From 64d03a409df5a6ed972d4dd149525d9872369fbe Mon Sep 17 00:00:00 2001 From: TrianglesDev Date: Wed, 16 Jul 2014 16:05:09 -0700 Subject: [PATCH] Initial upload --- COPYING | 22 + INSTALL | 9 + README | 1 + README.md | 6 + contrib/bitrpc/bitrpc.py | 324 + contrib/gitian-descriptors/README | 31 + contrib/gitian-descriptors/boost-win32.yml | 38 + contrib/gitian-descriptors/deps-win32.yml | 71 + contrib/gitian-descriptors/gitian-win32.yml | 74 + contrib/gitian-descriptors/gitian.yml | 56 + contrib/gitian-descriptors/qt-win32.yml | 54 + contrib/gitian-downloader/bluematt-key.pgp | Bin 0 -> 4113 bytes contrib/gitian-downloader/devrandom-key.pgp | Bin 0 -> 2213 bytes .../gitian-downloader/gavinandresen-key.pgp | Bin 0 -> 1176 bytes contrib/gitian-downloader/laanwj-key.pgp | 28 + .../gitian-downloader/linux-download-config | 38 + contrib/gitian-downloader/luke-jr-key.pgp | Bin 0 -> 5467 bytes .../gitian-downloader/richardsmith-key.gpg | 52 + contrib/gitian-downloader/scottnadal-key.gpg | 52 + contrib/gitian-downloader/sipa-key.pgp | Bin 0 -> 108922 bytes contrib/gitian-downloader/sunnyking-key.gpg | 52 + contrib/gitian-downloader/tcatm-key.pgp | Bin 0 -> 1554 bytes .../gitian-downloader/win32-download-config | 38 + contrib/macdeploy/LICENSE | 674 + contrib/macdeploy/background.png | Bin 0 -> 16606 bytes contrib/macdeploy/background.psd | Bin 0 -> 66096 bytes contrib/macdeploy/fancy.plist | 32 + contrib/macdeploy/macdeployqtplus | 758 + contrib/macdeploy/notes.txt | 26 + contrib/qt_translations.py | 22 + contrib/wallettools/walletchangepass.py | 5 + contrib/wallettools/walletunlock.py | 4 + doc/Doxyfile | 1752 + doc/README | 14 + doc/assets-attribution.txt | 56 + doc/bitcoin_logo_doxygen.png | Bin 0 -> 5735 bytes doc/build-msw.txt | 84 + doc/build-osx.txt | 61 + doc/build-unix.txt | 159 + doc/coding.txt | 99 + doc/readme-qt.rst | 159 + doc/release-process.txt | 142 + doc/translation_process.md | 80 + share/genbuild.sh | 35 + share/pixmaps/addressbook16.bmp | Bin 0 -> 1334 bytes share/pixmaps/addressbook16mask.bmp | Bin 0 -> 126 bytes share/pixmaps/addressbook20.bmp | Bin 0 -> 1478 bytes share/pixmaps/addressbook20mask.bmp | Bin 0 -> 142 bytes share/pixmaps/bitcoin-bc.ico | Bin 0 -> 22486 bytes share/pixmaps/bitcoin.ico | Bin 0 -> 306398 bytes share/pixmaps/bitcoin32.xpm | 232 + share/pixmaps/bitcoin80.xpm | 292 + share/pixmaps/bitgem32.xpm | 468 + share/pixmaps/bitgem80.xpm | 955 + share/pixmaps/check.ico | Bin 0 -> 766 bytes share/pixmaps/favicon.ico | Bin 0 -> 2294 bytes share/pixmaps/nsis-header.bmp | Bin 0 -> 34254 bytes share/pixmaps/nsis-wizard.bmp | Bin 0 -> 206038 bytes share/pixmaps/send16.bmp | Bin 0 -> 1334 bytes share/pixmaps/send16mask.bmp | Bin 0 -> 126 bytes share/pixmaps/send16masknoshadow.bmp | Bin 0 -> 126 bytes share/pixmaps/send20.bmp | Bin 0 -> 1478 bytes share/pixmaps/send20mask.bmp | Bin 0 -> 142 bytes share/qt/extract_strings_qt.py | 70 + share/qt/img/reload.xcf | Bin 0 -> 25292 bytes share/qt/make_spinner.py | 43 + share/qt/make_windows_icon.sh | 5 + share/setup.nsi | 164 + share/ui.rc | 15 + src/addrman.cpp | 527 + src/addrman.h | 574 + src/aes_helper.c | 392 + src/alert.cpp | 241 + src/alert.h | 102 + src/allocators.h | 257 + src/base58.h | 460 + src/bignum.h | 564 + src/bitcoinrpc.cpp | 1292 + src/bitcoinrpc.h | 208 + src/blake.c | 1120 + src/bmw.c | 965 + src/checkpoints.cpp | 435 + src/checkpoints.h | 140 + src/clientversion.h | 19 + src/coincontrol.h | 57 + src/compat.h | 63 + src/crypter.cpp | 121 + src/crypter.h | 107 + src/cubehash.c | 723 + src/db.cpp | 976 + src/db.h | 366 + src/echo.c | 1031 + src/fugue.c | 1208 + src/groestl.c | 3123 ++ src/hamsi.c | 867 + src/hamsi_helper.c | 39648 ++++++++++++++++ src/hashblock.h | 155 + src/init.cpp | 847 + src/init.h | 18 + src/irc.cpp | 393 + src/irc.h | 12 + src/jh.c | 1116 + src/json/LICENSE.txt | 24 + src/json/json_spirit.h | 18 + src/json/json_spirit_error_position.h | 54 + src/json/json_spirit_reader.cpp | 137 + src/json/json_spirit_reader.h | 62 + src/json/json_spirit_reader_template.h | 612 + src/json/json_spirit_stream_reader.h | 70 + src/json/json_spirit_utils.h | 61 + src/json/json_spirit_value.cpp | 8 + src/json/json_spirit_value.h | 534 + src/json/json_spirit_writer.cpp | 95 + src/json/json_spirit_writer.h | 50 + src/json/json_spirit_writer_template.h | 248 + src/keccak.c | 1824 + src/kernel.cpp | 432 + src/kernel.h | 40 + src/key.cpp | 406 + src/key.h | 162 + src/keystore.cpp | 221 + src/keystore.h | 184 + src/luffa.c | 1426 + src/main.cpp | 4507 ++ src/main.h | 1604 + src/makefile.bsd | 189 + src/makefile.linux-mingw | 226 + src/makefile.mingw | 118 + src/makefile.osx | 286 + src/makefile.unix | 304 + src/mruset.h | 64 + src/net.cpp | 1938 + src/net.h | 693 + src/netbase.cpp | 1224 + src/netbase.h | 153 + src/noui.cpp | 28 + src/onionseed.h | 18 + src/pbkdf2.cpp | 148 + src/pbkdf2.h | 27 + src/protocol.cpp | 150 + src/protocol.h | 137 + src/qt/aboutdialog.cpp | 31 + src/qt/aboutdialog.h | 28 + src/qt/addressbookpage.cpp | 374 + src/qt/addressbookpage.h | 85 + src/qt/addresstablemodel.cpp | 406 + src/qt/addresstablemodel.h | 91 + src/qt/askpassphrasedialog.cpp | 257 + src/qt/askpassphrasedialog.h | 46 + src/qt/bitcoin.cpp | 270 + src/qt/bitcoin.qrc | 57 + src/qt/bitcoinaddressvalidator.cpp | 77 + src/qt/bitcoinaddressvalidator.h | 24 + src/qt/bitcoinamountfield.cpp | 168 + src/qt/bitcoinamountfield.h | 61 + src/qt/bitcoingui.cpp | 1009 + src/qt/bitcoingui.h | 192 + src/qt/bitcoinstrings.cpp | 177 + src/qt/bitcoinunits.cpp | 181 + src/qt/bitcoinunits.h | 66 + src/qt/clientmodel.cpp | 205 + src/qt/clientmodel.h | 72 + src/qt/coincontroldialog.cpp | 738 + src/qt/coincontroldialog.h | 92 + src/qt/coincontroltreewidget.cpp | 28 + src/qt/coincontroltreewidget.h | 17 + src/qt/csvmodelwriter.cpp | 88 + src/qt/csvmodelwriter.h | 46 + src/qt/editaddressdialog.cpp | 128 + src/qt/editaddressdialog.h | 50 + src/qt/forms/aboutdialog.ui | 190 + src/qt/forms/addressbookpage.ui | 178 + src/qt/forms/askpassphrasedialog.ui | 167 + src/qt/forms/coincontroldialog.ui | 549 + src/qt/forms/editaddressdialog.ui | 105 + src/qt/forms/optionsdialog.ui | 470 + src/qt/forms/overviewpage.ui | 388 + src/qt/forms/qrcodedialog.ui | 212 + src/qt/forms/rpcconsole.ui | 456 + src/qt/forms/sendcoinsdialog.ui | 812 + src/qt/forms/sendcoinsentry.ui | 169 + src/qt/forms/signverifymessagedialog.ui | 386 + src/qt/forms/transactiondescdialog.ui | 74 + src/qt/guiconstants.h | 34 + src/qt/guiutil.cpp | 457 + src/qt/guiutil.h | 120 + src/qt/httpsocket.cpp | 46 + src/qt/httpsocket.h | 29 + src/qt/locale/bitcoin_en.qm | Bin 0 -> 74856 bytes src/qt/locale/bitcoin_en.ts | 2750 ++ src/qt/locale/bitcoin_ru.qm | Bin 0 -> 84243 bytes src/qt/locale/bitcoin_ru.ts | 2753 ++ src/qt/macdockiconhandler.h | 51 + src/qt/macdockiconhandler.hh | 51 + src/qt/macdockiconhandler.mm | 137 + src/qt/macnotificationhandler.h | 30 + src/qt/macnotificationhandler.hh | 30 + src/qt/macnotificationhandler.mm | 69 + src/qt/monitoreddatamapper.cpp | 36 + src/qt/monitoreddatamapper.h | 31 + src/qt/notificator.cpp | 302 + src/qt/notificator.h | 69 + src/qt/optionsdialog.cpp | 257 + src/qt/optionsdialog.h | 60 + src/qt/optionsmodel.cpp | 308 + src/qt/optionsmodel.h | 69 + src/qt/overviewpage.cpp | 204 + src/qt/overviewpage.h | 52 + src/qt/qrcodedialog.cpp | 171 + src/qt/qrcodedialog.h | 41 + src/qt/qtipcserver.cpp | 162 + src/qt/qtipcserver.h | 10 + src/qt/qvalidatedlineedit.cpp | 45 + src/qt/qvalidatedlineedit.h | 29 + src/qt/qvaluecombobox.cpp | 27 + src/qt/qvaluecombobox.h | 33 + src/qt/res/.!37041!icons.zip | 1 + src/qt/res/.!37364!icons.zip | 1 + src/qt/res/bitcoin-qt.rc | 37 + src/qt/res/icons/add.png | Bin 0 -> 1279 bytes src/qt/res/icons/address-book.png | Bin 0 -> 1916 bytes src/qt/res/icons/bitcoin.icns | Bin 0 -> 79804 bytes src/qt/res/icons/bitcoin.png | Bin 0 -> 14457 bytes src/qt/res/icons/bitcoin_testnet.png | Bin 0 -> 14457 bytes src/qt/res/icons/clock1.png | Bin 0 -> 946 bytes src/qt/res/icons/clock2.png | Bin 0 -> 944 bytes src/qt/res/icons/clock3.png | Bin 0 -> 946 bytes src/qt/res/icons/clock4.png | Bin 0 -> 962 bytes src/qt/res/icons/clock5.png | Bin 0 -> 956 bytes src/qt/res/icons/configure.png | Bin 0 -> 1055 bytes src/qt/res/icons/connect0_16.png | Bin 0 -> 702 bytes src/qt/res/icons/connect1_16.png | Bin 0 -> 612 bytes src/qt/res/icons/connect2_16.png | Bin 0 -> 623 bytes src/qt/res/icons/connect3_16.png | Bin 0 -> 625 bytes src/qt/res/icons/connect4_16.png | Bin 0 -> 673 bytes src/qt/res/icons/debugwindow.png | Bin 0 -> 5402 bytes src/qt/res/icons/edit.png | Bin 0 -> 1627 bytes src/qt/res/icons/editcopy.png | Bin 0 -> 879 bytes src/qt/res/icons/editpaste.png | Bin 0 -> 1458 bytes src/qt/res/icons/export.png | Bin 0 -> 2148 bytes src/qt/res/icons/filesave.png | Bin 0 -> 1741 bytes src/qt/res/icons/history.png | Bin 0 -> 1432 bytes src/qt/res/icons/key.png | Bin 0 -> 1727 bytes src/qt/res/icons/lock_closed.png | Bin 0 -> 1679 bytes src/qt/res/icons/lock_open.png | Bin 0 -> 1644 bytes src/qt/res/icons/mining.png | Bin 0 -> 10027 bytes src/qt/res/icons/mining_active.png | Bin 0 -> 10027 bytes src/qt/res/icons/mining_inactive.png | Bin 0 -> 665 bytes src/qt/res/icons/notsynced.png | Bin 0 -> 1013 bytes src/qt/res/icons/overview.png | Bin 0 -> 7455 bytes src/qt/res/icons/qrcode.png | Bin 0 -> 237 bytes src/qt/res/icons/quit.png | Bin 0 -> 2163 bytes src/qt/res/icons/receive.png | Bin 0 -> 1437 bytes src/qt/res/icons/remove.png | Bin 0 -> 1224 bytes src/qt/res/icons/send.png | Bin 0 -> 1487 bytes src/qt/res/icons/staking_off.png | Bin 0 -> 978 bytes src/qt/res/icons/staking_on.png | Bin 0 -> 968 bytes src/qt/res/icons/synced.png | Bin 0 -> 781 bytes src/qt/res/icons/transaction0.png | Bin 0 -> 569 bytes src/qt/res/icons/transaction2.png | Bin 0 -> 413 bytes src/qt/res/icons/transaction_conflicted.png | Bin 0 -> 474 bytes src/qt/res/icons/triangles-128.png | Bin 0 -> 14457 bytes src/qt/res/icons/triangles-16.png | Bin 0 -> 10027 bytes src/qt/res/icons/triangles.icns | Bin 0 -> 79804 bytes src/qt/res/icons/triangles.ico | Bin 0 -> 370070 bytes src/qt/res/icons/triangles.png | Bin 0 -> 21016 bytes src/qt/res/icons/tx_inout.png | Bin 0 -> 2442 bytes src/qt/res/icons/tx_input.png | Bin 0 -> 2152 bytes src/qt/res/icons/tx_mined.png | Bin 0 -> 3287 bytes src/qt/res/icons/tx_output.png | Bin 0 -> 2129 bytes src/qt/res/images/about.png | Bin 0 -> 21016 bytes src/qt/res/images/splash.png | Bin 0 -> 21016 bytes src/qt/res/images/wallet.png | Bin 0 -> 21016 bytes src/qt/res/movies/update_spinner.mng | Bin 0 -> 27817 bytes src/qt/res/src/bitcoin.svg | 115 + src/qt/res/src/clock1.svg | 261 + src/qt/res/src/clock2.svg | 262 + src/qt/res/src/clock3.svg | 261 + src/qt/res/src/clock4.svg | 261 + src/qt/res/src/clock5.svg | 262 + src/qt/res/src/clock_green.svg | 262 + src/qt/res/src/inout.svg | 122 + src/qt/res/src/questionmark.svg | 159 + src/qt/rpcconsole.cpp | 437 + src/qt/rpcconsole.h | 66 + src/qt/sendcoinsdialog.cpp | 516 + src/qt/sendcoinsdialog.h | 68 + src/qt/sendcoinsentry.cpp | 175 + src/qt/sendcoinsentry.h | 56 + src/qt/signverifymessagedialog.cpp | 274 + src/qt/signverifymessagedialog.h | 49 + src/qt/test/test_main.cpp | 16 + src/qt/test/uritests.cpp | 71 + src/qt/test/uritests.h | 15 + src/qt/transactiondesc.cpp | 278 + src/qt/transactiondesc.h | 24 + src/qt/transactiondescdialog.cpp | 20 + src/qt/transactiondescdialog.h | 26 + src/qt/transactionfilterproxy.cpp | 86 + src/qt/transactionfilterproxy.h | 52 + src/qt/transactionrecord.cpp | 236 + src/qt/transactionrecord.h | 130 + src/qt/transactiontablemodel.cpp | 639 + src/qt/transactiontablemodel.h | 85 + src/qt/transactionview.cpp | 432 + src/qt/transactionview.h | 82 + src/qt/walletmodel.cpp | 456 + src/qt/walletmodel.h | 185 + src/rpcblockchain.cpp | 256 + src/rpcdump.cpp | 95 + src/rpcmining.cpp | 552 + src/rpcnet.cpp | 136 + src/rpcrawtransaction.cpp | 532 + src/rpcwallet.cpp | 1763 + src/script.cpp | 1883 + src/script.h | 606 + src/scrypt-x86.S | 908 + src/scrypt-x86_64.S | 1831 + src/scrypt.cpp | 198 + src/scrypt.h | 15 + src/scrypt_mine.cpp | 208 + src/scrypt_mine.h | 30 + src/serialize.h | 1133 + src/shavite.c | 1764 + src/simd.c | 1799 + src/skein.c | 1254 + src/sph_blake.h | 327 + src/sph_bmw.h | 328 + src/sph_cubehash.h | 292 + src/sph_echo.h | 320 + src/sph_fugue.h | 81 + src/sph_groestl.h | 329 + src/sph_hamsi.h | 321 + src/sph_jh.h | 298 + src/sph_keccak.h | 293 + src/sph_luffa.h | 296 + src/sph_shavite.h | 314 + src/sph_simd.h | 309 + src/sph_skein.h | 298 + src/sph_types.h | 1976 + src/strlcpy.h | 90 + src/sync.cpp | 128 + src/sync.h | 212 + src/test/Checkpoints_tests.cpp | 34 + src/test/DoS_tests.cpp | 314 + src/test/README | 21 + src/test/accounting_tests.cpp | 123 + src/test/allocator_tests.cpp | 115 + src/test/base32_tests.cpp | 20 + src/test/base58_tests.cpp | 259 + src/test/base64_tests.cpp | 22 + src/test/bignum_tests.cpp | 125 + src/test/data/base58_encode_decode.json | 14 + src/test/data/base58_keys_invalid.json | 152 + src/test/data/base58_keys_valid.json | 452 + src/test/data/script_invalid.json | 245 + src/test/data/script_valid.json | 313 + src/test/data/tx_invalid.json | 64 + src/test/data/tx_valid.json | 71 + src/test/getarg_tests.cpp | 167 + src/test/key_tests.cpp | 147 + src/test/miner_tests.cpp | 227 + src/test/mruset_tests.cpp | 90 + src/test/multisig_tests.cpp | 296 + src/test/netbase_tests.cpp | 102 + src/test/rpc_tests.cpp | 62 + src/test/script_P2SH_tests.cpp | 330 + src/test/script_tests.cpp | 445 + src/test/sigopcount_tests.cpp | 60 + src/test/test_bitcoin.cpp | 44 + src/test/transaction_tests.cpp | 264 + src/test/uint160_tests.cpp | 18 + src/test/uint256_tests.cpp | 18 + src/test/util_tests.cpp | 264 + src/test/wallet_tests.cpp | 295 + src/tor/LICENSE | 174 + src/tor/address.c | 1692 + src/tor/address.h | 232 + src/tor/addressmap.c | 1078 + src/tor/addressmap.h | 62 + src/tor/aes.c | 522 + src/tor/aes.h | 29 + src/tor/anonymize.P | 1072 + src/tor/anonymize.cpp | 60 + src/tor/anonymize.h | 37 + src/tor/backtrace.c | 205 + src/tor/backtrace.h | 12 + src/tor/buffers.c | 2584 + src/tor/buffers.h | 106 + src/tor/channel.c | 4191 ++ src/tor/channel.h | 489 + src/tor/channeltls.c | 2074 + src/tor/channeltls.h | 57 + src/tor/ciphers.inc | 182 + src/tor/circpathbias.c | 1538 + src/tor/circpathbias.h | 29 + src/tor/circuitbuild.c | 2200 + src/tor/circuitbuild.h | 62 + src/tor/circuitlist.c | 1878 + src/tor/circuitlist.h | 82 + src/tor/circuitmux.c | 1898 + src/tor/circuitmux.h | 147 + src/tor/circuitmux_ewma.c | 684 + src/tor/circuitmux_ewma.h | 29 + src/tor/circuitstats.c | 1644 + src/tor/circuitstats.h | 98 + src/tor/circuituse.c | 2326 + src/tor/circuituse.h | 61 + src/tor/command.c | 589 + src/tor/command.h | 31 + src/tor/common_sha1.i | 26 + src/tor/compat.c | 3254 ++ src/tor/compat_libevent.c | 663 + src/tor/compat_libevent.h | 96 + src/tor/config.c | 6704 +++ src/tor/config.h | 144 + src/tor/config_codedigest.c | 13 + src/tor/confparse.c | 1316 + src/tor/confparse.h | 137 + src/tor/connection.c | 4850 ++ src/tor/connection.h | 231 + src/tor/connection_edge.c | 3119 ++ src/tor/connection_edge.h | 143 + src/tor/connection_or.c | 2452 + src/tor/connection_or.h | 100 + src/tor/container.c | 1557 + src/tor/container.h | 681 + src/tor/control.c | 5110 ++ src/tor/control.h | 205 + src/tor/cpuworker.c | 718 + src/tor/cpuworker.h | 31 + src/tor/crypto.c | 3154 ++ src/tor/crypto.h | 302 + src/tor/crypto_curve25519.c | 191 + src/tor/crypto_curve25519.h | 74 + src/tor/crypto_format.c | 45 + src/tor/curve25519-donna.c | 732 + src/tor/di_ops.c | 222 + src/tor/di_ops.h | 47 + src/tor/directory.c | 3894 ++ src/tor/directory.h | 127 + src/tor/dirserv.c | 3780 ++ src/tor/dirserv.h | 138 + src/tor/dirvote.c | 3778 ++ src/tor/dirvote.h | 148 + src/tor/dns.c | 2203 + src/tor/dns.h | 32 + src/tor/dnsserv.c | 374 + src/tor/dnsserv.h | 27 + src/tor/entrynodes.c | 2334 + src/tor/entrynodes.h | 133 + src/tor/eventdns.h | 337 + src/tor/eventdns_tor.h | 25 + src/tor/ext_orport.c | 648 + src/tor/ext_orport.h | 42 + src/tor/fp_pair.c | 308 + src/tor/fp_pair.h | 45 + src/tor/geoip.c | 1684 + src/tor/geoip.h | 69 + src/tor/hibernate.c | 1031 + src/tor/hibernate.h | 55 + src/tor/ht.h | 490 + src/tor/log.c | 1316 + src/tor/memarea.c | 328 + src/tor/memarea.h | 25 + src/tor/mempool.c | 628 + src/tor/mempool.h | 65 + src/tor/microdesc.c | 833 + src/tor/microdesc.h | 56 + src/tor/networkstatus.c | 1871 + src/tor/networkstatus.h | 104 + src/tor/nodelist.c | 1557 + src/tor/nodelist.h | 86 + src/tor/ntmain.h | 30 + src/tor/onion.c | 1183 + src/tor/onion.h | 122 + src/tor/onion_fast.c | 123 + src/tor/onion_fast.h | 38 + src/tor/onion_main.c | 2908 ++ src/tor/onion_main.h | 86 + src/tor/onion_ntor.c | 295 + src/tor/onion_ntor.h | 63 + src/tor/onion_tap.c | 218 + src/tor/onion_tap.h | 37 + src/tor/or.h | 5044 ++ src/tor/or_sha1.i | 167 + src/tor/orconfig.h | 12 + src/tor/orconfig_apple.h | 623 + src/tor/orconfig_linux.h | 621 + src/tor/orconfig_win32.h | 259 + src/tor/policies.c | 1758 + src/tor/policies.h | 77 + src/tor/procmon.c | 356 + src/tor/procmon.h | 33 + src/tor/reasons.c | 439 + src/tor/reasons.h | 31 + src/tor/relay.c | 2870 ++ src/tor/relay.h | 91 + src/tor/rendclient.c | 1362 + src/tor/rendclient.h | 57 + src/tor/rendcommon.c | 1487 + src/tor/rendcommon.h | 66 + src/tor/rendmid.c | 340 + src/tor/rendmid.h | 25 + src/tor/rendservice.c | 3396 ++ src/tor/rendservice.h | 108 + src/tor/rephist.c | 3057 ++ src/tor/rephist.h | 106 + src/tor/replaycache.c | 204 + src/tor/replaycache.h | 66 + src/tor/router.c | 3060 ++ src/tor/router.h | 154 + src/tor/routerlist.c | 5145 ++ src/tor/routerlist.h | 217 + src/tor/routerparse.c | 4925 ++ src/tor/routerparse.h | 86 + src/tor/routerset.c | 466 + src/tor/routerset.h | 49 + src/tor/sandbox.c | 1510 + src/tor/sandbox.h | 247 + src/tor/statefile.c | 627 + src/tor/statefile.h | 26 + src/tor/status.c | 166 + src/tor/status.h | 10 + src/tor/strlcat.c | 70 + src/tor/strlcpy.c | 60 + src/tor/testsupport.h | 80 + src/tor/tinytest.h | 87 + src/tor/tinytest_macros.h | 184 + src/tor/tor_compat.h | 751 + src/tor/tor_queue.h | 568 + src/tor/tor_util.c | 5086 ++ src/tor/tor_util.h | 550 + src/tor/torgzip.c | 527 + src/tor/torgzip.h | 59 + src/tor/torint.h | 365 + src/tor/torlog.h | 233 + src/tor/tortls.c | 2822 ++ src/tor/tortls.h | 142 + src/tor/transports.c | 1625 + src/tor/transports.h | 129 + src/tor/util_codedigest.c | 13 + src/ui_interface.h | 105 + src/uint256.h | 883 + src/util.cpp | 1382 + src/util.h | 651 + src/version.cpp | 66 + src/version.h | 52 + src/wallet.cpp | 2269 + src/wallet.h | 861 + src/walletdb.cpp | 676 + src/walletdb.h | 163 + triangles-qt.pro | 492 + 553 files changed, 292909 insertions(+) create mode 100644 COPYING create mode 100644 INSTALL create mode 100644 README create mode 100644 README.md create mode 100644 contrib/bitrpc/bitrpc.py create mode 100644 contrib/gitian-descriptors/README create mode 100644 contrib/gitian-descriptors/boost-win32.yml create mode 100644 contrib/gitian-descriptors/deps-win32.yml create mode 100644 contrib/gitian-descriptors/gitian-win32.yml create mode 100644 contrib/gitian-descriptors/gitian.yml create mode 100644 contrib/gitian-descriptors/qt-win32.yml create mode 100644 contrib/gitian-downloader/bluematt-key.pgp create mode 100644 contrib/gitian-downloader/devrandom-key.pgp create mode 100644 contrib/gitian-downloader/gavinandresen-key.pgp create mode 100644 contrib/gitian-downloader/laanwj-key.pgp create mode 100644 contrib/gitian-downloader/linux-download-config create mode 100644 contrib/gitian-downloader/luke-jr-key.pgp create mode 100644 contrib/gitian-downloader/richardsmith-key.gpg create mode 100644 contrib/gitian-downloader/scottnadal-key.gpg create mode 100644 contrib/gitian-downloader/sipa-key.pgp create mode 100644 contrib/gitian-downloader/sunnyking-key.gpg create mode 100644 contrib/gitian-downloader/tcatm-key.pgp create mode 100644 contrib/gitian-downloader/win32-download-config create mode 100644 contrib/macdeploy/LICENSE create mode 100644 contrib/macdeploy/background.png create mode 100644 contrib/macdeploy/background.psd create mode 100644 contrib/macdeploy/fancy.plist create mode 100644 contrib/macdeploy/macdeployqtplus create mode 100644 contrib/macdeploy/notes.txt create mode 100644 contrib/qt_translations.py create mode 100644 contrib/wallettools/walletchangepass.py create mode 100644 contrib/wallettools/walletunlock.py create mode 100644 doc/Doxyfile create mode 100644 doc/README create mode 100644 doc/assets-attribution.txt create mode 100644 doc/bitcoin_logo_doxygen.png create mode 100644 doc/build-msw.txt create mode 100644 doc/build-osx.txt create mode 100644 doc/build-unix.txt create mode 100644 doc/coding.txt create mode 100644 doc/readme-qt.rst create mode 100644 doc/release-process.txt create mode 100644 doc/translation_process.md create mode 100644 share/genbuild.sh create mode 100644 share/pixmaps/addressbook16.bmp create mode 100644 share/pixmaps/addressbook16mask.bmp create mode 100644 share/pixmaps/addressbook20.bmp create mode 100644 share/pixmaps/addressbook20mask.bmp create mode 100644 share/pixmaps/bitcoin-bc.ico create mode 100644 share/pixmaps/bitcoin.ico create mode 100644 share/pixmaps/bitcoin32.xpm create mode 100644 share/pixmaps/bitcoin80.xpm create mode 100644 share/pixmaps/bitgem32.xpm create mode 100644 share/pixmaps/bitgem80.xpm create mode 100644 share/pixmaps/check.ico create mode 100644 share/pixmaps/favicon.ico create mode 100644 share/pixmaps/nsis-header.bmp create mode 100644 share/pixmaps/nsis-wizard.bmp create mode 100644 share/pixmaps/send16.bmp create mode 100644 share/pixmaps/send16mask.bmp create mode 100644 share/pixmaps/send16masknoshadow.bmp create mode 100644 share/pixmaps/send20.bmp create mode 100644 share/pixmaps/send20mask.bmp create mode 100644 share/qt/extract_strings_qt.py create mode 100644 share/qt/img/reload.xcf create mode 100644 share/qt/make_spinner.py create mode 100644 share/qt/make_windows_icon.sh create mode 100644 share/setup.nsi create mode 100644 share/ui.rc create mode 100644 src/addrman.cpp create mode 100644 src/addrman.h create mode 100644 src/aes_helper.c create mode 100644 src/alert.cpp create mode 100644 src/alert.h create mode 100644 src/allocators.h create mode 100644 src/base58.h create mode 100644 src/bignum.h create mode 100644 src/bitcoinrpc.cpp create mode 100644 src/bitcoinrpc.h create mode 100644 src/blake.c create mode 100644 src/bmw.c create mode 100644 src/checkpoints.cpp create mode 100644 src/checkpoints.h create mode 100644 src/clientversion.h create mode 100644 src/coincontrol.h create mode 100644 src/compat.h create mode 100644 src/crypter.cpp create mode 100644 src/crypter.h create mode 100644 src/cubehash.c create mode 100644 src/db.cpp create mode 100644 src/db.h create mode 100644 src/echo.c create mode 100644 src/fugue.c create mode 100644 src/groestl.c create mode 100644 src/hamsi.c create mode 100644 src/hamsi_helper.c create mode 100644 src/hashblock.h create mode 100644 src/init.cpp create mode 100644 src/init.h create mode 100644 src/irc.cpp create mode 100644 src/irc.h create mode 100644 src/jh.c create mode 100644 src/json/LICENSE.txt create mode 100644 src/json/json_spirit.h create mode 100644 src/json/json_spirit_error_position.h create mode 100644 src/json/json_spirit_reader.cpp create mode 100644 src/json/json_spirit_reader.h create mode 100644 src/json/json_spirit_reader_template.h create mode 100644 src/json/json_spirit_stream_reader.h create mode 100644 src/json/json_spirit_utils.h create mode 100644 src/json/json_spirit_value.cpp create mode 100644 src/json/json_spirit_value.h create mode 100644 src/json/json_spirit_writer.cpp create mode 100644 src/json/json_spirit_writer.h create mode 100644 src/json/json_spirit_writer_template.h create mode 100644 src/keccak.c create mode 100644 src/kernel.cpp create mode 100644 src/kernel.h create mode 100644 src/key.cpp create mode 100644 src/key.h create mode 100644 src/keystore.cpp create mode 100644 src/keystore.h create mode 100644 src/luffa.c create mode 100644 src/main.cpp create mode 100644 src/main.h create mode 100644 src/makefile.bsd create mode 100644 src/makefile.linux-mingw create mode 100644 src/makefile.mingw create mode 100644 src/makefile.osx create mode 100644 src/makefile.unix create mode 100644 src/mruset.h create mode 100644 src/net.cpp create mode 100644 src/net.h create mode 100644 src/netbase.cpp create mode 100644 src/netbase.h create mode 100644 src/noui.cpp create mode 100644 src/onionseed.h create mode 100644 src/pbkdf2.cpp create mode 100644 src/pbkdf2.h create mode 100644 src/protocol.cpp create mode 100644 src/protocol.h create mode 100644 src/qt/aboutdialog.cpp create mode 100644 src/qt/aboutdialog.h create mode 100644 src/qt/addressbookpage.cpp create mode 100644 src/qt/addressbookpage.h create mode 100644 src/qt/addresstablemodel.cpp create mode 100644 src/qt/addresstablemodel.h create mode 100644 src/qt/askpassphrasedialog.cpp create mode 100644 src/qt/askpassphrasedialog.h create mode 100644 src/qt/bitcoin.cpp create mode 100644 src/qt/bitcoin.qrc create mode 100644 src/qt/bitcoinaddressvalidator.cpp create mode 100644 src/qt/bitcoinaddressvalidator.h create mode 100644 src/qt/bitcoinamountfield.cpp create mode 100644 src/qt/bitcoinamountfield.h create mode 100644 src/qt/bitcoingui.cpp create mode 100644 src/qt/bitcoingui.h create mode 100644 src/qt/bitcoinstrings.cpp create mode 100644 src/qt/bitcoinunits.cpp create mode 100644 src/qt/bitcoinunits.h create mode 100644 src/qt/clientmodel.cpp create mode 100644 src/qt/clientmodel.h create mode 100644 src/qt/coincontroldialog.cpp create mode 100644 src/qt/coincontroldialog.h create mode 100644 src/qt/coincontroltreewidget.cpp create mode 100644 src/qt/coincontroltreewidget.h create mode 100644 src/qt/csvmodelwriter.cpp create mode 100644 src/qt/csvmodelwriter.h create mode 100644 src/qt/editaddressdialog.cpp create mode 100644 src/qt/editaddressdialog.h create mode 100644 src/qt/forms/aboutdialog.ui create mode 100644 src/qt/forms/addressbookpage.ui create mode 100644 src/qt/forms/askpassphrasedialog.ui create mode 100644 src/qt/forms/coincontroldialog.ui create mode 100644 src/qt/forms/editaddressdialog.ui create mode 100644 src/qt/forms/optionsdialog.ui create mode 100644 src/qt/forms/overviewpage.ui create mode 100644 src/qt/forms/qrcodedialog.ui create mode 100644 src/qt/forms/rpcconsole.ui create mode 100644 src/qt/forms/sendcoinsdialog.ui create mode 100644 src/qt/forms/sendcoinsentry.ui create mode 100644 src/qt/forms/signverifymessagedialog.ui create mode 100644 src/qt/forms/transactiondescdialog.ui create mode 100644 src/qt/guiconstants.h create mode 100644 src/qt/guiutil.cpp create mode 100644 src/qt/guiutil.h create mode 100755 src/qt/httpsocket.cpp create mode 100755 src/qt/httpsocket.h create mode 100644 src/qt/locale/bitcoin_en.qm create mode 100644 src/qt/locale/bitcoin_en.ts create mode 100644 src/qt/locale/bitcoin_ru.qm create mode 100644 src/qt/locale/bitcoin_ru.ts create mode 100644 src/qt/macdockiconhandler.h create mode 100644 src/qt/macdockiconhandler.hh create mode 100644 src/qt/macdockiconhandler.mm create mode 100644 src/qt/macnotificationhandler.h create mode 100644 src/qt/macnotificationhandler.hh create mode 100644 src/qt/macnotificationhandler.mm create mode 100644 src/qt/monitoreddatamapper.cpp create mode 100644 src/qt/monitoreddatamapper.h create mode 100644 src/qt/notificator.cpp create mode 100644 src/qt/notificator.h create mode 100644 src/qt/optionsdialog.cpp create mode 100644 src/qt/optionsdialog.h create mode 100644 src/qt/optionsmodel.cpp create mode 100644 src/qt/optionsmodel.h create mode 100644 src/qt/overviewpage.cpp create mode 100644 src/qt/overviewpage.h create mode 100644 src/qt/qrcodedialog.cpp create mode 100644 src/qt/qrcodedialog.h create mode 100644 src/qt/qtipcserver.cpp create mode 100644 src/qt/qtipcserver.h create mode 100644 src/qt/qvalidatedlineedit.cpp create mode 100644 src/qt/qvalidatedlineedit.h create mode 100644 src/qt/qvaluecombobox.cpp create mode 100644 src/qt/qvaluecombobox.h create mode 100644 src/qt/res/.!37041!icons.zip create mode 100644 src/qt/res/.!37364!icons.zip create mode 100644 src/qt/res/bitcoin-qt.rc create mode 100644 src/qt/res/icons/add.png create mode 100644 src/qt/res/icons/address-book.png create mode 100644 src/qt/res/icons/bitcoin.icns create mode 100644 src/qt/res/icons/bitcoin.png create mode 100644 src/qt/res/icons/bitcoin_testnet.png create mode 100644 src/qt/res/icons/clock1.png create mode 100644 src/qt/res/icons/clock2.png create mode 100644 src/qt/res/icons/clock3.png create mode 100644 src/qt/res/icons/clock4.png create mode 100644 src/qt/res/icons/clock5.png create mode 100644 src/qt/res/icons/configure.png create mode 100644 src/qt/res/icons/connect0_16.png create mode 100644 src/qt/res/icons/connect1_16.png create mode 100644 src/qt/res/icons/connect2_16.png create mode 100644 src/qt/res/icons/connect3_16.png create mode 100644 src/qt/res/icons/connect4_16.png create mode 100644 src/qt/res/icons/debugwindow.png create mode 100644 src/qt/res/icons/edit.png create mode 100644 src/qt/res/icons/editcopy.png create mode 100644 src/qt/res/icons/editpaste.png create mode 100644 src/qt/res/icons/export.png create mode 100644 src/qt/res/icons/filesave.png create mode 100644 src/qt/res/icons/history.png create mode 100644 src/qt/res/icons/key.png create mode 100644 src/qt/res/icons/lock_closed.png create mode 100644 src/qt/res/icons/lock_open.png create mode 100644 src/qt/res/icons/mining.png create mode 100644 src/qt/res/icons/mining_active.png create mode 100644 src/qt/res/icons/mining_inactive.png create mode 100644 src/qt/res/icons/notsynced.png create mode 100644 src/qt/res/icons/overview.png create mode 100644 src/qt/res/icons/qrcode.png create mode 100644 src/qt/res/icons/quit.png create mode 100644 src/qt/res/icons/receive.png create mode 100644 src/qt/res/icons/remove.png create mode 100644 src/qt/res/icons/send.png create mode 100644 src/qt/res/icons/staking_off.png create mode 100644 src/qt/res/icons/staking_on.png create mode 100644 src/qt/res/icons/synced.png create mode 100644 src/qt/res/icons/transaction0.png create mode 100644 src/qt/res/icons/transaction2.png create mode 100644 src/qt/res/icons/transaction_conflicted.png create mode 100644 src/qt/res/icons/triangles-128.png create mode 100644 src/qt/res/icons/triangles-16.png create mode 100644 src/qt/res/icons/triangles.icns create mode 100644 src/qt/res/icons/triangles.ico create mode 100644 src/qt/res/icons/triangles.png create mode 100644 src/qt/res/icons/tx_inout.png create mode 100644 src/qt/res/icons/tx_input.png create mode 100644 src/qt/res/icons/tx_mined.png create mode 100644 src/qt/res/icons/tx_output.png create mode 100644 src/qt/res/images/about.png create mode 100644 src/qt/res/images/splash.png create mode 100644 src/qt/res/images/wallet.png create mode 100644 src/qt/res/movies/update_spinner.mng create mode 100644 src/qt/res/src/bitcoin.svg create mode 100644 src/qt/res/src/clock1.svg create mode 100644 src/qt/res/src/clock2.svg create mode 100644 src/qt/res/src/clock3.svg create mode 100644 src/qt/res/src/clock4.svg create mode 100644 src/qt/res/src/clock5.svg create mode 100644 src/qt/res/src/clock_green.svg create mode 100644 src/qt/res/src/inout.svg create mode 100644 src/qt/res/src/questionmark.svg create mode 100644 src/qt/rpcconsole.cpp create mode 100644 src/qt/rpcconsole.h create mode 100644 src/qt/sendcoinsdialog.cpp create mode 100644 src/qt/sendcoinsdialog.h create mode 100644 src/qt/sendcoinsentry.cpp create mode 100644 src/qt/sendcoinsentry.h create mode 100644 src/qt/signverifymessagedialog.cpp create mode 100644 src/qt/signverifymessagedialog.h create mode 100644 src/qt/test/test_main.cpp create mode 100644 src/qt/test/uritests.cpp create mode 100644 src/qt/test/uritests.h create mode 100644 src/qt/transactiondesc.cpp create mode 100644 src/qt/transactiondesc.h create mode 100644 src/qt/transactiondescdialog.cpp create mode 100644 src/qt/transactiondescdialog.h create mode 100644 src/qt/transactionfilterproxy.cpp create mode 100644 src/qt/transactionfilterproxy.h create mode 100644 src/qt/transactionrecord.cpp create mode 100644 src/qt/transactionrecord.h create mode 100644 src/qt/transactiontablemodel.cpp create mode 100644 src/qt/transactiontablemodel.h create mode 100644 src/qt/transactionview.cpp create mode 100644 src/qt/transactionview.h create mode 100644 src/qt/walletmodel.cpp create mode 100644 src/qt/walletmodel.h create mode 100644 src/rpcblockchain.cpp create mode 100644 src/rpcdump.cpp create mode 100644 src/rpcmining.cpp create mode 100644 src/rpcnet.cpp create mode 100644 src/rpcrawtransaction.cpp create mode 100644 src/rpcwallet.cpp create mode 100644 src/script.cpp create mode 100644 src/script.h create mode 100644 src/scrypt-x86.S create mode 100644 src/scrypt-x86_64.S create mode 100644 src/scrypt.cpp create mode 100644 src/scrypt.h create mode 100644 src/scrypt_mine.cpp create mode 100644 src/scrypt_mine.h create mode 100644 src/serialize.h create mode 100644 src/shavite.c create mode 100644 src/simd.c create mode 100644 src/skein.c create mode 100644 src/sph_blake.h create mode 100644 src/sph_bmw.h create mode 100644 src/sph_cubehash.h create mode 100644 src/sph_echo.h create mode 100644 src/sph_fugue.h create mode 100644 src/sph_groestl.h create mode 100644 src/sph_hamsi.h create mode 100644 src/sph_jh.h create mode 100644 src/sph_keccak.h create mode 100644 src/sph_luffa.h create mode 100644 src/sph_shavite.h create mode 100644 src/sph_simd.h create mode 100644 src/sph_skein.h create mode 100644 src/sph_types.h create mode 100644 src/strlcpy.h create mode 100644 src/sync.cpp create mode 100644 src/sync.h create mode 100644 src/test/Checkpoints_tests.cpp create mode 100644 src/test/DoS_tests.cpp create mode 100644 src/test/README create mode 100644 src/test/accounting_tests.cpp create mode 100644 src/test/allocator_tests.cpp create mode 100644 src/test/base32_tests.cpp create mode 100644 src/test/base58_tests.cpp create mode 100644 src/test/base64_tests.cpp create mode 100644 src/test/bignum_tests.cpp create mode 100644 src/test/data/base58_encode_decode.json create mode 100644 src/test/data/base58_keys_invalid.json create mode 100644 src/test/data/base58_keys_valid.json create mode 100644 src/test/data/script_invalid.json create mode 100644 src/test/data/script_valid.json create mode 100644 src/test/data/tx_invalid.json create mode 100644 src/test/data/tx_valid.json create mode 100644 src/test/getarg_tests.cpp create mode 100644 src/test/key_tests.cpp create mode 100644 src/test/miner_tests.cpp create mode 100644 src/test/mruset_tests.cpp create mode 100644 src/test/multisig_tests.cpp create mode 100644 src/test/netbase_tests.cpp create mode 100644 src/test/rpc_tests.cpp create mode 100644 src/test/script_P2SH_tests.cpp create mode 100644 src/test/script_tests.cpp create mode 100644 src/test/sigopcount_tests.cpp create mode 100644 src/test/test_bitcoin.cpp create mode 100644 src/test/transaction_tests.cpp create mode 100644 src/test/uint160_tests.cpp create mode 100644 src/test/uint256_tests.cpp create mode 100644 src/test/util_tests.cpp create mode 100644 src/test/wallet_tests.cpp create mode 100644 src/tor/LICENSE create mode 100644 src/tor/address.c create mode 100644 src/tor/address.h create mode 100644 src/tor/addressmap.c create mode 100644 src/tor/addressmap.h create mode 100644 src/tor/aes.c create mode 100644 src/tor/aes.h create mode 100644 src/tor/anonymize.P create mode 100644 src/tor/anonymize.cpp create mode 100644 src/tor/anonymize.h create mode 100644 src/tor/backtrace.c create mode 100644 src/tor/backtrace.h create mode 100644 src/tor/buffers.c create mode 100644 src/tor/buffers.h create mode 100644 src/tor/channel.c create mode 100644 src/tor/channel.h create mode 100644 src/tor/channeltls.c create mode 100644 src/tor/channeltls.h create mode 100644 src/tor/ciphers.inc create mode 100644 src/tor/circpathbias.c create mode 100644 src/tor/circpathbias.h create mode 100644 src/tor/circuitbuild.c create mode 100644 src/tor/circuitbuild.h create mode 100644 src/tor/circuitlist.c create mode 100644 src/tor/circuitlist.h create mode 100644 src/tor/circuitmux.c create mode 100644 src/tor/circuitmux.h create mode 100644 src/tor/circuitmux_ewma.c create mode 100644 src/tor/circuitmux_ewma.h create mode 100644 src/tor/circuitstats.c create mode 100644 src/tor/circuitstats.h create mode 100644 src/tor/circuituse.c create mode 100644 src/tor/circuituse.h create mode 100644 src/tor/command.c create mode 100644 src/tor/command.h create mode 100644 src/tor/common_sha1.i create mode 100644 src/tor/compat.c create mode 100644 src/tor/compat_libevent.c create mode 100644 src/tor/compat_libevent.h create mode 100644 src/tor/config.c create mode 100644 src/tor/config.h create mode 100644 src/tor/config_codedigest.c create mode 100644 src/tor/confparse.c create mode 100644 src/tor/confparse.h create mode 100644 src/tor/connection.c create mode 100644 src/tor/connection.h create mode 100644 src/tor/connection_edge.c create mode 100644 src/tor/connection_edge.h create mode 100644 src/tor/connection_or.c create mode 100644 src/tor/connection_or.h create mode 100644 src/tor/container.c create mode 100644 src/tor/container.h create mode 100644 src/tor/control.c create mode 100644 src/tor/control.h create mode 100644 src/tor/cpuworker.c create mode 100644 src/tor/cpuworker.h create mode 100644 src/tor/crypto.c create mode 100644 src/tor/crypto.h create mode 100644 src/tor/crypto_curve25519.c create mode 100644 src/tor/crypto_curve25519.h create mode 100644 src/tor/crypto_format.c create mode 100644 src/tor/curve25519-donna.c create mode 100644 src/tor/di_ops.c create mode 100644 src/tor/di_ops.h create mode 100644 src/tor/directory.c create mode 100644 src/tor/directory.h create mode 100644 src/tor/dirserv.c create mode 100644 src/tor/dirserv.h create mode 100644 src/tor/dirvote.c create mode 100644 src/tor/dirvote.h create mode 100644 src/tor/dns.c create mode 100644 src/tor/dns.h create mode 100644 src/tor/dnsserv.c create mode 100644 src/tor/dnsserv.h create mode 100644 src/tor/entrynodes.c create mode 100644 src/tor/entrynodes.h create mode 100644 src/tor/eventdns.h create mode 100644 src/tor/eventdns_tor.h create mode 100644 src/tor/ext_orport.c create mode 100644 src/tor/ext_orport.h create mode 100644 src/tor/fp_pair.c create mode 100644 src/tor/fp_pair.h create mode 100644 src/tor/geoip.c create mode 100644 src/tor/geoip.h create mode 100644 src/tor/hibernate.c create mode 100644 src/tor/hibernate.h create mode 100644 src/tor/ht.h create mode 100644 src/tor/log.c create mode 100644 src/tor/memarea.c create mode 100644 src/tor/memarea.h create mode 100644 src/tor/mempool.c create mode 100644 src/tor/mempool.h create mode 100644 src/tor/microdesc.c create mode 100644 src/tor/microdesc.h create mode 100644 src/tor/networkstatus.c create mode 100644 src/tor/networkstatus.h create mode 100644 src/tor/nodelist.c create mode 100644 src/tor/nodelist.h create mode 100644 src/tor/ntmain.h create mode 100644 src/tor/onion.c create mode 100644 src/tor/onion.h create mode 100644 src/tor/onion_fast.c create mode 100644 src/tor/onion_fast.h create mode 100644 src/tor/onion_main.c create mode 100644 src/tor/onion_main.h create mode 100644 src/tor/onion_ntor.c create mode 100644 src/tor/onion_ntor.h create mode 100644 src/tor/onion_tap.c create mode 100644 src/tor/onion_tap.h create mode 100644 src/tor/or.h create mode 100644 src/tor/or_sha1.i create mode 100644 src/tor/orconfig.h create mode 100644 src/tor/orconfig_apple.h create mode 100644 src/tor/orconfig_linux.h create mode 100644 src/tor/orconfig_win32.h create mode 100644 src/tor/policies.c create mode 100644 src/tor/policies.h create mode 100644 src/tor/procmon.c create mode 100644 src/tor/procmon.h create mode 100644 src/tor/reasons.c create mode 100644 src/tor/reasons.h create mode 100644 src/tor/relay.c create mode 100644 src/tor/relay.h create mode 100644 src/tor/rendclient.c create mode 100644 src/tor/rendclient.h create mode 100644 src/tor/rendcommon.c create mode 100644 src/tor/rendcommon.h create mode 100644 src/tor/rendmid.c create mode 100644 src/tor/rendmid.h create mode 100644 src/tor/rendservice.c create mode 100644 src/tor/rendservice.h create mode 100644 src/tor/rephist.c create mode 100644 src/tor/rephist.h create mode 100644 src/tor/replaycache.c create mode 100644 src/tor/replaycache.h create mode 100644 src/tor/router.c create mode 100644 src/tor/router.h create mode 100644 src/tor/routerlist.c create mode 100644 src/tor/routerlist.h create mode 100644 src/tor/routerparse.c create mode 100644 src/tor/routerparse.h create mode 100644 src/tor/routerset.c create mode 100644 src/tor/routerset.h create mode 100644 src/tor/sandbox.c create mode 100644 src/tor/sandbox.h create mode 100644 src/tor/statefile.c create mode 100644 src/tor/statefile.h create mode 100644 src/tor/status.c create mode 100644 src/tor/status.h create mode 100644 src/tor/strlcat.c create mode 100644 src/tor/strlcpy.c create mode 100644 src/tor/testsupport.h create mode 100644 src/tor/tinytest.h create mode 100644 src/tor/tinytest_macros.h create mode 100644 src/tor/tor_compat.h create mode 100644 src/tor/tor_queue.h create mode 100644 src/tor/tor_util.c create mode 100644 src/tor/tor_util.h create mode 100644 src/tor/torgzip.c create mode 100644 src/tor/torgzip.h create mode 100644 src/tor/torint.h create mode 100644 src/tor/torlog.h create mode 100644 src/tor/tortls.c create mode 100644 src/tor/tortls.h create mode 100644 src/tor/transports.c create mode 100644 src/tor/transports.h create mode 100644 src/tor/util_codedigest.c create mode 100644 src/ui_interface.h create mode 100644 src/uint256.h create mode 100644 src/util.cpp create mode 100644 src/util.h create mode 100644 src/version.cpp create mode 100644 src/version.h create mode 100644 src/wallet.cpp create mode 100644 src/wallet.h create mode 100644 src/walletdb.cpp create mode 100644 src/walletdb.h create mode 100644 triangles-qt.pro diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..ce7db4c --- /dev/null +++ b/COPYING @@ -0,0 +1,22 @@ +Copyright (c) 2014 triangles Developers +Copyright (c) 2013 NovaCoin Developers +Copyright (c) 2011-2012 PPCoin Developers +Copyright (c) 2009-2012 Bitcoin Developers + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/INSTALL b/INSTALL new file mode 100644 index 0000000..5039fbc --- /dev/null +++ b/INSTALL @@ -0,0 +1,9 @@ +Building triangles + +See doc/readme-qt.rst for instructions on building triangles QT, +the intended-for-end-users, nice-graphical-interface, reference +implementation of triangles. + +See doc/build-*.txt for instructions on building trianglesd, +the intended-for-services, no-graphical-interface, reference +implementation of triangles. diff --git a/README b/README new file mode 100644 index 0000000..b43bf86 --- /dev/null +++ b/README @@ -0,0 +1 @@ +README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..922c794 --- /dev/null +++ b/README.md @@ -0,0 +1,6 @@ +Triangles (TRI) Release + +triangles is a cool new crypto currency that will feature a uniquely implemented anonymization feature that uses exchanges on the back end and a decoupled transaction flow architecture. + +This wallet supports the staking=0 option in the triangles.conf file to disable the stake miner thread for pool and exchange operators. + diff --git a/contrib/bitrpc/bitrpc.py b/contrib/bitrpc/bitrpc.py new file mode 100644 index 0000000..b02b299 --- /dev/null +++ b/contrib/bitrpc/bitrpc.py @@ -0,0 +1,324 @@ +from jsonrpc import ServiceProxy +import sys +import string + +# ===== BEGIN USER SETTINGS ===== +# if you do not set these you will be prompted for a password for every command +rpcuser = "" +rpcpass = "" +# ====== END USER SETTINGS ====== + + +if rpcpass == "": + access = ServiceProxy("http://127.0.0.1:8332") +else: + access = ServiceProxy("http://"+rpcuser+":"+rpcpass+"@127.0.0.1:8332") +cmd = sys.argv[1].lower() + +if cmd == "backupwallet": + try: + path = raw_input("Enter destination path/filename: ") + print access.backupwallet(path) + except: + print "\n---An error occurred---\n" + +elif cmd == "getaccount": + try: + addr = raw_input("Enter a Bitcoin address: ") + print access.getaccount(addr) + except: + print "\n---An error occurred---\n" + +elif cmd == "getaccountaddress": + try: + acct = raw_input("Enter an account name: ") + print access.getaccountaddress(acct) + except: + print "\n---An error occurred---\n" + +elif cmd == "getaddressesbyaccount": + try: + acct = raw_input("Enter an account name: ") + print access.getaddressesbyaccount(acct) + except: + print "\n---An error occurred---\n" + +elif cmd == "getbalance": + try: + acct = raw_input("Enter an account (optional): ") + mc = raw_input("Minimum confirmations (optional): ") + try: + print access.getbalance(acct, mc) + except: + print access.getbalance() + except: + print "\n---An error occurred---\n" + +elif cmd == "getblockbycount": + try: + height = raw_input("Height: ") + print access.getblockbycount(height) + except: + print "\n---An error occurred---\n" + +elif cmd == "getblockcount": + try: + print access.getblockcount() + except: + print "\n---An error occurred---\n" + +elif cmd == "getblocknumber": + try: + print access.getblocknumber() + except: + print "\n---An error occurred---\n" + +elif cmd == "getconnectioncount": + try: + print access.getconnectioncount() + except: + print "\n---An error occurred---\n" + +elif cmd == "getdifficulty": + try: + print access.getdifficulty() + except: + print "\n---An error occurred---\n" + +elif cmd == "getgenerate": + try: + print access.getgenerate() + except: + print "\n---An error occurred---\n" + +elif cmd == "gethashespersec": + try: + print access.gethashespersec() + except: + print "\n---An error occurred---\n" + +elif cmd == "getinfo": + try: + print access.getinfo() + except: + print "\n---An error occurred---\n" + +elif cmd == "getnewaddress": + try: + acct = raw_input("Enter an account name: ") + try: + print access.getnewaddress(acct) + except: + print access.getnewaddress() + except: + print "\n---An error occurred---\n" + +elif cmd == "getreceivedbyaccount": + try: + acct = raw_input("Enter an account (optional): ") + mc = raw_input("Minimum confirmations (optional): ") + try: + print access.getreceivedbyaccount(acct, mc) + except: + print access.getreceivedbyaccount() + except: + print "\n---An error occurred---\n" + +elif cmd == "getreceivedbyaddress": + try: + addr = raw_input("Enter a Bitcoin address (optional): ") + mc = raw_input("Minimum confirmations (optional): ") + try: + print access.getreceivedbyaddress(addr, mc) + except: + print access.getreceivedbyaddress() + except: + print "\n---An error occurred---\n" + +elif cmd == "gettransaction": + try: + txid = raw_input("Enter a transaction ID: ") + print access.gettransaction(txid) + except: + print "\n---An error occurred---\n" + +elif cmd == "getwork": + try: + data = raw_input("Data (optional): ") + try: + print access.gettransaction(data) + except: + print access.gettransaction() + except: + print "\n---An error occurred---\n" + +elif cmd == "help": + try: + cmd = raw_input("Command (optional): ") + try: + print access.help(cmd) + except: + print access.help() + except: + print "\n---An error occurred---\n" + +elif cmd == "listaccounts": + try: + mc = raw_input("Minimum confirmations (optional): ") + try: + print access.listaccounts(mc) + except: + print access.listaccounts() + except: + print "\n---An error occurred---\n" + +elif cmd == "listreceivedbyaccount": + try: + mc = raw_input("Minimum confirmations (optional): ") + incemp = raw_input("Include empty? (true/false, optional): ") + try: + print access.listreceivedbyaccount(mc, incemp) + except: + print access.listreceivedbyaccount() + except: + print "\n---An error occurred---\n" + +elif cmd == "listreceivedbyaddress": + try: + mc = raw_input("Minimum confirmations (optional): ") + incemp = raw_input("Include empty? (true/false, optional): ") + try: + print access.listreceivedbyaddress(mc, incemp) + except: + print access.listreceivedbyaddress() + except: + print "\n---An error occurred---\n" + +elif cmd == "listtransactions": + try: + acct = raw_input("Account (optional): ") + count = raw_input("Number of transactions (optional): ") + frm = raw_input("Skip (optional):") + try: + print access.listtransactions(acct, count, frm) + except: + print access.listtransactions() + except: + print "\n---An error occurred---\n" + +elif cmd == "move": + try: + frm = raw_input("From: ") + to = raw_input("To: ") + amt = raw_input("Amount:") + mc = raw_input("Minimum confirmations (optional): ") + comment = raw_input("Comment (optional): ") + try: + print access.move(frm, to, amt, mc, comment) + except: + print access.move(frm, to, amt) + except: + print "\n---An error occurred---\n" + +elif cmd == "sendfrom": + try: + frm = raw_input("From: ") + to = raw_input("To: ") + amt = raw_input("Amount:") + mc = raw_input("Minimum confirmations (optional): ") + comment = raw_input("Comment (optional): ") + commentto = raw_input("Comment-to (optional): ") + try: + print access.sendfrom(frm, to, amt, mc, comment, commentto) + except: + print access.sendfrom(frm, to, amt) + except: + print "\n---An error occurred---\n" + +elif cmd == "sendmany": + try: + frm = raw_input("From: ") + to = raw_input("To (in format address1:amount1,address2:amount2,...): ") + mc = raw_input("Minimum confirmations (optional): ") + comment = raw_input("Comment (optional): ") + try: + print access.sendmany(frm,to,mc,comment) + except: + print access.sendmany(frm,to) + except: + print "\n---An error occurred---\n" + +elif cmd == "sendtoaddress": + try: + to = raw_input("To (in format address1:amount1,address2:amount2,...): ") + amt = raw_input("Amount:") + comment = raw_input("Comment (optional): ") + commentto = raw_input("Comment-to (optional): ") + try: + print access.sendtoaddress(to,amt,comment,commentto) + except: + print access.sendtoaddress(to,amt) + except: + print "\n---An error occurred---\n" + +elif cmd == "setaccount": + try: + addr = raw_input("Address: ") + acct = raw_input("Account:") + print access.setaccount(addr,acct) + except: + print "\n---An error occurred---\n" + +elif cmd == "setgenerate": + try: + gen= raw_input("Generate? (true/false): ") + cpus = raw_input("Max processors/cores (-1 for unlimited, optional):") + try: + print access.setgenerate(gen, cpus) + except: + print access.setgenerate(gen) + except: + print "\n---An error occurred---\n" + +elif cmd == "settxfee": + try: + amt = raw_input("Amount:") + print access.settxfee(amt) + except: + print "\n---An error occurred---\n" + +elif cmd == "stop": + try: + print access.stop() + except: + print "\n---An error occurred---\n" + +elif cmd == "validateaddress": + try: + addr = raw_input("Address: ") + print access.validateaddress(addr) + except: + print "\n---An error occurred---\n" + +elif cmd == "walletpassphrase": + try: + pwd = raw_input("Enter wallet passphrase: ") + access.walletpassphrase(pwd, 60) + print "\n---Wallet unlocked---\n" + except: + print "\n---An error occurred---\n" + +elif cmd == "walletpassphrasechange": + try: + pwd = raw_input("Enter old wallet passphrase: ") + pwd2 = raw_input("Enter new wallet passphrase: ") + access.walletpassphrasechange(pwd, pwd2) + print + print "\n---Passphrase changed---\n" + except: + print + print "\n---An error occurred---\n" + print + +else: + print "Command not found or not supported" \ No newline at end of file diff --git a/contrib/gitian-descriptors/README b/contrib/gitian-descriptors/README new file mode 100644 index 0000000..a2d902e --- /dev/null +++ b/contrib/gitian-descriptors/README @@ -0,0 +1,31 @@ +Gavin's notes on getting gitian builds up and running: + +You need the right hardware: you need a 64-bit-capable CPU with hardware virtualization support (Intel VT-x or AMD-V). Not all modern CPUs support hardware virtualization. + +You probably need to enable hardware virtualization in your machine's BIOS. + +You need to be running a recent version of 64-bit-Ubuntu, and you need to install several prerequisites: + sudo apt-get install apache2 git apt-cacher-ng python-vm-builder qemu-kvm + +Sanity checks: + sudo service apt-cacher-ng status # Should return apt-cacher-ng is running + ls -l /dev/kvm # Should show a /dev/kvm device + +Once you've got the right hardware and software: + + git clone git://github.com/bitcoin/bitcoin.git + git clone git://github.com/devrandom/gitian-builder.git + mkdir gitian-builder/inputs + wget 'http://miniupnp.tuxfamily.org/files/download.php?file=miniupnpc-1.6.tar.gz' -O gitian-builder/inputs/miniupnpc-1.6.tar.gz + + cd gitian-builder + bin/make-base-vm --arch i386 + bin/make-base-vm --arch amd64 + cd .. + + # To build + cd bitcoin + git pull + cd ../gitian-builder + git pull + ./bin/gbuild --commit bitcoin=HEAD ../bitcoin/contrib/gitian.yml diff --git a/contrib/gitian-descriptors/boost-win32.yml b/contrib/gitian-descriptors/boost-win32.yml new file mode 100644 index 0000000..61ea50e --- /dev/null +++ b/contrib/gitian-descriptors/boost-win32.yml @@ -0,0 +1,38 @@ +--- +name: "boost" +suites: +- "lucid" +architectures: +- "i386" +packages: +- "mingw32" +- "faketime" +- "zip" +reference_datetime: "2011-01-30 00:00:00" +remotes: [] +files: +- "boost_1_47_0.tar.bz2" +script: | + TMPDIR="$HOME/tmpdir" + mkdir -p $TMPDIR/bin/$GBUILD_BITS $TMPDIR/include + tar xjf boost_1_47_0.tar.bz2 + cd boost_1_47_0 + echo "using gcc : 4.4 : i586-mingw32msvc-g++ + : + i586-mingw32msvc-windres + i586-mingw32msvc-ar + -frandom-seed=boost1 + ;" > user-config.jam + ./bootstrap.sh --without-icu + ./bjam toolset=gcc target-os=windows threadapi=win32 threading=multi variant=release link=static --user-config=user-config.jam --without-mpi --without-python -sNO_BZIP2=1 -sNO_ZLIB=1 --layout=tagged --build-type=complete $MAKEOPTS stage + for lib in chrono date_time exception filesystem graph iostreams math_c99f math_c99l math_c99 math_tr1f math_tr1l math_tr1 prg_exec_monitor program_options random regex serialization signals system test_exec_monitor thread_win32 unit_test_framework wave wserialization; do + mkdir $lib + (cd $lib ; ar xf ../stage/lib/libboost_${lib}-mt-s.a) + mv $lib $TMPDIR/bin/$GBUILD_BITS + done + cp -a boost $TMPDIR/include + cd $TMPDIR + export LD_PRELOAD=/usr/lib/faketime/libfaketime.so.1 + export FAKETIME=$REFERENCE_DATETIME + zip -r boost-win32-1.47.0-gitian.zip * + cp boost-win32-1.47.0-gitian.zip $OUTDIR diff --git a/contrib/gitian-descriptors/deps-win32.yml b/contrib/gitian-descriptors/deps-win32.yml new file mode 100644 index 0000000..62b67ee --- /dev/null +++ b/contrib/gitian-descriptors/deps-win32.yml @@ -0,0 +1,71 @@ +--- +name: "bitcoin-deps" +suites: +- "lucid" +architectures: +- "i386" +packages: +- "mingw32" +- "git-core" +- "zip" +- "faketime" +- "wine" +reference_datetime: "2011-01-30 00:00:00" +remotes: [] +files: +- "openssl-1.0.1b.tar.gz" +- "db-4.8.30.NC.tar.gz" +- "miniupnpc-1.6.tar.gz" +- "zlib-1.2.7.tar.gz" +- "libpng-1.5.12.tar.gz" +- "qrencode-3.2.0.tar.bz2" +script: | + # + export LD_PRELOAD=/usr/lib/faketime/libfaketime.so.1 + export FAKETIME=$REFERENCE_DATETIME + export TZ=UTC + # + tar xzf openssl-1.0.1b.tar.gz + cd openssl-1.0.1b + ./Configure --cross-compile-prefix=i586-mingw32msvc- mingw + make + cd .. + # + tar xzf db-4.8.30.NC.tar.gz + cd db-4.8.30.NC/build_unix + ../dist/configure --enable-mingw --enable-cxx --host=i586-mingw32msvc CFLAGS="-I/usr/i586-mingw32msvc/include" + make $MAKEOPTS + cd ../.. + # + tar xzf miniupnpc-1.6.tar.gz + cd miniupnpc-1.6 + sed 's/dllwrap -k --driver-name gcc/$(DLLWRAP) -k --driver-name $(CC)/' -i Makefile.mingw + sed 's|wingenminiupnpcstrings $< $@|./wingenminiupnpcstrings $< $@|' -i Makefile.mingw + make -f Makefile.mingw DLLWRAP=i586-mingw32msvc-dllwrap CC=i586-mingw32msvc-gcc AR=i586-mingw32msvc-ar + cd .. + mv miniupnpc-1.6 miniupnpc + # + tar xzf zlib-1.2.7.tar.gz + cd zlib-1.2.7 + make -f win32/Makefile.gcc PREFIX=i586-mingw32msvc- $MAKEOPTS + cd .. + # + tar xzf libpng-1.5.12.tar.gz + cd libpng-1.5.12 + ./configure -disable-shared CC=i586-mingw32msvc-cc AR=i586-mingw32msvc-ar STRIP=i586-mingw32msvc-strip RANLIB=i586-mingw32msvc-ranlib OBJDUMP=i586-mingw32msvc-objdump LD=i586-mingw32msvc-ld LDFLAGS="-L../zlib-1.2.7/" CFLAGS="-I../zlib-1.2.7/" + make $MAKEOPTS + cd .. + # + tar xjf qrencode-3.2.0.tar.bz2 + cd qrencode-3.2.0 + ./configure CC=i586-mingw32msvc-cc AR=i586-mingw32msvc-ar STRIP=i586-mingw32msvc-strip RANLIB=i586-mingw32msvc-ranlib OBJDUMP=i586-mingw32msvc-objdump LD=i586-mingw32msvc-ld png_LIBS="../libpng-1.5.12/.libs/libpng15.a ../zlib-1.2.7/libz.a" png_CFLAGS="-I../libpng-1.5.12" + make $MAKEOPTS + cd .. + # + zip -r $OUTDIR/ppcoin-deps-0.0.1.zip \ + $(ls qrencode-*/{qrencode.h,.libs/libqrencode.{,l}a} | sort) \ + $(ls db-*/build_unix/{libdb_cxx.a,db.h,db_cxx.h,libdb.a,.libs/libdb_cxx-?.?.a} | sort) \ + $(find openssl-* -name '*.a' -o -name '*.h' | sort) \ + $(find miniupnpc -name '*.h' -o -name 'libminiupnpc.a' | sort) + # Kill wine processes as gitian won't figure out we are done otherwise + killall wineserver services.exe explorer.exe winedevice.exe diff --git a/contrib/gitian-descriptors/gitian-win32.yml b/contrib/gitian-descriptors/gitian-win32.yml new file mode 100644 index 0000000..2bf3a7d --- /dev/null +++ b/contrib/gitian-descriptors/gitian-win32.yml @@ -0,0 +1,74 @@ +--- +name: "ppcoin" +suites: +- "lucid" +architectures: +- "i386" +packages: +- "mingw32" +- "git-core" +- "unzip" +- "nsis" +- "faketime" +reference_datetime: "2011-01-30 00:00:00" +remotes: +- "url": "https://github.com/ppcoin/ppcoin.git" + "dir": "ppcoin" +files: +- "qt-win32-4.7.4-gitian.zip" +- "boost-win32-1.47.0-gitian.zip" +- "ppcoin-deps-0.0.1.zip" +script: | + # + mkdir $HOME/qt + cd $HOME/qt + unzip ../build/qt-win32-4.7.4-gitian.zip + cd $HOME/build/ + export PATH=$PATH:$HOME/qt/bin/ + # + mkdir boost_1_47_0 + cd boost_1_47_0 + mkdir -p stage/lib + unzip ../boost-win32-1.47.0-gitian.zip + cd bin/$GBUILD_BITS + for lib in *; do + i586-mingw32msvc-ar rc ../../stage/lib/libboost_${lib}-mt-s.a $lib/*.o + i586-mingw32msvc-ranlib ../../stage/lib/libboost_${lib}-mt-s.a + done + cd ../.. + mv include/boost . + cd .. + # + unzip ppcoin-deps-0.0.1.zip + # + find -type f | xargs touch --date="$REFERENCE_DATETIME" + # + cd ppcoin + mkdir -p $OUTDIR/src + git archive HEAD | tar -x -C $OUTDIR/src + cp $OUTDIR/src/doc/README_windows.txt $OUTDIR/readme.txt + cp $OUTDIR/src/COPYING $OUTDIR/license.txt + export LD_PRELOAD=/usr/lib/faketime/libfaketime.so.1 + export FAKETIME=$REFERENCE_DATETIME + export TZ=UTC + $HOME/qt/src/bin/qmake -spec unsupported/win32-g++-cross MINIUPNPC_LIB_PATH=$HOME/build/miniupnpc MINIUPNPC_INCLUDE_PATH=$HOME/build/ BDB_LIB_PATH=$HOME/build/db-4.8.30.NC/build_unix BDB_INCLUDE_PATH=$HOME/build/db-4.8.30.NC/build_unix BOOST_LIB_PATH=$HOME/build/boost_1_47_0/stage/lib BOOST_INCLUDE_PATH=$HOME/build/boost_1_47_0 BOOST_LIB_SUFFIX=-mt-s BOOST_THREAD_LIB_SUFFIX=_win32-mt-s OPENSSL_LIB_PATH=$HOME/build/openssl-1.0.1b OPENSSL_INCLUDE_PATH=$HOME/build/openssl-1.0.1b/include QRENCODE_LIB_PATH=$HOME/build/qrencode-3.2.0/.libs QRENCODE_INCLUDE_PATH=$HOME/build/qrencode-3.2.0 USE_QRCODE=1 INCLUDEPATH=$HOME/build DEFINES=BOOST_THREAD_USE_LIB BITCOIN_NEED_QT_PLUGINS=1 QMAKE_LRELEASE=lrelease QMAKE_CXXFLAGS=-frandom-seed=ppcoin QMAKE_LFLAGS=-frandom-seed=ppcoin USE_BUILD_INFO=1 + make $MAKEOPTS + cp release/ppcoin-qt.exe $OUTDIR/ + # + cd src + export LD_PRELOAD=/usr/lib/faketime/libfaketime.so.1 + export FAKETIME=$REFERENCE_DATETIME + export TZ=UTC + make -f makefile.linux-mingw $MAKEOPTS DEPSDIR=$HOME/build ppcoind.exe USE_UPNP=1 DEBUGFLAGS="-frandom-seed=ppcoin" + i586-mingw32msvc-strip ppcoind.exe + mkdir $OUTDIR/daemon + cp ppcoind.exe $OUTDIR/daemon + cd .. + mkdir nsis + git archive HEAD | tar -x -C nsis + cd nsis/src + mkdir ../release + cp ../../release/* ../release/ + cp ../../src/*.exe . + makensis ../share/setup.nsi + cp ../share/ppcoin-*-win32-setup.exe $OUTDIR/ diff --git a/contrib/gitian-descriptors/gitian.yml b/contrib/gitian-descriptors/gitian.yml new file mode 100644 index 0000000..340de5e --- /dev/null +++ b/contrib/gitian-descriptors/gitian.yml @@ -0,0 +1,56 @@ +--- +name: "ppcoin" +suites: +- "lucid" +architectures: +- "i386" +- "amd64" +packages: +- "libdb4.8++-dev" +- "qt4-qmake" +- "libqt4-dev" +- "libboost-system-dev" +- "libboost-filesystem-dev" +- "libboost-program-options-dev" +- "libboost-thread-dev" +- "libssl-dev" +- "git-core" +- "unzip" +- "pkg-config" +- "libpng12-dev" +reference_datetime: "2011-01-30 00:00:00" +remotes: +- "url": "https://github.com/ppcoin/ppcoin.git" + "dir": "ppcoin" +files: +- "miniupnpc-1.6.tar.gz" +- "qrencode-3.2.0.tar.bz2" +script: | + INSTDIR="$HOME/install" + export LIBRARY_PATH="$INSTDIR/lib" + # + tar xzf miniupnpc-1.6.tar.gz + cd miniupnpc-1.6 + INSTALLPREFIX=$INSTDIR make $MAKEOPTS install + cd .. + # + tar xjf qrencode-3.2.0.tar.bz2 + cd qrencode-3.2.0 + ./configure --prefix=$INSTDIR --enable-static --disable-shared + make $MAKEOPTS install + cd .. + # + cd ppcoin + mkdir -p $OUTDIR/src + git archive HEAD | tar -x -C $OUTDIR/src + cp $OUTDIR/src/doc/README $OUTDIR + cp $OUTDIR/src/COPYING $OUTDIR + cd src + make -f makefile.unix STATIC=1 OPENSSL_INCLUDE_PATH="$INSTDIR/include" OPENSSL_LIB_PATH="$INSTDIR/lib" $MAKEOPTS ppcoind USE_UPNP=1 DEBUGFLAGS= + mkdir -p $OUTDIR/bin/$GBUILD_BITS + install -s ppcoind $OUTDIR/bin/$GBUILD_BITS + # + cd .. + qmake INCLUDEPATH="$INSTDIR/include" LIBS="-L$INSTDIR/lib" RELEASE=1 USE_QRCODE=1 + make $MAKEOPTS + install ppcoin-qt $OUTDIR/bin/$GBUILD_BITS diff --git a/contrib/gitian-descriptors/qt-win32.yml b/contrib/gitian-descriptors/qt-win32.yml new file mode 100644 index 0000000..6eb76b2 --- /dev/null +++ b/contrib/gitian-descriptors/qt-win32.yml @@ -0,0 +1,54 @@ +--- +name: "qt" +suites: +- "lucid" +architectures: +- "i386" +packages: +- "mingw32" +- "zip" +- "faketime" +reference_datetime: "2011-01-30 00:00:00" +remotes: [] +files: +- "qt-everywhere-opensource-src-4.7.4.tar.gz" +script: | + INSTDIR="$HOME/qt/" + mkdir $INSTDIR + SRCDIR="$INSTDIR/src/" + mkdir $SRCDIR + # + tar xzf qt-everywhere-opensource-src-4.7.4.tar.gz + cd qt-everywhere-opensource-src-4.7.4 + sed 's/$TODAY/2011-01-30/' -i configure + sed 's/i686-pc-mingw32-/i586-mingw32msvc-/' -i mkspecs/unsupported/win32-g++-cross/qmake.conf + sed --posix 's|QMAKE_CFLAGS\t\t= -pipe|QMAKE_CFLAGS\t\t= -pipe -isystem /usr/i586-mingw32msvc/include/ -frandom-seed=qtbuild|' -i mkspecs/unsupported/win32-g++-cross/qmake.conf + sed 's/QMAKE_CXXFLAGS_EXCEPTIONS_ON = -fexceptions -mthreads/QMAKE_CXXFLAGS_EXCEPTIONS_ON = -fexceptions/' -i mkspecs/unsupported/win32-g++-cross/qmake.conf + sed 's/QMAKE_LFLAGS_EXCEPTIONS_ON = -mthreads/QMAKE_LFLAGS_EXCEPTIONS_ON = -lmingwthrd/' -i mkspecs/unsupported/win32-g++-cross/qmake.conf + sed --posix 's/QMAKE_MOC\t\t= i586-mingw32msvc-moc/QMAKE_MOC\t\t= moc/' -i mkspecs/unsupported/win32-g++-cross/qmake.conf + sed --posix 's/QMAKE_RCC\t\t= i586-mingw32msvc-rcc/QMAKE_RCC\t\t= rcc/' -i mkspecs/unsupported/win32-g++-cross/qmake.conf + sed --posix 's/QMAKE_UIC\t\t= i586-mingw32msvc-uic/QMAKE_UIC\t\t= uic/' -i mkspecs/unsupported/win32-g++-cross/qmake.conf + # ar adds timestamps to every object file included in the static library + # providing -D as ar argument is supposed to solve it, but doesn't work as qmake strips off the arguments and adds -M to pass a script... + # which somehow cannot be combined with other flags. + # use faketime only for ar, as it confuses make/qmake into hanging sometimes + sed --posix "s|QMAKE_LIB\t\t= i586-mingw32msvc-ar -ru|QMAKE_LIB\t\t= $HOME/ar -Dr|" -i mkspecs/unsupported/win32-g++-cross/qmake.conf + echo '#!/bin/bash' > $HOME/ar + echo 'export LD_PRELOAD=/usr/lib/faketime/libfaketime.so.1' >> $HOME/ar + echo 'i586-mingw32msvc-ar "$@"' >> $HOME/ar + chmod +x $HOME/ar + #export LD_PRELOAD=/usr/lib/faketime/libfaketime.so.1 + export FAKETIME=$REFERENCE_DATETIME + export TZ=UTC + ./configure -prefix $INSTDIR -confirm-license -release -opensource -static -no-qt3support -xplatform unsupported/win32-g++-cross -no-multimedia -no-audio-backend -no-phonon -no-phonon-backend -no-declarative -no-script -no-scripttools -no-javascript-jit -no-webkit -no-svg -no-xmlpatterns -no-sql-sqlite -no-nis -no-cups -no-iconv -no-dbus -no-gif -no-libtiff -opengl no -nomake examples -nomake demos -nomake docs + find . -name *.prl | xargs -l sed 's|/\.||' -i + find . -name *.prl | xargs -l sed 's|/$||' -i + make $MAKEOPTS install + cp -a bin $SRCDIR/ + cd $INSTDIR + find . -name *.prl | xargs -l sed 's|/$||' -i + #sed 's|QMAKE_PRL_LIBS.*|QMAKE_PRL_LIBS = -lQtDeclarative -lQtScript -lQtSvg -lQtSql -lQtXmlPatterns -lQtGui -lgdi32 -lcomdlg32 -loleaut32 -limm32 -lwinmm -lwinspool -lmsimg32 -lQtNetwork -lQtCore -lole32 -luuid -lws2_32 -ladvapi32 -lshell32 -luser32 -lkernel32|' -i imports/Qt/labs/particles/qmlparticlesplugin.prl + + # as zip stores file timestamps, use faketime to intercept stat calls to set dates for all files to reference date + export LD_PRELOAD=/usr/lib/faketime/libfaketime.so.1 + zip -r $OUTDIR/qt-win32-4.7.4-gitian.zip * diff --git a/contrib/gitian-downloader/bluematt-key.pgp b/contrib/gitian-downloader/bluematt-key.pgp new file mode 100644 index 0000000000000000000000000000000000000000..fb6d9eb28423d2c8ece89179f8e67ae06fa6dc13 GIT binary patch literal 4113 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 literal 0 HcmV?d00001 diff --git a/contrib/gitian-downloader/gavinandresen-key.pgp b/contrib/gitian-downloader/gavinandresen-key.pgp new file mode 100644 index 0000000000000000000000000000000000000000..f81f44e874707837c13446858db2fed14ad5c501 GIT binary patch literal 1176 zcmV;J1ZVr10ipyd+BPOXG1ZrDpv%iXyY*~=|+SlmVRJ2@d|5G=3lw%C&g;j0KvRW zG0RVD!3nRuh%R)pia&~L1FEOGx;eXR*K` zu*WO05N?XC!C+-X<8ovFvIpC&fxEyfX(2{j!G#JZ7?CU%mrw)$TSGNqq(L>S_EMhm z>C$tB193UkB)z)vhMWgbGCTvPxP}Kfdx0GIl8t06ZPII(&3kQCzEXv7#M)%vPj{EY zcen(gIU`UxU-nd2`Gon+|B_0Ff*@;+F`bIwREZv?xbmc4=-PL2hJnWpib2AUtPbc4=;5Ze((0b7gKoXKi6=Y%XJO zZ9a%*1QQVg044HzfCdW*2nPcK1Qh}Z0|XWV0|5da0Rk6*0162Z zb%-P{zBtpUe6IkY$jlON2g&-~!PtabhH%KRx;RqM0G%3)n>ot_(%$#C+gXU@atMHu zy_C5E4FpWQvb7Kh0Lyf?4-i~4^f3$`ga{Ay5*wreKf>2lV6ywp8d}7ENW=D%ux6^* zfe_#szOQ3V{y*tz7?DrDyfq@LWFCHCr%@-(h(6PCP!Kw9x74URPC$@TblGE?^C!T- zq8)?0%b0~_Ytjnul$QnT9RS<*D5dmu1n$x{uRAV*zh*N+8p9}Ho%Pe)*0 zMnEdZ`oH?%L4~7A1F_aQ|8Rcjri-TI9EL4W#QMcIXrNTVrH)rvOHg%{!T`G$1?>8K zRy|m)M}%VOrUsN$>#AQvZnPq$teX`yY;D;>tsyDHK5Qtj#S?asN{)W{exHw@bhzOU z9^1V{J3(+Kj{pM&2mgPBEamX!SrHwdYa^4uCaz(-f7?+0M)V2mw#6{WkHkn8b1R-^ zYDL+eN?p#i&&iBy&Go@UU6MyD*c7YSQ3wLLX`?CdU~}FpEb`VEVP6+=?&FSbCm=k@ z&d1&vM(f=F5d18_%WVyD>j@@JhkmOlWQELtPqF$CFI z6&Wk2#X|#%!_kOO1Q-zl01pKMOuVwS0vikk2`>HzfB*^!5Os(oFTOa_s4)oupKEmm q7ky6Gg$kN{t|V0xiYY!|8vvlVg5(~9gx$G(luB9`Z;BnEL2B3d)*1@{ literal 0 HcmV?d00001 diff --git a/contrib/gitian-downloader/laanwj-key.pgp b/contrib/gitian-downloader/laanwj-key.pgp new file mode 100644 index 0000000..5592951 --- /dev/null +++ b/contrib/gitian-downloader/laanwj-key.pgp @@ -0,0 +1,28 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: SKS 1.1.0 + +mQENBE5UtMEBCADOUz2i9l/D8xYINCmfUDnxi+DXvX5LmZ39ZdvsoE+ugO0SRRGdIHEFO2is +0xezX50wXu9aneb+tEqM0BuiLo6VxaXpxrkxHpr6c4jf37SkE/H0qsi/txEUp7337y3+4HMG +lUjiuh802I72p1qusjsKBnmnnR0rwNouTcoDmGUDh7jpKCtzFv+2TR2dRthJn7vmmjq3+bG6 +PYfqoFY1yHrAGT1lrDBULZsQ/NBLI2+J4oo2LYv3GCq8GNnzrovqvTvui50VSROhLrOe58o2 +shE+sjQShAy5wYkPt1R1fQnpfx+5vf+TPnkxVwRb3h5GhCp0YL8XC/BXsd5vM4KlVH2rABEB +AAG0K1dsYWRpbWlyIEouIHZhbiBkZXIgTGFhbiA8bGFhbndqQGdtYWlsLmNvbT6JATgEEwEC +ACIFAk5UtMECGwMGCwkIBwMCBhUIAgkKCwQWAgMBAh4BAheAAAoJEHSBCwEjRsmmy6YIAK09 +buNXyYQrJBsX16sXxEhx5QPKyF3uHJDFJv66SdnpvIkNoznsaPiRJkbTANop93FZmaGa6wVn +zGDiz7jPA8Dpxx5aAYPhIT+zPJAdXWM3wJ/Gio9besRNzniai8Lwi5MZ9R/5yFGBobm6/AcN +4sUoqA3NSV2U3I29R0Vwlzo8GVtmyi9ENSi6Oo7AcXNTRt69cxW4nAHkB+amwwDJlcAb31ex +bogYXPhScwqQZixRr+JBkKxBjkTXXnQypT4KI5SegYwQVYfyiZmDP7UHKe/u6pSKKbVphLg8 +xLB5spcXse8/a2+onrbNlw6y8TXiJ++Z54PE7zztWTXf2huakeG5AQ0ETlS0wQEIAMNO3OkP +xoPRKWzBLcI7JRITAW+HNaLTq3uN2+4WxA57DEjbL9EDoAv+7wTkDAL40f0T+xiu6GJcLFjw +GJZu/tYu7+mErHjrdo+K4suCQt7w5EXCBvOLjhW4tyYMzNx8hP+oqzOW9iEC+6VV91+DYeqt +EkJuyVXOI4vzBlTw8uGow8aMMsCq8XVvKUZFTPsjGl197Q5B3A+ZOFCR8xqiqdPjuz6MglVV +oFdDNu3EZn8zkGsQlovXoE9ndVeVzx/XMNmsxFaMYsReUs253RIf1FEfgExID0fg2OnyLCjS +2iFW1RgajS+/saIkKl+N1iuMzJA7wMAM0plhRueOG0MtZSsAEQEAAYkBHwQYAQIACQUCTlS0 +wQIbDAAKCRB0gQsBI0bJpmsDB/4waenn2CvSHXyomykfpwf5lMte1V5LvH3z5R2LY+1NopRv +LSz3iC39x69XWiTbhywDfgafnGPW4pWBOff2/bu5/A6z1Hnan1vyrRRD/hx1uMJ7S6q+bIvZ +iVIg1p0jH6tdIIhwX3cydhdRZHo7e9oSMgOUWsr6Ar59NRo9CENwGPE4U61HXfOnxWdrFWoA +XdwZczBeLxmUy6Vo6sKqv+gE4bqrtAM0sY/MsQ9cU95x+52ox/sq44lQMwd3ZBYUP7B1qbHI +hZSZuch6MLi5scLPeau0ZvCaljiaMeivP5+x0gWPRs0kI+9sZxInbqvrsJ6oOBJM3xYGhtn1 +zZ7qmZR7 +=si/k +-----END PGP PUBLIC KEY BLOCK----- diff --git a/contrib/gitian-downloader/linux-download-config b/contrib/gitian-downloader/linux-download-config new file mode 100644 index 0000000..aef614d --- /dev/null +++ b/contrib/gitian-downloader/linux-download-config @@ -0,0 +1,38 @@ +--- +name: bitcoin +urls: +- http://bitcoin.org/bitcoin-latest-linux-gitian.zip +rss: +- url: http://sourceforge.net/api/file/index/project-id/244765/mtime/desc/limit/100/rss + xpath: //item/link/text() + pattern: bitcoin-\d+.\d+.\d+-linux-gitian.zip +signers: + 0A82509767C7D4A5D14DA2301AE1D35043E08E54: + weight: 40 + name: BlueMatt + key: bluematt + BF6273FAEF7CC0BA1F562E50989F6B3048A116B5: + weight: 40 + name: Devrandom + key: devrandom + E463A93F5F3117EEDE6C7316BD02942421F4889F: + weight: 40 + name: Luke-Jr + key: luke-jr + D762373D24904A3E42F33B08B9A408E71DAAC974: + weight: 40 + name: "Pieter Wuille" + key: sipa + 77E72E69DA7EE0A148C06B21B34821D4944DE5F7: + weight: 40 + name: tcatm + key: tcatm + 01CDF4627A3B88AAE4A571C87588242FBE38D3A8: + weight: 40 + name: "Gavin Andresen" + key: gavinandresen + 71A3B16735405025D447E8F274810B012346C9A6: + weight: 40 + name: "Wladimir J. van der Laan" + key: laanwj +minimum_weight: 120 diff --git a/contrib/gitian-downloader/luke-jr-key.pgp b/contrib/gitian-downloader/luke-jr-key.pgp new file mode 100644 index 0000000000000000000000000000000000000000..c40917d78c512ac13414b0d9e92c59f57e6a9c77 GIT binary patch literal 5467 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 CBINY| literal 0 HcmV?d00001 diff --git a/contrib/gitian-downloader/sunnyking-key.gpg b/contrib/gitian-downloader/sunnyking-key.gpg new file mode 100644 index 0000000..16b2a40 --- /dev/null +++ b/contrib/gitian-downloader/sunnyking-key.gpg @@ -0,0 +1,52 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v1.4.10 (GNU/Linux) + +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 +KIjGheFAFTRFLgBmol4= +=Qxzm +-----END PGP PUBLIC KEY BLOCK----- diff --git a/contrib/gitian-downloader/tcatm-key.pgp b/contrib/gitian-downloader/tcatm-key.pgp new file mode 100644 index 0000000000000000000000000000000000000000..baaec76b8c656a04beb4a91155dff40658c87bd7 GIT binary patch literal 1554 zcmaLXdpOez7zgm}=ej6sb1Pa#8IlSy8m4eWF6A1DTv~I_jFQVZ%x!YXHIs5;lv2b&au>j&AO;b^5AaZw zS_2#|)T*hrzK+H*LHsz!|6K?Ku&VUx#NdeA@N5NXFT>aIOjxF zy4whds0=Oq(@2 zz5C0o8+C^w{_b)@?4r`gwi%FXMnpT2F%#BQYsG;hiPIg))5Y|!x1ZJex)A$MiNNX( zq6&=I<&6kZI1wW|8o{H$=I*P|T^9^$R+XKtQ`SnvhEOJ;uhQjn2CWkmj_^7`Aa3c- z8Zs}@d#(_b{reL%xnIYqQg<&4Shq?0ZMJt4#E_eu1;rw?zks%bLEvhXHQt|~VCQuq z&A-#OrVqAfk)-lg}vy7 zYs{BAGW}t+Bct766}J4~uIL-c)@4fnX~wI?{tt{!6ZM`1wc=GKOA;;?`>n3icWB0G zn*||8j}j?7(5Ob(-PQ-uJThqd2@S1uW*w1X-|9A4-%6Qux^GMLljXjQ)sN@kpv?VO z)UkLWhmj->gnz;q!4owp@2yD~e{+z0Gz?Wg#-nKk+Qh}dVfq|kPnBUdp-;hvz)x2t zD?{SnDzor5MGJ>X13OouOQ(XXjf?e%bQ%eENi%61!fX|rVS*-fUgk}jZXdQS*=pu7 zn*l%)vEtxtnsfe78h_1@2}w%6!25|yQBmC1DEcXumbL82v@a7>)Mz3#h|4L`WPlN(+95yvu#{C!>gm(Nv!S*Yv%^(qS9*ha8g`_+-5KMB1k7w}O?nKX_$dgx0zKT> zsK@?(;%%efAn>h*Z*5Z>_ERN@VpIEg)VY;7&-da56_Nt)d)n(s{^moqKbzg#(kvLW z_g3p9;|WwT=QceTow#FuTvuyb#6|7txyOiS%w#V=}?{wnLKuU3K z)LKWy{tfcIT~3<;zL)*5y45%&9BU728+bn0YHD;;MHsu8*-lKYQs(yGsc3#7XH3FF z)6ZNg<)%-4Jo9KihD(yQ2p@45F;h{7b%utDjKt-eDI`%@T2fxC!k6(j540(SjvdEY z&4sPj$l9*nt{0{Ksm2XXNloeRVl7wfZyz{W@(szDaGi^F^8SE`Mg86EWbj@=+3$sw z5CVQYJU~ud2m(0|CjFY5huQFyjG2;4Ye>`;Or>jAW`VBfSSCzgV_T@{G&oZG zMZ&q+CGm;Gb?Vy`__|_oh6ILLkb2J~@O-;TLScpzuRgCrq~`N8>#L#y{$+GFo~DN* zIi%T&4(?=Dgd6kV_SqzM&HYCc@^&t@&q)T@niB6VT*F0pG7n11dnBi@v SyHEabV7`Cld{4j + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/contrib/macdeploy/background.png b/contrib/macdeploy/background.png new file mode 100644 index 0000000000000000000000000000000000000000..51dc01ac08f55952ddfcf115d0c3a829d8d2ac8d GIT binary patch literal 16606 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 Q6|rtySCcQ1HGTO105^iBbN~PV literal 0 HcmV?d00001 diff --git a/contrib/macdeploy/background.psd b/contrib/macdeploy/background.psd new file mode 100644 index 0000000000000000000000000000000000000000..e0a8c9ab9da81e052dfd9daa61e594462ef0e8fe GIT binary patch literal 66096 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%0D&E9M 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 SdW)#^7SZ=_%J{SE!2btPrJpkZ literal 0 HcmV?d00001 diff --git a/contrib/macdeploy/fancy.plist b/contrib/macdeploy/fancy.plist new file mode 100644 index 0000000..3468821 --- /dev/null +++ b/contrib/macdeploy/fancy.plist @@ -0,0 +1,32 @@ + + + + + window_bounds + + 300 + 300 + 800 + 620 + + background_picture + background.png + icon_size + 96 + applications_symlink + + items_position + + Applications + + 370 + 156 + + BlueChip-Qt.app + + 128 + 156 + + + + diff --git a/contrib/macdeploy/macdeployqtplus b/contrib/macdeploy/macdeployqtplus new file mode 100644 index 0000000..7981eca --- /dev/null +++ b/contrib/macdeploy/macdeployqtplus @@ -0,0 +1,758 @@ +#!/usr/bin/env python + +# +# Copyright (C) 2011 Patrick "p2k" Schneider +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +import subprocess, sys, re, os, shutil, stat, os.path +from string import Template +from time import sleep +from argparse import ArgumentParser + +# This is ported from the original macdeployqt with modifications + +class FrameworkInfo(object): + def __init__(self): + self.frameworkDirectory = "" + self.frameworkName = "" + self.frameworkPath = "" + self.binaryDirectory = "" + self.binaryName = "" + self.binaryPath = "" + self.version = "" + self.installName = "" + self.deployedInstallName = "" + self.sourceFilePath = "" + self.destinationDirectory = "" + self.sourceResourcesDirectory = "" + self.destinationResourcesDirectory = "" + + def __eq__(self, other): + if self.__class__ == other.__class__: + return self.__dict__ == other.__dict__ + else: + return False + + def __str__(self): + return """ Framework name: %s + Framework directory: %s + Framework path: %s + Binary name: %s + Binary directory: %s + Binary path: %s + Version: %s + Install name: %s + Deployed install name: %s + Source file Path: %s + Deployed Directory (relative to bundle): %s +""" % (self.frameworkName, + self.frameworkDirectory, + self.frameworkPath, + self.binaryName, + self.binaryDirectory, + self.binaryPath, + self.version, + self.installName, + self.deployedInstallName, + self.sourceFilePath, + self.destinationDirectory) + + def isDylib(self): + return self.frameworkName.endswith(".dylib") + + def isQtFramework(self): + if self.isDylib(): + return self.frameworkName.startswith("libQt") + else: + return self.frameworkName.startswith("Qt") + + reOLine = re.compile(r'^(.+) \(compatibility version [0-9.]+, current version [0-9.]+\)$') + bundleFrameworkDirectory = "Contents/Frameworks" + bundleBinaryDirectory = "Contents/MacOS" + + @classmethod + def fromOtoolLibraryLine(cls, line): + # Note: line must be trimmed + if line == "": + return None + + # Don't deploy system libraries (exception for libQtuitools and libQtlucene). + if line.startswith("/System/Library/") or line.startswith("@executable_path") or (line.startswith("/usr/lib/") and "libQt" not in line): + return None + + m = cls.reOLine.match(line) + if m is None: + raise RuntimeError("otool line could not be parsed: " + line) + + path = m.group(1) + + info = cls() + info.sourceFilePath = path + info.installName = path + + if path.endswith(".dylib"): + dirname, filename = os.path.split(path) + info.frameworkName = filename + info.frameworkDirectory = dirname + info.frameworkPath = path + + info.binaryDirectory = dirname + info.binaryName = filename + info.binaryPath = path + info.version = "-" + + info.installName = path + info.deployedInstallName = "@executable_path/../Frameworks/" + info.binaryName + info.sourceFilePath = path + info.destinationDirectory = cls.bundleFrameworkDirectory + else: + parts = path.split("/") + i = 0 + # Search for the .framework directory + for part in parts: + if part.endswith(".framework"): + break + i += 1 + if i == len(parts): + raise RuntimeError("Could not find .framework or .dylib in otool line: " + line) + + info.frameworkName = parts[i] + info.frameworkDirectory = "/".join(parts[:i]) + info.frameworkPath = os.path.join(info.frameworkDirectory, info.frameworkName) + + info.binaryName = parts[i+3] + info.binaryDirectory = "/".join(parts[i+1:i+3]) + info.binaryPath = os.path.join(info.binaryDirectory, info.binaryName) + info.version = parts[i+2] + + info.deployedInstallName = "@executable_path/../Frameworks/" + os.path.join(info.frameworkName, info.binaryPath) + info.destinationDirectory = os.path.join(cls.bundleFrameworkDirectory, info.frameworkName, info.binaryDirectory) + + info.sourceResourcesDirectory = os.path.join(info.frameworkPath, "Resources") + info.destinationResourcesDirectory = os.path.join(cls.bundleFrameworkDirectory, info.frameworkName, "Resources") + + return info + +class ApplicationBundleInfo(object): + def __init__(self, path): + self.path = path + appName = os.path.splitext(os.path.basename(path))[0] + self.binaryPath = os.path.join(path, "Contents", "MacOS", appName) + if not os.path.exists(self.binaryPath): + raise RuntimeError("Could not find bundle binary for " + path) + self.resourcesPath = os.path.join(path, "Contents", "Resources") + self.pluginPath = os.path.join(path, "Contents", "PlugIns") + +class DeploymentInfo(object): + def __init__(self): + self.qtPath = None + self.pluginPath = None + self.deployedFrameworks = [] + + def detectQtPath(self, frameworkDirectory): + parentDir = os.path.dirname(frameworkDirectory) + if os.path.exists(os.path.join(parentDir, "translations")): + # Classic layout, e.g. "/usr/local/Trolltech/Qt-4.x.x" + self.qtPath = parentDir + elif os.path.exists(os.path.join(parentDir, "share", "qt4", "translations")): + # MacPorts layout, e.g. "/opt/local/share/qt4" + self.qtPath = os.path.join(parentDir, "share", "qt4") + elif os.path.exists(os.path.join(os.path.dirname(parentDir), "share", "qt4", "translations")): + # Newer Macports layout + self.qtPath = os.path.join(os.path.dirname(parentDir), "share", "qt4") + else: + self.qtPath = os.getenv("QTDIR", None) + + if self.qtPath is not None: + pluginPath = os.path.join(self.qtPath, "plugins") + if os.path.exists(pluginPath): + self.pluginPath = pluginPath + + def usesFramework(self, name): + nameDot = "%s." % name + libNameDot = "lib%s." % name + for framework in self.deployedFrameworks: + if framework.endswith(".framework"): + if framework.startswith(nameDot): + return True + elif framework.endswith(".dylib"): + if framework.startswith(libNameDot): + return True + return False + +def getFrameworks(binaryPath, verbose): + if verbose >= 3: + print "Inspecting with otool: " + binaryPath + otool = subprocess.Popen(["otool", "-L", binaryPath], stdout=subprocess.PIPE, stderr=subprocess.PIPE) + o_stdout, o_stderr = otool.communicate() + if otool.returncode != 0: + if verbose >= 1: + sys.stderr.write(o_stderr) + sys.stderr.flush() + raise RuntimeError("otool failed with return code %d" % otool.returncode) + + otoolLines = o_stdout.split("\n") + otoolLines.pop(0) # First line is the inspected binary + if ".framework" in binaryPath or binaryPath.endswith(".dylib"): + otoolLines.pop(0) # Frameworks and dylibs list themselves as a dependency. + + libraries = [] + for line in otoolLines: + info = FrameworkInfo.fromOtoolLibraryLine(line.strip()) + if info is not None: + if verbose >= 3: + print "Found framework:" + print info + libraries.append(info) + + return libraries + +def runInstallNameTool(action, *args): + subprocess.check_call(["install_name_tool", "-"+action] + list(args)) + +def changeInstallName(oldName, newName, binaryPath, verbose): + if verbose >= 3: + print "Using install_name_tool:" + print " in", binaryPath + print " change reference", oldName + print " to", newName + runInstallNameTool("change", oldName, newName, binaryPath) + +def changeIdentification(id, binaryPath, verbose): + if verbose >= 3: + print "Using install_name_tool:" + print " change identification in", binaryPath + print " to", id + runInstallNameTool("id", id, binaryPath) + +def runStrip(binaryPath, verbose): + if verbose >= 3: + print "Using strip:" + print " stripped", binaryPath + subprocess.check_call(["strip", "-x", binaryPath]) + +def copyFramework(framework, path, verbose): + if framework.sourceFilePath.startswith("Qt"): + #standard place for Nokia Qt installer's frameworks + fromPath = "/Library/Frameworks/" + framework.sourceFilePath + else: + fromPath = framework.sourceFilePath + + toDir = os.path.join(path, framework.destinationDirectory) + toPath = os.path.join(toDir, framework.binaryName) + + if not os.path.exists(fromPath): + raise RuntimeError("No file at " + fromPath) + + if os.path.exists(toPath): + return None # Already there + + if not os.path.exists(toDir): + os.makedirs(toDir) + + shutil.copy2(fromPath, toPath) + if verbose >= 3: + print "Copied:", fromPath + print " to:", toPath + + permissions = os.stat(toPath) + if not permissions.st_mode & stat.S_IWRITE: + os.chmod(toPath, permissions.st_mode | stat.S_IWRITE) + + if not framework.isDylib(): # Copy resources for real frameworks + fromResourcesDir = framework.sourceResourcesDirectory + if os.path.exists(fromResourcesDir): + toResourcesDir = os.path.join(path, framework.destinationResourcesDirectory) + shutil.copytree(fromResourcesDir, toResourcesDir) + if verbose >= 3: + print "Copied resources:", fromResourcesDir + print " to:", toResourcesDir + elif framework.frameworkName.startswith("libQtGui"): # Copy qt_menu.nib (applies to non-framework layout) + qtMenuNibSourcePath = os.path.join(framework.frameworkDirectory, "Resources", "qt_menu.nib") + qtMenuNibDestinationPath = os.path.join(path, "Contents", "Resources", "qt_menu.nib") + if os.path.exists(qtMenuNibSourcePath) and not os.path.exists(qtMenuNibDestinationPath): + shutil.copytree(qtMenuNibSourcePath, qtMenuNibDestinationPath) + if verbose >= 3: + print "Copied for libQtGui:", qtMenuNibSourcePath + print " to:", qtMenuNibDestinationPath + + return toPath + +def deployFrameworks(frameworks, bundlePath, binaryPath, strip, verbose, deploymentInfo=None): + if deploymentInfo is None: + deploymentInfo = DeploymentInfo() + + while len(frameworks) > 0: + framework = frameworks.pop(0) + deploymentInfo.deployedFrameworks.append(framework.frameworkName) + + if verbose >= 2: + print "Processing", framework.frameworkName, "..." + + # Get the Qt path from one of the Qt frameworks + if deploymentInfo.qtPath is None and framework.isQtFramework(): + deploymentInfo.detectQtPath(framework.frameworkDirectory) + + if framework.installName.startswith("@executable_path"): + if verbose >= 2: + print framework.frameworkName, "already deployed, skipping." + continue + + # install_name_tool the new id into the binary + changeInstallName(framework.installName, framework.deployedInstallName, binaryPath, verbose) + + # Copy farmework to app bundle. + deployedBinaryPath = copyFramework(framework, bundlePath, verbose) + # Skip the rest if already was deployed. + if deployedBinaryPath is None: + continue + + if strip: + runStrip(deployedBinaryPath, verbose) + + # install_name_tool it a new id. + changeIdentification(framework.deployedInstallName, deployedBinaryPath, verbose) + # Check for framework dependencies + dependencies = getFrameworks(deployedBinaryPath, verbose) + + for dependency in dependencies: + changeInstallName(dependency.installName, dependency.deployedInstallName, deployedBinaryPath, verbose) + + # Deploy framework if necessary. + if dependency.frameworkName not in deploymentInfo.deployedFrameworks and dependency not in frameworks: + frameworks.append(dependency) + + return deploymentInfo + +def deployFrameworksForAppBundle(applicationBundle, strip, verbose): + frameworks = getFrameworks(applicationBundle.binaryPath, verbose) + if len(frameworks) == 0 and verbose >= 1: + print "Warning: Could not find any external frameworks to deploy in %s." % (applicationBundle.path) + return DeploymentInfo() + else: + return deployFrameworks(frameworks, applicationBundle.path, applicationBundle.binaryPath, strip, verbose) + +def deployPlugins(appBundleInfo, deploymentInfo, strip, verbose): + # Lookup available plugins, exclude unneeded + plugins = [] + for dirpath, dirnames, filenames in os.walk(deploymentInfo.pluginPath): + pluginDirectory = os.path.relpath(dirpath, deploymentInfo.pluginPath) + if pluginDirectory == "designer": + # Skip designer plugins + continue + elif pluginDirectory == "phonon" or pluginDirectory == "phonon_backend": + # Deploy the phonon plugins only if phonon is in use + if not deploymentInfo.usesFramework("phonon"): + continue + elif pluginDirectory == "sqldrivers": + # Deploy the sql plugins only if QtSql is in use + if not deploymentInfo.usesFramework("QtSql"): + continue + elif pluginDirectory == "script": + # Deploy the script plugins only if QtScript is in use + if not deploymentInfo.usesFramework("QtScript"): + continue + elif pluginDirectory == "qmltooling": + # Deploy the qml plugins only if QtDeclarative is in use + if not deploymentInfo.usesFramework("QtDeclarative"): + continue + elif pluginDirectory == "bearer": + # Deploy the bearer plugins only if QtNetwork is in use + if not deploymentInfo.usesFramework("QtNetwork"): + continue + + for pluginName in filenames: + pluginPath = os.path.join(pluginDirectory, pluginName) + if pluginName.endswith("_debug.dylib"): + # Skip debug plugins + continue + elif pluginPath == "imageformats/libqsvg.dylib" or pluginPath == "iconengines/libqsvgicon.dylib": + # Deploy the svg plugins only if QtSvg is in use + if not deploymentInfo.usesFramework("QtSvg"): + continue + elif pluginPath == "accessible/libqtaccessiblecompatwidgets.dylib": + # Deploy accessibility for Qt3Support only if the Qt3Support is in use + if not deploymentInfo.usesFramework("Qt3Support"): + continue + elif pluginPath == "graphicssystems/libqglgraphicssystem.dylib": + # Deploy the opengl graphicssystem plugin only if QtOpenGL is in use + if not deploymentInfo.usesFramework("QtOpenGL"): + continue + + plugins.append((pluginDirectory, pluginName)) + + for pluginDirectory, pluginName in plugins: + if verbose >= 2: + print "Processing plugin", os.path.join(pluginDirectory, pluginName), "..." + + sourcePath = os.path.join(deploymentInfo.pluginPath, pluginDirectory, pluginName) + destinationDirectory = os.path.join(appBundleInfo.pluginPath, pluginDirectory) + if not os.path.exists(destinationDirectory): + os.makedirs(destinationDirectory) + + destinationPath = os.path.join(destinationDirectory, pluginName) + shutil.copy2(sourcePath, destinationPath) + if verbose >= 3: + print "Copied:", sourcePath + print " to:", destinationPath + + if strip: + runStrip(destinationPath, verbose) + + dependencies = getFrameworks(destinationPath, verbose) + + for dependency in dependencies: + changeInstallName(dependency.installName, dependency.deployedInstallName, destinationPath, verbose) + + # Deploy framework if necessary. + if dependency.frameworkName not in deploymentInfo.deployedFrameworks: + deployFrameworks([dependency], appBundleInfo.path, destinationPath, strip, verbose, deploymentInfo) + +qt_conf="""[Paths] +translations=Resources +plugins=PlugIns +""" + +ap = ArgumentParser(description="""Improved version of macdeployqt. + +Outputs a ready-to-deploy app in a folder "dist" and optionally wraps it in a .dmg file. +Note, that the "dist" folder will be deleted before deploying on each run. + +Optionally, Qt translation files (.qm) and additional resources can be added to the bundle.""") + +ap.add_argument("app_bundle", nargs=1, metavar="app-bundle", help="application bundle to be deployed") +ap.add_argument("-verbose", type=int, nargs=1, default=[1], metavar="<0-3>", help="0 = no output, 1 = error/warning (default), 2 = normal, 3 = debug") +ap.add_argument("-no-plugins", dest="plugins", action="store_false", default=True, help="skip plugin deployment") +ap.add_argument("-no-strip", dest="strip", action="store_false", default=True, help="don't run 'strip' on the binaries") +ap.add_argument("-dmg", nargs="?", const="", metavar="basename", help="create a .dmg disk image; if basename is not specified, a camel-cased version of the app name is used") +ap.add_argument("-fancy", nargs=1, metavar="plist", default=[], help="make a fancy looking disk image using the given plist file with instructions; requires -dmg to work") +ap.add_argument("-add-qt-tr", nargs=1, metavar="languages", default=[], help="add Qt translation files to the bundle's ressources; the language list must be separated with commas, not with whitespace") +ap.add_argument("-add-resources", nargs="+", metavar="path", default=[], help="list of additional files or folders to be copied into the bundle's resources; must be the last argument") + +config = ap.parse_args() + +verbose = config.verbose[0] + +# ------------------------------------------------ + +app_bundle = config.app_bundle[0] + +if not os.path.exists(app_bundle): + if verbose >= 1: + sys.stderr.write("Error: Could not find app bundle \"%s\"\n" % (app_bundle)) + sys.exit(1) + +app_bundle_name = os.path.splitext(os.path.basename(app_bundle))[0] + +# ------------------------------------------------ + +for p in config.add_resources: + if verbose >= 3: + print "Checking for \"%s\"..." % p + if not os.path.exists(p): + if verbose >= 1: + sys.stderr.write("Error: Could not find additional resource file \"%s\"\n" % (p)) + sys.exit(1) + +# ------------------------------------------------ + +if len(config.fancy) == 1: + if verbose >= 3: + print "Fancy: Importing plistlib..." + try: + import plistlib + except ImportError: + if verbose >= 1: + sys.stderr.write("Error: Could not import plistlib which is required for fancy disk images.\n") + sys.exit(1) + + if verbose >= 3: + print "Fancy: Importing appscript..." + try: + import appscript + except ImportError: + if verbose >= 1: + sys.stderr.write("Error: Could not import appscript which is required for fancy disk images.\n") + sys.stderr.write("Please install it e.g. with \"sudo easy_install appscript\".\n") + sys.exit(1) + + p = config.fancy[0] + if verbose >= 3: + print "Fancy: Loading \"%s\"..." % p + if not os.path.exists(p): + if verbose >= 1: + sys.stderr.write("Error: Could not find fancy disk image plist at \"%s\"\n" % (p)) + sys.exit(1) + + try: + fancy = plistlib.readPlist(p) + except: + if verbose >= 1: + sys.stderr.write("Error: Could not parse fancy disk image plist at \"%s\"\n" % (p)) + sys.exit(1) + + try: + assert not fancy.has_key("window_bounds") or (isinstance(fancy["window_bounds"], list) and len(fancy["window_bounds"]) == 4) + assert not fancy.has_key("background_picture") or isinstance(fancy["background_picture"], str) + assert not fancy.has_key("icon_size") or isinstance(fancy["icon_size"], int) + assert not fancy.has_key("applications_symlink") or isinstance(fancy["applications_symlink"], bool) + if fancy.has_key("items_position"): + assert isinstance(fancy["items_position"], dict) + for key, value in fancy["items_position"].iteritems(): + assert isinstance(value, list) and len(value) == 2 and isinstance(value[0], int) and isinstance(value[1], int) + except: + if verbose >= 1: + sys.stderr.write("Error: Bad format of fancy disk image plist at \"%s\"\n" % (p)) + sys.exit(1) + + if fancy.has_key("background_picture"): + bp = fancy["background_picture"] + if verbose >= 3: + print "Fancy: Resolving background picture \"%s\"..." % bp + if not os.path.exists(bp): + bp = os.path.join(os.path.dirname(p), bp) + if not os.path.exists(bp): + if verbose >= 1: + sys.stderr.write("Error: Could not find background picture at \"%s\" or \"%s\"\n" % (fancy["background_picture"], bp)) + sys.exit(1) + else: + fancy["background_picture"] = bp +else: + fancy = None + +# ------------------------------------------------ + +if os.path.exists("dist"): + if verbose >= 2: + print "+ Removing old dist folder +" + + shutil.rmtree("dist") + +# ------------------------------------------------ + +target = os.path.join("dist", app_bundle) + +if verbose >= 2: + print "+ Copying source bundle +" +if verbose >= 3: + print app_bundle, "->", target + +os.mkdir("dist") +shutil.copytree(app_bundle, target) + +applicationBundle = ApplicationBundleInfo(target) + +# ------------------------------------------------ + +if verbose >= 2: + print "+ Deploying frameworks +" + +try: + deploymentInfo = deployFrameworksForAppBundle(applicationBundle, config.strip, verbose) + if deploymentInfo.qtPath is None: + deploymentInfo.qtPath = os.getenv("QTDIR", None) + if deploymentInfo.qtPath is None: + if verbose >= 1: + sys.stderr.write("Warning: Could not detect Qt's path, skipping plugin deployment!\n") + config.plugins = False +except RuntimeError as e: + if verbose >= 1: + sys.stderr.write("Error: %s\n" % str(e)) + sys.exit(ret) + +# ------------------------------------------------ + +if config.plugins: + if verbose >= 2: + print "+ Deploying plugins +" + + try: + deployPlugins(applicationBundle, deploymentInfo, config.strip, verbose) + except RuntimeError as e: + if verbose >= 1: + sys.stderr.write("Error: %s\n" % str(e)) + sys.exit(ret) + +# ------------------------------------------------ + +if len(config.add_qt_tr) == 0: + add_qt_tr = [] +else: + qt_tr_dir = os.path.join(deploymentInfo.qtPath, "translations") + add_qt_tr = ["qt_%s.qm" % lng for lng in config.add_qt_tr[0].split(",")] + for lng_file in add_qt_tr: + p = os.path.join(qt_tr_dir, lng_file) + if verbose >= 3: + print "Checking for \"%s\"..." % p + if not os.path.exists(p): + if verbose >= 1: + sys.stderr.write("Error: Could not find Qt translation file \"%s\"\n" % (lng_file)) + sys.exit(1) + +# ------------------------------------------------ + +if verbose >= 2: + print "+ Installing qt.conf +" + +f = open(os.path.join(applicationBundle.resourcesPath, "qt.conf"), "wb") +f.write(qt_conf) +f.close() + +# ------------------------------------------------ + +if len(add_qt_tr) > 0 and verbose >= 2: + print "+ Adding Qt translations +" + +for lng_file in add_qt_tr: + if verbose >= 3: + print os.path.join(qt_tr_dir, lng_file), "->", os.path.join(applicationBundle.resourcesPath, lng_file) + shutil.copy2(os.path.join(qt_tr_dir, lng_file), os.path.join(applicationBundle.resourcesPath, lng_file)) + +# ------------------------------------------------ + +if len(config.add_resources) > 0 and verbose >= 2: + print "+ Adding additional resources +" + +for p in config.add_resources: + t = os.path.join(applicationBundle.resourcesPath, os.path.basename(p)) + if verbose >= 3: + print p, "->", t + if os.path.isdir(p): + shutil.copytree(p, t) + else: + shutil.copy2(p, t) + +# ------------------------------------------------ + +if config.dmg is not None: + def runHDIUtil(verb, image_basename, **kwargs): + hdiutil_args = ["hdiutil", verb, image_basename + ".dmg"] + if kwargs.has_key("capture_stdout"): + del kwargs["capture_stdout"] + run = subprocess.check_output + else: + if verbose < 2: + hdiutil_args.append("-quiet") + elif verbose >= 3: + hdiutil_args.append("-verbose") + run = subprocess.check_call + + for key, value in kwargs.iteritems(): + hdiutil_args.append("-" + key) + if not value is True: + hdiutil_args.append(str(value)) + + return run(hdiutil_args) + + if verbose >= 2: + if fancy is None: + print "+ Creating .dmg disk image +" + else: + print "+ Preparing .dmg disk image +" + + if config.dmg != "": + dmg_name = config.dmg + else: + spl = app_bundle_name.split(" ") + dmg_name = spl[0] + "".join(p.capitalize() for p in spl[1:]) + + if fancy is None: + try: + runHDIUtil("create", dmg_name, srcfolder="dist", format="UDBZ", volname=app_bundle_name, ov=True) + except subprocess.CalledProcessError as e: + sys.exit(e.returncode) + else: + if verbose >= 3: + print "Determining size of \"dist\"..." + size = 0 + for path, dirs, files in os.walk("dist"): + for file in files: + size += os.path.getsize(os.path.join(path, file)) + size += int(size * 0.1) + + if verbose >= 3: + print "Creating temp image for modification..." + try: + runHDIUtil("create", dmg_name + ".temp", srcfolder="dist", format="UDRW", size=size, volname=app_bundle_name, ov=True) + except subprocess.CalledProcessError as e: + sys.exit(e.returncode) + + if verbose >= 3: + print "Attaching temp image..." + try: + output = runHDIUtil("attach", dmg_name + ".temp", readwrite=True, noverify=True, noautoopen=True, capture_stdout=True) + except subprocess.CalledProcessError as e: + sys.exit(e.returncode) + + m = re.search("/Volumes/(.+$)", output) + disk_root = m.group(0) + disk_name = m.group(1) + + if verbose >= 2: + print "+ Applying fancy settings +" + + if fancy.has_key("background_picture"): + bg_path = os.path.join(disk_root, os.path.basename(fancy["background_picture"])) + if verbose >= 3: + print fancy["background_picture"], "->", bg_path + shutil.copy2(fancy["background_picture"], bg_path) + else: + bg_path = None + + if fancy.get("applications_symlink", False): + os.symlink("/Applications", os.path.join(disk_root, "Applications")) + + finder = appscript.app("Finder") + disk = finder.disks[disk_name] + disk.open() + window = disk.container_window + window.current_view.set(appscript.k.icon_view) + window.toolbar_visible.set(False) + window.statusbar_visible.set(False) + if fancy.has_key("window_bounds"): + window.bounds.set(fancy["window_bounds"]) + view_options = window.icon_view_options + view_options.arrangement.set(appscript.k.not_arranged) + if fancy.has_key("icon_size"): + view_options.icon_size.set(fancy["icon_size"]) + if bg_path is not None: + view_options.background_picture.set(disk.files[os.path.basename(bg_path)]) + if fancy.has_key("items_position"): + for name, position in fancy["items_position"].iteritems(): + window.items[name].position.set(position) + disk.close() + if bg_path is not None: + subprocess.call(["SetFile", "-a", "V", bg_path]) + disk.update(registering_applications=False) + sleep(2) + disk.eject() + + if verbose >= 2: + print "+ Finalizing .dmg disk image +" + + try: + runHDIUtil("convert", dmg_name + ".temp", format="UDBZ", o=dmg_name + ".dmg", ov=True) + except subprocess.CalledProcessError as e: + sys.exit(e.returncode) + + os.unlink(dmg_name + ".temp.dmg") + +# ------------------------------------------------ + +if verbose >= 2: + print "+ Done +" + +sys.exit(0) diff --git a/contrib/macdeploy/notes.txt b/contrib/macdeploy/notes.txt new file mode 100644 index 0000000..b19cd3c --- /dev/null +++ b/contrib/macdeploy/notes.txt @@ -0,0 +1,26 @@ + +macdeployqtplus works best on OS X Lion, for Snow Leopard you'd need to install +Python 2.7 and make it your default Python installation. + +You will need the appscript package for the fancy disk image creation to work. +Install it by invoking "sudo easy_install appscript". + +Ths script should be invoked in the target directory like this: +$source_dir/contrib/macdeploy/macdeployqtplus triangles-qt.app -add-qt-tr da,de,es,hu,ru,uk,zh_CN,zh_TW -dmg -fancy $source_dir/contrib/macdeploy/fancy.plist -verbose 2 + +During the process, the disk image window will pop up briefly where the fancy +settings are applied. This is normal, please do not interfere. + +You can also set up Qt Creator for invoking the script. For this, go to the +"Projects" tab on the left side, switch to "Run Settings" above and add a +deploy configuration. Next add a deploy step choosing "Custom Process Step". +Fill in the following. + +Enable custom process step: [x] +Command: %{sourceDir}/contrib/macdeploy/macdeployqtplus +Working directory: %{buildDir} +Command arguments: triangles-qt.app -add-qt-tr da,de,es,hu,ru,uk,zh_CN,zh_TW -dmg -fancy %{sourceDir}/contrib/macdeploy/fancy.plist -verbose 2 + +After that you can start the deployment process through the menu with +Build -> Deploy Project "triangles-qt" + diff --git a/contrib/qt_translations.py b/contrib/qt_translations.py new file mode 100644 index 0000000..fd8a8b7 --- /dev/null +++ b/contrib/qt_translations.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python + +# Helpful little script that spits out a comma-separated list of +# language codes for Qt icons that should be included +# in binary bitcoin distributions + +import glob +import os +import re +import sys + +if len(sys.argv) != 3: + sys.exit("Usage: %s $QTDIR/translations $BITCOINDIR/src/qt/locale"%sys.argv[0]) + +d1 = sys.argv[1] +d2 = sys.argv[2] + +l1 = set([ re.search(r'qt_(.*).qm', f).group(1) for f in glob.glob(os.path.join(d1, 'qt_*.qm')) ]) +l2 = set([ re.search(r'bitcoin_(.*).qm', f).group(1) for f in glob.glob(os.path.join(d2, 'bitcoin_*.qm')) ]) + +print ",".join(sorted(l1.intersection(l2))) + diff --git a/contrib/wallettools/walletchangepass.py b/contrib/wallettools/walletchangepass.py new file mode 100644 index 0000000..30f3f5b --- /dev/null +++ b/contrib/wallettools/walletchangepass.py @@ -0,0 +1,5 @@ +from jsonrpc import ServiceProxy +access = ServiceProxy("http://127.0.0.1:8332") +pwd = raw_input("Enter old wallet passphrase: ") +pwd2 = raw_input("Enter new wallet passphrase: ") +access.walletpassphrasechange(pwd, pwd2) \ No newline at end of file diff --git a/contrib/wallettools/walletunlock.py b/contrib/wallettools/walletunlock.py new file mode 100644 index 0000000..f847c6f --- /dev/null +++ b/contrib/wallettools/walletunlock.py @@ -0,0 +1,4 @@ +from jsonrpc import ServiceProxy +access = ServiceProxy("http://127.0.0.1:8332") +pwd = raw_input("Enter wallet passphrase: ") +access.walletpassphrase(pwd, 60) \ No newline at end of file diff --git a/doc/Doxyfile b/doc/Doxyfile new file mode 100644 index 0000000..08d4f8c --- /dev/null +++ b/doc/Doxyfile @@ -0,0 +1,1752 @@ +# Doxyfile 1.7.4 + +# !!! Invoke doxygen from project root using: +# doxygen doc/Doxyfile + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project +# +# All text after a hash (#) is considered a comment and will be ignored +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" ") + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# http://www.gnu.org/software/libiconv for the list of possible encodings. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded +# by quotes) that should identify the project. + +PROJECT_NAME = Bitcoin + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = 0.5.0 + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer +# a quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = "P2P Digital Currency" + +# With the PROJECT_LOGO tag one can specify an logo or icon that is +# included in the documentation. The maximum height of the logo should not +# exceed 55 pixels and the maximum width should not exceed 200 pixels. +# Doxygen will copy the logo to the output directory. + +PROJECT_LOGO = doc/bitcoin_logo_doxygen.png + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = doc/doxygen + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create +# 4096 sub-directories (in 2 levels) under the output directory of each output +# format and will distribute the generated files over these directories. +# Enabling this option can be useful when feeding doxygen a huge amount of +# source files, where putting all generated files in the same directory would +# otherwise cause performance problems for the file system. + +CREATE_SUBDIRS = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, +# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, +# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English +# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, +# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, +# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator +# that is used to form the text in various listings. Each string +# in this list, if found as the leading text of the brief description, will be +# stripped from the text and the result after processing the whole list, is +# used as the annotated text. Otherwise, the brief description is used as-is. +# If left blank, the following values are used ("$name" is automatically +# replaced with the name of the entity): "The $name class" "The $name widget" +# "The $name file" "is" "provides" "specifies" "contains" +# "represents" "a" "an" "the" + +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = YES + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user-defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the +# path to strip. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of +# the path mentioned in the documentation of a class, which tells +# the reader which header file to include in order to use a class. +# If left blank only the name of the header file containing the class +# definition is used. Otherwise one should specify the include paths that +# are normally passed to the compiler using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful if your file system +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like regular Qt-style comments +# (thus requiring an explicit @brief command for a brief description.) + +JAVADOC_AUTOBRIEF = YES + +# If the QT_AUTOBRIEF tag is set to YES then Doxygen will +# interpret the first line (until the first dot) of a Qt-style +# comment as the brief description. If set to NO, the comments +# will behave just like regular Qt-style comments (thus requiring +# an explicit \brief command for a brief description.) + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behaviour instead. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# re-implements. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce +# a new page for each member. If set to NO, the documentation of a member will +# be part of the file/class/namespace that contains it. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 8 + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C +# sources only. Doxygen will then generate output that is more tailored for C. +# For instance, some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java +# sources only. Doxygen will then generate output that is more tailored for +# Java. For instance, namespaces will be presented as packages, qualified +# scopes will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources only. Doxygen will then generate output that is more tailored for +# Fortran. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for +# VHDL. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given extension. +# Doxygen has a built-in mapping, but you can override or extend it using this +# tag. The format is ext=language, where ext is a file extension, and language +# is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C, +# C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make +# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C +# (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions +# you also need to set FILE_PATTERNS otherwise the files are not read by doxygen. + +EXTENSION_MAPPING = + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should +# set this tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. +# func(std::string) {}). This also makes the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. +# Doxygen will parse them like normal C++ but will assume all classes use public +# instead of private inheritance when no explicit protection keyword is present. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate getter +# and setter methods for a property. Setting this option to YES (the default) +# will make doxygen replace the get and set methods by a property in the +# documentation. This will only work if the methods are indeed getting or +# setting a simple type. If this is not the case, or you want to show the +# methods anyway, you should set this option to NO. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = NO + +# Set the SUBGROUPING tag to YES (the default) to allow class member groups of +# the same type (for instance a group of public functions) to be put as a +# subgroup of that type (e.g. under the Public Functions section). Set it to +# NO to prevent subgrouping. Alternatively, this can be done per class using +# the \nosubgrouping command. + +SUBGROUPING = YES + +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and +# unions are shown inside the group in which they are included (e.g. using +# @ingroup) instead of on a separate page (for HTML and Man pages) or +# section (for LaTeX and RTF). + +INLINE_GROUPED_CLASSES = NO + +# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum +# is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically +# be useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. + +TYPEDEF_HIDES_STRUCT = NO + +# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to +# determine which symbols to keep in memory and which to flush to disk. +# When the cache is full, less often used symbols will be written to disk. +# For small to medium size projects (<1000 input files) the default value is +# probably good enough. For larger projects a too small cache size can cause +# doxygen to be busy swapping symbols to and from disk most of the time +# causing a significant performance penalty. +# If the system has enough physical memory increasing the cache will improve the +# performance by keeping more symbols in memory. Note that the value works on +# a logarithmic scale so increasing the size by one will roughly double the +# memory usage. The cache size is given by this formula: +# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, +# corresponding to a cache size of 2^16 = 65536 symbols + +SYMBOL_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = YES + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = NO + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. When set to YES local +# methods, which are defined in the implementation section but not in +# the interface are included in the documentation. +# If set to NO (the default) only methods in the interface are included. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base +# name of the file that contains the anonymous namespace. By default +# anonymous namespaces are hidden. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these classes will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the +# documentation. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the +# function's detailed documentation block. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. + +CASE_SENSE_NAMES = NO + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put a list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = YES + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen +# will list include files with double quotes in the documentation +# rather than with sharp brackets. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the +# brief documentation of file, namespace and class members alphabetically +# by member name. If set to NO (the default) the members will appear in +# declaration order. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen +# will sort the (brief and detailed) documentation of class members so that +# constructors and destructors are listed first. If set to NO (the default) +# the constructors will appear in the respective orders defined by +# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. +# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO +# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the +# hierarchy of group names into alphabetical order. If set to NO (the default) +# the group names will appear in their defined order. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be +# sorted by fully-qualified names, including namespaces. If set to +# NO (the default), the class list will be sorted only by class name, +# not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the +# alphabetical list. + +SORT_BY_SCOPE_NAME = NO + +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to +# do proper type resolution of all parameters of a function it will reject a +# match between the prototype and the implementation of a member function even +# if there is only one candidate or it is obvious which candidate to choose +# by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen +# will still accept a match between prototype and implementation in such cases. + +STRICT_PROTO_MATCHING = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug +# commands in the documentation. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting +# \deprecated commands in the documentation. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or macro consists of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and macros in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the +# list will mention the files that were used to generate the documentation. + +SHOW_USED_FILES = YES + +# If the sources in your project are distributed over multiple directories +# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy +# in the documentation. The default is NO. + +SHOW_DIRECTORIES = NO + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. +# This will remove the Files entry from the Quick Index and from the +# Folder Tree View (if specified). The default is YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the +# Namespaces page. This will remove the Namespaces entry from the Quick Index +# and from the Folder Tree View (if specified). The default is YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command , where is the value of +# the FILE_VERSION_FILTER tag, and is the name of an input file +# provided by doxygen. Whatever the program writes to standard output +# is used as the file version. See the manual for examples. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. The create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. +# You can optionally specify a file name after the option, if omitted +# DoxygenLayout.xml will be used as the name of the layout file. + +LAYOUT_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = YES + +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that +# don't exist or using markup commands wrongly. + +WARN_IF_DOC_ERROR = YES + +# The WARN_NO_PARAMDOC option can be enabled to get warnings for +# functions that are documented, but have no documentation for their parameters +# or return value. If set to NO (the default) doxygen will only warn about +# wrong or incomplete parameter documentation, but not about the absence of +# documentation. + +WARN_NO_PARAMDOC = NO + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. Optionally the format may contain +# $version, which will be replaced by the version of the file (if it could +# be obtained via FILE_VERSION_FILTER) + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written +# to stderr. + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = src + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is +# also the default input encoding. Doxygen uses libiconv (or the iconv built +# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for +# the list of possible encodings. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh +# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py +# *.f90 *.f *.for *.vhd *.vhdl + +FILE_PATTERNS = *.c \ + *.cc \ + *.cxx \ + *.cpp \ + *.c++ \ + *.d \ + *.java \ + *.ii \ + *.ixx \ + *.ipp \ + *.i++ \ + *.inl \ + *.h \ + *.hh \ + *.hxx \ + *.hpp \ + *.h++ \ + *.idl \ + *.odl \ + *.cs \ + *.php \ + *.php3 \ + *.inc \ + *.m \ + *.mm \ + *.dox \ + *.py \ + *.f90 \ + *.f \ + *.for \ + *.vhd \ + *.vhdl + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = YES + +# The EXCLUDE tag can be used to specify files and/or directories that should +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded +# from the input. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. Note that the wildcards are matched +# against the file with absolute path, so to exclude all test directories +# for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = * + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command , where +# is the value of the INPUT_FILTER tag, and is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. If FILTER_PATTERNS is specified, this tag will be +# ignored. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: +# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further +# info on how filters are used. If FILTER_PATTERNS is empty or if +# non of the patterns match the file name, INPUT_FILTER is applied. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse (i.e. when SOURCE_BROWSER is set to YES). + +FILTER_SOURCE_FILES = NO + +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) +# and it is also possible to disable source filtering for a specific pattern +# using *.ext= (so without naming a filter). This option only has effect when +# FILTER_SOURCE_FILES is enabled. + +FILTER_SOURCE_PATTERNS = + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. +# Note: To get rid of all source code in the generated output, make sure also +# VERBATIM_HEADERS is set to NO. + +SOURCE_BROWSER = YES + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C and C++ comments will always remain visible. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) +# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from +# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will +# link to the source code. Otherwise they will link to the documentation. + +REFERENCES_LINK_SOURCE = YES + +# If the USE_HTAGS tag is set to YES then the references to source code +# will point to the HTML generated by the htags(1) tool instead of doxygen +# built-in source browser. The htags tool is part of GNU's global source +# tagging system (see http://www.gnu.org/software/global/global.html). You +# will need version 4.8.6 or higher. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = YES + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. Note that when using a custom header you are responsible +# for the proper inclusion of any scripts and style sheets that doxygen +# needs, which is dependent on the configuration options used. +# It is adviced to generate a default header using "doxygen -w html +# header.html footer.html stylesheet.css YourConfigFile" and then modify +# that header. Note that the header is subject to change so you typically +# have to redo this when upgrading to a newer version of doxygen or when +# changing the value of configuration settings such as GENERATE_TREEVIEW! + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If the tag is left blank doxygen +# will generate a default style sheet. Note that doxygen will try to copy +# the style sheet file to the HTML output directory, so don't put your own +# stylesheet in the HTML output directory as well, or it will be erased! + +HTML_STYLESHEET = + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that +# the files will be copied as-is; there are no commands or markers available. + +HTML_EXTRA_FILES = + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. +# Doxygen will adjust the colors in the stylesheet and background images +# according to this color. Hue is specified as an angle on a colorwheel, +# see http://en.wikipedia.org/wiki/Hue for more information. +# For instance the value 0 represents red, 60 is yellow, 120 is green, +# 180 is cyan, 240 is blue, 300 purple, and 360 is red again. +# The allowed range is 0 to 359. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of +# the colors in the HTML output. For a value of 0 the output will use +# grayscales only. A value of 255 will produce the most vivid colors. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to +# the luminance component of the colors in the HTML output. Values below +# 100 gradually make the output lighter, whereas values above 100 make +# the output darker. The value divided by 100 is the actual gamma applied, +# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2, +# and 100 does not change the gamma. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting +# this to NO can help when comparing the output of multiple runs. + +HTML_TIMESTAMP = YES + +# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, +# files or namespaces will be aligned in HTML using tables. If set to +# NO a bullet list will be used. + +HTML_ALIGN_MEMBERS = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. For this to work a browser that supports +# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox +# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). + +HTML_DYNAMIC_SECTIONS = NO + +# If the GENERATE_DOCSET tag is set to YES, additional index files +# will be generated that can be used as input for Apple's Xcode 3 +# integrated development environment, introduced with OSX 10.5 (Leopard). +# To create a documentation set, doxygen will generate a Makefile in the +# HTML output directory. Running make will produce the docset in that +# directory and running "make install" will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find +# it at startup. +# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html +# for more information. + +GENERATE_DOCSET = NO + +# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the +# feed. A documentation feed provides an umbrella under which multiple +# documentation sets from a single provider (such as a company or product suite) +# can be grouped. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that +# should uniquely identify the documentation set bundle. This should be a +# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen +# will append .docset to the name. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify +# the documentation publisher. This should be a reverse domain-name style +# string, e.g. com.mycompany.MyDocSet.documentation. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be +# written to the html output directory. + +CHM_FILE = + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# the HTML help compiler on the generated index.hhp. + +HHC_LOCATION = + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING +# is used to encode HtmlHelp index (hhk), content (hhc) and project file +# content. + +CHM_INDEX_ENCODING = + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the HTML help documentation and to the tree view. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated +# that can be used as input for Qt's qhelpgenerator to generate a +# Qt Compressed Help (.qch) of the generated HTML documentation. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can +# be used to specify the file name of the resulting .qch file. +# The path specified is relative to the HTML output folder. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#namespace + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#virtual-folders + +QHP_VIRTUAL_FOLDER = doc + +# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to +# add. For more information please see +# http://doc.trolltech.com/qthelpproject.html#custom-filters + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see +# +# Qt Help Project / Custom Filters. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's +# filter section matches. +# +# Qt Help Project / Filter Attributes. + +QHP_SECT_FILTER_ATTRS = + +# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can +# be used to specify the location of Qt's qhelpgenerator. +# If non-empty doxygen will try to run qhelpgenerator on the generated +# .qhp file. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files +# will be generated, which together with the HTML files, form an Eclipse help +# plugin. To install this plugin and make it available under the help contents +# menu in Eclipse, the contents of the directory containing the HTML and XML +# files needs to be copied into the plugins directory of eclipse. The name of +# the directory within the plugins directory should be the same as +# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before +# the help appears. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have +# this name. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index at +# top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. + +DISABLE_INDEX = NO + +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values +# (range [0,1..20]) that doxygen will group on one line in the generated HTML +# documentation. Note that a value of 0 will completely suppress the enum +# values from appearing in the overview section. + +ENUM_VALUES_PER_LINE = 4 + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. +# If the tag value is set to YES, a side panel will be generated +# containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). +# Windows users are probably better off using the HTML help feature. + +GENERATE_TREEVIEW = NO + +# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories, +# and Class Hierarchy pages using a tree view instead of an ordered list. + +USE_INLINE_TREES = NO + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 250 + +# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open +# links to external symbols imported via tag files in a separate window. + +EXT_LINKS_IN_WINDOW = NO + +# Use this tag to change the font size of Latex formulas included +# as images in the HTML documentation. The default is 10. Note that +# when you change the font size after a successful doxygen run you need +# to manually remove any form_*.png images from the HTML output directory +# to force them to be regenerated. + +FORMULA_FONTSIZE = 10 + +# Use the FORMULA_TRANPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are +# not supported properly for IE 6.0, but are supported on all modern browsers. +# Note that when changing this option you need to delete any form_*.png files +# in the HTML output before the changes have effect. + +FORMULA_TRANSPARENT = YES + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax +# (see http://www.mathjax.org) which uses client side Javascript for the +# rendering instead of using prerendered bitmaps. Use this if you do not +# have LaTeX installed or if you want to formulas look prettier in the HTML +# output. When enabled you also need to install MathJax separately and +# configure the path to it using the MATHJAX_RELPATH option. + +USE_MATHJAX = NO + +# When MathJax is enabled you need to specify the location relative to the +# HTML output directory using the MATHJAX_RELPATH option. The destination +# directory should contain the MathJax.js script. For instance, if the mathjax +# directory is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to the +# mathjax.org site, so you can quickly see the result without installing +# MathJax, but it is strongly recommended to install a local copy of MathJax +# before deployment. + +MATHJAX_RELPATH = http://www.mathjax.org/mathjax + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box +# for the HTML output. The underlying search engine uses javascript +# and DHTML and should work on any modern browser. Note that when using +# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets +# (GENERATE_DOCSET) there is already a search function so this one should +# typically be disabled. For large projects the javascript based search engine +# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution. + +SEARCHENGINE = YES + +# When the SERVER_BASED_SEARCH tag is enabled the search engine will be +# implemented using a PHP enabled web server instead of at the web client +# using Javascript. Doxygen will generate the search PHP script and index +# file to put on the web server. The advantage of the server +# based approach is that it scales better to large projects and allows +# full text search. The disadvantages are that it is more difficult to setup +# and does not have live searching capabilities. + +SERVER_BASED_SEARCH = NO + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = NO + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. If left blank `latex' will be used as the default command name. +# Note that when enabling USE_PDFLATEX this option is only used for +# generating bitmaps for formulas in the HTML output, but not in the +# Makefile that is written to the output directory. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the +# default command name. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = a4 + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for +# the generated latex document. The footer should contain everything after +# the last chapter. If it is left blank doxygen will generate a +# standard footer. Notice: only use this tag if you know what you are doing! + +LATEX_FOOTER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = YES + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = YES + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = NO + +# If LATEX_HIDE_INDICES is set to YES then doxygen will not +# include the index chapters (such as File Index, Compound Index, etc.) +# in the output. + +LATEX_HIDE_INDICES = NO + +# If LATEX_SOURCE_CODE is set to YES then doxygen will include +# source code with syntax highlighting in the LaTeX output. +# Note that which sources are shown also depends on other settings +# such as SOURCE_BROWSER. + +LATEX_SOURCE_CODE = NO + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimized for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load stylesheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an rtf document. +# Syntax is similar to doxygen's config file. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command +# would be unable to find the correct page. The default is NO. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `xml' will be used as the default path. + +XML_OUTPUT = xml + +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_SCHEMA = + +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_DTD = + +# If the XML_PROGRAMLISTING tag is set to YES Doxygen will +# dump the program listings (including syntax highlighting +# and cross-referencing information) to the XML output. Note that +# enabling this will significantly increase the size of the XML output. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# to generate PDF and DVI output from the Perl module output. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. This is useful +# if you want to understand what is going on. On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller +# and Perl will parse it just the same. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same +# Makefile don't overwrite each other's variables. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_DEFINED tags. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# pointed to by INCLUDE_PATH will be searched when a #include is found. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. To prevent a macro definition from being +# undefined via #undef or recursively expanded use the := operator +# instead of the = operator. + +PREDEFINED = + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition that +# overrules the definition found in the source code. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all references to function-like macros +# that are alone on a line, have an all uppercase name, and do not end with a +# semicolon, because these will confuse the parser if not removed. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES option can be used to specify one or more tagfiles. +# Optionally an initial location of the external documentation +# can be added for each tagfile. The format of a tag file without +# this location is as follows: +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where "loc1" and "loc2" can be relative or absolute paths or +# URLs. If a location is present for each tag, the installdox tool +# does not have to be run to correct the links. +# Note that each tag file must have a unique name +# (where the name does NOT include the path) +# If a tag file is not located in the directory in which doxygen +# is run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will +# be listed. + +EXTERNAL_GROUPS = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base +# or super classes. Setting the tag to NO turns the diagrams off. Note that +# this option also works with HAVE_DOT disabled, but it is recommended to +# install and use dot, since it yields more powerful graphs. + +CLASS_DIAGRAMS = YES + +# You can define message sequence charts within doxygen comments using the \msc +# command. Doxygen will then run the mscgen tool (see +# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the +# documentation. The MSCGEN_PATH tag allows you to specify the directory where +# the mscgen tool resides. If left empty the tool is assumed to be found in the +# default search path. + +MSCGEN_PATH = + +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented +# or is not a class. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = NO + +# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is +# allowed to run in parallel. When set to 0 (the default) doxygen will +# base this on the number of processors available in the system. You can set it +# explicitly to a value larger than 0 to get control over the balance +# between CPU load and processing speed. + +DOT_NUM_THREADS = 0 + +# By default doxygen will write a font called Helvetica to the output +# directory and reference it in all dot files that doxygen generates. +# When you want a differently looking font you can specify the font name +# using DOT_FONTNAME. You need to make sure dot is able to find the font, +# which can be done by putting it in a standard location or by setting the +# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory +# containing the font. + +DOT_FONTNAME = Helvetica + +# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. +# The default size is 10pt. + +DOT_FONTSIZE = 10 + +# By default doxygen will tell dot to use the output directory to look for the +# FreeSans.ttf font (which doxygen will put there itself). If you specify a +# different font using DOT_FONTNAME you can set the path where dot +# can find it using this tag. + +DOT_FONTPATH = + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# the CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = YES + +# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for groups, showing the direct groups dependencies + +GROUP_GRAPHS = YES + +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. + +UML_LOOK = NO + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = NO + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with +# other documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH and HAVE_DOT options are set to YES then +# doxygen will generate a call dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable call graphs +# for selected functions only using the \callgraph command. + +CALL_GRAPH = NO + +# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then +# doxygen will generate a caller dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable caller +# graphs for selected functions only using the \callergraph command. + +CALLER_GRAPH = NO + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will generate a graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES +# then doxygen will show the dependencies a directory has on other directories +# in a graphical way. The dependency relations are determined by the #include +# relations between the files in the directories. + +DIRECTORY_GRAPH = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are svg, png, jpg, or gif. +# If left blank png will be used. + +DOT_IMAGE_FORMAT = png + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = + +# The MSCFILE_DIRS tag can be used to specify one or more directories that +# contain msc files that are included in the documentation (see the +# \mscfile command). + +MSCFILE_DIRS = + +# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of +# nodes that will be shown in the graph. If the number of nodes in a graph +# becomes larger than this value, doxygen will truncate the graph, which is +# visualized by representing a node as a red box. Note that doxygen if the +# number of direct children of the root node in a graph is already larger than +# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note +# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. + +DOT_GRAPH_MAX_NODES = 50 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the +# graphs generated by dot. A depth value of 3 means that only nodes reachable +# from the root by following a path via at most 3 edges will be shown. Nodes +# that lay further from the root node will be omitted. Note that setting this +# option to 1 or 2 may greatly reduce the computation time needed for large +# code bases. Also note that the size of a graph can be further restricted by +# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. + +MAX_DOT_GRAPH_DEPTH = 0 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, because dot on Windows does not +# seem to support this out of the box. Warning: Depending on the platform used, +# enabling this option may lead to badly anti-aliased labels on the edges of +# a graph (i.e. they become hard to read). + +DOT_TRANSPARENT = NO + +# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) +# support this, this feature is disabled by default. + +DOT_MULTI_TARGETS = NO + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermediate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES diff --git a/doc/README b/doc/README new file mode 100644 index 0000000..ebab395 --- /dev/null +++ b/doc/README @@ -0,0 +1,14 @@ + +Copyright (c) 2014 TRI Developers + + +triangles 3.3.3.3 BETA + +Copyright (c) 2014 TRI Developers +Copyright (c) 2013 NovaCoin Developers +Copyright (c) 2011-2012 Bitcoin Developers +Distributed under the MIT/X11 software license, see the accompanying +file license.txt or http://www.opensource.org/licenses/mit-license.php. +This product includes software developed by the OpenSSL Project for use in +the OpenSSL Toolkit (http://www.openssl.org/). This product includes +cryptographic software written by Eric Young (eay@cryptsoft.com). diff --git a/doc/assets-attribution.txt b/doc/assets-attribution.txt new file mode 100644 index 0000000..0b0e377 --- /dev/null +++ b/doc/assets-attribution.txt @@ -0,0 +1,56 @@ +Code: src/strlcpy.h +Author: Todd C. Miller +License: ISC + +Icon: src/qt/res/icons/clock*.png, src/qt/res/icons/tx*.png, + src/qt/res/src/*.svg +Designer: Wladimir van der Laan +License: MIT + +Icon: src/qt/res/icons/address-book.png, src/qt/res/icons/export.png, + src/qt/res/icons/history.png, src/qt/res/icons/key.png, + src/qt/res/icons/lock_*.png, src/qt/res/icons/overview.png, + src/qt/res/icons/receive.png, src/qt/res/icons/send.png, + src/qt/res/icons/synced.png, src/qt/res/icons/filesave.png +Icon Pack: NUVOLA ICON THEME for KDE 3.x +Designer: David Vignoni (david@icon-king.com) + ICON KING - www.icon-king.com +License: LGPL +Site: http://www.icon-king.com/projects/nuvola/ + +Icon: src/qt/res/icons/connect*.png +Icon Pack: Human-O2 +Designer: schollidesign +License: GNU/GPL +Site: http://findicons.com/icon/93743/blocks_gnome_netstatus_0 + +Icon: src/qt/res/icons/transaction*.png +Designer: md2k7 +Site: https://forum.bitcoin.org/index.php?topic=15276.0 +License: You are free to do with these icons as you wish, including selling, + copying, modifying etc. + +Icon: src/qt/res/icons/configure.png, src/qt/res/icons/quit.png, + src/qt/res/icons/editcopy.png, src/qt/res/icons/editpaste.png, + src/qt/res/icons/add.png, src/qt/res/icons/edit.png, + src/qt/res/icons/remove.png (edited) +Designer: http://www.everaldo.com +Icon Pack: Crystal SVG +License: LGPL + +Icon: src/qt/res/icons/bitcoin.png, src/qt/res/icons/toolbar.png +Designer: Bitboy (optimized for 16x16 by Wladimir van der Laan) +License: Public Domain +Site: http://forum.bitcoin.org/?topic=1756.0 + +Icon: scripts/img/reload.xcf (modified),src/qt/res/movies/update_spinner.mng +Icon Pack: Kids +Designer: Everaldo (Everaldo Coelho) +License: GNU/GPL +Site: http://findicons.com/icon/17102/reload?id=17102 + +Image: src/qt/res/images/splash2.jpg (Wallet image) +Designer: Crobbo (forum) +Site: https://bitcointalk.org/index.php?topic=32273.0 +License: Public domain + diff --git a/doc/bitcoin_logo_doxygen.png b/doc/bitcoin_logo_doxygen.png new file mode 100644 index 0000000000000000000000000000000000000000..5b41b02e18e57e42ba6ee790ca69e88439ea09c0 GIT binary patch literal 5735 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 literal 0 HcmV?d00001 diff --git a/doc/build-msw.txt b/doc/build-msw.txt new file mode 100644 index 0000000..b180515 --- /dev/null +++ b/doc/build-msw.txt @@ -0,0 +1,84 @@ +Copyright (c) 2009-2012 Bitcoin Developers +Distributed under the MIT/X11 software license, see the accompanying +file license.txt or http://www.opensource.org/licenses/mit-license.php. +This product includes software developed by the OpenSSL Project for use in +the OpenSSL Toolkit (http://www.openssl.org/). This product includes +cryptographic software written by Eric Young (eay@cryptsoft.com) and UPnP +software written by Thomas Bernard. + + +See readme-qt.rst for instructions on building Bitcoin QT, the +graphical user interface. + +WINDOWS BUILD NOTES +=================== + +Compilers Supported +------------------- +TODO: What works? +Note: releases are cross-compiled using mingw running on Linux. + + +Dependencies +------------ +Libraries you need to download separately and build: + + default path download +OpenSSL \openssl-1.0.1b-mgw http://www.openssl.org/source/ +Berkeley DB \db-4.8.30.NC-mgw http://www.oracle.com/technology/software/products/berkeley-db/index.html +Boost \boost-1.47.0-mgw http://www.boost.org/users/download/ +miniupnpc \miniupnpc-1.6-mgw http://miniupnp.tuxfamily.org/files/ + +Their licenses: +OpenSSL Old BSD license with the problematic advertising requirement +Berkeley DB New BSD license with additional requirement that linked software must be free open source +Boost MIT-like license +miniupnpc New (3-clause) BSD license + +Versions used in this release: +OpenSSL 1.0.1b +Berkeley DB 4.8.30.NC +Boost 1.47.0 +miniupnpc 1.6 + + +OpenSSL +------- +MSYS shell: +un-tar sources with MSYS 'tar xfz' to avoid issue with symlinks (OpenSSL ticket 2377) +change 'MAKE' env. variable from 'C:\MinGW32\bin\mingw32-make.exe' to '/c/MinGW32/bin/mingw32-make.exe' + +cd /c/openssl-1.0.1b-mgw +./config +make + +Berkeley DB +----------- +MSYS shell: +cd /c/db-4.8.30.NC-mgw/build_unix +sh ../dist/configure --enable-mingw --enable-cxx +make + +Boost +----- +DOS prompt: +downloaded boost jam 3.1.18 +cd \boost-1.47.0-mgw +bjam toolset=gcc --build-type=complete stage + +MiniUPnPc +--------- +UPnP support is optional, make with USE_UPNP= to disable it. + +MSYS shell: +cd /c/miniupnpc-1.6-mgw +make -f Makefile.mingw +mkdir miniupnpc +cp *.h miniupnpc/ + +Bitcoin +------- +DOS prompt: +cd \bitcoin\src +mingw32-make -f makefile.mingw +strip bitcoind.exe diff --git a/doc/build-osx.txt b/doc/build-osx.txt new file mode 100644 index 0000000..b5916b2 --- /dev/null +++ b/doc/build-osx.txt @@ -0,0 +1,61 @@ +Copyright (c) 2009-2012 Bitcoin Developers +Distributed under the MIT/X11 software license, see the accompanying file +license.txt or http://www.opensource.org/licenses/mit-license.php. This +product includes software developed by the OpenSSL Project for use in the +OpenSSL Toolkit (http://www.openssl.org/). This product includes cryptographic +software written by Eric Young (eay@cryptsoft.com) and UPnP software written by +Thomas Bernard. + + +Mac OS X bitcoind build instructions +Laszlo Hanyecz +Douglas Huff + +These instructions are not complete and probably won't work. + +They will be ammneded in the future. + +Please read this if you are on 10.9: +https://github.com/bitcoin/bitcoin/issues/3228 + + +See readme-qt.rst for instructions on building Bitcoin QT, the +graphical user interface. + +Tested on 10.5 and 10.6 intel. PPC is not supported because it's big-endian. + +All of the commands should be executed in Terminal.app.. it's in +/Applications/Utilities + +You need to install XCode with all the options checked so that the compiler and +everything is available in /usr not just /Developer I think it comes on the DVD +but you can get the current version from http://developer.apple.com + + +1. Clone the github tree to get the source code: + +git clone git@github.com:bitcoin/bitcoin.git bitcoin + +2. Download and install MacPorts from http://www.macports.org/ + +2a. (for 10.7 Lion) + Edit /opt/local/etc/macports/macports.conf and uncomment "build_arch i386" + +3. Install dependencies from MacPorts + +sudo port install boost db48 openssl miniupnpc + +Optionally install qrencode (and set USE_QRCODE=1): +sudo port install qrencode + +4. Now you should be able to build bitcoind: + +cd bitcoin/src +make -f makefile.osx + +Run: + ./bitcoind --help # for a list of command-line options. +Run + ./bitcoind -daemon # to start the bitcoin daemon. +Run + ./bitcoind help # When the daemon is running, to get a list of RPC commands diff --git a/doc/build-unix.txt b/doc/build-unix.txt new file mode 100644 index 0000000..3dffb22 --- /dev/null +++ b/doc/build-unix.txt @@ -0,0 +1,159 @@ +Copyright (c) 2009-2012 Bitcoin Developers +Distributed under the MIT/X11 software license, see the accompanying +file license.txt or http://www.opensource.org/licenses/mit-license.php. +This product includes software developed by the OpenSSL Project for use in +the OpenSSL Toolkit (http://www.openssl.org/). This product includes +cryptographic software written by Eric Young (eay@cryptsoft.com) and UPnP +software written by Thomas Bernard. + + +UNIX BUILD NOTES +================ + +To Build +-------- + +cd src/ +make -f makefile.unix # Headless bitcoin + +See readme-qt.rst for instructions on building Bitcoin QT, +the graphical bitcoin. + +Dependencies +------------ + + Library Purpose Description + ------- ------- ----------- + libssl SSL Support Secure communications + libdb4.8 Berkeley DB Blockchain & wallet storage + libboost Boost C++ Library + miniupnpc UPnP Support Optional firewall-jumping support + libqrencode QRCode generation Optional QRCode generation + +Note that libexecinfo should be installed, if you building under *BSD systems. +This library provides backtrace facility. + +miniupnpc may be used for UPnP port mapping. It can be downloaded from +http://miniupnp.tuxfamily.org/files/. UPnP support is compiled in and +turned off by default. Set USE_UPNP to a different value to control this: + USE_UPNP=- No UPnP support - miniupnp not required + USE_UPNP=0 (the default) UPnP support turned off by default at runtime + USE_UPNP=1 UPnP support turned on by default at runtime + +libqrencode may be used for QRCode image generation. It can be downloaded +from http://fukuchi.org/works/qrencode/index.html.en, or installed via +your package manager. Set USE_QRCODE to control this: + USE_QRCODE=0 (the default) No QRCode support - libqrcode not required + USE_QRCODE=1 QRCode support enabled + +Licenses of statically linked libraries: + Berkeley DB New BSD license with additional requirement that linked + software must be free open source + Boost MIT-like license + miniupnpc New (3-clause) BSD license + +Versions used in this release: + GCC 4.3.3 + OpenSSL 0.9.8g + Berkeley DB 4.8.30.NC + Boost 1.37 + miniupnpc 1.6 + +Dependency Build Instructions: Ubuntu & Debian +---------------------------------------------- +sudo apt-get install build-essential +sudo apt-get install libssl-dev +sudo apt-get install libdb4.8-dev +sudo apt-get install libdb4.8++-dev + Boost 1.40+: sudo apt-get install libboost-all-dev + or Boost 1.37: sudo apt-get install libboost1.37-dev +sudo apt-get install libqrencode-dev + +If using Boost 1.37, append -mt to the boost libraries in the makefile. + + +Dependency Build Instructions: Gentoo +------------------------------------- + +Note: If you just want to install bitcoind on Gentoo, you can add the Bitcoin + overlay and use your package manager: + layman -a bitcoin && emerge bitcoind + +emerge -av1 --noreplace boost glib openssl sys-libs/db:4.8 + +Take the following steps to build (no UPnP support): + cd ${BITCOIN_DIR}/src + make -f makefile.unix USE_UPNP= BDB_INCLUDE_PATH='/usr/include/db4.8' + strip bitcoind + + +Notes +----- +The release is built with GCC and then "strip bitcoind" to strip the debug +symbols, which reduces the executable size by about 90%. + + +miniupnpc +--------- +tar -xzvf miniupnpc-1.6.tar.gz +cd miniupnpc-1.6 +make +sudo su +make install + + +Berkeley DB +----------- +You need Berkeley DB 4.8. If you have to build Berkeley DB yourself: +../dist/configure --enable-cxx +make + + +Boost +----- +If you need to build Boost yourself: +sudo su +./bootstrap.sh +./bjam install + + +Security +-------- +To help make your bitcoin installation more secure by making certain attacks impossible to +exploit even if a vulnerability is found, you can take the following measures: + +* Position Independent Executable + Build position independent code to take advantage of Address Space Layout Randomization + offered by some kernels. An attacker who is able to cause execution of code at an arbitrary + memory location is thwarted if he doesn't know where anything useful is located. + The stack and heap are randomly located by default but this allows the code section to be + randomly located as well. + + On an Amd64 processor where a library was not compiled with -fPIC, this will cause an error + such as: "relocation R_X86_64_32 against `......' can not be used when making a shared object;" + + To build with PIE, use: + make -f makefile.unix ... -e PIE=1 + + To test that you have built PIE executable, install scanelf, part of paxutils, and use: + scanelf -e ./bitcoin + + The output should contain: + TYPE + ET_DYN + +* Non-executable Stack + If the stack is executable then trivial stack based buffer overflow exploits are possible if + vulnerable buffers are found. By default, bitcoin should be built with a non-executable stack + but if one of the libraries it uses asks for an executable stack or someone makes a mistake + and uses a compiler extension which requires an executable stack, it will silently build an + executable without the non-executable stack protection. + + To verify that the stack is non-executable after compiling use: + scanelf -e ./bitcoin + + the output should contain: + STK/REL/PTL + RW- R-- RW- + + The STK RW- means that the stack is readable and writeable but not executable. diff --git a/doc/coding.txt b/doc/coding.txt new file mode 100644 index 0000000..46da661 --- /dev/null +++ b/doc/coding.txt @@ -0,0 +1,99 @@ +Please be consistent with the existing coding style. + +Block style: + +bool Function(char* psz, int n) +{ + // Comment summarising what this section of code does + for (int i = 0; i < n; i++) + { + // When something fails, return early + if (!Something()) + return false; + ... + } + + // Success return is usually at the end + return true; +} + +- ANSI/Allman block style +- 4 space indenting, no tabs +- No extra spaces inside parenthesis; please don't do ( this ) +- No space after function names, one space after if, for and while + +Variable names begin with the type in lowercase, like nSomeVariable. +Please don't put the first word of the variable name in lowercase like +someVariable. + +Common types: +n integer number: short, unsigned short, int, unsigned int, + int64, uint64, sometimes char if used as a number +d double, float +f flag +hash uint256 +p pointer or array, one p for each level of indirection +psz pointer to null terminated string +str string object +v vector or similar list objects +map map or multimap +set set or multiset +bn CBigNum + +------------------------- +Locking/mutex usage notes + +The code is multi-threaded, and uses mutexes and the +CRITICAL_BLOCK/TRY_CRITICAL_BLOCK macros to protect data structures. + +Deadlocks due to inconsistent lock ordering (thread 1 locks cs_main +and then cs_wallet, while thread 2 locks them in the opposite order: +result, deadlock as each waits for the other to release its lock) are +a problem. Compile with -DDEBUG_LOCKORDER to get lock order +inconsistencies reported in the debug.log file. + +Re-architecting the core code so there are better-defined interfaces +between the various components is a goal, with any necessary locking +done by the components (e.g. see the self-contained CKeyStore class +and its cs_KeyStore lock for example). + +------- +Threads + +StartNode : Starts other threads. + +ThreadGetMyExternalIP : Determines outside-the-firewall IP address, +sends addr message to connected peers when it determines it. + +ThreadIRCSeed : Joins IRC bootstrapping channel, watching for new +peers and advertising this node's IP address. + +ThreadSocketHandler : Sends/Receives data from peers on port 8333. + +ThreadMessageHandler : Higher-level message handling (sending and +receiving). + +ThreadOpenConnections : Initiates new connections to peers. + +ThreadTopUpKeyPool : replenishes the keystore's keypool. + +ThreadCleanWalletPassphrase : re-locks an encrypted wallet after user +has unlocked it for a period of time. + +SendingDialogStartTransfer : used by pay-via-ip-address code (obsolete) + +ThreadDelayedRepaint : repaint the gui + +ThreadFlushWalletDB : Close the wallet.dat file if it hasn't been used +in 500ms. + +ThreadRPCServer : Remote procedure call handler, listens on port 8332 +for connections and services them. + +ThreadBitcoinMiner : Generates bitcoins + +ThreadMapPort : Universal plug-and-play startup/shutdown + +Shutdown : Does an orderly shutdown of everything + +ExitTimeout : Windows-only, sleeps 5 seconds then exits application diff --git a/doc/readme-qt.rst b/doc/readme-qt.rst new file mode 100644 index 0000000..6bfbd93 --- /dev/null +++ b/doc/readme-qt.rst @@ -0,0 +1,159 @@ +Bitcoin-qt: Qt4 GUI for Bitcoin +=============================== + +Build instructions +=================== + +Debian +------- + +First, make sure that the required packages for Qt4 development of your +distribution are installed. + +On recent Ubuntu releases, the `libdb4.8++-dev` package is not in the default +repositories. However it's in the bitcoin repository, which we can add +with: + + apt-add-repository ppa:bitcoin/bitcoin + +Then we need to make sure our build environment is up to date. For Debian and Ubuntu: + +:: + + apt-get install qt4-qmake libqt4-dev build-essential libboost-dev libboost-system-dev \ + libboost-filesystem-dev libboost-program-options-dev libboost-thread-dev \ + libssl-dev libdb4.8++-dev libminiupnpc-dev libminiupnpc8 + +then execute the following: + +:: + + qmake + make + +Alternatively, install Qt Creator and open the `bitcoin-qt.pro` file. + +An executable named `bitcoin-qt` will be built. + + +Windows +-------- + +Windows build instructions: + +- Download the `QT Windows SDK`_ and install it. You don't need the Symbian stuff, just the desktop Qt. + +- Download and extract the `dependencies archive`_ [#]_, or compile openssl, boost and dbcxx yourself. + +- Copy the contents of the folder "deps" to "X:\\QtSDK\\mingw", replace X:\\ with the location where you installed the Qt SDK. Make sure that the contents of "deps\\include" end up in the current "include" directory. + +- Open the .pro file in QT creator and build as normal (ctrl-B) + +.. _`QT Windows SDK`: http://qt.nokia.com/downloads/sdk-windows-cpp +.. _`dependencies archive`: https://download.visucore.com/bitcoin/qtgui_deps_1.zip +.. [#] PGP signature: https://download.visucore.com/bitcoin/qtgui_deps_1.zip.sig (signed with RSA key ID `610945D0`_) +.. _`610945D0`: http://pgp.mit.edu:11371/pks/lookup?op=get&search=0x610945D0 + + +Mac OS X +-------- + +- Download and install the `Qt Mac OS X SDK`_. It is recommended to also install Apple's Xcode with UNIX tools. + +- Download and install `MacPorts`_. + +- Execute the following commands in a terminal to get the dependencies: + +:: + + sudo port selfupdate + sudo port install boost db48 miniupnpc + +- Open the .pro file in Qt Creator and build as normal (cmd-B) + +.. _`Qt Mac OS X SDK`: http://qt.nokia.com/downloads/sdk-mac-os-cpp +.. _`MacPorts`: http://www.macports.org/install.php + + +Build configuration options +============================ + +UPNnP port forwarding +--------------------- + +To use UPnP for port forwarding behind a NAT router (recommended, as more connections overall allow for a faster and more stable bitcoin experience), pass the following argument to qmake: + +:: + + qmake "USE_UPNP=1" + +(in **Qt Creator**, you can find the setting for additional qmake arguments under "Projects" -> "Build Settings" -> "Build Steps", then click "Details" next to **qmake**) + +This requires miniupnpc for UPnP port mapping. It can be downloaded from +http://miniupnp.tuxfamily.org/files/. UPnP support is not compiled in by default. + +Set USE_UPNP to a different value to control this: + ++------------+--------------------------------------------------------------------------+ +| USE_UPNP=- | no UPnP support, miniupnpc not required; | ++------------+--------------------------------------------------------------------------+ +| USE_UPNP=0 | (the default) built with UPnP, support turned off by default at runtime; | ++------------+--------------------------------------------------------------------------+ +| USE_UPNP=1 | build with UPnP support turned on by default at runtime. | ++------------+--------------------------------------------------------------------------+ + +Notification support for recent (k)ubuntu versions +--------------------------------------------------- + +To see desktop notifications on (k)ubuntu versions starting from 10.04, enable usage of the +FreeDesktop notification interface through DBUS using the following qmake option: + +:: + + qmake "USE_DBUS=1" + +Generation of QR codes +----------------------- + +libqrencode may be used to generate QRCode images for payment requests. +It can be downloaded from http://fukuchi.org/works/qrencode/index.html.en, or installed via your package manager. Pass the USE_QRCODE +flag to qmake to control this: + ++--------------+--------------------------------------------------------------------------+ +| USE_QRCODE=0 | (the default) No QRCode support - libarcode not required | ++--------------+--------------------------------------------------------------------------+ +| USE_QRCODE=1 | QRCode support enabled | ++--------------+--------------------------------------------------------------------------+ + + +Berkely DB version warning +========================== + +A warning for people using the *static binary* version of Bitcoin on a Linux/UNIX-ish system (tl;dr: **Berkely DB databases are not forward compatible**). + +The static binary version of Bitcoin is linked against libdb4.8 (see also `this Debian issue`_). + +Now the nasty thing is that databases from 5.X are not compatible with 4.X. + +If the globally installed development package of Berkely DB installed on your system is 5.X, any source you +build yourself will be linked against that. The first time you run with a 5.X version the database will be upgraded, +and 4.X cannot open the new format. This means that you cannot go back to the old statically linked version without +significant hassle! + +.. _`this Debian issue`: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=621425 + +Ubuntu 11.10 warning +==================== + +Ubuntu 11.10 has a package called 'qt-at-spi' installed by default. At the time of writing, having that package +installed causes bitcoin-qt to crash intermittently. The issue has been reported as `launchpad bug 857790`_, but +isn't yet fixed. + +Until the bug is fixed, you can remove the qt-at-spi package to work around the problem, though this will presumably +disable screen reader functionality for Qt apps: + +:: + + sudo apt-get remove qt-at-spi + +.. _`launchpad bug 857790`: https://bugs.launchpad.net/ubuntu/+source/qt-at-spi/+bug/857790 diff --git a/doc/release-process.txt b/doc/release-process.txt new file mode 100644 index 0000000..ed23ef3 --- /dev/null +++ b/doc/release-process.txt @@ -0,0 +1,142 @@ +* update translations (ping tcatm on IRC for now) + +* update (commit) version in sources + bitcoin-qt.pro + src/version.h + share/setup.nsi + doc/README* + +* tag version in git + + git tag -a v0.5.1 + +* write release notes. git shortlog helps a lot: + + git shortlog --no-merges v0.5.0.. + +* perform gitian builds + + * From a directory containing the bitcoin source, gitian-builder and gitian.sigs + export SIGNER=(your gitian key, ie bluematt, sipa, etc) + export VERSION=0.5.1 + cd ./gitian-builder + + * Fetch and build inputs: + mkdir -p inputs; cd inputs/ + wget 'http://miniupnp.free.fr/files/download.php?file=miniupnpc-1.6.tar.gz' -O miniupnpc-1.6.tar.gz + wget 'http://www.openssl.org/source/openssl-1.0.1b.tar.gz' + wget 'http://download.oracle.com/berkeley-db/db-4.8.30.NC.tar.gz' + wget 'http://zlib.net/zlib-1.2.6.tar.gz' + wget 'ftp://ftp.simplesystems.org/pub/libpng/png/src/libpng-1.5.9.tar.gz' + wget 'http://fukuchi.org/works/qrencode/qrencode-3.2.0.tar.bz2' + wget 'http://downloads.sourceforge.net/project/boost/boost/1.47.0/boost_1_47_0.tar.bz2' + wget 'http://download.qt.nokia.com/qt/source/qt-everywhere-opensource-src-4.7.4.tar.gz' + cd .. + ./bin/gbuild ../bitcoin/contrib/gitian-descriptors/boost-win32.yml + cp build/out/boost-win32-1.47.0-gitian.zip inputs/ + ./bin/gbuild ../bitcoin/contrib/gitian-descriptors/qt-win32.yml + cp build/out/qt-win32-4.7.4-gitian.zip inputs/ + ./bin/gbuild ../bitcoin/contrib/gitian-descriptors/deps-win32.yml + cp build/out/bitcoin-deps-0.0.3.zip inputs/ + + * Build bitcoind and bitcoin-qt on Linux32, Linux64, and Win32: + ./bin/gbuild --commit bitcoin=v${VERSION} ../bitcoin/contrib/gitian-descriptors/gitian.yml + ./bin/gsign --signer $SIGNER --release ${VERSION} --destination ../gitian.sigs/ ../bitcoin/contrib/gitian-descriptors/gitian.yml + pushd build/out + zip -r bitcoin-${VERSION}-linux-gitian.zip * + mv bitcoin-${VERSION}-linux-gitian.zip ../../ + popd + ./bin/gbuild --commit bitcoin=v${VERSION} ../bitcoin/contrib/gitian-descriptors/gitian-win32.yml + ./bin/gsign --signer $SIGNER --release ${VERSION}-win32 --destination ../gitian.sigs/ ../bitcoin/contrib/gitian-descriptors/gitian-win32.yml + pushd build/out + zip -r bitcoin-${VERSION}-win32-gitian.zip * + mv bitcoin-${VERSION}-win32-gitian.zip ../../ + popd + + Build output expected: + 1. linux 32-bit and 64-bit binaries + source (bitcoin-${VERSION}-linux-gitian.zip) + 2. windows 32-bit binary, installer + source (bitcoin-${VERSION}-win32-gitian.zip) + 3. Gitian signatures (in gitian.sigs/${VERSION}[-win32]/(your gitian key)/ + +* repackage gitian builds for release as stand-alone zip/tar/installer exe + + * Linux .tar.gz: + unzip bitcoin-${VERSION}-linux-gitian.zip -d bitcoin-${VERSION}-linux + tar czvf bitcoin-${VERSION}-linux.tar.gz bitcoin-${VERSION}-linux + rm -rf bitcoin-${VERSION}-linux + + * Windows .zip and setup.exe: + unzip bitcoin-${VERSION}-win32-gitian.zip -d bitcoin-${VERSION}-win32 + mv bitcoin-${VERSION}-win32/bitcoin-*-setup.exe . + zip -r bitcoin-${VERSION}-win32.zip bitcoin-${VERSION}-win32 + rm -rf bitcoin-${VERSION}-win32 + +* perform Mac build + See this blog post for how Gavin set up his build environment to build the OSX + release; note that a patched version of macdeployqt is not needed anymore, as + the required functionality and fixes are implemented directly in macdeployqtplus: + http://gavintech.blogspot.com/2011/11/deploying-bitcoin-qt-on-osx.html + Gavin also had trouble with the macports py27-appscript package; he + ended up installing a version that worked with: /usr/bin/easy_install-2.7 appscript + + qmake RELEASE=1 USE_UPNP=1 USE_QRCODE=1 bitcoin-qt.pro + make + export QTDIR=/opt/local/share/qt4 # needed to find translations/qt_*.qm files + T=$(contrib/qt_translations.py $QTDIR/translations src/qt/locale) + python2.7 contrib/macdeploy/macdeployqtplus Bitcoin-Qt.app -add-qt-tr $T -dmg -fancy contrib/macdeploy/fancy.plist + + Build output expected: + Bitcoin-Qt.dmg + +* upload builds to SourceForge + +* create SHA256SUMS for builds, and PGP-sign it + +* update bitcoin.org version + +* update forum version + +* update wiki download links + +* update wiki changelog: https://en.bitcoin.it/wiki/Changelog + +* Commit your signature to gitian.sigs: + pushd gitian.sigs + git add ${VERSION}/${SIGNER} + git add ${VERSION}-win32/${SIGNER} + git commit -a + git push # Assuming you can push to the gitian.sigs tree + popd + +------------------------------------------------------------------------- + +* After 3 or more people have gitian-built, repackage gitian-signed zips: + + * From a directory containing bitcoin source, gitian.sigs and gitian zips + export VERSION=0.5.1 + mkdir bitcoin-${VERSION}-linux-gitian + pushd bitcoin-${VERSION}-linux-gitian + unzip ../bitcoin-${VERSION}-linux-gitian.zip + mkdir gitian + cp ../bitcoin/contrib/gitian-downloader/*.pgp ./gitian/ + for signer in $(ls ../gitian.sigs/${VERSION}/); do + cp ../gitian.sigs/${VERSION}/${signer}/bitcoin-build.assert ./gitian/${signer}-build.assert + cp ../gitian.sigs/${VERSION}/${signer}/bitcoin-build.assert.sig ./gitian/${signer}-build.assert.sig + done + zip -r bitcoin-${VERSION}-linux-gitian.zip * + cp bitcoin-${VERSION}-linux-gitian.zip ../ + popd + mkdir bitcoin-${VERSION}-win32-gitian + pushd bitcoin-${VERSION}-win32-gitian + unzip ../bitcoin-${VERSION}-win32-gitian.zip + mkdir gitian + cp ../bitcoin/contrib/gitian-downloader/*.pgp ./gitian/ + for signer in $(ls ../gitian.sigs/${VERSION}-win32/); do + cp ../gitian.sigs/${VERSION}-win32/${signer}/bitcoin-build.assert ./gitian/${signer}-build.assert + cp ../gitian.sigs/${VERSION}-win32/${signer}/bitcoin-build.assert.sig ./gitian/${signer}-build.assert.sig + done + zip -r bitcoin-${VERSION}-win32-gitian.zip * + cp bitcoin-${VERSION}-win32-gitian.zip ../ + popd + + * Upload gitian zips to SourceForge diff --git a/doc/translation_process.md b/doc/translation_process.md new file mode 100644 index 0000000..3ddfc0c --- /dev/null +++ b/doc/translation_process.md @@ -0,0 +1,80 @@ +Translations +============ + +The Qt GUI can be easily translated into other languages. Here's how we +handle those translations. + +Files and Folders +----------------- + +### bitcoin-qt.pro + +This file takes care of generating `.qm` files from `.ts` files. It is mostly +automated. + +### src/qt/bitcoin.qrc + +This file must be updated whenever a new translation is added. Please note that +files must end with `.qm`, not `.ts`. + + + locale/bitcoin_en.qm + ... + + +### src/qt/locale/ + +This directory contains all translations. Filenames must adhere to this format: + + bitcoin_xx_YY.ts or bitcoin_xx.ts + +#### Source file + +`src/qt/locale/bitcoin_en.ts` is treated in a special way. It is used as the +source for all other translations. Whenever a string in the code is changed +this file must be updated to reflect those changes. Usually, this can be +accomplished by running `lupdate` (included in the Qt SDK). + +An updated source file should be merged to github and transifex will pick it +up from there. Afterwards the new strings show up as "Remaining" in transifex +and can be translated. + +Syncing with transifex +---------------------- + +We are using http://transifex.net as a frontend for translating the client. + +https://www.transifex.net/projects/p/bitcoin/resource/tx/ + +The "transifex client" (see: http://help.transifex.net/features/client/) +will help with fetching new translations from transifex. Use the following +config to be able to connect with the client. + +### .tx/config + + [main] + host = https://www.transifex.net + + [bitcoin.tx] + file_filter = src/qt/locale/bitcoin_.ts + source_file = src/qt/locale/bitcoin_en.ts + source_lang = en + +### .tx/config (for Windows) + + [main] + host = https://www.transifex.net + + [bitcoin.tx] + file_filter = src\qt\locale\bitcoin_.ts + source_file = src\qt\locale\bitcoin_en.ts + source_lang = en + +It is also possible to directly download new translations one by one from transifex. + +### Fetching new translations + +1. `tx pull -a` +2. update `src/qt/bitcoin.qrc` manually or via + `ls src/qt/locale/*ts|xargs -n1 basename|sed 's/\(bitcoin_\(.*\)\).ts/locale/\1.qm<\/file>/'` +3. `git add` new translations from `src/qt/locale/` diff --git a/share/genbuild.sh b/share/genbuild.sh new file mode 100644 index 0000000..d959877 --- /dev/null +++ b/share/genbuild.sh @@ -0,0 +1,35 @@ +#!/bin/sh + +if [ $# -gt 0 ]; then + FILE="$1" + shift + if [ -f "$FILE" ]; then + INFO="$(head -n 1 "$FILE")" + fi +else + echo "Usage: $0 " + exit 1 +fi + +if [ -e "$(which git)" ]; then + # clean 'dirty' status of touched files that haven't been modified + git diff >/dev/null 2>/dev/null + + # get a string like "v0.6.0-66-g59887e8-dirty" + DESC="$(git describe --dirty 2>/dev/null)" + + # get a string like "2012-04-10 16:27:19 +0200" + TIME="$(git log -n 1 --format="%ci")" +fi + +if [ -n "$DESC" ]; then + NEWINFO="#define BUILD_DESC \"$DESC\"" +else + NEWINFO="// No build information available" +fi + +# only update build.h if necessary +if [ "$INFO" != "$NEWINFO" ]; then + echo "$NEWINFO" >"$FILE" + echo "#define BUILD_DATE \"$TIME\"" >>"$FILE" +fi diff --git a/share/pixmaps/addressbook16.bmp b/share/pixmaps/addressbook16.bmp new file mode 100644 index 0000000000000000000000000000000000000000..c5576910b1b6b95c23ed7c53adec399a944e610a GIT binary patch literal 1334 zcmZ9MKWrOS9LK*+iDcA*T|jP9K#EfVb%3_kxoL?Sz~+CTKo0?umkcM}a-)X~w`8y~ zWwata$wP;F^b*OVM^AaW@iN6rqzqX?CP!j;d|n(O=-qwq_kQ2^d%y4Zy_2r_Y;|6j z*XnE1Jw~M~TvK5-acvg<`*zOBxvAXL<4n`D6HQM%GM!B(AlC_)PJEuJ;Aq!F>#NkLovPNIJ5$BCNMjXNzRgQ_+*rp!g; zA@kIOH0r69ChE4y+o3w`mbys@n%a#*r9QS=N;g8a!={p`qHa`Dn3U9Rt|@8O6xBjv zRneM91uViXss*BIg-Ct1pujo>E&wqwzyhb34*>)GZGZ*v0ek=-zz6UFd;rgan8}zy z9K*-(2F}14I0I)qN3Dgo@D|R(;UVVyV|>JTi1A?2a=ck4gU;+G$Cp8$Dx%MwXb<4< zWDqq77(5xY4U>i@25o~j0eEeA^bPt3eWn2Qp2vg1gW((~M&aj7mEptAkqMyg_a@XPLPt?d zkC;5hhr8_UYhqQ@*XHJ?wzjskv$LbUy*(Wq9B6-kUx$Z>IyySi@$s=vPfvAzey)p) z3;p%C)5{kxw7tE}>9ScKn#}@lhQO)#%Jtps`s3Lw7VG>=O7B&F`?+#Qdc9t(-w6Nw z{nu~qFaPlTdHBKC%zr1p5Vd?$#kAAwEFRk42>mO|ReC~Q-`SIO_!hG=g_r>}+ss?m65uRi?;YjfP( literal 0 HcmV?d00001 diff --git a/share/pixmaps/addressbook16mask.bmp b/share/pixmaps/addressbook16mask.bmp new file mode 100644 index 0000000000000000000000000000000000000000..d3a478d1ad1d4800008fda5be5d583f3d0423480 GIT binary patch literal 126 tcmZ?rtz&=yJ0PV2!~#&v$iN7eZ~&8-#Q*>Q!Giz)F))yd?S4Sa0{}e{AL0N2 literal 0 HcmV?d00001 diff --git a/share/pixmaps/addressbook20.bmp b/share/pixmaps/addressbook20.bmp new file mode 100644 index 0000000000000000000000000000000000000000..2b33b228aaec9ef51fb3dd46b3eab98f3d61d7df GIT binary patch literal 1478 zcma)+J!~6g9LAp(Xj4#-1LY%>FBd2^1%kPdf|c^&f`Ee-Fy_la3iQe$IKDk(@RGsG z9usXbe`4esg7wT_5VJWhTCq&7#TB`8C#7sMrJhB7@1L`@i5T{jfVq~s9}w4E! zw_*2z22GFXsne(_Y6L`^Q&Ln9)UH?6LQUklMn%-9Rn@6^>eWhWRy~zaBdDkql+^G% zxmCM%<*{$qXH@q}s-X&AKx|alBhM=mUG_yagLz^>b>!A&$jizrda9N1+@k8GJjy9> z3#t{1s-n7^Q?J+hqv|Z8#9m33I+p%fx*CFV4wui69xl=fgy&0 zHi&!}3=9Sa0|TuQJ`4s11A_s;Fh8c5q0o@z)5B-)!(r0iHpf?1ZLO}ZYHe*z8yg$i z+}zam_O`aRwzRXequt$I?d|Ppe}7*G2M0PlJk-Dc8U1tPhSt~DIbB|sAI&C#J4GgAUy7(iLxq5=0b7wD>|14iTJ13pEig)jYa`|ijuj|Xd{$44U-+JXM>s@~B ze0F~B8Rz8vXU<$GJsqUpEY+uS&Pl@Tw=exP@s8g$^ZbVs@0%yToOqAF{OrTj+PqKh z`{=0l_^GM)#Y3On@@AKo&)K~1UcWZ2U08f)$$4~Pap8&8SARLm(^2hh-qP}ew)Tg& zy<4?!7M$E7wco$@8{Qk2Q|5D5QkK+v>=D;`4}9?ACI0Kqe*VH!_CVjizOwS^rPG<` PK3-Y5_U;`Xahmo&>vaK4 literal 0 HcmV?d00001 diff --git a/share/pixmaps/addressbook20mask.bmp b/share/pixmaps/addressbook20mask.bmp new file mode 100644 index 0000000000000000000000000000000000000000..56ce6125dbb83abfac437bbbcdb611f45ee57cff GIT binary patch literal 142 zcmZ?r?PGudJ0PV2#3E44$iN7e2mq2o+z`wJ7J(4||Nn>c{{KI~KrXi54>yJZ01nMB AR{#J2 literal 0 HcmV?d00001 diff --git a/share/pixmaps/bitcoin-bc.ico b/share/pixmaps/bitcoin-bc.ico new file mode 100644 index 0000000000000000000000000000000000000000..88cc240e2d4f77fa66730593a890a17aab86cbdc GIT binary patch literal 22486 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 IOZolyKiCZ4$N&HU literal 0 HcmV?d00001 diff --git a/share/pixmaps/bitcoin.ico b/share/pixmaps/bitcoin.ico new file mode 100644 index 0000000000000000000000000000000000000000..61926807cc8d324562251501b9dfcf8894bb50e0 GIT binary patch literal 306398 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 literal 0 HcmV?d00001 diff --git a/share/pixmaps/bitcoin32.xpm b/share/pixmaps/bitcoin32.xpm new file mode 100644 index 0000000..f538a44 --- /dev/null +++ b/share/pixmaps/bitcoin32.xpm @@ -0,0 +1,232 @@ +/* XPM */ +static const char * bitcoin32_xpm[] = { +/* columns rows colors chars-per-pixel */ +"32 32 194 2", +" c #745305", +". c #785704", +"X c #7C5903", +"o c #75560B", +"O c #77590F", +"+ c #7C5C0B", +"@ c #795B12", +"# c #7F631D", +"$ c #825E07", +"% c #825F0B", +"& c #85610A", +"* c #8C660C", +"= c #8E680E", +"- c #916B0F", +"; c #856515", +": c #8B6714", +"> c #8F6A16", +", c #816218", +"< c #88691C", +"1 c #926D12", +"2 c #936F1C", +"3 c #997417", +"4 c #94721E", +"5 c #9B761C", +"6 c #9F781C", +"7 c #A17B1E", +"8 c #826622", +"9 c #916E20", +"0 c #967425", +"q c #9D7420", +"w c #9C7923", +"e c #997728", +"r c #99792C", +"t c #A37D23", +"y c #A37F2C", +"u c #A68125", +"i c #AB8225", +"p c #A5832B", +"a c #AA852C", +"s c #B28A2C", +"d c #A58233", +"f c #AC8734", +"g c #AE8C33", +"h c #AC8C3C", +"j c #B28C33", +"k c #B98E34", +"l c #B28D3D", +"z c #B59136", +"x c #BC9335", +"c c #B3913E", +"v c #BC933A", +"b c #BF9A3D", +"n c #C19235", +"m c #C2953C", +"M c #C39B3C", +"N c #CA9C3D", +"B c #B59343", +"V c #BE9642", +"C c #B69A44", +"Z c #BD9A45", +"A c #B49649", +"S c #BB9A49", +"D c #BB9F52", +"F c #BFA256", +"G c #C49C43", +"H c #CA9D41", +"J c #C59D4A", +"K c #C99E4D", +"L c #C3A144", +"P c #CDA244", +"I c #CFAA47", +"U c #C3A14D", +"Y c #CDA24A", +"T c #CCAB49", +"R c #D2A644", +"E c #D2A54B", +"W c #D6AA4C", +"Q c #DAAE4E", +"! c #DAB04F", +"~ c #C7A656", +"^ c #CDA452", +"/ c #CFAC52", +"( c #C0A65E", +") c #CEA75A", +"_ c #CCAC59", +"` c #D2AB53", +"' c #DCAF52", +"] c #D6AD5A", +"[ c #D9AE5B", +"{ c #DCB556", +"} c #DFB855", +"| c #D6B25F", +" . c #DCB35C", +".. c #DEBE5E", +"X. c #E2B656", +"o. c #E1B55A", +"O. c #E6BC5D", +"+. c #E9BD5E", +"@. c #C3AA63", +"#. c #CCAD62", +"$. c #D4AF62", +"%. c #CDB565", +"&. c #CEB46D", +"*. c #D7B164", +"=. c #DBB362", +"-. c #D6BD64", +";. c #DDBA64", +":. c #D3B66C", +">. c #DFB86B", +",. c #CEB772", +"<. c #D0B771", +"1. c #D4BA73", +"2. c #D9BE77", +"3. c #D6BE79", +"4. c #D8BF7A", +"5. c #E4BB62", +"6. c #E9BF64", +"7. c #E4BC69", +"8. c #E9BF69", +"9. c #E0BB71", +"0. c #E9C05E", +"q. c #D2C279", +"w. c #DBC27C", +"e. c #E2C667", +"r. c #EDC364", +"t. c #E3C16E", +"y. c #ECC46C", +"u. c #EDCC6C", +"i. c #F1C764", +"p. c #F5CA66", +"a. c #F9CD67", +"s. c #F5CC6A", +"d. c #F9CD6B", +"f. c #FBD36F", +"g. c #EDC572", +"h. c #E5CF77", +"j. c #ECCA74", +"k. c #E0C67E", +"l. c #EFCE78", +"z. c #F6CE72", +"x. c #FBCF71", +"c. c #F4CE79", +"v. c #F4D273", +"b. c #FCD473", +"n. c #F4DC75", +"m. c #FEDA74", +"M. c #F6D77C", +"N. c #FBD47A", +"B. c #F1DA7B", +"V. c #FDDA7C", +"C. c #FEE27D", +"Z. c #DDC683", +"A. c #DFC884", +"S. c #E4CA84", +"D. c #E3CC89", +"F. c #E7D183", +"G. c #EFD280", +"H. c #EFDC82", +"J. c #ECD48D", +"K. c #EFDA8C", +"L. c #F9D783", +"P. c #F2DF83", +"I. c #FCDB83", +"U. c #F5DC8F", +"Y. c #FADD8B", +"T. c #EBD593", +"R. c #EFDA99", +"E. c #F3DD93", +"W. c #F3DF9F", +"Q. c #FFE385", +"!. c #FEE986", +"~. c #FDE48C", +"^. c #FEEC8E", +"/. c #ECE199", +"(. c #F6E591", +"). c #FEE494", +"_. c #FEEB93", +"`. c #FEE69A", +"'. c #FFEB9B", +"]. c #FFF197", +"[. c #FFF39B", +"{. c #FEF99B", +"}. c #F6E2A2", +"|. c #F9E5A5", +" X c #F7E9A5", +".X c #FEECA4", +"XX c #FBE7A8", +"oX c #FDEAAB", +"OX c #F7F2AA", +"+X c #FEF2AC", +"@X c #FDF4B4", +"#X c #FFFABA", +"$X c #FFFEC2", +"%X c None", +/* pixels */ +"%X%X%X%X%X%X%X%X%X%X%X%Xp t 6 5 w t w %X%X%X%X%X%X%X%X%X%X%X%X%X", +"%X%X%X%X%X%X%X%X%Xu u x I X.0.s.u.0.W x 7 4 %X%X%X%X%X%X%X%X%X%X", +"%X%X%X%X%X%X%Xy i I i.a.f.m.m.b.f.s.a.s.i.W 7 > %X%X%X%X%X%X%X%X", +"%X%X%X%X%X%Xt M 0.a.m.m.m.m.f.d.p.p.p.f.d.f.i.b 1 < %X%X%X%X%X%X", +"%X%X%X%X%X7 ! d.f.f.m.f.+.W P R I Q 5.v.V.V.z.f.{ 5 + %X%X%X%X%X", +"%X%X%X%Xu X.f.m.m.f.' H s ~ V y _ Z J o.g.L.L.Q.!.e.5 X %X%X%X%X", +"%X%X%Xu X.b.C.m.+.N m n t }.3.> }.w.V 5.y.y.Y.[.^.^.-.1 + %X%X%X", +"%X%Xt P m.N.m.X.v v v k 6 }.1.: /.4.c 7.N.N.v.!.{.{.^.L & %X%X%X", +"%X%Xg Y.Y.V.+.m k a t t : }.1.% }.1.r | l.B.M.b.!.{.^.n.7 X %X%X", +"%Xp -._.'.Y.' Y n D.}.}.|.oXXX|.oX XT.w.F _ j.v.v._.^.C.T & @ %X", +"%Xa (.'.'.9.[ [ K S.}.oXoXoXoXXXoXoXoXoX XD / s.d.v.!.C.v.3 o %X", +"%XU '.'.Y.[ [ [ [ J f <.oXoX( 2 f S J.oXoXT.j r.s.i.C.C.C.z X %X", +"p e.'.'.F. .=.=.=.=.) 1.oXoX@.f . .F oXoX}.a +.i.i.b.C.m.I X O ", +"u w.'.[.j.5.8.7.7.7.] 2.oXoX@.y W c &.oXoXZ.k r.s.i.s.V.m.} = o ", +"u H.[.{.y.8.y.g.8.g.7.2.oXoXA.@.&.D.oXoXT.e G +.O.O.5.V.m.0.- o ", +"u !.].[.r.8.y.g.g.g.7.4.oXoXoXoXoXoXoXoXoX<.y W X.o.o.m.m.0.- o ", +"u B._._.5.5.8.y.g.c.g.w.oXoX,.h A F <..XoXoX1.k ' ' ' V.N.r.- ", +"u u.Q.~.r.6.z.N.V.I.v.k.oXoX@.B | _ c 1.oXoX}.a ' ' O.I.b.O.= o ", +"u ..Q.Q.v.i.s.c.N.L.l.Z.oXoX@.B t.=.S &.oXoXXXy Y R +.N.b.Q % o ", +"t T C.I.I.6.u.z.z.5.S 1.oXoX@.e B h D |.oXoXS.f Y Y 6.d.d.n X O ", +"%Xs m.V.Q.r.r.z.5.<.}.oXoXoXXXW.}.oXoXoXoXW.h G H R a.p.s.7 %X", +"%X7 O.V.V.v.+.r.` 4.oXoXoXoXoXoXoXoXXXR.<.h v N N o.a.p.Q = %X", +"%Xw x v.v.v.r.+. .Z l d e }.Z.r }.3.d l V G n n R a.s.a.s X O %X", +"%X%X6 { v.l.v.+.O.5.=.^ d }.4.9 }.1.f J G m m G d.d.x.Q = %X%X", +"%X%X%Xs u.v.v.v.r.6.o. .l }.4.9 W.4.l ^ ^ J ) c.N.N.y.7 X O %X%X", +"%X%X%X5 z v.v.M.I.g.;. .J 1.#.B 1.#.) 7.$.S..X'.W.Y.j $ %X%X%X", +"%X%X%X%X5 b N.Y.~.).Y.j.5.$.=.=.$.*.2.J.@X$X#X#XoXC $ %X%X%X%X", +"%X%X%X%X%X3 z U.@X+X`.`.`.(.E.E.E.|.@X@X#X#X#X/.j % %X%X%X%X%X", +"%X%X%X%X%X%Xw a q.OX|.).`._.'.'.XX.X.X+X+X X%.w X o %X%X%X%X%X%X", +"%X%X%X%X%X%X%X%Xw a _ j.~.~.).).`.`.`.F._ t & . # %X%X%X%X%X%X%X", +"%X%X%X%X%X%X%X%X%X%X4 3 t z L U Z z t 1 $ . 8 %X%X%X%X%X%X%X%X%X", +"%X%X%X%X%X%X%X%X%X%X%X%X%X< ; & + + , 8 %X%X%X%X%X%X%X%X%X%X%X%X" +}; diff --git a/share/pixmaps/bitcoin80.xpm b/share/pixmaps/bitcoin80.xpm new file mode 100644 index 0000000..c3c816e --- /dev/null +++ b/share/pixmaps/bitcoin80.xpm @@ -0,0 +1,292 @@ +/* XPM */ +static const char * bitcoin80_xpm[] = { +/* columns rows colors chars-per-pixel */ +"80 80 206 2", +" c #725203", +". c #785706", +"X c #7B5907", +"o c #7C5A09", +"O c #7F5F10", +"+ c #815E0B", +"@ c #85620C", +"# c #89650F", +"$ c #856313", +"% c #896614", +"& c #8D6913", +"* c #886718", +"= c #8D6B1B", +"- c #926D14", +"; c #926E1B", +": c #967116", +"> c #997317", +", c #95711E", +"< c #9B7419", +"1 c #9F781B", +"2 c #A27B1D", +"3 c #8F6F22", +"4 c #926F21", +"5 c #947323", +"6 c #9A7623", +"7 c #9D7925", +"8 c #957628", +"9 c #9A7729", +"0 c #9D7B2B", +"q c #9D7F33", +"w c #A47D23", +"e c #A97F27", +"r c #A37E2B", +"t c #9F8030", +"y c #A78021", +"u c #AC8425", +"i c #A5802D", +"p c #AC842B", +"a c #AF8829", +"s c #B2872C", +"d c #B28B2D", +"f c #A68333", +"g c #AA8633", +"h c #AD8A36", +"j c #A4863A", +"k c #A88638", +"l c #A7893B", +"z c #AC8B3B", +"x c #B28732", +"c c #B48C32", +"v c #B98E34", +"b c #B28D3B", +"n c #B88F3C", +"m c #B69033", +"M c #BD9235", +"N c #B4913D", +"B c #BC943A", +"V c #BE993C", +"C c #C19336", +"Z c #C1953B", +"A c #C49A3C", +"S c #C99C3D", +"D c #CDA13F", +"F c #D0A33F", +"G c #A88B40", +"H c #B08F40", +"J c #AE9142", +"K c #AE944C", +"L c #B49443", +"P c #BB9542", +"I c #B49946", +"U c #BD9846", +"Y c #B3964C", +"T c #BB974A", +"R c #B6994A", +"E c #BF9C4A", +"W c #B69B53", +"Q c #B99D53", +"! c #BCA055", +"~ c #BDA25A", +"^ c #C49742", +"/ c #C49C43", +"( c #CB9E42", +") c #C49D4B", +"_ c #C99E4C", +"` c #C29F52", +"' c #C5A244", +"] c #CDA245", +"[ c #C5A34C", +"{ c #CCA34B", +"} c #CCA94D", +"| c #D2A445", +" . c #D1A54B", +".. c #D5AA4E", +"X. c #DBAF4F", +"o. c #C6A352", +"O. c #CBA554", +"+. c #C5AA57", +"@. c #CEAC54", +"#. c #C4A65A", +"$. c #CDA458", +"%. c #C2A85F", +"&. c #CEAA5B", +"*. c #D0A550", +"=. c #D4AB53", +"-. c #DBAE53", +";. c #D0A75B", +":. c #D4AC5A", +">. c #D9AE5C", +",. c #CEB25E", +"<. c #D4B156", +"1. c #DDB156", +"2. c #D4B25C", +"3. c #DCB35D", +"4. c #D7B85C", +"5. c #DCBA5E", +"6. c #E2B355", +"7. c #E2B65B", +"8. c #E4BA5D", +"9. c #EABD5E", +"0. c #C5AA62", +"q. c #CCAE63", +"w. c #C6AE69", +"e. c #D5AF62", +"r. c #CEB167", +"t. c #CCB36C", +"y. c #D5B162", +"u. c #DCB462", +"i. c #D7B964", +"p. c #DCBC64", +"a. c #D2B66B", +"s. c #DCB669", +"d. c #D7BE69", +"f. c #DFB86A", +"g. c #D0B771", +"h. c #D2BA74", +"j. c #D5BE78", +"k. c #E1B766", +"l. c #E4BB63", +"z. c #E9BE63", +"x. c #E3BB6A", +"c. c #E9BF6A", +"v. c #E1BE72", +"b. c #DDC16B", +"n. c #DAC27E", +"m. c #E4C164", +"M. c #ECC264", +"N. c #E4C36B", +"B. c #EBC36C", +"V. c #E7C96F", +"C. c #EECA6E", +"Z. c #F1C564", +"A. c #F1C76A", +"S. c #F5CB6C", +"D. c #FACE6D", +"F. c #F4D06F", +"G. c #FCD06E", +"H. c #E5C371", +"J. c #EDC573", +"K. c #E4CA73", +"L. c #ECCC74", +"P. c #E7CF7A", +"I. c #EBCD7A", +"U. c #F3CD73", +"Y. c #F8CE71", +"T. c #F3CD7A", +"R. c #EDD076", +"E. c #EDD17B", +"W. c #F4D274", +"Q. c #FBD274", +"!. c #FED977", +"~. c #F3D47B", +"^. c #FDD47A", +"/. c #F5DA7C", +"(. c #FDDA7C", +"). c #FFE07F", +"_. c #DBC481", +"`. c #DFC885", +"'. c #E1CA86", +"]. c #EACC80", +"[. c #E4CD8A", +"{. c #EED383", +"}. c #E7D18F", +"|. c #EAD38C", +" X c #F4D680", +".X c #FDD780", +"XX c #F5DA83", +"oX c #FCDC84", +"OX c #F5DB8A", +"+X c #FADE89", +"@X c #EAD492", +"#X c #EED896", +"$X c #EFDA9A", +"%X c #F1DD9D", +"&X c #FDE283", +"*X c #F6E18D", +"=X c #FEE48D", +"-X c #FFE692", +";X c #FFE894", +":X c #FBE799", +">X c #FFEA98", +",X c #F6E2A3", +".J..X.X.X.X(.W.Z.C.&X;X;X;X;X-X-X-X<.u u < 3X3X3X3X3X3X3X3X3X3X3X", +"3X3X3X3X3X3X3X3Xu u c oX=X=X=X=X=X=X=Xl.Z C M M C C v v v s w = '.2X2X2X5 $ = 2X2X2X}.5 g ) u./.+X+X=X=X=X&XW.Z.F.=X;X;X;X;X-X-X*XV u y @ X 3X3X3X3X3X3X3X3X3X3X", +"3X3X3X3X3X3X3Xu u u N.-X-X-X-X=X=X=XB.Z M C v v s e e e e w > % `.2X2X2X= + % 2X2X2X}.= r L 4.E.OX+X-X=X=X&X).W.M.R.;X;X;X-X-X-X;XR.u u y 3X3X3X3X3X3X3X3X3X3X", +"3X3X3X3X3X3X3Xu u U -X-X-X-X-X-X=XW.^ C C C x e e r 6 5 4 ; = $ `.2X2X2X= O = 2X2X2X}.O = t Q ,.b.P./.*X=X&X&X).F.M.W.;X;X;X;X&X-X&X} u u O 3X3X3X3X3X3X3X3X3X", +"3X3X3X3X3X3Xu u u R.-X-X-X-X-X-X=X=.{ ^ Z C x n 2X2X.>.>.=.=._ n b 2X2X2X2X2X2X2X2X2X2X2X2X2X2X2X2X2X2X2X2X2X2X2X2X2X:XI N +.V./.).).F.F.9.W.;X=X;X-X-X-XR.u u > 3X3X3X3X3X3X3X3X", +"3X3X3X3X3Xu u d =X;X-X-X-X-X-Xx.>.>.>.>.>...^ P 2X2X2X2X2X2X2X2X2X2X2X2X2X2X2X2X2X2X2X2X2X2X2X2X2X2X,Xl N 4.R.!.!.!.G.Z.M.&X;X=X=X-X-X-XB a u 3X3X3X3X3X3X3X", +"3X3X3X3X3Xu u @.;X;X-X;X;X;XXX>.:.>.>.>.>.>._ P ` Y Y W _.2X2X2X2X2X2X@XW W ~ 0.t.'..>.>.>.>.>.>.=._ P z r 4 8 2X2X2X2X2X2X_.. $ , 6 1 3 t ~ 1X2X2X2X2X2X2X2Xt B 5.G.!.!.G.G.M.9.&X;X=X-X-X=X/.u u > 3X3X3X3X3X3X3X", +"3X3X3X3Xu u d =X;X;X=X;X;X=X3.>.>.>.e.>.3.3.>.:.*._ P r 9 2X2X2X2X2X1Xn.@ , c B N m h 8 ~ 2X2X2X2X2X2X2XI h <.F.!.G.G.F.M.9.W.;X=X-X-X=X=Xm u y . 3X3X3X3X3X3X", +"3X3X3X3Xu u ' -X-X>X-X-X-X X>.>.>.>.>.>.>.u.u.u.u.3.$.P f 2X2X2X2X2X2X_.$ i / -.<.8.} h 8 1X2X2X2X2X2X2X! i <.S.G.G.G.G.Z.9.Z.=X-X=X-X&X-X} u u X 3X3X3X3X3X3X", +"3X3X3X3Xu u 4.-X-X-X-X-X-XJ.3.>.>.k.k.k.k.k.u.k.u.u.:.U k 2X2X2X2X2X1X_.% f } 8.Z.F.8.U 8 ,X2X2X2X2X2X2XI g } Z.D.G.D.G.D.Z.9.&X-X=X=X=X-Xm.u u @ 3X3X3X3X3X3X", +"3X3X3X3Xu u K.;X-X;X-X>X-Xk.3.k.k.k.k.k.k.k.k.k.k.u.e.U k 2X2X2X2X2X2X_.% f [ 8.F.M.<.b i 2X2X2X2X2X2X2Xt a X.Z.D.D.D.G.G.Z.9./.=X-X=X=X=XR.u u & 3X3X3X3X3X3X", +"3X3X3X3Xu u E.;X-X;X-X-X=Xl.l.x.c.k.x.k.k.x.x.v.x.x.u.) z 2X2X2X2X2X2X_.$ 7 L <.<.} N 6 h.2X2X2X2X2X2X_.: V 1.S.D.D.G.D.S.M.6.W.-X=X-X=X=X&Xu u > X 3X3X3X3X3X", +"3X3X3Xu a u =X;X;X;X;X;XoX7.z.c.c.c.c.c.c.c.c.c.x.k.u.) z 2X2X2X2X2X2Xn.o = i N h i l n.2X2X2X2X2X2X.o.L r [.2X2X2X9 = 8 2X2X2X}.4 r ^ _ *.*._ ) ) ^ ^ ^ O.oX=X-X-X-X-X-X-X<.u u : . 3X3X3X3X3X3X3X3X3X", +"3X3X3X3X3X3X3X3X3Xy u u i.=X=X=X=X=X-X*X=XW.9.M.A.B.3.5.5.;.U f [.2X2X2Xq 4 8 2X2X2X}.r q _ _ ;.;.*._ _ ` _ e.+X-X-X-X-X-X-X-XR.a u 2 3X3X3X3X3X3X3X3X3X3X", +"3X3X3X3X3X3X3X3X3X3Xu u u K.=X=X=X-X=X=X=X=XXXz.M.8.5.8.u.:.) h }.2X2X2Xj r f 2X2X2X@Xq T _ e.e.u.e.;.$.$.b.-X-X-X=X;X=X;X-X&Xa a u + 3X3X3X3X3X3X3X3X3X3X3X", +"3X3X3X3X3X3X3X3X3X3X3Xu u d ~.=X=X=X=X=X-X=X-X+XC.3.5.7.7.2.@.) q.r.q.q.H H L g.r.w.q.T ` e.k.v.k.k.s.s.{.-X-X;X-X;X;X;X;X*XV u u & . 3X3X3X3X3X3X3X3X3X3X3X", +"3X3X3X3X3X3X3X3X3X3X3X2 u u c XX-X=X=X=X=X-X=X-X-X Xl.7.7.u.2.$.o.[ [ o.O.$.&.&.` ` ` q.s.k.v.k.k.x.{.%X>X>X>X;X>X;X>X>X*XV u u > 3X3X3X3X3X3X3X3X3X3X3X3X", +"3X3X3X3X3X3X3X3X3X3X3X3X2 u u m ~.=X-X-X-X=X-X-X-X-X-X Xc.7.5.u.3.e.y.u.s.f.k.s.e.e.s.s.k.k.k.v. X:X>X>X>X>X>X>X;X>X>X*XV u u < 3X3X3X3X3X3X3X3X3X3X3X3X3X", +"3X3X3X3X3X3X3X3X3X3X3X3X3X2 u u d R.-X=X-X=X-X-X-X-X-X-X-X+XI.v.u.s.l.k.k.x.x.x.s.s.s.s.j.].+X>X>X>X>X>X:X>X>X>X>X>XOXV u u 1 3X3X3X3X3X3X3X3X3X3X3X3X3X3X", +"3X3X3X3X3X3X3X3X3X3X3X3X3X3X2 u u a p.-X-X-X;X;X;X-X-X-X:X-X-X-X-XOX XL.J.J.J.L.I.].OX:X>X-X>X>X-X>X>X>X>X>X>X>X>XK.a a u < 3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X", +"3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X2 u u u @.=X;X;X>X;X-X-X>X-X-X-X-X;X-X-X-X-X-X>X>X-X>X-X>X>X>X>X;X>X>X>X-X>X-X-X:X<.u u u > 3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X", +"3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X1 u u u m n.>X;X>X>X-X-X-X-X>X-X-X-X;X;X;X-X-X-X-X-X>X-X-X>X-X>X>X-X>X>X>X>XK.B u u u & 3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X", +"3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3Xw u u u / {.>X>X-X-X-X-X-X-X-X-X-X-X;X-X-X;X:X-X-X>X-X:X>X;X;X>X;X;X{.[ u u u w + 3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X", +"3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X2 u u u u ) K.-X-X-X-X:X-X-X-X-X-X-X-X-X-X-X-X-X>X-X-X-X-X-X-XE.[ u u u u - . 3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X", +"3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X1 u u u u m 2.E.-X+X:X-X-X-X-X-X-X-X-X-X:X-X-X-X;X-XOXi.B u u u u 1 o 3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X", +"3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X> u u u u u v [ l.I.OX-X-X-X-X-X-X-X-X+XI.f.@.m u u u u u 1 + o 3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X", +"3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X& 2 u u u u u u u d B V V V V B d u u u u u u u y - . o 3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X", +"3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X+ - 1 u u u u u u u a u u u u u u u u 2 - o o 3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X", +"3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3Xo . X # - > 1 2 2 2 1 2 > - # o . o 3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X", +"3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3Xo o . o 3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X", +"3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X", +"3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X", +"3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X", +"3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X3X" +}; diff --git a/share/pixmaps/bitgem32.xpm b/share/pixmaps/bitgem32.xpm new file mode 100644 index 0000000..c77277b --- /dev/null +++ b/share/pixmaps/bitgem32.xpm @@ -0,0 +1,468 @@ +/* XPM */ +static char * BottleCaps32_xpm[] = { +"32 32 433 2", +" c None", +". c #B28F63", +"+ c #C8A274", +"@ c #C69962", +"# c #C59963", +"$ c #C59861", +"% c #C8A478", +"& c #C39760", +"* c #C49863", +"= c #C49963", +"- c #C49862", +"; c #C39862", +"> c #C49A67", +", c #C09F77", +"' c #D5AD79", +") c #E3AB66", +"! c #D38019", +"~ c #D3801B", +"{ c #D3811C", +"] c #D3811B", +"^ c #D07A10", +"/ c #DD9D4E", +"( c #EECB9E", +"_ c #D78D30", +": c #D17D15", +"< c #D17B11", +"[ c #E0A051", +"} c #E0B37D", +"| c #B9966D", +"1 c #C29C6C", +"2 c #D7913A", +"3 c #E1A050", +"4 c #DD9A48", +"5 c #D17A0F", +"6 c #D3801A", +"7 c #D27D14", +"8 c #D48422", +"9 c #ECC28F", +"0 c #F6D7B1", +"a c #E6B271", +"b c #D17A10", +"c c #D88D30", +"d c #E2A65B", +"e c #D98F33", +"f c #CE9F65", +"g c #AF8F67", +"h c #D39B55", +"i c #D57F15", +"j c #D5892A", +"k c #E1A965", +"l c #D68A2D", +"m c #D17E17", +"n c #D3821F", +"o c #D3821E", +"p c #D2811C", +"q c #D07B11", +"r c #E3AF6E", +"s c #F2CFA6", +"t c #F1C999", +"u c #F0CCA0", +"v c #DA9643", +"w c #D07A11", +"x c #D38320", +"y c #D2811D", +"z c #D27F19", +"A c #E1A863", +"B c #DA9541", +"C c #D2790C", +"D c #D69645", +"E c #C3A178", +"F c #CA9E68", +"G c #D88C2E", +"H c #D27E17", +"I c #D07C14", +"J c #DC9D4E", +"K c #DFA359", +"L c #D17D16", +"M c #DA9844", +"N c #F0CEA2", +"O c #F0C897", +"P c #EDC089", +"Q c #F2CEA3", +"R c #E8BC85", +"S c #D2821F", +"T c #D07B12", +"U c #DB9846", +"V c #E0A55C", +"W c #D78622", +"X c #D09C5C", +"Y c #BC976C", +"Z c #D7984B", +"` c #D37F16", +" . c #D2811E", +".. c #D3831F", +"+. c #D9933C", +"@. c #D17C14", +"#. c #D48524", +"$. c #EAC18D", +"%. c #F2CDA1", +"&. c #EEC28C", +"*. c #EEC592", +"=. c #EFC490", +"-. c #F2D1A9", +";. c #DEA156", +">. c #D58829", +",. c #E1AA65", +"'. c #D78E33", +"). c #D17C13", +"!. c #D8933D", +"~. c #C69E6D", +"{. c #CF9D5F", +"]. c #D88621", +"^. c #D2801C", +"/. c #D38422", +"(. c #D9943D", +"_. c #E2AB66", +":. c #E3AD6B", +"<. c #F3D4AE", +"[. c #EEC490", +"}. c #EFC592", +"|. c #EFC593", +"1. c #EEC390", +"2. c #F1CB9D", +"3. c #EEC899", +"4. c #D68B2F", +"5. c #CF790E", +"6. c #DEA053", +"7. c #DEA256", +"8. c #D38321", +"9. c #D28220", +"0. c #D58118", +"a. c #D49C56", +"b. c #B5936A", +"c. c #C09259", +"d. c #D88D31", +"e. c #CF7609", +"f. c #CF780C", +"g. c #DD9D50", +"h. c #D78F35", +"i. c #EDC18B", +"j. c #EEC28D", +"k. c #EDC08A", +"l. c #F2D0A7", +"m. c #E1A862", +"n. c #D5882A", +"o. c #DEA35A", +"p. c #D07C15", +"q. c #CF7910", +"r. c #D07B13", +"s. c #CE770D", +"t. c #D58521", +"u. c #C7975B", +"v. c #B59166", +"w. c #E1B680", +"x. c #DC9740", +"y. c #DB9947", +"z. c #DB9847", +"A. c #D99540", +"B. c #DB9A48", +"C. c #E8BF8A", +"D. c #EECEA4", +"E. c #F5D9B7", +"F. c #F3D1A8", +"G. c #F3D3AB", +"H. c #F3D2AB", +"I. c #F3D3AC", +"J. c #F4D4AE", +"K. c #F5DDC0", +"L. c #EDC38E", +"M. c #E6AB60", +"N. c #DF9841", +"O. c #E19D48", +"P. c #E19D49", +"Q. c #E29D48", +"R. c #E29D49", +"S. c #E39A41", +"T. c #E7B270", +"U. c #C09C72", +"V. c #B38E62", +"W. c #EDD1AD", +"X. c #F1CA9B", +"Y. c #EEC99B", +"Z. c #EFC99B", +"`. c #EFC99A", +" + c #EFC89A", +".+ c #EEC89A", +"++ c #EEC898", +"@+ c #EEC696", +"#+ c #F2D5B1", +"$+ c #ECC89B", +"%+ c #E1A964", +"&+ c #E2AC68", +"*+ c #E3AD6A", +"=+ c #E4AD68", +"-+ c #E9BB83", +";+ c #D1B594", +">+ c #B18349", +",+ c #B38449", +"'+ c #B4864D", +")+ c #B4864E", +"!+ c #B5864D", +"~+ c #B6864D", +"{+ c #B6874E", +"]+ c #B38348", +"^+ c #C1945E", +"/+ c #C7A984", +"(+ c #C8A67D", +"_+ c #F3CFA3", +":+ c #F0C48F", +"<+ c #F0C693", +"[+ c #F0CA9B", +"}+ c #E2AC6A", +"|+ c #CE7507", +"1+ c #CF780D", +"2+ c #CF790F", +"3+ c #CF780E", +"4+ c #D27A0D", +"5+ c #DA953E", +"6+ c #96682F", +"7+ c #764205", +"8+ c #7A4606", +"9+ c #7B4707", +"0+ c #7B4708", +"a+ c #794404", +"b+ c #7B4607", +"c+ c #A37D50", +"d+ c #D7B790", +"e+ c #F5CD9D", +"f+ c #EEC28E", +"g+ c #EEC491", +"h+ c #EEC38F", +"i+ c #F2CFA4", +"j+ c #EBC28F", +"k+ c #D7841F", +"l+ c #DAA665", +"m+ c #8E5E24", +"n+ c #7F4B0B", +"o+ c #865213", +"p+ c #804A08", +"q+ c #A27946", +"r+ c #C2A47E", +"s+ c #B39066", +"t+ c #E6C49B", +"u+ c #F3C894", +"v+ c #F2CCA0", +"w+ c #EDC697", +"x+ c #D5892B", +"y+ c #D17F19", +"z+ c #D3811E", +"A+ c #D6821B", +"B+ c #CA9B61", +"C+ c #895B24", +"D+ c #804A0A", +"E+ c #855112", +"F+ c #845112", +"G+ c #7F4907", +"H+ c #94662F", +"I+ c #B9986F", +"J+ c #C5A57E", +"K+ c #F1C692", +"L+ c #EFC591", +"M+ c #F0C795", +"N+ c #EFC897", +"O+ c #DDA054", +"P+ c #DB8F30", +"Q+ c #B48851", +"R+ c #83531A", +"S+ c #824D0C", +"T+ c #845011", +"U+ c #814B0B", +"V+ c #885518", +"W+ c #B08C61", +"X+ c #D6B790", +"Y+ c #F3CB9A", +"Z+ c #F1CCA0", +"`+ c #D37F18", +" @ c #E1A255", +".@ c #A17138", +"+@ c #7C490A", +"@@ c #834E0E", +"#@ c #814C0C", +"$@ c #A47C4B", +"%@ c #C5A885", +"&@ c #AD8A5E", +"*@ c #E6C49C", +"=@ c #F2C894", +"-@ c #EFC491", +";@ c #EEC38E", +">@ c #E8BA81", +",@ c #D47F16", +"'@ c #D8A15E", +")@ c #966831", +"!@ c #7C4706", +"~@ c #804B0A", +"{@ c #976A33", +"]@ c #BD9D76", +"^@ c #C4A27B", +"/@ c #F0CCA1", +"(@ c #F1C691", +"_@ c #F1CC9F", +":@ c #EBC08D", +"<@ c #D58A2D", +"[@ c #D68219", +"}@ c #C89659", +"|@ c #8F642F", +"1@ c #7F4908", +"2@ c #814C0B", +"3@ c #89571A", +"4@ c #B28F64", +"5@ c #D5B58D", +"6@ c #F4CC9C", +"7@ c #EFC38F", +"8@ c #EEC797", +"9@ c #DC9B4C", +"0@ c #D17E18", +"a@ c #DE9437", +"b@ c #B8884D", +"c@ c #84541A", +"d@ c #824D0D", +"e@ c #834F0F", +"f@ c #A88152", +"g@ c #B08C60", +"h@ c #E3C29B", +"i@ c #F3C995", +"j@ c #F2D0A8", +"k@ c #E0A65E", +"l@ c #E1A152", +"m@ c #A97B42", +"n@ c #855113", +"o@ c #9B703B", +"p@ c #B99970", +"q@ c #C1A078", +"r@ c #EECBA1", +"s@ c #F1C591", +"t@ c #EEC18C", +"u@ c #E5B273", +"v@ c #D37D12", +"w@ c #D59B53", +"x@ c #9D7341", +"y@ c #7D4705", +"z@ c #865314", +"A@ c #814B0A", +"B@ c #8D5D22", +"C@ c #B49268", +"D@ c #D2B38C", +"E@ c #F2CC9C", +"F@ c #F1CA9C", +"G@ c #EABD87", +"H@ c #D17F18", +"I@ c #D1811D", +"J@ c #D8851D", +"K@ c #C89250", +"L@ c #906735", +"M@ c #814B09", +"N@ c #834E0F", +"O@ c #AA8456", +"P@ c #AA875C", +"Q@ c #E2C199", +"R@ c #F3CA97", +"S@ c #DA9743", +"T@ c #D07C16", +"U@ c #DF973C", +"V@ c #BC8C50", +"W@ c #804F13", +"X@ c #844F0F", +"Y@ c #9E7441", +"Z@ c #BD9D77", +"`@ c #C09F78", +" # c #EDCAA0", +".# c #F3D4AF", +"+# c #DD9E4F", +"@# c #DD9A47", +"## c #B08550", +"$# c #7B4504", +"%# c #905F26", +"&# c #B7956D", +"*# c #D1B28C", +"=# c #EFC38D", +"-# c #F3D3AD", +";# c #E2AA65", +"># c #D27B10", +",# c #D39344", +"'# c #A37D4E", +")# c #7B4402", +"!# c #865315", +"~# c #AE895D", +"{# c #E1C19B", +"]# c #F3C996", +"^# c #F0C898", +"/# c #E9BB82", +"(# c #D48627", +"_# c #D7831B", +":# c #CD944D", +"<# c #906530", +"[# c #7D4604", +"}# c #A17948", +"|# c #BB9A72", +"1# c #BF9E75", +"2# c #EDCBA1", +"3# c #EEC99C", +"4# c #D58A2C", +"5# c #DB8C2A", +"6# c #C6965B", +"7# c #7A4504", +"8# c #92642B", +"9# c #B6946B", +"0# c #CFAF89", +"a# c #F2CC9E", +"b# c #F2D3AD", +"c# c #DA9239", +"d# c #D68A2B", +"e# c #B48A57", +"f# c #814E10", +"g# c #DEBF98", +"h# c #F7D6AD", +"i# c #E2A457", +"j# c #D28C36", +"k# c #A07948", +"l# c #BA9A70", +"m# c #EACAA1", +"n# c #F4C58B", +"o# c #CE944D", +"p# c #9E7542", +"q# c #B4936A", +"r# c #D0B28C", +"s# c #F4D4AD", +"t# c #D3A975", +"u# c #AC875B", +"v# c #E5D2BB", +"w# c #E0CAAE", +"x# c #AE895C", +"y# c #BB9D78", +"z# c #C5A989", +" . + @ # # # # # # $ # % & * * = * * - ; > , ", +" ' ) ! ~ { { { { ] ^ / ( _ : { { { { { < [ } | ", +" 1 2 3 4 5 { 6 6 6 7 8 9 0 a b ! 6 6 ] 7 c d e f ", +" g h i j k l m n o p q r s t u v w x o y z A B C D E ", +" F G H I J K L y x ^ M N O P Q R S z x T U V y m W X ", +" Y Z ` .p ..A +.@.m #.$.%.&.*.=.-.;.^ L >.,.'.: x ).!.~. ", +" {.].^.x /.L (._.x ^ :.<.[.}.|.1.2.3.4.5.6.7.L 8.x 9.0.a.b. ", +" c.d.e.I T T T f.g.h.+.u }.i.j.&.j.k.l.m.n.o.p.q.I r.I s.t.u. ", +"v.w.x.y.y.z.U U A.B.C.D.E.F.G.H.H.I.H.J.K.L.M.N.O.P.O.Q.R.S.T.U.", +"V.W.X.Y.Z.`. +.+++@+#+$+%+&+*+*+*+:.:.=+-+;+>+,+'+)+!+~+{+]+^+/+", +" (+_+:+}.}.}.}.}.<+[+}+|+1+2+2+2+2+3+4+5+6+7+8+9+9+0+0+a+b+c+ ", +" d+e+f+*.g+g+g+h+i+j+m y ........o k+l+m+n+o+o+o+o+o+p+q+r+ ", +" s+t+u+1.}.g+g+h+v+w+x+y+o z+y y { A+B+C+D+E+F+E+E+G+H+I+ ", +" J+u K+g+}.L+g+M+N+O+: o o o o 6 P+Q+R+S+F+T+E+U+V+W+ ", +" X+Y+=.g+g+}.=.Z+r w o y o o `+ @.@+@T+T+E+@@#@$@%@ ", +" &@*@=@-@*.}.;@F.>@T o o y o ,@'@)@!@E+E+T+~@{@]@ ", +" ^@/@(@g+L+h+_@:@<@z o o .[@}@|@1@T+E+2@3@4@ ", +" 5@6@7@}.g+L+8@9@r.x o 0@a@b@c@d@E+e@2@f@ ", +" g@h@i@1.}.j.j@k@5.8...).l@m@!@T+n@G+o@p@ ", +" q@r@s@g+t@<.u@@.n 9.v@w@x@y@z@A@B@C@ ", +" D@E@;@1.F@G@4.H@I@J@K@L@M@N@T+O@ ", +" P@Q@R@1.-@Y.S@r.T@U@V@W@X@A@Y@Z@ ", +" `@ #=@j..#+#2+T @###$#2@%#&# ", +" *#X.=#-#;#0@>#,#'#)#!#~# ", +" {#]#^#/#(#_#:#<#[#}#|# ", +" 1#2#=@3#4#5#6#7#8#9# ", +" 0#a#b#c#d#e#f#g@ ", +" g#h#i#j#}#k#l# ", +" ]@m#n#o#p#q# ", +" r#s#t#u# ", +" v#w#x# ", +" y#z# "}; diff --git a/share/pixmaps/bitgem80.xpm b/share/pixmaps/bitgem80.xpm new file mode 100644 index 0000000..1a0bad2 --- /dev/null +++ b/share/pixmaps/bitgem80.xpm @@ -0,0 +1,955 @@ +/* XPM */ +static char * BottleCaps80_xpm[] = { +"81 80 872 2", +" c None", +". c #844E0D", +"+ c #8B5A1E", +"@ c #8A591D", +"# c #8A571A", +"$ c #895517", +"% c #895617", +"& c #895618", +"* c #885414", +"= c #885312", +"- c #885313", +"; c #885210", +"> c #87500D", +", c #824C0D", +"' c #824D0D", +") c #814B0A", +"! c #814A07", +"~ c #814A08", +"{ c #804904", +"] c #804702", +"^ c #7F4600", +"/ c #7E4400", +"( c #7F4400", +"_ c #7D4200", +": c #8B5513", +"< c #824A07", +"[ c #CFB89B", +"} c #FFF8ED", +"| c #FCF0DF", +"1 c #FCF0E0", +"2 c #FDF1E1", +"3 c #FDF2E3", +"4 c #FDF2E2", +"5 c #FDF1E2", +"6 c #FDF3E4", +"7 c #FDF3E6", +"8 c #FDF3E5", +"9 c #FEF4E7", +"0 c #FEF5E9", +"a c #FBEDDB", +"b c #FEF7ED", +"c c #FEF6EC", +"d c #FFF7ED", +"e c #FFF8EF", +"f c #FFF9F0", +"g c #FFFAF2", +"h c #FFFBF3", +"i c #FFFCF5", +"j c #FFFBF4", +"k c #FFFFFF", +"l c #AA8353", +"m c #94652C", +"n c #F2D8B9", +"o c #CD7303", +"p c #D17C13", +"q c #D07C13", +"r c #D17C14", +"s c #D27B11", +"t c #FBF3E9", +"u c #D17A0F", +"v c #D17D15", +"w c #D17D16", +"x c #D17E16", +"y c #D17E17", +"z c #D17C12", +"A c #FBF4EC", +"B c #FDFBF8", +"C c #88510F", +"D c #7F4703", +"E c #F6F3F0", +"F c #D78D32", +"G c #F7EAD8", +"H c #E0A45B", +"I c #D17E18", +"J c #D2811D", +"K c #D3821E", +"L c #D3821D", +"M c #D3811E", +"N c #D2811E", +"O c #D2821E", +"P c #D07A0F", +"Q c #EFD1AB", +"R c #FEFDFA", +"S c #EDCA9E", +"T c #D3811D", +"U c #D2821D", +"V c #D07A10", +"W c #F1D6B4", +"X c #E6B77C", +"Y c #E6B478", +"Z c #CDB9A0", +"` c #884F0B", +" . c #B99C79", +".. c #F4D8B4", +"+. c #D0790F", +"@. c #D78B2D", +"#. c #D0790E", +"$. c #D17D17", +"%. c #DC9B4A", +"&. c #FEFDFB", +"*. c #EDBD84", +"=. c #D78A2D", +"-. c #D2801B", +";. c #D27F19", +">. c #DA953F", +",. c #FCF7F0", +"'. c #D07B12", +"). c #FFFFFA", +"!. c #946327", +"~. c #895514", +"{. c #D27F18", +"]. c #D3821F", +"^. c #D07C14", +"/. c #EBC493", +"(. c #EECDA3", +"_. c #CF780D", +":. c #FDFCFA", +"<. c #F0C99B", +"[. c #EEC490", +"}. c #F2D0A9", +"|. c #F7EAD9", +"1. c #CF7609", +"2. c #CF770A", +"3. c #FDF8F2", +"4. c #DB9641", +"5. c #D17F19", +"6. c #DC9947", +"7. c #EDE8E0", +"8. c #814700", +"9. c #7F4601", +"0. c #E6DDD1", +"a. c #E1A861", +"b. c #D78D31", +"c. c #D27F1A", +"d. c #F0D4B0", +"e. c #F6E1C6", +"f. c #EEC28D", +"g. c #EFC592", +"h. c #EDC18A", +"i. c #FCF5EC", +"j. c #E2AA65", +"k. c #E8BC86", +"l. c #FAE3C6", +"m. c #AE8A5F", +"n. c #8E5918", +"o. c #A67F4E", +"p. c #FDEDD8", +"q. c #CF790F", +"r. c #DD9C4C", +"s. c #FAF2E6", +"t. c #CF770B", +"u. c #D38320", +"v. c #DD9E4D", +"w. c #FEFDFC", +"x. c #EDC089", +"y. c #EEC592", +"z. c #FEFEFC", +"A. c #D2801A", +"B. c #D2811C", +"C. c #D48421", +"D. c #D27E17", +"E. c #D38321", +"F. c #D3811C", +"G. c #834D0C", +"H. c #D58523", +"I. c #CF780C", +"J. c #F4DEC4", +"K. c #E5B476", +"L. c #EFC797", +"M. c #EEC491", +"N. c #EFC591", +"O. c #EEC38E", +"P. c #F7E0C7", +"Q. c #EFD2AD", +"R. c #F6E5D1", +"S. c #E1A964", +"T. c #EBBC82", +"U. c #D1BFA8", +"V. c #834B06", +"W. c #834C09", +"X. c #D1BEA6", +"Y. c #CF790E", +"Z. c #D4821E", +"`. c #F1D7B6", +" + c #F6DFC4", +".+ c #DA943D", +"++ c #DFA45A", +"@+ c #F9EDDD", +"#+ c #FFFBF1", +"$+ c #986A32", +"%+ c #986B33", +"&+ c #E4B071", +"*+ c #F4DFC4", +"=+ c #D2801C", +"-+ c #DFA255", +";+ c #FFFCFA", +">+ c #EDC088", +",+ c #EFC491", +"'+ c #F2CFA5", +")+ c #FAF2E7", +"!+ c #D27E16", +"~+ c #D58828", +"{+ c #DC9740", +"]+ c #F2EFEA", +"^+ c #814904", +"/+ c #804906", +"(+ c #F6F3EF", +"_+ c #DB943D", +":+ c #CF780B", +"<+ c #FBF2E8", +"[+ c #DD9C4B", +"}+ c #D3801B", +"|+ c #EFC693", +"1+ c #EFC593", +"2+ c #EDBF88", +"3+ c #FBF3E8", +"4+ c #E5B374", +"5+ c #EECEA7", +"6+ c #EAC290", +"7+ c #F7DBB9", +"8+ c #B5956D", +"9+ c #89520E", +"0+ c #844C08", +"a+ c #BB9F7B", +"b+ c #F4D6B1", +"c+ c #D88E33", +"d+ c #D0790D", +"e+ c #F1D8B8", +"f+ c #F7E0C5", +"g+ c #EEC38F", +"h+ c #EEC591", +"i+ c #D37F18", +"j+ c #D88D32", +"k+ c #FEFCF8", +"l+ c #844D0B", +"m+ c #EECEA5", +"n+ c #EAC292", +"o+ c #DFA256", +"p+ c #FEFCF9", +"q+ c #F6DFC3", +"r+ c #F0D4B1", +"s+ c #FBF5EC", +"t+ c #DC9A48", +"u+ c #E7B476", +"v+ c #D8CAB8", +"w+ c #804500", +"x+ c #7E4500", +"y+ c #E4DCD1", +"z+ c #E2A861", +"A+ c #D17F18", +"B+ c #D17B11", +"C+ c #D68A2B", +"D+ c #EFC897", +"E+ c #EFC492", +"F+ c #FFFFFE", +"G+ c #DA9540", +"H+ c #F3DDC1", +"I+ c #FFF9EE", +"J+ c #986B34", +"K+ c #8B5310", +"L+ c #A68153", +"M+ c #FEEDD8", +"N+ c #E0A359", +"O+ c #F9EDDF", +"P+ c #F2DABC", +"Q+ c #F6DEC2", +"R+ c #EEC28C", +"S+ c #EEC492", +"T+ c #F1CEA3", +"U+ c #D0770B", +"V+ c #D38019", +"W+ c #DA933D", +"X+ c #F5F4F1", +"Y+ c #7F4602", +"Z+ c #824B08", +"`+ c #D48625", +" @ c #F5E3CD", +".@ c #E2AC69", +"+@ c #E0A55C", +"@@ c #FEFBF8", +"#@ c #EDC18B", +"$@ c #FAEEDF", +"%@ c #E6B87F", +"&@ c #E5B274", +"*@ c #F6D8B4", +"=@ c #B99C78", +"-@ c #89510F", +";@ c #834C0A", +">@ c #D4C3AE", +",@ c #EABC84", +"'@ c #D48320", +")@ c #D28019", +"!@ c #EFC695", +"~@ c #DE9E50", +"{@ c #FAF0E4", +"]@ c #8A5516", +"^@ c #986931", +"/@ c #FFFCF3", +"(@ c #D07B13", +"_@ c #E7BA81", +":@ c #F3DDC2", +"<@ c #F5DCBD", +"[@ c #F4DAB9", +"}@ c #F3DCC0", +"|@ c #D07A11", +"1@ c #E3AD6A", +"2@ c #DFD2C2", +"3@ c #824B07", +"4@ c #814906", +"5@ c #F9F7F4", +"6@ c #D89138", +"7@ c #FDF8F3", +"8@ c #E0A760", +"9@ c #FEFAF5", +"0@ c #FFFDFC", +"a@ c #EBC698", +"b@ c #FFF6E7", +"c@ c #9E723D", +"d@ c #925E1E", +"e@ c #864F0C", +"f@ c #BC9F7B", +"g@ c #F5D6B1", +"h@ c #DA9641", +"i@ c #FCF7EF", +"j@ c #FEFEFE", +"k@ c #EFC694", +"l@ c #F0CA9C", +"m@ c #FBF5ED", +"n@ c #D0780D", +"o@ c #D68929", +"p@ c #D17D13", +"q@ c #D98F34", +"r@ c #FAFAF9", +"s@ c #7E4501", +"t@ c #905F23", +"u@ c #D17D14", +"v@ c #CE7304", +"w@ c #EFCEA5", +"x@ c #E6B679", +"y@ c #F1DABB", +"z@ c #F3D7B4", +"A@ c #EEC18B", +"B@ c #EEC18A", +"C@ c #EDC08A", +"D@ c #F8E9D4", +"E@ c #F5E5CF", +"F@ c #DB9845", +"G@ c #CF760A", +"H@ c #CD7201", +"I@ c #F1CC9E", +"J@ c #BDA07C", +"K@ c #824A06", +"L@ c #854F0D", +"M@ c #D2BB9E", +"N@ c #F9F0E4", +"O@ c #F9F1E6", +"P@ c #F9EFE3", +"Q@ c #F8EEDF", +"R@ c #F8ECDC", +"S@ c #F7EADA", +"T@ c #F6E8D6", +"U@ c #F6E6D3", +"V@ c #F6E7D3", +"W@ c #F6E6D2", +"X@ c #F6E5D0", +"Y@ c #FEFFFF", +"Z@ c #FCF6ED", +"`@ c #FCF6EE", +" # c #FCF5ED", +".# c #FCF5EB", +"+# c #FCF4EB", +"@# c #FCF4EA", +"## c #FCF4E9", +"$# c #FBF4E9", +"%# c #FBF3E7", +"&# c #FBF2E6", +"*# c #FBF1E5", +"=# c #FBF1E4", +"-# c #FBF0E3", +";# c #F2D3AC", +"># c #F4D9B6", +",# c #F4D7B1", +"'# c #F3D6B0", +")# c #F3D4AD", +"!# c #F3D4AC", +"~# c #F2D1A8", +"{# c #F1D1A8", +"]# c #F1CEA2", +"^# c #F0CC9E", +"/# c #F0CB9E", +"(# c #EFC899", +"_# c #F0C999", +":# c #EFC999", +"<# c #EEC694", +"[# c #EEC695", +"}# c #ECC089", +"|# c #A57B49", +"1# c #824C0B", +"2# c #F0C897", +"3# c #EFC796", +"4# c #F0C796", +"5# c #F0C898", +"6# c #F0C99A", +"7# c #F0CA9B", +"8# c #F1CB9E", +"9# c #F8E8D4", +"0# c #E8BE88", +"a# c #D78D33", +"b# c #D9923A", +"c# c #D9933C", +"d# c #D9943E", +"e# c #DA9642", +"f# c #DA9744", +"g# c #DB9846", +"h# c #DA9846", +"i# c #DB9A48", +"j# c #DC9A4A", +"k# c #DC9C4C", +"l# c #DC9D4E", +"m# c #DC9C4D", +"n# c #DD9E50", +"o# c #DD9F52", +"p# c #DD9F51", +"q# c #DDA155", +"r# c #DB9948", +"s# c #FCF1E3", +"t# c #B59064", +"u# c #A88150", +"v# c #A88050", +"w# c #A98353", +"x# c #AA8454", +"y# c #AA8354", +"z# c #AB865A", +"A# c #AB875B", +"B# c #AB895F", +"C# c #AC8A60", +"D# c #AB8960", +"E# c #B18D62", +"F# c #B39067", +"G# c #B3936D", +"H# c #B3946D", +"I# c #B49773", +"J# c #B49772", +"K# c #B39671", +"L# c #BE9F79", +"M# c #97652A", +"N# c #8C5717", +"O# c #9B6E37", +"P# c #F1CEA4", +"Q# c #F4E0C7", +"R# c #D07E17", +"S# c #804805", +"T# c #824D0C", +"U# c #824C0C", +"V# c #814C0C", +"W# c #814C0B", +"X# c #814B0B", +"Y# c #773C00", +"Z# c #EEE4D8", +"`# c #A8804E", +" $ c #C9B193", +".$ c #FCECD7", +"+$ c #D27D15", +"@$ c #D89139", +"#$ c #EAE1D5", +"$$ c #7A4200", +"%$ c #855112", +"&$ c #845011", +"*$ c #855011", +"=$ c #845012", +"-$ c #804A08", +";$ c #C4A884", +">$ c #D6C2A9", +",$ c #7E4602", +"'$ c #F1EDE5", +")$ c #F1CFA6", +"!$ c #FDFAF4", +"~$ c #D78F35", +"{$ c #ECC088", +"]$ c #BDA17E", +"^$ c #814D0D", +"/$ c #966830", +"($ c #FBF8F3", +"_$ c #864E09", +":$ c #946023", +"<$ c #8B591B", +"[$ c #EDC28E", +"}$ c #FBEEDF", +"|$ c #E2AA64", +"1$ c #976932", +"2$ c #865214", +"3$ c #855111", +"4$ c #845111", +"5$ c #845112", +"6$ c #855213", +"7$ c #804907", +"8$ c #97682E", +"9$ c #BA9A74", +"0$ c #FFF6E8", +"a$ c #F4D6B2", +"b$ c #EFD3B1", +"c$ c #F8F2EA", +"d$ c #885413", +"e$ c #7B4400", +"f$ c #DBC8B1", +"g$ c #C0A27D", +"h$ c #7D4501", +"i$ c #E8DED1", +"j$ c #F5D8B5", +"k$ c #FCF6F0", +"l$ c #D68F36", +"m$ c #EDE6DD", +"n$ c #7B4200", +"o$ c #855012", +"p$ c #A8804F", +"q$ c #EFE5DA", +"r$ c #814600", +"s$ c #865111", +"t$ c #FDF9F3", +"u$ c #D68A2C", +"v$ c #E7B372", +"w$ c #C6B095", +"x$ c #7F4A09", +"y$ c #844F10", +"z$ c #875212", +"A$ c #8E5919", +"B$ c #86500E", +"C$ c #FFFFF9", +"D$ c #EDBF87", +"E$ c #DEA156", +"F$ c #FBE6CC", +"G$ c #9A6E39", +"H$ c #865315", +"I$ c #7A4100", +"J$ c #F1E8DC", +"K$ c #AD8657", +"L$ c #7D4502", +"M$ c #D8C7B1", +"N$ c #FAE3C7", +"O$ c #EEC28E", +"P$ c #F5DDBF", +"Q$ c #ECC89A", +"R$ c #FBF7F0", +"S$ c #865213", +"T$ c #865314", +"U$ c #7E4705", +"V$ c #C0A27E", +"W$ c #D8C5AE", +"X$ c #F1CB9D", +"Y$ c #FAF1E4", +"Z$ c #D78F36", +"`$ c #ECE4DA", +" % c #7C4300", +".% c #95652B", +"+% c #FFFEFB", +"@% c #844C07", +"#% c #8C5716", +"$% c #9A6D37", +"%% c #E4AE6A", +"&% c #CDB9A1", +"*% c #7E4603", +"=% c #FDFAF6", +"-% c #9A6C34", +";% c #C8AF91", +">% c #FDEDD9", +",% c #DD9E51", +"'% c #F8DEBD", +")% c #A17847", +"!% c #7B4401", +"~% c #D9C5AE", +"{% c #C2A481", +"]% c #F7F3ED", +"^% c #EEC18C", +"/% c #F7E4CB", +"(% c #E8BC85", +"_% c #CF7608", +":% c #824E0E", +"<% c #F0E8DC", +"[% c #854C07", +"}% c #946021", +"|% c #916125", +"1% c #EDC18C", +"2% c #F1CDA2", +"3% c #F4E3CC", +"4% c #EEE7E0", +"5% c #7F4806", +"6% c #905D1E", +"7% c #87500F", +"8% c #B99973", +"9% c #FFF6E9", +"0% c #D0780C", +"a% c #E1A962", +"b% c #D4C2AC", +"c% c #7B4300", +"d% c #EFE5D8", +"e% c #AE885A", +"f% c #7D4400", +"g% c #E8DED2", +"h% c #F4D7B3", +"i% c #F3D2A9", +"j% c #AC885D", +"k% c #804A09", +"l% c #7F4908", +"m% c #BC9C76", +"n% c #DDCCB7", +"o% c #854B03", +"p% c #85500F", +"q% c #F8E6CF", +"r% c #E6B77E", +"s% c #845010", +"t% c #926125", +"u% c #854D09", +"v% c #864F0D", +"w% c #A98253", +"x% c #FFFEF6", +"y% c #F3D3AC", +"z% c #F2DABB", +"A% c #D5831E", +"B% c #F2EFEB", +"C% c #7E4806", +"D% c #7F4704", +"E% c #FEFBF6", +"F% c #9B6E36", +"G% c #7D4500", +"H% c #D8C7B2", +"I% c #F8E2C5", +"J% c #FDF9F4", +"K% c #E2A860", +"L% c #7D4603", +"M% c #7C4503", +"N% c #D5C0A6", +"O% c #C7AC8B", +"P% c #7E4704", +"Q% c #FBFBF9", +"R% c #F1CA9C", +"S% c #FEFCFA", +"T% c #D6892A", +"U% c #B29068", +"V% c #F4EDE4", +"W% c #9D713B", +"X% c #F9E9D6", +"Y% c #E2AE6C", +"Z% c #FFF3E2", +"`% c #8E5D20", +" & c #834E0F", +".& c #814B08", +"+& c #905D1F", +"@& c #CBB395", +"#& c #FEEED9", +"$& c #D27C13", +"%& c #FBFAF8", +"&& c #7C4502", +"*& c #855113", +"=& c #794000", +"-& c #E9DECE", +";& c #AF8C5F", +">& c #804905", +",& c #F6F2EC", +"'& c #F3D0A6", +")& c #EFC795", +"!& c #F9EFE1", +"~& c #E0A051", +"{& c #D9CBBA", +"]& c #BA9971", +"^& c #E0D0BC", +"/& c #844903", +"(& c #915F24", +"_& c #EDC08B", +":& c #D3801A", +"<& c #EFCA9A", +"[& c #B79872", +"}& c #8E5C1F", +"|& c #885110", +"1& c #B99972", +"2& c #FFF4E6", +"3& c #FAEFE1", +"4& c #DFA359", +"5& c #D07B11", +"6& c #FBEBD6", +"7& c #96672F", +"8& c #FBF8F2", +"9& c #9D7039", +"0& c #E8DFD2", +"a& c #EEC390", +"b& c #F4D9B8", +"c& c #EECDA4", +"d& c #D27D16", +"e& c #FFFEFA", +"f& c #D2BB9F", +"g& c #C9B091", +"h& c #854F0E", +"i& c #F7E9D8", +"j& c #DE9843", +"k& c #DFD5C8", +"l& c #7D4705", +"m& c #834F10", +"n& c #A17743", +"o& c #F8F3EC", +"p& c #834A04", +"q& c #874F0D", +"r& c #A88152", +"s& c #FFFCF4", +"t& c #D38421", +"u& c #B89A75", +"v& c #8E5A1C", +"w& c #7F4702", +"x& c #DCCCB8", +"y& c #F8E1C4", +"z& c #FDF7F0", +"A& c #DA943E", +"B& c #F9E6CE", +"C& c #9D713C", +"D& c #E7DBC9", +"E& c #B49066", +"F& c #824C0A", +"G& c #FDFDFB", +"H& c #F6DFC2", +"I& c #E9C08E", +"J& c #7F4807", +"K& c #B59268", +"L& c #E5D8C7", +"M& c #8D5513", +"N& c #9C703B", +"O& c #F1CDA1", +"P& c #D38422", +"Q& c #D98E31", +"R& c #EAE3DA", +"S& c #834E0E", +"T& c #8D5B1E", +"U& c #87510F", +"V& c #CAB295", +"W& c #FDECD7", +"X& c #FBF5EE", +"Y& c #D3831F", +"Z& c #EDBF85", +"`& c #BFA483", +" * c #FAF5EF", +".* c #A07540", +"+* c #F4F0EA", +"@* c #F3D1A7", +"#* c #D88F36", +"$* c #FBE8CE", +"%* c #9D723D", +"&* c #CEB698", +"** c #CCB598", +"=* c #844902", +"-* c #F8E5CE", +";* c #E6B67A", +">* c #FBF4EB", +",* c #875211", +"'* c #804B0A", +")* c #9F733E", +"!* c #FAF6EF", +"~* c #814802", +"{* c #B89872", +"]* c #F5E2CB", +"^* c #D68B30", +"/* c #F1EBE2", +"(* c #814B09", +"_* c #905F22", +":* c #7E4601", +"<* c #F3D6B2", +"[* c #E7B474", +"}* c #C6AF93", +"|* c #7D4704", +"1* c #E5D8C6", +"2* c #8B5719", +"3* c #EDC390", +"4* c #FEFAF6", +"5* c #FAE3C5", +"6* c #9F7643", +"7* c #804B0B", +"8* c #B18D61", +"9* c #E7DACA", +"0* c #8D5817", +"a* c #A98355", +"b* c #FFFEF7", +"c* c #FBEFE1", +"d* c #E1A760", +"e* c #FAF2E9", +"f* c #8C591B", +"g* c #8A5719", +"h* c #885211", +"i* c #804803", +"j* c #DBCBB7", +"k* c #F8DFC2", +"l* c #F4D5B1", +"m* c #D58A2E", +"n* c #F2ECE5", +"o* c #F9F3EB", +"p* c #A27845", +"q* c #FDFDFC", +"r* c #E3A861", +"s* c #CFBEA7", +"t* c #7D4604", +"u* c #CAB091", +"v* c #D1BCA0", +"w* c #824801", +"x* c #9C6F39", +"y* c #F8DDBA", +"z* c #A17A4A", +"A* c #FEFCF7", +"B* c #804703", +"C* c #814803", +"D* c #FBEAD4", +"E* c #DEA257", +"F* c #926024", +"G* c #F4EFEA", +"H* c #F5DDBE", +"I* c #ECC89C", +"J* c #D58A2C", +"K* c #EFE9E1", +"L* c #E2D3BF", +"M* c #BA9973", +"N* c #916024", +"O* c #D6C6B2", +"P* c #EADFD1", +"Q* c #86500D", +"R* c #BB9B75", +"S* c #FFF7E9", +"T* c #F3D1A6", +"U* c #AD8A60", +"V* c #834F0F", +"W* c #875312", +"X* c #895413", +"Y* c #EAE0D4", +"Z* c #FCF3E9", +"`* c #FFF9ED", +" = c #885619", +".= c #F4EDE3", +"+= c #A47C4A", +"@= c #8A5617", +"#= c #F7E4CA", +"$= c #D4831F", +"%= c #F2EEE8", +"&= c #C8AD8C", +"*= c #D4BFA5", +"== c #844B06", +"-= c #8E5716", +";= c #AB8456", +">= c #F5E4CE", +",= c #DBCDBB", +"'= c #FDFAF5", +")= c #844D0A", +"!= c #814905", +"~= c #F7DFC2", +"{= c #CE7506", +"]= c #EFC898", +"^= c #B69771", +"/= c #926227", +"(= c #FFF3E1", +"_= c #DECCB7", +":= c #BE9F7A", +"<= c #874F0B", +"[= c #9B6E38", +"}= c #FFFFF8", +"|= c #F7E1C8", +"1= c #E6B374", +"2= c #F3EEE6", +"3= c #A77E4D", +"4= c #F0E7DC", +"5= c #7D4300", +"6= c #804600", +"7= c #C9B092", +"8= c #E0CFBA", +"9= c #86510F", +"0= c #F4EEE6", +"a= c #A47B49", +"b= c #D2BCA1", +"c= c #8A5412", +"d= c #B28D61", +"e= c #875110", +" . + @ @ @ @ # $ % % % % & * = = = = = - ; > > > > > > . , ' ' ' ' ' ) ! ! ! ! ! ~ { ] ] ] ] ] ] ^ / ( ( _ : ", +" < [ } | 1 1 1 2 3 4 4 4 4 5 6 7 7 7 7 7 8 9 0 0 0 0 0 0 a b c c c c c d e e e e e e f g g g g g g h i i j k l ", +" m k n o p p q p p p p p p p r r r r r r r r r r r r p s t u v v v v v v w w w w w w w w w w w w w x y w z A B C ", +" D E F G H I J K L J J M K N O L K L K L J K K J O O K P Q R S P T K K O K T K K T K K K U U M U T J U K V W X Y Z ` ", +" C ...+.@.k #.O K T J N J K N J L J J K L N K M J N K $.%.&.*.k =.-.J M N K J K J J J J N J J N O J N U ;.>.,.P '.).!. ", +" ~.k {.].^./.(._.K T O K M K M O U K L K L K O K J O N P :.<.[.}.|.1.].M O K T O K T K K K U U M K T K K 2.3.4.5.O 6.7.8. ", +" 9.0.a.-.J J V &.b.c.J J T T T M J N T M T M J J M J K 2.d.e.f.g.h.i.j.5.J N K M J T M T T M N N M J T K V k.d.V K K V l.m. ", +" n.o.p.q.K K K -.r.s.t.u.J J J K J J L J J K L J K M J w v.w.x.y.g.g.y.z.A.].K K J K J J J J N J J N J J B.C.k D.J J J E.F.k ; ", +" G.k H.E.J K K K I.J.K.y J M N K M N K N J K K N K J u.p w.L.M.g.N.M.O.P.Q.+.K K J K N J N N M J J N O ].t.R.S.I K J K J V T.U.V. ", +" W.X.h.Y.T U U O K K F.k Z.u.K J U J J O J J L O J U K V `. +f.g.M.M.g.g.x.k .+J J J U J J J J J J J J J -.++@+2.K K J O J K t.#+$+ ", +" %+#+t.K J K K K K K y &+*+V T K K M K K K K K K N N =+-+;+>+g.,+M.,+g.M.y.'+)++.J K K K K K K K K K K u.!+k ~+K K K K K N K I {+]+^+ ", +" /+(+_+I K J K K K K L ].:+<+[+N T K N O L K L K L J K }+k |+1+M.M.M.M.g.g.g.2+3+4+I K K K T K K K U U J q 5+6+q K K K U L J K K I.7+8+9+ ", +" 0+a+b+V K J J K K K K L O u.c+w.d+K K N J L J J K L K I.e+f+g+M.,+,+M.,+g.M.g.M.h+k i+B.K J J J J N J K O j+k+p ].J N K J L J M J B.F.k l+ ", +" * k !+J K K K K K K K K K T q.m+n+'.K M O U K L K K I o+p+>+1+g.,+,+M.,+,+,+,+M.f.q+r+_.K K T K K K U K 2.s+t+O J K K K U L K N K T y u+v+w+ ", +" x+y+z+A+L T T J T T K L K T K K B+k C+=+K J N T M T J !+k D+[.M.E+E+M.M.M.E+E+,+,+g.x.F+G+I K M T T M K w 4+H+I.K T T M M N M J J L J J d+I+J+ ", +" K+L+M+t.K O J J J K K K K L J K K v N+O+2.K J L J J K I.P+Q+R+g.h+S+,+M.M.M.g.M.g.M.g.g+T+t U+K J J J N B.Z.k V+J J J J N K J L J M U J K B.W+X+Y+ ", +" Z+k `+J K K N N N K K K K K M K K K I. @.@v K K N K v +@@@2+g.M.h+S+N.N.M.N.g.h+g.M.g.g.#@$@%@V K N N K _.*+&@'.K M L K M K J K N K K O K K #.*@=@-@ ", +" ;@>@,@v K J U J J J U U O U K J K U J -.'@k D.J O J J )@k !@[.g.M.h+E+M.M.M.M.g.,+g.,+g.M.M.g+k K J N J I ~@{@2.K J J U U J K J O J U U J O L ].I k ]@ ", +" ^@/@I.K K J K K K N K K K K K K K K N K (@_@W +.K K I.:@<@f.g.g.M.g.E+g.,+M.,+g.g.g.E+g.g.g.g+[@}@I.K O |@&.b.c.O K M L K K K K K N K K O K T J A+1@2@3@ ", +" 4@5@6@O J K J K K K J K K K K L K K L J J O 2.7@4.A+v 8@9@2+g.N.g.M.y.g.g.M.M.M.g.g.N.N.g.h+g.g.>+0@t+O '.a@S +.K U T J U U K K U L J K K U K J J ].t.b@c@d@ ", +" e@f@g@q J J M J O J J J K K K K L J K T J N J B.h@i@d+A.j@k@g.M.g.g.M.h+M.,+,+M.,+g.M.g.M.g.M.g.M.g.l@m@n@o@k p@J J O J N U U N K J L J M U U K J J N u.q@r@s@ ", +" t@i #.{.v v u@r u@r r r p p p q p p '.'.'.'.'.'.v@w@x@y@z@x.A@A@A@A@A@A@A@A@B@h.h.h.h.h.C@C@C@C@x.x.*.D@Y E@F@G@_._._.Y.Y.Y.#.#.#.+.+.+.P P P V V V |@|@H@I@J@K@", +"L@M@k N@O@O@O@P@P@P@Q@Q@Q@R@R@R@|.S@|.T@T@T@U@V@W@X@W@k Y@Z@`@Z@Z@ #.#.#+#@#@###t $#3+%#%#&#&#&#*#=#*#=#-#k k ;#>#,#'#b+)#!#)#~#{#~#]#]#]#^#/#^#(#_#:#<#<#[#}#k |#", +" 1#B 2#,+[.[.g.g.g.k@k@k@3#4#4#5#5#5#6#6#6#l@7#l@8#6#9#0#a#6@b#b#c#d#d#>.e#e#f#g#h#i#j#j#k#l#m#n#o#p#q#r#s#t#u#v#w#x#y#z#A#A#B#C#D#E#E#E#F#F#F#G#G#H#I#J#K#L#k M#", +" N#O#k C@g.M.M.M.M.M.M.M.M.M.M.M.M.M.[.[.[.[.[.[.[.M.P#Q#1.-.A.A.A.A.A.A.A.A.c.c.c.c.;.c.;.;.;.;.;.;.-.R#s+S#T#T#U#U#U#V#V#V#V#V#V#W#W#W#W#W#W#W#W#W#X#T#Y#Z#`# ", +" /+ $.$R+M.g.M.N.N.h+M.g.g.g.g.g.S+g.g.,+g.M.g.,+g.y.,.+$K O J U K J J J J U J U O U U J U J O J U E.@$#$$$%$&$&$&$*$&$=$=$&$&$%$&$%$=$%$&$&$%$&$&$&$-$;$>$ ", +" ,$'$)$M.g.M.g.g.g.,+g.g.g.g.g.E+g.g.M.S+g.g.M.g.2+!$~$].K N K K N K K K K J K K K O K K K K K K A+{$]$^$%$%$%$%$*$%$=$=$&$%$%$%$%$=$%$%$&$%$&$&$%$/$($_$ ", +" :$<$k [$g.M.N.g.y.M.N.g.g.g.g.g.g.g.M.y.h+g.M.M.f.}$|$J L J K K J O O K U J U K U O K K O K T J t..$1$2$%$%$3$%$*$4$=$5$4$3$%$%$%$5$%$%$4$%$&$6$7$k 8$ ", +" ;@9$0$x.g.h+h+h+,+g.g.g.g.g.,+y.y.M.h+M.y.M.,+g.a$b$'.K N K M J N J J U J U M U K N M N K J K w c$d$%$4$4$&$4$*$4$=$5$4$&$%$4$%$5$%$4$4$%$%$e$f$g$ ", +" h$i$j$f.g.N.N.,+,+,+,+g.g.E+N.,+,+g.,+,+,+,+1+3#k$1.J K O K J O O K K J K M U O K M O K T ].l$m$n$%$%$%$*$%$o$4$o$%$5$*$%$%$5$%$5$%$&$%$X#p$q$r$ ", +" s$k g.M.g.y.M.,+E+E+g.g.E+y.S+M.S+M.S+M.E+g.A@t$u$J J J M J N J T T J T M O J M T N K M =+v$w$x$&$&$&$&$&$&$&$&$&$&$&$&$&$4$&$=$&$%$y$z$k A$ ", +" B$w#C$D$g.h+M.g.g.g.g.g.E+g.g.M.S+M.g.M.,+M.>+&#E$B.J K M J N J J J J J M U O N M N K K +.F$G$H$*$*$*$*$*$&$&$&$&$&$*$%$*$%$&$%$*$%$I$J$K$ ", +" L$M$N$A@g.N.g.g.g.g.g.E+g.g.M.y.h+g.h+N.,+O$P$Q$w K K K N N N N K J K K U K N K N K J d+R$S$T$%$%$%$*$%$o$3$o$%$%$*$%$%$%$%$%$%$U$V$W$ ", +" /+:.X$[.M.g.g.g.g.g.S+g.g.,+g.M.g.,+M.g.S+2#Y$t.K U K J J J J U J U O U U J U J O J Z$`$ %%$&$&$&$&$&$*$&$=$=$&$&$%$&$%$=$&$' .%+%@% ", +" #%$%k x.1+g.g.g.g.g.E+g.g.M.S+g.g.M.g.g.g.f.&.F.B.K K N K K K K J K K K O K K K K -.%%&%e$&$%$%$%$%$%$*$%$=$=$&$%$%$%$%$%$%$*%=%-% ", +" ! ;%>%f.M.g.g.g.g.g.g.g.M.y.h+g.M.g.g.y.x.%#,%c.K K J O O K U J U K U O K K O J q '%)%^$3$%$%$%$3$%$*$4$=$5$4$3$%$%$%$%$!%~%{% ", +" 7$]%P#M.M.g.g.g.,+y.y.M.h+M.y.M.,+y.M.^%/%(%y K M J N J J U J U M U K N M N K _%j 6$%$3$4$4$4$&$4$*$4$=$5$4$&$%$4$&$:%|#<%[% ", +" }%|%k 1%g.g.g.g.E+N.,+,+g.,+,+,+,+,+,+[.2%3%V K K J O O K K J K M U O K M O B.C+4%5%&$3$%$%$%$*$%$o$4$o$%$5$*$%$&$2$. k 6% ", +" 7%8%9%x.g.g.g.E+y.S+M.S+M.S+M.E+S+S+g.f.F+0%J M J N J T T J T M O J M T N ;.a%b%c%&$*$&$&$&$&$&$&$&$&$&$&$&$&$%$n$d%e% ", +" f%g%h%g+g.g.E+g.g.M.S+M.g.M.,+g.M.M.A@`@G+;.M J N J J J J J M U O N M N v i%j%k%*$*$*$*$*$*$*$&$&$&$&$&$*$%$l%m%n%o% ", +" p%k |+M.g.E+g.g.M.y.h+g.h+N.g.M.M.^%q%r%v K N N N N K J K K U K N K K _.#+3$&$*$3$%$%$%$*$%$o$3$o$%$%$%$s%t%k u% ", +" v%w%x%x.g.S+g.g.,+g.M.g.,+M.g.M.M.g+y%z%'.J J J J J U J U O U U J U B.A%B%C%%$&$*$&$&$&$&$&$*$&$=$=$&$&$D%E%F% ", +" G%H%I%f.g.g.g.M.S+g.g.M.g.g.E+E+M.f.J%V K N K K K K J K K K O K K y K%>@L%%$%$%$%$%$%$%$%$*$%$=$=$%$M%N%O% ", +" P%Q%R%[.M.g.M.y.h+g.M.g.g.y.y.g.A@S%T%-.J O O K U J U K U O K K q ]#U%l%%$3$3$%$%$%$3$%$*$4$=$&$^$|#V%r$ ", +" A$W%k 2+g.M.M.h+M.y.M.,+y.M.M.g.f.X%Y%r J N J J U J U M U K N K |@Z%`% &4$&$3$4$4$4$&$4$*$4$=$y$.&k +& ", +" W.@&#&2+g.,+g.,+,+,+,+,+,+,+,+g+..Q.+.J O O K K J K M U O K J $&%&&&%$%$*$3$%$%$%$*$%$o$&$*&=&-&;& ", +" >&,&'&M.M.S+M.S+M.E+S+S+S+,+M.)&!&q K N J T T J T M O J M I ~&{&C%&$4$&$*$&$&$&$&$&$&$%$M%]&^&/& ", +" (&k _&1+M.M.g.M.,+g.M.M.g.g.x.k :&N N J J J J J M U O N V <&[&k%%$*$*$*$*$*$*$*$*$&$6$}&F+|& ", +" B$1&2&h.g.h+g.h+N.g.M.M.g.g.f.3&4&w J N N K J K K U K K 5&6&7&:%%$%$*$3$%$%$%$*$&$S$*%8&9& ", +" D 0&h%a&g.g.,+M.g.M.M.g.g.[.b&c&_.T J J U J U O U U O d&e&n$5$%$&$&$*$&$&$&$&$&$U$f&g& ", +" h&k S+g.M.M.g.g.E+E+g.E+M.l@i&V ].K K K J K K K O c.j&k&l&%$%$%$%$%$%$%$%$%$m&n&o&p& ", +" q&r&s&A@M.M.g.g.y.y.N.g.M.>+@@J t&O K U J U K U J V )&u&V#3$%$%$3$3$%$%$&$%$. k v& ", +" w&x&y&^%g.,+y.M.M.g.g.,+A@z&A&u.J J U J U M U K I.B&C& &4$%$4$&$3$4$4$%$$$D&E& ", +" F&G&6#[.g.,+,+,+,+,+N.[.H&I&v J K K J K M U u.I h 4@&$3$%$%$*$3$%$%$J&K&L&r$ ", +" M&N&k 2+g.S+S+S+,+E+M.M.O&W@n@K T T J T M O P&Q&R&!%%$&$&$4$&$*$%$S&T&k U& ", +" < V&W&C@g.M.M.g.g.M.M.O.X&K Y&J J J J M J I Z&`&V#%$*$%$*$*$*$%$$$ *.* ", +" D +*@*O.M.M.g.g.h+g.>+9@#*t&N K J K K K I.$*%*&$%$3$%$%$&$%$&&&***=* ", +" t@k 1%1+g.g.g.N.g.g+-*;*5.K U J U O ].I >*,*&$%$&$%$&$&$'*)*!*~* ", +" e@{*0$A@g.g.E+M.g.1+T+]*I.T K J K K E.^*/*=&%$%$%$%$%$H$(*k _* ", +" :*0&<*[.M.g.h+N.g.h+i@!+K U J U K -.[*}*'*%$%$3$%$%$|*1*K& ", +" 2*k 3*g.g.h+g.g.2+4*F ].U J U J Y.5*6*6$3$%$4$&$7*8*9*u% ", +" 0*a*b*2+g.N.N.S+f.c*d*J K J K K V e*f**&%$o$%$%$g*k h* ", +" i*j*k*f.g.N.g.g.l*r+'.K J T ].m*n* %%$*$=$%$c%o*p* ", +" < q*_#[.g.g.1+3#,.2.J J J J r*s*C%&$*$%$t*u*v*w* ", +" x*k C@g.g.g.A@J%u$J J K '.y*z**&%$%$:%O#A*B* ", +" C*V&D*#@g.M.>+&#E*J J J 2.z&& H$&$&$(*k F* ", +" x+G*'&g+M.O$H*I*w J J J*K**%%$%$c%L*M* ", +" N*k f.y.E+D+Y$t.O B.+@O*$$&$k%8*P*x+ ", +" Q*R*S*D$g.O.S%:&J w T*U*k%V*W*k X* ", +" < Y**@[.x.Z*m#A.G@`* =2$=&.=+= ", +" @=k [$f.#=k.w $=%=~ U$&=*=== ", +" -=;=s&2+O&>=_.E$,=$$$+'=)= ", +" !=j*~=C@k {=]=^=I$k /= ", +" 3@q*S+Z@F (=S&_=:=<= ", +" [=}=|=1=2=3=4=5= ", +" 6=7=9 $#8=e&9= ", +" Z+0=k k a= ", +" t%k b=^+ ", +" c=d=d$ ", +" e= "}; diff --git a/share/pixmaps/check.ico b/share/pixmaps/check.ico new file mode 100644 index 0000000000000000000000000000000000000000..0c4e6e81473d47761346fd71e171a807bda5ec58 GIT binary patch literal 766 zcmdUtAritc5Ji7?>Oo=IK{2@m+>AIRcZlpMaugJUL?RfLzb&Fm5tZVcTcTu78nlc+X79T)o9yH~Bu18~wK99d`Ux|y2#0TZ_)l%(v!!U*NL^S< zm%;~9QW>8Y{WOqh07L_>g8?ux2p5ho`>mS)zTM&e&IX1#g=n*mx%M2=4~G0=JGSscEg3UADSdc%uJ6^~y?X za>k8LtjfKC7>O=tAo^HYWw_4x;?2&BT?qR78lsZ_MGSX7>IZ!c=PDo6l$v_6?)Wpz zk~UyQf*SMpXq(&~h`#6J@X7iE8bcT41~(RK9#M#*g{CGHW739fY~;>y-_qY~dpkt1 z$8o3UDyrMNOB?%;seeU5oP(xtE`;o_Aip*LAb5x7t@v2Yk}rMiE7cGEbRWT8c3xB0 zxlv~Bhxlp-`K8$4pYFu`^lJG3k%h5qq*$7)Gd}Mpp|mV9|LSKg6Q8(yF#q;TsEz-l zz}Q0x6;C1Pe~~(|NNz^J1{sZtIzrRp6o|<@oBd@B+m)9V$g3W|5wsd(k0-CzP0LGK zX=17kze*j5P_R+MkUO)JnQMsiL zn!5imJJ;!Dj=Tk7s)tywx{aCfc?jI1q^WUAgzhfJ4)yh8`^wGs_=@LtknUSs)Ty;Ul(C zF#m6a%0<~V-K4wMhZ2*JPdAon+Yq5{Lx9vteiA1_@S`T$RC*r?Iy)BTnh>dI#DZLtC%VvrJtxcs!oR{I3C|+NJUs6v@%S*-%kyL; i&oIVr@uYdX`{R4zEFjng2ItJ+oEe-mgLCF*&zTPoC&^y` literal 0 HcmV?d00001 diff --git a/share/pixmaps/nsis-header.bmp b/share/pixmaps/nsis-header.bmp new file mode 100644 index 0000000000000000000000000000000000000000..5eb10ae77393363c2b33b44967f21b78ed5f170f GIT binary patch literal 34254 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 literal 0 HcmV?d00001 diff --git a/share/pixmaps/nsis-wizard.bmp b/share/pixmaps/nsis-wizard.bmp new file mode 100644 index 0000000000000000000000000000000000000000..330de6bc91099c0c2c112a9b8636df1d1a34cf44 GIT binary patch literal 206038 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 literal 0 HcmV?d00001 diff --git a/share/pixmaps/send16.bmp b/share/pixmaps/send16.bmp new file mode 100644 index 0000000000000000000000000000000000000000..676b5c4b490e0859578ae599af54aa3de26d5d3b GIT binary patch literal 1334 zcmYk5Jx^OP6oy|?if#e5^t<#cRBdTfU1zbxz?iX8m;M2UN?sTsJ~LYQ7gH)G3saMH zyB~}P>RC^tqazJ22kKf^qtTH%)*+8HB(`iz!{JD6Ym}Tk7?DT0LLYf-R`9Lfu|hGN{Hh5!TD1R4whhJ=^V zS4W7?sJSvv_HRM}BgTY`h7z_r3!Cba8Q^tE($rUtjC@AJfm>U2Se|a=Q6{ASdcovs^b%O|_~O^A9J3 zo8Gy{cW=fyyV5$bWwCUxW^1*ko3u|Q!khV8bNYU6kCq$$b?M$c zXwEFX|G1o6qw%(MADT1u`ciJFjYp+xPCtD)5ti!rOE=q`nY3s1`n}Q>|Lf1qO_lCf Z2B?~wyHmPbfR5?STF&s_p4QyW^e;amw9xQ85j>RFfcv<;txRlgMp#`4+F#he?a^n U34{0`aiBa{9Y{S$UjqXJ0D?~%)Bpeg literal 0 HcmV?d00001 diff --git a/share/pixmaps/send16masknoshadow.bmp b/share/pixmaps/send16masknoshadow.bmp new file mode 100644 index 0000000000000000000000000000000000000000..faf24e0d8aa81faf80072c7807e52d749cad63c0 GIT binary patch literal 126 zcmZ?rtz&=yJ0PV2!~#&v$iN7eZ~&8-#Q*>Q!Geqp3=E71fcOCre_&wv{{x8s0P#N{ U1}Xv5AU;qWBo9^xQV-Mz01_z}*8l(j literal 0 HcmV?d00001 diff --git a/share/pixmaps/send20.bmp b/share/pixmaps/send20.bmp new file mode 100644 index 0000000000000000000000000000000000000000..2b90422b38467ae30a2b6a866adbf0ad3c3f97f3 GIT binary patch literal 1478 zcmZXSKWrOi7{;GaLQNamP(c#|QaKSso$~KuQiKB~Sfms~DLR@G4onc1ZpoM-LzWCy zrW+Vekxuf^0gqWCdGvy0mVEN)Oz9FSLza-qkr-Zn=R}0i&wlRv?)Sa-KF@b{`Tn27 z8jRb|N;g@(bgCic2K=|7!F2A@wXWLMR;S-l%UasBO*O5lhBegf^^{nmZnvk{Vs*M* z)vd1NFwv^5s?+Ie*_N3*YNI7vQmfNe&1zceFR9&btA#=fRqNMS(;o#EsMUh^LuMEX z`hm(;R&W?-bCV3Ha#)dXz6w@Qv)Pnqp2A+J@_t##W}?cIic0$>h22o2HmXLWA%EXj z&T>i`iR#U|WKyYDQqT#cz7!|1>IwW%T5c>Wx1Up`g-^$q_F>7g^h631&JZt2J*nI* zs}|R!uH?1I5QkDn3gSSeMoE>pBDEzy@#Qr<`LVB3y(BO3REP`m>+sl9exSU(I()UD ze4X{Gr_uVT@~e48a>x`Fg^DObDS{W_5uDA4MHIm!cnV8lDJ+Gh8Kc(09o)ej%)xjU zk--dR4macD#A8bFIr(tUKP1JUD(39oM0*4yQ;KPdK}x0+@087yCMn)2-b^U-hU1^& zpW@FJqCVqfNXd{|mH@8e;Pen?uDkB#>=(#Rj30j=G8h?*3`Pbc1CJnjlEKJeWN>7l z4Wgb5Mg}8;k%86-P6i``k--RH_&b^z4;n=gJtFQSa@e4ERujonQ;Um>T3K1q`ue&y zHa4`qy{)aSE$!^=Xm@v4dwY92I5^PJ(UFdikM-Bzrr#ew*4o+{Zvdf^`qjovy#Co%$I+@J$@dB6B8f(^6~4>pU}%==y%-wtc z`osH^S7B4r)6+9EckZw;_raBil`&XhDx=xP?CkZot6ui($jfisni}w_EB+5zMp!mp zc<$!Ztz7BRSQc>pbPVUO41f0E-0{K-mo9vH_i9%4?^yU_=-W@Ty#E;s&wTgc|Io$i T{JW>;KP#Mn?J0D&nXUc-U3=Ry literal 0 HcmV?d00001 diff --git a/share/pixmaps/send20mask.bmp b/share/pixmaps/send20mask.bmp new file mode 100644 index 0000000000000000000000000000000000000000..f124d0da084e68cac62312e9fa8a0fbf9c7c5075 GIT binary patch literal 142 zcmZ?r?PGudJ0PV2#3E44$iN7e2mq2o+z`wJ7J(4||Nm!TJix%f_yCAM0PznX{=>jv m|BrzIC +// Automatically generated by extract_strings.py +#ifdef __GNUC__ +#define UNUSED __attribute__((unused)) +#else +#define UNUSED +#endif +""") +f.write('static const char UNUSED *bitcoin_strings[] = {') +for (msgid, msgstr) in messages: + if msgid != EMPTY: + f.write('QT_TRANSLATE_NOOP("bitcoin-core", %s),\n' % ('\n'.join(msgid))) +f.write('};') +f.close() diff --git a/share/qt/img/reload.xcf b/share/qt/img/reload.xcf new file mode 100644 index 0000000000000000000000000000000000000000..dc8be62831673c2e99f05f5e5b42581e6e4e1db1 GIT binary patch literal 25292 zcmb_^2Y8gl_WtZ{I!Q?Hy(}b<0!T>!i3mz>b^$>V5F6Z!w4YZ&(W@v5C?M7#R#ZTZ zV!0wJ5F1J8AtaO(0x6KXNl140`@ipe--Zo_h|lwfXS3hVoO7m~Ip@4*W_RwqM;1ga zoi!(F&b)_b3;bK5z4+{nmrjR2zIeF|U+eG|UwHPz%K@(lyaKdm()ojaINrVHLTu8! zNA8_FJ8AB}=iQGYfqI?jx$v=N56_NTIRD{!_b0gZoHKXU{D8=`MUo2pO%(3DD}GQ(gqA1 z(4TeMKixJVM&Dukg!dKNi?i)B{N7m)&HeZMMUUPeHEaHYWwCuwD4g)(+9-IrXwRf} z)t>Pt-0Ysa**&}4J$u+acgHhj+5S1>fo<@gy)LLFLO)e|Sb=xGK&xMfk&MMN|E*A8 z`ZYoXe<6f%oe=#nQX!Tb28yPHiE}or-JbQ?2cnOt55NEQ{fGDO`*G)vkKcVmB#WBJ zr8#F$<>&qO^Y@^5=e4z>x41Cj+nV#mCrI|q=UcbDx&Ed9ibPR0<3vL>NDut}%m2RG z_F?9xbuT>qxacV=GEO$vR+JPT$;saR%@?1%_ZG;PFa4J=igQsr+8QsEpFV!@k3BY) zmH%1v=v)ym$`@Q{sjF1Ez9rX&m!Dg)?B5UFKV8I%GW})7AHLrH(dO4*dGVPi7SEqM z^R6i(MwF(W0&i*2(cE8u`tHk5-+z0fjraD6qeQeQnNe-JckT+`n&XvIrNarrJ;B8=92+rrtXKreTBn^+`$U zEyBdfA?mc+R$$fBk3aUvoEdjc9&_Um%1P>#AVNh^_=(~|`z65~KR9dJZS9g0d-fpN zcO6y;(`^$qKo!-~7$-tR;gfQ`S89x*KK>QrIkRN&Q# z+|?E%glhIfL)k9QxYN~NXO@gS3lPV+2ecCw^MYSh2DLe#%E*JL}y6D;~ z3zI~Rmn`$UOqe3-LcwZRk}B#wf&=Ud`U;(2(`Al+!sLAUQ-9IyVH?;0(PGdh&nTAb zeiRmii|8k;29YML14X*9`ikY^SJCv;o1f+8oUN`rPcO9e!#^%G*4NftsH!+$4vTIb z1Akhx?2B_P&8CLB+KV7Ncea$SXhVM6rIx04+OpDOx}wY~bL%A=X~ns-WhG}$!6ZYB zv#3~IWl?$RAiwf_Ie1Q=ETTVJmSd{1%#&@!?fc|K!$abmI6i z`Xf&;wxL1vqXT39u_N?HE2}ML8!x(EZsW~AdiWsyQKqS#8zVkfj_#gDv&WAeIdmY8 z{wP!OW9T&;I{DAAZSo(;%@KhdnWH$9iGek9GA?RjFfdij!MvQDTsoypbc7Ql1z`@Q zpaKXw1VOoZ2kDgF(WI!;UsggX80eA1Qp$lthv}4FROQ�ux+RXp@tZcks}WV=yh& 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" no_smgroup +no_smgroup: + Pop $R0 +SectionEnd + +# Installer functions +Function .onInit + InitPluginsDir +FunctionEnd + +# Uninstaller functions +Function un.onInit + ReadRegStr $INSTDIR HKCU "${REGKEY}" Path + !insertmacro MUI_STARTMENU_GETFOLDER Application $StartMenuGroup + !insertmacro SELECT_UNSECTION Main ${UNSEC0000} +FunctionEnd diff --git a/share/ui.rc b/share/ui.rc new file mode 100644 index 0000000..431d8fd --- /dev/null +++ b/share/ui.rc @@ -0,0 +1,15 @@ +BottleCaps ICON "pixmaps/BottleCaps.ico" + +#include "wx/msw/wx.rc" + +check ICON "pixmaps/check.ico" +send16 BITMAP "pixmaps/send16.bmp" +send16mask BITMAP "pixmaps/send16mask.bmp" +send16masknoshadow BITMAP "pixmaps/send16masknoshadow.bmp" +send20 BITMAP "pixmaps/send20.bmp" +send20mask BITMAP "pixmaps/send20mask.bmp" +addressbook16 BITMAP "pixmaps/addressbook16.bmp" +addressbook16mask BITMAP "pixmaps/addressbook16mask.bmp" +addressbook20 BITMAP "pixmaps/addressbook20.bmp" +addressbook20mask BITMAP "pixmaps/addressbook20mask.bmp" +favicon ICON "pixmaps/favicon.ico" diff --git a/src/addrman.cpp b/src/addrman.cpp new file mode 100644 index 0000000..4428cd1 --- /dev/null +++ b/src/addrman.cpp @@ -0,0 +1,527 @@ +// Copyright (c) 2012 Pieter Wuille +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "addrman.h" + +using namespace std; + +int CAddrInfo::GetTriedBucket(const std::vector &nKey) const +{ + CDataStream ss1(SER_GETHASH, 0); + std::vector vchKey = GetKey(); + ss1 << nKey << vchKey; + uint64 hash1 = Hash(ss1.begin(), ss1.end()).Get64(); + + CDataStream ss2(SER_GETHASH, 0); + std::vector vchGroupKey = GetGroup(); + ss2 << nKey << vchGroupKey << (hash1 % ADDRMAN_TRIED_BUCKETS_PER_GROUP); + uint64 hash2 = Hash(ss2.begin(), ss2.end()).Get64(); + return hash2 % ADDRMAN_TRIED_BUCKET_COUNT; +} + +int CAddrInfo::GetNewBucket(const std::vector &nKey, const CNetAddr& src) const +{ + CDataStream ss1(SER_GETHASH, 0); + std::vector vchGroupKey = GetGroup(); + std::vector vchSourceGroupKey = src.GetGroup(); + ss1 << nKey << vchGroupKey << vchSourceGroupKey; + uint64 hash1 = Hash(ss1.begin(), ss1.end()).Get64(); + + CDataStream ss2(SER_GETHASH, 0); + ss2 << nKey << vchSourceGroupKey << (hash1 % ADDRMAN_NEW_BUCKETS_PER_SOURCE_GROUP); + uint64 hash2 = Hash(ss2.begin(), ss2.end()).Get64(); + return hash2 % ADDRMAN_NEW_BUCKET_COUNT; +} + +bool CAddrInfo::IsTerrible(int64 nNow) const +{ + if (nLastTry && nLastTry >= nNow-60) // never remove things tried the last minute + return false; + + if (nTime > nNow + 10*60) // came in a flying DeLorean + return true; + + if (nTime==0 || nNow-nTime > ADDRMAN_HORIZON_DAYS*86400) // not seen in over a month + return true; + + if (nLastSuccess==0 && nAttempts>=ADDRMAN_RETRIES) // tried three times and never a success + return true; + + if (nNow-nLastSuccess > ADDRMAN_MIN_FAIL_DAYS*86400 && nAttempts>=ADDRMAN_MAX_FAILURES) // 10 successive failures in the last week + return true; + + return false; +} + +double CAddrInfo::GetChance(int64 nNow) const +{ + double fChance = 1.0; + + int64 nSinceLastSeen = nNow - nTime; + int64 nSinceLastTry = nNow - nLastTry; + + if (nSinceLastSeen < 0) nSinceLastSeen = 0; + if (nSinceLastTry < 0) nSinceLastTry = 0; + + fChance *= 600.0 / (600.0 + nSinceLastSeen); + + // deprioritize very recent attempts away + if (nSinceLastTry < 60*10) + fChance *= 0.01; + + // deprioritize 50% after each failed attempt + for (int n=0; n::iterator it = mapAddr.find(addr); + if (it == mapAddr.end()) + return NULL; + if (pnId) + *pnId = (*it).second; + std::map::iterator it2 = mapInfo.find((*it).second); + if (it2 != mapInfo.end()) + return &(*it2).second; + return NULL; +} + +CAddrInfo* CAddrMan::Create(const CAddress &addr, const CNetAddr &addrSource, int *pnId) +{ + int nId = nIdCount++; + mapInfo[nId] = CAddrInfo(addr, addrSource); + mapAddr[addr] = nId; + mapInfo[nId].nRandomPos = vRandom.size(); + vRandom.push_back(nId); + if (pnId) + *pnId = nId; + return &mapInfo[nId]; +} + +void CAddrMan::SwapRandom(unsigned int nRndPos1, unsigned int nRndPos2) +{ + if (nRndPos1 == nRndPos2) + return; + + assert(nRndPos1 < vRandom.size() && nRndPos2 < vRandom.size()); + + int nId1 = vRandom[nRndPos1]; + int nId2 = vRandom[nRndPos2]; + + assert(mapInfo.count(nId1) == 1); + assert(mapInfo.count(nId2) == 1); + + mapInfo[nId1].nRandomPos = nRndPos2; + mapInfo[nId2].nRandomPos = nRndPos1; + + vRandom[nRndPos1] = nId2; + vRandom[nRndPos2] = nId1; +} + +int CAddrMan::SelectTried(int nKBucket) +{ + std::vector &vTried = vvTried[nKBucket]; + + // random shuffle the first few elements (using the entire list) + // find the least recently tried among them + int64 nOldest = -1; + int nOldestPos = -1; + for (unsigned int i = 0; i < ADDRMAN_TRIED_ENTRIES_INSPECT_ON_EVICT && i < vTried.size(); i++) + { + int nPos = GetRandInt(vTried.size() - i) + i; + int nTemp = vTried[nPos]; + vTried[nPos] = vTried[i]; + vTried[i] = nTemp; + assert(nOldest == -1 || mapInfo.count(nTemp) == 1); + if (nOldest == -1 || mapInfo[nTemp].nLastSuccess < mapInfo[nOldest].nLastSuccess) { + nOldest = nTemp; + nOldestPos = nPos; + } + } + + return nOldestPos; +} + +int CAddrMan::ShrinkNew(int nUBucket) +{ + assert(nUBucket >= 0 && (unsigned int)nUBucket < vvNew.size()); + std::set &vNew = vvNew[nUBucket]; + + // first look for deletable items + for (std::set::iterator it = vNew.begin(); it != vNew.end(); it++) + { + assert(mapInfo.count(*it)); + CAddrInfo &info = mapInfo[*it]; + if (info.IsTerrible()) + { + if (--info.nRefCount == 0) + { + SwapRandom(info.nRandomPos, vRandom.size()-1); + vRandom.pop_back(); + mapAddr.erase(info); + mapInfo.erase(*it); + nNew--; + } + vNew.erase(it); + return 0; + } + } + + // otherwise, select four randomly, and pick the oldest of those to replace + int n[4] = {GetRandInt(vNew.size()), GetRandInt(vNew.size()), GetRandInt(vNew.size()), GetRandInt(vNew.size())}; + int nI = 0; + int nOldest = -1; + for (std::set::iterator it = vNew.begin(); it != vNew.end(); it++) + { + if (nI == n[0] || nI == n[1] || nI == n[2] || nI == n[3]) + { + assert(nOldest == -1 || mapInfo.count(*it) == 1); + if (nOldest == -1 || mapInfo[*it].nTime < mapInfo[nOldest].nTime) + nOldest = *it; + } + nI++; + } + assert(mapInfo.count(nOldest) == 1); + CAddrInfo &info = mapInfo[nOldest]; + if (--info.nRefCount == 0) + { + SwapRandom(info.nRandomPos, vRandom.size()-1); + vRandom.pop_back(); + mapAddr.erase(info); + mapInfo.erase(nOldest); + nNew--; + } + vNew.erase(nOldest); + + return 1; +} + +void CAddrMan::MakeTried(CAddrInfo& info, int nId, int nOrigin) +{ + assert(vvNew[nOrigin].count(nId) == 1); + + // remove the entry from all new buckets + for (std::vector >::iterator it = vvNew.begin(); it != vvNew.end(); it++) + { + if ((*it).erase(nId)) + info.nRefCount--; + } + nNew--; + + assert(info.nRefCount == 0); + + // what tried bucket to move the entry to + int nKBucket = info.GetTriedBucket(nKey); + std::vector &vTried = vvTried[nKBucket]; + + // first check whether there is place to just add it + if (vTried.size() < ADDRMAN_TRIED_BUCKET_SIZE) + { + vTried.push_back(nId); + nTried++; + info.fInTried = true; + return; + } + + // otherwise, find an item to evict + int nPos = SelectTried(nKBucket); + + // find which new bucket it belongs to + assert(mapInfo.count(vTried[nPos]) == 1); + int nUBucket = mapInfo[vTried[nPos]].GetNewBucket(nKey); + std::set &vNew = vvNew[nUBucket]; + + // remove the to-be-replaced tried entry from the tried set + CAddrInfo& infoOld = mapInfo[vTried[nPos]]; + infoOld.fInTried = false; + infoOld.nRefCount = 1; + // do not update nTried, as we are going to move something else there immediately + + // check whether there is place in that one, + if (vNew.size() < ADDRMAN_NEW_BUCKET_SIZE) + { + // if so, move it back there + vNew.insert(vTried[nPos]); + } else { + // otherwise, move it to the new bucket nId came from (there is certainly place there) + vvNew[nOrigin].insert(vTried[nPos]); + } + nNew++; + + vTried[nPos] = nId; + // we just overwrote an entry in vTried; no need to update nTried + info.fInTried = true; + return; +} + +void CAddrMan::Good_(const CService &addr, int64 nTime) +{ +// printf("Good: addr=%s\n", addr.ToString().c_str()); + + int nId; + CAddrInfo *pinfo = Find(addr, &nId); + + // if not found, bail out + if (!pinfo) + return; + + CAddrInfo &info = *pinfo; + + // check whether we are talking about the exact same CService (including same port) + if (info != addr) + return; + + // update info + info.nLastSuccess = nTime; + info.nLastTry = nTime; + info.nTime = nTime; + info.nAttempts = 0; + + // if it is already in the tried set, don't do anything else + if (info.fInTried) + return; + + // find a bucket it is in now + int nRnd = GetRandInt(vvNew.size()); + int nUBucket = -1; + for (unsigned int n = 0; n < vvNew.size(); n++) + { + int nB = (n+nRnd) % vvNew.size(); + std::set &vNew = vvNew[nB]; + if (vNew.count(nId)) + { + nUBucket = nB; + break; + } + } + + // if no bucket is found, something bad happened; + // TODO: maybe re-add the node, but for now, just bail out + if (nUBucket == -1) return; + + printf("Moving %s to tried\n", addr.ToString().c_str()); + + // move nId to the tried tables + MakeTried(info, nId, nUBucket); +} + +bool CAddrMan::Add_(const CAddress &addr, const CNetAddr& source, int64 nTimePenalty) +{ + if (!addr.IsRoutable()) + return false; + + bool fNew = false; + int nId; + CAddrInfo *pinfo = Find(addr, &nId); + + if (pinfo) + { + // periodically update nTime + bool fCurrentlyOnline = (GetAdjustedTime() - addr.nTime < 24 * 60 * 60); + int64 nUpdateInterval = (fCurrentlyOnline ? 60 * 60 : 24 * 60 * 60); + if (addr.nTime && (!pinfo->nTime || pinfo->nTime < addr.nTime - nUpdateInterval - nTimePenalty)) + pinfo->nTime = max((int64)0, addr.nTime - nTimePenalty); + + // add services + pinfo->nServices |= addr.nServices; + + // do not update if no new information is present + if (!addr.nTime || (pinfo->nTime && addr.nTime <= pinfo->nTime)) + return false; + + // do not update if the entry was already in the "tried" table + if (pinfo->fInTried) + return false; + + // do not update if the max reference count is reached + if (pinfo->nRefCount == ADDRMAN_NEW_BUCKETS_PER_ADDRESS) + return false; + + // stochastic test: previous nRefCount == N: 2^N times harder to increase it + int nFactor = 1; + for (int n=0; nnRefCount; n++) + nFactor *= 2; + if (nFactor > 1 && (GetRandInt(nFactor) != 0)) + return false; + } else { + pinfo = Create(addr, source, &nId); + pinfo->nTime = max((int64)0, (int64)pinfo->nTime - nTimePenalty); +// printf("Added %s [nTime=%fhr]\n", pinfo->ToString().c_str(), (GetAdjustedTime() - pinfo->nTime) / 3600.0); + nNew++; + fNew = true; + } + + int nUBucket = pinfo->GetNewBucket(nKey, source); + std::set &vNew = vvNew[nUBucket]; + if (!vNew.count(nId)) + { + pinfo->nRefCount++; + if (vNew.size() == ADDRMAN_NEW_BUCKET_SIZE) + ShrinkNew(nUBucket); + vvNew[nUBucket].insert(nId); + } + return fNew; +} + +void CAddrMan::Attempt_(const CService &addr, int64 nTime) +{ + CAddrInfo *pinfo = Find(addr); + + // if not found, bail out + if (!pinfo) + return; + + CAddrInfo &info = *pinfo; + + // check whether we are talking about the exact same CService (including same port) + if (info != addr) + return; + + // update info + info.nLastTry = nTime; + info.nAttempts++; +} + +CAddress CAddrMan::Select_(int nUnkBias) +{ + if (size() == 0) + return CAddress(); + + double nCorTried = sqrt(nTried) * (100.0 - nUnkBias); + double nCorNew = sqrt(nNew) * nUnkBias; + if ((nCorTried + nCorNew)*GetRandInt(1<<30)/(1<<30) < nCorTried) + { + // use a tried node + double fChanceFactor = 1.0; + while(1) + { + int nKBucket = GetRandInt(vvTried.size()); + std::vector &vTried = vvTried[nKBucket]; + if (vTried.size() == 0) continue; + int nPos = GetRandInt(vTried.size()); + assert(mapInfo.count(vTried[nPos]) == 1); + CAddrInfo &info = mapInfo[vTried[nPos]]; + if (GetRandInt(1<<30) < fChanceFactor*info.GetChance()*(1<<30)) + return info; + fChanceFactor *= 1.2; + } + } else { + // use a new node + double fChanceFactor = 1.0; + while(1) + { + int nUBucket = GetRandInt(vvNew.size()); + std::set &vNew = vvNew[nUBucket]; + if (vNew.size() == 0) continue; + int nPos = GetRandInt(vNew.size()); + std::set::iterator it = vNew.begin(); + while (nPos--) + it++; + assert(mapInfo.count(*it) == 1); + CAddrInfo &info = mapInfo[*it]; + if (GetRandInt(1<<30) < fChanceFactor*info.GetChance()*(1<<30)) + return info; + fChanceFactor *= 1.2; + } + } +} + +#ifdef DEBUG_ADDRMAN +int CAddrMan::Check_() +{ + std::set setTried; + std::map mapNew; + + if (vRandom.size() != nTried + nNew) return -7; + + for (std::map::iterator it = mapInfo.begin(); it != mapInfo.end(); it++) + { + int n = (*it).first; + CAddrInfo &info = (*it).second; + if (info.fInTried) + { + + if (!info.nLastSuccess) return -1; + if (info.nRefCount) return -2; + setTried.insert(n); + } else { + if (info.nRefCount < 0 || info.nRefCount > ADDRMAN_NEW_BUCKETS_PER_ADDRESS) return -3; + if (!info.nRefCount) return -4; + mapNew[n] = info.nRefCount; + } + if (mapAddr[info] != n) return -5; + if (info.nRandomPos<0 || info.nRandomPos>=vRandom.size() || vRandom[info.nRandomPos] != n) return -14; + if (info.nLastTry < 0) return -6; + if (info.nLastSuccess < 0) return -8; + } + + if (setTried.size() != nTried) return -9; + if (mapNew.size() != nNew) return -10; + + for (int n=0; n &vTried = vvTried[n]; + for (std::vector::iterator it = vTried.begin(); it != vTried.end(); it++) + { + if (!setTried.count(*it)) return -11; + setTried.erase(*it); + } + } + + for (int n=0; n &vNew = vvNew[n]; + for (std::set::iterator it = vNew.begin(); it != vNew.end(); it++) + { + if (!mapNew.count(*it)) return -12; + if (--mapNew[*it] == 0) + mapNew.erase(*it); + } + } + + if (setTried.size()) return -13; + if (mapNew.size()) return -15; + + return 0; +} +#endif + +void CAddrMan::GetAddr_(std::vector &vAddr) +{ + int nNodes = ADDRMAN_GETADDR_MAX_PCT*vRandom.size()/100; + if (nNodes > ADDRMAN_GETADDR_MAX) + nNodes = ADDRMAN_GETADDR_MAX; + + // perform a random shuffle over the first nNodes elements of vRandom (selecting from all) + for (int n = 0; n nUpdateInterval) + info.nTime = nTime; +} diff --git a/src/addrman.h b/src/addrman.h new file mode 100644 index 0000000..f65e0b3 --- /dev/null +++ b/src/addrman.h @@ -0,0 +1,574 @@ +// Copyright (c) 2012 Pieter Wuille +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. +#ifndef _BITCOIN_ADDRMAN +#define _BITCOIN_ADDRMAN 1 + +#include "netbase.h" +#include "protocol.h" +#include "util.h" +#include "sync.h" + + +#include +#include + +#include + + +/** Extended statistics about a CAddress */ +class CAddrInfo : public CAddress +{ +private: + // where knowledge about this address first came from + CNetAddr source; + + // last successful connection by us + int64 nLastSuccess; + + // last try whatsoever by us: + // int64 CAddress::nLastTry + + // connection attempts since last successful attempt + int nAttempts; + + // reference count in new sets (memory only) + int nRefCount; + + // in tried set? (memory only) + bool fInTried; + + // position in vRandom + int nRandomPos; + + friend class CAddrMan; + +public: + + IMPLEMENT_SERIALIZE( + CAddress* pthis = (CAddress*)(this); + READWRITE(*pthis); + READWRITE(source); + READWRITE(nLastSuccess); + READWRITE(nAttempts); + ) + + void Init() + { + nLastSuccess = 0; + nLastTry = 0; + nAttempts = 0; + nRefCount = 0; + fInTried = false; + nRandomPos = -1; + } + + CAddrInfo(const CAddress &addrIn, const CNetAddr &addrSource) : CAddress(addrIn), source(addrSource) + { + Init(); + } + + CAddrInfo() : CAddress(), source() + { + Init(); + } + + // Calculate in which "tried" bucket this entry belongs + int GetTriedBucket(const std::vector &nKey) const; + + // Calculate in which "new" bucket this entry belongs, given a certain source + int GetNewBucket(const std::vector &nKey, const CNetAddr& src) const; + + // Calculate in which "new" bucket this entry belongs, using its default source + int GetNewBucket(const std::vector &nKey) const + { + return GetNewBucket(nKey, source); + } + + // Determine whether the statistics about this entry are bad enough so that it can just be deleted + bool IsTerrible(int64 nNow = GetAdjustedTime()) const; + + // Calculate the relative chance this entry should be given when selecting nodes to connect to + double GetChance(int64 nNow = GetAdjustedTime()) const; + +}; + +// Stochastic address manager +// +// Design goals: +// * Only keep a limited number of addresses around, so that addr.dat and memory requirements do not grow without bound. +// * Keep the address tables in-memory, and asynchronously dump the entire to able in addr.dat. +// * Make sure no (localized) attacker can fill the entire table with his nodes/addresses. +// +// To that end: +// * Addresses are organized into buckets. +// * Address that have not yet been tried go into 256 "new" buckets. +// * Based on the address range (/16 for IPv4) of source of the information, 32 buckets are selected at random +// * The actual bucket is chosen from one of these, based on the range the address itself is located. +// * One single address can occur in up to 4 different buckets, to increase selection chances for addresses that +// are seen frequently. The chance for increasing this multiplicity decreases exponentially. +// * When adding a new address to a full bucket, a randomly chosen entry (with a bias favoring less recently seen +// ones) is removed from it first. +// * Addresses of nodes that are known to be accessible go into 64 "tried" buckets. +// * Each address range selects at random 4 of these buckets. +// * The actual bucket is chosen from one of these, based on the full address. +// * When adding a new good address to a full bucket, a randomly chosen entry (with a bias favoring less recently +// tried ones) is evicted from it, back to the "new" buckets. +// * Bucket selection is based on cryptographic hashing, using a randomly-generated 256-bit key, which should not +// be observable by adversaries. +// * Several indexes are kept for high performance. Defining DEBUG_ADDRMAN will introduce frequent (and expensive) +// consistency checks for the entire data structure. + +// total number of buckets for tried addresses +#define ADDRMAN_TRIED_BUCKET_COUNT 64 + +// maximum allowed number of entries in buckets for tried addresses +#define ADDRMAN_TRIED_BUCKET_SIZE 64 + +// total number of buckets for new addresses +#define ADDRMAN_NEW_BUCKET_COUNT 256 + +// maximum allowed number of entries in buckets for new addresses +#define ADDRMAN_NEW_BUCKET_SIZE 64 + +// over how many buckets entries with tried addresses from a single group (/16 for IPv4) are spread +#define ADDRMAN_TRIED_BUCKETS_PER_GROUP 4 + +// over how many buckets entries with new addresses originating from a single group are spread +#define ADDRMAN_NEW_BUCKETS_PER_SOURCE_GROUP 32 + +// in how many buckets for entries with new addresses a single address may occur +#define ADDRMAN_NEW_BUCKETS_PER_ADDRESS 4 + +// how many entries in a bucket with tried addresses are inspected, when selecting one to replace +#define ADDRMAN_TRIED_ENTRIES_INSPECT_ON_EVICT 4 + +// how old addresses can maximally be +#define ADDRMAN_HORIZON_DAYS 30 + +// after how many failed attempts we give up on a new node +#define ADDRMAN_RETRIES 3 + +// how many successive failures are allowed ... +#define ADDRMAN_MAX_FAILURES 10 + +// ... in at least this many days +#define ADDRMAN_MIN_FAIL_DAYS 7 + +// the maximum percentage of nodes to return in a getaddr call +#define ADDRMAN_GETADDR_MAX_PCT 23 + +// the maximum number of nodes to return in a getaddr call +#define ADDRMAN_GETADDR_MAX 2500 + +/** Stochastical (IP) address manager */ +class CAddrMan +{ +private: + // critical section to protect the inner data structures + mutable CCriticalSection cs; + + // secret key to randomize bucket select with + std::vector nKey; + + // last used nId + int nIdCount; + + // table with information about all nIds + std::map mapInfo; + + // find an nId based on its network address + std::map mapAddr; + + // address verification tokens + std::map verificationToken; + + // address reconnect tokens + std::map reconnectToken; + + // randomly-ordered vector of all nIds + std::vector vRandom; + + // number of "tried" entries + int nTried; + + // list of "tried" buckets + std::vector > vvTried; + + // number of (unique) "new" entries + int nNew; + + // list of "new" buckets + std::vector > vvNew; + +protected: + + // Find an entry. + CAddrInfo* Find(const CNetAddr& addr, int *pnId = NULL); + + // find an entry, creating it if necessary. + // nTime and nServices of found node is updated, if necessary. + CAddrInfo* Create(const CAddress &addr, const CNetAddr &addrSource, int *pnId = NULL); + + // Swap two elements in vRandom. + void SwapRandom(unsigned int nRandomPos1, unsigned int nRandomPos2); + + // Return position in given bucket to replace. + int SelectTried(int nKBucket); + + // Remove an element from a "new" bucket. + // This is the only place where actual deletes occur. + // They are never deleted while in the "tried" table, only possibly evicted back to the "new" table. + int ShrinkNew(int nUBucket); + + // Move an entry from the "new" table(s) to the "tried" table + // @pre vvUnkown[nOrigin].count(nId) != 0 + void MakeTried(CAddrInfo& info, int nId, int nOrigin); + + // Mark an entry "good", possibly moving it from "new" to "tried". + void Good_(const CService &addr, int64 nTime); + + // Add an entry to the "new" table. + bool Add_(const CAddress &addr, const CNetAddr& source, int64 nTimePenalty); + + // Mark an entry as attempted to connect. + void Attempt_(const CService &addr, int64 nTime); + + // Select an address to connect to. + // nUnkBias determines how much to favor new addresses over tried ones (min=0, max=100) + CAddress Select_(int nUnkBias); + +#ifdef DEBUG_ADDRMAN + // Perform consistency check. Returns an error code or zero. + int Check_(); +#endif + + // Select several addresses at once. + void GetAddr_(std::vector &vAddr); + + // Mark an entry as currently-connected-to. + void Connected_(const CService &addr, int64 nTime); + +public: + + IMPLEMENT_SERIALIZE + (({ + // serialized format: + // * version byte (currently 0) + // * nKey + // * nNew + // * nTried + // * number of "new" buckets + // * all nNew addrinfos in vvNew + // * all nTried addrinfos in vvTried + // * for each bucket: + // * number of elements + // * for each element: index + // + // Notice that vvTried, mapAddr and vVector are never encoded explicitly; + // they are instead reconstructed from the other information. + // + // vvNew is serialized, but only used if ADDRMAN_UNKOWN_BUCKET_COUNT didn't change, + // otherwise it is reconstructed as well. + // + // This format is more complex, but significantly smaller (at most 1.5 MiB), and supports + // changes to the ADDRMAN_ parameters without breaking the on-disk structure. + { + LOCK(cs); + unsigned char nVersion = 0; + READWRITE(nVersion); + READWRITE(nKey); + READWRITE(nNew); + READWRITE(nTried); + + CAddrMan *am = const_cast(this); + if (fWrite) + { + int nUBuckets = ADDRMAN_NEW_BUCKET_COUNT; + READWRITE(nUBuckets); + std::map mapUnkIds; + int nIds = 0; + for (std::map::iterator it = am->mapInfo.begin(); it != am->mapInfo.end(); it++) + { + if (nIds == nNew) break; // this means nNew was wrong, oh ow + mapUnkIds[(*it).first] = nIds; + CAddrInfo &info = (*it).second; + if (info.nRefCount) + { + READWRITE(info); + nIds++; + } + } + nIds = 0; + for (std::map::iterator it = am->mapInfo.begin(); it != am->mapInfo.end(); it++) + { + if (nIds == nTried) break; // this means nTried was wrong, oh ow + CAddrInfo &info = (*it).second; + if (info.fInTried) + { + READWRITE(info); + nIds++; + } + } + for (std::vector >::iterator it = am->vvNew.begin(); it != am->vvNew.end(); it++) + { + const std::set &vNew = (*it); + int nSize = vNew.size(); + READWRITE(nSize); + for (std::set::iterator it2 = vNew.begin(); it2 != vNew.end(); it2++) + { + int nIndex = mapUnkIds[*it2]; + READWRITE(nIndex); + } + } + } else { + int nUBuckets = 0; + READWRITE(nUBuckets); + am->nIdCount = 0; + am->mapInfo.clear(); + am->mapAddr.clear(); + am->vRandom.clear(); + am->vvTried = std::vector >(ADDRMAN_TRIED_BUCKET_COUNT, std::vector(0)); + am->vvNew = std::vector >(ADDRMAN_NEW_BUCKET_COUNT, std::set()); + for (int n = 0; n < am->nNew; n++) + { + CAddrInfo &info = am->mapInfo[n]; + READWRITE(info); + am->mapAddr[info] = n; + info.nRandomPos = vRandom.size(); + am->vRandom.push_back(n); + if (nUBuckets != ADDRMAN_NEW_BUCKET_COUNT) + { + am->vvNew[info.GetNewBucket(am->nKey)].insert(n); + info.nRefCount++; + } + } + am->nIdCount = am->nNew; + int nLost = 0; + for (int n = 0; n < am->nTried; n++) + { + CAddrInfo info; + READWRITE(info); + std::vector &vTried = am->vvTried[info.GetTriedBucket(am->nKey)]; + if (vTried.size() < ADDRMAN_TRIED_BUCKET_SIZE) + { + info.nRandomPos = vRandom.size(); + info.fInTried = true; + am->vRandom.push_back(am->nIdCount); + am->mapInfo[am->nIdCount] = info; + am->mapAddr[info] = am->nIdCount; + vTried.push_back(am->nIdCount); + am->nIdCount++; + } else { + nLost++; + } + } + am->nTried -= nLost; + for (int b = 0; b < nUBuckets; b++) + { + std::set &vNew = am->vvNew[b]; + int nSize = 0; + READWRITE(nSize); + for (int n = 0; n < nSize; n++) + { + int nIndex = 0; + READWRITE(nIndex); + CAddrInfo &info = am->mapInfo[nIndex]; + if (nUBuckets == ADDRMAN_NEW_BUCKET_COUNT && info.nRefCount < ADDRMAN_NEW_BUCKETS_PER_ADDRESS) + { + info.nRefCount++; + vNew.insert(nIndex); + } + } + } + } + } + });) + + CAddrMan() : vRandom(0), vvTried(ADDRMAN_TRIED_BUCKET_COUNT, std::vector(0)), vvNew(ADDRMAN_NEW_BUCKET_COUNT, std::set()) + { + nKey.resize(32); + RAND_bytes(&nKey[0], 32); + + nIdCount = 0; + nTried = 0; + nNew = 0; + } + + // Return the number of (unique) addresses in all tables. + int size() + { + return vRandom.size(); + } + + // Consistency check + void Check() + { +#ifdef DEBUG_ADDRMAN + { + LOCK(cs); + int err; + if ((err=Check_())) + printf("ADDRMAN CONSISTENCY CHECK FAILED!!! err=%i\n", err); + } +#endif + } + + // Add a single address. + bool Add(const CAddress &addr, const CNetAddr& source, int64 nTimePenalty = 0) + { + bool fRet = false; + { + LOCK(cs); + Check(); + fRet |= Add_(addr, source, nTimePenalty); + Check(); + } + if (fRet) + printf("Added %s from %s: %i tried, %i new\n", addr.ToStringIPPort().c_str(), source.ToString().c_str(), nTried, nNew); + return fRet; + } + + // Add multiple addresses. + bool Add(const std::vector &vAddr, const CNetAddr& source, int64 nTimePenalty = 0) + { + int nAdd = 0; + { + LOCK(cs); + Check(); + for (std::vector::const_iterator it = vAddr.begin(); it != vAddr.end(); it++) + nAdd += Add_(*it, source, nTimePenalty) ? 1 : 0; + Check(); + } + if (nAdd) + printf("Added %i addresses from %s: %i tried, %i new\n", nAdd, source.ToString().c_str(), nTried, nNew); + return nAdd > 0; + } + + // Mark an entry as accessible. + void Good(const CService &addr, int64 nTime = GetAdjustedTime()) + { + { + LOCK(cs); + Check(); + Good_(addr, nTime); + Check(); + } + } + + // Mark an entry as connection attempted to. + void Attempt(const CService &addr, int64 nTime = GetAdjustedTime()) + { + { + LOCK(cs); + Check(); + Attempt_(addr, nTime); + Check(); + } + } + + void SetReconnectToken(const CNetAddr &addr, uint64 reconnect_token) + { + { + LOCK(cs); + Check(); + reconnectToken[addr] = reconnect_token; + Check(); + } + } + + bool GetReconnectToken(const CNetAddr &addr, uint64& reconnect_token) + { + bool result = false; + { + LOCK(cs); + Check(); + std::map< + CNetAddr, + uint64 + >::const_iterator found = reconnectToken.find( + addr + ); + if ( + reconnectToken.end() != found + ) { + reconnect_token = found->second; + result = true; + } + Check(); + } + return result; + } + + void SetVerificationToken(const CNetAddr &addr, uint64 verification_token) + { + { + LOCK(cs); + Check(); + verificationToken[addr] = verification_token; + Check(); + } + } + + bool CheckVerificationToken(const CNetAddr &addr, uint64 verification_token) + { + bool result = false; + { + LOCK(cs); + Check(); + std::map< + CNetAddr, + uint64 + >::const_iterator found = verificationToken.find( + addr + ); + if ( + verificationToken.end() != found + ) { + result = verification_token == found->second; + } + Check(); + } + return result; + } + + // Choose an address to connect to. + // nUnkBias determines how much "new" entries are favored over "tried" ones (0-100). + CAddress Select(int nUnkBias = 50) + { + CAddress addrRet; + { + LOCK(cs); + Check(); + addrRet = Select_(nUnkBias); + Check(); + } + return addrRet; + } + + // Return a bunch of addresses, selected at random. + std::vector GetAddr() + { + Check(); + std::vector vAddr; + { + LOCK(cs); + GetAddr_(vAddr); + } + Check(); + return vAddr; + } + + // Mark an entry as currently-connected-to. + void Connected(const CService &addr, int64 nTime = GetAdjustedTime()) + { + { + LOCK(cs); + Check(); + Connected_(addr, nTime); + Check(); + } + } +}; + +#endif diff --git a/src/aes_helper.c b/src/aes_helper.c new file mode 100644 index 0000000..75b7cc6 --- /dev/null +++ b/src/aes_helper.c @@ -0,0 +1,392 @@ +/* $Id: aes_helper.c 220 2010-06-09 09:21:50Z tp $ */ +/* + * AES tables. This file is not meant to be compiled by itself; it + * is included by some hash function implementations. It contains + * the precomputed tables and helper macros for evaluating an AES + * round, optionally with a final XOR with a subkey. + * + * By default, this file defines the tables and macros for little-endian + * processing (i.e. it is assumed that the input bytes have been read + * from memory and assembled with the little-endian convention). If + * the 'AES_BIG_ENDIAN' macro is defined (to a non-zero integer value) + * when this file is included, then the tables and macros for big-endian + * processing are defined instead. The big-endian tables and macros have + * names distinct from the little-endian tables and macros, hence it is + * possible to have both simultaneously, by including this file twice + * (with and without the AES_BIG_ENDIAN macro). + * + * ==========================(LICENSE BEGIN)============================ + * + * Copyright (c) 2007-2010 Projet RNRT SAPHIR + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * ===========================(LICENSE END)============================= + * + * @author Thomas Pornin + */ + +#include "sph_types.h" +#ifdef __cplusplus +extern "C"{ +#endif +#if AES_BIG_ENDIAN + +#define AESx(x) ( ((SPH_C32(x) >> 24) & SPH_C32(0x000000FF)) \ + | ((SPH_C32(x) >> 8) & SPH_C32(0x0000FF00)) \ + | ((SPH_C32(x) << 8) & SPH_C32(0x00FF0000)) \ + | ((SPH_C32(x) << 24) & SPH_C32(0xFF000000))) + +#define AES0 AES0_BE +#define AES1 AES1_BE +#define AES2 AES2_BE +#define AES3 AES3_BE + +#define AES_ROUND_BE(X0, X1, X2, X3, K0, K1, K2, K3, Y0, Y1, Y2, Y3) do { \ + (Y0) = AES0[((X0) >> 24) & 0xFF] \ + ^ AES1[((X1) >> 16) & 0xFF] \ + ^ AES2[((X2) >> 8) & 0xFF] \ + ^ AES3[(X3) & 0xFF] ^ (K0); \ + (Y1) = AES0[((X1) >> 24) & 0xFF] \ + ^ AES1[((X2) >> 16) & 0xFF] \ + ^ AES2[((X3) >> 8) & 0xFF] \ + ^ AES3[(X0) & 0xFF] ^ (K1); \ + (Y2) = AES0[((X2) >> 24) & 0xFF] \ + ^ AES1[((X3) >> 16) & 0xFF] \ + ^ AES2[((X0) >> 8) & 0xFF] \ + ^ AES3[(X1) & 0xFF] ^ (K2); \ + (Y3) = AES0[((X3) >> 24) & 0xFF] \ + ^ AES1[((X0) >> 16) & 0xFF] \ + ^ AES2[((X1) >> 8) & 0xFF] \ + ^ AES3[(X2) & 0xFF] ^ (K3); \ + } while (0) + +#define AES_ROUND_NOKEY_BE(X0, X1, X2, X3, Y0, Y1, Y2, Y3) \ + AES_ROUND_BE(X0, X1, X2, X3, 0, 0, 0, 0, Y0, Y1, Y2, Y3) + +#else + +#define AESx(x) SPH_C32(x) +#define AES0 AES0_LE +#define AES1 AES1_LE +#define AES2 AES2_LE +#define AES3 AES3_LE + +#define AES_ROUND_LE(X0, X1, X2, X3, K0, K1, K2, K3, Y0, Y1, Y2, Y3) do { \ + (Y0) = AES0[(X0) & 0xFF] \ + ^ AES1[((X1) >> 8) & 0xFF] \ + ^ AES2[((X2) >> 16) & 0xFF] \ + ^ AES3[((X3) >> 24) & 0xFF] ^ (K0); \ + (Y1) = AES0[(X1) & 0xFF] \ + ^ AES1[((X2) >> 8) & 0xFF] \ + ^ AES2[((X3) >> 16) & 0xFF] \ + ^ AES3[((X0) >> 24) & 0xFF] ^ (K1); \ + (Y2) = AES0[(X2) & 0xFF] \ + ^ AES1[((X3) >> 8) & 0xFF] \ + ^ AES2[((X0) >> 16) & 0xFF] \ + ^ AES3[((X1) >> 24) & 0xFF] ^ (K2); \ + (Y3) = AES0[(X3) & 0xFF] \ + ^ AES1[((X0) >> 8) & 0xFF] \ + ^ AES2[((X1) >> 16) & 0xFF] \ + ^ AES3[((X2) >> 24) & 0xFF] ^ (K3); \ + } while (0) + +#define AES_ROUND_NOKEY_LE(X0, X1, X2, X3, Y0, Y1, Y2, Y3) \ + AES_ROUND_LE(X0, X1, X2, X3, 0, 0, 0, 0, Y0, Y1, Y2, Y3) + +#endif + +/* + * The AES*[] tables allow us to perform a fast evaluation of an AES + * round; table AESi[] combines SubBytes for a byte at row i, and + * MixColumns for the column where that byte goes after ShiftRows. + */ + +static const sph_u32 AES0[256] = { + AESx(0xA56363C6), AESx(0x847C7CF8), AESx(0x997777EE), AESx(0x8D7B7BF6), + AESx(0x0DF2F2FF), AESx(0xBD6B6BD6), AESx(0xB16F6FDE), AESx(0x54C5C591), + AESx(0x50303060), AESx(0x03010102), AESx(0xA96767CE), AESx(0x7D2B2B56), + AESx(0x19FEFEE7), AESx(0x62D7D7B5), AESx(0xE6ABAB4D), AESx(0x9A7676EC), + AESx(0x45CACA8F), AESx(0x9D82821F), AESx(0x40C9C989), AESx(0x877D7DFA), + AESx(0x15FAFAEF), AESx(0xEB5959B2), AESx(0xC947478E), AESx(0x0BF0F0FB), + AESx(0xECADAD41), AESx(0x67D4D4B3), AESx(0xFDA2A25F), AESx(0xEAAFAF45), + AESx(0xBF9C9C23), AESx(0xF7A4A453), AESx(0x967272E4), AESx(0x5BC0C09B), + AESx(0xC2B7B775), AESx(0x1CFDFDE1), AESx(0xAE93933D), AESx(0x6A26264C), + AESx(0x5A36366C), AESx(0x413F3F7E), AESx(0x02F7F7F5), AESx(0x4FCCCC83), + AESx(0x5C343468), AESx(0xF4A5A551), AESx(0x34E5E5D1), AESx(0x08F1F1F9), + AESx(0x937171E2), AESx(0x73D8D8AB), AESx(0x53313162), AESx(0x3F15152A), + AESx(0x0C040408), AESx(0x52C7C795), AESx(0x65232346), AESx(0x5EC3C39D), + AESx(0x28181830), AESx(0xA1969637), AESx(0x0F05050A), AESx(0xB59A9A2F), + AESx(0x0907070E), AESx(0x36121224), AESx(0x9B80801B), AESx(0x3DE2E2DF), + AESx(0x26EBEBCD), AESx(0x6927274E), AESx(0xCDB2B27F), AESx(0x9F7575EA), + AESx(0x1B090912), AESx(0x9E83831D), AESx(0x742C2C58), AESx(0x2E1A1A34), + AESx(0x2D1B1B36), AESx(0xB26E6EDC), AESx(0xEE5A5AB4), AESx(0xFBA0A05B), + AESx(0xF65252A4), AESx(0x4D3B3B76), AESx(0x61D6D6B7), AESx(0xCEB3B37D), + AESx(0x7B292952), AESx(0x3EE3E3DD), AESx(0x712F2F5E), AESx(0x97848413), + AESx(0xF55353A6), AESx(0x68D1D1B9), AESx(0x00000000), AESx(0x2CEDEDC1), + AESx(0x60202040), AESx(0x1FFCFCE3), AESx(0xC8B1B179), AESx(0xED5B5BB6), + AESx(0xBE6A6AD4), AESx(0x46CBCB8D), AESx(0xD9BEBE67), AESx(0x4B393972), + AESx(0xDE4A4A94), AESx(0xD44C4C98), AESx(0xE85858B0), AESx(0x4ACFCF85), + AESx(0x6BD0D0BB), AESx(0x2AEFEFC5), AESx(0xE5AAAA4F), AESx(0x16FBFBED), + AESx(0xC5434386), AESx(0xD74D4D9A), AESx(0x55333366), AESx(0x94858511), + AESx(0xCF45458A), AESx(0x10F9F9E9), AESx(0x06020204), AESx(0x817F7FFE), + AESx(0xF05050A0), AESx(0x443C3C78), AESx(0xBA9F9F25), AESx(0xE3A8A84B), + AESx(0xF35151A2), AESx(0xFEA3A35D), AESx(0xC0404080), AESx(0x8A8F8F05), + AESx(0xAD92923F), AESx(0xBC9D9D21), AESx(0x48383870), AESx(0x04F5F5F1), + AESx(0xDFBCBC63), AESx(0xC1B6B677), AESx(0x75DADAAF), AESx(0x63212142), + AESx(0x30101020), AESx(0x1AFFFFE5), AESx(0x0EF3F3FD), AESx(0x6DD2D2BF), + AESx(0x4CCDCD81), AESx(0x140C0C18), AESx(0x35131326), AESx(0x2FECECC3), + AESx(0xE15F5FBE), AESx(0xA2979735), AESx(0xCC444488), AESx(0x3917172E), + AESx(0x57C4C493), AESx(0xF2A7A755), AESx(0x827E7EFC), AESx(0x473D3D7A), + AESx(0xAC6464C8), AESx(0xE75D5DBA), AESx(0x2B191932), AESx(0x957373E6), + AESx(0xA06060C0), AESx(0x98818119), AESx(0xD14F4F9E), AESx(0x7FDCDCA3), + AESx(0x66222244), AESx(0x7E2A2A54), AESx(0xAB90903B), AESx(0x8388880B), + AESx(0xCA46468C), AESx(0x29EEEEC7), AESx(0xD3B8B86B), AESx(0x3C141428), + AESx(0x79DEDEA7), AESx(0xE25E5EBC), AESx(0x1D0B0B16), AESx(0x76DBDBAD), + AESx(0x3BE0E0DB), AESx(0x56323264), AESx(0x4E3A3A74), AESx(0x1E0A0A14), + AESx(0xDB494992), AESx(0x0A06060C), AESx(0x6C242448), AESx(0xE45C5CB8), + AESx(0x5DC2C29F), AESx(0x6ED3D3BD), AESx(0xEFACAC43), AESx(0xA66262C4), + AESx(0xA8919139), AESx(0xA4959531), AESx(0x37E4E4D3), AESx(0x8B7979F2), + AESx(0x32E7E7D5), AESx(0x43C8C88B), AESx(0x5937376E), AESx(0xB76D6DDA), + AESx(0x8C8D8D01), AESx(0x64D5D5B1), AESx(0xD24E4E9C), AESx(0xE0A9A949), + AESx(0xB46C6CD8), AESx(0xFA5656AC), AESx(0x07F4F4F3), AESx(0x25EAEACF), + AESx(0xAF6565CA), AESx(0x8E7A7AF4), AESx(0xE9AEAE47), AESx(0x18080810), + AESx(0xD5BABA6F), AESx(0x887878F0), AESx(0x6F25254A), AESx(0x722E2E5C), + AESx(0x241C1C38), AESx(0xF1A6A657), AESx(0xC7B4B473), AESx(0x51C6C697), + AESx(0x23E8E8CB), AESx(0x7CDDDDA1), AESx(0x9C7474E8), AESx(0x211F1F3E), + AESx(0xDD4B4B96), AESx(0xDCBDBD61), AESx(0x868B8B0D), AESx(0x858A8A0F), + AESx(0x907070E0), AESx(0x423E3E7C), AESx(0xC4B5B571), AESx(0xAA6666CC), + AESx(0xD8484890), AESx(0x05030306), AESx(0x01F6F6F7), AESx(0x120E0E1C), + AESx(0xA36161C2), AESx(0x5F35356A), AESx(0xF95757AE), AESx(0xD0B9B969), + AESx(0x91868617), AESx(0x58C1C199), AESx(0x271D1D3A), AESx(0xB99E9E27), + AESx(0x38E1E1D9), AESx(0x13F8F8EB), AESx(0xB398982B), AESx(0x33111122), + AESx(0xBB6969D2), AESx(0x70D9D9A9), AESx(0x898E8E07), AESx(0xA7949433), + AESx(0xB69B9B2D), AESx(0x221E1E3C), AESx(0x92878715), AESx(0x20E9E9C9), + AESx(0x49CECE87), AESx(0xFF5555AA), AESx(0x78282850), AESx(0x7ADFDFA5), + AESx(0x8F8C8C03), AESx(0xF8A1A159), AESx(0x80898909), AESx(0x170D0D1A), + AESx(0xDABFBF65), AESx(0x31E6E6D7), AESx(0xC6424284), AESx(0xB86868D0), + AESx(0xC3414182), AESx(0xB0999929), AESx(0x772D2D5A), AESx(0x110F0F1E), + AESx(0xCBB0B07B), AESx(0xFC5454A8), AESx(0xD6BBBB6D), AESx(0x3A16162C) +}; + +static const sph_u32 AES1[256] = { + AESx(0x6363C6A5), AESx(0x7C7CF884), AESx(0x7777EE99), AESx(0x7B7BF68D), + AESx(0xF2F2FF0D), AESx(0x6B6BD6BD), AESx(0x6F6FDEB1), AESx(0xC5C59154), + AESx(0x30306050), AESx(0x01010203), AESx(0x6767CEA9), AESx(0x2B2B567D), + AESx(0xFEFEE719), AESx(0xD7D7B562), AESx(0xABAB4DE6), AESx(0x7676EC9A), + AESx(0xCACA8F45), AESx(0x82821F9D), AESx(0xC9C98940), AESx(0x7D7DFA87), + AESx(0xFAFAEF15), AESx(0x5959B2EB), AESx(0x47478EC9), AESx(0xF0F0FB0B), + AESx(0xADAD41EC), AESx(0xD4D4B367), AESx(0xA2A25FFD), AESx(0xAFAF45EA), + AESx(0x9C9C23BF), AESx(0xA4A453F7), AESx(0x7272E496), AESx(0xC0C09B5B), + AESx(0xB7B775C2), AESx(0xFDFDE11C), AESx(0x93933DAE), AESx(0x26264C6A), + AESx(0x36366C5A), AESx(0x3F3F7E41), AESx(0xF7F7F502), AESx(0xCCCC834F), + AESx(0x3434685C), AESx(0xA5A551F4), AESx(0xE5E5D134), AESx(0xF1F1F908), + AESx(0x7171E293), AESx(0xD8D8AB73), AESx(0x31316253), AESx(0x15152A3F), + AESx(0x0404080C), AESx(0xC7C79552), AESx(0x23234665), AESx(0xC3C39D5E), + AESx(0x18183028), AESx(0x969637A1), AESx(0x05050A0F), AESx(0x9A9A2FB5), + AESx(0x07070E09), AESx(0x12122436), AESx(0x80801B9B), AESx(0xE2E2DF3D), + AESx(0xEBEBCD26), AESx(0x27274E69), AESx(0xB2B27FCD), AESx(0x7575EA9F), + AESx(0x0909121B), AESx(0x83831D9E), AESx(0x2C2C5874), AESx(0x1A1A342E), + AESx(0x1B1B362D), AESx(0x6E6EDCB2), AESx(0x5A5AB4EE), AESx(0xA0A05BFB), + AESx(0x5252A4F6), AESx(0x3B3B764D), AESx(0xD6D6B761), AESx(0xB3B37DCE), + AESx(0x2929527B), AESx(0xE3E3DD3E), AESx(0x2F2F5E71), AESx(0x84841397), + AESx(0x5353A6F5), AESx(0xD1D1B968), AESx(0x00000000), AESx(0xEDEDC12C), + AESx(0x20204060), AESx(0xFCFCE31F), AESx(0xB1B179C8), AESx(0x5B5BB6ED), + AESx(0x6A6AD4BE), AESx(0xCBCB8D46), AESx(0xBEBE67D9), AESx(0x3939724B), + AESx(0x4A4A94DE), AESx(0x4C4C98D4), AESx(0x5858B0E8), AESx(0xCFCF854A), + AESx(0xD0D0BB6B), AESx(0xEFEFC52A), AESx(0xAAAA4FE5), AESx(0xFBFBED16), + AESx(0x434386C5), AESx(0x4D4D9AD7), AESx(0x33336655), AESx(0x85851194), + AESx(0x45458ACF), AESx(0xF9F9E910), AESx(0x02020406), AESx(0x7F7FFE81), + AESx(0x5050A0F0), AESx(0x3C3C7844), AESx(0x9F9F25BA), AESx(0xA8A84BE3), + AESx(0x5151A2F3), AESx(0xA3A35DFE), AESx(0x404080C0), AESx(0x8F8F058A), + AESx(0x92923FAD), AESx(0x9D9D21BC), AESx(0x38387048), AESx(0xF5F5F104), + AESx(0xBCBC63DF), AESx(0xB6B677C1), AESx(0xDADAAF75), AESx(0x21214263), + AESx(0x10102030), AESx(0xFFFFE51A), AESx(0xF3F3FD0E), AESx(0xD2D2BF6D), + AESx(0xCDCD814C), AESx(0x0C0C1814), AESx(0x13132635), AESx(0xECECC32F), + AESx(0x5F5FBEE1), AESx(0x979735A2), AESx(0x444488CC), AESx(0x17172E39), + AESx(0xC4C49357), AESx(0xA7A755F2), AESx(0x7E7EFC82), AESx(0x3D3D7A47), + AESx(0x6464C8AC), AESx(0x5D5DBAE7), AESx(0x1919322B), AESx(0x7373E695), + AESx(0x6060C0A0), AESx(0x81811998), AESx(0x4F4F9ED1), AESx(0xDCDCA37F), + AESx(0x22224466), AESx(0x2A2A547E), AESx(0x90903BAB), AESx(0x88880B83), + AESx(0x46468CCA), AESx(0xEEEEC729), AESx(0xB8B86BD3), AESx(0x1414283C), + AESx(0xDEDEA779), AESx(0x5E5EBCE2), AESx(0x0B0B161D), AESx(0xDBDBAD76), + AESx(0xE0E0DB3B), AESx(0x32326456), AESx(0x3A3A744E), AESx(0x0A0A141E), + AESx(0x494992DB), AESx(0x06060C0A), AESx(0x2424486C), AESx(0x5C5CB8E4), + AESx(0xC2C29F5D), AESx(0xD3D3BD6E), AESx(0xACAC43EF), AESx(0x6262C4A6), + AESx(0x919139A8), AESx(0x959531A4), AESx(0xE4E4D337), AESx(0x7979F28B), + AESx(0xE7E7D532), AESx(0xC8C88B43), AESx(0x37376E59), AESx(0x6D6DDAB7), + AESx(0x8D8D018C), AESx(0xD5D5B164), AESx(0x4E4E9CD2), AESx(0xA9A949E0), + AESx(0x6C6CD8B4), AESx(0x5656ACFA), AESx(0xF4F4F307), AESx(0xEAEACF25), + AESx(0x6565CAAF), AESx(0x7A7AF48E), AESx(0xAEAE47E9), AESx(0x08081018), + AESx(0xBABA6FD5), AESx(0x7878F088), AESx(0x25254A6F), AESx(0x2E2E5C72), + AESx(0x1C1C3824), AESx(0xA6A657F1), AESx(0xB4B473C7), AESx(0xC6C69751), + AESx(0xE8E8CB23), AESx(0xDDDDA17C), AESx(0x7474E89C), AESx(0x1F1F3E21), + AESx(0x4B4B96DD), AESx(0xBDBD61DC), AESx(0x8B8B0D86), AESx(0x8A8A0F85), + AESx(0x7070E090), AESx(0x3E3E7C42), AESx(0xB5B571C4), AESx(0x6666CCAA), + AESx(0x484890D8), AESx(0x03030605), AESx(0xF6F6F701), AESx(0x0E0E1C12), + AESx(0x6161C2A3), AESx(0x35356A5F), AESx(0x5757AEF9), AESx(0xB9B969D0), + AESx(0x86861791), AESx(0xC1C19958), AESx(0x1D1D3A27), AESx(0x9E9E27B9), + AESx(0xE1E1D938), AESx(0xF8F8EB13), AESx(0x98982BB3), AESx(0x11112233), + AESx(0x6969D2BB), AESx(0xD9D9A970), AESx(0x8E8E0789), AESx(0x949433A7), + AESx(0x9B9B2DB6), AESx(0x1E1E3C22), AESx(0x87871592), AESx(0xE9E9C920), + AESx(0xCECE8749), AESx(0x5555AAFF), AESx(0x28285078), AESx(0xDFDFA57A), + AESx(0x8C8C038F), AESx(0xA1A159F8), AESx(0x89890980), AESx(0x0D0D1A17), + AESx(0xBFBF65DA), AESx(0xE6E6D731), AESx(0x424284C6), AESx(0x6868D0B8), + AESx(0x414182C3), AESx(0x999929B0), AESx(0x2D2D5A77), AESx(0x0F0F1E11), + AESx(0xB0B07BCB), AESx(0x5454A8FC), AESx(0xBBBB6DD6), AESx(0x16162C3A) +}; + +static const sph_u32 AES2[256] = { + AESx(0x63C6A563), AESx(0x7CF8847C), AESx(0x77EE9977), AESx(0x7BF68D7B), + AESx(0xF2FF0DF2), AESx(0x6BD6BD6B), AESx(0x6FDEB16F), AESx(0xC59154C5), + AESx(0x30605030), AESx(0x01020301), AESx(0x67CEA967), AESx(0x2B567D2B), + AESx(0xFEE719FE), AESx(0xD7B562D7), AESx(0xAB4DE6AB), AESx(0x76EC9A76), + AESx(0xCA8F45CA), AESx(0x821F9D82), AESx(0xC98940C9), AESx(0x7DFA877D), + AESx(0xFAEF15FA), AESx(0x59B2EB59), AESx(0x478EC947), AESx(0xF0FB0BF0), + AESx(0xAD41ECAD), AESx(0xD4B367D4), AESx(0xA25FFDA2), AESx(0xAF45EAAF), + AESx(0x9C23BF9C), AESx(0xA453F7A4), AESx(0x72E49672), AESx(0xC09B5BC0), + AESx(0xB775C2B7), AESx(0xFDE11CFD), AESx(0x933DAE93), AESx(0x264C6A26), + AESx(0x366C5A36), AESx(0x3F7E413F), AESx(0xF7F502F7), AESx(0xCC834FCC), + AESx(0x34685C34), AESx(0xA551F4A5), AESx(0xE5D134E5), AESx(0xF1F908F1), + AESx(0x71E29371), AESx(0xD8AB73D8), AESx(0x31625331), AESx(0x152A3F15), + AESx(0x04080C04), AESx(0xC79552C7), AESx(0x23466523), AESx(0xC39D5EC3), + AESx(0x18302818), AESx(0x9637A196), AESx(0x050A0F05), AESx(0x9A2FB59A), + AESx(0x070E0907), AESx(0x12243612), AESx(0x801B9B80), AESx(0xE2DF3DE2), + AESx(0xEBCD26EB), AESx(0x274E6927), AESx(0xB27FCDB2), AESx(0x75EA9F75), + AESx(0x09121B09), AESx(0x831D9E83), AESx(0x2C58742C), AESx(0x1A342E1A), + AESx(0x1B362D1B), AESx(0x6EDCB26E), AESx(0x5AB4EE5A), AESx(0xA05BFBA0), + AESx(0x52A4F652), AESx(0x3B764D3B), AESx(0xD6B761D6), AESx(0xB37DCEB3), + AESx(0x29527B29), AESx(0xE3DD3EE3), AESx(0x2F5E712F), AESx(0x84139784), + AESx(0x53A6F553), AESx(0xD1B968D1), AESx(0x00000000), AESx(0xEDC12CED), + AESx(0x20406020), AESx(0xFCE31FFC), AESx(0xB179C8B1), AESx(0x5BB6ED5B), + AESx(0x6AD4BE6A), AESx(0xCB8D46CB), AESx(0xBE67D9BE), AESx(0x39724B39), + AESx(0x4A94DE4A), AESx(0x4C98D44C), AESx(0x58B0E858), AESx(0xCF854ACF), + AESx(0xD0BB6BD0), AESx(0xEFC52AEF), AESx(0xAA4FE5AA), AESx(0xFBED16FB), + AESx(0x4386C543), AESx(0x4D9AD74D), AESx(0x33665533), AESx(0x85119485), + AESx(0x458ACF45), AESx(0xF9E910F9), AESx(0x02040602), AESx(0x7FFE817F), + AESx(0x50A0F050), AESx(0x3C78443C), AESx(0x9F25BA9F), AESx(0xA84BE3A8), + AESx(0x51A2F351), AESx(0xA35DFEA3), AESx(0x4080C040), AESx(0x8F058A8F), + AESx(0x923FAD92), AESx(0x9D21BC9D), AESx(0x38704838), AESx(0xF5F104F5), + AESx(0xBC63DFBC), AESx(0xB677C1B6), AESx(0xDAAF75DA), AESx(0x21426321), + AESx(0x10203010), AESx(0xFFE51AFF), AESx(0xF3FD0EF3), AESx(0xD2BF6DD2), + AESx(0xCD814CCD), AESx(0x0C18140C), AESx(0x13263513), AESx(0xECC32FEC), + AESx(0x5FBEE15F), AESx(0x9735A297), AESx(0x4488CC44), AESx(0x172E3917), + AESx(0xC49357C4), AESx(0xA755F2A7), AESx(0x7EFC827E), AESx(0x3D7A473D), + AESx(0x64C8AC64), AESx(0x5DBAE75D), AESx(0x19322B19), AESx(0x73E69573), + AESx(0x60C0A060), AESx(0x81199881), AESx(0x4F9ED14F), AESx(0xDCA37FDC), + AESx(0x22446622), AESx(0x2A547E2A), AESx(0x903BAB90), AESx(0x880B8388), + AESx(0x468CCA46), AESx(0xEEC729EE), AESx(0xB86BD3B8), AESx(0x14283C14), + AESx(0xDEA779DE), AESx(0x5EBCE25E), AESx(0x0B161D0B), AESx(0xDBAD76DB), + AESx(0xE0DB3BE0), AESx(0x32645632), AESx(0x3A744E3A), AESx(0x0A141E0A), + AESx(0x4992DB49), AESx(0x060C0A06), AESx(0x24486C24), AESx(0x5CB8E45C), + AESx(0xC29F5DC2), AESx(0xD3BD6ED3), AESx(0xAC43EFAC), AESx(0x62C4A662), + AESx(0x9139A891), AESx(0x9531A495), AESx(0xE4D337E4), AESx(0x79F28B79), + AESx(0xE7D532E7), AESx(0xC88B43C8), AESx(0x376E5937), AESx(0x6DDAB76D), + AESx(0x8D018C8D), AESx(0xD5B164D5), AESx(0x4E9CD24E), AESx(0xA949E0A9), + AESx(0x6CD8B46C), AESx(0x56ACFA56), AESx(0xF4F307F4), AESx(0xEACF25EA), + AESx(0x65CAAF65), AESx(0x7AF48E7A), AESx(0xAE47E9AE), AESx(0x08101808), + AESx(0xBA6FD5BA), AESx(0x78F08878), AESx(0x254A6F25), AESx(0x2E5C722E), + AESx(0x1C38241C), AESx(0xA657F1A6), AESx(0xB473C7B4), AESx(0xC69751C6), + AESx(0xE8CB23E8), AESx(0xDDA17CDD), AESx(0x74E89C74), AESx(0x1F3E211F), + AESx(0x4B96DD4B), AESx(0xBD61DCBD), AESx(0x8B0D868B), AESx(0x8A0F858A), + AESx(0x70E09070), AESx(0x3E7C423E), AESx(0xB571C4B5), AESx(0x66CCAA66), + AESx(0x4890D848), AESx(0x03060503), AESx(0xF6F701F6), AESx(0x0E1C120E), + AESx(0x61C2A361), AESx(0x356A5F35), AESx(0x57AEF957), AESx(0xB969D0B9), + AESx(0x86179186), AESx(0xC19958C1), AESx(0x1D3A271D), AESx(0x9E27B99E), + AESx(0xE1D938E1), AESx(0xF8EB13F8), AESx(0x982BB398), AESx(0x11223311), + AESx(0x69D2BB69), AESx(0xD9A970D9), AESx(0x8E07898E), AESx(0x9433A794), + AESx(0x9B2DB69B), AESx(0x1E3C221E), AESx(0x87159287), AESx(0xE9C920E9), + AESx(0xCE8749CE), AESx(0x55AAFF55), AESx(0x28507828), AESx(0xDFA57ADF), + AESx(0x8C038F8C), AESx(0xA159F8A1), AESx(0x89098089), AESx(0x0D1A170D), + AESx(0xBF65DABF), AESx(0xE6D731E6), AESx(0x4284C642), AESx(0x68D0B868), + AESx(0x4182C341), AESx(0x9929B099), AESx(0x2D5A772D), AESx(0x0F1E110F), + AESx(0xB07BCBB0), AESx(0x54A8FC54), AESx(0xBB6DD6BB), AESx(0x162C3A16) +}; + +static const sph_u32 AES3[256] = { + AESx(0xC6A56363), AESx(0xF8847C7C), AESx(0xEE997777), AESx(0xF68D7B7B), + AESx(0xFF0DF2F2), AESx(0xD6BD6B6B), AESx(0xDEB16F6F), AESx(0x9154C5C5), + AESx(0x60503030), AESx(0x02030101), AESx(0xCEA96767), AESx(0x567D2B2B), + AESx(0xE719FEFE), AESx(0xB562D7D7), AESx(0x4DE6ABAB), AESx(0xEC9A7676), + AESx(0x8F45CACA), AESx(0x1F9D8282), AESx(0x8940C9C9), AESx(0xFA877D7D), + AESx(0xEF15FAFA), AESx(0xB2EB5959), AESx(0x8EC94747), AESx(0xFB0BF0F0), + AESx(0x41ECADAD), AESx(0xB367D4D4), AESx(0x5FFDA2A2), AESx(0x45EAAFAF), + AESx(0x23BF9C9C), AESx(0x53F7A4A4), AESx(0xE4967272), AESx(0x9B5BC0C0), + AESx(0x75C2B7B7), AESx(0xE11CFDFD), AESx(0x3DAE9393), AESx(0x4C6A2626), + AESx(0x6C5A3636), AESx(0x7E413F3F), AESx(0xF502F7F7), AESx(0x834FCCCC), + AESx(0x685C3434), AESx(0x51F4A5A5), AESx(0xD134E5E5), AESx(0xF908F1F1), + AESx(0xE2937171), AESx(0xAB73D8D8), AESx(0x62533131), AESx(0x2A3F1515), + AESx(0x080C0404), AESx(0x9552C7C7), AESx(0x46652323), AESx(0x9D5EC3C3), + AESx(0x30281818), AESx(0x37A19696), AESx(0x0A0F0505), AESx(0x2FB59A9A), + AESx(0x0E090707), AESx(0x24361212), AESx(0x1B9B8080), AESx(0xDF3DE2E2), + AESx(0xCD26EBEB), AESx(0x4E692727), AESx(0x7FCDB2B2), AESx(0xEA9F7575), + AESx(0x121B0909), AESx(0x1D9E8383), AESx(0x58742C2C), AESx(0x342E1A1A), + AESx(0x362D1B1B), AESx(0xDCB26E6E), AESx(0xB4EE5A5A), AESx(0x5BFBA0A0), + AESx(0xA4F65252), AESx(0x764D3B3B), AESx(0xB761D6D6), AESx(0x7DCEB3B3), + AESx(0x527B2929), AESx(0xDD3EE3E3), AESx(0x5E712F2F), AESx(0x13978484), + AESx(0xA6F55353), AESx(0xB968D1D1), AESx(0x00000000), AESx(0xC12CEDED), + AESx(0x40602020), AESx(0xE31FFCFC), AESx(0x79C8B1B1), AESx(0xB6ED5B5B), + AESx(0xD4BE6A6A), AESx(0x8D46CBCB), AESx(0x67D9BEBE), AESx(0x724B3939), + AESx(0x94DE4A4A), AESx(0x98D44C4C), AESx(0xB0E85858), AESx(0x854ACFCF), + AESx(0xBB6BD0D0), AESx(0xC52AEFEF), AESx(0x4FE5AAAA), AESx(0xED16FBFB), + AESx(0x86C54343), AESx(0x9AD74D4D), AESx(0x66553333), AESx(0x11948585), + AESx(0x8ACF4545), AESx(0xE910F9F9), AESx(0x04060202), AESx(0xFE817F7F), + AESx(0xA0F05050), AESx(0x78443C3C), AESx(0x25BA9F9F), AESx(0x4BE3A8A8), + AESx(0xA2F35151), AESx(0x5DFEA3A3), AESx(0x80C04040), AESx(0x058A8F8F), + AESx(0x3FAD9292), AESx(0x21BC9D9D), AESx(0x70483838), AESx(0xF104F5F5), + AESx(0x63DFBCBC), AESx(0x77C1B6B6), AESx(0xAF75DADA), AESx(0x42632121), + AESx(0x20301010), AESx(0xE51AFFFF), AESx(0xFD0EF3F3), AESx(0xBF6DD2D2), + AESx(0x814CCDCD), AESx(0x18140C0C), AESx(0x26351313), AESx(0xC32FECEC), + AESx(0xBEE15F5F), AESx(0x35A29797), AESx(0x88CC4444), AESx(0x2E391717), + AESx(0x9357C4C4), AESx(0x55F2A7A7), AESx(0xFC827E7E), AESx(0x7A473D3D), + AESx(0xC8AC6464), AESx(0xBAE75D5D), AESx(0x322B1919), AESx(0xE6957373), + AESx(0xC0A06060), AESx(0x19988181), AESx(0x9ED14F4F), AESx(0xA37FDCDC), + AESx(0x44662222), AESx(0x547E2A2A), AESx(0x3BAB9090), AESx(0x0B838888), + AESx(0x8CCA4646), AESx(0xC729EEEE), AESx(0x6BD3B8B8), AESx(0x283C1414), + AESx(0xA779DEDE), AESx(0xBCE25E5E), AESx(0x161D0B0B), AESx(0xAD76DBDB), + AESx(0xDB3BE0E0), AESx(0x64563232), AESx(0x744E3A3A), AESx(0x141E0A0A), + AESx(0x92DB4949), AESx(0x0C0A0606), AESx(0x486C2424), AESx(0xB8E45C5C), + AESx(0x9F5DC2C2), AESx(0xBD6ED3D3), AESx(0x43EFACAC), AESx(0xC4A66262), + AESx(0x39A89191), AESx(0x31A49595), AESx(0xD337E4E4), AESx(0xF28B7979), + AESx(0xD532E7E7), AESx(0x8B43C8C8), AESx(0x6E593737), AESx(0xDAB76D6D), + AESx(0x018C8D8D), AESx(0xB164D5D5), AESx(0x9CD24E4E), AESx(0x49E0A9A9), + AESx(0xD8B46C6C), AESx(0xACFA5656), AESx(0xF307F4F4), AESx(0xCF25EAEA), + AESx(0xCAAF6565), AESx(0xF48E7A7A), AESx(0x47E9AEAE), AESx(0x10180808), + AESx(0x6FD5BABA), AESx(0xF0887878), AESx(0x4A6F2525), AESx(0x5C722E2E), + AESx(0x38241C1C), AESx(0x57F1A6A6), AESx(0x73C7B4B4), AESx(0x9751C6C6), + AESx(0xCB23E8E8), AESx(0xA17CDDDD), AESx(0xE89C7474), AESx(0x3E211F1F), + AESx(0x96DD4B4B), AESx(0x61DCBDBD), AESx(0x0D868B8B), AESx(0x0F858A8A), + AESx(0xE0907070), AESx(0x7C423E3E), AESx(0x71C4B5B5), AESx(0xCCAA6666), + AESx(0x90D84848), AESx(0x06050303), AESx(0xF701F6F6), AESx(0x1C120E0E), + AESx(0xC2A36161), AESx(0x6A5F3535), AESx(0xAEF95757), AESx(0x69D0B9B9), + AESx(0x17918686), AESx(0x9958C1C1), AESx(0x3A271D1D), AESx(0x27B99E9E), + AESx(0xD938E1E1), AESx(0xEB13F8F8), AESx(0x2BB39898), AESx(0x22331111), + AESx(0xD2BB6969), AESx(0xA970D9D9), AESx(0x07898E8E), AESx(0x33A79494), + AESx(0x2DB69B9B), AESx(0x3C221E1E), AESx(0x15928787), AESx(0xC920E9E9), + AESx(0x8749CECE), AESx(0xAAFF5555), AESx(0x50782828), AESx(0xA57ADFDF), + AESx(0x038F8C8C), AESx(0x59F8A1A1), AESx(0x09808989), AESx(0x1A170D0D), + AESx(0x65DABFBF), AESx(0xD731E6E6), AESx(0x84C64242), AESx(0xD0B86868), + AESx(0x82C34141), AESx(0x29B09999), AESx(0x5A772D2D), AESx(0x1E110F0F), + AESx(0x7BCBB0B0), AESx(0xA8FC5454), AESx(0x6DD6BBBB), AESx(0x2C3A1616) +}; + +#ifdef __cplusplus +} +#endif diff --git a/src/alert.cpp b/src/alert.cpp new file mode 100644 index 0000000..437f21c --- /dev/null +++ b/src/alert.cpp @@ -0,0 +1,241 @@ +// +// Alert system +// + +#include +#include + +#include "alert.h" +#include "key.h" +#include "net.h" +#include "sync.h" +#include "ui_interface.h" + +using namespace std; + +map mapAlerts; +CCriticalSection cs_mapAlerts; + +static const char* pszMainKey = "a68b432b54018c4b1f653c2dbe0d3507b6b3939af8e97fdbee543dee3fd64bf590404330cf0c0e76bb8591011dcb61ad4f28c48940a09db1f3588e35827c89c09a"; + +// TestNet alerts pubKey +static const char* pszTestKey = "a68b432b54018c4b1f653c2dbe0d3507b6b3939af8e97fdbee543dee3fd64bf590404330cf0c0e76bb8591011dcb61ad4f28c48940a09db1f3588e35827c89c09a"; + +void CUnsignedAlert::SetNull() +{ + nVersion = 1; + nRelayUntil = 0; + nExpiration = 0; + nID = 0; + nCancel = 0; + setCancel.clear(); + nMinVer = 0; + nMaxVer = 0; + setSubVer.clear(); + nPriority = 0; + + strComment.clear(); + strStatusBar.clear(); + strReserved.clear(); +} + +std::string CUnsignedAlert::ToString() const +{ + std::string strSetCancel; + BOOST_FOREACH(int n, setCancel) + strSetCancel += strprintf("%d ", n); + std::string strSetSubVer; + BOOST_FOREACH(std::string str, setSubVer) + strSetSubVer += "\"" + str + "\" "; + return strprintf( + "CAlert(\n" + " nVersion = %d\n" + " nRelayUntil = %"PRI64d"\n" + " nExpiration = %"PRI64d"\n" + " nID = %d\n" + " nCancel = %d\n" + " setCancel = %s\n" + " nMinVer = %d\n" + " nMaxVer = %d\n" + " setSubVer = %s\n" + " nPriority = %d\n" + " strComment = \"%s\"\n" + " strStatusBar = \"%s\"\n" + ")\n", + nVersion, + nRelayUntil, + nExpiration, + nID, + nCancel, + strSetCancel.c_str(), + nMinVer, + nMaxVer, + strSetSubVer.c_str(), + nPriority, + strComment.c_str(), + strStatusBar.c_str()); +} + +void CUnsignedAlert::print() const +{ + printf("%s", ToString().c_str()); +} + +void CAlert::SetNull() +{ + CUnsignedAlert::SetNull(); + vchMsg.clear(); + vchSig.clear(); +} + +bool CAlert::IsNull() const +{ + return (nExpiration == 0); +} + +uint256 CAlert::GetHash() const +{ + return Hash(this->vchMsg.begin(), this->vchMsg.end()); +} + +bool CAlert::IsInEffect() const +{ + return (GetAdjustedTime() < nExpiration); +} + +bool CAlert::Cancels(const CAlert& alert) const +{ + if (!IsInEffect()) + return false; // this was a no-op before 31403 + return (alert.nID <= nCancel || setCancel.count(alert.nID)); +} + +bool CAlert::AppliesTo(int nVersion, std::string strSubVerIn) const +{ + // TODO: rework for client-version-embedded-in-strSubVer ? + return (IsInEffect() && + nMinVer <= nVersion && nVersion <= nMaxVer && + (setSubVer.empty() || setSubVer.count(strSubVerIn))); +} + +bool CAlert::AppliesToMe() const +{ + return AppliesTo(PROTOCOL_VERSION, FormatSubVersion(CLIENT_NAME, CLIENT_VERSION, std::vector())); +} + +bool CAlert::RelayTo(CNode* pnode) const +{ + if (!IsInEffect()) + return false; + // returns true if wasn't already contained in the set + if (pnode->setKnown.insert(GetHash()).second) + { + if (AppliesTo(pnode->nVersion, pnode->strSubVer) || + AppliesToMe() || + GetAdjustedTime() < nRelayUntil) + { + pnode->PushMessage("alert", *this); + return true; + } + } + return false; +} + +bool CAlert::CheckSignature() const +{ + CKey key; + if (!key.SetPubKey(ParseHex(fTestNet ? pszTestKey : pszMainKey))) + return error("CAlert::CheckSignature() : SetPubKey failed"); + if (!key.Verify(Hash(vchMsg.begin(), vchMsg.end()), vchSig)) + return error("CAlert::CheckSignature() : verify signature failed"); + + // Now unserialize the data + CDataStream sMsg(vchMsg, SER_NETWORK, PROTOCOL_VERSION); + sMsg >> *(CUnsignedAlert*)this; + return true; +} + +CAlert CAlert::getAlertByHash(const uint256 &hash) +{ + CAlert retval; + { + LOCK(cs_mapAlerts); + map::iterator mi = mapAlerts.find(hash); + if(mi != mapAlerts.end()) + retval = mi->second; + } + return retval; +} + +bool CAlert::ProcessAlert() +{ + if (!CheckSignature()) + return false; + if (!IsInEffect()) + return false; + + // alert.nID=max is reserved for if the alert key is + // compromised. It must have a pre-defined message, + // must never expire, must apply to all versions, + // and must cancel all previous + // alerts or it will be ignored (so an attacker can't + // send an "everything is OK, don't panic" version that + // cannot be overridden): + int maxInt = std::numeric_limits::max(); + if (nID == maxInt) + { + if (!( + nExpiration == maxInt && + nCancel == (maxInt-1) && + nMinVer == 0 && + nMaxVer == maxInt && + setSubVer.empty() && + nPriority == maxInt && + strStatusBar == "URGENT: Alert key compromised, upgrade required" + )) + return false; + } + + { + LOCK(cs_mapAlerts); + // Cancel previous alerts + for (map::iterator mi = mapAlerts.begin(); mi != mapAlerts.end();) + { + const CAlert& alert = (*mi).second; + if (Cancels(alert)) + { + printf("cancelling alert %d\n", alert.nID); + uiInterface.NotifyAlertChanged((*mi).first, CT_DELETED); + mapAlerts.erase(mi++); + } + else if (!alert.IsInEffect()) + { + printf("expiring alert %d\n", alert.nID); + uiInterface.NotifyAlertChanged((*mi).first, CT_DELETED); + mapAlerts.erase(mi++); + } + else + mi++; + } + + // Check if this alert has been cancelled + BOOST_FOREACH(PAIRTYPE(const uint256, CAlert)& item, mapAlerts) + { + const CAlert& alert = item.second; + if (alert.Cancels(*this)) + { + printf("alert already cancelled by %d\n", alert.nID); + return false; + } + } + + // Add to mapAlerts + mapAlerts.insert(make_pair(GetHash(), *this)); + // Notify UI if it applies to me + if(AppliesToMe()) + uiInterface.NotifyAlertChanged(GetHash(), CT_NEW); + } + + printf("accepted alert %d, AppliesToMe()=%d\n", nID, AppliesToMe()); + return true; +} diff --git a/src/alert.h b/src/alert.h new file mode 100644 index 0000000..7949c76 --- /dev/null +++ b/src/alert.h @@ -0,0 +1,102 @@ +// Copyright (c) 2010 Satoshi Nakamoto +// Copyright (c) 2009-2012 The Bitcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef _BITCOINALERT_H_ +#define _BITCOINALERT_H_ 1 + +#include +#include + +#include "uint256.h" +#include "util.h" + +class CNode; + +/** Alerts are for notifying old versions if they become too obsolete and + * need to upgrade. The message is displayed in the status bar. + * Alert messages are broadcast as a vector of signed data. Unserializing may + * not read the entire buffer if the alert is for a newer version, but older + * versions can still relay the original data. + */ +class CUnsignedAlert +{ +public: + int nVersion; + int64 nRelayUntil; // when newer nodes stop relaying to newer nodes + int64 nExpiration; + int nID; + int nCancel; + std::set setCancel; + int nMinVer; // lowest version inclusive + int nMaxVer; // highest version inclusive + std::set setSubVer; // empty matches all + int nPriority; + + // Actions + std::string strComment; + std::string strStatusBar; + std::string strReserved; + + IMPLEMENT_SERIALIZE + ( + READWRITE(this->nVersion); + nVersion = this->nVersion; + READWRITE(nRelayUntil); + READWRITE(nExpiration); + READWRITE(nID); + READWRITE(nCancel); + READWRITE(setCancel); + READWRITE(nMinVer); + READWRITE(nMaxVer); + READWRITE(setSubVer); + READWRITE(nPriority); + + READWRITE(strComment); + READWRITE(strStatusBar); + READWRITE(strReserved); + ) + + void SetNull(); + + std::string ToString() const; + void print() const; +}; + +/** An alert is a combination of a serialized CUnsignedAlert and a signature. */ +class CAlert : public CUnsignedAlert +{ +public: + std::vector vchMsg; + std::vector vchSig; + + CAlert() + { + SetNull(); + } + + IMPLEMENT_SERIALIZE + ( + READWRITE(vchMsg); + READWRITE(vchSig); + ) + + void SetNull(); + bool IsNull() const; + uint256 GetHash() const; + bool IsInEffect() const; + bool Cancels(const CAlert& alert) const; + bool AppliesTo(int nVersion, std::string strSubVerIn) const; + bool AppliesToMe() const; + bool RelayTo(CNode* pnode) const; + bool CheckSignature() const; + bool ProcessAlert(); + + /* + * Get copy of (active) alert object by hash. Returns a null alert if it is not found. + */ + static CAlert getAlertByHash(const uint256 &hash); +}; + +#endif diff --git a/src/allocators.h b/src/allocators.h new file mode 100644 index 0000000..99afa10 --- /dev/null +++ b/src/allocators.h @@ -0,0 +1,257 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2012 The Bitcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. +#ifndef BITCOIN_ALLOCATORS_H +#define BITCOIN_ALLOCATORS_H + +#include +#include +#include +#include + +#ifdef WIN32 +#ifdef _WIN32_WINNT +#undef _WIN32_WINNT +#endif +#define _WIN32_WINNT 0x0501 +#define WIN32_LEAN_AND_MEAN 1 +#ifndef NOMINMAX +#define NOMINMAX +#endif +#include +// This is used to attempt to keep keying material out of swap +// Note that VirtualLock does not provide this as a guarantee on Windows, +// but, in practice, memory that has been VirtualLock'd almost never gets written to +// the pagefile except in rare circumstances where memory is extremely low. +#else +#include +#include // for PAGESIZE +#include // for sysconf +#endif + +/** + * Thread-safe class to keep track of locked (ie, non-swappable) memory pages. + * + * Memory locks do not stack, that is, pages which have been locked several times by calls to mlock() + * will be unlocked by a single call to munlock(). This can result in keying material ending up in swap when + * those functions are used naively. This class simulates stacking memory locks by keeping a counter per page. + * + * @note By using a map from each page base address to lock count, this class is optimized for + * small objects that span up to a few pages, mostly smaller than a page. To support large allocations, + * something like an interval tree would be the preferred data structure. + */ +template class LockedPageManagerBase +{ +public: + LockedPageManagerBase(size_t page_size): + page_size(page_size) + { + // Determine bitmask for extracting page from address + assert(!(page_size & (page_size-1))); // size must be power of two + page_mask = ~(page_size - 1); + } + + // For all pages in affected range, increase lock count + void LockRange(void *p, size_t size) + { + boost::mutex::scoped_lock lock(mutex); + if(!size) return; + const size_t base_addr = reinterpret_cast(p); + const size_t start_page = base_addr & page_mask; + const size_t end_page = (base_addr + size - 1) & page_mask; + for(size_t page = start_page; page <= end_page; page += page_size) + { + Histogram::iterator it = histogram.find(page); + if(it == histogram.end()) // Newly locked page + { + locker.Lock(reinterpret_cast(page), page_size); + histogram.insert(std::make_pair(page, 1)); + } + else // Page was already locked; increase counter + { + it->second += 1; + } + } + } + + // For all pages in affected range, decrease lock count + void UnlockRange(void *p, size_t size) + { + boost::mutex::scoped_lock lock(mutex); + if(!size) return; + const size_t base_addr = reinterpret_cast(p); + const size_t start_page = base_addr & page_mask; + const size_t end_page = (base_addr + size - 1) & page_mask; + for(size_t page = start_page; page <= end_page; page += page_size) + { + Histogram::iterator it = histogram.find(page); + assert(it != histogram.end()); // Cannot unlock an area that was not locked + // Decrease counter for page, when it is zero, the page will be unlocked + it->second -= 1; + if(it->second == 0) // Nothing on the page anymore that keeps it locked + { + // Unlock page and remove the count from histogram + locker.Unlock(reinterpret_cast(page), page_size); + histogram.erase(it); + } + } + } + + // Get number of locked pages for diagnostics + int GetLockedPageCount() + { + boost::mutex::scoped_lock lock(mutex); + return histogram.size(); + } + +private: + Locker locker; + boost::mutex mutex; + size_t page_size, page_mask; + // map of page base address to lock count + typedef std::map Histogram; + Histogram histogram; +}; + +/** Determine system page size in bytes */ +static inline size_t GetSystemPageSize() +{ + size_t page_size; +#if defined(WIN32) + SYSTEM_INFO sSysInfo; + GetSystemInfo(&sSysInfo); + page_size = sSysInfo.dwPageSize; +#elif defined(PAGESIZE) // defined in limits.h + page_size = PAGESIZE; +#else // assume some POSIX OS + page_size = sysconf(_SC_PAGESIZE); +#endif + return page_size; +} + +/** + * OS-dependent memory page locking/unlocking. + * Defined as policy class to make stubbing for test possible. + */ +class MemoryPageLocker +{ +public: + /** Lock memory pages. + * addr and len must be a multiple of the system page size + */ + bool Lock(const void *addr, size_t len) + { +#ifdef WIN32 + return VirtualLock(const_cast(addr), len); +#else + return mlock(addr, len) == 0; +#endif + } + /** Unlock memory pages. + * addr and len must be a multiple of the system page size + */ + bool Unlock(const void *addr, size_t len) + { +#ifdef WIN32 + return VirtualUnlock(const_cast(addr), len); +#else + return munlock(addr, len) == 0; +#endif + } +}; + +/** + * Singleton class to keep track of locked (ie, non-swappable) memory pages, for use in + * std::allocator templates. + */ +class LockedPageManager: public LockedPageManagerBase +{ +public: + static LockedPageManager instance; // instantiated in util.cpp +private: + LockedPageManager(): + LockedPageManagerBase(GetSystemPageSize()) + {} +}; + +// +// Allocator that locks its contents from being paged +// out of memory and clears its contents before deletion. +// +template +struct secure_allocator : public std::allocator +{ + // MSVC8 default copy constructor is broken + typedef std::allocator base; + typedef typename base::size_type size_type; + typedef typename base::difference_type difference_type; + typedef typename base::pointer pointer; + typedef typename base::const_pointer const_pointer; + typedef typename base::reference reference; + typedef typename base::const_reference const_reference; + typedef typename base::value_type value_type; + secure_allocator() throw() {} + secure_allocator(const secure_allocator& a) throw() : base(a) {} + template + secure_allocator(const secure_allocator& a) throw() : base(a) {} + ~secure_allocator() throw() {} + template struct rebind + { typedef secure_allocator<_Other> other; }; + + T* allocate(std::size_t n, const void *hint = 0) + { + T *p; + p = std::allocator::allocate(n, hint); + if (p != NULL) + LockedPageManager::instance.LockRange(p, sizeof(T) * n); + return p; + } + + void deallocate(T* p, std::size_t n) + { + if (p != NULL) + { + memset(p, 0, sizeof(T) * n); + LockedPageManager::instance.UnlockRange(p, sizeof(T) * n); + } + std::allocator::deallocate(p, n); + } +}; + + +// +// Allocator that clears its contents before deletion. +// +template +struct zero_after_free_allocator : public std::allocator +{ + // MSVC8 default copy constructor is broken + typedef std::allocator base; + typedef typename base::size_type size_type; + typedef typename base::difference_type difference_type; + typedef typename base::pointer pointer; + typedef typename base::const_pointer const_pointer; + typedef typename base::reference reference; + typedef typename base::const_reference const_reference; + typedef typename base::value_type value_type; + zero_after_free_allocator() throw() {} + zero_after_free_allocator(const zero_after_free_allocator& a) throw() : base(a) {} + template + zero_after_free_allocator(const zero_after_free_allocator& a) throw() : base(a) {} + ~zero_after_free_allocator() throw() {} + template struct rebind + { typedef zero_after_free_allocator<_Other> other; }; + + void deallocate(T* p, std::size_t n) + { + if (p != NULL) + memset(p, 0, sizeof(T) * n); + std::allocator::deallocate(p, n); + } +}; + +// This is exactly like std::string, but with a custom allocator. +typedef std::basic_string, secure_allocator > SecureString; + +#endif diff --git a/src/base58.h b/src/base58.h new file mode 100644 index 0000000..082c2d0 --- /dev/null +++ b/src/base58.h @@ -0,0 +1,460 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2012 The Bitcoin Developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + + +// +// Why base-58 instead of standard base-64 encoding? +// - Don't want 0OIl characters that look the same in some fonts and +// could be used to create visually identical looking account numbers. +// - A string with non-alphanumeric characters is not as easily accepted as an account number. +// - E-mail usually won't line-break if there's no punctuation to break at. +// - Double-clicking selects the whole number as one word if it's all alphanumeric. +// +#ifndef BITCOIN_BASE58_H +#define BITCOIN_BASE58_H + +#include +#include +#include "bignum.h" +#include "key.h" +#include "script.h" + +static const char* pszBase58 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; + +// Encode a byte sequence as a base58-encoded string +inline std::string EncodeBase58(const unsigned char* pbegin, const unsigned char* pend) +{ + CAutoBN_CTX pctx; + CBigNum bn58 = 58; + CBigNum bn0 = 0; + + // Convert big endian data to little endian + // Extra zero at the end make sure bignum will interpret as a positive number + std::vector vchTmp(pend-pbegin+1, 0); + reverse_copy(pbegin, pend, vchTmp.begin()); + + // Convert little endian data to bignum + CBigNum bn; + bn.setvch(vchTmp); + + // Convert bignum to std::string + std::string str; + // Expected size increase from base58 conversion is approximately 137% + // use 138% to be safe + str.reserve((pend - pbegin) * 138 / 100 + 1); + CBigNum dv; + CBigNum rem; + while (bn > bn0) + { + if (!BN_div(&dv, &rem, &bn, &bn58, pctx)) + throw bignum_error("EncodeBase58 : BN_div failed"); + bn = dv; + unsigned int c = rem.getulong(); + str += pszBase58[c]; + } + + // Leading zeroes encoded as base58 zeros + for (const unsigned char* p = pbegin; p < pend && *p == 0; p++) + str += pszBase58[0]; + + // Convert little endian std::string to big endian + reverse(str.begin(), str.end()); + return str; +} + +// Encode a byte vector as a base58-encoded string +inline std::string EncodeBase58(const std::vector& vch) +{ + return EncodeBase58(&vch[0], &vch[0] + vch.size()); +} + +// Decode a base58-encoded string psz into byte vector vchRet +// returns true if decoding is successful +inline bool DecodeBase58(const char* psz, std::vector& vchRet) +{ + CAutoBN_CTX pctx; + vchRet.clear(); + CBigNum bn58 = 58; + CBigNum bn = 0; + CBigNum bnChar; + while (isspace(*psz)) + psz++; + + // Convert big endian string to bignum + for (const char* p = psz; *p; p++) + { + const char* p1 = strchr(pszBase58, *p); + if (p1 == NULL) + { + while (isspace(*p)) + p++; + if (*p != '\0') + return false; + break; + } + bnChar.setulong(p1 - pszBase58); + if (!BN_mul(&bn, &bn, &bn58, pctx)) + throw bignum_error("DecodeBase58 : BN_mul failed"); + bn += bnChar; + } + + // Get bignum as little endian data + std::vector vchTmp = bn.getvch(); + + // Trim off sign byte if present + if (vchTmp.size() >= 2 && vchTmp.end()[-1] == 0 && vchTmp.end()[-2] >= 0x80) + vchTmp.erase(vchTmp.end()-1); + + // Restore leading zeros + int nLeadingZeros = 0; + for (const char* p = psz; *p == pszBase58[0]; p++) + nLeadingZeros++; + vchRet.assign(nLeadingZeros + vchTmp.size(), 0); + + // Convert little endian data to big endian + reverse_copy(vchTmp.begin(), vchTmp.end(), vchRet.end() - vchTmp.size()); + return true; +} + +// Decode a base58-encoded string str into byte vector vchRet +// returns true if decoding is successful +inline bool DecodeBase58(const std::string& str, std::vector& vchRet) +{ + return DecodeBase58(str.c_str(), vchRet); +} + + + + +// Encode a byte vector to a base58-encoded string, including checksum +inline std::string EncodeBase58Check(const std::vector& vchIn) +{ + // add 4-byte hash check to the end + std::vector vch(vchIn); + uint256 hash = Hash(vch.begin(), vch.end()); + vch.insert(vch.end(), (unsigned char*)&hash, (unsigned char*)&hash + 4); + return EncodeBase58(vch); +} + +// Decode a base58-encoded string psz that includes a checksum, into byte vector vchRet +// returns true if decoding is successful +inline bool DecodeBase58Check(const char* psz, std::vector& vchRet) +{ + if (!DecodeBase58(psz, vchRet)) + return false; + if (vchRet.size() < 4) + { + vchRet.clear(); + return false; + } + uint256 hash = Hash(vchRet.begin(), vchRet.end()-4); + if (memcmp(&hash, &vchRet.end()[-4], 4) != 0) + { + vchRet.clear(); + return false; + } + vchRet.resize(vchRet.size()-4); + return true; +} + +// Decode a base58-encoded string str that includes a checksum, into byte vector vchRet +// returns true if decoding is successful +inline bool DecodeBase58Check(const std::string& str, std::vector& vchRet) +{ + return DecodeBase58Check(str.c_str(), vchRet); +} + + + + + +/** Base class for all base58-encoded data */ +class CBase58Data +{ +protected: + // the version byte + unsigned char nVersion; + + // the actually encoded data + std::vector vchData; + + CBase58Data() + { + nVersion = 0; + vchData.clear(); + } + + ~CBase58Data() + { + // zero the memory, as it may contain sensitive data + if (!vchData.empty()) + memset(&vchData[0], 0, vchData.size()); + } + + void SetData(int nVersionIn, const void* pdata, size_t nSize) + { + nVersion = nVersionIn; + vchData.resize(nSize); + if (!vchData.empty()) + memcpy(&vchData[0], pdata, nSize); + } + + void SetData(int nVersionIn, const unsigned char *pbegin, const unsigned char *pend) + { + SetData(nVersionIn, (void*)pbegin, pend - pbegin); + } + +public: + bool SetString(const char* psz) + { + std::vector vchTemp; + DecodeBase58Check(psz, vchTemp); + if (vchTemp.empty()) + { + vchData.clear(); + nVersion = 0; + return false; + } + nVersion = vchTemp[0]; + vchData.resize(vchTemp.size() - 1); + if (!vchData.empty()) + memcpy(&vchData[0], &vchTemp[1], vchData.size()); + memset(&vchTemp[0], 0, vchTemp.size()); + return true; + } + + bool SetString(const std::string& str) + { + return SetString(str.c_str()); + } + + std::string ToString() const + { + std::vector vch(1, nVersion); + vch.insert(vch.end(), vchData.begin(), vchData.end()); + return EncodeBase58Check(vch); + } + + int CompareTo(const CBase58Data& b58) const + { + if (nVersion < b58.nVersion) return -1; + if (nVersion > b58.nVersion) return 1; + if (vchData < b58.vchData) return -1; + if (vchData > b58.vchData) return 1; + return 0; + } + + bool operator==(const CBase58Data& b58) const { return CompareTo(b58) == 0; } + bool operator<=(const CBase58Data& b58) const { return CompareTo(b58) <= 0; } + bool operator>=(const CBase58Data& b58) const { return CompareTo(b58) >= 0; } + bool operator< (const CBase58Data& b58) const { return CompareTo(b58) < 0; } + bool operator> (const CBase58Data& b58) const { return CompareTo(b58) > 0; } +}; + +/** base58-encoded Bitcoin addresses. + * Public-key-hash-addresses have version 0 (or 111 testnet). + * The data vector contains RIPEMD160(SHA256(pubkey)), where pubkey is the serialized public key. + * Script-hash-addresses have version 5 (or 196 testnet). + * The data vector contains RIPEMD160(SHA256(cscript)), where cscript is the serialized redemption script. + */ +class CBitcoinAddress; +class CBitcoinAddressVisitor : public boost::static_visitor +{ +private: + CBitcoinAddress *addr; +public: + CBitcoinAddressVisitor(CBitcoinAddress *addrIn) : addr(addrIn) { } + bool operator()(const CKeyID &id) const; + bool operator()(const CScriptID &id) const; + bool operator()(const CNoDestination &no) const; +}; + +class CBitcoinAddress : public CBase58Data +{ +public: + enum + { + PUBKEY_ADDRESS = 65, + SCRIPT_ADDRESS = 28, + PUBKEY_ADDRESS_TEST = 111, + SCRIPT_ADDRESS_TEST = 196, + }; + + bool Set(const CKeyID &id) { + SetData(fTestNet ? PUBKEY_ADDRESS_TEST : PUBKEY_ADDRESS, &id, 20); + return true; + } + + bool Set(const CScriptID &id) { + SetData(fTestNet ? SCRIPT_ADDRESS_TEST : SCRIPT_ADDRESS, &id, 20); + return true; + } + + bool Set(const CTxDestination &dest) + { + return boost::apply_visitor(CBitcoinAddressVisitor(this), dest); + } + + bool IsValid() const + { + unsigned int nExpectedSize = 20; + bool fExpectTestNet = false; + switch(nVersion) + { + case PUBKEY_ADDRESS: + nExpectedSize = 20; // Hash of public key + fExpectTestNet = false; + break; + case SCRIPT_ADDRESS: + nExpectedSize = 20; // Hash of CScript + fExpectTestNet = false; + break; + + case PUBKEY_ADDRESS_TEST: + nExpectedSize = 20; + fExpectTestNet = true; + break; + case SCRIPT_ADDRESS_TEST: + nExpectedSize = 20; + fExpectTestNet = true; + break; + + default: + return false; + } + return fExpectTestNet == fTestNet && vchData.size() == nExpectedSize; + } + + CBitcoinAddress() + { + } + + CBitcoinAddress(const CTxDestination &dest) + { + Set(dest); + } + + CBitcoinAddress(const std::string& strAddress) + { + SetString(strAddress); + } + + CBitcoinAddress(const char* pszAddress) + { + SetString(pszAddress); + } + + CTxDestination Get() const { + if (!IsValid()) + return CNoDestination(); + switch (nVersion) { + case PUBKEY_ADDRESS: + case PUBKEY_ADDRESS_TEST: { + uint160 id; + memcpy(&id, &vchData[0], 20); + return CKeyID(id); + } + case SCRIPT_ADDRESS: + case SCRIPT_ADDRESS_TEST: { + uint160 id; + memcpy(&id, &vchData[0], 20); + return CScriptID(id); + } + } + return CNoDestination(); + } + + bool GetKeyID(CKeyID &keyID) const { + if (!IsValid()) + return false; + switch (nVersion) { + case PUBKEY_ADDRESS: + case PUBKEY_ADDRESS_TEST: { + uint160 id; + memcpy(&id, &vchData[0], 20); + keyID = CKeyID(id); + return true; + } + default: return false; + } + } + + bool IsScript() const { + if (!IsValid()) + return false; + switch (nVersion) { + case SCRIPT_ADDRESS: + case SCRIPT_ADDRESS_TEST: { + return true; + } + default: return false; + } + } +}; + +bool inline CBitcoinAddressVisitor::operator()(const CKeyID &id) const { return addr->Set(id); } +bool inline CBitcoinAddressVisitor::operator()(const CScriptID &id) const { return addr->Set(id); } +bool inline CBitcoinAddressVisitor::operator()(const CNoDestination &id) const { return false; } + +/** A base58-encoded secret key */ +class CBitcoinSecret : public CBase58Data +{ +public: + void SetSecret(const CSecret& vchSecret, bool fCompressed) + { + assert(vchSecret.size() == 32); + SetData(128 + (fTestNet ? CBitcoinAddress::PUBKEY_ADDRESS_TEST : CBitcoinAddress::PUBKEY_ADDRESS), &vchSecret[0], vchSecret.size()); + if (fCompressed) + vchData.push_back(1); + } + + CSecret GetSecret(bool &fCompressedOut) + { + CSecret vchSecret; + vchSecret.resize(32); + memcpy(&vchSecret[0], &vchData[0], 32); + fCompressedOut = vchData.size() == 33; + return vchSecret; + } + + bool IsValid() const + { + bool fExpectTestNet = false; + switch(nVersion) + { + case (128 + CBitcoinAddress::PUBKEY_ADDRESS): + break; + + case (128 + CBitcoinAddress::PUBKEY_ADDRESS_TEST): + fExpectTestNet = true; + break; + + default: + return false; + } + return fExpectTestNet == fTestNet && (vchData.size() == 32 || (vchData.size() == 33 && vchData[32] == 1)); + } + + bool SetString(const char* pszSecret) + { + return CBase58Data::SetString(pszSecret) && IsValid(); + } + + bool SetString(const std::string& strSecret) + { + return SetString(strSecret.c_str()); + } + + CBitcoinSecret(const CSecret& vchSecret, bool fCompressed) + { + SetSecret(vchSecret, fCompressed); + } + + CBitcoinSecret() + { + } +}; + +#endif diff --git a/src/bignum.h b/src/bignum.h new file mode 100644 index 0000000..c214275 --- /dev/null +++ b/src/bignum.h @@ -0,0 +1,564 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2012 The Bitcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. +#ifndef BITCOIN_BIGNUM_H +#define BITCOIN_BIGNUM_H + +#include +#include +#include + +#include "util.h" // for uint64 + +/** Errors thrown by the bignum class */ +class bignum_error : public std::runtime_error +{ +public: + explicit bignum_error(const std::string& str) : std::runtime_error(str) {} +}; + + +/** RAII encapsulated BN_CTX (OpenSSL bignum context) */ +class CAutoBN_CTX +{ +protected: + BN_CTX* pctx; + BN_CTX* operator=(BN_CTX* pnew) { return pctx = pnew; } + +public: + CAutoBN_CTX() + { + pctx = BN_CTX_new(); + if (pctx == NULL) + throw bignum_error("CAutoBN_CTX : BN_CTX_new() returned NULL"); + } + + ~CAutoBN_CTX() + { + if (pctx != NULL) + BN_CTX_free(pctx); + } + + operator BN_CTX*() { return pctx; } + BN_CTX& operator*() { return *pctx; } + BN_CTX** operator&() { return &pctx; } + bool operator!() { return (pctx == NULL); } +}; + + +/** C++ wrapper for BIGNUM (OpenSSL bignum) */ +class CBigNum : public BIGNUM +{ +public: + CBigNum() + { + BN_init(this); + } + + CBigNum(const CBigNum& b) + { + BN_init(this); + if (!BN_copy(this, &b)) + { + BN_clear_free(this); + throw bignum_error("CBigNum::CBigNum(const CBigNum&) : BN_copy failed"); + } + } + + CBigNum& operator=(const CBigNum& b) + { + if (!BN_copy(this, &b)) + throw bignum_error("CBigNum::operator= : BN_copy failed"); + return (*this); + } + + ~CBigNum() + { + BN_clear_free(this); + } + + //CBigNum(char n) is not portable. Use 'signed char' or 'unsigned char'. + CBigNum(signed char n) { BN_init(this); if (n >= 0) setulong(n); else setint64(n); } + CBigNum(short n) { BN_init(this); if (n >= 0) setulong(n); else setint64(n); } + CBigNum(int n) { BN_init(this); if (n >= 0) setulong(n); else setint64(n); } + CBigNum(long n) { BN_init(this); if (n >= 0) setulong(n); else setint64(n); } + CBigNum(int64 n) { BN_init(this); setint64(n); } + CBigNum(unsigned char n) { BN_init(this); setulong(n); } + CBigNum(unsigned short n) { BN_init(this); setulong(n); } + CBigNum(unsigned int n) { BN_init(this); setulong(n); } + CBigNum(unsigned long n) { BN_init(this); setulong(n); } + CBigNum(uint64 n) { BN_init(this); setuint64(n); } + explicit CBigNum(uint256 n) { BN_init(this); setuint256(n); } + + explicit CBigNum(const std::vector& vch) + { + BN_init(this); + setvch(vch); + } + + void setulong(unsigned long n) + { + if (!BN_set_word(this, n)) + throw bignum_error("CBigNum conversion from unsigned long : BN_set_word failed"); + } + + unsigned long getulong() const + { + return BN_get_word(this); + } + + unsigned int getuint() const + { + return BN_get_word(this); + } + + int getint() const + { + unsigned long n = BN_get_word(this); + if (!BN_is_negative(this)) + return (n > (unsigned long)std::numeric_limits::max() ? std::numeric_limits::max() : n); + else + return (n > (unsigned long)std::numeric_limits::max() ? std::numeric_limits::min() : -(int)n); + } + + void setint64(int64 sn) + { + unsigned char pch[sizeof(sn) + 6]; + unsigned char* p = pch + 4; + bool fNegative; + uint64 n; + + if (sn < (int64)0) + { + // Since the minimum signed integer cannot be represented as positive so long as its type is signed, and it's not well-defined what happens if you make it unsigned before negating it, we instead increment the negative integer by 1, convert it, then increment the (now positive) unsigned integer by 1 to compensate + n = -(sn + 1); + ++n; + fNegative = true; + } else { + n = sn; + fNegative = false; + } + + bool fLeadingZeroes = true; + for (int i = 0; i < 8; i++) + { + unsigned char c = (n >> 56) & 0xff; + n <<= 8; + if (fLeadingZeroes) + { + if (c == 0) + continue; + if (c & 0x80) + *p++ = (fNegative ? 0x80 : 0); + else if (fNegative) + c |= 0x80; + fLeadingZeroes = false; + } + *p++ = c; + } + unsigned int nSize = p - (pch + 4); + pch[0] = (nSize >> 24) & 0xff; + pch[1] = (nSize >> 16) & 0xff; + pch[2] = (nSize >> 8) & 0xff; + pch[3] = (nSize) & 0xff; + BN_mpi2bn(pch, p - pch, this); + } + + uint64 getuint64() + { + unsigned int nSize = BN_bn2mpi(this, NULL); + if (nSize < 4) + return 0; + std::vector vch(nSize); + BN_bn2mpi(this, &vch[0]); + if (vch.size() > 4) + vch[4] &= 0x7f; + uint64 n = 0; + for (unsigned int i = 0, j = vch.size()-1; i < sizeof(n) && j >= 4; i++, j--) + ((unsigned char*)&n)[i] = vch[j]; + return n; + } + + void setuint64(uint64 n) + { + unsigned char pch[sizeof(n) + 6]; + unsigned char* p = pch + 4; + bool fLeadingZeroes = true; + for (int i = 0; i < 8; i++) + { + unsigned char c = (n >> 56) & 0xff; + n <<= 8; + if (fLeadingZeroes) + { + if (c == 0) + continue; + if (c & 0x80) + *p++ = 0; + fLeadingZeroes = false; + } + *p++ = c; + } + unsigned int nSize = p - (pch + 4); + pch[0] = (nSize >> 24) & 0xff; + pch[1] = (nSize >> 16) & 0xff; + pch[2] = (nSize >> 8) & 0xff; + pch[3] = (nSize) & 0xff; + BN_mpi2bn(pch, p - pch, this); + } + + void setuint256(uint256 n) + { + unsigned char pch[sizeof(n) + 6]; + unsigned char* p = pch + 4; + bool fLeadingZeroes = true; + unsigned char* pbegin = (unsigned char*)&n; + unsigned char* psrc = pbegin + sizeof(n); + while (psrc != pbegin) + { + unsigned char c = *(--psrc); + if (fLeadingZeroes) + { + if (c == 0) + continue; + if (c & 0x80) + *p++ = 0; + fLeadingZeroes = false; + } + *p++ = c; + } + unsigned int nSize = p - (pch + 4); + pch[0] = (nSize >> 24) & 0xff; + pch[1] = (nSize >> 16) & 0xff; + pch[2] = (nSize >> 8) & 0xff; + pch[3] = (nSize >> 0) & 0xff; + BN_mpi2bn(pch, p - pch, this); + } + + uint256 getuint256() + { + unsigned int nSize = BN_bn2mpi(this, NULL); + if (nSize < 4) + return 0; + std::vector vch(nSize); + BN_bn2mpi(this, &vch[0]); + if (vch.size() > 4) + vch[4] &= 0x7f; + uint256 n = 0; + for (unsigned int i = 0, j = vch.size()-1; i < sizeof(n) && j >= 4; i++, j--) + ((unsigned char*)&n)[i] = vch[j]; + return n; + } + + + void setvch(const std::vector& vch) + { + std::vector vch2(vch.size() + 4); + unsigned int nSize = vch.size(); + // BIGNUM's byte stream format expects 4 bytes of + // big endian size data info at the front + vch2[0] = (nSize >> 24) & 0xff; + vch2[1] = (nSize >> 16) & 0xff; + vch2[2] = (nSize >> 8) & 0xff; + vch2[3] = (nSize >> 0) & 0xff; + // swap data to big endian + reverse_copy(vch.begin(), vch.end(), vch2.begin() + 4); + BN_mpi2bn(&vch2[0], vch2.size(), this); + } + + std::vector getvch() const + { + unsigned int nSize = BN_bn2mpi(this, NULL); + if (nSize <= 4) + return std::vector(); + std::vector vch(nSize); + BN_bn2mpi(this, &vch[0]); + vch.erase(vch.begin(), vch.begin() + 4); + reverse(vch.begin(), vch.end()); + return vch; + } + + CBigNum& SetCompact(unsigned int nCompact) + { + unsigned int nSize = nCompact >> 24; + std::vector vch(4 + nSize); + vch[3] = nSize; + if (nSize >= 1) vch[4] = (nCompact >> 16) & 0xff; + if (nSize >= 2) vch[5] = (nCompact >> 8) & 0xff; + if (nSize >= 3) vch[6] = (nCompact >> 0) & 0xff; + BN_mpi2bn(&vch[0], vch.size(), this); + return *this; + } + + unsigned int GetCompact() const + { + unsigned int nSize = BN_bn2mpi(this, NULL); + std::vector vch(nSize); + nSize -= 4; + BN_bn2mpi(this, &vch[0]); + unsigned int nCompact = nSize << 24; + if (nSize >= 1) nCompact |= (vch[4] << 16); + if (nSize >= 2) nCompact |= (vch[5] << 8); + if (nSize >= 3) nCompact |= (vch[6] << 0); + return nCompact; + } + + void SetHex(const std::string& str) + { + // skip 0x + const char* psz = str.c_str(); + while (isspace(*psz)) + psz++; + bool fNegative = false; + if (*psz == '-') + { + fNegative = true; + psz++; + } + if (psz[0] == '0' && tolower(psz[1]) == 'x') + psz += 2; + while (isspace(*psz)) + psz++; + + // hex string to bignum + static const signed char phexdigit[256] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,1,2,3,4,5,6,7,8,9,0,0,0,0,0,0, 0,0xa,0xb,0xc,0xd,0xe,0xf,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0xa,0xb,0xc,0xd,0xe,0xf,0,0,0,0,0,0,0,0,0 }; + *this = 0; + while (isxdigit(*psz)) + { + *this <<= 4; + int n = phexdigit[(unsigned char)*psz++]; + *this += n; + } + if (fNegative) + *this = 0 - *this; + } + + std::string ToString(int nBase=10) const + { + CAutoBN_CTX pctx; + CBigNum bnBase = nBase; + CBigNum bn0 = 0; + std::string str; + CBigNum bn = *this; + BN_set_negative(&bn, false); + CBigNum dv; + CBigNum rem; + if (BN_cmp(&bn, &bn0) == 0) + return "0"; + while (BN_cmp(&bn, &bn0) > 0) + { + if (!BN_div(&dv, &rem, &bn, &bnBase, pctx)) + throw bignum_error("CBigNum::ToString() : BN_div failed"); + bn = dv; + unsigned int c = rem.getulong(); + str += "0123456789abcdef"[c]; + } + if (BN_is_negative(this)) + str += "-"; + reverse(str.begin(), str.end()); + return str; + } + + std::string GetHex() const + { + return ToString(16); + } + + unsigned int GetSerializeSize(int nType=0, int nVersion=PROTOCOL_VERSION) const + { + return ::GetSerializeSize(getvch(), nType, nVersion); + } + + template + void Serialize(Stream& s, int nType=0, int nVersion=PROTOCOL_VERSION) const + { + ::Serialize(s, getvch(), nType, nVersion); + } + + template + void Unserialize(Stream& s, int nType=0, int nVersion=PROTOCOL_VERSION) + { + std::vector vch; + ::Unserialize(s, vch, nType, nVersion); + setvch(vch); + } + + + bool operator!() const + { + return BN_is_zero(this); + } + + CBigNum& operator+=(const CBigNum& b) + { + if (!BN_add(this, this, &b)) + throw bignum_error("CBigNum::operator+= : BN_add failed"); + return *this; + } + + CBigNum& operator-=(const CBigNum& b) + { + *this = *this - b; + return *this; + } + + CBigNum& operator*=(const CBigNum& b) + { + CAutoBN_CTX pctx; + if (!BN_mul(this, this, &b, pctx)) + throw bignum_error("CBigNum::operator*= : BN_mul failed"); + return *this; + } + + CBigNum& operator/=(const CBigNum& b) + { + *this = *this / b; + return *this; + } + + CBigNum& operator%=(const CBigNum& b) + { + *this = *this % b; + return *this; + } + + CBigNum& operator<<=(unsigned int shift) + { + if (!BN_lshift(this, this, shift)) + throw bignum_error("CBigNum:operator<<= : BN_lshift failed"); + return *this; + } + + CBigNum& operator>>=(unsigned int shift) + { + // Note: BN_rshift segfaults on 64-bit if 2^shift is greater than the number + // if built on ubuntu 9.04 or 9.10, probably depends on version of OpenSSL + CBigNum a = 1; + a <<= shift; + if (BN_cmp(&a, this) > 0) + { + *this = 0; + return *this; + } + + if (!BN_rshift(this, this, shift)) + throw bignum_error("CBigNum:operator>>= : BN_rshift failed"); + return *this; + } + + + CBigNum& operator++() + { + // prefix operator + if (!BN_add(this, this, BN_value_one())) + throw bignum_error("CBigNum::operator++ : BN_add failed"); + return *this; + } + + const CBigNum operator++(int) + { + // postfix operator + const CBigNum ret = *this; + ++(*this); + return ret; + } + + CBigNum& operator--() + { + // prefix operator + CBigNum r; + if (!BN_sub(&r, this, BN_value_one())) + throw bignum_error("CBigNum::operator-- : BN_sub failed"); + *this = r; + return *this; + } + + const CBigNum operator--(int) + { + // postfix operator + const CBigNum ret = *this; + --(*this); + return ret; + } + + + friend inline const CBigNum operator-(const CBigNum& a, const CBigNum& b); + friend inline const CBigNum operator/(const CBigNum& a, const CBigNum& b); + friend inline const CBigNum operator%(const CBigNum& a, const CBigNum& b); +}; + + + +inline const CBigNum operator+(const CBigNum& a, const CBigNum& b) +{ + CBigNum r; + if (!BN_add(&r, &a, &b)) + throw bignum_error("CBigNum::operator+ : BN_add failed"); + return r; +} + +inline const CBigNum operator-(const CBigNum& a, const CBigNum& b) +{ + CBigNum r; + if (!BN_sub(&r, &a, &b)) + throw bignum_error("CBigNum::operator- : BN_sub failed"); + return r; +} + +inline const CBigNum operator-(const CBigNum& a) +{ + CBigNum r(a); + BN_set_negative(&r, !BN_is_negative(&r)); + return r; +} + +inline const CBigNum operator*(const CBigNum& a, const CBigNum& b) +{ + CAutoBN_CTX pctx; + CBigNum r; + if (!BN_mul(&r, &a, &b, pctx)) + throw bignum_error("CBigNum::operator* : BN_mul failed"); + return r; +} + +inline const CBigNum operator/(const CBigNum& a, const CBigNum& b) +{ + CAutoBN_CTX pctx; + CBigNum r; + if (!BN_div(&r, NULL, &a, &b, pctx)) + throw bignum_error("CBigNum::operator/ : BN_div failed"); + return r; +} + +inline const CBigNum operator%(const CBigNum& a, const CBigNum& b) +{ + CAutoBN_CTX pctx; + CBigNum r; + if (!BN_mod(&r, &a, &b, pctx)) + throw bignum_error("CBigNum::operator% : BN_div failed"); + return r; +} + +inline const CBigNum operator<<(const CBigNum& a, unsigned int shift) +{ + CBigNum r; + if (!BN_lshift(&r, &a, shift)) + throw bignum_error("CBigNum:operator<< : BN_lshift failed"); + return r; +} + +inline const CBigNum operator>>(const CBigNum& a, unsigned int shift) +{ + CBigNum r = a; + r >>= shift; + return r; +} + +inline bool operator==(const CBigNum& a, const CBigNum& b) { return (BN_cmp(&a, &b) == 0); } +inline bool operator!=(const CBigNum& a, const CBigNum& b) { return (BN_cmp(&a, &b) != 0); } +inline bool operator<=(const CBigNum& a, const CBigNum& b) { return (BN_cmp(&a, &b) <= 0); } +inline bool operator>=(const CBigNum& a, const CBigNum& b) { return (BN_cmp(&a, &b) >= 0); } +inline bool operator<(const CBigNum& a, const CBigNum& b) { return (BN_cmp(&a, &b) < 0); } +inline bool operator>(const CBigNum& a, const CBigNum& b) { return (BN_cmp(&a, &b) > 0); } + +#endif diff --git a/src/bitcoinrpc.cpp b/src/bitcoinrpc.cpp new file mode 100644 index 0000000..b5f7b24 --- /dev/null +++ b/src/bitcoinrpc.cpp @@ -0,0 +1,1292 @@ +// Copyright (c) 2010 Satoshi Nakamoto +// Copyright (c) 2009-2012 The Bitcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "init.h" +#include "util.h" +#include "sync.h" +#include "ui_interface.h" +#include "base58.h" +#include "bitcoinrpc.h" +#include "db.h" + +#undef printf +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define printf OutputDebugStringF + +using namespace std; +using namespace boost; +using namespace boost::asio; +using namespace json_spirit; + +void ThreadRPCServer2(void* parg); + +static std::string strRPCUserColonPass; + +const Object emptyobj; + +void ThreadRPCServer3(void* parg); + +static inline unsigned short GetDefaultRPCPort() +{ + return GetBoolArg("-testnet", false) ? 19111 : 19112; +} + +Object JSONRPCError(int code, const string& message) +{ + Object error; + error.push_back(Pair("code", code)); + error.push_back(Pair("message", message)); + return error; +} + +void RPCTypeCheck(const Array& params, + const list& typesExpected, + bool fAllowNull) +{ + unsigned int i = 0; + BOOST_FOREACH(Value_type t, typesExpected) + { + if (params.size() <= i) + break; + + const Value& v = params[i]; + if (!((v.type() == t) || (fAllowNull && (v.type() == null_type)))) + { + string err = strprintf("Expected type %s, got %s", + Value_type_name[t], Value_type_name[v.type()]); + throw JSONRPCError(RPC_TYPE_ERROR, err); + } + i++; + } +} + +void RPCTypeCheck(const Object& o, + const map& typesExpected, + bool fAllowNull) +{ + BOOST_FOREACH(const PAIRTYPE(string, Value_type)& t, typesExpected) + { + const Value& v = find_value(o, t.first); + if (!fAllowNull && v.type() == null_type) + throw JSONRPCError(RPC_TYPE_ERROR, strprintf("Missing %s", t.first.c_str())); + + if (!((v.type() == t.second) || (fAllowNull && (v.type() == null_type)))) + { + string err = strprintf("Expected type %s for %s, got %s", + Value_type_name[t.second], t.first.c_str(), Value_type_name[v.type()]); + throw JSONRPCError(RPC_TYPE_ERROR, err); + } + } +} + +int64 AmountFromValue(const Value& value) +{ + double dAmount = value.get_real(); + if (dAmount <= 0.0 || dAmount > MAX_MONEY) + throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount"); + int64 nAmount = roundint64(dAmount * COIN); + if (!MoneyRange(nAmount)) + throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount"); + return nAmount; +} + +Value ValueFromAmount(int64 amount) +{ + return (double)amount / (double)COIN; +} + +std::string HexBits(unsigned int nBits) +{ + union { + int32_t nBits; + char cBits[4]; + } uBits; + uBits.nBits = htonl((int32_t)nBits); + return HexStr(BEGIN(uBits.cBits), END(uBits.cBits)); +} + + + +/// +/// Note: This interface may still be subject to change. +/// + +string CRPCTable::help(string strCommand) const +{ + string strRet; + set setDone; + for (map::const_iterator mi = mapCommands.begin(); mi != mapCommands.end(); ++mi) + { + const CRPCCommand *pcmd = mi->second; + string strMethod = mi->first; + // We already filter duplicates, but these deprecated screw up the sort order + if (strMethod.find("label") != string::npos) + continue; + if (strCommand != "" && strMethod != strCommand) + continue; + try + { + Array params; + rpcfn_type pfn = pcmd->actor; + if (setDone.insert(pfn).second) + (*pfn)(params, true); + } + catch (std::exception& e) + { + // Help text is returned in an exception + string strHelp = string(e.what()); + if (strCommand == "") + if (strHelp.find('\n') != string::npos) + strHelp = strHelp.substr(0, strHelp.find('\n')); + strRet += strHelp + "\n"; + } + } + if (strRet == "") + strRet = strprintf("help: unknown command: %s\n", strCommand.c_str()); + strRet = strRet.substr(0,strRet.size()-1); + return strRet; +} + +Value help(const Array& params, bool fHelp) +{ + if (fHelp || params.size() > 1) + throw runtime_error( + "help [command]\n" + "List commands, or get help for a command."); + + string strCommand; + if (params.size() > 0) + strCommand = params[0].get_str(); + + return tableRPC.help(strCommand); +} + + +Value stop(const Array& params, bool fHelp) +{ + if (fHelp || params.size() > 1) + throw runtime_error( + "stop \n" + " is true or false to detach the database or not for this stop only\n" + "Stop triangles server (and possibly override the detachdb config value)."); + // Shutdown will take long enough that the response should get back + if (params.size() > 0) + bitdb.SetDetach(params[0].get_bool()); + StartShutdown(); + return "triangles server stopping"; +} + + + +// +// Call Table +// + + +static const CRPCCommand vRPCCommands[] = +{ // name function safemd unlocked + // ------------------------ ----------------------- ------ -------- + { "help", &help, true, true }, + { "stop", &stop, true, true }, + { "getblockcount", &getblockcount, true, false }, + { "getconnectioncount", &getconnectioncount, true, false }, + { "getpeerinfo", &getpeerinfo, true, false }, + { "getdifficulty", &getdifficulty, true, false }, + { "getgenerate", &getgenerate, true, false }, + { "setgenerate", &setgenerate, true, false }, + { "gethashespersec", &gethashespersec, true, false }, + { "getinfo", &getinfo, true, false }, + { "getmininginfo", &getmininginfo, true, false }, + { "getnewaddress", &getnewaddress, true, false }, + { "getnewpubkey", &getnewpubkey, true, false }, + { "getaccountaddress", &getaccountaddress, true, false }, + { "setaccount", &setaccount, true, false }, + { "getaccount", &getaccount, false, false }, + { "getaddressesbyaccount", &getaddressesbyaccount, true, false }, + { "sendtoaddress", &sendtoaddress, false, false }, + { "getreceivedbyaddress", &getreceivedbyaddress, false, false }, + { "getreceivedbyaccount", &getreceivedbyaccount, false, false }, + { "listreceivedbyaddress", &listreceivedbyaddress, false, false }, + { "listreceivedbyaccount", &listreceivedbyaccount, false, false }, + { "backupwallet", &backupwallet, true, false }, + { "keypoolrefill", &keypoolrefill, true, false }, + { "walletpassphrase", &walletpassphrase, true, false }, + { "walletpassphrasechange", &walletpassphrasechange, false, false }, + { "walletlock", &walletlock, true, false }, + { "encryptwallet", &encryptwallet, false, false }, + { "validateaddress", &validateaddress, true, false }, + { "validatepubkey", &validatepubkey, true, false }, + { "getbalance", &getbalance, false, false }, + { "move", &movecmd, false, false }, + { "sendfrom", &sendfrom, false, false }, + { "sendmany", &sendmany, false, false }, + { "addmultisigaddress", &addmultisigaddress, false, false }, + { "getrawmempool", &getrawmempool, true, false }, + { "getblock", &getblock, false, false }, + { "getblockbynumber", &getblockbynumber, false, false }, + { "getblockhash", &getblockhash, false, false }, + { "gettransaction", &gettransaction, false, false }, + { "listtransactions", &listtransactions, false, false }, + { "listaddressgroupings", &listaddressgroupings, false, false }, + { "signmessage", &signmessage, false, false }, + { "verifymessage", &verifymessage, false, false }, + { "getwork", &getwork, true, false }, + { "getworkex", &getworkex, true, false }, + { "listaccounts", &listaccounts, false, false }, + { "settxfee", &settxfee, false, false }, + { "getblocktemplate", &getblocktemplate, true, false }, + { "submitblock", &submitblock, false, false }, + { "listsinceblock", &listsinceblock, false, false }, + { "dumpprivkey", &dumpprivkey, false, false }, + { "importprivkey", &importprivkey, false, false }, + { "listunspent", &listunspent, false, false }, + { "getrawtransaction", &getrawtransaction, false, false }, + { "createrawtransaction", &createrawtransaction, false, false }, + { "decoderawtransaction", &decoderawtransaction, false, false }, + { "signrawtransaction", &signrawtransaction, false, false }, + { "sendrawtransaction", &sendrawtransaction, false, false }, + { "getcheckpoint", &getcheckpoint, true, false }, + { "reservebalance", &reservebalance, false, true}, + { "checkwallet", &checkwallet, false, true}, + { "repairwallet", &repairwallet, false, true}, + { "resendtx", &resendtx, false, true}, + { "makekeypair", &makekeypair, false, true}, + { "sendalert", &sendalert, false, false}, +}; + +CRPCTable::CRPCTable() +{ + unsigned int vcidx; + for (vcidx = 0; vcidx < (sizeof(vRPCCommands) / sizeof(vRPCCommands[0])); vcidx++) + { + const CRPCCommand *pcmd; + + pcmd = &vRPCCommands[vcidx]; + mapCommands[pcmd->name] = pcmd; + } +} + +const CRPCCommand *CRPCTable::operator[](string name) const +{ + map::const_iterator it = mapCommands.find(name); + if (it == mapCommands.end()) + return NULL; + return (*it).second; +} + +// +// HTTP protocol +// +// This ain't Apache. We're just using HTTP header for the length field +// and to be compatible with other JSON-RPC implementations. +// + +string HTTPPost(const string& strMsg, const map& mapRequestHeaders) +{ + ostringstream s; + s << "POST / HTTP/1.1\r\n" + << "User-Agent: triangles-json-rpc/" << FormatFullVersion() << "\r\n" + << "Host: 127.0.0.1\r\n" + << "Content-Type: application/json\r\n" + << "Content-Length: " << strMsg.size() << "\r\n" + << "Connection: close\r\n" + << "Accept: application/json\r\n"; + BOOST_FOREACH(const PAIRTYPE(string, string)& item, mapRequestHeaders) + s << item.first << ": " << item.second << "\r\n"; + s << "\r\n" << strMsg; + + return s.str(); +} + +string rfc1123Time() +{ + char buffer[64]; + time_t now; + time(&now); + struct tm* now_gmt = gmtime(&now); + string locale(setlocale(LC_TIME, NULL)); + setlocale(LC_TIME, "C"); // we want POSIX (aka "C") weekday/month strings + strftime(buffer, sizeof(buffer), "%a, %d %b %Y %H:%M:%S +0000", now_gmt); + setlocale(LC_TIME, locale.c_str()); + return string(buffer); +} + +static string HTTPReply(int nStatus, const string& strMsg, bool keepalive) +{ + if (nStatus == HTTP_UNAUTHORIZED) + return strprintf("HTTP/1.0 401 Authorization Required\r\n" + "Date: %s\r\n" + "Server: triangles-json-rpc/%s\r\n" + "WWW-Authenticate: Basic realm=\"jsonrpc\"\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 296\r\n" + "\r\n" + "\r\n" + "\r\n" + "\r\n" + "Error\r\n" + "\r\n" + "\r\n" + "

401 Unauthorized.

\r\n" + "\r\n", rfc1123Time().c_str(), FormatFullVersion().c_str()); + const char *cStatus; + if (nStatus == HTTP_OK) cStatus = "OK"; + else if (nStatus == HTTP_BAD_REQUEST) cStatus = "Bad Request"; + else if (nStatus == HTTP_FORBIDDEN) cStatus = "Forbidden"; + else if (nStatus == HTTP_NOT_FOUND) cStatus = "Not Found"; + else if (nStatus == HTTP_INTERNAL_SERVER_ERROR) cStatus = "Internal Server Error"; + else cStatus = ""; + return strprintf( + "HTTP/1.1 %d %s\r\n" + "Date: %s\r\n" + "Connection: %s\r\n" + "Content-Length: %"PRIszu"\r\n" + "Content-Type: application/json\r\n" + "Server: triangles-json-rpc/%s\r\n" + "\r\n" + "%s", + nStatus, + cStatus, + rfc1123Time().c_str(), + keepalive ? "keep-alive" : "close", + strMsg.size(), + FormatFullVersion().c_str(), + strMsg.c_str()); +} + +int ReadHTTPStatus(std::basic_istream& stream, int &proto) +{ + string str; + getline(stream, str); + vector vWords; + boost::split(vWords, str, boost::is_any_of(" ")); + if (vWords.size() < 2) + return HTTP_INTERNAL_SERVER_ERROR; + proto = 0; + const char *ver = strstr(str.c_str(), "HTTP/1."); + if (ver != NULL) + proto = atoi(ver+7); + return atoi(vWords[1].c_str()); +} + +int ReadHTTPHeader(std::basic_istream& stream, map& mapHeadersRet) +{ + int nLen = 0; + loop + { + string str; + std::getline(stream, str); + if (str.empty() || str == "\r") + break; + string::size_type nColon = str.find(":"); + if (nColon != string::npos) + { + string strHeader = str.substr(0, nColon); + boost::trim(strHeader); + boost::to_lower(strHeader); + string strValue = str.substr(nColon+1); + boost::trim(strValue); + mapHeadersRet[strHeader] = strValue; + if (strHeader == "content-length") + nLen = atoi(strValue.c_str()); + } + } + return nLen; +} + +int ReadHTTP(std::basic_istream& stream, map& mapHeadersRet, string& strMessageRet) +{ + mapHeadersRet.clear(); + strMessageRet = ""; + + // Read status + int nProto = 0; + int nStatus = ReadHTTPStatus(stream, nProto); + + // Read header + int nLen = ReadHTTPHeader(stream, mapHeadersRet); + if (nLen < 0 || nLen > (int)MAX_SIZE) + return HTTP_INTERNAL_SERVER_ERROR; + + // Read message + if (nLen > 0) + { + vector vch(nLen); + stream.read(&vch[0], nLen); + strMessageRet = string(vch.begin(), vch.end()); + } + + string sConHdr = mapHeadersRet["connection"]; + + if ((sConHdr != "close") && (sConHdr != "keep-alive")) + { + if (nProto >= 1) + mapHeadersRet["connection"] = "keep-alive"; + else + mapHeadersRet["connection"] = "close"; + } + + return nStatus; +} + +bool HTTPAuthorized(map& mapHeaders) +{ + string strAuth = mapHeaders["authorization"]; + if (strAuth.substr(0,6) != "Basic ") + return false; + string strUserPass64 = strAuth.substr(6); boost::trim(strUserPass64); + string strUserPass = DecodeBase64(strUserPass64); + return strUserPass == strRPCUserColonPass; +} + +// +// JSON-RPC protocol. Bitcoin speaks version 1.0 for maximum compatibility, +// but uses JSON-RPC 1.1/2.0 standards for parts of the 1.0 standard that were +// unspecified (HTTP errors and contents of 'error'). +// +// 1.0 spec: http://json-rpc.org/wiki/specification +// 1.2 spec: http://groups.google.com/group/json-rpc/web/json-rpc-over-http +// http://www.codeproject.com/KB/recipes/JSON_Spirit.aspx +// + +string JSONRPCRequest(const string& strMethod, const Array& params, const Value& id) +{ + Object request; + request.push_back(Pair("method", strMethod)); + request.push_back(Pair("params", params)); + request.push_back(Pair("id", id)); + return write_string(Value(request), false) + "\n"; +} + +Object JSONRPCReplyObj(const Value& result, const Value& error, const Value& id) +{ + Object reply; + if (error.type() != null_type) + reply.push_back(Pair("result", Value::null)); + else + reply.push_back(Pair("result", result)); + reply.push_back(Pair("error", error)); + reply.push_back(Pair("id", id)); + return reply; +} + +string JSONRPCReply(const Value& result, const Value& error, const Value& id) +{ + Object reply = JSONRPCReplyObj(result, error, id); + return write_string(Value(reply), false) + "\n"; +} + +void ErrorReply(std::ostream& stream, const Object& objError, const Value& id) +{ + // Send error reply from json-rpc error object + int nStatus = HTTP_INTERNAL_SERVER_ERROR; + int code = find_value(objError, "code").get_int(); + if (code == RPC_INVALID_REQUEST) nStatus = HTTP_BAD_REQUEST; + else if (code == RPC_METHOD_NOT_FOUND) nStatus = HTTP_NOT_FOUND; + string strReply = JSONRPCReply(Value::null, objError, id); + stream << HTTPReply(nStatus, strReply, false) << std::flush; +} + +bool ClientAllowed(const boost::asio::ip::address& address) +{ + // Make sure that IPv4-compatible and IPv4-mapped IPv6 addresses are treated as IPv4 addresses + if (address.is_v6() + && (address.to_v6().is_v4_compatible() + || address.to_v6().is_v4_mapped())) + return ClientAllowed(address.to_v6().to_v4()); + + std::string ipv4addr = address.to_string(); + + if (address == asio::ip::address_v4::loopback() + || address == asio::ip::address_v6::loopback() + || (address.is_v4() + // Check whether IPv4 addresses match 127.0.0.0/8 (loopback subnet) + && (address.to_v4().to_ulong() & 0xff000000) == 0x7f000000)) + return true; + + const string strAddress = address.to_string(); + const vector& vAllow = mapMultiArgs["-rpcallowip"]; + BOOST_FOREACH(string strAllow, vAllow) + if (WildcardMatch(strAddress, strAllow)) + return true; + return false; +} + +// +// IOStream device that speaks SSL but can also speak non-SSL +// +template +class SSLIOStreamDevice : public iostreams::device { +public: + SSLIOStreamDevice(asio::ssl::stream &streamIn, bool fUseSSLIn) : stream(streamIn) + { + fUseSSL = fUseSSLIn; + fNeedHandshake = fUseSSLIn; + } + + void handshake(ssl::stream_base::handshake_type role) + { + if (!fNeedHandshake) return; + fNeedHandshake = false; + stream.handshake(role); + } + std::streamsize read(char* s, std::streamsize n) + { + handshake(ssl::stream_base::server); // HTTPS servers read first + if (fUseSSL) return stream.read_some(asio::buffer(s, n)); + return stream.next_layer().read_some(asio::buffer(s, n)); + } + std::streamsize write(const char* s, std::streamsize n) + { + handshake(ssl::stream_base::client); // HTTPS clients write first + if (fUseSSL) return asio::write(stream, asio::buffer(s, n)); + return asio::write(stream.next_layer(), asio::buffer(s, n)); + } + bool connect(const std::string& server, const std::string& port) + { + ip::tcp::resolver resolver(stream.get_io_service()); + ip::tcp::resolver::query query(server.c_str(), port.c_str()); + ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve(query); + ip::tcp::resolver::iterator end; + boost::system::error_code error = asio::error::host_not_found; + while (error && endpoint_iterator != end) + { + stream.lowest_layer().close(); + stream.lowest_layer().connect(*endpoint_iterator++, error); + } + if (error) + return false; + return true; + } + +private: + bool fNeedHandshake; + bool fUseSSL; + asio::ssl::stream& stream; +}; + +class AcceptedConnection +{ +public: + virtual ~AcceptedConnection() {} + + virtual std::iostream& stream() = 0; + virtual std::string peer_address_to_string() const = 0; + virtual void close() = 0; +}; + +template +class AcceptedConnectionImpl : public AcceptedConnection +{ +public: + AcceptedConnectionImpl( + asio::io_service& io_service, + ssl::context &context, + bool fUseSSL) : + sslStream(io_service, context), + _d(sslStream, fUseSSL), + _stream(_d) + { + } + + virtual std::iostream& stream() + { + return _stream; + } + + virtual std::string peer_address_to_string() const + { + return peer.address().to_string(); + } + + virtual void close() + { + _stream.close(); + } + + typename Protocol::endpoint peer; + asio::ssl::stream sslStream; + +private: + SSLIOStreamDevice _d; + iostreams::stream< SSLIOStreamDevice > _stream; +}; + +void ThreadRPCServer(void* parg) +{ + // Make this thread recognisable as the RPC listener + RenameThread("bitcoin-rpclist"); + + try + { + vnThreadsRunning[THREAD_RPCLISTENER]++; + ThreadRPCServer2(parg); + vnThreadsRunning[THREAD_RPCLISTENER]--; + } + catch (std::exception& e) { + vnThreadsRunning[THREAD_RPCLISTENER]--; + PrintException(&e, "ThreadRPCServer()"); + } catch (...) { + vnThreadsRunning[THREAD_RPCLISTENER]--; + PrintException(NULL, "ThreadRPCServer()"); + } + printf("ThreadRPCServer exited\n"); +} + +// Forward declaration required for RPCListen +template +static void RPCAcceptHandler(boost::shared_ptr< basic_socket_acceptor > acceptor, + ssl::context& context, + bool fUseSSL, + AcceptedConnection* conn, + const boost::system::error_code& error); + +/** + * Sets up I/O resources to accept and handle a new connection. + */ +template +static void RPCListen(boost::shared_ptr< basic_socket_acceptor > acceptor, + ssl::context& context, + const bool fUseSSL) +{ + // Accept connection + AcceptedConnectionImpl* conn = new AcceptedConnectionImpl(acceptor->get_io_service(), context, fUseSSL); + + acceptor->async_accept( + conn->sslStream.lowest_layer(), + conn->peer, + boost::bind(&RPCAcceptHandler, + acceptor, + boost::ref(context), + fUseSSL, + conn, + boost::asio::placeholders::error)); +} + +/** + * Accept and handle incoming connection. + */ +template +static void RPCAcceptHandler(boost::shared_ptr< basic_socket_acceptor > acceptor, + ssl::context& context, + const bool fUseSSL, + AcceptedConnection* conn, + const boost::system::error_code& error) +{ + vnThreadsRunning[THREAD_RPCLISTENER]++; + + // Immediately start accepting new connections, except when we're cancelled or our socket is closed. + if (error != asio::error::operation_aborted + && acceptor->is_open()) + RPCListen(acceptor, context, fUseSSL); + + AcceptedConnectionImpl* tcp_conn = dynamic_cast< AcceptedConnectionImpl* >(conn); + + // TODO: Actually handle errors + if (error) + { + delete conn; + } + + // Restrict callers by IP. It is important to + // do this before starting client thread, to filter out + // certain DoS and misbehaving clients. + else if (tcp_conn + && !ClientAllowed(tcp_conn->peer.address())) + { + // Only send a 403 if we're not using SSL to prevent a DoS during the SSL handshake. + if (!fUseSSL) + conn->stream() << HTTPReply(HTTP_FORBIDDEN, "", false) << std::flush; + delete conn; + } + + // start HTTP client thread + else if (!NewThread(ThreadRPCServer3, conn)) { + printf("Failed to create RPC server client thread\n"); + delete conn; + } + + vnThreadsRunning[THREAD_RPCLISTENER]--; +} + +void ThreadRPCServer2(void* parg) +{ + printf("ThreadRPCServer started\n"); + + strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]; + if (mapArgs["-rpcpassword"] == "") + { + unsigned char rand_pwd[32]; + RAND_bytes(rand_pwd, 32); + string strWhatAmI = "To use trianglesd"; + if (mapArgs.count("-server")) + strWhatAmI = strprintf(_("To use the %s option"), "\"-server\""); + else if (mapArgs.count("-daemon")) + strWhatAmI = strprintf(_("To use the %s option"), "\"-daemon\""); + uiInterface.ThreadSafeMessageBox(strprintf( + _("%s, you must set a rpcpassword in the configuration file:\n %s\n" + "It is recommended you use the following random password:\n" + "rpcuser=bitcoinrpc\n" + "rpcpassword=%s\n" + "(you do not need to remember this password)\n" + "If the file does not exist, create it with owner-readable-only file permissions.\n"), + strWhatAmI.c_str(), + GetConfigFile().string().c_str(), + EncodeBase58(&rand_pwd[0],&rand_pwd[0]+32).c_str()), + _("Error"), CClientUIInterface::OK | CClientUIInterface::MODAL); + StartShutdown(); + return; + } + + const bool fUseSSL = GetBoolArg("-rpcssl"); + + asio::io_service io_service; + + ssl::context context(io_service, ssl::context::sslv23); + if (fUseSSL) + { + context.set_options(ssl::context::no_sslv2); + + filesystem::path pathCertFile(GetArg("-rpcsslcertificatechainfile", "server.cert")); + if (!pathCertFile.is_complete()) pathCertFile = filesystem::path(GetDataDir()) / pathCertFile; + if (filesystem::exists(pathCertFile)) context.use_certificate_chain_file(pathCertFile.string()); + else printf("ThreadRPCServer ERROR: missing server certificate file %s\n", pathCertFile.string().c_str()); + + filesystem::path pathPKFile(GetArg("-rpcsslprivatekeyfile", "server.pem")); + if (!pathPKFile.is_complete()) pathPKFile = filesystem::path(GetDataDir()) / pathPKFile; + if (filesystem::exists(pathPKFile)) context.use_private_key_file(pathPKFile.string(), ssl::context::pem); + else printf("ThreadRPCServer ERROR: missing server private key file %s\n", pathPKFile.string().c_str()); + + string strCiphers = GetArg("-rpcsslciphers", "TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH"); + SSL_CTX_set_cipher_list(context.impl(), strCiphers.c_str()); + } + + // Try a dual IPv6/IPv4 socket, falling back to separate IPv4 and IPv6 sockets + const bool loopback = !mapArgs.count("-rpcallowip"); + asio::ip::address bindAddress = loopback ? asio::ip::address_v6::loopback() : asio::ip::address_v6::any(); + ip::tcp::endpoint endpoint(bindAddress, GetArg("-rpcport", GetDefaultRPCPort())); + boost::system::error_code v6_only_error; + boost::shared_ptr acceptor(new ip::tcp::acceptor(io_service)); + + boost::signals2::signal StopRequests; + + bool fListening = false; + std::string strerr; + try + { + acceptor->open(endpoint.protocol()); + acceptor->set_option(boost::asio::ip::tcp::acceptor::reuse_address(true)); + + // Try making the socket dual IPv6/IPv4 (if listening on the "any" address) + acceptor->set_option(boost::asio::ip::v6_only(loopback), v6_only_error); + + acceptor->bind(endpoint); + acceptor->listen(socket_base::max_connections); + + RPCListen(acceptor, context, fUseSSL); + // Cancel outstanding listen-requests for this acceptor when shutting down + StopRequests.connect(signals2::slot( + static_cast(&ip::tcp::acceptor::close), acceptor.get()) + .track(acceptor)); + + fListening = true; + } + catch(boost::system::system_error &e) + { + strerr = strprintf(_("An error occurred while setting up the RPC port %u for listening on IPv6, falling back to IPv4: %s"), endpoint.port(), e.what()); + } + + try { + // If dual IPv6/IPv4 failed (or we're opening loopback interfaces only), open IPv4 separately + if (!fListening || loopback || v6_only_error) + { + bindAddress = loopback ? asio::ip::address_v4::loopback() : asio::ip::address_v4::any(); + endpoint.address(bindAddress); + + acceptor.reset(new ip::tcp::acceptor(io_service)); + acceptor->open(endpoint.protocol()); + acceptor->set_option(boost::asio::ip::tcp::acceptor::reuse_address(true)); + acceptor->bind(endpoint); + acceptor->listen(socket_base::max_connections); + + RPCListen(acceptor, context, fUseSSL); + // Cancel outstanding listen-requests for this acceptor when shutting down + StopRequests.connect(signals2::slot( + static_cast(&ip::tcp::acceptor::close), acceptor.get()) + .track(acceptor)); + + fListening = true; + } + } + catch(boost::system::system_error &e) + { + strerr = strprintf(_("An error occurred while setting up the RPC port %u for listening on IPv4: %s"), endpoint.port(), e.what()); + } + + if (!fListening) { + uiInterface.ThreadSafeMessageBox(strerr, _("Error"), CClientUIInterface::OK | CClientUIInterface::MODAL); + StartShutdown(); + return; + } + + vnThreadsRunning[THREAD_RPCLISTENER]--; + while (!fShutdown) + io_service.run_one(); + vnThreadsRunning[THREAD_RPCLISTENER]++; + StopRequests(); +} + +class JSONRequest +{ +public: + Value id; + string strMethod; + Array params; + + JSONRequest() { id = Value::null; } + void parse(const Value& valRequest); +}; + +void JSONRequest::parse(const Value& valRequest) +{ + // Parse request + if (valRequest.type() != obj_type) + throw JSONRPCError(RPC_INVALID_REQUEST, "Invalid Request object"); + const Object& request = valRequest.get_obj(); + + // Parse id now so errors from here on will have the id + id = find_value(request, "id"); + + // Parse method + Value valMethod = find_value(request, "method"); + if (valMethod.type() == null_type) + throw JSONRPCError(RPC_INVALID_REQUEST, "Missing method"); + if (valMethod.type() != str_type) + throw JSONRPCError(RPC_INVALID_REQUEST, "Method must be a string"); + strMethod = valMethod.get_str(); + if (strMethod != "getwork" && strMethod != "getblocktemplate") + printf("ThreadRPCServer method=%s\n", strMethod.c_str()); + + // Parse params + Value valParams = find_value(request, "params"); + if (valParams.type() == array_type) + params = valParams.get_array(); + else if (valParams.type() == null_type) + params = Array(); + else + throw JSONRPCError(RPC_INVALID_REQUEST, "Params must be an array"); +} + +static Object JSONRPCExecOne(const Value& req) +{ + Object rpc_result; + + JSONRequest jreq; + try { + jreq.parse(req); + + Value result = tableRPC.execute(jreq.strMethod, jreq.params); + rpc_result = JSONRPCReplyObj(result, Value::null, jreq.id); + } + catch (Object& objError) + { + rpc_result = JSONRPCReplyObj(Value::null, objError, jreq.id); + } + catch (std::exception& e) + { + rpc_result = JSONRPCReplyObj(Value::null, + JSONRPCError(RPC_PARSE_ERROR, e.what()), jreq.id); + } + + return rpc_result; +} + +static string JSONRPCExecBatch(const Array& vReq) +{ + Array ret; + for (unsigned int reqIdx = 0; reqIdx < vReq.size(); reqIdx++) + ret.push_back(JSONRPCExecOne(vReq[reqIdx])); + + return write_string(Value(ret), false) + "\n"; +} + +static CCriticalSection cs_THREAD_RPCHANDLER; + +void ThreadRPCServer3(void* parg) +{ + // Make this thread recognisable as the RPC handler + RenameThread("bitcoin-rpchand"); + + { + LOCK(cs_THREAD_RPCHANDLER); + vnThreadsRunning[THREAD_RPCHANDLER]++; + } + AcceptedConnection *conn = (AcceptedConnection *) parg; + + bool fRun = true; + loop { + if (fShutdown || !fRun) + { + conn->close(); + delete conn; + { + LOCK(cs_THREAD_RPCHANDLER); + --vnThreadsRunning[THREAD_RPCHANDLER]; + } + return; + } + map mapHeaders; + string strRequest; + + ReadHTTP(conn->stream(), mapHeaders, strRequest); + + // Check authorization + if (mapHeaders.count("authorization") == 0) + { + conn->stream() << HTTPReply(HTTP_UNAUTHORIZED, "", false) << std::flush; + break; + } + if (!HTTPAuthorized(mapHeaders)) + { + printf("ThreadRPCServer incorrect password attempt from %s\n", conn->peer_address_to_string().c_str()); + /* Deter brute-forcing short passwords. + If this results in a DOS the user really + shouldn't have their RPC port exposed.*/ + if (mapArgs["-rpcpassword"].size() < 20) + Sleep(250); + + conn->stream() << HTTPReply(HTTP_UNAUTHORIZED, "", false) << std::flush; + break; + } + if (mapHeaders["connection"] == "close") + fRun = false; + + JSONRequest jreq; + try + { + // Parse request + Value valRequest; + if (!read_string(strRequest, valRequest)) + throw JSONRPCError(RPC_PARSE_ERROR, "Parse error"); + + string strReply; + + // singleton request + if (valRequest.type() == obj_type) { + jreq.parse(valRequest); + + Value result = tableRPC.execute(jreq.strMethod, jreq.params); + + // Send reply + strReply = JSONRPCReply(result, Value::null, jreq.id); + + // array of requests + } else if (valRequest.type() == array_type) + strReply = JSONRPCExecBatch(valRequest.get_array()); + else + throw JSONRPCError(RPC_PARSE_ERROR, "Top-level object parse error"); + + conn->stream() << HTTPReply(HTTP_OK, strReply, fRun) << std::flush; + } + catch (Object& objError) + { + ErrorReply(conn->stream(), objError, jreq.id); + break; + } + catch (std::exception& e) + { + ErrorReply(conn->stream(), JSONRPCError(RPC_PARSE_ERROR, e.what()), jreq.id); + break; + } + } + + delete conn; + { + LOCK(cs_THREAD_RPCHANDLER); + vnThreadsRunning[THREAD_RPCHANDLER]--; + } +} + +json_spirit::Value CRPCTable::execute(const std::string &strMethod, const json_spirit::Array ¶ms) const +{ + // Find method + const CRPCCommand *pcmd = tableRPC[strMethod]; + if (!pcmd) + throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Method not found"); + + // Observe safe mode + string strWarning = GetWarnings("rpc"); + if (strWarning != "" && !GetBoolArg("-disablesafemode") && + !pcmd->okSafeMode) + throw JSONRPCError(RPC_FORBIDDEN_BY_SAFE_MODE, string("Safe mode: ") + strWarning); + + try + { + // Execute + Value result; + { + if (pcmd->unlocked) + result = pcmd->actor(params, false); + else { + LOCK2(cs_main, pwalletMain->cs_wallet); + result = pcmd->actor(params, false); + } + } + return result; + } + catch (std::exception& e) + { + throw JSONRPCError(RPC_MISC_ERROR, e.what()); + } +} + + +Object CallRPC(const string& strMethod, const Array& params) +{ + if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "") + throw runtime_error(strprintf( + _("You must set rpcpassword= in the configuration file:\n%s\n" + "If the file does not exist, create it with owner-readable-only file permissions."), + GetConfigFile().string().c_str())); + + // Connect to localhost + bool fUseSSL = GetBoolArg("-rpcssl"); + asio::io_service io_service; + ssl::context context(io_service, ssl::context::sslv23); + context.set_options(ssl::context::no_sslv2); + asio::ssl::stream sslStream(io_service, context); + SSLIOStreamDevice d(sslStream, fUseSSL); + iostreams::stream< SSLIOStreamDevice > stream(d); + if (!d.connect(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", itostr(GetDefaultRPCPort())))) + throw runtime_error("couldn't connect to server"); + + // HTTP basic authentication + string strUserPass64 = EncodeBase64(mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]); + map mapRequestHeaders; + mapRequestHeaders["Authorization"] = string("Basic ") + strUserPass64; + + // Send request + string strRequest = JSONRPCRequest(strMethod, params, 1); + string strPost = HTTPPost(strRequest, mapRequestHeaders); + stream << strPost << std::flush; + + // Receive reply + map mapHeaders; + string strReply; + int nStatus = ReadHTTP(stream, mapHeaders, strReply); + if (nStatus == HTTP_UNAUTHORIZED) + throw runtime_error("incorrect rpcuser or rpcpassword (authorization failed)"); + else if (nStatus >= 400 && nStatus != HTTP_BAD_REQUEST && nStatus != HTTP_NOT_FOUND && nStatus != HTTP_INTERNAL_SERVER_ERROR) + throw runtime_error(strprintf("server returned HTTP error %d", nStatus)); + else if (strReply.empty()) + throw runtime_error("no response from server"); + + // Parse reply + Value valReply; + if (!read_string(strReply, valReply)) + throw runtime_error("couldn't parse reply from server"); + const Object& reply = valReply.get_obj(); + if (reply.empty()) + throw runtime_error("expected reply to have result, error and id properties"); + + return reply; +} + + + + +template +void ConvertTo(Value& value, bool fAllowNull=false) +{ + if (fAllowNull && value.type() == null_type) + return; + if (value.type() == str_type) + { + // reinterpret string as unquoted json value + Value value2; + string strJSON = value.get_str(); + if (!read_string(strJSON, value2)) + throw runtime_error(string("Error parsing JSON:")+strJSON); + ConvertTo(value2, fAllowNull); + value = value2; + } + else + { + value = value.get_value(); + } +} + +// Convert strings to command-specific RPC representation +Array RPCConvertValues(const std::string &strMethod, const std::vector &strParams) +{ + Array params; + BOOST_FOREACH(const std::string ¶m, strParams) + params.push_back(param); + + int n = params.size(); + + // + // Special case non-string parameter types + // + if (strMethod == "stop" && n > 0) ConvertTo(params[0]); + if (strMethod == "setgenerate" && n > 0) ConvertTo(params[0]); + if (strMethod == "setgenerate" && n > 1) ConvertTo(params[1]); + if (strMethod == "sendtoaddress" && n > 1) ConvertTo(params[1]); + if (strMethod == "settxfee" && n > 0) ConvertTo(params[0]); + if (strMethod == "getreceivedbyaddress" && n > 1) ConvertTo(params[1]); + if (strMethod == "getreceivedbyaccount" && n > 1) ConvertTo(params[1]); + if (strMethod == "listreceivedbyaddress" && n > 0) ConvertTo(params[0]); + if (strMethod == "listreceivedbyaddress" && n > 1) ConvertTo(params[1]); + if (strMethod == "listreceivedbyaccount" && n > 0) ConvertTo(params[0]); + if (strMethod == "listreceivedbyaccount" && n > 1) ConvertTo(params[1]); + if (strMethod == "getbalance" && n > 1) ConvertTo(params[1]); + if (strMethod == "getblock" && n > 1) ConvertTo(params[1]); + if (strMethod == "getblockbynumber" && n > 0) ConvertTo(params[0]); + if (strMethod == "getblockbynumber" && n > 1) ConvertTo(params[1]); + if (strMethod == "getblockhash" && n > 0) ConvertTo(params[0]); + if (strMethod == "move" && n > 2) ConvertTo(params[2]); + if (strMethod == "move" && n > 3) ConvertTo(params[3]); + if (strMethod == "sendfrom" && n > 2) ConvertTo(params[2]); + if (strMethod == "sendfrom" && n > 3) ConvertTo(params[3]); + if (strMethod == "listtransactions" && n > 1) ConvertTo(params[1]); + if (strMethod == "listtransactions" && n > 2) ConvertTo(params[2]); + if (strMethod == "listaccounts" && n > 0) ConvertTo(params[0]); + if (strMethod == "walletpassphrase" && n > 1) ConvertTo(params[1]); + if (strMethod == "walletpassphrase" && n > 2) ConvertTo(params[2]); + if (strMethod == "getblocktemplate" && n > 0) ConvertTo(params[0]); + if (strMethod == "listsinceblock" && n > 1) ConvertTo(params[1]); + if (strMethod == "sendmany" && n > 1) ConvertTo(params[1]); + if (strMethod == "sendmany" && n > 2) ConvertTo(params[2]); + if (strMethod == "reservebalance" && n > 0) ConvertTo(params[0]); + if (strMethod == "reservebalance" && n > 1) ConvertTo(params[1]); + if (strMethod == "addmultisigaddress" && n > 0) ConvertTo(params[0]); + if (strMethod == "addmultisigaddress" && n > 1) ConvertTo(params[1]); + if (strMethod == "listunspent" && n > 0) ConvertTo(params[0]); + if (strMethod == "listunspent" && n > 1) ConvertTo(params[1]); + if (strMethod == "listunspent" && n > 2) ConvertTo(params[2]); + if (strMethod == "getrawtransaction" && n > 1) ConvertTo(params[1]); + if (strMethod == "createrawtransaction" && n > 0) ConvertTo(params[0]); + if (strMethod == "createrawtransaction" && n > 1) ConvertTo(params[1]); + if (strMethod == "signrawtransaction" && n > 1) ConvertTo(params[1], true); + if (strMethod == "signrawtransaction" && n > 2) ConvertTo(params[2], true); + + return params; +} + +int CommandLineRPC(int argc, char *argv[]) +{ + string strPrint; + int nRet = 0; + try + { + // Skip switches + while (argc > 1 && IsSwitchChar(argv[1][0])) + { + argc--; + argv++; + } + + // Method + if (argc < 2) + throw runtime_error("too few parameters"); + string strMethod = argv[1]; + + // Parameters default to strings + std::vector strParams(&argv[2], &argv[argc]); + Array params = RPCConvertValues(strMethod, strParams); + + // Execute + Object reply = CallRPC(strMethod, params); + + // Parse reply + const Value& result = find_value(reply, "result"); + const Value& error = find_value(reply, "error"); + + if (error.type() != null_type) + { + // Error + strPrint = "error: " + write_string(error, false); + int code = find_value(error.get_obj(), "code").get_int(); + nRet = abs(code); + } + else + { + // Result + if (result.type() == null_type) + strPrint = ""; + else if (result.type() == str_type) + strPrint = result.get_str(); + else + strPrint = write_string(result, true); + } + } + catch (std::exception& e) + { + strPrint = string("error: ") + e.what(); + nRet = 87; + } + catch (...) + { + PrintException(NULL, "CommandLineRPC()"); + } + + if (strPrint != "") + { + fprintf((nRet == 0 ? stdout : stderr), "%s\n", strPrint.c_str()); + } + return nRet; +} + + + + +#ifdef TEST +int main(int argc, char *argv[]) +{ +#ifdef _MSC_VER + // Turn off Microsoft heap dump noise + _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE); + _CrtSetReportFile(_CRT_WARN, CreateFile("NUL", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0)); +#endif + setbuf(stdin, NULL); + setbuf(stdout, NULL); + setbuf(stderr, NULL); + + try + { + if (argc >= 2 && string(argv[1]) == "-server") + { + printf("server ready\n"); + ThreadRPCServer(NULL); + } + else + { + return CommandLineRPC(argc, argv); + } + } + catch (std::exception& e) { + PrintException(&e, "main()"); + } catch (...) { + PrintException(NULL, "main()"); + } + return 0; +} +#endif + +const CRPCTable tableRPC; diff --git a/src/bitcoinrpc.h b/src/bitcoinrpc.h new file mode 100644 index 0000000..d0788f0 --- /dev/null +++ b/src/bitcoinrpc.h @@ -0,0 +1,208 @@ +// Copyright (c) 2010 Satoshi Nakamoto +// Copyright (c) 2009-2012 The Bitcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef _BITCOINRPC_H_ +#define _BITCOINRPC_H_ 1 + +#include +#include +#include + +class CBlockIndex; + +#include "json/json_spirit_reader_template.h" +#include "json/json_spirit_writer_template.h" +#include "json/json_spirit_utils.h" + +#include "util.h" +#include "checkpoints.h" + +// HTTP status codes +enum HTTPStatusCode +{ + HTTP_OK = 200, + HTTP_BAD_REQUEST = 400, + HTTP_UNAUTHORIZED = 401, + HTTP_FORBIDDEN = 403, + HTTP_NOT_FOUND = 404, + HTTP_INTERNAL_SERVER_ERROR = 500, +}; + +// Bitcoin RPC error codes +enum RPCErrorCode +{ + // Standard JSON-RPC 2.0 errors + RPC_INVALID_REQUEST = -32600, + RPC_METHOD_NOT_FOUND = -32601, + RPC_INVALID_PARAMS = -32602, + RPC_INTERNAL_ERROR = -32603, + RPC_PARSE_ERROR = -32700, + + // General application defined errors + RPC_MISC_ERROR = -1, // std::exception thrown in command handling + RPC_FORBIDDEN_BY_SAFE_MODE = -2, // Server is in safe mode, and command is not allowed in safe mode + RPC_TYPE_ERROR = -3, // Unexpected type was passed as parameter + RPC_INVALID_ADDRESS_OR_KEY = -5, // Invalid address or key + RPC_OUT_OF_MEMORY = -7, // Ran out of memory during operation + RPC_INVALID_PARAMETER = -8, // Invalid, missing or duplicate parameter + RPC_DATABASE_ERROR = -20, // Database error + RPC_DESERIALIZATION_ERROR = -22, // Error parsing or validating structure in raw format + + // P2P client errors + RPC_CLIENT_NOT_CONNECTED = -9, // Bitcoin is not connected + RPC_CLIENT_IN_INITIAL_DOWNLOAD = -10, // Still downloading initial blocks + + // Wallet errors + RPC_WALLET_ERROR = -4, // Unspecified problem with wallet (key not found etc.) + RPC_WALLET_INSUFFICIENT_FUNDS = -6, // Not enough funds in wallet or account + RPC_WALLET_INVALID_ACCOUNT_NAME = -11, // Invalid account name + RPC_WALLET_KEYPOOL_RAN_OUT = -12, // Keypool ran out, call keypoolrefill first + RPC_WALLET_UNLOCK_NEEDED = -13, // Enter the wallet passphrase with walletpassphrase first + RPC_WALLET_PASSPHRASE_INCORRECT = -14, // The wallet passphrase entered was incorrect + RPC_WALLET_WRONG_ENC_STATE = -15, // Command given in wrong wallet encryption state (encrypting an encrypted wallet etc.) + RPC_WALLET_ENCRYPTION_FAILED = -16, // Failed to encrypt the wallet + RPC_WALLET_ALREADY_UNLOCKED = -17, // Wallet is already unlocked +}; + +json_spirit::Object JSONRPCError(int code, const std::string& message); + +void ThreadRPCServer(void* parg); +int CommandLineRPC(int argc, char *argv[]); + +/** Convert parameter values for RPC call from strings to command-specific JSON objects. */ +json_spirit::Array RPCConvertValues(const std::string &strMethod, const std::vector &strParams); + +/* + Type-check arguments; throws JSONRPCError if wrong type given. Does not check that + the right number of arguments are passed, just that any passed are the correct type. + Use like: RPCTypeCheck(params, boost::assign::list_of(str_type)(int_type)(obj_type)); +*/ +void RPCTypeCheck(const json_spirit::Array& params, + const std::list& typesExpected, bool fAllowNull=false); +/* + Check for expected keys/value types in an Object. + Use like: RPCTypeCheck(object, boost::assign::map_list_of("name", str_type)("value", int_type)); +*/ +void RPCTypeCheck(const json_spirit::Object& o, + const std::map& typesExpected, bool fAllowNull=false); + +typedef json_spirit::Value(*rpcfn_type)(const json_spirit::Array& params, bool fHelp); + +class CRPCCommand +{ +public: + std::string name; + rpcfn_type actor; + bool okSafeMode; + bool unlocked; +}; + +/** + * Bitcoin RPC command dispatcher. + */ +class CRPCTable +{ +private: + std::map mapCommands; +public: + CRPCTable(); + const CRPCCommand* operator[](std::string name) const; + std::string help(std::string name) const; + + /** + * Execute a method. + * @param method Method to execute + * @param params Array of arguments (JSON objects) + * @returns Result of the call. + * @throws an exception (json_spirit::Value) when an error happens. + */ + json_spirit::Value execute(const std::string &method, const json_spirit::Array ¶ms) const; +}; + +extern const CRPCTable tableRPC; + +extern int64 nWalletUnlockTime; +extern int64 AmountFromValue(const json_spirit::Value& value); +extern json_spirit::Value ValueFromAmount(int64 amount); +extern double GetDifficulty(const CBlockIndex* blockindex = NULL); + +extern double GetPoSKernelPS(); + +extern std::string HexBits(unsigned int nBits); +extern std::string HelpRequiringPassphrase(); +extern void EnsureWalletIsUnlocked(); + + +extern json_spirit::Value getconnectioncount(const json_spirit::Array& params, bool fHelp); // in rpcnet.cpp +extern json_spirit::Value getpeerinfo(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value dumpprivkey(const json_spirit::Array& params, bool fHelp); // in rpcdump.cpp +extern json_spirit::Value importprivkey(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value sendalert(const json_spirit::Array& params, bool fHelp); + +extern json_spirit::Value getgenerate(const json_spirit::Array& params, bool fHelp); // in rpcmining.cpp +extern json_spirit::Value setgenerate(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value gethashespersec(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value getmininginfo(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value getwork(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value getworkex(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value getblocktemplate(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value submitblock(const json_spirit::Array& params, bool fHelp); + +extern json_spirit::Value getnewaddress(const json_spirit::Array& params, bool fHelp); // in rpcwallet.cpp +extern json_spirit::Value getaccountaddress(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value setaccount(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value getaccount(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value getaddressesbyaccount(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value sendtoaddress(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value signmessage(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value verifymessage(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value getreceivedbyaddress(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value getreceivedbyaccount(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value getbalance(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value movecmd(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value sendfrom(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value sendmany(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value addmultisigaddress(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value listreceivedbyaddress(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value listreceivedbyaccount(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value listtransactions(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value listaddressgroupings(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value listaccounts(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value listsinceblock(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value gettransaction(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value backupwallet(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value keypoolrefill(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value walletpassphrase(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value walletpassphrasechange(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value walletlock(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value encryptwallet(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value validateaddress(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value getinfo(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value reservebalance(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value checkwallet(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value repairwallet(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value resendtx(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value makekeypair(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value validatepubkey(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value getnewpubkey(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value getnetworkhashps(const json_spirit::Array& params, bool fHelp); + +extern json_spirit::Value getrawtransaction(const json_spirit::Array& params, bool fHelp); // in rcprawtransaction.cpp +extern json_spirit::Value listunspent(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value createrawtransaction(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value decoderawtransaction(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value signrawtransaction(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value sendrawtransaction(const json_spirit::Array& params, bool fHelp); + +extern json_spirit::Value getblockcount(const json_spirit::Array& params, bool fHelp); // in rpcblockchain.cpp +extern json_spirit::Value getdifficulty(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value settxfee(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value getrawmempool(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value getblockhash(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value getblock(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value getblockbynumber(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value getcheckpoint(const json_spirit::Array& params, bool fHelp); + +#endif diff --git a/src/blake.c b/src/blake.c new file mode 100644 index 0000000..0650b9c --- /dev/null +++ b/src/blake.c @@ -0,0 +1,1120 @@ +/* $Id: blake.c 252 2011-06-07 17:55:14Z tp $ */ +/* + * BLAKE implementation. + * + * ==========================(LICENSE BEGIN)============================ + * + * Copyright (c) 2007-2010 Projet RNRT SAPHIR + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * ===========================(LICENSE END)============================= + * + * @author Thomas Pornin + */ + +#include +#include +#include + +#include "sph_blake.h" + +#ifdef __cplusplus +extern "C"{ +#endif + +#if SPH_SMALL_FOOTPRINT && !defined SPH_SMALL_FOOTPRINT_BLAKE +#define SPH_SMALL_FOOTPRINT_BLAKE 1 +#endif + +#if SPH_SMALL_FOOTPRINT_BLAKE +#define SPH_COMPACT_BLAKE_32 1 +#endif + +#if SPH_64 && (SPH_SMALL_FOOTPRINT_BLAKE || !SPH_64_TRUE) +#define SPH_COMPACT_BLAKE_64 1 +#endif + +#ifdef _MSC_VER +#pragma warning (disable: 4146) +#endif + +static const sph_u32 IV224[8] = { + SPH_C32(0xC1059ED8), SPH_C32(0x367CD507), + SPH_C32(0x3070DD17), SPH_C32(0xF70E5939), + SPH_C32(0xFFC00B31), SPH_C32(0x68581511), + SPH_C32(0x64F98FA7), SPH_C32(0xBEFA4FA4) +}; + +static const sph_u32 IV256[8] = { + SPH_C32(0x6A09E667), SPH_C32(0xBB67AE85), + SPH_C32(0x3C6EF372), SPH_C32(0xA54FF53A), + SPH_C32(0x510E527F), SPH_C32(0x9B05688C), + SPH_C32(0x1F83D9AB), SPH_C32(0x5BE0CD19) +}; + +#if SPH_64 + +static const sph_u64 IV384[8] = { + SPH_C64(0xCBBB9D5DC1059ED8), SPH_C64(0x629A292A367CD507), + SPH_C64(0x9159015A3070DD17), SPH_C64(0x152FECD8F70E5939), + SPH_C64(0x67332667FFC00B31), SPH_C64(0x8EB44A8768581511), + SPH_C64(0xDB0C2E0D64F98FA7), SPH_C64(0x47B5481DBEFA4FA4) +}; + +static const sph_u64 IV512[8] = { + SPH_C64(0x6A09E667F3BCC908), SPH_C64(0xBB67AE8584CAA73B), + SPH_C64(0x3C6EF372FE94F82B), SPH_C64(0xA54FF53A5F1D36F1), + SPH_C64(0x510E527FADE682D1), SPH_C64(0x9B05688C2B3E6C1F), + SPH_C64(0x1F83D9ABFB41BD6B), SPH_C64(0x5BE0CD19137E2179) +}; + +#endif + +#if SPH_COMPACT_BLAKE_32 || SPH_COMPACT_BLAKE_64 + +static const unsigned sigma[16][16] = { + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }, + { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 }, + { 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 }, + { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 }, + { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 }, + { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 }, + { 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 }, + { 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 }, + { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 }, + { 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0 }, + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }, + { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 }, + { 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 }, + { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 }, + { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 }, + { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 } +}; + +/* + 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 +*/ +#endif + +#define Z00 0 +#define Z01 1 +#define Z02 2 +#define Z03 3 +#define Z04 4 +#define Z05 5 +#define Z06 6 +#define Z07 7 +#define Z08 8 +#define Z09 9 +#define Z0A A +#define Z0B B +#define Z0C C +#define Z0D D +#define Z0E E +#define Z0F F + +#define Z10 E +#define Z11 A +#define Z12 4 +#define Z13 8 +#define Z14 9 +#define Z15 F +#define Z16 D +#define Z17 6 +#define Z18 1 +#define Z19 C +#define Z1A 0 +#define Z1B 2 +#define Z1C B +#define Z1D 7 +#define Z1E 5 +#define Z1F 3 + +#define Z20 B +#define Z21 8 +#define Z22 C +#define Z23 0 +#define Z24 5 +#define Z25 2 +#define Z26 F +#define Z27 D +#define Z28 A +#define Z29 E +#define Z2A 3 +#define Z2B 6 +#define Z2C 7 +#define Z2D 1 +#define Z2E 9 +#define Z2F 4 + +#define Z30 7 +#define Z31 9 +#define Z32 3 +#define Z33 1 +#define Z34 D +#define Z35 C +#define Z36 B +#define Z37 E +#define Z38 2 +#define Z39 6 +#define Z3A 5 +#define Z3B A +#define Z3C 4 +#define Z3D 0 +#define Z3E F +#define Z3F 8 + +#define Z40 9 +#define Z41 0 +#define Z42 5 +#define Z43 7 +#define Z44 2 +#define Z45 4 +#define Z46 A +#define Z47 F +#define Z48 E +#define Z49 1 +#define Z4A B +#define Z4B C +#define Z4C 6 +#define Z4D 8 +#define Z4E 3 +#define Z4F D + +#define Z50 2 +#define Z51 C +#define Z52 6 +#define Z53 A +#define Z54 0 +#define Z55 B +#define Z56 8 +#define Z57 3 +#define Z58 4 +#define Z59 D +#define Z5A 7 +#define Z5B 5 +#define Z5C F +#define Z5D E +#define Z5E 1 +#define Z5F 9 + +#define Z60 C +#define Z61 5 +#define Z62 1 +#define Z63 F +#define Z64 E +#define Z65 D +#define Z66 4 +#define Z67 A +#define Z68 0 +#define Z69 7 +#define Z6A 6 +#define Z6B 3 +#define Z6C 9 +#define Z6D 2 +#define Z6E 8 +#define Z6F B + +#define Z70 D +#define Z71 B +#define Z72 7 +#define Z73 E +#define Z74 C +#define Z75 1 +#define Z76 3 +#define Z77 9 +#define Z78 5 +#define Z79 0 +#define Z7A F +#define Z7B 4 +#define Z7C 8 +#define Z7D 6 +#define Z7E 2 +#define Z7F A + +#define Z80 6 +#define Z81 F +#define Z82 E +#define Z83 9 +#define Z84 B +#define Z85 3 +#define Z86 0 +#define Z87 8 +#define Z88 C +#define Z89 2 +#define Z8A D +#define Z8B 7 +#define Z8C 1 +#define Z8D 4 +#define Z8E A +#define Z8F 5 + +#define Z90 A +#define Z91 2 +#define Z92 8 +#define Z93 4 +#define Z94 7 +#define Z95 6 +#define Z96 1 +#define Z97 5 +#define Z98 F +#define Z99 B +#define Z9A 9 +#define Z9B E +#define Z9C 3 +#define Z9D C +#define Z9E D +#define Z9F 0 + +#define Mx(r, i) Mx_(Z ## r ## i) +#define Mx_(n) Mx__(n) +#define Mx__(n) M ## n + +#define CSx(r, i) CSx_(Z ## r ## i) +#define CSx_(n) CSx__(n) +#define CSx__(n) CS ## n + +#define CS0 SPH_C32(0x243F6A88) +#define CS1 SPH_C32(0x85A308D3) +#define CS2 SPH_C32(0x13198A2E) +#define CS3 SPH_C32(0x03707344) +#define CS4 SPH_C32(0xA4093822) +#define CS5 SPH_C32(0x299F31D0) +#define CS6 SPH_C32(0x082EFA98) +#define CS7 SPH_C32(0xEC4E6C89) +#define CS8 SPH_C32(0x452821E6) +#define CS9 SPH_C32(0x38D01377) +#define CSA SPH_C32(0xBE5466CF) +#define CSB SPH_C32(0x34E90C6C) +#define CSC SPH_C32(0xC0AC29B7) +#define CSD SPH_C32(0xC97C50DD) +#define CSE SPH_C32(0x3F84D5B5) +#define CSF SPH_C32(0xB5470917) + +#if SPH_COMPACT_BLAKE_32 + +static const sph_u32 CS[16] = { + SPH_C32(0x243F6A88), SPH_C32(0x85A308D3), + SPH_C32(0x13198A2E), SPH_C32(0x03707344), + SPH_C32(0xA4093822), SPH_C32(0x299F31D0), + SPH_C32(0x082EFA98), SPH_C32(0xEC4E6C89), + SPH_C32(0x452821E6), SPH_C32(0x38D01377), + SPH_C32(0xBE5466CF), SPH_C32(0x34E90C6C), + SPH_C32(0xC0AC29B7), SPH_C32(0xC97C50DD), + SPH_C32(0x3F84D5B5), SPH_C32(0xB5470917) +}; + +#endif + +#if SPH_64 + +#define CBx(r, i) CBx_(Z ## r ## i) +#define CBx_(n) CBx__(n) +#define CBx__(n) CB ## n + +#define CB0 SPH_C64(0x243F6A8885A308D3) +#define CB1 SPH_C64(0x13198A2E03707344) +#define CB2 SPH_C64(0xA4093822299F31D0) +#define CB3 SPH_C64(0x082EFA98EC4E6C89) +#define CB4 SPH_C64(0x452821E638D01377) +#define CB5 SPH_C64(0xBE5466CF34E90C6C) +#define CB6 SPH_C64(0xC0AC29B7C97C50DD) +#define CB7 SPH_C64(0x3F84D5B5B5470917) +#define CB8 SPH_C64(0x9216D5D98979FB1B) +#define CB9 SPH_C64(0xD1310BA698DFB5AC) +#define CBA SPH_C64(0x2FFD72DBD01ADFB7) +#define CBB SPH_C64(0xB8E1AFED6A267E96) +#define CBC SPH_C64(0xBA7C9045F12C7F99) +#define CBD SPH_C64(0x24A19947B3916CF7) +#define CBE SPH_C64(0x0801F2E2858EFC16) +#define CBF SPH_C64(0x636920D871574E69) + +#if SPH_COMPACT_BLAKE_64 + +static const sph_u64 CB[16] = { + SPH_C64(0x243F6A8885A308D3), SPH_C64(0x13198A2E03707344), + SPH_C64(0xA4093822299F31D0), SPH_C64(0x082EFA98EC4E6C89), + SPH_C64(0x452821E638D01377), SPH_C64(0xBE5466CF34E90C6C), + SPH_C64(0xC0AC29B7C97C50DD), SPH_C64(0x3F84D5B5B5470917), + SPH_C64(0x9216D5D98979FB1B), SPH_C64(0xD1310BA698DFB5AC), + SPH_C64(0x2FFD72DBD01ADFB7), SPH_C64(0xB8E1AFED6A267E96), + SPH_C64(0xBA7C9045F12C7F99), SPH_C64(0x24A19947B3916CF7), + SPH_C64(0x0801F2E2858EFC16), SPH_C64(0x636920D871574E69) +}; + +#endif + +#endif + +#define GS(m0, m1, c0, c1, a, b, c, d) do { \ + a = SPH_T32(a + b + (m0 ^ c1)); \ + d = SPH_ROTR32(d ^ a, 16); \ + c = SPH_T32(c + d); \ + b = SPH_ROTR32(b ^ c, 12); \ + a = SPH_T32(a + b + (m1 ^ c0)); \ + d = SPH_ROTR32(d ^ a, 8); \ + c = SPH_T32(c + d); \ + b = SPH_ROTR32(b ^ c, 7); \ + } while (0) + +#if SPH_COMPACT_BLAKE_32 + +#define ROUND_S(r) do { \ + GS(M[sigma[r][0x0]], M[sigma[r][0x1]], \ + CS[sigma[r][0x0]], CS[sigma[r][0x1]], V0, V4, V8, VC); \ + GS(M[sigma[r][0x2]], M[sigma[r][0x3]], \ + CS[sigma[r][0x2]], CS[sigma[r][0x3]], V1, V5, V9, VD); \ + GS(M[sigma[r][0x4]], M[sigma[r][0x5]], \ + CS[sigma[r][0x4]], CS[sigma[r][0x5]], V2, V6, VA, VE); \ + GS(M[sigma[r][0x6]], M[sigma[r][0x7]], \ + CS[sigma[r][0x6]], CS[sigma[r][0x7]], V3, V7, VB, VF); \ + GS(M[sigma[r][0x8]], M[sigma[r][0x9]], \ + CS[sigma[r][0x8]], CS[sigma[r][0x9]], V0, V5, VA, VF); \ + GS(M[sigma[r][0xA]], M[sigma[r][0xB]], \ + CS[sigma[r][0xA]], CS[sigma[r][0xB]], V1, V6, VB, VC); \ + GS(M[sigma[r][0xC]], M[sigma[r][0xD]], \ + CS[sigma[r][0xC]], CS[sigma[r][0xD]], V2, V7, V8, VD); \ + GS(M[sigma[r][0xE]], M[sigma[r][0xF]], \ + CS[sigma[r][0xE]], CS[sigma[r][0xF]], V3, V4, V9, VE); \ + } while (0) + +#else + +#define ROUND_S(r) do { \ + GS(Mx(r, 0), Mx(r, 1), CSx(r, 0), CSx(r, 1), V0, V4, V8, VC); \ + GS(Mx(r, 2), Mx(r, 3), CSx(r, 2), CSx(r, 3), V1, V5, V9, VD); \ + GS(Mx(r, 4), Mx(r, 5), CSx(r, 4), CSx(r, 5), V2, V6, VA, VE); \ + GS(Mx(r, 6), Mx(r, 7), CSx(r, 6), CSx(r, 7), V3, V7, VB, VF); \ + GS(Mx(r, 8), Mx(r, 9), CSx(r, 8), CSx(r, 9), V0, V5, VA, VF); \ + GS(Mx(r, A), Mx(r, B), CSx(r, A), CSx(r, B), V1, V6, VB, VC); \ + GS(Mx(r, C), Mx(r, D), CSx(r, C), CSx(r, D), V2, V7, V8, VD); \ + GS(Mx(r, E), Mx(r, F), CSx(r, E), CSx(r, F), V3, V4, V9, VE); \ + } while (0) + +#endif + +#if SPH_64 + +#define GB(m0, m1, c0, c1, a, b, c, d) do { \ + a = SPH_T64(a + b + (m0 ^ c1)); \ + d = SPH_ROTR64(d ^ a, 32); \ + c = SPH_T64(c + d); \ + b = SPH_ROTR64(b ^ c, 25); \ + a = SPH_T64(a + b + (m1 ^ c0)); \ + d = SPH_ROTR64(d ^ a, 16); \ + c = SPH_T64(c + d); \ + b = SPH_ROTR64(b ^ c, 11); \ + } while (0) + +#if SPH_COMPACT_BLAKE_64 + +#define ROUND_B(r) do { \ + GB(M[sigma[r][0x0]], M[sigma[r][0x1]], \ + CB[sigma[r][0x0]], CB[sigma[r][0x1]], V0, V4, V8, VC); \ + GB(M[sigma[r][0x2]], M[sigma[r][0x3]], \ + CB[sigma[r][0x2]], CB[sigma[r][0x3]], V1, V5, V9, VD); \ + GB(M[sigma[r][0x4]], M[sigma[r][0x5]], \ + CB[sigma[r][0x4]], CB[sigma[r][0x5]], V2, V6, VA, VE); \ + GB(M[sigma[r][0x6]], M[sigma[r][0x7]], \ + CB[sigma[r][0x6]], CB[sigma[r][0x7]], V3, V7, VB, VF); \ + GB(M[sigma[r][0x8]], M[sigma[r][0x9]], \ + CB[sigma[r][0x8]], CB[sigma[r][0x9]], V0, V5, VA, VF); \ + GB(M[sigma[r][0xA]], M[sigma[r][0xB]], \ + CB[sigma[r][0xA]], CB[sigma[r][0xB]], V1, V6, VB, VC); \ + GB(M[sigma[r][0xC]], M[sigma[r][0xD]], \ + CB[sigma[r][0xC]], CB[sigma[r][0xD]], V2, V7, V8, VD); \ + GB(M[sigma[r][0xE]], M[sigma[r][0xF]], \ + CB[sigma[r][0xE]], CB[sigma[r][0xF]], V3, V4, V9, VE); \ + } while (0) + +#else + +#define ROUND_B(r) do { \ + GB(Mx(r, 0), Mx(r, 1), CBx(r, 0), CBx(r, 1), V0, V4, V8, VC); \ + GB(Mx(r, 2), Mx(r, 3), CBx(r, 2), CBx(r, 3), V1, V5, V9, VD); \ + GB(Mx(r, 4), Mx(r, 5), CBx(r, 4), CBx(r, 5), V2, V6, VA, VE); \ + GB(Mx(r, 6), Mx(r, 7), CBx(r, 6), CBx(r, 7), V3, V7, VB, VF); \ + GB(Mx(r, 8), Mx(r, 9), CBx(r, 8), CBx(r, 9), V0, V5, VA, VF); \ + GB(Mx(r, A), Mx(r, B), CBx(r, A), CBx(r, B), V1, V6, VB, VC); \ + GB(Mx(r, C), Mx(r, D), CBx(r, C), CBx(r, D), V2, V7, V8, VD); \ + GB(Mx(r, E), Mx(r, F), CBx(r, E), CBx(r, F), V3, V4, V9, VE); \ + } while (0) + +#endif + +#endif + +#define DECL_STATE32 \ + sph_u32 H0, H1, H2, H3, H4, H5, H6, H7; \ + sph_u32 S0, S1, S2, S3, T0, T1; + +#define READ_STATE32(state) do { \ + H0 = (state)->H[0]; \ + H1 = (state)->H[1]; \ + H2 = (state)->H[2]; \ + H3 = (state)->H[3]; \ + H4 = (state)->H[4]; \ + H5 = (state)->H[5]; \ + H6 = (state)->H[6]; \ + H7 = (state)->H[7]; \ + S0 = (state)->S[0]; \ + S1 = (state)->S[1]; \ + S2 = (state)->S[2]; \ + S3 = (state)->S[3]; \ + T0 = (state)->T0; \ + T1 = (state)->T1; \ + } while (0) + +#define WRITE_STATE32(state) do { \ + (state)->H[0] = H0; \ + (state)->H[1] = H1; \ + (state)->H[2] = H2; \ + (state)->H[3] = H3; \ + (state)->H[4] = H4; \ + (state)->H[5] = H5; \ + (state)->H[6] = H6; \ + (state)->H[7] = H7; \ + (state)->S[0] = S0; \ + (state)->S[1] = S1; \ + (state)->S[2] = S2; \ + (state)->S[3] = S3; \ + (state)->T0 = T0; \ + (state)->T1 = T1; \ + } while (0) + +#if SPH_COMPACT_BLAKE_32 + +#define COMPRESS32 do { \ + sph_u32 M[16]; \ + sph_u32 V0, V1, V2, V3, V4, V5, V6, V7; \ + sph_u32 V8, V9, VA, VB, VC, VD, VE, VF; \ + unsigned r; \ + V0 = H0; \ + V1 = H1; \ + V2 = H2; \ + V3 = H3; \ + V4 = H4; \ + V5 = H5; \ + V6 = H6; \ + V7 = H7; \ + V8 = S0 ^ CS0; \ + V9 = S1 ^ CS1; \ + VA = S2 ^ CS2; \ + VB = S3 ^ CS3; \ + VC = T0 ^ CS4; \ + VD = T0 ^ CS5; \ + VE = T1 ^ CS6; \ + VF = T1 ^ CS7; \ + M[0x0] = sph_dec32be_aligned(buf + 0); \ + M[0x1] = sph_dec32be_aligned(buf + 4); \ + M[0x2] = sph_dec32be_aligned(buf + 8); \ + M[0x3] = sph_dec32be_aligned(buf + 12); \ + M[0x4] = sph_dec32be_aligned(buf + 16); \ + M[0x5] = sph_dec32be_aligned(buf + 20); \ + M[0x6] = sph_dec32be_aligned(buf + 24); \ + M[0x7] = sph_dec32be_aligned(buf + 28); \ + M[0x8] = sph_dec32be_aligned(buf + 32); \ + M[0x9] = sph_dec32be_aligned(buf + 36); \ + M[0xA] = sph_dec32be_aligned(buf + 40); \ + M[0xB] = sph_dec32be_aligned(buf + 44); \ + M[0xC] = sph_dec32be_aligned(buf + 48); \ + M[0xD] = sph_dec32be_aligned(buf + 52); \ + M[0xE] = sph_dec32be_aligned(buf + 56); \ + M[0xF] = sph_dec32be_aligned(buf + 60); \ + for (r = 0; r < 14; r ++) \ + ROUND_S(r); \ + H0 ^= S0 ^ V0 ^ V8; \ + H1 ^= S1 ^ V1 ^ V9; \ + H2 ^= S2 ^ V2 ^ VA; \ + H3 ^= S3 ^ V3 ^ VB; \ + H4 ^= S0 ^ V4 ^ VC; \ + H5 ^= S1 ^ V5 ^ VD; \ + H6 ^= S2 ^ V6 ^ VE; \ + H7 ^= S3 ^ V7 ^ VF; \ + } while (0) + +#else + +#define COMPRESS32 do { \ + sph_u32 M0, M1, M2, M3, M4, M5, M6, M7; \ + sph_u32 M8, M9, MA, MB, MC, MD, ME, MF; \ + sph_u32 V0, V1, V2, V3, V4, V5, V6, V7; \ + sph_u32 V8, V9, VA, VB, VC, VD, VE, VF; \ + V0 = H0; \ + V1 = H1; \ + V2 = H2; \ + V3 = H3; \ + V4 = H4; \ + V5 = H5; \ + V6 = H6; \ + V7 = H7; \ + V8 = S0 ^ CS0; \ + V9 = S1 ^ CS1; \ + VA = S2 ^ CS2; \ + VB = S3 ^ CS3; \ + VC = T0 ^ CS4; \ + VD = T0 ^ CS5; \ + VE = T1 ^ CS6; \ + VF = T1 ^ CS7; \ + M0 = sph_dec32be_aligned(buf + 0); \ + M1 = sph_dec32be_aligned(buf + 4); \ + M2 = sph_dec32be_aligned(buf + 8); \ + M3 = sph_dec32be_aligned(buf + 12); \ + M4 = sph_dec32be_aligned(buf + 16); \ + M5 = sph_dec32be_aligned(buf + 20); \ + M6 = sph_dec32be_aligned(buf + 24); \ + M7 = sph_dec32be_aligned(buf + 28); \ + M8 = sph_dec32be_aligned(buf + 32); \ + M9 = sph_dec32be_aligned(buf + 36); \ + MA = sph_dec32be_aligned(buf + 40); \ + MB = sph_dec32be_aligned(buf + 44); \ + MC = sph_dec32be_aligned(buf + 48); \ + MD = sph_dec32be_aligned(buf + 52); \ + ME = sph_dec32be_aligned(buf + 56); \ + MF = sph_dec32be_aligned(buf + 60); \ + ROUND_S(0); \ + ROUND_S(1); \ + ROUND_S(2); \ + ROUND_S(3); \ + ROUND_S(4); \ + ROUND_S(5); \ + ROUND_S(6); \ + ROUND_S(7); \ + ROUND_S(8); \ + ROUND_S(9); \ + ROUND_S(0); \ + ROUND_S(1); \ + ROUND_S(2); \ + ROUND_S(3); \ + H0 ^= S0 ^ V0 ^ V8; \ + H1 ^= S1 ^ V1 ^ V9; \ + H2 ^= S2 ^ V2 ^ VA; \ + H3 ^= S3 ^ V3 ^ VB; \ + H4 ^= S0 ^ V4 ^ VC; \ + H5 ^= S1 ^ V5 ^ VD; \ + H6 ^= S2 ^ V6 ^ VE; \ + H7 ^= S3 ^ V7 ^ VF; \ + } while (0) + +#endif + +#if SPH_64 + +#define DECL_STATE64 \ + sph_u64 H0, H1, H2, H3, H4, H5, H6, H7; \ + sph_u64 S0, S1, S2, S3, T0, T1; + +#define READ_STATE64(state) do { \ + H0 = (state)->H[0]; \ + H1 = (state)->H[1]; \ + H2 = (state)->H[2]; \ + H3 = (state)->H[3]; \ + H4 = (state)->H[4]; \ + H5 = (state)->H[5]; \ + H6 = (state)->H[6]; \ + H7 = (state)->H[7]; \ + S0 = (state)->S[0]; \ + S1 = (state)->S[1]; \ + S2 = (state)->S[2]; \ + S3 = (state)->S[3]; \ + T0 = (state)->T0; \ + T1 = (state)->T1; \ + } while (0) + +#define WRITE_STATE64(state) do { \ + (state)->H[0] = H0; \ + (state)->H[1] = H1; \ + (state)->H[2] = H2; \ + (state)->H[3] = H3; \ + (state)->H[4] = H4; \ + (state)->H[5] = H5; \ + (state)->H[6] = H6; \ + (state)->H[7] = H7; \ + (state)->S[0] = S0; \ + (state)->S[1] = S1; \ + (state)->S[2] = S2; \ + (state)->S[3] = S3; \ + (state)->T0 = T0; \ + (state)->T1 = T1; \ + } while (0) + +#if SPH_COMPACT_BLAKE_64 + +#define COMPRESS64 do { \ + sph_u64 M[16]; \ + sph_u64 V0, V1, V2, V3, V4, V5, V6, V7; \ + sph_u64 V8, V9, VA, VB, VC, VD, VE, VF; \ + unsigned r; \ + V0 = H0; \ + V1 = H1; \ + V2 = H2; \ + V3 = H3; \ + V4 = H4; \ + V5 = H5; \ + V6 = H6; \ + V7 = H7; \ + V8 = S0 ^ CB0; \ + V9 = S1 ^ CB1; \ + VA = S2 ^ CB2; \ + VB = S3 ^ CB3; \ + VC = T0 ^ CB4; \ + VD = T0 ^ CB5; \ + VE = T1 ^ CB6; \ + VF = T1 ^ CB7; \ + M[0x0] = sph_dec64be_aligned(buf + 0); \ + M[0x1] = sph_dec64be_aligned(buf + 8); \ + M[0x2] = sph_dec64be_aligned(buf + 16); \ + M[0x3] = sph_dec64be_aligned(buf + 24); \ + M[0x4] = sph_dec64be_aligned(buf + 32); \ + M[0x5] = sph_dec64be_aligned(buf + 40); \ + M[0x6] = sph_dec64be_aligned(buf + 48); \ + M[0x7] = sph_dec64be_aligned(buf + 56); \ + M[0x8] = sph_dec64be_aligned(buf + 64); \ + M[0x9] = sph_dec64be_aligned(buf + 72); \ + M[0xA] = sph_dec64be_aligned(buf + 80); \ + M[0xB] = sph_dec64be_aligned(buf + 88); \ + M[0xC] = sph_dec64be_aligned(buf + 96); \ + M[0xD] = sph_dec64be_aligned(buf + 104); \ + M[0xE] = sph_dec64be_aligned(buf + 112); \ + M[0xF] = sph_dec64be_aligned(buf + 120); \ + for (r = 0; r < 16; r ++) \ + ROUND_B(r); \ + H0 ^= S0 ^ V0 ^ V8; \ + H1 ^= S1 ^ V1 ^ V9; \ + H2 ^= S2 ^ V2 ^ VA; \ + H3 ^= S3 ^ V3 ^ VB; \ + H4 ^= S0 ^ V4 ^ VC; \ + H5 ^= S1 ^ V5 ^ VD; \ + H6 ^= S2 ^ V6 ^ VE; \ + H7 ^= S3 ^ V7 ^ VF; \ + } while (0) + +#else + +#define COMPRESS64 do { \ + sph_u64 M0, M1, M2, M3, M4, M5, M6, M7; \ + sph_u64 M8, M9, MA, MB, MC, MD, ME, MF; \ + sph_u64 V0, V1, V2, V3, V4, V5, V6, V7; \ + sph_u64 V8, V9, VA, VB, VC, VD, VE, VF; \ + V0 = H0; \ + V1 = H1; \ + V2 = H2; \ + V3 = H3; \ + V4 = H4; \ + V5 = H5; \ + V6 = H6; \ + V7 = H7; \ + V8 = S0 ^ CB0; \ + V9 = S1 ^ CB1; \ + VA = S2 ^ CB2; \ + VB = S3 ^ CB3; \ + VC = T0 ^ CB4; \ + VD = T0 ^ CB5; \ + VE = T1 ^ CB6; \ + VF = T1 ^ CB7; \ + M0 = sph_dec64be_aligned(buf + 0); \ + M1 = sph_dec64be_aligned(buf + 8); \ + M2 = sph_dec64be_aligned(buf + 16); \ + M3 = sph_dec64be_aligned(buf + 24); \ + M4 = sph_dec64be_aligned(buf + 32); \ + M5 = sph_dec64be_aligned(buf + 40); \ + M6 = sph_dec64be_aligned(buf + 48); \ + M7 = sph_dec64be_aligned(buf + 56); \ + M8 = sph_dec64be_aligned(buf + 64); \ + M9 = sph_dec64be_aligned(buf + 72); \ + MA = sph_dec64be_aligned(buf + 80); \ + MB = sph_dec64be_aligned(buf + 88); \ + MC = sph_dec64be_aligned(buf + 96); \ + MD = sph_dec64be_aligned(buf + 104); \ + ME = sph_dec64be_aligned(buf + 112); \ + MF = sph_dec64be_aligned(buf + 120); \ + ROUND_B(0); \ + ROUND_B(1); \ + ROUND_B(2); \ + ROUND_B(3); \ + ROUND_B(4); \ + ROUND_B(5); \ + ROUND_B(6); \ + ROUND_B(7); \ + ROUND_B(8); \ + ROUND_B(9); \ + ROUND_B(0); \ + ROUND_B(1); \ + ROUND_B(2); \ + ROUND_B(3); \ + ROUND_B(4); \ + ROUND_B(5); \ + H0 ^= S0 ^ V0 ^ V8; \ + H1 ^= S1 ^ V1 ^ V9; \ + H2 ^= S2 ^ V2 ^ VA; \ + H3 ^= S3 ^ V3 ^ VB; \ + H4 ^= S0 ^ V4 ^ VC; \ + H5 ^= S1 ^ V5 ^ VD; \ + H6 ^= S2 ^ V6 ^ VE; \ + H7 ^= S3 ^ V7 ^ VF; \ + } while (0) + +#endif + +#endif + +static const sph_u32 salt_zero_small[4] = { 0, 0, 0, 0 }; + +static void +blake32_init(sph_blake_small_context *sc, + const sph_u32 *iv, const sph_u32 *salt) +{ + memcpy(sc->H, iv, 8 * sizeof(sph_u32)); + memcpy(sc->S, salt, 4 * sizeof(sph_u32)); + sc->T0 = sc->T1 = 0; + sc->ptr = 0; +} + +static void +blake32(sph_blake_small_context *sc, const void *data, size_t len) +{ + unsigned char *buf; + size_t ptr; + DECL_STATE32 + + buf = sc->buf; + ptr = sc->ptr; + if (len < (sizeof sc->buf) - ptr) { + memcpy(buf + ptr, data, len); + ptr += len; + sc->ptr = ptr; + return; + } + + READ_STATE32(sc); + while (len > 0) { + size_t clen; + + clen = (sizeof sc->buf) - ptr; + if (clen > len) + clen = len; + memcpy(buf + ptr, data, clen); + ptr += clen; + data = (const unsigned char *)data + clen; + len -= clen; + if (ptr == sizeof sc->buf) { + if ((T0 = SPH_T32(T0 + 512)) < 512) + T1 = SPH_T32(T1 + 1); + COMPRESS32; + ptr = 0; + } + } + WRITE_STATE32(sc); + sc->ptr = ptr; +} + +static void +blake32_close(sph_blake_small_context *sc, + unsigned ub, unsigned n, void *dst, size_t out_size_w32) +{ + union { + unsigned char buf[64]; + sph_u32 dummy; + } u; + size_t ptr, k; + unsigned bit_len; + unsigned z; + sph_u32 th, tl; + unsigned char *out; + + ptr = sc->ptr; + bit_len = ((unsigned)ptr << 3) + n; + z = 0x80 >> n; + u.buf[ptr] = ((ub & -z) | z) & 0xFF; + tl = sc->T0 + bit_len; + th = sc->T1; + if (ptr == 0 && n == 0) { + sc->T0 = SPH_C32(0xFFFFFE00); + sc->T1 = SPH_C32(0xFFFFFFFF); + } else if (sc->T0 == 0) { + sc->T0 = SPH_C32(0xFFFFFE00) + bit_len; + sc->T1 = SPH_T32(sc->T1 - 1); + } else { + sc->T0 -= 512 - bit_len; + } + if (bit_len <= 446) { + memset(u.buf + ptr + 1, 0, 55 - ptr); + if (out_size_w32 == 8) + u.buf[55] |= 1; + sph_enc32be_aligned(u.buf + 56, th); + sph_enc32be_aligned(u.buf + 60, tl); + blake32(sc, u.buf + ptr, 64 - ptr); + } else { + memset(u.buf + ptr + 1, 0, 63 - ptr); + blake32(sc, u.buf + ptr, 64 - ptr); + sc->T0 = SPH_C32(0xFFFFFE00); + sc->T1 = SPH_C32(0xFFFFFFFF); + memset(u.buf, 0, 56); + if (out_size_w32 == 8) + u.buf[55] = 1; + sph_enc32be_aligned(u.buf + 56, th); + sph_enc32be_aligned(u.buf + 60, tl); + blake32(sc, u.buf, 64); + } + out = dst; + for (k = 0; k < out_size_w32; k ++) + sph_enc32be(out + (k << 2), sc->H[k]); +} + +#if SPH_64 + +static const sph_u64 salt_zero_big[4] = { 0, 0, 0, 0 }; + +static void +blake64_init(sph_blake_big_context *sc, + const sph_u64 *iv, const sph_u64 *salt) +{ + memcpy(sc->H, iv, 8 * sizeof(sph_u64)); + memcpy(sc->S, salt, 4 * sizeof(sph_u64)); + sc->T0 = sc->T1 = 0; + sc->ptr = 0; +} + +static void +blake64(sph_blake_big_context *sc, const void *data, size_t len) +{ + unsigned char *buf; + size_t ptr; + DECL_STATE64 + + buf = sc->buf; + ptr = sc->ptr; + if (len < (sizeof sc->buf) - ptr) { + memcpy(buf + ptr, data, len); + ptr += len; + sc->ptr = ptr; + return; + } + + READ_STATE64(sc); + while (len > 0) { + size_t clen; + + clen = (sizeof sc->buf) - ptr; + if (clen > len) + clen = len; + memcpy(buf + ptr, data, clen); + ptr += clen; + data = (const unsigned char *)data + clen; + len -= clen; + if (ptr == sizeof sc->buf) { + if ((T0 = SPH_T64(T0 + 1024)) < 1024) + T1 = SPH_T64(T1 + 1); + COMPRESS64; + ptr = 0; + } + } + WRITE_STATE64(sc); + sc->ptr = ptr; +} + +static void +blake64_close(sph_blake_big_context *sc, + unsigned ub, unsigned n, void *dst, size_t out_size_w64) +{ + union { + unsigned char buf[128]; + sph_u64 dummy; + } u; + size_t ptr, k; + unsigned bit_len; + unsigned z; + sph_u64 th, tl; + unsigned char *out; + + ptr = sc->ptr; + bit_len = ((unsigned)ptr << 3) + n; + z = 0x80 >> n; + u.buf[ptr] = ((ub & -z) | z) & 0xFF; + tl = sc->T0 + bit_len; + th = sc->T1; + if (ptr == 0 && n == 0) { + sc->T0 = SPH_C64(0xFFFFFFFFFFFFFC00); + sc->T1 = SPH_C64(0xFFFFFFFFFFFFFFFF); + } else if (sc->T0 == 0) { + sc->T0 = SPH_C64(0xFFFFFFFFFFFFFC00) + bit_len; + sc->T1 = SPH_T64(sc->T1 - 1); + } else { + sc->T0 -= 1024 - bit_len; + } + if (bit_len <= 894) { + memset(u.buf + ptr + 1, 0, 111 - ptr); + if (out_size_w64 == 8) + u.buf[111] |= 1; + sph_enc64be_aligned(u.buf + 112, th); + sph_enc64be_aligned(u.buf + 120, tl); + blake64(sc, u.buf + ptr, 128 - ptr); + } else { + memset(u.buf + ptr + 1, 0, 127 - ptr); + blake64(sc, u.buf + ptr, 128 - ptr); + sc->T0 = SPH_C64(0xFFFFFFFFFFFFFC00); + sc->T1 = SPH_C64(0xFFFFFFFFFFFFFFFF); + memset(u.buf, 0, 112); + if (out_size_w64 == 8) + u.buf[111] = 1; + sph_enc64be_aligned(u.buf + 112, th); + sph_enc64be_aligned(u.buf + 120, tl); + blake64(sc, u.buf, 128); + } + out = dst; + for (k = 0; k < out_size_w64; k ++) + sph_enc64be(out + (k << 3), sc->H[k]); +} + +#endif + +/* see sph_blake.h */ +void +sph_blake224_init(void *cc) +{ + blake32_init(cc, IV224, salt_zero_small); +} + +/* see sph_blake.h */ +void +sph_blake224(void *cc, const void *data, size_t len) +{ + blake32(cc, data, len); +} + +/* see sph_blake.h */ +void +sph_blake224_close(void *cc, void *dst) +{ + sph_blake224_addbits_and_close(cc, 0, 0, dst); +} + +/* see sph_blake.h */ +void +sph_blake224_addbits_and_close(void *cc, unsigned ub, unsigned n, void *dst) +{ + blake32_close(cc, ub, n, dst, 7); + sph_blake224_init(cc); +} + +/* see sph_blake.h */ +void +sph_blake256_init(void *cc) +{ + blake32_init(cc, IV256, salt_zero_small); +} + +/* see sph_blake.h */ +void +sph_blake256(void *cc, const void *data, size_t len) +{ + blake32(cc, data, len); +} + +/* see sph_blake.h */ +void +sph_blake256_close(void *cc, void *dst) +{ + sph_blake256_addbits_and_close(cc, 0, 0, dst); +} + +/* see sph_blake.h */ +void +sph_blake256_addbits_and_close(void *cc, unsigned ub, unsigned n, void *dst) +{ + blake32_close(cc, ub, n, dst, 8); + sph_blake256_init(cc); +} + +#if SPH_64 + +/* see sph_blake.h */ +void +sph_blake384_init(void *cc) +{ + blake64_init(cc, IV384, salt_zero_big); +} + +/* see sph_blake.h */ +void +sph_blake384(void *cc, const void *data, size_t len) +{ + blake64(cc, data, len); +} + +/* see sph_blake.h */ +void +sph_blake384_close(void *cc, void *dst) +{ + sph_blake384_addbits_and_close(cc, 0, 0, dst); +} + +/* see sph_blake.h */ +void +sph_blake384_addbits_and_close(void *cc, unsigned ub, unsigned n, void *dst) +{ + blake64_close(cc, ub, n, dst, 6); + sph_blake384_init(cc); +} + +/* see sph_blake.h */ +void +sph_blake512_init(void *cc) +{ + blake64_init(cc, IV512, salt_zero_big); +} + +/* see sph_blake.h */ +void +sph_blake512(void *cc, const void *data, size_t len) +{ + blake64(cc, data, len); +} + +/* see sph_blake.h */ +void +sph_blake512_close(void *cc, void *dst) +{ + sph_blake512_addbits_and_close(cc, 0, 0, dst); +} + +/* see sph_blake.h */ +void +sph_blake512_addbits_and_close(void *cc, unsigned ub, unsigned n, void *dst) +{ + blake64_close(cc, ub, n, dst, 8); + sph_blake512_init(cc); +} + +#endif + +#ifdef __cplusplus +} +#endif diff --git a/src/bmw.c b/src/bmw.c new file mode 100644 index 0000000..b89a881 --- /dev/null +++ b/src/bmw.c @@ -0,0 +1,965 @@ +/* $Id: bmw.c 227 2010-06-16 17:28:38Z tp $ */ +/* + * BMW implementation. + * + * ==========================(LICENSE BEGIN)============================ + * + * Copyright (c) 2007-2010 Projet RNRT SAPHIR + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * ===========================(LICENSE END)============================= + * + * @author Thomas Pornin + */ + +#include +#include +#include + +#ifdef __cplusplus +extern "C"{ +#endif + +#include "sph_bmw.h" + +#if SPH_SMALL_FOOTPRINT && !defined SPH_SMALL_FOOTPRINT_BMW +#define SPH_SMALL_FOOTPRINT_BMW 1 +#endif + +#ifdef _MSC_VER +#pragma warning (disable: 4146) +#endif + +static const sph_u32 IV224[] = { + SPH_C32(0x00010203), SPH_C32(0x04050607), + SPH_C32(0x08090A0B), SPH_C32(0x0C0D0E0F), + SPH_C32(0x10111213), SPH_C32(0x14151617), + SPH_C32(0x18191A1B), SPH_C32(0x1C1D1E1F), + SPH_C32(0x20212223), SPH_C32(0x24252627), + SPH_C32(0x28292A2B), SPH_C32(0x2C2D2E2F), + SPH_C32(0x30313233), SPH_C32(0x34353637), + SPH_C32(0x38393A3B), SPH_C32(0x3C3D3E3F) +}; + +static const sph_u32 IV256[] = { + SPH_C32(0x40414243), SPH_C32(0x44454647), + SPH_C32(0x48494A4B), SPH_C32(0x4C4D4E4F), + SPH_C32(0x50515253), SPH_C32(0x54555657), + SPH_C32(0x58595A5B), SPH_C32(0x5C5D5E5F), + SPH_C32(0x60616263), SPH_C32(0x64656667), + SPH_C32(0x68696A6B), SPH_C32(0x6C6D6E6F), + SPH_C32(0x70717273), SPH_C32(0x74757677), + SPH_C32(0x78797A7B), SPH_C32(0x7C7D7E7F) +}; + +#if SPH_64 + +static const sph_u64 IV384[] = { + SPH_C64(0x0001020304050607), SPH_C64(0x08090A0B0C0D0E0F), + SPH_C64(0x1011121314151617), SPH_C64(0x18191A1B1C1D1E1F), + SPH_C64(0x2021222324252627), SPH_C64(0x28292A2B2C2D2E2F), + SPH_C64(0x3031323334353637), SPH_C64(0x38393A3B3C3D3E3F), + SPH_C64(0x4041424344454647), SPH_C64(0x48494A4B4C4D4E4F), + SPH_C64(0x5051525354555657), SPH_C64(0x58595A5B5C5D5E5F), + SPH_C64(0x6061626364656667), SPH_C64(0x68696A6B6C6D6E6F), + SPH_C64(0x7071727374757677), SPH_C64(0x78797A7B7C7D7E7F) +}; + +static const sph_u64 IV512[] = { + SPH_C64(0x8081828384858687), SPH_C64(0x88898A8B8C8D8E8F), + SPH_C64(0x9091929394959697), SPH_C64(0x98999A9B9C9D9E9F), + SPH_C64(0xA0A1A2A3A4A5A6A7), SPH_C64(0xA8A9AAABACADAEAF), + SPH_C64(0xB0B1B2B3B4B5B6B7), SPH_C64(0xB8B9BABBBCBDBEBF), + SPH_C64(0xC0C1C2C3C4C5C6C7), SPH_C64(0xC8C9CACBCCCDCECF), + SPH_C64(0xD0D1D2D3D4D5D6D7), SPH_C64(0xD8D9DADBDCDDDEDF), + SPH_C64(0xE0E1E2E3E4E5E6E7), SPH_C64(0xE8E9EAEBECEDEEEF), + SPH_C64(0xF0F1F2F3F4F5F6F7), SPH_C64(0xF8F9FAFBFCFDFEFF) +}; + +#endif + +#define XCAT(x, y) XCAT_(x, y) +#define XCAT_(x, y) x ## y + +#define LPAR ( + +#define I16_16 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 +#define I16_17 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 +#define I16_18 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17 +#define I16_19 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18 +#define I16_20 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 +#define I16_21 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 +#define I16_22 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21 +#define I16_23 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22 +#define I16_24 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23 +#define I16_25 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24 +#define I16_26 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25 +#define I16_27 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26 +#define I16_28 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27 +#define I16_29 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28 +#define I16_30 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29 +#define I16_31 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30 + +#define M16_16 0, 1, 3, 4, 7, 10, 11 +#define M16_17 1, 2, 4, 5, 8, 11, 12 +#define M16_18 2, 3, 5, 6, 9, 12, 13 +#define M16_19 3, 4, 6, 7, 10, 13, 14 +#define M16_20 4, 5, 7, 8, 11, 14, 15 +#define M16_21 5, 6, 8, 9, 12, 15, 16 +#define M16_22 6, 7, 9, 10, 13, 0, 1 +#define M16_23 7, 8, 10, 11, 14, 1, 2 +#define M16_24 8, 9, 11, 12, 15, 2, 3 +#define M16_25 9, 10, 12, 13, 0, 3, 4 +#define M16_26 10, 11, 13, 14, 1, 4, 5 +#define M16_27 11, 12, 14, 15, 2, 5, 6 +#define M16_28 12, 13, 15, 16, 3, 6, 7 +#define M16_29 13, 14, 0, 1, 4, 7, 8 +#define M16_30 14, 15, 1, 2, 5, 8, 9 +#define M16_31 15, 16, 2, 3, 6, 9, 10 + +#define ss0(x) (((x) >> 1) ^ SPH_T32((x) << 3) \ + ^ SPH_ROTL32(x, 4) ^ SPH_ROTL32(x, 19)) +#define ss1(x) (((x) >> 1) ^ SPH_T32((x) << 2) \ + ^ SPH_ROTL32(x, 8) ^ SPH_ROTL32(x, 23)) +#define ss2(x) (((x) >> 2) ^ SPH_T32((x) << 1) \ + ^ SPH_ROTL32(x, 12) ^ SPH_ROTL32(x, 25)) +#define ss3(x) (((x) >> 2) ^ SPH_T32((x) << 2) \ + ^ SPH_ROTL32(x, 15) ^ SPH_ROTL32(x, 29)) +#define ss4(x) (((x) >> 1) ^ (x)) +#define ss5(x) (((x) >> 2) ^ (x)) +#define rs1(x) SPH_ROTL32(x, 3) +#define rs2(x) SPH_ROTL32(x, 7) +#define rs3(x) SPH_ROTL32(x, 13) +#define rs4(x) SPH_ROTL32(x, 16) +#define rs5(x) SPH_ROTL32(x, 19) +#define rs6(x) SPH_ROTL32(x, 23) +#define rs7(x) SPH_ROTL32(x, 27) + +#define Ks(j) SPH_T32((sph_u32)(j) * SPH_C32(0x05555555)) + +#define add_elt_s(mf, hf, j0m, j1m, j3m, j4m, j7m, j10m, j11m, j16) \ + (SPH_T32(SPH_ROTL32(mf(j0m), j1m) + SPH_ROTL32(mf(j3m), j4m) \ + - SPH_ROTL32(mf(j10m), j11m) + Ks(j16)) ^ hf(j7m)) + +#define expand1s_inner(qf, mf, hf, i16, \ + i0, i1, i2, i3, i4, i5, i6, i7, i8, \ + i9, i10, i11, i12, i13, i14, i15, \ + i0m, i1m, i3m, i4m, i7m, i10m, i11m) \ + SPH_T32(ss1(qf(i0)) + ss2(qf(i1)) + ss3(qf(i2)) + ss0(qf(i3)) \ + + ss1(qf(i4)) + ss2(qf(i5)) + ss3(qf(i6)) + ss0(qf(i7)) \ + + ss1(qf(i8)) + ss2(qf(i9)) + ss3(qf(i10)) + ss0(qf(i11)) \ + + ss1(qf(i12)) + ss2(qf(i13)) + ss3(qf(i14)) + ss0(qf(i15)) \ + + add_elt_s(mf, hf, i0m, i1m, i3m, i4m, i7m, i10m, i11m, i16)) + +#define expand1s(qf, mf, hf, i16) \ + expand1s_(qf, mf, hf, i16, I16_ ## i16, M16_ ## i16) +#define expand1s_(qf, mf, hf, i16, ix, iy) \ + expand1s_inner LPAR qf, mf, hf, i16, ix, iy) + +#define expand2s_inner(qf, mf, hf, i16, \ + i0, i1, i2, i3, i4, i5, i6, i7, i8, \ + i9, i10, i11, i12, i13, i14, i15, \ + i0m, i1m, i3m, i4m, i7m, i10m, i11m) \ + SPH_T32(qf(i0) + rs1(qf(i1)) + qf(i2) + rs2(qf(i3)) \ + + qf(i4) + rs3(qf(i5)) + qf(i6) + rs4(qf(i7)) \ + + qf(i8) + rs5(qf(i9)) + qf(i10) + rs6(qf(i11)) \ + + qf(i12) + rs7(qf(i13)) + ss4(qf(i14)) + ss5(qf(i15)) \ + + add_elt_s(mf, hf, i0m, i1m, i3m, i4m, i7m, i10m, i11m, i16)) + +#define expand2s(qf, mf, hf, i16) \ + expand2s_(qf, mf, hf, i16, I16_ ## i16, M16_ ## i16) +#define expand2s_(qf, mf, hf, i16, ix, iy) \ + expand2s_inner LPAR qf, mf, hf, i16, ix, iy) + +#if SPH_64 + +#define sb0(x) (((x) >> 1) ^ SPH_T64((x) << 3) \ + ^ SPH_ROTL64(x, 4) ^ SPH_ROTL64(x, 37)) +#define sb1(x) (((x) >> 1) ^ SPH_T64((x) << 2) \ + ^ SPH_ROTL64(x, 13) ^ SPH_ROTL64(x, 43)) +#define sb2(x) (((x) >> 2) ^ SPH_T64((x) << 1) \ + ^ SPH_ROTL64(x, 19) ^ SPH_ROTL64(x, 53)) +#define sb3(x) (((x) >> 2) ^ SPH_T64((x) << 2) \ + ^ SPH_ROTL64(x, 28) ^ SPH_ROTL64(x, 59)) +#define sb4(x) (((x) >> 1) ^ (x)) +#define sb5(x) (((x) >> 2) ^ (x)) +#define rb1(x) SPH_ROTL64(x, 5) +#define rb2(x) SPH_ROTL64(x, 11) +#define rb3(x) SPH_ROTL64(x, 27) +#define rb4(x) SPH_ROTL64(x, 32) +#define rb5(x) SPH_ROTL64(x, 37) +#define rb6(x) SPH_ROTL64(x, 43) +#define rb7(x) SPH_ROTL64(x, 53) + +#define Kb(j) SPH_T64((sph_u64)(j) * SPH_C64(0x0555555555555555)) + +#if SPH_SMALL_FOOTPRINT_BMW + +static const sph_u64 Kb_tab[] = { + Kb(16), Kb(17), Kb(18), Kb(19), Kb(20), Kb(21), Kb(22), Kb(23), + Kb(24), Kb(25), Kb(26), Kb(27), Kb(28), Kb(29), Kb(30), Kb(31) +}; + +#define rol_off(mf, j, off) \ + SPH_ROTL64(mf(((j) + (off)) & 15), (((j) + (off)) & 15) + 1) + +#define add_elt_b(mf, hf, j) \ + (SPH_T64(rol_off(mf, j, 0) + rol_off(mf, j, 3) \ + - rol_off(mf, j, 10) + Kb_tab[j]) ^ hf(((j) + 7) & 15)) + +#define expand1b(qf, mf, hf, i) \ + SPH_T64(sb1(qf((i) - 16)) + sb2(qf((i) - 15)) \ + + sb3(qf((i) - 14)) + sb0(qf((i) - 13)) \ + + sb1(qf((i) - 12)) + sb2(qf((i) - 11)) \ + + sb3(qf((i) - 10)) + sb0(qf((i) - 9)) \ + + sb1(qf((i) - 8)) + sb2(qf((i) - 7)) \ + + sb3(qf((i) - 6)) + sb0(qf((i) - 5)) \ + + sb1(qf((i) - 4)) + sb2(qf((i) - 3)) \ + + sb3(qf((i) - 2)) + sb0(qf((i) - 1)) \ + + add_elt_b(mf, hf, (i) - 16)) + +#define expand2b(qf, mf, hf, i) \ + SPH_T64(qf((i) - 16) + rb1(qf((i) - 15)) \ + + qf((i) - 14) + rb2(qf((i) - 13)) \ + + qf((i) - 12) + rb3(qf((i) - 11)) \ + + qf((i) - 10) + rb4(qf((i) - 9)) \ + + qf((i) - 8) + rb5(qf((i) - 7)) \ + + qf((i) - 6) + rb6(qf((i) - 5)) \ + + qf((i) - 4) + rb7(qf((i) - 3)) \ + + sb4(qf((i) - 2)) + sb5(qf((i) - 1)) \ + + add_elt_b(mf, hf, (i) - 16)) + +#else + +#define add_elt_b(mf, hf, j0m, j1m, j3m, j4m, j7m, j10m, j11m, j16) \ + (SPH_T64(SPH_ROTL64(mf(j0m), j1m) + SPH_ROTL64(mf(j3m), j4m) \ + - SPH_ROTL64(mf(j10m), j11m) + Kb(j16)) ^ hf(j7m)) + +#define expand1b_inner(qf, mf, hf, i16, \ + i0, i1, i2, i3, i4, i5, i6, i7, i8, \ + i9, i10, i11, i12, i13, i14, i15, \ + i0m, i1m, i3m, i4m, i7m, i10m, i11m) \ + SPH_T64(sb1(qf(i0)) + sb2(qf(i1)) + sb3(qf(i2)) + sb0(qf(i3)) \ + + sb1(qf(i4)) + sb2(qf(i5)) + sb3(qf(i6)) + sb0(qf(i7)) \ + + sb1(qf(i8)) + sb2(qf(i9)) + sb3(qf(i10)) + sb0(qf(i11)) \ + + sb1(qf(i12)) + sb2(qf(i13)) + sb3(qf(i14)) + sb0(qf(i15)) \ + + add_elt_b(mf, hf, i0m, i1m, i3m, i4m, i7m, i10m, i11m, i16)) + +#define expand1b(qf, mf, hf, i16) \ + expand1b_(qf, mf, hf, i16, I16_ ## i16, M16_ ## i16) +#define expand1b_(qf, mf, hf, i16, ix, iy) \ + expand1b_inner LPAR qf, mf, hf, i16, ix, iy) + +#define expand2b_inner(qf, mf, hf, i16, \ + i0, i1, i2, i3, i4, i5, i6, i7, i8, \ + i9, i10, i11, i12, i13, i14, i15, \ + i0m, i1m, i3m, i4m, i7m, i10m, i11m) \ + SPH_T64(qf(i0) + rb1(qf(i1)) + qf(i2) + rb2(qf(i3)) \ + + qf(i4) + rb3(qf(i5)) + qf(i6) + rb4(qf(i7)) \ + + qf(i8) + rb5(qf(i9)) + qf(i10) + rb6(qf(i11)) \ + + qf(i12) + rb7(qf(i13)) + sb4(qf(i14)) + sb5(qf(i15)) \ + + add_elt_b(mf, hf, i0m, i1m, i3m, i4m, i7m, i10m, i11m, i16)) + +#define expand2b(qf, mf, hf, i16) \ + expand2b_(qf, mf, hf, i16, I16_ ## i16, M16_ ## i16) +#define expand2b_(qf, mf, hf, i16, ix, iy) \ + expand2b_inner LPAR qf, mf, hf, i16, ix, iy) + +#endif + +#endif + +#define MAKE_W(tt, i0, op01, i1, op12, i2, op23, i3, op34, i4) \ + tt((M(i0) ^ H(i0)) op01 (M(i1) ^ H(i1)) op12 (M(i2) ^ H(i2)) \ + op23 (M(i3) ^ H(i3)) op34 (M(i4) ^ H(i4))) + +#define Ws0 MAKE_W(SPH_T32, 5, -, 7, +, 10, +, 13, +, 14) +#define Ws1 MAKE_W(SPH_T32, 6, -, 8, +, 11, +, 14, -, 15) +#define Ws2 MAKE_W(SPH_T32, 0, +, 7, +, 9, -, 12, +, 15) +#define Ws3 MAKE_W(SPH_T32, 0, -, 1, +, 8, -, 10, +, 13) +#define Ws4 MAKE_W(SPH_T32, 1, +, 2, +, 9, -, 11, -, 14) +#define Ws5 MAKE_W(SPH_T32, 3, -, 2, +, 10, -, 12, +, 15) +#define Ws6 MAKE_W(SPH_T32, 4, -, 0, -, 3, -, 11, +, 13) +#define Ws7 MAKE_W(SPH_T32, 1, -, 4, -, 5, -, 12, -, 14) +#define Ws8 MAKE_W(SPH_T32, 2, -, 5, -, 6, +, 13, -, 15) +#define Ws9 MAKE_W(SPH_T32, 0, -, 3, +, 6, -, 7, +, 14) +#define Ws10 MAKE_W(SPH_T32, 8, -, 1, -, 4, -, 7, +, 15) +#define Ws11 MAKE_W(SPH_T32, 8, -, 0, -, 2, -, 5, +, 9) +#define Ws12 MAKE_W(SPH_T32, 1, +, 3, -, 6, -, 9, +, 10) +#define Ws13 MAKE_W(SPH_T32, 2, +, 4, +, 7, +, 10, +, 11) +#define Ws14 MAKE_W(SPH_T32, 3, -, 5, +, 8, -, 11, -, 12) +#define Ws15 MAKE_W(SPH_T32, 12, -, 4, -, 6, -, 9, +, 13) + +#if SPH_SMALL_FOOTPRINT_BMW + +#define MAKE_Qas do { \ + unsigned u; \ + sph_u32 Ws[16]; \ + Ws[ 0] = Ws0; \ + Ws[ 1] = Ws1; \ + Ws[ 2] = Ws2; \ + Ws[ 3] = Ws3; \ + Ws[ 4] = Ws4; \ + Ws[ 5] = Ws5; \ + Ws[ 6] = Ws6; \ + Ws[ 7] = Ws7; \ + Ws[ 8] = Ws8; \ + Ws[ 9] = Ws9; \ + Ws[10] = Ws10; \ + Ws[11] = Ws11; \ + Ws[12] = Ws12; \ + Ws[13] = Ws13; \ + Ws[14] = Ws14; \ + Ws[15] = Ws15; \ + for (u = 0; u < 15; u += 5) { \ + qt[u + 0] = SPH_T32(ss0(Ws[u + 0]) + H(u + 1)); \ + qt[u + 1] = SPH_T32(ss1(Ws[u + 1]) + H(u + 2)); \ + qt[u + 2] = SPH_T32(ss2(Ws[u + 2]) + H(u + 3)); \ + qt[u + 3] = SPH_T32(ss3(Ws[u + 3]) + H(u + 4)); \ + qt[u + 4] = SPH_T32(ss4(Ws[u + 4]) + H(u + 5)); \ + } \ + qt[15] = SPH_T32(ss0(Ws[15]) + H(0)); \ + } while (0) + +#define MAKE_Qbs do { \ + qt[16] = expand1s(Qs, M, H, 16); \ + qt[17] = expand1s(Qs, M, H, 17); \ + qt[18] = expand2s(Qs, M, H, 18); \ + qt[19] = expand2s(Qs, M, H, 19); \ + qt[20] = expand2s(Qs, M, H, 20); \ + qt[21] = expand2s(Qs, M, H, 21); \ + qt[22] = expand2s(Qs, M, H, 22); \ + qt[23] = expand2s(Qs, M, H, 23); \ + qt[24] = expand2s(Qs, M, H, 24); \ + qt[25] = expand2s(Qs, M, H, 25); \ + qt[26] = expand2s(Qs, M, H, 26); \ + qt[27] = expand2s(Qs, M, H, 27); \ + qt[28] = expand2s(Qs, M, H, 28); \ + qt[29] = expand2s(Qs, M, H, 29); \ + qt[30] = expand2s(Qs, M, H, 30); \ + qt[31] = expand2s(Qs, M, H, 31); \ + } while (0) + +#else + +#define MAKE_Qas do { \ + qt[ 0] = SPH_T32(ss0(Ws0 ) + H( 1)); \ + qt[ 1] = SPH_T32(ss1(Ws1 ) + H( 2)); \ + qt[ 2] = SPH_T32(ss2(Ws2 ) + H( 3)); \ + qt[ 3] = SPH_T32(ss3(Ws3 ) + H( 4)); \ + qt[ 4] = SPH_T32(ss4(Ws4 ) + H( 5)); \ + qt[ 5] = SPH_T32(ss0(Ws5 ) + H( 6)); \ + qt[ 6] = SPH_T32(ss1(Ws6 ) + H( 7)); \ + qt[ 7] = SPH_T32(ss2(Ws7 ) + H( 8)); \ + qt[ 8] = SPH_T32(ss3(Ws8 ) + H( 9)); \ + qt[ 9] = SPH_T32(ss4(Ws9 ) + H(10)); \ + qt[10] = SPH_T32(ss0(Ws10) + H(11)); \ + qt[11] = SPH_T32(ss1(Ws11) + H(12)); \ + qt[12] = SPH_T32(ss2(Ws12) + H(13)); \ + qt[13] = SPH_T32(ss3(Ws13) + H(14)); \ + qt[14] = SPH_T32(ss4(Ws14) + H(15)); \ + qt[15] = SPH_T32(ss0(Ws15) + H( 0)); \ + } while (0) + +#define MAKE_Qbs do { \ + qt[16] = expand1s(Qs, M, H, 16); \ + qt[17] = expand1s(Qs, M, H, 17); \ + qt[18] = expand2s(Qs, M, H, 18); \ + qt[19] = expand2s(Qs, M, H, 19); \ + qt[20] = expand2s(Qs, M, H, 20); \ + qt[21] = expand2s(Qs, M, H, 21); \ + qt[22] = expand2s(Qs, M, H, 22); \ + qt[23] = expand2s(Qs, M, H, 23); \ + qt[24] = expand2s(Qs, M, H, 24); \ + qt[25] = expand2s(Qs, M, H, 25); \ + qt[26] = expand2s(Qs, M, H, 26); \ + qt[27] = expand2s(Qs, M, H, 27); \ + qt[28] = expand2s(Qs, M, H, 28); \ + qt[29] = expand2s(Qs, M, H, 29); \ + qt[30] = expand2s(Qs, M, H, 30); \ + qt[31] = expand2s(Qs, M, H, 31); \ + } while (0) + +#endif + +#define MAKE_Qs do { \ + MAKE_Qas; \ + MAKE_Qbs; \ + } while (0) + +#define Qs(j) (qt[j]) + +#if SPH_64 + +#define Wb0 MAKE_W(SPH_T64, 5, -, 7, +, 10, +, 13, +, 14) +#define Wb1 MAKE_W(SPH_T64, 6, -, 8, +, 11, +, 14, -, 15) +#define Wb2 MAKE_W(SPH_T64, 0, +, 7, +, 9, -, 12, +, 15) +#define Wb3 MAKE_W(SPH_T64, 0, -, 1, +, 8, -, 10, +, 13) +#define Wb4 MAKE_W(SPH_T64, 1, +, 2, +, 9, -, 11, -, 14) +#define Wb5 MAKE_W(SPH_T64, 3, -, 2, +, 10, -, 12, +, 15) +#define Wb6 MAKE_W(SPH_T64, 4, -, 0, -, 3, -, 11, +, 13) +#define Wb7 MAKE_W(SPH_T64, 1, -, 4, -, 5, -, 12, -, 14) +#define Wb8 MAKE_W(SPH_T64, 2, -, 5, -, 6, +, 13, -, 15) +#define Wb9 MAKE_W(SPH_T64, 0, -, 3, +, 6, -, 7, +, 14) +#define Wb10 MAKE_W(SPH_T64, 8, -, 1, -, 4, -, 7, +, 15) +#define Wb11 MAKE_W(SPH_T64, 8, -, 0, -, 2, -, 5, +, 9) +#define Wb12 MAKE_W(SPH_T64, 1, +, 3, -, 6, -, 9, +, 10) +#define Wb13 MAKE_W(SPH_T64, 2, +, 4, +, 7, +, 10, +, 11) +#define Wb14 MAKE_W(SPH_T64, 3, -, 5, +, 8, -, 11, -, 12) +#define Wb15 MAKE_W(SPH_T64, 12, -, 4, -, 6, -, 9, +, 13) + +#if SPH_SMALL_FOOTPRINT_BMW + +#define MAKE_Qab do { \ + unsigned u; \ + sph_u64 Wb[16]; \ + Wb[ 0] = Wb0; \ + Wb[ 1] = Wb1; \ + Wb[ 2] = Wb2; \ + Wb[ 3] = Wb3; \ + Wb[ 4] = Wb4; \ + Wb[ 5] = Wb5; \ + Wb[ 6] = Wb6; \ + Wb[ 7] = Wb7; \ + Wb[ 8] = Wb8; \ + Wb[ 9] = Wb9; \ + Wb[10] = Wb10; \ + Wb[11] = Wb11; \ + Wb[12] = Wb12; \ + Wb[13] = Wb13; \ + Wb[14] = Wb14; \ + Wb[15] = Wb15; \ + for (u = 0; u < 15; u += 5) { \ + qt[u + 0] = SPH_T64(sb0(Wb[u + 0]) + H(u + 1)); \ + qt[u + 1] = SPH_T64(sb1(Wb[u + 1]) + H(u + 2)); \ + qt[u + 2] = SPH_T64(sb2(Wb[u + 2]) + H(u + 3)); \ + qt[u + 3] = SPH_T64(sb3(Wb[u + 3]) + H(u + 4)); \ + qt[u + 4] = SPH_T64(sb4(Wb[u + 4]) + H(u + 5)); \ + } \ + qt[15] = SPH_T64(sb0(Wb[15]) + H(0)); \ + } while (0) + +#define MAKE_Qbb do { \ + unsigned u; \ + for (u = 16; u < 18; u ++) \ + qt[u] = expand1b(Qb, M, H, u); \ + for (u = 18; u < 32; u ++) \ + qt[u] = expand2b(Qb, M, H, u); \ + } while (0) + +#else + +#define MAKE_Qab do { \ + qt[ 0] = SPH_T64(sb0(Wb0 ) + H( 1)); \ + qt[ 1] = SPH_T64(sb1(Wb1 ) + H( 2)); \ + qt[ 2] = SPH_T64(sb2(Wb2 ) + H( 3)); \ + qt[ 3] = SPH_T64(sb3(Wb3 ) + H( 4)); \ + qt[ 4] = SPH_T64(sb4(Wb4 ) + H( 5)); \ + qt[ 5] = SPH_T64(sb0(Wb5 ) + H( 6)); \ + qt[ 6] = SPH_T64(sb1(Wb6 ) + H( 7)); \ + qt[ 7] = SPH_T64(sb2(Wb7 ) + H( 8)); \ + qt[ 8] = SPH_T64(sb3(Wb8 ) + H( 9)); \ + qt[ 9] = SPH_T64(sb4(Wb9 ) + H(10)); \ + qt[10] = SPH_T64(sb0(Wb10) + H(11)); \ + qt[11] = SPH_T64(sb1(Wb11) + H(12)); \ + qt[12] = SPH_T64(sb2(Wb12) + H(13)); \ + qt[13] = SPH_T64(sb3(Wb13) + H(14)); \ + qt[14] = SPH_T64(sb4(Wb14) + H(15)); \ + qt[15] = SPH_T64(sb0(Wb15) + H( 0)); \ + } while (0) + +#define MAKE_Qbb do { \ + qt[16] = expand1b(Qb, M, H, 16); \ + qt[17] = expand1b(Qb, M, H, 17); \ + qt[18] = expand2b(Qb, M, H, 18); \ + qt[19] = expand2b(Qb, M, H, 19); \ + qt[20] = expand2b(Qb, M, H, 20); \ + qt[21] = expand2b(Qb, M, H, 21); \ + qt[22] = expand2b(Qb, M, H, 22); \ + qt[23] = expand2b(Qb, M, H, 23); \ + qt[24] = expand2b(Qb, M, H, 24); \ + qt[25] = expand2b(Qb, M, H, 25); \ + qt[26] = expand2b(Qb, M, H, 26); \ + qt[27] = expand2b(Qb, M, H, 27); \ + qt[28] = expand2b(Qb, M, H, 28); \ + qt[29] = expand2b(Qb, M, H, 29); \ + qt[30] = expand2b(Qb, M, H, 30); \ + qt[31] = expand2b(Qb, M, H, 31); \ + } while (0) + +#endif + +#define MAKE_Qb do { \ + MAKE_Qab; \ + MAKE_Qbb; \ + } while (0) + +#define Qb(j) (qt[j]) + +#endif + +#define FOLD(type, mkQ, tt, rol, mf, qf, dhf) do { \ + type qt[32], xl, xh; \ + mkQ; \ + xl = qf(16) ^ qf(17) ^ qf(18) ^ qf(19) \ + ^ qf(20) ^ qf(21) ^ qf(22) ^ qf(23); \ + xh = xl ^ qf(24) ^ qf(25) ^ qf(26) ^ qf(27) \ + ^ qf(28) ^ qf(29) ^ qf(30) ^ qf(31); \ + dhf( 0) = tt(((xh << 5) ^ (qf(16) >> 5) ^ mf( 0)) \ + + (xl ^ qf(24) ^ qf( 0))); \ + dhf( 1) = tt(((xh >> 7) ^ (qf(17) << 8) ^ mf( 1)) \ + + (xl ^ qf(25) ^ qf( 1))); \ + dhf( 2) = tt(((xh >> 5) ^ (qf(18) << 5) ^ mf( 2)) \ + + (xl ^ qf(26) ^ qf( 2))); \ + dhf( 3) = tt(((xh >> 1) ^ (qf(19) << 5) ^ mf( 3)) \ + + (xl ^ qf(27) ^ qf( 3))); \ + dhf( 4) = tt(((xh >> 3) ^ (qf(20) << 0) ^ mf( 4)) \ + + (xl ^ qf(28) ^ qf( 4))); \ + dhf( 5) = tt(((xh << 6) ^ (qf(21) >> 6) ^ mf( 5)) \ + + (xl ^ qf(29) ^ qf( 5))); \ + dhf( 6) = tt(((xh >> 4) ^ (qf(22) << 6) ^ mf( 6)) \ + + (xl ^ qf(30) ^ qf( 6))); \ + dhf( 7) = tt(((xh >> 11) ^ (qf(23) << 2) ^ mf( 7)) \ + + (xl ^ qf(31) ^ qf( 7))); \ + dhf( 8) = tt(rol(dhf(4), 9) + (xh ^ qf(24) ^ mf( 8)) \ + + ((xl << 8) ^ qf(23) ^ qf( 8))); \ + dhf( 9) = tt(rol(dhf(5), 10) + (xh ^ qf(25) ^ mf( 9)) \ + + ((xl >> 6) ^ qf(16) ^ qf( 9))); \ + dhf(10) = tt(rol(dhf(6), 11) + (xh ^ qf(26) ^ mf(10)) \ + + ((xl << 6) ^ qf(17) ^ qf(10))); \ + dhf(11) = tt(rol(dhf(7), 12) + (xh ^ qf(27) ^ mf(11)) \ + + ((xl << 4) ^ qf(18) ^ qf(11))); \ + dhf(12) = tt(rol(dhf(0), 13) + (xh ^ qf(28) ^ mf(12)) \ + + ((xl >> 3) ^ qf(19) ^ qf(12))); \ + dhf(13) = tt(rol(dhf(1), 14) + (xh ^ qf(29) ^ mf(13)) \ + + ((xl >> 4) ^ qf(20) ^ qf(13))); \ + dhf(14) = tt(rol(dhf(2), 15) + (xh ^ qf(30) ^ mf(14)) \ + + ((xl >> 7) ^ qf(21) ^ qf(14))); \ + dhf(15) = tt(rol(dhf(3), 16) + (xh ^ qf(31) ^ mf(15)) \ + + ((xl >> 2) ^ qf(22) ^ qf(15))); \ + } while (0) + +#define FOLDs FOLD(sph_u32, MAKE_Qs, SPH_T32, SPH_ROTL32, M, Qs, dH) + +#if SPH_64 + +#define FOLDb FOLD(sph_u64, MAKE_Qb, SPH_T64, SPH_ROTL64, M, Qb, dH) + +#endif + +static void +compress_small(const unsigned char *data, const sph_u32 h[16], sph_u32 dh[16]) +{ +#if SPH_LITTLE_FAST +#define M(x) sph_dec32le_aligned(data + 4 * (x)) +#else + sph_u32 mv[16]; + + mv[ 0] = sph_dec32le_aligned(data + 0); + mv[ 1] = sph_dec32le_aligned(data + 4); + mv[ 2] = sph_dec32le_aligned(data + 8); + mv[ 3] = sph_dec32le_aligned(data + 12); + mv[ 4] = sph_dec32le_aligned(data + 16); + mv[ 5] = sph_dec32le_aligned(data + 20); + mv[ 6] = sph_dec32le_aligned(data + 24); + mv[ 7] = sph_dec32le_aligned(data + 28); + mv[ 8] = sph_dec32le_aligned(data + 32); + mv[ 9] = sph_dec32le_aligned(data + 36); + mv[10] = sph_dec32le_aligned(data + 40); + mv[11] = sph_dec32le_aligned(data + 44); + mv[12] = sph_dec32le_aligned(data + 48); + mv[13] = sph_dec32le_aligned(data + 52); + mv[14] = sph_dec32le_aligned(data + 56); + mv[15] = sph_dec32le_aligned(data + 60); +#define M(x) (mv[x]) +#endif +#define H(x) (h[x]) +#define dH(x) (dh[x]) + + FOLDs; + +#undef M +#undef H +#undef dH +} + +static const sph_u32 final_s[16] = { + SPH_C32(0xaaaaaaa0), SPH_C32(0xaaaaaaa1), SPH_C32(0xaaaaaaa2), + SPH_C32(0xaaaaaaa3), SPH_C32(0xaaaaaaa4), SPH_C32(0xaaaaaaa5), + SPH_C32(0xaaaaaaa6), SPH_C32(0xaaaaaaa7), SPH_C32(0xaaaaaaa8), + SPH_C32(0xaaaaaaa9), SPH_C32(0xaaaaaaaa), SPH_C32(0xaaaaaaab), + SPH_C32(0xaaaaaaac), SPH_C32(0xaaaaaaad), SPH_C32(0xaaaaaaae), + SPH_C32(0xaaaaaaaf) +}; + +static void +bmw32_init(sph_bmw_small_context *sc, const sph_u32 *iv) +{ + memcpy(sc->H, iv, sizeof sc->H); + sc->ptr = 0; +#if SPH_64 + sc->bit_count = 0; +#else + sc->bit_count_high = 0; + sc->bit_count_low = 0; +#endif +} + +static void +bmw32(sph_bmw_small_context *sc, const void *data, size_t len) +{ + unsigned char *buf; + size_t ptr; + sph_u32 htmp[16]; + sph_u32 *h1, *h2; +#if !SPH_64 + sph_u32 tmp; +#endif + +#if SPH_64 + sc->bit_count += (sph_u64)len << 3; +#else + tmp = sc->bit_count_low; + sc->bit_count_low = SPH_T32(tmp + ((sph_u32)len << 3)); + if (sc->bit_count_low < tmp) + sc->bit_count_high ++; + sc->bit_count_high += len >> 29; +#endif + buf = sc->buf; + ptr = sc->ptr; + h1 = sc->H; + h2 = htmp; + while (len > 0) { + size_t clen; + + clen = (sizeof sc->buf) - ptr; + if (clen > len) + clen = len; + memcpy(buf + ptr, data, clen); + data = (const unsigned char *)data + clen; + len -= clen; + ptr += clen; + if (ptr == sizeof sc->buf) { + sph_u32 *ht; + + compress_small(buf, h1, h2); + ht = h1; + h1 = h2; + h2 = ht; + ptr = 0; + } + } + sc->ptr = ptr; + if (h1 != sc->H) + memcpy(sc->H, h1, sizeof sc->H); +} + +static void +bmw32_close(sph_bmw_small_context *sc, unsigned ub, unsigned n, + void *dst, size_t out_size_w32) +{ + unsigned char *buf, *out; + size_t ptr, u, v; + unsigned z; + sph_u32 h1[16], h2[16], *h; + + buf = sc->buf; + ptr = sc->ptr; + z = 0x80 >> n; + buf[ptr ++] = ((ub & -z) | z) & 0xFF; + h = sc->H; + if (ptr > (sizeof sc->buf) - 8) { + memset(buf + ptr, 0, (sizeof sc->buf) - ptr); + compress_small(buf, h, h1); + ptr = 0; + h = h1; + } + memset(buf + ptr, 0, (sizeof sc->buf) - 8 - ptr); +#if SPH_64 + sph_enc64le_aligned(buf + (sizeof sc->buf) - 8, + SPH_T64(sc->bit_count + n)); +#else + sph_enc32le_aligned(buf + (sizeof sc->buf) - 8, + sc->bit_count_low + n); + sph_enc32le_aligned(buf + (sizeof sc->buf) - 4, + SPH_T32(sc->bit_count_high)); +#endif + compress_small(buf, h, h2); + for (u = 0; u < 16; u ++) + sph_enc32le_aligned(buf + 4 * u, h2[u]); + compress_small(buf, final_s, h1); + out = dst; + for (u = 0, v = 16 - out_size_w32; u < out_size_w32; u ++, v ++) + sph_enc32le(out + 4 * u, h1[v]); +} + +#if SPH_64 + +static void +compress_big(const unsigned char *data, const sph_u64 h[16], sph_u64 dh[16]) +{ +#if SPH_LITTLE_FAST +#define M(x) sph_dec64le_aligned(data + 8 * (x)) +#else + sph_u64 mv[16]; + + mv[ 0] = sph_dec64le_aligned(data + 0); + mv[ 1] = sph_dec64le_aligned(data + 8); + mv[ 2] = sph_dec64le_aligned(data + 16); + mv[ 3] = sph_dec64le_aligned(data + 24); + mv[ 4] = sph_dec64le_aligned(data + 32); + mv[ 5] = sph_dec64le_aligned(data + 40); + mv[ 6] = sph_dec64le_aligned(data + 48); + mv[ 7] = sph_dec64le_aligned(data + 56); + mv[ 8] = sph_dec64le_aligned(data + 64); + mv[ 9] = sph_dec64le_aligned(data + 72); + mv[10] = sph_dec64le_aligned(data + 80); + mv[11] = sph_dec64le_aligned(data + 88); + mv[12] = sph_dec64le_aligned(data + 96); + mv[13] = sph_dec64le_aligned(data + 104); + mv[14] = sph_dec64le_aligned(data + 112); + mv[15] = sph_dec64le_aligned(data + 120); +#define M(x) (mv[x]) +#endif +#define H(x) (h[x]) +#define dH(x) (dh[x]) + + FOLDb; + +#undef M +#undef H +#undef dH +} + +static const sph_u64 final_b[16] = { + SPH_C64(0xaaaaaaaaaaaaaaa0), SPH_C64(0xaaaaaaaaaaaaaaa1), + SPH_C64(0xaaaaaaaaaaaaaaa2), SPH_C64(0xaaaaaaaaaaaaaaa3), + SPH_C64(0xaaaaaaaaaaaaaaa4), SPH_C64(0xaaaaaaaaaaaaaaa5), + SPH_C64(0xaaaaaaaaaaaaaaa6), SPH_C64(0xaaaaaaaaaaaaaaa7), + SPH_C64(0xaaaaaaaaaaaaaaa8), SPH_C64(0xaaaaaaaaaaaaaaa9), + SPH_C64(0xaaaaaaaaaaaaaaaa), SPH_C64(0xaaaaaaaaaaaaaaab), + SPH_C64(0xaaaaaaaaaaaaaaac), SPH_C64(0xaaaaaaaaaaaaaaad), + SPH_C64(0xaaaaaaaaaaaaaaae), SPH_C64(0xaaaaaaaaaaaaaaaf) +}; + +static void +bmw64_init(sph_bmw_big_context *sc, const sph_u64 *iv) +{ + memcpy(sc->H, iv, sizeof sc->H); + sc->ptr = 0; + sc->bit_count = 0; +} + +static void +bmw64(sph_bmw_big_context *sc, const void *data, size_t len) +{ + unsigned char *buf; + size_t ptr; + sph_u64 htmp[16]; + sph_u64 *h1, *h2; + + sc->bit_count += (sph_u64)len << 3; + buf = sc->buf; + ptr = sc->ptr; + h1 = sc->H; + h2 = htmp; + while (len > 0) { + size_t clen; + + clen = (sizeof sc->buf) - ptr; + if (clen > len) + clen = len; + memcpy(buf + ptr, data, clen); + data = (const unsigned char *)data + clen; + len -= clen; + ptr += clen; + if (ptr == sizeof sc->buf) { + sph_u64 *ht; + + compress_big(buf, h1, h2); + ht = h1; + h1 = h2; + h2 = ht; + ptr = 0; + } + } + sc->ptr = ptr; + if (h1 != sc->H) + memcpy(sc->H, h1, sizeof sc->H); +} + +static void +bmw64_close(sph_bmw_big_context *sc, unsigned ub, unsigned n, + void *dst, size_t out_size_w64) +{ + unsigned char *buf, *out; + size_t ptr, u, v; + unsigned z; + sph_u64 h1[16], h2[16], *h; + + buf = sc->buf; + ptr = sc->ptr; + z = 0x80 >> n; + buf[ptr ++] = ((ub & -z) | z) & 0xFF; + h = sc->H; + if (ptr > (sizeof sc->buf) - 8) { + memset(buf + ptr, 0, (sizeof sc->buf) - ptr); + compress_big(buf, h, h1); + ptr = 0; + h = h1; + } + memset(buf + ptr, 0, (sizeof sc->buf) - 8 - ptr); + sph_enc64le_aligned(buf + (sizeof sc->buf) - 8, + SPH_T64(sc->bit_count + n)); + compress_big(buf, h, h2); + for (u = 0; u < 16; u ++) + sph_enc64le_aligned(buf + 8 * u, h2[u]); + compress_big(buf, final_b, h1); + out = dst; + for (u = 0, v = 16 - out_size_w64; u < out_size_w64; u ++, v ++) + sph_enc64le(out + 8 * u, h1[v]); +} + +#endif + +/* see sph_bmw.h */ +void +sph_bmw224_init(void *cc) +{ + bmw32_init(cc, IV224); +} + +/* see sph_bmw.h */ +void +sph_bmw224(void *cc, const void *data, size_t len) +{ + bmw32(cc, data, len); +} + +/* see sph_bmw.h */ +void +sph_bmw224_close(void *cc, void *dst) +{ + sph_bmw224_addbits_and_close(cc, 0, 0, dst); +} + +/* see sph_bmw.h */ +void +sph_bmw224_addbits_and_close(void *cc, unsigned ub, unsigned n, void *dst) +{ + bmw32_close(cc, ub, n, dst, 7); + sph_bmw224_init(cc); +} + +/* see sph_bmw.h */ +void +sph_bmw256_init(void *cc) +{ + bmw32_init(cc, IV256); +} + +/* see sph_bmw.h */ +void +sph_bmw256(void *cc, const void *data, size_t len) +{ + bmw32(cc, data, len); +} + +/* see sph_bmw.h */ +void +sph_bmw256_close(void *cc, void *dst) +{ + sph_bmw256_addbits_and_close(cc, 0, 0, dst); +} + +/* see sph_bmw.h */ +void +sph_bmw256_addbits_and_close(void *cc, unsigned ub, unsigned n, void *dst) +{ + bmw32_close(cc, ub, n, dst, 8); + sph_bmw256_init(cc); +} + +#if SPH_64 + +/* see sph_bmw.h */ +void +sph_bmw384_init(void *cc) +{ + bmw64_init(cc, IV384); +} + +/* see sph_bmw.h */ +void +sph_bmw384(void *cc, const void *data, size_t len) +{ + bmw64(cc, data, len); +} + +/* see sph_bmw.h */ +void +sph_bmw384_close(void *cc, void *dst) +{ + sph_bmw384_addbits_and_close(cc, 0, 0, dst); +} + +/* see sph_bmw.h */ +void +sph_bmw384_addbits_and_close(void *cc, unsigned ub, unsigned n, void *dst) +{ + bmw64_close(cc, ub, n, dst, 6); + sph_bmw384_init(cc); +} + +/* see sph_bmw.h */ +void +sph_bmw512_init(void *cc) +{ + bmw64_init(cc, IV512); +} + +/* see sph_bmw.h */ +void +sph_bmw512(void *cc, const void *data, size_t len) +{ + bmw64(cc, data, len); +} + +/* see sph_bmw.h */ +void +sph_bmw512_close(void *cc, void *dst) +{ + sph_bmw512_addbits_and_close(cc, 0, 0, dst); +} + +/* see sph_bmw.h */ +void +sph_bmw512_addbits_and_close(void *cc, unsigned ub, unsigned n, void *dst) +{ + bmw64_close(cc, ub, n, dst, 8); + sph_bmw512_init(cc); +} + +#endif + +#ifdef __cplusplus +} +#endif diff --git a/src/checkpoints.cpp b/src/checkpoints.cpp new file mode 100644 index 0000000..ad18024 --- /dev/null +++ b/src/checkpoints.cpp @@ -0,0 +1,435 @@ +// Copyright (c) 2009-2012 The Bitcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include // for 'map_list_of()' +#include + +#include "checkpoints.h" + +#include "db.h" +#include "main.h" +#include "uint256.h" + +namespace Checkpoints +{ + typedef std::map MapCheckpoints; + + // + // What makes a good checkpoint block? + // + Is surrounded by blocks with reasonable timestamps + // (no blocks before with a timestamp after, none after with + // timestamp before) + // + Contains no strange transactions + // + static MapCheckpoints mapCheckpoints = + boost::assign::map_list_of + ( 0, hashGenesisBlockOfficial ) + ; + + static MapCheckpoints mapCheckpointsTestnet = + boost::assign::map_list_of + ( 0, hashGenesisBlockTestNet ) + ; + + bool CheckHardened(int nHeight, const uint256& hash) + { + MapCheckpoints& checkpoints = (fTestNet ? mapCheckpointsTestnet : mapCheckpoints); + + MapCheckpoints::const_iterator i = checkpoints.find(nHeight); + if (i == checkpoints.end()) return true; + return hash == i->second; + } + + int GetTotalBlocksEstimate() + { + MapCheckpoints& checkpoints = (fTestNet ? mapCheckpointsTestnet : mapCheckpoints); + + return checkpoints.rbegin()->first; + } + + CBlockIndex* GetLastCheckpoint(const std::map& mapBlockIndex) + { + MapCheckpoints& checkpoints = (fTestNet ? mapCheckpointsTestnet : mapCheckpoints); + + BOOST_REVERSE_FOREACH(const MapCheckpoints::value_type& i, checkpoints) + { + const uint256& hash = i.second; + std::map::const_iterator t = mapBlockIndex.find(hash); + if (t != mapBlockIndex.end()) + return t->second; + } + return NULL; + } + + // triangles: synchronized checkpoint (centrally broadcasted) + uint256 hashSyncCheckpoint = 0; + uint256 hashPendingCheckpoint = 0; + CSyncCheckpoint checkpointMessage; + CSyncCheckpoint checkpointMessagePending; + uint256 hashInvalidCheckpoint = 0; + CCriticalSection cs_hashSyncCheckpoint; + + // triangles: get last synchronized checkpoint + CBlockIndex* GetLastSyncCheckpoint() + { + LOCK(cs_hashSyncCheckpoint); + if (!mapBlockIndex.count(hashSyncCheckpoint)) + error("GetSyncCheckpoint: block index missing for current sync-checkpoint %s", hashSyncCheckpoint.ToString().c_str()); + else + return mapBlockIndex[hashSyncCheckpoint]; + return NULL; + } + + // triangles: only descendant of current sync-checkpoint is allowed + bool ValidateSyncCheckpoint(uint256 hashCheckpoint) + { + if (!mapBlockIndex.count(hashSyncCheckpoint)) + return error("ValidateSyncCheckpoint: block index missing for current sync-checkpoint %s", hashSyncCheckpoint.ToString().c_str()); + if (!mapBlockIndex.count(hashCheckpoint)) + return error("ValidateSyncCheckpoint: block index missing for received sync-checkpoint %s", hashCheckpoint.ToString().c_str()); + + CBlockIndex* pindexSyncCheckpoint = mapBlockIndex[hashSyncCheckpoint]; + CBlockIndex* pindexCheckpointRecv = mapBlockIndex[hashCheckpoint]; + + if (pindexCheckpointRecv->nHeight <= pindexSyncCheckpoint->nHeight) + { + // Received an older checkpoint, trace back from current checkpoint + // to the same height of the received checkpoint to verify + // that current checkpoint should be a descendant block + CBlockIndex* pindex = pindexSyncCheckpoint; + while (pindex->nHeight > pindexCheckpointRecv->nHeight) + if (!(pindex = pindex->pprev)) + return error("ValidateSyncCheckpoint: pprev1 null - block index structure failure"); + if (pindex->GetBlockHash() != hashCheckpoint) + { + hashInvalidCheckpoint = hashCheckpoint; + return error("ValidateSyncCheckpoint: new sync-checkpoint %s is conflicting with current sync-checkpoint %s", hashCheckpoint.ToString().c_str(), hashSyncCheckpoint.ToString().c_str()); + } + return false; // ignore older checkpoint + } + + // Received checkpoint should be a descendant block of the current + // checkpoint. Trace back to the same height of current checkpoint + // to verify. + CBlockIndex* pindex = pindexCheckpointRecv; + while (pindex->nHeight > pindexSyncCheckpoint->nHeight) + if (!(pindex = pindex->pprev)) + return error("ValidateSyncCheckpoint: pprev2 null - block index structure failure"); + if (pindex->GetBlockHash() != hashSyncCheckpoint) + { + hashInvalidCheckpoint = hashCheckpoint; + return error("ValidateSyncCheckpoint: new sync-checkpoint %s is not a descendant of current sync-checkpoint %s", hashCheckpoint.ToString().c_str(), hashSyncCheckpoint.ToString().c_str()); + } + return true; + } + + bool WriteSyncCheckpoint(const uint256& hashCheckpoint) + { + CTxDB txdb; + txdb.TxnBegin(); + if (!txdb.WriteSyncCheckpoint(hashCheckpoint)) + { + txdb.TxnAbort(); + return error("WriteSyncCheckpoint(): failed to write to db sync checkpoint %s", hashCheckpoint.ToString().c_str()); + } + if (!txdb.TxnCommit()) + return error("WriteSyncCheckpoint(): failed to commit to db sync checkpoint %s", hashCheckpoint.ToString().c_str()); + txdb.Close(); + + Checkpoints::hashSyncCheckpoint = hashCheckpoint; + return true; + } + + bool AcceptPendingSyncCheckpoint() + { + LOCK(cs_hashSyncCheckpoint); + if (hashPendingCheckpoint != 0 && mapBlockIndex.count(hashPendingCheckpoint)) + { + if (!ValidateSyncCheckpoint(hashPendingCheckpoint)) + { + hashPendingCheckpoint = 0; + checkpointMessagePending.SetNull(); + return false; + } + + CTxDB txdb; + CBlockIndex* pindexCheckpoint = mapBlockIndex[hashPendingCheckpoint]; + if (!pindexCheckpoint->IsInMainChain()) + { + CBlock block; + if (!block.ReadFromDisk(pindexCheckpoint)) + return error("AcceptPendingSyncCheckpoint: ReadFromDisk failed for sync checkpoint %s", hashPendingCheckpoint.ToString().c_str()); + if (!block.SetBestChain(txdb, pindexCheckpoint)) + { + hashInvalidCheckpoint = hashPendingCheckpoint; + return error("AcceptPendingSyncCheckpoint: SetBestChain failed for sync checkpoint %s", hashPendingCheckpoint.ToString().c_str()); + } + } + txdb.Close(); + + if (!WriteSyncCheckpoint(hashPendingCheckpoint)) + return error("AcceptPendingSyncCheckpoint(): failed to write sync checkpoint %s", hashPendingCheckpoint.ToString().c_str()); + hashPendingCheckpoint = 0; + checkpointMessage = checkpointMessagePending; + checkpointMessagePending.SetNull(); + printf("AcceptPendingSyncCheckpoint : sync-checkpoint at %s\n", hashSyncCheckpoint.ToString().c_str()); + // relay the checkpoint + if (!checkpointMessage.IsNull()) + { + BOOST_FOREACH(CNode* pnode, vNodes) + checkpointMessage.RelayTo(pnode); + } + return true; + } + return false; + } + + // Automatically select a suitable sync-checkpoint + uint256 AutoSelectSyncCheckpoint() + { + // Proof-of-work blocks are immediately checkpointed + // to defend against 51% attack which rejects other miners block + + // Select the last proof-of-work block + const CBlockIndex *pindex = GetLastBlockIndex(pindexBest, false); + // Search forward for a block within max span and maturity window + while (pindex->pnext && (pindex->GetBlockTime() + CHECKPOINT_MAX_SPAN <= pindexBest->GetBlockTime() || pindex->nHeight + std::min(6, nCoinbaseMaturity - 20) <= pindexBest->nHeight)) + pindex = pindex->pnext; + return pindex->GetBlockHash(); + } + + // Check against synchronized checkpoint + bool CheckSync(const uint256& hashBlock, const CBlockIndex* pindexPrev) + { + if (fTestNet) return true; // Testnet has no checkpoints + int nHeight = pindexPrev->nHeight + 1; + + LOCK(cs_hashSyncCheckpoint); + // sync-checkpoint should always be accepted block + assert(mapBlockIndex.count(hashSyncCheckpoint)); + const CBlockIndex* pindexSync = mapBlockIndex[hashSyncCheckpoint]; + + if (nHeight > pindexSync->nHeight) + { + // trace back to same height as sync-checkpoint + const CBlockIndex* pindex = pindexPrev; + while (pindex->nHeight > pindexSync->nHeight) + if (!(pindex = pindex->pprev)) + return error("CheckSync: pprev null - block index structure failure"); + if (pindex->nHeight < pindexSync->nHeight || pindex->GetBlockHash() != hashSyncCheckpoint) + return false; // only descendant of sync-checkpoint can pass check + } + if (nHeight == pindexSync->nHeight && hashBlock != hashSyncCheckpoint) + return false; // same height with sync-checkpoint + if (nHeight < pindexSync->nHeight && !mapBlockIndex.count(hashBlock)) + return false; // lower height than sync-checkpoint + return true; + } + + bool WantedByPendingSyncCheckpoint(uint256 hashBlock) + { + LOCK(cs_hashSyncCheckpoint); + if (hashPendingCheckpoint == 0) + return false; + if (hashBlock == hashPendingCheckpoint) + return true; + if (mapOrphanBlocks.count(hashPendingCheckpoint) + && hashBlock == WantedByOrphan(mapOrphanBlocks[hashPendingCheckpoint])) + return true; + return false; + } + + // triangles: reset synchronized checkpoint to last hardened checkpoint + bool ResetSyncCheckpoint() + { + LOCK(cs_hashSyncCheckpoint); + const uint256& hash = mapCheckpoints.rbegin()->second; + if (mapBlockIndex.count(hash) && !mapBlockIndex[hash]->IsInMainChain()) + { + // checkpoint block accepted but not yet in main chain + printf("ResetSyncCheckpoint: SetBestChain to hardened checkpoint %s\n", hash.ToString().c_str()); + CTxDB txdb; + CBlock block; + if (!block.ReadFromDisk(mapBlockIndex[hash])) + return error("ResetSyncCheckpoint: ReadFromDisk failed for hardened checkpoint %s", hash.ToString().c_str()); + if (!block.SetBestChain(txdb, mapBlockIndex[hash])) + { + return error("ResetSyncCheckpoint: SetBestChain failed for hardened checkpoint %s", hash.ToString().c_str()); + } + txdb.Close(); + } + else if(!mapBlockIndex.count(hash)) + { + // checkpoint block not yet accepted + hashPendingCheckpoint = hash; + checkpointMessagePending.SetNull(); + printf("ResetSyncCheckpoint: pending for sync-checkpoint %s\n", hashPendingCheckpoint.ToString().c_str()); + } + + BOOST_REVERSE_FOREACH(const MapCheckpoints::value_type& i, mapCheckpoints) + { + const uint256& hash = i.second; + if (mapBlockIndex.count(hash) && mapBlockIndex[hash]->IsInMainChain()) + { + if (!WriteSyncCheckpoint(hash)) + return error("ResetSyncCheckpoint: failed to write sync checkpoint %s", hash.ToString().c_str()); + printf("ResetSyncCheckpoint: sync-checkpoint reset to %s\n", hashSyncCheckpoint.ToString().c_str()); + return true; + } + } + + return false; + } + + void AskForPendingSyncCheckpoint(CNode* pfrom) + { + LOCK(cs_hashSyncCheckpoint); + if (pfrom && hashPendingCheckpoint != 0 && (!mapBlockIndex.count(hashPendingCheckpoint)) && (!mapOrphanBlocks.count(hashPendingCheckpoint))) + pfrom->AskFor(CInv(MSG_BLOCK, hashPendingCheckpoint)); + } + + bool SetCheckpointPrivKey(std::string strPrivKey) + { + // Test signing a sync-checkpoint with genesis block + CSyncCheckpoint checkpoint; + checkpoint.hashCheckpoint = !fTestNet ? hashGenesisBlock : hashGenesisBlockTestNet; + CDataStream sMsg(SER_NETWORK, PROTOCOL_VERSION); + sMsg << (CUnsignedSyncCheckpoint)checkpoint; + checkpoint.vchMsg = std::vector(sMsg.begin(), sMsg.end()); + + std::vector vchPrivKey = ParseHex(strPrivKey); + CKey key; + key.SetPrivKey(CPrivKey(vchPrivKey.begin(), vchPrivKey.end())); // if key is not correct openssl may crash + if (!key.Sign(Hash(checkpoint.vchMsg.begin(), checkpoint.vchMsg.end()), checkpoint.vchSig)) + return false; + + // Test signing successful, proceed + CSyncCheckpoint::strMasterPrivKey = strPrivKey; + return true; + } + + bool SendSyncCheckpoint(uint256 hashCheckpoint) + { + CSyncCheckpoint checkpoint; + checkpoint.hashCheckpoint = hashCheckpoint; + CDataStream sMsg(SER_NETWORK, PROTOCOL_VERSION); + sMsg << (CUnsignedSyncCheckpoint)checkpoint; + checkpoint.vchMsg = std::vector(sMsg.begin(), sMsg.end()); + + if (CSyncCheckpoint::strMasterPrivKey.empty()) + return error("SendSyncCheckpoint: Checkpoint master key unavailable."); + std::vector vchPrivKey = ParseHex(CSyncCheckpoint::strMasterPrivKey); + CKey key; + key.SetPrivKey(CPrivKey(vchPrivKey.begin(), vchPrivKey.end())); // if key is not correct openssl may crash + if (!key.Sign(Hash(checkpoint.vchMsg.begin(), checkpoint.vchMsg.end()), checkpoint.vchSig)) + return error("SendSyncCheckpoint: Unable to sign checkpoint, check private key?"); + + if(!checkpoint.ProcessSyncCheckpoint(NULL)) + { + printf("WARNING: SendSyncCheckpoint: Failed to process checkpoint.\n"); + return false; + } + + // Relay checkpoint + { + LOCK(cs_vNodes); + BOOST_FOREACH(CNode* pnode, vNodes) + checkpoint.RelayTo(pnode); + } + return true; + } + + // Is the sync-checkpoint outside maturity window? + bool IsMatureSyncCheckpoint() + { + LOCK(cs_hashSyncCheckpoint); + // sync-checkpoint should always be accepted block + assert(mapBlockIndex.count(hashSyncCheckpoint)); + const CBlockIndex* pindexSync = mapBlockIndex[hashSyncCheckpoint]; + return (nBestHeight >= pindexSync->nHeight + nCoinbaseMaturity || + pindexSync->GetBlockTime() + nStakeMinAge < GetAdjustedTime()); + } + + // Is the sync-checkpoint too old? + bool IsSyncCheckpointTooOld(unsigned int nSeconds) + { + LOCK(cs_hashSyncCheckpoint); + // sync-checkpoint should always be accepted block + assert(mapBlockIndex.count(hashSyncCheckpoint)); + const CBlockIndex* pindexSync = mapBlockIndex[hashSyncCheckpoint]; + return (pindexSync->GetBlockTime() + nSeconds < GetAdjustedTime()); + } +} + +// triangles: sync-checkpoint master key +const std::string CSyncCheckpoint::strMasterPubKey = "404330cf0c0e76bb8591011dcb61ad4f28c48940a09db1f3588e35827c89c09aa68b432b54018c4b1f653c2dbe0d3507b6b3939af8e97fdbee543dee3fd64bf590"; + +std::string CSyncCheckpoint::strMasterPrivKey = ""; + +// triangles: verify signature of sync-checkpoint message +bool CSyncCheckpoint::CheckSignature() +{ + CKey key; + if (!key.SetPubKey(ParseHex(CSyncCheckpoint::strMasterPubKey))) + return error("CSyncCheckpoint::CheckSignature() : SetPubKey failed"); + if (!key.Verify(Hash(vchMsg.begin(), vchMsg.end()), vchSig)) + return error("CSyncCheckpoint::CheckSignature() : verify signature failed"); + + // Now unserialize the data + CDataStream sMsg(vchMsg, SER_NETWORK, PROTOCOL_VERSION); + sMsg >> *(CUnsignedSyncCheckpoint*)this; + return true; +} + +// triangles: process synchronized checkpoint +bool CSyncCheckpoint::ProcessSyncCheckpoint(CNode* pfrom) +{ + if (!CheckSignature()) + return false; + + LOCK(Checkpoints::cs_hashSyncCheckpoint); + if (!mapBlockIndex.count(hashCheckpoint)) + { + // We haven't received the checkpoint chain, keep the checkpoint as pending + Checkpoints::hashPendingCheckpoint = hashCheckpoint; + Checkpoints::checkpointMessagePending = *this; + printf("ProcessSyncCheckpoint: pending for sync-checkpoint %s\n", hashCheckpoint.ToString().c_str()); + // Ask this guy to fill in what we're missing + if (pfrom) + { + pfrom->PushGetBlocks(pindexBest, hashCheckpoint); + // ask directly as well in case rejected earlier by duplicate + // proof-of-stake because getblocks may not get it this time + pfrom->AskFor(CInv(MSG_BLOCK, mapOrphanBlocks.count(hashCheckpoint)? WantedByOrphan(mapOrphanBlocks[hashCheckpoint]) : hashCheckpoint)); + } + return false; + } + + if (!Checkpoints::ValidateSyncCheckpoint(hashCheckpoint)) + return false; + + CTxDB txdb; + CBlockIndex* pindexCheckpoint = mapBlockIndex[hashCheckpoint]; + if (!pindexCheckpoint->IsInMainChain()) + { + // checkpoint chain received but not yet main chain + CBlock block; + if (!block.ReadFromDisk(pindexCheckpoint)) + return error("ProcessSyncCheckpoint: ReadFromDisk failed for sync checkpoint %s", hashCheckpoint.ToString().c_str()); + if (!block.SetBestChain(txdb, pindexCheckpoint)) + { + Checkpoints::hashInvalidCheckpoint = hashCheckpoint; + return error("ProcessSyncCheckpoint: SetBestChain failed for sync checkpoint %s", hashCheckpoint.ToString().c_str()); + } + } + txdb.Close(); + + if (!Checkpoints::WriteSyncCheckpoint(hashCheckpoint)) + return error("ProcessSyncCheckpoint(): failed to write sync checkpoint %s", hashCheckpoint.ToString().c_str()); + Checkpoints::checkpointMessage = *this; + Checkpoints::hashPendingCheckpoint = 0; + Checkpoints::checkpointMessagePending.SetNull(); + printf("ProcessSyncCheckpoint: sync-checkpoint at %s\n", hashCheckpoint.ToString().c_str()); + return true; +} diff --git a/src/checkpoints.h b/src/checkpoints.h new file mode 100644 index 0000000..e5ab6a4 --- /dev/null +++ b/src/checkpoints.h @@ -0,0 +1,140 @@ +// Copyright (c) 2009-2012 The Bitcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. +#ifndef BITCOIN_CHECKPOINT_H +#define BITCOIN_CHECKPOINT_H + +#include +#include "net.h" +#include "util.h" + +#define CHECKPOINT_MAX_SPAN (60 * 60 * 2) // max 2 hours before latest block + +class uint256; +class CBlockIndex; +class CSyncCheckpoint; + +/** Block-chain checkpoints are compiled-in sanity checks. + * They are updated every release or three. + */ +namespace Checkpoints +{ + // Returns true if block passes checkpoint checks + bool CheckHardened(int nHeight, const uint256& hash); + + // Return conservative estimate of total number of blocks, 0 if unknown + int GetTotalBlocksEstimate(); + + // Returns last CBlockIndex* in mapBlockIndex that is a checkpoint + CBlockIndex* GetLastCheckpoint(const std::map& mapBlockIndex); + + extern uint256 hashSyncCheckpoint; + extern CSyncCheckpoint checkpointMessage; + extern uint256 hashInvalidCheckpoint; + extern CCriticalSection cs_hashSyncCheckpoint; + + CBlockIndex* GetLastSyncCheckpoint(); + bool WriteSyncCheckpoint(const uint256& hashCheckpoint); + bool AcceptPendingSyncCheckpoint(); + uint256 AutoSelectSyncCheckpoint(); + bool CheckSync(const uint256& hashBlock, const CBlockIndex* pindexPrev); + bool WantedByPendingSyncCheckpoint(uint256 hashBlock); + bool ResetSyncCheckpoint(); + void AskForPendingSyncCheckpoint(CNode* pfrom); + bool SetCheckpointPrivKey(std::string strPrivKey); + bool SendSyncCheckpoint(uint256 hashCheckpoint); + bool IsMatureSyncCheckpoint(); + bool IsSyncCheckpointTooOld(unsigned int nSeconds); +} + +// triangles: synchronized checkpoint +class CUnsignedSyncCheckpoint +{ +public: + int nVersion; + uint256 hashCheckpoint; // checkpoint block + + IMPLEMENT_SERIALIZE + ( + READWRITE(this->nVersion); + nVersion = this->nVersion; + READWRITE(hashCheckpoint); + ) + + void SetNull() + { + nVersion = 1; + hashCheckpoint = 0; + } + + std::string ToString() const + { + return strprintf( + "CSyncCheckpoint(\n" + " nVersion = %d\n" + " hashCheckpoint = %s\n" + ")\n", + nVersion, + hashCheckpoint.ToString().c_str()); + } + + void print() const + { + printf("%s", ToString().c_str()); + } +}; + +class CSyncCheckpoint : public CUnsignedSyncCheckpoint +{ +public: + static const std::string strMasterPubKey; + static std::string strMasterPrivKey; + + std::vector vchMsg; + std::vector vchSig; + + CSyncCheckpoint() + { + SetNull(); + } + + IMPLEMENT_SERIALIZE + ( + READWRITE(vchMsg); + READWRITE(vchSig); + ) + + void SetNull() + { + CUnsignedSyncCheckpoint::SetNull(); + vchMsg.clear(); + vchSig.clear(); + } + + bool IsNull() const + { + return (hashCheckpoint == 0); + } + + uint256 GetHash() const + { + return SerializeHash(*this); + } + + bool RelayTo(CNode* pnode) const + { + // returns true if wasn't already sent + if (pnode->hashCheckpointKnown != hashCheckpoint) + { + pnode->hashCheckpointKnown = hashCheckpoint; + pnode->PushMessage("checkpoint", *this); + return true; + } + return false; + } + + bool CheckSignature(); + bool ProcessSyncCheckpoint(CNode* pfrom); +}; + +#endif diff --git a/src/clientversion.h b/src/clientversion.h new file mode 100644 index 0000000..e7ba49a --- /dev/null +++ b/src/clientversion.h @@ -0,0 +1,19 @@ +#ifndef CLIENTVERSION_H +#define CLIENTVERSION_H + +// +// client versioning +// + +// These need to be macros, as version.cpp's and bitcoin-qt.rc's voodoo requires it +#define CLIENT_VERSION_MAJOR 3 +#define CLIENT_VERSION_MINOR 3 +#define CLIENT_VERSION_REVISION 3 +#define CLIENT_VERSION_BUILD 3 + +// Converts the parameter X to a string after macro replacement on X has been performed. +// Don't merge these into one macro! +#define STRINGIZE(X) DO_STRINGIZE(X) +#define DO_STRINGIZE(X) #X + +#endif // CLIENTVERSION_H diff --git a/src/coincontrol.h b/src/coincontrol.h new file mode 100644 index 0000000..236b586 --- /dev/null +++ b/src/coincontrol.h @@ -0,0 +1,57 @@ +#ifndef COINCONTROL_H +#define COINCONTROL_H + +/** Coin Control Features. */ +class CCoinControl +{ +public: + CTxDestination destChange; + + CCoinControl() + { + SetNull(); + } + + void SetNull() + { + destChange = CNoDestination(); + setSelected.clear(); + } + + bool HasSelected() const + { + return (setSelected.size() > 0); + } + + bool IsSelected(const uint256& hash, unsigned int n) const + { + COutPoint outpt(hash, n); + return (setSelected.count(outpt) > 0); + } + + void Select(COutPoint& output) + { + setSelected.insert(output); + } + + void UnSelect(COutPoint& output) + { + setSelected.erase(output); + } + + void UnSelectAll() + { + setSelected.clear(); + } + + void ListSelected(std::vector& vOutpoints) + { + vOutpoints.assign(setSelected.begin(), setSelected.end()); + } + +private: + std::set setSelected; + +}; + +#endif // COINCONTROL_H diff --git a/src/compat.h b/src/compat.h new file mode 100644 index 0000000..79ebb93 --- /dev/null +++ b/src/compat.h @@ -0,0 +1,63 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2012 The Bitcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. +#ifndef _BITCOIN_COMPAT_H +#define _BITCOIN_COMPAT_H 1 + +#ifdef WIN32 +#define _WIN32_WINNT 0x0501 +#define WIN32_LEAN_AND_MEAN 1 +#ifndef NOMINMAX +#define NOMINMAX +#endif +#include +#include +#include +#else +#include +#include +#include +#include +#include +#include +#include +#include +#endif + +typedef u_int SOCKET; +#ifdef WIN32 +#define MSG_NOSIGNAL 0 +#define MSG_DONTWAIT 0 +typedef int socklen_t; +#else +#include "errno.h" +#define WSAGetLastError() errno +#define WSAEINVAL EINVAL +#define WSAEALREADY EALREADY +#define WSAEWOULDBLOCK EWOULDBLOCK +#define WSAEMSGSIZE EMSGSIZE +#define WSAEINTR EINTR +#define WSAEINPROGRESS EINPROGRESS +#define WSAEADDRINUSE EADDRINUSE +#define WSAENOTSOCK EBADF +#define INVALID_SOCKET (SOCKET)(~0) +#define SOCKET_ERROR -1 +#endif + +inline int myclosesocket(SOCKET& hSocket) +{ + if (hSocket == INVALID_SOCKET) + return WSAENOTSOCK; +#ifdef WIN32 + int ret = closesocket(hSocket); +#else + int ret = close(hSocket); +#endif + hSocket = INVALID_SOCKET; + return ret; +} +#define closesocket(s) myclosesocket(s) + + +#endif diff --git a/src/crypter.cpp b/src/crypter.cpp new file mode 100644 index 0000000..181b8fa --- /dev/null +++ b/src/crypter.cpp @@ -0,0 +1,121 @@ +// Copyright (c) 2009-2012 The Bitcoin Developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include +#include +#include +#include +#ifdef WIN32 +#include +#endif + +#include "crypter.h" + +bool CCrypter::SetKeyFromPassphrase(const SecureString& strKeyData, const std::vector& chSalt, const unsigned int nRounds, const unsigned int nDerivationMethod) +{ + if (nRounds < 1 || chSalt.size() != WALLET_CRYPTO_SALT_SIZE) + return false; + + int i = 0; + if (nDerivationMethod == 0) + i = EVP_BytesToKey(EVP_aes_256_cbc(), EVP_sha512(), &chSalt[0], + (unsigned char *)&strKeyData[0], strKeyData.size(), nRounds, chKey, chIV); + + if (i != (int)WALLET_CRYPTO_KEY_SIZE) + { + memset(&chKey, 0, sizeof chKey); + memset(&chIV, 0, sizeof chIV); + return false; + } + + fKeySet = true; + return true; +} + +bool CCrypter::SetKey(const CKeyingMaterial& chNewKey, const std::vector& chNewIV) +{ + if (chNewKey.size() != WALLET_CRYPTO_KEY_SIZE || chNewIV.size() != WALLET_CRYPTO_KEY_SIZE) + return false; + + memcpy(&chKey[0], &chNewKey[0], sizeof chKey); + memcpy(&chIV[0], &chNewIV[0], sizeof chIV); + + fKeySet = true; + return true; +} + +bool CCrypter::Encrypt(const CKeyingMaterial& vchPlaintext, std::vector &vchCiphertext) +{ + if (!fKeySet) + return false; + + // max ciphertext len for a n bytes of plaintext is + // n + AES_BLOCK_SIZE - 1 bytes + int nLen = vchPlaintext.size(); + int nCLen = nLen + AES_BLOCK_SIZE, nFLen = 0; + vchCiphertext = std::vector (nCLen); + + EVP_CIPHER_CTX ctx; + + bool fOk = true; + + EVP_CIPHER_CTX_init(&ctx); + if (fOk) fOk = EVP_EncryptInit_ex(&ctx, EVP_aes_256_cbc(), NULL, chKey, chIV); + if (fOk) fOk = EVP_EncryptUpdate(&ctx, &vchCiphertext[0], &nCLen, &vchPlaintext[0], nLen); + if (fOk) fOk = EVP_EncryptFinal_ex(&ctx, (&vchCiphertext[0])+nCLen, &nFLen); + EVP_CIPHER_CTX_cleanup(&ctx); + + if (!fOk) return false; + + vchCiphertext.resize(nCLen + nFLen); + return true; +} + +bool CCrypter::Decrypt(const std::vector& vchCiphertext, CKeyingMaterial& vchPlaintext) +{ + if (!fKeySet) + return false; + + // plaintext will always be equal to or lesser than length of ciphertext + int nLen = vchCiphertext.size(); + int nPLen = nLen, nFLen = 0; + + vchPlaintext = CKeyingMaterial(nPLen); + + EVP_CIPHER_CTX ctx; + + bool fOk = true; + + EVP_CIPHER_CTX_init(&ctx); + if (fOk) fOk = EVP_DecryptInit_ex(&ctx, EVP_aes_256_cbc(), NULL, chKey, chIV); + if (fOk) fOk = EVP_DecryptUpdate(&ctx, &vchPlaintext[0], &nPLen, &vchCiphertext[0], nLen); + if (fOk) fOk = EVP_DecryptFinal_ex(&ctx, (&vchPlaintext[0])+nPLen, &nFLen); + EVP_CIPHER_CTX_cleanup(&ctx); + + if (!fOk) return false; + + vchPlaintext.resize(nPLen + nFLen); + return true; +} + + +bool EncryptSecret(CKeyingMaterial& vMasterKey, const CSecret &vchPlaintext, const uint256& nIV, std::vector &vchCiphertext) +{ + CCrypter cKeyCrypter; + std::vector chIV(WALLET_CRYPTO_KEY_SIZE); + memcpy(&chIV[0], &nIV, WALLET_CRYPTO_KEY_SIZE); + if(!cKeyCrypter.SetKey(vMasterKey, chIV)) + return false; + return cKeyCrypter.Encrypt((CKeyingMaterial)vchPlaintext, vchCiphertext); +} + +bool DecryptSecret(const CKeyingMaterial& vMasterKey, const std::vector& vchCiphertext, const uint256& nIV, CSecret& vchPlaintext) +{ + CCrypter cKeyCrypter; + std::vector chIV(WALLET_CRYPTO_KEY_SIZE); + memcpy(&chIV[0], &nIV, WALLET_CRYPTO_KEY_SIZE); + if(!cKeyCrypter.SetKey(vMasterKey, chIV)) + return false; + return cKeyCrypter.Decrypt(vchCiphertext, *((CKeyingMaterial*)&vchPlaintext)); +} diff --git a/src/crypter.h b/src/crypter.h new file mode 100644 index 0000000..04538a3 --- /dev/null +++ b/src/crypter.h @@ -0,0 +1,107 @@ +// Copyright (c) 2009-2012 The Bitcoin Developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. +#ifndef __CRYPTER_H__ +#define __CRYPTER_H__ + +#include "allocators.h" /* for SecureString */ +#include "key.h" +#include "serialize.h" + +const unsigned int WALLET_CRYPTO_KEY_SIZE = 32; +const unsigned int WALLET_CRYPTO_SALT_SIZE = 8; + +/* +Private key encryption is done based on a CMasterKey, +which holds a salt and random encryption key. + +CMasterKeys are encrypted using AES-256-CBC using a key +derived using derivation method nDerivationMethod +(0 == EVP_sha512()) and derivation iterations nDeriveIterations. +vchOtherDerivationParameters is provided for alternative algorithms +which may require more parameters (such as scrypt). + +Wallet Private Keys are then encrypted using AES-256-CBC +with the double-sha256 of the public key as the IV, and the +master key's key as the encryption key (see keystore.[ch]). +*/ + +/** Master key for wallet encryption */ +class CMasterKey +{ +public: + std::vector vchCryptedKey; + std::vector vchSalt; + // 0 = EVP_sha512() + // 1 = scrypt() + unsigned int nDerivationMethod; + unsigned int nDeriveIterations; + // Use this for more parameters to key derivation, + // such as the various parameters to scrypt + std::vector vchOtherDerivationParameters; + + IMPLEMENT_SERIALIZE + ( + READWRITE(vchCryptedKey); + READWRITE(vchSalt); + READWRITE(nDerivationMethod); + READWRITE(nDeriveIterations); + READWRITE(vchOtherDerivationParameters); + ) + CMasterKey() + { + // 25000 rounds is just under 0.1 seconds on a 1.86 GHz Pentium M + // ie slightly lower than the lowest hardware we need bother supporting + nDeriveIterations = 25000; + nDerivationMethod = 0; + vchOtherDerivationParameters = std::vector(0); + } +}; + +typedef std::vector > CKeyingMaterial; + +/** Encryption/decryption context with key information */ +class CCrypter +{ +private: + unsigned char chKey[WALLET_CRYPTO_KEY_SIZE]; + unsigned char chIV[WALLET_CRYPTO_KEY_SIZE]; + bool fKeySet; + +public: + bool SetKeyFromPassphrase(const SecureString &strKeyData, const std::vector& chSalt, const unsigned int nRounds, const unsigned int nDerivationMethod); + bool Encrypt(const CKeyingMaterial& vchPlaintext, std::vector &vchCiphertext); + bool Decrypt(const std::vector& vchCiphertext, CKeyingMaterial& vchPlaintext); + bool SetKey(const CKeyingMaterial& chNewKey, const std::vector& chNewIV); + + void CleanKey() + { + memset(&chKey, 0, sizeof chKey); + memset(&chIV, 0, sizeof chIV); + fKeySet = false; + } + + CCrypter() + { + fKeySet = false; + + // Try to keep the key data out of swap (and be a bit over-careful to keep the IV that we don't even use out of swap) + // Note that this does nothing about suspend-to-disk (which will put all our key data on disk) + // Note as well that at no point in this program is any attempt made to prevent stealing of keys by reading the memory of the running process. + LockedPageManager::instance.LockRange(&chKey[0], sizeof chKey); + LockedPageManager::instance.LockRange(&chIV[0], sizeof chIV); + } + + ~CCrypter() + { + CleanKey(); + + LockedPageManager::instance.UnlockRange(&chKey[0], sizeof chKey); + LockedPageManager::instance.UnlockRange(&chIV[0], sizeof chIV); + } +}; + +bool EncryptSecret(CKeyingMaterial& vMasterKey, const CSecret &vchPlaintext, const uint256& nIV, std::vector &vchCiphertext); +bool DecryptSecret(const CKeyingMaterial& vMasterKey, const std::vector &vchCiphertext, const uint256& nIV, CSecret &vchPlaintext); + +#endif diff --git a/src/cubehash.c b/src/cubehash.c new file mode 100644 index 0000000..9322fe1 --- /dev/null +++ b/src/cubehash.c @@ -0,0 +1,723 @@ +/* $Id: cubehash.c 227 2010-06-16 17:28:38Z tp $ */ +/* + * CubeHash implementation. + * + * ==========================(LICENSE BEGIN)============================ + * + * Copyright (c) 2007-2010 Projet RNRT SAPHIR + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * ===========================(LICENSE END)============================= + * + * @author Thomas Pornin + */ + +#include +#include +#include + +#include "sph_cubehash.h" +#ifdef __cplusplus +extern "C"{ +#endif + +#if SPH_SMALL_FOOTPRINT && !defined SPH_SMALL_FOOTPRINT_CUBEHASH +#define SPH_SMALL_FOOTPRINT_CUBEHASH 1 +#endif + +/* + * Some tests were conducted on an Intel Core2 Q6600 (32-bit and 64-bit + * mode), a PowerPC G3, and a MIPS-compatible CPU (Broadcom BCM3302). + * It appears that the optimal settings are: + * -- full unroll, no state copy on the "big" systems (x86, PowerPC) + * -- unroll to 4 or 8, state copy on the "small" system (MIPS) + */ + +#if SPH_SMALL_FOOTPRINT_CUBEHASH + +#if !defined SPH_CUBEHASH_UNROLL +#define SPH_CUBEHASH_UNROLL 4 +#endif +#if !defined SPH_CUBEHASH_NOCOPY +#define SPH_CUBEHASH_NOCOPY 1 +#endif + +#else + +#if !defined SPH_CUBEHASH_UNROLL +#define SPH_CUBEHASH_UNROLL 0 +#endif +#if !defined SPH_CUBEHASH_NOCOPY +#define SPH_CUBEHASH_NOCOPY 0 +#endif + +#endif + +#ifdef _MSC_VER +#pragma warning (disable: 4146) +#endif + +static const sph_u32 IV224[] = { + SPH_C32(0xB0FC8217), SPH_C32(0x1BEE1A90), SPH_C32(0x829E1A22), + SPH_C32(0x6362C342), SPH_C32(0x24D91C30), SPH_C32(0x03A7AA24), + SPH_C32(0xA63721C8), SPH_C32(0x85B0E2EF), SPH_C32(0xF35D13F3), + SPH_C32(0x41DA807D), SPH_C32(0x21A70CA6), SPH_C32(0x1F4E9774), + SPH_C32(0xB3E1C932), SPH_C32(0xEB0A79A8), SPH_C32(0xCDDAAA66), + SPH_C32(0xE2F6ECAA), SPH_C32(0x0A713362), SPH_C32(0xAA3080E0), + SPH_C32(0xD8F23A32), SPH_C32(0xCEF15E28), SPH_C32(0xDB086314), + SPH_C32(0x7F709DF7), SPH_C32(0xACD228A4), SPH_C32(0x704D6ECE), + SPH_C32(0xAA3EC95F), SPH_C32(0xE387C214), SPH_C32(0x3A6445FF), + SPH_C32(0x9CAB81C3), SPH_C32(0xC73D4B98), SPH_C32(0xD277AEBE), + SPH_C32(0xFD20151C), SPH_C32(0x00CB573E) +}; + +static const sph_u32 IV256[] = { + SPH_C32(0xEA2BD4B4), SPH_C32(0xCCD6F29F), SPH_C32(0x63117E71), + SPH_C32(0x35481EAE), SPH_C32(0x22512D5B), SPH_C32(0xE5D94E63), + SPH_C32(0x7E624131), SPH_C32(0xF4CC12BE), SPH_C32(0xC2D0B696), + SPH_C32(0x42AF2070), SPH_C32(0xD0720C35), SPH_C32(0x3361DA8C), + SPH_C32(0x28CCECA4), SPH_C32(0x8EF8AD83), SPH_C32(0x4680AC00), + SPH_C32(0x40E5FBAB), SPH_C32(0xD89041C3), SPH_C32(0x6107FBD5), + SPH_C32(0x6C859D41), SPH_C32(0xF0B26679), SPH_C32(0x09392549), + SPH_C32(0x5FA25603), SPH_C32(0x65C892FD), SPH_C32(0x93CB6285), + SPH_C32(0x2AF2B5AE), SPH_C32(0x9E4B4E60), SPH_C32(0x774ABFDD), + SPH_C32(0x85254725), SPH_C32(0x15815AEB), SPH_C32(0x4AB6AAD6), + SPH_C32(0x9CDAF8AF), SPH_C32(0xD6032C0A) +}; + +static const sph_u32 IV384[] = { + SPH_C32(0xE623087E), SPH_C32(0x04C00C87), SPH_C32(0x5EF46453), + SPH_C32(0x69524B13), SPH_C32(0x1A05C7A9), SPH_C32(0x3528DF88), + SPH_C32(0x6BDD01B5), SPH_C32(0x5057B792), SPH_C32(0x6AA7A922), + SPH_C32(0x649C7EEE), SPH_C32(0xF426309F), SPH_C32(0xCB629052), + SPH_C32(0xFC8E20ED), SPH_C32(0xB3482BAB), SPH_C32(0xF89E5E7E), + SPH_C32(0xD83D4DE4), SPH_C32(0x44BFC10D), SPH_C32(0x5FC1E63D), + SPH_C32(0x2104E6CB), SPH_C32(0x17958F7F), SPH_C32(0xDBEAEF70), + SPH_C32(0xB4B97E1E), SPH_C32(0x32C195F6), SPH_C32(0x6184A8E4), + SPH_C32(0x796C2543), SPH_C32(0x23DE176D), SPH_C32(0xD33BBAEC), + SPH_C32(0x0C12E5D2), SPH_C32(0x4EB95A7B), SPH_C32(0x2D18BA01), + SPH_C32(0x04EE475F), SPH_C32(0x1FC5F22E) +}; + +static const sph_u32 IV512[] = { + SPH_C32(0x2AEA2A61), SPH_C32(0x50F494D4), SPH_C32(0x2D538B8B), + SPH_C32(0x4167D83E), SPH_C32(0x3FEE2313), SPH_C32(0xC701CF8C), + SPH_C32(0xCC39968E), SPH_C32(0x50AC5695), SPH_C32(0x4D42C787), + SPH_C32(0xA647A8B3), SPH_C32(0x97CF0BEF), SPH_C32(0x825B4537), + SPH_C32(0xEEF864D2), SPH_C32(0xF22090C4), SPH_C32(0xD0E5CD33), + SPH_C32(0xA23911AE), SPH_C32(0xFCD398D9), SPH_C32(0x148FE485), + SPH_C32(0x1B017BEF), SPH_C32(0xB6444532), SPH_C32(0x6A536159), + SPH_C32(0x2FF5781C), SPH_C32(0x91FA7934), SPH_C32(0x0DBADEA9), + SPH_C32(0xD65C8A2B), SPH_C32(0xA5A70E75), SPH_C32(0xB1C62456), + SPH_C32(0xBC796576), SPH_C32(0x1921C8F7), SPH_C32(0xE7989AF1), + SPH_C32(0x7795D246), SPH_C32(0xD43E3B44) +}; + +#define T32 SPH_T32 +#define ROTL32 SPH_ROTL32 + +#if SPH_CUBEHASH_NOCOPY + +#define DECL_STATE +#define READ_STATE(cc) +#define WRITE_STATE(cc) + +#define x0 ((sc)->state[ 0]) +#define x1 ((sc)->state[ 1]) +#define x2 ((sc)->state[ 2]) +#define x3 ((sc)->state[ 3]) +#define x4 ((sc)->state[ 4]) +#define x5 ((sc)->state[ 5]) +#define x6 ((sc)->state[ 6]) +#define x7 ((sc)->state[ 7]) +#define x8 ((sc)->state[ 8]) +#define x9 ((sc)->state[ 9]) +#define xa ((sc)->state[10]) +#define xb ((sc)->state[11]) +#define xc ((sc)->state[12]) +#define xd ((sc)->state[13]) +#define xe ((sc)->state[14]) +#define xf ((sc)->state[15]) +#define xg ((sc)->state[16]) +#define xh ((sc)->state[17]) +#define xi ((sc)->state[18]) +#define xj ((sc)->state[19]) +#define xk ((sc)->state[20]) +#define xl ((sc)->state[21]) +#define xm ((sc)->state[22]) +#define xn ((sc)->state[23]) +#define xo ((sc)->state[24]) +#define xp ((sc)->state[25]) +#define xq ((sc)->state[26]) +#define xr ((sc)->state[27]) +#define xs ((sc)->state[28]) +#define xt ((sc)->state[29]) +#define xu ((sc)->state[30]) +#define xv ((sc)->state[31]) + +#else + +#define DECL_STATE \ + sph_u32 x0, x1, x2, x3, x4, x5, x6, x7; \ + sph_u32 x8, x9, xa, xb, xc, xd, xe, xf; \ + sph_u32 xg, xh, xi, xj, xk, xl, xm, xn; \ + sph_u32 xo, xp, xq, xr, xs, xt, xu, xv; + +#define READ_STATE(cc) do { \ + x0 = (cc)->state[ 0]; \ + x1 = (cc)->state[ 1]; \ + x2 = (cc)->state[ 2]; \ + x3 = (cc)->state[ 3]; \ + x4 = (cc)->state[ 4]; \ + x5 = (cc)->state[ 5]; \ + x6 = (cc)->state[ 6]; \ + x7 = (cc)->state[ 7]; \ + x8 = (cc)->state[ 8]; \ + x9 = (cc)->state[ 9]; \ + xa = (cc)->state[10]; \ + xb = (cc)->state[11]; \ + xc = (cc)->state[12]; \ + xd = (cc)->state[13]; \ + xe = (cc)->state[14]; \ + xf = (cc)->state[15]; \ + xg = (cc)->state[16]; \ + xh = (cc)->state[17]; \ + xi = (cc)->state[18]; \ + xj = (cc)->state[19]; \ + xk = (cc)->state[20]; \ + xl = (cc)->state[21]; \ + xm = (cc)->state[22]; \ + xn = (cc)->state[23]; \ + xo = (cc)->state[24]; \ + xp = (cc)->state[25]; \ + xq = (cc)->state[26]; \ + xr = (cc)->state[27]; \ + xs = (cc)->state[28]; \ + xt = (cc)->state[29]; \ + xu = (cc)->state[30]; \ + xv = (cc)->state[31]; \ + } while (0) + +#define WRITE_STATE(cc) do { \ + (cc)->state[ 0] = x0; \ + (cc)->state[ 1] = x1; \ + (cc)->state[ 2] = x2; \ + (cc)->state[ 3] = x3; \ + (cc)->state[ 4] = x4; \ + (cc)->state[ 5] = x5; \ + (cc)->state[ 6] = x6; \ + (cc)->state[ 7] = x7; \ + (cc)->state[ 8] = x8; \ + (cc)->state[ 9] = x9; \ + (cc)->state[10] = xa; \ + (cc)->state[11] = xb; \ + (cc)->state[12] = xc; \ + (cc)->state[13] = xd; \ + (cc)->state[14] = xe; \ + (cc)->state[15] = xf; \ + (cc)->state[16] = xg; \ + (cc)->state[17] = xh; \ + (cc)->state[18] = xi; \ + (cc)->state[19] = xj; \ + (cc)->state[20] = xk; \ + (cc)->state[21] = xl; \ + (cc)->state[22] = xm; \ + (cc)->state[23] = xn; \ + (cc)->state[24] = xo; \ + (cc)->state[25] = xp; \ + (cc)->state[26] = xq; \ + (cc)->state[27] = xr; \ + (cc)->state[28] = xs; \ + (cc)->state[29] = xt; \ + (cc)->state[30] = xu; \ + (cc)->state[31] = xv; \ + } while (0) + +#endif + +#define INPUT_BLOCK do { \ + x0 ^= sph_dec32le_aligned(buf + 0); \ + x1 ^= sph_dec32le_aligned(buf + 4); \ + x2 ^= sph_dec32le_aligned(buf + 8); \ + x3 ^= sph_dec32le_aligned(buf + 12); \ + x4 ^= sph_dec32le_aligned(buf + 16); \ + x5 ^= sph_dec32le_aligned(buf + 20); \ + x6 ^= sph_dec32le_aligned(buf + 24); \ + x7 ^= sph_dec32le_aligned(buf + 28); \ + } while (0) + +#define ROUND_EVEN do { \ + xg = T32(x0 + xg); \ + x0 = ROTL32(x0, 7); \ + xh = T32(x1 + xh); \ + x1 = ROTL32(x1, 7); \ + xi = T32(x2 + xi); \ + x2 = ROTL32(x2, 7); \ + xj = T32(x3 + xj); \ + x3 = ROTL32(x3, 7); \ + xk = T32(x4 + xk); \ + x4 = ROTL32(x4, 7); \ + xl = T32(x5 + xl); \ + x5 = ROTL32(x5, 7); \ + xm = T32(x6 + xm); \ + x6 = ROTL32(x6, 7); \ + xn = T32(x7 + xn); \ + x7 = ROTL32(x7, 7); \ + xo = T32(x8 + xo); \ + x8 = ROTL32(x8, 7); \ + xp = T32(x9 + xp); \ + x9 = ROTL32(x9, 7); \ + xq = T32(xa + xq); \ + xa = ROTL32(xa, 7); \ + xr = T32(xb + xr); \ + xb = ROTL32(xb, 7); \ + xs = T32(xc + xs); \ + xc = ROTL32(xc, 7); \ + xt = T32(xd + xt); \ + xd = ROTL32(xd, 7); \ + xu = T32(xe + xu); \ + xe = ROTL32(xe, 7); \ + xv = T32(xf + xv); \ + xf = ROTL32(xf, 7); \ + x8 ^= xg; \ + x9 ^= xh; \ + xa ^= xi; \ + xb ^= xj; \ + xc ^= xk; \ + xd ^= xl; \ + xe ^= xm; \ + xf ^= xn; \ + x0 ^= xo; \ + x1 ^= xp; \ + x2 ^= xq; \ + x3 ^= xr; \ + x4 ^= xs; \ + x5 ^= xt; \ + x6 ^= xu; \ + x7 ^= xv; \ + xi = T32(x8 + xi); \ + x8 = ROTL32(x8, 11); \ + xj = T32(x9 + xj); \ + x9 = ROTL32(x9, 11); \ + xg = T32(xa + xg); \ + xa = ROTL32(xa, 11); \ + xh = T32(xb + xh); \ + xb = ROTL32(xb, 11); \ + xm = T32(xc + xm); \ + xc = ROTL32(xc, 11); \ + xn = T32(xd + xn); \ + xd = ROTL32(xd, 11); \ + xk = T32(xe + xk); \ + xe = ROTL32(xe, 11); \ + xl = T32(xf + xl); \ + xf = ROTL32(xf, 11); \ + xq = T32(x0 + xq); \ + x0 = ROTL32(x0, 11); \ + xr = T32(x1 + xr); \ + x1 = ROTL32(x1, 11); \ + xo = T32(x2 + xo); \ + x2 = ROTL32(x2, 11); \ + xp = T32(x3 + xp); \ + x3 = ROTL32(x3, 11); \ + xu = T32(x4 + xu); \ + x4 = ROTL32(x4, 11); \ + xv = T32(x5 + xv); \ + x5 = ROTL32(x5, 11); \ + xs = T32(x6 + xs); \ + x6 = ROTL32(x6, 11); \ + xt = T32(x7 + xt); \ + x7 = ROTL32(x7, 11); \ + xc ^= xi; \ + xd ^= xj; \ + xe ^= xg; \ + xf ^= xh; \ + x8 ^= xm; \ + x9 ^= xn; \ + xa ^= xk; \ + xb ^= xl; \ + x4 ^= xq; \ + x5 ^= xr; \ + x6 ^= xo; \ + x7 ^= xp; \ + x0 ^= xu; \ + x1 ^= xv; \ + x2 ^= xs; \ + x3 ^= xt; \ + } while (0) + +#define ROUND_ODD do { \ + xj = T32(xc + xj); \ + xc = ROTL32(xc, 7); \ + xi = T32(xd + xi); \ + xd = ROTL32(xd, 7); \ + xh = T32(xe + xh); \ + xe = ROTL32(xe, 7); \ + xg = T32(xf + xg); \ + xf = ROTL32(xf, 7); \ + xn = T32(x8 + xn); \ + x8 = ROTL32(x8, 7); \ + xm = T32(x9 + xm); \ + x9 = ROTL32(x9, 7); \ + xl = T32(xa + xl); \ + xa = ROTL32(xa, 7); \ + xk = T32(xb + xk); \ + xb = ROTL32(xb, 7); \ + xr = T32(x4 + xr); \ + x4 = ROTL32(x4, 7); \ + xq = T32(x5 + xq); \ + x5 = ROTL32(x5, 7); \ + xp = T32(x6 + xp); \ + x6 = ROTL32(x6, 7); \ + xo = T32(x7 + xo); \ + x7 = ROTL32(x7, 7); \ + xv = T32(x0 + xv); \ + x0 = ROTL32(x0, 7); \ + xu = T32(x1 + xu); \ + x1 = ROTL32(x1, 7); \ + xt = T32(x2 + xt); \ + x2 = ROTL32(x2, 7); \ + xs = T32(x3 + xs); \ + x3 = ROTL32(x3, 7); \ + x4 ^= xj; \ + x5 ^= xi; \ + x6 ^= xh; \ + x7 ^= xg; \ + x0 ^= xn; \ + x1 ^= xm; \ + x2 ^= xl; \ + x3 ^= xk; \ + xc ^= xr; \ + xd ^= xq; \ + xe ^= xp; \ + xf ^= xo; \ + x8 ^= xv; \ + x9 ^= xu; \ + xa ^= xt; \ + xb ^= xs; \ + xh = T32(x4 + xh); \ + x4 = ROTL32(x4, 11); \ + xg = T32(x5 + xg); \ + x5 = ROTL32(x5, 11); \ + xj = T32(x6 + xj); \ + x6 = ROTL32(x6, 11); \ + xi = T32(x7 + xi); \ + x7 = ROTL32(x7, 11); \ + xl = T32(x0 + xl); \ + x0 = ROTL32(x0, 11); \ + xk = T32(x1 + xk); \ + x1 = ROTL32(x1, 11); \ + xn = T32(x2 + xn); \ + x2 = ROTL32(x2, 11); \ + xm = T32(x3 + xm); \ + x3 = ROTL32(x3, 11); \ + xp = T32(xc + xp); \ + xc = ROTL32(xc, 11); \ + xo = T32(xd + xo); \ + xd = ROTL32(xd, 11); \ + xr = T32(xe + xr); \ + xe = ROTL32(xe, 11); \ + xq = T32(xf + xq); \ + xf = ROTL32(xf, 11); \ + xt = T32(x8 + xt); \ + x8 = ROTL32(x8, 11); \ + xs = T32(x9 + xs); \ + x9 = ROTL32(x9, 11); \ + xv = T32(xa + xv); \ + xa = ROTL32(xa, 11); \ + xu = T32(xb + xu); \ + xb = ROTL32(xb, 11); \ + x0 ^= xh; \ + x1 ^= xg; \ + x2 ^= xj; \ + x3 ^= xi; \ + x4 ^= xl; \ + x5 ^= xk; \ + x6 ^= xn; \ + x7 ^= xm; \ + x8 ^= xp; \ + x9 ^= xo; \ + xa ^= xr; \ + xb ^= xq; \ + xc ^= xt; \ + xd ^= xs; \ + xe ^= xv; \ + xf ^= xu; \ + } while (0) + +/* + * There is no need to unroll all 16 rounds. The word-swapping permutation + * is an involution, so we need to unroll an even number of rounds. On + * "big" systems, unrolling 4 rounds yields about 97% of the speed + * achieved with full unrolling; and it keeps the code more compact + * for small architectures. + */ + +#if SPH_CUBEHASH_UNROLL == 2 + +#define SIXTEEN_ROUNDS do { \ + int j; \ + for (j = 0; j < 8; j ++) { \ + ROUND_EVEN; \ + ROUND_ODD; \ + } \ + } while (0) + +#elif SPH_CUBEHASH_UNROLL == 4 + +#define SIXTEEN_ROUNDS do { \ + int j; \ + for (j = 0; j < 4; j ++) { \ + ROUND_EVEN; \ + ROUND_ODD; \ + ROUND_EVEN; \ + ROUND_ODD; \ + } \ + } while (0) + +#elif SPH_CUBEHASH_UNROLL == 8 + +#define SIXTEEN_ROUNDS do { \ + int j; \ + for (j = 0; j < 2; j ++) { \ + ROUND_EVEN; \ + ROUND_ODD; \ + ROUND_EVEN; \ + ROUND_ODD; \ + ROUND_EVEN; \ + ROUND_ODD; \ + ROUND_EVEN; \ + ROUND_ODD; \ + } \ + } while (0) + +#else + +#define SIXTEEN_ROUNDS do { \ + ROUND_EVEN; \ + ROUND_ODD; \ + ROUND_EVEN; \ + ROUND_ODD; \ + ROUND_EVEN; \ + ROUND_ODD; \ + ROUND_EVEN; \ + ROUND_ODD; \ + ROUND_EVEN; \ + ROUND_ODD; \ + ROUND_EVEN; \ + ROUND_ODD; \ + ROUND_EVEN; \ + ROUND_ODD; \ + ROUND_EVEN; \ + ROUND_ODD; \ + } while (0) + +#endif + +static void +cubehash_init(sph_cubehash_context *sc, const sph_u32 *iv) +{ + memcpy(sc->state, iv, sizeof sc->state); + sc->ptr = 0; +} + +static void +cubehash_core(sph_cubehash_context *sc, const void *data, size_t len) +{ + unsigned char *buf; + size_t ptr; + DECL_STATE + + buf = sc->buf; + ptr = sc->ptr; + if (len < (sizeof sc->buf) - ptr) { + memcpy(buf + ptr, data, len); + ptr += len; + sc->ptr = ptr; + return; + } + + READ_STATE(sc); + while (len > 0) { + size_t clen; + + clen = (sizeof sc->buf) - ptr; + if (clen > len) + clen = len; + memcpy(buf + ptr, data, clen); + ptr += clen; + data = (const unsigned char *)data + clen; + len -= clen; + if (ptr == sizeof sc->buf) { + INPUT_BLOCK; + SIXTEEN_ROUNDS; + ptr = 0; + } + } + WRITE_STATE(sc); + sc->ptr = ptr; +} + +static void +cubehash_close(sph_cubehash_context *sc, unsigned ub, unsigned n, + void *dst, size_t out_size_w32) +{ + unsigned char *buf, *out; + size_t ptr; + unsigned z; + int i; + DECL_STATE + + buf = sc->buf; + ptr = sc->ptr; + z = 0x80 >> n; + buf[ptr ++] = ((ub & -z) | z) & 0xFF; + memset(buf + ptr, 0, (sizeof sc->buf) - ptr); + READ_STATE(sc); + INPUT_BLOCK; + for (i = 0; i < 11; i ++) { + SIXTEEN_ROUNDS; + if (i == 0) + xv ^= SPH_C32(1); + } + WRITE_STATE(sc); + out = dst; + for (z = 0; z < out_size_w32; z ++) + sph_enc32le(out + (z << 2), sc->state[z]); +} + +/* see sph_cubehash.h */ +void +sph_cubehash224_init(void *cc) +{ + cubehash_init(cc, IV224); +} + +/* see sph_cubehash.h */ +void +sph_cubehash224(void *cc, const void *data, size_t len) +{ + cubehash_core(cc, data, len); +} + +/* see sph_cubehash.h */ +void +sph_cubehash224_close(void *cc, void *dst) +{ + sph_cubehash224_addbits_and_close(cc, 0, 0, dst); +} + +/* see sph_cubehash.h */ +void +sph_cubehash224_addbits_and_close(void *cc, unsigned ub, unsigned n, void *dst) +{ + cubehash_close(cc, ub, n, dst, 7); + sph_cubehash224_init(cc); +} + +/* see sph_cubehash.h */ +void +sph_cubehash256_init(void *cc) +{ + cubehash_init(cc, IV256); +} + +/* see sph_cubehash.h */ +void +sph_cubehash256(void *cc, const void *data, size_t len) +{ + cubehash_core(cc, data, len); +} + +/* see sph_cubehash.h */ +void +sph_cubehash256_close(void *cc, void *dst) +{ + sph_cubehash256_addbits_and_close(cc, 0, 0, dst); +} + +/* see sph_cubehash.h */ +void +sph_cubehash256_addbits_and_close(void *cc, unsigned ub, unsigned n, void *dst) +{ + cubehash_close(cc, ub, n, dst, 8); + sph_cubehash256_init(cc); +} + +/* see sph_cubehash.h */ +void +sph_cubehash384_init(void *cc) +{ + cubehash_init(cc, IV384); +} + +/* see sph_cubehash.h */ +void +sph_cubehash384(void *cc, const void *data, size_t len) +{ + cubehash_core(cc, data, len); +} + +/* see sph_cubehash.h */ +void +sph_cubehash384_close(void *cc, void *dst) +{ + sph_cubehash384_addbits_and_close(cc, 0, 0, dst); +} + +/* see sph_cubehash.h */ +void +sph_cubehash384_addbits_and_close(void *cc, unsigned ub, unsigned n, void *dst) +{ + cubehash_close(cc, ub, n, dst, 12); + sph_cubehash384_init(cc); +} + +/* see sph_cubehash.h */ +void +sph_cubehash512_init(void *cc) +{ + cubehash_init(cc, IV512); +} + +/* see sph_cubehash.h */ +void +sph_cubehash512(void *cc, const void *data, size_t len) +{ + cubehash_core(cc, data, len); +} + +/* see sph_cubehash.h */ +void +sph_cubehash512_close(void *cc, void *dst) +{ + sph_cubehash512_addbits_and_close(cc, 0, 0, dst); +} + +/* see sph_cubehash.h */ +void +sph_cubehash512_addbits_and_close(void *cc, unsigned ub, unsigned n, void *dst) +{ + cubehash_close(cc, ub, n, dst, 16); + sph_cubehash512_init(cc); +} +#ifdef __cplusplus +} +#endif diff --git a/src/db.cpp b/src/db.cpp new file mode 100644 index 0000000..cfe173f --- /dev/null +++ b/src/db.cpp @@ -0,0 +1,976 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2012 The Bitcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "db.h" +#include "net.h" +#include "checkpoints.h" +#include "util.h" +#include "main.h" +#include "kernel.h" +#include +#include +#include + +#ifndef WIN32 +#include "sys/stat.h" +#endif + +using namespace std; +using namespace boost; + + +unsigned int nWalletDBUpdated; + + + +// +// CDB +// + +CDBEnv bitdb; + +void CDBEnv::EnvShutdown() +{ + if (!fDbEnvInit) + return; + + fDbEnvInit = false; + int ret = dbenv.close(0); + if (ret != 0) + printf("EnvShutdown exception: %s (%d)\n", DbEnv::strerror(ret), ret); + if (!fMockDb) + DbEnv(0).remove(strPath.c_str(), 0); +} + +CDBEnv::CDBEnv() : dbenv(DB_CXX_NO_EXCEPTIONS) +{ + fDbEnvInit = false; + fMockDb = false; +} + +CDBEnv::~CDBEnv() +{ + EnvShutdown(); +} + +void CDBEnv::Close() +{ + EnvShutdown(); +} + +bool CDBEnv::Open(boost::filesystem::path pathEnv_) +{ + if (fDbEnvInit) + return true; + + if (fShutdown) + return false; + + pathEnv = pathEnv_; + filesystem::path pathDataDir = pathEnv; + strPath = pathDataDir.string(); + filesystem::path pathLogDir = pathDataDir / "database"; + filesystem::create_directory(pathLogDir); + filesystem::path pathErrorFile = pathDataDir / "db.log"; + printf("dbenv.open LogDir=%s ErrorFile=%s\n", pathLogDir.string().c_str(), pathErrorFile.string().c_str()); + + unsigned int nEnvFlags = 0; + if (GetBoolArg("-privdb", true)) + nEnvFlags |= DB_PRIVATE; + + int nDbCache = GetArg("-dbcache", 25); + dbenv.set_lg_dir(pathLogDir.string().c_str()); + dbenv.set_cachesize(nDbCache / 1024, (nDbCache % 1024)*1048576, 1); + dbenv.set_lg_bsize(1048576); + dbenv.set_lg_max(10485760); + dbenv.set_lk_max_locks(10000); + dbenv.set_lk_max_objects(10000); + dbenv.set_errfile(fopen(pathErrorFile.string().c_str(), "a")); /// debug + dbenv.set_flags(DB_AUTO_COMMIT, 1); + dbenv.set_flags(DB_TXN_WRITE_NOSYNC, 1); +// dbenv.log_set_config(DB_LOG_AUTO_REMOVE, 1); + int ret = dbenv.open(strPath.c_str(), + DB_CREATE | + DB_INIT_LOCK | + DB_INIT_LOG | + DB_INIT_MPOOL | + DB_INIT_TXN | + DB_THREAD | + DB_RECOVER | + nEnvFlags, + S_IRUSR | S_IWUSR); + if (ret != 0) + return error("CDB() : error %s (%d) opening database environment", DbEnv::strerror(ret), ret); + + fDbEnvInit = true; + fMockDb = false; + return true; +} + +void CDBEnv::MakeMock() +{ + if (fDbEnvInit) + throw runtime_error("CDBEnv::MakeMock(): already initialized"); + + if (fShutdown) + throw runtime_error("CDBEnv::MakeMock(): during shutdown"); + + printf("CDBEnv::MakeMock()\n"); + + dbenv.set_cachesize(1, 0, 1); + dbenv.set_lg_bsize(10485760*4); + dbenv.set_lg_max(10485760); + dbenv.set_lk_max_locks(10000); + dbenv.set_lk_max_objects(10000); + dbenv.set_flags(DB_AUTO_COMMIT, 1); +// dbenv.log_set_config(DB_LOG_IN_MEMORY, 1); + int ret = dbenv.open(NULL, + DB_CREATE | + DB_INIT_LOCK | + DB_INIT_LOG | + DB_INIT_MPOOL | + DB_INIT_TXN | + DB_THREAD | + DB_PRIVATE, + S_IRUSR | S_IWUSR); + if (ret > 0) + throw runtime_error(strprintf("CDBEnv::MakeMock(): error %d opening database environment", ret)); + + fDbEnvInit = true; + fMockDb = true; +} + +CDBEnv::VerifyResult CDBEnv::Verify(std::string strFile, bool (*recoverFunc)(CDBEnv& dbenv, std::string strFile)) +{ + LOCK(cs_db); + assert(mapFileUseCount.count(strFile) == 0); + + Db db(&dbenv, 0); + int result = db.verify(strFile.c_str(), NULL, NULL, 0); + if (result == 0) + return VERIFY_OK; + else if (recoverFunc == NULL) + return RECOVER_FAIL; + + // Try to recover: + bool fRecovered = (*recoverFunc)(*this, strFile); + return (fRecovered ? RECOVER_OK : RECOVER_FAIL); +} + +bool CDBEnv::Salvage(std::string strFile, bool fAggressive, + std::vector& vResult) +{ + LOCK(cs_db); + assert(mapFileUseCount.count(strFile) == 0); + + u_int32_t flags = DB_SALVAGE; + if (fAggressive) flags |= DB_AGGRESSIVE; + + stringstream strDump; + + Db db(&dbenv, 0); + int result = db.verify(strFile.c_str(), NULL, &strDump, flags); + if (result != 0) + { + printf("ERROR: db salvage failed\n"); + return false; + } + + // Format of bdb dump is ascii lines: + // header lines... + // HEADER=END + // hexadecimal key + // hexadecimal value + // ... repeated + // DATA=END + + string strLine; + while (!strDump.eof() && strLine != "HEADER=END") + getline(strDump, strLine); // Skip past header + + std::string keyHex, valueHex; + while (!strDump.eof() && keyHex != "DATA=END") + { + getline(strDump, keyHex); + if (keyHex != "DATA_END") + { + getline(strDump, valueHex); + vResult.push_back(make_pair(ParseHex(keyHex),ParseHex(valueHex))); + } + } + + return (result == 0); +} + + +void CDBEnv::CheckpointLSN(std::string strFile) +{ + dbenv.txn_checkpoint(0, 0, 0); + if (fMockDb) + return; + dbenv.lsn_reset(strFile.c_str(), 0); +} + + +CDB::CDB(const char *pszFile, const char* pszMode) : + pdb(NULL), activeTxn(NULL) +{ + int ret; + if (pszFile == NULL) + return; + + fReadOnly = (!strchr(pszMode, '+') && !strchr(pszMode, 'w')); + bool fCreate = strchr(pszMode, 'c'); + unsigned int nFlags = DB_THREAD; + if (fCreate) + nFlags |= DB_CREATE; + + { + LOCK(bitdb.cs_db); + if (!bitdb.Open(GetDataDir())) + throw runtime_error("env open failed"); + + strFile = pszFile; + ++bitdb.mapFileUseCount[strFile]; + pdb = bitdb.mapDb[strFile]; + if (pdb == NULL) + { + pdb = new Db(&bitdb.dbenv, 0); + + bool fMockDb = bitdb.IsMock(); + if (fMockDb) + { + DbMpoolFile*mpf = pdb->get_mpf(); + ret = mpf->set_flags(DB_MPOOL_NOFILE, 1); + if (ret != 0) + throw runtime_error(strprintf("CDB() : failed to configure for no temp file backing for database %s", pszFile)); + } + + ret = pdb->open(NULL, // Txn pointer + fMockDb ? NULL : pszFile, // Filename + "main", // Logical db name + DB_BTREE, // Database type + nFlags, // Flags + 0); + + if (ret != 0) + { + delete pdb; + pdb = NULL; + --bitdb.mapFileUseCount[strFile]; + strFile = ""; + throw runtime_error(strprintf("CDB() : can't open database file %s, error %d", pszFile, ret)); + } + + if (fCreate && !Exists(string("version"))) + { + bool fTmp = fReadOnly; + fReadOnly = false; + WriteVersion(CLIENT_VERSION); + fReadOnly = fTmp; + } + + bitdb.mapDb[strFile] = pdb; + } + } +} + +static bool IsChainFile(std::string strFile) +{ + if (strFile == "blkindex.dat") + return true; + + return false; +} + +void CDB::Close() +{ + if (!pdb) + return; + if (activeTxn) + activeTxn->abort(); + activeTxn = NULL; + pdb = NULL; + + // Flush database activity from memory pool to disk log + unsigned int nMinutes = 0; + if (fReadOnly) + nMinutes = 1; + if (IsChainFile(strFile)) + nMinutes = 2; + if (IsChainFile(strFile) && IsInitialBlockDownload()) + nMinutes = 5; + + bitdb.dbenv.txn_checkpoint(nMinutes ? GetArg("-dblogsize", 100)*1024 : 0, nMinutes, 0); + + { + LOCK(bitdb.cs_db); + --bitdb.mapFileUseCount[strFile]; + } +} + +void CDBEnv::CloseDb(const string& strFile) +{ + { + LOCK(cs_db); + if (mapDb[strFile] != NULL) + { + // Close the database handle + Db* pdb = mapDb[strFile]; + pdb->close(0); + delete pdb; + mapDb[strFile] = NULL; + } + } +} + +bool CDBEnv::RemoveDb(const string& strFile) +{ + this->CloseDb(strFile); + + LOCK(cs_db); + int rc = dbenv.dbremove(NULL, strFile.c_str(), NULL, DB_AUTO_COMMIT); + return (rc == 0); +} + +bool CDB::Rewrite(const string& strFile, const char* pszSkip) +{ + while (!fShutdown) + { + { + LOCK(bitdb.cs_db); + if (!bitdb.mapFileUseCount.count(strFile) || bitdb.mapFileUseCount[strFile] == 0) + { + // Flush log data to the dat file + bitdb.CloseDb(strFile); + bitdb.CheckpointLSN(strFile); + bitdb.mapFileUseCount.erase(strFile); + + bool fSuccess = true; + printf("Rewriting %s...\n", strFile.c_str()); + string strFileRes = strFile + ".rewrite"; + { // surround usage of db with extra {} + CDB db(strFile.c_str(), "r"); + Db* pdbCopy = new Db(&bitdb.dbenv, 0); + + int ret = pdbCopy->open(NULL, // Txn pointer + strFileRes.c_str(), // Filename + "main", // Logical db name + DB_BTREE, // Database type + DB_CREATE, // Flags + 0); + if (ret > 0) + { + printf("Cannot create database file %s\n", strFileRes.c_str()); + fSuccess = false; + } + + Dbc* pcursor = db.GetCursor(); + if (pcursor) + while (fSuccess) + { + CDataStream ssKey(SER_DISK, CLIENT_VERSION); + CDataStream ssValue(SER_DISK, CLIENT_VERSION); + int ret = db.ReadAtCursor(pcursor, ssKey, ssValue, DB_NEXT); + if (ret == DB_NOTFOUND) + { + pcursor->close(); + break; + } + else if (ret != 0) + { + pcursor->close(); + fSuccess = false; + break; + } + if (pszSkip && + strncmp(&ssKey[0], pszSkip, std::min(ssKey.size(), strlen(pszSkip))) == 0) + continue; + if (strncmp(&ssKey[0], "\x07version", 8) == 0) + { + // Update version: + ssValue.clear(); + ssValue << CLIENT_VERSION; + } + Dbt datKey(&ssKey[0], ssKey.size()); + Dbt datValue(&ssValue[0], ssValue.size()); + int ret2 = pdbCopy->put(NULL, &datKey, &datValue, DB_NOOVERWRITE); + if (ret2 > 0) + fSuccess = false; + } + if (fSuccess) + { + db.Close(); + bitdb.CloseDb(strFile); + if (pdbCopy->close(0)) + fSuccess = false; + delete pdbCopy; + } + } + if (fSuccess) + { + Db dbA(&bitdb.dbenv, 0); + if (dbA.remove(strFile.c_str(), NULL, 0)) + fSuccess = false; + Db dbB(&bitdb.dbenv, 0); + if (dbB.rename(strFileRes.c_str(), NULL, strFile.c_str(), 0)) + fSuccess = false; + } + if (!fSuccess) + printf("Rewriting of %s FAILED!\n", strFileRes.c_str()); + return fSuccess; + } + } + Sleep(100); + } + return false; +} + + +void CDBEnv::Flush(bool fShutdown) +{ + int64 nStart = GetTimeMillis(); + // Flush log data to the actual data file + // on all files that are not in use + printf("Flush(%s)%s\n", fShutdown ? "true" : "false", fDbEnvInit ? "" : " db not started"); + if (!fDbEnvInit) + return; + { + LOCK(cs_db); + map::iterator mi = mapFileUseCount.begin(); + while (mi != mapFileUseCount.end()) + { + string strFile = (*mi).first; + int nRefCount = (*mi).second; + printf("%s refcount=%d\n", strFile.c_str(), nRefCount); + if (nRefCount == 0) + { + // Move log data to the dat file + CloseDb(strFile); + printf("%s checkpoint\n", strFile.c_str()); + dbenv.txn_checkpoint(0, 0, 0); + if (!IsChainFile(strFile) || fDetachDB) { + printf("%s detach\n", strFile.c_str()); + if (!fMockDb) + dbenv.lsn_reset(strFile.c_str(), 0); + } + printf("%s closed\n", strFile.c_str()); + mapFileUseCount.erase(mi++); + } + else + mi++; + } + printf("DBFlush(%s)%s ended %15"PRI64d"ms\n", fShutdown ? "true" : "false", fDbEnvInit ? "" : " db not started", GetTimeMillis() - nStart); + if (fShutdown) + { + char** listp; + if (mapFileUseCount.empty()) + { + dbenv.log_archive(&listp, DB_ARCH_REMOVE); + Close(); + } + } + } +} + + + + + + +// +// CTxDB +// + +bool CTxDB::ReadTxIndex(uint256 hash, CTxIndex& txindex) +{ + assert(!fClient); + txindex.SetNull(); + return Read(make_pair(string("tx"), hash), txindex); +} + +bool CTxDB::UpdateTxIndex(uint256 hash, const CTxIndex& txindex) +{ + assert(!fClient); + return Write(make_pair(string("tx"), hash), txindex); +} + +bool CTxDB::AddTxIndex(const CTransaction& tx, const CDiskTxPos& pos, int nHeight) +{ + assert(!fClient); + + // Add to tx index + uint256 hash = tx.GetHash(); + CTxIndex txindex(pos, tx.vout.size()); + return Write(make_pair(string("tx"), hash), txindex); +} + +bool CTxDB::EraseTxIndex(const CTransaction& tx) +{ + assert(!fClient); + uint256 hash = tx.GetHash(); + + return Erase(make_pair(string("tx"), hash)); +} + +bool CTxDB::ContainsTx(uint256 hash) +{ + assert(!fClient); + return Exists(make_pair(string("tx"), hash)); +} + +bool CTxDB::ReadDiskTx(uint256 hash, CTransaction& tx, CTxIndex& txindex) +{ + assert(!fClient); + tx.SetNull(); + if (!ReadTxIndex(hash, txindex)) + return false; + return (tx.ReadFromDisk(txindex.pos)); +} + +bool CTxDB::ReadDiskTx(uint256 hash, CTransaction& tx) +{ + CTxIndex txindex; + return ReadDiskTx(hash, tx, txindex); +} + +bool CTxDB::ReadDiskTx(COutPoint outpoint, CTransaction& tx, CTxIndex& txindex) +{ + return ReadDiskTx(outpoint.hash, tx, txindex); +} + +bool CTxDB::ReadDiskTx(COutPoint outpoint, CTransaction& tx) +{ + CTxIndex txindex; + return ReadDiskTx(outpoint.hash, tx, txindex); +} + +bool CTxDB::WriteBlockIndex(const CDiskBlockIndex& blockindex) +{ + return Write(make_pair(string("blockindex"), blockindex.GetBlockHash()), blockindex); +} + +bool CTxDB::ReadHashBestChain(uint256& hashBestChain) +{ + return Read(string("hashBestChain"), hashBestChain); +} + +bool CTxDB::WriteHashBestChain(uint256 hashBestChain) +{ + return Write(string("hashBestChain"), hashBestChain); +} + +bool CTxDB::ReadBestInvalidTrust(CBigNum& bnBestInvalidTrust) +{ + return Read(string("bnBestInvalidTrust"), bnBestInvalidTrust); +} + +bool CTxDB::WriteBestInvalidTrust(CBigNum bnBestInvalidTrust) +{ + return Write(string("bnBestInvalidTrust"), bnBestInvalidTrust); +} + +bool CTxDB::ReadSyncCheckpoint(uint256& hashCheckpoint) +{ + return Read(string("hashSyncCheckpoint"), hashCheckpoint); +} + +bool CTxDB::WriteSyncCheckpoint(uint256 hashCheckpoint) +{ + return Write(string("hashSyncCheckpoint"), hashCheckpoint); +} + +bool CTxDB::ReadCheckpointPubKey(string& strPubKey) +{ + return Read(string("strCheckpointPubKey"), strPubKey); +} + +bool CTxDB::WriteCheckpointPubKey(const string& strPubKey) +{ + return Write(string("strCheckpointPubKey"), strPubKey); +} + +CBlockIndex static * InsertBlockIndex(uint256 hash) +{ + if (hash == 0) + return NULL; + + // Return existing + map::iterator mi = mapBlockIndex.find(hash); + if (mi != mapBlockIndex.end()) + return (*mi).second; + + // Create new + CBlockIndex* pindexNew = new CBlockIndex(); + if (!pindexNew) + throw runtime_error("LoadBlockIndex() : new CBlockIndex failed"); + mi = mapBlockIndex.insert(make_pair(hash, pindexNew)).first; + pindexNew->phashBlock = &((*mi).first); + + return pindexNew; +} + +bool CTxDB::LoadBlockIndex() +{ + if (!LoadBlockIndexGuts()) + return false; + + if (fRequestShutdown) + return true; + + // Calculate bnChainTrust + vector > vSortedByHeight; + vSortedByHeight.reserve(mapBlockIndex.size()); + BOOST_FOREACH(const PAIRTYPE(uint256, CBlockIndex*)& item, mapBlockIndex) + { + CBlockIndex* pindex = item.second; + vSortedByHeight.push_back(make_pair(pindex->nHeight, pindex)); + } + sort(vSortedByHeight.begin(), vSortedByHeight.end()); + BOOST_FOREACH(const PAIRTYPE(int, CBlockIndex*)& item, vSortedByHeight) + { + CBlockIndex* pindex = item.second; + pindex->bnChainTrust = (pindex->pprev ? pindex->pprev->bnChainTrust : 0) + pindex->GetBlockTrust(); + // triangles: calculate stake modifier checksum + pindex->nStakeModifierChecksum = GetStakeModifierChecksum(pindex); + if (!CheckStakeModifierCheckpoints(pindex->nHeight, pindex->nStakeModifierChecksum)) + return error("CTxDB::LoadBlockIndex() : Failed stake modifier checkpoint height=%d, modifier=0x%016"PRI64x, pindex->nHeight, pindex->nStakeModifier); + } + + // Load hashBestChain pointer to end of best chain + if (!ReadHashBestChain(hashBestChain)) + { + if (pindexGenesisBlock == NULL) + return true; + return error("CTxDB::LoadBlockIndex() : hashBestChain not loaded"); + } + if (!mapBlockIndex.count(hashBestChain)) + return error("CTxDB::LoadBlockIndex() : hashBestChain not found in the block index"); + pindexBest = mapBlockIndex[hashBestChain]; + nBestHeight = pindexBest->nHeight; + bnBestChainTrust = pindexBest->bnChainTrust; + printf("LoadBlockIndex(): hashBestChain=%s height=%d trust=%s date=%s\n", + hashBestChain.ToString().substr(0,20).c_str(), nBestHeight, bnBestChainTrust.ToString().c_str(), + DateTimeStrFormat("%x %H:%M:%S", pindexBest->GetBlockTime()).c_str()); + + // triangles: load hashSyncCheckpoint + if (!ReadSyncCheckpoint(Checkpoints::hashSyncCheckpoint)) + return error("CTxDB::LoadBlockIndex() : hashSyncCheckpoint not loaded"); + printf("LoadBlockIndex(): synchronized checkpoint %s\n", Checkpoints::hashSyncCheckpoint.ToString().c_str()); + + // Load bnBestInvalidTrust, OK if it doesn't exist + ReadBestInvalidTrust(bnBestInvalidTrust); + + // Verify blocks in the best chain + int nCheckLevel = GetArg("-checklevel", 1); + int nCheckDepth = GetArg( "-checkblocks", 2500); + if (nCheckDepth == 0) + nCheckDepth = 1000000000; // suffices until the year 19000 + if (nCheckDepth > nBestHeight) + nCheckDepth = nBestHeight; + printf("Verifying last %i blocks at level %i\n", nCheckDepth, nCheckLevel); + CBlockIndex* pindexFork = NULL; + map, CBlockIndex*> mapBlockPos; + for (CBlockIndex* pindex = pindexBest; pindex && pindex->pprev; pindex = pindex->pprev) + { + if (fRequestShutdown || pindex->nHeight < nBestHeight-nCheckDepth) + break; + CBlock block; + if (!block.ReadFromDisk(pindex)) + return error("LoadBlockIndex() : block.ReadFromDisk failed"); + // check level 1: verify block validity + if (nCheckLevel>0 && !block.CheckBlock()) + { + printf("LoadBlockIndex() : *** found bad block at %d, hash=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString().c_str()); + pindexFork = pindex->pprev; + } + // check level 2: verify transaction index validity + if (nCheckLevel>1) + { + pair pos = make_pair(pindex->nFile, pindex->nBlockPos); + mapBlockPos[pos] = pindex; + BOOST_FOREACH(const CTransaction &tx, block.vtx) + { + uint256 hashTx = tx.GetHash(); + CTxIndex txindex; + if (ReadTxIndex(hashTx, txindex)) + { + // check level 3: checker transaction hashes + if (nCheckLevel>2 || pindex->nFile != txindex.pos.nFile || pindex->nBlockPos != txindex.pos.nBlockPos) + { + // either an error or a duplicate transaction + CTransaction txFound; + if (!txFound.ReadFromDisk(txindex.pos)) + { + printf("LoadBlockIndex() : *** cannot read mislocated transaction %s\n", hashTx.ToString().c_str()); + pindexFork = pindex->pprev; + } + else + if (txFound.GetHash() != hashTx) // not a duplicate tx + { + printf("LoadBlockIndex(): *** invalid tx position for %s\n", hashTx.ToString().c_str()); + pindexFork = pindex->pprev; + } + } + // check level 4: check whether spent txouts were spent within the main chain + unsigned int nOutput = 0; + if (nCheckLevel>3) + { + BOOST_FOREACH(const CDiskTxPos &txpos, txindex.vSpent) + { + if (!txpos.IsNull()) + { + pair posFind = make_pair(txpos.nFile, txpos.nBlockPos); + if (!mapBlockPos.count(posFind)) + { + printf("LoadBlockIndex(): *** found bad spend at %d, hashBlock=%s, hashTx=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString().c_str(), hashTx.ToString().c_str()); + pindexFork = pindex->pprev; + } + // check level 6: check whether spent txouts were spent by a valid transaction that consume them + if (nCheckLevel>5) + { + CTransaction txSpend; + if (!txSpend.ReadFromDisk(txpos)) + { + printf("LoadBlockIndex(): *** cannot read spending transaction of %s:%i from disk\n", hashTx.ToString().c_str(), nOutput); + pindexFork = pindex->pprev; + } + else if (!txSpend.CheckTransaction()) + { + printf("LoadBlockIndex(): *** spending transaction of %s:%i is invalid\n", hashTx.ToString().c_str(), nOutput); + pindexFork = pindex->pprev; + } + else + { + bool fFound = false; + BOOST_FOREACH(const CTxIn &txin, txSpend.vin) + if (txin.prevout.hash == hashTx && txin.prevout.n == nOutput) + fFound = true; + if (!fFound) + { + printf("LoadBlockIndex(): *** spending transaction of %s:%i does not spend it\n", hashTx.ToString().c_str(), nOutput); + pindexFork = pindex->pprev; + } + } + } + } + nOutput++; + } + } + } + // check level 5: check whether all prevouts are marked spent + if (nCheckLevel>4) + { + BOOST_FOREACH(const CTxIn &txin, tx.vin) + { + CTxIndex txindex; + if (ReadTxIndex(txin.prevout.hash, txindex)) + if (txindex.vSpent.size()-1 < txin.prevout.n || txindex.vSpent[txin.prevout.n].IsNull()) + { + printf("LoadBlockIndex(): *** found unspent prevout %s:%i in %s\n", txin.prevout.hash.ToString().c_str(), txin.prevout.n, hashTx.ToString().c_str()); + pindexFork = pindex->pprev; + } + } + } + } + } + } + if (pindexFork && !fRequestShutdown) + { + // Reorg back to the fork + printf("LoadBlockIndex() : *** moving best chain pointer back to block %d\n", pindexFork->nHeight); + CBlock block; + if (!block.ReadFromDisk(pindexFork)) + return error("LoadBlockIndex() : block.ReadFromDisk failed"); + CTxDB txdb; + block.SetBestChain(txdb, pindexFork); + } + + return true; +} + + + +bool CTxDB::LoadBlockIndexGuts() +{ + // Get database cursor + Dbc* pcursor = GetCursor(); + if (!pcursor) + return false; + + // Load mapBlockIndex + unsigned int fFlags = DB_SET_RANGE; + loop + { + // Read next record + CDataStream ssKey(SER_DISK, CLIENT_VERSION); + if (fFlags == DB_SET_RANGE) + ssKey << make_pair(string("blockindex"), uint256(0)); + CDataStream ssValue(SER_DISK, CLIENT_VERSION); + int ret = ReadAtCursor(pcursor, ssKey, ssValue, fFlags); + fFlags = DB_NEXT; + if (ret == DB_NOTFOUND) + break; + else if (ret != 0) + return false; + + // Unserialize + + try { + string strType; + ssKey >> strType; + if (strType == "blockindex" && !fRequestShutdown) + { + CDiskBlockIndex diskindex; + ssValue >> diskindex; + + // Construct block index object + CBlockIndex* pindexNew = InsertBlockIndex(diskindex.GetBlockHash()); + pindexNew->pprev = InsertBlockIndex(diskindex.hashPrev); + pindexNew->pnext = InsertBlockIndex(diskindex.hashNext); + pindexNew->nFile = diskindex.nFile; + pindexNew->nBlockPos = diskindex.nBlockPos; + pindexNew->nHeight = diskindex.nHeight; + pindexNew->nMint = diskindex.nMint; + pindexNew->nMoneySupply = diskindex.nMoneySupply; + pindexNew->nFlags = diskindex.nFlags; + pindexNew->nStakeModifier = diskindex.nStakeModifier; + pindexNew->prevoutStake = diskindex.prevoutStake; + pindexNew->nStakeTime = diskindex.nStakeTime; + pindexNew->hashProofOfStake = diskindex.hashProofOfStake; + pindexNew->nVersion = diskindex.nVersion; + pindexNew->hashMerkleRoot = diskindex.hashMerkleRoot; + pindexNew->nTime = diskindex.nTime; + pindexNew->nBits = diskindex.nBits; + pindexNew->nNonce = diskindex.nNonce; + + // Watch for genesis block + if (pindexGenesisBlock == NULL && diskindex.GetBlockHash() == (!fTestNet ? hashGenesisBlock : hashGenesisBlockTestNet)) + pindexGenesisBlock = pindexNew; + + if (!pindexNew->CheckIndex()) + return error("LoadBlockIndex() : CheckIndex failed at %d", pindexNew->nHeight); + + // triangles: build setStakeSeen + if (pindexNew->IsProofOfStake()) + setStakeSeen.insert(make_pair(pindexNew->prevoutStake, pindexNew->nStakeTime)); + } + else + { + break; // if shutdown requested or finished loading block index + } + } // try + catch (std::exception &e) { + return error("%s() : deserialize error", __PRETTY_FUNCTION__); + } + } + pcursor->close(); + + return true; +} + + + + + +// +// CAddrDB +// + + +CAddrDB::CAddrDB() +{ + pathAddr = GetDataDir() / "peers.dat"; +} + +bool CAddrDB::Write(const CAddrMan& addr) +{ + // Generate random temporary filename + unsigned short randv = 0; + RAND_bytes((unsigned char *)&randv, sizeof(randv)); + std::string tmpfn = strprintf("peers.dat.%04x", randv); + + // serialize addresses, checksum data up to that point, then append csum + CDataStream ssPeers(SER_DISK, CLIENT_VERSION); + ssPeers << FLATDATA(pchMessageStart); + ssPeers << addr; + uint256 hash = Hash(ssPeers.begin(), ssPeers.end()); + ssPeers << hash; + + // open temp output file, and associate with CAutoFile + boost::filesystem::path pathTmp = GetDataDir() / tmpfn; + FILE *file = fopen(pathTmp.string().c_str(), "wb"); + CAutoFile fileout = CAutoFile(file, SER_DISK, CLIENT_VERSION); + if (!fileout) + return error("CAddrman::Write() : open failed"); + + // Write and commit header, data + try { + fileout << ssPeers; + } + catch (std::exception &e) { + return error("CAddrman::Write() : I/O error"); + } + FileCommit(fileout); + fileout.fclose(); + + // replace existing peers.dat, if any, with new peers.dat.XXXX + if (!RenameOver(pathTmp, pathAddr)) + return error("CAddrman::Write() : Rename-into-place failed"); + + return true; +} + +bool CAddrDB::Read(CAddrMan& addr) +{ + // open input file, and associate with CAutoFile + FILE *file = fopen(pathAddr.string().c_str(), "rb"); + CAutoFile filein = CAutoFile(file, SER_DISK, CLIENT_VERSION); + if (!filein) + return error("CAddrman::Read() : open failed"); + + // use file size to size memory buffer + int fileSize = GetFilesize(filein); + int dataSize = fileSize - sizeof(uint256); + vector vchData; + vchData.resize(dataSize); + uint256 hashIn; + + // read data and checksum from file + try { + filein.read((char *)&vchData[0], dataSize); + filein >> hashIn; + } + catch (std::exception &e) { + return error("CAddrman::Read() 2 : I/O error or stream data corrupted"); + } + filein.fclose(); + + CDataStream ssPeers(vchData, SER_DISK, CLIENT_VERSION); + + // verify stored checksum matches input data + uint256 hashTmp = Hash(ssPeers.begin(), ssPeers.end()); + if (hashIn != hashTmp) + return error("CAddrman::Read() : checksum mismatch; data corrupted"); + + unsigned char pchMsgTmp[4]; + try { + // de-serialize file header (pchMessageStart magic number) and + ssPeers >> FLATDATA(pchMsgTmp); + + // verify the network matches ours + if (memcmp(pchMsgTmp, pchMessageStart, sizeof(pchMsgTmp))) + return error("CAddrman::Read() : invalid network magic number"); + + // de-serialize address data into one CAddrMan object + ssPeers >> addr; + } + catch (std::exception &e) { + return error("CAddrman::Read() : I/O error or stream data corrupted"); + } + + return true; +} + diff --git a/src/db.h b/src/db.h new file mode 100644 index 0000000..eeb3a0b --- /dev/null +++ b/src/db.h @@ -0,0 +1,366 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2012 The Bitcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. +#ifndef BITCOIN_DB_H +#define BITCOIN_DB_H + +#include "main.h" + +#include +#include +#include + +#include + +class CAddress; +class CAddrMan; +class CBlockLocator; +class CDiskBlockIndex; +class CDiskTxPos; +class CMasterKey; +class COutPoint; +class CTxIndex; +class CWallet; +class CWalletTx; + +extern unsigned int nWalletDBUpdated; + +void ThreadFlushWalletDB(void* parg); +bool BackupWallet(const CWallet& wallet, const std::string& strDest); + + +class CDBEnv +{ +private: + bool fDetachDB; + bool fDbEnvInit; + bool fMockDb; + boost::filesystem::path pathEnv; + std::string strPath; + + void EnvShutdown(); + +public: + mutable CCriticalSection cs_db; + DbEnv dbenv; + std::map mapFileUseCount; + std::map mapDb; + + CDBEnv(); + ~CDBEnv(); + void MakeMock(); + bool IsMock() { return fMockDb; }; + + /* + * Verify that database file strFile is OK. If it is not, + * call the callback to try to recover. + * This must be called BEFORE strFile is opened. + * Returns true if strFile is OK. + */ + enum VerifyResult { VERIFY_OK, RECOVER_OK, RECOVER_FAIL }; + VerifyResult Verify(std::string strFile, bool (*recoverFunc)(CDBEnv& dbenv, std::string strFile)); + /* + * Salvage data from a file that Verify says is bad. + * fAggressive sets the DB_AGGRESSIVE flag (see berkeley DB->verify() method documentation). + * Appends binary key/value pairs to vResult, returns true if successful. + * NOTE: reads the entire database into memory, so cannot be used + * for huge databases. + */ + typedef std::pair, std::vector > KeyValPair; + bool Salvage(std::string strFile, bool fAggressive, std::vector& vResult); + + bool Open(boost::filesystem::path pathEnv_); + void Close(); + void Flush(bool fShutdown); + void CheckpointLSN(std::string strFile); + void SetDetach(bool fDetachDB_) { fDetachDB = fDetachDB_; } + bool GetDetach() { return fDetachDB; } + + void CloseDb(const std::string& strFile); + bool RemoveDb(const std::string& strFile); + + DbTxn *TxnBegin(int flags=DB_TXN_WRITE_NOSYNC) + { + DbTxn* ptxn = NULL; + int ret = dbenv.txn_begin(NULL, &ptxn, flags); + if (!ptxn || ret != 0) + return NULL; + return ptxn; + } +}; + +extern CDBEnv bitdb; + + +/** RAII class that provides access to a Berkeley database */ +class CDB +{ +protected: + Db* pdb; + std::string strFile; + DbTxn *activeTxn; + bool fReadOnly; + + explicit CDB(const char* pszFile, const char* pszMode="r+"); + ~CDB() { Close(); } +public: + void Close(); +private: + CDB(const CDB&); + void operator=(const CDB&); + +protected: + template + bool Read(const K& key, T& value) + { + if (!pdb) + return false; + + // Key + CDataStream ssKey(SER_DISK, CLIENT_VERSION); + ssKey.reserve(1000); + ssKey << key; + Dbt datKey(&ssKey[0], ssKey.size()); + + // Read + Dbt datValue; + datValue.set_flags(DB_DBT_MALLOC); + int ret = pdb->get(activeTxn, &datKey, &datValue, 0); + memset(datKey.get_data(), 0, datKey.get_size()); + if (datValue.get_data() == NULL) + return false; + + // Unserialize value + try { + CDataStream ssValue((char*)datValue.get_data(), (char*)datValue.get_data() + datValue.get_size(), SER_DISK, CLIENT_VERSION); + ssValue >> value; + } + catch (std::exception &e) { + return false; + } + + // Clear and free memory + memset(datValue.get_data(), 0, datValue.get_size()); + free(datValue.get_data()); + return (ret == 0); + } + + template + bool Write(const K& key, const T& value, bool fOverwrite=true) + { + if (!pdb) + return false; + if (fReadOnly) + assert(!"Write called on database in read-only mode"); + + // Key + CDataStream ssKey(SER_DISK, CLIENT_VERSION); + ssKey.reserve(1000); + ssKey << key; + Dbt datKey(&ssKey[0], ssKey.size()); + + // Value + CDataStream ssValue(SER_DISK, CLIENT_VERSION); + ssValue.reserve(10000); + ssValue << value; + Dbt datValue(&ssValue[0], ssValue.size()); + + // Write + int ret = pdb->put(activeTxn, &datKey, &datValue, (fOverwrite ? 0 : DB_NOOVERWRITE)); + + // Clear memory in case it was a private key + memset(datKey.get_data(), 0, datKey.get_size()); + memset(datValue.get_data(), 0, datValue.get_size()); + return (ret == 0); + } + + template + bool Erase(const K& key) + { + if (!pdb) + return false; + if (fReadOnly) + assert(!"Erase called on database in read-only mode"); + + // Key + CDataStream ssKey(SER_DISK, CLIENT_VERSION); + ssKey.reserve(1000); + ssKey << key; + Dbt datKey(&ssKey[0], ssKey.size()); + + // Erase + int ret = pdb->del(activeTxn, &datKey, 0); + + // Clear memory + memset(datKey.get_data(), 0, datKey.get_size()); + return (ret == 0 || ret == DB_NOTFOUND); + } + + template + bool Exists(const K& key) + { + if (!pdb) + return false; + + // Key + CDataStream ssKey(SER_DISK, CLIENT_VERSION); + ssKey.reserve(1000); + ssKey << key; + Dbt datKey(&ssKey[0], ssKey.size()); + + // Exists + int ret = pdb->exists(activeTxn, &datKey, 0); + + // Clear memory + memset(datKey.get_data(), 0, datKey.get_size()); + return (ret == 0); + } + + Dbc* GetCursor() + { + if (!pdb) + return NULL; + Dbc* pcursor = NULL; + int ret = pdb->cursor(NULL, &pcursor, 0); + if (ret != 0) + return NULL; + return pcursor; + } + + int ReadAtCursor(Dbc* pcursor, CDataStream& ssKey, CDataStream& ssValue, unsigned int fFlags=DB_NEXT) + { + // Read at cursor + Dbt datKey; + if (fFlags == DB_SET || fFlags == DB_SET_RANGE || fFlags == DB_GET_BOTH || fFlags == DB_GET_BOTH_RANGE) + { + datKey.set_data(&ssKey[0]); + datKey.set_size(ssKey.size()); + } + Dbt datValue; + if (fFlags == DB_GET_BOTH || fFlags == DB_GET_BOTH_RANGE) + { + datValue.set_data(&ssValue[0]); + datValue.set_size(ssValue.size()); + } + datKey.set_flags(DB_DBT_MALLOC); + datValue.set_flags(DB_DBT_MALLOC); + int ret = pcursor->get(&datKey, &datValue, fFlags); + if (ret != 0) + return ret; + else if (datKey.get_data() == NULL || datValue.get_data() == NULL) + return 99999; + + // Convert to streams + ssKey.SetType(SER_DISK); + ssKey.clear(); + ssKey.write((char*)datKey.get_data(), datKey.get_size()); + ssValue.SetType(SER_DISK); + ssValue.clear(); + ssValue.write((char*)datValue.get_data(), datValue.get_size()); + + // Clear and free memory + memset(datKey.get_data(), 0, datKey.get_size()); + memset(datValue.get_data(), 0, datValue.get_size()); + free(datKey.get_data()); + free(datValue.get_data()); + return 0; + } + +public: + bool TxnBegin() + { + if (!pdb || activeTxn) + return false; + DbTxn* ptxn = bitdb.TxnBegin(); + if (!ptxn) + return false; + activeTxn = ptxn; + return true; + } + + bool TxnCommit() + { + if (!pdb || !activeTxn) + return false; + int ret = activeTxn->commit(0); + activeTxn = NULL; + return (ret == 0); + } + + bool TxnAbort() + { + if (!pdb || !activeTxn) + return false; + int ret = activeTxn->abort(); + activeTxn = NULL; + return (ret == 0); + } + + bool ReadVersion(int& nVersion) + { + nVersion = 0; + return Read(std::string("version"), nVersion); + } + + bool WriteVersion(int nVersion) + { + return Write(std::string("version"), nVersion); + } + + bool static Rewrite(const std::string& strFile, const char* pszSkip = NULL); +}; + + + + + + + +/** Access to the transaction database (blkindex.dat) */ +class CTxDB : public CDB +{ +public: + CTxDB(const char* pszMode="r+") : CDB("blkindex.dat", pszMode) { } +private: + CTxDB(const CTxDB&); + void operator=(const CTxDB&); +public: + bool ReadTxIndex(uint256 hash, CTxIndex& txindex); + bool UpdateTxIndex(uint256 hash, const CTxIndex& txindex); + bool AddTxIndex(const CTransaction& tx, const CDiskTxPos& pos, int nHeight); + bool EraseTxIndex(const CTransaction& tx); + bool ContainsTx(uint256 hash); + bool ReadDiskTx(uint256 hash, CTransaction& tx, CTxIndex& txindex); + bool ReadDiskTx(uint256 hash, CTransaction& tx); + bool ReadDiskTx(COutPoint outpoint, CTransaction& tx, CTxIndex& txindex); + bool ReadDiskTx(COutPoint outpoint, CTransaction& tx); + bool WriteBlockIndex(const CDiskBlockIndex& blockindex); + bool ReadHashBestChain(uint256& hashBestChain); + bool WriteHashBestChain(uint256 hashBestChain); + bool ReadBestInvalidTrust(CBigNum& bnBestInvalidTrust); + bool WriteBestInvalidTrust(CBigNum bnBestInvalidTrust); + bool ReadSyncCheckpoint(uint256& hashCheckpoint); + bool WriteSyncCheckpoint(uint256 hashCheckpoint); + bool ReadCheckpointPubKey(std::string& strPubKey); + bool WriteCheckpointPubKey(const std::string& strPubKey); + bool LoadBlockIndex(); +private: + bool LoadBlockIndexGuts(); +}; + + + + +/** Access to the (IP) address database (peers.dat) */ +class CAddrDB +{ +private: + boost::filesystem::path pathAddr; +public: + CAddrDB(); + bool Write(const CAddrMan& addr); + bool Read(CAddrMan& addr); +}; + +#endif // BITCOIN_DB_H diff --git a/src/echo.c b/src/echo.c new file mode 100644 index 0000000..667e3f3 --- /dev/null +++ b/src/echo.c @@ -0,0 +1,1031 @@ +/* $Id: echo.c 227 2010-06-16 17:28:38Z tp $ */ +/* + * ECHO implementation. + * + * ==========================(LICENSE BEGIN)============================ + * + * Copyright (c) 2007-2010 Projet RNRT SAPHIR + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * ===========================(LICENSE END)============================= + * + * @author Thomas Pornin + */ + +#include +#include +#include + +#include "sph_echo.h" + +#ifdef __cplusplus +extern "C"{ +#endif + +#if SPH_SMALL_FOOTPRINT && !defined SPH_SMALL_FOOTPRINT_ECHO +#define SPH_SMALL_FOOTPRINT_ECHO 1 +#endif + +/* + * Some measures tend to show that the 64-bit implementation offers + * better performance only on a "64-bit architectures", those which have + * actual 64-bit registers. + */ +#if !defined SPH_ECHO_64 && SPH_64_TRUE +#define SPH_ECHO_64 1 +#endif + +/* + * We can use a 64-bit implementation only if a 64-bit type is available. + */ +#if !SPH_64 +#undef SPH_ECHO_64 +#endif + +#ifdef _MSC_VER +#pragma warning (disable: 4146) +#endif + +#define T32 SPH_T32 +#define C32 SPH_C32 +#if SPH_64 +#define C64 SPH_C64 +#endif + +#define AES_BIG_ENDIAN 0 +#include "aes_helper.c" + +#if SPH_ECHO_64 + +#define DECL_STATE_SMALL \ + sph_u64 W[16][2]; + +#define DECL_STATE_BIG \ + sph_u64 W[16][2]; + +#define INPUT_BLOCK_SMALL(sc) do { \ + unsigned u; \ + memcpy(W, sc->u.Vb, 8 * sizeof(sph_u64)); \ + for (u = 0; u < 12; u ++) { \ + W[u + 4][0] = sph_dec64le_aligned( \ + sc->buf + 16 * u); \ + W[u + 4][1] = sph_dec64le_aligned( \ + sc->buf + 16 * u + 8); \ + } \ + } while (0) + +#define INPUT_BLOCK_BIG(sc) do { \ + unsigned u; \ + memcpy(W, sc->u.Vb, 16 * sizeof(sph_u64)); \ + for (u = 0; u < 8; u ++) { \ + W[u + 8][0] = sph_dec64le_aligned( \ + sc->buf + 16 * u); \ + W[u + 8][1] = sph_dec64le_aligned( \ + sc->buf + 16 * u + 8); \ + } \ + } while (0) + +#if SPH_SMALL_FOOTPRINT_ECHO + +static void +aes_2rounds_all(sph_u64 W[16][2], + sph_u32 *pK0, sph_u32 *pK1, sph_u32 *pK2, sph_u32 *pK3) +{ + int n; + sph_u32 K0 = *pK0; + sph_u32 K1 = *pK1; + sph_u32 K2 = *pK2; + sph_u32 K3 = *pK3; + + for (n = 0; n < 16; n ++) { + sph_u64 Wl = W[n][0]; + sph_u64 Wh = W[n][1]; + sph_u32 X0 = (sph_u32)Wl; + sph_u32 X1 = (sph_u32)(Wl >> 32); + sph_u32 X2 = (sph_u32)Wh; + sph_u32 X3 = (sph_u32)(Wh >> 32); + sph_u32 Y0, Y1, Y2, Y3; \ + AES_ROUND_LE(X0, X1, X2, X3, K0, K1, K2, K3, Y0, Y1, Y2, Y3); + AES_ROUND_NOKEY_LE(Y0, Y1, Y2, Y3, X0, X1, X2, X3); + W[n][0] = (sph_u64)X0 | ((sph_u64)X1 << 32); + W[n][1] = (sph_u64)X2 | ((sph_u64)X3 << 32); + if ((K0 = T32(K0 + 1)) == 0) { + if ((K1 = T32(K1 + 1)) == 0) + if ((K2 = T32(K2 + 1)) == 0) + K3 = T32(K3 + 1); + } + } + *pK0 = K0; + *pK1 = K1; + *pK2 = K2; + *pK3 = K3; +} + +#define BIG_SUB_WORDS do { \ + aes_2rounds_all(W, &K0, &K1, &K2, &K3); \ + } while (0) + +#else + +#define AES_2ROUNDS(X) do { \ + sph_u32 X0 = (sph_u32)(X[0]); \ + sph_u32 X1 = (sph_u32)(X[0] >> 32); \ + sph_u32 X2 = (sph_u32)(X[1]); \ + sph_u32 X3 = (sph_u32)(X[1] >> 32); \ + sph_u32 Y0, Y1, Y2, Y3; \ + AES_ROUND_LE(X0, X1, X2, X3, K0, K1, K2, K3, Y0, Y1, Y2, Y3); \ + AES_ROUND_NOKEY_LE(Y0, Y1, Y2, Y3, X0, X1, X2, X3); \ + X[0] = (sph_u64)X0 | ((sph_u64)X1 << 32); \ + X[1] = (sph_u64)X2 | ((sph_u64)X3 << 32); \ + if ((K0 = T32(K0 + 1)) == 0) { \ + if ((K1 = T32(K1 + 1)) == 0) \ + if ((K2 = T32(K2 + 1)) == 0) \ + K3 = T32(K3 + 1); \ + } \ + } while (0) + +#define BIG_SUB_WORDS do { \ + AES_2ROUNDS(W[ 0]); \ + AES_2ROUNDS(W[ 1]); \ + AES_2ROUNDS(W[ 2]); \ + AES_2ROUNDS(W[ 3]); \ + AES_2ROUNDS(W[ 4]); \ + AES_2ROUNDS(W[ 5]); \ + AES_2ROUNDS(W[ 6]); \ + AES_2ROUNDS(W[ 7]); \ + AES_2ROUNDS(W[ 8]); \ + AES_2ROUNDS(W[ 9]); \ + AES_2ROUNDS(W[10]); \ + AES_2ROUNDS(W[11]); \ + AES_2ROUNDS(W[12]); \ + AES_2ROUNDS(W[13]); \ + AES_2ROUNDS(W[14]); \ + AES_2ROUNDS(W[15]); \ + } while (0) + +#endif + +#define SHIFT_ROW1(a, b, c, d) do { \ + sph_u64 tmp; \ + tmp = W[a][0]; \ + W[a][0] = W[b][0]; \ + W[b][0] = W[c][0]; \ + W[c][0] = W[d][0]; \ + W[d][0] = tmp; \ + tmp = W[a][1]; \ + W[a][1] = W[b][1]; \ + W[b][1] = W[c][1]; \ + W[c][1] = W[d][1]; \ + W[d][1] = tmp; \ + } while (0) + +#define SHIFT_ROW2(a, b, c, d) do { \ + sph_u64 tmp; \ + tmp = W[a][0]; \ + W[a][0] = W[c][0]; \ + W[c][0] = tmp; \ + tmp = W[b][0]; \ + W[b][0] = W[d][0]; \ + W[d][0] = tmp; \ + tmp = W[a][1]; \ + W[a][1] = W[c][1]; \ + W[c][1] = tmp; \ + tmp = W[b][1]; \ + W[b][1] = W[d][1]; \ + W[d][1] = tmp; \ + } while (0) + +#define SHIFT_ROW3(a, b, c, d) SHIFT_ROW1(d, c, b, a) + +#define BIG_SHIFT_ROWS do { \ + SHIFT_ROW1(1, 5, 9, 13); \ + SHIFT_ROW2(2, 6, 10, 14); \ + SHIFT_ROW3(3, 7, 11, 15); \ + } while (0) + +#if SPH_SMALL_FOOTPRINT_ECHO + +static void +mix_column(sph_u64 W[16][2], int ia, int ib, int ic, int id) +{ + int n; + + for (n = 0; n < 2; n ++) { + sph_u64 a = W[ia][n]; + sph_u64 b = W[ib][n]; + sph_u64 c = W[ic][n]; + sph_u64 d = W[id][n]; + sph_u64 ab = a ^ b; + sph_u64 bc = b ^ c; + sph_u64 cd = c ^ d; + sph_u64 abx = ((ab & C64(0x8080808080808080)) >> 7) * 27U + ^ ((ab & C64(0x7F7F7F7F7F7F7F7F)) << 1); + sph_u64 bcx = ((bc & C64(0x8080808080808080)) >> 7) * 27U + ^ ((bc & C64(0x7F7F7F7F7F7F7F7F)) << 1); + sph_u64 cdx = ((cd & C64(0x8080808080808080)) >> 7) * 27U + ^ ((cd & C64(0x7F7F7F7F7F7F7F7F)) << 1); + W[ia][n] = abx ^ bc ^ d; + W[ib][n] = bcx ^ a ^ cd; + W[ic][n] = cdx ^ ab ^ d; + W[id][n] = abx ^ bcx ^ cdx ^ ab ^ c; + } +} + +#define MIX_COLUMN(a, b, c, d) mix_column(W, a, b, c, d) + +#else + +#define MIX_COLUMN1(ia, ib, ic, id, n) do { \ + sph_u64 a = W[ia][n]; \ + sph_u64 b = W[ib][n]; \ + sph_u64 c = W[ic][n]; \ + sph_u64 d = W[id][n]; \ + sph_u64 ab = a ^ b; \ + sph_u64 bc = b ^ c; \ + sph_u64 cd = c ^ d; \ + sph_u64 abx = ((ab & C64(0x8080808080808080)) >> 7) * 27U \ + ^ ((ab & C64(0x7F7F7F7F7F7F7F7F)) << 1); \ + sph_u64 bcx = ((bc & C64(0x8080808080808080)) >> 7) * 27U \ + ^ ((bc & C64(0x7F7F7F7F7F7F7F7F)) << 1); \ + sph_u64 cdx = ((cd & C64(0x8080808080808080)) >> 7) * 27U \ + ^ ((cd & C64(0x7F7F7F7F7F7F7F7F)) << 1); \ + W[ia][n] = abx ^ bc ^ d; \ + W[ib][n] = bcx ^ a ^ cd; \ + W[ic][n] = cdx ^ ab ^ d; \ + W[id][n] = abx ^ bcx ^ cdx ^ ab ^ c; \ + } while (0) + +#define MIX_COLUMN(a, b, c, d) do { \ + MIX_COLUMN1(a, b, c, d, 0); \ + MIX_COLUMN1(a, b, c, d, 1); \ + } while (0) + +#endif + +#define BIG_MIX_COLUMNS do { \ + MIX_COLUMN(0, 1, 2, 3); \ + MIX_COLUMN(4, 5, 6, 7); \ + MIX_COLUMN(8, 9, 10, 11); \ + MIX_COLUMN(12, 13, 14, 15); \ + } while (0) + +#define BIG_ROUND do { \ + BIG_SUB_WORDS; \ + BIG_SHIFT_ROWS; \ + BIG_MIX_COLUMNS; \ + } while (0) + +#define FINAL_SMALL do { \ + unsigned u; \ + sph_u64 *VV = &sc->u.Vb[0][0]; \ + sph_u64 *WW = &W[0][0]; \ + for (u = 0; u < 8; u ++) { \ + VV[u] ^= sph_dec64le_aligned(sc->buf + (u * 8)) \ + ^ sph_dec64le_aligned(sc->buf + (u * 8) + 64) \ + ^ sph_dec64le_aligned(sc->buf + (u * 8) + 128) \ + ^ WW[u] ^ WW[u + 8] \ + ^ WW[u + 16] ^ WW[u + 24]; \ + } \ + } while (0) + +#define FINAL_BIG do { \ + unsigned u; \ + sph_u64 *VV = &sc->u.Vb[0][0]; \ + sph_u64 *WW = &W[0][0]; \ + for (u = 0; u < 16; u ++) { \ + VV[u] ^= sph_dec64le_aligned(sc->buf + (u * 8)) \ + ^ WW[u] ^ WW[u + 16]; \ + } \ + } while (0) + +#define COMPRESS_SMALL(sc) do { \ + sph_u32 K0 = sc->C0; \ + sph_u32 K1 = sc->C1; \ + sph_u32 K2 = sc->C2; \ + sph_u32 K3 = sc->C3; \ + unsigned u; \ + INPUT_BLOCK_SMALL(sc); \ + for (u = 0; u < 8; u ++) { \ + BIG_ROUND; \ + } \ + FINAL_SMALL; \ + } while (0) + +#define COMPRESS_BIG(sc) do { \ + sph_u32 K0 = sc->C0; \ + sph_u32 K1 = sc->C1; \ + sph_u32 K2 = sc->C2; \ + sph_u32 K3 = sc->C3; \ + unsigned u; \ + INPUT_BLOCK_BIG(sc); \ + for (u = 0; u < 10; u ++) { \ + BIG_ROUND; \ + } \ + FINAL_BIG; \ + } while (0) + +#else + +#define DECL_STATE_SMALL \ + sph_u32 W[16][4]; + +#define DECL_STATE_BIG \ + sph_u32 W[16][4]; + +#define INPUT_BLOCK_SMALL(sc) do { \ + unsigned u; \ + memcpy(W, sc->u.Vs, 16 * sizeof(sph_u32)); \ + for (u = 0; u < 12; u ++) { \ + W[u + 4][0] = sph_dec32le_aligned( \ + sc->buf + 16 * u); \ + W[u + 4][1] = sph_dec32le_aligned( \ + sc->buf + 16 * u + 4); \ + W[u + 4][2] = sph_dec32le_aligned( \ + sc->buf + 16 * u + 8); \ + W[u + 4][3] = sph_dec32le_aligned( \ + sc->buf + 16 * u + 12); \ + } \ + } while (0) + +#define INPUT_BLOCK_BIG(sc) do { \ + unsigned u; \ + memcpy(W, sc->u.Vs, 32 * sizeof(sph_u32)); \ + for (u = 0; u < 8; u ++) { \ + W[u + 8][0] = sph_dec32le_aligned( \ + sc->buf + 16 * u); \ + W[u + 8][1] = sph_dec32le_aligned( \ + sc->buf + 16 * u + 4); \ + W[u + 8][2] = sph_dec32le_aligned( \ + sc->buf + 16 * u + 8); \ + W[u + 8][3] = sph_dec32le_aligned( \ + sc->buf + 16 * u + 12); \ + } \ + } while (0) + +#if SPH_SMALL_FOOTPRINT_ECHO + +static void +aes_2rounds_all(sph_u32 W[16][4], + sph_u32 *pK0, sph_u32 *pK1, sph_u32 *pK2, sph_u32 *pK3) +{ + int n; + sph_u32 K0 = *pK0; + sph_u32 K1 = *pK1; + sph_u32 K2 = *pK2; + sph_u32 K3 = *pK3; + + for (n = 0; n < 16; n ++) { + sph_u32 *X = W[n]; + sph_u32 Y0, Y1, Y2, Y3; + AES_ROUND_LE(X[0], X[1], X[2], X[3], + K0, K1, K2, K3, Y0, Y1, Y2, Y3); + AES_ROUND_NOKEY_LE(Y0, Y1, Y2, Y3, X[0], X[1], X[2], X[3]); + if ((K0 = T32(K0 + 1)) == 0) { + if ((K1 = T32(K1 + 1)) == 0) + if ((K2 = T32(K2 + 1)) == 0) + K3 = T32(K3 + 1); + } + } + *pK0 = K0; + *pK1 = K1; + *pK2 = K2; + *pK3 = K3; +} + +#define BIG_SUB_WORDS do { \ + aes_2rounds_all(W, &K0, &K1, &K2, &K3); \ + } while (0) + +#else + +#define AES_2ROUNDS(X) do { \ + sph_u32 Y0, Y1, Y2, Y3; \ + AES_ROUND_LE(X[0], X[1], X[2], X[3], \ + K0, K1, K2, K3, Y0, Y1, Y2, Y3); \ + AES_ROUND_NOKEY_LE(Y0, Y1, Y2, Y3, X[0], X[1], X[2], X[3]); \ + if ((K0 = T32(K0 + 1)) == 0) { \ + if ((K1 = T32(K1 + 1)) == 0) \ + if ((K2 = T32(K2 + 1)) == 0) \ + K3 = T32(K3 + 1); \ + } \ + } while (0) + +#define BIG_SUB_WORDS do { \ + AES_2ROUNDS(W[ 0]); \ + AES_2ROUNDS(W[ 1]); \ + AES_2ROUNDS(W[ 2]); \ + AES_2ROUNDS(W[ 3]); \ + AES_2ROUNDS(W[ 4]); \ + AES_2ROUNDS(W[ 5]); \ + AES_2ROUNDS(W[ 6]); \ + AES_2ROUNDS(W[ 7]); \ + AES_2ROUNDS(W[ 8]); \ + AES_2ROUNDS(W[ 9]); \ + AES_2ROUNDS(W[10]); \ + AES_2ROUNDS(W[11]); \ + AES_2ROUNDS(W[12]); \ + AES_2ROUNDS(W[13]); \ + AES_2ROUNDS(W[14]); \ + AES_2ROUNDS(W[15]); \ + } while (0) + +#endif + +#define SHIFT_ROW1(a, b, c, d) do { \ + sph_u32 tmp; \ + tmp = W[a][0]; \ + W[a][0] = W[b][0]; \ + W[b][0] = W[c][0]; \ + W[c][0] = W[d][0]; \ + W[d][0] = tmp; \ + tmp = W[a][1]; \ + W[a][1] = W[b][1]; \ + W[b][1] = W[c][1]; \ + W[c][1] = W[d][1]; \ + W[d][1] = tmp; \ + tmp = W[a][2]; \ + W[a][2] = W[b][2]; \ + W[b][2] = W[c][2]; \ + W[c][2] = W[d][2]; \ + W[d][2] = tmp; \ + tmp = W[a][3]; \ + W[a][3] = W[b][3]; \ + W[b][3] = W[c][3]; \ + W[c][3] = W[d][3]; \ + W[d][3] = tmp; \ + } while (0) + +#define SHIFT_ROW2(a, b, c, d) do { \ + sph_u32 tmp; \ + tmp = W[a][0]; \ + W[a][0] = W[c][0]; \ + W[c][0] = tmp; \ + tmp = W[b][0]; \ + W[b][0] = W[d][0]; \ + W[d][0] = tmp; \ + tmp = W[a][1]; \ + W[a][1] = W[c][1]; \ + W[c][1] = tmp; \ + tmp = W[b][1]; \ + W[b][1] = W[d][1]; \ + W[d][1] = tmp; \ + tmp = W[a][2]; \ + W[a][2] = W[c][2]; \ + W[c][2] = tmp; \ + tmp = W[b][2]; \ + W[b][2] = W[d][2]; \ + W[d][2] = tmp; \ + tmp = W[a][3]; \ + W[a][3] = W[c][3]; \ + W[c][3] = tmp; \ + tmp = W[b][3]; \ + W[b][3] = W[d][3]; \ + W[d][3] = tmp; \ + } while (0) + +#define SHIFT_ROW3(a, b, c, d) SHIFT_ROW1(d, c, b, a) + +#define BIG_SHIFT_ROWS do { \ + SHIFT_ROW1(1, 5, 9, 13); \ + SHIFT_ROW2(2, 6, 10, 14); \ + SHIFT_ROW3(3, 7, 11, 15); \ + } while (0) + +#if SPH_SMALL_FOOTPRINT_ECHO + +static void +mix_column(sph_u32 W[16][4], int ia, int ib, int ic, int id) +{ + int n; + + for (n = 0; n < 4; n ++) { + sph_u32 a = W[ia][n]; + sph_u32 b = W[ib][n]; + sph_u32 c = W[ic][n]; + sph_u32 d = W[id][n]; + sph_u32 ab = a ^ b; + sph_u32 bc = b ^ c; + sph_u32 cd = c ^ d; + sph_u32 abx = ((ab & C32(0x80808080)) >> 7) * 27U + ^ ((ab & C32(0x7F7F7F7F)) << 1); + sph_u32 bcx = ((bc & C32(0x80808080)) >> 7) * 27U + ^ ((bc & C32(0x7F7F7F7F)) << 1); + sph_u32 cdx = ((cd & C32(0x80808080)) >> 7) * 27U + ^ ((cd & C32(0x7F7F7F7F)) << 1); + W[ia][n] = abx ^ bc ^ d; + W[ib][n] = bcx ^ a ^ cd; + W[ic][n] = cdx ^ ab ^ d; + W[id][n] = abx ^ bcx ^ cdx ^ ab ^ c; + } +} + +#define MIX_COLUMN(a, b, c, d) mix_column(W, a, b, c, d) + +#else + +#define MIX_COLUMN1(ia, ib, ic, id, n) do { \ + sph_u32 a = W[ia][n]; \ + sph_u32 b = W[ib][n]; \ + sph_u32 c = W[ic][n]; \ + sph_u32 d = W[id][n]; \ + sph_u32 ab = a ^ b; \ + sph_u32 bc = b ^ c; \ + sph_u32 cd = c ^ d; \ + sph_u32 abx = ((ab & C32(0x80808080)) >> 7) * 27U \ + ^ ((ab & C32(0x7F7F7F7F)) << 1); \ + sph_u32 bcx = ((bc & C32(0x80808080)) >> 7) * 27U \ + ^ ((bc & C32(0x7F7F7F7F)) << 1); \ + sph_u32 cdx = ((cd & C32(0x80808080)) >> 7) * 27U \ + ^ ((cd & C32(0x7F7F7F7F)) << 1); \ + W[ia][n] = abx ^ bc ^ d; \ + W[ib][n] = bcx ^ a ^ cd; \ + W[ic][n] = cdx ^ ab ^ d; \ + W[id][n] = abx ^ bcx ^ cdx ^ ab ^ c; \ + } while (0) + +#define MIX_COLUMN(a, b, c, d) do { \ + MIX_COLUMN1(a, b, c, d, 0); \ + MIX_COLUMN1(a, b, c, d, 1); \ + MIX_COLUMN1(a, b, c, d, 2); \ + MIX_COLUMN1(a, b, c, d, 3); \ + } while (0) + +#endif + +#define BIG_MIX_COLUMNS do { \ + MIX_COLUMN(0, 1, 2, 3); \ + MIX_COLUMN(4, 5, 6, 7); \ + MIX_COLUMN(8, 9, 10, 11); \ + MIX_COLUMN(12, 13, 14, 15); \ + } while (0) + +#define BIG_ROUND do { \ + BIG_SUB_WORDS; \ + BIG_SHIFT_ROWS; \ + BIG_MIX_COLUMNS; \ + } while (0) + +#define FINAL_SMALL do { \ + unsigned u; \ + sph_u32 *VV = &sc->u.Vs[0][0]; \ + sph_u32 *WW = &W[0][0]; \ + for (u = 0; u < 16; u ++) { \ + VV[u] ^= sph_dec32le_aligned(sc->buf + (u * 4)) \ + ^ sph_dec32le_aligned(sc->buf + (u * 4) + 64) \ + ^ sph_dec32le_aligned(sc->buf + (u * 4) + 128) \ + ^ WW[u] ^ WW[u + 16] \ + ^ WW[u + 32] ^ WW[u + 48]; \ + } \ + } while (0) + +#define FINAL_BIG do { \ + unsigned u; \ + sph_u32 *VV = &sc->u.Vs[0][0]; \ + sph_u32 *WW = &W[0][0]; \ + for (u = 0; u < 32; u ++) { \ + VV[u] ^= sph_dec32le_aligned(sc->buf + (u * 4)) \ + ^ WW[u] ^ WW[u + 32]; \ + } \ + } while (0) + +#define COMPRESS_SMALL(sc) do { \ + sph_u32 K0 = sc->C0; \ + sph_u32 K1 = sc->C1; \ + sph_u32 K2 = sc->C2; \ + sph_u32 K3 = sc->C3; \ + unsigned u; \ + INPUT_BLOCK_SMALL(sc); \ + for (u = 0; u < 8; u ++) { \ + BIG_ROUND; \ + } \ + FINAL_SMALL; \ + } while (0) + +#define COMPRESS_BIG(sc) do { \ + sph_u32 K0 = sc->C0; \ + sph_u32 K1 = sc->C1; \ + sph_u32 K2 = sc->C2; \ + sph_u32 K3 = sc->C3; \ + unsigned u; \ + INPUT_BLOCK_BIG(sc); \ + for (u = 0; u < 10; u ++) { \ + BIG_ROUND; \ + } \ + FINAL_BIG; \ + } while (0) + +#endif + +#define INCR_COUNTER(sc, val) do { \ + sc->C0 = T32(sc->C0 + (sph_u32)(val)); \ + if (sc->C0 < (sph_u32)(val)) { \ + if ((sc->C1 = T32(sc->C1 + 1)) == 0) \ + if ((sc->C2 = T32(sc->C2 + 1)) == 0) \ + sc->C3 = T32(sc->C3 + 1); \ + } \ + } while (0) + +static void +echo_small_init(sph_echo_small_context *sc, unsigned out_len) +{ +#if SPH_ECHO_64 + sc->u.Vb[0][0] = (sph_u64)out_len; + sc->u.Vb[0][1] = 0; + sc->u.Vb[1][0] = (sph_u64)out_len; + sc->u.Vb[1][1] = 0; + sc->u.Vb[2][0] = (sph_u64)out_len; + sc->u.Vb[2][1] = 0; + sc->u.Vb[3][0] = (sph_u64)out_len; + sc->u.Vb[3][1] = 0; +#else + sc->u.Vs[0][0] = (sph_u32)out_len; + sc->u.Vs[0][1] = sc->u.Vs[0][2] = sc->u.Vs[0][3] = 0; + sc->u.Vs[1][0] = (sph_u32)out_len; + sc->u.Vs[1][1] = sc->u.Vs[1][2] = sc->u.Vs[1][3] = 0; + sc->u.Vs[2][0] = (sph_u32)out_len; + sc->u.Vs[2][1] = sc->u.Vs[2][2] = sc->u.Vs[2][3] = 0; + sc->u.Vs[3][0] = (sph_u32)out_len; + sc->u.Vs[3][1] = sc->u.Vs[3][2] = sc->u.Vs[3][3] = 0; +#endif + sc->ptr = 0; + sc->C0 = sc->C1 = sc->C2 = sc->C3 = 0; +} + +static void +echo_big_init(sph_echo_big_context *sc, unsigned out_len) +{ +#if SPH_ECHO_64 + sc->u.Vb[0][0] = (sph_u64)out_len; + sc->u.Vb[0][1] = 0; + sc->u.Vb[1][0] = (sph_u64)out_len; + sc->u.Vb[1][1] = 0; + sc->u.Vb[2][0] = (sph_u64)out_len; + sc->u.Vb[2][1] = 0; + sc->u.Vb[3][0] = (sph_u64)out_len; + sc->u.Vb[3][1] = 0; + sc->u.Vb[4][0] = (sph_u64)out_len; + sc->u.Vb[4][1] = 0; + sc->u.Vb[5][0] = (sph_u64)out_len; + sc->u.Vb[5][1] = 0; + sc->u.Vb[6][0] = (sph_u64)out_len; + sc->u.Vb[6][1] = 0; + sc->u.Vb[7][0] = (sph_u64)out_len; + sc->u.Vb[7][1] = 0; +#else + sc->u.Vs[0][0] = (sph_u32)out_len; + sc->u.Vs[0][1] = sc->u.Vs[0][2] = sc->u.Vs[0][3] = 0; + sc->u.Vs[1][0] = (sph_u32)out_len; + sc->u.Vs[1][1] = sc->u.Vs[1][2] = sc->u.Vs[1][3] = 0; + sc->u.Vs[2][0] = (sph_u32)out_len; + sc->u.Vs[2][1] = sc->u.Vs[2][2] = sc->u.Vs[2][3] = 0; + sc->u.Vs[3][0] = (sph_u32)out_len; + sc->u.Vs[3][1] = sc->u.Vs[3][2] = sc->u.Vs[3][3] = 0; + sc->u.Vs[4][0] = (sph_u32)out_len; + sc->u.Vs[4][1] = sc->u.Vs[4][2] = sc->u.Vs[4][3] = 0; + sc->u.Vs[5][0] = (sph_u32)out_len; + sc->u.Vs[5][1] = sc->u.Vs[5][2] = sc->u.Vs[5][3] = 0; + sc->u.Vs[6][0] = (sph_u32)out_len; + sc->u.Vs[6][1] = sc->u.Vs[6][2] = sc->u.Vs[6][3] = 0; + sc->u.Vs[7][0] = (sph_u32)out_len; + sc->u.Vs[7][1] = sc->u.Vs[7][2] = sc->u.Vs[7][3] = 0; +#endif + sc->ptr = 0; + sc->C0 = sc->C1 = sc->C2 = sc->C3 = 0; +} + +static void +echo_small_compress(sph_echo_small_context *sc) +{ + DECL_STATE_SMALL + + COMPRESS_SMALL(sc); +} + +static void +echo_big_compress(sph_echo_big_context *sc) +{ + DECL_STATE_BIG + + COMPRESS_BIG(sc); +} + +static void +echo_small_core(sph_echo_small_context *sc, + const unsigned char *data, size_t len) +{ + unsigned char *buf; + size_t ptr; + + buf = sc->buf; + ptr = sc->ptr; + if (len < (sizeof sc->buf) - ptr) { + memcpy(buf + ptr, data, len); + ptr += len; + sc->ptr = ptr; + return; + } + + while (len > 0) { + size_t clen; + + clen = (sizeof sc->buf) - ptr; + if (clen > len) + clen = len; + memcpy(buf + ptr, data, clen); + ptr += clen; + data += clen; + len -= clen; + if (ptr == sizeof sc->buf) { + INCR_COUNTER(sc, 1536); + echo_small_compress(sc); + ptr = 0; + } + } + sc->ptr = ptr; +} + +static void +echo_big_core(sph_echo_big_context *sc, + const unsigned char *data, size_t len) +{ + unsigned char *buf; + size_t ptr; + + buf = sc->buf; + ptr = sc->ptr; + if (len < (sizeof sc->buf) - ptr) { + memcpy(buf + ptr, data, len); + ptr += len; + sc->ptr = ptr; + return; + } + + while (len > 0) { + size_t clen; + + clen = (sizeof sc->buf) - ptr; + if (clen > len) + clen = len; + memcpy(buf + ptr, data, clen); + ptr += clen; + data += clen; + len -= clen; + if (ptr == sizeof sc->buf) { + INCR_COUNTER(sc, 1024); + echo_big_compress(sc); + ptr = 0; + } + } + sc->ptr = ptr; +} + +static void +echo_small_close(sph_echo_small_context *sc, unsigned ub, unsigned n, + void *dst, unsigned out_size_w32) +{ + unsigned char *buf; + size_t ptr; + unsigned z; + unsigned elen; + union { + unsigned char tmp[32]; + sph_u32 dummy; +#if SPH_ECHO_64 + sph_u64 dummy2; +#endif + } u; +#if SPH_ECHO_64 + sph_u64 *VV; +#else + sph_u32 *VV; +#endif + unsigned k; + + buf = sc->buf; + ptr = sc->ptr; + elen = ((unsigned)ptr << 3) + n; + INCR_COUNTER(sc, elen); + sph_enc32le_aligned(u.tmp, sc->C0); + sph_enc32le_aligned(u.tmp + 4, sc->C1); + sph_enc32le_aligned(u.tmp + 8, sc->C2); + sph_enc32le_aligned(u.tmp + 12, sc->C3); + /* + * If elen is zero, then this block actually contains no message + * bit, only the first padding bit. + */ + if (elen == 0) { + sc->C0 = sc->C1 = sc->C2 = sc->C3 = 0; + } + z = 0x80 >> n; + buf[ptr ++] = ((ub & -z) | z) & 0xFF; + memset(buf + ptr, 0, (sizeof sc->buf) - ptr); + if (ptr > ((sizeof sc->buf) - 18)) { + echo_small_compress(sc); + sc->C0 = sc->C1 = sc->C2 = sc->C3 = 0; + memset(buf, 0, sizeof sc->buf); + } + sph_enc16le(buf + (sizeof sc->buf) - 18, out_size_w32 << 5); + memcpy(buf + (sizeof sc->buf) - 16, u.tmp, 16); + echo_small_compress(sc); +#if SPH_ECHO_64 + for (VV = &sc->u.Vb[0][0], k = 0; k < ((out_size_w32 + 1) >> 1); k ++) + sph_enc64le_aligned(u.tmp + (k << 3), VV[k]); +#else + for (VV = &sc->u.Vs[0][0], k = 0; k < out_size_w32; k ++) + sph_enc32le_aligned(u.tmp + (k << 2), VV[k]); +#endif + memcpy(dst, u.tmp, out_size_w32 << 2); + echo_small_init(sc, out_size_w32 << 5); +} + +static void +echo_big_close(sph_echo_big_context *sc, unsigned ub, unsigned n, + void *dst, unsigned out_size_w32) +{ + unsigned char *buf; + size_t ptr; + unsigned z; + unsigned elen; + union { + unsigned char tmp[64]; + sph_u32 dummy; +#if SPH_ECHO_64 + sph_u64 dummy2; +#endif + } u; +#if SPH_ECHO_64 + sph_u64 *VV; +#else + sph_u32 *VV; +#endif + unsigned k; + + buf = sc->buf; + ptr = sc->ptr; + elen = ((unsigned)ptr << 3) + n; + INCR_COUNTER(sc, elen); + sph_enc32le_aligned(u.tmp, sc->C0); + sph_enc32le_aligned(u.tmp + 4, sc->C1); + sph_enc32le_aligned(u.tmp + 8, sc->C2); + sph_enc32le_aligned(u.tmp + 12, sc->C3); + /* + * If elen is zero, then this block actually contains no message + * bit, only the first padding bit. + */ + if (elen == 0) { + sc->C0 = sc->C1 = sc->C2 = sc->C3 = 0; + } + z = 0x80 >> n; + buf[ptr ++] = ((ub & -z) | z) & 0xFF; + memset(buf + ptr, 0, (sizeof sc->buf) - ptr); + if (ptr > ((sizeof sc->buf) - 18)) { + echo_big_compress(sc); + sc->C0 = sc->C1 = sc->C2 = sc->C3 = 0; + memset(buf, 0, sizeof sc->buf); + } + sph_enc16le(buf + (sizeof sc->buf) - 18, out_size_w32 << 5); + memcpy(buf + (sizeof sc->buf) - 16, u.tmp, 16); + echo_big_compress(sc); +#if SPH_ECHO_64 + for (VV = &sc->u.Vb[0][0], k = 0; k < ((out_size_w32 + 1) >> 1); k ++) + sph_enc64le_aligned(u.tmp + (k << 3), VV[k]); +#else + for (VV = &sc->u.Vs[0][0], k = 0; k < out_size_w32; k ++) + sph_enc32le_aligned(u.tmp + (k << 2), VV[k]); +#endif + memcpy(dst, u.tmp, out_size_w32 << 2); + echo_big_init(sc, out_size_w32 << 5); +} + +/* see sph_echo.h */ +void +sph_echo224_init(void *cc) +{ + echo_small_init(cc, 224); +} + +/* see sph_echo.h */ +void +sph_echo224(void *cc, const void *data, size_t len) +{ + echo_small_core(cc, data, len); +} + +/* see sph_echo.h */ +void +sph_echo224_close(void *cc, void *dst) +{ + echo_small_close(cc, 0, 0, dst, 7); +} + +/* see sph_echo.h */ +void +sph_echo224_addbits_and_close(void *cc, unsigned ub, unsigned n, void *dst) +{ + echo_small_close(cc, ub, n, dst, 7); +} + +/* see sph_echo.h */ +void +sph_echo256_init(void *cc) +{ + echo_small_init(cc, 256); +} + +/* see sph_echo.h */ +void +sph_echo256(void *cc, const void *data, size_t len) +{ + echo_small_core(cc, data, len); +} + +/* see sph_echo.h */ +void +sph_echo256_close(void *cc, void *dst) +{ + echo_small_close(cc, 0, 0, dst, 8); +} + +/* see sph_echo.h */ +void +sph_echo256_addbits_and_close(void *cc, unsigned ub, unsigned n, void *dst) +{ + echo_small_close(cc, ub, n, dst, 8); +} + +/* see sph_echo.h */ +void +sph_echo384_init(void *cc) +{ + echo_big_init(cc, 384); +} + +/* see sph_echo.h */ +void +sph_echo384(void *cc, const void *data, size_t len) +{ + echo_big_core(cc, data, len); +} + +/* see sph_echo.h */ +void +sph_echo384_close(void *cc, void *dst) +{ + echo_big_close(cc, 0, 0, dst, 12); +} + +/* see sph_echo.h */ +void +sph_echo384_addbits_and_close(void *cc, unsigned ub, unsigned n, void *dst) +{ + echo_big_close(cc, ub, n, dst, 12); +} + +/* see sph_echo.h */ +void +sph_echo512_init(void *cc) +{ + echo_big_init(cc, 512); +} + +/* see sph_echo.h */ +void +sph_echo512(void *cc, const void *data, size_t len) +{ + echo_big_core(cc, data, len); +} + +/* see sph_echo.h */ +void +sph_echo512_close(void *cc, void *dst) +{ + echo_big_close(cc, 0, 0, dst, 16); +} + +/* see sph_echo.h */ +void +sph_echo512_addbits_and_close(void *cc, unsigned ub, unsigned n, void *dst) +{ + echo_big_close(cc, ub, n, dst, 16); +} +#ifdef __cplusplus +} +#endif diff --git a/src/fugue.c b/src/fugue.c new file mode 100644 index 0000000..85767c9 --- /dev/null +++ b/src/fugue.c @@ -0,0 +1,1208 @@ +#include +#include + +#include "sph_fugue.h" + +#ifdef __cplusplus +extern "C"{ +#endif + +#ifdef _MSC_VER +#pragma warning (disable: 4146) +#endif + +static const sph_u32 IV224[] = { + SPH_C32(0xf4c9120d), SPH_C32(0x6286f757), SPH_C32(0xee39e01c), + SPH_C32(0xe074e3cb), SPH_C32(0xa1127c62), SPH_C32(0x9a43d215), + SPH_C32(0xbd8d679a) +}; + +static const sph_u32 IV256[] = { + SPH_C32(0xe952bdde), SPH_C32(0x6671135f), SPH_C32(0xe0d4f668), + SPH_C32(0xd2b0b594), SPH_C32(0xf96c621d), SPH_C32(0xfbf929de), + SPH_C32(0x9149e899), SPH_C32(0x34f8c248) +}; + +static const sph_u32 IV384[] = { + SPH_C32(0xaa61ec0d), SPH_C32(0x31252e1f), SPH_C32(0xa01db4c7), + SPH_C32(0x00600985), SPH_C32(0x215ef44a), SPH_C32(0x741b5e9c), + SPH_C32(0xfa693e9a), SPH_C32(0x473eb040), SPH_C32(0xe502ae8a), + SPH_C32(0xa99c25e0), SPH_C32(0xbc95517c), SPH_C32(0x5c1095a1) +}; + +static const sph_u32 IV512[] = { + SPH_C32(0x8807a57e), SPH_C32(0xe616af75), SPH_C32(0xc5d3e4db), + SPH_C32(0xac9ab027), SPH_C32(0xd915f117), SPH_C32(0xb6eecc54), + SPH_C32(0x06e8020b), SPH_C32(0x4a92efd1), SPH_C32(0xaac6e2c9), + SPH_C32(0xddb21398), SPH_C32(0xcae65838), SPH_C32(0x437f203f), + SPH_C32(0x25ea78e7), SPH_C32(0x951fddd6), SPH_C32(0xda6ed11d), + SPH_C32(0xe13e3567) +}; + +static const sph_u32 mixtab0[] = { + SPH_C32(0x63633297), SPH_C32(0x7c7c6feb), SPH_C32(0x77775ec7), + SPH_C32(0x7b7b7af7), SPH_C32(0xf2f2e8e5), SPH_C32(0x6b6b0ab7), + SPH_C32(0x6f6f16a7), SPH_C32(0xc5c56d39), SPH_C32(0x303090c0), + SPH_C32(0x01010704), SPH_C32(0x67672e87), SPH_C32(0x2b2bd1ac), + SPH_C32(0xfefeccd5), SPH_C32(0xd7d71371), SPH_C32(0xabab7c9a), + SPH_C32(0x767659c3), SPH_C32(0xcaca4005), SPH_C32(0x8282a33e), + SPH_C32(0xc9c94909), SPH_C32(0x7d7d68ef), SPH_C32(0xfafad0c5), + SPH_C32(0x5959947f), SPH_C32(0x4747ce07), SPH_C32(0xf0f0e6ed), + SPH_C32(0xadad6e82), SPH_C32(0xd4d41a7d), SPH_C32(0xa2a243be), + SPH_C32(0xafaf608a), SPH_C32(0x9c9cf946), SPH_C32(0xa4a451a6), + SPH_C32(0x727245d3), SPH_C32(0xc0c0762d), SPH_C32(0xb7b728ea), + SPH_C32(0xfdfdc5d9), SPH_C32(0x9393d47a), SPH_C32(0x2626f298), + SPH_C32(0x363682d8), SPH_C32(0x3f3fbdfc), SPH_C32(0xf7f7f3f1), + SPH_C32(0xcccc521d), SPH_C32(0x34348cd0), SPH_C32(0xa5a556a2), + SPH_C32(0xe5e58db9), SPH_C32(0xf1f1e1e9), SPH_C32(0x71714cdf), + SPH_C32(0xd8d83e4d), SPH_C32(0x313197c4), SPH_C32(0x15156b54), + SPH_C32(0x04041c10), SPH_C32(0xc7c76331), SPH_C32(0x2323e98c), + SPH_C32(0xc3c37f21), SPH_C32(0x18184860), SPH_C32(0x9696cf6e), + SPH_C32(0x05051b14), SPH_C32(0x9a9aeb5e), SPH_C32(0x0707151c), + SPH_C32(0x12127e48), SPH_C32(0x8080ad36), SPH_C32(0xe2e298a5), + SPH_C32(0xebeba781), SPH_C32(0x2727f59c), SPH_C32(0xb2b233fe), + SPH_C32(0x757550cf), SPH_C32(0x09093f24), SPH_C32(0x8383a43a), + SPH_C32(0x2c2cc4b0), SPH_C32(0x1a1a4668), SPH_C32(0x1b1b416c), + SPH_C32(0x6e6e11a3), SPH_C32(0x5a5a9d73), SPH_C32(0xa0a04db6), + SPH_C32(0x5252a553), SPH_C32(0x3b3ba1ec), SPH_C32(0xd6d61475), + SPH_C32(0xb3b334fa), SPH_C32(0x2929dfa4), SPH_C32(0xe3e39fa1), + SPH_C32(0x2f2fcdbc), SPH_C32(0x8484b126), SPH_C32(0x5353a257), + SPH_C32(0xd1d10169), SPH_C32(0x00000000), SPH_C32(0xededb599), + SPH_C32(0x2020e080), SPH_C32(0xfcfcc2dd), SPH_C32(0xb1b13af2), + SPH_C32(0x5b5b9a77), SPH_C32(0x6a6a0db3), SPH_C32(0xcbcb4701), + SPH_C32(0xbebe17ce), SPH_C32(0x3939afe4), SPH_C32(0x4a4aed33), + SPH_C32(0x4c4cff2b), SPH_C32(0x5858937b), SPH_C32(0xcfcf5b11), + SPH_C32(0xd0d0066d), SPH_C32(0xefefbb91), SPH_C32(0xaaaa7b9e), + SPH_C32(0xfbfbd7c1), SPH_C32(0x4343d217), SPH_C32(0x4d4df82f), + SPH_C32(0x333399cc), SPH_C32(0x8585b622), SPH_C32(0x4545c00f), + SPH_C32(0xf9f9d9c9), SPH_C32(0x02020e08), SPH_C32(0x7f7f66e7), + SPH_C32(0x5050ab5b), SPH_C32(0x3c3cb4f0), SPH_C32(0x9f9ff04a), + SPH_C32(0xa8a87596), SPH_C32(0x5151ac5f), SPH_C32(0xa3a344ba), + SPH_C32(0x4040db1b), SPH_C32(0x8f8f800a), SPH_C32(0x9292d37e), + SPH_C32(0x9d9dfe42), SPH_C32(0x3838a8e0), SPH_C32(0xf5f5fdf9), + SPH_C32(0xbcbc19c6), SPH_C32(0xb6b62fee), SPH_C32(0xdada3045), + SPH_C32(0x2121e784), SPH_C32(0x10107040), SPH_C32(0xffffcbd1), + SPH_C32(0xf3f3efe1), SPH_C32(0xd2d20865), SPH_C32(0xcdcd5519), + SPH_C32(0x0c0c2430), SPH_C32(0x1313794c), SPH_C32(0xececb29d), + SPH_C32(0x5f5f8667), SPH_C32(0x9797c86a), SPH_C32(0x4444c70b), + SPH_C32(0x1717655c), SPH_C32(0xc4c46a3d), SPH_C32(0xa7a758aa), + SPH_C32(0x7e7e61e3), SPH_C32(0x3d3db3f4), SPH_C32(0x6464278b), + SPH_C32(0x5d5d886f), SPH_C32(0x19194f64), SPH_C32(0x737342d7), + SPH_C32(0x60603b9b), SPH_C32(0x8181aa32), SPH_C32(0x4f4ff627), + SPH_C32(0xdcdc225d), SPH_C32(0x2222ee88), SPH_C32(0x2a2ad6a8), + SPH_C32(0x9090dd76), SPH_C32(0x88889516), SPH_C32(0x4646c903), + SPH_C32(0xeeeebc95), SPH_C32(0xb8b805d6), SPH_C32(0x14146c50), + SPH_C32(0xdede2c55), SPH_C32(0x5e5e8163), SPH_C32(0x0b0b312c), + SPH_C32(0xdbdb3741), SPH_C32(0xe0e096ad), SPH_C32(0x32329ec8), + SPH_C32(0x3a3aa6e8), SPH_C32(0x0a0a3628), SPH_C32(0x4949e43f), + SPH_C32(0x06061218), SPH_C32(0x2424fc90), SPH_C32(0x5c5c8f6b), + SPH_C32(0xc2c27825), SPH_C32(0xd3d30f61), SPH_C32(0xacac6986), + SPH_C32(0x62623593), SPH_C32(0x9191da72), SPH_C32(0x9595c662), + SPH_C32(0xe4e48abd), SPH_C32(0x797974ff), SPH_C32(0xe7e783b1), + SPH_C32(0xc8c84e0d), SPH_C32(0x373785dc), SPH_C32(0x6d6d18af), + SPH_C32(0x8d8d8e02), SPH_C32(0xd5d51d79), SPH_C32(0x4e4ef123), + SPH_C32(0xa9a97292), SPH_C32(0x6c6c1fab), SPH_C32(0x5656b943), + SPH_C32(0xf4f4fafd), SPH_C32(0xeaeaa085), SPH_C32(0x6565208f), + SPH_C32(0x7a7a7df3), SPH_C32(0xaeae678e), SPH_C32(0x08083820), + SPH_C32(0xbaba0bde), SPH_C32(0x787873fb), SPH_C32(0x2525fb94), + SPH_C32(0x2e2ecab8), SPH_C32(0x1c1c5470), SPH_C32(0xa6a65fae), + SPH_C32(0xb4b421e6), SPH_C32(0xc6c66435), SPH_C32(0xe8e8ae8d), + SPH_C32(0xdddd2559), SPH_C32(0x747457cb), SPH_C32(0x1f1f5d7c), + SPH_C32(0x4b4bea37), SPH_C32(0xbdbd1ec2), SPH_C32(0x8b8b9c1a), + SPH_C32(0x8a8a9b1e), SPH_C32(0x70704bdb), SPH_C32(0x3e3ebaf8), + SPH_C32(0xb5b526e2), SPH_C32(0x66662983), SPH_C32(0x4848e33b), + SPH_C32(0x0303090c), SPH_C32(0xf6f6f4f5), SPH_C32(0x0e0e2a38), + SPH_C32(0x61613c9f), SPH_C32(0x35358bd4), SPH_C32(0x5757be47), + SPH_C32(0xb9b902d2), SPH_C32(0x8686bf2e), SPH_C32(0xc1c17129), + SPH_C32(0x1d1d5374), SPH_C32(0x9e9ef74e), SPH_C32(0xe1e191a9), + SPH_C32(0xf8f8decd), SPH_C32(0x9898e556), SPH_C32(0x11117744), + SPH_C32(0x696904bf), SPH_C32(0xd9d93949), SPH_C32(0x8e8e870e), + SPH_C32(0x9494c166), SPH_C32(0x9b9bec5a), SPH_C32(0x1e1e5a78), + SPH_C32(0x8787b82a), SPH_C32(0xe9e9a989), SPH_C32(0xcece5c15), + SPH_C32(0x5555b04f), SPH_C32(0x2828d8a0), SPH_C32(0xdfdf2b51), + SPH_C32(0x8c8c8906), SPH_C32(0xa1a14ab2), SPH_C32(0x89899212), + SPH_C32(0x0d0d2334), SPH_C32(0xbfbf10ca), SPH_C32(0xe6e684b5), + SPH_C32(0x4242d513), SPH_C32(0x686803bb), SPH_C32(0x4141dc1f), + SPH_C32(0x9999e252), SPH_C32(0x2d2dc3b4), SPH_C32(0x0f0f2d3c), + SPH_C32(0xb0b03df6), SPH_C32(0x5454b74b), SPH_C32(0xbbbb0cda), + SPH_C32(0x16166258) +}; + +static const sph_u32 mixtab1[] = { + SPH_C32(0x97636332), SPH_C32(0xeb7c7c6f), SPH_C32(0xc777775e), + SPH_C32(0xf77b7b7a), SPH_C32(0xe5f2f2e8), SPH_C32(0xb76b6b0a), + SPH_C32(0xa76f6f16), SPH_C32(0x39c5c56d), SPH_C32(0xc0303090), + SPH_C32(0x04010107), SPH_C32(0x8767672e), SPH_C32(0xac2b2bd1), + SPH_C32(0xd5fefecc), SPH_C32(0x71d7d713), SPH_C32(0x9aabab7c), + SPH_C32(0xc3767659), SPH_C32(0x05caca40), SPH_C32(0x3e8282a3), + SPH_C32(0x09c9c949), SPH_C32(0xef7d7d68), SPH_C32(0xc5fafad0), + SPH_C32(0x7f595994), SPH_C32(0x074747ce), SPH_C32(0xedf0f0e6), + SPH_C32(0x82adad6e), SPH_C32(0x7dd4d41a), SPH_C32(0xbea2a243), + SPH_C32(0x8aafaf60), SPH_C32(0x469c9cf9), SPH_C32(0xa6a4a451), + SPH_C32(0xd3727245), SPH_C32(0x2dc0c076), SPH_C32(0xeab7b728), + SPH_C32(0xd9fdfdc5), SPH_C32(0x7a9393d4), SPH_C32(0x982626f2), + SPH_C32(0xd8363682), SPH_C32(0xfc3f3fbd), SPH_C32(0xf1f7f7f3), + SPH_C32(0x1dcccc52), SPH_C32(0xd034348c), SPH_C32(0xa2a5a556), + SPH_C32(0xb9e5e58d), SPH_C32(0xe9f1f1e1), SPH_C32(0xdf71714c), + SPH_C32(0x4dd8d83e), SPH_C32(0xc4313197), SPH_C32(0x5415156b), + SPH_C32(0x1004041c), SPH_C32(0x31c7c763), SPH_C32(0x8c2323e9), + SPH_C32(0x21c3c37f), SPH_C32(0x60181848), SPH_C32(0x6e9696cf), + SPH_C32(0x1405051b), SPH_C32(0x5e9a9aeb), SPH_C32(0x1c070715), + SPH_C32(0x4812127e), SPH_C32(0x368080ad), SPH_C32(0xa5e2e298), + SPH_C32(0x81ebeba7), SPH_C32(0x9c2727f5), SPH_C32(0xfeb2b233), + SPH_C32(0xcf757550), SPH_C32(0x2409093f), SPH_C32(0x3a8383a4), + SPH_C32(0xb02c2cc4), SPH_C32(0x681a1a46), SPH_C32(0x6c1b1b41), + SPH_C32(0xa36e6e11), SPH_C32(0x735a5a9d), SPH_C32(0xb6a0a04d), + SPH_C32(0x535252a5), SPH_C32(0xec3b3ba1), SPH_C32(0x75d6d614), + SPH_C32(0xfab3b334), SPH_C32(0xa42929df), SPH_C32(0xa1e3e39f), + SPH_C32(0xbc2f2fcd), SPH_C32(0x268484b1), SPH_C32(0x575353a2), + SPH_C32(0x69d1d101), SPH_C32(0x00000000), SPH_C32(0x99ededb5), + SPH_C32(0x802020e0), SPH_C32(0xddfcfcc2), SPH_C32(0xf2b1b13a), + SPH_C32(0x775b5b9a), SPH_C32(0xb36a6a0d), SPH_C32(0x01cbcb47), + SPH_C32(0xcebebe17), SPH_C32(0xe43939af), SPH_C32(0x334a4aed), + SPH_C32(0x2b4c4cff), SPH_C32(0x7b585893), SPH_C32(0x11cfcf5b), + SPH_C32(0x6dd0d006), SPH_C32(0x91efefbb), SPH_C32(0x9eaaaa7b), + SPH_C32(0xc1fbfbd7), SPH_C32(0x174343d2), SPH_C32(0x2f4d4df8), + SPH_C32(0xcc333399), SPH_C32(0x228585b6), SPH_C32(0x0f4545c0), + SPH_C32(0xc9f9f9d9), SPH_C32(0x0802020e), SPH_C32(0xe77f7f66), + SPH_C32(0x5b5050ab), SPH_C32(0xf03c3cb4), SPH_C32(0x4a9f9ff0), + SPH_C32(0x96a8a875), SPH_C32(0x5f5151ac), SPH_C32(0xbaa3a344), + SPH_C32(0x1b4040db), SPH_C32(0x0a8f8f80), SPH_C32(0x7e9292d3), + SPH_C32(0x429d9dfe), SPH_C32(0xe03838a8), SPH_C32(0xf9f5f5fd), + SPH_C32(0xc6bcbc19), SPH_C32(0xeeb6b62f), SPH_C32(0x45dada30), + SPH_C32(0x842121e7), SPH_C32(0x40101070), SPH_C32(0xd1ffffcb), + SPH_C32(0xe1f3f3ef), SPH_C32(0x65d2d208), SPH_C32(0x19cdcd55), + SPH_C32(0x300c0c24), SPH_C32(0x4c131379), SPH_C32(0x9dececb2), + SPH_C32(0x675f5f86), SPH_C32(0x6a9797c8), SPH_C32(0x0b4444c7), + SPH_C32(0x5c171765), SPH_C32(0x3dc4c46a), SPH_C32(0xaaa7a758), + SPH_C32(0xe37e7e61), SPH_C32(0xf43d3db3), SPH_C32(0x8b646427), + SPH_C32(0x6f5d5d88), SPH_C32(0x6419194f), SPH_C32(0xd7737342), + SPH_C32(0x9b60603b), SPH_C32(0x328181aa), SPH_C32(0x274f4ff6), + SPH_C32(0x5ddcdc22), SPH_C32(0x882222ee), SPH_C32(0xa82a2ad6), + SPH_C32(0x769090dd), SPH_C32(0x16888895), SPH_C32(0x034646c9), + SPH_C32(0x95eeeebc), SPH_C32(0xd6b8b805), SPH_C32(0x5014146c), + SPH_C32(0x55dede2c), SPH_C32(0x635e5e81), SPH_C32(0x2c0b0b31), + SPH_C32(0x41dbdb37), SPH_C32(0xade0e096), SPH_C32(0xc832329e), + SPH_C32(0xe83a3aa6), SPH_C32(0x280a0a36), SPH_C32(0x3f4949e4), + SPH_C32(0x18060612), SPH_C32(0x902424fc), SPH_C32(0x6b5c5c8f), + SPH_C32(0x25c2c278), SPH_C32(0x61d3d30f), SPH_C32(0x86acac69), + SPH_C32(0x93626235), SPH_C32(0x729191da), SPH_C32(0x629595c6), + SPH_C32(0xbde4e48a), SPH_C32(0xff797974), SPH_C32(0xb1e7e783), + SPH_C32(0x0dc8c84e), SPH_C32(0xdc373785), SPH_C32(0xaf6d6d18), + SPH_C32(0x028d8d8e), SPH_C32(0x79d5d51d), SPH_C32(0x234e4ef1), + SPH_C32(0x92a9a972), SPH_C32(0xab6c6c1f), SPH_C32(0x435656b9), + SPH_C32(0xfdf4f4fa), SPH_C32(0x85eaeaa0), SPH_C32(0x8f656520), + SPH_C32(0xf37a7a7d), SPH_C32(0x8eaeae67), SPH_C32(0x20080838), + SPH_C32(0xdebaba0b), SPH_C32(0xfb787873), SPH_C32(0x942525fb), + SPH_C32(0xb82e2eca), SPH_C32(0x701c1c54), SPH_C32(0xaea6a65f), + SPH_C32(0xe6b4b421), SPH_C32(0x35c6c664), SPH_C32(0x8de8e8ae), + SPH_C32(0x59dddd25), SPH_C32(0xcb747457), SPH_C32(0x7c1f1f5d), + SPH_C32(0x374b4bea), SPH_C32(0xc2bdbd1e), SPH_C32(0x1a8b8b9c), + SPH_C32(0x1e8a8a9b), SPH_C32(0xdb70704b), SPH_C32(0xf83e3eba), + SPH_C32(0xe2b5b526), SPH_C32(0x83666629), SPH_C32(0x3b4848e3), + SPH_C32(0x0c030309), SPH_C32(0xf5f6f6f4), SPH_C32(0x380e0e2a), + SPH_C32(0x9f61613c), SPH_C32(0xd435358b), SPH_C32(0x475757be), + SPH_C32(0xd2b9b902), SPH_C32(0x2e8686bf), SPH_C32(0x29c1c171), + SPH_C32(0x741d1d53), SPH_C32(0x4e9e9ef7), SPH_C32(0xa9e1e191), + SPH_C32(0xcdf8f8de), SPH_C32(0x569898e5), SPH_C32(0x44111177), + SPH_C32(0xbf696904), SPH_C32(0x49d9d939), SPH_C32(0x0e8e8e87), + SPH_C32(0x669494c1), SPH_C32(0x5a9b9bec), SPH_C32(0x781e1e5a), + SPH_C32(0x2a8787b8), SPH_C32(0x89e9e9a9), SPH_C32(0x15cece5c), + SPH_C32(0x4f5555b0), SPH_C32(0xa02828d8), SPH_C32(0x51dfdf2b), + SPH_C32(0x068c8c89), SPH_C32(0xb2a1a14a), SPH_C32(0x12898992), + SPH_C32(0x340d0d23), SPH_C32(0xcabfbf10), SPH_C32(0xb5e6e684), + SPH_C32(0x134242d5), SPH_C32(0xbb686803), SPH_C32(0x1f4141dc), + SPH_C32(0x529999e2), SPH_C32(0xb42d2dc3), SPH_C32(0x3c0f0f2d), + SPH_C32(0xf6b0b03d), SPH_C32(0x4b5454b7), SPH_C32(0xdabbbb0c), + SPH_C32(0x58161662) +}; + +static const sph_u32 mixtab2[] = { + SPH_C32(0x32976363), SPH_C32(0x6feb7c7c), SPH_C32(0x5ec77777), + SPH_C32(0x7af77b7b), SPH_C32(0xe8e5f2f2), SPH_C32(0x0ab76b6b), + SPH_C32(0x16a76f6f), SPH_C32(0x6d39c5c5), SPH_C32(0x90c03030), + SPH_C32(0x07040101), SPH_C32(0x2e876767), SPH_C32(0xd1ac2b2b), + SPH_C32(0xccd5fefe), SPH_C32(0x1371d7d7), SPH_C32(0x7c9aabab), + SPH_C32(0x59c37676), SPH_C32(0x4005caca), SPH_C32(0xa33e8282), + SPH_C32(0x4909c9c9), SPH_C32(0x68ef7d7d), SPH_C32(0xd0c5fafa), + SPH_C32(0x947f5959), SPH_C32(0xce074747), SPH_C32(0xe6edf0f0), + SPH_C32(0x6e82adad), SPH_C32(0x1a7dd4d4), SPH_C32(0x43bea2a2), + SPH_C32(0x608aafaf), SPH_C32(0xf9469c9c), SPH_C32(0x51a6a4a4), + SPH_C32(0x45d37272), SPH_C32(0x762dc0c0), SPH_C32(0x28eab7b7), + SPH_C32(0xc5d9fdfd), SPH_C32(0xd47a9393), SPH_C32(0xf2982626), + SPH_C32(0x82d83636), SPH_C32(0xbdfc3f3f), SPH_C32(0xf3f1f7f7), + SPH_C32(0x521dcccc), SPH_C32(0x8cd03434), SPH_C32(0x56a2a5a5), + SPH_C32(0x8db9e5e5), SPH_C32(0xe1e9f1f1), SPH_C32(0x4cdf7171), + SPH_C32(0x3e4dd8d8), SPH_C32(0x97c43131), SPH_C32(0x6b541515), + SPH_C32(0x1c100404), SPH_C32(0x6331c7c7), SPH_C32(0xe98c2323), + SPH_C32(0x7f21c3c3), SPH_C32(0x48601818), SPH_C32(0xcf6e9696), + SPH_C32(0x1b140505), SPH_C32(0xeb5e9a9a), SPH_C32(0x151c0707), + SPH_C32(0x7e481212), SPH_C32(0xad368080), SPH_C32(0x98a5e2e2), + SPH_C32(0xa781ebeb), SPH_C32(0xf59c2727), SPH_C32(0x33feb2b2), + SPH_C32(0x50cf7575), SPH_C32(0x3f240909), SPH_C32(0xa43a8383), + SPH_C32(0xc4b02c2c), SPH_C32(0x46681a1a), SPH_C32(0x416c1b1b), + SPH_C32(0x11a36e6e), SPH_C32(0x9d735a5a), SPH_C32(0x4db6a0a0), + SPH_C32(0xa5535252), SPH_C32(0xa1ec3b3b), SPH_C32(0x1475d6d6), + SPH_C32(0x34fab3b3), SPH_C32(0xdfa42929), SPH_C32(0x9fa1e3e3), + SPH_C32(0xcdbc2f2f), SPH_C32(0xb1268484), SPH_C32(0xa2575353), + SPH_C32(0x0169d1d1), SPH_C32(0x00000000), SPH_C32(0xb599eded), + SPH_C32(0xe0802020), SPH_C32(0xc2ddfcfc), SPH_C32(0x3af2b1b1), + SPH_C32(0x9a775b5b), SPH_C32(0x0db36a6a), SPH_C32(0x4701cbcb), + SPH_C32(0x17cebebe), SPH_C32(0xafe43939), SPH_C32(0xed334a4a), + SPH_C32(0xff2b4c4c), SPH_C32(0x937b5858), SPH_C32(0x5b11cfcf), + SPH_C32(0x066dd0d0), SPH_C32(0xbb91efef), SPH_C32(0x7b9eaaaa), + SPH_C32(0xd7c1fbfb), SPH_C32(0xd2174343), SPH_C32(0xf82f4d4d), + SPH_C32(0x99cc3333), SPH_C32(0xb6228585), SPH_C32(0xc00f4545), + SPH_C32(0xd9c9f9f9), SPH_C32(0x0e080202), SPH_C32(0x66e77f7f), + SPH_C32(0xab5b5050), SPH_C32(0xb4f03c3c), SPH_C32(0xf04a9f9f), + SPH_C32(0x7596a8a8), SPH_C32(0xac5f5151), SPH_C32(0x44baa3a3), + SPH_C32(0xdb1b4040), SPH_C32(0x800a8f8f), SPH_C32(0xd37e9292), + SPH_C32(0xfe429d9d), SPH_C32(0xa8e03838), SPH_C32(0xfdf9f5f5), + SPH_C32(0x19c6bcbc), SPH_C32(0x2feeb6b6), SPH_C32(0x3045dada), + SPH_C32(0xe7842121), SPH_C32(0x70401010), SPH_C32(0xcbd1ffff), + SPH_C32(0xefe1f3f3), SPH_C32(0x0865d2d2), SPH_C32(0x5519cdcd), + SPH_C32(0x24300c0c), SPH_C32(0x794c1313), SPH_C32(0xb29decec), + SPH_C32(0x86675f5f), SPH_C32(0xc86a9797), SPH_C32(0xc70b4444), + SPH_C32(0x655c1717), SPH_C32(0x6a3dc4c4), SPH_C32(0x58aaa7a7), + SPH_C32(0x61e37e7e), SPH_C32(0xb3f43d3d), SPH_C32(0x278b6464), + SPH_C32(0x886f5d5d), SPH_C32(0x4f641919), SPH_C32(0x42d77373), + SPH_C32(0x3b9b6060), SPH_C32(0xaa328181), SPH_C32(0xf6274f4f), + SPH_C32(0x225ddcdc), SPH_C32(0xee882222), SPH_C32(0xd6a82a2a), + SPH_C32(0xdd769090), SPH_C32(0x95168888), SPH_C32(0xc9034646), + SPH_C32(0xbc95eeee), SPH_C32(0x05d6b8b8), SPH_C32(0x6c501414), + SPH_C32(0x2c55dede), SPH_C32(0x81635e5e), SPH_C32(0x312c0b0b), + SPH_C32(0x3741dbdb), SPH_C32(0x96ade0e0), SPH_C32(0x9ec83232), + SPH_C32(0xa6e83a3a), SPH_C32(0x36280a0a), SPH_C32(0xe43f4949), + SPH_C32(0x12180606), SPH_C32(0xfc902424), SPH_C32(0x8f6b5c5c), + SPH_C32(0x7825c2c2), SPH_C32(0x0f61d3d3), SPH_C32(0x6986acac), + SPH_C32(0x35936262), SPH_C32(0xda729191), SPH_C32(0xc6629595), + SPH_C32(0x8abde4e4), SPH_C32(0x74ff7979), SPH_C32(0x83b1e7e7), + SPH_C32(0x4e0dc8c8), SPH_C32(0x85dc3737), SPH_C32(0x18af6d6d), + SPH_C32(0x8e028d8d), SPH_C32(0x1d79d5d5), SPH_C32(0xf1234e4e), + SPH_C32(0x7292a9a9), SPH_C32(0x1fab6c6c), SPH_C32(0xb9435656), + SPH_C32(0xfafdf4f4), SPH_C32(0xa085eaea), SPH_C32(0x208f6565), + SPH_C32(0x7df37a7a), SPH_C32(0x678eaeae), SPH_C32(0x38200808), + SPH_C32(0x0bdebaba), SPH_C32(0x73fb7878), SPH_C32(0xfb942525), + SPH_C32(0xcab82e2e), SPH_C32(0x54701c1c), SPH_C32(0x5faea6a6), + SPH_C32(0x21e6b4b4), SPH_C32(0x6435c6c6), SPH_C32(0xae8de8e8), + SPH_C32(0x2559dddd), SPH_C32(0x57cb7474), SPH_C32(0x5d7c1f1f), + SPH_C32(0xea374b4b), SPH_C32(0x1ec2bdbd), SPH_C32(0x9c1a8b8b), + SPH_C32(0x9b1e8a8a), SPH_C32(0x4bdb7070), SPH_C32(0xbaf83e3e), + SPH_C32(0x26e2b5b5), SPH_C32(0x29836666), SPH_C32(0xe33b4848), + SPH_C32(0x090c0303), SPH_C32(0xf4f5f6f6), SPH_C32(0x2a380e0e), + SPH_C32(0x3c9f6161), SPH_C32(0x8bd43535), SPH_C32(0xbe475757), + SPH_C32(0x02d2b9b9), SPH_C32(0xbf2e8686), SPH_C32(0x7129c1c1), + SPH_C32(0x53741d1d), SPH_C32(0xf74e9e9e), SPH_C32(0x91a9e1e1), + SPH_C32(0xdecdf8f8), SPH_C32(0xe5569898), SPH_C32(0x77441111), + SPH_C32(0x04bf6969), SPH_C32(0x3949d9d9), SPH_C32(0x870e8e8e), + SPH_C32(0xc1669494), SPH_C32(0xec5a9b9b), SPH_C32(0x5a781e1e), + SPH_C32(0xb82a8787), SPH_C32(0xa989e9e9), SPH_C32(0x5c15cece), + SPH_C32(0xb04f5555), SPH_C32(0xd8a02828), SPH_C32(0x2b51dfdf), + SPH_C32(0x89068c8c), SPH_C32(0x4ab2a1a1), SPH_C32(0x92128989), + SPH_C32(0x23340d0d), SPH_C32(0x10cabfbf), SPH_C32(0x84b5e6e6), + SPH_C32(0xd5134242), SPH_C32(0x03bb6868), SPH_C32(0xdc1f4141), + SPH_C32(0xe2529999), SPH_C32(0xc3b42d2d), SPH_C32(0x2d3c0f0f), + SPH_C32(0x3df6b0b0), SPH_C32(0xb74b5454), SPH_C32(0x0cdabbbb), + SPH_C32(0x62581616) +}; + +static const sph_u32 mixtab3[] = { + SPH_C32(0x63329763), SPH_C32(0x7c6feb7c), SPH_C32(0x775ec777), + SPH_C32(0x7b7af77b), SPH_C32(0xf2e8e5f2), SPH_C32(0x6b0ab76b), + SPH_C32(0x6f16a76f), SPH_C32(0xc56d39c5), SPH_C32(0x3090c030), + SPH_C32(0x01070401), SPH_C32(0x672e8767), SPH_C32(0x2bd1ac2b), + SPH_C32(0xfeccd5fe), SPH_C32(0xd71371d7), SPH_C32(0xab7c9aab), + SPH_C32(0x7659c376), SPH_C32(0xca4005ca), SPH_C32(0x82a33e82), + SPH_C32(0xc94909c9), SPH_C32(0x7d68ef7d), SPH_C32(0xfad0c5fa), + SPH_C32(0x59947f59), SPH_C32(0x47ce0747), SPH_C32(0xf0e6edf0), + SPH_C32(0xad6e82ad), SPH_C32(0xd41a7dd4), SPH_C32(0xa243bea2), + SPH_C32(0xaf608aaf), SPH_C32(0x9cf9469c), SPH_C32(0xa451a6a4), + SPH_C32(0x7245d372), SPH_C32(0xc0762dc0), SPH_C32(0xb728eab7), + SPH_C32(0xfdc5d9fd), SPH_C32(0x93d47a93), SPH_C32(0x26f29826), + SPH_C32(0x3682d836), SPH_C32(0x3fbdfc3f), SPH_C32(0xf7f3f1f7), + SPH_C32(0xcc521dcc), SPH_C32(0x348cd034), SPH_C32(0xa556a2a5), + SPH_C32(0xe58db9e5), SPH_C32(0xf1e1e9f1), SPH_C32(0x714cdf71), + SPH_C32(0xd83e4dd8), SPH_C32(0x3197c431), SPH_C32(0x156b5415), + SPH_C32(0x041c1004), SPH_C32(0xc76331c7), SPH_C32(0x23e98c23), + SPH_C32(0xc37f21c3), SPH_C32(0x18486018), SPH_C32(0x96cf6e96), + SPH_C32(0x051b1405), SPH_C32(0x9aeb5e9a), SPH_C32(0x07151c07), + SPH_C32(0x127e4812), SPH_C32(0x80ad3680), SPH_C32(0xe298a5e2), + SPH_C32(0xeba781eb), SPH_C32(0x27f59c27), SPH_C32(0xb233feb2), + SPH_C32(0x7550cf75), SPH_C32(0x093f2409), SPH_C32(0x83a43a83), + SPH_C32(0x2cc4b02c), SPH_C32(0x1a46681a), SPH_C32(0x1b416c1b), + SPH_C32(0x6e11a36e), SPH_C32(0x5a9d735a), SPH_C32(0xa04db6a0), + SPH_C32(0x52a55352), SPH_C32(0x3ba1ec3b), SPH_C32(0xd61475d6), + SPH_C32(0xb334fab3), SPH_C32(0x29dfa429), SPH_C32(0xe39fa1e3), + SPH_C32(0x2fcdbc2f), SPH_C32(0x84b12684), SPH_C32(0x53a25753), + SPH_C32(0xd10169d1), SPH_C32(0x00000000), SPH_C32(0xedb599ed), + SPH_C32(0x20e08020), SPH_C32(0xfcc2ddfc), SPH_C32(0xb13af2b1), + SPH_C32(0x5b9a775b), SPH_C32(0x6a0db36a), SPH_C32(0xcb4701cb), + SPH_C32(0xbe17cebe), SPH_C32(0x39afe439), SPH_C32(0x4aed334a), + SPH_C32(0x4cff2b4c), SPH_C32(0x58937b58), SPH_C32(0xcf5b11cf), + SPH_C32(0xd0066dd0), SPH_C32(0xefbb91ef), SPH_C32(0xaa7b9eaa), + SPH_C32(0xfbd7c1fb), SPH_C32(0x43d21743), SPH_C32(0x4df82f4d), + SPH_C32(0x3399cc33), SPH_C32(0x85b62285), SPH_C32(0x45c00f45), + SPH_C32(0xf9d9c9f9), SPH_C32(0x020e0802), SPH_C32(0x7f66e77f), + SPH_C32(0x50ab5b50), SPH_C32(0x3cb4f03c), SPH_C32(0x9ff04a9f), + SPH_C32(0xa87596a8), SPH_C32(0x51ac5f51), SPH_C32(0xa344baa3), + SPH_C32(0x40db1b40), SPH_C32(0x8f800a8f), SPH_C32(0x92d37e92), + SPH_C32(0x9dfe429d), SPH_C32(0x38a8e038), SPH_C32(0xf5fdf9f5), + SPH_C32(0xbc19c6bc), SPH_C32(0xb62feeb6), SPH_C32(0xda3045da), + SPH_C32(0x21e78421), SPH_C32(0x10704010), SPH_C32(0xffcbd1ff), + SPH_C32(0xf3efe1f3), SPH_C32(0xd20865d2), SPH_C32(0xcd5519cd), + SPH_C32(0x0c24300c), SPH_C32(0x13794c13), SPH_C32(0xecb29dec), + SPH_C32(0x5f86675f), SPH_C32(0x97c86a97), SPH_C32(0x44c70b44), + SPH_C32(0x17655c17), SPH_C32(0xc46a3dc4), SPH_C32(0xa758aaa7), + SPH_C32(0x7e61e37e), SPH_C32(0x3db3f43d), SPH_C32(0x64278b64), + SPH_C32(0x5d886f5d), SPH_C32(0x194f6419), SPH_C32(0x7342d773), + SPH_C32(0x603b9b60), SPH_C32(0x81aa3281), SPH_C32(0x4ff6274f), + SPH_C32(0xdc225ddc), SPH_C32(0x22ee8822), SPH_C32(0x2ad6a82a), + SPH_C32(0x90dd7690), SPH_C32(0x88951688), SPH_C32(0x46c90346), + SPH_C32(0xeebc95ee), SPH_C32(0xb805d6b8), SPH_C32(0x146c5014), + SPH_C32(0xde2c55de), SPH_C32(0x5e81635e), SPH_C32(0x0b312c0b), + SPH_C32(0xdb3741db), SPH_C32(0xe096ade0), SPH_C32(0x329ec832), + SPH_C32(0x3aa6e83a), SPH_C32(0x0a36280a), SPH_C32(0x49e43f49), + SPH_C32(0x06121806), SPH_C32(0x24fc9024), SPH_C32(0x5c8f6b5c), + SPH_C32(0xc27825c2), SPH_C32(0xd30f61d3), SPH_C32(0xac6986ac), + SPH_C32(0x62359362), SPH_C32(0x91da7291), SPH_C32(0x95c66295), + SPH_C32(0xe48abde4), SPH_C32(0x7974ff79), SPH_C32(0xe783b1e7), + SPH_C32(0xc84e0dc8), SPH_C32(0x3785dc37), SPH_C32(0x6d18af6d), + SPH_C32(0x8d8e028d), SPH_C32(0xd51d79d5), SPH_C32(0x4ef1234e), + SPH_C32(0xa97292a9), SPH_C32(0x6c1fab6c), SPH_C32(0x56b94356), + SPH_C32(0xf4fafdf4), SPH_C32(0xeaa085ea), SPH_C32(0x65208f65), + SPH_C32(0x7a7df37a), SPH_C32(0xae678eae), SPH_C32(0x08382008), + SPH_C32(0xba0bdeba), SPH_C32(0x7873fb78), SPH_C32(0x25fb9425), + SPH_C32(0x2ecab82e), SPH_C32(0x1c54701c), SPH_C32(0xa65faea6), + SPH_C32(0xb421e6b4), SPH_C32(0xc66435c6), SPH_C32(0xe8ae8de8), + SPH_C32(0xdd2559dd), SPH_C32(0x7457cb74), SPH_C32(0x1f5d7c1f), + SPH_C32(0x4bea374b), SPH_C32(0xbd1ec2bd), SPH_C32(0x8b9c1a8b), + SPH_C32(0x8a9b1e8a), SPH_C32(0x704bdb70), SPH_C32(0x3ebaf83e), + SPH_C32(0xb526e2b5), SPH_C32(0x66298366), SPH_C32(0x48e33b48), + SPH_C32(0x03090c03), SPH_C32(0xf6f4f5f6), SPH_C32(0x0e2a380e), + SPH_C32(0x613c9f61), SPH_C32(0x358bd435), SPH_C32(0x57be4757), + SPH_C32(0xb902d2b9), SPH_C32(0x86bf2e86), SPH_C32(0xc17129c1), + SPH_C32(0x1d53741d), SPH_C32(0x9ef74e9e), SPH_C32(0xe191a9e1), + SPH_C32(0xf8decdf8), SPH_C32(0x98e55698), SPH_C32(0x11774411), + SPH_C32(0x6904bf69), SPH_C32(0xd93949d9), SPH_C32(0x8e870e8e), + SPH_C32(0x94c16694), SPH_C32(0x9bec5a9b), SPH_C32(0x1e5a781e), + SPH_C32(0x87b82a87), SPH_C32(0xe9a989e9), SPH_C32(0xce5c15ce), + SPH_C32(0x55b04f55), SPH_C32(0x28d8a028), SPH_C32(0xdf2b51df), + SPH_C32(0x8c89068c), SPH_C32(0xa14ab2a1), SPH_C32(0x89921289), + SPH_C32(0x0d23340d), SPH_C32(0xbf10cabf), SPH_C32(0xe684b5e6), + SPH_C32(0x42d51342), SPH_C32(0x6803bb68), SPH_C32(0x41dc1f41), + SPH_C32(0x99e25299), SPH_C32(0x2dc3b42d), SPH_C32(0x0f2d3c0f), + SPH_C32(0xb03df6b0), SPH_C32(0x54b74b54), SPH_C32(0xbb0cdabb), + SPH_C32(0x16625816) +}; + +#define TIX2(q, x00, x01, x08, x10, x24) do { \ + x10 ^= x00; \ + x00 = (q); \ + x08 ^= x00; \ + x01 ^= x24; \ + } while (0) + +#define TIX3(q, x00, x01, x04, x08, x16, x27, x30) do { \ + x16 ^= x00; \ + x00 = (q); \ + x08 ^= x00; \ + x01 ^= x27; \ + x04 ^= x30; \ + } while (0) + +#define TIX4(q, x00, x01, x04, x07, x08, x22, x24, x27, x30) do { \ + x22 ^= x00; \ + x00 = (q); \ + x08 ^= x00; \ + x01 ^= x24; \ + x04 ^= x27; \ + x07 ^= x30; \ + } while (0) + +#define CMIX30(x00, x01, x02, x04, x05, x06, x15, x16, x17) do { \ + x00 ^= x04; \ + x01 ^= x05; \ + x02 ^= x06; \ + x15 ^= x04; \ + x16 ^= x05; \ + x17 ^= x06; \ + } while (0) + +#define CMIX36(x00, x01, x02, x04, x05, x06, x18, x19, x20) do { \ + x00 ^= x04; \ + x01 ^= x05; \ + x02 ^= x06; \ + x18 ^= x04; \ + x19 ^= x05; \ + x20 ^= x06; \ + } while (0) + +#define SMIX(x0, x1, x2, x3) do { \ + sph_u32 c0 = 0; \ + sph_u32 c1 = 0; \ + sph_u32 c2 = 0; \ + sph_u32 c3 = 0; \ + sph_u32 r0 = 0; \ + sph_u32 r1 = 0; \ + sph_u32 r2 = 0; \ + sph_u32 r3 = 0; \ + sph_u32 tmp; \ + tmp = mixtab0[x0 >> 24]; \ + c0 ^= tmp; \ + tmp = mixtab1[(x0 >> 16) & 0xFF]; \ + c0 ^= tmp; \ + r1 ^= tmp; \ + tmp = mixtab2[(x0 >> 8) & 0xFF]; \ + c0 ^= tmp; \ + r2 ^= tmp; \ + tmp = mixtab3[x0 & 0xFF]; \ + c0 ^= tmp; \ + r3 ^= tmp; \ + tmp = mixtab0[x1 >> 24]; \ + c1 ^= tmp; \ + r0 ^= tmp; \ + tmp = mixtab1[(x1 >> 16) & 0xFF]; \ + c1 ^= tmp; \ + tmp = mixtab2[(x1 >> 8) & 0xFF]; \ + c1 ^= tmp; \ + r2 ^= tmp; \ + tmp = mixtab3[x1 & 0xFF]; \ + c1 ^= tmp; \ + r3 ^= tmp; \ + tmp = mixtab0[x2 >> 24]; \ + c2 ^= tmp; \ + r0 ^= tmp; \ + tmp = mixtab1[(x2 >> 16) & 0xFF]; \ + c2 ^= tmp; \ + r1 ^= tmp; \ + tmp = mixtab2[(x2 >> 8) & 0xFF]; \ + c2 ^= tmp; \ + tmp = mixtab3[x2 & 0xFF]; \ + c2 ^= tmp; \ + r3 ^= tmp; \ + tmp = mixtab0[x3 >> 24]; \ + c3 ^= tmp; \ + r0 ^= tmp; \ + tmp = mixtab1[(x3 >> 16) & 0xFF]; \ + c3 ^= tmp; \ + r1 ^= tmp; \ + tmp = mixtab2[(x3 >> 8) & 0xFF]; \ + c3 ^= tmp; \ + r2 ^= tmp; \ + tmp = mixtab3[x3 & 0xFF]; \ + c3 ^= tmp; \ + x0 = ((c0 ^ r0) & SPH_C32(0xFF000000)) \ + | ((c1 ^ r1) & SPH_C32(0x00FF0000)) \ + | ((c2 ^ r2) & SPH_C32(0x0000FF00)) \ + | ((c3 ^ r3) & SPH_C32(0x000000FF)); \ + x1 = ((c1 ^ (r0 << 8)) & SPH_C32(0xFF000000)) \ + | ((c2 ^ (r1 << 8)) & SPH_C32(0x00FF0000)) \ + | ((c3 ^ (r2 << 8)) & SPH_C32(0x0000FF00)) \ + | ((c0 ^ (r3 >> 24)) & SPH_C32(0x000000FF)); \ + x2 = ((c2 ^ (r0 << 16)) & SPH_C32(0xFF000000)) \ + | ((c3 ^ (r1 << 16)) & SPH_C32(0x00FF0000)) \ + | ((c0 ^ (r2 >> 16)) & SPH_C32(0x0000FF00)) \ + | ((c1 ^ (r3 >> 16)) & SPH_C32(0x000000FF)); \ + x3 = ((c3 ^ (r0 << 24)) & SPH_C32(0xFF000000)) \ + | ((c0 ^ (r1 >> 8)) & SPH_C32(0x00FF0000)) \ + | ((c1 ^ (r2 >> 8)) & SPH_C32(0x0000FF00)) \ + | ((c2 ^ (r3 >> 8)) & SPH_C32(0x000000FF)); \ + /* */ \ + } while (0) + +#if SPH_FUGUE_NOCOPY + +#define DECL_STATE_SMALL +#define READ_STATE_SMALL(state) +#define WRITE_STATE_SMALL(state) +#define DECL_STATE_BIG +#define READ_STATE_BIG(state) +#define WRITE_STATE_BIG(state) + +#define S00 ((sc)->S[ 0]) +#define S01 ((sc)->S[ 1]) +#define S02 ((sc)->S[ 2]) +#define S03 ((sc)->S[ 3]) +#define S04 ((sc)->S[ 4]) +#define S05 ((sc)->S[ 5]) +#define S06 ((sc)->S[ 6]) +#define S07 ((sc)->S[ 7]) +#define S08 ((sc)->S[ 8]) +#define S09 ((sc)->S[ 9]) +#define S10 ((sc)->S[10]) +#define S11 ((sc)->S[11]) +#define S12 ((sc)->S[12]) +#define S13 ((sc)->S[13]) +#define S14 ((sc)->S[14]) +#define S15 ((sc)->S[15]) +#define S16 ((sc)->S[16]) +#define S17 ((sc)->S[17]) +#define S18 ((sc)->S[18]) +#define S19 ((sc)->S[19]) +#define S20 ((sc)->S[20]) +#define S21 ((sc)->S[21]) +#define S22 ((sc)->S[22]) +#define S23 ((sc)->S[23]) +#define S24 ((sc)->S[24]) +#define S25 ((sc)->S[25]) +#define S26 ((sc)->S[26]) +#define S27 ((sc)->S[27]) +#define S28 ((sc)->S[28]) +#define S29 ((sc)->S[29]) +#define S30 ((sc)->S[30]) +#define S31 ((sc)->S[31]) +#define S32 ((sc)->S[32]) +#define S33 ((sc)->S[33]) +#define S34 ((sc)->S[34]) +#define S35 ((sc)->S[35]) + +#else + +#define DECL_STATE_SMALL \ + sph_u32 S00, S01, S02, S03, S04, S05, S06, S07, S08, S09; \ + sph_u32 S10, S11, S12, S13, S14, S15, S16, S17, S18, S19; \ + sph_u32 S20, S21, S22, S23, S24, S25, S26, S27, S28, S29; + +#define DECL_STATE_BIG \ + DECL_STATE_SMALL \ + sph_u32 S30, S31, S32, S33, S34, S35; + +#define READ_STATE_SMALL(state) do { \ + S00 = (state)->S[ 0]; \ + S01 = (state)->S[ 1]; \ + S02 = (state)->S[ 2]; \ + S03 = (state)->S[ 3]; \ + S04 = (state)->S[ 4]; \ + S05 = (state)->S[ 5]; \ + S06 = (state)->S[ 6]; \ + S07 = (state)->S[ 7]; \ + S08 = (state)->S[ 8]; \ + S09 = (state)->S[ 9]; \ + S10 = (state)->S[10]; \ + S11 = (state)->S[11]; \ + S12 = (state)->S[12]; \ + S13 = (state)->S[13]; \ + S14 = (state)->S[14]; \ + S15 = (state)->S[15]; \ + S16 = (state)->S[16]; \ + S17 = (state)->S[17]; \ + S18 = (state)->S[18]; \ + S19 = (state)->S[19]; \ + S20 = (state)->S[20]; \ + S21 = (state)->S[21]; \ + S22 = (state)->S[22]; \ + S23 = (state)->S[23]; \ + S24 = (state)->S[24]; \ + S25 = (state)->S[25]; \ + S26 = (state)->S[26]; \ + S27 = (state)->S[27]; \ + S28 = (state)->S[28]; \ + S29 = (state)->S[29]; \ + } while (0) + +#define READ_STATE_BIG(state) do { \ + READ_STATE_SMALL(state); \ + S30 = (state)->S[30]; \ + S31 = (state)->S[31]; \ + S32 = (state)->S[32]; \ + S33 = (state)->S[33]; \ + S34 = (state)->S[34]; \ + S35 = (state)->S[35]; \ + } while (0) + +#define WRITE_STATE_SMALL(state) do { \ + (state)->S[ 0] = S00; \ + (state)->S[ 1] = S01; \ + (state)->S[ 2] = S02; \ + (state)->S[ 3] = S03; \ + (state)->S[ 4] = S04; \ + (state)->S[ 5] = S05; \ + (state)->S[ 6] = S06; \ + (state)->S[ 7] = S07; \ + (state)->S[ 8] = S08; \ + (state)->S[ 9] = S09; \ + (state)->S[10] = S10; \ + (state)->S[11] = S11; \ + (state)->S[12] = S12; \ + (state)->S[13] = S13; \ + (state)->S[14] = S14; \ + (state)->S[15] = S15; \ + (state)->S[16] = S16; \ + (state)->S[17] = S17; \ + (state)->S[18] = S18; \ + (state)->S[19] = S19; \ + (state)->S[20] = S20; \ + (state)->S[21] = S21; \ + (state)->S[22] = S22; \ + (state)->S[23] = S23; \ + (state)->S[24] = S24; \ + (state)->S[25] = S25; \ + (state)->S[26] = S26; \ + (state)->S[27] = S27; \ + (state)->S[28] = S28; \ + (state)->S[29] = S29; \ + } while (0) + +#define WRITE_STATE_BIG(state) do { \ + WRITE_STATE_SMALL(state); \ + (state)->S[30] = S30; \ + (state)->S[31] = S31; \ + (state)->S[32] = S32; \ + (state)->S[33] = S33; \ + (state)->S[34] = S34; \ + (state)->S[35] = S35; \ + } while (0) + +#endif + +static void +fugue_init(sph_fugue_context *sc, size_t z_len, + const sph_u32 *iv, size_t iv_len) +{ + size_t u; + + for (u = 0; u < z_len; u ++) + sc->S[u] = 0; + memcpy(&sc->S[z_len], iv, iv_len * sizeof *iv); + sc->partial = 0; + sc->partial_len = 0; + sc->round_shift = 0; +#if SPH_64 + sc->bit_count = 0; +#else + sc->bit_count_high = 0; + sc->bit_count_low = 0; +#endif +} + +#if SPH_64 + +#define INCR_COUNTER do { \ + sc->bit_count += (sph_u64)len << 3; \ + } while (0) + +#else + +#define INCR_COUNTER do { \ + sph_u32 tmp = SPH_T32((sph_u32)len << 3); \ + sc->bit_count_low = SPH_T32(sc->bit_count_low + tmp); \ + if (sc->bit_count_low < tmp) \ + sc->bit_count_high ++; \ + sc->bit_count_high = SPH_T32(sc->bit_count_high \ + + ((sph_u32)len >> 29)); \ + } while (0) + +#endif + +#define CORE_ENTRY \ + sph_u32 p; \ + unsigned plen, rshift; \ + INCR_COUNTER; \ + p = sc->partial; \ + plen = sc->partial_len; \ + if (plen < 4) { \ + unsigned count = 4 - plen; \ + if (len < count) \ + count = len; \ + plen += count; \ + while (count -- > 0) { \ + p = (p << 8) | *(const unsigned char *)data; \ + data = (const unsigned char *)data + 1; \ + len --; \ + } \ + if (len == 0) { \ + sc->partial = p; \ + sc->partial_len = plen; \ + return; \ + } \ + } + +#define CORE_EXIT \ + p = 0; \ + sc->partial_len = (unsigned)len; \ + while (len -- > 0) { \ + p = (p << 8) | *(const unsigned char *)data; \ + data = (const unsigned char *)data + 1; \ + } \ + sc->partial = p; \ + sc->round_shift = rshift; + +/* + * Not in a do..while: the 'break' must exit the outer loop. + */ +#define NEXT(rc) \ + if (len <= 4) { \ + rshift = (rc); \ + break; \ + } \ + p = sph_dec32be(data); \ + data = (const unsigned char *)data + 4; \ + len -= 4 + +static void +fugue2_core(sph_fugue_context *sc, const void *data, size_t len) +{ + DECL_STATE_SMALL + CORE_ENTRY + READ_STATE_SMALL(sc); + rshift = sc->round_shift; + switch (rshift) { + for (;;) { + sph_u32 q; + + case 0: + q = p; + TIX2(q, S00, S01, S08, S10, S24); + CMIX30(S27, S28, S29, S01, S02, S03, S12, S13, S14); + SMIX(S27, S28, S29, S00); + CMIX30(S24, S25, S26, S28, S29, S00, S09, S10, S11); + SMIX(S24, S25, S26, S27); + NEXT(1); + /* fall through */ + case 1: + q = p; + TIX2(q, S24, S25, S02, S04, S18); + CMIX30(S21, S22, S23, S25, S26, S27, S06, S07, S08); + SMIX(S21, S22, S23, S24); + CMIX30(S18, S19, S20, S22, S23, S24, S03, S04, S05); + SMIX(S18, S19, S20, S21); + NEXT(2); + /* fall through */ + case 2: + q = p; + TIX2(q, S18, S19, S26, S28, S12); + CMIX30(S15, S16, S17, S19, S20, S21, S00, S01, S02); + SMIX(S15, S16, S17, S18); + CMIX30(S12, S13, S14, S16, S17, S18, S27, S28, S29); + SMIX(S12, S13, S14, S15); + NEXT(3); + /* fall through */ + case 3: + q = p; + TIX2(q, S12, S13, S20, S22, S06); + CMIX30(S09, S10, S11, S13, S14, S15, S24, S25, S26); + SMIX(S09, S10, S11, S12); + CMIX30(S06, S07, S08, S10, S11, S12, S21, S22, S23); + SMIX(S06, S07, S08, S09); + NEXT(4); + /* fall through */ + case 4: + q = p; + TIX2(q, S06, S07, S14, S16, S00); + CMIX30(S03, S04, S05, S07, S08, S09, S18, S19, S20); + SMIX(S03, S04, S05, S06); + CMIX30(S00, S01, S02, S04, S05, S06, S15, S16, S17); + SMIX(S00, S01, S02, S03); + NEXT(0); + } + } + CORE_EXIT + WRITE_STATE_SMALL(sc); +} + +static void +fugue3_core(sph_fugue_context *sc, const void *data, size_t len) +{ + DECL_STATE_BIG + CORE_ENTRY + READ_STATE_BIG(sc); + rshift = sc->round_shift; + switch (rshift) { + for (;;) { + sph_u32 q; + + case 0: + q = p; + TIX3(q, S00, S01, S04, S08, S16, S27, S30); + CMIX36(S33, S34, S35, S01, S02, S03, S15, S16, S17); + SMIX(S33, S34, S35, S00); + CMIX36(S30, S31, S32, S34, S35, S00, S12, S13, S14); + SMIX(S30, S31, S32, S33); + CMIX36(S27, S28, S29, S31, S32, S33, S09, S10, S11); + SMIX(S27, S28, S29, S30); + NEXT(1); + /* fall through */ + case 1: + q = p; + TIX3(q, S27, S28, S31, S35, S07, S18, S21); + CMIX36(S24, S25, S26, S28, S29, S30, S06, S07, S08); + SMIX(S24, S25, S26, S27); + CMIX36(S21, S22, S23, S25, S26, S27, S03, S04, S05); + SMIX(S21, S22, S23, S24); + CMIX36(S18, S19, S20, S22, S23, S24, S00, S01, S02); + SMIX(S18, S19, S20, S21); + NEXT(2); + /* fall through */ + case 2: + q = p; + TIX3(q, S18, S19, S22, S26, S34, S09, S12); + CMIX36(S15, S16, S17, S19, S20, S21, S33, S34, S35); + SMIX(S15, S16, S17, S18); + CMIX36(S12, S13, S14, S16, S17, S18, S30, S31, S32); + SMIX(S12, S13, S14, S15); + CMIX36(S09, S10, S11, S13, S14, S15, S27, S28, S29); + SMIX(S09, S10, S11, S12); + NEXT(3); + /* fall through */ + case 3: + q = p; + TIX3(q, S09, S10, S13, S17, S25, S00, S03); + CMIX36(S06, S07, S08, S10, S11, S12, S24, S25, S26); + SMIX(S06, S07, S08, S09); + CMIX36(S03, S04, S05, S07, S08, S09, S21, S22, S23); + SMIX(S03, S04, S05, S06); + CMIX36(S00, S01, S02, S04, S05, S06, S18, S19, S20); + SMIX(S00, S01, S02, S03); + NEXT(0); + } + } + CORE_EXIT + WRITE_STATE_BIG(sc); +} + +static void +fugue4_core(sph_fugue_context *sc, const void *data, size_t len) +{ + DECL_STATE_BIG + CORE_ENTRY + READ_STATE_BIG(sc); + rshift = sc->round_shift; + switch (rshift) { + for (;;) { + sph_u32 q; + + case 0: + q = p; + TIX4(q, S00, S01, S04, S07, S08, S22, S24, S27, S30); + CMIX36(S33, S34, S35, S01, S02, S03, S15, S16, S17); + SMIX(S33, S34, S35, S00); + CMIX36(S30, S31, S32, S34, S35, S00, S12, S13, S14); + SMIX(S30, S31, S32, S33); + CMIX36(S27, S28, S29, S31, S32, S33, S09, S10, S11); + SMIX(S27, S28, S29, S30); + CMIX36(S24, S25, S26, S28, S29, S30, S06, S07, S08); + SMIX(S24, S25, S26, S27); + NEXT(1); + /* fall through */ + case 1: + q = p; + TIX4(q, S24, S25, S28, S31, S32, S10, S12, S15, S18); + CMIX36(S21, S22, S23, S25, S26, S27, S03, S04, S05); + SMIX(S21, S22, S23, S24); + CMIX36(S18, S19, S20, S22, S23, S24, S00, S01, S02); + SMIX(S18, S19, S20, S21); + CMIX36(S15, S16, S17, S19, S20, S21, S33, S34, S35); + SMIX(S15, S16, S17, S18); + CMIX36(S12, S13, S14, S16, S17, S18, S30, S31, S32); + SMIX(S12, S13, S14, S15); + NEXT(2); + /* fall through */ + case 2: + q = p; + TIX4(q, S12, S13, S16, S19, S20, S34, S00, S03, S06); + CMIX36(S09, S10, S11, S13, S14, S15, S27, S28, S29); + SMIX(S09, S10, S11, S12); + CMIX36(S06, S07, S08, S10, S11, S12, S24, S25, S26); + SMIX(S06, S07, S08, S09); + CMIX36(S03, S04, S05, S07, S08, S09, S21, S22, S23); + SMIX(S03, S04, S05, S06); + CMIX36(S00, S01, S02, S04, S05, S06, S18, S19, S20); + SMIX(S00, S01, S02, S03); + NEXT(0); + } + } + CORE_EXIT + WRITE_STATE_BIG(sc); +} + +#if SPH_64 + +#define WRITE_COUNTER do { \ + sph_enc64be(buf + 4, sc->bit_count + n); \ + } while (0) + +#else + +#define WRITE_COUNTER do { \ + sph_enc32be(buf + 4, sc->bit_count_high); \ + sph_enc32be(buf + 8, sc->bit_count_low + n); \ + } while (0) + +#endif + +#define CLOSE_ENTRY(s, rcm, core) \ + unsigned char buf[16]; \ + unsigned plen, rms; \ + unsigned char *out; \ + sph_u32 S[s]; \ + plen = sc->partial_len; \ + WRITE_COUNTER; \ + if (plen == 0 && n == 0) { \ + plen = 4; \ + } else if (plen < 4 || n != 0) { \ + unsigned u; \ + \ + if (plen == 4) \ + plen = 0; \ + buf[plen] = ub & ~(0xFFU >> n); \ + for (u = plen + 1; u < 4; u ++) \ + buf[u] = 0; \ + } \ + core(sc, buf + plen, (sizeof buf) - plen); \ + rms = sc->round_shift * (rcm); \ + memcpy(S, sc->S + (s) - rms, rms * sizeof(sph_u32)); \ + memcpy(S + rms, sc->S, ((s) - rms) * sizeof(sph_u32)); + +#define ROR(n, s) do { \ + sph_u32 tmp[n]; \ + memcpy(tmp, S + ((s) - (n)), (n) * sizeof(sph_u32)); \ + memmove(S + (n), S, ((s) - (n)) * sizeof(sph_u32)); \ + memcpy(S, tmp, (n) * sizeof(sph_u32)); \ + } while (0) + +static void +fugue2_close(sph_fugue_context *sc, unsigned ub, unsigned n, + void *dst, size_t out_size_w32) +{ + int i; + + CLOSE_ENTRY(30, 6, fugue2_core) + for (i = 0; i < 10; i ++) { + ROR(3, 30); + CMIX30(S[0], S[1], S[2], S[4], S[5], S[6], S[15], S[16], S[17]); + SMIX(S[0], S[1], S[2], S[3]); + } + for (i = 0; i < 13; i ++) { + S[4] ^= S[0]; + S[15] ^= S[0]; + ROR(15, 30); + SMIX(S[0], S[1], S[2], S[3]); + S[4] ^= S[0]; + S[16] ^= S[0]; + ROR(14, 30); + SMIX(S[0], S[1], S[2], S[3]); + } + S[4] ^= S[0]; + S[15] ^= S[0]; + out = dst; + sph_enc32be(out + 0, S[ 1]); + sph_enc32be(out + 4, S[ 2]); + sph_enc32be(out + 8, S[ 3]); + sph_enc32be(out + 12, S[ 4]); + sph_enc32be(out + 16, S[15]); + sph_enc32be(out + 20, S[16]); + sph_enc32be(out + 24, S[17]); + if (out_size_w32 == 8) { + sph_enc32be(out + 28, S[18]); + sph_fugue256_init(sc); + } else { + sph_fugue224_init(sc); + } +} + +static void +fugue3_close(sph_fugue_context *sc, unsigned ub, unsigned n, void *dst) +{ + int i; + + CLOSE_ENTRY(36, 9, fugue3_core) + for (i = 0; i < 18; i ++) { + ROR(3, 36); + CMIX36(S[0], S[1], S[2], S[4], S[5], S[6], S[18], S[19], S[20]); + SMIX(S[0], S[1], S[2], S[3]); + } + for (i = 0; i < 13; i ++) { + S[4] ^= S[0]; + S[12] ^= S[0]; + S[24] ^= S[0]; + ROR(12, 36); + SMIX(S[0], S[1], S[2], S[3]); + S[4] ^= S[0]; + S[13] ^= S[0]; + S[24] ^= S[0]; + ROR(12, 36); + SMIX(S[0], S[1], S[2], S[3]); + S[4] ^= S[0]; + S[13] ^= S[0]; + S[25] ^= S[0]; + ROR(11, 36); + SMIX(S[0], S[1], S[2], S[3]); + } + S[4] ^= S[0]; + S[12] ^= S[0]; + S[24] ^= S[0]; + out = dst; + sph_enc32be(out + 0, S[ 1]); + sph_enc32be(out + 4, S[ 2]); + sph_enc32be(out + 8, S[ 3]); + sph_enc32be(out + 12, S[ 4]); + sph_enc32be(out + 16, S[12]); + sph_enc32be(out + 20, S[13]); + sph_enc32be(out + 24, S[14]); + sph_enc32be(out + 28, S[15]); + sph_enc32be(out + 32, S[24]); + sph_enc32be(out + 36, S[25]); + sph_enc32be(out + 40, S[26]); + sph_enc32be(out + 44, S[27]); + sph_fugue384_init(sc); +} + +static void +fugue4_close(sph_fugue_context *sc, unsigned ub, unsigned n, void *dst) +{ + int i; + + CLOSE_ENTRY(36, 12, fugue4_core) + for (i = 0; i < 32; i ++) { + ROR(3, 36); + CMIX36(S[0], S[1], S[2], S[4], S[5], S[6], S[18], S[19], S[20]); + SMIX(S[0], S[1], S[2], S[3]); + } + for (i = 0; i < 13; i ++) { + S[4] ^= S[0]; + S[9] ^= S[0]; + S[18] ^= S[0]; + S[27] ^= S[0]; + ROR(9, 36); + SMIX(S[0], S[1], S[2], S[3]); + S[4] ^= S[0]; + S[10] ^= S[0]; + S[18] ^= S[0]; + S[27] ^= S[0]; + ROR(9, 36); + SMIX(S[0], S[1], S[2], S[3]); + S[4] ^= S[0]; + S[10] ^= S[0]; + S[19] ^= S[0]; + S[27] ^= S[0]; + ROR(9, 36); + SMIX(S[0], S[1], S[2], S[3]); + S[4] ^= S[0]; + S[10] ^= S[0]; + S[19] ^= S[0]; + S[28] ^= S[0]; + ROR(8, 36); + SMIX(S[0], S[1], S[2], S[3]); + } + S[4] ^= S[0]; + S[9] ^= S[0]; + S[18] ^= S[0]; + S[27] ^= S[0]; + out = dst; + sph_enc32be(out + 0, S[ 1]); + sph_enc32be(out + 4, S[ 2]); + sph_enc32be(out + 8, S[ 3]); + sph_enc32be(out + 12, S[ 4]); + sph_enc32be(out + 16, S[ 9]); + sph_enc32be(out + 20, S[10]); + sph_enc32be(out + 24, S[11]); + sph_enc32be(out + 28, S[12]); + sph_enc32be(out + 32, S[18]); + sph_enc32be(out + 36, S[19]); + sph_enc32be(out + 40, S[20]); + sph_enc32be(out + 44, S[21]); + sph_enc32be(out + 48, S[27]); + sph_enc32be(out + 52, S[28]); + sph_enc32be(out + 56, S[29]); + sph_enc32be(out + 60, S[30]); + sph_fugue512_init(sc); +} + +void +sph_fugue224_init(void *cc) +{ + fugue_init(cc, 23, IV224, 7); +} + +void +sph_fugue224(void *cc, const void *data, size_t len) +{ + fugue2_core(cc, data, len); +} + +void +sph_fugue224_close(void *cc, void *dst) +{ + fugue2_close(cc, 0, 0, dst, 7); +} + +void +sph_fugue224_addbits_and_close(void *cc, unsigned ub, unsigned n, void *dst) +{ + fugue2_close(cc, ub, n, dst, 7); +} + +void +sph_fugue256_init(void *cc) +{ + fugue_init(cc, 22, IV256, 8); +} + +void +sph_fugue256(void *cc, const void *data, size_t len) +{ + fugue2_core(cc, data, len); +} + +void +sph_fugue256_close(void *cc, void *dst) +{ + fugue2_close(cc, 0, 0, dst, 8); +} + +void +sph_fugue256_addbits_and_close(void *cc, unsigned ub, unsigned n, void *dst) +{ + fugue2_close(cc, ub, n, dst, 8); +} + +void +sph_fugue384_init(void *cc) +{ + fugue_init(cc, 24, IV384, 12); +} + +void +sph_fugue384(void *cc, const void *data, size_t len) +{ + fugue3_core(cc, data, len); +} + +void +sph_fugue384_close(void *cc, void *dst) +{ + fugue3_close(cc, 0, 0, dst); +} + +void +sph_fugue384_addbits_and_close(void *cc, unsigned ub, unsigned n, void *dst) +{ + fugue3_close(cc, ub, n, dst); +} + +void +sph_fugue512_init(void *cc) +{ + fugue_init(cc, 20, IV512, 16); +} + +void +sph_fugue512(void *cc, const void *data, size_t len) +{ + fugue4_core(cc, data, len); +} + +void +sph_fugue512_close(void *cc, void *dst) +{ + fugue4_close(cc, 0, 0, dst); +} + +void +sph_fugue512_addbits_and_close(void *cc, unsigned ub, unsigned n, void *dst) +{ + fugue4_close(cc, ub, n, dst); +} +#ifdef __cplusplus +} +#endif diff --git a/src/groestl.c b/src/groestl.c new file mode 100644 index 0000000..928bc41 --- /dev/null +++ b/src/groestl.c @@ -0,0 +1,3123 @@ +/* $Id: groestl.c 260 2011-07-21 01:02:38Z tp $ */ +/* + * Groestl implementation. + * + * ==========================(LICENSE BEGIN)============================ + * + * Copyright (c) 2007-2010 Projet RNRT SAPHIR + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * ===========================(LICENSE END)============================= + * + * @author Thomas Pornin + */ + +#include +#include + +#include "sph_groestl.h" + +#ifdef __cplusplus +extern "C"{ +#endif + +#if SPH_SMALL_FOOTPRINT && !defined SPH_SMALL_FOOTPRINT_GROESTL +#define SPH_SMALL_FOOTPRINT_GROESTL 1 +#endif + +/* + * Apparently, the 32-bit-only version is not faster than the 64-bit + * version unless using the "small footprint" code on a 32-bit machine. + */ +#if !defined SPH_GROESTL_64 +#if SPH_SMALL_FOOTPRINT_GROESTL && !SPH_64_TRUE +#define SPH_GROESTL_64 0 +#else +#define SPH_GROESTL_64 1 +#endif +#endif + +#if !SPH_64 +#undef SPH_GROESTL_64 +#endif + +#ifdef _MSC_VER +#pragma warning (disable: 4146) +#endif + +/* + * The internal representation may use either big-endian or + * little-endian. Using the platform default representation speeds up + * encoding and decoding between bytes and the matrix columns. + */ + +#undef USE_LE +#if SPH_GROESTL_LITTLE_ENDIAN +#define USE_LE 1 +#elif SPH_GROESTL_BIG_ENDIAN +#define USE_LE 0 +#elif SPH_LITTLE_ENDIAN +#define USE_LE 1 +#endif + +#if USE_LE + +#define C32e(x) ((SPH_C32(x) >> 24) \ + | ((SPH_C32(x) >> 8) & SPH_C32(0x0000FF00)) \ + | ((SPH_C32(x) << 8) & SPH_C32(0x00FF0000)) \ + | ((SPH_C32(x) << 24) & SPH_C32(0xFF000000))) +#define dec32e_aligned sph_dec32le_aligned +#define enc32e sph_enc32le +#define B32_0(x) ((x) & 0xFF) +#define B32_1(x) (((x) >> 8) & 0xFF) +#define B32_2(x) (((x) >> 16) & 0xFF) +#define B32_3(x) ((x) >> 24) + +#define R32u(u, d) SPH_T32(((u) << 16) | ((d) >> 16)) +#define R32d(u, d) SPH_T32(((u) >> 16) | ((d) << 16)) + +#define PC32up(j, r) ((sph_u32)((j) + (r))) +#define PC32dn(j, r) 0 +#define QC32up(j, r) SPH_C32(0xFFFFFFFF) +#define QC32dn(j, r) (((sph_u32)(r) << 24) ^ SPH_T32(~((sph_u32)(j) << 24))) + +#if SPH_64 +#define C64e(x) ((SPH_C64(x) >> 56) \ + | ((SPH_C64(x) >> 40) & SPH_C64(0x000000000000FF00)) \ + | ((SPH_C64(x) >> 24) & SPH_C64(0x0000000000FF0000)) \ + | ((SPH_C64(x) >> 8) & SPH_C64(0x00000000FF000000)) \ + | ((SPH_C64(x) << 8) & SPH_C64(0x000000FF00000000)) \ + | ((SPH_C64(x) << 24) & SPH_C64(0x0000FF0000000000)) \ + | ((SPH_C64(x) << 40) & SPH_C64(0x00FF000000000000)) \ + | ((SPH_C64(x) << 56) & SPH_C64(0xFF00000000000000))) +#define dec64e_aligned sph_dec64le_aligned +#define enc64e sph_enc64le +#define B64_0(x) ((x) & 0xFF) +#define B64_1(x) (((x) >> 8) & 0xFF) +#define B64_2(x) (((x) >> 16) & 0xFF) +#define B64_3(x) (((x) >> 24) & 0xFF) +#define B64_4(x) (((x) >> 32) & 0xFF) +#define B64_5(x) (((x) >> 40) & 0xFF) +#define B64_6(x) (((x) >> 48) & 0xFF) +#define B64_7(x) ((x) >> 56) +#define R64 SPH_ROTL64 +#define PC64(j, r) ((sph_u64)((j) + (r))) +#define QC64(j, r) (((sph_u64)(r) << 56) ^ SPH_T64(~((sph_u64)(j) << 56))) +#endif + +#else + +#define C32e(x) SPH_C32(x) +#define dec32e_aligned sph_dec32be_aligned +#define enc32e sph_enc32be +#define B32_0(x) ((x) >> 24) +#define B32_1(x) (((x) >> 16) & 0xFF) +#define B32_2(x) (((x) >> 8) & 0xFF) +#define B32_3(x) ((x) & 0xFF) + +#define R32u(u, d) SPH_T32(((u) >> 16) | ((d) << 16)) +#define R32d(u, d) SPH_T32(((u) << 16) | ((d) >> 16)) + +#define PC32up(j, r) ((sph_u32)((j) + (r)) << 24) +#define PC32dn(j, r) 0 +#define QC32up(j, r) SPH_C32(0xFFFFFFFF) +#define QC32dn(j, r) ((sph_u32)(r) ^ SPH_T32(~(sph_u32)(j))) + +#if SPH_64 +#define C64e(x) SPH_C64(x) +#define dec64e_aligned sph_dec64be_aligned +#define enc64e sph_enc64be +#define B64_0(x) ((x) >> 56) +#define B64_1(x) (((x) >> 48) & 0xFF) +#define B64_2(x) (((x) >> 40) & 0xFF) +#define B64_3(x) (((x) >> 32) & 0xFF) +#define B64_4(x) (((x) >> 24) & 0xFF) +#define B64_5(x) (((x) >> 16) & 0xFF) +#define B64_6(x) (((x) >> 8) & 0xFF) +#define B64_7(x) ((x) & 0xFF) +#define R64 SPH_ROTR64 +#define PC64(j, r) ((sph_u64)((j) + (r)) << 56) +#define QC64(j, r) ((sph_u64)(r) ^ SPH_T64(~(sph_u64)(j))) +#endif + +#endif + +#if SPH_GROESTL_64 + +static const sph_u64 T0[] = { + C64e(0xc632f4a5f497a5c6), C64e(0xf86f978497eb84f8), + C64e(0xee5eb099b0c799ee), C64e(0xf67a8c8d8cf78df6), + C64e(0xffe8170d17e50dff), C64e(0xd60adcbddcb7bdd6), + C64e(0xde16c8b1c8a7b1de), C64e(0x916dfc54fc395491), + C64e(0x6090f050f0c05060), C64e(0x0207050305040302), + C64e(0xce2ee0a9e087a9ce), C64e(0x56d1877d87ac7d56), + C64e(0xe7cc2b192bd519e7), C64e(0xb513a662a67162b5), + C64e(0x4d7c31e6319ae64d), C64e(0xec59b59ab5c39aec), + C64e(0x8f40cf45cf05458f), C64e(0x1fa3bc9dbc3e9d1f), + C64e(0x8949c040c0094089), C64e(0xfa68928792ef87fa), + C64e(0xefd03f153fc515ef), C64e(0xb29426eb267febb2), + C64e(0x8ece40c94007c98e), C64e(0xfbe61d0b1ded0bfb), + C64e(0x416e2fec2f82ec41), C64e(0xb31aa967a97d67b3), + C64e(0x5f431cfd1cbefd5f), C64e(0x456025ea258aea45), + C64e(0x23f9dabfda46bf23), C64e(0x535102f702a6f753), + C64e(0xe445a196a1d396e4), C64e(0x9b76ed5bed2d5b9b), + C64e(0x75285dc25deac275), C64e(0xe1c5241c24d91ce1), + C64e(0x3dd4e9aee97aae3d), C64e(0x4cf2be6abe986a4c), + C64e(0x6c82ee5aeed85a6c), C64e(0x7ebdc341c3fc417e), + C64e(0xf5f3060206f102f5), C64e(0x8352d14fd11d4f83), + C64e(0x688ce45ce4d05c68), C64e(0x515607f407a2f451), + C64e(0xd18d5c345cb934d1), C64e(0xf9e1180818e908f9), + C64e(0xe24cae93aedf93e2), C64e(0xab3e9573954d73ab), + C64e(0x6297f553f5c45362), C64e(0x2a6b413f41543f2a), + C64e(0x081c140c14100c08), C64e(0x9563f652f6315295), + C64e(0x46e9af65af8c6546), C64e(0x9d7fe25ee2215e9d), + C64e(0x3048782878602830), C64e(0x37cff8a1f86ea137), + C64e(0x0a1b110f11140f0a), C64e(0x2febc4b5c45eb52f), + C64e(0x0e151b091b1c090e), C64e(0x247e5a365a483624), + C64e(0x1badb69bb6369b1b), C64e(0xdf98473d47a53ddf), + C64e(0xcda76a266a8126cd), C64e(0x4ef5bb69bb9c694e), + C64e(0x7f334ccd4cfecd7f), C64e(0xea50ba9fbacf9fea), + C64e(0x123f2d1b2d241b12), C64e(0x1da4b99eb93a9e1d), + C64e(0x58c49c749cb07458), C64e(0x3446722e72682e34), + C64e(0x3641772d776c2d36), C64e(0xdc11cdb2cda3b2dc), + C64e(0xb49d29ee2973eeb4), C64e(0x5b4d16fb16b6fb5b), + C64e(0xa4a501f60153f6a4), C64e(0x76a1d74dd7ec4d76), + C64e(0xb714a361a37561b7), C64e(0x7d3449ce49face7d), + C64e(0x52df8d7b8da47b52), C64e(0xdd9f423e42a13edd), + C64e(0x5ecd937193bc715e), C64e(0x13b1a297a2269713), + C64e(0xa6a204f50457f5a6), C64e(0xb901b868b86968b9), + C64e(0x0000000000000000), C64e(0xc1b5742c74992cc1), + C64e(0x40e0a060a0806040), C64e(0xe3c2211f21dd1fe3), + C64e(0x793a43c843f2c879), C64e(0xb69a2ced2c77edb6), + C64e(0xd40dd9bed9b3bed4), C64e(0x8d47ca46ca01468d), + C64e(0x671770d970ced967), C64e(0x72afdd4bdde44b72), + C64e(0x94ed79de7933de94), C64e(0x98ff67d4672bd498), + C64e(0xb09323e8237be8b0), C64e(0x855bde4ade114a85), + C64e(0xbb06bd6bbd6d6bbb), C64e(0xc5bb7e2a7e912ac5), + C64e(0x4f7b34e5349ee54f), C64e(0xedd73a163ac116ed), + C64e(0x86d254c55417c586), C64e(0x9af862d7622fd79a), + C64e(0x6699ff55ffcc5566), C64e(0x11b6a794a7229411), + C64e(0x8ac04acf4a0fcf8a), C64e(0xe9d9301030c910e9), + C64e(0x040e0a060a080604), C64e(0xfe66988198e781fe), + C64e(0xa0ab0bf00b5bf0a0), C64e(0x78b4cc44ccf04478), + C64e(0x25f0d5bad54aba25), C64e(0x4b753ee33e96e34b), + C64e(0xa2ac0ef30e5ff3a2), C64e(0x5d4419fe19bafe5d), + C64e(0x80db5bc05b1bc080), C64e(0x0580858a850a8a05), + C64e(0x3fd3ecadec7ead3f), C64e(0x21fedfbcdf42bc21), + C64e(0x70a8d848d8e04870), C64e(0xf1fd0c040cf904f1), + C64e(0x63197adf7ac6df63), C64e(0x772f58c158eec177), + C64e(0xaf309f759f4575af), C64e(0x42e7a563a5846342), + C64e(0x2070503050403020), C64e(0xe5cb2e1a2ed11ae5), + C64e(0xfdef120e12e10efd), C64e(0xbf08b76db7656dbf), + C64e(0x8155d44cd4194c81), C64e(0x18243c143c301418), + C64e(0x26795f355f4c3526), C64e(0xc3b2712f719d2fc3), + C64e(0xbe8638e13867e1be), C64e(0x35c8fda2fd6aa235), + C64e(0x88c74fcc4f0bcc88), C64e(0x2e654b394b5c392e), + C64e(0x936af957f93d5793), C64e(0x55580df20daaf255), + C64e(0xfc619d829de382fc), C64e(0x7ab3c947c9f4477a), + C64e(0xc827efacef8bacc8), C64e(0xba8832e7326fe7ba), + C64e(0x324f7d2b7d642b32), C64e(0xe642a495a4d795e6), + C64e(0xc03bfba0fb9ba0c0), C64e(0x19aab398b3329819), + C64e(0x9ef668d16827d19e), C64e(0xa322817f815d7fa3), + C64e(0x44eeaa66aa886644), C64e(0x54d6827e82a87e54), + C64e(0x3bdde6abe676ab3b), C64e(0x0b959e839e16830b), + C64e(0x8cc945ca4503ca8c), C64e(0xc7bc7b297b9529c7), + C64e(0x6b056ed36ed6d36b), C64e(0x286c443c44503c28), + C64e(0xa72c8b798b5579a7), C64e(0xbc813de23d63e2bc), + C64e(0x1631271d272c1d16), C64e(0xad379a769a4176ad), + C64e(0xdb964d3b4dad3bdb), C64e(0x649efa56fac85664), + C64e(0x74a6d24ed2e84e74), C64e(0x1436221e22281e14), + C64e(0x92e476db763fdb92), C64e(0x0c121e0a1e180a0c), + C64e(0x48fcb46cb4906c48), C64e(0xb88f37e4376be4b8), + C64e(0x9f78e75de7255d9f), C64e(0xbd0fb26eb2616ebd), + C64e(0x43692aef2a86ef43), C64e(0xc435f1a6f193a6c4), + C64e(0x39dae3a8e372a839), C64e(0x31c6f7a4f762a431), + C64e(0xd38a593759bd37d3), C64e(0xf274868b86ff8bf2), + C64e(0xd583563256b132d5), C64e(0x8b4ec543c50d438b), + C64e(0x6e85eb59ebdc596e), C64e(0xda18c2b7c2afb7da), + C64e(0x018e8f8c8f028c01), C64e(0xb11dac64ac7964b1), + C64e(0x9cf16dd26d23d29c), C64e(0x49723be03b92e049), + C64e(0xd81fc7b4c7abb4d8), C64e(0xacb915fa1543faac), + C64e(0xf3fa090709fd07f3), C64e(0xcfa06f256f8525cf), + C64e(0xca20eaafea8fafca), C64e(0xf47d898e89f38ef4), + C64e(0x476720e9208ee947), C64e(0x1038281828201810), + C64e(0x6f0b64d564ded56f), C64e(0xf073838883fb88f0), + C64e(0x4afbb16fb1946f4a), C64e(0x5cca967296b8725c), + C64e(0x38546c246c702438), C64e(0x575f08f108aef157), + C64e(0x732152c752e6c773), C64e(0x9764f351f3355197), + C64e(0xcbae6523658d23cb), C64e(0xa125847c84597ca1), + C64e(0xe857bf9cbfcb9ce8), C64e(0x3e5d6321637c213e), + C64e(0x96ea7cdd7c37dd96), C64e(0x611e7fdc7fc2dc61), + C64e(0x0d9c9186911a860d), C64e(0x0f9b9485941e850f), + C64e(0xe04bab90abdb90e0), C64e(0x7cbac642c6f8427c), + C64e(0x712657c457e2c471), C64e(0xcc29e5aae583aacc), + C64e(0x90e373d8733bd890), C64e(0x06090f050f0c0506), + C64e(0xf7f4030103f501f7), C64e(0x1c2a36123638121c), + C64e(0xc23cfea3fe9fa3c2), C64e(0x6a8be15fe1d45f6a), + C64e(0xaebe10f91047f9ae), C64e(0x69026bd06bd2d069), + C64e(0x17bfa891a82e9117), C64e(0x9971e858e8295899), + C64e(0x3a5369276974273a), C64e(0x27f7d0b9d04eb927), + C64e(0xd991483848a938d9), C64e(0xebde351335cd13eb), + C64e(0x2be5ceb3ce56b32b), C64e(0x2277553355443322), + C64e(0xd204d6bbd6bfbbd2), C64e(0xa9399070904970a9), + C64e(0x07878089800e8907), C64e(0x33c1f2a7f266a733), + C64e(0x2decc1b6c15ab62d), C64e(0x3c5a66226678223c), + C64e(0x15b8ad92ad2a9215), C64e(0xc9a96020608920c9), + C64e(0x875cdb49db154987), C64e(0xaab01aff1a4fffaa), + C64e(0x50d8887888a07850), C64e(0xa52b8e7a8e517aa5), + C64e(0x03898a8f8a068f03), C64e(0x594a13f813b2f859), + C64e(0x09929b809b128009), C64e(0x1a2339173934171a), + C64e(0x651075da75cada65), C64e(0xd784533153b531d7), + C64e(0x84d551c65113c684), C64e(0xd003d3b8d3bbb8d0), + C64e(0x82dc5ec35e1fc382), C64e(0x29e2cbb0cb52b029), + C64e(0x5ac3997799b4775a), C64e(0x1e2d3311333c111e), + C64e(0x7b3d46cb46f6cb7b), C64e(0xa8b71ffc1f4bfca8), + C64e(0x6d0c61d661dad66d), C64e(0x2c624e3a4e583a2c) +}; + +#if !SPH_SMALL_FOOTPRINT_GROESTL + +static const sph_u64 T1[] = { + C64e(0xc6c632f4a5f497a5), C64e(0xf8f86f978497eb84), + C64e(0xeeee5eb099b0c799), C64e(0xf6f67a8c8d8cf78d), + C64e(0xffffe8170d17e50d), C64e(0xd6d60adcbddcb7bd), + C64e(0xdede16c8b1c8a7b1), C64e(0x91916dfc54fc3954), + C64e(0x606090f050f0c050), C64e(0x0202070503050403), + C64e(0xcece2ee0a9e087a9), C64e(0x5656d1877d87ac7d), + C64e(0xe7e7cc2b192bd519), C64e(0xb5b513a662a67162), + C64e(0x4d4d7c31e6319ae6), C64e(0xecec59b59ab5c39a), + C64e(0x8f8f40cf45cf0545), C64e(0x1f1fa3bc9dbc3e9d), + C64e(0x898949c040c00940), C64e(0xfafa68928792ef87), + C64e(0xefefd03f153fc515), C64e(0xb2b29426eb267feb), + C64e(0x8e8ece40c94007c9), C64e(0xfbfbe61d0b1ded0b), + C64e(0x41416e2fec2f82ec), C64e(0xb3b31aa967a97d67), + C64e(0x5f5f431cfd1cbefd), C64e(0x45456025ea258aea), + C64e(0x2323f9dabfda46bf), C64e(0x53535102f702a6f7), + C64e(0xe4e445a196a1d396), C64e(0x9b9b76ed5bed2d5b), + C64e(0x7575285dc25deac2), C64e(0xe1e1c5241c24d91c), + C64e(0x3d3dd4e9aee97aae), C64e(0x4c4cf2be6abe986a), + C64e(0x6c6c82ee5aeed85a), C64e(0x7e7ebdc341c3fc41), + C64e(0xf5f5f3060206f102), C64e(0x838352d14fd11d4f), + C64e(0x68688ce45ce4d05c), C64e(0x51515607f407a2f4), + C64e(0xd1d18d5c345cb934), C64e(0xf9f9e1180818e908), + C64e(0xe2e24cae93aedf93), C64e(0xabab3e9573954d73), + C64e(0x626297f553f5c453), C64e(0x2a2a6b413f41543f), + C64e(0x08081c140c14100c), C64e(0x959563f652f63152), + C64e(0x4646e9af65af8c65), C64e(0x9d9d7fe25ee2215e), + C64e(0x3030487828786028), C64e(0x3737cff8a1f86ea1), + C64e(0x0a0a1b110f11140f), C64e(0x2f2febc4b5c45eb5), + C64e(0x0e0e151b091b1c09), C64e(0x24247e5a365a4836), + C64e(0x1b1badb69bb6369b), C64e(0xdfdf98473d47a53d), + C64e(0xcdcda76a266a8126), C64e(0x4e4ef5bb69bb9c69), + C64e(0x7f7f334ccd4cfecd), C64e(0xeaea50ba9fbacf9f), + C64e(0x12123f2d1b2d241b), C64e(0x1d1da4b99eb93a9e), + C64e(0x5858c49c749cb074), C64e(0x343446722e72682e), + C64e(0x363641772d776c2d), C64e(0xdcdc11cdb2cda3b2), + C64e(0xb4b49d29ee2973ee), C64e(0x5b5b4d16fb16b6fb), + C64e(0xa4a4a501f60153f6), C64e(0x7676a1d74dd7ec4d), + C64e(0xb7b714a361a37561), C64e(0x7d7d3449ce49face), + C64e(0x5252df8d7b8da47b), C64e(0xdddd9f423e42a13e), + C64e(0x5e5ecd937193bc71), C64e(0x1313b1a297a22697), + C64e(0xa6a6a204f50457f5), C64e(0xb9b901b868b86968), + C64e(0x0000000000000000), C64e(0xc1c1b5742c74992c), + C64e(0x4040e0a060a08060), C64e(0xe3e3c2211f21dd1f), + C64e(0x79793a43c843f2c8), C64e(0xb6b69a2ced2c77ed), + C64e(0xd4d40dd9bed9b3be), C64e(0x8d8d47ca46ca0146), + C64e(0x67671770d970ced9), C64e(0x7272afdd4bdde44b), + C64e(0x9494ed79de7933de), C64e(0x9898ff67d4672bd4), + C64e(0xb0b09323e8237be8), C64e(0x85855bde4ade114a), + C64e(0xbbbb06bd6bbd6d6b), C64e(0xc5c5bb7e2a7e912a), + C64e(0x4f4f7b34e5349ee5), C64e(0xededd73a163ac116), + C64e(0x8686d254c55417c5), C64e(0x9a9af862d7622fd7), + C64e(0x666699ff55ffcc55), C64e(0x1111b6a794a72294), + C64e(0x8a8ac04acf4a0fcf), C64e(0xe9e9d9301030c910), + C64e(0x04040e0a060a0806), C64e(0xfefe66988198e781), + C64e(0xa0a0ab0bf00b5bf0), C64e(0x7878b4cc44ccf044), + C64e(0x2525f0d5bad54aba), C64e(0x4b4b753ee33e96e3), + C64e(0xa2a2ac0ef30e5ff3), C64e(0x5d5d4419fe19bafe), + C64e(0x8080db5bc05b1bc0), C64e(0x050580858a850a8a), + C64e(0x3f3fd3ecadec7ead), C64e(0x2121fedfbcdf42bc), + C64e(0x7070a8d848d8e048), C64e(0xf1f1fd0c040cf904), + C64e(0x6363197adf7ac6df), C64e(0x77772f58c158eec1), + C64e(0xafaf309f759f4575), C64e(0x4242e7a563a58463), + C64e(0x2020705030504030), C64e(0xe5e5cb2e1a2ed11a), + C64e(0xfdfdef120e12e10e), C64e(0xbfbf08b76db7656d), + C64e(0x818155d44cd4194c), C64e(0x1818243c143c3014), + C64e(0x2626795f355f4c35), C64e(0xc3c3b2712f719d2f), + C64e(0xbebe8638e13867e1), C64e(0x3535c8fda2fd6aa2), + C64e(0x8888c74fcc4f0bcc), C64e(0x2e2e654b394b5c39), + C64e(0x93936af957f93d57), C64e(0x5555580df20daaf2), + C64e(0xfcfc619d829de382), C64e(0x7a7ab3c947c9f447), + C64e(0xc8c827efacef8bac), C64e(0xbaba8832e7326fe7), + C64e(0x32324f7d2b7d642b), C64e(0xe6e642a495a4d795), + C64e(0xc0c03bfba0fb9ba0), C64e(0x1919aab398b33298), + C64e(0x9e9ef668d16827d1), C64e(0xa3a322817f815d7f), + C64e(0x4444eeaa66aa8866), C64e(0x5454d6827e82a87e), + C64e(0x3b3bdde6abe676ab), C64e(0x0b0b959e839e1683), + C64e(0x8c8cc945ca4503ca), C64e(0xc7c7bc7b297b9529), + C64e(0x6b6b056ed36ed6d3), C64e(0x28286c443c44503c), + C64e(0xa7a72c8b798b5579), C64e(0xbcbc813de23d63e2), + C64e(0x161631271d272c1d), C64e(0xadad379a769a4176), + C64e(0xdbdb964d3b4dad3b), C64e(0x64649efa56fac856), + C64e(0x7474a6d24ed2e84e), C64e(0x141436221e22281e), + C64e(0x9292e476db763fdb), C64e(0x0c0c121e0a1e180a), + C64e(0x4848fcb46cb4906c), C64e(0xb8b88f37e4376be4), + C64e(0x9f9f78e75de7255d), C64e(0xbdbd0fb26eb2616e), + C64e(0x4343692aef2a86ef), C64e(0xc4c435f1a6f193a6), + C64e(0x3939dae3a8e372a8), C64e(0x3131c6f7a4f762a4), + C64e(0xd3d38a593759bd37), C64e(0xf2f274868b86ff8b), + C64e(0xd5d583563256b132), C64e(0x8b8b4ec543c50d43), + C64e(0x6e6e85eb59ebdc59), C64e(0xdada18c2b7c2afb7), + C64e(0x01018e8f8c8f028c), C64e(0xb1b11dac64ac7964), + C64e(0x9c9cf16dd26d23d2), C64e(0x4949723be03b92e0), + C64e(0xd8d81fc7b4c7abb4), C64e(0xacacb915fa1543fa), + C64e(0xf3f3fa090709fd07), C64e(0xcfcfa06f256f8525), + C64e(0xcaca20eaafea8faf), C64e(0xf4f47d898e89f38e), + C64e(0x47476720e9208ee9), C64e(0x1010382818282018), + C64e(0x6f6f0b64d564ded5), C64e(0xf0f073838883fb88), + C64e(0x4a4afbb16fb1946f), C64e(0x5c5cca967296b872), + C64e(0x3838546c246c7024), C64e(0x57575f08f108aef1), + C64e(0x73732152c752e6c7), C64e(0x979764f351f33551), + C64e(0xcbcbae6523658d23), C64e(0xa1a125847c84597c), + C64e(0xe8e857bf9cbfcb9c), C64e(0x3e3e5d6321637c21), + C64e(0x9696ea7cdd7c37dd), C64e(0x61611e7fdc7fc2dc), + C64e(0x0d0d9c9186911a86), C64e(0x0f0f9b9485941e85), + C64e(0xe0e04bab90abdb90), C64e(0x7c7cbac642c6f842), + C64e(0x71712657c457e2c4), C64e(0xcccc29e5aae583aa), + C64e(0x9090e373d8733bd8), C64e(0x0606090f050f0c05), + C64e(0xf7f7f4030103f501), C64e(0x1c1c2a3612363812), + C64e(0xc2c23cfea3fe9fa3), C64e(0x6a6a8be15fe1d45f), + C64e(0xaeaebe10f91047f9), C64e(0x6969026bd06bd2d0), + C64e(0x1717bfa891a82e91), C64e(0x999971e858e82958), + C64e(0x3a3a536927697427), C64e(0x2727f7d0b9d04eb9), + C64e(0xd9d991483848a938), C64e(0xebebde351335cd13), + C64e(0x2b2be5ceb3ce56b3), C64e(0x2222775533554433), + C64e(0xd2d204d6bbd6bfbb), C64e(0xa9a9399070904970), + C64e(0x0707878089800e89), C64e(0x3333c1f2a7f266a7), + C64e(0x2d2decc1b6c15ab6), C64e(0x3c3c5a6622667822), + C64e(0x1515b8ad92ad2a92), C64e(0xc9c9a96020608920), + C64e(0x87875cdb49db1549), C64e(0xaaaab01aff1a4fff), + C64e(0x5050d8887888a078), C64e(0xa5a52b8e7a8e517a), + C64e(0x0303898a8f8a068f), C64e(0x59594a13f813b2f8), + C64e(0x0909929b809b1280), C64e(0x1a1a233917393417), + C64e(0x65651075da75cada), C64e(0xd7d784533153b531), + C64e(0x8484d551c65113c6), C64e(0xd0d003d3b8d3bbb8), + C64e(0x8282dc5ec35e1fc3), C64e(0x2929e2cbb0cb52b0), + C64e(0x5a5ac3997799b477), C64e(0x1e1e2d3311333c11), + C64e(0x7b7b3d46cb46f6cb), C64e(0xa8a8b71ffc1f4bfc), + C64e(0x6d6d0c61d661dad6), C64e(0x2c2c624e3a4e583a) +}; + +static const sph_u64 T2[] = { + C64e(0xa5c6c632f4a5f497), C64e(0x84f8f86f978497eb), + C64e(0x99eeee5eb099b0c7), C64e(0x8df6f67a8c8d8cf7), + C64e(0x0dffffe8170d17e5), C64e(0xbdd6d60adcbddcb7), + C64e(0xb1dede16c8b1c8a7), C64e(0x5491916dfc54fc39), + C64e(0x50606090f050f0c0), C64e(0x0302020705030504), + C64e(0xa9cece2ee0a9e087), C64e(0x7d5656d1877d87ac), + C64e(0x19e7e7cc2b192bd5), C64e(0x62b5b513a662a671), + C64e(0xe64d4d7c31e6319a), C64e(0x9aecec59b59ab5c3), + C64e(0x458f8f40cf45cf05), C64e(0x9d1f1fa3bc9dbc3e), + C64e(0x40898949c040c009), C64e(0x87fafa68928792ef), + C64e(0x15efefd03f153fc5), C64e(0xebb2b29426eb267f), + C64e(0xc98e8ece40c94007), C64e(0x0bfbfbe61d0b1ded), + C64e(0xec41416e2fec2f82), C64e(0x67b3b31aa967a97d), + C64e(0xfd5f5f431cfd1cbe), C64e(0xea45456025ea258a), + C64e(0xbf2323f9dabfda46), C64e(0xf753535102f702a6), + C64e(0x96e4e445a196a1d3), C64e(0x5b9b9b76ed5bed2d), + C64e(0xc27575285dc25dea), C64e(0x1ce1e1c5241c24d9), + C64e(0xae3d3dd4e9aee97a), C64e(0x6a4c4cf2be6abe98), + C64e(0x5a6c6c82ee5aeed8), C64e(0x417e7ebdc341c3fc), + C64e(0x02f5f5f3060206f1), C64e(0x4f838352d14fd11d), + C64e(0x5c68688ce45ce4d0), C64e(0xf451515607f407a2), + C64e(0x34d1d18d5c345cb9), C64e(0x08f9f9e1180818e9), + C64e(0x93e2e24cae93aedf), C64e(0x73abab3e9573954d), + C64e(0x53626297f553f5c4), C64e(0x3f2a2a6b413f4154), + C64e(0x0c08081c140c1410), C64e(0x52959563f652f631), + C64e(0x654646e9af65af8c), C64e(0x5e9d9d7fe25ee221), + C64e(0x2830304878287860), C64e(0xa13737cff8a1f86e), + C64e(0x0f0a0a1b110f1114), C64e(0xb52f2febc4b5c45e), + C64e(0x090e0e151b091b1c), C64e(0x3624247e5a365a48), + C64e(0x9b1b1badb69bb636), C64e(0x3ddfdf98473d47a5), + C64e(0x26cdcda76a266a81), C64e(0x694e4ef5bb69bb9c), + C64e(0xcd7f7f334ccd4cfe), C64e(0x9feaea50ba9fbacf), + C64e(0x1b12123f2d1b2d24), C64e(0x9e1d1da4b99eb93a), + C64e(0x745858c49c749cb0), C64e(0x2e343446722e7268), + C64e(0x2d363641772d776c), C64e(0xb2dcdc11cdb2cda3), + C64e(0xeeb4b49d29ee2973), C64e(0xfb5b5b4d16fb16b6), + C64e(0xf6a4a4a501f60153), C64e(0x4d7676a1d74dd7ec), + C64e(0x61b7b714a361a375), C64e(0xce7d7d3449ce49fa), + C64e(0x7b5252df8d7b8da4), C64e(0x3edddd9f423e42a1), + C64e(0x715e5ecd937193bc), C64e(0x971313b1a297a226), + C64e(0xf5a6a6a204f50457), C64e(0x68b9b901b868b869), + C64e(0x0000000000000000), C64e(0x2cc1c1b5742c7499), + C64e(0x604040e0a060a080), C64e(0x1fe3e3c2211f21dd), + C64e(0xc879793a43c843f2), C64e(0xedb6b69a2ced2c77), + C64e(0xbed4d40dd9bed9b3), C64e(0x468d8d47ca46ca01), + C64e(0xd967671770d970ce), C64e(0x4b7272afdd4bdde4), + C64e(0xde9494ed79de7933), C64e(0xd49898ff67d4672b), + C64e(0xe8b0b09323e8237b), C64e(0x4a85855bde4ade11), + C64e(0x6bbbbb06bd6bbd6d), C64e(0x2ac5c5bb7e2a7e91), + C64e(0xe54f4f7b34e5349e), C64e(0x16ededd73a163ac1), + C64e(0xc58686d254c55417), C64e(0xd79a9af862d7622f), + C64e(0x55666699ff55ffcc), C64e(0x941111b6a794a722), + C64e(0xcf8a8ac04acf4a0f), C64e(0x10e9e9d9301030c9), + C64e(0x0604040e0a060a08), C64e(0x81fefe66988198e7), + C64e(0xf0a0a0ab0bf00b5b), C64e(0x447878b4cc44ccf0), + C64e(0xba2525f0d5bad54a), C64e(0xe34b4b753ee33e96), + C64e(0xf3a2a2ac0ef30e5f), C64e(0xfe5d5d4419fe19ba), + C64e(0xc08080db5bc05b1b), C64e(0x8a050580858a850a), + C64e(0xad3f3fd3ecadec7e), C64e(0xbc2121fedfbcdf42), + C64e(0x487070a8d848d8e0), C64e(0x04f1f1fd0c040cf9), + C64e(0xdf6363197adf7ac6), C64e(0xc177772f58c158ee), + C64e(0x75afaf309f759f45), C64e(0x634242e7a563a584), + C64e(0x3020207050305040), C64e(0x1ae5e5cb2e1a2ed1), + C64e(0x0efdfdef120e12e1), C64e(0x6dbfbf08b76db765), + C64e(0x4c818155d44cd419), C64e(0x141818243c143c30), + C64e(0x352626795f355f4c), C64e(0x2fc3c3b2712f719d), + C64e(0xe1bebe8638e13867), C64e(0xa23535c8fda2fd6a), + C64e(0xcc8888c74fcc4f0b), C64e(0x392e2e654b394b5c), + C64e(0x5793936af957f93d), C64e(0xf25555580df20daa), + C64e(0x82fcfc619d829de3), C64e(0x477a7ab3c947c9f4), + C64e(0xacc8c827efacef8b), C64e(0xe7baba8832e7326f), + C64e(0x2b32324f7d2b7d64), C64e(0x95e6e642a495a4d7), + C64e(0xa0c0c03bfba0fb9b), C64e(0x981919aab398b332), + C64e(0xd19e9ef668d16827), C64e(0x7fa3a322817f815d), + C64e(0x664444eeaa66aa88), C64e(0x7e5454d6827e82a8), + C64e(0xab3b3bdde6abe676), C64e(0x830b0b959e839e16), + C64e(0xca8c8cc945ca4503), C64e(0x29c7c7bc7b297b95), + C64e(0xd36b6b056ed36ed6), C64e(0x3c28286c443c4450), + C64e(0x79a7a72c8b798b55), C64e(0xe2bcbc813de23d63), + C64e(0x1d161631271d272c), C64e(0x76adad379a769a41), + C64e(0x3bdbdb964d3b4dad), C64e(0x5664649efa56fac8), + C64e(0x4e7474a6d24ed2e8), C64e(0x1e141436221e2228), + C64e(0xdb9292e476db763f), C64e(0x0a0c0c121e0a1e18), + C64e(0x6c4848fcb46cb490), C64e(0xe4b8b88f37e4376b), + C64e(0x5d9f9f78e75de725), C64e(0x6ebdbd0fb26eb261), + C64e(0xef4343692aef2a86), C64e(0xa6c4c435f1a6f193), + C64e(0xa83939dae3a8e372), C64e(0xa43131c6f7a4f762), + C64e(0x37d3d38a593759bd), C64e(0x8bf2f274868b86ff), + C64e(0x32d5d583563256b1), C64e(0x438b8b4ec543c50d), + C64e(0x596e6e85eb59ebdc), C64e(0xb7dada18c2b7c2af), + C64e(0x8c01018e8f8c8f02), C64e(0x64b1b11dac64ac79), + C64e(0xd29c9cf16dd26d23), C64e(0xe04949723be03b92), + C64e(0xb4d8d81fc7b4c7ab), C64e(0xfaacacb915fa1543), + C64e(0x07f3f3fa090709fd), C64e(0x25cfcfa06f256f85), + C64e(0xafcaca20eaafea8f), C64e(0x8ef4f47d898e89f3), + C64e(0xe947476720e9208e), C64e(0x1810103828182820), + C64e(0xd56f6f0b64d564de), C64e(0x88f0f073838883fb), + C64e(0x6f4a4afbb16fb194), C64e(0x725c5cca967296b8), + C64e(0x243838546c246c70), C64e(0xf157575f08f108ae), + C64e(0xc773732152c752e6), C64e(0x51979764f351f335), + C64e(0x23cbcbae6523658d), C64e(0x7ca1a125847c8459), + C64e(0x9ce8e857bf9cbfcb), C64e(0x213e3e5d6321637c), + C64e(0xdd9696ea7cdd7c37), C64e(0xdc61611e7fdc7fc2), + C64e(0x860d0d9c9186911a), C64e(0x850f0f9b9485941e), + C64e(0x90e0e04bab90abdb), C64e(0x427c7cbac642c6f8), + C64e(0xc471712657c457e2), C64e(0xaacccc29e5aae583), + C64e(0xd89090e373d8733b), C64e(0x050606090f050f0c), + C64e(0x01f7f7f4030103f5), C64e(0x121c1c2a36123638), + C64e(0xa3c2c23cfea3fe9f), C64e(0x5f6a6a8be15fe1d4), + C64e(0xf9aeaebe10f91047), C64e(0xd06969026bd06bd2), + C64e(0x911717bfa891a82e), C64e(0x58999971e858e829), + C64e(0x273a3a5369276974), C64e(0xb92727f7d0b9d04e), + C64e(0x38d9d991483848a9), C64e(0x13ebebde351335cd), + C64e(0xb32b2be5ceb3ce56), C64e(0x3322227755335544), + C64e(0xbbd2d204d6bbd6bf), C64e(0x70a9a93990709049), + C64e(0x890707878089800e), C64e(0xa73333c1f2a7f266), + C64e(0xb62d2decc1b6c15a), C64e(0x223c3c5a66226678), + C64e(0x921515b8ad92ad2a), C64e(0x20c9c9a960206089), + C64e(0x4987875cdb49db15), C64e(0xffaaaab01aff1a4f), + C64e(0x785050d8887888a0), C64e(0x7aa5a52b8e7a8e51), + C64e(0x8f0303898a8f8a06), C64e(0xf859594a13f813b2), + C64e(0x800909929b809b12), C64e(0x171a1a2339173934), + C64e(0xda65651075da75ca), C64e(0x31d7d784533153b5), + C64e(0xc68484d551c65113), C64e(0xb8d0d003d3b8d3bb), + C64e(0xc38282dc5ec35e1f), C64e(0xb02929e2cbb0cb52), + C64e(0x775a5ac3997799b4), C64e(0x111e1e2d3311333c), + C64e(0xcb7b7b3d46cb46f6), C64e(0xfca8a8b71ffc1f4b), + C64e(0xd66d6d0c61d661da), C64e(0x3a2c2c624e3a4e58) +}; + +static const sph_u64 T3[] = { + C64e(0x97a5c6c632f4a5f4), C64e(0xeb84f8f86f978497), + C64e(0xc799eeee5eb099b0), C64e(0xf78df6f67a8c8d8c), + C64e(0xe50dffffe8170d17), C64e(0xb7bdd6d60adcbddc), + C64e(0xa7b1dede16c8b1c8), C64e(0x395491916dfc54fc), + C64e(0xc050606090f050f0), C64e(0x0403020207050305), + C64e(0x87a9cece2ee0a9e0), C64e(0xac7d5656d1877d87), + C64e(0xd519e7e7cc2b192b), C64e(0x7162b5b513a662a6), + C64e(0x9ae64d4d7c31e631), C64e(0xc39aecec59b59ab5), + C64e(0x05458f8f40cf45cf), C64e(0x3e9d1f1fa3bc9dbc), + C64e(0x0940898949c040c0), C64e(0xef87fafa68928792), + C64e(0xc515efefd03f153f), C64e(0x7febb2b29426eb26), + C64e(0x07c98e8ece40c940), C64e(0xed0bfbfbe61d0b1d), + C64e(0x82ec41416e2fec2f), C64e(0x7d67b3b31aa967a9), + C64e(0xbefd5f5f431cfd1c), C64e(0x8aea45456025ea25), + C64e(0x46bf2323f9dabfda), C64e(0xa6f753535102f702), + C64e(0xd396e4e445a196a1), C64e(0x2d5b9b9b76ed5bed), + C64e(0xeac27575285dc25d), C64e(0xd91ce1e1c5241c24), + C64e(0x7aae3d3dd4e9aee9), C64e(0x986a4c4cf2be6abe), + C64e(0xd85a6c6c82ee5aee), C64e(0xfc417e7ebdc341c3), + C64e(0xf102f5f5f3060206), C64e(0x1d4f838352d14fd1), + C64e(0xd05c68688ce45ce4), C64e(0xa2f451515607f407), + C64e(0xb934d1d18d5c345c), C64e(0xe908f9f9e1180818), + C64e(0xdf93e2e24cae93ae), C64e(0x4d73abab3e957395), + C64e(0xc453626297f553f5), C64e(0x543f2a2a6b413f41), + C64e(0x100c08081c140c14), C64e(0x3152959563f652f6), + C64e(0x8c654646e9af65af), C64e(0x215e9d9d7fe25ee2), + C64e(0x6028303048782878), C64e(0x6ea13737cff8a1f8), + C64e(0x140f0a0a1b110f11), C64e(0x5eb52f2febc4b5c4), + C64e(0x1c090e0e151b091b), C64e(0x483624247e5a365a), + C64e(0x369b1b1badb69bb6), C64e(0xa53ddfdf98473d47), + C64e(0x8126cdcda76a266a), C64e(0x9c694e4ef5bb69bb), + C64e(0xfecd7f7f334ccd4c), C64e(0xcf9feaea50ba9fba), + C64e(0x241b12123f2d1b2d), C64e(0x3a9e1d1da4b99eb9), + C64e(0xb0745858c49c749c), C64e(0x682e343446722e72), + C64e(0x6c2d363641772d77), C64e(0xa3b2dcdc11cdb2cd), + C64e(0x73eeb4b49d29ee29), C64e(0xb6fb5b5b4d16fb16), + C64e(0x53f6a4a4a501f601), C64e(0xec4d7676a1d74dd7), + C64e(0x7561b7b714a361a3), C64e(0xface7d7d3449ce49), + C64e(0xa47b5252df8d7b8d), C64e(0xa13edddd9f423e42), + C64e(0xbc715e5ecd937193), C64e(0x26971313b1a297a2), + C64e(0x57f5a6a6a204f504), C64e(0x6968b9b901b868b8), + C64e(0x0000000000000000), C64e(0x992cc1c1b5742c74), + C64e(0x80604040e0a060a0), C64e(0xdd1fe3e3c2211f21), + C64e(0xf2c879793a43c843), C64e(0x77edb6b69a2ced2c), + C64e(0xb3bed4d40dd9bed9), C64e(0x01468d8d47ca46ca), + C64e(0xced967671770d970), C64e(0xe44b7272afdd4bdd), + C64e(0x33de9494ed79de79), C64e(0x2bd49898ff67d467), + C64e(0x7be8b0b09323e823), C64e(0x114a85855bde4ade), + C64e(0x6d6bbbbb06bd6bbd), C64e(0x912ac5c5bb7e2a7e), + C64e(0x9ee54f4f7b34e534), C64e(0xc116ededd73a163a), + C64e(0x17c58686d254c554), C64e(0x2fd79a9af862d762), + C64e(0xcc55666699ff55ff), C64e(0x22941111b6a794a7), + C64e(0x0fcf8a8ac04acf4a), C64e(0xc910e9e9d9301030), + C64e(0x080604040e0a060a), C64e(0xe781fefe66988198), + C64e(0x5bf0a0a0ab0bf00b), C64e(0xf0447878b4cc44cc), + C64e(0x4aba2525f0d5bad5), C64e(0x96e34b4b753ee33e), + C64e(0x5ff3a2a2ac0ef30e), C64e(0xbafe5d5d4419fe19), + C64e(0x1bc08080db5bc05b), C64e(0x0a8a050580858a85), + C64e(0x7ead3f3fd3ecadec), C64e(0x42bc2121fedfbcdf), + C64e(0xe0487070a8d848d8), C64e(0xf904f1f1fd0c040c), + C64e(0xc6df6363197adf7a), C64e(0xeec177772f58c158), + C64e(0x4575afaf309f759f), C64e(0x84634242e7a563a5), + C64e(0x4030202070503050), C64e(0xd11ae5e5cb2e1a2e), + C64e(0xe10efdfdef120e12), C64e(0x656dbfbf08b76db7), + C64e(0x194c818155d44cd4), C64e(0x30141818243c143c), + C64e(0x4c352626795f355f), C64e(0x9d2fc3c3b2712f71), + C64e(0x67e1bebe8638e138), C64e(0x6aa23535c8fda2fd), + C64e(0x0bcc8888c74fcc4f), C64e(0x5c392e2e654b394b), + C64e(0x3d5793936af957f9), C64e(0xaaf25555580df20d), + C64e(0xe382fcfc619d829d), C64e(0xf4477a7ab3c947c9), + C64e(0x8bacc8c827efacef), C64e(0x6fe7baba8832e732), + C64e(0x642b32324f7d2b7d), C64e(0xd795e6e642a495a4), + C64e(0x9ba0c0c03bfba0fb), C64e(0x32981919aab398b3), + C64e(0x27d19e9ef668d168), C64e(0x5d7fa3a322817f81), + C64e(0x88664444eeaa66aa), C64e(0xa87e5454d6827e82), + C64e(0x76ab3b3bdde6abe6), C64e(0x16830b0b959e839e), + C64e(0x03ca8c8cc945ca45), C64e(0x9529c7c7bc7b297b), + C64e(0xd6d36b6b056ed36e), C64e(0x503c28286c443c44), + C64e(0x5579a7a72c8b798b), C64e(0x63e2bcbc813de23d), + C64e(0x2c1d161631271d27), C64e(0x4176adad379a769a), + C64e(0xad3bdbdb964d3b4d), C64e(0xc85664649efa56fa), + C64e(0xe84e7474a6d24ed2), C64e(0x281e141436221e22), + C64e(0x3fdb9292e476db76), C64e(0x180a0c0c121e0a1e), + C64e(0x906c4848fcb46cb4), C64e(0x6be4b8b88f37e437), + C64e(0x255d9f9f78e75de7), C64e(0x616ebdbd0fb26eb2), + C64e(0x86ef4343692aef2a), C64e(0x93a6c4c435f1a6f1), + C64e(0x72a83939dae3a8e3), C64e(0x62a43131c6f7a4f7), + C64e(0xbd37d3d38a593759), C64e(0xff8bf2f274868b86), + C64e(0xb132d5d583563256), C64e(0x0d438b8b4ec543c5), + C64e(0xdc596e6e85eb59eb), C64e(0xafb7dada18c2b7c2), + C64e(0x028c01018e8f8c8f), C64e(0x7964b1b11dac64ac), + C64e(0x23d29c9cf16dd26d), C64e(0x92e04949723be03b), + C64e(0xabb4d8d81fc7b4c7), C64e(0x43faacacb915fa15), + C64e(0xfd07f3f3fa090709), C64e(0x8525cfcfa06f256f), + C64e(0x8fafcaca20eaafea), C64e(0xf38ef4f47d898e89), + C64e(0x8ee947476720e920), C64e(0x2018101038281828), + C64e(0xded56f6f0b64d564), C64e(0xfb88f0f073838883), + C64e(0x946f4a4afbb16fb1), C64e(0xb8725c5cca967296), + C64e(0x70243838546c246c), C64e(0xaef157575f08f108), + C64e(0xe6c773732152c752), C64e(0x3551979764f351f3), + C64e(0x8d23cbcbae652365), C64e(0x597ca1a125847c84), + C64e(0xcb9ce8e857bf9cbf), C64e(0x7c213e3e5d632163), + C64e(0x37dd9696ea7cdd7c), C64e(0xc2dc61611e7fdc7f), + C64e(0x1a860d0d9c918691), C64e(0x1e850f0f9b948594), + C64e(0xdb90e0e04bab90ab), C64e(0xf8427c7cbac642c6), + C64e(0xe2c471712657c457), C64e(0x83aacccc29e5aae5), + C64e(0x3bd89090e373d873), C64e(0x0c050606090f050f), + C64e(0xf501f7f7f4030103), C64e(0x38121c1c2a361236), + C64e(0x9fa3c2c23cfea3fe), C64e(0xd45f6a6a8be15fe1), + C64e(0x47f9aeaebe10f910), C64e(0xd2d06969026bd06b), + C64e(0x2e911717bfa891a8), C64e(0x2958999971e858e8), + C64e(0x74273a3a53692769), C64e(0x4eb92727f7d0b9d0), + C64e(0xa938d9d991483848), C64e(0xcd13ebebde351335), + C64e(0x56b32b2be5ceb3ce), C64e(0x4433222277553355), + C64e(0xbfbbd2d204d6bbd6), C64e(0x4970a9a939907090), + C64e(0x0e89070787808980), C64e(0x66a73333c1f2a7f2), + C64e(0x5ab62d2decc1b6c1), C64e(0x78223c3c5a662266), + C64e(0x2a921515b8ad92ad), C64e(0x8920c9c9a9602060), + C64e(0x154987875cdb49db), C64e(0x4fffaaaab01aff1a), + C64e(0xa0785050d8887888), C64e(0x517aa5a52b8e7a8e), + C64e(0x068f0303898a8f8a), C64e(0xb2f859594a13f813), + C64e(0x12800909929b809b), C64e(0x34171a1a23391739), + C64e(0xcada65651075da75), C64e(0xb531d7d784533153), + C64e(0x13c68484d551c651), C64e(0xbbb8d0d003d3b8d3), + C64e(0x1fc38282dc5ec35e), C64e(0x52b02929e2cbb0cb), + C64e(0xb4775a5ac3997799), C64e(0x3c111e1e2d331133), + C64e(0xf6cb7b7b3d46cb46), C64e(0x4bfca8a8b71ffc1f), + C64e(0xdad66d6d0c61d661), C64e(0x583a2c2c624e3a4e) +}; + +#endif + +static const sph_u64 T4[] = { + C64e(0xf497a5c6c632f4a5), C64e(0x97eb84f8f86f9784), + C64e(0xb0c799eeee5eb099), C64e(0x8cf78df6f67a8c8d), + C64e(0x17e50dffffe8170d), C64e(0xdcb7bdd6d60adcbd), + C64e(0xc8a7b1dede16c8b1), C64e(0xfc395491916dfc54), + C64e(0xf0c050606090f050), C64e(0x0504030202070503), + C64e(0xe087a9cece2ee0a9), C64e(0x87ac7d5656d1877d), + C64e(0x2bd519e7e7cc2b19), C64e(0xa67162b5b513a662), + C64e(0x319ae64d4d7c31e6), C64e(0xb5c39aecec59b59a), + C64e(0xcf05458f8f40cf45), C64e(0xbc3e9d1f1fa3bc9d), + C64e(0xc00940898949c040), C64e(0x92ef87fafa689287), + C64e(0x3fc515efefd03f15), C64e(0x267febb2b29426eb), + C64e(0x4007c98e8ece40c9), C64e(0x1ded0bfbfbe61d0b), + C64e(0x2f82ec41416e2fec), C64e(0xa97d67b3b31aa967), + C64e(0x1cbefd5f5f431cfd), C64e(0x258aea45456025ea), + C64e(0xda46bf2323f9dabf), C64e(0x02a6f753535102f7), + C64e(0xa1d396e4e445a196), C64e(0xed2d5b9b9b76ed5b), + C64e(0x5deac27575285dc2), C64e(0x24d91ce1e1c5241c), + C64e(0xe97aae3d3dd4e9ae), C64e(0xbe986a4c4cf2be6a), + C64e(0xeed85a6c6c82ee5a), C64e(0xc3fc417e7ebdc341), + C64e(0x06f102f5f5f30602), C64e(0xd11d4f838352d14f), + C64e(0xe4d05c68688ce45c), C64e(0x07a2f451515607f4), + C64e(0x5cb934d1d18d5c34), C64e(0x18e908f9f9e11808), + C64e(0xaedf93e2e24cae93), C64e(0x954d73abab3e9573), + C64e(0xf5c453626297f553), C64e(0x41543f2a2a6b413f), + C64e(0x14100c08081c140c), C64e(0xf63152959563f652), + C64e(0xaf8c654646e9af65), C64e(0xe2215e9d9d7fe25e), + C64e(0x7860283030487828), C64e(0xf86ea13737cff8a1), + C64e(0x11140f0a0a1b110f), C64e(0xc45eb52f2febc4b5), + C64e(0x1b1c090e0e151b09), C64e(0x5a483624247e5a36), + C64e(0xb6369b1b1badb69b), C64e(0x47a53ddfdf98473d), + C64e(0x6a8126cdcda76a26), C64e(0xbb9c694e4ef5bb69), + C64e(0x4cfecd7f7f334ccd), C64e(0xbacf9feaea50ba9f), + C64e(0x2d241b12123f2d1b), C64e(0xb93a9e1d1da4b99e), + C64e(0x9cb0745858c49c74), C64e(0x72682e343446722e), + C64e(0x776c2d363641772d), C64e(0xcda3b2dcdc11cdb2), + C64e(0x2973eeb4b49d29ee), C64e(0x16b6fb5b5b4d16fb), + C64e(0x0153f6a4a4a501f6), C64e(0xd7ec4d7676a1d74d), + C64e(0xa37561b7b714a361), C64e(0x49face7d7d3449ce), + C64e(0x8da47b5252df8d7b), C64e(0x42a13edddd9f423e), + C64e(0x93bc715e5ecd9371), C64e(0xa226971313b1a297), + C64e(0x0457f5a6a6a204f5), C64e(0xb86968b9b901b868), + C64e(0x0000000000000000), C64e(0x74992cc1c1b5742c), + C64e(0xa080604040e0a060), C64e(0x21dd1fe3e3c2211f), + C64e(0x43f2c879793a43c8), C64e(0x2c77edb6b69a2ced), + C64e(0xd9b3bed4d40dd9be), C64e(0xca01468d8d47ca46), + C64e(0x70ced967671770d9), C64e(0xdde44b7272afdd4b), + C64e(0x7933de9494ed79de), C64e(0x672bd49898ff67d4), + C64e(0x237be8b0b09323e8), C64e(0xde114a85855bde4a), + C64e(0xbd6d6bbbbb06bd6b), C64e(0x7e912ac5c5bb7e2a), + C64e(0x349ee54f4f7b34e5), C64e(0x3ac116ededd73a16), + C64e(0x5417c58686d254c5), C64e(0x622fd79a9af862d7), + C64e(0xffcc55666699ff55), C64e(0xa722941111b6a794), + C64e(0x4a0fcf8a8ac04acf), C64e(0x30c910e9e9d93010), + C64e(0x0a080604040e0a06), C64e(0x98e781fefe669881), + C64e(0x0b5bf0a0a0ab0bf0), C64e(0xccf0447878b4cc44), + C64e(0xd54aba2525f0d5ba), C64e(0x3e96e34b4b753ee3), + C64e(0x0e5ff3a2a2ac0ef3), C64e(0x19bafe5d5d4419fe), + C64e(0x5b1bc08080db5bc0), C64e(0x850a8a050580858a), + C64e(0xec7ead3f3fd3ecad), C64e(0xdf42bc2121fedfbc), + C64e(0xd8e0487070a8d848), C64e(0x0cf904f1f1fd0c04), + C64e(0x7ac6df6363197adf), C64e(0x58eec177772f58c1), + C64e(0x9f4575afaf309f75), C64e(0xa584634242e7a563), + C64e(0x5040302020705030), C64e(0x2ed11ae5e5cb2e1a), + C64e(0x12e10efdfdef120e), C64e(0xb7656dbfbf08b76d), + C64e(0xd4194c818155d44c), C64e(0x3c30141818243c14), + C64e(0x5f4c352626795f35), C64e(0x719d2fc3c3b2712f), + C64e(0x3867e1bebe8638e1), C64e(0xfd6aa23535c8fda2), + C64e(0x4f0bcc8888c74fcc), C64e(0x4b5c392e2e654b39), + C64e(0xf93d5793936af957), C64e(0x0daaf25555580df2), + C64e(0x9de382fcfc619d82), C64e(0xc9f4477a7ab3c947), + C64e(0xef8bacc8c827efac), C64e(0x326fe7baba8832e7), + C64e(0x7d642b32324f7d2b), C64e(0xa4d795e6e642a495), + C64e(0xfb9ba0c0c03bfba0), C64e(0xb332981919aab398), + C64e(0x6827d19e9ef668d1), C64e(0x815d7fa3a322817f), + C64e(0xaa88664444eeaa66), C64e(0x82a87e5454d6827e), + C64e(0xe676ab3b3bdde6ab), C64e(0x9e16830b0b959e83), + C64e(0x4503ca8c8cc945ca), C64e(0x7b9529c7c7bc7b29), + C64e(0x6ed6d36b6b056ed3), C64e(0x44503c28286c443c), + C64e(0x8b5579a7a72c8b79), C64e(0x3d63e2bcbc813de2), + C64e(0x272c1d161631271d), C64e(0x9a4176adad379a76), + C64e(0x4dad3bdbdb964d3b), C64e(0xfac85664649efa56), + C64e(0xd2e84e7474a6d24e), C64e(0x22281e141436221e), + C64e(0x763fdb9292e476db), C64e(0x1e180a0c0c121e0a), + C64e(0xb4906c4848fcb46c), C64e(0x376be4b8b88f37e4), + C64e(0xe7255d9f9f78e75d), C64e(0xb2616ebdbd0fb26e), + C64e(0x2a86ef4343692aef), C64e(0xf193a6c4c435f1a6), + C64e(0xe372a83939dae3a8), C64e(0xf762a43131c6f7a4), + C64e(0x59bd37d3d38a5937), C64e(0x86ff8bf2f274868b), + C64e(0x56b132d5d5835632), C64e(0xc50d438b8b4ec543), + C64e(0xebdc596e6e85eb59), C64e(0xc2afb7dada18c2b7), + C64e(0x8f028c01018e8f8c), C64e(0xac7964b1b11dac64), + C64e(0x6d23d29c9cf16dd2), C64e(0x3b92e04949723be0), + C64e(0xc7abb4d8d81fc7b4), C64e(0x1543faacacb915fa), + C64e(0x09fd07f3f3fa0907), C64e(0x6f8525cfcfa06f25), + C64e(0xea8fafcaca20eaaf), C64e(0x89f38ef4f47d898e), + C64e(0x208ee947476720e9), C64e(0x2820181010382818), + C64e(0x64ded56f6f0b64d5), C64e(0x83fb88f0f0738388), + C64e(0xb1946f4a4afbb16f), C64e(0x96b8725c5cca9672), + C64e(0x6c70243838546c24), C64e(0x08aef157575f08f1), + C64e(0x52e6c773732152c7), C64e(0xf33551979764f351), + C64e(0x658d23cbcbae6523), C64e(0x84597ca1a125847c), + C64e(0xbfcb9ce8e857bf9c), C64e(0x637c213e3e5d6321), + C64e(0x7c37dd9696ea7cdd), C64e(0x7fc2dc61611e7fdc), + C64e(0x911a860d0d9c9186), C64e(0x941e850f0f9b9485), + C64e(0xabdb90e0e04bab90), C64e(0xc6f8427c7cbac642), + C64e(0x57e2c471712657c4), C64e(0xe583aacccc29e5aa), + C64e(0x733bd89090e373d8), C64e(0x0f0c050606090f05), + C64e(0x03f501f7f7f40301), C64e(0x3638121c1c2a3612), + C64e(0xfe9fa3c2c23cfea3), C64e(0xe1d45f6a6a8be15f), + C64e(0x1047f9aeaebe10f9), C64e(0x6bd2d06969026bd0), + C64e(0xa82e911717bfa891), C64e(0xe82958999971e858), + C64e(0x6974273a3a536927), C64e(0xd04eb92727f7d0b9), + C64e(0x48a938d9d9914838), C64e(0x35cd13ebebde3513), + C64e(0xce56b32b2be5ceb3), C64e(0x5544332222775533), + C64e(0xd6bfbbd2d204d6bb), C64e(0x904970a9a9399070), + C64e(0x800e890707878089), C64e(0xf266a73333c1f2a7), + C64e(0xc15ab62d2decc1b6), C64e(0x6678223c3c5a6622), + C64e(0xad2a921515b8ad92), C64e(0x608920c9c9a96020), + C64e(0xdb154987875cdb49), C64e(0x1a4fffaaaab01aff), + C64e(0x88a0785050d88878), C64e(0x8e517aa5a52b8e7a), + C64e(0x8a068f0303898a8f), C64e(0x13b2f859594a13f8), + C64e(0x9b12800909929b80), C64e(0x3934171a1a233917), + C64e(0x75cada65651075da), C64e(0x53b531d7d7845331), + C64e(0x5113c68484d551c6), C64e(0xd3bbb8d0d003d3b8), + C64e(0x5e1fc38282dc5ec3), C64e(0xcb52b02929e2cbb0), + C64e(0x99b4775a5ac39977), C64e(0x333c111e1e2d3311), + C64e(0x46f6cb7b7b3d46cb), C64e(0x1f4bfca8a8b71ffc), + C64e(0x61dad66d6d0c61d6), C64e(0x4e583a2c2c624e3a) +}; + +#if !SPH_SMALL_FOOTPRINT_GROESTL + +static const sph_u64 T5[] = { + C64e(0xa5f497a5c6c632f4), C64e(0x8497eb84f8f86f97), + C64e(0x99b0c799eeee5eb0), C64e(0x8d8cf78df6f67a8c), + C64e(0x0d17e50dffffe817), C64e(0xbddcb7bdd6d60adc), + C64e(0xb1c8a7b1dede16c8), C64e(0x54fc395491916dfc), + C64e(0x50f0c050606090f0), C64e(0x0305040302020705), + C64e(0xa9e087a9cece2ee0), C64e(0x7d87ac7d5656d187), + C64e(0x192bd519e7e7cc2b), C64e(0x62a67162b5b513a6), + C64e(0xe6319ae64d4d7c31), C64e(0x9ab5c39aecec59b5), + C64e(0x45cf05458f8f40cf), C64e(0x9dbc3e9d1f1fa3bc), + C64e(0x40c00940898949c0), C64e(0x8792ef87fafa6892), + C64e(0x153fc515efefd03f), C64e(0xeb267febb2b29426), + C64e(0xc94007c98e8ece40), C64e(0x0b1ded0bfbfbe61d), + C64e(0xec2f82ec41416e2f), C64e(0x67a97d67b3b31aa9), + C64e(0xfd1cbefd5f5f431c), C64e(0xea258aea45456025), + C64e(0xbfda46bf2323f9da), C64e(0xf702a6f753535102), + C64e(0x96a1d396e4e445a1), C64e(0x5bed2d5b9b9b76ed), + C64e(0xc25deac27575285d), C64e(0x1c24d91ce1e1c524), + C64e(0xaee97aae3d3dd4e9), C64e(0x6abe986a4c4cf2be), + C64e(0x5aeed85a6c6c82ee), C64e(0x41c3fc417e7ebdc3), + C64e(0x0206f102f5f5f306), C64e(0x4fd11d4f838352d1), + C64e(0x5ce4d05c68688ce4), C64e(0xf407a2f451515607), + C64e(0x345cb934d1d18d5c), C64e(0x0818e908f9f9e118), + C64e(0x93aedf93e2e24cae), C64e(0x73954d73abab3e95), + C64e(0x53f5c453626297f5), C64e(0x3f41543f2a2a6b41), + C64e(0x0c14100c08081c14), C64e(0x52f63152959563f6), + C64e(0x65af8c654646e9af), C64e(0x5ee2215e9d9d7fe2), + C64e(0x2878602830304878), C64e(0xa1f86ea13737cff8), + C64e(0x0f11140f0a0a1b11), C64e(0xb5c45eb52f2febc4), + C64e(0x091b1c090e0e151b), C64e(0x365a483624247e5a), + C64e(0x9bb6369b1b1badb6), C64e(0x3d47a53ddfdf9847), + C64e(0x266a8126cdcda76a), C64e(0x69bb9c694e4ef5bb), + C64e(0xcd4cfecd7f7f334c), C64e(0x9fbacf9feaea50ba), + C64e(0x1b2d241b12123f2d), C64e(0x9eb93a9e1d1da4b9), + C64e(0x749cb0745858c49c), C64e(0x2e72682e34344672), + C64e(0x2d776c2d36364177), C64e(0xb2cda3b2dcdc11cd), + C64e(0xee2973eeb4b49d29), C64e(0xfb16b6fb5b5b4d16), + C64e(0xf60153f6a4a4a501), C64e(0x4dd7ec4d7676a1d7), + C64e(0x61a37561b7b714a3), C64e(0xce49face7d7d3449), + C64e(0x7b8da47b5252df8d), C64e(0x3e42a13edddd9f42), + C64e(0x7193bc715e5ecd93), C64e(0x97a226971313b1a2), + C64e(0xf50457f5a6a6a204), C64e(0x68b86968b9b901b8), + C64e(0x0000000000000000), C64e(0x2c74992cc1c1b574), + C64e(0x60a080604040e0a0), C64e(0x1f21dd1fe3e3c221), + C64e(0xc843f2c879793a43), C64e(0xed2c77edb6b69a2c), + C64e(0xbed9b3bed4d40dd9), C64e(0x46ca01468d8d47ca), + C64e(0xd970ced967671770), C64e(0x4bdde44b7272afdd), + C64e(0xde7933de9494ed79), C64e(0xd4672bd49898ff67), + C64e(0xe8237be8b0b09323), C64e(0x4ade114a85855bde), + C64e(0x6bbd6d6bbbbb06bd), C64e(0x2a7e912ac5c5bb7e), + C64e(0xe5349ee54f4f7b34), C64e(0x163ac116ededd73a), + C64e(0xc55417c58686d254), C64e(0xd7622fd79a9af862), + C64e(0x55ffcc55666699ff), C64e(0x94a722941111b6a7), + C64e(0xcf4a0fcf8a8ac04a), C64e(0x1030c910e9e9d930), + C64e(0x060a080604040e0a), C64e(0x8198e781fefe6698), + C64e(0xf00b5bf0a0a0ab0b), C64e(0x44ccf0447878b4cc), + C64e(0xbad54aba2525f0d5), C64e(0xe33e96e34b4b753e), + C64e(0xf30e5ff3a2a2ac0e), C64e(0xfe19bafe5d5d4419), + C64e(0xc05b1bc08080db5b), C64e(0x8a850a8a05058085), + C64e(0xadec7ead3f3fd3ec), C64e(0xbcdf42bc2121fedf), + C64e(0x48d8e0487070a8d8), C64e(0x040cf904f1f1fd0c), + C64e(0xdf7ac6df6363197a), C64e(0xc158eec177772f58), + C64e(0x759f4575afaf309f), C64e(0x63a584634242e7a5), + C64e(0x3050403020207050), C64e(0x1a2ed11ae5e5cb2e), + C64e(0x0e12e10efdfdef12), C64e(0x6db7656dbfbf08b7), + C64e(0x4cd4194c818155d4), C64e(0x143c30141818243c), + C64e(0x355f4c352626795f), C64e(0x2f719d2fc3c3b271), + C64e(0xe13867e1bebe8638), C64e(0xa2fd6aa23535c8fd), + C64e(0xcc4f0bcc8888c74f), C64e(0x394b5c392e2e654b), + C64e(0x57f93d5793936af9), C64e(0xf20daaf25555580d), + C64e(0x829de382fcfc619d), C64e(0x47c9f4477a7ab3c9), + C64e(0xacef8bacc8c827ef), C64e(0xe7326fe7baba8832), + C64e(0x2b7d642b32324f7d), C64e(0x95a4d795e6e642a4), + C64e(0xa0fb9ba0c0c03bfb), C64e(0x98b332981919aab3), + C64e(0xd16827d19e9ef668), C64e(0x7f815d7fa3a32281), + C64e(0x66aa88664444eeaa), C64e(0x7e82a87e5454d682), + C64e(0xabe676ab3b3bdde6), C64e(0x839e16830b0b959e), + C64e(0xca4503ca8c8cc945), C64e(0x297b9529c7c7bc7b), + C64e(0xd36ed6d36b6b056e), C64e(0x3c44503c28286c44), + C64e(0x798b5579a7a72c8b), C64e(0xe23d63e2bcbc813d), + C64e(0x1d272c1d16163127), C64e(0x769a4176adad379a), + C64e(0x3b4dad3bdbdb964d), C64e(0x56fac85664649efa), + C64e(0x4ed2e84e7474a6d2), C64e(0x1e22281e14143622), + C64e(0xdb763fdb9292e476), C64e(0x0a1e180a0c0c121e), + C64e(0x6cb4906c4848fcb4), C64e(0xe4376be4b8b88f37), + C64e(0x5de7255d9f9f78e7), C64e(0x6eb2616ebdbd0fb2), + C64e(0xef2a86ef4343692a), C64e(0xa6f193a6c4c435f1), + C64e(0xa8e372a83939dae3), C64e(0xa4f762a43131c6f7), + C64e(0x3759bd37d3d38a59), C64e(0x8b86ff8bf2f27486), + C64e(0x3256b132d5d58356), C64e(0x43c50d438b8b4ec5), + C64e(0x59ebdc596e6e85eb), C64e(0xb7c2afb7dada18c2), + C64e(0x8c8f028c01018e8f), C64e(0x64ac7964b1b11dac), + C64e(0xd26d23d29c9cf16d), C64e(0xe03b92e04949723b), + C64e(0xb4c7abb4d8d81fc7), C64e(0xfa1543faacacb915), + C64e(0x0709fd07f3f3fa09), C64e(0x256f8525cfcfa06f), + C64e(0xafea8fafcaca20ea), C64e(0x8e89f38ef4f47d89), + C64e(0xe9208ee947476720), C64e(0x1828201810103828), + C64e(0xd564ded56f6f0b64), C64e(0x8883fb88f0f07383), + C64e(0x6fb1946f4a4afbb1), C64e(0x7296b8725c5cca96), + C64e(0x246c70243838546c), C64e(0xf108aef157575f08), + C64e(0xc752e6c773732152), C64e(0x51f33551979764f3), + C64e(0x23658d23cbcbae65), C64e(0x7c84597ca1a12584), + C64e(0x9cbfcb9ce8e857bf), C64e(0x21637c213e3e5d63), + C64e(0xdd7c37dd9696ea7c), C64e(0xdc7fc2dc61611e7f), + C64e(0x86911a860d0d9c91), C64e(0x85941e850f0f9b94), + C64e(0x90abdb90e0e04bab), C64e(0x42c6f8427c7cbac6), + C64e(0xc457e2c471712657), C64e(0xaae583aacccc29e5), + C64e(0xd8733bd89090e373), C64e(0x050f0c050606090f), + C64e(0x0103f501f7f7f403), C64e(0x123638121c1c2a36), + C64e(0xa3fe9fa3c2c23cfe), C64e(0x5fe1d45f6a6a8be1), + C64e(0xf91047f9aeaebe10), C64e(0xd06bd2d06969026b), + C64e(0x91a82e911717bfa8), C64e(0x58e82958999971e8), + C64e(0x276974273a3a5369), C64e(0xb9d04eb92727f7d0), + C64e(0x3848a938d9d99148), C64e(0x1335cd13ebebde35), + C64e(0xb3ce56b32b2be5ce), C64e(0x3355443322227755), + C64e(0xbbd6bfbbd2d204d6), C64e(0x70904970a9a93990), + C64e(0x89800e8907078780), C64e(0xa7f266a73333c1f2), + C64e(0xb6c15ab62d2decc1), C64e(0x226678223c3c5a66), + C64e(0x92ad2a921515b8ad), C64e(0x20608920c9c9a960), + C64e(0x49db154987875cdb), C64e(0xff1a4fffaaaab01a), + C64e(0x7888a0785050d888), C64e(0x7a8e517aa5a52b8e), + C64e(0x8f8a068f0303898a), C64e(0xf813b2f859594a13), + C64e(0x809b12800909929b), C64e(0x173934171a1a2339), + C64e(0xda75cada65651075), C64e(0x3153b531d7d78453), + C64e(0xc65113c68484d551), C64e(0xb8d3bbb8d0d003d3), + C64e(0xc35e1fc38282dc5e), C64e(0xb0cb52b02929e2cb), + C64e(0x7799b4775a5ac399), C64e(0x11333c111e1e2d33), + C64e(0xcb46f6cb7b7b3d46), C64e(0xfc1f4bfca8a8b71f), + C64e(0xd661dad66d6d0c61), C64e(0x3a4e583a2c2c624e) +}; + +static const sph_u64 T6[] = { + C64e(0xf4a5f497a5c6c632), C64e(0x978497eb84f8f86f), + C64e(0xb099b0c799eeee5e), C64e(0x8c8d8cf78df6f67a), + C64e(0x170d17e50dffffe8), C64e(0xdcbddcb7bdd6d60a), + C64e(0xc8b1c8a7b1dede16), C64e(0xfc54fc395491916d), + C64e(0xf050f0c050606090), C64e(0x0503050403020207), + C64e(0xe0a9e087a9cece2e), C64e(0x877d87ac7d5656d1), + C64e(0x2b192bd519e7e7cc), C64e(0xa662a67162b5b513), + C64e(0x31e6319ae64d4d7c), C64e(0xb59ab5c39aecec59), + C64e(0xcf45cf05458f8f40), C64e(0xbc9dbc3e9d1f1fa3), + C64e(0xc040c00940898949), C64e(0x928792ef87fafa68), + C64e(0x3f153fc515efefd0), C64e(0x26eb267febb2b294), + C64e(0x40c94007c98e8ece), C64e(0x1d0b1ded0bfbfbe6), + C64e(0x2fec2f82ec41416e), C64e(0xa967a97d67b3b31a), + C64e(0x1cfd1cbefd5f5f43), C64e(0x25ea258aea454560), + C64e(0xdabfda46bf2323f9), C64e(0x02f702a6f7535351), + C64e(0xa196a1d396e4e445), C64e(0xed5bed2d5b9b9b76), + C64e(0x5dc25deac2757528), C64e(0x241c24d91ce1e1c5), + C64e(0xe9aee97aae3d3dd4), C64e(0xbe6abe986a4c4cf2), + C64e(0xee5aeed85a6c6c82), C64e(0xc341c3fc417e7ebd), + C64e(0x060206f102f5f5f3), C64e(0xd14fd11d4f838352), + C64e(0xe45ce4d05c68688c), C64e(0x07f407a2f4515156), + C64e(0x5c345cb934d1d18d), C64e(0x180818e908f9f9e1), + C64e(0xae93aedf93e2e24c), C64e(0x9573954d73abab3e), + C64e(0xf553f5c453626297), C64e(0x413f41543f2a2a6b), + C64e(0x140c14100c08081c), C64e(0xf652f63152959563), + C64e(0xaf65af8c654646e9), C64e(0xe25ee2215e9d9d7f), + C64e(0x7828786028303048), C64e(0xf8a1f86ea13737cf), + C64e(0x110f11140f0a0a1b), C64e(0xc4b5c45eb52f2feb), + C64e(0x1b091b1c090e0e15), C64e(0x5a365a483624247e), + C64e(0xb69bb6369b1b1bad), C64e(0x473d47a53ddfdf98), + C64e(0x6a266a8126cdcda7), C64e(0xbb69bb9c694e4ef5), + C64e(0x4ccd4cfecd7f7f33), C64e(0xba9fbacf9feaea50), + C64e(0x2d1b2d241b12123f), C64e(0xb99eb93a9e1d1da4), + C64e(0x9c749cb0745858c4), C64e(0x722e72682e343446), + C64e(0x772d776c2d363641), C64e(0xcdb2cda3b2dcdc11), + C64e(0x29ee2973eeb4b49d), C64e(0x16fb16b6fb5b5b4d), + C64e(0x01f60153f6a4a4a5), C64e(0xd74dd7ec4d7676a1), + C64e(0xa361a37561b7b714), C64e(0x49ce49face7d7d34), + C64e(0x8d7b8da47b5252df), C64e(0x423e42a13edddd9f), + C64e(0x937193bc715e5ecd), C64e(0xa297a226971313b1), + C64e(0x04f50457f5a6a6a2), C64e(0xb868b86968b9b901), + C64e(0x0000000000000000), C64e(0x742c74992cc1c1b5), + C64e(0xa060a080604040e0), C64e(0x211f21dd1fe3e3c2), + C64e(0x43c843f2c879793a), C64e(0x2ced2c77edb6b69a), + C64e(0xd9bed9b3bed4d40d), C64e(0xca46ca01468d8d47), + C64e(0x70d970ced9676717), C64e(0xdd4bdde44b7272af), + C64e(0x79de7933de9494ed), C64e(0x67d4672bd49898ff), + C64e(0x23e8237be8b0b093), C64e(0xde4ade114a85855b), + C64e(0xbd6bbd6d6bbbbb06), C64e(0x7e2a7e912ac5c5bb), + C64e(0x34e5349ee54f4f7b), C64e(0x3a163ac116ededd7), + C64e(0x54c55417c58686d2), C64e(0x62d7622fd79a9af8), + C64e(0xff55ffcc55666699), C64e(0xa794a722941111b6), + C64e(0x4acf4a0fcf8a8ac0), C64e(0x301030c910e9e9d9), + C64e(0x0a060a080604040e), C64e(0x988198e781fefe66), + C64e(0x0bf00b5bf0a0a0ab), C64e(0xcc44ccf0447878b4), + C64e(0xd5bad54aba2525f0), C64e(0x3ee33e96e34b4b75), + C64e(0x0ef30e5ff3a2a2ac), C64e(0x19fe19bafe5d5d44), + C64e(0x5bc05b1bc08080db), C64e(0x858a850a8a050580), + C64e(0xecadec7ead3f3fd3), C64e(0xdfbcdf42bc2121fe), + C64e(0xd848d8e0487070a8), C64e(0x0c040cf904f1f1fd), + C64e(0x7adf7ac6df636319), C64e(0x58c158eec177772f), + C64e(0x9f759f4575afaf30), C64e(0xa563a584634242e7), + C64e(0x5030504030202070), C64e(0x2e1a2ed11ae5e5cb), + C64e(0x120e12e10efdfdef), C64e(0xb76db7656dbfbf08), + C64e(0xd44cd4194c818155), C64e(0x3c143c3014181824), + C64e(0x5f355f4c35262679), C64e(0x712f719d2fc3c3b2), + C64e(0x38e13867e1bebe86), C64e(0xfda2fd6aa23535c8), + C64e(0x4fcc4f0bcc8888c7), C64e(0x4b394b5c392e2e65), + C64e(0xf957f93d5793936a), C64e(0x0df20daaf2555558), + C64e(0x9d829de382fcfc61), C64e(0xc947c9f4477a7ab3), + C64e(0xefacef8bacc8c827), C64e(0x32e7326fe7baba88), + C64e(0x7d2b7d642b32324f), C64e(0xa495a4d795e6e642), + C64e(0xfba0fb9ba0c0c03b), C64e(0xb398b332981919aa), + C64e(0x68d16827d19e9ef6), C64e(0x817f815d7fa3a322), + C64e(0xaa66aa88664444ee), C64e(0x827e82a87e5454d6), + C64e(0xe6abe676ab3b3bdd), C64e(0x9e839e16830b0b95), + C64e(0x45ca4503ca8c8cc9), C64e(0x7b297b9529c7c7bc), + C64e(0x6ed36ed6d36b6b05), C64e(0x443c44503c28286c), + C64e(0x8b798b5579a7a72c), C64e(0x3de23d63e2bcbc81), + C64e(0x271d272c1d161631), C64e(0x9a769a4176adad37), + C64e(0x4d3b4dad3bdbdb96), C64e(0xfa56fac85664649e), + C64e(0xd24ed2e84e7474a6), C64e(0x221e22281e141436), + C64e(0x76db763fdb9292e4), C64e(0x1e0a1e180a0c0c12), + C64e(0xb46cb4906c4848fc), C64e(0x37e4376be4b8b88f), + C64e(0xe75de7255d9f9f78), C64e(0xb26eb2616ebdbd0f), + C64e(0x2aef2a86ef434369), C64e(0xf1a6f193a6c4c435), + C64e(0xe3a8e372a83939da), C64e(0xf7a4f762a43131c6), + C64e(0x593759bd37d3d38a), C64e(0x868b86ff8bf2f274), + C64e(0x563256b132d5d583), C64e(0xc543c50d438b8b4e), + C64e(0xeb59ebdc596e6e85), C64e(0xc2b7c2afb7dada18), + C64e(0x8f8c8f028c01018e), C64e(0xac64ac7964b1b11d), + C64e(0x6dd26d23d29c9cf1), C64e(0x3be03b92e0494972), + C64e(0xc7b4c7abb4d8d81f), C64e(0x15fa1543faacacb9), + C64e(0x090709fd07f3f3fa), C64e(0x6f256f8525cfcfa0), + C64e(0xeaafea8fafcaca20), C64e(0x898e89f38ef4f47d), + C64e(0x20e9208ee9474767), C64e(0x2818282018101038), + C64e(0x64d564ded56f6f0b), C64e(0x838883fb88f0f073), + C64e(0xb16fb1946f4a4afb), C64e(0x967296b8725c5cca), + C64e(0x6c246c7024383854), C64e(0x08f108aef157575f), + C64e(0x52c752e6c7737321), C64e(0xf351f33551979764), + C64e(0x6523658d23cbcbae), C64e(0x847c84597ca1a125), + C64e(0xbf9cbfcb9ce8e857), C64e(0x6321637c213e3e5d), + C64e(0x7cdd7c37dd9696ea), C64e(0x7fdc7fc2dc61611e), + C64e(0x9186911a860d0d9c), C64e(0x9485941e850f0f9b), + C64e(0xab90abdb90e0e04b), C64e(0xc642c6f8427c7cba), + C64e(0x57c457e2c4717126), C64e(0xe5aae583aacccc29), + C64e(0x73d8733bd89090e3), C64e(0x0f050f0c05060609), + C64e(0x030103f501f7f7f4), C64e(0x36123638121c1c2a), + C64e(0xfea3fe9fa3c2c23c), C64e(0xe15fe1d45f6a6a8b), + C64e(0x10f91047f9aeaebe), C64e(0x6bd06bd2d0696902), + C64e(0xa891a82e911717bf), C64e(0xe858e82958999971), + C64e(0x69276974273a3a53), C64e(0xd0b9d04eb92727f7), + C64e(0x483848a938d9d991), C64e(0x351335cd13ebebde), + C64e(0xceb3ce56b32b2be5), C64e(0x5533554433222277), + C64e(0xd6bbd6bfbbd2d204), C64e(0x9070904970a9a939), + C64e(0x8089800e89070787), C64e(0xf2a7f266a73333c1), + C64e(0xc1b6c15ab62d2dec), C64e(0x66226678223c3c5a), + C64e(0xad92ad2a921515b8), C64e(0x6020608920c9c9a9), + C64e(0xdb49db154987875c), C64e(0x1aff1a4fffaaaab0), + C64e(0x887888a0785050d8), C64e(0x8e7a8e517aa5a52b), + C64e(0x8a8f8a068f030389), C64e(0x13f813b2f859594a), + C64e(0x9b809b1280090992), C64e(0x39173934171a1a23), + C64e(0x75da75cada656510), C64e(0x533153b531d7d784), + C64e(0x51c65113c68484d5), C64e(0xd3b8d3bbb8d0d003), + C64e(0x5ec35e1fc38282dc), C64e(0xcbb0cb52b02929e2), + C64e(0x997799b4775a5ac3), C64e(0x3311333c111e1e2d), + C64e(0x46cb46f6cb7b7b3d), C64e(0x1ffc1f4bfca8a8b7), + C64e(0x61d661dad66d6d0c), C64e(0x4e3a4e583a2c2c62) +}; + +static const sph_u64 T7[] = { + C64e(0x32f4a5f497a5c6c6), C64e(0x6f978497eb84f8f8), + C64e(0x5eb099b0c799eeee), C64e(0x7a8c8d8cf78df6f6), + C64e(0xe8170d17e50dffff), C64e(0x0adcbddcb7bdd6d6), + C64e(0x16c8b1c8a7b1dede), C64e(0x6dfc54fc39549191), + C64e(0x90f050f0c0506060), C64e(0x0705030504030202), + C64e(0x2ee0a9e087a9cece), C64e(0xd1877d87ac7d5656), + C64e(0xcc2b192bd519e7e7), C64e(0x13a662a67162b5b5), + C64e(0x7c31e6319ae64d4d), C64e(0x59b59ab5c39aecec), + C64e(0x40cf45cf05458f8f), C64e(0xa3bc9dbc3e9d1f1f), + C64e(0x49c040c009408989), C64e(0x68928792ef87fafa), + C64e(0xd03f153fc515efef), C64e(0x9426eb267febb2b2), + C64e(0xce40c94007c98e8e), C64e(0xe61d0b1ded0bfbfb), + C64e(0x6e2fec2f82ec4141), C64e(0x1aa967a97d67b3b3), + C64e(0x431cfd1cbefd5f5f), C64e(0x6025ea258aea4545), + C64e(0xf9dabfda46bf2323), C64e(0x5102f702a6f75353), + C64e(0x45a196a1d396e4e4), C64e(0x76ed5bed2d5b9b9b), + C64e(0x285dc25deac27575), C64e(0xc5241c24d91ce1e1), + C64e(0xd4e9aee97aae3d3d), C64e(0xf2be6abe986a4c4c), + C64e(0x82ee5aeed85a6c6c), C64e(0xbdc341c3fc417e7e), + C64e(0xf3060206f102f5f5), C64e(0x52d14fd11d4f8383), + C64e(0x8ce45ce4d05c6868), C64e(0x5607f407a2f45151), + C64e(0x8d5c345cb934d1d1), C64e(0xe1180818e908f9f9), + C64e(0x4cae93aedf93e2e2), C64e(0x3e9573954d73abab), + C64e(0x97f553f5c4536262), C64e(0x6b413f41543f2a2a), + C64e(0x1c140c14100c0808), C64e(0x63f652f631529595), + C64e(0xe9af65af8c654646), C64e(0x7fe25ee2215e9d9d), + C64e(0x4878287860283030), C64e(0xcff8a1f86ea13737), + C64e(0x1b110f11140f0a0a), C64e(0xebc4b5c45eb52f2f), + C64e(0x151b091b1c090e0e), C64e(0x7e5a365a48362424), + C64e(0xadb69bb6369b1b1b), C64e(0x98473d47a53ddfdf), + C64e(0xa76a266a8126cdcd), C64e(0xf5bb69bb9c694e4e), + C64e(0x334ccd4cfecd7f7f), C64e(0x50ba9fbacf9feaea), + C64e(0x3f2d1b2d241b1212), C64e(0xa4b99eb93a9e1d1d), + C64e(0xc49c749cb0745858), C64e(0x46722e72682e3434), + C64e(0x41772d776c2d3636), C64e(0x11cdb2cda3b2dcdc), + C64e(0x9d29ee2973eeb4b4), C64e(0x4d16fb16b6fb5b5b), + C64e(0xa501f60153f6a4a4), C64e(0xa1d74dd7ec4d7676), + C64e(0x14a361a37561b7b7), C64e(0x3449ce49face7d7d), + C64e(0xdf8d7b8da47b5252), C64e(0x9f423e42a13edddd), + C64e(0xcd937193bc715e5e), C64e(0xb1a297a226971313), + C64e(0xa204f50457f5a6a6), C64e(0x01b868b86968b9b9), + C64e(0x0000000000000000), C64e(0xb5742c74992cc1c1), + C64e(0xe0a060a080604040), C64e(0xc2211f21dd1fe3e3), + C64e(0x3a43c843f2c87979), C64e(0x9a2ced2c77edb6b6), + C64e(0x0dd9bed9b3bed4d4), C64e(0x47ca46ca01468d8d), + C64e(0x1770d970ced96767), C64e(0xafdd4bdde44b7272), + C64e(0xed79de7933de9494), C64e(0xff67d4672bd49898), + C64e(0x9323e8237be8b0b0), C64e(0x5bde4ade114a8585), + C64e(0x06bd6bbd6d6bbbbb), C64e(0xbb7e2a7e912ac5c5), + C64e(0x7b34e5349ee54f4f), C64e(0xd73a163ac116eded), + C64e(0xd254c55417c58686), C64e(0xf862d7622fd79a9a), + C64e(0x99ff55ffcc556666), C64e(0xb6a794a722941111), + C64e(0xc04acf4a0fcf8a8a), C64e(0xd9301030c910e9e9), + C64e(0x0e0a060a08060404), C64e(0x66988198e781fefe), + C64e(0xab0bf00b5bf0a0a0), C64e(0xb4cc44ccf0447878), + C64e(0xf0d5bad54aba2525), C64e(0x753ee33e96e34b4b), + C64e(0xac0ef30e5ff3a2a2), C64e(0x4419fe19bafe5d5d), + C64e(0xdb5bc05b1bc08080), C64e(0x80858a850a8a0505), + C64e(0xd3ecadec7ead3f3f), C64e(0xfedfbcdf42bc2121), + C64e(0xa8d848d8e0487070), C64e(0xfd0c040cf904f1f1), + C64e(0x197adf7ac6df6363), C64e(0x2f58c158eec17777), + C64e(0x309f759f4575afaf), C64e(0xe7a563a584634242), + C64e(0x7050305040302020), C64e(0xcb2e1a2ed11ae5e5), + C64e(0xef120e12e10efdfd), C64e(0x08b76db7656dbfbf), + C64e(0x55d44cd4194c8181), C64e(0x243c143c30141818), + C64e(0x795f355f4c352626), C64e(0xb2712f719d2fc3c3), + C64e(0x8638e13867e1bebe), C64e(0xc8fda2fd6aa23535), + C64e(0xc74fcc4f0bcc8888), C64e(0x654b394b5c392e2e), + C64e(0x6af957f93d579393), C64e(0x580df20daaf25555), + C64e(0x619d829de382fcfc), C64e(0xb3c947c9f4477a7a), + C64e(0x27efacef8bacc8c8), C64e(0x8832e7326fe7baba), + C64e(0x4f7d2b7d642b3232), C64e(0x42a495a4d795e6e6), + C64e(0x3bfba0fb9ba0c0c0), C64e(0xaab398b332981919), + C64e(0xf668d16827d19e9e), C64e(0x22817f815d7fa3a3), + C64e(0xeeaa66aa88664444), C64e(0xd6827e82a87e5454), + C64e(0xdde6abe676ab3b3b), C64e(0x959e839e16830b0b), + C64e(0xc945ca4503ca8c8c), C64e(0xbc7b297b9529c7c7), + C64e(0x056ed36ed6d36b6b), C64e(0x6c443c44503c2828), + C64e(0x2c8b798b5579a7a7), C64e(0x813de23d63e2bcbc), + C64e(0x31271d272c1d1616), C64e(0x379a769a4176adad), + C64e(0x964d3b4dad3bdbdb), C64e(0x9efa56fac8566464), + C64e(0xa6d24ed2e84e7474), C64e(0x36221e22281e1414), + C64e(0xe476db763fdb9292), C64e(0x121e0a1e180a0c0c), + C64e(0xfcb46cb4906c4848), C64e(0x8f37e4376be4b8b8), + C64e(0x78e75de7255d9f9f), C64e(0x0fb26eb2616ebdbd), + C64e(0x692aef2a86ef4343), C64e(0x35f1a6f193a6c4c4), + C64e(0xdae3a8e372a83939), C64e(0xc6f7a4f762a43131), + C64e(0x8a593759bd37d3d3), C64e(0x74868b86ff8bf2f2), + C64e(0x83563256b132d5d5), C64e(0x4ec543c50d438b8b), + C64e(0x85eb59ebdc596e6e), C64e(0x18c2b7c2afb7dada), + C64e(0x8e8f8c8f028c0101), C64e(0x1dac64ac7964b1b1), + C64e(0xf16dd26d23d29c9c), C64e(0x723be03b92e04949), + C64e(0x1fc7b4c7abb4d8d8), C64e(0xb915fa1543faacac), + C64e(0xfa090709fd07f3f3), C64e(0xa06f256f8525cfcf), + C64e(0x20eaafea8fafcaca), C64e(0x7d898e89f38ef4f4), + C64e(0x6720e9208ee94747), C64e(0x3828182820181010), + C64e(0x0b64d564ded56f6f), C64e(0x73838883fb88f0f0), + C64e(0xfbb16fb1946f4a4a), C64e(0xca967296b8725c5c), + C64e(0x546c246c70243838), C64e(0x5f08f108aef15757), + C64e(0x2152c752e6c77373), C64e(0x64f351f335519797), + C64e(0xae6523658d23cbcb), C64e(0x25847c84597ca1a1), + C64e(0x57bf9cbfcb9ce8e8), C64e(0x5d6321637c213e3e), + C64e(0xea7cdd7c37dd9696), C64e(0x1e7fdc7fc2dc6161), + C64e(0x9c9186911a860d0d), C64e(0x9b9485941e850f0f), + C64e(0x4bab90abdb90e0e0), C64e(0xbac642c6f8427c7c), + C64e(0x2657c457e2c47171), C64e(0x29e5aae583aacccc), + C64e(0xe373d8733bd89090), C64e(0x090f050f0c050606), + C64e(0xf4030103f501f7f7), C64e(0x2a36123638121c1c), + C64e(0x3cfea3fe9fa3c2c2), C64e(0x8be15fe1d45f6a6a), + C64e(0xbe10f91047f9aeae), C64e(0x026bd06bd2d06969), + C64e(0xbfa891a82e911717), C64e(0x71e858e829589999), + C64e(0x5369276974273a3a), C64e(0xf7d0b9d04eb92727), + C64e(0x91483848a938d9d9), C64e(0xde351335cd13ebeb), + C64e(0xe5ceb3ce56b32b2b), C64e(0x7755335544332222), + C64e(0x04d6bbd6bfbbd2d2), C64e(0x399070904970a9a9), + C64e(0x878089800e890707), C64e(0xc1f2a7f266a73333), + C64e(0xecc1b6c15ab62d2d), C64e(0x5a66226678223c3c), + C64e(0xb8ad92ad2a921515), C64e(0xa96020608920c9c9), + C64e(0x5cdb49db15498787), C64e(0xb01aff1a4fffaaaa), + C64e(0xd8887888a0785050), C64e(0x2b8e7a8e517aa5a5), + C64e(0x898a8f8a068f0303), C64e(0x4a13f813b2f85959), + C64e(0x929b809b12800909), C64e(0x2339173934171a1a), + C64e(0x1075da75cada6565), C64e(0x84533153b531d7d7), + C64e(0xd551c65113c68484), C64e(0x03d3b8d3bbb8d0d0), + C64e(0xdc5ec35e1fc38282), C64e(0xe2cbb0cb52b02929), + C64e(0xc3997799b4775a5a), C64e(0x2d3311333c111e1e), + C64e(0x3d46cb46f6cb7b7b), C64e(0xb71ffc1f4bfca8a8), + C64e(0x0c61d661dad66d6d), C64e(0x624e3a4e583a2c2c) +}; + +#endif + +#define DECL_STATE_SMALL \ + sph_u64 H[8]; + +#define READ_STATE_SMALL(sc) do { \ + memcpy(H, (sc)->state.wide, sizeof H); \ + } while (0) + +#define WRITE_STATE_SMALL(sc) do { \ + memcpy((sc)->state.wide, H, sizeof H); \ + } while (0) + +#if SPH_SMALL_FOOTPRINT_GROESTL + +#define RSTT(d, a, b0, b1, b2, b3, b4, b5, b6, b7) do { \ + t[d] = T0[B64_0(a[b0])] \ + ^ R64(T0[B64_1(a[b1])], 8) \ + ^ R64(T0[B64_2(a[b2])], 16) \ + ^ R64(T0[B64_3(a[b3])], 24) \ + ^ T4[B64_4(a[b4])] \ + ^ R64(T4[B64_5(a[b5])], 8) \ + ^ R64(T4[B64_6(a[b6])], 16) \ + ^ R64(T4[B64_7(a[b7])], 24); \ + } while (0) + +#else + +#define RSTT(d, a, b0, b1, b2, b3, b4, b5, b6, b7) do { \ + t[d] = T0[B64_0(a[b0])] \ + ^ T1[B64_1(a[b1])] \ + ^ T2[B64_2(a[b2])] \ + ^ T3[B64_3(a[b3])] \ + ^ T4[B64_4(a[b4])] \ + ^ T5[B64_5(a[b5])] \ + ^ T6[B64_6(a[b6])] \ + ^ T7[B64_7(a[b7])]; \ + } while (0) + +#endif + +#define ROUND_SMALL_P(a, r) do { \ + sph_u64 t[8]; \ + a[0] ^= PC64(0x00, r); \ + a[1] ^= PC64(0x10, r); \ + a[2] ^= PC64(0x20, r); \ + a[3] ^= PC64(0x30, r); \ + a[4] ^= PC64(0x40, r); \ + a[5] ^= PC64(0x50, r); \ + a[6] ^= PC64(0x60, r); \ + a[7] ^= PC64(0x70, r); \ + RSTT(0, a, 0, 1, 2, 3, 4, 5, 6, 7); \ + RSTT(1, a, 1, 2, 3, 4, 5, 6, 7, 0); \ + RSTT(2, a, 2, 3, 4, 5, 6, 7, 0, 1); \ + RSTT(3, a, 3, 4, 5, 6, 7, 0, 1, 2); \ + RSTT(4, a, 4, 5, 6, 7, 0, 1, 2, 3); \ + RSTT(5, a, 5, 6, 7, 0, 1, 2, 3, 4); \ + RSTT(6, a, 6, 7, 0, 1, 2, 3, 4, 5); \ + RSTT(7, a, 7, 0, 1, 2, 3, 4, 5, 6); \ + a[0] = t[0]; \ + a[1] = t[1]; \ + a[2] = t[2]; \ + a[3] = t[3]; \ + a[4] = t[4]; \ + a[5] = t[5]; \ + a[6] = t[6]; \ + a[7] = t[7]; \ + } while (0) + +#define ROUND_SMALL_Q(a, r) do { \ + sph_u64 t[8]; \ + a[0] ^= QC64(0x00, r); \ + a[1] ^= QC64(0x10, r); \ + a[2] ^= QC64(0x20, r); \ + a[3] ^= QC64(0x30, r); \ + a[4] ^= QC64(0x40, r); \ + a[5] ^= QC64(0x50, r); \ + a[6] ^= QC64(0x60, r); \ + a[7] ^= QC64(0x70, r); \ + RSTT(0, a, 1, 3, 5, 7, 0, 2, 4, 6); \ + RSTT(1, a, 2, 4, 6, 0, 1, 3, 5, 7); \ + RSTT(2, a, 3, 5, 7, 1, 2, 4, 6, 0); \ + RSTT(3, a, 4, 6, 0, 2, 3, 5, 7, 1); \ + RSTT(4, a, 5, 7, 1, 3, 4, 6, 0, 2); \ + RSTT(5, a, 6, 0, 2, 4, 5, 7, 1, 3); \ + RSTT(6, a, 7, 1, 3, 5, 6, 0, 2, 4); \ + RSTT(7, a, 0, 2, 4, 6, 7, 1, 3, 5); \ + a[0] = t[0]; \ + a[1] = t[1]; \ + a[2] = t[2]; \ + a[3] = t[3]; \ + a[4] = t[4]; \ + a[5] = t[5]; \ + a[6] = t[6]; \ + a[7] = t[7]; \ + } while (0) + +#if SPH_SMALL_FOOTPRINT_GROESTL + +#define PERM_SMALL_P(a) do { \ + int r; \ + for (r = 0; r < 10; r ++) \ + ROUND_SMALL_P(a, r); \ + } while (0) + +#define PERM_SMALL_Q(a) do { \ + int r; \ + for (r = 0; r < 10; r ++) \ + ROUND_SMALL_Q(a, r); \ + } while (0) + +#else + +/* + * Apparently, unrolling more than that confuses GCC, resulting in + * lower performance, even though L1 cache would be no problem. + */ +#define PERM_SMALL_P(a) do { \ + int r; \ + for (r = 0; r < 10; r += 2) { \ + ROUND_SMALL_P(a, r + 0); \ + ROUND_SMALL_P(a, r + 1); \ + } \ + } while (0) + +#define PERM_SMALL_Q(a) do { \ + int r; \ + for (r = 0; r < 10; r += 2) { \ + ROUND_SMALL_Q(a, r + 0); \ + ROUND_SMALL_Q(a, r + 1); \ + } \ + } while (0) + +#endif + +#define COMPRESS_SMALL do { \ + sph_u64 g[8], m[8]; \ + size_t u; \ + for (u = 0; u < 8; u ++) { \ + m[u] = dec64e_aligned(buf + (u << 3)); \ + g[u] = m[u] ^ H[u]; \ + } \ + PERM_SMALL_P(g); \ + PERM_SMALL_Q(m); \ + for (u = 0; u < 8; u ++) \ + H[u] ^= g[u] ^ m[u]; \ + } while (0) + +#define FINAL_SMALL do { \ + sph_u64 x[8]; \ + size_t u; \ + memcpy(x, H, sizeof x); \ + PERM_SMALL_P(x); \ + for (u = 0; u < 8; u ++) \ + H[u] ^= x[u]; \ + } while (0) + +#define DECL_STATE_BIG \ + sph_u64 H[16]; + +#define READ_STATE_BIG(sc) do { \ + memcpy(H, (sc)->state.wide, sizeof H); \ + } while (0) + +#define WRITE_STATE_BIG(sc) do { \ + memcpy((sc)->state.wide, H, sizeof H); \ + } while (0) + +#if SPH_SMALL_FOOTPRINT_GROESTL + +#define RBTT(d, a, b0, b1, b2, b3, b4, b5, b6, b7) do { \ + t[d] = T0[B64_0(a[b0])] \ + ^ R64(T0[B64_1(a[b1])], 8) \ + ^ R64(T0[B64_2(a[b2])], 16) \ + ^ R64(T0[B64_3(a[b3])], 24) \ + ^ T4[B64_4(a[b4])] \ + ^ R64(T4[B64_5(a[b5])], 8) \ + ^ R64(T4[B64_6(a[b6])], 16) \ + ^ R64(T4[B64_7(a[b7])], 24); \ + } while (0) + +#else + +#define RBTT(d, a, b0, b1, b2, b3, b4, b5, b6, b7) do { \ + t[d] = T0[B64_0(a[b0])] \ + ^ T1[B64_1(a[b1])] \ + ^ T2[B64_2(a[b2])] \ + ^ T3[B64_3(a[b3])] \ + ^ T4[B64_4(a[b4])] \ + ^ T5[B64_5(a[b5])] \ + ^ T6[B64_6(a[b6])] \ + ^ T7[B64_7(a[b7])]; \ + } while (0) + +#endif + +#if SPH_SMALL_FOOTPRINT_GROESTL + +#define ROUND_BIG_P(a, r) do { \ + sph_u64 t[16]; \ + size_t u; \ + a[0x0] ^= PC64(0x00, r); \ + a[0x1] ^= PC64(0x10, r); \ + a[0x2] ^= PC64(0x20, r); \ + a[0x3] ^= PC64(0x30, r); \ + a[0x4] ^= PC64(0x40, r); \ + a[0x5] ^= PC64(0x50, r); \ + a[0x6] ^= PC64(0x60, r); \ + a[0x7] ^= PC64(0x70, r); \ + a[0x8] ^= PC64(0x80, r); \ + a[0x9] ^= PC64(0x90, r); \ + a[0xA] ^= PC64(0xA0, r); \ + a[0xB] ^= PC64(0xB0, r); \ + a[0xC] ^= PC64(0xC0, r); \ + a[0xD] ^= PC64(0xD0, r); \ + a[0xE] ^= PC64(0xE0, r); \ + a[0xF] ^= PC64(0xF0, r); \ + for (u = 0; u < 16; u += 4) { \ + RBTT(u + 0, a, u + 0, (u + 1) & 0xF, \ + (u + 2) & 0xF, (u + 3) & 0xF, (u + 4) & 0xF, \ + (u + 5) & 0xF, (u + 6) & 0xF, (u + 11) & 0xF); \ + RBTT(u + 1, a, u + 1, (u + 2) & 0xF, \ + (u + 3) & 0xF, (u + 4) & 0xF, (u + 5) & 0xF, \ + (u + 6) & 0xF, (u + 7) & 0xF, (u + 12) & 0xF); \ + RBTT(u + 2, a, u + 2, (u + 3) & 0xF, \ + (u + 4) & 0xF, (u + 5) & 0xF, (u + 6) & 0xF, \ + (u + 7) & 0xF, (u + 8) & 0xF, (u + 13) & 0xF); \ + RBTT(u + 3, a, u + 3, (u + 4) & 0xF, \ + (u + 5) & 0xF, (u + 6) & 0xF, (u + 7) & 0xF, \ + (u + 8) & 0xF, (u + 9) & 0xF, (u + 14) & 0xF); \ + } \ + memcpy(a, t, sizeof t); \ + } while (0) + +#define ROUND_BIG_Q(a, r) do { \ + sph_u64 t[16]; \ + size_t u; \ + a[0x0] ^= QC64(0x00, r); \ + a[0x1] ^= QC64(0x10, r); \ + a[0x2] ^= QC64(0x20, r); \ + a[0x3] ^= QC64(0x30, r); \ + a[0x4] ^= QC64(0x40, r); \ + a[0x5] ^= QC64(0x50, r); \ + a[0x6] ^= QC64(0x60, r); \ + a[0x7] ^= QC64(0x70, r); \ + a[0x8] ^= QC64(0x80, r); \ + a[0x9] ^= QC64(0x90, r); \ + a[0xA] ^= QC64(0xA0, r); \ + a[0xB] ^= QC64(0xB0, r); \ + a[0xC] ^= QC64(0xC0, r); \ + a[0xD] ^= QC64(0xD0, r); \ + a[0xE] ^= QC64(0xE0, r); \ + a[0xF] ^= QC64(0xF0, r); \ + for (u = 0; u < 16; u += 4) { \ + RBTT(u + 0, a, (u + 1) & 0xF, (u + 3) & 0xF, \ + (u + 5) & 0xF, (u + 11) & 0xF, (u + 0) & 0xF, \ + (u + 2) & 0xF, (u + 4) & 0xF, (u + 6) & 0xF); \ + RBTT(u + 1, a, (u + 2) & 0xF, (u + 4) & 0xF, \ + (u + 6) & 0xF, (u + 12) & 0xF, (u + 1) & 0xF, \ + (u + 3) & 0xF, (u + 5) & 0xF, (u + 7) & 0xF); \ + RBTT(u + 2, a, (u + 3) & 0xF, (u + 5) & 0xF, \ + (u + 7) & 0xF, (u + 13) & 0xF, (u + 2) & 0xF, \ + (u + 4) & 0xF, (u + 6) & 0xF, (u + 8) & 0xF); \ + RBTT(u + 3, a, (u + 4) & 0xF, (u + 6) & 0xF, \ + (u + 8) & 0xF, (u + 14) & 0xF, (u + 3) & 0xF, \ + (u + 5) & 0xF, (u + 7) & 0xF, (u + 9) & 0xF); \ + } \ + memcpy(a, t, sizeof t); \ + } while (0) + +#else + +#define ROUND_BIG_P(a, r) do { \ + sph_u64 t[16]; \ + a[0x0] ^= PC64(0x00, r); \ + a[0x1] ^= PC64(0x10, r); \ + a[0x2] ^= PC64(0x20, r); \ + a[0x3] ^= PC64(0x30, r); \ + a[0x4] ^= PC64(0x40, r); \ + a[0x5] ^= PC64(0x50, r); \ + a[0x6] ^= PC64(0x60, r); \ + a[0x7] ^= PC64(0x70, r); \ + a[0x8] ^= PC64(0x80, r); \ + a[0x9] ^= PC64(0x90, r); \ + a[0xA] ^= PC64(0xA0, r); \ + a[0xB] ^= PC64(0xB0, r); \ + a[0xC] ^= PC64(0xC0, r); \ + a[0xD] ^= PC64(0xD0, r); \ + a[0xE] ^= PC64(0xE0, r); \ + a[0xF] ^= PC64(0xF0, r); \ + RBTT(0x0, a, 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0xB); \ + RBTT(0x1, a, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0xC); \ + RBTT(0x2, a, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0xD); \ + RBTT(0x3, a, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xE); \ + RBTT(0x4, a, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xF); \ + RBTT(0x5, a, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0x0); \ + RBTT(0x6, a, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0x1); \ + RBTT(0x7, a, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0x2); \ + RBTT(0x8, a, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0x3); \ + RBTT(0x9, a, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF, 0x4); \ + RBTT(0xA, a, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF, 0x0, 0x5); \ + RBTT(0xB, a, 0xB, 0xC, 0xD, 0xE, 0xF, 0x0, 0x1, 0x6); \ + RBTT(0xC, a, 0xC, 0xD, 0xE, 0xF, 0x0, 0x1, 0x2, 0x7); \ + RBTT(0xD, a, 0xD, 0xE, 0xF, 0x0, 0x1, 0x2, 0x3, 0x8); \ + RBTT(0xE, a, 0xE, 0xF, 0x0, 0x1, 0x2, 0x3, 0x4, 0x9); \ + RBTT(0xF, a, 0xF, 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0xA); \ + a[0x0] = t[0x0]; \ + a[0x1] = t[0x1]; \ + a[0x2] = t[0x2]; \ + a[0x3] = t[0x3]; \ + a[0x4] = t[0x4]; \ + a[0x5] = t[0x5]; \ + a[0x6] = t[0x6]; \ + a[0x7] = t[0x7]; \ + a[0x8] = t[0x8]; \ + a[0x9] = t[0x9]; \ + a[0xA] = t[0xA]; \ + a[0xB] = t[0xB]; \ + a[0xC] = t[0xC]; \ + a[0xD] = t[0xD]; \ + a[0xE] = t[0xE]; \ + a[0xF] = t[0xF]; \ + } while (0) + +#define ROUND_BIG_Q(a, r) do { \ + sph_u64 t[16]; \ + a[0x0] ^= QC64(0x00, r); \ + a[0x1] ^= QC64(0x10, r); \ + a[0x2] ^= QC64(0x20, r); \ + a[0x3] ^= QC64(0x30, r); \ + a[0x4] ^= QC64(0x40, r); \ + a[0x5] ^= QC64(0x50, r); \ + a[0x6] ^= QC64(0x60, r); \ + a[0x7] ^= QC64(0x70, r); \ + a[0x8] ^= QC64(0x80, r); \ + a[0x9] ^= QC64(0x90, r); \ + a[0xA] ^= QC64(0xA0, r); \ + a[0xB] ^= QC64(0xB0, r); \ + a[0xC] ^= QC64(0xC0, r); \ + a[0xD] ^= QC64(0xD0, r); \ + a[0xE] ^= QC64(0xE0, r); \ + a[0xF] ^= QC64(0xF0, r); \ + RBTT(0x0, a, 0x1, 0x3, 0x5, 0xB, 0x0, 0x2, 0x4, 0x6); \ + RBTT(0x1, a, 0x2, 0x4, 0x6, 0xC, 0x1, 0x3, 0x5, 0x7); \ + RBTT(0x2, a, 0x3, 0x5, 0x7, 0xD, 0x2, 0x4, 0x6, 0x8); \ + RBTT(0x3, a, 0x4, 0x6, 0x8, 0xE, 0x3, 0x5, 0x7, 0x9); \ + RBTT(0x4, a, 0x5, 0x7, 0x9, 0xF, 0x4, 0x6, 0x8, 0xA); \ + RBTT(0x5, a, 0x6, 0x8, 0xA, 0x0, 0x5, 0x7, 0x9, 0xB); \ + RBTT(0x6, a, 0x7, 0x9, 0xB, 0x1, 0x6, 0x8, 0xA, 0xC); \ + RBTT(0x7, a, 0x8, 0xA, 0xC, 0x2, 0x7, 0x9, 0xB, 0xD); \ + RBTT(0x8, a, 0x9, 0xB, 0xD, 0x3, 0x8, 0xA, 0xC, 0xE); \ + RBTT(0x9, a, 0xA, 0xC, 0xE, 0x4, 0x9, 0xB, 0xD, 0xF); \ + RBTT(0xA, a, 0xB, 0xD, 0xF, 0x5, 0xA, 0xC, 0xE, 0x0); \ + RBTT(0xB, a, 0xC, 0xE, 0x0, 0x6, 0xB, 0xD, 0xF, 0x1); \ + RBTT(0xC, a, 0xD, 0xF, 0x1, 0x7, 0xC, 0xE, 0x0, 0x2); \ + RBTT(0xD, a, 0xE, 0x0, 0x2, 0x8, 0xD, 0xF, 0x1, 0x3); \ + RBTT(0xE, a, 0xF, 0x1, 0x3, 0x9, 0xE, 0x0, 0x2, 0x4); \ + RBTT(0xF, a, 0x0, 0x2, 0x4, 0xA, 0xF, 0x1, 0x3, 0x5); \ + a[0x0] = t[0x0]; \ + a[0x1] = t[0x1]; \ + a[0x2] = t[0x2]; \ + a[0x3] = t[0x3]; \ + a[0x4] = t[0x4]; \ + a[0x5] = t[0x5]; \ + a[0x6] = t[0x6]; \ + a[0x7] = t[0x7]; \ + a[0x8] = t[0x8]; \ + a[0x9] = t[0x9]; \ + a[0xA] = t[0xA]; \ + a[0xB] = t[0xB]; \ + a[0xC] = t[0xC]; \ + a[0xD] = t[0xD]; \ + a[0xE] = t[0xE]; \ + a[0xF] = t[0xF]; \ + } while (0) + +#endif + +#define PERM_BIG_P(a) do { \ + int r; \ + for (r = 0; r < 14; r += 2) { \ + ROUND_BIG_P(a, r + 0); \ + ROUND_BIG_P(a, r + 1); \ + } \ + } while (0) + +#define PERM_BIG_Q(a) do { \ + int r; \ + for (r = 0; r < 14; r += 2) { \ + ROUND_BIG_Q(a, r + 0); \ + ROUND_BIG_Q(a, r + 1); \ + } \ + } while (0) + +/* obsolete +#if SPH_SMALL_FOOTPRINT_GROESTL + +#define COMPRESS_BIG do { \ + sph_u64 g[16], m[16], *ya; \ + const sph_u64 *yc; \ + size_t u; \ + int i; \ + for (u = 0; u < 16; u ++) { \ + m[u] = dec64e_aligned(buf + (u << 3)); \ + g[u] = m[u] ^ H[u]; \ + } \ + ya = g; \ + yc = CP; \ + for (i = 0; i < 2; i ++) { \ + PERM_BIG(ya, yc); \ + ya = m; \ + yc = CQ; \ + } \ + for (u = 0; u < 16; u ++) { \ + H[u] ^= g[u] ^ m[u]; \ + } \ + } while (0) + +#else +*/ + +#define COMPRESS_BIG do { \ + sph_u64 g[16], m[16]; \ + size_t u; \ + for (u = 0; u < 16; u ++) { \ + m[u] = dec64e_aligned(buf + (u << 3)); \ + g[u] = m[u] ^ H[u]; \ + } \ + PERM_BIG_P(g); \ + PERM_BIG_Q(m); \ + for (u = 0; u < 16; u ++) { \ + H[u] ^= g[u] ^ m[u]; \ + } \ + } while (0) + +/* obsolete +#endif +*/ + +#define FINAL_BIG do { \ + sph_u64 x[16]; \ + size_t u; \ + memcpy(x, H, sizeof x); \ + PERM_BIG_P(x); \ + for (u = 0; u < 16; u ++) \ + H[u] ^= x[u]; \ + } while (0) + +#else + +static const sph_u32 T0up[] = { + C32e(0xc632f4a5), C32e(0xf86f9784), C32e(0xee5eb099), C32e(0xf67a8c8d), + C32e(0xffe8170d), C32e(0xd60adcbd), C32e(0xde16c8b1), C32e(0x916dfc54), + C32e(0x6090f050), C32e(0x02070503), C32e(0xce2ee0a9), C32e(0x56d1877d), + C32e(0xe7cc2b19), C32e(0xb513a662), C32e(0x4d7c31e6), C32e(0xec59b59a), + C32e(0x8f40cf45), C32e(0x1fa3bc9d), C32e(0x8949c040), C32e(0xfa689287), + C32e(0xefd03f15), C32e(0xb29426eb), C32e(0x8ece40c9), C32e(0xfbe61d0b), + C32e(0x416e2fec), C32e(0xb31aa967), C32e(0x5f431cfd), C32e(0x456025ea), + C32e(0x23f9dabf), C32e(0x535102f7), C32e(0xe445a196), C32e(0x9b76ed5b), + C32e(0x75285dc2), C32e(0xe1c5241c), C32e(0x3dd4e9ae), C32e(0x4cf2be6a), + C32e(0x6c82ee5a), C32e(0x7ebdc341), C32e(0xf5f30602), C32e(0x8352d14f), + C32e(0x688ce45c), C32e(0x515607f4), C32e(0xd18d5c34), C32e(0xf9e11808), + C32e(0xe24cae93), C32e(0xab3e9573), C32e(0x6297f553), C32e(0x2a6b413f), + C32e(0x081c140c), C32e(0x9563f652), C32e(0x46e9af65), C32e(0x9d7fe25e), + C32e(0x30487828), C32e(0x37cff8a1), C32e(0x0a1b110f), C32e(0x2febc4b5), + C32e(0x0e151b09), C32e(0x247e5a36), C32e(0x1badb69b), C32e(0xdf98473d), + C32e(0xcda76a26), C32e(0x4ef5bb69), C32e(0x7f334ccd), C32e(0xea50ba9f), + C32e(0x123f2d1b), C32e(0x1da4b99e), C32e(0x58c49c74), C32e(0x3446722e), + C32e(0x3641772d), C32e(0xdc11cdb2), C32e(0xb49d29ee), C32e(0x5b4d16fb), + C32e(0xa4a501f6), C32e(0x76a1d74d), C32e(0xb714a361), C32e(0x7d3449ce), + C32e(0x52df8d7b), C32e(0xdd9f423e), C32e(0x5ecd9371), C32e(0x13b1a297), + C32e(0xa6a204f5), C32e(0xb901b868), C32e(0x00000000), C32e(0xc1b5742c), + C32e(0x40e0a060), C32e(0xe3c2211f), C32e(0x793a43c8), C32e(0xb69a2ced), + C32e(0xd40dd9be), C32e(0x8d47ca46), C32e(0x671770d9), C32e(0x72afdd4b), + C32e(0x94ed79de), C32e(0x98ff67d4), C32e(0xb09323e8), C32e(0x855bde4a), + C32e(0xbb06bd6b), C32e(0xc5bb7e2a), C32e(0x4f7b34e5), C32e(0xedd73a16), + C32e(0x86d254c5), C32e(0x9af862d7), C32e(0x6699ff55), C32e(0x11b6a794), + C32e(0x8ac04acf), C32e(0xe9d93010), C32e(0x040e0a06), C32e(0xfe669881), + C32e(0xa0ab0bf0), C32e(0x78b4cc44), C32e(0x25f0d5ba), C32e(0x4b753ee3), + C32e(0xa2ac0ef3), C32e(0x5d4419fe), C32e(0x80db5bc0), C32e(0x0580858a), + C32e(0x3fd3ecad), C32e(0x21fedfbc), C32e(0x70a8d848), C32e(0xf1fd0c04), + C32e(0x63197adf), C32e(0x772f58c1), C32e(0xaf309f75), C32e(0x42e7a563), + C32e(0x20705030), C32e(0xe5cb2e1a), C32e(0xfdef120e), C32e(0xbf08b76d), + C32e(0x8155d44c), C32e(0x18243c14), C32e(0x26795f35), C32e(0xc3b2712f), + C32e(0xbe8638e1), C32e(0x35c8fda2), C32e(0x88c74fcc), C32e(0x2e654b39), + C32e(0x936af957), C32e(0x55580df2), C32e(0xfc619d82), C32e(0x7ab3c947), + C32e(0xc827efac), C32e(0xba8832e7), C32e(0x324f7d2b), C32e(0xe642a495), + C32e(0xc03bfba0), C32e(0x19aab398), C32e(0x9ef668d1), C32e(0xa322817f), + C32e(0x44eeaa66), C32e(0x54d6827e), C32e(0x3bdde6ab), C32e(0x0b959e83), + C32e(0x8cc945ca), C32e(0xc7bc7b29), C32e(0x6b056ed3), C32e(0x286c443c), + C32e(0xa72c8b79), C32e(0xbc813de2), C32e(0x1631271d), C32e(0xad379a76), + C32e(0xdb964d3b), C32e(0x649efa56), C32e(0x74a6d24e), C32e(0x1436221e), + C32e(0x92e476db), C32e(0x0c121e0a), C32e(0x48fcb46c), C32e(0xb88f37e4), + C32e(0x9f78e75d), C32e(0xbd0fb26e), C32e(0x43692aef), C32e(0xc435f1a6), + C32e(0x39dae3a8), C32e(0x31c6f7a4), C32e(0xd38a5937), C32e(0xf274868b), + C32e(0xd5835632), C32e(0x8b4ec543), C32e(0x6e85eb59), C32e(0xda18c2b7), + C32e(0x018e8f8c), C32e(0xb11dac64), C32e(0x9cf16dd2), C32e(0x49723be0), + C32e(0xd81fc7b4), C32e(0xacb915fa), C32e(0xf3fa0907), C32e(0xcfa06f25), + C32e(0xca20eaaf), C32e(0xf47d898e), C32e(0x476720e9), C32e(0x10382818), + C32e(0x6f0b64d5), C32e(0xf0738388), C32e(0x4afbb16f), C32e(0x5cca9672), + C32e(0x38546c24), C32e(0x575f08f1), C32e(0x732152c7), C32e(0x9764f351), + C32e(0xcbae6523), C32e(0xa125847c), C32e(0xe857bf9c), C32e(0x3e5d6321), + C32e(0x96ea7cdd), C32e(0x611e7fdc), C32e(0x0d9c9186), C32e(0x0f9b9485), + C32e(0xe04bab90), C32e(0x7cbac642), C32e(0x712657c4), C32e(0xcc29e5aa), + C32e(0x90e373d8), C32e(0x06090f05), C32e(0xf7f40301), C32e(0x1c2a3612), + C32e(0xc23cfea3), C32e(0x6a8be15f), C32e(0xaebe10f9), C32e(0x69026bd0), + C32e(0x17bfa891), C32e(0x9971e858), C32e(0x3a536927), C32e(0x27f7d0b9), + C32e(0xd9914838), C32e(0xebde3513), C32e(0x2be5ceb3), C32e(0x22775533), + C32e(0xd204d6bb), C32e(0xa9399070), C32e(0x07878089), C32e(0x33c1f2a7), + C32e(0x2decc1b6), C32e(0x3c5a6622), C32e(0x15b8ad92), C32e(0xc9a96020), + C32e(0x875cdb49), C32e(0xaab01aff), C32e(0x50d88878), C32e(0xa52b8e7a), + C32e(0x03898a8f), C32e(0x594a13f8), C32e(0x09929b80), C32e(0x1a233917), + C32e(0x651075da), C32e(0xd7845331), C32e(0x84d551c6), C32e(0xd003d3b8), + C32e(0x82dc5ec3), C32e(0x29e2cbb0), C32e(0x5ac39977), C32e(0x1e2d3311), + C32e(0x7b3d46cb), C32e(0xa8b71ffc), C32e(0x6d0c61d6), C32e(0x2c624e3a) +}; + +static const sph_u32 T0dn[] = { + C32e(0xf497a5c6), C32e(0x97eb84f8), C32e(0xb0c799ee), C32e(0x8cf78df6), + C32e(0x17e50dff), C32e(0xdcb7bdd6), C32e(0xc8a7b1de), C32e(0xfc395491), + C32e(0xf0c05060), C32e(0x05040302), C32e(0xe087a9ce), C32e(0x87ac7d56), + C32e(0x2bd519e7), C32e(0xa67162b5), C32e(0x319ae64d), C32e(0xb5c39aec), + C32e(0xcf05458f), C32e(0xbc3e9d1f), C32e(0xc0094089), C32e(0x92ef87fa), + C32e(0x3fc515ef), C32e(0x267febb2), C32e(0x4007c98e), C32e(0x1ded0bfb), + C32e(0x2f82ec41), C32e(0xa97d67b3), C32e(0x1cbefd5f), C32e(0x258aea45), + C32e(0xda46bf23), C32e(0x02a6f753), C32e(0xa1d396e4), C32e(0xed2d5b9b), + C32e(0x5deac275), C32e(0x24d91ce1), C32e(0xe97aae3d), C32e(0xbe986a4c), + C32e(0xeed85a6c), C32e(0xc3fc417e), C32e(0x06f102f5), C32e(0xd11d4f83), + C32e(0xe4d05c68), C32e(0x07a2f451), C32e(0x5cb934d1), C32e(0x18e908f9), + C32e(0xaedf93e2), C32e(0x954d73ab), C32e(0xf5c45362), C32e(0x41543f2a), + C32e(0x14100c08), C32e(0xf6315295), C32e(0xaf8c6546), C32e(0xe2215e9d), + C32e(0x78602830), C32e(0xf86ea137), C32e(0x11140f0a), C32e(0xc45eb52f), + C32e(0x1b1c090e), C32e(0x5a483624), C32e(0xb6369b1b), C32e(0x47a53ddf), + C32e(0x6a8126cd), C32e(0xbb9c694e), C32e(0x4cfecd7f), C32e(0xbacf9fea), + C32e(0x2d241b12), C32e(0xb93a9e1d), C32e(0x9cb07458), C32e(0x72682e34), + C32e(0x776c2d36), C32e(0xcda3b2dc), C32e(0x2973eeb4), C32e(0x16b6fb5b), + C32e(0x0153f6a4), C32e(0xd7ec4d76), C32e(0xa37561b7), C32e(0x49face7d), + C32e(0x8da47b52), C32e(0x42a13edd), C32e(0x93bc715e), C32e(0xa2269713), + C32e(0x0457f5a6), C32e(0xb86968b9), C32e(0x00000000), C32e(0x74992cc1), + C32e(0xa0806040), C32e(0x21dd1fe3), C32e(0x43f2c879), C32e(0x2c77edb6), + C32e(0xd9b3bed4), C32e(0xca01468d), C32e(0x70ced967), C32e(0xdde44b72), + C32e(0x7933de94), C32e(0x672bd498), C32e(0x237be8b0), C32e(0xde114a85), + C32e(0xbd6d6bbb), C32e(0x7e912ac5), C32e(0x349ee54f), C32e(0x3ac116ed), + C32e(0x5417c586), C32e(0x622fd79a), C32e(0xffcc5566), C32e(0xa7229411), + C32e(0x4a0fcf8a), C32e(0x30c910e9), C32e(0x0a080604), C32e(0x98e781fe), + C32e(0x0b5bf0a0), C32e(0xccf04478), C32e(0xd54aba25), C32e(0x3e96e34b), + C32e(0x0e5ff3a2), C32e(0x19bafe5d), C32e(0x5b1bc080), C32e(0x850a8a05), + C32e(0xec7ead3f), C32e(0xdf42bc21), C32e(0xd8e04870), C32e(0x0cf904f1), + C32e(0x7ac6df63), C32e(0x58eec177), C32e(0x9f4575af), C32e(0xa5846342), + C32e(0x50403020), C32e(0x2ed11ae5), C32e(0x12e10efd), C32e(0xb7656dbf), + C32e(0xd4194c81), C32e(0x3c301418), C32e(0x5f4c3526), C32e(0x719d2fc3), + C32e(0x3867e1be), C32e(0xfd6aa235), C32e(0x4f0bcc88), C32e(0x4b5c392e), + C32e(0xf93d5793), C32e(0x0daaf255), C32e(0x9de382fc), C32e(0xc9f4477a), + C32e(0xef8bacc8), C32e(0x326fe7ba), C32e(0x7d642b32), C32e(0xa4d795e6), + C32e(0xfb9ba0c0), C32e(0xb3329819), C32e(0x6827d19e), C32e(0x815d7fa3), + C32e(0xaa886644), C32e(0x82a87e54), C32e(0xe676ab3b), C32e(0x9e16830b), + C32e(0x4503ca8c), C32e(0x7b9529c7), C32e(0x6ed6d36b), C32e(0x44503c28), + C32e(0x8b5579a7), C32e(0x3d63e2bc), C32e(0x272c1d16), C32e(0x9a4176ad), + C32e(0x4dad3bdb), C32e(0xfac85664), C32e(0xd2e84e74), C32e(0x22281e14), + C32e(0x763fdb92), C32e(0x1e180a0c), C32e(0xb4906c48), C32e(0x376be4b8), + C32e(0xe7255d9f), C32e(0xb2616ebd), C32e(0x2a86ef43), C32e(0xf193a6c4), + C32e(0xe372a839), C32e(0xf762a431), C32e(0x59bd37d3), C32e(0x86ff8bf2), + C32e(0x56b132d5), C32e(0xc50d438b), C32e(0xebdc596e), C32e(0xc2afb7da), + C32e(0x8f028c01), C32e(0xac7964b1), C32e(0x6d23d29c), C32e(0x3b92e049), + C32e(0xc7abb4d8), C32e(0x1543faac), C32e(0x09fd07f3), C32e(0x6f8525cf), + C32e(0xea8fafca), C32e(0x89f38ef4), C32e(0x208ee947), C32e(0x28201810), + C32e(0x64ded56f), C32e(0x83fb88f0), C32e(0xb1946f4a), C32e(0x96b8725c), + C32e(0x6c702438), C32e(0x08aef157), C32e(0x52e6c773), C32e(0xf3355197), + C32e(0x658d23cb), C32e(0x84597ca1), C32e(0xbfcb9ce8), C32e(0x637c213e), + C32e(0x7c37dd96), C32e(0x7fc2dc61), C32e(0x911a860d), C32e(0x941e850f), + C32e(0xabdb90e0), C32e(0xc6f8427c), C32e(0x57e2c471), C32e(0xe583aacc), + C32e(0x733bd890), C32e(0x0f0c0506), C32e(0x03f501f7), C32e(0x3638121c), + C32e(0xfe9fa3c2), C32e(0xe1d45f6a), C32e(0x1047f9ae), C32e(0x6bd2d069), + C32e(0xa82e9117), C32e(0xe8295899), C32e(0x6974273a), C32e(0xd04eb927), + C32e(0x48a938d9), C32e(0x35cd13eb), C32e(0xce56b32b), C32e(0x55443322), + C32e(0xd6bfbbd2), C32e(0x904970a9), C32e(0x800e8907), C32e(0xf266a733), + C32e(0xc15ab62d), C32e(0x6678223c), C32e(0xad2a9215), C32e(0x608920c9), + C32e(0xdb154987), C32e(0x1a4fffaa), C32e(0x88a07850), C32e(0x8e517aa5), + C32e(0x8a068f03), C32e(0x13b2f859), C32e(0x9b128009), C32e(0x3934171a), + C32e(0x75cada65), C32e(0x53b531d7), C32e(0x5113c684), C32e(0xd3bbb8d0), + C32e(0x5e1fc382), C32e(0xcb52b029), C32e(0x99b4775a), C32e(0x333c111e), + C32e(0x46f6cb7b), C32e(0x1f4bfca8), C32e(0x61dad66d), C32e(0x4e583a2c) +}; + +static const sph_u32 T1up[] = { + C32e(0xc6c632f4), C32e(0xf8f86f97), C32e(0xeeee5eb0), C32e(0xf6f67a8c), + C32e(0xffffe817), C32e(0xd6d60adc), C32e(0xdede16c8), C32e(0x91916dfc), + C32e(0x606090f0), C32e(0x02020705), C32e(0xcece2ee0), C32e(0x5656d187), + C32e(0xe7e7cc2b), C32e(0xb5b513a6), C32e(0x4d4d7c31), C32e(0xecec59b5), + C32e(0x8f8f40cf), C32e(0x1f1fa3bc), C32e(0x898949c0), C32e(0xfafa6892), + C32e(0xefefd03f), C32e(0xb2b29426), C32e(0x8e8ece40), C32e(0xfbfbe61d), + C32e(0x41416e2f), C32e(0xb3b31aa9), C32e(0x5f5f431c), C32e(0x45456025), + C32e(0x2323f9da), C32e(0x53535102), C32e(0xe4e445a1), C32e(0x9b9b76ed), + C32e(0x7575285d), C32e(0xe1e1c524), C32e(0x3d3dd4e9), C32e(0x4c4cf2be), + C32e(0x6c6c82ee), C32e(0x7e7ebdc3), C32e(0xf5f5f306), C32e(0x838352d1), + C32e(0x68688ce4), C32e(0x51515607), C32e(0xd1d18d5c), C32e(0xf9f9e118), + C32e(0xe2e24cae), C32e(0xabab3e95), C32e(0x626297f5), C32e(0x2a2a6b41), + C32e(0x08081c14), C32e(0x959563f6), C32e(0x4646e9af), C32e(0x9d9d7fe2), + C32e(0x30304878), C32e(0x3737cff8), C32e(0x0a0a1b11), C32e(0x2f2febc4), + C32e(0x0e0e151b), C32e(0x24247e5a), C32e(0x1b1badb6), C32e(0xdfdf9847), + C32e(0xcdcda76a), C32e(0x4e4ef5bb), C32e(0x7f7f334c), C32e(0xeaea50ba), + C32e(0x12123f2d), C32e(0x1d1da4b9), C32e(0x5858c49c), C32e(0x34344672), + C32e(0x36364177), C32e(0xdcdc11cd), C32e(0xb4b49d29), C32e(0x5b5b4d16), + C32e(0xa4a4a501), C32e(0x7676a1d7), C32e(0xb7b714a3), C32e(0x7d7d3449), + C32e(0x5252df8d), C32e(0xdddd9f42), C32e(0x5e5ecd93), C32e(0x1313b1a2), + C32e(0xa6a6a204), C32e(0xb9b901b8), C32e(0x00000000), C32e(0xc1c1b574), + C32e(0x4040e0a0), C32e(0xe3e3c221), C32e(0x79793a43), C32e(0xb6b69a2c), + C32e(0xd4d40dd9), C32e(0x8d8d47ca), C32e(0x67671770), C32e(0x7272afdd), + C32e(0x9494ed79), C32e(0x9898ff67), C32e(0xb0b09323), C32e(0x85855bde), + C32e(0xbbbb06bd), C32e(0xc5c5bb7e), C32e(0x4f4f7b34), C32e(0xededd73a), + C32e(0x8686d254), C32e(0x9a9af862), C32e(0x666699ff), C32e(0x1111b6a7), + C32e(0x8a8ac04a), C32e(0xe9e9d930), C32e(0x04040e0a), C32e(0xfefe6698), + C32e(0xa0a0ab0b), C32e(0x7878b4cc), C32e(0x2525f0d5), C32e(0x4b4b753e), + C32e(0xa2a2ac0e), C32e(0x5d5d4419), C32e(0x8080db5b), C32e(0x05058085), + C32e(0x3f3fd3ec), C32e(0x2121fedf), C32e(0x7070a8d8), C32e(0xf1f1fd0c), + C32e(0x6363197a), C32e(0x77772f58), C32e(0xafaf309f), C32e(0x4242e7a5), + C32e(0x20207050), C32e(0xe5e5cb2e), C32e(0xfdfdef12), C32e(0xbfbf08b7), + C32e(0x818155d4), C32e(0x1818243c), C32e(0x2626795f), C32e(0xc3c3b271), + C32e(0xbebe8638), C32e(0x3535c8fd), C32e(0x8888c74f), C32e(0x2e2e654b), + C32e(0x93936af9), C32e(0x5555580d), C32e(0xfcfc619d), C32e(0x7a7ab3c9), + C32e(0xc8c827ef), C32e(0xbaba8832), C32e(0x32324f7d), C32e(0xe6e642a4), + C32e(0xc0c03bfb), C32e(0x1919aab3), C32e(0x9e9ef668), C32e(0xa3a32281), + C32e(0x4444eeaa), C32e(0x5454d682), C32e(0x3b3bdde6), C32e(0x0b0b959e), + C32e(0x8c8cc945), C32e(0xc7c7bc7b), C32e(0x6b6b056e), C32e(0x28286c44), + C32e(0xa7a72c8b), C32e(0xbcbc813d), C32e(0x16163127), C32e(0xadad379a), + C32e(0xdbdb964d), C32e(0x64649efa), C32e(0x7474a6d2), C32e(0x14143622), + C32e(0x9292e476), C32e(0x0c0c121e), C32e(0x4848fcb4), C32e(0xb8b88f37), + C32e(0x9f9f78e7), C32e(0xbdbd0fb2), C32e(0x4343692a), C32e(0xc4c435f1), + C32e(0x3939dae3), C32e(0x3131c6f7), C32e(0xd3d38a59), C32e(0xf2f27486), + C32e(0xd5d58356), C32e(0x8b8b4ec5), C32e(0x6e6e85eb), C32e(0xdada18c2), + C32e(0x01018e8f), C32e(0xb1b11dac), C32e(0x9c9cf16d), C32e(0x4949723b), + C32e(0xd8d81fc7), C32e(0xacacb915), C32e(0xf3f3fa09), C32e(0xcfcfa06f), + C32e(0xcaca20ea), C32e(0xf4f47d89), C32e(0x47476720), C32e(0x10103828), + C32e(0x6f6f0b64), C32e(0xf0f07383), C32e(0x4a4afbb1), C32e(0x5c5cca96), + C32e(0x3838546c), C32e(0x57575f08), C32e(0x73732152), C32e(0x979764f3), + C32e(0xcbcbae65), C32e(0xa1a12584), C32e(0xe8e857bf), C32e(0x3e3e5d63), + C32e(0x9696ea7c), C32e(0x61611e7f), C32e(0x0d0d9c91), C32e(0x0f0f9b94), + C32e(0xe0e04bab), C32e(0x7c7cbac6), C32e(0x71712657), C32e(0xcccc29e5), + C32e(0x9090e373), C32e(0x0606090f), C32e(0xf7f7f403), C32e(0x1c1c2a36), + C32e(0xc2c23cfe), C32e(0x6a6a8be1), C32e(0xaeaebe10), C32e(0x6969026b), + C32e(0x1717bfa8), C32e(0x999971e8), C32e(0x3a3a5369), C32e(0x2727f7d0), + C32e(0xd9d99148), C32e(0xebebde35), C32e(0x2b2be5ce), C32e(0x22227755), + C32e(0xd2d204d6), C32e(0xa9a93990), C32e(0x07078780), C32e(0x3333c1f2), + C32e(0x2d2decc1), C32e(0x3c3c5a66), C32e(0x1515b8ad), C32e(0xc9c9a960), + C32e(0x87875cdb), C32e(0xaaaab01a), C32e(0x5050d888), C32e(0xa5a52b8e), + C32e(0x0303898a), C32e(0x59594a13), C32e(0x0909929b), C32e(0x1a1a2339), + C32e(0x65651075), C32e(0xd7d78453), C32e(0x8484d551), C32e(0xd0d003d3), + C32e(0x8282dc5e), C32e(0x2929e2cb), C32e(0x5a5ac399), C32e(0x1e1e2d33), + C32e(0x7b7b3d46), C32e(0xa8a8b71f), C32e(0x6d6d0c61), C32e(0x2c2c624e) +}; + +static const sph_u32 T1dn[] = { + C32e(0xa5f497a5), C32e(0x8497eb84), C32e(0x99b0c799), C32e(0x8d8cf78d), + C32e(0x0d17e50d), C32e(0xbddcb7bd), C32e(0xb1c8a7b1), C32e(0x54fc3954), + C32e(0x50f0c050), C32e(0x03050403), C32e(0xa9e087a9), C32e(0x7d87ac7d), + C32e(0x192bd519), C32e(0x62a67162), C32e(0xe6319ae6), C32e(0x9ab5c39a), + C32e(0x45cf0545), C32e(0x9dbc3e9d), C32e(0x40c00940), C32e(0x8792ef87), + C32e(0x153fc515), C32e(0xeb267feb), C32e(0xc94007c9), C32e(0x0b1ded0b), + C32e(0xec2f82ec), C32e(0x67a97d67), C32e(0xfd1cbefd), C32e(0xea258aea), + C32e(0xbfda46bf), C32e(0xf702a6f7), C32e(0x96a1d396), C32e(0x5bed2d5b), + C32e(0xc25deac2), C32e(0x1c24d91c), C32e(0xaee97aae), C32e(0x6abe986a), + C32e(0x5aeed85a), C32e(0x41c3fc41), C32e(0x0206f102), C32e(0x4fd11d4f), + C32e(0x5ce4d05c), C32e(0xf407a2f4), C32e(0x345cb934), C32e(0x0818e908), + C32e(0x93aedf93), C32e(0x73954d73), C32e(0x53f5c453), C32e(0x3f41543f), + C32e(0x0c14100c), C32e(0x52f63152), C32e(0x65af8c65), C32e(0x5ee2215e), + C32e(0x28786028), C32e(0xa1f86ea1), C32e(0x0f11140f), C32e(0xb5c45eb5), + C32e(0x091b1c09), C32e(0x365a4836), C32e(0x9bb6369b), C32e(0x3d47a53d), + C32e(0x266a8126), C32e(0x69bb9c69), C32e(0xcd4cfecd), C32e(0x9fbacf9f), + C32e(0x1b2d241b), C32e(0x9eb93a9e), C32e(0x749cb074), C32e(0x2e72682e), + C32e(0x2d776c2d), C32e(0xb2cda3b2), C32e(0xee2973ee), C32e(0xfb16b6fb), + C32e(0xf60153f6), C32e(0x4dd7ec4d), C32e(0x61a37561), C32e(0xce49face), + C32e(0x7b8da47b), C32e(0x3e42a13e), C32e(0x7193bc71), C32e(0x97a22697), + C32e(0xf50457f5), C32e(0x68b86968), C32e(0x00000000), C32e(0x2c74992c), + C32e(0x60a08060), C32e(0x1f21dd1f), C32e(0xc843f2c8), C32e(0xed2c77ed), + C32e(0xbed9b3be), C32e(0x46ca0146), C32e(0xd970ced9), C32e(0x4bdde44b), + C32e(0xde7933de), C32e(0xd4672bd4), C32e(0xe8237be8), C32e(0x4ade114a), + C32e(0x6bbd6d6b), C32e(0x2a7e912a), C32e(0xe5349ee5), C32e(0x163ac116), + C32e(0xc55417c5), C32e(0xd7622fd7), C32e(0x55ffcc55), C32e(0x94a72294), + C32e(0xcf4a0fcf), C32e(0x1030c910), C32e(0x060a0806), C32e(0x8198e781), + C32e(0xf00b5bf0), C32e(0x44ccf044), C32e(0xbad54aba), C32e(0xe33e96e3), + C32e(0xf30e5ff3), C32e(0xfe19bafe), C32e(0xc05b1bc0), C32e(0x8a850a8a), + C32e(0xadec7ead), C32e(0xbcdf42bc), C32e(0x48d8e048), C32e(0x040cf904), + C32e(0xdf7ac6df), C32e(0xc158eec1), C32e(0x759f4575), C32e(0x63a58463), + C32e(0x30504030), C32e(0x1a2ed11a), C32e(0x0e12e10e), C32e(0x6db7656d), + C32e(0x4cd4194c), C32e(0x143c3014), C32e(0x355f4c35), C32e(0x2f719d2f), + C32e(0xe13867e1), C32e(0xa2fd6aa2), C32e(0xcc4f0bcc), C32e(0x394b5c39), + C32e(0x57f93d57), C32e(0xf20daaf2), C32e(0x829de382), C32e(0x47c9f447), + C32e(0xacef8bac), C32e(0xe7326fe7), C32e(0x2b7d642b), C32e(0x95a4d795), + C32e(0xa0fb9ba0), C32e(0x98b33298), C32e(0xd16827d1), C32e(0x7f815d7f), + C32e(0x66aa8866), C32e(0x7e82a87e), C32e(0xabe676ab), C32e(0x839e1683), + C32e(0xca4503ca), C32e(0x297b9529), C32e(0xd36ed6d3), C32e(0x3c44503c), + C32e(0x798b5579), C32e(0xe23d63e2), C32e(0x1d272c1d), C32e(0x769a4176), + C32e(0x3b4dad3b), C32e(0x56fac856), C32e(0x4ed2e84e), C32e(0x1e22281e), + C32e(0xdb763fdb), C32e(0x0a1e180a), C32e(0x6cb4906c), C32e(0xe4376be4), + C32e(0x5de7255d), C32e(0x6eb2616e), C32e(0xef2a86ef), C32e(0xa6f193a6), + C32e(0xa8e372a8), C32e(0xa4f762a4), C32e(0x3759bd37), C32e(0x8b86ff8b), + C32e(0x3256b132), C32e(0x43c50d43), C32e(0x59ebdc59), C32e(0xb7c2afb7), + C32e(0x8c8f028c), C32e(0x64ac7964), C32e(0xd26d23d2), C32e(0xe03b92e0), + C32e(0xb4c7abb4), C32e(0xfa1543fa), C32e(0x0709fd07), C32e(0x256f8525), + C32e(0xafea8faf), C32e(0x8e89f38e), C32e(0xe9208ee9), C32e(0x18282018), + C32e(0xd564ded5), C32e(0x8883fb88), C32e(0x6fb1946f), C32e(0x7296b872), + C32e(0x246c7024), C32e(0xf108aef1), C32e(0xc752e6c7), C32e(0x51f33551), + C32e(0x23658d23), C32e(0x7c84597c), C32e(0x9cbfcb9c), C32e(0x21637c21), + C32e(0xdd7c37dd), C32e(0xdc7fc2dc), C32e(0x86911a86), C32e(0x85941e85), + C32e(0x90abdb90), C32e(0x42c6f842), C32e(0xc457e2c4), C32e(0xaae583aa), + C32e(0xd8733bd8), C32e(0x050f0c05), C32e(0x0103f501), C32e(0x12363812), + C32e(0xa3fe9fa3), C32e(0x5fe1d45f), C32e(0xf91047f9), C32e(0xd06bd2d0), + C32e(0x91a82e91), C32e(0x58e82958), C32e(0x27697427), C32e(0xb9d04eb9), + C32e(0x3848a938), C32e(0x1335cd13), C32e(0xb3ce56b3), C32e(0x33554433), + C32e(0xbbd6bfbb), C32e(0x70904970), C32e(0x89800e89), C32e(0xa7f266a7), + C32e(0xb6c15ab6), C32e(0x22667822), C32e(0x92ad2a92), C32e(0x20608920), + C32e(0x49db1549), C32e(0xff1a4fff), C32e(0x7888a078), C32e(0x7a8e517a), + C32e(0x8f8a068f), C32e(0xf813b2f8), C32e(0x809b1280), C32e(0x17393417), + C32e(0xda75cada), C32e(0x3153b531), C32e(0xc65113c6), C32e(0xb8d3bbb8), + C32e(0xc35e1fc3), C32e(0xb0cb52b0), C32e(0x7799b477), C32e(0x11333c11), + C32e(0xcb46f6cb), C32e(0xfc1f4bfc), C32e(0xd661dad6), C32e(0x3a4e583a) +}; + +static const sph_u32 T2up[] = { + C32e(0xa5c6c632), C32e(0x84f8f86f), C32e(0x99eeee5e), C32e(0x8df6f67a), + C32e(0x0dffffe8), C32e(0xbdd6d60a), C32e(0xb1dede16), C32e(0x5491916d), + C32e(0x50606090), C32e(0x03020207), C32e(0xa9cece2e), C32e(0x7d5656d1), + C32e(0x19e7e7cc), C32e(0x62b5b513), C32e(0xe64d4d7c), C32e(0x9aecec59), + C32e(0x458f8f40), C32e(0x9d1f1fa3), C32e(0x40898949), C32e(0x87fafa68), + C32e(0x15efefd0), C32e(0xebb2b294), C32e(0xc98e8ece), C32e(0x0bfbfbe6), + C32e(0xec41416e), C32e(0x67b3b31a), C32e(0xfd5f5f43), C32e(0xea454560), + C32e(0xbf2323f9), C32e(0xf7535351), C32e(0x96e4e445), C32e(0x5b9b9b76), + C32e(0xc2757528), C32e(0x1ce1e1c5), C32e(0xae3d3dd4), C32e(0x6a4c4cf2), + C32e(0x5a6c6c82), C32e(0x417e7ebd), C32e(0x02f5f5f3), C32e(0x4f838352), + C32e(0x5c68688c), C32e(0xf4515156), C32e(0x34d1d18d), C32e(0x08f9f9e1), + C32e(0x93e2e24c), C32e(0x73abab3e), C32e(0x53626297), C32e(0x3f2a2a6b), + C32e(0x0c08081c), C32e(0x52959563), C32e(0x654646e9), C32e(0x5e9d9d7f), + C32e(0x28303048), C32e(0xa13737cf), C32e(0x0f0a0a1b), C32e(0xb52f2feb), + C32e(0x090e0e15), C32e(0x3624247e), C32e(0x9b1b1bad), C32e(0x3ddfdf98), + C32e(0x26cdcda7), C32e(0x694e4ef5), C32e(0xcd7f7f33), C32e(0x9feaea50), + C32e(0x1b12123f), C32e(0x9e1d1da4), C32e(0x745858c4), C32e(0x2e343446), + C32e(0x2d363641), C32e(0xb2dcdc11), C32e(0xeeb4b49d), C32e(0xfb5b5b4d), + C32e(0xf6a4a4a5), C32e(0x4d7676a1), C32e(0x61b7b714), C32e(0xce7d7d34), + C32e(0x7b5252df), C32e(0x3edddd9f), C32e(0x715e5ecd), C32e(0x971313b1), + C32e(0xf5a6a6a2), C32e(0x68b9b901), C32e(0x00000000), C32e(0x2cc1c1b5), + C32e(0x604040e0), C32e(0x1fe3e3c2), C32e(0xc879793a), C32e(0xedb6b69a), + C32e(0xbed4d40d), C32e(0x468d8d47), C32e(0xd9676717), C32e(0x4b7272af), + C32e(0xde9494ed), C32e(0xd49898ff), C32e(0xe8b0b093), C32e(0x4a85855b), + C32e(0x6bbbbb06), C32e(0x2ac5c5bb), C32e(0xe54f4f7b), C32e(0x16ededd7), + C32e(0xc58686d2), C32e(0xd79a9af8), C32e(0x55666699), C32e(0x941111b6), + C32e(0xcf8a8ac0), C32e(0x10e9e9d9), C32e(0x0604040e), C32e(0x81fefe66), + C32e(0xf0a0a0ab), C32e(0x447878b4), C32e(0xba2525f0), C32e(0xe34b4b75), + C32e(0xf3a2a2ac), C32e(0xfe5d5d44), C32e(0xc08080db), C32e(0x8a050580), + C32e(0xad3f3fd3), C32e(0xbc2121fe), C32e(0x487070a8), C32e(0x04f1f1fd), + C32e(0xdf636319), C32e(0xc177772f), C32e(0x75afaf30), C32e(0x634242e7), + C32e(0x30202070), C32e(0x1ae5e5cb), C32e(0x0efdfdef), C32e(0x6dbfbf08), + C32e(0x4c818155), C32e(0x14181824), C32e(0x35262679), C32e(0x2fc3c3b2), + C32e(0xe1bebe86), C32e(0xa23535c8), C32e(0xcc8888c7), C32e(0x392e2e65), + C32e(0x5793936a), C32e(0xf2555558), C32e(0x82fcfc61), C32e(0x477a7ab3), + C32e(0xacc8c827), C32e(0xe7baba88), C32e(0x2b32324f), C32e(0x95e6e642), + C32e(0xa0c0c03b), C32e(0x981919aa), C32e(0xd19e9ef6), C32e(0x7fa3a322), + C32e(0x664444ee), C32e(0x7e5454d6), C32e(0xab3b3bdd), C32e(0x830b0b95), + C32e(0xca8c8cc9), C32e(0x29c7c7bc), C32e(0xd36b6b05), C32e(0x3c28286c), + C32e(0x79a7a72c), C32e(0xe2bcbc81), C32e(0x1d161631), C32e(0x76adad37), + C32e(0x3bdbdb96), C32e(0x5664649e), C32e(0x4e7474a6), C32e(0x1e141436), + C32e(0xdb9292e4), C32e(0x0a0c0c12), C32e(0x6c4848fc), C32e(0xe4b8b88f), + C32e(0x5d9f9f78), C32e(0x6ebdbd0f), C32e(0xef434369), C32e(0xa6c4c435), + C32e(0xa83939da), C32e(0xa43131c6), C32e(0x37d3d38a), C32e(0x8bf2f274), + C32e(0x32d5d583), C32e(0x438b8b4e), C32e(0x596e6e85), C32e(0xb7dada18), + C32e(0x8c01018e), C32e(0x64b1b11d), C32e(0xd29c9cf1), C32e(0xe0494972), + C32e(0xb4d8d81f), C32e(0xfaacacb9), C32e(0x07f3f3fa), C32e(0x25cfcfa0), + C32e(0xafcaca20), C32e(0x8ef4f47d), C32e(0xe9474767), C32e(0x18101038), + C32e(0xd56f6f0b), C32e(0x88f0f073), C32e(0x6f4a4afb), C32e(0x725c5cca), + C32e(0x24383854), C32e(0xf157575f), C32e(0xc7737321), C32e(0x51979764), + C32e(0x23cbcbae), C32e(0x7ca1a125), C32e(0x9ce8e857), C32e(0x213e3e5d), + C32e(0xdd9696ea), C32e(0xdc61611e), C32e(0x860d0d9c), C32e(0x850f0f9b), + C32e(0x90e0e04b), C32e(0x427c7cba), C32e(0xc4717126), C32e(0xaacccc29), + C32e(0xd89090e3), C32e(0x05060609), C32e(0x01f7f7f4), C32e(0x121c1c2a), + C32e(0xa3c2c23c), C32e(0x5f6a6a8b), C32e(0xf9aeaebe), C32e(0xd0696902), + C32e(0x911717bf), C32e(0x58999971), C32e(0x273a3a53), C32e(0xb92727f7), + C32e(0x38d9d991), C32e(0x13ebebde), C32e(0xb32b2be5), C32e(0x33222277), + C32e(0xbbd2d204), C32e(0x70a9a939), C32e(0x89070787), C32e(0xa73333c1), + C32e(0xb62d2dec), C32e(0x223c3c5a), C32e(0x921515b8), C32e(0x20c9c9a9), + C32e(0x4987875c), C32e(0xffaaaab0), C32e(0x785050d8), C32e(0x7aa5a52b), + C32e(0x8f030389), C32e(0xf859594a), C32e(0x80090992), C32e(0x171a1a23), + C32e(0xda656510), C32e(0x31d7d784), C32e(0xc68484d5), C32e(0xb8d0d003), + C32e(0xc38282dc), C32e(0xb02929e2), C32e(0x775a5ac3), C32e(0x111e1e2d), + C32e(0xcb7b7b3d), C32e(0xfca8a8b7), C32e(0xd66d6d0c), C32e(0x3a2c2c62) +}; + +static const sph_u32 T2dn[] = { + C32e(0xf4a5f497), C32e(0x978497eb), C32e(0xb099b0c7), C32e(0x8c8d8cf7), + C32e(0x170d17e5), C32e(0xdcbddcb7), C32e(0xc8b1c8a7), C32e(0xfc54fc39), + C32e(0xf050f0c0), C32e(0x05030504), C32e(0xe0a9e087), C32e(0x877d87ac), + C32e(0x2b192bd5), C32e(0xa662a671), C32e(0x31e6319a), C32e(0xb59ab5c3), + C32e(0xcf45cf05), C32e(0xbc9dbc3e), C32e(0xc040c009), C32e(0x928792ef), + C32e(0x3f153fc5), C32e(0x26eb267f), C32e(0x40c94007), C32e(0x1d0b1ded), + C32e(0x2fec2f82), C32e(0xa967a97d), C32e(0x1cfd1cbe), C32e(0x25ea258a), + C32e(0xdabfda46), C32e(0x02f702a6), C32e(0xa196a1d3), C32e(0xed5bed2d), + C32e(0x5dc25dea), C32e(0x241c24d9), C32e(0xe9aee97a), C32e(0xbe6abe98), + C32e(0xee5aeed8), C32e(0xc341c3fc), C32e(0x060206f1), C32e(0xd14fd11d), + C32e(0xe45ce4d0), C32e(0x07f407a2), C32e(0x5c345cb9), C32e(0x180818e9), + C32e(0xae93aedf), C32e(0x9573954d), C32e(0xf553f5c4), C32e(0x413f4154), + C32e(0x140c1410), C32e(0xf652f631), C32e(0xaf65af8c), C32e(0xe25ee221), + C32e(0x78287860), C32e(0xf8a1f86e), C32e(0x110f1114), C32e(0xc4b5c45e), + C32e(0x1b091b1c), C32e(0x5a365a48), C32e(0xb69bb636), C32e(0x473d47a5), + C32e(0x6a266a81), C32e(0xbb69bb9c), C32e(0x4ccd4cfe), C32e(0xba9fbacf), + C32e(0x2d1b2d24), C32e(0xb99eb93a), C32e(0x9c749cb0), C32e(0x722e7268), + C32e(0x772d776c), C32e(0xcdb2cda3), C32e(0x29ee2973), C32e(0x16fb16b6), + C32e(0x01f60153), C32e(0xd74dd7ec), C32e(0xa361a375), C32e(0x49ce49fa), + C32e(0x8d7b8da4), C32e(0x423e42a1), C32e(0x937193bc), C32e(0xa297a226), + C32e(0x04f50457), C32e(0xb868b869), C32e(0x00000000), C32e(0x742c7499), + C32e(0xa060a080), C32e(0x211f21dd), C32e(0x43c843f2), C32e(0x2ced2c77), + C32e(0xd9bed9b3), C32e(0xca46ca01), C32e(0x70d970ce), C32e(0xdd4bdde4), + C32e(0x79de7933), C32e(0x67d4672b), C32e(0x23e8237b), C32e(0xde4ade11), + C32e(0xbd6bbd6d), C32e(0x7e2a7e91), C32e(0x34e5349e), C32e(0x3a163ac1), + C32e(0x54c55417), C32e(0x62d7622f), C32e(0xff55ffcc), C32e(0xa794a722), + C32e(0x4acf4a0f), C32e(0x301030c9), C32e(0x0a060a08), C32e(0x988198e7), + C32e(0x0bf00b5b), C32e(0xcc44ccf0), C32e(0xd5bad54a), C32e(0x3ee33e96), + C32e(0x0ef30e5f), C32e(0x19fe19ba), C32e(0x5bc05b1b), C32e(0x858a850a), + C32e(0xecadec7e), C32e(0xdfbcdf42), C32e(0xd848d8e0), C32e(0x0c040cf9), + C32e(0x7adf7ac6), C32e(0x58c158ee), C32e(0x9f759f45), C32e(0xa563a584), + C32e(0x50305040), C32e(0x2e1a2ed1), C32e(0x120e12e1), C32e(0xb76db765), + C32e(0xd44cd419), C32e(0x3c143c30), C32e(0x5f355f4c), C32e(0x712f719d), + C32e(0x38e13867), C32e(0xfda2fd6a), C32e(0x4fcc4f0b), C32e(0x4b394b5c), + C32e(0xf957f93d), C32e(0x0df20daa), C32e(0x9d829de3), C32e(0xc947c9f4), + C32e(0xefacef8b), C32e(0x32e7326f), C32e(0x7d2b7d64), C32e(0xa495a4d7), + C32e(0xfba0fb9b), C32e(0xb398b332), C32e(0x68d16827), C32e(0x817f815d), + C32e(0xaa66aa88), C32e(0x827e82a8), C32e(0xe6abe676), C32e(0x9e839e16), + C32e(0x45ca4503), C32e(0x7b297b95), C32e(0x6ed36ed6), C32e(0x443c4450), + C32e(0x8b798b55), C32e(0x3de23d63), C32e(0x271d272c), C32e(0x9a769a41), + C32e(0x4d3b4dad), C32e(0xfa56fac8), C32e(0xd24ed2e8), C32e(0x221e2228), + C32e(0x76db763f), C32e(0x1e0a1e18), C32e(0xb46cb490), C32e(0x37e4376b), + C32e(0xe75de725), C32e(0xb26eb261), C32e(0x2aef2a86), C32e(0xf1a6f193), + C32e(0xe3a8e372), C32e(0xf7a4f762), C32e(0x593759bd), C32e(0x868b86ff), + C32e(0x563256b1), C32e(0xc543c50d), C32e(0xeb59ebdc), C32e(0xc2b7c2af), + C32e(0x8f8c8f02), C32e(0xac64ac79), C32e(0x6dd26d23), C32e(0x3be03b92), + C32e(0xc7b4c7ab), C32e(0x15fa1543), C32e(0x090709fd), C32e(0x6f256f85), + C32e(0xeaafea8f), C32e(0x898e89f3), C32e(0x20e9208e), C32e(0x28182820), + C32e(0x64d564de), C32e(0x838883fb), C32e(0xb16fb194), C32e(0x967296b8), + C32e(0x6c246c70), C32e(0x08f108ae), C32e(0x52c752e6), C32e(0xf351f335), + C32e(0x6523658d), C32e(0x847c8459), C32e(0xbf9cbfcb), C32e(0x6321637c), + C32e(0x7cdd7c37), C32e(0x7fdc7fc2), C32e(0x9186911a), C32e(0x9485941e), + C32e(0xab90abdb), C32e(0xc642c6f8), C32e(0x57c457e2), C32e(0xe5aae583), + C32e(0x73d8733b), C32e(0x0f050f0c), C32e(0x030103f5), C32e(0x36123638), + C32e(0xfea3fe9f), C32e(0xe15fe1d4), C32e(0x10f91047), C32e(0x6bd06bd2), + C32e(0xa891a82e), C32e(0xe858e829), C32e(0x69276974), C32e(0xd0b9d04e), + C32e(0x483848a9), C32e(0x351335cd), C32e(0xceb3ce56), C32e(0x55335544), + C32e(0xd6bbd6bf), C32e(0x90709049), C32e(0x8089800e), C32e(0xf2a7f266), + C32e(0xc1b6c15a), C32e(0x66226678), C32e(0xad92ad2a), C32e(0x60206089), + C32e(0xdb49db15), C32e(0x1aff1a4f), C32e(0x887888a0), C32e(0x8e7a8e51), + C32e(0x8a8f8a06), C32e(0x13f813b2), C32e(0x9b809b12), C32e(0x39173934), + C32e(0x75da75ca), C32e(0x533153b5), C32e(0x51c65113), C32e(0xd3b8d3bb), + C32e(0x5ec35e1f), C32e(0xcbb0cb52), C32e(0x997799b4), C32e(0x3311333c), + C32e(0x46cb46f6), C32e(0x1ffc1f4b), C32e(0x61d661da), C32e(0x4e3a4e58) +}; + +static const sph_u32 T3up[] = { + C32e(0x97a5c6c6), C32e(0xeb84f8f8), C32e(0xc799eeee), C32e(0xf78df6f6), + C32e(0xe50dffff), C32e(0xb7bdd6d6), C32e(0xa7b1dede), C32e(0x39549191), + C32e(0xc0506060), C32e(0x04030202), C32e(0x87a9cece), C32e(0xac7d5656), + C32e(0xd519e7e7), C32e(0x7162b5b5), C32e(0x9ae64d4d), C32e(0xc39aecec), + C32e(0x05458f8f), C32e(0x3e9d1f1f), C32e(0x09408989), C32e(0xef87fafa), + C32e(0xc515efef), C32e(0x7febb2b2), C32e(0x07c98e8e), C32e(0xed0bfbfb), + C32e(0x82ec4141), C32e(0x7d67b3b3), C32e(0xbefd5f5f), C32e(0x8aea4545), + C32e(0x46bf2323), C32e(0xa6f75353), C32e(0xd396e4e4), C32e(0x2d5b9b9b), + C32e(0xeac27575), C32e(0xd91ce1e1), C32e(0x7aae3d3d), C32e(0x986a4c4c), + C32e(0xd85a6c6c), C32e(0xfc417e7e), C32e(0xf102f5f5), C32e(0x1d4f8383), + C32e(0xd05c6868), C32e(0xa2f45151), C32e(0xb934d1d1), C32e(0xe908f9f9), + C32e(0xdf93e2e2), C32e(0x4d73abab), C32e(0xc4536262), C32e(0x543f2a2a), + C32e(0x100c0808), C32e(0x31529595), C32e(0x8c654646), C32e(0x215e9d9d), + C32e(0x60283030), C32e(0x6ea13737), C32e(0x140f0a0a), C32e(0x5eb52f2f), + C32e(0x1c090e0e), C32e(0x48362424), C32e(0x369b1b1b), C32e(0xa53ddfdf), + C32e(0x8126cdcd), C32e(0x9c694e4e), C32e(0xfecd7f7f), C32e(0xcf9feaea), + C32e(0x241b1212), C32e(0x3a9e1d1d), C32e(0xb0745858), C32e(0x682e3434), + C32e(0x6c2d3636), C32e(0xa3b2dcdc), C32e(0x73eeb4b4), C32e(0xb6fb5b5b), + C32e(0x53f6a4a4), C32e(0xec4d7676), C32e(0x7561b7b7), C32e(0xface7d7d), + C32e(0xa47b5252), C32e(0xa13edddd), C32e(0xbc715e5e), C32e(0x26971313), + C32e(0x57f5a6a6), C32e(0x6968b9b9), C32e(0x00000000), C32e(0x992cc1c1), + C32e(0x80604040), C32e(0xdd1fe3e3), C32e(0xf2c87979), C32e(0x77edb6b6), + C32e(0xb3bed4d4), C32e(0x01468d8d), C32e(0xced96767), C32e(0xe44b7272), + C32e(0x33de9494), C32e(0x2bd49898), C32e(0x7be8b0b0), C32e(0x114a8585), + C32e(0x6d6bbbbb), C32e(0x912ac5c5), C32e(0x9ee54f4f), C32e(0xc116eded), + C32e(0x17c58686), C32e(0x2fd79a9a), C32e(0xcc556666), C32e(0x22941111), + C32e(0x0fcf8a8a), C32e(0xc910e9e9), C32e(0x08060404), C32e(0xe781fefe), + C32e(0x5bf0a0a0), C32e(0xf0447878), C32e(0x4aba2525), C32e(0x96e34b4b), + C32e(0x5ff3a2a2), C32e(0xbafe5d5d), C32e(0x1bc08080), C32e(0x0a8a0505), + C32e(0x7ead3f3f), C32e(0x42bc2121), C32e(0xe0487070), C32e(0xf904f1f1), + C32e(0xc6df6363), C32e(0xeec17777), C32e(0x4575afaf), C32e(0x84634242), + C32e(0x40302020), C32e(0xd11ae5e5), C32e(0xe10efdfd), C32e(0x656dbfbf), + C32e(0x194c8181), C32e(0x30141818), C32e(0x4c352626), C32e(0x9d2fc3c3), + C32e(0x67e1bebe), C32e(0x6aa23535), C32e(0x0bcc8888), C32e(0x5c392e2e), + C32e(0x3d579393), C32e(0xaaf25555), C32e(0xe382fcfc), C32e(0xf4477a7a), + C32e(0x8bacc8c8), C32e(0x6fe7baba), C32e(0x642b3232), C32e(0xd795e6e6), + C32e(0x9ba0c0c0), C32e(0x32981919), C32e(0x27d19e9e), C32e(0x5d7fa3a3), + C32e(0x88664444), C32e(0xa87e5454), C32e(0x76ab3b3b), C32e(0x16830b0b), + C32e(0x03ca8c8c), C32e(0x9529c7c7), C32e(0xd6d36b6b), C32e(0x503c2828), + C32e(0x5579a7a7), C32e(0x63e2bcbc), C32e(0x2c1d1616), C32e(0x4176adad), + C32e(0xad3bdbdb), C32e(0xc8566464), C32e(0xe84e7474), C32e(0x281e1414), + C32e(0x3fdb9292), C32e(0x180a0c0c), C32e(0x906c4848), C32e(0x6be4b8b8), + C32e(0x255d9f9f), C32e(0x616ebdbd), C32e(0x86ef4343), C32e(0x93a6c4c4), + C32e(0x72a83939), C32e(0x62a43131), C32e(0xbd37d3d3), C32e(0xff8bf2f2), + C32e(0xb132d5d5), C32e(0x0d438b8b), C32e(0xdc596e6e), C32e(0xafb7dada), + C32e(0x028c0101), C32e(0x7964b1b1), C32e(0x23d29c9c), C32e(0x92e04949), + C32e(0xabb4d8d8), C32e(0x43faacac), C32e(0xfd07f3f3), C32e(0x8525cfcf), + C32e(0x8fafcaca), C32e(0xf38ef4f4), C32e(0x8ee94747), C32e(0x20181010), + C32e(0xded56f6f), C32e(0xfb88f0f0), C32e(0x946f4a4a), C32e(0xb8725c5c), + C32e(0x70243838), C32e(0xaef15757), C32e(0xe6c77373), C32e(0x35519797), + C32e(0x8d23cbcb), C32e(0x597ca1a1), C32e(0xcb9ce8e8), C32e(0x7c213e3e), + C32e(0x37dd9696), C32e(0xc2dc6161), C32e(0x1a860d0d), C32e(0x1e850f0f), + C32e(0xdb90e0e0), C32e(0xf8427c7c), C32e(0xe2c47171), C32e(0x83aacccc), + C32e(0x3bd89090), C32e(0x0c050606), C32e(0xf501f7f7), C32e(0x38121c1c), + C32e(0x9fa3c2c2), C32e(0xd45f6a6a), C32e(0x47f9aeae), C32e(0xd2d06969), + C32e(0x2e911717), C32e(0x29589999), C32e(0x74273a3a), C32e(0x4eb92727), + C32e(0xa938d9d9), C32e(0xcd13ebeb), C32e(0x56b32b2b), C32e(0x44332222), + C32e(0xbfbbd2d2), C32e(0x4970a9a9), C32e(0x0e890707), C32e(0x66a73333), + C32e(0x5ab62d2d), C32e(0x78223c3c), C32e(0x2a921515), C32e(0x8920c9c9), + C32e(0x15498787), C32e(0x4fffaaaa), C32e(0xa0785050), C32e(0x517aa5a5), + C32e(0x068f0303), C32e(0xb2f85959), C32e(0x12800909), C32e(0x34171a1a), + C32e(0xcada6565), C32e(0xb531d7d7), C32e(0x13c68484), C32e(0xbbb8d0d0), + C32e(0x1fc38282), C32e(0x52b02929), C32e(0xb4775a5a), C32e(0x3c111e1e), + C32e(0xf6cb7b7b), C32e(0x4bfca8a8), C32e(0xdad66d6d), C32e(0x583a2c2c) +}; + +static const sph_u32 T3dn[] = { + C32e(0x32f4a5f4), C32e(0x6f978497), C32e(0x5eb099b0), C32e(0x7a8c8d8c), + C32e(0xe8170d17), C32e(0x0adcbddc), C32e(0x16c8b1c8), C32e(0x6dfc54fc), + C32e(0x90f050f0), C32e(0x07050305), C32e(0x2ee0a9e0), C32e(0xd1877d87), + C32e(0xcc2b192b), C32e(0x13a662a6), C32e(0x7c31e631), C32e(0x59b59ab5), + C32e(0x40cf45cf), C32e(0xa3bc9dbc), C32e(0x49c040c0), C32e(0x68928792), + C32e(0xd03f153f), C32e(0x9426eb26), C32e(0xce40c940), C32e(0xe61d0b1d), + C32e(0x6e2fec2f), C32e(0x1aa967a9), C32e(0x431cfd1c), C32e(0x6025ea25), + C32e(0xf9dabfda), C32e(0x5102f702), C32e(0x45a196a1), C32e(0x76ed5bed), + C32e(0x285dc25d), C32e(0xc5241c24), C32e(0xd4e9aee9), C32e(0xf2be6abe), + C32e(0x82ee5aee), C32e(0xbdc341c3), C32e(0xf3060206), C32e(0x52d14fd1), + C32e(0x8ce45ce4), C32e(0x5607f407), C32e(0x8d5c345c), C32e(0xe1180818), + C32e(0x4cae93ae), C32e(0x3e957395), C32e(0x97f553f5), C32e(0x6b413f41), + C32e(0x1c140c14), C32e(0x63f652f6), C32e(0xe9af65af), C32e(0x7fe25ee2), + C32e(0x48782878), C32e(0xcff8a1f8), C32e(0x1b110f11), C32e(0xebc4b5c4), + C32e(0x151b091b), C32e(0x7e5a365a), C32e(0xadb69bb6), C32e(0x98473d47), + C32e(0xa76a266a), C32e(0xf5bb69bb), C32e(0x334ccd4c), C32e(0x50ba9fba), + C32e(0x3f2d1b2d), C32e(0xa4b99eb9), C32e(0xc49c749c), C32e(0x46722e72), + C32e(0x41772d77), C32e(0x11cdb2cd), C32e(0x9d29ee29), C32e(0x4d16fb16), + C32e(0xa501f601), C32e(0xa1d74dd7), C32e(0x14a361a3), C32e(0x3449ce49), + C32e(0xdf8d7b8d), C32e(0x9f423e42), C32e(0xcd937193), C32e(0xb1a297a2), + C32e(0xa204f504), C32e(0x01b868b8), C32e(0x00000000), C32e(0xb5742c74), + C32e(0xe0a060a0), C32e(0xc2211f21), C32e(0x3a43c843), C32e(0x9a2ced2c), + C32e(0x0dd9bed9), C32e(0x47ca46ca), C32e(0x1770d970), C32e(0xafdd4bdd), + C32e(0xed79de79), C32e(0xff67d467), C32e(0x9323e823), C32e(0x5bde4ade), + C32e(0x06bd6bbd), C32e(0xbb7e2a7e), C32e(0x7b34e534), C32e(0xd73a163a), + C32e(0xd254c554), C32e(0xf862d762), C32e(0x99ff55ff), C32e(0xb6a794a7), + C32e(0xc04acf4a), C32e(0xd9301030), C32e(0x0e0a060a), C32e(0x66988198), + C32e(0xab0bf00b), C32e(0xb4cc44cc), C32e(0xf0d5bad5), C32e(0x753ee33e), + C32e(0xac0ef30e), C32e(0x4419fe19), C32e(0xdb5bc05b), C32e(0x80858a85), + C32e(0xd3ecadec), C32e(0xfedfbcdf), C32e(0xa8d848d8), C32e(0xfd0c040c), + C32e(0x197adf7a), C32e(0x2f58c158), C32e(0x309f759f), C32e(0xe7a563a5), + C32e(0x70503050), C32e(0xcb2e1a2e), C32e(0xef120e12), C32e(0x08b76db7), + C32e(0x55d44cd4), C32e(0x243c143c), C32e(0x795f355f), C32e(0xb2712f71), + C32e(0x8638e138), C32e(0xc8fda2fd), C32e(0xc74fcc4f), C32e(0x654b394b), + C32e(0x6af957f9), C32e(0x580df20d), C32e(0x619d829d), C32e(0xb3c947c9), + C32e(0x27efacef), C32e(0x8832e732), C32e(0x4f7d2b7d), C32e(0x42a495a4), + C32e(0x3bfba0fb), C32e(0xaab398b3), C32e(0xf668d168), C32e(0x22817f81), + C32e(0xeeaa66aa), C32e(0xd6827e82), C32e(0xdde6abe6), C32e(0x959e839e), + C32e(0xc945ca45), C32e(0xbc7b297b), C32e(0x056ed36e), C32e(0x6c443c44), + C32e(0x2c8b798b), C32e(0x813de23d), C32e(0x31271d27), C32e(0x379a769a), + C32e(0x964d3b4d), C32e(0x9efa56fa), C32e(0xa6d24ed2), C32e(0x36221e22), + C32e(0xe476db76), C32e(0x121e0a1e), C32e(0xfcb46cb4), C32e(0x8f37e437), + C32e(0x78e75de7), C32e(0x0fb26eb2), C32e(0x692aef2a), C32e(0x35f1a6f1), + C32e(0xdae3a8e3), C32e(0xc6f7a4f7), C32e(0x8a593759), C32e(0x74868b86), + C32e(0x83563256), C32e(0x4ec543c5), C32e(0x85eb59eb), C32e(0x18c2b7c2), + C32e(0x8e8f8c8f), C32e(0x1dac64ac), C32e(0xf16dd26d), C32e(0x723be03b), + C32e(0x1fc7b4c7), C32e(0xb915fa15), C32e(0xfa090709), C32e(0xa06f256f), + C32e(0x20eaafea), C32e(0x7d898e89), C32e(0x6720e920), C32e(0x38281828), + C32e(0x0b64d564), C32e(0x73838883), C32e(0xfbb16fb1), C32e(0xca967296), + C32e(0x546c246c), C32e(0x5f08f108), C32e(0x2152c752), C32e(0x64f351f3), + C32e(0xae652365), C32e(0x25847c84), C32e(0x57bf9cbf), C32e(0x5d632163), + C32e(0xea7cdd7c), C32e(0x1e7fdc7f), C32e(0x9c918691), C32e(0x9b948594), + C32e(0x4bab90ab), C32e(0xbac642c6), C32e(0x2657c457), C32e(0x29e5aae5), + C32e(0xe373d873), C32e(0x090f050f), C32e(0xf4030103), C32e(0x2a361236), + C32e(0x3cfea3fe), C32e(0x8be15fe1), C32e(0xbe10f910), C32e(0x026bd06b), + C32e(0xbfa891a8), C32e(0x71e858e8), C32e(0x53692769), C32e(0xf7d0b9d0), + C32e(0x91483848), C32e(0xde351335), C32e(0xe5ceb3ce), C32e(0x77553355), + C32e(0x04d6bbd6), C32e(0x39907090), C32e(0x87808980), C32e(0xc1f2a7f2), + C32e(0xecc1b6c1), C32e(0x5a662266), C32e(0xb8ad92ad), C32e(0xa9602060), + C32e(0x5cdb49db), C32e(0xb01aff1a), C32e(0xd8887888), C32e(0x2b8e7a8e), + C32e(0x898a8f8a), C32e(0x4a13f813), C32e(0x929b809b), C32e(0x23391739), + C32e(0x1075da75), C32e(0x84533153), C32e(0xd551c651), C32e(0x03d3b8d3), + C32e(0xdc5ec35e), C32e(0xe2cbb0cb), C32e(0xc3997799), C32e(0x2d331133), + C32e(0x3d46cb46), C32e(0xb71ffc1f), C32e(0x0c61d661), C32e(0x624e3a4e) +}; + +#define DECL_STATE_SMALL \ + sph_u32 H[16]; + +#define READ_STATE_SMALL(sc) do { \ + memcpy(H, (sc)->state.narrow, sizeof H); \ + } while (0) + +#define WRITE_STATE_SMALL(sc) do { \ + memcpy((sc)->state.narrow, H, sizeof H); \ + } while (0) + +#define XCAT(x, y) XCAT_(x, y) +#define XCAT_(x, y) x ## y + +#define RSTT(d0, d1, a, b0, b1, b2, b3, b4, b5, b6, b7) do { \ + t[d0] = T0up[B32_0(a[b0])] \ + ^ T1up[B32_1(a[b1])] \ + ^ T2up[B32_2(a[b2])] \ + ^ T3up[B32_3(a[b3])] \ + ^ T0dn[B32_0(a[b4])] \ + ^ T1dn[B32_1(a[b5])] \ + ^ T2dn[B32_2(a[b6])] \ + ^ T3dn[B32_3(a[b7])]; \ + t[d1] = T0dn[B32_0(a[b0])] \ + ^ T1dn[B32_1(a[b1])] \ + ^ T2dn[B32_2(a[b2])] \ + ^ T3dn[B32_3(a[b3])] \ + ^ T0up[B32_0(a[b4])] \ + ^ T1up[B32_1(a[b5])] \ + ^ T2up[B32_2(a[b6])] \ + ^ T3up[B32_3(a[b7])]; \ + } while (0) + +#define ROUND_SMALL_P(a, r) do { \ + sph_u32 t[16]; \ + a[0x0] ^= PC32up(0x00, r); \ + a[0x1] ^= PC32dn(0x00, r); \ + a[0x2] ^= PC32up(0x10, r); \ + a[0x3] ^= PC32dn(0x10, r); \ + a[0x4] ^= PC32up(0x20, r); \ + a[0x5] ^= PC32dn(0x20, r); \ + a[0x6] ^= PC32up(0x30, r); \ + a[0x7] ^= PC32dn(0x30, r); \ + a[0x8] ^= PC32up(0x40, r); \ + a[0x9] ^= PC32dn(0x40, r); \ + a[0xA] ^= PC32up(0x50, r); \ + a[0xB] ^= PC32dn(0x50, r); \ + a[0xC] ^= PC32up(0x60, r); \ + a[0xD] ^= PC32dn(0x60, r); \ + a[0xE] ^= PC32up(0x70, r); \ + a[0xF] ^= PC32dn(0x70, r); \ + RSTT(0x0, 0x1, a, 0x0, 0x2, 0x4, 0x6, 0x9, 0xB, 0xD, 0xF); \ + RSTT(0x2, 0x3, a, 0x2, 0x4, 0x6, 0x8, 0xB, 0xD, 0xF, 0x1); \ + RSTT(0x4, 0x5, a, 0x4, 0x6, 0x8, 0xA, 0xD, 0xF, 0x1, 0x3); \ + RSTT(0x6, 0x7, a, 0x6, 0x8, 0xA, 0xC, 0xF, 0x1, 0x3, 0x5); \ + RSTT(0x8, 0x9, a, 0x8, 0xA, 0xC, 0xE, 0x1, 0x3, 0x5, 0x7); \ + RSTT(0xA, 0xB, a, 0xA, 0xC, 0xE, 0x0, 0x3, 0x5, 0x7, 0x9); \ + RSTT(0xC, 0xD, a, 0xC, 0xE, 0x0, 0x2, 0x5, 0x7, 0x9, 0xB); \ + RSTT(0xE, 0xF, a, 0xE, 0x0, 0x2, 0x4, 0x7, 0x9, 0xB, 0xD); \ + memcpy(a, t, sizeof t); \ + } while (0) + +#define ROUND_SMALL_Q(a, r) do { \ + sph_u32 t[16]; \ + a[0x0] ^= QC32up(0x00, r); \ + a[0x1] ^= QC32dn(0x00, r); \ + a[0x2] ^= QC32up(0x10, r); \ + a[0x3] ^= QC32dn(0x10, r); \ + a[0x4] ^= QC32up(0x20, r); \ + a[0x5] ^= QC32dn(0x20, r); \ + a[0x6] ^= QC32up(0x30, r); \ + a[0x7] ^= QC32dn(0x30, r); \ + a[0x8] ^= QC32up(0x40, r); \ + a[0x9] ^= QC32dn(0x40, r); \ + a[0xA] ^= QC32up(0x50, r); \ + a[0xB] ^= QC32dn(0x50, r); \ + a[0xC] ^= QC32up(0x60, r); \ + a[0xD] ^= QC32dn(0x60, r); \ + a[0xE] ^= QC32up(0x70, r); \ + a[0xF] ^= QC32dn(0x70, r); \ + RSTT(0x0, 0x1, a, 0x2, 0x6, 0xA, 0xE, 0x1, 0x5, 0x9, 0xD); \ + RSTT(0x2, 0x3, a, 0x4, 0x8, 0xC, 0x0, 0x3, 0x7, 0xB, 0xF); \ + RSTT(0x4, 0x5, a, 0x6, 0xA, 0xE, 0x2, 0x5, 0x9, 0xD, 0x1); \ + RSTT(0x6, 0x7, a, 0x8, 0xC, 0x0, 0x4, 0x7, 0xB, 0xF, 0x3); \ + RSTT(0x8, 0x9, a, 0xA, 0xE, 0x2, 0x6, 0x9, 0xD, 0x1, 0x5); \ + RSTT(0xA, 0xB, a, 0xC, 0x0, 0x4, 0x8, 0xB, 0xF, 0x3, 0x7); \ + RSTT(0xC, 0xD, a, 0xE, 0x2, 0x6, 0xA, 0xD, 0x1, 0x5, 0x9); \ + RSTT(0xE, 0xF, a, 0x0, 0x4, 0x8, 0xC, 0xF, 0x3, 0x7, 0xB); \ + memcpy(a, t, sizeof t); \ + } while (0) + +#if SPH_SMALL_FOOTPRINT_GROESTL + +#define PERM_SMALL_P(a) do { \ + int r; \ + for (r = 0; r < 10; r ++) \ + ROUND_SMALL_P(a, r); \ + } while (0) + +#define PERM_SMALL_Q(a) do { \ + int r; \ + for (r = 0; r < 10; r ++) \ + ROUND_SMALL_Q(a, r); \ + } while (0) + +#else + +#define PERM_SMALL_P(a) do { \ + int r; \ + for (r = 0; r < 10; r += 2) { \ + ROUND_SMALL_P(a, r + 0); \ + ROUND_SMALL_P(a, r + 1); \ + } \ + } while (0) + +#define PERM_SMALL_Q(a) do { \ + int r; \ + for (r = 0; r < 10; r += 2) { \ + ROUND_SMALL_Q(a, r + 0); \ + ROUND_SMALL_Q(a, r + 1); \ + } \ + } while (0) + +#endif + +#define COMPRESS_SMALL do { \ + sph_u32 g[16], m[16]; \ + size_t u; \ + for (u = 0; u < 16; u ++) { \ + m[u] = dec32e_aligned(buf + (u << 2)); \ + g[u] = m[u] ^ H[u]; \ + } \ + PERM_SMALL_P(g); \ + PERM_SMALL_Q(m); \ + for (u = 0; u < 16; u ++) \ + H[u] ^= g[u] ^ m[u]; \ + } while (0) + +#define FINAL_SMALL do { \ + sph_u32 x[16]; \ + size_t u; \ + memcpy(x, H, sizeof x); \ + PERM_SMALL_P(x); \ + for (u = 0; u < 16; u ++) \ + H[u] ^= x[u]; \ + } while (0) + +#define DECL_STATE_BIG \ + sph_u32 H[32]; + +#define READ_STATE_BIG(sc) do { \ + memcpy(H, (sc)->state.narrow, sizeof H); \ + } while (0) + +#define WRITE_STATE_BIG(sc) do { \ + memcpy((sc)->state.narrow, H, sizeof H); \ + } while (0) + +#if SPH_SMALL_FOOTPRINT_GROESTL + +#define RBTT(d0, d1, a, b0, b1, b2, b3, b4, b5, b6, b7) do { \ + sph_u32 fu2 = T0up[B32_2(a[b2])]; \ + sph_u32 fd2 = T0dn[B32_2(a[b2])]; \ + sph_u32 fu3 = T1up[B32_3(a[b3])]; \ + sph_u32 fd3 = T1dn[B32_3(a[b3])]; \ + sph_u32 fu6 = T0up[B32_2(a[b6])]; \ + sph_u32 fd6 = T0dn[B32_2(a[b6])]; \ + sph_u32 fu7 = T1up[B32_3(a[b7])]; \ + sph_u32 fd7 = T1dn[B32_3(a[b7])]; \ + t[d0] = T0up[B32_0(a[b0])] \ + ^ T1up[B32_1(a[b1])] \ + ^ R32u(fu2, fd2) \ + ^ R32u(fu3, fd3) \ + ^ T0dn[B32_0(a[b4])] \ + ^ T1dn[B32_1(a[b5])] \ + ^ R32d(fu6, fd6) \ + ^ R32d(fu7, fd7); \ + t[d1] = T0dn[B32_0(a[b0])] \ + ^ T1dn[B32_1(a[b1])] \ + ^ R32d(fu2, fd2) \ + ^ R32d(fu3, fd3) \ + ^ T0up[B32_0(a[b4])] \ + ^ T1up[B32_1(a[b5])] \ + ^ R32u(fu6, fd6) \ + ^ R32u(fu7, fd7); \ + } while (0) + +#else + +#define RBTT(d0, d1, a, b0, b1, b2, b3, b4, b5, b6, b7) do { \ + t[d0] = T0up[B32_0(a[b0])] \ + ^ T1up[B32_1(a[b1])] \ + ^ T2up[B32_2(a[b2])] \ + ^ T3up[B32_3(a[b3])] \ + ^ T0dn[B32_0(a[b4])] \ + ^ T1dn[B32_1(a[b5])] \ + ^ T2dn[B32_2(a[b6])] \ + ^ T3dn[B32_3(a[b7])]; \ + t[d1] = T0dn[B32_0(a[b0])] \ + ^ T1dn[B32_1(a[b1])] \ + ^ T2dn[B32_2(a[b2])] \ + ^ T3dn[B32_3(a[b3])] \ + ^ T0up[B32_0(a[b4])] \ + ^ T1up[B32_1(a[b5])] \ + ^ T2up[B32_2(a[b6])] \ + ^ T3up[B32_3(a[b7])]; \ + } while (0) + +#endif + +#if SPH_SMALL_FOOTPRINT_GROESTL + +#define ROUND_BIG_P(a, r) do { \ + sph_u32 t[32]; \ + size_t u; \ + a[0x00] ^= PC32up(0x00, r); \ + a[0x01] ^= PC32dn(0x00, r); \ + a[0x02] ^= PC32up(0x10, r); \ + a[0x03] ^= PC32dn(0x10, r); \ + a[0x04] ^= PC32up(0x20, r); \ + a[0x05] ^= PC32dn(0x20, r); \ + a[0x06] ^= PC32up(0x30, r); \ + a[0x07] ^= PC32dn(0x30, r); \ + a[0x08] ^= PC32up(0x40, r); \ + a[0x09] ^= PC32dn(0x40, r); \ + a[0x0A] ^= PC32up(0x50, r); \ + a[0x0B] ^= PC32dn(0x50, r); \ + a[0x0C] ^= PC32up(0x60, r); \ + a[0x0D] ^= PC32dn(0x60, r); \ + a[0x0E] ^= PC32up(0x70, r); \ + a[0x0F] ^= PC32dn(0x70, r); \ + a[0x10] ^= PC32up(0x80, r); \ + a[0x11] ^= PC32dn(0x80, r); \ + a[0x12] ^= PC32up(0x90, r); \ + a[0x13] ^= PC32dn(0x90, r); \ + a[0x14] ^= PC32up(0xA0, r); \ + a[0x15] ^= PC32dn(0xA0, r); \ + a[0x16] ^= PC32up(0xB0, r); \ + a[0x17] ^= PC32dn(0xB0, r); \ + a[0x18] ^= PC32up(0xC0, r); \ + a[0x19] ^= PC32dn(0xC0, r); \ + a[0x1A] ^= PC32up(0xD0, r); \ + a[0x1B] ^= PC32dn(0xD0, r); \ + a[0x1C] ^= PC32up(0xE0, r); \ + a[0x1D] ^= PC32dn(0xE0, r); \ + a[0x1E] ^= PC32up(0xF0, r); \ + a[0x1F] ^= PC32dn(0xF0, r); \ + for (u = 0; u < 32; u += 8) { \ + RBTT(u + 0x00, (u + 0x01) & 0x1F, a, \ + u + 0x00, (u + 0x02) & 0x1F, \ + (u + 0x04) & 0x1F, (u + 0x06) & 0x1F, \ + (u + 0x09) & 0x1F, (u + 0x0B) & 0x1F, \ + (u + 0x0D) & 0x1F, (u + 0x17) & 0x1F); \ + RBTT(u + 0x02, (u + 0x03) & 0x1F, a, \ + u + 0x02, (u + 0x04) & 0x1F, \ + (u + 0x06) & 0x1F, (u + 0x08) & 0x1F, \ + (u + 0x0B) & 0x1F, (u + 0x0D) & 0x1F, \ + (u + 0x0F) & 0x1F, (u + 0x19) & 0x1F); \ + RBTT(u + 0x04, (u + 0x05) & 0x1F, a, \ + u + 0x04, (u + 0x06) & 0x1F, \ + (u + 0x08) & 0x1F, (u + 0x0A) & 0x1F, \ + (u + 0x0D) & 0x1F, (u + 0x0F) & 0x1F, \ + (u + 0x11) & 0x1F, (u + 0x1B) & 0x1F); \ + RBTT(u + 0x06, (u + 0x07) & 0x1F, a, \ + u + 0x06, (u + 0x08) & 0x1F, \ + (u + 0x0A) & 0x1F, (u + 0x0C) & 0x1F, \ + (u + 0x0F) & 0x1F, (u + 0x11) & 0x1F, \ + (u + 0x13) & 0x1F, (u + 0x1D) & 0x1F); \ + } \ + memcpy(a, t, sizeof t); \ + } while (0) + +#define ROUND_BIG_Q(a, r) do { \ + sph_u32 t[32]; \ + size_t u; \ + a[0x00] ^= QC32up(0x00, r); \ + a[0x01] ^= QC32dn(0x00, r); \ + a[0x02] ^= QC32up(0x10, r); \ + a[0x03] ^= QC32dn(0x10, r); \ + a[0x04] ^= QC32up(0x20, r); \ + a[0x05] ^= QC32dn(0x20, r); \ + a[0x06] ^= QC32up(0x30, r); \ + a[0x07] ^= QC32dn(0x30, r); \ + a[0x08] ^= QC32up(0x40, r); \ + a[0x09] ^= QC32dn(0x40, r); \ + a[0x0A] ^= QC32up(0x50, r); \ + a[0x0B] ^= QC32dn(0x50, r); \ + a[0x0C] ^= QC32up(0x60, r); \ + a[0x0D] ^= QC32dn(0x60, r); \ + a[0x0E] ^= QC32up(0x70, r); \ + a[0x0F] ^= QC32dn(0x70, r); \ + a[0x10] ^= QC32up(0x80, r); \ + a[0x11] ^= QC32dn(0x80, r); \ + a[0x12] ^= QC32up(0x90, r); \ + a[0x13] ^= QC32dn(0x90, r); \ + a[0x14] ^= QC32up(0xA0, r); \ + a[0x15] ^= QC32dn(0xA0, r); \ + a[0x16] ^= QC32up(0xB0, r); \ + a[0x17] ^= QC32dn(0xB0, r); \ + a[0x18] ^= QC32up(0xC0, r); \ + a[0x19] ^= QC32dn(0xC0, r); \ + a[0x1A] ^= QC32up(0xD0, r); \ + a[0x1B] ^= QC32dn(0xD0, r); \ + a[0x1C] ^= QC32up(0xE0, r); \ + a[0x1D] ^= QC32dn(0xE0, r); \ + a[0x1E] ^= QC32up(0xF0, r); \ + a[0x1F] ^= QC32dn(0xF0, r); \ + for (u = 0; u < 32; u += 8) { \ + RBTT(u + 0x00, (u + 0x01) & 0x1F, a, \ + (u + 0x02) & 0x1F, (u + 0x06) & 0x1F, \ + (u + 0x0A) & 0x1F, (u + 0x16) & 0x1F, \ + (u + 0x01) & 0x1F, (u + 0x05) & 0x1F, \ + (u + 0x09) & 0x1F, (u + 0x0D) & 0x1F); \ + RBTT(u + 0x02, (u + 0x03) & 0x1F, a, \ + (u + 0x04) & 0x1F, (u + 0x08) & 0x1F, \ + (u + 0x0C) & 0x1F, (u + 0x18) & 0x1F, \ + (u + 0x03) & 0x1F, (u + 0x07) & 0x1F, \ + (u + 0x0B) & 0x1F, (u + 0x0F) & 0x1F); \ + RBTT(u + 0x04, (u + 0x05) & 0x1F, a, \ + (u + 0x06) & 0x1F, (u + 0x0A) & 0x1F, \ + (u + 0x0E) & 0x1F, (u + 0x1A) & 0x1F, \ + (u + 0x05) & 0x1F, (u + 0x09) & 0x1F, \ + (u + 0x0D) & 0x1F, (u + 0x11) & 0x1F); \ + RBTT(u + 0x06, (u + 0x07) & 0x1F, a, \ + (u + 0x08) & 0x1F, (u + 0x0C) & 0x1F, \ + (u + 0x10) & 0x1F, (u + 0x1C) & 0x1F, \ + (u + 0x07) & 0x1F, (u + 0x0B) & 0x1F, \ + (u + 0x0F) & 0x1F, (u + 0x13) & 0x1F); \ + } \ + memcpy(a, t, sizeof t); \ + } while (0) + +#else + +#define ROUND_BIG_P(a, r) do { \ + sph_u32 t[32]; \ + a[0x00] ^= PC32up(0x00, r); \ + a[0x01] ^= PC32dn(0x00, r); \ + a[0x02] ^= PC32up(0x10, r); \ + a[0x03] ^= PC32dn(0x10, r); \ + a[0x04] ^= PC32up(0x20, r); \ + a[0x05] ^= PC32dn(0x20, r); \ + a[0x06] ^= PC32up(0x30, r); \ + a[0x07] ^= PC32dn(0x30, r); \ + a[0x08] ^= PC32up(0x40, r); \ + a[0x09] ^= PC32dn(0x40, r); \ + a[0x0A] ^= PC32up(0x50, r); \ + a[0x0B] ^= PC32dn(0x50, r); \ + a[0x0C] ^= PC32up(0x60, r); \ + a[0x0D] ^= PC32dn(0x60, r); \ + a[0x0E] ^= PC32up(0x70, r); \ + a[0x0F] ^= PC32dn(0x70, r); \ + a[0x10] ^= PC32up(0x80, r); \ + a[0x11] ^= PC32dn(0x80, r); \ + a[0x12] ^= PC32up(0x90, r); \ + a[0x13] ^= PC32dn(0x90, r); \ + a[0x14] ^= PC32up(0xA0, r); \ + a[0x15] ^= PC32dn(0xA0, r); \ + a[0x16] ^= PC32up(0xB0, r); \ + a[0x17] ^= PC32dn(0xB0, r); \ + a[0x18] ^= PC32up(0xC0, r); \ + a[0x19] ^= PC32dn(0xC0, r); \ + a[0x1A] ^= PC32up(0xD0, r); \ + a[0x1B] ^= PC32dn(0xD0, r); \ + a[0x1C] ^= PC32up(0xE0, r); \ + a[0x1D] ^= PC32dn(0xE0, r); \ + a[0x1E] ^= PC32up(0xF0, r); \ + a[0x1F] ^= PC32dn(0xF0, r); \ + RBTT(0x00, 0x01, a, \ + 0x00, 0x02, 0x04, 0x06, 0x09, 0x0B, 0x0D, 0x17); \ + RBTT(0x02, 0x03, a, \ + 0x02, 0x04, 0x06, 0x08, 0x0B, 0x0D, 0x0F, 0x19); \ + RBTT(0x04, 0x05, a, \ + 0x04, 0x06, 0x08, 0x0A, 0x0D, 0x0F, 0x11, 0x1B); \ + RBTT(0x06, 0x07, a, \ + 0x06, 0x08, 0x0A, 0x0C, 0x0F, 0x11, 0x13, 0x1D); \ + RBTT(0x08, 0x09, a, \ + 0x08, 0x0A, 0x0C, 0x0E, 0x11, 0x13, 0x15, 0x1F); \ + RBTT(0x0A, 0x0B, a, \ + 0x0A, 0x0C, 0x0E, 0x10, 0x13, 0x15, 0x17, 0x01); \ + RBTT(0x0C, 0x0D, a, \ + 0x0C, 0x0E, 0x10, 0x12, 0x15, 0x17, 0x19, 0x03); \ + RBTT(0x0E, 0x0F, a, \ + 0x0E, 0x10, 0x12, 0x14, 0x17, 0x19, 0x1B, 0x05); \ + RBTT(0x10, 0x11, a, \ + 0x10, 0x12, 0x14, 0x16, 0x19, 0x1B, 0x1D, 0x07); \ + RBTT(0x12, 0x13, a, \ + 0x12, 0x14, 0x16, 0x18, 0x1B, 0x1D, 0x1F, 0x09); \ + RBTT(0x14, 0x15, a, \ + 0x14, 0x16, 0x18, 0x1A, 0x1D, 0x1F, 0x01, 0x0B); \ + RBTT(0x16, 0x17, a, \ + 0x16, 0x18, 0x1A, 0x1C, 0x1F, 0x01, 0x03, 0x0D); \ + RBTT(0x18, 0x19, a, \ + 0x18, 0x1A, 0x1C, 0x1E, 0x01, 0x03, 0x05, 0x0F); \ + RBTT(0x1A, 0x1B, a, \ + 0x1A, 0x1C, 0x1E, 0x00, 0x03, 0x05, 0x07, 0x11); \ + RBTT(0x1C, 0x1D, a, \ + 0x1C, 0x1E, 0x00, 0x02, 0x05, 0x07, 0x09, 0x13); \ + RBTT(0x1E, 0x1F, a, \ + 0x1E, 0x00, 0x02, 0x04, 0x07, 0x09, 0x0B, 0x15); \ + memcpy(a, t, sizeof t); \ + } while (0) + +#define ROUND_BIG_Q(a, r) do { \ + sph_u32 t[32]; \ + a[0x00] ^= QC32up(0x00, r); \ + a[0x01] ^= QC32dn(0x00, r); \ + a[0x02] ^= QC32up(0x10, r); \ + a[0x03] ^= QC32dn(0x10, r); \ + a[0x04] ^= QC32up(0x20, r); \ + a[0x05] ^= QC32dn(0x20, r); \ + a[0x06] ^= QC32up(0x30, r); \ + a[0x07] ^= QC32dn(0x30, r); \ + a[0x08] ^= QC32up(0x40, r); \ + a[0x09] ^= QC32dn(0x40, r); \ + a[0x0A] ^= QC32up(0x50, r); \ + a[0x0B] ^= QC32dn(0x50, r); \ + a[0x0C] ^= QC32up(0x60, r); \ + a[0x0D] ^= QC32dn(0x60, r); \ + a[0x0E] ^= QC32up(0x70, r); \ + a[0x0F] ^= QC32dn(0x70, r); \ + a[0x10] ^= QC32up(0x80, r); \ + a[0x11] ^= QC32dn(0x80, r); \ + a[0x12] ^= QC32up(0x90, r); \ + a[0x13] ^= QC32dn(0x90, r); \ + a[0x14] ^= QC32up(0xA0, r); \ + a[0x15] ^= QC32dn(0xA0, r); \ + a[0x16] ^= QC32up(0xB0, r); \ + a[0x17] ^= QC32dn(0xB0, r); \ + a[0x18] ^= QC32up(0xC0, r); \ + a[0x19] ^= QC32dn(0xC0, r); \ + a[0x1A] ^= QC32up(0xD0, r); \ + a[0x1B] ^= QC32dn(0xD0, r); \ + a[0x1C] ^= QC32up(0xE0, r); \ + a[0x1D] ^= QC32dn(0xE0, r); \ + a[0x1E] ^= QC32up(0xF0, r); \ + a[0x1F] ^= QC32dn(0xF0, r); \ + RBTT(0x00, 0x01, a, \ + 0x02, 0x06, 0x0A, 0x16, 0x01, 0x05, 0x09, 0x0D); \ + RBTT(0x02, 0x03, a, \ + 0x04, 0x08, 0x0C, 0x18, 0x03, 0x07, 0x0B, 0x0F); \ + RBTT(0x04, 0x05, a, \ + 0x06, 0x0A, 0x0E, 0x1A, 0x05, 0x09, 0x0D, 0x11); \ + RBTT(0x06, 0x07, a, \ + 0x08, 0x0C, 0x10, 0x1C, 0x07, 0x0B, 0x0F, 0x13); \ + RBTT(0x08, 0x09, a, \ + 0x0A, 0x0E, 0x12, 0x1E, 0x09, 0x0D, 0x11, 0x15); \ + RBTT(0x0A, 0x0B, a, \ + 0x0C, 0x10, 0x14, 0x00, 0x0B, 0x0F, 0x13, 0x17); \ + RBTT(0x0C, 0x0D, a, \ + 0x0E, 0x12, 0x16, 0x02, 0x0D, 0x11, 0x15, 0x19); \ + RBTT(0x0E, 0x0F, a, \ + 0x10, 0x14, 0x18, 0x04, 0x0F, 0x13, 0x17, 0x1B); \ + RBTT(0x10, 0x11, a, \ + 0x12, 0x16, 0x1A, 0x06, 0x11, 0x15, 0x19, 0x1D); \ + RBTT(0x12, 0x13, a, \ + 0x14, 0x18, 0x1C, 0x08, 0x13, 0x17, 0x1B, 0x1F); \ + RBTT(0x14, 0x15, a, \ + 0x16, 0x1A, 0x1E, 0x0A, 0x15, 0x19, 0x1D, 0x01); \ + RBTT(0x16, 0x17, a, \ + 0x18, 0x1C, 0x00, 0x0C, 0x17, 0x1B, 0x1F, 0x03); \ + RBTT(0x18, 0x19, a, \ + 0x1A, 0x1E, 0x02, 0x0E, 0x19, 0x1D, 0x01, 0x05); \ + RBTT(0x1A, 0x1B, a, \ + 0x1C, 0x00, 0x04, 0x10, 0x1B, 0x1F, 0x03, 0x07); \ + RBTT(0x1C, 0x1D, a, \ + 0x1E, 0x02, 0x06, 0x12, 0x1D, 0x01, 0x05, 0x09); \ + RBTT(0x1E, 0x1F, a, \ + 0x00, 0x04, 0x08, 0x14, 0x1F, 0x03, 0x07, 0x0B); \ + memcpy(a, t, sizeof t); \ + } while (0) + +#endif + +#if SPH_SMALL_FOOTPRINT_GROESTL + +#define PERM_BIG_P(a) do { \ + int r; \ + for (r = 0; r < 14; r ++) \ + ROUND_BIG_P(a, r); \ + } while (0) + +#define PERM_BIG_Q(a) do { \ + int r; \ + for (r = 0; r < 14; r ++) \ + ROUND_BIG_Q(a, r); \ + } while (0) + +#else + +#define PERM_BIG_P(a) do { \ + int r; \ + for (r = 0; r < 14; r += 2) { \ + ROUND_BIG_P(a, r + 0); \ + ROUND_BIG_P(a, r + 1); \ + } \ + } while (0) + +#define PERM_BIG_Q(a) do { \ + int r; \ + for (r = 0; r < 14; r += 2) { \ + ROUND_BIG_Q(a, r + 0); \ + ROUND_BIG_Q(a, r + 1); \ + } \ + } while (0) + +#endif + +#define COMPRESS_BIG do { \ + sph_u32 g[32], m[32]; \ + size_t u; \ + for (u = 0; u < 32; u ++) { \ + m[u] = dec32e_aligned(buf + (u << 2)); \ + g[u] = m[u] ^ H[u]; \ + } \ + PERM_BIG_P(g); \ + PERM_BIG_Q(m); \ + for (u = 0; u < 32; u ++) \ + H[u] ^= g[u] ^ m[u]; \ + } while (0) + +#define FINAL_BIG do { \ + sph_u32 x[32]; \ + size_t u; \ + memcpy(x, H, sizeof x); \ + PERM_BIG_P(x); \ + for (u = 0; u < 32; u ++) \ + H[u] ^= x[u]; \ + } while (0) + +#endif + +static void +groestl_small_init(sph_groestl_small_context *sc, unsigned out_size) +{ + size_t u; + + sc->ptr = 0; +#if SPH_GROESTL_64 + for (u = 0; u < 7; u ++) + sc->state.wide[u] = 0; +#if USE_LE + sc->state.wide[7] = ((sph_u64)(out_size & 0xFF) << 56) + | ((sph_u64)(out_size & 0xFF00) << 40); +#else + sc->state.wide[7] = (sph_u64)out_size; +#endif +#else + for (u = 0; u < 15; u ++) + sc->state.narrow[u] = 0; +#if USE_LE + sc->state.narrow[15] = ((sph_u32)(out_size & 0xFF) << 24) + | ((sph_u32)(out_size & 0xFF00) << 8); +#else + sc->state.narrow[15] = (sph_u32)out_size; +#endif +#endif +#if SPH_64 + sc->count = 0; +#else + sc->count_high = 0; + sc->count_low = 0; +#endif +} + +static void +groestl_small_core(sph_groestl_small_context *sc, const void *data, size_t len) +{ + unsigned char *buf; + size_t ptr; + DECL_STATE_SMALL + + buf = sc->buf; + ptr = sc->ptr; + if (len < (sizeof sc->buf) - ptr) { + memcpy(buf + ptr, data, len); + ptr += len; + sc->ptr = ptr; + return; + } + + READ_STATE_SMALL(sc); + while (len > 0) { + size_t clen; + + clen = (sizeof sc->buf) - ptr; + if (clen > len) + clen = len; + memcpy(buf + ptr, data, clen); + ptr += clen; + data = (const unsigned char *)data + clen; + len -= clen; + if (ptr == sizeof sc->buf) { + COMPRESS_SMALL; +#if SPH_64 + sc->count ++; +#else + if ((sc->count_low = SPH_T32(sc->count_low + 1)) == 0) + sc->count_high = SPH_T32(sc->count_high + 1); +#endif + ptr = 0; + } + } + WRITE_STATE_SMALL(sc); + sc->ptr = ptr; +} + +static void +groestl_small_close(sph_groestl_small_context *sc, + unsigned ub, unsigned n, void *dst, size_t out_len) +{ + unsigned char *buf; + unsigned char pad[72]; + size_t u, ptr, pad_len; +#if SPH_64 + sph_u64 count; +#else + sph_u32 count_high, count_low; +#endif + unsigned z; + DECL_STATE_SMALL + + buf = sc->buf; + ptr = sc->ptr; + z = 0x80 >> n; + pad[0] = ((ub & -z) | z) & 0xFF; + if (ptr < 56) { + pad_len = 64 - ptr; +#if SPH_64 + count = SPH_T64(sc->count + 1); +#else + count_low = SPH_T32(sc->count_low + 1); + count_high = SPH_T32(sc->count_high); + if (count_low == 0) + count_high = SPH_T32(count_high + 1); +#endif + } else { + pad_len = 128 - ptr; +#if SPH_64 + count = SPH_T64(sc->count + 2); +#else + count_low = SPH_T32(sc->count_low + 2); + count_high = SPH_T32(sc->count_high); + if (count_low <= 1) + count_high = SPH_T32(count_high + 1); +#endif + } + memset(pad + 1, 0, pad_len - 9); +#if SPH_64 + sph_enc64be(pad + pad_len - 8, count); +#else + sph_enc64be(pad + pad_len - 8, count_high); + sph_enc64be(pad + pad_len - 4, count_low); +#endif + groestl_small_core(sc, pad, pad_len); + READ_STATE_SMALL(sc); + FINAL_SMALL; +#if SPH_GROESTL_64 + for (u = 0; u < 4; u ++) + enc64e(pad + (u << 3), H[u + 4]); +#else + for (u = 0; u < 8; u ++) + enc32e(pad + (u << 2), H[u + 8]); +#endif + memcpy(dst, pad + 32 - out_len, out_len); + groestl_small_init(sc, (unsigned)out_len << 3); +} + +static void +groestl_big_init(sph_groestl_big_context *sc, unsigned out_size) +{ + size_t u; + + sc->ptr = 0; +#if SPH_GROESTL_64 + for (u = 0; u < 15; u ++) + sc->state.wide[u] = 0; +#if USE_LE + sc->state.wide[15] = ((sph_u64)(out_size & 0xFF) << 56) + | ((sph_u64)(out_size & 0xFF00) << 40); +#else + sc->state.wide[15] = (sph_u64)out_size; +#endif +#else + for (u = 0; u < 31; u ++) + sc->state.narrow[u] = 0; +#if USE_LE + sc->state.narrow[31] = ((sph_u32)(out_size & 0xFF) << 24) + | ((sph_u32)(out_size & 0xFF00) << 8); +#else + sc->state.narrow[31] = (sph_u32)out_size; +#endif +#endif +#if SPH_64 + sc->count = 0; +#else + sc->count_high = 0; + sc->count_low = 0; +#endif +} + +static void +groestl_big_core(sph_groestl_big_context *sc, const void *data, size_t len) +{ + unsigned char *buf; + size_t ptr; + DECL_STATE_BIG + + buf = sc->buf; + ptr = sc->ptr; + if (len < (sizeof sc->buf) - ptr) { + memcpy(buf + ptr, data, len); + ptr += len; + sc->ptr = ptr; + return; + } + + READ_STATE_BIG(sc); + while (len > 0) { + size_t clen; + + clen = (sizeof sc->buf) - ptr; + if (clen > len) + clen = len; + memcpy(buf + ptr, data, clen); + ptr += clen; + data = (const unsigned char *)data + clen; + len -= clen; + if (ptr == sizeof sc->buf) { + COMPRESS_BIG; +#if SPH_64 + sc->count ++; +#else + if ((sc->count_low = SPH_T32(sc->count_low + 1)) == 0) + sc->count_high = SPH_T32(sc->count_high + 1); +#endif + ptr = 0; + } + } + WRITE_STATE_BIG(sc); + sc->ptr = ptr; +} + +static void +groestl_big_close(sph_groestl_big_context *sc, + unsigned ub, unsigned n, void *dst, size_t out_len) +{ + unsigned char *buf; + unsigned char pad[136]; + size_t ptr, pad_len, u; +#if SPH_64 + sph_u64 count; +#else + sph_u32 count_high, count_low; +#endif + unsigned z; + DECL_STATE_BIG + + buf = sc->buf; + ptr = sc->ptr; + z = 0x80 >> n; + pad[0] = ((ub & -z) | z) & 0xFF; + if (ptr < 120) { + pad_len = 128 - ptr; +#if SPH_64 + count = SPH_T64(sc->count + 1); +#else + count_low = SPH_T32(sc->count_low + 1); + count_high = SPH_T32(sc->count_high); + if (count_low == 0) + count_high = SPH_T32(count_high + 1); +#endif + } else { + pad_len = 256 - ptr; +#if SPH_64 + count = SPH_T64(sc->count + 2); +#else + count_low = SPH_T32(sc->count_low + 2); + count_high = SPH_T32(sc->count_high); + if (count_low <= 1) + count_high = SPH_T32(count_high + 1); +#endif + } + memset(pad + 1, 0, pad_len - 9); +#if SPH_64 + sph_enc64be(pad + pad_len - 8, count); +#else + sph_enc64be(pad + pad_len - 8, count_high); + sph_enc64be(pad + pad_len - 4, count_low); +#endif + groestl_big_core(sc, pad, pad_len); + READ_STATE_BIG(sc); + FINAL_BIG; +#if SPH_GROESTL_64 + for (u = 0; u < 8; u ++) + enc64e(pad + (u << 3), H[u + 8]); +#else + for (u = 0; u < 16; u ++) + enc32e(pad + (u << 2), H[u + 16]); +#endif + memcpy(dst, pad + 64 - out_len, out_len); + groestl_big_init(sc, (unsigned)out_len << 3); +} + +/* see sph_groestl.h */ +void +sph_groestl224_init(void *cc) +{ + groestl_small_init(cc, 224); +} + +/* see sph_groestl.h */ +void +sph_groestl224(void *cc, const void *data, size_t len) +{ + groestl_small_core(cc, data, len); +} + +/* see sph_groestl.h */ +void +sph_groestl224_close(void *cc, void *dst) +{ + groestl_small_close(cc, 0, 0, dst, 28); +} + +/* see sph_groestl.h */ +void +sph_groestl224_addbits_and_close(void *cc, unsigned ub, unsigned n, void *dst) +{ + groestl_small_close(cc, ub, n, dst, 28); +} + +/* see sph_groestl.h */ +void +sph_groestl256_init(void *cc) +{ + groestl_small_init(cc, 256); +} + +/* see sph_groestl.h */ +void +sph_groestl256(void *cc, const void *data, size_t len) +{ + groestl_small_core(cc, data, len); +} + +/* see sph_groestl.h */ +void +sph_groestl256_close(void *cc, void *dst) +{ + groestl_small_close(cc, 0, 0, dst, 32); +} + +/* see sph_groestl.h */ +void +sph_groestl256_addbits_and_close(void *cc, unsigned ub, unsigned n, void *dst) +{ + groestl_small_close(cc, ub, n, dst, 32); +} + +/* see sph_groestl.h */ +void +sph_groestl384_init(void *cc) +{ + groestl_big_init(cc, 384); +} + +/* see sph_groestl.h */ +void +sph_groestl384(void *cc, const void *data, size_t len) +{ + groestl_big_core(cc, data, len); +} + +/* see sph_groestl.h */ +void +sph_groestl384_close(void *cc, void *dst) +{ + groestl_big_close(cc, 0, 0, dst, 48); +} + +/* see sph_groestl.h */ +void +sph_groestl384_addbits_and_close(void *cc, unsigned ub, unsigned n, void *dst) +{ + groestl_big_close(cc, ub, n, dst, 48); +} + +/* see sph_groestl.h */ +void +sph_groestl512_init(void *cc) +{ + groestl_big_init(cc, 512); +} + +/* see sph_groestl.h */ +void +sph_groestl512(void *cc, const void *data, size_t len) +{ + groestl_big_core(cc, data, len); +} + +/* see sph_groestl.h */ +void +sph_groestl512_close(void *cc, void *dst) +{ + groestl_big_close(cc, 0, 0, dst, 64); +} + +/* see sph_groestl.h */ +void +sph_groestl512_addbits_and_close(void *cc, unsigned ub, unsigned n, void *dst) +{ + groestl_big_close(cc, ub, n, dst, 64); +} + +#ifdef __cplusplus +} +#endif diff --git a/src/hamsi.c b/src/hamsi.c new file mode 100644 index 0000000..5e5fdd0 --- /dev/null +++ b/src/hamsi.c @@ -0,0 +1,867 @@ +/* $Id: hamsi.c 251 2010-10-19 14:31:51Z tp $ */ +/* + * Hamsi implementation. + * + * ==========================(LICENSE BEGIN)============================ + * + * Copyright (c) 2007-2010 Projet RNRT SAPHIR + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * ===========================(LICENSE END)============================= + * + * @author Thomas Pornin + */ + +#include +#include + +#include "sph_hamsi.h" + +#ifdef __cplusplus +extern "C"{ +#endif + +#if SPH_SMALL_FOOTPRINT && !defined SPH_SMALL_FOOTPRINT_HAMSI +#define SPH_SMALL_FOOTPRINT_HAMSI 1 +#endif + +/* + * The SPH_HAMSI_EXPAND_* define how many input bits we handle in one + * table lookup during message expansion (1 to 8, inclusive). If we note + * w the number of bits per message word (w=32 for Hamsi-224/256, w=64 + * for Hamsi-384/512), r the size of a "row" in 32-bit words (r=8 for + * Hamsi-224/256, r=16 for Hamsi-384/512), and n the expansion level, + * then we will get t tables (where t=ceil(w/n)) of individual size + * 2^n*r*4 (in bytes). The last table may be shorter (e.g. with w=32 and + * n=5, there are 7 tables, but the last one uses only two bits on + * input, not five). + * + * Also, we read t rows of r words from RAM. Words in a given row are + * concatenated in RAM in that order, so most of the cost is about + * reading the first row word; comparatively, cache misses are thus + * less expensive with Hamsi-512 (r=16) than with Hamsi-256 (r=8). + * + * When n=1, tables are "special" in that we omit the first entry of + * each table (which always contains 0), so that total table size is + * halved. + * + * We thus have the following (size1 is the cumulative table size of + * Hamsi-224/256; size2 is for Hamsi-384/512; similarly, t1 and t2 + * are for Hamsi-224/256 and Hamsi-384/512, respectively). + * + * n size1 size2 t1 t2 + * --------------------------------------- + * 1 1024 4096 32 64 + * 2 2048 8192 16 32 + * 3 2688 10880 11 22 + * 4 4096 16384 8 16 + * 5 6272 25600 7 13 + * 6 10368 41984 6 11 + * 7 16896 73856 5 10 + * 8 32768 131072 4 8 + * + * So there is a trade-off: a lower n makes the tables fit better in + * L1 cache, but increases the number of memory accesses. The optimal + * value depends on the amount of available L1 cache and the relative + * impact of a cache miss. + * + * Experimentally, in ideal benchmark conditions (which are not necessarily + * realistic with regards to L1 cache contention), it seems that n=8 is + * the best value on "big" architectures (those with 32 kB or more of L1 + * cache), while n=4 is better on "small" architectures. This was tested + * on an Intel Core2 Q6600 (both 32-bit and 64-bit mode), a PowerPC G3 + * (32 kB L1 cache, hence "big"), and a MIPS-compatible Broadcom BCM3302 + * (8 kB L1 cache). + * + * Note: with n=1, the 32 tables (actually implemented as one big table) + * are read entirely and sequentially, regardless of the input data, + * thus avoiding any data-dependent table access pattern. + */ + +#if !defined SPH_HAMSI_EXPAND_SMALL +#if SPH_SMALL_FOOTPRINT_HAMSI +#define SPH_HAMSI_EXPAND_SMALL 4 +#else +#define SPH_HAMSI_EXPAND_SMALL 8 +#endif +#endif + +#if !defined SPH_HAMSI_EXPAND_BIG +#define SPH_HAMSI_EXPAND_BIG 8 +#endif + +#ifdef _MSC_VER +#pragma warning (disable: 4146) +#endif + +#include "hamsi_helper.c" + +static const sph_u32 IV224[] = { + SPH_C32(0xc3967a67), SPH_C32(0xc3bc6c20), SPH_C32(0x4bc3bcc3), + SPH_C32(0xa7c3bc6b), SPH_C32(0x2c204b61), SPH_C32(0x74686f6c), + SPH_C32(0x69656b65), SPH_C32(0x20556e69) +}; + +/* + * This version is the one used in the Hamsi submission package for + * round 2 of the SHA-3 competition; the UTF-8 encoding is wrong and + * shall soon be corrected in the official Hamsi specification. + * +static const sph_u32 IV224[] = { + SPH_C32(0x3c967a67), SPH_C32(0x3cbc6c20), SPH_C32(0xb4c343c3), + SPH_C32(0xa73cbc6b), SPH_C32(0x2c204b61), SPH_C32(0x74686f6c), + SPH_C32(0x69656b65), SPH_C32(0x20556e69) +}; + */ + +static const sph_u32 IV256[] = { + SPH_C32(0x76657273), SPH_C32(0x69746569), SPH_C32(0x74204c65), + SPH_C32(0x7576656e), SPH_C32(0x2c204465), SPH_C32(0x70617274), + SPH_C32(0x656d656e), SPH_C32(0x7420456c) +}; + +static const sph_u32 IV384[] = { + SPH_C32(0x656b7472), SPH_C32(0x6f746563), SPH_C32(0x686e6965), + SPH_C32(0x6b2c2043), SPH_C32(0x6f6d7075), SPH_C32(0x74657220), + SPH_C32(0x53656375), SPH_C32(0x72697479), SPH_C32(0x20616e64), + SPH_C32(0x20496e64), SPH_C32(0x75737472), SPH_C32(0x69616c20), + SPH_C32(0x43727970), SPH_C32(0x746f6772), SPH_C32(0x61706879), + SPH_C32(0x2c204b61) +}; + +static const sph_u32 IV512[] = { + SPH_C32(0x73746565), SPH_C32(0x6c706172), SPH_C32(0x6b204172), + SPH_C32(0x656e6265), SPH_C32(0x72672031), SPH_C32(0x302c2062), + SPH_C32(0x75732032), SPH_C32(0x3434362c), SPH_C32(0x20422d33), + SPH_C32(0x30303120), SPH_C32(0x4c657576), SPH_C32(0x656e2d48), + SPH_C32(0x65766572), SPH_C32(0x6c65652c), SPH_C32(0x2042656c), + SPH_C32(0x6769756d) +}; + +static const sph_u32 alpha_n[] = { + SPH_C32(0xff00f0f0), SPH_C32(0xccccaaaa), SPH_C32(0xf0f0cccc), + SPH_C32(0xff00aaaa), SPH_C32(0xccccaaaa), SPH_C32(0xf0f0ff00), + SPH_C32(0xaaaacccc), SPH_C32(0xf0f0ff00), SPH_C32(0xf0f0cccc), + SPH_C32(0xaaaaff00), SPH_C32(0xccccff00), SPH_C32(0xaaaaf0f0), + SPH_C32(0xaaaaf0f0), SPH_C32(0xff00cccc), SPH_C32(0xccccf0f0), + SPH_C32(0xff00aaaa), SPH_C32(0xccccaaaa), SPH_C32(0xff00f0f0), + SPH_C32(0xff00aaaa), SPH_C32(0xf0f0cccc), SPH_C32(0xf0f0ff00), + SPH_C32(0xccccaaaa), SPH_C32(0xf0f0ff00), SPH_C32(0xaaaacccc), + SPH_C32(0xaaaaff00), SPH_C32(0xf0f0cccc), SPH_C32(0xaaaaf0f0), + SPH_C32(0xccccff00), SPH_C32(0xff00cccc), SPH_C32(0xaaaaf0f0), + SPH_C32(0xff00aaaa), SPH_C32(0xccccf0f0) +}; + +static const sph_u32 alpha_f[] = { + SPH_C32(0xcaf9639c), SPH_C32(0x0ff0f9c0), SPH_C32(0x639c0ff0), + SPH_C32(0xcaf9f9c0), SPH_C32(0x0ff0f9c0), SPH_C32(0x639ccaf9), + SPH_C32(0xf9c00ff0), SPH_C32(0x639ccaf9), SPH_C32(0x639c0ff0), + SPH_C32(0xf9c0caf9), SPH_C32(0x0ff0caf9), SPH_C32(0xf9c0639c), + SPH_C32(0xf9c0639c), SPH_C32(0xcaf90ff0), SPH_C32(0x0ff0639c), + SPH_C32(0xcaf9f9c0), SPH_C32(0x0ff0f9c0), SPH_C32(0xcaf9639c), + SPH_C32(0xcaf9f9c0), SPH_C32(0x639c0ff0), SPH_C32(0x639ccaf9), + SPH_C32(0x0ff0f9c0), SPH_C32(0x639ccaf9), SPH_C32(0xf9c00ff0), + SPH_C32(0xf9c0caf9), SPH_C32(0x639c0ff0), SPH_C32(0xf9c0639c), + SPH_C32(0x0ff0caf9), SPH_C32(0xcaf90ff0), SPH_C32(0xf9c0639c), + SPH_C32(0xcaf9f9c0), SPH_C32(0x0ff0639c) +}; + +#define DECL_STATE_SMALL \ + sph_u32 c0, c1, c2, c3, c4, c5, c6, c7; + +#define READ_STATE_SMALL(sc) do { \ + c0 = sc->h[0x0]; \ + c1 = sc->h[0x1]; \ + c2 = sc->h[0x2]; \ + c3 = sc->h[0x3]; \ + c4 = sc->h[0x4]; \ + c5 = sc->h[0x5]; \ + c6 = sc->h[0x6]; \ + c7 = sc->h[0x7]; \ + } while (0) + +#define WRITE_STATE_SMALL(sc) do { \ + sc->h[0x0] = c0; \ + sc->h[0x1] = c1; \ + sc->h[0x2] = c2; \ + sc->h[0x3] = c3; \ + sc->h[0x4] = c4; \ + sc->h[0x5] = c5; \ + sc->h[0x6] = c6; \ + sc->h[0x7] = c7; \ + } while (0) + +#define s0 m0 +#define s1 m1 +#define s2 c0 +#define s3 c1 +#define s4 c2 +#define s5 c3 +#define s6 m2 +#define s7 m3 +#define s8 m4 +#define s9 m5 +#define sA c4 +#define sB c5 +#define sC c6 +#define sD c7 +#define sE m6 +#define sF m7 + +#define SBOX(a, b, c, d) do { \ + sph_u32 t; \ + t = (a); \ + (a) &= (c); \ + (a) ^= (d); \ + (c) ^= (b); \ + (c) ^= (a); \ + (d) |= t; \ + (d) ^= (b); \ + t ^= (c); \ + (b) = (d); \ + (d) |= t; \ + (d) ^= (a); \ + (a) &= (b); \ + t ^= (a); \ + (b) ^= (d); \ + (b) ^= t; \ + (a) = (c); \ + (c) = (b); \ + (b) = (d); \ + (d) = SPH_T32(~t); \ + } while (0) + +#define L(a, b, c, d) do { \ + (a) = SPH_ROTL32(a, 13); \ + (c) = SPH_ROTL32(c, 3); \ + (b) ^= (a) ^ (c); \ + (d) ^= (c) ^ SPH_T32((a) << 3); \ + (b) = SPH_ROTL32(b, 1); \ + (d) = SPH_ROTL32(d, 7); \ + (a) ^= (b) ^ (d); \ + (c) ^= (d) ^ SPH_T32((b) << 7); \ + (a) = SPH_ROTL32(a, 5); \ + (c) = SPH_ROTL32(c, 22); \ + } while (0) + +#define ROUND_SMALL(rc, alpha) do { \ + s0 ^= alpha[0x00]; \ + s1 ^= alpha[0x01] ^ (sph_u32)(rc); \ + s2 ^= alpha[0x02]; \ + s3 ^= alpha[0x03]; \ + s4 ^= alpha[0x08]; \ + s5 ^= alpha[0x09]; \ + s6 ^= alpha[0x0A]; \ + s7 ^= alpha[0x0B]; \ + s8 ^= alpha[0x10]; \ + s9 ^= alpha[0x11]; \ + sA ^= alpha[0x12]; \ + sB ^= alpha[0x13]; \ + sC ^= alpha[0x18]; \ + sD ^= alpha[0x19]; \ + sE ^= alpha[0x1A]; \ + sF ^= alpha[0x1B]; \ + SBOX(s0, s4, s8, sC); \ + SBOX(s1, s5, s9, sD); \ + SBOX(s2, s6, sA, sE); \ + SBOX(s3, s7, sB, sF); \ + L(s0, s5, sA, sF); \ + L(s1, s6, sB, sC); \ + L(s2, s7, s8, sD); \ + L(s3, s4, s9, sE); \ + } while (0) + +#define P_SMALL do { \ + ROUND_SMALL(0, alpha_n); \ + ROUND_SMALL(1, alpha_n); \ + ROUND_SMALL(2, alpha_n); \ + } while (0) + +#define PF_SMALL do { \ + ROUND_SMALL(0, alpha_f); \ + ROUND_SMALL(1, alpha_f); \ + ROUND_SMALL(2, alpha_f); \ + ROUND_SMALL(3, alpha_f); \ + ROUND_SMALL(4, alpha_f); \ + ROUND_SMALL(5, alpha_f); \ + } while (0) + +#define T_SMALL do { \ + /* order is important */ \ + c7 = (sc->h[7] ^= sB); \ + c6 = (sc->h[6] ^= sA); \ + c5 = (sc->h[5] ^= s9); \ + c4 = (sc->h[4] ^= s8); \ + c3 = (sc->h[3] ^= s3); \ + c2 = (sc->h[2] ^= s2); \ + c1 = (sc->h[1] ^= s1); \ + c0 = (sc->h[0] ^= s0); \ + } while (0) + +static void +hamsi_small(sph_hamsi_small_context *sc, const unsigned char *buf, size_t num) +{ + DECL_STATE_SMALL +#if !SPH_64 + sph_u32 tmp; +#endif + +#if SPH_64 + sc->count += (sph_u64)num << 5; +#else + tmp = SPH_T32((sph_u32)num << 5); + sc->count_low = SPH_T32(sc->count_low + tmp); + sc->count_high += (sph_u32)((num >> 13) >> 14); + if (sc->count_low < tmp) + sc->count_high ++; +#endif + READ_STATE_SMALL(sc); + while (num -- > 0) { + sph_u32 m0, m1, m2, m3, m4, m5, m6, m7; + + INPUT_SMALL; + P_SMALL; + T_SMALL; + buf += 4; + } + WRITE_STATE_SMALL(sc); +} + +static void +hamsi_small_final(sph_hamsi_small_context *sc, const unsigned char *buf) +{ + sph_u32 m0, m1, m2, m3, m4, m5, m6, m7; + DECL_STATE_SMALL + + READ_STATE_SMALL(sc); + INPUT_SMALL; + PF_SMALL; + T_SMALL; + WRITE_STATE_SMALL(sc); +} + +static void +hamsi_small_init(sph_hamsi_small_context *sc, const sph_u32 *iv) +{ + sc->partial_len = 0; + memcpy(sc->h, iv, sizeof sc->h); +#if SPH_64 + sc->count = 0; +#else + sc->count_high = sc->count_low = 0; +#endif +} + +static void +hamsi_small_core(sph_hamsi_small_context *sc, const void *data, size_t len) +{ + if (sc->partial_len != 0) { + size_t mlen; + + mlen = 4 - sc->partial_len; + if (len < mlen) { + memcpy(sc->partial + sc->partial_len, data, len); + sc->partial_len += len; + return; + } else { + memcpy(sc->partial + sc->partial_len, data, mlen); + len -= mlen; + data = (const unsigned char *)data + mlen; + hamsi_small(sc, sc->partial, 1); + sc->partial_len = 0; + } + } + + hamsi_small(sc, data, (len >> 2)); + data = (const unsigned char *)data + (len & ~(size_t)3); + len &= (size_t)3; + memcpy(sc->partial, data, len); + sc->partial_len = len; +} + +static void +hamsi_small_close(sph_hamsi_small_context *sc, + unsigned ub, unsigned n, void *dst, size_t out_size_w32) +{ + unsigned char pad[12]; + size_t ptr, u; + unsigned z; + unsigned char *out; + + ptr = sc->partial_len; + memcpy(pad, sc->partial, ptr); +#if SPH_64 + sph_enc64be(pad + 4, sc->count + (ptr << 3) + n); +#else + sph_enc32be(pad + 4, sc->count_high); + sph_enc32be(pad + 8, sc->count_low + (ptr << 3) + n); +#endif + z = 0x80 >> n; + pad[ptr ++] = ((ub & -z) | z) & 0xFF; + while (ptr < 4) + pad[ptr ++] = 0; + hamsi_small(sc, pad, 2); + hamsi_small_final(sc, pad + 8); + out = dst; + for (u = 0; u < out_size_w32; u ++) + sph_enc32be(out + (u << 2), sc->h[u]); +} + +#define DECL_STATE_BIG \ + sph_u32 c0, c1, c2, c3, c4, c5, c6, c7; \ + sph_u32 c8, c9, cA, cB, cC, cD, cE, cF; + +#define READ_STATE_BIG(sc) do { \ + c0 = sc->h[0x0]; \ + c1 = sc->h[0x1]; \ + c2 = sc->h[0x2]; \ + c3 = sc->h[0x3]; \ + c4 = sc->h[0x4]; \ + c5 = sc->h[0x5]; \ + c6 = sc->h[0x6]; \ + c7 = sc->h[0x7]; \ + c8 = sc->h[0x8]; \ + c9 = sc->h[0x9]; \ + cA = sc->h[0xA]; \ + cB = sc->h[0xB]; \ + cC = sc->h[0xC]; \ + cD = sc->h[0xD]; \ + cE = sc->h[0xE]; \ + cF = sc->h[0xF]; \ + } while (0) + +#define WRITE_STATE_BIG(sc) do { \ + sc->h[0x0] = c0; \ + sc->h[0x1] = c1; \ + sc->h[0x2] = c2; \ + sc->h[0x3] = c3; \ + sc->h[0x4] = c4; \ + sc->h[0x5] = c5; \ + sc->h[0x6] = c6; \ + sc->h[0x7] = c7; \ + sc->h[0x8] = c8; \ + sc->h[0x9] = c9; \ + sc->h[0xA] = cA; \ + sc->h[0xB] = cB; \ + sc->h[0xC] = cC; \ + sc->h[0xD] = cD; \ + sc->h[0xE] = cE; \ + sc->h[0xF] = cF; \ + } while (0) + +#define s00 m0 +#define s01 m1 +#define s02 c0 +#define s03 c1 +#define s04 m2 +#define s05 m3 +#define s06 c2 +#define s07 c3 +#define s08 c4 +#define s09 c5 +#define s0A m4 +#define s0B m5 +#define s0C c6 +#define s0D c7 +#define s0E m6 +#define s0F m7 +#define s10 m8 +#define s11 m9 +#define s12 c8 +#define s13 c9 +#define s14 mA +#define s15 mB +#define s16 cA +#define s17 cB +#define s18 cC +#define s19 cD +#define s1A mC +#define s1B mD +#define s1C cE +#define s1D cF +#define s1E mE +#define s1F mF + +#define ROUND_BIG(rc, alpha) do { \ + s00 ^= alpha[0x00]; \ + s01 ^= alpha[0x01] ^ (sph_u32)(rc); \ + s02 ^= alpha[0x02]; \ + s03 ^= alpha[0x03]; \ + s04 ^= alpha[0x04]; \ + s05 ^= alpha[0x05]; \ + s06 ^= alpha[0x06]; \ + s07 ^= alpha[0x07]; \ + s08 ^= alpha[0x08]; \ + s09 ^= alpha[0x09]; \ + s0A ^= alpha[0x0A]; \ + s0B ^= alpha[0x0B]; \ + s0C ^= alpha[0x0C]; \ + s0D ^= alpha[0x0D]; \ + s0E ^= alpha[0x0E]; \ + s0F ^= alpha[0x0F]; \ + s10 ^= alpha[0x10]; \ + s11 ^= alpha[0x11]; \ + s12 ^= alpha[0x12]; \ + s13 ^= alpha[0x13]; \ + s14 ^= alpha[0x14]; \ + s15 ^= alpha[0x15]; \ + s16 ^= alpha[0x16]; \ + s17 ^= alpha[0x17]; \ + s18 ^= alpha[0x18]; \ + s19 ^= alpha[0x19]; \ + s1A ^= alpha[0x1A]; \ + s1B ^= alpha[0x1B]; \ + s1C ^= alpha[0x1C]; \ + s1D ^= alpha[0x1D]; \ + s1E ^= alpha[0x1E]; \ + s1F ^= alpha[0x1F]; \ + SBOX(s00, s08, s10, s18); \ + SBOX(s01, s09, s11, s19); \ + SBOX(s02, s0A, s12, s1A); \ + SBOX(s03, s0B, s13, s1B); \ + SBOX(s04, s0C, s14, s1C); \ + SBOX(s05, s0D, s15, s1D); \ + SBOX(s06, s0E, s16, s1E); \ + SBOX(s07, s0F, s17, s1F); \ + L(s00, s09, s12, s1B); \ + L(s01, s0A, s13, s1C); \ + L(s02, s0B, s14, s1D); \ + L(s03, s0C, s15, s1E); \ + L(s04, s0D, s16, s1F); \ + L(s05, s0E, s17, s18); \ + L(s06, s0F, s10, s19); \ + L(s07, s08, s11, s1A); \ + L(s00, s02, s05, s07); \ + L(s10, s13, s15, s16); \ + L(s09, s0B, s0C, s0E); \ + L(s19, s1A, s1C, s1F); \ + } while (0) + +#if SPH_SMALL_FOOTPRINT_HAMSI + +#define P_BIG do { \ + unsigned r; \ + for (r = 0; r < 6; r ++) \ + ROUND_BIG(r, alpha_n); \ + } while (0) + +#define PF_BIG do { \ + unsigned r; \ + for (r = 0; r < 12; r ++) \ + ROUND_BIG(r, alpha_f); \ + } while (0) + +#else + +#define P_BIG do { \ + ROUND_BIG(0, alpha_n); \ + ROUND_BIG(1, alpha_n); \ + ROUND_BIG(2, alpha_n); \ + ROUND_BIG(3, alpha_n); \ + ROUND_BIG(4, alpha_n); \ + ROUND_BIG(5, alpha_n); \ + } while (0) + +#define PF_BIG do { \ + ROUND_BIG(0, alpha_f); \ + ROUND_BIG(1, alpha_f); \ + ROUND_BIG(2, alpha_f); \ + ROUND_BIG(3, alpha_f); \ + ROUND_BIG(4, alpha_f); \ + ROUND_BIG(5, alpha_f); \ + ROUND_BIG(6, alpha_f); \ + ROUND_BIG(7, alpha_f); \ + ROUND_BIG(8, alpha_f); \ + ROUND_BIG(9, alpha_f); \ + ROUND_BIG(10, alpha_f); \ + ROUND_BIG(11, alpha_f); \ + } while (0) + +#endif + +#define T_BIG do { \ + /* order is important */ \ + cF = (sc->h[0xF] ^= s17); \ + cE = (sc->h[0xE] ^= s16); \ + cD = (sc->h[0xD] ^= s15); \ + cC = (sc->h[0xC] ^= s14); \ + cB = (sc->h[0xB] ^= s13); \ + cA = (sc->h[0xA] ^= s12); \ + c9 = (sc->h[0x9] ^= s11); \ + c8 = (sc->h[0x8] ^= s10); \ + c7 = (sc->h[0x7] ^= s07); \ + c6 = (sc->h[0x6] ^= s06); \ + c5 = (sc->h[0x5] ^= s05); \ + c4 = (sc->h[0x4] ^= s04); \ + c3 = (sc->h[0x3] ^= s03); \ + c2 = (sc->h[0x2] ^= s02); \ + c1 = (sc->h[0x1] ^= s01); \ + c0 = (sc->h[0x0] ^= s00); \ + } while (0) + +static void +hamsi_big(sph_hamsi_big_context *sc, const unsigned char *buf, size_t num) +{ + DECL_STATE_BIG +#if !SPH_64 + sph_u32 tmp; +#endif + +#if SPH_64 + sc->count += (sph_u64)num << 6; +#else + tmp = SPH_T32((sph_u32)num << 6); + sc->count_low = SPH_T32(sc->count_low + tmp); + sc->count_high += (sph_u32)((num >> 13) >> 13); + if (sc->count_low < tmp) + sc->count_high ++; +#endif + READ_STATE_BIG(sc); + while (num -- > 0) { + sph_u32 m0, m1, m2, m3, m4, m5, m6, m7; + sph_u32 m8, m9, mA, mB, mC, mD, mE, mF; + + INPUT_BIG; + P_BIG; + T_BIG; + buf += 8; + } + WRITE_STATE_BIG(sc); +} + +static void +hamsi_big_final(sph_hamsi_big_context *sc, const unsigned char *buf) +{ + sph_u32 m0, m1, m2, m3, m4, m5, m6, m7; + sph_u32 m8, m9, mA, mB, mC, mD, mE, mF; + DECL_STATE_BIG + + READ_STATE_BIG(sc); + INPUT_BIG; + PF_BIG; + T_BIG; + WRITE_STATE_BIG(sc); +} + +static void +hamsi_big_init(sph_hamsi_big_context *sc, const sph_u32 *iv) +{ + sc->partial_len = 0; + memcpy(sc->h, iv, sizeof sc->h); +#if SPH_64 + sc->count = 0; +#else + sc->count_high = sc->count_low = 0; +#endif +} + +static void +hamsi_big_core(sph_hamsi_big_context *sc, const void *data, size_t len) +{ + if (sc->partial_len != 0) { + size_t mlen; + + mlen = 8 - sc->partial_len; + if (len < mlen) { + memcpy(sc->partial + sc->partial_len, data, len); + sc->partial_len += len; + return; + } else { + memcpy(sc->partial + sc->partial_len, data, mlen); + len -= mlen; + data = (const unsigned char *)data + mlen; + hamsi_big(sc, sc->partial, 1); + sc->partial_len = 0; + } + } + + hamsi_big(sc, data, (len >> 3)); + data = (const unsigned char *)data + (len & ~(size_t)7); + len &= (size_t)7; + memcpy(sc->partial, data, len); + sc->partial_len = len; +} + +static void +hamsi_big_close(sph_hamsi_big_context *sc, + unsigned ub, unsigned n, void *dst, size_t out_size_w32) +{ + unsigned char pad[8]; + size_t ptr, u; + unsigned z; + unsigned char *out; + + ptr = sc->partial_len; +#if SPH_64 + sph_enc64be(pad, sc->count + (ptr << 3) + n); +#else + sph_enc32be(pad, sc->count_high); + sph_enc32be(pad + 4, sc->count_low + (ptr << 3) + n); +#endif + z = 0x80 >> n; + sc->partial[ptr ++] = ((ub & -z) | z) & 0xFF; + while (ptr < 8) + sc->partial[ptr ++] = 0; + hamsi_big(sc, sc->partial, 1); + hamsi_big_final(sc, pad); + out = dst; + if (out_size_w32 == 12) { + sph_enc32be(out + 0, sc->h[ 0]); + sph_enc32be(out + 4, sc->h[ 1]); + sph_enc32be(out + 8, sc->h[ 3]); + sph_enc32be(out + 12, sc->h[ 4]); + sph_enc32be(out + 16, sc->h[ 5]); + sph_enc32be(out + 20, sc->h[ 6]); + sph_enc32be(out + 24, sc->h[ 8]); + sph_enc32be(out + 28, sc->h[ 9]); + sph_enc32be(out + 32, sc->h[10]); + sph_enc32be(out + 36, sc->h[12]); + sph_enc32be(out + 40, sc->h[13]); + sph_enc32be(out + 44, sc->h[15]); + } else { + for (u = 0; u < 16; u ++) + sph_enc32be(out + (u << 2), sc->h[u]); + } +} + +/* see sph_hamsi.h */ +void +sph_hamsi224_init(void *cc) +{ + hamsi_small_init(cc, IV224); +} + +/* see sph_hamsi.h */ +void +sph_hamsi224(void *cc, const void *data, size_t len) +{ + hamsi_small_core(cc, data, len); +} + +/* see sph_hamsi.h */ +void +sph_hamsi224_close(void *cc, void *dst) +{ + hamsi_small_close(cc, 0, 0, dst, 7); + hamsi_small_init(cc, IV224); +} + +/* see sph_hamsi.h */ +void +sph_hamsi224_addbits_and_close(void *cc, unsigned ub, unsigned n, void *dst) +{ + hamsi_small_close(cc, ub, n, dst, 7); + hamsi_small_init(cc, IV224); +} + +/* see sph_hamsi.h */ +void +sph_hamsi256_init(void *cc) +{ + hamsi_small_init(cc, IV256); +} + +/* see sph_hamsi.h */ +void +sph_hamsi256(void *cc, const void *data, size_t len) +{ + hamsi_small_core(cc, data, len); +} + +/* see sph_hamsi.h */ +void +sph_hamsi256_close(void *cc, void *dst) +{ + hamsi_small_close(cc, 0, 0, dst, 8); + hamsi_small_init(cc, IV256); +} + +/* see sph_hamsi.h */ +void +sph_hamsi256_addbits_and_close(void *cc, unsigned ub, unsigned n, void *dst) +{ + hamsi_small_close(cc, ub, n, dst, 8); + hamsi_small_init(cc, IV256); +} + +/* see sph_hamsi.h */ +void +sph_hamsi384_init(void *cc) +{ + hamsi_big_init(cc, IV384); +} + +/* see sph_hamsi.h */ +void +sph_hamsi384(void *cc, const void *data, size_t len) +{ + hamsi_big_core(cc, data, len); +} + +/* see sph_hamsi.h */ +void +sph_hamsi384_close(void *cc, void *dst) +{ + hamsi_big_close(cc, 0, 0, dst, 12); + hamsi_big_init(cc, IV384); +} + +/* see sph_hamsi.h */ +void +sph_hamsi384_addbits_and_close(void *cc, unsigned ub, unsigned n, void *dst) +{ + hamsi_big_close(cc, ub, n, dst, 12); + hamsi_big_init(cc, IV384); +} + +/* see sph_hamsi.h */ +void +sph_hamsi512_init(void *cc) +{ + hamsi_big_init(cc, IV512); +} + +/* see sph_hamsi.h */ +void +sph_hamsi512(void *cc, const void *data, size_t len) +{ + hamsi_big_core(cc, data, len); +} + +/* see sph_hamsi.h */ +void +sph_hamsi512_close(void *cc, void *dst) +{ + hamsi_big_close(cc, 0, 0, dst, 16); + hamsi_big_init(cc, IV512); +} + +/* see sph_hamsi.h */ +void +sph_hamsi512_addbits_and_close(void *cc, unsigned ub, unsigned n, void *dst) +{ + hamsi_big_close(cc, ub, n, dst, 16); + hamsi_big_init(cc, IV512); +} + +#ifdef __cplusplus +} +#endif diff --git a/src/hamsi_helper.c b/src/hamsi_helper.c new file mode 100644 index 0000000..9f8231b --- /dev/null +++ b/src/hamsi_helper.c @@ -0,0 +1,39648 @@ +/* $Id: hamsi_helper.c 202 2010-05-31 15:46:48Z tp $ */ +/* + * Helper code for Hamsi (input block expansion). This code is + * automatically generated and includes precomputed tables for + * expansion code which handles 2 to 8 bits at a time. + * + * This file is included from hamsi.c, and is not meant to be compiled + * independently. + * + * ==========================(LICENSE BEGIN)============================ + * + * Copyright (c) 2007-2010 Projet RNRT SAPHIR + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * ===========================(LICENSE END)============================= + * + * @author Thomas Pornin + */ + +#ifdef __cplusplus +extern "C"{ +#endif + +#if SPH_HAMSI_EXPAND_SMALL == 1 + +/* Note: this table lists bits within each byte from least + siginificant to most significant. */ +static const sph_u32 T256[32][8] = { + { SPH_C32(0x74951000), SPH_C32(0x5a2b467e), SPH_C32(0x88fd1d2b), + SPH_C32(0x1ee68292), SPH_C32(0xcba90000), SPH_C32(0x90273769), + SPH_C32(0xbbdcf407), SPH_C32(0xd0f4af61) }, + { SPH_C32(0xcba90000), SPH_C32(0x90273769), SPH_C32(0xbbdcf407), + SPH_C32(0xd0f4af61), SPH_C32(0xbf3c1000), SPH_C32(0xca0c7117), + SPH_C32(0x3321e92c), SPH_C32(0xce122df3) }, + { SPH_C32(0xe92a2000), SPH_C32(0xb4578cfc), SPH_C32(0x11fa3a57), + SPH_C32(0x3dc90524), SPH_C32(0x97530000), SPH_C32(0x204f6ed3), + SPH_C32(0x77b9e80f), SPH_C32(0xa1ec5ec1) }, + { SPH_C32(0x97530000), SPH_C32(0x204f6ed3), SPH_C32(0x77b9e80f), + SPH_C32(0xa1ec5ec1), SPH_C32(0x7e792000), SPH_C32(0x9418e22f), + SPH_C32(0x6643d258), SPH_C32(0x9c255be5) }, + { SPH_C32(0x121b4000), SPH_C32(0x5b17d9e8), SPH_C32(0x8dfacfab), + SPH_C32(0xce36cc72), SPH_C32(0xe6570000), SPH_C32(0x4bb33a25), + SPH_C32(0x848598ba), SPH_C32(0x1041003e) }, + { SPH_C32(0xe6570000), SPH_C32(0x4bb33a25), SPH_C32(0x848598ba), + SPH_C32(0x1041003e), SPH_C32(0xf44c4000), SPH_C32(0x10a4e3cd), + SPH_C32(0x097f5711), SPH_C32(0xde77cc4c) }, + { SPH_C32(0xe4788000), SPH_C32(0x859673c1), SPH_C32(0xb5fb2452), + SPH_C32(0x29cc5edf), SPH_C32(0x045f0000), SPH_C32(0x9c4a93c9), + SPH_C32(0x62fc79d0), SPH_C32(0x731ebdc2) }, + { SPH_C32(0x045f0000), SPH_C32(0x9c4a93c9), SPH_C32(0x62fc79d0), + SPH_C32(0x731ebdc2), SPH_C32(0xe0278000), SPH_C32(0x19dce008), + SPH_C32(0xd7075d82), SPH_C32(0x5ad2e31d) }, + { SPH_C32(0xb7a40100), SPH_C32(0x8a1f31d8), SPH_C32(0x8589d8ab), + SPH_C32(0xe6c46464), SPH_C32(0x734c0000), SPH_C32(0x956fa7d6), + SPH_C32(0xa29d1297), SPH_C32(0x6ee56854) }, + { SPH_C32(0x734c0000), SPH_C32(0x956fa7d6), SPH_C32(0xa29d1297), + SPH_C32(0x6ee56854), SPH_C32(0xc4e80100), SPH_C32(0x1f70960e), + SPH_C32(0x2714ca3c), SPH_C32(0x88210c30) }, + { SPH_C32(0xa7b80200), SPH_C32(0x1f128433), SPH_C32(0x60e5f9f2), + SPH_C32(0x9e147576), SPH_C32(0xee260000), SPH_C32(0x124b683e), + SPH_C32(0x80c2d68f), SPH_C32(0x3bf3ab2c) }, + { SPH_C32(0xee260000), SPH_C32(0x124b683e), SPH_C32(0x80c2d68f), + SPH_C32(0x3bf3ab2c), SPH_C32(0x499e0200), SPH_C32(0x0d59ec0d), + SPH_C32(0xe0272f7d), SPH_C32(0xa5e7de5a) }, + { SPH_C32(0x8f3e0400), SPH_C32(0x0d9dc877), SPH_C32(0x6fc548e1), + SPH_C32(0x898d2cd6), SPH_C32(0x14bd0000), SPH_C32(0x2fba37ff), + SPH_C32(0x6a72e5bb), SPH_C32(0x247febe6) }, + { SPH_C32(0x14bd0000), SPH_C32(0x2fba37ff), SPH_C32(0x6a72e5bb), + SPH_C32(0x247febe6), SPH_C32(0x9b830400), SPH_C32(0x2227ff88), + SPH_C32(0x05b7ad5a), SPH_C32(0xadf2c730) }, + { SPH_C32(0xde320800), SPH_C32(0x288350fe), SPH_C32(0x71852ac7), + SPH_C32(0xa6bf9f96), SPH_C32(0xe18b0000), SPH_C32(0x5459887d), + SPH_C32(0xbf1283d3), SPH_C32(0x1b666a73) }, + { SPH_C32(0xe18b0000), SPH_C32(0x5459887d), SPH_C32(0xbf1283d3), + SPH_C32(0x1b666a73), SPH_C32(0x3fb90800), SPH_C32(0x7cdad883), + SPH_C32(0xce97a914), SPH_C32(0xbdd9f5e5) }, + { SPH_C32(0x515c0010), SPH_C32(0x40f372fb), SPH_C32(0xfce72602), + SPH_C32(0x71575061), SPH_C32(0x2e390000), SPH_C32(0x64dd6689), + SPH_C32(0x3cd406fc), SPH_C32(0xb1f490bc) }, + { SPH_C32(0x2e390000), SPH_C32(0x64dd6689), SPH_C32(0x3cd406fc), + SPH_C32(0xb1f490bc), SPH_C32(0x7f650010), SPH_C32(0x242e1472), + SPH_C32(0xc03320fe), SPH_C32(0xc0a3c0dd) }, + { SPH_C32(0xa2b80020), SPH_C32(0x81e7e5f6), SPH_C32(0xf9ce4c04), + SPH_C32(0xe2afa0c0), SPH_C32(0x5c720000), SPH_C32(0xc9bacd12), + SPH_C32(0x79a90df9), SPH_C32(0x63e92178) }, + { SPH_C32(0x5c720000), SPH_C32(0xc9bacd12), SPH_C32(0x79a90df9), + SPH_C32(0x63e92178), SPH_C32(0xfeca0020), SPH_C32(0x485d28e4), + SPH_C32(0x806741fd), SPH_C32(0x814681b8) }, + { SPH_C32(0x4dce0040), SPH_C32(0x3b5bec7e), SPH_C32(0x36656ba8), + SPH_C32(0x23633a05), SPH_C32(0x78ab0000), SPH_C32(0xa0cd5a34), + SPH_C32(0x5d5ca0f7), SPH_C32(0x727784cb) }, + { SPH_C32(0x78ab0000), SPH_C32(0xa0cd5a34), SPH_C32(0x5d5ca0f7), + SPH_C32(0x727784cb), SPH_C32(0x35650040), SPH_C32(0x9b96b64a), + SPH_C32(0x6b39cb5f), SPH_C32(0x5114bece) }, + { SPH_C32(0x5bd20080), SPH_C32(0x450f18ec), SPH_C32(0xc2c46c55), + SPH_C32(0xf362b233), SPH_C32(0x39a60000), SPH_C32(0x4ab753eb), + SPH_C32(0xd14e094b), SPH_C32(0xb772b42b) }, + { SPH_C32(0x39a60000), SPH_C32(0x4ab753eb), SPH_C32(0xd14e094b), + SPH_C32(0xb772b42b), SPH_C32(0x62740080), SPH_C32(0x0fb84b07), + SPH_C32(0x138a651e), SPH_C32(0x44100618) }, + { SPH_C32(0xc04e0001), SPH_C32(0x33b9c010), SPH_C32(0xae0ebb05), + SPH_C32(0xb5a4c63b), SPH_C32(0xc8f10000), SPH_C32(0x0b2de782), + SPH_C32(0x6bf648a4), SPH_C32(0x539cbdbf) }, + { SPH_C32(0xc8f10000), SPH_C32(0x0b2de782), SPH_C32(0x6bf648a4), + SPH_C32(0x539cbdbf), SPH_C32(0x08bf0001), SPH_C32(0x38942792), + SPH_C32(0xc5f8f3a1), SPH_C32(0xe6387b84) }, + { SPH_C32(0x88230002), SPH_C32(0x5fe7a7b3), SPH_C32(0x99e585aa), + SPH_C32(0x8d75f7f1), SPH_C32(0x51ac0000), SPH_C32(0x25e30f14), + SPH_C32(0x79e22a4c), SPH_C32(0x1298bd46) }, + { SPH_C32(0x51ac0000), SPH_C32(0x25e30f14), SPH_C32(0x79e22a4c), + SPH_C32(0x1298bd46), SPH_C32(0xd98f0002), SPH_C32(0x7a04a8a7), + SPH_C32(0xe007afe6), SPH_C32(0x9fed4ab7) }, + { SPH_C32(0xd0080004), SPH_C32(0x8c768f77), SPH_C32(0x9dc5b050), + SPH_C32(0xaf4a29da), SPH_C32(0x6ba90000), SPH_C32(0x40ebf9aa), + SPH_C32(0x98321c3d), SPH_C32(0x76acc733) }, + { SPH_C32(0x6ba90000), SPH_C32(0x40ebf9aa), SPH_C32(0x98321c3d), + SPH_C32(0x76acc733), SPH_C32(0xbba10004), SPH_C32(0xcc9d76dd), + SPH_C32(0x05f7ac6d), SPH_C32(0xd9e6eee9) }, + { SPH_C32(0xa8ae0008), SPH_C32(0x2079397d), SPH_C32(0xfe739301), + SPH_C32(0xb8a92831), SPH_C32(0x171c0000), SPH_C32(0xb26e3344), + SPH_C32(0x9e6a837e), SPH_C32(0x58f8485f) }, + { SPH_C32(0x171c0000), SPH_C32(0xb26e3344), SPH_C32(0x9e6a837e), + SPH_C32(0x58f8485f), SPH_C32(0xbfb20008), SPH_C32(0x92170a39), + SPH_C32(0x6019107f), SPH_C32(0xe051606e) } +}; + +#define INPUT_SMALL do { \ + const sph_u32 *tp = &T256[0][0]; \ + unsigned u, v; \ + m0 = 0; \ + m1 = 0; \ + m2 = 0; \ + m3 = 0; \ + m4 = 0; \ + m5 = 0; \ + m6 = 0; \ + m7 = 0; \ + for (u = 0; u < 4; u ++) { \ + unsigned db = buf[u]; \ + for (v = 0; v < 8; v ++, db >>= 1) { \ + sph_u32 dm = SPH_T32(-(sph_u32)(db & 1)); \ + m0 ^= dm & *tp ++; \ + m1 ^= dm & *tp ++; \ + m2 ^= dm & *tp ++; \ + m3 ^= dm & *tp ++; \ + m4 ^= dm & *tp ++; \ + m5 ^= dm & *tp ++; \ + m6 ^= dm & *tp ++; \ + m7 ^= dm & *tp ++; \ + } \ + } \ + } while (0) + +#endif + +#if SPH_HAMSI_EXPAND_SMALL == 2 + +static const sph_u32 T256_0[4][8] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000) }, + { SPH_C32(0xe4788000), SPH_C32(0x859673c1), SPH_C32(0xb5fb2452), + SPH_C32(0x29cc5edf), SPH_C32(0x045f0000), SPH_C32(0x9c4a93c9), + SPH_C32(0x62fc79d0), SPH_C32(0x731ebdc2) }, + { SPH_C32(0x045f0000), SPH_C32(0x9c4a93c9), SPH_C32(0x62fc79d0), + SPH_C32(0x731ebdc2), SPH_C32(0xe0278000), SPH_C32(0x19dce008), + SPH_C32(0xd7075d82), SPH_C32(0x5ad2e31d) }, + { SPH_C32(0xe0278000), SPH_C32(0x19dce008), SPH_C32(0xd7075d82), + SPH_C32(0x5ad2e31d), SPH_C32(0xe4788000), SPH_C32(0x859673c1), + SPH_C32(0xb5fb2452), SPH_C32(0x29cc5edf) } +}; + +static const sph_u32 T256_2[4][8] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000) }, + { SPH_C32(0x121b4000), SPH_C32(0x5b17d9e8), SPH_C32(0x8dfacfab), + SPH_C32(0xce36cc72), SPH_C32(0xe6570000), SPH_C32(0x4bb33a25), + SPH_C32(0x848598ba), SPH_C32(0x1041003e) }, + { SPH_C32(0xe6570000), SPH_C32(0x4bb33a25), SPH_C32(0x848598ba), + SPH_C32(0x1041003e), SPH_C32(0xf44c4000), SPH_C32(0x10a4e3cd), + SPH_C32(0x097f5711), SPH_C32(0xde77cc4c) }, + { SPH_C32(0xf44c4000), SPH_C32(0x10a4e3cd), SPH_C32(0x097f5711), + SPH_C32(0xde77cc4c), SPH_C32(0x121b4000), SPH_C32(0x5b17d9e8), + SPH_C32(0x8dfacfab), SPH_C32(0xce36cc72) } +}; + +static const sph_u32 T256_4[4][8] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000) }, + { SPH_C32(0xe92a2000), SPH_C32(0xb4578cfc), SPH_C32(0x11fa3a57), + SPH_C32(0x3dc90524), SPH_C32(0x97530000), SPH_C32(0x204f6ed3), + SPH_C32(0x77b9e80f), SPH_C32(0xa1ec5ec1) }, + { SPH_C32(0x97530000), SPH_C32(0x204f6ed3), SPH_C32(0x77b9e80f), + SPH_C32(0xa1ec5ec1), SPH_C32(0x7e792000), SPH_C32(0x9418e22f), + SPH_C32(0x6643d258), SPH_C32(0x9c255be5) }, + { SPH_C32(0x7e792000), SPH_C32(0x9418e22f), SPH_C32(0x6643d258), + SPH_C32(0x9c255be5), SPH_C32(0xe92a2000), SPH_C32(0xb4578cfc), + SPH_C32(0x11fa3a57), SPH_C32(0x3dc90524) } +}; + +static const sph_u32 T256_6[4][8] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000) }, + { SPH_C32(0x74951000), SPH_C32(0x5a2b467e), SPH_C32(0x88fd1d2b), + SPH_C32(0x1ee68292), SPH_C32(0xcba90000), SPH_C32(0x90273769), + SPH_C32(0xbbdcf407), SPH_C32(0xd0f4af61) }, + { SPH_C32(0xcba90000), SPH_C32(0x90273769), SPH_C32(0xbbdcf407), + SPH_C32(0xd0f4af61), SPH_C32(0xbf3c1000), SPH_C32(0xca0c7117), + SPH_C32(0x3321e92c), SPH_C32(0xce122df3) }, + { SPH_C32(0xbf3c1000), SPH_C32(0xca0c7117), SPH_C32(0x3321e92c), + SPH_C32(0xce122df3), SPH_C32(0x74951000), SPH_C32(0x5a2b467e), + SPH_C32(0x88fd1d2b), SPH_C32(0x1ee68292) } +}; + +static const sph_u32 T256_8[4][8] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000) }, + { SPH_C32(0xde320800), SPH_C32(0x288350fe), SPH_C32(0x71852ac7), + SPH_C32(0xa6bf9f96), SPH_C32(0xe18b0000), SPH_C32(0x5459887d), + SPH_C32(0xbf1283d3), SPH_C32(0x1b666a73) }, + { SPH_C32(0xe18b0000), SPH_C32(0x5459887d), SPH_C32(0xbf1283d3), + SPH_C32(0x1b666a73), SPH_C32(0x3fb90800), SPH_C32(0x7cdad883), + SPH_C32(0xce97a914), SPH_C32(0xbdd9f5e5) }, + { SPH_C32(0x3fb90800), SPH_C32(0x7cdad883), SPH_C32(0xce97a914), + SPH_C32(0xbdd9f5e5), SPH_C32(0xde320800), SPH_C32(0x288350fe), + SPH_C32(0x71852ac7), SPH_C32(0xa6bf9f96) } +}; + +static const sph_u32 T256_10[4][8] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000) }, + { SPH_C32(0x8f3e0400), SPH_C32(0x0d9dc877), SPH_C32(0x6fc548e1), + SPH_C32(0x898d2cd6), SPH_C32(0x14bd0000), SPH_C32(0x2fba37ff), + SPH_C32(0x6a72e5bb), SPH_C32(0x247febe6) }, + { SPH_C32(0x14bd0000), SPH_C32(0x2fba37ff), SPH_C32(0x6a72e5bb), + SPH_C32(0x247febe6), SPH_C32(0x9b830400), SPH_C32(0x2227ff88), + SPH_C32(0x05b7ad5a), SPH_C32(0xadf2c730) }, + { SPH_C32(0x9b830400), SPH_C32(0x2227ff88), SPH_C32(0x05b7ad5a), + SPH_C32(0xadf2c730), SPH_C32(0x8f3e0400), SPH_C32(0x0d9dc877), + SPH_C32(0x6fc548e1), SPH_C32(0x898d2cd6) } +}; + +static const sph_u32 T256_12[4][8] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000) }, + { SPH_C32(0xa7b80200), SPH_C32(0x1f128433), SPH_C32(0x60e5f9f2), + SPH_C32(0x9e147576), SPH_C32(0xee260000), SPH_C32(0x124b683e), + SPH_C32(0x80c2d68f), SPH_C32(0x3bf3ab2c) }, + { SPH_C32(0xee260000), SPH_C32(0x124b683e), SPH_C32(0x80c2d68f), + SPH_C32(0x3bf3ab2c), SPH_C32(0x499e0200), SPH_C32(0x0d59ec0d), + SPH_C32(0xe0272f7d), SPH_C32(0xa5e7de5a) }, + { SPH_C32(0x499e0200), SPH_C32(0x0d59ec0d), SPH_C32(0xe0272f7d), + SPH_C32(0xa5e7de5a), SPH_C32(0xa7b80200), SPH_C32(0x1f128433), + SPH_C32(0x60e5f9f2), SPH_C32(0x9e147576) } +}; + +static const sph_u32 T256_14[4][8] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000) }, + { SPH_C32(0xb7a40100), SPH_C32(0x8a1f31d8), SPH_C32(0x8589d8ab), + SPH_C32(0xe6c46464), SPH_C32(0x734c0000), SPH_C32(0x956fa7d6), + SPH_C32(0xa29d1297), SPH_C32(0x6ee56854) }, + { SPH_C32(0x734c0000), SPH_C32(0x956fa7d6), SPH_C32(0xa29d1297), + SPH_C32(0x6ee56854), SPH_C32(0xc4e80100), SPH_C32(0x1f70960e), + SPH_C32(0x2714ca3c), SPH_C32(0x88210c30) }, + { SPH_C32(0xc4e80100), SPH_C32(0x1f70960e), SPH_C32(0x2714ca3c), + SPH_C32(0x88210c30), SPH_C32(0xb7a40100), SPH_C32(0x8a1f31d8), + SPH_C32(0x8589d8ab), SPH_C32(0xe6c46464) } +}; + +static const sph_u32 T256_16[4][8] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000) }, + { SPH_C32(0x5bd20080), SPH_C32(0x450f18ec), SPH_C32(0xc2c46c55), + SPH_C32(0xf362b233), SPH_C32(0x39a60000), SPH_C32(0x4ab753eb), + SPH_C32(0xd14e094b), SPH_C32(0xb772b42b) }, + { SPH_C32(0x39a60000), SPH_C32(0x4ab753eb), SPH_C32(0xd14e094b), + SPH_C32(0xb772b42b), SPH_C32(0x62740080), SPH_C32(0x0fb84b07), + SPH_C32(0x138a651e), SPH_C32(0x44100618) }, + { SPH_C32(0x62740080), SPH_C32(0x0fb84b07), SPH_C32(0x138a651e), + SPH_C32(0x44100618), SPH_C32(0x5bd20080), SPH_C32(0x450f18ec), + SPH_C32(0xc2c46c55), SPH_C32(0xf362b233) } +}; + +static const sph_u32 T256_18[4][8] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000) }, + { SPH_C32(0x4dce0040), SPH_C32(0x3b5bec7e), SPH_C32(0x36656ba8), + SPH_C32(0x23633a05), SPH_C32(0x78ab0000), SPH_C32(0xa0cd5a34), + SPH_C32(0x5d5ca0f7), SPH_C32(0x727784cb) }, + { SPH_C32(0x78ab0000), SPH_C32(0xa0cd5a34), SPH_C32(0x5d5ca0f7), + SPH_C32(0x727784cb), SPH_C32(0x35650040), SPH_C32(0x9b96b64a), + SPH_C32(0x6b39cb5f), SPH_C32(0x5114bece) }, + { SPH_C32(0x35650040), SPH_C32(0x9b96b64a), SPH_C32(0x6b39cb5f), + SPH_C32(0x5114bece), SPH_C32(0x4dce0040), SPH_C32(0x3b5bec7e), + SPH_C32(0x36656ba8), SPH_C32(0x23633a05) } +}; + +static const sph_u32 T256_20[4][8] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000) }, + { SPH_C32(0xa2b80020), SPH_C32(0x81e7e5f6), SPH_C32(0xf9ce4c04), + SPH_C32(0xe2afa0c0), SPH_C32(0x5c720000), SPH_C32(0xc9bacd12), + SPH_C32(0x79a90df9), SPH_C32(0x63e92178) }, + { SPH_C32(0x5c720000), SPH_C32(0xc9bacd12), SPH_C32(0x79a90df9), + SPH_C32(0x63e92178), SPH_C32(0xfeca0020), SPH_C32(0x485d28e4), + SPH_C32(0x806741fd), SPH_C32(0x814681b8) }, + { SPH_C32(0xfeca0020), SPH_C32(0x485d28e4), SPH_C32(0x806741fd), + SPH_C32(0x814681b8), SPH_C32(0xa2b80020), SPH_C32(0x81e7e5f6), + SPH_C32(0xf9ce4c04), SPH_C32(0xe2afa0c0) } +}; + +static const sph_u32 T256_22[4][8] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000) }, + { SPH_C32(0x515c0010), SPH_C32(0x40f372fb), SPH_C32(0xfce72602), + SPH_C32(0x71575061), SPH_C32(0x2e390000), SPH_C32(0x64dd6689), + SPH_C32(0x3cd406fc), SPH_C32(0xb1f490bc) }, + { SPH_C32(0x2e390000), SPH_C32(0x64dd6689), SPH_C32(0x3cd406fc), + SPH_C32(0xb1f490bc), SPH_C32(0x7f650010), SPH_C32(0x242e1472), + SPH_C32(0xc03320fe), SPH_C32(0xc0a3c0dd) }, + { SPH_C32(0x7f650010), SPH_C32(0x242e1472), SPH_C32(0xc03320fe), + SPH_C32(0xc0a3c0dd), SPH_C32(0x515c0010), SPH_C32(0x40f372fb), + SPH_C32(0xfce72602), SPH_C32(0x71575061) } +}; + +static const sph_u32 T256_24[4][8] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000) }, + { SPH_C32(0xa8ae0008), SPH_C32(0x2079397d), SPH_C32(0xfe739301), + SPH_C32(0xb8a92831), SPH_C32(0x171c0000), SPH_C32(0xb26e3344), + SPH_C32(0x9e6a837e), SPH_C32(0x58f8485f) }, + { SPH_C32(0x171c0000), SPH_C32(0xb26e3344), SPH_C32(0x9e6a837e), + SPH_C32(0x58f8485f), SPH_C32(0xbfb20008), SPH_C32(0x92170a39), + SPH_C32(0x6019107f), SPH_C32(0xe051606e) }, + { SPH_C32(0xbfb20008), SPH_C32(0x92170a39), SPH_C32(0x6019107f), + SPH_C32(0xe051606e), SPH_C32(0xa8ae0008), SPH_C32(0x2079397d), + SPH_C32(0xfe739301), SPH_C32(0xb8a92831) } +}; + +static const sph_u32 T256_26[4][8] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000) }, + { SPH_C32(0xd0080004), SPH_C32(0x8c768f77), SPH_C32(0x9dc5b050), + SPH_C32(0xaf4a29da), SPH_C32(0x6ba90000), SPH_C32(0x40ebf9aa), + SPH_C32(0x98321c3d), SPH_C32(0x76acc733) }, + { SPH_C32(0x6ba90000), SPH_C32(0x40ebf9aa), SPH_C32(0x98321c3d), + SPH_C32(0x76acc733), SPH_C32(0xbba10004), SPH_C32(0xcc9d76dd), + SPH_C32(0x05f7ac6d), SPH_C32(0xd9e6eee9) }, + { SPH_C32(0xbba10004), SPH_C32(0xcc9d76dd), SPH_C32(0x05f7ac6d), + SPH_C32(0xd9e6eee9), SPH_C32(0xd0080004), SPH_C32(0x8c768f77), + SPH_C32(0x9dc5b050), SPH_C32(0xaf4a29da) } +}; + +static const sph_u32 T256_28[4][8] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000) }, + { SPH_C32(0x88230002), SPH_C32(0x5fe7a7b3), SPH_C32(0x99e585aa), + SPH_C32(0x8d75f7f1), SPH_C32(0x51ac0000), SPH_C32(0x25e30f14), + SPH_C32(0x79e22a4c), SPH_C32(0x1298bd46) }, + { SPH_C32(0x51ac0000), SPH_C32(0x25e30f14), SPH_C32(0x79e22a4c), + SPH_C32(0x1298bd46), SPH_C32(0xd98f0002), SPH_C32(0x7a04a8a7), + SPH_C32(0xe007afe6), SPH_C32(0x9fed4ab7) }, + { SPH_C32(0xd98f0002), SPH_C32(0x7a04a8a7), SPH_C32(0xe007afe6), + SPH_C32(0x9fed4ab7), SPH_C32(0x88230002), SPH_C32(0x5fe7a7b3), + SPH_C32(0x99e585aa), SPH_C32(0x8d75f7f1) } +}; + +static const sph_u32 T256_30[4][8] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000) }, + { SPH_C32(0xc04e0001), SPH_C32(0x33b9c010), SPH_C32(0xae0ebb05), + SPH_C32(0xb5a4c63b), SPH_C32(0xc8f10000), SPH_C32(0x0b2de782), + SPH_C32(0x6bf648a4), SPH_C32(0x539cbdbf) }, + { SPH_C32(0xc8f10000), SPH_C32(0x0b2de782), SPH_C32(0x6bf648a4), + SPH_C32(0x539cbdbf), SPH_C32(0x08bf0001), SPH_C32(0x38942792), + SPH_C32(0xc5f8f3a1), SPH_C32(0xe6387b84) }, + { SPH_C32(0x08bf0001), SPH_C32(0x38942792), SPH_C32(0xc5f8f3a1), + SPH_C32(0xe6387b84), SPH_C32(0xc04e0001), SPH_C32(0x33b9c010), + SPH_C32(0xae0ebb05), SPH_C32(0xb5a4c63b) } +}; + +#define INPUT_SMALL do { \ + unsigned acc = buf[0]; \ + const sph_u32 *rp; \ + rp = &T256_0[acc >> 6][0]; \ + m0 = rp[0]; \ + m1 = rp[1]; \ + m2 = rp[2]; \ + m3 = rp[3]; \ + m4 = rp[4]; \ + m5 = rp[5]; \ + m6 = rp[6]; \ + m7 = rp[7]; \ + rp = &T256_2[(acc >> 4) & 0x03][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + rp = &T256_4[(acc >> 2) & 0x03][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + rp = &T256_6[acc & 0x03][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + acc = buf[1]; \ + rp = &T256_8[acc >> 6][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + rp = &T256_10[(acc >> 4) & 0x03][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + rp = &T256_12[(acc >> 2) & 0x03][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + rp = &T256_14[acc & 0x03][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + acc = buf[2]; \ + rp = &T256_16[acc >> 6][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + rp = &T256_18[(acc >> 4) & 0x03][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + rp = &T256_20[(acc >> 2) & 0x03][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + rp = &T256_22[acc & 0x03][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + acc = buf[3]; \ + rp = &T256_24[acc >> 6][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + rp = &T256_26[(acc >> 4) & 0x03][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + rp = &T256_28[(acc >> 2) & 0x03][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + rp = &T256_30[acc & 0x03][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + } while (0) + +#endif + +#if SPH_HAMSI_EXPAND_SMALL == 3 + +static const sph_u32 T256_0[8][8] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000) }, + { SPH_C32(0xe6570000), SPH_C32(0x4bb33a25), SPH_C32(0x848598ba), + SPH_C32(0x1041003e), SPH_C32(0xf44c4000), SPH_C32(0x10a4e3cd), + SPH_C32(0x097f5711), SPH_C32(0xde77cc4c) }, + { SPH_C32(0xe4788000), SPH_C32(0x859673c1), SPH_C32(0xb5fb2452), + SPH_C32(0x29cc5edf), SPH_C32(0x045f0000), SPH_C32(0x9c4a93c9), + SPH_C32(0x62fc79d0), SPH_C32(0x731ebdc2) }, + { SPH_C32(0x022f8000), SPH_C32(0xce2549e4), SPH_C32(0x317ebce8), + SPH_C32(0x398d5ee1), SPH_C32(0xf0134000), SPH_C32(0x8cee7004), + SPH_C32(0x6b832ec1), SPH_C32(0xad69718e) }, + { SPH_C32(0x045f0000), SPH_C32(0x9c4a93c9), SPH_C32(0x62fc79d0), + SPH_C32(0x731ebdc2), SPH_C32(0xe0278000), SPH_C32(0x19dce008), + SPH_C32(0xd7075d82), SPH_C32(0x5ad2e31d) }, + { SPH_C32(0xe2080000), SPH_C32(0xd7f9a9ec), SPH_C32(0xe679e16a), + SPH_C32(0x635fbdfc), SPH_C32(0x146bc000), SPH_C32(0x097803c5), + SPH_C32(0xde780a93), SPH_C32(0x84a52f51) }, + { SPH_C32(0xe0278000), SPH_C32(0x19dce008), SPH_C32(0xd7075d82), + SPH_C32(0x5ad2e31d), SPH_C32(0xe4788000), SPH_C32(0x859673c1), + SPH_C32(0xb5fb2452), SPH_C32(0x29cc5edf) }, + { SPH_C32(0x06708000), SPH_C32(0x526fda2d), SPH_C32(0x5382c538), + SPH_C32(0x4a93e323), SPH_C32(0x1034c000), SPH_C32(0x9532900c), + SPH_C32(0xbc847343), SPH_C32(0xf7bb9293) } +}; + +static const sph_u32 T256_3[8][8] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000) }, + { SPH_C32(0xe92a2000), SPH_C32(0xb4578cfc), SPH_C32(0x11fa3a57), + SPH_C32(0x3dc90524), SPH_C32(0x97530000), SPH_C32(0x204f6ed3), + SPH_C32(0x77b9e80f), SPH_C32(0xa1ec5ec1) }, + { SPH_C32(0x97530000), SPH_C32(0x204f6ed3), SPH_C32(0x77b9e80f), + SPH_C32(0xa1ec5ec1), SPH_C32(0x7e792000), SPH_C32(0x9418e22f), + SPH_C32(0x6643d258), SPH_C32(0x9c255be5) }, + { SPH_C32(0x7e792000), SPH_C32(0x9418e22f), SPH_C32(0x6643d258), + SPH_C32(0x9c255be5), SPH_C32(0xe92a2000), SPH_C32(0xb4578cfc), + SPH_C32(0x11fa3a57), SPH_C32(0x3dc90524) }, + { SPH_C32(0x121b4000), SPH_C32(0x5b17d9e8), SPH_C32(0x8dfacfab), + SPH_C32(0xce36cc72), SPH_C32(0xe6570000), SPH_C32(0x4bb33a25), + SPH_C32(0x848598ba), SPH_C32(0x1041003e) }, + { SPH_C32(0xfb316000), SPH_C32(0xef405514), SPH_C32(0x9c00f5fc), + SPH_C32(0xf3ffc956), SPH_C32(0x71040000), SPH_C32(0x6bfc54f6), + SPH_C32(0xf33c70b5), SPH_C32(0xb1ad5eff) }, + { SPH_C32(0x85484000), SPH_C32(0x7b58b73b), SPH_C32(0xfa4327a4), + SPH_C32(0x6fda92b3), SPH_C32(0x982e2000), SPH_C32(0xdfabd80a), + SPH_C32(0xe2c64ae2), SPH_C32(0x8c645bdb) }, + { SPH_C32(0x6c626000), SPH_C32(0xcf0f3bc7), SPH_C32(0xebb91df3), + SPH_C32(0x52139797), SPH_C32(0x0f7d2000), SPH_C32(0xffe4b6d9), + SPH_C32(0x957fa2ed), SPH_C32(0x2d88051a) } +}; + +static const sph_u32 T256_6[8][8] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000) }, + { SPH_C32(0xe18b0000), SPH_C32(0x5459887d), SPH_C32(0xbf1283d3), + SPH_C32(0x1b666a73), SPH_C32(0x3fb90800), SPH_C32(0x7cdad883), + SPH_C32(0xce97a914), SPH_C32(0xbdd9f5e5) }, + { SPH_C32(0x74951000), SPH_C32(0x5a2b467e), SPH_C32(0x88fd1d2b), + SPH_C32(0x1ee68292), SPH_C32(0xcba90000), SPH_C32(0x90273769), + SPH_C32(0xbbdcf407), SPH_C32(0xd0f4af61) }, + { SPH_C32(0x951e1000), SPH_C32(0x0e72ce03), SPH_C32(0x37ef9ef8), + SPH_C32(0x0580e8e1), SPH_C32(0xf4100800), SPH_C32(0xecfdefea), + SPH_C32(0x754b5d13), SPH_C32(0x6d2d5a84) }, + { SPH_C32(0xcba90000), SPH_C32(0x90273769), SPH_C32(0xbbdcf407), + SPH_C32(0xd0f4af61), SPH_C32(0xbf3c1000), SPH_C32(0xca0c7117), + SPH_C32(0x3321e92c), SPH_C32(0xce122df3) }, + { SPH_C32(0x2a220000), SPH_C32(0xc47ebf14), SPH_C32(0x04ce77d4), + SPH_C32(0xcb92c512), SPH_C32(0x80851800), SPH_C32(0xb6d6a994), + SPH_C32(0xfdb64038), SPH_C32(0x73cbd816) }, + { SPH_C32(0xbf3c1000), SPH_C32(0xca0c7117), SPH_C32(0x3321e92c), + SPH_C32(0xce122df3), SPH_C32(0x74951000), SPH_C32(0x5a2b467e), + SPH_C32(0x88fd1d2b), SPH_C32(0x1ee68292) }, + { SPH_C32(0x5eb71000), SPH_C32(0x9e55f96a), SPH_C32(0x8c336aff), + SPH_C32(0xd5744780), SPH_C32(0x4b2c1800), SPH_C32(0x26f19efd), + SPH_C32(0x466ab43f), SPH_C32(0xa33f7777) } +}; + +static const sph_u32 T256_9[8][8] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000) }, + { SPH_C32(0x8f3e0400), SPH_C32(0x0d9dc877), SPH_C32(0x6fc548e1), + SPH_C32(0x898d2cd6), SPH_C32(0x14bd0000), SPH_C32(0x2fba37ff), + SPH_C32(0x6a72e5bb), SPH_C32(0x247febe6) }, + { SPH_C32(0x14bd0000), SPH_C32(0x2fba37ff), SPH_C32(0x6a72e5bb), + SPH_C32(0x247febe6), SPH_C32(0x9b830400), SPH_C32(0x2227ff88), + SPH_C32(0x05b7ad5a), SPH_C32(0xadf2c730) }, + { SPH_C32(0x9b830400), SPH_C32(0x2227ff88), SPH_C32(0x05b7ad5a), + SPH_C32(0xadf2c730), SPH_C32(0x8f3e0400), SPH_C32(0x0d9dc877), + SPH_C32(0x6fc548e1), SPH_C32(0x898d2cd6) }, + { SPH_C32(0xde320800), SPH_C32(0x288350fe), SPH_C32(0x71852ac7), + SPH_C32(0xa6bf9f96), SPH_C32(0xe18b0000), SPH_C32(0x5459887d), + SPH_C32(0xbf1283d3), SPH_C32(0x1b666a73) }, + { SPH_C32(0x510c0c00), SPH_C32(0x251e9889), SPH_C32(0x1e406226), + SPH_C32(0x2f32b340), SPH_C32(0xf5360000), SPH_C32(0x7be3bf82), + SPH_C32(0xd5606668), SPH_C32(0x3f198195) }, + { SPH_C32(0xca8f0800), SPH_C32(0x07396701), SPH_C32(0x1bf7cf7c), + SPH_C32(0x82c07470), SPH_C32(0x7a080400), SPH_C32(0x767e77f5), + SPH_C32(0xbaa52e89), SPH_C32(0xb694ad43) }, + { SPH_C32(0x45b10c00), SPH_C32(0x0aa4af76), SPH_C32(0x7432879d), + SPH_C32(0x0b4d58a6), SPH_C32(0x6eb50400), SPH_C32(0x59c4400a), + SPH_C32(0xd0d7cb32), SPH_C32(0x92eb46a5) } +}; + +static const sph_u32 T256_12[8][8] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000) }, + { SPH_C32(0x734c0000), SPH_C32(0x956fa7d6), SPH_C32(0xa29d1297), + SPH_C32(0x6ee56854), SPH_C32(0xc4e80100), SPH_C32(0x1f70960e), + SPH_C32(0x2714ca3c), SPH_C32(0x88210c30) }, + { SPH_C32(0xa7b80200), SPH_C32(0x1f128433), SPH_C32(0x60e5f9f2), + SPH_C32(0x9e147576), SPH_C32(0xee260000), SPH_C32(0x124b683e), + SPH_C32(0x80c2d68f), SPH_C32(0x3bf3ab2c) }, + { SPH_C32(0xd4f40200), SPH_C32(0x8a7d23e5), SPH_C32(0xc278eb65), + SPH_C32(0xf0f11d22), SPH_C32(0x2ace0100), SPH_C32(0x0d3bfe30), + SPH_C32(0xa7d61cb3), SPH_C32(0xb3d2a71c) }, + { SPH_C32(0xee260000), SPH_C32(0x124b683e), SPH_C32(0x80c2d68f), + SPH_C32(0x3bf3ab2c), SPH_C32(0x499e0200), SPH_C32(0x0d59ec0d), + SPH_C32(0xe0272f7d), SPH_C32(0xa5e7de5a) }, + { SPH_C32(0x9d6a0000), SPH_C32(0x8724cfe8), SPH_C32(0x225fc418), + SPH_C32(0x5516c378), SPH_C32(0x8d760300), SPH_C32(0x12297a03), + SPH_C32(0xc733e541), SPH_C32(0x2dc6d26a) }, + { SPH_C32(0x499e0200), SPH_C32(0x0d59ec0d), SPH_C32(0xe0272f7d), + SPH_C32(0xa5e7de5a), SPH_C32(0xa7b80200), SPH_C32(0x1f128433), + SPH_C32(0x60e5f9f2), SPH_C32(0x9e147576) }, + { SPH_C32(0x3ad20200), SPH_C32(0x98364bdb), SPH_C32(0x42ba3dea), + SPH_C32(0xcb02b60e), SPH_C32(0x63500300), SPH_C32(0x0062123d), + SPH_C32(0x47f133ce), SPH_C32(0x16357946) } +}; + +static const sph_u32 T256_15[8][8] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000) }, + { SPH_C32(0x5bd20080), SPH_C32(0x450f18ec), SPH_C32(0xc2c46c55), + SPH_C32(0xf362b233), SPH_C32(0x39a60000), SPH_C32(0x4ab753eb), + SPH_C32(0xd14e094b), SPH_C32(0xb772b42b) }, + { SPH_C32(0x39a60000), SPH_C32(0x4ab753eb), SPH_C32(0xd14e094b), + SPH_C32(0xb772b42b), SPH_C32(0x62740080), SPH_C32(0x0fb84b07), + SPH_C32(0x138a651e), SPH_C32(0x44100618) }, + { SPH_C32(0x62740080), SPH_C32(0x0fb84b07), SPH_C32(0x138a651e), + SPH_C32(0x44100618), SPH_C32(0x5bd20080), SPH_C32(0x450f18ec), + SPH_C32(0xc2c46c55), SPH_C32(0xf362b233) }, + { SPH_C32(0xb7a40100), SPH_C32(0x8a1f31d8), SPH_C32(0x8589d8ab), + SPH_C32(0xe6c46464), SPH_C32(0x734c0000), SPH_C32(0x956fa7d6), + SPH_C32(0xa29d1297), SPH_C32(0x6ee56854) }, + { SPH_C32(0xec760180), SPH_C32(0xcf102934), SPH_C32(0x474db4fe), + SPH_C32(0x15a6d657), SPH_C32(0x4aea0000), SPH_C32(0xdfd8f43d), + SPH_C32(0x73d31bdc), SPH_C32(0xd997dc7f) }, + { SPH_C32(0x8e020100), SPH_C32(0xc0a86233), SPH_C32(0x54c7d1e0), + SPH_C32(0x51b6d04f), SPH_C32(0x11380080), SPH_C32(0x9ad7ecd1), + SPH_C32(0xb1177789), SPH_C32(0x2af56e4c) }, + { SPH_C32(0xd5d00180), SPH_C32(0x85a77adf), SPH_C32(0x9603bdb5), + SPH_C32(0xa2d4627c), SPH_C32(0x289e0080), SPH_C32(0xd060bf3a), + SPH_C32(0x60597ec2), SPH_C32(0x9d87da67) } +}; + +static const sph_u32 T256_18[8][8] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000) }, + { SPH_C32(0x5c720000), SPH_C32(0xc9bacd12), SPH_C32(0x79a90df9), + SPH_C32(0x63e92178), SPH_C32(0xfeca0020), SPH_C32(0x485d28e4), + SPH_C32(0x806741fd), SPH_C32(0x814681b8) }, + { SPH_C32(0x4dce0040), SPH_C32(0x3b5bec7e), SPH_C32(0x36656ba8), + SPH_C32(0x23633a05), SPH_C32(0x78ab0000), SPH_C32(0xa0cd5a34), + SPH_C32(0x5d5ca0f7), SPH_C32(0x727784cb) }, + { SPH_C32(0x11bc0040), SPH_C32(0xf2e1216c), SPH_C32(0x4fcc6651), + SPH_C32(0x408a1b7d), SPH_C32(0x86610020), SPH_C32(0xe89072d0), + SPH_C32(0xdd3be10a), SPH_C32(0xf3310573) }, + { SPH_C32(0x78ab0000), SPH_C32(0xa0cd5a34), SPH_C32(0x5d5ca0f7), + SPH_C32(0x727784cb), SPH_C32(0x35650040), SPH_C32(0x9b96b64a), + SPH_C32(0x6b39cb5f), SPH_C32(0x5114bece) }, + { SPH_C32(0x24d90000), SPH_C32(0x69779726), SPH_C32(0x24f5ad0e), + SPH_C32(0x119ea5b3), SPH_C32(0xcbaf0060), SPH_C32(0xd3cb9eae), + SPH_C32(0xeb5e8aa2), SPH_C32(0xd0523f76) }, + { SPH_C32(0x35650040), SPH_C32(0x9b96b64a), SPH_C32(0x6b39cb5f), + SPH_C32(0x5114bece), SPH_C32(0x4dce0040), SPH_C32(0x3b5bec7e), + SPH_C32(0x36656ba8), SPH_C32(0x23633a05) }, + { SPH_C32(0x69170040), SPH_C32(0x522c7b58), SPH_C32(0x1290c6a6), + SPH_C32(0x32fd9fb6), SPH_C32(0xb3040060), SPH_C32(0x7306c49a), + SPH_C32(0xb6022a55), SPH_C32(0xa225bbbd) } +}; + +static const sph_u32 T256_21[8][8] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000) }, + { SPH_C32(0x515c0010), SPH_C32(0x40f372fb), SPH_C32(0xfce72602), + SPH_C32(0x71575061), SPH_C32(0x2e390000), SPH_C32(0x64dd6689), + SPH_C32(0x3cd406fc), SPH_C32(0xb1f490bc) }, + { SPH_C32(0x2e390000), SPH_C32(0x64dd6689), SPH_C32(0x3cd406fc), + SPH_C32(0xb1f490bc), SPH_C32(0x7f650010), SPH_C32(0x242e1472), + SPH_C32(0xc03320fe), SPH_C32(0xc0a3c0dd) }, + { SPH_C32(0x7f650010), SPH_C32(0x242e1472), SPH_C32(0xc03320fe), + SPH_C32(0xc0a3c0dd), SPH_C32(0x515c0010), SPH_C32(0x40f372fb), + SPH_C32(0xfce72602), SPH_C32(0x71575061) }, + { SPH_C32(0xa2b80020), SPH_C32(0x81e7e5f6), SPH_C32(0xf9ce4c04), + SPH_C32(0xe2afa0c0), SPH_C32(0x5c720000), SPH_C32(0xc9bacd12), + SPH_C32(0x79a90df9), SPH_C32(0x63e92178) }, + { SPH_C32(0xf3e40030), SPH_C32(0xc114970d), SPH_C32(0x05296a06), + SPH_C32(0x93f8f0a1), SPH_C32(0x724b0000), SPH_C32(0xad67ab9b), + SPH_C32(0x457d0b05), SPH_C32(0xd21db1c4) }, + { SPH_C32(0x8c810020), SPH_C32(0xe53a837f), SPH_C32(0xc51a4af8), + SPH_C32(0x535b307c), SPH_C32(0x23170010), SPH_C32(0xed94d960), + SPH_C32(0xb99a2d07), SPH_C32(0xa34ae1a5) }, + { SPH_C32(0xdddd0030), SPH_C32(0xa5c9f184), SPH_C32(0x39fd6cfa), + SPH_C32(0x220c601d), SPH_C32(0x0d2e0010), SPH_C32(0x8949bfe9), + SPH_C32(0x854e2bfb), SPH_C32(0x12be7119) } +}; + +static const sph_u32 T256_24[8][8] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000) }, + { SPH_C32(0x6ba90000), SPH_C32(0x40ebf9aa), SPH_C32(0x98321c3d), + SPH_C32(0x76acc733), SPH_C32(0xbba10004), SPH_C32(0xcc9d76dd), + SPH_C32(0x05f7ac6d), SPH_C32(0xd9e6eee9) }, + { SPH_C32(0xa8ae0008), SPH_C32(0x2079397d), SPH_C32(0xfe739301), + SPH_C32(0xb8a92831), SPH_C32(0x171c0000), SPH_C32(0xb26e3344), + SPH_C32(0x9e6a837e), SPH_C32(0x58f8485f) }, + { SPH_C32(0xc3070008), SPH_C32(0x6092c0d7), SPH_C32(0x66418f3c), + SPH_C32(0xce05ef02), SPH_C32(0xacbd0004), SPH_C32(0x7ef34599), + SPH_C32(0x9b9d2f13), SPH_C32(0x811ea6b6) }, + { SPH_C32(0x171c0000), SPH_C32(0xb26e3344), SPH_C32(0x9e6a837e), + SPH_C32(0x58f8485f), SPH_C32(0xbfb20008), SPH_C32(0x92170a39), + SPH_C32(0x6019107f), SPH_C32(0xe051606e) }, + { SPH_C32(0x7cb50000), SPH_C32(0xf285caee), SPH_C32(0x06589f43), + SPH_C32(0x2e548f6c), SPH_C32(0x0413000c), SPH_C32(0x5e8a7ce4), + SPH_C32(0x65eebc12), SPH_C32(0x39b78e87) }, + { SPH_C32(0xbfb20008), SPH_C32(0x92170a39), SPH_C32(0x6019107f), + SPH_C32(0xe051606e), SPH_C32(0xa8ae0008), SPH_C32(0x2079397d), + SPH_C32(0xfe739301), SPH_C32(0xb8a92831) }, + { SPH_C32(0xd41b0008), SPH_C32(0xd2fcf393), SPH_C32(0xf82b0c42), + SPH_C32(0x96fda75d), SPH_C32(0x130f000c), SPH_C32(0xece44fa0), + SPH_C32(0xfb843f6c), SPH_C32(0x614fc6d8) } +}; + +static const sph_u32 T256_27[8][8] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000) }, + { SPH_C32(0x88230002), SPH_C32(0x5fe7a7b3), SPH_C32(0x99e585aa), + SPH_C32(0x8d75f7f1), SPH_C32(0x51ac0000), SPH_C32(0x25e30f14), + SPH_C32(0x79e22a4c), SPH_C32(0x1298bd46) }, + { SPH_C32(0x51ac0000), SPH_C32(0x25e30f14), SPH_C32(0x79e22a4c), + SPH_C32(0x1298bd46), SPH_C32(0xd98f0002), SPH_C32(0x7a04a8a7), + SPH_C32(0xe007afe6), SPH_C32(0x9fed4ab7) }, + { SPH_C32(0xd98f0002), SPH_C32(0x7a04a8a7), SPH_C32(0xe007afe6), + SPH_C32(0x9fed4ab7), SPH_C32(0x88230002), SPH_C32(0x5fe7a7b3), + SPH_C32(0x99e585aa), SPH_C32(0x8d75f7f1) }, + { SPH_C32(0xd0080004), SPH_C32(0x8c768f77), SPH_C32(0x9dc5b050), + SPH_C32(0xaf4a29da), SPH_C32(0x6ba90000), SPH_C32(0x40ebf9aa), + SPH_C32(0x98321c3d), SPH_C32(0x76acc733) }, + { SPH_C32(0x582b0006), SPH_C32(0xd39128c4), SPH_C32(0x042035fa), + SPH_C32(0x223fde2b), SPH_C32(0x3a050000), SPH_C32(0x6508f6be), + SPH_C32(0xe1d03671), SPH_C32(0x64347a75) }, + { SPH_C32(0x81a40004), SPH_C32(0xa9958063), SPH_C32(0xe4279a1c), + SPH_C32(0xbdd2949c), SPH_C32(0xb2260002), SPH_C32(0x3aef510d), + SPH_C32(0x7835b3db), SPH_C32(0xe9418d84) }, + { SPH_C32(0x09870006), SPH_C32(0xf67227d0), SPH_C32(0x7dc21fb6), + SPH_C32(0x30a7636d), SPH_C32(0xe38a0002), SPH_C32(0x1f0c5e19), + SPH_C32(0x01d79997), SPH_C32(0xfbd930c2) } +}; + +static const sph_u32 T256_30[4][8] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000) }, + { SPH_C32(0xc04e0001), SPH_C32(0x33b9c010), SPH_C32(0xae0ebb05), + SPH_C32(0xb5a4c63b), SPH_C32(0xc8f10000), SPH_C32(0x0b2de782), + SPH_C32(0x6bf648a4), SPH_C32(0x539cbdbf) }, + { SPH_C32(0xc8f10000), SPH_C32(0x0b2de782), SPH_C32(0x6bf648a4), + SPH_C32(0x539cbdbf), SPH_C32(0x08bf0001), SPH_C32(0x38942792), + SPH_C32(0xc5f8f3a1), SPH_C32(0xe6387b84) }, + { SPH_C32(0x08bf0001), SPH_C32(0x38942792), SPH_C32(0xc5f8f3a1), + SPH_C32(0xe6387b84), SPH_C32(0xc04e0001), SPH_C32(0x33b9c010), + SPH_C32(0xae0ebb05), SPH_C32(0xb5a4c63b) } +}; + +#define INPUT_SMALL do { \ + unsigned acc = buf[0]; \ + const sph_u32 *rp; \ + rp = &T256_0[acc >> 5][0]; \ + m0 = rp[0]; \ + m1 = rp[1]; \ + m2 = rp[2]; \ + m3 = rp[3]; \ + m4 = rp[4]; \ + m5 = rp[5]; \ + m6 = rp[6]; \ + m7 = rp[7]; \ + rp = &T256_3[(acc >> 2) & 0x07][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + acc = (acc << 8) | buf[1]; \ + rp = &T256_6[(acc >> 7) & 0x07][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + rp = &T256_9[(acc >> 4) & 0x07][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + rp = &T256_12[(acc >> 1) & 0x07][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + acc = (acc << 8) | buf[2]; \ + rp = &T256_15[(acc >> 6) & 0x07][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + rp = &T256_18[(acc >> 3) & 0x07][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + rp = &T256_21[acc & 0x07][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + acc = buf[3]; \ + rp = &T256_24[acc >> 5][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + rp = &T256_27[(acc >> 2) & 0x07][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + rp = &T256_30[acc & 0x03][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + } while (0) + +#endif + +#if SPH_HAMSI_EXPAND_SMALL == 4 + +static const sph_u32 T256_0[16][8] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000) }, + { SPH_C32(0x121b4000), SPH_C32(0x5b17d9e8), SPH_C32(0x8dfacfab), + SPH_C32(0xce36cc72), SPH_C32(0xe6570000), SPH_C32(0x4bb33a25), + SPH_C32(0x848598ba), SPH_C32(0x1041003e) }, + { SPH_C32(0xe6570000), SPH_C32(0x4bb33a25), SPH_C32(0x848598ba), + SPH_C32(0x1041003e), SPH_C32(0xf44c4000), SPH_C32(0x10a4e3cd), + SPH_C32(0x097f5711), SPH_C32(0xde77cc4c) }, + { SPH_C32(0xf44c4000), SPH_C32(0x10a4e3cd), SPH_C32(0x097f5711), + SPH_C32(0xde77cc4c), SPH_C32(0x121b4000), SPH_C32(0x5b17d9e8), + SPH_C32(0x8dfacfab), SPH_C32(0xce36cc72) }, + { SPH_C32(0xe4788000), SPH_C32(0x859673c1), SPH_C32(0xb5fb2452), + SPH_C32(0x29cc5edf), SPH_C32(0x045f0000), SPH_C32(0x9c4a93c9), + SPH_C32(0x62fc79d0), SPH_C32(0x731ebdc2) }, + { SPH_C32(0xf663c000), SPH_C32(0xde81aa29), SPH_C32(0x3801ebf9), + SPH_C32(0xe7fa92ad), SPH_C32(0xe2080000), SPH_C32(0xd7f9a9ec), + SPH_C32(0xe679e16a), SPH_C32(0x635fbdfc) }, + { SPH_C32(0x022f8000), SPH_C32(0xce2549e4), SPH_C32(0x317ebce8), + SPH_C32(0x398d5ee1), SPH_C32(0xf0134000), SPH_C32(0x8cee7004), + SPH_C32(0x6b832ec1), SPH_C32(0xad69718e) }, + { SPH_C32(0x1034c000), SPH_C32(0x9532900c), SPH_C32(0xbc847343), + SPH_C32(0xf7bb9293), SPH_C32(0x16444000), SPH_C32(0xc75d4a21), + SPH_C32(0xef06b67b), SPH_C32(0xbd2871b0) }, + { SPH_C32(0x045f0000), SPH_C32(0x9c4a93c9), SPH_C32(0x62fc79d0), + SPH_C32(0x731ebdc2), SPH_C32(0xe0278000), SPH_C32(0x19dce008), + SPH_C32(0xd7075d82), SPH_C32(0x5ad2e31d) }, + { SPH_C32(0x16444000), SPH_C32(0xc75d4a21), SPH_C32(0xef06b67b), + SPH_C32(0xbd2871b0), SPH_C32(0x06708000), SPH_C32(0x526fda2d), + SPH_C32(0x5382c538), SPH_C32(0x4a93e323) }, + { SPH_C32(0xe2080000), SPH_C32(0xd7f9a9ec), SPH_C32(0xe679e16a), + SPH_C32(0x635fbdfc), SPH_C32(0x146bc000), SPH_C32(0x097803c5), + SPH_C32(0xde780a93), SPH_C32(0x84a52f51) }, + { SPH_C32(0xf0134000), SPH_C32(0x8cee7004), SPH_C32(0x6b832ec1), + SPH_C32(0xad69718e), SPH_C32(0xf23cc000), SPH_C32(0x42cb39e0), + SPH_C32(0x5afd9229), SPH_C32(0x94e42f6f) }, + { SPH_C32(0xe0278000), SPH_C32(0x19dce008), SPH_C32(0xd7075d82), + SPH_C32(0x5ad2e31d), SPH_C32(0xe4788000), SPH_C32(0x859673c1), + SPH_C32(0xb5fb2452), SPH_C32(0x29cc5edf) }, + { SPH_C32(0xf23cc000), SPH_C32(0x42cb39e0), SPH_C32(0x5afd9229), + SPH_C32(0x94e42f6f), SPH_C32(0x022f8000), SPH_C32(0xce2549e4), + SPH_C32(0x317ebce8), SPH_C32(0x398d5ee1) }, + { SPH_C32(0x06708000), SPH_C32(0x526fda2d), SPH_C32(0x5382c538), + SPH_C32(0x4a93e323), SPH_C32(0x1034c000), SPH_C32(0x9532900c), + SPH_C32(0xbc847343), SPH_C32(0xf7bb9293) }, + { SPH_C32(0x146bc000), SPH_C32(0x097803c5), SPH_C32(0xde780a93), + SPH_C32(0x84a52f51), SPH_C32(0xf663c000), SPH_C32(0xde81aa29), + SPH_C32(0x3801ebf9), SPH_C32(0xe7fa92ad) } +}; + +static const sph_u32 T256_4[16][8] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000) }, + { SPH_C32(0x74951000), SPH_C32(0x5a2b467e), SPH_C32(0x88fd1d2b), + SPH_C32(0x1ee68292), SPH_C32(0xcba90000), SPH_C32(0x90273769), + SPH_C32(0xbbdcf407), SPH_C32(0xd0f4af61) }, + { SPH_C32(0xcba90000), SPH_C32(0x90273769), SPH_C32(0xbbdcf407), + SPH_C32(0xd0f4af61), SPH_C32(0xbf3c1000), SPH_C32(0xca0c7117), + SPH_C32(0x3321e92c), SPH_C32(0xce122df3) }, + { SPH_C32(0xbf3c1000), SPH_C32(0xca0c7117), SPH_C32(0x3321e92c), + SPH_C32(0xce122df3), SPH_C32(0x74951000), SPH_C32(0x5a2b467e), + SPH_C32(0x88fd1d2b), SPH_C32(0x1ee68292) }, + { SPH_C32(0xe92a2000), SPH_C32(0xb4578cfc), SPH_C32(0x11fa3a57), + SPH_C32(0x3dc90524), SPH_C32(0x97530000), SPH_C32(0x204f6ed3), + SPH_C32(0x77b9e80f), SPH_C32(0xa1ec5ec1) }, + { SPH_C32(0x9dbf3000), SPH_C32(0xee7cca82), SPH_C32(0x9907277c), + SPH_C32(0x232f87b6), SPH_C32(0x5cfa0000), SPH_C32(0xb06859ba), + SPH_C32(0xcc651c08), SPH_C32(0x7118f1a0) }, + { SPH_C32(0x22832000), SPH_C32(0x2470bb95), SPH_C32(0xaa26ce50), + SPH_C32(0xed3daa45), SPH_C32(0x286f1000), SPH_C32(0xea431fc4), + SPH_C32(0x44980123), SPH_C32(0x6ffe7332) }, + { SPH_C32(0x56163000), SPH_C32(0x7e5bfdeb), SPH_C32(0x22dbd37b), + SPH_C32(0xf3db28d7), SPH_C32(0xe3c61000), SPH_C32(0x7a6428ad), + SPH_C32(0xff44f524), SPH_C32(0xbf0adc53) }, + { SPH_C32(0x97530000), SPH_C32(0x204f6ed3), SPH_C32(0x77b9e80f), + SPH_C32(0xa1ec5ec1), SPH_C32(0x7e792000), SPH_C32(0x9418e22f), + SPH_C32(0x6643d258), SPH_C32(0x9c255be5) }, + { SPH_C32(0xe3c61000), SPH_C32(0x7a6428ad), SPH_C32(0xff44f524), + SPH_C32(0xbf0adc53), SPH_C32(0xb5d02000), SPH_C32(0x043fd546), + SPH_C32(0xdd9f265f), SPH_C32(0x4cd1f484) }, + { SPH_C32(0x5cfa0000), SPH_C32(0xb06859ba), SPH_C32(0xcc651c08), + SPH_C32(0x7118f1a0), SPH_C32(0xc1453000), SPH_C32(0x5e149338), + SPH_C32(0x55623b74), SPH_C32(0x52377616) }, + { SPH_C32(0x286f1000), SPH_C32(0xea431fc4), SPH_C32(0x44980123), + SPH_C32(0x6ffe7332), SPH_C32(0x0aec3000), SPH_C32(0xce33a451), + SPH_C32(0xeebecf73), SPH_C32(0x82c3d977) }, + { SPH_C32(0x7e792000), SPH_C32(0x9418e22f), SPH_C32(0x6643d258), + SPH_C32(0x9c255be5), SPH_C32(0xe92a2000), SPH_C32(0xb4578cfc), + SPH_C32(0x11fa3a57), SPH_C32(0x3dc90524) }, + { SPH_C32(0x0aec3000), SPH_C32(0xce33a451), SPH_C32(0xeebecf73), + SPH_C32(0x82c3d977), SPH_C32(0x22832000), SPH_C32(0x2470bb95), + SPH_C32(0xaa26ce50), SPH_C32(0xed3daa45) }, + { SPH_C32(0xb5d02000), SPH_C32(0x043fd546), SPH_C32(0xdd9f265f), + SPH_C32(0x4cd1f484), SPH_C32(0x56163000), SPH_C32(0x7e5bfdeb), + SPH_C32(0x22dbd37b), SPH_C32(0xf3db28d7) }, + { SPH_C32(0xc1453000), SPH_C32(0x5e149338), SPH_C32(0x55623b74), + SPH_C32(0x52377616), SPH_C32(0x9dbf3000), SPH_C32(0xee7cca82), + SPH_C32(0x9907277c), SPH_C32(0x232f87b6) } +}; + +static const sph_u32 T256_8[16][8] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000) }, + { SPH_C32(0x8f3e0400), SPH_C32(0x0d9dc877), SPH_C32(0x6fc548e1), + SPH_C32(0x898d2cd6), SPH_C32(0x14bd0000), SPH_C32(0x2fba37ff), + SPH_C32(0x6a72e5bb), SPH_C32(0x247febe6) }, + { SPH_C32(0x14bd0000), SPH_C32(0x2fba37ff), SPH_C32(0x6a72e5bb), + SPH_C32(0x247febe6), SPH_C32(0x9b830400), SPH_C32(0x2227ff88), + SPH_C32(0x05b7ad5a), SPH_C32(0xadf2c730) }, + { SPH_C32(0x9b830400), SPH_C32(0x2227ff88), SPH_C32(0x05b7ad5a), + SPH_C32(0xadf2c730), SPH_C32(0x8f3e0400), SPH_C32(0x0d9dc877), + SPH_C32(0x6fc548e1), SPH_C32(0x898d2cd6) }, + { SPH_C32(0xde320800), SPH_C32(0x288350fe), SPH_C32(0x71852ac7), + SPH_C32(0xa6bf9f96), SPH_C32(0xe18b0000), SPH_C32(0x5459887d), + SPH_C32(0xbf1283d3), SPH_C32(0x1b666a73) }, + { SPH_C32(0x510c0c00), SPH_C32(0x251e9889), SPH_C32(0x1e406226), + SPH_C32(0x2f32b340), SPH_C32(0xf5360000), SPH_C32(0x7be3bf82), + SPH_C32(0xd5606668), SPH_C32(0x3f198195) }, + { SPH_C32(0xca8f0800), SPH_C32(0x07396701), SPH_C32(0x1bf7cf7c), + SPH_C32(0x82c07470), SPH_C32(0x7a080400), SPH_C32(0x767e77f5), + SPH_C32(0xbaa52e89), SPH_C32(0xb694ad43) }, + { SPH_C32(0x45b10c00), SPH_C32(0x0aa4af76), SPH_C32(0x7432879d), + SPH_C32(0x0b4d58a6), SPH_C32(0x6eb50400), SPH_C32(0x59c4400a), + SPH_C32(0xd0d7cb32), SPH_C32(0x92eb46a5) }, + { SPH_C32(0xe18b0000), SPH_C32(0x5459887d), SPH_C32(0xbf1283d3), + SPH_C32(0x1b666a73), SPH_C32(0x3fb90800), SPH_C32(0x7cdad883), + SPH_C32(0xce97a914), SPH_C32(0xbdd9f5e5) }, + { SPH_C32(0x6eb50400), SPH_C32(0x59c4400a), SPH_C32(0xd0d7cb32), + SPH_C32(0x92eb46a5), SPH_C32(0x2b040800), SPH_C32(0x5360ef7c), + SPH_C32(0xa4e54caf), SPH_C32(0x99a61e03) }, + { SPH_C32(0xf5360000), SPH_C32(0x7be3bf82), SPH_C32(0xd5606668), + SPH_C32(0x3f198195), SPH_C32(0xa43a0c00), SPH_C32(0x5efd270b), + SPH_C32(0xcb20044e), SPH_C32(0x102b32d5) }, + { SPH_C32(0x7a080400), SPH_C32(0x767e77f5), SPH_C32(0xbaa52e89), + SPH_C32(0xb694ad43), SPH_C32(0xb0870c00), SPH_C32(0x714710f4), + SPH_C32(0xa152e1f5), SPH_C32(0x3454d933) }, + { SPH_C32(0x3fb90800), SPH_C32(0x7cdad883), SPH_C32(0xce97a914), + SPH_C32(0xbdd9f5e5), SPH_C32(0xde320800), SPH_C32(0x288350fe), + SPH_C32(0x71852ac7), SPH_C32(0xa6bf9f96) }, + { SPH_C32(0xb0870c00), SPH_C32(0x714710f4), SPH_C32(0xa152e1f5), + SPH_C32(0x3454d933), SPH_C32(0xca8f0800), SPH_C32(0x07396701), + SPH_C32(0x1bf7cf7c), SPH_C32(0x82c07470) }, + { SPH_C32(0x2b040800), SPH_C32(0x5360ef7c), SPH_C32(0xa4e54caf), + SPH_C32(0x99a61e03), SPH_C32(0x45b10c00), SPH_C32(0x0aa4af76), + SPH_C32(0x7432879d), SPH_C32(0x0b4d58a6) }, + { SPH_C32(0xa43a0c00), SPH_C32(0x5efd270b), SPH_C32(0xcb20044e), + SPH_C32(0x102b32d5), SPH_C32(0x510c0c00), SPH_C32(0x251e9889), + SPH_C32(0x1e406226), SPH_C32(0x2f32b340) } +}; + +static const sph_u32 T256_12[16][8] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000) }, + { SPH_C32(0xb7a40100), SPH_C32(0x8a1f31d8), SPH_C32(0x8589d8ab), + SPH_C32(0xe6c46464), SPH_C32(0x734c0000), SPH_C32(0x956fa7d6), + SPH_C32(0xa29d1297), SPH_C32(0x6ee56854) }, + { SPH_C32(0x734c0000), SPH_C32(0x956fa7d6), SPH_C32(0xa29d1297), + SPH_C32(0x6ee56854), SPH_C32(0xc4e80100), SPH_C32(0x1f70960e), + SPH_C32(0x2714ca3c), SPH_C32(0x88210c30) }, + { SPH_C32(0xc4e80100), SPH_C32(0x1f70960e), SPH_C32(0x2714ca3c), + SPH_C32(0x88210c30), SPH_C32(0xb7a40100), SPH_C32(0x8a1f31d8), + SPH_C32(0x8589d8ab), SPH_C32(0xe6c46464) }, + { SPH_C32(0xa7b80200), SPH_C32(0x1f128433), SPH_C32(0x60e5f9f2), + SPH_C32(0x9e147576), SPH_C32(0xee260000), SPH_C32(0x124b683e), + SPH_C32(0x80c2d68f), SPH_C32(0x3bf3ab2c) }, + { SPH_C32(0x101c0300), SPH_C32(0x950db5eb), SPH_C32(0xe56c2159), + SPH_C32(0x78d01112), SPH_C32(0x9d6a0000), SPH_C32(0x8724cfe8), + SPH_C32(0x225fc418), SPH_C32(0x5516c378) }, + { SPH_C32(0xd4f40200), SPH_C32(0x8a7d23e5), SPH_C32(0xc278eb65), + SPH_C32(0xf0f11d22), SPH_C32(0x2ace0100), SPH_C32(0x0d3bfe30), + SPH_C32(0xa7d61cb3), SPH_C32(0xb3d2a71c) }, + { SPH_C32(0x63500300), SPH_C32(0x0062123d), SPH_C32(0x47f133ce), + SPH_C32(0x16357946), SPH_C32(0x59820100), SPH_C32(0x985459e6), + SPH_C32(0x054b0e24), SPH_C32(0xdd37cf48) }, + { SPH_C32(0xee260000), SPH_C32(0x124b683e), SPH_C32(0x80c2d68f), + SPH_C32(0x3bf3ab2c), SPH_C32(0x499e0200), SPH_C32(0x0d59ec0d), + SPH_C32(0xe0272f7d), SPH_C32(0xa5e7de5a) }, + { SPH_C32(0x59820100), SPH_C32(0x985459e6), SPH_C32(0x054b0e24), + SPH_C32(0xdd37cf48), SPH_C32(0x3ad20200), SPH_C32(0x98364bdb), + SPH_C32(0x42ba3dea), SPH_C32(0xcb02b60e) }, + { SPH_C32(0x9d6a0000), SPH_C32(0x8724cfe8), SPH_C32(0x225fc418), + SPH_C32(0x5516c378), SPH_C32(0x8d760300), SPH_C32(0x12297a03), + SPH_C32(0xc733e541), SPH_C32(0x2dc6d26a) }, + { SPH_C32(0x2ace0100), SPH_C32(0x0d3bfe30), SPH_C32(0xa7d61cb3), + SPH_C32(0xb3d2a71c), SPH_C32(0xfe3a0300), SPH_C32(0x8746ddd5), + SPH_C32(0x65aef7d6), SPH_C32(0x4323ba3e) }, + { SPH_C32(0x499e0200), SPH_C32(0x0d59ec0d), SPH_C32(0xe0272f7d), + SPH_C32(0xa5e7de5a), SPH_C32(0xa7b80200), SPH_C32(0x1f128433), + SPH_C32(0x60e5f9f2), SPH_C32(0x9e147576) }, + { SPH_C32(0xfe3a0300), SPH_C32(0x8746ddd5), SPH_C32(0x65aef7d6), + SPH_C32(0x4323ba3e), SPH_C32(0xd4f40200), SPH_C32(0x8a7d23e5), + SPH_C32(0xc278eb65), SPH_C32(0xf0f11d22) }, + { SPH_C32(0x3ad20200), SPH_C32(0x98364bdb), SPH_C32(0x42ba3dea), + SPH_C32(0xcb02b60e), SPH_C32(0x63500300), SPH_C32(0x0062123d), + SPH_C32(0x47f133ce), SPH_C32(0x16357946) }, + { SPH_C32(0x8d760300), SPH_C32(0x12297a03), SPH_C32(0xc733e541), + SPH_C32(0x2dc6d26a), SPH_C32(0x101c0300), SPH_C32(0x950db5eb), + SPH_C32(0xe56c2159), SPH_C32(0x78d01112) } +}; + +static const sph_u32 T256_16[16][8] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000) }, + { SPH_C32(0x4dce0040), SPH_C32(0x3b5bec7e), SPH_C32(0x36656ba8), + SPH_C32(0x23633a05), SPH_C32(0x78ab0000), SPH_C32(0xa0cd5a34), + SPH_C32(0x5d5ca0f7), SPH_C32(0x727784cb) }, + { SPH_C32(0x78ab0000), SPH_C32(0xa0cd5a34), SPH_C32(0x5d5ca0f7), + SPH_C32(0x727784cb), SPH_C32(0x35650040), SPH_C32(0x9b96b64a), + SPH_C32(0x6b39cb5f), SPH_C32(0x5114bece) }, + { SPH_C32(0x35650040), SPH_C32(0x9b96b64a), SPH_C32(0x6b39cb5f), + SPH_C32(0x5114bece), SPH_C32(0x4dce0040), SPH_C32(0x3b5bec7e), + SPH_C32(0x36656ba8), SPH_C32(0x23633a05) }, + { SPH_C32(0x5bd20080), SPH_C32(0x450f18ec), SPH_C32(0xc2c46c55), + SPH_C32(0xf362b233), SPH_C32(0x39a60000), SPH_C32(0x4ab753eb), + SPH_C32(0xd14e094b), SPH_C32(0xb772b42b) }, + { SPH_C32(0x161c00c0), SPH_C32(0x7e54f492), SPH_C32(0xf4a107fd), + SPH_C32(0xd0018836), SPH_C32(0x410d0000), SPH_C32(0xea7a09df), + SPH_C32(0x8c12a9bc), SPH_C32(0xc50530e0) }, + { SPH_C32(0x23790080), SPH_C32(0xe5c242d8), SPH_C32(0x9f98cca2), + SPH_C32(0x811536f8), SPH_C32(0x0cc30040), SPH_C32(0xd121e5a1), + SPH_C32(0xba77c214), SPH_C32(0xe6660ae5) }, + { SPH_C32(0x6eb700c0), SPH_C32(0xde99aea6), SPH_C32(0xa9fda70a), + SPH_C32(0xa2760cfd), SPH_C32(0x74680040), SPH_C32(0x71ecbf95), + SPH_C32(0xe72b62e3), SPH_C32(0x94118e2e) }, + { SPH_C32(0x39a60000), SPH_C32(0x4ab753eb), SPH_C32(0xd14e094b), + SPH_C32(0xb772b42b), SPH_C32(0x62740080), SPH_C32(0x0fb84b07), + SPH_C32(0x138a651e), SPH_C32(0x44100618) }, + { SPH_C32(0x74680040), SPH_C32(0x71ecbf95), SPH_C32(0xe72b62e3), + SPH_C32(0x94118e2e), SPH_C32(0x1adf0080), SPH_C32(0xaf751133), + SPH_C32(0x4ed6c5e9), SPH_C32(0x366782d3) }, + { SPH_C32(0x410d0000), SPH_C32(0xea7a09df), SPH_C32(0x8c12a9bc), + SPH_C32(0xc50530e0), SPH_C32(0x571100c0), SPH_C32(0x942efd4d), + SPH_C32(0x78b3ae41), SPH_C32(0x1504b8d6) }, + { SPH_C32(0x0cc30040), SPH_C32(0xd121e5a1), SPH_C32(0xba77c214), + SPH_C32(0xe6660ae5), SPH_C32(0x2fba00c0), SPH_C32(0x34e3a779), + SPH_C32(0x25ef0eb6), SPH_C32(0x67733c1d) }, + { SPH_C32(0x62740080), SPH_C32(0x0fb84b07), SPH_C32(0x138a651e), + SPH_C32(0x44100618), SPH_C32(0x5bd20080), SPH_C32(0x450f18ec), + SPH_C32(0xc2c46c55), SPH_C32(0xf362b233) }, + { SPH_C32(0x2fba00c0), SPH_C32(0x34e3a779), SPH_C32(0x25ef0eb6), + SPH_C32(0x67733c1d), SPH_C32(0x23790080), SPH_C32(0xe5c242d8), + SPH_C32(0x9f98cca2), SPH_C32(0x811536f8) }, + { SPH_C32(0x1adf0080), SPH_C32(0xaf751133), SPH_C32(0x4ed6c5e9), + SPH_C32(0x366782d3), SPH_C32(0x6eb700c0), SPH_C32(0xde99aea6), + SPH_C32(0xa9fda70a), SPH_C32(0xa2760cfd) }, + { SPH_C32(0x571100c0), SPH_C32(0x942efd4d), SPH_C32(0x78b3ae41), + SPH_C32(0x1504b8d6), SPH_C32(0x161c00c0), SPH_C32(0x7e54f492), + SPH_C32(0xf4a107fd), SPH_C32(0xd0018836) } +}; + +static const sph_u32 T256_20[16][8] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000) }, + { SPH_C32(0x515c0010), SPH_C32(0x40f372fb), SPH_C32(0xfce72602), + SPH_C32(0x71575061), SPH_C32(0x2e390000), SPH_C32(0x64dd6689), + SPH_C32(0x3cd406fc), SPH_C32(0xb1f490bc) }, + { SPH_C32(0x2e390000), SPH_C32(0x64dd6689), SPH_C32(0x3cd406fc), + SPH_C32(0xb1f490bc), SPH_C32(0x7f650010), SPH_C32(0x242e1472), + SPH_C32(0xc03320fe), SPH_C32(0xc0a3c0dd) }, + { SPH_C32(0x7f650010), SPH_C32(0x242e1472), SPH_C32(0xc03320fe), + SPH_C32(0xc0a3c0dd), SPH_C32(0x515c0010), SPH_C32(0x40f372fb), + SPH_C32(0xfce72602), SPH_C32(0x71575061) }, + { SPH_C32(0xa2b80020), SPH_C32(0x81e7e5f6), SPH_C32(0xf9ce4c04), + SPH_C32(0xe2afa0c0), SPH_C32(0x5c720000), SPH_C32(0xc9bacd12), + SPH_C32(0x79a90df9), SPH_C32(0x63e92178) }, + { SPH_C32(0xf3e40030), SPH_C32(0xc114970d), SPH_C32(0x05296a06), + SPH_C32(0x93f8f0a1), SPH_C32(0x724b0000), SPH_C32(0xad67ab9b), + SPH_C32(0x457d0b05), SPH_C32(0xd21db1c4) }, + { SPH_C32(0x8c810020), SPH_C32(0xe53a837f), SPH_C32(0xc51a4af8), + SPH_C32(0x535b307c), SPH_C32(0x23170010), SPH_C32(0xed94d960), + SPH_C32(0xb99a2d07), SPH_C32(0xa34ae1a5) }, + { SPH_C32(0xdddd0030), SPH_C32(0xa5c9f184), SPH_C32(0x39fd6cfa), + SPH_C32(0x220c601d), SPH_C32(0x0d2e0010), SPH_C32(0x8949bfe9), + SPH_C32(0x854e2bfb), SPH_C32(0x12be7119) }, + { SPH_C32(0x5c720000), SPH_C32(0xc9bacd12), SPH_C32(0x79a90df9), + SPH_C32(0x63e92178), SPH_C32(0xfeca0020), SPH_C32(0x485d28e4), + SPH_C32(0x806741fd), SPH_C32(0x814681b8) }, + { SPH_C32(0x0d2e0010), SPH_C32(0x8949bfe9), SPH_C32(0x854e2bfb), + SPH_C32(0x12be7119), SPH_C32(0xd0f30020), SPH_C32(0x2c804e6d), + SPH_C32(0xbcb34701), SPH_C32(0x30b21104) }, + { SPH_C32(0x724b0000), SPH_C32(0xad67ab9b), SPH_C32(0x457d0b05), + SPH_C32(0xd21db1c4), SPH_C32(0x81af0030), SPH_C32(0x6c733c96), + SPH_C32(0x40546103), SPH_C32(0x41e54165) }, + { SPH_C32(0x23170010), SPH_C32(0xed94d960), SPH_C32(0xb99a2d07), + SPH_C32(0xa34ae1a5), SPH_C32(0xaf960030), SPH_C32(0x08ae5a1f), + SPH_C32(0x7c8067ff), SPH_C32(0xf011d1d9) }, + { SPH_C32(0xfeca0020), SPH_C32(0x485d28e4), SPH_C32(0x806741fd), + SPH_C32(0x814681b8), SPH_C32(0xa2b80020), SPH_C32(0x81e7e5f6), + SPH_C32(0xf9ce4c04), SPH_C32(0xe2afa0c0) }, + { SPH_C32(0xaf960030), SPH_C32(0x08ae5a1f), SPH_C32(0x7c8067ff), + SPH_C32(0xf011d1d9), SPH_C32(0x8c810020), SPH_C32(0xe53a837f), + SPH_C32(0xc51a4af8), SPH_C32(0x535b307c) }, + { SPH_C32(0xd0f30020), SPH_C32(0x2c804e6d), SPH_C32(0xbcb34701), + SPH_C32(0x30b21104), SPH_C32(0xdddd0030), SPH_C32(0xa5c9f184), + SPH_C32(0x39fd6cfa), SPH_C32(0x220c601d) }, + { SPH_C32(0x81af0030), SPH_C32(0x6c733c96), SPH_C32(0x40546103), + SPH_C32(0x41e54165), SPH_C32(0xf3e40030), SPH_C32(0xc114970d), + SPH_C32(0x05296a06), SPH_C32(0x93f8f0a1) } +}; + +static const sph_u32 T256_24[16][8] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000) }, + { SPH_C32(0xd0080004), SPH_C32(0x8c768f77), SPH_C32(0x9dc5b050), + SPH_C32(0xaf4a29da), SPH_C32(0x6ba90000), SPH_C32(0x40ebf9aa), + SPH_C32(0x98321c3d), SPH_C32(0x76acc733) }, + { SPH_C32(0x6ba90000), SPH_C32(0x40ebf9aa), SPH_C32(0x98321c3d), + SPH_C32(0x76acc733), SPH_C32(0xbba10004), SPH_C32(0xcc9d76dd), + SPH_C32(0x05f7ac6d), SPH_C32(0xd9e6eee9) }, + { SPH_C32(0xbba10004), SPH_C32(0xcc9d76dd), SPH_C32(0x05f7ac6d), + SPH_C32(0xd9e6eee9), SPH_C32(0xd0080004), SPH_C32(0x8c768f77), + SPH_C32(0x9dc5b050), SPH_C32(0xaf4a29da) }, + { SPH_C32(0xa8ae0008), SPH_C32(0x2079397d), SPH_C32(0xfe739301), + SPH_C32(0xb8a92831), SPH_C32(0x171c0000), SPH_C32(0xb26e3344), + SPH_C32(0x9e6a837e), SPH_C32(0x58f8485f) }, + { SPH_C32(0x78a6000c), SPH_C32(0xac0fb60a), SPH_C32(0x63b62351), + SPH_C32(0x17e301eb), SPH_C32(0x7cb50000), SPH_C32(0xf285caee), + SPH_C32(0x06589f43), SPH_C32(0x2e548f6c) }, + { SPH_C32(0xc3070008), SPH_C32(0x6092c0d7), SPH_C32(0x66418f3c), + SPH_C32(0xce05ef02), SPH_C32(0xacbd0004), SPH_C32(0x7ef34599), + SPH_C32(0x9b9d2f13), SPH_C32(0x811ea6b6) }, + { SPH_C32(0x130f000c), SPH_C32(0xece44fa0), SPH_C32(0xfb843f6c), + SPH_C32(0x614fc6d8), SPH_C32(0xc7140004), SPH_C32(0x3e18bc33), + SPH_C32(0x03af332e), SPH_C32(0xf7b26185) }, + { SPH_C32(0x171c0000), SPH_C32(0xb26e3344), SPH_C32(0x9e6a837e), + SPH_C32(0x58f8485f), SPH_C32(0xbfb20008), SPH_C32(0x92170a39), + SPH_C32(0x6019107f), SPH_C32(0xe051606e) }, + { SPH_C32(0xc7140004), SPH_C32(0x3e18bc33), SPH_C32(0x03af332e), + SPH_C32(0xf7b26185), SPH_C32(0xd41b0008), SPH_C32(0xd2fcf393), + SPH_C32(0xf82b0c42), SPH_C32(0x96fda75d) }, + { SPH_C32(0x7cb50000), SPH_C32(0xf285caee), SPH_C32(0x06589f43), + SPH_C32(0x2e548f6c), SPH_C32(0x0413000c), SPH_C32(0x5e8a7ce4), + SPH_C32(0x65eebc12), SPH_C32(0x39b78e87) }, + { SPH_C32(0xacbd0004), SPH_C32(0x7ef34599), SPH_C32(0x9b9d2f13), + SPH_C32(0x811ea6b6), SPH_C32(0x6fba000c), SPH_C32(0x1e61854e), + SPH_C32(0xfddca02f), SPH_C32(0x4f1b49b4) }, + { SPH_C32(0xbfb20008), SPH_C32(0x92170a39), SPH_C32(0x6019107f), + SPH_C32(0xe051606e), SPH_C32(0xa8ae0008), SPH_C32(0x2079397d), + SPH_C32(0xfe739301), SPH_C32(0xb8a92831) }, + { SPH_C32(0x6fba000c), SPH_C32(0x1e61854e), SPH_C32(0xfddca02f), + SPH_C32(0x4f1b49b4), SPH_C32(0xc3070008), SPH_C32(0x6092c0d7), + SPH_C32(0x66418f3c), SPH_C32(0xce05ef02) }, + { SPH_C32(0xd41b0008), SPH_C32(0xd2fcf393), SPH_C32(0xf82b0c42), + SPH_C32(0x96fda75d), SPH_C32(0x130f000c), SPH_C32(0xece44fa0), + SPH_C32(0xfb843f6c), SPH_C32(0x614fc6d8) }, + { SPH_C32(0x0413000c), SPH_C32(0x5e8a7ce4), SPH_C32(0x65eebc12), + SPH_C32(0x39b78e87), SPH_C32(0x78a6000c), SPH_C32(0xac0fb60a), + SPH_C32(0x63b62351), SPH_C32(0x17e301eb) } +}; + +static const sph_u32 T256_28[16][8] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000) }, + { SPH_C32(0xc04e0001), SPH_C32(0x33b9c010), SPH_C32(0xae0ebb05), + SPH_C32(0xb5a4c63b), SPH_C32(0xc8f10000), SPH_C32(0x0b2de782), + SPH_C32(0x6bf648a4), SPH_C32(0x539cbdbf) }, + { SPH_C32(0xc8f10000), SPH_C32(0x0b2de782), SPH_C32(0x6bf648a4), + SPH_C32(0x539cbdbf), SPH_C32(0x08bf0001), SPH_C32(0x38942792), + SPH_C32(0xc5f8f3a1), SPH_C32(0xe6387b84) }, + { SPH_C32(0x08bf0001), SPH_C32(0x38942792), SPH_C32(0xc5f8f3a1), + SPH_C32(0xe6387b84), SPH_C32(0xc04e0001), SPH_C32(0x33b9c010), + SPH_C32(0xae0ebb05), SPH_C32(0xb5a4c63b) }, + { SPH_C32(0x88230002), SPH_C32(0x5fe7a7b3), SPH_C32(0x99e585aa), + SPH_C32(0x8d75f7f1), SPH_C32(0x51ac0000), SPH_C32(0x25e30f14), + SPH_C32(0x79e22a4c), SPH_C32(0x1298bd46) }, + { SPH_C32(0x486d0003), SPH_C32(0x6c5e67a3), SPH_C32(0x37eb3eaf), + SPH_C32(0x38d131ca), SPH_C32(0x995d0000), SPH_C32(0x2ecee896), + SPH_C32(0x121462e8), SPH_C32(0x410400f9) }, + { SPH_C32(0x40d20002), SPH_C32(0x54ca4031), SPH_C32(0xf213cd0e), + SPH_C32(0xdee94a4e), SPH_C32(0x59130001), SPH_C32(0x1d772886), + SPH_C32(0xbc1ad9ed), SPH_C32(0xf4a0c6c2) }, + { SPH_C32(0x809c0003), SPH_C32(0x67738021), SPH_C32(0x5c1d760b), + SPH_C32(0x6b4d8c75), SPH_C32(0x91e20001), SPH_C32(0x165acf04), + SPH_C32(0xd7ec9149), SPH_C32(0xa73c7b7d) }, + { SPH_C32(0x51ac0000), SPH_C32(0x25e30f14), SPH_C32(0x79e22a4c), + SPH_C32(0x1298bd46), SPH_C32(0xd98f0002), SPH_C32(0x7a04a8a7), + SPH_C32(0xe007afe6), SPH_C32(0x9fed4ab7) }, + { SPH_C32(0x91e20001), SPH_C32(0x165acf04), SPH_C32(0xd7ec9149), + SPH_C32(0xa73c7b7d), SPH_C32(0x117e0002), SPH_C32(0x71294f25), + SPH_C32(0x8bf1e742), SPH_C32(0xcc71f708) }, + { SPH_C32(0x995d0000), SPH_C32(0x2ecee896), SPH_C32(0x121462e8), + SPH_C32(0x410400f9), SPH_C32(0xd1300003), SPH_C32(0x42908f35), + SPH_C32(0x25ff5c47), SPH_C32(0x79d53133) }, + { SPH_C32(0x59130001), SPH_C32(0x1d772886), SPH_C32(0xbc1ad9ed), + SPH_C32(0xf4a0c6c2), SPH_C32(0x19c10003), SPH_C32(0x49bd68b7), + SPH_C32(0x4e0914e3), SPH_C32(0x2a498c8c) }, + { SPH_C32(0xd98f0002), SPH_C32(0x7a04a8a7), SPH_C32(0xe007afe6), + SPH_C32(0x9fed4ab7), SPH_C32(0x88230002), SPH_C32(0x5fe7a7b3), + SPH_C32(0x99e585aa), SPH_C32(0x8d75f7f1) }, + { SPH_C32(0x19c10003), SPH_C32(0x49bd68b7), SPH_C32(0x4e0914e3), + SPH_C32(0x2a498c8c), SPH_C32(0x40d20002), SPH_C32(0x54ca4031), + SPH_C32(0xf213cd0e), SPH_C32(0xdee94a4e) }, + { SPH_C32(0x117e0002), SPH_C32(0x71294f25), SPH_C32(0x8bf1e742), + SPH_C32(0xcc71f708), SPH_C32(0x809c0003), SPH_C32(0x67738021), + SPH_C32(0x5c1d760b), SPH_C32(0x6b4d8c75) }, + { SPH_C32(0xd1300003), SPH_C32(0x42908f35), SPH_C32(0x25ff5c47), + SPH_C32(0x79d53133), SPH_C32(0x486d0003), SPH_C32(0x6c5e67a3), + SPH_C32(0x37eb3eaf), SPH_C32(0x38d131ca) } +}; + +#define INPUT_SMALL do { \ + unsigned acc = buf[0]; \ + const sph_u32 *rp; \ + rp = &T256_0[acc >> 4][0]; \ + m0 = rp[0]; \ + m1 = rp[1]; \ + m2 = rp[2]; \ + m3 = rp[3]; \ + m4 = rp[4]; \ + m5 = rp[5]; \ + m6 = rp[6]; \ + m7 = rp[7]; \ + rp = &T256_4[acc & 0x0f][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + acc = buf[1]; \ + rp = &T256_8[acc >> 4][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + rp = &T256_12[acc & 0x0f][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + acc = buf[2]; \ + rp = &T256_16[acc >> 4][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + rp = &T256_20[acc & 0x0f][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + acc = buf[3]; \ + rp = &T256_24[acc >> 4][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + rp = &T256_28[acc & 0x0f][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + } while (0) + +#endif + +#if SPH_HAMSI_EXPAND_SMALL == 5 + +static const sph_u32 T256_0[32][8] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000) }, + { SPH_C32(0x97530000), SPH_C32(0x204f6ed3), SPH_C32(0x77b9e80f), + SPH_C32(0xa1ec5ec1), SPH_C32(0x7e792000), SPH_C32(0x9418e22f), + SPH_C32(0x6643d258), SPH_C32(0x9c255be5) }, + { SPH_C32(0x121b4000), SPH_C32(0x5b17d9e8), SPH_C32(0x8dfacfab), + SPH_C32(0xce36cc72), SPH_C32(0xe6570000), SPH_C32(0x4bb33a25), + SPH_C32(0x848598ba), SPH_C32(0x1041003e) }, + { SPH_C32(0x85484000), SPH_C32(0x7b58b73b), SPH_C32(0xfa4327a4), + SPH_C32(0x6fda92b3), SPH_C32(0x982e2000), SPH_C32(0xdfabd80a), + SPH_C32(0xe2c64ae2), SPH_C32(0x8c645bdb) }, + { SPH_C32(0xe6570000), SPH_C32(0x4bb33a25), SPH_C32(0x848598ba), + SPH_C32(0x1041003e), SPH_C32(0xf44c4000), SPH_C32(0x10a4e3cd), + SPH_C32(0x097f5711), SPH_C32(0xde77cc4c) }, + { SPH_C32(0x71040000), SPH_C32(0x6bfc54f6), SPH_C32(0xf33c70b5), + SPH_C32(0xb1ad5eff), SPH_C32(0x8a356000), SPH_C32(0x84bc01e2), + SPH_C32(0x6f3c8549), SPH_C32(0x425297a9) }, + { SPH_C32(0xf44c4000), SPH_C32(0x10a4e3cd), SPH_C32(0x097f5711), + SPH_C32(0xde77cc4c), SPH_C32(0x121b4000), SPH_C32(0x5b17d9e8), + SPH_C32(0x8dfacfab), SPH_C32(0xce36cc72) }, + { SPH_C32(0x631f4000), SPH_C32(0x30eb8d1e), SPH_C32(0x7ec6bf1e), + SPH_C32(0x7f9b928d), SPH_C32(0x6c626000), SPH_C32(0xcf0f3bc7), + SPH_C32(0xebb91df3), SPH_C32(0x52139797) }, + { SPH_C32(0xe4788000), SPH_C32(0x859673c1), SPH_C32(0xb5fb2452), + SPH_C32(0x29cc5edf), SPH_C32(0x045f0000), SPH_C32(0x9c4a93c9), + SPH_C32(0x62fc79d0), SPH_C32(0x731ebdc2) }, + { SPH_C32(0x732b8000), SPH_C32(0xa5d91d12), SPH_C32(0xc242cc5d), + SPH_C32(0x8820001e), SPH_C32(0x7a262000), SPH_C32(0x085271e6), + SPH_C32(0x04bfab88), SPH_C32(0xef3be627) }, + { SPH_C32(0xf663c000), SPH_C32(0xde81aa29), SPH_C32(0x3801ebf9), + SPH_C32(0xe7fa92ad), SPH_C32(0xe2080000), SPH_C32(0xd7f9a9ec), + SPH_C32(0xe679e16a), SPH_C32(0x635fbdfc) }, + { SPH_C32(0x6130c000), SPH_C32(0xfecec4fa), SPH_C32(0x4fb803f6), + SPH_C32(0x4616cc6c), SPH_C32(0x9c712000), SPH_C32(0x43e14bc3), + SPH_C32(0x803a3332), SPH_C32(0xff7ae619) }, + { SPH_C32(0x022f8000), SPH_C32(0xce2549e4), SPH_C32(0x317ebce8), + SPH_C32(0x398d5ee1), SPH_C32(0xf0134000), SPH_C32(0x8cee7004), + SPH_C32(0x6b832ec1), SPH_C32(0xad69718e) }, + { SPH_C32(0x957c8000), SPH_C32(0xee6a2737), SPH_C32(0x46c754e7), + SPH_C32(0x98610020), SPH_C32(0x8e6a6000), SPH_C32(0x18f6922b), + SPH_C32(0x0dc0fc99), SPH_C32(0x314c2a6b) }, + { SPH_C32(0x1034c000), SPH_C32(0x9532900c), SPH_C32(0xbc847343), + SPH_C32(0xf7bb9293), SPH_C32(0x16444000), SPH_C32(0xc75d4a21), + SPH_C32(0xef06b67b), SPH_C32(0xbd2871b0) }, + { SPH_C32(0x8767c000), SPH_C32(0xb57dfedf), SPH_C32(0xcb3d9b4c), + SPH_C32(0x5657cc52), SPH_C32(0x683d6000), SPH_C32(0x5345a80e), + SPH_C32(0x89456423), SPH_C32(0x210d2a55) }, + { SPH_C32(0x045f0000), SPH_C32(0x9c4a93c9), SPH_C32(0x62fc79d0), + SPH_C32(0x731ebdc2), SPH_C32(0xe0278000), SPH_C32(0x19dce008), + SPH_C32(0xd7075d82), SPH_C32(0x5ad2e31d) }, + { SPH_C32(0x930c0000), SPH_C32(0xbc05fd1a), SPH_C32(0x154591df), + SPH_C32(0xd2f2e303), SPH_C32(0x9e5ea000), SPH_C32(0x8dc40227), + SPH_C32(0xb1448fda), SPH_C32(0xc6f7b8f8) }, + { SPH_C32(0x16444000), SPH_C32(0xc75d4a21), SPH_C32(0xef06b67b), + SPH_C32(0xbd2871b0), SPH_C32(0x06708000), SPH_C32(0x526fda2d), + SPH_C32(0x5382c538), SPH_C32(0x4a93e323) }, + { SPH_C32(0x81174000), SPH_C32(0xe71224f2), SPH_C32(0x98bf5e74), + SPH_C32(0x1cc42f71), SPH_C32(0x7809a000), SPH_C32(0xc6773802), + SPH_C32(0x35c11760), SPH_C32(0xd6b6b8c6) }, + { SPH_C32(0xe2080000), SPH_C32(0xd7f9a9ec), SPH_C32(0xe679e16a), + SPH_C32(0x635fbdfc), SPH_C32(0x146bc000), SPH_C32(0x097803c5), + SPH_C32(0xde780a93), SPH_C32(0x84a52f51) }, + { SPH_C32(0x755b0000), SPH_C32(0xf7b6c73f), SPH_C32(0x91c00965), + SPH_C32(0xc2b3e33d), SPH_C32(0x6a12e000), SPH_C32(0x9d60e1ea), + SPH_C32(0xb83bd8cb), SPH_C32(0x188074b4) }, + { SPH_C32(0xf0134000), SPH_C32(0x8cee7004), SPH_C32(0x6b832ec1), + SPH_C32(0xad69718e), SPH_C32(0xf23cc000), SPH_C32(0x42cb39e0), + SPH_C32(0x5afd9229), SPH_C32(0x94e42f6f) }, + { SPH_C32(0x67404000), SPH_C32(0xaca11ed7), SPH_C32(0x1c3ac6ce), + SPH_C32(0x0c852f4f), SPH_C32(0x8c45e000), SPH_C32(0xd6d3dbcf), + SPH_C32(0x3cbe4071), SPH_C32(0x08c1748a) }, + { SPH_C32(0xe0278000), SPH_C32(0x19dce008), SPH_C32(0xd7075d82), + SPH_C32(0x5ad2e31d), SPH_C32(0xe4788000), SPH_C32(0x859673c1), + SPH_C32(0xb5fb2452), SPH_C32(0x29cc5edf) }, + { SPH_C32(0x77748000), SPH_C32(0x39938edb), SPH_C32(0xa0beb58d), + SPH_C32(0xfb3ebddc), SPH_C32(0x9a01a000), SPH_C32(0x118e91ee), + SPH_C32(0xd3b8f60a), SPH_C32(0xb5e9053a) }, + { SPH_C32(0xf23cc000), SPH_C32(0x42cb39e0), SPH_C32(0x5afd9229), + SPH_C32(0x94e42f6f), SPH_C32(0x022f8000), SPH_C32(0xce2549e4), + SPH_C32(0x317ebce8), SPH_C32(0x398d5ee1) }, + { SPH_C32(0x656fc000), SPH_C32(0x62845733), SPH_C32(0x2d447a26), + SPH_C32(0x350871ae), SPH_C32(0x7c56a000), SPH_C32(0x5a3dabcb), + SPH_C32(0x573d6eb0), SPH_C32(0xa5a80504) }, + { SPH_C32(0x06708000), SPH_C32(0x526fda2d), SPH_C32(0x5382c538), + SPH_C32(0x4a93e323), SPH_C32(0x1034c000), SPH_C32(0x9532900c), + SPH_C32(0xbc847343), SPH_C32(0xf7bb9293) }, + { SPH_C32(0x91238000), SPH_C32(0x7220b4fe), SPH_C32(0x243b2d37), + SPH_C32(0xeb7fbde2), SPH_C32(0x6e4de000), SPH_C32(0x012a7223), + SPH_C32(0xdac7a11b), SPH_C32(0x6b9ec976) }, + { SPH_C32(0x146bc000), SPH_C32(0x097803c5), SPH_C32(0xde780a93), + SPH_C32(0x84a52f51), SPH_C32(0xf663c000), SPH_C32(0xde81aa29), + SPH_C32(0x3801ebf9), SPH_C32(0xe7fa92ad) }, + { SPH_C32(0x8338c000), SPH_C32(0x29376d16), SPH_C32(0xa9c1e29c), + SPH_C32(0x25497190), SPH_C32(0x881ae000), SPH_C32(0x4a994806), + SPH_C32(0x5e4239a1), SPH_C32(0x7bdfc948) } +}; + +static const sph_u32 T256_5[32][8] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000) }, + { SPH_C32(0xde320800), SPH_C32(0x288350fe), SPH_C32(0x71852ac7), + SPH_C32(0xa6bf9f96), SPH_C32(0xe18b0000), SPH_C32(0x5459887d), + SPH_C32(0xbf1283d3), SPH_C32(0x1b666a73) }, + { SPH_C32(0xe18b0000), SPH_C32(0x5459887d), SPH_C32(0xbf1283d3), + SPH_C32(0x1b666a73), SPH_C32(0x3fb90800), SPH_C32(0x7cdad883), + SPH_C32(0xce97a914), SPH_C32(0xbdd9f5e5) }, + { SPH_C32(0x3fb90800), SPH_C32(0x7cdad883), SPH_C32(0xce97a914), + SPH_C32(0xbdd9f5e5), SPH_C32(0xde320800), SPH_C32(0x288350fe), + SPH_C32(0x71852ac7), SPH_C32(0xa6bf9f96) }, + { SPH_C32(0x74951000), SPH_C32(0x5a2b467e), SPH_C32(0x88fd1d2b), + SPH_C32(0x1ee68292), SPH_C32(0xcba90000), SPH_C32(0x90273769), + SPH_C32(0xbbdcf407), SPH_C32(0xd0f4af61) }, + { SPH_C32(0xaaa71800), SPH_C32(0x72a81680), SPH_C32(0xf97837ec), + SPH_C32(0xb8591d04), SPH_C32(0x2a220000), SPH_C32(0xc47ebf14), + SPH_C32(0x04ce77d4), SPH_C32(0xcb92c512) }, + { SPH_C32(0x951e1000), SPH_C32(0x0e72ce03), SPH_C32(0x37ef9ef8), + SPH_C32(0x0580e8e1), SPH_C32(0xf4100800), SPH_C32(0xecfdefea), + SPH_C32(0x754b5d13), SPH_C32(0x6d2d5a84) }, + { SPH_C32(0x4b2c1800), SPH_C32(0x26f19efd), SPH_C32(0x466ab43f), + SPH_C32(0xa33f7777), SPH_C32(0x159b0800), SPH_C32(0xb8a46797), + SPH_C32(0xca59dec0), SPH_C32(0x764b30f7) }, + { SPH_C32(0xcba90000), SPH_C32(0x90273769), SPH_C32(0xbbdcf407), + SPH_C32(0xd0f4af61), SPH_C32(0xbf3c1000), SPH_C32(0xca0c7117), + SPH_C32(0x3321e92c), SPH_C32(0xce122df3) }, + { SPH_C32(0x159b0800), SPH_C32(0xb8a46797), SPH_C32(0xca59dec0), + SPH_C32(0x764b30f7), SPH_C32(0x5eb71000), SPH_C32(0x9e55f96a), + SPH_C32(0x8c336aff), SPH_C32(0xd5744780) }, + { SPH_C32(0x2a220000), SPH_C32(0xc47ebf14), SPH_C32(0x04ce77d4), + SPH_C32(0xcb92c512), SPH_C32(0x80851800), SPH_C32(0xb6d6a994), + SPH_C32(0xfdb64038), SPH_C32(0x73cbd816) }, + { SPH_C32(0xf4100800), SPH_C32(0xecfdefea), SPH_C32(0x754b5d13), + SPH_C32(0x6d2d5a84), SPH_C32(0x610e1800), SPH_C32(0xe28f21e9), + SPH_C32(0x42a4c3eb), SPH_C32(0x68adb265) }, + { SPH_C32(0xbf3c1000), SPH_C32(0xca0c7117), SPH_C32(0x3321e92c), + SPH_C32(0xce122df3), SPH_C32(0x74951000), SPH_C32(0x5a2b467e), + SPH_C32(0x88fd1d2b), SPH_C32(0x1ee68292) }, + { SPH_C32(0x610e1800), SPH_C32(0xe28f21e9), SPH_C32(0x42a4c3eb), + SPH_C32(0x68adb265), SPH_C32(0x951e1000), SPH_C32(0x0e72ce03), + SPH_C32(0x37ef9ef8), SPH_C32(0x0580e8e1) }, + { SPH_C32(0x5eb71000), SPH_C32(0x9e55f96a), SPH_C32(0x8c336aff), + SPH_C32(0xd5744780), SPH_C32(0x4b2c1800), SPH_C32(0x26f19efd), + SPH_C32(0x466ab43f), SPH_C32(0xa33f7777) }, + { SPH_C32(0x80851800), SPH_C32(0xb6d6a994), SPH_C32(0xfdb64038), + SPH_C32(0x73cbd816), SPH_C32(0xaaa71800), SPH_C32(0x72a81680), + SPH_C32(0xf97837ec), SPH_C32(0xb8591d04) }, + { SPH_C32(0xe92a2000), SPH_C32(0xb4578cfc), SPH_C32(0x11fa3a57), + SPH_C32(0x3dc90524), SPH_C32(0x97530000), SPH_C32(0x204f6ed3), + SPH_C32(0x77b9e80f), SPH_C32(0xa1ec5ec1) }, + { SPH_C32(0x37182800), SPH_C32(0x9cd4dc02), SPH_C32(0x607f1090), + SPH_C32(0x9b769ab2), SPH_C32(0x76d80000), SPH_C32(0x7416e6ae), + SPH_C32(0xc8ab6bdc), SPH_C32(0xba8a34b2) }, + { SPH_C32(0x08a12000), SPH_C32(0xe00e0481), SPH_C32(0xaee8b984), + SPH_C32(0x26af6f57), SPH_C32(0xa8ea0800), SPH_C32(0x5c95b650), + SPH_C32(0xb92e411b), SPH_C32(0x1c35ab24) }, + { SPH_C32(0xd6932800), SPH_C32(0xc88d547f), SPH_C32(0xdf6d9343), + SPH_C32(0x8010f0c1), SPH_C32(0x49610800), SPH_C32(0x08cc3e2d), + SPH_C32(0x063cc2c8), SPH_C32(0x0753c157) }, + { SPH_C32(0x9dbf3000), SPH_C32(0xee7cca82), SPH_C32(0x9907277c), + SPH_C32(0x232f87b6), SPH_C32(0x5cfa0000), SPH_C32(0xb06859ba), + SPH_C32(0xcc651c08), SPH_C32(0x7118f1a0) }, + { SPH_C32(0x438d3800), SPH_C32(0xc6ff9a7c), SPH_C32(0xe8820dbb), + SPH_C32(0x85901820), SPH_C32(0xbd710000), SPH_C32(0xe431d1c7), + SPH_C32(0x73779fdb), SPH_C32(0x6a7e9bd3) }, + { SPH_C32(0x7c343000), SPH_C32(0xba2542ff), SPH_C32(0x2615a4af), + SPH_C32(0x3849edc5), SPH_C32(0x63430800), SPH_C32(0xccb28139), + SPH_C32(0x02f2b51c), SPH_C32(0xccc10445) }, + { SPH_C32(0xa2063800), SPH_C32(0x92a61201), SPH_C32(0x57908e68), + SPH_C32(0x9ef67253), SPH_C32(0x82c80800), SPH_C32(0x98eb0944), + SPH_C32(0xbde036cf), SPH_C32(0xd7a76e36) }, + { SPH_C32(0x22832000), SPH_C32(0x2470bb95), SPH_C32(0xaa26ce50), + SPH_C32(0xed3daa45), SPH_C32(0x286f1000), SPH_C32(0xea431fc4), + SPH_C32(0x44980123), SPH_C32(0x6ffe7332) }, + { SPH_C32(0xfcb12800), SPH_C32(0x0cf3eb6b), SPH_C32(0xdba3e497), + SPH_C32(0x4b8235d3), SPH_C32(0xc9e41000), SPH_C32(0xbe1a97b9), + SPH_C32(0xfb8a82f0), SPH_C32(0x74981941) }, + { SPH_C32(0xc3082000), SPH_C32(0x702933e8), SPH_C32(0x15344d83), + SPH_C32(0xf65bc036), SPH_C32(0x17d61800), SPH_C32(0x9699c747), + SPH_C32(0x8a0fa837), SPH_C32(0xd22786d7) }, + { SPH_C32(0x1d3a2800), SPH_C32(0x58aa6316), SPH_C32(0x64b16744), + SPH_C32(0x50e45fa0), SPH_C32(0xf65d1800), SPH_C32(0xc2c04f3a), + SPH_C32(0x351d2be4), SPH_C32(0xc941eca4) }, + { SPH_C32(0x56163000), SPH_C32(0x7e5bfdeb), SPH_C32(0x22dbd37b), + SPH_C32(0xf3db28d7), SPH_C32(0xe3c61000), SPH_C32(0x7a6428ad), + SPH_C32(0xff44f524), SPH_C32(0xbf0adc53) }, + { SPH_C32(0x88243800), SPH_C32(0x56d8ad15), SPH_C32(0x535ef9bc), + SPH_C32(0x5564b741), SPH_C32(0x024d1000), SPH_C32(0x2e3da0d0), + SPH_C32(0x405676f7), SPH_C32(0xa46cb620) }, + { SPH_C32(0xb79d3000), SPH_C32(0x2a027596), SPH_C32(0x9dc950a8), + SPH_C32(0xe8bd42a4), SPH_C32(0xdc7f1800), SPH_C32(0x06bef02e), + SPH_C32(0x31d35c30), SPH_C32(0x02d329b6) }, + { SPH_C32(0x69af3800), SPH_C32(0x02812568), SPH_C32(0xec4c7a6f), + SPH_C32(0x4e02dd32), SPH_C32(0x3df41800), SPH_C32(0x52e77853), + SPH_C32(0x8ec1dfe3), SPH_C32(0x19b543c5) } +}; + +static const sph_u32 T256_10[32][8] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000) }, + { SPH_C32(0x734c0000), SPH_C32(0x956fa7d6), SPH_C32(0xa29d1297), + SPH_C32(0x6ee56854), SPH_C32(0xc4e80100), SPH_C32(0x1f70960e), + SPH_C32(0x2714ca3c), SPH_C32(0x88210c30) }, + { SPH_C32(0xa7b80200), SPH_C32(0x1f128433), SPH_C32(0x60e5f9f2), + SPH_C32(0x9e147576), SPH_C32(0xee260000), SPH_C32(0x124b683e), + SPH_C32(0x80c2d68f), SPH_C32(0x3bf3ab2c) }, + { SPH_C32(0xd4f40200), SPH_C32(0x8a7d23e5), SPH_C32(0xc278eb65), + SPH_C32(0xf0f11d22), SPH_C32(0x2ace0100), SPH_C32(0x0d3bfe30), + SPH_C32(0xa7d61cb3), SPH_C32(0xb3d2a71c) }, + { SPH_C32(0xee260000), SPH_C32(0x124b683e), SPH_C32(0x80c2d68f), + SPH_C32(0x3bf3ab2c), SPH_C32(0x499e0200), SPH_C32(0x0d59ec0d), + SPH_C32(0xe0272f7d), SPH_C32(0xa5e7de5a) }, + { SPH_C32(0x9d6a0000), SPH_C32(0x8724cfe8), SPH_C32(0x225fc418), + SPH_C32(0x5516c378), SPH_C32(0x8d760300), SPH_C32(0x12297a03), + SPH_C32(0xc733e541), SPH_C32(0x2dc6d26a) }, + { SPH_C32(0x499e0200), SPH_C32(0x0d59ec0d), SPH_C32(0xe0272f7d), + SPH_C32(0xa5e7de5a), SPH_C32(0xa7b80200), SPH_C32(0x1f128433), + SPH_C32(0x60e5f9f2), SPH_C32(0x9e147576) }, + { SPH_C32(0x3ad20200), SPH_C32(0x98364bdb), SPH_C32(0x42ba3dea), + SPH_C32(0xcb02b60e), SPH_C32(0x63500300), SPH_C32(0x0062123d), + SPH_C32(0x47f133ce), SPH_C32(0x16357946) }, + { SPH_C32(0x8f3e0400), SPH_C32(0x0d9dc877), SPH_C32(0x6fc548e1), + SPH_C32(0x898d2cd6), SPH_C32(0x14bd0000), SPH_C32(0x2fba37ff), + SPH_C32(0x6a72e5bb), SPH_C32(0x247febe6) }, + { SPH_C32(0xfc720400), SPH_C32(0x98f26fa1), SPH_C32(0xcd585a76), + SPH_C32(0xe7684482), SPH_C32(0xd0550100), SPH_C32(0x30caa1f1), + SPH_C32(0x4d662f87), SPH_C32(0xac5ee7d6) }, + { SPH_C32(0x28860600), SPH_C32(0x128f4c44), SPH_C32(0x0f20b113), + SPH_C32(0x179959a0), SPH_C32(0xfa9b0000), SPH_C32(0x3df15fc1), + SPH_C32(0xeab03334), SPH_C32(0x1f8c40ca) }, + { SPH_C32(0x5bca0600), SPH_C32(0x87e0eb92), SPH_C32(0xadbda384), + SPH_C32(0x797c31f4), SPH_C32(0x3e730100), SPH_C32(0x2281c9cf), + SPH_C32(0xcda4f908), SPH_C32(0x97ad4cfa) }, + { SPH_C32(0x61180400), SPH_C32(0x1fd6a049), SPH_C32(0xef079e6e), + SPH_C32(0xb27e87fa), SPH_C32(0x5d230200), SPH_C32(0x22e3dbf2), + SPH_C32(0x8a55cac6), SPH_C32(0x819835bc) }, + { SPH_C32(0x12540400), SPH_C32(0x8ab9079f), SPH_C32(0x4d9a8cf9), + SPH_C32(0xdc9befae), SPH_C32(0x99cb0300), SPH_C32(0x3d934dfc), + SPH_C32(0xad4100fa), SPH_C32(0x09b9398c) }, + { SPH_C32(0xc6a00600), SPH_C32(0x00c4247a), SPH_C32(0x8fe2679c), + SPH_C32(0x2c6af28c), SPH_C32(0xb3050200), SPH_C32(0x30a8b3cc), + SPH_C32(0x0a971c49), SPH_C32(0xba6b9e90) }, + { SPH_C32(0xb5ec0600), SPH_C32(0x95ab83ac), SPH_C32(0x2d7f750b), + SPH_C32(0x428f9ad8), SPH_C32(0x77ed0300), SPH_C32(0x2fd825c2), + SPH_C32(0x2d83d675), SPH_C32(0x324a92a0) }, + { SPH_C32(0x14bd0000), SPH_C32(0x2fba37ff), SPH_C32(0x6a72e5bb), + SPH_C32(0x247febe6), SPH_C32(0x9b830400), SPH_C32(0x2227ff88), + SPH_C32(0x05b7ad5a), SPH_C32(0xadf2c730) }, + { SPH_C32(0x67f10000), SPH_C32(0xbad59029), SPH_C32(0xc8eff72c), + SPH_C32(0x4a9a83b2), SPH_C32(0x5f6b0500), SPH_C32(0x3d576986), + SPH_C32(0x22a36766), SPH_C32(0x25d3cb00) }, + { SPH_C32(0xb3050200), SPH_C32(0x30a8b3cc), SPH_C32(0x0a971c49), + SPH_C32(0xba6b9e90), SPH_C32(0x75a50400), SPH_C32(0x306c97b6), + SPH_C32(0x85757bd5), SPH_C32(0x96016c1c) }, + { SPH_C32(0xc0490200), SPH_C32(0xa5c7141a), SPH_C32(0xa80a0ede), + SPH_C32(0xd48ef6c4), SPH_C32(0xb14d0500), SPH_C32(0x2f1c01b8), + SPH_C32(0xa261b1e9), SPH_C32(0x1e20602c) }, + { SPH_C32(0xfa9b0000), SPH_C32(0x3df15fc1), SPH_C32(0xeab03334), + SPH_C32(0x1f8c40ca), SPH_C32(0xd21d0600), SPH_C32(0x2f7e1385), + SPH_C32(0xe5908227), SPH_C32(0x0815196a) }, + { SPH_C32(0x89d70000), SPH_C32(0xa89ef817), SPH_C32(0x482d21a3), + SPH_C32(0x7169289e), SPH_C32(0x16f50700), SPH_C32(0x300e858b), + SPH_C32(0xc284481b), SPH_C32(0x8034155a) }, + { SPH_C32(0x5d230200), SPH_C32(0x22e3dbf2), SPH_C32(0x8a55cac6), + SPH_C32(0x819835bc), SPH_C32(0x3c3b0600), SPH_C32(0x3d357bbb), + SPH_C32(0x655254a8), SPH_C32(0x33e6b246) }, + { SPH_C32(0x2e6f0200), SPH_C32(0xb78c7c24), SPH_C32(0x28c8d851), + SPH_C32(0xef7d5de8), SPH_C32(0xf8d30700), SPH_C32(0x2245edb5), + SPH_C32(0x42469e94), SPH_C32(0xbbc7be76) }, + { SPH_C32(0x9b830400), SPH_C32(0x2227ff88), SPH_C32(0x05b7ad5a), + SPH_C32(0xadf2c730), SPH_C32(0x8f3e0400), SPH_C32(0x0d9dc877), + SPH_C32(0x6fc548e1), SPH_C32(0x898d2cd6) }, + { SPH_C32(0xe8cf0400), SPH_C32(0xb748585e), SPH_C32(0xa72abfcd), + SPH_C32(0xc317af64), SPH_C32(0x4bd60500), SPH_C32(0x12ed5e79), + SPH_C32(0x48d182dd), SPH_C32(0x01ac20e6) }, + { SPH_C32(0x3c3b0600), SPH_C32(0x3d357bbb), SPH_C32(0x655254a8), + SPH_C32(0x33e6b246), SPH_C32(0x61180400), SPH_C32(0x1fd6a049), + SPH_C32(0xef079e6e), SPH_C32(0xb27e87fa) }, + { SPH_C32(0x4f770600), SPH_C32(0xa85adc6d), SPH_C32(0xc7cf463f), + SPH_C32(0x5d03da12), SPH_C32(0xa5f00500), SPH_C32(0x00a63647), + SPH_C32(0xc8135452), SPH_C32(0x3a5f8bca) }, + { SPH_C32(0x75a50400), SPH_C32(0x306c97b6), SPH_C32(0x85757bd5), + SPH_C32(0x96016c1c), SPH_C32(0xc6a00600), SPH_C32(0x00c4247a), + SPH_C32(0x8fe2679c), SPH_C32(0x2c6af28c) }, + { SPH_C32(0x06e90400), SPH_C32(0xa5033060), SPH_C32(0x27e86942), + SPH_C32(0xf8e40448), SPH_C32(0x02480700), SPH_C32(0x1fb4b274), + SPH_C32(0xa8f6ada0), SPH_C32(0xa44bfebc) }, + { SPH_C32(0xd21d0600), SPH_C32(0x2f7e1385), SPH_C32(0xe5908227), + SPH_C32(0x0815196a), SPH_C32(0x28860600), SPH_C32(0x128f4c44), + SPH_C32(0x0f20b113), SPH_C32(0x179959a0) }, + { SPH_C32(0xa1510600), SPH_C32(0xba11b453), SPH_C32(0x470d90b0), + SPH_C32(0x66f0713e), SPH_C32(0xec6e0700), SPH_C32(0x0dffda4a), + SPH_C32(0x28347b2f), SPH_C32(0x9fb85590) } +}; + +static const sph_u32 T256_15[32][8] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000) }, + { SPH_C32(0x4dce0040), SPH_C32(0x3b5bec7e), SPH_C32(0x36656ba8), + SPH_C32(0x23633a05), SPH_C32(0x78ab0000), SPH_C32(0xa0cd5a34), + SPH_C32(0x5d5ca0f7), SPH_C32(0x727784cb) }, + { SPH_C32(0x78ab0000), SPH_C32(0xa0cd5a34), SPH_C32(0x5d5ca0f7), + SPH_C32(0x727784cb), SPH_C32(0x35650040), SPH_C32(0x9b96b64a), + SPH_C32(0x6b39cb5f), SPH_C32(0x5114bece) }, + { SPH_C32(0x35650040), SPH_C32(0x9b96b64a), SPH_C32(0x6b39cb5f), + SPH_C32(0x5114bece), SPH_C32(0x4dce0040), SPH_C32(0x3b5bec7e), + SPH_C32(0x36656ba8), SPH_C32(0x23633a05) }, + { SPH_C32(0x5bd20080), SPH_C32(0x450f18ec), SPH_C32(0xc2c46c55), + SPH_C32(0xf362b233), SPH_C32(0x39a60000), SPH_C32(0x4ab753eb), + SPH_C32(0xd14e094b), SPH_C32(0xb772b42b) }, + { SPH_C32(0x161c00c0), SPH_C32(0x7e54f492), SPH_C32(0xf4a107fd), + SPH_C32(0xd0018836), SPH_C32(0x410d0000), SPH_C32(0xea7a09df), + SPH_C32(0x8c12a9bc), SPH_C32(0xc50530e0) }, + { SPH_C32(0x23790080), SPH_C32(0xe5c242d8), SPH_C32(0x9f98cca2), + SPH_C32(0x811536f8), SPH_C32(0x0cc30040), SPH_C32(0xd121e5a1), + SPH_C32(0xba77c214), SPH_C32(0xe6660ae5) }, + { SPH_C32(0x6eb700c0), SPH_C32(0xde99aea6), SPH_C32(0xa9fda70a), + SPH_C32(0xa2760cfd), SPH_C32(0x74680040), SPH_C32(0x71ecbf95), + SPH_C32(0xe72b62e3), SPH_C32(0x94118e2e) }, + { SPH_C32(0x39a60000), SPH_C32(0x4ab753eb), SPH_C32(0xd14e094b), + SPH_C32(0xb772b42b), SPH_C32(0x62740080), SPH_C32(0x0fb84b07), + SPH_C32(0x138a651e), SPH_C32(0x44100618) }, + { SPH_C32(0x74680040), SPH_C32(0x71ecbf95), SPH_C32(0xe72b62e3), + SPH_C32(0x94118e2e), SPH_C32(0x1adf0080), SPH_C32(0xaf751133), + SPH_C32(0x4ed6c5e9), SPH_C32(0x366782d3) }, + { SPH_C32(0x410d0000), SPH_C32(0xea7a09df), SPH_C32(0x8c12a9bc), + SPH_C32(0xc50530e0), SPH_C32(0x571100c0), SPH_C32(0x942efd4d), + SPH_C32(0x78b3ae41), SPH_C32(0x1504b8d6) }, + { SPH_C32(0x0cc30040), SPH_C32(0xd121e5a1), SPH_C32(0xba77c214), + SPH_C32(0xe6660ae5), SPH_C32(0x2fba00c0), SPH_C32(0x34e3a779), + SPH_C32(0x25ef0eb6), SPH_C32(0x67733c1d) }, + { SPH_C32(0x62740080), SPH_C32(0x0fb84b07), SPH_C32(0x138a651e), + SPH_C32(0x44100618), SPH_C32(0x5bd20080), SPH_C32(0x450f18ec), + SPH_C32(0xc2c46c55), SPH_C32(0xf362b233) }, + { SPH_C32(0x2fba00c0), SPH_C32(0x34e3a779), SPH_C32(0x25ef0eb6), + SPH_C32(0x67733c1d), SPH_C32(0x23790080), SPH_C32(0xe5c242d8), + SPH_C32(0x9f98cca2), SPH_C32(0x811536f8) }, + { SPH_C32(0x1adf0080), SPH_C32(0xaf751133), SPH_C32(0x4ed6c5e9), + SPH_C32(0x366782d3), SPH_C32(0x6eb700c0), SPH_C32(0xde99aea6), + SPH_C32(0xa9fda70a), SPH_C32(0xa2760cfd) }, + { SPH_C32(0x571100c0), SPH_C32(0x942efd4d), SPH_C32(0x78b3ae41), + SPH_C32(0x1504b8d6), SPH_C32(0x161c00c0), SPH_C32(0x7e54f492), + SPH_C32(0xf4a107fd), SPH_C32(0xd0018836) }, + { SPH_C32(0xb7a40100), SPH_C32(0x8a1f31d8), SPH_C32(0x8589d8ab), + SPH_C32(0xe6c46464), SPH_C32(0x734c0000), SPH_C32(0x956fa7d6), + SPH_C32(0xa29d1297), SPH_C32(0x6ee56854) }, + { SPH_C32(0xfa6a0140), SPH_C32(0xb144dda6), SPH_C32(0xb3ecb303), + SPH_C32(0xc5a75e61), SPH_C32(0x0be70000), SPH_C32(0x35a2fde2), + SPH_C32(0xffc1b260), SPH_C32(0x1c92ec9f) }, + { SPH_C32(0xcf0f0100), SPH_C32(0x2ad26bec), SPH_C32(0xd8d5785c), + SPH_C32(0x94b3e0af), SPH_C32(0x46290040), SPH_C32(0x0ef9119c), + SPH_C32(0xc9a4d9c8), SPH_C32(0x3ff1d69a) }, + { SPH_C32(0x82c10140), SPH_C32(0x11898792), SPH_C32(0xeeb013f4), + SPH_C32(0xb7d0daaa), SPH_C32(0x3e820040), SPH_C32(0xae344ba8), + SPH_C32(0x94f8793f), SPH_C32(0x4d865251) }, + { SPH_C32(0xec760180), SPH_C32(0xcf102934), SPH_C32(0x474db4fe), + SPH_C32(0x15a6d657), SPH_C32(0x4aea0000), SPH_C32(0xdfd8f43d), + SPH_C32(0x73d31bdc), SPH_C32(0xd997dc7f) }, + { SPH_C32(0xa1b801c0), SPH_C32(0xf44bc54a), SPH_C32(0x7128df56), + SPH_C32(0x36c5ec52), SPH_C32(0x32410000), SPH_C32(0x7f15ae09), + SPH_C32(0x2e8fbb2b), SPH_C32(0xabe058b4) }, + { SPH_C32(0x94dd0180), SPH_C32(0x6fdd7300), SPH_C32(0x1a111409), + SPH_C32(0x67d1529c), SPH_C32(0x7f8f0040), SPH_C32(0x444e4277), + SPH_C32(0x18ead083), SPH_C32(0x888362b1) }, + { SPH_C32(0xd91301c0), SPH_C32(0x54869f7e), SPH_C32(0x2c747fa1), + SPH_C32(0x44b26899), SPH_C32(0x07240040), SPH_C32(0xe4831843), + SPH_C32(0x45b67074), SPH_C32(0xfaf4e67a) }, + { SPH_C32(0x8e020100), SPH_C32(0xc0a86233), SPH_C32(0x54c7d1e0), + SPH_C32(0x51b6d04f), SPH_C32(0x11380080), SPH_C32(0x9ad7ecd1), + SPH_C32(0xb1177789), SPH_C32(0x2af56e4c) }, + { SPH_C32(0xc3cc0140), SPH_C32(0xfbf38e4d), SPH_C32(0x62a2ba48), + SPH_C32(0x72d5ea4a), SPH_C32(0x69930080), SPH_C32(0x3a1ab6e5), + SPH_C32(0xec4bd77e), SPH_C32(0x5882ea87) }, + { SPH_C32(0xf6a90100), SPH_C32(0x60653807), SPH_C32(0x099b7117), + SPH_C32(0x23c15484), SPH_C32(0x245d00c0), SPH_C32(0x01415a9b), + SPH_C32(0xda2ebcd6), SPH_C32(0x7be1d082) }, + { SPH_C32(0xbb670140), SPH_C32(0x5b3ed479), SPH_C32(0x3ffe1abf), + SPH_C32(0x00a26e81), SPH_C32(0x5cf600c0), SPH_C32(0xa18c00af), + SPH_C32(0x87721c21), SPH_C32(0x09965449) }, + { SPH_C32(0xd5d00180), SPH_C32(0x85a77adf), SPH_C32(0x9603bdb5), + SPH_C32(0xa2d4627c), SPH_C32(0x289e0080), SPH_C32(0xd060bf3a), + SPH_C32(0x60597ec2), SPH_C32(0x9d87da67) }, + { SPH_C32(0x981e01c0), SPH_C32(0xbefc96a1), SPH_C32(0xa066d61d), + SPH_C32(0x81b75879), SPH_C32(0x50350080), SPH_C32(0x70ade50e), + SPH_C32(0x3d05de35), SPH_C32(0xeff05eac) }, + { SPH_C32(0xad7b0180), SPH_C32(0x256a20eb), SPH_C32(0xcb5f1d42), + SPH_C32(0xd0a3e6b7), SPH_C32(0x1dfb00c0), SPH_C32(0x4bf60970), + SPH_C32(0x0b60b59d), SPH_C32(0xcc9364a9) }, + { SPH_C32(0xe0b501c0), SPH_C32(0x1e31cc95), SPH_C32(0xfd3a76ea), + SPH_C32(0xf3c0dcb2), SPH_C32(0x655000c0), SPH_C32(0xeb3b5344), + SPH_C32(0x563c156a), SPH_C32(0xbee4e062) } +}; + +static const sph_u32 T256_20[32][8] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000) }, + { SPH_C32(0x171c0000), SPH_C32(0xb26e3344), SPH_C32(0x9e6a837e), + SPH_C32(0x58f8485f), SPH_C32(0xbfb20008), SPH_C32(0x92170a39), + SPH_C32(0x6019107f), SPH_C32(0xe051606e) }, + { SPH_C32(0x515c0010), SPH_C32(0x40f372fb), SPH_C32(0xfce72602), + SPH_C32(0x71575061), SPH_C32(0x2e390000), SPH_C32(0x64dd6689), + SPH_C32(0x3cd406fc), SPH_C32(0xb1f490bc) }, + { SPH_C32(0x46400010), SPH_C32(0xf29d41bf), SPH_C32(0x628da57c), + SPH_C32(0x29af183e), SPH_C32(0x918b0008), SPH_C32(0xf6ca6cb0), + SPH_C32(0x5ccd1683), SPH_C32(0x51a5f0d2) }, + { SPH_C32(0x2e390000), SPH_C32(0x64dd6689), SPH_C32(0x3cd406fc), + SPH_C32(0xb1f490bc), SPH_C32(0x7f650010), SPH_C32(0x242e1472), + SPH_C32(0xc03320fe), SPH_C32(0xc0a3c0dd) }, + { SPH_C32(0x39250000), SPH_C32(0xd6b355cd), SPH_C32(0xa2be8582), + SPH_C32(0xe90cd8e3), SPH_C32(0xc0d70018), SPH_C32(0xb6391e4b), + SPH_C32(0xa02a3081), SPH_C32(0x20f2a0b3) }, + { SPH_C32(0x7f650010), SPH_C32(0x242e1472), SPH_C32(0xc03320fe), + SPH_C32(0xc0a3c0dd), SPH_C32(0x515c0010), SPH_C32(0x40f372fb), + SPH_C32(0xfce72602), SPH_C32(0x71575061) }, + { SPH_C32(0x68790010), SPH_C32(0x96402736), SPH_C32(0x5e59a380), + SPH_C32(0x985b8882), SPH_C32(0xeeee0018), SPH_C32(0xd2e478c2), + SPH_C32(0x9cfe367d), SPH_C32(0x9106300f) }, + { SPH_C32(0xa2b80020), SPH_C32(0x81e7e5f6), SPH_C32(0xf9ce4c04), + SPH_C32(0xe2afa0c0), SPH_C32(0x5c720000), SPH_C32(0xc9bacd12), + SPH_C32(0x79a90df9), SPH_C32(0x63e92178) }, + { SPH_C32(0xb5a40020), SPH_C32(0x3389d6b2), SPH_C32(0x67a4cf7a), + SPH_C32(0xba57e89f), SPH_C32(0xe3c00008), SPH_C32(0x5badc72b), + SPH_C32(0x19b01d86), SPH_C32(0x83b84116) }, + { SPH_C32(0xf3e40030), SPH_C32(0xc114970d), SPH_C32(0x05296a06), + SPH_C32(0x93f8f0a1), SPH_C32(0x724b0000), SPH_C32(0xad67ab9b), + SPH_C32(0x457d0b05), SPH_C32(0xd21db1c4) }, + { SPH_C32(0xe4f80030), SPH_C32(0x737aa449), SPH_C32(0x9b43e978), + SPH_C32(0xcb00b8fe), SPH_C32(0xcdf90008), SPH_C32(0x3f70a1a2), + SPH_C32(0x25641b7a), SPH_C32(0x324cd1aa) }, + { SPH_C32(0x8c810020), SPH_C32(0xe53a837f), SPH_C32(0xc51a4af8), + SPH_C32(0x535b307c), SPH_C32(0x23170010), SPH_C32(0xed94d960), + SPH_C32(0xb99a2d07), SPH_C32(0xa34ae1a5) }, + { SPH_C32(0x9b9d0020), SPH_C32(0x5754b03b), SPH_C32(0x5b70c986), + SPH_C32(0x0ba37823), SPH_C32(0x9ca50018), SPH_C32(0x7f83d359), + SPH_C32(0xd9833d78), SPH_C32(0x431b81cb) }, + { SPH_C32(0xdddd0030), SPH_C32(0xa5c9f184), SPH_C32(0x39fd6cfa), + SPH_C32(0x220c601d), SPH_C32(0x0d2e0010), SPH_C32(0x8949bfe9), + SPH_C32(0x854e2bfb), SPH_C32(0x12be7119) }, + { SPH_C32(0xcac10030), SPH_C32(0x17a7c2c0), SPH_C32(0xa797ef84), + SPH_C32(0x7af42842), SPH_C32(0xb29c0018), SPH_C32(0x1b5eb5d0), + SPH_C32(0xe5573b84), SPH_C32(0xf2ef1177) }, + { SPH_C32(0x5c720000), SPH_C32(0xc9bacd12), SPH_C32(0x79a90df9), + SPH_C32(0x63e92178), SPH_C32(0xfeca0020), SPH_C32(0x485d28e4), + SPH_C32(0x806741fd), SPH_C32(0x814681b8) }, + { SPH_C32(0x4b6e0000), SPH_C32(0x7bd4fe56), SPH_C32(0xe7c38e87), + SPH_C32(0x3b116927), SPH_C32(0x41780028), SPH_C32(0xda4a22dd), + SPH_C32(0xe07e5182), SPH_C32(0x6117e1d6) }, + { SPH_C32(0x0d2e0010), SPH_C32(0x8949bfe9), SPH_C32(0x854e2bfb), + SPH_C32(0x12be7119), SPH_C32(0xd0f30020), SPH_C32(0x2c804e6d), + SPH_C32(0xbcb34701), SPH_C32(0x30b21104) }, + { SPH_C32(0x1a320010), SPH_C32(0x3b278cad), SPH_C32(0x1b24a885), + SPH_C32(0x4a463946), SPH_C32(0x6f410028), SPH_C32(0xbe974454), + SPH_C32(0xdcaa577e), SPH_C32(0xd0e3716a) }, + { SPH_C32(0x724b0000), SPH_C32(0xad67ab9b), SPH_C32(0x457d0b05), + SPH_C32(0xd21db1c4), SPH_C32(0x81af0030), SPH_C32(0x6c733c96), + SPH_C32(0x40546103), SPH_C32(0x41e54165) }, + { SPH_C32(0x65570000), SPH_C32(0x1f0998df), SPH_C32(0xdb17887b), + SPH_C32(0x8ae5f99b), SPH_C32(0x3e1d0038), SPH_C32(0xfe6436af), + SPH_C32(0x204d717c), SPH_C32(0xa1b4210b) }, + { SPH_C32(0x23170010), SPH_C32(0xed94d960), SPH_C32(0xb99a2d07), + SPH_C32(0xa34ae1a5), SPH_C32(0xaf960030), SPH_C32(0x08ae5a1f), + SPH_C32(0x7c8067ff), SPH_C32(0xf011d1d9) }, + { SPH_C32(0x340b0010), SPH_C32(0x5ffaea24), SPH_C32(0x27f0ae79), + SPH_C32(0xfbb2a9fa), SPH_C32(0x10240038), SPH_C32(0x9ab95026), + SPH_C32(0x1c997780), SPH_C32(0x1040b1b7) }, + { SPH_C32(0xfeca0020), SPH_C32(0x485d28e4), SPH_C32(0x806741fd), + SPH_C32(0x814681b8), SPH_C32(0xa2b80020), SPH_C32(0x81e7e5f6), + SPH_C32(0xf9ce4c04), SPH_C32(0xe2afa0c0) }, + { SPH_C32(0xe9d60020), SPH_C32(0xfa331ba0), SPH_C32(0x1e0dc283), + SPH_C32(0xd9bec9e7), SPH_C32(0x1d0a0028), SPH_C32(0x13f0efcf), + SPH_C32(0x99d75c7b), SPH_C32(0x02fec0ae) }, + { SPH_C32(0xaf960030), SPH_C32(0x08ae5a1f), SPH_C32(0x7c8067ff), + SPH_C32(0xf011d1d9), SPH_C32(0x8c810020), SPH_C32(0xe53a837f), + SPH_C32(0xc51a4af8), SPH_C32(0x535b307c) }, + { SPH_C32(0xb88a0030), SPH_C32(0xbac0695b), SPH_C32(0xe2eae481), + SPH_C32(0xa8e99986), SPH_C32(0x33330028), SPH_C32(0x772d8946), + SPH_C32(0xa5035a87), SPH_C32(0xb30a5012) }, + { SPH_C32(0xd0f30020), SPH_C32(0x2c804e6d), SPH_C32(0xbcb34701), + SPH_C32(0x30b21104), SPH_C32(0xdddd0030), SPH_C32(0xa5c9f184), + SPH_C32(0x39fd6cfa), SPH_C32(0x220c601d) }, + { SPH_C32(0xc7ef0020), SPH_C32(0x9eee7d29), SPH_C32(0x22d9c47f), + SPH_C32(0x684a595b), SPH_C32(0x626f0038), SPH_C32(0x37defbbd), + SPH_C32(0x59e47c85), SPH_C32(0xc25d0073) }, + { SPH_C32(0x81af0030), SPH_C32(0x6c733c96), SPH_C32(0x40546103), + SPH_C32(0x41e54165), SPH_C32(0xf3e40030), SPH_C32(0xc114970d), + SPH_C32(0x05296a06), SPH_C32(0x93f8f0a1) }, + { SPH_C32(0x96b30030), SPH_C32(0xde1d0fd2), SPH_C32(0xde3ee27d), + SPH_C32(0x191d093a), SPH_C32(0x4c560038), SPH_C32(0x53039d34), + SPH_C32(0x65307a79), SPH_C32(0x73a990cf) } +}; + +static const sph_u32 T256_25[32][8] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000) }, + { SPH_C32(0x88230002), SPH_C32(0x5fe7a7b3), SPH_C32(0x99e585aa), + SPH_C32(0x8d75f7f1), SPH_C32(0x51ac0000), SPH_C32(0x25e30f14), + SPH_C32(0x79e22a4c), SPH_C32(0x1298bd46) }, + { SPH_C32(0x51ac0000), SPH_C32(0x25e30f14), SPH_C32(0x79e22a4c), + SPH_C32(0x1298bd46), SPH_C32(0xd98f0002), SPH_C32(0x7a04a8a7), + SPH_C32(0xe007afe6), SPH_C32(0x9fed4ab7) }, + { SPH_C32(0xd98f0002), SPH_C32(0x7a04a8a7), SPH_C32(0xe007afe6), + SPH_C32(0x9fed4ab7), SPH_C32(0x88230002), SPH_C32(0x5fe7a7b3), + SPH_C32(0x99e585aa), SPH_C32(0x8d75f7f1) }, + { SPH_C32(0xd0080004), SPH_C32(0x8c768f77), SPH_C32(0x9dc5b050), + SPH_C32(0xaf4a29da), SPH_C32(0x6ba90000), SPH_C32(0x40ebf9aa), + SPH_C32(0x98321c3d), SPH_C32(0x76acc733) }, + { SPH_C32(0x582b0006), SPH_C32(0xd39128c4), SPH_C32(0x042035fa), + SPH_C32(0x223fde2b), SPH_C32(0x3a050000), SPH_C32(0x6508f6be), + SPH_C32(0xe1d03671), SPH_C32(0x64347a75) }, + { SPH_C32(0x81a40004), SPH_C32(0xa9958063), SPH_C32(0xe4279a1c), + SPH_C32(0xbdd2949c), SPH_C32(0xb2260002), SPH_C32(0x3aef510d), + SPH_C32(0x7835b3db), SPH_C32(0xe9418d84) }, + { SPH_C32(0x09870006), SPH_C32(0xf67227d0), SPH_C32(0x7dc21fb6), + SPH_C32(0x30a7636d), SPH_C32(0xe38a0002), SPH_C32(0x1f0c5e19), + SPH_C32(0x01d79997), SPH_C32(0xfbd930c2) }, + { SPH_C32(0x6ba90000), SPH_C32(0x40ebf9aa), SPH_C32(0x98321c3d), + SPH_C32(0x76acc733), SPH_C32(0xbba10004), SPH_C32(0xcc9d76dd), + SPH_C32(0x05f7ac6d), SPH_C32(0xd9e6eee9) }, + { SPH_C32(0xe38a0002), SPH_C32(0x1f0c5e19), SPH_C32(0x01d79997), + SPH_C32(0xfbd930c2), SPH_C32(0xea0d0004), SPH_C32(0xe97e79c9), + SPH_C32(0x7c158621), SPH_C32(0xcb7e53af) }, + { SPH_C32(0x3a050000), SPH_C32(0x6508f6be), SPH_C32(0xe1d03671), + SPH_C32(0x64347a75), SPH_C32(0x622e0006), SPH_C32(0xb699de7a), + SPH_C32(0xe5f0038b), SPH_C32(0x460ba45e) }, + { SPH_C32(0xb2260002), SPH_C32(0x3aef510d), SPH_C32(0x7835b3db), + SPH_C32(0xe9418d84), SPH_C32(0x33820006), SPH_C32(0x937ad16e), + SPH_C32(0x9c1229c7), SPH_C32(0x54931918) }, + { SPH_C32(0xbba10004), SPH_C32(0xcc9d76dd), SPH_C32(0x05f7ac6d), + SPH_C32(0xd9e6eee9), SPH_C32(0xd0080004), SPH_C32(0x8c768f77), + SPH_C32(0x9dc5b050), SPH_C32(0xaf4a29da) }, + { SPH_C32(0x33820006), SPH_C32(0x937ad16e), SPH_C32(0x9c1229c7), + SPH_C32(0x54931918), SPH_C32(0x81a40004), SPH_C32(0xa9958063), + SPH_C32(0xe4279a1c), SPH_C32(0xbdd2949c) }, + { SPH_C32(0xea0d0004), SPH_C32(0xe97e79c9), SPH_C32(0x7c158621), + SPH_C32(0xcb7e53af), SPH_C32(0x09870006), SPH_C32(0xf67227d0), + SPH_C32(0x7dc21fb6), SPH_C32(0x30a7636d) }, + { SPH_C32(0x622e0006), SPH_C32(0xb699de7a), SPH_C32(0xe5f0038b), + SPH_C32(0x460ba45e), SPH_C32(0x582b0006), SPH_C32(0xd39128c4), + SPH_C32(0x042035fa), SPH_C32(0x223fde2b) }, + { SPH_C32(0xa8ae0008), SPH_C32(0x2079397d), SPH_C32(0xfe739301), + SPH_C32(0xb8a92831), SPH_C32(0x171c0000), SPH_C32(0xb26e3344), + SPH_C32(0x9e6a837e), SPH_C32(0x58f8485f) }, + { SPH_C32(0x208d000a), SPH_C32(0x7f9e9ece), SPH_C32(0x679616ab), + SPH_C32(0x35dcdfc0), SPH_C32(0x46b00000), SPH_C32(0x978d3c50), + SPH_C32(0xe788a932), SPH_C32(0x4a60f519) }, + { SPH_C32(0xf9020008), SPH_C32(0x059a3669), SPH_C32(0x8791b94d), + SPH_C32(0xaa319577), SPH_C32(0xce930002), SPH_C32(0xc86a9be3), + SPH_C32(0x7e6d2c98), SPH_C32(0xc71502e8) }, + { SPH_C32(0x7121000a), SPH_C32(0x5a7d91da), SPH_C32(0x1e743ce7), + SPH_C32(0x27446286), SPH_C32(0x9f3f0002), SPH_C32(0xed8994f7), + SPH_C32(0x078f06d4), SPH_C32(0xd58dbfae) }, + { SPH_C32(0x78a6000c), SPH_C32(0xac0fb60a), SPH_C32(0x63b62351), + SPH_C32(0x17e301eb), SPH_C32(0x7cb50000), SPH_C32(0xf285caee), + SPH_C32(0x06589f43), SPH_C32(0x2e548f6c) }, + { SPH_C32(0xf085000e), SPH_C32(0xf3e811b9), SPH_C32(0xfa53a6fb), + SPH_C32(0x9a96f61a), SPH_C32(0x2d190000), SPH_C32(0xd766c5fa), + SPH_C32(0x7fbab50f), SPH_C32(0x3ccc322a) }, + { SPH_C32(0x290a000c), SPH_C32(0x89ecb91e), SPH_C32(0x1a54091d), + SPH_C32(0x057bbcad), SPH_C32(0xa53a0002), SPH_C32(0x88816249), + SPH_C32(0xe65f30a5), SPH_C32(0xb1b9c5db) }, + { SPH_C32(0xa129000e), SPH_C32(0xd60b1ead), SPH_C32(0x83b18cb7), + SPH_C32(0x880e4b5c), SPH_C32(0xf4960002), SPH_C32(0xad626d5d), + SPH_C32(0x9fbd1ae9), SPH_C32(0xa321789d) }, + { SPH_C32(0xc3070008), SPH_C32(0x6092c0d7), SPH_C32(0x66418f3c), + SPH_C32(0xce05ef02), SPH_C32(0xacbd0004), SPH_C32(0x7ef34599), + SPH_C32(0x9b9d2f13), SPH_C32(0x811ea6b6) }, + { SPH_C32(0x4b24000a), SPH_C32(0x3f756764), SPH_C32(0xffa40a96), + SPH_C32(0x437018f3), SPH_C32(0xfd110004), SPH_C32(0x5b104a8d), + SPH_C32(0xe27f055f), SPH_C32(0x93861bf0) }, + { SPH_C32(0x92ab0008), SPH_C32(0x4571cfc3), SPH_C32(0x1fa3a570), + SPH_C32(0xdc9d5244), SPH_C32(0x75320006), SPH_C32(0x04f7ed3e), + SPH_C32(0x7b9a80f5), SPH_C32(0x1ef3ec01) }, + { SPH_C32(0x1a88000a), SPH_C32(0x1a966870), SPH_C32(0x864620da), + SPH_C32(0x51e8a5b5), SPH_C32(0x249e0006), SPH_C32(0x2114e22a), + SPH_C32(0x0278aab9), SPH_C32(0x0c6b5147) }, + { SPH_C32(0x130f000c), SPH_C32(0xece44fa0), SPH_C32(0xfb843f6c), + SPH_C32(0x614fc6d8), SPH_C32(0xc7140004), SPH_C32(0x3e18bc33), + SPH_C32(0x03af332e), SPH_C32(0xf7b26185) }, + { SPH_C32(0x9b2c000e), SPH_C32(0xb303e813), SPH_C32(0x6261bac6), + SPH_C32(0xec3a3129), SPH_C32(0x96b80004), SPH_C32(0x1bfbb327), + SPH_C32(0x7a4d1962), SPH_C32(0xe52adcc3) }, + { SPH_C32(0x42a3000c), SPH_C32(0xc90740b4), SPH_C32(0x82661520), + SPH_C32(0x73d77b9e), SPH_C32(0x1e9b0006), SPH_C32(0x441c1494), + SPH_C32(0xe3a89cc8), SPH_C32(0x685f2b32) }, + { SPH_C32(0xca80000e), SPH_C32(0x96e0e707), SPH_C32(0x1b83908a), + SPH_C32(0xfea28c6f), SPH_C32(0x4f370006), SPH_C32(0x61ff1b80), + SPH_C32(0x9a4ab684), SPH_C32(0x7ac79674) } +}; + +static const sph_u32 T256_30[4][8] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000) }, + { SPH_C32(0xc04e0001), SPH_C32(0x33b9c010), SPH_C32(0xae0ebb05), + SPH_C32(0xb5a4c63b), SPH_C32(0xc8f10000), SPH_C32(0x0b2de782), + SPH_C32(0x6bf648a4), SPH_C32(0x539cbdbf) }, + { SPH_C32(0xc8f10000), SPH_C32(0x0b2de782), SPH_C32(0x6bf648a4), + SPH_C32(0x539cbdbf), SPH_C32(0x08bf0001), SPH_C32(0x38942792), + SPH_C32(0xc5f8f3a1), SPH_C32(0xe6387b84) }, + { SPH_C32(0x08bf0001), SPH_C32(0x38942792), SPH_C32(0xc5f8f3a1), + SPH_C32(0xe6387b84), SPH_C32(0xc04e0001), SPH_C32(0x33b9c010), + SPH_C32(0xae0ebb05), SPH_C32(0xb5a4c63b) } +}; + +#define INPUT_SMALL do { \ + unsigned acc = buf[0]; \ + const sph_u32 *rp; \ + rp = &T256_0[acc >> 3][0]; \ + m0 = rp[0]; \ + m1 = rp[1]; \ + m2 = rp[2]; \ + m3 = rp[3]; \ + m4 = rp[4]; \ + m5 = rp[5]; \ + m6 = rp[6]; \ + m7 = rp[7]; \ + acc = (acc << 8) | buf[1]; \ + rp = &T256_5[(acc >> 6) & 0x1f][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + rp = &T256_10[(acc >> 1) & 0x1f][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + acc = (acc << 8) | buf[2]; \ + rp = &T256_15[(acc >> 4) & 0x1f][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + acc = (acc << 8) | buf[3]; \ + rp = &T256_20[(acc >> 7) & 0x1f][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + rp = &T256_25[(acc >> 2) & 0x1f][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + rp = &T256_30[acc & 0x03][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + } while (0) + +#endif + +#if SPH_HAMSI_EXPAND_SMALL == 6 + +static const sph_u32 T256_0[64][8] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000) }, + { SPH_C32(0xe92a2000), SPH_C32(0xb4578cfc), SPH_C32(0x11fa3a57), + SPH_C32(0x3dc90524), SPH_C32(0x97530000), SPH_C32(0x204f6ed3), + SPH_C32(0x77b9e80f), SPH_C32(0xa1ec5ec1) }, + { SPH_C32(0x97530000), SPH_C32(0x204f6ed3), SPH_C32(0x77b9e80f), + SPH_C32(0xa1ec5ec1), SPH_C32(0x7e792000), SPH_C32(0x9418e22f), + SPH_C32(0x6643d258), SPH_C32(0x9c255be5) }, + { SPH_C32(0x7e792000), SPH_C32(0x9418e22f), SPH_C32(0x6643d258), + SPH_C32(0x9c255be5), SPH_C32(0xe92a2000), SPH_C32(0xb4578cfc), + SPH_C32(0x11fa3a57), SPH_C32(0x3dc90524) }, + { SPH_C32(0x121b4000), SPH_C32(0x5b17d9e8), SPH_C32(0x8dfacfab), + SPH_C32(0xce36cc72), SPH_C32(0xe6570000), SPH_C32(0x4bb33a25), + SPH_C32(0x848598ba), SPH_C32(0x1041003e) }, + { SPH_C32(0xfb316000), SPH_C32(0xef405514), SPH_C32(0x9c00f5fc), + SPH_C32(0xf3ffc956), SPH_C32(0x71040000), SPH_C32(0x6bfc54f6), + SPH_C32(0xf33c70b5), SPH_C32(0xb1ad5eff) }, + { SPH_C32(0x85484000), SPH_C32(0x7b58b73b), SPH_C32(0xfa4327a4), + SPH_C32(0x6fda92b3), SPH_C32(0x982e2000), SPH_C32(0xdfabd80a), + SPH_C32(0xe2c64ae2), SPH_C32(0x8c645bdb) }, + { SPH_C32(0x6c626000), SPH_C32(0xcf0f3bc7), SPH_C32(0xebb91df3), + SPH_C32(0x52139797), SPH_C32(0x0f7d2000), SPH_C32(0xffe4b6d9), + SPH_C32(0x957fa2ed), SPH_C32(0x2d88051a) }, + { SPH_C32(0xe6570000), SPH_C32(0x4bb33a25), SPH_C32(0x848598ba), + SPH_C32(0x1041003e), SPH_C32(0xf44c4000), SPH_C32(0x10a4e3cd), + SPH_C32(0x097f5711), SPH_C32(0xde77cc4c) }, + { SPH_C32(0x0f7d2000), SPH_C32(0xffe4b6d9), SPH_C32(0x957fa2ed), + SPH_C32(0x2d88051a), SPH_C32(0x631f4000), SPH_C32(0x30eb8d1e), + SPH_C32(0x7ec6bf1e), SPH_C32(0x7f9b928d) }, + { SPH_C32(0x71040000), SPH_C32(0x6bfc54f6), SPH_C32(0xf33c70b5), + SPH_C32(0xb1ad5eff), SPH_C32(0x8a356000), SPH_C32(0x84bc01e2), + SPH_C32(0x6f3c8549), SPH_C32(0x425297a9) }, + { SPH_C32(0x982e2000), SPH_C32(0xdfabd80a), SPH_C32(0xe2c64ae2), + SPH_C32(0x8c645bdb), SPH_C32(0x1d666000), SPH_C32(0xa4f36f31), + SPH_C32(0x18856d46), SPH_C32(0xe3bec968) }, + { SPH_C32(0xf44c4000), SPH_C32(0x10a4e3cd), SPH_C32(0x097f5711), + SPH_C32(0xde77cc4c), SPH_C32(0x121b4000), SPH_C32(0x5b17d9e8), + SPH_C32(0x8dfacfab), SPH_C32(0xce36cc72) }, + { SPH_C32(0x1d666000), SPH_C32(0xa4f36f31), SPH_C32(0x18856d46), + SPH_C32(0xe3bec968), SPH_C32(0x85484000), SPH_C32(0x7b58b73b), + SPH_C32(0xfa4327a4), SPH_C32(0x6fda92b3) }, + { SPH_C32(0x631f4000), SPH_C32(0x30eb8d1e), SPH_C32(0x7ec6bf1e), + SPH_C32(0x7f9b928d), SPH_C32(0x6c626000), SPH_C32(0xcf0f3bc7), + SPH_C32(0xebb91df3), SPH_C32(0x52139797) }, + { SPH_C32(0x8a356000), SPH_C32(0x84bc01e2), SPH_C32(0x6f3c8549), + SPH_C32(0x425297a9), SPH_C32(0xfb316000), SPH_C32(0xef405514), + SPH_C32(0x9c00f5fc), SPH_C32(0xf3ffc956) }, + { SPH_C32(0xe4788000), SPH_C32(0x859673c1), SPH_C32(0xb5fb2452), + SPH_C32(0x29cc5edf), SPH_C32(0x045f0000), SPH_C32(0x9c4a93c9), + SPH_C32(0x62fc79d0), SPH_C32(0x731ebdc2) }, + { SPH_C32(0x0d52a000), SPH_C32(0x31c1ff3d), SPH_C32(0xa4011e05), + SPH_C32(0x14055bfb), SPH_C32(0x930c0000), SPH_C32(0xbc05fd1a), + SPH_C32(0x154591df), SPH_C32(0xd2f2e303) }, + { SPH_C32(0x732b8000), SPH_C32(0xa5d91d12), SPH_C32(0xc242cc5d), + SPH_C32(0x8820001e), SPH_C32(0x7a262000), SPH_C32(0x085271e6), + SPH_C32(0x04bfab88), SPH_C32(0xef3be627) }, + { SPH_C32(0x9a01a000), SPH_C32(0x118e91ee), SPH_C32(0xd3b8f60a), + SPH_C32(0xb5e9053a), SPH_C32(0xed752000), SPH_C32(0x281d1f35), + SPH_C32(0x73064387), SPH_C32(0x4ed7b8e6) }, + { SPH_C32(0xf663c000), SPH_C32(0xde81aa29), SPH_C32(0x3801ebf9), + SPH_C32(0xe7fa92ad), SPH_C32(0xe2080000), SPH_C32(0xd7f9a9ec), + SPH_C32(0xe679e16a), SPH_C32(0x635fbdfc) }, + { SPH_C32(0x1f49e000), SPH_C32(0x6ad626d5), SPH_C32(0x29fbd1ae), + SPH_C32(0xda339789), SPH_C32(0x755b0000), SPH_C32(0xf7b6c73f), + SPH_C32(0x91c00965), SPH_C32(0xc2b3e33d) }, + { SPH_C32(0x6130c000), SPH_C32(0xfecec4fa), SPH_C32(0x4fb803f6), + SPH_C32(0x4616cc6c), SPH_C32(0x9c712000), SPH_C32(0x43e14bc3), + SPH_C32(0x803a3332), SPH_C32(0xff7ae619) }, + { SPH_C32(0x881ae000), SPH_C32(0x4a994806), SPH_C32(0x5e4239a1), + SPH_C32(0x7bdfc948), SPH_C32(0x0b222000), SPH_C32(0x63ae2510), + SPH_C32(0xf783db3d), SPH_C32(0x5e96b8d8) }, + { SPH_C32(0x022f8000), SPH_C32(0xce2549e4), SPH_C32(0x317ebce8), + SPH_C32(0x398d5ee1), SPH_C32(0xf0134000), SPH_C32(0x8cee7004), + SPH_C32(0x6b832ec1), SPH_C32(0xad69718e) }, + { SPH_C32(0xeb05a000), SPH_C32(0x7a72c518), SPH_C32(0x208486bf), + SPH_C32(0x04445bc5), SPH_C32(0x67404000), SPH_C32(0xaca11ed7), + SPH_C32(0x1c3ac6ce), SPH_C32(0x0c852f4f) }, + { SPH_C32(0x957c8000), SPH_C32(0xee6a2737), SPH_C32(0x46c754e7), + SPH_C32(0x98610020), SPH_C32(0x8e6a6000), SPH_C32(0x18f6922b), + SPH_C32(0x0dc0fc99), SPH_C32(0x314c2a6b) }, + { SPH_C32(0x7c56a000), SPH_C32(0x5a3dabcb), SPH_C32(0x573d6eb0), + SPH_C32(0xa5a80504), SPH_C32(0x19396000), SPH_C32(0x38b9fcf8), + SPH_C32(0x7a791496), SPH_C32(0x90a074aa) }, + { SPH_C32(0x1034c000), SPH_C32(0x9532900c), SPH_C32(0xbc847343), + SPH_C32(0xf7bb9293), SPH_C32(0x16444000), SPH_C32(0xc75d4a21), + SPH_C32(0xef06b67b), SPH_C32(0xbd2871b0) }, + { SPH_C32(0xf91ee000), SPH_C32(0x21651cf0), SPH_C32(0xad7e4914), + SPH_C32(0xca7297b7), SPH_C32(0x81174000), SPH_C32(0xe71224f2), + SPH_C32(0x98bf5e74), SPH_C32(0x1cc42f71) }, + { SPH_C32(0x8767c000), SPH_C32(0xb57dfedf), SPH_C32(0xcb3d9b4c), + SPH_C32(0x5657cc52), SPH_C32(0x683d6000), SPH_C32(0x5345a80e), + SPH_C32(0x89456423), SPH_C32(0x210d2a55) }, + { SPH_C32(0x6e4de000), SPH_C32(0x012a7223), SPH_C32(0xdac7a11b), + SPH_C32(0x6b9ec976), SPH_C32(0xff6e6000), SPH_C32(0x730ac6dd), + SPH_C32(0xfefc8c2c), SPH_C32(0x80e17494) }, + { SPH_C32(0x045f0000), SPH_C32(0x9c4a93c9), SPH_C32(0x62fc79d0), + SPH_C32(0x731ebdc2), SPH_C32(0xe0278000), SPH_C32(0x19dce008), + SPH_C32(0xd7075d82), SPH_C32(0x5ad2e31d) }, + { SPH_C32(0xed752000), SPH_C32(0x281d1f35), SPH_C32(0x73064387), + SPH_C32(0x4ed7b8e6), SPH_C32(0x77748000), SPH_C32(0x39938edb), + SPH_C32(0xa0beb58d), SPH_C32(0xfb3ebddc) }, + { SPH_C32(0x930c0000), SPH_C32(0xbc05fd1a), SPH_C32(0x154591df), + SPH_C32(0xd2f2e303), SPH_C32(0x9e5ea000), SPH_C32(0x8dc40227), + SPH_C32(0xb1448fda), SPH_C32(0xc6f7b8f8) }, + { SPH_C32(0x7a262000), SPH_C32(0x085271e6), SPH_C32(0x04bfab88), + SPH_C32(0xef3be627), SPH_C32(0x090da000), SPH_C32(0xad8b6cf4), + SPH_C32(0xc6fd67d5), SPH_C32(0x671be639) }, + { SPH_C32(0x16444000), SPH_C32(0xc75d4a21), SPH_C32(0xef06b67b), + SPH_C32(0xbd2871b0), SPH_C32(0x06708000), SPH_C32(0x526fda2d), + SPH_C32(0x5382c538), SPH_C32(0x4a93e323) }, + { SPH_C32(0xff6e6000), SPH_C32(0x730ac6dd), SPH_C32(0xfefc8c2c), + SPH_C32(0x80e17494), SPH_C32(0x91238000), SPH_C32(0x7220b4fe), + SPH_C32(0x243b2d37), SPH_C32(0xeb7fbde2) }, + { SPH_C32(0x81174000), SPH_C32(0xe71224f2), SPH_C32(0x98bf5e74), + SPH_C32(0x1cc42f71), SPH_C32(0x7809a000), SPH_C32(0xc6773802), + SPH_C32(0x35c11760), SPH_C32(0xd6b6b8c6) }, + { SPH_C32(0x683d6000), SPH_C32(0x5345a80e), SPH_C32(0x89456423), + SPH_C32(0x210d2a55), SPH_C32(0xef5aa000), SPH_C32(0xe63856d1), + SPH_C32(0x4278ff6f), SPH_C32(0x775ae607) }, + { SPH_C32(0xe2080000), SPH_C32(0xd7f9a9ec), SPH_C32(0xe679e16a), + SPH_C32(0x635fbdfc), SPH_C32(0x146bc000), SPH_C32(0x097803c5), + SPH_C32(0xde780a93), SPH_C32(0x84a52f51) }, + { SPH_C32(0x0b222000), SPH_C32(0x63ae2510), SPH_C32(0xf783db3d), + SPH_C32(0x5e96b8d8), SPH_C32(0x8338c000), SPH_C32(0x29376d16), + SPH_C32(0xa9c1e29c), SPH_C32(0x25497190) }, + { SPH_C32(0x755b0000), SPH_C32(0xf7b6c73f), SPH_C32(0x91c00965), + SPH_C32(0xc2b3e33d), SPH_C32(0x6a12e000), SPH_C32(0x9d60e1ea), + SPH_C32(0xb83bd8cb), SPH_C32(0x188074b4) }, + { SPH_C32(0x9c712000), SPH_C32(0x43e14bc3), SPH_C32(0x803a3332), + SPH_C32(0xff7ae619), SPH_C32(0xfd41e000), SPH_C32(0xbd2f8f39), + SPH_C32(0xcf8230c4), SPH_C32(0xb96c2a75) }, + { SPH_C32(0xf0134000), SPH_C32(0x8cee7004), SPH_C32(0x6b832ec1), + SPH_C32(0xad69718e), SPH_C32(0xf23cc000), SPH_C32(0x42cb39e0), + SPH_C32(0x5afd9229), SPH_C32(0x94e42f6f) }, + { SPH_C32(0x19396000), SPH_C32(0x38b9fcf8), SPH_C32(0x7a791496), + SPH_C32(0x90a074aa), SPH_C32(0x656fc000), SPH_C32(0x62845733), + SPH_C32(0x2d447a26), SPH_C32(0x350871ae) }, + { SPH_C32(0x67404000), SPH_C32(0xaca11ed7), SPH_C32(0x1c3ac6ce), + SPH_C32(0x0c852f4f), SPH_C32(0x8c45e000), SPH_C32(0xd6d3dbcf), + SPH_C32(0x3cbe4071), SPH_C32(0x08c1748a) }, + { SPH_C32(0x8e6a6000), SPH_C32(0x18f6922b), SPH_C32(0x0dc0fc99), + SPH_C32(0x314c2a6b), SPH_C32(0x1b16e000), SPH_C32(0xf69cb51c), + SPH_C32(0x4b07a87e), SPH_C32(0xa92d2a4b) }, + { SPH_C32(0xe0278000), SPH_C32(0x19dce008), SPH_C32(0xd7075d82), + SPH_C32(0x5ad2e31d), SPH_C32(0xe4788000), SPH_C32(0x859673c1), + SPH_C32(0xb5fb2452), SPH_C32(0x29cc5edf) }, + { SPH_C32(0x090da000), SPH_C32(0xad8b6cf4), SPH_C32(0xc6fd67d5), + SPH_C32(0x671be639), SPH_C32(0x732b8000), SPH_C32(0xa5d91d12), + SPH_C32(0xc242cc5d), SPH_C32(0x8820001e) }, + { SPH_C32(0x77748000), SPH_C32(0x39938edb), SPH_C32(0xa0beb58d), + SPH_C32(0xfb3ebddc), SPH_C32(0x9a01a000), SPH_C32(0x118e91ee), + SPH_C32(0xd3b8f60a), SPH_C32(0xb5e9053a) }, + { SPH_C32(0x9e5ea000), SPH_C32(0x8dc40227), SPH_C32(0xb1448fda), + SPH_C32(0xc6f7b8f8), SPH_C32(0x0d52a000), SPH_C32(0x31c1ff3d), + SPH_C32(0xa4011e05), SPH_C32(0x14055bfb) }, + { SPH_C32(0xf23cc000), SPH_C32(0x42cb39e0), SPH_C32(0x5afd9229), + SPH_C32(0x94e42f6f), SPH_C32(0x022f8000), SPH_C32(0xce2549e4), + SPH_C32(0x317ebce8), SPH_C32(0x398d5ee1) }, + { SPH_C32(0x1b16e000), SPH_C32(0xf69cb51c), SPH_C32(0x4b07a87e), + SPH_C32(0xa92d2a4b), SPH_C32(0x957c8000), SPH_C32(0xee6a2737), + SPH_C32(0x46c754e7), SPH_C32(0x98610020) }, + { SPH_C32(0x656fc000), SPH_C32(0x62845733), SPH_C32(0x2d447a26), + SPH_C32(0x350871ae), SPH_C32(0x7c56a000), SPH_C32(0x5a3dabcb), + SPH_C32(0x573d6eb0), SPH_C32(0xa5a80504) }, + { SPH_C32(0x8c45e000), SPH_C32(0xd6d3dbcf), SPH_C32(0x3cbe4071), + SPH_C32(0x08c1748a), SPH_C32(0xeb05a000), SPH_C32(0x7a72c518), + SPH_C32(0x208486bf), SPH_C32(0x04445bc5) }, + { SPH_C32(0x06708000), SPH_C32(0x526fda2d), SPH_C32(0x5382c538), + SPH_C32(0x4a93e323), SPH_C32(0x1034c000), SPH_C32(0x9532900c), + SPH_C32(0xbc847343), SPH_C32(0xf7bb9293) }, + { SPH_C32(0xef5aa000), SPH_C32(0xe63856d1), SPH_C32(0x4278ff6f), + SPH_C32(0x775ae607), SPH_C32(0x8767c000), SPH_C32(0xb57dfedf), + SPH_C32(0xcb3d9b4c), SPH_C32(0x5657cc52) }, + { SPH_C32(0x91238000), SPH_C32(0x7220b4fe), SPH_C32(0x243b2d37), + SPH_C32(0xeb7fbde2), SPH_C32(0x6e4de000), SPH_C32(0x012a7223), + SPH_C32(0xdac7a11b), SPH_C32(0x6b9ec976) }, + { SPH_C32(0x7809a000), SPH_C32(0xc6773802), SPH_C32(0x35c11760), + SPH_C32(0xd6b6b8c6), SPH_C32(0xf91ee000), SPH_C32(0x21651cf0), + SPH_C32(0xad7e4914), SPH_C32(0xca7297b7) }, + { SPH_C32(0x146bc000), SPH_C32(0x097803c5), SPH_C32(0xde780a93), + SPH_C32(0x84a52f51), SPH_C32(0xf663c000), SPH_C32(0xde81aa29), + SPH_C32(0x3801ebf9), SPH_C32(0xe7fa92ad) }, + { SPH_C32(0xfd41e000), SPH_C32(0xbd2f8f39), SPH_C32(0xcf8230c4), + SPH_C32(0xb96c2a75), SPH_C32(0x6130c000), SPH_C32(0xfecec4fa), + SPH_C32(0x4fb803f6), SPH_C32(0x4616cc6c) }, + { SPH_C32(0x8338c000), SPH_C32(0x29376d16), SPH_C32(0xa9c1e29c), + SPH_C32(0x25497190), SPH_C32(0x881ae000), SPH_C32(0x4a994806), + SPH_C32(0x5e4239a1), SPH_C32(0x7bdfc948) }, + { SPH_C32(0x6a12e000), SPH_C32(0x9d60e1ea), SPH_C32(0xb83bd8cb), + SPH_C32(0x188074b4), SPH_C32(0x1f49e000), SPH_C32(0x6ad626d5), + SPH_C32(0x29fbd1ae), SPH_C32(0xda339789) } +}; + +static const sph_u32 T256_6[64][8] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000) }, + { SPH_C32(0x8f3e0400), SPH_C32(0x0d9dc877), SPH_C32(0x6fc548e1), + SPH_C32(0x898d2cd6), SPH_C32(0x14bd0000), SPH_C32(0x2fba37ff), + SPH_C32(0x6a72e5bb), SPH_C32(0x247febe6) }, + { SPH_C32(0x14bd0000), SPH_C32(0x2fba37ff), SPH_C32(0x6a72e5bb), + SPH_C32(0x247febe6), SPH_C32(0x9b830400), SPH_C32(0x2227ff88), + SPH_C32(0x05b7ad5a), SPH_C32(0xadf2c730) }, + { SPH_C32(0x9b830400), SPH_C32(0x2227ff88), SPH_C32(0x05b7ad5a), + SPH_C32(0xadf2c730), SPH_C32(0x8f3e0400), SPH_C32(0x0d9dc877), + SPH_C32(0x6fc548e1), SPH_C32(0x898d2cd6) }, + { SPH_C32(0xde320800), SPH_C32(0x288350fe), SPH_C32(0x71852ac7), + SPH_C32(0xa6bf9f96), SPH_C32(0xe18b0000), SPH_C32(0x5459887d), + SPH_C32(0xbf1283d3), SPH_C32(0x1b666a73) }, + { SPH_C32(0x510c0c00), SPH_C32(0x251e9889), SPH_C32(0x1e406226), + SPH_C32(0x2f32b340), SPH_C32(0xf5360000), SPH_C32(0x7be3bf82), + SPH_C32(0xd5606668), SPH_C32(0x3f198195) }, + { SPH_C32(0xca8f0800), SPH_C32(0x07396701), SPH_C32(0x1bf7cf7c), + SPH_C32(0x82c07470), SPH_C32(0x7a080400), SPH_C32(0x767e77f5), + SPH_C32(0xbaa52e89), SPH_C32(0xb694ad43) }, + { SPH_C32(0x45b10c00), SPH_C32(0x0aa4af76), SPH_C32(0x7432879d), + SPH_C32(0x0b4d58a6), SPH_C32(0x6eb50400), SPH_C32(0x59c4400a), + SPH_C32(0xd0d7cb32), SPH_C32(0x92eb46a5) }, + { SPH_C32(0xe18b0000), SPH_C32(0x5459887d), SPH_C32(0xbf1283d3), + SPH_C32(0x1b666a73), SPH_C32(0x3fb90800), SPH_C32(0x7cdad883), + SPH_C32(0xce97a914), SPH_C32(0xbdd9f5e5) }, + { SPH_C32(0x6eb50400), SPH_C32(0x59c4400a), SPH_C32(0xd0d7cb32), + SPH_C32(0x92eb46a5), SPH_C32(0x2b040800), SPH_C32(0x5360ef7c), + SPH_C32(0xa4e54caf), SPH_C32(0x99a61e03) }, + { SPH_C32(0xf5360000), SPH_C32(0x7be3bf82), SPH_C32(0xd5606668), + SPH_C32(0x3f198195), SPH_C32(0xa43a0c00), SPH_C32(0x5efd270b), + SPH_C32(0xcb20044e), SPH_C32(0x102b32d5) }, + { SPH_C32(0x7a080400), SPH_C32(0x767e77f5), SPH_C32(0xbaa52e89), + SPH_C32(0xb694ad43), SPH_C32(0xb0870c00), SPH_C32(0x714710f4), + SPH_C32(0xa152e1f5), SPH_C32(0x3454d933) }, + { SPH_C32(0x3fb90800), SPH_C32(0x7cdad883), SPH_C32(0xce97a914), + SPH_C32(0xbdd9f5e5), SPH_C32(0xde320800), SPH_C32(0x288350fe), + SPH_C32(0x71852ac7), SPH_C32(0xa6bf9f96) }, + { SPH_C32(0xb0870c00), SPH_C32(0x714710f4), SPH_C32(0xa152e1f5), + SPH_C32(0x3454d933), SPH_C32(0xca8f0800), SPH_C32(0x07396701), + SPH_C32(0x1bf7cf7c), SPH_C32(0x82c07470) }, + { SPH_C32(0x2b040800), SPH_C32(0x5360ef7c), SPH_C32(0xa4e54caf), + SPH_C32(0x99a61e03), SPH_C32(0x45b10c00), SPH_C32(0x0aa4af76), + SPH_C32(0x7432879d), SPH_C32(0x0b4d58a6) }, + { SPH_C32(0xa43a0c00), SPH_C32(0x5efd270b), SPH_C32(0xcb20044e), + SPH_C32(0x102b32d5), SPH_C32(0x510c0c00), SPH_C32(0x251e9889), + SPH_C32(0x1e406226), SPH_C32(0x2f32b340) }, + { SPH_C32(0x74951000), SPH_C32(0x5a2b467e), SPH_C32(0x88fd1d2b), + SPH_C32(0x1ee68292), SPH_C32(0xcba90000), SPH_C32(0x90273769), + SPH_C32(0xbbdcf407), SPH_C32(0xd0f4af61) }, + { SPH_C32(0xfbab1400), SPH_C32(0x57b68e09), SPH_C32(0xe73855ca), + SPH_C32(0x976bae44), SPH_C32(0xdf140000), SPH_C32(0xbf9d0096), + SPH_C32(0xd1ae11bc), SPH_C32(0xf48b4487) }, + { SPH_C32(0x60281000), SPH_C32(0x75917181), SPH_C32(0xe28ff890), + SPH_C32(0x3a996974), SPH_C32(0x502a0400), SPH_C32(0xb200c8e1), + SPH_C32(0xbe6b595d), SPH_C32(0x7d066851) }, + { SPH_C32(0xef161400), SPH_C32(0x780cb9f6), SPH_C32(0x8d4ab071), + SPH_C32(0xb31445a2), SPH_C32(0x44970400), SPH_C32(0x9dbaff1e), + SPH_C32(0xd419bce6), SPH_C32(0x597983b7) }, + { SPH_C32(0xaaa71800), SPH_C32(0x72a81680), SPH_C32(0xf97837ec), + SPH_C32(0xb8591d04), SPH_C32(0x2a220000), SPH_C32(0xc47ebf14), + SPH_C32(0x04ce77d4), SPH_C32(0xcb92c512) }, + { SPH_C32(0x25991c00), SPH_C32(0x7f35def7), SPH_C32(0x96bd7f0d), + SPH_C32(0x31d431d2), SPH_C32(0x3e9f0000), SPH_C32(0xebc488eb), + SPH_C32(0x6ebc926f), SPH_C32(0xefed2ef4) }, + { SPH_C32(0xbe1a1800), SPH_C32(0x5d12217f), SPH_C32(0x930ad257), + SPH_C32(0x9c26f6e2), SPH_C32(0xb1a10400), SPH_C32(0xe659409c), + SPH_C32(0x0179da8e), SPH_C32(0x66600222) }, + { SPH_C32(0x31241c00), SPH_C32(0x508fe908), SPH_C32(0xfccf9ab6), + SPH_C32(0x15abda34), SPH_C32(0xa51c0400), SPH_C32(0xc9e37763), + SPH_C32(0x6b0b3f35), SPH_C32(0x421fe9c4) }, + { SPH_C32(0x951e1000), SPH_C32(0x0e72ce03), SPH_C32(0x37ef9ef8), + SPH_C32(0x0580e8e1), SPH_C32(0xf4100800), SPH_C32(0xecfdefea), + SPH_C32(0x754b5d13), SPH_C32(0x6d2d5a84) }, + { SPH_C32(0x1a201400), SPH_C32(0x03ef0674), SPH_C32(0x582ad619), + SPH_C32(0x8c0dc437), SPH_C32(0xe0ad0800), SPH_C32(0xc347d815), + SPH_C32(0x1f39b8a8), SPH_C32(0x4952b162) }, + { SPH_C32(0x81a31000), SPH_C32(0x21c8f9fc), SPH_C32(0x5d9d7b43), + SPH_C32(0x21ff0307), SPH_C32(0x6f930c00), SPH_C32(0xceda1062), + SPH_C32(0x70fcf049), SPH_C32(0xc0df9db4) }, + { SPH_C32(0x0e9d1400), SPH_C32(0x2c55318b), SPH_C32(0x325833a2), + SPH_C32(0xa8722fd1), SPH_C32(0x7b2e0c00), SPH_C32(0xe160279d), + SPH_C32(0x1a8e15f2), SPH_C32(0xe4a07652) }, + { SPH_C32(0x4b2c1800), SPH_C32(0x26f19efd), SPH_C32(0x466ab43f), + SPH_C32(0xa33f7777), SPH_C32(0x159b0800), SPH_C32(0xb8a46797), + SPH_C32(0xca59dec0), SPH_C32(0x764b30f7) }, + { SPH_C32(0xc4121c00), SPH_C32(0x2b6c568a), SPH_C32(0x29affcde), + SPH_C32(0x2ab25ba1), SPH_C32(0x01260800), SPH_C32(0x971e5068), + SPH_C32(0xa02b3b7b), SPH_C32(0x5234db11) }, + { SPH_C32(0x5f911800), SPH_C32(0x094ba902), SPH_C32(0x2c185184), + SPH_C32(0x87409c91), SPH_C32(0x8e180c00), SPH_C32(0x9a83981f), + SPH_C32(0xcfee739a), SPH_C32(0xdbb9f7c7) }, + { SPH_C32(0xd0af1c00), SPH_C32(0x04d66175), SPH_C32(0x43dd1965), + SPH_C32(0x0ecdb047), SPH_C32(0x9aa50c00), SPH_C32(0xb539afe0), + SPH_C32(0xa59c9621), SPH_C32(0xffc61c21) }, + { SPH_C32(0xcba90000), SPH_C32(0x90273769), SPH_C32(0xbbdcf407), + SPH_C32(0xd0f4af61), SPH_C32(0xbf3c1000), SPH_C32(0xca0c7117), + SPH_C32(0x3321e92c), SPH_C32(0xce122df3) }, + { SPH_C32(0x44970400), SPH_C32(0x9dbaff1e), SPH_C32(0xd419bce6), + SPH_C32(0x597983b7), SPH_C32(0xab811000), SPH_C32(0xe5b646e8), + SPH_C32(0x59530c97), SPH_C32(0xea6dc615) }, + { SPH_C32(0xdf140000), SPH_C32(0xbf9d0096), SPH_C32(0xd1ae11bc), + SPH_C32(0xf48b4487), SPH_C32(0x24bf1400), SPH_C32(0xe82b8e9f), + SPH_C32(0x36964476), SPH_C32(0x63e0eac3) }, + { SPH_C32(0x502a0400), SPH_C32(0xb200c8e1), SPH_C32(0xbe6b595d), + SPH_C32(0x7d066851), SPH_C32(0x30021400), SPH_C32(0xc791b960), + SPH_C32(0x5ce4a1cd), SPH_C32(0x479f0125) }, + { SPH_C32(0x159b0800), SPH_C32(0xb8a46797), SPH_C32(0xca59dec0), + SPH_C32(0x764b30f7), SPH_C32(0x5eb71000), SPH_C32(0x9e55f96a), + SPH_C32(0x8c336aff), SPH_C32(0xd5744780) }, + { SPH_C32(0x9aa50c00), SPH_C32(0xb539afe0), SPH_C32(0xa59c9621), + SPH_C32(0xffc61c21), SPH_C32(0x4a0a1000), SPH_C32(0xb1efce95), + SPH_C32(0xe6418f44), SPH_C32(0xf10bac66) }, + { SPH_C32(0x01260800), SPH_C32(0x971e5068), SPH_C32(0xa02b3b7b), + SPH_C32(0x5234db11), SPH_C32(0xc5341400), SPH_C32(0xbc7206e2), + SPH_C32(0x8984c7a5), SPH_C32(0x788680b0) }, + { SPH_C32(0x8e180c00), SPH_C32(0x9a83981f), SPH_C32(0xcfee739a), + SPH_C32(0xdbb9f7c7), SPH_C32(0xd1891400), SPH_C32(0x93c8311d), + SPH_C32(0xe3f6221e), SPH_C32(0x5cf96b56) }, + { SPH_C32(0x2a220000), SPH_C32(0xc47ebf14), SPH_C32(0x04ce77d4), + SPH_C32(0xcb92c512), SPH_C32(0x80851800), SPH_C32(0xb6d6a994), + SPH_C32(0xfdb64038), SPH_C32(0x73cbd816) }, + { SPH_C32(0xa51c0400), SPH_C32(0xc9e37763), SPH_C32(0x6b0b3f35), + SPH_C32(0x421fe9c4), SPH_C32(0x94381800), SPH_C32(0x996c9e6b), + SPH_C32(0x97c4a583), SPH_C32(0x57b433f0) }, + { SPH_C32(0x3e9f0000), SPH_C32(0xebc488eb), SPH_C32(0x6ebc926f), + SPH_C32(0xefed2ef4), SPH_C32(0x1b061c00), SPH_C32(0x94f1561c), + SPH_C32(0xf801ed62), SPH_C32(0xde391f26) }, + { SPH_C32(0xb1a10400), SPH_C32(0xe659409c), SPH_C32(0x0179da8e), + SPH_C32(0x66600222), SPH_C32(0x0fbb1c00), SPH_C32(0xbb4b61e3), + SPH_C32(0x927308d9), SPH_C32(0xfa46f4c0) }, + { SPH_C32(0xf4100800), SPH_C32(0xecfdefea), SPH_C32(0x754b5d13), + SPH_C32(0x6d2d5a84), SPH_C32(0x610e1800), SPH_C32(0xe28f21e9), + SPH_C32(0x42a4c3eb), SPH_C32(0x68adb265) }, + { SPH_C32(0x7b2e0c00), SPH_C32(0xe160279d), SPH_C32(0x1a8e15f2), + SPH_C32(0xe4a07652), SPH_C32(0x75b31800), SPH_C32(0xcd351616), + SPH_C32(0x28d62650), SPH_C32(0x4cd25983) }, + { SPH_C32(0xe0ad0800), SPH_C32(0xc347d815), SPH_C32(0x1f39b8a8), + SPH_C32(0x4952b162), SPH_C32(0xfa8d1c00), SPH_C32(0xc0a8de61), + SPH_C32(0x47136eb1), SPH_C32(0xc55f7555) }, + { SPH_C32(0x6f930c00), SPH_C32(0xceda1062), SPH_C32(0x70fcf049), + SPH_C32(0xc0df9db4), SPH_C32(0xee301c00), SPH_C32(0xef12e99e), + SPH_C32(0x2d618b0a), SPH_C32(0xe1209eb3) }, + { SPH_C32(0xbf3c1000), SPH_C32(0xca0c7117), SPH_C32(0x3321e92c), + SPH_C32(0xce122df3), SPH_C32(0x74951000), SPH_C32(0x5a2b467e), + SPH_C32(0x88fd1d2b), SPH_C32(0x1ee68292) }, + { SPH_C32(0x30021400), SPH_C32(0xc791b960), SPH_C32(0x5ce4a1cd), + SPH_C32(0x479f0125), SPH_C32(0x60281000), SPH_C32(0x75917181), + SPH_C32(0xe28ff890), SPH_C32(0x3a996974) }, + { SPH_C32(0xab811000), SPH_C32(0xe5b646e8), SPH_C32(0x59530c97), + SPH_C32(0xea6dc615), SPH_C32(0xef161400), SPH_C32(0x780cb9f6), + SPH_C32(0x8d4ab071), SPH_C32(0xb31445a2) }, + { SPH_C32(0x24bf1400), SPH_C32(0xe82b8e9f), SPH_C32(0x36964476), + SPH_C32(0x63e0eac3), SPH_C32(0xfbab1400), SPH_C32(0x57b68e09), + SPH_C32(0xe73855ca), SPH_C32(0x976bae44) }, + { SPH_C32(0x610e1800), SPH_C32(0xe28f21e9), SPH_C32(0x42a4c3eb), + SPH_C32(0x68adb265), SPH_C32(0x951e1000), SPH_C32(0x0e72ce03), + SPH_C32(0x37ef9ef8), SPH_C32(0x0580e8e1) }, + { SPH_C32(0xee301c00), SPH_C32(0xef12e99e), SPH_C32(0x2d618b0a), + SPH_C32(0xe1209eb3), SPH_C32(0x81a31000), SPH_C32(0x21c8f9fc), + SPH_C32(0x5d9d7b43), SPH_C32(0x21ff0307) }, + { SPH_C32(0x75b31800), SPH_C32(0xcd351616), SPH_C32(0x28d62650), + SPH_C32(0x4cd25983), SPH_C32(0x0e9d1400), SPH_C32(0x2c55318b), + SPH_C32(0x325833a2), SPH_C32(0xa8722fd1) }, + { SPH_C32(0xfa8d1c00), SPH_C32(0xc0a8de61), SPH_C32(0x47136eb1), + SPH_C32(0xc55f7555), SPH_C32(0x1a201400), SPH_C32(0x03ef0674), + SPH_C32(0x582ad619), SPH_C32(0x8c0dc437) }, + { SPH_C32(0x5eb71000), SPH_C32(0x9e55f96a), SPH_C32(0x8c336aff), + SPH_C32(0xd5744780), SPH_C32(0x4b2c1800), SPH_C32(0x26f19efd), + SPH_C32(0x466ab43f), SPH_C32(0xa33f7777) }, + { SPH_C32(0xd1891400), SPH_C32(0x93c8311d), SPH_C32(0xe3f6221e), + SPH_C32(0x5cf96b56), SPH_C32(0x5f911800), SPH_C32(0x094ba902), + SPH_C32(0x2c185184), SPH_C32(0x87409c91) }, + { SPH_C32(0x4a0a1000), SPH_C32(0xb1efce95), SPH_C32(0xe6418f44), + SPH_C32(0xf10bac66), SPH_C32(0xd0af1c00), SPH_C32(0x04d66175), + SPH_C32(0x43dd1965), SPH_C32(0x0ecdb047) }, + { SPH_C32(0xc5341400), SPH_C32(0xbc7206e2), SPH_C32(0x8984c7a5), + SPH_C32(0x788680b0), SPH_C32(0xc4121c00), SPH_C32(0x2b6c568a), + SPH_C32(0x29affcde), SPH_C32(0x2ab25ba1) }, + { SPH_C32(0x80851800), SPH_C32(0xb6d6a994), SPH_C32(0xfdb64038), + SPH_C32(0x73cbd816), SPH_C32(0xaaa71800), SPH_C32(0x72a81680), + SPH_C32(0xf97837ec), SPH_C32(0xb8591d04) }, + { SPH_C32(0x0fbb1c00), SPH_C32(0xbb4b61e3), SPH_C32(0x927308d9), + SPH_C32(0xfa46f4c0), SPH_C32(0xbe1a1800), SPH_C32(0x5d12217f), + SPH_C32(0x930ad257), SPH_C32(0x9c26f6e2) }, + { SPH_C32(0x94381800), SPH_C32(0x996c9e6b), SPH_C32(0x97c4a583), + SPH_C32(0x57b433f0), SPH_C32(0x31241c00), SPH_C32(0x508fe908), + SPH_C32(0xfccf9ab6), SPH_C32(0x15abda34) }, + { SPH_C32(0x1b061c00), SPH_C32(0x94f1561c), SPH_C32(0xf801ed62), + SPH_C32(0xde391f26), SPH_C32(0x25991c00), SPH_C32(0x7f35def7), + SPH_C32(0x96bd7f0d), SPH_C32(0x31d431d2) } +}; + +static const sph_u32 T256_12[64][8] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000) }, + { SPH_C32(0x5bd20080), SPH_C32(0x450f18ec), SPH_C32(0xc2c46c55), + SPH_C32(0xf362b233), SPH_C32(0x39a60000), SPH_C32(0x4ab753eb), + SPH_C32(0xd14e094b), SPH_C32(0xb772b42b) }, + { SPH_C32(0x39a60000), SPH_C32(0x4ab753eb), SPH_C32(0xd14e094b), + SPH_C32(0xb772b42b), SPH_C32(0x62740080), SPH_C32(0x0fb84b07), + SPH_C32(0x138a651e), SPH_C32(0x44100618) }, + { SPH_C32(0x62740080), SPH_C32(0x0fb84b07), SPH_C32(0x138a651e), + SPH_C32(0x44100618), SPH_C32(0x5bd20080), SPH_C32(0x450f18ec), + SPH_C32(0xc2c46c55), SPH_C32(0xf362b233) }, + { SPH_C32(0xb7a40100), SPH_C32(0x8a1f31d8), SPH_C32(0x8589d8ab), + SPH_C32(0xe6c46464), SPH_C32(0x734c0000), SPH_C32(0x956fa7d6), + SPH_C32(0xa29d1297), SPH_C32(0x6ee56854) }, + { SPH_C32(0xec760180), SPH_C32(0xcf102934), SPH_C32(0x474db4fe), + SPH_C32(0x15a6d657), SPH_C32(0x4aea0000), SPH_C32(0xdfd8f43d), + SPH_C32(0x73d31bdc), SPH_C32(0xd997dc7f) }, + { SPH_C32(0x8e020100), SPH_C32(0xc0a86233), SPH_C32(0x54c7d1e0), + SPH_C32(0x51b6d04f), SPH_C32(0x11380080), SPH_C32(0x9ad7ecd1), + SPH_C32(0xb1177789), SPH_C32(0x2af56e4c) }, + { SPH_C32(0xd5d00180), SPH_C32(0x85a77adf), SPH_C32(0x9603bdb5), + SPH_C32(0xa2d4627c), SPH_C32(0x289e0080), SPH_C32(0xd060bf3a), + SPH_C32(0x60597ec2), SPH_C32(0x9d87da67) }, + { SPH_C32(0x734c0000), SPH_C32(0x956fa7d6), SPH_C32(0xa29d1297), + SPH_C32(0x6ee56854), SPH_C32(0xc4e80100), SPH_C32(0x1f70960e), + SPH_C32(0x2714ca3c), SPH_C32(0x88210c30) }, + { SPH_C32(0x289e0080), SPH_C32(0xd060bf3a), SPH_C32(0x60597ec2), + SPH_C32(0x9d87da67), SPH_C32(0xfd4e0100), SPH_C32(0x55c7c5e5), + SPH_C32(0xf65ac377), SPH_C32(0x3f53b81b) }, + { SPH_C32(0x4aea0000), SPH_C32(0xdfd8f43d), SPH_C32(0x73d31bdc), + SPH_C32(0xd997dc7f), SPH_C32(0xa69c0180), SPH_C32(0x10c8dd09), + SPH_C32(0x349eaf22), SPH_C32(0xcc310a28) }, + { SPH_C32(0x11380080), SPH_C32(0x9ad7ecd1), SPH_C32(0xb1177789), + SPH_C32(0x2af56e4c), SPH_C32(0x9f3a0180), SPH_C32(0x5a7f8ee2), + SPH_C32(0xe5d0a669), SPH_C32(0x7b43be03) }, + { SPH_C32(0xc4e80100), SPH_C32(0x1f70960e), SPH_C32(0x2714ca3c), + SPH_C32(0x88210c30), SPH_C32(0xb7a40100), SPH_C32(0x8a1f31d8), + SPH_C32(0x8589d8ab), SPH_C32(0xe6c46464) }, + { SPH_C32(0x9f3a0180), SPH_C32(0x5a7f8ee2), SPH_C32(0xe5d0a669), + SPH_C32(0x7b43be03), SPH_C32(0x8e020100), SPH_C32(0xc0a86233), + SPH_C32(0x54c7d1e0), SPH_C32(0x51b6d04f) }, + { SPH_C32(0xfd4e0100), SPH_C32(0x55c7c5e5), SPH_C32(0xf65ac377), + SPH_C32(0x3f53b81b), SPH_C32(0xd5d00180), SPH_C32(0x85a77adf), + SPH_C32(0x9603bdb5), SPH_C32(0xa2d4627c) }, + { SPH_C32(0xa69c0180), SPH_C32(0x10c8dd09), SPH_C32(0x349eaf22), + SPH_C32(0xcc310a28), SPH_C32(0xec760180), SPH_C32(0xcf102934), + SPH_C32(0x474db4fe), SPH_C32(0x15a6d657) }, + { SPH_C32(0xa7b80200), SPH_C32(0x1f128433), SPH_C32(0x60e5f9f2), + SPH_C32(0x9e147576), SPH_C32(0xee260000), SPH_C32(0x124b683e), + SPH_C32(0x80c2d68f), SPH_C32(0x3bf3ab2c) }, + { SPH_C32(0xfc6a0280), SPH_C32(0x5a1d9cdf), SPH_C32(0xa22195a7), + SPH_C32(0x6d76c745), SPH_C32(0xd7800000), SPH_C32(0x58fc3bd5), + SPH_C32(0x518cdfc4), SPH_C32(0x8c811f07) }, + { SPH_C32(0x9e1e0200), SPH_C32(0x55a5d7d8), SPH_C32(0xb1abf0b9), + SPH_C32(0x2966c15d), SPH_C32(0x8c520080), SPH_C32(0x1df32339), + SPH_C32(0x9348b391), SPH_C32(0x7fe3ad34) }, + { SPH_C32(0xc5cc0280), SPH_C32(0x10aacf34), SPH_C32(0x736f9cec), + SPH_C32(0xda04736e), SPH_C32(0xb5f40080), SPH_C32(0x574470d2), + SPH_C32(0x4206bada), SPH_C32(0xc891191f) }, + { SPH_C32(0x101c0300), SPH_C32(0x950db5eb), SPH_C32(0xe56c2159), + SPH_C32(0x78d01112), SPH_C32(0x9d6a0000), SPH_C32(0x8724cfe8), + SPH_C32(0x225fc418), SPH_C32(0x5516c378) }, + { SPH_C32(0x4bce0380), SPH_C32(0xd002ad07), SPH_C32(0x27a84d0c), + SPH_C32(0x8bb2a321), SPH_C32(0xa4cc0000), SPH_C32(0xcd939c03), + SPH_C32(0xf311cd53), SPH_C32(0xe2647753) }, + { SPH_C32(0x29ba0300), SPH_C32(0xdfbae600), SPH_C32(0x34222812), + SPH_C32(0xcfa2a539), SPH_C32(0xff1e0080), SPH_C32(0x889c84ef), + SPH_C32(0x31d5a106), SPH_C32(0x1106c560) }, + { SPH_C32(0x72680380), SPH_C32(0x9ab5feec), SPH_C32(0xf6e64447), + SPH_C32(0x3cc0170a), SPH_C32(0xc6b80080), SPH_C32(0xc22bd704), + SPH_C32(0xe09ba84d), SPH_C32(0xa674714b) }, + { SPH_C32(0xd4f40200), SPH_C32(0x8a7d23e5), SPH_C32(0xc278eb65), + SPH_C32(0xf0f11d22), SPH_C32(0x2ace0100), SPH_C32(0x0d3bfe30), + SPH_C32(0xa7d61cb3), SPH_C32(0xb3d2a71c) }, + { SPH_C32(0x8f260280), SPH_C32(0xcf723b09), SPH_C32(0x00bc8730), + SPH_C32(0x0393af11), SPH_C32(0x13680100), SPH_C32(0x478caddb), + SPH_C32(0x769815f8), SPH_C32(0x04a01337) }, + { SPH_C32(0xed520200), SPH_C32(0xc0ca700e), SPH_C32(0x1336e22e), + SPH_C32(0x4783a909), SPH_C32(0x48ba0180), SPH_C32(0x0283b537), + SPH_C32(0xb45c79ad), SPH_C32(0xf7c2a104) }, + { SPH_C32(0xb6800280), SPH_C32(0x85c568e2), SPH_C32(0xd1f28e7b), + SPH_C32(0xb4e11b3a), SPH_C32(0x711c0180), SPH_C32(0x4834e6dc), + SPH_C32(0x651270e6), SPH_C32(0x40b0152f) }, + { SPH_C32(0x63500300), SPH_C32(0x0062123d), SPH_C32(0x47f133ce), + SPH_C32(0x16357946), SPH_C32(0x59820100), SPH_C32(0x985459e6), + SPH_C32(0x054b0e24), SPH_C32(0xdd37cf48) }, + { SPH_C32(0x38820380), SPH_C32(0x456d0ad1), SPH_C32(0x85355f9b), + SPH_C32(0xe557cb75), SPH_C32(0x60240100), SPH_C32(0xd2e30a0d), + SPH_C32(0xd405076f), SPH_C32(0x6a457b63) }, + { SPH_C32(0x5af60300), SPH_C32(0x4ad541d6), SPH_C32(0x96bf3a85), + SPH_C32(0xa147cd6d), SPH_C32(0x3bf60180), SPH_C32(0x97ec12e1), + SPH_C32(0x16c16b3a), SPH_C32(0x9927c950) }, + { SPH_C32(0x01240380), SPH_C32(0x0fda593a), SPH_C32(0x547b56d0), + SPH_C32(0x52257f5e), SPH_C32(0x02500180), SPH_C32(0xdd5b410a), + SPH_C32(0xc78f6271), SPH_C32(0x2e557d7b) }, + { SPH_C32(0xee260000), SPH_C32(0x124b683e), SPH_C32(0x80c2d68f), + SPH_C32(0x3bf3ab2c), SPH_C32(0x499e0200), SPH_C32(0x0d59ec0d), + SPH_C32(0xe0272f7d), SPH_C32(0xa5e7de5a) }, + { SPH_C32(0xb5f40080), SPH_C32(0x574470d2), SPH_C32(0x4206bada), + SPH_C32(0xc891191f), SPH_C32(0x70380200), SPH_C32(0x47eebfe6), + SPH_C32(0x31692636), SPH_C32(0x12956a71) }, + { SPH_C32(0xd7800000), SPH_C32(0x58fc3bd5), SPH_C32(0x518cdfc4), + SPH_C32(0x8c811f07), SPH_C32(0x2bea0280), SPH_C32(0x02e1a70a), + SPH_C32(0xf3ad4a63), SPH_C32(0xe1f7d842) }, + { SPH_C32(0x8c520080), SPH_C32(0x1df32339), SPH_C32(0x9348b391), + SPH_C32(0x7fe3ad34), SPH_C32(0x124c0280), SPH_C32(0x4856f4e1), + SPH_C32(0x22e34328), SPH_C32(0x56856c69) }, + { SPH_C32(0x59820100), SPH_C32(0x985459e6), SPH_C32(0x054b0e24), + SPH_C32(0xdd37cf48), SPH_C32(0x3ad20200), SPH_C32(0x98364bdb), + SPH_C32(0x42ba3dea), SPH_C32(0xcb02b60e) }, + { SPH_C32(0x02500180), SPH_C32(0xdd5b410a), SPH_C32(0xc78f6271), + SPH_C32(0x2e557d7b), SPH_C32(0x03740200), SPH_C32(0xd2811830), + SPH_C32(0x93f434a1), SPH_C32(0x7c700225) }, + { SPH_C32(0x60240100), SPH_C32(0xd2e30a0d), SPH_C32(0xd405076f), + SPH_C32(0x6a457b63), SPH_C32(0x58a60280), SPH_C32(0x978e00dc), + SPH_C32(0x513058f4), SPH_C32(0x8f12b016) }, + { SPH_C32(0x3bf60180), SPH_C32(0x97ec12e1), SPH_C32(0x16c16b3a), + SPH_C32(0x9927c950), SPH_C32(0x61000280), SPH_C32(0xdd395337), + SPH_C32(0x807e51bf), SPH_C32(0x3860043d) }, + { SPH_C32(0x9d6a0000), SPH_C32(0x8724cfe8), SPH_C32(0x225fc418), + SPH_C32(0x5516c378), SPH_C32(0x8d760300), SPH_C32(0x12297a03), + SPH_C32(0xc733e541), SPH_C32(0x2dc6d26a) }, + { SPH_C32(0xc6b80080), SPH_C32(0xc22bd704), SPH_C32(0xe09ba84d), + SPH_C32(0xa674714b), SPH_C32(0xb4d00300), SPH_C32(0x589e29e8), + SPH_C32(0x167dec0a), SPH_C32(0x9ab46641) }, + { SPH_C32(0xa4cc0000), SPH_C32(0xcd939c03), SPH_C32(0xf311cd53), + SPH_C32(0xe2647753), SPH_C32(0xef020380), SPH_C32(0x1d913104), + SPH_C32(0xd4b9805f), SPH_C32(0x69d6d472) }, + { SPH_C32(0xff1e0080), SPH_C32(0x889c84ef), SPH_C32(0x31d5a106), + SPH_C32(0x1106c560), SPH_C32(0xd6a40380), SPH_C32(0x572662ef), + SPH_C32(0x05f78914), SPH_C32(0xdea46059) }, + { SPH_C32(0x2ace0100), SPH_C32(0x0d3bfe30), SPH_C32(0xa7d61cb3), + SPH_C32(0xb3d2a71c), SPH_C32(0xfe3a0300), SPH_C32(0x8746ddd5), + SPH_C32(0x65aef7d6), SPH_C32(0x4323ba3e) }, + { SPH_C32(0x711c0180), SPH_C32(0x4834e6dc), SPH_C32(0x651270e6), + SPH_C32(0x40b0152f), SPH_C32(0xc79c0300), SPH_C32(0xcdf18e3e), + SPH_C32(0xb4e0fe9d), SPH_C32(0xf4510e15) }, + { SPH_C32(0x13680100), SPH_C32(0x478caddb), SPH_C32(0x769815f8), + SPH_C32(0x04a01337), SPH_C32(0x9c4e0380), SPH_C32(0x88fe96d2), + SPH_C32(0x762492c8), SPH_C32(0x0733bc26) }, + { SPH_C32(0x48ba0180), SPH_C32(0x0283b537), SPH_C32(0xb45c79ad), + SPH_C32(0xf7c2a104), SPH_C32(0xa5e80380), SPH_C32(0xc249c539), + SPH_C32(0xa76a9b83), SPH_C32(0xb041080d) }, + { SPH_C32(0x499e0200), SPH_C32(0x0d59ec0d), SPH_C32(0xe0272f7d), + SPH_C32(0xa5e7de5a), SPH_C32(0xa7b80200), SPH_C32(0x1f128433), + SPH_C32(0x60e5f9f2), SPH_C32(0x9e147576) }, + { SPH_C32(0x124c0280), SPH_C32(0x4856f4e1), SPH_C32(0x22e34328), + SPH_C32(0x56856c69), SPH_C32(0x9e1e0200), SPH_C32(0x55a5d7d8), + SPH_C32(0xb1abf0b9), SPH_C32(0x2966c15d) }, + { SPH_C32(0x70380200), SPH_C32(0x47eebfe6), SPH_C32(0x31692636), + SPH_C32(0x12956a71), SPH_C32(0xc5cc0280), SPH_C32(0x10aacf34), + SPH_C32(0x736f9cec), SPH_C32(0xda04736e) }, + { SPH_C32(0x2bea0280), SPH_C32(0x02e1a70a), SPH_C32(0xf3ad4a63), + SPH_C32(0xe1f7d842), SPH_C32(0xfc6a0280), SPH_C32(0x5a1d9cdf), + SPH_C32(0xa22195a7), SPH_C32(0x6d76c745) }, + { SPH_C32(0xfe3a0300), SPH_C32(0x8746ddd5), SPH_C32(0x65aef7d6), + SPH_C32(0x4323ba3e), SPH_C32(0xd4f40200), SPH_C32(0x8a7d23e5), + SPH_C32(0xc278eb65), SPH_C32(0xf0f11d22) }, + { SPH_C32(0xa5e80380), SPH_C32(0xc249c539), SPH_C32(0xa76a9b83), + SPH_C32(0xb041080d), SPH_C32(0xed520200), SPH_C32(0xc0ca700e), + SPH_C32(0x1336e22e), SPH_C32(0x4783a909) }, + { SPH_C32(0xc79c0300), SPH_C32(0xcdf18e3e), SPH_C32(0xb4e0fe9d), + SPH_C32(0xf4510e15), SPH_C32(0xb6800280), SPH_C32(0x85c568e2), + SPH_C32(0xd1f28e7b), SPH_C32(0xb4e11b3a) }, + { SPH_C32(0x9c4e0380), SPH_C32(0x88fe96d2), SPH_C32(0x762492c8), + SPH_C32(0x0733bc26), SPH_C32(0x8f260280), SPH_C32(0xcf723b09), + SPH_C32(0x00bc8730), SPH_C32(0x0393af11) }, + { SPH_C32(0x3ad20200), SPH_C32(0x98364bdb), SPH_C32(0x42ba3dea), + SPH_C32(0xcb02b60e), SPH_C32(0x63500300), SPH_C32(0x0062123d), + SPH_C32(0x47f133ce), SPH_C32(0x16357946) }, + { SPH_C32(0x61000280), SPH_C32(0xdd395337), SPH_C32(0x807e51bf), + SPH_C32(0x3860043d), SPH_C32(0x5af60300), SPH_C32(0x4ad541d6), + SPH_C32(0x96bf3a85), SPH_C32(0xa147cd6d) }, + { SPH_C32(0x03740200), SPH_C32(0xd2811830), SPH_C32(0x93f434a1), + SPH_C32(0x7c700225), SPH_C32(0x01240380), SPH_C32(0x0fda593a), + SPH_C32(0x547b56d0), SPH_C32(0x52257f5e) }, + { SPH_C32(0x58a60280), SPH_C32(0x978e00dc), SPH_C32(0x513058f4), + SPH_C32(0x8f12b016), SPH_C32(0x38820380), SPH_C32(0x456d0ad1), + SPH_C32(0x85355f9b), SPH_C32(0xe557cb75) }, + { SPH_C32(0x8d760300), SPH_C32(0x12297a03), SPH_C32(0xc733e541), + SPH_C32(0x2dc6d26a), SPH_C32(0x101c0300), SPH_C32(0x950db5eb), + SPH_C32(0xe56c2159), SPH_C32(0x78d01112) }, + { SPH_C32(0xd6a40380), SPH_C32(0x572662ef), SPH_C32(0x05f78914), + SPH_C32(0xdea46059), SPH_C32(0x29ba0300), SPH_C32(0xdfbae600), + SPH_C32(0x34222812), SPH_C32(0xcfa2a539) }, + { SPH_C32(0xb4d00300), SPH_C32(0x589e29e8), SPH_C32(0x167dec0a), + SPH_C32(0x9ab46641), SPH_C32(0x72680380), SPH_C32(0x9ab5feec), + SPH_C32(0xf6e64447), SPH_C32(0x3cc0170a) }, + { SPH_C32(0xef020380), SPH_C32(0x1d913104), SPH_C32(0xd4b9805f), + SPH_C32(0x69d6d472), SPH_C32(0x4bce0380), SPH_C32(0xd002ad07), + SPH_C32(0x27a84d0c), SPH_C32(0x8bb2a321) } +}; + +static const sph_u32 T256_18[64][8] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000) }, + { SPH_C32(0x515c0010), SPH_C32(0x40f372fb), SPH_C32(0xfce72602), + SPH_C32(0x71575061), SPH_C32(0x2e390000), SPH_C32(0x64dd6689), + SPH_C32(0x3cd406fc), SPH_C32(0xb1f490bc) }, + { SPH_C32(0x2e390000), SPH_C32(0x64dd6689), SPH_C32(0x3cd406fc), + SPH_C32(0xb1f490bc), SPH_C32(0x7f650010), SPH_C32(0x242e1472), + SPH_C32(0xc03320fe), SPH_C32(0xc0a3c0dd) }, + { SPH_C32(0x7f650010), SPH_C32(0x242e1472), SPH_C32(0xc03320fe), + SPH_C32(0xc0a3c0dd), SPH_C32(0x515c0010), SPH_C32(0x40f372fb), + SPH_C32(0xfce72602), SPH_C32(0x71575061) }, + { SPH_C32(0xa2b80020), SPH_C32(0x81e7e5f6), SPH_C32(0xf9ce4c04), + SPH_C32(0xe2afa0c0), SPH_C32(0x5c720000), SPH_C32(0xc9bacd12), + SPH_C32(0x79a90df9), SPH_C32(0x63e92178) }, + { SPH_C32(0xf3e40030), SPH_C32(0xc114970d), SPH_C32(0x05296a06), + SPH_C32(0x93f8f0a1), SPH_C32(0x724b0000), SPH_C32(0xad67ab9b), + SPH_C32(0x457d0b05), SPH_C32(0xd21db1c4) }, + { SPH_C32(0x8c810020), SPH_C32(0xe53a837f), SPH_C32(0xc51a4af8), + SPH_C32(0x535b307c), SPH_C32(0x23170010), SPH_C32(0xed94d960), + SPH_C32(0xb99a2d07), SPH_C32(0xa34ae1a5) }, + { SPH_C32(0xdddd0030), SPH_C32(0xa5c9f184), SPH_C32(0x39fd6cfa), + SPH_C32(0x220c601d), SPH_C32(0x0d2e0010), SPH_C32(0x8949bfe9), + SPH_C32(0x854e2bfb), SPH_C32(0x12be7119) }, + { SPH_C32(0x5c720000), SPH_C32(0xc9bacd12), SPH_C32(0x79a90df9), + SPH_C32(0x63e92178), SPH_C32(0xfeca0020), SPH_C32(0x485d28e4), + SPH_C32(0x806741fd), SPH_C32(0x814681b8) }, + { SPH_C32(0x0d2e0010), SPH_C32(0x8949bfe9), SPH_C32(0x854e2bfb), + SPH_C32(0x12be7119), SPH_C32(0xd0f30020), SPH_C32(0x2c804e6d), + SPH_C32(0xbcb34701), SPH_C32(0x30b21104) }, + { SPH_C32(0x724b0000), SPH_C32(0xad67ab9b), SPH_C32(0x457d0b05), + SPH_C32(0xd21db1c4), SPH_C32(0x81af0030), SPH_C32(0x6c733c96), + SPH_C32(0x40546103), SPH_C32(0x41e54165) }, + { SPH_C32(0x23170010), SPH_C32(0xed94d960), SPH_C32(0xb99a2d07), + SPH_C32(0xa34ae1a5), SPH_C32(0xaf960030), SPH_C32(0x08ae5a1f), + SPH_C32(0x7c8067ff), SPH_C32(0xf011d1d9) }, + { SPH_C32(0xfeca0020), SPH_C32(0x485d28e4), SPH_C32(0x806741fd), + SPH_C32(0x814681b8), SPH_C32(0xa2b80020), SPH_C32(0x81e7e5f6), + SPH_C32(0xf9ce4c04), SPH_C32(0xe2afa0c0) }, + { SPH_C32(0xaf960030), SPH_C32(0x08ae5a1f), SPH_C32(0x7c8067ff), + SPH_C32(0xf011d1d9), SPH_C32(0x8c810020), SPH_C32(0xe53a837f), + SPH_C32(0xc51a4af8), SPH_C32(0x535b307c) }, + { SPH_C32(0xd0f30020), SPH_C32(0x2c804e6d), SPH_C32(0xbcb34701), + SPH_C32(0x30b21104), SPH_C32(0xdddd0030), SPH_C32(0xa5c9f184), + SPH_C32(0x39fd6cfa), SPH_C32(0x220c601d) }, + { SPH_C32(0x81af0030), SPH_C32(0x6c733c96), SPH_C32(0x40546103), + SPH_C32(0x41e54165), SPH_C32(0xf3e40030), SPH_C32(0xc114970d), + SPH_C32(0x05296a06), SPH_C32(0x93f8f0a1) }, + { SPH_C32(0x4dce0040), SPH_C32(0x3b5bec7e), SPH_C32(0x36656ba8), + SPH_C32(0x23633a05), SPH_C32(0x78ab0000), SPH_C32(0xa0cd5a34), + SPH_C32(0x5d5ca0f7), SPH_C32(0x727784cb) }, + { SPH_C32(0x1c920050), SPH_C32(0x7ba89e85), SPH_C32(0xca824daa), + SPH_C32(0x52346a64), SPH_C32(0x56920000), SPH_C32(0xc4103cbd), + SPH_C32(0x6188a60b), SPH_C32(0xc3831477) }, + { SPH_C32(0x63f70040), SPH_C32(0x5f868af7), SPH_C32(0x0ab16d54), + SPH_C32(0x9297aab9), SPH_C32(0x07ce0010), SPH_C32(0x84e34e46), + SPH_C32(0x9d6f8009), SPH_C32(0xb2d44416) }, + { SPH_C32(0x32ab0050), SPH_C32(0x1f75f80c), SPH_C32(0xf6564b56), + SPH_C32(0xe3c0fad8), SPH_C32(0x29f70010), SPH_C32(0xe03e28cf), + SPH_C32(0xa1bb86f5), SPH_C32(0x0320d4aa) }, + { SPH_C32(0xef760060), SPH_C32(0xbabc0988), SPH_C32(0xcfab27ac), + SPH_C32(0xc1cc9ac5), SPH_C32(0x24d90000), SPH_C32(0x69779726), + SPH_C32(0x24f5ad0e), SPH_C32(0x119ea5b3) }, + { SPH_C32(0xbe2a0070), SPH_C32(0xfa4f7b73), SPH_C32(0x334c01ae), + SPH_C32(0xb09bcaa4), SPH_C32(0x0ae00000), SPH_C32(0x0daaf1af), + SPH_C32(0x1821abf2), SPH_C32(0xa06a350f) }, + { SPH_C32(0xc14f0060), SPH_C32(0xde616f01), SPH_C32(0xf37f2150), + SPH_C32(0x70380a79), SPH_C32(0x5bbc0010), SPH_C32(0x4d598354), + SPH_C32(0xe4c68df0), SPH_C32(0xd13d656e) }, + { SPH_C32(0x90130070), SPH_C32(0x9e921dfa), SPH_C32(0x0f980752), + SPH_C32(0x016f5a18), SPH_C32(0x75850010), SPH_C32(0x2984e5dd), + SPH_C32(0xd8128b0c), SPH_C32(0x60c9f5d2) }, + { SPH_C32(0x11bc0040), SPH_C32(0xf2e1216c), SPH_C32(0x4fcc6651), + SPH_C32(0x408a1b7d), SPH_C32(0x86610020), SPH_C32(0xe89072d0), + SPH_C32(0xdd3be10a), SPH_C32(0xf3310573) }, + { SPH_C32(0x40e00050), SPH_C32(0xb2125397), SPH_C32(0xb32b4053), + SPH_C32(0x31dd4b1c), SPH_C32(0xa8580020), SPH_C32(0x8c4d1459), + SPH_C32(0xe1efe7f6), SPH_C32(0x42c595cf) }, + { SPH_C32(0x3f850040), SPH_C32(0x963c47e5), SPH_C32(0x731860ad), + SPH_C32(0xf17e8bc1), SPH_C32(0xf9040030), SPH_C32(0xccbe66a2), + SPH_C32(0x1d08c1f4), SPH_C32(0x3392c5ae) }, + { SPH_C32(0x6ed90050), SPH_C32(0xd6cf351e), SPH_C32(0x8fff46af), + SPH_C32(0x8029dba0), SPH_C32(0xd73d0030), SPH_C32(0xa863002b), + SPH_C32(0x21dcc708), SPH_C32(0x82665512) }, + { SPH_C32(0xb3040060), SPH_C32(0x7306c49a), SPH_C32(0xb6022a55), + SPH_C32(0xa225bbbd), SPH_C32(0xda130020), SPH_C32(0x212abfc2), + SPH_C32(0xa492ecf3), SPH_C32(0x90d8240b) }, + { SPH_C32(0xe2580070), SPH_C32(0x33f5b661), SPH_C32(0x4ae50c57), + SPH_C32(0xd372ebdc), SPH_C32(0xf42a0020), SPH_C32(0x45f7d94b), + SPH_C32(0x9846ea0f), SPH_C32(0x212cb4b7) }, + { SPH_C32(0x9d3d0060), SPH_C32(0x17dba213), SPH_C32(0x8ad62ca9), + SPH_C32(0x13d12b01), SPH_C32(0xa5760030), SPH_C32(0x0504abb0), + SPH_C32(0x64a1cc0d), SPH_C32(0x507be4d6) }, + { SPH_C32(0xcc610070), SPH_C32(0x5728d0e8), SPH_C32(0x76310aab), + SPH_C32(0x62867b60), SPH_C32(0x8b4f0030), SPH_C32(0x61d9cd39), + SPH_C32(0x5875caf1), SPH_C32(0xe18f746a) }, + { SPH_C32(0x78ab0000), SPH_C32(0xa0cd5a34), SPH_C32(0x5d5ca0f7), + SPH_C32(0x727784cb), SPH_C32(0x35650040), SPH_C32(0x9b96b64a), + SPH_C32(0x6b39cb5f), SPH_C32(0x5114bece) }, + { SPH_C32(0x29f70010), SPH_C32(0xe03e28cf), SPH_C32(0xa1bb86f5), + SPH_C32(0x0320d4aa), SPH_C32(0x1b5c0040), SPH_C32(0xff4bd0c3), + SPH_C32(0x57edcda3), SPH_C32(0xe0e02e72) }, + { SPH_C32(0x56920000), SPH_C32(0xc4103cbd), SPH_C32(0x6188a60b), + SPH_C32(0xc3831477), SPH_C32(0x4a000050), SPH_C32(0xbfb8a238), + SPH_C32(0xab0aeba1), SPH_C32(0x91b77e13) }, + { SPH_C32(0x07ce0010), SPH_C32(0x84e34e46), SPH_C32(0x9d6f8009), + SPH_C32(0xb2d44416), SPH_C32(0x64390050), SPH_C32(0xdb65c4b1), + SPH_C32(0x97deed5d), SPH_C32(0x2043eeaf) }, + { SPH_C32(0xda130020), SPH_C32(0x212abfc2), SPH_C32(0xa492ecf3), + SPH_C32(0x90d8240b), SPH_C32(0x69170040), SPH_C32(0x522c7b58), + SPH_C32(0x1290c6a6), SPH_C32(0x32fd9fb6) }, + { SPH_C32(0x8b4f0030), SPH_C32(0x61d9cd39), SPH_C32(0x5875caf1), + SPH_C32(0xe18f746a), SPH_C32(0x472e0040), SPH_C32(0x36f11dd1), + SPH_C32(0x2e44c05a), SPH_C32(0x83090f0a) }, + { SPH_C32(0xf42a0020), SPH_C32(0x45f7d94b), SPH_C32(0x9846ea0f), + SPH_C32(0x212cb4b7), SPH_C32(0x16720050), SPH_C32(0x76026f2a), + SPH_C32(0xd2a3e658), SPH_C32(0xf25e5f6b) }, + { SPH_C32(0xa5760030), SPH_C32(0x0504abb0), SPH_C32(0x64a1cc0d), + SPH_C32(0x507be4d6), SPH_C32(0x384b0050), SPH_C32(0x12df09a3), + SPH_C32(0xee77e0a4), SPH_C32(0x43aacfd7) }, + { SPH_C32(0x24d90000), SPH_C32(0x69779726), SPH_C32(0x24f5ad0e), + SPH_C32(0x119ea5b3), SPH_C32(0xcbaf0060), SPH_C32(0xd3cb9eae), + SPH_C32(0xeb5e8aa2), SPH_C32(0xd0523f76) }, + { SPH_C32(0x75850010), SPH_C32(0x2984e5dd), SPH_C32(0xd8128b0c), + SPH_C32(0x60c9f5d2), SPH_C32(0xe5960060), SPH_C32(0xb716f827), + SPH_C32(0xd78a8c5e), SPH_C32(0x61a6afca) }, + { SPH_C32(0x0ae00000), SPH_C32(0x0daaf1af), SPH_C32(0x1821abf2), + SPH_C32(0xa06a350f), SPH_C32(0xb4ca0070), SPH_C32(0xf7e58adc), + SPH_C32(0x2b6daa5c), SPH_C32(0x10f1ffab) }, + { SPH_C32(0x5bbc0010), SPH_C32(0x4d598354), SPH_C32(0xe4c68df0), + SPH_C32(0xd13d656e), SPH_C32(0x9af30070), SPH_C32(0x9338ec55), + SPH_C32(0x17b9aca0), SPH_C32(0xa1056f17) }, + { SPH_C32(0x86610020), SPH_C32(0xe89072d0), SPH_C32(0xdd3be10a), + SPH_C32(0xf3310573), SPH_C32(0x97dd0060), SPH_C32(0x1a7153bc), + SPH_C32(0x92f7875b), SPH_C32(0xb3bb1e0e) }, + { SPH_C32(0xd73d0030), SPH_C32(0xa863002b), SPH_C32(0x21dcc708), + SPH_C32(0x82665512), SPH_C32(0xb9e40060), SPH_C32(0x7eac3535), + SPH_C32(0xae2381a7), SPH_C32(0x024f8eb2) }, + { SPH_C32(0xa8580020), SPH_C32(0x8c4d1459), SPH_C32(0xe1efe7f6), + SPH_C32(0x42c595cf), SPH_C32(0xe8b80070), SPH_C32(0x3e5f47ce), + SPH_C32(0x52c4a7a5), SPH_C32(0x7318ded3) }, + { SPH_C32(0xf9040030), SPH_C32(0xccbe66a2), SPH_C32(0x1d08c1f4), + SPH_C32(0x3392c5ae), SPH_C32(0xc6810070), SPH_C32(0x5a822147), + SPH_C32(0x6e10a159), SPH_C32(0xc2ec4e6f) }, + { SPH_C32(0x35650040), SPH_C32(0x9b96b64a), SPH_C32(0x6b39cb5f), + SPH_C32(0x5114bece), SPH_C32(0x4dce0040), SPH_C32(0x3b5bec7e), + SPH_C32(0x36656ba8), SPH_C32(0x23633a05) }, + { SPH_C32(0x64390050), SPH_C32(0xdb65c4b1), SPH_C32(0x97deed5d), + SPH_C32(0x2043eeaf), SPH_C32(0x63f70040), SPH_C32(0x5f868af7), + SPH_C32(0x0ab16d54), SPH_C32(0x9297aab9) }, + { SPH_C32(0x1b5c0040), SPH_C32(0xff4bd0c3), SPH_C32(0x57edcda3), + SPH_C32(0xe0e02e72), SPH_C32(0x32ab0050), SPH_C32(0x1f75f80c), + SPH_C32(0xf6564b56), SPH_C32(0xe3c0fad8) }, + { SPH_C32(0x4a000050), SPH_C32(0xbfb8a238), SPH_C32(0xab0aeba1), + SPH_C32(0x91b77e13), SPH_C32(0x1c920050), SPH_C32(0x7ba89e85), + SPH_C32(0xca824daa), SPH_C32(0x52346a64) }, + { SPH_C32(0x97dd0060), SPH_C32(0x1a7153bc), SPH_C32(0x92f7875b), + SPH_C32(0xb3bb1e0e), SPH_C32(0x11bc0040), SPH_C32(0xf2e1216c), + SPH_C32(0x4fcc6651), SPH_C32(0x408a1b7d) }, + { SPH_C32(0xc6810070), SPH_C32(0x5a822147), SPH_C32(0x6e10a159), + SPH_C32(0xc2ec4e6f), SPH_C32(0x3f850040), SPH_C32(0x963c47e5), + SPH_C32(0x731860ad), SPH_C32(0xf17e8bc1) }, + { SPH_C32(0xb9e40060), SPH_C32(0x7eac3535), SPH_C32(0xae2381a7), + SPH_C32(0x024f8eb2), SPH_C32(0x6ed90050), SPH_C32(0xd6cf351e), + SPH_C32(0x8fff46af), SPH_C32(0x8029dba0) }, + { SPH_C32(0xe8b80070), SPH_C32(0x3e5f47ce), SPH_C32(0x52c4a7a5), + SPH_C32(0x7318ded3), SPH_C32(0x40e00050), SPH_C32(0xb2125397), + SPH_C32(0xb32b4053), SPH_C32(0x31dd4b1c) }, + { SPH_C32(0x69170040), SPH_C32(0x522c7b58), SPH_C32(0x1290c6a6), + SPH_C32(0x32fd9fb6), SPH_C32(0xb3040060), SPH_C32(0x7306c49a), + SPH_C32(0xb6022a55), SPH_C32(0xa225bbbd) }, + { SPH_C32(0x384b0050), SPH_C32(0x12df09a3), SPH_C32(0xee77e0a4), + SPH_C32(0x43aacfd7), SPH_C32(0x9d3d0060), SPH_C32(0x17dba213), + SPH_C32(0x8ad62ca9), SPH_C32(0x13d12b01) }, + { SPH_C32(0x472e0040), SPH_C32(0x36f11dd1), SPH_C32(0x2e44c05a), + SPH_C32(0x83090f0a), SPH_C32(0xcc610070), SPH_C32(0x5728d0e8), + SPH_C32(0x76310aab), SPH_C32(0x62867b60) }, + { SPH_C32(0x16720050), SPH_C32(0x76026f2a), SPH_C32(0xd2a3e658), + SPH_C32(0xf25e5f6b), SPH_C32(0xe2580070), SPH_C32(0x33f5b661), + SPH_C32(0x4ae50c57), SPH_C32(0xd372ebdc) }, + { SPH_C32(0xcbaf0060), SPH_C32(0xd3cb9eae), SPH_C32(0xeb5e8aa2), + SPH_C32(0xd0523f76), SPH_C32(0xef760060), SPH_C32(0xbabc0988), + SPH_C32(0xcfab27ac), SPH_C32(0xc1cc9ac5) }, + { SPH_C32(0x9af30070), SPH_C32(0x9338ec55), SPH_C32(0x17b9aca0), + SPH_C32(0xa1056f17), SPH_C32(0xc14f0060), SPH_C32(0xde616f01), + SPH_C32(0xf37f2150), SPH_C32(0x70380a79) }, + { SPH_C32(0xe5960060), SPH_C32(0xb716f827), SPH_C32(0xd78a8c5e), + SPH_C32(0x61a6afca), SPH_C32(0x90130070), SPH_C32(0x9e921dfa), + SPH_C32(0x0f980752), SPH_C32(0x016f5a18) }, + { SPH_C32(0xb4ca0070), SPH_C32(0xf7e58adc), SPH_C32(0x2b6daa5c), + SPH_C32(0x10f1ffab), SPH_C32(0xbe2a0070), SPH_C32(0xfa4f7b73), + SPH_C32(0x334c01ae), SPH_C32(0xb09bcaa4) } +}; + +static const sph_u32 T256_24[64][8] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000) }, + { SPH_C32(0x88230002), SPH_C32(0x5fe7a7b3), SPH_C32(0x99e585aa), + SPH_C32(0x8d75f7f1), SPH_C32(0x51ac0000), SPH_C32(0x25e30f14), + SPH_C32(0x79e22a4c), SPH_C32(0x1298bd46) }, + { SPH_C32(0x51ac0000), SPH_C32(0x25e30f14), SPH_C32(0x79e22a4c), + SPH_C32(0x1298bd46), SPH_C32(0xd98f0002), SPH_C32(0x7a04a8a7), + SPH_C32(0xe007afe6), SPH_C32(0x9fed4ab7) }, + { SPH_C32(0xd98f0002), SPH_C32(0x7a04a8a7), SPH_C32(0xe007afe6), + SPH_C32(0x9fed4ab7), SPH_C32(0x88230002), SPH_C32(0x5fe7a7b3), + SPH_C32(0x99e585aa), SPH_C32(0x8d75f7f1) }, + { SPH_C32(0xd0080004), SPH_C32(0x8c768f77), SPH_C32(0x9dc5b050), + SPH_C32(0xaf4a29da), SPH_C32(0x6ba90000), SPH_C32(0x40ebf9aa), + SPH_C32(0x98321c3d), SPH_C32(0x76acc733) }, + { SPH_C32(0x582b0006), SPH_C32(0xd39128c4), SPH_C32(0x042035fa), + SPH_C32(0x223fde2b), SPH_C32(0x3a050000), SPH_C32(0x6508f6be), + SPH_C32(0xe1d03671), SPH_C32(0x64347a75) }, + { SPH_C32(0x81a40004), SPH_C32(0xa9958063), SPH_C32(0xe4279a1c), + SPH_C32(0xbdd2949c), SPH_C32(0xb2260002), SPH_C32(0x3aef510d), + SPH_C32(0x7835b3db), SPH_C32(0xe9418d84) }, + { SPH_C32(0x09870006), SPH_C32(0xf67227d0), SPH_C32(0x7dc21fb6), + SPH_C32(0x30a7636d), SPH_C32(0xe38a0002), SPH_C32(0x1f0c5e19), + SPH_C32(0x01d79997), SPH_C32(0xfbd930c2) }, + { SPH_C32(0x6ba90000), SPH_C32(0x40ebf9aa), SPH_C32(0x98321c3d), + SPH_C32(0x76acc733), SPH_C32(0xbba10004), SPH_C32(0xcc9d76dd), + SPH_C32(0x05f7ac6d), SPH_C32(0xd9e6eee9) }, + { SPH_C32(0xe38a0002), SPH_C32(0x1f0c5e19), SPH_C32(0x01d79997), + SPH_C32(0xfbd930c2), SPH_C32(0xea0d0004), SPH_C32(0xe97e79c9), + SPH_C32(0x7c158621), SPH_C32(0xcb7e53af) }, + { SPH_C32(0x3a050000), SPH_C32(0x6508f6be), SPH_C32(0xe1d03671), + SPH_C32(0x64347a75), SPH_C32(0x622e0006), SPH_C32(0xb699de7a), + SPH_C32(0xe5f0038b), SPH_C32(0x460ba45e) }, + { SPH_C32(0xb2260002), SPH_C32(0x3aef510d), SPH_C32(0x7835b3db), + SPH_C32(0xe9418d84), SPH_C32(0x33820006), SPH_C32(0x937ad16e), + SPH_C32(0x9c1229c7), SPH_C32(0x54931918) }, + { SPH_C32(0xbba10004), SPH_C32(0xcc9d76dd), SPH_C32(0x05f7ac6d), + SPH_C32(0xd9e6eee9), SPH_C32(0xd0080004), SPH_C32(0x8c768f77), + SPH_C32(0x9dc5b050), SPH_C32(0xaf4a29da) }, + { SPH_C32(0x33820006), SPH_C32(0x937ad16e), SPH_C32(0x9c1229c7), + SPH_C32(0x54931918), SPH_C32(0x81a40004), SPH_C32(0xa9958063), + SPH_C32(0xe4279a1c), SPH_C32(0xbdd2949c) }, + { SPH_C32(0xea0d0004), SPH_C32(0xe97e79c9), SPH_C32(0x7c158621), + SPH_C32(0xcb7e53af), SPH_C32(0x09870006), SPH_C32(0xf67227d0), + SPH_C32(0x7dc21fb6), SPH_C32(0x30a7636d) }, + { SPH_C32(0x622e0006), SPH_C32(0xb699de7a), SPH_C32(0xe5f0038b), + SPH_C32(0x460ba45e), SPH_C32(0x582b0006), SPH_C32(0xd39128c4), + SPH_C32(0x042035fa), SPH_C32(0x223fde2b) }, + { SPH_C32(0xa8ae0008), SPH_C32(0x2079397d), SPH_C32(0xfe739301), + SPH_C32(0xb8a92831), SPH_C32(0x171c0000), SPH_C32(0xb26e3344), + SPH_C32(0x9e6a837e), SPH_C32(0x58f8485f) }, + { SPH_C32(0x208d000a), SPH_C32(0x7f9e9ece), SPH_C32(0x679616ab), + SPH_C32(0x35dcdfc0), SPH_C32(0x46b00000), SPH_C32(0x978d3c50), + SPH_C32(0xe788a932), SPH_C32(0x4a60f519) }, + { SPH_C32(0xf9020008), SPH_C32(0x059a3669), SPH_C32(0x8791b94d), + SPH_C32(0xaa319577), SPH_C32(0xce930002), SPH_C32(0xc86a9be3), + SPH_C32(0x7e6d2c98), SPH_C32(0xc71502e8) }, + { SPH_C32(0x7121000a), SPH_C32(0x5a7d91da), SPH_C32(0x1e743ce7), + SPH_C32(0x27446286), SPH_C32(0x9f3f0002), SPH_C32(0xed8994f7), + SPH_C32(0x078f06d4), SPH_C32(0xd58dbfae) }, + { SPH_C32(0x78a6000c), SPH_C32(0xac0fb60a), SPH_C32(0x63b62351), + SPH_C32(0x17e301eb), SPH_C32(0x7cb50000), SPH_C32(0xf285caee), + SPH_C32(0x06589f43), SPH_C32(0x2e548f6c) }, + { SPH_C32(0xf085000e), SPH_C32(0xf3e811b9), SPH_C32(0xfa53a6fb), + SPH_C32(0x9a96f61a), SPH_C32(0x2d190000), SPH_C32(0xd766c5fa), + SPH_C32(0x7fbab50f), SPH_C32(0x3ccc322a) }, + { SPH_C32(0x290a000c), SPH_C32(0x89ecb91e), SPH_C32(0x1a54091d), + SPH_C32(0x057bbcad), SPH_C32(0xa53a0002), SPH_C32(0x88816249), + SPH_C32(0xe65f30a5), SPH_C32(0xb1b9c5db) }, + { SPH_C32(0xa129000e), SPH_C32(0xd60b1ead), SPH_C32(0x83b18cb7), + SPH_C32(0x880e4b5c), SPH_C32(0xf4960002), SPH_C32(0xad626d5d), + SPH_C32(0x9fbd1ae9), SPH_C32(0xa321789d) }, + { SPH_C32(0xc3070008), SPH_C32(0x6092c0d7), SPH_C32(0x66418f3c), + SPH_C32(0xce05ef02), SPH_C32(0xacbd0004), SPH_C32(0x7ef34599), + SPH_C32(0x9b9d2f13), SPH_C32(0x811ea6b6) }, + { SPH_C32(0x4b24000a), SPH_C32(0x3f756764), SPH_C32(0xffa40a96), + SPH_C32(0x437018f3), SPH_C32(0xfd110004), SPH_C32(0x5b104a8d), + SPH_C32(0xe27f055f), SPH_C32(0x93861bf0) }, + { SPH_C32(0x92ab0008), SPH_C32(0x4571cfc3), SPH_C32(0x1fa3a570), + SPH_C32(0xdc9d5244), SPH_C32(0x75320006), SPH_C32(0x04f7ed3e), + SPH_C32(0x7b9a80f5), SPH_C32(0x1ef3ec01) }, + { SPH_C32(0x1a88000a), SPH_C32(0x1a966870), SPH_C32(0x864620da), + SPH_C32(0x51e8a5b5), SPH_C32(0x249e0006), SPH_C32(0x2114e22a), + SPH_C32(0x0278aab9), SPH_C32(0x0c6b5147) }, + { SPH_C32(0x130f000c), SPH_C32(0xece44fa0), SPH_C32(0xfb843f6c), + SPH_C32(0x614fc6d8), SPH_C32(0xc7140004), SPH_C32(0x3e18bc33), + SPH_C32(0x03af332e), SPH_C32(0xf7b26185) }, + { SPH_C32(0x9b2c000e), SPH_C32(0xb303e813), SPH_C32(0x6261bac6), + SPH_C32(0xec3a3129), SPH_C32(0x96b80004), SPH_C32(0x1bfbb327), + SPH_C32(0x7a4d1962), SPH_C32(0xe52adcc3) }, + { SPH_C32(0x42a3000c), SPH_C32(0xc90740b4), SPH_C32(0x82661520), + SPH_C32(0x73d77b9e), SPH_C32(0x1e9b0006), SPH_C32(0x441c1494), + SPH_C32(0xe3a89cc8), SPH_C32(0x685f2b32) }, + { SPH_C32(0xca80000e), SPH_C32(0x96e0e707), SPH_C32(0x1b83908a), + SPH_C32(0xfea28c6f), SPH_C32(0x4f370006), SPH_C32(0x61ff1b80), + SPH_C32(0x9a4ab684), SPH_C32(0x7ac79674) }, + { SPH_C32(0x171c0000), SPH_C32(0xb26e3344), SPH_C32(0x9e6a837e), + SPH_C32(0x58f8485f), SPH_C32(0xbfb20008), SPH_C32(0x92170a39), + SPH_C32(0x6019107f), SPH_C32(0xe051606e) }, + { SPH_C32(0x9f3f0002), SPH_C32(0xed8994f7), SPH_C32(0x078f06d4), + SPH_C32(0xd58dbfae), SPH_C32(0xee1e0008), SPH_C32(0xb7f4052d), + SPH_C32(0x19fb3a33), SPH_C32(0xf2c9dd28) }, + { SPH_C32(0x46b00000), SPH_C32(0x978d3c50), SPH_C32(0xe788a932), + SPH_C32(0x4a60f519), SPH_C32(0x663d000a), SPH_C32(0xe813a29e), + SPH_C32(0x801ebf99), SPH_C32(0x7fbc2ad9) }, + { SPH_C32(0xce930002), SPH_C32(0xc86a9be3), SPH_C32(0x7e6d2c98), + SPH_C32(0xc71502e8), SPH_C32(0x3791000a), SPH_C32(0xcdf0ad8a), + SPH_C32(0xf9fc95d5), SPH_C32(0x6d24979f) }, + { SPH_C32(0xc7140004), SPH_C32(0x3e18bc33), SPH_C32(0x03af332e), + SPH_C32(0xf7b26185), SPH_C32(0xd41b0008), SPH_C32(0xd2fcf393), + SPH_C32(0xf82b0c42), SPH_C32(0x96fda75d) }, + { SPH_C32(0x4f370006), SPH_C32(0x61ff1b80), SPH_C32(0x9a4ab684), + SPH_C32(0x7ac79674), SPH_C32(0x85b70008), SPH_C32(0xf71ffc87), + SPH_C32(0x81c9260e), SPH_C32(0x84651a1b) }, + { SPH_C32(0x96b80004), SPH_C32(0x1bfbb327), SPH_C32(0x7a4d1962), + SPH_C32(0xe52adcc3), SPH_C32(0x0d94000a), SPH_C32(0xa8f85b34), + SPH_C32(0x182ca3a4), SPH_C32(0x0910edea) }, + { SPH_C32(0x1e9b0006), SPH_C32(0x441c1494), SPH_C32(0xe3a89cc8), + SPH_C32(0x685f2b32), SPH_C32(0x5c38000a), SPH_C32(0x8d1b5420), + SPH_C32(0x61ce89e8), SPH_C32(0x1b8850ac) }, + { SPH_C32(0x7cb50000), SPH_C32(0xf285caee), SPH_C32(0x06589f43), + SPH_C32(0x2e548f6c), SPH_C32(0x0413000c), SPH_C32(0x5e8a7ce4), + SPH_C32(0x65eebc12), SPH_C32(0x39b78e87) }, + { SPH_C32(0xf4960002), SPH_C32(0xad626d5d), SPH_C32(0x9fbd1ae9), + SPH_C32(0xa321789d), SPH_C32(0x55bf000c), SPH_C32(0x7b6973f0), + SPH_C32(0x1c0c965e), SPH_C32(0x2b2f33c1) }, + { SPH_C32(0x2d190000), SPH_C32(0xd766c5fa), SPH_C32(0x7fbab50f), + SPH_C32(0x3ccc322a), SPH_C32(0xdd9c000e), SPH_C32(0x248ed443), + SPH_C32(0x85e913f4), SPH_C32(0xa65ac430) }, + { SPH_C32(0xa53a0002), SPH_C32(0x88816249), SPH_C32(0xe65f30a5), + SPH_C32(0xb1b9c5db), SPH_C32(0x8c30000e), SPH_C32(0x016ddb57), + SPH_C32(0xfc0b39b8), SPH_C32(0xb4c27976) }, + { SPH_C32(0xacbd0004), SPH_C32(0x7ef34599), SPH_C32(0x9b9d2f13), + SPH_C32(0x811ea6b6), SPH_C32(0x6fba000c), SPH_C32(0x1e61854e), + SPH_C32(0xfddca02f), SPH_C32(0x4f1b49b4) }, + { SPH_C32(0x249e0006), SPH_C32(0x2114e22a), SPH_C32(0x0278aab9), + SPH_C32(0x0c6b5147), SPH_C32(0x3e16000c), SPH_C32(0x3b828a5a), + SPH_C32(0x843e8a63), SPH_C32(0x5d83f4f2) }, + { SPH_C32(0xfd110004), SPH_C32(0x5b104a8d), SPH_C32(0xe27f055f), + SPH_C32(0x93861bf0), SPH_C32(0xb635000e), SPH_C32(0x64652de9), + SPH_C32(0x1ddb0fc9), SPH_C32(0xd0f60303) }, + { SPH_C32(0x75320006), SPH_C32(0x04f7ed3e), SPH_C32(0x7b9a80f5), + SPH_C32(0x1ef3ec01), SPH_C32(0xe799000e), SPH_C32(0x418622fd), + SPH_C32(0x64392585), SPH_C32(0xc26ebe45) }, + { SPH_C32(0xbfb20008), SPH_C32(0x92170a39), SPH_C32(0x6019107f), + SPH_C32(0xe051606e), SPH_C32(0xa8ae0008), SPH_C32(0x2079397d), + SPH_C32(0xfe739301), SPH_C32(0xb8a92831) }, + { SPH_C32(0x3791000a), SPH_C32(0xcdf0ad8a), SPH_C32(0xf9fc95d5), + SPH_C32(0x6d24979f), SPH_C32(0xf9020008), SPH_C32(0x059a3669), + SPH_C32(0x8791b94d), SPH_C32(0xaa319577) }, + { SPH_C32(0xee1e0008), SPH_C32(0xb7f4052d), SPH_C32(0x19fb3a33), + SPH_C32(0xf2c9dd28), SPH_C32(0x7121000a), SPH_C32(0x5a7d91da), + SPH_C32(0x1e743ce7), SPH_C32(0x27446286) }, + { SPH_C32(0x663d000a), SPH_C32(0xe813a29e), SPH_C32(0x801ebf99), + SPH_C32(0x7fbc2ad9), SPH_C32(0x208d000a), SPH_C32(0x7f9e9ece), + SPH_C32(0x679616ab), SPH_C32(0x35dcdfc0) }, + { SPH_C32(0x6fba000c), SPH_C32(0x1e61854e), SPH_C32(0xfddca02f), + SPH_C32(0x4f1b49b4), SPH_C32(0xc3070008), SPH_C32(0x6092c0d7), + SPH_C32(0x66418f3c), SPH_C32(0xce05ef02) }, + { SPH_C32(0xe799000e), SPH_C32(0x418622fd), SPH_C32(0x64392585), + SPH_C32(0xc26ebe45), SPH_C32(0x92ab0008), SPH_C32(0x4571cfc3), + SPH_C32(0x1fa3a570), SPH_C32(0xdc9d5244) }, + { SPH_C32(0x3e16000c), SPH_C32(0x3b828a5a), SPH_C32(0x843e8a63), + SPH_C32(0x5d83f4f2), SPH_C32(0x1a88000a), SPH_C32(0x1a966870), + SPH_C32(0x864620da), SPH_C32(0x51e8a5b5) }, + { SPH_C32(0xb635000e), SPH_C32(0x64652de9), SPH_C32(0x1ddb0fc9), + SPH_C32(0xd0f60303), SPH_C32(0x4b24000a), SPH_C32(0x3f756764), + SPH_C32(0xffa40a96), SPH_C32(0x437018f3) }, + { SPH_C32(0xd41b0008), SPH_C32(0xd2fcf393), SPH_C32(0xf82b0c42), + SPH_C32(0x96fda75d), SPH_C32(0x130f000c), SPH_C32(0xece44fa0), + SPH_C32(0xfb843f6c), SPH_C32(0x614fc6d8) }, + { SPH_C32(0x5c38000a), SPH_C32(0x8d1b5420), SPH_C32(0x61ce89e8), + SPH_C32(0x1b8850ac), SPH_C32(0x42a3000c), SPH_C32(0xc90740b4), + SPH_C32(0x82661520), SPH_C32(0x73d77b9e) }, + { SPH_C32(0x85b70008), SPH_C32(0xf71ffc87), SPH_C32(0x81c9260e), + SPH_C32(0x84651a1b), SPH_C32(0xca80000e), SPH_C32(0x96e0e707), + SPH_C32(0x1b83908a), SPH_C32(0xfea28c6f) }, + { SPH_C32(0x0d94000a), SPH_C32(0xa8f85b34), SPH_C32(0x182ca3a4), + SPH_C32(0x0910edea), SPH_C32(0x9b2c000e), SPH_C32(0xb303e813), + SPH_C32(0x6261bac6), SPH_C32(0xec3a3129) }, + { SPH_C32(0x0413000c), SPH_C32(0x5e8a7ce4), SPH_C32(0x65eebc12), + SPH_C32(0x39b78e87), SPH_C32(0x78a6000c), SPH_C32(0xac0fb60a), + SPH_C32(0x63b62351), SPH_C32(0x17e301eb) }, + { SPH_C32(0x8c30000e), SPH_C32(0x016ddb57), SPH_C32(0xfc0b39b8), + SPH_C32(0xb4c27976), SPH_C32(0x290a000c), SPH_C32(0x89ecb91e), + SPH_C32(0x1a54091d), SPH_C32(0x057bbcad) }, + { SPH_C32(0x55bf000c), SPH_C32(0x7b6973f0), SPH_C32(0x1c0c965e), + SPH_C32(0x2b2f33c1), SPH_C32(0xa129000e), SPH_C32(0xd60b1ead), + SPH_C32(0x83b18cb7), SPH_C32(0x880e4b5c) }, + { SPH_C32(0xdd9c000e), SPH_C32(0x248ed443), SPH_C32(0x85e913f4), + SPH_C32(0xa65ac430), SPH_C32(0xf085000e), SPH_C32(0xf3e811b9), + SPH_C32(0xfa53a6fb), SPH_C32(0x9a96f61a) } +}; + +static const sph_u32 T256_30[4][8] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000) }, + { SPH_C32(0xc04e0001), SPH_C32(0x33b9c010), SPH_C32(0xae0ebb05), + SPH_C32(0xb5a4c63b), SPH_C32(0xc8f10000), SPH_C32(0x0b2de782), + SPH_C32(0x6bf648a4), SPH_C32(0x539cbdbf) }, + { SPH_C32(0xc8f10000), SPH_C32(0x0b2de782), SPH_C32(0x6bf648a4), + SPH_C32(0x539cbdbf), SPH_C32(0x08bf0001), SPH_C32(0x38942792), + SPH_C32(0xc5f8f3a1), SPH_C32(0xe6387b84) }, + { SPH_C32(0x08bf0001), SPH_C32(0x38942792), SPH_C32(0xc5f8f3a1), + SPH_C32(0xe6387b84), SPH_C32(0xc04e0001), SPH_C32(0x33b9c010), + SPH_C32(0xae0ebb05), SPH_C32(0xb5a4c63b) } +}; + +#define INPUT_SMALL do { \ + unsigned acc = buf[0]; \ + const sph_u32 *rp; \ + rp = &T256_0[acc >> 2][0]; \ + m0 = rp[0]; \ + m1 = rp[1]; \ + m2 = rp[2]; \ + m3 = rp[3]; \ + m4 = rp[4]; \ + m5 = rp[5]; \ + m6 = rp[6]; \ + m7 = rp[7]; \ + acc = (acc << 8) | buf[1]; \ + rp = &T256_6[(acc >> 4) & 0x3f][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + acc = (acc << 8) | buf[2]; \ + rp = &T256_12[(acc >> 6) & 0x3f][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + rp = &T256_18[acc & 0x3f][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + acc = buf[3]; \ + rp = &T256_24[acc >> 2][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + rp = &T256_30[acc & 0x03][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + } while (0) + +#endif + +#if SPH_HAMSI_EXPAND_SMALL == 7 + +static const sph_u32 T256_0[128][8] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000) }, + { SPH_C32(0xcba90000), SPH_C32(0x90273769), SPH_C32(0xbbdcf407), + SPH_C32(0xd0f4af61), SPH_C32(0xbf3c1000), SPH_C32(0xca0c7117), + SPH_C32(0x3321e92c), SPH_C32(0xce122df3) }, + { SPH_C32(0xe92a2000), SPH_C32(0xb4578cfc), SPH_C32(0x11fa3a57), + SPH_C32(0x3dc90524), SPH_C32(0x97530000), SPH_C32(0x204f6ed3), + SPH_C32(0x77b9e80f), SPH_C32(0xa1ec5ec1) }, + { SPH_C32(0x22832000), SPH_C32(0x2470bb95), SPH_C32(0xaa26ce50), + SPH_C32(0xed3daa45), SPH_C32(0x286f1000), SPH_C32(0xea431fc4), + SPH_C32(0x44980123), SPH_C32(0x6ffe7332) }, + { SPH_C32(0x97530000), SPH_C32(0x204f6ed3), SPH_C32(0x77b9e80f), + SPH_C32(0xa1ec5ec1), SPH_C32(0x7e792000), SPH_C32(0x9418e22f), + SPH_C32(0x6643d258), SPH_C32(0x9c255be5) }, + { SPH_C32(0x5cfa0000), SPH_C32(0xb06859ba), SPH_C32(0xcc651c08), + SPH_C32(0x7118f1a0), SPH_C32(0xc1453000), SPH_C32(0x5e149338), + SPH_C32(0x55623b74), SPH_C32(0x52377616) }, + { SPH_C32(0x7e792000), SPH_C32(0x9418e22f), SPH_C32(0x6643d258), + SPH_C32(0x9c255be5), SPH_C32(0xe92a2000), SPH_C32(0xb4578cfc), + SPH_C32(0x11fa3a57), SPH_C32(0x3dc90524) }, + { SPH_C32(0xb5d02000), SPH_C32(0x043fd546), SPH_C32(0xdd9f265f), + SPH_C32(0x4cd1f484), SPH_C32(0x56163000), SPH_C32(0x7e5bfdeb), + SPH_C32(0x22dbd37b), SPH_C32(0xf3db28d7) }, + { SPH_C32(0x121b4000), SPH_C32(0x5b17d9e8), SPH_C32(0x8dfacfab), + SPH_C32(0xce36cc72), SPH_C32(0xe6570000), SPH_C32(0x4bb33a25), + SPH_C32(0x848598ba), SPH_C32(0x1041003e) }, + { SPH_C32(0xd9b24000), SPH_C32(0xcb30ee81), SPH_C32(0x36263bac), + SPH_C32(0x1ec26313), SPH_C32(0x596b1000), SPH_C32(0x81bf4b32), + SPH_C32(0xb7a47196), SPH_C32(0xde532dcd) }, + { SPH_C32(0xfb316000), SPH_C32(0xef405514), SPH_C32(0x9c00f5fc), + SPH_C32(0xf3ffc956), SPH_C32(0x71040000), SPH_C32(0x6bfc54f6), + SPH_C32(0xf33c70b5), SPH_C32(0xb1ad5eff) }, + { SPH_C32(0x30986000), SPH_C32(0x7f67627d), SPH_C32(0x27dc01fb), + SPH_C32(0x230b6637), SPH_C32(0xce381000), SPH_C32(0xa1f025e1), + SPH_C32(0xc01d9999), SPH_C32(0x7fbf730c) }, + { SPH_C32(0x85484000), SPH_C32(0x7b58b73b), SPH_C32(0xfa4327a4), + SPH_C32(0x6fda92b3), SPH_C32(0x982e2000), SPH_C32(0xdfabd80a), + SPH_C32(0xe2c64ae2), SPH_C32(0x8c645bdb) }, + { SPH_C32(0x4ee14000), SPH_C32(0xeb7f8052), SPH_C32(0x419fd3a3), + SPH_C32(0xbf2e3dd2), SPH_C32(0x27123000), SPH_C32(0x15a7a91d), + SPH_C32(0xd1e7a3ce), SPH_C32(0x42767628) }, + { SPH_C32(0x6c626000), SPH_C32(0xcf0f3bc7), SPH_C32(0xebb91df3), + SPH_C32(0x52139797), SPH_C32(0x0f7d2000), SPH_C32(0xffe4b6d9), + SPH_C32(0x957fa2ed), SPH_C32(0x2d88051a) }, + { SPH_C32(0xa7cb6000), SPH_C32(0x5f280cae), SPH_C32(0x5065e9f4), + SPH_C32(0x82e738f6), SPH_C32(0xb0413000), SPH_C32(0x35e8c7ce), + SPH_C32(0xa65e4bc1), SPH_C32(0xe39a28e9) }, + { SPH_C32(0xe6570000), SPH_C32(0x4bb33a25), SPH_C32(0x848598ba), + SPH_C32(0x1041003e), SPH_C32(0xf44c4000), SPH_C32(0x10a4e3cd), + SPH_C32(0x097f5711), SPH_C32(0xde77cc4c) }, + { SPH_C32(0x2dfe0000), SPH_C32(0xdb940d4c), SPH_C32(0x3f596cbd), + SPH_C32(0xc0b5af5f), SPH_C32(0x4b705000), SPH_C32(0xdaa892da), + SPH_C32(0x3a5ebe3d), SPH_C32(0x1065e1bf) }, + { SPH_C32(0x0f7d2000), SPH_C32(0xffe4b6d9), SPH_C32(0x957fa2ed), + SPH_C32(0x2d88051a), SPH_C32(0x631f4000), SPH_C32(0x30eb8d1e), + SPH_C32(0x7ec6bf1e), SPH_C32(0x7f9b928d) }, + { SPH_C32(0xc4d42000), SPH_C32(0x6fc381b0), SPH_C32(0x2ea356ea), + SPH_C32(0xfd7caa7b), SPH_C32(0xdc235000), SPH_C32(0xfae7fc09), + SPH_C32(0x4de75632), SPH_C32(0xb189bf7e) }, + { SPH_C32(0x71040000), SPH_C32(0x6bfc54f6), SPH_C32(0xf33c70b5), + SPH_C32(0xb1ad5eff), SPH_C32(0x8a356000), SPH_C32(0x84bc01e2), + SPH_C32(0x6f3c8549), SPH_C32(0x425297a9) }, + { SPH_C32(0xbaad0000), SPH_C32(0xfbdb639f), SPH_C32(0x48e084b2), + SPH_C32(0x6159f19e), SPH_C32(0x35097000), SPH_C32(0x4eb070f5), + SPH_C32(0x5c1d6c65), SPH_C32(0x8c40ba5a) }, + { SPH_C32(0x982e2000), SPH_C32(0xdfabd80a), SPH_C32(0xe2c64ae2), + SPH_C32(0x8c645bdb), SPH_C32(0x1d666000), SPH_C32(0xa4f36f31), + SPH_C32(0x18856d46), SPH_C32(0xe3bec968) }, + { SPH_C32(0x53872000), SPH_C32(0x4f8cef63), SPH_C32(0x591abee5), + SPH_C32(0x5c90f4ba), SPH_C32(0xa25a7000), SPH_C32(0x6eff1e26), + SPH_C32(0x2ba4846a), SPH_C32(0x2dace49b) }, + { SPH_C32(0xf44c4000), SPH_C32(0x10a4e3cd), SPH_C32(0x097f5711), + SPH_C32(0xde77cc4c), SPH_C32(0x121b4000), SPH_C32(0x5b17d9e8), + SPH_C32(0x8dfacfab), SPH_C32(0xce36cc72) }, + { SPH_C32(0x3fe54000), SPH_C32(0x8083d4a4), SPH_C32(0xb2a3a316), + SPH_C32(0x0e83632d), SPH_C32(0xad275000), SPH_C32(0x911ba8ff), + SPH_C32(0xbedb2687), SPH_C32(0x0024e181) }, + { SPH_C32(0x1d666000), SPH_C32(0xa4f36f31), SPH_C32(0x18856d46), + SPH_C32(0xe3bec968), SPH_C32(0x85484000), SPH_C32(0x7b58b73b), + SPH_C32(0xfa4327a4), SPH_C32(0x6fda92b3) }, + { SPH_C32(0xd6cf6000), SPH_C32(0x34d45858), SPH_C32(0xa3599941), + SPH_C32(0x334a6609), SPH_C32(0x3a745000), SPH_C32(0xb154c62c), + SPH_C32(0xc962ce88), SPH_C32(0xa1c8bf40) }, + { SPH_C32(0x631f4000), SPH_C32(0x30eb8d1e), SPH_C32(0x7ec6bf1e), + SPH_C32(0x7f9b928d), SPH_C32(0x6c626000), SPH_C32(0xcf0f3bc7), + SPH_C32(0xebb91df3), SPH_C32(0x52139797) }, + { SPH_C32(0xa8b64000), SPH_C32(0xa0ccba77), SPH_C32(0xc51a4b19), + SPH_C32(0xaf6f3dec), SPH_C32(0xd35e7000), SPH_C32(0x05034ad0), + SPH_C32(0xd898f4df), SPH_C32(0x9c01ba64) }, + { SPH_C32(0x8a356000), SPH_C32(0x84bc01e2), SPH_C32(0x6f3c8549), + SPH_C32(0x425297a9), SPH_C32(0xfb316000), SPH_C32(0xef405514), + SPH_C32(0x9c00f5fc), SPH_C32(0xf3ffc956) }, + { SPH_C32(0x419c6000), SPH_C32(0x149b368b), SPH_C32(0xd4e0714e), + SPH_C32(0x92a638c8), SPH_C32(0x440d7000), SPH_C32(0x254c2403), + SPH_C32(0xaf211cd0), SPH_C32(0x3dede4a5) }, + { SPH_C32(0xe4788000), SPH_C32(0x859673c1), SPH_C32(0xb5fb2452), + SPH_C32(0x29cc5edf), SPH_C32(0x045f0000), SPH_C32(0x9c4a93c9), + SPH_C32(0x62fc79d0), SPH_C32(0x731ebdc2) }, + { SPH_C32(0x2fd18000), SPH_C32(0x15b144a8), SPH_C32(0x0e27d055), + SPH_C32(0xf938f1be), SPH_C32(0xbb631000), SPH_C32(0x5646e2de), + SPH_C32(0x51dd90fc), SPH_C32(0xbd0c9031) }, + { SPH_C32(0x0d52a000), SPH_C32(0x31c1ff3d), SPH_C32(0xa4011e05), + SPH_C32(0x14055bfb), SPH_C32(0x930c0000), SPH_C32(0xbc05fd1a), + SPH_C32(0x154591df), SPH_C32(0xd2f2e303) }, + { SPH_C32(0xc6fba000), SPH_C32(0xa1e6c854), SPH_C32(0x1fddea02), + SPH_C32(0xc4f1f49a), SPH_C32(0x2c301000), SPH_C32(0x76098c0d), + SPH_C32(0x266478f3), SPH_C32(0x1ce0cef0) }, + { SPH_C32(0x732b8000), SPH_C32(0xa5d91d12), SPH_C32(0xc242cc5d), + SPH_C32(0x8820001e), SPH_C32(0x7a262000), SPH_C32(0x085271e6), + SPH_C32(0x04bfab88), SPH_C32(0xef3be627) }, + { SPH_C32(0xb8828000), SPH_C32(0x35fe2a7b), SPH_C32(0x799e385a), + SPH_C32(0x58d4af7f), SPH_C32(0xc51a3000), SPH_C32(0xc25e00f1), + SPH_C32(0x379e42a4), SPH_C32(0x2129cbd4) }, + { SPH_C32(0x9a01a000), SPH_C32(0x118e91ee), SPH_C32(0xd3b8f60a), + SPH_C32(0xb5e9053a), SPH_C32(0xed752000), SPH_C32(0x281d1f35), + SPH_C32(0x73064387), SPH_C32(0x4ed7b8e6) }, + { SPH_C32(0x51a8a000), SPH_C32(0x81a9a687), SPH_C32(0x6864020d), + SPH_C32(0x651daa5b), SPH_C32(0x52493000), SPH_C32(0xe2116e22), + SPH_C32(0x4027aaab), SPH_C32(0x80c59515) }, + { SPH_C32(0xf663c000), SPH_C32(0xde81aa29), SPH_C32(0x3801ebf9), + SPH_C32(0xe7fa92ad), SPH_C32(0xe2080000), SPH_C32(0xd7f9a9ec), + SPH_C32(0xe679e16a), SPH_C32(0x635fbdfc) }, + { SPH_C32(0x3dcac000), SPH_C32(0x4ea69d40), SPH_C32(0x83dd1ffe), + SPH_C32(0x370e3dcc), SPH_C32(0x5d341000), SPH_C32(0x1df5d8fb), + SPH_C32(0xd5580846), SPH_C32(0xad4d900f) }, + { SPH_C32(0x1f49e000), SPH_C32(0x6ad626d5), SPH_C32(0x29fbd1ae), + SPH_C32(0xda339789), SPH_C32(0x755b0000), SPH_C32(0xf7b6c73f), + SPH_C32(0x91c00965), SPH_C32(0xc2b3e33d) }, + { SPH_C32(0xd4e0e000), SPH_C32(0xfaf111bc), SPH_C32(0x922725a9), + SPH_C32(0x0ac738e8), SPH_C32(0xca671000), SPH_C32(0x3dbab628), + SPH_C32(0xa2e1e049), SPH_C32(0x0ca1cece) }, + { SPH_C32(0x6130c000), SPH_C32(0xfecec4fa), SPH_C32(0x4fb803f6), + SPH_C32(0x4616cc6c), SPH_C32(0x9c712000), SPH_C32(0x43e14bc3), + SPH_C32(0x803a3332), SPH_C32(0xff7ae619) }, + { SPH_C32(0xaa99c000), SPH_C32(0x6ee9f393), SPH_C32(0xf464f7f1), + SPH_C32(0x96e2630d), SPH_C32(0x234d3000), SPH_C32(0x89ed3ad4), + SPH_C32(0xb31bda1e), SPH_C32(0x3168cbea) }, + { SPH_C32(0x881ae000), SPH_C32(0x4a994806), SPH_C32(0x5e4239a1), + SPH_C32(0x7bdfc948), SPH_C32(0x0b222000), SPH_C32(0x63ae2510), + SPH_C32(0xf783db3d), SPH_C32(0x5e96b8d8) }, + { SPH_C32(0x43b3e000), SPH_C32(0xdabe7f6f), SPH_C32(0xe59ecda6), + SPH_C32(0xab2b6629), SPH_C32(0xb41e3000), SPH_C32(0xa9a25407), + SPH_C32(0xc4a23211), SPH_C32(0x9084952b) }, + { SPH_C32(0x022f8000), SPH_C32(0xce2549e4), SPH_C32(0x317ebce8), + SPH_C32(0x398d5ee1), SPH_C32(0xf0134000), SPH_C32(0x8cee7004), + SPH_C32(0x6b832ec1), SPH_C32(0xad69718e) }, + { SPH_C32(0xc9868000), SPH_C32(0x5e027e8d), SPH_C32(0x8aa248ef), + SPH_C32(0xe979f180), SPH_C32(0x4f2f5000), SPH_C32(0x46e20113), + SPH_C32(0x58a2c7ed), SPH_C32(0x637b5c7d) }, + { SPH_C32(0xeb05a000), SPH_C32(0x7a72c518), SPH_C32(0x208486bf), + SPH_C32(0x04445bc5), SPH_C32(0x67404000), SPH_C32(0xaca11ed7), + SPH_C32(0x1c3ac6ce), SPH_C32(0x0c852f4f) }, + { SPH_C32(0x20aca000), SPH_C32(0xea55f271), SPH_C32(0x9b5872b8), + SPH_C32(0xd4b0f4a4), SPH_C32(0xd87c5000), SPH_C32(0x66ad6fc0), + SPH_C32(0x2f1b2fe2), SPH_C32(0xc29702bc) }, + { SPH_C32(0x957c8000), SPH_C32(0xee6a2737), SPH_C32(0x46c754e7), + SPH_C32(0x98610020), SPH_C32(0x8e6a6000), SPH_C32(0x18f6922b), + SPH_C32(0x0dc0fc99), SPH_C32(0x314c2a6b) }, + { SPH_C32(0x5ed58000), SPH_C32(0x7e4d105e), SPH_C32(0xfd1ba0e0), + SPH_C32(0x4895af41), SPH_C32(0x31567000), SPH_C32(0xd2fae33c), + SPH_C32(0x3ee115b5), SPH_C32(0xff5e0798) }, + { SPH_C32(0x7c56a000), SPH_C32(0x5a3dabcb), SPH_C32(0x573d6eb0), + SPH_C32(0xa5a80504), SPH_C32(0x19396000), SPH_C32(0x38b9fcf8), + SPH_C32(0x7a791496), SPH_C32(0x90a074aa) }, + { SPH_C32(0xb7ffa000), SPH_C32(0xca1a9ca2), SPH_C32(0xece19ab7), + SPH_C32(0x755caa65), SPH_C32(0xa6057000), SPH_C32(0xf2b58def), + SPH_C32(0x4958fdba), SPH_C32(0x5eb25959) }, + { SPH_C32(0x1034c000), SPH_C32(0x9532900c), SPH_C32(0xbc847343), + SPH_C32(0xf7bb9293), SPH_C32(0x16444000), SPH_C32(0xc75d4a21), + SPH_C32(0xef06b67b), SPH_C32(0xbd2871b0) }, + { SPH_C32(0xdb9dc000), SPH_C32(0x0515a765), SPH_C32(0x07588744), + SPH_C32(0x274f3df2), SPH_C32(0xa9785000), SPH_C32(0x0d513b36), + SPH_C32(0xdc275f57), SPH_C32(0x733a5c43) }, + { SPH_C32(0xf91ee000), SPH_C32(0x21651cf0), SPH_C32(0xad7e4914), + SPH_C32(0xca7297b7), SPH_C32(0x81174000), SPH_C32(0xe71224f2), + SPH_C32(0x98bf5e74), SPH_C32(0x1cc42f71) }, + { SPH_C32(0x32b7e000), SPH_C32(0xb1422b99), SPH_C32(0x16a2bd13), + SPH_C32(0x1a8638d6), SPH_C32(0x3e2b5000), SPH_C32(0x2d1e55e5), + SPH_C32(0xab9eb758), SPH_C32(0xd2d60282) }, + { SPH_C32(0x8767c000), SPH_C32(0xb57dfedf), SPH_C32(0xcb3d9b4c), + SPH_C32(0x5657cc52), SPH_C32(0x683d6000), SPH_C32(0x5345a80e), + SPH_C32(0x89456423), SPH_C32(0x210d2a55) }, + { SPH_C32(0x4ccec000), SPH_C32(0x255ac9b6), SPH_C32(0x70e16f4b), + SPH_C32(0x86a36333), SPH_C32(0xd7017000), SPH_C32(0x9949d919), + SPH_C32(0xba648d0f), SPH_C32(0xef1f07a6) }, + { SPH_C32(0x6e4de000), SPH_C32(0x012a7223), SPH_C32(0xdac7a11b), + SPH_C32(0x6b9ec976), SPH_C32(0xff6e6000), SPH_C32(0x730ac6dd), + SPH_C32(0xfefc8c2c), SPH_C32(0x80e17494) }, + { SPH_C32(0xa5e4e000), SPH_C32(0x910d454a), SPH_C32(0x611b551c), + SPH_C32(0xbb6a6617), SPH_C32(0x40527000), SPH_C32(0xb906b7ca), + SPH_C32(0xcddd6500), SPH_C32(0x4ef35967) }, + { SPH_C32(0x045f0000), SPH_C32(0x9c4a93c9), SPH_C32(0x62fc79d0), + SPH_C32(0x731ebdc2), SPH_C32(0xe0278000), SPH_C32(0x19dce008), + SPH_C32(0xd7075d82), SPH_C32(0x5ad2e31d) }, + { SPH_C32(0xcff60000), SPH_C32(0x0c6da4a0), SPH_C32(0xd9208dd7), + SPH_C32(0xa3ea12a3), SPH_C32(0x5f1b9000), SPH_C32(0xd3d0911f), + SPH_C32(0xe426b4ae), SPH_C32(0x94c0ceee) }, + { SPH_C32(0xed752000), SPH_C32(0x281d1f35), SPH_C32(0x73064387), + SPH_C32(0x4ed7b8e6), SPH_C32(0x77748000), SPH_C32(0x39938edb), + SPH_C32(0xa0beb58d), SPH_C32(0xfb3ebddc) }, + { SPH_C32(0x26dc2000), SPH_C32(0xb83a285c), SPH_C32(0xc8dab780), + SPH_C32(0x9e231787), SPH_C32(0xc8489000), SPH_C32(0xf39fffcc), + SPH_C32(0x939f5ca1), SPH_C32(0x352c902f) }, + { SPH_C32(0x930c0000), SPH_C32(0xbc05fd1a), SPH_C32(0x154591df), + SPH_C32(0xd2f2e303), SPH_C32(0x9e5ea000), SPH_C32(0x8dc40227), + SPH_C32(0xb1448fda), SPH_C32(0xc6f7b8f8) }, + { SPH_C32(0x58a50000), SPH_C32(0x2c22ca73), SPH_C32(0xae9965d8), + SPH_C32(0x02064c62), SPH_C32(0x2162b000), SPH_C32(0x47c87330), + SPH_C32(0x826566f6), SPH_C32(0x08e5950b) }, + { SPH_C32(0x7a262000), SPH_C32(0x085271e6), SPH_C32(0x04bfab88), + SPH_C32(0xef3be627), SPH_C32(0x090da000), SPH_C32(0xad8b6cf4), + SPH_C32(0xc6fd67d5), SPH_C32(0x671be639) }, + { SPH_C32(0xb18f2000), SPH_C32(0x9875468f), SPH_C32(0xbf635f8f), + SPH_C32(0x3fcf4946), SPH_C32(0xb631b000), SPH_C32(0x67871de3), + SPH_C32(0xf5dc8ef9), SPH_C32(0xa909cbca) }, + { SPH_C32(0x16444000), SPH_C32(0xc75d4a21), SPH_C32(0xef06b67b), + SPH_C32(0xbd2871b0), SPH_C32(0x06708000), SPH_C32(0x526fda2d), + SPH_C32(0x5382c538), SPH_C32(0x4a93e323) }, + { SPH_C32(0xdded4000), SPH_C32(0x577a7d48), SPH_C32(0x54da427c), + SPH_C32(0x6ddcded1), SPH_C32(0xb94c9000), SPH_C32(0x9863ab3a), + SPH_C32(0x60a32c14), SPH_C32(0x8481ced0) }, + { SPH_C32(0xff6e6000), SPH_C32(0x730ac6dd), SPH_C32(0xfefc8c2c), + SPH_C32(0x80e17494), SPH_C32(0x91238000), SPH_C32(0x7220b4fe), + SPH_C32(0x243b2d37), SPH_C32(0xeb7fbde2) }, + { SPH_C32(0x34c76000), SPH_C32(0xe32df1b4), SPH_C32(0x4520782b), + SPH_C32(0x5015dbf5), SPH_C32(0x2e1f9000), SPH_C32(0xb82cc5e9), + SPH_C32(0x171ac41b), SPH_C32(0x256d9011) }, + { SPH_C32(0x81174000), SPH_C32(0xe71224f2), SPH_C32(0x98bf5e74), + SPH_C32(0x1cc42f71), SPH_C32(0x7809a000), SPH_C32(0xc6773802), + SPH_C32(0x35c11760), SPH_C32(0xd6b6b8c6) }, + { SPH_C32(0x4abe4000), SPH_C32(0x7735139b), SPH_C32(0x2363aa73), + SPH_C32(0xcc308010), SPH_C32(0xc735b000), SPH_C32(0x0c7b4915), + SPH_C32(0x06e0fe4c), SPH_C32(0x18a49535) }, + { SPH_C32(0x683d6000), SPH_C32(0x5345a80e), SPH_C32(0x89456423), + SPH_C32(0x210d2a55), SPH_C32(0xef5aa000), SPH_C32(0xe63856d1), + SPH_C32(0x4278ff6f), SPH_C32(0x775ae607) }, + { SPH_C32(0xa3946000), SPH_C32(0xc3629f67), SPH_C32(0x32999024), + SPH_C32(0xf1f98534), SPH_C32(0x5066b000), SPH_C32(0x2c3427c6), + SPH_C32(0x71591643), SPH_C32(0xb948cbf4) }, + { SPH_C32(0xe2080000), SPH_C32(0xd7f9a9ec), SPH_C32(0xe679e16a), + SPH_C32(0x635fbdfc), SPH_C32(0x146bc000), SPH_C32(0x097803c5), + SPH_C32(0xde780a93), SPH_C32(0x84a52f51) }, + { SPH_C32(0x29a10000), SPH_C32(0x47de9e85), SPH_C32(0x5da5156d), + SPH_C32(0xb3ab129d), SPH_C32(0xab57d000), SPH_C32(0xc37472d2), + SPH_C32(0xed59e3bf), SPH_C32(0x4ab702a2) }, + { SPH_C32(0x0b222000), SPH_C32(0x63ae2510), SPH_C32(0xf783db3d), + SPH_C32(0x5e96b8d8), SPH_C32(0x8338c000), SPH_C32(0x29376d16), + SPH_C32(0xa9c1e29c), SPH_C32(0x25497190) }, + { SPH_C32(0xc08b2000), SPH_C32(0xf3891279), SPH_C32(0x4c5f2f3a), + SPH_C32(0x8e6217b9), SPH_C32(0x3c04d000), SPH_C32(0xe33b1c01), + SPH_C32(0x9ae00bb0), SPH_C32(0xeb5b5c63) }, + { SPH_C32(0x755b0000), SPH_C32(0xf7b6c73f), SPH_C32(0x91c00965), + SPH_C32(0xc2b3e33d), SPH_C32(0x6a12e000), SPH_C32(0x9d60e1ea), + SPH_C32(0xb83bd8cb), SPH_C32(0x188074b4) }, + { SPH_C32(0xbef20000), SPH_C32(0x6791f056), SPH_C32(0x2a1cfd62), + SPH_C32(0x12474c5c), SPH_C32(0xd52ef000), SPH_C32(0x576c90fd), + SPH_C32(0x8b1a31e7), SPH_C32(0xd6925947) }, + { SPH_C32(0x9c712000), SPH_C32(0x43e14bc3), SPH_C32(0x803a3332), + SPH_C32(0xff7ae619), SPH_C32(0xfd41e000), SPH_C32(0xbd2f8f39), + SPH_C32(0xcf8230c4), SPH_C32(0xb96c2a75) }, + { SPH_C32(0x57d82000), SPH_C32(0xd3c67caa), SPH_C32(0x3be6c735), + SPH_C32(0x2f8e4978), SPH_C32(0x427df000), SPH_C32(0x7723fe2e), + SPH_C32(0xfca3d9e8), SPH_C32(0x777e0786) }, + { SPH_C32(0xf0134000), SPH_C32(0x8cee7004), SPH_C32(0x6b832ec1), + SPH_C32(0xad69718e), SPH_C32(0xf23cc000), SPH_C32(0x42cb39e0), + SPH_C32(0x5afd9229), SPH_C32(0x94e42f6f) }, + { SPH_C32(0x3bba4000), SPH_C32(0x1cc9476d), SPH_C32(0xd05fdac6), + SPH_C32(0x7d9ddeef), SPH_C32(0x4d00d000), SPH_C32(0x88c748f7), + SPH_C32(0x69dc7b05), SPH_C32(0x5af6029c) }, + { SPH_C32(0x19396000), SPH_C32(0x38b9fcf8), SPH_C32(0x7a791496), + SPH_C32(0x90a074aa), SPH_C32(0x656fc000), SPH_C32(0x62845733), + SPH_C32(0x2d447a26), SPH_C32(0x350871ae) }, + { SPH_C32(0xd2906000), SPH_C32(0xa89ecb91), SPH_C32(0xc1a5e091), + SPH_C32(0x4054dbcb), SPH_C32(0xda53d000), SPH_C32(0xa8882624), + SPH_C32(0x1e65930a), SPH_C32(0xfb1a5c5d) }, + { SPH_C32(0x67404000), SPH_C32(0xaca11ed7), SPH_C32(0x1c3ac6ce), + SPH_C32(0x0c852f4f), SPH_C32(0x8c45e000), SPH_C32(0xd6d3dbcf), + SPH_C32(0x3cbe4071), SPH_C32(0x08c1748a) }, + { SPH_C32(0xace94000), SPH_C32(0x3c8629be), SPH_C32(0xa7e632c9), + SPH_C32(0xdc71802e), SPH_C32(0x3379f000), SPH_C32(0x1cdfaad8), + SPH_C32(0x0f9fa95d), SPH_C32(0xc6d35979) }, + { SPH_C32(0x8e6a6000), SPH_C32(0x18f6922b), SPH_C32(0x0dc0fc99), + SPH_C32(0x314c2a6b), SPH_C32(0x1b16e000), SPH_C32(0xf69cb51c), + SPH_C32(0x4b07a87e), SPH_C32(0xa92d2a4b) }, + { SPH_C32(0x45c36000), SPH_C32(0x88d1a542), SPH_C32(0xb61c089e), + SPH_C32(0xe1b8850a), SPH_C32(0xa42af000), SPH_C32(0x3c90c40b), + SPH_C32(0x78264152), SPH_C32(0x673f07b8) }, + { SPH_C32(0xe0278000), SPH_C32(0x19dce008), SPH_C32(0xd7075d82), + SPH_C32(0x5ad2e31d), SPH_C32(0xe4788000), SPH_C32(0x859673c1), + SPH_C32(0xb5fb2452), SPH_C32(0x29cc5edf) }, + { SPH_C32(0x2b8e8000), SPH_C32(0x89fbd761), SPH_C32(0x6cdba985), + SPH_C32(0x8a264c7c), SPH_C32(0x5b449000), SPH_C32(0x4f9a02d6), + SPH_C32(0x86dacd7e), SPH_C32(0xe7de732c) }, + { SPH_C32(0x090da000), SPH_C32(0xad8b6cf4), SPH_C32(0xc6fd67d5), + SPH_C32(0x671be639), SPH_C32(0x732b8000), SPH_C32(0xa5d91d12), + SPH_C32(0xc242cc5d), SPH_C32(0x8820001e) }, + { SPH_C32(0xc2a4a000), SPH_C32(0x3dac5b9d), SPH_C32(0x7d2193d2), + SPH_C32(0xb7ef4958), SPH_C32(0xcc179000), SPH_C32(0x6fd56c05), + SPH_C32(0xf1632571), SPH_C32(0x46322ded) }, + { SPH_C32(0x77748000), SPH_C32(0x39938edb), SPH_C32(0xa0beb58d), + SPH_C32(0xfb3ebddc), SPH_C32(0x9a01a000), SPH_C32(0x118e91ee), + SPH_C32(0xd3b8f60a), SPH_C32(0xb5e9053a) }, + { SPH_C32(0xbcdd8000), SPH_C32(0xa9b4b9b2), SPH_C32(0x1b62418a), + SPH_C32(0x2bca12bd), SPH_C32(0x253db000), SPH_C32(0xdb82e0f9), + SPH_C32(0xe0991f26), SPH_C32(0x7bfb28c9) }, + { SPH_C32(0x9e5ea000), SPH_C32(0x8dc40227), SPH_C32(0xb1448fda), + SPH_C32(0xc6f7b8f8), SPH_C32(0x0d52a000), SPH_C32(0x31c1ff3d), + SPH_C32(0xa4011e05), SPH_C32(0x14055bfb) }, + { SPH_C32(0x55f7a000), SPH_C32(0x1de3354e), SPH_C32(0x0a987bdd), + SPH_C32(0x16031799), SPH_C32(0xb26eb000), SPH_C32(0xfbcd8e2a), + SPH_C32(0x9720f729), SPH_C32(0xda177608) }, + { SPH_C32(0xf23cc000), SPH_C32(0x42cb39e0), SPH_C32(0x5afd9229), + SPH_C32(0x94e42f6f), SPH_C32(0x022f8000), SPH_C32(0xce2549e4), + SPH_C32(0x317ebce8), SPH_C32(0x398d5ee1) }, + { SPH_C32(0x3995c000), SPH_C32(0xd2ec0e89), SPH_C32(0xe121662e), + SPH_C32(0x4410800e), SPH_C32(0xbd139000), SPH_C32(0x042938f3), + SPH_C32(0x025f55c4), SPH_C32(0xf79f7312) }, + { SPH_C32(0x1b16e000), SPH_C32(0xf69cb51c), SPH_C32(0x4b07a87e), + SPH_C32(0xa92d2a4b), SPH_C32(0x957c8000), SPH_C32(0xee6a2737), + SPH_C32(0x46c754e7), SPH_C32(0x98610020) }, + { SPH_C32(0xd0bfe000), SPH_C32(0x66bb8275), SPH_C32(0xf0db5c79), + SPH_C32(0x79d9852a), SPH_C32(0x2a409000), SPH_C32(0x24665620), + SPH_C32(0x75e6bdcb), SPH_C32(0x56732dd3) }, + { SPH_C32(0x656fc000), SPH_C32(0x62845733), SPH_C32(0x2d447a26), + SPH_C32(0x350871ae), SPH_C32(0x7c56a000), SPH_C32(0x5a3dabcb), + SPH_C32(0x573d6eb0), SPH_C32(0xa5a80504) }, + { SPH_C32(0xaec6c000), SPH_C32(0xf2a3605a), SPH_C32(0x96988e21), + SPH_C32(0xe5fcdecf), SPH_C32(0xc36ab000), SPH_C32(0x9031dadc), + SPH_C32(0x641c879c), SPH_C32(0x6bba28f7) }, + { SPH_C32(0x8c45e000), SPH_C32(0xd6d3dbcf), SPH_C32(0x3cbe4071), + SPH_C32(0x08c1748a), SPH_C32(0xeb05a000), SPH_C32(0x7a72c518), + SPH_C32(0x208486bf), SPH_C32(0x04445bc5) }, + { SPH_C32(0x47ece000), SPH_C32(0x46f4eca6), SPH_C32(0x8762b476), + SPH_C32(0xd835dbeb), SPH_C32(0x5439b000), SPH_C32(0xb07eb40f), + SPH_C32(0x13a56f93), SPH_C32(0xca567636) }, + { SPH_C32(0x06708000), SPH_C32(0x526fda2d), SPH_C32(0x5382c538), + SPH_C32(0x4a93e323), SPH_C32(0x1034c000), SPH_C32(0x9532900c), + SPH_C32(0xbc847343), SPH_C32(0xf7bb9293) }, + { SPH_C32(0xcdd98000), SPH_C32(0xc248ed44), SPH_C32(0xe85e313f), + SPH_C32(0x9a674c42), SPH_C32(0xaf08d000), SPH_C32(0x5f3ee11b), + SPH_C32(0x8fa59a6f), SPH_C32(0x39a9bf60) }, + { SPH_C32(0xef5aa000), SPH_C32(0xe63856d1), SPH_C32(0x4278ff6f), + SPH_C32(0x775ae607), SPH_C32(0x8767c000), SPH_C32(0xb57dfedf), + SPH_C32(0xcb3d9b4c), SPH_C32(0x5657cc52) }, + { SPH_C32(0x24f3a000), SPH_C32(0x761f61b8), SPH_C32(0xf9a40b68), + SPH_C32(0xa7ae4966), SPH_C32(0x385bd000), SPH_C32(0x7f718fc8), + SPH_C32(0xf81c7260), SPH_C32(0x9845e1a1) }, + { SPH_C32(0x91238000), SPH_C32(0x7220b4fe), SPH_C32(0x243b2d37), + SPH_C32(0xeb7fbde2), SPH_C32(0x6e4de000), SPH_C32(0x012a7223), + SPH_C32(0xdac7a11b), SPH_C32(0x6b9ec976) }, + { SPH_C32(0x5a8a8000), SPH_C32(0xe2078397), SPH_C32(0x9fe7d930), + SPH_C32(0x3b8b1283), SPH_C32(0xd171f000), SPH_C32(0xcb260334), + SPH_C32(0xe9e64837), SPH_C32(0xa58ce485) }, + { SPH_C32(0x7809a000), SPH_C32(0xc6773802), SPH_C32(0x35c11760), + SPH_C32(0xd6b6b8c6), SPH_C32(0xf91ee000), SPH_C32(0x21651cf0), + SPH_C32(0xad7e4914), SPH_C32(0xca7297b7) }, + { SPH_C32(0xb3a0a000), SPH_C32(0x56500f6b), SPH_C32(0x8e1de367), + SPH_C32(0x064217a7), SPH_C32(0x4622f000), SPH_C32(0xeb696de7), + SPH_C32(0x9e5fa038), SPH_C32(0x0460ba44) }, + { SPH_C32(0x146bc000), SPH_C32(0x097803c5), SPH_C32(0xde780a93), + SPH_C32(0x84a52f51), SPH_C32(0xf663c000), SPH_C32(0xde81aa29), + SPH_C32(0x3801ebf9), SPH_C32(0xe7fa92ad) }, + { SPH_C32(0xdfc2c000), SPH_C32(0x995f34ac), SPH_C32(0x65a4fe94), + SPH_C32(0x54518030), SPH_C32(0x495fd000), SPH_C32(0x148ddb3e), + SPH_C32(0x0b2002d5), SPH_C32(0x29e8bf5e) }, + { SPH_C32(0xfd41e000), SPH_C32(0xbd2f8f39), SPH_C32(0xcf8230c4), + SPH_C32(0xb96c2a75), SPH_C32(0x6130c000), SPH_C32(0xfecec4fa), + SPH_C32(0x4fb803f6), SPH_C32(0x4616cc6c) }, + { SPH_C32(0x36e8e000), SPH_C32(0x2d08b850), SPH_C32(0x745ec4c3), + SPH_C32(0x69988514), SPH_C32(0xde0cd000), SPH_C32(0x34c2b5ed), + SPH_C32(0x7c99eada), SPH_C32(0x8804e19f) }, + { SPH_C32(0x8338c000), SPH_C32(0x29376d16), SPH_C32(0xa9c1e29c), + SPH_C32(0x25497190), SPH_C32(0x881ae000), SPH_C32(0x4a994806), + SPH_C32(0x5e4239a1), SPH_C32(0x7bdfc948) }, + { SPH_C32(0x4891c000), SPH_C32(0xb9105a7f), SPH_C32(0x121d169b), + SPH_C32(0xf5bddef1), SPH_C32(0x3726f000), SPH_C32(0x80953911), + SPH_C32(0x6d63d08d), SPH_C32(0xb5cde4bb) }, + { SPH_C32(0x6a12e000), SPH_C32(0x9d60e1ea), SPH_C32(0xb83bd8cb), + SPH_C32(0x188074b4), SPH_C32(0x1f49e000), SPH_C32(0x6ad626d5), + SPH_C32(0x29fbd1ae), SPH_C32(0xda339789) }, + { SPH_C32(0xa1bbe000), SPH_C32(0x0d47d683), SPH_C32(0x03e72ccc), + SPH_C32(0xc874dbd5), SPH_C32(0xa075f000), SPH_C32(0xa0da57c2), + SPH_C32(0x1ada3882), SPH_C32(0x1421ba7a) } +}; + +static const sph_u32 T256_7[128][8] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000) }, + { SPH_C32(0xa7b80200), SPH_C32(0x1f128433), SPH_C32(0x60e5f9f2), + SPH_C32(0x9e147576), SPH_C32(0xee260000), SPH_C32(0x124b683e), + SPH_C32(0x80c2d68f), SPH_C32(0x3bf3ab2c) }, + { SPH_C32(0xee260000), SPH_C32(0x124b683e), SPH_C32(0x80c2d68f), + SPH_C32(0x3bf3ab2c), SPH_C32(0x499e0200), SPH_C32(0x0d59ec0d), + SPH_C32(0xe0272f7d), SPH_C32(0xa5e7de5a) }, + { SPH_C32(0x499e0200), SPH_C32(0x0d59ec0d), SPH_C32(0xe0272f7d), + SPH_C32(0xa5e7de5a), SPH_C32(0xa7b80200), SPH_C32(0x1f128433), + SPH_C32(0x60e5f9f2), SPH_C32(0x9e147576) }, + { SPH_C32(0x8f3e0400), SPH_C32(0x0d9dc877), SPH_C32(0x6fc548e1), + SPH_C32(0x898d2cd6), SPH_C32(0x14bd0000), SPH_C32(0x2fba37ff), + SPH_C32(0x6a72e5bb), SPH_C32(0x247febe6) }, + { SPH_C32(0x28860600), SPH_C32(0x128f4c44), SPH_C32(0x0f20b113), + SPH_C32(0x179959a0), SPH_C32(0xfa9b0000), SPH_C32(0x3df15fc1), + SPH_C32(0xeab03334), SPH_C32(0x1f8c40ca) }, + { SPH_C32(0x61180400), SPH_C32(0x1fd6a049), SPH_C32(0xef079e6e), + SPH_C32(0xb27e87fa), SPH_C32(0x5d230200), SPH_C32(0x22e3dbf2), + SPH_C32(0x8a55cac6), SPH_C32(0x819835bc) }, + { SPH_C32(0xc6a00600), SPH_C32(0x00c4247a), SPH_C32(0x8fe2679c), + SPH_C32(0x2c6af28c), SPH_C32(0xb3050200), SPH_C32(0x30a8b3cc), + SPH_C32(0x0a971c49), SPH_C32(0xba6b9e90) }, + { SPH_C32(0x14bd0000), SPH_C32(0x2fba37ff), SPH_C32(0x6a72e5bb), + SPH_C32(0x247febe6), SPH_C32(0x9b830400), SPH_C32(0x2227ff88), + SPH_C32(0x05b7ad5a), SPH_C32(0xadf2c730) }, + { SPH_C32(0xb3050200), SPH_C32(0x30a8b3cc), SPH_C32(0x0a971c49), + SPH_C32(0xba6b9e90), SPH_C32(0x75a50400), SPH_C32(0x306c97b6), + SPH_C32(0x85757bd5), SPH_C32(0x96016c1c) }, + { SPH_C32(0xfa9b0000), SPH_C32(0x3df15fc1), SPH_C32(0xeab03334), + SPH_C32(0x1f8c40ca), SPH_C32(0xd21d0600), SPH_C32(0x2f7e1385), + SPH_C32(0xe5908227), SPH_C32(0x0815196a) }, + { SPH_C32(0x5d230200), SPH_C32(0x22e3dbf2), SPH_C32(0x8a55cac6), + SPH_C32(0x819835bc), SPH_C32(0x3c3b0600), SPH_C32(0x3d357bbb), + SPH_C32(0x655254a8), SPH_C32(0x33e6b246) }, + { SPH_C32(0x9b830400), SPH_C32(0x2227ff88), SPH_C32(0x05b7ad5a), + SPH_C32(0xadf2c730), SPH_C32(0x8f3e0400), SPH_C32(0x0d9dc877), + SPH_C32(0x6fc548e1), SPH_C32(0x898d2cd6) }, + { SPH_C32(0x3c3b0600), SPH_C32(0x3d357bbb), SPH_C32(0x655254a8), + SPH_C32(0x33e6b246), SPH_C32(0x61180400), SPH_C32(0x1fd6a049), + SPH_C32(0xef079e6e), SPH_C32(0xb27e87fa) }, + { SPH_C32(0x75a50400), SPH_C32(0x306c97b6), SPH_C32(0x85757bd5), + SPH_C32(0x96016c1c), SPH_C32(0xc6a00600), SPH_C32(0x00c4247a), + SPH_C32(0x8fe2679c), SPH_C32(0x2c6af28c) }, + { SPH_C32(0xd21d0600), SPH_C32(0x2f7e1385), SPH_C32(0xe5908227), + SPH_C32(0x0815196a), SPH_C32(0x28860600), SPH_C32(0x128f4c44), + SPH_C32(0x0f20b113), SPH_C32(0x179959a0) }, + { SPH_C32(0xde320800), SPH_C32(0x288350fe), SPH_C32(0x71852ac7), + SPH_C32(0xa6bf9f96), SPH_C32(0xe18b0000), SPH_C32(0x5459887d), + SPH_C32(0xbf1283d3), SPH_C32(0x1b666a73) }, + { SPH_C32(0x798a0a00), SPH_C32(0x3791d4cd), SPH_C32(0x1160d335), + SPH_C32(0x38abeae0), SPH_C32(0x0fad0000), SPH_C32(0x4612e043), + SPH_C32(0x3fd0555c), SPH_C32(0x2095c15f) }, + { SPH_C32(0x30140800), SPH_C32(0x3ac838c0), SPH_C32(0xf147fc48), + SPH_C32(0x9d4c34ba), SPH_C32(0xa8150200), SPH_C32(0x59006470), + SPH_C32(0x5f35acae), SPH_C32(0xbe81b429) }, + { SPH_C32(0x97ac0a00), SPH_C32(0x25dabcf3), SPH_C32(0x91a205ba), + SPH_C32(0x035841cc), SPH_C32(0x46330200), SPH_C32(0x4b4b0c4e), + SPH_C32(0xdff77a21), SPH_C32(0x85721f05) }, + { SPH_C32(0x510c0c00), SPH_C32(0x251e9889), SPH_C32(0x1e406226), + SPH_C32(0x2f32b340), SPH_C32(0xf5360000), SPH_C32(0x7be3bf82), + SPH_C32(0xd5606668), SPH_C32(0x3f198195) }, + { SPH_C32(0xf6b40e00), SPH_C32(0x3a0c1cba), SPH_C32(0x7ea59bd4), + SPH_C32(0xb126c636), SPH_C32(0x1b100000), SPH_C32(0x69a8d7bc), + SPH_C32(0x55a2b0e7), SPH_C32(0x04ea2ab9) }, + { SPH_C32(0xbf2a0c00), SPH_C32(0x3755f0b7), SPH_C32(0x9e82b4a9), + SPH_C32(0x14c1186c), SPH_C32(0xbca80200), SPH_C32(0x76ba538f), + SPH_C32(0x35474915), SPH_C32(0x9afe5fcf) }, + { SPH_C32(0x18920e00), SPH_C32(0x28477484), SPH_C32(0xfe674d5b), + SPH_C32(0x8ad56d1a), SPH_C32(0x528e0200), SPH_C32(0x64f13bb1), + SPH_C32(0xb5859f9a), SPH_C32(0xa10df4e3) }, + { SPH_C32(0xca8f0800), SPH_C32(0x07396701), SPH_C32(0x1bf7cf7c), + SPH_C32(0x82c07470), SPH_C32(0x7a080400), SPH_C32(0x767e77f5), + SPH_C32(0xbaa52e89), SPH_C32(0xb694ad43) }, + { SPH_C32(0x6d370a00), SPH_C32(0x182be332), SPH_C32(0x7b12368e), + SPH_C32(0x1cd40106), SPH_C32(0x942e0400), SPH_C32(0x64351fcb), + SPH_C32(0x3a67f806), SPH_C32(0x8d67066f) }, + { SPH_C32(0x24a90800), SPH_C32(0x15720f3f), SPH_C32(0x9b3519f3), + SPH_C32(0xb933df5c), SPH_C32(0x33960600), SPH_C32(0x7b279bf8), + SPH_C32(0x5a8201f4), SPH_C32(0x13737319) }, + { SPH_C32(0x83110a00), SPH_C32(0x0a608b0c), SPH_C32(0xfbd0e001), + SPH_C32(0x2727aa2a), SPH_C32(0xddb00600), SPH_C32(0x696cf3c6), + SPH_C32(0xda40d77b), SPH_C32(0x2880d835) }, + { SPH_C32(0x45b10c00), SPH_C32(0x0aa4af76), SPH_C32(0x7432879d), + SPH_C32(0x0b4d58a6), SPH_C32(0x6eb50400), SPH_C32(0x59c4400a), + SPH_C32(0xd0d7cb32), SPH_C32(0x92eb46a5) }, + { SPH_C32(0xe2090e00), SPH_C32(0x15b62b45), SPH_C32(0x14d77e6f), + SPH_C32(0x95592dd0), SPH_C32(0x80930400), SPH_C32(0x4b8f2834), + SPH_C32(0x50151dbd), SPH_C32(0xa918ed89) }, + { SPH_C32(0xab970c00), SPH_C32(0x18efc748), SPH_C32(0xf4f05112), + SPH_C32(0x30bef38a), SPH_C32(0x272b0600), SPH_C32(0x549dac07), + SPH_C32(0x30f0e44f), SPH_C32(0x370c98ff) }, + { SPH_C32(0x0c2f0e00), SPH_C32(0x07fd437b), SPH_C32(0x9415a8e0), + SPH_C32(0xaeaa86fc), SPH_C32(0xc90d0600), SPH_C32(0x46d6c439), + SPH_C32(0xb03232c0), SPH_C32(0x0cff33d3) }, + { SPH_C32(0xe18b0000), SPH_C32(0x5459887d), SPH_C32(0xbf1283d3), + SPH_C32(0x1b666a73), SPH_C32(0x3fb90800), SPH_C32(0x7cdad883), + SPH_C32(0xce97a914), SPH_C32(0xbdd9f5e5) }, + { SPH_C32(0x46330200), SPH_C32(0x4b4b0c4e), SPH_C32(0xdff77a21), + SPH_C32(0x85721f05), SPH_C32(0xd19f0800), SPH_C32(0x6e91b0bd), + SPH_C32(0x4e557f9b), SPH_C32(0x862a5ec9) }, + { SPH_C32(0x0fad0000), SPH_C32(0x4612e043), SPH_C32(0x3fd0555c), + SPH_C32(0x2095c15f), SPH_C32(0x76270a00), SPH_C32(0x7183348e), + SPH_C32(0x2eb08669), SPH_C32(0x183e2bbf) }, + { SPH_C32(0xa8150200), SPH_C32(0x59006470), SPH_C32(0x5f35acae), + SPH_C32(0xbe81b429), SPH_C32(0x98010a00), SPH_C32(0x63c85cb0), + SPH_C32(0xae7250e6), SPH_C32(0x23cd8093) }, + { SPH_C32(0x6eb50400), SPH_C32(0x59c4400a), SPH_C32(0xd0d7cb32), + SPH_C32(0x92eb46a5), SPH_C32(0x2b040800), SPH_C32(0x5360ef7c), + SPH_C32(0xa4e54caf), SPH_C32(0x99a61e03) }, + { SPH_C32(0xc90d0600), SPH_C32(0x46d6c439), SPH_C32(0xb03232c0), + SPH_C32(0x0cff33d3), SPH_C32(0xc5220800), SPH_C32(0x412b8742), + SPH_C32(0x24279a20), SPH_C32(0xa255b52f) }, + { SPH_C32(0x80930400), SPH_C32(0x4b8f2834), SPH_C32(0x50151dbd), + SPH_C32(0xa918ed89), SPH_C32(0x629a0a00), SPH_C32(0x5e390371), + SPH_C32(0x44c263d2), SPH_C32(0x3c41c059) }, + { SPH_C32(0x272b0600), SPH_C32(0x549dac07), SPH_C32(0x30f0e44f), + SPH_C32(0x370c98ff), SPH_C32(0x8cbc0a00), SPH_C32(0x4c726b4f), + SPH_C32(0xc400b55d), SPH_C32(0x07b26b75) }, + { SPH_C32(0xf5360000), SPH_C32(0x7be3bf82), SPH_C32(0xd5606668), + SPH_C32(0x3f198195), SPH_C32(0xa43a0c00), SPH_C32(0x5efd270b), + SPH_C32(0xcb20044e), SPH_C32(0x102b32d5) }, + { SPH_C32(0x528e0200), SPH_C32(0x64f13bb1), SPH_C32(0xb5859f9a), + SPH_C32(0xa10df4e3), SPH_C32(0x4a1c0c00), SPH_C32(0x4cb64f35), + SPH_C32(0x4be2d2c1), SPH_C32(0x2bd899f9) }, + { SPH_C32(0x1b100000), SPH_C32(0x69a8d7bc), SPH_C32(0x55a2b0e7), + SPH_C32(0x04ea2ab9), SPH_C32(0xeda40e00), SPH_C32(0x53a4cb06), + SPH_C32(0x2b072b33), SPH_C32(0xb5ccec8f) }, + { SPH_C32(0xbca80200), SPH_C32(0x76ba538f), SPH_C32(0x35474915), + SPH_C32(0x9afe5fcf), SPH_C32(0x03820e00), SPH_C32(0x41efa338), + SPH_C32(0xabc5fdbc), SPH_C32(0x8e3f47a3) }, + { SPH_C32(0x7a080400), SPH_C32(0x767e77f5), SPH_C32(0xbaa52e89), + SPH_C32(0xb694ad43), SPH_C32(0xb0870c00), SPH_C32(0x714710f4), + SPH_C32(0xa152e1f5), SPH_C32(0x3454d933) }, + { SPH_C32(0xddb00600), SPH_C32(0x696cf3c6), SPH_C32(0xda40d77b), + SPH_C32(0x2880d835), SPH_C32(0x5ea10c00), SPH_C32(0x630c78ca), + SPH_C32(0x2190377a), SPH_C32(0x0fa7721f) }, + { SPH_C32(0x942e0400), SPH_C32(0x64351fcb), SPH_C32(0x3a67f806), + SPH_C32(0x8d67066f), SPH_C32(0xf9190e00), SPH_C32(0x7c1efcf9), + SPH_C32(0x4175ce88), SPH_C32(0x91b30769) }, + { SPH_C32(0x33960600), SPH_C32(0x7b279bf8), SPH_C32(0x5a8201f4), + SPH_C32(0x13737319), SPH_C32(0x173f0e00), SPH_C32(0x6e5594c7), + SPH_C32(0xc1b71807), SPH_C32(0xaa40ac45) }, + { SPH_C32(0x3fb90800), SPH_C32(0x7cdad883), SPH_C32(0xce97a914), + SPH_C32(0xbdd9f5e5), SPH_C32(0xde320800), SPH_C32(0x288350fe), + SPH_C32(0x71852ac7), SPH_C32(0xa6bf9f96) }, + { SPH_C32(0x98010a00), SPH_C32(0x63c85cb0), SPH_C32(0xae7250e6), + SPH_C32(0x23cd8093), SPH_C32(0x30140800), SPH_C32(0x3ac838c0), + SPH_C32(0xf147fc48), SPH_C32(0x9d4c34ba) }, + { SPH_C32(0xd19f0800), SPH_C32(0x6e91b0bd), SPH_C32(0x4e557f9b), + SPH_C32(0x862a5ec9), SPH_C32(0x97ac0a00), SPH_C32(0x25dabcf3), + SPH_C32(0x91a205ba), SPH_C32(0x035841cc) }, + { SPH_C32(0x76270a00), SPH_C32(0x7183348e), SPH_C32(0x2eb08669), + SPH_C32(0x183e2bbf), SPH_C32(0x798a0a00), SPH_C32(0x3791d4cd), + SPH_C32(0x1160d335), SPH_C32(0x38abeae0) }, + { SPH_C32(0xb0870c00), SPH_C32(0x714710f4), SPH_C32(0xa152e1f5), + SPH_C32(0x3454d933), SPH_C32(0xca8f0800), SPH_C32(0x07396701), + SPH_C32(0x1bf7cf7c), SPH_C32(0x82c07470) }, + { SPH_C32(0x173f0e00), SPH_C32(0x6e5594c7), SPH_C32(0xc1b71807), + SPH_C32(0xaa40ac45), SPH_C32(0x24a90800), SPH_C32(0x15720f3f), + SPH_C32(0x9b3519f3), SPH_C32(0xb933df5c) }, + { SPH_C32(0x5ea10c00), SPH_C32(0x630c78ca), SPH_C32(0x2190377a), + SPH_C32(0x0fa7721f), SPH_C32(0x83110a00), SPH_C32(0x0a608b0c), + SPH_C32(0xfbd0e001), SPH_C32(0x2727aa2a) }, + { SPH_C32(0xf9190e00), SPH_C32(0x7c1efcf9), SPH_C32(0x4175ce88), + SPH_C32(0x91b30769), SPH_C32(0x6d370a00), SPH_C32(0x182be332), + SPH_C32(0x7b12368e), SPH_C32(0x1cd40106) }, + { SPH_C32(0x2b040800), SPH_C32(0x5360ef7c), SPH_C32(0xa4e54caf), + SPH_C32(0x99a61e03), SPH_C32(0x45b10c00), SPH_C32(0x0aa4af76), + SPH_C32(0x7432879d), SPH_C32(0x0b4d58a6) }, + { SPH_C32(0x8cbc0a00), SPH_C32(0x4c726b4f), SPH_C32(0xc400b55d), + SPH_C32(0x07b26b75), SPH_C32(0xab970c00), SPH_C32(0x18efc748), + SPH_C32(0xf4f05112), SPH_C32(0x30bef38a) }, + { SPH_C32(0xc5220800), SPH_C32(0x412b8742), SPH_C32(0x24279a20), + SPH_C32(0xa255b52f), SPH_C32(0x0c2f0e00), SPH_C32(0x07fd437b), + SPH_C32(0x9415a8e0), SPH_C32(0xaeaa86fc) }, + { SPH_C32(0x629a0a00), SPH_C32(0x5e390371), SPH_C32(0x44c263d2), + SPH_C32(0x3c41c059), SPH_C32(0xe2090e00), SPH_C32(0x15b62b45), + SPH_C32(0x14d77e6f), SPH_C32(0x95592dd0) }, + { SPH_C32(0xa43a0c00), SPH_C32(0x5efd270b), SPH_C32(0xcb20044e), + SPH_C32(0x102b32d5), SPH_C32(0x510c0c00), SPH_C32(0x251e9889), + SPH_C32(0x1e406226), SPH_C32(0x2f32b340) }, + { SPH_C32(0x03820e00), SPH_C32(0x41efa338), SPH_C32(0xabc5fdbc), + SPH_C32(0x8e3f47a3), SPH_C32(0xbf2a0c00), SPH_C32(0x3755f0b7), + SPH_C32(0x9e82b4a9), SPH_C32(0x14c1186c) }, + { SPH_C32(0x4a1c0c00), SPH_C32(0x4cb64f35), SPH_C32(0x4be2d2c1), + SPH_C32(0x2bd899f9), SPH_C32(0x18920e00), SPH_C32(0x28477484), + SPH_C32(0xfe674d5b), SPH_C32(0x8ad56d1a) }, + { SPH_C32(0xeda40e00), SPH_C32(0x53a4cb06), SPH_C32(0x2b072b33), + SPH_C32(0xb5ccec8f), SPH_C32(0xf6b40e00), SPH_C32(0x3a0c1cba), + SPH_C32(0x7ea59bd4), SPH_C32(0xb126c636) }, + { SPH_C32(0x74951000), SPH_C32(0x5a2b467e), SPH_C32(0x88fd1d2b), + SPH_C32(0x1ee68292), SPH_C32(0xcba90000), SPH_C32(0x90273769), + SPH_C32(0xbbdcf407), SPH_C32(0xd0f4af61) }, + { SPH_C32(0xd32d1200), SPH_C32(0x4539c24d), SPH_C32(0xe818e4d9), + SPH_C32(0x80f2f7e4), SPH_C32(0x258f0000), SPH_C32(0x826c5f57), + SPH_C32(0x3b1e2288), SPH_C32(0xeb07044d) }, + { SPH_C32(0x9ab31000), SPH_C32(0x48602e40), SPH_C32(0x083fcba4), + SPH_C32(0x251529be), SPH_C32(0x82370200), SPH_C32(0x9d7edb64), + SPH_C32(0x5bfbdb7a), SPH_C32(0x7513713b) }, + { SPH_C32(0x3d0b1200), SPH_C32(0x5772aa73), SPH_C32(0x68da3256), + SPH_C32(0xbb015cc8), SPH_C32(0x6c110200), SPH_C32(0x8f35b35a), + SPH_C32(0xdb390df5), SPH_C32(0x4ee0da17) }, + { SPH_C32(0xfbab1400), SPH_C32(0x57b68e09), SPH_C32(0xe73855ca), + SPH_C32(0x976bae44), SPH_C32(0xdf140000), SPH_C32(0xbf9d0096), + SPH_C32(0xd1ae11bc), SPH_C32(0xf48b4487) }, + { SPH_C32(0x5c131600), SPH_C32(0x48a40a3a), SPH_C32(0x87ddac38), + SPH_C32(0x097fdb32), SPH_C32(0x31320000), SPH_C32(0xadd668a8), + SPH_C32(0x516cc733), SPH_C32(0xcf78efab) }, + { SPH_C32(0x158d1400), SPH_C32(0x45fde637), SPH_C32(0x67fa8345), + SPH_C32(0xac980568), SPH_C32(0x968a0200), SPH_C32(0xb2c4ec9b), + SPH_C32(0x31893ec1), SPH_C32(0x516c9add) }, + { SPH_C32(0xb2351600), SPH_C32(0x5aef6204), SPH_C32(0x071f7ab7), + SPH_C32(0x328c701e), SPH_C32(0x78ac0200), SPH_C32(0xa08f84a5), + SPH_C32(0xb14be84e), SPH_C32(0x6a9f31f1) }, + { SPH_C32(0x60281000), SPH_C32(0x75917181), SPH_C32(0xe28ff890), + SPH_C32(0x3a996974), SPH_C32(0x502a0400), SPH_C32(0xb200c8e1), + SPH_C32(0xbe6b595d), SPH_C32(0x7d066851) }, + { SPH_C32(0xc7901200), SPH_C32(0x6a83f5b2), SPH_C32(0x826a0162), + SPH_C32(0xa48d1c02), SPH_C32(0xbe0c0400), SPH_C32(0xa04ba0df), + SPH_C32(0x3ea98fd2), SPH_C32(0x46f5c37d) }, + { SPH_C32(0x8e0e1000), SPH_C32(0x67da19bf), SPH_C32(0x624d2e1f), + SPH_C32(0x016ac258), SPH_C32(0x19b40600), SPH_C32(0xbf5924ec), + SPH_C32(0x5e4c7620), SPH_C32(0xd8e1b60b) }, + { SPH_C32(0x29b61200), SPH_C32(0x78c89d8c), SPH_C32(0x02a8d7ed), + SPH_C32(0x9f7eb72e), SPH_C32(0xf7920600), SPH_C32(0xad124cd2), + SPH_C32(0xde8ea0af), SPH_C32(0xe3121d27) }, + { SPH_C32(0xef161400), SPH_C32(0x780cb9f6), SPH_C32(0x8d4ab071), + SPH_C32(0xb31445a2), SPH_C32(0x44970400), SPH_C32(0x9dbaff1e), + SPH_C32(0xd419bce6), SPH_C32(0x597983b7) }, + { SPH_C32(0x48ae1600), SPH_C32(0x671e3dc5), SPH_C32(0xedaf4983), + SPH_C32(0x2d0030d4), SPH_C32(0xaab10400), SPH_C32(0x8ff19720), + SPH_C32(0x54db6a69), SPH_C32(0x628a289b) }, + { SPH_C32(0x01301400), SPH_C32(0x6a47d1c8), SPH_C32(0x0d8866fe), + SPH_C32(0x88e7ee8e), SPH_C32(0x0d090600), SPH_C32(0x90e31313), + SPH_C32(0x343e939b), SPH_C32(0xfc9e5ded) }, + { SPH_C32(0xa6881600), SPH_C32(0x755555fb), SPH_C32(0x6d6d9f0c), + SPH_C32(0x16f39bf8), SPH_C32(0xe32f0600), SPH_C32(0x82a87b2d), + SPH_C32(0xb4fc4514), SPH_C32(0xc76df6c1) }, + { SPH_C32(0xaaa71800), SPH_C32(0x72a81680), SPH_C32(0xf97837ec), + SPH_C32(0xb8591d04), SPH_C32(0x2a220000), SPH_C32(0xc47ebf14), + SPH_C32(0x04ce77d4), SPH_C32(0xcb92c512) }, + { SPH_C32(0x0d1f1a00), SPH_C32(0x6dba92b3), SPH_C32(0x999dce1e), + SPH_C32(0x264d6872), SPH_C32(0xc4040000), SPH_C32(0xd635d72a), + SPH_C32(0x840ca15b), SPH_C32(0xf0616e3e) }, + { SPH_C32(0x44811800), SPH_C32(0x60e37ebe), SPH_C32(0x79bae163), + SPH_C32(0x83aab628), SPH_C32(0x63bc0200), SPH_C32(0xc9275319), + SPH_C32(0xe4e958a9), SPH_C32(0x6e751b48) }, + { SPH_C32(0xe3391a00), SPH_C32(0x7ff1fa8d), SPH_C32(0x195f1891), + SPH_C32(0x1dbec35e), SPH_C32(0x8d9a0200), SPH_C32(0xdb6c3b27), + SPH_C32(0x642b8e26), SPH_C32(0x5586b064) }, + { SPH_C32(0x25991c00), SPH_C32(0x7f35def7), SPH_C32(0x96bd7f0d), + SPH_C32(0x31d431d2), SPH_C32(0x3e9f0000), SPH_C32(0xebc488eb), + SPH_C32(0x6ebc926f), SPH_C32(0xefed2ef4) }, + { SPH_C32(0x82211e00), SPH_C32(0x60275ac4), SPH_C32(0xf65886ff), + SPH_C32(0xafc044a4), SPH_C32(0xd0b90000), SPH_C32(0xf98fe0d5), + SPH_C32(0xee7e44e0), SPH_C32(0xd41e85d8) }, + { SPH_C32(0xcbbf1c00), SPH_C32(0x6d7eb6c9), SPH_C32(0x167fa982), + SPH_C32(0x0a279afe), SPH_C32(0x77010200), SPH_C32(0xe69d64e6), + SPH_C32(0x8e9bbd12), SPH_C32(0x4a0af0ae) }, + { SPH_C32(0x6c071e00), SPH_C32(0x726c32fa), SPH_C32(0x769a5070), + SPH_C32(0x9433ef88), SPH_C32(0x99270200), SPH_C32(0xf4d60cd8), + SPH_C32(0x0e596b9d), SPH_C32(0x71f95b82) }, + { SPH_C32(0xbe1a1800), SPH_C32(0x5d12217f), SPH_C32(0x930ad257), + SPH_C32(0x9c26f6e2), SPH_C32(0xb1a10400), SPH_C32(0xe659409c), + SPH_C32(0x0179da8e), SPH_C32(0x66600222) }, + { SPH_C32(0x19a21a00), SPH_C32(0x4200a54c), SPH_C32(0xf3ef2ba5), + SPH_C32(0x02328394), SPH_C32(0x5f870400), SPH_C32(0xf41228a2), + SPH_C32(0x81bb0c01), SPH_C32(0x5d93a90e) }, + { SPH_C32(0x503c1800), SPH_C32(0x4f594941), SPH_C32(0x13c804d8), + SPH_C32(0xa7d55dce), SPH_C32(0xf83f0600), SPH_C32(0xeb00ac91), + SPH_C32(0xe15ef5f3), SPH_C32(0xc387dc78) }, + { SPH_C32(0xf7841a00), SPH_C32(0x504bcd72), SPH_C32(0x732dfd2a), + SPH_C32(0x39c128b8), SPH_C32(0x16190600), SPH_C32(0xf94bc4af), + SPH_C32(0x619c237c), SPH_C32(0xf8747754) }, + { SPH_C32(0x31241c00), SPH_C32(0x508fe908), SPH_C32(0xfccf9ab6), + SPH_C32(0x15abda34), SPH_C32(0xa51c0400), SPH_C32(0xc9e37763), + SPH_C32(0x6b0b3f35), SPH_C32(0x421fe9c4) }, + { SPH_C32(0x969c1e00), SPH_C32(0x4f9d6d3b), SPH_C32(0x9c2a6344), + SPH_C32(0x8bbfaf42), SPH_C32(0x4b3a0400), SPH_C32(0xdba81f5d), + SPH_C32(0xebc9e9ba), SPH_C32(0x79ec42e8) }, + { SPH_C32(0xdf021c00), SPH_C32(0x42c48136), SPH_C32(0x7c0d4c39), + SPH_C32(0x2e587118), SPH_C32(0xec820600), SPH_C32(0xc4ba9b6e), + SPH_C32(0x8b2c1048), SPH_C32(0xe7f8379e) }, + { SPH_C32(0x78ba1e00), SPH_C32(0x5dd60505), SPH_C32(0x1ce8b5cb), + SPH_C32(0xb04c046e), SPH_C32(0x02a40600), SPH_C32(0xd6f1f350), + SPH_C32(0x0beec6c7), SPH_C32(0xdc0b9cb2) }, + { SPH_C32(0x951e1000), SPH_C32(0x0e72ce03), SPH_C32(0x37ef9ef8), + SPH_C32(0x0580e8e1), SPH_C32(0xf4100800), SPH_C32(0xecfdefea), + SPH_C32(0x754b5d13), SPH_C32(0x6d2d5a84) }, + { SPH_C32(0x32a61200), SPH_C32(0x11604a30), SPH_C32(0x570a670a), + SPH_C32(0x9b949d97), SPH_C32(0x1a360800), SPH_C32(0xfeb687d4), + SPH_C32(0xf5898b9c), SPH_C32(0x56def1a8) }, + { SPH_C32(0x7b381000), SPH_C32(0x1c39a63d), SPH_C32(0xb72d4877), + SPH_C32(0x3e7343cd), SPH_C32(0xbd8e0a00), SPH_C32(0xe1a403e7), + SPH_C32(0x956c726e), SPH_C32(0xc8ca84de) }, + { SPH_C32(0xdc801200), SPH_C32(0x032b220e), SPH_C32(0xd7c8b185), + SPH_C32(0xa06736bb), SPH_C32(0x53a80a00), SPH_C32(0xf3ef6bd9), + SPH_C32(0x15aea4e1), SPH_C32(0xf3392ff2) }, + { SPH_C32(0x1a201400), SPH_C32(0x03ef0674), SPH_C32(0x582ad619), + SPH_C32(0x8c0dc437), SPH_C32(0xe0ad0800), SPH_C32(0xc347d815), + SPH_C32(0x1f39b8a8), SPH_C32(0x4952b162) }, + { SPH_C32(0xbd981600), SPH_C32(0x1cfd8247), SPH_C32(0x38cf2feb), + SPH_C32(0x1219b141), SPH_C32(0x0e8b0800), SPH_C32(0xd10cb02b), + SPH_C32(0x9ffb6e27), SPH_C32(0x72a11a4e) }, + { SPH_C32(0xf4061400), SPH_C32(0x11a46e4a), SPH_C32(0xd8e80096), + SPH_C32(0xb7fe6f1b), SPH_C32(0xa9330a00), SPH_C32(0xce1e3418), + SPH_C32(0xff1e97d5), SPH_C32(0xecb56f38) }, + { SPH_C32(0x53be1600), SPH_C32(0x0eb6ea79), SPH_C32(0xb80df964), + SPH_C32(0x29ea1a6d), SPH_C32(0x47150a00), SPH_C32(0xdc555c26), + SPH_C32(0x7fdc415a), SPH_C32(0xd746c414) }, + { SPH_C32(0x81a31000), SPH_C32(0x21c8f9fc), SPH_C32(0x5d9d7b43), + SPH_C32(0x21ff0307), SPH_C32(0x6f930c00), SPH_C32(0xceda1062), + SPH_C32(0x70fcf049), SPH_C32(0xc0df9db4) }, + { SPH_C32(0x261b1200), SPH_C32(0x3eda7dcf), SPH_C32(0x3d7882b1), + SPH_C32(0xbfeb7671), SPH_C32(0x81b50c00), SPH_C32(0xdc91785c), + SPH_C32(0xf03e26c6), SPH_C32(0xfb2c3698) }, + { SPH_C32(0x6f851000), SPH_C32(0x338391c2), SPH_C32(0xdd5fadcc), + SPH_C32(0x1a0ca82b), SPH_C32(0x260d0e00), SPH_C32(0xc383fc6f), + SPH_C32(0x90dbdf34), SPH_C32(0x653843ee) }, + { SPH_C32(0xc83d1200), SPH_C32(0x2c9115f1), SPH_C32(0xbdba543e), + SPH_C32(0x8418dd5d), SPH_C32(0xc82b0e00), SPH_C32(0xd1c89451), + SPH_C32(0x101909bb), SPH_C32(0x5ecbe8c2) }, + { SPH_C32(0x0e9d1400), SPH_C32(0x2c55318b), SPH_C32(0x325833a2), + SPH_C32(0xa8722fd1), SPH_C32(0x7b2e0c00), SPH_C32(0xe160279d), + SPH_C32(0x1a8e15f2), SPH_C32(0xe4a07652) }, + { SPH_C32(0xa9251600), SPH_C32(0x3347b5b8), SPH_C32(0x52bdca50), + SPH_C32(0x36665aa7), SPH_C32(0x95080c00), SPH_C32(0xf32b4fa3), + SPH_C32(0x9a4cc37d), SPH_C32(0xdf53dd7e) }, + { SPH_C32(0xe0bb1400), SPH_C32(0x3e1e59b5), SPH_C32(0xb29ae52d), + SPH_C32(0x938184fd), SPH_C32(0x32b00e00), SPH_C32(0xec39cb90), + SPH_C32(0xfaa93a8f), SPH_C32(0x4147a808) }, + { SPH_C32(0x47031600), SPH_C32(0x210cdd86), SPH_C32(0xd27f1cdf), + SPH_C32(0x0d95f18b), SPH_C32(0xdc960e00), SPH_C32(0xfe72a3ae), + SPH_C32(0x7a6bec00), SPH_C32(0x7ab40324) }, + { SPH_C32(0x4b2c1800), SPH_C32(0x26f19efd), SPH_C32(0x466ab43f), + SPH_C32(0xa33f7777), SPH_C32(0x159b0800), SPH_C32(0xb8a46797), + SPH_C32(0xca59dec0), SPH_C32(0x764b30f7) }, + { SPH_C32(0xec941a00), SPH_C32(0x39e31ace), SPH_C32(0x268f4dcd), + SPH_C32(0x3d2b0201), SPH_C32(0xfbbd0800), SPH_C32(0xaaef0fa9), + SPH_C32(0x4a9b084f), SPH_C32(0x4db89bdb) }, + { SPH_C32(0xa50a1800), SPH_C32(0x34baf6c3), SPH_C32(0xc6a862b0), + SPH_C32(0x98ccdc5b), SPH_C32(0x5c050a00), SPH_C32(0xb5fd8b9a), + SPH_C32(0x2a7ef1bd), SPH_C32(0xd3aceead) }, + { SPH_C32(0x02b21a00), SPH_C32(0x2ba872f0), SPH_C32(0xa64d9b42), + SPH_C32(0x06d8a92d), SPH_C32(0xb2230a00), SPH_C32(0xa7b6e3a4), + SPH_C32(0xaabc2732), SPH_C32(0xe85f4581) }, + { SPH_C32(0xc4121c00), SPH_C32(0x2b6c568a), SPH_C32(0x29affcde), + SPH_C32(0x2ab25ba1), SPH_C32(0x01260800), SPH_C32(0x971e5068), + SPH_C32(0xa02b3b7b), SPH_C32(0x5234db11) }, + { SPH_C32(0x63aa1e00), SPH_C32(0x347ed2b9), SPH_C32(0x494a052c), + SPH_C32(0xb4a62ed7), SPH_C32(0xef000800), SPH_C32(0x85553856), + SPH_C32(0x20e9edf4), SPH_C32(0x69c7703d) }, + { SPH_C32(0x2a341c00), SPH_C32(0x39273eb4), SPH_C32(0xa96d2a51), + SPH_C32(0x1141f08d), SPH_C32(0x48b80a00), SPH_C32(0x9a47bc65), + SPH_C32(0x400c1406), SPH_C32(0xf7d3054b) }, + { SPH_C32(0x8d8c1e00), SPH_C32(0x2635ba87), SPH_C32(0xc988d3a3), + SPH_C32(0x8f5585fb), SPH_C32(0xa69e0a00), SPH_C32(0x880cd45b), + SPH_C32(0xc0cec289), SPH_C32(0xcc20ae67) }, + { SPH_C32(0x5f911800), SPH_C32(0x094ba902), SPH_C32(0x2c185184), + SPH_C32(0x87409c91), SPH_C32(0x8e180c00), SPH_C32(0x9a83981f), + SPH_C32(0xcfee739a), SPH_C32(0xdbb9f7c7) }, + { SPH_C32(0xf8291a00), SPH_C32(0x16592d31), SPH_C32(0x4cfda876), + SPH_C32(0x1954e9e7), SPH_C32(0x603e0c00), SPH_C32(0x88c8f021), + SPH_C32(0x4f2ca515), SPH_C32(0xe04a5ceb) }, + { SPH_C32(0xb1b71800), SPH_C32(0x1b00c13c), SPH_C32(0xacda870b), + SPH_C32(0xbcb337bd), SPH_C32(0xc7860e00), SPH_C32(0x97da7412), + SPH_C32(0x2fc95ce7), SPH_C32(0x7e5e299d) }, + { SPH_C32(0x160f1a00), SPH_C32(0x0412450f), SPH_C32(0xcc3f7ef9), + SPH_C32(0x22a742cb), SPH_C32(0x29a00e00), SPH_C32(0x85911c2c), + SPH_C32(0xaf0b8a68), SPH_C32(0x45ad82b1) }, + { SPH_C32(0xd0af1c00), SPH_C32(0x04d66175), SPH_C32(0x43dd1965), + SPH_C32(0x0ecdb047), SPH_C32(0x9aa50c00), SPH_C32(0xb539afe0), + SPH_C32(0xa59c9621), SPH_C32(0xffc61c21) }, + { SPH_C32(0x77171e00), SPH_C32(0x1bc4e546), SPH_C32(0x2338e097), + SPH_C32(0x90d9c531), SPH_C32(0x74830c00), SPH_C32(0xa772c7de), + SPH_C32(0x255e40ae), SPH_C32(0xc435b70d) }, + { SPH_C32(0x3e891c00), SPH_C32(0x169d094b), SPH_C32(0xc31fcfea), + SPH_C32(0x353e1b6b), SPH_C32(0xd33b0e00), SPH_C32(0xb86043ed), + SPH_C32(0x45bbb95c), SPH_C32(0x5a21c27b) }, + { SPH_C32(0x99311e00), SPH_C32(0x098f8d78), SPH_C32(0xa3fa3618), + SPH_C32(0xab2a6e1d), SPH_C32(0x3d1d0e00), SPH_C32(0xaa2b2bd3), + SPH_C32(0xc5796fd3), SPH_C32(0x61d26957) } +}; + +static const sph_u32 T256_14[128][8] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000) }, + { SPH_C32(0x5c720000), SPH_C32(0xc9bacd12), SPH_C32(0x79a90df9), + SPH_C32(0x63e92178), SPH_C32(0xfeca0020), SPH_C32(0x485d28e4), + SPH_C32(0x806741fd), SPH_C32(0x814681b8) }, + { SPH_C32(0x4dce0040), SPH_C32(0x3b5bec7e), SPH_C32(0x36656ba8), + SPH_C32(0x23633a05), SPH_C32(0x78ab0000), SPH_C32(0xa0cd5a34), + SPH_C32(0x5d5ca0f7), SPH_C32(0x727784cb) }, + { SPH_C32(0x11bc0040), SPH_C32(0xf2e1216c), SPH_C32(0x4fcc6651), + SPH_C32(0x408a1b7d), SPH_C32(0x86610020), SPH_C32(0xe89072d0), + SPH_C32(0xdd3be10a), SPH_C32(0xf3310573) }, + { SPH_C32(0x78ab0000), SPH_C32(0xa0cd5a34), SPH_C32(0x5d5ca0f7), + SPH_C32(0x727784cb), SPH_C32(0x35650040), SPH_C32(0x9b96b64a), + SPH_C32(0x6b39cb5f), SPH_C32(0x5114bece) }, + { SPH_C32(0x24d90000), SPH_C32(0x69779726), SPH_C32(0x24f5ad0e), + SPH_C32(0x119ea5b3), SPH_C32(0xcbaf0060), SPH_C32(0xd3cb9eae), + SPH_C32(0xeb5e8aa2), SPH_C32(0xd0523f76) }, + { SPH_C32(0x35650040), SPH_C32(0x9b96b64a), SPH_C32(0x6b39cb5f), + SPH_C32(0x5114bece), SPH_C32(0x4dce0040), SPH_C32(0x3b5bec7e), + SPH_C32(0x36656ba8), SPH_C32(0x23633a05) }, + { SPH_C32(0x69170040), SPH_C32(0x522c7b58), SPH_C32(0x1290c6a6), + SPH_C32(0x32fd9fb6), SPH_C32(0xb3040060), SPH_C32(0x7306c49a), + SPH_C32(0xb6022a55), SPH_C32(0xa225bbbd) }, + { SPH_C32(0x5bd20080), SPH_C32(0x450f18ec), SPH_C32(0xc2c46c55), + SPH_C32(0xf362b233), SPH_C32(0x39a60000), SPH_C32(0x4ab753eb), + SPH_C32(0xd14e094b), SPH_C32(0xb772b42b) }, + { SPH_C32(0x07a00080), SPH_C32(0x8cb5d5fe), SPH_C32(0xbb6d61ac), + SPH_C32(0x908b934b), SPH_C32(0xc76c0020), SPH_C32(0x02ea7b0f), + SPH_C32(0x512948b6), SPH_C32(0x36343593) }, + { SPH_C32(0x161c00c0), SPH_C32(0x7e54f492), SPH_C32(0xf4a107fd), + SPH_C32(0xd0018836), SPH_C32(0x410d0000), SPH_C32(0xea7a09df), + SPH_C32(0x8c12a9bc), SPH_C32(0xc50530e0) }, + { SPH_C32(0x4a6e00c0), SPH_C32(0xb7ee3980), SPH_C32(0x8d080a04), + SPH_C32(0xb3e8a94e), SPH_C32(0xbfc70020), SPH_C32(0xa227213b), + SPH_C32(0x0c75e841), SPH_C32(0x4443b158) }, + { SPH_C32(0x23790080), SPH_C32(0xe5c242d8), SPH_C32(0x9f98cca2), + SPH_C32(0x811536f8), SPH_C32(0x0cc30040), SPH_C32(0xd121e5a1), + SPH_C32(0xba77c214), SPH_C32(0xe6660ae5) }, + { SPH_C32(0x7f0b0080), SPH_C32(0x2c788fca), SPH_C32(0xe631c15b), + SPH_C32(0xe2fc1780), SPH_C32(0xf2090060), SPH_C32(0x997ccd45), + SPH_C32(0x3a1083e9), SPH_C32(0x67208b5d) }, + { SPH_C32(0x6eb700c0), SPH_C32(0xde99aea6), SPH_C32(0xa9fda70a), + SPH_C32(0xa2760cfd), SPH_C32(0x74680040), SPH_C32(0x71ecbf95), + SPH_C32(0xe72b62e3), SPH_C32(0x94118e2e) }, + { SPH_C32(0x32c500c0), SPH_C32(0x172363b4), SPH_C32(0xd054aaf3), + SPH_C32(0xc19f2d85), SPH_C32(0x8aa20060), SPH_C32(0x39b19771), + SPH_C32(0x674c231e), SPH_C32(0x15570f96) }, + { SPH_C32(0x39a60000), SPH_C32(0x4ab753eb), SPH_C32(0xd14e094b), + SPH_C32(0xb772b42b), SPH_C32(0x62740080), SPH_C32(0x0fb84b07), + SPH_C32(0x138a651e), SPH_C32(0x44100618) }, + { SPH_C32(0x65d40000), SPH_C32(0x830d9ef9), SPH_C32(0xa8e704b2), + SPH_C32(0xd49b9553), SPH_C32(0x9cbe00a0), SPH_C32(0x47e563e3), + SPH_C32(0x93ed24e3), SPH_C32(0xc55687a0) }, + { SPH_C32(0x74680040), SPH_C32(0x71ecbf95), SPH_C32(0xe72b62e3), + SPH_C32(0x94118e2e), SPH_C32(0x1adf0080), SPH_C32(0xaf751133), + SPH_C32(0x4ed6c5e9), SPH_C32(0x366782d3) }, + { SPH_C32(0x281a0040), SPH_C32(0xb8567287), SPH_C32(0x9e826f1a), + SPH_C32(0xf7f8af56), SPH_C32(0xe41500a0), SPH_C32(0xe72839d7), + SPH_C32(0xceb18414), SPH_C32(0xb721036b) }, + { SPH_C32(0x410d0000), SPH_C32(0xea7a09df), SPH_C32(0x8c12a9bc), + SPH_C32(0xc50530e0), SPH_C32(0x571100c0), SPH_C32(0x942efd4d), + SPH_C32(0x78b3ae41), SPH_C32(0x1504b8d6) }, + { SPH_C32(0x1d7f0000), SPH_C32(0x23c0c4cd), SPH_C32(0xf5bba445), + SPH_C32(0xa6ec1198), SPH_C32(0xa9db00e0), SPH_C32(0xdc73d5a9), + SPH_C32(0xf8d4efbc), SPH_C32(0x9442396e) }, + { SPH_C32(0x0cc30040), SPH_C32(0xd121e5a1), SPH_C32(0xba77c214), + SPH_C32(0xe6660ae5), SPH_C32(0x2fba00c0), SPH_C32(0x34e3a779), + SPH_C32(0x25ef0eb6), SPH_C32(0x67733c1d) }, + { SPH_C32(0x50b10040), SPH_C32(0x189b28b3), SPH_C32(0xc3decfed), + SPH_C32(0x858f2b9d), SPH_C32(0xd17000e0), SPH_C32(0x7cbe8f9d), + SPH_C32(0xa5884f4b), SPH_C32(0xe635bda5) }, + { SPH_C32(0x62740080), SPH_C32(0x0fb84b07), SPH_C32(0x138a651e), + SPH_C32(0x44100618), SPH_C32(0x5bd20080), SPH_C32(0x450f18ec), + SPH_C32(0xc2c46c55), SPH_C32(0xf362b233) }, + { SPH_C32(0x3e060080), SPH_C32(0xc6028615), SPH_C32(0x6a2368e7), + SPH_C32(0x27f92760), SPH_C32(0xa51800a0), SPH_C32(0x0d523008), + SPH_C32(0x42a32da8), SPH_C32(0x7224338b) }, + { SPH_C32(0x2fba00c0), SPH_C32(0x34e3a779), SPH_C32(0x25ef0eb6), + SPH_C32(0x67733c1d), SPH_C32(0x23790080), SPH_C32(0xe5c242d8), + SPH_C32(0x9f98cca2), SPH_C32(0x811536f8) }, + { SPH_C32(0x73c800c0), SPH_C32(0xfd596a6b), SPH_C32(0x5c46034f), + SPH_C32(0x049a1d65), SPH_C32(0xddb300a0), SPH_C32(0xad9f6a3c), + SPH_C32(0x1fff8d5f), SPH_C32(0x0053b740) }, + { SPH_C32(0x1adf0080), SPH_C32(0xaf751133), SPH_C32(0x4ed6c5e9), + SPH_C32(0x366782d3), SPH_C32(0x6eb700c0), SPH_C32(0xde99aea6), + SPH_C32(0xa9fda70a), SPH_C32(0xa2760cfd) }, + { SPH_C32(0x46ad0080), SPH_C32(0x66cfdc21), SPH_C32(0x377fc810), + SPH_C32(0x558ea3ab), SPH_C32(0x907d00e0), SPH_C32(0x96c48642), + SPH_C32(0x299ae6f7), SPH_C32(0x23308d45) }, + { SPH_C32(0x571100c0), SPH_C32(0x942efd4d), SPH_C32(0x78b3ae41), + SPH_C32(0x1504b8d6), SPH_C32(0x161c00c0), SPH_C32(0x7e54f492), + SPH_C32(0xf4a107fd), SPH_C32(0xd0018836) }, + { SPH_C32(0x0b6300c0), SPH_C32(0x5d94305f), SPH_C32(0x011aa3b8), + SPH_C32(0x76ed99ae), SPH_C32(0xe8d600e0), SPH_C32(0x3609dc76), + SPH_C32(0x74c64600), SPH_C32(0x5147098e) }, + { SPH_C32(0xb7a40100), SPH_C32(0x8a1f31d8), SPH_C32(0x8589d8ab), + SPH_C32(0xe6c46464), SPH_C32(0x734c0000), SPH_C32(0x956fa7d6), + SPH_C32(0xa29d1297), SPH_C32(0x6ee56854) }, + { SPH_C32(0xebd60100), SPH_C32(0x43a5fcca), SPH_C32(0xfc20d552), + SPH_C32(0x852d451c), SPH_C32(0x8d860020), SPH_C32(0xdd328f32), + SPH_C32(0x22fa536a), SPH_C32(0xefa3e9ec) }, + { SPH_C32(0xfa6a0140), SPH_C32(0xb144dda6), SPH_C32(0xb3ecb303), + SPH_C32(0xc5a75e61), SPH_C32(0x0be70000), SPH_C32(0x35a2fde2), + SPH_C32(0xffc1b260), SPH_C32(0x1c92ec9f) }, + { SPH_C32(0xa6180140), SPH_C32(0x78fe10b4), SPH_C32(0xca45befa), + SPH_C32(0xa64e7f19), SPH_C32(0xf52d0020), SPH_C32(0x7dffd506), + SPH_C32(0x7fa6f39d), SPH_C32(0x9dd46d27) }, + { SPH_C32(0xcf0f0100), SPH_C32(0x2ad26bec), SPH_C32(0xd8d5785c), + SPH_C32(0x94b3e0af), SPH_C32(0x46290040), SPH_C32(0x0ef9119c), + SPH_C32(0xc9a4d9c8), SPH_C32(0x3ff1d69a) }, + { SPH_C32(0x937d0100), SPH_C32(0xe368a6fe), SPH_C32(0xa17c75a5), + SPH_C32(0xf75ac1d7), SPH_C32(0xb8e30060), SPH_C32(0x46a43978), + SPH_C32(0x49c39835), SPH_C32(0xbeb75722) }, + { SPH_C32(0x82c10140), SPH_C32(0x11898792), SPH_C32(0xeeb013f4), + SPH_C32(0xb7d0daaa), SPH_C32(0x3e820040), SPH_C32(0xae344ba8), + SPH_C32(0x94f8793f), SPH_C32(0x4d865251) }, + { SPH_C32(0xdeb30140), SPH_C32(0xd8334a80), SPH_C32(0x97191e0d), + SPH_C32(0xd439fbd2), SPH_C32(0xc0480060), SPH_C32(0xe669634c), + SPH_C32(0x149f38c2), SPH_C32(0xccc0d3e9) }, + { SPH_C32(0xec760180), SPH_C32(0xcf102934), SPH_C32(0x474db4fe), + SPH_C32(0x15a6d657), SPH_C32(0x4aea0000), SPH_C32(0xdfd8f43d), + SPH_C32(0x73d31bdc), SPH_C32(0xd997dc7f) }, + { SPH_C32(0xb0040180), SPH_C32(0x06aae426), SPH_C32(0x3ee4b907), + SPH_C32(0x764ff72f), SPH_C32(0xb4200020), SPH_C32(0x9785dcd9), + SPH_C32(0xf3b45a21), SPH_C32(0x58d15dc7) }, + { SPH_C32(0xa1b801c0), SPH_C32(0xf44bc54a), SPH_C32(0x7128df56), + SPH_C32(0x36c5ec52), SPH_C32(0x32410000), SPH_C32(0x7f15ae09), + SPH_C32(0x2e8fbb2b), SPH_C32(0xabe058b4) }, + { SPH_C32(0xfdca01c0), SPH_C32(0x3df10858), SPH_C32(0x0881d2af), + SPH_C32(0x552ccd2a), SPH_C32(0xcc8b0020), SPH_C32(0x374886ed), + SPH_C32(0xaee8fad6), SPH_C32(0x2aa6d90c) }, + { SPH_C32(0x94dd0180), SPH_C32(0x6fdd7300), SPH_C32(0x1a111409), + SPH_C32(0x67d1529c), SPH_C32(0x7f8f0040), SPH_C32(0x444e4277), + SPH_C32(0x18ead083), SPH_C32(0x888362b1) }, + { SPH_C32(0xc8af0180), SPH_C32(0xa667be12), SPH_C32(0x63b819f0), + SPH_C32(0x043873e4), SPH_C32(0x81450060), SPH_C32(0x0c136a93), + SPH_C32(0x988d917e), SPH_C32(0x09c5e309) }, + { SPH_C32(0xd91301c0), SPH_C32(0x54869f7e), SPH_C32(0x2c747fa1), + SPH_C32(0x44b26899), SPH_C32(0x07240040), SPH_C32(0xe4831843), + SPH_C32(0x45b67074), SPH_C32(0xfaf4e67a) }, + { SPH_C32(0x856101c0), SPH_C32(0x9d3c526c), SPH_C32(0x55dd7258), + SPH_C32(0x275b49e1), SPH_C32(0xf9ee0060), SPH_C32(0xacde30a7), + SPH_C32(0xc5d13189), SPH_C32(0x7bb267c2) }, + { SPH_C32(0x8e020100), SPH_C32(0xc0a86233), SPH_C32(0x54c7d1e0), + SPH_C32(0x51b6d04f), SPH_C32(0x11380080), SPH_C32(0x9ad7ecd1), + SPH_C32(0xb1177789), SPH_C32(0x2af56e4c) }, + { SPH_C32(0xd2700100), SPH_C32(0x0912af21), SPH_C32(0x2d6edc19), + SPH_C32(0x325ff137), SPH_C32(0xeff200a0), SPH_C32(0xd28ac435), + SPH_C32(0x31703674), SPH_C32(0xabb3eff4) }, + { SPH_C32(0xc3cc0140), SPH_C32(0xfbf38e4d), SPH_C32(0x62a2ba48), + SPH_C32(0x72d5ea4a), SPH_C32(0x69930080), SPH_C32(0x3a1ab6e5), + SPH_C32(0xec4bd77e), SPH_C32(0x5882ea87) }, + { SPH_C32(0x9fbe0140), SPH_C32(0x3249435f), SPH_C32(0x1b0bb7b1), + SPH_C32(0x113ccb32), SPH_C32(0x975900a0), SPH_C32(0x72479e01), + SPH_C32(0x6c2c9683), SPH_C32(0xd9c46b3f) }, + { SPH_C32(0xf6a90100), SPH_C32(0x60653807), SPH_C32(0x099b7117), + SPH_C32(0x23c15484), SPH_C32(0x245d00c0), SPH_C32(0x01415a9b), + SPH_C32(0xda2ebcd6), SPH_C32(0x7be1d082) }, + { SPH_C32(0xaadb0100), SPH_C32(0xa9dff515), SPH_C32(0x70327cee), + SPH_C32(0x402875fc), SPH_C32(0xda9700e0), SPH_C32(0x491c727f), + SPH_C32(0x5a49fd2b), SPH_C32(0xfaa7513a) }, + { SPH_C32(0xbb670140), SPH_C32(0x5b3ed479), SPH_C32(0x3ffe1abf), + SPH_C32(0x00a26e81), SPH_C32(0x5cf600c0), SPH_C32(0xa18c00af), + SPH_C32(0x87721c21), SPH_C32(0x09965449) }, + { SPH_C32(0xe7150140), SPH_C32(0x9284196b), SPH_C32(0x46571746), + SPH_C32(0x634b4ff9), SPH_C32(0xa23c00e0), SPH_C32(0xe9d1284b), + SPH_C32(0x07155ddc), SPH_C32(0x88d0d5f1) }, + { SPH_C32(0xd5d00180), SPH_C32(0x85a77adf), SPH_C32(0x9603bdb5), + SPH_C32(0xa2d4627c), SPH_C32(0x289e0080), SPH_C32(0xd060bf3a), + SPH_C32(0x60597ec2), SPH_C32(0x9d87da67) }, + { SPH_C32(0x89a20180), SPH_C32(0x4c1db7cd), SPH_C32(0xefaab04c), + SPH_C32(0xc13d4304), SPH_C32(0xd65400a0), SPH_C32(0x983d97de), + SPH_C32(0xe03e3f3f), SPH_C32(0x1cc15bdf) }, + { SPH_C32(0x981e01c0), SPH_C32(0xbefc96a1), SPH_C32(0xa066d61d), + SPH_C32(0x81b75879), SPH_C32(0x50350080), SPH_C32(0x70ade50e), + SPH_C32(0x3d05de35), SPH_C32(0xeff05eac) }, + { SPH_C32(0xc46c01c0), SPH_C32(0x77465bb3), SPH_C32(0xd9cfdbe4), + SPH_C32(0xe25e7901), SPH_C32(0xaeff00a0), SPH_C32(0x38f0cdea), + SPH_C32(0xbd629fc8), SPH_C32(0x6eb6df14) }, + { SPH_C32(0xad7b0180), SPH_C32(0x256a20eb), SPH_C32(0xcb5f1d42), + SPH_C32(0xd0a3e6b7), SPH_C32(0x1dfb00c0), SPH_C32(0x4bf60970), + SPH_C32(0x0b60b59d), SPH_C32(0xcc9364a9) }, + { SPH_C32(0xf1090180), SPH_C32(0xecd0edf9), SPH_C32(0xb2f610bb), + SPH_C32(0xb34ac7cf), SPH_C32(0xe33100e0), SPH_C32(0x03ab2194), + SPH_C32(0x8b07f460), SPH_C32(0x4dd5e511) }, + { SPH_C32(0xe0b501c0), SPH_C32(0x1e31cc95), SPH_C32(0xfd3a76ea), + SPH_C32(0xf3c0dcb2), SPH_C32(0x655000c0), SPH_C32(0xeb3b5344), + SPH_C32(0x563c156a), SPH_C32(0xbee4e062) }, + { SPH_C32(0xbcc701c0), SPH_C32(0xd78b0187), SPH_C32(0x84937b13), + SPH_C32(0x9029fdca), SPH_C32(0x9b9a00e0), SPH_C32(0xa3667ba0), + SPH_C32(0xd65b5497), SPH_C32(0x3fa261da) }, + { SPH_C32(0x734c0000), SPH_C32(0x956fa7d6), SPH_C32(0xa29d1297), + SPH_C32(0x6ee56854), SPH_C32(0xc4e80100), SPH_C32(0x1f70960e), + SPH_C32(0x2714ca3c), SPH_C32(0x88210c30) }, + { SPH_C32(0x2f3e0000), SPH_C32(0x5cd56ac4), SPH_C32(0xdb341f6e), + SPH_C32(0x0d0c492c), SPH_C32(0x3a220120), SPH_C32(0x572dbeea), + SPH_C32(0xa7738bc1), SPH_C32(0x09678d88) }, + { SPH_C32(0x3e820040), SPH_C32(0xae344ba8), SPH_C32(0x94f8793f), + SPH_C32(0x4d865251), SPH_C32(0xbc430100), SPH_C32(0xbfbdcc3a), + SPH_C32(0x7a486acb), SPH_C32(0xfa5688fb) }, + { SPH_C32(0x62f00040), SPH_C32(0x678e86ba), SPH_C32(0xed5174c6), + SPH_C32(0x2e6f7329), SPH_C32(0x42890120), SPH_C32(0xf7e0e4de), + SPH_C32(0xfa2f2b36), SPH_C32(0x7b100943) }, + { SPH_C32(0x0be70000), SPH_C32(0x35a2fde2), SPH_C32(0xffc1b260), + SPH_C32(0x1c92ec9f), SPH_C32(0xf18d0140), SPH_C32(0x84e62044), + SPH_C32(0x4c2d0163), SPH_C32(0xd935b2fe) }, + { SPH_C32(0x57950000), SPH_C32(0xfc1830f0), SPH_C32(0x8668bf99), + SPH_C32(0x7f7bcde7), SPH_C32(0x0f470160), SPH_C32(0xccbb08a0), + SPH_C32(0xcc4a409e), SPH_C32(0x58733346) }, + { SPH_C32(0x46290040), SPH_C32(0x0ef9119c), SPH_C32(0xc9a4d9c8), + SPH_C32(0x3ff1d69a), SPH_C32(0x89260140), SPH_C32(0x242b7a70), + SPH_C32(0x1171a194), SPH_C32(0xab423635) }, + { SPH_C32(0x1a5b0040), SPH_C32(0xc743dc8e), SPH_C32(0xb00dd431), + SPH_C32(0x5c18f7e2), SPH_C32(0x77ec0160), SPH_C32(0x6c765294), + SPH_C32(0x9116e069), SPH_C32(0x2a04b78d) }, + { SPH_C32(0x289e0080), SPH_C32(0xd060bf3a), SPH_C32(0x60597ec2), + SPH_C32(0x9d87da67), SPH_C32(0xfd4e0100), SPH_C32(0x55c7c5e5), + SPH_C32(0xf65ac377), SPH_C32(0x3f53b81b) }, + { SPH_C32(0x74ec0080), SPH_C32(0x19da7228), SPH_C32(0x19f0733b), + SPH_C32(0xfe6efb1f), SPH_C32(0x03840120), SPH_C32(0x1d9aed01), + SPH_C32(0x763d828a), SPH_C32(0xbe1539a3) }, + { SPH_C32(0x655000c0), SPH_C32(0xeb3b5344), SPH_C32(0x563c156a), + SPH_C32(0xbee4e062), SPH_C32(0x85e50100), SPH_C32(0xf50a9fd1), + SPH_C32(0xab066380), SPH_C32(0x4d243cd0) }, + { SPH_C32(0x392200c0), SPH_C32(0x22819e56), SPH_C32(0x2f951893), + SPH_C32(0xdd0dc11a), SPH_C32(0x7b2f0120), SPH_C32(0xbd57b735), + SPH_C32(0x2b61227d), SPH_C32(0xcc62bd68) }, + { SPH_C32(0x50350080), SPH_C32(0x70ade50e), SPH_C32(0x3d05de35), + SPH_C32(0xeff05eac), SPH_C32(0xc82b0140), SPH_C32(0xce5173af), + SPH_C32(0x9d630828), SPH_C32(0x6e4706d5) }, + { SPH_C32(0x0c470080), SPH_C32(0xb917281c), SPH_C32(0x44acd3cc), + SPH_C32(0x8c197fd4), SPH_C32(0x36e10160), SPH_C32(0x860c5b4b), + SPH_C32(0x1d0449d5), SPH_C32(0xef01876d) }, + { SPH_C32(0x1dfb00c0), SPH_C32(0x4bf60970), SPH_C32(0x0b60b59d), + SPH_C32(0xcc9364a9), SPH_C32(0xb0800140), SPH_C32(0x6e9c299b), + SPH_C32(0xc03fa8df), SPH_C32(0x1c30821e) }, + { SPH_C32(0x418900c0), SPH_C32(0x824cc462), SPH_C32(0x72c9b864), + SPH_C32(0xaf7a45d1), SPH_C32(0x4e4a0160), SPH_C32(0x26c1017f), + SPH_C32(0x4058e922), SPH_C32(0x9d7603a6) }, + { SPH_C32(0x4aea0000), SPH_C32(0xdfd8f43d), SPH_C32(0x73d31bdc), + SPH_C32(0xd997dc7f), SPH_C32(0xa69c0180), SPH_C32(0x10c8dd09), + SPH_C32(0x349eaf22), SPH_C32(0xcc310a28) }, + { SPH_C32(0x16980000), SPH_C32(0x1662392f), SPH_C32(0x0a7a1625), + SPH_C32(0xba7efd07), SPH_C32(0x585601a0), SPH_C32(0x5895f5ed), + SPH_C32(0xb4f9eedf), SPH_C32(0x4d778b90) }, + { SPH_C32(0x07240040), SPH_C32(0xe4831843), SPH_C32(0x45b67074), + SPH_C32(0xfaf4e67a), SPH_C32(0xde370180), SPH_C32(0xb005873d), + SPH_C32(0x69c20fd5), SPH_C32(0xbe468ee3) }, + { SPH_C32(0x5b560040), SPH_C32(0x2d39d551), SPH_C32(0x3c1f7d8d), + SPH_C32(0x991dc702), SPH_C32(0x20fd01a0), SPH_C32(0xf858afd9), + SPH_C32(0xe9a54e28), SPH_C32(0x3f000f5b) }, + { SPH_C32(0x32410000), SPH_C32(0x7f15ae09), SPH_C32(0x2e8fbb2b), + SPH_C32(0xabe058b4), SPH_C32(0x93f901c0), SPH_C32(0x8b5e6b43), + SPH_C32(0x5fa7647d), SPH_C32(0x9d25b4e6) }, + { SPH_C32(0x6e330000), SPH_C32(0xb6af631b), SPH_C32(0x5726b6d2), + SPH_C32(0xc80979cc), SPH_C32(0x6d3301e0), SPH_C32(0xc30343a7), + SPH_C32(0xdfc02580), SPH_C32(0x1c63355e) }, + { SPH_C32(0x7f8f0040), SPH_C32(0x444e4277), SPH_C32(0x18ead083), + SPH_C32(0x888362b1), SPH_C32(0xeb5201c0), SPH_C32(0x2b933177), + SPH_C32(0x02fbc48a), SPH_C32(0xef52302d) }, + { SPH_C32(0x23fd0040), SPH_C32(0x8df48f65), SPH_C32(0x6143dd7a), + SPH_C32(0xeb6a43c9), SPH_C32(0x159801e0), SPH_C32(0x63ce1993), + SPH_C32(0x829c8577), SPH_C32(0x6e14b195) }, + { SPH_C32(0x11380080), SPH_C32(0x9ad7ecd1), SPH_C32(0xb1177789), + SPH_C32(0x2af56e4c), SPH_C32(0x9f3a0180), SPH_C32(0x5a7f8ee2), + SPH_C32(0xe5d0a669), SPH_C32(0x7b43be03) }, + { SPH_C32(0x4d4a0080), SPH_C32(0x536d21c3), SPH_C32(0xc8be7a70), + SPH_C32(0x491c4f34), SPH_C32(0x61f001a0), SPH_C32(0x1222a606), + SPH_C32(0x65b7e794), SPH_C32(0xfa053fbb) }, + { SPH_C32(0x5cf600c0), SPH_C32(0xa18c00af), SPH_C32(0x87721c21), + SPH_C32(0x09965449), SPH_C32(0xe7910180), SPH_C32(0xfab2d4d6), + SPH_C32(0xb88c069e), SPH_C32(0x09343ac8) }, + { SPH_C32(0x008400c0), SPH_C32(0x6836cdbd), SPH_C32(0xfedb11d8), + SPH_C32(0x6a7f7531), SPH_C32(0x195b01a0), SPH_C32(0xb2effc32), + SPH_C32(0x38eb4763), SPH_C32(0x8872bb70) }, + { SPH_C32(0x69930080), SPH_C32(0x3a1ab6e5), SPH_C32(0xec4bd77e), + SPH_C32(0x5882ea87), SPH_C32(0xaa5f01c0), SPH_C32(0xc1e938a8), + SPH_C32(0x8ee96d36), SPH_C32(0x2a5700cd) }, + { SPH_C32(0x35e10080), SPH_C32(0xf3a07bf7), SPH_C32(0x95e2da87), + SPH_C32(0x3b6bcbff), SPH_C32(0x549501e0), SPH_C32(0x89b4104c), + SPH_C32(0x0e8e2ccb), SPH_C32(0xab118175) }, + { SPH_C32(0x245d00c0), SPH_C32(0x01415a9b), SPH_C32(0xda2ebcd6), + SPH_C32(0x7be1d082), SPH_C32(0xd2f401c0), SPH_C32(0x6124629c), + SPH_C32(0xd3b5cdc1), SPH_C32(0x58208406) }, + { SPH_C32(0x782f00c0), SPH_C32(0xc8fb9789), SPH_C32(0xa387b12f), + SPH_C32(0x1808f1fa), SPH_C32(0x2c3e01e0), SPH_C32(0x29794a78), + SPH_C32(0x53d28c3c), SPH_C32(0xd96605be) }, + { SPH_C32(0xc4e80100), SPH_C32(0x1f70960e), SPH_C32(0x2714ca3c), + SPH_C32(0x88210c30), SPH_C32(0xb7a40100), SPH_C32(0x8a1f31d8), + SPH_C32(0x8589d8ab), SPH_C32(0xe6c46464) }, + { SPH_C32(0x989a0100), SPH_C32(0xd6ca5b1c), SPH_C32(0x5ebdc7c5), + SPH_C32(0xebc82d48), SPH_C32(0x496e0120), SPH_C32(0xc242193c), + SPH_C32(0x05ee9956), SPH_C32(0x6782e5dc) }, + { SPH_C32(0x89260140), SPH_C32(0x242b7a70), SPH_C32(0x1171a194), + SPH_C32(0xab423635), SPH_C32(0xcf0f0100), SPH_C32(0x2ad26bec), + SPH_C32(0xd8d5785c), SPH_C32(0x94b3e0af) }, + { SPH_C32(0xd5540140), SPH_C32(0xed91b762), SPH_C32(0x68d8ac6d), + SPH_C32(0xc8ab174d), SPH_C32(0x31c50120), SPH_C32(0x628f4308), + SPH_C32(0x58b239a1), SPH_C32(0x15f56117) }, + { SPH_C32(0xbc430100), SPH_C32(0xbfbdcc3a), SPH_C32(0x7a486acb), + SPH_C32(0xfa5688fb), SPH_C32(0x82c10140), SPH_C32(0x11898792), + SPH_C32(0xeeb013f4), SPH_C32(0xb7d0daaa) }, + { SPH_C32(0xe0310100), SPH_C32(0x76070128), SPH_C32(0x03e16732), + SPH_C32(0x99bfa983), SPH_C32(0x7c0b0160), SPH_C32(0x59d4af76), + SPH_C32(0x6ed75209), SPH_C32(0x36965b12) }, + { SPH_C32(0xf18d0140), SPH_C32(0x84e62044), SPH_C32(0x4c2d0163), + SPH_C32(0xd935b2fe), SPH_C32(0xfa6a0140), SPH_C32(0xb144dda6), + SPH_C32(0xb3ecb303), SPH_C32(0xc5a75e61) }, + { SPH_C32(0xadff0140), SPH_C32(0x4d5ced56), SPH_C32(0x35840c9a), + SPH_C32(0xbadc9386), SPH_C32(0x04a00160), SPH_C32(0xf919f542), + SPH_C32(0x338bf2fe), SPH_C32(0x44e1dfd9) }, + { SPH_C32(0x9f3a0180), SPH_C32(0x5a7f8ee2), SPH_C32(0xe5d0a669), + SPH_C32(0x7b43be03), SPH_C32(0x8e020100), SPH_C32(0xc0a86233), + SPH_C32(0x54c7d1e0), SPH_C32(0x51b6d04f) }, + { SPH_C32(0xc3480180), SPH_C32(0x93c543f0), SPH_C32(0x9c79ab90), + SPH_C32(0x18aa9f7b), SPH_C32(0x70c80120), SPH_C32(0x88f54ad7), + SPH_C32(0xd4a0901d), SPH_C32(0xd0f051f7) }, + { SPH_C32(0xd2f401c0), SPH_C32(0x6124629c), SPH_C32(0xd3b5cdc1), + SPH_C32(0x58208406), SPH_C32(0xf6a90100), SPH_C32(0x60653807), + SPH_C32(0x099b7117), SPH_C32(0x23c15484) }, + { SPH_C32(0x8e8601c0), SPH_C32(0xa89eaf8e), SPH_C32(0xaa1cc038), + SPH_C32(0x3bc9a57e), SPH_C32(0x08630120), SPH_C32(0x283810e3), + SPH_C32(0x89fc30ea), SPH_C32(0xa287d53c) }, + { SPH_C32(0xe7910180), SPH_C32(0xfab2d4d6), SPH_C32(0xb88c069e), + SPH_C32(0x09343ac8), SPH_C32(0xbb670140), SPH_C32(0x5b3ed479), + SPH_C32(0x3ffe1abf), SPH_C32(0x00a26e81) }, + { SPH_C32(0xbbe30180), SPH_C32(0x330819c4), SPH_C32(0xc1250b67), + SPH_C32(0x6add1bb0), SPH_C32(0x45ad0160), SPH_C32(0x1363fc9d), + SPH_C32(0xbf995b42), SPH_C32(0x81e4ef39) }, + { SPH_C32(0xaa5f01c0), SPH_C32(0xc1e938a8), SPH_C32(0x8ee96d36), + SPH_C32(0x2a5700cd), SPH_C32(0xc3cc0140), SPH_C32(0xfbf38e4d), + SPH_C32(0x62a2ba48), SPH_C32(0x72d5ea4a) }, + { SPH_C32(0xf62d01c0), SPH_C32(0x0853f5ba), SPH_C32(0xf74060cf), + SPH_C32(0x49be21b5), SPH_C32(0x3d060160), SPH_C32(0xb3aea6a9), + SPH_C32(0xe2c5fbb5), SPH_C32(0xf3936bf2) }, + { SPH_C32(0xfd4e0100), SPH_C32(0x55c7c5e5), SPH_C32(0xf65ac377), + SPH_C32(0x3f53b81b), SPH_C32(0xd5d00180), SPH_C32(0x85a77adf), + SPH_C32(0x9603bdb5), SPH_C32(0xa2d4627c) }, + { SPH_C32(0xa13c0100), SPH_C32(0x9c7d08f7), SPH_C32(0x8ff3ce8e), + SPH_C32(0x5cba9963), SPH_C32(0x2b1a01a0), SPH_C32(0xcdfa523b), + SPH_C32(0x1664fc48), SPH_C32(0x2392e3c4) }, + { SPH_C32(0xb0800140), SPH_C32(0x6e9c299b), SPH_C32(0xc03fa8df), + SPH_C32(0x1c30821e), SPH_C32(0xad7b0180), SPH_C32(0x256a20eb), + SPH_C32(0xcb5f1d42), SPH_C32(0xd0a3e6b7) }, + { SPH_C32(0xecf20140), SPH_C32(0xa726e489), SPH_C32(0xb996a526), + SPH_C32(0x7fd9a366), SPH_C32(0x53b101a0), SPH_C32(0x6d37080f), + SPH_C32(0x4b385cbf), SPH_C32(0x51e5670f) }, + { SPH_C32(0x85e50100), SPH_C32(0xf50a9fd1), SPH_C32(0xab066380), + SPH_C32(0x4d243cd0), SPH_C32(0xe0b501c0), SPH_C32(0x1e31cc95), + SPH_C32(0xfd3a76ea), SPH_C32(0xf3c0dcb2) }, + { SPH_C32(0xd9970100), SPH_C32(0x3cb052c3), SPH_C32(0xd2af6e79), + SPH_C32(0x2ecd1da8), SPH_C32(0x1e7f01e0), SPH_C32(0x566ce471), + SPH_C32(0x7d5d3717), SPH_C32(0x72865d0a) }, + { SPH_C32(0xc82b0140), SPH_C32(0xce5173af), SPH_C32(0x9d630828), + SPH_C32(0x6e4706d5), SPH_C32(0x981e01c0), SPH_C32(0xbefc96a1), + SPH_C32(0xa066d61d), SPH_C32(0x81b75879) }, + { SPH_C32(0x94590140), SPH_C32(0x07ebbebd), SPH_C32(0xe4ca05d1), + SPH_C32(0x0dae27ad), SPH_C32(0x66d401e0), SPH_C32(0xf6a1be45), + SPH_C32(0x200197e0), SPH_C32(0x00f1d9c1) }, + { SPH_C32(0xa69c0180), SPH_C32(0x10c8dd09), SPH_C32(0x349eaf22), + SPH_C32(0xcc310a28), SPH_C32(0xec760180), SPH_C32(0xcf102934), + SPH_C32(0x474db4fe), SPH_C32(0x15a6d657) }, + { SPH_C32(0xfaee0180), SPH_C32(0xd972101b), SPH_C32(0x4d37a2db), + SPH_C32(0xafd82b50), SPH_C32(0x12bc01a0), SPH_C32(0x874d01d0), + SPH_C32(0xc72af503), SPH_C32(0x94e057ef) }, + { SPH_C32(0xeb5201c0), SPH_C32(0x2b933177), SPH_C32(0x02fbc48a), + SPH_C32(0xef52302d), SPH_C32(0x94dd0180), SPH_C32(0x6fdd7300), + SPH_C32(0x1a111409), SPH_C32(0x67d1529c) }, + { SPH_C32(0xb72001c0), SPH_C32(0xe229fc65), SPH_C32(0x7b52c973), + SPH_C32(0x8cbb1155), SPH_C32(0x6a1701a0), SPH_C32(0x27805be4), + SPH_C32(0x9a7655f4), SPH_C32(0xe697d324) }, + { SPH_C32(0xde370180), SPH_C32(0xb005873d), SPH_C32(0x69c20fd5), + SPH_C32(0xbe468ee3), SPH_C32(0xd91301c0), SPH_C32(0x54869f7e), + SPH_C32(0x2c747fa1), SPH_C32(0x44b26899) }, + { SPH_C32(0x82450180), SPH_C32(0x79bf4a2f), SPH_C32(0x106b022c), + SPH_C32(0xddafaf9b), SPH_C32(0x27d901e0), SPH_C32(0x1cdbb79a), + SPH_C32(0xac133e5c), SPH_C32(0xc5f4e921) }, + { SPH_C32(0x93f901c0), SPH_C32(0x8b5e6b43), SPH_C32(0x5fa7647d), + SPH_C32(0x9d25b4e6), SPH_C32(0xa1b801c0), SPH_C32(0xf44bc54a), + SPH_C32(0x7128df56), SPH_C32(0x36c5ec52) }, + { SPH_C32(0xcf8b01c0), SPH_C32(0x42e4a651), SPH_C32(0x260e6984), + SPH_C32(0xfecc959e), SPH_C32(0x5f7201e0), SPH_C32(0xbc16edae), + SPH_C32(0xf14f9eab), SPH_C32(0xb7836dea) } +}; + +static const sph_u32 T256_21[128][8] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000) }, + { SPH_C32(0xd0080004), SPH_C32(0x8c768f77), SPH_C32(0x9dc5b050), + SPH_C32(0xaf4a29da), SPH_C32(0x6ba90000), SPH_C32(0x40ebf9aa), + SPH_C32(0x98321c3d), SPH_C32(0x76acc733) }, + { SPH_C32(0x6ba90000), SPH_C32(0x40ebf9aa), SPH_C32(0x98321c3d), + SPH_C32(0x76acc733), SPH_C32(0xbba10004), SPH_C32(0xcc9d76dd), + SPH_C32(0x05f7ac6d), SPH_C32(0xd9e6eee9) }, + { SPH_C32(0xbba10004), SPH_C32(0xcc9d76dd), SPH_C32(0x05f7ac6d), + SPH_C32(0xd9e6eee9), SPH_C32(0xd0080004), SPH_C32(0x8c768f77), + SPH_C32(0x9dc5b050), SPH_C32(0xaf4a29da) }, + { SPH_C32(0xa8ae0008), SPH_C32(0x2079397d), SPH_C32(0xfe739301), + SPH_C32(0xb8a92831), SPH_C32(0x171c0000), SPH_C32(0xb26e3344), + SPH_C32(0x9e6a837e), SPH_C32(0x58f8485f) }, + { SPH_C32(0x78a6000c), SPH_C32(0xac0fb60a), SPH_C32(0x63b62351), + SPH_C32(0x17e301eb), SPH_C32(0x7cb50000), SPH_C32(0xf285caee), + SPH_C32(0x06589f43), SPH_C32(0x2e548f6c) }, + { SPH_C32(0xc3070008), SPH_C32(0x6092c0d7), SPH_C32(0x66418f3c), + SPH_C32(0xce05ef02), SPH_C32(0xacbd0004), SPH_C32(0x7ef34599), + SPH_C32(0x9b9d2f13), SPH_C32(0x811ea6b6) }, + { SPH_C32(0x130f000c), SPH_C32(0xece44fa0), SPH_C32(0xfb843f6c), + SPH_C32(0x614fc6d8), SPH_C32(0xc7140004), SPH_C32(0x3e18bc33), + SPH_C32(0x03af332e), SPH_C32(0xf7b26185) }, + { SPH_C32(0x171c0000), SPH_C32(0xb26e3344), SPH_C32(0x9e6a837e), + SPH_C32(0x58f8485f), SPH_C32(0xbfb20008), SPH_C32(0x92170a39), + SPH_C32(0x6019107f), SPH_C32(0xe051606e) }, + { SPH_C32(0xc7140004), SPH_C32(0x3e18bc33), SPH_C32(0x03af332e), + SPH_C32(0xf7b26185), SPH_C32(0xd41b0008), SPH_C32(0xd2fcf393), + SPH_C32(0xf82b0c42), SPH_C32(0x96fda75d) }, + { SPH_C32(0x7cb50000), SPH_C32(0xf285caee), SPH_C32(0x06589f43), + SPH_C32(0x2e548f6c), SPH_C32(0x0413000c), SPH_C32(0x5e8a7ce4), + SPH_C32(0x65eebc12), SPH_C32(0x39b78e87) }, + { SPH_C32(0xacbd0004), SPH_C32(0x7ef34599), SPH_C32(0x9b9d2f13), + SPH_C32(0x811ea6b6), SPH_C32(0x6fba000c), SPH_C32(0x1e61854e), + SPH_C32(0xfddca02f), SPH_C32(0x4f1b49b4) }, + { SPH_C32(0xbfb20008), SPH_C32(0x92170a39), SPH_C32(0x6019107f), + SPH_C32(0xe051606e), SPH_C32(0xa8ae0008), SPH_C32(0x2079397d), + SPH_C32(0xfe739301), SPH_C32(0xb8a92831) }, + { SPH_C32(0x6fba000c), SPH_C32(0x1e61854e), SPH_C32(0xfddca02f), + SPH_C32(0x4f1b49b4), SPH_C32(0xc3070008), SPH_C32(0x6092c0d7), + SPH_C32(0x66418f3c), SPH_C32(0xce05ef02) }, + { SPH_C32(0xd41b0008), SPH_C32(0xd2fcf393), SPH_C32(0xf82b0c42), + SPH_C32(0x96fda75d), SPH_C32(0x130f000c), SPH_C32(0xece44fa0), + SPH_C32(0xfb843f6c), SPH_C32(0x614fc6d8) }, + { SPH_C32(0x0413000c), SPH_C32(0x5e8a7ce4), SPH_C32(0x65eebc12), + SPH_C32(0x39b78e87), SPH_C32(0x78a6000c), SPH_C32(0xac0fb60a), + SPH_C32(0x63b62351), SPH_C32(0x17e301eb) }, + { SPH_C32(0x515c0010), SPH_C32(0x40f372fb), SPH_C32(0xfce72602), + SPH_C32(0x71575061), SPH_C32(0x2e390000), SPH_C32(0x64dd6689), + SPH_C32(0x3cd406fc), SPH_C32(0xb1f490bc) }, + { SPH_C32(0x81540014), SPH_C32(0xcc85fd8c), SPH_C32(0x61229652), + SPH_C32(0xde1d79bb), SPH_C32(0x45900000), SPH_C32(0x24369f23), + SPH_C32(0xa4e61ac1), SPH_C32(0xc758578f) }, + { SPH_C32(0x3af50010), SPH_C32(0x00188b51), SPH_C32(0x64d53a3f), + SPH_C32(0x07fb9752), SPH_C32(0x95980004), SPH_C32(0xa8401054), + SPH_C32(0x3923aa91), SPH_C32(0x68127e55) }, + { SPH_C32(0xeafd0014), SPH_C32(0x8c6e0426), SPH_C32(0xf9108a6f), + SPH_C32(0xa8b1be88), SPH_C32(0xfe310004), SPH_C32(0xe8abe9fe), + SPH_C32(0xa111b6ac), SPH_C32(0x1ebeb966) }, + { SPH_C32(0xf9f20018), SPH_C32(0x608a4b86), SPH_C32(0x0294b503), + SPH_C32(0xc9fe7850), SPH_C32(0x39250000), SPH_C32(0xd6b355cd), + SPH_C32(0xa2be8582), SPH_C32(0xe90cd8e3) }, + { SPH_C32(0x29fa001c), SPH_C32(0xecfcc4f1), SPH_C32(0x9f510553), + SPH_C32(0x66b4518a), SPH_C32(0x528c0000), SPH_C32(0x9658ac67), + SPH_C32(0x3a8c99bf), SPH_C32(0x9fa01fd0) }, + { SPH_C32(0x925b0018), SPH_C32(0x2061b22c), SPH_C32(0x9aa6a93e), + SPH_C32(0xbf52bf63), SPH_C32(0x82840004), SPH_C32(0x1a2e2310), + SPH_C32(0xa74929ef), SPH_C32(0x30ea360a) }, + { SPH_C32(0x4253001c), SPH_C32(0xac173d5b), SPH_C32(0x0763196e), + SPH_C32(0x101896b9), SPH_C32(0xe92d0004), SPH_C32(0x5ac5daba), + SPH_C32(0x3f7b35d2), SPH_C32(0x4646f139) }, + { SPH_C32(0x46400010), SPH_C32(0xf29d41bf), SPH_C32(0x628da57c), + SPH_C32(0x29af183e), SPH_C32(0x918b0008), SPH_C32(0xf6ca6cb0), + SPH_C32(0x5ccd1683), SPH_C32(0x51a5f0d2) }, + { SPH_C32(0x96480014), SPH_C32(0x7eebcec8), SPH_C32(0xff48152c), + SPH_C32(0x86e531e4), SPH_C32(0xfa220008), SPH_C32(0xb621951a), + SPH_C32(0xc4ff0abe), SPH_C32(0x270937e1) }, + { SPH_C32(0x2de90010), SPH_C32(0xb276b815), SPH_C32(0xfabfb941), + SPH_C32(0x5f03df0d), SPH_C32(0x2a2a000c), SPH_C32(0x3a571a6d), + SPH_C32(0x593abaee), SPH_C32(0x88431e3b) }, + { SPH_C32(0xfde10014), SPH_C32(0x3e003762), SPH_C32(0x677a0911), + SPH_C32(0xf049f6d7), SPH_C32(0x4183000c), SPH_C32(0x7abce3c7), + SPH_C32(0xc108a6d3), SPH_C32(0xfeefd908) }, + { SPH_C32(0xeeee0018), SPH_C32(0xd2e478c2), SPH_C32(0x9cfe367d), + SPH_C32(0x9106300f), SPH_C32(0x86970008), SPH_C32(0x44a45ff4), + SPH_C32(0xc2a795fd), SPH_C32(0x095db88d) }, + { SPH_C32(0x3ee6001c), SPH_C32(0x5e92f7b5), SPH_C32(0x013b862d), + SPH_C32(0x3e4c19d5), SPH_C32(0xed3e0008), SPH_C32(0x044fa65e), + SPH_C32(0x5a9589c0), SPH_C32(0x7ff17fbe) }, + { SPH_C32(0x85470018), SPH_C32(0x920f8168), SPH_C32(0x04cc2a40), + SPH_C32(0xe7aaf73c), SPH_C32(0x3d36000c), SPH_C32(0x88392929), + SPH_C32(0xc7503990), SPH_C32(0xd0bb5664) }, + { SPH_C32(0x554f001c), SPH_C32(0x1e790e1f), SPH_C32(0x99099a10), + SPH_C32(0x48e0dee6), SPH_C32(0x569f000c), SPH_C32(0xc8d2d083), + SPH_C32(0x5f6225ad), SPH_C32(0xa6179157) }, + { SPH_C32(0x2e390000), SPH_C32(0x64dd6689), SPH_C32(0x3cd406fc), + SPH_C32(0xb1f490bc), SPH_C32(0x7f650010), SPH_C32(0x242e1472), + SPH_C32(0xc03320fe), SPH_C32(0xc0a3c0dd) }, + { SPH_C32(0xfe310004), SPH_C32(0xe8abe9fe), SPH_C32(0xa111b6ac), + SPH_C32(0x1ebeb966), SPH_C32(0x14cc0010), SPH_C32(0x64c5edd8), + SPH_C32(0x58013cc3), SPH_C32(0xb60f07ee) }, + { SPH_C32(0x45900000), SPH_C32(0x24369f23), SPH_C32(0xa4e61ac1), + SPH_C32(0xc758578f), SPH_C32(0xc4c40014), SPH_C32(0xe8b362af), + SPH_C32(0xc5c48c93), SPH_C32(0x19452e34) }, + { SPH_C32(0x95980004), SPH_C32(0xa8401054), SPH_C32(0x3923aa91), + SPH_C32(0x68127e55), SPH_C32(0xaf6d0014), SPH_C32(0xa8589b05), + SPH_C32(0x5df690ae), SPH_C32(0x6fe9e907) }, + { SPH_C32(0x86970008), SPH_C32(0x44a45ff4), SPH_C32(0xc2a795fd), + SPH_C32(0x095db88d), SPH_C32(0x68790010), SPH_C32(0x96402736), + SPH_C32(0x5e59a380), SPH_C32(0x985b8882) }, + { SPH_C32(0x569f000c), SPH_C32(0xc8d2d083), SPH_C32(0x5f6225ad), + SPH_C32(0xa6179157), SPH_C32(0x03d00010), SPH_C32(0xd6abde9c), + SPH_C32(0xc66bbfbd), SPH_C32(0xeef74fb1) }, + { SPH_C32(0xed3e0008), SPH_C32(0x044fa65e), SPH_C32(0x5a9589c0), + SPH_C32(0x7ff17fbe), SPH_C32(0xd3d80014), SPH_C32(0x5add51eb), + SPH_C32(0x5bae0fed), SPH_C32(0x41bd666b) }, + { SPH_C32(0x3d36000c), SPH_C32(0x88392929), SPH_C32(0xc7503990), + SPH_C32(0xd0bb5664), SPH_C32(0xb8710014), SPH_C32(0x1a36a841), + SPH_C32(0xc39c13d0), SPH_C32(0x3711a158) }, + { SPH_C32(0x39250000), SPH_C32(0xd6b355cd), SPH_C32(0xa2be8582), + SPH_C32(0xe90cd8e3), SPH_C32(0xc0d70018), SPH_C32(0xb6391e4b), + SPH_C32(0xa02a3081), SPH_C32(0x20f2a0b3) }, + { SPH_C32(0xe92d0004), SPH_C32(0x5ac5daba), SPH_C32(0x3f7b35d2), + SPH_C32(0x4646f139), SPH_C32(0xab7e0018), SPH_C32(0xf6d2e7e1), + SPH_C32(0x38182cbc), SPH_C32(0x565e6780) }, + { SPH_C32(0x528c0000), SPH_C32(0x9658ac67), SPH_C32(0x3a8c99bf), + SPH_C32(0x9fa01fd0), SPH_C32(0x7b76001c), SPH_C32(0x7aa46896), + SPH_C32(0xa5dd9cec), SPH_C32(0xf9144e5a) }, + { SPH_C32(0x82840004), SPH_C32(0x1a2e2310), SPH_C32(0xa74929ef), + SPH_C32(0x30ea360a), SPH_C32(0x10df001c), SPH_C32(0x3a4f913c), + SPH_C32(0x3def80d1), SPH_C32(0x8fb88969) }, + { SPH_C32(0x918b0008), SPH_C32(0xf6ca6cb0), SPH_C32(0x5ccd1683), + SPH_C32(0x51a5f0d2), SPH_C32(0xd7cb0018), SPH_C32(0x04572d0f), + SPH_C32(0x3e40b3ff), SPH_C32(0x780ae8ec) }, + { SPH_C32(0x4183000c), SPH_C32(0x7abce3c7), SPH_C32(0xc108a6d3), + SPH_C32(0xfeefd908), SPH_C32(0xbc620018), SPH_C32(0x44bcd4a5), + SPH_C32(0xa672afc2), SPH_C32(0x0ea62fdf) }, + { SPH_C32(0xfa220008), SPH_C32(0xb621951a), SPH_C32(0xc4ff0abe), + SPH_C32(0x270937e1), SPH_C32(0x6c6a001c), SPH_C32(0xc8ca5bd2), + SPH_C32(0x3bb71f92), SPH_C32(0xa1ec0605) }, + { SPH_C32(0x2a2a000c), SPH_C32(0x3a571a6d), SPH_C32(0x593abaee), + SPH_C32(0x88431e3b), SPH_C32(0x07c3001c), SPH_C32(0x8821a278), + SPH_C32(0xa38503af), SPH_C32(0xd740c136) }, + { SPH_C32(0x7f650010), SPH_C32(0x242e1472), SPH_C32(0xc03320fe), + SPH_C32(0xc0a3c0dd), SPH_C32(0x515c0010), SPH_C32(0x40f372fb), + SPH_C32(0xfce72602), SPH_C32(0x71575061) }, + { SPH_C32(0xaf6d0014), SPH_C32(0xa8589b05), SPH_C32(0x5df690ae), + SPH_C32(0x6fe9e907), SPH_C32(0x3af50010), SPH_C32(0x00188b51), + SPH_C32(0x64d53a3f), SPH_C32(0x07fb9752) }, + { SPH_C32(0x14cc0010), SPH_C32(0x64c5edd8), SPH_C32(0x58013cc3), + SPH_C32(0xb60f07ee), SPH_C32(0xeafd0014), SPH_C32(0x8c6e0426), + SPH_C32(0xf9108a6f), SPH_C32(0xa8b1be88) }, + { SPH_C32(0xc4c40014), SPH_C32(0xe8b362af), SPH_C32(0xc5c48c93), + SPH_C32(0x19452e34), SPH_C32(0x81540014), SPH_C32(0xcc85fd8c), + SPH_C32(0x61229652), SPH_C32(0xde1d79bb) }, + { SPH_C32(0xd7cb0018), SPH_C32(0x04572d0f), SPH_C32(0x3e40b3ff), + SPH_C32(0x780ae8ec), SPH_C32(0x46400010), SPH_C32(0xf29d41bf), + SPH_C32(0x628da57c), SPH_C32(0x29af183e) }, + { SPH_C32(0x07c3001c), SPH_C32(0x8821a278), SPH_C32(0xa38503af), + SPH_C32(0xd740c136), SPH_C32(0x2de90010), SPH_C32(0xb276b815), + SPH_C32(0xfabfb941), SPH_C32(0x5f03df0d) }, + { SPH_C32(0xbc620018), SPH_C32(0x44bcd4a5), SPH_C32(0xa672afc2), + SPH_C32(0x0ea62fdf), SPH_C32(0xfde10014), SPH_C32(0x3e003762), + SPH_C32(0x677a0911), SPH_C32(0xf049f6d7) }, + { SPH_C32(0x6c6a001c), SPH_C32(0xc8ca5bd2), SPH_C32(0x3bb71f92), + SPH_C32(0xa1ec0605), SPH_C32(0x96480014), SPH_C32(0x7eebcec8), + SPH_C32(0xff48152c), SPH_C32(0x86e531e4) }, + { SPH_C32(0x68790010), SPH_C32(0x96402736), SPH_C32(0x5e59a380), + SPH_C32(0x985b8882), SPH_C32(0xeeee0018), SPH_C32(0xd2e478c2), + SPH_C32(0x9cfe367d), SPH_C32(0x9106300f) }, + { SPH_C32(0xb8710014), SPH_C32(0x1a36a841), SPH_C32(0xc39c13d0), + SPH_C32(0x3711a158), SPH_C32(0x85470018), SPH_C32(0x920f8168), + SPH_C32(0x04cc2a40), SPH_C32(0xe7aaf73c) }, + { SPH_C32(0x03d00010), SPH_C32(0xd6abde9c), SPH_C32(0xc66bbfbd), + SPH_C32(0xeef74fb1), SPH_C32(0x554f001c), SPH_C32(0x1e790e1f), + SPH_C32(0x99099a10), SPH_C32(0x48e0dee6) }, + { SPH_C32(0xd3d80014), SPH_C32(0x5add51eb), SPH_C32(0x5bae0fed), + SPH_C32(0x41bd666b), SPH_C32(0x3ee6001c), SPH_C32(0x5e92f7b5), + SPH_C32(0x013b862d), SPH_C32(0x3e4c19d5) }, + { SPH_C32(0xc0d70018), SPH_C32(0xb6391e4b), SPH_C32(0xa02a3081), + SPH_C32(0x20f2a0b3), SPH_C32(0xf9f20018), SPH_C32(0x608a4b86), + SPH_C32(0x0294b503), SPH_C32(0xc9fe7850) }, + { SPH_C32(0x10df001c), SPH_C32(0x3a4f913c), SPH_C32(0x3def80d1), + SPH_C32(0x8fb88969), SPH_C32(0x925b0018), SPH_C32(0x2061b22c), + SPH_C32(0x9aa6a93e), SPH_C32(0xbf52bf63) }, + { SPH_C32(0xab7e0018), SPH_C32(0xf6d2e7e1), SPH_C32(0x38182cbc), + SPH_C32(0x565e6780), SPH_C32(0x4253001c), SPH_C32(0xac173d5b), + SPH_C32(0x0763196e), SPH_C32(0x101896b9) }, + { SPH_C32(0x7b76001c), SPH_C32(0x7aa46896), SPH_C32(0xa5dd9cec), + SPH_C32(0xf9144e5a), SPH_C32(0x29fa001c), SPH_C32(0xecfcc4f1), + SPH_C32(0x9f510553), SPH_C32(0x66b4518a) }, + { SPH_C32(0xa2b80020), SPH_C32(0x81e7e5f6), SPH_C32(0xf9ce4c04), + SPH_C32(0xe2afa0c0), SPH_C32(0x5c720000), SPH_C32(0xc9bacd12), + SPH_C32(0x79a90df9), SPH_C32(0x63e92178) }, + { SPH_C32(0x72b00024), SPH_C32(0x0d916a81), SPH_C32(0x640bfc54), + SPH_C32(0x4de5891a), SPH_C32(0x37db0000), SPH_C32(0x895134b8), + SPH_C32(0xe19b11c4), SPH_C32(0x1545e64b) }, + { SPH_C32(0xc9110020), SPH_C32(0xc10c1c5c), SPH_C32(0x61fc5039), + SPH_C32(0x940367f3), SPH_C32(0xe7d30004), SPH_C32(0x0527bbcf), + SPH_C32(0x7c5ea194), SPH_C32(0xba0fcf91) }, + { SPH_C32(0x19190024), SPH_C32(0x4d7a932b), SPH_C32(0xfc39e069), + SPH_C32(0x3b494e29), SPH_C32(0x8c7a0004), SPH_C32(0x45cc4265), + SPH_C32(0xe46cbda9), SPH_C32(0xcca308a2) }, + { SPH_C32(0x0a160028), SPH_C32(0xa19edc8b), SPH_C32(0x07bddf05), + SPH_C32(0x5a0688f1), SPH_C32(0x4b6e0000), SPH_C32(0x7bd4fe56), + SPH_C32(0xe7c38e87), SPH_C32(0x3b116927) }, + { SPH_C32(0xda1e002c), SPH_C32(0x2de853fc), SPH_C32(0x9a786f55), + SPH_C32(0xf54ca12b), SPH_C32(0x20c70000), SPH_C32(0x3b3f07fc), + SPH_C32(0x7ff192ba), SPH_C32(0x4dbdae14) }, + { SPH_C32(0x61bf0028), SPH_C32(0xe1752521), SPH_C32(0x9f8fc338), + SPH_C32(0x2caa4fc2), SPH_C32(0xf0cf0004), SPH_C32(0xb749888b), + SPH_C32(0xe23422ea), SPH_C32(0xe2f787ce) }, + { SPH_C32(0xb1b7002c), SPH_C32(0x6d03aa56), SPH_C32(0x024a7368), + SPH_C32(0x83e06618), SPH_C32(0x9b660004), SPH_C32(0xf7a27121), + SPH_C32(0x7a063ed7), SPH_C32(0x945b40fd) }, + { SPH_C32(0xb5a40020), SPH_C32(0x3389d6b2), SPH_C32(0x67a4cf7a), + SPH_C32(0xba57e89f), SPH_C32(0xe3c00008), SPH_C32(0x5badc72b), + SPH_C32(0x19b01d86), SPH_C32(0x83b84116) }, + { SPH_C32(0x65ac0024), SPH_C32(0xbfff59c5), SPH_C32(0xfa617f2a), + SPH_C32(0x151dc145), SPH_C32(0x88690008), SPH_C32(0x1b463e81), + SPH_C32(0x818201bb), SPH_C32(0xf5148625) }, + { SPH_C32(0xde0d0020), SPH_C32(0x73622f18), SPH_C32(0xff96d347), + SPH_C32(0xccfb2fac), SPH_C32(0x5861000c), SPH_C32(0x9730b1f6), + SPH_C32(0x1c47b1eb), SPH_C32(0x5a5eafff) }, + { SPH_C32(0x0e050024), SPH_C32(0xff14a06f), SPH_C32(0x62536317), + SPH_C32(0x63b10676), SPH_C32(0x33c8000c), SPH_C32(0xd7db485c), + SPH_C32(0x8475add6), SPH_C32(0x2cf268cc) }, + { SPH_C32(0x1d0a0028), SPH_C32(0x13f0efcf), SPH_C32(0x99d75c7b), + SPH_C32(0x02fec0ae), SPH_C32(0xf4dc0008), SPH_C32(0xe9c3f46f), + SPH_C32(0x87da9ef8), SPH_C32(0xdb400949) }, + { SPH_C32(0xcd02002c), SPH_C32(0x9f8660b8), SPH_C32(0x0412ec2b), + SPH_C32(0xadb4e974), SPH_C32(0x9f750008), SPH_C32(0xa9280dc5), + SPH_C32(0x1fe882c5), SPH_C32(0xadecce7a) }, + { SPH_C32(0x76a30028), SPH_C32(0x531b1665), SPH_C32(0x01e54046), + SPH_C32(0x7452079d), SPH_C32(0x4f7d000c), SPH_C32(0x255e82b2), + SPH_C32(0x822d3295), SPH_C32(0x02a6e7a0) }, + { SPH_C32(0xa6ab002c), SPH_C32(0xdf6d9912), SPH_C32(0x9c20f016), + SPH_C32(0xdb182e47), SPH_C32(0x24d4000c), SPH_C32(0x65b57b18), + SPH_C32(0x1a1f2ea8), SPH_C32(0x740a2093) }, + { SPH_C32(0xf3e40030), SPH_C32(0xc114970d), SPH_C32(0x05296a06), + SPH_C32(0x93f8f0a1), SPH_C32(0x724b0000), SPH_C32(0xad67ab9b), + SPH_C32(0x457d0b05), SPH_C32(0xd21db1c4) }, + { SPH_C32(0x23ec0034), SPH_C32(0x4d62187a), SPH_C32(0x98ecda56), + SPH_C32(0x3cb2d97b), SPH_C32(0x19e20000), SPH_C32(0xed8c5231), + SPH_C32(0xdd4f1738), SPH_C32(0xa4b176f7) }, + { SPH_C32(0x984d0030), SPH_C32(0x81ff6ea7), SPH_C32(0x9d1b763b), + SPH_C32(0xe5543792), SPH_C32(0xc9ea0004), SPH_C32(0x61fadd46), + SPH_C32(0x408aa768), SPH_C32(0x0bfb5f2d) }, + { SPH_C32(0x48450034), SPH_C32(0x0d89e1d0), SPH_C32(0x00dec66b), + SPH_C32(0x4a1e1e48), SPH_C32(0xa2430004), SPH_C32(0x211124ec), + SPH_C32(0xd8b8bb55), SPH_C32(0x7d57981e) }, + { SPH_C32(0x5b4a0038), SPH_C32(0xe16dae70), SPH_C32(0xfb5af907), + SPH_C32(0x2b51d890), SPH_C32(0x65570000), SPH_C32(0x1f0998df), + SPH_C32(0xdb17887b), SPH_C32(0x8ae5f99b) }, + { SPH_C32(0x8b42003c), SPH_C32(0x6d1b2107), SPH_C32(0x669f4957), + SPH_C32(0x841bf14a), SPH_C32(0x0efe0000), SPH_C32(0x5fe26175), + SPH_C32(0x43259446), SPH_C32(0xfc493ea8) }, + { SPH_C32(0x30e30038), SPH_C32(0xa18657da), SPH_C32(0x6368e53a), + SPH_C32(0x5dfd1fa3), SPH_C32(0xdef60004), SPH_C32(0xd394ee02), + SPH_C32(0xdee02416), SPH_C32(0x53031772) }, + { SPH_C32(0xe0eb003c), SPH_C32(0x2df0d8ad), SPH_C32(0xfead556a), + SPH_C32(0xf2b73679), SPH_C32(0xb55f0004), SPH_C32(0x937f17a8), + SPH_C32(0x46d2382b), SPH_C32(0x25afd041) }, + { SPH_C32(0xe4f80030), SPH_C32(0x737aa449), SPH_C32(0x9b43e978), + SPH_C32(0xcb00b8fe), SPH_C32(0xcdf90008), SPH_C32(0x3f70a1a2), + SPH_C32(0x25641b7a), SPH_C32(0x324cd1aa) }, + { SPH_C32(0x34f00034), SPH_C32(0xff0c2b3e), SPH_C32(0x06865928), + SPH_C32(0x644a9124), SPH_C32(0xa6500008), SPH_C32(0x7f9b5808), + SPH_C32(0xbd560747), SPH_C32(0x44e01699) }, + { SPH_C32(0x8f510030), SPH_C32(0x33915de3), SPH_C32(0x0371f545), + SPH_C32(0xbdac7fcd), SPH_C32(0x7658000c), SPH_C32(0xf3edd77f), + SPH_C32(0x2093b717), SPH_C32(0xebaa3f43) }, + { SPH_C32(0x5f590034), SPH_C32(0xbfe7d294), SPH_C32(0x9eb44515), + SPH_C32(0x12e65617), SPH_C32(0x1df1000c), SPH_C32(0xb3062ed5), + SPH_C32(0xb8a1ab2a), SPH_C32(0x9d06f870) }, + { SPH_C32(0x4c560038), SPH_C32(0x53039d34), SPH_C32(0x65307a79), + SPH_C32(0x73a990cf), SPH_C32(0xdae50008), SPH_C32(0x8d1e92e6), + SPH_C32(0xbb0e9804), SPH_C32(0x6ab499f5) }, + { SPH_C32(0x9c5e003c), SPH_C32(0xdf751243), SPH_C32(0xf8f5ca29), + SPH_C32(0xdce3b915), SPH_C32(0xb14c0008), SPH_C32(0xcdf56b4c), + SPH_C32(0x233c8439), SPH_C32(0x1c185ec6) }, + { SPH_C32(0x27ff0038), SPH_C32(0x13e8649e), SPH_C32(0xfd026644), + SPH_C32(0x050557fc), SPH_C32(0x6144000c), SPH_C32(0x4183e43b), + SPH_C32(0xbef93469), SPH_C32(0xb352771c) }, + { SPH_C32(0xf7f7003c), SPH_C32(0x9f9eebe9), SPH_C32(0x60c7d614), + SPH_C32(0xaa4f7e26), SPH_C32(0x0aed000c), SPH_C32(0x01681d91), + SPH_C32(0x26cb2854), SPH_C32(0xc5feb02f) }, + { SPH_C32(0x8c810020), SPH_C32(0xe53a837f), SPH_C32(0xc51a4af8), + SPH_C32(0x535b307c), SPH_C32(0x23170010), SPH_C32(0xed94d960), + SPH_C32(0xb99a2d07), SPH_C32(0xa34ae1a5) }, + { SPH_C32(0x5c890024), SPH_C32(0x694c0c08), SPH_C32(0x58dffaa8), + SPH_C32(0xfc1119a6), SPH_C32(0x48be0010), SPH_C32(0xad7f20ca), + SPH_C32(0x21a8313a), SPH_C32(0xd5e62696) }, + { SPH_C32(0xe7280020), SPH_C32(0xa5d17ad5), SPH_C32(0x5d2856c5), + SPH_C32(0x25f7f74f), SPH_C32(0x98b60014), SPH_C32(0x2109afbd), + SPH_C32(0xbc6d816a), SPH_C32(0x7aac0f4c) }, + { SPH_C32(0x37200024), SPH_C32(0x29a7f5a2), SPH_C32(0xc0ede695), + SPH_C32(0x8abdde95), SPH_C32(0xf31f0014), SPH_C32(0x61e25617), + SPH_C32(0x245f9d57), SPH_C32(0x0c00c87f) }, + { SPH_C32(0x242f0028), SPH_C32(0xc543ba02), SPH_C32(0x3b69d9f9), + SPH_C32(0xebf2184d), SPH_C32(0x340b0010), SPH_C32(0x5ffaea24), + SPH_C32(0x27f0ae79), SPH_C32(0xfbb2a9fa) }, + { SPH_C32(0xf427002c), SPH_C32(0x49353575), SPH_C32(0xa6ac69a9), + SPH_C32(0x44b83197), SPH_C32(0x5fa20010), SPH_C32(0x1f11138e), + SPH_C32(0xbfc2b244), SPH_C32(0x8d1e6ec9) }, + { SPH_C32(0x4f860028), SPH_C32(0x85a843a8), SPH_C32(0xa35bc5c4), + SPH_C32(0x9d5edf7e), SPH_C32(0x8faa0014), SPH_C32(0x93679cf9), + SPH_C32(0x22070214), SPH_C32(0x22544713) }, + { SPH_C32(0x9f8e002c), SPH_C32(0x09deccdf), SPH_C32(0x3e9e7594), + SPH_C32(0x3214f6a4), SPH_C32(0xe4030014), SPH_C32(0xd38c6553), + SPH_C32(0xba351e29), SPH_C32(0x54f88020) }, + { SPH_C32(0x9b9d0020), SPH_C32(0x5754b03b), SPH_C32(0x5b70c986), + SPH_C32(0x0ba37823), SPH_C32(0x9ca50018), SPH_C32(0x7f83d359), + SPH_C32(0xd9833d78), SPH_C32(0x431b81cb) }, + { SPH_C32(0x4b950024), SPH_C32(0xdb223f4c), SPH_C32(0xc6b579d6), + SPH_C32(0xa4e951f9), SPH_C32(0xf70c0018), SPH_C32(0x3f682af3), + SPH_C32(0x41b12145), SPH_C32(0x35b746f8) }, + { SPH_C32(0xf0340020), SPH_C32(0x17bf4991), SPH_C32(0xc342d5bb), + SPH_C32(0x7d0fbf10), SPH_C32(0x2704001c), SPH_C32(0xb31ea584), + SPH_C32(0xdc749115), SPH_C32(0x9afd6f22) }, + { SPH_C32(0x203c0024), SPH_C32(0x9bc9c6e6), SPH_C32(0x5e8765eb), + SPH_C32(0xd24596ca), SPH_C32(0x4cad001c), SPH_C32(0xf3f55c2e), + SPH_C32(0x44468d28), SPH_C32(0xec51a811) }, + { SPH_C32(0x33330028), SPH_C32(0x772d8946), SPH_C32(0xa5035a87), + SPH_C32(0xb30a5012), SPH_C32(0x8bb90018), SPH_C32(0xcdede01d), + SPH_C32(0x47e9be06), SPH_C32(0x1be3c994) }, + { SPH_C32(0xe33b002c), SPH_C32(0xfb5b0631), SPH_C32(0x38c6ead7), + SPH_C32(0x1c4079c8), SPH_C32(0xe0100018), SPH_C32(0x8d0619b7), + SPH_C32(0xdfdba23b), SPH_C32(0x6d4f0ea7) }, + { SPH_C32(0x589a0028), SPH_C32(0x37c670ec), SPH_C32(0x3d3146ba), + SPH_C32(0xc5a69721), SPH_C32(0x3018001c), SPH_C32(0x017096c0), + SPH_C32(0x421e126b), SPH_C32(0xc205277d) }, + { SPH_C32(0x8892002c), SPH_C32(0xbbb0ff9b), SPH_C32(0xa0f4f6ea), + SPH_C32(0x6aecbefb), SPH_C32(0x5bb1001c), SPH_C32(0x419b6f6a), + SPH_C32(0xda2c0e56), SPH_C32(0xb4a9e04e) }, + { SPH_C32(0xdddd0030), SPH_C32(0xa5c9f184), SPH_C32(0x39fd6cfa), + SPH_C32(0x220c601d), SPH_C32(0x0d2e0010), SPH_C32(0x8949bfe9), + SPH_C32(0x854e2bfb), SPH_C32(0x12be7119) }, + { SPH_C32(0x0dd50034), SPH_C32(0x29bf7ef3), SPH_C32(0xa438dcaa), + SPH_C32(0x8d4649c7), SPH_C32(0x66870010), SPH_C32(0xc9a24643), + SPH_C32(0x1d7c37c6), SPH_C32(0x6412b62a) }, + { SPH_C32(0xb6740030), SPH_C32(0xe522082e), SPH_C32(0xa1cf70c7), + SPH_C32(0x54a0a72e), SPH_C32(0xb68f0014), SPH_C32(0x45d4c934), + SPH_C32(0x80b98796), SPH_C32(0xcb589ff0) }, + { SPH_C32(0x667c0034), SPH_C32(0x69548759), SPH_C32(0x3c0ac097), + SPH_C32(0xfbea8ef4), SPH_C32(0xdd260014), SPH_C32(0x053f309e), + SPH_C32(0x188b9bab), SPH_C32(0xbdf458c3) }, + { SPH_C32(0x75730038), SPH_C32(0x85b0c8f9), SPH_C32(0xc78efffb), + SPH_C32(0x9aa5482c), SPH_C32(0x1a320010), SPH_C32(0x3b278cad), + SPH_C32(0x1b24a885), SPH_C32(0x4a463946) }, + { SPH_C32(0xa57b003c), SPH_C32(0x09c6478e), SPH_C32(0x5a4b4fab), + SPH_C32(0x35ef61f6), SPH_C32(0x719b0010), SPH_C32(0x7bcc7507), + SPH_C32(0x8316b4b8), SPH_C32(0x3ceafe75) }, + { SPH_C32(0x1eda0038), SPH_C32(0xc55b3153), SPH_C32(0x5fbce3c6), + SPH_C32(0xec098f1f), SPH_C32(0xa1930014), SPH_C32(0xf7bafa70), + SPH_C32(0x1ed304e8), SPH_C32(0x93a0d7af) }, + { SPH_C32(0xced2003c), SPH_C32(0x492dbe24), SPH_C32(0xc2795396), + SPH_C32(0x4343a6c5), SPH_C32(0xca3a0014), SPH_C32(0xb75103da), + SPH_C32(0x86e118d5), SPH_C32(0xe50c109c) }, + { SPH_C32(0xcac10030), SPH_C32(0x17a7c2c0), SPH_C32(0xa797ef84), + SPH_C32(0x7af42842), SPH_C32(0xb29c0018), SPH_C32(0x1b5eb5d0), + SPH_C32(0xe5573b84), SPH_C32(0xf2ef1177) }, + { SPH_C32(0x1ac90034), SPH_C32(0x9bd14db7), SPH_C32(0x3a525fd4), + SPH_C32(0xd5be0198), SPH_C32(0xd9350018), SPH_C32(0x5bb54c7a), + SPH_C32(0x7d6527b9), SPH_C32(0x8443d644) }, + { SPH_C32(0xa1680030), SPH_C32(0x574c3b6a), SPH_C32(0x3fa5f3b9), + SPH_C32(0x0c58ef71), SPH_C32(0x093d001c), SPH_C32(0xd7c3c30d), + SPH_C32(0xe0a097e9), SPH_C32(0x2b09ff9e) }, + { SPH_C32(0x71600034), SPH_C32(0xdb3ab41d), SPH_C32(0xa26043e9), + SPH_C32(0xa312c6ab), SPH_C32(0x6294001c), SPH_C32(0x97283aa7), + SPH_C32(0x78928bd4), SPH_C32(0x5da538ad) }, + { SPH_C32(0x626f0038), SPH_C32(0x37defbbd), SPH_C32(0x59e47c85), + SPH_C32(0xc25d0073), SPH_C32(0xa5800018), SPH_C32(0xa9308694), + SPH_C32(0x7b3db8fa), SPH_C32(0xaa175928) }, + { SPH_C32(0xb267003c), SPH_C32(0xbba874ca), SPH_C32(0xc421ccd5), + SPH_C32(0x6d1729a9), SPH_C32(0xce290018), SPH_C32(0xe9db7f3e), + SPH_C32(0xe30fa4c7), SPH_C32(0xdcbb9e1b) }, + { SPH_C32(0x09c60038), SPH_C32(0x77350217), SPH_C32(0xc1d660b8), + SPH_C32(0xb4f1c740), SPH_C32(0x1e21001c), SPH_C32(0x65adf049), + SPH_C32(0x7eca1497), SPH_C32(0x73f1b7c1) }, + { SPH_C32(0xd9ce003c), SPH_C32(0xfb438d60), SPH_C32(0x5c13d0e8), + SPH_C32(0x1bbbee9a), SPH_C32(0x7588001c), SPH_C32(0x254609e3), + SPH_C32(0xe6f808aa), SPH_C32(0x055d70f2) } +}; + +static const sph_u32 T256_28[16][8] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000) }, + { SPH_C32(0xc04e0001), SPH_C32(0x33b9c010), SPH_C32(0xae0ebb05), + SPH_C32(0xb5a4c63b), SPH_C32(0xc8f10000), SPH_C32(0x0b2de782), + SPH_C32(0x6bf648a4), SPH_C32(0x539cbdbf) }, + { SPH_C32(0xc8f10000), SPH_C32(0x0b2de782), SPH_C32(0x6bf648a4), + SPH_C32(0x539cbdbf), SPH_C32(0x08bf0001), SPH_C32(0x38942792), + SPH_C32(0xc5f8f3a1), SPH_C32(0xe6387b84) }, + { SPH_C32(0x08bf0001), SPH_C32(0x38942792), SPH_C32(0xc5f8f3a1), + SPH_C32(0xe6387b84), SPH_C32(0xc04e0001), SPH_C32(0x33b9c010), + SPH_C32(0xae0ebb05), SPH_C32(0xb5a4c63b) }, + { SPH_C32(0x88230002), SPH_C32(0x5fe7a7b3), SPH_C32(0x99e585aa), + SPH_C32(0x8d75f7f1), SPH_C32(0x51ac0000), SPH_C32(0x25e30f14), + SPH_C32(0x79e22a4c), SPH_C32(0x1298bd46) }, + { SPH_C32(0x486d0003), SPH_C32(0x6c5e67a3), SPH_C32(0x37eb3eaf), + SPH_C32(0x38d131ca), SPH_C32(0x995d0000), SPH_C32(0x2ecee896), + SPH_C32(0x121462e8), SPH_C32(0x410400f9) }, + { SPH_C32(0x40d20002), SPH_C32(0x54ca4031), SPH_C32(0xf213cd0e), + SPH_C32(0xdee94a4e), SPH_C32(0x59130001), SPH_C32(0x1d772886), + SPH_C32(0xbc1ad9ed), SPH_C32(0xf4a0c6c2) }, + { SPH_C32(0x809c0003), SPH_C32(0x67738021), SPH_C32(0x5c1d760b), + SPH_C32(0x6b4d8c75), SPH_C32(0x91e20001), SPH_C32(0x165acf04), + SPH_C32(0xd7ec9149), SPH_C32(0xa73c7b7d) }, + { SPH_C32(0x51ac0000), SPH_C32(0x25e30f14), SPH_C32(0x79e22a4c), + SPH_C32(0x1298bd46), SPH_C32(0xd98f0002), SPH_C32(0x7a04a8a7), + SPH_C32(0xe007afe6), SPH_C32(0x9fed4ab7) }, + { SPH_C32(0x91e20001), SPH_C32(0x165acf04), SPH_C32(0xd7ec9149), + SPH_C32(0xa73c7b7d), SPH_C32(0x117e0002), SPH_C32(0x71294f25), + SPH_C32(0x8bf1e742), SPH_C32(0xcc71f708) }, + { SPH_C32(0x995d0000), SPH_C32(0x2ecee896), SPH_C32(0x121462e8), + SPH_C32(0x410400f9), SPH_C32(0xd1300003), SPH_C32(0x42908f35), + SPH_C32(0x25ff5c47), SPH_C32(0x79d53133) }, + { SPH_C32(0x59130001), SPH_C32(0x1d772886), SPH_C32(0xbc1ad9ed), + SPH_C32(0xf4a0c6c2), SPH_C32(0x19c10003), SPH_C32(0x49bd68b7), + SPH_C32(0x4e0914e3), SPH_C32(0x2a498c8c) }, + { SPH_C32(0xd98f0002), SPH_C32(0x7a04a8a7), SPH_C32(0xe007afe6), + SPH_C32(0x9fed4ab7), SPH_C32(0x88230002), SPH_C32(0x5fe7a7b3), + SPH_C32(0x99e585aa), SPH_C32(0x8d75f7f1) }, + { SPH_C32(0x19c10003), SPH_C32(0x49bd68b7), SPH_C32(0x4e0914e3), + SPH_C32(0x2a498c8c), SPH_C32(0x40d20002), SPH_C32(0x54ca4031), + SPH_C32(0xf213cd0e), SPH_C32(0xdee94a4e) }, + { SPH_C32(0x117e0002), SPH_C32(0x71294f25), SPH_C32(0x8bf1e742), + SPH_C32(0xcc71f708), SPH_C32(0x809c0003), SPH_C32(0x67738021), + SPH_C32(0x5c1d760b), SPH_C32(0x6b4d8c75) }, + { SPH_C32(0xd1300003), SPH_C32(0x42908f35), SPH_C32(0x25ff5c47), + SPH_C32(0x79d53133), SPH_C32(0x486d0003), SPH_C32(0x6c5e67a3), + SPH_C32(0x37eb3eaf), SPH_C32(0x38d131ca) } +}; + +#define INPUT_SMALL do { \ + unsigned acc = buf[0]; \ + const sph_u32 *rp; \ + rp = &T256_0[acc >> 1][0]; \ + m0 = rp[0]; \ + m1 = rp[1]; \ + m2 = rp[2]; \ + m3 = rp[3]; \ + m4 = rp[4]; \ + m5 = rp[5]; \ + m6 = rp[6]; \ + m7 = rp[7]; \ + acc = (acc << 8) | buf[1]; \ + rp = &T256_7[(acc >> 2) & 0x7f][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + acc = (acc << 8) | buf[2]; \ + rp = &T256_14[(acc >> 3) & 0x7f][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + acc = (acc << 8) | buf[3]; \ + rp = &T256_21[(acc >> 4) & 0x7f][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + rp = &T256_28[acc & 0x0f][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + } while (0) + +#endif + +#if SPH_HAMSI_EXPAND_SMALL == 8 + +static const sph_u32 T256_0[256][8] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000) }, + { SPH_C32(0x74951000), SPH_C32(0x5a2b467e), SPH_C32(0x88fd1d2b), + SPH_C32(0x1ee68292), SPH_C32(0xcba90000), SPH_C32(0x90273769), + SPH_C32(0xbbdcf407), SPH_C32(0xd0f4af61) }, + { SPH_C32(0xcba90000), SPH_C32(0x90273769), SPH_C32(0xbbdcf407), + SPH_C32(0xd0f4af61), SPH_C32(0xbf3c1000), SPH_C32(0xca0c7117), + SPH_C32(0x3321e92c), SPH_C32(0xce122df3) }, + { SPH_C32(0xbf3c1000), SPH_C32(0xca0c7117), SPH_C32(0x3321e92c), + SPH_C32(0xce122df3), SPH_C32(0x74951000), SPH_C32(0x5a2b467e), + SPH_C32(0x88fd1d2b), SPH_C32(0x1ee68292) }, + { SPH_C32(0xe92a2000), SPH_C32(0xb4578cfc), SPH_C32(0x11fa3a57), + SPH_C32(0x3dc90524), SPH_C32(0x97530000), SPH_C32(0x204f6ed3), + SPH_C32(0x77b9e80f), SPH_C32(0xa1ec5ec1) }, + { SPH_C32(0x9dbf3000), SPH_C32(0xee7cca82), SPH_C32(0x9907277c), + SPH_C32(0x232f87b6), SPH_C32(0x5cfa0000), SPH_C32(0xb06859ba), + SPH_C32(0xcc651c08), SPH_C32(0x7118f1a0) }, + { SPH_C32(0x22832000), SPH_C32(0x2470bb95), SPH_C32(0xaa26ce50), + SPH_C32(0xed3daa45), SPH_C32(0x286f1000), SPH_C32(0xea431fc4), + SPH_C32(0x44980123), SPH_C32(0x6ffe7332) }, + { SPH_C32(0x56163000), SPH_C32(0x7e5bfdeb), SPH_C32(0x22dbd37b), + SPH_C32(0xf3db28d7), SPH_C32(0xe3c61000), SPH_C32(0x7a6428ad), + SPH_C32(0xff44f524), SPH_C32(0xbf0adc53) }, + { SPH_C32(0x97530000), SPH_C32(0x204f6ed3), SPH_C32(0x77b9e80f), + SPH_C32(0xa1ec5ec1), SPH_C32(0x7e792000), SPH_C32(0x9418e22f), + SPH_C32(0x6643d258), SPH_C32(0x9c255be5) }, + { SPH_C32(0xe3c61000), SPH_C32(0x7a6428ad), SPH_C32(0xff44f524), + SPH_C32(0xbf0adc53), SPH_C32(0xb5d02000), SPH_C32(0x043fd546), + SPH_C32(0xdd9f265f), SPH_C32(0x4cd1f484) }, + { SPH_C32(0x5cfa0000), SPH_C32(0xb06859ba), SPH_C32(0xcc651c08), + SPH_C32(0x7118f1a0), SPH_C32(0xc1453000), SPH_C32(0x5e149338), + SPH_C32(0x55623b74), SPH_C32(0x52377616) }, + { SPH_C32(0x286f1000), SPH_C32(0xea431fc4), SPH_C32(0x44980123), + SPH_C32(0x6ffe7332), SPH_C32(0x0aec3000), SPH_C32(0xce33a451), + SPH_C32(0xeebecf73), SPH_C32(0x82c3d977) }, + { SPH_C32(0x7e792000), SPH_C32(0x9418e22f), SPH_C32(0x6643d258), + SPH_C32(0x9c255be5), SPH_C32(0xe92a2000), SPH_C32(0xb4578cfc), + SPH_C32(0x11fa3a57), SPH_C32(0x3dc90524) }, + { SPH_C32(0x0aec3000), SPH_C32(0xce33a451), SPH_C32(0xeebecf73), + SPH_C32(0x82c3d977), SPH_C32(0x22832000), SPH_C32(0x2470bb95), + SPH_C32(0xaa26ce50), SPH_C32(0xed3daa45) }, + { SPH_C32(0xb5d02000), SPH_C32(0x043fd546), SPH_C32(0xdd9f265f), + SPH_C32(0x4cd1f484), SPH_C32(0x56163000), SPH_C32(0x7e5bfdeb), + SPH_C32(0x22dbd37b), SPH_C32(0xf3db28d7) }, + { SPH_C32(0xc1453000), SPH_C32(0x5e149338), SPH_C32(0x55623b74), + SPH_C32(0x52377616), SPH_C32(0x9dbf3000), SPH_C32(0xee7cca82), + SPH_C32(0x9907277c), SPH_C32(0x232f87b6) }, + { SPH_C32(0x121b4000), SPH_C32(0x5b17d9e8), SPH_C32(0x8dfacfab), + SPH_C32(0xce36cc72), SPH_C32(0xe6570000), SPH_C32(0x4bb33a25), + SPH_C32(0x848598ba), SPH_C32(0x1041003e) }, + { SPH_C32(0x668e5000), SPH_C32(0x013c9f96), SPH_C32(0x0507d280), + SPH_C32(0xd0d04ee0), SPH_C32(0x2dfe0000), SPH_C32(0xdb940d4c), + SPH_C32(0x3f596cbd), SPH_C32(0xc0b5af5f) }, + { SPH_C32(0xd9b24000), SPH_C32(0xcb30ee81), SPH_C32(0x36263bac), + SPH_C32(0x1ec26313), SPH_C32(0x596b1000), SPH_C32(0x81bf4b32), + SPH_C32(0xb7a47196), SPH_C32(0xde532dcd) }, + { SPH_C32(0xad275000), SPH_C32(0x911ba8ff), SPH_C32(0xbedb2687), + SPH_C32(0x0024e181), SPH_C32(0x92c21000), SPH_C32(0x11987c5b), + SPH_C32(0x0c788591), SPH_C32(0x0ea782ac) }, + { SPH_C32(0xfb316000), SPH_C32(0xef405514), SPH_C32(0x9c00f5fc), + SPH_C32(0xf3ffc956), SPH_C32(0x71040000), SPH_C32(0x6bfc54f6), + SPH_C32(0xf33c70b5), SPH_C32(0xb1ad5eff) }, + { SPH_C32(0x8fa47000), SPH_C32(0xb56b136a), SPH_C32(0x14fde8d7), + SPH_C32(0xed194bc4), SPH_C32(0xbaad0000), SPH_C32(0xfbdb639f), + SPH_C32(0x48e084b2), SPH_C32(0x6159f19e) }, + { SPH_C32(0x30986000), SPH_C32(0x7f67627d), SPH_C32(0x27dc01fb), + SPH_C32(0x230b6637), SPH_C32(0xce381000), SPH_C32(0xa1f025e1), + SPH_C32(0xc01d9999), SPH_C32(0x7fbf730c) }, + { SPH_C32(0x440d7000), SPH_C32(0x254c2403), SPH_C32(0xaf211cd0), + SPH_C32(0x3dede4a5), SPH_C32(0x05911000), SPH_C32(0x31d71288), + SPH_C32(0x7bc16d9e), SPH_C32(0xaf4bdc6d) }, + { SPH_C32(0x85484000), SPH_C32(0x7b58b73b), SPH_C32(0xfa4327a4), + SPH_C32(0x6fda92b3), SPH_C32(0x982e2000), SPH_C32(0xdfabd80a), + SPH_C32(0xe2c64ae2), SPH_C32(0x8c645bdb) }, + { SPH_C32(0xf1dd5000), SPH_C32(0x2173f145), SPH_C32(0x72be3a8f), + SPH_C32(0x713c1021), SPH_C32(0x53872000), SPH_C32(0x4f8cef63), + SPH_C32(0x591abee5), SPH_C32(0x5c90f4ba) }, + { SPH_C32(0x4ee14000), SPH_C32(0xeb7f8052), SPH_C32(0x419fd3a3), + SPH_C32(0xbf2e3dd2), SPH_C32(0x27123000), SPH_C32(0x15a7a91d), + SPH_C32(0xd1e7a3ce), SPH_C32(0x42767628) }, + { SPH_C32(0x3a745000), SPH_C32(0xb154c62c), SPH_C32(0xc962ce88), + SPH_C32(0xa1c8bf40), SPH_C32(0xecbb3000), SPH_C32(0x85809e74), + SPH_C32(0x6a3b57c9), SPH_C32(0x9282d949) }, + { SPH_C32(0x6c626000), SPH_C32(0xcf0f3bc7), SPH_C32(0xebb91df3), + SPH_C32(0x52139797), SPH_C32(0x0f7d2000), SPH_C32(0xffe4b6d9), + SPH_C32(0x957fa2ed), SPH_C32(0x2d88051a) }, + { SPH_C32(0x18f77000), SPH_C32(0x95247db9), SPH_C32(0x634400d8), + SPH_C32(0x4cf51505), SPH_C32(0xc4d42000), SPH_C32(0x6fc381b0), + SPH_C32(0x2ea356ea), SPH_C32(0xfd7caa7b) }, + { SPH_C32(0xa7cb6000), SPH_C32(0x5f280cae), SPH_C32(0x5065e9f4), + SPH_C32(0x82e738f6), SPH_C32(0xb0413000), SPH_C32(0x35e8c7ce), + SPH_C32(0xa65e4bc1), SPH_C32(0xe39a28e9) }, + { SPH_C32(0xd35e7000), SPH_C32(0x05034ad0), SPH_C32(0xd898f4df), + SPH_C32(0x9c01ba64), SPH_C32(0x7be83000), SPH_C32(0xa5cff0a7), + SPH_C32(0x1d82bfc6), SPH_C32(0x336e8788) }, + { SPH_C32(0xe6570000), SPH_C32(0x4bb33a25), SPH_C32(0x848598ba), + SPH_C32(0x1041003e), SPH_C32(0xf44c4000), SPH_C32(0x10a4e3cd), + SPH_C32(0x097f5711), SPH_C32(0xde77cc4c) }, + { SPH_C32(0x92c21000), SPH_C32(0x11987c5b), SPH_C32(0x0c788591), + SPH_C32(0x0ea782ac), SPH_C32(0x3fe54000), SPH_C32(0x8083d4a4), + SPH_C32(0xb2a3a316), SPH_C32(0x0e83632d) }, + { SPH_C32(0x2dfe0000), SPH_C32(0xdb940d4c), SPH_C32(0x3f596cbd), + SPH_C32(0xc0b5af5f), SPH_C32(0x4b705000), SPH_C32(0xdaa892da), + SPH_C32(0x3a5ebe3d), SPH_C32(0x1065e1bf) }, + { SPH_C32(0x596b1000), SPH_C32(0x81bf4b32), SPH_C32(0xb7a47196), + SPH_C32(0xde532dcd), SPH_C32(0x80d95000), SPH_C32(0x4a8fa5b3), + SPH_C32(0x81824a3a), SPH_C32(0xc0914ede) }, + { SPH_C32(0x0f7d2000), SPH_C32(0xffe4b6d9), SPH_C32(0x957fa2ed), + SPH_C32(0x2d88051a), SPH_C32(0x631f4000), SPH_C32(0x30eb8d1e), + SPH_C32(0x7ec6bf1e), SPH_C32(0x7f9b928d) }, + { SPH_C32(0x7be83000), SPH_C32(0xa5cff0a7), SPH_C32(0x1d82bfc6), + SPH_C32(0x336e8788), SPH_C32(0xa8b64000), SPH_C32(0xa0ccba77), + SPH_C32(0xc51a4b19), SPH_C32(0xaf6f3dec) }, + { SPH_C32(0xc4d42000), SPH_C32(0x6fc381b0), SPH_C32(0x2ea356ea), + SPH_C32(0xfd7caa7b), SPH_C32(0xdc235000), SPH_C32(0xfae7fc09), + SPH_C32(0x4de75632), SPH_C32(0xb189bf7e) }, + { SPH_C32(0xb0413000), SPH_C32(0x35e8c7ce), SPH_C32(0xa65e4bc1), + SPH_C32(0xe39a28e9), SPH_C32(0x178a5000), SPH_C32(0x6ac0cb60), + SPH_C32(0xf63ba235), SPH_C32(0x617d101f) }, + { SPH_C32(0x71040000), SPH_C32(0x6bfc54f6), SPH_C32(0xf33c70b5), + SPH_C32(0xb1ad5eff), SPH_C32(0x8a356000), SPH_C32(0x84bc01e2), + SPH_C32(0x6f3c8549), SPH_C32(0x425297a9) }, + { SPH_C32(0x05911000), SPH_C32(0x31d71288), SPH_C32(0x7bc16d9e), + SPH_C32(0xaf4bdc6d), SPH_C32(0x419c6000), SPH_C32(0x149b368b), + SPH_C32(0xd4e0714e), SPH_C32(0x92a638c8) }, + { SPH_C32(0xbaad0000), SPH_C32(0xfbdb639f), SPH_C32(0x48e084b2), + SPH_C32(0x6159f19e), SPH_C32(0x35097000), SPH_C32(0x4eb070f5), + SPH_C32(0x5c1d6c65), SPH_C32(0x8c40ba5a) }, + { SPH_C32(0xce381000), SPH_C32(0xa1f025e1), SPH_C32(0xc01d9999), + SPH_C32(0x7fbf730c), SPH_C32(0xfea07000), SPH_C32(0xde97479c), + SPH_C32(0xe7c19862), SPH_C32(0x5cb4153b) }, + { SPH_C32(0x982e2000), SPH_C32(0xdfabd80a), SPH_C32(0xe2c64ae2), + SPH_C32(0x8c645bdb), SPH_C32(0x1d666000), SPH_C32(0xa4f36f31), + SPH_C32(0x18856d46), SPH_C32(0xe3bec968) }, + { SPH_C32(0xecbb3000), SPH_C32(0x85809e74), SPH_C32(0x6a3b57c9), + SPH_C32(0x9282d949), SPH_C32(0xd6cf6000), SPH_C32(0x34d45858), + SPH_C32(0xa3599941), SPH_C32(0x334a6609) }, + { SPH_C32(0x53872000), SPH_C32(0x4f8cef63), SPH_C32(0x591abee5), + SPH_C32(0x5c90f4ba), SPH_C32(0xa25a7000), SPH_C32(0x6eff1e26), + SPH_C32(0x2ba4846a), SPH_C32(0x2dace49b) }, + { SPH_C32(0x27123000), SPH_C32(0x15a7a91d), SPH_C32(0xd1e7a3ce), + SPH_C32(0x42767628), SPH_C32(0x69f37000), SPH_C32(0xfed8294f), + SPH_C32(0x9078706d), SPH_C32(0xfd584bfa) }, + { SPH_C32(0xf44c4000), SPH_C32(0x10a4e3cd), SPH_C32(0x097f5711), + SPH_C32(0xde77cc4c), SPH_C32(0x121b4000), SPH_C32(0x5b17d9e8), + SPH_C32(0x8dfacfab), SPH_C32(0xce36cc72) }, + { SPH_C32(0x80d95000), SPH_C32(0x4a8fa5b3), SPH_C32(0x81824a3a), + SPH_C32(0xc0914ede), SPH_C32(0xd9b24000), SPH_C32(0xcb30ee81), + SPH_C32(0x36263bac), SPH_C32(0x1ec26313) }, + { SPH_C32(0x3fe54000), SPH_C32(0x8083d4a4), SPH_C32(0xb2a3a316), + SPH_C32(0x0e83632d), SPH_C32(0xad275000), SPH_C32(0x911ba8ff), + SPH_C32(0xbedb2687), SPH_C32(0x0024e181) }, + { SPH_C32(0x4b705000), SPH_C32(0xdaa892da), SPH_C32(0x3a5ebe3d), + SPH_C32(0x1065e1bf), SPH_C32(0x668e5000), SPH_C32(0x013c9f96), + SPH_C32(0x0507d280), SPH_C32(0xd0d04ee0) }, + { SPH_C32(0x1d666000), SPH_C32(0xa4f36f31), SPH_C32(0x18856d46), + SPH_C32(0xe3bec968), SPH_C32(0x85484000), SPH_C32(0x7b58b73b), + SPH_C32(0xfa4327a4), SPH_C32(0x6fda92b3) }, + { SPH_C32(0x69f37000), SPH_C32(0xfed8294f), SPH_C32(0x9078706d), + SPH_C32(0xfd584bfa), SPH_C32(0x4ee14000), SPH_C32(0xeb7f8052), + SPH_C32(0x419fd3a3), SPH_C32(0xbf2e3dd2) }, + { SPH_C32(0xd6cf6000), SPH_C32(0x34d45858), SPH_C32(0xa3599941), + SPH_C32(0x334a6609), SPH_C32(0x3a745000), SPH_C32(0xb154c62c), + SPH_C32(0xc962ce88), SPH_C32(0xa1c8bf40) }, + { SPH_C32(0xa25a7000), SPH_C32(0x6eff1e26), SPH_C32(0x2ba4846a), + SPH_C32(0x2dace49b), SPH_C32(0xf1dd5000), SPH_C32(0x2173f145), + SPH_C32(0x72be3a8f), SPH_C32(0x713c1021) }, + { SPH_C32(0x631f4000), SPH_C32(0x30eb8d1e), SPH_C32(0x7ec6bf1e), + SPH_C32(0x7f9b928d), SPH_C32(0x6c626000), SPH_C32(0xcf0f3bc7), + SPH_C32(0xebb91df3), SPH_C32(0x52139797) }, + { SPH_C32(0x178a5000), SPH_C32(0x6ac0cb60), SPH_C32(0xf63ba235), + SPH_C32(0x617d101f), SPH_C32(0xa7cb6000), SPH_C32(0x5f280cae), + SPH_C32(0x5065e9f4), SPH_C32(0x82e738f6) }, + { SPH_C32(0xa8b64000), SPH_C32(0xa0ccba77), SPH_C32(0xc51a4b19), + SPH_C32(0xaf6f3dec), SPH_C32(0xd35e7000), SPH_C32(0x05034ad0), + SPH_C32(0xd898f4df), SPH_C32(0x9c01ba64) }, + { SPH_C32(0xdc235000), SPH_C32(0xfae7fc09), SPH_C32(0x4de75632), + SPH_C32(0xb189bf7e), SPH_C32(0x18f77000), SPH_C32(0x95247db9), + SPH_C32(0x634400d8), SPH_C32(0x4cf51505) }, + { SPH_C32(0x8a356000), SPH_C32(0x84bc01e2), SPH_C32(0x6f3c8549), + SPH_C32(0x425297a9), SPH_C32(0xfb316000), SPH_C32(0xef405514), + SPH_C32(0x9c00f5fc), SPH_C32(0xf3ffc956) }, + { SPH_C32(0xfea07000), SPH_C32(0xde97479c), SPH_C32(0xe7c19862), + SPH_C32(0x5cb4153b), SPH_C32(0x30986000), SPH_C32(0x7f67627d), + SPH_C32(0x27dc01fb), SPH_C32(0x230b6637) }, + { SPH_C32(0x419c6000), SPH_C32(0x149b368b), SPH_C32(0xd4e0714e), + SPH_C32(0x92a638c8), SPH_C32(0x440d7000), SPH_C32(0x254c2403), + SPH_C32(0xaf211cd0), SPH_C32(0x3dede4a5) }, + { SPH_C32(0x35097000), SPH_C32(0x4eb070f5), SPH_C32(0x5c1d6c65), + SPH_C32(0x8c40ba5a), SPH_C32(0x8fa47000), SPH_C32(0xb56b136a), + SPH_C32(0x14fde8d7), SPH_C32(0xed194bc4) }, + { SPH_C32(0xe4788000), SPH_C32(0x859673c1), SPH_C32(0xb5fb2452), + SPH_C32(0x29cc5edf), SPH_C32(0x045f0000), SPH_C32(0x9c4a93c9), + SPH_C32(0x62fc79d0), SPH_C32(0x731ebdc2) }, + { SPH_C32(0x90ed9000), SPH_C32(0xdfbd35bf), SPH_C32(0x3d063979), + SPH_C32(0x372adc4d), SPH_C32(0xcff60000), SPH_C32(0x0c6da4a0), + SPH_C32(0xd9208dd7), SPH_C32(0xa3ea12a3) }, + { SPH_C32(0x2fd18000), SPH_C32(0x15b144a8), SPH_C32(0x0e27d055), + SPH_C32(0xf938f1be), SPH_C32(0xbb631000), SPH_C32(0x5646e2de), + SPH_C32(0x51dd90fc), SPH_C32(0xbd0c9031) }, + { SPH_C32(0x5b449000), SPH_C32(0x4f9a02d6), SPH_C32(0x86dacd7e), + SPH_C32(0xe7de732c), SPH_C32(0x70ca1000), SPH_C32(0xc661d5b7), + SPH_C32(0xea0164fb), SPH_C32(0x6df83f50) }, + { SPH_C32(0x0d52a000), SPH_C32(0x31c1ff3d), SPH_C32(0xa4011e05), + SPH_C32(0x14055bfb), SPH_C32(0x930c0000), SPH_C32(0xbc05fd1a), + SPH_C32(0x154591df), SPH_C32(0xd2f2e303) }, + { SPH_C32(0x79c7b000), SPH_C32(0x6beab943), SPH_C32(0x2cfc032e), + SPH_C32(0x0ae3d969), SPH_C32(0x58a50000), SPH_C32(0x2c22ca73), + SPH_C32(0xae9965d8), SPH_C32(0x02064c62) }, + { SPH_C32(0xc6fba000), SPH_C32(0xa1e6c854), SPH_C32(0x1fddea02), + SPH_C32(0xc4f1f49a), SPH_C32(0x2c301000), SPH_C32(0x76098c0d), + SPH_C32(0x266478f3), SPH_C32(0x1ce0cef0) }, + { SPH_C32(0xb26eb000), SPH_C32(0xfbcd8e2a), SPH_C32(0x9720f729), + SPH_C32(0xda177608), SPH_C32(0xe7991000), SPH_C32(0xe62ebb64), + SPH_C32(0x9db88cf4), SPH_C32(0xcc146191) }, + { SPH_C32(0x732b8000), SPH_C32(0xa5d91d12), SPH_C32(0xc242cc5d), + SPH_C32(0x8820001e), SPH_C32(0x7a262000), SPH_C32(0x085271e6), + SPH_C32(0x04bfab88), SPH_C32(0xef3be627) }, + { SPH_C32(0x07be9000), SPH_C32(0xfff25b6c), SPH_C32(0x4abfd176), + SPH_C32(0x96c6828c), SPH_C32(0xb18f2000), SPH_C32(0x9875468f), + SPH_C32(0xbf635f8f), SPH_C32(0x3fcf4946) }, + { SPH_C32(0xb8828000), SPH_C32(0x35fe2a7b), SPH_C32(0x799e385a), + SPH_C32(0x58d4af7f), SPH_C32(0xc51a3000), SPH_C32(0xc25e00f1), + SPH_C32(0x379e42a4), SPH_C32(0x2129cbd4) }, + { SPH_C32(0xcc179000), SPH_C32(0x6fd56c05), SPH_C32(0xf1632571), + SPH_C32(0x46322ded), SPH_C32(0x0eb33000), SPH_C32(0x52793798), + SPH_C32(0x8c42b6a3), SPH_C32(0xf1dd64b5) }, + { SPH_C32(0x9a01a000), SPH_C32(0x118e91ee), SPH_C32(0xd3b8f60a), + SPH_C32(0xb5e9053a), SPH_C32(0xed752000), SPH_C32(0x281d1f35), + SPH_C32(0x73064387), SPH_C32(0x4ed7b8e6) }, + { SPH_C32(0xee94b000), SPH_C32(0x4ba5d790), SPH_C32(0x5b45eb21), + SPH_C32(0xab0f87a8), SPH_C32(0x26dc2000), SPH_C32(0xb83a285c), + SPH_C32(0xc8dab780), SPH_C32(0x9e231787) }, + { SPH_C32(0x51a8a000), SPH_C32(0x81a9a687), SPH_C32(0x6864020d), + SPH_C32(0x651daa5b), SPH_C32(0x52493000), SPH_C32(0xe2116e22), + SPH_C32(0x4027aaab), SPH_C32(0x80c59515) }, + { SPH_C32(0x253db000), SPH_C32(0xdb82e0f9), SPH_C32(0xe0991f26), + SPH_C32(0x7bfb28c9), SPH_C32(0x99e03000), SPH_C32(0x7236594b), + SPH_C32(0xfbfb5eac), SPH_C32(0x50313a74) }, + { SPH_C32(0xf663c000), SPH_C32(0xde81aa29), SPH_C32(0x3801ebf9), + SPH_C32(0xe7fa92ad), SPH_C32(0xe2080000), SPH_C32(0xd7f9a9ec), + SPH_C32(0xe679e16a), SPH_C32(0x635fbdfc) }, + { SPH_C32(0x82f6d000), SPH_C32(0x84aaec57), SPH_C32(0xb0fcf6d2), + SPH_C32(0xf91c103f), SPH_C32(0x29a10000), SPH_C32(0x47de9e85), + SPH_C32(0x5da5156d), SPH_C32(0xb3ab129d) }, + { SPH_C32(0x3dcac000), SPH_C32(0x4ea69d40), SPH_C32(0x83dd1ffe), + SPH_C32(0x370e3dcc), SPH_C32(0x5d341000), SPH_C32(0x1df5d8fb), + SPH_C32(0xd5580846), SPH_C32(0xad4d900f) }, + { SPH_C32(0x495fd000), SPH_C32(0x148ddb3e), SPH_C32(0x0b2002d5), + SPH_C32(0x29e8bf5e), SPH_C32(0x969d1000), SPH_C32(0x8dd2ef92), + SPH_C32(0x6e84fc41), SPH_C32(0x7db93f6e) }, + { SPH_C32(0x1f49e000), SPH_C32(0x6ad626d5), SPH_C32(0x29fbd1ae), + SPH_C32(0xda339789), SPH_C32(0x755b0000), SPH_C32(0xf7b6c73f), + SPH_C32(0x91c00965), SPH_C32(0xc2b3e33d) }, + { SPH_C32(0x6bdcf000), SPH_C32(0x30fd60ab), SPH_C32(0xa106cc85), + SPH_C32(0xc4d5151b), SPH_C32(0xbef20000), SPH_C32(0x6791f056), + SPH_C32(0x2a1cfd62), SPH_C32(0x12474c5c) }, + { SPH_C32(0xd4e0e000), SPH_C32(0xfaf111bc), SPH_C32(0x922725a9), + SPH_C32(0x0ac738e8), SPH_C32(0xca671000), SPH_C32(0x3dbab628), + SPH_C32(0xa2e1e049), SPH_C32(0x0ca1cece) }, + { SPH_C32(0xa075f000), SPH_C32(0xa0da57c2), SPH_C32(0x1ada3882), + SPH_C32(0x1421ba7a), SPH_C32(0x01ce1000), SPH_C32(0xad9d8141), + SPH_C32(0x193d144e), SPH_C32(0xdc5561af) }, + { SPH_C32(0x6130c000), SPH_C32(0xfecec4fa), SPH_C32(0x4fb803f6), + SPH_C32(0x4616cc6c), SPH_C32(0x9c712000), SPH_C32(0x43e14bc3), + SPH_C32(0x803a3332), SPH_C32(0xff7ae619) }, + { SPH_C32(0x15a5d000), SPH_C32(0xa4e58284), SPH_C32(0xc7451edd), + SPH_C32(0x58f04efe), SPH_C32(0x57d82000), SPH_C32(0xd3c67caa), + SPH_C32(0x3be6c735), SPH_C32(0x2f8e4978) }, + { SPH_C32(0xaa99c000), SPH_C32(0x6ee9f393), SPH_C32(0xf464f7f1), + SPH_C32(0x96e2630d), SPH_C32(0x234d3000), SPH_C32(0x89ed3ad4), + SPH_C32(0xb31bda1e), SPH_C32(0x3168cbea) }, + { SPH_C32(0xde0cd000), SPH_C32(0x34c2b5ed), SPH_C32(0x7c99eada), + SPH_C32(0x8804e19f), SPH_C32(0xe8e43000), SPH_C32(0x19ca0dbd), + SPH_C32(0x08c72e19), SPH_C32(0xe19c648b) }, + { SPH_C32(0x881ae000), SPH_C32(0x4a994806), SPH_C32(0x5e4239a1), + SPH_C32(0x7bdfc948), SPH_C32(0x0b222000), SPH_C32(0x63ae2510), + SPH_C32(0xf783db3d), SPH_C32(0x5e96b8d8) }, + { SPH_C32(0xfc8ff000), SPH_C32(0x10b20e78), SPH_C32(0xd6bf248a), + SPH_C32(0x65394bda), SPH_C32(0xc08b2000), SPH_C32(0xf3891279), + SPH_C32(0x4c5f2f3a), SPH_C32(0x8e6217b9) }, + { SPH_C32(0x43b3e000), SPH_C32(0xdabe7f6f), SPH_C32(0xe59ecda6), + SPH_C32(0xab2b6629), SPH_C32(0xb41e3000), SPH_C32(0xa9a25407), + SPH_C32(0xc4a23211), SPH_C32(0x9084952b) }, + { SPH_C32(0x3726f000), SPH_C32(0x80953911), SPH_C32(0x6d63d08d), + SPH_C32(0xb5cde4bb), SPH_C32(0x7fb73000), SPH_C32(0x3985636e), + SPH_C32(0x7f7ec616), SPH_C32(0x40703a4a) }, + { SPH_C32(0x022f8000), SPH_C32(0xce2549e4), SPH_C32(0x317ebce8), + SPH_C32(0x398d5ee1), SPH_C32(0xf0134000), SPH_C32(0x8cee7004), + SPH_C32(0x6b832ec1), SPH_C32(0xad69718e) }, + { SPH_C32(0x76ba9000), SPH_C32(0x940e0f9a), SPH_C32(0xb983a1c3), + SPH_C32(0x276bdc73), SPH_C32(0x3bba4000), SPH_C32(0x1cc9476d), + SPH_C32(0xd05fdac6), SPH_C32(0x7d9ddeef) }, + { SPH_C32(0xc9868000), SPH_C32(0x5e027e8d), SPH_C32(0x8aa248ef), + SPH_C32(0xe979f180), SPH_C32(0x4f2f5000), SPH_C32(0x46e20113), + SPH_C32(0x58a2c7ed), SPH_C32(0x637b5c7d) }, + { SPH_C32(0xbd139000), SPH_C32(0x042938f3), SPH_C32(0x025f55c4), + SPH_C32(0xf79f7312), SPH_C32(0x84865000), SPH_C32(0xd6c5367a), + SPH_C32(0xe37e33ea), SPH_C32(0xb38ff31c) }, + { SPH_C32(0xeb05a000), SPH_C32(0x7a72c518), SPH_C32(0x208486bf), + SPH_C32(0x04445bc5), SPH_C32(0x67404000), SPH_C32(0xaca11ed7), + SPH_C32(0x1c3ac6ce), SPH_C32(0x0c852f4f) }, + { SPH_C32(0x9f90b000), SPH_C32(0x20598366), SPH_C32(0xa8799b94), + SPH_C32(0x1aa2d957), SPH_C32(0xace94000), SPH_C32(0x3c8629be), + SPH_C32(0xa7e632c9), SPH_C32(0xdc71802e) }, + { SPH_C32(0x20aca000), SPH_C32(0xea55f271), SPH_C32(0x9b5872b8), + SPH_C32(0xd4b0f4a4), SPH_C32(0xd87c5000), SPH_C32(0x66ad6fc0), + SPH_C32(0x2f1b2fe2), SPH_C32(0xc29702bc) }, + { SPH_C32(0x5439b000), SPH_C32(0xb07eb40f), SPH_C32(0x13a56f93), + SPH_C32(0xca567636), SPH_C32(0x13d55000), SPH_C32(0xf68a58a9), + SPH_C32(0x94c7dbe5), SPH_C32(0x1263addd) }, + { SPH_C32(0x957c8000), SPH_C32(0xee6a2737), SPH_C32(0x46c754e7), + SPH_C32(0x98610020), SPH_C32(0x8e6a6000), SPH_C32(0x18f6922b), + SPH_C32(0x0dc0fc99), SPH_C32(0x314c2a6b) }, + { SPH_C32(0xe1e99000), SPH_C32(0xb4416149), SPH_C32(0xce3a49cc), + SPH_C32(0x868782b2), SPH_C32(0x45c36000), SPH_C32(0x88d1a542), + SPH_C32(0xb61c089e), SPH_C32(0xe1b8850a) }, + { SPH_C32(0x5ed58000), SPH_C32(0x7e4d105e), SPH_C32(0xfd1ba0e0), + SPH_C32(0x4895af41), SPH_C32(0x31567000), SPH_C32(0xd2fae33c), + SPH_C32(0x3ee115b5), SPH_C32(0xff5e0798) }, + { SPH_C32(0x2a409000), SPH_C32(0x24665620), SPH_C32(0x75e6bdcb), + SPH_C32(0x56732dd3), SPH_C32(0xfaff7000), SPH_C32(0x42ddd455), + SPH_C32(0x853de1b2), SPH_C32(0x2faaa8f9) }, + { SPH_C32(0x7c56a000), SPH_C32(0x5a3dabcb), SPH_C32(0x573d6eb0), + SPH_C32(0xa5a80504), SPH_C32(0x19396000), SPH_C32(0x38b9fcf8), + SPH_C32(0x7a791496), SPH_C32(0x90a074aa) }, + { SPH_C32(0x08c3b000), SPH_C32(0x0016edb5), SPH_C32(0xdfc0739b), + SPH_C32(0xbb4e8796), SPH_C32(0xd2906000), SPH_C32(0xa89ecb91), + SPH_C32(0xc1a5e091), SPH_C32(0x4054dbcb) }, + { SPH_C32(0xb7ffa000), SPH_C32(0xca1a9ca2), SPH_C32(0xece19ab7), + SPH_C32(0x755caa65), SPH_C32(0xa6057000), SPH_C32(0xf2b58def), + SPH_C32(0x4958fdba), SPH_C32(0x5eb25959) }, + { SPH_C32(0xc36ab000), SPH_C32(0x9031dadc), SPH_C32(0x641c879c), + SPH_C32(0x6bba28f7), SPH_C32(0x6dac7000), SPH_C32(0x6292ba86), + SPH_C32(0xf28409bd), SPH_C32(0x8e46f638) }, + { SPH_C32(0x1034c000), SPH_C32(0x9532900c), SPH_C32(0xbc847343), + SPH_C32(0xf7bb9293), SPH_C32(0x16444000), SPH_C32(0xc75d4a21), + SPH_C32(0xef06b67b), SPH_C32(0xbd2871b0) }, + { SPH_C32(0x64a1d000), SPH_C32(0xcf19d672), SPH_C32(0x34796e68), + SPH_C32(0xe95d1001), SPH_C32(0xdded4000), SPH_C32(0x577a7d48), + SPH_C32(0x54da427c), SPH_C32(0x6ddcded1) }, + { SPH_C32(0xdb9dc000), SPH_C32(0x0515a765), SPH_C32(0x07588744), + SPH_C32(0x274f3df2), SPH_C32(0xa9785000), SPH_C32(0x0d513b36), + SPH_C32(0xdc275f57), SPH_C32(0x733a5c43) }, + { SPH_C32(0xaf08d000), SPH_C32(0x5f3ee11b), SPH_C32(0x8fa59a6f), + SPH_C32(0x39a9bf60), SPH_C32(0x62d15000), SPH_C32(0x9d760c5f), + SPH_C32(0x67fbab50), SPH_C32(0xa3cef322) }, + { SPH_C32(0xf91ee000), SPH_C32(0x21651cf0), SPH_C32(0xad7e4914), + SPH_C32(0xca7297b7), SPH_C32(0x81174000), SPH_C32(0xe71224f2), + SPH_C32(0x98bf5e74), SPH_C32(0x1cc42f71) }, + { SPH_C32(0x8d8bf000), SPH_C32(0x7b4e5a8e), SPH_C32(0x2583543f), + SPH_C32(0xd4941525), SPH_C32(0x4abe4000), SPH_C32(0x7735139b), + SPH_C32(0x2363aa73), SPH_C32(0xcc308010) }, + { SPH_C32(0x32b7e000), SPH_C32(0xb1422b99), SPH_C32(0x16a2bd13), + SPH_C32(0x1a8638d6), SPH_C32(0x3e2b5000), SPH_C32(0x2d1e55e5), + SPH_C32(0xab9eb758), SPH_C32(0xd2d60282) }, + { SPH_C32(0x4622f000), SPH_C32(0xeb696de7), SPH_C32(0x9e5fa038), + SPH_C32(0x0460ba44), SPH_C32(0xf5825000), SPH_C32(0xbd39628c), + SPH_C32(0x1042435f), SPH_C32(0x0222ade3) }, + { SPH_C32(0x8767c000), SPH_C32(0xb57dfedf), SPH_C32(0xcb3d9b4c), + SPH_C32(0x5657cc52), SPH_C32(0x683d6000), SPH_C32(0x5345a80e), + SPH_C32(0x89456423), SPH_C32(0x210d2a55) }, + { SPH_C32(0xf3f2d000), SPH_C32(0xef56b8a1), SPH_C32(0x43c08667), + SPH_C32(0x48b14ec0), SPH_C32(0xa3946000), SPH_C32(0xc3629f67), + SPH_C32(0x32999024), SPH_C32(0xf1f98534) }, + { SPH_C32(0x4ccec000), SPH_C32(0x255ac9b6), SPH_C32(0x70e16f4b), + SPH_C32(0x86a36333), SPH_C32(0xd7017000), SPH_C32(0x9949d919), + SPH_C32(0xba648d0f), SPH_C32(0xef1f07a6) }, + { SPH_C32(0x385bd000), SPH_C32(0x7f718fc8), SPH_C32(0xf81c7260), + SPH_C32(0x9845e1a1), SPH_C32(0x1ca87000), SPH_C32(0x096eee70), + SPH_C32(0x01b87908), SPH_C32(0x3feba8c7) }, + { SPH_C32(0x6e4de000), SPH_C32(0x012a7223), SPH_C32(0xdac7a11b), + SPH_C32(0x6b9ec976), SPH_C32(0xff6e6000), SPH_C32(0x730ac6dd), + SPH_C32(0xfefc8c2c), SPH_C32(0x80e17494) }, + { SPH_C32(0x1ad8f000), SPH_C32(0x5b01345d), SPH_C32(0x523abc30), + SPH_C32(0x75784be4), SPH_C32(0x34c76000), SPH_C32(0xe32df1b4), + SPH_C32(0x4520782b), SPH_C32(0x5015dbf5) }, + { SPH_C32(0xa5e4e000), SPH_C32(0x910d454a), SPH_C32(0x611b551c), + SPH_C32(0xbb6a6617), SPH_C32(0x40527000), SPH_C32(0xb906b7ca), + SPH_C32(0xcddd6500), SPH_C32(0x4ef35967) }, + { SPH_C32(0xd171f000), SPH_C32(0xcb260334), SPH_C32(0xe9e64837), + SPH_C32(0xa58ce485), SPH_C32(0x8bfb7000), SPH_C32(0x292180a3), + SPH_C32(0x76019107), SPH_C32(0x9e07f606) }, + { SPH_C32(0x045f0000), SPH_C32(0x9c4a93c9), SPH_C32(0x62fc79d0), + SPH_C32(0x731ebdc2), SPH_C32(0xe0278000), SPH_C32(0x19dce008), + SPH_C32(0xd7075d82), SPH_C32(0x5ad2e31d) }, + { SPH_C32(0x70ca1000), SPH_C32(0xc661d5b7), SPH_C32(0xea0164fb), + SPH_C32(0x6df83f50), SPH_C32(0x2b8e8000), SPH_C32(0x89fbd761), + SPH_C32(0x6cdba985), SPH_C32(0x8a264c7c) }, + { SPH_C32(0xcff60000), SPH_C32(0x0c6da4a0), SPH_C32(0xd9208dd7), + SPH_C32(0xa3ea12a3), SPH_C32(0x5f1b9000), SPH_C32(0xd3d0911f), + SPH_C32(0xe426b4ae), SPH_C32(0x94c0ceee) }, + { SPH_C32(0xbb631000), SPH_C32(0x5646e2de), SPH_C32(0x51dd90fc), + SPH_C32(0xbd0c9031), SPH_C32(0x94b29000), SPH_C32(0x43f7a676), + SPH_C32(0x5ffa40a9), SPH_C32(0x4434618f) }, + { SPH_C32(0xed752000), SPH_C32(0x281d1f35), SPH_C32(0x73064387), + SPH_C32(0x4ed7b8e6), SPH_C32(0x77748000), SPH_C32(0x39938edb), + SPH_C32(0xa0beb58d), SPH_C32(0xfb3ebddc) }, + { SPH_C32(0x99e03000), SPH_C32(0x7236594b), SPH_C32(0xfbfb5eac), + SPH_C32(0x50313a74), SPH_C32(0xbcdd8000), SPH_C32(0xa9b4b9b2), + SPH_C32(0x1b62418a), SPH_C32(0x2bca12bd) }, + { SPH_C32(0x26dc2000), SPH_C32(0xb83a285c), SPH_C32(0xc8dab780), + SPH_C32(0x9e231787), SPH_C32(0xc8489000), SPH_C32(0xf39fffcc), + SPH_C32(0x939f5ca1), SPH_C32(0x352c902f) }, + { SPH_C32(0x52493000), SPH_C32(0xe2116e22), SPH_C32(0x4027aaab), + SPH_C32(0x80c59515), SPH_C32(0x03e19000), SPH_C32(0x63b8c8a5), + SPH_C32(0x2843a8a6), SPH_C32(0xe5d83f4e) }, + { SPH_C32(0x930c0000), SPH_C32(0xbc05fd1a), SPH_C32(0x154591df), + SPH_C32(0xd2f2e303), SPH_C32(0x9e5ea000), SPH_C32(0x8dc40227), + SPH_C32(0xb1448fda), SPH_C32(0xc6f7b8f8) }, + { SPH_C32(0xe7991000), SPH_C32(0xe62ebb64), SPH_C32(0x9db88cf4), + SPH_C32(0xcc146191), SPH_C32(0x55f7a000), SPH_C32(0x1de3354e), + SPH_C32(0x0a987bdd), SPH_C32(0x16031799) }, + { SPH_C32(0x58a50000), SPH_C32(0x2c22ca73), SPH_C32(0xae9965d8), + SPH_C32(0x02064c62), SPH_C32(0x2162b000), SPH_C32(0x47c87330), + SPH_C32(0x826566f6), SPH_C32(0x08e5950b) }, + { SPH_C32(0x2c301000), SPH_C32(0x76098c0d), SPH_C32(0x266478f3), + SPH_C32(0x1ce0cef0), SPH_C32(0xeacbb000), SPH_C32(0xd7ef4459), + SPH_C32(0x39b992f1), SPH_C32(0xd8113a6a) }, + { SPH_C32(0x7a262000), SPH_C32(0x085271e6), SPH_C32(0x04bfab88), + SPH_C32(0xef3be627), SPH_C32(0x090da000), SPH_C32(0xad8b6cf4), + SPH_C32(0xc6fd67d5), SPH_C32(0x671be639) }, + { SPH_C32(0x0eb33000), SPH_C32(0x52793798), SPH_C32(0x8c42b6a3), + SPH_C32(0xf1dd64b5), SPH_C32(0xc2a4a000), SPH_C32(0x3dac5b9d), + SPH_C32(0x7d2193d2), SPH_C32(0xb7ef4958) }, + { SPH_C32(0xb18f2000), SPH_C32(0x9875468f), SPH_C32(0xbf635f8f), + SPH_C32(0x3fcf4946), SPH_C32(0xb631b000), SPH_C32(0x67871de3), + SPH_C32(0xf5dc8ef9), SPH_C32(0xa909cbca) }, + { SPH_C32(0xc51a3000), SPH_C32(0xc25e00f1), SPH_C32(0x379e42a4), + SPH_C32(0x2129cbd4), SPH_C32(0x7d98b000), SPH_C32(0xf7a02a8a), + SPH_C32(0x4e007afe), SPH_C32(0x79fd64ab) }, + { SPH_C32(0x16444000), SPH_C32(0xc75d4a21), SPH_C32(0xef06b67b), + SPH_C32(0xbd2871b0), SPH_C32(0x06708000), SPH_C32(0x526fda2d), + SPH_C32(0x5382c538), SPH_C32(0x4a93e323) }, + { SPH_C32(0x62d15000), SPH_C32(0x9d760c5f), SPH_C32(0x67fbab50), + SPH_C32(0xa3cef322), SPH_C32(0xcdd98000), SPH_C32(0xc248ed44), + SPH_C32(0xe85e313f), SPH_C32(0x9a674c42) }, + { SPH_C32(0xdded4000), SPH_C32(0x577a7d48), SPH_C32(0x54da427c), + SPH_C32(0x6ddcded1), SPH_C32(0xb94c9000), SPH_C32(0x9863ab3a), + SPH_C32(0x60a32c14), SPH_C32(0x8481ced0) }, + { SPH_C32(0xa9785000), SPH_C32(0x0d513b36), SPH_C32(0xdc275f57), + SPH_C32(0x733a5c43), SPH_C32(0x72e59000), SPH_C32(0x08449c53), + SPH_C32(0xdb7fd813), SPH_C32(0x547561b1) }, + { SPH_C32(0xff6e6000), SPH_C32(0x730ac6dd), SPH_C32(0xfefc8c2c), + SPH_C32(0x80e17494), SPH_C32(0x91238000), SPH_C32(0x7220b4fe), + SPH_C32(0x243b2d37), SPH_C32(0xeb7fbde2) }, + { SPH_C32(0x8bfb7000), SPH_C32(0x292180a3), SPH_C32(0x76019107), + SPH_C32(0x9e07f606), SPH_C32(0x5a8a8000), SPH_C32(0xe2078397), + SPH_C32(0x9fe7d930), SPH_C32(0x3b8b1283) }, + { SPH_C32(0x34c76000), SPH_C32(0xe32df1b4), SPH_C32(0x4520782b), + SPH_C32(0x5015dbf5), SPH_C32(0x2e1f9000), SPH_C32(0xb82cc5e9), + SPH_C32(0x171ac41b), SPH_C32(0x256d9011) }, + { SPH_C32(0x40527000), SPH_C32(0xb906b7ca), SPH_C32(0xcddd6500), + SPH_C32(0x4ef35967), SPH_C32(0xe5b69000), SPH_C32(0x280bf280), + SPH_C32(0xacc6301c), SPH_C32(0xf5993f70) }, + { SPH_C32(0x81174000), SPH_C32(0xe71224f2), SPH_C32(0x98bf5e74), + SPH_C32(0x1cc42f71), SPH_C32(0x7809a000), SPH_C32(0xc6773802), + SPH_C32(0x35c11760), SPH_C32(0xd6b6b8c6) }, + { SPH_C32(0xf5825000), SPH_C32(0xbd39628c), SPH_C32(0x1042435f), + SPH_C32(0x0222ade3), SPH_C32(0xb3a0a000), SPH_C32(0x56500f6b), + SPH_C32(0x8e1de367), SPH_C32(0x064217a7) }, + { SPH_C32(0x4abe4000), SPH_C32(0x7735139b), SPH_C32(0x2363aa73), + SPH_C32(0xcc308010), SPH_C32(0xc735b000), SPH_C32(0x0c7b4915), + SPH_C32(0x06e0fe4c), SPH_C32(0x18a49535) }, + { SPH_C32(0x3e2b5000), SPH_C32(0x2d1e55e5), SPH_C32(0xab9eb758), + SPH_C32(0xd2d60282), SPH_C32(0x0c9cb000), SPH_C32(0x9c5c7e7c), + SPH_C32(0xbd3c0a4b), SPH_C32(0xc8503a54) }, + { SPH_C32(0x683d6000), SPH_C32(0x5345a80e), SPH_C32(0x89456423), + SPH_C32(0x210d2a55), SPH_C32(0xef5aa000), SPH_C32(0xe63856d1), + SPH_C32(0x4278ff6f), SPH_C32(0x775ae607) }, + { SPH_C32(0x1ca87000), SPH_C32(0x096eee70), SPH_C32(0x01b87908), + SPH_C32(0x3feba8c7), SPH_C32(0x24f3a000), SPH_C32(0x761f61b8), + SPH_C32(0xf9a40b68), SPH_C32(0xa7ae4966) }, + { SPH_C32(0xa3946000), SPH_C32(0xc3629f67), SPH_C32(0x32999024), + SPH_C32(0xf1f98534), SPH_C32(0x5066b000), SPH_C32(0x2c3427c6), + SPH_C32(0x71591643), SPH_C32(0xb948cbf4) }, + { SPH_C32(0xd7017000), SPH_C32(0x9949d919), SPH_C32(0xba648d0f), + SPH_C32(0xef1f07a6), SPH_C32(0x9bcfb000), SPH_C32(0xbc1310af), + SPH_C32(0xca85e244), SPH_C32(0x69bc6495) }, + { SPH_C32(0xe2080000), SPH_C32(0xd7f9a9ec), SPH_C32(0xe679e16a), + SPH_C32(0x635fbdfc), SPH_C32(0x146bc000), SPH_C32(0x097803c5), + SPH_C32(0xde780a93), SPH_C32(0x84a52f51) }, + { SPH_C32(0x969d1000), SPH_C32(0x8dd2ef92), SPH_C32(0x6e84fc41), + SPH_C32(0x7db93f6e), SPH_C32(0xdfc2c000), SPH_C32(0x995f34ac), + SPH_C32(0x65a4fe94), SPH_C32(0x54518030) }, + { SPH_C32(0x29a10000), SPH_C32(0x47de9e85), SPH_C32(0x5da5156d), + SPH_C32(0xb3ab129d), SPH_C32(0xab57d000), SPH_C32(0xc37472d2), + SPH_C32(0xed59e3bf), SPH_C32(0x4ab702a2) }, + { SPH_C32(0x5d341000), SPH_C32(0x1df5d8fb), SPH_C32(0xd5580846), + SPH_C32(0xad4d900f), SPH_C32(0x60fed000), SPH_C32(0x535345bb), + SPH_C32(0x568517b8), SPH_C32(0x9a43adc3) }, + { SPH_C32(0x0b222000), SPH_C32(0x63ae2510), SPH_C32(0xf783db3d), + SPH_C32(0x5e96b8d8), SPH_C32(0x8338c000), SPH_C32(0x29376d16), + SPH_C32(0xa9c1e29c), SPH_C32(0x25497190) }, + { SPH_C32(0x7fb73000), SPH_C32(0x3985636e), SPH_C32(0x7f7ec616), + SPH_C32(0x40703a4a), SPH_C32(0x4891c000), SPH_C32(0xb9105a7f), + SPH_C32(0x121d169b), SPH_C32(0xf5bddef1) }, + { SPH_C32(0xc08b2000), SPH_C32(0xf3891279), SPH_C32(0x4c5f2f3a), + SPH_C32(0x8e6217b9), SPH_C32(0x3c04d000), SPH_C32(0xe33b1c01), + SPH_C32(0x9ae00bb0), SPH_C32(0xeb5b5c63) }, + { SPH_C32(0xb41e3000), SPH_C32(0xa9a25407), SPH_C32(0xc4a23211), + SPH_C32(0x9084952b), SPH_C32(0xf7add000), SPH_C32(0x731c2b68), + SPH_C32(0x213cffb7), SPH_C32(0x3baff302) }, + { SPH_C32(0x755b0000), SPH_C32(0xf7b6c73f), SPH_C32(0x91c00965), + SPH_C32(0xc2b3e33d), SPH_C32(0x6a12e000), SPH_C32(0x9d60e1ea), + SPH_C32(0xb83bd8cb), SPH_C32(0x188074b4) }, + { SPH_C32(0x01ce1000), SPH_C32(0xad9d8141), SPH_C32(0x193d144e), + SPH_C32(0xdc5561af), SPH_C32(0xa1bbe000), SPH_C32(0x0d47d683), + SPH_C32(0x03e72ccc), SPH_C32(0xc874dbd5) }, + { SPH_C32(0xbef20000), SPH_C32(0x6791f056), SPH_C32(0x2a1cfd62), + SPH_C32(0x12474c5c), SPH_C32(0xd52ef000), SPH_C32(0x576c90fd), + SPH_C32(0x8b1a31e7), SPH_C32(0xd6925947) }, + { SPH_C32(0xca671000), SPH_C32(0x3dbab628), SPH_C32(0xa2e1e049), + SPH_C32(0x0ca1cece), SPH_C32(0x1e87f000), SPH_C32(0xc74ba794), + SPH_C32(0x30c6c5e0), SPH_C32(0x0666f626) }, + { SPH_C32(0x9c712000), SPH_C32(0x43e14bc3), SPH_C32(0x803a3332), + SPH_C32(0xff7ae619), SPH_C32(0xfd41e000), SPH_C32(0xbd2f8f39), + SPH_C32(0xcf8230c4), SPH_C32(0xb96c2a75) }, + { SPH_C32(0xe8e43000), SPH_C32(0x19ca0dbd), SPH_C32(0x08c72e19), + SPH_C32(0xe19c648b), SPH_C32(0x36e8e000), SPH_C32(0x2d08b850), + SPH_C32(0x745ec4c3), SPH_C32(0x69988514) }, + { SPH_C32(0x57d82000), SPH_C32(0xd3c67caa), SPH_C32(0x3be6c735), + SPH_C32(0x2f8e4978), SPH_C32(0x427df000), SPH_C32(0x7723fe2e), + SPH_C32(0xfca3d9e8), SPH_C32(0x777e0786) }, + { SPH_C32(0x234d3000), SPH_C32(0x89ed3ad4), SPH_C32(0xb31bda1e), + SPH_C32(0x3168cbea), SPH_C32(0x89d4f000), SPH_C32(0xe704c947), + SPH_C32(0x477f2def), SPH_C32(0xa78aa8e7) }, + { SPH_C32(0xf0134000), SPH_C32(0x8cee7004), SPH_C32(0x6b832ec1), + SPH_C32(0xad69718e), SPH_C32(0xf23cc000), SPH_C32(0x42cb39e0), + SPH_C32(0x5afd9229), SPH_C32(0x94e42f6f) }, + { SPH_C32(0x84865000), SPH_C32(0xd6c5367a), SPH_C32(0xe37e33ea), + SPH_C32(0xb38ff31c), SPH_C32(0x3995c000), SPH_C32(0xd2ec0e89), + SPH_C32(0xe121662e), SPH_C32(0x4410800e) }, + { SPH_C32(0x3bba4000), SPH_C32(0x1cc9476d), SPH_C32(0xd05fdac6), + SPH_C32(0x7d9ddeef), SPH_C32(0x4d00d000), SPH_C32(0x88c748f7), + SPH_C32(0x69dc7b05), SPH_C32(0x5af6029c) }, + { SPH_C32(0x4f2f5000), SPH_C32(0x46e20113), SPH_C32(0x58a2c7ed), + SPH_C32(0x637b5c7d), SPH_C32(0x86a9d000), SPH_C32(0x18e07f9e), + SPH_C32(0xd2008f02), SPH_C32(0x8a02adfd) }, + { SPH_C32(0x19396000), SPH_C32(0x38b9fcf8), SPH_C32(0x7a791496), + SPH_C32(0x90a074aa), SPH_C32(0x656fc000), SPH_C32(0x62845733), + SPH_C32(0x2d447a26), SPH_C32(0x350871ae) }, + { SPH_C32(0x6dac7000), SPH_C32(0x6292ba86), SPH_C32(0xf28409bd), + SPH_C32(0x8e46f638), SPH_C32(0xaec6c000), SPH_C32(0xf2a3605a), + SPH_C32(0x96988e21), SPH_C32(0xe5fcdecf) }, + { SPH_C32(0xd2906000), SPH_C32(0xa89ecb91), SPH_C32(0xc1a5e091), + SPH_C32(0x4054dbcb), SPH_C32(0xda53d000), SPH_C32(0xa8882624), + SPH_C32(0x1e65930a), SPH_C32(0xfb1a5c5d) }, + { SPH_C32(0xa6057000), SPH_C32(0xf2b58def), SPH_C32(0x4958fdba), + SPH_C32(0x5eb25959), SPH_C32(0x11fad000), SPH_C32(0x38af114d), + SPH_C32(0xa5b9670d), SPH_C32(0x2beef33c) }, + { SPH_C32(0x67404000), SPH_C32(0xaca11ed7), SPH_C32(0x1c3ac6ce), + SPH_C32(0x0c852f4f), SPH_C32(0x8c45e000), SPH_C32(0xd6d3dbcf), + SPH_C32(0x3cbe4071), SPH_C32(0x08c1748a) }, + { SPH_C32(0x13d55000), SPH_C32(0xf68a58a9), SPH_C32(0x94c7dbe5), + SPH_C32(0x1263addd), SPH_C32(0x47ece000), SPH_C32(0x46f4eca6), + SPH_C32(0x8762b476), SPH_C32(0xd835dbeb) }, + { SPH_C32(0xace94000), SPH_C32(0x3c8629be), SPH_C32(0xa7e632c9), + SPH_C32(0xdc71802e), SPH_C32(0x3379f000), SPH_C32(0x1cdfaad8), + SPH_C32(0x0f9fa95d), SPH_C32(0xc6d35979) }, + { SPH_C32(0xd87c5000), SPH_C32(0x66ad6fc0), SPH_C32(0x2f1b2fe2), + SPH_C32(0xc29702bc), SPH_C32(0xf8d0f000), SPH_C32(0x8cf89db1), + SPH_C32(0xb4435d5a), SPH_C32(0x1627f618) }, + { SPH_C32(0x8e6a6000), SPH_C32(0x18f6922b), SPH_C32(0x0dc0fc99), + SPH_C32(0x314c2a6b), SPH_C32(0x1b16e000), SPH_C32(0xf69cb51c), + SPH_C32(0x4b07a87e), SPH_C32(0xa92d2a4b) }, + { SPH_C32(0xfaff7000), SPH_C32(0x42ddd455), SPH_C32(0x853de1b2), + SPH_C32(0x2faaa8f9), SPH_C32(0xd0bfe000), SPH_C32(0x66bb8275), + SPH_C32(0xf0db5c79), SPH_C32(0x79d9852a) }, + { SPH_C32(0x45c36000), SPH_C32(0x88d1a542), SPH_C32(0xb61c089e), + SPH_C32(0xe1b8850a), SPH_C32(0xa42af000), SPH_C32(0x3c90c40b), + SPH_C32(0x78264152), SPH_C32(0x673f07b8) }, + { SPH_C32(0x31567000), SPH_C32(0xd2fae33c), SPH_C32(0x3ee115b5), + SPH_C32(0xff5e0798), SPH_C32(0x6f83f000), SPH_C32(0xacb7f362), + SPH_C32(0xc3fab555), SPH_C32(0xb7cba8d9) }, + { SPH_C32(0xe0278000), SPH_C32(0x19dce008), SPH_C32(0xd7075d82), + SPH_C32(0x5ad2e31d), SPH_C32(0xe4788000), SPH_C32(0x859673c1), + SPH_C32(0xb5fb2452), SPH_C32(0x29cc5edf) }, + { SPH_C32(0x94b29000), SPH_C32(0x43f7a676), SPH_C32(0x5ffa40a9), + SPH_C32(0x4434618f), SPH_C32(0x2fd18000), SPH_C32(0x15b144a8), + SPH_C32(0x0e27d055), SPH_C32(0xf938f1be) }, + { SPH_C32(0x2b8e8000), SPH_C32(0x89fbd761), SPH_C32(0x6cdba985), + SPH_C32(0x8a264c7c), SPH_C32(0x5b449000), SPH_C32(0x4f9a02d6), + SPH_C32(0x86dacd7e), SPH_C32(0xe7de732c) }, + { SPH_C32(0x5f1b9000), SPH_C32(0xd3d0911f), SPH_C32(0xe426b4ae), + SPH_C32(0x94c0ceee), SPH_C32(0x90ed9000), SPH_C32(0xdfbd35bf), + SPH_C32(0x3d063979), SPH_C32(0x372adc4d) }, + { SPH_C32(0x090da000), SPH_C32(0xad8b6cf4), SPH_C32(0xc6fd67d5), + SPH_C32(0x671be639), SPH_C32(0x732b8000), SPH_C32(0xa5d91d12), + SPH_C32(0xc242cc5d), SPH_C32(0x8820001e) }, + { SPH_C32(0x7d98b000), SPH_C32(0xf7a02a8a), SPH_C32(0x4e007afe), + SPH_C32(0x79fd64ab), SPH_C32(0xb8828000), SPH_C32(0x35fe2a7b), + SPH_C32(0x799e385a), SPH_C32(0x58d4af7f) }, + { SPH_C32(0xc2a4a000), SPH_C32(0x3dac5b9d), SPH_C32(0x7d2193d2), + SPH_C32(0xb7ef4958), SPH_C32(0xcc179000), SPH_C32(0x6fd56c05), + SPH_C32(0xf1632571), SPH_C32(0x46322ded) }, + { SPH_C32(0xb631b000), SPH_C32(0x67871de3), SPH_C32(0xf5dc8ef9), + SPH_C32(0xa909cbca), SPH_C32(0x07be9000), SPH_C32(0xfff25b6c), + SPH_C32(0x4abfd176), SPH_C32(0x96c6828c) }, + { SPH_C32(0x77748000), SPH_C32(0x39938edb), SPH_C32(0xa0beb58d), + SPH_C32(0xfb3ebddc), SPH_C32(0x9a01a000), SPH_C32(0x118e91ee), + SPH_C32(0xd3b8f60a), SPH_C32(0xb5e9053a) }, + { SPH_C32(0x03e19000), SPH_C32(0x63b8c8a5), SPH_C32(0x2843a8a6), + SPH_C32(0xe5d83f4e), SPH_C32(0x51a8a000), SPH_C32(0x81a9a687), + SPH_C32(0x6864020d), SPH_C32(0x651daa5b) }, + { SPH_C32(0xbcdd8000), SPH_C32(0xa9b4b9b2), SPH_C32(0x1b62418a), + SPH_C32(0x2bca12bd), SPH_C32(0x253db000), SPH_C32(0xdb82e0f9), + SPH_C32(0xe0991f26), SPH_C32(0x7bfb28c9) }, + { SPH_C32(0xc8489000), SPH_C32(0xf39fffcc), SPH_C32(0x939f5ca1), + SPH_C32(0x352c902f), SPH_C32(0xee94b000), SPH_C32(0x4ba5d790), + SPH_C32(0x5b45eb21), SPH_C32(0xab0f87a8) }, + { SPH_C32(0x9e5ea000), SPH_C32(0x8dc40227), SPH_C32(0xb1448fda), + SPH_C32(0xc6f7b8f8), SPH_C32(0x0d52a000), SPH_C32(0x31c1ff3d), + SPH_C32(0xa4011e05), SPH_C32(0x14055bfb) }, + { SPH_C32(0xeacbb000), SPH_C32(0xd7ef4459), SPH_C32(0x39b992f1), + SPH_C32(0xd8113a6a), SPH_C32(0xc6fba000), SPH_C32(0xa1e6c854), + SPH_C32(0x1fddea02), SPH_C32(0xc4f1f49a) }, + { SPH_C32(0x55f7a000), SPH_C32(0x1de3354e), SPH_C32(0x0a987bdd), + SPH_C32(0x16031799), SPH_C32(0xb26eb000), SPH_C32(0xfbcd8e2a), + SPH_C32(0x9720f729), SPH_C32(0xda177608) }, + { SPH_C32(0x2162b000), SPH_C32(0x47c87330), SPH_C32(0x826566f6), + SPH_C32(0x08e5950b), SPH_C32(0x79c7b000), SPH_C32(0x6beab943), + SPH_C32(0x2cfc032e), SPH_C32(0x0ae3d969) }, + { SPH_C32(0xf23cc000), SPH_C32(0x42cb39e0), SPH_C32(0x5afd9229), + SPH_C32(0x94e42f6f), SPH_C32(0x022f8000), SPH_C32(0xce2549e4), + SPH_C32(0x317ebce8), SPH_C32(0x398d5ee1) }, + { SPH_C32(0x86a9d000), SPH_C32(0x18e07f9e), SPH_C32(0xd2008f02), + SPH_C32(0x8a02adfd), SPH_C32(0xc9868000), SPH_C32(0x5e027e8d), + SPH_C32(0x8aa248ef), SPH_C32(0xe979f180) }, + { SPH_C32(0x3995c000), SPH_C32(0xd2ec0e89), SPH_C32(0xe121662e), + SPH_C32(0x4410800e), SPH_C32(0xbd139000), SPH_C32(0x042938f3), + SPH_C32(0x025f55c4), SPH_C32(0xf79f7312) }, + { SPH_C32(0x4d00d000), SPH_C32(0x88c748f7), SPH_C32(0x69dc7b05), + SPH_C32(0x5af6029c), SPH_C32(0x76ba9000), SPH_C32(0x940e0f9a), + SPH_C32(0xb983a1c3), SPH_C32(0x276bdc73) }, + { SPH_C32(0x1b16e000), SPH_C32(0xf69cb51c), SPH_C32(0x4b07a87e), + SPH_C32(0xa92d2a4b), SPH_C32(0x957c8000), SPH_C32(0xee6a2737), + SPH_C32(0x46c754e7), SPH_C32(0x98610020) }, + { SPH_C32(0x6f83f000), SPH_C32(0xacb7f362), SPH_C32(0xc3fab555), + SPH_C32(0xb7cba8d9), SPH_C32(0x5ed58000), SPH_C32(0x7e4d105e), + SPH_C32(0xfd1ba0e0), SPH_C32(0x4895af41) }, + { SPH_C32(0xd0bfe000), SPH_C32(0x66bb8275), SPH_C32(0xf0db5c79), + SPH_C32(0x79d9852a), SPH_C32(0x2a409000), SPH_C32(0x24665620), + SPH_C32(0x75e6bdcb), SPH_C32(0x56732dd3) }, + { SPH_C32(0xa42af000), SPH_C32(0x3c90c40b), SPH_C32(0x78264152), + SPH_C32(0x673f07b8), SPH_C32(0xe1e99000), SPH_C32(0xb4416149), + SPH_C32(0xce3a49cc), SPH_C32(0x868782b2) }, + { SPH_C32(0x656fc000), SPH_C32(0x62845733), SPH_C32(0x2d447a26), + SPH_C32(0x350871ae), SPH_C32(0x7c56a000), SPH_C32(0x5a3dabcb), + SPH_C32(0x573d6eb0), SPH_C32(0xa5a80504) }, + { SPH_C32(0x11fad000), SPH_C32(0x38af114d), SPH_C32(0xa5b9670d), + SPH_C32(0x2beef33c), SPH_C32(0xb7ffa000), SPH_C32(0xca1a9ca2), + SPH_C32(0xece19ab7), SPH_C32(0x755caa65) }, + { SPH_C32(0xaec6c000), SPH_C32(0xf2a3605a), SPH_C32(0x96988e21), + SPH_C32(0xe5fcdecf), SPH_C32(0xc36ab000), SPH_C32(0x9031dadc), + SPH_C32(0x641c879c), SPH_C32(0x6bba28f7) }, + { SPH_C32(0xda53d000), SPH_C32(0xa8882624), SPH_C32(0x1e65930a), + SPH_C32(0xfb1a5c5d), SPH_C32(0x08c3b000), SPH_C32(0x0016edb5), + SPH_C32(0xdfc0739b), SPH_C32(0xbb4e8796) }, + { SPH_C32(0x8c45e000), SPH_C32(0xd6d3dbcf), SPH_C32(0x3cbe4071), + SPH_C32(0x08c1748a), SPH_C32(0xeb05a000), SPH_C32(0x7a72c518), + SPH_C32(0x208486bf), SPH_C32(0x04445bc5) }, + { SPH_C32(0xf8d0f000), SPH_C32(0x8cf89db1), SPH_C32(0xb4435d5a), + SPH_C32(0x1627f618), SPH_C32(0x20aca000), SPH_C32(0xea55f271), + SPH_C32(0x9b5872b8), SPH_C32(0xd4b0f4a4) }, + { SPH_C32(0x47ece000), SPH_C32(0x46f4eca6), SPH_C32(0x8762b476), + SPH_C32(0xd835dbeb), SPH_C32(0x5439b000), SPH_C32(0xb07eb40f), + SPH_C32(0x13a56f93), SPH_C32(0xca567636) }, + { SPH_C32(0x3379f000), SPH_C32(0x1cdfaad8), SPH_C32(0x0f9fa95d), + SPH_C32(0xc6d35979), SPH_C32(0x9f90b000), SPH_C32(0x20598366), + SPH_C32(0xa8799b94), SPH_C32(0x1aa2d957) }, + { SPH_C32(0x06708000), SPH_C32(0x526fda2d), SPH_C32(0x5382c538), + SPH_C32(0x4a93e323), SPH_C32(0x1034c000), SPH_C32(0x9532900c), + SPH_C32(0xbc847343), SPH_C32(0xf7bb9293) }, + { SPH_C32(0x72e59000), SPH_C32(0x08449c53), SPH_C32(0xdb7fd813), + SPH_C32(0x547561b1), SPH_C32(0xdb9dc000), SPH_C32(0x0515a765), + SPH_C32(0x07588744), SPH_C32(0x274f3df2) }, + { SPH_C32(0xcdd98000), SPH_C32(0xc248ed44), SPH_C32(0xe85e313f), + SPH_C32(0x9a674c42), SPH_C32(0xaf08d000), SPH_C32(0x5f3ee11b), + SPH_C32(0x8fa59a6f), SPH_C32(0x39a9bf60) }, + { SPH_C32(0xb94c9000), SPH_C32(0x9863ab3a), SPH_C32(0x60a32c14), + SPH_C32(0x8481ced0), SPH_C32(0x64a1d000), SPH_C32(0xcf19d672), + SPH_C32(0x34796e68), SPH_C32(0xe95d1001) }, + { SPH_C32(0xef5aa000), SPH_C32(0xe63856d1), SPH_C32(0x4278ff6f), + SPH_C32(0x775ae607), SPH_C32(0x8767c000), SPH_C32(0xb57dfedf), + SPH_C32(0xcb3d9b4c), SPH_C32(0x5657cc52) }, + { SPH_C32(0x9bcfb000), SPH_C32(0xbc1310af), SPH_C32(0xca85e244), + SPH_C32(0x69bc6495), SPH_C32(0x4ccec000), SPH_C32(0x255ac9b6), + SPH_C32(0x70e16f4b), SPH_C32(0x86a36333) }, + { SPH_C32(0x24f3a000), SPH_C32(0x761f61b8), SPH_C32(0xf9a40b68), + SPH_C32(0xa7ae4966), SPH_C32(0x385bd000), SPH_C32(0x7f718fc8), + SPH_C32(0xf81c7260), SPH_C32(0x9845e1a1) }, + { SPH_C32(0x5066b000), SPH_C32(0x2c3427c6), SPH_C32(0x71591643), + SPH_C32(0xb948cbf4), SPH_C32(0xf3f2d000), SPH_C32(0xef56b8a1), + SPH_C32(0x43c08667), SPH_C32(0x48b14ec0) }, + { SPH_C32(0x91238000), SPH_C32(0x7220b4fe), SPH_C32(0x243b2d37), + SPH_C32(0xeb7fbde2), SPH_C32(0x6e4de000), SPH_C32(0x012a7223), + SPH_C32(0xdac7a11b), SPH_C32(0x6b9ec976) }, + { SPH_C32(0xe5b69000), SPH_C32(0x280bf280), SPH_C32(0xacc6301c), + SPH_C32(0xf5993f70), SPH_C32(0xa5e4e000), SPH_C32(0x910d454a), + SPH_C32(0x611b551c), SPH_C32(0xbb6a6617) }, + { SPH_C32(0x5a8a8000), SPH_C32(0xe2078397), SPH_C32(0x9fe7d930), + SPH_C32(0x3b8b1283), SPH_C32(0xd171f000), SPH_C32(0xcb260334), + SPH_C32(0xe9e64837), SPH_C32(0xa58ce485) }, + { SPH_C32(0x2e1f9000), SPH_C32(0xb82cc5e9), SPH_C32(0x171ac41b), + SPH_C32(0x256d9011), SPH_C32(0x1ad8f000), SPH_C32(0x5b01345d), + SPH_C32(0x523abc30), SPH_C32(0x75784be4) }, + { SPH_C32(0x7809a000), SPH_C32(0xc6773802), SPH_C32(0x35c11760), + SPH_C32(0xd6b6b8c6), SPH_C32(0xf91ee000), SPH_C32(0x21651cf0), + SPH_C32(0xad7e4914), SPH_C32(0xca7297b7) }, + { SPH_C32(0x0c9cb000), SPH_C32(0x9c5c7e7c), SPH_C32(0xbd3c0a4b), + SPH_C32(0xc8503a54), SPH_C32(0x32b7e000), SPH_C32(0xb1422b99), + SPH_C32(0x16a2bd13), SPH_C32(0x1a8638d6) }, + { SPH_C32(0xb3a0a000), SPH_C32(0x56500f6b), SPH_C32(0x8e1de367), + SPH_C32(0x064217a7), SPH_C32(0x4622f000), SPH_C32(0xeb696de7), + SPH_C32(0x9e5fa038), SPH_C32(0x0460ba44) }, + { SPH_C32(0xc735b000), SPH_C32(0x0c7b4915), SPH_C32(0x06e0fe4c), + SPH_C32(0x18a49535), SPH_C32(0x8d8bf000), SPH_C32(0x7b4e5a8e), + SPH_C32(0x2583543f), SPH_C32(0xd4941525) }, + { SPH_C32(0x146bc000), SPH_C32(0x097803c5), SPH_C32(0xde780a93), + SPH_C32(0x84a52f51), SPH_C32(0xf663c000), SPH_C32(0xde81aa29), + SPH_C32(0x3801ebf9), SPH_C32(0xe7fa92ad) }, + { SPH_C32(0x60fed000), SPH_C32(0x535345bb), SPH_C32(0x568517b8), + SPH_C32(0x9a43adc3), SPH_C32(0x3dcac000), SPH_C32(0x4ea69d40), + SPH_C32(0x83dd1ffe), SPH_C32(0x370e3dcc) }, + { SPH_C32(0xdfc2c000), SPH_C32(0x995f34ac), SPH_C32(0x65a4fe94), + SPH_C32(0x54518030), SPH_C32(0x495fd000), SPH_C32(0x148ddb3e), + SPH_C32(0x0b2002d5), SPH_C32(0x29e8bf5e) }, + { SPH_C32(0xab57d000), SPH_C32(0xc37472d2), SPH_C32(0xed59e3bf), + SPH_C32(0x4ab702a2), SPH_C32(0x82f6d000), SPH_C32(0x84aaec57), + SPH_C32(0xb0fcf6d2), SPH_C32(0xf91c103f) }, + { SPH_C32(0xfd41e000), SPH_C32(0xbd2f8f39), SPH_C32(0xcf8230c4), + SPH_C32(0xb96c2a75), SPH_C32(0x6130c000), SPH_C32(0xfecec4fa), + SPH_C32(0x4fb803f6), SPH_C32(0x4616cc6c) }, + { SPH_C32(0x89d4f000), SPH_C32(0xe704c947), SPH_C32(0x477f2def), + SPH_C32(0xa78aa8e7), SPH_C32(0xaa99c000), SPH_C32(0x6ee9f393), + SPH_C32(0xf464f7f1), SPH_C32(0x96e2630d) }, + { SPH_C32(0x36e8e000), SPH_C32(0x2d08b850), SPH_C32(0x745ec4c3), + SPH_C32(0x69988514), SPH_C32(0xde0cd000), SPH_C32(0x34c2b5ed), + SPH_C32(0x7c99eada), SPH_C32(0x8804e19f) }, + { SPH_C32(0x427df000), SPH_C32(0x7723fe2e), SPH_C32(0xfca3d9e8), + SPH_C32(0x777e0786), SPH_C32(0x15a5d000), SPH_C32(0xa4e58284), + SPH_C32(0xc7451edd), SPH_C32(0x58f04efe) }, + { SPH_C32(0x8338c000), SPH_C32(0x29376d16), SPH_C32(0xa9c1e29c), + SPH_C32(0x25497190), SPH_C32(0x881ae000), SPH_C32(0x4a994806), + SPH_C32(0x5e4239a1), SPH_C32(0x7bdfc948) }, + { SPH_C32(0xf7add000), SPH_C32(0x731c2b68), SPH_C32(0x213cffb7), + SPH_C32(0x3baff302), SPH_C32(0x43b3e000), SPH_C32(0xdabe7f6f), + SPH_C32(0xe59ecda6), SPH_C32(0xab2b6629) }, + { SPH_C32(0x4891c000), SPH_C32(0xb9105a7f), SPH_C32(0x121d169b), + SPH_C32(0xf5bddef1), SPH_C32(0x3726f000), SPH_C32(0x80953911), + SPH_C32(0x6d63d08d), SPH_C32(0xb5cde4bb) }, + { SPH_C32(0x3c04d000), SPH_C32(0xe33b1c01), SPH_C32(0x9ae00bb0), + SPH_C32(0xeb5b5c63), SPH_C32(0xfc8ff000), SPH_C32(0x10b20e78), + SPH_C32(0xd6bf248a), SPH_C32(0x65394bda) }, + { SPH_C32(0x6a12e000), SPH_C32(0x9d60e1ea), SPH_C32(0xb83bd8cb), + SPH_C32(0x188074b4), SPH_C32(0x1f49e000), SPH_C32(0x6ad626d5), + SPH_C32(0x29fbd1ae), SPH_C32(0xda339789) }, + { SPH_C32(0x1e87f000), SPH_C32(0xc74ba794), SPH_C32(0x30c6c5e0), + SPH_C32(0x0666f626), SPH_C32(0xd4e0e000), SPH_C32(0xfaf111bc), + SPH_C32(0x922725a9), SPH_C32(0x0ac738e8) }, + { SPH_C32(0xa1bbe000), SPH_C32(0x0d47d683), SPH_C32(0x03e72ccc), + SPH_C32(0xc874dbd5), SPH_C32(0xa075f000), SPH_C32(0xa0da57c2), + SPH_C32(0x1ada3882), SPH_C32(0x1421ba7a) }, + { SPH_C32(0xd52ef000), SPH_C32(0x576c90fd), SPH_C32(0x8b1a31e7), + SPH_C32(0xd6925947), SPH_C32(0x6bdcf000), SPH_C32(0x30fd60ab), + SPH_C32(0xa106cc85), SPH_C32(0xc4d5151b) } +}; + +static const sph_u32 T256_8[256][8] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000) }, + { SPH_C32(0xb7a40100), SPH_C32(0x8a1f31d8), SPH_C32(0x8589d8ab), + SPH_C32(0xe6c46464), SPH_C32(0x734c0000), SPH_C32(0x956fa7d6), + SPH_C32(0xa29d1297), SPH_C32(0x6ee56854) }, + { SPH_C32(0x734c0000), SPH_C32(0x956fa7d6), SPH_C32(0xa29d1297), + SPH_C32(0x6ee56854), SPH_C32(0xc4e80100), SPH_C32(0x1f70960e), + SPH_C32(0x2714ca3c), SPH_C32(0x88210c30) }, + { SPH_C32(0xc4e80100), SPH_C32(0x1f70960e), SPH_C32(0x2714ca3c), + SPH_C32(0x88210c30), SPH_C32(0xb7a40100), SPH_C32(0x8a1f31d8), + SPH_C32(0x8589d8ab), SPH_C32(0xe6c46464) }, + { SPH_C32(0xa7b80200), SPH_C32(0x1f128433), SPH_C32(0x60e5f9f2), + SPH_C32(0x9e147576), SPH_C32(0xee260000), SPH_C32(0x124b683e), + SPH_C32(0x80c2d68f), SPH_C32(0x3bf3ab2c) }, + { SPH_C32(0x101c0300), SPH_C32(0x950db5eb), SPH_C32(0xe56c2159), + SPH_C32(0x78d01112), SPH_C32(0x9d6a0000), SPH_C32(0x8724cfe8), + SPH_C32(0x225fc418), SPH_C32(0x5516c378) }, + { SPH_C32(0xd4f40200), SPH_C32(0x8a7d23e5), SPH_C32(0xc278eb65), + SPH_C32(0xf0f11d22), SPH_C32(0x2ace0100), SPH_C32(0x0d3bfe30), + SPH_C32(0xa7d61cb3), SPH_C32(0xb3d2a71c) }, + { SPH_C32(0x63500300), SPH_C32(0x0062123d), SPH_C32(0x47f133ce), + SPH_C32(0x16357946), SPH_C32(0x59820100), SPH_C32(0x985459e6), + SPH_C32(0x054b0e24), SPH_C32(0xdd37cf48) }, + { SPH_C32(0xee260000), SPH_C32(0x124b683e), SPH_C32(0x80c2d68f), + SPH_C32(0x3bf3ab2c), SPH_C32(0x499e0200), SPH_C32(0x0d59ec0d), + SPH_C32(0xe0272f7d), SPH_C32(0xa5e7de5a) }, + { SPH_C32(0x59820100), SPH_C32(0x985459e6), SPH_C32(0x054b0e24), + SPH_C32(0xdd37cf48), SPH_C32(0x3ad20200), SPH_C32(0x98364bdb), + SPH_C32(0x42ba3dea), SPH_C32(0xcb02b60e) }, + { SPH_C32(0x9d6a0000), SPH_C32(0x8724cfe8), SPH_C32(0x225fc418), + SPH_C32(0x5516c378), SPH_C32(0x8d760300), SPH_C32(0x12297a03), + SPH_C32(0xc733e541), SPH_C32(0x2dc6d26a) }, + { SPH_C32(0x2ace0100), SPH_C32(0x0d3bfe30), SPH_C32(0xa7d61cb3), + SPH_C32(0xb3d2a71c), SPH_C32(0xfe3a0300), SPH_C32(0x8746ddd5), + SPH_C32(0x65aef7d6), SPH_C32(0x4323ba3e) }, + { SPH_C32(0x499e0200), SPH_C32(0x0d59ec0d), SPH_C32(0xe0272f7d), + SPH_C32(0xa5e7de5a), SPH_C32(0xa7b80200), SPH_C32(0x1f128433), + SPH_C32(0x60e5f9f2), SPH_C32(0x9e147576) }, + { SPH_C32(0xfe3a0300), SPH_C32(0x8746ddd5), SPH_C32(0x65aef7d6), + SPH_C32(0x4323ba3e), SPH_C32(0xd4f40200), SPH_C32(0x8a7d23e5), + SPH_C32(0xc278eb65), SPH_C32(0xf0f11d22) }, + { SPH_C32(0x3ad20200), SPH_C32(0x98364bdb), SPH_C32(0x42ba3dea), + SPH_C32(0xcb02b60e), SPH_C32(0x63500300), SPH_C32(0x0062123d), + SPH_C32(0x47f133ce), SPH_C32(0x16357946) }, + { SPH_C32(0x8d760300), SPH_C32(0x12297a03), SPH_C32(0xc733e541), + SPH_C32(0x2dc6d26a), SPH_C32(0x101c0300), SPH_C32(0x950db5eb), + SPH_C32(0xe56c2159), SPH_C32(0x78d01112) }, + { SPH_C32(0x8f3e0400), SPH_C32(0x0d9dc877), SPH_C32(0x6fc548e1), + SPH_C32(0x898d2cd6), SPH_C32(0x14bd0000), SPH_C32(0x2fba37ff), + SPH_C32(0x6a72e5bb), SPH_C32(0x247febe6) }, + { SPH_C32(0x389a0500), SPH_C32(0x8782f9af), SPH_C32(0xea4c904a), + SPH_C32(0x6f4948b2), SPH_C32(0x67f10000), SPH_C32(0xbad59029), + SPH_C32(0xc8eff72c), SPH_C32(0x4a9a83b2) }, + { SPH_C32(0xfc720400), SPH_C32(0x98f26fa1), SPH_C32(0xcd585a76), + SPH_C32(0xe7684482), SPH_C32(0xd0550100), SPH_C32(0x30caa1f1), + SPH_C32(0x4d662f87), SPH_C32(0xac5ee7d6) }, + { SPH_C32(0x4bd60500), SPH_C32(0x12ed5e79), SPH_C32(0x48d182dd), + SPH_C32(0x01ac20e6), SPH_C32(0xa3190100), SPH_C32(0xa5a50627), + SPH_C32(0xeffb3d10), SPH_C32(0xc2bb8f82) }, + { SPH_C32(0x28860600), SPH_C32(0x128f4c44), SPH_C32(0x0f20b113), + SPH_C32(0x179959a0), SPH_C32(0xfa9b0000), SPH_C32(0x3df15fc1), + SPH_C32(0xeab03334), SPH_C32(0x1f8c40ca) }, + { SPH_C32(0x9f220700), SPH_C32(0x98907d9c), SPH_C32(0x8aa969b8), + SPH_C32(0xf15d3dc4), SPH_C32(0x89d70000), SPH_C32(0xa89ef817), + SPH_C32(0x482d21a3), SPH_C32(0x7169289e) }, + { SPH_C32(0x5bca0600), SPH_C32(0x87e0eb92), SPH_C32(0xadbda384), + SPH_C32(0x797c31f4), SPH_C32(0x3e730100), SPH_C32(0x2281c9cf), + SPH_C32(0xcda4f908), SPH_C32(0x97ad4cfa) }, + { SPH_C32(0xec6e0700), SPH_C32(0x0dffda4a), SPH_C32(0x28347b2f), + SPH_C32(0x9fb85590), SPH_C32(0x4d3f0100), SPH_C32(0xb7ee6e19), + SPH_C32(0x6f39eb9f), SPH_C32(0xf94824ae) }, + { SPH_C32(0x61180400), SPH_C32(0x1fd6a049), SPH_C32(0xef079e6e), + SPH_C32(0xb27e87fa), SPH_C32(0x5d230200), SPH_C32(0x22e3dbf2), + SPH_C32(0x8a55cac6), SPH_C32(0x819835bc) }, + { SPH_C32(0xd6bc0500), SPH_C32(0x95c99191), SPH_C32(0x6a8e46c5), + SPH_C32(0x54bae39e), SPH_C32(0x2e6f0200), SPH_C32(0xb78c7c24), + SPH_C32(0x28c8d851), SPH_C32(0xef7d5de8) }, + { SPH_C32(0x12540400), SPH_C32(0x8ab9079f), SPH_C32(0x4d9a8cf9), + SPH_C32(0xdc9befae), SPH_C32(0x99cb0300), SPH_C32(0x3d934dfc), + SPH_C32(0xad4100fa), SPH_C32(0x09b9398c) }, + { SPH_C32(0xa5f00500), SPH_C32(0x00a63647), SPH_C32(0xc8135452), + SPH_C32(0x3a5f8bca), SPH_C32(0xea870300), SPH_C32(0xa8fcea2a), + SPH_C32(0x0fdc126d), SPH_C32(0x675c51d8) }, + { SPH_C32(0xc6a00600), SPH_C32(0x00c4247a), SPH_C32(0x8fe2679c), + SPH_C32(0x2c6af28c), SPH_C32(0xb3050200), SPH_C32(0x30a8b3cc), + SPH_C32(0x0a971c49), SPH_C32(0xba6b9e90) }, + { SPH_C32(0x71040700), SPH_C32(0x8adb15a2), SPH_C32(0x0a6bbf37), + SPH_C32(0xcaae96e8), SPH_C32(0xc0490200), SPH_C32(0xa5c7141a), + SPH_C32(0xa80a0ede), SPH_C32(0xd48ef6c4) }, + { SPH_C32(0xb5ec0600), SPH_C32(0x95ab83ac), SPH_C32(0x2d7f750b), + SPH_C32(0x428f9ad8), SPH_C32(0x77ed0300), SPH_C32(0x2fd825c2), + SPH_C32(0x2d83d675), SPH_C32(0x324a92a0) }, + { SPH_C32(0x02480700), SPH_C32(0x1fb4b274), SPH_C32(0xa8f6ada0), + SPH_C32(0xa44bfebc), SPH_C32(0x04a10300), SPH_C32(0xbab78214), + SPH_C32(0x8f1ec4e2), SPH_C32(0x5caffaf4) }, + { SPH_C32(0x14bd0000), SPH_C32(0x2fba37ff), SPH_C32(0x6a72e5bb), + SPH_C32(0x247febe6), SPH_C32(0x9b830400), SPH_C32(0x2227ff88), + SPH_C32(0x05b7ad5a), SPH_C32(0xadf2c730) }, + { SPH_C32(0xa3190100), SPH_C32(0xa5a50627), SPH_C32(0xeffb3d10), + SPH_C32(0xc2bb8f82), SPH_C32(0xe8cf0400), SPH_C32(0xb748585e), + SPH_C32(0xa72abfcd), SPH_C32(0xc317af64) }, + { SPH_C32(0x67f10000), SPH_C32(0xbad59029), SPH_C32(0xc8eff72c), + SPH_C32(0x4a9a83b2), SPH_C32(0x5f6b0500), SPH_C32(0x3d576986), + SPH_C32(0x22a36766), SPH_C32(0x25d3cb00) }, + { SPH_C32(0xd0550100), SPH_C32(0x30caa1f1), SPH_C32(0x4d662f87), + SPH_C32(0xac5ee7d6), SPH_C32(0x2c270500), SPH_C32(0xa838ce50), + SPH_C32(0x803e75f1), SPH_C32(0x4b36a354) }, + { SPH_C32(0xb3050200), SPH_C32(0x30a8b3cc), SPH_C32(0x0a971c49), + SPH_C32(0xba6b9e90), SPH_C32(0x75a50400), SPH_C32(0x306c97b6), + SPH_C32(0x85757bd5), SPH_C32(0x96016c1c) }, + { SPH_C32(0x04a10300), SPH_C32(0xbab78214), SPH_C32(0x8f1ec4e2), + SPH_C32(0x5caffaf4), SPH_C32(0x06e90400), SPH_C32(0xa5033060), + SPH_C32(0x27e86942), SPH_C32(0xf8e40448) }, + { SPH_C32(0xc0490200), SPH_C32(0xa5c7141a), SPH_C32(0xa80a0ede), + SPH_C32(0xd48ef6c4), SPH_C32(0xb14d0500), SPH_C32(0x2f1c01b8), + SPH_C32(0xa261b1e9), SPH_C32(0x1e20602c) }, + { SPH_C32(0x77ed0300), SPH_C32(0x2fd825c2), SPH_C32(0x2d83d675), + SPH_C32(0x324a92a0), SPH_C32(0xc2010500), SPH_C32(0xba73a66e), + SPH_C32(0x00fca37e), SPH_C32(0x70c50878) }, + { SPH_C32(0xfa9b0000), SPH_C32(0x3df15fc1), SPH_C32(0xeab03334), + SPH_C32(0x1f8c40ca), SPH_C32(0xd21d0600), SPH_C32(0x2f7e1385), + SPH_C32(0xe5908227), SPH_C32(0x0815196a) }, + { SPH_C32(0x4d3f0100), SPH_C32(0xb7ee6e19), SPH_C32(0x6f39eb9f), + SPH_C32(0xf94824ae), SPH_C32(0xa1510600), SPH_C32(0xba11b453), + SPH_C32(0x470d90b0), SPH_C32(0x66f0713e) }, + { SPH_C32(0x89d70000), SPH_C32(0xa89ef817), SPH_C32(0x482d21a3), + SPH_C32(0x7169289e), SPH_C32(0x16f50700), SPH_C32(0x300e858b), + SPH_C32(0xc284481b), SPH_C32(0x8034155a) }, + { SPH_C32(0x3e730100), SPH_C32(0x2281c9cf), SPH_C32(0xcda4f908), + SPH_C32(0x97ad4cfa), SPH_C32(0x65b90700), SPH_C32(0xa561225d), + SPH_C32(0x60195a8c), SPH_C32(0xeed17d0e) }, + { SPH_C32(0x5d230200), SPH_C32(0x22e3dbf2), SPH_C32(0x8a55cac6), + SPH_C32(0x819835bc), SPH_C32(0x3c3b0600), SPH_C32(0x3d357bbb), + SPH_C32(0x655254a8), SPH_C32(0x33e6b246) }, + { SPH_C32(0xea870300), SPH_C32(0xa8fcea2a), SPH_C32(0x0fdc126d), + SPH_C32(0x675c51d8), SPH_C32(0x4f770600), SPH_C32(0xa85adc6d), + SPH_C32(0xc7cf463f), SPH_C32(0x5d03da12) }, + { SPH_C32(0x2e6f0200), SPH_C32(0xb78c7c24), SPH_C32(0x28c8d851), + SPH_C32(0xef7d5de8), SPH_C32(0xf8d30700), SPH_C32(0x2245edb5), + SPH_C32(0x42469e94), SPH_C32(0xbbc7be76) }, + { SPH_C32(0x99cb0300), SPH_C32(0x3d934dfc), SPH_C32(0xad4100fa), + SPH_C32(0x09b9398c), SPH_C32(0x8b9f0700), SPH_C32(0xb72a4a63), + SPH_C32(0xe0db8c03), SPH_C32(0xd522d622) }, + { SPH_C32(0x9b830400), SPH_C32(0x2227ff88), SPH_C32(0x05b7ad5a), + SPH_C32(0xadf2c730), SPH_C32(0x8f3e0400), SPH_C32(0x0d9dc877), + SPH_C32(0x6fc548e1), SPH_C32(0x898d2cd6) }, + { SPH_C32(0x2c270500), SPH_C32(0xa838ce50), SPH_C32(0x803e75f1), + SPH_C32(0x4b36a354), SPH_C32(0xfc720400), SPH_C32(0x98f26fa1), + SPH_C32(0xcd585a76), SPH_C32(0xe7684482) }, + { SPH_C32(0xe8cf0400), SPH_C32(0xb748585e), SPH_C32(0xa72abfcd), + SPH_C32(0xc317af64), SPH_C32(0x4bd60500), SPH_C32(0x12ed5e79), + SPH_C32(0x48d182dd), SPH_C32(0x01ac20e6) }, + { SPH_C32(0x5f6b0500), SPH_C32(0x3d576986), SPH_C32(0x22a36766), + SPH_C32(0x25d3cb00), SPH_C32(0x389a0500), SPH_C32(0x8782f9af), + SPH_C32(0xea4c904a), SPH_C32(0x6f4948b2) }, + { SPH_C32(0x3c3b0600), SPH_C32(0x3d357bbb), SPH_C32(0x655254a8), + SPH_C32(0x33e6b246), SPH_C32(0x61180400), SPH_C32(0x1fd6a049), + SPH_C32(0xef079e6e), SPH_C32(0xb27e87fa) }, + { SPH_C32(0x8b9f0700), SPH_C32(0xb72a4a63), SPH_C32(0xe0db8c03), + SPH_C32(0xd522d622), SPH_C32(0x12540400), SPH_C32(0x8ab9079f), + SPH_C32(0x4d9a8cf9), SPH_C32(0xdc9befae) }, + { SPH_C32(0x4f770600), SPH_C32(0xa85adc6d), SPH_C32(0xc7cf463f), + SPH_C32(0x5d03da12), SPH_C32(0xa5f00500), SPH_C32(0x00a63647), + SPH_C32(0xc8135452), SPH_C32(0x3a5f8bca) }, + { SPH_C32(0xf8d30700), SPH_C32(0x2245edb5), SPH_C32(0x42469e94), + SPH_C32(0xbbc7be76), SPH_C32(0xd6bc0500), SPH_C32(0x95c99191), + SPH_C32(0x6a8e46c5), SPH_C32(0x54bae39e) }, + { SPH_C32(0x75a50400), SPH_C32(0x306c97b6), SPH_C32(0x85757bd5), + SPH_C32(0x96016c1c), SPH_C32(0xc6a00600), SPH_C32(0x00c4247a), + SPH_C32(0x8fe2679c), SPH_C32(0x2c6af28c) }, + { SPH_C32(0xc2010500), SPH_C32(0xba73a66e), SPH_C32(0x00fca37e), + SPH_C32(0x70c50878), SPH_C32(0xb5ec0600), SPH_C32(0x95ab83ac), + SPH_C32(0x2d7f750b), SPH_C32(0x428f9ad8) }, + { SPH_C32(0x06e90400), SPH_C32(0xa5033060), SPH_C32(0x27e86942), + SPH_C32(0xf8e40448), SPH_C32(0x02480700), SPH_C32(0x1fb4b274), + SPH_C32(0xa8f6ada0), SPH_C32(0xa44bfebc) }, + { SPH_C32(0xb14d0500), SPH_C32(0x2f1c01b8), SPH_C32(0xa261b1e9), + SPH_C32(0x1e20602c), SPH_C32(0x71040700), SPH_C32(0x8adb15a2), + SPH_C32(0x0a6bbf37), SPH_C32(0xcaae96e8) }, + { SPH_C32(0xd21d0600), SPH_C32(0x2f7e1385), SPH_C32(0xe5908227), + SPH_C32(0x0815196a), SPH_C32(0x28860600), SPH_C32(0x128f4c44), + SPH_C32(0x0f20b113), SPH_C32(0x179959a0) }, + { SPH_C32(0x65b90700), SPH_C32(0xa561225d), SPH_C32(0x60195a8c), + SPH_C32(0xeed17d0e), SPH_C32(0x5bca0600), SPH_C32(0x87e0eb92), + SPH_C32(0xadbda384), SPH_C32(0x797c31f4) }, + { SPH_C32(0xa1510600), SPH_C32(0xba11b453), SPH_C32(0x470d90b0), + SPH_C32(0x66f0713e), SPH_C32(0xec6e0700), SPH_C32(0x0dffda4a), + SPH_C32(0x28347b2f), SPH_C32(0x9fb85590) }, + { SPH_C32(0x16f50700), SPH_C32(0x300e858b), SPH_C32(0xc284481b), + SPH_C32(0x8034155a), SPH_C32(0x9f220700), SPH_C32(0x98907d9c), + SPH_C32(0x8aa969b8), SPH_C32(0xf15d3dc4) }, + { SPH_C32(0xde320800), SPH_C32(0x288350fe), SPH_C32(0x71852ac7), + SPH_C32(0xa6bf9f96), SPH_C32(0xe18b0000), SPH_C32(0x5459887d), + SPH_C32(0xbf1283d3), SPH_C32(0x1b666a73) }, + { SPH_C32(0x69960900), SPH_C32(0xa29c6126), SPH_C32(0xf40cf26c), + SPH_C32(0x407bfbf2), SPH_C32(0x92c70000), SPH_C32(0xc1362fab), + SPH_C32(0x1d8f9144), SPH_C32(0x75830227) }, + { SPH_C32(0xad7e0800), SPH_C32(0xbdecf728), SPH_C32(0xd3183850), + SPH_C32(0xc85af7c2), SPH_C32(0x25630100), SPH_C32(0x4b291e73), + SPH_C32(0x980649ef), SPH_C32(0x93476643) }, + { SPH_C32(0x1ada0900), SPH_C32(0x37f3c6f0), SPH_C32(0x5691e0fb), + SPH_C32(0x2e9e93a6), SPH_C32(0x562f0100), SPH_C32(0xde46b9a5), + SPH_C32(0x3a9b5b78), SPH_C32(0xfda20e17) }, + { SPH_C32(0x798a0a00), SPH_C32(0x3791d4cd), SPH_C32(0x1160d335), + SPH_C32(0x38abeae0), SPH_C32(0x0fad0000), SPH_C32(0x4612e043), + SPH_C32(0x3fd0555c), SPH_C32(0x2095c15f) }, + { SPH_C32(0xce2e0b00), SPH_C32(0xbd8ee515), SPH_C32(0x94e90b9e), + SPH_C32(0xde6f8e84), SPH_C32(0x7ce10000), SPH_C32(0xd37d4795), + SPH_C32(0x9d4d47cb), SPH_C32(0x4e70a90b) }, + { SPH_C32(0x0ac60a00), SPH_C32(0xa2fe731b), SPH_C32(0xb3fdc1a2), + SPH_C32(0x564e82b4), SPH_C32(0xcb450100), SPH_C32(0x5962764d), + SPH_C32(0x18c49f60), SPH_C32(0xa8b4cd6f) }, + { SPH_C32(0xbd620b00), SPH_C32(0x28e142c3), SPH_C32(0x36741909), + SPH_C32(0xb08ae6d0), SPH_C32(0xb8090100), SPH_C32(0xcc0dd19b), + SPH_C32(0xba598df7), SPH_C32(0xc651a53b) }, + { SPH_C32(0x30140800), SPH_C32(0x3ac838c0), SPH_C32(0xf147fc48), + SPH_C32(0x9d4c34ba), SPH_C32(0xa8150200), SPH_C32(0x59006470), + SPH_C32(0x5f35acae), SPH_C32(0xbe81b429) }, + { SPH_C32(0x87b00900), SPH_C32(0xb0d70918), SPH_C32(0x74ce24e3), + SPH_C32(0x7b8850de), SPH_C32(0xdb590200), SPH_C32(0xcc6fc3a6), + SPH_C32(0xfda8be39), SPH_C32(0xd064dc7d) }, + { SPH_C32(0x43580800), SPH_C32(0xafa79f16), SPH_C32(0x53daeedf), + SPH_C32(0xf3a95cee), SPH_C32(0x6cfd0300), SPH_C32(0x4670f27e), + SPH_C32(0x78216692), SPH_C32(0x36a0b819) }, + { SPH_C32(0xf4fc0900), SPH_C32(0x25b8aece), SPH_C32(0xd6533674), + SPH_C32(0x156d388a), SPH_C32(0x1fb10300), SPH_C32(0xd31f55a8), + SPH_C32(0xdabc7405), SPH_C32(0x5845d04d) }, + { SPH_C32(0x97ac0a00), SPH_C32(0x25dabcf3), SPH_C32(0x91a205ba), + SPH_C32(0x035841cc), SPH_C32(0x46330200), SPH_C32(0x4b4b0c4e), + SPH_C32(0xdff77a21), SPH_C32(0x85721f05) }, + { SPH_C32(0x20080b00), SPH_C32(0xafc58d2b), SPH_C32(0x142bdd11), + SPH_C32(0xe59c25a8), SPH_C32(0x357f0200), SPH_C32(0xde24ab98), + SPH_C32(0x7d6a68b6), SPH_C32(0xeb977751) }, + { SPH_C32(0xe4e00a00), SPH_C32(0xb0b51b25), SPH_C32(0x333f172d), + SPH_C32(0x6dbd2998), SPH_C32(0x82db0300), SPH_C32(0x543b9a40), + SPH_C32(0xf8e3b01d), SPH_C32(0x0d531335) }, + { SPH_C32(0x53440b00), SPH_C32(0x3aaa2afd), SPH_C32(0xb6b6cf86), + SPH_C32(0x8b794dfc), SPH_C32(0xf1970300), SPH_C32(0xc1543d96), + SPH_C32(0x5a7ea28a), SPH_C32(0x63b67b61) }, + { SPH_C32(0x510c0c00), SPH_C32(0x251e9889), SPH_C32(0x1e406226), + SPH_C32(0x2f32b340), SPH_C32(0xf5360000), SPH_C32(0x7be3bf82), + SPH_C32(0xd5606668), SPH_C32(0x3f198195) }, + { SPH_C32(0xe6a80d00), SPH_C32(0xaf01a951), SPH_C32(0x9bc9ba8d), + SPH_C32(0xc9f6d724), SPH_C32(0x867a0000), SPH_C32(0xee8c1854), + SPH_C32(0x77fd74ff), SPH_C32(0x51fce9c1) }, + { SPH_C32(0x22400c00), SPH_C32(0xb0713f5f), SPH_C32(0xbcdd70b1), + SPH_C32(0x41d7db14), SPH_C32(0x31de0100), SPH_C32(0x6493298c), + SPH_C32(0xf274ac54), SPH_C32(0xb7388da5) }, + { SPH_C32(0x95e40d00), SPH_C32(0x3a6e0e87), SPH_C32(0x3954a81a), + SPH_C32(0xa713bf70), SPH_C32(0x42920100), SPH_C32(0xf1fc8e5a), + SPH_C32(0x50e9bec3), SPH_C32(0xd9dde5f1) }, + { SPH_C32(0xf6b40e00), SPH_C32(0x3a0c1cba), SPH_C32(0x7ea59bd4), + SPH_C32(0xb126c636), SPH_C32(0x1b100000), SPH_C32(0x69a8d7bc), + SPH_C32(0x55a2b0e7), SPH_C32(0x04ea2ab9) }, + { SPH_C32(0x41100f00), SPH_C32(0xb0132d62), SPH_C32(0xfb2c437f), + SPH_C32(0x57e2a252), SPH_C32(0x685c0000), SPH_C32(0xfcc7706a), + SPH_C32(0xf73fa270), SPH_C32(0x6a0f42ed) }, + { SPH_C32(0x85f80e00), SPH_C32(0xaf63bb6c), SPH_C32(0xdc388943), + SPH_C32(0xdfc3ae62), SPH_C32(0xdff80100), SPH_C32(0x76d841b2), + SPH_C32(0x72b67adb), SPH_C32(0x8ccb2689) }, + { SPH_C32(0x325c0f00), SPH_C32(0x257c8ab4), SPH_C32(0x59b151e8), + SPH_C32(0x3907ca06), SPH_C32(0xacb40100), SPH_C32(0xe3b7e664), + SPH_C32(0xd02b684c), SPH_C32(0xe22e4edd) }, + { SPH_C32(0xbf2a0c00), SPH_C32(0x3755f0b7), SPH_C32(0x9e82b4a9), + SPH_C32(0x14c1186c), SPH_C32(0xbca80200), SPH_C32(0x76ba538f), + SPH_C32(0x35474915), SPH_C32(0x9afe5fcf) }, + { SPH_C32(0x088e0d00), SPH_C32(0xbd4ac16f), SPH_C32(0x1b0b6c02), + SPH_C32(0xf2057c08), SPH_C32(0xcfe40200), SPH_C32(0xe3d5f459), + SPH_C32(0x97da5b82), SPH_C32(0xf41b379b) }, + { SPH_C32(0xcc660c00), SPH_C32(0xa23a5761), SPH_C32(0x3c1fa63e), + SPH_C32(0x7a247038), SPH_C32(0x78400300), SPH_C32(0x69cac581), + SPH_C32(0x12538329), SPH_C32(0x12df53ff) }, + { SPH_C32(0x7bc20d00), SPH_C32(0x282566b9), SPH_C32(0xb9967e95), + SPH_C32(0x9ce0145c), SPH_C32(0x0b0c0300), SPH_C32(0xfca56257), + SPH_C32(0xb0ce91be), SPH_C32(0x7c3a3bab) }, + { SPH_C32(0x18920e00), SPH_C32(0x28477484), SPH_C32(0xfe674d5b), + SPH_C32(0x8ad56d1a), SPH_C32(0x528e0200), SPH_C32(0x64f13bb1), + SPH_C32(0xb5859f9a), SPH_C32(0xa10df4e3) }, + { SPH_C32(0xaf360f00), SPH_C32(0xa258455c), SPH_C32(0x7bee95f0), + SPH_C32(0x6c11097e), SPH_C32(0x21c20200), SPH_C32(0xf19e9c67), + SPH_C32(0x17188d0d), SPH_C32(0xcfe89cb7) }, + { SPH_C32(0x6bde0e00), SPH_C32(0xbd28d352), SPH_C32(0x5cfa5fcc), + SPH_C32(0xe430054e), SPH_C32(0x96660300), SPH_C32(0x7b81adbf), + SPH_C32(0x929155a6), SPH_C32(0x292cf8d3) }, + { SPH_C32(0xdc7a0f00), SPH_C32(0x3737e28a), SPH_C32(0xd9738767), + SPH_C32(0x02f4612a), SPH_C32(0xe52a0300), SPH_C32(0xeeee0a69), + SPH_C32(0x300c4731), SPH_C32(0x47c99087) }, + { SPH_C32(0xca8f0800), SPH_C32(0x07396701), SPH_C32(0x1bf7cf7c), + SPH_C32(0x82c07470), SPH_C32(0x7a080400), SPH_C32(0x767e77f5), + SPH_C32(0xbaa52e89), SPH_C32(0xb694ad43) }, + { SPH_C32(0x7d2b0900), SPH_C32(0x8d2656d9), SPH_C32(0x9e7e17d7), + SPH_C32(0x64041014), SPH_C32(0x09440400), SPH_C32(0xe311d023), + SPH_C32(0x18383c1e), SPH_C32(0xd871c517) }, + { SPH_C32(0xb9c30800), SPH_C32(0x9256c0d7), SPH_C32(0xb96addeb), + SPH_C32(0xec251c24), SPH_C32(0xbee00500), SPH_C32(0x690ee1fb), + SPH_C32(0x9db1e4b5), SPH_C32(0x3eb5a173) }, + { SPH_C32(0x0e670900), SPH_C32(0x1849f10f), SPH_C32(0x3ce30540), + SPH_C32(0x0ae17840), SPH_C32(0xcdac0500), SPH_C32(0xfc61462d), + SPH_C32(0x3f2cf622), SPH_C32(0x5050c927) }, + { SPH_C32(0x6d370a00), SPH_C32(0x182be332), SPH_C32(0x7b12368e), + SPH_C32(0x1cd40106), SPH_C32(0x942e0400), SPH_C32(0x64351fcb), + SPH_C32(0x3a67f806), SPH_C32(0x8d67066f) }, + { SPH_C32(0xda930b00), SPH_C32(0x9234d2ea), SPH_C32(0xfe9bee25), + SPH_C32(0xfa106562), SPH_C32(0xe7620400), SPH_C32(0xf15ab81d), + SPH_C32(0x98faea91), SPH_C32(0xe3826e3b) }, + { SPH_C32(0x1e7b0a00), SPH_C32(0x8d4444e4), SPH_C32(0xd98f2419), + SPH_C32(0x72316952), SPH_C32(0x50c60500), SPH_C32(0x7b4589c5), + SPH_C32(0x1d73323a), SPH_C32(0x05460a5f) }, + { SPH_C32(0xa9df0b00), SPH_C32(0x075b753c), SPH_C32(0x5c06fcb2), + SPH_C32(0x94f50d36), SPH_C32(0x238a0500), SPH_C32(0xee2a2e13), + SPH_C32(0xbfee20ad), SPH_C32(0x6ba3620b) }, + { SPH_C32(0x24a90800), SPH_C32(0x15720f3f), SPH_C32(0x9b3519f3), + SPH_C32(0xb933df5c), SPH_C32(0x33960600), SPH_C32(0x7b279bf8), + SPH_C32(0x5a8201f4), SPH_C32(0x13737319) }, + { SPH_C32(0x930d0900), SPH_C32(0x9f6d3ee7), SPH_C32(0x1ebcc158), + SPH_C32(0x5ff7bb38), SPH_C32(0x40da0600), SPH_C32(0xee483c2e), + SPH_C32(0xf81f1363), SPH_C32(0x7d961b4d) }, + { SPH_C32(0x57e50800), SPH_C32(0x801da8e9), SPH_C32(0x39a80b64), + SPH_C32(0xd7d6b708), SPH_C32(0xf77e0700), SPH_C32(0x64570df6), + SPH_C32(0x7d96cbc8), SPH_C32(0x9b527f29) }, + { SPH_C32(0xe0410900), SPH_C32(0x0a029931), SPH_C32(0xbc21d3cf), + SPH_C32(0x3112d36c), SPH_C32(0x84320700), SPH_C32(0xf138aa20), + SPH_C32(0xdf0bd95f), SPH_C32(0xf5b7177d) }, + { SPH_C32(0x83110a00), SPH_C32(0x0a608b0c), SPH_C32(0xfbd0e001), + SPH_C32(0x2727aa2a), SPH_C32(0xddb00600), SPH_C32(0x696cf3c6), + SPH_C32(0xda40d77b), SPH_C32(0x2880d835) }, + { SPH_C32(0x34b50b00), SPH_C32(0x807fbad4), SPH_C32(0x7e5938aa), + SPH_C32(0xc1e3ce4e), SPH_C32(0xaefc0600), SPH_C32(0xfc035410), + SPH_C32(0x78ddc5ec), SPH_C32(0x4665b061) }, + { SPH_C32(0xf05d0a00), SPH_C32(0x9f0f2cda), SPH_C32(0x594df296), + SPH_C32(0x49c2c27e), SPH_C32(0x19580700), SPH_C32(0x761c65c8), + SPH_C32(0xfd541d47), SPH_C32(0xa0a1d405) }, + { SPH_C32(0x47f90b00), SPH_C32(0x15101d02), SPH_C32(0xdcc42a3d), + SPH_C32(0xaf06a61a), SPH_C32(0x6a140700), SPH_C32(0xe373c21e), + SPH_C32(0x5fc90fd0), SPH_C32(0xce44bc51) }, + { SPH_C32(0x45b10c00), SPH_C32(0x0aa4af76), SPH_C32(0x7432879d), + SPH_C32(0x0b4d58a6), SPH_C32(0x6eb50400), SPH_C32(0x59c4400a), + SPH_C32(0xd0d7cb32), SPH_C32(0x92eb46a5) }, + { SPH_C32(0xf2150d00), SPH_C32(0x80bb9eae), SPH_C32(0xf1bb5f36), + SPH_C32(0xed893cc2), SPH_C32(0x1df90400), SPH_C32(0xccabe7dc), + SPH_C32(0x724ad9a5), SPH_C32(0xfc0e2ef1) }, + { SPH_C32(0x36fd0c00), SPH_C32(0x9fcb08a0), SPH_C32(0xd6af950a), + SPH_C32(0x65a830f2), SPH_C32(0xaa5d0500), SPH_C32(0x46b4d604), + SPH_C32(0xf7c3010e), SPH_C32(0x1aca4a95) }, + { SPH_C32(0x81590d00), SPH_C32(0x15d43978), SPH_C32(0x53264da1), + SPH_C32(0x836c5496), SPH_C32(0xd9110500), SPH_C32(0xd3db71d2), + SPH_C32(0x555e1399), SPH_C32(0x742f22c1) }, + { SPH_C32(0xe2090e00), SPH_C32(0x15b62b45), SPH_C32(0x14d77e6f), + SPH_C32(0x95592dd0), SPH_C32(0x80930400), SPH_C32(0x4b8f2834), + SPH_C32(0x50151dbd), SPH_C32(0xa918ed89) }, + { SPH_C32(0x55ad0f00), SPH_C32(0x9fa91a9d), SPH_C32(0x915ea6c4), + SPH_C32(0x739d49b4), SPH_C32(0xf3df0400), SPH_C32(0xdee08fe2), + SPH_C32(0xf2880f2a), SPH_C32(0xc7fd85dd) }, + { SPH_C32(0x91450e00), SPH_C32(0x80d98c93), SPH_C32(0xb64a6cf8), + SPH_C32(0xfbbc4584), SPH_C32(0x447b0500), SPH_C32(0x54ffbe3a), + SPH_C32(0x7701d781), SPH_C32(0x2139e1b9) }, + { SPH_C32(0x26e10f00), SPH_C32(0x0ac6bd4b), SPH_C32(0x33c3b453), + SPH_C32(0x1d7821e0), SPH_C32(0x37370500), SPH_C32(0xc19019ec), + SPH_C32(0xd59cc516), SPH_C32(0x4fdc89ed) }, + { SPH_C32(0xab970c00), SPH_C32(0x18efc748), SPH_C32(0xf4f05112), + SPH_C32(0x30bef38a), SPH_C32(0x272b0600), SPH_C32(0x549dac07), + SPH_C32(0x30f0e44f), SPH_C32(0x370c98ff) }, + { SPH_C32(0x1c330d00), SPH_C32(0x92f0f690), SPH_C32(0x717989b9), + SPH_C32(0xd67a97ee), SPH_C32(0x54670600), SPH_C32(0xc1f20bd1), + SPH_C32(0x926df6d8), SPH_C32(0x59e9f0ab) }, + { SPH_C32(0xd8db0c00), SPH_C32(0x8d80609e), SPH_C32(0x566d4385), + SPH_C32(0x5e5b9bde), SPH_C32(0xe3c30700), SPH_C32(0x4bed3a09), + SPH_C32(0x17e42e73), SPH_C32(0xbf2d94cf) }, + { SPH_C32(0x6f7f0d00), SPH_C32(0x079f5146), SPH_C32(0xd3e49b2e), + SPH_C32(0xb89fffba), SPH_C32(0x908f0700), SPH_C32(0xde829ddf), + SPH_C32(0xb5793ce4), SPH_C32(0xd1c8fc9b) }, + { SPH_C32(0x0c2f0e00), SPH_C32(0x07fd437b), SPH_C32(0x9415a8e0), + SPH_C32(0xaeaa86fc), SPH_C32(0xc90d0600), SPH_C32(0x46d6c439), + SPH_C32(0xb03232c0), SPH_C32(0x0cff33d3) }, + { SPH_C32(0xbb8b0f00), SPH_C32(0x8de272a3), SPH_C32(0x119c704b), + SPH_C32(0x486ee298), SPH_C32(0xba410600), SPH_C32(0xd3b963ef), + SPH_C32(0x12af2057), SPH_C32(0x621a5b87) }, + { SPH_C32(0x7f630e00), SPH_C32(0x9292e4ad), SPH_C32(0x3688ba77), + SPH_C32(0xc04feea8), SPH_C32(0x0de50700), SPH_C32(0x59a65237), + SPH_C32(0x9726f8fc), SPH_C32(0x84de3fe3) }, + { SPH_C32(0xc8c70f00), SPH_C32(0x188dd575), SPH_C32(0xb30162dc), + SPH_C32(0x268b8acc), SPH_C32(0x7ea90700), SPH_C32(0xccc9f5e1), + SPH_C32(0x35bbea6b), SPH_C32(0xea3b57b7) }, + { SPH_C32(0xe18b0000), SPH_C32(0x5459887d), SPH_C32(0xbf1283d3), + SPH_C32(0x1b666a73), SPH_C32(0x3fb90800), SPH_C32(0x7cdad883), + SPH_C32(0xce97a914), SPH_C32(0xbdd9f5e5) }, + { SPH_C32(0x562f0100), SPH_C32(0xde46b9a5), SPH_C32(0x3a9b5b78), + SPH_C32(0xfda20e17), SPH_C32(0x4cf50800), SPH_C32(0xe9b57f55), + SPH_C32(0x6c0abb83), SPH_C32(0xd33c9db1) }, + { SPH_C32(0x92c70000), SPH_C32(0xc1362fab), SPH_C32(0x1d8f9144), + SPH_C32(0x75830227), SPH_C32(0xfb510900), SPH_C32(0x63aa4e8d), + SPH_C32(0xe9836328), SPH_C32(0x35f8f9d5) }, + { SPH_C32(0x25630100), SPH_C32(0x4b291e73), SPH_C32(0x980649ef), + SPH_C32(0x93476643), SPH_C32(0x881d0900), SPH_C32(0xf6c5e95b), + SPH_C32(0x4b1e71bf), SPH_C32(0x5b1d9181) }, + { SPH_C32(0x46330200), SPH_C32(0x4b4b0c4e), SPH_C32(0xdff77a21), + SPH_C32(0x85721f05), SPH_C32(0xd19f0800), SPH_C32(0x6e91b0bd), + SPH_C32(0x4e557f9b), SPH_C32(0x862a5ec9) }, + { SPH_C32(0xf1970300), SPH_C32(0xc1543d96), SPH_C32(0x5a7ea28a), + SPH_C32(0x63b67b61), SPH_C32(0xa2d30800), SPH_C32(0xfbfe176b), + SPH_C32(0xecc86d0c), SPH_C32(0xe8cf369d) }, + { SPH_C32(0x357f0200), SPH_C32(0xde24ab98), SPH_C32(0x7d6a68b6), + SPH_C32(0xeb977751), SPH_C32(0x15770900), SPH_C32(0x71e126b3), + SPH_C32(0x6941b5a7), SPH_C32(0x0e0b52f9) }, + { SPH_C32(0x82db0300), SPH_C32(0x543b9a40), SPH_C32(0xf8e3b01d), + SPH_C32(0x0d531335), SPH_C32(0x663b0900), SPH_C32(0xe48e8165), + SPH_C32(0xcbdca730), SPH_C32(0x60ee3aad) }, + { SPH_C32(0x0fad0000), SPH_C32(0x4612e043), SPH_C32(0x3fd0555c), + SPH_C32(0x2095c15f), SPH_C32(0x76270a00), SPH_C32(0x7183348e), + SPH_C32(0x2eb08669), SPH_C32(0x183e2bbf) }, + { SPH_C32(0xb8090100), SPH_C32(0xcc0dd19b), SPH_C32(0xba598df7), + SPH_C32(0xc651a53b), SPH_C32(0x056b0a00), SPH_C32(0xe4ec9358), + SPH_C32(0x8c2d94fe), SPH_C32(0x76db43eb) }, + { SPH_C32(0x7ce10000), SPH_C32(0xd37d4795), SPH_C32(0x9d4d47cb), + SPH_C32(0x4e70a90b), SPH_C32(0xb2cf0b00), SPH_C32(0x6ef3a280), + SPH_C32(0x09a44c55), SPH_C32(0x901f278f) }, + { SPH_C32(0xcb450100), SPH_C32(0x5962764d), SPH_C32(0x18c49f60), + SPH_C32(0xa8b4cd6f), SPH_C32(0xc1830b00), SPH_C32(0xfb9c0556), + SPH_C32(0xab395ec2), SPH_C32(0xfefa4fdb) }, + { SPH_C32(0xa8150200), SPH_C32(0x59006470), SPH_C32(0x5f35acae), + SPH_C32(0xbe81b429), SPH_C32(0x98010a00), SPH_C32(0x63c85cb0), + SPH_C32(0xae7250e6), SPH_C32(0x23cd8093) }, + { SPH_C32(0x1fb10300), SPH_C32(0xd31f55a8), SPH_C32(0xdabc7405), + SPH_C32(0x5845d04d), SPH_C32(0xeb4d0a00), SPH_C32(0xf6a7fb66), + SPH_C32(0x0cef4271), SPH_C32(0x4d28e8c7) }, + { SPH_C32(0xdb590200), SPH_C32(0xcc6fc3a6), SPH_C32(0xfda8be39), + SPH_C32(0xd064dc7d), SPH_C32(0x5ce90b00), SPH_C32(0x7cb8cabe), + SPH_C32(0x89669ada), SPH_C32(0xabec8ca3) }, + { SPH_C32(0x6cfd0300), SPH_C32(0x4670f27e), SPH_C32(0x78216692), + SPH_C32(0x36a0b819), SPH_C32(0x2fa50b00), SPH_C32(0xe9d76d68), + SPH_C32(0x2bfb884d), SPH_C32(0xc509e4f7) }, + { SPH_C32(0x6eb50400), SPH_C32(0x59c4400a), SPH_C32(0xd0d7cb32), + SPH_C32(0x92eb46a5), SPH_C32(0x2b040800), SPH_C32(0x5360ef7c), + SPH_C32(0xa4e54caf), SPH_C32(0x99a61e03) }, + { SPH_C32(0xd9110500), SPH_C32(0xd3db71d2), SPH_C32(0x555e1399), + SPH_C32(0x742f22c1), SPH_C32(0x58480800), SPH_C32(0xc60f48aa), + SPH_C32(0x06785e38), SPH_C32(0xf7437657) }, + { SPH_C32(0x1df90400), SPH_C32(0xccabe7dc), SPH_C32(0x724ad9a5), + SPH_C32(0xfc0e2ef1), SPH_C32(0xefec0900), SPH_C32(0x4c107972), + SPH_C32(0x83f18693), SPH_C32(0x11871233) }, + { SPH_C32(0xaa5d0500), SPH_C32(0x46b4d604), SPH_C32(0xf7c3010e), + SPH_C32(0x1aca4a95), SPH_C32(0x9ca00900), SPH_C32(0xd97fdea4), + SPH_C32(0x216c9404), SPH_C32(0x7f627a67) }, + { SPH_C32(0xc90d0600), SPH_C32(0x46d6c439), SPH_C32(0xb03232c0), + SPH_C32(0x0cff33d3), SPH_C32(0xc5220800), SPH_C32(0x412b8742), + SPH_C32(0x24279a20), SPH_C32(0xa255b52f) }, + { SPH_C32(0x7ea90700), SPH_C32(0xccc9f5e1), SPH_C32(0x35bbea6b), + SPH_C32(0xea3b57b7), SPH_C32(0xb66e0800), SPH_C32(0xd4442094), + SPH_C32(0x86ba88b7), SPH_C32(0xccb0dd7b) }, + { SPH_C32(0xba410600), SPH_C32(0xd3b963ef), SPH_C32(0x12af2057), + SPH_C32(0x621a5b87), SPH_C32(0x01ca0900), SPH_C32(0x5e5b114c), + SPH_C32(0x0333501c), SPH_C32(0x2a74b91f) }, + { SPH_C32(0x0de50700), SPH_C32(0x59a65237), SPH_C32(0x9726f8fc), + SPH_C32(0x84de3fe3), SPH_C32(0x72860900), SPH_C32(0xcb34b69a), + SPH_C32(0xa1ae428b), SPH_C32(0x4491d14b) }, + { SPH_C32(0x80930400), SPH_C32(0x4b8f2834), SPH_C32(0x50151dbd), + SPH_C32(0xa918ed89), SPH_C32(0x629a0a00), SPH_C32(0x5e390371), + SPH_C32(0x44c263d2), SPH_C32(0x3c41c059) }, + { SPH_C32(0x37370500), SPH_C32(0xc19019ec), SPH_C32(0xd59cc516), + SPH_C32(0x4fdc89ed), SPH_C32(0x11d60a00), SPH_C32(0xcb56a4a7), + SPH_C32(0xe65f7145), SPH_C32(0x52a4a80d) }, + { SPH_C32(0xf3df0400), SPH_C32(0xdee08fe2), SPH_C32(0xf2880f2a), + SPH_C32(0xc7fd85dd), SPH_C32(0xa6720b00), SPH_C32(0x4149957f), + SPH_C32(0x63d6a9ee), SPH_C32(0xb460cc69) }, + { SPH_C32(0x447b0500), SPH_C32(0x54ffbe3a), SPH_C32(0x7701d781), + SPH_C32(0x2139e1b9), SPH_C32(0xd53e0b00), SPH_C32(0xd42632a9), + SPH_C32(0xc14bbb79), SPH_C32(0xda85a43d) }, + { SPH_C32(0x272b0600), SPH_C32(0x549dac07), SPH_C32(0x30f0e44f), + SPH_C32(0x370c98ff), SPH_C32(0x8cbc0a00), SPH_C32(0x4c726b4f), + SPH_C32(0xc400b55d), SPH_C32(0x07b26b75) }, + { SPH_C32(0x908f0700), SPH_C32(0xde829ddf), SPH_C32(0xb5793ce4), + SPH_C32(0xd1c8fc9b), SPH_C32(0xfff00a00), SPH_C32(0xd91dcc99), + SPH_C32(0x669da7ca), SPH_C32(0x69570321) }, + { SPH_C32(0x54670600), SPH_C32(0xc1f20bd1), SPH_C32(0x926df6d8), + SPH_C32(0x59e9f0ab), SPH_C32(0x48540b00), SPH_C32(0x5302fd41), + SPH_C32(0xe3147f61), SPH_C32(0x8f936745) }, + { SPH_C32(0xe3c30700), SPH_C32(0x4bed3a09), SPH_C32(0x17e42e73), + SPH_C32(0xbf2d94cf), SPH_C32(0x3b180b00), SPH_C32(0xc66d5a97), + SPH_C32(0x41896df6), SPH_C32(0xe1760f11) }, + { SPH_C32(0xf5360000), SPH_C32(0x7be3bf82), SPH_C32(0xd5606668), + SPH_C32(0x3f198195), SPH_C32(0xa43a0c00), SPH_C32(0x5efd270b), + SPH_C32(0xcb20044e), SPH_C32(0x102b32d5) }, + { SPH_C32(0x42920100), SPH_C32(0xf1fc8e5a), SPH_C32(0x50e9bec3), + SPH_C32(0xd9dde5f1), SPH_C32(0xd7760c00), SPH_C32(0xcb9280dd), + SPH_C32(0x69bd16d9), SPH_C32(0x7ece5a81) }, + { SPH_C32(0x867a0000), SPH_C32(0xee8c1854), SPH_C32(0x77fd74ff), + SPH_C32(0x51fce9c1), SPH_C32(0x60d20d00), SPH_C32(0x418db105), + SPH_C32(0xec34ce72), SPH_C32(0x980a3ee5) }, + { SPH_C32(0x31de0100), SPH_C32(0x6493298c), SPH_C32(0xf274ac54), + SPH_C32(0xb7388da5), SPH_C32(0x139e0d00), SPH_C32(0xd4e216d3), + SPH_C32(0x4ea9dce5), SPH_C32(0xf6ef56b1) }, + { SPH_C32(0x528e0200), SPH_C32(0x64f13bb1), SPH_C32(0xb5859f9a), + SPH_C32(0xa10df4e3), SPH_C32(0x4a1c0c00), SPH_C32(0x4cb64f35), + SPH_C32(0x4be2d2c1), SPH_C32(0x2bd899f9) }, + { SPH_C32(0xe52a0300), SPH_C32(0xeeee0a69), SPH_C32(0x300c4731), + SPH_C32(0x47c99087), SPH_C32(0x39500c00), SPH_C32(0xd9d9e8e3), + SPH_C32(0xe97fc056), SPH_C32(0x453df1ad) }, + { SPH_C32(0x21c20200), SPH_C32(0xf19e9c67), SPH_C32(0x17188d0d), + SPH_C32(0xcfe89cb7), SPH_C32(0x8ef40d00), SPH_C32(0x53c6d93b), + SPH_C32(0x6cf618fd), SPH_C32(0xa3f995c9) }, + { SPH_C32(0x96660300), SPH_C32(0x7b81adbf), SPH_C32(0x929155a6), + SPH_C32(0x292cf8d3), SPH_C32(0xfdb80d00), SPH_C32(0xc6a97eed), + SPH_C32(0xce6b0a6a), SPH_C32(0xcd1cfd9d) }, + { SPH_C32(0x1b100000), SPH_C32(0x69a8d7bc), SPH_C32(0x55a2b0e7), + SPH_C32(0x04ea2ab9), SPH_C32(0xeda40e00), SPH_C32(0x53a4cb06), + SPH_C32(0x2b072b33), SPH_C32(0xb5ccec8f) }, + { SPH_C32(0xacb40100), SPH_C32(0xe3b7e664), SPH_C32(0xd02b684c), + SPH_C32(0xe22e4edd), SPH_C32(0x9ee80e00), SPH_C32(0xc6cb6cd0), + SPH_C32(0x899a39a4), SPH_C32(0xdb2984db) }, + { SPH_C32(0x685c0000), SPH_C32(0xfcc7706a), SPH_C32(0xf73fa270), + SPH_C32(0x6a0f42ed), SPH_C32(0x294c0f00), SPH_C32(0x4cd45d08), + SPH_C32(0x0c13e10f), SPH_C32(0x3dede0bf) }, + { SPH_C32(0xdff80100), SPH_C32(0x76d841b2), SPH_C32(0x72b67adb), + SPH_C32(0x8ccb2689), SPH_C32(0x5a000f00), SPH_C32(0xd9bbfade), + SPH_C32(0xae8ef398), SPH_C32(0x530888eb) }, + { SPH_C32(0xbca80200), SPH_C32(0x76ba538f), SPH_C32(0x35474915), + SPH_C32(0x9afe5fcf), SPH_C32(0x03820e00), SPH_C32(0x41efa338), + SPH_C32(0xabc5fdbc), SPH_C32(0x8e3f47a3) }, + { SPH_C32(0x0b0c0300), SPH_C32(0xfca56257), SPH_C32(0xb0ce91be), + SPH_C32(0x7c3a3bab), SPH_C32(0x70ce0e00), SPH_C32(0xd48004ee), + SPH_C32(0x0958ef2b), SPH_C32(0xe0da2ff7) }, + { SPH_C32(0xcfe40200), SPH_C32(0xe3d5f459), SPH_C32(0x97da5b82), + SPH_C32(0xf41b379b), SPH_C32(0xc76a0f00), SPH_C32(0x5e9f3536), + SPH_C32(0x8cd13780), SPH_C32(0x061e4b93) }, + { SPH_C32(0x78400300), SPH_C32(0x69cac581), SPH_C32(0x12538329), + SPH_C32(0x12df53ff), SPH_C32(0xb4260f00), SPH_C32(0xcbf092e0), + SPH_C32(0x2e4c2517), SPH_C32(0x68fb23c7) }, + { SPH_C32(0x7a080400), SPH_C32(0x767e77f5), SPH_C32(0xbaa52e89), + SPH_C32(0xb694ad43), SPH_C32(0xb0870c00), SPH_C32(0x714710f4), + SPH_C32(0xa152e1f5), SPH_C32(0x3454d933) }, + { SPH_C32(0xcdac0500), SPH_C32(0xfc61462d), SPH_C32(0x3f2cf622), + SPH_C32(0x5050c927), SPH_C32(0xc3cb0c00), SPH_C32(0xe428b722), + SPH_C32(0x03cff362), SPH_C32(0x5ab1b167) }, + { SPH_C32(0x09440400), SPH_C32(0xe311d023), SPH_C32(0x18383c1e), + SPH_C32(0xd871c517), SPH_C32(0x746f0d00), SPH_C32(0x6e3786fa), + SPH_C32(0x86462bc9), SPH_C32(0xbc75d503) }, + { SPH_C32(0xbee00500), SPH_C32(0x690ee1fb), SPH_C32(0x9db1e4b5), + SPH_C32(0x3eb5a173), SPH_C32(0x07230d00), SPH_C32(0xfb58212c), + SPH_C32(0x24db395e), SPH_C32(0xd290bd57) }, + { SPH_C32(0xddb00600), SPH_C32(0x696cf3c6), SPH_C32(0xda40d77b), + SPH_C32(0x2880d835), SPH_C32(0x5ea10c00), SPH_C32(0x630c78ca), + SPH_C32(0x2190377a), SPH_C32(0x0fa7721f) }, + { SPH_C32(0x6a140700), SPH_C32(0xe373c21e), SPH_C32(0x5fc90fd0), + SPH_C32(0xce44bc51), SPH_C32(0x2ded0c00), SPH_C32(0xf663df1c), + SPH_C32(0x830d25ed), SPH_C32(0x61421a4b) }, + { SPH_C32(0xaefc0600), SPH_C32(0xfc035410), SPH_C32(0x78ddc5ec), + SPH_C32(0x4665b061), SPH_C32(0x9a490d00), SPH_C32(0x7c7ceec4), + SPH_C32(0x0684fd46), SPH_C32(0x87867e2f) }, + { SPH_C32(0x19580700), SPH_C32(0x761c65c8), SPH_C32(0xfd541d47), + SPH_C32(0xa0a1d405), SPH_C32(0xe9050d00), SPH_C32(0xe9134912), + SPH_C32(0xa419efd1), SPH_C32(0xe963167b) }, + { SPH_C32(0x942e0400), SPH_C32(0x64351fcb), SPH_C32(0x3a67f806), + SPH_C32(0x8d67066f), SPH_C32(0xf9190e00), SPH_C32(0x7c1efcf9), + SPH_C32(0x4175ce88), SPH_C32(0x91b30769) }, + { SPH_C32(0x238a0500), SPH_C32(0xee2a2e13), SPH_C32(0xbfee20ad), + SPH_C32(0x6ba3620b), SPH_C32(0x8a550e00), SPH_C32(0xe9715b2f), + SPH_C32(0xe3e8dc1f), SPH_C32(0xff566f3d) }, + { SPH_C32(0xe7620400), SPH_C32(0xf15ab81d), SPH_C32(0x98faea91), + SPH_C32(0xe3826e3b), SPH_C32(0x3df10f00), SPH_C32(0x636e6af7), + SPH_C32(0x666104b4), SPH_C32(0x19920b59) }, + { SPH_C32(0x50c60500), SPH_C32(0x7b4589c5), SPH_C32(0x1d73323a), + SPH_C32(0x05460a5f), SPH_C32(0x4ebd0f00), SPH_C32(0xf601cd21), + SPH_C32(0xc4fc1623), SPH_C32(0x7777630d) }, + { SPH_C32(0x33960600), SPH_C32(0x7b279bf8), SPH_C32(0x5a8201f4), + SPH_C32(0x13737319), SPH_C32(0x173f0e00), SPH_C32(0x6e5594c7), + SPH_C32(0xc1b71807), SPH_C32(0xaa40ac45) }, + { SPH_C32(0x84320700), SPH_C32(0xf138aa20), SPH_C32(0xdf0bd95f), + SPH_C32(0xf5b7177d), SPH_C32(0x64730e00), SPH_C32(0xfb3a3311), + SPH_C32(0x632a0a90), SPH_C32(0xc4a5c411) }, + { SPH_C32(0x40da0600), SPH_C32(0xee483c2e), SPH_C32(0xf81f1363), + SPH_C32(0x7d961b4d), SPH_C32(0xd3d70f00), SPH_C32(0x712502c9), + SPH_C32(0xe6a3d23b), SPH_C32(0x2261a075) }, + { SPH_C32(0xf77e0700), SPH_C32(0x64570df6), SPH_C32(0x7d96cbc8), + SPH_C32(0x9b527f29), SPH_C32(0xa09b0f00), SPH_C32(0xe44aa51f), + SPH_C32(0x443ec0ac), SPH_C32(0x4c84c821) }, + { SPH_C32(0x3fb90800), SPH_C32(0x7cdad883), SPH_C32(0xce97a914), + SPH_C32(0xbdd9f5e5), SPH_C32(0xde320800), SPH_C32(0x288350fe), + SPH_C32(0x71852ac7), SPH_C32(0xa6bf9f96) }, + { SPH_C32(0x881d0900), SPH_C32(0xf6c5e95b), SPH_C32(0x4b1e71bf), + SPH_C32(0x5b1d9181), SPH_C32(0xad7e0800), SPH_C32(0xbdecf728), + SPH_C32(0xd3183850), SPH_C32(0xc85af7c2) }, + { SPH_C32(0x4cf50800), SPH_C32(0xe9b57f55), SPH_C32(0x6c0abb83), + SPH_C32(0xd33c9db1), SPH_C32(0x1ada0900), SPH_C32(0x37f3c6f0), + SPH_C32(0x5691e0fb), SPH_C32(0x2e9e93a6) }, + { SPH_C32(0xfb510900), SPH_C32(0x63aa4e8d), SPH_C32(0xe9836328), + SPH_C32(0x35f8f9d5), SPH_C32(0x69960900), SPH_C32(0xa29c6126), + SPH_C32(0xf40cf26c), SPH_C32(0x407bfbf2) }, + { SPH_C32(0x98010a00), SPH_C32(0x63c85cb0), SPH_C32(0xae7250e6), + SPH_C32(0x23cd8093), SPH_C32(0x30140800), SPH_C32(0x3ac838c0), + SPH_C32(0xf147fc48), SPH_C32(0x9d4c34ba) }, + { SPH_C32(0x2fa50b00), SPH_C32(0xe9d76d68), SPH_C32(0x2bfb884d), + SPH_C32(0xc509e4f7), SPH_C32(0x43580800), SPH_C32(0xafa79f16), + SPH_C32(0x53daeedf), SPH_C32(0xf3a95cee) }, + { SPH_C32(0xeb4d0a00), SPH_C32(0xf6a7fb66), SPH_C32(0x0cef4271), + SPH_C32(0x4d28e8c7), SPH_C32(0xf4fc0900), SPH_C32(0x25b8aece), + SPH_C32(0xd6533674), SPH_C32(0x156d388a) }, + { SPH_C32(0x5ce90b00), SPH_C32(0x7cb8cabe), SPH_C32(0x89669ada), + SPH_C32(0xabec8ca3), SPH_C32(0x87b00900), SPH_C32(0xb0d70918), + SPH_C32(0x74ce24e3), SPH_C32(0x7b8850de) }, + { SPH_C32(0xd19f0800), SPH_C32(0x6e91b0bd), SPH_C32(0x4e557f9b), + SPH_C32(0x862a5ec9), SPH_C32(0x97ac0a00), SPH_C32(0x25dabcf3), + SPH_C32(0x91a205ba), SPH_C32(0x035841cc) }, + { SPH_C32(0x663b0900), SPH_C32(0xe48e8165), SPH_C32(0xcbdca730), + SPH_C32(0x60ee3aad), SPH_C32(0xe4e00a00), SPH_C32(0xb0b51b25), + SPH_C32(0x333f172d), SPH_C32(0x6dbd2998) }, + { SPH_C32(0xa2d30800), SPH_C32(0xfbfe176b), SPH_C32(0xecc86d0c), + SPH_C32(0xe8cf369d), SPH_C32(0x53440b00), SPH_C32(0x3aaa2afd), + SPH_C32(0xb6b6cf86), SPH_C32(0x8b794dfc) }, + { SPH_C32(0x15770900), SPH_C32(0x71e126b3), SPH_C32(0x6941b5a7), + SPH_C32(0x0e0b52f9), SPH_C32(0x20080b00), SPH_C32(0xafc58d2b), + SPH_C32(0x142bdd11), SPH_C32(0xe59c25a8) }, + { SPH_C32(0x76270a00), SPH_C32(0x7183348e), SPH_C32(0x2eb08669), + SPH_C32(0x183e2bbf), SPH_C32(0x798a0a00), SPH_C32(0x3791d4cd), + SPH_C32(0x1160d335), SPH_C32(0x38abeae0) }, + { SPH_C32(0xc1830b00), SPH_C32(0xfb9c0556), SPH_C32(0xab395ec2), + SPH_C32(0xfefa4fdb), SPH_C32(0x0ac60a00), SPH_C32(0xa2fe731b), + SPH_C32(0xb3fdc1a2), SPH_C32(0x564e82b4) }, + { SPH_C32(0x056b0a00), SPH_C32(0xe4ec9358), SPH_C32(0x8c2d94fe), + SPH_C32(0x76db43eb), SPH_C32(0xbd620b00), SPH_C32(0x28e142c3), + SPH_C32(0x36741909), SPH_C32(0xb08ae6d0) }, + { SPH_C32(0xb2cf0b00), SPH_C32(0x6ef3a280), SPH_C32(0x09a44c55), + SPH_C32(0x901f278f), SPH_C32(0xce2e0b00), SPH_C32(0xbd8ee515), + SPH_C32(0x94e90b9e), SPH_C32(0xde6f8e84) }, + { SPH_C32(0xb0870c00), SPH_C32(0x714710f4), SPH_C32(0xa152e1f5), + SPH_C32(0x3454d933), SPH_C32(0xca8f0800), SPH_C32(0x07396701), + SPH_C32(0x1bf7cf7c), SPH_C32(0x82c07470) }, + { SPH_C32(0x07230d00), SPH_C32(0xfb58212c), SPH_C32(0x24db395e), + SPH_C32(0xd290bd57), SPH_C32(0xb9c30800), SPH_C32(0x9256c0d7), + SPH_C32(0xb96addeb), SPH_C32(0xec251c24) }, + { SPH_C32(0xc3cb0c00), SPH_C32(0xe428b722), SPH_C32(0x03cff362), + SPH_C32(0x5ab1b167), SPH_C32(0x0e670900), SPH_C32(0x1849f10f), + SPH_C32(0x3ce30540), SPH_C32(0x0ae17840) }, + { SPH_C32(0x746f0d00), SPH_C32(0x6e3786fa), SPH_C32(0x86462bc9), + SPH_C32(0xbc75d503), SPH_C32(0x7d2b0900), SPH_C32(0x8d2656d9), + SPH_C32(0x9e7e17d7), SPH_C32(0x64041014) }, + { SPH_C32(0x173f0e00), SPH_C32(0x6e5594c7), SPH_C32(0xc1b71807), + SPH_C32(0xaa40ac45), SPH_C32(0x24a90800), SPH_C32(0x15720f3f), + SPH_C32(0x9b3519f3), SPH_C32(0xb933df5c) }, + { SPH_C32(0xa09b0f00), SPH_C32(0xe44aa51f), SPH_C32(0x443ec0ac), + SPH_C32(0x4c84c821), SPH_C32(0x57e50800), SPH_C32(0x801da8e9), + SPH_C32(0x39a80b64), SPH_C32(0xd7d6b708) }, + { SPH_C32(0x64730e00), SPH_C32(0xfb3a3311), SPH_C32(0x632a0a90), + SPH_C32(0xc4a5c411), SPH_C32(0xe0410900), SPH_C32(0x0a029931), + SPH_C32(0xbc21d3cf), SPH_C32(0x3112d36c) }, + { SPH_C32(0xd3d70f00), SPH_C32(0x712502c9), SPH_C32(0xe6a3d23b), + SPH_C32(0x2261a075), SPH_C32(0x930d0900), SPH_C32(0x9f6d3ee7), + SPH_C32(0x1ebcc158), SPH_C32(0x5ff7bb38) }, + { SPH_C32(0x5ea10c00), SPH_C32(0x630c78ca), SPH_C32(0x2190377a), + SPH_C32(0x0fa7721f), SPH_C32(0x83110a00), SPH_C32(0x0a608b0c), + SPH_C32(0xfbd0e001), SPH_C32(0x2727aa2a) }, + { SPH_C32(0xe9050d00), SPH_C32(0xe9134912), SPH_C32(0xa419efd1), + SPH_C32(0xe963167b), SPH_C32(0xf05d0a00), SPH_C32(0x9f0f2cda), + SPH_C32(0x594df296), SPH_C32(0x49c2c27e) }, + { SPH_C32(0x2ded0c00), SPH_C32(0xf663df1c), SPH_C32(0x830d25ed), + SPH_C32(0x61421a4b), SPH_C32(0x47f90b00), SPH_C32(0x15101d02), + SPH_C32(0xdcc42a3d), SPH_C32(0xaf06a61a) }, + { SPH_C32(0x9a490d00), SPH_C32(0x7c7ceec4), SPH_C32(0x0684fd46), + SPH_C32(0x87867e2f), SPH_C32(0x34b50b00), SPH_C32(0x807fbad4), + SPH_C32(0x7e5938aa), SPH_C32(0xc1e3ce4e) }, + { SPH_C32(0xf9190e00), SPH_C32(0x7c1efcf9), SPH_C32(0x4175ce88), + SPH_C32(0x91b30769), SPH_C32(0x6d370a00), SPH_C32(0x182be332), + SPH_C32(0x7b12368e), SPH_C32(0x1cd40106) }, + { SPH_C32(0x4ebd0f00), SPH_C32(0xf601cd21), SPH_C32(0xc4fc1623), + SPH_C32(0x7777630d), SPH_C32(0x1e7b0a00), SPH_C32(0x8d4444e4), + SPH_C32(0xd98f2419), SPH_C32(0x72316952) }, + { SPH_C32(0x8a550e00), SPH_C32(0xe9715b2f), SPH_C32(0xe3e8dc1f), + SPH_C32(0xff566f3d), SPH_C32(0xa9df0b00), SPH_C32(0x075b753c), + SPH_C32(0x5c06fcb2), SPH_C32(0x94f50d36) }, + { SPH_C32(0x3df10f00), SPH_C32(0x636e6af7), SPH_C32(0x666104b4), + SPH_C32(0x19920b59), SPH_C32(0xda930b00), SPH_C32(0x9234d2ea), + SPH_C32(0xfe9bee25), SPH_C32(0xfa106562) }, + { SPH_C32(0x2b040800), SPH_C32(0x5360ef7c), SPH_C32(0xa4e54caf), + SPH_C32(0x99a61e03), SPH_C32(0x45b10c00), SPH_C32(0x0aa4af76), + SPH_C32(0x7432879d), SPH_C32(0x0b4d58a6) }, + { SPH_C32(0x9ca00900), SPH_C32(0xd97fdea4), SPH_C32(0x216c9404), + SPH_C32(0x7f627a67), SPH_C32(0x36fd0c00), SPH_C32(0x9fcb08a0), + SPH_C32(0xd6af950a), SPH_C32(0x65a830f2) }, + { SPH_C32(0x58480800), SPH_C32(0xc60f48aa), SPH_C32(0x06785e38), + SPH_C32(0xf7437657), SPH_C32(0x81590d00), SPH_C32(0x15d43978), + SPH_C32(0x53264da1), SPH_C32(0x836c5496) }, + { SPH_C32(0xefec0900), SPH_C32(0x4c107972), SPH_C32(0x83f18693), + SPH_C32(0x11871233), SPH_C32(0xf2150d00), SPH_C32(0x80bb9eae), + SPH_C32(0xf1bb5f36), SPH_C32(0xed893cc2) }, + { SPH_C32(0x8cbc0a00), SPH_C32(0x4c726b4f), SPH_C32(0xc400b55d), + SPH_C32(0x07b26b75), SPH_C32(0xab970c00), SPH_C32(0x18efc748), + SPH_C32(0xf4f05112), SPH_C32(0x30bef38a) }, + { SPH_C32(0x3b180b00), SPH_C32(0xc66d5a97), SPH_C32(0x41896df6), + SPH_C32(0xe1760f11), SPH_C32(0xd8db0c00), SPH_C32(0x8d80609e), + SPH_C32(0x566d4385), SPH_C32(0x5e5b9bde) }, + { SPH_C32(0xfff00a00), SPH_C32(0xd91dcc99), SPH_C32(0x669da7ca), + SPH_C32(0x69570321), SPH_C32(0x6f7f0d00), SPH_C32(0x079f5146), + SPH_C32(0xd3e49b2e), SPH_C32(0xb89fffba) }, + { SPH_C32(0x48540b00), SPH_C32(0x5302fd41), SPH_C32(0xe3147f61), + SPH_C32(0x8f936745), SPH_C32(0x1c330d00), SPH_C32(0x92f0f690), + SPH_C32(0x717989b9), SPH_C32(0xd67a97ee) }, + { SPH_C32(0xc5220800), SPH_C32(0x412b8742), SPH_C32(0x24279a20), + SPH_C32(0xa255b52f), SPH_C32(0x0c2f0e00), SPH_C32(0x07fd437b), + SPH_C32(0x9415a8e0), SPH_C32(0xaeaa86fc) }, + { SPH_C32(0x72860900), SPH_C32(0xcb34b69a), SPH_C32(0xa1ae428b), + SPH_C32(0x4491d14b), SPH_C32(0x7f630e00), SPH_C32(0x9292e4ad), + SPH_C32(0x3688ba77), SPH_C32(0xc04feea8) }, + { SPH_C32(0xb66e0800), SPH_C32(0xd4442094), SPH_C32(0x86ba88b7), + SPH_C32(0xccb0dd7b), SPH_C32(0xc8c70f00), SPH_C32(0x188dd575), + SPH_C32(0xb30162dc), SPH_C32(0x268b8acc) }, + { SPH_C32(0x01ca0900), SPH_C32(0x5e5b114c), SPH_C32(0x0333501c), + SPH_C32(0x2a74b91f), SPH_C32(0xbb8b0f00), SPH_C32(0x8de272a3), + SPH_C32(0x119c704b), SPH_C32(0x486ee298) }, + { SPH_C32(0x629a0a00), SPH_C32(0x5e390371), SPH_C32(0x44c263d2), + SPH_C32(0x3c41c059), SPH_C32(0xe2090e00), SPH_C32(0x15b62b45), + SPH_C32(0x14d77e6f), SPH_C32(0x95592dd0) }, + { SPH_C32(0xd53e0b00), SPH_C32(0xd42632a9), SPH_C32(0xc14bbb79), + SPH_C32(0xda85a43d), SPH_C32(0x91450e00), SPH_C32(0x80d98c93), + SPH_C32(0xb64a6cf8), SPH_C32(0xfbbc4584) }, + { SPH_C32(0x11d60a00), SPH_C32(0xcb56a4a7), SPH_C32(0xe65f7145), + SPH_C32(0x52a4a80d), SPH_C32(0x26e10f00), SPH_C32(0x0ac6bd4b), + SPH_C32(0x33c3b453), SPH_C32(0x1d7821e0) }, + { SPH_C32(0xa6720b00), SPH_C32(0x4149957f), SPH_C32(0x63d6a9ee), + SPH_C32(0xb460cc69), SPH_C32(0x55ad0f00), SPH_C32(0x9fa91a9d), + SPH_C32(0x915ea6c4), SPH_C32(0x739d49b4) }, + { SPH_C32(0xa43a0c00), SPH_C32(0x5efd270b), SPH_C32(0xcb20044e), + SPH_C32(0x102b32d5), SPH_C32(0x510c0c00), SPH_C32(0x251e9889), + SPH_C32(0x1e406226), SPH_C32(0x2f32b340) }, + { SPH_C32(0x139e0d00), SPH_C32(0xd4e216d3), SPH_C32(0x4ea9dce5), + SPH_C32(0xf6ef56b1), SPH_C32(0x22400c00), SPH_C32(0xb0713f5f), + SPH_C32(0xbcdd70b1), SPH_C32(0x41d7db14) }, + { SPH_C32(0xd7760c00), SPH_C32(0xcb9280dd), SPH_C32(0x69bd16d9), + SPH_C32(0x7ece5a81), SPH_C32(0x95e40d00), SPH_C32(0x3a6e0e87), + SPH_C32(0x3954a81a), SPH_C32(0xa713bf70) }, + { SPH_C32(0x60d20d00), SPH_C32(0x418db105), SPH_C32(0xec34ce72), + SPH_C32(0x980a3ee5), SPH_C32(0xe6a80d00), SPH_C32(0xaf01a951), + SPH_C32(0x9bc9ba8d), SPH_C32(0xc9f6d724) }, + { SPH_C32(0x03820e00), SPH_C32(0x41efa338), SPH_C32(0xabc5fdbc), + SPH_C32(0x8e3f47a3), SPH_C32(0xbf2a0c00), SPH_C32(0x3755f0b7), + SPH_C32(0x9e82b4a9), SPH_C32(0x14c1186c) }, + { SPH_C32(0xb4260f00), SPH_C32(0xcbf092e0), SPH_C32(0x2e4c2517), + SPH_C32(0x68fb23c7), SPH_C32(0xcc660c00), SPH_C32(0xa23a5761), + SPH_C32(0x3c1fa63e), SPH_C32(0x7a247038) }, + { SPH_C32(0x70ce0e00), SPH_C32(0xd48004ee), SPH_C32(0x0958ef2b), + SPH_C32(0xe0da2ff7), SPH_C32(0x7bc20d00), SPH_C32(0x282566b9), + SPH_C32(0xb9967e95), SPH_C32(0x9ce0145c) }, + { SPH_C32(0xc76a0f00), SPH_C32(0x5e9f3536), SPH_C32(0x8cd13780), + SPH_C32(0x061e4b93), SPH_C32(0x088e0d00), SPH_C32(0xbd4ac16f), + SPH_C32(0x1b0b6c02), SPH_C32(0xf2057c08) }, + { SPH_C32(0x4a1c0c00), SPH_C32(0x4cb64f35), SPH_C32(0x4be2d2c1), + SPH_C32(0x2bd899f9), SPH_C32(0x18920e00), SPH_C32(0x28477484), + SPH_C32(0xfe674d5b), SPH_C32(0x8ad56d1a) }, + { SPH_C32(0xfdb80d00), SPH_C32(0xc6a97eed), SPH_C32(0xce6b0a6a), + SPH_C32(0xcd1cfd9d), SPH_C32(0x6bde0e00), SPH_C32(0xbd28d352), + SPH_C32(0x5cfa5fcc), SPH_C32(0xe430054e) }, + { SPH_C32(0x39500c00), SPH_C32(0xd9d9e8e3), SPH_C32(0xe97fc056), + SPH_C32(0x453df1ad), SPH_C32(0xdc7a0f00), SPH_C32(0x3737e28a), + SPH_C32(0xd9738767), SPH_C32(0x02f4612a) }, + { SPH_C32(0x8ef40d00), SPH_C32(0x53c6d93b), SPH_C32(0x6cf618fd), + SPH_C32(0xa3f995c9), SPH_C32(0xaf360f00), SPH_C32(0xa258455c), + SPH_C32(0x7bee95f0), SPH_C32(0x6c11097e) }, + { SPH_C32(0xeda40e00), SPH_C32(0x53a4cb06), SPH_C32(0x2b072b33), + SPH_C32(0xb5ccec8f), SPH_C32(0xf6b40e00), SPH_C32(0x3a0c1cba), + SPH_C32(0x7ea59bd4), SPH_C32(0xb126c636) }, + { SPH_C32(0x5a000f00), SPH_C32(0xd9bbfade), SPH_C32(0xae8ef398), + SPH_C32(0x530888eb), SPH_C32(0x85f80e00), SPH_C32(0xaf63bb6c), + SPH_C32(0xdc388943), SPH_C32(0xdfc3ae62) }, + { SPH_C32(0x9ee80e00), SPH_C32(0xc6cb6cd0), SPH_C32(0x899a39a4), + SPH_C32(0xdb2984db), SPH_C32(0x325c0f00), SPH_C32(0x257c8ab4), + SPH_C32(0x59b151e8), SPH_C32(0x3907ca06) }, + { SPH_C32(0x294c0f00), SPH_C32(0x4cd45d08), SPH_C32(0x0c13e10f), + SPH_C32(0x3dede0bf), SPH_C32(0x41100f00), SPH_C32(0xb0132d62), + SPH_C32(0xfb2c437f), SPH_C32(0x57e2a252) } +}; + +static const sph_u32 T256_16[256][8] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000) }, + { SPH_C32(0x515c0010), SPH_C32(0x40f372fb), SPH_C32(0xfce72602), + SPH_C32(0x71575061), SPH_C32(0x2e390000), SPH_C32(0x64dd6689), + SPH_C32(0x3cd406fc), SPH_C32(0xb1f490bc) }, + { SPH_C32(0x2e390000), SPH_C32(0x64dd6689), SPH_C32(0x3cd406fc), + SPH_C32(0xb1f490bc), SPH_C32(0x7f650010), SPH_C32(0x242e1472), + SPH_C32(0xc03320fe), SPH_C32(0xc0a3c0dd) }, + { SPH_C32(0x7f650010), SPH_C32(0x242e1472), SPH_C32(0xc03320fe), + SPH_C32(0xc0a3c0dd), SPH_C32(0x515c0010), SPH_C32(0x40f372fb), + SPH_C32(0xfce72602), SPH_C32(0x71575061) }, + { SPH_C32(0xa2b80020), SPH_C32(0x81e7e5f6), SPH_C32(0xf9ce4c04), + SPH_C32(0xe2afa0c0), SPH_C32(0x5c720000), SPH_C32(0xc9bacd12), + SPH_C32(0x79a90df9), SPH_C32(0x63e92178) }, + { SPH_C32(0xf3e40030), SPH_C32(0xc114970d), SPH_C32(0x05296a06), + SPH_C32(0x93f8f0a1), SPH_C32(0x724b0000), SPH_C32(0xad67ab9b), + SPH_C32(0x457d0b05), SPH_C32(0xd21db1c4) }, + { SPH_C32(0x8c810020), SPH_C32(0xe53a837f), SPH_C32(0xc51a4af8), + SPH_C32(0x535b307c), SPH_C32(0x23170010), SPH_C32(0xed94d960), + SPH_C32(0xb99a2d07), SPH_C32(0xa34ae1a5) }, + { SPH_C32(0xdddd0030), SPH_C32(0xa5c9f184), SPH_C32(0x39fd6cfa), + SPH_C32(0x220c601d), SPH_C32(0x0d2e0010), SPH_C32(0x8949bfe9), + SPH_C32(0x854e2bfb), SPH_C32(0x12be7119) }, + { SPH_C32(0x5c720000), SPH_C32(0xc9bacd12), SPH_C32(0x79a90df9), + SPH_C32(0x63e92178), SPH_C32(0xfeca0020), SPH_C32(0x485d28e4), + SPH_C32(0x806741fd), SPH_C32(0x814681b8) }, + { SPH_C32(0x0d2e0010), SPH_C32(0x8949bfe9), SPH_C32(0x854e2bfb), + SPH_C32(0x12be7119), SPH_C32(0xd0f30020), SPH_C32(0x2c804e6d), + SPH_C32(0xbcb34701), SPH_C32(0x30b21104) }, + { SPH_C32(0x724b0000), SPH_C32(0xad67ab9b), SPH_C32(0x457d0b05), + SPH_C32(0xd21db1c4), SPH_C32(0x81af0030), SPH_C32(0x6c733c96), + SPH_C32(0x40546103), SPH_C32(0x41e54165) }, + { SPH_C32(0x23170010), SPH_C32(0xed94d960), SPH_C32(0xb99a2d07), + SPH_C32(0xa34ae1a5), SPH_C32(0xaf960030), SPH_C32(0x08ae5a1f), + SPH_C32(0x7c8067ff), SPH_C32(0xf011d1d9) }, + { SPH_C32(0xfeca0020), SPH_C32(0x485d28e4), SPH_C32(0x806741fd), + SPH_C32(0x814681b8), SPH_C32(0xa2b80020), SPH_C32(0x81e7e5f6), + SPH_C32(0xf9ce4c04), SPH_C32(0xe2afa0c0) }, + { SPH_C32(0xaf960030), SPH_C32(0x08ae5a1f), SPH_C32(0x7c8067ff), + SPH_C32(0xf011d1d9), SPH_C32(0x8c810020), SPH_C32(0xe53a837f), + SPH_C32(0xc51a4af8), SPH_C32(0x535b307c) }, + { SPH_C32(0xd0f30020), SPH_C32(0x2c804e6d), SPH_C32(0xbcb34701), + SPH_C32(0x30b21104), SPH_C32(0xdddd0030), SPH_C32(0xa5c9f184), + SPH_C32(0x39fd6cfa), SPH_C32(0x220c601d) }, + { SPH_C32(0x81af0030), SPH_C32(0x6c733c96), SPH_C32(0x40546103), + SPH_C32(0x41e54165), SPH_C32(0xf3e40030), SPH_C32(0xc114970d), + SPH_C32(0x05296a06), SPH_C32(0x93f8f0a1) }, + { SPH_C32(0x4dce0040), SPH_C32(0x3b5bec7e), SPH_C32(0x36656ba8), + SPH_C32(0x23633a05), SPH_C32(0x78ab0000), SPH_C32(0xa0cd5a34), + SPH_C32(0x5d5ca0f7), SPH_C32(0x727784cb) }, + { SPH_C32(0x1c920050), SPH_C32(0x7ba89e85), SPH_C32(0xca824daa), + SPH_C32(0x52346a64), SPH_C32(0x56920000), SPH_C32(0xc4103cbd), + SPH_C32(0x6188a60b), SPH_C32(0xc3831477) }, + { SPH_C32(0x63f70040), SPH_C32(0x5f868af7), SPH_C32(0x0ab16d54), + SPH_C32(0x9297aab9), SPH_C32(0x07ce0010), SPH_C32(0x84e34e46), + SPH_C32(0x9d6f8009), SPH_C32(0xb2d44416) }, + { SPH_C32(0x32ab0050), SPH_C32(0x1f75f80c), SPH_C32(0xf6564b56), + SPH_C32(0xe3c0fad8), SPH_C32(0x29f70010), SPH_C32(0xe03e28cf), + SPH_C32(0xa1bb86f5), SPH_C32(0x0320d4aa) }, + { SPH_C32(0xef760060), SPH_C32(0xbabc0988), SPH_C32(0xcfab27ac), + SPH_C32(0xc1cc9ac5), SPH_C32(0x24d90000), SPH_C32(0x69779726), + SPH_C32(0x24f5ad0e), SPH_C32(0x119ea5b3) }, + { SPH_C32(0xbe2a0070), SPH_C32(0xfa4f7b73), SPH_C32(0x334c01ae), + SPH_C32(0xb09bcaa4), SPH_C32(0x0ae00000), SPH_C32(0x0daaf1af), + SPH_C32(0x1821abf2), SPH_C32(0xa06a350f) }, + { SPH_C32(0xc14f0060), SPH_C32(0xde616f01), SPH_C32(0xf37f2150), + SPH_C32(0x70380a79), SPH_C32(0x5bbc0010), SPH_C32(0x4d598354), + SPH_C32(0xe4c68df0), SPH_C32(0xd13d656e) }, + { SPH_C32(0x90130070), SPH_C32(0x9e921dfa), SPH_C32(0x0f980752), + SPH_C32(0x016f5a18), SPH_C32(0x75850010), SPH_C32(0x2984e5dd), + SPH_C32(0xd8128b0c), SPH_C32(0x60c9f5d2) }, + { SPH_C32(0x11bc0040), SPH_C32(0xf2e1216c), SPH_C32(0x4fcc6651), + SPH_C32(0x408a1b7d), SPH_C32(0x86610020), SPH_C32(0xe89072d0), + SPH_C32(0xdd3be10a), SPH_C32(0xf3310573) }, + { SPH_C32(0x40e00050), SPH_C32(0xb2125397), SPH_C32(0xb32b4053), + SPH_C32(0x31dd4b1c), SPH_C32(0xa8580020), SPH_C32(0x8c4d1459), + SPH_C32(0xe1efe7f6), SPH_C32(0x42c595cf) }, + { SPH_C32(0x3f850040), SPH_C32(0x963c47e5), SPH_C32(0x731860ad), + SPH_C32(0xf17e8bc1), SPH_C32(0xf9040030), SPH_C32(0xccbe66a2), + SPH_C32(0x1d08c1f4), SPH_C32(0x3392c5ae) }, + { SPH_C32(0x6ed90050), SPH_C32(0xd6cf351e), SPH_C32(0x8fff46af), + SPH_C32(0x8029dba0), SPH_C32(0xd73d0030), SPH_C32(0xa863002b), + SPH_C32(0x21dcc708), SPH_C32(0x82665512) }, + { SPH_C32(0xb3040060), SPH_C32(0x7306c49a), SPH_C32(0xb6022a55), + SPH_C32(0xa225bbbd), SPH_C32(0xda130020), SPH_C32(0x212abfc2), + SPH_C32(0xa492ecf3), SPH_C32(0x90d8240b) }, + { SPH_C32(0xe2580070), SPH_C32(0x33f5b661), SPH_C32(0x4ae50c57), + SPH_C32(0xd372ebdc), SPH_C32(0xf42a0020), SPH_C32(0x45f7d94b), + SPH_C32(0x9846ea0f), SPH_C32(0x212cb4b7) }, + { SPH_C32(0x9d3d0060), SPH_C32(0x17dba213), SPH_C32(0x8ad62ca9), + SPH_C32(0x13d12b01), SPH_C32(0xa5760030), SPH_C32(0x0504abb0), + SPH_C32(0x64a1cc0d), SPH_C32(0x507be4d6) }, + { SPH_C32(0xcc610070), SPH_C32(0x5728d0e8), SPH_C32(0x76310aab), + SPH_C32(0x62867b60), SPH_C32(0x8b4f0030), SPH_C32(0x61d9cd39), + SPH_C32(0x5875caf1), SPH_C32(0xe18f746a) }, + { SPH_C32(0x78ab0000), SPH_C32(0xa0cd5a34), SPH_C32(0x5d5ca0f7), + SPH_C32(0x727784cb), SPH_C32(0x35650040), SPH_C32(0x9b96b64a), + SPH_C32(0x6b39cb5f), SPH_C32(0x5114bece) }, + { SPH_C32(0x29f70010), SPH_C32(0xe03e28cf), SPH_C32(0xa1bb86f5), + SPH_C32(0x0320d4aa), SPH_C32(0x1b5c0040), SPH_C32(0xff4bd0c3), + SPH_C32(0x57edcda3), SPH_C32(0xe0e02e72) }, + { SPH_C32(0x56920000), SPH_C32(0xc4103cbd), SPH_C32(0x6188a60b), + SPH_C32(0xc3831477), SPH_C32(0x4a000050), SPH_C32(0xbfb8a238), + SPH_C32(0xab0aeba1), SPH_C32(0x91b77e13) }, + { SPH_C32(0x07ce0010), SPH_C32(0x84e34e46), SPH_C32(0x9d6f8009), + SPH_C32(0xb2d44416), SPH_C32(0x64390050), SPH_C32(0xdb65c4b1), + SPH_C32(0x97deed5d), SPH_C32(0x2043eeaf) }, + { SPH_C32(0xda130020), SPH_C32(0x212abfc2), SPH_C32(0xa492ecf3), + SPH_C32(0x90d8240b), SPH_C32(0x69170040), SPH_C32(0x522c7b58), + SPH_C32(0x1290c6a6), SPH_C32(0x32fd9fb6) }, + { SPH_C32(0x8b4f0030), SPH_C32(0x61d9cd39), SPH_C32(0x5875caf1), + SPH_C32(0xe18f746a), SPH_C32(0x472e0040), SPH_C32(0x36f11dd1), + SPH_C32(0x2e44c05a), SPH_C32(0x83090f0a) }, + { SPH_C32(0xf42a0020), SPH_C32(0x45f7d94b), SPH_C32(0x9846ea0f), + SPH_C32(0x212cb4b7), SPH_C32(0x16720050), SPH_C32(0x76026f2a), + SPH_C32(0xd2a3e658), SPH_C32(0xf25e5f6b) }, + { SPH_C32(0xa5760030), SPH_C32(0x0504abb0), SPH_C32(0x64a1cc0d), + SPH_C32(0x507be4d6), SPH_C32(0x384b0050), SPH_C32(0x12df09a3), + SPH_C32(0xee77e0a4), SPH_C32(0x43aacfd7) }, + { SPH_C32(0x24d90000), SPH_C32(0x69779726), SPH_C32(0x24f5ad0e), + SPH_C32(0x119ea5b3), SPH_C32(0xcbaf0060), SPH_C32(0xd3cb9eae), + SPH_C32(0xeb5e8aa2), SPH_C32(0xd0523f76) }, + { SPH_C32(0x75850010), SPH_C32(0x2984e5dd), SPH_C32(0xd8128b0c), + SPH_C32(0x60c9f5d2), SPH_C32(0xe5960060), SPH_C32(0xb716f827), + SPH_C32(0xd78a8c5e), SPH_C32(0x61a6afca) }, + { SPH_C32(0x0ae00000), SPH_C32(0x0daaf1af), SPH_C32(0x1821abf2), + SPH_C32(0xa06a350f), SPH_C32(0xb4ca0070), SPH_C32(0xf7e58adc), + SPH_C32(0x2b6daa5c), SPH_C32(0x10f1ffab) }, + { SPH_C32(0x5bbc0010), SPH_C32(0x4d598354), SPH_C32(0xe4c68df0), + SPH_C32(0xd13d656e), SPH_C32(0x9af30070), SPH_C32(0x9338ec55), + SPH_C32(0x17b9aca0), SPH_C32(0xa1056f17) }, + { SPH_C32(0x86610020), SPH_C32(0xe89072d0), SPH_C32(0xdd3be10a), + SPH_C32(0xf3310573), SPH_C32(0x97dd0060), SPH_C32(0x1a7153bc), + SPH_C32(0x92f7875b), SPH_C32(0xb3bb1e0e) }, + { SPH_C32(0xd73d0030), SPH_C32(0xa863002b), SPH_C32(0x21dcc708), + SPH_C32(0x82665512), SPH_C32(0xb9e40060), SPH_C32(0x7eac3535), + SPH_C32(0xae2381a7), SPH_C32(0x024f8eb2) }, + { SPH_C32(0xa8580020), SPH_C32(0x8c4d1459), SPH_C32(0xe1efe7f6), + SPH_C32(0x42c595cf), SPH_C32(0xe8b80070), SPH_C32(0x3e5f47ce), + SPH_C32(0x52c4a7a5), SPH_C32(0x7318ded3) }, + { SPH_C32(0xf9040030), SPH_C32(0xccbe66a2), SPH_C32(0x1d08c1f4), + SPH_C32(0x3392c5ae), SPH_C32(0xc6810070), SPH_C32(0x5a822147), + SPH_C32(0x6e10a159), SPH_C32(0xc2ec4e6f) }, + { SPH_C32(0x35650040), SPH_C32(0x9b96b64a), SPH_C32(0x6b39cb5f), + SPH_C32(0x5114bece), SPH_C32(0x4dce0040), SPH_C32(0x3b5bec7e), + SPH_C32(0x36656ba8), SPH_C32(0x23633a05) }, + { SPH_C32(0x64390050), SPH_C32(0xdb65c4b1), SPH_C32(0x97deed5d), + SPH_C32(0x2043eeaf), SPH_C32(0x63f70040), SPH_C32(0x5f868af7), + SPH_C32(0x0ab16d54), SPH_C32(0x9297aab9) }, + { SPH_C32(0x1b5c0040), SPH_C32(0xff4bd0c3), SPH_C32(0x57edcda3), + SPH_C32(0xe0e02e72), SPH_C32(0x32ab0050), SPH_C32(0x1f75f80c), + SPH_C32(0xf6564b56), SPH_C32(0xe3c0fad8) }, + { SPH_C32(0x4a000050), SPH_C32(0xbfb8a238), SPH_C32(0xab0aeba1), + SPH_C32(0x91b77e13), SPH_C32(0x1c920050), SPH_C32(0x7ba89e85), + SPH_C32(0xca824daa), SPH_C32(0x52346a64) }, + { SPH_C32(0x97dd0060), SPH_C32(0x1a7153bc), SPH_C32(0x92f7875b), + SPH_C32(0xb3bb1e0e), SPH_C32(0x11bc0040), SPH_C32(0xf2e1216c), + SPH_C32(0x4fcc6651), SPH_C32(0x408a1b7d) }, + { SPH_C32(0xc6810070), SPH_C32(0x5a822147), SPH_C32(0x6e10a159), + SPH_C32(0xc2ec4e6f), SPH_C32(0x3f850040), SPH_C32(0x963c47e5), + SPH_C32(0x731860ad), SPH_C32(0xf17e8bc1) }, + { SPH_C32(0xb9e40060), SPH_C32(0x7eac3535), SPH_C32(0xae2381a7), + SPH_C32(0x024f8eb2), SPH_C32(0x6ed90050), SPH_C32(0xd6cf351e), + SPH_C32(0x8fff46af), SPH_C32(0x8029dba0) }, + { SPH_C32(0xe8b80070), SPH_C32(0x3e5f47ce), SPH_C32(0x52c4a7a5), + SPH_C32(0x7318ded3), SPH_C32(0x40e00050), SPH_C32(0xb2125397), + SPH_C32(0xb32b4053), SPH_C32(0x31dd4b1c) }, + { SPH_C32(0x69170040), SPH_C32(0x522c7b58), SPH_C32(0x1290c6a6), + SPH_C32(0x32fd9fb6), SPH_C32(0xb3040060), SPH_C32(0x7306c49a), + SPH_C32(0xb6022a55), SPH_C32(0xa225bbbd) }, + { SPH_C32(0x384b0050), SPH_C32(0x12df09a3), SPH_C32(0xee77e0a4), + SPH_C32(0x43aacfd7), SPH_C32(0x9d3d0060), SPH_C32(0x17dba213), + SPH_C32(0x8ad62ca9), SPH_C32(0x13d12b01) }, + { SPH_C32(0x472e0040), SPH_C32(0x36f11dd1), SPH_C32(0x2e44c05a), + SPH_C32(0x83090f0a), SPH_C32(0xcc610070), SPH_C32(0x5728d0e8), + SPH_C32(0x76310aab), SPH_C32(0x62867b60) }, + { SPH_C32(0x16720050), SPH_C32(0x76026f2a), SPH_C32(0xd2a3e658), + SPH_C32(0xf25e5f6b), SPH_C32(0xe2580070), SPH_C32(0x33f5b661), + SPH_C32(0x4ae50c57), SPH_C32(0xd372ebdc) }, + { SPH_C32(0xcbaf0060), SPH_C32(0xd3cb9eae), SPH_C32(0xeb5e8aa2), + SPH_C32(0xd0523f76), SPH_C32(0xef760060), SPH_C32(0xbabc0988), + SPH_C32(0xcfab27ac), SPH_C32(0xc1cc9ac5) }, + { SPH_C32(0x9af30070), SPH_C32(0x9338ec55), SPH_C32(0x17b9aca0), + SPH_C32(0xa1056f17), SPH_C32(0xc14f0060), SPH_C32(0xde616f01), + SPH_C32(0xf37f2150), SPH_C32(0x70380a79) }, + { SPH_C32(0xe5960060), SPH_C32(0xb716f827), SPH_C32(0xd78a8c5e), + SPH_C32(0x61a6afca), SPH_C32(0x90130070), SPH_C32(0x9e921dfa), + SPH_C32(0x0f980752), SPH_C32(0x016f5a18) }, + { SPH_C32(0xb4ca0070), SPH_C32(0xf7e58adc), SPH_C32(0x2b6daa5c), + SPH_C32(0x10f1ffab), SPH_C32(0xbe2a0070), SPH_C32(0xfa4f7b73), + SPH_C32(0x334c01ae), SPH_C32(0xb09bcaa4) }, + { SPH_C32(0x5bd20080), SPH_C32(0x450f18ec), SPH_C32(0xc2c46c55), + SPH_C32(0xf362b233), SPH_C32(0x39a60000), SPH_C32(0x4ab753eb), + SPH_C32(0xd14e094b), SPH_C32(0xb772b42b) }, + { SPH_C32(0x0a8e0090), SPH_C32(0x05fc6a17), SPH_C32(0x3e234a57), + SPH_C32(0x8235e252), SPH_C32(0x179f0000), SPH_C32(0x2e6a3562), + SPH_C32(0xed9a0fb7), SPH_C32(0x06862497) }, + { SPH_C32(0x75eb0080), SPH_C32(0x21d27e65), SPH_C32(0xfe106aa9), + SPH_C32(0x4296228f), SPH_C32(0x46c30010), SPH_C32(0x6e994799), + SPH_C32(0x117d29b5), SPH_C32(0x77d174f6) }, + { SPH_C32(0x24b70090), SPH_C32(0x61210c9e), SPH_C32(0x02f74cab), + SPH_C32(0x33c172ee), SPH_C32(0x68fa0010), SPH_C32(0x0a442110), + SPH_C32(0x2da92f49), SPH_C32(0xc625e44a) }, + { SPH_C32(0xf96a00a0), SPH_C32(0xc4e8fd1a), SPH_C32(0x3b0a2051), + SPH_C32(0x11cd12f3), SPH_C32(0x65d40000), SPH_C32(0x830d9ef9), + SPH_C32(0xa8e704b2), SPH_C32(0xd49b9553) }, + { SPH_C32(0xa83600b0), SPH_C32(0x841b8fe1), SPH_C32(0xc7ed0653), + SPH_C32(0x609a4292), SPH_C32(0x4bed0000), SPH_C32(0xe7d0f870), + SPH_C32(0x9433024e), SPH_C32(0x656f05ef) }, + { SPH_C32(0xd75300a0), SPH_C32(0xa0359b93), SPH_C32(0x07de26ad), + SPH_C32(0xa039824f), SPH_C32(0x1ab10010), SPH_C32(0xa7238a8b), + SPH_C32(0x68d4244c), SPH_C32(0x1438558e) }, + { SPH_C32(0x860f00b0), SPH_C32(0xe0c6e968), SPH_C32(0xfb3900af), + SPH_C32(0xd16ed22e), SPH_C32(0x34880010), SPH_C32(0xc3feec02), + SPH_C32(0x540022b0), SPH_C32(0xa5ccc532) }, + { SPH_C32(0x07a00080), SPH_C32(0x8cb5d5fe), SPH_C32(0xbb6d61ac), + SPH_C32(0x908b934b), SPH_C32(0xc76c0020), SPH_C32(0x02ea7b0f), + SPH_C32(0x512948b6), SPH_C32(0x36343593) }, + { SPH_C32(0x56fc0090), SPH_C32(0xcc46a705), SPH_C32(0x478a47ae), + SPH_C32(0xe1dcc32a), SPH_C32(0xe9550020), SPH_C32(0x66371d86), + SPH_C32(0x6dfd4e4a), SPH_C32(0x87c0a52f) }, + { SPH_C32(0x29990080), SPH_C32(0xe868b377), SPH_C32(0x87b96750), + SPH_C32(0x217f03f7), SPH_C32(0xb8090030), SPH_C32(0x26c46f7d), + SPH_C32(0x911a6848), SPH_C32(0xf697f54e) }, + { SPH_C32(0x78c50090), SPH_C32(0xa89bc18c), SPH_C32(0x7b5e4152), + SPH_C32(0x50285396), SPH_C32(0x96300030), SPH_C32(0x421909f4), + SPH_C32(0xadce6eb4), SPH_C32(0x476365f2) }, + { SPH_C32(0xa51800a0), SPH_C32(0x0d523008), SPH_C32(0x42a32da8), + SPH_C32(0x7224338b), SPH_C32(0x9b1e0020), SPH_C32(0xcb50b61d), + SPH_C32(0x2880454f), SPH_C32(0x55dd14eb) }, + { SPH_C32(0xf44400b0), SPH_C32(0x4da142f3), SPH_C32(0xbe440baa), + SPH_C32(0x037363ea), SPH_C32(0xb5270020), SPH_C32(0xaf8dd094), + SPH_C32(0x145443b3), SPH_C32(0xe4298457) }, + { SPH_C32(0x8b2100a0), SPH_C32(0x698f5681), SPH_C32(0x7e772b54), + SPH_C32(0xc3d0a337), SPH_C32(0xe47b0030), SPH_C32(0xef7ea26f), + SPH_C32(0xe8b365b1), SPH_C32(0x957ed436) }, + { SPH_C32(0xda7d00b0), SPH_C32(0x297c247a), SPH_C32(0x82900d56), + SPH_C32(0xb287f356), SPH_C32(0xca420030), SPH_C32(0x8ba3c4e6), + SPH_C32(0xd467634d), SPH_C32(0x248a448a) }, + { SPH_C32(0x161c00c0), SPH_C32(0x7e54f492), SPH_C32(0xf4a107fd), + SPH_C32(0xd0018836), SPH_C32(0x410d0000), SPH_C32(0xea7a09df), + SPH_C32(0x8c12a9bc), SPH_C32(0xc50530e0) }, + { SPH_C32(0x474000d0), SPH_C32(0x3ea78669), SPH_C32(0x084621ff), + SPH_C32(0xa156d857), SPH_C32(0x6f340000), SPH_C32(0x8ea76f56), + SPH_C32(0xb0c6af40), SPH_C32(0x74f1a05c) }, + { SPH_C32(0x382500c0), SPH_C32(0x1a89921b), SPH_C32(0xc8750101), + SPH_C32(0x61f5188a), SPH_C32(0x3e680010), SPH_C32(0xce541dad), + SPH_C32(0x4c218942), SPH_C32(0x05a6f03d) }, + { SPH_C32(0x697900d0), SPH_C32(0x5a7ae0e0), SPH_C32(0x34922703), + SPH_C32(0x10a248eb), SPH_C32(0x10510010), SPH_C32(0xaa897b24), + SPH_C32(0x70f58fbe), SPH_C32(0xb4526081) }, + { SPH_C32(0xb4a400e0), SPH_C32(0xffb31164), SPH_C32(0x0d6f4bf9), + SPH_C32(0x32ae28f6), SPH_C32(0x1d7f0000), SPH_C32(0x23c0c4cd), + SPH_C32(0xf5bba445), SPH_C32(0xa6ec1198) }, + { SPH_C32(0xe5f800f0), SPH_C32(0xbf40639f), SPH_C32(0xf1886dfb), + SPH_C32(0x43f97897), SPH_C32(0x33460000), SPH_C32(0x471da244), + SPH_C32(0xc96fa2b9), SPH_C32(0x17188124) }, + { SPH_C32(0x9a9d00e0), SPH_C32(0x9b6e77ed), SPH_C32(0x31bb4d05), + SPH_C32(0x835ab84a), SPH_C32(0x621a0010), SPH_C32(0x07eed0bf), + SPH_C32(0x358884bb), SPH_C32(0x664fd145) }, + { SPH_C32(0xcbc100f0), SPH_C32(0xdb9d0516), SPH_C32(0xcd5c6b07), + SPH_C32(0xf20de82b), SPH_C32(0x4c230010), SPH_C32(0x6333b636), + SPH_C32(0x095c8247), SPH_C32(0xd7bb41f9) }, + { SPH_C32(0x4a6e00c0), SPH_C32(0xb7ee3980), SPH_C32(0x8d080a04), + SPH_C32(0xb3e8a94e), SPH_C32(0xbfc70020), SPH_C32(0xa227213b), + SPH_C32(0x0c75e841), SPH_C32(0x4443b158) }, + { SPH_C32(0x1b3200d0), SPH_C32(0xf71d4b7b), SPH_C32(0x71ef2c06), + SPH_C32(0xc2bff92f), SPH_C32(0x91fe0020), SPH_C32(0xc6fa47b2), + SPH_C32(0x30a1eebd), SPH_C32(0xf5b721e4) }, + { SPH_C32(0x645700c0), SPH_C32(0xd3335f09), SPH_C32(0xb1dc0cf8), + SPH_C32(0x021c39f2), SPH_C32(0xc0a20030), SPH_C32(0x86093549), + SPH_C32(0xcc46c8bf), SPH_C32(0x84e07185) }, + { SPH_C32(0x350b00d0), SPH_C32(0x93c02df2), SPH_C32(0x4d3b2afa), + SPH_C32(0x734b6993), SPH_C32(0xee9b0030), SPH_C32(0xe2d453c0), + SPH_C32(0xf092ce43), SPH_C32(0x3514e139) }, + { SPH_C32(0xe8d600e0), SPH_C32(0x3609dc76), SPH_C32(0x74c64600), + SPH_C32(0x5147098e), SPH_C32(0xe3b50020), SPH_C32(0x6b9dec29), + SPH_C32(0x75dce5b8), SPH_C32(0x27aa9020) }, + { SPH_C32(0xb98a00f0), SPH_C32(0x76faae8d), SPH_C32(0x88216002), + SPH_C32(0x201059ef), SPH_C32(0xcd8c0020), SPH_C32(0x0f408aa0), + SPH_C32(0x4908e344), SPH_C32(0x965e009c) }, + { SPH_C32(0xc6ef00e0), SPH_C32(0x52d4baff), SPH_C32(0x481240fc), + SPH_C32(0xe0b39932), SPH_C32(0x9cd00030), SPH_C32(0x4fb3f85b), + SPH_C32(0xb5efc546), SPH_C32(0xe70950fd) }, + { SPH_C32(0x97b300f0), SPH_C32(0x1227c804), SPH_C32(0xb4f566fe), + SPH_C32(0x91e4c953), SPH_C32(0xb2e90030), SPH_C32(0x2b6e9ed2), + SPH_C32(0x893bc3ba), SPH_C32(0x56fdc041) }, + { SPH_C32(0x23790080), SPH_C32(0xe5c242d8), SPH_C32(0x9f98cca2), + SPH_C32(0x811536f8), SPH_C32(0x0cc30040), SPH_C32(0xd121e5a1), + SPH_C32(0xba77c214), SPH_C32(0xe6660ae5) }, + { SPH_C32(0x72250090), SPH_C32(0xa5313023), SPH_C32(0x637feaa0), + SPH_C32(0xf0426699), SPH_C32(0x22fa0040), SPH_C32(0xb5fc8328), + SPH_C32(0x86a3c4e8), SPH_C32(0x57929a59) }, + { SPH_C32(0x0d400080), SPH_C32(0x811f2451), SPH_C32(0xa34cca5e), + SPH_C32(0x30e1a644), SPH_C32(0x73a60050), SPH_C32(0xf50ff1d3), + SPH_C32(0x7a44e2ea), SPH_C32(0x26c5ca38) }, + { SPH_C32(0x5c1c0090), SPH_C32(0xc1ec56aa), SPH_C32(0x5fabec5c), + SPH_C32(0x41b6f625), SPH_C32(0x5d9f0050), SPH_C32(0x91d2975a), + SPH_C32(0x4690e416), SPH_C32(0x97315a84) }, + { SPH_C32(0x81c100a0), SPH_C32(0x6425a72e), SPH_C32(0x665680a6), + SPH_C32(0x63ba9638), SPH_C32(0x50b10040), SPH_C32(0x189b28b3), + SPH_C32(0xc3decfed), SPH_C32(0x858f2b9d) }, + { SPH_C32(0xd09d00b0), SPH_C32(0x24d6d5d5), SPH_C32(0x9ab1a6a4), + SPH_C32(0x12edc659), SPH_C32(0x7e880040), SPH_C32(0x7c464e3a), + SPH_C32(0xff0ac911), SPH_C32(0x347bbb21) }, + { SPH_C32(0xaff800a0), SPH_C32(0x00f8c1a7), SPH_C32(0x5a82865a), + SPH_C32(0xd24e0684), SPH_C32(0x2fd40050), SPH_C32(0x3cb53cc1), + SPH_C32(0x03edef13), SPH_C32(0x452ceb40) }, + { SPH_C32(0xfea400b0), SPH_C32(0x400bb35c), SPH_C32(0xa665a058), + SPH_C32(0xa31956e5), SPH_C32(0x01ed0050), SPH_C32(0x58685a48), + SPH_C32(0x3f39e9ef), SPH_C32(0xf4d87bfc) }, + { SPH_C32(0x7f0b0080), SPH_C32(0x2c788fca), SPH_C32(0xe631c15b), + SPH_C32(0xe2fc1780), SPH_C32(0xf2090060), SPH_C32(0x997ccd45), + SPH_C32(0x3a1083e9), SPH_C32(0x67208b5d) }, + { SPH_C32(0x2e570090), SPH_C32(0x6c8bfd31), SPH_C32(0x1ad6e759), + SPH_C32(0x93ab47e1), SPH_C32(0xdc300060), SPH_C32(0xfda1abcc), + SPH_C32(0x06c48515), SPH_C32(0xd6d41be1) }, + { SPH_C32(0x51320080), SPH_C32(0x48a5e943), SPH_C32(0xdae5c7a7), + SPH_C32(0x5308873c), SPH_C32(0x8d6c0070), SPH_C32(0xbd52d937), + SPH_C32(0xfa23a317), SPH_C32(0xa7834b80) }, + { SPH_C32(0x006e0090), SPH_C32(0x08569bb8), SPH_C32(0x2602e1a5), + SPH_C32(0x225fd75d), SPH_C32(0xa3550070), SPH_C32(0xd98fbfbe), + SPH_C32(0xc6f7a5eb), SPH_C32(0x1677db3c) }, + { SPH_C32(0xddb300a0), SPH_C32(0xad9f6a3c), SPH_C32(0x1fff8d5f), + SPH_C32(0x0053b740), SPH_C32(0xae7b0060), SPH_C32(0x50c60057), + SPH_C32(0x43b98e10), SPH_C32(0x04c9aa25) }, + { SPH_C32(0x8cef00b0), SPH_C32(0xed6c18c7), SPH_C32(0xe318ab5d), + SPH_C32(0x7104e721), SPH_C32(0x80420060), SPH_C32(0x341b66de), + SPH_C32(0x7f6d88ec), SPH_C32(0xb53d3a99) }, + { SPH_C32(0xf38a00a0), SPH_C32(0xc9420cb5), SPH_C32(0x232b8ba3), + SPH_C32(0xb1a727fc), SPH_C32(0xd11e0070), SPH_C32(0x74e81425), + SPH_C32(0x838aaeee), SPH_C32(0xc46a6af8) }, + { SPH_C32(0xa2d600b0), SPH_C32(0x89b17e4e), SPH_C32(0xdfccada1), + SPH_C32(0xc0f0779d), SPH_C32(0xff270070), SPH_C32(0x103572ac), + SPH_C32(0xbf5ea812), SPH_C32(0x759efa44) }, + { SPH_C32(0x6eb700c0), SPH_C32(0xde99aea6), SPH_C32(0xa9fda70a), + SPH_C32(0xa2760cfd), SPH_C32(0x74680040), SPH_C32(0x71ecbf95), + SPH_C32(0xe72b62e3), SPH_C32(0x94118e2e) }, + { SPH_C32(0x3feb00d0), SPH_C32(0x9e6adc5d), SPH_C32(0x551a8108), + SPH_C32(0xd3215c9c), SPH_C32(0x5a510040), SPH_C32(0x1531d91c), + SPH_C32(0xdbff641f), SPH_C32(0x25e51e92) }, + { SPH_C32(0x408e00c0), SPH_C32(0xba44c82f), SPH_C32(0x9529a1f6), + SPH_C32(0x13829c41), SPH_C32(0x0b0d0050), SPH_C32(0x55c2abe7), + SPH_C32(0x2718421d), SPH_C32(0x54b24ef3) }, + { SPH_C32(0x11d200d0), SPH_C32(0xfab7bad4), SPH_C32(0x69ce87f4), + SPH_C32(0x62d5cc20), SPH_C32(0x25340050), SPH_C32(0x311fcd6e), + SPH_C32(0x1bcc44e1), SPH_C32(0xe546de4f) }, + { SPH_C32(0xcc0f00e0), SPH_C32(0x5f7e4b50), SPH_C32(0x5033eb0e), + SPH_C32(0x40d9ac3d), SPH_C32(0x281a0040), SPH_C32(0xb8567287), + SPH_C32(0x9e826f1a), SPH_C32(0xf7f8af56) }, + { SPH_C32(0x9d5300f0), SPH_C32(0x1f8d39ab), SPH_C32(0xacd4cd0c), + SPH_C32(0x318efc5c), SPH_C32(0x06230040), SPH_C32(0xdc8b140e), + SPH_C32(0xa25669e6), SPH_C32(0x460c3fea) }, + { SPH_C32(0xe23600e0), SPH_C32(0x3ba32dd9), SPH_C32(0x6ce7edf2), + SPH_C32(0xf12d3c81), SPH_C32(0x577f0050), SPH_C32(0x9c7866f5), + SPH_C32(0x5eb14fe4), SPH_C32(0x375b6f8b) }, + { SPH_C32(0xb36a00f0), SPH_C32(0x7b505f22), SPH_C32(0x9000cbf0), + SPH_C32(0x807a6ce0), SPH_C32(0x79460050), SPH_C32(0xf8a5007c), + SPH_C32(0x62654918), SPH_C32(0x86afff37) }, + { SPH_C32(0x32c500c0), SPH_C32(0x172363b4), SPH_C32(0xd054aaf3), + SPH_C32(0xc19f2d85), SPH_C32(0x8aa20060), SPH_C32(0x39b19771), + SPH_C32(0x674c231e), SPH_C32(0x15570f96) }, + { SPH_C32(0x639900d0), SPH_C32(0x57d0114f), SPH_C32(0x2cb38cf1), + SPH_C32(0xb0c87de4), SPH_C32(0xa49b0060), SPH_C32(0x5d6cf1f8), + SPH_C32(0x5b9825e2), SPH_C32(0xa4a39f2a) }, + { SPH_C32(0x1cfc00c0), SPH_C32(0x73fe053d), SPH_C32(0xec80ac0f), + SPH_C32(0x706bbd39), SPH_C32(0xf5c70070), SPH_C32(0x1d9f8303), + SPH_C32(0xa77f03e0), SPH_C32(0xd5f4cf4b) }, + { SPH_C32(0x4da000d0), SPH_C32(0x330d77c6), SPH_C32(0x10678a0d), + SPH_C32(0x013ced58), SPH_C32(0xdbfe0070), SPH_C32(0x7942e58a), + SPH_C32(0x9bab051c), SPH_C32(0x64005ff7) }, + { SPH_C32(0x907d00e0), SPH_C32(0x96c48642), SPH_C32(0x299ae6f7), + SPH_C32(0x23308d45), SPH_C32(0xd6d00060), SPH_C32(0xf00b5a63), + SPH_C32(0x1ee52ee7), SPH_C32(0x76be2eee) }, + { SPH_C32(0xc12100f0), SPH_C32(0xd637f4b9), SPH_C32(0xd57dc0f5), + SPH_C32(0x5267dd24), SPH_C32(0xf8e90060), SPH_C32(0x94d63cea), + SPH_C32(0x2231281b), SPH_C32(0xc74abe52) }, + { SPH_C32(0xbe4400e0), SPH_C32(0xf219e0cb), SPH_C32(0x154ee00b), + SPH_C32(0x92c41df9), SPH_C32(0xa9b50070), SPH_C32(0xd4254e11), + SPH_C32(0xded60e19), SPH_C32(0xb61dee33) }, + { SPH_C32(0xef1800f0), SPH_C32(0xb2ea9230), SPH_C32(0xe9a9c609), + SPH_C32(0xe3934d98), SPH_C32(0x878c0070), SPH_C32(0xb0f82898), + SPH_C32(0xe20208e5), SPH_C32(0x07e97e8f) }, + { SPH_C32(0x39a60000), SPH_C32(0x4ab753eb), SPH_C32(0xd14e094b), + SPH_C32(0xb772b42b), SPH_C32(0x62740080), SPH_C32(0x0fb84b07), + SPH_C32(0x138a651e), SPH_C32(0x44100618) }, + { SPH_C32(0x68fa0010), SPH_C32(0x0a442110), SPH_C32(0x2da92f49), + SPH_C32(0xc625e44a), SPH_C32(0x4c4d0080), SPH_C32(0x6b652d8e), + SPH_C32(0x2f5e63e2), SPH_C32(0xf5e496a4) }, + { SPH_C32(0x179f0000), SPH_C32(0x2e6a3562), SPH_C32(0xed9a0fb7), + SPH_C32(0x06862497), SPH_C32(0x1d110090), SPH_C32(0x2b965f75), + SPH_C32(0xd3b945e0), SPH_C32(0x84b3c6c5) }, + { SPH_C32(0x46c30010), SPH_C32(0x6e994799), SPH_C32(0x117d29b5), + SPH_C32(0x77d174f6), SPH_C32(0x33280090), SPH_C32(0x4f4b39fc), + SPH_C32(0xef6d431c), SPH_C32(0x35475679) }, + { SPH_C32(0x9b1e0020), SPH_C32(0xcb50b61d), SPH_C32(0x2880454f), + SPH_C32(0x55dd14eb), SPH_C32(0x3e060080), SPH_C32(0xc6028615), + SPH_C32(0x6a2368e7), SPH_C32(0x27f92760) }, + { SPH_C32(0xca420030), SPH_C32(0x8ba3c4e6), SPH_C32(0xd467634d), + SPH_C32(0x248a448a), SPH_C32(0x103f0080), SPH_C32(0xa2dfe09c), + SPH_C32(0x56f76e1b), SPH_C32(0x960db7dc) }, + { SPH_C32(0xb5270020), SPH_C32(0xaf8dd094), SPH_C32(0x145443b3), + SPH_C32(0xe4298457), SPH_C32(0x41630090), SPH_C32(0xe22c9267), + SPH_C32(0xaa104819), SPH_C32(0xe75ae7bd) }, + { SPH_C32(0xe47b0030), SPH_C32(0xef7ea26f), SPH_C32(0xe8b365b1), + SPH_C32(0x957ed436), SPH_C32(0x6f5a0090), SPH_C32(0x86f1f4ee), + SPH_C32(0x96c44ee5), SPH_C32(0x56ae7701) }, + { SPH_C32(0x65d40000), SPH_C32(0x830d9ef9), SPH_C32(0xa8e704b2), + SPH_C32(0xd49b9553), SPH_C32(0x9cbe00a0), SPH_C32(0x47e563e3), + SPH_C32(0x93ed24e3), SPH_C32(0xc55687a0) }, + { SPH_C32(0x34880010), SPH_C32(0xc3feec02), SPH_C32(0x540022b0), + SPH_C32(0xa5ccc532), SPH_C32(0xb28700a0), SPH_C32(0x2338056a), + SPH_C32(0xaf39221f), SPH_C32(0x74a2171c) }, + { SPH_C32(0x4bed0000), SPH_C32(0xe7d0f870), SPH_C32(0x9433024e), + SPH_C32(0x656f05ef), SPH_C32(0xe3db00b0), SPH_C32(0x63cb7791), + SPH_C32(0x53de041d), SPH_C32(0x05f5477d) }, + { SPH_C32(0x1ab10010), SPH_C32(0xa7238a8b), SPH_C32(0x68d4244c), + SPH_C32(0x1438558e), SPH_C32(0xcde200b0), SPH_C32(0x07161118), + SPH_C32(0x6f0a02e1), SPH_C32(0xb401d7c1) }, + { SPH_C32(0xc76c0020), SPH_C32(0x02ea7b0f), SPH_C32(0x512948b6), + SPH_C32(0x36343593), SPH_C32(0xc0cc00a0), SPH_C32(0x8e5faef1), + SPH_C32(0xea44291a), SPH_C32(0xa6bfa6d8) }, + { SPH_C32(0x96300030), SPH_C32(0x421909f4), SPH_C32(0xadce6eb4), + SPH_C32(0x476365f2), SPH_C32(0xeef500a0), SPH_C32(0xea82c878), + SPH_C32(0xd6902fe6), SPH_C32(0x174b3664) }, + { SPH_C32(0xe9550020), SPH_C32(0x66371d86), SPH_C32(0x6dfd4e4a), + SPH_C32(0x87c0a52f), SPH_C32(0xbfa900b0), SPH_C32(0xaa71ba83), + SPH_C32(0x2a7709e4), SPH_C32(0x661c6605) }, + { SPH_C32(0xb8090030), SPH_C32(0x26c46f7d), SPH_C32(0x911a6848), + SPH_C32(0xf697f54e), SPH_C32(0x919000b0), SPH_C32(0xceacdc0a), + SPH_C32(0x16a30f18), SPH_C32(0xd7e8f6b9) }, + { SPH_C32(0x74680040), SPH_C32(0x71ecbf95), SPH_C32(0xe72b62e3), + SPH_C32(0x94118e2e), SPH_C32(0x1adf0080), SPH_C32(0xaf751133), + SPH_C32(0x4ed6c5e9), SPH_C32(0x366782d3) }, + { SPH_C32(0x25340050), SPH_C32(0x311fcd6e), SPH_C32(0x1bcc44e1), + SPH_C32(0xe546de4f), SPH_C32(0x34e60080), SPH_C32(0xcba877ba), + SPH_C32(0x7202c315), SPH_C32(0x8793126f) }, + { SPH_C32(0x5a510040), SPH_C32(0x1531d91c), SPH_C32(0xdbff641f), + SPH_C32(0x25e51e92), SPH_C32(0x65ba0090), SPH_C32(0x8b5b0541), + SPH_C32(0x8ee5e517), SPH_C32(0xf6c4420e) }, + { SPH_C32(0x0b0d0050), SPH_C32(0x55c2abe7), SPH_C32(0x2718421d), + SPH_C32(0x54b24ef3), SPH_C32(0x4b830090), SPH_C32(0xef8663c8), + SPH_C32(0xb231e3eb), SPH_C32(0x4730d2b2) }, + { SPH_C32(0xd6d00060), SPH_C32(0xf00b5a63), SPH_C32(0x1ee52ee7), + SPH_C32(0x76be2eee), SPH_C32(0x46ad0080), SPH_C32(0x66cfdc21), + SPH_C32(0x377fc810), SPH_C32(0x558ea3ab) }, + { SPH_C32(0x878c0070), SPH_C32(0xb0f82898), SPH_C32(0xe20208e5), + SPH_C32(0x07e97e8f), SPH_C32(0x68940080), SPH_C32(0x0212baa8), + SPH_C32(0x0babceec), SPH_C32(0xe47a3317) }, + { SPH_C32(0xf8e90060), SPH_C32(0x94d63cea), SPH_C32(0x2231281b), + SPH_C32(0xc74abe52), SPH_C32(0x39c80090), SPH_C32(0x42e1c853), + SPH_C32(0xf74ce8ee), SPH_C32(0x952d6376) }, + { SPH_C32(0xa9b50070), SPH_C32(0xd4254e11), SPH_C32(0xded60e19), + SPH_C32(0xb61dee33), SPH_C32(0x17f10090), SPH_C32(0x263caeda), + SPH_C32(0xcb98ee12), SPH_C32(0x24d9f3ca) }, + { SPH_C32(0x281a0040), SPH_C32(0xb8567287), SPH_C32(0x9e826f1a), + SPH_C32(0xf7f8af56), SPH_C32(0xe41500a0), SPH_C32(0xe72839d7), + SPH_C32(0xceb18414), SPH_C32(0xb721036b) }, + { SPH_C32(0x79460050), SPH_C32(0xf8a5007c), SPH_C32(0x62654918), + SPH_C32(0x86afff37), SPH_C32(0xca2c00a0), SPH_C32(0x83f55f5e), + SPH_C32(0xf26582e8), SPH_C32(0x06d593d7) }, + { SPH_C32(0x06230040), SPH_C32(0xdc8b140e), SPH_C32(0xa25669e6), + SPH_C32(0x460c3fea), SPH_C32(0x9b7000b0), SPH_C32(0xc3062da5), + SPH_C32(0x0e82a4ea), SPH_C32(0x7782c3b6) }, + { SPH_C32(0x577f0050), SPH_C32(0x9c7866f5), SPH_C32(0x5eb14fe4), + SPH_C32(0x375b6f8b), SPH_C32(0xb54900b0), SPH_C32(0xa7db4b2c), + SPH_C32(0x3256a216), SPH_C32(0xc676530a) }, + { SPH_C32(0x8aa20060), SPH_C32(0x39b19771), SPH_C32(0x674c231e), + SPH_C32(0x15570f96), SPH_C32(0xb86700a0), SPH_C32(0x2e92f4c5), + SPH_C32(0xb71889ed), SPH_C32(0xd4c82213) }, + { SPH_C32(0xdbfe0070), SPH_C32(0x7942e58a), SPH_C32(0x9bab051c), + SPH_C32(0x64005ff7), SPH_C32(0x965e00a0), SPH_C32(0x4a4f924c), + SPH_C32(0x8bcc8f11), SPH_C32(0x653cb2af) }, + { SPH_C32(0xa49b0060), SPH_C32(0x5d6cf1f8), SPH_C32(0x5b9825e2), + SPH_C32(0xa4a39f2a), SPH_C32(0xc70200b0), SPH_C32(0x0abce0b7), + SPH_C32(0x772ba913), SPH_C32(0x146be2ce) }, + { SPH_C32(0xf5c70070), SPH_C32(0x1d9f8303), SPH_C32(0xa77f03e0), + SPH_C32(0xd5f4cf4b), SPH_C32(0xe93b00b0), SPH_C32(0x6e61863e), + SPH_C32(0x4bffafef), SPH_C32(0xa59f7272) }, + { SPH_C32(0x410d0000), SPH_C32(0xea7a09df), SPH_C32(0x8c12a9bc), + SPH_C32(0xc50530e0), SPH_C32(0x571100c0), SPH_C32(0x942efd4d), + SPH_C32(0x78b3ae41), SPH_C32(0x1504b8d6) }, + { SPH_C32(0x10510010), SPH_C32(0xaa897b24), SPH_C32(0x70f58fbe), + SPH_C32(0xb4526081), SPH_C32(0x792800c0), SPH_C32(0xf0f39bc4), + SPH_C32(0x4467a8bd), SPH_C32(0xa4f0286a) }, + { SPH_C32(0x6f340000), SPH_C32(0x8ea76f56), SPH_C32(0xb0c6af40), + SPH_C32(0x74f1a05c), SPH_C32(0x287400d0), SPH_C32(0xb000e93f), + SPH_C32(0xb8808ebf), SPH_C32(0xd5a7780b) }, + { SPH_C32(0x3e680010), SPH_C32(0xce541dad), SPH_C32(0x4c218942), + SPH_C32(0x05a6f03d), SPH_C32(0x064d00d0), SPH_C32(0xd4dd8fb6), + SPH_C32(0x84548843), SPH_C32(0x6453e8b7) }, + { SPH_C32(0xe3b50020), SPH_C32(0x6b9dec29), SPH_C32(0x75dce5b8), + SPH_C32(0x27aa9020), SPH_C32(0x0b6300c0), SPH_C32(0x5d94305f), + SPH_C32(0x011aa3b8), SPH_C32(0x76ed99ae) }, + { SPH_C32(0xb2e90030), SPH_C32(0x2b6e9ed2), SPH_C32(0x893bc3ba), + SPH_C32(0x56fdc041), SPH_C32(0x255a00c0), SPH_C32(0x394956d6), + SPH_C32(0x3dcea544), SPH_C32(0xc7190912) }, + { SPH_C32(0xcd8c0020), SPH_C32(0x0f408aa0), SPH_C32(0x4908e344), + SPH_C32(0x965e009c), SPH_C32(0x740600d0), SPH_C32(0x79ba242d), + SPH_C32(0xc1298346), SPH_C32(0xb64e5973) }, + { SPH_C32(0x9cd00030), SPH_C32(0x4fb3f85b), SPH_C32(0xb5efc546), + SPH_C32(0xe70950fd), SPH_C32(0x5a3f00d0), SPH_C32(0x1d6742a4), + SPH_C32(0xfdfd85ba), SPH_C32(0x07bac9cf) }, + { SPH_C32(0x1d7f0000), SPH_C32(0x23c0c4cd), SPH_C32(0xf5bba445), + SPH_C32(0xa6ec1198), SPH_C32(0xa9db00e0), SPH_C32(0xdc73d5a9), + SPH_C32(0xf8d4efbc), SPH_C32(0x9442396e) }, + { SPH_C32(0x4c230010), SPH_C32(0x6333b636), SPH_C32(0x095c8247), + SPH_C32(0xd7bb41f9), SPH_C32(0x87e200e0), SPH_C32(0xb8aeb320), + SPH_C32(0xc400e940), SPH_C32(0x25b6a9d2) }, + { SPH_C32(0x33460000), SPH_C32(0x471da244), SPH_C32(0xc96fa2b9), + SPH_C32(0x17188124), SPH_C32(0xd6be00f0), SPH_C32(0xf85dc1db), + SPH_C32(0x38e7cf42), SPH_C32(0x54e1f9b3) }, + { SPH_C32(0x621a0010), SPH_C32(0x07eed0bf), SPH_C32(0x358884bb), + SPH_C32(0x664fd145), SPH_C32(0xf88700f0), SPH_C32(0x9c80a752), + SPH_C32(0x0433c9be), SPH_C32(0xe515690f) }, + { SPH_C32(0xbfc70020), SPH_C32(0xa227213b), SPH_C32(0x0c75e841), + SPH_C32(0x4443b158), SPH_C32(0xf5a900e0), SPH_C32(0x15c918bb), + SPH_C32(0x817de245), SPH_C32(0xf7ab1816) }, + { SPH_C32(0xee9b0030), SPH_C32(0xe2d453c0), SPH_C32(0xf092ce43), + SPH_C32(0x3514e139), SPH_C32(0xdb9000e0), SPH_C32(0x71147e32), + SPH_C32(0xbda9e4b9), SPH_C32(0x465f88aa) }, + { SPH_C32(0x91fe0020), SPH_C32(0xc6fa47b2), SPH_C32(0x30a1eebd), + SPH_C32(0xf5b721e4), SPH_C32(0x8acc00f0), SPH_C32(0x31e70cc9), + SPH_C32(0x414ec2bb), SPH_C32(0x3708d8cb) }, + { SPH_C32(0xc0a20030), SPH_C32(0x86093549), SPH_C32(0xcc46c8bf), + SPH_C32(0x84e07185), SPH_C32(0xa4f500f0), SPH_C32(0x553a6a40), + SPH_C32(0x7d9ac447), SPH_C32(0x86fc4877) }, + { SPH_C32(0x0cc30040), SPH_C32(0xd121e5a1), SPH_C32(0xba77c214), + SPH_C32(0xe6660ae5), SPH_C32(0x2fba00c0), SPH_C32(0x34e3a779), + SPH_C32(0x25ef0eb6), SPH_C32(0x67733c1d) }, + { SPH_C32(0x5d9f0050), SPH_C32(0x91d2975a), SPH_C32(0x4690e416), + SPH_C32(0x97315a84), SPH_C32(0x018300c0), SPH_C32(0x503ec1f0), + SPH_C32(0x193b084a), SPH_C32(0xd687aca1) }, + { SPH_C32(0x22fa0040), SPH_C32(0xb5fc8328), SPH_C32(0x86a3c4e8), + SPH_C32(0x57929a59), SPH_C32(0x50df00d0), SPH_C32(0x10cdb30b), + SPH_C32(0xe5dc2e48), SPH_C32(0xa7d0fcc0) }, + { SPH_C32(0x73a60050), SPH_C32(0xf50ff1d3), SPH_C32(0x7a44e2ea), + SPH_C32(0x26c5ca38), SPH_C32(0x7ee600d0), SPH_C32(0x7410d582), + SPH_C32(0xd90828b4), SPH_C32(0x16246c7c) }, + { SPH_C32(0xae7b0060), SPH_C32(0x50c60057), SPH_C32(0x43b98e10), + SPH_C32(0x04c9aa25), SPH_C32(0x73c800c0), SPH_C32(0xfd596a6b), + SPH_C32(0x5c46034f), SPH_C32(0x049a1d65) }, + { SPH_C32(0xff270070), SPH_C32(0x103572ac), SPH_C32(0xbf5ea812), + SPH_C32(0x759efa44), SPH_C32(0x5df100c0), SPH_C32(0x99840ce2), + SPH_C32(0x609205b3), SPH_C32(0xb56e8dd9) }, + { SPH_C32(0x80420060), SPH_C32(0x341b66de), SPH_C32(0x7f6d88ec), + SPH_C32(0xb53d3a99), SPH_C32(0x0cad00d0), SPH_C32(0xd9777e19), + SPH_C32(0x9c7523b1), SPH_C32(0xc439ddb8) }, + { SPH_C32(0xd11e0070), SPH_C32(0x74e81425), SPH_C32(0x838aaeee), + SPH_C32(0xc46a6af8), SPH_C32(0x229400d0), SPH_C32(0xbdaa1890), + SPH_C32(0xa0a1254d), SPH_C32(0x75cd4d04) }, + { SPH_C32(0x50b10040), SPH_C32(0x189b28b3), SPH_C32(0xc3decfed), + SPH_C32(0x858f2b9d), SPH_C32(0xd17000e0), SPH_C32(0x7cbe8f9d), + SPH_C32(0xa5884f4b), SPH_C32(0xe635bda5) }, + { SPH_C32(0x01ed0050), SPH_C32(0x58685a48), SPH_C32(0x3f39e9ef), + SPH_C32(0xf4d87bfc), SPH_C32(0xff4900e0), SPH_C32(0x1863e914), + SPH_C32(0x995c49b7), SPH_C32(0x57c12d19) }, + { SPH_C32(0x7e880040), SPH_C32(0x7c464e3a), SPH_C32(0xff0ac911), + SPH_C32(0x347bbb21), SPH_C32(0xae1500f0), SPH_C32(0x58909bef), + SPH_C32(0x65bb6fb5), SPH_C32(0x26967d78) }, + { SPH_C32(0x2fd40050), SPH_C32(0x3cb53cc1), SPH_C32(0x03edef13), + SPH_C32(0x452ceb40), SPH_C32(0x802c00f0), SPH_C32(0x3c4dfd66), + SPH_C32(0x596f6949), SPH_C32(0x9762edc4) }, + { SPH_C32(0xf2090060), SPH_C32(0x997ccd45), SPH_C32(0x3a1083e9), + SPH_C32(0x67208b5d), SPH_C32(0x8d0200e0), SPH_C32(0xb504428f), + SPH_C32(0xdc2142b2), SPH_C32(0x85dc9cdd) }, + { SPH_C32(0xa3550070), SPH_C32(0xd98fbfbe), SPH_C32(0xc6f7a5eb), + SPH_C32(0x1677db3c), SPH_C32(0xa33b00e0), SPH_C32(0xd1d92406), + SPH_C32(0xe0f5444e), SPH_C32(0x34280c61) }, + { SPH_C32(0xdc300060), SPH_C32(0xfda1abcc), SPH_C32(0x06c48515), + SPH_C32(0xd6d41be1), SPH_C32(0xf26700f0), SPH_C32(0x912a56fd), + SPH_C32(0x1c12624c), SPH_C32(0x457f5c00) }, + { SPH_C32(0x8d6c0070), SPH_C32(0xbd52d937), SPH_C32(0xfa23a317), + SPH_C32(0xa7834b80), SPH_C32(0xdc5e00f0), SPH_C32(0xf5f73074), + SPH_C32(0x20c664b0), SPH_C32(0xf48bccbc) }, + { SPH_C32(0x62740080), SPH_C32(0x0fb84b07), SPH_C32(0x138a651e), + SPH_C32(0x44100618), SPH_C32(0x5bd20080), SPH_C32(0x450f18ec), + SPH_C32(0xc2c46c55), SPH_C32(0xf362b233) }, + { SPH_C32(0x33280090), SPH_C32(0x4f4b39fc), SPH_C32(0xef6d431c), + SPH_C32(0x35475679), SPH_C32(0x75eb0080), SPH_C32(0x21d27e65), + SPH_C32(0xfe106aa9), SPH_C32(0x4296228f) }, + { SPH_C32(0x4c4d0080), SPH_C32(0x6b652d8e), SPH_C32(0x2f5e63e2), + SPH_C32(0xf5e496a4), SPH_C32(0x24b70090), SPH_C32(0x61210c9e), + SPH_C32(0x02f74cab), SPH_C32(0x33c172ee) }, + { SPH_C32(0x1d110090), SPH_C32(0x2b965f75), SPH_C32(0xd3b945e0), + SPH_C32(0x84b3c6c5), SPH_C32(0x0a8e0090), SPH_C32(0x05fc6a17), + SPH_C32(0x3e234a57), SPH_C32(0x8235e252) }, + { SPH_C32(0xc0cc00a0), SPH_C32(0x8e5faef1), SPH_C32(0xea44291a), + SPH_C32(0xa6bfa6d8), SPH_C32(0x07a00080), SPH_C32(0x8cb5d5fe), + SPH_C32(0xbb6d61ac), SPH_C32(0x908b934b) }, + { SPH_C32(0x919000b0), SPH_C32(0xceacdc0a), SPH_C32(0x16a30f18), + SPH_C32(0xd7e8f6b9), SPH_C32(0x29990080), SPH_C32(0xe868b377), + SPH_C32(0x87b96750), SPH_C32(0x217f03f7) }, + { SPH_C32(0xeef500a0), SPH_C32(0xea82c878), SPH_C32(0xd6902fe6), + SPH_C32(0x174b3664), SPH_C32(0x78c50090), SPH_C32(0xa89bc18c), + SPH_C32(0x7b5e4152), SPH_C32(0x50285396) }, + { SPH_C32(0xbfa900b0), SPH_C32(0xaa71ba83), SPH_C32(0x2a7709e4), + SPH_C32(0x661c6605), SPH_C32(0x56fc0090), SPH_C32(0xcc46a705), + SPH_C32(0x478a47ae), SPH_C32(0xe1dcc32a) }, + { SPH_C32(0x3e060080), SPH_C32(0xc6028615), SPH_C32(0x6a2368e7), + SPH_C32(0x27f92760), SPH_C32(0xa51800a0), SPH_C32(0x0d523008), + SPH_C32(0x42a32da8), SPH_C32(0x7224338b) }, + { SPH_C32(0x6f5a0090), SPH_C32(0x86f1f4ee), SPH_C32(0x96c44ee5), + SPH_C32(0x56ae7701), SPH_C32(0x8b2100a0), SPH_C32(0x698f5681), + SPH_C32(0x7e772b54), SPH_C32(0xc3d0a337) }, + { SPH_C32(0x103f0080), SPH_C32(0xa2dfe09c), SPH_C32(0x56f76e1b), + SPH_C32(0x960db7dc), SPH_C32(0xda7d00b0), SPH_C32(0x297c247a), + SPH_C32(0x82900d56), SPH_C32(0xb287f356) }, + { SPH_C32(0x41630090), SPH_C32(0xe22c9267), SPH_C32(0xaa104819), + SPH_C32(0xe75ae7bd), SPH_C32(0xf44400b0), SPH_C32(0x4da142f3), + SPH_C32(0xbe440baa), SPH_C32(0x037363ea) }, + { SPH_C32(0x9cbe00a0), SPH_C32(0x47e563e3), SPH_C32(0x93ed24e3), + SPH_C32(0xc55687a0), SPH_C32(0xf96a00a0), SPH_C32(0xc4e8fd1a), + SPH_C32(0x3b0a2051), SPH_C32(0x11cd12f3) }, + { SPH_C32(0xcde200b0), SPH_C32(0x07161118), SPH_C32(0x6f0a02e1), + SPH_C32(0xb401d7c1), SPH_C32(0xd75300a0), SPH_C32(0xa0359b93), + SPH_C32(0x07de26ad), SPH_C32(0xa039824f) }, + { SPH_C32(0xb28700a0), SPH_C32(0x2338056a), SPH_C32(0xaf39221f), + SPH_C32(0x74a2171c), SPH_C32(0x860f00b0), SPH_C32(0xe0c6e968), + SPH_C32(0xfb3900af), SPH_C32(0xd16ed22e) }, + { SPH_C32(0xe3db00b0), SPH_C32(0x63cb7791), SPH_C32(0x53de041d), + SPH_C32(0x05f5477d), SPH_C32(0xa83600b0), SPH_C32(0x841b8fe1), + SPH_C32(0xc7ed0653), SPH_C32(0x609a4292) }, + { SPH_C32(0x2fba00c0), SPH_C32(0x34e3a779), SPH_C32(0x25ef0eb6), + SPH_C32(0x67733c1d), SPH_C32(0x23790080), SPH_C32(0xe5c242d8), + SPH_C32(0x9f98cca2), SPH_C32(0x811536f8) }, + { SPH_C32(0x7ee600d0), SPH_C32(0x7410d582), SPH_C32(0xd90828b4), + SPH_C32(0x16246c7c), SPH_C32(0x0d400080), SPH_C32(0x811f2451), + SPH_C32(0xa34cca5e), SPH_C32(0x30e1a644) }, + { SPH_C32(0x018300c0), SPH_C32(0x503ec1f0), SPH_C32(0x193b084a), + SPH_C32(0xd687aca1), SPH_C32(0x5c1c0090), SPH_C32(0xc1ec56aa), + SPH_C32(0x5fabec5c), SPH_C32(0x41b6f625) }, + { SPH_C32(0x50df00d0), SPH_C32(0x10cdb30b), SPH_C32(0xe5dc2e48), + SPH_C32(0xa7d0fcc0), SPH_C32(0x72250090), SPH_C32(0xa5313023), + SPH_C32(0x637feaa0), SPH_C32(0xf0426699) }, + { SPH_C32(0x8d0200e0), SPH_C32(0xb504428f), SPH_C32(0xdc2142b2), + SPH_C32(0x85dc9cdd), SPH_C32(0x7f0b0080), SPH_C32(0x2c788fca), + SPH_C32(0xe631c15b), SPH_C32(0xe2fc1780) }, + { SPH_C32(0xdc5e00f0), SPH_C32(0xf5f73074), SPH_C32(0x20c664b0), + SPH_C32(0xf48bccbc), SPH_C32(0x51320080), SPH_C32(0x48a5e943), + SPH_C32(0xdae5c7a7), SPH_C32(0x5308873c) }, + { SPH_C32(0xa33b00e0), SPH_C32(0xd1d92406), SPH_C32(0xe0f5444e), + SPH_C32(0x34280c61), SPH_C32(0x006e0090), SPH_C32(0x08569bb8), + SPH_C32(0x2602e1a5), SPH_C32(0x225fd75d) }, + { SPH_C32(0xf26700f0), SPH_C32(0x912a56fd), SPH_C32(0x1c12624c), + SPH_C32(0x457f5c00), SPH_C32(0x2e570090), SPH_C32(0x6c8bfd31), + SPH_C32(0x1ad6e759), SPH_C32(0x93ab47e1) }, + { SPH_C32(0x73c800c0), SPH_C32(0xfd596a6b), SPH_C32(0x5c46034f), + SPH_C32(0x049a1d65), SPH_C32(0xddb300a0), SPH_C32(0xad9f6a3c), + SPH_C32(0x1fff8d5f), SPH_C32(0x0053b740) }, + { SPH_C32(0x229400d0), SPH_C32(0xbdaa1890), SPH_C32(0xa0a1254d), + SPH_C32(0x75cd4d04), SPH_C32(0xf38a00a0), SPH_C32(0xc9420cb5), + SPH_C32(0x232b8ba3), SPH_C32(0xb1a727fc) }, + { SPH_C32(0x5df100c0), SPH_C32(0x99840ce2), SPH_C32(0x609205b3), + SPH_C32(0xb56e8dd9), SPH_C32(0xa2d600b0), SPH_C32(0x89b17e4e), + SPH_C32(0xdfccada1), SPH_C32(0xc0f0779d) }, + { SPH_C32(0x0cad00d0), SPH_C32(0xd9777e19), SPH_C32(0x9c7523b1), + SPH_C32(0xc439ddb8), SPH_C32(0x8cef00b0), SPH_C32(0xed6c18c7), + SPH_C32(0xe318ab5d), SPH_C32(0x7104e721) }, + { SPH_C32(0xd17000e0), SPH_C32(0x7cbe8f9d), SPH_C32(0xa5884f4b), + SPH_C32(0xe635bda5), SPH_C32(0x81c100a0), SPH_C32(0x6425a72e), + SPH_C32(0x665680a6), SPH_C32(0x63ba9638) }, + { SPH_C32(0x802c00f0), SPH_C32(0x3c4dfd66), SPH_C32(0x596f6949), + SPH_C32(0x9762edc4), SPH_C32(0xaff800a0), SPH_C32(0x00f8c1a7), + SPH_C32(0x5a82865a), SPH_C32(0xd24e0684) }, + { SPH_C32(0xff4900e0), SPH_C32(0x1863e914), SPH_C32(0x995c49b7), + SPH_C32(0x57c12d19), SPH_C32(0xfea400b0), SPH_C32(0x400bb35c), + SPH_C32(0xa665a058), SPH_C32(0xa31956e5) }, + { SPH_C32(0xae1500f0), SPH_C32(0x58909bef), SPH_C32(0x65bb6fb5), + SPH_C32(0x26967d78), SPH_C32(0xd09d00b0), SPH_C32(0x24d6d5d5), + SPH_C32(0x9ab1a6a4), SPH_C32(0x12edc659) }, + { SPH_C32(0x1adf0080), SPH_C32(0xaf751133), SPH_C32(0x4ed6c5e9), + SPH_C32(0x366782d3), SPH_C32(0x6eb700c0), SPH_C32(0xde99aea6), + SPH_C32(0xa9fda70a), SPH_C32(0xa2760cfd) }, + { SPH_C32(0x4b830090), SPH_C32(0xef8663c8), SPH_C32(0xb231e3eb), + SPH_C32(0x4730d2b2), SPH_C32(0x408e00c0), SPH_C32(0xba44c82f), + SPH_C32(0x9529a1f6), SPH_C32(0x13829c41) }, + { SPH_C32(0x34e60080), SPH_C32(0xcba877ba), SPH_C32(0x7202c315), + SPH_C32(0x8793126f), SPH_C32(0x11d200d0), SPH_C32(0xfab7bad4), + SPH_C32(0x69ce87f4), SPH_C32(0x62d5cc20) }, + { SPH_C32(0x65ba0090), SPH_C32(0x8b5b0541), SPH_C32(0x8ee5e517), + SPH_C32(0xf6c4420e), SPH_C32(0x3feb00d0), SPH_C32(0x9e6adc5d), + SPH_C32(0x551a8108), SPH_C32(0xd3215c9c) }, + { SPH_C32(0xb86700a0), SPH_C32(0x2e92f4c5), SPH_C32(0xb71889ed), + SPH_C32(0xd4c82213), SPH_C32(0x32c500c0), SPH_C32(0x172363b4), + SPH_C32(0xd054aaf3), SPH_C32(0xc19f2d85) }, + { SPH_C32(0xe93b00b0), SPH_C32(0x6e61863e), SPH_C32(0x4bffafef), + SPH_C32(0xa59f7272), SPH_C32(0x1cfc00c0), SPH_C32(0x73fe053d), + SPH_C32(0xec80ac0f), SPH_C32(0x706bbd39) }, + { SPH_C32(0x965e00a0), SPH_C32(0x4a4f924c), SPH_C32(0x8bcc8f11), + SPH_C32(0x653cb2af), SPH_C32(0x4da000d0), SPH_C32(0x330d77c6), + SPH_C32(0x10678a0d), SPH_C32(0x013ced58) }, + { SPH_C32(0xc70200b0), SPH_C32(0x0abce0b7), SPH_C32(0x772ba913), + SPH_C32(0x146be2ce), SPH_C32(0x639900d0), SPH_C32(0x57d0114f), + SPH_C32(0x2cb38cf1), SPH_C32(0xb0c87de4) }, + { SPH_C32(0x46ad0080), SPH_C32(0x66cfdc21), SPH_C32(0x377fc810), + SPH_C32(0x558ea3ab), SPH_C32(0x907d00e0), SPH_C32(0x96c48642), + SPH_C32(0x299ae6f7), SPH_C32(0x23308d45) }, + { SPH_C32(0x17f10090), SPH_C32(0x263caeda), SPH_C32(0xcb98ee12), + SPH_C32(0x24d9f3ca), SPH_C32(0xbe4400e0), SPH_C32(0xf219e0cb), + SPH_C32(0x154ee00b), SPH_C32(0x92c41df9) }, + { SPH_C32(0x68940080), SPH_C32(0x0212baa8), SPH_C32(0x0babceec), + SPH_C32(0xe47a3317), SPH_C32(0xef1800f0), SPH_C32(0xb2ea9230), + SPH_C32(0xe9a9c609), SPH_C32(0xe3934d98) }, + { SPH_C32(0x39c80090), SPH_C32(0x42e1c853), SPH_C32(0xf74ce8ee), + SPH_C32(0x952d6376), SPH_C32(0xc12100f0), SPH_C32(0xd637f4b9), + SPH_C32(0xd57dc0f5), SPH_C32(0x5267dd24) }, + { SPH_C32(0xe41500a0), SPH_C32(0xe72839d7), SPH_C32(0xceb18414), + SPH_C32(0xb721036b), SPH_C32(0xcc0f00e0), SPH_C32(0x5f7e4b50), + SPH_C32(0x5033eb0e), SPH_C32(0x40d9ac3d) }, + { SPH_C32(0xb54900b0), SPH_C32(0xa7db4b2c), SPH_C32(0x3256a216), + SPH_C32(0xc676530a), SPH_C32(0xe23600e0), SPH_C32(0x3ba32dd9), + SPH_C32(0x6ce7edf2), SPH_C32(0xf12d3c81) }, + { SPH_C32(0xca2c00a0), SPH_C32(0x83f55f5e), SPH_C32(0xf26582e8), + SPH_C32(0x06d593d7), SPH_C32(0xb36a00f0), SPH_C32(0x7b505f22), + SPH_C32(0x9000cbf0), SPH_C32(0x807a6ce0) }, + { SPH_C32(0x9b7000b0), SPH_C32(0xc3062da5), SPH_C32(0x0e82a4ea), + SPH_C32(0x7782c3b6), SPH_C32(0x9d5300f0), SPH_C32(0x1f8d39ab), + SPH_C32(0xacd4cd0c), SPH_C32(0x318efc5c) }, + { SPH_C32(0x571100c0), SPH_C32(0x942efd4d), SPH_C32(0x78b3ae41), + SPH_C32(0x1504b8d6), SPH_C32(0x161c00c0), SPH_C32(0x7e54f492), + SPH_C32(0xf4a107fd), SPH_C32(0xd0018836) }, + { SPH_C32(0x064d00d0), SPH_C32(0xd4dd8fb6), SPH_C32(0x84548843), + SPH_C32(0x6453e8b7), SPH_C32(0x382500c0), SPH_C32(0x1a89921b), + SPH_C32(0xc8750101), SPH_C32(0x61f5188a) }, + { SPH_C32(0x792800c0), SPH_C32(0xf0f39bc4), SPH_C32(0x4467a8bd), + SPH_C32(0xa4f0286a), SPH_C32(0x697900d0), SPH_C32(0x5a7ae0e0), + SPH_C32(0x34922703), SPH_C32(0x10a248eb) }, + { SPH_C32(0x287400d0), SPH_C32(0xb000e93f), SPH_C32(0xb8808ebf), + SPH_C32(0xd5a7780b), SPH_C32(0x474000d0), SPH_C32(0x3ea78669), + SPH_C32(0x084621ff), SPH_C32(0xa156d857) }, + { SPH_C32(0xf5a900e0), SPH_C32(0x15c918bb), SPH_C32(0x817de245), + SPH_C32(0xf7ab1816), SPH_C32(0x4a6e00c0), SPH_C32(0xb7ee3980), + SPH_C32(0x8d080a04), SPH_C32(0xb3e8a94e) }, + { SPH_C32(0xa4f500f0), SPH_C32(0x553a6a40), SPH_C32(0x7d9ac447), + SPH_C32(0x86fc4877), SPH_C32(0x645700c0), SPH_C32(0xd3335f09), + SPH_C32(0xb1dc0cf8), SPH_C32(0x021c39f2) }, + { SPH_C32(0xdb9000e0), SPH_C32(0x71147e32), SPH_C32(0xbda9e4b9), + SPH_C32(0x465f88aa), SPH_C32(0x350b00d0), SPH_C32(0x93c02df2), + SPH_C32(0x4d3b2afa), SPH_C32(0x734b6993) }, + { SPH_C32(0x8acc00f0), SPH_C32(0x31e70cc9), SPH_C32(0x414ec2bb), + SPH_C32(0x3708d8cb), SPH_C32(0x1b3200d0), SPH_C32(0xf71d4b7b), + SPH_C32(0x71ef2c06), SPH_C32(0xc2bff92f) }, + { SPH_C32(0x0b6300c0), SPH_C32(0x5d94305f), SPH_C32(0x011aa3b8), + SPH_C32(0x76ed99ae), SPH_C32(0xe8d600e0), SPH_C32(0x3609dc76), + SPH_C32(0x74c64600), SPH_C32(0x5147098e) }, + { SPH_C32(0x5a3f00d0), SPH_C32(0x1d6742a4), SPH_C32(0xfdfd85ba), + SPH_C32(0x07bac9cf), SPH_C32(0xc6ef00e0), SPH_C32(0x52d4baff), + SPH_C32(0x481240fc), SPH_C32(0xe0b39932) }, + { SPH_C32(0x255a00c0), SPH_C32(0x394956d6), SPH_C32(0x3dcea544), + SPH_C32(0xc7190912), SPH_C32(0x97b300f0), SPH_C32(0x1227c804), + SPH_C32(0xb4f566fe), SPH_C32(0x91e4c953) }, + { SPH_C32(0x740600d0), SPH_C32(0x79ba242d), SPH_C32(0xc1298346), + SPH_C32(0xb64e5973), SPH_C32(0xb98a00f0), SPH_C32(0x76faae8d), + SPH_C32(0x88216002), SPH_C32(0x201059ef) }, + { SPH_C32(0xa9db00e0), SPH_C32(0xdc73d5a9), SPH_C32(0xf8d4efbc), + SPH_C32(0x9442396e), SPH_C32(0xb4a400e0), SPH_C32(0xffb31164), + SPH_C32(0x0d6f4bf9), SPH_C32(0x32ae28f6) }, + { SPH_C32(0xf88700f0), SPH_C32(0x9c80a752), SPH_C32(0x0433c9be), + SPH_C32(0xe515690f), SPH_C32(0x9a9d00e0), SPH_C32(0x9b6e77ed), + SPH_C32(0x31bb4d05), SPH_C32(0x835ab84a) }, + { SPH_C32(0x87e200e0), SPH_C32(0xb8aeb320), SPH_C32(0xc400e940), + SPH_C32(0x25b6a9d2), SPH_C32(0xcbc100f0), SPH_C32(0xdb9d0516), + SPH_C32(0xcd5c6b07), SPH_C32(0xf20de82b) }, + { SPH_C32(0xd6be00f0), SPH_C32(0xf85dc1db), SPH_C32(0x38e7cf42), + SPH_C32(0x54e1f9b3), SPH_C32(0xe5f800f0), SPH_C32(0xbf40639f), + SPH_C32(0xf1886dfb), SPH_C32(0x43f97897) } +}; + +static const sph_u32 T256_24[256][8] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000) }, + { SPH_C32(0xc04e0001), SPH_C32(0x33b9c010), SPH_C32(0xae0ebb05), + SPH_C32(0xb5a4c63b), SPH_C32(0xc8f10000), SPH_C32(0x0b2de782), + SPH_C32(0x6bf648a4), SPH_C32(0x539cbdbf) }, + { SPH_C32(0xc8f10000), SPH_C32(0x0b2de782), SPH_C32(0x6bf648a4), + SPH_C32(0x539cbdbf), SPH_C32(0x08bf0001), SPH_C32(0x38942792), + SPH_C32(0xc5f8f3a1), SPH_C32(0xe6387b84) }, + { SPH_C32(0x08bf0001), SPH_C32(0x38942792), SPH_C32(0xc5f8f3a1), + SPH_C32(0xe6387b84), SPH_C32(0xc04e0001), SPH_C32(0x33b9c010), + SPH_C32(0xae0ebb05), SPH_C32(0xb5a4c63b) }, + { SPH_C32(0x88230002), SPH_C32(0x5fe7a7b3), SPH_C32(0x99e585aa), + SPH_C32(0x8d75f7f1), SPH_C32(0x51ac0000), SPH_C32(0x25e30f14), + SPH_C32(0x79e22a4c), SPH_C32(0x1298bd46) }, + { SPH_C32(0x486d0003), SPH_C32(0x6c5e67a3), SPH_C32(0x37eb3eaf), + SPH_C32(0x38d131ca), SPH_C32(0x995d0000), SPH_C32(0x2ecee896), + SPH_C32(0x121462e8), SPH_C32(0x410400f9) }, + { SPH_C32(0x40d20002), SPH_C32(0x54ca4031), SPH_C32(0xf213cd0e), + SPH_C32(0xdee94a4e), SPH_C32(0x59130001), SPH_C32(0x1d772886), + SPH_C32(0xbc1ad9ed), SPH_C32(0xf4a0c6c2) }, + { SPH_C32(0x809c0003), SPH_C32(0x67738021), SPH_C32(0x5c1d760b), + SPH_C32(0x6b4d8c75), SPH_C32(0x91e20001), SPH_C32(0x165acf04), + SPH_C32(0xd7ec9149), SPH_C32(0xa73c7b7d) }, + { SPH_C32(0x51ac0000), SPH_C32(0x25e30f14), SPH_C32(0x79e22a4c), + SPH_C32(0x1298bd46), SPH_C32(0xd98f0002), SPH_C32(0x7a04a8a7), + SPH_C32(0xe007afe6), SPH_C32(0x9fed4ab7) }, + { SPH_C32(0x91e20001), SPH_C32(0x165acf04), SPH_C32(0xd7ec9149), + SPH_C32(0xa73c7b7d), SPH_C32(0x117e0002), SPH_C32(0x71294f25), + SPH_C32(0x8bf1e742), SPH_C32(0xcc71f708) }, + { SPH_C32(0x995d0000), SPH_C32(0x2ecee896), SPH_C32(0x121462e8), + SPH_C32(0x410400f9), SPH_C32(0xd1300003), SPH_C32(0x42908f35), + SPH_C32(0x25ff5c47), SPH_C32(0x79d53133) }, + { SPH_C32(0x59130001), SPH_C32(0x1d772886), SPH_C32(0xbc1ad9ed), + SPH_C32(0xf4a0c6c2), SPH_C32(0x19c10003), SPH_C32(0x49bd68b7), + SPH_C32(0x4e0914e3), SPH_C32(0x2a498c8c) }, + { SPH_C32(0xd98f0002), SPH_C32(0x7a04a8a7), SPH_C32(0xe007afe6), + SPH_C32(0x9fed4ab7), SPH_C32(0x88230002), SPH_C32(0x5fe7a7b3), + SPH_C32(0x99e585aa), SPH_C32(0x8d75f7f1) }, + { SPH_C32(0x19c10003), SPH_C32(0x49bd68b7), SPH_C32(0x4e0914e3), + SPH_C32(0x2a498c8c), SPH_C32(0x40d20002), SPH_C32(0x54ca4031), + SPH_C32(0xf213cd0e), SPH_C32(0xdee94a4e) }, + { SPH_C32(0x117e0002), SPH_C32(0x71294f25), SPH_C32(0x8bf1e742), + SPH_C32(0xcc71f708), SPH_C32(0x809c0003), SPH_C32(0x67738021), + SPH_C32(0x5c1d760b), SPH_C32(0x6b4d8c75) }, + { SPH_C32(0xd1300003), SPH_C32(0x42908f35), SPH_C32(0x25ff5c47), + SPH_C32(0x79d53133), SPH_C32(0x486d0003), SPH_C32(0x6c5e67a3), + SPH_C32(0x37eb3eaf), SPH_C32(0x38d131ca) }, + { SPH_C32(0xd0080004), SPH_C32(0x8c768f77), SPH_C32(0x9dc5b050), + SPH_C32(0xaf4a29da), SPH_C32(0x6ba90000), SPH_C32(0x40ebf9aa), + SPH_C32(0x98321c3d), SPH_C32(0x76acc733) }, + { SPH_C32(0x10460005), SPH_C32(0xbfcf4f67), SPH_C32(0x33cb0b55), + SPH_C32(0x1aeeefe1), SPH_C32(0xa3580000), SPH_C32(0x4bc61e28), + SPH_C32(0xf3c45499), SPH_C32(0x25307a8c) }, + { SPH_C32(0x18f90004), SPH_C32(0x875b68f5), SPH_C32(0xf633f8f4), + SPH_C32(0xfcd69465), SPH_C32(0x63160001), SPH_C32(0x787fde38), + SPH_C32(0x5dcaef9c), SPH_C32(0x9094bcb7) }, + { SPH_C32(0xd8b70005), SPH_C32(0xb4e2a8e5), SPH_C32(0x583d43f1), + SPH_C32(0x4972525e), SPH_C32(0xabe70001), SPH_C32(0x735239ba), + SPH_C32(0x363ca738), SPH_C32(0xc3080108) }, + { SPH_C32(0x582b0006), SPH_C32(0xd39128c4), SPH_C32(0x042035fa), + SPH_C32(0x223fde2b), SPH_C32(0x3a050000), SPH_C32(0x6508f6be), + SPH_C32(0xe1d03671), SPH_C32(0x64347a75) }, + { SPH_C32(0x98650007), SPH_C32(0xe028e8d4), SPH_C32(0xaa2e8eff), + SPH_C32(0x979b1810), SPH_C32(0xf2f40000), SPH_C32(0x6e25113c), + SPH_C32(0x8a267ed5), SPH_C32(0x37a8c7ca) }, + { SPH_C32(0x90da0006), SPH_C32(0xd8bccf46), SPH_C32(0x6fd67d5e), + SPH_C32(0x71a36394), SPH_C32(0x32ba0001), SPH_C32(0x5d9cd12c), + SPH_C32(0x2428c5d0), SPH_C32(0x820c01f1) }, + { SPH_C32(0x50940007), SPH_C32(0xeb050f56), SPH_C32(0xc1d8c65b), + SPH_C32(0xc407a5af), SPH_C32(0xfa4b0001), SPH_C32(0x56b136ae), + SPH_C32(0x4fde8d74), SPH_C32(0xd190bc4e) }, + { SPH_C32(0x81a40004), SPH_C32(0xa9958063), SPH_C32(0xe4279a1c), + SPH_C32(0xbdd2949c), SPH_C32(0xb2260002), SPH_C32(0x3aef510d), + SPH_C32(0x7835b3db), SPH_C32(0xe9418d84) }, + { SPH_C32(0x41ea0005), SPH_C32(0x9a2c4073), SPH_C32(0x4a292119), + SPH_C32(0x087652a7), SPH_C32(0x7ad70002), SPH_C32(0x31c2b68f), + SPH_C32(0x13c3fb7f), SPH_C32(0xbadd303b) }, + { SPH_C32(0x49550004), SPH_C32(0xa2b867e1), SPH_C32(0x8fd1d2b8), + SPH_C32(0xee4e2923), SPH_C32(0xba990003), SPH_C32(0x027b769f), + SPH_C32(0xbdcd407a), SPH_C32(0x0f79f600) }, + { SPH_C32(0x891b0005), SPH_C32(0x9101a7f1), SPH_C32(0x21df69bd), + SPH_C32(0x5beaef18), SPH_C32(0x72680003), SPH_C32(0x0956911d), + SPH_C32(0xd63b08de), SPH_C32(0x5ce54bbf) }, + { SPH_C32(0x09870006), SPH_C32(0xf67227d0), SPH_C32(0x7dc21fb6), + SPH_C32(0x30a7636d), SPH_C32(0xe38a0002), SPH_C32(0x1f0c5e19), + SPH_C32(0x01d79997), SPH_C32(0xfbd930c2) }, + { SPH_C32(0xc9c90007), SPH_C32(0xc5cbe7c0), SPH_C32(0xd3cca4b3), + SPH_C32(0x8503a556), SPH_C32(0x2b7b0002), SPH_C32(0x1421b99b), + SPH_C32(0x6a21d133), SPH_C32(0xa8458d7d) }, + { SPH_C32(0xc1760006), SPH_C32(0xfd5fc052), SPH_C32(0x16345712), + SPH_C32(0x633bded2), SPH_C32(0xeb350003), SPH_C32(0x2798798b), + SPH_C32(0xc42f6a36), SPH_C32(0x1de14b46) }, + { SPH_C32(0x01380007), SPH_C32(0xcee60042), SPH_C32(0xb83aec17), + SPH_C32(0xd69f18e9), SPH_C32(0x23c40003), SPH_C32(0x2cb59e09), + SPH_C32(0xafd92292), SPH_C32(0x4e7df6f9) }, + { SPH_C32(0x6ba90000), SPH_C32(0x40ebf9aa), SPH_C32(0x98321c3d), + SPH_C32(0x76acc733), SPH_C32(0xbba10004), SPH_C32(0xcc9d76dd), + SPH_C32(0x05f7ac6d), SPH_C32(0xd9e6eee9) }, + { SPH_C32(0xabe70001), SPH_C32(0x735239ba), SPH_C32(0x363ca738), + SPH_C32(0xc3080108), SPH_C32(0x73500004), SPH_C32(0xc7b0915f), + SPH_C32(0x6e01e4c9), SPH_C32(0x8a7a5356) }, + { SPH_C32(0xa3580000), SPH_C32(0x4bc61e28), SPH_C32(0xf3c45499), + SPH_C32(0x25307a8c), SPH_C32(0xb31e0005), SPH_C32(0xf409514f), + SPH_C32(0xc00f5fcc), SPH_C32(0x3fde956d) }, + { SPH_C32(0x63160001), SPH_C32(0x787fde38), SPH_C32(0x5dcaef9c), + SPH_C32(0x9094bcb7), SPH_C32(0x7bef0005), SPH_C32(0xff24b6cd), + SPH_C32(0xabf91768), SPH_C32(0x6c4228d2) }, + { SPH_C32(0xe38a0002), SPH_C32(0x1f0c5e19), SPH_C32(0x01d79997), + SPH_C32(0xfbd930c2), SPH_C32(0xea0d0004), SPH_C32(0xe97e79c9), + SPH_C32(0x7c158621), SPH_C32(0xcb7e53af) }, + { SPH_C32(0x23c40003), SPH_C32(0x2cb59e09), SPH_C32(0xafd92292), + SPH_C32(0x4e7df6f9), SPH_C32(0x22fc0004), SPH_C32(0xe2539e4b), + SPH_C32(0x17e3ce85), SPH_C32(0x98e2ee10) }, + { SPH_C32(0x2b7b0002), SPH_C32(0x1421b99b), SPH_C32(0x6a21d133), + SPH_C32(0xa8458d7d), SPH_C32(0xe2b20005), SPH_C32(0xd1ea5e5b), + SPH_C32(0xb9ed7580), SPH_C32(0x2d46282b) }, + { SPH_C32(0xeb350003), SPH_C32(0x2798798b), SPH_C32(0xc42f6a36), + SPH_C32(0x1de14b46), SPH_C32(0x2a430005), SPH_C32(0xdac7b9d9), + SPH_C32(0xd21b3d24), SPH_C32(0x7eda9594) }, + { SPH_C32(0x3a050000), SPH_C32(0x6508f6be), SPH_C32(0xe1d03671), + SPH_C32(0x64347a75), SPH_C32(0x622e0006), SPH_C32(0xb699de7a), + SPH_C32(0xe5f0038b), SPH_C32(0x460ba45e) }, + { SPH_C32(0xfa4b0001), SPH_C32(0x56b136ae), SPH_C32(0x4fde8d74), + SPH_C32(0xd190bc4e), SPH_C32(0xaadf0006), SPH_C32(0xbdb439f8), + SPH_C32(0x8e064b2f), SPH_C32(0x159719e1) }, + { SPH_C32(0xf2f40000), SPH_C32(0x6e25113c), SPH_C32(0x8a267ed5), + SPH_C32(0x37a8c7ca), SPH_C32(0x6a910007), SPH_C32(0x8e0df9e8), + SPH_C32(0x2008f02a), SPH_C32(0xa033dfda) }, + { SPH_C32(0x32ba0001), SPH_C32(0x5d9cd12c), SPH_C32(0x2428c5d0), + SPH_C32(0x820c01f1), SPH_C32(0xa2600007), SPH_C32(0x85201e6a), + SPH_C32(0x4bfeb88e), SPH_C32(0xf3af6265) }, + { SPH_C32(0xb2260002), SPH_C32(0x3aef510d), SPH_C32(0x7835b3db), + SPH_C32(0xe9418d84), SPH_C32(0x33820006), SPH_C32(0x937ad16e), + SPH_C32(0x9c1229c7), SPH_C32(0x54931918) }, + { SPH_C32(0x72680003), SPH_C32(0x0956911d), SPH_C32(0xd63b08de), + SPH_C32(0x5ce54bbf), SPH_C32(0xfb730006), SPH_C32(0x985736ec), + SPH_C32(0xf7e46163), SPH_C32(0x070fa4a7) }, + { SPH_C32(0x7ad70002), SPH_C32(0x31c2b68f), SPH_C32(0x13c3fb7f), + SPH_C32(0xbadd303b), SPH_C32(0x3b3d0007), SPH_C32(0xabeef6fc), + SPH_C32(0x59eada66), SPH_C32(0xb2ab629c) }, + { SPH_C32(0xba990003), SPH_C32(0x027b769f), SPH_C32(0xbdcd407a), + SPH_C32(0x0f79f600), SPH_C32(0xf3cc0007), SPH_C32(0xa0c3117e), + SPH_C32(0x321c92c2), SPH_C32(0xe137df23) }, + { SPH_C32(0xbba10004), SPH_C32(0xcc9d76dd), SPH_C32(0x05f7ac6d), + SPH_C32(0xd9e6eee9), SPH_C32(0xd0080004), SPH_C32(0x8c768f77), + SPH_C32(0x9dc5b050), SPH_C32(0xaf4a29da) }, + { SPH_C32(0x7bef0005), SPH_C32(0xff24b6cd), SPH_C32(0xabf91768), + SPH_C32(0x6c4228d2), SPH_C32(0x18f90004), SPH_C32(0x875b68f5), + SPH_C32(0xf633f8f4), SPH_C32(0xfcd69465) }, + { SPH_C32(0x73500004), SPH_C32(0xc7b0915f), SPH_C32(0x6e01e4c9), + SPH_C32(0x8a7a5356), SPH_C32(0xd8b70005), SPH_C32(0xb4e2a8e5), + SPH_C32(0x583d43f1), SPH_C32(0x4972525e) }, + { SPH_C32(0xb31e0005), SPH_C32(0xf409514f), SPH_C32(0xc00f5fcc), + SPH_C32(0x3fde956d), SPH_C32(0x10460005), SPH_C32(0xbfcf4f67), + SPH_C32(0x33cb0b55), SPH_C32(0x1aeeefe1) }, + { SPH_C32(0x33820006), SPH_C32(0x937ad16e), SPH_C32(0x9c1229c7), + SPH_C32(0x54931918), SPH_C32(0x81a40004), SPH_C32(0xa9958063), + SPH_C32(0xe4279a1c), SPH_C32(0xbdd2949c) }, + { SPH_C32(0xf3cc0007), SPH_C32(0xa0c3117e), SPH_C32(0x321c92c2), + SPH_C32(0xe137df23), SPH_C32(0x49550004), SPH_C32(0xa2b867e1), + SPH_C32(0x8fd1d2b8), SPH_C32(0xee4e2923) }, + { SPH_C32(0xfb730006), SPH_C32(0x985736ec), SPH_C32(0xf7e46163), + SPH_C32(0x070fa4a7), SPH_C32(0x891b0005), SPH_C32(0x9101a7f1), + SPH_C32(0x21df69bd), SPH_C32(0x5beaef18) }, + { SPH_C32(0x3b3d0007), SPH_C32(0xabeef6fc), SPH_C32(0x59eada66), + SPH_C32(0xb2ab629c), SPH_C32(0x41ea0005), SPH_C32(0x9a2c4073), + SPH_C32(0x4a292119), SPH_C32(0x087652a7) }, + { SPH_C32(0xea0d0004), SPH_C32(0xe97e79c9), SPH_C32(0x7c158621), + SPH_C32(0xcb7e53af), SPH_C32(0x09870006), SPH_C32(0xf67227d0), + SPH_C32(0x7dc21fb6), SPH_C32(0x30a7636d) }, + { SPH_C32(0x2a430005), SPH_C32(0xdac7b9d9), SPH_C32(0xd21b3d24), + SPH_C32(0x7eda9594), SPH_C32(0xc1760006), SPH_C32(0xfd5fc052), + SPH_C32(0x16345712), SPH_C32(0x633bded2) }, + { SPH_C32(0x22fc0004), SPH_C32(0xe2539e4b), SPH_C32(0x17e3ce85), + SPH_C32(0x98e2ee10), SPH_C32(0x01380007), SPH_C32(0xcee60042), + SPH_C32(0xb83aec17), SPH_C32(0xd69f18e9) }, + { SPH_C32(0xe2b20005), SPH_C32(0xd1ea5e5b), SPH_C32(0xb9ed7580), + SPH_C32(0x2d46282b), SPH_C32(0xc9c90007), SPH_C32(0xc5cbe7c0), + SPH_C32(0xd3cca4b3), SPH_C32(0x8503a556) }, + { SPH_C32(0x622e0006), SPH_C32(0xb699de7a), SPH_C32(0xe5f0038b), + SPH_C32(0x460ba45e), SPH_C32(0x582b0006), SPH_C32(0xd39128c4), + SPH_C32(0x042035fa), SPH_C32(0x223fde2b) }, + { SPH_C32(0xa2600007), SPH_C32(0x85201e6a), SPH_C32(0x4bfeb88e), + SPH_C32(0xf3af6265), SPH_C32(0x90da0006), SPH_C32(0xd8bccf46), + SPH_C32(0x6fd67d5e), SPH_C32(0x71a36394) }, + { SPH_C32(0xaadf0006), SPH_C32(0xbdb439f8), SPH_C32(0x8e064b2f), + SPH_C32(0x159719e1), SPH_C32(0x50940007), SPH_C32(0xeb050f56), + SPH_C32(0xc1d8c65b), SPH_C32(0xc407a5af) }, + { SPH_C32(0x6a910007), SPH_C32(0x8e0df9e8), SPH_C32(0x2008f02a), + SPH_C32(0xa033dfda), SPH_C32(0x98650007), SPH_C32(0xe028e8d4), + SPH_C32(0xaa2e8eff), SPH_C32(0x979b1810) }, + { SPH_C32(0xa8ae0008), SPH_C32(0x2079397d), SPH_C32(0xfe739301), + SPH_C32(0xb8a92831), SPH_C32(0x171c0000), SPH_C32(0xb26e3344), + SPH_C32(0x9e6a837e), SPH_C32(0x58f8485f) }, + { SPH_C32(0x68e00009), SPH_C32(0x13c0f96d), SPH_C32(0x507d2804), + SPH_C32(0x0d0dee0a), SPH_C32(0xdfed0000), SPH_C32(0xb943d4c6), + SPH_C32(0xf59ccbda), SPH_C32(0x0b64f5e0) }, + { SPH_C32(0x605f0008), SPH_C32(0x2b54deff), SPH_C32(0x9585dba5), + SPH_C32(0xeb35958e), SPH_C32(0x1fa30001), SPH_C32(0x8afa14d6), + SPH_C32(0x5b9270df), SPH_C32(0xbec033db) }, + { SPH_C32(0xa0110009), SPH_C32(0x18ed1eef), SPH_C32(0x3b8b60a0), + SPH_C32(0x5e9153b5), SPH_C32(0xd7520001), SPH_C32(0x81d7f354), + SPH_C32(0x3064387b), SPH_C32(0xed5c8e64) }, + { SPH_C32(0x208d000a), SPH_C32(0x7f9e9ece), SPH_C32(0x679616ab), + SPH_C32(0x35dcdfc0), SPH_C32(0x46b00000), SPH_C32(0x978d3c50), + SPH_C32(0xe788a932), SPH_C32(0x4a60f519) }, + { SPH_C32(0xe0c3000b), SPH_C32(0x4c275ede), SPH_C32(0xc998adae), + SPH_C32(0x807819fb), SPH_C32(0x8e410000), SPH_C32(0x9ca0dbd2), + SPH_C32(0x8c7ee196), SPH_C32(0x19fc48a6) }, + { SPH_C32(0xe87c000a), SPH_C32(0x74b3794c), SPH_C32(0x0c605e0f), + SPH_C32(0x6640627f), SPH_C32(0x4e0f0001), SPH_C32(0xaf191bc2), + SPH_C32(0x22705a93), SPH_C32(0xac588e9d) }, + { SPH_C32(0x2832000b), SPH_C32(0x470ab95c), SPH_C32(0xa26ee50a), + SPH_C32(0xd3e4a444), SPH_C32(0x86fe0001), SPH_C32(0xa434fc40), + SPH_C32(0x49861237), SPH_C32(0xffc43322) }, + { SPH_C32(0xf9020008), SPH_C32(0x059a3669), SPH_C32(0x8791b94d), + SPH_C32(0xaa319577), SPH_C32(0xce930002), SPH_C32(0xc86a9be3), + SPH_C32(0x7e6d2c98), SPH_C32(0xc71502e8) }, + { SPH_C32(0x394c0009), SPH_C32(0x3623f679), SPH_C32(0x299f0248), + SPH_C32(0x1f95534c), SPH_C32(0x06620002), SPH_C32(0xc3477c61), + SPH_C32(0x159b643c), SPH_C32(0x9489bf57) }, + { SPH_C32(0x31f30008), SPH_C32(0x0eb7d1eb), SPH_C32(0xec67f1e9), + SPH_C32(0xf9ad28c8), SPH_C32(0xc62c0003), SPH_C32(0xf0febc71), + SPH_C32(0xbb95df39), SPH_C32(0x212d796c) }, + { SPH_C32(0xf1bd0009), SPH_C32(0x3d0e11fb), SPH_C32(0x42694aec), + SPH_C32(0x4c09eef3), SPH_C32(0x0edd0003), SPH_C32(0xfbd35bf3), + SPH_C32(0xd063979d), SPH_C32(0x72b1c4d3) }, + { SPH_C32(0x7121000a), SPH_C32(0x5a7d91da), SPH_C32(0x1e743ce7), + SPH_C32(0x27446286), SPH_C32(0x9f3f0002), SPH_C32(0xed8994f7), + SPH_C32(0x078f06d4), SPH_C32(0xd58dbfae) }, + { SPH_C32(0xb16f000b), SPH_C32(0x69c451ca), SPH_C32(0xb07a87e2), + SPH_C32(0x92e0a4bd), SPH_C32(0x57ce0002), SPH_C32(0xe6a47375), + SPH_C32(0x6c794e70), SPH_C32(0x86110211) }, + { SPH_C32(0xb9d0000a), SPH_C32(0x51507658), SPH_C32(0x75827443), + SPH_C32(0x74d8df39), SPH_C32(0x97800003), SPH_C32(0xd51db365), + SPH_C32(0xc277f575), SPH_C32(0x33b5c42a) }, + { SPH_C32(0x799e000b), SPH_C32(0x62e9b648), SPH_C32(0xdb8ccf46), + SPH_C32(0xc17c1902), SPH_C32(0x5f710003), SPH_C32(0xde3054e7), + SPH_C32(0xa981bdd1), SPH_C32(0x60297995) }, + { SPH_C32(0x78a6000c), SPH_C32(0xac0fb60a), SPH_C32(0x63b62351), + SPH_C32(0x17e301eb), SPH_C32(0x7cb50000), SPH_C32(0xf285caee), + SPH_C32(0x06589f43), SPH_C32(0x2e548f6c) }, + { SPH_C32(0xb8e8000d), SPH_C32(0x9fb6761a), SPH_C32(0xcdb89854), + SPH_C32(0xa247c7d0), SPH_C32(0xb4440000), SPH_C32(0xf9a82d6c), + SPH_C32(0x6daed7e7), SPH_C32(0x7dc832d3) }, + { SPH_C32(0xb057000c), SPH_C32(0xa7225188), SPH_C32(0x08406bf5), + SPH_C32(0x447fbc54), SPH_C32(0x740a0001), SPH_C32(0xca11ed7c), + SPH_C32(0xc3a06ce2), SPH_C32(0xc86cf4e8) }, + { SPH_C32(0x7019000d), SPH_C32(0x949b9198), SPH_C32(0xa64ed0f0), + SPH_C32(0xf1db7a6f), SPH_C32(0xbcfb0001), SPH_C32(0xc13c0afe), + SPH_C32(0xa8562446), SPH_C32(0x9bf04957) }, + { SPH_C32(0xf085000e), SPH_C32(0xf3e811b9), SPH_C32(0xfa53a6fb), + SPH_C32(0x9a96f61a), SPH_C32(0x2d190000), SPH_C32(0xd766c5fa), + SPH_C32(0x7fbab50f), SPH_C32(0x3ccc322a) }, + { SPH_C32(0x30cb000f), SPH_C32(0xc051d1a9), SPH_C32(0x545d1dfe), + SPH_C32(0x2f323021), SPH_C32(0xe5e80000), SPH_C32(0xdc4b2278), + SPH_C32(0x144cfdab), SPH_C32(0x6f508f95) }, + { SPH_C32(0x3874000e), SPH_C32(0xf8c5f63b), SPH_C32(0x91a5ee5f), + SPH_C32(0xc90a4ba5), SPH_C32(0x25a60001), SPH_C32(0xeff2e268), + SPH_C32(0xba4246ae), SPH_C32(0xdaf449ae) }, + { SPH_C32(0xf83a000f), SPH_C32(0xcb7c362b), SPH_C32(0x3fab555a), + SPH_C32(0x7cae8d9e), SPH_C32(0xed570001), SPH_C32(0xe4df05ea), + SPH_C32(0xd1b40e0a), SPH_C32(0x8968f411) }, + { SPH_C32(0x290a000c), SPH_C32(0x89ecb91e), SPH_C32(0x1a54091d), + SPH_C32(0x057bbcad), SPH_C32(0xa53a0002), SPH_C32(0x88816249), + SPH_C32(0xe65f30a5), SPH_C32(0xb1b9c5db) }, + { SPH_C32(0xe944000d), SPH_C32(0xba55790e), SPH_C32(0xb45ab218), + SPH_C32(0xb0df7a96), SPH_C32(0x6dcb0002), SPH_C32(0x83ac85cb), + SPH_C32(0x8da97801), SPH_C32(0xe2257864) }, + { SPH_C32(0xe1fb000c), SPH_C32(0x82c15e9c), SPH_C32(0x71a241b9), + SPH_C32(0x56e70112), SPH_C32(0xad850003), SPH_C32(0xb01545db), + SPH_C32(0x23a7c304), SPH_C32(0x5781be5f) }, + { SPH_C32(0x21b5000d), SPH_C32(0xb1789e8c), SPH_C32(0xdfacfabc), + SPH_C32(0xe343c729), SPH_C32(0x65740003), SPH_C32(0xbb38a259), + SPH_C32(0x48518ba0), SPH_C32(0x041d03e0) }, + { SPH_C32(0xa129000e), SPH_C32(0xd60b1ead), SPH_C32(0x83b18cb7), + SPH_C32(0x880e4b5c), SPH_C32(0xf4960002), SPH_C32(0xad626d5d), + SPH_C32(0x9fbd1ae9), SPH_C32(0xa321789d) }, + { SPH_C32(0x6167000f), SPH_C32(0xe5b2debd), SPH_C32(0x2dbf37b2), + SPH_C32(0x3daa8d67), SPH_C32(0x3c670002), SPH_C32(0xa64f8adf), + SPH_C32(0xf44b524d), SPH_C32(0xf0bdc522) }, + { SPH_C32(0x69d8000e), SPH_C32(0xdd26f92f), SPH_C32(0xe847c413), + SPH_C32(0xdb92f6e3), SPH_C32(0xfc290003), SPH_C32(0x95f64acf), + SPH_C32(0x5a45e948), SPH_C32(0x45190319) }, + { SPH_C32(0xa996000f), SPH_C32(0xee9f393f), SPH_C32(0x46497f16), + SPH_C32(0x6e3630d8), SPH_C32(0x34d80003), SPH_C32(0x9edbad4d), + SPH_C32(0x31b3a1ec), SPH_C32(0x1685bea6) }, + { SPH_C32(0xc3070008), SPH_C32(0x6092c0d7), SPH_C32(0x66418f3c), + SPH_C32(0xce05ef02), SPH_C32(0xacbd0004), SPH_C32(0x7ef34599), + SPH_C32(0x9b9d2f13), SPH_C32(0x811ea6b6) }, + { SPH_C32(0x03490009), SPH_C32(0x532b00c7), SPH_C32(0xc84f3439), + SPH_C32(0x7ba12939), SPH_C32(0x644c0004), SPH_C32(0x75dea21b), + SPH_C32(0xf06b67b7), SPH_C32(0xd2821b09) }, + { SPH_C32(0x0bf60008), SPH_C32(0x6bbf2755), SPH_C32(0x0db7c798), + SPH_C32(0x9d9952bd), SPH_C32(0xa4020005), SPH_C32(0x4667620b), + SPH_C32(0x5e65dcb2), SPH_C32(0x6726dd32) }, + { SPH_C32(0xcbb80009), SPH_C32(0x5806e745), SPH_C32(0xa3b97c9d), + SPH_C32(0x283d9486), SPH_C32(0x6cf30005), SPH_C32(0x4d4a8589), + SPH_C32(0x35939416), SPH_C32(0x34ba608d) }, + { SPH_C32(0x4b24000a), SPH_C32(0x3f756764), SPH_C32(0xffa40a96), + SPH_C32(0x437018f3), SPH_C32(0xfd110004), SPH_C32(0x5b104a8d), + SPH_C32(0xe27f055f), SPH_C32(0x93861bf0) }, + { SPH_C32(0x8b6a000b), SPH_C32(0x0ccca774), SPH_C32(0x51aab193), + SPH_C32(0xf6d4dec8), SPH_C32(0x35e00004), SPH_C32(0x503dad0f), + SPH_C32(0x89894dfb), SPH_C32(0xc01aa64f) }, + { SPH_C32(0x83d5000a), SPH_C32(0x345880e6), SPH_C32(0x94524232), + SPH_C32(0x10eca54c), SPH_C32(0xf5ae0005), SPH_C32(0x63846d1f), + SPH_C32(0x2787f6fe), SPH_C32(0x75be6074) }, + { SPH_C32(0x439b000b), SPH_C32(0x07e140f6), SPH_C32(0x3a5cf937), + SPH_C32(0xa5486377), SPH_C32(0x3d5f0005), SPH_C32(0x68a98a9d), + SPH_C32(0x4c71be5a), SPH_C32(0x2622ddcb) }, + { SPH_C32(0x92ab0008), SPH_C32(0x4571cfc3), SPH_C32(0x1fa3a570), + SPH_C32(0xdc9d5244), SPH_C32(0x75320006), SPH_C32(0x04f7ed3e), + SPH_C32(0x7b9a80f5), SPH_C32(0x1ef3ec01) }, + { SPH_C32(0x52e50009), SPH_C32(0x76c80fd3), SPH_C32(0xb1ad1e75), + SPH_C32(0x6939947f), SPH_C32(0xbdc30006), SPH_C32(0x0fda0abc), + SPH_C32(0x106cc851), SPH_C32(0x4d6f51be) }, + { SPH_C32(0x5a5a0008), SPH_C32(0x4e5c2841), SPH_C32(0x7455edd4), + SPH_C32(0x8f01effb), SPH_C32(0x7d8d0007), SPH_C32(0x3c63caac), + SPH_C32(0xbe627354), SPH_C32(0xf8cb9785) }, + { SPH_C32(0x9a140009), SPH_C32(0x7de5e851), SPH_C32(0xda5b56d1), + SPH_C32(0x3aa529c0), SPH_C32(0xb57c0007), SPH_C32(0x374e2d2e), + SPH_C32(0xd5943bf0), SPH_C32(0xab572a3a) }, + { SPH_C32(0x1a88000a), SPH_C32(0x1a966870), SPH_C32(0x864620da), + SPH_C32(0x51e8a5b5), SPH_C32(0x249e0006), SPH_C32(0x2114e22a), + SPH_C32(0x0278aab9), SPH_C32(0x0c6b5147) }, + { SPH_C32(0xdac6000b), SPH_C32(0x292fa860), SPH_C32(0x28489bdf), + SPH_C32(0xe44c638e), SPH_C32(0xec6f0006), SPH_C32(0x2a3905a8), + SPH_C32(0x698ee21d), SPH_C32(0x5ff7ecf8) }, + { SPH_C32(0xd279000a), SPH_C32(0x11bb8ff2), SPH_C32(0xedb0687e), + SPH_C32(0x0274180a), SPH_C32(0x2c210007), SPH_C32(0x1980c5b8), + SPH_C32(0xc7805918), SPH_C32(0xea532ac3) }, + { SPH_C32(0x1237000b), SPH_C32(0x22024fe2), SPH_C32(0x43bed37b), + SPH_C32(0xb7d0de31), SPH_C32(0xe4d00007), SPH_C32(0x12ad223a), + SPH_C32(0xac7611bc), SPH_C32(0xb9cf977c) }, + { SPH_C32(0x130f000c), SPH_C32(0xece44fa0), SPH_C32(0xfb843f6c), + SPH_C32(0x614fc6d8), SPH_C32(0xc7140004), SPH_C32(0x3e18bc33), + SPH_C32(0x03af332e), SPH_C32(0xf7b26185) }, + { SPH_C32(0xd341000d), SPH_C32(0xdf5d8fb0), SPH_C32(0x558a8469), + SPH_C32(0xd4eb00e3), SPH_C32(0x0fe50004), SPH_C32(0x35355bb1), + SPH_C32(0x68597b8a), SPH_C32(0xa42edc3a) }, + { SPH_C32(0xdbfe000c), SPH_C32(0xe7c9a822), SPH_C32(0x907277c8), + SPH_C32(0x32d37b67), SPH_C32(0xcfab0005), SPH_C32(0x068c9ba1), + SPH_C32(0xc657c08f), SPH_C32(0x118a1a01) }, + { SPH_C32(0x1bb0000d), SPH_C32(0xd4706832), SPH_C32(0x3e7ccccd), + SPH_C32(0x8777bd5c), SPH_C32(0x075a0005), SPH_C32(0x0da17c23), + SPH_C32(0xada1882b), SPH_C32(0x4216a7be) }, + { SPH_C32(0x9b2c000e), SPH_C32(0xb303e813), SPH_C32(0x6261bac6), + SPH_C32(0xec3a3129), SPH_C32(0x96b80004), SPH_C32(0x1bfbb327), + SPH_C32(0x7a4d1962), SPH_C32(0xe52adcc3) }, + { SPH_C32(0x5b62000f), SPH_C32(0x80ba2803), SPH_C32(0xcc6f01c3), + SPH_C32(0x599ef712), SPH_C32(0x5e490004), SPH_C32(0x10d654a5), + SPH_C32(0x11bb51c6), SPH_C32(0xb6b6617c) }, + { SPH_C32(0x53dd000e), SPH_C32(0xb82e0f91), SPH_C32(0x0997f262), + SPH_C32(0xbfa68c96), SPH_C32(0x9e070005), SPH_C32(0x236f94b5), + SPH_C32(0xbfb5eac3), SPH_C32(0x0312a747) }, + { SPH_C32(0x9393000f), SPH_C32(0x8b97cf81), SPH_C32(0xa7994967), + SPH_C32(0x0a024aad), SPH_C32(0x56f60005), SPH_C32(0x28427337), + SPH_C32(0xd443a267), SPH_C32(0x508e1af8) }, + { SPH_C32(0x42a3000c), SPH_C32(0xc90740b4), SPH_C32(0x82661520), + SPH_C32(0x73d77b9e), SPH_C32(0x1e9b0006), SPH_C32(0x441c1494), + SPH_C32(0xe3a89cc8), SPH_C32(0x685f2b32) }, + { SPH_C32(0x82ed000d), SPH_C32(0xfabe80a4), SPH_C32(0x2c68ae25), + SPH_C32(0xc673bda5), SPH_C32(0xd66a0006), SPH_C32(0x4f31f316), + SPH_C32(0x885ed46c), SPH_C32(0x3bc3968d) }, + { SPH_C32(0x8a52000c), SPH_C32(0xc22aa736), SPH_C32(0xe9905d84), + SPH_C32(0x204bc621), SPH_C32(0x16240007), SPH_C32(0x7c883306), + SPH_C32(0x26506f69), SPH_C32(0x8e6750b6) }, + { SPH_C32(0x4a1c000d), SPH_C32(0xf1936726), SPH_C32(0x479ee681), + SPH_C32(0x95ef001a), SPH_C32(0xded50007), SPH_C32(0x77a5d484), + SPH_C32(0x4da627cd), SPH_C32(0xddfbed09) }, + { SPH_C32(0xca80000e), SPH_C32(0x96e0e707), SPH_C32(0x1b83908a), + SPH_C32(0xfea28c6f), SPH_C32(0x4f370006), SPH_C32(0x61ff1b80), + SPH_C32(0x9a4ab684), SPH_C32(0x7ac79674) }, + { SPH_C32(0x0ace000f), SPH_C32(0xa5592717), SPH_C32(0xb58d2b8f), + SPH_C32(0x4b064a54), SPH_C32(0x87c60006), SPH_C32(0x6ad2fc02), + SPH_C32(0xf1bcfe20), SPH_C32(0x295b2bcb) }, + { SPH_C32(0x0271000e), SPH_C32(0x9dcd0085), SPH_C32(0x7075d82e), + SPH_C32(0xad3e31d0), SPH_C32(0x47880007), SPH_C32(0x596b3c12), + SPH_C32(0x5fb24525), SPH_C32(0x9cffedf0) }, + { SPH_C32(0xc23f000f), SPH_C32(0xae74c095), SPH_C32(0xde7b632b), + SPH_C32(0x189af7eb), SPH_C32(0x8f790007), SPH_C32(0x5246db90), + SPH_C32(0x34440d81), SPH_C32(0xcf63504f) }, + { SPH_C32(0x171c0000), SPH_C32(0xb26e3344), SPH_C32(0x9e6a837e), + SPH_C32(0x58f8485f), SPH_C32(0xbfb20008), SPH_C32(0x92170a39), + SPH_C32(0x6019107f), SPH_C32(0xe051606e) }, + { SPH_C32(0xd7520001), SPH_C32(0x81d7f354), SPH_C32(0x3064387b), + SPH_C32(0xed5c8e64), SPH_C32(0x77430008), SPH_C32(0x993aedbb), + SPH_C32(0x0bef58db), SPH_C32(0xb3cdddd1) }, + { SPH_C32(0xdfed0000), SPH_C32(0xb943d4c6), SPH_C32(0xf59ccbda), + SPH_C32(0x0b64f5e0), SPH_C32(0xb70d0009), SPH_C32(0xaa832dab), + SPH_C32(0xa5e1e3de), SPH_C32(0x06691bea) }, + { SPH_C32(0x1fa30001), SPH_C32(0x8afa14d6), SPH_C32(0x5b9270df), + SPH_C32(0xbec033db), SPH_C32(0x7ffc0009), SPH_C32(0xa1aeca29), + SPH_C32(0xce17ab7a), SPH_C32(0x55f5a655) }, + { SPH_C32(0x9f3f0002), SPH_C32(0xed8994f7), SPH_C32(0x078f06d4), + SPH_C32(0xd58dbfae), SPH_C32(0xee1e0008), SPH_C32(0xb7f4052d), + SPH_C32(0x19fb3a33), SPH_C32(0xf2c9dd28) }, + { SPH_C32(0x5f710003), SPH_C32(0xde3054e7), SPH_C32(0xa981bdd1), + SPH_C32(0x60297995), SPH_C32(0x26ef0008), SPH_C32(0xbcd9e2af), + SPH_C32(0x720d7297), SPH_C32(0xa1556097) }, + { SPH_C32(0x57ce0002), SPH_C32(0xe6a47375), SPH_C32(0x6c794e70), + SPH_C32(0x86110211), SPH_C32(0xe6a10009), SPH_C32(0x8f6022bf), + SPH_C32(0xdc03c992), SPH_C32(0x14f1a6ac) }, + { SPH_C32(0x97800003), SPH_C32(0xd51db365), SPH_C32(0xc277f575), + SPH_C32(0x33b5c42a), SPH_C32(0x2e500009), SPH_C32(0x844dc53d), + SPH_C32(0xb7f58136), SPH_C32(0x476d1b13) }, + { SPH_C32(0x46b00000), SPH_C32(0x978d3c50), SPH_C32(0xe788a932), + SPH_C32(0x4a60f519), SPH_C32(0x663d000a), SPH_C32(0xe813a29e), + SPH_C32(0x801ebf99), SPH_C32(0x7fbc2ad9) }, + { SPH_C32(0x86fe0001), SPH_C32(0xa434fc40), SPH_C32(0x49861237), + SPH_C32(0xffc43322), SPH_C32(0xaecc000a), SPH_C32(0xe33e451c), + SPH_C32(0xebe8f73d), SPH_C32(0x2c209766) }, + { SPH_C32(0x8e410000), SPH_C32(0x9ca0dbd2), SPH_C32(0x8c7ee196), + SPH_C32(0x19fc48a6), SPH_C32(0x6e82000b), SPH_C32(0xd087850c), + SPH_C32(0x45e64c38), SPH_C32(0x9984515d) }, + { SPH_C32(0x4e0f0001), SPH_C32(0xaf191bc2), SPH_C32(0x22705a93), + SPH_C32(0xac588e9d), SPH_C32(0xa673000b), SPH_C32(0xdbaa628e), + SPH_C32(0x2e10049c), SPH_C32(0xca18ece2) }, + { SPH_C32(0xce930002), SPH_C32(0xc86a9be3), SPH_C32(0x7e6d2c98), + SPH_C32(0xc71502e8), SPH_C32(0x3791000a), SPH_C32(0xcdf0ad8a), + SPH_C32(0xf9fc95d5), SPH_C32(0x6d24979f) }, + { SPH_C32(0x0edd0003), SPH_C32(0xfbd35bf3), SPH_C32(0xd063979d), + SPH_C32(0x72b1c4d3), SPH_C32(0xff60000a), SPH_C32(0xc6dd4a08), + SPH_C32(0x920add71), SPH_C32(0x3eb82a20) }, + { SPH_C32(0x06620002), SPH_C32(0xc3477c61), SPH_C32(0x159b643c), + SPH_C32(0x9489bf57), SPH_C32(0x3f2e000b), SPH_C32(0xf5648a18), + SPH_C32(0x3c046674), SPH_C32(0x8b1cec1b) }, + { SPH_C32(0xc62c0003), SPH_C32(0xf0febc71), SPH_C32(0xbb95df39), + SPH_C32(0x212d796c), SPH_C32(0xf7df000b), SPH_C32(0xfe496d9a), + SPH_C32(0x57f22ed0), SPH_C32(0xd88051a4) }, + { SPH_C32(0xc7140004), SPH_C32(0x3e18bc33), SPH_C32(0x03af332e), + SPH_C32(0xf7b26185), SPH_C32(0xd41b0008), SPH_C32(0xd2fcf393), + SPH_C32(0xf82b0c42), SPH_C32(0x96fda75d) }, + { SPH_C32(0x075a0005), SPH_C32(0x0da17c23), SPH_C32(0xada1882b), + SPH_C32(0x4216a7be), SPH_C32(0x1cea0008), SPH_C32(0xd9d11411), + SPH_C32(0x93dd44e6), SPH_C32(0xc5611ae2) }, + { SPH_C32(0x0fe50004), SPH_C32(0x35355bb1), SPH_C32(0x68597b8a), + SPH_C32(0xa42edc3a), SPH_C32(0xdca40009), SPH_C32(0xea68d401), + SPH_C32(0x3dd3ffe3), SPH_C32(0x70c5dcd9) }, + { SPH_C32(0xcfab0005), SPH_C32(0x068c9ba1), SPH_C32(0xc657c08f), + SPH_C32(0x118a1a01), SPH_C32(0x14550009), SPH_C32(0xe1453383), + SPH_C32(0x5625b747), SPH_C32(0x23596166) }, + { SPH_C32(0x4f370006), SPH_C32(0x61ff1b80), SPH_C32(0x9a4ab684), + SPH_C32(0x7ac79674), SPH_C32(0x85b70008), SPH_C32(0xf71ffc87), + SPH_C32(0x81c9260e), SPH_C32(0x84651a1b) }, + { SPH_C32(0x8f790007), SPH_C32(0x5246db90), SPH_C32(0x34440d81), + SPH_C32(0xcf63504f), SPH_C32(0x4d460008), SPH_C32(0xfc321b05), + SPH_C32(0xea3f6eaa), SPH_C32(0xd7f9a7a4) }, + { SPH_C32(0x87c60006), SPH_C32(0x6ad2fc02), SPH_C32(0xf1bcfe20), + SPH_C32(0x295b2bcb), SPH_C32(0x8d080009), SPH_C32(0xcf8bdb15), + SPH_C32(0x4431d5af), SPH_C32(0x625d619f) }, + { SPH_C32(0x47880007), SPH_C32(0x596b3c12), SPH_C32(0x5fb24525), + SPH_C32(0x9cffedf0), SPH_C32(0x45f90009), SPH_C32(0xc4a63c97), + SPH_C32(0x2fc79d0b), SPH_C32(0x31c1dc20) }, + { SPH_C32(0x96b80004), SPH_C32(0x1bfbb327), SPH_C32(0x7a4d1962), + SPH_C32(0xe52adcc3), SPH_C32(0x0d94000a), SPH_C32(0xa8f85b34), + SPH_C32(0x182ca3a4), SPH_C32(0x0910edea) }, + { SPH_C32(0x56f60005), SPH_C32(0x28427337), SPH_C32(0xd443a267), + SPH_C32(0x508e1af8), SPH_C32(0xc565000a), SPH_C32(0xa3d5bcb6), + SPH_C32(0x73daeb00), SPH_C32(0x5a8c5055) }, + { SPH_C32(0x5e490004), SPH_C32(0x10d654a5), SPH_C32(0x11bb51c6), + SPH_C32(0xb6b6617c), SPH_C32(0x052b000b), SPH_C32(0x906c7ca6), + SPH_C32(0xddd45005), SPH_C32(0xef28966e) }, + { SPH_C32(0x9e070005), SPH_C32(0x236f94b5), SPH_C32(0xbfb5eac3), + SPH_C32(0x0312a747), SPH_C32(0xcdda000b), SPH_C32(0x9b419b24), + SPH_C32(0xb62218a1), SPH_C32(0xbcb42bd1) }, + { SPH_C32(0x1e9b0006), SPH_C32(0x441c1494), SPH_C32(0xe3a89cc8), + SPH_C32(0x685f2b32), SPH_C32(0x5c38000a), SPH_C32(0x8d1b5420), + SPH_C32(0x61ce89e8), SPH_C32(0x1b8850ac) }, + { SPH_C32(0xded50007), SPH_C32(0x77a5d484), SPH_C32(0x4da627cd), + SPH_C32(0xddfbed09), SPH_C32(0x94c9000a), SPH_C32(0x8636b3a2), + SPH_C32(0x0a38c14c), SPH_C32(0x4814ed13) }, + { SPH_C32(0xd66a0006), SPH_C32(0x4f31f316), SPH_C32(0x885ed46c), + SPH_C32(0x3bc3968d), SPH_C32(0x5487000b), SPH_C32(0xb58f73b2), + SPH_C32(0xa4367a49), SPH_C32(0xfdb02b28) }, + { SPH_C32(0x16240007), SPH_C32(0x7c883306), SPH_C32(0x26506f69), + SPH_C32(0x8e6750b6), SPH_C32(0x9c76000b), SPH_C32(0xbea29430), + SPH_C32(0xcfc032ed), SPH_C32(0xae2c9697) }, + { SPH_C32(0x7cb50000), SPH_C32(0xf285caee), SPH_C32(0x06589f43), + SPH_C32(0x2e548f6c), SPH_C32(0x0413000c), SPH_C32(0x5e8a7ce4), + SPH_C32(0x65eebc12), SPH_C32(0x39b78e87) }, + { SPH_C32(0xbcfb0001), SPH_C32(0xc13c0afe), SPH_C32(0xa8562446), + SPH_C32(0x9bf04957), SPH_C32(0xcce2000c), SPH_C32(0x55a79b66), + SPH_C32(0x0e18f4b6), SPH_C32(0x6a2b3338) }, + { SPH_C32(0xb4440000), SPH_C32(0xf9a82d6c), SPH_C32(0x6daed7e7), + SPH_C32(0x7dc832d3), SPH_C32(0x0cac000d), SPH_C32(0x661e5b76), + SPH_C32(0xa0164fb3), SPH_C32(0xdf8ff503) }, + { SPH_C32(0x740a0001), SPH_C32(0xca11ed7c), SPH_C32(0xc3a06ce2), + SPH_C32(0xc86cf4e8), SPH_C32(0xc45d000d), SPH_C32(0x6d33bcf4), + SPH_C32(0xcbe00717), SPH_C32(0x8c1348bc) }, + { SPH_C32(0xf4960002), SPH_C32(0xad626d5d), SPH_C32(0x9fbd1ae9), + SPH_C32(0xa321789d), SPH_C32(0x55bf000c), SPH_C32(0x7b6973f0), + SPH_C32(0x1c0c965e), SPH_C32(0x2b2f33c1) }, + { SPH_C32(0x34d80003), SPH_C32(0x9edbad4d), SPH_C32(0x31b3a1ec), + SPH_C32(0x1685bea6), SPH_C32(0x9d4e000c), SPH_C32(0x70449472), + SPH_C32(0x77fadefa), SPH_C32(0x78b38e7e) }, + { SPH_C32(0x3c670002), SPH_C32(0xa64f8adf), SPH_C32(0xf44b524d), + SPH_C32(0xf0bdc522), SPH_C32(0x5d00000d), SPH_C32(0x43fd5462), + SPH_C32(0xd9f465ff), SPH_C32(0xcd174845) }, + { SPH_C32(0xfc290003), SPH_C32(0x95f64acf), SPH_C32(0x5a45e948), + SPH_C32(0x45190319), SPH_C32(0x95f1000d), SPH_C32(0x48d0b3e0), + SPH_C32(0xb2022d5b), SPH_C32(0x9e8bf5fa) }, + { SPH_C32(0x2d190000), SPH_C32(0xd766c5fa), SPH_C32(0x7fbab50f), + SPH_C32(0x3ccc322a), SPH_C32(0xdd9c000e), SPH_C32(0x248ed443), + SPH_C32(0x85e913f4), SPH_C32(0xa65ac430) }, + { SPH_C32(0xed570001), SPH_C32(0xe4df05ea), SPH_C32(0xd1b40e0a), + SPH_C32(0x8968f411), SPH_C32(0x156d000e), SPH_C32(0x2fa333c1), + SPH_C32(0xee1f5b50), SPH_C32(0xf5c6798f) }, + { SPH_C32(0xe5e80000), SPH_C32(0xdc4b2278), SPH_C32(0x144cfdab), + SPH_C32(0x6f508f95), SPH_C32(0xd523000f), SPH_C32(0x1c1af3d1), + SPH_C32(0x4011e055), SPH_C32(0x4062bfb4) }, + { SPH_C32(0x25a60001), SPH_C32(0xeff2e268), SPH_C32(0xba4246ae), + SPH_C32(0xdaf449ae), SPH_C32(0x1dd2000f), SPH_C32(0x17371453), + SPH_C32(0x2be7a8f1), SPH_C32(0x13fe020b) }, + { SPH_C32(0xa53a0002), SPH_C32(0x88816249), SPH_C32(0xe65f30a5), + SPH_C32(0xb1b9c5db), SPH_C32(0x8c30000e), SPH_C32(0x016ddb57), + SPH_C32(0xfc0b39b8), SPH_C32(0xb4c27976) }, + { SPH_C32(0x65740003), SPH_C32(0xbb38a259), SPH_C32(0x48518ba0), + SPH_C32(0x041d03e0), SPH_C32(0x44c1000e), SPH_C32(0x0a403cd5), + SPH_C32(0x97fd711c), SPH_C32(0xe75ec4c9) }, + { SPH_C32(0x6dcb0002), SPH_C32(0x83ac85cb), SPH_C32(0x8da97801), + SPH_C32(0xe2257864), SPH_C32(0x848f000f), SPH_C32(0x39f9fcc5), + SPH_C32(0x39f3ca19), SPH_C32(0x52fa02f2) }, + { SPH_C32(0xad850003), SPH_C32(0xb01545db), SPH_C32(0x23a7c304), + SPH_C32(0x5781be5f), SPH_C32(0x4c7e000f), SPH_C32(0x32d41b47), + SPH_C32(0x520582bd), SPH_C32(0x0166bf4d) }, + { SPH_C32(0xacbd0004), SPH_C32(0x7ef34599), SPH_C32(0x9b9d2f13), + SPH_C32(0x811ea6b6), SPH_C32(0x6fba000c), SPH_C32(0x1e61854e), + SPH_C32(0xfddca02f), SPH_C32(0x4f1b49b4) }, + { SPH_C32(0x6cf30005), SPH_C32(0x4d4a8589), SPH_C32(0x35939416), + SPH_C32(0x34ba608d), SPH_C32(0xa74b000c), SPH_C32(0x154c62cc), + SPH_C32(0x962ae88b), SPH_C32(0x1c87f40b) }, + { SPH_C32(0x644c0004), SPH_C32(0x75dea21b), SPH_C32(0xf06b67b7), + SPH_C32(0xd2821b09), SPH_C32(0x6705000d), SPH_C32(0x26f5a2dc), + SPH_C32(0x3824538e), SPH_C32(0xa9233230) }, + { SPH_C32(0xa4020005), SPH_C32(0x4667620b), SPH_C32(0x5e65dcb2), + SPH_C32(0x6726dd32), SPH_C32(0xaff4000d), SPH_C32(0x2dd8455e), + SPH_C32(0x53d21b2a), SPH_C32(0xfabf8f8f) }, + { SPH_C32(0x249e0006), SPH_C32(0x2114e22a), SPH_C32(0x0278aab9), + SPH_C32(0x0c6b5147), SPH_C32(0x3e16000c), SPH_C32(0x3b828a5a), + SPH_C32(0x843e8a63), SPH_C32(0x5d83f4f2) }, + { SPH_C32(0xe4d00007), SPH_C32(0x12ad223a), SPH_C32(0xac7611bc), + SPH_C32(0xb9cf977c), SPH_C32(0xf6e7000c), SPH_C32(0x30af6dd8), + SPH_C32(0xefc8c2c7), SPH_C32(0x0e1f494d) }, + { SPH_C32(0xec6f0006), SPH_C32(0x2a3905a8), SPH_C32(0x698ee21d), + SPH_C32(0x5ff7ecf8), SPH_C32(0x36a9000d), SPH_C32(0x0316adc8), + SPH_C32(0x41c679c2), SPH_C32(0xbbbb8f76) }, + { SPH_C32(0x2c210007), SPH_C32(0x1980c5b8), SPH_C32(0xc7805918), + SPH_C32(0xea532ac3), SPH_C32(0xfe58000d), SPH_C32(0x083b4a4a), + SPH_C32(0x2a303166), SPH_C32(0xe82732c9) }, + { SPH_C32(0xfd110004), SPH_C32(0x5b104a8d), SPH_C32(0xe27f055f), + SPH_C32(0x93861bf0), SPH_C32(0xb635000e), SPH_C32(0x64652de9), + SPH_C32(0x1ddb0fc9), SPH_C32(0xd0f60303) }, + { SPH_C32(0x3d5f0005), SPH_C32(0x68a98a9d), SPH_C32(0x4c71be5a), + SPH_C32(0x2622ddcb), SPH_C32(0x7ec4000e), SPH_C32(0x6f48ca6b), + SPH_C32(0x762d476d), SPH_C32(0x836abebc) }, + { SPH_C32(0x35e00004), SPH_C32(0x503dad0f), SPH_C32(0x89894dfb), + SPH_C32(0xc01aa64f), SPH_C32(0xbe8a000f), SPH_C32(0x5cf10a7b), + SPH_C32(0xd823fc68), SPH_C32(0x36ce7887) }, + { SPH_C32(0xf5ae0005), SPH_C32(0x63846d1f), SPH_C32(0x2787f6fe), + SPH_C32(0x75be6074), SPH_C32(0x767b000f), SPH_C32(0x57dcedf9), + SPH_C32(0xb3d5b4cc), SPH_C32(0x6552c538) }, + { SPH_C32(0x75320006), SPH_C32(0x04f7ed3e), SPH_C32(0x7b9a80f5), + SPH_C32(0x1ef3ec01), SPH_C32(0xe799000e), SPH_C32(0x418622fd), + SPH_C32(0x64392585), SPH_C32(0xc26ebe45) }, + { SPH_C32(0xb57c0007), SPH_C32(0x374e2d2e), SPH_C32(0xd5943bf0), + SPH_C32(0xab572a3a), SPH_C32(0x2f68000e), SPH_C32(0x4aabc57f), + SPH_C32(0x0fcf6d21), SPH_C32(0x91f203fa) }, + { SPH_C32(0xbdc30006), SPH_C32(0x0fda0abc), SPH_C32(0x106cc851), + SPH_C32(0x4d6f51be), SPH_C32(0xef26000f), SPH_C32(0x7912056f), + SPH_C32(0xa1c1d624), SPH_C32(0x2456c5c1) }, + { SPH_C32(0x7d8d0007), SPH_C32(0x3c63caac), SPH_C32(0xbe627354), + SPH_C32(0xf8cb9785), SPH_C32(0x27d7000f), SPH_C32(0x723fe2ed), + SPH_C32(0xca379e80), SPH_C32(0x77ca787e) }, + { SPH_C32(0xbfb20008), SPH_C32(0x92170a39), SPH_C32(0x6019107f), + SPH_C32(0xe051606e), SPH_C32(0xa8ae0008), SPH_C32(0x2079397d), + SPH_C32(0xfe739301), SPH_C32(0xb8a92831) }, + { SPH_C32(0x7ffc0009), SPH_C32(0xa1aeca29), SPH_C32(0xce17ab7a), + SPH_C32(0x55f5a655), SPH_C32(0x605f0008), SPH_C32(0x2b54deff), + SPH_C32(0x9585dba5), SPH_C32(0xeb35958e) }, + { SPH_C32(0x77430008), SPH_C32(0x993aedbb), SPH_C32(0x0bef58db), + SPH_C32(0xb3cdddd1), SPH_C32(0xa0110009), SPH_C32(0x18ed1eef), + SPH_C32(0x3b8b60a0), SPH_C32(0x5e9153b5) }, + { SPH_C32(0xb70d0009), SPH_C32(0xaa832dab), SPH_C32(0xa5e1e3de), + SPH_C32(0x06691bea), SPH_C32(0x68e00009), SPH_C32(0x13c0f96d), + SPH_C32(0x507d2804), SPH_C32(0x0d0dee0a) }, + { SPH_C32(0x3791000a), SPH_C32(0xcdf0ad8a), SPH_C32(0xf9fc95d5), + SPH_C32(0x6d24979f), SPH_C32(0xf9020008), SPH_C32(0x059a3669), + SPH_C32(0x8791b94d), SPH_C32(0xaa319577) }, + { SPH_C32(0xf7df000b), SPH_C32(0xfe496d9a), SPH_C32(0x57f22ed0), + SPH_C32(0xd88051a4), SPH_C32(0x31f30008), SPH_C32(0x0eb7d1eb), + SPH_C32(0xec67f1e9), SPH_C32(0xf9ad28c8) }, + { SPH_C32(0xff60000a), SPH_C32(0xc6dd4a08), SPH_C32(0x920add71), + SPH_C32(0x3eb82a20), SPH_C32(0xf1bd0009), SPH_C32(0x3d0e11fb), + SPH_C32(0x42694aec), SPH_C32(0x4c09eef3) }, + { SPH_C32(0x3f2e000b), SPH_C32(0xf5648a18), SPH_C32(0x3c046674), + SPH_C32(0x8b1cec1b), SPH_C32(0x394c0009), SPH_C32(0x3623f679), + SPH_C32(0x299f0248), SPH_C32(0x1f95534c) }, + { SPH_C32(0xee1e0008), SPH_C32(0xb7f4052d), SPH_C32(0x19fb3a33), + SPH_C32(0xf2c9dd28), SPH_C32(0x7121000a), SPH_C32(0x5a7d91da), + SPH_C32(0x1e743ce7), SPH_C32(0x27446286) }, + { SPH_C32(0x2e500009), SPH_C32(0x844dc53d), SPH_C32(0xb7f58136), + SPH_C32(0x476d1b13), SPH_C32(0xb9d0000a), SPH_C32(0x51507658), + SPH_C32(0x75827443), SPH_C32(0x74d8df39) }, + { SPH_C32(0x26ef0008), SPH_C32(0xbcd9e2af), SPH_C32(0x720d7297), + SPH_C32(0xa1556097), SPH_C32(0x799e000b), SPH_C32(0x62e9b648), + SPH_C32(0xdb8ccf46), SPH_C32(0xc17c1902) }, + { SPH_C32(0xe6a10009), SPH_C32(0x8f6022bf), SPH_C32(0xdc03c992), + SPH_C32(0x14f1a6ac), SPH_C32(0xb16f000b), SPH_C32(0x69c451ca), + SPH_C32(0xb07a87e2), SPH_C32(0x92e0a4bd) }, + { SPH_C32(0x663d000a), SPH_C32(0xe813a29e), SPH_C32(0x801ebf99), + SPH_C32(0x7fbc2ad9), SPH_C32(0x208d000a), SPH_C32(0x7f9e9ece), + SPH_C32(0x679616ab), SPH_C32(0x35dcdfc0) }, + { SPH_C32(0xa673000b), SPH_C32(0xdbaa628e), SPH_C32(0x2e10049c), + SPH_C32(0xca18ece2), SPH_C32(0xe87c000a), SPH_C32(0x74b3794c), + SPH_C32(0x0c605e0f), SPH_C32(0x6640627f) }, + { SPH_C32(0xaecc000a), SPH_C32(0xe33e451c), SPH_C32(0xebe8f73d), + SPH_C32(0x2c209766), SPH_C32(0x2832000b), SPH_C32(0x470ab95c), + SPH_C32(0xa26ee50a), SPH_C32(0xd3e4a444) }, + { SPH_C32(0x6e82000b), SPH_C32(0xd087850c), SPH_C32(0x45e64c38), + SPH_C32(0x9984515d), SPH_C32(0xe0c3000b), SPH_C32(0x4c275ede), + SPH_C32(0xc998adae), SPH_C32(0x807819fb) }, + { SPH_C32(0x6fba000c), SPH_C32(0x1e61854e), SPH_C32(0xfddca02f), + SPH_C32(0x4f1b49b4), SPH_C32(0xc3070008), SPH_C32(0x6092c0d7), + SPH_C32(0x66418f3c), SPH_C32(0xce05ef02) }, + { SPH_C32(0xaff4000d), SPH_C32(0x2dd8455e), SPH_C32(0x53d21b2a), + SPH_C32(0xfabf8f8f), SPH_C32(0x0bf60008), SPH_C32(0x6bbf2755), + SPH_C32(0x0db7c798), SPH_C32(0x9d9952bd) }, + { SPH_C32(0xa74b000c), SPH_C32(0x154c62cc), SPH_C32(0x962ae88b), + SPH_C32(0x1c87f40b), SPH_C32(0xcbb80009), SPH_C32(0x5806e745), + SPH_C32(0xa3b97c9d), SPH_C32(0x283d9486) }, + { SPH_C32(0x6705000d), SPH_C32(0x26f5a2dc), SPH_C32(0x3824538e), + SPH_C32(0xa9233230), SPH_C32(0x03490009), SPH_C32(0x532b00c7), + SPH_C32(0xc84f3439), SPH_C32(0x7ba12939) }, + { SPH_C32(0xe799000e), SPH_C32(0x418622fd), SPH_C32(0x64392585), + SPH_C32(0xc26ebe45), SPH_C32(0x92ab0008), SPH_C32(0x4571cfc3), + SPH_C32(0x1fa3a570), SPH_C32(0xdc9d5244) }, + { SPH_C32(0x27d7000f), SPH_C32(0x723fe2ed), SPH_C32(0xca379e80), + SPH_C32(0x77ca787e), SPH_C32(0x5a5a0008), SPH_C32(0x4e5c2841), + SPH_C32(0x7455edd4), SPH_C32(0x8f01effb) }, + { SPH_C32(0x2f68000e), SPH_C32(0x4aabc57f), SPH_C32(0x0fcf6d21), + SPH_C32(0x91f203fa), SPH_C32(0x9a140009), SPH_C32(0x7de5e851), + SPH_C32(0xda5b56d1), SPH_C32(0x3aa529c0) }, + { SPH_C32(0xef26000f), SPH_C32(0x7912056f), SPH_C32(0xa1c1d624), + SPH_C32(0x2456c5c1), SPH_C32(0x52e50009), SPH_C32(0x76c80fd3), + SPH_C32(0xb1ad1e75), SPH_C32(0x6939947f) }, + { SPH_C32(0x3e16000c), SPH_C32(0x3b828a5a), SPH_C32(0x843e8a63), + SPH_C32(0x5d83f4f2), SPH_C32(0x1a88000a), SPH_C32(0x1a966870), + SPH_C32(0x864620da), SPH_C32(0x51e8a5b5) }, + { SPH_C32(0xfe58000d), SPH_C32(0x083b4a4a), SPH_C32(0x2a303166), + SPH_C32(0xe82732c9), SPH_C32(0xd279000a), SPH_C32(0x11bb8ff2), + SPH_C32(0xedb0687e), SPH_C32(0x0274180a) }, + { SPH_C32(0xf6e7000c), SPH_C32(0x30af6dd8), SPH_C32(0xefc8c2c7), + SPH_C32(0x0e1f494d), SPH_C32(0x1237000b), SPH_C32(0x22024fe2), + SPH_C32(0x43bed37b), SPH_C32(0xb7d0de31) }, + { SPH_C32(0x36a9000d), SPH_C32(0x0316adc8), SPH_C32(0x41c679c2), + SPH_C32(0xbbbb8f76), SPH_C32(0xdac6000b), SPH_C32(0x292fa860), + SPH_C32(0x28489bdf), SPH_C32(0xe44c638e) }, + { SPH_C32(0xb635000e), SPH_C32(0x64652de9), SPH_C32(0x1ddb0fc9), + SPH_C32(0xd0f60303), SPH_C32(0x4b24000a), SPH_C32(0x3f756764), + SPH_C32(0xffa40a96), SPH_C32(0x437018f3) }, + { SPH_C32(0x767b000f), SPH_C32(0x57dcedf9), SPH_C32(0xb3d5b4cc), + SPH_C32(0x6552c538), SPH_C32(0x83d5000a), SPH_C32(0x345880e6), + SPH_C32(0x94524232), SPH_C32(0x10eca54c) }, + { SPH_C32(0x7ec4000e), SPH_C32(0x6f48ca6b), SPH_C32(0x762d476d), + SPH_C32(0x836abebc), SPH_C32(0x439b000b), SPH_C32(0x07e140f6), + SPH_C32(0x3a5cf937), SPH_C32(0xa5486377) }, + { SPH_C32(0xbe8a000f), SPH_C32(0x5cf10a7b), SPH_C32(0xd823fc68), + SPH_C32(0x36ce7887), SPH_C32(0x8b6a000b), SPH_C32(0x0ccca774), + SPH_C32(0x51aab193), SPH_C32(0xf6d4dec8) }, + { SPH_C32(0xd41b0008), SPH_C32(0xd2fcf393), SPH_C32(0xf82b0c42), + SPH_C32(0x96fda75d), SPH_C32(0x130f000c), SPH_C32(0xece44fa0), + SPH_C32(0xfb843f6c), SPH_C32(0x614fc6d8) }, + { SPH_C32(0x14550009), SPH_C32(0xe1453383), SPH_C32(0x5625b747), + SPH_C32(0x23596166), SPH_C32(0xdbfe000c), SPH_C32(0xe7c9a822), + SPH_C32(0x907277c8), SPH_C32(0x32d37b67) }, + { SPH_C32(0x1cea0008), SPH_C32(0xd9d11411), SPH_C32(0x93dd44e6), + SPH_C32(0xc5611ae2), SPH_C32(0x1bb0000d), SPH_C32(0xd4706832), + SPH_C32(0x3e7ccccd), SPH_C32(0x8777bd5c) }, + { SPH_C32(0xdca40009), SPH_C32(0xea68d401), SPH_C32(0x3dd3ffe3), + SPH_C32(0x70c5dcd9), SPH_C32(0xd341000d), SPH_C32(0xdf5d8fb0), + SPH_C32(0x558a8469), SPH_C32(0xd4eb00e3) }, + { SPH_C32(0x5c38000a), SPH_C32(0x8d1b5420), SPH_C32(0x61ce89e8), + SPH_C32(0x1b8850ac), SPH_C32(0x42a3000c), SPH_C32(0xc90740b4), + SPH_C32(0x82661520), SPH_C32(0x73d77b9e) }, + { SPH_C32(0x9c76000b), SPH_C32(0xbea29430), SPH_C32(0xcfc032ed), + SPH_C32(0xae2c9697), SPH_C32(0x8a52000c), SPH_C32(0xc22aa736), + SPH_C32(0xe9905d84), SPH_C32(0x204bc621) }, + { SPH_C32(0x94c9000a), SPH_C32(0x8636b3a2), SPH_C32(0x0a38c14c), + SPH_C32(0x4814ed13), SPH_C32(0x4a1c000d), SPH_C32(0xf1936726), + SPH_C32(0x479ee681), SPH_C32(0x95ef001a) }, + { SPH_C32(0x5487000b), SPH_C32(0xb58f73b2), SPH_C32(0xa4367a49), + SPH_C32(0xfdb02b28), SPH_C32(0x82ed000d), SPH_C32(0xfabe80a4), + SPH_C32(0x2c68ae25), SPH_C32(0xc673bda5) }, + { SPH_C32(0x85b70008), SPH_C32(0xf71ffc87), SPH_C32(0x81c9260e), + SPH_C32(0x84651a1b), SPH_C32(0xca80000e), SPH_C32(0x96e0e707), + SPH_C32(0x1b83908a), SPH_C32(0xfea28c6f) }, + { SPH_C32(0x45f90009), SPH_C32(0xc4a63c97), SPH_C32(0x2fc79d0b), + SPH_C32(0x31c1dc20), SPH_C32(0x0271000e), SPH_C32(0x9dcd0085), + SPH_C32(0x7075d82e), SPH_C32(0xad3e31d0) }, + { SPH_C32(0x4d460008), SPH_C32(0xfc321b05), SPH_C32(0xea3f6eaa), + SPH_C32(0xd7f9a7a4), SPH_C32(0xc23f000f), SPH_C32(0xae74c095), + SPH_C32(0xde7b632b), SPH_C32(0x189af7eb) }, + { SPH_C32(0x8d080009), SPH_C32(0xcf8bdb15), SPH_C32(0x4431d5af), + SPH_C32(0x625d619f), SPH_C32(0x0ace000f), SPH_C32(0xa5592717), + SPH_C32(0xb58d2b8f), SPH_C32(0x4b064a54) }, + { SPH_C32(0x0d94000a), SPH_C32(0xa8f85b34), SPH_C32(0x182ca3a4), + SPH_C32(0x0910edea), SPH_C32(0x9b2c000e), SPH_C32(0xb303e813), + SPH_C32(0x6261bac6), SPH_C32(0xec3a3129) }, + { SPH_C32(0xcdda000b), SPH_C32(0x9b419b24), SPH_C32(0xb62218a1), + SPH_C32(0xbcb42bd1), SPH_C32(0x53dd000e), SPH_C32(0xb82e0f91), + SPH_C32(0x0997f262), SPH_C32(0xbfa68c96) }, + { SPH_C32(0xc565000a), SPH_C32(0xa3d5bcb6), SPH_C32(0x73daeb00), + SPH_C32(0x5a8c5055), SPH_C32(0x9393000f), SPH_C32(0x8b97cf81), + SPH_C32(0xa7994967), SPH_C32(0x0a024aad) }, + { SPH_C32(0x052b000b), SPH_C32(0x906c7ca6), SPH_C32(0xddd45005), + SPH_C32(0xef28966e), SPH_C32(0x5b62000f), SPH_C32(0x80ba2803), + SPH_C32(0xcc6f01c3), SPH_C32(0x599ef712) }, + { SPH_C32(0x0413000c), SPH_C32(0x5e8a7ce4), SPH_C32(0x65eebc12), + SPH_C32(0x39b78e87), SPH_C32(0x78a6000c), SPH_C32(0xac0fb60a), + SPH_C32(0x63b62351), SPH_C32(0x17e301eb) }, + { SPH_C32(0xc45d000d), SPH_C32(0x6d33bcf4), SPH_C32(0xcbe00717), + SPH_C32(0x8c1348bc), SPH_C32(0xb057000c), SPH_C32(0xa7225188), + SPH_C32(0x08406bf5), SPH_C32(0x447fbc54) }, + { SPH_C32(0xcce2000c), SPH_C32(0x55a79b66), SPH_C32(0x0e18f4b6), + SPH_C32(0x6a2b3338), SPH_C32(0x7019000d), SPH_C32(0x949b9198), + SPH_C32(0xa64ed0f0), SPH_C32(0xf1db7a6f) }, + { SPH_C32(0x0cac000d), SPH_C32(0x661e5b76), SPH_C32(0xa0164fb3), + SPH_C32(0xdf8ff503), SPH_C32(0xb8e8000d), SPH_C32(0x9fb6761a), + SPH_C32(0xcdb89854), SPH_C32(0xa247c7d0) }, + { SPH_C32(0x8c30000e), SPH_C32(0x016ddb57), SPH_C32(0xfc0b39b8), + SPH_C32(0xb4c27976), SPH_C32(0x290a000c), SPH_C32(0x89ecb91e), + SPH_C32(0x1a54091d), SPH_C32(0x057bbcad) }, + { SPH_C32(0x4c7e000f), SPH_C32(0x32d41b47), SPH_C32(0x520582bd), + SPH_C32(0x0166bf4d), SPH_C32(0xe1fb000c), SPH_C32(0x82c15e9c), + SPH_C32(0x71a241b9), SPH_C32(0x56e70112) }, + { SPH_C32(0x44c1000e), SPH_C32(0x0a403cd5), SPH_C32(0x97fd711c), + SPH_C32(0xe75ec4c9), SPH_C32(0x21b5000d), SPH_C32(0xb1789e8c), + SPH_C32(0xdfacfabc), SPH_C32(0xe343c729) }, + { SPH_C32(0x848f000f), SPH_C32(0x39f9fcc5), SPH_C32(0x39f3ca19), + SPH_C32(0x52fa02f2), SPH_C32(0xe944000d), SPH_C32(0xba55790e), + SPH_C32(0xb45ab218), SPH_C32(0xb0df7a96) }, + { SPH_C32(0x55bf000c), SPH_C32(0x7b6973f0), SPH_C32(0x1c0c965e), + SPH_C32(0x2b2f33c1), SPH_C32(0xa129000e), SPH_C32(0xd60b1ead), + SPH_C32(0x83b18cb7), SPH_C32(0x880e4b5c) }, + { SPH_C32(0x95f1000d), SPH_C32(0x48d0b3e0), SPH_C32(0xb2022d5b), + SPH_C32(0x9e8bf5fa), SPH_C32(0x69d8000e), SPH_C32(0xdd26f92f), + SPH_C32(0xe847c413), SPH_C32(0xdb92f6e3) }, + { SPH_C32(0x9d4e000c), SPH_C32(0x70449472), SPH_C32(0x77fadefa), + SPH_C32(0x78b38e7e), SPH_C32(0xa996000f), SPH_C32(0xee9f393f), + SPH_C32(0x46497f16), SPH_C32(0x6e3630d8) }, + { SPH_C32(0x5d00000d), SPH_C32(0x43fd5462), SPH_C32(0xd9f465ff), + SPH_C32(0xcd174845), SPH_C32(0x6167000f), SPH_C32(0xe5b2debd), + SPH_C32(0x2dbf37b2), SPH_C32(0x3daa8d67) }, + { SPH_C32(0xdd9c000e), SPH_C32(0x248ed443), SPH_C32(0x85e913f4), + SPH_C32(0xa65ac430), SPH_C32(0xf085000e), SPH_C32(0xf3e811b9), + SPH_C32(0xfa53a6fb), SPH_C32(0x9a96f61a) }, + { SPH_C32(0x1dd2000f), SPH_C32(0x17371453), SPH_C32(0x2be7a8f1), + SPH_C32(0x13fe020b), SPH_C32(0x3874000e), SPH_C32(0xf8c5f63b), + SPH_C32(0x91a5ee5f), SPH_C32(0xc90a4ba5) }, + { SPH_C32(0x156d000e), SPH_C32(0x2fa333c1), SPH_C32(0xee1f5b50), + SPH_C32(0xf5c6798f), SPH_C32(0xf83a000f), SPH_C32(0xcb7c362b), + SPH_C32(0x3fab555a), SPH_C32(0x7cae8d9e) }, + { SPH_C32(0xd523000f), SPH_C32(0x1c1af3d1), SPH_C32(0x4011e055), + SPH_C32(0x4062bfb4), SPH_C32(0x30cb000f), SPH_C32(0xc051d1a9), + SPH_C32(0x545d1dfe), SPH_C32(0x2f323021) } +}; + +#define INPUT_SMALL do { \ + unsigned acc = buf[0]; \ + const sph_u32 *rp; \ + rp = &T256_0[acc][0]; \ + m0 = rp[0]; \ + m1 = rp[1]; \ + m2 = rp[2]; \ + m3 = rp[3]; \ + m4 = rp[4]; \ + m5 = rp[5]; \ + m6 = rp[6]; \ + m7 = rp[7]; \ + acc = buf[1]; \ + rp = &T256_8[acc][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + acc = buf[2]; \ + rp = &T256_16[acc][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + acc = buf[3]; \ + rp = &T256_24[acc][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + } while (0) + +#endif + +#if SPH_HAMSI_EXPAND_BIG == 1 + +/* Note: this table lists bits within each byte from least + siginificant to most significant. */ +static const sph_u32 T512[64][16] = { + { SPH_C32(0xef0b0270), SPH_C32(0x3afd0000), SPH_C32(0x5dae0000), + SPH_C32(0x69490000), SPH_C32(0x9b0f3c06), SPH_C32(0x4405b5f9), + SPH_C32(0x66140a51), SPH_C32(0x924f5d0a), SPH_C32(0xc96b0030), + SPH_C32(0xe7250000), SPH_C32(0x2f840000), SPH_C32(0x264f0000), + SPH_C32(0x08695bf9), SPH_C32(0x6dfcf137), SPH_C32(0x509f6984), + SPH_C32(0x9e69af68) }, + { SPH_C32(0xc96b0030), SPH_C32(0xe7250000), SPH_C32(0x2f840000), + SPH_C32(0x264f0000), SPH_C32(0x08695bf9), SPH_C32(0x6dfcf137), + SPH_C32(0x509f6984), SPH_C32(0x9e69af68), SPH_C32(0x26600240), + SPH_C32(0xddd80000), SPH_C32(0x722a0000), SPH_C32(0x4f060000), + SPH_C32(0x936667ff), SPH_C32(0x29f944ce), SPH_C32(0x368b63d5), + SPH_C32(0x0c26f262) }, + { SPH_C32(0x145a3c00), SPH_C32(0xb9e90000), SPH_C32(0x61270000), + SPH_C32(0xf1610000), SPH_C32(0xce613d6c), SPH_C32(0xb0493d78), + SPH_C32(0x47a96720), SPH_C32(0xe18e24c5), SPH_C32(0x23671400), + SPH_C32(0xc8b90000), SPH_C32(0xf4c70000), SPH_C32(0xfb750000), + SPH_C32(0x73cd2465), SPH_C32(0xf8a6a549), SPH_C32(0x02c40a3f), + SPH_C32(0xdc24e61f) }, + { SPH_C32(0x23671400), SPH_C32(0xc8b90000), SPH_C32(0xf4c70000), + SPH_C32(0xfb750000), SPH_C32(0x73cd2465), SPH_C32(0xf8a6a549), + SPH_C32(0x02c40a3f), SPH_C32(0xdc24e61f), SPH_C32(0x373d2800), + SPH_C32(0x71500000), SPH_C32(0x95e00000), SPH_C32(0x0a140000), + SPH_C32(0xbdac1909), SPH_C32(0x48ef9831), SPH_C32(0x456d6d1f), + SPH_C32(0x3daac2da) }, + { SPH_C32(0x54285c00), SPH_C32(0xeaed0000), SPH_C32(0xc5d60000), + SPH_C32(0xa1c50000), SPH_C32(0xb3a26770), SPH_C32(0x94a5c4e1), + SPH_C32(0x6bb0419d), SPH_C32(0x551b3782), SPH_C32(0x9cbb1800), + SPH_C32(0xb0d30000), SPH_C32(0x92510000), SPH_C32(0xed930000), + SPH_C32(0x593a4345), SPH_C32(0xe114d5f4), SPH_C32(0x430633da), + SPH_C32(0x78cace29) }, + { SPH_C32(0x9cbb1800), SPH_C32(0xb0d30000), SPH_C32(0x92510000), + SPH_C32(0xed930000), SPH_C32(0x593a4345), SPH_C32(0xe114d5f4), + SPH_C32(0x430633da), SPH_C32(0x78cace29), SPH_C32(0xc8934400), + SPH_C32(0x5a3e0000), SPH_C32(0x57870000), SPH_C32(0x4c560000), + SPH_C32(0xea982435), SPH_C32(0x75b11115), SPH_C32(0x28b67247), + SPH_C32(0x2dd1f9ab) }, + { SPH_C32(0x29449c00), SPH_C32(0x64e70000), SPH_C32(0xf24b0000), + SPH_C32(0xc2f30000), SPH_C32(0x0ede4e8f), SPH_C32(0x56c23745), + SPH_C32(0xf3e04259), SPH_C32(0x8d0d9ec4), SPH_C32(0x466d0c00), + SPH_C32(0x08620000), SPH_C32(0xdd5d0000), SPH_C32(0xbadd0000), + SPH_C32(0x6a927942), SPH_C32(0x441f2b93), SPH_C32(0x218ace6f), + SPH_C32(0xbf2c0be2) }, + { SPH_C32(0x466d0c00), SPH_C32(0x08620000), SPH_C32(0xdd5d0000), + SPH_C32(0xbadd0000), SPH_C32(0x6a927942), SPH_C32(0x441f2b93), + SPH_C32(0x218ace6f), SPH_C32(0xbf2c0be2), SPH_C32(0x6f299000), + SPH_C32(0x6c850000), SPH_C32(0x2f160000), SPH_C32(0x782e0000), + SPH_C32(0x644c37cd), SPH_C32(0x12dd1cd6), SPH_C32(0xd26a8c36), + SPH_C32(0x32219526) }, + { SPH_C32(0xf6800005), SPH_C32(0x3443c000), SPH_C32(0x24070000), + SPH_C32(0x8f3d0000), SPH_C32(0x21373bfb), SPH_C32(0x0ab8d5ae), + SPH_C32(0xcdc58b19), SPH_C32(0xd795ba31), SPH_C32(0xa67f0001), + SPH_C32(0x71378000), SPH_C32(0x19fc0000), SPH_C32(0x96db0000), + SPH_C32(0x3a8b6dfd), SPH_C32(0xebcaaef3), SPH_C32(0x2c6d478f), + SPH_C32(0xac8e6c88) }, + { SPH_C32(0xa67f0001), SPH_C32(0x71378000), SPH_C32(0x19fc0000), + SPH_C32(0x96db0000), SPH_C32(0x3a8b6dfd), SPH_C32(0xebcaaef3), + SPH_C32(0x2c6d478f), SPH_C32(0xac8e6c88), SPH_C32(0x50ff0004), + SPH_C32(0x45744000), SPH_C32(0x3dfb0000), SPH_C32(0x19e60000), + SPH_C32(0x1bbc5606), SPH_C32(0xe1727b5d), SPH_C32(0xe1a8cc96), + SPH_C32(0x7b1bd6b9) }, + { SPH_C32(0xf7750009), SPH_C32(0xcf3cc000), SPH_C32(0xc3d60000), + SPH_C32(0x04920000), SPH_C32(0x029519a9), SPH_C32(0xf8e836ba), + SPH_C32(0x7a87f14e), SPH_C32(0x9e16981a), SPH_C32(0xd46a0000), + SPH_C32(0x8dc8c000), SPH_C32(0xa5af0000), SPH_C32(0x4a290000), + SPH_C32(0xfc4e427a), SPH_C32(0xc9b4866c), SPH_C32(0x98369604), + SPH_C32(0xf746c320) }, + { SPH_C32(0xd46a0000), SPH_C32(0x8dc8c000), SPH_C32(0xa5af0000), + SPH_C32(0x4a290000), SPH_C32(0xfc4e427a), SPH_C32(0xc9b4866c), + SPH_C32(0x98369604), SPH_C32(0xf746c320), SPH_C32(0x231f0009), + SPH_C32(0x42f40000), SPH_C32(0x66790000), SPH_C32(0x4ebb0000), + SPH_C32(0xfedb5bd3), SPH_C32(0x315cb0d6), SPH_C32(0xe2b1674a), + SPH_C32(0x69505b3a) }, + { SPH_C32(0x774400f0), SPH_C32(0xf15a0000), SPH_C32(0xf5b20000), + SPH_C32(0x34140000), SPH_C32(0x89377e8c), SPH_C32(0x5a8bec25), + SPH_C32(0x0bc3cd1e), SPH_C32(0xcf3775cb), SPH_C32(0xf46c0050), + SPH_C32(0x96180000), SPH_C32(0x14a50000), SPH_C32(0x031f0000), + SPH_C32(0x42947eb8), SPH_C32(0x66bf7e19), SPH_C32(0x9ca470d2), + SPH_C32(0x8a341574) }, + { SPH_C32(0xf46c0050), SPH_C32(0x96180000), SPH_C32(0x14a50000), + SPH_C32(0x031f0000), SPH_C32(0x42947eb8), SPH_C32(0x66bf7e19), + SPH_C32(0x9ca470d2), SPH_C32(0x8a341574), SPH_C32(0x832800a0), + SPH_C32(0x67420000), SPH_C32(0xe1170000), SPH_C32(0x370b0000), + SPH_C32(0xcba30034), SPH_C32(0x3c34923c), SPH_C32(0x9767bdcc), + SPH_C32(0x450360bf) }, + { SPH_C32(0xe8870170), SPH_C32(0x9d720000), SPH_C32(0x12db0000), + SPH_C32(0xd4220000), SPH_C32(0xf2886b27), SPH_C32(0xa921e543), + SPH_C32(0x4ef8b518), SPH_C32(0x618813b1), SPH_C32(0xb4370060), + SPH_C32(0x0c4c0000), SPH_C32(0x56c20000), SPH_C32(0x5cae0000), + SPH_C32(0x94541f3f), SPH_C32(0x3b3ef825), SPH_C32(0x1b365f3d), + SPH_C32(0xf3d45758) }, + { SPH_C32(0xb4370060), SPH_C32(0x0c4c0000), SPH_C32(0x56c20000), + SPH_C32(0x5cae0000), SPH_C32(0x94541f3f), SPH_C32(0x3b3ef825), + SPH_C32(0x1b365f3d), SPH_C32(0xf3d45758), SPH_C32(0x5cb00110), + SPH_C32(0x913e0000), SPH_C32(0x44190000), SPH_C32(0x888c0000), + SPH_C32(0x66dc7418), SPH_C32(0x921f1d66), SPH_C32(0x55ceea25), + SPH_C32(0x925c44e9) }, + { SPH_C32(0x0c720000), SPH_C32(0x49e50f00), SPH_C32(0x42790000), + SPH_C32(0x5cea0000), SPH_C32(0x33aa301a), SPH_C32(0x15822514), + SPH_C32(0x95a34b7b), SPH_C32(0xb44b0090), SPH_C32(0xfe220000), + SPH_C32(0xa7580500), SPH_C32(0x25d10000), SPH_C32(0xf7600000), + SPH_C32(0x893178da), SPH_C32(0x1fd4f860), SPH_C32(0x4ed0a315), + SPH_C32(0xa123ff9f) }, + { SPH_C32(0xfe220000), SPH_C32(0xa7580500), SPH_C32(0x25d10000), + SPH_C32(0xf7600000), SPH_C32(0x893178da), SPH_C32(0x1fd4f860), + SPH_C32(0x4ed0a315), SPH_C32(0xa123ff9f), SPH_C32(0xf2500000), + SPH_C32(0xeebd0a00), SPH_C32(0x67a80000), SPH_C32(0xab8a0000), + SPH_C32(0xba9b48c0), SPH_C32(0x0a56dd74), SPH_C32(0xdb73e86e), + SPH_C32(0x1568ff0f) }, + { SPH_C32(0x45180000), SPH_C32(0xa5b51700), SPH_C32(0xf96a0000), + SPH_C32(0x3b480000), SPH_C32(0x1ecc142c), SPH_C32(0x231395d6), + SPH_C32(0x16bca6b0), SPH_C32(0xdf33f4df), SPH_C32(0xb83d0000), + SPH_C32(0x16710600), SPH_C32(0x379a0000), SPH_C32(0xf5b10000), + SPH_C32(0x228161ac), SPH_C32(0xae48f145), SPH_C32(0x66241616), + SPH_C32(0xc5c1eb3e) }, + { SPH_C32(0xb83d0000), SPH_C32(0x16710600), SPH_C32(0x379a0000), + SPH_C32(0xf5b10000), SPH_C32(0x228161ac), SPH_C32(0xae48f145), + SPH_C32(0x66241616), SPH_C32(0xc5c1eb3e), SPH_C32(0xfd250000), + SPH_C32(0xb3c41100), SPH_C32(0xcef00000), SPH_C32(0xcef90000), + SPH_C32(0x3c4d7580), SPH_C32(0x8d5b6493), SPH_C32(0x7098b0a6), + SPH_C32(0x1af21fe1) }, + { SPH_C32(0x75a40000), SPH_C32(0xc28b2700), SPH_C32(0x94a40000), + SPH_C32(0x90f50000), SPH_C32(0xfb7857e0), SPH_C32(0x49ce0bae), + SPH_C32(0x1767c483), SPH_C32(0xaedf667e), SPH_C32(0xd1660000), + SPH_C32(0x1bbc0300), SPH_C32(0x9eec0000), SPH_C32(0xf6940000), + SPH_C32(0x03024527), SPH_C32(0xcf70fcf2), SPH_C32(0xb4431b17), + SPH_C32(0x857f3c2b) }, + { SPH_C32(0xd1660000), SPH_C32(0x1bbc0300), SPH_C32(0x9eec0000), + SPH_C32(0xf6940000), SPH_C32(0x03024527), SPH_C32(0xcf70fcf2), + SPH_C32(0xb4431b17), SPH_C32(0x857f3c2b), SPH_C32(0xa4c20000), + SPH_C32(0xd9372400), SPH_C32(0x0a480000), SPH_C32(0x66610000), + SPH_C32(0xf87a12c7), SPH_C32(0x86bef75c), SPH_C32(0xa324df94), + SPH_C32(0x2ba05a55) }, + { SPH_C32(0x75c90003), SPH_C32(0x0e10c000), SPH_C32(0xd1200000), + SPH_C32(0xbaea0000), SPH_C32(0x8bc42f3e), SPH_C32(0x8758b757), + SPH_C32(0xbb28761d), SPH_C32(0x00b72e2b), SPH_C32(0xeecf0001), + SPH_C32(0x6f564000), SPH_C32(0xf33e0000), SPH_C32(0xa79e0000), + SPH_C32(0xbdb57219), SPH_C32(0xb711ebc5), SPH_C32(0x4a3b40ba), + SPH_C32(0xfeabf254) }, + { SPH_C32(0xeecf0001), SPH_C32(0x6f564000), SPH_C32(0xf33e0000), + SPH_C32(0xa79e0000), SPH_C32(0xbdb57219), SPH_C32(0xb711ebc5), + SPH_C32(0x4a3b40ba), SPH_C32(0xfeabf254), SPH_C32(0x9b060002), + SPH_C32(0x61468000), SPH_C32(0x221e0000), SPH_C32(0x1d740000), + SPH_C32(0x36715d27), SPH_C32(0x30495c92), SPH_C32(0xf11336a7), + SPH_C32(0xfe1cdc7f) }, + { SPH_C32(0x86790000), SPH_C32(0x3f390002), SPH_C32(0xe19ae000), + SPH_C32(0x98560000), SPH_C32(0x9565670e), SPH_C32(0x4e88c8ea), + SPH_C32(0xd3dd4944), SPH_C32(0x161ddab9), SPH_C32(0x30b70000), + SPH_C32(0xe5d00000), SPH_C32(0xf4f46000), SPH_C32(0x42c40000), + SPH_C32(0x63b83d6a), SPH_C32(0x78ba9460), SPH_C32(0x21afa1ea), + SPH_C32(0xb0a51834) }, + { SPH_C32(0x30b70000), SPH_C32(0xe5d00000), SPH_C32(0xf4f46000), + SPH_C32(0x42c40000), SPH_C32(0x63b83d6a), SPH_C32(0x78ba9460), + SPH_C32(0x21afa1ea), SPH_C32(0xb0a51834), SPH_C32(0xb6ce0000), + SPH_C32(0xdae90002), SPH_C32(0x156e8000), SPH_C32(0xda920000), + SPH_C32(0xf6dd5a64), SPH_C32(0x36325c8a), SPH_C32(0xf272e8ae), + SPH_C32(0xa6b8c28d) }, + { SPH_C32(0x14190000), SPH_C32(0x23ca003c), SPH_C32(0x50df0000), + SPH_C32(0x44b60000), SPH_C32(0x1b6c67b0), SPH_C32(0x3cf3ac75), + SPH_C32(0x61e610b0), SPH_C32(0xdbcadb80), SPH_C32(0xe3430000), + SPH_C32(0x3a4e0014), SPH_C32(0xf2c60000), SPH_C32(0xaa4e0000), + SPH_C32(0xdb1e42a6), SPH_C32(0x256bbe15), SPH_C32(0x123db156), + SPH_C32(0x3a4e99d7) }, + { SPH_C32(0xe3430000), SPH_C32(0x3a4e0014), SPH_C32(0xf2c60000), + SPH_C32(0xaa4e0000), SPH_C32(0xdb1e42a6), SPH_C32(0x256bbe15), + SPH_C32(0x123db156), SPH_C32(0x3a4e99d7), SPH_C32(0xf75a0000), + SPH_C32(0x19840028), SPH_C32(0xa2190000), SPH_C32(0xeef80000), + SPH_C32(0xc0722516), SPH_C32(0x19981260), SPH_C32(0x73dba1e6), + SPH_C32(0xe1844257) }, + { SPH_C32(0x54500000), SPH_C32(0x0671005c), SPH_C32(0x25ae0000), + SPH_C32(0x6a1e0000), SPH_C32(0x2ea54edf), SPH_C32(0x664e8512), + SPH_C32(0xbfba18c3), SPH_C32(0x7e715d17), SPH_C32(0xbc8d0000), + SPH_C32(0xfc3b0018), SPH_C32(0x19830000), SPH_C32(0xd10b0000), + SPH_C32(0xae1878c4), SPH_C32(0x42a69856), SPH_C32(0x0012da37), + SPH_C32(0x2c3b504e) }, + { SPH_C32(0xbc8d0000), SPH_C32(0xfc3b0018), SPH_C32(0x19830000), + SPH_C32(0xd10b0000), SPH_C32(0xae1878c4), SPH_C32(0x42a69856), + SPH_C32(0x0012da37), SPH_C32(0x2c3b504e), SPH_C32(0xe8dd0000), + SPH_C32(0xfa4a0044), SPH_C32(0x3c2d0000), SPH_C32(0xbb150000), + SPH_C32(0x80bd361b), SPH_C32(0x24e81d44), SPH_C32(0xbfa8c2f4), + SPH_C32(0x524a0d59) }, + { SPH_C32(0x69510000), SPH_C32(0xd4e1009c), SPH_C32(0xc3230000), + SPH_C32(0xac2f0000), SPH_C32(0xe4950bae), SPH_C32(0xcea415dc), + SPH_C32(0x87ec287c), SPH_C32(0xbce1a3ce), SPH_C32(0xc6730000), + SPH_C32(0xaf8d000c), SPH_C32(0xa4c10000), SPH_C32(0x218d0000), + SPH_C32(0x23111587), SPH_C32(0x7913512f), SPH_C32(0x1d28ac88), + SPH_C32(0x378dd173) }, + { SPH_C32(0xc6730000), SPH_C32(0xaf8d000c), SPH_C32(0xa4c10000), + SPH_C32(0x218d0000), SPH_C32(0x23111587), SPH_C32(0x7913512f), + SPH_C32(0x1d28ac88), SPH_C32(0x378dd173), SPH_C32(0xaf220000), + SPH_C32(0x7b6c0090), SPH_C32(0x67e20000), SPH_C32(0x8da20000), + SPH_C32(0xc7841e29), SPH_C32(0xb7b744f3), SPH_C32(0x9ac484f4), + SPH_C32(0x8b6c72bd) }, + { SPH_C32(0xcc140000), SPH_C32(0xa5630000), SPH_C32(0x5ab90780), + SPH_C32(0x3b500000), SPH_C32(0x4bd013ff), SPH_C32(0x879b3418), + SPH_C32(0x694348c1), SPH_C32(0xca5a87fe), SPH_C32(0x819e0000), + SPH_C32(0xec570000), SPH_C32(0x66320280), SPH_C32(0x95f30000), + SPH_C32(0x5da92802), SPH_C32(0x48f43cbc), SPH_C32(0xe65aa22d), + SPH_C32(0x8e67b7fa) }, + { SPH_C32(0x819e0000), SPH_C32(0xec570000), SPH_C32(0x66320280), + SPH_C32(0x95f30000), SPH_C32(0x5da92802), SPH_C32(0x48f43cbc), + SPH_C32(0xe65aa22d), SPH_C32(0x8e67b7fa), SPH_C32(0x4d8a0000), + SPH_C32(0x49340000), SPH_C32(0x3c8b0500), SPH_C32(0xaea30000), + SPH_C32(0x16793bfd), SPH_C32(0xcf6f08a4), SPH_C32(0x8f19eaec), + SPH_C32(0x443d3004) }, + { SPH_C32(0x78230000), SPH_C32(0x12fc0000), SPH_C32(0xa93a0b80), + SPH_C32(0x90a50000), SPH_C32(0x713e2879), SPH_C32(0x7ee98924), + SPH_C32(0xf08ca062), SPH_C32(0x636f8bab), SPH_C32(0x02af0000), + SPH_C32(0xb7280000), SPH_C32(0xba1c0300), SPH_C32(0x56980000), + SPH_C32(0xba8d45d3), SPH_C32(0x8048c667), SPH_C32(0xa95c149a), + SPH_C32(0xf4f6ea7b) }, + { SPH_C32(0x02af0000), SPH_C32(0xb7280000), SPH_C32(0xba1c0300), + SPH_C32(0x56980000), SPH_C32(0xba8d45d3), SPH_C32(0x8048c667), + SPH_C32(0xa95c149a), SPH_C32(0xf4f6ea7b), SPH_C32(0x7a8c0000), + SPH_C32(0xa5d40000), SPH_C32(0x13260880), SPH_C32(0xc63d0000), + SPH_C32(0xcbb36daa), SPH_C32(0xfea14f43), SPH_C32(0x59d0b4f8), + SPH_C32(0x979961d0) }, + { SPH_C32(0xac480000), SPH_C32(0x1ba60000), SPH_C32(0x45fb1380), + SPH_C32(0x03430000), SPH_C32(0x5a85316a), SPH_C32(0x1fb250b6), + SPH_C32(0xfe72c7fe), SPH_C32(0x91e478f6), SPH_C32(0x1e4e0000), + SPH_C32(0xdecf0000), SPH_C32(0x6df80180), SPH_C32(0x77240000), + SPH_C32(0xec47079e), SPH_C32(0xf4a0694e), SPH_C32(0xcda31812), + SPH_C32(0x98aa496e) }, + { SPH_C32(0x1e4e0000), SPH_C32(0xdecf0000), SPH_C32(0x6df80180), + SPH_C32(0x77240000), SPH_C32(0xec47079e), SPH_C32(0xf4a0694e), + SPH_C32(0xcda31812), SPH_C32(0x98aa496e), SPH_C32(0xb2060000), + SPH_C32(0xc5690000), SPH_C32(0x28031200), SPH_C32(0x74670000), + SPH_C32(0xb6c236f4), SPH_C32(0xeb1239f8), SPH_C32(0x33d1dfec), + SPH_C32(0x094e3198) }, + { SPH_C32(0xaec30000), SPH_C32(0x9c4f0001), SPH_C32(0x79d1e000), + SPH_C32(0x2c150000), SPH_C32(0x45cc75b3), SPH_C32(0x6650b736), + SPH_C32(0xab92f78f), SPH_C32(0xa312567b), SPH_C32(0xdb250000), + SPH_C32(0x09290000), SPH_C32(0x49aac000), SPH_C32(0x81e10000), + SPH_C32(0xcafe6b59), SPH_C32(0x42793431), SPH_C32(0x43566b76), + SPH_C32(0xe86cba2e) }, + { SPH_C32(0xdb250000), SPH_C32(0x09290000), SPH_C32(0x49aac000), + SPH_C32(0x81e10000), SPH_C32(0xcafe6b59), SPH_C32(0x42793431), + SPH_C32(0x43566b76), SPH_C32(0xe86cba2e), SPH_C32(0x75e60000), + SPH_C32(0x95660001), SPH_C32(0x307b2000), SPH_C32(0xadf40000), + SPH_C32(0x8f321eea), SPH_C32(0x24298307), SPH_C32(0xe8c49cf9), + SPH_C32(0x4b7eec55) }, + { SPH_C32(0x58430000), SPH_C32(0x807e0000), SPH_C32(0x78330001), + SPH_C32(0xc66b3800), SPH_C32(0xe7375cdc), SPH_C32(0x79ad3fdd), + SPH_C32(0xac73fe6f), SPH_C32(0x3a4479b1), SPH_C32(0x1d5a0000), + SPH_C32(0x2b720000), SPH_C32(0x488d0000), SPH_C32(0xaf611800), + SPH_C32(0x25cb2ec5), SPH_C32(0xc879bfd0), SPH_C32(0x81a20429), + SPH_C32(0x1e7536a6) }, + { SPH_C32(0x1d5a0000), SPH_C32(0x2b720000), SPH_C32(0x488d0000), + SPH_C32(0xaf611800), SPH_C32(0x25cb2ec5), SPH_C32(0xc879bfd0), + SPH_C32(0x81a20429), SPH_C32(0x1e7536a6), SPH_C32(0x45190000), + SPH_C32(0xab0c0000), SPH_C32(0x30be0001), SPH_C32(0x690a2000), + SPH_C32(0xc2fc7219), SPH_C32(0xb1d4800d), SPH_C32(0x2dd1fa46), + SPH_C32(0x24314f17) }, + { SPH_C32(0xa53b0000), SPH_C32(0x14260000), SPH_C32(0x4e30001e), + SPH_C32(0x7cae0000), SPH_C32(0x8f9e0dd5), SPH_C32(0x78dfaa3d), + SPH_C32(0xf73168d8), SPH_C32(0x0b1b4946), SPH_C32(0x07ed0000), + SPH_C32(0xb2500000), SPH_C32(0x8774000a), SPH_C32(0x970d0000), + SPH_C32(0x437223ae), SPH_C32(0x48c76ea4), SPH_C32(0xf4786222), + SPH_C32(0x9075b1ce) }, + { SPH_C32(0x07ed0000), SPH_C32(0xb2500000), SPH_C32(0x8774000a), + SPH_C32(0x970d0000), SPH_C32(0x437223ae), SPH_C32(0x48c76ea4), + SPH_C32(0xf4786222), SPH_C32(0x9075b1ce), SPH_C32(0xa2d60000), + SPH_C32(0xa6760000), SPH_C32(0xc9440014), SPH_C32(0xeba30000), + SPH_C32(0xccec2e7b), SPH_C32(0x3018c499), SPH_C32(0x03490afa), + SPH_C32(0x9b6ef888) }, + { SPH_C32(0x88980000), SPH_C32(0x1f940000), SPH_C32(0x7fcf002e), + SPH_C32(0xfb4e0000), SPH_C32(0xf158079a), SPH_C32(0x61ae9167), + SPH_C32(0xa895706c), SPH_C32(0xe6107494), SPH_C32(0x0bc20000), + SPH_C32(0xdb630000), SPH_C32(0x7e88000c), SPH_C32(0x15860000), + SPH_C32(0x91fd48f3), SPH_C32(0x7581bb43), SPH_C32(0xf460449e), + SPH_C32(0xd8b61463) }, + { SPH_C32(0x0bc20000), SPH_C32(0xdb630000), SPH_C32(0x7e88000c), + SPH_C32(0x15860000), SPH_C32(0x91fd48f3), SPH_C32(0x7581bb43), + SPH_C32(0xf460449e), SPH_C32(0xd8b61463), SPH_C32(0x835a0000), + SPH_C32(0xc4f70000), SPH_C32(0x01470022), SPH_C32(0xeec80000), + SPH_C32(0x60a54f69), SPH_C32(0x142f2a24), SPH_C32(0x5cf534f2), + SPH_C32(0x3ea660f7) }, + { SPH_C32(0x52500000), SPH_C32(0x29540000), SPH_C32(0x6a61004e), + SPH_C32(0xf0ff0000), SPH_C32(0x9a317eec), SPH_C32(0x452341ce), + SPH_C32(0xcf568fe5), SPH_C32(0x5303130f), SPH_C32(0x538d0000), + SPH_C32(0xa9fc0000), SPH_C32(0x9ef70006), SPH_C32(0x56ff0000), + SPH_C32(0x0ae4004e), SPH_C32(0x92c5cdf9), SPH_C32(0xa9444018), + SPH_C32(0x7f975691) }, + { SPH_C32(0x538d0000), SPH_C32(0xa9fc0000), SPH_C32(0x9ef70006), + SPH_C32(0x56ff0000), SPH_C32(0x0ae4004e), SPH_C32(0x92c5cdf9), + SPH_C32(0xa9444018), SPH_C32(0x7f975691), SPH_C32(0x01dd0000), + SPH_C32(0x80a80000), SPH_C32(0xf4960048), SPH_C32(0xa6000000), + SPH_C32(0x90d57ea2), SPH_C32(0xd7e68c37), SPH_C32(0x6612cffd), + SPH_C32(0x2c94459e) }, + { SPH_C32(0xe6280000), SPH_C32(0x4c4b0000), SPH_C32(0xa8550000), + SPH_C32(0xd3d002e0), SPH_C32(0xd86130b8), SPH_C32(0x98a7b0da), + SPH_C32(0x289506b4), SPH_C32(0xd75a4897), SPH_C32(0xf0c50000), + SPH_C32(0x59230000), SPH_C32(0x45820000), SPH_C32(0xe18d00c0), + SPH_C32(0x3b6d0631), SPH_C32(0xc2ed5699), SPH_C32(0xcbe0fe1c), + SPH_C32(0x56a7b19f) }, + { SPH_C32(0xf0c50000), SPH_C32(0x59230000), SPH_C32(0x45820000), + SPH_C32(0xe18d00c0), SPH_C32(0x3b6d0631), SPH_C32(0xc2ed5699), + SPH_C32(0xcbe0fe1c), SPH_C32(0x56a7b19f), SPH_C32(0x16ed0000), + SPH_C32(0x15680000), SPH_C32(0xedd70000), SPH_C32(0x325d0220), + SPH_C32(0xe30c3689), SPH_C32(0x5a4ae643), SPH_C32(0xe375f8a8), + SPH_C32(0x81fdf908) }, + { SPH_C32(0xb4310000), SPH_C32(0x77330000), SPH_C32(0xb15d0000), + SPH_C32(0x7fd004e0), SPH_C32(0x78a26138), SPH_C32(0xd116c35d), + SPH_C32(0xd256d489), SPH_C32(0x4e6f74de), SPH_C32(0xe3060000), + SPH_C32(0xbdc10000), SPH_C32(0x87130000), SPH_C32(0xbff20060), + SPH_C32(0x2eba0a1a), SPH_C32(0x8db53751), SPH_C32(0x73c5ab06), + SPH_C32(0x5bd61539) }, + { SPH_C32(0xe3060000), SPH_C32(0xbdc10000), SPH_C32(0x87130000), + SPH_C32(0xbff20060), SPH_C32(0x2eba0a1a), SPH_C32(0x8db53751), + SPH_C32(0x73c5ab06), SPH_C32(0x5bd61539), SPH_C32(0x57370000), + SPH_C32(0xcaf20000), SPH_C32(0x364e0000), SPH_C32(0xc0220480), + SPH_C32(0x56186b22), SPH_C32(0x5ca3f40c), SPH_C32(0xa1937f8f), + SPH_C32(0x15b961e7) }, + { SPH_C32(0x02f20000), SPH_C32(0xa2810000), SPH_C32(0x873f0000), + SPH_C32(0xe36c7800), SPH_C32(0x1e1d74ef), SPH_C32(0x073d2bd6), + SPH_C32(0xc4c23237), SPH_C32(0x7f32259e), SPH_C32(0xbadd0000), + SPH_C32(0x13ad0000), SPH_C32(0xb7e70000), SPH_C32(0xf7282800), + SPH_C32(0xdf45144d), SPH_C32(0x361ac33a), SPH_C32(0xea5a8d14), + SPH_C32(0x2a2c18f0) }, + { SPH_C32(0xbadd0000), SPH_C32(0x13ad0000), SPH_C32(0xb7e70000), + SPH_C32(0xf7282800), SPH_C32(0xdf45144d), SPH_C32(0x361ac33a), + SPH_C32(0xea5a8d14), SPH_C32(0x2a2c18f0), SPH_C32(0xb82f0000), + SPH_C32(0xb12c0000), SPH_C32(0x30d80000), SPH_C32(0x14445000), + SPH_C32(0xc15860a2), SPH_C32(0x3127e8ec), SPH_C32(0x2e98bf23), + SPH_C32(0x551e3d6e) }, + { SPH_C32(0x1e6c0000), SPH_C32(0xc4420000), SPH_C32(0x8a2e0000), + SPH_C32(0xbcb6b800), SPH_C32(0x2c4413b6), SPH_C32(0x8bfdd3da), + SPH_C32(0x6a0c1bc8), SPH_C32(0xb99dc2eb), SPH_C32(0x92560000), + SPH_C32(0x1eda0000), SPH_C32(0xea510000), SPH_C32(0xe8b13000), + SPH_C32(0xa93556a5), SPH_C32(0xebfb6199), SPH_C32(0xb15c2254), + SPH_C32(0x33c5244f) }, + { SPH_C32(0x92560000), SPH_C32(0x1eda0000), SPH_C32(0xea510000), + SPH_C32(0xe8b13000), SPH_C32(0xa93556a5), SPH_C32(0xebfb6199), + SPH_C32(0xb15c2254), SPH_C32(0x33c5244f), SPH_C32(0x8c3a0000), + SPH_C32(0xda980000), SPH_C32(0x607f0000), SPH_C32(0x54078800), + SPH_C32(0x85714513), SPH_C32(0x6006b243), SPH_C32(0xdb50399c), + SPH_C32(0x8a58e6a4) }, + { SPH_C32(0x033d0000), SPH_C32(0x08b30000), SPH_C32(0xf33a0000), + SPH_C32(0x3ac20007), SPH_C32(0x51298a50), SPH_C32(0x6b6e661f), + SPH_C32(0x0ea5cfe3), SPH_C32(0xe6da7ffe), SPH_C32(0xa8da0000), + SPH_C32(0x96be0000), SPH_C32(0x5c1d0000), SPH_C32(0x07da0002), + SPH_C32(0x7d669583), SPH_C32(0x1f98708a), SPH_C32(0xbb668808), + SPH_C32(0xda878000) }, + { SPH_C32(0xa8da0000), SPH_C32(0x96be0000), SPH_C32(0x5c1d0000), + SPH_C32(0x07da0002), SPH_C32(0x7d669583), SPH_C32(0x1f98708a), + SPH_C32(0xbb668808), SPH_C32(0xda878000), SPH_C32(0xabe70000), + SPH_C32(0x9e0d0000), SPH_C32(0xaf270000), SPH_C32(0x3d180005), + SPH_C32(0x2c4f1fd3), SPH_C32(0x74f61695), SPH_C32(0xb5c347eb), + SPH_C32(0x3c5dfffe) }, + { SPH_C32(0x01930000), SPH_C32(0xe7820000), SPH_C32(0xedfb0000), + SPH_C32(0xcf0c000b), SPH_C32(0x8dd08d58), SPH_C32(0xbca3b42e), + SPH_C32(0x063661e1), SPH_C32(0x536f9e7b), SPH_C32(0x92280000), + SPH_C32(0xdc850000), SPH_C32(0x57fa0000), SPH_C32(0x56dc0003), + SPH_C32(0xbae92316), SPH_C32(0x5aefa30c), SPH_C32(0x90cef752), + SPH_C32(0x7b1675d7) }, + { SPH_C32(0x92280000), SPH_C32(0xdc850000), SPH_C32(0x57fa0000), + SPH_C32(0x56dc0003), SPH_C32(0xbae92316), SPH_C32(0x5aefa30c), + SPH_C32(0x90cef752), SPH_C32(0x7b1675d7), SPH_C32(0x93bb0000), + SPH_C32(0x3b070000), SPH_C32(0xba010000), SPH_C32(0x99d00008), + SPH_C32(0x3739ae4e), SPH_C32(0xe64c1722), SPH_C32(0x96f896b3), + SPH_C32(0x2879ebac) }, + { SPH_C32(0x5fa80000), SPH_C32(0x56030000), SPH_C32(0x43ae0000), + SPH_C32(0x64f30013), SPH_C32(0x257e86bf), SPH_C32(0x1311944e), + SPH_C32(0x541e95bf), SPH_C32(0x8ea4db69), SPH_C32(0x00440000), + SPH_C32(0x7f480000), SPH_C32(0xda7c0000), SPH_C32(0x2a230001), + SPH_C32(0x3badc9cc), SPH_C32(0xa9b69c87), SPH_C32(0x030a9e60), + SPH_C32(0xbe0a679e) }, + { SPH_C32(0x00440000), SPH_C32(0x7f480000), SPH_C32(0xda7c0000), + SPH_C32(0x2a230001), SPH_C32(0x3badc9cc), SPH_C32(0xa9b69c87), + SPH_C32(0x030a9e60), SPH_C32(0xbe0a679e), SPH_C32(0x5fec0000), + SPH_C32(0x294b0000), SPH_C32(0x99d20000), SPH_C32(0x4ed00012), + SPH_C32(0x1ed34f73), SPH_C32(0xbaa708c9), SPH_C32(0x57140bdf), + SPH_C32(0x30aebcf7) }, + { SPH_C32(0xee930000), SPH_C32(0xd6070000), SPH_C32(0x92c10000), + SPH_C32(0x2b9801e0), SPH_C32(0x9451287c), SPH_C32(0x3b6cfb57), + SPH_C32(0x45312374), SPH_C32(0x201f6a64), SPH_C32(0x7b280000), + SPH_C32(0x57420000), SPH_C32(0xa9e50000), SPH_C32(0x634300a0), + SPH_C32(0x9edb442f), SPH_C32(0x6d9995bb), SPH_C32(0x27f83b03), + SPH_C32(0xc7ff60f0) }, + { SPH_C32(0x7b280000), SPH_C32(0x57420000), SPH_C32(0xa9e50000), + SPH_C32(0x634300a0), SPH_C32(0x9edb442f), SPH_C32(0x6d9995bb), + SPH_C32(0x27f83b03), SPH_C32(0xc7ff60f0), SPH_C32(0x95bb0000), + SPH_C32(0x81450000), SPH_C32(0x3b240000), SPH_C32(0x48db0140), + SPH_C32(0x0a8a6c53), SPH_C32(0x56f56eec), SPH_C32(0x62c91877), + SPH_C32(0xe7e00a94) } +}; + +#define INPUT_BIG do { \ + const sph_u32 *tp = &T512[0][0]; \ + unsigned u, v; \ + m0 = 0; \ + m1 = 0; \ + m2 = 0; \ + m3 = 0; \ + m4 = 0; \ + m5 = 0; \ + m6 = 0; \ + m7 = 0; \ + m8 = 0; \ + m9 = 0; \ + mA = 0; \ + mB = 0; \ + mC = 0; \ + mD = 0; \ + mE = 0; \ + mF = 0; \ + for (u = 0; u < 8; u ++) { \ + unsigned db = buf[u]; \ + for (v = 0; v < 8; v ++, db >>= 1) { \ + sph_u32 dm = SPH_T32(-(sph_u32)(db & 1)); \ + m0 ^= dm & *tp ++; \ + m1 ^= dm & *tp ++; \ + m2 ^= dm & *tp ++; \ + m3 ^= dm & *tp ++; \ + m4 ^= dm & *tp ++; \ + m5 ^= dm & *tp ++; \ + m6 ^= dm & *tp ++; \ + m7 ^= dm & *tp ++; \ + m8 ^= dm & *tp ++; \ + m9 ^= dm & *tp ++; \ + mA ^= dm & *tp ++; \ + mB ^= dm & *tp ++; \ + mC ^= dm & *tp ++; \ + mD ^= dm & *tp ++; \ + mE ^= dm & *tp ++; \ + mF ^= dm & *tp ++; \ + } \ + } \ + } while (0) + +#endif + +#if SPH_HAMSI_EXPAND_BIG == 2 + +static const sph_u32 T512_0[4][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0x29449c00), SPH_C32(0x64e70000), SPH_C32(0xf24b0000), + SPH_C32(0xc2f30000), SPH_C32(0x0ede4e8f), SPH_C32(0x56c23745), + SPH_C32(0xf3e04259), SPH_C32(0x8d0d9ec4), SPH_C32(0x466d0c00), + SPH_C32(0x08620000), SPH_C32(0xdd5d0000), SPH_C32(0xbadd0000), + SPH_C32(0x6a927942), SPH_C32(0x441f2b93), SPH_C32(0x218ace6f), + SPH_C32(0xbf2c0be2) }, + { SPH_C32(0x466d0c00), SPH_C32(0x08620000), SPH_C32(0xdd5d0000), + SPH_C32(0xbadd0000), SPH_C32(0x6a927942), SPH_C32(0x441f2b93), + SPH_C32(0x218ace6f), SPH_C32(0xbf2c0be2), SPH_C32(0x6f299000), + SPH_C32(0x6c850000), SPH_C32(0x2f160000), SPH_C32(0x782e0000), + SPH_C32(0x644c37cd), SPH_C32(0x12dd1cd6), SPH_C32(0xd26a8c36), + SPH_C32(0x32219526) }, + { SPH_C32(0x6f299000), SPH_C32(0x6c850000), SPH_C32(0x2f160000), + SPH_C32(0x782e0000), SPH_C32(0x644c37cd), SPH_C32(0x12dd1cd6), + SPH_C32(0xd26a8c36), SPH_C32(0x32219526), SPH_C32(0x29449c00), + SPH_C32(0x64e70000), SPH_C32(0xf24b0000), SPH_C32(0xc2f30000), + SPH_C32(0x0ede4e8f), SPH_C32(0x56c23745), SPH_C32(0xf3e04259), + SPH_C32(0x8d0d9ec4) } +}; + +static const sph_u32 T512_2[4][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0x54285c00), SPH_C32(0xeaed0000), SPH_C32(0xc5d60000), + SPH_C32(0xa1c50000), SPH_C32(0xb3a26770), SPH_C32(0x94a5c4e1), + SPH_C32(0x6bb0419d), SPH_C32(0x551b3782), SPH_C32(0x9cbb1800), + SPH_C32(0xb0d30000), SPH_C32(0x92510000), SPH_C32(0xed930000), + SPH_C32(0x593a4345), SPH_C32(0xe114d5f4), SPH_C32(0x430633da), + SPH_C32(0x78cace29) }, + { SPH_C32(0x9cbb1800), SPH_C32(0xb0d30000), SPH_C32(0x92510000), + SPH_C32(0xed930000), SPH_C32(0x593a4345), SPH_C32(0xe114d5f4), + SPH_C32(0x430633da), SPH_C32(0x78cace29), SPH_C32(0xc8934400), + SPH_C32(0x5a3e0000), SPH_C32(0x57870000), SPH_C32(0x4c560000), + SPH_C32(0xea982435), SPH_C32(0x75b11115), SPH_C32(0x28b67247), + SPH_C32(0x2dd1f9ab) }, + { SPH_C32(0xc8934400), SPH_C32(0x5a3e0000), SPH_C32(0x57870000), + SPH_C32(0x4c560000), SPH_C32(0xea982435), SPH_C32(0x75b11115), + SPH_C32(0x28b67247), SPH_C32(0x2dd1f9ab), SPH_C32(0x54285c00), + SPH_C32(0xeaed0000), SPH_C32(0xc5d60000), SPH_C32(0xa1c50000), + SPH_C32(0xb3a26770), SPH_C32(0x94a5c4e1), SPH_C32(0x6bb0419d), + SPH_C32(0x551b3782) } +}; + +static const sph_u32 T512_4[4][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0x145a3c00), SPH_C32(0xb9e90000), SPH_C32(0x61270000), + SPH_C32(0xf1610000), SPH_C32(0xce613d6c), SPH_C32(0xb0493d78), + SPH_C32(0x47a96720), SPH_C32(0xe18e24c5), SPH_C32(0x23671400), + SPH_C32(0xc8b90000), SPH_C32(0xf4c70000), SPH_C32(0xfb750000), + SPH_C32(0x73cd2465), SPH_C32(0xf8a6a549), SPH_C32(0x02c40a3f), + SPH_C32(0xdc24e61f) }, + { SPH_C32(0x23671400), SPH_C32(0xc8b90000), SPH_C32(0xf4c70000), + SPH_C32(0xfb750000), SPH_C32(0x73cd2465), SPH_C32(0xf8a6a549), + SPH_C32(0x02c40a3f), SPH_C32(0xdc24e61f), SPH_C32(0x373d2800), + SPH_C32(0x71500000), SPH_C32(0x95e00000), SPH_C32(0x0a140000), + SPH_C32(0xbdac1909), SPH_C32(0x48ef9831), SPH_C32(0x456d6d1f), + SPH_C32(0x3daac2da) }, + { SPH_C32(0x373d2800), SPH_C32(0x71500000), SPH_C32(0x95e00000), + SPH_C32(0x0a140000), SPH_C32(0xbdac1909), SPH_C32(0x48ef9831), + SPH_C32(0x456d6d1f), SPH_C32(0x3daac2da), SPH_C32(0x145a3c00), + SPH_C32(0xb9e90000), SPH_C32(0x61270000), SPH_C32(0xf1610000), + SPH_C32(0xce613d6c), SPH_C32(0xb0493d78), SPH_C32(0x47a96720), + SPH_C32(0xe18e24c5) } +}; + +static const sph_u32 T512_6[4][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0xef0b0270), SPH_C32(0x3afd0000), SPH_C32(0x5dae0000), + SPH_C32(0x69490000), SPH_C32(0x9b0f3c06), SPH_C32(0x4405b5f9), + SPH_C32(0x66140a51), SPH_C32(0x924f5d0a), SPH_C32(0xc96b0030), + SPH_C32(0xe7250000), SPH_C32(0x2f840000), SPH_C32(0x264f0000), + SPH_C32(0x08695bf9), SPH_C32(0x6dfcf137), SPH_C32(0x509f6984), + SPH_C32(0x9e69af68) }, + { SPH_C32(0xc96b0030), SPH_C32(0xe7250000), SPH_C32(0x2f840000), + SPH_C32(0x264f0000), SPH_C32(0x08695bf9), SPH_C32(0x6dfcf137), + SPH_C32(0x509f6984), SPH_C32(0x9e69af68), SPH_C32(0x26600240), + SPH_C32(0xddd80000), SPH_C32(0x722a0000), SPH_C32(0x4f060000), + SPH_C32(0x936667ff), SPH_C32(0x29f944ce), SPH_C32(0x368b63d5), + SPH_C32(0x0c26f262) }, + { SPH_C32(0x26600240), SPH_C32(0xddd80000), SPH_C32(0x722a0000), + SPH_C32(0x4f060000), SPH_C32(0x936667ff), SPH_C32(0x29f944ce), + SPH_C32(0x368b63d5), SPH_C32(0x0c26f262), SPH_C32(0xef0b0270), + SPH_C32(0x3afd0000), SPH_C32(0x5dae0000), SPH_C32(0x69490000), + SPH_C32(0x9b0f3c06), SPH_C32(0x4405b5f9), SPH_C32(0x66140a51), + SPH_C32(0x924f5d0a) } +}; + +static const sph_u32 T512_8[4][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0xe8870170), SPH_C32(0x9d720000), SPH_C32(0x12db0000), + SPH_C32(0xd4220000), SPH_C32(0xf2886b27), SPH_C32(0xa921e543), + SPH_C32(0x4ef8b518), SPH_C32(0x618813b1), SPH_C32(0xb4370060), + SPH_C32(0x0c4c0000), SPH_C32(0x56c20000), SPH_C32(0x5cae0000), + SPH_C32(0x94541f3f), SPH_C32(0x3b3ef825), SPH_C32(0x1b365f3d), + SPH_C32(0xf3d45758) }, + { SPH_C32(0xb4370060), SPH_C32(0x0c4c0000), SPH_C32(0x56c20000), + SPH_C32(0x5cae0000), SPH_C32(0x94541f3f), SPH_C32(0x3b3ef825), + SPH_C32(0x1b365f3d), SPH_C32(0xf3d45758), SPH_C32(0x5cb00110), + SPH_C32(0x913e0000), SPH_C32(0x44190000), SPH_C32(0x888c0000), + SPH_C32(0x66dc7418), SPH_C32(0x921f1d66), SPH_C32(0x55ceea25), + SPH_C32(0x925c44e9) }, + { SPH_C32(0x5cb00110), SPH_C32(0x913e0000), SPH_C32(0x44190000), + SPH_C32(0x888c0000), SPH_C32(0x66dc7418), SPH_C32(0x921f1d66), + SPH_C32(0x55ceea25), SPH_C32(0x925c44e9), SPH_C32(0xe8870170), + SPH_C32(0x9d720000), SPH_C32(0x12db0000), SPH_C32(0xd4220000), + SPH_C32(0xf2886b27), SPH_C32(0xa921e543), SPH_C32(0x4ef8b518), + SPH_C32(0x618813b1) } +}; + +static const sph_u32 T512_10[4][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0x774400f0), SPH_C32(0xf15a0000), SPH_C32(0xf5b20000), + SPH_C32(0x34140000), SPH_C32(0x89377e8c), SPH_C32(0x5a8bec25), + SPH_C32(0x0bc3cd1e), SPH_C32(0xcf3775cb), SPH_C32(0xf46c0050), + SPH_C32(0x96180000), SPH_C32(0x14a50000), SPH_C32(0x031f0000), + SPH_C32(0x42947eb8), SPH_C32(0x66bf7e19), SPH_C32(0x9ca470d2), + SPH_C32(0x8a341574) }, + { SPH_C32(0xf46c0050), SPH_C32(0x96180000), SPH_C32(0x14a50000), + SPH_C32(0x031f0000), SPH_C32(0x42947eb8), SPH_C32(0x66bf7e19), + SPH_C32(0x9ca470d2), SPH_C32(0x8a341574), SPH_C32(0x832800a0), + SPH_C32(0x67420000), SPH_C32(0xe1170000), SPH_C32(0x370b0000), + SPH_C32(0xcba30034), SPH_C32(0x3c34923c), SPH_C32(0x9767bdcc), + SPH_C32(0x450360bf) }, + { SPH_C32(0x832800a0), SPH_C32(0x67420000), SPH_C32(0xe1170000), + SPH_C32(0x370b0000), SPH_C32(0xcba30034), SPH_C32(0x3c34923c), + SPH_C32(0x9767bdcc), SPH_C32(0x450360bf), SPH_C32(0x774400f0), + SPH_C32(0xf15a0000), SPH_C32(0xf5b20000), SPH_C32(0x34140000), + SPH_C32(0x89377e8c), SPH_C32(0x5a8bec25), SPH_C32(0x0bc3cd1e), + SPH_C32(0xcf3775cb) } +}; + +static const sph_u32 T512_12[4][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0xf7750009), SPH_C32(0xcf3cc000), SPH_C32(0xc3d60000), + SPH_C32(0x04920000), SPH_C32(0x029519a9), SPH_C32(0xf8e836ba), + SPH_C32(0x7a87f14e), SPH_C32(0x9e16981a), SPH_C32(0xd46a0000), + SPH_C32(0x8dc8c000), SPH_C32(0xa5af0000), SPH_C32(0x4a290000), + SPH_C32(0xfc4e427a), SPH_C32(0xc9b4866c), SPH_C32(0x98369604), + SPH_C32(0xf746c320) }, + { SPH_C32(0xd46a0000), SPH_C32(0x8dc8c000), SPH_C32(0xa5af0000), + SPH_C32(0x4a290000), SPH_C32(0xfc4e427a), SPH_C32(0xc9b4866c), + SPH_C32(0x98369604), SPH_C32(0xf746c320), SPH_C32(0x231f0009), + SPH_C32(0x42f40000), SPH_C32(0x66790000), SPH_C32(0x4ebb0000), + SPH_C32(0xfedb5bd3), SPH_C32(0x315cb0d6), SPH_C32(0xe2b1674a), + SPH_C32(0x69505b3a) }, + { SPH_C32(0x231f0009), SPH_C32(0x42f40000), SPH_C32(0x66790000), + SPH_C32(0x4ebb0000), SPH_C32(0xfedb5bd3), SPH_C32(0x315cb0d6), + SPH_C32(0xe2b1674a), SPH_C32(0x69505b3a), SPH_C32(0xf7750009), + SPH_C32(0xcf3cc000), SPH_C32(0xc3d60000), SPH_C32(0x04920000), + SPH_C32(0x029519a9), SPH_C32(0xf8e836ba), SPH_C32(0x7a87f14e), + SPH_C32(0x9e16981a) } +}; + +static const sph_u32 T512_14[4][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0xf6800005), SPH_C32(0x3443c000), SPH_C32(0x24070000), + SPH_C32(0x8f3d0000), SPH_C32(0x21373bfb), SPH_C32(0x0ab8d5ae), + SPH_C32(0xcdc58b19), SPH_C32(0xd795ba31), SPH_C32(0xa67f0001), + SPH_C32(0x71378000), SPH_C32(0x19fc0000), SPH_C32(0x96db0000), + SPH_C32(0x3a8b6dfd), SPH_C32(0xebcaaef3), SPH_C32(0x2c6d478f), + SPH_C32(0xac8e6c88) }, + { SPH_C32(0xa67f0001), SPH_C32(0x71378000), SPH_C32(0x19fc0000), + SPH_C32(0x96db0000), SPH_C32(0x3a8b6dfd), SPH_C32(0xebcaaef3), + SPH_C32(0x2c6d478f), SPH_C32(0xac8e6c88), SPH_C32(0x50ff0004), + SPH_C32(0x45744000), SPH_C32(0x3dfb0000), SPH_C32(0x19e60000), + SPH_C32(0x1bbc5606), SPH_C32(0xe1727b5d), SPH_C32(0xe1a8cc96), + SPH_C32(0x7b1bd6b9) }, + { SPH_C32(0x50ff0004), SPH_C32(0x45744000), SPH_C32(0x3dfb0000), + SPH_C32(0x19e60000), SPH_C32(0x1bbc5606), SPH_C32(0xe1727b5d), + SPH_C32(0xe1a8cc96), SPH_C32(0x7b1bd6b9), SPH_C32(0xf6800005), + SPH_C32(0x3443c000), SPH_C32(0x24070000), SPH_C32(0x8f3d0000), + SPH_C32(0x21373bfb), SPH_C32(0x0ab8d5ae), SPH_C32(0xcdc58b19), + SPH_C32(0xd795ba31) } +}; + +static const sph_u32 T512_16[4][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0x75c90003), SPH_C32(0x0e10c000), SPH_C32(0xd1200000), + SPH_C32(0xbaea0000), SPH_C32(0x8bc42f3e), SPH_C32(0x8758b757), + SPH_C32(0xbb28761d), SPH_C32(0x00b72e2b), SPH_C32(0xeecf0001), + SPH_C32(0x6f564000), SPH_C32(0xf33e0000), SPH_C32(0xa79e0000), + SPH_C32(0xbdb57219), SPH_C32(0xb711ebc5), SPH_C32(0x4a3b40ba), + SPH_C32(0xfeabf254) }, + { SPH_C32(0xeecf0001), SPH_C32(0x6f564000), SPH_C32(0xf33e0000), + SPH_C32(0xa79e0000), SPH_C32(0xbdb57219), SPH_C32(0xb711ebc5), + SPH_C32(0x4a3b40ba), SPH_C32(0xfeabf254), SPH_C32(0x9b060002), + SPH_C32(0x61468000), SPH_C32(0x221e0000), SPH_C32(0x1d740000), + SPH_C32(0x36715d27), SPH_C32(0x30495c92), SPH_C32(0xf11336a7), + SPH_C32(0xfe1cdc7f) }, + { SPH_C32(0x9b060002), SPH_C32(0x61468000), SPH_C32(0x221e0000), + SPH_C32(0x1d740000), SPH_C32(0x36715d27), SPH_C32(0x30495c92), + SPH_C32(0xf11336a7), SPH_C32(0xfe1cdc7f), SPH_C32(0x75c90003), + SPH_C32(0x0e10c000), SPH_C32(0xd1200000), SPH_C32(0xbaea0000), + SPH_C32(0x8bc42f3e), SPH_C32(0x8758b757), SPH_C32(0xbb28761d), + SPH_C32(0x00b72e2b) } +}; + +static const sph_u32 T512_18[4][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0x75a40000), SPH_C32(0xc28b2700), SPH_C32(0x94a40000), + SPH_C32(0x90f50000), SPH_C32(0xfb7857e0), SPH_C32(0x49ce0bae), + SPH_C32(0x1767c483), SPH_C32(0xaedf667e), SPH_C32(0xd1660000), + SPH_C32(0x1bbc0300), SPH_C32(0x9eec0000), SPH_C32(0xf6940000), + SPH_C32(0x03024527), SPH_C32(0xcf70fcf2), SPH_C32(0xb4431b17), + SPH_C32(0x857f3c2b) }, + { SPH_C32(0xd1660000), SPH_C32(0x1bbc0300), SPH_C32(0x9eec0000), + SPH_C32(0xf6940000), SPH_C32(0x03024527), SPH_C32(0xcf70fcf2), + SPH_C32(0xb4431b17), SPH_C32(0x857f3c2b), SPH_C32(0xa4c20000), + SPH_C32(0xd9372400), SPH_C32(0x0a480000), SPH_C32(0x66610000), + SPH_C32(0xf87a12c7), SPH_C32(0x86bef75c), SPH_C32(0xa324df94), + SPH_C32(0x2ba05a55) }, + { SPH_C32(0xa4c20000), SPH_C32(0xd9372400), SPH_C32(0x0a480000), + SPH_C32(0x66610000), SPH_C32(0xf87a12c7), SPH_C32(0x86bef75c), + SPH_C32(0xa324df94), SPH_C32(0x2ba05a55), SPH_C32(0x75a40000), + SPH_C32(0xc28b2700), SPH_C32(0x94a40000), SPH_C32(0x90f50000), + SPH_C32(0xfb7857e0), SPH_C32(0x49ce0bae), SPH_C32(0x1767c483), + SPH_C32(0xaedf667e) } +}; + +static const sph_u32 T512_20[4][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0x45180000), SPH_C32(0xa5b51700), SPH_C32(0xf96a0000), + SPH_C32(0x3b480000), SPH_C32(0x1ecc142c), SPH_C32(0x231395d6), + SPH_C32(0x16bca6b0), SPH_C32(0xdf33f4df), SPH_C32(0xb83d0000), + SPH_C32(0x16710600), SPH_C32(0x379a0000), SPH_C32(0xf5b10000), + SPH_C32(0x228161ac), SPH_C32(0xae48f145), SPH_C32(0x66241616), + SPH_C32(0xc5c1eb3e) }, + { SPH_C32(0xb83d0000), SPH_C32(0x16710600), SPH_C32(0x379a0000), + SPH_C32(0xf5b10000), SPH_C32(0x228161ac), SPH_C32(0xae48f145), + SPH_C32(0x66241616), SPH_C32(0xc5c1eb3e), SPH_C32(0xfd250000), + SPH_C32(0xb3c41100), SPH_C32(0xcef00000), SPH_C32(0xcef90000), + SPH_C32(0x3c4d7580), SPH_C32(0x8d5b6493), SPH_C32(0x7098b0a6), + SPH_C32(0x1af21fe1) }, + { SPH_C32(0xfd250000), SPH_C32(0xb3c41100), SPH_C32(0xcef00000), + SPH_C32(0xcef90000), SPH_C32(0x3c4d7580), SPH_C32(0x8d5b6493), + SPH_C32(0x7098b0a6), SPH_C32(0x1af21fe1), SPH_C32(0x45180000), + SPH_C32(0xa5b51700), SPH_C32(0xf96a0000), SPH_C32(0x3b480000), + SPH_C32(0x1ecc142c), SPH_C32(0x231395d6), SPH_C32(0x16bca6b0), + SPH_C32(0xdf33f4df) } +}; + +static const sph_u32 T512_22[4][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0x0c720000), SPH_C32(0x49e50f00), SPH_C32(0x42790000), + SPH_C32(0x5cea0000), SPH_C32(0x33aa301a), SPH_C32(0x15822514), + SPH_C32(0x95a34b7b), SPH_C32(0xb44b0090), SPH_C32(0xfe220000), + SPH_C32(0xa7580500), SPH_C32(0x25d10000), SPH_C32(0xf7600000), + SPH_C32(0x893178da), SPH_C32(0x1fd4f860), SPH_C32(0x4ed0a315), + SPH_C32(0xa123ff9f) }, + { SPH_C32(0xfe220000), SPH_C32(0xa7580500), SPH_C32(0x25d10000), + SPH_C32(0xf7600000), SPH_C32(0x893178da), SPH_C32(0x1fd4f860), + SPH_C32(0x4ed0a315), SPH_C32(0xa123ff9f), SPH_C32(0xf2500000), + SPH_C32(0xeebd0a00), SPH_C32(0x67a80000), SPH_C32(0xab8a0000), + SPH_C32(0xba9b48c0), SPH_C32(0x0a56dd74), SPH_C32(0xdb73e86e), + SPH_C32(0x1568ff0f) }, + { SPH_C32(0xf2500000), SPH_C32(0xeebd0a00), SPH_C32(0x67a80000), + SPH_C32(0xab8a0000), SPH_C32(0xba9b48c0), SPH_C32(0x0a56dd74), + SPH_C32(0xdb73e86e), SPH_C32(0x1568ff0f), SPH_C32(0x0c720000), + SPH_C32(0x49e50f00), SPH_C32(0x42790000), SPH_C32(0x5cea0000), + SPH_C32(0x33aa301a), SPH_C32(0x15822514), SPH_C32(0x95a34b7b), + SPH_C32(0xb44b0090) } +}; + +static const sph_u32 T512_24[4][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0x69510000), SPH_C32(0xd4e1009c), SPH_C32(0xc3230000), + SPH_C32(0xac2f0000), SPH_C32(0xe4950bae), SPH_C32(0xcea415dc), + SPH_C32(0x87ec287c), SPH_C32(0xbce1a3ce), SPH_C32(0xc6730000), + SPH_C32(0xaf8d000c), SPH_C32(0xa4c10000), SPH_C32(0x218d0000), + SPH_C32(0x23111587), SPH_C32(0x7913512f), SPH_C32(0x1d28ac88), + SPH_C32(0x378dd173) }, + { SPH_C32(0xc6730000), SPH_C32(0xaf8d000c), SPH_C32(0xa4c10000), + SPH_C32(0x218d0000), SPH_C32(0x23111587), SPH_C32(0x7913512f), + SPH_C32(0x1d28ac88), SPH_C32(0x378dd173), SPH_C32(0xaf220000), + SPH_C32(0x7b6c0090), SPH_C32(0x67e20000), SPH_C32(0x8da20000), + SPH_C32(0xc7841e29), SPH_C32(0xb7b744f3), SPH_C32(0x9ac484f4), + SPH_C32(0x8b6c72bd) }, + { SPH_C32(0xaf220000), SPH_C32(0x7b6c0090), SPH_C32(0x67e20000), + SPH_C32(0x8da20000), SPH_C32(0xc7841e29), SPH_C32(0xb7b744f3), + SPH_C32(0x9ac484f4), SPH_C32(0x8b6c72bd), SPH_C32(0x69510000), + SPH_C32(0xd4e1009c), SPH_C32(0xc3230000), SPH_C32(0xac2f0000), + SPH_C32(0xe4950bae), SPH_C32(0xcea415dc), SPH_C32(0x87ec287c), + SPH_C32(0xbce1a3ce) } +}; + +static const sph_u32 T512_26[4][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0x54500000), SPH_C32(0x0671005c), SPH_C32(0x25ae0000), + SPH_C32(0x6a1e0000), SPH_C32(0x2ea54edf), SPH_C32(0x664e8512), + SPH_C32(0xbfba18c3), SPH_C32(0x7e715d17), SPH_C32(0xbc8d0000), + SPH_C32(0xfc3b0018), SPH_C32(0x19830000), SPH_C32(0xd10b0000), + SPH_C32(0xae1878c4), SPH_C32(0x42a69856), SPH_C32(0x0012da37), + SPH_C32(0x2c3b504e) }, + { SPH_C32(0xbc8d0000), SPH_C32(0xfc3b0018), SPH_C32(0x19830000), + SPH_C32(0xd10b0000), SPH_C32(0xae1878c4), SPH_C32(0x42a69856), + SPH_C32(0x0012da37), SPH_C32(0x2c3b504e), SPH_C32(0xe8dd0000), + SPH_C32(0xfa4a0044), SPH_C32(0x3c2d0000), SPH_C32(0xbb150000), + SPH_C32(0x80bd361b), SPH_C32(0x24e81d44), SPH_C32(0xbfa8c2f4), + SPH_C32(0x524a0d59) }, + { SPH_C32(0xe8dd0000), SPH_C32(0xfa4a0044), SPH_C32(0x3c2d0000), + SPH_C32(0xbb150000), SPH_C32(0x80bd361b), SPH_C32(0x24e81d44), + SPH_C32(0xbfa8c2f4), SPH_C32(0x524a0d59), SPH_C32(0x54500000), + SPH_C32(0x0671005c), SPH_C32(0x25ae0000), SPH_C32(0x6a1e0000), + SPH_C32(0x2ea54edf), SPH_C32(0x664e8512), SPH_C32(0xbfba18c3), + SPH_C32(0x7e715d17) } +}; + +static const sph_u32 T512_28[4][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0x14190000), SPH_C32(0x23ca003c), SPH_C32(0x50df0000), + SPH_C32(0x44b60000), SPH_C32(0x1b6c67b0), SPH_C32(0x3cf3ac75), + SPH_C32(0x61e610b0), SPH_C32(0xdbcadb80), SPH_C32(0xe3430000), + SPH_C32(0x3a4e0014), SPH_C32(0xf2c60000), SPH_C32(0xaa4e0000), + SPH_C32(0xdb1e42a6), SPH_C32(0x256bbe15), SPH_C32(0x123db156), + SPH_C32(0x3a4e99d7) }, + { SPH_C32(0xe3430000), SPH_C32(0x3a4e0014), SPH_C32(0xf2c60000), + SPH_C32(0xaa4e0000), SPH_C32(0xdb1e42a6), SPH_C32(0x256bbe15), + SPH_C32(0x123db156), SPH_C32(0x3a4e99d7), SPH_C32(0xf75a0000), + SPH_C32(0x19840028), SPH_C32(0xa2190000), SPH_C32(0xeef80000), + SPH_C32(0xc0722516), SPH_C32(0x19981260), SPH_C32(0x73dba1e6), + SPH_C32(0xe1844257) }, + { SPH_C32(0xf75a0000), SPH_C32(0x19840028), SPH_C32(0xa2190000), + SPH_C32(0xeef80000), SPH_C32(0xc0722516), SPH_C32(0x19981260), + SPH_C32(0x73dba1e6), SPH_C32(0xe1844257), SPH_C32(0x14190000), + SPH_C32(0x23ca003c), SPH_C32(0x50df0000), SPH_C32(0x44b60000), + SPH_C32(0x1b6c67b0), SPH_C32(0x3cf3ac75), SPH_C32(0x61e610b0), + SPH_C32(0xdbcadb80) } +}; + +static const sph_u32 T512_30[4][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0x86790000), SPH_C32(0x3f390002), SPH_C32(0xe19ae000), + SPH_C32(0x98560000), SPH_C32(0x9565670e), SPH_C32(0x4e88c8ea), + SPH_C32(0xd3dd4944), SPH_C32(0x161ddab9), SPH_C32(0x30b70000), + SPH_C32(0xe5d00000), SPH_C32(0xf4f46000), SPH_C32(0x42c40000), + SPH_C32(0x63b83d6a), SPH_C32(0x78ba9460), SPH_C32(0x21afa1ea), + SPH_C32(0xb0a51834) }, + { SPH_C32(0x30b70000), SPH_C32(0xe5d00000), SPH_C32(0xf4f46000), + SPH_C32(0x42c40000), SPH_C32(0x63b83d6a), SPH_C32(0x78ba9460), + SPH_C32(0x21afa1ea), SPH_C32(0xb0a51834), SPH_C32(0xb6ce0000), + SPH_C32(0xdae90002), SPH_C32(0x156e8000), SPH_C32(0xda920000), + SPH_C32(0xf6dd5a64), SPH_C32(0x36325c8a), SPH_C32(0xf272e8ae), + SPH_C32(0xa6b8c28d) }, + { SPH_C32(0xb6ce0000), SPH_C32(0xdae90002), SPH_C32(0x156e8000), + SPH_C32(0xda920000), SPH_C32(0xf6dd5a64), SPH_C32(0x36325c8a), + SPH_C32(0xf272e8ae), SPH_C32(0xa6b8c28d), SPH_C32(0x86790000), + SPH_C32(0x3f390002), SPH_C32(0xe19ae000), SPH_C32(0x98560000), + SPH_C32(0x9565670e), SPH_C32(0x4e88c8ea), SPH_C32(0xd3dd4944), + SPH_C32(0x161ddab9) } +}; + +static const sph_u32 T512_32[4][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0xaec30000), SPH_C32(0x9c4f0001), SPH_C32(0x79d1e000), + SPH_C32(0x2c150000), SPH_C32(0x45cc75b3), SPH_C32(0x6650b736), + SPH_C32(0xab92f78f), SPH_C32(0xa312567b), SPH_C32(0xdb250000), + SPH_C32(0x09290000), SPH_C32(0x49aac000), SPH_C32(0x81e10000), + SPH_C32(0xcafe6b59), SPH_C32(0x42793431), SPH_C32(0x43566b76), + SPH_C32(0xe86cba2e) }, + { SPH_C32(0xdb250000), SPH_C32(0x09290000), SPH_C32(0x49aac000), + SPH_C32(0x81e10000), SPH_C32(0xcafe6b59), SPH_C32(0x42793431), + SPH_C32(0x43566b76), SPH_C32(0xe86cba2e), SPH_C32(0x75e60000), + SPH_C32(0x95660001), SPH_C32(0x307b2000), SPH_C32(0xadf40000), + SPH_C32(0x8f321eea), SPH_C32(0x24298307), SPH_C32(0xe8c49cf9), + SPH_C32(0x4b7eec55) }, + { SPH_C32(0x75e60000), SPH_C32(0x95660001), SPH_C32(0x307b2000), + SPH_C32(0xadf40000), SPH_C32(0x8f321eea), SPH_C32(0x24298307), + SPH_C32(0xe8c49cf9), SPH_C32(0x4b7eec55), SPH_C32(0xaec30000), + SPH_C32(0x9c4f0001), SPH_C32(0x79d1e000), SPH_C32(0x2c150000), + SPH_C32(0x45cc75b3), SPH_C32(0x6650b736), SPH_C32(0xab92f78f), + SPH_C32(0xa312567b) } +}; + +static const sph_u32 T512_34[4][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0xac480000), SPH_C32(0x1ba60000), SPH_C32(0x45fb1380), + SPH_C32(0x03430000), SPH_C32(0x5a85316a), SPH_C32(0x1fb250b6), + SPH_C32(0xfe72c7fe), SPH_C32(0x91e478f6), SPH_C32(0x1e4e0000), + SPH_C32(0xdecf0000), SPH_C32(0x6df80180), SPH_C32(0x77240000), + SPH_C32(0xec47079e), SPH_C32(0xf4a0694e), SPH_C32(0xcda31812), + SPH_C32(0x98aa496e) }, + { SPH_C32(0x1e4e0000), SPH_C32(0xdecf0000), SPH_C32(0x6df80180), + SPH_C32(0x77240000), SPH_C32(0xec47079e), SPH_C32(0xf4a0694e), + SPH_C32(0xcda31812), SPH_C32(0x98aa496e), SPH_C32(0xb2060000), + SPH_C32(0xc5690000), SPH_C32(0x28031200), SPH_C32(0x74670000), + SPH_C32(0xb6c236f4), SPH_C32(0xeb1239f8), SPH_C32(0x33d1dfec), + SPH_C32(0x094e3198) }, + { SPH_C32(0xb2060000), SPH_C32(0xc5690000), SPH_C32(0x28031200), + SPH_C32(0x74670000), SPH_C32(0xb6c236f4), SPH_C32(0xeb1239f8), + SPH_C32(0x33d1dfec), SPH_C32(0x094e3198), SPH_C32(0xac480000), + SPH_C32(0x1ba60000), SPH_C32(0x45fb1380), SPH_C32(0x03430000), + SPH_C32(0x5a85316a), SPH_C32(0x1fb250b6), SPH_C32(0xfe72c7fe), + SPH_C32(0x91e478f6) } +}; + +static const sph_u32 T512_36[4][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0x78230000), SPH_C32(0x12fc0000), SPH_C32(0xa93a0b80), + SPH_C32(0x90a50000), SPH_C32(0x713e2879), SPH_C32(0x7ee98924), + SPH_C32(0xf08ca062), SPH_C32(0x636f8bab), SPH_C32(0x02af0000), + SPH_C32(0xb7280000), SPH_C32(0xba1c0300), SPH_C32(0x56980000), + SPH_C32(0xba8d45d3), SPH_C32(0x8048c667), SPH_C32(0xa95c149a), + SPH_C32(0xf4f6ea7b) }, + { SPH_C32(0x02af0000), SPH_C32(0xb7280000), SPH_C32(0xba1c0300), + SPH_C32(0x56980000), SPH_C32(0xba8d45d3), SPH_C32(0x8048c667), + SPH_C32(0xa95c149a), SPH_C32(0xf4f6ea7b), SPH_C32(0x7a8c0000), + SPH_C32(0xa5d40000), SPH_C32(0x13260880), SPH_C32(0xc63d0000), + SPH_C32(0xcbb36daa), SPH_C32(0xfea14f43), SPH_C32(0x59d0b4f8), + SPH_C32(0x979961d0) }, + { SPH_C32(0x7a8c0000), SPH_C32(0xa5d40000), SPH_C32(0x13260880), + SPH_C32(0xc63d0000), SPH_C32(0xcbb36daa), SPH_C32(0xfea14f43), + SPH_C32(0x59d0b4f8), SPH_C32(0x979961d0), SPH_C32(0x78230000), + SPH_C32(0x12fc0000), SPH_C32(0xa93a0b80), SPH_C32(0x90a50000), + SPH_C32(0x713e2879), SPH_C32(0x7ee98924), SPH_C32(0xf08ca062), + SPH_C32(0x636f8bab) } +}; + +static const sph_u32 T512_38[4][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0xcc140000), SPH_C32(0xa5630000), SPH_C32(0x5ab90780), + SPH_C32(0x3b500000), SPH_C32(0x4bd013ff), SPH_C32(0x879b3418), + SPH_C32(0x694348c1), SPH_C32(0xca5a87fe), SPH_C32(0x819e0000), + SPH_C32(0xec570000), SPH_C32(0x66320280), SPH_C32(0x95f30000), + SPH_C32(0x5da92802), SPH_C32(0x48f43cbc), SPH_C32(0xe65aa22d), + SPH_C32(0x8e67b7fa) }, + { SPH_C32(0x819e0000), SPH_C32(0xec570000), SPH_C32(0x66320280), + SPH_C32(0x95f30000), SPH_C32(0x5da92802), SPH_C32(0x48f43cbc), + SPH_C32(0xe65aa22d), SPH_C32(0x8e67b7fa), SPH_C32(0x4d8a0000), + SPH_C32(0x49340000), SPH_C32(0x3c8b0500), SPH_C32(0xaea30000), + SPH_C32(0x16793bfd), SPH_C32(0xcf6f08a4), SPH_C32(0x8f19eaec), + SPH_C32(0x443d3004) }, + { SPH_C32(0x4d8a0000), SPH_C32(0x49340000), SPH_C32(0x3c8b0500), + SPH_C32(0xaea30000), SPH_C32(0x16793bfd), SPH_C32(0xcf6f08a4), + SPH_C32(0x8f19eaec), SPH_C32(0x443d3004), SPH_C32(0xcc140000), + SPH_C32(0xa5630000), SPH_C32(0x5ab90780), SPH_C32(0x3b500000), + SPH_C32(0x4bd013ff), SPH_C32(0x879b3418), SPH_C32(0x694348c1), + SPH_C32(0xca5a87fe) } +}; + +static const sph_u32 T512_40[4][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0x52500000), SPH_C32(0x29540000), SPH_C32(0x6a61004e), + SPH_C32(0xf0ff0000), SPH_C32(0x9a317eec), SPH_C32(0x452341ce), + SPH_C32(0xcf568fe5), SPH_C32(0x5303130f), SPH_C32(0x538d0000), + SPH_C32(0xa9fc0000), SPH_C32(0x9ef70006), SPH_C32(0x56ff0000), + SPH_C32(0x0ae4004e), SPH_C32(0x92c5cdf9), SPH_C32(0xa9444018), + SPH_C32(0x7f975691) }, + { SPH_C32(0x538d0000), SPH_C32(0xa9fc0000), SPH_C32(0x9ef70006), + SPH_C32(0x56ff0000), SPH_C32(0x0ae4004e), SPH_C32(0x92c5cdf9), + SPH_C32(0xa9444018), SPH_C32(0x7f975691), SPH_C32(0x01dd0000), + SPH_C32(0x80a80000), SPH_C32(0xf4960048), SPH_C32(0xa6000000), + SPH_C32(0x90d57ea2), SPH_C32(0xd7e68c37), SPH_C32(0x6612cffd), + SPH_C32(0x2c94459e) }, + { SPH_C32(0x01dd0000), SPH_C32(0x80a80000), SPH_C32(0xf4960048), + SPH_C32(0xa6000000), SPH_C32(0x90d57ea2), SPH_C32(0xd7e68c37), + SPH_C32(0x6612cffd), SPH_C32(0x2c94459e), SPH_C32(0x52500000), + SPH_C32(0x29540000), SPH_C32(0x6a61004e), SPH_C32(0xf0ff0000), + SPH_C32(0x9a317eec), SPH_C32(0x452341ce), SPH_C32(0xcf568fe5), + SPH_C32(0x5303130f) } +}; + +static const sph_u32 T512_42[4][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0x88980000), SPH_C32(0x1f940000), SPH_C32(0x7fcf002e), + SPH_C32(0xfb4e0000), SPH_C32(0xf158079a), SPH_C32(0x61ae9167), + SPH_C32(0xa895706c), SPH_C32(0xe6107494), SPH_C32(0x0bc20000), + SPH_C32(0xdb630000), SPH_C32(0x7e88000c), SPH_C32(0x15860000), + SPH_C32(0x91fd48f3), SPH_C32(0x7581bb43), SPH_C32(0xf460449e), + SPH_C32(0xd8b61463) }, + { SPH_C32(0x0bc20000), SPH_C32(0xdb630000), SPH_C32(0x7e88000c), + SPH_C32(0x15860000), SPH_C32(0x91fd48f3), SPH_C32(0x7581bb43), + SPH_C32(0xf460449e), SPH_C32(0xd8b61463), SPH_C32(0x835a0000), + SPH_C32(0xc4f70000), SPH_C32(0x01470022), SPH_C32(0xeec80000), + SPH_C32(0x60a54f69), SPH_C32(0x142f2a24), SPH_C32(0x5cf534f2), + SPH_C32(0x3ea660f7) }, + { SPH_C32(0x835a0000), SPH_C32(0xc4f70000), SPH_C32(0x01470022), + SPH_C32(0xeec80000), SPH_C32(0x60a54f69), SPH_C32(0x142f2a24), + SPH_C32(0x5cf534f2), SPH_C32(0x3ea660f7), SPH_C32(0x88980000), + SPH_C32(0x1f940000), SPH_C32(0x7fcf002e), SPH_C32(0xfb4e0000), + SPH_C32(0xf158079a), SPH_C32(0x61ae9167), SPH_C32(0xa895706c), + SPH_C32(0xe6107494) } +}; + +static const sph_u32 T512_44[4][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0xa53b0000), SPH_C32(0x14260000), SPH_C32(0x4e30001e), + SPH_C32(0x7cae0000), SPH_C32(0x8f9e0dd5), SPH_C32(0x78dfaa3d), + SPH_C32(0xf73168d8), SPH_C32(0x0b1b4946), SPH_C32(0x07ed0000), + SPH_C32(0xb2500000), SPH_C32(0x8774000a), SPH_C32(0x970d0000), + SPH_C32(0x437223ae), SPH_C32(0x48c76ea4), SPH_C32(0xf4786222), + SPH_C32(0x9075b1ce) }, + { SPH_C32(0x07ed0000), SPH_C32(0xb2500000), SPH_C32(0x8774000a), + SPH_C32(0x970d0000), SPH_C32(0x437223ae), SPH_C32(0x48c76ea4), + SPH_C32(0xf4786222), SPH_C32(0x9075b1ce), SPH_C32(0xa2d60000), + SPH_C32(0xa6760000), SPH_C32(0xc9440014), SPH_C32(0xeba30000), + SPH_C32(0xccec2e7b), SPH_C32(0x3018c499), SPH_C32(0x03490afa), + SPH_C32(0x9b6ef888) }, + { SPH_C32(0xa2d60000), SPH_C32(0xa6760000), SPH_C32(0xc9440014), + SPH_C32(0xeba30000), SPH_C32(0xccec2e7b), SPH_C32(0x3018c499), + SPH_C32(0x03490afa), SPH_C32(0x9b6ef888), SPH_C32(0xa53b0000), + SPH_C32(0x14260000), SPH_C32(0x4e30001e), SPH_C32(0x7cae0000), + SPH_C32(0x8f9e0dd5), SPH_C32(0x78dfaa3d), SPH_C32(0xf73168d8), + SPH_C32(0x0b1b4946) } +}; + +static const sph_u32 T512_46[4][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0x58430000), SPH_C32(0x807e0000), SPH_C32(0x78330001), + SPH_C32(0xc66b3800), SPH_C32(0xe7375cdc), SPH_C32(0x79ad3fdd), + SPH_C32(0xac73fe6f), SPH_C32(0x3a4479b1), SPH_C32(0x1d5a0000), + SPH_C32(0x2b720000), SPH_C32(0x488d0000), SPH_C32(0xaf611800), + SPH_C32(0x25cb2ec5), SPH_C32(0xc879bfd0), SPH_C32(0x81a20429), + SPH_C32(0x1e7536a6) }, + { SPH_C32(0x1d5a0000), SPH_C32(0x2b720000), SPH_C32(0x488d0000), + SPH_C32(0xaf611800), SPH_C32(0x25cb2ec5), SPH_C32(0xc879bfd0), + SPH_C32(0x81a20429), SPH_C32(0x1e7536a6), SPH_C32(0x45190000), + SPH_C32(0xab0c0000), SPH_C32(0x30be0001), SPH_C32(0x690a2000), + SPH_C32(0xc2fc7219), SPH_C32(0xb1d4800d), SPH_C32(0x2dd1fa46), + SPH_C32(0x24314f17) }, + { SPH_C32(0x45190000), SPH_C32(0xab0c0000), SPH_C32(0x30be0001), + SPH_C32(0x690a2000), SPH_C32(0xc2fc7219), SPH_C32(0xb1d4800d), + SPH_C32(0x2dd1fa46), SPH_C32(0x24314f17), SPH_C32(0x58430000), + SPH_C32(0x807e0000), SPH_C32(0x78330001), SPH_C32(0xc66b3800), + SPH_C32(0xe7375cdc), SPH_C32(0x79ad3fdd), SPH_C32(0xac73fe6f), + SPH_C32(0x3a4479b1) } +}; + +static const sph_u32 T512_48[4][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0x1e6c0000), SPH_C32(0xc4420000), SPH_C32(0x8a2e0000), + SPH_C32(0xbcb6b800), SPH_C32(0x2c4413b6), SPH_C32(0x8bfdd3da), + SPH_C32(0x6a0c1bc8), SPH_C32(0xb99dc2eb), SPH_C32(0x92560000), + SPH_C32(0x1eda0000), SPH_C32(0xea510000), SPH_C32(0xe8b13000), + SPH_C32(0xa93556a5), SPH_C32(0xebfb6199), SPH_C32(0xb15c2254), + SPH_C32(0x33c5244f) }, + { SPH_C32(0x92560000), SPH_C32(0x1eda0000), SPH_C32(0xea510000), + SPH_C32(0xe8b13000), SPH_C32(0xa93556a5), SPH_C32(0xebfb6199), + SPH_C32(0xb15c2254), SPH_C32(0x33c5244f), SPH_C32(0x8c3a0000), + SPH_C32(0xda980000), SPH_C32(0x607f0000), SPH_C32(0x54078800), + SPH_C32(0x85714513), SPH_C32(0x6006b243), SPH_C32(0xdb50399c), + SPH_C32(0x8a58e6a4) }, + { SPH_C32(0x8c3a0000), SPH_C32(0xda980000), SPH_C32(0x607f0000), + SPH_C32(0x54078800), SPH_C32(0x85714513), SPH_C32(0x6006b243), + SPH_C32(0xdb50399c), SPH_C32(0x8a58e6a4), SPH_C32(0x1e6c0000), + SPH_C32(0xc4420000), SPH_C32(0x8a2e0000), SPH_C32(0xbcb6b800), + SPH_C32(0x2c4413b6), SPH_C32(0x8bfdd3da), SPH_C32(0x6a0c1bc8), + SPH_C32(0xb99dc2eb) } +}; + +static const sph_u32 T512_50[4][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0x02f20000), SPH_C32(0xa2810000), SPH_C32(0x873f0000), + SPH_C32(0xe36c7800), SPH_C32(0x1e1d74ef), SPH_C32(0x073d2bd6), + SPH_C32(0xc4c23237), SPH_C32(0x7f32259e), SPH_C32(0xbadd0000), + SPH_C32(0x13ad0000), SPH_C32(0xb7e70000), SPH_C32(0xf7282800), + SPH_C32(0xdf45144d), SPH_C32(0x361ac33a), SPH_C32(0xea5a8d14), + SPH_C32(0x2a2c18f0) }, + { SPH_C32(0xbadd0000), SPH_C32(0x13ad0000), SPH_C32(0xb7e70000), + SPH_C32(0xf7282800), SPH_C32(0xdf45144d), SPH_C32(0x361ac33a), + SPH_C32(0xea5a8d14), SPH_C32(0x2a2c18f0), SPH_C32(0xb82f0000), + SPH_C32(0xb12c0000), SPH_C32(0x30d80000), SPH_C32(0x14445000), + SPH_C32(0xc15860a2), SPH_C32(0x3127e8ec), SPH_C32(0x2e98bf23), + SPH_C32(0x551e3d6e) }, + { SPH_C32(0xb82f0000), SPH_C32(0xb12c0000), SPH_C32(0x30d80000), + SPH_C32(0x14445000), SPH_C32(0xc15860a2), SPH_C32(0x3127e8ec), + SPH_C32(0x2e98bf23), SPH_C32(0x551e3d6e), SPH_C32(0x02f20000), + SPH_C32(0xa2810000), SPH_C32(0x873f0000), SPH_C32(0xe36c7800), + SPH_C32(0x1e1d74ef), SPH_C32(0x073d2bd6), SPH_C32(0xc4c23237), + SPH_C32(0x7f32259e) } +}; + +static const sph_u32 T512_52[4][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0xb4310000), SPH_C32(0x77330000), SPH_C32(0xb15d0000), + SPH_C32(0x7fd004e0), SPH_C32(0x78a26138), SPH_C32(0xd116c35d), + SPH_C32(0xd256d489), SPH_C32(0x4e6f74de), SPH_C32(0xe3060000), + SPH_C32(0xbdc10000), SPH_C32(0x87130000), SPH_C32(0xbff20060), + SPH_C32(0x2eba0a1a), SPH_C32(0x8db53751), SPH_C32(0x73c5ab06), + SPH_C32(0x5bd61539) }, + { SPH_C32(0xe3060000), SPH_C32(0xbdc10000), SPH_C32(0x87130000), + SPH_C32(0xbff20060), SPH_C32(0x2eba0a1a), SPH_C32(0x8db53751), + SPH_C32(0x73c5ab06), SPH_C32(0x5bd61539), SPH_C32(0x57370000), + SPH_C32(0xcaf20000), SPH_C32(0x364e0000), SPH_C32(0xc0220480), + SPH_C32(0x56186b22), SPH_C32(0x5ca3f40c), SPH_C32(0xa1937f8f), + SPH_C32(0x15b961e7) }, + { SPH_C32(0x57370000), SPH_C32(0xcaf20000), SPH_C32(0x364e0000), + SPH_C32(0xc0220480), SPH_C32(0x56186b22), SPH_C32(0x5ca3f40c), + SPH_C32(0xa1937f8f), SPH_C32(0x15b961e7), SPH_C32(0xb4310000), + SPH_C32(0x77330000), SPH_C32(0xb15d0000), SPH_C32(0x7fd004e0), + SPH_C32(0x78a26138), SPH_C32(0xd116c35d), SPH_C32(0xd256d489), + SPH_C32(0x4e6f74de) } +}; + +static const sph_u32 T512_54[4][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0xe6280000), SPH_C32(0x4c4b0000), SPH_C32(0xa8550000), + SPH_C32(0xd3d002e0), SPH_C32(0xd86130b8), SPH_C32(0x98a7b0da), + SPH_C32(0x289506b4), SPH_C32(0xd75a4897), SPH_C32(0xf0c50000), + SPH_C32(0x59230000), SPH_C32(0x45820000), SPH_C32(0xe18d00c0), + SPH_C32(0x3b6d0631), SPH_C32(0xc2ed5699), SPH_C32(0xcbe0fe1c), + SPH_C32(0x56a7b19f) }, + { SPH_C32(0xf0c50000), SPH_C32(0x59230000), SPH_C32(0x45820000), + SPH_C32(0xe18d00c0), SPH_C32(0x3b6d0631), SPH_C32(0xc2ed5699), + SPH_C32(0xcbe0fe1c), SPH_C32(0x56a7b19f), SPH_C32(0x16ed0000), + SPH_C32(0x15680000), SPH_C32(0xedd70000), SPH_C32(0x325d0220), + SPH_C32(0xe30c3689), SPH_C32(0x5a4ae643), SPH_C32(0xe375f8a8), + SPH_C32(0x81fdf908) }, + { SPH_C32(0x16ed0000), SPH_C32(0x15680000), SPH_C32(0xedd70000), + SPH_C32(0x325d0220), SPH_C32(0xe30c3689), SPH_C32(0x5a4ae643), + SPH_C32(0xe375f8a8), SPH_C32(0x81fdf908), SPH_C32(0xe6280000), + SPH_C32(0x4c4b0000), SPH_C32(0xa8550000), SPH_C32(0xd3d002e0), + SPH_C32(0xd86130b8), SPH_C32(0x98a7b0da), SPH_C32(0x289506b4), + SPH_C32(0xd75a4897) } +}; + +static const sph_u32 T512_56[4][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0xee930000), SPH_C32(0xd6070000), SPH_C32(0x92c10000), + SPH_C32(0x2b9801e0), SPH_C32(0x9451287c), SPH_C32(0x3b6cfb57), + SPH_C32(0x45312374), SPH_C32(0x201f6a64), SPH_C32(0x7b280000), + SPH_C32(0x57420000), SPH_C32(0xa9e50000), SPH_C32(0x634300a0), + SPH_C32(0x9edb442f), SPH_C32(0x6d9995bb), SPH_C32(0x27f83b03), + SPH_C32(0xc7ff60f0) }, + { SPH_C32(0x7b280000), SPH_C32(0x57420000), SPH_C32(0xa9e50000), + SPH_C32(0x634300a0), SPH_C32(0x9edb442f), SPH_C32(0x6d9995bb), + SPH_C32(0x27f83b03), SPH_C32(0xc7ff60f0), SPH_C32(0x95bb0000), + SPH_C32(0x81450000), SPH_C32(0x3b240000), SPH_C32(0x48db0140), + SPH_C32(0x0a8a6c53), SPH_C32(0x56f56eec), SPH_C32(0x62c91877), + SPH_C32(0xe7e00a94) }, + { SPH_C32(0x95bb0000), SPH_C32(0x81450000), SPH_C32(0x3b240000), + SPH_C32(0x48db0140), SPH_C32(0x0a8a6c53), SPH_C32(0x56f56eec), + SPH_C32(0x62c91877), SPH_C32(0xe7e00a94), SPH_C32(0xee930000), + SPH_C32(0xd6070000), SPH_C32(0x92c10000), SPH_C32(0x2b9801e0), + SPH_C32(0x9451287c), SPH_C32(0x3b6cfb57), SPH_C32(0x45312374), + SPH_C32(0x201f6a64) } +}; + +static const sph_u32 T512_58[4][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0x5fa80000), SPH_C32(0x56030000), SPH_C32(0x43ae0000), + SPH_C32(0x64f30013), SPH_C32(0x257e86bf), SPH_C32(0x1311944e), + SPH_C32(0x541e95bf), SPH_C32(0x8ea4db69), SPH_C32(0x00440000), + SPH_C32(0x7f480000), SPH_C32(0xda7c0000), SPH_C32(0x2a230001), + SPH_C32(0x3badc9cc), SPH_C32(0xa9b69c87), SPH_C32(0x030a9e60), + SPH_C32(0xbe0a679e) }, + { SPH_C32(0x00440000), SPH_C32(0x7f480000), SPH_C32(0xda7c0000), + SPH_C32(0x2a230001), SPH_C32(0x3badc9cc), SPH_C32(0xa9b69c87), + SPH_C32(0x030a9e60), SPH_C32(0xbe0a679e), SPH_C32(0x5fec0000), + SPH_C32(0x294b0000), SPH_C32(0x99d20000), SPH_C32(0x4ed00012), + SPH_C32(0x1ed34f73), SPH_C32(0xbaa708c9), SPH_C32(0x57140bdf), + SPH_C32(0x30aebcf7) }, + { SPH_C32(0x5fec0000), SPH_C32(0x294b0000), SPH_C32(0x99d20000), + SPH_C32(0x4ed00012), SPH_C32(0x1ed34f73), SPH_C32(0xbaa708c9), + SPH_C32(0x57140bdf), SPH_C32(0x30aebcf7), SPH_C32(0x5fa80000), + SPH_C32(0x56030000), SPH_C32(0x43ae0000), SPH_C32(0x64f30013), + SPH_C32(0x257e86bf), SPH_C32(0x1311944e), SPH_C32(0x541e95bf), + SPH_C32(0x8ea4db69) } +}; + +static const sph_u32 T512_60[4][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0x01930000), SPH_C32(0xe7820000), SPH_C32(0xedfb0000), + SPH_C32(0xcf0c000b), SPH_C32(0x8dd08d58), SPH_C32(0xbca3b42e), + SPH_C32(0x063661e1), SPH_C32(0x536f9e7b), SPH_C32(0x92280000), + SPH_C32(0xdc850000), SPH_C32(0x57fa0000), SPH_C32(0x56dc0003), + SPH_C32(0xbae92316), SPH_C32(0x5aefa30c), SPH_C32(0x90cef752), + SPH_C32(0x7b1675d7) }, + { SPH_C32(0x92280000), SPH_C32(0xdc850000), SPH_C32(0x57fa0000), + SPH_C32(0x56dc0003), SPH_C32(0xbae92316), SPH_C32(0x5aefa30c), + SPH_C32(0x90cef752), SPH_C32(0x7b1675d7), SPH_C32(0x93bb0000), + SPH_C32(0x3b070000), SPH_C32(0xba010000), SPH_C32(0x99d00008), + SPH_C32(0x3739ae4e), SPH_C32(0xe64c1722), SPH_C32(0x96f896b3), + SPH_C32(0x2879ebac) }, + { SPH_C32(0x93bb0000), SPH_C32(0x3b070000), SPH_C32(0xba010000), + SPH_C32(0x99d00008), SPH_C32(0x3739ae4e), SPH_C32(0xe64c1722), + SPH_C32(0x96f896b3), SPH_C32(0x2879ebac), SPH_C32(0x01930000), + SPH_C32(0xe7820000), SPH_C32(0xedfb0000), SPH_C32(0xcf0c000b), + SPH_C32(0x8dd08d58), SPH_C32(0xbca3b42e), SPH_C32(0x063661e1), + SPH_C32(0x536f9e7b) } +}; + +static const sph_u32 T512_62[4][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0x033d0000), SPH_C32(0x08b30000), SPH_C32(0xf33a0000), + SPH_C32(0x3ac20007), SPH_C32(0x51298a50), SPH_C32(0x6b6e661f), + SPH_C32(0x0ea5cfe3), SPH_C32(0xe6da7ffe), SPH_C32(0xa8da0000), + SPH_C32(0x96be0000), SPH_C32(0x5c1d0000), SPH_C32(0x07da0002), + SPH_C32(0x7d669583), SPH_C32(0x1f98708a), SPH_C32(0xbb668808), + SPH_C32(0xda878000) }, + { SPH_C32(0xa8da0000), SPH_C32(0x96be0000), SPH_C32(0x5c1d0000), + SPH_C32(0x07da0002), SPH_C32(0x7d669583), SPH_C32(0x1f98708a), + SPH_C32(0xbb668808), SPH_C32(0xda878000), SPH_C32(0xabe70000), + SPH_C32(0x9e0d0000), SPH_C32(0xaf270000), SPH_C32(0x3d180005), + SPH_C32(0x2c4f1fd3), SPH_C32(0x74f61695), SPH_C32(0xb5c347eb), + SPH_C32(0x3c5dfffe) }, + { SPH_C32(0xabe70000), SPH_C32(0x9e0d0000), SPH_C32(0xaf270000), + SPH_C32(0x3d180005), SPH_C32(0x2c4f1fd3), SPH_C32(0x74f61695), + SPH_C32(0xb5c347eb), SPH_C32(0x3c5dfffe), SPH_C32(0x033d0000), + SPH_C32(0x08b30000), SPH_C32(0xf33a0000), SPH_C32(0x3ac20007), + SPH_C32(0x51298a50), SPH_C32(0x6b6e661f), SPH_C32(0x0ea5cfe3), + SPH_C32(0xe6da7ffe) } +}; + +#define INPUT_BIG do { \ + unsigned acc = buf[0]; \ + const sph_u32 *rp; \ + rp = &T512_0[acc >> 6][0]; \ + m0 = rp[0]; \ + m1 = rp[1]; \ + m2 = rp[2]; \ + m3 = rp[3]; \ + m4 = rp[4]; \ + m5 = rp[5]; \ + m6 = rp[6]; \ + m7 = rp[7]; \ + m8 = rp[8]; \ + m9 = rp[9]; \ + mA = rp[10]; \ + mB = rp[11]; \ + mC = rp[12]; \ + mD = rp[13]; \ + mE = rp[14]; \ + mF = rp[15]; \ + rp = &T512_2[(acc >> 4) & 0x03][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + m8 ^= rp[8]; \ + m9 ^= rp[9]; \ + mA ^= rp[10]; \ + mB ^= rp[11]; \ + mC ^= rp[12]; \ + mD ^= rp[13]; \ + mE ^= rp[14]; \ + mF ^= rp[15]; \ + rp = &T512_4[(acc >> 2) & 0x03][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + m8 ^= rp[8]; \ + m9 ^= rp[9]; \ + mA ^= rp[10]; \ + mB ^= rp[11]; \ + mC ^= rp[12]; \ + mD ^= rp[13]; \ + mE ^= rp[14]; \ + mF ^= rp[15]; \ + rp = &T512_6[acc & 0x03][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + m8 ^= rp[8]; \ + m9 ^= rp[9]; \ + mA ^= rp[10]; \ + mB ^= rp[11]; \ + mC ^= rp[12]; \ + mD ^= rp[13]; \ + mE ^= rp[14]; \ + mF ^= rp[15]; \ + acc = buf[1]; \ + rp = &T512_8[acc >> 6][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + m8 ^= rp[8]; \ + m9 ^= rp[9]; \ + mA ^= rp[10]; \ + mB ^= rp[11]; \ + mC ^= rp[12]; \ + mD ^= rp[13]; \ + mE ^= rp[14]; \ + mF ^= rp[15]; \ + rp = &T512_10[(acc >> 4) & 0x03][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + m8 ^= rp[8]; \ + m9 ^= rp[9]; \ + mA ^= rp[10]; \ + mB ^= rp[11]; \ + mC ^= rp[12]; \ + mD ^= rp[13]; \ + mE ^= rp[14]; \ + mF ^= rp[15]; \ + rp = &T512_12[(acc >> 2) & 0x03][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + m8 ^= rp[8]; \ + m9 ^= rp[9]; \ + mA ^= rp[10]; \ + mB ^= rp[11]; \ + mC ^= rp[12]; \ + mD ^= rp[13]; \ + mE ^= rp[14]; \ + mF ^= rp[15]; \ + rp = &T512_14[acc & 0x03][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + m8 ^= rp[8]; \ + m9 ^= rp[9]; \ + mA ^= rp[10]; \ + mB ^= rp[11]; \ + mC ^= rp[12]; \ + mD ^= rp[13]; \ + mE ^= rp[14]; \ + mF ^= rp[15]; \ + acc = buf[2]; \ + rp = &T512_16[acc >> 6][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + m8 ^= rp[8]; \ + m9 ^= rp[9]; \ + mA ^= rp[10]; \ + mB ^= rp[11]; \ + mC ^= rp[12]; \ + mD ^= rp[13]; \ + mE ^= rp[14]; \ + mF ^= rp[15]; \ + rp = &T512_18[(acc >> 4) & 0x03][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + m8 ^= rp[8]; \ + m9 ^= rp[9]; \ + mA ^= rp[10]; \ + mB ^= rp[11]; \ + mC ^= rp[12]; \ + mD ^= rp[13]; \ + mE ^= rp[14]; \ + mF ^= rp[15]; \ + rp = &T512_20[(acc >> 2) & 0x03][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + m8 ^= rp[8]; \ + m9 ^= rp[9]; \ + mA ^= rp[10]; \ + mB ^= rp[11]; \ + mC ^= rp[12]; \ + mD ^= rp[13]; \ + mE ^= rp[14]; \ + mF ^= rp[15]; \ + rp = &T512_22[acc & 0x03][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + m8 ^= rp[8]; \ + m9 ^= rp[9]; \ + mA ^= rp[10]; \ + mB ^= rp[11]; \ + mC ^= rp[12]; \ + mD ^= rp[13]; \ + mE ^= rp[14]; \ + mF ^= rp[15]; \ + acc = buf[3]; \ + rp = &T512_24[acc >> 6][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + m8 ^= rp[8]; \ + m9 ^= rp[9]; \ + mA ^= rp[10]; \ + mB ^= rp[11]; \ + mC ^= rp[12]; \ + mD ^= rp[13]; \ + mE ^= rp[14]; \ + mF ^= rp[15]; \ + rp = &T512_26[(acc >> 4) & 0x03][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + m8 ^= rp[8]; \ + m9 ^= rp[9]; \ + mA ^= rp[10]; \ + mB ^= rp[11]; \ + mC ^= rp[12]; \ + mD ^= rp[13]; \ + mE ^= rp[14]; \ + mF ^= rp[15]; \ + rp = &T512_28[(acc >> 2) & 0x03][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + m8 ^= rp[8]; \ + m9 ^= rp[9]; \ + mA ^= rp[10]; \ + mB ^= rp[11]; \ + mC ^= rp[12]; \ + mD ^= rp[13]; \ + mE ^= rp[14]; \ + mF ^= rp[15]; \ + rp = &T512_30[acc & 0x03][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + m8 ^= rp[8]; \ + m9 ^= rp[9]; \ + mA ^= rp[10]; \ + mB ^= rp[11]; \ + mC ^= rp[12]; \ + mD ^= rp[13]; \ + mE ^= rp[14]; \ + mF ^= rp[15]; \ + acc = buf[4]; \ + rp = &T512_32[acc >> 6][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + m8 ^= rp[8]; \ + m9 ^= rp[9]; \ + mA ^= rp[10]; \ + mB ^= rp[11]; \ + mC ^= rp[12]; \ + mD ^= rp[13]; \ + mE ^= rp[14]; \ + mF ^= rp[15]; \ + rp = &T512_34[(acc >> 4) & 0x03][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + m8 ^= rp[8]; \ + m9 ^= rp[9]; \ + mA ^= rp[10]; \ + mB ^= rp[11]; \ + mC ^= rp[12]; \ + mD ^= rp[13]; \ + mE ^= rp[14]; \ + mF ^= rp[15]; \ + rp = &T512_36[(acc >> 2) & 0x03][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + m8 ^= rp[8]; \ + m9 ^= rp[9]; \ + mA ^= rp[10]; \ + mB ^= rp[11]; \ + mC ^= rp[12]; \ + mD ^= rp[13]; \ + mE ^= rp[14]; \ + mF ^= rp[15]; \ + rp = &T512_38[acc & 0x03][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + m8 ^= rp[8]; \ + m9 ^= rp[9]; \ + mA ^= rp[10]; \ + mB ^= rp[11]; \ + mC ^= rp[12]; \ + mD ^= rp[13]; \ + mE ^= rp[14]; \ + mF ^= rp[15]; \ + acc = buf[5]; \ + rp = &T512_40[acc >> 6][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + m8 ^= rp[8]; \ + m9 ^= rp[9]; \ + mA ^= rp[10]; \ + mB ^= rp[11]; \ + mC ^= rp[12]; \ + mD ^= rp[13]; \ + mE ^= rp[14]; \ + mF ^= rp[15]; \ + rp = &T512_42[(acc >> 4) & 0x03][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + m8 ^= rp[8]; \ + m9 ^= rp[9]; \ + mA ^= rp[10]; \ + mB ^= rp[11]; \ + mC ^= rp[12]; \ + mD ^= rp[13]; \ + mE ^= rp[14]; \ + mF ^= rp[15]; \ + rp = &T512_44[(acc >> 2) & 0x03][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + m8 ^= rp[8]; \ + m9 ^= rp[9]; \ + mA ^= rp[10]; \ + mB ^= rp[11]; \ + mC ^= rp[12]; \ + mD ^= rp[13]; \ + mE ^= rp[14]; \ + mF ^= rp[15]; \ + rp = &T512_46[acc & 0x03][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + m8 ^= rp[8]; \ + m9 ^= rp[9]; \ + mA ^= rp[10]; \ + mB ^= rp[11]; \ + mC ^= rp[12]; \ + mD ^= rp[13]; \ + mE ^= rp[14]; \ + mF ^= rp[15]; \ + acc = buf[6]; \ + rp = &T512_48[acc >> 6][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + m8 ^= rp[8]; \ + m9 ^= rp[9]; \ + mA ^= rp[10]; \ + mB ^= rp[11]; \ + mC ^= rp[12]; \ + mD ^= rp[13]; \ + mE ^= rp[14]; \ + mF ^= rp[15]; \ + rp = &T512_50[(acc >> 4) & 0x03][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + m8 ^= rp[8]; \ + m9 ^= rp[9]; \ + mA ^= rp[10]; \ + mB ^= rp[11]; \ + mC ^= rp[12]; \ + mD ^= rp[13]; \ + mE ^= rp[14]; \ + mF ^= rp[15]; \ + rp = &T512_52[(acc >> 2) & 0x03][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + m8 ^= rp[8]; \ + m9 ^= rp[9]; \ + mA ^= rp[10]; \ + mB ^= rp[11]; \ + mC ^= rp[12]; \ + mD ^= rp[13]; \ + mE ^= rp[14]; \ + mF ^= rp[15]; \ + rp = &T512_54[acc & 0x03][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + m8 ^= rp[8]; \ + m9 ^= rp[9]; \ + mA ^= rp[10]; \ + mB ^= rp[11]; \ + mC ^= rp[12]; \ + mD ^= rp[13]; \ + mE ^= rp[14]; \ + mF ^= rp[15]; \ + acc = buf[7]; \ + rp = &T512_56[acc >> 6][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + m8 ^= rp[8]; \ + m9 ^= rp[9]; \ + mA ^= rp[10]; \ + mB ^= rp[11]; \ + mC ^= rp[12]; \ + mD ^= rp[13]; \ + mE ^= rp[14]; \ + mF ^= rp[15]; \ + rp = &T512_58[(acc >> 4) & 0x03][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + m8 ^= rp[8]; \ + m9 ^= rp[9]; \ + mA ^= rp[10]; \ + mB ^= rp[11]; \ + mC ^= rp[12]; \ + mD ^= rp[13]; \ + mE ^= rp[14]; \ + mF ^= rp[15]; \ + rp = &T512_60[(acc >> 2) & 0x03][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + m8 ^= rp[8]; \ + m9 ^= rp[9]; \ + mA ^= rp[10]; \ + mB ^= rp[11]; \ + mC ^= rp[12]; \ + mD ^= rp[13]; \ + mE ^= rp[14]; \ + mF ^= rp[15]; \ + rp = &T512_62[acc & 0x03][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + m8 ^= rp[8]; \ + m9 ^= rp[9]; \ + mA ^= rp[10]; \ + mB ^= rp[11]; \ + mC ^= rp[12]; \ + mD ^= rp[13]; \ + mE ^= rp[14]; \ + mF ^= rp[15]; \ + } while (0) + +#endif + +#if SPH_HAMSI_EXPAND_BIG == 3 + +static const sph_u32 T512_0[8][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0x9cbb1800), SPH_C32(0xb0d30000), SPH_C32(0x92510000), + SPH_C32(0xed930000), SPH_C32(0x593a4345), SPH_C32(0xe114d5f4), + SPH_C32(0x430633da), SPH_C32(0x78cace29), SPH_C32(0xc8934400), + SPH_C32(0x5a3e0000), SPH_C32(0x57870000), SPH_C32(0x4c560000), + SPH_C32(0xea982435), SPH_C32(0x75b11115), SPH_C32(0x28b67247), + SPH_C32(0x2dd1f9ab) }, + { SPH_C32(0x29449c00), SPH_C32(0x64e70000), SPH_C32(0xf24b0000), + SPH_C32(0xc2f30000), SPH_C32(0x0ede4e8f), SPH_C32(0x56c23745), + SPH_C32(0xf3e04259), SPH_C32(0x8d0d9ec4), SPH_C32(0x466d0c00), + SPH_C32(0x08620000), SPH_C32(0xdd5d0000), SPH_C32(0xbadd0000), + SPH_C32(0x6a927942), SPH_C32(0x441f2b93), SPH_C32(0x218ace6f), + SPH_C32(0xbf2c0be2) }, + { SPH_C32(0xb5ff8400), SPH_C32(0xd4340000), SPH_C32(0x601a0000), + SPH_C32(0x2f600000), SPH_C32(0x57e40dca), SPH_C32(0xb7d6e2b1), + SPH_C32(0xb0e67183), SPH_C32(0xf5c750ed), SPH_C32(0x8efe4800), + SPH_C32(0x525c0000), SPH_C32(0x8ada0000), SPH_C32(0xf68b0000), + SPH_C32(0x800a5d77), SPH_C32(0x31ae3a86), SPH_C32(0x093cbc28), + SPH_C32(0x92fdf249) }, + { SPH_C32(0x466d0c00), SPH_C32(0x08620000), SPH_C32(0xdd5d0000), + SPH_C32(0xbadd0000), SPH_C32(0x6a927942), SPH_C32(0x441f2b93), + SPH_C32(0x218ace6f), SPH_C32(0xbf2c0be2), SPH_C32(0x6f299000), + SPH_C32(0x6c850000), SPH_C32(0x2f160000), SPH_C32(0x782e0000), + SPH_C32(0x644c37cd), SPH_C32(0x12dd1cd6), SPH_C32(0xd26a8c36), + SPH_C32(0x32219526) }, + { SPH_C32(0xdad61400), SPH_C32(0xb8b10000), SPH_C32(0x4f0c0000), + SPH_C32(0x574e0000), SPH_C32(0x33a83a07), SPH_C32(0xa50bfe67), + SPH_C32(0x628cfdb5), SPH_C32(0xc7e6c5cb), SPH_C32(0xa7bad400), + SPH_C32(0x36bb0000), SPH_C32(0x78910000), SPH_C32(0x34780000), + SPH_C32(0x8ed413f8), SPH_C32(0x676c0dc3), SPH_C32(0xfadcfe71), + SPH_C32(0x1ff06c8d) }, + { SPH_C32(0x6f299000), SPH_C32(0x6c850000), SPH_C32(0x2f160000), + SPH_C32(0x782e0000), SPH_C32(0x644c37cd), SPH_C32(0x12dd1cd6), + SPH_C32(0xd26a8c36), SPH_C32(0x32219526), SPH_C32(0x29449c00), + SPH_C32(0x64e70000), SPH_C32(0xf24b0000), SPH_C32(0xc2f30000), + SPH_C32(0x0ede4e8f), SPH_C32(0x56c23745), SPH_C32(0xf3e04259), + SPH_C32(0x8d0d9ec4) }, + { SPH_C32(0xf3928800), SPH_C32(0xdc560000), SPH_C32(0xbd470000), + SPH_C32(0x95bd0000), SPH_C32(0x3d767488), SPH_C32(0xf3c9c922), + SPH_C32(0x916cbfec), SPH_C32(0x4aeb5b0f), SPH_C32(0xe1d7d800), + SPH_C32(0x3ed90000), SPH_C32(0xa5cc0000), SPH_C32(0x8ea50000), + SPH_C32(0xe4466aba), SPH_C32(0x23732650), SPH_C32(0xdb56301e), + SPH_C32(0xa0dc676f) } +}; + +static const sph_u32 T512_3[8][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0x145a3c00), SPH_C32(0xb9e90000), SPH_C32(0x61270000), + SPH_C32(0xf1610000), SPH_C32(0xce613d6c), SPH_C32(0xb0493d78), + SPH_C32(0x47a96720), SPH_C32(0xe18e24c5), SPH_C32(0x23671400), + SPH_C32(0xc8b90000), SPH_C32(0xf4c70000), SPH_C32(0xfb750000), + SPH_C32(0x73cd2465), SPH_C32(0xf8a6a549), SPH_C32(0x02c40a3f), + SPH_C32(0xdc24e61f) }, + { SPH_C32(0x23671400), SPH_C32(0xc8b90000), SPH_C32(0xf4c70000), + SPH_C32(0xfb750000), SPH_C32(0x73cd2465), SPH_C32(0xf8a6a549), + SPH_C32(0x02c40a3f), SPH_C32(0xdc24e61f), SPH_C32(0x373d2800), + SPH_C32(0x71500000), SPH_C32(0x95e00000), SPH_C32(0x0a140000), + SPH_C32(0xbdac1909), SPH_C32(0x48ef9831), SPH_C32(0x456d6d1f), + SPH_C32(0x3daac2da) }, + { SPH_C32(0x373d2800), SPH_C32(0x71500000), SPH_C32(0x95e00000), + SPH_C32(0x0a140000), SPH_C32(0xbdac1909), SPH_C32(0x48ef9831), + SPH_C32(0x456d6d1f), SPH_C32(0x3daac2da), SPH_C32(0x145a3c00), + SPH_C32(0xb9e90000), SPH_C32(0x61270000), SPH_C32(0xf1610000), + SPH_C32(0xce613d6c), SPH_C32(0xb0493d78), SPH_C32(0x47a96720), + SPH_C32(0xe18e24c5) }, + { SPH_C32(0x54285c00), SPH_C32(0xeaed0000), SPH_C32(0xc5d60000), + SPH_C32(0xa1c50000), SPH_C32(0xb3a26770), SPH_C32(0x94a5c4e1), + SPH_C32(0x6bb0419d), SPH_C32(0x551b3782), SPH_C32(0x9cbb1800), + SPH_C32(0xb0d30000), SPH_C32(0x92510000), SPH_C32(0xed930000), + SPH_C32(0x593a4345), SPH_C32(0xe114d5f4), SPH_C32(0x430633da), + SPH_C32(0x78cace29) }, + { SPH_C32(0x40726000), SPH_C32(0x53040000), SPH_C32(0xa4f10000), + SPH_C32(0x50a40000), SPH_C32(0x7dc35a1c), SPH_C32(0x24ecf999), + SPH_C32(0x2c1926bd), SPH_C32(0xb4951347), SPH_C32(0xbfdc0c00), + SPH_C32(0x786a0000), SPH_C32(0x66960000), SPH_C32(0x16e60000), + SPH_C32(0x2af76720), SPH_C32(0x19b270bd), SPH_C32(0x41c239e5), + SPH_C32(0xa4ee2836) }, + { SPH_C32(0x774f4800), SPH_C32(0x22540000), SPH_C32(0x31110000), + SPH_C32(0x5ab00000), SPH_C32(0xc06f4315), SPH_C32(0x6c0361a8), + SPH_C32(0x69744ba2), SPH_C32(0x893fd19d), SPH_C32(0xab863000), + SPH_C32(0xc1830000), SPH_C32(0x07b10000), SPH_C32(0xe7870000), + SPH_C32(0xe4965a4c), SPH_C32(0xa9fb4dc5), SPH_C32(0x066b5ec5), + SPH_C32(0x45600cf3) }, + { SPH_C32(0x63157400), SPH_C32(0x9bbd0000), SPH_C32(0x50360000), + SPH_C32(0xabd10000), SPH_C32(0x0e0e7e79), SPH_C32(0xdc4a5cd0), + SPH_C32(0x2edd2c82), SPH_C32(0x68b1f558), SPH_C32(0x88e12400), + SPH_C32(0x093a0000), SPH_C32(0xf3760000), SPH_C32(0x1cf20000), + SPH_C32(0x975b7e29), SPH_C32(0x515de88c), SPH_C32(0x04af54fa), + SPH_C32(0x9944eaec) } +}; + +static const sph_u32 T512_6[8][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0xb4370060), SPH_C32(0x0c4c0000), SPH_C32(0x56c20000), + SPH_C32(0x5cae0000), SPH_C32(0x94541f3f), SPH_C32(0x3b3ef825), + SPH_C32(0x1b365f3d), SPH_C32(0xf3d45758), SPH_C32(0x5cb00110), + SPH_C32(0x913e0000), SPH_C32(0x44190000), SPH_C32(0x888c0000), + SPH_C32(0x66dc7418), SPH_C32(0x921f1d66), SPH_C32(0x55ceea25), + SPH_C32(0x925c44e9) }, + { SPH_C32(0xef0b0270), SPH_C32(0x3afd0000), SPH_C32(0x5dae0000), + SPH_C32(0x69490000), SPH_C32(0x9b0f3c06), SPH_C32(0x4405b5f9), + SPH_C32(0x66140a51), SPH_C32(0x924f5d0a), SPH_C32(0xc96b0030), + SPH_C32(0xe7250000), SPH_C32(0x2f840000), SPH_C32(0x264f0000), + SPH_C32(0x08695bf9), SPH_C32(0x6dfcf137), SPH_C32(0x509f6984), + SPH_C32(0x9e69af68) }, + { SPH_C32(0x5b3c0210), SPH_C32(0x36b10000), SPH_C32(0x0b6c0000), + SPH_C32(0x35e70000), SPH_C32(0x0f5b2339), SPH_C32(0x7f3b4ddc), + SPH_C32(0x7d22556c), SPH_C32(0x619b0a52), SPH_C32(0x95db0120), + SPH_C32(0x761b0000), SPH_C32(0x6b9d0000), SPH_C32(0xaec30000), + SPH_C32(0x6eb52fe1), SPH_C32(0xffe3ec51), SPH_C32(0x055183a1), + SPH_C32(0x0c35eb81) }, + { SPH_C32(0xc96b0030), SPH_C32(0xe7250000), SPH_C32(0x2f840000), + SPH_C32(0x264f0000), SPH_C32(0x08695bf9), SPH_C32(0x6dfcf137), + SPH_C32(0x509f6984), SPH_C32(0x9e69af68), SPH_C32(0x26600240), + SPH_C32(0xddd80000), SPH_C32(0x722a0000), SPH_C32(0x4f060000), + SPH_C32(0x936667ff), SPH_C32(0x29f944ce), SPH_C32(0x368b63d5), + SPH_C32(0x0c26f262) }, + { SPH_C32(0x7d5c0050), SPH_C32(0xeb690000), SPH_C32(0x79460000), + SPH_C32(0x7ae10000), SPH_C32(0x9c3d44c6), SPH_C32(0x56c20912), + SPH_C32(0x4ba936b9), SPH_C32(0x6dbdf830), SPH_C32(0x7ad00350), + SPH_C32(0x4ce60000), SPH_C32(0x36330000), SPH_C32(0xc78a0000), + SPH_C32(0xf5ba13e7), SPH_C32(0xbbe659a8), SPH_C32(0x634589f0), + SPH_C32(0x9e7ab68b) }, + { SPH_C32(0x26600240), SPH_C32(0xddd80000), SPH_C32(0x722a0000), + SPH_C32(0x4f060000), SPH_C32(0x936667ff), SPH_C32(0x29f944ce), + SPH_C32(0x368b63d5), SPH_C32(0x0c26f262), SPH_C32(0xef0b0270), + SPH_C32(0x3afd0000), SPH_C32(0x5dae0000), SPH_C32(0x69490000), + SPH_C32(0x9b0f3c06), SPH_C32(0x4405b5f9), SPH_C32(0x66140a51), + SPH_C32(0x924f5d0a) }, + { SPH_C32(0x92570220), SPH_C32(0xd1940000), SPH_C32(0x24e80000), + SPH_C32(0x13a80000), SPH_C32(0x073278c0), SPH_C32(0x12c7bceb), + SPH_C32(0x2dbd3ce8), SPH_C32(0xfff2a53a), SPH_C32(0xb3bb0360), + SPH_C32(0xabc30000), SPH_C32(0x19b70000), SPH_C32(0xe1c50000), + SPH_C32(0xfdd3481e), SPH_C32(0xd61aa89f), SPH_C32(0x33dae074), + SPH_C32(0x001319e3) } +}; + +static const sph_u32 T512_9[8][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0x774400f0), SPH_C32(0xf15a0000), SPH_C32(0xf5b20000), + SPH_C32(0x34140000), SPH_C32(0x89377e8c), SPH_C32(0x5a8bec25), + SPH_C32(0x0bc3cd1e), SPH_C32(0xcf3775cb), SPH_C32(0xf46c0050), + SPH_C32(0x96180000), SPH_C32(0x14a50000), SPH_C32(0x031f0000), + SPH_C32(0x42947eb8), SPH_C32(0x66bf7e19), SPH_C32(0x9ca470d2), + SPH_C32(0x8a341574) }, + { SPH_C32(0xf46c0050), SPH_C32(0x96180000), SPH_C32(0x14a50000), + SPH_C32(0x031f0000), SPH_C32(0x42947eb8), SPH_C32(0x66bf7e19), + SPH_C32(0x9ca470d2), SPH_C32(0x8a341574), SPH_C32(0x832800a0), + SPH_C32(0x67420000), SPH_C32(0xe1170000), SPH_C32(0x370b0000), + SPH_C32(0xcba30034), SPH_C32(0x3c34923c), SPH_C32(0x9767bdcc), + SPH_C32(0x450360bf) }, + { SPH_C32(0x832800a0), SPH_C32(0x67420000), SPH_C32(0xe1170000), + SPH_C32(0x370b0000), SPH_C32(0xcba30034), SPH_C32(0x3c34923c), + SPH_C32(0x9767bdcc), SPH_C32(0x450360bf), SPH_C32(0x774400f0), + SPH_C32(0xf15a0000), SPH_C32(0xf5b20000), SPH_C32(0x34140000), + SPH_C32(0x89377e8c), SPH_C32(0x5a8bec25), SPH_C32(0x0bc3cd1e), + SPH_C32(0xcf3775cb) }, + { SPH_C32(0xe8870170), SPH_C32(0x9d720000), SPH_C32(0x12db0000), + SPH_C32(0xd4220000), SPH_C32(0xf2886b27), SPH_C32(0xa921e543), + SPH_C32(0x4ef8b518), SPH_C32(0x618813b1), SPH_C32(0xb4370060), + SPH_C32(0x0c4c0000), SPH_C32(0x56c20000), SPH_C32(0x5cae0000), + SPH_C32(0x94541f3f), SPH_C32(0x3b3ef825), SPH_C32(0x1b365f3d), + SPH_C32(0xf3d45758) }, + { SPH_C32(0x9fc30180), SPH_C32(0x6c280000), SPH_C32(0xe7690000), + SPH_C32(0xe0360000), SPH_C32(0x7bbf15ab), SPH_C32(0xf3aa0966), + SPH_C32(0x453b7806), SPH_C32(0xaebf667a), SPH_C32(0x405b0030), + SPH_C32(0x9a540000), SPH_C32(0x42670000), SPH_C32(0x5fb10000), + SPH_C32(0xd6c06187), SPH_C32(0x5d81863c), SPH_C32(0x87922fef), + SPH_C32(0x79e0422c) }, + { SPH_C32(0x1ceb0120), SPH_C32(0x0b6a0000), SPH_C32(0x067e0000), + SPH_C32(0xd73d0000), SPH_C32(0xb01c159f), SPH_C32(0xcf9e9b5a), + SPH_C32(0xd25cc5ca), SPH_C32(0xebbc06c5), SPH_C32(0x371f00c0), + SPH_C32(0x6b0e0000), SPH_C32(0xb7d50000), SPH_C32(0x6ba50000), + SPH_C32(0x5ff71f0b), SPH_C32(0x070a6a19), SPH_C32(0x8c51e2f1), + SPH_C32(0xb6d737e7) }, + { SPH_C32(0x6baf01d0), SPH_C32(0xfa300000), SPH_C32(0xf3cc0000), + SPH_C32(0xe3290000), SPH_C32(0x392b6b13), SPH_C32(0x9515777f), + SPH_C32(0xd99f08d4), SPH_C32(0x248b730e), SPH_C32(0xc3730090), + SPH_C32(0xfd160000), SPH_C32(0xa3700000), SPH_C32(0x68ba0000), + SPH_C32(0x1d6361b3), SPH_C32(0x61b51400), SPH_C32(0x10f59223), + SPH_C32(0x3ce32293) } +}; + +static const sph_u32 T512_12[8][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0xa67f0001), SPH_C32(0x71378000), SPH_C32(0x19fc0000), + SPH_C32(0x96db0000), SPH_C32(0x3a8b6dfd), SPH_C32(0xebcaaef3), + SPH_C32(0x2c6d478f), SPH_C32(0xac8e6c88), SPH_C32(0x50ff0004), + SPH_C32(0x45744000), SPH_C32(0x3dfb0000), SPH_C32(0x19e60000), + SPH_C32(0x1bbc5606), SPH_C32(0xe1727b5d), SPH_C32(0xe1a8cc96), + SPH_C32(0x7b1bd6b9) }, + { SPH_C32(0xf7750009), SPH_C32(0xcf3cc000), SPH_C32(0xc3d60000), + SPH_C32(0x04920000), SPH_C32(0x029519a9), SPH_C32(0xf8e836ba), + SPH_C32(0x7a87f14e), SPH_C32(0x9e16981a), SPH_C32(0xd46a0000), + SPH_C32(0x8dc8c000), SPH_C32(0xa5af0000), SPH_C32(0x4a290000), + SPH_C32(0xfc4e427a), SPH_C32(0xc9b4866c), SPH_C32(0x98369604), + SPH_C32(0xf746c320) }, + { SPH_C32(0x510a0008), SPH_C32(0xbe0b4000), SPH_C32(0xda2a0000), + SPH_C32(0x92490000), SPH_C32(0x381e7454), SPH_C32(0x13229849), + SPH_C32(0x56eab6c1), SPH_C32(0x3298f492), SPH_C32(0x84950004), + SPH_C32(0xc8bc8000), SPH_C32(0x98540000), SPH_C32(0x53cf0000), + SPH_C32(0xe7f2147c), SPH_C32(0x28c6fd31), SPH_C32(0x799e5a92), + SPH_C32(0x8c5d1599) }, + { SPH_C32(0xd46a0000), SPH_C32(0x8dc8c000), SPH_C32(0xa5af0000), + SPH_C32(0x4a290000), SPH_C32(0xfc4e427a), SPH_C32(0xc9b4866c), + SPH_C32(0x98369604), SPH_C32(0xf746c320), SPH_C32(0x231f0009), + SPH_C32(0x42f40000), SPH_C32(0x66790000), SPH_C32(0x4ebb0000), + SPH_C32(0xfedb5bd3), SPH_C32(0x315cb0d6), SPH_C32(0xe2b1674a), + SPH_C32(0x69505b3a) }, + { SPH_C32(0x72150001), SPH_C32(0xfcff4000), SPH_C32(0xbc530000), + SPH_C32(0xdcf20000), SPH_C32(0xc6c52f87), SPH_C32(0x227e289f), + SPH_C32(0xb45bd18b), SPH_C32(0x5bc8afa8), SPH_C32(0x73e0000d), + SPH_C32(0x07804000), SPH_C32(0x5b820000), SPH_C32(0x575d0000), + SPH_C32(0xe5670dd5), SPH_C32(0xd02ecb8b), SPH_C32(0x0319abdc), + SPH_C32(0x124b8d83) }, + { SPH_C32(0x231f0009), SPH_C32(0x42f40000), SPH_C32(0x66790000), + SPH_C32(0x4ebb0000), SPH_C32(0xfedb5bd3), SPH_C32(0x315cb0d6), + SPH_C32(0xe2b1674a), SPH_C32(0x69505b3a), SPH_C32(0xf7750009), + SPH_C32(0xcf3cc000), SPH_C32(0xc3d60000), SPH_C32(0x04920000), + SPH_C32(0x029519a9), SPH_C32(0xf8e836ba), SPH_C32(0x7a87f14e), + SPH_C32(0x9e16981a) }, + { SPH_C32(0x85600008), SPH_C32(0x33c38000), SPH_C32(0x7f850000), + SPH_C32(0xd8600000), SPH_C32(0xc450362e), SPH_C32(0xda961e25), + SPH_C32(0xcedc20c5), SPH_C32(0xc5de37b2), SPH_C32(0xa78a000d), + SPH_C32(0x8a488000), SPH_C32(0xfe2d0000), SPH_C32(0x1d740000), + SPH_C32(0x19294faf), SPH_C32(0x199a4de7), SPH_C32(0x9b2f3dd8), + SPH_C32(0xe50d4ea3) } +}; + +static const sph_u32 T512_15[8][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0x75c90003), SPH_C32(0x0e10c000), SPH_C32(0xd1200000), + SPH_C32(0xbaea0000), SPH_C32(0x8bc42f3e), SPH_C32(0x8758b757), + SPH_C32(0xbb28761d), SPH_C32(0x00b72e2b), SPH_C32(0xeecf0001), + SPH_C32(0x6f564000), SPH_C32(0xf33e0000), SPH_C32(0xa79e0000), + SPH_C32(0xbdb57219), SPH_C32(0xb711ebc5), SPH_C32(0x4a3b40ba), + SPH_C32(0xfeabf254) }, + { SPH_C32(0xeecf0001), SPH_C32(0x6f564000), SPH_C32(0xf33e0000), + SPH_C32(0xa79e0000), SPH_C32(0xbdb57219), SPH_C32(0xb711ebc5), + SPH_C32(0x4a3b40ba), SPH_C32(0xfeabf254), SPH_C32(0x9b060002), + SPH_C32(0x61468000), SPH_C32(0x221e0000), SPH_C32(0x1d740000), + SPH_C32(0x36715d27), SPH_C32(0x30495c92), SPH_C32(0xf11336a7), + SPH_C32(0xfe1cdc7f) }, + { SPH_C32(0x9b060002), SPH_C32(0x61468000), SPH_C32(0x221e0000), + SPH_C32(0x1d740000), SPH_C32(0x36715d27), SPH_C32(0x30495c92), + SPH_C32(0xf11336a7), SPH_C32(0xfe1cdc7f), SPH_C32(0x75c90003), + SPH_C32(0x0e10c000), SPH_C32(0xd1200000), SPH_C32(0xbaea0000), + SPH_C32(0x8bc42f3e), SPH_C32(0x8758b757), SPH_C32(0xbb28761d), + SPH_C32(0x00b72e2b) }, + { SPH_C32(0xf6800005), SPH_C32(0x3443c000), SPH_C32(0x24070000), + SPH_C32(0x8f3d0000), SPH_C32(0x21373bfb), SPH_C32(0x0ab8d5ae), + SPH_C32(0xcdc58b19), SPH_C32(0xd795ba31), SPH_C32(0xa67f0001), + SPH_C32(0x71378000), SPH_C32(0x19fc0000), SPH_C32(0x96db0000), + SPH_C32(0x3a8b6dfd), SPH_C32(0xebcaaef3), SPH_C32(0x2c6d478f), + SPH_C32(0xac8e6c88) }, + { SPH_C32(0x83490006), SPH_C32(0x3a530000), SPH_C32(0xf5270000), + SPH_C32(0x35d70000), SPH_C32(0xaaf314c5), SPH_C32(0x8de062f9), + SPH_C32(0x76edfd04), SPH_C32(0xd722941a), SPH_C32(0x48b00000), + SPH_C32(0x1e61c000), SPH_C32(0xeac20000), SPH_C32(0x31450000), + SPH_C32(0x873e1fe4), SPH_C32(0x5cdb4536), SPH_C32(0x66560735), + SPH_C32(0x52259edc) }, + { SPH_C32(0x184f0004), SPH_C32(0x5b158000), SPH_C32(0xd7390000), + SPH_C32(0x28a30000), SPH_C32(0x9c8249e2), SPH_C32(0xbda93e6b), + SPH_C32(0x87fecba3), SPH_C32(0x293e4865), SPH_C32(0x3d790003), + SPH_C32(0x10710000), SPH_C32(0x3be20000), SPH_C32(0x8baf0000), + SPH_C32(0x0cfa30da), SPH_C32(0xdb83f261), SPH_C32(0xdd7e7128), + SPH_C32(0x5292b0f7) }, + { SPH_C32(0x6d860007), SPH_C32(0x55054000), SPH_C32(0x06190000), + SPH_C32(0x92490000), SPH_C32(0x174666dc), SPH_C32(0x3af1893c), + SPH_C32(0x3cd6bdbe), SPH_C32(0x2989664e), SPH_C32(0xd3b60002), + SPH_C32(0x7f274000), SPH_C32(0xc8dc0000), SPH_C32(0x2c310000), + SPH_C32(0xb14f42c3), SPH_C32(0x6c9219a4), SPH_C32(0x97453192), + SPH_C32(0xac3942a3) } +}; + +static const sph_u32 T512_18[8][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0xb83d0000), SPH_C32(0x16710600), SPH_C32(0x379a0000), + SPH_C32(0xf5b10000), SPH_C32(0x228161ac), SPH_C32(0xae48f145), + SPH_C32(0x66241616), SPH_C32(0xc5c1eb3e), SPH_C32(0xfd250000), + SPH_C32(0xb3c41100), SPH_C32(0xcef00000), SPH_C32(0xcef90000), + SPH_C32(0x3c4d7580), SPH_C32(0x8d5b6493), SPH_C32(0x7098b0a6), + SPH_C32(0x1af21fe1) }, + { SPH_C32(0x75a40000), SPH_C32(0xc28b2700), SPH_C32(0x94a40000), + SPH_C32(0x90f50000), SPH_C32(0xfb7857e0), SPH_C32(0x49ce0bae), + SPH_C32(0x1767c483), SPH_C32(0xaedf667e), SPH_C32(0xd1660000), + SPH_C32(0x1bbc0300), SPH_C32(0x9eec0000), SPH_C32(0xf6940000), + SPH_C32(0x03024527), SPH_C32(0xcf70fcf2), SPH_C32(0xb4431b17), + SPH_C32(0x857f3c2b) }, + { SPH_C32(0xcd990000), SPH_C32(0xd4fa2100), SPH_C32(0xa33e0000), + SPH_C32(0x65440000), SPH_C32(0xd9f9364c), SPH_C32(0xe786faeb), + SPH_C32(0x7143d295), SPH_C32(0x6b1e8d40), SPH_C32(0x2c430000), + SPH_C32(0xa8781200), SPH_C32(0x501c0000), SPH_C32(0x386d0000), + SPH_C32(0x3f4f30a7), SPH_C32(0x422b9861), SPH_C32(0xc4dbabb1), + SPH_C32(0x9f8d23ca) }, + { SPH_C32(0xd1660000), SPH_C32(0x1bbc0300), SPH_C32(0x9eec0000), + SPH_C32(0xf6940000), SPH_C32(0x03024527), SPH_C32(0xcf70fcf2), + SPH_C32(0xb4431b17), SPH_C32(0x857f3c2b), SPH_C32(0xa4c20000), + SPH_C32(0xd9372400), SPH_C32(0x0a480000), SPH_C32(0x66610000), + SPH_C32(0xf87a12c7), SPH_C32(0x86bef75c), SPH_C32(0xa324df94), + SPH_C32(0x2ba05a55) }, + { SPH_C32(0x695b0000), SPH_C32(0x0dcd0500), SPH_C32(0xa9760000), + SPH_C32(0x03250000), SPH_C32(0x2183248b), SPH_C32(0x61380db7), + SPH_C32(0xd2670d01), SPH_C32(0x40bed715), SPH_C32(0x59e70000), + SPH_C32(0x6af33500), SPH_C32(0xc4b80000), SPH_C32(0xa8980000), + SPH_C32(0xc4376747), SPH_C32(0x0be593cf), SPH_C32(0xd3bc6f32), + SPH_C32(0x315245b4) }, + { SPH_C32(0xa4c20000), SPH_C32(0xd9372400), SPH_C32(0x0a480000), + SPH_C32(0x66610000), SPH_C32(0xf87a12c7), SPH_C32(0x86bef75c), + SPH_C32(0xa324df94), SPH_C32(0x2ba05a55), SPH_C32(0x75a40000), + SPH_C32(0xc28b2700), SPH_C32(0x94a40000), SPH_C32(0x90f50000), + SPH_C32(0xfb7857e0), SPH_C32(0x49ce0bae), SPH_C32(0x1767c483), + SPH_C32(0xaedf667e) }, + { SPH_C32(0x1cff0000), SPH_C32(0xcf462200), SPH_C32(0x3dd20000), + SPH_C32(0x93d00000), SPH_C32(0xdafb736b), SPH_C32(0x28f60619), + SPH_C32(0xc500c982), SPH_C32(0xee61b16b), SPH_C32(0x88810000), + SPH_C32(0x714f3600), SPH_C32(0x5a540000), SPH_C32(0x5e0c0000), + SPH_C32(0xc7352260), SPH_C32(0xc4956f3d), SPH_C32(0x67ff7425), + SPH_C32(0xb42d799f) } +}; + +static const sph_u32 T512_21[8][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0x0c720000), SPH_C32(0x49e50f00), SPH_C32(0x42790000), + SPH_C32(0x5cea0000), SPH_C32(0x33aa301a), SPH_C32(0x15822514), + SPH_C32(0x95a34b7b), SPH_C32(0xb44b0090), SPH_C32(0xfe220000), + SPH_C32(0xa7580500), SPH_C32(0x25d10000), SPH_C32(0xf7600000), + SPH_C32(0x893178da), SPH_C32(0x1fd4f860), SPH_C32(0x4ed0a315), + SPH_C32(0xa123ff9f) }, + { SPH_C32(0xfe220000), SPH_C32(0xa7580500), SPH_C32(0x25d10000), + SPH_C32(0xf7600000), SPH_C32(0x893178da), SPH_C32(0x1fd4f860), + SPH_C32(0x4ed0a315), SPH_C32(0xa123ff9f), SPH_C32(0xf2500000), + SPH_C32(0xeebd0a00), SPH_C32(0x67a80000), SPH_C32(0xab8a0000), + SPH_C32(0xba9b48c0), SPH_C32(0x0a56dd74), SPH_C32(0xdb73e86e), + SPH_C32(0x1568ff0f) }, + { SPH_C32(0xf2500000), SPH_C32(0xeebd0a00), SPH_C32(0x67a80000), + SPH_C32(0xab8a0000), SPH_C32(0xba9b48c0), SPH_C32(0x0a56dd74), + SPH_C32(0xdb73e86e), SPH_C32(0x1568ff0f), SPH_C32(0x0c720000), + SPH_C32(0x49e50f00), SPH_C32(0x42790000), SPH_C32(0x5cea0000), + SPH_C32(0x33aa301a), SPH_C32(0x15822514), SPH_C32(0x95a34b7b), + SPH_C32(0xb44b0090) }, + { SPH_C32(0x45180000), SPH_C32(0xa5b51700), SPH_C32(0xf96a0000), + SPH_C32(0x3b480000), SPH_C32(0x1ecc142c), SPH_C32(0x231395d6), + SPH_C32(0x16bca6b0), SPH_C32(0xdf33f4df), SPH_C32(0xb83d0000), + SPH_C32(0x16710600), SPH_C32(0x379a0000), SPH_C32(0xf5b10000), + SPH_C32(0x228161ac), SPH_C32(0xae48f145), SPH_C32(0x66241616), + SPH_C32(0xc5c1eb3e) }, + { SPH_C32(0x496a0000), SPH_C32(0xec501800), SPH_C32(0xbb130000), + SPH_C32(0x67a20000), SPH_C32(0x2d662436), SPH_C32(0x3691b0c2), + SPH_C32(0x831fedcb), SPH_C32(0x6b78f44f), SPH_C32(0x461f0000), + SPH_C32(0xb1290300), SPH_C32(0x124b0000), SPH_C32(0x02d10000), + SPH_C32(0xabb01976), SPH_C32(0xb19c0925), SPH_C32(0x28f4b503), + SPH_C32(0x64e214a1) }, + { SPH_C32(0xbb3a0000), SPH_C32(0x02ed1200), SPH_C32(0xdcbb0000), + SPH_C32(0xcc280000), SPH_C32(0x97fd6cf6), SPH_C32(0x3cc76db6), + SPH_C32(0x586c05a5), SPH_C32(0x7e100b40), SPH_C32(0x4a6d0000), + SPH_C32(0xf8cc0c00), SPH_C32(0x50320000), SPH_C32(0x5e3b0000), + SPH_C32(0x981a296c), SPH_C32(0xa41e2c31), SPH_C32(0xbd57fe78), + SPH_C32(0xd0a91431) }, + { SPH_C32(0xb7480000), SPH_C32(0x4b081d00), SPH_C32(0x9ec20000), + SPH_C32(0x90c20000), SPH_C32(0xa4575cec), SPH_C32(0x294548a2), + SPH_C32(0xcdcf4ede), SPH_C32(0xca5b0bd0), SPH_C32(0xb44f0000), + SPH_C32(0x5f940900), SPH_C32(0x75e30000), SPH_C32(0xa95b0000), + SPH_C32(0x112b51b6), SPH_C32(0xbbcad451), SPH_C32(0xf3875d6d), + SPH_C32(0x718aebae) } +}; + +static const sph_u32 T512_24[8][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0xbc8d0000), SPH_C32(0xfc3b0018), SPH_C32(0x19830000), + SPH_C32(0xd10b0000), SPH_C32(0xae1878c4), SPH_C32(0x42a69856), + SPH_C32(0x0012da37), SPH_C32(0x2c3b504e), SPH_C32(0xe8dd0000), + SPH_C32(0xfa4a0044), SPH_C32(0x3c2d0000), SPH_C32(0xbb150000), + SPH_C32(0x80bd361b), SPH_C32(0x24e81d44), SPH_C32(0xbfa8c2f4), + SPH_C32(0x524a0d59) }, + { SPH_C32(0x69510000), SPH_C32(0xd4e1009c), SPH_C32(0xc3230000), + SPH_C32(0xac2f0000), SPH_C32(0xe4950bae), SPH_C32(0xcea415dc), + SPH_C32(0x87ec287c), SPH_C32(0xbce1a3ce), SPH_C32(0xc6730000), + SPH_C32(0xaf8d000c), SPH_C32(0xa4c10000), SPH_C32(0x218d0000), + SPH_C32(0x23111587), SPH_C32(0x7913512f), SPH_C32(0x1d28ac88), + SPH_C32(0x378dd173) }, + { SPH_C32(0xd5dc0000), SPH_C32(0x28da0084), SPH_C32(0xdaa00000), + SPH_C32(0x7d240000), SPH_C32(0x4a8d736a), SPH_C32(0x8c028d8a), + SPH_C32(0x87fef24b), SPH_C32(0x90daf380), SPH_C32(0x2eae0000), + SPH_C32(0x55c70048), SPH_C32(0x98ec0000), SPH_C32(0x9a980000), + SPH_C32(0xa3ac239c), SPH_C32(0x5dfb4c6b), SPH_C32(0xa2806e7c), + SPH_C32(0x65c7dc2a) }, + { SPH_C32(0xc6730000), SPH_C32(0xaf8d000c), SPH_C32(0xa4c10000), + SPH_C32(0x218d0000), SPH_C32(0x23111587), SPH_C32(0x7913512f), + SPH_C32(0x1d28ac88), SPH_C32(0x378dd173), SPH_C32(0xaf220000), + SPH_C32(0x7b6c0090), SPH_C32(0x67e20000), SPH_C32(0x8da20000), + SPH_C32(0xc7841e29), SPH_C32(0xb7b744f3), SPH_C32(0x9ac484f4), + SPH_C32(0x8b6c72bd) }, + { SPH_C32(0x7afe0000), SPH_C32(0x53b60014), SPH_C32(0xbd420000), + SPH_C32(0xf0860000), SPH_C32(0x8d096d43), SPH_C32(0x3bb5c979), + SPH_C32(0x1d3a76bf), SPH_C32(0x1bb6813d), SPH_C32(0x47ff0000), + SPH_C32(0x812600d4), SPH_C32(0x5bcf0000), SPH_C32(0x36b70000), + SPH_C32(0x47392832), SPH_C32(0x935f59b7), SPH_C32(0x256c4600), + SPH_C32(0xd9267fe4) }, + { SPH_C32(0xaf220000), SPH_C32(0x7b6c0090), SPH_C32(0x67e20000), + SPH_C32(0x8da20000), SPH_C32(0xc7841e29), SPH_C32(0xb7b744f3), + SPH_C32(0x9ac484f4), SPH_C32(0x8b6c72bd), SPH_C32(0x69510000), + SPH_C32(0xd4e1009c), SPH_C32(0xc3230000), SPH_C32(0xac2f0000), + SPH_C32(0xe4950bae), SPH_C32(0xcea415dc), SPH_C32(0x87ec287c), + SPH_C32(0xbce1a3ce) }, + { SPH_C32(0x13af0000), SPH_C32(0x87570088), SPH_C32(0x7e610000), + SPH_C32(0x5ca90000), SPH_C32(0x699c66ed), SPH_C32(0xf511dca5), + SPH_C32(0x9ad65ec3), SPH_C32(0xa75722f3), SPH_C32(0x818c0000), + SPH_C32(0x2eab00d8), SPH_C32(0xff0e0000), SPH_C32(0x173a0000), + SPH_C32(0x64283db5), SPH_C32(0xea4c0898), SPH_C32(0x3844ea88), + SPH_C32(0xeeabae97) } +}; + +static const sph_u32 T512_27[8][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0x14190000), SPH_C32(0x23ca003c), SPH_C32(0x50df0000), + SPH_C32(0x44b60000), SPH_C32(0x1b6c67b0), SPH_C32(0x3cf3ac75), + SPH_C32(0x61e610b0), SPH_C32(0xdbcadb80), SPH_C32(0xe3430000), + SPH_C32(0x3a4e0014), SPH_C32(0xf2c60000), SPH_C32(0xaa4e0000), + SPH_C32(0xdb1e42a6), SPH_C32(0x256bbe15), SPH_C32(0x123db156), + SPH_C32(0x3a4e99d7) }, + { SPH_C32(0xe3430000), SPH_C32(0x3a4e0014), SPH_C32(0xf2c60000), + SPH_C32(0xaa4e0000), SPH_C32(0xdb1e42a6), SPH_C32(0x256bbe15), + SPH_C32(0x123db156), SPH_C32(0x3a4e99d7), SPH_C32(0xf75a0000), + SPH_C32(0x19840028), SPH_C32(0xa2190000), SPH_C32(0xeef80000), + SPH_C32(0xc0722516), SPH_C32(0x19981260), SPH_C32(0x73dba1e6), + SPH_C32(0xe1844257) }, + { SPH_C32(0xf75a0000), SPH_C32(0x19840028), SPH_C32(0xa2190000), + SPH_C32(0xeef80000), SPH_C32(0xc0722516), SPH_C32(0x19981260), + SPH_C32(0x73dba1e6), SPH_C32(0xe1844257), SPH_C32(0x14190000), + SPH_C32(0x23ca003c), SPH_C32(0x50df0000), SPH_C32(0x44b60000), + SPH_C32(0x1b6c67b0), SPH_C32(0x3cf3ac75), SPH_C32(0x61e610b0), + SPH_C32(0xdbcadb80) }, + { SPH_C32(0x54500000), SPH_C32(0x0671005c), SPH_C32(0x25ae0000), + SPH_C32(0x6a1e0000), SPH_C32(0x2ea54edf), SPH_C32(0x664e8512), + SPH_C32(0xbfba18c3), SPH_C32(0x7e715d17), SPH_C32(0xbc8d0000), + SPH_C32(0xfc3b0018), SPH_C32(0x19830000), SPH_C32(0xd10b0000), + SPH_C32(0xae1878c4), SPH_C32(0x42a69856), SPH_C32(0x0012da37), + SPH_C32(0x2c3b504e) }, + { SPH_C32(0x40490000), SPH_C32(0x25bb0060), SPH_C32(0x75710000), + SPH_C32(0x2ea80000), SPH_C32(0x35c9296f), SPH_C32(0x5abd2967), + SPH_C32(0xde5c0873), SPH_C32(0xa5bb8697), SPH_C32(0x5fce0000), + SPH_C32(0xc675000c), SPH_C32(0xeb450000), SPH_C32(0x7b450000), + SPH_C32(0x75063a62), SPH_C32(0x67cd2643), SPH_C32(0x122f6b61), + SPH_C32(0x1675c999) }, + { SPH_C32(0xb7130000), SPH_C32(0x3c3f0048), SPH_C32(0xd7680000), + SPH_C32(0xc0500000), SPH_C32(0xf5bb0c79), SPH_C32(0x43253b07), + SPH_C32(0xad87a995), SPH_C32(0x443fc4c0), SPH_C32(0x4bd70000), + SPH_C32(0xe5bf0030), SPH_C32(0xbb9a0000), SPH_C32(0x3ff30000), + SPH_C32(0x6e6a5dd2), SPH_C32(0x5b3e8a36), SPH_C32(0x73c97bd1), + SPH_C32(0xcdbf1219) }, + { SPH_C32(0xa30a0000), SPH_C32(0x1ff50074), SPH_C32(0x87b70000), + SPH_C32(0x84e60000), SPH_C32(0xeed76bc9), SPH_C32(0x7fd69772), + SPH_C32(0xcc61b925), SPH_C32(0x9ff51f40), SPH_C32(0xa8940000), + SPH_C32(0xdff10024), SPH_C32(0x495c0000), SPH_C32(0x95bd0000), + SPH_C32(0xb5741f74), SPH_C32(0x7e553423), SPH_C32(0x61f4ca87), + SPH_C32(0xf7f18bce) } +}; + +static const sph_u32 T512_30[8][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0xdb250000), SPH_C32(0x09290000), SPH_C32(0x49aac000), + SPH_C32(0x81e10000), SPH_C32(0xcafe6b59), SPH_C32(0x42793431), + SPH_C32(0x43566b76), SPH_C32(0xe86cba2e), SPH_C32(0x75e60000), + SPH_C32(0x95660001), SPH_C32(0x307b2000), SPH_C32(0xadf40000), + SPH_C32(0x8f321eea), SPH_C32(0x24298307), SPH_C32(0xe8c49cf9), + SPH_C32(0x4b7eec55) }, + { SPH_C32(0x86790000), SPH_C32(0x3f390002), SPH_C32(0xe19ae000), + SPH_C32(0x98560000), SPH_C32(0x9565670e), SPH_C32(0x4e88c8ea), + SPH_C32(0xd3dd4944), SPH_C32(0x161ddab9), SPH_C32(0x30b70000), + SPH_C32(0xe5d00000), SPH_C32(0xf4f46000), SPH_C32(0x42c40000), + SPH_C32(0x63b83d6a), SPH_C32(0x78ba9460), SPH_C32(0x21afa1ea), + SPH_C32(0xb0a51834) }, + { SPH_C32(0x5d5c0000), SPH_C32(0x36100002), SPH_C32(0xa8302000), + SPH_C32(0x19b70000), SPH_C32(0x5f9b0c57), SPH_C32(0x0cf1fcdb), + SPH_C32(0x908b2232), SPH_C32(0xfe716097), SPH_C32(0x45510000), + SPH_C32(0x70b60001), SPH_C32(0xc48f4000), SPH_C32(0xef300000), + SPH_C32(0xec8a2380), SPH_C32(0x5c931767), SPH_C32(0xc96b3d13), + SPH_C32(0xfbdbf461) }, + { SPH_C32(0x30b70000), SPH_C32(0xe5d00000), SPH_C32(0xf4f46000), + SPH_C32(0x42c40000), SPH_C32(0x63b83d6a), SPH_C32(0x78ba9460), + SPH_C32(0x21afa1ea), SPH_C32(0xb0a51834), SPH_C32(0xb6ce0000), + SPH_C32(0xdae90002), SPH_C32(0x156e8000), SPH_C32(0xda920000), + SPH_C32(0xf6dd5a64), SPH_C32(0x36325c8a), SPH_C32(0xf272e8ae), + SPH_C32(0xa6b8c28d) }, + { SPH_C32(0xeb920000), SPH_C32(0xecf90000), SPH_C32(0xbd5ea000), + SPH_C32(0xc3250000), SPH_C32(0xa9465633), SPH_C32(0x3ac3a051), + SPH_C32(0x62f9ca9c), SPH_C32(0x58c9a21a), SPH_C32(0xc3280000), + SPH_C32(0x4f8f0003), SPH_C32(0x2515a000), SPH_C32(0x77660000), + SPH_C32(0x79ef448e), SPH_C32(0x121bdf8d), SPH_C32(0x1ab67457), + SPH_C32(0xedc62ed8) }, + { SPH_C32(0xb6ce0000), SPH_C32(0xdae90002), SPH_C32(0x156e8000), + SPH_C32(0xda920000), SPH_C32(0xf6dd5a64), SPH_C32(0x36325c8a), + SPH_C32(0xf272e8ae), SPH_C32(0xa6b8c28d), SPH_C32(0x86790000), + SPH_C32(0x3f390002), SPH_C32(0xe19ae000), SPH_C32(0x98560000), + SPH_C32(0x9565670e), SPH_C32(0x4e88c8ea), SPH_C32(0xd3dd4944), + SPH_C32(0x161ddab9) }, + { SPH_C32(0x6deb0000), SPH_C32(0xd3c00002), SPH_C32(0x5cc44000), + SPH_C32(0x5b730000), SPH_C32(0x3c23313d), SPH_C32(0x744b68bb), + SPH_C32(0xb12483d8), SPH_C32(0x4ed478a3), SPH_C32(0xf39f0000), + SPH_C32(0xaa5f0003), SPH_C32(0xd1e1c000), SPH_C32(0x35a20000), + SPH_C32(0x1a5779e4), SPH_C32(0x6aa14bed), SPH_C32(0x3b19d5bd), + SPH_C32(0x5d6336ec) } +}; + +static const sph_u32 T512_33[8][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0xac480000), SPH_C32(0x1ba60000), SPH_C32(0x45fb1380), + SPH_C32(0x03430000), SPH_C32(0x5a85316a), SPH_C32(0x1fb250b6), + SPH_C32(0xfe72c7fe), SPH_C32(0x91e478f6), SPH_C32(0x1e4e0000), + SPH_C32(0xdecf0000), SPH_C32(0x6df80180), SPH_C32(0x77240000), + SPH_C32(0xec47079e), SPH_C32(0xf4a0694e), SPH_C32(0xcda31812), + SPH_C32(0x98aa496e) }, + { SPH_C32(0x1e4e0000), SPH_C32(0xdecf0000), SPH_C32(0x6df80180), + SPH_C32(0x77240000), SPH_C32(0xec47079e), SPH_C32(0xf4a0694e), + SPH_C32(0xcda31812), SPH_C32(0x98aa496e), SPH_C32(0xb2060000), + SPH_C32(0xc5690000), SPH_C32(0x28031200), SPH_C32(0x74670000), + SPH_C32(0xb6c236f4), SPH_C32(0xeb1239f8), SPH_C32(0x33d1dfec), + SPH_C32(0x094e3198) }, + { SPH_C32(0xb2060000), SPH_C32(0xc5690000), SPH_C32(0x28031200), + SPH_C32(0x74670000), SPH_C32(0xb6c236f4), SPH_C32(0xeb1239f8), + SPH_C32(0x33d1dfec), SPH_C32(0x094e3198), SPH_C32(0xac480000), + SPH_C32(0x1ba60000), SPH_C32(0x45fb1380), SPH_C32(0x03430000), + SPH_C32(0x5a85316a), SPH_C32(0x1fb250b6), SPH_C32(0xfe72c7fe), + SPH_C32(0x91e478f6) }, + { SPH_C32(0xaec30000), SPH_C32(0x9c4f0001), SPH_C32(0x79d1e000), + SPH_C32(0x2c150000), SPH_C32(0x45cc75b3), SPH_C32(0x6650b736), + SPH_C32(0xab92f78f), SPH_C32(0xa312567b), SPH_C32(0xdb250000), + SPH_C32(0x09290000), SPH_C32(0x49aac000), SPH_C32(0x81e10000), + SPH_C32(0xcafe6b59), SPH_C32(0x42793431), SPH_C32(0x43566b76), + SPH_C32(0xe86cba2e) }, + { SPH_C32(0x028b0000), SPH_C32(0x87e90001), SPH_C32(0x3c2af380), + SPH_C32(0x2f560000), SPH_C32(0x1f4944d9), SPH_C32(0x79e2e780), + SPH_C32(0x55e03071), SPH_C32(0x32f62e8d), SPH_C32(0xc56b0000), + SPH_C32(0xd7e60000), SPH_C32(0x2452c180), SPH_C32(0xf6c50000), + SPH_C32(0x26b96cc7), SPH_C32(0xb6d95d7f), SPH_C32(0x8ef57364), + SPH_C32(0x70c6f340) }, + { SPH_C32(0xb08d0000), SPH_C32(0x42800001), SPH_C32(0x1429e180), + SPH_C32(0x5b310000), SPH_C32(0xa98b722d), SPH_C32(0x92f0de78), + SPH_C32(0x6631ef9d), SPH_C32(0x3bb81f15), SPH_C32(0x69230000), + SPH_C32(0xcc400000), SPH_C32(0x61a9d200), SPH_C32(0xf5860000), + SPH_C32(0x7c3c5dad), SPH_C32(0xa96b0dc9), SPH_C32(0x7087b49a), + SPH_C32(0xe1228bb6) }, + { SPH_C32(0x1cc50000), SPH_C32(0x59260001), SPH_C32(0x51d2f200), + SPH_C32(0x58720000), SPH_C32(0xf30e4347), SPH_C32(0x8d428ece), + SPH_C32(0x98432863), SPH_C32(0xaa5c67e3), SPH_C32(0x776d0000), + SPH_C32(0x128f0000), SPH_C32(0x0c51d380), SPH_C32(0x82a20000), + SPH_C32(0x907b5a33), SPH_C32(0x5dcb6487), SPH_C32(0xbd24ac88), + SPH_C32(0x7988c2d8) } +}; + +static const sph_u32 T512_36[8][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0x819e0000), SPH_C32(0xec570000), SPH_C32(0x66320280), + SPH_C32(0x95f30000), SPH_C32(0x5da92802), SPH_C32(0x48f43cbc), + SPH_C32(0xe65aa22d), SPH_C32(0x8e67b7fa), SPH_C32(0x4d8a0000), + SPH_C32(0x49340000), SPH_C32(0x3c8b0500), SPH_C32(0xaea30000), + SPH_C32(0x16793bfd), SPH_C32(0xcf6f08a4), SPH_C32(0x8f19eaec), + SPH_C32(0x443d3004) }, + { SPH_C32(0x78230000), SPH_C32(0x12fc0000), SPH_C32(0xa93a0b80), + SPH_C32(0x90a50000), SPH_C32(0x713e2879), SPH_C32(0x7ee98924), + SPH_C32(0xf08ca062), SPH_C32(0x636f8bab), SPH_C32(0x02af0000), + SPH_C32(0xb7280000), SPH_C32(0xba1c0300), SPH_C32(0x56980000), + SPH_C32(0xba8d45d3), SPH_C32(0x8048c667), SPH_C32(0xa95c149a), + SPH_C32(0xf4f6ea7b) }, + { SPH_C32(0xf9bd0000), SPH_C32(0xfeab0000), SPH_C32(0xcf080900), + SPH_C32(0x05560000), SPH_C32(0x2c97007b), SPH_C32(0x361db598), + SPH_C32(0x16d6024f), SPH_C32(0xed083c51), SPH_C32(0x4f250000), + SPH_C32(0xfe1c0000), SPH_C32(0x86970600), SPH_C32(0xf83b0000), + SPH_C32(0xacf47e2e), SPH_C32(0x4f27cec3), SPH_C32(0x2645fe76), + SPH_C32(0xb0cbda7f) }, + { SPH_C32(0x02af0000), SPH_C32(0xb7280000), SPH_C32(0xba1c0300), + SPH_C32(0x56980000), SPH_C32(0xba8d45d3), SPH_C32(0x8048c667), + SPH_C32(0xa95c149a), SPH_C32(0xf4f6ea7b), SPH_C32(0x7a8c0000), + SPH_C32(0xa5d40000), SPH_C32(0x13260880), SPH_C32(0xc63d0000), + SPH_C32(0xcbb36daa), SPH_C32(0xfea14f43), SPH_C32(0x59d0b4f8), + SPH_C32(0x979961d0) }, + { SPH_C32(0x83310000), SPH_C32(0x5b7f0000), SPH_C32(0xdc2e0180), + SPH_C32(0xc36b0000), SPH_C32(0xe7246dd1), SPH_C32(0xc8bcfadb), + SPH_C32(0x4f06b6b7), SPH_C32(0x7a915d81), SPH_C32(0x37060000), + SPH_C32(0xece00000), SPH_C32(0x2fad0d80), SPH_C32(0x689e0000), + SPH_C32(0xddca5657), SPH_C32(0x31ce47e7), SPH_C32(0xd6c95e14), + SPH_C32(0xd3a451d4) }, + { SPH_C32(0x7a8c0000), SPH_C32(0xa5d40000), SPH_C32(0x13260880), + SPH_C32(0xc63d0000), SPH_C32(0xcbb36daa), SPH_C32(0xfea14f43), + SPH_C32(0x59d0b4f8), SPH_C32(0x979961d0), SPH_C32(0x78230000), + SPH_C32(0x12fc0000), SPH_C32(0xa93a0b80), SPH_C32(0x90a50000), + SPH_C32(0x713e2879), SPH_C32(0x7ee98924), SPH_C32(0xf08ca062), + SPH_C32(0x636f8bab) }, + { SPH_C32(0xfb120000), SPH_C32(0x49830000), SPH_C32(0x75140a00), + SPH_C32(0x53ce0000), SPH_C32(0x961a45a8), SPH_C32(0xb65573ff), + SPH_C32(0xbf8a16d5), SPH_C32(0x19fed62a), SPH_C32(0x35a90000), + SPH_C32(0x5bc80000), SPH_C32(0x95b10e80), SPH_C32(0x3e060000), + SPH_C32(0x67471384), SPH_C32(0xb1868180), SPH_C32(0x7f954a8e), + SPH_C32(0x2752bbaf) } +}; + +static const sph_u32 T512_39[8][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0x52500000), SPH_C32(0x29540000), SPH_C32(0x6a61004e), + SPH_C32(0xf0ff0000), SPH_C32(0x9a317eec), SPH_C32(0x452341ce), + SPH_C32(0xcf568fe5), SPH_C32(0x5303130f), SPH_C32(0x538d0000), + SPH_C32(0xa9fc0000), SPH_C32(0x9ef70006), SPH_C32(0x56ff0000), + SPH_C32(0x0ae4004e), SPH_C32(0x92c5cdf9), SPH_C32(0xa9444018), + SPH_C32(0x7f975691) }, + { SPH_C32(0x538d0000), SPH_C32(0xa9fc0000), SPH_C32(0x9ef70006), + SPH_C32(0x56ff0000), SPH_C32(0x0ae4004e), SPH_C32(0x92c5cdf9), + SPH_C32(0xa9444018), SPH_C32(0x7f975691), SPH_C32(0x01dd0000), + SPH_C32(0x80a80000), SPH_C32(0xf4960048), SPH_C32(0xa6000000), + SPH_C32(0x90d57ea2), SPH_C32(0xd7e68c37), SPH_C32(0x6612cffd), + SPH_C32(0x2c94459e) }, + { SPH_C32(0x01dd0000), SPH_C32(0x80a80000), SPH_C32(0xf4960048), + SPH_C32(0xa6000000), SPH_C32(0x90d57ea2), SPH_C32(0xd7e68c37), + SPH_C32(0x6612cffd), SPH_C32(0x2c94459e), SPH_C32(0x52500000), + SPH_C32(0x29540000), SPH_C32(0x6a61004e), SPH_C32(0xf0ff0000), + SPH_C32(0x9a317eec), SPH_C32(0x452341ce), SPH_C32(0xcf568fe5), + SPH_C32(0x5303130f) }, + { SPH_C32(0xcc140000), SPH_C32(0xa5630000), SPH_C32(0x5ab90780), + SPH_C32(0x3b500000), SPH_C32(0x4bd013ff), SPH_C32(0x879b3418), + SPH_C32(0x694348c1), SPH_C32(0xca5a87fe), SPH_C32(0x819e0000), + SPH_C32(0xec570000), SPH_C32(0x66320280), SPH_C32(0x95f30000), + SPH_C32(0x5da92802), SPH_C32(0x48f43cbc), SPH_C32(0xe65aa22d), + SPH_C32(0x8e67b7fa) }, + { SPH_C32(0x9e440000), SPH_C32(0x8c370000), SPH_C32(0x30d807ce), + SPH_C32(0xcbaf0000), SPH_C32(0xd1e16d13), SPH_C32(0xc2b875d6), + SPH_C32(0xa615c724), SPH_C32(0x995994f1), SPH_C32(0xd2130000), + SPH_C32(0x45ab0000), SPH_C32(0xf8c50286), SPH_C32(0xc30c0000), + SPH_C32(0x574d284c), SPH_C32(0xda31f145), SPH_C32(0x4f1ee235), + SPH_C32(0xf1f0e16b) }, + { SPH_C32(0x9f990000), SPH_C32(0x0c9f0000), SPH_C32(0xc44e0786), + SPH_C32(0x6daf0000), SPH_C32(0x413413b1), SPH_C32(0x155ef9e1), + SPH_C32(0xc00708d9), SPH_C32(0xb5cdd16f), SPH_C32(0x80430000), + SPH_C32(0x6cff0000), SPH_C32(0x92a402c8), SPH_C32(0x33f30000), + SPH_C32(0xcd7c56a0), SPH_C32(0x9f12b08b), SPH_C32(0x80486dd0), + SPH_C32(0xa2f3f264) }, + { SPH_C32(0xcdc90000), SPH_C32(0x25cb0000), SPH_C32(0xae2f07c8), + SPH_C32(0x9d500000), SPH_C32(0xdb056d5d), SPH_C32(0x507db82f), + SPH_C32(0x0f51873c), SPH_C32(0xe6cec260), SPH_C32(0xd3ce0000), + SPH_C32(0xc5030000), SPH_C32(0x0c5302ce), SPH_C32(0x650c0000), + SPH_C32(0xc79856ee), SPH_C32(0x0dd77d72), SPH_C32(0x290c2dc8), + SPH_C32(0xdd64a4f5) } +}; + +static const sph_u32 T512_42[8][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0x07ed0000), SPH_C32(0xb2500000), SPH_C32(0x8774000a), + SPH_C32(0x970d0000), SPH_C32(0x437223ae), SPH_C32(0x48c76ea4), + SPH_C32(0xf4786222), SPH_C32(0x9075b1ce), SPH_C32(0xa2d60000), + SPH_C32(0xa6760000), SPH_C32(0xc9440014), SPH_C32(0xeba30000), + SPH_C32(0xccec2e7b), SPH_C32(0x3018c499), SPH_C32(0x03490afa), + SPH_C32(0x9b6ef888) }, + { SPH_C32(0x88980000), SPH_C32(0x1f940000), SPH_C32(0x7fcf002e), + SPH_C32(0xfb4e0000), SPH_C32(0xf158079a), SPH_C32(0x61ae9167), + SPH_C32(0xa895706c), SPH_C32(0xe6107494), SPH_C32(0x0bc20000), + SPH_C32(0xdb630000), SPH_C32(0x7e88000c), SPH_C32(0x15860000), + SPH_C32(0x91fd48f3), SPH_C32(0x7581bb43), SPH_C32(0xf460449e), + SPH_C32(0xd8b61463) }, + { SPH_C32(0x8f750000), SPH_C32(0xadc40000), SPH_C32(0xf8bb0024), + SPH_C32(0x6c430000), SPH_C32(0xb22a2434), SPH_C32(0x2969ffc3), + SPH_C32(0x5ced124e), SPH_C32(0x7665c55a), SPH_C32(0xa9140000), + SPH_C32(0x7d150000), SPH_C32(0xb7cc0018), SPH_C32(0xfe250000), + SPH_C32(0x5d116688), SPH_C32(0x45997fda), SPH_C32(0xf7294e64), + SPH_C32(0x43d8eceb) }, + { SPH_C32(0x0bc20000), SPH_C32(0xdb630000), SPH_C32(0x7e88000c), + SPH_C32(0x15860000), SPH_C32(0x91fd48f3), SPH_C32(0x7581bb43), + SPH_C32(0xf460449e), SPH_C32(0xd8b61463), SPH_C32(0x835a0000), + SPH_C32(0xc4f70000), SPH_C32(0x01470022), SPH_C32(0xeec80000), + SPH_C32(0x60a54f69), SPH_C32(0x142f2a24), SPH_C32(0x5cf534f2), + SPH_C32(0x3ea660f7) }, + { SPH_C32(0x0c2f0000), SPH_C32(0x69330000), SPH_C32(0xf9fc0006), + SPH_C32(0x828b0000), SPH_C32(0xd28f6b5d), SPH_C32(0x3d46d5e7), + SPH_C32(0x001826bc), SPH_C32(0x48c3a5ad), SPH_C32(0x218c0000), + SPH_C32(0x62810000), SPH_C32(0xc8030036), SPH_C32(0x056b0000), + SPH_C32(0xac496112), SPH_C32(0x2437eebd), SPH_C32(0x5fbc3e08), + SPH_C32(0xa5c8987f) }, + { SPH_C32(0x835a0000), SPH_C32(0xc4f70000), SPH_C32(0x01470022), + SPH_C32(0xeec80000), SPH_C32(0x60a54f69), SPH_C32(0x142f2a24), + SPH_C32(0x5cf534f2), SPH_C32(0x3ea660f7), SPH_C32(0x88980000), + SPH_C32(0x1f940000), SPH_C32(0x7fcf002e), SPH_C32(0xfb4e0000), + SPH_C32(0xf158079a), SPH_C32(0x61ae9167), SPH_C32(0xa895706c), + SPH_C32(0xe6107494) }, + { SPH_C32(0x84b70000), SPH_C32(0x76a70000), SPH_C32(0x86330028), + SPH_C32(0x79c50000), SPH_C32(0x23d76cc7), SPH_C32(0x5ce84480), + SPH_C32(0xa88d56d0), SPH_C32(0xaed3d139), SPH_C32(0x2a4e0000), + SPH_C32(0xb9e20000), SPH_C32(0xb68b003a), SPH_C32(0x10ed0000), + SPH_C32(0x3db429e1), SPH_C32(0x51b655fe), SPH_C32(0xabdc7a96), + SPH_C32(0x7d7e8c1c) } +}; + +static const sph_u32 T512_45[8][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0x58430000), SPH_C32(0x807e0000), SPH_C32(0x78330001), + SPH_C32(0xc66b3800), SPH_C32(0xe7375cdc), SPH_C32(0x79ad3fdd), + SPH_C32(0xac73fe6f), SPH_C32(0x3a4479b1), SPH_C32(0x1d5a0000), + SPH_C32(0x2b720000), SPH_C32(0x488d0000), SPH_C32(0xaf611800), + SPH_C32(0x25cb2ec5), SPH_C32(0xc879bfd0), SPH_C32(0x81a20429), + SPH_C32(0x1e7536a6) }, + { SPH_C32(0x1d5a0000), SPH_C32(0x2b720000), SPH_C32(0x488d0000), + SPH_C32(0xaf611800), SPH_C32(0x25cb2ec5), SPH_C32(0xc879bfd0), + SPH_C32(0x81a20429), SPH_C32(0x1e7536a6), SPH_C32(0x45190000), + SPH_C32(0xab0c0000), SPH_C32(0x30be0001), SPH_C32(0x690a2000), + SPH_C32(0xc2fc7219), SPH_C32(0xb1d4800d), SPH_C32(0x2dd1fa46), + SPH_C32(0x24314f17) }, + { SPH_C32(0x45190000), SPH_C32(0xab0c0000), SPH_C32(0x30be0001), + SPH_C32(0x690a2000), SPH_C32(0xc2fc7219), SPH_C32(0xb1d4800d), + SPH_C32(0x2dd1fa46), SPH_C32(0x24314f17), SPH_C32(0x58430000), + SPH_C32(0x807e0000), SPH_C32(0x78330001), SPH_C32(0xc66b3800), + SPH_C32(0xe7375cdc), SPH_C32(0x79ad3fdd), SPH_C32(0xac73fe6f), + SPH_C32(0x3a4479b1) }, + { SPH_C32(0xa53b0000), SPH_C32(0x14260000), SPH_C32(0x4e30001e), + SPH_C32(0x7cae0000), SPH_C32(0x8f9e0dd5), SPH_C32(0x78dfaa3d), + SPH_C32(0xf73168d8), SPH_C32(0x0b1b4946), SPH_C32(0x07ed0000), + SPH_C32(0xb2500000), SPH_C32(0x8774000a), SPH_C32(0x970d0000), + SPH_C32(0x437223ae), SPH_C32(0x48c76ea4), SPH_C32(0xf4786222), + SPH_C32(0x9075b1ce) }, + { SPH_C32(0xfd780000), SPH_C32(0x94580000), SPH_C32(0x3603001f), + SPH_C32(0xbac53800), SPH_C32(0x68a95109), SPH_C32(0x017295e0), + SPH_C32(0x5b4296b7), SPH_C32(0x315f30f7), SPH_C32(0x1ab70000), + SPH_C32(0x99220000), SPH_C32(0xcff9000a), SPH_C32(0x386c1800), + SPH_C32(0x66b90d6b), SPH_C32(0x80bed174), SPH_C32(0x75da660b), + SPH_C32(0x8e008768) }, + { SPH_C32(0xb8610000), SPH_C32(0x3f540000), SPH_C32(0x06bd001e), + SPH_C32(0xd3cf1800), SPH_C32(0xaa552310), SPH_C32(0xb0a615ed), + SPH_C32(0x76936cf1), SPH_C32(0x156e7fe0), SPH_C32(0x42f40000), + SPH_C32(0x195c0000), SPH_C32(0xb7ca000b), SPH_C32(0xfe072000), + SPH_C32(0x818e51b7), SPH_C32(0xf913eea9), SPH_C32(0xd9a99864), + SPH_C32(0xb444fed9) }, + { SPH_C32(0xe0220000), SPH_C32(0xbf2a0000), SPH_C32(0x7e8e001f), + SPH_C32(0x15a42000), SPH_C32(0x4d627fcc), SPH_C32(0xc90b2a30), + SPH_C32(0xdae0929e), SPH_C32(0x2f2a0651), SPH_C32(0x5fae0000), + SPH_C32(0x322e0000), SPH_C32(0xff47000b), SPH_C32(0x51663800), + SPH_C32(0xa4457f72), SPH_C32(0x316a5179), SPH_C32(0x580b9c4d), + SPH_C32(0xaa31c87f) } +}; + +static const sph_u32 T512_48[8][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0xbadd0000), SPH_C32(0x13ad0000), SPH_C32(0xb7e70000), + SPH_C32(0xf7282800), SPH_C32(0xdf45144d), SPH_C32(0x361ac33a), + SPH_C32(0xea5a8d14), SPH_C32(0x2a2c18f0), SPH_C32(0xb82f0000), + SPH_C32(0xb12c0000), SPH_C32(0x30d80000), SPH_C32(0x14445000), + SPH_C32(0xc15860a2), SPH_C32(0x3127e8ec), SPH_C32(0x2e98bf23), + SPH_C32(0x551e3d6e) }, + { SPH_C32(0x1e6c0000), SPH_C32(0xc4420000), SPH_C32(0x8a2e0000), + SPH_C32(0xbcb6b800), SPH_C32(0x2c4413b6), SPH_C32(0x8bfdd3da), + SPH_C32(0x6a0c1bc8), SPH_C32(0xb99dc2eb), SPH_C32(0x92560000), + SPH_C32(0x1eda0000), SPH_C32(0xea510000), SPH_C32(0xe8b13000), + SPH_C32(0xa93556a5), SPH_C32(0xebfb6199), SPH_C32(0xb15c2254), + SPH_C32(0x33c5244f) }, + { SPH_C32(0xa4b10000), SPH_C32(0xd7ef0000), SPH_C32(0x3dc90000), + SPH_C32(0x4b9e9000), SPH_C32(0xf30107fb), SPH_C32(0xbde710e0), + SPH_C32(0x805696dc), SPH_C32(0x93b1da1b), SPH_C32(0x2a790000), + SPH_C32(0xaff60000), SPH_C32(0xda890000), SPH_C32(0xfcf56000), + SPH_C32(0x686d3607), SPH_C32(0xdadc8975), SPH_C32(0x9fc49d77), + SPH_C32(0x66db1921) }, + { SPH_C32(0x92560000), SPH_C32(0x1eda0000), SPH_C32(0xea510000), + SPH_C32(0xe8b13000), SPH_C32(0xa93556a5), SPH_C32(0xebfb6199), + SPH_C32(0xb15c2254), SPH_C32(0x33c5244f), SPH_C32(0x8c3a0000), + SPH_C32(0xda980000), SPH_C32(0x607f0000), SPH_C32(0x54078800), + SPH_C32(0x85714513), SPH_C32(0x6006b243), SPH_C32(0xdb50399c), + SPH_C32(0x8a58e6a4) }, + { SPH_C32(0x288b0000), SPH_C32(0x0d770000), SPH_C32(0x5db60000), + SPH_C32(0x1f991800), SPH_C32(0x767042e8), SPH_C32(0xdde1a2a3), + SPH_C32(0x5b06af40), SPH_C32(0x19e93cbf), SPH_C32(0x34150000), + SPH_C32(0x6bb40000), SPH_C32(0x50a70000), SPH_C32(0x4043d800), + SPH_C32(0x442925b1), SPH_C32(0x51215aaf), SPH_C32(0xf5c886bf), + SPH_C32(0xdf46dbca) }, + { SPH_C32(0x8c3a0000), SPH_C32(0xda980000), SPH_C32(0x607f0000), + SPH_C32(0x54078800), SPH_C32(0x85714513), SPH_C32(0x6006b243), + SPH_C32(0xdb50399c), SPH_C32(0x8a58e6a4), SPH_C32(0x1e6c0000), + SPH_C32(0xc4420000), SPH_C32(0x8a2e0000), SPH_C32(0xbcb6b800), + SPH_C32(0x2c4413b6), SPH_C32(0x8bfdd3da), SPH_C32(0x6a0c1bc8), + SPH_C32(0xb99dc2eb) }, + { SPH_C32(0x36e70000), SPH_C32(0xc9350000), SPH_C32(0xd7980000), + SPH_C32(0xa32fa000), SPH_C32(0x5a34515e), SPH_C32(0x561c7179), + SPH_C32(0x310ab488), SPH_C32(0xa074fe54), SPH_C32(0xa6430000), + SPH_C32(0x756e0000), SPH_C32(0xbaf60000), SPH_C32(0xa8f2e800), + SPH_C32(0xed1c7314), SPH_C32(0xbada3b36), SPH_C32(0x4494a4eb), + SPH_C32(0xec83ff85) } +}; + +static const sph_u32 T512_51[8][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0xb4310000), SPH_C32(0x77330000), SPH_C32(0xb15d0000), + SPH_C32(0x7fd004e0), SPH_C32(0x78a26138), SPH_C32(0xd116c35d), + SPH_C32(0xd256d489), SPH_C32(0x4e6f74de), SPH_C32(0xe3060000), + SPH_C32(0xbdc10000), SPH_C32(0x87130000), SPH_C32(0xbff20060), + SPH_C32(0x2eba0a1a), SPH_C32(0x8db53751), SPH_C32(0x73c5ab06), + SPH_C32(0x5bd61539) }, + { SPH_C32(0xe3060000), SPH_C32(0xbdc10000), SPH_C32(0x87130000), + SPH_C32(0xbff20060), SPH_C32(0x2eba0a1a), SPH_C32(0x8db53751), + SPH_C32(0x73c5ab06), SPH_C32(0x5bd61539), SPH_C32(0x57370000), + SPH_C32(0xcaf20000), SPH_C32(0x364e0000), SPH_C32(0xc0220480), + SPH_C32(0x56186b22), SPH_C32(0x5ca3f40c), SPH_C32(0xa1937f8f), + SPH_C32(0x15b961e7) }, + { SPH_C32(0x57370000), SPH_C32(0xcaf20000), SPH_C32(0x364e0000), + SPH_C32(0xc0220480), SPH_C32(0x56186b22), SPH_C32(0x5ca3f40c), + SPH_C32(0xa1937f8f), SPH_C32(0x15b961e7), SPH_C32(0xb4310000), + SPH_C32(0x77330000), SPH_C32(0xb15d0000), SPH_C32(0x7fd004e0), + SPH_C32(0x78a26138), SPH_C32(0xd116c35d), SPH_C32(0xd256d489), + SPH_C32(0x4e6f74de) }, + { SPH_C32(0x02f20000), SPH_C32(0xa2810000), SPH_C32(0x873f0000), + SPH_C32(0xe36c7800), SPH_C32(0x1e1d74ef), SPH_C32(0x073d2bd6), + SPH_C32(0xc4c23237), SPH_C32(0x7f32259e), SPH_C32(0xbadd0000), + SPH_C32(0x13ad0000), SPH_C32(0xb7e70000), SPH_C32(0xf7282800), + SPH_C32(0xdf45144d), SPH_C32(0x361ac33a), SPH_C32(0xea5a8d14), + SPH_C32(0x2a2c18f0) }, + { SPH_C32(0xb6c30000), SPH_C32(0xd5b20000), SPH_C32(0x36620000), + SPH_C32(0x9cbc7ce0), SPH_C32(0x66bf15d7), SPH_C32(0xd62be88b), + SPH_C32(0x1694e6be), SPH_C32(0x315d5140), SPH_C32(0x59db0000), + SPH_C32(0xae6c0000), SPH_C32(0x30f40000), SPH_C32(0x48da2860), + SPH_C32(0xf1ff1e57), SPH_C32(0xbbaff46b), SPH_C32(0x999f2612), + SPH_C32(0x71fa0dc9) }, + { SPH_C32(0xe1f40000), SPH_C32(0x1f400000), SPH_C32(0x002c0000), + SPH_C32(0x5c9e7860), SPH_C32(0x30a77ef5), SPH_C32(0x8a881c87), + SPH_C32(0xb7079931), SPH_C32(0x24e430a7), SPH_C32(0xedea0000), + SPH_C32(0xd95f0000), SPH_C32(0x81a90000), SPH_C32(0x370a2c80), + SPH_C32(0x895d7f6f), SPH_C32(0x6ab93736), SPH_C32(0x4bc9f29b), + SPH_C32(0x3f957917) }, + { SPH_C32(0x55c50000), SPH_C32(0x68730000), SPH_C32(0xb1710000), + SPH_C32(0x234e7c80), SPH_C32(0x48051fcd), SPH_C32(0x5b9edfda), + SPH_C32(0x65514db8), SPH_C32(0x6a8b4479), SPH_C32(0x0eec0000), + SPH_C32(0x649e0000), SPH_C32(0x06ba0000), SPH_C32(0x88f82ce0), + SPH_C32(0xa7e77575), SPH_C32(0xe70c0067), SPH_C32(0x380c599d), + SPH_C32(0x64436c2e) } +}; + +static const sph_u32 T512_54[8][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0x7b280000), SPH_C32(0x57420000), SPH_C32(0xa9e50000), + SPH_C32(0x634300a0), SPH_C32(0x9edb442f), SPH_C32(0x6d9995bb), + SPH_C32(0x27f83b03), SPH_C32(0xc7ff60f0), SPH_C32(0x95bb0000), + SPH_C32(0x81450000), SPH_C32(0x3b240000), SPH_C32(0x48db0140), + SPH_C32(0x0a8a6c53), SPH_C32(0x56f56eec), SPH_C32(0x62c91877), + SPH_C32(0xe7e00a94) }, + { SPH_C32(0xe6280000), SPH_C32(0x4c4b0000), SPH_C32(0xa8550000), + SPH_C32(0xd3d002e0), SPH_C32(0xd86130b8), SPH_C32(0x98a7b0da), + SPH_C32(0x289506b4), SPH_C32(0xd75a4897), SPH_C32(0xf0c50000), + SPH_C32(0x59230000), SPH_C32(0x45820000), SPH_C32(0xe18d00c0), + SPH_C32(0x3b6d0631), SPH_C32(0xc2ed5699), SPH_C32(0xcbe0fe1c), + SPH_C32(0x56a7b19f) }, + { SPH_C32(0x9d000000), SPH_C32(0x1b090000), SPH_C32(0x01b00000), + SPH_C32(0xb0930240), SPH_C32(0x46ba7497), SPH_C32(0xf53e2561), + SPH_C32(0x0f6d3db7), SPH_C32(0x10a52867), SPH_C32(0x657e0000), + SPH_C32(0xd8660000), SPH_C32(0x7ea60000), SPH_C32(0xa9560180), + SPH_C32(0x31e76a62), SPH_C32(0x94183875), SPH_C32(0xa929e66b), + SPH_C32(0xb147bb0b) }, + { SPH_C32(0xf0c50000), SPH_C32(0x59230000), SPH_C32(0x45820000), + SPH_C32(0xe18d00c0), SPH_C32(0x3b6d0631), SPH_C32(0xc2ed5699), + SPH_C32(0xcbe0fe1c), SPH_C32(0x56a7b19f), SPH_C32(0x16ed0000), + SPH_C32(0x15680000), SPH_C32(0xedd70000), SPH_C32(0x325d0220), + SPH_C32(0xe30c3689), SPH_C32(0x5a4ae643), SPH_C32(0xe375f8a8), + SPH_C32(0x81fdf908) }, + { SPH_C32(0x8bed0000), SPH_C32(0x0e610000), SPH_C32(0xec670000), + SPH_C32(0x82ce0060), SPH_C32(0xa5b6421e), SPH_C32(0xaf74c322), + SPH_C32(0xec18c51f), SPH_C32(0x9158d16f), SPH_C32(0x83560000), + SPH_C32(0x942d0000), SPH_C32(0xd6f30000), SPH_C32(0x7a860360), + SPH_C32(0xe9865ada), SPH_C32(0x0cbf88af), SPH_C32(0x81bce0df), + SPH_C32(0x661df39c) }, + { SPH_C32(0x16ed0000), SPH_C32(0x15680000), SPH_C32(0xedd70000), + SPH_C32(0x325d0220), SPH_C32(0xe30c3689), SPH_C32(0x5a4ae643), + SPH_C32(0xe375f8a8), SPH_C32(0x81fdf908), SPH_C32(0xe6280000), + SPH_C32(0x4c4b0000), SPH_C32(0xa8550000), SPH_C32(0xd3d002e0), + SPH_C32(0xd86130b8), SPH_C32(0x98a7b0da), SPH_C32(0x289506b4), + SPH_C32(0xd75a4897) }, + { SPH_C32(0x6dc50000), SPH_C32(0x422a0000), SPH_C32(0x44320000), + SPH_C32(0x511e0280), SPH_C32(0x7dd772a6), SPH_C32(0x37d373f8), + SPH_C32(0xc48dc3ab), SPH_C32(0x460299f8), SPH_C32(0x73930000), + SPH_C32(0xcd0e0000), SPH_C32(0x93710000), SPH_C32(0x9b0b03a0), + SPH_C32(0xd2eb5ceb), SPH_C32(0xce52de36), SPH_C32(0x4a5c1ec3), + SPH_C32(0x30ba4203) } +}; + +static const sph_u32 T512_57[8][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0x5fa80000), SPH_C32(0x56030000), SPH_C32(0x43ae0000), + SPH_C32(0x64f30013), SPH_C32(0x257e86bf), SPH_C32(0x1311944e), + SPH_C32(0x541e95bf), SPH_C32(0x8ea4db69), SPH_C32(0x00440000), + SPH_C32(0x7f480000), SPH_C32(0xda7c0000), SPH_C32(0x2a230001), + SPH_C32(0x3badc9cc), SPH_C32(0xa9b69c87), SPH_C32(0x030a9e60), + SPH_C32(0xbe0a679e) }, + { SPH_C32(0x00440000), SPH_C32(0x7f480000), SPH_C32(0xda7c0000), + SPH_C32(0x2a230001), SPH_C32(0x3badc9cc), SPH_C32(0xa9b69c87), + SPH_C32(0x030a9e60), SPH_C32(0xbe0a679e), SPH_C32(0x5fec0000), + SPH_C32(0x294b0000), SPH_C32(0x99d20000), SPH_C32(0x4ed00012), + SPH_C32(0x1ed34f73), SPH_C32(0xbaa708c9), SPH_C32(0x57140bdf), + SPH_C32(0x30aebcf7) }, + { SPH_C32(0x5fec0000), SPH_C32(0x294b0000), SPH_C32(0x99d20000), + SPH_C32(0x4ed00012), SPH_C32(0x1ed34f73), SPH_C32(0xbaa708c9), + SPH_C32(0x57140bdf), SPH_C32(0x30aebcf7), SPH_C32(0x5fa80000), + SPH_C32(0x56030000), SPH_C32(0x43ae0000), SPH_C32(0x64f30013), + SPH_C32(0x257e86bf), SPH_C32(0x1311944e), SPH_C32(0x541e95bf), + SPH_C32(0x8ea4db69) }, + { SPH_C32(0xee930000), SPH_C32(0xd6070000), SPH_C32(0x92c10000), + SPH_C32(0x2b9801e0), SPH_C32(0x9451287c), SPH_C32(0x3b6cfb57), + SPH_C32(0x45312374), SPH_C32(0x201f6a64), SPH_C32(0x7b280000), + SPH_C32(0x57420000), SPH_C32(0xa9e50000), SPH_C32(0x634300a0), + SPH_C32(0x9edb442f), SPH_C32(0x6d9995bb), SPH_C32(0x27f83b03), + SPH_C32(0xc7ff60f0) }, + { SPH_C32(0xb13b0000), SPH_C32(0x80040000), SPH_C32(0xd16f0000), + SPH_C32(0x4f6b01f3), SPH_C32(0xb12faec3), SPH_C32(0x287d6f19), + SPH_C32(0x112fb6cb), SPH_C32(0xaebbb10d), SPH_C32(0x7b6c0000), + SPH_C32(0x280a0000), SPH_C32(0x73990000), SPH_C32(0x496000a1), + SPH_C32(0xa5768de3), SPH_C32(0xc42f093c), SPH_C32(0x24f2a563), + SPH_C32(0x79f5076e) }, + { SPH_C32(0xeed70000), SPH_C32(0xa94f0000), SPH_C32(0x48bd0000), + SPH_C32(0x01bb01e1), SPH_C32(0xaffce1b0), SPH_C32(0x92da67d0), + SPH_C32(0x463bbd14), SPH_C32(0x9e150dfa), SPH_C32(0x24c40000), + SPH_C32(0x7e090000), SPH_C32(0x30370000), SPH_C32(0x2d9300b2), + SPH_C32(0x80080b5c), SPH_C32(0xd73e9d72), SPH_C32(0x70ec30dc), + SPH_C32(0xf751dc07) }, + { SPH_C32(0xb17f0000), SPH_C32(0xff4c0000), SPH_C32(0x0b130000), + SPH_C32(0x654801f2), SPH_C32(0x8a82670f), SPH_C32(0x81cbf39e), + SPH_C32(0x122528ab), SPH_C32(0x10b1d693), SPH_C32(0x24800000), + SPH_C32(0x01410000), SPH_C32(0xea4b0000), SPH_C32(0x07b000b3), + SPH_C32(0xbba5c290), SPH_C32(0x7e8801f5), SPH_C32(0x73e6aebc), + SPH_C32(0x495bbb99) } +}; + +static const sph_u32 T512_60[8][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0xa8da0000), SPH_C32(0x96be0000), SPH_C32(0x5c1d0000), + SPH_C32(0x07da0002), SPH_C32(0x7d669583), SPH_C32(0x1f98708a), + SPH_C32(0xbb668808), SPH_C32(0xda878000), SPH_C32(0xabe70000), + SPH_C32(0x9e0d0000), SPH_C32(0xaf270000), SPH_C32(0x3d180005), + SPH_C32(0x2c4f1fd3), SPH_C32(0x74f61695), SPH_C32(0xb5c347eb), + SPH_C32(0x3c5dfffe) }, + { SPH_C32(0x01930000), SPH_C32(0xe7820000), SPH_C32(0xedfb0000), + SPH_C32(0xcf0c000b), SPH_C32(0x8dd08d58), SPH_C32(0xbca3b42e), + SPH_C32(0x063661e1), SPH_C32(0x536f9e7b), SPH_C32(0x92280000), + SPH_C32(0xdc850000), SPH_C32(0x57fa0000), SPH_C32(0x56dc0003), + SPH_C32(0xbae92316), SPH_C32(0x5aefa30c), SPH_C32(0x90cef752), + SPH_C32(0x7b1675d7) }, + { SPH_C32(0xa9490000), SPH_C32(0x713c0000), SPH_C32(0xb1e60000), + SPH_C32(0xc8d60009), SPH_C32(0xf0b618db), SPH_C32(0xa33bc4a4), + SPH_C32(0xbd50e9e9), SPH_C32(0x89e81e7b), SPH_C32(0x39cf0000), + SPH_C32(0x42880000), SPH_C32(0xf8dd0000), SPH_C32(0x6bc40006), + SPH_C32(0x96a63cc5), SPH_C32(0x2e19b599), SPH_C32(0x250db0b9), + SPH_C32(0x474b8a29) }, + { SPH_C32(0x92280000), SPH_C32(0xdc850000), SPH_C32(0x57fa0000), + SPH_C32(0x56dc0003), SPH_C32(0xbae92316), SPH_C32(0x5aefa30c), + SPH_C32(0x90cef752), SPH_C32(0x7b1675d7), SPH_C32(0x93bb0000), + SPH_C32(0x3b070000), SPH_C32(0xba010000), SPH_C32(0x99d00008), + SPH_C32(0x3739ae4e), SPH_C32(0xe64c1722), SPH_C32(0x96f896b3), + SPH_C32(0x2879ebac) }, + { SPH_C32(0x3af20000), SPH_C32(0x4a3b0000), SPH_C32(0x0be70000), + SPH_C32(0x51060001), SPH_C32(0xc78fb695), SPH_C32(0x4577d386), + SPH_C32(0x2ba87f5a), SPH_C32(0xa191f5d7), SPH_C32(0x385c0000), + SPH_C32(0xa50a0000), SPH_C32(0x15260000), SPH_C32(0xa4c8000d), + SPH_C32(0x1b76b19d), SPH_C32(0x92ba01b7), SPH_C32(0x233bd158), + SPH_C32(0x14241452) }, + { SPH_C32(0x93bb0000), SPH_C32(0x3b070000), SPH_C32(0xba010000), + SPH_C32(0x99d00008), SPH_C32(0x3739ae4e), SPH_C32(0xe64c1722), + SPH_C32(0x96f896b3), SPH_C32(0x2879ebac), SPH_C32(0x01930000), + SPH_C32(0xe7820000), SPH_C32(0xedfb0000), SPH_C32(0xcf0c000b), + SPH_C32(0x8dd08d58), SPH_C32(0xbca3b42e), SPH_C32(0x063661e1), + SPH_C32(0x536f9e7b) }, + { SPH_C32(0x3b610000), SPH_C32(0xadb90000), SPH_C32(0xe61c0000), + SPH_C32(0x9e0a000a), SPH_C32(0x4a5f3bcd), SPH_C32(0xf9d467a8), + SPH_C32(0x2d9e1ebb), SPH_C32(0xf2fe6bac), SPH_C32(0xaa740000), + SPH_C32(0x798f0000), SPH_C32(0x42dc0000), SPH_C32(0xf214000e), + SPH_C32(0xa19f928b), SPH_C32(0xc855a2bb), SPH_C32(0xb3f5260a), + SPH_C32(0x6f326185) } +}; + +static const sph_u32 T512_63[2][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0x033d0000), SPH_C32(0x08b30000), SPH_C32(0xf33a0000), + SPH_C32(0x3ac20007), SPH_C32(0x51298a50), SPH_C32(0x6b6e661f), + SPH_C32(0x0ea5cfe3), SPH_C32(0xe6da7ffe), SPH_C32(0xa8da0000), + SPH_C32(0x96be0000), SPH_C32(0x5c1d0000), SPH_C32(0x07da0002), + SPH_C32(0x7d669583), SPH_C32(0x1f98708a), SPH_C32(0xbb668808), + SPH_C32(0xda878000) } +}; + +#define INPUT_BIG do { \ + unsigned acc = buf[0]; \ + const sph_u32 *rp; \ + rp = &T512_0[acc >> 5][0]; \ + m0 = rp[0]; \ + m1 = rp[1]; \ + m2 = rp[2]; \ + m3 = rp[3]; \ + m4 = rp[4]; \ + m5 = rp[5]; \ + m6 = rp[6]; \ + m7 = rp[7]; \ + m8 = rp[8]; \ + m9 = rp[9]; \ + mA = rp[10]; \ + mB = rp[11]; \ + mC = rp[12]; \ + mD = rp[13]; \ + mE = rp[14]; \ + mF = rp[15]; \ + rp = &T512_3[(acc >> 2) & 0x07][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + m8 ^= rp[8]; \ + m9 ^= rp[9]; \ + mA ^= rp[10]; \ + mB ^= rp[11]; \ + mC ^= rp[12]; \ + mD ^= rp[13]; \ + mE ^= rp[14]; \ + mF ^= rp[15]; \ + acc = (acc << 8) | buf[1]; \ + rp = &T512_6[(acc >> 7) & 0x07][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + m8 ^= rp[8]; \ + m9 ^= rp[9]; \ + mA ^= rp[10]; \ + mB ^= rp[11]; \ + mC ^= rp[12]; \ + mD ^= rp[13]; \ + mE ^= rp[14]; \ + mF ^= rp[15]; \ + rp = &T512_9[(acc >> 4) & 0x07][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + m8 ^= rp[8]; \ + m9 ^= rp[9]; \ + mA ^= rp[10]; \ + mB ^= rp[11]; \ + mC ^= rp[12]; \ + mD ^= rp[13]; \ + mE ^= rp[14]; \ + mF ^= rp[15]; \ + rp = &T512_12[(acc >> 1) & 0x07][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + m8 ^= rp[8]; \ + m9 ^= rp[9]; \ + mA ^= rp[10]; \ + mB ^= rp[11]; \ + mC ^= rp[12]; \ + mD ^= rp[13]; \ + mE ^= rp[14]; \ + mF ^= rp[15]; \ + acc = (acc << 8) | buf[2]; \ + rp = &T512_15[(acc >> 6) & 0x07][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + m8 ^= rp[8]; \ + m9 ^= rp[9]; \ + mA ^= rp[10]; \ + mB ^= rp[11]; \ + mC ^= rp[12]; \ + mD ^= rp[13]; \ + mE ^= rp[14]; \ + mF ^= rp[15]; \ + rp = &T512_18[(acc >> 3) & 0x07][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + m8 ^= rp[8]; \ + m9 ^= rp[9]; \ + mA ^= rp[10]; \ + mB ^= rp[11]; \ + mC ^= rp[12]; \ + mD ^= rp[13]; \ + mE ^= rp[14]; \ + mF ^= rp[15]; \ + rp = &T512_21[acc & 0x07][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + m8 ^= rp[8]; \ + m9 ^= rp[9]; \ + mA ^= rp[10]; \ + mB ^= rp[11]; \ + mC ^= rp[12]; \ + mD ^= rp[13]; \ + mE ^= rp[14]; \ + mF ^= rp[15]; \ + acc = buf[3]; \ + rp = &T512_24[acc >> 5][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + m8 ^= rp[8]; \ + m9 ^= rp[9]; \ + mA ^= rp[10]; \ + mB ^= rp[11]; \ + mC ^= rp[12]; \ + mD ^= rp[13]; \ + mE ^= rp[14]; \ + mF ^= rp[15]; \ + rp = &T512_27[(acc >> 2) & 0x07][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + m8 ^= rp[8]; \ + m9 ^= rp[9]; \ + mA ^= rp[10]; \ + mB ^= rp[11]; \ + mC ^= rp[12]; \ + mD ^= rp[13]; \ + mE ^= rp[14]; \ + mF ^= rp[15]; \ + acc = (acc << 8) | buf[4]; \ + rp = &T512_30[(acc >> 7) & 0x07][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + m8 ^= rp[8]; \ + m9 ^= rp[9]; \ + mA ^= rp[10]; \ + mB ^= rp[11]; \ + mC ^= rp[12]; \ + mD ^= rp[13]; \ + mE ^= rp[14]; \ + mF ^= rp[15]; \ + rp = &T512_33[(acc >> 4) & 0x07][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + m8 ^= rp[8]; \ + m9 ^= rp[9]; \ + mA ^= rp[10]; \ + mB ^= rp[11]; \ + mC ^= rp[12]; \ + mD ^= rp[13]; \ + mE ^= rp[14]; \ + mF ^= rp[15]; \ + rp = &T512_36[(acc >> 1) & 0x07][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + m8 ^= rp[8]; \ + m9 ^= rp[9]; \ + mA ^= rp[10]; \ + mB ^= rp[11]; \ + mC ^= rp[12]; \ + mD ^= rp[13]; \ + mE ^= rp[14]; \ + mF ^= rp[15]; \ + acc = (acc << 8) | buf[5]; \ + rp = &T512_39[(acc >> 6) & 0x07][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + m8 ^= rp[8]; \ + m9 ^= rp[9]; \ + mA ^= rp[10]; \ + mB ^= rp[11]; \ + mC ^= rp[12]; \ + mD ^= rp[13]; \ + mE ^= rp[14]; \ + mF ^= rp[15]; \ + rp = &T512_42[(acc >> 3) & 0x07][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + m8 ^= rp[8]; \ + m9 ^= rp[9]; \ + mA ^= rp[10]; \ + mB ^= rp[11]; \ + mC ^= rp[12]; \ + mD ^= rp[13]; \ + mE ^= rp[14]; \ + mF ^= rp[15]; \ + rp = &T512_45[acc & 0x07][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + m8 ^= rp[8]; \ + m9 ^= rp[9]; \ + mA ^= rp[10]; \ + mB ^= rp[11]; \ + mC ^= rp[12]; \ + mD ^= rp[13]; \ + mE ^= rp[14]; \ + mF ^= rp[15]; \ + acc = buf[6]; \ + rp = &T512_48[acc >> 5][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + m8 ^= rp[8]; \ + m9 ^= rp[9]; \ + mA ^= rp[10]; \ + mB ^= rp[11]; \ + mC ^= rp[12]; \ + mD ^= rp[13]; \ + mE ^= rp[14]; \ + mF ^= rp[15]; \ + rp = &T512_51[(acc >> 2) & 0x07][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + m8 ^= rp[8]; \ + m9 ^= rp[9]; \ + mA ^= rp[10]; \ + mB ^= rp[11]; \ + mC ^= rp[12]; \ + mD ^= rp[13]; \ + mE ^= rp[14]; \ + mF ^= rp[15]; \ + acc = (acc << 8) | buf[7]; \ + rp = &T512_54[(acc >> 7) & 0x07][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + m8 ^= rp[8]; \ + m9 ^= rp[9]; \ + mA ^= rp[10]; \ + mB ^= rp[11]; \ + mC ^= rp[12]; \ + mD ^= rp[13]; \ + mE ^= rp[14]; \ + mF ^= rp[15]; \ + rp = &T512_57[(acc >> 4) & 0x07][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + m8 ^= rp[8]; \ + m9 ^= rp[9]; \ + mA ^= rp[10]; \ + mB ^= rp[11]; \ + mC ^= rp[12]; \ + mD ^= rp[13]; \ + mE ^= rp[14]; \ + mF ^= rp[15]; \ + rp = &T512_60[(acc >> 1) & 0x07][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + m8 ^= rp[8]; \ + m9 ^= rp[9]; \ + mA ^= rp[10]; \ + mB ^= rp[11]; \ + mC ^= rp[12]; \ + mD ^= rp[13]; \ + mE ^= rp[14]; \ + mF ^= rp[15]; \ + rp = &T512_63[acc & 0x01][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + m8 ^= rp[8]; \ + m9 ^= rp[9]; \ + mA ^= rp[10]; \ + mB ^= rp[11]; \ + mC ^= rp[12]; \ + mD ^= rp[13]; \ + mE ^= rp[14]; \ + mF ^= rp[15]; \ + } while (0) + +#endif + +#if SPH_HAMSI_EXPAND_BIG == 4 + +static const sph_u32 T512_0[16][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0x54285c00), SPH_C32(0xeaed0000), SPH_C32(0xc5d60000), + SPH_C32(0xa1c50000), SPH_C32(0xb3a26770), SPH_C32(0x94a5c4e1), + SPH_C32(0x6bb0419d), SPH_C32(0x551b3782), SPH_C32(0x9cbb1800), + SPH_C32(0xb0d30000), SPH_C32(0x92510000), SPH_C32(0xed930000), + SPH_C32(0x593a4345), SPH_C32(0xe114d5f4), SPH_C32(0x430633da), + SPH_C32(0x78cace29) }, + { SPH_C32(0x9cbb1800), SPH_C32(0xb0d30000), SPH_C32(0x92510000), + SPH_C32(0xed930000), SPH_C32(0x593a4345), SPH_C32(0xe114d5f4), + SPH_C32(0x430633da), SPH_C32(0x78cace29), SPH_C32(0xc8934400), + SPH_C32(0x5a3e0000), SPH_C32(0x57870000), SPH_C32(0x4c560000), + SPH_C32(0xea982435), SPH_C32(0x75b11115), SPH_C32(0x28b67247), + SPH_C32(0x2dd1f9ab) }, + { SPH_C32(0xc8934400), SPH_C32(0x5a3e0000), SPH_C32(0x57870000), + SPH_C32(0x4c560000), SPH_C32(0xea982435), SPH_C32(0x75b11115), + SPH_C32(0x28b67247), SPH_C32(0x2dd1f9ab), SPH_C32(0x54285c00), + SPH_C32(0xeaed0000), SPH_C32(0xc5d60000), SPH_C32(0xa1c50000), + SPH_C32(0xb3a26770), SPH_C32(0x94a5c4e1), SPH_C32(0x6bb0419d), + SPH_C32(0x551b3782) }, + { SPH_C32(0x29449c00), SPH_C32(0x64e70000), SPH_C32(0xf24b0000), + SPH_C32(0xc2f30000), SPH_C32(0x0ede4e8f), SPH_C32(0x56c23745), + SPH_C32(0xf3e04259), SPH_C32(0x8d0d9ec4), SPH_C32(0x466d0c00), + SPH_C32(0x08620000), SPH_C32(0xdd5d0000), SPH_C32(0xbadd0000), + SPH_C32(0x6a927942), SPH_C32(0x441f2b93), SPH_C32(0x218ace6f), + SPH_C32(0xbf2c0be2) }, + { SPH_C32(0x7d6cc000), SPH_C32(0x8e0a0000), SPH_C32(0x379d0000), + SPH_C32(0x63360000), SPH_C32(0xbd7c29ff), SPH_C32(0xc267f3a4), + SPH_C32(0x985003c4), SPH_C32(0xd816a946), SPH_C32(0xdad61400), + SPH_C32(0xb8b10000), SPH_C32(0x4f0c0000), SPH_C32(0x574e0000), + SPH_C32(0x33a83a07), SPH_C32(0xa50bfe67), SPH_C32(0x628cfdb5), + SPH_C32(0xc7e6c5cb) }, + { SPH_C32(0xb5ff8400), SPH_C32(0xd4340000), SPH_C32(0x601a0000), + SPH_C32(0x2f600000), SPH_C32(0x57e40dca), SPH_C32(0xb7d6e2b1), + SPH_C32(0xb0e67183), SPH_C32(0xf5c750ed), SPH_C32(0x8efe4800), + SPH_C32(0x525c0000), SPH_C32(0x8ada0000), SPH_C32(0xf68b0000), + SPH_C32(0x800a5d77), SPH_C32(0x31ae3a86), SPH_C32(0x093cbc28), + SPH_C32(0x92fdf249) }, + { SPH_C32(0xe1d7d800), SPH_C32(0x3ed90000), SPH_C32(0xa5cc0000), + SPH_C32(0x8ea50000), SPH_C32(0xe4466aba), SPH_C32(0x23732650), + SPH_C32(0xdb56301e), SPH_C32(0xa0dc676f), SPH_C32(0x12455000), + SPH_C32(0xe28f0000), SPH_C32(0x188b0000), SPH_C32(0x1b180000), + SPH_C32(0xd9301e32), SPH_C32(0xd0baef72), SPH_C32(0x4a3a8ff2), + SPH_C32(0xea373c60) }, + { SPH_C32(0x466d0c00), SPH_C32(0x08620000), SPH_C32(0xdd5d0000), + SPH_C32(0xbadd0000), SPH_C32(0x6a927942), SPH_C32(0x441f2b93), + SPH_C32(0x218ace6f), SPH_C32(0xbf2c0be2), SPH_C32(0x6f299000), + SPH_C32(0x6c850000), SPH_C32(0x2f160000), SPH_C32(0x782e0000), + SPH_C32(0x644c37cd), SPH_C32(0x12dd1cd6), SPH_C32(0xd26a8c36), + SPH_C32(0x32219526) }, + { SPH_C32(0x12455000), SPH_C32(0xe28f0000), SPH_C32(0x188b0000), + SPH_C32(0x1b180000), SPH_C32(0xd9301e32), SPH_C32(0xd0baef72), + SPH_C32(0x4a3a8ff2), SPH_C32(0xea373c60), SPH_C32(0xf3928800), + SPH_C32(0xdc560000), SPH_C32(0xbd470000), SPH_C32(0x95bd0000), + SPH_C32(0x3d767488), SPH_C32(0xf3c9c922), SPH_C32(0x916cbfec), + SPH_C32(0x4aeb5b0f) }, + { SPH_C32(0xdad61400), SPH_C32(0xb8b10000), SPH_C32(0x4f0c0000), + SPH_C32(0x574e0000), SPH_C32(0x33a83a07), SPH_C32(0xa50bfe67), + SPH_C32(0x628cfdb5), SPH_C32(0xc7e6c5cb), SPH_C32(0xa7bad400), + SPH_C32(0x36bb0000), SPH_C32(0x78910000), SPH_C32(0x34780000), + SPH_C32(0x8ed413f8), SPH_C32(0x676c0dc3), SPH_C32(0xfadcfe71), + SPH_C32(0x1ff06c8d) }, + { SPH_C32(0x8efe4800), SPH_C32(0x525c0000), SPH_C32(0x8ada0000), + SPH_C32(0xf68b0000), SPH_C32(0x800a5d77), SPH_C32(0x31ae3a86), + SPH_C32(0x093cbc28), SPH_C32(0x92fdf249), SPH_C32(0x3b01cc00), + SPH_C32(0x86680000), SPH_C32(0xeac00000), SPH_C32(0xd9eb0000), + SPH_C32(0xd7ee50bd), SPH_C32(0x8678d837), SPH_C32(0xb9dacdab), + SPH_C32(0x673aa2a4) }, + { SPH_C32(0x6f299000), SPH_C32(0x6c850000), SPH_C32(0x2f160000), + SPH_C32(0x782e0000), SPH_C32(0x644c37cd), SPH_C32(0x12dd1cd6), + SPH_C32(0xd26a8c36), SPH_C32(0x32219526), SPH_C32(0x29449c00), + SPH_C32(0x64e70000), SPH_C32(0xf24b0000), SPH_C32(0xc2f30000), + SPH_C32(0x0ede4e8f), SPH_C32(0x56c23745), SPH_C32(0xf3e04259), + SPH_C32(0x8d0d9ec4) }, + { SPH_C32(0x3b01cc00), SPH_C32(0x86680000), SPH_C32(0xeac00000), + SPH_C32(0xd9eb0000), SPH_C32(0xd7ee50bd), SPH_C32(0x8678d837), + SPH_C32(0xb9dacdab), SPH_C32(0x673aa2a4), SPH_C32(0xb5ff8400), + SPH_C32(0xd4340000), SPH_C32(0x601a0000), SPH_C32(0x2f600000), + SPH_C32(0x57e40dca), SPH_C32(0xb7d6e2b1), SPH_C32(0xb0e67183), + SPH_C32(0xf5c750ed) }, + { SPH_C32(0xf3928800), SPH_C32(0xdc560000), SPH_C32(0xbd470000), + SPH_C32(0x95bd0000), SPH_C32(0x3d767488), SPH_C32(0xf3c9c922), + SPH_C32(0x916cbfec), SPH_C32(0x4aeb5b0f), SPH_C32(0xe1d7d800), + SPH_C32(0x3ed90000), SPH_C32(0xa5cc0000), SPH_C32(0x8ea50000), + SPH_C32(0xe4466aba), SPH_C32(0x23732650), SPH_C32(0xdb56301e), + SPH_C32(0xa0dc676f) }, + { SPH_C32(0xa7bad400), SPH_C32(0x36bb0000), SPH_C32(0x78910000), + SPH_C32(0x34780000), SPH_C32(0x8ed413f8), SPH_C32(0x676c0dc3), + SPH_C32(0xfadcfe71), SPH_C32(0x1ff06c8d), SPH_C32(0x7d6cc000), + SPH_C32(0x8e0a0000), SPH_C32(0x379d0000), SPH_C32(0x63360000), + SPH_C32(0xbd7c29ff), SPH_C32(0xc267f3a4), SPH_C32(0x985003c4), + SPH_C32(0xd816a946) } +}; + +static const sph_u32 T512_4[16][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0xef0b0270), SPH_C32(0x3afd0000), SPH_C32(0x5dae0000), + SPH_C32(0x69490000), SPH_C32(0x9b0f3c06), SPH_C32(0x4405b5f9), + SPH_C32(0x66140a51), SPH_C32(0x924f5d0a), SPH_C32(0xc96b0030), + SPH_C32(0xe7250000), SPH_C32(0x2f840000), SPH_C32(0x264f0000), + SPH_C32(0x08695bf9), SPH_C32(0x6dfcf137), SPH_C32(0x509f6984), + SPH_C32(0x9e69af68) }, + { SPH_C32(0xc96b0030), SPH_C32(0xe7250000), SPH_C32(0x2f840000), + SPH_C32(0x264f0000), SPH_C32(0x08695bf9), SPH_C32(0x6dfcf137), + SPH_C32(0x509f6984), SPH_C32(0x9e69af68), SPH_C32(0x26600240), + SPH_C32(0xddd80000), SPH_C32(0x722a0000), SPH_C32(0x4f060000), + SPH_C32(0x936667ff), SPH_C32(0x29f944ce), SPH_C32(0x368b63d5), + SPH_C32(0x0c26f262) }, + { SPH_C32(0x26600240), SPH_C32(0xddd80000), SPH_C32(0x722a0000), + SPH_C32(0x4f060000), SPH_C32(0x936667ff), SPH_C32(0x29f944ce), + SPH_C32(0x368b63d5), SPH_C32(0x0c26f262), SPH_C32(0xef0b0270), + SPH_C32(0x3afd0000), SPH_C32(0x5dae0000), SPH_C32(0x69490000), + SPH_C32(0x9b0f3c06), SPH_C32(0x4405b5f9), SPH_C32(0x66140a51), + SPH_C32(0x924f5d0a) }, + { SPH_C32(0x145a3c00), SPH_C32(0xb9e90000), SPH_C32(0x61270000), + SPH_C32(0xf1610000), SPH_C32(0xce613d6c), SPH_C32(0xb0493d78), + SPH_C32(0x47a96720), SPH_C32(0xe18e24c5), SPH_C32(0x23671400), + SPH_C32(0xc8b90000), SPH_C32(0xf4c70000), SPH_C32(0xfb750000), + SPH_C32(0x73cd2465), SPH_C32(0xf8a6a549), SPH_C32(0x02c40a3f), + SPH_C32(0xdc24e61f) }, + { SPH_C32(0xfb513e70), SPH_C32(0x83140000), SPH_C32(0x3c890000), + SPH_C32(0x98280000), SPH_C32(0x556e016a), SPH_C32(0xf44c8881), + SPH_C32(0x21bd6d71), SPH_C32(0x73c179cf), SPH_C32(0xea0c1430), + SPH_C32(0x2f9c0000), SPH_C32(0xdb430000), SPH_C32(0xdd3a0000), + SPH_C32(0x7ba47f9c), SPH_C32(0x955a547e), SPH_C32(0x525b63bb), + SPH_C32(0x424d4977) }, + { SPH_C32(0xdd313c30), SPH_C32(0x5ecc0000), SPH_C32(0x4ea30000), + SPH_C32(0xd72e0000), SPH_C32(0xc6086695), SPH_C32(0xddb5cc4f), + SPH_C32(0x17360ea4), SPH_C32(0x7fe78bad), SPH_C32(0x05071640), + SPH_C32(0x15610000), SPH_C32(0x86ed0000), SPH_C32(0xb4730000), + SPH_C32(0xe0ab439a), SPH_C32(0xd15fe187), SPH_C32(0x344f69ea), + SPH_C32(0xd002147d) }, + { SPH_C32(0x323a3e40), SPH_C32(0x64310000), SPH_C32(0x130d0000), + SPH_C32(0xbe670000), SPH_C32(0x5d075a93), SPH_C32(0x99b079b6), + SPH_C32(0x712204f5), SPH_C32(0xeda8d6a7), SPH_C32(0xcc6c1670), + SPH_C32(0xf2440000), SPH_C32(0xa9690000), SPH_C32(0x923c0000), + SPH_C32(0xe8c21863), SPH_C32(0xbca310b0), SPH_C32(0x64d0006e), + SPH_C32(0x4e6bbb15) }, + { SPH_C32(0x23671400), SPH_C32(0xc8b90000), SPH_C32(0xf4c70000), + SPH_C32(0xfb750000), SPH_C32(0x73cd2465), SPH_C32(0xf8a6a549), + SPH_C32(0x02c40a3f), SPH_C32(0xdc24e61f), SPH_C32(0x373d2800), + SPH_C32(0x71500000), SPH_C32(0x95e00000), SPH_C32(0x0a140000), + SPH_C32(0xbdac1909), SPH_C32(0x48ef9831), SPH_C32(0x456d6d1f), + SPH_C32(0x3daac2da) }, + { SPH_C32(0xcc6c1670), SPH_C32(0xf2440000), SPH_C32(0xa9690000), + SPH_C32(0x923c0000), SPH_C32(0xe8c21863), SPH_C32(0xbca310b0), + SPH_C32(0x64d0006e), SPH_C32(0x4e6bbb15), SPH_C32(0xfe562830), + SPH_C32(0x96750000), SPH_C32(0xba640000), SPH_C32(0x2c5b0000), + SPH_C32(0xb5c542f0), SPH_C32(0x25136906), SPH_C32(0x15f2049b), + SPH_C32(0xa3c36db2) }, + { SPH_C32(0xea0c1430), SPH_C32(0x2f9c0000), SPH_C32(0xdb430000), + SPH_C32(0xdd3a0000), SPH_C32(0x7ba47f9c), SPH_C32(0x955a547e), + SPH_C32(0x525b63bb), SPH_C32(0x424d4977), SPH_C32(0x115d2a40), + SPH_C32(0xac880000), SPH_C32(0xe7ca0000), SPH_C32(0x45120000), + SPH_C32(0x2eca7ef6), SPH_C32(0x6116dcff), SPH_C32(0x73e60eca), + SPH_C32(0x318c30b8) }, + { SPH_C32(0x05071640), SPH_C32(0x15610000), SPH_C32(0x86ed0000), + SPH_C32(0xb4730000), SPH_C32(0xe0ab439a), SPH_C32(0xd15fe187), + SPH_C32(0x344f69ea), SPH_C32(0xd002147d), SPH_C32(0xd8362a70), + SPH_C32(0x4bad0000), SPH_C32(0xc84e0000), SPH_C32(0x635d0000), + SPH_C32(0x26a3250f), SPH_C32(0x0cea2dc8), SPH_C32(0x2379674e), + SPH_C32(0xafe59fd0) }, + { SPH_C32(0x373d2800), SPH_C32(0x71500000), SPH_C32(0x95e00000), + SPH_C32(0x0a140000), SPH_C32(0xbdac1909), SPH_C32(0x48ef9831), + SPH_C32(0x456d6d1f), SPH_C32(0x3daac2da), SPH_C32(0x145a3c00), + SPH_C32(0xb9e90000), SPH_C32(0x61270000), SPH_C32(0xf1610000), + SPH_C32(0xce613d6c), SPH_C32(0xb0493d78), SPH_C32(0x47a96720), + SPH_C32(0xe18e24c5) }, + { SPH_C32(0xd8362a70), SPH_C32(0x4bad0000), SPH_C32(0xc84e0000), + SPH_C32(0x635d0000), SPH_C32(0x26a3250f), SPH_C32(0x0cea2dc8), + SPH_C32(0x2379674e), SPH_C32(0xafe59fd0), SPH_C32(0xdd313c30), + SPH_C32(0x5ecc0000), SPH_C32(0x4ea30000), SPH_C32(0xd72e0000), + SPH_C32(0xc6086695), SPH_C32(0xddb5cc4f), SPH_C32(0x17360ea4), + SPH_C32(0x7fe78bad) }, + { SPH_C32(0xfe562830), SPH_C32(0x96750000), SPH_C32(0xba640000), + SPH_C32(0x2c5b0000), SPH_C32(0xb5c542f0), SPH_C32(0x25136906), + SPH_C32(0x15f2049b), SPH_C32(0xa3c36db2), SPH_C32(0x323a3e40), + SPH_C32(0x64310000), SPH_C32(0x130d0000), SPH_C32(0xbe670000), + SPH_C32(0x5d075a93), SPH_C32(0x99b079b6), SPH_C32(0x712204f5), + SPH_C32(0xeda8d6a7) }, + { SPH_C32(0x115d2a40), SPH_C32(0xac880000), SPH_C32(0xe7ca0000), + SPH_C32(0x45120000), SPH_C32(0x2eca7ef6), SPH_C32(0x6116dcff), + SPH_C32(0x73e60eca), SPH_C32(0x318c30b8), SPH_C32(0xfb513e70), + SPH_C32(0x83140000), SPH_C32(0x3c890000), SPH_C32(0x98280000), + SPH_C32(0x556e016a), SPH_C32(0xf44c8881), SPH_C32(0x21bd6d71), + SPH_C32(0x73c179cf) } +}; + +static const sph_u32 T512_8[16][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0x774400f0), SPH_C32(0xf15a0000), SPH_C32(0xf5b20000), + SPH_C32(0x34140000), SPH_C32(0x89377e8c), SPH_C32(0x5a8bec25), + SPH_C32(0x0bc3cd1e), SPH_C32(0xcf3775cb), SPH_C32(0xf46c0050), + SPH_C32(0x96180000), SPH_C32(0x14a50000), SPH_C32(0x031f0000), + SPH_C32(0x42947eb8), SPH_C32(0x66bf7e19), SPH_C32(0x9ca470d2), + SPH_C32(0x8a341574) }, + { SPH_C32(0xf46c0050), SPH_C32(0x96180000), SPH_C32(0x14a50000), + SPH_C32(0x031f0000), SPH_C32(0x42947eb8), SPH_C32(0x66bf7e19), + SPH_C32(0x9ca470d2), SPH_C32(0x8a341574), SPH_C32(0x832800a0), + SPH_C32(0x67420000), SPH_C32(0xe1170000), SPH_C32(0x370b0000), + SPH_C32(0xcba30034), SPH_C32(0x3c34923c), SPH_C32(0x9767bdcc), + SPH_C32(0x450360bf) }, + { SPH_C32(0x832800a0), SPH_C32(0x67420000), SPH_C32(0xe1170000), + SPH_C32(0x370b0000), SPH_C32(0xcba30034), SPH_C32(0x3c34923c), + SPH_C32(0x9767bdcc), SPH_C32(0x450360bf), SPH_C32(0x774400f0), + SPH_C32(0xf15a0000), SPH_C32(0xf5b20000), SPH_C32(0x34140000), + SPH_C32(0x89377e8c), SPH_C32(0x5a8bec25), SPH_C32(0x0bc3cd1e), + SPH_C32(0xcf3775cb) }, + { SPH_C32(0xe8870170), SPH_C32(0x9d720000), SPH_C32(0x12db0000), + SPH_C32(0xd4220000), SPH_C32(0xf2886b27), SPH_C32(0xa921e543), + SPH_C32(0x4ef8b518), SPH_C32(0x618813b1), SPH_C32(0xb4370060), + SPH_C32(0x0c4c0000), SPH_C32(0x56c20000), SPH_C32(0x5cae0000), + SPH_C32(0x94541f3f), SPH_C32(0x3b3ef825), SPH_C32(0x1b365f3d), + SPH_C32(0xf3d45758) }, + { SPH_C32(0x9fc30180), SPH_C32(0x6c280000), SPH_C32(0xe7690000), + SPH_C32(0xe0360000), SPH_C32(0x7bbf15ab), SPH_C32(0xf3aa0966), + SPH_C32(0x453b7806), SPH_C32(0xaebf667a), SPH_C32(0x405b0030), + SPH_C32(0x9a540000), SPH_C32(0x42670000), SPH_C32(0x5fb10000), + SPH_C32(0xd6c06187), SPH_C32(0x5d81863c), SPH_C32(0x87922fef), + SPH_C32(0x79e0422c) }, + { SPH_C32(0x1ceb0120), SPH_C32(0x0b6a0000), SPH_C32(0x067e0000), + SPH_C32(0xd73d0000), SPH_C32(0xb01c159f), SPH_C32(0xcf9e9b5a), + SPH_C32(0xd25cc5ca), SPH_C32(0xebbc06c5), SPH_C32(0x371f00c0), + SPH_C32(0x6b0e0000), SPH_C32(0xb7d50000), SPH_C32(0x6ba50000), + SPH_C32(0x5ff71f0b), SPH_C32(0x070a6a19), SPH_C32(0x8c51e2f1), + SPH_C32(0xb6d737e7) }, + { SPH_C32(0x6baf01d0), SPH_C32(0xfa300000), SPH_C32(0xf3cc0000), + SPH_C32(0xe3290000), SPH_C32(0x392b6b13), SPH_C32(0x9515777f), + SPH_C32(0xd99f08d4), SPH_C32(0x248b730e), SPH_C32(0xc3730090), + SPH_C32(0xfd160000), SPH_C32(0xa3700000), SPH_C32(0x68ba0000), + SPH_C32(0x1d6361b3), SPH_C32(0x61b51400), SPH_C32(0x10f59223), + SPH_C32(0x3ce32293) }, + { SPH_C32(0xb4370060), SPH_C32(0x0c4c0000), SPH_C32(0x56c20000), + SPH_C32(0x5cae0000), SPH_C32(0x94541f3f), SPH_C32(0x3b3ef825), + SPH_C32(0x1b365f3d), SPH_C32(0xf3d45758), SPH_C32(0x5cb00110), + SPH_C32(0x913e0000), SPH_C32(0x44190000), SPH_C32(0x888c0000), + SPH_C32(0x66dc7418), SPH_C32(0x921f1d66), SPH_C32(0x55ceea25), + SPH_C32(0x925c44e9) }, + { SPH_C32(0xc3730090), SPH_C32(0xfd160000), SPH_C32(0xa3700000), + SPH_C32(0x68ba0000), SPH_C32(0x1d6361b3), SPH_C32(0x61b51400), + SPH_C32(0x10f59223), SPH_C32(0x3ce32293), SPH_C32(0xa8dc0140), + SPH_C32(0x07260000), SPH_C32(0x50bc0000), SPH_C32(0x8b930000), + SPH_C32(0x24480aa0), SPH_C32(0xf4a0637f), SPH_C32(0xc96a9af7), + SPH_C32(0x1868519d) }, + { SPH_C32(0x405b0030), SPH_C32(0x9a540000), SPH_C32(0x42670000), + SPH_C32(0x5fb10000), SPH_C32(0xd6c06187), SPH_C32(0x5d81863c), + SPH_C32(0x87922fef), SPH_C32(0x79e0422c), SPH_C32(0xdf9801b0), + SPH_C32(0xf67c0000), SPH_C32(0xa50e0000), SPH_C32(0xbf870000), + SPH_C32(0xad7f742c), SPH_C32(0xae2b8f5a), SPH_C32(0xc2a957e9), + SPH_C32(0xd75f2456) }, + { SPH_C32(0x371f00c0), SPH_C32(0x6b0e0000), SPH_C32(0xb7d50000), + SPH_C32(0x6ba50000), SPH_C32(0x5ff71f0b), SPH_C32(0x070a6a19), + SPH_C32(0x8c51e2f1), SPH_C32(0xb6d737e7), SPH_C32(0x2bf401e0), + SPH_C32(0x60640000), SPH_C32(0xb1ab0000), SPH_C32(0xbc980000), + SPH_C32(0xefeb0a94), SPH_C32(0xc894f143), SPH_C32(0x5e0d273b), + SPH_C32(0x5d6b3122) }, + { SPH_C32(0x5cb00110), SPH_C32(0x913e0000), SPH_C32(0x44190000), + SPH_C32(0x888c0000), SPH_C32(0x66dc7418), SPH_C32(0x921f1d66), + SPH_C32(0x55ceea25), SPH_C32(0x925c44e9), SPH_C32(0xe8870170), + SPH_C32(0x9d720000), SPH_C32(0x12db0000), SPH_C32(0xd4220000), + SPH_C32(0xf2886b27), SPH_C32(0xa921e543), SPH_C32(0x4ef8b518), + SPH_C32(0x618813b1) }, + { SPH_C32(0x2bf401e0), SPH_C32(0x60640000), SPH_C32(0xb1ab0000), + SPH_C32(0xbc980000), SPH_C32(0xefeb0a94), SPH_C32(0xc894f143), + SPH_C32(0x5e0d273b), SPH_C32(0x5d6b3122), SPH_C32(0x1ceb0120), + SPH_C32(0x0b6a0000), SPH_C32(0x067e0000), SPH_C32(0xd73d0000), + SPH_C32(0xb01c159f), SPH_C32(0xcf9e9b5a), SPH_C32(0xd25cc5ca), + SPH_C32(0xebbc06c5) }, + { SPH_C32(0xa8dc0140), SPH_C32(0x07260000), SPH_C32(0x50bc0000), + SPH_C32(0x8b930000), SPH_C32(0x24480aa0), SPH_C32(0xf4a0637f), + SPH_C32(0xc96a9af7), SPH_C32(0x1868519d), SPH_C32(0x6baf01d0), + SPH_C32(0xfa300000), SPH_C32(0xf3cc0000), SPH_C32(0xe3290000), + SPH_C32(0x392b6b13), SPH_C32(0x9515777f), SPH_C32(0xd99f08d4), + SPH_C32(0x248b730e) }, + { SPH_C32(0xdf9801b0), SPH_C32(0xf67c0000), SPH_C32(0xa50e0000), + SPH_C32(0xbf870000), SPH_C32(0xad7f742c), SPH_C32(0xae2b8f5a), + SPH_C32(0xc2a957e9), SPH_C32(0xd75f2456), SPH_C32(0x9fc30180), + SPH_C32(0x6c280000), SPH_C32(0xe7690000), SPH_C32(0xe0360000), + SPH_C32(0x7bbf15ab), SPH_C32(0xf3aa0966), SPH_C32(0x453b7806), + SPH_C32(0xaebf667a) } +}; + +static const sph_u32 T512_12[16][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0xf6800005), SPH_C32(0x3443c000), SPH_C32(0x24070000), + SPH_C32(0x8f3d0000), SPH_C32(0x21373bfb), SPH_C32(0x0ab8d5ae), + SPH_C32(0xcdc58b19), SPH_C32(0xd795ba31), SPH_C32(0xa67f0001), + SPH_C32(0x71378000), SPH_C32(0x19fc0000), SPH_C32(0x96db0000), + SPH_C32(0x3a8b6dfd), SPH_C32(0xebcaaef3), SPH_C32(0x2c6d478f), + SPH_C32(0xac8e6c88) }, + { SPH_C32(0xa67f0001), SPH_C32(0x71378000), SPH_C32(0x19fc0000), + SPH_C32(0x96db0000), SPH_C32(0x3a8b6dfd), SPH_C32(0xebcaaef3), + SPH_C32(0x2c6d478f), SPH_C32(0xac8e6c88), SPH_C32(0x50ff0004), + SPH_C32(0x45744000), SPH_C32(0x3dfb0000), SPH_C32(0x19e60000), + SPH_C32(0x1bbc5606), SPH_C32(0xe1727b5d), SPH_C32(0xe1a8cc96), + SPH_C32(0x7b1bd6b9) }, + { SPH_C32(0x50ff0004), SPH_C32(0x45744000), SPH_C32(0x3dfb0000), + SPH_C32(0x19e60000), SPH_C32(0x1bbc5606), SPH_C32(0xe1727b5d), + SPH_C32(0xe1a8cc96), SPH_C32(0x7b1bd6b9), SPH_C32(0xf6800005), + SPH_C32(0x3443c000), SPH_C32(0x24070000), SPH_C32(0x8f3d0000), + SPH_C32(0x21373bfb), SPH_C32(0x0ab8d5ae), SPH_C32(0xcdc58b19), + SPH_C32(0xd795ba31) }, + { SPH_C32(0xf7750009), SPH_C32(0xcf3cc000), SPH_C32(0xc3d60000), + SPH_C32(0x04920000), SPH_C32(0x029519a9), SPH_C32(0xf8e836ba), + SPH_C32(0x7a87f14e), SPH_C32(0x9e16981a), SPH_C32(0xd46a0000), + SPH_C32(0x8dc8c000), SPH_C32(0xa5af0000), SPH_C32(0x4a290000), + SPH_C32(0xfc4e427a), SPH_C32(0xc9b4866c), SPH_C32(0x98369604), + SPH_C32(0xf746c320) }, + { SPH_C32(0x01f5000c), SPH_C32(0xfb7f0000), SPH_C32(0xe7d10000), + SPH_C32(0x8baf0000), SPH_C32(0x23a22252), SPH_C32(0xf250e314), + SPH_C32(0xb7427a57), SPH_C32(0x4983222b), SPH_C32(0x72150001), + SPH_C32(0xfcff4000), SPH_C32(0xbc530000), SPH_C32(0xdcf20000), + SPH_C32(0xc6c52f87), SPH_C32(0x227e289f), SPH_C32(0xb45bd18b), + SPH_C32(0x5bc8afa8) }, + { SPH_C32(0x510a0008), SPH_C32(0xbe0b4000), SPH_C32(0xda2a0000), + SPH_C32(0x92490000), SPH_C32(0x381e7454), SPH_C32(0x13229849), + SPH_C32(0x56eab6c1), SPH_C32(0x3298f492), SPH_C32(0x84950004), + SPH_C32(0xc8bc8000), SPH_C32(0x98540000), SPH_C32(0x53cf0000), + SPH_C32(0xe7f2147c), SPH_C32(0x28c6fd31), SPH_C32(0x799e5a92), + SPH_C32(0x8c5d1599) }, + { SPH_C32(0xa78a000d), SPH_C32(0x8a488000), SPH_C32(0xfe2d0000), + SPH_C32(0x1d740000), SPH_C32(0x19294faf), SPH_C32(0x199a4de7), + SPH_C32(0x9b2f3dd8), SPH_C32(0xe50d4ea3), SPH_C32(0x22ea0005), + SPH_C32(0xb98b0000), SPH_C32(0x81a80000), SPH_C32(0xc5140000), + SPH_C32(0xdd797981), SPH_C32(0xc30c53c2), SPH_C32(0x55f31d1d), + SPH_C32(0x20d37911) }, + { SPH_C32(0xd46a0000), SPH_C32(0x8dc8c000), SPH_C32(0xa5af0000), + SPH_C32(0x4a290000), SPH_C32(0xfc4e427a), SPH_C32(0xc9b4866c), + SPH_C32(0x98369604), SPH_C32(0xf746c320), SPH_C32(0x231f0009), + SPH_C32(0x42f40000), SPH_C32(0x66790000), SPH_C32(0x4ebb0000), + SPH_C32(0xfedb5bd3), SPH_C32(0x315cb0d6), SPH_C32(0xe2b1674a), + SPH_C32(0x69505b3a) }, + { SPH_C32(0x22ea0005), SPH_C32(0xb98b0000), SPH_C32(0x81a80000), + SPH_C32(0xc5140000), SPH_C32(0xdd797981), SPH_C32(0xc30c53c2), + SPH_C32(0x55f31d1d), SPH_C32(0x20d37911), SPH_C32(0x85600008), + SPH_C32(0x33c38000), SPH_C32(0x7f850000), SPH_C32(0xd8600000), + SPH_C32(0xc450362e), SPH_C32(0xda961e25), SPH_C32(0xcedc20c5), + SPH_C32(0xc5de37b2) }, + { SPH_C32(0x72150001), SPH_C32(0xfcff4000), SPH_C32(0xbc530000), + SPH_C32(0xdcf20000), SPH_C32(0xc6c52f87), SPH_C32(0x227e289f), + SPH_C32(0xb45bd18b), SPH_C32(0x5bc8afa8), SPH_C32(0x73e0000d), + SPH_C32(0x07804000), SPH_C32(0x5b820000), SPH_C32(0x575d0000), + SPH_C32(0xe5670dd5), SPH_C32(0xd02ecb8b), SPH_C32(0x0319abdc), + SPH_C32(0x124b8d83) }, + { SPH_C32(0x84950004), SPH_C32(0xc8bc8000), SPH_C32(0x98540000), + SPH_C32(0x53cf0000), SPH_C32(0xe7f2147c), SPH_C32(0x28c6fd31), + SPH_C32(0x799e5a92), SPH_C32(0x8c5d1599), SPH_C32(0xd59f000c), + SPH_C32(0x76b7c000), SPH_C32(0x427e0000), SPH_C32(0xc1860000), + SPH_C32(0xdfec6028), SPH_C32(0x3be46578), SPH_C32(0x2f74ec53), + SPH_C32(0xbec5e10b) }, + { SPH_C32(0x231f0009), SPH_C32(0x42f40000), SPH_C32(0x66790000), + SPH_C32(0x4ebb0000), SPH_C32(0xfedb5bd3), SPH_C32(0x315cb0d6), + SPH_C32(0xe2b1674a), SPH_C32(0x69505b3a), SPH_C32(0xf7750009), + SPH_C32(0xcf3cc000), SPH_C32(0xc3d60000), SPH_C32(0x04920000), + SPH_C32(0x029519a9), SPH_C32(0xf8e836ba), SPH_C32(0x7a87f14e), + SPH_C32(0x9e16981a) }, + { SPH_C32(0xd59f000c), SPH_C32(0x76b7c000), SPH_C32(0x427e0000), + SPH_C32(0xc1860000), SPH_C32(0xdfec6028), SPH_C32(0x3be46578), + SPH_C32(0x2f74ec53), SPH_C32(0xbec5e10b), SPH_C32(0x510a0008), + SPH_C32(0xbe0b4000), SPH_C32(0xda2a0000), SPH_C32(0x92490000), + SPH_C32(0x381e7454), SPH_C32(0x13229849), SPH_C32(0x56eab6c1), + SPH_C32(0x3298f492) }, + { SPH_C32(0x85600008), SPH_C32(0x33c38000), SPH_C32(0x7f850000), + SPH_C32(0xd8600000), SPH_C32(0xc450362e), SPH_C32(0xda961e25), + SPH_C32(0xcedc20c5), SPH_C32(0xc5de37b2), SPH_C32(0xa78a000d), + SPH_C32(0x8a488000), SPH_C32(0xfe2d0000), SPH_C32(0x1d740000), + SPH_C32(0x19294faf), SPH_C32(0x199a4de7), SPH_C32(0x9b2f3dd8), + SPH_C32(0xe50d4ea3) }, + { SPH_C32(0x73e0000d), SPH_C32(0x07804000), SPH_C32(0x5b820000), + SPH_C32(0x575d0000), SPH_C32(0xe5670dd5), SPH_C32(0xd02ecb8b), + SPH_C32(0x0319abdc), SPH_C32(0x124b8d83), SPH_C32(0x01f5000c), + SPH_C32(0xfb7f0000), SPH_C32(0xe7d10000), SPH_C32(0x8baf0000), + SPH_C32(0x23a22252), SPH_C32(0xf250e314), SPH_C32(0xb7427a57), + SPH_C32(0x4983222b) } +}; + +static const sph_u32 T512_16[16][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0x75a40000), SPH_C32(0xc28b2700), SPH_C32(0x94a40000), + SPH_C32(0x90f50000), SPH_C32(0xfb7857e0), SPH_C32(0x49ce0bae), + SPH_C32(0x1767c483), SPH_C32(0xaedf667e), SPH_C32(0xd1660000), + SPH_C32(0x1bbc0300), SPH_C32(0x9eec0000), SPH_C32(0xf6940000), + SPH_C32(0x03024527), SPH_C32(0xcf70fcf2), SPH_C32(0xb4431b17), + SPH_C32(0x857f3c2b) }, + { SPH_C32(0xd1660000), SPH_C32(0x1bbc0300), SPH_C32(0x9eec0000), + SPH_C32(0xf6940000), SPH_C32(0x03024527), SPH_C32(0xcf70fcf2), + SPH_C32(0xb4431b17), SPH_C32(0x857f3c2b), SPH_C32(0xa4c20000), + SPH_C32(0xd9372400), SPH_C32(0x0a480000), SPH_C32(0x66610000), + SPH_C32(0xf87a12c7), SPH_C32(0x86bef75c), SPH_C32(0xa324df94), + SPH_C32(0x2ba05a55) }, + { SPH_C32(0xa4c20000), SPH_C32(0xd9372400), SPH_C32(0x0a480000), + SPH_C32(0x66610000), SPH_C32(0xf87a12c7), SPH_C32(0x86bef75c), + SPH_C32(0xa324df94), SPH_C32(0x2ba05a55), SPH_C32(0x75a40000), + SPH_C32(0xc28b2700), SPH_C32(0x94a40000), SPH_C32(0x90f50000), + SPH_C32(0xfb7857e0), SPH_C32(0x49ce0bae), SPH_C32(0x1767c483), + SPH_C32(0xaedf667e) }, + { SPH_C32(0x75c90003), SPH_C32(0x0e10c000), SPH_C32(0xd1200000), + SPH_C32(0xbaea0000), SPH_C32(0x8bc42f3e), SPH_C32(0x8758b757), + SPH_C32(0xbb28761d), SPH_C32(0x00b72e2b), SPH_C32(0xeecf0001), + SPH_C32(0x6f564000), SPH_C32(0xf33e0000), SPH_C32(0xa79e0000), + SPH_C32(0xbdb57219), SPH_C32(0xb711ebc5), SPH_C32(0x4a3b40ba), + SPH_C32(0xfeabf254) }, + { SPH_C32(0x006d0003), SPH_C32(0xcc9be700), SPH_C32(0x45840000), + SPH_C32(0x2a1f0000), SPH_C32(0x70bc78de), SPH_C32(0xce96bcf9), + SPH_C32(0xac4fb29e), SPH_C32(0xae684855), SPH_C32(0x3fa90001), + SPH_C32(0x74ea4300), SPH_C32(0x6dd20000), SPH_C32(0x510a0000), + SPH_C32(0xbeb7373e), SPH_C32(0x78611737), SPH_C32(0xfe785bad), + SPH_C32(0x7bd4ce7f) }, + { SPH_C32(0xa4af0003), SPH_C32(0x15acc300), SPH_C32(0x4fcc0000), + SPH_C32(0x4c7e0000), SPH_C32(0x88c66a19), SPH_C32(0x48284ba5), + SPH_C32(0x0f6b6d0a), SPH_C32(0x85c81200), SPH_C32(0x4a0d0001), + SPH_C32(0xb6616400), SPH_C32(0xf9760000), SPH_C32(0xc1ff0000), + SPH_C32(0x45cf60de), SPH_C32(0x31af1c99), SPH_C32(0xe91f9f2e), + SPH_C32(0xd50ba801) }, + { SPH_C32(0xd10b0003), SPH_C32(0xd727e400), SPH_C32(0xdb680000), + SPH_C32(0xdc8b0000), SPH_C32(0x73be3df9), SPH_C32(0x01e6400b), + SPH_C32(0x180ca989), SPH_C32(0x2b17747e), SPH_C32(0x9b6b0001), + SPH_C32(0xaddd6700), SPH_C32(0x679a0000), SPH_C32(0x376b0000), + SPH_C32(0x46cd25f9), SPH_C32(0xfedfe06b), SPH_C32(0x5d5c8439), + SPH_C32(0x5074942a) }, + { SPH_C32(0xeecf0001), SPH_C32(0x6f564000), SPH_C32(0xf33e0000), + SPH_C32(0xa79e0000), SPH_C32(0xbdb57219), SPH_C32(0xb711ebc5), + SPH_C32(0x4a3b40ba), SPH_C32(0xfeabf254), SPH_C32(0x9b060002), + SPH_C32(0x61468000), SPH_C32(0x221e0000), SPH_C32(0x1d740000), + SPH_C32(0x36715d27), SPH_C32(0x30495c92), SPH_C32(0xf11336a7), + SPH_C32(0xfe1cdc7f) }, + { SPH_C32(0x9b6b0001), SPH_C32(0xaddd6700), SPH_C32(0x679a0000), + SPH_C32(0x376b0000), SPH_C32(0x46cd25f9), SPH_C32(0xfedfe06b), + SPH_C32(0x5d5c8439), SPH_C32(0x5074942a), SPH_C32(0x4a600002), + SPH_C32(0x7afa8300), SPH_C32(0xbcf20000), SPH_C32(0xebe00000), + SPH_C32(0x35731800), SPH_C32(0xff39a060), SPH_C32(0x45502db0), + SPH_C32(0x7b63e054) }, + { SPH_C32(0x3fa90001), SPH_C32(0x74ea4300), SPH_C32(0x6dd20000), + SPH_C32(0x510a0000), SPH_C32(0xbeb7373e), SPH_C32(0x78611737), + SPH_C32(0xfe785bad), SPH_C32(0x7bd4ce7f), SPH_C32(0x3fc40002), + SPH_C32(0xb871a400), SPH_C32(0x28560000), SPH_C32(0x7b150000), + SPH_C32(0xce0b4fe0), SPH_C32(0xb6f7abce), SPH_C32(0x5237e933), + SPH_C32(0xd5bc862a) }, + { SPH_C32(0x4a0d0001), SPH_C32(0xb6616400), SPH_C32(0xf9760000), + SPH_C32(0xc1ff0000), SPH_C32(0x45cf60de), SPH_C32(0x31af1c99), + SPH_C32(0xe91f9f2e), SPH_C32(0xd50ba801), SPH_C32(0xeea20002), + SPH_C32(0xa3cda700), SPH_C32(0xb6ba0000), SPH_C32(0x8d810000), + SPH_C32(0xcd090ac7), SPH_C32(0x7987573c), SPH_C32(0xe674f224), + SPH_C32(0x50c3ba01) }, + { SPH_C32(0x9b060002), SPH_C32(0x61468000), SPH_C32(0x221e0000), + SPH_C32(0x1d740000), SPH_C32(0x36715d27), SPH_C32(0x30495c92), + SPH_C32(0xf11336a7), SPH_C32(0xfe1cdc7f), SPH_C32(0x75c90003), + SPH_C32(0x0e10c000), SPH_C32(0xd1200000), SPH_C32(0xbaea0000), + SPH_C32(0x8bc42f3e), SPH_C32(0x8758b757), SPH_C32(0xbb28761d), + SPH_C32(0x00b72e2b) }, + { SPH_C32(0xeea20002), SPH_C32(0xa3cda700), SPH_C32(0xb6ba0000), + SPH_C32(0x8d810000), SPH_C32(0xcd090ac7), SPH_C32(0x7987573c), + SPH_C32(0xe674f224), SPH_C32(0x50c3ba01), SPH_C32(0xa4af0003), + SPH_C32(0x15acc300), SPH_C32(0x4fcc0000), SPH_C32(0x4c7e0000), + SPH_C32(0x88c66a19), SPH_C32(0x48284ba5), SPH_C32(0x0f6b6d0a), + SPH_C32(0x85c81200) }, + { SPH_C32(0x4a600002), SPH_C32(0x7afa8300), SPH_C32(0xbcf20000), + SPH_C32(0xebe00000), SPH_C32(0x35731800), SPH_C32(0xff39a060), + SPH_C32(0x45502db0), SPH_C32(0x7b63e054), SPH_C32(0xd10b0003), + SPH_C32(0xd727e400), SPH_C32(0xdb680000), SPH_C32(0xdc8b0000), + SPH_C32(0x73be3df9), SPH_C32(0x01e6400b), SPH_C32(0x180ca989), + SPH_C32(0x2b17747e) }, + { SPH_C32(0x3fc40002), SPH_C32(0xb871a400), SPH_C32(0x28560000), + SPH_C32(0x7b150000), SPH_C32(0xce0b4fe0), SPH_C32(0xb6f7abce), + SPH_C32(0x5237e933), SPH_C32(0xd5bc862a), SPH_C32(0x006d0003), + SPH_C32(0xcc9be700), SPH_C32(0x45840000), SPH_C32(0x2a1f0000), + SPH_C32(0x70bc78de), SPH_C32(0xce96bcf9), SPH_C32(0xac4fb29e), + SPH_C32(0xae684855) } +}; + +static const sph_u32 T512_20[16][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0x0c720000), SPH_C32(0x49e50f00), SPH_C32(0x42790000), + SPH_C32(0x5cea0000), SPH_C32(0x33aa301a), SPH_C32(0x15822514), + SPH_C32(0x95a34b7b), SPH_C32(0xb44b0090), SPH_C32(0xfe220000), + SPH_C32(0xa7580500), SPH_C32(0x25d10000), SPH_C32(0xf7600000), + SPH_C32(0x893178da), SPH_C32(0x1fd4f860), SPH_C32(0x4ed0a315), + SPH_C32(0xa123ff9f) }, + { SPH_C32(0xfe220000), SPH_C32(0xa7580500), SPH_C32(0x25d10000), + SPH_C32(0xf7600000), SPH_C32(0x893178da), SPH_C32(0x1fd4f860), + SPH_C32(0x4ed0a315), SPH_C32(0xa123ff9f), SPH_C32(0xf2500000), + SPH_C32(0xeebd0a00), SPH_C32(0x67a80000), SPH_C32(0xab8a0000), + SPH_C32(0xba9b48c0), SPH_C32(0x0a56dd74), SPH_C32(0xdb73e86e), + SPH_C32(0x1568ff0f) }, + { SPH_C32(0xf2500000), SPH_C32(0xeebd0a00), SPH_C32(0x67a80000), + SPH_C32(0xab8a0000), SPH_C32(0xba9b48c0), SPH_C32(0x0a56dd74), + SPH_C32(0xdb73e86e), SPH_C32(0x1568ff0f), SPH_C32(0x0c720000), + SPH_C32(0x49e50f00), SPH_C32(0x42790000), SPH_C32(0x5cea0000), + SPH_C32(0x33aa301a), SPH_C32(0x15822514), SPH_C32(0x95a34b7b), + SPH_C32(0xb44b0090) }, + { SPH_C32(0x45180000), SPH_C32(0xa5b51700), SPH_C32(0xf96a0000), + SPH_C32(0x3b480000), SPH_C32(0x1ecc142c), SPH_C32(0x231395d6), + SPH_C32(0x16bca6b0), SPH_C32(0xdf33f4df), SPH_C32(0xb83d0000), + SPH_C32(0x16710600), SPH_C32(0x379a0000), SPH_C32(0xf5b10000), + SPH_C32(0x228161ac), SPH_C32(0xae48f145), SPH_C32(0x66241616), + SPH_C32(0xc5c1eb3e) }, + { SPH_C32(0x496a0000), SPH_C32(0xec501800), SPH_C32(0xbb130000), + SPH_C32(0x67a20000), SPH_C32(0x2d662436), SPH_C32(0x3691b0c2), + SPH_C32(0x831fedcb), SPH_C32(0x6b78f44f), SPH_C32(0x461f0000), + SPH_C32(0xb1290300), SPH_C32(0x124b0000), SPH_C32(0x02d10000), + SPH_C32(0xabb01976), SPH_C32(0xb19c0925), SPH_C32(0x28f4b503), + SPH_C32(0x64e214a1) }, + { SPH_C32(0xbb3a0000), SPH_C32(0x02ed1200), SPH_C32(0xdcbb0000), + SPH_C32(0xcc280000), SPH_C32(0x97fd6cf6), SPH_C32(0x3cc76db6), + SPH_C32(0x586c05a5), SPH_C32(0x7e100b40), SPH_C32(0x4a6d0000), + SPH_C32(0xf8cc0c00), SPH_C32(0x50320000), SPH_C32(0x5e3b0000), + SPH_C32(0x981a296c), SPH_C32(0xa41e2c31), SPH_C32(0xbd57fe78), + SPH_C32(0xd0a91431) }, + { SPH_C32(0xb7480000), SPH_C32(0x4b081d00), SPH_C32(0x9ec20000), + SPH_C32(0x90c20000), SPH_C32(0xa4575cec), SPH_C32(0x294548a2), + SPH_C32(0xcdcf4ede), SPH_C32(0xca5b0bd0), SPH_C32(0xb44f0000), + SPH_C32(0x5f940900), SPH_C32(0x75e30000), SPH_C32(0xa95b0000), + SPH_C32(0x112b51b6), SPH_C32(0xbbcad451), SPH_C32(0xf3875d6d), + SPH_C32(0x718aebae) }, + { SPH_C32(0xb83d0000), SPH_C32(0x16710600), SPH_C32(0x379a0000), + SPH_C32(0xf5b10000), SPH_C32(0x228161ac), SPH_C32(0xae48f145), + SPH_C32(0x66241616), SPH_C32(0xc5c1eb3e), SPH_C32(0xfd250000), + SPH_C32(0xb3c41100), SPH_C32(0xcef00000), SPH_C32(0xcef90000), + SPH_C32(0x3c4d7580), SPH_C32(0x8d5b6493), SPH_C32(0x7098b0a6), + SPH_C32(0x1af21fe1) }, + { SPH_C32(0xb44f0000), SPH_C32(0x5f940900), SPH_C32(0x75e30000), + SPH_C32(0xa95b0000), SPH_C32(0x112b51b6), SPH_C32(0xbbcad451), + SPH_C32(0xf3875d6d), SPH_C32(0x718aebae), SPH_C32(0x03070000), + SPH_C32(0x149c1400), SPH_C32(0xeb210000), SPH_C32(0x39990000), + SPH_C32(0xb57c0d5a), SPH_C32(0x928f9cf3), SPH_C32(0x3e4813b3), + SPH_C32(0xbbd1e07e) }, + { SPH_C32(0x461f0000), SPH_C32(0xb1290300), SPH_C32(0x124b0000), + SPH_C32(0x02d10000), SPH_C32(0xabb01976), SPH_C32(0xb19c0925), + SPH_C32(0x28f4b503), SPH_C32(0x64e214a1), SPH_C32(0x0f750000), + SPH_C32(0x5d791b00), SPH_C32(0xa9580000), SPH_C32(0x65730000), + SPH_C32(0x86d63d40), SPH_C32(0x870db9e7), SPH_C32(0xabeb58c8), + SPH_C32(0x0f9ae0ee) }, + { SPH_C32(0x4a6d0000), SPH_C32(0xf8cc0c00), SPH_C32(0x50320000), + SPH_C32(0x5e3b0000), SPH_C32(0x981a296c), SPH_C32(0xa41e2c31), + SPH_C32(0xbd57fe78), SPH_C32(0xd0a91431), SPH_C32(0xf1570000), + SPH_C32(0xfa211e00), SPH_C32(0x8c890000), SPH_C32(0x92130000), + SPH_C32(0x0fe7459a), SPH_C32(0x98d94187), SPH_C32(0xe53bfbdd), + SPH_C32(0xaeb91f71) }, + { SPH_C32(0xfd250000), SPH_C32(0xb3c41100), SPH_C32(0xcef00000), + SPH_C32(0xcef90000), SPH_C32(0x3c4d7580), SPH_C32(0x8d5b6493), + SPH_C32(0x7098b0a6), SPH_C32(0x1af21fe1), SPH_C32(0x45180000), + SPH_C32(0xa5b51700), SPH_C32(0xf96a0000), SPH_C32(0x3b480000), + SPH_C32(0x1ecc142c), SPH_C32(0x231395d6), SPH_C32(0x16bca6b0), + SPH_C32(0xdf33f4df) }, + { SPH_C32(0xf1570000), SPH_C32(0xfa211e00), SPH_C32(0x8c890000), + SPH_C32(0x92130000), SPH_C32(0x0fe7459a), SPH_C32(0x98d94187), + SPH_C32(0xe53bfbdd), SPH_C32(0xaeb91f71), SPH_C32(0xbb3a0000), + SPH_C32(0x02ed1200), SPH_C32(0xdcbb0000), SPH_C32(0xcc280000), + SPH_C32(0x97fd6cf6), SPH_C32(0x3cc76db6), SPH_C32(0x586c05a5), + SPH_C32(0x7e100b40) }, + { SPH_C32(0x03070000), SPH_C32(0x149c1400), SPH_C32(0xeb210000), + SPH_C32(0x39990000), SPH_C32(0xb57c0d5a), SPH_C32(0x928f9cf3), + SPH_C32(0x3e4813b3), SPH_C32(0xbbd1e07e), SPH_C32(0xb7480000), + SPH_C32(0x4b081d00), SPH_C32(0x9ec20000), SPH_C32(0x90c20000), + SPH_C32(0xa4575cec), SPH_C32(0x294548a2), SPH_C32(0xcdcf4ede), + SPH_C32(0xca5b0bd0) }, + { SPH_C32(0x0f750000), SPH_C32(0x5d791b00), SPH_C32(0xa9580000), + SPH_C32(0x65730000), SPH_C32(0x86d63d40), SPH_C32(0x870db9e7), + SPH_C32(0xabeb58c8), SPH_C32(0x0f9ae0ee), SPH_C32(0x496a0000), + SPH_C32(0xec501800), SPH_C32(0xbb130000), SPH_C32(0x67a20000), + SPH_C32(0x2d662436), SPH_C32(0x3691b0c2), SPH_C32(0x831fedcb), + SPH_C32(0x6b78f44f) } +}; + +static const sph_u32 T512_24[16][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0x54500000), SPH_C32(0x0671005c), SPH_C32(0x25ae0000), + SPH_C32(0x6a1e0000), SPH_C32(0x2ea54edf), SPH_C32(0x664e8512), + SPH_C32(0xbfba18c3), SPH_C32(0x7e715d17), SPH_C32(0xbc8d0000), + SPH_C32(0xfc3b0018), SPH_C32(0x19830000), SPH_C32(0xd10b0000), + SPH_C32(0xae1878c4), SPH_C32(0x42a69856), SPH_C32(0x0012da37), + SPH_C32(0x2c3b504e) }, + { SPH_C32(0xbc8d0000), SPH_C32(0xfc3b0018), SPH_C32(0x19830000), + SPH_C32(0xd10b0000), SPH_C32(0xae1878c4), SPH_C32(0x42a69856), + SPH_C32(0x0012da37), SPH_C32(0x2c3b504e), SPH_C32(0xe8dd0000), + SPH_C32(0xfa4a0044), SPH_C32(0x3c2d0000), SPH_C32(0xbb150000), + SPH_C32(0x80bd361b), SPH_C32(0x24e81d44), SPH_C32(0xbfa8c2f4), + SPH_C32(0x524a0d59) }, + { SPH_C32(0xe8dd0000), SPH_C32(0xfa4a0044), SPH_C32(0x3c2d0000), + SPH_C32(0xbb150000), SPH_C32(0x80bd361b), SPH_C32(0x24e81d44), + SPH_C32(0xbfa8c2f4), SPH_C32(0x524a0d59), SPH_C32(0x54500000), + SPH_C32(0x0671005c), SPH_C32(0x25ae0000), SPH_C32(0x6a1e0000), + SPH_C32(0x2ea54edf), SPH_C32(0x664e8512), SPH_C32(0xbfba18c3), + SPH_C32(0x7e715d17) }, + { SPH_C32(0x69510000), SPH_C32(0xd4e1009c), SPH_C32(0xc3230000), + SPH_C32(0xac2f0000), SPH_C32(0xe4950bae), SPH_C32(0xcea415dc), + SPH_C32(0x87ec287c), SPH_C32(0xbce1a3ce), SPH_C32(0xc6730000), + SPH_C32(0xaf8d000c), SPH_C32(0xa4c10000), SPH_C32(0x218d0000), + SPH_C32(0x23111587), SPH_C32(0x7913512f), SPH_C32(0x1d28ac88), + SPH_C32(0x378dd173) }, + { SPH_C32(0x3d010000), SPH_C32(0xd29000c0), SPH_C32(0xe68d0000), + SPH_C32(0xc6310000), SPH_C32(0xca304571), SPH_C32(0xa8ea90ce), + SPH_C32(0x385630bf), SPH_C32(0xc290fed9), SPH_C32(0x7afe0000), + SPH_C32(0x53b60014), SPH_C32(0xbd420000), SPH_C32(0xf0860000), + SPH_C32(0x8d096d43), SPH_C32(0x3bb5c979), SPH_C32(0x1d3a76bf), + SPH_C32(0x1bb6813d) }, + { SPH_C32(0xd5dc0000), SPH_C32(0x28da0084), SPH_C32(0xdaa00000), + SPH_C32(0x7d240000), SPH_C32(0x4a8d736a), SPH_C32(0x8c028d8a), + SPH_C32(0x87fef24b), SPH_C32(0x90daf380), SPH_C32(0x2eae0000), + SPH_C32(0x55c70048), SPH_C32(0x98ec0000), SPH_C32(0x9a980000), + SPH_C32(0xa3ac239c), SPH_C32(0x5dfb4c6b), SPH_C32(0xa2806e7c), + SPH_C32(0x65c7dc2a) }, + { SPH_C32(0x818c0000), SPH_C32(0x2eab00d8), SPH_C32(0xff0e0000), + SPH_C32(0x173a0000), SPH_C32(0x64283db5), SPH_C32(0xea4c0898), + SPH_C32(0x3844ea88), SPH_C32(0xeeabae97), SPH_C32(0x92230000), + SPH_C32(0xa9fc0050), SPH_C32(0x816f0000), SPH_C32(0x4b930000), + SPH_C32(0x0db45b58), SPH_C32(0x1f5dd43d), SPH_C32(0xa292b44b), + SPH_C32(0x49fc8c64) }, + { SPH_C32(0xc6730000), SPH_C32(0xaf8d000c), SPH_C32(0xa4c10000), + SPH_C32(0x218d0000), SPH_C32(0x23111587), SPH_C32(0x7913512f), + SPH_C32(0x1d28ac88), SPH_C32(0x378dd173), SPH_C32(0xaf220000), + SPH_C32(0x7b6c0090), SPH_C32(0x67e20000), SPH_C32(0x8da20000), + SPH_C32(0xc7841e29), SPH_C32(0xb7b744f3), SPH_C32(0x9ac484f4), + SPH_C32(0x8b6c72bd) }, + { SPH_C32(0x92230000), SPH_C32(0xa9fc0050), SPH_C32(0x816f0000), + SPH_C32(0x4b930000), SPH_C32(0x0db45b58), SPH_C32(0x1f5dd43d), + SPH_C32(0xa292b44b), SPH_C32(0x49fc8c64), SPH_C32(0x13af0000), + SPH_C32(0x87570088), SPH_C32(0x7e610000), SPH_C32(0x5ca90000), + SPH_C32(0x699c66ed), SPH_C32(0xf511dca5), SPH_C32(0x9ad65ec3), + SPH_C32(0xa75722f3) }, + { SPH_C32(0x7afe0000), SPH_C32(0x53b60014), SPH_C32(0xbd420000), + SPH_C32(0xf0860000), SPH_C32(0x8d096d43), SPH_C32(0x3bb5c979), + SPH_C32(0x1d3a76bf), SPH_C32(0x1bb6813d), SPH_C32(0x47ff0000), + SPH_C32(0x812600d4), SPH_C32(0x5bcf0000), SPH_C32(0x36b70000), + SPH_C32(0x47392832), SPH_C32(0x935f59b7), SPH_C32(0x256c4600), + SPH_C32(0xd9267fe4) }, + { SPH_C32(0x2eae0000), SPH_C32(0x55c70048), SPH_C32(0x98ec0000), + SPH_C32(0x9a980000), SPH_C32(0xa3ac239c), SPH_C32(0x5dfb4c6b), + SPH_C32(0xa2806e7c), SPH_C32(0x65c7dc2a), SPH_C32(0xfb720000), + SPH_C32(0x7d1d00cc), SPH_C32(0x424c0000), SPH_C32(0xe7bc0000), + SPH_C32(0xe92150f6), SPH_C32(0xd1f9c1e1), SPH_C32(0x257e9c37), + SPH_C32(0xf51d2faa) }, + { SPH_C32(0xaf220000), SPH_C32(0x7b6c0090), SPH_C32(0x67e20000), + SPH_C32(0x8da20000), SPH_C32(0xc7841e29), SPH_C32(0xb7b744f3), + SPH_C32(0x9ac484f4), SPH_C32(0x8b6c72bd), SPH_C32(0x69510000), + SPH_C32(0xd4e1009c), SPH_C32(0xc3230000), SPH_C32(0xac2f0000), + SPH_C32(0xe4950bae), SPH_C32(0xcea415dc), SPH_C32(0x87ec287c), + SPH_C32(0xbce1a3ce) }, + { SPH_C32(0xfb720000), SPH_C32(0x7d1d00cc), SPH_C32(0x424c0000), + SPH_C32(0xe7bc0000), SPH_C32(0xe92150f6), SPH_C32(0xd1f9c1e1), + SPH_C32(0x257e9c37), SPH_C32(0xf51d2faa), SPH_C32(0xd5dc0000), + SPH_C32(0x28da0084), SPH_C32(0xdaa00000), SPH_C32(0x7d240000), + SPH_C32(0x4a8d736a), SPH_C32(0x8c028d8a), SPH_C32(0x87fef24b), + SPH_C32(0x90daf380) }, + { SPH_C32(0x13af0000), SPH_C32(0x87570088), SPH_C32(0x7e610000), + SPH_C32(0x5ca90000), SPH_C32(0x699c66ed), SPH_C32(0xf511dca5), + SPH_C32(0x9ad65ec3), SPH_C32(0xa75722f3), SPH_C32(0x818c0000), + SPH_C32(0x2eab00d8), SPH_C32(0xff0e0000), SPH_C32(0x173a0000), + SPH_C32(0x64283db5), SPH_C32(0xea4c0898), SPH_C32(0x3844ea88), + SPH_C32(0xeeabae97) }, + { SPH_C32(0x47ff0000), SPH_C32(0x812600d4), SPH_C32(0x5bcf0000), + SPH_C32(0x36b70000), SPH_C32(0x47392832), SPH_C32(0x935f59b7), + SPH_C32(0x256c4600), SPH_C32(0xd9267fe4), SPH_C32(0x3d010000), + SPH_C32(0xd29000c0), SPH_C32(0xe68d0000), SPH_C32(0xc6310000), + SPH_C32(0xca304571), SPH_C32(0xa8ea90ce), SPH_C32(0x385630bf), + SPH_C32(0xc290fed9) } +}; + +static const sph_u32 T512_28[16][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0x86790000), SPH_C32(0x3f390002), SPH_C32(0xe19ae000), + SPH_C32(0x98560000), SPH_C32(0x9565670e), SPH_C32(0x4e88c8ea), + SPH_C32(0xd3dd4944), SPH_C32(0x161ddab9), SPH_C32(0x30b70000), + SPH_C32(0xe5d00000), SPH_C32(0xf4f46000), SPH_C32(0x42c40000), + SPH_C32(0x63b83d6a), SPH_C32(0x78ba9460), SPH_C32(0x21afa1ea), + SPH_C32(0xb0a51834) }, + { SPH_C32(0x30b70000), SPH_C32(0xe5d00000), SPH_C32(0xf4f46000), + SPH_C32(0x42c40000), SPH_C32(0x63b83d6a), SPH_C32(0x78ba9460), + SPH_C32(0x21afa1ea), SPH_C32(0xb0a51834), SPH_C32(0xb6ce0000), + SPH_C32(0xdae90002), SPH_C32(0x156e8000), SPH_C32(0xda920000), + SPH_C32(0xf6dd5a64), SPH_C32(0x36325c8a), SPH_C32(0xf272e8ae), + SPH_C32(0xa6b8c28d) }, + { SPH_C32(0xb6ce0000), SPH_C32(0xdae90002), SPH_C32(0x156e8000), + SPH_C32(0xda920000), SPH_C32(0xf6dd5a64), SPH_C32(0x36325c8a), + SPH_C32(0xf272e8ae), SPH_C32(0xa6b8c28d), SPH_C32(0x86790000), + SPH_C32(0x3f390002), SPH_C32(0xe19ae000), SPH_C32(0x98560000), + SPH_C32(0x9565670e), SPH_C32(0x4e88c8ea), SPH_C32(0xd3dd4944), + SPH_C32(0x161ddab9) }, + { SPH_C32(0x14190000), SPH_C32(0x23ca003c), SPH_C32(0x50df0000), + SPH_C32(0x44b60000), SPH_C32(0x1b6c67b0), SPH_C32(0x3cf3ac75), + SPH_C32(0x61e610b0), SPH_C32(0xdbcadb80), SPH_C32(0xe3430000), + SPH_C32(0x3a4e0014), SPH_C32(0xf2c60000), SPH_C32(0xaa4e0000), + SPH_C32(0xdb1e42a6), SPH_C32(0x256bbe15), SPH_C32(0x123db156), + SPH_C32(0x3a4e99d7) }, + { SPH_C32(0x92600000), SPH_C32(0x1cf3003e), SPH_C32(0xb145e000), + SPH_C32(0xdce00000), SPH_C32(0x8e0900be), SPH_C32(0x727b649f), + SPH_C32(0xb23b59f4), SPH_C32(0xcdd70139), SPH_C32(0xd3f40000), + SPH_C32(0xdf9e0014), SPH_C32(0x06326000), SPH_C32(0xe88a0000), + SPH_C32(0xb8a67fcc), SPH_C32(0x5dd12a75), SPH_C32(0x339210bc), + SPH_C32(0x8aeb81e3) }, + { SPH_C32(0x24ae0000), SPH_C32(0xc61a003c), SPH_C32(0xa42b6000), + SPH_C32(0x06720000), SPH_C32(0x78d45ada), SPH_C32(0x44493815), + SPH_C32(0x4049b15a), SPH_C32(0x6b6fc3b4), SPH_C32(0x558d0000), + SPH_C32(0xe0a70016), SPH_C32(0xe7a88000), SPH_C32(0x70dc0000), + SPH_C32(0x2dc318c2), SPH_C32(0x1359e29f), SPH_C32(0xe04f59f8), + SPH_C32(0x9cf65b5a) }, + { SPH_C32(0xa2d70000), SPH_C32(0xf923003e), SPH_C32(0x45b18000), + SPH_C32(0x9e240000), SPH_C32(0xedb13dd4), SPH_C32(0x0ac1f0ff), + SPH_C32(0x9394f81e), SPH_C32(0x7d72190d), SPH_C32(0x653a0000), + SPH_C32(0x05770016), SPH_C32(0x135ce000), SPH_C32(0x32180000), + SPH_C32(0x4e7b25a8), SPH_C32(0x6be376ff), SPH_C32(0xc1e0f812), + SPH_C32(0x2c53436e) }, + { SPH_C32(0xe3430000), SPH_C32(0x3a4e0014), SPH_C32(0xf2c60000), + SPH_C32(0xaa4e0000), SPH_C32(0xdb1e42a6), SPH_C32(0x256bbe15), + SPH_C32(0x123db156), SPH_C32(0x3a4e99d7), SPH_C32(0xf75a0000), + SPH_C32(0x19840028), SPH_C32(0xa2190000), SPH_C32(0xeef80000), + SPH_C32(0xc0722516), SPH_C32(0x19981260), SPH_C32(0x73dba1e6), + SPH_C32(0xe1844257) }, + { SPH_C32(0x653a0000), SPH_C32(0x05770016), SPH_C32(0x135ce000), + SPH_C32(0x32180000), SPH_C32(0x4e7b25a8), SPH_C32(0x6be376ff), + SPH_C32(0xc1e0f812), SPH_C32(0x2c53436e), SPH_C32(0xc7ed0000), + SPH_C32(0xfc540028), SPH_C32(0x56ed6000), SPH_C32(0xac3c0000), + SPH_C32(0xa3ca187c), SPH_C32(0x61228600), SPH_C32(0x5274000c), + SPH_C32(0x51215a63) }, + { SPH_C32(0xd3f40000), SPH_C32(0xdf9e0014), SPH_C32(0x06326000), + SPH_C32(0xe88a0000), SPH_C32(0xb8a67fcc), SPH_C32(0x5dd12a75), + SPH_C32(0x339210bc), SPH_C32(0x8aeb81e3), SPH_C32(0x41940000), + SPH_C32(0xc36d002a), SPH_C32(0xb7778000), SPH_C32(0x346a0000), + SPH_C32(0x36af7f72), SPH_C32(0x2faa4eea), SPH_C32(0x81a94948), + SPH_C32(0x473c80da) }, + { SPH_C32(0x558d0000), SPH_C32(0xe0a70016), SPH_C32(0xe7a88000), + SPH_C32(0x70dc0000), SPH_C32(0x2dc318c2), SPH_C32(0x1359e29f), + SPH_C32(0xe04f59f8), SPH_C32(0x9cf65b5a), SPH_C32(0x71230000), + SPH_C32(0x26bd002a), SPH_C32(0x4383e000), SPH_C32(0x76ae0000), + SPH_C32(0x55174218), SPH_C32(0x5710da8a), SPH_C32(0xa006e8a2), + SPH_C32(0xf79998ee) }, + { SPH_C32(0xf75a0000), SPH_C32(0x19840028), SPH_C32(0xa2190000), + SPH_C32(0xeef80000), SPH_C32(0xc0722516), SPH_C32(0x19981260), + SPH_C32(0x73dba1e6), SPH_C32(0xe1844257), SPH_C32(0x14190000), + SPH_C32(0x23ca003c), SPH_C32(0x50df0000), SPH_C32(0x44b60000), + SPH_C32(0x1b6c67b0), SPH_C32(0x3cf3ac75), SPH_C32(0x61e610b0), + SPH_C32(0xdbcadb80) }, + { SPH_C32(0x71230000), SPH_C32(0x26bd002a), SPH_C32(0x4383e000), + SPH_C32(0x76ae0000), SPH_C32(0x55174218), SPH_C32(0x5710da8a), + SPH_C32(0xa006e8a2), SPH_C32(0xf79998ee), SPH_C32(0x24ae0000), + SPH_C32(0xc61a003c), SPH_C32(0xa42b6000), SPH_C32(0x06720000), + SPH_C32(0x78d45ada), SPH_C32(0x44493815), SPH_C32(0x4049b15a), + SPH_C32(0x6b6fc3b4) }, + { SPH_C32(0xc7ed0000), SPH_C32(0xfc540028), SPH_C32(0x56ed6000), + SPH_C32(0xac3c0000), SPH_C32(0xa3ca187c), SPH_C32(0x61228600), + SPH_C32(0x5274000c), SPH_C32(0x51215a63), SPH_C32(0xa2d70000), + SPH_C32(0xf923003e), SPH_C32(0x45b18000), SPH_C32(0x9e240000), + SPH_C32(0xedb13dd4), SPH_C32(0x0ac1f0ff), SPH_C32(0x9394f81e), + SPH_C32(0x7d72190d) }, + { SPH_C32(0x41940000), SPH_C32(0xc36d002a), SPH_C32(0xb7778000), + SPH_C32(0x346a0000), SPH_C32(0x36af7f72), SPH_C32(0x2faa4eea), + SPH_C32(0x81a94948), SPH_C32(0x473c80da), SPH_C32(0x92600000), + SPH_C32(0x1cf3003e), SPH_C32(0xb145e000), SPH_C32(0xdce00000), + SPH_C32(0x8e0900be), SPH_C32(0x727b649f), SPH_C32(0xb23b59f4), + SPH_C32(0xcdd70139) } +}; + +static const sph_u32 T512_32[16][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0xac480000), SPH_C32(0x1ba60000), SPH_C32(0x45fb1380), + SPH_C32(0x03430000), SPH_C32(0x5a85316a), SPH_C32(0x1fb250b6), + SPH_C32(0xfe72c7fe), SPH_C32(0x91e478f6), SPH_C32(0x1e4e0000), + SPH_C32(0xdecf0000), SPH_C32(0x6df80180), SPH_C32(0x77240000), + SPH_C32(0xec47079e), SPH_C32(0xf4a0694e), SPH_C32(0xcda31812), + SPH_C32(0x98aa496e) }, + { SPH_C32(0x1e4e0000), SPH_C32(0xdecf0000), SPH_C32(0x6df80180), + SPH_C32(0x77240000), SPH_C32(0xec47079e), SPH_C32(0xf4a0694e), + SPH_C32(0xcda31812), SPH_C32(0x98aa496e), SPH_C32(0xb2060000), + SPH_C32(0xc5690000), SPH_C32(0x28031200), SPH_C32(0x74670000), + SPH_C32(0xb6c236f4), SPH_C32(0xeb1239f8), SPH_C32(0x33d1dfec), + SPH_C32(0x094e3198) }, + { SPH_C32(0xb2060000), SPH_C32(0xc5690000), SPH_C32(0x28031200), + SPH_C32(0x74670000), SPH_C32(0xb6c236f4), SPH_C32(0xeb1239f8), + SPH_C32(0x33d1dfec), SPH_C32(0x094e3198), SPH_C32(0xac480000), + SPH_C32(0x1ba60000), SPH_C32(0x45fb1380), SPH_C32(0x03430000), + SPH_C32(0x5a85316a), SPH_C32(0x1fb250b6), SPH_C32(0xfe72c7fe), + SPH_C32(0x91e478f6) }, + { SPH_C32(0xaec30000), SPH_C32(0x9c4f0001), SPH_C32(0x79d1e000), + SPH_C32(0x2c150000), SPH_C32(0x45cc75b3), SPH_C32(0x6650b736), + SPH_C32(0xab92f78f), SPH_C32(0xa312567b), SPH_C32(0xdb250000), + SPH_C32(0x09290000), SPH_C32(0x49aac000), SPH_C32(0x81e10000), + SPH_C32(0xcafe6b59), SPH_C32(0x42793431), SPH_C32(0x43566b76), + SPH_C32(0xe86cba2e) }, + { SPH_C32(0x028b0000), SPH_C32(0x87e90001), SPH_C32(0x3c2af380), + SPH_C32(0x2f560000), SPH_C32(0x1f4944d9), SPH_C32(0x79e2e780), + SPH_C32(0x55e03071), SPH_C32(0x32f62e8d), SPH_C32(0xc56b0000), + SPH_C32(0xd7e60000), SPH_C32(0x2452c180), SPH_C32(0xf6c50000), + SPH_C32(0x26b96cc7), SPH_C32(0xb6d95d7f), SPH_C32(0x8ef57364), + SPH_C32(0x70c6f340) }, + { SPH_C32(0xb08d0000), SPH_C32(0x42800001), SPH_C32(0x1429e180), + SPH_C32(0x5b310000), SPH_C32(0xa98b722d), SPH_C32(0x92f0de78), + SPH_C32(0x6631ef9d), SPH_C32(0x3bb81f15), SPH_C32(0x69230000), + SPH_C32(0xcc400000), SPH_C32(0x61a9d200), SPH_C32(0xf5860000), + SPH_C32(0x7c3c5dad), SPH_C32(0xa96b0dc9), SPH_C32(0x7087b49a), + SPH_C32(0xe1228bb6) }, + { SPH_C32(0x1cc50000), SPH_C32(0x59260001), SPH_C32(0x51d2f200), + SPH_C32(0x58720000), SPH_C32(0xf30e4347), SPH_C32(0x8d428ece), + SPH_C32(0x98432863), SPH_C32(0xaa5c67e3), SPH_C32(0x776d0000), + SPH_C32(0x128f0000), SPH_C32(0x0c51d380), SPH_C32(0x82a20000), + SPH_C32(0x907b5a33), SPH_C32(0x5dcb6487), SPH_C32(0xbd24ac88), + SPH_C32(0x7988c2d8) }, + { SPH_C32(0xdb250000), SPH_C32(0x09290000), SPH_C32(0x49aac000), + SPH_C32(0x81e10000), SPH_C32(0xcafe6b59), SPH_C32(0x42793431), + SPH_C32(0x43566b76), SPH_C32(0xe86cba2e), SPH_C32(0x75e60000), + SPH_C32(0x95660001), SPH_C32(0x307b2000), SPH_C32(0xadf40000), + SPH_C32(0x8f321eea), SPH_C32(0x24298307), SPH_C32(0xe8c49cf9), + SPH_C32(0x4b7eec55) }, + { SPH_C32(0x776d0000), SPH_C32(0x128f0000), SPH_C32(0x0c51d380), + SPH_C32(0x82a20000), SPH_C32(0x907b5a33), SPH_C32(0x5dcb6487), + SPH_C32(0xbd24ac88), SPH_C32(0x7988c2d8), SPH_C32(0x6ba80000), + SPH_C32(0x4ba90001), SPH_C32(0x5d832180), SPH_C32(0xdad00000), + SPH_C32(0x63751974), SPH_C32(0xd089ea49), SPH_C32(0x256784eb), + SPH_C32(0xd3d4a53b) }, + { SPH_C32(0xc56b0000), SPH_C32(0xd7e60000), SPH_C32(0x2452c180), + SPH_C32(0xf6c50000), SPH_C32(0x26b96cc7), SPH_C32(0xb6d95d7f), + SPH_C32(0x8ef57364), SPH_C32(0x70c6f340), SPH_C32(0xc7e00000), + SPH_C32(0x500f0001), SPH_C32(0x18783200), SPH_C32(0xd9930000), + SPH_C32(0x39f0281e), SPH_C32(0xcf3bbaff), SPH_C32(0xdb154315), + SPH_C32(0x4230ddcd) }, + { SPH_C32(0x69230000), SPH_C32(0xcc400000), SPH_C32(0x61a9d200), + SPH_C32(0xf5860000), SPH_C32(0x7c3c5dad), SPH_C32(0xa96b0dc9), + SPH_C32(0x7087b49a), SPH_C32(0xe1228bb6), SPH_C32(0xd9ae0000), + SPH_C32(0x8ec00001), SPH_C32(0x75803380), SPH_C32(0xaeb70000), + SPH_C32(0xd5b72f80), SPH_C32(0x3b9bd3b1), SPH_C32(0x16b65b07), + SPH_C32(0xda9a94a3) }, + { SPH_C32(0x75e60000), SPH_C32(0x95660001), SPH_C32(0x307b2000), + SPH_C32(0xadf40000), SPH_C32(0x8f321eea), SPH_C32(0x24298307), + SPH_C32(0xe8c49cf9), SPH_C32(0x4b7eec55), SPH_C32(0xaec30000), + SPH_C32(0x9c4f0001), SPH_C32(0x79d1e000), SPH_C32(0x2c150000), + SPH_C32(0x45cc75b3), SPH_C32(0x6650b736), SPH_C32(0xab92f78f), + SPH_C32(0xa312567b) }, + { SPH_C32(0xd9ae0000), SPH_C32(0x8ec00001), SPH_C32(0x75803380), + SPH_C32(0xaeb70000), SPH_C32(0xd5b72f80), SPH_C32(0x3b9bd3b1), + SPH_C32(0x16b65b07), SPH_C32(0xda9a94a3), SPH_C32(0xb08d0000), + SPH_C32(0x42800001), SPH_C32(0x1429e180), SPH_C32(0x5b310000), + SPH_C32(0xa98b722d), SPH_C32(0x92f0de78), SPH_C32(0x6631ef9d), + SPH_C32(0x3bb81f15) }, + { SPH_C32(0x6ba80000), SPH_C32(0x4ba90001), SPH_C32(0x5d832180), + SPH_C32(0xdad00000), SPH_C32(0x63751974), SPH_C32(0xd089ea49), + SPH_C32(0x256784eb), SPH_C32(0xd3d4a53b), SPH_C32(0x1cc50000), + SPH_C32(0x59260001), SPH_C32(0x51d2f200), SPH_C32(0x58720000), + SPH_C32(0xf30e4347), SPH_C32(0x8d428ece), SPH_C32(0x98432863), + SPH_C32(0xaa5c67e3) }, + { SPH_C32(0xc7e00000), SPH_C32(0x500f0001), SPH_C32(0x18783200), + SPH_C32(0xd9930000), SPH_C32(0x39f0281e), SPH_C32(0xcf3bbaff), + SPH_C32(0xdb154315), SPH_C32(0x4230ddcd), SPH_C32(0x028b0000), + SPH_C32(0x87e90001), SPH_C32(0x3c2af380), SPH_C32(0x2f560000), + SPH_C32(0x1f4944d9), SPH_C32(0x79e2e780), SPH_C32(0x55e03071), + SPH_C32(0x32f62e8d) } +}; + +static const sph_u32 T512_36[16][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0xcc140000), SPH_C32(0xa5630000), SPH_C32(0x5ab90780), + SPH_C32(0x3b500000), SPH_C32(0x4bd013ff), SPH_C32(0x879b3418), + SPH_C32(0x694348c1), SPH_C32(0xca5a87fe), SPH_C32(0x819e0000), + SPH_C32(0xec570000), SPH_C32(0x66320280), SPH_C32(0x95f30000), + SPH_C32(0x5da92802), SPH_C32(0x48f43cbc), SPH_C32(0xe65aa22d), + SPH_C32(0x8e67b7fa) }, + { SPH_C32(0x819e0000), SPH_C32(0xec570000), SPH_C32(0x66320280), + SPH_C32(0x95f30000), SPH_C32(0x5da92802), SPH_C32(0x48f43cbc), + SPH_C32(0xe65aa22d), SPH_C32(0x8e67b7fa), SPH_C32(0x4d8a0000), + SPH_C32(0x49340000), SPH_C32(0x3c8b0500), SPH_C32(0xaea30000), + SPH_C32(0x16793bfd), SPH_C32(0xcf6f08a4), SPH_C32(0x8f19eaec), + SPH_C32(0x443d3004) }, + { SPH_C32(0x4d8a0000), SPH_C32(0x49340000), SPH_C32(0x3c8b0500), + SPH_C32(0xaea30000), SPH_C32(0x16793bfd), SPH_C32(0xcf6f08a4), + SPH_C32(0x8f19eaec), SPH_C32(0x443d3004), SPH_C32(0xcc140000), + SPH_C32(0xa5630000), SPH_C32(0x5ab90780), SPH_C32(0x3b500000), + SPH_C32(0x4bd013ff), SPH_C32(0x879b3418), SPH_C32(0x694348c1), + SPH_C32(0xca5a87fe) }, + { SPH_C32(0x78230000), SPH_C32(0x12fc0000), SPH_C32(0xa93a0b80), + SPH_C32(0x90a50000), SPH_C32(0x713e2879), SPH_C32(0x7ee98924), + SPH_C32(0xf08ca062), SPH_C32(0x636f8bab), SPH_C32(0x02af0000), + SPH_C32(0xb7280000), SPH_C32(0xba1c0300), SPH_C32(0x56980000), + SPH_C32(0xba8d45d3), SPH_C32(0x8048c667), SPH_C32(0xa95c149a), + SPH_C32(0xf4f6ea7b) }, + { SPH_C32(0xb4370000), SPH_C32(0xb79f0000), SPH_C32(0xf3830c00), + SPH_C32(0xabf50000), SPH_C32(0x3aee3b86), SPH_C32(0xf972bd3c), + SPH_C32(0x99cfe8a3), SPH_C32(0xa9350c55), SPH_C32(0x83310000), + SPH_C32(0x5b7f0000), SPH_C32(0xdc2e0180), SPH_C32(0xc36b0000), + SPH_C32(0xe7246dd1), SPH_C32(0xc8bcfadb), SPH_C32(0x4f06b6b7), + SPH_C32(0x7a915d81) }, + { SPH_C32(0xf9bd0000), SPH_C32(0xfeab0000), SPH_C32(0xcf080900), + SPH_C32(0x05560000), SPH_C32(0x2c97007b), SPH_C32(0x361db598), + SPH_C32(0x16d6024f), SPH_C32(0xed083c51), SPH_C32(0x4f250000), + SPH_C32(0xfe1c0000), SPH_C32(0x86970600), SPH_C32(0xf83b0000), + SPH_C32(0xacf47e2e), SPH_C32(0x4f27cec3), SPH_C32(0x2645fe76), + SPH_C32(0xb0cbda7f) }, + { SPH_C32(0x35a90000), SPH_C32(0x5bc80000), SPH_C32(0x95b10e80), + SPH_C32(0x3e060000), SPH_C32(0x67471384), SPH_C32(0xb1868180), + SPH_C32(0x7f954a8e), SPH_C32(0x2752bbaf), SPH_C32(0xcebb0000), + SPH_C32(0x124b0000), SPH_C32(0xe0a50480), SPH_C32(0x6dc80000), + SPH_C32(0xf15d562c), SPH_C32(0x07d3f27f), SPH_C32(0xc01f5c5b), + SPH_C32(0x3eac6d85) }, + { SPH_C32(0x02af0000), SPH_C32(0xb7280000), SPH_C32(0xba1c0300), + SPH_C32(0x56980000), SPH_C32(0xba8d45d3), SPH_C32(0x8048c667), + SPH_C32(0xa95c149a), SPH_C32(0xf4f6ea7b), SPH_C32(0x7a8c0000), + SPH_C32(0xa5d40000), SPH_C32(0x13260880), SPH_C32(0xc63d0000), + SPH_C32(0xcbb36daa), SPH_C32(0xfea14f43), SPH_C32(0x59d0b4f8), + SPH_C32(0x979961d0) }, + { SPH_C32(0xcebb0000), SPH_C32(0x124b0000), SPH_C32(0xe0a50480), + SPH_C32(0x6dc80000), SPH_C32(0xf15d562c), SPH_C32(0x07d3f27f), + SPH_C32(0xc01f5c5b), SPH_C32(0x3eac6d85), SPH_C32(0xfb120000), + SPH_C32(0x49830000), SPH_C32(0x75140a00), SPH_C32(0x53ce0000), + SPH_C32(0x961a45a8), SPH_C32(0xb65573ff), SPH_C32(0xbf8a16d5), + SPH_C32(0x19fed62a) }, + { SPH_C32(0x83310000), SPH_C32(0x5b7f0000), SPH_C32(0xdc2e0180), + SPH_C32(0xc36b0000), SPH_C32(0xe7246dd1), SPH_C32(0xc8bcfadb), + SPH_C32(0x4f06b6b7), SPH_C32(0x7a915d81), SPH_C32(0x37060000), + SPH_C32(0xece00000), SPH_C32(0x2fad0d80), SPH_C32(0x689e0000), + SPH_C32(0xddca5657), SPH_C32(0x31ce47e7), SPH_C32(0xd6c95e14), + SPH_C32(0xd3a451d4) }, + { SPH_C32(0x4f250000), SPH_C32(0xfe1c0000), SPH_C32(0x86970600), + SPH_C32(0xf83b0000), SPH_C32(0xacf47e2e), SPH_C32(0x4f27cec3), + SPH_C32(0x2645fe76), SPH_C32(0xb0cbda7f), SPH_C32(0xb6980000), + SPH_C32(0x00b70000), SPH_C32(0x499f0f00), SPH_C32(0xfd6d0000), + SPH_C32(0x80637e55), SPH_C32(0x793a7b5b), SPH_C32(0x3093fc39), + SPH_C32(0x5dc3e62e) }, + { SPH_C32(0x7a8c0000), SPH_C32(0xa5d40000), SPH_C32(0x13260880), + SPH_C32(0xc63d0000), SPH_C32(0xcbb36daa), SPH_C32(0xfea14f43), + SPH_C32(0x59d0b4f8), SPH_C32(0x979961d0), SPH_C32(0x78230000), + SPH_C32(0x12fc0000), SPH_C32(0xa93a0b80), SPH_C32(0x90a50000), + SPH_C32(0x713e2879), SPH_C32(0x7ee98924), SPH_C32(0xf08ca062), + SPH_C32(0x636f8bab) }, + { SPH_C32(0xb6980000), SPH_C32(0x00b70000), SPH_C32(0x499f0f00), + SPH_C32(0xfd6d0000), SPH_C32(0x80637e55), SPH_C32(0x793a7b5b), + SPH_C32(0x3093fc39), SPH_C32(0x5dc3e62e), SPH_C32(0xf9bd0000), + SPH_C32(0xfeab0000), SPH_C32(0xcf080900), SPH_C32(0x05560000), + SPH_C32(0x2c97007b), SPH_C32(0x361db598), SPH_C32(0x16d6024f), + SPH_C32(0xed083c51) }, + { SPH_C32(0xfb120000), SPH_C32(0x49830000), SPH_C32(0x75140a00), + SPH_C32(0x53ce0000), SPH_C32(0x961a45a8), SPH_C32(0xb65573ff), + SPH_C32(0xbf8a16d5), SPH_C32(0x19fed62a), SPH_C32(0x35a90000), + SPH_C32(0x5bc80000), SPH_C32(0x95b10e80), SPH_C32(0x3e060000), + SPH_C32(0x67471384), SPH_C32(0xb1868180), SPH_C32(0x7f954a8e), + SPH_C32(0x2752bbaf) }, + { SPH_C32(0x37060000), SPH_C32(0xece00000), SPH_C32(0x2fad0d80), + SPH_C32(0x689e0000), SPH_C32(0xddca5657), SPH_C32(0x31ce47e7), + SPH_C32(0xd6c95e14), SPH_C32(0xd3a451d4), SPH_C32(0xb4370000), + SPH_C32(0xb79f0000), SPH_C32(0xf3830c00), SPH_C32(0xabf50000), + SPH_C32(0x3aee3b86), SPH_C32(0xf972bd3c), SPH_C32(0x99cfe8a3), + SPH_C32(0xa9350c55) } +}; + +static const sph_u32 T512_40[16][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0x88980000), SPH_C32(0x1f940000), SPH_C32(0x7fcf002e), + SPH_C32(0xfb4e0000), SPH_C32(0xf158079a), SPH_C32(0x61ae9167), + SPH_C32(0xa895706c), SPH_C32(0xe6107494), SPH_C32(0x0bc20000), + SPH_C32(0xdb630000), SPH_C32(0x7e88000c), SPH_C32(0x15860000), + SPH_C32(0x91fd48f3), SPH_C32(0x7581bb43), SPH_C32(0xf460449e), + SPH_C32(0xd8b61463) }, + { SPH_C32(0x0bc20000), SPH_C32(0xdb630000), SPH_C32(0x7e88000c), + SPH_C32(0x15860000), SPH_C32(0x91fd48f3), SPH_C32(0x7581bb43), + SPH_C32(0xf460449e), SPH_C32(0xd8b61463), SPH_C32(0x835a0000), + SPH_C32(0xc4f70000), SPH_C32(0x01470022), SPH_C32(0xeec80000), + SPH_C32(0x60a54f69), SPH_C32(0x142f2a24), SPH_C32(0x5cf534f2), + SPH_C32(0x3ea660f7) }, + { SPH_C32(0x835a0000), SPH_C32(0xc4f70000), SPH_C32(0x01470022), + SPH_C32(0xeec80000), SPH_C32(0x60a54f69), SPH_C32(0x142f2a24), + SPH_C32(0x5cf534f2), SPH_C32(0x3ea660f7), SPH_C32(0x88980000), + SPH_C32(0x1f940000), SPH_C32(0x7fcf002e), SPH_C32(0xfb4e0000), + SPH_C32(0xf158079a), SPH_C32(0x61ae9167), SPH_C32(0xa895706c), + SPH_C32(0xe6107494) }, + { SPH_C32(0x52500000), SPH_C32(0x29540000), SPH_C32(0x6a61004e), + SPH_C32(0xf0ff0000), SPH_C32(0x9a317eec), SPH_C32(0x452341ce), + SPH_C32(0xcf568fe5), SPH_C32(0x5303130f), SPH_C32(0x538d0000), + SPH_C32(0xa9fc0000), SPH_C32(0x9ef70006), SPH_C32(0x56ff0000), + SPH_C32(0x0ae4004e), SPH_C32(0x92c5cdf9), SPH_C32(0xa9444018), + SPH_C32(0x7f975691) }, + { SPH_C32(0xdac80000), SPH_C32(0x36c00000), SPH_C32(0x15ae0060), + SPH_C32(0x0bb10000), SPH_C32(0x6b697976), SPH_C32(0x248dd0a9), + SPH_C32(0x67c3ff89), SPH_C32(0xb513679b), SPH_C32(0x584f0000), + SPH_C32(0x729f0000), SPH_C32(0xe07f000a), SPH_C32(0x43790000), + SPH_C32(0x9b1948bd), SPH_C32(0xe74476ba), SPH_C32(0x5d240486), + SPH_C32(0xa72142f2) }, + { SPH_C32(0x59920000), SPH_C32(0xf2370000), SPH_C32(0x14e90042), + SPH_C32(0xe5790000), SPH_C32(0x0bcc361f), SPH_C32(0x30a2fa8d), + SPH_C32(0x3b36cb7b), SPH_C32(0x8bb5076c), SPH_C32(0xd0d70000), + SPH_C32(0x6d0b0000), SPH_C32(0x9fb00024), SPH_C32(0xb8370000), + SPH_C32(0x6a414f27), SPH_C32(0x86eae7dd), SPH_C32(0xf5b174ea), + SPH_C32(0x41313666) }, + { SPH_C32(0xd10a0000), SPH_C32(0xeda30000), SPH_C32(0x6b26006c), + SPH_C32(0x1e370000), SPH_C32(0xfa943185), SPH_C32(0x510c6bea), + SPH_C32(0x93a3bb17), SPH_C32(0x6da573f8), SPH_C32(0xdb150000), + SPH_C32(0xb6680000), SPH_C32(0xe1380028), SPH_C32(0xadb10000), + SPH_C32(0xfbbc07d4), SPH_C32(0xf36b5c9e), SPH_C32(0x01d13074), + SPH_C32(0x99872205) }, + { SPH_C32(0x538d0000), SPH_C32(0xa9fc0000), SPH_C32(0x9ef70006), + SPH_C32(0x56ff0000), SPH_C32(0x0ae4004e), SPH_C32(0x92c5cdf9), + SPH_C32(0xa9444018), SPH_C32(0x7f975691), SPH_C32(0x01dd0000), + SPH_C32(0x80a80000), SPH_C32(0xf4960048), SPH_C32(0xa6000000), + SPH_C32(0x90d57ea2), SPH_C32(0xd7e68c37), SPH_C32(0x6612cffd), + SPH_C32(0x2c94459e) }, + { SPH_C32(0xdb150000), SPH_C32(0xb6680000), SPH_C32(0xe1380028), + SPH_C32(0xadb10000), SPH_C32(0xfbbc07d4), SPH_C32(0xf36b5c9e), + SPH_C32(0x01d13074), SPH_C32(0x99872205), SPH_C32(0x0a1f0000), + SPH_C32(0x5bcb0000), SPH_C32(0x8a1e0044), SPH_C32(0xb3860000), + SPH_C32(0x01283651), SPH_C32(0xa2673774), SPH_C32(0x92728b63), + SPH_C32(0xf42251fd) }, + { SPH_C32(0x584f0000), SPH_C32(0x729f0000), SPH_C32(0xe07f000a), + SPH_C32(0x43790000), SPH_C32(0x9b1948bd), SPH_C32(0xe74476ba), + SPH_C32(0x5d240486), SPH_C32(0xa72142f2), SPH_C32(0x82870000), + SPH_C32(0x445f0000), SPH_C32(0xf5d1006a), SPH_C32(0x48c80000), + SPH_C32(0xf07031cb), SPH_C32(0xc3c9a613), SPH_C32(0x3ae7fb0f), + SPH_C32(0x12322569) }, + { SPH_C32(0xd0d70000), SPH_C32(0x6d0b0000), SPH_C32(0x9fb00024), + SPH_C32(0xb8370000), SPH_C32(0x6a414f27), SPH_C32(0x86eae7dd), + SPH_C32(0xf5b174ea), SPH_C32(0x41313666), SPH_C32(0x89450000), + SPH_C32(0x9f3c0000), SPH_C32(0x8b590066), SPH_C32(0x5d4e0000), + SPH_C32(0x618d7938), SPH_C32(0xb6481d50), SPH_C32(0xce87bf91), + SPH_C32(0xca84310a) }, + { SPH_C32(0x01dd0000), SPH_C32(0x80a80000), SPH_C32(0xf4960048), + SPH_C32(0xa6000000), SPH_C32(0x90d57ea2), SPH_C32(0xd7e68c37), + SPH_C32(0x6612cffd), SPH_C32(0x2c94459e), SPH_C32(0x52500000), + SPH_C32(0x29540000), SPH_C32(0x6a61004e), SPH_C32(0xf0ff0000), + SPH_C32(0x9a317eec), SPH_C32(0x452341ce), SPH_C32(0xcf568fe5), + SPH_C32(0x5303130f) }, + { SPH_C32(0x89450000), SPH_C32(0x9f3c0000), SPH_C32(0x8b590066), + SPH_C32(0x5d4e0000), SPH_C32(0x618d7938), SPH_C32(0xb6481d50), + SPH_C32(0xce87bf91), SPH_C32(0xca84310a), SPH_C32(0x59920000), + SPH_C32(0xf2370000), SPH_C32(0x14e90042), SPH_C32(0xe5790000), + SPH_C32(0x0bcc361f), SPH_C32(0x30a2fa8d), SPH_C32(0x3b36cb7b), + SPH_C32(0x8bb5076c) }, + { SPH_C32(0x0a1f0000), SPH_C32(0x5bcb0000), SPH_C32(0x8a1e0044), + SPH_C32(0xb3860000), SPH_C32(0x01283651), SPH_C32(0xa2673774), + SPH_C32(0x92728b63), SPH_C32(0xf42251fd), SPH_C32(0xd10a0000), + SPH_C32(0xeda30000), SPH_C32(0x6b26006c), SPH_C32(0x1e370000), + SPH_C32(0xfa943185), SPH_C32(0x510c6bea), SPH_C32(0x93a3bb17), + SPH_C32(0x6da573f8) }, + { SPH_C32(0x82870000), SPH_C32(0x445f0000), SPH_C32(0xf5d1006a), + SPH_C32(0x48c80000), SPH_C32(0xf07031cb), SPH_C32(0xc3c9a613), + SPH_C32(0x3ae7fb0f), SPH_C32(0x12322569), SPH_C32(0xdac80000), + SPH_C32(0x36c00000), SPH_C32(0x15ae0060), SPH_C32(0x0bb10000), + SPH_C32(0x6b697976), SPH_C32(0x248dd0a9), SPH_C32(0x67c3ff89), + SPH_C32(0xb513679b) } +}; + +static const sph_u32 T512_44[16][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0x58430000), SPH_C32(0x807e0000), SPH_C32(0x78330001), + SPH_C32(0xc66b3800), SPH_C32(0xe7375cdc), SPH_C32(0x79ad3fdd), + SPH_C32(0xac73fe6f), SPH_C32(0x3a4479b1), SPH_C32(0x1d5a0000), + SPH_C32(0x2b720000), SPH_C32(0x488d0000), SPH_C32(0xaf611800), + SPH_C32(0x25cb2ec5), SPH_C32(0xc879bfd0), SPH_C32(0x81a20429), + SPH_C32(0x1e7536a6) }, + { SPH_C32(0x1d5a0000), SPH_C32(0x2b720000), SPH_C32(0x488d0000), + SPH_C32(0xaf611800), SPH_C32(0x25cb2ec5), SPH_C32(0xc879bfd0), + SPH_C32(0x81a20429), SPH_C32(0x1e7536a6), SPH_C32(0x45190000), + SPH_C32(0xab0c0000), SPH_C32(0x30be0001), SPH_C32(0x690a2000), + SPH_C32(0xc2fc7219), SPH_C32(0xb1d4800d), SPH_C32(0x2dd1fa46), + SPH_C32(0x24314f17) }, + { SPH_C32(0x45190000), SPH_C32(0xab0c0000), SPH_C32(0x30be0001), + SPH_C32(0x690a2000), SPH_C32(0xc2fc7219), SPH_C32(0xb1d4800d), + SPH_C32(0x2dd1fa46), SPH_C32(0x24314f17), SPH_C32(0x58430000), + SPH_C32(0x807e0000), SPH_C32(0x78330001), SPH_C32(0xc66b3800), + SPH_C32(0xe7375cdc), SPH_C32(0x79ad3fdd), SPH_C32(0xac73fe6f), + SPH_C32(0x3a4479b1) }, + { SPH_C32(0xa53b0000), SPH_C32(0x14260000), SPH_C32(0x4e30001e), + SPH_C32(0x7cae0000), SPH_C32(0x8f9e0dd5), SPH_C32(0x78dfaa3d), + SPH_C32(0xf73168d8), SPH_C32(0x0b1b4946), SPH_C32(0x07ed0000), + SPH_C32(0xb2500000), SPH_C32(0x8774000a), SPH_C32(0x970d0000), + SPH_C32(0x437223ae), SPH_C32(0x48c76ea4), SPH_C32(0xf4786222), + SPH_C32(0x9075b1ce) }, + { SPH_C32(0xfd780000), SPH_C32(0x94580000), SPH_C32(0x3603001f), + SPH_C32(0xbac53800), SPH_C32(0x68a95109), SPH_C32(0x017295e0), + SPH_C32(0x5b4296b7), SPH_C32(0x315f30f7), SPH_C32(0x1ab70000), + SPH_C32(0x99220000), SPH_C32(0xcff9000a), SPH_C32(0x386c1800), + SPH_C32(0x66b90d6b), SPH_C32(0x80bed174), SPH_C32(0x75da660b), + SPH_C32(0x8e008768) }, + { SPH_C32(0xb8610000), SPH_C32(0x3f540000), SPH_C32(0x06bd001e), + SPH_C32(0xd3cf1800), SPH_C32(0xaa552310), SPH_C32(0xb0a615ed), + SPH_C32(0x76936cf1), SPH_C32(0x156e7fe0), SPH_C32(0x42f40000), + SPH_C32(0x195c0000), SPH_C32(0xb7ca000b), SPH_C32(0xfe072000), + SPH_C32(0x818e51b7), SPH_C32(0xf913eea9), SPH_C32(0xd9a99864), + SPH_C32(0xb444fed9) }, + { SPH_C32(0xe0220000), SPH_C32(0xbf2a0000), SPH_C32(0x7e8e001f), + SPH_C32(0x15a42000), SPH_C32(0x4d627fcc), SPH_C32(0xc90b2a30), + SPH_C32(0xdae0929e), SPH_C32(0x2f2a0651), SPH_C32(0x5fae0000), + SPH_C32(0x322e0000), SPH_C32(0xff47000b), SPH_C32(0x51663800), + SPH_C32(0xa4457f72), SPH_C32(0x316a5179), SPH_C32(0x580b9c4d), + SPH_C32(0xaa31c87f) }, + { SPH_C32(0x07ed0000), SPH_C32(0xb2500000), SPH_C32(0x8774000a), + SPH_C32(0x970d0000), SPH_C32(0x437223ae), SPH_C32(0x48c76ea4), + SPH_C32(0xf4786222), SPH_C32(0x9075b1ce), SPH_C32(0xa2d60000), + SPH_C32(0xa6760000), SPH_C32(0xc9440014), SPH_C32(0xeba30000), + SPH_C32(0xccec2e7b), SPH_C32(0x3018c499), SPH_C32(0x03490afa), + SPH_C32(0x9b6ef888) }, + { SPH_C32(0x5fae0000), SPH_C32(0x322e0000), SPH_C32(0xff47000b), + SPH_C32(0x51663800), SPH_C32(0xa4457f72), SPH_C32(0x316a5179), + SPH_C32(0x580b9c4d), SPH_C32(0xaa31c87f), SPH_C32(0xbf8c0000), + SPH_C32(0x8d040000), SPH_C32(0x81c90014), SPH_C32(0x44c21800), + SPH_C32(0xe92700be), SPH_C32(0xf8617b49), SPH_C32(0x82eb0ed3), + SPH_C32(0x851bce2e) }, + { SPH_C32(0x1ab70000), SPH_C32(0x99220000), SPH_C32(0xcff9000a), + SPH_C32(0x386c1800), SPH_C32(0x66b90d6b), SPH_C32(0x80bed174), + SPH_C32(0x75da660b), SPH_C32(0x8e008768), SPH_C32(0xe7cf0000), + SPH_C32(0x0d7a0000), SPH_C32(0xf9fa0015), SPH_C32(0x82a92000), + SPH_C32(0x0e105c62), SPH_C32(0x81cc4494), SPH_C32(0x2e98f0bc), + SPH_C32(0xbf5fb79f) }, + { SPH_C32(0x42f40000), SPH_C32(0x195c0000), SPH_C32(0xb7ca000b), + SPH_C32(0xfe072000), SPH_C32(0x818e51b7), SPH_C32(0xf913eea9), + SPH_C32(0xd9a99864), SPH_C32(0xb444fed9), SPH_C32(0xfa950000), + SPH_C32(0x26080000), SPH_C32(0xb1770015), SPH_C32(0x2dc83800), + SPH_C32(0x2bdb72a7), SPH_C32(0x49b5fb44), SPH_C32(0xaf3af495), + SPH_C32(0xa12a8139) }, + { SPH_C32(0xa2d60000), SPH_C32(0xa6760000), SPH_C32(0xc9440014), + SPH_C32(0xeba30000), SPH_C32(0xccec2e7b), SPH_C32(0x3018c499), + SPH_C32(0x03490afa), SPH_C32(0x9b6ef888), SPH_C32(0xa53b0000), + SPH_C32(0x14260000), SPH_C32(0x4e30001e), SPH_C32(0x7cae0000), + SPH_C32(0x8f9e0dd5), SPH_C32(0x78dfaa3d), SPH_C32(0xf73168d8), + SPH_C32(0x0b1b4946) }, + { SPH_C32(0xfa950000), SPH_C32(0x26080000), SPH_C32(0xb1770015), + SPH_C32(0x2dc83800), SPH_C32(0x2bdb72a7), SPH_C32(0x49b5fb44), + SPH_C32(0xaf3af495), SPH_C32(0xa12a8139), SPH_C32(0xb8610000), + SPH_C32(0x3f540000), SPH_C32(0x06bd001e), SPH_C32(0xd3cf1800), + SPH_C32(0xaa552310), SPH_C32(0xb0a615ed), SPH_C32(0x76936cf1), + SPH_C32(0x156e7fe0) }, + { SPH_C32(0xbf8c0000), SPH_C32(0x8d040000), SPH_C32(0x81c90014), + SPH_C32(0x44c21800), SPH_C32(0xe92700be), SPH_C32(0xf8617b49), + SPH_C32(0x82eb0ed3), SPH_C32(0x851bce2e), SPH_C32(0xe0220000), + SPH_C32(0xbf2a0000), SPH_C32(0x7e8e001f), SPH_C32(0x15a42000), + SPH_C32(0x4d627fcc), SPH_C32(0xc90b2a30), SPH_C32(0xdae0929e), + SPH_C32(0x2f2a0651) }, + { SPH_C32(0xe7cf0000), SPH_C32(0x0d7a0000), SPH_C32(0xf9fa0015), + SPH_C32(0x82a92000), SPH_C32(0x0e105c62), SPH_C32(0x81cc4494), + SPH_C32(0x2e98f0bc), SPH_C32(0xbf5fb79f), SPH_C32(0xfd780000), + SPH_C32(0x94580000), SPH_C32(0x3603001f), SPH_C32(0xbac53800), + SPH_C32(0x68a95109), SPH_C32(0x017295e0), SPH_C32(0x5b4296b7), + SPH_C32(0x315f30f7) } +}; + +static const sph_u32 T512_48[16][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0x02f20000), SPH_C32(0xa2810000), SPH_C32(0x873f0000), + SPH_C32(0xe36c7800), SPH_C32(0x1e1d74ef), SPH_C32(0x073d2bd6), + SPH_C32(0xc4c23237), SPH_C32(0x7f32259e), SPH_C32(0xbadd0000), + SPH_C32(0x13ad0000), SPH_C32(0xb7e70000), SPH_C32(0xf7282800), + SPH_C32(0xdf45144d), SPH_C32(0x361ac33a), SPH_C32(0xea5a8d14), + SPH_C32(0x2a2c18f0) }, + { SPH_C32(0xbadd0000), SPH_C32(0x13ad0000), SPH_C32(0xb7e70000), + SPH_C32(0xf7282800), SPH_C32(0xdf45144d), SPH_C32(0x361ac33a), + SPH_C32(0xea5a8d14), SPH_C32(0x2a2c18f0), SPH_C32(0xb82f0000), + SPH_C32(0xb12c0000), SPH_C32(0x30d80000), SPH_C32(0x14445000), + SPH_C32(0xc15860a2), SPH_C32(0x3127e8ec), SPH_C32(0x2e98bf23), + SPH_C32(0x551e3d6e) }, + { SPH_C32(0xb82f0000), SPH_C32(0xb12c0000), SPH_C32(0x30d80000), + SPH_C32(0x14445000), SPH_C32(0xc15860a2), SPH_C32(0x3127e8ec), + SPH_C32(0x2e98bf23), SPH_C32(0x551e3d6e), SPH_C32(0x02f20000), + SPH_C32(0xa2810000), SPH_C32(0x873f0000), SPH_C32(0xe36c7800), + SPH_C32(0x1e1d74ef), SPH_C32(0x073d2bd6), SPH_C32(0xc4c23237), + SPH_C32(0x7f32259e) }, + { SPH_C32(0x1e6c0000), SPH_C32(0xc4420000), SPH_C32(0x8a2e0000), + SPH_C32(0xbcb6b800), SPH_C32(0x2c4413b6), SPH_C32(0x8bfdd3da), + SPH_C32(0x6a0c1bc8), SPH_C32(0xb99dc2eb), SPH_C32(0x92560000), + SPH_C32(0x1eda0000), SPH_C32(0xea510000), SPH_C32(0xe8b13000), + SPH_C32(0xa93556a5), SPH_C32(0xebfb6199), SPH_C32(0xb15c2254), + SPH_C32(0x33c5244f) }, + { SPH_C32(0x1c9e0000), SPH_C32(0x66c30000), SPH_C32(0x0d110000), + SPH_C32(0x5fdac000), SPH_C32(0x32596759), SPH_C32(0x8cc0f80c), + SPH_C32(0xaece29ff), SPH_C32(0xc6afe775), SPH_C32(0x288b0000), + SPH_C32(0x0d770000), SPH_C32(0x5db60000), SPH_C32(0x1f991800), + SPH_C32(0x767042e8), SPH_C32(0xdde1a2a3), SPH_C32(0x5b06af40), + SPH_C32(0x19e93cbf) }, + { SPH_C32(0xa4b10000), SPH_C32(0xd7ef0000), SPH_C32(0x3dc90000), + SPH_C32(0x4b9e9000), SPH_C32(0xf30107fb), SPH_C32(0xbde710e0), + SPH_C32(0x805696dc), SPH_C32(0x93b1da1b), SPH_C32(0x2a790000), + SPH_C32(0xaff60000), SPH_C32(0xda890000), SPH_C32(0xfcf56000), + SPH_C32(0x686d3607), SPH_C32(0xdadc8975), SPH_C32(0x9fc49d77), + SPH_C32(0x66db1921) }, + { SPH_C32(0xa6430000), SPH_C32(0x756e0000), SPH_C32(0xbaf60000), + SPH_C32(0xa8f2e800), SPH_C32(0xed1c7314), SPH_C32(0xbada3b36), + SPH_C32(0x4494a4eb), SPH_C32(0xec83ff85), SPH_C32(0x90a40000), + SPH_C32(0xbc5b0000), SPH_C32(0x6d6e0000), SPH_C32(0x0bdd4800), + SPH_C32(0xb728224a), SPH_C32(0xecc64a4f), SPH_C32(0x759e1063), + SPH_C32(0x4cf701d1) }, + { SPH_C32(0x92560000), SPH_C32(0x1eda0000), SPH_C32(0xea510000), + SPH_C32(0xe8b13000), SPH_C32(0xa93556a5), SPH_C32(0xebfb6199), + SPH_C32(0xb15c2254), SPH_C32(0x33c5244f), SPH_C32(0x8c3a0000), + SPH_C32(0xda980000), SPH_C32(0x607f0000), SPH_C32(0x54078800), + SPH_C32(0x85714513), SPH_C32(0x6006b243), SPH_C32(0xdb50399c), + SPH_C32(0x8a58e6a4) }, + { SPH_C32(0x90a40000), SPH_C32(0xbc5b0000), SPH_C32(0x6d6e0000), + SPH_C32(0x0bdd4800), SPH_C32(0xb728224a), SPH_C32(0xecc64a4f), + SPH_C32(0x759e1063), SPH_C32(0x4cf701d1), SPH_C32(0x36e70000), + SPH_C32(0xc9350000), SPH_C32(0xd7980000), SPH_C32(0xa32fa000), + SPH_C32(0x5a34515e), SPH_C32(0x561c7179), SPH_C32(0x310ab488), + SPH_C32(0xa074fe54) }, + { SPH_C32(0x288b0000), SPH_C32(0x0d770000), SPH_C32(0x5db60000), + SPH_C32(0x1f991800), SPH_C32(0x767042e8), SPH_C32(0xdde1a2a3), + SPH_C32(0x5b06af40), SPH_C32(0x19e93cbf), SPH_C32(0x34150000), + SPH_C32(0x6bb40000), SPH_C32(0x50a70000), SPH_C32(0x4043d800), + SPH_C32(0x442925b1), SPH_C32(0x51215aaf), SPH_C32(0xf5c886bf), + SPH_C32(0xdf46dbca) }, + { SPH_C32(0x2a790000), SPH_C32(0xaff60000), SPH_C32(0xda890000), + SPH_C32(0xfcf56000), SPH_C32(0x686d3607), SPH_C32(0xdadc8975), + SPH_C32(0x9fc49d77), SPH_C32(0x66db1921), SPH_C32(0x8ec80000), + SPH_C32(0x78190000), SPH_C32(0xe7400000), SPH_C32(0xb76bf000), + SPH_C32(0x9b6c31fc), SPH_C32(0x673b9995), SPH_C32(0x1f920bab), + SPH_C32(0xf56ac33a) }, + { SPH_C32(0x8c3a0000), SPH_C32(0xda980000), SPH_C32(0x607f0000), + SPH_C32(0x54078800), SPH_C32(0x85714513), SPH_C32(0x6006b243), + SPH_C32(0xdb50399c), SPH_C32(0x8a58e6a4), SPH_C32(0x1e6c0000), + SPH_C32(0xc4420000), SPH_C32(0x8a2e0000), SPH_C32(0xbcb6b800), + SPH_C32(0x2c4413b6), SPH_C32(0x8bfdd3da), SPH_C32(0x6a0c1bc8), + SPH_C32(0xb99dc2eb) }, + { SPH_C32(0x8ec80000), SPH_C32(0x78190000), SPH_C32(0xe7400000), + SPH_C32(0xb76bf000), SPH_C32(0x9b6c31fc), SPH_C32(0x673b9995), + SPH_C32(0x1f920bab), SPH_C32(0xf56ac33a), SPH_C32(0xa4b10000), + SPH_C32(0xd7ef0000), SPH_C32(0x3dc90000), SPH_C32(0x4b9e9000), + SPH_C32(0xf30107fb), SPH_C32(0xbde710e0), SPH_C32(0x805696dc), + SPH_C32(0x93b1da1b) }, + { SPH_C32(0x36e70000), SPH_C32(0xc9350000), SPH_C32(0xd7980000), + SPH_C32(0xa32fa000), SPH_C32(0x5a34515e), SPH_C32(0x561c7179), + SPH_C32(0x310ab488), SPH_C32(0xa074fe54), SPH_C32(0xa6430000), + SPH_C32(0x756e0000), SPH_C32(0xbaf60000), SPH_C32(0xa8f2e800), + SPH_C32(0xed1c7314), SPH_C32(0xbada3b36), SPH_C32(0x4494a4eb), + SPH_C32(0xec83ff85) }, + { SPH_C32(0x34150000), SPH_C32(0x6bb40000), SPH_C32(0x50a70000), + SPH_C32(0x4043d800), SPH_C32(0x442925b1), SPH_C32(0x51215aaf), + SPH_C32(0xf5c886bf), SPH_C32(0xdf46dbca), SPH_C32(0x1c9e0000), + SPH_C32(0x66c30000), SPH_C32(0x0d110000), SPH_C32(0x5fdac000), + SPH_C32(0x32596759), SPH_C32(0x8cc0f80c), SPH_C32(0xaece29ff), + SPH_C32(0xc6afe775) } +}; + +static const sph_u32 T512_52[16][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0xe6280000), SPH_C32(0x4c4b0000), SPH_C32(0xa8550000), + SPH_C32(0xd3d002e0), SPH_C32(0xd86130b8), SPH_C32(0x98a7b0da), + SPH_C32(0x289506b4), SPH_C32(0xd75a4897), SPH_C32(0xf0c50000), + SPH_C32(0x59230000), SPH_C32(0x45820000), SPH_C32(0xe18d00c0), + SPH_C32(0x3b6d0631), SPH_C32(0xc2ed5699), SPH_C32(0xcbe0fe1c), + SPH_C32(0x56a7b19f) }, + { SPH_C32(0xf0c50000), SPH_C32(0x59230000), SPH_C32(0x45820000), + SPH_C32(0xe18d00c0), SPH_C32(0x3b6d0631), SPH_C32(0xc2ed5699), + SPH_C32(0xcbe0fe1c), SPH_C32(0x56a7b19f), SPH_C32(0x16ed0000), + SPH_C32(0x15680000), SPH_C32(0xedd70000), SPH_C32(0x325d0220), + SPH_C32(0xe30c3689), SPH_C32(0x5a4ae643), SPH_C32(0xe375f8a8), + SPH_C32(0x81fdf908) }, + { SPH_C32(0x16ed0000), SPH_C32(0x15680000), SPH_C32(0xedd70000), + SPH_C32(0x325d0220), SPH_C32(0xe30c3689), SPH_C32(0x5a4ae643), + SPH_C32(0xe375f8a8), SPH_C32(0x81fdf908), SPH_C32(0xe6280000), + SPH_C32(0x4c4b0000), SPH_C32(0xa8550000), SPH_C32(0xd3d002e0), + SPH_C32(0xd86130b8), SPH_C32(0x98a7b0da), SPH_C32(0x289506b4), + SPH_C32(0xd75a4897) }, + { SPH_C32(0xb4310000), SPH_C32(0x77330000), SPH_C32(0xb15d0000), + SPH_C32(0x7fd004e0), SPH_C32(0x78a26138), SPH_C32(0xd116c35d), + SPH_C32(0xd256d489), SPH_C32(0x4e6f74de), SPH_C32(0xe3060000), + SPH_C32(0xbdc10000), SPH_C32(0x87130000), SPH_C32(0xbff20060), + SPH_C32(0x2eba0a1a), SPH_C32(0x8db53751), SPH_C32(0x73c5ab06), + SPH_C32(0x5bd61539) }, + { SPH_C32(0x52190000), SPH_C32(0x3b780000), SPH_C32(0x19080000), + SPH_C32(0xac000600), SPH_C32(0xa0c35180), SPH_C32(0x49b17387), + SPH_C32(0xfac3d23d), SPH_C32(0x99353c49), SPH_C32(0x13c30000), + SPH_C32(0xe4e20000), SPH_C32(0xc2910000), SPH_C32(0x5e7f00a0), + SPH_C32(0x15d70c2b), SPH_C32(0x4f5861c8), SPH_C32(0xb825551a), + SPH_C32(0x0d71a4a6) }, + { SPH_C32(0x44f40000), SPH_C32(0x2e100000), SPH_C32(0xf4df0000), + SPH_C32(0x9e5d0420), SPH_C32(0x43cf6709), SPH_C32(0x13fb95c4), + SPH_C32(0x19b62a95), SPH_C32(0x18c8c541), SPH_C32(0xf5eb0000), + SPH_C32(0xa8a90000), SPH_C32(0x6ac40000), SPH_C32(0x8daf0240), + SPH_C32(0xcdb63c93), SPH_C32(0xd7ffd112), SPH_C32(0x90b053ae), + SPH_C32(0xda2bec31) }, + { SPH_C32(0xa2dc0000), SPH_C32(0x625b0000), SPH_C32(0x5c8a0000), + SPH_C32(0x4d8d06c0), SPH_C32(0x9bae57b1), SPH_C32(0x8b5c251e), + SPH_C32(0x31232c21), SPH_C32(0xcf928dd6), SPH_C32(0x052e0000), + SPH_C32(0xf18a0000), SPH_C32(0x2f460000), SPH_C32(0x6c220280), + SPH_C32(0xf6db3aa2), SPH_C32(0x1512878b), SPH_C32(0x5b50adb2), + SPH_C32(0x8c8c5dae) }, + { SPH_C32(0xe3060000), SPH_C32(0xbdc10000), SPH_C32(0x87130000), + SPH_C32(0xbff20060), SPH_C32(0x2eba0a1a), SPH_C32(0x8db53751), + SPH_C32(0x73c5ab06), SPH_C32(0x5bd61539), SPH_C32(0x57370000), + SPH_C32(0xcaf20000), SPH_C32(0x364e0000), SPH_C32(0xc0220480), + SPH_C32(0x56186b22), SPH_C32(0x5ca3f40c), SPH_C32(0xa1937f8f), + SPH_C32(0x15b961e7) }, + { SPH_C32(0x052e0000), SPH_C32(0xf18a0000), SPH_C32(0x2f460000), + SPH_C32(0x6c220280), SPH_C32(0xf6db3aa2), SPH_C32(0x1512878b), + SPH_C32(0x5b50adb2), SPH_C32(0x8c8c5dae), SPH_C32(0xa7f20000), + SPH_C32(0x93d10000), SPH_C32(0x73cc0000), SPH_C32(0x21af0440), + SPH_C32(0x6d756d13), SPH_C32(0x9e4ea295), SPH_C32(0x6a738193), + SPH_C32(0x431ed078) }, + { SPH_C32(0x13c30000), SPH_C32(0xe4e20000), SPH_C32(0xc2910000), + SPH_C32(0x5e7f00a0), SPH_C32(0x15d70c2b), SPH_C32(0x4f5861c8), + SPH_C32(0xb825551a), SPH_C32(0x0d71a4a6), SPH_C32(0x41da0000), + SPH_C32(0xdf9a0000), SPH_C32(0xdb990000), SPH_C32(0xf27f06a0), + SPH_C32(0xb5145dab), SPH_C32(0x06e9124f), SPH_C32(0x42e68727), + SPH_C32(0x944498ef) }, + { SPH_C32(0xf5eb0000), SPH_C32(0xa8a90000), SPH_C32(0x6ac40000), + SPH_C32(0x8daf0240), SPH_C32(0xcdb63c93), SPH_C32(0xd7ffd112), + SPH_C32(0x90b053ae), SPH_C32(0xda2bec31), SPH_C32(0xb11f0000), + SPH_C32(0x86b90000), SPH_C32(0x9e1b0000), SPH_C32(0x13f20660), + SPH_C32(0x8e795b9a), SPH_C32(0xc40444d6), SPH_C32(0x8906793b), + SPH_C32(0xc2e32970) }, + { SPH_C32(0x57370000), SPH_C32(0xcaf20000), SPH_C32(0x364e0000), + SPH_C32(0xc0220480), SPH_C32(0x56186b22), SPH_C32(0x5ca3f40c), + SPH_C32(0xa1937f8f), SPH_C32(0x15b961e7), SPH_C32(0xb4310000), + SPH_C32(0x77330000), SPH_C32(0xb15d0000), SPH_C32(0x7fd004e0), + SPH_C32(0x78a26138), SPH_C32(0xd116c35d), SPH_C32(0xd256d489), + SPH_C32(0x4e6f74de) }, + { SPH_C32(0xb11f0000), SPH_C32(0x86b90000), SPH_C32(0x9e1b0000), + SPH_C32(0x13f20660), SPH_C32(0x8e795b9a), SPH_C32(0xc40444d6), + SPH_C32(0x8906793b), SPH_C32(0xc2e32970), SPH_C32(0x44f40000), + SPH_C32(0x2e100000), SPH_C32(0xf4df0000), SPH_C32(0x9e5d0420), + SPH_C32(0x43cf6709), SPH_C32(0x13fb95c4), SPH_C32(0x19b62a95), + SPH_C32(0x18c8c541) }, + { SPH_C32(0xa7f20000), SPH_C32(0x93d10000), SPH_C32(0x73cc0000), + SPH_C32(0x21af0440), SPH_C32(0x6d756d13), SPH_C32(0x9e4ea295), + SPH_C32(0x6a738193), SPH_C32(0x431ed078), SPH_C32(0xa2dc0000), + SPH_C32(0x625b0000), SPH_C32(0x5c8a0000), SPH_C32(0x4d8d06c0), + SPH_C32(0x9bae57b1), SPH_C32(0x8b5c251e), SPH_C32(0x31232c21), + SPH_C32(0xcf928dd6) }, + { SPH_C32(0x41da0000), SPH_C32(0xdf9a0000), SPH_C32(0xdb990000), + SPH_C32(0xf27f06a0), SPH_C32(0xb5145dab), SPH_C32(0x06e9124f), + SPH_C32(0x42e68727), SPH_C32(0x944498ef), SPH_C32(0x52190000), + SPH_C32(0x3b780000), SPH_C32(0x19080000), SPH_C32(0xac000600), + SPH_C32(0xa0c35180), SPH_C32(0x49b17387), SPH_C32(0xfac3d23d), + SPH_C32(0x99353c49) } +}; + +static const sph_u32 T512_56[16][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0x5fa80000), SPH_C32(0x56030000), SPH_C32(0x43ae0000), + SPH_C32(0x64f30013), SPH_C32(0x257e86bf), SPH_C32(0x1311944e), + SPH_C32(0x541e95bf), SPH_C32(0x8ea4db69), SPH_C32(0x00440000), + SPH_C32(0x7f480000), SPH_C32(0xda7c0000), SPH_C32(0x2a230001), + SPH_C32(0x3badc9cc), SPH_C32(0xa9b69c87), SPH_C32(0x030a9e60), + SPH_C32(0xbe0a679e) }, + { SPH_C32(0x00440000), SPH_C32(0x7f480000), SPH_C32(0xda7c0000), + SPH_C32(0x2a230001), SPH_C32(0x3badc9cc), SPH_C32(0xa9b69c87), + SPH_C32(0x030a9e60), SPH_C32(0xbe0a679e), SPH_C32(0x5fec0000), + SPH_C32(0x294b0000), SPH_C32(0x99d20000), SPH_C32(0x4ed00012), + SPH_C32(0x1ed34f73), SPH_C32(0xbaa708c9), SPH_C32(0x57140bdf), + SPH_C32(0x30aebcf7) }, + { SPH_C32(0x5fec0000), SPH_C32(0x294b0000), SPH_C32(0x99d20000), + SPH_C32(0x4ed00012), SPH_C32(0x1ed34f73), SPH_C32(0xbaa708c9), + SPH_C32(0x57140bdf), SPH_C32(0x30aebcf7), SPH_C32(0x5fa80000), + SPH_C32(0x56030000), SPH_C32(0x43ae0000), SPH_C32(0x64f30013), + SPH_C32(0x257e86bf), SPH_C32(0x1311944e), SPH_C32(0x541e95bf), + SPH_C32(0x8ea4db69) }, + { SPH_C32(0xee930000), SPH_C32(0xd6070000), SPH_C32(0x92c10000), + SPH_C32(0x2b9801e0), SPH_C32(0x9451287c), SPH_C32(0x3b6cfb57), + SPH_C32(0x45312374), SPH_C32(0x201f6a64), SPH_C32(0x7b280000), + SPH_C32(0x57420000), SPH_C32(0xa9e50000), SPH_C32(0x634300a0), + SPH_C32(0x9edb442f), SPH_C32(0x6d9995bb), SPH_C32(0x27f83b03), + SPH_C32(0xc7ff60f0) }, + { SPH_C32(0xb13b0000), SPH_C32(0x80040000), SPH_C32(0xd16f0000), + SPH_C32(0x4f6b01f3), SPH_C32(0xb12faec3), SPH_C32(0x287d6f19), + SPH_C32(0x112fb6cb), SPH_C32(0xaebbb10d), SPH_C32(0x7b6c0000), + SPH_C32(0x280a0000), SPH_C32(0x73990000), SPH_C32(0x496000a1), + SPH_C32(0xa5768de3), SPH_C32(0xc42f093c), SPH_C32(0x24f2a563), + SPH_C32(0x79f5076e) }, + { SPH_C32(0xeed70000), SPH_C32(0xa94f0000), SPH_C32(0x48bd0000), + SPH_C32(0x01bb01e1), SPH_C32(0xaffce1b0), SPH_C32(0x92da67d0), + SPH_C32(0x463bbd14), SPH_C32(0x9e150dfa), SPH_C32(0x24c40000), + SPH_C32(0x7e090000), SPH_C32(0x30370000), SPH_C32(0x2d9300b2), + SPH_C32(0x80080b5c), SPH_C32(0xd73e9d72), SPH_C32(0x70ec30dc), + SPH_C32(0xf751dc07) }, + { SPH_C32(0xb17f0000), SPH_C32(0xff4c0000), SPH_C32(0x0b130000), + SPH_C32(0x654801f2), SPH_C32(0x8a82670f), SPH_C32(0x81cbf39e), + SPH_C32(0x122528ab), SPH_C32(0x10b1d693), SPH_C32(0x24800000), + SPH_C32(0x01410000), SPH_C32(0xea4b0000), SPH_C32(0x07b000b3), + SPH_C32(0xbba5c290), SPH_C32(0x7e8801f5), SPH_C32(0x73e6aebc), + SPH_C32(0x495bbb99) }, + { SPH_C32(0x7b280000), SPH_C32(0x57420000), SPH_C32(0xa9e50000), + SPH_C32(0x634300a0), SPH_C32(0x9edb442f), SPH_C32(0x6d9995bb), + SPH_C32(0x27f83b03), SPH_C32(0xc7ff60f0), SPH_C32(0x95bb0000), + SPH_C32(0x81450000), SPH_C32(0x3b240000), SPH_C32(0x48db0140), + SPH_C32(0x0a8a6c53), SPH_C32(0x56f56eec), SPH_C32(0x62c91877), + SPH_C32(0xe7e00a94) }, + { SPH_C32(0x24800000), SPH_C32(0x01410000), SPH_C32(0xea4b0000), + SPH_C32(0x07b000b3), SPH_C32(0xbba5c290), SPH_C32(0x7e8801f5), + SPH_C32(0x73e6aebc), SPH_C32(0x495bbb99), SPH_C32(0x95ff0000), + SPH_C32(0xfe0d0000), SPH_C32(0xe1580000), SPH_C32(0x62f80141), + SPH_C32(0x3127a59f), SPH_C32(0xff43f26b), SPH_C32(0x61c38617), + SPH_C32(0x59ea6d0a) }, + { SPH_C32(0x7b6c0000), SPH_C32(0x280a0000), SPH_C32(0x73990000), + SPH_C32(0x496000a1), SPH_C32(0xa5768de3), SPH_C32(0xc42f093c), + SPH_C32(0x24f2a563), SPH_C32(0x79f5076e), SPH_C32(0xca570000), + SPH_C32(0xa80e0000), SPH_C32(0xa2f60000), SPH_C32(0x060b0152), + SPH_C32(0x14592320), SPH_C32(0xec526625), SPH_C32(0x35dd13a8), + SPH_C32(0xd74eb663) }, + { SPH_C32(0x24c40000), SPH_C32(0x7e090000), SPH_C32(0x30370000), + SPH_C32(0x2d9300b2), SPH_C32(0x80080b5c), SPH_C32(0xd73e9d72), + SPH_C32(0x70ec30dc), SPH_C32(0xf751dc07), SPH_C32(0xca130000), + SPH_C32(0xd7460000), SPH_C32(0x788a0000), SPH_C32(0x2c280153), + SPH_C32(0x2ff4eaec), SPH_C32(0x45e4faa2), SPH_C32(0x36d78dc8), + SPH_C32(0x6944d1fd) }, + { SPH_C32(0x95bb0000), SPH_C32(0x81450000), SPH_C32(0x3b240000), + SPH_C32(0x48db0140), SPH_C32(0x0a8a6c53), SPH_C32(0x56f56eec), + SPH_C32(0x62c91877), SPH_C32(0xe7e00a94), SPH_C32(0xee930000), + SPH_C32(0xd6070000), SPH_C32(0x92c10000), SPH_C32(0x2b9801e0), + SPH_C32(0x9451287c), SPH_C32(0x3b6cfb57), SPH_C32(0x45312374), + SPH_C32(0x201f6a64) }, + { SPH_C32(0xca130000), SPH_C32(0xd7460000), SPH_C32(0x788a0000), + SPH_C32(0x2c280153), SPH_C32(0x2ff4eaec), SPH_C32(0x45e4faa2), + SPH_C32(0x36d78dc8), SPH_C32(0x6944d1fd), SPH_C32(0xeed70000), + SPH_C32(0xa94f0000), SPH_C32(0x48bd0000), SPH_C32(0x01bb01e1), + SPH_C32(0xaffce1b0), SPH_C32(0x92da67d0), SPH_C32(0x463bbd14), + SPH_C32(0x9e150dfa) }, + { SPH_C32(0x95ff0000), SPH_C32(0xfe0d0000), SPH_C32(0xe1580000), + SPH_C32(0x62f80141), SPH_C32(0x3127a59f), SPH_C32(0xff43f26b), + SPH_C32(0x61c38617), SPH_C32(0x59ea6d0a), SPH_C32(0xb17f0000), + SPH_C32(0xff4c0000), SPH_C32(0x0b130000), SPH_C32(0x654801f2), + SPH_C32(0x8a82670f), SPH_C32(0x81cbf39e), SPH_C32(0x122528ab), + SPH_C32(0x10b1d693) }, + { SPH_C32(0xca570000), SPH_C32(0xa80e0000), SPH_C32(0xa2f60000), + SPH_C32(0x060b0152), SPH_C32(0x14592320), SPH_C32(0xec526625), + SPH_C32(0x35dd13a8), SPH_C32(0xd74eb663), SPH_C32(0xb13b0000), + SPH_C32(0x80040000), SPH_C32(0xd16f0000), SPH_C32(0x4f6b01f3), + SPH_C32(0xb12faec3), SPH_C32(0x287d6f19), SPH_C32(0x112fb6cb), + SPH_C32(0xaebbb10d) } +}; + +static const sph_u32 T512_60[16][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0x033d0000), SPH_C32(0x08b30000), SPH_C32(0xf33a0000), + SPH_C32(0x3ac20007), SPH_C32(0x51298a50), SPH_C32(0x6b6e661f), + SPH_C32(0x0ea5cfe3), SPH_C32(0xe6da7ffe), SPH_C32(0xa8da0000), + SPH_C32(0x96be0000), SPH_C32(0x5c1d0000), SPH_C32(0x07da0002), + SPH_C32(0x7d669583), SPH_C32(0x1f98708a), SPH_C32(0xbb668808), + SPH_C32(0xda878000) }, + { SPH_C32(0xa8da0000), SPH_C32(0x96be0000), SPH_C32(0x5c1d0000), + SPH_C32(0x07da0002), SPH_C32(0x7d669583), SPH_C32(0x1f98708a), + SPH_C32(0xbb668808), SPH_C32(0xda878000), SPH_C32(0xabe70000), + SPH_C32(0x9e0d0000), SPH_C32(0xaf270000), SPH_C32(0x3d180005), + SPH_C32(0x2c4f1fd3), SPH_C32(0x74f61695), SPH_C32(0xb5c347eb), + SPH_C32(0x3c5dfffe) }, + { SPH_C32(0xabe70000), SPH_C32(0x9e0d0000), SPH_C32(0xaf270000), + SPH_C32(0x3d180005), SPH_C32(0x2c4f1fd3), SPH_C32(0x74f61695), + SPH_C32(0xb5c347eb), SPH_C32(0x3c5dfffe), SPH_C32(0x033d0000), + SPH_C32(0x08b30000), SPH_C32(0xf33a0000), SPH_C32(0x3ac20007), + SPH_C32(0x51298a50), SPH_C32(0x6b6e661f), SPH_C32(0x0ea5cfe3), + SPH_C32(0xe6da7ffe) }, + { SPH_C32(0x01930000), SPH_C32(0xe7820000), SPH_C32(0xedfb0000), + SPH_C32(0xcf0c000b), SPH_C32(0x8dd08d58), SPH_C32(0xbca3b42e), + SPH_C32(0x063661e1), SPH_C32(0x536f9e7b), SPH_C32(0x92280000), + SPH_C32(0xdc850000), SPH_C32(0x57fa0000), SPH_C32(0x56dc0003), + SPH_C32(0xbae92316), SPH_C32(0x5aefa30c), SPH_C32(0x90cef752), + SPH_C32(0x7b1675d7) }, + { SPH_C32(0x02ae0000), SPH_C32(0xef310000), SPH_C32(0x1ec10000), + SPH_C32(0xf5ce000c), SPH_C32(0xdcf90708), SPH_C32(0xd7cdd231), + SPH_C32(0x0893ae02), SPH_C32(0xb5b5e185), SPH_C32(0x3af20000), + SPH_C32(0x4a3b0000), SPH_C32(0x0be70000), SPH_C32(0x51060001), + SPH_C32(0xc78fb695), SPH_C32(0x4577d386), SPH_C32(0x2ba87f5a), + SPH_C32(0xa191f5d7) }, + { SPH_C32(0xa9490000), SPH_C32(0x713c0000), SPH_C32(0xb1e60000), + SPH_C32(0xc8d60009), SPH_C32(0xf0b618db), SPH_C32(0xa33bc4a4), + SPH_C32(0xbd50e9e9), SPH_C32(0x89e81e7b), SPH_C32(0x39cf0000), + SPH_C32(0x42880000), SPH_C32(0xf8dd0000), SPH_C32(0x6bc40006), + SPH_C32(0x96a63cc5), SPH_C32(0x2e19b599), SPH_C32(0x250db0b9), + SPH_C32(0x474b8a29) }, + { SPH_C32(0xaa740000), SPH_C32(0x798f0000), SPH_C32(0x42dc0000), + SPH_C32(0xf214000e), SPH_C32(0xa19f928b), SPH_C32(0xc855a2bb), + SPH_C32(0xb3f5260a), SPH_C32(0x6f326185), SPH_C32(0x91150000), + SPH_C32(0xd4360000), SPH_C32(0xa4c00000), SPH_C32(0x6c1e0004), + SPH_C32(0xebc0a946), SPH_C32(0x3181c513), SPH_C32(0x9e6b38b1), + SPH_C32(0x9dcc0a29) }, + { SPH_C32(0x92280000), SPH_C32(0xdc850000), SPH_C32(0x57fa0000), + SPH_C32(0x56dc0003), SPH_C32(0xbae92316), SPH_C32(0x5aefa30c), + SPH_C32(0x90cef752), SPH_C32(0x7b1675d7), SPH_C32(0x93bb0000), + SPH_C32(0x3b070000), SPH_C32(0xba010000), SPH_C32(0x99d00008), + SPH_C32(0x3739ae4e), SPH_C32(0xe64c1722), SPH_C32(0x96f896b3), + SPH_C32(0x2879ebac) }, + { SPH_C32(0x91150000), SPH_C32(0xd4360000), SPH_C32(0xa4c00000), + SPH_C32(0x6c1e0004), SPH_C32(0xebc0a946), SPH_C32(0x3181c513), + SPH_C32(0x9e6b38b1), SPH_C32(0x9dcc0a29), SPH_C32(0x3b610000), + SPH_C32(0xadb90000), SPH_C32(0xe61c0000), SPH_C32(0x9e0a000a), + SPH_C32(0x4a5f3bcd), SPH_C32(0xf9d467a8), SPH_C32(0x2d9e1ebb), + SPH_C32(0xf2fe6bac) }, + { SPH_C32(0x3af20000), SPH_C32(0x4a3b0000), SPH_C32(0x0be70000), + SPH_C32(0x51060001), SPH_C32(0xc78fb695), SPH_C32(0x4577d386), + SPH_C32(0x2ba87f5a), SPH_C32(0xa191f5d7), SPH_C32(0x385c0000), + SPH_C32(0xa50a0000), SPH_C32(0x15260000), SPH_C32(0xa4c8000d), + SPH_C32(0x1b76b19d), SPH_C32(0x92ba01b7), SPH_C32(0x233bd158), + SPH_C32(0x14241452) }, + { SPH_C32(0x39cf0000), SPH_C32(0x42880000), SPH_C32(0xf8dd0000), + SPH_C32(0x6bc40006), SPH_C32(0x96a63cc5), SPH_C32(0x2e19b599), + SPH_C32(0x250db0b9), SPH_C32(0x474b8a29), SPH_C32(0x90860000), + SPH_C32(0x33b40000), SPH_C32(0x493b0000), SPH_C32(0xa312000f), + SPH_C32(0x6610241e), SPH_C32(0x8d22713d), SPH_C32(0x985d5950), + SPH_C32(0xcea39452) }, + { SPH_C32(0x93bb0000), SPH_C32(0x3b070000), SPH_C32(0xba010000), + SPH_C32(0x99d00008), SPH_C32(0x3739ae4e), SPH_C32(0xe64c1722), + SPH_C32(0x96f896b3), SPH_C32(0x2879ebac), SPH_C32(0x01930000), + SPH_C32(0xe7820000), SPH_C32(0xedfb0000), SPH_C32(0xcf0c000b), + SPH_C32(0x8dd08d58), SPH_C32(0xbca3b42e), SPH_C32(0x063661e1), + SPH_C32(0x536f9e7b) }, + { SPH_C32(0x90860000), SPH_C32(0x33b40000), SPH_C32(0x493b0000), + SPH_C32(0xa312000f), SPH_C32(0x6610241e), SPH_C32(0x8d22713d), + SPH_C32(0x985d5950), SPH_C32(0xcea39452), SPH_C32(0xa9490000), + SPH_C32(0x713c0000), SPH_C32(0xb1e60000), SPH_C32(0xc8d60009), + SPH_C32(0xf0b618db), SPH_C32(0xa33bc4a4), SPH_C32(0xbd50e9e9), + SPH_C32(0x89e81e7b) }, + { SPH_C32(0x3b610000), SPH_C32(0xadb90000), SPH_C32(0xe61c0000), + SPH_C32(0x9e0a000a), SPH_C32(0x4a5f3bcd), SPH_C32(0xf9d467a8), + SPH_C32(0x2d9e1ebb), SPH_C32(0xf2fe6bac), SPH_C32(0xaa740000), + SPH_C32(0x798f0000), SPH_C32(0x42dc0000), SPH_C32(0xf214000e), + SPH_C32(0xa19f928b), SPH_C32(0xc855a2bb), SPH_C32(0xb3f5260a), + SPH_C32(0x6f326185) }, + { SPH_C32(0x385c0000), SPH_C32(0xa50a0000), SPH_C32(0x15260000), + SPH_C32(0xa4c8000d), SPH_C32(0x1b76b19d), SPH_C32(0x92ba01b7), + SPH_C32(0x233bd158), SPH_C32(0x14241452), SPH_C32(0x02ae0000), + SPH_C32(0xef310000), SPH_C32(0x1ec10000), SPH_C32(0xf5ce000c), + SPH_C32(0xdcf90708), SPH_C32(0xd7cdd231), SPH_C32(0x0893ae02), + SPH_C32(0xb5b5e185) } +}; + +#define INPUT_BIG do { \ + unsigned acc = buf[0]; \ + const sph_u32 *rp; \ + rp = &T512_0[acc >> 4][0]; \ + m0 = rp[0]; \ + m1 = rp[1]; \ + m2 = rp[2]; \ + m3 = rp[3]; \ + m4 = rp[4]; \ + m5 = rp[5]; \ + m6 = rp[6]; \ + m7 = rp[7]; \ + m8 = rp[8]; \ + m9 = rp[9]; \ + mA = rp[10]; \ + mB = rp[11]; \ + mC = rp[12]; \ + mD = rp[13]; \ + mE = rp[14]; \ + mF = rp[15]; \ + rp = &T512_4[acc & 0x0f][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + m8 ^= rp[8]; \ + m9 ^= rp[9]; \ + mA ^= rp[10]; \ + mB ^= rp[11]; \ + mC ^= rp[12]; \ + mD ^= rp[13]; \ + mE ^= rp[14]; \ + mF ^= rp[15]; \ + acc = buf[1]; \ + rp = &T512_8[acc >> 4][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + m8 ^= rp[8]; \ + m9 ^= rp[9]; \ + mA ^= rp[10]; \ + mB ^= rp[11]; \ + mC ^= rp[12]; \ + mD ^= rp[13]; \ + mE ^= rp[14]; \ + mF ^= rp[15]; \ + rp = &T512_12[acc & 0x0f][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + m8 ^= rp[8]; \ + m9 ^= rp[9]; \ + mA ^= rp[10]; \ + mB ^= rp[11]; \ + mC ^= rp[12]; \ + mD ^= rp[13]; \ + mE ^= rp[14]; \ + mF ^= rp[15]; \ + acc = buf[2]; \ + rp = &T512_16[acc >> 4][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + m8 ^= rp[8]; \ + m9 ^= rp[9]; \ + mA ^= rp[10]; \ + mB ^= rp[11]; \ + mC ^= rp[12]; \ + mD ^= rp[13]; \ + mE ^= rp[14]; \ + mF ^= rp[15]; \ + rp = &T512_20[acc & 0x0f][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + m8 ^= rp[8]; \ + m9 ^= rp[9]; \ + mA ^= rp[10]; \ + mB ^= rp[11]; \ + mC ^= rp[12]; \ + mD ^= rp[13]; \ + mE ^= rp[14]; \ + mF ^= rp[15]; \ + acc = buf[3]; \ + rp = &T512_24[acc >> 4][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + m8 ^= rp[8]; \ + m9 ^= rp[9]; \ + mA ^= rp[10]; \ + mB ^= rp[11]; \ + mC ^= rp[12]; \ + mD ^= rp[13]; \ + mE ^= rp[14]; \ + mF ^= rp[15]; \ + rp = &T512_28[acc & 0x0f][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + m8 ^= rp[8]; \ + m9 ^= rp[9]; \ + mA ^= rp[10]; \ + mB ^= rp[11]; \ + mC ^= rp[12]; \ + mD ^= rp[13]; \ + mE ^= rp[14]; \ + mF ^= rp[15]; \ + acc = buf[4]; \ + rp = &T512_32[acc >> 4][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + m8 ^= rp[8]; \ + m9 ^= rp[9]; \ + mA ^= rp[10]; \ + mB ^= rp[11]; \ + mC ^= rp[12]; \ + mD ^= rp[13]; \ + mE ^= rp[14]; \ + mF ^= rp[15]; \ + rp = &T512_36[acc & 0x0f][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + m8 ^= rp[8]; \ + m9 ^= rp[9]; \ + mA ^= rp[10]; \ + mB ^= rp[11]; \ + mC ^= rp[12]; \ + mD ^= rp[13]; \ + mE ^= rp[14]; \ + mF ^= rp[15]; \ + acc = buf[5]; \ + rp = &T512_40[acc >> 4][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + m8 ^= rp[8]; \ + m9 ^= rp[9]; \ + mA ^= rp[10]; \ + mB ^= rp[11]; \ + mC ^= rp[12]; \ + mD ^= rp[13]; \ + mE ^= rp[14]; \ + mF ^= rp[15]; \ + rp = &T512_44[acc & 0x0f][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + m8 ^= rp[8]; \ + m9 ^= rp[9]; \ + mA ^= rp[10]; \ + mB ^= rp[11]; \ + mC ^= rp[12]; \ + mD ^= rp[13]; \ + mE ^= rp[14]; \ + mF ^= rp[15]; \ + acc = buf[6]; \ + rp = &T512_48[acc >> 4][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + m8 ^= rp[8]; \ + m9 ^= rp[9]; \ + mA ^= rp[10]; \ + mB ^= rp[11]; \ + mC ^= rp[12]; \ + mD ^= rp[13]; \ + mE ^= rp[14]; \ + mF ^= rp[15]; \ + rp = &T512_52[acc & 0x0f][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + m8 ^= rp[8]; \ + m9 ^= rp[9]; \ + mA ^= rp[10]; \ + mB ^= rp[11]; \ + mC ^= rp[12]; \ + mD ^= rp[13]; \ + mE ^= rp[14]; \ + mF ^= rp[15]; \ + acc = buf[7]; \ + rp = &T512_56[acc >> 4][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + m8 ^= rp[8]; \ + m9 ^= rp[9]; \ + mA ^= rp[10]; \ + mB ^= rp[11]; \ + mC ^= rp[12]; \ + mD ^= rp[13]; \ + mE ^= rp[14]; \ + mF ^= rp[15]; \ + rp = &T512_60[acc & 0x0f][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + m8 ^= rp[8]; \ + m9 ^= rp[9]; \ + mA ^= rp[10]; \ + mB ^= rp[11]; \ + mC ^= rp[12]; \ + mD ^= rp[13]; \ + mE ^= rp[14]; \ + mF ^= rp[15]; \ + } while (0) + +#endif + +#if SPH_HAMSI_EXPAND_BIG == 5 + +static const sph_u32 T512_0[32][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0x23671400), SPH_C32(0xc8b90000), SPH_C32(0xf4c70000), + SPH_C32(0xfb750000), SPH_C32(0x73cd2465), SPH_C32(0xf8a6a549), + SPH_C32(0x02c40a3f), SPH_C32(0xdc24e61f), SPH_C32(0x373d2800), + SPH_C32(0x71500000), SPH_C32(0x95e00000), SPH_C32(0x0a140000), + SPH_C32(0xbdac1909), SPH_C32(0x48ef9831), SPH_C32(0x456d6d1f), + SPH_C32(0x3daac2da) }, + { SPH_C32(0x54285c00), SPH_C32(0xeaed0000), SPH_C32(0xc5d60000), + SPH_C32(0xa1c50000), SPH_C32(0xb3a26770), SPH_C32(0x94a5c4e1), + SPH_C32(0x6bb0419d), SPH_C32(0x551b3782), SPH_C32(0x9cbb1800), + SPH_C32(0xb0d30000), SPH_C32(0x92510000), SPH_C32(0xed930000), + SPH_C32(0x593a4345), SPH_C32(0xe114d5f4), SPH_C32(0x430633da), + SPH_C32(0x78cace29) }, + { SPH_C32(0x774f4800), SPH_C32(0x22540000), SPH_C32(0x31110000), + SPH_C32(0x5ab00000), SPH_C32(0xc06f4315), SPH_C32(0x6c0361a8), + SPH_C32(0x69744ba2), SPH_C32(0x893fd19d), SPH_C32(0xab863000), + SPH_C32(0xc1830000), SPH_C32(0x07b10000), SPH_C32(0xe7870000), + SPH_C32(0xe4965a4c), SPH_C32(0xa9fb4dc5), SPH_C32(0x066b5ec5), + SPH_C32(0x45600cf3) }, + { SPH_C32(0x9cbb1800), SPH_C32(0xb0d30000), SPH_C32(0x92510000), + SPH_C32(0xed930000), SPH_C32(0x593a4345), SPH_C32(0xe114d5f4), + SPH_C32(0x430633da), SPH_C32(0x78cace29), SPH_C32(0xc8934400), + SPH_C32(0x5a3e0000), SPH_C32(0x57870000), SPH_C32(0x4c560000), + SPH_C32(0xea982435), SPH_C32(0x75b11115), SPH_C32(0x28b67247), + SPH_C32(0x2dd1f9ab) }, + { SPH_C32(0xbfdc0c00), SPH_C32(0x786a0000), SPH_C32(0x66960000), + SPH_C32(0x16e60000), SPH_C32(0x2af76720), SPH_C32(0x19b270bd), + SPH_C32(0x41c239e5), SPH_C32(0xa4ee2836), SPH_C32(0xffae6c00), + SPH_C32(0x2b6e0000), SPH_C32(0xc2670000), SPH_C32(0x46420000), + SPH_C32(0x57343d3c), SPH_C32(0x3d5e8924), SPH_C32(0x6ddb1f58), + SPH_C32(0x107b3b71) }, + { SPH_C32(0xc8934400), SPH_C32(0x5a3e0000), SPH_C32(0x57870000), + SPH_C32(0x4c560000), SPH_C32(0xea982435), SPH_C32(0x75b11115), + SPH_C32(0x28b67247), SPH_C32(0x2dd1f9ab), SPH_C32(0x54285c00), + SPH_C32(0xeaed0000), SPH_C32(0xc5d60000), SPH_C32(0xa1c50000), + SPH_C32(0xb3a26770), SPH_C32(0x94a5c4e1), SPH_C32(0x6bb0419d), + SPH_C32(0x551b3782) }, + { SPH_C32(0xebf45000), SPH_C32(0x92870000), SPH_C32(0xa3400000), + SPH_C32(0xb7230000), SPH_C32(0x99550050), SPH_C32(0x8d17b45c), + SPH_C32(0x2a727878), SPH_C32(0xf1f51fb4), SPH_C32(0x63157400), + SPH_C32(0x9bbd0000), SPH_C32(0x50360000), SPH_C32(0xabd10000), + SPH_C32(0x0e0e7e79), SPH_C32(0xdc4a5cd0), SPH_C32(0x2edd2c82), + SPH_C32(0x68b1f558) }, + { SPH_C32(0x29449c00), SPH_C32(0x64e70000), SPH_C32(0xf24b0000), + SPH_C32(0xc2f30000), SPH_C32(0x0ede4e8f), SPH_C32(0x56c23745), + SPH_C32(0xf3e04259), SPH_C32(0x8d0d9ec4), SPH_C32(0x466d0c00), + SPH_C32(0x08620000), SPH_C32(0xdd5d0000), SPH_C32(0xbadd0000), + SPH_C32(0x6a927942), SPH_C32(0x441f2b93), SPH_C32(0x218ace6f), + SPH_C32(0xbf2c0be2) }, + { SPH_C32(0x0a238800), SPH_C32(0xac5e0000), SPH_C32(0x068c0000), + SPH_C32(0x39860000), SPH_C32(0x7d136aea), SPH_C32(0xae64920c), + SPH_C32(0xf1244866), SPH_C32(0x512978db), SPH_C32(0x71502400), + SPH_C32(0x79320000), SPH_C32(0x48bd0000), SPH_C32(0xb0c90000), + SPH_C32(0xd73e604b), SPH_C32(0x0cf0b3a2), SPH_C32(0x64e7a370), + SPH_C32(0x8286c938) }, + { SPH_C32(0x7d6cc000), SPH_C32(0x8e0a0000), SPH_C32(0x379d0000), + SPH_C32(0x63360000), SPH_C32(0xbd7c29ff), SPH_C32(0xc267f3a4), + SPH_C32(0x985003c4), SPH_C32(0xd816a946), SPH_C32(0xdad61400), + SPH_C32(0xb8b10000), SPH_C32(0x4f0c0000), SPH_C32(0x574e0000), + SPH_C32(0x33a83a07), SPH_C32(0xa50bfe67), SPH_C32(0x628cfdb5), + SPH_C32(0xc7e6c5cb) }, + { SPH_C32(0x5e0bd400), SPH_C32(0x46b30000), SPH_C32(0xc35a0000), + SPH_C32(0x98430000), SPH_C32(0xceb10d9a), SPH_C32(0x3ac156ed), + SPH_C32(0x9a9409fb), SPH_C32(0x04324f59), SPH_C32(0xedeb3c00), + SPH_C32(0xc9e10000), SPH_C32(0xdaec0000), SPH_C32(0x5d5a0000), + SPH_C32(0x8e04230e), SPH_C32(0xede46656), SPH_C32(0x27e190aa), + SPH_C32(0xfa4c0711) }, + { SPH_C32(0xb5ff8400), SPH_C32(0xd4340000), SPH_C32(0x601a0000), + SPH_C32(0x2f600000), SPH_C32(0x57e40dca), SPH_C32(0xb7d6e2b1), + SPH_C32(0xb0e67183), SPH_C32(0xf5c750ed), SPH_C32(0x8efe4800), + SPH_C32(0x525c0000), SPH_C32(0x8ada0000), SPH_C32(0xf68b0000), + SPH_C32(0x800a5d77), SPH_C32(0x31ae3a86), SPH_C32(0x093cbc28), + SPH_C32(0x92fdf249) }, + { SPH_C32(0x96989000), SPH_C32(0x1c8d0000), SPH_C32(0x94dd0000), + SPH_C32(0xd4150000), SPH_C32(0x242929af), SPH_C32(0x4f7047f8), + SPH_C32(0xb2227bbc), SPH_C32(0x29e3b6f2), SPH_C32(0xb9c36000), + SPH_C32(0x230c0000), SPH_C32(0x1f3a0000), SPH_C32(0xfc9f0000), + SPH_C32(0x3da6447e), SPH_C32(0x7941a2b7), SPH_C32(0x4c51d137), + SPH_C32(0xaf573093) }, + { SPH_C32(0xe1d7d800), SPH_C32(0x3ed90000), SPH_C32(0xa5cc0000), + SPH_C32(0x8ea50000), SPH_C32(0xe4466aba), SPH_C32(0x23732650), + SPH_C32(0xdb56301e), SPH_C32(0xa0dc676f), SPH_C32(0x12455000), + SPH_C32(0xe28f0000), SPH_C32(0x188b0000), SPH_C32(0x1b180000), + SPH_C32(0xd9301e32), SPH_C32(0xd0baef72), SPH_C32(0x4a3a8ff2), + SPH_C32(0xea373c60) }, + { SPH_C32(0xc2b0cc00), SPH_C32(0xf6600000), SPH_C32(0x510b0000), + SPH_C32(0x75d00000), SPH_C32(0x978b4edf), SPH_C32(0xdbd58319), + SPH_C32(0xd9923a21), SPH_C32(0x7cf88170), SPH_C32(0x25787800), + SPH_C32(0x93df0000), SPH_C32(0x8d6b0000), SPH_C32(0x110c0000), + SPH_C32(0x649c073b), SPH_C32(0x98557743), SPH_C32(0x0f57e2ed), + SPH_C32(0xd79dfeba) }, + { SPH_C32(0x466d0c00), SPH_C32(0x08620000), SPH_C32(0xdd5d0000), + SPH_C32(0xbadd0000), SPH_C32(0x6a927942), SPH_C32(0x441f2b93), + SPH_C32(0x218ace6f), SPH_C32(0xbf2c0be2), SPH_C32(0x6f299000), + SPH_C32(0x6c850000), SPH_C32(0x2f160000), SPH_C32(0x782e0000), + SPH_C32(0x644c37cd), SPH_C32(0x12dd1cd6), SPH_C32(0xd26a8c36), + SPH_C32(0x32219526) }, + { SPH_C32(0x650a1800), SPH_C32(0xc0db0000), SPH_C32(0x299a0000), + SPH_C32(0x41a80000), SPH_C32(0x195f5d27), SPH_C32(0xbcb98eda), + SPH_C32(0x234ec450), SPH_C32(0x6308edfd), SPH_C32(0x5814b800), + SPH_C32(0x1dd50000), SPH_C32(0xbaf60000), SPH_C32(0x723a0000), + SPH_C32(0xd9e02ec4), SPH_C32(0x5a3284e7), SPH_C32(0x9707e129), + SPH_C32(0x0f8b57fc) }, + { SPH_C32(0x12455000), SPH_C32(0xe28f0000), SPH_C32(0x188b0000), + SPH_C32(0x1b180000), SPH_C32(0xd9301e32), SPH_C32(0xd0baef72), + SPH_C32(0x4a3a8ff2), SPH_C32(0xea373c60), SPH_C32(0xf3928800), + SPH_C32(0xdc560000), SPH_C32(0xbd470000), SPH_C32(0x95bd0000), + SPH_C32(0x3d767488), SPH_C32(0xf3c9c922), SPH_C32(0x916cbfec), + SPH_C32(0x4aeb5b0f) }, + { SPH_C32(0x31224400), SPH_C32(0x2a360000), SPH_C32(0xec4c0000), + SPH_C32(0xe06d0000), SPH_C32(0xaafd3a57), SPH_C32(0x281c4a3b), + SPH_C32(0x48fe85cd), SPH_C32(0x3613da7f), SPH_C32(0xc4afa000), + SPH_C32(0xad060000), SPH_C32(0x28a70000), SPH_C32(0x9fa90000), + SPH_C32(0x80da6d81), SPH_C32(0xbb265113), SPH_C32(0xd401d2f3), + SPH_C32(0x774199d5) }, + { SPH_C32(0xdad61400), SPH_C32(0xb8b10000), SPH_C32(0x4f0c0000), + SPH_C32(0x574e0000), SPH_C32(0x33a83a07), SPH_C32(0xa50bfe67), + SPH_C32(0x628cfdb5), SPH_C32(0xc7e6c5cb), SPH_C32(0xa7bad400), + SPH_C32(0x36bb0000), SPH_C32(0x78910000), SPH_C32(0x34780000), + SPH_C32(0x8ed413f8), SPH_C32(0x676c0dc3), SPH_C32(0xfadcfe71), + SPH_C32(0x1ff06c8d) }, + { SPH_C32(0xf9b10000), SPH_C32(0x70080000), SPH_C32(0xbbcb0000), + SPH_C32(0xac3b0000), SPH_C32(0x40651e62), SPH_C32(0x5dad5b2e), + SPH_C32(0x6048f78a), SPH_C32(0x1bc223d4), SPH_C32(0x9087fc00), + SPH_C32(0x47eb0000), SPH_C32(0xed710000), SPH_C32(0x3e6c0000), + SPH_C32(0x33780af1), SPH_C32(0x2f8395f2), SPH_C32(0xbfb1936e), + SPH_C32(0x225aae57) }, + { SPH_C32(0x8efe4800), SPH_C32(0x525c0000), SPH_C32(0x8ada0000), + SPH_C32(0xf68b0000), SPH_C32(0x800a5d77), SPH_C32(0x31ae3a86), + SPH_C32(0x093cbc28), SPH_C32(0x92fdf249), SPH_C32(0x3b01cc00), + SPH_C32(0x86680000), SPH_C32(0xeac00000), SPH_C32(0xd9eb0000), + SPH_C32(0xd7ee50bd), SPH_C32(0x8678d837), SPH_C32(0xb9dacdab), + SPH_C32(0x673aa2a4) }, + { SPH_C32(0xad995c00), SPH_C32(0x9ae50000), SPH_C32(0x7e1d0000), + SPH_C32(0x0dfe0000), SPH_C32(0xf3c77912), SPH_C32(0xc9089fcf), + SPH_C32(0x0bf8b617), SPH_C32(0x4ed91456), SPH_C32(0x0c3ce400), + SPH_C32(0xf7380000), SPH_C32(0x7f200000), SPH_C32(0xd3ff0000), + SPH_C32(0x6a4249b4), SPH_C32(0xce974006), SPH_C32(0xfcb7a0b4), + SPH_C32(0x5a90607e) }, + { SPH_C32(0x6f299000), SPH_C32(0x6c850000), SPH_C32(0x2f160000), + SPH_C32(0x782e0000), SPH_C32(0x644c37cd), SPH_C32(0x12dd1cd6), + SPH_C32(0xd26a8c36), SPH_C32(0x32219526), SPH_C32(0x29449c00), + SPH_C32(0x64e70000), SPH_C32(0xf24b0000), SPH_C32(0xc2f30000), + SPH_C32(0x0ede4e8f), SPH_C32(0x56c23745), SPH_C32(0xf3e04259), + SPH_C32(0x8d0d9ec4) }, + { SPH_C32(0x4c4e8400), SPH_C32(0xa43c0000), SPH_C32(0xdbd10000), + SPH_C32(0x835b0000), SPH_C32(0x178113a8), SPH_C32(0xea7bb99f), + SPH_C32(0xd0ae8609), SPH_C32(0xee057339), SPH_C32(0x1e79b400), + SPH_C32(0x15b70000), SPH_C32(0x67ab0000), SPH_C32(0xc8e70000), + SPH_C32(0xb3725786), SPH_C32(0x1e2daf74), SPH_C32(0xb68d2f46), + SPH_C32(0xb0a75c1e) }, + { SPH_C32(0x3b01cc00), SPH_C32(0x86680000), SPH_C32(0xeac00000), + SPH_C32(0xd9eb0000), SPH_C32(0xd7ee50bd), SPH_C32(0x8678d837), + SPH_C32(0xb9dacdab), SPH_C32(0x673aa2a4), SPH_C32(0xb5ff8400), + SPH_C32(0xd4340000), SPH_C32(0x601a0000), SPH_C32(0x2f600000), + SPH_C32(0x57e40dca), SPH_C32(0xb7d6e2b1), SPH_C32(0xb0e67183), + SPH_C32(0xf5c750ed) }, + { SPH_C32(0x1866d800), SPH_C32(0x4ed10000), SPH_C32(0x1e070000), + SPH_C32(0x229e0000), SPH_C32(0xa42374d8), SPH_C32(0x7ede7d7e), + SPH_C32(0xbb1ec794), SPH_C32(0xbb1e44bb), SPH_C32(0x82c2ac00), + SPH_C32(0xa5640000), SPH_C32(0xf5fa0000), SPH_C32(0x25740000), + SPH_C32(0xea4814c3), SPH_C32(0xff397a80), SPH_C32(0xf58b1c9c), + SPH_C32(0xc86d9237) }, + { SPH_C32(0xf3928800), SPH_C32(0xdc560000), SPH_C32(0xbd470000), + SPH_C32(0x95bd0000), SPH_C32(0x3d767488), SPH_C32(0xf3c9c922), + SPH_C32(0x916cbfec), SPH_C32(0x4aeb5b0f), SPH_C32(0xe1d7d800), + SPH_C32(0x3ed90000), SPH_C32(0xa5cc0000), SPH_C32(0x8ea50000), + SPH_C32(0xe4466aba), SPH_C32(0x23732650), SPH_C32(0xdb56301e), + SPH_C32(0xa0dc676f) }, + { SPH_C32(0xd0f59c00), SPH_C32(0x14ef0000), SPH_C32(0x49800000), + SPH_C32(0x6ec80000), SPH_C32(0x4ebb50ed), SPH_C32(0x0b6f6c6b), + SPH_C32(0x93a8b5d3), SPH_C32(0x96cfbd10), SPH_C32(0xd6eaf000), + SPH_C32(0x4f890000), SPH_C32(0x302c0000), SPH_C32(0x84b10000), + SPH_C32(0x59ea73b3), SPH_C32(0x6b9cbe61), SPH_C32(0x9e3b5d01), + SPH_C32(0x9d76a5b5) }, + { SPH_C32(0xa7bad400), SPH_C32(0x36bb0000), SPH_C32(0x78910000), + SPH_C32(0x34780000), SPH_C32(0x8ed413f8), SPH_C32(0x676c0dc3), + SPH_C32(0xfadcfe71), SPH_C32(0x1ff06c8d), SPH_C32(0x7d6cc000), + SPH_C32(0x8e0a0000), SPH_C32(0x379d0000), SPH_C32(0x63360000), + SPH_C32(0xbd7c29ff), SPH_C32(0xc267f3a4), SPH_C32(0x985003c4), + SPH_C32(0xd816a946) }, + { SPH_C32(0x84ddc000), SPH_C32(0xfe020000), SPH_C32(0x8c560000), + SPH_C32(0xcf0d0000), SPH_C32(0xfd19379d), SPH_C32(0x9fcaa88a), + SPH_C32(0xf818f44e), SPH_C32(0xc3d48a92), SPH_C32(0x4a51e800), + SPH_C32(0xff5a0000), SPH_C32(0xa27d0000), SPH_C32(0x69220000), + SPH_C32(0x00d030f6), SPH_C32(0x8a886b95), SPH_C32(0xdd3d6edb), + SPH_C32(0xe5bc6b9c) } +}; + +static const sph_u32 T512_5[32][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0xe8870170), SPH_C32(0x9d720000), SPH_C32(0x12db0000), + SPH_C32(0xd4220000), SPH_C32(0xf2886b27), SPH_C32(0xa921e543), + SPH_C32(0x4ef8b518), SPH_C32(0x618813b1), SPH_C32(0xb4370060), + SPH_C32(0x0c4c0000), SPH_C32(0x56c20000), SPH_C32(0x5cae0000), + SPH_C32(0x94541f3f), SPH_C32(0x3b3ef825), SPH_C32(0x1b365f3d), + SPH_C32(0xf3d45758) }, + { SPH_C32(0xb4370060), SPH_C32(0x0c4c0000), SPH_C32(0x56c20000), + SPH_C32(0x5cae0000), SPH_C32(0x94541f3f), SPH_C32(0x3b3ef825), + SPH_C32(0x1b365f3d), SPH_C32(0xf3d45758), SPH_C32(0x5cb00110), + SPH_C32(0x913e0000), SPH_C32(0x44190000), SPH_C32(0x888c0000), + SPH_C32(0x66dc7418), SPH_C32(0x921f1d66), SPH_C32(0x55ceea25), + SPH_C32(0x925c44e9) }, + { SPH_C32(0x5cb00110), SPH_C32(0x913e0000), SPH_C32(0x44190000), + SPH_C32(0x888c0000), SPH_C32(0x66dc7418), SPH_C32(0x921f1d66), + SPH_C32(0x55ceea25), SPH_C32(0x925c44e9), SPH_C32(0xe8870170), + SPH_C32(0x9d720000), SPH_C32(0x12db0000), SPH_C32(0xd4220000), + SPH_C32(0xf2886b27), SPH_C32(0xa921e543), SPH_C32(0x4ef8b518), + SPH_C32(0x618813b1) }, + { SPH_C32(0xef0b0270), SPH_C32(0x3afd0000), SPH_C32(0x5dae0000), + SPH_C32(0x69490000), SPH_C32(0x9b0f3c06), SPH_C32(0x4405b5f9), + SPH_C32(0x66140a51), SPH_C32(0x924f5d0a), SPH_C32(0xc96b0030), + SPH_C32(0xe7250000), SPH_C32(0x2f840000), SPH_C32(0x264f0000), + SPH_C32(0x08695bf9), SPH_C32(0x6dfcf137), SPH_C32(0x509f6984), + SPH_C32(0x9e69af68) }, + { SPH_C32(0x078c0300), SPH_C32(0xa78f0000), SPH_C32(0x4f750000), + SPH_C32(0xbd6b0000), SPH_C32(0x69875721), SPH_C32(0xed2450ba), + SPH_C32(0x28ecbf49), SPH_C32(0xf3c74ebb), SPH_C32(0x7d5c0050), + SPH_C32(0xeb690000), SPH_C32(0x79460000), SPH_C32(0x7ae10000), + SPH_C32(0x9c3d44c6), SPH_C32(0x56c20912), SPH_C32(0x4ba936b9), + SPH_C32(0x6dbdf830) }, + { SPH_C32(0x5b3c0210), SPH_C32(0x36b10000), SPH_C32(0x0b6c0000), + SPH_C32(0x35e70000), SPH_C32(0x0f5b2339), SPH_C32(0x7f3b4ddc), + SPH_C32(0x7d22556c), SPH_C32(0x619b0a52), SPH_C32(0x95db0120), + SPH_C32(0x761b0000), SPH_C32(0x6b9d0000), SPH_C32(0xaec30000), + SPH_C32(0x6eb52fe1), SPH_C32(0xffe3ec51), SPH_C32(0x055183a1), + SPH_C32(0x0c35eb81) }, + { SPH_C32(0xb3bb0360), SPH_C32(0xabc30000), SPH_C32(0x19b70000), + SPH_C32(0xe1c50000), SPH_C32(0xfdd3481e), SPH_C32(0xd61aa89f), + SPH_C32(0x33dae074), SPH_C32(0x001319e3), SPH_C32(0x21ec0140), + SPH_C32(0x7a570000), SPH_C32(0x3d5f0000), SPH_C32(0xf26d0000), + SPH_C32(0xfae130de), SPH_C32(0xc4dd1474), SPH_C32(0x1e67dc9c), + SPH_C32(0xffe1bcd9) }, + { SPH_C32(0xc96b0030), SPH_C32(0xe7250000), SPH_C32(0x2f840000), + SPH_C32(0x264f0000), SPH_C32(0x08695bf9), SPH_C32(0x6dfcf137), + SPH_C32(0x509f6984), SPH_C32(0x9e69af68), SPH_C32(0x26600240), + SPH_C32(0xddd80000), SPH_C32(0x722a0000), SPH_C32(0x4f060000), + SPH_C32(0x936667ff), SPH_C32(0x29f944ce), SPH_C32(0x368b63d5), + SPH_C32(0x0c26f262) }, + { SPH_C32(0x21ec0140), SPH_C32(0x7a570000), SPH_C32(0x3d5f0000), + SPH_C32(0xf26d0000), SPH_C32(0xfae130de), SPH_C32(0xc4dd1474), + SPH_C32(0x1e67dc9c), SPH_C32(0xffe1bcd9), SPH_C32(0x92570220), + SPH_C32(0xd1940000), SPH_C32(0x24e80000), SPH_C32(0x13a80000), + SPH_C32(0x073278c0), SPH_C32(0x12c7bceb), SPH_C32(0x2dbd3ce8), + SPH_C32(0xfff2a53a) }, + { SPH_C32(0x7d5c0050), SPH_C32(0xeb690000), SPH_C32(0x79460000), + SPH_C32(0x7ae10000), SPH_C32(0x9c3d44c6), SPH_C32(0x56c20912), + SPH_C32(0x4ba936b9), SPH_C32(0x6dbdf830), SPH_C32(0x7ad00350), + SPH_C32(0x4ce60000), SPH_C32(0x36330000), SPH_C32(0xc78a0000), + SPH_C32(0xf5ba13e7), SPH_C32(0xbbe659a8), SPH_C32(0x634589f0), + SPH_C32(0x9e7ab68b) }, + { SPH_C32(0x95db0120), SPH_C32(0x761b0000), SPH_C32(0x6b9d0000), + SPH_C32(0xaec30000), SPH_C32(0x6eb52fe1), SPH_C32(0xffe3ec51), + SPH_C32(0x055183a1), SPH_C32(0x0c35eb81), SPH_C32(0xcee70330), + SPH_C32(0x40aa0000), SPH_C32(0x60f10000), SPH_C32(0x9b240000), + SPH_C32(0x61ee0cd8), SPH_C32(0x80d8a18d), SPH_C32(0x7873d6cd), + SPH_C32(0x6daee1d3) }, + { SPH_C32(0x26600240), SPH_C32(0xddd80000), SPH_C32(0x722a0000), + SPH_C32(0x4f060000), SPH_C32(0x936667ff), SPH_C32(0x29f944ce), + SPH_C32(0x368b63d5), SPH_C32(0x0c26f262), SPH_C32(0xef0b0270), + SPH_C32(0x3afd0000), SPH_C32(0x5dae0000), SPH_C32(0x69490000), + SPH_C32(0x9b0f3c06), SPH_C32(0x4405b5f9), SPH_C32(0x66140a51), + SPH_C32(0x924f5d0a) }, + { SPH_C32(0xcee70330), SPH_C32(0x40aa0000), SPH_C32(0x60f10000), + SPH_C32(0x9b240000), SPH_C32(0x61ee0cd8), SPH_C32(0x80d8a18d), + SPH_C32(0x7873d6cd), SPH_C32(0x6daee1d3), SPH_C32(0x5b3c0210), + SPH_C32(0x36b10000), SPH_C32(0x0b6c0000), SPH_C32(0x35e70000), + SPH_C32(0x0f5b2339), SPH_C32(0x7f3b4ddc), SPH_C32(0x7d22556c), + SPH_C32(0x619b0a52) }, + { SPH_C32(0x92570220), SPH_C32(0xd1940000), SPH_C32(0x24e80000), + SPH_C32(0x13a80000), SPH_C32(0x073278c0), SPH_C32(0x12c7bceb), + SPH_C32(0x2dbd3ce8), SPH_C32(0xfff2a53a), SPH_C32(0xb3bb0360), + SPH_C32(0xabc30000), SPH_C32(0x19b70000), SPH_C32(0xe1c50000), + SPH_C32(0xfdd3481e), SPH_C32(0xd61aa89f), SPH_C32(0x33dae074), + SPH_C32(0x001319e3) }, + { SPH_C32(0x7ad00350), SPH_C32(0x4ce60000), SPH_C32(0x36330000), + SPH_C32(0xc78a0000), SPH_C32(0xf5ba13e7), SPH_C32(0xbbe659a8), + SPH_C32(0x634589f0), SPH_C32(0x9e7ab68b), SPH_C32(0x078c0300), + SPH_C32(0xa78f0000), SPH_C32(0x4f750000), SPH_C32(0xbd6b0000), + SPH_C32(0x69875721), SPH_C32(0xed2450ba), SPH_C32(0x28ecbf49), + SPH_C32(0xf3c74ebb) }, + { SPH_C32(0x145a3c00), SPH_C32(0xb9e90000), SPH_C32(0x61270000), + SPH_C32(0xf1610000), SPH_C32(0xce613d6c), SPH_C32(0xb0493d78), + SPH_C32(0x47a96720), SPH_C32(0xe18e24c5), SPH_C32(0x23671400), + SPH_C32(0xc8b90000), SPH_C32(0xf4c70000), SPH_C32(0xfb750000), + SPH_C32(0x73cd2465), SPH_C32(0xf8a6a549), SPH_C32(0x02c40a3f), + SPH_C32(0xdc24e61f) }, + { SPH_C32(0xfcdd3d70), SPH_C32(0x249b0000), SPH_C32(0x73fc0000), + SPH_C32(0x25430000), SPH_C32(0x3ce9564b), SPH_C32(0x1968d83b), + SPH_C32(0x0951d238), SPH_C32(0x80063774), SPH_C32(0x97501460), + SPH_C32(0xc4f50000), SPH_C32(0xa2050000), SPH_C32(0xa7db0000), + SPH_C32(0xe7993b5a), SPH_C32(0xc3985d6c), SPH_C32(0x19f25502), + SPH_C32(0x2ff0b147) }, + { SPH_C32(0xa06d3c60), SPH_C32(0xb5a50000), SPH_C32(0x37e50000), + SPH_C32(0xadcf0000), SPH_C32(0x5a352253), SPH_C32(0x8b77c55d), + SPH_C32(0x5c9f381d), SPH_C32(0x125a739d), SPH_C32(0x7fd71510), + SPH_C32(0x59870000), SPH_C32(0xb0de0000), SPH_C32(0x73f90000), + SPH_C32(0x1511507d), SPH_C32(0x6ab9b82f), SPH_C32(0x570ae01a), + SPH_C32(0x4e78a2f6) }, + { SPH_C32(0x48ea3d10), SPH_C32(0x28d70000), SPH_C32(0x253e0000), + SPH_C32(0x79ed0000), SPH_C32(0xa8bd4974), SPH_C32(0x2256201e), + SPH_C32(0x12678d05), SPH_C32(0x73d2602c), SPH_C32(0xcbe01570), + SPH_C32(0x55cb0000), SPH_C32(0xe61c0000), SPH_C32(0x2f570000), + SPH_C32(0x81454f42), SPH_C32(0x5187400a), SPH_C32(0x4c3cbf27), + SPH_C32(0xbdacf5ae) }, + { SPH_C32(0xfb513e70), SPH_C32(0x83140000), SPH_C32(0x3c890000), + SPH_C32(0x98280000), SPH_C32(0x556e016a), SPH_C32(0xf44c8881), + SPH_C32(0x21bd6d71), SPH_C32(0x73c179cf), SPH_C32(0xea0c1430), + SPH_C32(0x2f9c0000), SPH_C32(0xdb430000), SPH_C32(0xdd3a0000), + SPH_C32(0x7ba47f9c), SPH_C32(0x955a547e), SPH_C32(0x525b63bb), + SPH_C32(0x424d4977) }, + { SPH_C32(0x13d63f00), SPH_C32(0x1e660000), SPH_C32(0x2e520000), + SPH_C32(0x4c0a0000), SPH_C32(0xa7e66a4d), SPH_C32(0x5d6d6dc2), + SPH_C32(0x6f45d869), SPH_C32(0x12496a7e), SPH_C32(0x5e3b1450), + SPH_C32(0x23d00000), SPH_C32(0x8d810000), SPH_C32(0x81940000), + SPH_C32(0xeff060a3), SPH_C32(0xae64ac5b), SPH_C32(0x496d3c86), + SPH_C32(0xb1991e2f) }, + { SPH_C32(0x4f663e10), SPH_C32(0x8f580000), SPH_C32(0x6a4b0000), + SPH_C32(0xc4860000), SPH_C32(0xc13a1e55), SPH_C32(0xcf7270a4), + SPH_C32(0x3a8b324c), SPH_C32(0x80152e97), SPH_C32(0xb6bc1520), + SPH_C32(0xbea20000), SPH_C32(0x9f5a0000), SPH_C32(0x55b60000), + SPH_C32(0x1d780b84), SPH_C32(0x07454918), SPH_C32(0x0795899e), + SPH_C32(0xd0110d9e) }, + { SPH_C32(0xa7e13f60), SPH_C32(0x122a0000), SPH_C32(0x78900000), + SPH_C32(0x10a40000), SPH_C32(0x33b27572), SPH_C32(0x665395e7), + SPH_C32(0x74738754), SPH_C32(0xe19d3d26), SPH_C32(0x028b1540), + SPH_C32(0xb2ee0000), SPH_C32(0xc9980000), SPH_C32(0x09180000), + SPH_C32(0x892c14bb), SPH_C32(0x3c7bb13d), SPH_C32(0x1ca3d6a3), + SPH_C32(0x23c55ac6) }, + { SPH_C32(0xdd313c30), SPH_C32(0x5ecc0000), SPH_C32(0x4ea30000), + SPH_C32(0xd72e0000), SPH_C32(0xc6086695), SPH_C32(0xddb5cc4f), + SPH_C32(0x17360ea4), SPH_C32(0x7fe78bad), SPH_C32(0x05071640), + SPH_C32(0x15610000), SPH_C32(0x86ed0000), SPH_C32(0xb4730000), + SPH_C32(0xe0ab439a), SPH_C32(0xd15fe187), SPH_C32(0x344f69ea), + SPH_C32(0xd002147d) }, + { SPH_C32(0x35b63d40), SPH_C32(0xc3be0000), SPH_C32(0x5c780000), + SPH_C32(0x030c0000), SPH_C32(0x34800db2), SPH_C32(0x7494290c), + SPH_C32(0x59cebbbc), SPH_C32(0x1e6f981c), SPH_C32(0xb1301620), + SPH_C32(0x192d0000), SPH_C32(0xd02f0000), SPH_C32(0xe8dd0000), + SPH_C32(0x74ff5ca5), SPH_C32(0xea6119a2), SPH_C32(0x2f7936d7), + SPH_C32(0x23d64325) }, + { SPH_C32(0x69063c50), SPH_C32(0x52800000), SPH_C32(0x18610000), + SPH_C32(0x8b800000), SPH_C32(0x525c79aa), SPH_C32(0xe68b346a), + SPH_C32(0x0c005199), SPH_C32(0x8c33dcf5), SPH_C32(0x59b71750), + SPH_C32(0x845f0000), SPH_C32(0xc2f40000), SPH_C32(0x3cff0000), + SPH_C32(0x86773782), SPH_C32(0x4340fce1), SPH_C32(0x618183cf), + SPH_C32(0x425e5094) }, + { SPH_C32(0x81813d20), SPH_C32(0xcff20000), SPH_C32(0x0aba0000), + SPH_C32(0x5fa20000), SPH_C32(0xa0d4128d), SPH_C32(0x4faad129), + SPH_C32(0x42f8e481), SPH_C32(0xedbbcf44), SPH_C32(0xed801730), + SPH_C32(0x88130000), SPH_C32(0x94360000), SPH_C32(0x60510000), + SPH_C32(0x122328bd), SPH_C32(0x787e04c4), SPH_C32(0x7ab7dcf2), + SPH_C32(0xb18a07cc) }, + { SPH_C32(0x323a3e40), SPH_C32(0x64310000), SPH_C32(0x130d0000), + SPH_C32(0xbe670000), SPH_C32(0x5d075a93), SPH_C32(0x99b079b6), + SPH_C32(0x712204f5), SPH_C32(0xeda8d6a7), SPH_C32(0xcc6c1670), + SPH_C32(0xf2440000), SPH_C32(0xa9690000), SPH_C32(0x923c0000), + SPH_C32(0xe8c21863), SPH_C32(0xbca310b0), SPH_C32(0x64d0006e), + SPH_C32(0x4e6bbb15) }, + { SPH_C32(0xdabd3f30), SPH_C32(0xf9430000), SPH_C32(0x01d60000), + SPH_C32(0x6a450000), SPH_C32(0xaf8f31b4), SPH_C32(0x30919cf5), + SPH_C32(0x3fdab1ed), SPH_C32(0x8c20c516), SPH_C32(0x785b1610), + SPH_C32(0xfe080000), SPH_C32(0xffab0000), SPH_C32(0xce920000), + SPH_C32(0x7c96075c), SPH_C32(0x879de895), SPH_C32(0x7fe65f53), + SPH_C32(0xbdbfec4d) }, + { SPH_C32(0x860d3e20), SPH_C32(0x687d0000), SPH_C32(0x45cf0000), + SPH_C32(0xe2c90000), SPH_C32(0xc95345ac), SPH_C32(0xa28e8193), + SPH_C32(0x6a145bc8), SPH_C32(0x1e7c81ff), SPH_C32(0x90dc1760), + SPH_C32(0x637a0000), SPH_C32(0xed700000), SPH_C32(0x1ab00000), + SPH_C32(0x8e1e6c7b), SPH_C32(0x2ebc0dd6), SPH_C32(0x311eea4b), + SPH_C32(0xdc37fffc) }, + { SPH_C32(0x6e8a3f50), SPH_C32(0xf50f0000), SPH_C32(0x57140000), + SPH_C32(0x36eb0000), SPH_C32(0x3bdb2e8b), SPH_C32(0x0baf64d0), + SPH_C32(0x24eceed0), SPH_C32(0x7ff4924e), SPH_C32(0x24eb1700), + SPH_C32(0x6f360000), SPH_C32(0xbbb20000), SPH_C32(0x461e0000), + SPH_C32(0x1a4a7344), SPH_C32(0x1582f5f3), SPH_C32(0x2a28b576), + SPH_C32(0x2fe3a8a4) } +}; + +static const sph_u32 T512_10[32][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0xa67f0001), SPH_C32(0x71378000), SPH_C32(0x19fc0000), + SPH_C32(0x96db0000), SPH_C32(0x3a8b6dfd), SPH_C32(0xebcaaef3), + SPH_C32(0x2c6d478f), SPH_C32(0xac8e6c88), SPH_C32(0x50ff0004), + SPH_C32(0x45744000), SPH_C32(0x3dfb0000), SPH_C32(0x19e60000), + SPH_C32(0x1bbc5606), SPH_C32(0xe1727b5d), SPH_C32(0xe1a8cc96), + SPH_C32(0x7b1bd6b9) }, + { SPH_C32(0xf7750009), SPH_C32(0xcf3cc000), SPH_C32(0xc3d60000), + SPH_C32(0x04920000), SPH_C32(0x029519a9), SPH_C32(0xf8e836ba), + SPH_C32(0x7a87f14e), SPH_C32(0x9e16981a), SPH_C32(0xd46a0000), + SPH_C32(0x8dc8c000), SPH_C32(0xa5af0000), SPH_C32(0x4a290000), + SPH_C32(0xfc4e427a), SPH_C32(0xc9b4866c), SPH_C32(0x98369604), + SPH_C32(0xf746c320) }, + { SPH_C32(0x510a0008), SPH_C32(0xbe0b4000), SPH_C32(0xda2a0000), + SPH_C32(0x92490000), SPH_C32(0x381e7454), SPH_C32(0x13229849), + SPH_C32(0x56eab6c1), SPH_C32(0x3298f492), SPH_C32(0x84950004), + SPH_C32(0xc8bc8000), SPH_C32(0x98540000), SPH_C32(0x53cf0000), + SPH_C32(0xe7f2147c), SPH_C32(0x28c6fd31), SPH_C32(0x799e5a92), + SPH_C32(0x8c5d1599) }, + { SPH_C32(0xd46a0000), SPH_C32(0x8dc8c000), SPH_C32(0xa5af0000), + SPH_C32(0x4a290000), SPH_C32(0xfc4e427a), SPH_C32(0xc9b4866c), + SPH_C32(0x98369604), SPH_C32(0xf746c320), SPH_C32(0x231f0009), + SPH_C32(0x42f40000), SPH_C32(0x66790000), SPH_C32(0x4ebb0000), + SPH_C32(0xfedb5bd3), SPH_C32(0x315cb0d6), SPH_C32(0xe2b1674a), + SPH_C32(0x69505b3a) }, + { SPH_C32(0x72150001), SPH_C32(0xfcff4000), SPH_C32(0xbc530000), + SPH_C32(0xdcf20000), SPH_C32(0xc6c52f87), SPH_C32(0x227e289f), + SPH_C32(0xb45bd18b), SPH_C32(0x5bc8afa8), SPH_C32(0x73e0000d), + SPH_C32(0x07804000), SPH_C32(0x5b820000), SPH_C32(0x575d0000), + SPH_C32(0xe5670dd5), SPH_C32(0xd02ecb8b), SPH_C32(0x0319abdc), + SPH_C32(0x124b8d83) }, + { SPH_C32(0x231f0009), SPH_C32(0x42f40000), SPH_C32(0x66790000), + SPH_C32(0x4ebb0000), SPH_C32(0xfedb5bd3), SPH_C32(0x315cb0d6), + SPH_C32(0xe2b1674a), SPH_C32(0x69505b3a), SPH_C32(0xf7750009), + SPH_C32(0xcf3cc000), SPH_C32(0xc3d60000), SPH_C32(0x04920000), + SPH_C32(0x029519a9), SPH_C32(0xf8e836ba), SPH_C32(0x7a87f14e), + SPH_C32(0x9e16981a) }, + { SPH_C32(0x85600008), SPH_C32(0x33c38000), SPH_C32(0x7f850000), + SPH_C32(0xd8600000), SPH_C32(0xc450362e), SPH_C32(0xda961e25), + SPH_C32(0xcedc20c5), SPH_C32(0xc5de37b2), SPH_C32(0xa78a000d), + SPH_C32(0x8a488000), SPH_C32(0xfe2d0000), SPH_C32(0x1d740000), + SPH_C32(0x19294faf), SPH_C32(0x199a4de7), SPH_C32(0x9b2f3dd8), + SPH_C32(0xe50d4ea3) }, + { SPH_C32(0x774400f0), SPH_C32(0xf15a0000), SPH_C32(0xf5b20000), + SPH_C32(0x34140000), SPH_C32(0x89377e8c), SPH_C32(0x5a8bec25), + SPH_C32(0x0bc3cd1e), SPH_C32(0xcf3775cb), SPH_C32(0xf46c0050), + SPH_C32(0x96180000), SPH_C32(0x14a50000), SPH_C32(0x031f0000), + SPH_C32(0x42947eb8), SPH_C32(0x66bf7e19), SPH_C32(0x9ca470d2), + SPH_C32(0x8a341574) }, + { SPH_C32(0xd13b00f1), SPH_C32(0x806d8000), SPH_C32(0xec4e0000), + SPH_C32(0xa2cf0000), SPH_C32(0xb3bc1371), SPH_C32(0xb14142d6), + SPH_C32(0x27ae8a91), SPH_C32(0x63b91943), SPH_C32(0xa4930054), + SPH_C32(0xd36c4000), SPH_C32(0x295e0000), SPH_C32(0x1af90000), + SPH_C32(0x592828be), SPH_C32(0x87cd0544), SPH_C32(0x7d0cbc44), + SPH_C32(0xf12fc3cd) }, + { SPH_C32(0x803100f9), SPH_C32(0x3e66c000), SPH_C32(0x36640000), + SPH_C32(0x30860000), SPH_C32(0x8ba26725), SPH_C32(0xa263da9f), + SPH_C32(0x71443c50), SPH_C32(0x5121edd1), SPH_C32(0x20060050), + SPH_C32(0x1bd0c000), SPH_C32(0xb10a0000), SPH_C32(0x49360000), + SPH_C32(0xbeda3cc2), SPH_C32(0xaf0bf875), SPH_C32(0x0492e6d6), + SPH_C32(0x7d72d654) }, + { SPH_C32(0x264e00f8), SPH_C32(0x4f514000), SPH_C32(0x2f980000), + SPH_C32(0xa65d0000), SPH_C32(0xb1290ad8), SPH_C32(0x49a9746c), + SPH_C32(0x5d297bdf), SPH_C32(0xfdaf8159), SPH_C32(0x70f90054), + SPH_C32(0x5ea48000), SPH_C32(0x8cf10000), SPH_C32(0x50d00000), + SPH_C32(0xa5666ac4), SPH_C32(0x4e798328), SPH_C32(0xe53a2a40), + SPH_C32(0x066900ed) }, + { SPH_C32(0xa32e00f0), SPH_C32(0x7c92c000), SPH_C32(0x501d0000), + SPH_C32(0x7e3d0000), SPH_C32(0x75793cf6), SPH_C32(0x933f6a49), + SPH_C32(0x93f55b1a), SPH_C32(0x3871b6eb), SPH_C32(0xd7730059), + SPH_C32(0xd4ec0000), SPH_C32(0x72dc0000), SPH_C32(0x4da40000), + SPH_C32(0xbc4f256b), SPH_C32(0x57e3cecf), SPH_C32(0x7e151798), + SPH_C32(0xe3644e4e) }, + { SPH_C32(0x055100f1), SPH_C32(0x0da54000), SPH_C32(0x49e10000), + SPH_C32(0xe8e60000), SPH_C32(0x4ff2510b), SPH_C32(0x78f5c4ba), + SPH_C32(0xbf981c95), SPH_C32(0x94ffda63), SPH_C32(0x878c005d), + SPH_C32(0x91984000), SPH_C32(0x4f270000), SPH_C32(0x54420000), + SPH_C32(0xa7f3736d), SPH_C32(0xb691b592), SPH_C32(0x9fbddb0e), + SPH_C32(0x987f98f7) }, + { SPH_C32(0x545b00f9), SPH_C32(0xb3ae0000), SPH_C32(0x93cb0000), + SPH_C32(0x7aaf0000), SPH_C32(0x77ec255f), SPH_C32(0x6bd75cf3), + SPH_C32(0xe972aa54), SPH_C32(0xa6672ef1), SPH_C32(0x03190059), + SPH_C32(0x5924c000), SPH_C32(0xd7730000), SPH_C32(0x078d0000), + SPH_C32(0x40016711), SPH_C32(0x9e5748a3), SPH_C32(0xe623819c), + SPH_C32(0x14228d6e) }, + { SPH_C32(0xf22400f8), SPH_C32(0xc2998000), SPH_C32(0x8a370000), + SPH_C32(0xec740000), SPH_C32(0x4d6748a2), SPH_C32(0x801df200), + SPH_C32(0xc51feddb), SPH_C32(0x0ae94279), SPH_C32(0x53e6005d), + SPH_C32(0x1c508000), SPH_C32(0xea880000), SPH_C32(0x1e6b0000), + SPH_C32(0x5bbd3117), SPH_C32(0x7f2533fe), SPH_C32(0x078b4d0a), + SPH_C32(0x6f395bd7) }, + { SPH_C32(0xf46c0050), SPH_C32(0x96180000), SPH_C32(0x14a50000), + SPH_C32(0x031f0000), SPH_C32(0x42947eb8), SPH_C32(0x66bf7e19), + SPH_C32(0x9ca470d2), SPH_C32(0x8a341574), SPH_C32(0x832800a0), + SPH_C32(0x67420000), SPH_C32(0xe1170000), SPH_C32(0x370b0000), + SPH_C32(0xcba30034), SPH_C32(0x3c34923c), SPH_C32(0x9767bdcc), + SPH_C32(0x450360bf) }, + { SPH_C32(0x52130051), SPH_C32(0xe72f8000), SPH_C32(0x0d590000), + SPH_C32(0x95c40000), SPH_C32(0x781f1345), SPH_C32(0x8d75d0ea), + SPH_C32(0xb0c9375d), SPH_C32(0x26ba79fc), SPH_C32(0xd3d700a4), + SPH_C32(0x22364000), SPH_C32(0xdcec0000), SPH_C32(0x2eed0000), + SPH_C32(0xd01f5632), SPH_C32(0xdd46e961), SPH_C32(0x76cf715a), + SPH_C32(0x3e18b606) }, + { SPH_C32(0x03190059), SPH_C32(0x5924c000), SPH_C32(0xd7730000), + SPH_C32(0x078d0000), SPH_C32(0x40016711), SPH_C32(0x9e5748a3), + SPH_C32(0xe623819c), SPH_C32(0x14228d6e), SPH_C32(0x574200a0), + SPH_C32(0xea8ac000), SPH_C32(0x44b80000), SPH_C32(0x7d220000), + SPH_C32(0x37ed424e), SPH_C32(0xf5801450), SPH_C32(0x0f512bc8), + SPH_C32(0xb245a39f) }, + { SPH_C32(0xa5660058), SPH_C32(0x28134000), SPH_C32(0xce8f0000), + SPH_C32(0x91560000), SPH_C32(0x7a8a0aec), SPH_C32(0x759de650), + SPH_C32(0xca4ec613), SPH_C32(0xb8ace1e6), SPH_C32(0x07bd00a4), + SPH_C32(0xaffe8000), SPH_C32(0x79430000), SPH_C32(0x64c40000), + SPH_C32(0x2c511448), SPH_C32(0x14f26f0d), SPH_C32(0xeef9e75e), + SPH_C32(0xc95e7526) }, + { SPH_C32(0x20060050), SPH_C32(0x1bd0c000), SPH_C32(0xb10a0000), + SPH_C32(0x49360000), SPH_C32(0xbeda3cc2), SPH_C32(0xaf0bf875), + SPH_C32(0x0492e6d6), SPH_C32(0x7d72d654), SPH_C32(0xa03700a9), + SPH_C32(0x25b60000), SPH_C32(0x876e0000), SPH_C32(0x79b00000), + SPH_C32(0x35785be7), SPH_C32(0x0d6822ea), SPH_C32(0x75d6da86), + SPH_C32(0x2c533b85) }, + { SPH_C32(0x86790051), SPH_C32(0x6ae74000), SPH_C32(0xa8f60000), + SPH_C32(0xdfed0000), SPH_C32(0x8451513f), SPH_C32(0x44c15686), + SPH_C32(0x28ffa159), SPH_C32(0xd1fcbadc), SPH_C32(0xf0c800ad), + SPH_C32(0x60c24000), SPH_C32(0xba950000), SPH_C32(0x60560000), + SPH_C32(0x2ec40de1), SPH_C32(0xec1a59b7), SPH_C32(0x947e1610), + SPH_C32(0x5748ed3c) }, + { SPH_C32(0xd7730059), SPH_C32(0xd4ec0000), SPH_C32(0x72dc0000), + SPH_C32(0x4da40000), SPH_C32(0xbc4f256b), SPH_C32(0x57e3cecf), + SPH_C32(0x7e151798), SPH_C32(0xe3644e4e), SPH_C32(0x745d00a9), + SPH_C32(0xa87ec000), SPH_C32(0x22c10000), SPH_C32(0x33990000), + SPH_C32(0xc936199d), SPH_C32(0xc4dca486), SPH_C32(0xede04c82), + SPH_C32(0xdb15f8a5) }, + { SPH_C32(0x710c0058), SPH_C32(0xa5db8000), SPH_C32(0x6b200000), + SPH_C32(0xdb7f0000), SPH_C32(0x86c44896), SPH_C32(0xbc29603c), + SPH_C32(0x52785017), SPH_C32(0x4fea22c6), SPH_C32(0x24a200ad), + SPH_C32(0xed0a8000), SPH_C32(0x1f3a0000), SPH_C32(0x2a7f0000), + SPH_C32(0xd28a4f9b), SPH_C32(0x25aedfdb), SPH_C32(0x0c488014), + SPH_C32(0xa00e2e1c) }, + { SPH_C32(0x832800a0), SPH_C32(0x67420000), SPH_C32(0xe1170000), + SPH_C32(0x370b0000), SPH_C32(0xcba30034), SPH_C32(0x3c34923c), + SPH_C32(0x9767bdcc), SPH_C32(0x450360bf), SPH_C32(0x774400f0), + SPH_C32(0xf15a0000), SPH_C32(0xf5b20000), SPH_C32(0x34140000), + SPH_C32(0x89377e8c), SPH_C32(0x5a8bec25), SPH_C32(0x0bc3cd1e), + SPH_C32(0xcf3775cb) }, + { SPH_C32(0x255700a1), SPH_C32(0x16758000), SPH_C32(0xf8eb0000), + SPH_C32(0xa1d00000), SPH_C32(0xf1286dc9), SPH_C32(0xd7fe3ccf), + SPH_C32(0xbb0afa43), SPH_C32(0xe98d0c37), SPH_C32(0x27bb00f4), + SPH_C32(0xb42e4000), SPH_C32(0xc8490000), SPH_C32(0x2df20000), + SPH_C32(0x928b288a), SPH_C32(0xbbf99778), SPH_C32(0xea6b0188), + SPH_C32(0xb42ca372) }, + { SPH_C32(0x745d00a9), SPH_C32(0xa87ec000), SPH_C32(0x22c10000), + SPH_C32(0x33990000), SPH_C32(0xc936199d), SPH_C32(0xc4dca486), + SPH_C32(0xede04c82), SPH_C32(0xdb15f8a5), SPH_C32(0xa32e00f0), + SPH_C32(0x7c92c000), SPH_C32(0x501d0000), SPH_C32(0x7e3d0000), + SPH_C32(0x75793cf6), SPH_C32(0x933f6a49), SPH_C32(0x93f55b1a), + SPH_C32(0x3871b6eb) }, + { SPH_C32(0xd22200a8), SPH_C32(0xd9494000), SPH_C32(0x3b3d0000), + SPH_C32(0xa5420000), SPH_C32(0xf3bd7460), SPH_C32(0x2f160a75), + SPH_C32(0xc18d0b0d), SPH_C32(0x779b942d), SPH_C32(0xf3d100f4), + SPH_C32(0x39e68000), SPH_C32(0x6de60000), SPH_C32(0x67db0000), + SPH_C32(0x6ec56af0), SPH_C32(0x724d1114), SPH_C32(0x725d978c), + SPH_C32(0x436a6052) }, + { SPH_C32(0x574200a0), SPH_C32(0xea8ac000), SPH_C32(0x44b80000), + SPH_C32(0x7d220000), SPH_C32(0x37ed424e), SPH_C32(0xf5801450), + SPH_C32(0x0f512bc8), SPH_C32(0xb245a39f), SPH_C32(0x545b00f9), + SPH_C32(0xb3ae0000), SPH_C32(0x93cb0000), SPH_C32(0x7aaf0000), + SPH_C32(0x77ec255f), SPH_C32(0x6bd75cf3), SPH_C32(0xe972aa54), + SPH_C32(0xa6672ef1) }, + { SPH_C32(0xf13d00a1), SPH_C32(0x9bbd4000), SPH_C32(0x5d440000), + SPH_C32(0xebf90000), SPH_C32(0x0d662fb3), SPH_C32(0x1e4abaa3), + SPH_C32(0x233c6c47), SPH_C32(0x1ecbcf17), SPH_C32(0x04a400fd), + SPH_C32(0xf6da4000), SPH_C32(0xae300000), SPH_C32(0x63490000), + SPH_C32(0x6c507359), SPH_C32(0x8aa527ae), SPH_C32(0x08da66c2), + SPH_C32(0xdd7cf848) }, + { SPH_C32(0xa03700a9), SPH_C32(0x25b60000), SPH_C32(0x876e0000), + SPH_C32(0x79b00000), SPH_C32(0x35785be7), SPH_C32(0x0d6822ea), + SPH_C32(0x75d6da86), SPH_C32(0x2c533b85), SPH_C32(0x803100f9), + SPH_C32(0x3e66c000), SPH_C32(0x36640000), SPH_C32(0x30860000), + SPH_C32(0x8ba26725), SPH_C32(0xa263da9f), SPH_C32(0x71443c50), + SPH_C32(0x5121edd1) }, + { SPH_C32(0x064800a8), SPH_C32(0x54818000), SPH_C32(0x9e920000), + SPH_C32(0xef6b0000), SPH_C32(0x0ff3361a), SPH_C32(0xe6a28c19), + SPH_C32(0x59bb9d09), SPH_C32(0x80dd570d), SPH_C32(0xd0ce00fd), + SPH_C32(0x7b128000), SPH_C32(0x0b9f0000), SPH_C32(0x29600000), + SPH_C32(0x901e3123), SPH_C32(0x4311a1c2), SPH_C32(0x90ecf0c6), + SPH_C32(0x2a3a3b68) } +}; + +static const sph_u32 T512_15[32][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0x75a40000), SPH_C32(0xc28b2700), SPH_C32(0x94a40000), + SPH_C32(0x90f50000), SPH_C32(0xfb7857e0), SPH_C32(0x49ce0bae), + SPH_C32(0x1767c483), SPH_C32(0xaedf667e), SPH_C32(0xd1660000), + SPH_C32(0x1bbc0300), SPH_C32(0x9eec0000), SPH_C32(0xf6940000), + SPH_C32(0x03024527), SPH_C32(0xcf70fcf2), SPH_C32(0xb4431b17), + SPH_C32(0x857f3c2b) }, + { SPH_C32(0xd1660000), SPH_C32(0x1bbc0300), SPH_C32(0x9eec0000), + SPH_C32(0xf6940000), SPH_C32(0x03024527), SPH_C32(0xcf70fcf2), + SPH_C32(0xb4431b17), SPH_C32(0x857f3c2b), SPH_C32(0xa4c20000), + SPH_C32(0xd9372400), SPH_C32(0x0a480000), SPH_C32(0x66610000), + SPH_C32(0xf87a12c7), SPH_C32(0x86bef75c), SPH_C32(0xa324df94), + SPH_C32(0x2ba05a55) }, + { SPH_C32(0xa4c20000), SPH_C32(0xd9372400), SPH_C32(0x0a480000), + SPH_C32(0x66610000), SPH_C32(0xf87a12c7), SPH_C32(0x86bef75c), + SPH_C32(0xa324df94), SPH_C32(0x2ba05a55), SPH_C32(0x75a40000), + SPH_C32(0xc28b2700), SPH_C32(0x94a40000), SPH_C32(0x90f50000), + SPH_C32(0xfb7857e0), SPH_C32(0x49ce0bae), SPH_C32(0x1767c483), + SPH_C32(0xaedf667e) }, + { SPH_C32(0x75c90003), SPH_C32(0x0e10c000), SPH_C32(0xd1200000), + SPH_C32(0xbaea0000), SPH_C32(0x8bc42f3e), SPH_C32(0x8758b757), + SPH_C32(0xbb28761d), SPH_C32(0x00b72e2b), SPH_C32(0xeecf0001), + SPH_C32(0x6f564000), SPH_C32(0xf33e0000), SPH_C32(0xa79e0000), + SPH_C32(0xbdb57219), SPH_C32(0xb711ebc5), SPH_C32(0x4a3b40ba), + SPH_C32(0xfeabf254) }, + { SPH_C32(0x006d0003), SPH_C32(0xcc9be700), SPH_C32(0x45840000), + SPH_C32(0x2a1f0000), SPH_C32(0x70bc78de), SPH_C32(0xce96bcf9), + SPH_C32(0xac4fb29e), SPH_C32(0xae684855), SPH_C32(0x3fa90001), + SPH_C32(0x74ea4300), SPH_C32(0x6dd20000), SPH_C32(0x510a0000), + SPH_C32(0xbeb7373e), SPH_C32(0x78611737), SPH_C32(0xfe785bad), + SPH_C32(0x7bd4ce7f) }, + { SPH_C32(0xa4af0003), SPH_C32(0x15acc300), SPH_C32(0x4fcc0000), + SPH_C32(0x4c7e0000), SPH_C32(0x88c66a19), SPH_C32(0x48284ba5), + SPH_C32(0x0f6b6d0a), SPH_C32(0x85c81200), SPH_C32(0x4a0d0001), + SPH_C32(0xb6616400), SPH_C32(0xf9760000), SPH_C32(0xc1ff0000), + SPH_C32(0x45cf60de), SPH_C32(0x31af1c99), SPH_C32(0xe91f9f2e), + SPH_C32(0xd50ba801) }, + { SPH_C32(0xd10b0003), SPH_C32(0xd727e400), SPH_C32(0xdb680000), + SPH_C32(0xdc8b0000), SPH_C32(0x73be3df9), SPH_C32(0x01e6400b), + SPH_C32(0x180ca989), SPH_C32(0x2b17747e), SPH_C32(0x9b6b0001), + SPH_C32(0xaddd6700), SPH_C32(0x679a0000), SPH_C32(0x376b0000), + SPH_C32(0x46cd25f9), SPH_C32(0xfedfe06b), SPH_C32(0x5d5c8439), + SPH_C32(0x5074942a) }, + { SPH_C32(0xeecf0001), SPH_C32(0x6f564000), SPH_C32(0xf33e0000), + SPH_C32(0xa79e0000), SPH_C32(0xbdb57219), SPH_C32(0xb711ebc5), + SPH_C32(0x4a3b40ba), SPH_C32(0xfeabf254), SPH_C32(0x9b060002), + SPH_C32(0x61468000), SPH_C32(0x221e0000), SPH_C32(0x1d740000), + SPH_C32(0x36715d27), SPH_C32(0x30495c92), SPH_C32(0xf11336a7), + SPH_C32(0xfe1cdc7f) }, + { SPH_C32(0x9b6b0001), SPH_C32(0xaddd6700), SPH_C32(0x679a0000), + SPH_C32(0x376b0000), SPH_C32(0x46cd25f9), SPH_C32(0xfedfe06b), + SPH_C32(0x5d5c8439), SPH_C32(0x5074942a), SPH_C32(0x4a600002), + SPH_C32(0x7afa8300), SPH_C32(0xbcf20000), SPH_C32(0xebe00000), + SPH_C32(0x35731800), SPH_C32(0xff39a060), SPH_C32(0x45502db0), + SPH_C32(0x7b63e054) }, + { SPH_C32(0x3fa90001), SPH_C32(0x74ea4300), SPH_C32(0x6dd20000), + SPH_C32(0x510a0000), SPH_C32(0xbeb7373e), SPH_C32(0x78611737), + SPH_C32(0xfe785bad), SPH_C32(0x7bd4ce7f), SPH_C32(0x3fc40002), + SPH_C32(0xb871a400), SPH_C32(0x28560000), SPH_C32(0x7b150000), + SPH_C32(0xce0b4fe0), SPH_C32(0xb6f7abce), SPH_C32(0x5237e933), + SPH_C32(0xd5bc862a) }, + { SPH_C32(0x4a0d0001), SPH_C32(0xb6616400), SPH_C32(0xf9760000), + SPH_C32(0xc1ff0000), SPH_C32(0x45cf60de), SPH_C32(0x31af1c99), + SPH_C32(0xe91f9f2e), SPH_C32(0xd50ba801), SPH_C32(0xeea20002), + SPH_C32(0xa3cda700), SPH_C32(0xb6ba0000), SPH_C32(0x8d810000), + SPH_C32(0xcd090ac7), SPH_C32(0x7987573c), SPH_C32(0xe674f224), + SPH_C32(0x50c3ba01) }, + { SPH_C32(0x9b060002), SPH_C32(0x61468000), SPH_C32(0x221e0000), + SPH_C32(0x1d740000), SPH_C32(0x36715d27), SPH_C32(0x30495c92), + SPH_C32(0xf11336a7), SPH_C32(0xfe1cdc7f), SPH_C32(0x75c90003), + SPH_C32(0x0e10c000), SPH_C32(0xd1200000), SPH_C32(0xbaea0000), + SPH_C32(0x8bc42f3e), SPH_C32(0x8758b757), SPH_C32(0xbb28761d), + SPH_C32(0x00b72e2b) }, + { SPH_C32(0xeea20002), SPH_C32(0xa3cda700), SPH_C32(0xb6ba0000), + SPH_C32(0x8d810000), SPH_C32(0xcd090ac7), SPH_C32(0x7987573c), + SPH_C32(0xe674f224), SPH_C32(0x50c3ba01), SPH_C32(0xa4af0003), + SPH_C32(0x15acc300), SPH_C32(0x4fcc0000), SPH_C32(0x4c7e0000), + SPH_C32(0x88c66a19), SPH_C32(0x48284ba5), SPH_C32(0x0f6b6d0a), + SPH_C32(0x85c81200) }, + { SPH_C32(0x4a600002), SPH_C32(0x7afa8300), SPH_C32(0xbcf20000), + SPH_C32(0xebe00000), SPH_C32(0x35731800), SPH_C32(0xff39a060), + SPH_C32(0x45502db0), SPH_C32(0x7b63e054), SPH_C32(0xd10b0003), + SPH_C32(0xd727e400), SPH_C32(0xdb680000), SPH_C32(0xdc8b0000), + SPH_C32(0x73be3df9), SPH_C32(0x01e6400b), SPH_C32(0x180ca989), + SPH_C32(0x2b17747e) }, + { SPH_C32(0x3fc40002), SPH_C32(0xb871a400), SPH_C32(0x28560000), + SPH_C32(0x7b150000), SPH_C32(0xce0b4fe0), SPH_C32(0xb6f7abce), + SPH_C32(0x5237e933), SPH_C32(0xd5bc862a), SPH_C32(0x006d0003), + SPH_C32(0xcc9be700), SPH_C32(0x45840000), SPH_C32(0x2a1f0000), + SPH_C32(0x70bc78de), SPH_C32(0xce96bcf9), SPH_C32(0xac4fb29e), + SPH_C32(0xae684855) }, + { SPH_C32(0xf6800005), SPH_C32(0x3443c000), SPH_C32(0x24070000), + SPH_C32(0x8f3d0000), SPH_C32(0x21373bfb), SPH_C32(0x0ab8d5ae), + SPH_C32(0xcdc58b19), SPH_C32(0xd795ba31), SPH_C32(0xa67f0001), + SPH_C32(0x71378000), SPH_C32(0x19fc0000), SPH_C32(0x96db0000), + SPH_C32(0x3a8b6dfd), SPH_C32(0xebcaaef3), SPH_C32(0x2c6d478f), + SPH_C32(0xac8e6c88) }, + { SPH_C32(0x83240005), SPH_C32(0xf6c8e700), SPH_C32(0xb0a30000), + SPH_C32(0x1fc80000), SPH_C32(0xda4f6c1b), SPH_C32(0x4376de00), + SPH_C32(0xdaa24f9a), SPH_C32(0x794adc4f), SPH_C32(0x77190001), + SPH_C32(0x6a8b8300), SPH_C32(0x87100000), SPH_C32(0x604f0000), + SPH_C32(0x398928da), SPH_C32(0x24ba5201), SPH_C32(0x982e5c98), + SPH_C32(0x29f150a3) }, + { SPH_C32(0x27e60005), SPH_C32(0x2fffc300), SPH_C32(0xbaeb0000), + SPH_C32(0x79a90000), SPH_C32(0x22357edc), SPH_C32(0xc5c8295c), + SPH_C32(0x7986900e), SPH_C32(0x52ea861a), SPH_C32(0x02bd0001), + SPH_C32(0xa800a400), SPH_C32(0x13b40000), SPH_C32(0xf0ba0000), + SPH_C32(0xc2f17f3a), SPH_C32(0x6d7459af), SPH_C32(0x8f49981b), + SPH_C32(0x872e36dd) }, + { SPH_C32(0x52420005), SPH_C32(0xed74e400), SPH_C32(0x2e4f0000), + SPH_C32(0xe95c0000), SPH_C32(0xd94d293c), SPH_C32(0x8c0622f2), + SPH_C32(0x6ee1548d), SPH_C32(0xfc35e064), SPH_C32(0xd3db0001), + SPH_C32(0xb3bca700), SPH_C32(0x8d580000), SPH_C32(0x062e0000), + SPH_C32(0xc1f33a1d), SPH_C32(0xa204a55d), SPH_C32(0x3b0a830c), + SPH_C32(0x02510af6) }, + { SPH_C32(0x83490006), SPH_C32(0x3a530000), SPH_C32(0xf5270000), + SPH_C32(0x35d70000), SPH_C32(0xaaf314c5), SPH_C32(0x8de062f9), + SPH_C32(0x76edfd04), SPH_C32(0xd722941a), SPH_C32(0x48b00000), + SPH_C32(0x1e61c000), SPH_C32(0xeac20000), SPH_C32(0x31450000), + SPH_C32(0x873e1fe4), SPH_C32(0x5cdb4536), SPH_C32(0x66560735), + SPH_C32(0x52259edc) }, + { SPH_C32(0xf6ed0006), SPH_C32(0xf8d82700), SPH_C32(0x61830000), + SPH_C32(0xa5220000), SPH_C32(0x518b4325), SPH_C32(0xc42e6957), + SPH_C32(0x618a3987), SPH_C32(0x79fdf264), SPH_C32(0x99d60000), + SPH_C32(0x05ddc300), SPH_C32(0x742e0000), SPH_C32(0xc7d10000), + SPH_C32(0x843c5ac3), SPH_C32(0x93abb9c4), SPH_C32(0xd2151c22), + SPH_C32(0xd75aa2f7) }, + { SPH_C32(0x522f0006), SPH_C32(0x21ef0300), SPH_C32(0x6bcb0000), + SPH_C32(0xc3430000), SPH_C32(0xa9f151e2), SPH_C32(0x42909e0b), + SPH_C32(0xc2aee613), SPH_C32(0x525da831), SPH_C32(0xec720000), + SPH_C32(0xc756e400), SPH_C32(0xe08a0000), SPH_C32(0x57240000), + SPH_C32(0x7f440d23), SPH_C32(0xda65b26a), SPH_C32(0xc572d8a1), + SPH_C32(0x7985c489) }, + { SPH_C32(0x278b0006), SPH_C32(0xe3642400), SPH_C32(0xff6f0000), + SPH_C32(0x53b60000), SPH_C32(0x52890602), SPH_C32(0x0b5e95a5), + SPH_C32(0xd5c92290), SPH_C32(0xfc82ce4f), SPH_C32(0x3d140000), + SPH_C32(0xdceae700), SPH_C32(0x7e660000), SPH_C32(0xa1b00000), + SPH_C32(0x7c464804), SPH_C32(0x15154e98), SPH_C32(0x7131c3b6), + SPH_C32(0xfcfaf8a2) }, + { SPH_C32(0x184f0004), SPH_C32(0x5b158000), SPH_C32(0xd7390000), + SPH_C32(0x28a30000), SPH_C32(0x9c8249e2), SPH_C32(0xbda93e6b), + SPH_C32(0x87fecba3), SPH_C32(0x293e4865), SPH_C32(0x3d790003), + SPH_C32(0x10710000), SPH_C32(0x3be20000), SPH_C32(0x8baf0000), + SPH_C32(0x0cfa30da), SPH_C32(0xdb83f261), SPH_C32(0xdd7e7128), + SPH_C32(0x5292b0f7) }, + { SPH_C32(0x6deb0004), SPH_C32(0x999ea700), SPH_C32(0x439d0000), + SPH_C32(0xb8560000), SPH_C32(0x67fa1e02), SPH_C32(0xf46735c5), + SPH_C32(0x90990f20), SPH_C32(0x87e12e1b), SPH_C32(0xec1f0003), + SPH_C32(0x0bcd0300), SPH_C32(0xa50e0000), SPH_C32(0x7d3b0000), + SPH_C32(0x0ff875fd), SPH_C32(0x14f30e93), SPH_C32(0x693d6a3f), + SPH_C32(0xd7ed8cdc) }, + { SPH_C32(0xc9290004), SPH_C32(0x40a98300), SPH_C32(0x49d50000), + SPH_C32(0xde370000), SPH_C32(0x9f800cc5), SPH_C32(0x72d9c299), + SPH_C32(0x33bdd0b4), SPH_C32(0xac41744e), SPH_C32(0x99bb0003), + SPH_C32(0xc9462400), SPH_C32(0x31aa0000), SPH_C32(0xedce0000), + SPH_C32(0xf480221d), SPH_C32(0x5d3d053d), SPH_C32(0x7e5aaebc), + SPH_C32(0x7932eaa2) }, + { SPH_C32(0xbc8d0004), SPH_C32(0x8222a400), SPH_C32(0xdd710000), + SPH_C32(0x4ec20000), SPH_C32(0x64f85b25), SPH_C32(0x3b17c937), + SPH_C32(0x24da1437), SPH_C32(0x029e1230), SPH_C32(0x48dd0003), + SPH_C32(0xd2fa2700), SPH_C32(0xaf460000), SPH_C32(0x1b5a0000), + SPH_C32(0xf782673a), SPH_C32(0x924df9cf), SPH_C32(0xca19b5ab), + SPH_C32(0xfc4dd689) }, + { SPH_C32(0x6d860007), SPH_C32(0x55054000), SPH_C32(0x06190000), + SPH_C32(0x92490000), SPH_C32(0x174666dc), SPH_C32(0x3af1893c), + SPH_C32(0x3cd6bdbe), SPH_C32(0x2989664e), SPH_C32(0xd3b60002), + SPH_C32(0x7f274000), SPH_C32(0xc8dc0000), SPH_C32(0x2c310000), + SPH_C32(0xb14f42c3), SPH_C32(0x6c9219a4), SPH_C32(0x97453192), + SPH_C32(0xac3942a3) }, + { SPH_C32(0x18220007), SPH_C32(0x978e6700), SPH_C32(0x92bd0000), + SPH_C32(0x02bc0000), SPH_C32(0xec3e313c), SPH_C32(0x733f8292), + SPH_C32(0x2bb1793d), SPH_C32(0x87560030), SPH_C32(0x02d00002), + SPH_C32(0x649b4300), SPH_C32(0x56300000), SPH_C32(0xdaa50000), + SPH_C32(0xb24d07e4), SPH_C32(0xa3e2e556), SPH_C32(0x23062a85), + SPH_C32(0x29467e88) }, + { SPH_C32(0xbce00007), SPH_C32(0x4eb94300), SPH_C32(0x98f50000), + SPH_C32(0x64dd0000), SPH_C32(0x144423fb), SPH_C32(0xf58175ce), + SPH_C32(0x8895a6a9), SPH_C32(0xacf65a65), SPH_C32(0x77740002), + SPH_C32(0xa6106400), SPH_C32(0xc2940000), SPH_C32(0x4a500000), + SPH_C32(0x49355004), SPH_C32(0xea2ceef8), SPH_C32(0x3461ee06), + SPH_C32(0x879918f6) }, + { SPH_C32(0xc9440007), SPH_C32(0x8c326400), SPH_C32(0x0c510000), + SPH_C32(0xf4280000), SPH_C32(0xef3c741b), SPH_C32(0xbc4f7e60), + SPH_C32(0x9ff2622a), SPH_C32(0x02293c1b), SPH_C32(0xa6120002), + SPH_C32(0xbdac6700), SPH_C32(0x5c780000), SPH_C32(0xbcc40000), + SPH_C32(0x4a371523), SPH_C32(0x255c120a), SPH_C32(0x8022f511), + SPH_C32(0x02e624dd) } +}; + +static const sph_u32 T512_20[32][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0xc6730000), SPH_C32(0xaf8d000c), SPH_C32(0xa4c10000), + SPH_C32(0x218d0000), SPH_C32(0x23111587), SPH_C32(0x7913512f), + SPH_C32(0x1d28ac88), SPH_C32(0x378dd173), SPH_C32(0xaf220000), + SPH_C32(0x7b6c0090), SPH_C32(0x67e20000), SPH_C32(0x8da20000), + SPH_C32(0xc7841e29), SPH_C32(0xb7b744f3), SPH_C32(0x9ac484f4), + SPH_C32(0x8b6c72bd) }, + { SPH_C32(0x0c720000), SPH_C32(0x49e50f00), SPH_C32(0x42790000), + SPH_C32(0x5cea0000), SPH_C32(0x33aa301a), SPH_C32(0x15822514), + SPH_C32(0x95a34b7b), SPH_C32(0xb44b0090), SPH_C32(0xfe220000), + SPH_C32(0xa7580500), SPH_C32(0x25d10000), SPH_C32(0xf7600000), + SPH_C32(0x893178da), SPH_C32(0x1fd4f860), SPH_C32(0x4ed0a315), + SPH_C32(0xa123ff9f) }, + { SPH_C32(0xca010000), SPH_C32(0xe6680f0c), SPH_C32(0xe6b80000), + SPH_C32(0x7d670000), SPH_C32(0x10bb259d), SPH_C32(0x6c91743b), + SPH_C32(0x888be7f3), SPH_C32(0x83c6d1e3), SPH_C32(0x51000000), + SPH_C32(0xdc340590), SPH_C32(0x42330000), SPH_C32(0x7ac20000), + SPH_C32(0x4eb566f3), SPH_C32(0xa863bc93), SPH_C32(0xd41427e1), + SPH_C32(0x2a4f8d22) }, + { SPH_C32(0xfe220000), SPH_C32(0xa7580500), SPH_C32(0x25d10000), + SPH_C32(0xf7600000), SPH_C32(0x893178da), SPH_C32(0x1fd4f860), + SPH_C32(0x4ed0a315), SPH_C32(0xa123ff9f), SPH_C32(0xf2500000), + SPH_C32(0xeebd0a00), SPH_C32(0x67a80000), SPH_C32(0xab8a0000), + SPH_C32(0xba9b48c0), SPH_C32(0x0a56dd74), SPH_C32(0xdb73e86e), + SPH_C32(0x1568ff0f) }, + { SPH_C32(0x38510000), SPH_C32(0x08d5050c), SPH_C32(0x81100000), + SPH_C32(0xd6ed0000), SPH_C32(0xaa206d5d), SPH_C32(0x66c7a94f), + SPH_C32(0x53f80f9d), SPH_C32(0x96ae2eec), SPH_C32(0x5d720000), + SPH_C32(0x95d10a90), SPH_C32(0x004a0000), SPH_C32(0x26280000), + SPH_C32(0x7d1f56e9), SPH_C32(0xbde19987), SPH_C32(0x41b76c9a), + SPH_C32(0x9e048db2) }, + { SPH_C32(0xf2500000), SPH_C32(0xeebd0a00), SPH_C32(0x67a80000), + SPH_C32(0xab8a0000), SPH_C32(0xba9b48c0), SPH_C32(0x0a56dd74), + SPH_C32(0xdb73e86e), SPH_C32(0x1568ff0f), SPH_C32(0x0c720000), + SPH_C32(0x49e50f00), SPH_C32(0x42790000), SPH_C32(0x5cea0000), + SPH_C32(0x33aa301a), SPH_C32(0x15822514), SPH_C32(0x95a34b7b), + SPH_C32(0xb44b0090) }, + { SPH_C32(0x34230000), SPH_C32(0x41300a0c), SPH_C32(0xc3690000), + SPH_C32(0x8a070000), SPH_C32(0x998a5d47), SPH_C32(0x73458c5b), + SPH_C32(0xc65b44e6), SPH_C32(0x22e52e7c), SPH_C32(0xa3500000), + SPH_C32(0x32890f90), SPH_C32(0x259b0000), SPH_C32(0xd1480000), + SPH_C32(0xf42e2e33), SPH_C32(0xa23561e7), SPH_C32(0x0f67cf8f), + SPH_C32(0x3f27722d) }, + { SPH_C32(0x45180000), SPH_C32(0xa5b51700), SPH_C32(0xf96a0000), + SPH_C32(0x3b480000), SPH_C32(0x1ecc142c), SPH_C32(0x231395d6), + SPH_C32(0x16bca6b0), SPH_C32(0xdf33f4df), SPH_C32(0xb83d0000), + SPH_C32(0x16710600), SPH_C32(0x379a0000), SPH_C32(0xf5b10000), + SPH_C32(0x228161ac), SPH_C32(0xae48f145), SPH_C32(0x66241616), + SPH_C32(0xc5c1eb3e) }, + { SPH_C32(0x836b0000), SPH_C32(0x0a38170c), SPH_C32(0x5dab0000), + SPH_C32(0x1ac50000), SPH_C32(0x3ddd01ab), SPH_C32(0x5a00c4f9), + SPH_C32(0x0b940a38), SPH_C32(0xe8be25ac), SPH_C32(0x171f0000), + SPH_C32(0x6d1d0690), SPH_C32(0x50780000), SPH_C32(0x78130000), + SPH_C32(0xe5057f85), SPH_C32(0x19ffb5b6), SPH_C32(0xfce092e2), + SPH_C32(0x4ead9983) }, + { SPH_C32(0x496a0000), SPH_C32(0xec501800), SPH_C32(0xbb130000), + SPH_C32(0x67a20000), SPH_C32(0x2d662436), SPH_C32(0x3691b0c2), + SPH_C32(0x831fedcb), SPH_C32(0x6b78f44f), SPH_C32(0x461f0000), + SPH_C32(0xb1290300), SPH_C32(0x124b0000), SPH_C32(0x02d10000), + SPH_C32(0xabb01976), SPH_C32(0xb19c0925), SPH_C32(0x28f4b503), + SPH_C32(0x64e214a1) }, + { SPH_C32(0x8f190000), SPH_C32(0x43dd180c), SPH_C32(0x1fd20000), + SPH_C32(0x462f0000), SPH_C32(0x0e7731b1), SPH_C32(0x4f82e1ed), + SPH_C32(0x9e374143), SPH_C32(0x5cf5253c), SPH_C32(0xe93d0000), + SPH_C32(0xca450390), SPH_C32(0x75a90000), SPH_C32(0x8f730000), + SPH_C32(0x6c34075f), SPH_C32(0x062b4dd6), SPH_C32(0xb23031f7), + SPH_C32(0xef8e661c) }, + { SPH_C32(0xbb3a0000), SPH_C32(0x02ed1200), SPH_C32(0xdcbb0000), + SPH_C32(0xcc280000), SPH_C32(0x97fd6cf6), SPH_C32(0x3cc76db6), + SPH_C32(0x586c05a5), SPH_C32(0x7e100b40), SPH_C32(0x4a6d0000), + SPH_C32(0xf8cc0c00), SPH_C32(0x50320000), SPH_C32(0x5e3b0000), + SPH_C32(0x981a296c), SPH_C32(0xa41e2c31), SPH_C32(0xbd57fe78), + SPH_C32(0xd0a91431) }, + { SPH_C32(0x7d490000), SPH_C32(0xad60120c), SPH_C32(0x787a0000), + SPH_C32(0xeda50000), SPH_C32(0xb4ec7971), SPH_C32(0x45d43c99), + SPH_C32(0x4544a92d), SPH_C32(0x499dda33), SPH_C32(0xe54f0000), + SPH_C32(0x83a00c90), SPH_C32(0x37d00000), SPH_C32(0xd3990000), + SPH_C32(0x5f9e3745), SPH_C32(0x13a968c2), SPH_C32(0x27937a8c), + SPH_C32(0x5bc5668c) }, + { SPH_C32(0xb7480000), SPH_C32(0x4b081d00), SPH_C32(0x9ec20000), + SPH_C32(0x90c20000), SPH_C32(0xa4575cec), SPH_C32(0x294548a2), + SPH_C32(0xcdcf4ede), SPH_C32(0xca5b0bd0), SPH_C32(0xb44f0000), + SPH_C32(0x5f940900), SPH_C32(0x75e30000), SPH_C32(0xa95b0000), + SPH_C32(0x112b51b6), SPH_C32(0xbbcad451), SPH_C32(0xf3875d6d), + SPH_C32(0x718aebae) }, + { SPH_C32(0x713b0000), SPH_C32(0xe4851d0c), SPH_C32(0x3a030000), + SPH_C32(0xb14f0000), SPH_C32(0x8746496b), SPH_C32(0x5056198d), + SPH_C32(0xd0e7e256), SPH_C32(0xfdd6daa3), SPH_C32(0x1b6d0000), + SPH_C32(0x24f80990), SPH_C32(0x12010000), SPH_C32(0x24f90000), + SPH_C32(0xd6af4f9f), SPH_C32(0x0c7d90a2), SPH_C32(0x6943d999), + SPH_C32(0xfae69913) }, + { SPH_C32(0xb83d0000), SPH_C32(0x16710600), SPH_C32(0x379a0000), + SPH_C32(0xf5b10000), SPH_C32(0x228161ac), SPH_C32(0xae48f145), + SPH_C32(0x66241616), SPH_C32(0xc5c1eb3e), SPH_C32(0xfd250000), + SPH_C32(0xb3c41100), SPH_C32(0xcef00000), SPH_C32(0xcef90000), + SPH_C32(0x3c4d7580), SPH_C32(0x8d5b6493), SPH_C32(0x7098b0a6), + SPH_C32(0x1af21fe1) }, + { SPH_C32(0x7e4e0000), SPH_C32(0xb9fc060c), SPH_C32(0x935b0000), + SPH_C32(0xd43c0000), SPH_C32(0x0190742b), SPH_C32(0xd75ba06a), + SPH_C32(0x7b0cba9e), SPH_C32(0xf24c3a4d), SPH_C32(0x52070000), + SPH_C32(0xc8a81190), SPH_C32(0xa9120000), SPH_C32(0x435b0000), + SPH_C32(0xfbc96ba9), SPH_C32(0x3aec2060), SPH_C32(0xea5c3452), + SPH_C32(0x919e6d5c) }, + { SPH_C32(0xb44f0000), SPH_C32(0x5f940900), SPH_C32(0x75e30000), + SPH_C32(0xa95b0000), SPH_C32(0x112b51b6), SPH_C32(0xbbcad451), + SPH_C32(0xf3875d6d), SPH_C32(0x718aebae), SPH_C32(0x03070000), + SPH_C32(0x149c1400), SPH_C32(0xeb210000), SPH_C32(0x39990000), + SPH_C32(0xb57c0d5a), SPH_C32(0x928f9cf3), SPH_C32(0x3e4813b3), + SPH_C32(0xbbd1e07e) }, + { SPH_C32(0x723c0000), SPH_C32(0xf019090c), SPH_C32(0xd1220000), + SPH_C32(0x88d60000), SPH_C32(0x323a4431), SPH_C32(0xc2d9857e), + SPH_C32(0xeeaff1e5), SPH_C32(0x46073add), SPH_C32(0xac250000), + SPH_C32(0x6ff01490), SPH_C32(0x8cc30000), SPH_C32(0xb43b0000), + SPH_C32(0x72f81373), SPH_C32(0x2538d800), SPH_C32(0xa48c9747), + SPH_C32(0x30bd92c3) }, + { SPH_C32(0x461f0000), SPH_C32(0xb1290300), SPH_C32(0x124b0000), + SPH_C32(0x02d10000), SPH_C32(0xabb01976), SPH_C32(0xb19c0925), + SPH_C32(0x28f4b503), SPH_C32(0x64e214a1), SPH_C32(0x0f750000), + SPH_C32(0x5d791b00), SPH_C32(0xa9580000), SPH_C32(0x65730000), + SPH_C32(0x86d63d40), SPH_C32(0x870db9e7), SPH_C32(0xabeb58c8), + SPH_C32(0x0f9ae0ee) }, + { SPH_C32(0x806c0000), SPH_C32(0x1ea4030c), SPH_C32(0xb68a0000), + SPH_C32(0x235c0000), SPH_C32(0x88a10cf1), SPH_C32(0xc88f580a), + SPH_C32(0x35dc198b), SPH_C32(0x536fc5d2), SPH_C32(0xa0570000), + SPH_C32(0x26151b90), SPH_C32(0xceba0000), SPH_C32(0xe8d10000), + SPH_C32(0x41522369), SPH_C32(0x30bafd14), SPH_C32(0x312fdc3c), + SPH_C32(0x84f69253) }, + { SPH_C32(0x4a6d0000), SPH_C32(0xf8cc0c00), SPH_C32(0x50320000), + SPH_C32(0x5e3b0000), SPH_C32(0x981a296c), SPH_C32(0xa41e2c31), + SPH_C32(0xbd57fe78), SPH_C32(0xd0a91431), SPH_C32(0xf1570000), + SPH_C32(0xfa211e00), SPH_C32(0x8c890000), SPH_C32(0x92130000), + SPH_C32(0x0fe7459a), SPH_C32(0x98d94187), SPH_C32(0xe53bfbdd), + SPH_C32(0xaeb91f71) }, + { SPH_C32(0x8c1e0000), SPH_C32(0x57410c0c), SPH_C32(0xf4f30000), + SPH_C32(0x7fb60000), SPH_C32(0xbb0b3ceb), SPH_C32(0xdd0d7d1e), + SPH_C32(0xa07f52f0), SPH_C32(0xe724c542), SPH_C32(0x5e750000), + SPH_C32(0x814d1e90), SPH_C32(0xeb6b0000), SPH_C32(0x1fb10000), + SPH_C32(0xc8635bb3), SPH_C32(0x2f6e0574), SPH_C32(0x7fff7f29), + SPH_C32(0x25d56dcc) }, + { SPH_C32(0xfd250000), SPH_C32(0xb3c41100), SPH_C32(0xcef00000), + SPH_C32(0xcef90000), SPH_C32(0x3c4d7580), SPH_C32(0x8d5b6493), + SPH_C32(0x7098b0a6), SPH_C32(0x1af21fe1), SPH_C32(0x45180000), + SPH_C32(0xa5b51700), SPH_C32(0xf96a0000), SPH_C32(0x3b480000), + SPH_C32(0x1ecc142c), SPH_C32(0x231395d6), SPH_C32(0x16bca6b0), + SPH_C32(0xdf33f4df) }, + { SPH_C32(0x3b560000), SPH_C32(0x1c49110c), SPH_C32(0x6a310000), + SPH_C32(0xef740000), SPH_C32(0x1f5c6007), SPH_C32(0xf44835bc), + SPH_C32(0x6db01c2e), SPH_C32(0x2d7fce92), SPH_C32(0xea3a0000), + SPH_C32(0xded91790), SPH_C32(0x9e880000), SPH_C32(0xb6ea0000), + SPH_C32(0xd9480a05), SPH_C32(0x94a4d125), SPH_C32(0x8c782244), + SPH_C32(0x545f8662) }, + { SPH_C32(0xf1570000), SPH_C32(0xfa211e00), SPH_C32(0x8c890000), + SPH_C32(0x92130000), SPH_C32(0x0fe7459a), SPH_C32(0x98d94187), + SPH_C32(0xe53bfbdd), SPH_C32(0xaeb91f71), SPH_C32(0xbb3a0000), + SPH_C32(0x02ed1200), SPH_C32(0xdcbb0000), SPH_C32(0xcc280000), + SPH_C32(0x97fd6cf6), SPH_C32(0x3cc76db6), SPH_C32(0x586c05a5), + SPH_C32(0x7e100b40) }, + { SPH_C32(0x37240000), SPH_C32(0x55ac1e0c), SPH_C32(0x28480000), + SPH_C32(0xb39e0000), SPH_C32(0x2cf6501d), SPH_C32(0xe1ca10a8), + SPH_C32(0xf8135755), SPH_C32(0x9934ce02), SPH_C32(0x14180000), + SPH_C32(0x79811290), SPH_C32(0xbb590000), SPH_C32(0x418a0000), + SPH_C32(0x507972df), SPH_C32(0x8b702945), SPH_C32(0xc2a88151), + SPH_C32(0xf57c79fd) }, + { SPH_C32(0x03070000), SPH_C32(0x149c1400), SPH_C32(0xeb210000), + SPH_C32(0x39990000), SPH_C32(0xb57c0d5a), SPH_C32(0x928f9cf3), + SPH_C32(0x3e4813b3), SPH_C32(0xbbd1e07e), SPH_C32(0xb7480000), + SPH_C32(0x4b081d00), SPH_C32(0x9ec20000), SPH_C32(0x90c20000), + SPH_C32(0xa4575cec), SPH_C32(0x294548a2), SPH_C32(0xcdcf4ede), + SPH_C32(0xca5b0bd0) }, + { SPH_C32(0xc5740000), SPH_C32(0xbb11140c), SPH_C32(0x4fe00000), + SPH_C32(0x18140000), SPH_C32(0x966d18dd), SPH_C32(0xeb9ccddc), + SPH_C32(0x2360bf3b), SPH_C32(0x8c5c310d), SPH_C32(0x186a0000), + SPH_C32(0x30641d90), SPH_C32(0xf9200000), SPH_C32(0x1d600000), + SPH_C32(0x63d342c5), SPH_C32(0x9ef20c51), SPH_C32(0x570bca2a), + SPH_C32(0x4137796d) }, + { SPH_C32(0x0f750000), SPH_C32(0x5d791b00), SPH_C32(0xa9580000), + SPH_C32(0x65730000), SPH_C32(0x86d63d40), SPH_C32(0x870db9e7), + SPH_C32(0xabeb58c8), SPH_C32(0x0f9ae0ee), SPH_C32(0x496a0000), + SPH_C32(0xec501800), SPH_C32(0xbb130000), SPH_C32(0x67a20000), + SPH_C32(0x2d662436), SPH_C32(0x3691b0c2), SPH_C32(0x831fedcb), + SPH_C32(0x6b78f44f) }, + { SPH_C32(0xc9060000), SPH_C32(0xf2f41b0c), SPH_C32(0x0d990000), + SPH_C32(0x44fe0000), SPH_C32(0xa5c728c7), SPH_C32(0xfe1ee8c8), + SPH_C32(0xb6c3f440), SPH_C32(0x3817319d), SPH_C32(0xe6480000), + SPH_C32(0x973c1890), SPH_C32(0xdcf10000), SPH_C32(0xea000000), + SPH_C32(0xeae23a1f), SPH_C32(0x8126f431), SPH_C32(0x19db693f), + SPH_C32(0xe01486f2) } +}; + +static const sph_u32 T512_25[32][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0x14190000), SPH_C32(0x23ca003c), SPH_C32(0x50df0000), + SPH_C32(0x44b60000), SPH_C32(0x1b6c67b0), SPH_C32(0x3cf3ac75), + SPH_C32(0x61e610b0), SPH_C32(0xdbcadb80), SPH_C32(0xe3430000), + SPH_C32(0x3a4e0014), SPH_C32(0xf2c60000), SPH_C32(0xaa4e0000), + SPH_C32(0xdb1e42a6), SPH_C32(0x256bbe15), SPH_C32(0x123db156), + SPH_C32(0x3a4e99d7) }, + { SPH_C32(0xe3430000), SPH_C32(0x3a4e0014), SPH_C32(0xf2c60000), + SPH_C32(0xaa4e0000), SPH_C32(0xdb1e42a6), SPH_C32(0x256bbe15), + SPH_C32(0x123db156), SPH_C32(0x3a4e99d7), SPH_C32(0xf75a0000), + SPH_C32(0x19840028), SPH_C32(0xa2190000), SPH_C32(0xeef80000), + SPH_C32(0xc0722516), SPH_C32(0x19981260), SPH_C32(0x73dba1e6), + SPH_C32(0xe1844257) }, + { SPH_C32(0xf75a0000), SPH_C32(0x19840028), SPH_C32(0xa2190000), + SPH_C32(0xeef80000), SPH_C32(0xc0722516), SPH_C32(0x19981260), + SPH_C32(0x73dba1e6), SPH_C32(0xe1844257), SPH_C32(0x14190000), + SPH_C32(0x23ca003c), SPH_C32(0x50df0000), SPH_C32(0x44b60000), + SPH_C32(0x1b6c67b0), SPH_C32(0x3cf3ac75), SPH_C32(0x61e610b0), + SPH_C32(0xdbcadb80) }, + { SPH_C32(0x54500000), SPH_C32(0x0671005c), SPH_C32(0x25ae0000), + SPH_C32(0x6a1e0000), SPH_C32(0x2ea54edf), SPH_C32(0x664e8512), + SPH_C32(0xbfba18c3), SPH_C32(0x7e715d17), SPH_C32(0xbc8d0000), + SPH_C32(0xfc3b0018), SPH_C32(0x19830000), SPH_C32(0xd10b0000), + SPH_C32(0xae1878c4), SPH_C32(0x42a69856), SPH_C32(0x0012da37), + SPH_C32(0x2c3b504e) }, + { SPH_C32(0x40490000), SPH_C32(0x25bb0060), SPH_C32(0x75710000), + SPH_C32(0x2ea80000), SPH_C32(0x35c9296f), SPH_C32(0x5abd2967), + SPH_C32(0xde5c0873), SPH_C32(0xa5bb8697), SPH_C32(0x5fce0000), + SPH_C32(0xc675000c), SPH_C32(0xeb450000), SPH_C32(0x7b450000), + SPH_C32(0x75063a62), SPH_C32(0x67cd2643), SPH_C32(0x122f6b61), + SPH_C32(0x1675c999) }, + { SPH_C32(0xb7130000), SPH_C32(0x3c3f0048), SPH_C32(0xd7680000), + SPH_C32(0xc0500000), SPH_C32(0xf5bb0c79), SPH_C32(0x43253b07), + SPH_C32(0xad87a995), SPH_C32(0x443fc4c0), SPH_C32(0x4bd70000), + SPH_C32(0xe5bf0030), SPH_C32(0xbb9a0000), SPH_C32(0x3ff30000), + SPH_C32(0x6e6a5dd2), SPH_C32(0x5b3e8a36), SPH_C32(0x73c97bd1), + SPH_C32(0xcdbf1219) }, + { SPH_C32(0xa30a0000), SPH_C32(0x1ff50074), SPH_C32(0x87b70000), + SPH_C32(0x84e60000), SPH_C32(0xeed76bc9), SPH_C32(0x7fd69772), + SPH_C32(0xcc61b925), SPH_C32(0x9ff51f40), SPH_C32(0xa8940000), + SPH_C32(0xdff10024), SPH_C32(0x495c0000), SPH_C32(0x95bd0000), + SPH_C32(0xb5741f74), SPH_C32(0x7e553423), SPH_C32(0x61f4ca87), + SPH_C32(0xf7f18bce) }, + { SPH_C32(0xbc8d0000), SPH_C32(0xfc3b0018), SPH_C32(0x19830000), + SPH_C32(0xd10b0000), SPH_C32(0xae1878c4), SPH_C32(0x42a69856), + SPH_C32(0x0012da37), SPH_C32(0x2c3b504e), SPH_C32(0xe8dd0000), + SPH_C32(0xfa4a0044), SPH_C32(0x3c2d0000), SPH_C32(0xbb150000), + SPH_C32(0x80bd361b), SPH_C32(0x24e81d44), SPH_C32(0xbfa8c2f4), + SPH_C32(0x524a0d59) }, + { SPH_C32(0xa8940000), SPH_C32(0xdff10024), SPH_C32(0x495c0000), + SPH_C32(0x95bd0000), SPH_C32(0xb5741f74), SPH_C32(0x7e553423), + SPH_C32(0x61f4ca87), SPH_C32(0xf7f18bce), SPH_C32(0x0b9e0000), + SPH_C32(0xc0040050), SPH_C32(0xceeb0000), SPH_C32(0x115b0000), + SPH_C32(0x5ba374bd), SPH_C32(0x0183a351), SPH_C32(0xad9573a2), + SPH_C32(0x6804948e) }, + { SPH_C32(0x5fce0000), SPH_C32(0xc675000c), SPH_C32(0xeb450000), + SPH_C32(0x7b450000), SPH_C32(0x75063a62), SPH_C32(0x67cd2643), + SPH_C32(0x122f6b61), SPH_C32(0x1675c999), SPH_C32(0x1f870000), + SPH_C32(0xe3ce006c), SPH_C32(0x9e340000), SPH_C32(0x55ed0000), + SPH_C32(0x40cf130d), SPH_C32(0x3d700f24), SPH_C32(0xcc736312), + SPH_C32(0xb3ce4f0e) }, + { SPH_C32(0x4bd70000), SPH_C32(0xe5bf0030), SPH_C32(0xbb9a0000), + SPH_C32(0x3ff30000), SPH_C32(0x6e6a5dd2), SPH_C32(0x5b3e8a36), + SPH_C32(0x73c97bd1), SPH_C32(0xcdbf1219), SPH_C32(0xfcc40000), + SPH_C32(0xd9800078), SPH_C32(0x6cf20000), SPH_C32(0xffa30000), + SPH_C32(0x9bd151ab), SPH_C32(0x181bb131), SPH_C32(0xde4ed244), + SPH_C32(0x8980d6d9) }, + { SPH_C32(0xe8dd0000), SPH_C32(0xfa4a0044), SPH_C32(0x3c2d0000), + SPH_C32(0xbb150000), SPH_C32(0x80bd361b), SPH_C32(0x24e81d44), + SPH_C32(0xbfa8c2f4), SPH_C32(0x524a0d59), SPH_C32(0x54500000), + SPH_C32(0x0671005c), SPH_C32(0x25ae0000), SPH_C32(0x6a1e0000), + SPH_C32(0x2ea54edf), SPH_C32(0x664e8512), SPH_C32(0xbfba18c3), + SPH_C32(0x7e715d17) }, + { SPH_C32(0xfcc40000), SPH_C32(0xd9800078), SPH_C32(0x6cf20000), + SPH_C32(0xffa30000), SPH_C32(0x9bd151ab), SPH_C32(0x181bb131), + SPH_C32(0xde4ed244), SPH_C32(0x8980d6d9), SPH_C32(0xb7130000), + SPH_C32(0x3c3f0048), SPH_C32(0xd7680000), SPH_C32(0xc0500000), + SPH_C32(0xf5bb0c79), SPH_C32(0x43253b07), SPH_C32(0xad87a995), + SPH_C32(0x443fc4c0) }, + { SPH_C32(0x0b9e0000), SPH_C32(0xc0040050), SPH_C32(0xceeb0000), + SPH_C32(0x115b0000), SPH_C32(0x5ba374bd), SPH_C32(0x0183a351), + SPH_C32(0xad9573a2), SPH_C32(0x6804948e), SPH_C32(0xa30a0000), + SPH_C32(0x1ff50074), SPH_C32(0x87b70000), SPH_C32(0x84e60000), + SPH_C32(0xeed76bc9), SPH_C32(0x7fd69772), SPH_C32(0xcc61b925), + SPH_C32(0x9ff51f40) }, + { SPH_C32(0x1f870000), SPH_C32(0xe3ce006c), SPH_C32(0x9e340000), + SPH_C32(0x55ed0000), SPH_C32(0x40cf130d), SPH_C32(0x3d700f24), + SPH_C32(0xcc736312), SPH_C32(0xb3ce4f0e), SPH_C32(0x40490000), + SPH_C32(0x25bb0060), SPH_C32(0x75710000), SPH_C32(0x2ea80000), + SPH_C32(0x35c9296f), SPH_C32(0x5abd2967), SPH_C32(0xde5c0873), + SPH_C32(0xa5bb8697) }, + { SPH_C32(0x69510000), SPH_C32(0xd4e1009c), SPH_C32(0xc3230000), + SPH_C32(0xac2f0000), SPH_C32(0xe4950bae), SPH_C32(0xcea415dc), + SPH_C32(0x87ec287c), SPH_C32(0xbce1a3ce), SPH_C32(0xc6730000), + SPH_C32(0xaf8d000c), SPH_C32(0xa4c10000), SPH_C32(0x218d0000), + SPH_C32(0x23111587), SPH_C32(0x7913512f), SPH_C32(0x1d28ac88), + SPH_C32(0x378dd173) }, + { SPH_C32(0x7d480000), SPH_C32(0xf72b00a0), SPH_C32(0x93fc0000), + SPH_C32(0xe8990000), SPH_C32(0xfff96c1e), SPH_C32(0xf257b9a9), + SPH_C32(0xe60a38cc), SPH_C32(0x672b784e), SPH_C32(0x25300000), + SPH_C32(0x95c30018), SPH_C32(0x56070000), SPH_C32(0x8bc30000), + SPH_C32(0xf80f5721), SPH_C32(0x5c78ef3a), SPH_C32(0x0f151dde), + SPH_C32(0x0dc348a4) }, + { SPH_C32(0x8a120000), SPH_C32(0xeeaf0088), SPH_C32(0x31e50000), + SPH_C32(0x06610000), SPH_C32(0x3f8b4908), SPH_C32(0xebcfabc9), + SPH_C32(0x95d1992a), SPH_C32(0x86af3a19), SPH_C32(0x31290000), + SPH_C32(0xb6090024), SPH_C32(0x06d80000), SPH_C32(0xcf750000), + SPH_C32(0xe3633091), SPH_C32(0x608b434f), SPH_C32(0x6ef30d6e), + SPH_C32(0xd6099324) }, + { SPH_C32(0x9e0b0000), SPH_C32(0xcd6500b4), SPH_C32(0x613a0000), + SPH_C32(0x42d70000), SPH_C32(0x24e72eb8), SPH_C32(0xd73c07bc), + SPH_C32(0xf437899a), SPH_C32(0x5d65e199), SPH_C32(0xd26a0000), + SPH_C32(0x8c470030), SPH_C32(0xf41e0000), SPH_C32(0x653b0000), + SPH_C32(0x387d7237), SPH_C32(0x45e0fd5a), SPH_C32(0x7ccebc38), + SPH_C32(0xec470af3) }, + { SPH_C32(0x3d010000), SPH_C32(0xd29000c0), SPH_C32(0xe68d0000), + SPH_C32(0xc6310000), SPH_C32(0xca304571), SPH_C32(0xa8ea90ce), + SPH_C32(0x385630bf), SPH_C32(0xc290fed9), SPH_C32(0x7afe0000), + SPH_C32(0x53b60014), SPH_C32(0xbd420000), SPH_C32(0xf0860000), + SPH_C32(0x8d096d43), SPH_C32(0x3bb5c979), SPH_C32(0x1d3a76bf), + SPH_C32(0x1bb6813d) }, + { SPH_C32(0x29180000), SPH_C32(0xf15a00fc), SPH_C32(0xb6520000), + SPH_C32(0x82870000), SPH_C32(0xd15c22c1), SPH_C32(0x94193cbb), + SPH_C32(0x59b0200f), SPH_C32(0x195a2559), SPH_C32(0x99bd0000), + SPH_C32(0x69f80000), SPH_C32(0x4f840000), SPH_C32(0x5ac80000), + SPH_C32(0x56172fe5), SPH_C32(0x1ede776c), SPH_C32(0x0f07c7e9), + SPH_C32(0x21f818ea) }, + { SPH_C32(0xde420000), SPH_C32(0xe8de00d4), SPH_C32(0x144b0000), + SPH_C32(0x6c7f0000), SPH_C32(0x112e07d7), SPH_C32(0x8d812edb), + SPH_C32(0x2a6b81e9), SPH_C32(0xf8de670e), SPH_C32(0x8da40000), + SPH_C32(0x4a32003c), SPH_C32(0x1f5b0000), SPH_C32(0x1e7e0000), + SPH_C32(0x4d7b4855), SPH_C32(0x222ddb19), SPH_C32(0x6ee1d759), + SPH_C32(0xfa32c36a) }, + { SPH_C32(0xca5b0000), SPH_C32(0xcb1400e8), SPH_C32(0x44940000), + SPH_C32(0x28c90000), SPH_C32(0x0a426067), SPH_C32(0xb17282ae), + SPH_C32(0x4b8d9159), SPH_C32(0x2314bc8e), SPH_C32(0x6ee70000), + SPH_C32(0x707c0028), SPH_C32(0xed9d0000), SPH_C32(0xb4300000), + SPH_C32(0x96650af3), SPH_C32(0x0746650c), SPH_C32(0x7cdc660f), + SPH_C32(0xc07c5abd) }, + { SPH_C32(0xd5dc0000), SPH_C32(0x28da0084), SPH_C32(0xdaa00000), + SPH_C32(0x7d240000), SPH_C32(0x4a8d736a), SPH_C32(0x8c028d8a), + SPH_C32(0x87fef24b), SPH_C32(0x90daf380), SPH_C32(0x2eae0000), + SPH_C32(0x55c70048), SPH_C32(0x98ec0000), SPH_C32(0x9a980000), + SPH_C32(0xa3ac239c), SPH_C32(0x5dfb4c6b), SPH_C32(0xa2806e7c), + SPH_C32(0x65c7dc2a) }, + { SPH_C32(0xc1c50000), SPH_C32(0x0b1000b8), SPH_C32(0x8a7f0000), + SPH_C32(0x39920000), SPH_C32(0x51e114da), SPH_C32(0xb0f121ff), + SPH_C32(0xe618e2fb), SPH_C32(0x4b102800), SPH_C32(0xcded0000), + SPH_C32(0x6f89005c), SPH_C32(0x6a2a0000), SPH_C32(0x30d60000), + SPH_C32(0x78b2613a), SPH_C32(0x7890f27e), SPH_C32(0xb0bddf2a), + SPH_C32(0x5f8945fd) }, + { SPH_C32(0x369f0000), SPH_C32(0x12940090), SPH_C32(0x28660000), + SPH_C32(0xd76a0000), SPH_C32(0x919331cc), SPH_C32(0xa969339f), + SPH_C32(0x95c3431d), SPH_C32(0xaa946a57), SPH_C32(0xd9f40000), + SPH_C32(0x4c430060), SPH_C32(0x3af50000), SPH_C32(0x74600000), + SPH_C32(0x63de068a), SPH_C32(0x44635e0b), SPH_C32(0xd15bcf9a), + SPH_C32(0x84439e7d) }, + { SPH_C32(0x22860000), SPH_C32(0x315e00ac), SPH_C32(0x78b90000), + SPH_C32(0x93dc0000), SPH_C32(0x8aff567c), SPH_C32(0x959a9fea), + SPH_C32(0xf42553ad), SPH_C32(0x715eb1d7), SPH_C32(0x3ab70000), + SPH_C32(0x760d0074), SPH_C32(0xc8330000), SPH_C32(0xde2e0000), + SPH_C32(0xb8c0442c), SPH_C32(0x6108e01e), SPH_C32(0xc3667ecc), + SPH_C32(0xbe0d07aa) }, + { SPH_C32(0x818c0000), SPH_C32(0x2eab00d8), SPH_C32(0xff0e0000), + SPH_C32(0x173a0000), SPH_C32(0x64283db5), SPH_C32(0xea4c0898), + SPH_C32(0x3844ea88), SPH_C32(0xeeabae97), SPH_C32(0x92230000), + SPH_C32(0xa9fc0050), SPH_C32(0x816f0000), SPH_C32(0x4b930000), + SPH_C32(0x0db45b58), SPH_C32(0x1f5dd43d), SPH_C32(0xa292b44b), + SPH_C32(0x49fc8c64) }, + { SPH_C32(0x95950000), SPH_C32(0x0d6100e4), SPH_C32(0xafd10000), + SPH_C32(0x538c0000), SPH_C32(0x7f445a05), SPH_C32(0xd6bfa4ed), + SPH_C32(0x59a2fa38), SPH_C32(0x35617517), SPH_C32(0x71600000), + SPH_C32(0x93b20044), SPH_C32(0x73a90000), SPH_C32(0xe1dd0000), + SPH_C32(0xd6aa19fe), SPH_C32(0x3a366a28), SPH_C32(0xb0af051d), + SPH_C32(0x73b215b3) }, + { SPH_C32(0x62cf0000), SPH_C32(0x14e500cc), SPH_C32(0x0dc80000), + SPH_C32(0xbd740000), SPH_C32(0xbf367f13), SPH_C32(0xcf27b68d), + SPH_C32(0x2a795bde), SPH_C32(0xd4e53740), SPH_C32(0x65790000), + SPH_C32(0xb0780078), SPH_C32(0x23760000), SPH_C32(0xa56b0000), + SPH_C32(0xcdc67e4e), SPH_C32(0x06c5c65d), SPH_C32(0xd14915ad), + SPH_C32(0xa878ce33) }, + { SPH_C32(0x76d60000), SPH_C32(0x372f00f0), SPH_C32(0x5d170000), + SPH_C32(0xf9c20000), SPH_C32(0xa45a18a3), SPH_C32(0xf3d41af8), + SPH_C32(0x4b9f4b6e), SPH_C32(0x0f2fecc0), SPH_C32(0x863a0000), + SPH_C32(0x8a36006c), SPH_C32(0xd1b00000), SPH_C32(0x0f250000), + SPH_C32(0x16d83ce8), SPH_C32(0x23ae7848), SPH_C32(0xc374a4fb), + SPH_C32(0x923657e4) } +}; + +static const sph_u32 T512_30[32][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0x1e4e0000), SPH_C32(0xdecf0000), SPH_C32(0x6df80180), + SPH_C32(0x77240000), SPH_C32(0xec47079e), SPH_C32(0xf4a0694e), + SPH_C32(0xcda31812), SPH_C32(0x98aa496e), SPH_C32(0xb2060000), + SPH_C32(0xc5690000), SPH_C32(0x28031200), SPH_C32(0x74670000), + SPH_C32(0xb6c236f4), SPH_C32(0xeb1239f8), SPH_C32(0x33d1dfec), + SPH_C32(0x094e3198) }, + { SPH_C32(0xaec30000), SPH_C32(0x9c4f0001), SPH_C32(0x79d1e000), + SPH_C32(0x2c150000), SPH_C32(0x45cc75b3), SPH_C32(0x6650b736), + SPH_C32(0xab92f78f), SPH_C32(0xa312567b), SPH_C32(0xdb250000), + SPH_C32(0x09290000), SPH_C32(0x49aac000), SPH_C32(0x81e10000), + SPH_C32(0xcafe6b59), SPH_C32(0x42793431), SPH_C32(0x43566b76), + SPH_C32(0xe86cba2e) }, + { SPH_C32(0xb08d0000), SPH_C32(0x42800001), SPH_C32(0x1429e180), + SPH_C32(0x5b310000), SPH_C32(0xa98b722d), SPH_C32(0x92f0de78), + SPH_C32(0x6631ef9d), SPH_C32(0x3bb81f15), SPH_C32(0x69230000), + SPH_C32(0xcc400000), SPH_C32(0x61a9d200), SPH_C32(0xf5860000), + SPH_C32(0x7c3c5dad), SPH_C32(0xa96b0dc9), SPH_C32(0x7087b49a), + SPH_C32(0xe1228bb6) }, + { SPH_C32(0xdb250000), SPH_C32(0x09290000), SPH_C32(0x49aac000), + SPH_C32(0x81e10000), SPH_C32(0xcafe6b59), SPH_C32(0x42793431), + SPH_C32(0x43566b76), SPH_C32(0xe86cba2e), SPH_C32(0x75e60000), + SPH_C32(0x95660001), SPH_C32(0x307b2000), SPH_C32(0xadf40000), + SPH_C32(0x8f321eea), SPH_C32(0x24298307), SPH_C32(0xe8c49cf9), + SPH_C32(0x4b7eec55) }, + { SPH_C32(0xc56b0000), SPH_C32(0xd7e60000), SPH_C32(0x2452c180), + SPH_C32(0xf6c50000), SPH_C32(0x26b96cc7), SPH_C32(0xb6d95d7f), + SPH_C32(0x8ef57364), SPH_C32(0x70c6f340), SPH_C32(0xc7e00000), + SPH_C32(0x500f0001), SPH_C32(0x18783200), SPH_C32(0xd9930000), + SPH_C32(0x39f0281e), SPH_C32(0xcf3bbaff), SPH_C32(0xdb154315), + SPH_C32(0x4230ddcd) }, + { SPH_C32(0x75e60000), SPH_C32(0x95660001), SPH_C32(0x307b2000), + SPH_C32(0xadf40000), SPH_C32(0x8f321eea), SPH_C32(0x24298307), + SPH_C32(0xe8c49cf9), SPH_C32(0x4b7eec55), SPH_C32(0xaec30000), + SPH_C32(0x9c4f0001), SPH_C32(0x79d1e000), SPH_C32(0x2c150000), + SPH_C32(0x45cc75b3), SPH_C32(0x6650b736), SPH_C32(0xab92f78f), + SPH_C32(0xa312567b) }, + { SPH_C32(0x6ba80000), SPH_C32(0x4ba90001), SPH_C32(0x5d832180), + SPH_C32(0xdad00000), SPH_C32(0x63751974), SPH_C32(0xd089ea49), + SPH_C32(0x256784eb), SPH_C32(0xd3d4a53b), SPH_C32(0x1cc50000), + SPH_C32(0x59260001), SPH_C32(0x51d2f200), SPH_C32(0x58720000), + SPH_C32(0xf30e4347), SPH_C32(0x8d428ece), SPH_C32(0x98432863), + SPH_C32(0xaa5c67e3) }, + { SPH_C32(0x86790000), SPH_C32(0x3f390002), SPH_C32(0xe19ae000), + SPH_C32(0x98560000), SPH_C32(0x9565670e), SPH_C32(0x4e88c8ea), + SPH_C32(0xd3dd4944), SPH_C32(0x161ddab9), SPH_C32(0x30b70000), + SPH_C32(0xe5d00000), SPH_C32(0xf4f46000), SPH_C32(0x42c40000), + SPH_C32(0x63b83d6a), SPH_C32(0x78ba9460), SPH_C32(0x21afa1ea), + SPH_C32(0xb0a51834) }, + { SPH_C32(0x98370000), SPH_C32(0xe1f60002), SPH_C32(0x8c62e180), + SPH_C32(0xef720000), SPH_C32(0x79226090), SPH_C32(0xba28a1a4), + SPH_C32(0x1e7e5156), SPH_C32(0x8eb793d7), SPH_C32(0x82b10000), + SPH_C32(0x20b90000), SPH_C32(0xdcf77200), SPH_C32(0x36a30000), + SPH_C32(0xd57a0b9e), SPH_C32(0x93a8ad98), SPH_C32(0x127e7e06), + SPH_C32(0xb9eb29ac) }, + { SPH_C32(0x28ba0000), SPH_C32(0xa3760003), SPH_C32(0x984b0000), + SPH_C32(0xb4430000), SPH_C32(0xd0a912bd), SPH_C32(0x28d87fdc), + SPH_C32(0x784fbecb), SPH_C32(0xb50f8cc2), SPH_C32(0xeb920000), + SPH_C32(0xecf90000), SPH_C32(0xbd5ea000), SPH_C32(0xc3250000), + SPH_C32(0xa9465633), SPH_C32(0x3ac3a051), SPH_C32(0x62f9ca9c), + SPH_C32(0x58c9a21a) }, + { SPH_C32(0x36f40000), SPH_C32(0x7db90003), SPH_C32(0xf5b30180), + SPH_C32(0xc3670000), SPH_C32(0x3cee1523), SPH_C32(0xdc781692), + SPH_C32(0xb5eca6d9), SPH_C32(0x2da5c5ac), SPH_C32(0x59940000), + SPH_C32(0x29900000), SPH_C32(0x955db200), SPH_C32(0xb7420000), + SPH_C32(0x1f8460c7), SPH_C32(0xd1d199a9), SPH_C32(0x51281570), + SPH_C32(0x51879382) }, + { SPH_C32(0x5d5c0000), SPH_C32(0x36100002), SPH_C32(0xa8302000), + SPH_C32(0x19b70000), SPH_C32(0x5f9b0c57), SPH_C32(0x0cf1fcdb), + SPH_C32(0x908b2232), SPH_C32(0xfe716097), SPH_C32(0x45510000), + SPH_C32(0x70b60001), SPH_C32(0xc48f4000), SPH_C32(0xef300000), + SPH_C32(0xec8a2380), SPH_C32(0x5c931767), SPH_C32(0xc96b3d13), + SPH_C32(0xfbdbf461) }, + { SPH_C32(0x43120000), SPH_C32(0xe8df0002), SPH_C32(0xc5c82180), + SPH_C32(0x6e930000), SPH_C32(0xb3dc0bc9), SPH_C32(0xf8519595), + SPH_C32(0x5d283a20), SPH_C32(0x66db29f9), SPH_C32(0xf7570000), + SPH_C32(0xb5df0001), SPH_C32(0xec8c5200), SPH_C32(0x9b570000), + SPH_C32(0x5a481574), SPH_C32(0xb7812e9f), SPH_C32(0xfabae2ff), + SPH_C32(0xf295c5f9) }, + { SPH_C32(0xf39f0000), SPH_C32(0xaa5f0003), SPH_C32(0xd1e1c000), + SPH_C32(0x35a20000), SPH_C32(0x1a5779e4), SPH_C32(0x6aa14bed), + SPH_C32(0x3b19d5bd), SPH_C32(0x5d6336ec), SPH_C32(0x9e740000), + SPH_C32(0x799f0001), SPH_C32(0x8d258000), SPH_C32(0x6ed10000), + SPH_C32(0x267448d9), SPH_C32(0x1eea2356), SPH_C32(0x8a3d5665), + SPH_C32(0x13b74e4f) }, + { SPH_C32(0xedd10000), SPH_C32(0x74900003), SPH_C32(0xbc19c180), + SPH_C32(0x42860000), SPH_C32(0xf6107e7a), SPH_C32(0x9e0122a3), + SPH_C32(0xf6bacdaf), SPH_C32(0xc5c97f82), SPH_C32(0x2c720000), + SPH_C32(0xbcf60001), SPH_C32(0xa5269200), SPH_C32(0x1ab60000), + SPH_C32(0x90b67e2d), SPH_C32(0xf5f81aae), SPH_C32(0xb9ec8989), + SPH_C32(0x1af97fd7) }, + { SPH_C32(0x30b70000), SPH_C32(0xe5d00000), SPH_C32(0xf4f46000), + SPH_C32(0x42c40000), SPH_C32(0x63b83d6a), SPH_C32(0x78ba9460), + SPH_C32(0x21afa1ea), SPH_C32(0xb0a51834), SPH_C32(0xb6ce0000), + SPH_C32(0xdae90002), SPH_C32(0x156e8000), SPH_C32(0xda920000), + SPH_C32(0xf6dd5a64), SPH_C32(0x36325c8a), SPH_C32(0xf272e8ae), + SPH_C32(0xa6b8c28d) }, + { SPH_C32(0x2ef90000), SPH_C32(0x3b1f0000), SPH_C32(0x990c6180), + SPH_C32(0x35e00000), SPH_C32(0x8fff3af4), SPH_C32(0x8c1afd2e), + SPH_C32(0xec0cb9f8), SPH_C32(0x280f515a), SPH_C32(0x04c80000), + SPH_C32(0x1f800002), SPH_C32(0x3d6d9200), SPH_C32(0xaef50000), + SPH_C32(0x401f6c90), SPH_C32(0xdd206572), SPH_C32(0xc1a33742), + SPH_C32(0xaff6f315) }, + { SPH_C32(0x9e740000), SPH_C32(0x799f0001), SPH_C32(0x8d258000), + SPH_C32(0x6ed10000), SPH_C32(0x267448d9), SPH_C32(0x1eea2356), + SPH_C32(0x8a3d5665), SPH_C32(0x13b74e4f), SPH_C32(0x6deb0000), + SPH_C32(0xd3c00002), SPH_C32(0x5cc44000), SPH_C32(0x5b730000), + SPH_C32(0x3c23313d), SPH_C32(0x744b68bb), SPH_C32(0xb12483d8), + SPH_C32(0x4ed478a3) }, + { SPH_C32(0x803a0000), SPH_C32(0xa7500001), SPH_C32(0xe0dd8180), + SPH_C32(0x19f50000), SPH_C32(0xca334f47), SPH_C32(0xea4a4a18), + SPH_C32(0x479e4e77), SPH_C32(0x8b1d0721), SPH_C32(0xdfed0000), + SPH_C32(0x16a90002), SPH_C32(0x74c75200), SPH_C32(0x2f140000), + SPH_C32(0x8ae107c9), SPH_C32(0x9f595143), SPH_C32(0x82f55c34), + SPH_C32(0x479a493b) }, + { SPH_C32(0xeb920000), SPH_C32(0xecf90000), SPH_C32(0xbd5ea000), + SPH_C32(0xc3250000), SPH_C32(0xa9465633), SPH_C32(0x3ac3a051), + SPH_C32(0x62f9ca9c), SPH_C32(0x58c9a21a), SPH_C32(0xc3280000), + SPH_C32(0x4f8f0003), SPH_C32(0x2515a000), SPH_C32(0x77660000), + SPH_C32(0x79ef448e), SPH_C32(0x121bdf8d), SPH_C32(0x1ab67457), + SPH_C32(0xedc62ed8) }, + { SPH_C32(0xf5dc0000), SPH_C32(0x32360000), SPH_C32(0xd0a6a180), + SPH_C32(0xb4010000), SPH_C32(0x450151ad), SPH_C32(0xce63c91f), + SPH_C32(0xaf5ad28e), SPH_C32(0xc063eb74), SPH_C32(0x712e0000), + SPH_C32(0x8ae60003), SPH_C32(0x0d16b200), SPH_C32(0x03010000), + SPH_C32(0xcf2d727a), SPH_C32(0xf909e675), SPH_C32(0x2967abbb), + SPH_C32(0xe4881f40) }, + { SPH_C32(0x45510000), SPH_C32(0x70b60001), SPH_C32(0xc48f4000), + SPH_C32(0xef300000), SPH_C32(0xec8a2380), SPH_C32(0x5c931767), + SPH_C32(0xc96b3d13), SPH_C32(0xfbdbf461), SPH_C32(0x180d0000), + SPH_C32(0x46a60003), SPH_C32(0x6cbf6000), SPH_C32(0xf6870000), + SPH_C32(0xb3112fd7), SPH_C32(0x5062ebbc), SPH_C32(0x59e01f21), + SPH_C32(0x05aa94f6) }, + { SPH_C32(0x5b1f0000), SPH_C32(0xae790001), SPH_C32(0xa9774180), + SPH_C32(0x98140000), SPH_C32(0x00cd241e), SPH_C32(0xa8337e29), + SPH_C32(0x04c82501), SPH_C32(0x6371bd0f), SPH_C32(0xaa0b0000), + SPH_C32(0x83cf0003), SPH_C32(0x44bc7200), SPH_C32(0x82e00000), + SPH_C32(0x05d31923), SPH_C32(0xbb70d244), SPH_C32(0x6a31c0cd), + SPH_C32(0x0ce4a56e) }, + { SPH_C32(0xb6ce0000), SPH_C32(0xdae90002), SPH_C32(0x156e8000), + SPH_C32(0xda920000), SPH_C32(0xf6dd5a64), SPH_C32(0x36325c8a), + SPH_C32(0xf272e8ae), SPH_C32(0xa6b8c28d), SPH_C32(0x86790000), + SPH_C32(0x3f390002), SPH_C32(0xe19ae000), SPH_C32(0x98560000), + SPH_C32(0x9565670e), SPH_C32(0x4e88c8ea), SPH_C32(0xd3dd4944), + SPH_C32(0x161ddab9) }, + { SPH_C32(0xa8800000), SPH_C32(0x04260002), SPH_C32(0x78968180), + SPH_C32(0xadb60000), SPH_C32(0x1a9a5dfa), SPH_C32(0xc29235c4), + SPH_C32(0x3fd1f0bc), SPH_C32(0x3e128be3), SPH_C32(0x347f0000), + SPH_C32(0xfa500002), SPH_C32(0xc999f200), SPH_C32(0xec310000), + SPH_C32(0x23a751fa), SPH_C32(0xa59af112), SPH_C32(0xe00c96a8), + SPH_C32(0x1f53eb21) }, + { SPH_C32(0x180d0000), SPH_C32(0x46a60003), SPH_C32(0x6cbf6000), + SPH_C32(0xf6870000), SPH_C32(0xb3112fd7), SPH_C32(0x5062ebbc), + SPH_C32(0x59e01f21), SPH_C32(0x05aa94f6), SPH_C32(0x5d5c0000), + SPH_C32(0x36100002), SPH_C32(0xa8302000), SPH_C32(0x19b70000), + SPH_C32(0x5f9b0c57), SPH_C32(0x0cf1fcdb), SPH_C32(0x908b2232), + SPH_C32(0xfe716097) }, + { SPH_C32(0x06430000), SPH_C32(0x98690003), SPH_C32(0x01476180), + SPH_C32(0x81a30000), SPH_C32(0x5f562849), SPH_C32(0xa4c282f2), + SPH_C32(0x94430733), SPH_C32(0x9d00dd98), SPH_C32(0xef5a0000), + SPH_C32(0xf3790002), SPH_C32(0x80333200), SPH_C32(0x6dd00000), + SPH_C32(0xe9593aa3), SPH_C32(0xe7e3c523), SPH_C32(0xa35afdde), + SPH_C32(0xf73f510f) }, + { SPH_C32(0x6deb0000), SPH_C32(0xd3c00002), SPH_C32(0x5cc44000), + SPH_C32(0x5b730000), SPH_C32(0x3c23313d), SPH_C32(0x744b68bb), + SPH_C32(0xb12483d8), SPH_C32(0x4ed478a3), SPH_C32(0xf39f0000), + SPH_C32(0xaa5f0003), SPH_C32(0xd1e1c000), SPH_C32(0x35a20000), + SPH_C32(0x1a5779e4), SPH_C32(0x6aa14bed), SPH_C32(0x3b19d5bd), + SPH_C32(0x5d6336ec) }, + { SPH_C32(0x73a50000), SPH_C32(0x0d0f0002), SPH_C32(0x313c4180), + SPH_C32(0x2c570000), SPH_C32(0xd06436a3), SPH_C32(0x80eb01f5), + SPH_C32(0x7c879bca), SPH_C32(0xd67e31cd), SPH_C32(0x41990000), + SPH_C32(0x6f360003), SPH_C32(0xf9e2d200), SPH_C32(0x41c50000), + SPH_C32(0xac954f10), SPH_C32(0x81b37215), SPH_C32(0x08c80a51), + SPH_C32(0x542d0774) }, + { SPH_C32(0xc3280000), SPH_C32(0x4f8f0003), SPH_C32(0x2515a000), + SPH_C32(0x77660000), SPH_C32(0x79ef448e), SPH_C32(0x121bdf8d), + SPH_C32(0x1ab67457), SPH_C32(0xedc62ed8), SPH_C32(0x28ba0000), + SPH_C32(0xa3760003), SPH_C32(0x984b0000), SPH_C32(0xb4430000), + SPH_C32(0xd0a912bd), SPH_C32(0x28d87fdc), SPH_C32(0x784fbecb), + SPH_C32(0xb50f8cc2) }, + { SPH_C32(0xdd660000), SPH_C32(0x91400003), SPH_C32(0x48eda180), + SPH_C32(0x00420000), SPH_C32(0x95a84310), SPH_C32(0xe6bbb6c3), + SPH_C32(0xd7156c45), SPH_C32(0x756c67b6), SPH_C32(0x9abc0000), + SPH_C32(0x661f0003), SPH_C32(0xb0481200), SPH_C32(0xc0240000), + SPH_C32(0x666b2449), SPH_C32(0xc3ca4624), SPH_C32(0x4b9e6127), + SPH_C32(0xbc41bd5a) } +}; + +static const sph_u32 T512_35[32][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0xcc140000), SPH_C32(0xa5630000), SPH_C32(0x5ab90780), + SPH_C32(0x3b500000), SPH_C32(0x4bd013ff), SPH_C32(0x879b3418), + SPH_C32(0x694348c1), SPH_C32(0xca5a87fe), SPH_C32(0x819e0000), + SPH_C32(0xec570000), SPH_C32(0x66320280), SPH_C32(0x95f30000), + SPH_C32(0x5da92802), SPH_C32(0x48f43cbc), SPH_C32(0xe65aa22d), + SPH_C32(0x8e67b7fa) }, + { SPH_C32(0x819e0000), SPH_C32(0xec570000), SPH_C32(0x66320280), + SPH_C32(0x95f30000), SPH_C32(0x5da92802), SPH_C32(0x48f43cbc), + SPH_C32(0xe65aa22d), SPH_C32(0x8e67b7fa), SPH_C32(0x4d8a0000), + SPH_C32(0x49340000), SPH_C32(0x3c8b0500), SPH_C32(0xaea30000), + SPH_C32(0x16793bfd), SPH_C32(0xcf6f08a4), SPH_C32(0x8f19eaec), + SPH_C32(0x443d3004) }, + { SPH_C32(0x4d8a0000), SPH_C32(0x49340000), SPH_C32(0x3c8b0500), + SPH_C32(0xaea30000), SPH_C32(0x16793bfd), SPH_C32(0xcf6f08a4), + SPH_C32(0x8f19eaec), SPH_C32(0x443d3004), SPH_C32(0xcc140000), + SPH_C32(0xa5630000), SPH_C32(0x5ab90780), SPH_C32(0x3b500000), + SPH_C32(0x4bd013ff), SPH_C32(0x879b3418), SPH_C32(0x694348c1), + SPH_C32(0xca5a87fe) }, + { SPH_C32(0x78230000), SPH_C32(0x12fc0000), SPH_C32(0xa93a0b80), + SPH_C32(0x90a50000), SPH_C32(0x713e2879), SPH_C32(0x7ee98924), + SPH_C32(0xf08ca062), SPH_C32(0x636f8bab), SPH_C32(0x02af0000), + SPH_C32(0xb7280000), SPH_C32(0xba1c0300), SPH_C32(0x56980000), + SPH_C32(0xba8d45d3), SPH_C32(0x8048c667), SPH_C32(0xa95c149a), + SPH_C32(0xf4f6ea7b) }, + { SPH_C32(0xb4370000), SPH_C32(0xb79f0000), SPH_C32(0xf3830c00), + SPH_C32(0xabf50000), SPH_C32(0x3aee3b86), SPH_C32(0xf972bd3c), + SPH_C32(0x99cfe8a3), SPH_C32(0xa9350c55), SPH_C32(0x83310000), + SPH_C32(0x5b7f0000), SPH_C32(0xdc2e0180), SPH_C32(0xc36b0000), + SPH_C32(0xe7246dd1), SPH_C32(0xc8bcfadb), SPH_C32(0x4f06b6b7), + SPH_C32(0x7a915d81) }, + { SPH_C32(0xf9bd0000), SPH_C32(0xfeab0000), SPH_C32(0xcf080900), + SPH_C32(0x05560000), SPH_C32(0x2c97007b), SPH_C32(0x361db598), + SPH_C32(0x16d6024f), SPH_C32(0xed083c51), SPH_C32(0x4f250000), + SPH_C32(0xfe1c0000), SPH_C32(0x86970600), SPH_C32(0xf83b0000), + SPH_C32(0xacf47e2e), SPH_C32(0x4f27cec3), SPH_C32(0x2645fe76), + SPH_C32(0xb0cbda7f) }, + { SPH_C32(0x35a90000), SPH_C32(0x5bc80000), SPH_C32(0x95b10e80), + SPH_C32(0x3e060000), SPH_C32(0x67471384), SPH_C32(0xb1868180), + SPH_C32(0x7f954a8e), SPH_C32(0x2752bbaf), SPH_C32(0xcebb0000), + SPH_C32(0x124b0000), SPH_C32(0xe0a50480), SPH_C32(0x6dc80000), + SPH_C32(0xf15d562c), SPH_C32(0x07d3f27f), SPH_C32(0xc01f5c5b), + SPH_C32(0x3eac6d85) }, + { SPH_C32(0x02af0000), SPH_C32(0xb7280000), SPH_C32(0xba1c0300), + SPH_C32(0x56980000), SPH_C32(0xba8d45d3), SPH_C32(0x8048c667), + SPH_C32(0xa95c149a), SPH_C32(0xf4f6ea7b), SPH_C32(0x7a8c0000), + SPH_C32(0xa5d40000), SPH_C32(0x13260880), SPH_C32(0xc63d0000), + SPH_C32(0xcbb36daa), SPH_C32(0xfea14f43), SPH_C32(0x59d0b4f8), + SPH_C32(0x979961d0) }, + { SPH_C32(0xcebb0000), SPH_C32(0x124b0000), SPH_C32(0xe0a50480), + SPH_C32(0x6dc80000), SPH_C32(0xf15d562c), SPH_C32(0x07d3f27f), + SPH_C32(0xc01f5c5b), SPH_C32(0x3eac6d85), SPH_C32(0xfb120000), + SPH_C32(0x49830000), SPH_C32(0x75140a00), SPH_C32(0x53ce0000), + SPH_C32(0x961a45a8), SPH_C32(0xb65573ff), SPH_C32(0xbf8a16d5), + SPH_C32(0x19fed62a) }, + { SPH_C32(0x83310000), SPH_C32(0x5b7f0000), SPH_C32(0xdc2e0180), + SPH_C32(0xc36b0000), SPH_C32(0xe7246dd1), SPH_C32(0xc8bcfadb), + SPH_C32(0x4f06b6b7), SPH_C32(0x7a915d81), SPH_C32(0x37060000), + SPH_C32(0xece00000), SPH_C32(0x2fad0d80), SPH_C32(0x689e0000), + SPH_C32(0xddca5657), SPH_C32(0x31ce47e7), SPH_C32(0xd6c95e14), + SPH_C32(0xd3a451d4) }, + { SPH_C32(0x4f250000), SPH_C32(0xfe1c0000), SPH_C32(0x86970600), + SPH_C32(0xf83b0000), SPH_C32(0xacf47e2e), SPH_C32(0x4f27cec3), + SPH_C32(0x2645fe76), SPH_C32(0xb0cbda7f), SPH_C32(0xb6980000), + SPH_C32(0x00b70000), SPH_C32(0x499f0f00), SPH_C32(0xfd6d0000), + SPH_C32(0x80637e55), SPH_C32(0x793a7b5b), SPH_C32(0x3093fc39), + SPH_C32(0x5dc3e62e) }, + { SPH_C32(0x7a8c0000), SPH_C32(0xa5d40000), SPH_C32(0x13260880), + SPH_C32(0xc63d0000), SPH_C32(0xcbb36daa), SPH_C32(0xfea14f43), + SPH_C32(0x59d0b4f8), SPH_C32(0x979961d0), SPH_C32(0x78230000), + SPH_C32(0x12fc0000), SPH_C32(0xa93a0b80), SPH_C32(0x90a50000), + SPH_C32(0x713e2879), SPH_C32(0x7ee98924), SPH_C32(0xf08ca062), + SPH_C32(0x636f8bab) }, + { SPH_C32(0xb6980000), SPH_C32(0x00b70000), SPH_C32(0x499f0f00), + SPH_C32(0xfd6d0000), SPH_C32(0x80637e55), SPH_C32(0x793a7b5b), + SPH_C32(0x3093fc39), SPH_C32(0x5dc3e62e), SPH_C32(0xf9bd0000), + SPH_C32(0xfeab0000), SPH_C32(0xcf080900), SPH_C32(0x05560000), + SPH_C32(0x2c97007b), SPH_C32(0x361db598), SPH_C32(0x16d6024f), + SPH_C32(0xed083c51) }, + { SPH_C32(0xfb120000), SPH_C32(0x49830000), SPH_C32(0x75140a00), + SPH_C32(0x53ce0000), SPH_C32(0x961a45a8), SPH_C32(0xb65573ff), + SPH_C32(0xbf8a16d5), SPH_C32(0x19fed62a), SPH_C32(0x35a90000), + SPH_C32(0x5bc80000), SPH_C32(0x95b10e80), SPH_C32(0x3e060000), + SPH_C32(0x67471384), SPH_C32(0xb1868180), SPH_C32(0x7f954a8e), + SPH_C32(0x2752bbaf) }, + { SPH_C32(0x37060000), SPH_C32(0xece00000), SPH_C32(0x2fad0d80), + SPH_C32(0x689e0000), SPH_C32(0xddca5657), SPH_C32(0x31ce47e7), + SPH_C32(0xd6c95e14), SPH_C32(0xd3a451d4), SPH_C32(0xb4370000), + SPH_C32(0xb79f0000), SPH_C32(0xf3830c00), SPH_C32(0xabf50000), + SPH_C32(0x3aee3b86), SPH_C32(0xf972bd3c), SPH_C32(0x99cfe8a3), + SPH_C32(0xa9350c55) }, + { SPH_C32(0xac480000), SPH_C32(0x1ba60000), SPH_C32(0x45fb1380), + SPH_C32(0x03430000), SPH_C32(0x5a85316a), SPH_C32(0x1fb250b6), + SPH_C32(0xfe72c7fe), SPH_C32(0x91e478f6), SPH_C32(0x1e4e0000), + SPH_C32(0xdecf0000), SPH_C32(0x6df80180), SPH_C32(0x77240000), + SPH_C32(0xec47079e), SPH_C32(0xf4a0694e), SPH_C32(0xcda31812), + SPH_C32(0x98aa496e) }, + { SPH_C32(0x605c0000), SPH_C32(0xbec50000), SPH_C32(0x1f421400), + SPH_C32(0x38130000), SPH_C32(0x11552295), SPH_C32(0x982964ae), + SPH_C32(0x97318f3f), SPH_C32(0x5bbeff08), SPH_C32(0x9fd00000), + SPH_C32(0x32980000), SPH_C32(0x0bca0300), SPH_C32(0xe2d70000), + SPH_C32(0xb1ee2f9c), SPH_C32(0xbc5455f2), SPH_C32(0x2bf9ba3f), + SPH_C32(0x16cdfe94) }, + { SPH_C32(0x2dd60000), SPH_C32(0xf7f10000), SPH_C32(0x23c91100), + SPH_C32(0x96b00000), SPH_C32(0x072c1968), SPH_C32(0x57466c0a), + SPH_C32(0x182865d3), SPH_C32(0x1f83cf0c), SPH_C32(0x53c40000), + SPH_C32(0x97fb0000), SPH_C32(0x51730480), SPH_C32(0xd9870000), + SPH_C32(0xfa3e3c63), SPH_C32(0x3bcf61ea), SPH_C32(0x42baf2fe), + SPH_C32(0xdc97796a) }, + { SPH_C32(0xe1c20000), SPH_C32(0x52920000), SPH_C32(0x79701680), + SPH_C32(0xade00000), SPH_C32(0x4cfc0a97), SPH_C32(0xd0dd5812), + SPH_C32(0x716b2d12), SPH_C32(0xd5d948f2), SPH_C32(0xd25a0000), + SPH_C32(0x7bac0000), SPH_C32(0x37410600), SPH_C32(0x4c740000), + SPH_C32(0xa7971461), SPH_C32(0x733b5d56), SPH_C32(0xa4e050d3), + SPH_C32(0x52f0ce90) }, + { SPH_C32(0xd46b0000), SPH_C32(0x095a0000), SPH_C32(0xecc11800), + SPH_C32(0x93e60000), SPH_C32(0x2bbb1913), SPH_C32(0x615bd992), + SPH_C32(0x0efe679c), SPH_C32(0xf28bf35d), SPH_C32(0x1ce10000), + SPH_C32(0x69e70000), SPH_C32(0xd7e40280), SPH_C32(0x21bc0000), + SPH_C32(0x56ca424d), SPH_C32(0x74e8af29), SPH_C32(0x64ff0c88), + SPH_C32(0x6c5ca315) }, + { SPH_C32(0x187f0000), SPH_C32(0xac390000), SPH_C32(0xb6781f80), + SPH_C32(0xa8b60000), SPH_C32(0x606b0aec), SPH_C32(0xe6c0ed8a), + SPH_C32(0x67bd2f5d), SPH_C32(0x38d174a3), SPH_C32(0x9d7f0000), + SPH_C32(0x85b00000), SPH_C32(0xb1d60000), SPH_C32(0xb44f0000), + SPH_C32(0x0b636a4f), SPH_C32(0x3c1c9395), SPH_C32(0x82a5aea5), + SPH_C32(0xe23b14ef) }, + { SPH_C32(0x55f50000), SPH_C32(0xe50d0000), SPH_C32(0x8af31a80), + SPH_C32(0x06150000), SPH_C32(0x76123111), SPH_C32(0x29afe52e), + SPH_C32(0xe8a4c5b1), SPH_C32(0x7cec44a7), SPH_C32(0x516b0000), + SPH_C32(0x20d30000), SPH_C32(0xeb6f0780), SPH_C32(0x8f1f0000), + SPH_C32(0x40b379b0), SPH_C32(0xbb87a78d), SPH_C32(0xebe6e664), + SPH_C32(0x28619311) }, + { SPH_C32(0x99e10000), SPH_C32(0x406e0000), SPH_C32(0xd04a1d00), + SPH_C32(0x3d450000), SPH_C32(0x3dc222ee), SPH_C32(0xae34d136), + SPH_C32(0x81e78d70), SPH_C32(0xb6b6c359), SPH_C32(0xd0f50000), + SPH_C32(0xcc840000), SPH_C32(0x8d5d0500), SPH_C32(0x1aec0000), + SPH_C32(0x1d1a51b2), SPH_C32(0xf3739b31), SPH_C32(0x0dbc4449), + SPH_C32(0xa60624eb) }, + { SPH_C32(0xaee70000), SPH_C32(0xac8e0000), SPH_C32(0xffe71080), + SPH_C32(0x55db0000), SPH_C32(0xe00874b9), SPH_C32(0x9ffa96d1), + SPH_C32(0x572ed364), SPH_C32(0x6512928d), SPH_C32(0x64c20000), + SPH_C32(0x7b1b0000), SPH_C32(0x7ede0900), SPH_C32(0xb1190000), + SPH_C32(0x27f46a34), SPH_C32(0x0a01260d), SPH_C32(0x9473acea), + SPH_C32(0x0f3328be) }, + { SPH_C32(0x62f30000), SPH_C32(0x09ed0000), SPH_C32(0xa55e1700), + SPH_C32(0x6e8b0000), SPH_C32(0xabd86746), SPH_C32(0x1861a2c9), + SPH_C32(0x3e6d9ba5), SPH_C32(0xaf481573), SPH_C32(0xe55c0000), + SPH_C32(0x974c0000), SPH_C32(0x18ec0b80), SPH_C32(0x24ea0000), + SPH_C32(0x7a5d4236), SPH_C32(0x42f51ab1), SPH_C32(0x72290ec7), + SPH_C32(0x81549f44) }, + { SPH_C32(0x2f790000), SPH_C32(0x40d90000), SPH_C32(0x99d51200), + SPH_C32(0xc0280000), SPH_C32(0xbda15cbb), SPH_C32(0xd70eaa6d), + SPH_C32(0xb1747149), SPH_C32(0xeb752577), SPH_C32(0x29480000), + SPH_C32(0x322f0000), SPH_C32(0x42550c00), SPH_C32(0x1fba0000), + SPH_C32(0x318d51c9), SPH_C32(0xc56e2ea9), SPH_C32(0x1b6a4606), + SPH_C32(0x4b0e18ba) }, + { SPH_C32(0xe36d0000), SPH_C32(0xe5ba0000), SPH_C32(0xc36c1580), + SPH_C32(0xfb780000), SPH_C32(0xf6714f44), SPH_C32(0x50959e75), + SPH_C32(0xd8373988), SPH_C32(0x212fa289), SPH_C32(0xa8d60000), + SPH_C32(0xde780000), SPH_C32(0x24670e80), SPH_C32(0x8a490000), + SPH_C32(0x6c2479cb), SPH_C32(0x8d9a1215), SPH_C32(0xfd30e42b), + SPH_C32(0xc569af40) }, + { SPH_C32(0xd6c40000), SPH_C32(0xbe720000), SPH_C32(0x56dd1b00), + SPH_C32(0xc57e0000), SPH_C32(0x91365cc0), SPH_C32(0xe1131ff5), + SPH_C32(0xa7a27306), SPH_C32(0x067d1926), SPH_C32(0x666d0000), + SPH_C32(0xcc330000), SPH_C32(0xc4c20a00), SPH_C32(0xe7810000), + SPH_C32(0x9d792fe7), SPH_C32(0x8a49e06a), SPH_C32(0x3d2fb870), + SPH_C32(0xfbc5c2c5) }, + { SPH_C32(0x1ad00000), SPH_C32(0x1b110000), SPH_C32(0x0c641c80), + SPH_C32(0xfe2e0000), SPH_C32(0xdae64f3f), SPH_C32(0x66882bed), + SPH_C32(0xcee13bc7), SPH_C32(0xcc279ed8), SPH_C32(0xe7f30000), + SPH_C32(0x20640000), SPH_C32(0xa2f00880), SPH_C32(0x72720000), + SPH_C32(0xc0d007e5), SPH_C32(0xc2bddcd6), SPH_C32(0xdb751a5d), + SPH_C32(0x75a2753f) }, + { SPH_C32(0x575a0000), SPH_C32(0x52250000), SPH_C32(0x30ef1980), + SPH_C32(0x508d0000), SPH_C32(0xcc9f74c2), SPH_C32(0xa9e72349), + SPH_C32(0x41f8d12b), SPH_C32(0x881aaedc), SPH_C32(0x2be70000), + SPH_C32(0x85070000), SPH_C32(0xf8490f00), SPH_C32(0x49220000), + SPH_C32(0x8b00141a), SPH_C32(0x4526e8ce), SPH_C32(0xb236529c), + SPH_C32(0xbff8f2c1) }, + { SPH_C32(0x9b4e0000), SPH_C32(0xf7460000), SPH_C32(0x6a561e00), + SPH_C32(0x6bdd0000), SPH_C32(0x874f673d), SPH_C32(0x2e7c1751), + SPH_C32(0x28bb99ea), SPH_C32(0x42402922), SPH_C32(0xaa790000), + SPH_C32(0x69500000), SPH_C32(0x9e7b0d80), SPH_C32(0xdcd10000), + SPH_C32(0xd6a93c18), SPH_C32(0x0dd2d472), SPH_C32(0x546cf0b1), + SPH_C32(0x319f453b) } +}; + +static const sph_u32 T512_40[32][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0x07ed0000), SPH_C32(0xb2500000), SPH_C32(0x8774000a), + SPH_C32(0x970d0000), SPH_C32(0x437223ae), SPH_C32(0x48c76ea4), + SPH_C32(0xf4786222), SPH_C32(0x9075b1ce), SPH_C32(0xa2d60000), + SPH_C32(0xa6760000), SPH_C32(0xc9440014), SPH_C32(0xeba30000), + SPH_C32(0xccec2e7b), SPH_C32(0x3018c499), SPH_C32(0x03490afa), + SPH_C32(0x9b6ef888) }, + { SPH_C32(0x88980000), SPH_C32(0x1f940000), SPH_C32(0x7fcf002e), + SPH_C32(0xfb4e0000), SPH_C32(0xf158079a), SPH_C32(0x61ae9167), + SPH_C32(0xa895706c), SPH_C32(0xe6107494), SPH_C32(0x0bc20000), + SPH_C32(0xdb630000), SPH_C32(0x7e88000c), SPH_C32(0x15860000), + SPH_C32(0x91fd48f3), SPH_C32(0x7581bb43), SPH_C32(0xf460449e), + SPH_C32(0xd8b61463) }, + { SPH_C32(0x8f750000), SPH_C32(0xadc40000), SPH_C32(0xf8bb0024), + SPH_C32(0x6c430000), SPH_C32(0xb22a2434), SPH_C32(0x2969ffc3), + SPH_C32(0x5ced124e), SPH_C32(0x7665c55a), SPH_C32(0xa9140000), + SPH_C32(0x7d150000), SPH_C32(0xb7cc0018), SPH_C32(0xfe250000), + SPH_C32(0x5d116688), SPH_C32(0x45997fda), SPH_C32(0xf7294e64), + SPH_C32(0x43d8eceb) }, + { SPH_C32(0x0bc20000), SPH_C32(0xdb630000), SPH_C32(0x7e88000c), + SPH_C32(0x15860000), SPH_C32(0x91fd48f3), SPH_C32(0x7581bb43), + SPH_C32(0xf460449e), SPH_C32(0xd8b61463), SPH_C32(0x835a0000), + SPH_C32(0xc4f70000), SPH_C32(0x01470022), SPH_C32(0xeec80000), + SPH_C32(0x60a54f69), SPH_C32(0x142f2a24), SPH_C32(0x5cf534f2), + SPH_C32(0x3ea660f7) }, + { SPH_C32(0x0c2f0000), SPH_C32(0x69330000), SPH_C32(0xf9fc0006), + SPH_C32(0x828b0000), SPH_C32(0xd28f6b5d), SPH_C32(0x3d46d5e7), + SPH_C32(0x001826bc), SPH_C32(0x48c3a5ad), SPH_C32(0x218c0000), + SPH_C32(0x62810000), SPH_C32(0xc8030036), SPH_C32(0x056b0000), + SPH_C32(0xac496112), SPH_C32(0x2437eebd), SPH_C32(0x5fbc3e08), + SPH_C32(0xa5c8987f) }, + { SPH_C32(0x835a0000), SPH_C32(0xc4f70000), SPH_C32(0x01470022), + SPH_C32(0xeec80000), SPH_C32(0x60a54f69), SPH_C32(0x142f2a24), + SPH_C32(0x5cf534f2), SPH_C32(0x3ea660f7), SPH_C32(0x88980000), + SPH_C32(0x1f940000), SPH_C32(0x7fcf002e), SPH_C32(0xfb4e0000), + SPH_C32(0xf158079a), SPH_C32(0x61ae9167), SPH_C32(0xa895706c), + SPH_C32(0xe6107494) }, + { SPH_C32(0x84b70000), SPH_C32(0x76a70000), SPH_C32(0x86330028), + SPH_C32(0x79c50000), SPH_C32(0x23d76cc7), SPH_C32(0x5ce84480), + SPH_C32(0xa88d56d0), SPH_C32(0xaed3d139), SPH_C32(0x2a4e0000), + SPH_C32(0xb9e20000), SPH_C32(0xb68b003a), SPH_C32(0x10ed0000), + SPH_C32(0x3db429e1), SPH_C32(0x51b655fe), SPH_C32(0xabdc7a96), + SPH_C32(0x7d7e8c1c) }, + { SPH_C32(0x52500000), SPH_C32(0x29540000), SPH_C32(0x6a61004e), + SPH_C32(0xf0ff0000), SPH_C32(0x9a317eec), SPH_C32(0x452341ce), + SPH_C32(0xcf568fe5), SPH_C32(0x5303130f), SPH_C32(0x538d0000), + SPH_C32(0xa9fc0000), SPH_C32(0x9ef70006), SPH_C32(0x56ff0000), + SPH_C32(0x0ae4004e), SPH_C32(0x92c5cdf9), SPH_C32(0xa9444018), + SPH_C32(0x7f975691) }, + { SPH_C32(0x55bd0000), SPH_C32(0x9b040000), SPH_C32(0xed150044), + SPH_C32(0x67f20000), SPH_C32(0xd9435d42), SPH_C32(0x0de42f6a), + SPH_C32(0x3b2eedc7), SPH_C32(0xc376a2c1), SPH_C32(0xf15b0000), + SPH_C32(0x0f8a0000), SPH_C32(0x57b30012), SPH_C32(0xbd5c0000), + SPH_C32(0xc6082e35), SPH_C32(0xa2dd0960), SPH_C32(0xaa0d4ae2), + SPH_C32(0xe4f9ae19) }, + { SPH_C32(0xdac80000), SPH_C32(0x36c00000), SPH_C32(0x15ae0060), + SPH_C32(0x0bb10000), SPH_C32(0x6b697976), SPH_C32(0x248dd0a9), + SPH_C32(0x67c3ff89), SPH_C32(0xb513679b), SPH_C32(0x584f0000), + SPH_C32(0x729f0000), SPH_C32(0xe07f000a), SPH_C32(0x43790000), + SPH_C32(0x9b1948bd), SPH_C32(0xe74476ba), SPH_C32(0x5d240486), + SPH_C32(0xa72142f2) }, + { SPH_C32(0xdd250000), SPH_C32(0x84900000), SPH_C32(0x92da006a), + SPH_C32(0x9cbc0000), SPH_C32(0x281b5ad8), SPH_C32(0x6c4abe0d), + SPH_C32(0x93bb9dab), SPH_C32(0x2566d655), SPH_C32(0xfa990000), + SPH_C32(0xd4e90000), SPH_C32(0x293b001e), SPH_C32(0xa8da0000), + SPH_C32(0x57f566c6), SPH_C32(0xd75cb223), SPH_C32(0x5e6d0e7c), + SPH_C32(0x3c4fba7a) }, + { SPH_C32(0x59920000), SPH_C32(0xf2370000), SPH_C32(0x14e90042), + SPH_C32(0xe5790000), SPH_C32(0x0bcc361f), SPH_C32(0x30a2fa8d), + SPH_C32(0x3b36cb7b), SPH_C32(0x8bb5076c), SPH_C32(0xd0d70000), + SPH_C32(0x6d0b0000), SPH_C32(0x9fb00024), SPH_C32(0xb8370000), + SPH_C32(0x6a414f27), SPH_C32(0x86eae7dd), SPH_C32(0xf5b174ea), + SPH_C32(0x41313666) }, + { SPH_C32(0x5e7f0000), SPH_C32(0x40670000), SPH_C32(0x939d0048), + SPH_C32(0x72740000), SPH_C32(0x48be15b1), SPH_C32(0x78659429), + SPH_C32(0xcf4ea959), SPH_C32(0x1bc0b6a2), SPH_C32(0x72010000), + SPH_C32(0xcb7d0000), SPH_C32(0x56f40030), SPH_C32(0x53940000), + SPH_C32(0xa6ad615c), SPH_C32(0xb6f22344), SPH_C32(0xf6f87e10), + SPH_C32(0xda5fceee) }, + { SPH_C32(0xd10a0000), SPH_C32(0xeda30000), SPH_C32(0x6b26006c), + SPH_C32(0x1e370000), SPH_C32(0xfa943185), SPH_C32(0x510c6bea), + SPH_C32(0x93a3bb17), SPH_C32(0x6da573f8), SPH_C32(0xdb150000), + SPH_C32(0xb6680000), SPH_C32(0xe1380028), SPH_C32(0xadb10000), + SPH_C32(0xfbbc07d4), SPH_C32(0xf36b5c9e), SPH_C32(0x01d13074), + SPH_C32(0x99872205) }, + { SPH_C32(0xd6e70000), SPH_C32(0x5ff30000), SPH_C32(0xec520066), + SPH_C32(0x893a0000), SPH_C32(0xb9e6122b), SPH_C32(0x19cb054e), + SPH_C32(0x67dbd935), SPH_C32(0xfdd0c236), SPH_C32(0x79c30000), + SPH_C32(0x101e0000), SPH_C32(0x287c003c), SPH_C32(0x46120000), + SPH_C32(0x375029af), SPH_C32(0xc3739807), SPH_C32(0x02983a8e), + SPH_C32(0x02e9da8d) }, + { SPH_C32(0x538d0000), SPH_C32(0xa9fc0000), SPH_C32(0x9ef70006), + SPH_C32(0x56ff0000), SPH_C32(0x0ae4004e), SPH_C32(0x92c5cdf9), + SPH_C32(0xa9444018), SPH_C32(0x7f975691), SPH_C32(0x01dd0000), + SPH_C32(0x80a80000), SPH_C32(0xf4960048), SPH_C32(0xa6000000), + SPH_C32(0x90d57ea2), SPH_C32(0xd7e68c37), SPH_C32(0x6612cffd), + SPH_C32(0x2c94459e) }, + { SPH_C32(0x54600000), SPH_C32(0x1bac0000), SPH_C32(0x1983000c), + SPH_C32(0xc1f20000), SPH_C32(0x499623e0), SPH_C32(0xda02a35d), + SPH_C32(0x5d3c223a), SPH_C32(0xefe2e75f), SPH_C32(0xa30b0000), + SPH_C32(0x26de0000), SPH_C32(0x3dd2005c), SPH_C32(0x4da30000), + SPH_C32(0x5c3950d9), SPH_C32(0xe7fe48ae), SPH_C32(0x655bc507), + SPH_C32(0xb7fabd16) }, + { SPH_C32(0xdb150000), SPH_C32(0xb6680000), SPH_C32(0xe1380028), + SPH_C32(0xadb10000), SPH_C32(0xfbbc07d4), SPH_C32(0xf36b5c9e), + SPH_C32(0x01d13074), SPH_C32(0x99872205), SPH_C32(0x0a1f0000), + SPH_C32(0x5bcb0000), SPH_C32(0x8a1e0044), SPH_C32(0xb3860000), + SPH_C32(0x01283651), SPH_C32(0xa2673774), SPH_C32(0x92728b63), + SPH_C32(0xf42251fd) }, + { SPH_C32(0xdcf80000), SPH_C32(0x04380000), SPH_C32(0x664c0022), + SPH_C32(0x3abc0000), SPH_C32(0xb8ce247a), SPH_C32(0xbbac323a), + SPH_C32(0xf5a95256), SPH_C32(0x09f293cb), SPH_C32(0xa8c90000), + SPH_C32(0xfdbd0000), SPH_C32(0x435a0050), SPH_C32(0x58250000), + SPH_C32(0xcdc4182a), SPH_C32(0x927ff3ed), SPH_C32(0x913b8199), + SPH_C32(0x6f4ca975) }, + { SPH_C32(0x584f0000), SPH_C32(0x729f0000), SPH_C32(0xe07f000a), + SPH_C32(0x43790000), SPH_C32(0x9b1948bd), SPH_C32(0xe74476ba), + SPH_C32(0x5d240486), SPH_C32(0xa72142f2), SPH_C32(0x82870000), + SPH_C32(0x445f0000), SPH_C32(0xf5d1006a), SPH_C32(0x48c80000), + SPH_C32(0xf07031cb), SPH_C32(0xc3c9a613), SPH_C32(0x3ae7fb0f), + SPH_C32(0x12322569) }, + { SPH_C32(0x5fa20000), SPH_C32(0xc0cf0000), SPH_C32(0x670b0000), + SPH_C32(0xd4740000), SPH_C32(0xd86b6b13), SPH_C32(0xaf83181e), + SPH_C32(0xa95c66a4), SPH_C32(0x3754f33c), SPH_C32(0x20510000), + SPH_C32(0xe2290000), SPH_C32(0x3c95007e), SPH_C32(0xa36b0000), + SPH_C32(0x3c9c1fb0), SPH_C32(0xf3d1628a), SPH_C32(0x39aef1f5), + SPH_C32(0x895cdde1) }, + { SPH_C32(0xd0d70000), SPH_C32(0x6d0b0000), SPH_C32(0x9fb00024), + SPH_C32(0xb8370000), SPH_C32(0x6a414f27), SPH_C32(0x86eae7dd), + SPH_C32(0xf5b174ea), SPH_C32(0x41313666), SPH_C32(0x89450000), + SPH_C32(0x9f3c0000), SPH_C32(0x8b590066), SPH_C32(0x5d4e0000), + SPH_C32(0x618d7938), SPH_C32(0xb6481d50), SPH_C32(0xce87bf91), + SPH_C32(0xca84310a) }, + { SPH_C32(0xd73a0000), SPH_C32(0xdf5b0000), SPH_C32(0x18c4002e), + SPH_C32(0x2f3a0000), SPH_C32(0x29336c89), SPH_C32(0xce2d8979), + SPH_C32(0x01c916c8), SPH_C32(0xd14487a8), SPH_C32(0x2b930000), + SPH_C32(0x394a0000), SPH_C32(0x421d0072), SPH_C32(0xb6ed0000), + SPH_C32(0xad615743), SPH_C32(0x8650d9c9), SPH_C32(0xcdceb56b), + SPH_C32(0x51eac982) }, + { SPH_C32(0x01dd0000), SPH_C32(0x80a80000), SPH_C32(0xf4960048), + SPH_C32(0xa6000000), SPH_C32(0x90d57ea2), SPH_C32(0xd7e68c37), + SPH_C32(0x6612cffd), SPH_C32(0x2c94459e), SPH_C32(0x52500000), + SPH_C32(0x29540000), SPH_C32(0x6a61004e), SPH_C32(0xf0ff0000), + SPH_C32(0x9a317eec), SPH_C32(0x452341ce), SPH_C32(0xcf568fe5), + SPH_C32(0x5303130f) }, + { SPH_C32(0x06300000), SPH_C32(0x32f80000), SPH_C32(0x73e20042), + SPH_C32(0x310d0000), SPH_C32(0xd3a75d0c), SPH_C32(0x9f21e293), + SPH_C32(0x926aaddf), SPH_C32(0xbce1f450), SPH_C32(0xf0860000), + SPH_C32(0x8f220000), SPH_C32(0xa325005a), SPH_C32(0x1b5c0000), + SPH_C32(0x56dd5097), SPH_C32(0x753b8557), SPH_C32(0xcc1f851f), + SPH_C32(0xc86deb87) }, + { SPH_C32(0x89450000), SPH_C32(0x9f3c0000), SPH_C32(0x8b590066), + SPH_C32(0x5d4e0000), SPH_C32(0x618d7938), SPH_C32(0xb6481d50), + SPH_C32(0xce87bf91), SPH_C32(0xca84310a), SPH_C32(0x59920000), + SPH_C32(0xf2370000), SPH_C32(0x14e90042), SPH_C32(0xe5790000), + SPH_C32(0x0bcc361f), SPH_C32(0x30a2fa8d), SPH_C32(0x3b36cb7b), + SPH_C32(0x8bb5076c) }, + { SPH_C32(0x8ea80000), SPH_C32(0x2d6c0000), SPH_C32(0x0c2d006c), + SPH_C32(0xca430000), SPH_C32(0x22ff5a96), SPH_C32(0xfe8f73f4), + SPH_C32(0x3affddb3), SPH_C32(0x5af180c4), SPH_C32(0xfb440000), + SPH_C32(0x54410000), SPH_C32(0xddad0056), SPH_C32(0x0eda0000), + SPH_C32(0xc7201864), SPH_C32(0x00ba3e14), SPH_C32(0x387fc181), + SPH_C32(0x10dbffe4) }, + { SPH_C32(0x0a1f0000), SPH_C32(0x5bcb0000), SPH_C32(0x8a1e0044), + SPH_C32(0xb3860000), SPH_C32(0x01283651), SPH_C32(0xa2673774), + SPH_C32(0x92728b63), SPH_C32(0xf42251fd), SPH_C32(0xd10a0000), + SPH_C32(0xeda30000), SPH_C32(0x6b26006c), SPH_C32(0x1e370000), + SPH_C32(0xfa943185), SPH_C32(0x510c6bea), SPH_C32(0x93a3bb17), + SPH_C32(0x6da573f8) }, + { SPH_C32(0x0df20000), SPH_C32(0xe99b0000), SPH_C32(0x0d6a004e), + SPH_C32(0x248b0000), SPH_C32(0x425a15ff), SPH_C32(0xeaa059d0), + SPH_C32(0x660ae941), SPH_C32(0x6457e033), SPH_C32(0x73dc0000), + SPH_C32(0x4bd50000), SPH_C32(0xa2620078), SPH_C32(0xf5940000), + SPH_C32(0x36781ffe), SPH_C32(0x6114af73), SPH_C32(0x90eab1ed), + SPH_C32(0xf6cb8b70) }, + { SPH_C32(0x82870000), SPH_C32(0x445f0000), SPH_C32(0xf5d1006a), + SPH_C32(0x48c80000), SPH_C32(0xf07031cb), SPH_C32(0xc3c9a613), + SPH_C32(0x3ae7fb0f), SPH_C32(0x12322569), SPH_C32(0xdac80000), + SPH_C32(0x36c00000), SPH_C32(0x15ae0060), SPH_C32(0x0bb10000), + SPH_C32(0x6b697976), SPH_C32(0x248dd0a9), SPH_C32(0x67c3ff89), + SPH_C32(0xb513679b) }, + { SPH_C32(0x856a0000), SPH_C32(0xf60f0000), SPH_C32(0x72a50060), + SPH_C32(0xdfc50000), SPH_C32(0xb3021265), SPH_C32(0x8b0ec8b7), + SPH_C32(0xce9f992d), SPH_C32(0x824794a7), SPH_C32(0x781e0000), + SPH_C32(0x90b60000), SPH_C32(0xdcea0074), SPH_C32(0xe0120000), + SPH_C32(0xa785570d), SPH_C32(0x14951430), SPH_C32(0x648af573), + SPH_C32(0x2e7d9f13) } +}; + +static const sph_u32 T512_45[32][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0x1e6c0000), SPH_C32(0xc4420000), SPH_C32(0x8a2e0000), + SPH_C32(0xbcb6b800), SPH_C32(0x2c4413b6), SPH_C32(0x8bfdd3da), + SPH_C32(0x6a0c1bc8), SPH_C32(0xb99dc2eb), SPH_C32(0x92560000), + SPH_C32(0x1eda0000), SPH_C32(0xea510000), SPH_C32(0xe8b13000), + SPH_C32(0xa93556a5), SPH_C32(0xebfb6199), SPH_C32(0xb15c2254), + SPH_C32(0x33c5244f) }, + { SPH_C32(0x92560000), SPH_C32(0x1eda0000), SPH_C32(0xea510000), + SPH_C32(0xe8b13000), SPH_C32(0xa93556a5), SPH_C32(0xebfb6199), + SPH_C32(0xb15c2254), SPH_C32(0x33c5244f), SPH_C32(0x8c3a0000), + SPH_C32(0xda980000), SPH_C32(0x607f0000), SPH_C32(0x54078800), + SPH_C32(0x85714513), SPH_C32(0x6006b243), SPH_C32(0xdb50399c), + SPH_C32(0x8a58e6a4) }, + { SPH_C32(0x8c3a0000), SPH_C32(0xda980000), SPH_C32(0x607f0000), + SPH_C32(0x54078800), SPH_C32(0x85714513), SPH_C32(0x6006b243), + SPH_C32(0xdb50399c), SPH_C32(0x8a58e6a4), SPH_C32(0x1e6c0000), + SPH_C32(0xc4420000), SPH_C32(0x8a2e0000), SPH_C32(0xbcb6b800), + SPH_C32(0x2c4413b6), SPH_C32(0x8bfdd3da), SPH_C32(0x6a0c1bc8), + SPH_C32(0xb99dc2eb) }, + { SPH_C32(0x58430000), SPH_C32(0x807e0000), SPH_C32(0x78330001), + SPH_C32(0xc66b3800), SPH_C32(0xe7375cdc), SPH_C32(0x79ad3fdd), + SPH_C32(0xac73fe6f), SPH_C32(0x3a4479b1), SPH_C32(0x1d5a0000), + SPH_C32(0x2b720000), SPH_C32(0x488d0000), SPH_C32(0xaf611800), + SPH_C32(0x25cb2ec5), SPH_C32(0xc879bfd0), SPH_C32(0x81a20429), + SPH_C32(0x1e7536a6) }, + { SPH_C32(0x462f0000), SPH_C32(0x443c0000), SPH_C32(0xf21d0001), + SPH_C32(0x7add8000), SPH_C32(0xcb734f6a), SPH_C32(0xf250ec07), + SPH_C32(0xc67fe5a7), SPH_C32(0x83d9bb5a), SPH_C32(0x8f0c0000), + SPH_C32(0x35a80000), SPH_C32(0xa2dc0000), SPH_C32(0x47d02800), + SPH_C32(0x8cfe7860), SPH_C32(0x2382de49), SPH_C32(0x30fe267d), + SPH_C32(0x2db012e9) }, + { SPH_C32(0xca150000), SPH_C32(0x9ea40000), SPH_C32(0x92620001), + SPH_C32(0x2eda0800), SPH_C32(0x4e020a79), SPH_C32(0x92565e44), + SPH_C32(0x1d2fdc3b), SPH_C32(0x09815dfe), SPH_C32(0x91600000), + SPH_C32(0xf1ea0000), SPH_C32(0x28f20000), SPH_C32(0xfb669000), + SPH_C32(0xa0ba6bd6), SPH_C32(0xa87f0d93), SPH_C32(0x5af23db5), + SPH_C32(0x942dd002) }, + { SPH_C32(0xd4790000), SPH_C32(0x5ae60000), SPH_C32(0x184c0001), + SPH_C32(0x926cb000), SPH_C32(0x624619cf), SPH_C32(0x19ab8d9e), + SPH_C32(0x7723c7f3), SPH_C32(0xb01c9f15), SPH_C32(0x03360000), + SPH_C32(0xef300000), SPH_C32(0xc2a30000), SPH_C32(0x13d7a000), + SPH_C32(0x098f3d73), SPH_C32(0x43846c0a), SPH_C32(0xebae1fe1), + SPH_C32(0xa7e8f44d) }, + { SPH_C32(0x1d5a0000), SPH_C32(0x2b720000), SPH_C32(0x488d0000), + SPH_C32(0xaf611800), SPH_C32(0x25cb2ec5), SPH_C32(0xc879bfd0), + SPH_C32(0x81a20429), SPH_C32(0x1e7536a6), SPH_C32(0x45190000), + SPH_C32(0xab0c0000), SPH_C32(0x30be0001), SPH_C32(0x690a2000), + SPH_C32(0xc2fc7219), SPH_C32(0xb1d4800d), SPH_C32(0x2dd1fa46), + SPH_C32(0x24314f17) }, + { SPH_C32(0x03360000), SPH_C32(0xef300000), SPH_C32(0xc2a30000), + SPH_C32(0x13d7a000), SPH_C32(0x098f3d73), SPH_C32(0x43846c0a), + SPH_C32(0xebae1fe1), SPH_C32(0xa7e8f44d), SPH_C32(0xd74f0000), + SPH_C32(0xb5d60000), SPH_C32(0xdaef0001), SPH_C32(0x81bb1000), + SPH_C32(0x6bc924bc), SPH_C32(0x5a2fe194), SPH_C32(0x9c8dd812), + SPH_C32(0x17f46b58) }, + { SPH_C32(0x8f0c0000), SPH_C32(0x35a80000), SPH_C32(0xa2dc0000), + SPH_C32(0x47d02800), SPH_C32(0x8cfe7860), SPH_C32(0x2382de49), + SPH_C32(0x30fe267d), SPH_C32(0x2db012e9), SPH_C32(0xc9230000), + SPH_C32(0x71940000), SPH_C32(0x50c10001), SPH_C32(0x3d0da800), + SPH_C32(0x478d370a), SPH_C32(0xd1d2324e), SPH_C32(0xf681c3da), + SPH_C32(0xae69a9b3) }, + { SPH_C32(0x91600000), SPH_C32(0xf1ea0000), SPH_C32(0x28f20000), + SPH_C32(0xfb669000), SPH_C32(0xa0ba6bd6), SPH_C32(0xa87f0d93), + SPH_C32(0x5af23db5), SPH_C32(0x942dd002), SPH_C32(0x5b750000), + SPH_C32(0x6f4e0000), SPH_C32(0xba900001), SPH_C32(0xd5bc9800), + SPH_C32(0xeeb861af), SPH_C32(0x3a2953d7), SPH_C32(0x47dde18e), + SPH_C32(0x9dac8dfc) }, + { SPH_C32(0x45190000), SPH_C32(0xab0c0000), SPH_C32(0x30be0001), + SPH_C32(0x690a2000), SPH_C32(0xc2fc7219), SPH_C32(0xb1d4800d), + SPH_C32(0x2dd1fa46), SPH_C32(0x24314f17), SPH_C32(0x58430000), + SPH_C32(0x807e0000), SPH_C32(0x78330001), SPH_C32(0xc66b3800), + SPH_C32(0xe7375cdc), SPH_C32(0x79ad3fdd), SPH_C32(0xac73fe6f), + SPH_C32(0x3a4479b1) }, + { SPH_C32(0x5b750000), SPH_C32(0x6f4e0000), SPH_C32(0xba900001), + SPH_C32(0xd5bc9800), SPH_C32(0xeeb861af), SPH_C32(0x3a2953d7), + SPH_C32(0x47dde18e), SPH_C32(0x9dac8dfc), SPH_C32(0xca150000), + SPH_C32(0x9ea40000), SPH_C32(0x92620001), SPH_C32(0x2eda0800), + SPH_C32(0x4e020a79), SPH_C32(0x92565e44), SPH_C32(0x1d2fdc3b), + SPH_C32(0x09815dfe) }, + { SPH_C32(0xd74f0000), SPH_C32(0xb5d60000), SPH_C32(0xdaef0001), + SPH_C32(0x81bb1000), SPH_C32(0x6bc924bc), SPH_C32(0x5a2fe194), + SPH_C32(0x9c8dd812), SPH_C32(0x17f46b58), SPH_C32(0xd4790000), + SPH_C32(0x5ae60000), SPH_C32(0x184c0001), SPH_C32(0x926cb000), + SPH_C32(0x624619cf), SPH_C32(0x19ab8d9e), SPH_C32(0x7723c7f3), + SPH_C32(0xb01c9f15) }, + { SPH_C32(0xc9230000), SPH_C32(0x71940000), SPH_C32(0x50c10001), + SPH_C32(0x3d0da800), SPH_C32(0x478d370a), SPH_C32(0xd1d2324e), + SPH_C32(0xf681c3da), SPH_C32(0xae69a9b3), SPH_C32(0x462f0000), + SPH_C32(0x443c0000), SPH_C32(0xf21d0001), SPH_C32(0x7add8000), + SPH_C32(0xcb734f6a), SPH_C32(0xf250ec07), SPH_C32(0xc67fe5a7), + SPH_C32(0x83d9bb5a) }, + { SPH_C32(0xa53b0000), SPH_C32(0x14260000), SPH_C32(0x4e30001e), + SPH_C32(0x7cae0000), SPH_C32(0x8f9e0dd5), SPH_C32(0x78dfaa3d), + SPH_C32(0xf73168d8), SPH_C32(0x0b1b4946), SPH_C32(0x07ed0000), + SPH_C32(0xb2500000), SPH_C32(0x8774000a), SPH_C32(0x970d0000), + SPH_C32(0x437223ae), SPH_C32(0x48c76ea4), SPH_C32(0xf4786222), + SPH_C32(0x9075b1ce) }, + { SPH_C32(0xbb570000), SPH_C32(0xd0640000), SPH_C32(0xc41e001e), + SPH_C32(0xc018b800), SPH_C32(0xa3da1e63), SPH_C32(0xf32279e7), + SPH_C32(0x9d3d7310), SPH_C32(0xb2868bad), SPH_C32(0x95bb0000), + SPH_C32(0xac8a0000), SPH_C32(0x6d25000a), SPH_C32(0x7fbc3000), + SPH_C32(0xea47750b), SPH_C32(0xa33c0f3d), SPH_C32(0x45244076), + SPH_C32(0xa3b09581) }, + { SPH_C32(0x376d0000), SPH_C32(0x0afc0000), SPH_C32(0xa461001e), + SPH_C32(0x941f3000), SPH_C32(0x26ab5b70), SPH_C32(0x9324cba4), + SPH_C32(0x466d4a8c), SPH_C32(0x38de6d09), SPH_C32(0x8bd70000), + SPH_C32(0x68c80000), SPH_C32(0xe70b000a), SPH_C32(0xc30a8800), + SPH_C32(0xc60366bd), SPH_C32(0x28c1dce7), SPH_C32(0x2f285bbe), + SPH_C32(0x1a2d576a) }, + { SPH_C32(0x29010000), SPH_C32(0xcebe0000), SPH_C32(0x2e4f001e), + SPH_C32(0x28a98800), SPH_C32(0x0aef48c6), SPH_C32(0x18d9187e), + SPH_C32(0x2c615144), SPH_C32(0x8143afe2), SPH_C32(0x19810000), + SPH_C32(0x76120000), SPH_C32(0x0d5a000a), SPH_C32(0x2bbbb800), + SPH_C32(0x6f363018), SPH_C32(0xc33abd7e), SPH_C32(0x9e7479ea), + SPH_C32(0x29e87325) }, + { SPH_C32(0xfd780000), SPH_C32(0x94580000), SPH_C32(0x3603001f), + SPH_C32(0xbac53800), SPH_C32(0x68a95109), SPH_C32(0x017295e0), + SPH_C32(0x5b4296b7), SPH_C32(0x315f30f7), SPH_C32(0x1ab70000), + SPH_C32(0x99220000), SPH_C32(0xcff9000a), SPH_C32(0x386c1800), + SPH_C32(0x66b90d6b), SPH_C32(0x80bed174), SPH_C32(0x75da660b), + SPH_C32(0x8e008768) }, + { SPH_C32(0xe3140000), SPH_C32(0x501a0000), SPH_C32(0xbc2d001f), + SPH_C32(0x06738000), SPH_C32(0x44ed42bf), SPH_C32(0x8a8f463a), + SPH_C32(0x314e8d7f), SPH_C32(0x88c2f21c), SPH_C32(0x88e10000), + SPH_C32(0x87f80000), SPH_C32(0x25a8000a), SPH_C32(0xd0dd2800), + SPH_C32(0xcf8c5bce), SPH_C32(0x6b45b0ed), SPH_C32(0xc486445f), + SPH_C32(0xbdc5a327) }, + { SPH_C32(0x6f2e0000), SPH_C32(0x8a820000), SPH_C32(0xdc52001f), + SPH_C32(0x52740800), SPH_C32(0xc19c07ac), SPH_C32(0xea89f479), + SPH_C32(0xea1eb4e3), SPH_C32(0x029a14b8), SPH_C32(0x968d0000), + SPH_C32(0x43ba0000), SPH_C32(0xaf86000a), SPH_C32(0x6c6b9000), + SPH_C32(0xe3c84878), SPH_C32(0xe0b86337), SPH_C32(0xae8a5f97), + SPH_C32(0x045861cc) }, + { SPH_C32(0x71420000), SPH_C32(0x4ec00000), SPH_C32(0x567c001f), + SPH_C32(0xeec2b000), SPH_C32(0xedd8141a), SPH_C32(0x617427a3), + SPH_C32(0x8012af2b), SPH_C32(0xbb07d653), SPH_C32(0x04db0000), + SPH_C32(0x5d600000), SPH_C32(0x45d7000a), SPH_C32(0x84daa000), + SPH_C32(0x4afd1edd), SPH_C32(0x0b4302ae), SPH_C32(0x1fd67dc3), + SPH_C32(0x379d4583) }, + { SPH_C32(0xb8610000), SPH_C32(0x3f540000), SPH_C32(0x06bd001e), + SPH_C32(0xd3cf1800), SPH_C32(0xaa552310), SPH_C32(0xb0a615ed), + SPH_C32(0x76936cf1), SPH_C32(0x156e7fe0), SPH_C32(0x42f40000), + SPH_C32(0x195c0000), SPH_C32(0xb7ca000b), SPH_C32(0xfe072000), + SPH_C32(0x818e51b7), SPH_C32(0xf913eea9), SPH_C32(0xd9a99864), + SPH_C32(0xb444fed9) }, + { SPH_C32(0xa60d0000), SPH_C32(0xfb160000), SPH_C32(0x8c93001e), + SPH_C32(0x6f79a000), SPH_C32(0x861130a6), SPH_C32(0x3b5bc637), + SPH_C32(0x1c9f7739), SPH_C32(0xacf3bd0b), SPH_C32(0xd0a20000), + SPH_C32(0x07860000), SPH_C32(0x5d9b000b), SPH_C32(0x16b61000), + SPH_C32(0x28bb0712), SPH_C32(0x12e88f30), SPH_C32(0x68f5ba30), + SPH_C32(0x8781da96) }, + { SPH_C32(0x2a370000), SPH_C32(0x218e0000), SPH_C32(0xecec001e), + SPH_C32(0x3b7e2800), SPH_C32(0x036075b5), SPH_C32(0x5b5d7474), + SPH_C32(0xc7cf4ea5), SPH_C32(0x26ab5baf), SPH_C32(0xcece0000), + SPH_C32(0xc3c40000), SPH_C32(0xd7b5000b), SPH_C32(0xaa00a800), + SPH_C32(0x04ff14a4), SPH_C32(0x99155cea), SPH_C32(0x02f9a1f8), + SPH_C32(0x3e1c187d) }, + { SPH_C32(0x345b0000), SPH_C32(0xe5cc0000), SPH_C32(0x66c2001e), + SPH_C32(0x87c89000), SPH_C32(0x2f246603), SPH_C32(0xd0a0a7ae), + SPH_C32(0xadc3556d), SPH_C32(0x9f369944), SPH_C32(0x5c980000), + SPH_C32(0xdd1e0000), SPH_C32(0x3de4000b), SPH_C32(0x42b19800), + SPH_C32(0xadca4201), SPH_C32(0x72ee3d73), SPH_C32(0xb3a583ac), + SPH_C32(0x0dd93c32) }, + { SPH_C32(0xe0220000), SPH_C32(0xbf2a0000), SPH_C32(0x7e8e001f), + SPH_C32(0x15a42000), SPH_C32(0x4d627fcc), SPH_C32(0xc90b2a30), + SPH_C32(0xdae0929e), SPH_C32(0x2f2a0651), SPH_C32(0x5fae0000), + SPH_C32(0x322e0000), SPH_C32(0xff47000b), SPH_C32(0x51663800), + SPH_C32(0xa4457f72), SPH_C32(0x316a5179), SPH_C32(0x580b9c4d), + SPH_C32(0xaa31c87f) }, + { SPH_C32(0xfe4e0000), SPH_C32(0x7b680000), SPH_C32(0xf4a0001f), + SPH_C32(0xa9129800), SPH_C32(0x61266c7a), SPH_C32(0x42f6f9ea), + SPH_C32(0xb0ec8956), SPH_C32(0x96b7c4ba), SPH_C32(0xcdf80000), + SPH_C32(0x2cf40000), SPH_C32(0x1516000b), SPH_C32(0xb9d70800), + SPH_C32(0x0d7029d7), SPH_C32(0xda9130e0), SPH_C32(0xe957be19), + SPH_C32(0x99f4ec30) }, + { SPH_C32(0x72740000), SPH_C32(0xa1f00000), SPH_C32(0x94df001f), + SPH_C32(0xfd151000), SPH_C32(0xe4572969), SPH_C32(0x22f04ba9), + SPH_C32(0x6bbcb0ca), SPH_C32(0x1cef221e), SPH_C32(0xd3940000), + SPH_C32(0xe8b60000), SPH_C32(0x9f38000b), SPH_C32(0x0561b000), + SPH_C32(0x21343a61), SPH_C32(0x516ce33a), SPH_C32(0x835ba5d1), + SPH_C32(0x20692edb) }, + { SPH_C32(0x6c180000), SPH_C32(0x65b20000), SPH_C32(0x1ef1001f), + SPH_C32(0x41a3a800), SPH_C32(0xc8133adf), SPH_C32(0xa90d9873), + SPH_C32(0x01b0ab02), SPH_C32(0xa572e0f5), SPH_C32(0x41c20000), + SPH_C32(0xf66c0000), SPH_C32(0x7569000b), SPH_C32(0xedd08000), + SPH_C32(0x88016cc4), SPH_C32(0xba9782a3), SPH_C32(0x32078785), + SPH_C32(0x13ac0a94) } +}; + +static const sph_u32 T512_50[32][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0xf0c50000), SPH_C32(0x59230000), SPH_C32(0x45820000), + SPH_C32(0xe18d00c0), SPH_C32(0x3b6d0631), SPH_C32(0xc2ed5699), + SPH_C32(0xcbe0fe1c), SPH_C32(0x56a7b19f), SPH_C32(0x16ed0000), + SPH_C32(0x15680000), SPH_C32(0xedd70000), SPH_C32(0x325d0220), + SPH_C32(0xe30c3689), SPH_C32(0x5a4ae643), SPH_C32(0xe375f8a8), + SPH_C32(0x81fdf908) }, + { SPH_C32(0xb4310000), SPH_C32(0x77330000), SPH_C32(0xb15d0000), + SPH_C32(0x7fd004e0), SPH_C32(0x78a26138), SPH_C32(0xd116c35d), + SPH_C32(0xd256d489), SPH_C32(0x4e6f74de), SPH_C32(0xe3060000), + SPH_C32(0xbdc10000), SPH_C32(0x87130000), SPH_C32(0xbff20060), + SPH_C32(0x2eba0a1a), SPH_C32(0x8db53751), SPH_C32(0x73c5ab06), + SPH_C32(0x5bd61539) }, + { SPH_C32(0x44f40000), SPH_C32(0x2e100000), SPH_C32(0xf4df0000), + SPH_C32(0x9e5d0420), SPH_C32(0x43cf6709), SPH_C32(0x13fb95c4), + SPH_C32(0x19b62a95), SPH_C32(0x18c8c541), SPH_C32(0xf5eb0000), + SPH_C32(0xa8a90000), SPH_C32(0x6ac40000), SPH_C32(0x8daf0240), + SPH_C32(0xcdb63c93), SPH_C32(0xd7ffd112), SPH_C32(0x90b053ae), + SPH_C32(0xda2bec31) }, + { SPH_C32(0xe3060000), SPH_C32(0xbdc10000), SPH_C32(0x87130000), + SPH_C32(0xbff20060), SPH_C32(0x2eba0a1a), SPH_C32(0x8db53751), + SPH_C32(0x73c5ab06), SPH_C32(0x5bd61539), SPH_C32(0x57370000), + SPH_C32(0xcaf20000), SPH_C32(0x364e0000), SPH_C32(0xc0220480), + SPH_C32(0x56186b22), SPH_C32(0x5ca3f40c), SPH_C32(0xa1937f8f), + SPH_C32(0x15b961e7) }, + { SPH_C32(0x13c30000), SPH_C32(0xe4e20000), SPH_C32(0xc2910000), + SPH_C32(0x5e7f00a0), SPH_C32(0x15d70c2b), SPH_C32(0x4f5861c8), + SPH_C32(0xb825551a), SPH_C32(0x0d71a4a6), SPH_C32(0x41da0000), + SPH_C32(0xdf9a0000), SPH_C32(0xdb990000), SPH_C32(0xf27f06a0), + SPH_C32(0xb5145dab), SPH_C32(0x06e9124f), SPH_C32(0x42e68727), + SPH_C32(0x944498ef) }, + { SPH_C32(0x57370000), SPH_C32(0xcaf20000), SPH_C32(0x364e0000), + SPH_C32(0xc0220480), SPH_C32(0x56186b22), SPH_C32(0x5ca3f40c), + SPH_C32(0xa1937f8f), SPH_C32(0x15b961e7), SPH_C32(0xb4310000), + SPH_C32(0x77330000), SPH_C32(0xb15d0000), SPH_C32(0x7fd004e0), + SPH_C32(0x78a26138), SPH_C32(0xd116c35d), SPH_C32(0xd256d489), + SPH_C32(0x4e6f74de) }, + { SPH_C32(0xa7f20000), SPH_C32(0x93d10000), SPH_C32(0x73cc0000), + SPH_C32(0x21af0440), SPH_C32(0x6d756d13), SPH_C32(0x9e4ea295), + SPH_C32(0x6a738193), SPH_C32(0x431ed078), SPH_C32(0xa2dc0000), + SPH_C32(0x625b0000), SPH_C32(0x5c8a0000), SPH_C32(0x4d8d06c0), + SPH_C32(0x9bae57b1), SPH_C32(0x8b5c251e), SPH_C32(0x31232c21), + SPH_C32(0xcf928dd6) }, + { SPH_C32(0x02f20000), SPH_C32(0xa2810000), SPH_C32(0x873f0000), + SPH_C32(0xe36c7800), SPH_C32(0x1e1d74ef), SPH_C32(0x073d2bd6), + SPH_C32(0xc4c23237), SPH_C32(0x7f32259e), SPH_C32(0xbadd0000), + SPH_C32(0x13ad0000), SPH_C32(0xb7e70000), SPH_C32(0xf7282800), + SPH_C32(0xdf45144d), SPH_C32(0x361ac33a), SPH_C32(0xea5a8d14), + SPH_C32(0x2a2c18f0) }, + { SPH_C32(0xf2370000), SPH_C32(0xfba20000), SPH_C32(0xc2bd0000), + SPH_C32(0x02e178c0), SPH_C32(0x257072de), SPH_C32(0xc5d07d4f), + SPH_C32(0x0f22cc2b), SPH_C32(0x29959401), SPH_C32(0xac300000), + SPH_C32(0x06c50000), SPH_C32(0x5a300000), SPH_C32(0xc5752a20), + SPH_C32(0x3c4922c4), SPH_C32(0x6c502579), SPH_C32(0x092f75bc), + SPH_C32(0xabd1e1f8) }, + { SPH_C32(0xb6c30000), SPH_C32(0xd5b20000), SPH_C32(0x36620000), + SPH_C32(0x9cbc7ce0), SPH_C32(0x66bf15d7), SPH_C32(0xd62be88b), + SPH_C32(0x1694e6be), SPH_C32(0x315d5140), SPH_C32(0x59db0000), + SPH_C32(0xae6c0000), SPH_C32(0x30f40000), SPH_C32(0x48da2860), + SPH_C32(0xf1ff1e57), SPH_C32(0xbbaff46b), SPH_C32(0x999f2612), + SPH_C32(0x71fa0dc9) }, + { SPH_C32(0x46060000), SPH_C32(0x8c910000), SPH_C32(0x73e00000), + SPH_C32(0x7d317c20), SPH_C32(0x5dd213e6), SPH_C32(0x14c6be12), + SPH_C32(0xdd7418a2), SPH_C32(0x67fae0df), SPH_C32(0x4f360000), + SPH_C32(0xbb040000), SPH_C32(0xdd230000), SPH_C32(0x7a872a40), + SPH_C32(0x12f328de), SPH_C32(0xe1e51228), SPH_C32(0x7aeadeba), + SPH_C32(0xf007f4c1) }, + { SPH_C32(0xe1f40000), SPH_C32(0x1f400000), SPH_C32(0x002c0000), + SPH_C32(0x5c9e7860), SPH_C32(0x30a77ef5), SPH_C32(0x8a881c87), + SPH_C32(0xb7079931), SPH_C32(0x24e430a7), SPH_C32(0xedea0000), + SPH_C32(0xd95f0000), SPH_C32(0x81a90000), SPH_C32(0x370a2c80), + SPH_C32(0x895d7f6f), SPH_C32(0x6ab93736), SPH_C32(0x4bc9f29b), + SPH_C32(0x3f957917) }, + { SPH_C32(0x11310000), SPH_C32(0x46630000), SPH_C32(0x45ae0000), + SPH_C32(0xbd1378a0), SPH_C32(0x0bca78c4), SPH_C32(0x48654a1e), + SPH_C32(0x7ce7672d), SPH_C32(0x72438138), SPH_C32(0xfb070000), + SPH_C32(0xcc370000), SPH_C32(0x6c7e0000), SPH_C32(0x05572ea0), + SPH_C32(0x6a5149e6), SPH_C32(0x30f3d175), SPH_C32(0xa8bc0a33), + SPH_C32(0xbe68801f) }, + { SPH_C32(0x55c50000), SPH_C32(0x68730000), SPH_C32(0xb1710000), + SPH_C32(0x234e7c80), SPH_C32(0x48051fcd), SPH_C32(0x5b9edfda), + SPH_C32(0x65514db8), SPH_C32(0x6a8b4479), SPH_C32(0x0eec0000), + SPH_C32(0x649e0000), SPH_C32(0x06ba0000), SPH_C32(0x88f82ce0), + SPH_C32(0xa7e77575), SPH_C32(0xe70c0067), SPH_C32(0x380c599d), + SPH_C32(0x64436c2e) }, + { SPH_C32(0xa5000000), SPH_C32(0x31500000), SPH_C32(0xf4f30000), + SPH_C32(0xc2c37c40), SPH_C32(0x736819fc), SPH_C32(0x99738943), + SPH_C32(0xaeb1b3a4), SPH_C32(0x3c2cf5e6), SPH_C32(0x18010000), + SPH_C32(0x71f60000), SPH_C32(0xeb6d0000), SPH_C32(0xbaa52ec0), + SPH_C32(0x44eb43fc), SPH_C32(0xbd46e624), SPH_C32(0xdb79a135), + SPH_C32(0xe5be9526) }, + { SPH_C32(0xbadd0000), SPH_C32(0x13ad0000), SPH_C32(0xb7e70000), + SPH_C32(0xf7282800), SPH_C32(0xdf45144d), SPH_C32(0x361ac33a), + SPH_C32(0xea5a8d14), SPH_C32(0x2a2c18f0), SPH_C32(0xb82f0000), + SPH_C32(0xb12c0000), SPH_C32(0x30d80000), SPH_C32(0x14445000), + SPH_C32(0xc15860a2), SPH_C32(0x3127e8ec), SPH_C32(0x2e98bf23), + SPH_C32(0x551e3d6e) }, + { SPH_C32(0x4a180000), SPH_C32(0x4a8e0000), SPH_C32(0xf2650000), + SPH_C32(0x16a528c0), SPH_C32(0xe428127c), SPH_C32(0xf4f795a3), + SPH_C32(0x21ba7308), SPH_C32(0x7c8ba96f), SPH_C32(0xaec20000), + SPH_C32(0xa4440000), SPH_C32(0xdd0f0000), SPH_C32(0x26195220), + SPH_C32(0x2254562b), SPH_C32(0x6b6d0eaf), SPH_C32(0xcded478b), + SPH_C32(0xd4e3c466) }, + { SPH_C32(0x0eec0000), SPH_C32(0x649e0000), SPH_C32(0x06ba0000), + SPH_C32(0x88f82ce0), SPH_C32(0xa7e77575), SPH_C32(0xe70c0067), + SPH_C32(0x380c599d), SPH_C32(0x64436c2e), SPH_C32(0x5b290000), + SPH_C32(0x0ced0000), SPH_C32(0xb7cb0000), SPH_C32(0xabb65060), + SPH_C32(0xefe26ab8), SPH_C32(0xbc92dfbd), SPH_C32(0x5d5d1425), + SPH_C32(0x0ec82857) }, + { SPH_C32(0xfe290000), SPH_C32(0x3dbd0000), SPH_C32(0x43380000), + SPH_C32(0x69752c20), SPH_C32(0x9c8a7344), SPH_C32(0x25e156fe), + SPH_C32(0xf3eca781), SPH_C32(0x32e4ddb1), SPH_C32(0x4dc40000), + SPH_C32(0x19850000), SPH_C32(0x5a1c0000), SPH_C32(0x99eb5240), + SPH_C32(0x0cee5c31), SPH_C32(0xe6d839fe), SPH_C32(0xbe28ec8d), + SPH_C32(0x8f35d15f) }, + { SPH_C32(0x59db0000), SPH_C32(0xae6c0000), SPH_C32(0x30f40000), + SPH_C32(0x48da2860), SPH_C32(0xf1ff1e57), SPH_C32(0xbbaff46b), + SPH_C32(0x999f2612), SPH_C32(0x71fa0dc9), SPH_C32(0xef180000), + SPH_C32(0x7bde0000), SPH_C32(0x06960000), SPH_C32(0xd4665480), + SPH_C32(0x97400b80), SPH_C32(0x6d841ce0), SPH_C32(0x8f0bc0ac), + SPH_C32(0x40a75c89) }, + { SPH_C32(0xa91e0000), SPH_C32(0xf74f0000), SPH_C32(0x75760000), + SPH_C32(0xa95728a0), SPH_C32(0xca921866), SPH_C32(0x7942a2f2), + SPH_C32(0x527fd80e), SPH_C32(0x275dbc56), SPH_C32(0xf9f50000), + SPH_C32(0x6eb60000), SPH_C32(0xeb410000), SPH_C32(0xe63b56a0), + SPH_C32(0x744c3d09), SPH_C32(0x37cefaa3), SPH_C32(0x6c7e3804), + SPH_C32(0xc15aa581) }, + { SPH_C32(0xedea0000), SPH_C32(0xd95f0000), SPH_C32(0x81a90000), + SPH_C32(0x370a2c80), SPH_C32(0x895d7f6f), SPH_C32(0x6ab93736), + SPH_C32(0x4bc9f29b), SPH_C32(0x3f957917), SPH_C32(0x0c1e0000), + SPH_C32(0xc61f0000), SPH_C32(0x81850000), SPH_C32(0x6b9454e0), + SPH_C32(0xb9fa019a), SPH_C32(0xe0312bb1), SPH_C32(0xfcce6baa), + SPH_C32(0x1b7149b0) }, + { SPH_C32(0x1d2f0000), SPH_C32(0x807c0000), SPH_C32(0xc42b0000), + SPH_C32(0xd6872c40), SPH_C32(0xb230795e), SPH_C32(0xa85461af), + SPH_C32(0x80290c87), SPH_C32(0x6932c888), SPH_C32(0x1af30000), + SPH_C32(0xd3770000), SPH_C32(0x6c520000), SPH_C32(0x59c956c0), + SPH_C32(0x5af63713), SPH_C32(0xba7bcdf2), SPH_C32(0x1fbb9302), + SPH_C32(0x9a8cb0b8) }, + { SPH_C32(0xb82f0000), SPH_C32(0xb12c0000), SPH_C32(0x30d80000), + SPH_C32(0x14445000), SPH_C32(0xc15860a2), SPH_C32(0x3127e8ec), + SPH_C32(0x2e98bf23), SPH_C32(0x551e3d6e), SPH_C32(0x02f20000), + SPH_C32(0xa2810000), SPH_C32(0x873f0000), SPH_C32(0xe36c7800), + SPH_C32(0x1e1d74ef), SPH_C32(0x073d2bd6), SPH_C32(0xc4c23237), + SPH_C32(0x7f32259e) }, + { SPH_C32(0x48ea0000), SPH_C32(0xe80f0000), SPH_C32(0x755a0000), + SPH_C32(0xf5c950c0), SPH_C32(0xfa356693), SPH_C32(0xf3cabe75), + SPH_C32(0xe578413f), SPH_C32(0x03b98cf1), SPH_C32(0x141f0000), + SPH_C32(0xb7e90000), SPH_C32(0x6ae80000), SPH_C32(0xd1317a20), + SPH_C32(0xfd114266), SPH_C32(0x5d77cd95), SPH_C32(0x27b7ca9f), + SPH_C32(0xfecfdc96) }, + { SPH_C32(0x0c1e0000), SPH_C32(0xc61f0000), SPH_C32(0x81850000), + SPH_C32(0x6b9454e0), SPH_C32(0xb9fa019a), SPH_C32(0xe0312bb1), + SPH_C32(0xfcce6baa), SPH_C32(0x1b7149b0), SPH_C32(0xe1f40000), + SPH_C32(0x1f400000), SPH_C32(0x002c0000), SPH_C32(0x5c9e7860), + SPH_C32(0x30a77ef5), SPH_C32(0x8a881c87), SPH_C32(0xb7079931), + SPH_C32(0x24e430a7) }, + { SPH_C32(0xfcdb0000), SPH_C32(0x9f3c0000), SPH_C32(0xc4070000), + SPH_C32(0x8a195420), SPH_C32(0x829707ab), SPH_C32(0x22dc7d28), + SPH_C32(0x372e95b6), SPH_C32(0x4dd6f82f), SPH_C32(0xf7190000), + SPH_C32(0x0a280000), SPH_C32(0xedfb0000), SPH_C32(0x6ec37a40), + SPH_C32(0xd3ab487c), SPH_C32(0xd0c2fac4), SPH_C32(0x54726199), + SPH_C32(0xa519c9af) }, + { SPH_C32(0x5b290000), SPH_C32(0x0ced0000), SPH_C32(0xb7cb0000), + SPH_C32(0xabb65060), SPH_C32(0xefe26ab8), SPH_C32(0xbc92dfbd), + SPH_C32(0x5d5d1425), SPH_C32(0x0ec82857), SPH_C32(0x55c50000), + SPH_C32(0x68730000), SPH_C32(0xb1710000), SPH_C32(0x234e7c80), + SPH_C32(0x48051fcd), SPH_C32(0x5b9edfda), SPH_C32(0x65514db8), + SPH_C32(0x6a8b4479) }, + { SPH_C32(0xabec0000), SPH_C32(0x55ce0000), SPH_C32(0xf2490000), + SPH_C32(0x4a3b50a0), SPH_C32(0xd48f6c89), SPH_C32(0x7e7f8924), + SPH_C32(0x96bdea39), SPH_C32(0x586f99c8), SPH_C32(0x43280000), + SPH_C32(0x7d1b0000), SPH_C32(0x5ca60000), SPH_C32(0x11137ea0), + SPH_C32(0xab092944), SPH_C32(0x01d43999), SPH_C32(0x8624b510), + SPH_C32(0xeb76bd71) }, + { SPH_C32(0xef180000), SPH_C32(0x7bde0000), SPH_C32(0x06960000), + SPH_C32(0xd4665480), SPH_C32(0x97400b80), SPH_C32(0x6d841ce0), + SPH_C32(0x8f0bc0ac), SPH_C32(0x40a75c89), SPH_C32(0xb6c30000), + SPH_C32(0xd5b20000), SPH_C32(0x36620000), SPH_C32(0x9cbc7ce0), + SPH_C32(0x66bf15d7), SPH_C32(0xd62be88b), SPH_C32(0x1694e6be), + SPH_C32(0x315d5140) }, + { SPH_C32(0x1fdd0000), SPH_C32(0x22fd0000), SPH_C32(0x43140000), + SPH_C32(0x35eb5440), SPH_C32(0xac2d0db1), SPH_C32(0xaf694a79), + SPH_C32(0x44eb3eb0), SPH_C32(0x1600ed16), SPH_C32(0xa02e0000), + SPH_C32(0xc0da0000), SPH_C32(0xdbb50000), SPH_C32(0xaee17ec0), + SPH_C32(0x85b3235e), SPH_C32(0x8c610ec8), SPH_C32(0xf5e11e16), + SPH_C32(0xb0a0a848) } +}; + +static const sph_u32 T512_55[32][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0x5fa80000), SPH_C32(0x56030000), SPH_C32(0x43ae0000), + SPH_C32(0x64f30013), SPH_C32(0x257e86bf), SPH_C32(0x1311944e), + SPH_C32(0x541e95bf), SPH_C32(0x8ea4db69), SPH_C32(0x00440000), + SPH_C32(0x7f480000), SPH_C32(0xda7c0000), SPH_C32(0x2a230001), + SPH_C32(0x3badc9cc), SPH_C32(0xa9b69c87), SPH_C32(0x030a9e60), + SPH_C32(0xbe0a679e) }, + { SPH_C32(0x00440000), SPH_C32(0x7f480000), SPH_C32(0xda7c0000), + SPH_C32(0x2a230001), SPH_C32(0x3badc9cc), SPH_C32(0xa9b69c87), + SPH_C32(0x030a9e60), SPH_C32(0xbe0a679e), SPH_C32(0x5fec0000), + SPH_C32(0x294b0000), SPH_C32(0x99d20000), SPH_C32(0x4ed00012), + SPH_C32(0x1ed34f73), SPH_C32(0xbaa708c9), SPH_C32(0x57140bdf), + SPH_C32(0x30aebcf7) }, + { SPH_C32(0x5fec0000), SPH_C32(0x294b0000), SPH_C32(0x99d20000), + SPH_C32(0x4ed00012), SPH_C32(0x1ed34f73), SPH_C32(0xbaa708c9), + SPH_C32(0x57140bdf), SPH_C32(0x30aebcf7), SPH_C32(0x5fa80000), + SPH_C32(0x56030000), SPH_C32(0x43ae0000), SPH_C32(0x64f30013), + SPH_C32(0x257e86bf), SPH_C32(0x1311944e), SPH_C32(0x541e95bf), + SPH_C32(0x8ea4db69) }, + { SPH_C32(0xee930000), SPH_C32(0xd6070000), SPH_C32(0x92c10000), + SPH_C32(0x2b9801e0), SPH_C32(0x9451287c), SPH_C32(0x3b6cfb57), + SPH_C32(0x45312374), SPH_C32(0x201f6a64), SPH_C32(0x7b280000), + SPH_C32(0x57420000), SPH_C32(0xa9e50000), SPH_C32(0x634300a0), + SPH_C32(0x9edb442f), SPH_C32(0x6d9995bb), SPH_C32(0x27f83b03), + SPH_C32(0xc7ff60f0) }, + { SPH_C32(0xb13b0000), SPH_C32(0x80040000), SPH_C32(0xd16f0000), + SPH_C32(0x4f6b01f3), SPH_C32(0xb12faec3), SPH_C32(0x287d6f19), + SPH_C32(0x112fb6cb), SPH_C32(0xaebbb10d), SPH_C32(0x7b6c0000), + SPH_C32(0x280a0000), SPH_C32(0x73990000), SPH_C32(0x496000a1), + SPH_C32(0xa5768de3), SPH_C32(0xc42f093c), SPH_C32(0x24f2a563), + SPH_C32(0x79f5076e) }, + { SPH_C32(0xeed70000), SPH_C32(0xa94f0000), SPH_C32(0x48bd0000), + SPH_C32(0x01bb01e1), SPH_C32(0xaffce1b0), SPH_C32(0x92da67d0), + SPH_C32(0x463bbd14), SPH_C32(0x9e150dfa), SPH_C32(0x24c40000), + SPH_C32(0x7e090000), SPH_C32(0x30370000), SPH_C32(0x2d9300b2), + SPH_C32(0x80080b5c), SPH_C32(0xd73e9d72), SPH_C32(0x70ec30dc), + SPH_C32(0xf751dc07) }, + { SPH_C32(0xb17f0000), SPH_C32(0xff4c0000), SPH_C32(0x0b130000), + SPH_C32(0x654801f2), SPH_C32(0x8a82670f), SPH_C32(0x81cbf39e), + SPH_C32(0x122528ab), SPH_C32(0x10b1d693), SPH_C32(0x24800000), + SPH_C32(0x01410000), SPH_C32(0xea4b0000), SPH_C32(0x07b000b3), + SPH_C32(0xbba5c290), SPH_C32(0x7e8801f5), SPH_C32(0x73e6aebc), + SPH_C32(0x495bbb99) }, + { SPH_C32(0x7b280000), SPH_C32(0x57420000), SPH_C32(0xa9e50000), + SPH_C32(0x634300a0), SPH_C32(0x9edb442f), SPH_C32(0x6d9995bb), + SPH_C32(0x27f83b03), SPH_C32(0xc7ff60f0), SPH_C32(0x95bb0000), + SPH_C32(0x81450000), SPH_C32(0x3b240000), SPH_C32(0x48db0140), + SPH_C32(0x0a8a6c53), SPH_C32(0x56f56eec), SPH_C32(0x62c91877), + SPH_C32(0xe7e00a94) }, + { SPH_C32(0x24800000), SPH_C32(0x01410000), SPH_C32(0xea4b0000), + SPH_C32(0x07b000b3), SPH_C32(0xbba5c290), SPH_C32(0x7e8801f5), + SPH_C32(0x73e6aebc), SPH_C32(0x495bbb99), SPH_C32(0x95ff0000), + SPH_C32(0xfe0d0000), SPH_C32(0xe1580000), SPH_C32(0x62f80141), + SPH_C32(0x3127a59f), SPH_C32(0xff43f26b), SPH_C32(0x61c38617), + SPH_C32(0x59ea6d0a) }, + { SPH_C32(0x7b6c0000), SPH_C32(0x280a0000), SPH_C32(0x73990000), + SPH_C32(0x496000a1), SPH_C32(0xa5768de3), SPH_C32(0xc42f093c), + SPH_C32(0x24f2a563), SPH_C32(0x79f5076e), SPH_C32(0xca570000), + SPH_C32(0xa80e0000), SPH_C32(0xa2f60000), SPH_C32(0x060b0152), + SPH_C32(0x14592320), SPH_C32(0xec526625), SPH_C32(0x35dd13a8), + SPH_C32(0xd74eb663) }, + { SPH_C32(0x24c40000), SPH_C32(0x7e090000), SPH_C32(0x30370000), + SPH_C32(0x2d9300b2), SPH_C32(0x80080b5c), SPH_C32(0xd73e9d72), + SPH_C32(0x70ec30dc), SPH_C32(0xf751dc07), SPH_C32(0xca130000), + SPH_C32(0xd7460000), SPH_C32(0x788a0000), SPH_C32(0x2c280153), + SPH_C32(0x2ff4eaec), SPH_C32(0x45e4faa2), SPH_C32(0x36d78dc8), + SPH_C32(0x6944d1fd) }, + { SPH_C32(0x95bb0000), SPH_C32(0x81450000), SPH_C32(0x3b240000), + SPH_C32(0x48db0140), SPH_C32(0x0a8a6c53), SPH_C32(0x56f56eec), + SPH_C32(0x62c91877), SPH_C32(0xe7e00a94), SPH_C32(0xee930000), + SPH_C32(0xd6070000), SPH_C32(0x92c10000), SPH_C32(0x2b9801e0), + SPH_C32(0x9451287c), SPH_C32(0x3b6cfb57), SPH_C32(0x45312374), + SPH_C32(0x201f6a64) }, + { SPH_C32(0xca130000), SPH_C32(0xd7460000), SPH_C32(0x788a0000), + SPH_C32(0x2c280153), SPH_C32(0x2ff4eaec), SPH_C32(0x45e4faa2), + SPH_C32(0x36d78dc8), SPH_C32(0x6944d1fd), SPH_C32(0xeed70000), + SPH_C32(0xa94f0000), SPH_C32(0x48bd0000), SPH_C32(0x01bb01e1), + SPH_C32(0xaffce1b0), SPH_C32(0x92da67d0), SPH_C32(0x463bbd14), + SPH_C32(0x9e150dfa) }, + { SPH_C32(0x95ff0000), SPH_C32(0xfe0d0000), SPH_C32(0xe1580000), + SPH_C32(0x62f80141), SPH_C32(0x3127a59f), SPH_C32(0xff43f26b), + SPH_C32(0x61c38617), SPH_C32(0x59ea6d0a), SPH_C32(0xb17f0000), + SPH_C32(0xff4c0000), SPH_C32(0x0b130000), SPH_C32(0x654801f2), + SPH_C32(0x8a82670f), SPH_C32(0x81cbf39e), SPH_C32(0x122528ab), + SPH_C32(0x10b1d693) }, + { SPH_C32(0xca570000), SPH_C32(0xa80e0000), SPH_C32(0xa2f60000), + SPH_C32(0x060b0152), SPH_C32(0x14592320), SPH_C32(0xec526625), + SPH_C32(0x35dd13a8), SPH_C32(0xd74eb663), SPH_C32(0xb13b0000), + SPH_C32(0x80040000), SPH_C32(0xd16f0000), SPH_C32(0x4f6b01f3), + SPH_C32(0xb12faec3), SPH_C32(0x287d6f19), SPH_C32(0x112fb6cb), + SPH_C32(0xaebbb10d) }, + { SPH_C32(0xe6280000), SPH_C32(0x4c4b0000), SPH_C32(0xa8550000), + SPH_C32(0xd3d002e0), SPH_C32(0xd86130b8), SPH_C32(0x98a7b0da), + SPH_C32(0x289506b4), SPH_C32(0xd75a4897), SPH_C32(0xf0c50000), + SPH_C32(0x59230000), SPH_C32(0x45820000), SPH_C32(0xe18d00c0), + SPH_C32(0x3b6d0631), SPH_C32(0xc2ed5699), SPH_C32(0xcbe0fe1c), + SPH_C32(0x56a7b19f) }, + { SPH_C32(0xb9800000), SPH_C32(0x1a480000), SPH_C32(0xebfb0000), + SPH_C32(0xb72302f3), SPH_C32(0xfd1fb607), SPH_C32(0x8bb62494), + SPH_C32(0x7c8b930b), SPH_C32(0x59fe93fe), SPH_C32(0xf0810000), + SPH_C32(0x266b0000), SPH_C32(0x9ffe0000), SPH_C32(0xcbae00c1), + SPH_C32(0x00c0cffd), SPH_C32(0x6b5bca1e), SPH_C32(0xc8ea607c), + SPH_C32(0xe8add601) }, + { SPH_C32(0xe66c0000), SPH_C32(0x33030000), SPH_C32(0x72290000), + SPH_C32(0xf9f302e1), SPH_C32(0xe3ccf974), SPH_C32(0x31112c5d), + SPH_C32(0x2b9f98d4), SPH_C32(0x69502f09), SPH_C32(0xaf290000), + SPH_C32(0x70680000), SPH_C32(0xdc500000), SPH_C32(0xaf5d00d2), + SPH_C32(0x25be4942), SPH_C32(0x784a5e50), SPH_C32(0x9cf4f5c3), + SPH_C32(0x66090d68) }, + { SPH_C32(0xb9c40000), SPH_C32(0x65000000), SPH_C32(0x31870000), + SPH_C32(0x9d0002f2), SPH_C32(0xc6b27fcb), SPH_C32(0x2200b813), + SPH_C32(0x7f810d6b), SPH_C32(0xe7f4f460), SPH_C32(0xaf6d0000), + SPH_C32(0x0f200000), SPH_C32(0x062c0000), SPH_C32(0x857e00d3), + SPH_C32(0x1e13808e), SPH_C32(0xd1fcc2d7), SPH_C32(0x9ffe6ba3), + SPH_C32(0xd8036af6) }, + { SPH_C32(0x08bb0000), SPH_C32(0x9a4c0000), SPH_C32(0x3a940000), + SPH_C32(0xf8480300), SPH_C32(0x4c3018c4), SPH_C32(0xa3cb4b8d), + SPH_C32(0x6da425c0), SPH_C32(0xf74522f3), SPH_C32(0x8bed0000), + SPH_C32(0x0e610000), SPH_C32(0xec670000), SPH_C32(0x82ce0060), + SPH_C32(0xa5b6421e), SPH_C32(0xaf74c322), SPH_C32(0xec18c51f), + SPH_C32(0x9158d16f) }, + { SPH_C32(0x57130000), SPH_C32(0xcc4f0000), SPH_C32(0x793a0000), + SPH_C32(0x9cbb0313), SPH_C32(0x694e9e7b), SPH_C32(0xb0dadfc3), + SPH_C32(0x39bab07f), SPH_C32(0x79e1f99a), SPH_C32(0x8ba90000), + SPH_C32(0x71290000), SPH_C32(0x361b0000), SPH_C32(0xa8ed0061), + SPH_C32(0x9e1b8bd2), SPH_C32(0x06c25fa5), SPH_C32(0xef125b7f), + SPH_C32(0x2f52b6f1) }, + { SPH_C32(0x08ff0000), SPH_C32(0xe5040000), SPH_C32(0xe0e80000), + SPH_C32(0xd26b0301), SPH_C32(0x779dd108), SPH_C32(0x0a7dd70a), + SPH_C32(0x6eaebba0), SPH_C32(0x494f456d), SPH_C32(0xd4010000), + SPH_C32(0x272a0000), SPH_C32(0x75b50000), SPH_C32(0xcc1e0072), + SPH_C32(0xbb650d6d), SPH_C32(0x15d3cbeb), SPH_C32(0xbb0ccec0), + SPH_C32(0xa1f66d98) }, + { SPH_C32(0x57570000), SPH_C32(0xb3070000), SPH_C32(0xa3460000), + SPH_C32(0xb6980312), SPH_C32(0x52e357b7), SPH_C32(0x196c4344), + SPH_C32(0x3ab02e1f), SPH_C32(0xc7eb9e04), SPH_C32(0xd4450000), + SPH_C32(0x58620000), SPH_C32(0xafc90000), SPH_C32(0xe63d0073), + SPH_C32(0x80c8c4a1), SPH_C32(0xbc65576c), SPH_C32(0xb80650a0), + SPH_C32(0x1ffc0a06) }, + { SPH_C32(0x9d000000), SPH_C32(0x1b090000), SPH_C32(0x01b00000), + SPH_C32(0xb0930240), SPH_C32(0x46ba7497), SPH_C32(0xf53e2561), + SPH_C32(0x0f6d3db7), SPH_C32(0x10a52867), SPH_C32(0x657e0000), + SPH_C32(0xd8660000), SPH_C32(0x7ea60000), SPH_C32(0xa9560180), + SPH_C32(0x31e76a62), SPH_C32(0x94183875), SPH_C32(0xa929e66b), + SPH_C32(0xb147bb0b) }, + { SPH_C32(0xc2a80000), SPH_C32(0x4d0a0000), SPH_C32(0x421e0000), + SPH_C32(0xd4600253), SPH_C32(0x63c4f228), SPH_C32(0xe62fb12f), + SPH_C32(0x5b73a808), SPH_C32(0x9e01f30e), SPH_C32(0x653a0000), + SPH_C32(0xa72e0000), SPH_C32(0xa4da0000), SPH_C32(0x83750181), + SPH_C32(0x0a4aa3ae), SPH_C32(0x3daea4f2), SPH_C32(0xaa23780b), + SPH_C32(0x0f4ddc95) }, + { SPH_C32(0x9d440000), SPH_C32(0x64410000), SPH_C32(0xdbcc0000), + SPH_C32(0x9ab00241), SPH_C32(0x7d17bd5b), SPH_C32(0x5c88b9e6), + SPH_C32(0x0c67a3d7), SPH_C32(0xaeaf4ff9), SPH_C32(0x3a920000), + SPH_C32(0xf12d0000), SPH_C32(0xe7740000), SPH_C32(0xe7860192), + SPH_C32(0x2f342511), SPH_C32(0x2ebf30bc), SPH_C32(0xfe3dedb4), + SPH_C32(0x81e907fc) }, + { SPH_C32(0xc2ec0000), SPH_C32(0x32420000), SPH_C32(0x98620000), + SPH_C32(0xfe430252), SPH_C32(0x58693be4), SPH_C32(0x4f992da8), + SPH_C32(0x58793668), SPH_C32(0x200b9490), SPH_C32(0x3ad60000), + SPH_C32(0x8e650000), SPH_C32(0x3d080000), SPH_C32(0xcda50193), + SPH_C32(0x1499ecdd), SPH_C32(0x8709ac3b), SPH_C32(0xfd3773d4), + SPH_C32(0x3fe36062) }, + { SPH_C32(0x73930000), SPH_C32(0xcd0e0000), SPH_C32(0x93710000), + SPH_C32(0x9b0b03a0), SPH_C32(0xd2eb5ceb), SPH_C32(0xce52de36), + SPH_C32(0x4a5c1ec3), SPH_C32(0x30ba4203), SPH_C32(0x1e560000), + SPH_C32(0x8f240000), SPH_C32(0xd7430000), SPH_C32(0xca150120), + SPH_C32(0xaf3c2e4d), SPH_C32(0xf981adce), SPH_C32(0x8ed1dd68), + SPH_C32(0x76b8dbfb) }, + { SPH_C32(0x2c3b0000), SPH_C32(0x9b0d0000), SPH_C32(0xd0df0000), + SPH_C32(0xfff803b3), SPH_C32(0xf795da54), SPH_C32(0xdd434a78), + SPH_C32(0x1e428b7c), SPH_C32(0xbe1e996a), SPH_C32(0x1e120000), + SPH_C32(0xf06c0000), SPH_C32(0x0d3f0000), SPH_C32(0xe0360121), + SPH_C32(0x9491e781), SPH_C32(0x50373149), SPH_C32(0x8ddb4308), + SPH_C32(0xc8b2bc65) }, + { SPH_C32(0x73d70000), SPH_C32(0xb2460000), SPH_C32(0x490d0000), + SPH_C32(0xb12803a1), SPH_C32(0xe9469527), SPH_C32(0x67e442b1), + SPH_C32(0x495680a3), SPH_C32(0x8eb0259d), SPH_C32(0x41ba0000), + SPH_C32(0xa66f0000), SPH_C32(0x4e910000), SPH_C32(0x84c50132), + SPH_C32(0xb1ef613e), SPH_C32(0x4326a507), SPH_C32(0xd9c5d6b7), + SPH_C32(0x4616670c) }, + { SPH_C32(0x2c7f0000), SPH_C32(0xe4450000), SPH_C32(0x0aa30000), + SPH_C32(0xd5db03b2), SPH_C32(0xcc381398), SPH_C32(0x74f5d6ff), + SPH_C32(0x1d48151c), SPH_C32(0x0014fef4), SPH_C32(0x41fe0000), + SPH_C32(0xd9270000), SPH_C32(0x94ed0000), SPH_C32(0xaee60133), + SPH_C32(0x8a42a8f2), SPH_C32(0xea903980), SPH_C32(0xdacf48d7), + SPH_C32(0xf81c0092) } +}; + +static const sph_u32 T512_60[16][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0x033d0000), SPH_C32(0x08b30000), SPH_C32(0xf33a0000), + SPH_C32(0x3ac20007), SPH_C32(0x51298a50), SPH_C32(0x6b6e661f), + SPH_C32(0x0ea5cfe3), SPH_C32(0xe6da7ffe), SPH_C32(0xa8da0000), + SPH_C32(0x96be0000), SPH_C32(0x5c1d0000), SPH_C32(0x07da0002), + SPH_C32(0x7d669583), SPH_C32(0x1f98708a), SPH_C32(0xbb668808), + SPH_C32(0xda878000) }, + { SPH_C32(0xa8da0000), SPH_C32(0x96be0000), SPH_C32(0x5c1d0000), + SPH_C32(0x07da0002), SPH_C32(0x7d669583), SPH_C32(0x1f98708a), + SPH_C32(0xbb668808), SPH_C32(0xda878000), SPH_C32(0xabe70000), + SPH_C32(0x9e0d0000), SPH_C32(0xaf270000), SPH_C32(0x3d180005), + SPH_C32(0x2c4f1fd3), SPH_C32(0x74f61695), SPH_C32(0xb5c347eb), + SPH_C32(0x3c5dfffe) }, + { SPH_C32(0xabe70000), SPH_C32(0x9e0d0000), SPH_C32(0xaf270000), + SPH_C32(0x3d180005), SPH_C32(0x2c4f1fd3), SPH_C32(0x74f61695), + SPH_C32(0xb5c347eb), SPH_C32(0x3c5dfffe), SPH_C32(0x033d0000), + SPH_C32(0x08b30000), SPH_C32(0xf33a0000), SPH_C32(0x3ac20007), + SPH_C32(0x51298a50), SPH_C32(0x6b6e661f), SPH_C32(0x0ea5cfe3), + SPH_C32(0xe6da7ffe) }, + { SPH_C32(0x01930000), SPH_C32(0xe7820000), SPH_C32(0xedfb0000), + SPH_C32(0xcf0c000b), SPH_C32(0x8dd08d58), SPH_C32(0xbca3b42e), + SPH_C32(0x063661e1), SPH_C32(0x536f9e7b), SPH_C32(0x92280000), + SPH_C32(0xdc850000), SPH_C32(0x57fa0000), SPH_C32(0x56dc0003), + SPH_C32(0xbae92316), SPH_C32(0x5aefa30c), SPH_C32(0x90cef752), + SPH_C32(0x7b1675d7) }, + { SPH_C32(0x02ae0000), SPH_C32(0xef310000), SPH_C32(0x1ec10000), + SPH_C32(0xf5ce000c), SPH_C32(0xdcf90708), SPH_C32(0xd7cdd231), + SPH_C32(0x0893ae02), SPH_C32(0xb5b5e185), SPH_C32(0x3af20000), + SPH_C32(0x4a3b0000), SPH_C32(0x0be70000), SPH_C32(0x51060001), + SPH_C32(0xc78fb695), SPH_C32(0x4577d386), SPH_C32(0x2ba87f5a), + SPH_C32(0xa191f5d7) }, + { SPH_C32(0xa9490000), SPH_C32(0x713c0000), SPH_C32(0xb1e60000), + SPH_C32(0xc8d60009), SPH_C32(0xf0b618db), SPH_C32(0xa33bc4a4), + SPH_C32(0xbd50e9e9), SPH_C32(0x89e81e7b), SPH_C32(0x39cf0000), + SPH_C32(0x42880000), SPH_C32(0xf8dd0000), SPH_C32(0x6bc40006), + SPH_C32(0x96a63cc5), SPH_C32(0x2e19b599), SPH_C32(0x250db0b9), + SPH_C32(0x474b8a29) }, + { SPH_C32(0xaa740000), SPH_C32(0x798f0000), SPH_C32(0x42dc0000), + SPH_C32(0xf214000e), SPH_C32(0xa19f928b), SPH_C32(0xc855a2bb), + SPH_C32(0xb3f5260a), SPH_C32(0x6f326185), SPH_C32(0x91150000), + SPH_C32(0xd4360000), SPH_C32(0xa4c00000), SPH_C32(0x6c1e0004), + SPH_C32(0xebc0a946), SPH_C32(0x3181c513), SPH_C32(0x9e6b38b1), + SPH_C32(0x9dcc0a29) }, + { SPH_C32(0x92280000), SPH_C32(0xdc850000), SPH_C32(0x57fa0000), + SPH_C32(0x56dc0003), SPH_C32(0xbae92316), SPH_C32(0x5aefa30c), + SPH_C32(0x90cef752), SPH_C32(0x7b1675d7), SPH_C32(0x93bb0000), + SPH_C32(0x3b070000), SPH_C32(0xba010000), SPH_C32(0x99d00008), + SPH_C32(0x3739ae4e), SPH_C32(0xe64c1722), SPH_C32(0x96f896b3), + SPH_C32(0x2879ebac) }, + { SPH_C32(0x91150000), SPH_C32(0xd4360000), SPH_C32(0xa4c00000), + SPH_C32(0x6c1e0004), SPH_C32(0xebc0a946), SPH_C32(0x3181c513), + SPH_C32(0x9e6b38b1), SPH_C32(0x9dcc0a29), SPH_C32(0x3b610000), + SPH_C32(0xadb90000), SPH_C32(0xe61c0000), SPH_C32(0x9e0a000a), + SPH_C32(0x4a5f3bcd), SPH_C32(0xf9d467a8), SPH_C32(0x2d9e1ebb), + SPH_C32(0xf2fe6bac) }, + { SPH_C32(0x3af20000), SPH_C32(0x4a3b0000), SPH_C32(0x0be70000), + SPH_C32(0x51060001), SPH_C32(0xc78fb695), SPH_C32(0x4577d386), + SPH_C32(0x2ba87f5a), SPH_C32(0xa191f5d7), SPH_C32(0x385c0000), + SPH_C32(0xa50a0000), SPH_C32(0x15260000), SPH_C32(0xa4c8000d), + SPH_C32(0x1b76b19d), SPH_C32(0x92ba01b7), SPH_C32(0x233bd158), + SPH_C32(0x14241452) }, + { SPH_C32(0x39cf0000), SPH_C32(0x42880000), SPH_C32(0xf8dd0000), + SPH_C32(0x6bc40006), SPH_C32(0x96a63cc5), SPH_C32(0x2e19b599), + SPH_C32(0x250db0b9), SPH_C32(0x474b8a29), SPH_C32(0x90860000), + SPH_C32(0x33b40000), SPH_C32(0x493b0000), SPH_C32(0xa312000f), + SPH_C32(0x6610241e), SPH_C32(0x8d22713d), SPH_C32(0x985d5950), + SPH_C32(0xcea39452) }, + { SPH_C32(0x93bb0000), SPH_C32(0x3b070000), SPH_C32(0xba010000), + SPH_C32(0x99d00008), SPH_C32(0x3739ae4e), SPH_C32(0xe64c1722), + SPH_C32(0x96f896b3), SPH_C32(0x2879ebac), SPH_C32(0x01930000), + SPH_C32(0xe7820000), SPH_C32(0xedfb0000), SPH_C32(0xcf0c000b), + SPH_C32(0x8dd08d58), SPH_C32(0xbca3b42e), SPH_C32(0x063661e1), + SPH_C32(0x536f9e7b) }, + { SPH_C32(0x90860000), SPH_C32(0x33b40000), SPH_C32(0x493b0000), + SPH_C32(0xa312000f), SPH_C32(0x6610241e), SPH_C32(0x8d22713d), + SPH_C32(0x985d5950), SPH_C32(0xcea39452), SPH_C32(0xa9490000), + SPH_C32(0x713c0000), SPH_C32(0xb1e60000), SPH_C32(0xc8d60009), + SPH_C32(0xf0b618db), SPH_C32(0xa33bc4a4), SPH_C32(0xbd50e9e9), + SPH_C32(0x89e81e7b) }, + { SPH_C32(0x3b610000), SPH_C32(0xadb90000), SPH_C32(0xe61c0000), + SPH_C32(0x9e0a000a), SPH_C32(0x4a5f3bcd), SPH_C32(0xf9d467a8), + SPH_C32(0x2d9e1ebb), SPH_C32(0xf2fe6bac), SPH_C32(0xaa740000), + SPH_C32(0x798f0000), SPH_C32(0x42dc0000), SPH_C32(0xf214000e), + SPH_C32(0xa19f928b), SPH_C32(0xc855a2bb), SPH_C32(0xb3f5260a), + SPH_C32(0x6f326185) }, + { SPH_C32(0x385c0000), SPH_C32(0xa50a0000), SPH_C32(0x15260000), + SPH_C32(0xa4c8000d), SPH_C32(0x1b76b19d), SPH_C32(0x92ba01b7), + SPH_C32(0x233bd158), SPH_C32(0x14241452), SPH_C32(0x02ae0000), + SPH_C32(0xef310000), SPH_C32(0x1ec10000), SPH_C32(0xf5ce000c), + SPH_C32(0xdcf90708), SPH_C32(0xd7cdd231), SPH_C32(0x0893ae02), + SPH_C32(0xb5b5e185) } +}; + +#define INPUT_BIG do { \ + unsigned acc = buf[0]; \ + const sph_u32 *rp; \ + rp = &T512_0[acc >> 3][0]; \ + m0 = rp[0]; \ + m1 = rp[1]; \ + m2 = rp[2]; \ + m3 = rp[3]; \ + m4 = rp[4]; \ + m5 = rp[5]; \ + m6 = rp[6]; \ + m7 = rp[7]; \ + m8 = rp[8]; \ + m9 = rp[9]; \ + mA = rp[10]; \ + mB = rp[11]; \ + mC = rp[12]; \ + mD = rp[13]; \ + mE = rp[14]; \ + mF = rp[15]; \ + acc = (acc << 8) | buf[1]; \ + rp = &T512_5[(acc >> 6) & 0x1f][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + m8 ^= rp[8]; \ + m9 ^= rp[9]; \ + mA ^= rp[10]; \ + mB ^= rp[11]; \ + mC ^= rp[12]; \ + mD ^= rp[13]; \ + mE ^= rp[14]; \ + mF ^= rp[15]; \ + rp = &T512_10[(acc >> 1) & 0x1f][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + m8 ^= rp[8]; \ + m9 ^= rp[9]; \ + mA ^= rp[10]; \ + mB ^= rp[11]; \ + mC ^= rp[12]; \ + mD ^= rp[13]; \ + mE ^= rp[14]; \ + mF ^= rp[15]; \ + acc = (acc << 8) | buf[2]; \ + rp = &T512_15[(acc >> 4) & 0x1f][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + m8 ^= rp[8]; \ + m9 ^= rp[9]; \ + mA ^= rp[10]; \ + mB ^= rp[11]; \ + mC ^= rp[12]; \ + mD ^= rp[13]; \ + mE ^= rp[14]; \ + mF ^= rp[15]; \ + acc = (acc << 8) | buf[3]; \ + rp = &T512_20[(acc >> 7) & 0x1f][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + m8 ^= rp[8]; \ + m9 ^= rp[9]; \ + mA ^= rp[10]; \ + mB ^= rp[11]; \ + mC ^= rp[12]; \ + mD ^= rp[13]; \ + mE ^= rp[14]; \ + mF ^= rp[15]; \ + rp = &T512_25[(acc >> 2) & 0x1f][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + m8 ^= rp[8]; \ + m9 ^= rp[9]; \ + mA ^= rp[10]; \ + mB ^= rp[11]; \ + mC ^= rp[12]; \ + mD ^= rp[13]; \ + mE ^= rp[14]; \ + mF ^= rp[15]; \ + acc = (acc << 8) | buf[4]; \ + rp = &T512_30[(acc >> 5) & 0x1f][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + m8 ^= rp[8]; \ + m9 ^= rp[9]; \ + mA ^= rp[10]; \ + mB ^= rp[11]; \ + mC ^= rp[12]; \ + mD ^= rp[13]; \ + mE ^= rp[14]; \ + mF ^= rp[15]; \ + rp = &T512_35[acc & 0x1f][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + m8 ^= rp[8]; \ + m9 ^= rp[9]; \ + mA ^= rp[10]; \ + mB ^= rp[11]; \ + mC ^= rp[12]; \ + mD ^= rp[13]; \ + mE ^= rp[14]; \ + mF ^= rp[15]; \ + acc = buf[5]; \ + rp = &T512_40[acc >> 3][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + m8 ^= rp[8]; \ + m9 ^= rp[9]; \ + mA ^= rp[10]; \ + mB ^= rp[11]; \ + mC ^= rp[12]; \ + mD ^= rp[13]; \ + mE ^= rp[14]; \ + mF ^= rp[15]; \ + acc = (acc << 8) | buf[6]; \ + rp = &T512_45[(acc >> 6) & 0x1f][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + m8 ^= rp[8]; \ + m9 ^= rp[9]; \ + mA ^= rp[10]; \ + mB ^= rp[11]; \ + mC ^= rp[12]; \ + mD ^= rp[13]; \ + mE ^= rp[14]; \ + mF ^= rp[15]; \ + rp = &T512_50[(acc >> 1) & 0x1f][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + m8 ^= rp[8]; \ + m9 ^= rp[9]; \ + mA ^= rp[10]; \ + mB ^= rp[11]; \ + mC ^= rp[12]; \ + mD ^= rp[13]; \ + mE ^= rp[14]; \ + mF ^= rp[15]; \ + acc = (acc << 8) | buf[7]; \ + rp = &T512_55[(acc >> 4) & 0x1f][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + m8 ^= rp[8]; \ + m9 ^= rp[9]; \ + mA ^= rp[10]; \ + mB ^= rp[11]; \ + mC ^= rp[12]; \ + mD ^= rp[13]; \ + mE ^= rp[14]; \ + mF ^= rp[15]; \ + rp = &T512_60[acc & 0x0f][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + m8 ^= rp[8]; \ + m9 ^= rp[9]; \ + mA ^= rp[10]; \ + mB ^= rp[11]; \ + mC ^= rp[12]; \ + mD ^= rp[13]; \ + mE ^= rp[14]; \ + mF ^= rp[15]; \ + } while (0) + +#endif + +#if SPH_HAMSI_EXPAND_BIG == 6 + +static const sph_u32 T512_0[64][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0x145a3c00), SPH_C32(0xb9e90000), SPH_C32(0x61270000), + SPH_C32(0xf1610000), SPH_C32(0xce613d6c), SPH_C32(0xb0493d78), + SPH_C32(0x47a96720), SPH_C32(0xe18e24c5), SPH_C32(0x23671400), + SPH_C32(0xc8b90000), SPH_C32(0xf4c70000), SPH_C32(0xfb750000), + SPH_C32(0x73cd2465), SPH_C32(0xf8a6a549), SPH_C32(0x02c40a3f), + SPH_C32(0xdc24e61f) }, + { SPH_C32(0x23671400), SPH_C32(0xc8b90000), SPH_C32(0xf4c70000), + SPH_C32(0xfb750000), SPH_C32(0x73cd2465), SPH_C32(0xf8a6a549), + SPH_C32(0x02c40a3f), SPH_C32(0xdc24e61f), SPH_C32(0x373d2800), + SPH_C32(0x71500000), SPH_C32(0x95e00000), SPH_C32(0x0a140000), + SPH_C32(0xbdac1909), SPH_C32(0x48ef9831), SPH_C32(0x456d6d1f), + SPH_C32(0x3daac2da) }, + { SPH_C32(0x373d2800), SPH_C32(0x71500000), SPH_C32(0x95e00000), + SPH_C32(0x0a140000), SPH_C32(0xbdac1909), SPH_C32(0x48ef9831), + SPH_C32(0x456d6d1f), SPH_C32(0x3daac2da), SPH_C32(0x145a3c00), + SPH_C32(0xb9e90000), SPH_C32(0x61270000), SPH_C32(0xf1610000), + SPH_C32(0xce613d6c), SPH_C32(0xb0493d78), SPH_C32(0x47a96720), + SPH_C32(0xe18e24c5) }, + { SPH_C32(0x54285c00), SPH_C32(0xeaed0000), SPH_C32(0xc5d60000), + SPH_C32(0xa1c50000), SPH_C32(0xb3a26770), SPH_C32(0x94a5c4e1), + SPH_C32(0x6bb0419d), SPH_C32(0x551b3782), SPH_C32(0x9cbb1800), + SPH_C32(0xb0d30000), SPH_C32(0x92510000), SPH_C32(0xed930000), + SPH_C32(0x593a4345), SPH_C32(0xe114d5f4), SPH_C32(0x430633da), + SPH_C32(0x78cace29) }, + { SPH_C32(0x40726000), SPH_C32(0x53040000), SPH_C32(0xa4f10000), + SPH_C32(0x50a40000), SPH_C32(0x7dc35a1c), SPH_C32(0x24ecf999), + SPH_C32(0x2c1926bd), SPH_C32(0xb4951347), SPH_C32(0xbfdc0c00), + SPH_C32(0x786a0000), SPH_C32(0x66960000), SPH_C32(0x16e60000), + SPH_C32(0x2af76720), SPH_C32(0x19b270bd), SPH_C32(0x41c239e5), + SPH_C32(0xa4ee2836) }, + { SPH_C32(0x774f4800), SPH_C32(0x22540000), SPH_C32(0x31110000), + SPH_C32(0x5ab00000), SPH_C32(0xc06f4315), SPH_C32(0x6c0361a8), + SPH_C32(0x69744ba2), SPH_C32(0x893fd19d), SPH_C32(0xab863000), + SPH_C32(0xc1830000), SPH_C32(0x07b10000), SPH_C32(0xe7870000), + SPH_C32(0xe4965a4c), SPH_C32(0xa9fb4dc5), SPH_C32(0x066b5ec5), + SPH_C32(0x45600cf3) }, + { SPH_C32(0x63157400), SPH_C32(0x9bbd0000), SPH_C32(0x50360000), + SPH_C32(0xabd10000), SPH_C32(0x0e0e7e79), SPH_C32(0xdc4a5cd0), + SPH_C32(0x2edd2c82), SPH_C32(0x68b1f558), SPH_C32(0x88e12400), + SPH_C32(0x093a0000), SPH_C32(0xf3760000), SPH_C32(0x1cf20000), + SPH_C32(0x975b7e29), SPH_C32(0x515de88c), SPH_C32(0x04af54fa), + SPH_C32(0x9944eaec) }, + { SPH_C32(0x9cbb1800), SPH_C32(0xb0d30000), SPH_C32(0x92510000), + SPH_C32(0xed930000), SPH_C32(0x593a4345), SPH_C32(0xe114d5f4), + SPH_C32(0x430633da), SPH_C32(0x78cace29), SPH_C32(0xc8934400), + SPH_C32(0x5a3e0000), SPH_C32(0x57870000), SPH_C32(0x4c560000), + SPH_C32(0xea982435), SPH_C32(0x75b11115), SPH_C32(0x28b67247), + SPH_C32(0x2dd1f9ab) }, + { SPH_C32(0x88e12400), SPH_C32(0x093a0000), SPH_C32(0xf3760000), + SPH_C32(0x1cf20000), SPH_C32(0x975b7e29), SPH_C32(0x515de88c), + SPH_C32(0x04af54fa), SPH_C32(0x9944eaec), SPH_C32(0xebf45000), + SPH_C32(0x92870000), SPH_C32(0xa3400000), SPH_C32(0xb7230000), + SPH_C32(0x99550050), SPH_C32(0x8d17b45c), SPH_C32(0x2a727878), + SPH_C32(0xf1f51fb4) }, + { SPH_C32(0xbfdc0c00), SPH_C32(0x786a0000), SPH_C32(0x66960000), + SPH_C32(0x16e60000), SPH_C32(0x2af76720), SPH_C32(0x19b270bd), + SPH_C32(0x41c239e5), SPH_C32(0xa4ee2836), SPH_C32(0xffae6c00), + SPH_C32(0x2b6e0000), SPH_C32(0xc2670000), SPH_C32(0x46420000), + SPH_C32(0x57343d3c), SPH_C32(0x3d5e8924), SPH_C32(0x6ddb1f58), + SPH_C32(0x107b3b71) }, + { SPH_C32(0xab863000), SPH_C32(0xc1830000), SPH_C32(0x07b10000), + SPH_C32(0xe7870000), SPH_C32(0xe4965a4c), SPH_C32(0xa9fb4dc5), + SPH_C32(0x066b5ec5), SPH_C32(0x45600cf3), SPH_C32(0xdcc97800), + SPH_C32(0xe3d70000), SPH_C32(0x36a00000), SPH_C32(0xbd370000), + SPH_C32(0x24f91959), SPH_C32(0xc5f82c6d), SPH_C32(0x6f1f1567), + SPH_C32(0xcc5fdd6e) }, + { SPH_C32(0xc8934400), SPH_C32(0x5a3e0000), SPH_C32(0x57870000), + SPH_C32(0x4c560000), SPH_C32(0xea982435), SPH_C32(0x75b11115), + SPH_C32(0x28b67247), SPH_C32(0x2dd1f9ab), SPH_C32(0x54285c00), + SPH_C32(0xeaed0000), SPH_C32(0xc5d60000), SPH_C32(0xa1c50000), + SPH_C32(0xb3a26770), SPH_C32(0x94a5c4e1), SPH_C32(0x6bb0419d), + SPH_C32(0x551b3782) }, + { SPH_C32(0xdcc97800), SPH_C32(0xe3d70000), SPH_C32(0x36a00000), + SPH_C32(0xbd370000), SPH_C32(0x24f91959), SPH_C32(0xc5f82c6d), + SPH_C32(0x6f1f1567), SPH_C32(0xcc5fdd6e), SPH_C32(0x774f4800), + SPH_C32(0x22540000), SPH_C32(0x31110000), SPH_C32(0x5ab00000), + SPH_C32(0xc06f4315), SPH_C32(0x6c0361a8), SPH_C32(0x69744ba2), + SPH_C32(0x893fd19d) }, + { SPH_C32(0xebf45000), SPH_C32(0x92870000), SPH_C32(0xa3400000), + SPH_C32(0xb7230000), SPH_C32(0x99550050), SPH_C32(0x8d17b45c), + SPH_C32(0x2a727878), SPH_C32(0xf1f51fb4), SPH_C32(0x63157400), + SPH_C32(0x9bbd0000), SPH_C32(0x50360000), SPH_C32(0xabd10000), + SPH_C32(0x0e0e7e79), SPH_C32(0xdc4a5cd0), SPH_C32(0x2edd2c82), + SPH_C32(0x68b1f558) }, + { SPH_C32(0xffae6c00), SPH_C32(0x2b6e0000), SPH_C32(0xc2670000), + SPH_C32(0x46420000), SPH_C32(0x57343d3c), SPH_C32(0x3d5e8924), + SPH_C32(0x6ddb1f58), SPH_C32(0x107b3b71), SPH_C32(0x40726000), + SPH_C32(0x53040000), SPH_C32(0xa4f10000), SPH_C32(0x50a40000), + SPH_C32(0x7dc35a1c), SPH_C32(0x24ecf999), SPH_C32(0x2c1926bd), + SPH_C32(0xb4951347) }, + { SPH_C32(0x29449c00), SPH_C32(0x64e70000), SPH_C32(0xf24b0000), + SPH_C32(0xc2f30000), SPH_C32(0x0ede4e8f), SPH_C32(0x56c23745), + SPH_C32(0xf3e04259), SPH_C32(0x8d0d9ec4), SPH_C32(0x466d0c00), + SPH_C32(0x08620000), SPH_C32(0xdd5d0000), SPH_C32(0xbadd0000), + SPH_C32(0x6a927942), SPH_C32(0x441f2b93), SPH_C32(0x218ace6f), + SPH_C32(0xbf2c0be2) }, + { SPH_C32(0x3d1ea000), SPH_C32(0xdd0e0000), SPH_C32(0x936c0000), + SPH_C32(0x33920000), SPH_C32(0xc0bf73e3), SPH_C32(0xe68b0a3d), + SPH_C32(0xb4492579), SPH_C32(0x6c83ba01), SPH_C32(0x650a1800), + SPH_C32(0xc0db0000), SPH_C32(0x299a0000), SPH_C32(0x41a80000), + SPH_C32(0x195f5d27), SPH_C32(0xbcb98eda), SPH_C32(0x234ec450), + SPH_C32(0x6308edfd) }, + { SPH_C32(0x0a238800), SPH_C32(0xac5e0000), SPH_C32(0x068c0000), + SPH_C32(0x39860000), SPH_C32(0x7d136aea), SPH_C32(0xae64920c), + SPH_C32(0xf1244866), SPH_C32(0x512978db), SPH_C32(0x71502400), + SPH_C32(0x79320000), SPH_C32(0x48bd0000), SPH_C32(0xb0c90000), + SPH_C32(0xd73e604b), SPH_C32(0x0cf0b3a2), SPH_C32(0x64e7a370), + SPH_C32(0x8286c938) }, + { SPH_C32(0x1e79b400), SPH_C32(0x15b70000), SPH_C32(0x67ab0000), + SPH_C32(0xc8e70000), SPH_C32(0xb3725786), SPH_C32(0x1e2daf74), + SPH_C32(0xb68d2f46), SPH_C32(0xb0a75c1e), SPH_C32(0x52373000), + SPH_C32(0xb18b0000), SPH_C32(0xbc7a0000), SPH_C32(0x4bbc0000), + SPH_C32(0xa4f3442e), SPH_C32(0xf45616eb), SPH_C32(0x6623a94f), + SPH_C32(0x5ea22f27) }, + { SPH_C32(0x7d6cc000), SPH_C32(0x8e0a0000), SPH_C32(0x379d0000), + SPH_C32(0x63360000), SPH_C32(0xbd7c29ff), SPH_C32(0xc267f3a4), + SPH_C32(0x985003c4), SPH_C32(0xd816a946), SPH_C32(0xdad61400), + SPH_C32(0xb8b10000), SPH_C32(0x4f0c0000), SPH_C32(0x574e0000), + SPH_C32(0x33a83a07), SPH_C32(0xa50bfe67), SPH_C32(0x628cfdb5), + SPH_C32(0xc7e6c5cb) }, + { SPH_C32(0x6936fc00), SPH_C32(0x37e30000), SPH_C32(0x56ba0000), + SPH_C32(0x92570000), SPH_C32(0x731d1493), SPH_C32(0x722ecedc), + SPH_C32(0xdff964e4), SPH_C32(0x39988d83), SPH_C32(0xf9b10000), + SPH_C32(0x70080000), SPH_C32(0xbbcb0000), SPH_C32(0xac3b0000), + SPH_C32(0x40651e62), SPH_C32(0x5dad5b2e), SPH_C32(0x6048f78a), + SPH_C32(0x1bc223d4) }, + { SPH_C32(0x5e0bd400), SPH_C32(0x46b30000), SPH_C32(0xc35a0000), + SPH_C32(0x98430000), SPH_C32(0xceb10d9a), SPH_C32(0x3ac156ed), + SPH_C32(0x9a9409fb), SPH_C32(0x04324f59), SPH_C32(0xedeb3c00), + SPH_C32(0xc9e10000), SPH_C32(0xdaec0000), SPH_C32(0x5d5a0000), + SPH_C32(0x8e04230e), SPH_C32(0xede46656), SPH_C32(0x27e190aa), + SPH_C32(0xfa4c0711) }, + { SPH_C32(0x4a51e800), SPH_C32(0xff5a0000), SPH_C32(0xa27d0000), + SPH_C32(0x69220000), SPH_C32(0x00d030f6), SPH_C32(0x8a886b95), + SPH_C32(0xdd3d6edb), SPH_C32(0xe5bc6b9c), SPH_C32(0xce8c2800), + SPH_C32(0x01580000), SPH_C32(0x2e2b0000), SPH_C32(0xa62f0000), + SPH_C32(0xfdc9076b), SPH_C32(0x1542c31f), SPH_C32(0x25259a95), + SPH_C32(0x2668e10e) }, + { SPH_C32(0xb5ff8400), SPH_C32(0xd4340000), SPH_C32(0x601a0000), + SPH_C32(0x2f600000), SPH_C32(0x57e40dca), SPH_C32(0xb7d6e2b1), + SPH_C32(0xb0e67183), SPH_C32(0xf5c750ed), SPH_C32(0x8efe4800), + SPH_C32(0x525c0000), SPH_C32(0x8ada0000), SPH_C32(0xf68b0000), + SPH_C32(0x800a5d77), SPH_C32(0x31ae3a86), SPH_C32(0x093cbc28), + SPH_C32(0x92fdf249) }, + { SPH_C32(0xa1a5b800), SPH_C32(0x6ddd0000), SPH_C32(0x013d0000), + SPH_C32(0xde010000), SPH_C32(0x998530a6), SPH_C32(0x079fdfc9), + SPH_C32(0xf74f16a3), SPH_C32(0x14497428), SPH_C32(0xad995c00), + SPH_C32(0x9ae50000), SPH_C32(0x7e1d0000), SPH_C32(0x0dfe0000), + SPH_C32(0xf3c77912), SPH_C32(0xc9089fcf), SPH_C32(0x0bf8b617), + SPH_C32(0x4ed91456) }, + { SPH_C32(0x96989000), SPH_C32(0x1c8d0000), SPH_C32(0x94dd0000), + SPH_C32(0xd4150000), SPH_C32(0x242929af), SPH_C32(0x4f7047f8), + SPH_C32(0xb2227bbc), SPH_C32(0x29e3b6f2), SPH_C32(0xb9c36000), + SPH_C32(0x230c0000), SPH_C32(0x1f3a0000), SPH_C32(0xfc9f0000), + SPH_C32(0x3da6447e), SPH_C32(0x7941a2b7), SPH_C32(0x4c51d137), + SPH_C32(0xaf573093) }, + { SPH_C32(0x82c2ac00), SPH_C32(0xa5640000), SPH_C32(0xf5fa0000), + SPH_C32(0x25740000), SPH_C32(0xea4814c3), SPH_C32(0xff397a80), + SPH_C32(0xf58b1c9c), SPH_C32(0xc86d9237), SPH_C32(0x9aa47400), + SPH_C32(0xebb50000), SPH_C32(0xebfd0000), SPH_C32(0x07ea0000), + SPH_C32(0x4e6b601b), SPH_C32(0x81e707fe), SPH_C32(0x4e95db08), + SPH_C32(0x7373d68c) }, + { SPH_C32(0xe1d7d800), SPH_C32(0x3ed90000), SPH_C32(0xa5cc0000), + SPH_C32(0x8ea50000), SPH_C32(0xe4466aba), SPH_C32(0x23732650), + SPH_C32(0xdb56301e), SPH_C32(0xa0dc676f), SPH_C32(0x12455000), + SPH_C32(0xe28f0000), SPH_C32(0x188b0000), SPH_C32(0x1b180000), + SPH_C32(0xd9301e32), SPH_C32(0xd0baef72), SPH_C32(0x4a3a8ff2), + SPH_C32(0xea373c60) }, + { SPH_C32(0xf58de400), SPH_C32(0x87300000), SPH_C32(0xc4eb0000), + SPH_C32(0x7fc40000), SPH_C32(0x2a2757d6), SPH_C32(0x933a1b28), + SPH_C32(0x9cff573e), SPH_C32(0x415243aa), SPH_C32(0x31224400), + SPH_C32(0x2a360000), SPH_C32(0xec4c0000), SPH_C32(0xe06d0000), + SPH_C32(0xaafd3a57), SPH_C32(0x281c4a3b), SPH_C32(0x48fe85cd), + SPH_C32(0x3613da7f) }, + { SPH_C32(0xc2b0cc00), SPH_C32(0xf6600000), SPH_C32(0x510b0000), + SPH_C32(0x75d00000), SPH_C32(0x978b4edf), SPH_C32(0xdbd58319), + SPH_C32(0xd9923a21), SPH_C32(0x7cf88170), SPH_C32(0x25787800), + SPH_C32(0x93df0000), SPH_C32(0x8d6b0000), SPH_C32(0x110c0000), + SPH_C32(0x649c073b), SPH_C32(0x98557743), SPH_C32(0x0f57e2ed), + SPH_C32(0xd79dfeba) }, + { SPH_C32(0xd6eaf000), SPH_C32(0x4f890000), SPH_C32(0x302c0000), + SPH_C32(0x84b10000), SPH_C32(0x59ea73b3), SPH_C32(0x6b9cbe61), + SPH_C32(0x9e3b5d01), SPH_C32(0x9d76a5b5), SPH_C32(0x061f6c00), + SPH_C32(0x5b660000), SPH_C32(0x79ac0000), SPH_C32(0xea790000), + SPH_C32(0x1751235e), SPH_C32(0x60f3d20a), SPH_C32(0x0d93e8d2), + SPH_C32(0x0bb918a5) }, + { SPH_C32(0x466d0c00), SPH_C32(0x08620000), SPH_C32(0xdd5d0000), + SPH_C32(0xbadd0000), SPH_C32(0x6a927942), SPH_C32(0x441f2b93), + SPH_C32(0x218ace6f), SPH_C32(0xbf2c0be2), SPH_C32(0x6f299000), + SPH_C32(0x6c850000), SPH_C32(0x2f160000), SPH_C32(0x782e0000), + SPH_C32(0x644c37cd), SPH_C32(0x12dd1cd6), SPH_C32(0xd26a8c36), + SPH_C32(0x32219526) }, + { SPH_C32(0x52373000), SPH_C32(0xb18b0000), SPH_C32(0xbc7a0000), + SPH_C32(0x4bbc0000), SPH_C32(0xa4f3442e), SPH_C32(0xf45616eb), + SPH_C32(0x6623a94f), SPH_C32(0x5ea22f27), SPH_C32(0x4c4e8400), + SPH_C32(0xa43c0000), SPH_C32(0xdbd10000), SPH_C32(0x835b0000), + SPH_C32(0x178113a8), SPH_C32(0xea7bb99f), SPH_C32(0xd0ae8609), + SPH_C32(0xee057339) }, + { SPH_C32(0x650a1800), SPH_C32(0xc0db0000), SPH_C32(0x299a0000), + SPH_C32(0x41a80000), SPH_C32(0x195f5d27), SPH_C32(0xbcb98eda), + SPH_C32(0x234ec450), SPH_C32(0x6308edfd), SPH_C32(0x5814b800), + SPH_C32(0x1dd50000), SPH_C32(0xbaf60000), SPH_C32(0x723a0000), + SPH_C32(0xd9e02ec4), SPH_C32(0x5a3284e7), SPH_C32(0x9707e129), + SPH_C32(0x0f8b57fc) }, + { SPH_C32(0x71502400), SPH_C32(0x79320000), SPH_C32(0x48bd0000), + SPH_C32(0xb0c90000), SPH_C32(0xd73e604b), SPH_C32(0x0cf0b3a2), + SPH_C32(0x64e7a370), SPH_C32(0x8286c938), SPH_C32(0x7b73ac00), + SPH_C32(0xd56c0000), SPH_C32(0x4e310000), SPH_C32(0x894f0000), + SPH_C32(0xaa2d0aa1), SPH_C32(0xa29421ae), SPH_C32(0x95c3eb16), + SPH_C32(0xd3afb1e3) }, + { SPH_C32(0x12455000), SPH_C32(0xe28f0000), SPH_C32(0x188b0000), + SPH_C32(0x1b180000), SPH_C32(0xd9301e32), SPH_C32(0xd0baef72), + SPH_C32(0x4a3a8ff2), SPH_C32(0xea373c60), SPH_C32(0xf3928800), + SPH_C32(0xdc560000), SPH_C32(0xbd470000), SPH_C32(0x95bd0000), + SPH_C32(0x3d767488), SPH_C32(0xf3c9c922), SPH_C32(0x916cbfec), + SPH_C32(0x4aeb5b0f) }, + { SPH_C32(0x061f6c00), SPH_C32(0x5b660000), SPH_C32(0x79ac0000), + SPH_C32(0xea790000), SPH_C32(0x1751235e), SPH_C32(0x60f3d20a), + SPH_C32(0x0d93e8d2), SPH_C32(0x0bb918a5), SPH_C32(0xd0f59c00), + SPH_C32(0x14ef0000), SPH_C32(0x49800000), SPH_C32(0x6ec80000), + SPH_C32(0x4ebb50ed), SPH_C32(0x0b6f6c6b), SPH_C32(0x93a8b5d3), + SPH_C32(0x96cfbd10) }, + { SPH_C32(0x31224400), SPH_C32(0x2a360000), SPH_C32(0xec4c0000), + SPH_C32(0xe06d0000), SPH_C32(0xaafd3a57), SPH_C32(0x281c4a3b), + SPH_C32(0x48fe85cd), SPH_C32(0x3613da7f), SPH_C32(0xc4afa000), + SPH_C32(0xad060000), SPH_C32(0x28a70000), SPH_C32(0x9fa90000), + SPH_C32(0x80da6d81), SPH_C32(0xbb265113), SPH_C32(0xd401d2f3), + SPH_C32(0x774199d5) }, + { SPH_C32(0x25787800), SPH_C32(0x93df0000), SPH_C32(0x8d6b0000), + SPH_C32(0x110c0000), SPH_C32(0x649c073b), SPH_C32(0x98557743), + SPH_C32(0x0f57e2ed), SPH_C32(0xd79dfeba), SPH_C32(0xe7c8b400), + SPH_C32(0x65bf0000), SPH_C32(0xdc600000), SPH_C32(0x64dc0000), + SPH_C32(0xf31749e4), SPH_C32(0x4380f45a), SPH_C32(0xd6c5d8cc), + SPH_C32(0xab657fca) }, + { SPH_C32(0xdad61400), SPH_C32(0xb8b10000), SPH_C32(0x4f0c0000), + SPH_C32(0x574e0000), SPH_C32(0x33a83a07), SPH_C32(0xa50bfe67), + SPH_C32(0x628cfdb5), SPH_C32(0xc7e6c5cb), SPH_C32(0xa7bad400), + SPH_C32(0x36bb0000), SPH_C32(0x78910000), SPH_C32(0x34780000), + SPH_C32(0x8ed413f8), SPH_C32(0x676c0dc3), SPH_C32(0xfadcfe71), + SPH_C32(0x1ff06c8d) }, + { SPH_C32(0xce8c2800), SPH_C32(0x01580000), SPH_C32(0x2e2b0000), + SPH_C32(0xa62f0000), SPH_C32(0xfdc9076b), SPH_C32(0x1542c31f), + SPH_C32(0x25259a95), SPH_C32(0x2668e10e), SPH_C32(0x84ddc000), + SPH_C32(0xfe020000), SPH_C32(0x8c560000), SPH_C32(0xcf0d0000), + SPH_C32(0xfd19379d), SPH_C32(0x9fcaa88a), SPH_C32(0xf818f44e), + SPH_C32(0xc3d48a92) }, + { SPH_C32(0xf9b10000), SPH_C32(0x70080000), SPH_C32(0xbbcb0000), + SPH_C32(0xac3b0000), SPH_C32(0x40651e62), SPH_C32(0x5dad5b2e), + SPH_C32(0x6048f78a), SPH_C32(0x1bc223d4), SPH_C32(0x9087fc00), + SPH_C32(0x47eb0000), SPH_C32(0xed710000), SPH_C32(0x3e6c0000), + SPH_C32(0x33780af1), SPH_C32(0x2f8395f2), SPH_C32(0xbfb1936e), + SPH_C32(0x225aae57) }, + { SPH_C32(0xedeb3c00), SPH_C32(0xc9e10000), SPH_C32(0xdaec0000), + SPH_C32(0x5d5a0000), SPH_C32(0x8e04230e), SPH_C32(0xede46656), + SPH_C32(0x27e190aa), SPH_C32(0xfa4c0711), SPH_C32(0xb3e0e800), + SPH_C32(0x8f520000), SPH_C32(0x19b60000), SPH_C32(0xc5190000), + SPH_C32(0x40b52e94), SPH_C32(0xd72530bb), SPH_C32(0xbd759951), + SPH_C32(0xfe7e4848) }, + { SPH_C32(0x8efe4800), SPH_C32(0x525c0000), SPH_C32(0x8ada0000), + SPH_C32(0xf68b0000), SPH_C32(0x800a5d77), SPH_C32(0x31ae3a86), + SPH_C32(0x093cbc28), SPH_C32(0x92fdf249), SPH_C32(0x3b01cc00), + SPH_C32(0x86680000), SPH_C32(0xeac00000), SPH_C32(0xd9eb0000), + SPH_C32(0xd7ee50bd), SPH_C32(0x8678d837), SPH_C32(0xb9dacdab), + SPH_C32(0x673aa2a4) }, + { SPH_C32(0x9aa47400), SPH_C32(0xebb50000), SPH_C32(0xebfd0000), + SPH_C32(0x07ea0000), SPH_C32(0x4e6b601b), SPH_C32(0x81e707fe), + SPH_C32(0x4e95db08), SPH_C32(0x7373d68c), SPH_C32(0x1866d800), + SPH_C32(0x4ed10000), SPH_C32(0x1e070000), SPH_C32(0x229e0000), + SPH_C32(0xa42374d8), SPH_C32(0x7ede7d7e), SPH_C32(0xbb1ec794), + SPH_C32(0xbb1e44bb) }, + { SPH_C32(0xad995c00), SPH_C32(0x9ae50000), SPH_C32(0x7e1d0000), + SPH_C32(0x0dfe0000), SPH_C32(0xf3c77912), SPH_C32(0xc9089fcf), + SPH_C32(0x0bf8b617), SPH_C32(0x4ed91456), SPH_C32(0x0c3ce400), + SPH_C32(0xf7380000), SPH_C32(0x7f200000), SPH_C32(0xd3ff0000), + SPH_C32(0x6a4249b4), SPH_C32(0xce974006), SPH_C32(0xfcb7a0b4), + SPH_C32(0x5a90607e) }, + { SPH_C32(0xb9c36000), SPH_C32(0x230c0000), SPH_C32(0x1f3a0000), + SPH_C32(0xfc9f0000), SPH_C32(0x3da6447e), SPH_C32(0x7941a2b7), + SPH_C32(0x4c51d137), SPH_C32(0xaf573093), SPH_C32(0x2f5bf000), + SPH_C32(0x3f810000), SPH_C32(0x8be70000), SPH_C32(0x288a0000), + SPH_C32(0x198f6dd1), SPH_C32(0x3631e54f), SPH_C32(0xfe73aa8b), + SPH_C32(0x86b48661) }, + { SPH_C32(0x6f299000), SPH_C32(0x6c850000), SPH_C32(0x2f160000), + SPH_C32(0x782e0000), SPH_C32(0x644c37cd), SPH_C32(0x12dd1cd6), + SPH_C32(0xd26a8c36), SPH_C32(0x32219526), SPH_C32(0x29449c00), + SPH_C32(0x64e70000), SPH_C32(0xf24b0000), SPH_C32(0xc2f30000), + SPH_C32(0x0ede4e8f), SPH_C32(0x56c23745), SPH_C32(0xf3e04259), + SPH_C32(0x8d0d9ec4) }, + { SPH_C32(0x7b73ac00), SPH_C32(0xd56c0000), SPH_C32(0x4e310000), + SPH_C32(0x894f0000), SPH_C32(0xaa2d0aa1), SPH_C32(0xa29421ae), + SPH_C32(0x95c3eb16), SPH_C32(0xd3afb1e3), SPH_C32(0x0a238800), + SPH_C32(0xac5e0000), SPH_C32(0x068c0000), SPH_C32(0x39860000), + SPH_C32(0x7d136aea), SPH_C32(0xae64920c), SPH_C32(0xf1244866), + SPH_C32(0x512978db) }, + { SPH_C32(0x4c4e8400), SPH_C32(0xa43c0000), SPH_C32(0xdbd10000), + SPH_C32(0x835b0000), SPH_C32(0x178113a8), SPH_C32(0xea7bb99f), + SPH_C32(0xd0ae8609), SPH_C32(0xee057339), SPH_C32(0x1e79b400), + SPH_C32(0x15b70000), SPH_C32(0x67ab0000), SPH_C32(0xc8e70000), + SPH_C32(0xb3725786), SPH_C32(0x1e2daf74), SPH_C32(0xb68d2f46), + SPH_C32(0xb0a75c1e) }, + { SPH_C32(0x5814b800), SPH_C32(0x1dd50000), SPH_C32(0xbaf60000), + SPH_C32(0x723a0000), SPH_C32(0xd9e02ec4), SPH_C32(0x5a3284e7), + SPH_C32(0x9707e129), SPH_C32(0x0f8b57fc), SPH_C32(0x3d1ea000), + SPH_C32(0xdd0e0000), SPH_C32(0x936c0000), SPH_C32(0x33920000), + SPH_C32(0xc0bf73e3), SPH_C32(0xe68b0a3d), SPH_C32(0xb4492579), + SPH_C32(0x6c83ba01) }, + { SPH_C32(0x3b01cc00), SPH_C32(0x86680000), SPH_C32(0xeac00000), + SPH_C32(0xd9eb0000), SPH_C32(0xd7ee50bd), SPH_C32(0x8678d837), + SPH_C32(0xb9dacdab), SPH_C32(0x673aa2a4), SPH_C32(0xb5ff8400), + SPH_C32(0xd4340000), SPH_C32(0x601a0000), SPH_C32(0x2f600000), + SPH_C32(0x57e40dca), SPH_C32(0xb7d6e2b1), SPH_C32(0xb0e67183), + SPH_C32(0xf5c750ed) }, + { SPH_C32(0x2f5bf000), SPH_C32(0x3f810000), SPH_C32(0x8be70000), + SPH_C32(0x288a0000), SPH_C32(0x198f6dd1), SPH_C32(0x3631e54f), + SPH_C32(0xfe73aa8b), SPH_C32(0x86b48661), SPH_C32(0x96989000), + SPH_C32(0x1c8d0000), SPH_C32(0x94dd0000), SPH_C32(0xd4150000), + SPH_C32(0x242929af), SPH_C32(0x4f7047f8), SPH_C32(0xb2227bbc), + SPH_C32(0x29e3b6f2) }, + { SPH_C32(0x1866d800), SPH_C32(0x4ed10000), SPH_C32(0x1e070000), + SPH_C32(0x229e0000), SPH_C32(0xa42374d8), SPH_C32(0x7ede7d7e), + SPH_C32(0xbb1ec794), SPH_C32(0xbb1e44bb), SPH_C32(0x82c2ac00), + SPH_C32(0xa5640000), SPH_C32(0xf5fa0000), SPH_C32(0x25740000), + SPH_C32(0xea4814c3), SPH_C32(0xff397a80), SPH_C32(0xf58b1c9c), + SPH_C32(0xc86d9237) }, + { SPH_C32(0x0c3ce400), SPH_C32(0xf7380000), SPH_C32(0x7f200000), + SPH_C32(0xd3ff0000), SPH_C32(0x6a4249b4), SPH_C32(0xce974006), + SPH_C32(0xfcb7a0b4), SPH_C32(0x5a90607e), SPH_C32(0xa1a5b800), + SPH_C32(0x6ddd0000), SPH_C32(0x013d0000), SPH_C32(0xde010000), + SPH_C32(0x998530a6), SPH_C32(0x079fdfc9), SPH_C32(0xf74f16a3), + SPH_C32(0x14497428) }, + { SPH_C32(0xf3928800), SPH_C32(0xdc560000), SPH_C32(0xbd470000), + SPH_C32(0x95bd0000), SPH_C32(0x3d767488), SPH_C32(0xf3c9c922), + SPH_C32(0x916cbfec), SPH_C32(0x4aeb5b0f), SPH_C32(0xe1d7d800), + SPH_C32(0x3ed90000), SPH_C32(0xa5cc0000), SPH_C32(0x8ea50000), + SPH_C32(0xe4466aba), SPH_C32(0x23732650), SPH_C32(0xdb56301e), + SPH_C32(0xa0dc676f) }, + { SPH_C32(0xe7c8b400), SPH_C32(0x65bf0000), SPH_C32(0xdc600000), + SPH_C32(0x64dc0000), SPH_C32(0xf31749e4), SPH_C32(0x4380f45a), + SPH_C32(0xd6c5d8cc), SPH_C32(0xab657fca), SPH_C32(0xc2b0cc00), + SPH_C32(0xf6600000), SPH_C32(0x510b0000), SPH_C32(0x75d00000), + SPH_C32(0x978b4edf), SPH_C32(0xdbd58319), SPH_C32(0xd9923a21), + SPH_C32(0x7cf88170) }, + { SPH_C32(0xd0f59c00), SPH_C32(0x14ef0000), SPH_C32(0x49800000), + SPH_C32(0x6ec80000), SPH_C32(0x4ebb50ed), SPH_C32(0x0b6f6c6b), + SPH_C32(0x93a8b5d3), SPH_C32(0x96cfbd10), SPH_C32(0xd6eaf000), + SPH_C32(0x4f890000), SPH_C32(0x302c0000), SPH_C32(0x84b10000), + SPH_C32(0x59ea73b3), SPH_C32(0x6b9cbe61), SPH_C32(0x9e3b5d01), + SPH_C32(0x9d76a5b5) }, + { SPH_C32(0xc4afa000), SPH_C32(0xad060000), SPH_C32(0x28a70000), + SPH_C32(0x9fa90000), SPH_C32(0x80da6d81), SPH_C32(0xbb265113), + SPH_C32(0xd401d2f3), SPH_C32(0x774199d5), SPH_C32(0xf58de400), + SPH_C32(0x87300000), SPH_C32(0xc4eb0000), SPH_C32(0x7fc40000), + SPH_C32(0x2a2757d6), SPH_C32(0x933a1b28), SPH_C32(0x9cff573e), + SPH_C32(0x415243aa) }, + { SPH_C32(0xa7bad400), SPH_C32(0x36bb0000), SPH_C32(0x78910000), + SPH_C32(0x34780000), SPH_C32(0x8ed413f8), SPH_C32(0x676c0dc3), + SPH_C32(0xfadcfe71), SPH_C32(0x1ff06c8d), SPH_C32(0x7d6cc000), + SPH_C32(0x8e0a0000), SPH_C32(0x379d0000), SPH_C32(0x63360000), + SPH_C32(0xbd7c29ff), SPH_C32(0xc267f3a4), SPH_C32(0x985003c4), + SPH_C32(0xd816a946) }, + { SPH_C32(0xb3e0e800), SPH_C32(0x8f520000), SPH_C32(0x19b60000), + SPH_C32(0xc5190000), SPH_C32(0x40b52e94), SPH_C32(0xd72530bb), + SPH_C32(0xbd759951), SPH_C32(0xfe7e4848), SPH_C32(0x5e0bd400), + SPH_C32(0x46b30000), SPH_C32(0xc35a0000), SPH_C32(0x98430000), + SPH_C32(0xceb10d9a), SPH_C32(0x3ac156ed), SPH_C32(0x9a9409fb), + SPH_C32(0x04324f59) }, + { SPH_C32(0x84ddc000), SPH_C32(0xfe020000), SPH_C32(0x8c560000), + SPH_C32(0xcf0d0000), SPH_C32(0xfd19379d), SPH_C32(0x9fcaa88a), + SPH_C32(0xf818f44e), SPH_C32(0xc3d48a92), SPH_C32(0x4a51e800), + SPH_C32(0xff5a0000), SPH_C32(0xa27d0000), SPH_C32(0x69220000), + SPH_C32(0x00d030f6), SPH_C32(0x8a886b95), SPH_C32(0xdd3d6edb), + SPH_C32(0xe5bc6b9c) }, + { SPH_C32(0x9087fc00), SPH_C32(0x47eb0000), SPH_C32(0xed710000), + SPH_C32(0x3e6c0000), SPH_C32(0x33780af1), SPH_C32(0x2f8395f2), + SPH_C32(0xbfb1936e), SPH_C32(0x225aae57), SPH_C32(0x6936fc00), + SPH_C32(0x37e30000), SPH_C32(0x56ba0000), SPH_C32(0x92570000), + SPH_C32(0x731d1493), SPH_C32(0x722ecedc), SPH_C32(0xdff964e4), + SPH_C32(0x39988d83) } +}; + +static const sph_u32 T512_6[64][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0x774400f0), SPH_C32(0xf15a0000), SPH_C32(0xf5b20000), + SPH_C32(0x34140000), SPH_C32(0x89377e8c), SPH_C32(0x5a8bec25), + SPH_C32(0x0bc3cd1e), SPH_C32(0xcf3775cb), SPH_C32(0xf46c0050), + SPH_C32(0x96180000), SPH_C32(0x14a50000), SPH_C32(0x031f0000), + SPH_C32(0x42947eb8), SPH_C32(0x66bf7e19), SPH_C32(0x9ca470d2), + SPH_C32(0x8a341574) }, + { SPH_C32(0xf46c0050), SPH_C32(0x96180000), SPH_C32(0x14a50000), + SPH_C32(0x031f0000), SPH_C32(0x42947eb8), SPH_C32(0x66bf7e19), + SPH_C32(0x9ca470d2), SPH_C32(0x8a341574), SPH_C32(0x832800a0), + SPH_C32(0x67420000), SPH_C32(0xe1170000), SPH_C32(0x370b0000), + SPH_C32(0xcba30034), SPH_C32(0x3c34923c), SPH_C32(0x9767bdcc), + SPH_C32(0x450360bf) }, + { SPH_C32(0x832800a0), SPH_C32(0x67420000), SPH_C32(0xe1170000), + SPH_C32(0x370b0000), SPH_C32(0xcba30034), SPH_C32(0x3c34923c), + SPH_C32(0x9767bdcc), SPH_C32(0x450360bf), SPH_C32(0x774400f0), + SPH_C32(0xf15a0000), SPH_C32(0xf5b20000), SPH_C32(0x34140000), + SPH_C32(0x89377e8c), SPH_C32(0x5a8bec25), SPH_C32(0x0bc3cd1e), + SPH_C32(0xcf3775cb) }, + { SPH_C32(0xe8870170), SPH_C32(0x9d720000), SPH_C32(0x12db0000), + SPH_C32(0xd4220000), SPH_C32(0xf2886b27), SPH_C32(0xa921e543), + SPH_C32(0x4ef8b518), SPH_C32(0x618813b1), SPH_C32(0xb4370060), + SPH_C32(0x0c4c0000), SPH_C32(0x56c20000), SPH_C32(0x5cae0000), + SPH_C32(0x94541f3f), SPH_C32(0x3b3ef825), SPH_C32(0x1b365f3d), + SPH_C32(0xf3d45758) }, + { SPH_C32(0x9fc30180), SPH_C32(0x6c280000), SPH_C32(0xe7690000), + SPH_C32(0xe0360000), SPH_C32(0x7bbf15ab), SPH_C32(0xf3aa0966), + SPH_C32(0x453b7806), SPH_C32(0xaebf667a), SPH_C32(0x405b0030), + SPH_C32(0x9a540000), SPH_C32(0x42670000), SPH_C32(0x5fb10000), + SPH_C32(0xd6c06187), SPH_C32(0x5d81863c), SPH_C32(0x87922fef), + SPH_C32(0x79e0422c) }, + { SPH_C32(0x1ceb0120), SPH_C32(0x0b6a0000), SPH_C32(0x067e0000), + SPH_C32(0xd73d0000), SPH_C32(0xb01c159f), SPH_C32(0xcf9e9b5a), + SPH_C32(0xd25cc5ca), SPH_C32(0xebbc06c5), SPH_C32(0x371f00c0), + SPH_C32(0x6b0e0000), SPH_C32(0xb7d50000), SPH_C32(0x6ba50000), + SPH_C32(0x5ff71f0b), SPH_C32(0x070a6a19), SPH_C32(0x8c51e2f1), + SPH_C32(0xb6d737e7) }, + { SPH_C32(0x6baf01d0), SPH_C32(0xfa300000), SPH_C32(0xf3cc0000), + SPH_C32(0xe3290000), SPH_C32(0x392b6b13), SPH_C32(0x9515777f), + SPH_C32(0xd99f08d4), SPH_C32(0x248b730e), SPH_C32(0xc3730090), + SPH_C32(0xfd160000), SPH_C32(0xa3700000), SPH_C32(0x68ba0000), + SPH_C32(0x1d6361b3), SPH_C32(0x61b51400), SPH_C32(0x10f59223), + SPH_C32(0x3ce32293) }, + { SPH_C32(0xb4370060), SPH_C32(0x0c4c0000), SPH_C32(0x56c20000), + SPH_C32(0x5cae0000), SPH_C32(0x94541f3f), SPH_C32(0x3b3ef825), + SPH_C32(0x1b365f3d), SPH_C32(0xf3d45758), SPH_C32(0x5cb00110), + SPH_C32(0x913e0000), SPH_C32(0x44190000), SPH_C32(0x888c0000), + SPH_C32(0x66dc7418), SPH_C32(0x921f1d66), SPH_C32(0x55ceea25), + SPH_C32(0x925c44e9) }, + { SPH_C32(0xc3730090), SPH_C32(0xfd160000), SPH_C32(0xa3700000), + SPH_C32(0x68ba0000), SPH_C32(0x1d6361b3), SPH_C32(0x61b51400), + SPH_C32(0x10f59223), SPH_C32(0x3ce32293), SPH_C32(0xa8dc0140), + SPH_C32(0x07260000), SPH_C32(0x50bc0000), SPH_C32(0x8b930000), + SPH_C32(0x24480aa0), SPH_C32(0xf4a0637f), SPH_C32(0xc96a9af7), + SPH_C32(0x1868519d) }, + { SPH_C32(0x405b0030), SPH_C32(0x9a540000), SPH_C32(0x42670000), + SPH_C32(0x5fb10000), SPH_C32(0xd6c06187), SPH_C32(0x5d81863c), + SPH_C32(0x87922fef), SPH_C32(0x79e0422c), SPH_C32(0xdf9801b0), + SPH_C32(0xf67c0000), SPH_C32(0xa50e0000), SPH_C32(0xbf870000), + SPH_C32(0xad7f742c), SPH_C32(0xae2b8f5a), SPH_C32(0xc2a957e9), + SPH_C32(0xd75f2456) }, + { SPH_C32(0x371f00c0), SPH_C32(0x6b0e0000), SPH_C32(0xb7d50000), + SPH_C32(0x6ba50000), SPH_C32(0x5ff71f0b), SPH_C32(0x070a6a19), + SPH_C32(0x8c51e2f1), SPH_C32(0xb6d737e7), SPH_C32(0x2bf401e0), + SPH_C32(0x60640000), SPH_C32(0xb1ab0000), SPH_C32(0xbc980000), + SPH_C32(0xefeb0a94), SPH_C32(0xc894f143), SPH_C32(0x5e0d273b), + SPH_C32(0x5d6b3122) }, + { SPH_C32(0x5cb00110), SPH_C32(0x913e0000), SPH_C32(0x44190000), + SPH_C32(0x888c0000), SPH_C32(0x66dc7418), SPH_C32(0x921f1d66), + SPH_C32(0x55ceea25), SPH_C32(0x925c44e9), SPH_C32(0xe8870170), + SPH_C32(0x9d720000), SPH_C32(0x12db0000), SPH_C32(0xd4220000), + SPH_C32(0xf2886b27), SPH_C32(0xa921e543), SPH_C32(0x4ef8b518), + SPH_C32(0x618813b1) }, + { SPH_C32(0x2bf401e0), SPH_C32(0x60640000), SPH_C32(0xb1ab0000), + SPH_C32(0xbc980000), SPH_C32(0xefeb0a94), SPH_C32(0xc894f143), + SPH_C32(0x5e0d273b), SPH_C32(0x5d6b3122), SPH_C32(0x1ceb0120), + SPH_C32(0x0b6a0000), SPH_C32(0x067e0000), SPH_C32(0xd73d0000), + SPH_C32(0xb01c159f), SPH_C32(0xcf9e9b5a), SPH_C32(0xd25cc5ca), + SPH_C32(0xebbc06c5) }, + { SPH_C32(0xa8dc0140), SPH_C32(0x07260000), SPH_C32(0x50bc0000), + SPH_C32(0x8b930000), SPH_C32(0x24480aa0), SPH_C32(0xf4a0637f), + SPH_C32(0xc96a9af7), SPH_C32(0x1868519d), SPH_C32(0x6baf01d0), + SPH_C32(0xfa300000), SPH_C32(0xf3cc0000), SPH_C32(0xe3290000), + SPH_C32(0x392b6b13), SPH_C32(0x9515777f), SPH_C32(0xd99f08d4), + SPH_C32(0x248b730e) }, + { SPH_C32(0xdf9801b0), SPH_C32(0xf67c0000), SPH_C32(0xa50e0000), + SPH_C32(0xbf870000), SPH_C32(0xad7f742c), SPH_C32(0xae2b8f5a), + SPH_C32(0xc2a957e9), SPH_C32(0xd75f2456), SPH_C32(0x9fc30180), + SPH_C32(0x6c280000), SPH_C32(0xe7690000), SPH_C32(0xe0360000), + SPH_C32(0x7bbf15ab), SPH_C32(0xf3aa0966), SPH_C32(0x453b7806), + SPH_C32(0xaebf667a) }, + { SPH_C32(0xef0b0270), SPH_C32(0x3afd0000), SPH_C32(0x5dae0000), + SPH_C32(0x69490000), SPH_C32(0x9b0f3c06), SPH_C32(0x4405b5f9), + SPH_C32(0x66140a51), SPH_C32(0x924f5d0a), SPH_C32(0xc96b0030), + SPH_C32(0xe7250000), SPH_C32(0x2f840000), SPH_C32(0x264f0000), + SPH_C32(0x08695bf9), SPH_C32(0x6dfcf137), SPH_C32(0x509f6984), + SPH_C32(0x9e69af68) }, + { SPH_C32(0x984f0280), SPH_C32(0xcba70000), SPH_C32(0xa81c0000), + SPH_C32(0x5d5d0000), SPH_C32(0x1238428a), SPH_C32(0x1e8e59dc), + SPH_C32(0x6dd7c74f), SPH_C32(0x5d7828c1), SPH_C32(0x3d070060), + SPH_C32(0x713d0000), SPH_C32(0x3b210000), SPH_C32(0x25500000), + SPH_C32(0x4afd2541), SPH_C32(0x0b438f2e), SPH_C32(0xcc3b1956), + SPH_C32(0x145dba1c) }, + { SPH_C32(0x1b670220), SPH_C32(0xace50000), SPH_C32(0x490b0000), + SPH_C32(0x6a560000), SPH_C32(0xd99b42be), SPH_C32(0x22bacbe0), + SPH_C32(0xfab07a83), SPH_C32(0x187b487e), SPH_C32(0x4a430090), + SPH_C32(0x80670000), SPH_C32(0xce930000), SPH_C32(0x11440000), + SPH_C32(0xc3ca5bcd), SPH_C32(0x51c8630b), SPH_C32(0xc7f8d448), + SPH_C32(0xdb6acfd7) }, + { SPH_C32(0x6c2302d0), SPH_C32(0x5dbf0000), SPH_C32(0xbcb90000), + SPH_C32(0x5e420000), SPH_C32(0x50ac3c32), SPH_C32(0x783127c5), + SPH_C32(0xf173b79d), SPH_C32(0xd74c3db5), SPH_C32(0xbe2f00c0), + SPH_C32(0x167f0000), SPH_C32(0xda360000), SPH_C32(0x125b0000), + SPH_C32(0x815e2575), SPH_C32(0x37771d12), SPH_C32(0x5b5ca49a), + SPH_C32(0x515edaa3) }, + { SPH_C32(0x078c0300), SPH_C32(0xa78f0000), SPH_C32(0x4f750000), + SPH_C32(0xbd6b0000), SPH_C32(0x69875721), SPH_C32(0xed2450ba), + SPH_C32(0x28ecbf49), SPH_C32(0xf3c74ebb), SPH_C32(0x7d5c0050), + SPH_C32(0xeb690000), SPH_C32(0x79460000), SPH_C32(0x7ae10000), + SPH_C32(0x9c3d44c6), SPH_C32(0x56c20912), SPH_C32(0x4ba936b9), + SPH_C32(0x6dbdf830) }, + { SPH_C32(0x70c803f0), SPH_C32(0x56d50000), SPH_C32(0xbac70000), + SPH_C32(0x897f0000), SPH_C32(0xe0b029ad), SPH_C32(0xb7afbc9f), + SPH_C32(0x232f7257), SPH_C32(0x3cf03b70), SPH_C32(0x89300000), + SPH_C32(0x7d710000), SPH_C32(0x6de30000), SPH_C32(0x79fe0000), + SPH_C32(0xdea93a7e), SPH_C32(0x307d770b), SPH_C32(0xd70d466b), + SPH_C32(0xe789ed44) }, + { SPH_C32(0xf3e00350), SPH_C32(0x31970000), SPH_C32(0x5bd00000), + SPH_C32(0xbe740000), SPH_C32(0x2b132999), SPH_C32(0x8b9b2ea3), + SPH_C32(0xb448cf9b), SPH_C32(0x79f35bcf), SPH_C32(0xfe7400f0), + SPH_C32(0x8c2b0000), SPH_C32(0x98510000), SPH_C32(0x4dea0000), + SPH_C32(0x579e44f2), SPH_C32(0x6af69b2e), SPH_C32(0xdcce8b75), + SPH_C32(0x28be988f) }, + { SPH_C32(0x84a403a0), SPH_C32(0xc0cd0000), SPH_C32(0xae620000), + SPH_C32(0x8a600000), SPH_C32(0xa2245715), SPH_C32(0xd110c286), + SPH_C32(0xbf8b0285), SPH_C32(0xb6c42e04), SPH_C32(0x0a1800a0), + SPH_C32(0x1a330000), SPH_C32(0x8cf40000), SPH_C32(0x4ef50000), + SPH_C32(0x150a3a4a), SPH_C32(0x0c49e537), SPH_C32(0x406afba7), + SPH_C32(0xa28a8dfb) }, + { SPH_C32(0x5b3c0210), SPH_C32(0x36b10000), SPH_C32(0x0b6c0000), + SPH_C32(0x35e70000), SPH_C32(0x0f5b2339), SPH_C32(0x7f3b4ddc), + SPH_C32(0x7d22556c), SPH_C32(0x619b0a52), SPH_C32(0x95db0120), + SPH_C32(0x761b0000), SPH_C32(0x6b9d0000), SPH_C32(0xaec30000), + SPH_C32(0x6eb52fe1), SPH_C32(0xffe3ec51), SPH_C32(0x055183a1), + SPH_C32(0x0c35eb81) }, + { SPH_C32(0x2c7802e0), SPH_C32(0xc7eb0000), SPH_C32(0xfede0000), + SPH_C32(0x01f30000), SPH_C32(0x866c5db5), SPH_C32(0x25b0a1f9), + SPH_C32(0x76e19872), SPH_C32(0xaeac7f99), SPH_C32(0x61b70170), + SPH_C32(0xe0030000), SPH_C32(0x7f380000), SPH_C32(0xaddc0000), + SPH_C32(0x2c215159), SPH_C32(0x995c9248), SPH_C32(0x99f5f373), + SPH_C32(0x8601fef5) }, + { SPH_C32(0xaf500240), SPH_C32(0xa0a90000), SPH_C32(0x1fc90000), + SPH_C32(0x36f80000), SPH_C32(0x4dcf5d81), SPH_C32(0x198433c5), + SPH_C32(0xe18625be), SPH_C32(0xebaf1f26), SPH_C32(0x16f30180), + SPH_C32(0x11590000), SPH_C32(0x8a8a0000), SPH_C32(0x99c80000), + SPH_C32(0xa5162fd5), SPH_C32(0xc3d77e6d), SPH_C32(0x92363e6d), + SPH_C32(0x49368b3e) }, + { SPH_C32(0xd81402b0), SPH_C32(0x51f30000), SPH_C32(0xea7b0000), + SPH_C32(0x02ec0000), SPH_C32(0xc4f8230d), SPH_C32(0x430fdfe0), + SPH_C32(0xea45e8a0), SPH_C32(0x24986aed), SPH_C32(0xe29f01d0), + SPH_C32(0x87410000), SPH_C32(0x9e2f0000), SPH_C32(0x9ad70000), + SPH_C32(0xe782516d), SPH_C32(0xa5680074), SPH_C32(0x0e924ebf), + SPH_C32(0xc3029e4a) }, + { SPH_C32(0xb3bb0360), SPH_C32(0xabc30000), SPH_C32(0x19b70000), + SPH_C32(0xe1c50000), SPH_C32(0xfdd3481e), SPH_C32(0xd61aa89f), + SPH_C32(0x33dae074), SPH_C32(0x001319e3), SPH_C32(0x21ec0140), + SPH_C32(0x7a570000), SPH_C32(0x3d5f0000), SPH_C32(0xf26d0000), + SPH_C32(0xfae130de), SPH_C32(0xc4dd1474), SPH_C32(0x1e67dc9c), + SPH_C32(0xffe1bcd9) }, + { SPH_C32(0xc4ff0390), SPH_C32(0x5a990000), SPH_C32(0xec050000), + SPH_C32(0xd5d10000), SPH_C32(0x74e43692), SPH_C32(0x8c9144ba), + SPH_C32(0x38192d6a), SPH_C32(0xcf246c28), SPH_C32(0xd5800110), + SPH_C32(0xec4f0000), SPH_C32(0x29fa0000), SPH_C32(0xf1720000), + SPH_C32(0xb8754e66), SPH_C32(0xa2626a6d), SPH_C32(0x82c3ac4e), + SPH_C32(0x75d5a9ad) }, + { SPH_C32(0x47d70330), SPH_C32(0x3ddb0000), SPH_C32(0x0d120000), + SPH_C32(0xe2da0000), SPH_C32(0xbf4736a6), SPH_C32(0xb0a5d686), + SPH_C32(0xaf7e90a6), SPH_C32(0x8a270c97), SPH_C32(0xa2c401e0), + SPH_C32(0x1d150000), SPH_C32(0xdc480000), SPH_C32(0xc5660000), + SPH_C32(0x314230ea), SPH_C32(0xf8e98648), SPH_C32(0x89006150), + SPH_C32(0xbae2dc66) }, + { SPH_C32(0x309303c0), SPH_C32(0xcc810000), SPH_C32(0xf8a00000), + SPH_C32(0xd6ce0000), SPH_C32(0x3670482a), SPH_C32(0xea2e3aa3), + SPH_C32(0xa4bd5db8), SPH_C32(0x4510795c), SPH_C32(0x56a801b0), + SPH_C32(0x8b0d0000), SPH_C32(0xc8ed0000), SPH_C32(0xc6790000), + SPH_C32(0x73d64e52), SPH_C32(0x9e56f851), SPH_C32(0x15a41182), + SPH_C32(0x30d6c912) }, + { SPH_C32(0xc96b0030), SPH_C32(0xe7250000), SPH_C32(0x2f840000), + SPH_C32(0x264f0000), SPH_C32(0x08695bf9), SPH_C32(0x6dfcf137), + SPH_C32(0x509f6984), SPH_C32(0x9e69af68), SPH_C32(0x26600240), + SPH_C32(0xddd80000), SPH_C32(0x722a0000), SPH_C32(0x4f060000), + SPH_C32(0x936667ff), SPH_C32(0x29f944ce), SPH_C32(0x368b63d5), + SPH_C32(0x0c26f262) }, + { SPH_C32(0xbe2f00c0), SPH_C32(0x167f0000), SPH_C32(0xda360000), + SPH_C32(0x125b0000), SPH_C32(0x815e2575), SPH_C32(0x37771d12), + SPH_C32(0x5b5ca49a), SPH_C32(0x515edaa3), SPH_C32(0xd20c0210), + SPH_C32(0x4bc00000), SPH_C32(0x668f0000), SPH_C32(0x4c190000), + SPH_C32(0xd1f21947), SPH_C32(0x4f463ad7), SPH_C32(0xaa2f1307), + SPH_C32(0x8612e716) }, + { SPH_C32(0x3d070060), SPH_C32(0x713d0000), SPH_C32(0x3b210000), + SPH_C32(0x25500000), SPH_C32(0x4afd2541), SPH_C32(0x0b438f2e), + SPH_C32(0xcc3b1956), SPH_C32(0x145dba1c), SPH_C32(0xa54802e0), + SPH_C32(0xba9a0000), SPH_C32(0x933d0000), SPH_C32(0x780d0000), + SPH_C32(0x58c567cb), SPH_C32(0x15cdd6f2), SPH_C32(0xa1ecde19), + SPH_C32(0x492592dd) }, + { SPH_C32(0x4a430090), SPH_C32(0x80670000), SPH_C32(0xce930000), + SPH_C32(0x11440000), SPH_C32(0xc3ca5bcd), SPH_C32(0x51c8630b), + SPH_C32(0xc7f8d448), SPH_C32(0xdb6acfd7), SPH_C32(0x512402b0), + SPH_C32(0x2c820000), SPH_C32(0x87980000), SPH_C32(0x7b120000), + SPH_C32(0x1a511973), SPH_C32(0x7372a8eb), SPH_C32(0x3d48aecb), + SPH_C32(0xc31187a9) }, + { SPH_C32(0x21ec0140), SPH_C32(0x7a570000), SPH_C32(0x3d5f0000), + SPH_C32(0xf26d0000), SPH_C32(0xfae130de), SPH_C32(0xc4dd1474), + SPH_C32(0x1e67dc9c), SPH_C32(0xffe1bcd9), SPH_C32(0x92570220), + SPH_C32(0xd1940000), SPH_C32(0x24e80000), SPH_C32(0x13a80000), + SPH_C32(0x073278c0), SPH_C32(0x12c7bceb), SPH_C32(0x2dbd3ce8), + SPH_C32(0xfff2a53a) }, + { SPH_C32(0x56a801b0), SPH_C32(0x8b0d0000), SPH_C32(0xc8ed0000), + SPH_C32(0xc6790000), SPH_C32(0x73d64e52), SPH_C32(0x9e56f851), + SPH_C32(0x15a41182), SPH_C32(0x30d6c912), SPH_C32(0x663b0270), + SPH_C32(0x478c0000), SPH_C32(0x304d0000), SPH_C32(0x10b70000), + SPH_C32(0x45a60678), SPH_C32(0x7478c2f2), SPH_C32(0xb1194c3a), + SPH_C32(0x75c6b04e) }, + { SPH_C32(0xd5800110), SPH_C32(0xec4f0000), SPH_C32(0x29fa0000), + SPH_C32(0xf1720000), SPH_C32(0xb8754e66), SPH_C32(0xa2626a6d), + SPH_C32(0x82c3ac4e), SPH_C32(0x75d5a9ad), SPH_C32(0x117f0280), + SPH_C32(0xb6d60000), SPH_C32(0xc5ff0000), SPH_C32(0x24a30000), + SPH_C32(0xcc9178f4), SPH_C32(0x2ef32ed7), SPH_C32(0xbada8124), + SPH_C32(0xbaf1c585) }, + { SPH_C32(0xa2c401e0), SPH_C32(0x1d150000), SPH_C32(0xdc480000), + SPH_C32(0xc5660000), SPH_C32(0x314230ea), SPH_C32(0xf8e98648), + SPH_C32(0x89006150), SPH_C32(0xbae2dc66), SPH_C32(0xe51302d0), + SPH_C32(0x20ce0000), SPH_C32(0xd15a0000), SPH_C32(0x27bc0000), + SPH_C32(0x8e05064c), SPH_C32(0x484c50ce), SPH_C32(0x267ef1f6), + SPH_C32(0x30c5d0f1) }, + { SPH_C32(0x7d5c0050), SPH_C32(0xeb690000), SPH_C32(0x79460000), + SPH_C32(0x7ae10000), SPH_C32(0x9c3d44c6), SPH_C32(0x56c20912), + SPH_C32(0x4ba936b9), SPH_C32(0x6dbdf830), SPH_C32(0x7ad00350), + SPH_C32(0x4ce60000), SPH_C32(0x36330000), SPH_C32(0xc78a0000), + SPH_C32(0xf5ba13e7), SPH_C32(0xbbe659a8), SPH_C32(0x634589f0), + SPH_C32(0x9e7ab68b) }, + { SPH_C32(0x0a1800a0), SPH_C32(0x1a330000), SPH_C32(0x8cf40000), + SPH_C32(0x4ef50000), SPH_C32(0x150a3a4a), SPH_C32(0x0c49e537), + SPH_C32(0x406afba7), SPH_C32(0xa28a8dfb), SPH_C32(0x8ebc0300), + SPH_C32(0xdafe0000), SPH_C32(0x22960000), SPH_C32(0xc4950000), + SPH_C32(0xb72e6d5f), SPH_C32(0xdd5927b1), SPH_C32(0xffe1f922), + SPH_C32(0x144ea3ff) }, + { SPH_C32(0x89300000), SPH_C32(0x7d710000), SPH_C32(0x6de30000), + SPH_C32(0x79fe0000), SPH_C32(0xdea93a7e), SPH_C32(0x307d770b), + SPH_C32(0xd70d466b), SPH_C32(0xe789ed44), SPH_C32(0xf9f803f0), + SPH_C32(0x2ba40000), SPH_C32(0xd7240000), SPH_C32(0xf0810000), + SPH_C32(0x3e1913d3), SPH_C32(0x87d2cb94), SPH_C32(0xf422343c), + SPH_C32(0xdb79d634) }, + { SPH_C32(0xfe7400f0), SPH_C32(0x8c2b0000), SPH_C32(0x98510000), + SPH_C32(0x4dea0000), SPH_C32(0x579e44f2), SPH_C32(0x6af69b2e), + SPH_C32(0xdcce8b75), SPH_C32(0x28be988f), SPH_C32(0x0d9403a0), + SPH_C32(0xbdbc0000), SPH_C32(0xc3810000), SPH_C32(0xf39e0000), + SPH_C32(0x7c8d6d6b), SPH_C32(0xe16db58d), SPH_C32(0x688644ee), + SPH_C32(0x514dc340) }, + { SPH_C32(0x95db0120), SPH_C32(0x761b0000), SPH_C32(0x6b9d0000), + SPH_C32(0xaec30000), SPH_C32(0x6eb52fe1), SPH_C32(0xffe3ec51), + SPH_C32(0x055183a1), SPH_C32(0x0c35eb81), SPH_C32(0xcee70330), + SPH_C32(0x40aa0000), SPH_C32(0x60f10000), SPH_C32(0x9b240000), + SPH_C32(0x61ee0cd8), SPH_C32(0x80d8a18d), SPH_C32(0x7873d6cd), + SPH_C32(0x6daee1d3) }, + { SPH_C32(0xe29f01d0), SPH_C32(0x87410000), SPH_C32(0x9e2f0000), + SPH_C32(0x9ad70000), SPH_C32(0xe782516d), SPH_C32(0xa5680074), + SPH_C32(0x0e924ebf), SPH_C32(0xc3029e4a), SPH_C32(0x3a8b0360), + SPH_C32(0xd6b20000), SPH_C32(0x74540000), SPH_C32(0x983b0000), + SPH_C32(0x237a7260), SPH_C32(0xe667df94), SPH_C32(0xe4d7a61f), + SPH_C32(0xe79af4a7) }, + { SPH_C32(0x61b70170), SPH_C32(0xe0030000), SPH_C32(0x7f380000), + SPH_C32(0xaddc0000), SPH_C32(0x2c215159), SPH_C32(0x995c9248), + SPH_C32(0x99f5f373), SPH_C32(0x8601fef5), SPH_C32(0x4dcf0390), + SPH_C32(0x27e80000), SPH_C32(0x81e60000), SPH_C32(0xac2f0000), + SPH_C32(0xaa4d0cec), SPH_C32(0xbcec33b1), SPH_C32(0xef146b01), + SPH_C32(0x28ad816c) }, + { SPH_C32(0x16f30180), SPH_C32(0x11590000), SPH_C32(0x8a8a0000), + SPH_C32(0x99c80000), SPH_C32(0xa5162fd5), SPH_C32(0xc3d77e6d), + SPH_C32(0x92363e6d), SPH_C32(0x49368b3e), SPH_C32(0xb9a303c0), + SPH_C32(0xb1f00000), SPH_C32(0x95430000), SPH_C32(0xaf300000), + SPH_C32(0xe8d97254), SPH_C32(0xda534da8), SPH_C32(0x73b01bd3), + SPH_C32(0xa2999418) }, + { SPH_C32(0x26600240), SPH_C32(0xddd80000), SPH_C32(0x722a0000), + SPH_C32(0x4f060000), SPH_C32(0x936667ff), SPH_C32(0x29f944ce), + SPH_C32(0x368b63d5), SPH_C32(0x0c26f262), SPH_C32(0xef0b0270), + SPH_C32(0x3afd0000), SPH_C32(0x5dae0000), SPH_C32(0x69490000), + SPH_C32(0x9b0f3c06), SPH_C32(0x4405b5f9), SPH_C32(0x66140a51), + SPH_C32(0x924f5d0a) }, + { SPH_C32(0x512402b0), SPH_C32(0x2c820000), SPH_C32(0x87980000), + SPH_C32(0x7b120000), SPH_C32(0x1a511973), SPH_C32(0x7372a8eb), + SPH_C32(0x3d48aecb), SPH_C32(0xc31187a9), SPH_C32(0x1b670220), + SPH_C32(0xace50000), SPH_C32(0x490b0000), SPH_C32(0x6a560000), + SPH_C32(0xd99b42be), SPH_C32(0x22bacbe0), SPH_C32(0xfab07a83), + SPH_C32(0x187b487e) }, + { SPH_C32(0xd20c0210), SPH_C32(0x4bc00000), SPH_C32(0x668f0000), + SPH_C32(0x4c190000), SPH_C32(0xd1f21947), SPH_C32(0x4f463ad7), + SPH_C32(0xaa2f1307), SPH_C32(0x8612e716), SPH_C32(0x6c2302d0), + SPH_C32(0x5dbf0000), SPH_C32(0xbcb90000), SPH_C32(0x5e420000), + SPH_C32(0x50ac3c32), SPH_C32(0x783127c5), SPH_C32(0xf173b79d), + SPH_C32(0xd74c3db5) }, + { SPH_C32(0xa54802e0), SPH_C32(0xba9a0000), SPH_C32(0x933d0000), + SPH_C32(0x780d0000), SPH_C32(0x58c567cb), SPH_C32(0x15cdd6f2), + SPH_C32(0xa1ecde19), SPH_C32(0x492592dd), SPH_C32(0x984f0280), + SPH_C32(0xcba70000), SPH_C32(0xa81c0000), SPH_C32(0x5d5d0000), + SPH_C32(0x1238428a), SPH_C32(0x1e8e59dc), SPH_C32(0x6dd7c74f), + SPH_C32(0x5d7828c1) }, + { SPH_C32(0xcee70330), SPH_C32(0x40aa0000), SPH_C32(0x60f10000), + SPH_C32(0x9b240000), SPH_C32(0x61ee0cd8), SPH_C32(0x80d8a18d), + SPH_C32(0x7873d6cd), SPH_C32(0x6daee1d3), SPH_C32(0x5b3c0210), + SPH_C32(0x36b10000), SPH_C32(0x0b6c0000), SPH_C32(0x35e70000), + SPH_C32(0x0f5b2339), SPH_C32(0x7f3b4ddc), SPH_C32(0x7d22556c), + SPH_C32(0x619b0a52) }, + { SPH_C32(0xb9a303c0), SPH_C32(0xb1f00000), SPH_C32(0x95430000), + SPH_C32(0xaf300000), SPH_C32(0xe8d97254), SPH_C32(0xda534da8), + SPH_C32(0x73b01bd3), SPH_C32(0xa2999418), SPH_C32(0xaf500240), + SPH_C32(0xa0a90000), SPH_C32(0x1fc90000), SPH_C32(0x36f80000), + SPH_C32(0x4dcf5d81), SPH_C32(0x198433c5), SPH_C32(0xe18625be), + SPH_C32(0xebaf1f26) }, + { SPH_C32(0x3a8b0360), SPH_C32(0xd6b20000), SPH_C32(0x74540000), + SPH_C32(0x983b0000), SPH_C32(0x237a7260), SPH_C32(0xe667df94), + SPH_C32(0xe4d7a61f), SPH_C32(0xe79af4a7), SPH_C32(0xd81402b0), + SPH_C32(0x51f30000), SPH_C32(0xea7b0000), SPH_C32(0x02ec0000), + SPH_C32(0xc4f8230d), SPH_C32(0x430fdfe0), SPH_C32(0xea45e8a0), + SPH_C32(0x24986aed) }, + { SPH_C32(0x4dcf0390), SPH_C32(0x27e80000), SPH_C32(0x81e60000), + SPH_C32(0xac2f0000), SPH_C32(0xaa4d0cec), SPH_C32(0xbcec33b1), + SPH_C32(0xef146b01), SPH_C32(0x28ad816c), SPH_C32(0x2c7802e0), + SPH_C32(0xc7eb0000), SPH_C32(0xfede0000), SPH_C32(0x01f30000), + SPH_C32(0x866c5db5), SPH_C32(0x25b0a1f9), SPH_C32(0x76e19872), + SPH_C32(0xaeac7f99) }, + { SPH_C32(0x92570220), SPH_C32(0xd1940000), SPH_C32(0x24e80000), + SPH_C32(0x13a80000), SPH_C32(0x073278c0), SPH_C32(0x12c7bceb), + SPH_C32(0x2dbd3ce8), SPH_C32(0xfff2a53a), SPH_C32(0xb3bb0360), + SPH_C32(0xabc30000), SPH_C32(0x19b70000), SPH_C32(0xe1c50000), + SPH_C32(0xfdd3481e), SPH_C32(0xd61aa89f), SPH_C32(0x33dae074), + SPH_C32(0x001319e3) }, + { SPH_C32(0xe51302d0), SPH_C32(0x20ce0000), SPH_C32(0xd15a0000), + SPH_C32(0x27bc0000), SPH_C32(0x8e05064c), SPH_C32(0x484c50ce), + SPH_C32(0x267ef1f6), SPH_C32(0x30c5d0f1), SPH_C32(0x47d70330), + SPH_C32(0x3ddb0000), SPH_C32(0x0d120000), SPH_C32(0xe2da0000), + SPH_C32(0xbf4736a6), SPH_C32(0xb0a5d686), SPH_C32(0xaf7e90a6), + SPH_C32(0x8a270c97) }, + { SPH_C32(0x663b0270), SPH_C32(0x478c0000), SPH_C32(0x304d0000), + SPH_C32(0x10b70000), SPH_C32(0x45a60678), SPH_C32(0x7478c2f2), + SPH_C32(0xb1194c3a), SPH_C32(0x75c6b04e), SPH_C32(0x309303c0), + SPH_C32(0xcc810000), SPH_C32(0xf8a00000), SPH_C32(0xd6ce0000), + SPH_C32(0x3670482a), SPH_C32(0xea2e3aa3), SPH_C32(0xa4bd5db8), + SPH_C32(0x4510795c) }, + { SPH_C32(0x117f0280), SPH_C32(0xb6d60000), SPH_C32(0xc5ff0000), + SPH_C32(0x24a30000), SPH_C32(0xcc9178f4), SPH_C32(0x2ef32ed7), + SPH_C32(0xbada8124), SPH_C32(0xbaf1c585), SPH_C32(0xc4ff0390), + SPH_C32(0x5a990000), SPH_C32(0xec050000), SPH_C32(0xd5d10000), + SPH_C32(0x74e43692), SPH_C32(0x8c9144ba), SPH_C32(0x38192d6a), + SPH_C32(0xcf246c28) }, + { SPH_C32(0x7ad00350), SPH_C32(0x4ce60000), SPH_C32(0x36330000), + SPH_C32(0xc78a0000), SPH_C32(0xf5ba13e7), SPH_C32(0xbbe659a8), + SPH_C32(0x634589f0), SPH_C32(0x9e7ab68b), SPH_C32(0x078c0300), + SPH_C32(0xa78f0000), SPH_C32(0x4f750000), SPH_C32(0xbd6b0000), + SPH_C32(0x69875721), SPH_C32(0xed2450ba), SPH_C32(0x28ecbf49), + SPH_C32(0xf3c74ebb) }, + { SPH_C32(0x0d9403a0), SPH_C32(0xbdbc0000), SPH_C32(0xc3810000), + SPH_C32(0xf39e0000), SPH_C32(0x7c8d6d6b), SPH_C32(0xe16db58d), + SPH_C32(0x688644ee), SPH_C32(0x514dc340), SPH_C32(0xf3e00350), + SPH_C32(0x31970000), SPH_C32(0x5bd00000), SPH_C32(0xbe740000), + SPH_C32(0x2b132999), SPH_C32(0x8b9b2ea3), SPH_C32(0xb448cf9b), + SPH_C32(0x79f35bcf) }, + { SPH_C32(0x8ebc0300), SPH_C32(0xdafe0000), SPH_C32(0x22960000), + SPH_C32(0xc4950000), SPH_C32(0xb72e6d5f), SPH_C32(0xdd5927b1), + SPH_C32(0xffe1f922), SPH_C32(0x144ea3ff), SPH_C32(0x84a403a0), + SPH_C32(0xc0cd0000), SPH_C32(0xae620000), SPH_C32(0x8a600000), + SPH_C32(0xa2245715), SPH_C32(0xd110c286), SPH_C32(0xbf8b0285), + SPH_C32(0xb6c42e04) }, + { SPH_C32(0xf9f803f0), SPH_C32(0x2ba40000), SPH_C32(0xd7240000), + SPH_C32(0xf0810000), SPH_C32(0x3e1913d3), SPH_C32(0x87d2cb94), + SPH_C32(0xf422343c), SPH_C32(0xdb79d634), SPH_C32(0x70c803f0), + SPH_C32(0x56d50000), SPH_C32(0xbac70000), SPH_C32(0x897f0000), + SPH_C32(0xe0b029ad), SPH_C32(0xb7afbc9f), SPH_C32(0x232f7257), + SPH_C32(0x3cf03b70) } +}; + +static const sph_u32 T512_12[64][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0x75c90003), SPH_C32(0x0e10c000), SPH_C32(0xd1200000), + SPH_C32(0xbaea0000), SPH_C32(0x8bc42f3e), SPH_C32(0x8758b757), + SPH_C32(0xbb28761d), SPH_C32(0x00b72e2b), SPH_C32(0xeecf0001), + SPH_C32(0x6f564000), SPH_C32(0xf33e0000), SPH_C32(0xa79e0000), + SPH_C32(0xbdb57219), SPH_C32(0xb711ebc5), SPH_C32(0x4a3b40ba), + SPH_C32(0xfeabf254) }, + { SPH_C32(0xeecf0001), SPH_C32(0x6f564000), SPH_C32(0xf33e0000), + SPH_C32(0xa79e0000), SPH_C32(0xbdb57219), SPH_C32(0xb711ebc5), + SPH_C32(0x4a3b40ba), SPH_C32(0xfeabf254), SPH_C32(0x9b060002), + SPH_C32(0x61468000), SPH_C32(0x221e0000), SPH_C32(0x1d740000), + SPH_C32(0x36715d27), SPH_C32(0x30495c92), SPH_C32(0xf11336a7), + SPH_C32(0xfe1cdc7f) }, + { SPH_C32(0x9b060002), SPH_C32(0x61468000), SPH_C32(0x221e0000), + SPH_C32(0x1d740000), SPH_C32(0x36715d27), SPH_C32(0x30495c92), + SPH_C32(0xf11336a7), SPH_C32(0xfe1cdc7f), SPH_C32(0x75c90003), + SPH_C32(0x0e10c000), SPH_C32(0xd1200000), SPH_C32(0xbaea0000), + SPH_C32(0x8bc42f3e), SPH_C32(0x8758b757), SPH_C32(0xbb28761d), + SPH_C32(0x00b72e2b) }, + { SPH_C32(0xf6800005), SPH_C32(0x3443c000), SPH_C32(0x24070000), + SPH_C32(0x8f3d0000), SPH_C32(0x21373bfb), SPH_C32(0x0ab8d5ae), + SPH_C32(0xcdc58b19), SPH_C32(0xd795ba31), SPH_C32(0xa67f0001), + SPH_C32(0x71378000), SPH_C32(0x19fc0000), SPH_C32(0x96db0000), + SPH_C32(0x3a8b6dfd), SPH_C32(0xebcaaef3), SPH_C32(0x2c6d478f), + SPH_C32(0xac8e6c88) }, + { SPH_C32(0x83490006), SPH_C32(0x3a530000), SPH_C32(0xf5270000), + SPH_C32(0x35d70000), SPH_C32(0xaaf314c5), SPH_C32(0x8de062f9), + SPH_C32(0x76edfd04), SPH_C32(0xd722941a), SPH_C32(0x48b00000), + SPH_C32(0x1e61c000), SPH_C32(0xeac20000), SPH_C32(0x31450000), + SPH_C32(0x873e1fe4), SPH_C32(0x5cdb4536), SPH_C32(0x66560735), + SPH_C32(0x52259edc) }, + { SPH_C32(0x184f0004), SPH_C32(0x5b158000), SPH_C32(0xd7390000), + SPH_C32(0x28a30000), SPH_C32(0x9c8249e2), SPH_C32(0xbda93e6b), + SPH_C32(0x87fecba3), SPH_C32(0x293e4865), SPH_C32(0x3d790003), + SPH_C32(0x10710000), SPH_C32(0x3be20000), SPH_C32(0x8baf0000), + SPH_C32(0x0cfa30da), SPH_C32(0xdb83f261), SPH_C32(0xdd7e7128), + SPH_C32(0x5292b0f7) }, + { SPH_C32(0x6d860007), SPH_C32(0x55054000), SPH_C32(0x06190000), + SPH_C32(0x92490000), SPH_C32(0x174666dc), SPH_C32(0x3af1893c), + SPH_C32(0x3cd6bdbe), SPH_C32(0x2989664e), SPH_C32(0xd3b60002), + SPH_C32(0x7f274000), SPH_C32(0xc8dc0000), SPH_C32(0x2c310000), + SPH_C32(0xb14f42c3), SPH_C32(0x6c9219a4), SPH_C32(0x97453192), + SPH_C32(0xac3942a3) }, + { SPH_C32(0xa67f0001), SPH_C32(0x71378000), SPH_C32(0x19fc0000), + SPH_C32(0x96db0000), SPH_C32(0x3a8b6dfd), SPH_C32(0xebcaaef3), + SPH_C32(0x2c6d478f), SPH_C32(0xac8e6c88), SPH_C32(0x50ff0004), + SPH_C32(0x45744000), SPH_C32(0x3dfb0000), SPH_C32(0x19e60000), + SPH_C32(0x1bbc5606), SPH_C32(0xe1727b5d), SPH_C32(0xe1a8cc96), + SPH_C32(0x7b1bd6b9) }, + { SPH_C32(0xd3b60002), SPH_C32(0x7f274000), SPH_C32(0xc8dc0000), + SPH_C32(0x2c310000), SPH_C32(0xb14f42c3), SPH_C32(0x6c9219a4), + SPH_C32(0x97453192), SPH_C32(0xac3942a3), SPH_C32(0xbe300005), + SPH_C32(0x2a220000), SPH_C32(0xcec50000), SPH_C32(0xbe780000), + SPH_C32(0xa609241f), SPH_C32(0x56639098), SPH_C32(0xab938c2c), + SPH_C32(0x85b024ed) }, + { SPH_C32(0x48b00000), SPH_C32(0x1e61c000), SPH_C32(0xeac20000), + SPH_C32(0x31450000), SPH_C32(0x873e1fe4), SPH_C32(0x5cdb4536), + SPH_C32(0x66560735), SPH_C32(0x52259edc), SPH_C32(0xcbf90006), + SPH_C32(0x2432c000), SPH_C32(0x1fe50000), SPH_C32(0x04920000), + SPH_C32(0x2dcd0b21), SPH_C32(0xd13b27cf), SPH_C32(0x10bbfa31), + SPH_C32(0x85070ac6) }, + { SPH_C32(0x3d790003), SPH_C32(0x10710000), SPH_C32(0x3be20000), + SPH_C32(0x8baf0000), SPH_C32(0x0cfa30da), SPH_C32(0xdb83f261), + SPH_C32(0xdd7e7128), SPH_C32(0x5292b0f7), SPH_C32(0x25360007), + SPH_C32(0x4b648000), SPH_C32(0xecdb0000), SPH_C32(0xa30c0000), + SPH_C32(0x90787938), SPH_C32(0x662acc0a), SPH_C32(0x5a80ba8b), + SPH_C32(0x7bacf892) }, + { SPH_C32(0x50ff0004), SPH_C32(0x45744000), SPH_C32(0x3dfb0000), + SPH_C32(0x19e60000), SPH_C32(0x1bbc5606), SPH_C32(0xe1727b5d), + SPH_C32(0xe1a8cc96), SPH_C32(0x7b1bd6b9), SPH_C32(0xf6800005), + SPH_C32(0x3443c000), SPH_C32(0x24070000), SPH_C32(0x8f3d0000), + SPH_C32(0x21373bfb), SPH_C32(0x0ab8d5ae), SPH_C32(0xcdc58b19), + SPH_C32(0xd795ba31) }, + { SPH_C32(0x25360007), SPH_C32(0x4b648000), SPH_C32(0xecdb0000), + SPH_C32(0xa30c0000), SPH_C32(0x90787938), SPH_C32(0x662acc0a), + SPH_C32(0x5a80ba8b), SPH_C32(0x7bacf892), SPH_C32(0x184f0004), + SPH_C32(0x5b158000), SPH_C32(0xd7390000), SPH_C32(0x28a30000), + SPH_C32(0x9c8249e2), SPH_C32(0xbda93e6b), SPH_C32(0x87fecba3), + SPH_C32(0x293e4865) }, + { SPH_C32(0xbe300005), SPH_C32(0x2a220000), SPH_C32(0xcec50000), + SPH_C32(0xbe780000), SPH_C32(0xa609241f), SPH_C32(0x56639098), + SPH_C32(0xab938c2c), SPH_C32(0x85b024ed), SPH_C32(0x6d860007), + SPH_C32(0x55054000), SPH_C32(0x06190000), SPH_C32(0x92490000), + SPH_C32(0x174666dc), SPH_C32(0x3af1893c), SPH_C32(0x3cd6bdbe), + SPH_C32(0x2989664e) }, + { SPH_C32(0xcbf90006), SPH_C32(0x2432c000), SPH_C32(0x1fe50000), + SPH_C32(0x04920000), SPH_C32(0x2dcd0b21), SPH_C32(0xd13b27cf), + SPH_C32(0x10bbfa31), SPH_C32(0x85070ac6), SPH_C32(0x83490006), + SPH_C32(0x3a530000), SPH_C32(0xf5270000), SPH_C32(0x35d70000), + SPH_C32(0xaaf314c5), SPH_C32(0x8de062f9), SPH_C32(0x76edfd04), + SPH_C32(0xd722941a) }, + { SPH_C32(0xf7750009), SPH_C32(0xcf3cc000), SPH_C32(0xc3d60000), + SPH_C32(0x04920000), SPH_C32(0x029519a9), SPH_C32(0xf8e836ba), + SPH_C32(0x7a87f14e), SPH_C32(0x9e16981a), SPH_C32(0xd46a0000), + SPH_C32(0x8dc8c000), SPH_C32(0xa5af0000), SPH_C32(0x4a290000), + SPH_C32(0xfc4e427a), SPH_C32(0xc9b4866c), SPH_C32(0x98369604), + SPH_C32(0xf746c320) }, + { SPH_C32(0x82bc000a), SPH_C32(0xc12c0000), SPH_C32(0x12f60000), + SPH_C32(0xbe780000), SPH_C32(0x89513697), SPH_C32(0x7fb081ed), + SPH_C32(0xc1af8753), SPH_C32(0x9ea1b631), SPH_C32(0x3aa50001), + SPH_C32(0xe29e8000), SPH_C32(0x56910000), SPH_C32(0xedb70000), + SPH_C32(0x41fb3063), SPH_C32(0x7ea56da9), SPH_C32(0xd20dd6be), + SPH_C32(0x09ed3174) }, + { SPH_C32(0x19ba0008), SPH_C32(0xa06a8000), SPH_C32(0x30e80000), + SPH_C32(0xa30c0000), SPH_C32(0xbf206bb0), SPH_C32(0x4ff9dd7f), + SPH_C32(0x30bcb1f4), SPH_C32(0x60bd6a4e), SPH_C32(0x4f6c0002), + SPH_C32(0xec8e4000), SPH_C32(0x87b10000), SPH_C32(0x575d0000), + SPH_C32(0xca3f1f5d), SPH_C32(0xf9fddafe), SPH_C32(0x6925a0a3), + SPH_C32(0x095a1f5f) }, + { SPH_C32(0x6c73000b), SPH_C32(0xae7a4000), SPH_C32(0xe1c80000), + SPH_C32(0x19e60000), SPH_C32(0x34e4448e), SPH_C32(0xc8a16a28), + SPH_C32(0x8b94c7e9), SPH_C32(0x600a4465), SPH_C32(0xa1a30003), + SPH_C32(0x83d80000), SPH_C32(0x748f0000), SPH_C32(0xf0c30000), + SPH_C32(0x778a6d44), SPH_C32(0x4eec313b), SPH_C32(0x231ee019), + SPH_C32(0xf7f1ed0b) }, + { SPH_C32(0x01f5000c), SPH_C32(0xfb7f0000), SPH_C32(0xe7d10000), + SPH_C32(0x8baf0000), SPH_C32(0x23a22252), SPH_C32(0xf250e314), + SPH_C32(0xb7427a57), SPH_C32(0x4983222b), SPH_C32(0x72150001), + SPH_C32(0xfcff4000), SPH_C32(0xbc530000), SPH_C32(0xdcf20000), + SPH_C32(0xc6c52f87), SPH_C32(0x227e289f), SPH_C32(0xb45bd18b), + SPH_C32(0x5bc8afa8) }, + { SPH_C32(0x743c000f), SPH_C32(0xf56fc000), SPH_C32(0x36f10000), + SPH_C32(0x31450000), SPH_C32(0xa8660d6c), SPH_C32(0x75085443), + SPH_C32(0x0c6a0c4a), SPH_C32(0x49340c00), SPH_C32(0x9cda0000), + SPH_C32(0x93a90000), SPH_C32(0x4f6d0000), SPH_C32(0x7b6c0000), + SPH_C32(0x7b705d9e), SPH_C32(0x956fc35a), SPH_C32(0xfe609131), + SPH_C32(0xa5635dfc) }, + { SPH_C32(0xef3a000d), SPH_C32(0x94294000), SPH_C32(0x14ef0000), + SPH_C32(0x2c310000), SPH_C32(0x9e17504b), SPH_C32(0x454108d1), + SPH_C32(0xfd793aed), SPH_C32(0xb728d07f), SPH_C32(0xe9130003), + SPH_C32(0x9db9c000), SPH_C32(0x9e4d0000), SPH_C32(0xc1860000), + SPH_C32(0xf0b472a0), SPH_C32(0x1237740d), SPH_C32(0x4548e72c), + SPH_C32(0xa5d473d7) }, + { SPH_C32(0x9af3000e), SPH_C32(0x9a398000), SPH_C32(0xc5cf0000), + SPH_C32(0x96db0000), SPH_C32(0x15d37f75), SPH_C32(0xc219bf86), + SPH_C32(0x46514cf0), SPH_C32(0xb79ffe54), SPH_C32(0x07dc0002), + SPH_C32(0xf2ef8000), SPH_C32(0x6d730000), SPH_C32(0x66180000), + SPH_C32(0x4d0100b9), SPH_C32(0xa5269fc8), SPH_C32(0x0f73a796), + SPH_C32(0x5b7f8183) }, + { SPH_C32(0x510a0008), SPH_C32(0xbe0b4000), SPH_C32(0xda2a0000), + SPH_C32(0x92490000), SPH_C32(0x381e7454), SPH_C32(0x13229849), + SPH_C32(0x56eab6c1), SPH_C32(0x3298f492), SPH_C32(0x84950004), + SPH_C32(0xc8bc8000), SPH_C32(0x98540000), SPH_C32(0x53cf0000), + SPH_C32(0xe7f2147c), SPH_C32(0x28c6fd31), SPH_C32(0x799e5a92), + SPH_C32(0x8c5d1599) }, + { SPH_C32(0x24c3000b), SPH_C32(0xb01b8000), SPH_C32(0x0b0a0000), + SPH_C32(0x28a30000), SPH_C32(0xb3da5b6a), SPH_C32(0x947a2f1e), + SPH_C32(0xedc2c0dc), SPH_C32(0x322fdab9), SPH_C32(0x6a5a0005), + SPH_C32(0xa7eac000), SPH_C32(0x6b6a0000), SPH_C32(0xf4510000), + SPH_C32(0x5a476665), SPH_C32(0x9fd716f4), SPH_C32(0x33a51a28), + SPH_C32(0x72f6e7cd) }, + { SPH_C32(0xbfc50009), SPH_C32(0xd15d0000), SPH_C32(0x29140000), + SPH_C32(0x35d70000), SPH_C32(0x85ab064d), SPH_C32(0xa433738c), + SPH_C32(0x1cd1f67b), SPH_C32(0xcc3306c6), SPH_C32(0x1f930006), + SPH_C32(0xa9fa0000), SPH_C32(0xba4a0000), SPH_C32(0x4ebb0000), + SPH_C32(0xd183495b), SPH_C32(0x188fa1a3), SPH_C32(0x888d6c35), + SPH_C32(0x7241c9e6) }, + { SPH_C32(0xca0c000a), SPH_C32(0xdf4dc000), SPH_C32(0xf8340000), + SPH_C32(0x8f3d0000), SPH_C32(0x0e6f2973), SPH_C32(0x236bc4db), + SPH_C32(0xa7f98066), SPH_C32(0xcc8428ed), SPH_C32(0xf15c0007), + SPH_C32(0xc6ac4000), SPH_C32(0x49740000), SPH_C32(0xe9250000), + SPH_C32(0x6c363b42), SPH_C32(0xaf9e4a66), SPH_C32(0xc2b62c8f), + SPH_C32(0x8cea3bb2) }, + { SPH_C32(0xa78a000d), SPH_C32(0x8a488000), SPH_C32(0xfe2d0000), + SPH_C32(0x1d740000), SPH_C32(0x19294faf), SPH_C32(0x199a4de7), + SPH_C32(0x9b2f3dd8), SPH_C32(0xe50d4ea3), SPH_C32(0x22ea0005), + SPH_C32(0xb98b0000), SPH_C32(0x81a80000), SPH_C32(0xc5140000), + SPH_C32(0xdd797981), SPH_C32(0xc30c53c2), SPH_C32(0x55f31d1d), + SPH_C32(0x20d37911) }, + { SPH_C32(0xd243000e), SPH_C32(0x84584000), SPH_C32(0x2f0d0000), + SPH_C32(0xa79e0000), SPH_C32(0x92ed6091), SPH_C32(0x9ec2fab0), + SPH_C32(0x20074bc5), SPH_C32(0xe5ba6088), SPH_C32(0xcc250004), + SPH_C32(0xd6dd4000), SPH_C32(0x72960000), SPH_C32(0x628a0000), + SPH_C32(0x60cc0b98), SPH_C32(0x741db807), SPH_C32(0x1fc85da7), + SPH_C32(0xde788b45) }, + { SPH_C32(0x4945000c), SPH_C32(0xe51ec000), SPH_C32(0x0d130000), + SPH_C32(0xbaea0000), SPH_C32(0xa49c3db6), SPH_C32(0xae8ba622), + SPH_C32(0xd1147d62), SPH_C32(0x1ba6bcf7), SPH_C32(0xb9ec0007), + SPH_C32(0xd8cd8000), SPH_C32(0xa3b60000), SPH_C32(0xd8600000), + SPH_C32(0xeb0824a6), SPH_C32(0xf3450f50), SPH_C32(0xa4e02bba), + SPH_C32(0xdecfa56e) }, + { SPH_C32(0x3c8c000f), SPH_C32(0xeb0e0000), SPH_C32(0xdc330000), + SPH_C32(0x00000000), SPH_C32(0x2f581288), SPH_C32(0x29d31175), + SPH_C32(0x6a3c0b7f), SPH_C32(0x1b1192dc), SPH_C32(0x57230006), + SPH_C32(0xb79bc000), SPH_C32(0x50880000), SPH_C32(0x7ffe0000), + SPH_C32(0x56bd56bf), SPH_C32(0x4454e495), SPH_C32(0xeedb6b00), + SPH_C32(0x2064573a) }, + { SPH_C32(0xd46a0000), SPH_C32(0x8dc8c000), SPH_C32(0xa5af0000), + SPH_C32(0x4a290000), SPH_C32(0xfc4e427a), SPH_C32(0xc9b4866c), + SPH_C32(0x98369604), SPH_C32(0xf746c320), SPH_C32(0x231f0009), + SPH_C32(0x42f40000), SPH_C32(0x66790000), SPH_C32(0x4ebb0000), + SPH_C32(0xfedb5bd3), SPH_C32(0x315cb0d6), SPH_C32(0xe2b1674a), + SPH_C32(0x69505b3a) }, + { SPH_C32(0xa1a30003), SPH_C32(0x83d80000), SPH_C32(0x748f0000), + SPH_C32(0xf0c30000), SPH_C32(0x778a6d44), SPH_C32(0x4eec313b), + SPH_C32(0x231ee019), SPH_C32(0xf7f1ed0b), SPH_C32(0xcdd00008), + SPH_C32(0x2da24000), SPH_C32(0x95470000), SPH_C32(0xe9250000), + SPH_C32(0x436e29ca), SPH_C32(0x864d5b13), SPH_C32(0xa88a27f0), + SPH_C32(0x97fba96e) }, + { SPH_C32(0x3aa50001), SPH_C32(0xe29e8000), SPH_C32(0x56910000), + SPH_C32(0xedb70000), SPH_C32(0x41fb3063), SPH_C32(0x7ea56da9), + SPH_C32(0xd20dd6be), SPH_C32(0x09ed3174), SPH_C32(0xb819000b), + SPH_C32(0x23b28000), SPH_C32(0x44670000), SPH_C32(0x53cf0000), + SPH_C32(0xc8aa06f4), SPH_C32(0x0115ec44), SPH_C32(0x13a251ed), + SPH_C32(0x974c8745) }, + { SPH_C32(0x4f6c0002), SPH_C32(0xec8e4000), SPH_C32(0x87b10000), + SPH_C32(0x575d0000), SPH_C32(0xca3f1f5d), SPH_C32(0xf9fddafe), + SPH_C32(0x6925a0a3), SPH_C32(0x095a1f5f), SPH_C32(0x56d6000a), + SPH_C32(0x4ce4c000), SPH_C32(0xb7590000), SPH_C32(0xf4510000), + SPH_C32(0x751f74ed), SPH_C32(0xb6040781), SPH_C32(0x59991157), + SPH_C32(0x69e77511) }, + { SPH_C32(0x22ea0005), SPH_C32(0xb98b0000), SPH_C32(0x81a80000), + SPH_C32(0xc5140000), SPH_C32(0xdd797981), SPH_C32(0xc30c53c2), + SPH_C32(0x55f31d1d), SPH_C32(0x20d37911), SPH_C32(0x85600008), + SPH_C32(0x33c38000), SPH_C32(0x7f850000), SPH_C32(0xd8600000), + SPH_C32(0xc450362e), SPH_C32(0xda961e25), SPH_C32(0xcedc20c5), + SPH_C32(0xc5de37b2) }, + { SPH_C32(0x57230006), SPH_C32(0xb79bc000), SPH_C32(0x50880000), + SPH_C32(0x7ffe0000), SPH_C32(0x56bd56bf), SPH_C32(0x4454e495), + SPH_C32(0xeedb6b00), SPH_C32(0x2064573a), SPH_C32(0x6baf0009), + SPH_C32(0x5c95c000), SPH_C32(0x8cbb0000), SPH_C32(0x7ffe0000), + SPH_C32(0x79e54437), SPH_C32(0x6d87f5e0), SPH_C32(0x84e7607f), + SPH_C32(0x3b75c5e6) }, + { SPH_C32(0xcc250004), SPH_C32(0xd6dd4000), SPH_C32(0x72960000), + SPH_C32(0x628a0000), SPH_C32(0x60cc0b98), SPH_C32(0x741db807), + SPH_C32(0x1fc85da7), SPH_C32(0xde788b45), SPH_C32(0x1e66000a), + SPH_C32(0x52850000), SPH_C32(0x5d9b0000), SPH_C32(0xc5140000), + SPH_C32(0xf2216b09), SPH_C32(0xeadf42b7), SPH_C32(0x3fcf1662), + SPH_C32(0x3bc2ebcd) }, + { SPH_C32(0xb9ec0007), SPH_C32(0xd8cd8000), SPH_C32(0xa3b60000), + SPH_C32(0xd8600000), SPH_C32(0xeb0824a6), SPH_C32(0xf3450f50), + SPH_C32(0xa4e02bba), SPH_C32(0xdecfa56e), SPH_C32(0xf0a9000b), + SPH_C32(0x3dd34000), SPH_C32(0xaea50000), SPH_C32(0x628a0000), + SPH_C32(0x4f941910), SPH_C32(0x5dcea972), SPH_C32(0x75f456d8), + SPH_C32(0xc5691999) }, + { SPH_C32(0x72150001), SPH_C32(0xfcff4000), SPH_C32(0xbc530000), + SPH_C32(0xdcf20000), SPH_C32(0xc6c52f87), SPH_C32(0x227e289f), + SPH_C32(0xb45bd18b), SPH_C32(0x5bc8afa8), SPH_C32(0x73e0000d), + SPH_C32(0x07804000), SPH_C32(0x5b820000), SPH_C32(0x575d0000), + SPH_C32(0xe5670dd5), SPH_C32(0xd02ecb8b), SPH_C32(0x0319abdc), + SPH_C32(0x124b8d83) }, + { SPH_C32(0x07dc0002), SPH_C32(0xf2ef8000), SPH_C32(0x6d730000), + SPH_C32(0x66180000), SPH_C32(0x4d0100b9), SPH_C32(0xa5269fc8), + SPH_C32(0x0f73a796), SPH_C32(0x5b7f8183), SPH_C32(0x9d2f000c), + SPH_C32(0x68d60000), SPH_C32(0xa8bc0000), SPH_C32(0xf0c30000), + SPH_C32(0x58d27fcc), SPH_C32(0x673f204e), SPH_C32(0x4922eb66), + SPH_C32(0xece07fd7) }, + { SPH_C32(0x9cda0000), SPH_C32(0x93a90000), SPH_C32(0x4f6d0000), + SPH_C32(0x7b6c0000), SPH_C32(0x7b705d9e), SPH_C32(0x956fc35a), + SPH_C32(0xfe609131), SPH_C32(0xa5635dfc), SPH_C32(0xe8e6000f), + SPH_C32(0x66c6c000), SPH_C32(0x799c0000), SPH_C32(0x4a290000), + SPH_C32(0xd31650f2), SPH_C32(0xe0679719), SPH_C32(0xf20a9d7b), + SPH_C32(0xec5751fc) }, + { SPH_C32(0xe9130003), SPH_C32(0x9db9c000), SPH_C32(0x9e4d0000), + SPH_C32(0xc1860000), SPH_C32(0xf0b472a0), SPH_C32(0x1237740d), + SPH_C32(0x4548e72c), SPH_C32(0xa5d473d7), SPH_C32(0x0629000e), + SPH_C32(0x09908000), SPH_C32(0x8aa20000), SPH_C32(0xedb70000), + SPH_C32(0x6ea322eb), SPH_C32(0x57767cdc), SPH_C32(0xb831ddc1), + SPH_C32(0x12fca3a8) }, + { SPH_C32(0x84950004), SPH_C32(0xc8bc8000), SPH_C32(0x98540000), + SPH_C32(0x53cf0000), SPH_C32(0xe7f2147c), SPH_C32(0x28c6fd31), + SPH_C32(0x799e5a92), SPH_C32(0x8c5d1599), SPH_C32(0xd59f000c), + SPH_C32(0x76b7c000), SPH_C32(0x427e0000), SPH_C32(0xc1860000), + SPH_C32(0xdfec6028), SPH_C32(0x3be46578), SPH_C32(0x2f74ec53), + SPH_C32(0xbec5e10b) }, + { SPH_C32(0xf15c0007), SPH_C32(0xc6ac4000), SPH_C32(0x49740000), + SPH_C32(0xe9250000), SPH_C32(0x6c363b42), SPH_C32(0xaf9e4a66), + SPH_C32(0xc2b62c8f), SPH_C32(0x8cea3bb2), SPH_C32(0x3b50000d), + SPH_C32(0x19e18000), SPH_C32(0xb1400000), SPH_C32(0x66180000), + SPH_C32(0x62591231), SPH_C32(0x8cf58ebd), SPH_C32(0x654face9), + SPH_C32(0x406e135f) }, + { SPH_C32(0x6a5a0005), SPH_C32(0xa7eac000), SPH_C32(0x6b6a0000), + SPH_C32(0xf4510000), SPH_C32(0x5a476665), SPH_C32(0x9fd716f4), + SPH_C32(0x33a51a28), SPH_C32(0x72f6e7cd), SPH_C32(0x4e99000e), + SPH_C32(0x17f14000), SPH_C32(0x60600000), SPH_C32(0xdcf20000), + SPH_C32(0xe99d3d0f), SPH_C32(0x0bad39ea), SPH_C32(0xde67daf4), + SPH_C32(0x40d93d74) }, + { SPH_C32(0x1f930006), SPH_C32(0xa9fa0000), SPH_C32(0xba4a0000), + SPH_C32(0x4ebb0000), SPH_C32(0xd183495b), SPH_C32(0x188fa1a3), + SPH_C32(0x888d6c35), SPH_C32(0x7241c9e6), SPH_C32(0xa056000f), + SPH_C32(0x78a70000), SPH_C32(0x935e0000), SPH_C32(0x7b6c0000), + SPH_C32(0x54284f16), SPH_C32(0xbcbcd22f), SPH_C32(0x945c9a4e), + SPH_C32(0xbe72cf20) }, + { SPH_C32(0x231f0009), SPH_C32(0x42f40000), SPH_C32(0x66790000), + SPH_C32(0x4ebb0000), SPH_C32(0xfedb5bd3), SPH_C32(0x315cb0d6), + SPH_C32(0xe2b1674a), SPH_C32(0x69505b3a), SPH_C32(0xf7750009), + SPH_C32(0xcf3cc000), SPH_C32(0xc3d60000), SPH_C32(0x04920000), + SPH_C32(0x029519a9), SPH_C32(0xf8e836ba), SPH_C32(0x7a87f14e), + SPH_C32(0x9e16981a) }, + { SPH_C32(0x56d6000a), SPH_C32(0x4ce4c000), SPH_C32(0xb7590000), + SPH_C32(0xf4510000), SPH_C32(0x751f74ed), SPH_C32(0xb6040781), + SPH_C32(0x59991157), SPH_C32(0x69e77511), SPH_C32(0x19ba0008), + SPH_C32(0xa06a8000), SPH_C32(0x30e80000), SPH_C32(0xa30c0000), + SPH_C32(0xbf206bb0), SPH_C32(0x4ff9dd7f), SPH_C32(0x30bcb1f4), + SPH_C32(0x60bd6a4e) }, + { SPH_C32(0xcdd00008), SPH_C32(0x2da24000), SPH_C32(0x95470000), + SPH_C32(0xe9250000), SPH_C32(0x436e29ca), SPH_C32(0x864d5b13), + SPH_C32(0xa88a27f0), SPH_C32(0x97fba96e), SPH_C32(0x6c73000b), + SPH_C32(0xae7a4000), SPH_C32(0xe1c80000), SPH_C32(0x19e60000), + SPH_C32(0x34e4448e), SPH_C32(0xc8a16a28), SPH_C32(0x8b94c7e9), + SPH_C32(0x600a4465) }, + { SPH_C32(0xb819000b), SPH_C32(0x23b28000), SPH_C32(0x44670000), + SPH_C32(0x53cf0000), SPH_C32(0xc8aa06f4), SPH_C32(0x0115ec44), + SPH_C32(0x13a251ed), SPH_C32(0x974c8745), SPH_C32(0x82bc000a), + SPH_C32(0xc12c0000), SPH_C32(0x12f60000), SPH_C32(0xbe780000), + SPH_C32(0x89513697), SPH_C32(0x7fb081ed), SPH_C32(0xc1af8753), + SPH_C32(0x9ea1b631) }, + { SPH_C32(0xd59f000c), SPH_C32(0x76b7c000), SPH_C32(0x427e0000), + SPH_C32(0xc1860000), SPH_C32(0xdfec6028), SPH_C32(0x3be46578), + SPH_C32(0x2f74ec53), SPH_C32(0xbec5e10b), SPH_C32(0x510a0008), + SPH_C32(0xbe0b4000), SPH_C32(0xda2a0000), SPH_C32(0x92490000), + SPH_C32(0x381e7454), SPH_C32(0x13229849), SPH_C32(0x56eab6c1), + SPH_C32(0x3298f492) }, + { SPH_C32(0xa056000f), SPH_C32(0x78a70000), SPH_C32(0x935e0000), + SPH_C32(0x7b6c0000), SPH_C32(0x54284f16), SPH_C32(0xbcbcd22f), + SPH_C32(0x945c9a4e), SPH_C32(0xbe72cf20), SPH_C32(0xbfc50009), + SPH_C32(0xd15d0000), SPH_C32(0x29140000), SPH_C32(0x35d70000), + SPH_C32(0x85ab064d), SPH_C32(0xa433738c), SPH_C32(0x1cd1f67b), + SPH_C32(0xcc3306c6) }, + { SPH_C32(0x3b50000d), SPH_C32(0x19e18000), SPH_C32(0xb1400000), + SPH_C32(0x66180000), SPH_C32(0x62591231), SPH_C32(0x8cf58ebd), + SPH_C32(0x654face9), SPH_C32(0x406e135f), SPH_C32(0xca0c000a), + SPH_C32(0xdf4dc000), SPH_C32(0xf8340000), SPH_C32(0x8f3d0000), + SPH_C32(0x0e6f2973), SPH_C32(0x236bc4db), SPH_C32(0xa7f98066), + SPH_C32(0xcc8428ed) }, + { SPH_C32(0x4e99000e), SPH_C32(0x17f14000), SPH_C32(0x60600000), + SPH_C32(0xdcf20000), SPH_C32(0xe99d3d0f), SPH_C32(0x0bad39ea), + SPH_C32(0xde67daf4), SPH_C32(0x40d93d74), SPH_C32(0x24c3000b), + SPH_C32(0xb01b8000), SPH_C32(0x0b0a0000), SPH_C32(0x28a30000), + SPH_C32(0xb3da5b6a), SPH_C32(0x947a2f1e), SPH_C32(0xedc2c0dc), + SPH_C32(0x322fdab9) }, + { SPH_C32(0x85600008), SPH_C32(0x33c38000), SPH_C32(0x7f850000), + SPH_C32(0xd8600000), SPH_C32(0xc450362e), SPH_C32(0xda961e25), + SPH_C32(0xcedc20c5), SPH_C32(0xc5de37b2), SPH_C32(0xa78a000d), + SPH_C32(0x8a488000), SPH_C32(0xfe2d0000), SPH_C32(0x1d740000), + SPH_C32(0x19294faf), SPH_C32(0x199a4de7), SPH_C32(0x9b2f3dd8), + SPH_C32(0xe50d4ea3) }, + { SPH_C32(0xf0a9000b), SPH_C32(0x3dd34000), SPH_C32(0xaea50000), + SPH_C32(0x628a0000), SPH_C32(0x4f941910), SPH_C32(0x5dcea972), + SPH_C32(0x75f456d8), SPH_C32(0xc5691999), SPH_C32(0x4945000c), + SPH_C32(0xe51ec000), SPH_C32(0x0d130000), SPH_C32(0xbaea0000), + SPH_C32(0xa49c3db6), SPH_C32(0xae8ba622), SPH_C32(0xd1147d62), + SPH_C32(0x1ba6bcf7) }, + { SPH_C32(0x6baf0009), SPH_C32(0x5c95c000), SPH_C32(0x8cbb0000), + SPH_C32(0x7ffe0000), SPH_C32(0x79e54437), SPH_C32(0x6d87f5e0), + SPH_C32(0x84e7607f), SPH_C32(0x3b75c5e6), SPH_C32(0x3c8c000f), + SPH_C32(0xeb0e0000), SPH_C32(0xdc330000), SPH_C32(0x00000000), + SPH_C32(0x2f581288), SPH_C32(0x29d31175), SPH_C32(0x6a3c0b7f), + SPH_C32(0x1b1192dc) }, + { SPH_C32(0x1e66000a), SPH_C32(0x52850000), SPH_C32(0x5d9b0000), + SPH_C32(0xc5140000), SPH_C32(0xf2216b09), SPH_C32(0xeadf42b7), + SPH_C32(0x3fcf1662), SPH_C32(0x3bc2ebcd), SPH_C32(0xd243000e), + SPH_C32(0x84584000), SPH_C32(0x2f0d0000), SPH_C32(0xa79e0000), + SPH_C32(0x92ed6091), SPH_C32(0x9ec2fab0), SPH_C32(0x20074bc5), + SPH_C32(0xe5ba6088) }, + { SPH_C32(0x73e0000d), SPH_C32(0x07804000), SPH_C32(0x5b820000), + SPH_C32(0x575d0000), SPH_C32(0xe5670dd5), SPH_C32(0xd02ecb8b), + SPH_C32(0x0319abdc), SPH_C32(0x124b8d83), SPH_C32(0x01f5000c), + SPH_C32(0xfb7f0000), SPH_C32(0xe7d10000), SPH_C32(0x8baf0000), + SPH_C32(0x23a22252), SPH_C32(0xf250e314), SPH_C32(0xb7427a57), + SPH_C32(0x4983222b) }, + { SPH_C32(0x0629000e), SPH_C32(0x09908000), SPH_C32(0x8aa20000), + SPH_C32(0xedb70000), SPH_C32(0x6ea322eb), SPH_C32(0x57767cdc), + SPH_C32(0xb831ddc1), SPH_C32(0x12fca3a8), SPH_C32(0xef3a000d), + SPH_C32(0x94294000), SPH_C32(0x14ef0000), SPH_C32(0x2c310000), + SPH_C32(0x9e17504b), SPH_C32(0x454108d1), SPH_C32(0xfd793aed), + SPH_C32(0xb728d07f) }, + { SPH_C32(0x9d2f000c), SPH_C32(0x68d60000), SPH_C32(0xa8bc0000), + SPH_C32(0xf0c30000), SPH_C32(0x58d27fcc), SPH_C32(0x673f204e), + SPH_C32(0x4922eb66), SPH_C32(0xece07fd7), SPH_C32(0x9af3000e), + SPH_C32(0x9a398000), SPH_C32(0xc5cf0000), SPH_C32(0x96db0000), + SPH_C32(0x15d37f75), SPH_C32(0xc219bf86), SPH_C32(0x46514cf0), + SPH_C32(0xb79ffe54) }, + { SPH_C32(0xe8e6000f), SPH_C32(0x66c6c000), SPH_C32(0x799c0000), + SPH_C32(0x4a290000), SPH_C32(0xd31650f2), SPH_C32(0xe0679719), + SPH_C32(0xf20a9d7b), SPH_C32(0xec5751fc), SPH_C32(0x743c000f), + SPH_C32(0xf56fc000), SPH_C32(0x36f10000), SPH_C32(0x31450000), + SPH_C32(0xa8660d6c), SPH_C32(0x75085443), SPH_C32(0x0c6a0c4a), + SPH_C32(0x49340c00) } +}; + +static const sph_u32 T512_18[64][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0x0c720000), SPH_C32(0x49e50f00), SPH_C32(0x42790000), + SPH_C32(0x5cea0000), SPH_C32(0x33aa301a), SPH_C32(0x15822514), + SPH_C32(0x95a34b7b), SPH_C32(0xb44b0090), SPH_C32(0xfe220000), + SPH_C32(0xa7580500), SPH_C32(0x25d10000), SPH_C32(0xf7600000), + SPH_C32(0x893178da), SPH_C32(0x1fd4f860), SPH_C32(0x4ed0a315), + SPH_C32(0xa123ff9f) }, + { SPH_C32(0xfe220000), SPH_C32(0xa7580500), SPH_C32(0x25d10000), + SPH_C32(0xf7600000), SPH_C32(0x893178da), SPH_C32(0x1fd4f860), + SPH_C32(0x4ed0a315), SPH_C32(0xa123ff9f), SPH_C32(0xf2500000), + SPH_C32(0xeebd0a00), SPH_C32(0x67a80000), SPH_C32(0xab8a0000), + SPH_C32(0xba9b48c0), SPH_C32(0x0a56dd74), SPH_C32(0xdb73e86e), + SPH_C32(0x1568ff0f) }, + { SPH_C32(0xf2500000), SPH_C32(0xeebd0a00), SPH_C32(0x67a80000), + SPH_C32(0xab8a0000), SPH_C32(0xba9b48c0), SPH_C32(0x0a56dd74), + SPH_C32(0xdb73e86e), SPH_C32(0x1568ff0f), SPH_C32(0x0c720000), + SPH_C32(0x49e50f00), SPH_C32(0x42790000), SPH_C32(0x5cea0000), + SPH_C32(0x33aa301a), SPH_C32(0x15822514), SPH_C32(0x95a34b7b), + SPH_C32(0xb44b0090) }, + { SPH_C32(0x45180000), SPH_C32(0xa5b51700), SPH_C32(0xf96a0000), + SPH_C32(0x3b480000), SPH_C32(0x1ecc142c), SPH_C32(0x231395d6), + SPH_C32(0x16bca6b0), SPH_C32(0xdf33f4df), SPH_C32(0xb83d0000), + SPH_C32(0x16710600), SPH_C32(0x379a0000), SPH_C32(0xf5b10000), + SPH_C32(0x228161ac), SPH_C32(0xae48f145), SPH_C32(0x66241616), + SPH_C32(0xc5c1eb3e) }, + { SPH_C32(0x496a0000), SPH_C32(0xec501800), SPH_C32(0xbb130000), + SPH_C32(0x67a20000), SPH_C32(0x2d662436), SPH_C32(0x3691b0c2), + SPH_C32(0x831fedcb), SPH_C32(0x6b78f44f), SPH_C32(0x461f0000), + SPH_C32(0xb1290300), SPH_C32(0x124b0000), SPH_C32(0x02d10000), + SPH_C32(0xabb01976), SPH_C32(0xb19c0925), SPH_C32(0x28f4b503), + SPH_C32(0x64e214a1) }, + { SPH_C32(0xbb3a0000), SPH_C32(0x02ed1200), SPH_C32(0xdcbb0000), + SPH_C32(0xcc280000), SPH_C32(0x97fd6cf6), SPH_C32(0x3cc76db6), + SPH_C32(0x586c05a5), SPH_C32(0x7e100b40), SPH_C32(0x4a6d0000), + SPH_C32(0xf8cc0c00), SPH_C32(0x50320000), SPH_C32(0x5e3b0000), + SPH_C32(0x981a296c), SPH_C32(0xa41e2c31), SPH_C32(0xbd57fe78), + SPH_C32(0xd0a91431) }, + { SPH_C32(0xb7480000), SPH_C32(0x4b081d00), SPH_C32(0x9ec20000), + SPH_C32(0x90c20000), SPH_C32(0xa4575cec), SPH_C32(0x294548a2), + SPH_C32(0xcdcf4ede), SPH_C32(0xca5b0bd0), SPH_C32(0xb44f0000), + SPH_C32(0x5f940900), SPH_C32(0x75e30000), SPH_C32(0xa95b0000), + SPH_C32(0x112b51b6), SPH_C32(0xbbcad451), SPH_C32(0xf3875d6d), + SPH_C32(0x718aebae) }, + { SPH_C32(0xb83d0000), SPH_C32(0x16710600), SPH_C32(0x379a0000), + SPH_C32(0xf5b10000), SPH_C32(0x228161ac), SPH_C32(0xae48f145), + SPH_C32(0x66241616), SPH_C32(0xc5c1eb3e), SPH_C32(0xfd250000), + SPH_C32(0xb3c41100), SPH_C32(0xcef00000), SPH_C32(0xcef90000), + SPH_C32(0x3c4d7580), SPH_C32(0x8d5b6493), SPH_C32(0x7098b0a6), + SPH_C32(0x1af21fe1) }, + { SPH_C32(0xb44f0000), SPH_C32(0x5f940900), SPH_C32(0x75e30000), + SPH_C32(0xa95b0000), SPH_C32(0x112b51b6), SPH_C32(0xbbcad451), + SPH_C32(0xf3875d6d), SPH_C32(0x718aebae), SPH_C32(0x03070000), + SPH_C32(0x149c1400), SPH_C32(0xeb210000), SPH_C32(0x39990000), + SPH_C32(0xb57c0d5a), SPH_C32(0x928f9cf3), SPH_C32(0x3e4813b3), + SPH_C32(0xbbd1e07e) }, + { SPH_C32(0x461f0000), SPH_C32(0xb1290300), SPH_C32(0x124b0000), + SPH_C32(0x02d10000), SPH_C32(0xabb01976), SPH_C32(0xb19c0925), + SPH_C32(0x28f4b503), SPH_C32(0x64e214a1), SPH_C32(0x0f750000), + SPH_C32(0x5d791b00), SPH_C32(0xa9580000), SPH_C32(0x65730000), + SPH_C32(0x86d63d40), SPH_C32(0x870db9e7), SPH_C32(0xabeb58c8), + SPH_C32(0x0f9ae0ee) }, + { SPH_C32(0x4a6d0000), SPH_C32(0xf8cc0c00), SPH_C32(0x50320000), + SPH_C32(0x5e3b0000), SPH_C32(0x981a296c), SPH_C32(0xa41e2c31), + SPH_C32(0xbd57fe78), SPH_C32(0xd0a91431), SPH_C32(0xf1570000), + SPH_C32(0xfa211e00), SPH_C32(0x8c890000), SPH_C32(0x92130000), + SPH_C32(0x0fe7459a), SPH_C32(0x98d94187), SPH_C32(0xe53bfbdd), + SPH_C32(0xaeb91f71) }, + { SPH_C32(0xfd250000), SPH_C32(0xb3c41100), SPH_C32(0xcef00000), + SPH_C32(0xcef90000), SPH_C32(0x3c4d7580), SPH_C32(0x8d5b6493), + SPH_C32(0x7098b0a6), SPH_C32(0x1af21fe1), SPH_C32(0x45180000), + SPH_C32(0xa5b51700), SPH_C32(0xf96a0000), SPH_C32(0x3b480000), + SPH_C32(0x1ecc142c), SPH_C32(0x231395d6), SPH_C32(0x16bca6b0), + SPH_C32(0xdf33f4df) }, + { SPH_C32(0xf1570000), SPH_C32(0xfa211e00), SPH_C32(0x8c890000), + SPH_C32(0x92130000), SPH_C32(0x0fe7459a), SPH_C32(0x98d94187), + SPH_C32(0xe53bfbdd), SPH_C32(0xaeb91f71), SPH_C32(0xbb3a0000), + SPH_C32(0x02ed1200), SPH_C32(0xdcbb0000), SPH_C32(0xcc280000), + SPH_C32(0x97fd6cf6), SPH_C32(0x3cc76db6), SPH_C32(0x586c05a5), + SPH_C32(0x7e100b40) }, + { SPH_C32(0x03070000), SPH_C32(0x149c1400), SPH_C32(0xeb210000), + SPH_C32(0x39990000), SPH_C32(0xb57c0d5a), SPH_C32(0x928f9cf3), + SPH_C32(0x3e4813b3), SPH_C32(0xbbd1e07e), SPH_C32(0xb7480000), + SPH_C32(0x4b081d00), SPH_C32(0x9ec20000), SPH_C32(0x90c20000), + SPH_C32(0xa4575cec), SPH_C32(0x294548a2), SPH_C32(0xcdcf4ede), + SPH_C32(0xca5b0bd0) }, + { SPH_C32(0x0f750000), SPH_C32(0x5d791b00), SPH_C32(0xa9580000), + SPH_C32(0x65730000), SPH_C32(0x86d63d40), SPH_C32(0x870db9e7), + SPH_C32(0xabeb58c8), SPH_C32(0x0f9ae0ee), SPH_C32(0x496a0000), + SPH_C32(0xec501800), SPH_C32(0xbb130000), SPH_C32(0x67a20000), + SPH_C32(0x2d662436), SPH_C32(0x3691b0c2), SPH_C32(0x831fedcb), + SPH_C32(0x6b78f44f) }, + { SPH_C32(0x75a40000), SPH_C32(0xc28b2700), SPH_C32(0x94a40000), + SPH_C32(0x90f50000), SPH_C32(0xfb7857e0), SPH_C32(0x49ce0bae), + SPH_C32(0x1767c483), SPH_C32(0xaedf667e), SPH_C32(0xd1660000), + SPH_C32(0x1bbc0300), SPH_C32(0x9eec0000), SPH_C32(0xf6940000), + SPH_C32(0x03024527), SPH_C32(0xcf70fcf2), SPH_C32(0xb4431b17), + SPH_C32(0x857f3c2b) }, + { SPH_C32(0x79d60000), SPH_C32(0x8b6e2800), SPH_C32(0xd6dd0000), + SPH_C32(0xcc1f0000), SPH_C32(0xc8d267fa), SPH_C32(0x5c4c2eba), + SPH_C32(0x82c48ff8), SPH_C32(0x1a9466ee), SPH_C32(0x2f440000), + SPH_C32(0xbce40600), SPH_C32(0xbb3d0000), SPH_C32(0x01f40000), + SPH_C32(0x8a333dfd), SPH_C32(0xd0a40492), SPH_C32(0xfa93b802), + SPH_C32(0x245cc3b4) }, + { SPH_C32(0x8b860000), SPH_C32(0x65d32200), SPH_C32(0xb1750000), + SPH_C32(0x67950000), SPH_C32(0x72492f3a), SPH_C32(0x561af3ce), + SPH_C32(0x59b76796), SPH_C32(0x0ffc99e1), SPH_C32(0x23360000), + SPH_C32(0xf5010900), SPH_C32(0xf9440000), SPH_C32(0x5d1e0000), + SPH_C32(0xb9990de7), SPH_C32(0xc5262186), SPH_C32(0x6f30f379), + SPH_C32(0x9017c324) }, + { SPH_C32(0x87f40000), SPH_C32(0x2c362d00), SPH_C32(0xf30c0000), + SPH_C32(0x3b7f0000), SPH_C32(0x41e31f20), SPH_C32(0x4398d6da), + SPH_C32(0xcc142ced), SPH_C32(0xbbb79971), SPH_C32(0xdd140000), + SPH_C32(0x52590c00), SPH_C32(0xdc950000), SPH_C32(0xaa7e0000), + SPH_C32(0x30a8753d), SPH_C32(0xdaf2d9e6), SPH_C32(0x21e0506c), + SPH_C32(0x31343cbb) }, + { SPH_C32(0x30bc0000), SPH_C32(0x673e3000), SPH_C32(0x6dce0000), + SPH_C32(0xabbd0000), SPH_C32(0xe5b443cc), SPH_C32(0x6add9e78), + SPH_C32(0x01db6233), SPH_C32(0x71ec92a1), SPH_C32(0x695b0000), + SPH_C32(0x0dcd0500), SPH_C32(0xa9760000), SPH_C32(0x03250000), + SPH_C32(0x2183248b), SPH_C32(0x61380db7), SPH_C32(0xd2670d01), + SPH_C32(0x40bed715) }, + { SPH_C32(0x3cce0000), SPH_C32(0x2edb3f00), SPH_C32(0x2fb70000), + SPH_C32(0xf7570000), SPH_C32(0xd61e73d6), SPH_C32(0x7f5fbb6c), + SPH_C32(0x94782948), SPH_C32(0xc5a79231), SPH_C32(0x97790000), + SPH_C32(0xaa950000), SPH_C32(0x8ca70000), SPH_C32(0xf4450000), + SPH_C32(0xa8b25c51), SPH_C32(0x7eecf5d7), SPH_C32(0x9cb7ae14), + SPH_C32(0xe19d288a) }, + { SPH_C32(0xce9e0000), SPH_C32(0xc0663500), SPH_C32(0x481f0000), + SPH_C32(0x5cdd0000), SPH_C32(0x6c853b16), SPH_C32(0x75096618), + SPH_C32(0x4f0bc126), SPH_C32(0xd0cf6d3e), SPH_C32(0x9b0b0000), + SPH_C32(0xe3700f00), SPH_C32(0xcede0000), SPH_C32(0xa8af0000), + SPH_C32(0x9b186c4b), SPH_C32(0x6b6ed0c3), SPH_C32(0x0914e56f), + SPH_C32(0x55d6281a) }, + { SPH_C32(0xc2ec0000), SPH_C32(0x89833a00), SPH_C32(0x0a660000), + SPH_C32(0x00370000), SPH_C32(0x5f2f0b0c), SPH_C32(0x608b430c), + SPH_C32(0xdaa88a5d), SPH_C32(0x64846dae), SPH_C32(0x65290000), + SPH_C32(0x44280a00), SPH_C32(0xeb0f0000), SPH_C32(0x5fcf0000), + SPH_C32(0x12291491), SPH_C32(0x74ba28a3), SPH_C32(0x47c4467a), + SPH_C32(0xf4f5d785) }, + { SPH_C32(0xcd990000), SPH_C32(0xd4fa2100), SPH_C32(0xa33e0000), + SPH_C32(0x65440000), SPH_C32(0xd9f9364c), SPH_C32(0xe786faeb), + SPH_C32(0x7143d295), SPH_C32(0x6b1e8d40), SPH_C32(0x2c430000), + SPH_C32(0xa8781200), SPH_C32(0x501c0000), SPH_C32(0x386d0000), + SPH_C32(0x3f4f30a7), SPH_C32(0x422b9861), SPH_C32(0xc4dbabb1), + SPH_C32(0x9f8d23ca) }, + { SPH_C32(0xc1eb0000), SPH_C32(0x9d1f2e00), SPH_C32(0xe1470000), + SPH_C32(0x39ae0000), SPH_C32(0xea530656), SPH_C32(0xf204dfff), + SPH_C32(0xe4e099ee), SPH_C32(0xdf558dd0), SPH_C32(0xd2610000), + SPH_C32(0x0f201700), SPH_C32(0x75cd0000), SPH_C32(0xcf0d0000), + SPH_C32(0xb67e487d), SPH_C32(0x5dff6001), SPH_C32(0x8a0b08a4), + SPH_C32(0x3eaedc55) }, + { SPH_C32(0x33bb0000), SPH_C32(0x73a22400), SPH_C32(0x86ef0000), + SPH_C32(0x92240000), SPH_C32(0x50c84e96), SPH_C32(0xf852028b), + SPH_C32(0x3f937180), SPH_C32(0xca3d72df), SPH_C32(0xde130000), + SPH_C32(0x46c51800), SPH_C32(0x37b40000), SPH_C32(0x93e70000), + SPH_C32(0x85d47867), SPH_C32(0x487d4515), SPH_C32(0x1fa843df), + SPH_C32(0x8ae5dcc5) }, + { SPH_C32(0x3fc90000), SPH_C32(0x3a472b00), SPH_C32(0xc4960000), + SPH_C32(0xcece0000), SPH_C32(0x63627e8c), SPH_C32(0xedd0279f), + SPH_C32(0xaa303afb), SPH_C32(0x7e76724f), SPH_C32(0x20310000), + SPH_C32(0xe19d1d00), SPH_C32(0x12650000), SPH_C32(0x64870000), + SPH_C32(0x0ce500bd), SPH_C32(0x57a9bd75), SPH_C32(0x5178e0ca), + SPH_C32(0x2bc6235a) }, + { SPH_C32(0x88810000), SPH_C32(0x714f3600), SPH_C32(0x5a540000), + SPH_C32(0x5e0c0000), SPH_C32(0xc7352260), SPH_C32(0xc4956f3d), + SPH_C32(0x67ff7425), SPH_C32(0xb42d799f), SPH_C32(0x947e0000), + SPH_C32(0xbe091400), SPH_C32(0x67860000), SPH_C32(0xcddc0000), + SPH_C32(0x1dce510b), SPH_C32(0xec636924), SPH_C32(0xa2ffbda7), + SPH_C32(0x5a4cc8f4) }, + { SPH_C32(0x84f30000), SPH_C32(0x38aa3900), SPH_C32(0x182d0000), + SPH_C32(0x02e60000), SPH_C32(0xf49f127a), SPH_C32(0xd1174a29), + SPH_C32(0xf25c3f5e), SPH_C32(0x0066790f), SPH_C32(0x6a5c0000), + SPH_C32(0x19511100), SPH_C32(0x42570000), SPH_C32(0x3abc0000), + SPH_C32(0x94ff29d1), SPH_C32(0xf3b79144), SPH_C32(0xec2f1eb2), + SPH_C32(0xfb6f376b) }, + { SPH_C32(0x76a30000), SPH_C32(0xd6173300), SPH_C32(0x7f850000), + SPH_C32(0xa96c0000), SPH_C32(0x4e045aba), SPH_C32(0xdb41975d), + SPH_C32(0x292fd730), SPH_C32(0x150e8600), SPH_C32(0x662e0000), + SPH_C32(0x50b41e00), SPH_C32(0x002e0000), SPH_C32(0x66560000), + SPH_C32(0xa75519cb), SPH_C32(0xe635b450), SPH_C32(0x798c55c9), + SPH_C32(0x4f2437fb) }, + { SPH_C32(0x7ad10000), SPH_C32(0x9ff23c00), SPH_C32(0x3dfc0000), + SPH_C32(0xf5860000), SPH_C32(0x7dae6aa0), SPH_C32(0xcec3b249), + SPH_C32(0xbc8c9c4b), SPH_C32(0xa1458690), SPH_C32(0x980c0000), + SPH_C32(0xf7ec1b00), SPH_C32(0x25ff0000), SPH_C32(0x91360000), + SPH_C32(0x2e646111), SPH_C32(0xf9e14c30), SPH_C32(0x375cf6dc), + SPH_C32(0xee07c864) }, + { SPH_C32(0xd1660000), SPH_C32(0x1bbc0300), SPH_C32(0x9eec0000), + SPH_C32(0xf6940000), SPH_C32(0x03024527), SPH_C32(0xcf70fcf2), + SPH_C32(0xb4431b17), SPH_C32(0x857f3c2b), SPH_C32(0xa4c20000), + SPH_C32(0xd9372400), SPH_C32(0x0a480000), SPH_C32(0x66610000), + SPH_C32(0xf87a12c7), SPH_C32(0x86bef75c), SPH_C32(0xa324df94), + SPH_C32(0x2ba05a55) }, + { SPH_C32(0xdd140000), SPH_C32(0x52590c00), SPH_C32(0xdc950000), + SPH_C32(0xaa7e0000), SPH_C32(0x30a8753d), SPH_C32(0xdaf2d9e6), + SPH_C32(0x21e0506c), SPH_C32(0x31343cbb), SPH_C32(0x5ae00000), + SPH_C32(0x7e6f2100), SPH_C32(0x2f990000), SPH_C32(0x91010000), + SPH_C32(0x714b6a1d), SPH_C32(0x996a0f3c), SPH_C32(0xedf47c81), + SPH_C32(0x8a83a5ca) }, + { SPH_C32(0x2f440000), SPH_C32(0xbce40600), SPH_C32(0xbb3d0000), + SPH_C32(0x01f40000), SPH_C32(0x8a333dfd), SPH_C32(0xd0a40492), + SPH_C32(0xfa93b802), SPH_C32(0x245cc3b4), SPH_C32(0x56920000), + SPH_C32(0x378a2e00), SPH_C32(0x6de00000), SPH_C32(0xcdeb0000), + SPH_C32(0x42e15a07), SPH_C32(0x8ce82a28), SPH_C32(0x785737fa), + SPH_C32(0x3ec8a55a) }, + { SPH_C32(0x23360000), SPH_C32(0xf5010900), SPH_C32(0xf9440000), + SPH_C32(0x5d1e0000), SPH_C32(0xb9990de7), SPH_C32(0xc5262186), + SPH_C32(0x6f30f379), SPH_C32(0x9017c324), SPH_C32(0xa8b00000), + SPH_C32(0x90d22b00), SPH_C32(0x48310000), SPH_C32(0x3a8b0000), + SPH_C32(0xcbd022dd), SPH_C32(0x933cd248), SPH_C32(0x368794ef), + SPH_C32(0x9feb5ac5) }, + { SPH_C32(0x947e0000), SPH_C32(0xbe091400), SPH_C32(0x67860000), + SPH_C32(0xcddc0000), SPH_C32(0x1dce510b), SPH_C32(0xec636924), + SPH_C32(0xa2ffbda7), SPH_C32(0x5a4cc8f4), SPH_C32(0x1cff0000), + SPH_C32(0xcf462200), SPH_C32(0x3dd20000), SPH_C32(0x93d00000), + SPH_C32(0xdafb736b), SPH_C32(0x28f60619), SPH_C32(0xc500c982), + SPH_C32(0xee61b16b) }, + { SPH_C32(0x980c0000), SPH_C32(0xf7ec1b00), SPH_C32(0x25ff0000), + SPH_C32(0x91360000), SPH_C32(0x2e646111), SPH_C32(0xf9e14c30), + SPH_C32(0x375cf6dc), SPH_C32(0xee07c864), SPH_C32(0xe2dd0000), + SPH_C32(0x681e2700), SPH_C32(0x18030000), SPH_C32(0x64b00000), + SPH_C32(0x53ca0bb1), SPH_C32(0x3722fe79), SPH_C32(0x8bd06a97), + SPH_C32(0x4f424ef4) }, + { SPH_C32(0x6a5c0000), SPH_C32(0x19511100), SPH_C32(0x42570000), + SPH_C32(0x3abc0000), SPH_C32(0x94ff29d1), SPH_C32(0xf3b79144), + SPH_C32(0xec2f1eb2), SPH_C32(0xfb6f376b), SPH_C32(0xeeaf0000), + SPH_C32(0x21fb2800), SPH_C32(0x5a7a0000), SPH_C32(0x385a0000), + SPH_C32(0x60603bab), SPH_C32(0x22a0db6d), SPH_C32(0x1e7321ec), + SPH_C32(0xfb094e64) }, + { SPH_C32(0x662e0000), SPH_C32(0x50b41e00), SPH_C32(0x002e0000), + SPH_C32(0x66560000), SPH_C32(0xa75519cb), SPH_C32(0xe635b450), + SPH_C32(0x798c55c9), SPH_C32(0x4f2437fb), SPH_C32(0x108d0000), + SPH_C32(0x86a32d00), SPH_C32(0x7fab0000), SPH_C32(0xcf3a0000), + SPH_C32(0xe9514371), SPH_C32(0x3d74230d), SPH_C32(0x50a382f9), + SPH_C32(0x5a2ab1fb) }, + { SPH_C32(0x695b0000), SPH_C32(0x0dcd0500), SPH_C32(0xa9760000), + SPH_C32(0x03250000), SPH_C32(0x2183248b), SPH_C32(0x61380db7), + SPH_C32(0xd2670d01), SPH_C32(0x40bed715), SPH_C32(0x59e70000), + SPH_C32(0x6af33500), SPH_C32(0xc4b80000), SPH_C32(0xa8980000), + SPH_C32(0xc4376747), SPH_C32(0x0be593cf), SPH_C32(0xd3bc6f32), + SPH_C32(0x315245b4) }, + { SPH_C32(0x65290000), SPH_C32(0x44280a00), SPH_C32(0xeb0f0000), + SPH_C32(0x5fcf0000), SPH_C32(0x12291491), SPH_C32(0x74ba28a3), + SPH_C32(0x47c4467a), SPH_C32(0xf4f5d785), SPH_C32(0xa7c50000), + SPH_C32(0xcdab3000), SPH_C32(0xe1690000), SPH_C32(0x5ff80000), + SPH_C32(0x4d061f9d), SPH_C32(0x14316baf), SPH_C32(0x9d6ccc27), + SPH_C32(0x9071ba2b) }, + { SPH_C32(0x97790000), SPH_C32(0xaa950000), SPH_C32(0x8ca70000), + SPH_C32(0xf4450000), SPH_C32(0xa8b25c51), SPH_C32(0x7eecf5d7), + SPH_C32(0x9cb7ae14), SPH_C32(0xe19d288a), SPH_C32(0xabb70000), + SPH_C32(0x844e3f00), SPH_C32(0xa3100000), SPH_C32(0x03120000), + SPH_C32(0x7eac2f87), SPH_C32(0x01b34ebb), SPH_C32(0x08cf875c), + SPH_C32(0x243ababb) }, + { SPH_C32(0x9b0b0000), SPH_C32(0xe3700f00), SPH_C32(0xcede0000), + SPH_C32(0xa8af0000), SPH_C32(0x9b186c4b), SPH_C32(0x6b6ed0c3), + SPH_C32(0x0914e56f), SPH_C32(0x55d6281a), SPH_C32(0x55950000), + SPH_C32(0x23163a00), SPH_C32(0x86c10000), SPH_C32(0xf4720000), + SPH_C32(0xf79d575d), SPH_C32(0x1e67b6db), SPH_C32(0x461f2449), + SPH_C32(0x85194524) }, + { SPH_C32(0x2c430000), SPH_C32(0xa8781200), SPH_C32(0x501c0000), + SPH_C32(0x386d0000), SPH_C32(0x3f4f30a7), SPH_C32(0x422b9861), + SPH_C32(0xc4dbabb1), SPH_C32(0x9f8d23ca), SPH_C32(0xe1da0000), + SPH_C32(0x7c823300), SPH_C32(0xf3220000), SPH_C32(0x5d290000), + SPH_C32(0xe6b606eb), SPH_C32(0xa5ad628a), SPH_C32(0xb5987924), + SPH_C32(0xf493ae8a) }, + { SPH_C32(0x20310000), SPH_C32(0xe19d1d00), SPH_C32(0x12650000), + SPH_C32(0x64870000), SPH_C32(0x0ce500bd), SPH_C32(0x57a9bd75), + SPH_C32(0x5178e0ca), SPH_C32(0x2bc6235a), SPH_C32(0x1ff80000), + SPH_C32(0xdbda3600), SPH_C32(0xd6f30000), SPH_C32(0xaa490000), + SPH_C32(0x6f877e31), SPH_C32(0xba799aea), SPH_C32(0xfb48da31), + SPH_C32(0x55b05115) }, + { SPH_C32(0xd2610000), SPH_C32(0x0f201700), SPH_C32(0x75cd0000), + SPH_C32(0xcf0d0000), SPH_C32(0xb67e487d), SPH_C32(0x5dff6001), + SPH_C32(0x8a0b08a4), SPH_C32(0x3eaedc55), SPH_C32(0x138a0000), + SPH_C32(0x923f3900), SPH_C32(0x948a0000), SPH_C32(0xf6a30000), + SPH_C32(0x5c2d4e2b), SPH_C32(0xaffbbffe), SPH_C32(0x6eeb914a), + SPH_C32(0xe1fb5185) }, + { SPH_C32(0xde130000), SPH_C32(0x46c51800), SPH_C32(0x37b40000), + SPH_C32(0x93e70000), SPH_C32(0x85d47867), SPH_C32(0x487d4515), + SPH_C32(0x1fa843df), SPH_C32(0x8ae5dcc5), SPH_C32(0xeda80000), + SPH_C32(0x35673c00), SPH_C32(0xb15b0000), SPH_C32(0x01c30000), + SPH_C32(0xd51c36f1), SPH_C32(0xb02f479e), SPH_C32(0x203b325f), + SPH_C32(0x40d8ae1a) }, + { SPH_C32(0xa4c20000), SPH_C32(0xd9372400), SPH_C32(0x0a480000), + SPH_C32(0x66610000), SPH_C32(0xf87a12c7), SPH_C32(0x86bef75c), + SPH_C32(0xa324df94), SPH_C32(0x2ba05a55), SPH_C32(0x75a40000), + SPH_C32(0xc28b2700), SPH_C32(0x94a40000), SPH_C32(0x90f50000), + SPH_C32(0xfb7857e0), SPH_C32(0x49ce0bae), SPH_C32(0x1767c483), + SPH_C32(0xaedf667e) }, + { SPH_C32(0xa8b00000), SPH_C32(0x90d22b00), SPH_C32(0x48310000), + SPH_C32(0x3a8b0000), SPH_C32(0xcbd022dd), SPH_C32(0x933cd248), + SPH_C32(0x368794ef), SPH_C32(0x9feb5ac5), SPH_C32(0x8b860000), + SPH_C32(0x65d32200), SPH_C32(0xb1750000), SPH_C32(0x67950000), + SPH_C32(0x72492f3a), SPH_C32(0x561af3ce), SPH_C32(0x59b76796), + SPH_C32(0x0ffc99e1) }, + { SPH_C32(0x5ae00000), SPH_C32(0x7e6f2100), SPH_C32(0x2f990000), + SPH_C32(0x91010000), SPH_C32(0x714b6a1d), SPH_C32(0x996a0f3c), + SPH_C32(0xedf47c81), SPH_C32(0x8a83a5ca), SPH_C32(0x87f40000), + SPH_C32(0x2c362d00), SPH_C32(0xf30c0000), SPH_C32(0x3b7f0000), + SPH_C32(0x41e31f20), SPH_C32(0x4398d6da), SPH_C32(0xcc142ced), + SPH_C32(0xbbb79971) }, + { SPH_C32(0x56920000), SPH_C32(0x378a2e00), SPH_C32(0x6de00000), + SPH_C32(0xcdeb0000), SPH_C32(0x42e15a07), SPH_C32(0x8ce82a28), + SPH_C32(0x785737fa), SPH_C32(0x3ec8a55a), SPH_C32(0x79d60000), + SPH_C32(0x8b6e2800), SPH_C32(0xd6dd0000), SPH_C32(0xcc1f0000), + SPH_C32(0xc8d267fa), SPH_C32(0x5c4c2eba), SPH_C32(0x82c48ff8), + SPH_C32(0x1a9466ee) }, + { SPH_C32(0xe1da0000), SPH_C32(0x7c823300), SPH_C32(0xf3220000), + SPH_C32(0x5d290000), SPH_C32(0xe6b606eb), SPH_C32(0xa5ad628a), + SPH_C32(0xb5987924), SPH_C32(0xf493ae8a), SPH_C32(0xcd990000), + SPH_C32(0xd4fa2100), SPH_C32(0xa33e0000), SPH_C32(0x65440000), + SPH_C32(0xd9f9364c), SPH_C32(0xe786faeb), SPH_C32(0x7143d295), + SPH_C32(0x6b1e8d40) }, + { SPH_C32(0xeda80000), SPH_C32(0x35673c00), SPH_C32(0xb15b0000), + SPH_C32(0x01c30000), SPH_C32(0xd51c36f1), SPH_C32(0xb02f479e), + SPH_C32(0x203b325f), SPH_C32(0x40d8ae1a), SPH_C32(0x33bb0000), + SPH_C32(0x73a22400), SPH_C32(0x86ef0000), SPH_C32(0x92240000), + SPH_C32(0x50c84e96), SPH_C32(0xf852028b), SPH_C32(0x3f937180), + SPH_C32(0xca3d72df) }, + { SPH_C32(0x1ff80000), SPH_C32(0xdbda3600), SPH_C32(0xd6f30000), + SPH_C32(0xaa490000), SPH_C32(0x6f877e31), SPH_C32(0xba799aea), + SPH_C32(0xfb48da31), SPH_C32(0x55b05115), SPH_C32(0x3fc90000), + SPH_C32(0x3a472b00), SPH_C32(0xc4960000), SPH_C32(0xcece0000), + SPH_C32(0x63627e8c), SPH_C32(0xedd0279f), SPH_C32(0xaa303afb), + SPH_C32(0x7e76724f) }, + { SPH_C32(0x138a0000), SPH_C32(0x923f3900), SPH_C32(0x948a0000), + SPH_C32(0xf6a30000), SPH_C32(0x5c2d4e2b), SPH_C32(0xaffbbffe), + SPH_C32(0x6eeb914a), SPH_C32(0xe1fb5185), SPH_C32(0xc1eb0000), + SPH_C32(0x9d1f2e00), SPH_C32(0xe1470000), SPH_C32(0x39ae0000), + SPH_C32(0xea530656), SPH_C32(0xf204dfff), SPH_C32(0xe4e099ee), + SPH_C32(0xdf558dd0) }, + { SPH_C32(0x1cff0000), SPH_C32(0xcf462200), SPH_C32(0x3dd20000), + SPH_C32(0x93d00000), SPH_C32(0xdafb736b), SPH_C32(0x28f60619), + SPH_C32(0xc500c982), SPH_C32(0xee61b16b), SPH_C32(0x88810000), + SPH_C32(0x714f3600), SPH_C32(0x5a540000), SPH_C32(0x5e0c0000), + SPH_C32(0xc7352260), SPH_C32(0xc4956f3d), SPH_C32(0x67ff7425), + SPH_C32(0xb42d799f) }, + { SPH_C32(0x108d0000), SPH_C32(0x86a32d00), SPH_C32(0x7fab0000), + SPH_C32(0xcf3a0000), SPH_C32(0xe9514371), SPH_C32(0x3d74230d), + SPH_C32(0x50a382f9), SPH_C32(0x5a2ab1fb), SPH_C32(0x76a30000), + SPH_C32(0xd6173300), SPH_C32(0x7f850000), SPH_C32(0xa96c0000), + SPH_C32(0x4e045aba), SPH_C32(0xdb41975d), SPH_C32(0x292fd730), + SPH_C32(0x150e8600) }, + { SPH_C32(0xe2dd0000), SPH_C32(0x681e2700), SPH_C32(0x18030000), + SPH_C32(0x64b00000), SPH_C32(0x53ca0bb1), SPH_C32(0x3722fe79), + SPH_C32(0x8bd06a97), SPH_C32(0x4f424ef4), SPH_C32(0x7ad10000), + SPH_C32(0x9ff23c00), SPH_C32(0x3dfc0000), SPH_C32(0xf5860000), + SPH_C32(0x7dae6aa0), SPH_C32(0xcec3b249), SPH_C32(0xbc8c9c4b), + SPH_C32(0xa1458690) }, + { SPH_C32(0xeeaf0000), SPH_C32(0x21fb2800), SPH_C32(0x5a7a0000), + SPH_C32(0x385a0000), SPH_C32(0x60603bab), SPH_C32(0x22a0db6d), + SPH_C32(0x1e7321ec), SPH_C32(0xfb094e64), SPH_C32(0x84f30000), + SPH_C32(0x38aa3900), SPH_C32(0x182d0000), SPH_C32(0x02e60000), + SPH_C32(0xf49f127a), SPH_C32(0xd1174a29), SPH_C32(0xf25c3f5e), + SPH_C32(0x0066790f) }, + { SPH_C32(0x59e70000), SPH_C32(0x6af33500), SPH_C32(0xc4b80000), + SPH_C32(0xa8980000), SPH_C32(0xc4376747), SPH_C32(0x0be593cf), + SPH_C32(0xd3bc6f32), SPH_C32(0x315245b4), SPH_C32(0x30bc0000), + SPH_C32(0x673e3000), SPH_C32(0x6dce0000), SPH_C32(0xabbd0000), + SPH_C32(0xe5b443cc), SPH_C32(0x6add9e78), SPH_C32(0x01db6233), + SPH_C32(0x71ec92a1) }, + { SPH_C32(0x55950000), SPH_C32(0x23163a00), SPH_C32(0x86c10000), + SPH_C32(0xf4720000), SPH_C32(0xf79d575d), SPH_C32(0x1e67b6db), + SPH_C32(0x461f2449), SPH_C32(0x85194524), SPH_C32(0xce9e0000), + SPH_C32(0xc0663500), SPH_C32(0x481f0000), SPH_C32(0x5cdd0000), + SPH_C32(0x6c853b16), SPH_C32(0x75096618), SPH_C32(0x4f0bc126), + SPH_C32(0xd0cf6d3e) }, + { SPH_C32(0xa7c50000), SPH_C32(0xcdab3000), SPH_C32(0xe1690000), + SPH_C32(0x5ff80000), SPH_C32(0x4d061f9d), SPH_C32(0x14316baf), + SPH_C32(0x9d6ccc27), SPH_C32(0x9071ba2b), SPH_C32(0xc2ec0000), + SPH_C32(0x89833a00), SPH_C32(0x0a660000), SPH_C32(0x00370000), + SPH_C32(0x5f2f0b0c), SPH_C32(0x608b430c), SPH_C32(0xdaa88a5d), + SPH_C32(0x64846dae) }, + { SPH_C32(0xabb70000), SPH_C32(0x844e3f00), SPH_C32(0xa3100000), + SPH_C32(0x03120000), SPH_C32(0x7eac2f87), SPH_C32(0x01b34ebb), + SPH_C32(0x08cf875c), SPH_C32(0x243ababb), SPH_C32(0x3cce0000), + SPH_C32(0x2edb3f00), SPH_C32(0x2fb70000), SPH_C32(0xf7570000), + SPH_C32(0xd61e73d6), SPH_C32(0x7f5fbb6c), SPH_C32(0x94782948), + SPH_C32(0xc5a79231) } +}; + +static const sph_u32 T512_24[64][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0x14190000), SPH_C32(0x23ca003c), SPH_C32(0x50df0000), + SPH_C32(0x44b60000), SPH_C32(0x1b6c67b0), SPH_C32(0x3cf3ac75), + SPH_C32(0x61e610b0), SPH_C32(0xdbcadb80), SPH_C32(0xe3430000), + SPH_C32(0x3a4e0014), SPH_C32(0xf2c60000), SPH_C32(0xaa4e0000), + SPH_C32(0xdb1e42a6), SPH_C32(0x256bbe15), SPH_C32(0x123db156), + SPH_C32(0x3a4e99d7) }, + { SPH_C32(0xe3430000), SPH_C32(0x3a4e0014), SPH_C32(0xf2c60000), + SPH_C32(0xaa4e0000), SPH_C32(0xdb1e42a6), SPH_C32(0x256bbe15), + SPH_C32(0x123db156), SPH_C32(0x3a4e99d7), SPH_C32(0xf75a0000), + SPH_C32(0x19840028), SPH_C32(0xa2190000), SPH_C32(0xeef80000), + SPH_C32(0xc0722516), SPH_C32(0x19981260), SPH_C32(0x73dba1e6), + SPH_C32(0xe1844257) }, + { SPH_C32(0xf75a0000), SPH_C32(0x19840028), SPH_C32(0xa2190000), + SPH_C32(0xeef80000), SPH_C32(0xc0722516), SPH_C32(0x19981260), + SPH_C32(0x73dba1e6), SPH_C32(0xe1844257), SPH_C32(0x14190000), + SPH_C32(0x23ca003c), SPH_C32(0x50df0000), SPH_C32(0x44b60000), + SPH_C32(0x1b6c67b0), SPH_C32(0x3cf3ac75), SPH_C32(0x61e610b0), + SPH_C32(0xdbcadb80) }, + { SPH_C32(0x54500000), SPH_C32(0x0671005c), SPH_C32(0x25ae0000), + SPH_C32(0x6a1e0000), SPH_C32(0x2ea54edf), SPH_C32(0x664e8512), + SPH_C32(0xbfba18c3), SPH_C32(0x7e715d17), SPH_C32(0xbc8d0000), + SPH_C32(0xfc3b0018), SPH_C32(0x19830000), SPH_C32(0xd10b0000), + SPH_C32(0xae1878c4), SPH_C32(0x42a69856), SPH_C32(0x0012da37), + SPH_C32(0x2c3b504e) }, + { SPH_C32(0x40490000), SPH_C32(0x25bb0060), SPH_C32(0x75710000), + SPH_C32(0x2ea80000), SPH_C32(0x35c9296f), SPH_C32(0x5abd2967), + SPH_C32(0xde5c0873), SPH_C32(0xa5bb8697), SPH_C32(0x5fce0000), + SPH_C32(0xc675000c), SPH_C32(0xeb450000), SPH_C32(0x7b450000), + SPH_C32(0x75063a62), SPH_C32(0x67cd2643), SPH_C32(0x122f6b61), + SPH_C32(0x1675c999) }, + { SPH_C32(0xb7130000), SPH_C32(0x3c3f0048), SPH_C32(0xd7680000), + SPH_C32(0xc0500000), SPH_C32(0xf5bb0c79), SPH_C32(0x43253b07), + SPH_C32(0xad87a995), SPH_C32(0x443fc4c0), SPH_C32(0x4bd70000), + SPH_C32(0xe5bf0030), SPH_C32(0xbb9a0000), SPH_C32(0x3ff30000), + SPH_C32(0x6e6a5dd2), SPH_C32(0x5b3e8a36), SPH_C32(0x73c97bd1), + SPH_C32(0xcdbf1219) }, + { SPH_C32(0xa30a0000), SPH_C32(0x1ff50074), SPH_C32(0x87b70000), + SPH_C32(0x84e60000), SPH_C32(0xeed76bc9), SPH_C32(0x7fd69772), + SPH_C32(0xcc61b925), SPH_C32(0x9ff51f40), SPH_C32(0xa8940000), + SPH_C32(0xdff10024), SPH_C32(0x495c0000), SPH_C32(0x95bd0000), + SPH_C32(0xb5741f74), SPH_C32(0x7e553423), SPH_C32(0x61f4ca87), + SPH_C32(0xf7f18bce) }, + { SPH_C32(0xbc8d0000), SPH_C32(0xfc3b0018), SPH_C32(0x19830000), + SPH_C32(0xd10b0000), SPH_C32(0xae1878c4), SPH_C32(0x42a69856), + SPH_C32(0x0012da37), SPH_C32(0x2c3b504e), SPH_C32(0xe8dd0000), + SPH_C32(0xfa4a0044), SPH_C32(0x3c2d0000), SPH_C32(0xbb150000), + SPH_C32(0x80bd361b), SPH_C32(0x24e81d44), SPH_C32(0xbfa8c2f4), + SPH_C32(0x524a0d59) }, + { SPH_C32(0xa8940000), SPH_C32(0xdff10024), SPH_C32(0x495c0000), + SPH_C32(0x95bd0000), SPH_C32(0xb5741f74), SPH_C32(0x7e553423), + SPH_C32(0x61f4ca87), SPH_C32(0xf7f18bce), SPH_C32(0x0b9e0000), + SPH_C32(0xc0040050), SPH_C32(0xceeb0000), SPH_C32(0x115b0000), + SPH_C32(0x5ba374bd), SPH_C32(0x0183a351), SPH_C32(0xad9573a2), + SPH_C32(0x6804948e) }, + { SPH_C32(0x5fce0000), SPH_C32(0xc675000c), SPH_C32(0xeb450000), + SPH_C32(0x7b450000), SPH_C32(0x75063a62), SPH_C32(0x67cd2643), + SPH_C32(0x122f6b61), SPH_C32(0x1675c999), SPH_C32(0x1f870000), + SPH_C32(0xe3ce006c), SPH_C32(0x9e340000), SPH_C32(0x55ed0000), + SPH_C32(0x40cf130d), SPH_C32(0x3d700f24), SPH_C32(0xcc736312), + SPH_C32(0xb3ce4f0e) }, + { SPH_C32(0x4bd70000), SPH_C32(0xe5bf0030), SPH_C32(0xbb9a0000), + SPH_C32(0x3ff30000), SPH_C32(0x6e6a5dd2), SPH_C32(0x5b3e8a36), + SPH_C32(0x73c97bd1), SPH_C32(0xcdbf1219), SPH_C32(0xfcc40000), + SPH_C32(0xd9800078), SPH_C32(0x6cf20000), SPH_C32(0xffa30000), + SPH_C32(0x9bd151ab), SPH_C32(0x181bb131), SPH_C32(0xde4ed244), + SPH_C32(0x8980d6d9) }, + { SPH_C32(0xe8dd0000), SPH_C32(0xfa4a0044), SPH_C32(0x3c2d0000), + SPH_C32(0xbb150000), SPH_C32(0x80bd361b), SPH_C32(0x24e81d44), + SPH_C32(0xbfa8c2f4), SPH_C32(0x524a0d59), SPH_C32(0x54500000), + SPH_C32(0x0671005c), SPH_C32(0x25ae0000), SPH_C32(0x6a1e0000), + SPH_C32(0x2ea54edf), SPH_C32(0x664e8512), SPH_C32(0xbfba18c3), + SPH_C32(0x7e715d17) }, + { SPH_C32(0xfcc40000), SPH_C32(0xd9800078), SPH_C32(0x6cf20000), + SPH_C32(0xffa30000), SPH_C32(0x9bd151ab), SPH_C32(0x181bb131), + SPH_C32(0xde4ed244), SPH_C32(0x8980d6d9), SPH_C32(0xb7130000), + SPH_C32(0x3c3f0048), SPH_C32(0xd7680000), SPH_C32(0xc0500000), + SPH_C32(0xf5bb0c79), SPH_C32(0x43253b07), SPH_C32(0xad87a995), + SPH_C32(0x443fc4c0) }, + { SPH_C32(0x0b9e0000), SPH_C32(0xc0040050), SPH_C32(0xceeb0000), + SPH_C32(0x115b0000), SPH_C32(0x5ba374bd), SPH_C32(0x0183a351), + SPH_C32(0xad9573a2), SPH_C32(0x6804948e), SPH_C32(0xa30a0000), + SPH_C32(0x1ff50074), SPH_C32(0x87b70000), SPH_C32(0x84e60000), + SPH_C32(0xeed76bc9), SPH_C32(0x7fd69772), SPH_C32(0xcc61b925), + SPH_C32(0x9ff51f40) }, + { SPH_C32(0x1f870000), SPH_C32(0xe3ce006c), SPH_C32(0x9e340000), + SPH_C32(0x55ed0000), SPH_C32(0x40cf130d), SPH_C32(0x3d700f24), + SPH_C32(0xcc736312), SPH_C32(0xb3ce4f0e), SPH_C32(0x40490000), + SPH_C32(0x25bb0060), SPH_C32(0x75710000), SPH_C32(0x2ea80000), + SPH_C32(0x35c9296f), SPH_C32(0x5abd2967), SPH_C32(0xde5c0873), + SPH_C32(0xa5bb8697) }, + { SPH_C32(0x69510000), SPH_C32(0xd4e1009c), SPH_C32(0xc3230000), + SPH_C32(0xac2f0000), SPH_C32(0xe4950bae), SPH_C32(0xcea415dc), + SPH_C32(0x87ec287c), SPH_C32(0xbce1a3ce), SPH_C32(0xc6730000), + SPH_C32(0xaf8d000c), SPH_C32(0xa4c10000), SPH_C32(0x218d0000), + SPH_C32(0x23111587), SPH_C32(0x7913512f), SPH_C32(0x1d28ac88), + SPH_C32(0x378dd173) }, + { SPH_C32(0x7d480000), SPH_C32(0xf72b00a0), SPH_C32(0x93fc0000), + SPH_C32(0xe8990000), SPH_C32(0xfff96c1e), SPH_C32(0xf257b9a9), + SPH_C32(0xe60a38cc), SPH_C32(0x672b784e), SPH_C32(0x25300000), + SPH_C32(0x95c30018), SPH_C32(0x56070000), SPH_C32(0x8bc30000), + SPH_C32(0xf80f5721), SPH_C32(0x5c78ef3a), SPH_C32(0x0f151dde), + SPH_C32(0x0dc348a4) }, + { SPH_C32(0x8a120000), SPH_C32(0xeeaf0088), SPH_C32(0x31e50000), + SPH_C32(0x06610000), SPH_C32(0x3f8b4908), SPH_C32(0xebcfabc9), + SPH_C32(0x95d1992a), SPH_C32(0x86af3a19), SPH_C32(0x31290000), + SPH_C32(0xb6090024), SPH_C32(0x06d80000), SPH_C32(0xcf750000), + SPH_C32(0xe3633091), SPH_C32(0x608b434f), SPH_C32(0x6ef30d6e), + SPH_C32(0xd6099324) }, + { SPH_C32(0x9e0b0000), SPH_C32(0xcd6500b4), SPH_C32(0x613a0000), + SPH_C32(0x42d70000), SPH_C32(0x24e72eb8), SPH_C32(0xd73c07bc), + SPH_C32(0xf437899a), SPH_C32(0x5d65e199), SPH_C32(0xd26a0000), + SPH_C32(0x8c470030), SPH_C32(0xf41e0000), SPH_C32(0x653b0000), + SPH_C32(0x387d7237), SPH_C32(0x45e0fd5a), SPH_C32(0x7ccebc38), + SPH_C32(0xec470af3) }, + { SPH_C32(0x3d010000), SPH_C32(0xd29000c0), SPH_C32(0xe68d0000), + SPH_C32(0xc6310000), SPH_C32(0xca304571), SPH_C32(0xa8ea90ce), + SPH_C32(0x385630bf), SPH_C32(0xc290fed9), SPH_C32(0x7afe0000), + SPH_C32(0x53b60014), SPH_C32(0xbd420000), SPH_C32(0xf0860000), + SPH_C32(0x8d096d43), SPH_C32(0x3bb5c979), SPH_C32(0x1d3a76bf), + SPH_C32(0x1bb6813d) }, + { SPH_C32(0x29180000), SPH_C32(0xf15a00fc), SPH_C32(0xb6520000), + SPH_C32(0x82870000), SPH_C32(0xd15c22c1), SPH_C32(0x94193cbb), + SPH_C32(0x59b0200f), SPH_C32(0x195a2559), SPH_C32(0x99bd0000), + SPH_C32(0x69f80000), SPH_C32(0x4f840000), SPH_C32(0x5ac80000), + SPH_C32(0x56172fe5), SPH_C32(0x1ede776c), SPH_C32(0x0f07c7e9), + SPH_C32(0x21f818ea) }, + { SPH_C32(0xde420000), SPH_C32(0xe8de00d4), SPH_C32(0x144b0000), + SPH_C32(0x6c7f0000), SPH_C32(0x112e07d7), SPH_C32(0x8d812edb), + SPH_C32(0x2a6b81e9), SPH_C32(0xf8de670e), SPH_C32(0x8da40000), + SPH_C32(0x4a32003c), SPH_C32(0x1f5b0000), SPH_C32(0x1e7e0000), + SPH_C32(0x4d7b4855), SPH_C32(0x222ddb19), SPH_C32(0x6ee1d759), + SPH_C32(0xfa32c36a) }, + { SPH_C32(0xca5b0000), SPH_C32(0xcb1400e8), SPH_C32(0x44940000), + SPH_C32(0x28c90000), SPH_C32(0x0a426067), SPH_C32(0xb17282ae), + SPH_C32(0x4b8d9159), SPH_C32(0x2314bc8e), SPH_C32(0x6ee70000), + SPH_C32(0x707c0028), SPH_C32(0xed9d0000), SPH_C32(0xb4300000), + SPH_C32(0x96650af3), SPH_C32(0x0746650c), SPH_C32(0x7cdc660f), + SPH_C32(0xc07c5abd) }, + { SPH_C32(0xd5dc0000), SPH_C32(0x28da0084), SPH_C32(0xdaa00000), + SPH_C32(0x7d240000), SPH_C32(0x4a8d736a), SPH_C32(0x8c028d8a), + SPH_C32(0x87fef24b), SPH_C32(0x90daf380), SPH_C32(0x2eae0000), + SPH_C32(0x55c70048), SPH_C32(0x98ec0000), SPH_C32(0x9a980000), + SPH_C32(0xa3ac239c), SPH_C32(0x5dfb4c6b), SPH_C32(0xa2806e7c), + SPH_C32(0x65c7dc2a) }, + { SPH_C32(0xc1c50000), SPH_C32(0x0b1000b8), SPH_C32(0x8a7f0000), + SPH_C32(0x39920000), SPH_C32(0x51e114da), SPH_C32(0xb0f121ff), + SPH_C32(0xe618e2fb), SPH_C32(0x4b102800), SPH_C32(0xcded0000), + SPH_C32(0x6f89005c), SPH_C32(0x6a2a0000), SPH_C32(0x30d60000), + SPH_C32(0x78b2613a), SPH_C32(0x7890f27e), SPH_C32(0xb0bddf2a), + SPH_C32(0x5f8945fd) }, + { SPH_C32(0x369f0000), SPH_C32(0x12940090), SPH_C32(0x28660000), + SPH_C32(0xd76a0000), SPH_C32(0x919331cc), SPH_C32(0xa969339f), + SPH_C32(0x95c3431d), SPH_C32(0xaa946a57), SPH_C32(0xd9f40000), + SPH_C32(0x4c430060), SPH_C32(0x3af50000), SPH_C32(0x74600000), + SPH_C32(0x63de068a), SPH_C32(0x44635e0b), SPH_C32(0xd15bcf9a), + SPH_C32(0x84439e7d) }, + { SPH_C32(0x22860000), SPH_C32(0x315e00ac), SPH_C32(0x78b90000), + SPH_C32(0x93dc0000), SPH_C32(0x8aff567c), SPH_C32(0x959a9fea), + SPH_C32(0xf42553ad), SPH_C32(0x715eb1d7), SPH_C32(0x3ab70000), + SPH_C32(0x760d0074), SPH_C32(0xc8330000), SPH_C32(0xde2e0000), + SPH_C32(0xb8c0442c), SPH_C32(0x6108e01e), SPH_C32(0xc3667ecc), + SPH_C32(0xbe0d07aa) }, + { SPH_C32(0x818c0000), SPH_C32(0x2eab00d8), SPH_C32(0xff0e0000), + SPH_C32(0x173a0000), SPH_C32(0x64283db5), SPH_C32(0xea4c0898), + SPH_C32(0x3844ea88), SPH_C32(0xeeabae97), SPH_C32(0x92230000), + SPH_C32(0xa9fc0050), SPH_C32(0x816f0000), SPH_C32(0x4b930000), + SPH_C32(0x0db45b58), SPH_C32(0x1f5dd43d), SPH_C32(0xa292b44b), + SPH_C32(0x49fc8c64) }, + { SPH_C32(0x95950000), SPH_C32(0x0d6100e4), SPH_C32(0xafd10000), + SPH_C32(0x538c0000), SPH_C32(0x7f445a05), SPH_C32(0xd6bfa4ed), + SPH_C32(0x59a2fa38), SPH_C32(0x35617517), SPH_C32(0x71600000), + SPH_C32(0x93b20044), SPH_C32(0x73a90000), SPH_C32(0xe1dd0000), + SPH_C32(0xd6aa19fe), SPH_C32(0x3a366a28), SPH_C32(0xb0af051d), + SPH_C32(0x73b215b3) }, + { SPH_C32(0x62cf0000), SPH_C32(0x14e500cc), SPH_C32(0x0dc80000), + SPH_C32(0xbd740000), SPH_C32(0xbf367f13), SPH_C32(0xcf27b68d), + SPH_C32(0x2a795bde), SPH_C32(0xd4e53740), SPH_C32(0x65790000), + SPH_C32(0xb0780078), SPH_C32(0x23760000), SPH_C32(0xa56b0000), + SPH_C32(0xcdc67e4e), SPH_C32(0x06c5c65d), SPH_C32(0xd14915ad), + SPH_C32(0xa878ce33) }, + { SPH_C32(0x76d60000), SPH_C32(0x372f00f0), SPH_C32(0x5d170000), + SPH_C32(0xf9c20000), SPH_C32(0xa45a18a3), SPH_C32(0xf3d41af8), + SPH_C32(0x4b9f4b6e), SPH_C32(0x0f2fecc0), SPH_C32(0x863a0000), + SPH_C32(0x8a36006c), SPH_C32(0xd1b00000), SPH_C32(0x0f250000), + SPH_C32(0x16d83ce8), SPH_C32(0x23ae7848), SPH_C32(0xc374a4fb), + SPH_C32(0x923657e4) }, + { SPH_C32(0xc6730000), SPH_C32(0xaf8d000c), SPH_C32(0xa4c10000), + SPH_C32(0x218d0000), SPH_C32(0x23111587), SPH_C32(0x7913512f), + SPH_C32(0x1d28ac88), SPH_C32(0x378dd173), SPH_C32(0xaf220000), + SPH_C32(0x7b6c0090), SPH_C32(0x67e20000), SPH_C32(0x8da20000), + SPH_C32(0xc7841e29), SPH_C32(0xb7b744f3), SPH_C32(0x9ac484f4), + SPH_C32(0x8b6c72bd) }, + { SPH_C32(0xd26a0000), SPH_C32(0x8c470030), SPH_C32(0xf41e0000), + SPH_C32(0x653b0000), SPH_C32(0x387d7237), SPH_C32(0x45e0fd5a), + SPH_C32(0x7ccebc38), SPH_C32(0xec470af3), SPH_C32(0x4c610000), + SPH_C32(0x41220084), SPH_C32(0x95240000), SPH_C32(0x27ec0000), + SPH_C32(0x1c9a5c8f), SPH_C32(0x92dcfae6), SPH_C32(0x88f935a2), + SPH_C32(0xb122eb6a) }, + { SPH_C32(0x25300000), SPH_C32(0x95c30018), SPH_C32(0x56070000), + SPH_C32(0x8bc30000), SPH_C32(0xf80f5721), SPH_C32(0x5c78ef3a), + SPH_C32(0x0f151dde), SPH_C32(0x0dc348a4), SPH_C32(0x58780000), + SPH_C32(0x62e800b8), SPH_C32(0xc5fb0000), SPH_C32(0x635a0000), + SPH_C32(0x07f63b3f), SPH_C32(0xae2f5693), SPH_C32(0xe91f2512), + SPH_C32(0x6ae830ea) }, + { SPH_C32(0x31290000), SPH_C32(0xb6090024), SPH_C32(0x06d80000), + SPH_C32(0xcf750000), SPH_C32(0xe3633091), SPH_C32(0x608b434f), + SPH_C32(0x6ef30d6e), SPH_C32(0xd6099324), SPH_C32(0xbb3b0000), + SPH_C32(0x58a600ac), SPH_C32(0x373d0000), SPH_C32(0xc9140000), + SPH_C32(0xdce87999), SPH_C32(0x8b44e886), SPH_C32(0xfb229444), + SPH_C32(0x50a6a93d) }, + { SPH_C32(0x92230000), SPH_C32(0xa9fc0050), SPH_C32(0x816f0000), + SPH_C32(0x4b930000), SPH_C32(0x0db45b58), SPH_C32(0x1f5dd43d), + SPH_C32(0xa292b44b), SPH_C32(0x49fc8c64), SPH_C32(0x13af0000), + SPH_C32(0x87570088), SPH_C32(0x7e610000), SPH_C32(0x5ca90000), + SPH_C32(0x699c66ed), SPH_C32(0xf511dca5), SPH_C32(0x9ad65ec3), + SPH_C32(0xa75722f3) }, + { SPH_C32(0x863a0000), SPH_C32(0x8a36006c), SPH_C32(0xd1b00000), + SPH_C32(0x0f250000), SPH_C32(0x16d83ce8), SPH_C32(0x23ae7848), + SPH_C32(0xc374a4fb), SPH_C32(0x923657e4), SPH_C32(0xf0ec0000), + SPH_C32(0xbd19009c), SPH_C32(0x8ca70000), SPH_C32(0xf6e70000), + SPH_C32(0xb282244b), SPH_C32(0xd07a62b0), SPH_C32(0x88ebef95), + SPH_C32(0x9d19bb24) }, + { SPH_C32(0x71600000), SPH_C32(0x93b20044), SPH_C32(0x73a90000), + SPH_C32(0xe1dd0000), SPH_C32(0xd6aa19fe), SPH_C32(0x3a366a28), + SPH_C32(0xb0af051d), SPH_C32(0x73b215b3), SPH_C32(0xe4f50000), + SPH_C32(0x9ed300a0), SPH_C32(0xdc780000), SPH_C32(0xb2510000), + SPH_C32(0xa9ee43fb), SPH_C32(0xec89cec5), SPH_C32(0xe90dff25), + SPH_C32(0x46d360a4) }, + { SPH_C32(0x65790000), SPH_C32(0xb0780078), SPH_C32(0x23760000), + SPH_C32(0xa56b0000), SPH_C32(0xcdc67e4e), SPH_C32(0x06c5c65d), + SPH_C32(0xd14915ad), SPH_C32(0xa878ce33), SPH_C32(0x07b60000), + SPH_C32(0xa49d00b4), SPH_C32(0x2ebe0000), SPH_C32(0x181f0000), + SPH_C32(0x72f0015d), SPH_C32(0xc9e270d0), SPH_C32(0xfb304e73), + SPH_C32(0x7c9df973) }, + { SPH_C32(0x7afe0000), SPH_C32(0x53b60014), SPH_C32(0xbd420000), + SPH_C32(0xf0860000), SPH_C32(0x8d096d43), SPH_C32(0x3bb5c979), + SPH_C32(0x1d3a76bf), SPH_C32(0x1bb6813d), SPH_C32(0x47ff0000), + SPH_C32(0x812600d4), SPH_C32(0x5bcf0000), SPH_C32(0x36b70000), + SPH_C32(0x47392832), SPH_C32(0x935f59b7), SPH_C32(0x256c4600), + SPH_C32(0xd9267fe4) }, + { SPH_C32(0x6ee70000), SPH_C32(0x707c0028), SPH_C32(0xed9d0000), + SPH_C32(0xb4300000), SPH_C32(0x96650af3), SPH_C32(0x0746650c), + SPH_C32(0x7cdc660f), SPH_C32(0xc07c5abd), SPH_C32(0xa4bc0000), + SPH_C32(0xbb6800c0), SPH_C32(0xa9090000), SPH_C32(0x9cf90000), + SPH_C32(0x9c276a94), SPH_C32(0xb634e7a2), SPH_C32(0x3751f756), + SPH_C32(0xe368e633) }, + { SPH_C32(0x99bd0000), SPH_C32(0x69f80000), SPH_C32(0x4f840000), + SPH_C32(0x5ac80000), SPH_C32(0x56172fe5), SPH_C32(0x1ede776c), + SPH_C32(0x0f07c7e9), SPH_C32(0x21f818ea), SPH_C32(0xb0a50000), + SPH_C32(0x98a200fc), SPH_C32(0xf9d60000), SPH_C32(0xd84f0000), + SPH_C32(0x874b0d24), SPH_C32(0x8ac74bd7), SPH_C32(0x56b7e7e6), + SPH_C32(0x38a23db3) }, + { SPH_C32(0x8da40000), SPH_C32(0x4a32003c), SPH_C32(0x1f5b0000), + SPH_C32(0x1e7e0000), SPH_C32(0x4d7b4855), SPH_C32(0x222ddb19), + SPH_C32(0x6ee1d759), SPH_C32(0xfa32c36a), SPH_C32(0x53e60000), + SPH_C32(0xa2ec00e8), SPH_C32(0x0b100000), SPH_C32(0x72010000), + SPH_C32(0x5c554f82), SPH_C32(0xafacf5c2), SPH_C32(0x448a56b0), + SPH_C32(0x02eca464) }, + { SPH_C32(0x2eae0000), SPH_C32(0x55c70048), SPH_C32(0x98ec0000), + SPH_C32(0x9a980000), SPH_C32(0xa3ac239c), SPH_C32(0x5dfb4c6b), + SPH_C32(0xa2806e7c), SPH_C32(0x65c7dc2a), SPH_C32(0xfb720000), + SPH_C32(0x7d1d00cc), SPH_C32(0x424c0000), SPH_C32(0xe7bc0000), + SPH_C32(0xe92150f6), SPH_C32(0xd1f9c1e1), SPH_C32(0x257e9c37), + SPH_C32(0xf51d2faa) }, + { SPH_C32(0x3ab70000), SPH_C32(0x760d0074), SPH_C32(0xc8330000), + SPH_C32(0xde2e0000), SPH_C32(0xb8c0442c), SPH_C32(0x6108e01e), + SPH_C32(0xc3667ecc), SPH_C32(0xbe0d07aa), SPH_C32(0x18310000), + SPH_C32(0x475300d8), SPH_C32(0xb08a0000), SPH_C32(0x4df20000), + SPH_C32(0x323f1250), SPH_C32(0xf4927ff4), SPH_C32(0x37432d61), + SPH_C32(0xcf53b67d) }, + { SPH_C32(0xcded0000), SPH_C32(0x6f89005c), SPH_C32(0x6a2a0000), + SPH_C32(0x30d60000), SPH_C32(0x78b2613a), SPH_C32(0x7890f27e), + SPH_C32(0xb0bddf2a), SPH_C32(0x5f8945fd), SPH_C32(0x0c280000), + SPH_C32(0x649900e4), SPH_C32(0xe0550000), SPH_C32(0x09440000), + SPH_C32(0x295375e0), SPH_C32(0xc861d381), SPH_C32(0x56a53dd1), + SPH_C32(0x14996dfd) }, + { SPH_C32(0xd9f40000), SPH_C32(0x4c430060), SPH_C32(0x3af50000), + SPH_C32(0x74600000), SPH_C32(0x63de068a), SPH_C32(0x44635e0b), + SPH_C32(0xd15bcf9a), SPH_C32(0x84439e7d), SPH_C32(0xef6b0000), + SPH_C32(0x5ed700f0), SPH_C32(0x12930000), SPH_C32(0xa30a0000), + SPH_C32(0xf24d3746), SPH_C32(0xed0a6d94), SPH_C32(0x44988c87), + SPH_C32(0x2ed7f42a) }, + { SPH_C32(0xaf220000), SPH_C32(0x7b6c0090), SPH_C32(0x67e20000), + SPH_C32(0x8da20000), SPH_C32(0xc7841e29), SPH_C32(0xb7b744f3), + SPH_C32(0x9ac484f4), SPH_C32(0x8b6c72bd), SPH_C32(0x69510000), + SPH_C32(0xd4e1009c), SPH_C32(0xc3230000), SPH_C32(0xac2f0000), + SPH_C32(0xe4950bae), SPH_C32(0xcea415dc), SPH_C32(0x87ec287c), + SPH_C32(0xbce1a3ce) }, + { SPH_C32(0xbb3b0000), SPH_C32(0x58a600ac), SPH_C32(0x373d0000), + SPH_C32(0xc9140000), SPH_C32(0xdce87999), SPH_C32(0x8b44e886), + SPH_C32(0xfb229444), SPH_C32(0x50a6a93d), SPH_C32(0x8a120000), + SPH_C32(0xeeaf0088), SPH_C32(0x31e50000), SPH_C32(0x06610000), + SPH_C32(0x3f8b4908), SPH_C32(0xebcfabc9), SPH_C32(0x95d1992a), + SPH_C32(0x86af3a19) }, + { SPH_C32(0x4c610000), SPH_C32(0x41220084), SPH_C32(0x95240000), + SPH_C32(0x27ec0000), SPH_C32(0x1c9a5c8f), SPH_C32(0x92dcfae6), + SPH_C32(0x88f935a2), SPH_C32(0xb122eb6a), SPH_C32(0x9e0b0000), + SPH_C32(0xcd6500b4), SPH_C32(0x613a0000), SPH_C32(0x42d70000), + SPH_C32(0x24e72eb8), SPH_C32(0xd73c07bc), SPH_C32(0xf437899a), + SPH_C32(0x5d65e199) }, + { SPH_C32(0x58780000), SPH_C32(0x62e800b8), SPH_C32(0xc5fb0000), + SPH_C32(0x635a0000), SPH_C32(0x07f63b3f), SPH_C32(0xae2f5693), + SPH_C32(0xe91f2512), SPH_C32(0x6ae830ea), SPH_C32(0x7d480000), + SPH_C32(0xf72b00a0), SPH_C32(0x93fc0000), SPH_C32(0xe8990000), + SPH_C32(0xfff96c1e), SPH_C32(0xf257b9a9), SPH_C32(0xe60a38cc), + SPH_C32(0x672b784e) }, + { SPH_C32(0xfb720000), SPH_C32(0x7d1d00cc), SPH_C32(0x424c0000), + SPH_C32(0xe7bc0000), SPH_C32(0xe92150f6), SPH_C32(0xd1f9c1e1), + SPH_C32(0x257e9c37), SPH_C32(0xf51d2faa), SPH_C32(0xd5dc0000), + SPH_C32(0x28da0084), SPH_C32(0xdaa00000), SPH_C32(0x7d240000), + SPH_C32(0x4a8d736a), SPH_C32(0x8c028d8a), SPH_C32(0x87fef24b), + SPH_C32(0x90daf380) }, + { SPH_C32(0xef6b0000), SPH_C32(0x5ed700f0), SPH_C32(0x12930000), + SPH_C32(0xa30a0000), SPH_C32(0xf24d3746), SPH_C32(0xed0a6d94), + SPH_C32(0x44988c87), SPH_C32(0x2ed7f42a), SPH_C32(0x369f0000), + SPH_C32(0x12940090), SPH_C32(0x28660000), SPH_C32(0xd76a0000), + SPH_C32(0x919331cc), SPH_C32(0xa969339f), SPH_C32(0x95c3431d), + SPH_C32(0xaa946a57) }, + { SPH_C32(0x18310000), SPH_C32(0x475300d8), SPH_C32(0xb08a0000), + SPH_C32(0x4df20000), SPH_C32(0x323f1250), SPH_C32(0xf4927ff4), + SPH_C32(0x37432d61), SPH_C32(0xcf53b67d), SPH_C32(0x22860000), + SPH_C32(0x315e00ac), SPH_C32(0x78b90000), SPH_C32(0x93dc0000), + SPH_C32(0x8aff567c), SPH_C32(0x959a9fea), SPH_C32(0xf42553ad), + SPH_C32(0x715eb1d7) }, + { SPH_C32(0x0c280000), SPH_C32(0x649900e4), SPH_C32(0xe0550000), + SPH_C32(0x09440000), SPH_C32(0x295375e0), SPH_C32(0xc861d381), + SPH_C32(0x56a53dd1), SPH_C32(0x14996dfd), SPH_C32(0xc1c50000), + SPH_C32(0x0b1000b8), SPH_C32(0x8a7f0000), SPH_C32(0x39920000), + SPH_C32(0x51e114da), SPH_C32(0xb0f121ff), SPH_C32(0xe618e2fb), + SPH_C32(0x4b102800) }, + { SPH_C32(0x13af0000), SPH_C32(0x87570088), SPH_C32(0x7e610000), + SPH_C32(0x5ca90000), SPH_C32(0x699c66ed), SPH_C32(0xf511dca5), + SPH_C32(0x9ad65ec3), SPH_C32(0xa75722f3), SPH_C32(0x818c0000), + SPH_C32(0x2eab00d8), SPH_C32(0xff0e0000), SPH_C32(0x173a0000), + SPH_C32(0x64283db5), SPH_C32(0xea4c0898), SPH_C32(0x3844ea88), + SPH_C32(0xeeabae97) }, + { SPH_C32(0x07b60000), SPH_C32(0xa49d00b4), SPH_C32(0x2ebe0000), + SPH_C32(0x181f0000), SPH_C32(0x72f0015d), SPH_C32(0xc9e270d0), + SPH_C32(0xfb304e73), SPH_C32(0x7c9df973), SPH_C32(0x62cf0000), + SPH_C32(0x14e500cc), SPH_C32(0x0dc80000), SPH_C32(0xbd740000), + SPH_C32(0xbf367f13), SPH_C32(0xcf27b68d), SPH_C32(0x2a795bde), + SPH_C32(0xd4e53740) }, + { SPH_C32(0xf0ec0000), SPH_C32(0xbd19009c), SPH_C32(0x8ca70000), + SPH_C32(0xf6e70000), SPH_C32(0xb282244b), SPH_C32(0xd07a62b0), + SPH_C32(0x88ebef95), SPH_C32(0x9d19bb24), SPH_C32(0x76d60000), + SPH_C32(0x372f00f0), SPH_C32(0x5d170000), SPH_C32(0xf9c20000), + SPH_C32(0xa45a18a3), SPH_C32(0xf3d41af8), SPH_C32(0x4b9f4b6e), + SPH_C32(0x0f2fecc0) }, + { SPH_C32(0xe4f50000), SPH_C32(0x9ed300a0), SPH_C32(0xdc780000), + SPH_C32(0xb2510000), SPH_C32(0xa9ee43fb), SPH_C32(0xec89cec5), + SPH_C32(0xe90dff25), SPH_C32(0x46d360a4), SPH_C32(0x95950000), + SPH_C32(0x0d6100e4), SPH_C32(0xafd10000), SPH_C32(0x538c0000), + SPH_C32(0x7f445a05), SPH_C32(0xd6bfa4ed), SPH_C32(0x59a2fa38), + SPH_C32(0x35617517) }, + { SPH_C32(0x47ff0000), SPH_C32(0x812600d4), SPH_C32(0x5bcf0000), + SPH_C32(0x36b70000), SPH_C32(0x47392832), SPH_C32(0x935f59b7), + SPH_C32(0x256c4600), SPH_C32(0xd9267fe4), SPH_C32(0x3d010000), + SPH_C32(0xd29000c0), SPH_C32(0xe68d0000), SPH_C32(0xc6310000), + SPH_C32(0xca304571), SPH_C32(0xa8ea90ce), SPH_C32(0x385630bf), + SPH_C32(0xc290fed9) }, + { SPH_C32(0x53e60000), SPH_C32(0xa2ec00e8), SPH_C32(0x0b100000), + SPH_C32(0x72010000), SPH_C32(0x5c554f82), SPH_C32(0xafacf5c2), + SPH_C32(0x448a56b0), SPH_C32(0x02eca464), SPH_C32(0xde420000), + SPH_C32(0xe8de00d4), SPH_C32(0x144b0000), SPH_C32(0x6c7f0000), + SPH_C32(0x112e07d7), SPH_C32(0x8d812edb), SPH_C32(0x2a6b81e9), + SPH_C32(0xf8de670e) }, + { SPH_C32(0xa4bc0000), SPH_C32(0xbb6800c0), SPH_C32(0xa9090000), + SPH_C32(0x9cf90000), SPH_C32(0x9c276a94), SPH_C32(0xb634e7a2), + SPH_C32(0x3751f756), SPH_C32(0xe368e633), SPH_C32(0xca5b0000), + SPH_C32(0xcb1400e8), SPH_C32(0x44940000), SPH_C32(0x28c90000), + SPH_C32(0x0a426067), SPH_C32(0xb17282ae), SPH_C32(0x4b8d9159), + SPH_C32(0x2314bc8e) }, + { SPH_C32(0xb0a50000), SPH_C32(0x98a200fc), SPH_C32(0xf9d60000), + SPH_C32(0xd84f0000), SPH_C32(0x874b0d24), SPH_C32(0x8ac74bd7), + SPH_C32(0x56b7e7e6), SPH_C32(0x38a23db3), SPH_C32(0x29180000), + SPH_C32(0xf15a00fc), SPH_C32(0xb6520000), SPH_C32(0x82870000), + SPH_C32(0xd15c22c1), SPH_C32(0x94193cbb), SPH_C32(0x59b0200f), + SPH_C32(0x195a2559) } +}; + +static const sph_u32 T512_30[64][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0xac480000), SPH_C32(0x1ba60000), SPH_C32(0x45fb1380), + SPH_C32(0x03430000), SPH_C32(0x5a85316a), SPH_C32(0x1fb250b6), + SPH_C32(0xfe72c7fe), SPH_C32(0x91e478f6), SPH_C32(0x1e4e0000), + SPH_C32(0xdecf0000), SPH_C32(0x6df80180), SPH_C32(0x77240000), + SPH_C32(0xec47079e), SPH_C32(0xf4a0694e), SPH_C32(0xcda31812), + SPH_C32(0x98aa496e) }, + { SPH_C32(0x1e4e0000), SPH_C32(0xdecf0000), SPH_C32(0x6df80180), + SPH_C32(0x77240000), SPH_C32(0xec47079e), SPH_C32(0xf4a0694e), + SPH_C32(0xcda31812), SPH_C32(0x98aa496e), SPH_C32(0xb2060000), + SPH_C32(0xc5690000), SPH_C32(0x28031200), SPH_C32(0x74670000), + SPH_C32(0xb6c236f4), SPH_C32(0xeb1239f8), SPH_C32(0x33d1dfec), + SPH_C32(0x094e3198) }, + { SPH_C32(0xb2060000), SPH_C32(0xc5690000), SPH_C32(0x28031200), + SPH_C32(0x74670000), SPH_C32(0xb6c236f4), SPH_C32(0xeb1239f8), + SPH_C32(0x33d1dfec), SPH_C32(0x094e3198), SPH_C32(0xac480000), + SPH_C32(0x1ba60000), SPH_C32(0x45fb1380), SPH_C32(0x03430000), + SPH_C32(0x5a85316a), SPH_C32(0x1fb250b6), SPH_C32(0xfe72c7fe), + SPH_C32(0x91e478f6) }, + { SPH_C32(0xaec30000), SPH_C32(0x9c4f0001), SPH_C32(0x79d1e000), + SPH_C32(0x2c150000), SPH_C32(0x45cc75b3), SPH_C32(0x6650b736), + SPH_C32(0xab92f78f), SPH_C32(0xa312567b), SPH_C32(0xdb250000), + SPH_C32(0x09290000), SPH_C32(0x49aac000), SPH_C32(0x81e10000), + SPH_C32(0xcafe6b59), SPH_C32(0x42793431), SPH_C32(0x43566b76), + SPH_C32(0xe86cba2e) }, + { SPH_C32(0x028b0000), SPH_C32(0x87e90001), SPH_C32(0x3c2af380), + SPH_C32(0x2f560000), SPH_C32(0x1f4944d9), SPH_C32(0x79e2e780), + SPH_C32(0x55e03071), SPH_C32(0x32f62e8d), SPH_C32(0xc56b0000), + SPH_C32(0xd7e60000), SPH_C32(0x2452c180), SPH_C32(0xf6c50000), + SPH_C32(0x26b96cc7), SPH_C32(0xb6d95d7f), SPH_C32(0x8ef57364), + SPH_C32(0x70c6f340) }, + { SPH_C32(0xb08d0000), SPH_C32(0x42800001), SPH_C32(0x1429e180), + SPH_C32(0x5b310000), SPH_C32(0xa98b722d), SPH_C32(0x92f0de78), + SPH_C32(0x6631ef9d), SPH_C32(0x3bb81f15), SPH_C32(0x69230000), + SPH_C32(0xcc400000), SPH_C32(0x61a9d200), SPH_C32(0xf5860000), + SPH_C32(0x7c3c5dad), SPH_C32(0xa96b0dc9), SPH_C32(0x7087b49a), + SPH_C32(0xe1228bb6) }, + { SPH_C32(0x1cc50000), SPH_C32(0x59260001), SPH_C32(0x51d2f200), + SPH_C32(0x58720000), SPH_C32(0xf30e4347), SPH_C32(0x8d428ece), + SPH_C32(0x98432863), SPH_C32(0xaa5c67e3), SPH_C32(0x776d0000), + SPH_C32(0x128f0000), SPH_C32(0x0c51d380), SPH_C32(0x82a20000), + SPH_C32(0x907b5a33), SPH_C32(0x5dcb6487), SPH_C32(0xbd24ac88), + SPH_C32(0x7988c2d8) }, + { SPH_C32(0xdb250000), SPH_C32(0x09290000), SPH_C32(0x49aac000), + SPH_C32(0x81e10000), SPH_C32(0xcafe6b59), SPH_C32(0x42793431), + SPH_C32(0x43566b76), SPH_C32(0xe86cba2e), SPH_C32(0x75e60000), + SPH_C32(0x95660001), SPH_C32(0x307b2000), SPH_C32(0xadf40000), + SPH_C32(0x8f321eea), SPH_C32(0x24298307), SPH_C32(0xe8c49cf9), + SPH_C32(0x4b7eec55) }, + { SPH_C32(0x776d0000), SPH_C32(0x128f0000), SPH_C32(0x0c51d380), + SPH_C32(0x82a20000), SPH_C32(0x907b5a33), SPH_C32(0x5dcb6487), + SPH_C32(0xbd24ac88), SPH_C32(0x7988c2d8), SPH_C32(0x6ba80000), + SPH_C32(0x4ba90001), SPH_C32(0x5d832180), SPH_C32(0xdad00000), + SPH_C32(0x63751974), SPH_C32(0xd089ea49), SPH_C32(0x256784eb), + SPH_C32(0xd3d4a53b) }, + { SPH_C32(0xc56b0000), SPH_C32(0xd7e60000), SPH_C32(0x2452c180), + SPH_C32(0xf6c50000), SPH_C32(0x26b96cc7), SPH_C32(0xb6d95d7f), + SPH_C32(0x8ef57364), SPH_C32(0x70c6f340), SPH_C32(0xc7e00000), + SPH_C32(0x500f0001), SPH_C32(0x18783200), SPH_C32(0xd9930000), + SPH_C32(0x39f0281e), SPH_C32(0xcf3bbaff), SPH_C32(0xdb154315), + SPH_C32(0x4230ddcd) }, + { SPH_C32(0x69230000), SPH_C32(0xcc400000), SPH_C32(0x61a9d200), + SPH_C32(0xf5860000), SPH_C32(0x7c3c5dad), SPH_C32(0xa96b0dc9), + SPH_C32(0x7087b49a), SPH_C32(0xe1228bb6), SPH_C32(0xd9ae0000), + SPH_C32(0x8ec00001), SPH_C32(0x75803380), SPH_C32(0xaeb70000), + SPH_C32(0xd5b72f80), SPH_C32(0x3b9bd3b1), SPH_C32(0x16b65b07), + SPH_C32(0xda9a94a3) }, + { SPH_C32(0x75e60000), SPH_C32(0x95660001), SPH_C32(0x307b2000), + SPH_C32(0xadf40000), SPH_C32(0x8f321eea), SPH_C32(0x24298307), + SPH_C32(0xe8c49cf9), SPH_C32(0x4b7eec55), SPH_C32(0xaec30000), + SPH_C32(0x9c4f0001), SPH_C32(0x79d1e000), SPH_C32(0x2c150000), + SPH_C32(0x45cc75b3), SPH_C32(0x6650b736), SPH_C32(0xab92f78f), + SPH_C32(0xa312567b) }, + { SPH_C32(0xd9ae0000), SPH_C32(0x8ec00001), SPH_C32(0x75803380), + SPH_C32(0xaeb70000), SPH_C32(0xd5b72f80), SPH_C32(0x3b9bd3b1), + SPH_C32(0x16b65b07), SPH_C32(0xda9a94a3), SPH_C32(0xb08d0000), + SPH_C32(0x42800001), SPH_C32(0x1429e180), SPH_C32(0x5b310000), + SPH_C32(0xa98b722d), SPH_C32(0x92f0de78), SPH_C32(0x6631ef9d), + SPH_C32(0x3bb81f15) }, + { SPH_C32(0x6ba80000), SPH_C32(0x4ba90001), SPH_C32(0x5d832180), + SPH_C32(0xdad00000), SPH_C32(0x63751974), SPH_C32(0xd089ea49), + SPH_C32(0x256784eb), SPH_C32(0xd3d4a53b), SPH_C32(0x1cc50000), + SPH_C32(0x59260001), SPH_C32(0x51d2f200), SPH_C32(0x58720000), + SPH_C32(0xf30e4347), SPH_C32(0x8d428ece), SPH_C32(0x98432863), + SPH_C32(0xaa5c67e3) }, + { SPH_C32(0xc7e00000), SPH_C32(0x500f0001), SPH_C32(0x18783200), + SPH_C32(0xd9930000), SPH_C32(0x39f0281e), SPH_C32(0xcf3bbaff), + SPH_C32(0xdb154315), SPH_C32(0x4230ddcd), SPH_C32(0x028b0000), + SPH_C32(0x87e90001), SPH_C32(0x3c2af380), SPH_C32(0x2f560000), + SPH_C32(0x1f4944d9), SPH_C32(0x79e2e780), SPH_C32(0x55e03071), + SPH_C32(0x32f62e8d) }, + { SPH_C32(0x86790000), SPH_C32(0x3f390002), SPH_C32(0xe19ae000), + SPH_C32(0x98560000), SPH_C32(0x9565670e), SPH_C32(0x4e88c8ea), + SPH_C32(0xd3dd4944), SPH_C32(0x161ddab9), SPH_C32(0x30b70000), + SPH_C32(0xe5d00000), SPH_C32(0xf4f46000), SPH_C32(0x42c40000), + SPH_C32(0x63b83d6a), SPH_C32(0x78ba9460), SPH_C32(0x21afa1ea), + SPH_C32(0xb0a51834) }, + { SPH_C32(0x2a310000), SPH_C32(0x249f0002), SPH_C32(0xa461f380), + SPH_C32(0x9b150000), SPH_C32(0xcfe05664), SPH_C32(0x513a985c), + SPH_C32(0x2daf8eba), SPH_C32(0x87f9a24f), SPH_C32(0x2ef90000), + SPH_C32(0x3b1f0000), SPH_C32(0x990c6180), SPH_C32(0x35e00000), + SPH_C32(0x8fff3af4), SPH_C32(0x8c1afd2e), SPH_C32(0xec0cb9f8), + SPH_C32(0x280f515a) }, + { SPH_C32(0x98370000), SPH_C32(0xe1f60002), SPH_C32(0x8c62e180), + SPH_C32(0xef720000), SPH_C32(0x79226090), SPH_C32(0xba28a1a4), + SPH_C32(0x1e7e5156), SPH_C32(0x8eb793d7), SPH_C32(0x82b10000), + SPH_C32(0x20b90000), SPH_C32(0xdcf77200), SPH_C32(0x36a30000), + SPH_C32(0xd57a0b9e), SPH_C32(0x93a8ad98), SPH_C32(0x127e7e06), + SPH_C32(0xb9eb29ac) }, + { SPH_C32(0x347f0000), SPH_C32(0xfa500002), SPH_C32(0xc999f200), + SPH_C32(0xec310000), SPH_C32(0x23a751fa), SPH_C32(0xa59af112), + SPH_C32(0xe00c96a8), SPH_C32(0x1f53eb21), SPH_C32(0x9cff0000), + SPH_C32(0xfe760000), SPH_C32(0xb10f7380), SPH_C32(0x41870000), + SPH_C32(0x393d0c00), SPH_C32(0x6708c4d6), SPH_C32(0xdfdd6614), + SPH_C32(0x214160c2) }, + { SPH_C32(0x28ba0000), SPH_C32(0xa3760003), SPH_C32(0x984b0000), + SPH_C32(0xb4430000), SPH_C32(0xd0a912bd), SPH_C32(0x28d87fdc), + SPH_C32(0x784fbecb), SPH_C32(0xb50f8cc2), SPH_C32(0xeb920000), + SPH_C32(0xecf90000), SPH_C32(0xbd5ea000), SPH_C32(0xc3250000), + SPH_C32(0xa9465633), SPH_C32(0x3ac3a051), SPH_C32(0x62f9ca9c), + SPH_C32(0x58c9a21a) }, + { SPH_C32(0x84f20000), SPH_C32(0xb8d00003), SPH_C32(0xddb01380), + SPH_C32(0xb7000000), SPH_C32(0x8a2c23d7), SPH_C32(0x376a2f6a), + SPH_C32(0x863d7935), SPH_C32(0x24ebf434), SPH_C32(0xf5dc0000), + SPH_C32(0x32360000), SPH_C32(0xd0a6a180), SPH_C32(0xb4010000), + SPH_C32(0x450151ad), SPH_C32(0xce63c91f), SPH_C32(0xaf5ad28e), + SPH_C32(0xc063eb74) }, + { SPH_C32(0x36f40000), SPH_C32(0x7db90003), SPH_C32(0xf5b30180), + SPH_C32(0xc3670000), SPH_C32(0x3cee1523), SPH_C32(0xdc781692), + SPH_C32(0xb5eca6d9), SPH_C32(0x2da5c5ac), SPH_C32(0x59940000), + SPH_C32(0x29900000), SPH_C32(0x955db200), SPH_C32(0xb7420000), + SPH_C32(0x1f8460c7), SPH_C32(0xd1d199a9), SPH_C32(0x51281570), + SPH_C32(0x51879382) }, + { SPH_C32(0x9abc0000), SPH_C32(0x661f0003), SPH_C32(0xb0481200), + SPH_C32(0xc0240000), SPH_C32(0x666b2449), SPH_C32(0xc3ca4624), + SPH_C32(0x4b9e6127), SPH_C32(0xbc41bd5a), SPH_C32(0x47da0000), + SPH_C32(0xf75f0000), SPH_C32(0xf8a5b380), SPH_C32(0xc0660000), + SPH_C32(0xf3c36759), SPH_C32(0x2571f0e7), SPH_C32(0x9c8b0d62), + SPH_C32(0xc92ddaec) }, + { SPH_C32(0x5d5c0000), SPH_C32(0x36100002), SPH_C32(0xa8302000), + SPH_C32(0x19b70000), SPH_C32(0x5f9b0c57), SPH_C32(0x0cf1fcdb), + SPH_C32(0x908b2232), SPH_C32(0xfe716097), SPH_C32(0x45510000), + SPH_C32(0x70b60001), SPH_C32(0xc48f4000), SPH_C32(0xef300000), + SPH_C32(0xec8a2380), SPH_C32(0x5c931767), SPH_C32(0xc96b3d13), + SPH_C32(0xfbdbf461) }, + { SPH_C32(0xf1140000), SPH_C32(0x2db60002), SPH_C32(0xedcb3380), + SPH_C32(0x1af40000), SPH_C32(0x051e3d3d), SPH_C32(0x1343ac6d), + SPH_C32(0x6ef9e5cc), SPH_C32(0x6f951861), SPH_C32(0x5b1f0000), + SPH_C32(0xae790001), SPH_C32(0xa9774180), SPH_C32(0x98140000), + SPH_C32(0x00cd241e), SPH_C32(0xa8337e29), SPH_C32(0x04c82501), + SPH_C32(0x6371bd0f) }, + { SPH_C32(0x43120000), SPH_C32(0xe8df0002), SPH_C32(0xc5c82180), + SPH_C32(0x6e930000), SPH_C32(0xb3dc0bc9), SPH_C32(0xf8519595), + SPH_C32(0x5d283a20), SPH_C32(0x66db29f9), SPH_C32(0xf7570000), + SPH_C32(0xb5df0001), SPH_C32(0xec8c5200), SPH_C32(0x9b570000), + SPH_C32(0x5a481574), SPH_C32(0xb7812e9f), SPH_C32(0xfabae2ff), + SPH_C32(0xf295c5f9) }, + { SPH_C32(0xef5a0000), SPH_C32(0xf3790002), SPH_C32(0x80333200), + SPH_C32(0x6dd00000), SPH_C32(0xe9593aa3), SPH_C32(0xe7e3c523), + SPH_C32(0xa35afdde), SPH_C32(0xf73f510f), SPH_C32(0xe9190000), + SPH_C32(0x6b100001), SPH_C32(0x81745380), SPH_C32(0xec730000), + SPH_C32(0xb60f12ea), SPH_C32(0x432147d1), SPH_C32(0x3719faed), + SPH_C32(0x6a3f8c97) }, + { SPH_C32(0xf39f0000), SPH_C32(0xaa5f0003), SPH_C32(0xd1e1c000), + SPH_C32(0x35a20000), SPH_C32(0x1a5779e4), SPH_C32(0x6aa14bed), + SPH_C32(0x3b19d5bd), SPH_C32(0x5d6336ec), SPH_C32(0x9e740000), + SPH_C32(0x799f0001), SPH_C32(0x8d258000), SPH_C32(0x6ed10000), + SPH_C32(0x267448d9), SPH_C32(0x1eea2356), SPH_C32(0x8a3d5665), + SPH_C32(0x13b74e4f) }, + { SPH_C32(0x5fd70000), SPH_C32(0xb1f90003), SPH_C32(0x941ad380), + SPH_C32(0x36e10000), SPH_C32(0x40d2488e), SPH_C32(0x75131b5b), + SPH_C32(0xc56b1243), SPH_C32(0xcc874e1a), SPH_C32(0x803a0000), + SPH_C32(0xa7500001), SPH_C32(0xe0dd8180), SPH_C32(0x19f50000), + SPH_C32(0xca334f47), SPH_C32(0xea4a4a18), SPH_C32(0x479e4e77), + SPH_C32(0x8b1d0721) }, + { SPH_C32(0xedd10000), SPH_C32(0x74900003), SPH_C32(0xbc19c180), + SPH_C32(0x42860000), SPH_C32(0xf6107e7a), SPH_C32(0x9e0122a3), + SPH_C32(0xf6bacdaf), SPH_C32(0xc5c97f82), SPH_C32(0x2c720000), + SPH_C32(0xbcf60001), SPH_C32(0xa5269200), SPH_C32(0x1ab60000), + SPH_C32(0x90b67e2d), SPH_C32(0xf5f81aae), SPH_C32(0xb9ec8989), + SPH_C32(0x1af97fd7) }, + { SPH_C32(0x41990000), SPH_C32(0x6f360003), SPH_C32(0xf9e2d200), + SPH_C32(0x41c50000), SPH_C32(0xac954f10), SPH_C32(0x81b37215), + SPH_C32(0x08c80a51), SPH_C32(0x542d0774), SPH_C32(0x323c0000), + SPH_C32(0x62390001), SPH_C32(0xc8de9380), SPH_C32(0x6d920000), + SPH_C32(0x7cf179b3), SPH_C32(0x015873e0), SPH_C32(0x744f919b), + SPH_C32(0x825336b9) }, + { SPH_C32(0x30b70000), SPH_C32(0xe5d00000), SPH_C32(0xf4f46000), + SPH_C32(0x42c40000), SPH_C32(0x63b83d6a), SPH_C32(0x78ba9460), + SPH_C32(0x21afa1ea), SPH_C32(0xb0a51834), SPH_C32(0xb6ce0000), + SPH_C32(0xdae90002), SPH_C32(0x156e8000), SPH_C32(0xda920000), + SPH_C32(0xf6dd5a64), SPH_C32(0x36325c8a), SPH_C32(0xf272e8ae), + SPH_C32(0xa6b8c28d) }, + { SPH_C32(0x9cff0000), SPH_C32(0xfe760000), SPH_C32(0xb10f7380), + SPH_C32(0x41870000), SPH_C32(0x393d0c00), SPH_C32(0x6708c4d6), + SPH_C32(0xdfdd6614), SPH_C32(0x214160c2), SPH_C32(0xa8800000), + SPH_C32(0x04260002), SPH_C32(0x78968180), SPH_C32(0xadb60000), + SPH_C32(0x1a9a5dfa), SPH_C32(0xc29235c4), SPH_C32(0x3fd1f0bc), + SPH_C32(0x3e128be3) }, + { SPH_C32(0x2ef90000), SPH_C32(0x3b1f0000), SPH_C32(0x990c6180), + SPH_C32(0x35e00000), SPH_C32(0x8fff3af4), SPH_C32(0x8c1afd2e), + SPH_C32(0xec0cb9f8), SPH_C32(0x280f515a), SPH_C32(0x04c80000), + SPH_C32(0x1f800002), SPH_C32(0x3d6d9200), SPH_C32(0xaef50000), + SPH_C32(0x401f6c90), SPH_C32(0xdd206572), SPH_C32(0xc1a33742), + SPH_C32(0xaff6f315) }, + { SPH_C32(0x82b10000), SPH_C32(0x20b90000), SPH_C32(0xdcf77200), + SPH_C32(0x36a30000), SPH_C32(0xd57a0b9e), SPH_C32(0x93a8ad98), + SPH_C32(0x127e7e06), SPH_C32(0xb9eb29ac), SPH_C32(0x1a860000), + SPH_C32(0xc14f0002), SPH_C32(0x50959380), SPH_C32(0xd9d10000), + SPH_C32(0xac586b0e), SPH_C32(0x29800c3c), SPH_C32(0x0c002f50), + SPH_C32(0x375cba7b) }, + { SPH_C32(0x9e740000), SPH_C32(0x799f0001), SPH_C32(0x8d258000), + SPH_C32(0x6ed10000), SPH_C32(0x267448d9), SPH_C32(0x1eea2356), + SPH_C32(0x8a3d5665), SPH_C32(0x13b74e4f), SPH_C32(0x6deb0000), + SPH_C32(0xd3c00002), SPH_C32(0x5cc44000), SPH_C32(0x5b730000), + SPH_C32(0x3c23313d), SPH_C32(0x744b68bb), SPH_C32(0xb12483d8), + SPH_C32(0x4ed478a3) }, + { SPH_C32(0x323c0000), SPH_C32(0x62390001), SPH_C32(0xc8de9380), + SPH_C32(0x6d920000), SPH_C32(0x7cf179b3), SPH_C32(0x015873e0), + SPH_C32(0x744f919b), SPH_C32(0x825336b9), SPH_C32(0x73a50000), + SPH_C32(0x0d0f0002), SPH_C32(0x313c4180), SPH_C32(0x2c570000), + SPH_C32(0xd06436a3), SPH_C32(0x80eb01f5), SPH_C32(0x7c879bca), + SPH_C32(0xd67e31cd) }, + { SPH_C32(0x803a0000), SPH_C32(0xa7500001), SPH_C32(0xe0dd8180), + SPH_C32(0x19f50000), SPH_C32(0xca334f47), SPH_C32(0xea4a4a18), + SPH_C32(0x479e4e77), SPH_C32(0x8b1d0721), SPH_C32(0xdfed0000), + SPH_C32(0x16a90002), SPH_C32(0x74c75200), SPH_C32(0x2f140000), + SPH_C32(0x8ae107c9), SPH_C32(0x9f595143), SPH_C32(0x82f55c34), + SPH_C32(0x479a493b) }, + { SPH_C32(0x2c720000), SPH_C32(0xbcf60001), SPH_C32(0xa5269200), + SPH_C32(0x1ab60000), SPH_C32(0x90b67e2d), SPH_C32(0xf5f81aae), + SPH_C32(0xb9ec8989), SPH_C32(0x1af97fd7), SPH_C32(0xc1a30000), + SPH_C32(0xc8660002), SPH_C32(0x193f5380), SPH_C32(0x58300000), + SPH_C32(0x66a60057), SPH_C32(0x6bf9380d), SPH_C32(0x4f564426), + SPH_C32(0xdf300055) }, + { SPH_C32(0xeb920000), SPH_C32(0xecf90000), SPH_C32(0xbd5ea000), + SPH_C32(0xc3250000), SPH_C32(0xa9465633), SPH_C32(0x3ac3a051), + SPH_C32(0x62f9ca9c), SPH_C32(0x58c9a21a), SPH_C32(0xc3280000), + SPH_C32(0x4f8f0003), SPH_C32(0x2515a000), SPH_C32(0x77660000), + SPH_C32(0x79ef448e), SPH_C32(0x121bdf8d), SPH_C32(0x1ab67457), + SPH_C32(0xedc62ed8) }, + { SPH_C32(0x47da0000), SPH_C32(0xf75f0000), SPH_C32(0xf8a5b380), + SPH_C32(0xc0660000), SPH_C32(0xf3c36759), SPH_C32(0x2571f0e7), + SPH_C32(0x9c8b0d62), SPH_C32(0xc92ddaec), SPH_C32(0xdd660000), + SPH_C32(0x91400003), SPH_C32(0x48eda180), SPH_C32(0x00420000), + SPH_C32(0x95a84310), SPH_C32(0xe6bbb6c3), SPH_C32(0xd7156c45), + SPH_C32(0x756c67b6) }, + { SPH_C32(0xf5dc0000), SPH_C32(0x32360000), SPH_C32(0xd0a6a180), + SPH_C32(0xb4010000), SPH_C32(0x450151ad), SPH_C32(0xce63c91f), + SPH_C32(0xaf5ad28e), SPH_C32(0xc063eb74), SPH_C32(0x712e0000), + SPH_C32(0x8ae60003), SPH_C32(0x0d16b200), SPH_C32(0x03010000), + SPH_C32(0xcf2d727a), SPH_C32(0xf909e675), SPH_C32(0x2967abbb), + SPH_C32(0xe4881f40) }, + { SPH_C32(0x59940000), SPH_C32(0x29900000), SPH_C32(0x955db200), + SPH_C32(0xb7420000), SPH_C32(0x1f8460c7), SPH_C32(0xd1d199a9), + SPH_C32(0x51281570), SPH_C32(0x51879382), SPH_C32(0x6f600000), + SPH_C32(0x54290003), SPH_C32(0x60eeb380), SPH_C32(0x74250000), + SPH_C32(0x236a75e4), SPH_C32(0x0da98f3b), SPH_C32(0xe4c4b3a9), + SPH_C32(0x7c22562e) }, + { SPH_C32(0x45510000), SPH_C32(0x70b60001), SPH_C32(0xc48f4000), + SPH_C32(0xef300000), SPH_C32(0xec8a2380), SPH_C32(0x5c931767), + SPH_C32(0xc96b3d13), SPH_C32(0xfbdbf461), SPH_C32(0x180d0000), + SPH_C32(0x46a60003), SPH_C32(0x6cbf6000), SPH_C32(0xf6870000), + SPH_C32(0xb3112fd7), SPH_C32(0x5062ebbc), SPH_C32(0x59e01f21), + SPH_C32(0x05aa94f6) }, + { SPH_C32(0xe9190000), SPH_C32(0x6b100001), SPH_C32(0x81745380), + SPH_C32(0xec730000), SPH_C32(0xb60f12ea), SPH_C32(0x432147d1), + SPH_C32(0x3719faed), SPH_C32(0x6a3f8c97), SPH_C32(0x06430000), + SPH_C32(0x98690003), SPH_C32(0x01476180), SPH_C32(0x81a30000), + SPH_C32(0x5f562849), SPH_C32(0xa4c282f2), SPH_C32(0x94430733), + SPH_C32(0x9d00dd98) }, + { SPH_C32(0x5b1f0000), SPH_C32(0xae790001), SPH_C32(0xa9774180), + SPH_C32(0x98140000), SPH_C32(0x00cd241e), SPH_C32(0xa8337e29), + SPH_C32(0x04c82501), SPH_C32(0x6371bd0f), SPH_C32(0xaa0b0000), + SPH_C32(0x83cf0003), SPH_C32(0x44bc7200), SPH_C32(0x82e00000), + SPH_C32(0x05d31923), SPH_C32(0xbb70d244), SPH_C32(0x6a31c0cd), + SPH_C32(0x0ce4a56e) }, + { SPH_C32(0xf7570000), SPH_C32(0xb5df0001), SPH_C32(0xec8c5200), + SPH_C32(0x9b570000), SPH_C32(0x5a481574), SPH_C32(0xb7812e9f), + SPH_C32(0xfabae2ff), SPH_C32(0xf295c5f9), SPH_C32(0xb4450000), + SPH_C32(0x5d000003), SPH_C32(0x29447380), SPH_C32(0xf5c40000), + SPH_C32(0xe9941ebd), SPH_C32(0x4fd0bb0a), SPH_C32(0xa792d8df), + SPH_C32(0x944eec00) }, + { SPH_C32(0xb6ce0000), SPH_C32(0xdae90002), SPH_C32(0x156e8000), + SPH_C32(0xda920000), SPH_C32(0xf6dd5a64), SPH_C32(0x36325c8a), + SPH_C32(0xf272e8ae), SPH_C32(0xa6b8c28d), SPH_C32(0x86790000), + SPH_C32(0x3f390002), SPH_C32(0xe19ae000), SPH_C32(0x98560000), + SPH_C32(0x9565670e), SPH_C32(0x4e88c8ea), SPH_C32(0xd3dd4944), + SPH_C32(0x161ddab9) }, + { SPH_C32(0x1a860000), SPH_C32(0xc14f0002), SPH_C32(0x50959380), + SPH_C32(0xd9d10000), SPH_C32(0xac586b0e), SPH_C32(0x29800c3c), + SPH_C32(0x0c002f50), SPH_C32(0x375cba7b), SPH_C32(0x98370000), + SPH_C32(0xe1f60002), SPH_C32(0x8c62e180), SPH_C32(0xef720000), + SPH_C32(0x79226090), SPH_C32(0xba28a1a4), SPH_C32(0x1e7e5156), + SPH_C32(0x8eb793d7) }, + { SPH_C32(0xa8800000), SPH_C32(0x04260002), SPH_C32(0x78968180), + SPH_C32(0xadb60000), SPH_C32(0x1a9a5dfa), SPH_C32(0xc29235c4), + SPH_C32(0x3fd1f0bc), SPH_C32(0x3e128be3), SPH_C32(0x347f0000), + SPH_C32(0xfa500002), SPH_C32(0xc999f200), SPH_C32(0xec310000), + SPH_C32(0x23a751fa), SPH_C32(0xa59af112), SPH_C32(0xe00c96a8), + SPH_C32(0x1f53eb21) }, + { SPH_C32(0x04c80000), SPH_C32(0x1f800002), SPH_C32(0x3d6d9200), + SPH_C32(0xaef50000), SPH_C32(0x401f6c90), SPH_C32(0xdd206572), + SPH_C32(0xc1a33742), SPH_C32(0xaff6f315), SPH_C32(0x2a310000), + SPH_C32(0x249f0002), SPH_C32(0xa461f380), SPH_C32(0x9b150000), + SPH_C32(0xcfe05664), SPH_C32(0x513a985c), SPH_C32(0x2daf8eba), + SPH_C32(0x87f9a24f) }, + { SPH_C32(0x180d0000), SPH_C32(0x46a60003), SPH_C32(0x6cbf6000), + SPH_C32(0xf6870000), SPH_C32(0xb3112fd7), SPH_C32(0x5062ebbc), + SPH_C32(0x59e01f21), SPH_C32(0x05aa94f6), SPH_C32(0x5d5c0000), + SPH_C32(0x36100002), SPH_C32(0xa8302000), SPH_C32(0x19b70000), + SPH_C32(0x5f9b0c57), SPH_C32(0x0cf1fcdb), SPH_C32(0x908b2232), + SPH_C32(0xfe716097) }, + { SPH_C32(0xb4450000), SPH_C32(0x5d000003), SPH_C32(0x29447380), + SPH_C32(0xf5c40000), SPH_C32(0xe9941ebd), SPH_C32(0x4fd0bb0a), + SPH_C32(0xa792d8df), SPH_C32(0x944eec00), SPH_C32(0x43120000), + SPH_C32(0xe8df0002), SPH_C32(0xc5c82180), SPH_C32(0x6e930000), + SPH_C32(0xb3dc0bc9), SPH_C32(0xf8519595), SPH_C32(0x5d283a20), + SPH_C32(0x66db29f9) }, + { SPH_C32(0x06430000), SPH_C32(0x98690003), SPH_C32(0x01476180), + SPH_C32(0x81a30000), SPH_C32(0x5f562849), SPH_C32(0xa4c282f2), + SPH_C32(0x94430733), SPH_C32(0x9d00dd98), SPH_C32(0xef5a0000), + SPH_C32(0xf3790002), SPH_C32(0x80333200), SPH_C32(0x6dd00000), + SPH_C32(0xe9593aa3), SPH_C32(0xe7e3c523), SPH_C32(0xa35afdde), + SPH_C32(0xf73f510f) }, + { SPH_C32(0xaa0b0000), SPH_C32(0x83cf0003), SPH_C32(0x44bc7200), + SPH_C32(0x82e00000), SPH_C32(0x05d31923), SPH_C32(0xbb70d244), + SPH_C32(0x6a31c0cd), SPH_C32(0x0ce4a56e), SPH_C32(0xf1140000), + SPH_C32(0x2db60002), SPH_C32(0xedcb3380), SPH_C32(0x1af40000), + SPH_C32(0x051e3d3d), SPH_C32(0x1343ac6d), SPH_C32(0x6ef9e5cc), + SPH_C32(0x6f951861) }, + { SPH_C32(0x6deb0000), SPH_C32(0xd3c00002), SPH_C32(0x5cc44000), + SPH_C32(0x5b730000), SPH_C32(0x3c23313d), SPH_C32(0x744b68bb), + SPH_C32(0xb12483d8), SPH_C32(0x4ed478a3), SPH_C32(0xf39f0000), + SPH_C32(0xaa5f0003), SPH_C32(0xd1e1c000), SPH_C32(0x35a20000), + SPH_C32(0x1a5779e4), SPH_C32(0x6aa14bed), SPH_C32(0x3b19d5bd), + SPH_C32(0x5d6336ec) }, + { SPH_C32(0xc1a30000), SPH_C32(0xc8660002), SPH_C32(0x193f5380), + SPH_C32(0x58300000), SPH_C32(0x66a60057), SPH_C32(0x6bf9380d), + SPH_C32(0x4f564426), SPH_C32(0xdf300055), SPH_C32(0xedd10000), + SPH_C32(0x74900003), SPH_C32(0xbc19c180), SPH_C32(0x42860000), + SPH_C32(0xf6107e7a), SPH_C32(0x9e0122a3), SPH_C32(0xf6bacdaf), + SPH_C32(0xc5c97f82) }, + { SPH_C32(0x73a50000), SPH_C32(0x0d0f0002), SPH_C32(0x313c4180), + SPH_C32(0x2c570000), SPH_C32(0xd06436a3), SPH_C32(0x80eb01f5), + SPH_C32(0x7c879bca), SPH_C32(0xd67e31cd), SPH_C32(0x41990000), + SPH_C32(0x6f360003), SPH_C32(0xf9e2d200), SPH_C32(0x41c50000), + SPH_C32(0xac954f10), SPH_C32(0x81b37215), SPH_C32(0x08c80a51), + SPH_C32(0x542d0774) }, + { SPH_C32(0xdfed0000), SPH_C32(0x16a90002), SPH_C32(0x74c75200), + SPH_C32(0x2f140000), SPH_C32(0x8ae107c9), SPH_C32(0x9f595143), + SPH_C32(0x82f55c34), SPH_C32(0x479a493b), SPH_C32(0x5fd70000), + SPH_C32(0xb1f90003), SPH_C32(0x941ad380), SPH_C32(0x36e10000), + SPH_C32(0x40d2488e), SPH_C32(0x75131b5b), SPH_C32(0xc56b1243), + SPH_C32(0xcc874e1a) }, + { SPH_C32(0xc3280000), SPH_C32(0x4f8f0003), SPH_C32(0x2515a000), + SPH_C32(0x77660000), SPH_C32(0x79ef448e), SPH_C32(0x121bdf8d), + SPH_C32(0x1ab67457), SPH_C32(0xedc62ed8), SPH_C32(0x28ba0000), + SPH_C32(0xa3760003), SPH_C32(0x984b0000), SPH_C32(0xb4430000), + SPH_C32(0xd0a912bd), SPH_C32(0x28d87fdc), SPH_C32(0x784fbecb), + SPH_C32(0xb50f8cc2) }, + { SPH_C32(0x6f600000), SPH_C32(0x54290003), SPH_C32(0x60eeb380), + SPH_C32(0x74250000), SPH_C32(0x236a75e4), SPH_C32(0x0da98f3b), + SPH_C32(0xe4c4b3a9), SPH_C32(0x7c22562e), SPH_C32(0x36f40000), + SPH_C32(0x7db90003), SPH_C32(0xf5b30180), SPH_C32(0xc3670000), + SPH_C32(0x3cee1523), SPH_C32(0xdc781692), SPH_C32(0xb5eca6d9), + SPH_C32(0x2da5c5ac) }, + { SPH_C32(0xdd660000), SPH_C32(0x91400003), SPH_C32(0x48eda180), + SPH_C32(0x00420000), SPH_C32(0x95a84310), SPH_C32(0xe6bbb6c3), + SPH_C32(0xd7156c45), SPH_C32(0x756c67b6), SPH_C32(0x9abc0000), + SPH_C32(0x661f0003), SPH_C32(0xb0481200), SPH_C32(0xc0240000), + SPH_C32(0x666b2449), SPH_C32(0xc3ca4624), SPH_C32(0x4b9e6127), + SPH_C32(0xbc41bd5a) }, + { SPH_C32(0x712e0000), SPH_C32(0x8ae60003), SPH_C32(0x0d16b200), + SPH_C32(0x03010000), SPH_C32(0xcf2d727a), SPH_C32(0xf909e675), + SPH_C32(0x2967abbb), SPH_C32(0xe4881f40), SPH_C32(0x84f20000), + SPH_C32(0xb8d00003), SPH_C32(0xddb01380), SPH_C32(0xb7000000), + SPH_C32(0x8a2c23d7), SPH_C32(0x376a2f6a), SPH_C32(0x863d7935), + SPH_C32(0x24ebf434) } +}; + +static const sph_u32 T512_36[64][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0x52500000), SPH_C32(0x29540000), SPH_C32(0x6a61004e), + SPH_C32(0xf0ff0000), SPH_C32(0x9a317eec), SPH_C32(0x452341ce), + SPH_C32(0xcf568fe5), SPH_C32(0x5303130f), SPH_C32(0x538d0000), + SPH_C32(0xa9fc0000), SPH_C32(0x9ef70006), SPH_C32(0x56ff0000), + SPH_C32(0x0ae4004e), SPH_C32(0x92c5cdf9), SPH_C32(0xa9444018), + SPH_C32(0x7f975691) }, + { SPH_C32(0x538d0000), SPH_C32(0xa9fc0000), SPH_C32(0x9ef70006), + SPH_C32(0x56ff0000), SPH_C32(0x0ae4004e), SPH_C32(0x92c5cdf9), + SPH_C32(0xa9444018), SPH_C32(0x7f975691), SPH_C32(0x01dd0000), + SPH_C32(0x80a80000), SPH_C32(0xf4960048), SPH_C32(0xa6000000), + SPH_C32(0x90d57ea2), SPH_C32(0xd7e68c37), SPH_C32(0x6612cffd), + SPH_C32(0x2c94459e) }, + { SPH_C32(0x01dd0000), SPH_C32(0x80a80000), SPH_C32(0xf4960048), + SPH_C32(0xa6000000), SPH_C32(0x90d57ea2), SPH_C32(0xd7e68c37), + SPH_C32(0x6612cffd), SPH_C32(0x2c94459e), SPH_C32(0x52500000), + SPH_C32(0x29540000), SPH_C32(0x6a61004e), SPH_C32(0xf0ff0000), + SPH_C32(0x9a317eec), SPH_C32(0x452341ce), SPH_C32(0xcf568fe5), + SPH_C32(0x5303130f) }, + { SPH_C32(0xcc140000), SPH_C32(0xa5630000), SPH_C32(0x5ab90780), + SPH_C32(0x3b500000), SPH_C32(0x4bd013ff), SPH_C32(0x879b3418), + SPH_C32(0x694348c1), SPH_C32(0xca5a87fe), SPH_C32(0x819e0000), + SPH_C32(0xec570000), SPH_C32(0x66320280), SPH_C32(0x95f30000), + SPH_C32(0x5da92802), SPH_C32(0x48f43cbc), SPH_C32(0xe65aa22d), + SPH_C32(0x8e67b7fa) }, + { SPH_C32(0x9e440000), SPH_C32(0x8c370000), SPH_C32(0x30d807ce), + SPH_C32(0xcbaf0000), SPH_C32(0xd1e16d13), SPH_C32(0xc2b875d6), + SPH_C32(0xa615c724), SPH_C32(0x995994f1), SPH_C32(0xd2130000), + SPH_C32(0x45ab0000), SPH_C32(0xf8c50286), SPH_C32(0xc30c0000), + SPH_C32(0x574d284c), SPH_C32(0xda31f145), SPH_C32(0x4f1ee235), + SPH_C32(0xf1f0e16b) }, + { SPH_C32(0x9f990000), SPH_C32(0x0c9f0000), SPH_C32(0xc44e0786), + SPH_C32(0x6daf0000), SPH_C32(0x413413b1), SPH_C32(0x155ef9e1), + SPH_C32(0xc00708d9), SPH_C32(0xb5cdd16f), SPH_C32(0x80430000), + SPH_C32(0x6cff0000), SPH_C32(0x92a402c8), SPH_C32(0x33f30000), + SPH_C32(0xcd7c56a0), SPH_C32(0x9f12b08b), SPH_C32(0x80486dd0), + SPH_C32(0xa2f3f264) }, + { SPH_C32(0xcdc90000), SPH_C32(0x25cb0000), SPH_C32(0xae2f07c8), + SPH_C32(0x9d500000), SPH_C32(0xdb056d5d), SPH_C32(0x507db82f), + SPH_C32(0x0f51873c), SPH_C32(0xe6cec260), SPH_C32(0xd3ce0000), + SPH_C32(0xc5030000), SPH_C32(0x0c5302ce), SPH_C32(0x650c0000), + SPH_C32(0xc79856ee), SPH_C32(0x0dd77d72), SPH_C32(0x290c2dc8), + SPH_C32(0xdd64a4f5) }, + { SPH_C32(0x819e0000), SPH_C32(0xec570000), SPH_C32(0x66320280), + SPH_C32(0x95f30000), SPH_C32(0x5da92802), SPH_C32(0x48f43cbc), + SPH_C32(0xe65aa22d), SPH_C32(0x8e67b7fa), SPH_C32(0x4d8a0000), + SPH_C32(0x49340000), SPH_C32(0x3c8b0500), SPH_C32(0xaea30000), + SPH_C32(0x16793bfd), SPH_C32(0xcf6f08a4), SPH_C32(0x8f19eaec), + SPH_C32(0x443d3004) }, + { SPH_C32(0xd3ce0000), SPH_C32(0xc5030000), SPH_C32(0x0c5302ce), + SPH_C32(0x650c0000), SPH_C32(0xc79856ee), SPH_C32(0x0dd77d72), + SPH_C32(0x290c2dc8), SPH_C32(0xdd64a4f5), SPH_C32(0x1e070000), + SPH_C32(0xe0c80000), SPH_C32(0xa27c0506), SPH_C32(0xf85c0000), + SPH_C32(0x1c9d3bb3), SPH_C32(0x5daac55d), SPH_C32(0x265daaf4), + SPH_C32(0x3baa6695) }, + { SPH_C32(0xd2130000), SPH_C32(0x45ab0000), SPH_C32(0xf8c50286), + SPH_C32(0xc30c0000), SPH_C32(0x574d284c), SPH_C32(0xda31f145), + SPH_C32(0x4f1ee235), SPH_C32(0xf1f0e16b), SPH_C32(0x4c570000), + SPH_C32(0xc99c0000), SPH_C32(0xc81d0548), SPH_C32(0x08a30000), + SPH_C32(0x86ac455f), SPH_C32(0x18898493), SPH_C32(0xe90b2511), + SPH_C32(0x68a9759a) }, + { SPH_C32(0x80430000), SPH_C32(0x6cff0000), SPH_C32(0x92a402c8), + SPH_C32(0x33f30000), SPH_C32(0xcd7c56a0), SPH_C32(0x9f12b08b), + SPH_C32(0x80486dd0), SPH_C32(0xa2f3f264), SPH_C32(0x1fda0000), + SPH_C32(0x60600000), SPH_C32(0x56ea054e), SPH_C32(0x5e5c0000), + SPH_C32(0x8c484511), SPH_C32(0x8a4c496a), SPH_C32(0x404f6509), + SPH_C32(0x173e230b) }, + { SPH_C32(0x4d8a0000), SPH_C32(0x49340000), SPH_C32(0x3c8b0500), + SPH_C32(0xaea30000), SPH_C32(0x16793bfd), SPH_C32(0xcf6f08a4), + SPH_C32(0x8f19eaec), SPH_C32(0x443d3004), SPH_C32(0xcc140000), + SPH_C32(0xa5630000), SPH_C32(0x5ab90780), SPH_C32(0x3b500000), + SPH_C32(0x4bd013ff), SPH_C32(0x879b3418), SPH_C32(0x694348c1), + SPH_C32(0xca5a87fe) }, + { SPH_C32(0x1fda0000), SPH_C32(0x60600000), SPH_C32(0x56ea054e), + SPH_C32(0x5e5c0000), SPH_C32(0x8c484511), SPH_C32(0x8a4c496a), + SPH_C32(0x404f6509), SPH_C32(0x173e230b), SPH_C32(0x9f990000), + SPH_C32(0x0c9f0000), SPH_C32(0xc44e0786), SPH_C32(0x6daf0000), + SPH_C32(0x413413b1), SPH_C32(0x155ef9e1), SPH_C32(0xc00708d9), + SPH_C32(0xb5cdd16f) }, + { SPH_C32(0x1e070000), SPH_C32(0xe0c80000), SPH_C32(0xa27c0506), + SPH_C32(0xf85c0000), SPH_C32(0x1c9d3bb3), SPH_C32(0x5daac55d), + SPH_C32(0x265daaf4), SPH_C32(0x3baa6695), SPH_C32(0xcdc90000), + SPH_C32(0x25cb0000), SPH_C32(0xae2f07c8), SPH_C32(0x9d500000), + SPH_C32(0xdb056d5d), SPH_C32(0x507db82f), SPH_C32(0x0f51873c), + SPH_C32(0xe6cec260) }, + { SPH_C32(0x4c570000), SPH_C32(0xc99c0000), SPH_C32(0xc81d0548), + SPH_C32(0x08a30000), SPH_C32(0x86ac455f), SPH_C32(0x18898493), + SPH_C32(0xe90b2511), SPH_C32(0x68a9759a), SPH_C32(0x9e440000), + SPH_C32(0x8c370000), SPH_C32(0x30d807ce), SPH_C32(0xcbaf0000), + SPH_C32(0xd1e16d13), SPH_C32(0xc2b875d6), SPH_C32(0xa615c724), + SPH_C32(0x995994f1) }, + { SPH_C32(0x78230000), SPH_C32(0x12fc0000), SPH_C32(0xa93a0b80), + SPH_C32(0x90a50000), SPH_C32(0x713e2879), SPH_C32(0x7ee98924), + SPH_C32(0xf08ca062), SPH_C32(0x636f8bab), SPH_C32(0x02af0000), + SPH_C32(0xb7280000), SPH_C32(0xba1c0300), SPH_C32(0x56980000), + SPH_C32(0xba8d45d3), SPH_C32(0x8048c667), SPH_C32(0xa95c149a), + SPH_C32(0xf4f6ea7b) }, + { SPH_C32(0x2a730000), SPH_C32(0x3ba80000), SPH_C32(0xc35b0bce), + SPH_C32(0x605a0000), SPH_C32(0xeb0f5695), SPH_C32(0x3bcac8ea), + SPH_C32(0x3fda2f87), SPH_C32(0x306c98a4), SPH_C32(0x51220000), + SPH_C32(0x1ed40000), SPH_C32(0x24eb0306), SPH_C32(0x00670000), + SPH_C32(0xb069459d), SPH_C32(0x128d0b9e), SPH_C32(0x00185482), + SPH_C32(0x8b61bcea) }, + { SPH_C32(0x2bae0000), SPH_C32(0xbb000000), SPH_C32(0x37cd0b86), + SPH_C32(0xc65a0000), SPH_C32(0x7bda2837), SPH_C32(0xec2c44dd), + SPH_C32(0x59c8e07a), SPH_C32(0x1cf8dd3a), SPH_C32(0x03720000), + SPH_C32(0x37800000), SPH_C32(0x4e8a0348), SPH_C32(0xf0980000), + SPH_C32(0x2a583b71), SPH_C32(0x57ae4a50), SPH_C32(0xcf4edb67), + SPH_C32(0xd862afe5) }, + { SPH_C32(0x79fe0000), SPH_C32(0x92540000), SPH_C32(0x5dac0bc8), + SPH_C32(0x36a50000), SPH_C32(0xe1eb56db), SPH_C32(0xa90f0513), + SPH_C32(0x969e6f9f), SPH_C32(0x4ffbce35), SPH_C32(0x50ff0000), + SPH_C32(0x9e7c0000), SPH_C32(0xd07d034e), SPH_C32(0xa6670000), + SPH_C32(0x20bc3b3f), SPH_C32(0xc56b87a9), SPH_C32(0x660a9b7f), + SPH_C32(0xa7f5f974) }, + { SPH_C32(0xb4370000), SPH_C32(0xb79f0000), SPH_C32(0xf3830c00), + SPH_C32(0xabf50000), SPH_C32(0x3aee3b86), SPH_C32(0xf972bd3c), + SPH_C32(0x99cfe8a3), SPH_C32(0xa9350c55), SPH_C32(0x83310000), + SPH_C32(0x5b7f0000), SPH_C32(0xdc2e0180), SPH_C32(0xc36b0000), + SPH_C32(0xe7246dd1), SPH_C32(0xc8bcfadb), SPH_C32(0x4f06b6b7), + SPH_C32(0x7a915d81) }, + { SPH_C32(0xe6670000), SPH_C32(0x9ecb0000), SPH_C32(0x99e20c4e), + SPH_C32(0x5b0a0000), SPH_C32(0xa0df456a), SPH_C32(0xbc51fcf2), + SPH_C32(0x56996746), SPH_C32(0xfa361f5a), SPH_C32(0xd0bc0000), + SPH_C32(0xf2830000), SPH_C32(0x42d90186), SPH_C32(0x95940000), + SPH_C32(0xedc06d9f), SPH_C32(0x5a793722), SPH_C32(0xe642f6af), + SPH_C32(0x05060b10) }, + { SPH_C32(0xe7ba0000), SPH_C32(0x1e630000), SPH_C32(0x6d740c06), + SPH_C32(0xfd0a0000), SPH_C32(0x300a3bc8), SPH_C32(0x6bb770c5), + SPH_C32(0x308ba8bb), SPH_C32(0xd6a25ac4), SPH_C32(0x82ec0000), + SPH_C32(0xdbd70000), SPH_C32(0x28b801c8), SPH_C32(0x656b0000), + SPH_C32(0x77f11373), SPH_C32(0x1f5a76ec), SPH_C32(0x2914794a), + SPH_C32(0x5605181f) }, + { SPH_C32(0xb5ea0000), SPH_C32(0x37370000), SPH_C32(0x07150c48), + SPH_C32(0x0df50000), SPH_C32(0xaa3b4524), SPH_C32(0x2e94310b), + SPH_C32(0xffdd275e), SPH_C32(0x85a149cb), SPH_C32(0xd1610000), + SPH_C32(0x722b0000), SPH_C32(0xb64f01ce), SPH_C32(0x33940000), + SPH_C32(0x7d15133d), SPH_C32(0x8d9fbb15), SPH_C32(0x80503952), + SPH_C32(0x29924e8e) }, + { SPH_C32(0xf9bd0000), SPH_C32(0xfeab0000), SPH_C32(0xcf080900), + SPH_C32(0x05560000), SPH_C32(0x2c97007b), SPH_C32(0x361db598), + SPH_C32(0x16d6024f), SPH_C32(0xed083c51), SPH_C32(0x4f250000), + SPH_C32(0xfe1c0000), SPH_C32(0x86970600), SPH_C32(0xf83b0000), + SPH_C32(0xacf47e2e), SPH_C32(0x4f27cec3), SPH_C32(0x2645fe76), + SPH_C32(0xb0cbda7f) }, + { SPH_C32(0xabed0000), SPH_C32(0xd7ff0000), SPH_C32(0xa569094e), + SPH_C32(0xf5a90000), SPH_C32(0xb6a67e97), SPH_C32(0x733ef456), + SPH_C32(0xd9808daa), SPH_C32(0xbe0b2f5e), SPH_C32(0x1ca80000), + SPH_C32(0x57e00000), SPH_C32(0x18600606), SPH_C32(0xaec40000), + SPH_C32(0xa6107e60), SPH_C32(0xdde2033a), SPH_C32(0x8f01be6e), + SPH_C32(0xcf5c8cee) }, + { SPH_C32(0xaa300000), SPH_C32(0x57570000), SPH_C32(0x51ff0906), + SPH_C32(0x53a90000), SPH_C32(0x26730035), SPH_C32(0xa4d87861), + SPH_C32(0xbf924257), SPH_C32(0x929f6ac0), SPH_C32(0x4ef80000), + SPH_C32(0x7eb40000), SPH_C32(0x72010648), SPH_C32(0x5e3b0000), + SPH_C32(0x3c21008c), SPH_C32(0x98c142f4), SPH_C32(0x4057318b), + SPH_C32(0x9c5f9fe1) }, + { SPH_C32(0xf8600000), SPH_C32(0x7e030000), SPH_C32(0x3b9e0948), + SPH_C32(0xa3560000), SPH_C32(0xbc427ed9), SPH_C32(0xe1fb39af), + SPH_C32(0x70c4cdb2), SPH_C32(0xc19c79cf), SPH_C32(0x1d750000), + SPH_C32(0xd7480000), SPH_C32(0xecf6064e), SPH_C32(0x08c40000), + SPH_C32(0x36c500c2), SPH_C32(0x0a048f0d), SPH_C32(0xe9137193), + SPH_C32(0xe3c8c970) }, + { SPH_C32(0x35a90000), SPH_C32(0x5bc80000), SPH_C32(0x95b10e80), + SPH_C32(0x3e060000), SPH_C32(0x67471384), SPH_C32(0xb1868180), + SPH_C32(0x7f954a8e), SPH_C32(0x2752bbaf), SPH_C32(0xcebb0000), + SPH_C32(0x124b0000), SPH_C32(0xe0a50480), SPH_C32(0x6dc80000), + SPH_C32(0xf15d562c), SPH_C32(0x07d3f27f), SPH_C32(0xc01f5c5b), + SPH_C32(0x3eac6d85) }, + { SPH_C32(0x67f90000), SPH_C32(0x729c0000), SPH_C32(0xffd00ece), + SPH_C32(0xcef90000), SPH_C32(0xfd766d68), SPH_C32(0xf4a5c04e), + SPH_C32(0xb0c3c56b), SPH_C32(0x7451a8a0), SPH_C32(0x9d360000), + SPH_C32(0xbbb70000), SPH_C32(0x7e520486), SPH_C32(0x3b370000), + SPH_C32(0xfbb95662), SPH_C32(0x95163f86), SPH_C32(0x695b1c43), + SPH_C32(0x413b3b14) }, + { SPH_C32(0x66240000), SPH_C32(0xf2340000), SPH_C32(0x0b460e86), + SPH_C32(0x68f90000), SPH_C32(0x6da313ca), SPH_C32(0x23434c79), + SPH_C32(0xd6d10a96), SPH_C32(0x58c5ed3e), SPH_C32(0xcf660000), + SPH_C32(0x92e30000), SPH_C32(0x143304c8), SPH_C32(0xcbc80000), + SPH_C32(0x6188288e), SPH_C32(0xd0357e48), SPH_C32(0xa60d93a6), + SPH_C32(0x1238281b) }, + { SPH_C32(0x34740000), SPH_C32(0xdb600000), SPH_C32(0x61270ec8), + SPH_C32(0x98060000), SPH_C32(0xf7926d26), SPH_C32(0x66600db7), + SPH_C32(0x19878573), SPH_C32(0x0bc6fe31), SPH_C32(0x9ceb0000), + SPH_C32(0x3b1f0000), SPH_C32(0x8ac404ce), SPH_C32(0x9d370000), + SPH_C32(0x6b6c28c0), SPH_C32(0x42f0b3b1), SPH_C32(0x0f49d3be), + SPH_C32(0x6daf7e8a) }, + { SPH_C32(0x02af0000), SPH_C32(0xb7280000), SPH_C32(0xba1c0300), + SPH_C32(0x56980000), SPH_C32(0xba8d45d3), SPH_C32(0x8048c667), + SPH_C32(0xa95c149a), SPH_C32(0xf4f6ea7b), SPH_C32(0x7a8c0000), + SPH_C32(0xa5d40000), SPH_C32(0x13260880), SPH_C32(0xc63d0000), + SPH_C32(0xcbb36daa), SPH_C32(0xfea14f43), SPH_C32(0x59d0b4f8), + SPH_C32(0x979961d0) }, + { SPH_C32(0x50ff0000), SPH_C32(0x9e7c0000), SPH_C32(0xd07d034e), + SPH_C32(0xa6670000), SPH_C32(0x20bc3b3f), SPH_C32(0xc56b87a9), + SPH_C32(0x660a9b7f), SPH_C32(0xa7f5f974), SPH_C32(0x29010000), + SPH_C32(0x0c280000), SPH_C32(0x8dd10886), SPH_C32(0x90c20000), + SPH_C32(0xc1576de4), SPH_C32(0x6c6482ba), SPH_C32(0xf094f4e0), + SPH_C32(0xe80e3741) }, + { SPH_C32(0x51220000), SPH_C32(0x1ed40000), SPH_C32(0x24eb0306), + SPH_C32(0x00670000), SPH_C32(0xb069459d), SPH_C32(0x128d0b9e), + SPH_C32(0x00185482), SPH_C32(0x8b61bcea), SPH_C32(0x7b510000), + SPH_C32(0x257c0000), SPH_C32(0xe7b008c8), SPH_C32(0x603d0000), + SPH_C32(0x5b661308), SPH_C32(0x2947c374), SPH_C32(0x3fc27b05), + SPH_C32(0xbb0d244e) }, + { SPH_C32(0x03720000), SPH_C32(0x37800000), SPH_C32(0x4e8a0348), + SPH_C32(0xf0980000), SPH_C32(0x2a583b71), SPH_C32(0x57ae4a50), + SPH_C32(0xcf4edb67), SPH_C32(0xd862afe5), SPH_C32(0x28dc0000), + SPH_C32(0x8c800000), SPH_C32(0x794708ce), SPH_C32(0x36c20000), + SPH_C32(0x51821346), SPH_C32(0xbb820e8d), SPH_C32(0x96863b1d), + SPH_C32(0xc49a72df) }, + { SPH_C32(0xcebb0000), SPH_C32(0x124b0000), SPH_C32(0xe0a50480), + SPH_C32(0x6dc80000), SPH_C32(0xf15d562c), SPH_C32(0x07d3f27f), + SPH_C32(0xc01f5c5b), SPH_C32(0x3eac6d85), SPH_C32(0xfb120000), + SPH_C32(0x49830000), SPH_C32(0x75140a00), SPH_C32(0x53ce0000), + SPH_C32(0x961a45a8), SPH_C32(0xb65573ff), SPH_C32(0xbf8a16d5), + SPH_C32(0x19fed62a) }, + { SPH_C32(0x9ceb0000), SPH_C32(0x3b1f0000), SPH_C32(0x8ac404ce), + SPH_C32(0x9d370000), SPH_C32(0x6b6c28c0), SPH_C32(0x42f0b3b1), + SPH_C32(0x0f49d3be), SPH_C32(0x6daf7e8a), SPH_C32(0xa89f0000), + SPH_C32(0xe07f0000), SPH_C32(0xebe30a06), SPH_C32(0x05310000), + SPH_C32(0x9cfe45e6), SPH_C32(0x2490be06), SPH_C32(0x16ce56cd), + SPH_C32(0x666980bb) }, + { SPH_C32(0x9d360000), SPH_C32(0xbbb70000), SPH_C32(0x7e520486), + SPH_C32(0x3b370000), SPH_C32(0xfbb95662), SPH_C32(0x95163f86), + SPH_C32(0x695b1c43), SPH_C32(0x413b3b14), SPH_C32(0xfacf0000), + SPH_C32(0xc92b0000), SPH_C32(0x81820a48), SPH_C32(0xf5ce0000), + SPH_C32(0x06cf3b0a), SPH_C32(0x61b3ffc8), SPH_C32(0xd998d928), + SPH_C32(0x356a93b4) }, + { SPH_C32(0xcf660000), SPH_C32(0x92e30000), SPH_C32(0x143304c8), + SPH_C32(0xcbc80000), SPH_C32(0x6188288e), SPH_C32(0xd0357e48), + SPH_C32(0xa60d93a6), SPH_C32(0x1238281b), SPH_C32(0xa9420000), + SPH_C32(0x60d70000), SPH_C32(0x1f750a4e), SPH_C32(0xa3310000), + SPH_C32(0x0c2b3b44), SPH_C32(0xf3763231), SPH_C32(0x70dc9930), + SPH_C32(0x4afdc525) }, + { SPH_C32(0x83310000), SPH_C32(0x5b7f0000), SPH_C32(0xdc2e0180), + SPH_C32(0xc36b0000), SPH_C32(0xe7246dd1), SPH_C32(0xc8bcfadb), + SPH_C32(0x4f06b6b7), SPH_C32(0x7a915d81), SPH_C32(0x37060000), + SPH_C32(0xece00000), SPH_C32(0x2fad0d80), SPH_C32(0x689e0000), + SPH_C32(0xddca5657), SPH_C32(0x31ce47e7), SPH_C32(0xd6c95e14), + SPH_C32(0xd3a451d4) }, + { SPH_C32(0xd1610000), SPH_C32(0x722b0000), SPH_C32(0xb64f01ce), + SPH_C32(0x33940000), SPH_C32(0x7d15133d), SPH_C32(0x8d9fbb15), + SPH_C32(0x80503952), SPH_C32(0x29924e8e), SPH_C32(0x648b0000), + SPH_C32(0x451c0000), SPH_C32(0xb15a0d86), SPH_C32(0x3e610000), + SPH_C32(0xd72e5619), SPH_C32(0xa30b8a1e), SPH_C32(0x7f8d1e0c), + SPH_C32(0xac330745) }, + { SPH_C32(0xd0bc0000), SPH_C32(0xf2830000), SPH_C32(0x42d90186), + SPH_C32(0x95940000), SPH_C32(0xedc06d9f), SPH_C32(0x5a793722), + SPH_C32(0xe642f6af), SPH_C32(0x05060b10), SPH_C32(0x36db0000), + SPH_C32(0x6c480000), SPH_C32(0xdb3b0dc8), SPH_C32(0xce9e0000), + SPH_C32(0x4d1f28f5), SPH_C32(0xe628cbd0), SPH_C32(0xb0db91e9), + SPH_C32(0xff30144a) }, + { SPH_C32(0x82ec0000), SPH_C32(0xdbd70000), SPH_C32(0x28b801c8), + SPH_C32(0x656b0000), SPH_C32(0x77f11373), SPH_C32(0x1f5a76ec), + SPH_C32(0x2914794a), SPH_C32(0x5605181f), SPH_C32(0x65560000), + SPH_C32(0xc5b40000), SPH_C32(0x45cc0dce), SPH_C32(0x98610000), + SPH_C32(0x47fb28bb), SPH_C32(0x74ed0629), SPH_C32(0x199fd1f1), + SPH_C32(0x80a742db) }, + { SPH_C32(0x4f250000), SPH_C32(0xfe1c0000), SPH_C32(0x86970600), + SPH_C32(0xf83b0000), SPH_C32(0xacf47e2e), SPH_C32(0x4f27cec3), + SPH_C32(0x2645fe76), SPH_C32(0xb0cbda7f), SPH_C32(0xb6980000), + SPH_C32(0x00b70000), SPH_C32(0x499f0f00), SPH_C32(0xfd6d0000), + SPH_C32(0x80637e55), SPH_C32(0x793a7b5b), SPH_C32(0x3093fc39), + SPH_C32(0x5dc3e62e) }, + { SPH_C32(0x1d750000), SPH_C32(0xd7480000), SPH_C32(0xecf6064e), + SPH_C32(0x08c40000), SPH_C32(0x36c500c2), SPH_C32(0x0a048f0d), + SPH_C32(0xe9137193), SPH_C32(0xe3c8c970), SPH_C32(0xe5150000), + SPH_C32(0xa94b0000), SPH_C32(0xd7680f06), SPH_C32(0xab920000), + SPH_C32(0x8a877e1b), SPH_C32(0xebffb6a2), SPH_C32(0x99d7bc21), + SPH_C32(0x2254b0bf) }, + { SPH_C32(0x1ca80000), SPH_C32(0x57e00000), SPH_C32(0x18600606), + SPH_C32(0xaec40000), SPH_C32(0xa6107e60), SPH_C32(0xdde2033a), + SPH_C32(0x8f01be6e), SPH_C32(0xcf5c8cee), SPH_C32(0xb7450000), + SPH_C32(0x801f0000), SPH_C32(0xbd090f48), SPH_C32(0x5b6d0000), + SPH_C32(0x10b600f7), SPH_C32(0xaedcf76c), SPH_C32(0x568133c4), + SPH_C32(0x7157a3b0) }, + { SPH_C32(0x4ef80000), SPH_C32(0x7eb40000), SPH_C32(0x72010648), + SPH_C32(0x5e3b0000), SPH_C32(0x3c21008c), SPH_C32(0x98c142f4), + SPH_C32(0x4057318b), SPH_C32(0x9c5f9fe1), SPH_C32(0xe4c80000), + SPH_C32(0x29e30000), SPH_C32(0x23fe0f4e), SPH_C32(0x0d920000), + SPH_C32(0x1a5200b9), SPH_C32(0x3c193a95), SPH_C32(0xffc573dc), + SPH_C32(0x0ec0f521) }, + { SPH_C32(0x7a8c0000), SPH_C32(0xa5d40000), SPH_C32(0x13260880), + SPH_C32(0xc63d0000), SPH_C32(0xcbb36daa), SPH_C32(0xfea14f43), + SPH_C32(0x59d0b4f8), SPH_C32(0x979961d0), SPH_C32(0x78230000), + SPH_C32(0x12fc0000), SPH_C32(0xa93a0b80), SPH_C32(0x90a50000), + SPH_C32(0x713e2879), SPH_C32(0x7ee98924), SPH_C32(0xf08ca062), + SPH_C32(0x636f8bab) }, + { SPH_C32(0x28dc0000), SPH_C32(0x8c800000), SPH_C32(0x794708ce), + SPH_C32(0x36c20000), SPH_C32(0x51821346), SPH_C32(0xbb820e8d), + SPH_C32(0x96863b1d), SPH_C32(0xc49a72df), SPH_C32(0x2bae0000), + SPH_C32(0xbb000000), SPH_C32(0x37cd0b86), SPH_C32(0xc65a0000), + SPH_C32(0x7bda2837), SPH_C32(0xec2c44dd), SPH_C32(0x59c8e07a), + SPH_C32(0x1cf8dd3a) }, + { SPH_C32(0x29010000), SPH_C32(0x0c280000), SPH_C32(0x8dd10886), + SPH_C32(0x90c20000), SPH_C32(0xc1576de4), SPH_C32(0x6c6482ba), + SPH_C32(0xf094f4e0), SPH_C32(0xe80e3741), SPH_C32(0x79fe0000), + SPH_C32(0x92540000), SPH_C32(0x5dac0bc8), SPH_C32(0x36a50000), + SPH_C32(0xe1eb56db), SPH_C32(0xa90f0513), SPH_C32(0x969e6f9f), + SPH_C32(0x4ffbce35) }, + { SPH_C32(0x7b510000), SPH_C32(0x257c0000), SPH_C32(0xe7b008c8), + SPH_C32(0x603d0000), SPH_C32(0x5b661308), SPH_C32(0x2947c374), + SPH_C32(0x3fc27b05), SPH_C32(0xbb0d244e), SPH_C32(0x2a730000), + SPH_C32(0x3ba80000), SPH_C32(0xc35b0bce), SPH_C32(0x605a0000), + SPH_C32(0xeb0f5695), SPH_C32(0x3bcac8ea), SPH_C32(0x3fda2f87), + SPH_C32(0x306c98a4) }, + { SPH_C32(0xb6980000), SPH_C32(0x00b70000), SPH_C32(0x499f0f00), + SPH_C32(0xfd6d0000), SPH_C32(0x80637e55), SPH_C32(0x793a7b5b), + SPH_C32(0x3093fc39), SPH_C32(0x5dc3e62e), SPH_C32(0xf9bd0000), + SPH_C32(0xfeab0000), SPH_C32(0xcf080900), SPH_C32(0x05560000), + SPH_C32(0x2c97007b), SPH_C32(0x361db598), SPH_C32(0x16d6024f), + SPH_C32(0xed083c51) }, + { SPH_C32(0xe4c80000), SPH_C32(0x29e30000), SPH_C32(0x23fe0f4e), + SPH_C32(0x0d920000), SPH_C32(0x1a5200b9), SPH_C32(0x3c193a95), + SPH_C32(0xffc573dc), SPH_C32(0x0ec0f521), SPH_C32(0xaa300000), + SPH_C32(0x57570000), SPH_C32(0x51ff0906), SPH_C32(0x53a90000), + SPH_C32(0x26730035), SPH_C32(0xa4d87861), SPH_C32(0xbf924257), + SPH_C32(0x929f6ac0) }, + { SPH_C32(0xe5150000), SPH_C32(0xa94b0000), SPH_C32(0xd7680f06), + SPH_C32(0xab920000), SPH_C32(0x8a877e1b), SPH_C32(0xebffb6a2), + SPH_C32(0x99d7bc21), SPH_C32(0x2254b0bf), SPH_C32(0xf8600000), + SPH_C32(0x7e030000), SPH_C32(0x3b9e0948), SPH_C32(0xa3560000), + SPH_C32(0xbc427ed9), SPH_C32(0xe1fb39af), SPH_C32(0x70c4cdb2), + SPH_C32(0xc19c79cf) }, + { SPH_C32(0xb7450000), SPH_C32(0x801f0000), SPH_C32(0xbd090f48), + SPH_C32(0x5b6d0000), SPH_C32(0x10b600f7), SPH_C32(0xaedcf76c), + SPH_C32(0x568133c4), SPH_C32(0x7157a3b0), SPH_C32(0xabed0000), + SPH_C32(0xd7ff0000), SPH_C32(0xa569094e), SPH_C32(0xf5a90000), + SPH_C32(0xb6a67e97), SPH_C32(0x733ef456), SPH_C32(0xd9808daa), + SPH_C32(0xbe0b2f5e) }, + { SPH_C32(0xfb120000), SPH_C32(0x49830000), SPH_C32(0x75140a00), + SPH_C32(0x53ce0000), SPH_C32(0x961a45a8), SPH_C32(0xb65573ff), + SPH_C32(0xbf8a16d5), SPH_C32(0x19fed62a), SPH_C32(0x35a90000), + SPH_C32(0x5bc80000), SPH_C32(0x95b10e80), SPH_C32(0x3e060000), + SPH_C32(0x67471384), SPH_C32(0xb1868180), SPH_C32(0x7f954a8e), + SPH_C32(0x2752bbaf) }, + { SPH_C32(0xa9420000), SPH_C32(0x60d70000), SPH_C32(0x1f750a4e), + SPH_C32(0xa3310000), SPH_C32(0x0c2b3b44), SPH_C32(0xf3763231), + SPH_C32(0x70dc9930), SPH_C32(0x4afdc525), SPH_C32(0x66240000), + SPH_C32(0xf2340000), SPH_C32(0x0b460e86), SPH_C32(0x68f90000), + SPH_C32(0x6da313ca), SPH_C32(0x23434c79), SPH_C32(0xd6d10a96), + SPH_C32(0x58c5ed3e) }, + { SPH_C32(0xa89f0000), SPH_C32(0xe07f0000), SPH_C32(0xebe30a06), + SPH_C32(0x05310000), SPH_C32(0x9cfe45e6), SPH_C32(0x2490be06), + SPH_C32(0x16ce56cd), SPH_C32(0x666980bb), SPH_C32(0x34740000), + SPH_C32(0xdb600000), SPH_C32(0x61270ec8), SPH_C32(0x98060000), + SPH_C32(0xf7926d26), SPH_C32(0x66600db7), SPH_C32(0x19878573), + SPH_C32(0x0bc6fe31) }, + { SPH_C32(0xfacf0000), SPH_C32(0xc92b0000), SPH_C32(0x81820a48), + SPH_C32(0xf5ce0000), SPH_C32(0x06cf3b0a), SPH_C32(0x61b3ffc8), + SPH_C32(0xd998d928), SPH_C32(0x356a93b4), SPH_C32(0x67f90000), + SPH_C32(0x729c0000), SPH_C32(0xffd00ece), SPH_C32(0xcef90000), + SPH_C32(0xfd766d68), SPH_C32(0xf4a5c04e), SPH_C32(0xb0c3c56b), + SPH_C32(0x7451a8a0) }, + { SPH_C32(0x37060000), SPH_C32(0xece00000), SPH_C32(0x2fad0d80), + SPH_C32(0x689e0000), SPH_C32(0xddca5657), SPH_C32(0x31ce47e7), + SPH_C32(0xd6c95e14), SPH_C32(0xd3a451d4), SPH_C32(0xb4370000), + SPH_C32(0xb79f0000), SPH_C32(0xf3830c00), SPH_C32(0xabf50000), + SPH_C32(0x3aee3b86), SPH_C32(0xf972bd3c), SPH_C32(0x99cfe8a3), + SPH_C32(0xa9350c55) }, + { SPH_C32(0x65560000), SPH_C32(0xc5b40000), SPH_C32(0x45cc0dce), + SPH_C32(0x98610000), SPH_C32(0x47fb28bb), SPH_C32(0x74ed0629), + SPH_C32(0x199fd1f1), SPH_C32(0x80a742db), SPH_C32(0xe7ba0000), + SPH_C32(0x1e630000), SPH_C32(0x6d740c06), SPH_C32(0xfd0a0000), + SPH_C32(0x300a3bc8), SPH_C32(0x6bb770c5), SPH_C32(0x308ba8bb), + SPH_C32(0xd6a25ac4) }, + { SPH_C32(0x648b0000), SPH_C32(0x451c0000), SPH_C32(0xb15a0d86), + SPH_C32(0x3e610000), SPH_C32(0xd72e5619), SPH_C32(0xa30b8a1e), + SPH_C32(0x7f8d1e0c), SPH_C32(0xac330745), SPH_C32(0xb5ea0000), + SPH_C32(0x37370000), SPH_C32(0x07150c48), SPH_C32(0x0df50000), + SPH_C32(0xaa3b4524), SPH_C32(0x2e94310b), SPH_C32(0xffdd275e), + SPH_C32(0x85a149cb) }, + { SPH_C32(0x36db0000), SPH_C32(0x6c480000), SPH_C32(0xdb3b0dc8), + SPH_C32(0xce9e0000), SPH_C32(0x4d1f28f5), SPH_C32(0xe628cbd0), + SPH_C32(0xb0db91e9), SPH_C32(0xff30144a), SPH_C32(0xe6670000), + SPH_C32(0x9ecb0000), SPH_C32(0x99e20c4e), SPH_C32(0x5b0a0000), + SPH_C32(0xa0df456a), SPH_C32(0xbc51fcf2), SPH_C32(0x56996746), + SPH_C32(0xfa361f5a) } +}; + +static const sph_u32 T512_42[64][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0x58430000), SPH_C32(0x807e0000), SPH_C32(0x78330001), + SPH_C32(0xc66b3800), SPH_C32(0xe7375cdc), SPH_C32(0x79ad3fdd), + SPH_C32(0xac73fe6f), SPH_C32(0x3a4479b1), SPH_C32(0x1d5a0000), + SPH_C32(0x2b720000), SPH_C32(0x488d0000), SPH_C32(0xaf611800), + SPH_C32(0x25cb2ec5), SPH_C32(0xc879bfd0), SPH_C32(0x81a20429), + SPH_C32(0x1e7536a6) }, + { SPH_C32(0x1d5a0000), SPH_C32(0x2b720000), SPH_C32(0x488d0000), + SPH_C32(0xaf611800), SPH_C32(0x25cb2ec5), SPH_C32(0xc879bfd0), + SPH_C32(0x81a20429), SPH_C32(0x1e7536a6), SPH_C32(0x45190000), + SPH_C32(0xab0c0000), SPH_C32(0x30be0001), SPH_C32(0x690a2000), + SPH_C32(0xc2fc7219), SPH_C32(0xb1d4800d), SPH_C32(0x2dd1fa46), + SPH_C32(0x24314f17) }, + { SPH_C32(0x45190000), SPH_C32(0xab0c0000), SPH_C32(0x30be0001), + SPH_C32(0x690a2000), SPH_C32(0xc2fc7219), SPH_C32(0xb1d4800d), + SPH_C32(0x2dd1fa46), SPH_C32(0x24314f17), SPH_C32(0x58430000), + SPH_C32(0x807e0000), SPH_C32(0x78330001), SPH_C32(0xc66b3800), + SPH_C32(0xe7375cdc), SPH_C32(0x79ad3fdd), SPH_C32(0xac73fe6f), + SPH_C32(0x3a4479b1) }, + { SPH_C32(0xa53b0000), SPH_C32(0x14260000), SPH_C32(0x4e30001e), + SPH_C32(0x7cae0000), SPH_C32(0x8f9e0dd5), SPH_C32(0x78dfaa3d), + SPH_C32(0xf73168d8), SPH_C32(0x0b1b4946), SPH_C32(0x07ed0000), + SPH_C32(0xb2500000), SPH_C32(0x8774000a), SPH_C32(0x970d0000), + SPH_C32(0x437223ae), SPH_C32(0x48c76ea4), SPH_C32(0xf4786222), + SPH_C32(0x9075b1ce) }, + { SPH_C32(0xfd780000), SPH_C32(0x94580000), SPH_C32(0x3603001f), + SPH_C32(0xbac53800), SPH_C32(0x68a95109), SPH_C32(0x017295e0), + SPH_C32(0x5b4296b7), SPH_C32(0x315f30f7), SPH_C32(0x1ab70000), + SPH_C32(0x99220000), SPH_C32(0xcff9000a), SPH_C32(0x386c1800), + SPH_C32(0x66b90d6b), SPH_C32(0x80bed174), SPH_C32(0x75da660b), + SPH_C32(0x8e008768) }, + { SPH_C32(0xb8610000), SPH_C32(0x3f540000), SPH_C32(0x06bd001e), + SPH_C32(0xd3cf1800), SPH_C32(0xaa552310), SPH_C32(0xb0a615ed), + SPH_C32(0x76936cf1), SPH_C32(0x156e7fe0), SPH_C32(0x42f40000), + SPH_C32(0x195c0000), SPH_C32(0xb7ca000b), SPH_C32(0xfe072000), + SPH_C32(0x818e51b7), SPH_C32(0xf913eea9), SPH_C32(0xd9a99864), + SPH_C32(0xb444fed9) }, + { SPH_C32(0xe0220000), SPH_C32(0xbf2a0000), SPH_C32(0x7e8e001f), + SPH_C32(0x15a42000), SPH_C32(0x4d627fcc), SPH_C32(0xc90b2a30), + SPH_C32(0xdae0929e), SPH_C32(0x2f2a0651), SPH_C32(0x5fae0000), + SPH_C32(0x322e0000), SPH_C32(0xff47000b), SPH_C32(0x51663800), + SPH_C32(0xa4457f72), SPH_C32(0x316a5179), SPH_C32(0x580b9c4d), + SPH_C32(0xaa31c87f) }, + { SPH_C32(0x07ed0000), SPH_C32(0xb2500000), SPH_C32(0x8774000a), + SPH_C32(0x970d0000), SPH_C32(0x437223ae), SPH_C32(0x48c76ea4), + SPH_C32(0xf4786222), SPH_C32(0x9075b1ce), SPH_C32(0xa2d60000), + SPH_C32(0xa6760000), SPH_C32(0xc9440014), SPH_C32(0xeba30000), + SPH_C32(0xccec2e7b), SPH_C32(0x3018c499), SPH_C32(0x03490afa), + SPH_C32(0x9b6ef888) }, + { SPH_C32(0x5fae0000), SPH_C32(0x322e0000), SPH_C32(0xff47000b), + SPH_C32(0x51663800), SPH_C32(0xa4457f72), SPH_C32(0x316a5179), + SPH_C32(0x580b9c4d), SPH_C32(0xaa31c87f), SPH_C32(0xbf8c0000), + SPH_C32(0x8d040000), SPH_C32(0x81c90014), SPH_C32(0x44c21800), + SPH_C32(0xe92700be), SPH_C32(0xf8617b49), SPH_C32(0x82eb0ed3), + SPH_C32(0x851bce2e) }, + { SPH_C32(0x1ab70000), SPH_C32(0x99220000), SPH_C32(0xcff9000a), + SPH_C32(0x386c1800), SPH_C32(0x66b90d6b), SPH_C32(0x80bed174), + SPH_C32(0x75da660b), SPH_C32(0x8e008768), SPH_C32(0xe7cf0000), + SPH_C32(0x0d7a0000), SPH_C32(0xf9fa0015), SPH_C32(0x82a92000), + SPH_C32(0x0e105c62), SPH_C32(0x81cc4494), SPH_C32(0x2e98f0bc), + SPH_C32(0xbf5fb79f) }, + { SPH_C32(0x42f40000), SPH_C32(0x195c0000), SPH_C32(0xb7ca000b), + SPH_C32(0xfe072000), SPH_C32(0x818e51b7), SPH_C32(0xf913eea9), + SPH_C32(0xd9a99864), SPH_C32(0xb444fed9), SPH_C32(0xfa950000), + SPH_C32(0x26080000), SPH_C32(0xb1770015), SPH_C32(0x2dc83800), + SPH_C32(0x2bdb72a7), SPH_C32(0x49b5fb44), SPH_C32(0xaf3af495), + SPH_C32(0xa12a8139) }, + { SPH_C32(0xa2d60000), SPH_C32(0xa6760000), SPH_C32(0xc9440014), + SPH_C32(0xeba30000), SPH_C32(0xccec2e7b), SPH_C32(0x3018c499), + SPH_C32(0x03490afa), SPH_C32(0x9b6ef888), SPH_C32(0xa53b0000), + SPH_C32(0x14260000), SPH_C32(0x4e30001e), SPH_C32(0x7cae0000), + SPH_C32(0x8f9e0dd5), SPH_C32(0x78dfaa3d), SPH_C32(0xf73168d8), + SPH_C32(0x0b1b4946) }, + { SPH_C32(0xfa950000), SPH_C32(0x26080000), SPH_C32(0xb1770015), + SPH_C32(0x2dc83800), SPH_C32(0x2bdb72a7), SPH_C32(0x49b5fb44), + SPH_C32(0xaf3af495), SPH_C32(0xa12a8139), SPH_C32(0xb8610000), + SPH_C32(0x3f540000), SPH_C32(0x06bd001e), SPH_C32(0xd3cf1800), + SPH_C32(0xaa552310), SPH_C32(0xb0a615ed), SPH_C32(0x76936cf1), + SPH_C32(0x156e7fe0) }, + { SPH_C32(0xbf8c0000), SPH_C32(0x8d040000), SPH_C32(0x81c90014), + SPH_C32(0x44c21800), SPH_C32(0xe92700be), SPH_C32(0xf8617b49), + SPH_C32(0x82eb0ed3), SPH_C32(0x851bce2e), SPH_C32(0xe0220000), + SPH_C32(0xbf2a0000), SPH_C32(0x7e8e001f), SPH_C32(0x15a42000), + SPH_C32(0x4d627fcc), SPH_C32(0xc90b2a30), SPH_C32(0xdae0929e), + SPH_C32(0x2f2a0651) }, + { SPH_C32(0xe7cf0000), SPH_C32(0x0d7a0000), SPH_C32(0xf9fa0015), + SPH_C32(0x82a92000), SPH_C32(0x0e105c62), SPH_C32(0x81cc4494), + SPH_C32(0x2e98f0bc), SPH_C32(0xbf5fb79f), SPH_C32(0xfd780000), + SPH_C32(0x94580000), SPH_C32(0x3603001f), SPH_C32(0xbac53800), + SPH_C32(0x68a95109), SPH_C32(0x017295e0), SPH_C32(0x5b4296b7), + SPH_C32(0x315f30f7) }, + { SPH_C32(0x88980000), SPH_C32(0x1f940000), SPH_C32(0x7fcf002e), + SPH_C32(0xfb4e0000), SPH_C32(0xf158079a), SPH_C32(0x61ae9167), + SPH_C32(0xa895706c), SPH_C32(0xe6107494), SPH_C32(0x0bc20000), + SPH_C32(0xdb630000), SPH_C32(0x7e88000c), SPH_C32(0x15860000), + SPH_C32(0x91fd48f3), SPH_C32(0x7581bb43), SPH_C32(0xf460449e), + SPH_C32(0xd8b61463) }, + { SPH_C32(0xd0db0000), SPH_C32(0x9fea0000), SPH_C32(0x07fc002f), + SPH_C32(0x3d253800), SPH_C32(0x166f5b46), SPH_C32(0x1803aeba), + SPH_C32(0x04e68e03), SPH_C32(0xdc540d25), SPH_C32(0x16980000), + SPH_C32(0xf0110000), SPH_C32(0x3605000c), SPH_C32(0xbae71800), + SPH_C32(0xb4366636), SPH_C32(0xbdf80493), SPH_C32(0x75c240b7), + SPH_C32(0xc6c322c5) }, + { SPH_C32(0x95c20000), SPH_C32(0x34e60000), SPH_C32(0x3742002e), + SPH_C32(0x542f1800), SPH_C32(0xd493295f), SPH_C32(0xa9d72eb7), + SPH_C32(0x29377445), SPH_C32(0xf8654232), SPH_C32(0x4edb0000), + SPH_C32(0x706f0000), SPH_C32(0x4e36000d), SPH_C32(0x7c8c2000), + SPH_C32(0x53013aea), SPH_C32(0xc4553b4e), SPH_C32(0xd9b1bed8), + SPH_C32(0xfc875b74) }, + { SPH_C32(0xcd810000), SPH_C32(0xb4980000), SPH_C32(0x4f71002f), + SPH_C32(0x92442000), SPH_C32(0x33a47583), SPH_C32(0xd07a116a), + SPH_C32(0x85448a2a), SPH_C32(0xc2213b83), SPH_C32(0x53810000), + SPH_C32(0x5b1d0000), SPH_C32(0x06bb000d), SPH_C32(0xd3ed3800), + SPH_C32(0x76ca142f), SPH_C32(0x0c2c849e), SPH_C32(0x5813baf1), + SPH_C32(0xe2f26dd2) }, + { SPH_C32(0x2da30000), SPH_C32(0x0bb20000), SPH_C32(0x31ff0030), + SPH_C32(0x87e00000), SPH_C32(0x7ec60a4f), SPH_C32(0x19713b5a), + SPH_C32(0x5fa418b4), SPH_C32(0xed0b3dd2), SPH_C32(0x0c2f0000), + SPH_C32(0x69330000), SPH_C32(0xf9fc0006), SPH_C32(0x828b0000), + SPH_C32(0xd28f6b5d), SPH_C32(0x3d46d5e7), SPH_C32(0x001826bc), + SPH_C32(0x48c3a5ad) }, + { SPH_C32(0x75e00000), SPH_C32(0x8bcc0000), SPH_C32(0x49cc0031), + SPH_C32(0x418b3800), SPH_C32(0x99f15693), SPH_C32(0x60dc0487), + SPH_C32(0xf3d7e6db), SPH_C32(0xd74f4463), SPH_C32(0x11750000), + SPH_C32(0x42410000), SPH_C32(0xb1710006), SPH_C32(0x2dea1800), + SPH_C32(0xf7444598), SPH_C32(0xf53f6a37), SPH_C32(0x81ba2295), + SPH_C32(0x56b6930b) }, + { SPH_C32(0x30f90000), SPH_C32(0x20c00000), SPH_C32(0x79720030), + SPH_C32(0x28811800), SPH_C32(0x5b0d248a), SPH_C32(0xd108848a), + SPH_C32(0xde061c9d), SPH_C32(0xf37e0b74), SPH_C32(0x49360000), + SPH_C32(0xc23f0000), SPH_C32(0xc9420007), SPH_C32(0xeb812000), + SPH_C32(0x10731944), SPH_C32(0x8c9255ea), SPH_C32(0x2dc9dcfa), + SPH_C32(0x6cf2eaba) }, + { SPH_C32(0x68ba0000), SPH_C32(0xa0be0000), SPH_C32(0x01410031), + SPH_C32(0xeeea2000), SPH_C32(0xbc3a7856), SPH_C32(0xa8a5bb57), + SPH_C32(0x7275e2f2), SPH_C32(0xc93a72c5), SPH_C32(0x546c0000), + SPH_C32(0xe94d0000), SPH_C32(0x81cf0007), SPH_C32(0x44e03800), + SPH_C32(0x35b83781), SPH_C32(0x44ebea3a), SPH_C32(0xac6bd8d3), + SPH_C32(0x7287dc1c) }, + { SPH_C32(0x8f750000), SPH_C32(0xadc40000), SPH_C32(0xf8bb0024), + SPH_C32(0x6c430000), SPH_C32(0xb22a2434), SPH_C32(0x2969ffc3), + SPH_C32(0x5ced124e), SPH_C32(0x7665c55a), SPH_C32(0xa9140000), + SPH_C32(0x7d150000), SPH_C32(0xb7cc0018), SPH_C32(0xfe250000), + SPH_C32(0x5d116688), SPH_C32(0x45997fda), SPH_C32(0xf7294e64), + SPH_C32(0x43d8eceb) }, + { SPH_C32(0xd7360000), SPH_C32(0x2dba0000), SPH_C32(0x80880025), + SPH_C32(0xaa283800), SPH_C32(0x551d78e8), SPH_C32(0x50c4c01e), + SPH_C32(0xf09eec21), SPH_C32(0x4c21bceb), SPH_C32(0xb44e0000), + SPH_C32(0x56670000), SPH_C32(0xff410018), SPH_C32(0x51441800), + SPH_C32(0x78da484d), SPH_C32(0x8de0c00a), SPH_C32(0x768b4a4d), + SPH_C32(0x5dadda4d) }, + { SPH_C32(0x922f0000), SPH_C32(0x86b60000), SPH_C32(0xb0360024), + SPH_C32(0xc3221800), SPH_C32(0x97e10af1), SPH_C32(0xe1104013), + SPH_C32(0xdd4f1667), SPH_C32(0x6810f3fc), SPH_C32(0xec0d0000), + SPH_C32(0xd6190000), SPH_C32(0x87720019), SPH_C32(0x972f2000), + SPH_C32(0x9fed1491), SPH_C32(0xf44dffd7), SPH_C32(0xdaf8b422), + SPH_C32(0x67e9a3fc) }, + { SPH_C32(0xca6c0000), SPH_C32(0x06c80000), SPH_C32(0xc8050025), + SPH_C32(0x05492000), SPH_C32(0x70d6562d), SPH_C32(0x98bd7fce), + SPH_C32(0x713ce808), SPH_C32(0x52548a4d), SPH_C32(0xf1570000), + SPH_C32(0xfd6b0000), SPH_C32(0xcfff0019), SPH_C32(0x384e3800), + SPH_C32(0xba263a54), SPH_C32(0x3c344007), SPH_C32(0x5b5ab00b), + SPH_C32(0x799c955a) }, + { SPH_C32(0x2a4e0000), SPH_C32(0xb9e20000), SPH_C32(0xb68b003a), + SPH_C32(0x10ed0000), SPH_C32(0x3db429e1), SPH_C32(0x51b655fe), + SPH_C32(0xabdc7a96), SPH_C32(0x7d7e8c1c), SPH_C32(0xaef90000), + SPH_C32(0xcf450000), SPH_C32(0x30b80012), SPH_C32(0x69280000), + SPH_C32(0x1e634526), SPH_C32(0x0d5e117e), SPH_C32(0x03512c46), + SPH_C32(0xd3ad5d25) }, + { SPH_C32(0x720d0000), SPH_C32(0x399c0000), SPH_C32(0xceb8003b), + SPH_C32(0xd6863800), SPH_C32(0xda83753d), SPH_C32(0x281b6a23), + SPH_C32(0x07af84f9), SPH_C32(0x473af5ad), SPH_C32(0xb3a30000), + SPH_C32(0xe4370000), SPH_C32(0x78350012), SPH_C32(0xc6491800), + SPH_C32(0x3ba86be3), SPH_C32(0xc527aeae), SPH_C32(0x82f3286f), + SPH_C32(0xcdd86b83) }, + { SPH_C32(0x37140000), SPH_C32(0x92900000), SPH_C32(0xfe06003a), + SPH_C32(0xbf8c1800), SPH_C32(0x187f0724), SPH_C32(0x99cfea2e), + SPH_C32(0x2a7e7ebf), SPH_C32(0x630bbaba), SPH_C32(0xebe00000), + SPH_C32(0x64490000), SPH_C32(0x00060013), SPH_C32(0x00222000), + SPH_C32(0xdc9f373f), SPH_C32(0xbc8a9173), SPH_C32(0x2e80d600), + SPH_C32(0xf79c1232) }, + { SPH_C32(0x6f570000), SPH_C32(0x12ee0000), SPH_C32(0x8635003b), + SPH_C32(0x79e72000), SPH_C32(0xff485bf8), SPH_C32(0xe062d5f3), + SPH_C32(0x860d80d0), SPH_C32(0x594fc30b), SPH_C32(0xf6ba0000), + SPH_C32(0x4f3b0000), SPH_C32(0x488b0013), SPH_C32(0xaf433800), + SPH_C32(0xf95419fa), SPH_C32(0x74f32ea3), SPH_C32(0xaf22d229), + SPH_C32(0xe9e92494) }, + { SPH_C32(0x0bc20000), SPH_C32(0xdb630000), SPH_C32(0x7e88000c), + SPH_C32(0x15860000), SPH_C32(0x91fd48f3), SPH_C32(0x7581bb43), + SPH_C32(0xf460449e), SPH_C32(0xd8b61463), SPH_C32(0x835a0000), + SPH_C32(0xc4f70000), SPH_C32(0x01470022), SPH_C32(0xeec80000), + SPH_C32(0x60a54f69), SPH_C32(0x142f2a24), SPH_C32(0x5cf534f2), + SPH_C32(0x3ea660f7) }, + { SPH_C32(0x53810000), SPH_C32(0x5b1d0000), SPH_C32(0x06bb000d), + SPH_C32(0xd3ed3800), SPH_C32(0x76ca142f), SPH_C32(0x0c2c849e), + SPH_C32(0x5813baf1), SPH_C32(0xe2f26dd2), SPH_C32(0x9e000000), + SPH_C32(0xef850000), SPH_C32(0x49ca0022), SPH_C32(0x41a91800), + SPH_C32(0x456e61ac), SPH_C32(0xdc5695f4), SPH_C32(0xdd5730db), + SPH_C32(0x20d35651) }, + { SPH_C32(0x16980000), SPH_C32(0xf0110000), SPH_C32(0x3605000c), + SPH_C32(0xbae71800), SPH_C32(0xb4366636), SPH_C32(0xbdf80493), + SPH_C32(0x75c240b7), SPH_C32(0xc6c322c5), SPH_C32(0xc6430000), + SPH_C32(0x6ffb0000), SPH_C32(0x31f90023), SPH_C32(0x87c22000), + SPH_C32(0xa2593d70), SPH_C32(0xa5fbaa29), SPH_C32(0x7124ceb4), + SPH_C32(0x1a972fe0) }, + { SPH_C32(0x4edb0000), SPH_C32(0x706f0000), SPH_C32(0x4e36000d), + SPH_C32(0x7c8c2000), SPH_C32(0x53013aea), SPH_C32(0xc4553b4e), + SPH_C32(0xd9b1bed8), SPH_C32(0xfc875b74), SPH_C32(0xdb190000), + SPH_C32(0x44890000), SPH_C32(0x79740023), SPH_C32(0x28a33800), + SPH_C32(0x879213b5), SPH_C32(0x6d8215f9), SPH_C32(0xf086ca9d), + SPH_C32(0x04e21946) }, + { SPH_C32(0xaef90000), SPH_C32(0xcf450000), SPH_C32(0x30b80012), + SPH_C32(0x69280000), SPH_C32(0x1e634526), SPH_C32(0x0d5e117e), + SPH_C32(0x03512c46), SPH_C32(0xd3ad5d25), SPH_C32(0x84b70000), + SPH_C32(0x76a70000), SPH_C32(0x86330028), SPH_C32(0x79c50000), + SPH_C32(0x23d76cc7), SPH_C32(0x5ce84480), SPH_C32(0xa88d56d0), + SPH_C32(0xaed3d139) }, + { SPH_C32(0xf6ba0000), SPH_C32(0x4f3b0000), SPH_C32(0x488b0013), + SPH_C32(0xaf433800), SPH_C32(0xf95419fa), SPH_C32(0x74f32ea3), + SPH_C32(0xaf22d229), SPH_C32(0xe9e92494), SPH_C32(0x99ed0000), + SPH_C32(0x5dd50000), SPH_C32(0xcebe0028), SPH_C32(0xd6a41800), + SPH_C32(0x061c4202), SPH_C32(0x9491fb50), SPH_C32(0x292f52f9), + SPH_C32(0xb0a6e79f) }, + { SPH_C32(0xb3a30000), SPH_C32(0xe4370000), SPH_C32(0x78350012), + SPH_C32(0xc6491800), SPH_C32(0x3ba86be3), SPH_C32(0xc527aeae), + SPH_C32(0x82f3286f), SPH_C32(0xcdd86b83), SPH_C32(0xc1ae0000), + SPH_C32(0xddab0000), SPH_C32(0xb68d0029), SPH_C32(0x10cf2000), + SPH_C32(0xe12b1ede), SPH_C32(0xed3cc48d), SPH_C32(0x855cac96), + SPH_C32(0x8ae29e2e) }, + { SPH_C32(0xebe00000), SPH_C32(0x64490000), SPH_C32(0x00060013), + SPH_C32(0x00222000), SPH_C32(0xdc9f373f), SPH_C32(0xbc8a9173), + SPH_C32(0x2e80d600), SPH_C32(0xf79c1232), SPH_C32(0xdcf40000), + SPH_C32(0xf6d90000), SPH_C32(0xfe000029), SPH_C32(0xbfae3800), + SPH_C32(0xc4e0301b), SPH_C32(0x25457b5d), SPH_C32(0x04fea8bf), + SPH_C32(0x9497a888) }, + { SPH_C32(0x0c2f0000), SPH_C32(0x69330000), SPH_C32(0xf9fc0006), + SPH_C32(0x828b0000), SPH_C32(0xd28f6b5d), SPH_C32(0x3d46d5e7), + SPH_C32(0x001826bc), SPH_C32(0x48c3a5ad), SPH_C32(0x218c0000), + SPH_C32(0x62810000), SPH_C32(0xc8030036), SPH_C32(0x056b0000), + SPH_C32(0xac496112), SPH_C32(0x2437eebd), SPH_C32(0x5fbc3e08), + SPH_C32(0xa5c8987f) }, + { SPH_C32(0x546c0000), SPH_C32(0xe94d0000), SPH_C32(0x81cf0007), + SPH_C32(0x44e03800), SPH_C32(0x35b83781), SPH_C32(0x44ebea3a), + SPH_C32(0xac6bd8d3), SPH_C32(0x7287dc1c), SPH_C32(0x3cd60000), + SPH_C32(0x49f30000), SPH_C32(0x808e0036), SPH_C32(0xaa0a1800), + SPH_C32(0x89824fd7), SPH_C32(0xec4e516d), SPH_C32(0xde1e3a21), + SPH_C32(0xbbbdaed9) }, + { SPH_C32(0x11750000), SPH_C32(0x42410000), SPH_C32(0xb1710006), + SPH_C32(0x2dea1800), SPH_C32(0xf7444598), SPH_C32(0xf53f6a37), + SPH_C32(0x81ba2295), SPH_C32(0x56b6930b), SPH_C32(0x64950000), + SPH_C32(0xc98d0000), SPH_C32(0xf8bd0037), SPH_C32(0x6c612000), + SPH_C32(0x6eb5130b), SPH_C32(0x95e36eb0), SPH_C32(0x726dc44e), + SPH_C32(0x81f9d768) }, + { SPH_C32(0x49360000), SPH_C32(0xc23f0000), SPH_C32(0xc9420007), + SPH_C32(0xeb812000), SPH_C32(0x10731944), SPH_C32(0x8c9255ea), + SPH_C32(0x2dc9dcfa), SPH_C32(0x6cf2eaba), SPH_C32(0x79cf0000), + SPH_C32(0xe2ff0000), SPH_C32(0xb0300037), SPH_C32(0xc3003800), + SPH_C32(0x4b7e3dce), SPH_C32(0x5d9ad160), SPH_C32(0xf3cfc067), + SPH_C32(0x9f8ce1ce) }, + { SPH_C32(0xa9140000), SPH_C32(0x7d150000), SPH_C32(0xb7cc0018), + SPH_C32(0xfe250000), SPH_C32(0x5d116688), SPH_C32(0x45997fda), + SPH_C32(0xf7294e64), SPH_C32(0x43d8eceb), SPH_C32(0x26610000), + SPH_C32(0xd0d10000), SPH_C32(0x4f77003c), SPH_C32(0x92660000), + SPH_C32(0xef3b42bc), SPH_C32(0x6cf08019), SPH_C32(0xabc45c2a), + SPH_C32(0x35bd29b1) }, + { SPH_C32(0xf1570000), SPH_C32(0xfd6b0000), SPH_C32(0xcfff0019), + SPH_C32(0x384e3800), SPH_C32(0xba263a54), SPH_C32(0x3c344007), + SPH_C32(0x5b5ab00b), SPH_C32(0x799c955a), SPH_C32(0x3b3b0000), + SPH_C32(0xfba30000), SPH_C32(0x07fa003c), SPH_C32(0x3d071800), + SPH_C32(0xcaf06c79), SPH_C32(0xa4893fc9), SPH_C32(0x2a665803), + SPH_C32(0x2bc81f17) }, + { SPH_C32(0xb44e0000), SPH_C32(0x56670000), SPH_C32(0xff410018), + SPH_C32(0x51441800), SPH_C32(0x78da484d), SPH_C32(0x8de0c00a), + SPH_C32(0x768b4a4d), SPH_C32(0x5dadda4d), SPH_C32(0x63780000), + SPH_C32(0x7bdd0000), SPH_C32(0x7fc9003d), SPH_C32(0xfb6c2000), + SPH_C32(0x2dc730a5), SPH_C32(0xdd240014), SPH_C32(0x8615a66c), + SPH_C32(0x118c66a6) }, + { SPH_C32(0xec0d0000), SPH_C32(0xd6190000), SPH_C32(0x87720019), + SPH_C32(0x972f2000), SPH_C32(0x9fed1491), SPH_C32(0xf44dffd7), + SPH_C32(0xdaf8b422), SPH_C32(0x67e9a3fc), SPH_C32(0x7e220000), + SPH_C32(0x50af0000), SPH_C32(0x3744003d), SPH_C32(0x540d3800), + SPH_C32(0x080c1e60), SPH_C32(0x155dbfc4), SPH_C32(0x07b7a245), + SPH_C32(0x0ff95000) }, + { SPH_C32(0x835a0000), SPH_C32(0xc4f70000), SPH_C32(0x01470022), + SPH_C32(0xeec80000), SPH_C32(0x60a54f69), SPH_C32(0x142f2a24), + SPH_C32(0x5cf534f2), SPH_C32(0x3ea660f7), SPH_C32(0x88980000), + SPH_C32(0x1f940000), SPH_C32(0x7fcf002e), SPH_C32(0xfb4e0000), + SPH_C32(0xf158079a), SPH_C32(0x61ae9167), SPH_C32(0xa895706c), + SPH_C32(0xe6107494) }, + { SPH_C32(0xdb190000), SPH_C32(0x44890000), SPH_C32(0x79740023), + SPH_C32(0x28a33800), SPH_C32(0x879213b5), SPH_C32(0x6d8215f9), + SPH_C32(0xf086ca9d), SPH_C32(0x04e21946), SPH_C32(0x95c20000), + SPH_C32(0x34e60000), SPH_C32(0x3742002e), SPH_C32(0x542f1800), + SPH_C32(0xd493295f), SPH_C32(0xa9d72eb7), SPH_C32(0x29377445), + SPH_C32(0xf8654232) }, + { SPH_C32(0x9e000000), SPH_C32(0xef850000), SPH_C32(0x49ca0022), + SPH_C32(0x41a91800), SPH_C32(0x456e61ac), SPH_C32(0xdc5695f4), + SPH_C32(0xdd5730db), SPH_C32(0x20d35651), SPH_C32(0xcd810000), + SPH_C32(0xb4980000), SPH_C32(0x4f71002f), SPH_C32(0x92442000), + SPH_C32(0x33a47583), SPH_C32(0xd07a116a), SPH_C32(0x85448a2a), + SPH_C32(0xc2213b83) }, + { SPH_C32(0xc6430000), SPH_C32(0x6ffb0000), SPH_C32(0x31f90023), + SPH_C32(0x87c22000), SPH_C32(0xa2593d70), SPH_C32(0xa5fbaa29), + SPH_C32(0x7124ceb4), SPH_C32(0x1a972fe0), SPH_C32(0xd0db0000), + SPH_C32(0x9fea0000), SPH_C32(0x07fc002f), SPH_C32(0x3d253800), + SPH_C32(0x166f5b46), SPH_C32(0x1803aeba), SPH_C32(0x04e68e03), + SPH_C32(0xdc540d25) }, + { SPH_C32(0x26610000), SPH_C32(0xd0d10000), SPH_C32(0x4f77003c), + SPH_C32(0x92660000), SPH_C32(0xef3b42bc), SPH_C32(0x6cf08019), + SPH_C32(0xabc45c2a), SPH_C32(0x35bd29b1), SPH_C32(0x8f750000), + SPH_C32(0xadc40000), SPH_C32(0xf8bb0024), SPH_C32(0x6c430000), + SPH_C32(0xb22a2434), SPH_C32(0x2969ffc3), SPH_C32(0x5ced124e), + SPH_C32(0x7665c55a) }, + { SPH_C32(0x7e220000), SPH_C32(0x50af0000), SPH_C32(0x3744003d), + SPH_C32(0x540d3800), SPH_C32(0x080c1e60), SPH_C32(0x155dbfc4), + SPH_C32(0x07b7a245), SPH_C32(0x0ff95000), SPH_C32(0x922f0000), + SPH_C32(0x86b60000), SPH_C32(0xb0360024), SPH_C32(0xc3221800), + SPH_C32(0x97e10af1), SPH_C32(0xe1104013), SPH_C32(0xdd4f1667), + SPH_C32(0x6810f3fc) }, + { SPH_C32(0x3b3b0000), SPH_C32(0xfba30000), SPH_C32(0x07fa003c), + SPH_C32(0x3d071800), SPH_C32(0xcaf06c79), SPH_C32(0xa4893fc9), + SPH_C32(0x2a665803), SPH_C32(0x2bc81f17), SPH_C32(0xca6c0000), + SPH_C32(0x06c80000), SPH_C32(0xc8050025), SPH_C32(0x05492000), + SPH_C32(0x70d6562d), SPH_C32(0x98bd7fce), SPH_C32(0x713ce808), + SPH_C32(0x52548a4d) }, + { SPH_C32(0x63780000), SPH_C32(0x7bdd0000), SPH_C32(0x7fc9003d), + SPH_C32(0xfb6c2000), SPH_C32(0x2dc730a5), SPH_C32(0xdd240014), + SPH_C32(0x8615a66c), SPH_C32(0x118c66a6), SPH_C32(0xd7360000), + SPH_C32(0x2dba0000), SPH_C32(0x80880025), SPH_C32(0xaa283800), + SPH_C32(0x551d78e8), SPH_C32(0x50c4c01e), SPH_C32(0xf09eec21), + SPH_C32(0x4c21bceb) }, + { SPH_C32(0x84b70000), SPH_C32(0x76a70000), SPH_C32(0x86330028), + SPH_C32(0x79c50000), SPH_C32(0x23d76cc7), SPH_C32(0x5ce84480), + SPH_C32(0xa88d56d0), SPH_C32(0xaed3d139), SPH_C32(0x2a4e0000), + SPH_C32(0xb9e20000), SPH_C32(0xb68b003a), SPH_C32(0x10ed0000), + SPH_C32(0x3db429e1), SPH_C32(0x51b655fe), SPH_C32(0xabdc7a96), + SPH_C32(0x7d7e8c1c) }, + { SPH_C32(0xdcf40000), SPH_C32(0xf6d90000), SPH_C32(0xfe000029), + SPH_C32(0xbfae3800), SPH_C32(0xc4e0301b), SPH_C32(0x25457b5d), + SPH_C32(0x04fea8bf), SPH_C32(0x9497a888), SPH_C32(0x37140000), + SPH_C32(0x92900000), SPH_C32(0xfe06003a), SPH_C32(0xbf8c1800), + SPH_C32(0x187f0724), SPH_C32(0x99cfea2e), SPH_C32(0x2a7e7ebf), + SPH_C32(0x630bbaba) }, + { SPH_C32(0x99ed0000), SPH_C32(0x5dd50000), SPH_C32(0xcebe0028), + SPH_C32(0xd6a41800), SPH_C32(0x061c4202), SPH_C32(0x9491fb50), + SPH_C32(0x292f52f9), SPH_C32(0xb0a6e79f), SPH_C32(0x6f570000), + SPH_C32(0x12ee0000), SPH_C32(0x8635003b), SPH_C32(0x79e72000), + SPH_C32(0xff485bf8), SPH_C32(0xe062d5f3), SPH_C32(0x860d80d0), + SPH_C32(0x594fc30b) }, + { SPH_C32(0xc1ae0000), SPH_C32(0xddab0000), SPH_C32(0xb68d0029), + SPH_C32(0x10cf2000), SPH_C32(0xe12b1ede), SPH_C32(0xed3cc48d), + SPH_C32(0x855cac96), SPH_C32(0x8ae29e2e), SPH_C32(0x720d0000), + SPH_C32(0x399c0000), SPH_C32(0xceb8003b), SPH_C32(0xd6863800), + SPH_C32(0xda83753d), SPH_C32(0x281b6a23), SPH_C32(0x07af84f9), + SPH_C32(0x473af5ad) }, + { SPH_C32(0x218c0000), SPH_C32(0x62810000), SPH_C32(0xc8030036), + SPH_C32(0x056b0000), SPH_C32(0xac496112), SPH_C32(0x2437eebd), + SPH_C32(0x5fbc3e08), SPH_C32(0xa5c8987f), SPH_C32(0x2da30000), + SPH_C32(0x0bb20000), SPH_C32(0x31ff0030), SPH_C32(0x87e00000), + SPH_C32(0x7ec60a4f), SPH_C32(0x19713b5a), SPH_C32(0x5fa418b4), + SPH_C32(0xed0b3dd2) }, + { SPH_C32(0x79cf0000), SPH_C32(0xe2ff0000), SPH_C32(0xb0300037), + SPH_C32(0xc3003800), SPH_C32(0x4b7e3dce), SPH_C32(0x5d9ad160), + SPH_C32(0xf3cfc067), SPH_C32(0x9f8ce1ce), SPH_C32(0x30f90000), + SPH_C32(0x20c00000), SPH_C32(0x79720030), SPH_C32(0x28811800), + SPH_C32(0x5b0d248a), SPH_C32(0xd108848a), SPH_C32(0xde061c9d), + SPH_C32(0xf37e0b74) }, + { SPH_C32(0x3cd60000), SPH_C32(0x49f30000), SPH_C32(0x808e0036), + SPH_C32(0xaa0a1800), SPH_C32(0x89824fd7), SPH_C32(0xec4e516d), + SPH_C32(0xde1e3a21), SPH_C32(0xbbbdaed9), SPH_C32(0x68ba0000), + SPH_C32(0xa0be0000), SPH_C32(0x01410031), SPH_C32(0xeeea2000), + SPH_C32(0xbc3a7856), SPH_C32(0xa8a5bb57), SPH_C32(0x7275e2f2), + SPH_C32(0xc93a72c5) }, + { SPH_C32(0x64950000), SPH_C32(0xc98d0000), SPH_C32(0xf8bd0037), + SPH_C32(0x6c612000), SPH_C32(0x6eb5130b), SPH_C32(0x95e36eb0), + SPH_C32(0x726dc44e), SPH_C32(0x81f9d768), SPH_C32(0x75e00000), + SPH_C32(0x8bcc0000), SPH_C32(0x49cc0031), SPH_C32(0x418b3800), + SPH_C32(0x99f15693), SPH_C32(0x60dc0487), SPH_C32(0xf3d7e6db), + SPH_C32(0xd74f4463) } +}; + +static const sph_u32 T512_48[64][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0xb4310000), SPH_C32(0x77330000), SPH_C32(0xb15d0000), + SPH_C32(0x7fd004e0), SPH_C32(0x78a26138), SPH_C32(0xd116c35d), + SPH_C32(0xd256d489), SPH_C32(0x4e6f74de), SPH_C32(0xe3060000), + SPH_C32(0xbdc10000), SPH_C32(0x87130000), SPH_C32(0xbff20060), + SPH_C32(0x2eba0a1a), SPH_C32(0x8db53751), SPH_C32(0x73c5ab06), + SPH_C32(0x5bd61539) }, + { SPH_C32(0xe3060000), SPH_C32(0xbdc10000), SPH_C32(0x87130000), + SPH_C32(0xbff20060), SPH_C32(0x2eba0a1a), SPH_C32(0x8db53751), + SPH_C32(0x73c5ab06), SPH_C32(0x5bd61539), SPH_C32(0x57370000), + SPH_C32(0xcaf20000), SPH_C32(0x364e0000), SPH_C32(0xc0220480), + SPH_C32(0x56186b22), SPH_C32(0x5ca3f40c), SPH_C32(0xa1937f8f), + SPH_C32(0x15b961e7) }, + { SPH_C32(0x57370000), SPH_C32(0xcaf20000), SPH_C32(0x364e0000), + SPH_C32(0xc0220480), SPH_C32(0x56186b22), SPH_C32(0x5ca3f40c), + SPH_C32(0xa1937f8f), SPH_C32(0x15b961e7), SPH_C32(0xb4310000), + SPH_C32(0x77330000), SPH_C32(0xb15d0000), SPH_C32(0x7fd004e0), + SPH_C32(0x78a26138), SPH_C32(0xd116c35d), SPH_C32(0xd256d489), + SPH_C32(0x4e6f74de) }, + { SPH_C32(0x02f20000), SPH_C32(0xa2810000), SPH_C32(0x873f0000), + SPH_C32(0xe36c7800), SPH_C32(0x1e1d74ef), SPH_C32(0x073d2bd6), + SPH_C32(0xc4c23237), SPH_C32(0x7f32259e), SPH_C32(0xbadd0000), + SPH_C32(0x13ad0000), SPH_C32(0xb7e70000), SPH_C32(0xf7282800), + SPH_C32(0xdf45144d), SPH_C32(0x361ac33a), SPH_C32(0xea5a8d14), + SPH_C32(0x2a2c18f0) }, + { SPH_C32(0xb6c30000), SPH_C32(0xd5b20000), SPH_C32(0x36620000), + SPH_C32(0x9cbc7ce0), SPH_C32(0x66bf15d7), SPH_C32(0xd62be88b), + SPH_C32(0x1694e6be), SPH_C32(0x315d5140), SPH_C32(0x59db0000), + SPH_C32(0xae6c0000), SPH_C32(0x30f40000), SPH_C32(0x48da2860), + SPH_C32(0xf1ff1e57), SPH_C32(0xbbaff46b), SPH_C32(0x999f2612), + SPH_C32(0x71fa0dc9) }, + { SPH_C32(0xe1f40000), SPH_C32(0x1f400000), SPH_C32(0x002c0000), + SPH_C32(0x5c9e7860), SPH_C32(0x30a77ef5), SPH_C32(0x8a881c87), + SPH_C32(0xb7079931), SPH_C32(0x24e430a7), SPH_C32(0xedea0000), + SPH_C32(0xd95f0000), SPH_C32(0x81a90000), SPH_C32(0x370a2c80), + SPH_C32(0x895d7f6f), SPH_C32(0x6ab93736), SPH_C32(0x4bc9f29b), + SPH_C32(0x3f957917) }, + { SPH_C32(0x55c50000), SPH_C32(0x68730000), SPH_C32(0xb1710000), + SPH_C32(0x234e7c80), SPH_C32(0x48051fcd), SPH_C32(0x5b9edfda), + SPH_C32(0x65514db8), SPH_C32(0x6a8b4479), SPH_C32(0x0eec0000), + SPH_C32(0x649e0000), SPH_C32(0x06ba0000), SPH_C32(0x88f82ce0), + SPH_C32(0xa7e77575), SPH_C32(0xe70c0067), SPH_C32(0x380c599d), + SPH_C32(0x64436c2e) }, + { SPH_C32(0xbadd0000), SPH_C32(0x13ad0000), SPH_C32(0xb7e70000), + SPH_C32(0xf7282800), SPH_C32(0xdf45144d), SPH_C32(0x361ac33a), + SPH_C32(0xea5a8d14), SPH_C32(0x2a2c18f0), SPH_C32(0xb82f0000), + SPH_C32(0xb12c0000), SPH_C32(0x30d80000), SPH_C32(0x14445000), + SPH_C32(0xc15860a2), SPH_C32(0x3127e8ec), SPH_C32(0x2e98bf23), + SPH_C32(0x551e3d6e) }, + { SPH_C32(0x0eec0000), SPH_C32(0x649e0000), SPH_C32(0x06ba0000), + SPH_C32(0x88f82ce0), SPH_C32(0xa7e77575), SPH_C32(0xe70c0067), + SPH_C32(0x380c599d), SPH_C32(0x64436c2e), SPH_C32(0x5b290000), + SPH_C32(0x0ced0000), SPH_C32(0xb7cb0000), SPH_C32(0xabb65060), + SPH_C32(0xefe26ab8), SPH_C32(0xbc92dfbd), SPH_C32(0x5d5d1425), + SPH_C32(0x0ec82857) }, + { SPH_C32(0x59db0000), SPH_C32(0xae6c0000), SPH_C32(0x30f40000), + SPH_C32(0x48da2860), SPH_C32(0xf1ff1e57), SPH_C32(0xbbaff46b), + SPH_C32(0x999f2612), SPH_C32(0x71fa0dc9), SPH_C32(0xef180000), + SPH_C32(0x7bde0000), SPH_C32(0x06960000), SPH_C32(0xd4665480), + SPH_C32(0x97400b80), SPH_C32(0x6d841ce0), SPH_C32(0x8f0bc0ac), + SPH_C32(0x40a75c89) }, + { SPH_C32(0xedea0000), SPH_C32(0xd95f0000), SPH_C32(0x81a90000), + SPH_C32(0x370a2c80), SPH_C32(0x895d7f6f), SPH_C32(0x6ab93736), + SPH_C32(0x4bc9f29b), SPH_C32(0x3f957917), SPH_C32(0x0c1e0000), + SPH_C32(0xc61f0000), SPH_C32(0x81850000), SPH_C32(0x6b9454e0), + SPH_C32(0xb9fa019a), SPH_C32(0xe0312bb1), SPH_C32(0xfcce6baa), + SPH_C32(0x1b7149b0) }, + { SPH_C32(0xb82f0000), SPH_C32(0xb12c0000), SPH_C32(0x30d80000), + SPH_C32(0x14445000), SPH_C32(0xc15860a2), SPH_C32(0x3127e8ec), + SPH_C32(0x2e98bf23), SPH_C32(0x551e3d6e), SPH_C32(0x02f20000), + SPH_C32(0xa2810000), SPH_C32(0x873f0000), SPH_C32(0xe36c7800), + SPH_C32(0x1e1d74ef), SPH_C32(0x073d2bd6), SPH_C32(0xc4c23237), + SPH_C32(0x7f32259e) }, + { SPH_C32(0x0c1e0000), SPH_C32(0xc61f0000), SPH_C32(0x81850000), + SPH_C32(0x6b9454e0), SPH_C32(0xb9fa019a), SPH_C32(0xe0312bb1), + SPH_C32(0xfcce6baa), SPH_C32(0x1b7149b0), SPH_C32(0xe1f40000), + SPH_C32(0x1f400000), SPH_C32(0x002c0000), SPH_C32(0x5c9e7860), + SPH_C32(0x30a77ef5), SPH_C32(0x8a881c87), SPH_C32(0xb7079931), + SPH_C32(0x24e430a7) }, + { SPH_C32(0x5b290000), SPH_C32(0x0ced0000), SPH_C32(0xb7cb0000), + SPH_C32(0xabb65060), SPH_C32(0xefe26ab8), SPH_C32(0xbc92dfbd), + SPH_C32(0x5d5d1425), SPH_C32(0x0ec82857), SPH_C32(0x55c50000), + SPH_C32(0x68730000), SPH_C32(0xb1710000), SPH_C32(0x234e7c80), + SPH_C32(0x48051fcd), SPH_C32(0x5b9edfda), SPH_C32(0x65514db8), + SPH_C32(0x6a8b4479) }, + { SPH_C32(0xef180000), SPH_C32(0x7bde0000), SPH_C32(0x06960000), + SPH_C32(0xd4665480), SPH_C32(0x97400b80), SPH_C32(0x6d841ce0), + SPH_C32(0x8f0bc0ac), SPH_C32(0x40a75c89), SPH_C32(0xb6c30000), + SPH_C32(0xd5b20000), SPH_C32(0x36620000), SPH_C32(0x9cbc7ce0), + SPH_C32(0x66bf15d7), SPH_C32(0xd62be88b), SPH_C32(0x1694e6be), + SPH_C32(0x315d5140) }, + { SPH_C32(0x1e6c0000), SPH_C32(0xc4420000), SPH_C32(0x8a2e0000), + SPH_C32(0xbcb6b800), SPH_C32(0x2c4413b6), SPH_C32(0x8bfdd3da), + SPH_C32(0x6a0c1bc8), SPH_C32(0xb99dc2eb), SPH_C32(0x92560000), + SPH_C32(0x1eda0000), SPH_C32(0xea510000), SPH_C32(0xe8b13000), + SPH_C32(0xa93556a5), SPH_C32(0xebfb6199), SPH_C32(0xb15c2254), + SPH_C32(0x33c5244f) }, + { SPH_C32(0xaa5d0000), SPH_C32(0xb3710000), SPH_C32(0x3b730000), + SPH_C32(0xc366bce0), SPH_C32(0x54e6728e), SPH_C32(0x5aeb1087), + SPH_C32(0xb85acf41), SPH_C32(0xf7f2b635), SPH_C32(0x71500000), + SPH_C32(0xa31b0000), SPH_C32(0x6d420000), SPH_C32(0x57433060), + SPH_C32(0x878f5cbf), SPH_C32(0x664e56c8), SPH_C32(0xc2998952), + SPH_C32(0x68133176) }, + { SPH_C32(0xfd6a0000), SPH_C32(0x79830000), SPH_C32(0x0d3d0000), + SPH_C32(0x0344b860), SPH_C32(0x02fe19ac), SPH_C32(0x0648e48b), + SPH_C32(0x19c9b0ce), SPH_C32(0xe24bd7d2), SPH_C32(0xc5610000), + SPH_C32(0xd4280000), SPH_C32(0xdc1f0000), SPH_C32(0x28933480), + SPH_C32(0xff2d3d87), SPH_C32(0xb7589595), SPH_C32(0x10cf5ddb), + SPH_C32(0x267c45a8) }, + { SPH_C32(0x495b0000), SPH_C32(0x0eb00000), SPH_C32(0xbc600000), + SPH_C32(0x7c94bc80), SPH_C32(0x7a5c7894), SPH_C32(0xd75e27d6), + SPH_C32(0xcb9f6447), SPH_C32(0xac24a30c), SPH_C32(0x26670000), + SPH_C32(0x69e90000), SPH_C32(0x5b0c0000), SPH_C32(0x976134e0), + SPH_C32(0xd197379d), SPH_C32(0x3aeda2c4), SPH_C32(0x630af6dd), + SPH_C32(0x7daa5091) }, + { SPH_C32(0x1c9e0000), SPH_C32(0x66c30000), SPH_C32(0x0d110000), + SPH_C32(0x5fdac000), SPH_C32(0x32596759), SPH_C32(0x8cc0f80c), + SPH_C32(0xaece29ff), SPH_C32(0xc6afe775), SPH_C32(0x288b0000), + SPH_C32(0x0d770000), SPH_C32(0x5db60000), SPH_C32(0x1f991800), + SPH_C32(0x767042e8), SPH_C32(0xdde1a2a3), SPH_C32(0x5b06af40), + SPH_C32(0x19e93cbf) }, + { SPH_C32(0xa8af0000), SPH_C32(0x11f00000), SPH_C32(0xbc4c0000), + SPH_C32(0x200ac4e0), SPH_C32(0x4afb0661), SPH_C32(0x5dd63b51), + SPH_C32(0x7c98fd76), SPH_C32(0x88c093ab), SPH_C32(0xcb8d0000), + SPH_C32(0xb0b60000), SPH_C32(0xdaa50000), SPH_C32(0xa06b1860), + SPH_C32(0x58ca48f2), SPH_C32(0x505495f2), SPH_C32(0x28c30446), + SPH_C32(0x423f2986) }, + { SPH_C32(0xff980000), SPH_C32(0xdb020000), SPH_C32(0x8a020000), + SPH_C32(0xe028c060), SPH_C32(0x1ce36d43), SPH_C32(0x0175cf5d), + SPH_C32(0xdd0b82f9), SPH_C32(0x9d79f24c), SPH_C32(0x7fbc0000), + SPH_C32(0xc7850000), SPH_C32(0x6bf80000), SPH_C32(0xdfbb1c80), + SPH_C32(0x206829ca), SPH_C32(0x814256af), SPH_C32(0xfa95d0cf), + SPH_C32(0x0c505d58) }, + { SPH_C32(0x4ba90000), SPH_C32(0xac310000), SPH_C32(0x3b5f0000), + SPH_C32(0x9ff8c480), SPH_C32(0x64410c7b), SPH_C32(0xd0630c00), + SPH_C32(0x0f5d5670), SPH_C32(0xd3168692), SPH_C32(0x9cba0000), + SPH_C32(0x7a440000), SPH_C32(0xeceb0000), SPH_C32(0x60491ce0), + SPH_C32(0x0ed223d0), SPH_C32(0x0cf761fe), SPH_C32(0x89507bc9), + SPH_C32(0x57864861) }, + { SPH_C32(0xa4b10000), SPH_C32(0xd7ef0000), SPH_C32(0x3dc90000), + SPH_C32(0x4b9e9000), SPH_C32(0xf30107fb), SPH_C32(0xbde710e0), + SPH_C32(0x805696dc), SPH_C32(0x93b1da1b), SPH_C32(0x2a790000), + SPH_C32(0xaff60000), SPH_C32(0xda890000), SPH_C32(0xfcf56000), + SPH_C32(0x686d3607), SPH_C32(0xdadc8975), SPH_C32(0x9fc49d77), + SPH_C32(0x66db1921) }, + { SPH_C32(0x10800000), SPH_C32(0xa0dc0000), SPH_C32(0x8c940000), + SPH_C32(0x344e94e0), SPH_C32(0x8ba366c3), SPH_C32(0x6cf1d3bd), + SPH_C32(0x52004255), SPH_C32(0xdddeaec5), SPH_C32(0xc97f0000), + SPH_C32(0x12370000), SPH_C32(0x5d9a0000), SPH_C32(0x43076060), + SPH_C32(0x46d73c1d), SPH_C32(0x5769be24), SPH_C32(0xec013671), + SPH_C32(0x3d0d0c18) }, + { SPH_C32(0x47b70000), SPH_C32(0x6a2e0000), SPH_C32(0xbada0000), + SPH_C32(0xf46c9060), SPH_C32(0xddbb0de1), SPH_C32(0x305227b1), + SPH_C32(0xf3933dda), SPH_C32(0xc867cf22), SPH_C32(0x7d4e0000), + SPH_C32(0x65040000), SPH_C32(0xecc70000), SPH_C32(0x3cd76480), + SPH_C32(0x3e755d25), SPH_C32(0x867f7d79), SPH_C32(0x3e57e2f8), + SPH_C32(0x736278c6) }, + { SPH_C32(0xf3860000), SPH_C32(0x1d1d0000), SPH_C32(0x0b870000), + SPH_C32(0x8bbc9480), SPH_C32(0xa5196cd9), SPH_C32(0xe144e4ec), + SPH_C32(0x21c5e953), SPH_C32(0x8608bbfc), SPH_C32(0x9e480000), + SPH_C32(0xd8c50000), SPH_C32(0x6bd40000), SPH_C32(0x832564e0), + SPH_C32(0x10cf573f), SPH_C32(0x0bca4a28), SPH_C32(0x4d9249fe), + SPH_C32(0x28b46dff) }, + { SPH_C32(0xa6430000), SPH_C32(0x756e0000), SPH_C32(0xbaf60000), + SPH_C32(0xa8f2e800), SPH_C32(0xed1c7314), SPH_C32(0xbada3b36), + SPH_C32(0x4494a4eb), SPH_C32(0xec83ff85), SPH_C32(0x90a40000), + SPH_C32(0xbc5b0000), SPH_C32(0x6d6e0000), SPH_C32(0x0bdd4800), + SPH_C32(0xb728224a), SPH_C32(0xecc64a4f), SPH_C32(0x759e1063), + SPH_C32(0x4cf701d1) }, + { SPH_C32(0x12720000), SPH_C32(0x025d0000), SPH_C32(0x0bab0000), + SPH_C32(0xd722ece0), SPH_C32(0x95be122c), SPH_C32(0x6bccf86b), + SPH_C32(0x96c27062), SPH_C32(0xa2ec8b5b), SPH_C32(0x73a20000), + SPH_C32(0x019a0000), SPH_C32(0xea7d0000), SPH_C32(0xb42f4860), + SPH_C32(0x99922850), SPH_C32(0x61737d1e), SPH_C32(0x065bbb65), + SPH_C32(0x172114e8) }, + { SPH_C32(0x45450000), SPH_C32(0xc8af0000), SPH_C32(0x3de50000), + SPH_C32(0x1700e860), SPH_C32(0xc3a6790e), SPH_C32(0x376f0c67), + SPH_C32(0x37510fed), SPH_C32(0xb755eabc), SPH_C32(0xc7930000), + SPH_C32(0x76a90000), SPH_C32(0x5b200000), SPH_C32(0xcbff4c80), + SPH_C32(0xe1304968), SPH_C32(0xb065be43), SPH_C32(0xd40d6fec), + SPH_C32(0x594e6036) }, + { SPH_C32(0xf1740000), SPH_C32(0xbf9c0000), SPH_C32(0x8cb80000), + SPH_C32(0x68d0ec80), SPH_C32(0xbb041836), SPH_C32(0xe679cf3a), + SPH_C32(0xe507db64), SPH_C32(0xf93a9e62), SPH_C32(0x24950000), + SPH_C32(0xcb680000), SPH_C32(0xdc330000), SPH_C32(0x740d4ce0), + SPH_C32(0xcf8a4372), SPH_C32(0x3dd08912), SPH_C32(0xa7c8c4ea), + SPH_C32(0x0298750f) }, + { SPH_C32(0x92560000), SPH_C32(0x1eda0000), SPH_C32(0xea510000), + SPH_C32(0xe8b13000), SPH_C32(0xa93556a5), SPH_C32(0xebfb6199), + SPH_C32(0xb15c2254), SPH_C32(0x33c5244f), SPH_C32(0x8c3a0000), + SPH_C32(0xda980000), SPH_C32(0x607f0000), SPH_C32(0x54078800), + SPH_C32(0x85714513), SPH_C32(0x6006b243), SPH_C32(0xdb50399c), + SPH_C32(0x8a58e6a4) }, + { SPH_C32(0x26670000), SPH_C32(0x69e90000), SPH_C32(0x5b0c0000), + SPH_C32(0x976134e0), SPH_C32(0xd197379d), SPH_C32(0x3aeda2c4), + SPH_C32(0x630af6dd), SPH_C32(0x7daa5091), SPH_C32(0x6f3c0000), + SPH_C32(0x67590000), SPH_C32(0xe76c0000), SPH_C32(0xebf58860), + SPH_C32(0xabcb4f09), SPH_C32(0xedb38512), SPH_C32(0xa895929a), + SPH_C32(0xd18ef39d) }, + { SPH_C32(0x71500000), SPH_C32(0xa31b0000), SPH_C32(0x6d420000), + SPH_C32(0x57433060), SPH_C32(0x878f5cbf), SPH_C32(0x664e56c8), + SPH_C32(0xc2998952), SPH_C32(0x68133176), SPH_C32(0xdb0d0000), + SPH_C32(0x106a0000), SPH_C32(0x56310000), SPH_C32(0x94258c80), + SPH_C32(0xd3692e31), SPH_C32(0x3ca5464f), SPH_C32(0x7ac34613), + SPH_C32(0x9fe18743) }, + { SPH_C32(0xc5610000), SPH_C32(0xd4280000), SPH_C32(0xdc1f0000), + SPH_C32(0x28933480), SPH_C32(0xff2d3d87), SPH_C32(0xb7589595), + SPH_C32(0x10cf5ddb), SPH_C32(0x267c45a8), SPH_C32(0x380b0000), + SPH_C32(0xadab0000), SPH_C32(0xd1220000), SPH_C32(0x2bd78ce0), + SPH_C32(0xfdd3242b), SPH_C32(0xb110711e), SPH_C32(0x0906ed15), + SPH_C32(0xc437927a) }, + { SPH_C32(0x90a40000), SPH_C32(0xbc5b0000), SPH_C32(0x6d6e0000), + SPH_C32(0x0bdd4800), SPH_C32(0xb728224a), SPH_C32(0xecc64a4f), + SPH_C32(0x759e1063), SPH_C32(0x4cf701d1), SPH_C32(0x36e70000), + SPH_C32(0xc9350000), SPH_C32(0xd7980000), SPH_C32(0xa32fa000), + SPH_C32(0x5a34515e), SPH_C32(0x561c7179), SPH_C32(0x310ab488), + SPH_C32(0xa074fe54) }, + { SPH_C32(0x24950000), SPH_C32(0xcb680000), SPH_C32(0xdc330000), + SPH_C32(0x740d4ce0), SPH_C32(0xcf8a4372), SPH_C32(0x3dd08912), + SPH_C32(0xa7c8c4ea), SPH_C32(0x0298750f), SPH_C32(0xd5e10000), + SPH_C32(0x74f40000), SPH_C32(0x508b0000), SPH_C32(0x1cdda060), + SPH_C32(0x748e5b44), SPH_C32(0xdba94628), SPH_C32(0x42cf1f8e), + SPH_C32(0xfba2eb6d) }, + { SPH_C32(0x73a20000), SPH_C32(0x019a0000), SPH_C32(0xea7d0000), + SPH_C32(0xb42f4860), SPH_C32(0x99922850), SPH_C32(0x61737d1e), + SPH_C32(0x065bbb65), SPH_C32(0x172114e8), SPH_C32(0x61d00000), + SPH_C32(0x03c70000), SPH_C32(0xe1d60000), SPH_C32(0x630da480), + SPH_C32(0x0c2c3a7c), SPH_C32(0x0abf8575), SPH_C32(0x9099cb07), + SPH_C32(0xb5cd9fb3) }, + { SPH_C32(0xc7930000), SPH_C32(0x76a90000), SPH_C32(0x5b200000), + SPH_C32(0xcbff4c80), SPH_C32(0xe1304968), SPH_C32(0xb065be43), + SPH_C32(0xd40d6fec), SPH_C32(0x594e6036), SPH_C32(0x82d60000), + SPH_C32(0xbe060000), SPH_C32(0x66c50000), SPH_C32(0xdcffa4e0), + SPH_C32(0x22963066), SPH_C32(0x870ab224), SPH_C32(0xe35c6001), + SPH_C32(0xee1b8a8a) }, + { SPH_C32(0x288b0000), SPH_C32(0x0d770000), SPH_C32(0x5db60000), + SPH_C32(0x1f991800), SPH_C32(0x767042e8), SPH_C32(0xdde1a2a3), + SPH_C32(0x5b06af40), SPH_C32(0x19e93cbf), SPH_C32(0x34150000), + SPH_C32(0x6bb40000), SPH_C32(0x50a70000), SPH_C32(0x4043d800), + SPH_C32(0x442925b1), SPH_C32(0x51215aaf), SPH_C32(0xf5c886bf), + SPH_C32(0xdf46dbca) }, + { SPH_C32(0x9cba0000), SPH_C32(0x7a440000), SPH_C32(0xeceb0000), + SPH_C32(0x60491ce0), SPH_C32(0x0ed223d0), SPH_C32(0x0cf761fe), + SPH_C32(0x89507bc9), SPH_C32(0x57864861), SPH_C32(0xd7130000), + SPH_C32(0xd6750000), SPH_C32(0xd7b40000), SPH_C32(0xffb1d860), + SPH_C32(0x6a932fab), SPH_C32(0xdc946dfe), SPH_C32(0x860d2db9), + SPH_C32(0x8490cef3) }, + { SPH_C32(0xcb8d0000), SPH_C32(0xb0b60000), SPH_C32(0xdaa50000), + SPH_C32(0xa06b1860), SPH_C32(0x58ca48f2), SPH_C32(0x505495f2), + SPH_C32(0x28c30446), SPH_C32(0x423f2986), SPH_C32(0x63220000), + SPH_C32(0xa1460000), SPH_C32(0x66e90000), SPH_C32(0x8061dc80), + SPH_C32(0x12314e93), SPH_C32(0x0d82aea3), SPH_C32(0x545bf930), + SPH_C32(0xcaffba2d) }, + { SPH_C32(0x7fbc0000), SPH_C32(0xc7850000), SPH_C32(0x6bf80000), + SPH_C32(0xdfbb1c80), SPH_C32(0x206829ca), SPH_C32(0x814256af), + SPH_C32(0xfa95d0cf), SPH_C32(0x0c505d58), SPH_C32(0x80240000), + SPH_C32(0x1c870000), SPH_C32(0xe1fa0000), SPH_C32(0x3f93dce0), + SPH_C32(0x3c8b4489), SPH_C32(0x803799f2), SPH_C32(0x279e5236), + SPH_C32(0x9129af14) }, + { SPH_C32(0x2a790000), SPH_C32(0xaff60000), SPH_C32(0xda890000), + SPH_C32(0xfcf56000), SPH_C32(0x686d3607), SPH_C32(0xdadc8975), + SPH_C32(0x9fc49d77), SPH_C32(0x66db1921), SPH_C32(0x8ec80000), + SPH_C32(0x78190000), SPH_C32(0xe7400000), SPH_C32(0xb76bf000), + SPH_C32(0x9b6c31fc), SPH_C32(0x673b9995), SPH_C32(0x1f920bab), + SPH_C32(0xf56ac33a) }, + { SPH_C32(0x9e480000), SPH_C32(0xd8c50000), SPH_C32(0x6bd40000), + SPH_C32(0x832564e0), SPH_C32(0x10cf573f), SPH_C32(0x0bca4a28), + SPH_C32(0x4d9249fe), SPH_C32(0x28b46dff), SPH_C32(0x6dce0000), + SPH_C32(0xc5d80000), SPH_C32(0x60530000), SPH_C32(0x0899f060), + SPH_C32(0xb5d63be6), SPH_C32(0xea8eaec4), SPH_C32(0x6c57a0ad), + SPH_C32(0xaebcd603) }, + { SPH_C32(0xc97f0000), SPH_C32(0x12370000), SPH_C32(0x5d9a0000), + SPH_C32(0x43076060), SPH_C32(0x46d73c1d), SPH_C32(0x5769be24), + SPH_C32(0xec013671), SPH_C32(0x3d0d0c18), SPH_C32(0xd9ff0000), + SPH_C32(0xb2eb0000), SPH_C32(0xd10e0000), SPH_C32(0x7749f480), + SPH_C32(0xcd745ade), SPH_C32(0x3b986d99), SPH_C32(0xbe017424), + SPH_C32(0xe0d3a2dd) }, + { SPH_C32(0x7d4e0000), SPH_C32(0x65040000), SPH_C32(0xecc70000), + SPH_C32(0x3cd76480), SPH_C32(0x3e755d25), SPH_C32(0x867f7d79), + SPH_C32(0x3e57e2f8), SPH_C32(0x736278c6), SPH_C32(0x3af90000), + SPH_C32(0x0f2a0000), SPH_C32(0x561d0000), SPH_C32(0xc8bbf4e0), + SPH_C32(0xe3ce50c4), SPH_C32(0xb62d5ac8), SPH_C32(0xcdc4df22), + SPH_C32(0xbb05b7e4) }, + { SPH_C32(0x8c3a0000), SPH_C32(0xda980000), SPH_C32(0x607f0000), + SPH_C32(0x54078800), SPH_C32(0x85714513), SPH_C32(0x6006b243), + SPH_C32(0xdb50399c), SPH_C32(0x8a58e6a4), SPH_C32(0x1e6c0000), + SPH_C32(0xc4420000), SPH_C32(0x8a2e0000), SPH_C32(0xbcb6b800), + SPH_C32(0x2c4413b6), SPH_C32(0x8bfdd3da), SPH_C32(0x6a0c1bc8), + SPH_C32(0xb99dc2eb) }, + { SPH_C32(0x380b0000), SPH_C32(0xadab0000), SPH_C32(0xd1220000), + SPH_C32(0x2bd78ce0), SPH_C32(0xfdd3242b), SPH_C32(0xb110711e), + SPH_C32(0x0906ed15), SPH_C32(0xc437927a), SPH_C32(0xfd6a0000), + SPH_C32(0x79830000), SPH_C32(0x0d3d0000), SPH_C32(0x0344b860), + SPH_C32(0x02fe19ac), SPH_C32(0x0648e48b), SPH_C32(0x19c9b0ce), + SPH_C32(0xe24bd7d2) }, + { SPH_C32(0x6f3c0000), SPH_C32(0x67590000), SPH_C32(0xe76c0000), + SPH_C32(0xebf58860), SPH_C32(0xabcb4f09), SPH_C32(0xedb38512), + SPH_C32(0xa895929a), SPH_C32(0xd18ef39d), SPH_C32(0x495b0000), + SPH_C32(0x0eb00000), SPH_C32(0xbc600000), SPH_C32(0x7c94bc80), + SPH_C32(0x7a5c7894), SPH_C32(0xd75e27d6), SPH_C32(0xcb9f6447), + SPH_C32(0xac24a30c) }, + { SPH_C32(0xdb0d0000), SPH_C32(0x106a0000), SPH_C32(0x56310000), + SPH_C32(0x94258c80), SPH_C32(0xd3692e31), SPH_C32(0x3ca5464f), + SPH_C32(0x7ac34613), SPH_C32(0x9fe18743), SPH_C32(0xaa5d0000), + SPH_C32(0xb3710000), SPH_C32(0x3b730000), SPH_C32(0xc366bce0), + SPH_C32(0x54e6728e), SPH_C32(0x5aeb1087), SPH_C32(0xb85acf41), + SPH_C32(0xf7f2b635) }, + { SPH_C32(0x8ec80000), SPH_C32(0x78190000), SPH_C32(0xe7400000), + SPH_C32(0xb76bf000), SPH_C32(0x9b6c31fc), SPH_C32(0x673b9995), + SPH_C32(0x1f920bab), SPH_C32(0xf56ac33a), SPH_C32(0xa4b10000), + SPH_C32(0xd7ef0000), SPH_C32(0x3dc90000), SPH_C32(0x4b9e9000), + SPH_C32(0xf30107fb), SPH_C32(0xbde710e0), SPH_C32(0x805696dc), + SPH_C32(0x93b1da1b) }, + { SPH_C32(0x3af90000), SPH_C32(0x0f2a0000), SPH_C32(0x561d0000), + SPH_C32(0xc8bbf4e0), SPH_C32(0xe3ce50c4), SPH_C32(0xb62d5ac8), + SPH_C32(0xcdc4df22), SPH_C32(0xbb05b7e4), SPH_C32(0x47b70000), + SPH_C32(0x6a2e0000), SPH_C32(0xbada0000), SPH_C32(0xf46c9060), + SPH_C32(0xddbb0de1), SPH_C32(0x305227b1), SPH_C32(0xf3933dda), + SPH_C32(0xc867cf22) }, + { SPH_C32(0x6dce0000), SPH_C32(0xc5d80000), SPH_C32(0x60530000), + SPH_C32(0x0899f060), SPH_C32(0xb5d63be6), SPH_C32(0xea8eaec4), + SPH_C32(0x6c57a0ad), SPH_C32(0xaebcd603), SPH_C32(0xf3860000), + SPH_C32(0x1d1d0000), SPH_C32(0x0b870000), SPH_C32(0x8bbc9480), + SPH_C32(0xa5196cd9), SPH_C32(0xe144e4ec), SPH_C32(0x21c5e953), + SPH_C32(0x8608bbfc) }, + { SPH_C32(0xd9ff0000), SPH_C32(0xb2eb0000), SPH_C32(0xd10e0000), + SPH_C32(0x7749f480), SPH_C32(0xcd745ade), SPH_C32(0x3b986d99), + SPH_C32(0xbe017424), SPH_C32(0xe0d3a2dd), SPH_C32(0x10800000), + SPH_C32(0xa0dc0000), SPH_C32(0x8c940000), SPH_C32(0x344e94e0), + SPH_C32(0x8ba366c3), SPH_C32(0x6cf1d3bd), SPH_C32(0x52004255), + SPH_C32(0xdddeaec5) }, + { SPH_C32(0x36e70000), SPH_C32(0xc9350000), SPH_C32(0xd7980000), + SPH_C32(0xa32fa000), SPH_C32(0x5a34515e), SPH_C32(0x561c7179), + SPH_C32(0x310ab488), SPH_C32(0xa074fe54), SPH_C32(0xa6430000), + SPH_C32(0x756e0000), SPH_C32(0xbaf60000), SPH_C32(0xa8f2e800), + SPH_C32(0xed1c7314), SPH_C32(0xbada3b36), SPH_C32(0x4494a4eb), + SPH_C32(0xec83ff85) }, + { SPH_C32(0x82d60000), SPH_C32(0xbe060000), SPH_C32(0x66c50000), + SPH_C32(0xdcffa4e0), SPH_C32(0x22963066), SPH_C32(0x870ab224), + SPH_C32(0xe35c6001), SPH_C32(0xee1b8a8a), SPH_C32(0x45450000), + SPH_C32(0xc8af0000), SPH_C32(0x3de50000), SPH_C32(0x1700e860), + SPH_C32(0xc3a6790e), SPH_C32(0x376f0c67), SPH_C32(0x37510fed), + SPH_C32(0xb755eabc) }, + { SPH_C32(0xd5e10000), SPH_C32(0x74f40000), SPH_C32(0x508b0000), + SPH_C32(0x1cdda060), SPH_C32(0x748e5b44), SPH_C32(0xdba94628), + SPH_C32(0x42cf1f8e), SPH_C32(0xfba2eb6d), SPH_C32(0xf1740000), + SPH_C32(0xbf9c0000), SPH_C32(0x8cb80000), SPH_C32(0x68d0ec80), + SPH_C32(0xbb041836), SPH_C32(0xe679cf3a), SPH_C32(0xe507db64), + SPH_C32(0xf93a9e62) }, + { SPH_C32(0x61d00000), SPH_C32(0x03c70000), SPH_C32(0xe1d60000), + SPH_C32(0x630da480), SPH_C32(0x0c2c3a7c), SPH_C32(0x0abf8575), + SPH_C32(0x9099cb07), SPH_C32(0xb5cd9fb3), SPH_C32(0x12720000), + SPH_C32(0x025d0000), SPH_C32(0x0bab0000), SPH_C32(0xd722ece0), + SPH_C32(0x95be122c), SPH_C32(0x6bccf86b), SPH_C32(0x96c27062), + SPH_C32(0xa2ec8b5b) }, + { SPH_C32(0x34150000), SPH_C32(0x6bb40000), SPH_C32(0x50a70000), + SPH_C32(0x4043d800), SPH_C32(0x442925b1), SPH_C32(0x51215aaf), + SPH_C32(0xf5c886bf), SPH_C32(0xdf46dbca), SPH_C32(0x1c9e0000), + SPH_C32(0x66c30000), SPH_C32(0x0d110000), SPH_C32(0x5fdac000), + SPH_C32(0x32596759), SPH_C32(0x8cc0f80c), SPH_C32(0xaece29ff), + SPH_C32(0xc6afe775) }, + { SPH_C32(0x80240000), SPH_C32(0x1c870000), SPH_C32(0xe1fa0000), + SPH_C32(0x3f93dce0), SPH_C32(0x3c8b4489), SPH_C32(0x803799f2), + SPH_C32(0x279e5236), SPH_C32(0x9129af14), SPH_C32(0xff980000), + SPH_C32(0xdb020000), SPH_C32(0x8a020000), SPH_C32(0xe028c060), + SPH_C32(0x1ce36d43), SPH_C32(0x0175cf5d), SPH_C32(0xdd0b82f9), + SPH_C32(0x9d79f24c) }, + { SPH_C32(0xd7130000), SPH_C32(0xd6750000), SPH_C32(0xd7b40000), + SPH_C32(0xffb1d860), SPH_C32(0x6a932fab), SPH_C32(0xdc946dfe), + SPH_C32(0x860d2db9), SPH_C32(0x8490cef3), SPH_C32(0x4ba90000), + SPH_C32(0xac310000), SPH_C32(0x3b5f0000), SPH_C32(0x9ff8c480), + SPH_C32(0x64410c7b), SPH_C32(0xd0630c00), SPH_C32(0x0f5d5670), + SPH_C32(0xd3168692) }, + { SPH_C32(0x63220000), SPH_C32(0xa1460000), SPH_C32(0x66e90000), + SPH_C32(0x8061dc80), SPH_C32(0x12314e93), SPH_C32(0x0d82aea3), + SPH_C32(0x545bf930), SPH_C32(0xcaffba2d), SPH_C32(0xa8af0000), + SPH_C32(0x11f00000), SPH_C32(0xbc4c0000), SPH_C32(0x200ac4e0), + SPH_C32(0x4afb0661), SPH_C32(0x5dd63b51), SPH_C32(0x7c98fd76), + SPH_C32(0x88c093ab) } +}; + +static const sph_u32 T512_54[64][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0x5fa80000), SPH_C32(0x56030000), SPH_C32(0x43ae0000), + SPH_C32(0x64f30013), SPH_C32(0x257e86bf), SPH_C32(0x1311944e), + SPH_C32(0x541e95bf), SPH_C32(0x8ea4db69), SPH_C32(0x00440000), + SPH_C32(0x7f480000), SPH_C32(0xda7c0000), SPH_C32(0x2a230001), + SPH_C32(0x3badc9cc), SPH_C32(0xa9b69c87), SPH_C32(0x030a9e60), + SPH_C32(0xbe0a679e) }, + { SPH_C32(0x00440000), SPH_C32(0x7f480000), SPH_C32(0xda7c0000), + SPH_C32(0x2a230001), SPH_C32(0x3badc9cc), SPH_C32(0xa9b69c87), + SPH_C32(0x030a9e60), SPH_C32(0xbe0a679e), SPH_C32(0x5fec0000), + SPH_C32(0x294b0000), SPH_C32(0x99d20000), SPH_C32(0x4ed00012), + SPH_C32(0x1ed34f73), SPH_C32(0xbaa708c9), SPH_C32(0x57140bdf), + SPH_C32(0x30aebcf7) }, + { SPH_C32(0x5fec0000), SPH_C32(0x294b0000), SPH_C32(0x99d20000), + SPH_C32(0x4ed00012), SPH_C32(0x1ed34f73), SPH_C32(0xbaa708c9), + SPH_C32(0x57140bdf), SPH_C32(0x30aebcf7), SPH_C32(0x5fa80000), + SPH_C32(0x56030000), SPH_C32(0x43ae0000), SPH_C32(0x64f30013), + SPH_C32(0x257e86bf), SPH_C32(0x1311944e), SPH_C32(0x541e95bf), + SPH_C32(0x8ea4db69) }, + { SPH_C32(0xee930000), SPH_C32(0xd6070000), SPH_C32(0x92c10000), + SPH_C32(0x2b9801e0), SPH_C32(0x9451287c), SPH_C32(0x3b6cfb57), + SPH_C32(0x45312374), SPH_C32(0x201f6a64), SPH_C32(0x7b280000), + SPH_C32(0x57420000), SPH_C32(0xa9e50000), SPH_C32(0x634300a0), + SPH_C32(0x9edb442f), SPH_C32(0x6d9995bb), SPH_C32(0x27f83b03), + SPH_C32(0xc7ff60f0) }, + { SPH_C32(0xb13b0000), SPH_C32(0x80040000), SPH_C32(0xd16f0000), + SPH_C32(0x4f6b01f3), SPH_C32(0xb12faec3), SPH_C32(0x287d6f19), + SPH_C32(0x112fb6cb), SPH_C32(0xaebbb10d), SPH_C32(0x7b6c0000), + SPH_C32(0x280a0000), SPH_C32(0x73990000), SPH_C32(0x496000a1), + SPH_C32(0xa5768de3), SPH_C32(0xc42f093c), SPH_C32(0x24f2a563), + SPH_C32(0x79f5076e) }, + { SPH_C32(0xeed70000), SPH_C32(0xa94f0000), SPH_C32(0x48bd0000), + SPH_C32(0x01bb01e1), SPH_C32(0xaffce1b0), SPH_C32(0x92da67d0), + SPH_C32(0x463bbd14), SPH_C32(0x9e150dfa), SPH_C32(0x24c40000), + SPH_C32(0x7e090000), SPH_C32(0x30370000), SPH_C32(0x2d9300b2), + SPH_C32(0x80080b5c), SPH_C32(0xd73e9d72), SPH_C32(0x70ec30dc), + SPH_C32(0xf751dc07) }, + { SPH_C32(0xb17f0000), SPH_C32(0xff4c0000), SPH_C32(0x0b130000), + SPH_C32(0x654801f2), SPH_C32(0x8a82670f), SPH_C32(0x81cbf39e), + SPH_C32(0x122528ab), SPH_C32(0x10b1d693), SPH_C32(0x24800000), + SPH_C32(0x01410000), SPH_C32(0xea4b0000), SPH_C32(0x07b000b3), + SPH_C32(0xbba5c290), SPH_C32(0x7e8801f5), SPH_C32(0x73e6aebc), + SPH_C32(0x495bbb99) }, + { SPH_C32(0x7b280000), SPH_C32(0x57420000), SPH_C32(0xa9e50000), + SPH_C32(0x634300a0), SPH_C32(0x9edb442f), SPH_C32(0x6d9995bb), + SPH_C32(0x27f83b03), SPH_C32(0xc7ff60f0), SPH_C32(0x95bb0000), + SPH_C32(0x81450000), SPH_C32(0x3b240000), SPH_C32(0x48db0140), + SPH_C32(0x0a8a6c53), SPH_C32(0x56f56eec), SPH_C32(0x62c91877), + SPH_C32(0xe7e00a94) }, + { SPH_C32(0x24800000), SPH_C32(0x01410000), SPH_C32(0xea4b0000), + SPH_C32(0x07b000b3), SPH_C32(0xbba5c290), SPH_C32(0x7e8801f5), + SPH_C32(0x73e6aebc), SPH_C32(0x495bbb99), SPH_C32(0x95ff0000), + SPH_C32(0xfe0d0000), SPH_C32(0xe1580000), SPH_C32(0x62f80141), + SPH_C32(0x3127a59f), SPH_C32(0xff43f26b), SPH_C32(0x61c38617), + SPH_C32(0x59ea6d0a) }, + { SPH_C32(0x7b6c0000), SPH_C32(0x280a0000), SPH_C32(0x73990000), + SPH_C32(0x496000a1), SPH_C32(0xa5768de3), SPH_C32(0xc42f093c), + SPH_C32(0x24f2a563), SPH_C32(0x79f5076e), SPH_C32(0xca570000), + SPH_C32(0xa80e0000), SPH_C32(0xa2f60000), SPH_C32(0x060b0152), + SPH_C32(0x14592320), SPH_C32(0xec526625), SPH_C32(0x35dd13a8), + SPH_C32(0xd74eb663) }, + { SPH_C32(0x24c40000), SPH_C32(0x7e090000), SPH_C32(0x30370000), + SPH_C32(0x2d9300b2), SPH_C32(0x80080b5c), SPH_C32(0xd73e9d72), + SPH_C32(0x70ec30dc), SPH_C32(0xf751dc07), SPH_C32(0xca130000), + SPH_C32(0xd7460000), SPH_C32(0x788a0000), SPH_C32(0x2c280153), + SPH_C32(0x2ff4eaec), SPH_C32(0x45e4faa2), SPH_C32(0x36d78dc8), + SPH_C32(0x6944d1fd) }, + { SPH_C32(0x95bb0000), SPH_C32(0x81450000), SPH_C32(0x3b240000), + SPH_C32(0x48db0140), SPH_C32(0x0a8a6c53), SPH_C32(0x56f56eec), + SPH_C32(0x62c91877), SPH_C32(0xe7e00a94), SPH_C32(0xee930000), + SPH_C32(0xd6070000), SPH_C32(0x92c10000), SPH_C32(0x2b9801e0), + SPH_C32(0x9451287c), SPH_C32(0x3b6cfb57), SPH_C32(0x45312374), + SPH_C32(0x201f6a64) }, + { SPH_C32(0xca130000), SPH_C32(0xd7460000), SPH_C32(0x788a0000), + SPH_C32(0x2c280153), SPH_C32(0x2ff4eaec), SPH_C32(0x45e4faa2), + SPH_C32(0x36d78dc8), SPH_C32(0x6944d1fd), SPH_C32(0xeed70000), + SPH_C32(0xa94f0000), SPH_C32(0x48bd0000), SPH_C32(0x01bb01e1), + SPH_C32(0xaffce1b0), SPH_C32(0x92da67d0), SPH_C32(0x463bbd14), + SPH_C32(0x9e150dfa) }, + { SPH_C32(0x95ff0000), SPH_C32(0xfe0d0000), SPH_C32(0xe1580000), + SPH_C32(0x62f80141), SPH_C32(0x3127a59f), SPH_C32(0xff43f26b), + SPH_C32(0x61c38617), SPH_C32(0x59ea6d0a), SPH_C32(0xb17f0000), + SPH_C32(0xff4c0000), SPH_C32(0x0b130000), SPH_C32(0x654801f2), + SPH_C32(0x8a82670f), SPH_C32(0x81cbf39e), SPH_C32(0x122528ab), + SPH_C32(0x10b1d693) }, + { SPH_C32(0xca570000), SPH_C32(0xa80e0000), SPH_C32(0xa2f60000), + SPH_C32(0x060b0152), SPH_C32(0x14592320), SPH_C32(0xec526625), + SPH_C32(0x35dd13a8), SPH_C32(0xd74eb663), SPH_C32(0xb13b0000), + SPH_C32(0x80040000), SPH_C32(0xd16f0000), SPH_C32(0x4f6b01f3), + SPH_C32(0xb12faec3), SPH_C32(0x287d6f19), SPH_C32(0x112fb6cb), + SPH_C32(0xaebbb10d) }, + { SPH_C32(0xe6280000), SPH_C32(0x4c4b0000), SPH_C32(0xa8550000), + SPH_C32(0xd3d002e0), SPH_C32(0xd86130b8), SPH_C32(0x98a7b0da), + SPH_C32(0x289506b4), SPH_C32(0xd75a4897), SPH_C32(0xf0c50000), + SPH_C32(0x59230000), SPH_C32(0x45820000), SPH_C32(0xe18d00c0), + SPH_C32(0x3b6d0631), SPH_C32(0xc2ed5699), SPH_C32(0xcbe0fe1c), + SPH_C32(0x56a7b19f) }, + { SPH_C32(0xb9800000), SPH_C32(0x1a480000), SPH_C32(0xebfb0000), + SPH_C32(0xb72302f3), SPH_C32(0xfd1fb607), SPH_C32(0x8bb62494), + SPH_C32(0x7c8b930b), SPH_C32(0x59fe93fe), SPH_C32(0xf0810000), + SPH_C32(0x266b0000), SPH_C32(0x9ffe0000), SPH_C32(0xcbae00c1), + SPH_C32(0x00c0cffd), SPH_C32(0x6b5bca1e), SPH_C32(0xc8ea607c), + SPH_C32(0xe8add601) }, + { SPH_C32(0xe66c0000), SPH_C32(0x33030000), SPH_C32(0x72290000), + SPH_C32(0xf9f302e1), SPH_C32(0xe3ccf974), SPH_C32(0x31112c5d), + SPH_C32(0x2b9f98d4), SPH_C32(0x69502f09), SPH_C32(0xaf290000), + SPH_C32(0x70680000), SPH_C32(0xdc500000), SPH_C32(0xaf5d00d2), + SPH_C32(0x25be4942), SPH_C32(0x784a5e50), SPH_C32(0x9cf4f5c3), + SPH_C32(0x66090d68) }, + { SPH_C32(0xb9c40000), SPH_C32(0x65000000), SPH_C32(0x31870000), + SPH_C32(0x9d0002f2), SPH_C32(0xc6b27fcb), SPH_C32(0x2200b813), + SPH_C32(0x7f810d6b), SPH_C32(0xe7f4f460), SPH_C32(0xaf6d0000), + SPH_C32(0x0f200000), SPH_C32(0x062c0000), SPH_C32(0x857e00d3), + SPH_C32(0x1e13808e), SPH_C32(0xd1fcc2d7), SPH_C32(0x9ffe6ba3), + SPH_C32(0xd8036af6) }, + { SPH_C32(0x08bb0000), SPH_C32(0x9a4c0000), SPH_C32(0x3a940000), + SPH_C32(0xf8480300), SPH_C32(0x4c3018c4), SPH_C32(0xa3cb4b8d), + SPH_C32(0x6da425c0), SPH_C32(0xf74522f3), SPH_C32(0x8bed0000), + SPH_C32(0x0e610000), SPH_C32(0xec670000), SPH_C32(0x82ce0060), + SPH_C32(0xa5b6421e), SPH_C32(0xaf74c322), SPH_C32(0xec18c51f), + SPH_C32(0x9158d16f) }, + { SPH_C32(0x57130000), SPH_C32(0xcc4f0000), SPH_C32(0x793a0000), + SPH_C32(0x9cbb0313), SPH_C32(0x694e9e7b), SPH_C32(0xb0dadfc3), + SPH_C32(0x39bab07f), SPH_C32(0x79e1f99a), SPH_C32(0x8ba90000), + SPH_C32(0x71290000), SPH_C32(0x361b0000), SPH_C32(0xa8ed0061), + SPH_C32(0x9e1b8bd2), SPH_C32(0x06c25fa5), SPH_C32(0xef125b7f), + SPH_C32(0x2f52b6f1) }, + { SPH_C32(0x08ff0000), SPH_C32(0xe5040000), SPH_C32(0xe0e80000), + SPH_C32(0xd26b0301), SPH_C32(0x779dd108), SPH_C32(0x0a7dd70a), + SPH_C32(0x6eaebba0), SPH_C32(0x494f456d), SPH_C32(0xd4010000), + SPH_C32(0x272a0000), SPH_C32(0x75b50000), SPH_C32(0xcc1e0072), + SPH_C32(0xbb650d6d), SPH_C32(0x15d3cbeb), SPH_C32(0xbb0ccec0), + SPH_C32(0xa1f66d98) }, + { SPH_C32(0x57570000), SPH_C32(0xb3070000), SPH_C32(0xa3460000), + SPH_C32(0xb6980312), SPH_C32(0x52e357b7), SPH_C32(0x196c4344), + SPH_C32(0x3ab02e1f), SPH_C32(0xc7eb9e04), SPH_C32(0xd4450000), + SPH_C32(0x58620000), SPH_C32(0xafc90000), SPH_C32(0xe63d0073), + SPH_C32(0x80c8c4a1), SPH_C32(0xbc65576c), SPH_C32(0xb80650a0), + SPH_C32(0x1ffc0a06) }, + { SPH_C32(0x9d000000), SPH_C32(0x1b090000), SPH_C32(0x01b00000), + SPH_C32(0xb0930240), SPH_C32(0x46ba7497), SPH_C32(0xf53e2561), + SPH_C32(0x0f6d3db7), SPH_C32(0x10a52867), SPH_C32(0x657e0000), + SPH_C32(0xd8660000), SPH_C32(0x7ea60000), SPH_C32(0xa9560180), + SPH_C32(0x31e76a62), SPH_C32(0x94183875), SPH_C32(0xa929e66b), + SPH_C32(0xb147bb0b) }, + { SPH_C32(0xc2a80000), SPH_C32(0x4d0a0000), SPH_C32(0x421e0000), + SPH_C32(0xd4600253), SPH_C32(0x63c4f228), SPH_C32(0xe62fb12f), + SPH_C32(0x5b73a808), SPH_C32(0x9e01f30e), SPH_C32(0x653a0000), + SPH_C32(0xa72e0000), SPH_C32(0xa4da0000), SPH_C32(0x83750181), + SPH_C32(0x0a4aa3ae), SPH_C32(0x3daea4f2), SPH_C32(0xaa23780b), + SPH_C32(0x0f4ddc95) }, + { SPH_C32(0x9d440000), SPH_C32(0x64410000), SPH_C32(0xdbcc0000), + SPH_C32(0x9ab00241), SPH_C32(0x7d17bd5b), SPH_C32(0x5c88b9e6), + SPH_C32(0x0c67a3d7), SPH_C32(0xaeaf4ff9), SPH_C32(0x3a920000), + SPH_C32(0xf12d0000), SPH_C32(0xe7740000), SPH_C32(0xe7860192), + SPH_C32(0x2f342511), SPH_C32(0x2ebf30bc), SPH_C32(0xfe3dedb4), + SPH_C32(0x81e907fc) }, + { SPH_C32(0xc2ec0000), SPH_C32(0x32420000), SPH_C32(0x98620000), + SPH_C32(0xfe430252), SPH_C32(0x58693be4), SPH_C32(0x4f992da8), + SPH_C32(0x58793668), SPH_C32(0x200b9490), SPH_C32(0x3ad60000), + SPH_C32(0x8e650000), SPH_C32(0x3d080000), SPH_C32(0xcda50193), + SPH_C32(0x1499ecdd), SPH_C32(0x8709ac3b), SPH_C32(0xfd3773d4), + SPH_C32(0x3fe36062) }, + { SPH_C32(0x73930000), SPH_C32(0xcd0e0000), SPH_C32(0x93710000), + SPH_C32(0x9b0b03a0), SPH_C32(0xd2eb5ceb), SPH_C32(0xce52de36), + SPH_C32(0x4a5c1ec3), SPH_C32(0x30ba4203), SPH_C32(0x1e560000), + SPH_C32(0x8f240000), SPH_C32(0xd7430000), SPH_C32(0xca150120), + SPH_C32(0xaf3c2e4d), SPH_C32(0xf981adce), SPH_C32(0x8ed1dd68), + SPH_C32(0x76b8dbfb) }, + { SPH_C32(0x2c3b0000), SPH_C32(0x9b0d0000), SPH_C32(0xd0df0000), + SPH_C32(0xfff803b3), SPH_C32(0xf795da54), SPH_C32(0xdd434a78), + SPH_C32(0x1e428b7c), SPH_C32(0xbe1e996a), SPH_C32(0x1e120000), + SPH_C32(0xf06c0000), SPH_C32(0x0d3f0000), SPH_C32(0xe0360121), + SPH_C32(0x9491e781), SPH_C32(0x50373149), SPH_C32(0x8ddb4308), + SPH_C32(0xc8b2bc65) }, + { SPH_C32(0x73d70000), SPH_C32(0xb2460000), SPH_C32(0x490d0000), + SPH_C32(0xb12803a1), SPH_C32(0xe9469527), SPH_C32(0x67e442b1), + SPH_C32(0x495680a3), SPH_C32(0x8eb0259d), SPH_C32(0x41ba0000), + SPH_C32(0xa66f0000), SPH_C32(0x4e910000), SPH_C32(0x84c50132), + SPH_C32(0xb1ef613e), SPH_C32(0x4326a507), SPH_C32(0xd9c5d6b7), + SPH_C32(0x4616670c) }, + { SPH_C32(0x2c7f0000), SPH_C32(0xe4450000), SPH_C32(0x0aa30000), + SPH_C32(0xd5db03b2), SPH_C32(0xcc381398), SPH_C32(0x74f5d6ff), + SPH_C32(0x1d48151c), SPH_C32(0x0014fef4), SPH_C32(0x41fe0000), + SPH_C32(0xd9270000), SPH_C32(0x94ed0000), SPH_C32(0xaee60133), + SPH_C32(0x8a42a8f2), SPH_C32(0xea903980), SPH_C32(0xdacf48d7), + SPH_C32(0xf81c0092) }, + { SPH_C32(0xf0c50000), SPH_C32(0x59230000), SPH_C32(0x45820000), + SPH_C32(0xe18d00c0), SPH_C32(0x3b6d0631), SPH_C32(0xc2ed5699), + SPH_C32(0xcbe0fe1c), SPH_C32(0x56a7b19f), SPH_C32(0x16ed0000), + SPH_C32(0x15680000), SPH_C32(0xedd70000), SPH_C32(0x325d0220), + SPH_C32(0xe30c3689), SPH_C32(0x5a4ae643), SPH_C32(0xe375f8a8), + SPH_C32(0x81fdf908) }, + { SPH_C32(0xaf6d0000), SPH_C32(0x0f200000), SPH_C32(0x062c0000), + SPH_C32(0x857e00d3), SPH_C32(0x1e13808e), SPH_C32(0xd1fcc2d7), + SPH_C32(0x9ffe6ba3), SPH_C32(0xd8036af6), SPH_C32(0x16a90000), + SPH_C32(0x6a200000), SPH_C32(0x37ab0000), SPH_C32(0x187e0221), + SPH_C32(0xd8a1ff45), SPH_C32(0xf3fc7ac4), SPH_C32(0xe07f66c8), + SPH_C32(0x3ff79e96) }, + { SPH_C32(0xf0810000), SPH_C32(0x266b0000), SPH_C32(0x9ffe0000), + SPH_C32(0xcbae00c1), SPH_C32(0x00c0cffd), SPH_C32(0x6b5bca1e), + SPH_C32(0xc8ea607c), SPH_C32(0xe8add601), SPH_C32(0x49010000), + SPH_C32(0x3c230000), SPH_C32(0x74050000), SPH_C32(0x7c8d0232), + SPH_C32(0xfddf79fa), SPH_C32(0xe0edee8a), SPH_C32(0xb461f377), + SPH_C32(0xb15345ff) }, + { SPH_C32(0xaf290000), SPH_C32(0x70680000), SPH_C32(0xdc500000), + SPH_C32(0xaf5d00d2), SPH_C32(0x25be4942), SPH_C32(0x784a5e50), + SPH_C32(0x9cf4f5c3), SPH_C32(0x66090d68), SPH_C32(0x49450000), + SPH_C32(0x436b0000), SPH_C32(0xae790000), SPH_C32(0x56ae0233), + SPH_C32(0xc672b036), SPH_C32(0x495b720d), SPH_C32(0xb76b6d17), + SPH_C32(0x0f592261) }, + { SPH_C32(0x1e560000), SPH_C32(0x8f240000), SPH_C32(0xd7430000), + SPH_C32(0xca150120), SPH_C32(0xaf3c2e4d), SPH_C32(0xf981adce), + SPH_C32(0x8ed1dd68), SPH_C32(0x76b8dbfb), SPH_C32(0x6dc50000), + SPH_C32(0x422a0000), SPH_C32(0x44320000), SPH_C32(0x511e0280), + SPH_C32(0x7dd772a6), SPH_C32(0x37d373f8), SPH_C32(0xc48dc3ab), + SPH_C32(0x460299f8) }, + { SPH_C32(0x41fe0000), SPH_C32(0xd9270000), SPH_C32(0x94ed0000), + SPH_C32(0xaee60133), SPH_C32(0x8a42a8f2), SPH_C32(0xea903980), + SPH_C32(0xdacf48d7), SPH_C32(0xf81c0092), SPH_C32(0x6d810000), + SPH_C32(0x3d620000), SPH_C32(0x9e4e0000), SPH_C32(0x7b3d0281), + SPH_C32(0x467abb6a), SPH_C32(0x9e65ef7f), SPH_C32(0xc7875dcb), + SPH_C32(0xf808fe66) }, + { SPH_C32(0x1e120000), SPH_C32(0xf06c0000), SPH_C32(0x0d3f0000), + SPH_C32(0xe0360121), SPH_C32(0x9491e781), SPH_C32(0x50373149), + SPH_C32(0x8ddb4308), SPH_C32(0xc8b2bc65), SPH_C32(0x32290000), + SPH_C32(0x6b610000), SPH_C32(0xdde00000), SPH_C32(0x1fce0292), + SPH_C32(0x63043dd5), SPH_C32(0x8d747b31), SPH_C32(0x9399c874), + SPH_C32(0x76ac250f) }, + { SPH_C32(0x41ba0000), SPH_C32(0xa66f0000), SPH_C32(0x4e910000), + SPH_C32(0x84c50132), SPH_C32(0xb1ef613e), SPH_C32(0x4326a507), + SPH_C32(0xd9c5d6b7), SPH_C32(0x4616670c), SPH_C32(0x326d0000), + SPH_C32(0x14290000), SPH_C32(0x079c0000), SPH_C32(0x35ed0293), + SPH_C32(0x58a9f419), SPH_C32(0x24c2e7b6), SPH_C32(0x90935614), + SPH_C32(0xc8a64291) }, + { SPH_C32(0x8bed0000), SPH_C32(0x0e610000), SPH_C32(0xec670000), + SPH_C32(0x82ce0060), SPH_C32(0xa5b6421e), SPH_C32(0xaf74c322), + SPH_C32(0xec18c51f), SPH_C32(0x9158d16f), SPH_C32(0x83560000), + SPH_C32(0x942d0000), SPH_C32(0xd6f30000), SPH_C32(0x7a860360), + SPH_C32(0xe9865ada), SPH_C32(0x0cbf88af), SPH_C32(0x81bce0df), + SPH_C32(0x661df39c) }, + { SPH_C32(0xd4450000), SPH_C32(0x58620000), SPH_C32(0xafc90000), + SPH_C32(0xe63d0073), SPH_C32(0x80c8c4a1), SPH_C32(0xbc65576c), + SPH_C32(0xb80650a0), SPH_C32(0x1ffc0a06), SPH_C32(0x83120000), + SPH_C32(0xeb650000), SPH_C32(0x0c8f0000), SPH_C32(0x50a50361), + SPH_C32(0xd22b9316), SPH_C32(0xa5091428), SPH_C32(0x82b67ebf), + SPH_C32(0xd8179402) }, + { SPH_C32(0x8ba90000), SPH_C32(0x71290000), SPH_C32(0x361b0000), + SPH_C32(0xa8ed0061), SPH_C32(0x9e1b8bd2), SPH_C32(0x06c25fa5), + SPH_C32(0xef125b7f), SPH_C32(0x2f52b6f1), SPH_C32(0xdcba0000), + SPH_C32(0xbd660000), SPH_C32(0x4f210000), SPH_C32(0x34560372), + SPH_C32(0xf75515a9), SPH_C32(0xb6188066), SPH_C32(0xd6a8eb00), + SPH_C32(0x56b34f6b) }, + { SPH_C32(0xd4010000), SPH_C32(0x272a0000), SPH_C32(0x75b50000), + SPH_C32(0xcc1e0072), SPH_C32(0xbb650d6d), SPH_C32(0x15d3cbeb), + SPH_C32(0xbb0ccec0), SPH_C32(0xa1f66d98), SPH_C32(0xdcfe0000), + SPH_C32(0xc22e0000), SPH_C32(0x955d0000), SPH_C32(0x1e750373), + SPH_C32(0xccf8dc65), SPH_C32(0x1fae1ce1), SPH_C32(0xd5a27560), + SPH_C32(0xe8b928f5) }, + { SPH_C32(0x657e0000), SPH_C32(0xd8660000), SPH_C32(0x7ea60000), + SPH_C32(0xa9560180), SPH_C32(0x31e76a62), SPH_C32(0x94183875), + SPH_C32(0xa929e66b), SPH_C32(0xb147bb0b), SPH_C32(0xf87e0000), + SPH_C32(0xc36f0000), SPH_C32(0x7f160000), SPH_C32(0x19c503c0), + SPH_C32(0x775d1ef5), SPH_C32(0x61261d14), SPH_C32(0xa644dbdc), + SPH_C32(0xa1e2936c) }, + { SPH_C32(0x3ad60000), SPH_C32(0x8e650000), SPH_C32(0x3d080000), + SPH_C32(0xcda50193), SPH_C32(0x1499ecdd), SPH_C32(0x8709ac3b), + SPH_C32(0xfd3773d4), SPH_C32(0x3fe36062), SPH_C32(0xf83a0000), + SPH_C32(0xbc270000), SPH_C32(0xa56a0000), SPH_C32(0x33e603c1), + SPH_C32(0x4cf0d739), SPH_C32(0xc8908193), SPH_C32(0xa54e45bc), + SPH_C32(0x1fe8f4f2) }, + { SPH_C32(0x653a0000), SPH_C32(0xa72e0000), SPH_C32(0xa4da0000), + SPH_C32(0x83750181), SPH_C32(0x0a4aa3ae), SPH_C32(0x3daea4f2), + SPH_C32(0xaa23780b), SPH_C32(0x0f4ddc95), SPH_C32(0xa7920000), + SPH_C32(0xea240000), SPH_C32(0xe6c40000), SPH_C32(0x571503d2), + SPH_C32(0x698e5186), SPH_C32(0xdb8115dd), SPH_C32(0xf150d003), + SPH_C32(0x914c2f9b) }, + { SPH_C32(0x3a920000), SPH_C32(0xf12d0000), SPH_C32(0xe7740000), + SPH_C32(0xe7860192), SPH_C32(0x2f342511), SPH_C32(0x2ebf30bc), + SPH_C32(0xfe3dedb4), SPH_C32(0x81e907fc), SPH_C32(0xa7d60000), + SPH_C32(0x956c0000), SPH_C32(0x3cb80000), SPH_C32(0x7d3603d3), + SPH_C32(0x5223984a), SPH_C32(0x7237895a), SPH_C32(0xf25a4e63), + SPH_C32(0x2f464805) }, + { SPH_C32(0x16ed0000), SPH_C32(0x15680000), SPH_C32(0xedd70000), + SPH_C32(0x325d0220), SPH_C32(0xe30c3689), SPH_C32(0x5a4ae643), + SPH_C32(0xe375f8a8), SPH_C32(0x81fdf908), SPH_C32(0xe6280000), + SPH_C32(0x4c4b0000), SPH_C32(0xa8550000), SPH_C32(0xd3d002e0), + SPH_C32(0xd86130b8), SPH_C32(0x98a7b0da), SPH_C32(0x289506b4), + SPH_C32(0xd75a4897) }, + { SPH_C32(0x49450000), SPH_C32(0x436b0000), SPH_C32(0xae790000), + SPH_C32(0x56ae0233), SPH_C32(0xc672b036), SPH_C32(0x495b720d), + SPH_C32(0xb76b6d17), SPH_C32(0x0f592261), SPH_C32(0xe66c0000), + SPH_C32(0x33030000), SPH_C32(0x72290000), SPH_C32(0xf9f302e1), + SPH_C32(0xe3ccf974), SPH_C32(0x31112c5d), SPH_C32(0x2b9f98d4), + SPH_C32(0x69502f09) }, + { SPH_C32(0x16a90000), SPH_C32(0x6a200000), SPH_C32(0x37ab0000), + SPH_C32(0x187e0221), SPH_C32(0xd8a1ff45), SPH_C32(0xf3fc7ac4), + SPH_C32(0xe07f66c8), SPH_C32(0x3ff79e96), SPH_C32(0xb9c40000), + SPH_C32(0x65000000), SPH_C32(0x31870000), SPH_C32(0x9d0002f2), + SPH_C32(0xc6b27fcb), SPH_C32(0x2200b813), SPH_C32(0x7f810d6b), + SPH_C32(0xe7f4f460) }, + { SPH_C32(0x49010000), SPH_C32(0x3c230000), SPH_C32(0x74050000), + SPH_C32(0x7c8d0232), SPH_C32(0xfddf79fa), SPH_C32(0xe0edee8a), + SPH_C32(0xb461f377), SPH_C32(0xb15345ff), SPH_C32(0xb9800000), + SPH_C32(0x1a480000), SPH_C32(0xebfb0000), SPH_C32(0xb72302f3), + SPH_C32(0xfd1fb607), SPH_C32(0x8bb62494), SPH_C32(0x7c8b930b), + SPH_C32(0x59fe93fe) }, + { SPH_C32(0xf87e0000), SPH_C32(0xc36f0000), SPH_C32(0x7f160000), + SPH_C32(0x19c503c0), SPH_C32(0x775d1ef5), SPH_C32(0x61261d14), + SPH_C32(0xa644dbdc), SPH_C32(0xa1e2936c), SPH_C32(0x9d000000), + SPH_C32(0x1b090000), SPH_C32(0x01b00000), SPH_C32(0xb0930240), + SPH_C32(0x46ba7497), SPH_C32(0xf53e2561), SPH_C32(0x0f6d3db7), + SPH_C32(0x10a52867) }, + { SPH_C32(0xa7d60000), SPH_C32(0x956c0000), SPH_C32(0x3cb80000), + SPH_C32(0x7d3603d3), SPH_C32(0x5223984a), SPH_C32(0x7237895a), + SPH_C32(0xf25a4e63), SPH_C32(0x2f464805), SPH_C32(0x9d440000), + SPH_C32(0x64410000), SPH_C32(0xdbcc0000), SPH_C32(0x9ab00241), + SPH_C32(0x7d17bd5b), SPH_C32(0x5c88b9e6), SPH_C32(0x0c67a3d7), + SPH_C32(0xaeaf4ff9) }, + { SPH_C32(0xf83a0000), SPH_C32(0xbc270000), SPH_C32(0xa56a0000), + SPH_C32(0x33e603c1), SPH_C32(0x4cf0d739), SPH_C32(0xc8908193), + SPH_C32(0xa54e45bc), SPH_C32(0x1fe8f4f2), SPH_C32(0xc2ec0000), + SPH_C32(0x32420000), SPH_C32(0x98620000), SPH_C32(0xfe430252), + SPH_C32(0x58693be4), SPH_C32(0x4f992da8), SPH_C32(0x58793668), + SPH_C32(0x200b9490) }, + { SPH_C32(0xa7920000), SPH_C32(0xea240000), SPH_C32(0xe6c40000), + SPH_C32(0x571503d2), SPH_C32(0x698e5186), SPH_C32(0xdb8115dd), + SPH_C32(0xf150d003), SPH_C32(0x914c2f9b), SPH_C32(0xc2a80000), + SPH_C32(0x4d0a0000), SPH_C32(0x421e0000), SPH_C32(0xd4600253), + SPH_C32(0x63c4f228), SPH_C32(0xe62fb12f), SPH_C32(0x5b73a808), + SPH_C32(0x9e01f30e) }, + { SPH_C32(0x6dc50000), SPH_C32(0x422a0000), SPH_C32(0x44320000), + SPH_C32(0x511e0280), SPH_C32(0x7dd772a6), SPH_C32(0x37d373f8), + SPH_C32(0xc48dc3ab), SPH_C32(0x460299f8), SPH_C32(0x73930000), + SPH_C32(0xcd0e0000), SPH_C32(0x93710000), SPH_C32(0x9b0b03a0), + SPH_C32(0xd2eb5ceb), SPH_C32(0xce52de36), SPH_C32(0x4a5c1ec3), + SPH_C32(0x30ba4203) }, + { SPH_C32(0x326d0000), SPH_C32(0x14290000), SPH_C32(0x079c0000), + SPH_C32(0x35ed0293), SPH_C32(0x58a9f419), SPH_C32(0x24c2e7b6), + SPH_C32(0x90935614), SPH_C32(0xc8a64291), SPH_C32(0x73d70000), + SPH_C32(0xb2460000), SPH_C32(0x490d0000), SPH_C32(0xb12803a1), + SPH_C32(0xe9469527), SPH_C32(0x67e442b1), SPH_C32(0x495680a3), + SPH_C32(0x8eb0259d) }, + { SPH_C32(0x6d810000), SPH_C32(0x3d620000), SPH_C32(0x9e4e0000), + SPH_C32(0x7b3d0281), SPH_C32(0x467abb6a), SPH_C32(0x9e65ef7f), + SPH_C32(0xc7875dcb), SPH_C32(0xf808fe66), SPH_C32(0x2c7f0000), + SPH_C32(0xe4450000), SPH_C32(0x0aa30000), SPH_C32(0xd5db03b2), + SPH_C32(0xcc381398), SPH_C32(0x74f5d6ff), SPH_C32(0x1d48151c), + SPH_C32(0x0014fef4) }, + { SPH_C32(0x32290000), SPH_C32(0x6b610000), SPH_C32(0xdde00000), + SPH_C32(0x1fce0292), SPH_C32(0x63043dd5), SPH_C32(0x8d747b31), + SPH_C32(0x9399c874), SPH_C32(0x76ac250f), SPH_C32(0x2c3b0000), + SPH_C32(0x9b0d0000), SPH_C32(0xd0df0000), SPH_C32(0xfff803b3), + SPH_C32(0xf795da54), SPH_C32(0xdd434a78), SPH_C32(0x1e428b7c), + SPH_C32(0xbe1e996a) }, + { SPH_C32(0x83560000), SPH_C32(0x942d0000), SPH_C32(0xd6f30000), + SPH_C32(0x7a860360), SPH_C32(0xe9865ada), SPH_C32(0x0cbf88af), + SPH_C32(0x81bce0df), SPH_C32(0x661df39c), SPH_C32(0x08bb0000), + SPH_C32(0x9a4c0000), SPH_C32(0x3a940000), SPH_C32(0xf8480300), + SPH_C32(0x4c3018c4), SPH_C32(0xa3cb4b8d), SPH_C32(0x6da425c0), + SPH_C32(0xf74522f3) }, + { SPH_C32(0xdcfe0000), SPH_C32(0xc22e0000), SPH_C32(0x955d0000), + SPH_C32(0x1e750373), SPH_C32(0xccf8dc65), SPH_C32(0x1fae1ce1), + SPH_C32(0xd5a27560), SPH_C32(0xe8b928f5), SPH_C32(0x08ff0000), + SPH_C32(0xe5040000), SPH_C32(0xe0e80000), SPH_C32(0xd26b0301), + SPH_C32(0x779dd108), SPH_C32(0x0a7dd70a), SPH_C32(0x6eaebba0), + SPH_C32(0x494f456d) }, + { SPH_C32(0x83120000), SPH_C32(0xeb650000), SPH_C32(0x0c8f0000), + SPH_C32(0x50a50361), SPH_C32(0xd22b9316), SPH_C32(0xa5091428), + SPH_C32(0x82b67ebf), SPH_C32(0xd8179402), SPH_C32(0x57570000), + SPH_C32(0xb3070000), SPH_C32(0xa3460000), SPH_C32(0xb6980312), + SPH_C32(0x52e357b7), SPH_C32(0x196c4344), SPH_C32(0x3ab02e1f), + SPH_C32(0xc7eb9e04) }, + { SPH_C32(0xdcba0000), SPH_C32(0xbd660000), SPH_C32(0x4f210000), + SPH_C32(0x34560372), SPH_C32(0xf75515a9), SPH_C32(0xb6188066), + SPH_C32(0xd6a8eb00), SPH_C32(0x56b34f6b), SPH_C32(0x57130000), + SPH_C32(0xcc4f0000), SPH_C32(0x793a0000), SPH_C32(0x9cbb0313), + SPH_C32(0x694e9e7b), SPH_C32(0xb0dadfc3), SPH_C32(0x39bab07f), + SPH_C32(0x79e1f99a) } +}; + +static const sph_u32 T512_60[16][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0x033d0000), SPH_C32(0x08b30000), SPH_C32(0xf33a0000), + SPH_C32(0x3ac20007), SPH_C32(0x51298a50), SPH_C32(0x6b6e661f), + SPH_C32(0x0ea5cfe3), SPH_C32(0xe6da7ffe), SPH_C32(0xa8da0000), + SPH_C32(0x96be0000), SPH_C32(0x5c1d0000), SPH_C32(0x07da0002), + SPH_C32(0x7d669583), SPH_C32(0x1f98708a), SPH_C32(0xbb668808), + SPH_C32(0xda878000) }, + { SPH_C32(0xa8da0000), SPH_C32(0x96be0000), SPH_C32(0x5c1d0000), + SPH_C32(0x07da0002), SPH_C32(0x7d669583), SPH_C32(0x1f98708a), + SPH_C32(0xbb668808), SPH_C32(0xda878000), SPH_C32(0xabe70000), + SPH_C32(0x9e0d0000), SPH_C32(0xaf270000), SPH_C32(0x3d180005), + SPH_C32(0x2c4f1fd3), SPH_C32(0x74f61695), SPH_C32(0xb5c347eb), + SPH_C32(0x3c5dfffe) }, + { SPH_C32(0xabe70000), SPH_C32(0x9e0d0000), SPH_C32(0xaf270000), + SPH_C32(0x3d180005), SPH_C32(0x2c4f1fd3), SPH_C32(0x74f61695), + SPH_C32(0xb5c347eb), SPH_C32(0x3c5dfffe), SPH_C32(0x033d0000), + SPH_C32(0x08b30000), SPH_C32(0xf33a0000), SPH_C32(0x3ac20007), + SPH_C32(0x51298a50), SPH_C32(0x6b6e661f), SPH_C32(0x0ea5cfe3), + SPH_C32(0xe6da7ffe) }, + { SPH_C32(0x01930000), SPH_C32(0xe7820000), SPH_C32(0xedfb0000), + SPH_C32(0xcf0c000b), SPH_C32(0x8dd08d58), SPH_C32(0xbca3b42e), + SPH_C32(0x063661e1), SPH_C32(0x536f9e7b), SPH_C32(0x92280000), + SPH_C32(0xdc850000), SPH_C32(0x57fa0000), SPH_C32(0x56dc0003), + SPH_C32(0xbae92316), SPH_C32(0x5aefa30c), SPH_C32(0x90cef752), + SPH_C32(0x7b1675d7) }, + { SPH_C32(0x02ae0000), SPH_C32(0xef310000), SPH_C32(0x1ec10000), + SPH_C32(0xf5ce000c), SPH_C32(0xdcf90708), SPH_C32(0xd7cdd231), + SPH_C32(0x0893ae02), SPH_C32(0xb5b5e185), SPH_C32(0x3af20000), + SPH_C32(0x4a3b0000), SPH_C32(0x0be70000), SPH_C32(0x51060001), + SPH_C32(0xc78fb695), SPH_C32(0x4577d386), SPH_C32(0x2ba87f5a), + SPH_C32(0xa191f5d7) }, + { SPH_C32(0xa9490000), SPH_C32(0x713c0000), SPH_C32(0xb1e60000), + SPH_C32(0xc8d60009), SPH_C32(0xf0b618db), SPH_C32(0xa33bc4a4), + SPH_C32(0xbd50e9e9), SPH_C32(0x89e81e7b), SPH_C32(0x39cf0000), + SPH_C32(0x42880000), SPH_C32(0xf8dd0000), SPH_C32(0x6bc40006), + SPH_C32(0x96a63cc5), SPH_C32(0x2e19b599), SPH_C32(0x250db0b9), + SPH_C32(0x474b8a29) }, + { SPH_C32(0xaa740000), SPH_C32(0x798f0000), SPH_C32(0x42dc0000), + SPH_C32(0xf214000e), SPH_C32(0xa19f928b), SPH_C32(0xc855a2bb), + SPH_C32(0xb3f5260a), SPH_C32(0x6f326185), SPH_C32(0x91150000), + SPH_C32(0xd4360000), SPH_C32(0xa4c00000), SPH_C32(0x6c1e0004), + SPH_C32(0xebc0a946), SPH_C32(0x3181c513), SPH_C32(0x9e6b38b1), + SPH_C32(0x9dcc0a29) }, + { SPH_C32(0x92280000), SPH_C32(0xdc850000), SPH_C32(0x57fa0000), + SPH_C32(0x56dc0003), SPH_C32(0xbae92316), SPH_C32(0x5aefa30c), + SPH_C32(0x90cef752), SPH_C32(0x7b1675d7), SPH_C32(0x93bb0000), + SPH_C32(0x3b070000), SPH_C32(0xba010000), SPH_C32(0x99d00008), + SPH_C32(0x3739ae4e), SPH_C32(0xe64c1722), SPH_C32(0x96f896b3), + SPH_C32(0x2879ebac) }, + { SPH_C32(0x91150000), SPH_C32(0xd4360000), SPH_C32(0xa4c00000), + SPH_C32(0x6c1e0004), SPH_C32(0xebc0a946), SPH_C32(0x3181c513), + SPH_C32(0x9e6b38b1), SPH_C32(0x9dcc0a29), SPH_C32(0x3b610000), + SPH_C32(0xadb90000), SPH_C32(0xe61c0000), SPH_C32(0x9e0a000a), + SPH_C32(0x4a5f3bcd), SPH_C32(0xf9d467a8), SPH_C32(0x2d9e1ebb), + SPH_C32(0xf2fe6bac) }, + { SPH_C32(0x3af20000), SPH_C32(0x4a3b0000), SPH_C32(0x0be70000), + SPH_C32(0x51060001), SPH_C32(0xc78fb695), SPH_C32(0x4577d386), + SPH_C32(0x2ba87f5a), SPH_C32(0xa191f5d7), SPH_C32(0x385c0000), + SPH_C32(0xa50a0000), SPH_C32(0x15260000), SPH_C32(0xa4c8000d), + SPH_C32(0x1b76b19d), SPH_C32(0x92ba01b7), SPH_C32(0x233bd158), + SPH_C32(0x14241452) }, + { SPH_C32(0x39cf0000), SPH_C32(0x42880000), SPH_C32(0xf8dd0000), + SPH_C32(0x6bc40006), SPH_C32(0x96a63cc5), SPH_C32(0x2e19b599), + SPH_C32(0x250db0b9), SPH_C32(0x474b8a29), SPH_C32(0x90860000), + SPH_C32(0x33b40000), SPH_C32(0x493b0000), SPH_C32(0xa312000f), + SPH_C32(0x6610241e), SPH_C32(0x8d22713d), SPH_C32(0x985d5950), + SPH_C32(0xcea39452) }, + { SPH_C32(0x93bb0000), SPH_C32(0x3b070000), SPH_C32(0xba010000), + SPH_C32(0x99d00008), SPH_C32(0x3739ae4e), SPH_C32(0xe64c1722), + SPH_C32(0x96f896b3), SPH_C32(0x2879ebac), SPH_C32(0x01930000), + SPH_C32(0xe7820000), SPH_C32(0xedfb0000), SPH_C32(0xcf0c000b), + SPH_C32(0x8dd08d58), SPH_C32(0xbca3b42e), SPH_C32(0x063661e1), + SPH_C32(0x536f9e7b) }, + { SPH_C32(0x90860000), SPH_C32(0x33b40000), SPH_C32(0x493b0000), + SPH_C32(0xa312000f), SPH_C32(0x6610241e), SPH_C32(0x8d22713d), + SPH_C32(0x985d5950), SPH_C32(0xcea39452), SPH_C32(0xa9490000), + SPH_C32(0x713c0000), SPH_C32(0xb1e60000), SPH_C32(0xc8d60009), + SPH_C32(0xf0b618db), SPH_C32(0xa33bc4a4), SPH_C32(0xbd50e9e9), + SPH_C32(0x89e81e7b) }, + { SPH_C32(0x3b610000), SPH_C32(0xadb90000), SPH_C32(0xe61c0000), + SPH_C32(0x9e0a000a), SPH_C32(0x4a5f3bcd), SPH_C32(0xf9d467a8), + SPH_C32(0x2d9e1ebb), SPH_C32(0xf2fe6bac), SPH_C32(0xaa740000), + SPH_C32(0x798f0000), SPH_C32(0x42dc0000), SPH_C32(0xf214000e), + SPH_C32(0xa19f928b), SPH_C32(0xc855a2bb), SPH_C32(0xb3f5260a), + SPH_C32(0x6f326185) }, + { SPH_C32(0x385c0000), SPH_C32(0xa50a0000), SPH_C32(0x15260000), + SPH_C32(0xa4c8000d), SPH_C32(0x1b76b19d), SPH_C32(0x92ba01b7), + SPH_C32(0x233bd158), SPH_C32(0x14241452), SPH_C32(0x02ae0000), + SPH_C32(0xef310000), SPH_C32(0x1ec10000), SPH_C32(0xf5ce000c), + SPH_C32(0xdcf90708), SPH_C32(0xd7cdd231), SPH_C32(0x0893ae02), + SPH_C32(0xb5b5e185) } +}; + +#define INPUT_BIG do { \ + unsigned acc = buf[0]; \ + const sph_u32 *rp; \ + rp = &T512_0[acc >> 2][0]; \ + m0 = rp[0]; \ + m1 = rp[1]; \ + m2 = rp[2]; \ + m3 = rp[3]; \ + m4 = rp[4]; \ + m5 = rp[5]; \ + m6 = rp[6]; \ + m7 = rp[7]; \ + m8 = rp[8]; \ + m9 = rp[9]; \ + mA = rp[10]; \ + mB = rp[11]; \ + mC = rp[12]; \ + mD = rp[13]; \ + mE = rp[14]; \ + mF = rp[15]; \ + acc = (acc << 8) | buf[1]; \ + rp = &T512_6[(acc >> 4) & 0x3f][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + m8 ^= rp[8]; \ + m9 ^= rp[9]; \ + mA ^= rp[10]; \ + mB ^= rp[11]; \ + mC ^= rp[12]; \ + mD ^= rp[13]; \ + mE ^= rp[14]; \ + mF ^= rp[15]; \ + acc = (acc << 8) | buf[2]; \ + rp = &T512_12[(acc >> 6) & 0x3f][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + m8 ^= rp[8]; \ + m9 ^= rp[9]; \ + mA ^= rp[10]; \ + mB ^= rp[11]; \ + mC ^= rp[12]; \ + mD ^= rp[13]; \ + mE ^= rp[14]; \ + mF ^= rp[15]; \ + rp = &T512_18[acc & 0x3f][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + m8 ^= rp[8]; \ + m9 ^= rp[9]; \ + mA ^= rp[10]; \ + mB ^= rp[11]; \ + mC ^= rp[12]; \ + mD ^= rp[13]; \ + mE ^= rp[14]; \ + mF ^= rp[15]; \ + acc = buf[3]; \ + rp = &T512_24[acc >> 2][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + m8 ^= rp[8]; \ + m9 ^= rp[9]; \ + mA ^= rp[10]; \ + mB ^= rp[11]; \ + mC ^= rp[12]; \ + mD ^= rp[13]; \ + mE ^= rp[14]; \ + mF ^= rp[15]; \ + acc = (acc << 8) | buf[4]; \ + rp = &T512_30[(acc >> 4) & 0x3f][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + m8 ^= rp[8]; \ + m9 ^= rp[9]; \ + mA ^= rp[10]; \ + mB ^= rp[11]; \ + mC ^= rp[12]; \ + mD ^= rp[13]; \ + mE ^= rp[14]; \ + mF ^= rp[15]; \ + acc = (acc << 8) | buf[5]; \ + rp = &T512_36[(acc >> 6) & 0x3f][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + m8 ^= rp[8]; \ + m9 ^= rp[9]; \ + mA ^= rp[10]; \ + mB ^= rp[11]; \ + mC ^= rp[12]; \ + mD ^= rp[13]; \ + mE ^= rp[14]; \ + mF ^= rp[15]; \ + rp = &T512_42[acc & 0x3f][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + m8 ^= rp[8]; \ + m9 ^= rp[9]; \ + mA ^= rp[10]; \ + mB ^= rp[11]; \ + mC ^= rp[12]; \ + mD ^= rp[13]; \ + mE ^= rp[14]; \ + mF ^= rp[15]; \ + acc = buf[6]; \ + rp = &T512_48[acc >> 2][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + m8 ^= rp[8]; \ + m9 ^= rp[9]; \ + mA ^= rp[10]; \ + mB ^= rp[11]; \ + mC ^= rp[12]; \ + mD ^= rp[13]; \ + mE ^= rp[14]; \ + mF ^= rp[15]; \ + acc = (acc << 8) | buf[7]; \ + rp = &T512_54[(acc >> 4) & 0x3f][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + m8 ^= rp[8]; \ + m9 ^= rp[9]; \ + mA ^= rp[10]; \ + mB ^= rp[11]; \ + mC ^= rp[12]; \ + mD ^= rp[13]; \ + mE ^= rp[14]; \ + mF ^= rp[15]; \ + rp = &T512_60[acc & 0x0f][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + m8 ^= rp[8]; \ + m9 ^= rp[9]; \ + mA ^= rp[10]; \ + mB ^= rp[11]; \ + mC ^= rp[12]; \ + mD ^= rp[13]; \ + mE ^= rp[14]; \ + mF ^= rp[15]; \ + } while (0) + +#endif + +#if SPH_HAMSI_EXPAND_BIG == 7 + +static const sph_u32 T512_0[128][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0xc96b0030), SPH_C32(0xe7250000), SPH_C32(0x2f840000), + SPH_C32(0x264f0000), SPH_C32(0x08695bf9), SPH_C32(0x6dfcf137), + SPH_C32(0x509f6984), SPH_C32(0x9e69af68), SPH_C32(0x26600240), + SPH_C32(0xddd80000), SPH_C32(0x722a0000), SPH_C32(0x4f060000), + SPH_C32(0x936667ff), SPH_C32(0x29f944ce), SPH_C32(0x368b63d5), + SPH_C32(0x0c26f262) }, + { SPH_C32(0x145a3c00), SPH_C32(0xb9e90000), SPH_C32(0x61270000), + SPH_C32(0xf1610000), SPH_C32(0xce613d6c), SPH_C32(0xb0493d78), + SPH_C32(0x47a96720), SPH_C32(0xe18e24c5), SPH_C32(0x23671400), + SPH_C32(0xc8b90000), SPH_C32(0xf4c70000), SPH_C32(0xfb750000), + SPH_C32(0x73cd2465), SPH_C32(0xf8a6a549), SPH_C32(0x02c40a3f), + SPH_C32(0xdc24e61f) }, + { SPH_C32(0xdd313c30), SPH_C32(0x5ecc0000), SPH_C32(0x4ea30000), + SPH_C32(0xd72e0000), SPH_C32(0xc6086695), SPH_C32(0xddb5cc4f), + SPH_C32(0x17360ea4), SPH_C32(0x7fe78bad), SPH_C32(0x05071640), + SPH_C32(0x15610000), SPH_C32(0x86ed0000), SPH_C32(0xb4730000), + SPH_C32(0xe0ab439a), SPH_C32(0xd15fe187), SPH_C32(0x344f69ea), + SPH_C32(0xd002147d) }, + { SPH_C32(0x23671400), SPH_C32(0xc8b90000), SPH_C32(0xf4c70000), + SPH_C32(0xfb750000), SPH_C32(0x73cd2465), SPH_C32(0xf8a6a549), + SPH_C32(0x02c40a3f), SPH_C32(0xdc24e61f), SPH_C32(0x373d2800), + SPH_C32(0x71500000), SPH_C32(0x95e00000), SPH_C32(0x0a140000), + SPH_C32(0xbdac1909), SPH_C32(0x48ef9831), SPH_C32(0x456d6d1f), + SPH_C32(0x3daac2da) }, + { SPH_C32(0xea0c1430), SPH_C32(0x2f9c0000), SPH_C32(0xdb430000), + SPH_C32(0xdd3a0000), SPH_C32(0x7ba47f9c), SPH_C32(0x955a547e), + SPH_C32(0x525b63bb), SPH_C32(0x424d4977), SPH_C32(0x115d2a40), + SPH_C32(0xac880000), SPH_C32(0xe7ca0000), SPH_C32(0x45120000), + SPH_C32(0x2eca7ef6), SPH_C32(0x6116dcff), SPH_C32(0x73e60eca), + SPH_C32(0x318c30b8) }, + { SPH_C32(0x373d2800), SPH_C32(0x71500000), SPH_C32(0x95e00000), + SPH_C32(0x0a140000), SPH_C32(0xbdac1909), SPH_C32(0x48ef9831), + SPH_C32(0x456d6d1f), SPH_C32(0x3daac2da), SPH_C32(0x145a3c00), + SPH_C32(0xb9e90000), SPH_C32(0x61270000), SPH_C32(0xf1610000), + SPH_C32(0xce613d6c), SPH_C32(0xb0493d78), SPH_C32(0x47a96720), + SPH_C32(0xe18e24c5) }, + { SPH_C32(0xfe562830), SPH_C32(0x96750000), SPH_C32(0xba640000), + SPH_C32(0x2c5b0000), SPH_C32(0xb5c542f0), SPH_C32(0x25136906), + SPH_C32(0x15f2049b), SPH_C32(0xa3c36db2), SPH_C32(0x323a3e40), + SPH_C32(0x64310000), SPH_C32(0x130d0000), SPH_C32(0xbe670000), + SPH_C32(0x5d075a93), SPH_C32(0x99b079b6), SPH_C32(0x712204f5), + SPH_C32(0xeda8d6a7) }, + { SPH_C32(0x54285c00), SPH_C32(0xeaed0000), SPH_C32(0xc5d60000), + SPH_C32(0xa1c50000), SPH_C32(0xb3a26770), SPH_C32(0x94a5c4e1), + SPH_C32(0x6bb0419d), SPH_C32(0x551b3782), SPH_C32(0x9cbb1800), + SPH_C32(0xb0d30000), SPH_C32(0x92510000), SPH_C32(0xed930000), + SPH_C32(0x593a4345), SPH_C32(0xe114d5f4), SPH_C32(0x430633da), + SPH_C32(0x78cace29) }, + { SPH_C32(0x9d435c30), SPH_C32(0x0dc80000), SPH_C32(0xea520000), + SPH_C32(0x878a0000), SPH_C32(0xbbcb3c89), SPH_C32(0xf95935d6), + SPH_C32(0x3b2f2819), SPH_C32(0xcb7298ea), SPH_C32(0xbadb1a40), + SPH_C32(0x6d0b0000), SPH_C32(0xe07b0000), SPH_C32(0xa2950000), + SPH_C32(0xca5c24ba), SPH_C32(0xc8ed913a), SPH_C32(0x758d500f), + SPH_C32(0x74ec3c4b) }, + { SPH_C32(0x40726000), SPH_C32(0x53040000), SPH_C32(0xa4f10000), + SPH_C32(0x50a40000), SPH_C32(0x7dc35a1c), SPH_C32(0x24ecf999), + SPH_C32(0x2c1926bd), SPH_C32(0xb4951347), SPH_C32(0xbfdc0c00), + SPH_C32(0x786a0000), SPH_C32(0x66960000), SPH_C32(0x16e60000), + SPH_C32(0x2af76720), SPH_C32(0x19b270bd), SPH_C32(0x41c239e5), + SPH_C32(0xa4ee2836) }, + { SPH_C32(0x89196030), SPH_C32(0xb4210000), SPH_C32(0x8b750000), + SPH_C32(0x76eb0000), SPH_C32(0x75aa01e5), SPH_C32(0x491008ae), + SPH_C32(0x7c864f39), SPH_C32(0x2afcbc2f), SPH_C32(0x99bc0e40), + SPH_C32(0xa5b20000), SPH_C32(0x14bc0000), SPH_C32(0x59e00000), + SPH_C32(0xb99100df), SPH_C32(0x304b3473), SPH_C32(0x77495a30), + SPH_C32(0xa8c8da54) }, + { SPH_C32(0x774f4800), SPH_C32(0x22540000), SPH_C32(0x31110000), + SPH_C32(0x5ab00000), SPH_C32(0xc06f4315), SPH_C32(0x6c0361a8), + SPH_C32(0x69744ba2), SPH_C32(0x893fd19d), SPH_C32(0xab863000), + SPH_C32(0xc1830000), SPH_C32(0x07b10000), SPH_C32(0xe7870000), + SPH_C32(0xe4965a4c), SPH_C32(0xa9fb4dc5), SPH_C32(0x066b5ec5), + SPH_C32(0x45600cf3) }, + { SPH_C32(0xbe244830), SPH_C32(0xc5710000), SPH_C32(0x1e950000), + SPH_C32(0x7cff0000), SPH_C32(0xc80618ec), SPH_C32(0x01ff909f), + SPH_C32(0x39eb2226), SPH_C32(0x17567ef5), SPH_C32(0x8de63240), + SPH_C32(0x1c5b0000), SPH_C32(0x759b0000), SPH_C32(0xa8810000), + SPH_C32(0x77f03db3), SPH_C32(0x8002090b), SPH_C32(0x30e03d10), + SPH_C32(0x4946fe91) }, + { SPH_C32(0x63157400), SPH_C32(0x9bbd0000), SPH_C32(0x50360000), + SPH_C32(0xabd10000), SPH_C32(0x0e0e7e79), SPH_C32(0xdc4a5cd0), + SPH_C32(0x2edd2c82), SPH_C32(0x68b1f558), SPH_C32(0x88e12400), + SPH_C32(0x093a0000), SPH_C32(0xf3760000), SPH_C32(0x1cf20000), + SPH_C32(0x975b7e29), SPH_C32(0x515de88c), SPH_C32(0x04af54fa), + SPH_C32(0x9944eaec) }, + { SPH_C32(0xaa7e7430), SPH_C32(0x7c980000), SPH_C32(0x7fb20000), + SPH_C32(0x8d9e0000), SPH_C32(0x06672580), SPH_C32(0xb1b6ade7), + SPH_C32(0x7e424506), SPH_C32(0xf6d85a30), SPH_C32(0xae812640), + SPH_C32(0xd4e20000), SPH_C32(0x815c0000), SPH_C32(0x53f40000), + SPH_C32(0x043d19d6), SPH_C32(0x78a4ac42), SPH_C32(0x3224372f), + SPH_C32(0x9562188e) }, + { SPH_C32(0x9cbb1800), SPH_C32(0xb0d30000), SPH_C32(0x92510000), + SPH_C32(0xed930000), SPH_C32(0x593a4345), SPH_C32(0xe114d5f4), + SPH_C32(0x430633da), SPH_C32(0x78cace29), SPH_C32(0xc8934400), + SPH_C32(0x5a3e0000), SPH_C32(0x57870000), SPH_C32(0x4c560000), + SPH_C32(0xea982435), SPH_C32(0x75b11115), SPH_C32(0x28b67247), + SPH_C32(0x2dd1f9ab) }, + { SPH_C32(0x55d01830), SPH_C32(0x57f60000), SPH_C32(0xbdd50000), + SPH_C32(0xcbdc0000), SPH_C32(0x515318bc), SPH_C32(0x8ce824c3), + SPH_C32(0x13995a5e), SPH_C32(0xe6a36141), SPH_C32(0xeef34640), + SPH_C32(0x87e60000), SPH_C32(0x25ad0000), SPH_C32(0x03500000), + SPH_C32(0x79fe43ca), SPH_C32(0x5c4855db), SPH_C32(0x1e3d1192), + SPH_C32(0x21f70bc9) }, + { SPH_C32(0x88e12400), SPH_C32(0x093a0000), SPH_C32(0xf3760000), + SPH_C32(0x1cf20000), SPH_C32(0x975b7e29), SPH_C32(0x515de88c), + SPH_C32(0x04af54fa), SPH_C32(0x9944eaec), SPH_C32(0xebf45000), + SPH_C32(0x92870000), SPH_C32(0xa3400000), SPH_C32(0xb7230000), + SPH_C32(0x99550050), SPH_C32(0x8d17b45c), SPH_C32(0x2a727878), + SPH_C32(0xf1f51fb4) }, + { SPH_C32(0x418a2430), SPH_C32(0xee1f0000), SPH_C32(0xdcf20000), + SPH_C32(0x3abd0000), SPH_C32(0x9f3225d0), SPH_C32(0x3ca119bb), + SPH_C32(0x54303d7e), SPH_C32(0x072d4584), SPH_C32(0xcd945240), + SPH_C32(0x4f5f0000), SPH_C32(0xd16a0000), SPH_C32(0xf8250000), + SPH_C32(0x0a3367af), SPH_C32(0xa4eef092), SPH_C32(0x1cf91bad), + SPH_C32(0xfdd3edd6) }, + { SPH_C32(0xbfdc0c00), SPH_C32(0x786a0000), SPH_C32(0x66960000), + SPH_C32(0x16e60000), SPH_C32(0x2af76720), SPH_C32(0x19b270bd), + SPH_C32(0x41c239e5), SPH_C32(0xa4ee2836), SPH_C32(0xffae6c00), + SPH_C32(0x2b6e0000), SPH_C32(0xc2670000), SPH_C32(0x46420000), + SPH_C32(0x57343d3c), SPH_C32(0x3d5e8924), SPH_C32(0x6ddb1f58), + SPH_C32(0x107b3b71) }, + { SPH_C32(0x76b70c30), SPH_C32(0x9f4f0000), SPH_C32(0x49120000), + SPH_C32(0x30a90000), SPH_C32(0x229e3cd9), SPH_C32(0x744e818a), + SPH_C32(0x115d5061), SPH_C32(0x3a87875e), SPH_C32(0xd9ce6e40), + SPH_C32(0xf6b60000), SPH_C32(0xb04d0000), SPH_C32(0x09440000), + SPH_C32(0xc4525ac3), SPH_C32(0x14a7cdea), SPH_C32(0x5b507c8d), + SPH_C32(0x1c5dc913) }, + { SPH_C32(0xab863000), SPH_C32(0xc1830000), SPH_C32(0x07b10000), + SPH_C32(0xe7870000), SPH_C32(0xe4965a4c), SPH_C32(0xa9fb4dc5), + SPH_C32(0x066b5ec5), SPH_C32(0x45600cf3), SPH_C32(0xdcc97800), + SPH_C32(0xe3d70000), SPH_C32(0x36a00000), SPH_C32(0xbd370000), + SPH_C32(0x24f91959), SPH_C32(0xc5f82c6d), SPH_C32(0x6f1f1567), + SPH_C32(0xcc5fdd6e) }, + { SPH_C32(0x62ed3030), SPH_C32(0x26a60000), SPH_C32(0x28350000), + SPH_C32(0xc1c80000), SPH_C32(0xecff01b5), SPH_C32(0xc407bcf2), + SPH_C32(0x56f43741), SPH_C32(0xdb09a39b), SPH_C32(0xfaa97a40), + SPH_C32(0x3e0f0000), SPH_C32(0x448a0000), SPH_C32(0xf2310000), + SPH_C32(0xb79f7ea6), SPH_C32(0xec0168a3), SPH_C32(0x599476b2), + SPH_C32(0xc0792f0c) }, + { SPH_C32(0xc8934400), SPH_C32(0x5a3e0000), SPH_C32(0x57870000), + SPH_C32(0x4c560000), SPH_C32(0xea982435), SPH_C32(0x75b11115), + SPH_C32(0x28b67247), SPH_C32(0x2dd1f9ab), SPH_C32(0x54285c00), + SPH_C32(0xeaed0000), SPH_C32(0xc5d60000), SPH_C32(0xa1c50000), + SPH_C32(0xb3a26770), SPH_C32(0x94a5c4e1), SPH_C32(0x6bb0419d), + SPH_C32(0x551b3782) }, + { SPH_C32(0x01f84430), SPH_C32(0xbd1b0000), SPH_C32(0x78030000), + SPH_C32(0x6a190000), SPH_C32(0xe2f17fcc), SPH_C32(0x184de022), + SPH_C32(0x78291bc3), SPH_C32(0xb3b856c3), SPH_C32(0x72485e40), + SPH_C32(0x37350000), SPH_C32(0xb7fc0000), SPH_C32(0xeec30000), + SPH_C32(0x20c4008f), SPH_C32(0xbd5c802f), SPH_C32(0x5d3b2248), + SPH_C32(0x593dc5e0) }, + { SPH_C32(0xdcc97800), SPH_C32(0xe3d70000), SPH_C32(0x36a00000), + SPH_C32(0xbd370000), SPH_C32(0x24f91959), SPH_C32(0xc5f82c6d), + SPH_C32(0x6f1f1567), SPH_C32(0xcc5fdd6e), SPH_C32(0x774f4800), + SPH_C32(0x22540000), SPH_C32(0x31110000), SPH_C32(0x5ab00000), + SPH_C32(0xc06f4315), SPH_C32(0x6c0361a8), SPH_C32(0x69744ba2), + SPH_C32(0x893fd19d) }, + { SPH_C32(0x15a27830), SPH_C32(0x04f20000), SPH_C32(0x19240000), + SPH_C32(0x9b780000), SPH_C32(0x2c9042a0), SPH_C32(0xa804dd5a), + SPH_C32(0x3f807ce3), SPH_C32(0x52367206), SPH_C32(0x512f4a40), + SPH_C32(0xff8c0000), SPH_C32(0x433b0000), SPH_C32(0x15b60000), + SPH_C32(0x530924ea), SPH_C32(0x45fa2566), SPH_C32(0x5fff2877), + SPH_C32(0x851923ff) }, + { SPH_C32(0xebf45000), SPH_C32(0x92870000), SPH_C32(0xa3400000), + SPH_C32(0xb7230000), SPH_C32(0x99550050), SPH_C32(0x8d17b45c), + SPH_C32(0x2a727878), SPH_C32(0xf1f51fb4), SPH_C32(0x63157400), + SPH_C32(0x9bbd0000), SPH_C32(0x50360000), SPH_C32(0xabd10000), + SPH_C32(0x0e0e7e79), SPH_C32(0xdc4a5cd0), SPH_C32(0x2edd2c82), + SPH_C32(0x68b1f558) }, + { SPH_C32(0x229f5030), SPH_C32(0x75a20000), SPH_C32(0x8cc40000), + SPH_C32(0x916c0000), SPH_C32(0x913c5ba9), SPH_C32(0xe0eb456b), + SPH_C32(0x7aed11fc), SPH_C32(0x6f9cb0dc), SPH_C32(0x45757640), + SPH_C32(0x46650000), SPH_C32(0x221c0000), SPH_C32(0xe4d70000), + SPH_C32(0x9d681986), SPH_C32(0xf5b3181e), SPH_C32(0x18564f57), + SPH_C32(0x6497073a) }, + { SPH_C32(0xffae6c00), SPH_C32(0x2b6e0000), SPH_C32(0xc2670000), + SPH_C32(0x46420000), SPH_C32(0x57343d3c), SPH_C32(0x3d5e8924), + SPH_C32(0x6ddb1f58), SPH_C32(0x107b3b71), SPH_C32(0x40726000), + SPH_C32(0x53040000), SPH_C32(0xa4f10000), SPH_C32(0x50a40000), + SPH_C32(0x7dc35a1c), SPH_C32(0x24ecf999), SPH_C32(0x2c1926bd), + SPH_C32(0xb4951347) }, + { SPH_C32(0x36c56c30), SPH_C32(0xcc4b0000), SPH_C32(0xede30000), + SPH_C32(0x600d0000), SPH_C32(0x5f5d66c5), SPH_C32(0x50a27813), + SPH_C32(0x3d4476dc), SPH_C32(0x8e129419), SPH_C32(0x66126240), + SPH_C32(0x8edc0000), SPH_C32(0xd6db0000), SPH_C32(0x1fa20000), + SPH_C32(0xeea53de3), SPH_C32(0x0d15bd57), SPH_C32(0x1a924568), + SPH_C32(0xb8b3e125) }, + { SPH_C32(0x29449c00), SPH_C32(0x64e70000), SPH_C32(0xf24b0000), + SPH_C32(0xc2f30000), SPH_C32(0x0ede4e8f), SPH_C32(0x56c23745), + SPH_C32(0xf3e04259), SPH_C32(0x8d0d9ec4), SPH_C32(0x466d0c00), + SPH_C32(0x08620000), SPH_C32(0xdd5d0000), SPH_C32(0xbadd0000), + SPH_C32(0x6a927942), SPH_C32(0x441f2b93), SPH_C32(0x218ace6f), + SPH_C32(0xbf2c0be2) }, + { SPH_C32(0xe02f9c30), SPH_C32(0x83c20000), SPH_C32(0xddcf0000), + SPH_C32(0xe4bc0000), SPH_C32(0x06b71576), SPH_C32(0x3b3ec672), + SPH_C32(0xa37f2bdd), SPH_C32(0x136431ac), SPH_C32(0x600d0e40), + SPH_C32(0xd5ba0000), SPH_C32(0xaf770000), SPH_C32(0xf5db0000), + SPH_C32(0xf9f41ebd), SPH_C32(0x6de66f5d), SPH_C32(0x1701adba), + SPH_C32(0xb30af980) }, + { SPH_C32(0x3d1ea000), SPH_C32(0xdd0e0000), SPH_C32(0x936c0000), + SPH_C32(0x33920000), SPH_C32(0xc0bf73e3), SPH_C32(0xe68b0a3d), + SPH_C32(0xb4492579), SPH_C32(0x6c83ba01), SPH_C32(0x650a1800), + SPH_C32(0xc0db0000), SPH_C32(0x299a0000), SPH_C32(0x41a80000), + SPH_C32(0x195f5d27), SPH_C32(0xbcb98eda), SPH_C32(0x234ec450), + SPH_C32(0x6308edfd) }, + { SPH_C32(0xf475a030), SPH_C32(0x3a2b0000), SPH_C32(0xbce80000), + SPH_C32(0x15dd0000), SPH_C32(0xc8d6281a), SPH_C32(0x8b77fb0a), + SPH_C32(0xe4d64cfd), SPH_C32(0xf2ea1569), SPH_C32(0x436a1a40), + SPH_C32(0x1d030000), SPH_C32(0x5bb00000), SPH_C32(0x0eae0000), + SPH_C32(0x8a393ad8), SPH_C32(0x9540ca14), SPH_C32(0x15c5a785), + SPH_C32(0x6f2e1f9f) }, + { SPH_C32(0x0a238800), SPH_C32(0xac5e0000), SPH_C32(0x068c0000), + SPH_C32(0x39860000), SPH_C32(0x7d136aea), SPH_C32(0xae64920c), + SPH_C32(0xf1244866), SPH_C32(0x512978db), SPH_C32(0x71502400), + SPH_C32(0x79320000), SPH_C32(0x48bd0000), SPH_C32(0xb0c90000), + SPH_C32(0xd73e604b), SPH_C32(0x0cf0b3a2), SPH_C32(0x64e7a370), + SPH_C32(0x8286c938) }, + { SPH_C32(0xc3488830), SPH_C32(0x4b7b0000), SPH_C32(0x29080000), + SPH_C32(0x1fc90000), SPH_C32(0x757a3113), SPH_C32(0xc398633b), + SPH_C32(0xa1bb21e2), SPH_C32(0xcf40d7b3), SPH_C32(0x57302640), + SPH_C32(0xa4ea0000), SPH_C32(0x3a970000), SPH_C32(0xffcf0000), + SPH_C32(0x445807b4), SPH_C32(0x2509f76c), SPH_C32(0x526cc0a5), + SPH_C32(0x8ea03b5a) }, + { SPH_C32(0x1e79b400), SPH_C32(0x15b70000), SPH_C32(0x67ab0000), + SPH_C32(0xc8e70000), SPH_C32(0xb3725786), SPH_C32(0x1e2daf74), + SPH_C32(0xb68d2f46), SPH_C32(0xb0a75c1e), SPH_C32(0x52373000), + SPH_C32(0xb18b0000), SPH_C32(0xbc7a0000), SPH_C32(0x4bbc0000), + SPH_C32(0xa4f3442e), SPH_C32(0xf45616eb), SPH_C32(0x6623a94f), + SPH_C32(0x5ea22f27) }, + { SPH_C32(0xd712b430), SPH_C32(0xf2920000), SPH_C32(0x482f0000), + SPH_C32(0xeea80000), SPH_C32(0xbb1b0c7f), SPH_C32(0x73d15e43), + SPH_C32(0xe61246c2), SPH_C32(0x2ecef376), SPH_C32(0x74573240), + SPH_C32(0x6c530000), SPH_C32(0xce500000), SPH_C32(0x04ba0000), + SPH_C32(0x379523d1), SPH_C32(0xddaf5225), SPH_C32(0x50a8ca9a), + SPH_C32(0x5284dd45) }, + { SPH_C32(0x7d6cc000), SPH_C32(0x8e0a0000), SPH_C32(0x379d0000), + SPH_C32(0x63360000), SPH_C32(0xbd7c29ff), SPH_C32(0xc267f3a4), + SPH_C32(0x985003c4), SPH_C32(0xd816a946), SPH_C32(0xdad61400), + SPH_C32(0xb8b10000), SPH_C32(0x4f0c0000), SPH_C32(0x574e0000), + SPH_C32(0x33a83a07), SPH_C32(0xa50bfe67), SPH_C32(0x628cfdb5), + SPH_C32(0xc7e6c5cb) }, + { SPH_C32(0xb407c030), SPH_C32(0x692f0000), SPH_C32(0x18190000), + SPH_C32(0x45790000), SPH_C32(0xb5157206), SPH_C32(0xaf9b0293), + SPH_C32(0xc8cf6a40), SPH_C32(0x467f062e), SPH_C32(0xfcb61640), + SPH_C32(0x65690000), SPH_C32(0x3d260000), SPH_C32(0x18480000), + SPH_C32(0xa0ce5df8), SPH_C32(0x8cf2baa9), SPH_C32(0x54079e60), + SPH_C32(0xcbc037a9) }, + { SPH_C32(0x6936fc00), SPH_C32(0x37e30000), SPH_C32(0x56ba0000), + SPH_C32(0x92570000), SPH_C32(0x731d1493), SPH_C32(0x722ecedc), + SPH_C32(0xdff964e4), SPH_C32(0x39988d83), SPH_C32(0xf9b10000), + SPH_C32(0x70080000), SPH_C32(0xbbcb0000), SPH_C32(0xac3b0000), + SPH_C32(0x40651e62), SPH_C32(0x5dad5b2e), SPH_C32(0x6048f78a), + SPH_C32(0x1bc223d4) }, + { SPH_C32(0xa05dfc30), SPH_C32(0xd0c60000), SPH_C32(0x793e0000), + SPH_C32(0xb4180000), SPH_C32(0x7b744f6a), SPH_C32(0x1fd23feb), + SPH_C32(0x8f660d60), SPH_C32(0xa7f122eb), SPH_C32(0xdfd10240), + SPH_C32(0xadd00000), SPH_C32(0xc9e10000), SPH_C32(0xe33d0000), + SPH_C32(0xd303799d), SPH_C32(0x74541fe0), SPH_C32(0x56c3945f), + SPH_C32(0x17e4d1b6) }, + { SPH_C32(0x5e0bd400), SPH_C32(0x46b30000), SPH_C32(0xc35a0000), + SPH_C32(0x98430000), SPH_C32(0xceb10d9a), SPH_C32(0x3ac156ed), + SPH_C32(0x9a9409fb), SPH_C32(0x04324f59), SPH_C32(0xedeb3c00), + SPH_C32(0xc9e10000), SPH_C32(0xdaec0000), SPH_C32(0x5d5a0000), + SPH_C32(0x8e04230e), SPH_C32(0xede46656), SPH_C32(0x27e190aa), + SPH_C32(0xfa4c0711) }, + { SPH_C32(0x9760d430), SPH_C32(0xa1960000), SPH_C32(0xecde0000), + SPH_C32(0xbe0c0000), SPH_C32(0xc6d85663), SPH_C32(0x573da7da), + SPH_C32(0xca0b607f), SPH_C32(0x9a5be031), SPH_C32(0xcb8b3e40), + SPH_C32(0x14390000), SPH_C32(0xa8c60000), SPH_C32(0x125c0000), + SPH_C32(0x1d6244f1), SPH_C32(0xc41d2298), SPH_C32(0x116af37f), + SPH_C32(0xf66af573) }, + { SPH_C32(0x4a51e800), SPH_C32(0xff5a0000), SPH_C32(0xa27d0000), + SPH_C32(0x69220000), SPH_C32(0x00d030f6), SPH_C32(0x8a886b95), + SPH_C32(0xdd3d6edb), SPH_C32(0xe5bc6b9c), SPH_C32(0xce8c2800), + SPH_C32(0x01580000), SPH_C32(0x2e2b0000), SPH_C32(0xa62f0000), + SPH_C32(0xfdc9076b), SPH_C32(0x1542c31f), SPH_C32(0x25259a95), + SPH_C32(0x2668e10e) }, + { SPH_C32(0x833ae830), SPH_C32(0x187f0000), SPH_C32(0x8df90000), + SPH_C32(0x4f6d0000), SPH_C32(0x08b96b0f), SPH_C32(0xe7749aa2), + SPH_C32(0x8da2075f), SPH_C32(0x7bd5c4f4), SPH_C32(0xe8ec2a40), + SPH_C32(0xdc800000), SPH_C32(0x5c010000), SPH_C32(0xe9290000), + SPH_C32(0x6eaf6094), SPH_C32(0x3cbb87d1), SPH_C32(0x13aef940), + SPH_C32(0x2a4e136c) }, + { SPH_C32(0xb5ff8400), SPH_C32(0xd4340000), SPH_C32(0x601a0000), + SPH_C32(0x2f600000), SPH_C32(0x57e40dca), SPH_C32(0xb7d6e2b1), + SPH_C32(0xb0e67183), SPH_C32(0xf5c750ed), SPH_C32(0x8efe4800), + SPH_C32(0x525c0000), SPH_C32(0x8ada0000), SPH_C32(0xf68b0000), + SPH_C32(0x800a5d77), SPH_C32(0x31ae3a86), SPH_C32(0x093cbc28), + SPH_C32(0x92fdf249) }, + { SPH_C32(0x7c948430), SPH_C32(0x33110000), SPH_C32(0x4f9e0000), + SPH_C32(0x092f0000), SPH_C32(0x5f8d5633), SPH_C32(0xda2a1386), + SPH_C32(0xe0791807), SPH_C32(0x6baeff85), SPH_C32(0xa89e4a40), + SPH_C32(0x8f840000), SPH_C32(0xf8f00000), SPH_C32(0xb98d0000), + SPH_C32(0x136c3a88), SPH_C32(0x18577e48), SPH_C32(0x3fb7dffd), + SPH_C32(0x9edb002b) }, + { SPH_C32(0xa1a5b800), SPH_C32(0x6ddd0000), SPH_C32(0x013d0000), + SPH_C32(0xde010000), SPH_C32(0x998530a6), SPH_C32(0x079fdfc9), + SPH_C32(0xf74f16a3), SPH_C32(0x14497428), SPH_C32(0xad995c00), + SPH_C32(0x9ae50000), SPH_C32(0x7e1d0000), SPH_C32(0x0dfe0000), + SPH_C32(0xf3c77912), SPH_C32(0xc9089fcf), SPH_C32(0x0bf8b617), + SPH_C32(0x4ed91456) }, + { SPH_C32(0x68ceb830), SPH_C32(0x8af80000), SPH_C32(0x2eb90000), + SPH_C32(0xf84e0000), SPH_C32(0x91ec6b5f), SPH_C32(0x6a632efe), + SPH_C32(0xa7d07f27), SPH_C32(0x8a20db40), SPH_C32(0x8bf95e40), + SPH_C32(0x473d0000), SPH_C32(0x0c370000), SPH_C32(0x42f80000), + SPH_C32(0x60a11eed), SPH_C32(0xe0f1db01), SPH_C32(0x3d73d5c2), + SPH_C32(0x42ffe634) }, + { SPH_C32(0x96989000), SPH_C32(0x1c8d0000), SPH_C32(0x94dd0000), + SPH_C32(0xd4150000), SPH_C32(0x242929af), SPH_C32(0x4f7047f8), + SPH_C32(0xb2227bbc), SPH_C32(0x29e3b6f2), SPH_C32(0xb9c36000), + SPH_C32(0x230c0000), SPH_C32(0x1f3a0000), SPH_C32(0xfc9f0000), + SPH_C32(0x3da6447e), SPH_C32(0x7941a2b7), SPH_C32(0x4c51d137), + SPH_C32(0xaf573093) }, + { SPH_C32(0x5ff39030), SPH_C32(0xfba80000), SPH_C32(0xbb590000), + SPH_C32(0xf25a0000), SPH_C32(0x2c407256), SPH_C32(0x228cb6cf), + SPH_C32(0xe2bd1238), SPH_C32(0xb78a199a), SPH_C32(0x9fa36240), + SPH_C32(0xfed40000), SPH_C32(0x6d100000), SPH_C32(0xb3990000), + SPH_C32(0xaec02381), SPH_C32(0x50b8e679), SPH_C32(0x7adab2e2), + SPH_C32(0xa371c2f1) }, + { SPH_C32(0x82c2ac00), SPH_C32(0xa5640000), SPH_C32(0xf5fa0000), + SPH_C32(0x25740000), SPH_C32(0xea4814c3), SPH_C32(0xff397a80), + SPH_C32(0xf58b1c9c), SPH_C32(0xc86d9237), SPH_C32(0x9aa47400), + SPH_C32(0xebb50000), SPH_C32(0xebfd0000), SPH_C32(0x07ea0000), + SPH_C32(0x4e6b601b), SPH_C32(0x81e707fe), SPH_C32(0x4e95db08), + SPH_C32(0x7373d68c) }, + { SPH_C32(0x4ba9ac30), SPH_C32(0x42410000), SPH_C32(0xda7e0000), + SPH_C32(0x033b0000), SPH_C32(0xe2214f3a), SPH_C32(0x92c58bb7), + SPH_C32(0xa5147518), SPH_C32(0x56043d5f), SPH_C32(0xbcc47640), + SPH_C32(0x366d0000), SPH_C32(0x99d70000), SPH_C32(0x48ec0000), + SPH_C32(0xdd0d07e4), SPH_C32(0xa81e4330), SPH_C32(0x781eb8dd), + SPH_C32(0x7f5524ee) }, + { SPH_C32(0xe1d7d800), SPH_C32(0x3ed90000), SPH_C32(0xa5cc0000), + SPH_C32(0x8ea50000), SPH_C32(0xe4466aba), SPH_C32(0x23732650), + SPH_C32(0xdb56301e), SPH_C32(0xa0dc676f), SPH_C32(0x12455000), + SPH_C32(0xe28f0000), SPH_C32(0x188b0000), SPH_C32(0x1b180000), + SPH_C32(0xd9301e32), SPH_C32(0xd0baef72), SPH_C32(0x4a3a8ff2), + SPH_C32(0xea373c60) }, + { SPH_C32(0x28bcd830), SPH_C32(0xd9fc0000), SPH_C32(0x8a480000), + SPH_C32(0xa8ea0000), SPH_C32(0xec2f3143), SPH_C32(0x4e8fd767), + SPH_C32(0x8bc9599a), SPH_C32(0x3eb5c807), SPH_C32(0x34255240), + SPH_C32(0x3f570000), SPH_C32(0x6aa10000), SPH_C32(0x541e0000), + SPH_C32(0x4a5679cd), SPH_C32(0xf943abbc), SPH_C32(0x7cb1ec27), + SPH_C32(0xe611ce02) }, + { SPH_C32(0xf58de400), SPH_C32(0x87300000), SPH_C32(0xc4eb0000), + SPH_C32(0x7fc40000), SPH_C32(0x2a2757d6), SPH_C32(0x933a1b28), + SPH_C32(0x9cff573e), SPH_C32(0x415243aa), SPH_C32(0x31224400), + SPH_C32(0x2a360000), SPH_C32(0xec4c0000), SPH_C32(0xe06d0000), + SPH_C32(0xaafd3a57), SPH_C32(0x281c4a3b), SPH_C32(0x48fe85cd), + SPH_C32(0x3613da7f) }, + { SPH_C32(0x3ce6e430), SPH_C32(0x60150000), SPH_C32(0xeb6f0000), + SPH_C32(0x598b0000), SPH_C32(0x224e0c2f), SPH_C32(0xfec6ea1f), + SPH_C32(0xcc603eba), SPH_C32(0xdf3becc2), SPH_C32(0x17424640), + SPH_C32(0xf7ee0000), SPH_C32(0x9e660000), SPH_C32(0xaf6b0000), + SPH_C32(0x399b5da8), SPH_C32(0x01e50ef5), SPH_C32(0x7e75e618), + SPH_C32(0x3a35281d) }, + { SPH_C32(0xc2b0cc00), SPH_C32(0xf6600000), SPH_C32(0x510b0000), + SPH_C32(0x75d00000), SPH_C32(0x978b4edf), SPH_C32(0xdbd58319), + SPH_C32(0xd9923a21), SPH_C32(0x7cf88170), SPH_C32(0x25787800), + SPH_C32(0x93df0000), SPH_C32(0x8d6b0000), SPH_C32(0x110c0000), + SPH_C32(0x649c073b), SPH_C32(0x98557743), SPH_C32(0x0f57e2ed), + SPH_C32(0xd79dfeba) }, + { SPH_C32(0x0bdbcc30), SPH_C32(0x11450000), SPH_C32(0x7e8f0000), + SPH_C32(0x539f0000), SPH_C32(0x9fe21526), SPH_C32(0xb629722e), + SPH_C32(0x890d53a5), SPH_C32(0xe2912e18), SPH_C32(0x03187a40), + SPH_C32(0x4e070000), SPH_C32(0xff410000), SPH_C32(0x5e0a0000), + SPH_C32(0xf7fa60c4), SPH_C32(0xb1ac338d), SPH_C32(0x39dc8138), + SPH_C32(0xdbbb0cd8) }, + { SPH_C32(0xd6eaf000), SPH_C32(0x4f890000), SPH_C32(0x302c0000), + SPH_C32(0x84b10000), SPH_C32(0x59ea73b3), SPH_C32(0x6b9cbe61), + SPH_C32(0x9e3b5d01), SPH_C32(0x9d76a5b5), SPH_C32(0x061f6c00), + SPH_C32(0x5b660000), SPH_C32(0x79ac0000), SPH_C32(0xea790000), + SPH_C32(0x1751235e), SPH_C32(0x60f3d20a), SPH_C32(0x0d93e8d2), + SPH_C32(0x0bb918a5) }, + { SPH_C32(0x1f81f030), SPH_C32(0xa8ac0000), SPH_C32(0x1fa80000), + SPH_C32(0xa2fe0000), SPH_C32(0x5183284a), SPH_C32(0x06604f56), + SPH_C32(0xcea43485), SPH_C32(0x031f0add), SPH_C32(0x207f6e40), + SPH_C32(0x86be0000), SPH_C32(0x0b860000), SPH_C32(0xa57f0000), + SPH_C32(0x843744a1), SPH_C32(0x490a96c4), SPH_C32(0x3b188b07), + SPH_C32(0x079feac7) }, + { SPH_C32(0x466d0c00), SPH_C32(0x08620000), SPH_C32(0xdd5d0000), + SPH_C32(0xbadd0000), SPH_C32(0x6a927942), SPH_C32(0x441f2b93), + SPH_C32(0x218ace6f), SPH_C32(0xbf2c0be2), SPH_C32(0x6f299000), + SPH_C32(0x6c850000), SPH_C32(0x2f160000), SPH_C32(0x782e0000), + SPH_C32(0x644c37cd), SPH_C32(0x12dd1cd6), SPH_C32(0xd26a8c36), + SPH_C32(0x32219526) }, + { SPH_C32(0x8f060c30), SPH_C32(0xef470000), SPH_C32(0xf2d90000), + SPH_C32(0x9c920000), SPH_C32(0x62fb22bb), SPH_C32(0x29e3daa4), + SPH_C32(0x7115a7eb), SPH_C32(0x2145a48a), SPH_C32(0x49499240), + SPH_C32(0xb15d0000), SPH_C32(0x5d3c0000), SPH_C32(0x37280000), + SPH_C32(0xf72a5032), SPH_C32(0x3b245818), SPH_C32(0xe4e1efe3), + SPH_C32(0x3e076744) }, + { SPH_C32(0x52373000), SPH_C32(0xb18b0000), SPH_C32(0xbc7a0000), + SPH_C32(0x4bbc0000), SPH_C32(0xa4f3442e), SPH_C32(0xf45616eb), + SPH_C32(0x6623a94f), SPH_C32(0x5ea22f27), SPH_C32(0x4c4e8400), + SPH_C32(0xa43c0000), SPH_C32(0xdbd10000), SPH_C32(0x835b0000), + SPH_C32(0x178113a8), SPH_C32(0xea7bb99f), SPH_C32(0xd0ae8609), + SPH_C32(0xee057339) }, + { SPH_C32(0x9b5c3030), SPH_C32(0x56ae0000), SPH_C32(0x93fe0000), + SPH_C32(0x6df30000), SPH_C32(0xac9a1fd7), SPH_C32(0x99aae7dc), + SPH_C32(0x36bcc0cb), SPH_C32(0xc0cb804f), SPH_C32(0x6a2e8640), + SPH_C32(0x79e40000), SPH_C32(0xa9fb0000), SPH_C32(0xcc5d0000), + SPH_C32(0x84e77457), SPH_C32(0xc382fd51), SPH_C32(0xe625e5dc), + SPH_C32(0xe223815b) }, + { SPH_C32(0x650a1800), SPH_C32(0xc0db0000), SPH_C32(0x299a0000), + SPH_C32(0x41a80000), SPH_C32(0x195f5d27), SPH_C32(0xbcb98eda), + SPH_C32(0x234ec450), SPH_C32(0x6308edfd), SPH_C32(0x5814b800), + SPH_C32(0x1dd50000), SPH_C32(0xbaf60000), SPH_C32(0x723a0000), + SPH_C32(0xd9e02ec4), SPH_C32(0x5a3284e7), SPH_C32(0x9707e129), + SPH_C32(0x0f8b57fc) }, + { SPH_C32(0xac611830), SPH_C32(0x27fe0000), SPH_C32(0x061e0000), + SPH_C32(0x67e70000), SPH_C32(0x113606de), SPH_C32(0xd1457fed), + SPH_C32(0x73d1add4), SPH_C32(0xfd614295), SPH_C32(0x7e74ba40), + SPH_C32(0xc00d0000), SPH_C32(0xc8dc0000), SPH_C32(0x3d3c0000), + SPH_C32(0x4a86493b), SPH_C32(0x73cbc029), SPH_C32(0xa18c82fc), + SPH_C32(0x03ada59e) }, + { SPH_C32(0x71502400), SPH_C32(0x79320000), SPH_C32(0x48bd0000), + SPH_C32(0xb0c90000), SPH_C32(0xd73e604b), SPH_C32(0x0cf0b3a2), + SPH_C32(0x64e7a370), SPH_C32(0x8286c938), SPH_C32(0x7b73ac00), + SPH_C32(0xd56c0000), SPH_C32(0x4e310000), SPH_C32(0x894f0000), + SPH_C32(0xaa2d0aa1), SPH_C32(0xa29421ae), SPH_C32(0x95c3eb16), + SPH_C32(0xd3afb1e3) }, + { SPH_C32(0xb83b2430), SPH_C32(0x9e170000), SPH_C32(0x67390000), + SPH_C32(0x96860000), SPH_C32(0xdf573bb2), SPH_C32(0x610c4295), + SPH_C32(0x3478caf4), SPH_C32(0x1cef6650), SPH_C32(0x5d13ae40), + SPH_C32(0x08b40000), SPH_C32(0x3c1b0000), SPH_C32(0xc6490000), + SPH_C32(0x394b6d5e), SPH_C32(0x8b6d6560), SPH_C32(0xa34888c3), + SPH_C32(0xdf894381) }, + { SPH_C32(0x12455000), SPH_C32(0xe28f0000), SPH_C32(0x188b0000), + SPH_C32(0x1b180000), SPH_C32(0xd9301e32), SPH_C32(0xd0baef72), + SPH_C32(0x4a3a8ff2), SPH_C32(0xea373c60), SPH_C32(0xf3928800), + SPH_C32(0xdc560000), SPH_C32(0xbd470000), SPH_C32(0x95bd0000), + SPH_C32(0x3d767488), SPH_C32(0xf3c9c922), SPH_C32(0x916cbfec), + SPH_C32(0x4aeb5b0f) }, + { SPH_C32(0xdb2e5030), SPH_C32(0x05aa0000), SPH_C32(0x370f0000), + SPH_C32(0x3d570000), SPH_C32(0xd15945cb), SPH_C32(0xbd461e45), + SPH_C32(0x1aa5e676), SPH_C32(0x745e9308), SPH_C32(0xd5f28a40), + SPH_C32(0x018e0000), SPH_C32(0xcf6d0000), SPH_C32(0xdabb0000), + SPH_C32(0xae101377), SPH_C32(0xda308dec), SPH_C32(0xa7e7dc39), + SPH_C32(0x46cda96d) }, + { SPH_C32(0x061f6c00), SPH_C32(0x5b660000), SPH_C32(0x79ac0000), + SPH_C32(0xea790000), SPH_C32(0x1751235e), SPH_C32(0x60f3d20a), + SPH_C32(0x0d93e8d2), SPH_C32(0x0bb918a5), SPH_C32(0xd0f59c00), + SPH_C32(0x14ef0000), SPH_C32(0x49800000), SPH_C32(0x6ec80000), + SPH_C32(0x4ebb50ed), SPH_C32(0x0b6f6c6b), SPH_C32(0x93a8b5d3), + SPH_C32(0x96cfbd10) }, + { SPH_C32(0xcf746c30), SPH_C32(0xbc430000), SPH_C32(0x56280000), + SPH_C32(0xcc360000), SPH_C32(0x1f3878a7), SPH_C32(0x0d0f233d), + SPH_C32(0x5d0c8156), SPH_C32(0x95d0b7cd), SPH_C32(0xf6959e40), + SPH_C32(0xc9370000), SPH_C32(0x3baa0000), SPH_C32(0x21ce0000), + SPH_C32(0xdddd3712), SPH_C32(0x229628a5), SPH_C32(0xa523d606), + SPH_C32(0x9ae94f72) }, + { SPH_C32(0x31224400), SPH_C32(0x2a360000), SPH_C32(0xec4c0000), + SPH_C32(0xe06d0000), SPH_C32(0xaafd3a57), SPH_C32(0x281c4a3b), + SPH_C32(0x48fe85cd), SPH_C32(0x3613da7f), SPH_C32(0xc4afa000), + SPH_C32(0xad060000), SPH_C32(0x28a70000), SPH_C32(0x9fa90000), + SPH_C32(0x80da6d81), SPH_C32(0xbb265113), SPH_C32(0xd401d2f3), + SPH_C32(0x774199d5) }, + { SPH_C32(0xf8494430), SPH_C32(0xcd130000), SPH_C32(0xc3c80000), + SPH_C32(0xc6220000), SPH_C32(0xa29461ae), SPH_C32(0x45e0bb0c), + SPH_C32(0x1861ec49), SPH_C32(0xa87a7517), SPH_C32(0xe2cfa240), + SPH_C32(0x70de0000), SPH_C32(0x5a8d0000), SPH_C32(0xd0af0000), + SPH_C32(0x13bc0a7e), SPH_C32(0x92df15dd), SPH_C32(0xe28ab126), + SPH_C32(0x7b676bb7) }, + { SPH_C32(0x25787800), SPH_C32(0x93df0000), SPH_C32(0x8d6b0000), + SPH_C32(0x110c0000), SPH_C32(0x649c073b), SPH_C32(0x98557743), + SPH_C32(0x0f57e2ed), SPH_C32(0xd79dfeba), SPH_C32(0xe7c8b400), + SPH_C32(0x65bf0000), SPH_C32(0xdc600000), SPH_C32(0x64dc0000), + SPH_C32(0xf31749e4), SPH_C32(0x4380f45a), SPH_C32(0xd6c5d8cc), + SPH_C32(0xab657fca) }, + { SPH_C32(0xec137830), SPH_C32(0x74fa0000), SPH_C32(0xa2ef0000), + SPH_C32(0x37430000), SPH_C32(0x6cf55cc2), SPH_C32(0xf5a98674), + SPH_C32(0x5fc88b69), SPH_C32(0x49f451d2), SPH_C32(0xc1a8b640), + SPH_C32(0xb8670000), SPH_C32(0xae4a0000), SPH_C32(0x2bda0000), + SPH_C32(0x60712e1b), SPH_C32(0x6a79b094), SPH_C32(0xe04ebb19), + SPH_C32(0xa7438da8) }, + { SPH_C32(0xdad61400), SPH_C32(0xb8b10000), SPH_C32(0x4f0c0000), + SPH_C32(0x574e0000), SPH_C32(0x33a83a07), SPH_C32(0xa50bfe67), + SPH_C32(0x628cfdb5), SPH_C32(0xc7e6c5cb), SPH_C32(0xa7bad400), + SPH_C32(0x36bb0000), SPH_C32(0x78910000), SPH_C32(0x34780000), + SPH_C32(0x8ed413f8), SPH_C32(0x676c0dc3), SPH_C32(0xfadcfe71), + SPH_C32(0x1ff06c8d) }, + { SPH_C32(0x13bd1430), SPH_C32(0x5f940000), SPH_C32(0x60880000), + SPH_C32(0x71010000), SPH_C32(0x3bc161fe), SPH_C32(0xc8f70f50), + SPH_C32(0x32139431), SPH_C32(0x598f6aa3), SPH_C32(0x81dad640), + SPH_C32(0xeb630000), SPH_C32(0x0abb0000), SPH_C32(0x7b7e0000), + SPH_C32(0x1db27407), SPH_C32(0x4e95490d), SPH_C32(0xcc579da4), + SPH_C32(0x13d69eef) }, + { SPH_C32(0xce8c2800), SPH_C32(0x01580000), SPH_C32(0x2e2b0000), + SPH_C32(0xa62f0000), SPH_C32(0xfdc9076b), SPH_C32(0x1542c31f), + SPH_C32(0x25259a95), SPH_C32(0x2668e10e), SPH_C32(0x84ddc000), + SPH_C32(0xfe020000), SPH_C32(0x8c560000), SPH_C32(0xcf0d0000), + SPH_C32(0xfd19379d), SPH_C32(0x9fcaa88a), SPH_C32(0xf818f44e), + SPH_C32(0xc3d48a92) }, + { SPH_C32(0x07e72830), SPH_C32(0xe67d0000), SPH_C32(0x01af0000), + SPH_C32(0x80600000), SPH_C32(0xf5a05c92), SPH_C32(0x78be3228), + SPH_C32(0x75baf311), SPH_C32(0xb8014e66), SPH_C32(0xa2bdc240), + SPH_C32(0x23da0000), SPH_C32(0xfe7c0000), SPH_C32(0x800b0000), + SPH_C32(0x6e7f5062), SPH_C32(0xb633ec44), SPH_C32(0xce93979b), + SPH_C32(0xcff278f0) }, + { SPH_C32(0xf9b10000), SPH_C32(0x70080000), SPH_C32(0xbbcb0000), + SPH_C32(0xac3b0000), SPH_C32(0x40651e62), SPH_C32(0x5dad5b2e), + SPH_C32(0x6048f78a), SPH_C32(0x1bc223d4), SPH_C32(0x9087fc00), + SPH_C32(0x47eb0000), SPH_C32(0xed710000), SPH_C32(0x3e6c0000), + SPH_C32(0x33780af1), SPH_C32(0x2f8395f2), SPH_C32(0xbfb1936e), + SPH_C32(0x225aae57) }, + { SPH_C32(0x30da0030), SPH_C32(0x972d0000), SPH_C32(0x944f0000), + SPH_C32(0x8a740000), SPH_C32(0x480c459b), SPH_C32(0x3051aa19), + SPH_C32(0x30d79e0e), SPH_C32(0x85ab8cbc), SPH_C32(0xb6e7fe40), + SPH_C32(0x9a330000), SPH_C32(0x9f5b0000), SPH_C32(0x716a0000), + SPH_C32(0xa01e6d0e), SPH_C32(0x067ad13c), SPH_C32(0x893af0bb), + SPH_C32(0x2e7c5c35) }, + { SPH_C32(0xedeb3c00), SPH_C32(0xc9e10000), SPH_C32(0xdaec0000), + SPH_C32(0x5d5a0000), SPH_C32(0x8e04230e), SPH_C32(0xede46656), + SPH_C32(0x27e190aa), SPH_C32(0xfa4c0711), SPH_C32(0xb3e0e800), + SPH_C32(0x8f520000), SPH_C32(0x19b60000), SPH_C32(0xc5190000), + SPH_C32(0x40b52e94), SPH_C32(0xd72530bb), SPH_C32(0xbd759951), + SPH_C32(0xfe7e4848) }, + { SPH_C32(0x24803c30), SPH_C32(0x2ec40000), SPH_C32(0xf5680000), + SPH_C32(0x7b150000), SPH_C32(0x866d78f7), SPH_C32(0x80189761), + SPH_C32(0x777ef92e), SPH_C32(0x6425a879), SPH_C32(0x9580ea40), + SPH_C32(0x528a0000), SPH_C32(0x6b9c0000), SPH_C32(0x8a1f0000), + SPH_C32(0xd3d3496b), SPH_C32(0xfedc7475), SPH_C32(0x8bfefa84), + SPH_C32(0xf258ba2a) }, + { SPH_C32(0x8efe4800), SPH_C32(0x525c0000), SPH_C32(0x8ada0000), + SPH_C32(0xf68b0000), SPH_C32(0x800a5d77), SPH_C32(0x31ae3a86), + SPH_C32(0x093cbc28), SPH_C32(0x92fdf249), SPH_C32(0x3b01cc00), + SPH_C32(0x86680000), SPH_C32(0xeac00000), SPH_C32(0xd9eb0000), + SPH_C32(0xd7ee50bd), SPH_C32(0x8678d837), SPH_C32(0xb9dacdab), + SPH_C32(0x673aa2a4) }, + { SPH_C32(0x47954830), SPH_C32(0xb5790000), SPH_C32(0xa55e0000), + SPH_C32(0xd0c40000), SPH_C32(0x8863068e), SPH_C32(0x5c52cbb1), + SPH_C32(0x59a3d5ac), SPH_C32(0x0c945d21), SPH_C32(0x1d61ce40), + SPH_C32(0x5bb00000), SPH_C32(0x98ea0000), SPH_C32(0x96ed0000), + SPH_C32(0x44883742), SPH_C32(0xaf819cf9), SPH_C32(0x8f51ae7e), + SPH_C32(0x6b1c50c6) }, + { SPH_C32(0x9aa47400), SPH_C32(0xebb50000), SPH_C32(0xebfd0000), + SPH_C32(0x07ea0000), SPH_C32(0x4e6b601b), SPH_C32(0x81e707fe), + SPH_C32(0x4e95db08), SPH_C32(0x7373d68c), SPH_C32(0x1866d800), + SPH_C32(0x4ed10000), SPH_C32(0x1e070000), SPH_C32(0x229e0000), + SPH_C32(0xa42374d8), SPH_C32(0x7ede7d7e), SPH_C32(0xbb1ec794), + SPH_C32(0xbb1e44bb) }, + { SPH_C32(0x53cf7430), SPH_C32(0x0c900000), SPH_C32(0xc4790000), + SPH_C32(0x21a50000), SPH_C32(0x46023be2), SPH_C32(0xec1bf6c9), + SPH_C32(0x1e0ab28c), SPH_C32(0xed1a79e4), SPH_C32(0x3e06da40), + SPH_C32(0x93090000), SPH_C32(0x6c2d0000), SPH_C32(0x6d980000), + SPH_C32(0x37451327), SPH_C32(0x572739b0), SPH_C32(0x8d95a441), + SPH_C32(0xb738b6d9) }, + { SPH_C32(0xad995c00), SPH_C32(0x9ae50000), SPH_C32(0x7e1d0000), + SPH_C32(0x0dfe0000), SPH_C32(0xf3c77912), SPH_C32(0xc9089fcf), + SPH_C32(0x0bf8b617), SPH_C32(0x4ed91456), SPH_C32(0x0c3ce400), + SPH_C32(0xf7380000), SPH_C32(0x7f200000), SPH_C32(0xd3ff0000), + SPH_C32(0x6a4249b4), SPH_C32(0xce974006), SPH_C32(0xfcb7a0b4), + SPH_C32(0x5a90607e) }, + { SPH_C32(0x64f25c30), SPH_C32(0x7dc00000), SPH_C32(0x51990000), + SPH_C32(0x2bb10000), SPH_C32(0xfbae22eb), SPH_C32(0xa4f46ef8), + SPH_C32(0x5b67df93), SPH_C32(0xd0b0bb3e), SPH_C32(0x2a5ce640), + SPH_C32(0x2ae00000), SPH_C32(0x0d0a0000), SPH_C32(0x9cf90000), + SPH_C32(0xf9242e4b), SPH_C32(0xe76e04c8), SPH_C32(0xca3cc361), + SPH_C32(0x56b6921c) }, + { SPH_C32(0xb9c36000), SPH_C32(0x230c0000), SPH_C32(0x1f3a0000), + SPH_C32(0xfc9f0000), SPH_C32(0x3da6447e), SPH_C32(0x7941a2b7), + SPH_C32(0x4c51d137), SPH_C32(0xaf573093), SPH_C32(0x2f5bf000), + SPH_C32(0x3f810000), SPH_C32(0x8be70000), SPH_C32(0x288a0000), + SPH_C32(0x198f6dd1), SPH_C32(0x3631e54f), SPH_C32(0xfe73aa8b), + SPH_C32(0x86b48661) }, + { SPH_C32(0x70a86030), SPH_C32(0xc4290000), SPH_C32(0x30be0000), + SPH_C32(0xdad00000), SPH_C32(0x35cf1f87), SPH_C32(0x14bd5380), + SPH_C32(0x1cceb8b3), SPH_C32(0x313e9ffb), SPH_C32(0x093bf240), + SPH_C32(0xe2590000), SPH_C32(0xf9cd0000), SPH_C32(0x678c0000), + SPH_C32(0x8ae90a2e), SPH_C32(0x1fc8a181), SPH_C32(0xc8f8c95e), + SPH_C32(0x8a927403) }, + { SPH_C32(0x6f299000), SPH_C32(0x6c850000), SPH_C32(0x2f160000), + SPH_C32(0x782e0000), SPH_C32(0x644c37cd), SPH_C32(0x12dd1cd6), + SPH_C32(0xd26a8c36), SPH_C32(0x32219526), SPH_C32(0x29449c00), + SPH_C32(0x64e70000), SPH_C32(0xf24b0000), SPH_C32(0xc2f30000), + SPH_C32(0x0ede4e8f), SPH_C32(0x56c23745), SPH_C32(0xf3e04259), + SPH_C32(0x8d0d9ec4) }, + { SPH_C32(0xa6429030), SPH_C32(0x8ba00000), SPH_C32(0x00920000), + SPH_C32(0x5e610000), SPH_C32(0x6c256c34), SPH_C32(0x7f21ede1), + SPH_C32(0x82f5e5b2), SPH_C32(0xac483a4e), SPH_C32(0x0f249e40), + SPH_C32(0xb93f0000), SPH_C32(0x80610000), SPH_C32(0x8df50000), + SPH_C32(0x9db82970), SPH_C32(0x7f3b738b), SPH_C32(0xc56b218c), + SPH_C32(0x812b6ca6) }, + { SPH_C32(0x7b73ac00), SPH_C32(0xd56c0000), SPH_C32(0x4e310000), + SPH_C32(0x894f0000), SPH_C32(0xaa2d0aa1), SPH_C32(0xa29421ae), + SPH_C32(0x95c3eb16), SPH_C32(0xd3afb1e3), SPH_C32(0x0a238800), + SPH_C32(0xac5e0000), SPH_C32(0x068c0000), SPH_C32(0x39860000), + SPH_C32(0x7d136aea), SPH_C32(0xae64920c), SPH_C32(0xf1244866), + SPH_C32(0x512978db) }, + { SPH_C32(0xb218ac30), SPH_C32(0x32490000), SPH_C32(0x61b50000), + SPH_C32(0xaf000000), SPH_C32(0xa2445158), SPH_C32(0xcf68d099), + SPH_C32(0xc55c8292), SPH_C32(0x4dc61e8b), SPH_C32(0x2c438a40), + SPH_C32(0x71860000), SPH_C32(0x74a60000), SPH_C32(0x76800000), + SPH_C32(0xee750d15), SPH_C32(0x879dd6c2), SPH_C32(0xc7af2bb3), + SPH_C32(0x5d0f8ab9) }, + { SPH_C32(0x4c4e8400), SPH_C32(0xa43c0000), SPH_C32(0xdbd10000), + SPH_C32(0x835b0000), SPH_C32(0x178113a8), SPH_C32(0xea7bb99f), + SPH_C32(0xd0ae8609), SPH_C32(0xee057339), SPH_C32(0x1e79b400), + SPH_C32(0x15b70000), SPH_C32(0x67ab0000), SPH_C32(0xc8e70000), + SPH_C32(0xb3725786), SPH_C32(0x1e2daf74), SPH_C32(0xb68d2f46), + SPH_C32(0xb0a75c1e) }, + { SPH_C32(0x85258430), SPH_C32(0x43190000), SPH_C32(0xf4550000), + SPH_C32(0xa5140000), SPH_C32(0x1fe84851), SPH_C32(0x878748a8), + SPH_C32(0x8031ef8d), SPH_C32(0x706cdc51), SPH_C32(0x3819b640), + SPH_C32(0xc86f0000), SPH_C32(0x15810000), SPH_C32(0x87e10000), + SPH_C32(0x20143079), SPH_C32(0x37d4ebba), SPH_C32(0x80064c93), + SPH_C32(0xbc81ae7c) }, + { SPH_C32(0x5814b800), SPH_C32(0x1dd50000), SPH_C32(0xbaf60000), + SPH_C32(0x723a0000), SPH_C32(0xd9e02ec4), SPH_C32(0x5a3284e7), + SPH_C32(0x9707e129), SPH_C32(0x0f8b57fc), SPH_C32(0x3d1ea000), + SPH_C32(0xdd0e0000), SPH_C32(0x936c0000), SPH_C32(0x33920000), + SPH_C32(0xc0bf73e3), SPH_C32(0xe68b0a3d), SPH_C32(0xb4492579), + SPH_C32(0x6c83ba01) }, + { SPH_C32(0x917fb830), SPH_C32(0xfaf00000), SPH_C32(0x95720000), + SPH_C32(0x54750000), SPH_C32(0xd189753d), SPH_C32(0x37ce75d0), + SPH_C32(0xc79888ad), SPH_C32(0x91e2f894), SPH_C32(0x1b7ea240), + SPH_C32(0x00d60000), SPH_C32(0xe1460000), SPH_C32(0x7c940000), + SPH_C32(0x53d9141c), SPH_C32(0xcf724ef3), SPH_C32(0x82c246ac), + SPH_C32(0x60a54863) }, + { SPH_C32(0x3b01cc00), SPH_C32(0x86680000), SPH_C32(0xeac00000), + SPH_C32(0xd9eb0000), SPH_C32(0xd7ee50bd), SPH_C32(0x8678d837), + SPH_C32(0xb9dacdab), SPH_C32(0x673aa2a4), SPH_C32(0xb5ff8400), + SPH_C32(0xd4340000), SPH_C32(0x601a0000), SPH_C32(0x2f600000), + SPH_C32(0x57e40dca), SPH_C32(0xb7d6e2b1), SPH_C32(0xb0e67183), + SPH_C32(0xf5c750ed) }, + { SPH_C32(0xf26acc30), SPH_C32(0x614d0000), SPH_C32(0xc5440000), + SPH_C32(0xffa40000), SPH_C32(0xdf870b44), SPH_C32(0xeb842900), + SPH_C32(0xe945a42f), SPH_C32(0xf9530dcc), SPH_C32(0x939f8640), + SPH_C32(0x09ec0000), SPH_C32(0x12300000), SPH_C32(0x60660000), + SPH_C32(0xc4826a35), SPH_C32(0x9e2fa67f), SPH_C32(0x866d1256), + SPH_C32(0xf9e1a28f) }, + { SPH_C32(0x2f5bf000), SPH_C32(0x3f810000), SPH_C32(0x8be70000), + SPH_C32(0x288a0000), SPH_C32(0x198f6dd1), SPH_C32(0x3631e54f), + SPH_C32(0xfe73aa8b), SPH_C32(0x86b48661), SPH_C32(0x96989000), + SPH_C32(0x1c8d0000), SPH_C32(0x94dd0000), SPH_C32(0xd4150000), + SPH_C32(0x242929af), SPH_C32(0x4f7047f8), SPH_C32(0xb2227bbc), + SPH_C32(0x29e3b6f2) }, + { SPH_C32(0xe630f030), SPH_C32(0xd8a40000), SPH_C32(0xa4630000), + SPH_C32(0x0ec50000), SPH_C32(0x11e63628), SPH_C32(0x5bcd1478), + SPH_C32(0xaeecc30f), SPH_C32(0x18dd2909), SPH_C32(0xb0f89240), + SPH_C32(0xc1550000), SPH_C32(0xe6f70000), SPH_C32(0x9b130000), + SPH_C32(0xb74f4e50), SPH_C32(0x66890336), SPH_C32(0x84a91869), + SPH_C32(0x25c54490) }, + { SPH_C32(0x1866d800), SPH_C32(0x4ed10000), SPH_C32(0x1e070000), + SPH_C32(0x229e0000), SPH_C32(0xa42374d8), SPH_C32(0x7ede7d7e), + SPH_C32(0xbb1ec794), SPH_C32(0xbb1e44bb), SPH_C32(0x82c2ac00), + SPH_C32(0xa5640000), SPH_C32(0xf5fa0000), SPH_C32(0x25740000), + SPH_C32(0xea4814c3), SPH_C32(0xff397a80), SPH_C32(0xf58b1c9c), + SPH_C32(0xc86d9237) }, + { SPH_C32(0xd10dd830), SPH_C32(0xa9f40000), SPH_C32(0x31830000), + SPH_C32(0x04d10000), SPH_C32(0xac4a2f21), SPH_C32(0x13228c49), + SPH_C32(0xeb81ae10), SPH_C32(0x2577ebd3), SPH_C32(0xa4a2ae40), + SPH_C32(0x78bc0000), SPH_C32(0x87d00000), SPH_C32(0x6a720000), + SPH_C32(0x792e733c), SPH_C32(0xd6c03e4e), SPH_C32(0xc3007f49), + SPH_C32(0xc44b6055) }, + { SPH_C32(0x0c3ce400), SPH_C32(0xf7380000), SPH_C32(0x7f200000), + SPH_C32(0xd3ff0000), SPH_C32(0x6a4249b4), SPH_C32(0xce974006), + SPH_C32(0xfcb7a0b4), SPH_C32(0x5a90607e), SPH_C32(0xa1a5b800), + SPH_C32(0x6ddd0000), SPH_C32(0x013d0000), SPH_C32(0xde010000), + SPH_C32(0x998530a6), SPH_C32(0x079fdfc9), SPH_C32(0xf74f16a3), + SPH_C32(0x14497428) }, + { SPH_C32(0xc557e430), SPH_C32(0x101d0000), SPH_C32(0x50a40000), + SPH_C32(0xf5b00000), SPH_C32(0x622b124d), SPH_C32(0xa36bb131), + SPH_C32(0xac28c930), SPH_C32(0xc4f9cf16), SPH_C32(0x87c5ba40), + SPH_C32(0xb0050000), SPH_C32(0x73170000), SPH_C32(0x91070000), + SPH_C32(0x0ae35759), SPH_C32(0x2e669b07), SPH_C32(0xc1c47576), + SPH_C32(0x186f864a) }, + { SPH_C32(0xf3928800), SPH_C32(0xdc560000), SPH_C32(0xbd470000), + SPH_C32(0x95bd0000), SPH_C32(0x3d767488), SPH_C32(0xf3c9c922), + SPH_C32(0x916cbfec), SPH_C32(0x4aeb5b0f), SPH_C32(0xe1d7d800), + SPH_C32(0x3ed90000), SPH_C32(0xa5cc0000), SPH_C32(0x8ea50000), + SPH_C32(0xe4466aba), SPH_C32(0x23732650), SPH_C32(0xdb56301e), + SPH_C32(0xa0dc676f) }, + { SPH_C32(0x3af98830), SPH_C32(0x3b730000), SPH_C32(0x92c30000), + SPH_C32(0xb3f20000), SPH_C32(0x351f2f71), SPH_C32(0x9e353815), + SPH_C32(0xc1f3d668), SPH_C32(0xd482f467), SPH_C32(0xc7b7da40), + SPH_C32(0xe3010000), SPH_C32(0xd7e60000), SPH_C32(0xc1a30000), + SPH_C32(0x77200d45), SPH_C32(0x0a8a629e), SPH_C32(0xeddd53cb), + SPH_C32(0xacfa950d) }, + { SPH_C32(0xe7c8b400), SPH_C32(0x65bf0000), SPH_C32(0xdc600000), + SPH_C32(0x64dc0000), SPH_C32(0xf31749e4), SPH_C32(0x4380f45a), + SPH_C32(0xd6c5d8cc), SPH_C32(0xab657fca), SPH_C32(0xc2b0cc00), + SPH_C32(0xf6600000), SPH_C32(0x510b0000), SPH_C32(0x75d00000), + SPH_C32(0x978b4edf), SPH_C32(0xdbd58319), SPH_C32(0xd9923a21), + SPH_C32(0x7cf88170) }, + { SPH_C32(0x2ea3b430), SPH_C32(0x829a0000), SPH_C32(0xf3e40000), + SPH_C32(0x42930000), SPH_C32(0xfb7e121d), SPH_C32(0x2e7c056d), + SPH_C32(0x865ab148), SPH_C32(0x350cd0a2), SPH_C32(0xe4d0ce40), + SPH_C32(0x2bb80000), SPH_C32(0x23210000), SPH_C32(0x3ad60000), + SPH_C32(0x04ed2920), SPH_C32(0xf22cc7d7), SPH_C32(0xef1959f4), + SPH_C32(0x70de7312) }, + { SPH_C32(0xd0f59c00), SPH_C32(0x14ef0000), SPH_C32(0x49800000), + SPH_C32(0x6ec80000), SPH_C32(0x4ebb50ed), SPH_C32(0x0b6f6c6b), + SPH_C32(0x93a8b5d3), SPH_C32(0x96cfbd10), SPH_C32(0xd6eaf000), + SPH_C32(0x4f890000), SPH_C32(0x302c0000), SPH_C32(0x84b10000), + SPH_C32(0x59ea73b3), SPH_C32(0x6b9cbe61), SPH_C32(0x9e3b5d01), + SPH_C32(0x9d76a5b5) }, + { SPH_C32(0x199e9c30), SPH_C32(0xf3ca0000), SPH_C32(0x66040000), + SPH_C32(0x48870000), SPH_C32(0x46d20b14), SPH_C32(0x66939d5c), + SPH_C32(0xc337dc57), SPH_C32(0x08a61278), SPH_C32(0xf08af240), + SPH_C32(0x92510000), SPH_C32(0x42060000), SPH_C32(0xcbb70000), + SPH_C32(0xca8c144c), SPH_C32(0x4265faaf), SPH_C32(0xa8b03ed4), + SPH_C32(0x915057d7) }, + { SPH_C32(0xc4afa000), SPH_C32(0xad060000), SPH_C32(0x28a70000), + SPH_C32(0x9fa90000), SPH_C32(0x80da6d81), SPH_C32(0xbb265113), + SPH_C32(0xd401d2f3), SPH_C32(0x774199d5), SPH_C32(0xf58de400), + SPH_C32(0x87300000), SPH_C32(0xc4eb0000), SPH_C32(0x7fc40000), + SPH_C32(0x2a2757d6), SPH_C32(0x933a1b28), SPH_C32(0x9cff573e), + SPH_C32(0x415243aa) }, + { SPH_C32(0x0dc4a030), SPH_C32(0x4a230000), SPH_C32(0x07230000), + SPH_C32(0xb9e60000), SPH_C32(0x88b33678), SPH_C32(0xd6daa024), + SPH_C32(0x849ebb77), SPH_C32(0xe92836bd), SPH_C32(0xd3ede640), + SPH_C32(0x5ae80000), SPH_C32(0xb6c10000), SPH_C32(0x30c20000), + SPH_C32(0xb9413029), SPH_C32(0xbac35fe6), SPH_C32(0xaa7434eb), + SPH_C32(0x4d74b1c8) }, + { SPH_C32(0xa7bad400), SPH_C32(0x36bb0000), SPH_C32(0x78910000), + SPH_C32(0x34780000), SPH_C32(0x8ed413f8), SPH_C32(0x676c0dc3), + SPH_C32(0xfadcfe71), SPH_C32(0x1ff06c8d), SPH_C32(0x7d6cc000), + SPH_C32(0x8e0a0000), SPH_C32(0x379d0000), SPH_C32(0x63360000), + SPH_C32(0xbd7c29ff), SPH_C32(0xc267f3a4), SPH_C32(0x985003c4), + SPH_C32(0xd816a946) }, + { SPH_C32(0x6ed1d430), SPH_C32(0xd19e0000), SPH_C32(0x57150000), + SPH_C32(0x12370000), SPH_C32(0x86bd4801), SPH_C32(0x0a90fcf4), + SPH_C32(0xaa4397f5), SPH_C32(0x8199c3e5), SPH_C32(0x5b0cc240), + SPH_C32(0x53d20000), SPH_C32(0x45b70000), SPH_C32(0x2c300000), + SPH_C32(0x2e1a4e00), SPH_C32(0xeb9eb76a), SPH_C32(0xaedb6011), + SPH_C32(0xd4305b24) }, + { SPH_C32(0xb3e0e800), SPH_C32(0x8f520000), SPH_C32(0x19b60000), + SPH_C32(0xc5190000), SPH_C32(0x40b52e94), SPH_C32(0xd72530bb), + SPH_C32(0xbd759951), SPH_C32(0xfe7e4848), SPH_C32(0x5e0bd400), + SPH_C32(0x46b30000), SPH_C32(0xc35a0000), SPH_C32(0x98430000), + SPH_C32(0xceb10d9a), SPH_C32(0x3ac156ed), SPH_C32(0x9a9409fb), + SPH_C32(0x04324f59) }, + { SPH_C32(0x7a8be830), SPH_C32(0x68770000), SPH_C32(0x36320000), + SPH_C32(0xe3560000), SPH_C32(0x48dc756d), SPH_C32(0xbad9c18c), + SPH_C32(0xedeaf0d5), SPH_C32(0x6017e720), SPH_C32(0x786bd640), + SPH_C32(0x9b6b0000), SPH_C32(0xb1700000), SPH_C32(0xd7450000), + SPH_C32(0x5dd76a65), SPH_C32(0x13381223), SPH_C32(0xac1f6a2e), + SPH_C32(0x0814bd3b) }, + { SPH_C32(0x84ddc000), SPH_C32(0xfe020000), SPH_C32(0x8c560000), + SPH_C32(0xcf0d0000), SPH_C32(0xfd19379d), SPH_C32(0x9fcaa88a), + SPH_C32(0xf818f44e), SPH_C32(0xc3d48a92), SPH_C32(0x4a51e800), + SPH_C32(0xff5a0000), SPH_C32(0xa27d0000), SPH_C32(0x69220000), + SPH_C32(0x00d030f6), SPH_C32(0x8a886b95), SPH_C32(0xdd3d6edb), + SPH_C32(0xe5bc6b9c) }, + { SPH_C32(0x4db6c030), SPH_C32(0x19270000), SPH_C32(0xa3d20000), + SPH_C32(0xe9420000), SPH_C32(0xf5706c64), SPH_C32(0xf23659bd), + SPH_C32(0xa8879dca), SPH_C32(0x5dbd25fa), SPH_C32(0x6c31ea40), + SPH_C32(0x22820000), SPH_C32(0xd0570000), SPH_C32(0x26240000), + SPH_C32(0x93b65709), SPH_C32(0xa3712f5b), SPH_C32(0xebb60d0e), + SPH_C32(0xe99a99fe) }, + { SPH_C32(0x9087fc00), SPH_C32(0x47eb0000), SPH_C32(0xed710000), + SPH_C32(0x3e6c0000), SPH_C32(0x33780af1), SPH_C32(0x2f8395f2), + SPH_C32(0xbfb1936e), SPH_C32(0x225aae57), SPH_C32(0x6936fc00), + SPH_C32(0x37e30000), SPH_C32(0x56ba0000), SPH_C32(0x92570000), + SPH_C32(0x731d1493), SPH_C32(0x722ecedc), SPH_C32(0xdff964e4), + SPH_C32(0x39988d83) }, + { SPH_C32(0x59ecfc30), SPH_C32(0xa0ce0000), SPH_C32(0xc2f50000), + SPH_C32(0x18230000), SPH_C32(0x3b115108), SPH_C32(0x427f64c5), + SPH_C32(0xef2efaea), SPH_C32(0xbc33013f), SPH_C32(0x4f56fe40), + SPH_C32(0xea3b0000), SPH_C32(0x24900000), SPH_C32(0xdd510000), + SPH_C32(0xe07b736c), SPH_C32(0x5bd78a12), SPH_C32(0xe9720731), + SPH_C32(0x35be7fe1) } +}; + +static const sph_u32 T512_7[128][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0xf7750009), SPH_C32(0xcf3cc000), SPH_C32(0xc3d60000), + SPH_C32(0x04920000), SPH_C32(0x029519a9), SPH_C32(0xf8e836ba), + SPH_C32(0x7a87f14e), SPH_C32(0x9e16981a), SPH_C32(0xd46a0000), + SPH_C32(0x8dc8c000), SPH_C32(0xa5af0000), SPH_C32(0x4a290000), + SPH_C32(0xfc4e427a), SPH_C32(0xc9b4866c), SPH_C32(0x98369604), + SPH_C32(0xf746c320) }, + { SPH_C32(0xd46a0000), SPH_C32(0x8dc8c000), SPH_C32(0xa5af0000), + SPH_C32(0x4a290000), SPH_C32(0xfc4e427a), SPH_C32(0xc9b4866c), + SPH_C32(0x98369604), SPH_C32(0xf746c320), SPH_C32(0x231f0009), + SPH_C32(0x42f40000), SPH_C32(0x66790000), SPH_C32(0x4ebb0000), + SPH_C32(0xfedb5bd3), SPH_C32(0x315cb0d6), SPH_C32(0xe2b1674a), + SPH_C32(0x69505b3a) }, + { SPH_C32(0x231f0009), SPH_C32(0x42f40000), SPH_C32(0x66790000), + SPH_C32(0x4ebb0000), SPH_C32(0xfedb5bd3), SPH_C32(0x315cb0d6), + SPH_C32(0xe2b1674a), SPH_C32(0x69505b3a), SPH_C32(0xf7750009), + SPH_C32(0xcf3cc000), SPH_C32(0xc3d60000), SPH_C32(0x04920000), + SPH_C32(0x029519a9), SPH_C32(0xf8e836ba), SPH_C32(0x7a87f14e), + SPH_C32(0x9e16981a) }, + { SPH_C32(0x774400f0), SPH_C32(0xf15a0000), SPH_C32(0xf5b20000), + SPH_C32(0x34140000), SPH_C32(0x89377e8c), SPH_C32(0x5a8bec25), + SPH_C32(0x0bc3cd1e), SPH_C32(0xcf3775cb), SPH_C32(0xf46c0050), + SPH_C32(0x96180000), SPH_C32(0x14a50000), SPH_C32(0x031f0000), + SPH_C32(0x42947eb8), SPH_C32(0x66bf7e19), SPH_C32(0x9ca470d2), + SPH_C32(0x8a341574) }, + { SPH_C32(0x803100f9), SPH_C32(0x3e66c000), SPH_C32(0x36640000), + SPH_C32(0x30860000), SPH_C32(0x8ba26725), SPH_C32(0xa263da9f), + SPH_C32(0x71443c50), SPH_C32(0x5121edd1), SPH_C32(0x20060050), + SPH_C32(0x1bd0c000), SPH_C32(0xb10a0000), SPH_C32(0x49360000), + SPH_C32(0xbeda3cc2), SPH_C32(0xaf0bf875), SPH_C32(0x0492e6d6), + SPH_C32(0x7d72d654) }, + { SPH_C32(0xa32e00f0), SPH_C32(0x7c92c000), SPH_C32(0x501d0000), + SPH_C32(0x7e3d0000), SPH_C32(0x75793cf6), SPH_C32(0x933f6a49), + SPH_C32(0x93f55b1a), SPH_C32(0x3871b6eb), SPH_C32(0xd7730059), + SPH_C32(0xd4ec0000), SPH_C32(0x72dc0000), SPH_C32(0x4da40000), + SPH_C32(0xbc4f256b), SPH_C32(0x57e3cecf), SPH_C32(0x7e151798), + SPH_C32(0xe3644e4e) }, + { SPH_C32(0x545b00f9), SPH_C32(0xb3ae0000), SPH_C32(0x93cb0000), + SPH_C32(0x7aaf0000), SPH_C32(0x77ec255f), SPH_C32(0x6bd75cf3), + SPH_C32(0xe972aa54), SPH_C32(0xa6672ef1), SPH_C32(0x03190059), + SPH_C32(0x5924c000), SPH_C32(0xd7730000), SPH_C32(0x078d0000), + SPH_C32(0x40016711), SPH_C32(0x9e5748a3), SPH_C32(0xe623819c), + SPH_C32(0x14228d6e) }, + { SPH_C32(0xf46c0050), SPH_C32(0x96180000), SPH_C32(0x14a50000), + SPH_C32(0x031f0000), SPH_C32(0x42947eb8), SPH_C32(0x66bf7e19), + SPH_C32(0x9ca470d2), SPH_C32(0x8a341574), SPH_C32(0x832800a0), + SPH_C32(0x67420000), SPH_C32(0xe1170000), SPH_C32(0x370b0000), + SPH_C32(0xcba30034), SPH_C32(0x3c34923c), SPH_C32(0x9767bdcc), + SPH_C32(0x450360bf) }, + { SPH_C32(0x03190059), SPH_C32(0x5924c000), SPH_C32(0xd7730000), + SPH_C32(0x078d0000), SPH_C32(0x40016711), SPH_C32(0x9e5748a3), + SPH_C32(0xe623819c), SPH_C32(0x14228d6e), SPH_C32(0x574200a0), + SPH_C32(0xea8ac000), SPH_C32(0x44b80000), SPH_C32(0x7d220000), + SPH_C32(0x37ed424e), SPH_C32(0xf5801450), SPH_C32(0x0f512bc8), + SPH_C32(0xb245a39f) }, + { SPH_C32(0x20060050), SPH_C32(0x1bd0c000), SPH_C32(0xb10a0000), + SPH_C32(0x49360000), SPH_C32(0xbeda3cc2), SPH_C32(0xaf0bf875), + SPH_C32(0x0492e6d6), SPH_C32(0x7d72d654), SPH_C32(0xa03700a9), + SPH_C32(0x25b60000), SPH_C32(0x876e0000), SPH_C32(0x79b00000), + SPH_C32(0x35785be7), SPH_C32(0x0d6822ea), SPH_C32(0x75d6da86), + SPH_C32(0x2c533b85) }, + { SPH_C32(0xd7730059), SPH_C32(0xd4ec0000), SPH_C32(0x72dc0000), + SPH_C32(0x4da40000), SPH_C32(0xbc4f256b), SPH_C32(0x57e3cecf), + SPH_C32(0x7e151798), SPH_C32(0xe3644e4e), SPH_C32(0x745d00a9), + SPH_C32(0xa87ec000), SPH_C32(0x22c10000), SPH_C32(0x33990000), + SPH_C32(0xc936199d), SPH_C32(0xc4dca486), SPH_C32(0xede04c82), + SPH_C32(0xdb15f8a5) }, + { SPH_C32(0x832800a0), SPH_C32(0x67420000), SPH_C32(0xe1170000), + SPH_C32(0x370b0000), SPH_C32(0xcba30034), SPH_C32(0x3c34923c), + SPH_C32(0x9767bdcc), SPH_C32(0x450360bf), SPH_C32(0x774400f0), + SPH_C32(0xf15a0000), SPH_C32(0xf5b20000), SPH_C32(0x34140000), + SPH_C32(0x89377e8c), SPH_C32(0x5a8bec25), SPH_C32(0x0bc3cd1e), + SPH_C32(0xcf3775cb) }, + { SPH_C32(0x745d00a9), SPH_C32(0xa87ec000), SPH_C32(0x22c10000), + SPH_C32(0x33990000), SPH_C32(0xc936199d), SPH_C32(0xc4dca486), + SPH_C32(0xede04c82), SPH_C32(0xdb15f8a5), SPH_C32(0xa32e00f0), + SPH_C32(0x7c92c000), SPH_C32(0x501d0000), SPH_C32(0x7e3d0000), + SPH_C32(0x75793cf6), SPH_C32(0x933f6a49), SPH_C32(0x93f55b1a), + SPH_C32(0x3871b6eb) }, + { SPH_C32(0x574200a0), SPH_C32(0xea8ac000), SPH_C32(0x44b80000), + SPH_C32(0x7d220000), SPH_C32(0x37ed424e), SPH_C32(0xf5801450), + SPH_C32(0x0f512bc8), SPH_C32(0xb245a39f), SPH_C32(0x545b00f9), + SPH_C32(0xb3ae0000), SPH_C32(0x93cb0000), SPH_C32(0x7aaf0000), + SPH_C32(0x77ec255f), SPH_C32(0x6bd75cf3), SPH_C32(0xe972aa54), + SPH_C32(0xa6672ef1) }, + { SPH_C32(0xa03700a9), SPH_C32(0x25b60000), SPH_C32(0x876e0000), + SPH_C32(0x79b00000), SPH_C32(0x35785be7), SPH_C32(0x0d6822ea), + SPH_C32(0x75d6da86), SPH_C32(0x2c533b85), SPH_C32(0x803100f9), + SPH_C32(0x3e66c000), SPH_C32(0x36640000), SPH_C32(0x30860000), + SPH_C32(0x8ba26725), SPH_C32(0xa263da9f), SPH_C32(0x71443c50), + SPH_C32(0x5121edd1) }, + { SPH_C32(0xe8870170), SPH_C32(0x9d720000), SPH_C32(0x12db0000), + SPH_C32(0xd4220000), SPH_C32(0xf2886b27), SPH_C32(0xa921e543), + SPH_C32(0x4ef8b518), SPH_C32(0x618813b1), SPH_C32(0xb4370060), + SPH_C32(0x0c4c0000), SPH_C32(0x56c20000), SPH_C32(0x5cae0000), + SPH_C32(0x94541f3f), SPH_C32(0x3b3ef825), SPH_C32(0x1b365f3d), + SPH_C32(0xf3d45758) }, + { SPH_C32(0x1ff20179), SPH_C32(0x524ec000), SPH_C32(0xd10d0000), + SPH_C32(0xd0b00000), SPH_C32(0xf01d728e), SPH_C32(0x51c9d3f9), + SPH_C32(0x347f4456), SPH_C32(0xff9e8bab), SPH_C32(0x605d0060), + SPH_C32(0x8184c000), SPH_C32(0xf36d0000), SPH_C32(0x16870000), + SPH_C32(0x681a5d45), SPH_C32(0xf28a7e49), SPH_C32(0x8300c939), + SPH_C32(0x04929478) }, + { SPH_C32(0x3ced0170), SPH_C32(0x10bac000), SPH_C32(0xb7740000), + SPH_C32(0x9e0b0000), SPH_C32(0x0ec6295d), SPH_C32(0x6095632f), + SPH_C32(0xd6ce231c), SPH_C32(0x96ced091), SPH_C32(0x97280069), + SPH_C32(0x4eb80000), SPH_C32(0x30bb0000), SPH_C32(0x12150000), + SPH_C32(0x6a8f44ec), SPH_C32(0x0a6248f3), SPH_C32(0xf9873877), + SPH_C32(0x9a840c62) }, + { SPH_C32(0xcb980179), SPH_C32(0xdf860000), SPH_C32(0x74a20000), + SPH_C32(0x9a990000), SPH_C32(0x0c5330f4), SPH_C32(0x987d5595), + SPH_C32(0xac49d252), SPH_C32(0x08d8488b), SPH_C32(0x43420069), + SPH_C32(0xc370c000), SPH_C32(0x95140000), SPH_C32(0x583c0000), + SPH_C32(0x96c10696), SPH_C32(0xc3d6ce9f), SPH_C32(0x61b1ae73), + SPH_C32(0x6dc2cf42) }, + { SPH_C32(0x9fc30180), SPH_C32(0x6c280000), SPH_C32(0xe7690000), + SPH_C32(0xe0360000), SPH_C32(0x7bbf15ab), SPH_C32(0xf3aa0966), + SPH_C32(0x453b7806), SPH_C32(0xaebf667a), SPH_C32(0x405b0030), + SPH_C32(0x9a540000), SPH_C32(0x42670000), SPH_C32(0x5fb10000), + SPH_C32(0xd6c06187), SPH_C32(0x5d81863c), SPH_C32(0x87922fef), + SPH_C32(0x79e0422c) }, + { SPH_C32(0x68b60189), SPH_C32(0xa314c000), SPH_C32(0x24bf0000), + SPH_C32(0xe4a40000), SPH_C32(0x792a0c02), SPH_C32(0x0b423fdc), + SPH_C32(0x3fbc8948), SPH_C32(0x30a9fe60), SPH_C32(0x94310030), + SPH_C32(0x179cc000), SPH_C32(0xe7c80000), SPH_C32(0x15980000), + SPH_C32(0x2a8e23fd), SPH_C32(0x94350050), SPH_C32(0x1fa4b9eb), + SPH_C32(0x8ea6810c) }, + { SPH_C32(0x4ba90180), SPH_C32(0xe1e0c000), SPH_C32(0x42c60000), + SPH_C32(0xaa1f0000), SPH_C32(0x87f157d1), SPH_C32(0x3a1e8f0a), + SPH_C32(0xdd0dee02), SPH_C32(0x59f9a55a), SPH_C32(0x63440039), + SPH_C32(0xd8a00000), SPH_C32(0x241e0000), SPH_C32(0x110a0000), + SPH_C32(0x281b3a54), SPH_C32(0x6cdd36ea), SPH_C32(0x652348a5), + SPH_C32(0x10b01916) }, + { SPH_C32(0xbcdc0189), SPH_C32(0x2edc0000), SPH_C32(0x81100000), + SPH_C32(0xae8d0000), SPH_C32(0x85644e78), SPH_C32(0xc2f6b9b0), + SPH_C32(0xa78a1f4c), SPH_C32(0xc7ef3d40), SPH_C32(0xb72e0039), + SPH_C32(0x5568c000), SPH_C32(0x81b10000), SPH_C32(0x5b230000), + SPH_C32(0xd455782e), SPH_C32(0xa569b086), SPH_C32(0xfd15dea1), + SPH_C32(0xe7f6da36) }, + { SPH_C32(0x1ceb0120), SPH_C32(0x0b6a0000), SPH_C32(0x067e0000), + SPH_C32(0xd73d0000), SPH_C32(0xb01c159f), SPH_C32(0xcf9e9b5a), + SPH_C32(0xd25cc5ca), SPH_C32(0xebbc06c5), SPH_C32(0x371f00c0), + SPH_C32(0x6b0e0000), SPH_C32(0xb7d50000), SPH_C32(0x6ba50000), + SPH_C32(0x5ff71f0b), SPH_C32(0x070a6a19), SPH_C32(0x8c51e2f1), + SPH_C32(0xb6d737e7) }, + { SPH_C32(0xeb9e0129), SPH_C32(0xc456c000), SPH_C32(0xc5a80000), + SPH_C32(0xd3af0000), SPH_C32(0xb2890c36), SPH_C32(0x3776ade0), + SPH_C32(0xa8db3484), SPH_C32(0x75aa9edf), SPH_C32(0xe37500c0), + SPH_C32(0xe6c6c000), SPH_C32(0x127a0000), SPH_C32(0x218c0000), + SPH_C32(0xa3b95d71), SPH_C32(0xcebeec75), SPH_C32(0x146774f5), + SPH_C32(0x4191f4c7) }, + { SPH_C32(0xc8810120), SPH_C32(0x86a2c000), SPH_C32(0xa3d10000), + SPH_C32(0x9d140000), SPH_C32(0x4c5257e5), SPH_C32(0x062a1d36), + SPH_C32(0x4a6a53ce), SPH_C32(0x1cfac5e5), SPH_C32(0x140000c9), + SPH_C32(0x29fa0000), SPH_C32(0xd1ac0000), SPH_C32(0x251e0000), + SPH_C32(0xa12c44d8), SPH_C32(0x3656dacf), SPH_C32(0x6ee085bb), + SPH_C32(0xdf876cdd) }, + { SPH_C32(0x3ff40129), SPH_C32(0x499e0000), SPH_C32(0x60070000), + SPH_C32(0x99860000), SPH_C32(0x4ec74e4c), SPH_C32(0xfec22b8c), + SPH_C32(0x30eda280), SPH_C32(0x82ec5dff), SPH_C32(0xc06a00c9), + SPH_C32(0xa432c000), SPH_C32(0x74030000), SPH_C32(0x6f370000), + SPH_C32(0x5d6206a2), SPH_C32(0xffe25ca3), SPH_C32(0xf6d613bf), + SPH_C32(0x28c1affd) }, + { SPH_C32(0x6baf01d0), SPH_C32(0xfa300000), SPH_C32(0xf3cc0000), + SPH_C32(0xe3290000), SPH_C32(0x392b6b13), SPH_C32(0x9515777f), + SPH_C32(0xd99f08d4), SPH_C32(0x248b730e), SPH_C32(0xc3730090), + SPH_C32(0xfd160000), SPH_C32(0xa3700000), SPH_C32(0x68ba0000), + SPH_C32(0x1d6361b3), SPH_C32(0x61b51400), SPH_C32(0x10f59223), + SPH_C32(0x3ce32293) }, + { SPH_C32(0x9cda01d9), SPH_C32(0x350cc000), SPH_C32(0x301a0000), + SPH_C32(0xe7bb0000), SPH_C32(0x3bbe72ba), SPH_C32(0x6dfd41c5), + SPH_C32(0xa318f99a), SPH_C32(0xba9deb14), SPH_C32(0x17190090), + SPH_C32(0x70dec000), SPH_C32(0x06df0000), SPH_C32(0x22930000), + SPH_C32(0xe12d23c9), SPH_C32(0xa801926c), SPH_C32(0x88c30427), + SPH_C32(0xcba5e1b3) }, + { SPH_C32(0xbfc501d0), SPH_C32(0x77f8c000), SPH_C32(0x56630000), + SPH_C32(0xa9000000), SPH_C32(0xc5652969), SPH_C32(0x5ca1f113), + SPH_C32(0x41a99ed0), SPH_C32(0xd3cdb02e), SPH_C32(0xe06c0099), + SPH_C32(0xbfe20000), SPH_C32(0xc5090000), SPH_C32(0x26010000), + SPH_C32(0xe3b83a60), SPH_C32(0x50e9a4d6), SPH_C32(0xf244f569), + SPH_C32(0x55b379a9) }, + { SPH_C32(0x48b001d9), SPH_C32(0xb8c40000), SPH_C32(0x95b50000), + SPH_C32(0xad920000), SPH_C32(0xc7f030c0), SPH_C32(0xa449c7a9), + SPH_C32(0x3b2e6f9e), SPH_C32(0x4ddb2834), SPH_C32(0x34060099), + SPH_C32(0x322ac000), SPH_C32(0x60a60000), SPH_C32(0x6c280000), + SPH_C32(0x1ff6781a), SPH_C32(0x995d22ba), SPH_C32(0x6a72636d), + SPH_C32(0xa2f5ba89) }, + { SPH_C32(0xb4370060), SPH_C32(0x0c4c0000), SPH_C32(0x56c20000), + SPH_C32(0x5cae0000), SPH_C32(0x94541f3f), SPH_C32(0x3b3ef825), + SPH_C32(0x1b365f3d), SPH_C32(0xf3d45758), SPH_C32(0x5cb00110), + SPH_C32(0x913e0000), SPH_C32(0x44190000), SPH_C32(0x888c0000), + SPH_C32(0x66dc7418), SPH_C32(0x921f1d66), SPH_C32(0x55ceea25), + SPH_C32(0x925c44e9) }, + { SPH_C32(0x43420069), SPH_C32(0xc370c000), SPH_C32(0x95140000), + SPH_C32(0x583c0000), SPH_C32(0x96c10696), SPH_C32(0xc3d6ce9f), + SPH_C32(0x61b1ae73), SPH_C32(0x6dc2cf42), SPH_C32(0x88da0110), + SPH_C32(0x1cf6c000), SPH_C32(0xe1b60000), SPH_C32(0xc2a50000), + SPH_C32(0x9a923662), SPH_C32(0x5bab9b0a), SPH_C32(0xcdf87c21), + SPH_C32(0x651a87c9) }, + { SPH_C32(0x605d0060), SPH_C32(0x8184c000), SPH_C32(0xf36d0000), + SPH_C32(0x16870000), SPH_C32(0x681a5d45), SPH_C32(0xf28a7e49), + SPH_C32(0x8300c939), SPH_C32(0x04929478), SPH_C32(0x7faf0119), + SPH_C32(0xd3ca0000), SPH_C32(0x22600000), SPH_C32(0xc6370000), + SPH_C32(0x98072fcb), SPH_C32(0xa343adb0), SPH_C32(0xb77f8d6f), + SPH_C32(0xfb0c1fd3) }, + { SPH_C32(0x97280069), SPH_C32(0x4eb80000), SPH_C32(0x30bb0000), + SPH_C32(0x12150000), SPH_C32(0x6a8f44ec), SPH_C32(0x0a6248f3), + SPH_C32(0xf9873877), SPH_C32(0x9a840c62), SPH_C32(0xabc50119), + SPH_C32(0x5e02c000), SPH_C32(0x87cf0000), SPH_C32(0x8c1e0000), + SPH_C32(0x64496db1), SPH_C32(0x6af72bdc), SPH_C32(0x2f491b6b), + SPH_C32(0x0c4adcf3) }, + { SPH_C32(0xc3730090), SPH_C32(0xfd160000), SPH_C32(0xa3700000), + SPH_C32(0x68ba0000), SPH_C32(0x1d6361b3), SPH_C32(0x61b51400), + SPH_C32(0x10f59223), SPH_C32(0x3ce32293), SPH_C32(0xa8dc0140), + SPH_C32(0x07260000), SPH_C32(0x50bc0000), SPH_C32(0x8b930000), + SPH_C32(0x24480aa0), SPH_C32(0xf4a0637f), SPH_C32(0xc96a9af7), + SPH_C32(0x1868519d) }, + { SPH_C32(0x34060099), SPH_C32(0x322ac000), SPH_C32(0x60a60000), + SPH_C32(0x6c280000), SPH_C32(0x1ff6781a), SPH_C32(0x995d22ba), + SPH_C32(0x6a72636d), SPH_C32(0xa2f5ba89), SPH_C32(0x7cb60140), + SPH_C32(0x8aeec000), SPH_C32(0xf5130000), SPH_C32(0xc1ba0000), + SPH_C32(0xd80648da), SPH_C32(0x3d14e513), SPH_C32(0x515c0cf3), + SPH_C32(0xef2e92bd) }, + { SPH_C32(0x17190090), SPH_C32(0x70dec000), SPH_C32(0x06df0000), + SPH_C32(0x22930000), SPH_C32(0xe12d23c9), SPH_C32(0xa801926c), + SPH_C32(0x88c30427), SPH_C32(0xcba5e1b3), SPH_C32(0x8bc30149), + SPH_C32(0x45d20000), SPH_C32(0x36c50000), SPH_C32(0xc5280000), + SPH_C32(0xda935173), SPH_C32(0xc5fcd3a9), SPH_C32(0x2bdbfdbd), + SPH_C32(0x71380aa7) }, + { SPH_C32(0xe06c0099), SPH_C32(0xbfe20000), SPH_C32(0xc5090000), + SPH_C32(0x26010000), SPH_C32(0xe3b83a60), SPH_C32(0x50e9a4d6), + SPH_C32(0xf244f569), SPH_C32(0x55b379a9), SPH_C32(0x5fa90149), + SPH_C32(0xc81ac000), SPH_C32(0x936a0000), SPH_C32(0x8f010000), + SPH_C32(0x26dd1309), SPH_C32(0x0c4855c5), SPH_C32(0xb3ed6bb9), + SPH_C32(0x867ec987) }, + { SPH_C32(0x405b0030), SPH_C32(0x9a540000), SPH_C32(0x42670000), + SPH_C32(0x5fb10000), SPH_C32(0xd6c06187), SPH_C32(0x5d81863c), + SPH_C32(0x87922fef), SPH_C32(0x79e0422c), SPH_C32(0xdf9801b0), + SPH_C32(0xf67c0000), SPH_C32(0xa50e0000), SPH_C32(0xbf870000), + SPH_C32(0xad7f742c), SPH_C32(0xae2b8f5a), SPH_C32(0xc2a957e9), + SPH_C32(0xd75f2456) }, + { SPH_C32(0xb72e0039), SPH_C32(0x5568c000), SPH_C32(0x81b10000), + SPH_C32(0x5b230000), SPH_C32(0xd455782e), SPH_C32(0xa569b086), + SPH_C32(0xfd15dea1), SPH_C32(0xe7f6da36), SPH_C32(0x0bf201b0), + SPH_C32(0x7bb4c000), SPH_C32(0x00a10000), SPH_C32(0xf5ae0000), + SPH_C32(0x51313656), SPH_C32(0x679f0936), SPH_C32(0x5a9fc1ed), + SPH_C32(0x2019e776) }, + { SPH_C32(0x94310030), SPH_C32(0x179cc000), SPH_C32(0xe7c80000), + SPH_C32(0x15980000), SPH_C32(0x2a8e23fd), SPH_C32(0x94350050), + SPH_C32(0x1fa4b9eb), SPH_C32(0x8ea6810c), SPH_C32(0xfc8701b9), + SPH_C32(0xb4880000), SPH_C32(0xc3770000), SPH_C32(0xf13c0000), + SPH_C32(0x53a42fff), SPH_C32(0x9f773f8c), SPH_C32(0x201830a3), + SPH_C32(0xbe0f7f6c) }, + { SPH_C32(0x63440039), SPH_C32(0xd8a00000), SPH_C32(0x241e0000), + SPH_C32(0x110a0000), SPH_C32(0x281b3a54), SPH_C32(0x6cdd36ea), + SPH_C32(0x652348a5), SPH_C32(0x10b01916), SPH_C32(0x28ed01b9), + SPH_C32(0x3940c000), SPH_C32(0x66d80000), SPH_C32(0xbb150000), + SPH_C32(0xafea6d85), SPH_C32(0x56c3b9e0), SPH_C32(0xb82ea6a7), + SPH_C32(0x4949bc4c) }, + { SPH_C32(0x371f00c0), SPH_C32(0x6b0e0000), SPH_C32(0xb7d50000), + SPH_C32(0x6ba50000), SPH_C32(0x5ff71f0b), SPH_C32(0x070a6a19), + SPH_C32(0x8c51e2f1), SPH_C32(0xb6d737e7), SPH_C32(0x2bf401e0), + SPH_C32(0x60640000), SPH_C32(0xb1ab0000), SPH_C32(0xbc980000), + SPH_C32(0xefeb0a94), SPH_C32(0xc894f143), SPH_C32(0x5e0d273b), + SPH_C32(0x5d6b3122) }, + { SPH_C32(0xc06a00c9), SPH_C32(0xa432c000), SPH_C32(0x74030000), + SPH_C32(0x6f370000), SPH_C32(0x5d6206a2), SPH_C32(0xffe25ca3), + SPH_C32(0xf6d613bf), SPH_C32(0x28c1affd), SPH_C32(0xff9e01e0), + SPH_C32(0xedacc000), SPH_C32(0x14040000), SPH_C32(0xf6b10000), + SPH_C32(0x13a548ee), SPH_C32(0x0120772f), SPH_C32(0xc63bb13f), + SPH_C32(0xaa2df202) }, + { SPH_C32(0xe37500c0), SPH_C32(0xe6c6c000), SPH_C32(0x127a0000), + SPH_C32(0x218c0000), SPH_C32(0xa3b95d71), SPH_C32(0xcebeec75), + SPH_C32(0x146774f5), SPH_C32(0x4191f4c7), SPH_C32(0x08eb01e9), + SPH_C32(0x22900000), SPH_C32(0xd7d20000), SPH_C32(0xf2230000), + SPH_C32(0x11305147), SPH_C32(0xf9c84195), SPH_C32(0xbcbc4071), + SPH_C32(0x343b6a18) }, + { SPH_C32(0x140000c9), SPH_C32(0x29fa0000), SPH_C32(0xd1ac0000), + SPH_C32(0x251e0000), SPH_C32(0xa12c44d8), SPH_C32(0x3656dacf), + SPH_C32(0x6ee085bb), SPH_C32(0xdf876cdd), SPH_C32(0xdc8101e9), + SPH_C32(0xaf58c000), SPH_C32(0x727d0000), SPH_C32(0xb80a0000), + SPH_C32(0xed7e133d), SPH_C32(0x307cc7f9), SPH_C32(0x248ad675), + SPH_C32(0xc37da938) }, + { SPH_C32(0x5cb00110), SPH_C32(0x913e0000), SPH_C32(0x44190000), + SPH_C32(0x888c0000), SPH_C32(0x66dc7418), SPH_C32(0x921f1d66), + SPH_C32(0x55ceea25), SPH_C32(0x925c44e9), SPH_C32(0xe8870170), + SPH_C32(0x9d720000), SPH_C32(0x12db0000), SPH_C32(0xd4220000), + SPH_C32(0xf2886b27), SPH_C32(0xa921e543), SPH_C32(0x4ef8b518), + SPH_C32(0x618813b1) }, + { SPH_C32(0xabc50119), SPH_C32(0x5e02c000), SPH_C32(0x87cf0000), + SPH_C32(0x8c1e0000), SPH_C32(0x64496db1), SPH_C32(0x6af72bdc), + SPH_C32(0x2f491b6b), SPH_C32(0x0c4adcf3), SPH_C32(0x3ced0170), + SPH_C32(0x10bac000), SPH_C32(0xb7740000), SPH_C32(0x9e0b0000), + SPH_C32(0x0ec6295d), SPH_C32(0x6095632f), SPH_C32(0xd6ce231c), + SPH_C32(0x96ced091) }, + { SPH_C32(0x88da0110), SPH_C32(0x1cf6c000), SPH_C32(0xe1b60000), + SPH_C32(0xc2a50000), SPH_C32(0x9a923662), SPH_C32(0x5bab9b0a), + SPH_C32(0xcdf87c21), SPH_C32(0x651a87c9), SPH_C32(0xcb980179), + SPH_C32(0xdf860000), SPH_C32(0x74a20000), SPH_C32(0x9a990000), + SPH_C32(0x0c5330f4), SPH_C32(0x987d5595), SPH_C32(0xac49d252), + SPH_C32(0x08d8488b) }, + { SPH_C32(0x7faf0119), SPH_C32(0xd3ca0000), SPH_C32(0x22600000), + SPH_C32(0xc6370000), SPH_C32(0x98072fcb), SPH_C32(0xa343adb0), + SPH_C32(0xb77f8d6f), SPH_C32(0xfb0c1fd3), SPH_C32(0x1ff20179), + SPH_C32(0x524ec000), SPH_C32(0xd10d0000), SPH_C32(0xd0b00000), + SPH_C32(0xf01d728e), SPH_C32(0x51c9d3f9), SPH_C32(0x347f4456), + SPH_C32(0xff9e8bab) }, + { SPH_C32(0x2bf401e0), SPH_C32(0x60640000), SPH_C32(0xb1ab0000), + SPH_C32(0xbc980000), SPH_C32(0xefeb0a94), SPH_C32(0xc894f143), + SPH_C32(0x5e0d273b), SPH_C32(0x5d6b3122), SPH_C32(0x1ceb0120), + SPH_C32(0x0b6a0000), SPH_C32(0x067e0000), SPH_C32(0xd73d0000), + SPH_C32(0xb01c159f), SPH_C32(0xcf9e9b5a), SPH_C32(0xd25cc5ca), + SPH_C32(0xebbc06c5) }, + { SPH_C32(0xdc8101e9), SPH_C32(0xaf58c000), SPH_C32(0x727d0000), + SPH_C32(0xb80a0000), SPH_C32(0xed7e133d), SPH_C32(0x307cc7f9), + SPH_C32(0x248ad675), SPH_C32(0xc37da938), SPH_C32(0xc8810120), + SPH_C32(0x86a2c000), SPH_C32(0xa3d10000), SPH_C32(0x9d140000), + SPH_C32(0x4c5257e5), SPH_C32(0x062a1d36), SPH_C32(0x4a6a53ce), + SPH_C32(0x1cfac5e5) }, + { SPH_C32(0xff9e01e0), SPH_C32(0xedacc000), SPH_C32(0x14040000), + SPH_C32(0xf6b10000), SPH_C32(0x13a548ee), SPH_C32(0x0120772f), + SPH_C32(0xc63bb13f), SPH_C32(0xaa2df202), SPH_C32(0x3ff40129), + SPH_C32(0x499e0000), SPH_C32(0x60070000), SPH_C32(0x99860000), + SPH_C32(0x4ec74e4c), SPH_C32(0xfec22b8c), SPH_C32(0x30eda280), + SPH_C32(0x82ec5dff) }, + { SPH_C32(0x08eb01e9), SPH_C32(0x22900000), SPH_C32(0xd7d20000), + SPH_C32(0xf2230000), SPH_C32(0x11305147), SPH_C32(0xf9c84195), + SPH_C32(0xbcbc4071), SPH_C32(0x343b6a18), SPH_C32(0xeb9e0129), + SPH_C32(0xc456c000), SPH_C32(0xc5a80000), SPH_C32(0xd3af0000), + SPH_C32(0xb2890c36), SPH_C32(0x3776ade0), SPH_C32(0xa8db3484), + SPH_C32(0x75aa9edf) }, + { SPH_C32(0xa8dc0140), SPH_C32(0x07260000), SPH_C32(0x50bc0000), + SPH_C32(0x8b930000), SPH_C32(0x24480aa0), SPH_C32(0xf4a0637f), + SPH_C32(0xc96a9af7), SPH_C32(0x1868519d), SPH_C32(0x6baf01d0), + SPH_C32(0xfa300000), SPH_C32(0xf3cc0000), SPH_C32(0xe3290000), + SPH_C32(0x392b6b13), SPH_C32(0x9515777f), SPH_C32(0xd99f08d4), + SPH_C32(0x248b730e) }, + { SPH_C32(0x5fa90149), SPH_C32(0xc81ac000), SPH_C32(0x936a0000), + SPH_C32(0x8f010000), SPH_C32(0x26dd1309), SPH_C32(0x0c4855c5), + SPH_C32(0xb3ed6bb9), SPH_C32(0x867ec987), SPH_C32(0xbfc501d0), + SPH_C32(0x77f8c000), SPH_C32(0x56630000), SPH_C32(0xa9000000), + SPH_C32(0xc5652969), SPH_C32(0x5ca1f113), SPH_C32(0x41a99ed0), + SPH_C32(0xd3cdb02e) }, + { SPH_C32(0x7cb60140), SPH_C32(0x8aeec000), SPH_C32(0xf5130000), + SPH_C32(0xc1ba0000), SPH_C32(0xd80648da), SPH_C32(0x3d14e513), + SPH_C32(0x515c0cf3), SPH_C32(0xef2e92bd), SPH_C32(0x48b001d9), + SPH_C32(0xb8c40000), SPH_C32(0x95b50000), SPH_C32(0xad920000), + SPH_C32(0xc7f030c0), SPH_C32(0xa449c7a9), SPH_C32(0x3b2e6f9e), + SPH_C32(0x4ddb2834) }, + { SPH_C32(0x8bc30149), SPH_C32(0x45d20000), SPH_C32(0x36c50000), + SPH_C32(0xc5280000), SPH_C32(0xda935173), SPH_C32(0xc5fcd3a9), + SPH_C32(0x2bdbfdbd), SPH_C32(0x71380aa7), SPH_C32(0x9cda01d9), + SPH_C32(0x350cc000), SPH_C32(0x301a0000), SPH_C32(0xe7bb0000), + SPH_C32(0x3bbe72ba), SPH_C32(0x6dfd41c5), SPH_C32(0xa318f99a), + SPH_C32(0xba9deb14) }, + { SPH_C32(0xdf9801b0), SPH_C32(0xf67c0000), SPH_C32(0xa50e0000), + SPH_C32(0xbf870000), SPH_C32(0xad7f742c), SPH_C32(0xae2b8f5a), + SPH_C32(0xc2a957e9), SPH_C32(0xd75f2456), SPH_C32(0x9fc30180), + SPH_C32(0x6c280000), SPH_C32(0xe7690000), SPH_C32(0xe0360000), + SPH_C32(0x7bbf15ab), SPH_C32(0xf3aa0966), SPH_C32(0x453b7806), + SPH_C32(0xaebf667a) }, + { SPH_C32(0x28ed01b9), SPH_C32(0x3940c000), SPH_C32(0x66d80000), + SPH_C32(0xbb150000), SPH_C32(0xafea6d85), SPH_C32(0x56c3b9e0), + SPH_C32(0xb82ea6a7), SPH_C32(0x4949bc4c), SPH_C32(0x4ba90180), + SPH_C32(0xe1e0c000), SPH_C32(0x42c60000), SPH_C32(0xaa1f0000), + SPH_C32(0x87f157d1), SPH_C32(0x3a1e8f0a), SPH_C32(0xdd0dee02), + SPH_C32(0x59f9a55a) }, + { SPH_C32(0x0bf201b0), SPH_C32(0x7bb4c000), SPH_C32(0x00a10000), + SPH_C32(0xf5ae0000), SPH_C32(0x51313656), SPH_C32(0x679f0936), + SPH_C32(0x5a9fc1ed), SPH_C32(0x2019e776), SPH_C32(0xbcdc0189), + SPH_C32(0x2edc0000), SPH_C32(0x81100000), SPH_C32(0xae8d0000), + SPH_C32(0x85644e78), SPH_C32(0xc2f6b9b0), SPH_C32(0xa78a1f4c), + SPH_C32(0xc7ef3d40) }, + { SPH_C32(0xfc8701b9), SPH_C32(0xb4880000), SPH_C32(0xc3770000), + SPH_C32(0xf13c0000), SPH_C32(0x53a42fff), SPH_C32(0x9f773f8c), + SPH_C32(0x201830a3), SPH_C32(0xbe0f7f6c), SPH_C32(0x68b60189), + SPH_C32(0xa314c000), SPH_C32(0x24bf0000), SPH_C32(0xe4a40000), + SPH_C32(0x792a0c02), SPH_C32(0x0b423fdc), SPH_C32(0x3fbc8948), + SPH_C32(0x30a9fe60) }, + { SPH_C32(0xef0b0270), SPH_C32(0x3afd0000), SPH_C32(0x5dae0000), + SPH_C32(0x69490000), SPH_C32(0x9b0f3c06), SPH_C32(0x4405b5f9), + SPH_C32(0x66140a51), SPH_C32(0x924f5d0a), SPH_C32(0xc96b0030), + SPH_C32(0xe7250000), SPH_C32(0x2f840000), SPH_C32(0x264f0000), + SPH_C32(0x08695bf9), SPH_C32(0x6dfcf137), SPH_C32(0x509f6984), + SPH_C32(0x9e69af68) }, + { SPH_C32(0x187e0279), SPH_C32(0xf5c1c000), SPH_C32(0x9e780000), + SPH_C32(0x6ddb0000), SPH_C32(0x999a25af), SPH_C32(0xbced8343), + SPH_C32(0x1c93fb1f), SPH_C32(0x0c59c510), SPH_C32(0x1d010030), + SPH_C32(0x6aedc000), SPH_C32(0x8a2b0000), SPH_C32(0x6c660000), + SPH_C32(0xf4271983), SPH_C32(0xa448775b), SPH_C32(0xc8a9ff80), + SPH_C32(0x692f6c48) }, + { SPH_C32(0x3b610270), SPH_C32(0xb735c000), SPH_C32(0xf8010000), + SPH_C32(0x23600000), SPH_C32(0x67417e7c), SPH_C32(0x8db13395), + SPH_C32(0xfe229c55), SPH_C32(0x65099e2a), SPH_C32(0xea740039), + SPH_C32(0xa5d10000), SPH_C32(0x49fd0000), SPH_C32(0x68f40000), + SPH_C32(0xf6b2002a), SPH_C32(0x5ca041e1), SPH_C32(0xb22e0ece), + SPH_C32(0xf739f452) }, + { SPH_C32(0xcc140279), SPH_C32(0x78090000), SPH_C32(0x3bd70000), + SPH_C32(0x27f20000), SPH_C32(0x65d467d5), SPH_C32(0x7559052f), + SPH_C32(0x84a56d1b), SPH_C32(0xfb1f0630), SPH_C32(0x3e1e0039), + SPH_C32(0x2819c000), SPH_C32(0xec520000), SPH_C32(0x22dd0000), + SPH_C32(0x0afc4250), SPH_C32(0x9514c78d), SPH_C32(0x2a1898ca), + SPH_C32(0x007f3772) }, + { SPH_C32(0x984f0280), SPH_C32(0xcba70000), SPH_C32(0xa81c0000), + SPH_C32(0x5d5d0000), SPH_C32(0x1238428a), SPH_C32(0x1e8e59dc), + SPH_C32(0x6dd7c74f), SPH_C32(0x5d7828c1), SPH_C32(0x3d070060), + SPH_C32(0x713d0000), SPH_C32(0x3b210000), SPH_C32(0x25500000), + SPH_C32(0x4afd2541), SPH_C32(0x0b438f2e), SPH_C32(0xcc3b1956), + SPH_C32(0x145dba1c) }, + { SPH_C32(0x6f3a0289), SPH_C32(0x049bc000), SPH_C32(0x6bca0000), + SPH_C32(0x59cf0000), SPH_C32(0x10ad5b23), SPH_C32(0xe6666f66), + SPH_C32(0x17503601), SPH_C32(0xc36eb0db), SPH_C32(0xe96d0060), + SPH_C32(0xfcf5c000), SPH_C32(0x9e8e0000), SPH_C32(0x6f790000), + SPH_C32(0xb6b3673b), SPH_C32(0xc2f70942), SPH_C32(0x540d8f52), + SPH_C32(0xe31b793c) }, + { SPH_C32(0x4c250280), SPH_C32(0x466fc000), SPH_C32(0x0db30000), + SPH_C32(0x17740000), SPH_C32(0xee7600f0), SPH_C32(0xd73adfb0), + SPH_C32(0xf5e1514b), SPH_C32(0xaa3eebe1), SPH_C32(0x1e180069), + SPH_C32(0x33c90000), SPH_C32(0x5d580000), SPH_C32(0x6beb0000), + SPH_C32(0xb4267e92), SPH_C32(0x3a1f3ff8), SPH_C32(0x2e8a7e1c), + SPH_C32(0x7d0de126) }, + { SPH_C32(0xbb500289), SPH_C32(0x89530000), SPH_C32(0xce650000), + SPH_C32(0x13e60000), SPH_C32(0xece31959), SPH_C32(0x2fd2e90a), + SPH_C32(0x8f66a005), SPH_C32(0x342873fb), SPH_C32(0xca720069), + SPH_C32(0xbe01c000), SPH_C32(0xf8f70000), SPH_C32(0x21c20000), + SPH_C32(0x48683ce8), SPH_C32(0xf3abb994), SPH_C32(0xb6bce818), + SPH_C32(0x8a4b2206) }, + { SPH_C32(0x1b670220), SPH_C32(0xace50000), SPH_C32(0x490b0000), + SPH_C32(0x6a560000), SPH_C32(0xd99b42be), SPH_C32(0x22bacbe0), + SPH_C32(0xfab07a83), SPH_C32(0x187b487e), SPH_C32(0x4a430090), + SPH_C32(0x80670000), SPH_C32(0xce930000), SPH_C32(0x11440000), + SPH_C32(0xc3ca5bcd), SPH_C32(0x51c8630b), SPH_C32(0xc7f8d448), + SPH_C32(0xdb6acfd7) }, + { SPH_C32(0xec120229), SPH_C32(0x63d9c000), SPH_C32(0x8add0000), + SPH_C32(0x6ec40000), SPH_C32(0xdb0e5b17), SPH_C32(0xda52fd5a), + SPH_C32(0x80378bcd), SPH_C32(0x866dd064), SPH_C32(0x9e290090), + SPH_C32(0x0dafc000), SPH_C32(0x6b3c0000), SPH_C32(0x5b6d0000), + SPH_C32(0x3f8419b7), SPH_C32(0x987ce567), SPH_C32(0x5fce424c), + SPH_C32(0x2c2c0cf7) }, + { SPH_C32(0xcf0d0220), SPH_C32(0x212dc000), SPH_C32(0xeca40000), + SPH_C32(0x207f0000), SPH_C32(0x25d500c4), SPH_C32(0xeb0e4d8c), + SPH_C32(0x6286ec87), SPH_C32(0xef3d8b5e), SPH_C32(0x695c0099), + SPH_C32(0xc2930000), SPH_C32(0xa8ea0000), SPH_C32(0x5fff0000), + SPH_C32(0x3d11001e), SPH_C32(0x6094d3dd), SPH_C32(0x2549b302), + SPH_C32(0xb23a94ed) }, + { SPH_C32(0x38780229), SPH_C32(0xee110000), SPH_C32(0x2f720000), + SPH_C32(0x24ed0000), SPH_C32(0x2740196d), SPH_C32(0x13e67b36), + SPH_C32(0x18011dc9), SPH_C32(0x712b1344), SPH_C32(0xbd360099), + SPH_C32(0x4f5bc000), SPH_C32(0x0d450000), SPH_C32(0x15d60000), + SPH_C32(0xc15f4264), SPH_C32(0xa92055b1), SPH_C32(0xbd7f2506), + SPH_C32(0x457c57cd) }, + { SPH_C32(0x6c2302d0), SPH_C32(0x5dbf0000), SPH_C32(0xbcb90000), + SPH_C32(0x5e420000), SPH_C32(0x50ac3c32), SPH_C32(0x783127c5), + SPH_C32(0xf173b79d), SPH_C32(0xd74c3db5), SPH_C32(0xbe2f00c0), + SPH_C32(0x167f0000), SPH_C32(0xda360000), SPH_C32(0x125b0000), + SPH_C32(0x815e2575), SPH_C32(0x37771d12), SPH_C32(0x5b5ca49a), + SPH_C32(0x515edaa3) }, + { SPH_C32(0x9b5602d9), SPH_C32(0x9283c000), SPH_C32(0x7f6f0000), + SPH_C32(0x5ad00000), SPH_C32(0x5239259b), SPH_C32(0x80d9117f), + SPH_C32(0x8bf446d3), SPH_C32(0x495aa5af), SPH_C32(0x6a4500c0), + SPH_C32(0x9bb7c000), SPH_C32(0x7f990000), SPH_C32(0x58720000), + SPH_C32(0x7d10670f), SPH_C32(0xfec39b7e), SPH_C32(0xc36a329e), + SPH_C32(0xa6181983) }, + { SPH_C32(0xb84902d0), SPH_C32(0xd077c000), SPH_C32(0x19160000), + SPH_C32(0x146b0000), SPH_C32(0xace27e48), SPH_C32(0xb185a1a9), + SPH_C32(0x69452199), SPH_C32(0x200afe95), SPH_C32(0x9d3000c9), + SPH_C32(0x548b0000), SPH_C32(0xbc4f0000), SPH_C32(0x5ce00000), + SPH_C32(0x7f857ea6), SPH_C32(0x062badc4), SPH_C32(0xb9edc3d0), + SPH_C32(0x380e8199) }, + { SPH_C32(0x4f3c02d9), SPH_C32(0x1f4b0000), SPH_C32(0xdac00000), + SPH_C32(0x10f90000), SPH_C32(0xae7767e1), SPH_C32(0x496d9713), + SPH_C32(0x13c2d0d7), SPH_C32(0xbe1c668f), SPH_C32(0x495a00c9), + SPH_C32(0xd943c000), SPH_C32(0x19e00000), SPH_C32(0x16c90000), + SPH_C32(0x83cb3cdc), SPH_C32(0xcf9f2ba8), SPH_C32(0x21db55d4), + SPH_C32(0xcf4842b9) }, + { SPH_C32(0x078c0300), SPH_C32(0xa78f0000), SPH_C32(0x4f750000), + SPH_C32(0xbd6b0000), SPH_C32(0x69875721), SPH_C32(0xed2450ba), + SPH_C32(0x28ecbf49), SPH_C32(0xf3c74ebb), SPH_C32(0x7d5c0050), + SPH_C32(0xeb690000), SPH_C32(0x79460000), SPH_C32(0x7ae10000), + SPH_C32(0x9c3d44c6), SPH_C32(0x56c20912), SPH_C32(0x4ba936b9), + SPH_C32(0x6dbdf830) }, + { SPH_C32(0xf0f90309), SPH_C32(0x68b3c000), SPH_C32(0x8ca30000), + SPH_C32(0xb9f90000), SPH_C32(0x6b124e88), SPH_C32(0x15cc6600), + SPH_C32(0x526b4e07), SPH_C32(0x6dd1d6a1), SPH_C32(0xa9360050), + SPH_C32(0x66a1c000), SPH_C32(0xdce90000), SPH_C32(0x30c80000), + SPH_C32(0x607306bc), SPH_C32(0x9f768f7e), SPH_C32(0xd39fa0bd), + SPH_C32(0x9afb3b10) }, + { SPH_C32(0xd3e60300), SPH_C32(0x2a47c000), SPH_C32(0xeada0000), + SPH_C32(0xf7420000), SPH_C32(0x95c9155b), SPH_C32(0x2490d6d6), + SPH_C32(0xb0da294d), SPH_C32(0x04818d9b), SPH_C32(0x5e430059), + SPH_C32(0xa99d0000), SPH_C32(0x1f3f0000), SPH_C32(0x345a0000), + SPH_C32(0x62e61f15), SPH_C32(0x679eb9c4), SPH_C32(0xa91851f3), + SPH_C32(0x04eda30a) }, + { SPH_C32(0x24930309), SPH_C32(0xe57b0000), SPH_C32(0x290c0000), + SPH_C32(0xf3d00000), SPH_C32(0x975c0cf2), SPH_C32(0xdc78e06c), + SPH_C32(0xca5dd803), SPH_C32(0x9a971581), SPH_C32(0x8a290059), + SPH_C32(0x2455c000), SPH_C32(0xba900000), SPH_C32(0x7e730000), + SPH_C32(0x9ea85d6f), SPH_C32(0xae2a3fa8), SPH_C32(0x312ec7f7), + SPH_C32(0xf3ab602a) }, + { SPH_C32(0x70c803f0), SPH_C32(0x56d50000), SPH_C32(0xbac70000), + SPH_C32(0x897f0000), SPH_C32(0xe0b029ad), SPH_C32(0xb7afbc9f), + SPH_C32(0x232f7257), SPH_C32(0x3cf03b70), SPH_C32(0x89300000), + SPH_C32(0x7d710000), SPH_C32(0x6de30000), SPH_C32(0x79fe0000), + SPH_C32(0xdea93a7e), SPH_C32(0x307d770b), SPH_C32(0xd70d466b), + SPH_C32(0xe789ed44) }, + { SPH_C32(0x87bd03f9), SPH_C32(0x99e9c000), SPH_C32(0x79110000), + SPH_C32(0x8ded0000), SPH_C32(0xe2253004), SPH_C32(0x4f478a25), + SPH_C32(0x59a88319), SPH_C32(0xa2e6a36a), SPH_C32(0x5d5a0000), + SPH_C32(0xf0b9c000), SPH_C32(0xc84c0000), SPH_C32(0x33d70000), + SPH_C32(0x22e77804), SPH_C32(0xf9c9f167), SPH_C32(0x4f3bd06f), + SPH_C32(0x10cf2e64) }, + { SPH_C32(0xa4a203f0), SPH_C32(0xdb1dc000), SPH_C32(0x1f680000), + SPH_C32(0xc3560000), SPH_C32(0x1cfe6bd7), SPH_C32(0x7e1b3af3), + SPH_C32(0xbb19e453), SPH_C32(0xcbb6f850), SPH_C32(0xaa2f0009), + SPH_C32(0x3f850000), SPH_C32(0x0b9a0000), SPH_C32(0x37450000), + SPH_C32(0x207261ad), SPH_C32(0x0121c7dd), SPH_C32(0x35bc2121), + SPH_C32(0x8ed9b67e) }, + { SPH_C32(0x53d703f9), SPH_C32(0x14210000), SPH_C32(0xdcbe0000), + SPH_C32(0xc7c40000), SPH_C32(0x1e6b727e), SPH_C32(0x86f30c49), + SPH_C32(0xc19e151d), SPH_C32(0x55a0604a), SPH_C32(0x7e450009), + SPH_C32(0xb24dc000), SPH_C32(0xae350000), SPH_C32(0x7d6c0000), + SPH_C32(0xdc3c23d7), SPH_C32(0xc89541b1), SPH_C32(0xad8ab725), + SPH_C32(0x799f755e) }, + { SPH_C32(0xf3e00350), SPH_C32(0x31970000), SPH_C32(0x5bd00000), + SPH_C32(0xbe740000), SPH_C32(0x2b132999), SPH_C32(0x8b9b2ea3), + SPH_C32(0xb448cf9b), SPH_C32(0x79f35bcf), SPH_C32(0xfe7400f0), + SPH_C32(0x8c2b0000), SPH_C32(0x98510000), SPH_C32(0x4dea0000), + SPH_C32(0x579e44f2), SPH_C32(0x6af69b2e), SPH_C32(0xdcce8b75), + SPH_C32(0x28be988f) }, + { SPH_C32(0x04950359), SPH_C32(0xfeabc000), SPH_C32(0x98060000), + SPH_C32(0xbae60000), SPH_C32(0x29863030), SPH_C32(0x73731819), + SPH_C32(0xcecf3ed5), SPH_C32(0xe7e5c3d5), SPH_C32(0x2a1e00f0), + SPH_C32(0x01e3c000), SPH_C32(0x3dfe0000), SPH_C32(0x07c30000), + SPH_C32(0xabd00688), SPH_C32(0xa3421d42), SPH_C32(0x44f81d71), + SPH_C32(0xdff85baf) }, + { SPH_C32(0x278a0350), SPH_C32(0xbc5fc000), SPH_C32(0xfe7f0000), + SPH_C32(0xf45d0000), SPH_C32(0xd75d6be3), SPH_C32(0x422fa8cf), + SPH_C32(0x2c7e599f), SPH_C32(0x8eb598ef), SPH_C32(0xdd6b00f9), + SPH_C32(0xcedf0000), SPH_C32(0xfe280000), SPH_C32(0x03510000), + SPH_C32(0xa9451f21), SPH_C32(0x5baa2bf8), SPH_C32(0x3e7fec3f), + SPH_C32(0x41eec3b5) }, + { SPH_C32(0xd0ff0359), SPH_C32(0x73630000), SPH_C32(0x3da90000), + SPH_C32(0xf0cf0000), SPH_C32(0xd5c8724a), SPH_C32(0xbac79e75), + SPH_C32(0x56f9a8d1), SPH_C32(0x10a300f5), SPH_C32(0x090100f9), + SPH_C32(0x4317c000), SPH_C32(0x5b870000), SPH_C32(0x49780000), + SPH_C32(0x550b5d5b), SPH_C32(0x921ead94), SPH_C32(0xa6497a3b), + SPH_C32(0xb6a80095) }, + { SPH_C32(0x84a403a0), SPH_C32(0xc0cd0000), SPH_C32(0xae620000), + SPH_C32(0x8a600000), SPH_C32(0xa2245715), SPH_C32(0xd110c286), + SPH_C32(0xbf8b0285), SPH_C32(0xb6c42e04), SPH_C32(0x0a1800a0), + SPH_C32(0x1a330000), SPH_C32(0x8cf40000), SPH_C32(0x4ef50000), + SPH_C32(0x150a3a4a), SPH_C32(0x0c49e537), SPH_C32(0x406afba7), + SPH_C32(0xa28a8dfb) }, + { SPH_C32(0x73d103a9), SPH_C32(0x0ff1c000), SPH_C32(0x6db40000), + SPH_C32(0x8ef20000), SPH_C32(0xa0b14ebc), SPH_C32(0x29f8f43c), + SPH_C32(0xc50cf3cb), SPH_C32(0x28d2b61e), SPH_C32(0xde7200a0), + SPH_C32(0x97fbc000), SPH_C32(0x295b0000), SPH_C32(0x04dc0000), + SPH_C32(0xe9447830), SPH_C32(0xc5fd635b), SPH_C32(0xd85c6da3), + SPH_C32(0x55cc4edb) }, + { SPH_C32(0x50ce03a0), SPH_C32(0x4d05c000), SPH_C32(0x0bcd0000), + SPH_C32(0xc0490000), SPH_C32(0x5e6a156f), SPH_C32(0x18a444ea), + SPH_C32(0x27bd9481), SPH_C32(0x4182ed24), SPH_C32(0x290700a9), + SPH_C32(0x58c70000), SPH_C32(0xea8d0000), SPH_C32(0x004e0000), + SPH_C32(0xebd16199), SPH_C32(0x3d1555e1), SPH_C32(0xa2db9ced), + SPH_C32(0xcbdad6c1) }, + { SPH_C32(0xa7bb03a9), SPH_C32(0x82390000), SPH_C32(0xc81b0000), + SPH_C32(0xc4db0000), SPH_C32(0x5cff0cc6), SPH_C32(0xe04c7250), + SPH_C32(0x5d3a65cf), SPH_C32(0xdf94753e), SPH_C32(0xfd6d00a9), + SPH_C32(0xd50fc000), SPH_C32(0x4f220000), SPH_C32(0x4a670000), + SPH_C32(0x179f23e3), SPH_C32(0xf4a1d38d), SPH_C32(0x3aed0ae9), + SPH_C32(0x3c9c15e1) }, + { SPH_C32(0x5b3c0210), SPH_C32(0x36b10000), SPH_C32(0x0b6c0000), + SPH_C32(0x35e70000), SPH_C32(0x0f5b2339), SPH_C32(0x7f3b4ddc), + SPH_C32(0x7d22556c), SPH_C32(0x619b0a52), SPH_C32(0x95db0120), + SPH_C32(0x761b0000), SPH_C32(0x6b9d0000), SPH_C32(0xaec30000), + SPH_C32(0x6eb52fe1), SPH_C32(0xffe3ec51), SPH_C32(0x055183a1), + SPH_C32(0x0c35eb81) }, + { SPH_C32(0xac490219), SPH_C32(0xf98dc000), SPH_C32(0xc8ba0000), + SPH_C32(0x31750000), SPH_C32(0x0dce3a90), SPH_C32(0x87d37b66), + SPH_C32(0x07a5a422), SPH_C32(0xff8d9248), SPH_C32(0x41b10120), + SPH_C32(0xfbd3c000), SPH_C32(0xce320000), SPH_C32(0xe4ea0000), + SPH_C32(0x92fb6d9b), SPH_C32(0x36576a3d), SPH_C32(0x9d6715a5), + SPH_C32(0xfb7328a1) }, + { SPH_C32(0x8f560210), SPH_C32(0xbb79c000), SPH_C32(0xaec30000), + SPH_C32(0x7fce0000), SPH_C32(0xf3156143), SPH_C32(0xb68fcbb0), + SPH_C32(0xe514c368), SPH_C32(0x96ddc972), SPH_C32(0xb6c40129), + SPH_C32(0x34ef0000), SPH_C32(0x0de40000), SPH_C32(0xe0780000), + SPH_C32(0x906e7432), SPH_C32(0xcebf5c87), SPH_C32(0xe7e0e4eb), + SPH_C32(0x6565b0bb) }, + { SPH_C32(0x78230219), SPH_C32(0x74450000), SPH_C32(0x6d150000), + SPH_C32(0x7b5c0000), SPH_C32(0xf18078ea), SPH_C32(0x4e67fd0a), + SPH_C32(0x9f933226), SPH_C32(0x08cb5168), SPH_C32(0x62ae0129), + SPH_C32(0xb927c000), SPH_C32(0xa84b0000), SPH_C32(0xaa510000), + SPH_C32(0x6c203648), SPH_C32(0x070bdaeb), SPH_C32(0x7fd672ef), + SPH_C32(0x9223739b) }, + { SPH_C32(0x2c7802e0), SPH_C32(0xc7eb0000), SPH_C32(0xfede0000), + SPH_C32(0x01f30000), SPH_C32(0x866c5db5), SPH_C32(0x25b0a1f9), + SPH_C32(0x76e19872), SPH_C32(0xaeac7f99), SPH_C32(0x61b70170), + SPH_C32(0xe0030000), SPH_C32(0x7f380000), SPH_C32(0xaddc0000), + SPH_C32(0x2c215159), SPH_C32(0x995c9248), SPH_C32(0x99f5f373), + SPH_C32(0x8601fef5) }, + { SPH_C32(0xdb0d02e9), SPH_C32(0x08d7c000), SPH_C32(0x3d080000), + SPH_C32(0x05610000), SPH_C32(0x84f9441c), SPH_C32(0xdd589743), + SPH_C32(0x0c66693c), SPH_C32(0x30bae783), SPH_C32(0xb5dd0170), + SPH_C32(0x6dcbc000), SPH_C32(0xda970000), SPH_C32(0xe7f50000), + SPH_C32(0xd06f1323), SPH_C32(0x50e81424), SPH_C32(0x01c36577), + SPH_C32(0x71473dd5) }, + { SPH_C32(0xf81202e0), SPH_C32(0x4a23c000), SPH_C32(0x5b710000), + SPH_C32(0x4bda0000), SPH_C32(0x7a221fcf), SPH_C32(0xec042795), + SPH_C32(0xeed70e76), SPH_C32(0x59eabcb9), SPH_C32(0x42a80179), + SPH_C32(0xa2f70000), SPH_C32(0x19410000), SPH_C32(0xe3670000), + SPH_C32(0xd2fa0a8a), SPH_C32(0xa800229e), SPH_C32(0x7b449439), + SPH_C32(0xef51a5cf) }, + { SPH_C32(0x0f6702e9), SPH_C32(0x851f0000), SPH_C32(0x98a70000), + SPH_C32(0x4f480000), SPH_C32(0x78b70666), SPH_C32(0x14ec112f), + SPH_C32(0x9450ff38), SPH_C32(0xc7fc24a3), SPH_C32(0x96c20179), + SPH_C32(0x2f3fc000), SPH_C32(0xbcee0000), SPH_C32(0xa94e0000), + SPH_C32(0x2eb448f0), SPH_C32(0x61b4a4f2), SPH_C32(0xe372023d), + SPH_C32(0x181766ef) }, + { SPH_C32(0xaf500240), SPH_C32(0xa0a90000), SPH_C32(0x1fc90000), + SPH_C32(0x36f80000), SPH_C32(0x4dcf5d81), SPH_C32(0x198433c5), + SPH_C32(0xe18625be), SPH_C32(0xebaf1f26), SPH_C32(0x16f30180), + SPH_C32(0x11590000), SPH_C32(0x8a8a0000), SPH_C32(0x99c80000), + SPH_C32(0xa5162fd5), SPH_C32(0xc3d77e6d), SPH_C32(0x92363e6d), + SPH_C32(0x49368b3e) }, + { SPH_C32(0x58250249), SPH_C32(0x6f95c000), SPH_C32(0xdc1f0000), + SPH_C32(0x326a0000), SPH_C32(0x4f5a4428), SPH_C32(0xe16c057f), + SPH_C32(0x9b01d4f0), SPH_C32(0x75b9873c), SPH_C32(0xc2990180), + SPH_C32(0x9c91c000), SPH_C32(0x2f250000), SPH_C32(0xd3e10000), + SPH_C32(0x59586daf), SPH_C32(0x0a63f801), SPH_C32(0x0a00a869), + SPH_C32(0xbe70481e) }, + { SPH_C32(0x7b3a0240), SPH_C32(0x2d61c000), SPH_C32(0xba660000), + SPH_C32(0x7cd10000), SPH_C32(0xb1811ffb), SPH_C32(0xd030b5a9), + SPH_C32(0x79b0b3ba), SPH_C32(0x1ce9dc06), SPH_C32(0x35ec0189), + SPH_C32(0x53ad0000), SPH_C32(0xecf30000), SPH_C32(0xd7730000), + SPH_C32(0x5bcd7406), SPH_C32(0xf28bcebb), SPH_C32(0x70875927), + SPH_C32(0x2066d004) }, + { SPH_C32(0x8c4f0249), SPH_C32(0xe25d0000), SPH_C32(0x79b00000), + SPH_C32(0x78430000), SPH_C32(0xb3140652), SPH_C32(0x28d88313), + SPH_C32(0x033742f4), SPH_C32(0x82ff441c), SPH_C32(0xe1860189), + SPH_C32(0xde65c000), SPH_C32(0x495c0000), SPH_C32(0x9d5a0000), + SPH_C32(0xa783367c), SPH_C32(0x3b3f48d7), SPH_C32(0xe8b1cf23), + SPH_C32(0xd7201324) }, + { SPH_C32(0xd81402b0), SPH_C32(0x51f30000), SPH_C32(0xea7b0000), + SPH_C32(0x02ec0000), SPH_C32(0xc4f8230d), SPH_C32(0x430fdfe0), + SPH_C32(0xea45e8a0), SPH_C32(0x24986aed), SPH_C32(0xe29f01d0), + SPH_C32(0x87410000), SPH_C32(0x9e2f0000), SPH_C32(0x9ad70000), + SPH_C32(0xe782516d), SPH_C32(0xa5680074), SPH_C32(0x0e924ebf), + SPH_C32(0xc3029e4a) }, + { SPH_C32(0x2f6102b9), SPH_C32(0x9ecfc000), SPH_C32(0x29ad0000), + SPH_C32(0x067e0000), SPH_C32(0xc66d3aa4), SPH_C32(0xbbe7e95a), + SPH_C32(0x90c219ee), SPH_C32(0xba8ef2f7), SPH_C32(0x36f501d0), + SPH_C32(0x0a89c000), SPH_C32(0x3b800000), SPH_C32(0xd0fe0000), + SPH_C32(0x1bcc1317), SPH_C32(0x6cdc8618), SPH_C32(0x96a4d8bb), + SPH_C32(0x34445d6a) }, + { SPH_C32(0x0c7e02b0), SPH_C32(0xdc3bc000), SPH_C32(0x4fd40000), + SPH_C32(0x48c50000), SPH_C32(0x38b66177), SPH_C32(0x8abb598c), + SPH_C32(0x72737ea4), SPH_C32(0xd3dea9cd), SPH_C32(0xc18001d9), + SPH_C32(0xc5b50000), SPH_C32(0xf8560000), SPH_C32(0xd46c0000), + SPH_C32(0x19590abe), SPH_C32(0x9434b0a2), SPH_C32(0xec2329f5), + SPH_C32(0xaa52c570) }, + { SPH_C32(0xfb0b02b9), SPH_C32(0x13070000), SPH_C32(0x8c020000), + SPH_C32(0x4c570000), SPH_C32(0x3a2378de), SPH_C32(0x72536f36), + SPH_C32(0x08f48fea), SPH_C32(0x4dc831d7), SPH_C32(0x15ea01d9), + SPH_C32(0x487dc000), SPH_C32(0x5df90000), SPH_C32(0x9e450000), + SPH_C32(0xe51748c4), SPH_C32(0x5d8036ce), SPH_C32(0x7415bff1), + SPH_C32(0x5d140650) }, + { SPH_C32(0xb3bb0360), SPH_C32(0xabc30000), SPH_C32(0x19b70000), + SPH_C32(0xe1c50000), SPH_C32(0xfdd3481e), SPH_C32(0xd61aa89f), + SPH_C32(0x33dae074), SPH_C32(0x001319e3), SPH_C32(0x21ec0140), + SPH_C32(0x7a570000), SPH_C32(0x3d5f0000), SPH_C32(0xf26d0000), + SPH_C32(0xfae130de), SPH_C32(0xc4dd1474), SPH_C32(0x1e67dc9c), + SPH_C32(0xffe1bcd9) }, + { SPH_C32(0x44ce0369), SPH_C32(0x64ffc000), SPH_C32(0xda610000), + SPH_C32(0xe5570000), SPH_C32(0xff4651b7), SPH_C32(0x2ef29e25), + SPH_C32(0x495d113a), SPH_C32(0x9e0581f9), SPH_C32(0xf5860140), + SPH_C32(0xf79fc000), SPH_C32(0x98f00000), SPH_C32(0xb8440000), + SPH_C32(0x06af72a4), SPH_C32(0x0d699218), SPH_C32(0x86514a98), + SPH_C32(0x08a77ff9) }, + { SPH_C32(0x67d10360), SPH_C32(0x260bc000), SPH_C32(0xbc180000), + SPH_C32(0xabec0000), SPH_C32(0x019d0a64), SPH_C32(0x1fae2ef3), + SPH_C32(0xabec7670), SPH_C32(0xf755dac3), SPH_C32(0x02f30149), + SPH_C32(0x38a30000), SPH_C32(0x5b260000), SPH_C32(0xbcd60000), + SPH_C32(0x043a6b0d), SPH_C32(0xf581a4a2), SPH_C32(0xfcd6bbd6), + SPH_C32(0x96b1e7e3) }, + { SPH_C32(0x90a40369), SPH_C32(0xe9370000), SPH_C32(0x7fce0000), + SPH_C32(0xaf7e0000), SPH_C32(0x030813cd), SPH_C32(0xe7461849), + SPH_C32(0xd16b873e), SPH_C32(0x694342d9), SPH_C32(0xd6990149), + SPH_C32(0xb56bc000), SPH_C32(0xfe890000), SPH_C32(0xf6ff0000), + SPH_C32(0xf8742977), SPH_C32(0x3c3522ce), SPH_C32(0x64e02dd2), + SPH_C32(0x61f724c3) }, + { SPH_C32(0xc4ff0390), SPH_C32(0x5a990000), SPH_C32(0xec050000), + SPH_C32(0xd5d10000), SPH_C32(0x74e43692), SPH_C32(0x8c9144ba), + SPH_C32(0x38192d6a), SPH_C32(0xcf246c28), SPH_C32(0xd5800110), + SPH_C32(0xec4f0000), SPH_C32(0x29fa0000), SPH_C32(0xf1720000), + SPH_C32(0xb8754e66), SPH_C32(0xa2626a6d), SPH_C32(0x82c3ac4e), + SPH_C32(0x75d5a9ad) }, + { SPH_C32(0x338a0399), SPH_C32(0x95a5c000), SPH_C32(0x2fd30000), + SPH_C32(0xd1430000), SPH_C32(0x76712f3b), SPH_C32(0x74797200), + SPH_C32(0x429edc24), SPH_C32(0x5132f432), SPH_C32(0x01ea0110), + SPH_C32(0x6187c000), SPH_C32(0x8c550000), SPH_C32(0xbb5b0000), + SPH_C32(0x443b0c1c), SPH_C32(0x6bd6ec01), SPH_C32(0x1af53a4a), + SPH_C32(0x82936a8d) }, + { SPH_C32(0x10950390), SPH_C32(0xd751c000), SPH_C32(0x49aa0000), + SPH_C32(0x9ff80000), SPH_C32(0x88aa74e8), SPH_C32(0x4525c2d6), + SPH_C32(0xa02fbb6e), SPH_C32(0x3862af08), SPH_C32(0xf69f0119), + SPH_C32(0xaebb0000), SPH_C32(0x4f830000), SPH_C32(0xbfc90000), + SPH_C32(0x46ae15b5), SPH_C32(0x933edabb), SPH_C32(0x6072cb04), + SPH_C32(0x1c85f297) }, + { SPH_C32(0xe7e00399), SPH_C32(0x186d0000), SPH_C32(0x8a7c0000), + SPH_C32(0x9b6a0000), SPH_C32(0x8a3f6d41), SPH_C32(0xbdcdf46c), + SPH_C32(0xdaa84a20), SPH_C32(0xa6743712), SPH_C32(0x22f50119), + SPH_C32(0x2373c000), SPH_C32(0xea2c0000), SPH_C32(0xf5e00000), + SPH_C32(0xbae057cf), SPH_C32(0x5a8a5cd7), SPH_C32(0xf8445d00), + SPH_C32(0xebc331b7) }, + { SPH_C32(0x47d70330), SPH_C32(0x3ddb0000), SPH_C32(0x0d120000), + SPH_C32(0xe2da0000), SPH_C32(0xbf4736a6), SPH_C32(0xb0a5d686), + SPH_C32(0xaf7e90a6), SPH_C32(0x8a270c97), SPH_C32(0xa2c401e0), + SPH_C32(0x1d150000), SPH_C32(0xdc480000), SPH_C32(0xc5660000), + SPH_C32(0x314230ea), SPH_C32(0xf8e98648), SPH_C32(0x89006150), + SPH_C32(0xbae2dc66) }, + { SPH_C32(0xb0a20339), SPH_C32(0xf2e7c000), SPH_C32(0xcec40000), + SPH_C32(0xe6480000), SPH_C32(0xbdd22f0f), SPH_C32(0x484de03c), + SPH_C32(0xd5f961e8), SPH_C32(0x1431948d), SPH_C32(0x76ae01e0), + SPH_C32(0x90ddc000), SPH_C32(0x79e70000), SPH_C32(0x8f4f0000), + SPH_C32(0xcd0c7290), SPH_C32(0x315d0024), SPH_C32(0x1136f754), + SPH_C32(0x4da41f46) }, + { SPH_C32(0x93bd0330), SPH_C32(0xb013c000), SPH_C32(0xa8bd0000), + SPH_C32(0xa8f30000), SPH_C32(0x430974dc), SPH_C32(0x791150ea), + SPH_C32(0x374806a2), SPH_C32(0x7d61cfb7), SPH_C32(0x81db01e9), + SPH_C32(0x5fe10000), SPH_C32(0xba310000), SPH_C32(0x8bdd0000), + SPH_C32(0xcf996b39), SPH_C32(0xc9b5369e), SPH_C32(0x6bb1061a), + SPH_C32(0xd3b2875c) }, + { SPH_C32(0x64c80339), SPH_C32(0x7f2f0000), SPH_C32(0x6b6b0000), + SPH_C32(0xac610000), SPH_C32(0x419c6d75), SPH_C32(0x81f96650), + SPH_C32(0x4dcff7ec), SPH_C32(0xe37757ad), SPH_C32(0x55b101e9), + SPH_C32(0xd229c000), SPH_C32(0x1f9e0000), SPH_C32(0xc1f40000), + SPH_C32(0x33d72943), SPH_C32(0x0001b0f2), SPH_C32(0xf387901e), + SPH_C32(0x24f4447c) }, + { SPH_C32(0x309303c0), SPH_C32(0xcc810000), SPH_C32(0xf8a00000), + SPH_C32(0xd6ce0000), SPH_C32(0x3670482a), SPH_C32(0xea2e3aa3), + SPH_C32(0xa4bd5db8), SPH_C32(0x4510795c), SPH_C32(0x56a801b0), + SPH_C32(0x8b0d0000), SPH_C32(0xc8ed0000), SPH_C32(0xc6790000), + SPH_C32(0x73d64e52), SPH_C32(0x9e56f851), SPH_C32(0x15a41182), + SPH_C32(0x30d6c912) }, + { SPH_C32(0xc7e603c9), SPH_C32(0x03bdc000), SPH_C32(0x3b760000), + SPH_C32(0xd25c0000), SPH_C32(0x34e55183), SPH_C32(0x12c60c19), + SPH_C32(0xde3aacf6), SPH_C32(0xdb06e146), SPH_C32(0x82c201b0), + SPH_C32(0x06c5c000), SPH_C32(0x6d420000), SPH_C32(0x8c500000), + SPH_C32(0x8f980c28), SPH_C32(0x57e27e3d), SPH_C32(0x8d928786), + SPH_C32(0xc7900a32) }, + { SPH_C32(0xe4f903c0), SPH_C32(0x4149c000), SPH_C32(0x5d0f0000), + SPH_C32(0x9ce70000), SPH_C32(0xca3e0a50), SPH_C32(0x239abccf), + SPH_C32(0x3c8bcbbc), SPH_C32(0xb256ba7c), SPH_C32(0x75b701b9), + SPH_C32(0xc9f90000), SPH_C32(0xae940000), SPH_C32(0x88c20000), + SPH_C32(0x8d0d1581), SPH_C32(0xaf0a4887), SPH_C32(0xf71576c8), + SPH_C32(0x59869228) }, + { SPH_C32(0x138c03c9), SPH_C32(0x8e750000), SPH_C32(0x9ed90000), + SPH_C32(0x98750000), SPH_C32(0xc8ab13f9), SPH_C32(0xdb728a75), + SPH_C32(0x460c3af2), SPH_C32(0x2c402266), SPH_C32(0xa1dd01b9), + SPH_C32(0x4431c000), SPH_C32(0x0b3b0000), SPH_C32(0xc2eb0000), + SPH_C32(0x714357fb), SPH_C32(0x66beceeb), SPH_C32(0x6f23e0cc), + SPH_C32(0xaec05108) } +}; + +static const sph_u32 T512_14[128][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0xb83d0000), SPH_C32(0x16710600), SPH_C32(0x379a0000), + SPH_C32(0xf5b10000), SPH_C32(0x228161ac), SPH_C32(0xae48f145), + SPH_C32(0x66241616), SPH_C32(0xc5c1eb3e), SPH_C32(0xfd250000), + SPH_C32(0xb3c41100), SPH_C32(0xcef00000), SPH_C32(0xcef90000), + SPH_C32(0x3c4d7580), SPH_C32(0x8d5b6493), SPH_C32(0x7098b0a6), + SPH_C32(0x1af21fe1) }, + { SPH_C32(0x75a40000), SPH_C32(0xc28b2700), SPH_C32(0x94a40000), + SPH_C32(0x90f50000), SPH_C32(0xfb7857e0), SPH_C32(0x49ce0bae), + SPH_C32(0x1767c483), SPH_C32(0xaedf667e), SPH_C32(0xd1660000), + SPH_C32(0x1bbc0300), SPH_C32(0x9eec0000), SPH_C32(0xf6940000), + SPH_C32(0x03024527), SPH_C32(0xcf70fcf2), SPH_C32(0xb4431b17), + SPH_C32(0x857f3c2b) }, + { SPH_C32(0xcd990000), SPH_C32(0xd4fa2100), SPH_C32(0xa33e0000), + SPH_C32(0x65440000), SPH_C32(0xd9f9364c), SPH_C32(0xe786faeb), + SPH_C32(0x7143d295), SPH_C32(0x6b1e8d40), SPH_C32(0x2c430000), + SPH_C32(0xa8781200), SPH_C32(0x501c0000), SPH_C32(0x386d0000), + SPH_C32(0x3f4f30a7), SPH_C32(0x422b9861), SPH_C32(0xc4dbabb1), + SPH_C32(0x9f8d23ca) }, + { SPH_C32(0xd1660000), SPH_C32(0x1bbc0300), SPH_C32(0x9eec0000), + SPH_C32(0xf6940000), SPH_C32(0x03024527), SPH_C32(0xcf70fcf2), + SPH_C32(0xb4431b17), SPH_C32(0x857f3c2b), SPH_C32(0xa4c20000), + SPH_C32(0xd9372400), SPH_C32(0x0a480000), SPH_C32(0x66610000), + SPH_C32(0xf87a12c7), SPH_C32(0x86bef75c), SPH_C32(0xa324df94), + SPH_C32(0x2ba05a55) }, + { SPH_C32(0x695b0000), SPH_C32(0x0dcd0500), SPH_C32(0xa9760000), + SPH_C32(0x03250000), SPH_C32(0x2183248b), SPH_C32(0x61380db7), + SPH_C32(0xd2670d01), SPH_C32(0x40bed715), SPH_C32(0x59e70000), + SPH_C32(0x6af33500), SPH_C32(0xc4b80000), SPH_C32(0xa8980000), + SPH_C32(0xc4376747), SPH_C32(0x0be593cf), SPH_C32(0xd3bc6f32), + SPH_C32(0x315245b4) }, + { SPH_C32(0xa4c20000), SPH_C32(0xd9372400), SPH_C32(0x0a480000), + SPH_C32(0x66610000), SPH_C32(0xf87a12c7), SPH_C32(0x86bef75c), + SPH_C32(0xa324df94), SPH_C32(0x2ba05a55), SPH_C32(0x75a40000), + SPH_C32(0xc28b2700), SPH_C32(0x94a40000), SPH_C32(0x90f50000), + SPH_C32(0xfb7857e0), SPH_C32(0x49ce0bae), SPH_C32(0x1767c483), + SPH_C32(0xaedf667e) }, + { SPH_C32(0x1cff0000), SPH_C32(0xcf462200), SPH_C32(0x3dd20000), + SPH_C32(0x93d00000), SPH_C32(0xdafb736b), SPH_C32(0x28f60619), + SPH_C32(0xc500c982), SPH_C32(0xee61b16b), SPH_C32(0x88810000), + SPH_C32(0x714f3600), SPH_C32(0x5a540000), SPH_C32(0x5e0c0000), + SPH_C32(0xc7352260), SPH_C32(0xc4956f3d), SPH_C32(0x67ff7425), + SPH_C32(0xb42d799f) }, + { SPH_C32(0x75c90003), SPH_C32(0x0e10c000), SPH_C32(0xd1200000), + SPH_C32(0xbaea0000), SPH_C32(0x8bc42f3e), SPH_C32(0x8758b757), + SPH_C32(0xbb28761d), SPH_C32(0x00b72e2b), SPH_C32(0xeecf0001), + SPH_C32(0x6f564000), SPH_C32(0xf33e0000), SPH_C32(0xa79e0000), + SPH_C32(0xbdb57219), SPH_C32(0xb711ebc5), SPH_C32(0x4a3b40ba), + SPH_C32(0xfeabf254) }, + { SPH_C32(0xcdf40003), SPH_C32(0x1861c600), SPH_C32(0xe6ba0000), + SPH_C32(0x4f5b0000), SPH_C32(0xa9454e92), SPH_C32(0x29104612), + SPH_C32(0xdd0c600b), SPH_C32(0xc576c515), SPH_C32(0x13ea0001), + SPH_C32(0xdc925100), SPH_C32(0x3dce0000), SPH_C32(0x69670000), + SPH_C32(0x81f80799), SPH_C32(0x3a4a8f56), SPH_C32(0x3aa3f01c), + SPH_C32(0xe459edb5) }, + { SPH_C32(0x006d0003), SPH_C32(0xcc9be700), SPH_C32(0x45840000), + SPH_C32(0x2a1f0000), SPH_C32(0x70bc78de), SPH_C32(0xce96bcf9), + SPH_C32(0xac4fb29e), SPH_C32(0xae684855), SPH_C32(0x3fa90001), + SPH_C32(0x74ea4300), SPH_C32(0x6dd20000), SPH_C32(0x510a0000), + SPH_C32(0xbeb7373e), SPH_C32(0x78611737), SPH_C32(0xfe785bad), + SPH_C32(0x7bd4ce7f) }, + { SPH_C32(0xb8500003), SPH_C32(0xdaeae100), SPH_C32(0x721e0000), + SPH_C32(0xdfae0000), SPH_C32(0x523d1972), SPH_C32(0x60de4dbc), + SPH_C32(0xca6ba488), SPH_C32(0x6ba9a36b), SPH_C32(0xc28c0001), + SPH_C32(0xc72e5200), SPH_C32(0xa3220000), SPH_C32(0x9ff30000), + SPH_C32(0x82fa42be), SPH_C32(0xf53a73a4), SPH_C32(0x8ee0eb0b), + SPH_C32(0x6126d19e) }, + { SPH_C32(0xa4af0003), SPH_C32(0x15acc300), SPH_C32(0x4fcc0000), + SPH_C32(0x4c7e0000), SPH_C32(0x88c66a19), SPH_C32(0x48284ba5), + SPH_C32(0x0f6b6d0a), SPH_C32(0x85c81200), SPH_C32(0x4a0d0001), + SPH_C32(0xb6616400), SPH_C32(0xf9760000), SPH_C32(0xc1ff0000), + SPH_C32(0x45cf60de), SPH_C32(0x31af1c99), SPH_C32(0xe91f9f2e), + SPH_C32(0xd50ba801) }, + { SPH_C32(0x1c920003), SPH_C32(0x03ddc500), SPH_C32(0x78560000), + SPH_C32(0xb9cf0000), SPH_C32(0xaa470bb5), SPH_C32(0xe660bae0), + SPH_C32(0x694f7b1c), SPH_C32(0x4009f93e), SPH_C32(0xb7280001), + SPH_C32(0x05a57500), SPH_C32(0x37860000), SPH_C32(0x0f060000), + SPH_C32(0x7982155e), SPH_C32(0xbcf4780a), SPH_C32(0x99872f88), + SPH_C32(0xcff9b7e0) }, + { SPH_C32(0xd10b0003), SPH_C32(0xd727e400), SPH_C32(0xdb680000), + SPH_C32(0xdc8b0000), SPH_C32(0x73be3df9), SPH_C32(0x01e6400b), + SPH_C32(0x180ca989), SPH_C32(0x2b17747e), SPH_C32(0x9b6b0001), + SPH_C32(0xaddd6700), SPH_C32(0x679a0000), SPH_C32(0x376b0000), + SPH_C32(0x46cd25f9), SPH_C32(0xfedfe06b), SPH_C32(0x5d5c8439), + SPH_C32(0x5074942a) }, + { SPH_C32(0x69360003), SPH_C32(0xc156e200), SPH_C32(0xecf20000), + SPH_C32(0x293a0000), SPH_C32(0x513f5c55), SPH_C32(0xafaeb14e), + SPH_C32(0x7e28bf9f), SPH_C32(0xeed69f40), SPH_C32(0x664e0001), + SPH_C32(0x1e197600), SPH_C32(0xa96a0000), SPH_C32(0xf9920000), + SPH_C32(0x7a805079), SPH_C32(0x738484f8), SPH_C32(0x2dc4349f), + SPH_C32(0x4a868bcb) }, + { SPH_C32(0xeecf0001), SPH_C32(0x6f564000), SPH_C32(0xf33e0000), + SPH_C32(0xa79e0000), SPH_C32(0xbdb57219), SPH_C32(0xb711ebc5), + SPH_C32(0x4a3b40ba), SPH_C32(0xfeabf254), SPH_C32(0x9b060002), + SPH_C32(0x61468000), SPH_C32(0x221e0000), SPH_C32(0x1d740000), + SPH_C32(0x36715d27), SPH_C32(0x30495c92), SPH_C32(0xf11336a7), + SPH_C32(0xfe1cdc7f) }, + { SPH_C32(0x56f20001), SPH_C32(0x79274600), SPH_C32(0xc4a40000), + SPH_C32(0x522f0000), SPH_C32(0x9f3413b5), SPH_C32(0x19591a80), + SPH_C32(0x2c1f56ac), SPH_C32(0x3b6a196a), SPH_C32(0x66230002), + SPH_C32(0xd2829100), SPH_C32(0xecee0000), SPH_C32(0xd38d0000), + SPH_C32(0x0a3c28a7), SPH_C32(0xbd123801), SPH_C32(0x818b8601), + SPH_C32(0xe4eec39e) }, + { SPH_C32(0x9b6b0001), SPH_C32(0xaddd6700), SPH_C32(0x679a0000), + SPH_C32(0x376b0000), SPH_C32(0x46cd25f9), SPH_C32(0xfedfe06b), + SPH_C32(0x5d5c8439), SPH_C32(0x5074942a), SPH_C32(0x4a600002), + SPH_C32(0x7afa8300), SPH_C32(0xbcf20000), SPH_C32(0xebe00000), + SPH_C32(0x35731800), SPH_C32(0xff39a060), SPH_C32(0x45502db0), + SPH_C32(0x7b63e054) }, + { SPH_C32(0x23560001), SPH_C32(0xbbac6100), SPH_C32(0x50000000), + SPH_C32(0xc2da0000), SPH_C32(0x644c4455), SPH_C32(0x5097112e), + SPH_C32(0x3b78922f), SPH_C32(0x95b57f14), SPH_C32(0xb7450002), + SPH_C32(0xc93e9200), SPH_C32(0x72020000), SPH_C32(0x25190000), + SPH_C32(0x093e6d80), SPH_C32(0x7262c4f3), SPH_C32(0x35c89d16), + SPH_C32(0x6191ffb5) }, + { SPH_C32(0x3fa90001), SPH_C32(0x74ea4300), SPH_C32(0x6dd20000), + SPH_C32(0x510a0000), SPH_C32(0xbeb7373e), SPH_C32(0x78611737), + SPH_C32(0xfe785bad), SPH_C32(0x7bd4ce7f), SPH_C32(0x3fc40002), + SPH_C32(0xb871a400), SPH_C32(0x28560000), SPH_C32(0x7b150000), + SPH_C32(0xce0b4fe0), SPH_C32(0xb6f7abce), SPH_C32(0x5237e933), + SPH_C32(0xd5bc862a) }, + { SPH_C32(0x87940001), SPH_C32(0x629b4500), SPH_C32(0x5a480000), + SPH_C32(0xa4bb0000), SPH_C32(0x9c365692), SPH_C32(0xd629e672), + SPH_C32(0x985c4dbb), SPH_C32(0xbe152541), SPH_C32(0xc2e10002), + SPH_C32(0x0bb5b500), SPH_C32(0xe6a60000), SPH_C32(0xb5ec0000), + SPH_C32(0xf2463a60), SPH_C32(0x3baccf5d), SPH_C32(0x22af5995), + SPH_C32(0xcf4e99cb) }, + { SPH_C32(0x4a0d0001), SPH_C32(0xb6616400), SPH_C32(0xf9760000), + SPH_C32(0xc1ff0000), SPH_C32(0x45cf60de), SPH_C32(0x31af1c99), + SPH_C32(0xe91f9f2e), SPH_C32(0xd50ba801), SPH_C32(0xeea20002), + SPH_C32(0xa3cda700), SPH_C32(0xb6ba0000), SPH_C32(0x8d810000), + SPH_C32(0xcd090ac7), SPH_C32(0x7987573c), SPH_C32(0xe674f224), + SPH_C32(0x50c3ba01) }, + { SPH_C32(0xf2300001), SPH_C32(0xa0106200), SPH_C32(0xceec0000), + SPH_C32(0x344e0000), SPH_C32(0x674e0172), SPH_C32(0x9fe7eddc), + SPH_C32(0x8f3b8938), SPH_C32(0x10ca433f), SPH_C32(0x13870002), + SPH_C32(0x1009b600), SPH_C32(0x784a0000), SPH_C32(0x43780000), + SPH_C32(0xf1447f47), SPH_C32(0xf4dc33af), SPH_C32(0x96ec4282), + SPH_C32(0x4a31a5e0) }, + { SPH_C32(0x9b060002), SPH_C32(0x61468000), SPH_C32(0x221e0000), + SPH_C32(0x1d740000), SPH_C32(0x36715d27), SPH_C32(0x30495c92), + SPH_C32(0xf11336a7), SPH_C32(0xfe1cdc7f), SPH_C32(0x75c90003), + SPH_C32(0x0e10c000), SPH_C32(0xd1200000), SPH_C32(0xbaea0000), + SPH_C32(0x8bc42f3e), SPH_C32(0x8758b757), SPH_C32(0xbb28761d), + SPH_C32(0x00b72e2b) }, + { SPH_C32(0x233b0002), SPH_C32(0x77378600), SPH_C32(0x15840000), + SPH_C32(0xe8c50000), SPH_C32(0x14f03c8b), SPH_C32(0x9e01add7), + SPH_C32(0x973720b1), SPH_C32(0x3bdd3741), SPH_C32(0x88ec0003), + SPH_C32(0xbdd4d100), SPH_C32(0x1fd00000), SPH_C32(0x74130000), + SPH_C32(0xb7895abe), SPH_C32(0x0a03d3c4), SPH_C32(0xcbb0c6bb), + SPH_C32(0x1a4531ca) }, + { SPH_C32(0xeea20002), SPH_C32(0xa3cda700), SPH_C32(0xb6ba0000), + SPH_C32(0x8d810000), SPH_C32(0xcd090ac7), SPH_C32(0x7987573c), + SPH_C32(0xe674f224), SPH_C32(0x50c3ba01), SPH_C32(0xa4af0003), + SPH_C32(0x15acc300), SPH_C32(0x4fcc0000), SPH_C32(0x4c7e0000), + SPH_C32(0x88c66a19), SPH_C32(0x48284ba5), SPH_C32(0x0f6b6d0a), + SPH_C32(0x85c81200) }, + { SPH_C32(0x569f0002), SPH_C32(0xb5bca100), SPH_C32(0x81200000), + SPH_C32(0x78300000), SPH_C32(0xef886b6b), SPH_C32(0xd7cfa679), + SPH_C32(0x8050e432), SPH_C32(0x9502513f), SPH_C32(0x598a0003), + SPH_C32(0xa668d200), SPH_C32(0x813c0000), SPH_C32(0x82870000), + SPH_C32(0xb48b1f99), SPH_C32(0xc5732f36), SPH_C32(0x7ff3ddac), + SPH_C32(0x9f3a0de1) }, + { SPH_C32(0x4a600002), SPH_C32(0x7afa8300), SPH_C32(0xbcf20000), + SPH_C32(0xebe00000), SPH_C32(0x35731800), SPH_C32(0xff39a060), + SPH_C32(0x45502db0), SPH_C32(0x7b63e054), SPH_C32(0xd10b0003), + SPH_C32(0xd727e400), SPH_C32(0xdb680000), SPH_C32(0xdc8b0000), + SPH_C32(0x73be3df9), SPH_C32(0x01e6400b), SPH_C32(0x180ca989), + SPH_C32(0x2b17747e) }, + { SPH_C32(0xf25d0002), SPH_C32(0x6c8b8500), SPH_C32(0x8b680000), + SPH_C32(0x1e510000), SPH_C32(0x17f279ac), SPH_C32(0x51715125), + SPH_C32(0x23743ba6), SPH_C32(0xbea20b6a), SPH_C32(0x2c2e0003), + SPH_C32(0x64e3f500), SPH_C32(0x15980000), SPH_C32(0x12720000), + SPH_C32(0x4ff34879), SPH_C32(0x8cbd2498), SPH_C32(0x6894192f), + SPH_C32(0x31e56b9f) }, + { SPH_C32(0x3fc40002), SPH_C32(0xb871a400), SPH_C32(0x28560000), + SPH_C32(0x7b150000), SPH_C32(0xce0b4fe0), SPH_C32(0xb6f7abce), + SPH_C32(0x5237e933), SPH_C32(0xd5bc862a), SPH_C32(0x006d0003), + SPH_C32(0xcc9be700), SPH_C32(0x45840000), SPH_C32(0x2a1f0000), + SPH_C32(0x70bc78de), SPH_C32(0xce96bcf9), SPH_C32(0xac4fb29e), + SPH_C32(0xae684855) }, + { SPH_C32(0x87f90002), SPH_C32(0xae00a200), SPH_C32(0x1fcc0000), + SPH_C32(0x8ea40000), SPH_C32(0xec8a2e4c), SPH_C32(0x18bf5a8b), + SPH_C32(0x3413ff25), SPH_C32(0x107d6d14), SPH_C32(0xfd480003), + SPH_C32(0x7f5ff600), SPH_C32(0x8b740000), SPH_C32(0xe4e60000), + SPH_C32(0x4cf10d5e), SPH_C32(0x43cdd86a), SPH_C32(0xdcd70238), + SPH_C32(0xb49a57b4) }, + { SPH_C32(0xf6800005), SPH_C32(0x3443c000), SPH_C32(0x24070000), + SPH_C32(0x8f3d0000), SPH_C32(0x21373bfb), SPH_C32(0x0ab8d5ae), + SPH_C32(0xcdc58b19), SPH_C32(0xd795ba31), SPH_C32(0xa67f0001), + SPH_C32(0x71378000), SPH_C32(0x19fc0000), SPH_C32(0x96db0000), + SPH_C32(0x3a8b6dfd), SPH_C32(0xebcaaef3), SPH_C32(0x2c6d478f), + SPH_C32(0xac8e6c88) }, + { SPH_C32(0x4ebd0005), SPH_C32(0x2232c600), SPH_C32(0x139d0000), + SPH_C32(0x7a8c0000), SPH_C32(0x03b65a57), SPH_C32(0xa4f024eb), + SPH_C32(0xabe19d0f), SPH_C32(0x1254510f), SPH_C32(0x5b5a0001), + SPH_C32(0xc2f39100), SPH_C32(0xd70c0000), SPH_C32(0x58220000), + SPH_C32(0x06c6187d), SPH_C32(0x6691ca60), SPH_C32(0x5cf5f729), + SPH_C32(0xb67c7369) }, + { SPH_C32(0x83240005), SPH_C32(0xf6c8e700), SPH_C32(0xb0a30000), + SPH_C32(0x1fc80000), SPH_C32(0xda4f6c1b), SPH_C32(0x4376de00), + SPH_C32(0xdaa24f9a), SPH_C32(0x794adc4f), SPH_C32(0x77190001), + SPH_C32(0x6a8b8300), SPH_C32(0x87100000), SPH_C32(0x604f0000), + SPH_C32(0x398928da), SPH_C32(0x24ba5201), SPH_C32(0x982e5c98), + SPH_C32(0x29f150a3) }, + { SPH_C32(0x3b190005), SPH_C32(0xe0b9e100), SPH_C32(0x87390000), + SPH_C32(0xea790000), SPH_C32(0xf8ce0db7), SPH_C32(0xed3e2f45), + SPH_C32(0xbc86598c), SPH_C32(0xbc8b3771), SPH_C32(0x8a3c0001), + SPH_C32(0xd94f9200), SPH_C32(0x49e00000), SPH_C32(0xaeb60000), + SPH_C32(0x05c45d5a), SPH_C32(0xa9e13692), SPH_C32(0xe8b6ec3e), + SPH_C32(0x33034f42) }, + { SPH_C32(0x27e60005), SPH_C32(0x2fffc300), SPH_C32(0xbaeb0000), + SPH_C32(0x79a90000), SPH_C32(0x22357edc), SPH_C32(0xc5c8295c), + SPH_C32(0x7986900e), SPH_C32(0x52ea861a), SPH_C32(0x02bd0001), + SPH_C32(0xa800a400), SPH_C32(0x13b40000), SPH_C32(0xf0ba0000), + SPH_C32(0xc2f17f3a), SPH_C32(0x6d7459af), SPH_C32(0x8f49981b), + SPH_C32(0x872e36dd) }, + { SPH_C32(0x9fdb0005), SPH_C32(0x398ec500), SPH_C32(0x8d710000), + SPH_C32(0x8c180000), SPH_C32(0x00b41f70), SPH_C32(0x6b80d819), + SPH_C32(0x1fa28618), SPH_C32(0x972b6d24), SPH_C32(0xff980001), + SPH_C32(0x1bc4b500), SPH_C32(0xdd440000), SPH_C32(0x3e430000), + SPH_C32(0xfebc0aba), SPH_C32(0xe02f3d3c), SPH_C32(0xffd128bd), + SPH_C32(0x9ddc293c) }, + { SPH_C32(0x52420005), SPH_C32(0xed74e400), SPH_C32(0x2e4f0000), + SPH_C32(0xe95c0000), SPH_C32(0xd94d293c), SPH_C32(0x8c0622f2), + SPH_C32(0x6ee1548d), SPH_C32(0xfc35e064), SPH_C32(0xd3db0001), + SPH_C32(0xb3bca700), SPH_C32(0x8d580000), SPH_C32(0x062e0000), + SPH_C32(0xc1f33a1d), SPH_C32(0xa204a55d), SPH_C32(0x3b0a830c), + SPH_C32(0x02510af6) }, + { SPH_C32(0xea7f0005), SPH_C32(0xfb05e200), SPH_C32(0x19d50000), + SPH_C32(0x1ced0000), SPH_C32(0xfbcc4890), SPH_C32(0x224ed3b7), + SPH_C32(0x08c5429b), SPH_C32(0x39f40b5a), SPH_C32(0x2efe0001), + SPH_C32(0x0078b600), SPH_C32(0x43a80000), SPH_C32(0xc8d70000), + SPH_C32(0xfdbe4f9d), SPH_C32(0x2f5fc1ce), SPH_C32(0x4b9233aa), + SPH_C32(0x18a31517) }, + { SPH_C32(0x83490006), SPH_C32(0x3a530000), SPH_C32(0xf5270000), + SPH_C32(0x35d70000), SPH_C32(0xaaf314c5), SPH_C32(0x8de062f9), + SPH_C32(0x76edfd04), SPH_C32(0xd722941a), SPH_C32(0x48b00000), + SPH_C32(0x1e61c000), SPH_C32(0xeac20000), SPH_C32(0x31450000), + SPH_C32(0x873e1fe4), SPH_C32(0x5cdb4536), SPH_C32(0x66560735), + SPH_C32(0x52259edc) }, + { SPH_C32(0x3b740006), SPH_C32(0x2c220600), SPH_C32(0xc2bd0000), + SPH_C32(0xc0660000), SPH_C32(0x88727569), SPH_C32(0x23a893bc), + SPH_C32(0x10c9eb12), SPH_C32(0x12e37f24), SPH_C32(0xb5950000), + SPH_C32(0xada5d100), SPH_C32(0x24320000), SPH_C32(0xffbc0000), + SPH_C32(0xbb736a64), SPH_C32(0xd18021a5), SPH_C32(0x16ceb793), + SPH_C32(0x48d7813d) }, + { SPH_C32(0xf6ed0006), SPH_C32(0xf8d82700), SPH_C32(0x61830000), + SPH_C32(0xa5220000), SPH_C32(0x518b4325), SPH_C32(0xc42e6957), + SPH_C32(0x618a3987), SPH_C32(0x79fdf264), SPH_C32(0x99d60000), + SPH_C32(0x05ddc300), SPH_C32(0x742e0000), SPH_C32(0xc7d10000), + SPH_C32(0x843c5ac3), SPH_C32(0x93abb9c4), SPH_C32(0xd2151c22), + SPH_C32(0xd75aa2f7) }, + { SPH_C32(0x4ed00006), SPH_C32(0xeea92100), SPH_C32(0x56190000), + SPH_C32(0x50930000), SPH_C32(0x730a2289), SPH_C32(0x6a669812), + SPH_C32(0x07ae2f91), SPH_C32(0xbc3c195a), SPH_C32(0x64f30000), + SPH_C32(0xb619d200), SPH_C32(0xbade0000), SPH_C32(0x09280000), + SPH_C32(0xb8712f43), SPH_C32(0x1ef0dd57), SPH_C32(0xa28dac84), + SPH_C32(0xcda8bd16) }, + { SPH_C32(0x522f0006), SPH_C32(0x21ef0300), SPH_C32(0x6bcb0000), + SPH_C32(0xc3430000), SPH_C32(0xa9f151e2), SPH_C32(0x42909e0b), + SPH_C32(0xc2aee613), SPH_C32(0x525da831), SPH_C32(0xec720000), + SPH_C32(0xc756e400), SPH_C32(0xe08a0000), SPH_C32(0x57240000), + SPH_C32(0x7f440d23), SPH_C32(0xda65b26a), SPH_C32(0xc572d8a1), + SPH_C32(0x7985c489) }, + { SPH_C32(0xea120006), SPH_C32(0x379e0500), SPH_C32(0x5c510000), + SPH_C32(0x36f20000), SPH_C32(0x8b70304e), SPH_C32(0xecd86f4e), + SPH_C32(0xa48af005), SPH_C32(0x979c430f), SPH_C32(0x11570000), + SPH_C32(0x7492f500), SPH_C32(0x2e7a0000), SPH_C32(0x99dd0000), + SPH_C32(0x430978a3), SPH_C32(0x573ed6f9), SPH_C32(0xb5ea6807), + SPH_C32(0x6377db68) }, + { SPH_C32(0x278b0006), SPH_C32(0xe3642400), SPH_C32(0xff6f0000), + SPH_C32(0x53b60000), SPH_C32(0x52890602), SPH_C32(0x0b5e95a5), + SPH_C32(0xd5c92290), SPH_C32(0xfc82ce4f), SPH_C32(0x3d140000), + SPH_C32(0xdceae700), SPH_C32(0x7e660000), SPH_C32(0xa1b00000), + SPH_C32(0x7c464804), SPH_C32(0x15154e98), SPH_C32(0x7131c3b6), + SPH_C32(0xfcfaf8a2) }, + { SPH_C32(0x9fb60006), SPH_C32(0xf5152200), SPH_C32(0xc8f50000), + SPH_C32(0xa6070000), SPH_C32(0x700867ae), SPH_C32(0xa51664e0), + SPH_C32(0xb3ed3486), SPH_C32(0x39432571), SPH_C32(0xc0310000), + SPH_C32(0x6f2ef600), SPH_C32(0xb0960000), SPH_C32(0x6f490000), + SPH_C32(0x400b3d84), SPH_C32(0x984e2a0b), SPH_C32(0x01a97310), + SPH_C32(0xe608e743) }, + { SPH_C32(0x184f0004), SPH_C32(0x5b158000), SPH_C32(0xd7390000), + SPH_C32(0x28a30000), SPH_C32(0x9c8249e2), SPH_C32(0xbda93e6b), + SPH_C32(0x87fecba3), SPH_C32(0x293e4865), SPH_C32(0x3d790003), + SPH_C32(0x10710000), SPH_C32(0x3be20000), SPH_C32(0x8baf0000), + SPH_C32(0x0cfa30da), SPH_C32(0xdb83f261), SPH_C32(0xdd7e7128), + SPH_C32(0x5292b0f7) }, + { SPH_C32(0xa0720004), SPH_C32(0x4d648600), SPH_C32(0xe0a30000), + SPH_C32(0xdd120000), SPH_C32(0xbe03284e), SPH_C32(0x13e1cf2e), + SPH_C32(0xe1daddb5), SPH_C32(0xecffa35b), SPH_C32(0xc05c0003), + SPH_C32(0xa3b51100), SPH_C32(0xf5120000), SPH_C32(0x45560000), + SPH_C32(0x30b7455a), SPH_C32(0x56d896f2), SPH_C32(0xade6c18e), + SPH_C32(0x4860af16) }, + { SPH_C32(0x6deb0004), SPH_C32(0x999ea700), SPH_C32(0x439d0000), + SPH_C32(0xb8560000), SPH_C32(0x67fa1e02), SPH_C32(0xf46735c5), + SPH_C32(0x90990f20), SPH_C32(0x87e12e1b), SPH_C32(0xec1f0003), + SPH_C32(0x0bcd0300), SPH_C32(0xa50e0000), SPH_C32(0x7d3b0000), + SPH_C32(0x0ff875fd), SPH_C32(0x14f30e93), SPH_C32(0x693d6a3f), + SPH_C32(0xd7ed8cdc) }, + { SPH_C32(0xd5d60004), SPH_C32(0x8fefa100), SPH_C32(0x74070000), + SPH_C32(0x4de70000), SPH_C32(0x457b7fae), SPH_C32(0x5a2fc480), + SPH_C32(0xf6bd1936), SPH_C32(0x4220c525), SPH_C32(0x113a0003), + SPH_C32(0xb8091200), SPH_C32(0x6bfe0000), SPH_C32(0xb3c20000), + SPH_C32(0x33b5007d), SPH_C32(0x99a86a00), SPH_C32(0x19a5da99), + SPH_C32(0xcd1f933d) }, + { SPH_C32(0xc9290004), SPH_C32(0x40a98300), SPH_C32(0x49d50000), + SPH_C32(0xde370000), SPH_C32(0x9f800cc5), SPH_C32(0x72d9c299), + SPH_C32(0x33bdd0b4), SPH_C32(0xac41744e), SPH_C32(0x99bb0003), + SPH_C32(0xc9462400), SPH_C32(0x31aa0000), SPH_C32(0xedce0000), + SPH_C32(0xf480221d), SPH_C32(0x5d3d053d), SPH_C32(0x7e5aaebc), + SPH_C32(0x7932eaa2) }, + { SPH_C32(0x71140004), SPH_C32(0x56d88500), SPH_C32(0x7e4f0000), + SPH_C32(0x2b860000), SPH_C32(0xbd016d69), SPH_C32(0xdc9133dc), + SPH_C32(0x5599c6a2), SPH_C32(0x69809f70), SPH_C32(0x649e0003), + SPH_C32(0x7a823500), SPH_C32(0xff5a0000), SPH_C32(0x23370000), + SPH_C32(0xc8cd579d), SPH_C32(0xd06661ae), SPH_C32(0x0ec21e1a), + SPH_C32(0x63c0f543) }, + { SPH_C32(0xbc8d0004), SPH_C32(0x8222a400), SPH_C32(0xdd710000), + SPH_C32(0x4ec20000), SPH_C32(0x64f85b25), SPH_C32(0x3b17c937), + SPH_C32(0x24da1437), SPH_C32(0x029e1230), SPH_C32(0x48dd0003), + SPH_C32(0xd2fa2700), SPH_C32(0xaf460000), SPH_C32(0x1b5a0000), + SPH_C32(0xf782673a), SPH_C32(0x924df9cf), SPH_C32(0xca19b5ab), + SPH_C32(0xfc4dd689) }, + { SPH_C32(0x04b00004), SPH_C32(0x9453a200), SPH_C32(0xeaeb0000), + SPH_C32(0xbb730000), SPH_C32(0x46793a89), SPH_C32(0x955f3872), + SPH_C32(0x42fe0221), SPH_C32(0xc75ff90e), SPH_C32(0xb5f80003), + SPH_C32(0x613e3600), SPH_C32(0x61b60000), SPH_C32(0xd5a30000), + SPH_C32(0xcbcf12ba), SPH_C32(0x1f169d5c), SPH_C32(0xba81050d), + SPH_C32(0xe6bfc968) }, + { SPH_C32(0x6d860007), SPH_C32(0x55054000), SPH_C32(0x06190000), + SPH_C32(0x92490000), SPH_C32(0x174666dc), SPH_C32(0x3af1893c), + SPH_C32(0x3cd6bdbe), SPH_C32(0x2989664e), SPH_C32(0xd3b60002), + SPH_C32(0x7f274000), SPH_C32(0xc8dc0000), SPH_C32(0x2c310000), + SPH_C32(0xb14f42c3), SPH_C32(0x6c9219a4), SPH_C32(0x97453192), + SPH_C32(0xac3942a3) }, + { SPH_C32(0xd5bb0007), SPH_C32(0x43744600), SPH_C32(0x31830000), + SPH_C32(0x67f80000), SPH_C32(0x35c70770), SPH_C32(0x94b97879), + SPH_C32(0x5af2aba8), SPH_C32(0xec488d70), SPH_C32(0x2e930002), + SPH_C32(0xcce35100), SPH_C32(0x062c0000), SPH_C32(0xe2c80000), + SPH_C32(0x8d023743), SPH_C32(0xe1c97d37), SPH_C32(0xe7dd8134), + SPH_C32(0xb6cb5d42) }, + { SPH_C32(0x18220007), SPH_C32(0x978e6700), SPH_C32(0x92bd0000), + SPH_C32(0x02bc0000), SPH_C32(0xec3e313c), SPH_C32(0x733f8292), + SPH_C32(0x2bb1793d), SPH_C32(0x87560030), SPH_C32(0x02d00002), + SPH_C32(0x649b4300), SPH_C32(0x56300000), SPH_C32(0xdaa50000), + SPH_C32(0xb24d07e4), SPH_C32(0xa3e2e556), SPH_C32(0x23062a85), + SPH_C32(0x29467e88) }, + { SPH_C32(0xa01f0007), SPH_C32(0x81ff6100), SPH_C32(0xa5270000), + SPH_C32(0xf70d0000), SPH_C32(0xcebf5090), SPH_C32(0xdd7773d7), + SPH_C32(0x4d956f2b), SPH_C32(0x4297eb0e), SPH_C32(0xfff50002), + SPH_C32(0xd75f5200), SPH_C32(0x98c00000), SPH_C32(0x145c0000), + SPH_C32(0x8e007264), SPH_C32(0x2eb981c5), SPH_C32(0x539e9a23), + SPH_C32(0x33b46169) }, + { SPH_C32(0xbce00007), SPH_C32(0x4eb94300), SPH_C32(0x98f50000), + SPH_C32(0x64dd0000), SPH_C32(0x144423fb), SPH_C32(0xf58175ce), + SPH_C32(0x8895a6a9), SPH_C32(0xacf65a65), SPH_C32(0x77740002), + SPH_C32(0xa6106400), SPH_C32(0xc2940000), SPH_C32(0x4a500000), + SPH_C32(0x49355004), SPH_C32(0xea2ceef8), SPH_C32(0x3461ee06), + SPH_C32(0x879918f6) }, + { SPH_C32(0x04dd0007), SPH_C32(0x58c84500), SPH_C32(0xaf6f0000), + SPH_C32(0x916c0000), SPH_C32(0x36c54257), SPH_C32(0x5bc9848b), + SPH_C32(0xeeb1b0bf), SPH_C32(0x6937b15b), SPH_C32(0x8a510002), + SPH_C32(0x15d47500), SPH_C32(0x0c640000), SPH_C32(0x84a90000), + SPH_C32(0x75782584), SPH_C32(0x67778a6b), SPH_C32(0x44f95ea0), + SPH_C32(0x9d6b0717) }, + { SPH_C32(0xc9440007), SPH_C32(0x8c326400), SPH_C32(0x0c510000), + SPH_C32(0xf4280000), SPH_C32(0xef3c741b), SPH_C32(0xbc4f7e60), + SPH_C32(0x9ff2622a), SPH_C32(0x02293c1b), SPH_C32(0xa6120002), + SPH_C32(0xbdac6700), SPH_C32(0x5c780000), SPH_C32(0xbcc40000), + SPH_C32(0x4a371523), SPH_C32(0x255c120a), SPH_C32(0x8022f511), + SPH_C32(0x02e624dd) }, + { SPH_C32(0x71790007), SPH_C32(0x9a436200), SPH_C32(0x3bcb0000), + SPH_C32(0x01990000), SPH_C32(0xcdbd15b7), SPH_C32(0x12078f25), + SPH_C32(0xf9d6743c), SPH_C32(0xc7e8d725), SPH_C32(0x5b370002), + SPH_C32(0x0e687600), SPH_C32(0x92880000), SPH_C32(0x723d0000), + SPH_C32(0x767a60a3), SPH_C32(0xa8077699), SPH_C32(0xf0ba45b7), + SPH_C32(0x18143b3c) }, + { SPH_C32(0xa67f0001), SPH_C32(0x71378000), SPH_C32(0x19fc0000), + SPH_C32(0x96db0000), SPH_C32(0x3a8b6dfd), SPH_C32(0xebcaaef3), + SPH_C32(0x2c6d478f), SPH_C32(0xac8e6c88), SPH_C32(0x50ff0004), + SPH_C32(0x45744000), SPH_C32(0x3dfb0000), SPH_C32(0x19e60000), + SPH_C32(0x1bbc5606), SPH_C32(0xe1727b5d), SPH_C32(0xe1a8cc96), + SPH_C32(0x7b1bd6b9) }, + { SPH_C32(0x1e420001), SPH_C32(0x67468600), SPH_C32(0x2e660000), + SPH_C32(0x636a0000), SPH_C32(0x180a0c51), SPH_C32(0x45825fb6), + SPH_C32(0x4a495199), SPH_C32(0x694f87b6), SPH_C32(0xadda0004), + SPH_C32(0xf6b05100), SPH_C32(0xf30b0000), SPH_C32(0xd71f0000), + SPH_C32(0x27f12386), SPH_C32(0x6c291fce), SPH_C32(0x91307c30), + SPH_C32(0x61e9c958) }, + { SPH_C32(0xd3db0001), SPH_C32(0xb3bca700), SPH_C32(0x8d580000), + SPH_C32(0x062e0000), SPH_C32(0xc1f33a1d), SPH_C32(0xa204a55d), + SPH_C32(0x3b0a830c), SPH_C32(0x02510af6), SPH_C32(0x81990004), + SPH_C32(0x5ec84300), SPH_C32(0xa3170000), SPH_C32(0xef720000), + SPH_C32(0x18be1321), SPH_C32(0x2e0287af), SPH_C32(0x55ebd781), + SPH_C32(0xfe64ea92) }, + { SPH_C32(0x6be60001), SPH_C32(0xa5cda100), SPH_C32(0xbac20000), + SPH_C32(0xf39f0000), SPH_C32(0xe3725bb1), SPH_C32(0x0c4c5418), + SPH_C32(0x5d2e951a), SPH_C32(0xc790e1c8), SPH_C32(0x7cbc0004), + SPH_C32(0xed0c5200), SPH_C32(0x6de70000), SPH_C32(0x218b0000), + SPH_C32(0x24f366a1), SPH_C32(0xa359e33c), SPH_C32(0x25736727), + SPH_C32(0xe496f573) }, + { SPH_C32(0x77190001), SPH_C32(0x6a8b8300), SPH_C32(0x87100000), + SPH_C32(0x604f0000), SPH_C32(0x398928da), SPH_C32(0x24ba5201), + SPH_C32(0x982e5c98), SPH_C32(0x29f150a3), SPH_C32(0xf43d0004), + SPH_C32(0x9c436400), SPH_C32(0x37b30000), SPH_C32(0x7f870000), + SPH_C32(0xe3c644c1), SPH_C32(0x67cc8c01), SPH_C32(0x428c1302), + SPH_C32(0x50bb8cec) }, + { SPH_C32(0xcf240001), SPH_C32(0x7cfa8500), SPH_C32(0xb08a0000), + SPH_C32(0x95fe0000), SPH_C32(0x1b084976), SPH_C32(0x8af2a344), + SPH_C32(0xfe0a4a8e), SPH_C32(0xec30bb9d), SPH_C32(0x09180004), + SPH_C32(0x2f877500), SPH_C32(0xf9430000), SPH_C32(0xb17e0000), + SPH_C32(0xdf8b3141), SPH_C32(0xea97e892), SPH_C32(0x3214a3a4), + SPH_C32(0x4a49930d) }, + { SPH_C32(0x02bd0001), SPH_C32(0xa800a400), SPH_C32(0x13b40000), + SPH_C32(0xf0ba0000), SPH_C32(0xc2f17f3a), SPH_C32(0x6d7459af), + SPH_C32(0x8f49981b), SPH_C32(0x872e36dd), SPH_C32(0x255b0004), + SPH_C32(0x87ff6700), SPH_C32(0xa95f0000), SPH_C32(0x89130000), + SPH_C32(0xe0c401e6), SPH_C32(0xa8bc70f3), SPH_C32(0xf6cf0815), + SPH_C32(0xd5c4b0c7) }, + { SPH_C32(0xba800001), SPH_C32(0xbe71a200), SPH_C32(0x242e0000), + SPH_C32(0x050b0000), SPH_C32(0xe0701e96), SPH_C32(0xc33ca8ea), + SPH_C32(0xe96d8e0d), SPH_C32(0x42efdde3), SPH_C32(0xd87e0004), + SPH_C32(0x343b7600), SPH_C32(0x67af0000), SPH_C32(0x47ea0000), + SPH_C32(0xdc897466), SPH_C32(0x25e71460), SPH_C32(0x8657b8b3), + SPH_C32(0xcf36af26) }, + { SPH_C32(0xd3b60002), SPH_C32(0x7f274000), SPH_C32(0xc8dc0000), + SPH_C32(0x2c310000), SPH_C32(0xb14f42c3), SPH_C32(0x6c9219a4), + SPH_C32(0x97453192), SPH_C32(0xac3942a3), SPH_C32(0xbe300005), + SPH_C32(0x2a220000), SPH_C32(0xcec50000), SPH_C32(0xbe780000), + SPH_C32(0xa609241f), SPH_C32(0x56639098), SPH_C32(0xab938c2c), + SPH_C32(0x85b024ed) }, + { SPH_C32(0x6b8b0002), SPH_C32(0x69564600), SPH_C32(0xff460000), + SPH_C32(0xd9800000), SPH_C32(0x93ce236f), SPH_C32(0xc2dae8e1), + SPH_C32(0xf1612784), SPH_C32(0x69f8a99d), SPH_C32(0x43150005), + SPH_C32(0x99e61100), SPH_C32(0x00350000), SPH_C32(0x70810000), + SPH_C32(0x9a44519f), SPH_C32(0xdb38f40b), SPH_C32(0xdb0b3c8a), + SPH_C32(0x9f423b0c) }, + { SPH_C32(0xa6120002), SPH_C32(0xbdac6700), SPH_C32(0x5c780000), + SPH_C32(0xbcc40000), SPH_C32(0x4a371523), SPH_C32(0x255c120a), + SPH_C32(0x8022f511), SPH_C32(0x02e624dd), SPH_C32(0x6f560005), + SPH_C32(0x319e0300), SPH_C32(0x50290000), SPH_C32(0x48ec0000), + SPH_C32(0xa50b6138), SPH_C32(0x99136c6a), SPH_C32(0x1fd0973b), + SPH_C32(0x00cf18c6) }, + { SPH_C32(0x1e2f0002), SPH_C32(0xabdd6100), SPH_C32(0x6be20000), + SPH_C32(0x49750000), SPH_C32(0x68b6748f), SPH_C32(0x8b14e34f), + SPH_C32(0xe606e307), SPH_C32(0xc727cfe3), SPH_C32(0x92730005), + SPH_C32(0x825a1200), SPH_C32(0x9ed90000), SPH_C32(0x86150000), + SPH_C32(0x994614b8), SPH_C32(0x144808f9), SPH_C32(0x6f48279d), + SPH_C32(0x1a3d0727) }, + { SPH_C32(0x02d00002), SPH_C32(0x649b4300), SPH_C32(0x56300000), + SPH_C32(0xdaa50000), SPH_C32(0xb24d07e4), SPH_C32(0xa3e2e556), + SPH_C32(0x23062a85), SPH_C32(0x29467e88), SPH_C32(0x1af20005), + SPH_C32(0xf3152400), SPH_C32(0xc48d0000), SPH_C32(0xd8190000), + SPH_C32(0x5e7336d8), SPH_C32(0xd0dd67c4), SPH_C32(0x08b753b8), + SPH_C32(0xae107eb8) }, + { SPH_C32(0xbaed0002), SPH_C32(0x72ea4500), SPH_C32(0x61aa0000), + SPH_C32(0x2f140000), SPH_C32(0x90cc6648), SPH_C32(0x0daa1413), + SPH_C32(0x45223c93), SPH_C32(0xec8795b6), SPH_C32(0xe7d70005), + SPH_C32(0x40d13500), SPH_C32(0x0a7d0000), SPH_C32(0x16e00000), + SPH_C32(0x623e4358), SPH_C32(0x5d860357), SPH_C32(0x782fe31e), + SPH_C32(0xb4e26159) }, + { SPH_C32(0x77740002), SPH_C32(0xa6106400), SPH_C32(0xc2940000), + SPH_C32(0x4a500000), SPH_C32(0x49355004), SPH_C32(0xea2ceef8), + SPH_C32(0x3461ee06), SPH_C32(0x879918f6), SPH_C32(0xcb940005), + SPH_C32(0xe8a92700), SPH_C32(0x5a610000), SPH_C32(0x2e8d0000), + SPH_C32(0x5d7173ff), SPH_C32(0x1fad9b36), SPH_C32(0xbcf448af), + SPH_C32(0x2b6f4293) }, + { SPH_C32(0xcf490002), SPH_C32(0xb0616200), SPH_C32(0xf50e0000), + SPH_C32(0xbfe10000), SPH_C32(0x6bb431a8), SPH_C32(0x44641fbd), + SPH_C32(0x5245f810), SPH_C32(0x4258f3c8), SPH_C32(0x36b10005), + SPH_C32(0x5b6d3600), SPH_C32(0x94910000), SPH_C32(0xe0740000), + SPH_C32(0x613c067f), SPH_C32(0x92f6ffa5), SPH_C32(0xcc6cf809), + SPH_C32(0x319d5d72) }, + { SPH_C32(0x48b00000), SPH_C32(0x1e61c000), SPH_C32(0xeac20000), + SPH_C32(0x31450000), SPH_C32(0x873e1fe4), SPH_C32(0x5cdb4536), + SPH_C32(0x66560735), SPH_C32(0x52259edc), SPH_C32(0xcbf90006), + SPH_C32(0x2432c000), SPH_C32(0x1fe50000), SPH_C32(0x04920000), + SPH_C32(0x2dcd0b21), SPH_C32(0xd13b27cf), SPH_C32(0x10bbfa31), + SPH_C32(0x85070ac6) }, + { SPH_C32(0xf08d0000), SPH_C32(0x0810c600), SPH_C32(0xdd580000), + SPH_C32(0xc4f40000), SPH_C32(0xa5bf7e48), SPH_C32(0xf293b473), + SPH_C32(0x00721123), SPH_C32(0x97e475e2), SPH_C32(0x36dc0006), + SPH_C32(0x97f6d100), SPH_C32(0xd1150000), SPH_C32(0xca6b0000), + SPH_C32(0x11807ea1), SPH_C32(0x5c60435c), SPH_C32(0x60234a97), + SPH_C32(0x9ff51527) }, + { SPH_C32(0x3d140000), SPH_C32(0xdceae700), SPH_C32(0x7e660000), + SPH_C32(0xa1b00000), SPH_C32(0x7c464804), SPH_C32(0x15154e98), + SPH_C32(0x7131c3b6), SPH_C32(0xfcfaf8a2), SPH_C32(0x1a9f0006), + SPH_C32(0x3f8ec300), SPH_C32(0x81090000), SPH_C32(0xf2060000), + SPH_C32(0x2ecf4e06), SPH_C32(0x1e4bdb3d), SPH_C32(0xa4f8e126), + SPH_C32(0x007836ed) }, + { SPH_C32(0x85290000), SPH_C32(0xca9be100), SPH_C32(0x49fc0000), + SPH_C32(0x54010000), SPH_C32(0x5ec729a8), SPH_C32(0xbb5dbfdd), + SPH_C32(0x1715d5a0), SPH_C32(0x393b139c), SPH_C32(0xe7ba0006), + SPH_C32(0x8c4ad200), SPH_C32(0x4ff90000), SPH_C32(0x3cff0000), + SPH_C32(0x12823b86), SPH_C32(0x9310bfae), SPH_C32(0xd4605180), + SPH_C32(0x1a8a290c) }, + { SPH_C32(0x99d60000), SPH_C32(0x05ddc300), SPH_C32(0x742e0000), + SPH_C32(0xc7d10000), SPH_C32(0x843c5ac3), SPH_C32(0x93abb9c4), + SPH_C32(0xd2151c22), SPH_C32(0xd75aa2f7), SPH_C32(0x6f3b0006), + SPH_C32(0xfd05e400), SPH_C32(0x15ad0000), SPH_C32(0x62f30000), + SPH_C32(0xd5b719e6), SPH_C32(0x5785d093), SPH_C32(0xb39f25a5), + SPH_C32(0xaea75093) }, + { SPH_C32(0x21eb0000), SPH_C32(0x13acc500), SPH_C32(0x43b40000), + SPH_C32(0x32600000), SPH_C32(0xa6bd3b6f), SPH_C32(0x3de34881), + SPH_C32(0xb4310a34), SPH_C32(0x129b49c9), SPH_C32(0x921e0006), + SPH_C32(0x4ec1f500), SPH_C32(0xdb5d0000), SPH_C32(0xac0a0000), + SPH_C32(0xe9fa6c66), SPH_C32(0xdadeb400), SPH_C32(0xc3079503), + SPH_C32(0xb4554f72) }, + { SPH_C32(0xec720000), SPH_C32(0xc756e400), SPH_C32(0xe08a0000), + SPH_C32(0x57240000), SPH_C32(0x7f440d23), SPH_C32(0xda65b26a), + SPH_C32(0xc572d8a1), SPH_C32(0x7985c489), SPH_C32(0xbe5d0006), + SPH_C32(0xe6b9e700), SPH_C32(0x8b410000), SPH_C32(0x94670000), + SPH_C32(0xd6b55cc1), SPH_C32(0x98f52c61), SPH_C32(0x07dc3eb2), + SPH_C32(0x2bd86cb8) }, + { SPH_C32(0x544f0000), SPH_C32(0xd127e200), SPH_C32(0xd7100000), + SPH_C32(0xa2950000), SPH_C32(0x5dc56c8f), SPH_C32(0x742d432f), + SPH_C32(0xa356ceb7), SPH_C32(0xbc442fb7), SPH_C32(0x43780006), + SPH_C32(0x557df600), SPH_C32(0x45b10000), SPH_C32(0x5a9e0000), + SPH_C32(0xeaf82941), SPH_C32(0x15ae48f2), SPH_C32(0x77448e14), + SPH_C32(0x312a7359) }, + { SPH_C32(0x3d790003), SPH_C32(0x10710000), SPH_C32(0x3be20000), + SPH_C32(0x8baf0000), SPH_C32(0x0cfa30da), SPH_C32(0xdb83f261), + SPH_C32(0xdd7e7128), SPH_C32(0x5292b0f7), SPH_C32(0x25360007), + SPH_C32(0x4b648000), SPH_C32(0xecdb0000), SPH_C32(0xa30c0000), + SPH_C32(0x90787938), SPH_C32(0x662acc0a), SPH_C32(0x5a80ba8b), + SPH_C32(0x7bacf892) }, + { SPH_C32(0x85440003), SPH_C32(0x06000600), SPH_C32(0x0c780000), + SPH_C32(0x7e1e0000), SPH_C32(0x2e7b5176), SPH_C32(0x75cb0324), + SPH_C32(0xbb5a673e), SPH_C32(0x97535bc9), SPH_C32(0xd8130007), + SPH_C32(0xf8a09100), SPH_C32(0x222b0000), SPH_C32(0x6df50000), + SPH_C32(0xac350cb8), SPH_C32(0xeb71a899), SPH_C32(0x2a180a2d), + SPH_C32(0x615ee773) }, + { SPH_C32(0x48dd0003), SPH_C32(0xd2fa2700), SPH_C32(0xaf460000), + SPH_C32(0x1b5a0000), SPH_C32(0xf782673a), SPH_C32(0x924df9cf), + SPH_C32(0xca19b5ab), SPH_C32(0xfc4dd689), SPH_C32(0xf4500007), + SPH_C32(0x50d88300), SPH_C32(0x72370000), SPH_C32(0x55980000), + SPH_C32(0x937a3c1f), SPH_C32(0xa95a30f8), SPH_C32(0xeec3a19c), + SPH_C32(0xfed3c4b9) }, + { SPH_C32(0xf0e00003), SPH_C32(0xc48b2100), SPH_C32(0x98dc0000), + SPH_C32(0xeeeb0000), SPH_C32(0xd5030696), SPH_C32(0x3c05088a), + SPH_C32(0xac3da3bd), SPH_C32(0x398c3db7), SPH_C32(0x09750007), + SPH_C32(0xe31c9200), SPH_C32(0xbcc70000), SPH_C32(0x9b610000), + SPH_C32(0xaf37499f), SPH_C32(0x2401546b), SPH_C32(0x9e5b113a), + SPH_C32(0xe421db58) }, + { SPH_C32(0xec1f0003), SPH_C32(0x0bcd0300), SPH_C32(0xa50e0000), + SPH_C32(0x7d3b0000), SPH_C32(0x0ff875fd), SPH_C32(0x14f30e93), + SPH_C32(0x693d6a3f), SPH_C32(0xd7ed8cdc), SPH_C32(0x81f40007), + SPH_C32(0x9253a400), SPH_C32(0xe6930000), SPH_C32(0xc56d0000), + SPH_C32(0x68026bff), SPH_C32(0xe0943b56), SPH_C32(0xf9a4651f), + SPH_C32(0x500ca2c7) }, + { SPH_C32(0x54220003), SPH_C32(0x1dbc0500), SPH_C32(0x92940000), + SPH_C32(0x888a0000), SPH_C32(0x2d791451), SPH_C32(0xbabbffd6), + SPH_C32(0x0f197c29), SPH_C32(0x122c67e2), SPH_C32(0x7cd10007), + SPH_C32(0x2197b500), SPH_C32(0x28630000), SPH_C32(0x0b940000), + SPH_C32(0x544f1e7f), SPH_C32(0x6dcf5fc5), SPH_C32(0x893cd5b9), + SPH_C32(0x4afebd26) }, + { SPH_C32(0x99bb0003), SPH_C32(0xc9462400), SPH_C32(0x31aa0000), + SPH_C32(0xedce0000), SPH_C32(0xf480221d), SPH_C32(0x5d3d053d), + SPH_C32(0x7e5aaebc), SPH_C32(0x7932eaa2), SPH_C32(0x50920007), + SPH_C32(0x89efa700), SPH_C32(0x787f0000), SPH_C32(0x33f90000), + SPH_C32(0x6b002ed8), SPH_C32(0x2fe4c7a4), SPH_C32(0x4de77e08), + SPH_C32(0xd5739eec) }, + { SPH_C32(0x21860003), SPH_C32(0xdf372200), SPH_C32(0x06300000), + SPH_C32(0x187f0000), SPH_C32(0xd60143b1), SPH_C32(0xf375f478), + SPH_C32(0x187eb8aa), SPH_C32(0xbcf3019c), SPH_C32(0xadb70007), + SPH_C32(0x3a2bb600), SPH_C32(0xb68f0000), SPH_C32(0xfd000000), + SPH_C32(0x574d5b58), SPH_C32(0xa2bfa337), SPH_C32(0x3d7fceae), + SPH_C32(0xcf81810d) }, + { SPH_C32(0x50ff0004), SPH_C32(0x45744000), SPH_C32(0x3dfb0000), + SPH_C32(0x19e60000), SPH_C32(0x1bbc5606), SPH_C32(0xe1727b5d), + SPH_C32(0xe1a8cc96), SPH_C32(0x7b1bd6b9), SPH_C32(0xf6800005), + SPH_C32(0x3443c000), SPH_C32(0x24070000), SPH_C32(0x8f3d0000), + SPH_C32(0x21373bfb), SPH_C32(0x0ab8d5ae), SPH_C32(0xcdc58b19), + SPH_C32(0xd795ba31) }, + { SPH_C32(0xe8c20004), SPH_C32(0x53054600), SPH_C32(0x0a610000), + SPH_C32(0xec570000), SPH_C32(0x393d37aa), SPH_C32(0x4f3a8a18), + SPH_C32(0x878cda80), SPH_C32(0xbeda3d87), SPH_C32(0x0ba50005), + SPH_C32(0x8787d100), SPH_C32(0xeaf70000), SPH_C32(0x41c40000), + SPH_C32(0x1d7a4e7b), SPH_C32(0x87e3b13d), SPH_C32(0xbd5d3bbf), + SPH_C32(0xcd67a5d0) }, + { SPH_C32(0x255b0004), SPH_C32(0x87ff6700), SPH_C32(0xa95f0000), + SPH_C32(0x89130000), SPH_C32(0xe0c401e6), SPH_C32(0xa8bc70f3), + SPH_C32(0xf6cf0815), SPH_C32(0xd5c4b0c7), SPH_C32(0x27e60005), + SPH_C32(0x2fffc300), SPH_C32(0xbaeb0000), SPH_C32(0x79a90000), + SPH_C32(0x22357edc), SPH_C32(0xc5c8295c), SPH_C32(0x7986900e), + SPH_C32(0x52ea861a) }, + { SPH_C32(0x9d660004), SPH_C32(0x918e6100), SPH_C32(0x9ec50000), + SPH_C32(0x7ca20000), SPH_C32(0xc245604a), SPH_C32(0x06f481b6), + SPH_C32(0x90eb1e03), SPH_C32(0x10055bf9), SPH_C32(0xdac30005), + SPH_C32(0x9c3bd200), SPH_C32(0x741b0000), SPH_C32(0xb7500000), + SPH_C32(0x1e780b5c), SPH_C32(0x48934dcf), SPH_C32(0x091e20a8), + SPH_C32(0x481899fb) }, + { SPH_C32(0x81990004), SPH_C32(0x5ec84300), SPH_C32(0xa3170000), + SPH_C32(0xef720000), SPH_C32(0x18be1321), SPH_C32(0x2e0287af), + SPH_C32(0x55ebd781), SPH_C32(0xfe64ea92), SPH_C32(0x52420005), + SPH_C32(0xed74e400), SPH_C32(0x2e4f0000), SPH_C32(0xe95c0000), + SPH_C32(0xd94d293c), SPH_C32(0x8c0622f2), SPH_C32(0x6ee1548d), + SPH_C32(0xfc35e064) }, + { SPH_C32(0x39a40004), SPH_C32(0x48b94500), SPH_C32(0x948d0000), + SPH_C32(0x1ac30000), SPH_C32(0x3a3f728d), SPH_C32(0x804a76ea), + SPH_C32(0x33cfc197), SPH_C32(0x3ba501ac), SPH_C32(0xaf670005), + SPH_C32(0x5eb0f500), SPH_C32(0xe0bf0000), SPH_C32(0x27a50000), + SPH_C32(0xe5005cbc), SPH_C32(0x015d4661), SPH_C32(0x1e79e42b), + SPH_C32(0xe6c7ff85) }, + { SPH_C32(0xf43d0004), SPH_C32(0x9c436400), SPH_C32(0x37b30000), + SPH_C32(0x7f870000), SPH_C32(0xe3c644c1), SPH_C32(0x67cc8c01), + SPH_C32(0x428c1302), SPH_C32(0x50bb8cec), SPH_C32(0x83240005), + SPH_C32(0xf6c8e700), SPH_C32(0xb0a30000), SPH_C32(0x1fc80000), + SPH_C32(0xda4f6c1b), SPH_C32(0x4376de00), SPH_C32(0xdaa24f9a), + SPH_C32(0x794adc4f) }, + { SPH_C32(0x4c000004), SPH_C32(0x8a326200), SPH_C32(0x00290000), + SPH_C32(0x8a360000), SPH_C32(0xc147256d), SPH_C32(0xc9847d44), + SPH_C32(0x24a80514), SPH_C32(0x957a67d2), SPH_C32(0x7e010005), + SPH_C32(0x450cf600), SPH_C32(0x7e530000), SPH_C32(0xd1310000), + SPH_C32(0xe602199b), SPH_C32(0xce2dba93), SPH_C32(0xaa3aff3c), + SPH_C32(0x63b8c3ae) }, + { SPH_C32(0x25360007), SPH_C32(0x4b648000), SPH_C32(0xecdb0000), + SPH_C32(0xa30c0000), SPH_C32(0x90787938), SPH_C32(0x662acc0a), + SPH_C32(0x5a80ba8b), SPH_C32(0x7bacf892), SPH_C32(0x184f0004), + SPH_C32(0x5b158000), SPH_C32(0xd7390000), SPH_C32(0x28a30000), + SPH_C32(0x9c8249e2), SPH_C32(0xbda93e6b), SPH_C32(0x87fecba3), + SPH_C32(0x293e4865) }, + { SPH_C32(0x9d0b0007), SPH_C32(0x5d158600), SPH_C32(0xdb410000), + SPH_C32(0x56bd0000), SPH_C32(0xb2f91894), SPH_C32(0xc8623d4f), + SPH_C32(0x3ca4ac9d), SPH_C32(0xbe6d13ac), SPH_C32(0xe56a0004), + SPH_C32(0xe8d19100), SPH_C32(0x19c90000), SPH_C32(0xe65a0000), + SPH_C32(0xa0cf3c62), SPH_C32(0x30f25af8), SPH_C32(0xf7667b05), + SPH_C32(0x33cc5784) }, + { SPH_C32(0x50920007), SPH_C32(0x89efa700), SPH_C32(0x787f0000), + SPH_C32(0x33f90000), SPH_C32(0x6b002ed8), SPH_C32(0x2fe4c7a4), + SPH_C32(0x4de77e08), SPH_C32(0xd5739eec), SPH_C32(0xc9290004), + SPH_C32(0x40a98300), SPH_C32(0x49d50000), SPH_C32(0xde370000), + SPH_C32(0x9f800cc5), SPH_C32(0x72d9c299), SPH_C32(0x33bdd0b4), + SPH_C32(0xac41744e) }, + { SPH_C32(0xe8af0007), SPH_C32(0x9f9ea100), SPH_C32(0x4fe50000), + SPH_C32(0xc6480000), SPH_C32(0x49814f74), SPH_C32(0x81ac36e1), + SPH_C32(0x2bc3681e), SPH_C32(0x10b275d2), SPH_C32(0x340c0004), + SPH_C32(0xf36d9200), SPH_C32(0x87250000), SPH_C32(0x10ce0000), + SPH_C32(0xa3cd7945), SPH_C32(0xff82a60a), SPH_C32(0x43256012), + SPH_C32(0xb6b36baf) }, + { SPH_C32(0xf4500007), SPH_C32(0x50d88300), SPH_C32(0x72370000), + SPH_C32(0x55980000), SPH_C32(0x937a3c1f), SPH_C32(0xa95a30f8), + SPH_C32(0xeec3a19c), SPH_C32(0xfed3c4b9), SPH_C32(0xbc8d0004), + SPH_C32(0x8222a400), SPH_C32(0xdd710000), SPH_C32(0x4ec20000), + SPH_C32(0x64f85b25), SPH_C32(0x3b17c937), SPH_C32(0x24da1437), + SPH_C32(0x029e1230) }, + { SPH_C32(0x4c6d0007), SPH_C32(0x46a98500), SPH_C32(0x45ad0000), + SPH_C32(0xa0290000), SPH_C32(0xb1fb5db3), SPH_C32(0x0712c1bd), + SPH_C32(0x88e7b78a), SPH_C32(0x3b122f87), SPH_C32(0x41a80004), + SPH_C32(0x31e6b500), SPH_C32(0x13810000), SPH_C32(0x803b0000), + SPH_C32(0x58b52ea5), SPH_C32(0xb64cada4), SPH_C32(0x5442a491), + SPH_C32(0x186c0dd1) }, + { SPH_C32(0x81f40007), SPH_C32(0x9253a400), SPH_C32(0xe6930000), + SPH_C32(0xc56d0000), SPH_C32(0x68026bff), SPH_C32(0xe0943b56), + SPH_C32(0xf9a4651f), SPH_C32(0x500ca2c7), SPH_C32(0x6deb0004), + SPH_C32(0x999ea700), SPH_C32(0x439d0000), SPH_C32(0xb8560000), + SPH_C32(0x67fa1e02), SPH_C32(0xf46735c5), SPH_C32(0x90990f20), + SPH_C32(0x87e12e1b) }, + { SPH_C32(0x39c90007), SPH_C32(0x8422a200), SPH_C32(0xd1090000), + SPH_C32(0x30dc0000), SPH_C32(0x4a830a53), SPH_C32(0x4edcca13), + SPH_C32(0x9f807309), SPH_C32(0x95cd49f9), SPH_C32(0x90ce0004), + SPH_C32(0x2a5ab600), SPH_C32(0x8d6d0000), SPH_C32(0x76af0000), + SPH_C32(0x5bb76b82), SPH_C32(0x793c5156), SPH_C32(0xe001bf86), + SPH_C32(0x9d1331fa) }, + { SPH_C32(0xbe300005), SPH_C32(0x2a220000), SPH_C32(0xcec50000), + SPH_C32(0xbe780000), SPH_C32(0xa609241f), SPH_C32(0x56639098), + SPH_C32(0xab938c2c), SPH_C32(0x85b024ed), SPH_C32(0x6d860007), + SPH_C32(0x55054000), SPH_C32(0x06190000), SPH_C32(0x92490000), + SPH_C32(0x174666dc), SPH_C32(0x3af1893c), SPH_C32(0x3cd6bdbe), + SPH_C32(0x2989664e) }, + { SPH_C32(0x060d0005), SPH_C32(0x3c530600), SPH_C32(0xf95f0000), + SPH_C32(0x4bc90000), SPH_C32(0x848845b3), SPH_C32(0xf82b61dd), + SPH_C32(0xcdb79a3a), SPH_C32(0x4071cfd3), SPH_C32(0x90a30007), + SPH_C32(0xe6c15100), SPH_C32(0xc8e90000), SPH_C32(0x5cb00000), + SPH_C32(0x2b0b135c), SPH_C32(0xb7aaedaf), SPH_C32(0x4c4e0d18), + SPH_C32(0x337b79af) }, + { SPH_C32(0xcb940005), SPH_C32(0xe8a92700), SPH_C32(0x5a610000), + SPH_C32(0x2e8d0000), SPH_C32(0x5d7173ff), SPH_C32(0x1fad9b36), + SPH_C32(0xbcf448af), SPH_C32(0x2b6f4293), SPH_C32(0xbce00007), + SPH_C32(0x4eb94300), SPH_C32(0x98f50000), SPH_C32(0x64dd0000), + SPH_C32(0x144423fb), SPH_C32(0xf58175ce), SPH_C32(0x8895a6a9), + SPH_C32(0xacf65a65) }, + { SPH_C32(0x73a90005), SPH_C32(0xfed82100), SPH_C32(0x6dfb0000), + SPH_C32(0xdb3c0000), SPH_C32(0x7ff01253), SPH_C32(0xb1e56a73), + SPH_C32(0xdad05eb9), SPH_C32(0xeeaea9ad), SPH_C32(0x41c50007), + SPH_C32(0xfd7d5200), SPH_C32(0x56050000), SPH_C32(0xaa240000), + SPH_C32(0x2809567b), SPH_C32(0x78da115d), SPH_C32(0xf80d160f), + SPH_C32(0xb6044584) }, + { SPH_C32(0x6f560005), SPH_C32(0x319e0300), SPH_C32(0x50290000), + SPH_C32(0x48ec0000), SPH_C32(0xa50b6138), SPH_C32(0x99136c6a), + SPH_C32(0x1fd0973b), SPH_C32(0x00cf18c6), SPH_C32(0xc9440007), + SPH_C32(0x8c326400), SPH_C32(0x0c510000), SPH_C32(0xf4280000), + SPH_C32(0xef3c741b), SPH_C32(0xbc4f7e60), SPH_C32(0x9ff2622a), + SPH_C32(0x02293c1b) }, + { SPH_C32(0xd76b0005), SPH_C32(0x27ef0500), SPH_C32(0x67b30000), + SPH_C32(0xbd5d0000), SPH_C32(0x878a0094), SPH_C32(0x375b9d2f), + SPH_C32(0x79f4812d), SPH_C32(0xc50ef3f8), SPH_C32(0x34610007), + SPH_C32(0x3ff67500), SPH_C32(0xc2a10000), SPH_C32(0x3ad10000), + SPH_C32(0xd371019b), SPH_C32(0x31141af3), SPH_C32(0xef6ad28c), + SPH_C32(0x18db23fa) }, + { SPH_C32(0x1af20005), SPH_C32(0xf3152400), SPH_C32(0xc48d0000), + SPH_C32(0xd8190000), SPH_C32(0x5e7336d8), SPH_C32(0xd0dd67c4), + SPH_C32(0x08b753b8), SPH_C32(0xae107eb8), SPH_C32(0x18220007), + SPH_C32(0x978e6700), SPH_C32(0x92bd0000), SPH_C32(0x02bc0000), + SPH_C32(0xec3e313c), SPH_C32(0x733f8292), SPH_C32(0x2bb1793d), + SPH_C32(0x87560030) }, + { SPH_C32(0xa2cf0005), SPH_C32(0xe5642200), SPH_C32(0xf3170000), + SPH_C32(0x2da80000), SPH_C32(0x7cf25774), SPH_C32(0x7e959681), + SPH_C32(0x6e9345ae), SPH_C32(0x6bd19586), SPH_C32(0xe5070007), + SPH_C32(0x244a7600), SPH_C32(0x5c4d0000), SPH_C32(0xcc450000), + SPH_C32(0xd07344bc), SPH_C32(0xfe64e601), SPH_C32(0x5b29c99b), + SPH_C32(0x9da41fd1) }, + { SPH_C32(0xcbf90006), SPH_C32(0x2432c000), SPH_C32(0x1fe50000), + SPH_C32(0x04920000), SPH_C32(0x2dcd0b21), SPH_C32(0xd13b27cf), + SPH_C32(0x10bbfa31), SPH_C32(0x85070ac6), SPH_C32(0x83490006), + SPH_C32(0x3a530000), SPH_C32(0xf5270000), SPH_C32(0x35d70000), + SPH_C32(0xaaf314c5), SPH_C32(0x8de062f9), SPH_C32(0x76edfd04), + SPH_C32(0xd722941a) }, + { SPH_C32(0x73c40006), SPH_C32(0x3243c600), SPH_C32(0x287f0000), + SPH_C32(0xf1230000), SPH_C32(0x0f4c6a8d), SPH_C32(0x7f73d68a), + SPH_C32(0x769fec27), SPH_C32(0x40c6e1f8), SPH_C32(0x7e6c0006), + SPH_C32(0x89971100), SPH_C32(0x3bd70000), SPH_C32(0xfb2e0000), + SPH_C32(0x96be6145), SPH_C32(0x00bb066a), SPH_C32(0x06754da2), + SPH_C32(0xcdd08bfb) }, + { SPH_C32(0xbe5d0006), SPH_C32(0xe6b9e700), SPH_C32(0x8b410000), + SPH_C32(0x94670000), SPH_C32(0xd6b55cc1), SPH_C32(0x98f52c61), + SPH_C32(0x07dc3eb2), SPH_C32(0x2bd86cb8), SPH_C32(0x522f0006), + SPH_C32(0x21ef0300), SPH_C32(0x6bcb0000), SPH_C32(0xc3430000), + SPH_C32(0xa9f151e2), SPH_C32(0x42909e0b), SPH_C32(0xc2aee613), + SPH_C32(0x525da831) }, + { SPH_C32(0x06600006), SPH_C32(0xf0c8e100), SPH_C32(0xbcdb0000), + SPH_C32(0x61d60000), SPH_C32(0xf4343d6d), SPH_C32(0x36bddd24), + SPH_C32(0x61f828a4), SPH_C32(0xee198786), SPH_C32(0xaf0a0006), + SPH_C32(0x922b1200), SPH_C32(0xa53b0000), SPH_C32(0x0dba0000), + SPH_C32(0x95bc2462), SPH_C32(0xcfcbfa98), SPH_C32(0xb23656b5), + SPH_C32(0x48afb7d0) }, + { SPH_C32(0x1a9f0006), SPH_C32(0x3f8ec300), SPH_C32(0x81090000), + SPH_C32(0xf2060000), SPH_C32(0x2ecf4e06), SPH_C32(0x1e4bdb3d), + SPH_C32(0xa4f8e126), SPH_C32(0x007836ed), SPH_C32(0x278b0006), + SPH_C32(0xe3642400), SPH_C32(0xff6f0000), SPH_C32(0x53b60000), + SPH_C32(0x52890602), SPH_C32(0x0b5e95a5), SPH_C32(0xd5c92290), + SPH_C32(0xfc82ce4f) }, + { SPH_C32(0xa2a20006), SPH_C32(0x29ffc500), SPH_C32(0xb6930000), + SPH_C32(0x07b70000), SPH_C32(0x0c4e2faa), SPH_C32(0xb0032a78), + SPH_C32(0xc2dcf730), SPH_C32(0xc5b9ddd3), SPH_C32(0xdaae0006), + SPH_C32(0x50a03500), SPH_C32(0x319f0000), SPH_C32(0x9d4f0000), + SPH_C32(0x6ec47382), SPH_C32(0x8605f136), SPH_C32(0xa5519236), + SPH_C32(0xe670d1ae) }, + { SPH_C32(0x6f3b0006), SPH_C32(0xfd05e400), SPH_C32(0x15ad0000), + SPH_C32(0x62f30000), SPH_C32(0xd5b719e6), SPH_C32(0x5785d093), + SPH_C32(0xb39f25a5), SPH_C32(0xaea75093), SPH_C32(0xf6ed0006), + SPH_C32(0xf8d82700), SPH_C32(0x61830000), SPH_C32(0xa5220000), + SPH_C32(0x518b4325), SPH_C32(0xc42e6957), SPH_C32(0x618a3987), + SPH_C32(0x79fdf264) }, + { SPH_C32(0xd7060006), SPH_C32(0xeb74e200), SPH_C32(0x22370000), + SPH_C32(0x97420000), SPH_C32(0xf736784a), SPH_C32(0xf9cd21d6), + SPH_C32(0xd5bb33b3), SPH_C32(0x6b66bbad), SPH_C32(0x0bc80006), + SPH_C32(0x4b1c3600), SPH_C32(0xaf730000), SPH_C32(0x6bdb0000), + SPH_C32(0x6dc636a5), SPH_C32(0x49750dc4), SPH_C32(0x11128921), + SPH_C32(0x630fed85) } +}; + +static const sph_u32 T512_21[128][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0x54500000), SPH_C32(0x0671005c), SPH_C32(0x25ae0000), + SPH_C32(0x6a1e0000), SPH_C32(0x2ea54edf), SPH_C32(0x664e8512), + SPH_C32(0xbfba18c3), SPH_C32(0x7e715d17), SPH_C32(0xbc8d0000), + SPH_C32(0xfc3b0018), SPH_C32(0x19830000), SPH_C32(0xd10b0000), + SPH_C32(0xae1878c4), SPH_C32(0x42a69856), SPH_C32(0x0012da37), + SPH_C32(0x2c3b504e) }, + { SPH_C32(0xbc8d0000), SPH_C32(0xfc3b0018), SPH_C32(0x19830000), + SPH_C32(0xd10b0000), SPH_C32(0xae1878c4), SPH_C32(0x42a69856), + SPH_C32(0x0012da37), SPH_C32(0x2c3b504e), SPH_C32(0xe8dd0000), + SPH_C32(0xfa4a0044), SPH_C32(0x3c2d0000), SPH_C32(0xbb150000), + SPH_C32(0x80bd361b), SPH_C32(0x24e81d44), SPH_C32(0xbfa8c2f4), + SPH_C32(0x524a0d59) }, + { SPH_C32(0xe8dd0000), SPH_C32(0xfa4a0044), SPH_C32(0x3c2d0000), + SPH_C32(0xbb150000), SPH_C32(0x80bd361b), SPH_C32(0x24e81d44), + SPH_C32(0xbfa8c2f4), SPH_C32(0x524a0d59), SPH_C32(0x54500000), + SPH_C32(0x0671005c), SPH_C32(0x25ae0000), SPH_C32(0x6a1e0000), + SPH_C32(0x2ea54edf), SPH_C32(0x664e8512), SPH_C32(0xbfba18c3), + SPH_C32(0x7e715d17) }, + { SPH_C32(0x69510000), SPH_C32(0xd4e1009c), SPH_C32(0xc3230000), + SPH_C32(0xac2f0000), SPH_C32(0xe4950bae), SPH_C32(0xcea415dc), + SPH_C32(0x87ec287c), SPH_C32(0xbce1a3ce), SPH_C32(0xc6730000), + SPH_C32(0xaf8d000c), SPH_C32(0xa4c10000), SPH_C32(0x218d0000), + SPH_C32(0x23111587), SPH_C32(0x7913512f), SPH_C32(0x1d28ac88), + SPH_C32(0x378dd173) }, + { SPH_C32(0x3d010000), SPH_C32(0xd29000c0), SPH_C32(0xe68d0000), + SPH_C32(0xc6310000), SPH_C32(0xca304571), SPH_C32(0xa8ea90ce), + SPH_C32(0x385630bf), SPH_C32(0xc290fed9), SPH_C32(0x7afe0000), + SPH_C32(0x53b60014), SPH_C32(0xbd420000), SPH_C32(0xf0860000), + SPH_C32(0x8d096d43), SPH_C32(0x3bb5c979), SPH_C32(0x1d3a76bf), + SPH_C32(0x1bb6813d) }, + { SPH_C32(0xd5dc0000), SPH_C32(0x28da0084), SPH_C32(0xdaa00000), + SPH_C32(0x7d240000), SPH_C32(0x4a8d736a), SPH_C32(0x8c028d8a), + SPH_C32(0x87fef24b), SPH_C32(0x90daf380), SPH_C32(0x2eae0000), + SPH_C32(0x55c70048), SPH_C32(0x98ec0000), SPH_C32(0x9a980000), + SPH_C32(0xa3ac239c), SPH_C32(0x5dfb4c6b), SPH_C32(0xa2806e7c), + SPH_C32(0x65c7dc2a) }, + { SPH_C32(0x818c0000), SPH_C32(0x2eab00d8), SPH_C32(0xff0e0000), + SPH_C32(0x173a0000), SPH_C32(0x64283db5), SPH_C32(0xea4c0898), + SPH_C32(0x3844ea88), SPH_C32(0xeeabae97), SPH_C32(0x92230000), + SPH_C32(0xa9fc0050), SPH_C32(0x816f0000), SPH_C32(0x4b930000), + SPH_C32(0x0db45b58), SPH_C32(0x1f5dd43d), SPH_C32(0xa292b44b), + SPH_C32(0x49fc8c64) }, + { SPH_C32(0xc6730000), SPH_C32(0xaf8d000c), SPH_C32(0xa4c10000), + SPH_C32(0x218d0000), SPH_C32(0x23111587), SPH_C32(0x7913512f), + SPH_C32(0x1d28ac88), SPH_C32(0x378dd173), SPH_C32(0xaf220000), + SPH_C32(0x7b6c0090), SPH_C32(0x67e20000), SPH_C32(0x8da20000), + SPH_C32(0xc7841e29), SPH_C32(0xb7b744f3), SPH_C32(0x9ac484f4), + SPH_C32(0x8b6c72bd) }, + { SPH_C32(0x92230000), SPH_C32(0xa9fc0050), SPH_C32(0x816f0000), + SPH_C32(0x4b930000), SPH_C32(0x0db45b58), SPH_C32(0x1f5dd43d), + SPH_C32(0xa292b44b), SPH_C32(0x49fc8c64), SPH_C32(0x13af0000), + SPH_C32(0x87570088), SPH_C32(0x7e610000), SPH_C32(0x5ca90000), + SPH_C32(0x699c66ed), SPH_C32(0xf511dca5), SPH_C32(0x9ad65ec3), + SPH_C32(0xa75722f3) }, + { SPH_C32(0x7afe0000), SPH_C32(0x53b60014), SPH_C32(0xbd420000), + SPH_C32(0xf0860000), SPH_C32(0x8d096d43), SPH_C32(0x3bb5c979), + SPH_C32(0x1d3a76bf), SPH_C32(0x1bb6813d), SPH_C32(0x47ff0000), + SPH_C32(0x812600d4), SPH_C32(0x5bcf0000), SPH_C32(0x36b70000), + SPH_C32(0x47392832), SPH_C32(0x935f59b7), SPH_C32(0x256c4600), + SPH_C32(0xd9267fe4) }, + { SPH_C32(0x2eae0000), SPH_C32(0x55c70048), SPH_C32(0x98ec0000), + SPH_C32(0x9a980000), SPH_C32(0xa3ac239c), SPH_C32(0x5dfb4c6b), + SPH_C32(0xa2806e7c), SPH_C32(0x65c7dc2a), SPH_C32(0xfb720000), + SPH_C32(0x7d1d00cc), SPH_C32(0x424c0000), SPH_C32(0xe7bc0000), + SPH_C32(0xe92150f6), SPH_C32(0xd1f9c1e1), SPH_C32(0x257e9c37), + SPH_C32(0xf51d2faa) }, + { SPH_C32(0xaf220000), SPH_C32(0x7b6c0090), SPH_C32(0x67e20000), + SPH_C32(0x8da20000), SPH_C32(0xc7841e29), SPH_C32(0xb7b744f3), + SPH_C32(0x9ac484f4), SPH_C32(0x8b6c72bd), SPH_C32(0x69510000), + SPH_C32(0xd4e1009c), SPH_C32(0xc3230000), SPH_C32(0xac2f0000), + SPH_C32(0xe4950bae), SPH_C32(0xcea415dc), SPH_C32(0x87ec287c), + SPH_C32(0xbce1a3ce) }, + { SPH_C32(0xfb720000), SPH_C32(0x7d1d00cc), SPH_C32(0x424c0000), + SPH_C32(0xe7bc0000), SPH_C32(0xe92150f6), SPH_C32(0xd1f9c1e1), + SPH_C32(0x257e9c37), SPH_C32(0xf51d2faa), SPH_C32(0xd5dc0000), + SPH_C32(0x28da0084), SPH_C32(0xdaa00000), SPH_C32(0x7d240000), + SPH_C32(0x4a8d736a), SPH_C32(0x8c028d8a), SPH_C32(0x87fef24b), + SPH_C32(0x90daf380) }, + { SPH_C32(0x13af0000), SPH_C32(0x87570088), SPH_C32(0x7e610000), + SPH_C32(0x5ca90000), SPH_C32(0x699c66ed), SPH_C32(0xf511dca5), + SPH_C32(0x9ad65ec3), SPH_C32(0xa75722f3), SPH_C32(0x818c0000), + SPH_C32(0x2eab00d8), SPH_C32(0xff0e0000), SPH_C32(0x173a0000), + SPH_C32(0x64283db5), SPH_C32(0xea4c0898), SPH_C32(0x3844ea88), + SPH_C32(0xeeabae97) }, + { SPH_C32(0x47ff0000), SPH_C32(0x812600d4), SPH_C32(0x5bcf0000), + SPH_C32(0x36b70000), SPH_C32(0x47392832), SPH_C32(0x935f59b7), + SPH_C32(0x256c4600), SPH_C32(0xd9267fe4), SPH_C32(0x3d010000), + SPH_C32(0xd29000c0), SPH_C32(0xe68d0000), SPH_C32(0xc6310000), + SPH_C32(0xca304571), SPH_C32(0xa8ea90ce), SPH_C32(0x385630bf), + SPH_C32(0xc290fed9) }, + { SPH_C32(0x0c720000), SPH_C32(0x49e50f00), SPH_C32(0x42790000), + SPH_C32(0x5cea0000), SPH_C32(0x33aa301a), SPH_C32(0x15822514), + SPH_C32(0x95a34b7b), SPH_C32(0xb44b0090), SPH_C32(0xfe220000), + SPH_C32(0xa7580500), SPH_C32(0x25d10000), SPH_C32(0xf7600000), + SPH_C32(0x893178da), SPH_C32(0x1fd4f860), SPH_C32(0x4ed0a315), + SPH_C32(0xa123ff9f) }, + { SPH_C32(0x58220000), SPH_C32(0x4f940f5c), SPH_C32(0x67d70000), + SPH_C32(0x36f40000), SPH_C32(0x1d0f7ec5), SPH_C32(0x73cca006), + SPH_C32(0x2a1953b8), SPH_C32(0xca3a5d87), SPH_C32(0x42af0000), + SPH_C32(0x5b630518), SPH_C32(0x3c520000), SPH_C32(0x266b0000), + SPH_C32(0x2729001e), SPH_C32(0x5d726036), SPH_C32(0x4ec27922), + SPH_C32(0x8d18afd1) }, + { SPH_C32(0xb0ff0000), SPH_C32(0xb5de0f18), SPH_C32(0x5bfa0000), + SPH_C32(0x8de10000), SPH_C32(0x9db248de), SPH_C32(0x5724bd42), + SPH_C32(0x95b1914c), SPH_C32(0x987050de), SPH_C32(0x16ff0000), + SPH_C32(0x5d120544), SPH_C32(0x19fc0000), SPH_C32(0x4c750000), + SPH_C32(0x098c4ec1), SPH_C32(0x3b3ce524), SPH_C32(0xf17861e1), + SPH_C32(0xf369f2c6) }, + { SPH_C32(0xe4af0000), SPH_C32(0xb3af0f44), SPH_C32(0x7e540000), + SPH_C32(0xe7ff0000), SPH_C32(0xb3170601), SPH_C32(0x316a3850), + SPH_C32(0x2a0b898f), SPH_C32(0xe6010dc9), SPH_C32(0xaa720000), + SPH_C32(0xa129055c), SPH_C32(0x007f0000), SPH_C32(0x9d7e0000), + SPH_C32(0xa7943605), SPH_C32(0x799a7d72), SPH_C32(0xf16abbd6), + SPH_C32(0xdf52a288) }, + { SPH_C32(0x65230000), SPH_C32(0x9d040f9c), SPH_C32(0x815a0000), + SPH_C32(0xf0c50000), SPH_C32(0xd73f3bb4), SPH_C32(0xdb2630c8), + SPH_C32(0x124f6307), SPH_C32(0x08aaa35e), SPH_C32(0x38510000), + SPH_C32(0x08d5050c), SPH_C32(0x81100000), SPH_C32(0xd6ed0000), + SPH_C32(0xaa206d5d), SPH_C32(0x66c7a94f), SPH_C32(0x53f80f9d), + SPH_C32(0x96ae2eec) }, + { SPH_C32(0x31730000), SPH_C32(0x9b750fc0), SPH_C32(0xa4f40000), + SPH_C32(0x9adb0000), SPH_C32(0xf99a756b), SPH_C32(0xbd68b5da), + SPH_C32(0xadf57bc4), SPH_C32(0x76dbfe49), SPH_C32(0x84dc0000), + SPH_C32(0xf4ee0514), SPH_C32(0x98930000), SPH_C32(0x07e60000), + SPH_C32(0x04381599), SPH_C32(0x24613119), SPH_C32(0x53ead5aa), + SPH_C32(0xba957ea2) }, + { SPH_C32(0xd9ae0000), SPH_C32(0x613f0f84), SPH_C32(0x98d90000), + SPH_C32(0x21ce0000), SPH_C32(0x79274370), SPH_C32(0x9980a89e), + SPH_C32(0x125db930), SPH_C32(0x2491f310), SPH_C32(0xd08c0000), + SPH_C32(0xf29f0548), SPH_C32(0xbd3d0000), SPH_C32(0x6df80000), + SPH_C32(0x2a9d5b46), SPH_C32(0x422fb40b), SPH_C32(0xec50cd69), + SPH_C32(0xc4e423b5) }, + { SPH_C32(0x8dfe0000), SPH_C32(0x674e0fd8), SPH_C32(0xbd770000), + SPH_C32(0x4bd00000), SPH_C32(0x57820daf), SPH_C32(0xffce2d8c), + SPH_C32(0xade7a1f3), SPH_C32(0x5ae0ae07), SPH_C32(0x6c010000), + SPH_C32(0x0ea40550), SPH_C32(0xa4be0000), SPH_C32(0xbcf30000), + SPH_C32(0x84852382), SPH_C32(0x00892c5d), SPH_C32(0xec42175e), + SPH_C32(0xe8df73fb) }, + { SPH_C32(0xca010000), SPH_C32(0xe6680f0c), SPH_C32(0xe6b80000), + SPH_C32(0x7d670000), SPH_C32(0x10bb259d), SPH_C32(0x6c91743b), + SPH_C32(0x888be7f3), SPH_C32(0x83c6d1e3), SPH_C32(0x51000000), + SPH_C32(0xdc340590), SPH_C32(0x42330000), SPH_C32(0x7ac20000), + SPH_C32(0x4eb566f3), SPH_C32(0xa863bc93), SPH_C32(0xd41427e1), + SPH_C32(0x2a4f8d22) }, + { SPH_C32(0x9e510000), SPH_C32(0xe0190f50), SPH_C32(0xc3160000), + SPH_C32(0x17790000), SPH_C32(0x3e1e6b42), SPH_C32(0x0adff129), + SPH_C32(0x3731ff30), SPH_C32(0xfdb78cf4), SPH_C32(0xed8d0000), + SPH_C32(0x200f0588), SPH_C32(0x5bb00000), SPH_C32(0xabc90000), + SPH_C32(0xe0ad1e37), SPH_C32(0xeac524c5), SPH_C32(0xd406fdd6), + SPH_C32(0x0674dd6c) }, + { SPH_C32(0x768c0000), SPH_C32(0x1a530f14), SPH_C32(0xff3b0000), + SPH_C32(0xac6c0000), SPH_C32(0xbea35d59), SPH_C32(0x2e37ec6d), + SPH_C32(0x88993dc4), SPH_C32(0xaffd81ad), SPH_C32(0xb9dd0000), + SPH_C32(0x267e05d4), SPH_C32(0x7e1e0000), SPH_C32(0xc1d70000), + SPH_C32(0xce0850e8), SPH_C32(0x8c8ba1d7), SPH_C32(0x6bbce515), + SPH_C32(0x7805807b) }, + { SPH_C32(0x22dc0000), SPH_C32(0x1c220f48), SPH_C32(0xda950000), + SPH_C32(0xc6720000), SPH_C32(0x90061386), SPH_C32(0x4879697f), + SPH_C32(0x37232507), SPH_C32(0xd18cdcba), SPH_C32(0x05500000), + SPH_C32(0xda4505cc), SPH_C32(0x679d0000), SPH_C32(0x10dc0000), + SPH_C32(0x6010282c), SPH_C32(0xce2d3981), SPH_C32(0x6bae3f22), + SPH_C32(0x543ed035) }, + { SPH_C32(0xa3500000), SPH_C32(0x32890f90), SPH_C32(0x259b0000), + SPH_C32(0xd1480000), SPH_C32(0xf42e2e33), SPH_C32(0xa23561e7), + SPH_C32(0x0f67cf8f), SPH_C32(0x3f27722d), SPH_C32(0x97730000), + SPH_C32(0x73b9059c), SPH_C32(0xe6f20000), SPH_C32(0x5b4f0000), + SPH_C32(0x6da47374), SPH_C32(0xd170edbc), SPH_C32(0xc93c8b69), + SPH_C32(0x1dc25c51) }, + { SPH_C32(0xf7000000), SPH_C32(0x34f80fcc), SPH_C32(0x00350000), + SPH_C32(0xbb560000), SPH_C32(0xda8b60ec), SPH_C32(0xc47be4f5), + SPH_C32(0xb0ddd74c), SPH_C32(0x41562f3a), SPH_C32(0x2bfe0000), + SPH_C32(0x8f820584), SPH_C32(0xff710000), SPH_C32(0x8a440000), + SPH_C32(0xc3bc0bb0), SPH_C32(0x93d675ea), SPH_C32(0xc92e515e), + SPH_C32(0x31f90c1f) }, + { SPH_C32(0x1fdd0000), SPH_C32(0xceb20f88), SPH_C32(0x3c180000), + SPH_C32(0x00430000), SPH_C32(0x5a3656f7), SPH_C32(0xe093f9b1), + SPH_C32(0x0f7515b8), SPH_C32(0x131c2263), SPH_C32(0x7fae0000), + SPH_C32(0x89f305d8), SPH_C32(0xdadf0000), SPH_C32(0xe05a0000), + SPH_C32(0xed19456f), SPH_C32(0xf598f0f8), SPH_C32(0x7694499d), + SPH_C32(0x4f885108) }, + { SPH_C32(0x4b8d0000), SPH_C32(0xc8c30fd4), SPH_C32(0x19b60000), + SPH_C32(0x6a5d0000), SPH_C32(0x74931828), SPH_C32(0x86dd7ca3), + SPH_C32(0xb0cf0d7b), SPH_C32(0x6d6d7f74), SPH_C32(0xc3230000), + SPH_C32(0x75c805c0), SPH_C32(0xc35c0000), SPH_C32(0x31510000), + SPH_C32(0x43013dab), SPH_C32(0xb73e68ae), SPH_C32(0x768693aa), + SPH_C32(0x63b30146) }, + { SPH_C32(0xfe220000), SPH_C32(0xa7580500), SPH_C32(0x25d10000), + SPH_C32(0xf7600000), SPH_C32(0x893178da), SPH_C32(0x1fd4f860), + SPH_C32(0x4ed0a315), SPH_C32(0xa123ff9f), SPH_C32(0xf2500000), + SPH_C32(0xeebd0a00), SPH_C32(0x67a80000), SPH_C32(0xab8a0000), + SPH_C32(0xba9b48c0), SPH_C32(0x0a56dd74), SPH_C32(0xdb73e86e), + SPH_C32(0x1568ff0f) }, + { SPH_C32(0xaa720000), SPH_C32(0xa129055c), SPH_C32(0x007f0000), + SPH_C32(0x9d7e0000), SPH_C32(0xa7943605), SPH_C32(0x799a7d72), + SPH_C32(0xf16abbd6), SPH_C32(0xdf52a288), SPH_C32(0x4edd0000), + SPH_C32(0x12860a18), SPH_C32(0x7e2b0000), SPH_C32(0x7a810000), + SPH_C32(0x14833004), SPH_C32(0x48f04522), SPH_C32(0xdb613259), + SPH_C32(0x3953af41) }, + { SPH_C32(0x42af0000), SPH_C32(0x5b630518), SPH_C32(0x3c520000), + SPH_C32(0x266b0000), SPH_C32(0x2729001e), SPH_C32(0x5d726036), + SPH_C32(0x4ec27922), SPH_C32(0x8d18afd1), SPH_C32(0x1a8d0000), + SPH_C32(0x14f70a44), SPH_C32(0x5b850000), SPH_C32(0x109f0000), + SPH_C32(0x3a267edb), SPH_C32(0x2ebec030), SPH_C32(0x64db2a9a), + SPH_C32(0x4722f256) }, + { SPH_C32(0x16ff0000), SPH_C32(0x5d120544), SPH_C32(0x19fc0000), + SPH_C32(0x4c750000), SPH_C32(0x098c4ec1), SPH_C32(0x3b3ce524), + SPH_C32(0xf17861e1), SPH_C32(0xf369f2c6), SPH_C32(0xa6000000), + SPH_C32(0xe8cc0a5c), SPH_C32(0x42060000), SPH_C32(0xc1940000), + SPH_C32(0x943e061f), SPH_C32(0x6c185866), SPH_C32(0x64c9f0ad), + SPH_C32(0x6b19a218) }, + { SPH_C32(0x97730000), SPH_C32(0x73b9059c), SPH_C32(0xe6f20000), + SPH_C32(0x5b4f0000), SPH_C32(0x6da47374), SPH_C32(0xd170edbc), + SPH_C32(0xc93c8b69), SPH_C32(0x1dc25c51), SPH_C32(0x34230000), + SPH_C32(0x41300a0c), SPH_C32(0xc3690000), SPH_C32(0x8a070000), + SPH_C32(0x998a5d47), SPH_C32(0x73458c5b), SPH_C32(0xc65b44e6), + SPH_C32(0x22e52e7c) }, + { SPH_C32(0xc3230000), SPH_C32(0x75c805c0), SPH_C32(0xc35c0000), + SPH_C32(0x31510000), SPH_C32(0x43013dab), SPH_C32(0xb73e68ae), + SPH_C32(0x768693aa), SPH_C32(0x63b30146), SPH_C32(0x88ae0000), + SPH_C32(0xbd0b0a14), SPH_C32(0xdaea0000), SPH_C32(0x5b0c0000), + SPH_C32(0x37922583), SPH_C32(0x31e3140d), SPH_C32(0xc6499ed1), + SPH_C32(0x0ede7e32) }, + { SPH_C32(0x2bfe0000), SPH_C32(0x8f820584), SPH_C32(0xff710000), + SPH_C32(0x8a440000), SPH_C32(0xc3bc0bb0), SPH_C32(0x93d675ea), + SPH_C32(0xc92e515e), SPH_C32(0x31f90c1f), SPH_C32(0xdcfe0000), + SPH_C32(0xbb7a0a48), SPH_C32(0xff440000), SPH_C32(0x31120000), + SPH_C32(0x19376b5c), SPH_C32(0x57ad911f), SPH_C32(0x79f38612), + SPH_C32(0x70af2325) }, + { SPH_C32(0x7fae0000), SPH_C32(0x89f305d8), SPH_C32(0xdadf0000), + SPH_C32(0xe05a0000), SPH_C32(0xed19456f), SPH_C32(0xf598f0f8), + SPH_C32(0x7694499d), SPH_C32(0x4f885108), SPH_C32(0x60730000), + SPH_C32(0x47410a50), SPH_C32(0xe6c70000), SPH_C32(0xe0190000), + SPH_C32(0xb72f1398), SPH_C32(0x150b0949), SPH_C32(0x79e15c25), + SPH_C32(0x5c94736b) }, + { SPH_C32(0x38510000), SPH_C32(0x08d5050c), SPH_C32(0x81100000), + SPH_C32(0xd6ed0000), SPH_C32(0xaa206d5d), SPH_C32(0x66c7a94f), + SPH_C32(0x53f80f9d), SPH_C32(0x96ae2eec), SPH_C32(0x5d720000), + SPH_C32(0x95d10a90), SPH_C32(0x004a0000), SPH_C32(0x26280000), + SPH_C32(0x7d1f56e9), SPH_C32(0xbde19987), SPH_C32(0x41b76c9a), + SPH_C32(0x9e048db2) }, + { SPH_C32(0x6c010000), SPH_C32(0x0ea40550), SPH_C32(0xa4be0000), + SPH_C32(0xbcf30000), SPH_C32(0x84852382), SPH_C32(0x00892c5d), + SPH_C32(0xec42175e), SPH_C32(0xe8df73fb), SPH_C32(0xe1ff0000), + SPH_C32(0x69ea0a88), SPH_C32(0x19c90000), SPH_C32(0xf7230000), + SPH_C32(0xd3072e2d), SPH_C32(0xff4701d1), SPH_C32(0x41a5b6ad), + SPH_C32(0xb23fddfc) }, + { SPH_C32(0x84dc0000), SPH_C32(0xf4ee0514), SPH_C32(0x98930000), + SPH_C32(0x07e60000), SPH_C32(0x04381599), SPH_C32(0x24613119), + SPH_C32(0x53ead5aa), SPH_C32(0xba957ea2), SPH_C32(0xb5af0000), + SPH_C32(0x6f9b0ad4), SPH_C32(0x3c670000), SPH_C32(0x9d3d0000), + SPH_C32(0xfda260f2), SPH_C32(0x990984c3), SPH_C32(0xfe1fae6e), + SPH_C32(0xcc4e80eb) }, + { SPH_C32(0xd08c0000), SPH_C32(0xf29f0548), SPH_C32(0xbd3d0000), + SPH_C32(0x6df80000), SPH_C32(0x2a9d5b46), SPH_C32(0x422fb40b), + SPH_C32(0xec50cd69), SPH_C32(0xc4e423b5), SPH_C32(0x09220000), + SPH_C32(0x93a00acc), SPH_C32(0x25e40000), SPH_C32(0x4c360000), + SPH_C32(0x53ba1836), SPH_C32(0xdbaf1c95), SPH_C32(0xfe0d7459), + SPH_C32(0xe075d0a5) }, + { SPH_C32(0x51000000), SPH_C32(0xdc340590), SPH_C32(0x42330000), + SPH_C32(0x7ac20000), SPH_C32(0x4eb566f3), SPH_C32(0xa863bc93), + SPH_C32(0xd41427e1), SPH_C32(0x2a4f8d22), SPH_C32(0x9b010000), + SPH_C32(0x3a5c0a9c), SPH_C32(0xa48b0000), SPH_C32(0x07a50000), + SPH_C32(0x5e0e436e), SPH_C32(0xc4f2c8a8), SPH_C32(0x5c9fc012), + SPH_C32(0xa9895cc1) }, + { SPH_C32(0x05500000), SPH_C32(0xda4505cc), SPH_C32(0x679d0000), + SPH_C32(0x10dc0000), SPH_C32(0x6010282c), SPH_C32(0xce2d3981), + SPH_C32(0x6bae3f22), SPH_C32(0x543ed035), SPH_C32(0x278c0000), + SPH_C32(0xc6670a84), SPH_C32(0xbd080000), SPH_C32(0xd6ae0000), + SPH_C32(0xf0163baa), SPH_C32(0x865450fe), SPH_C32(0x5c8d1a25), + SPH_C32(0x85b20c8f) }, + { SPH_C32(0xed8d0000), SPH_C32(0x200f0588), SPH_C32(0x5bb00000), + SPH_C32(0xabc90000), SPH_C32(0xe0ad1e37), SPH_C32(0xeac524c5), + SPH_C32(0xd406fdd6), SPH_C32(0x0674dd6c), SPH_C32(0x73dc0000), + SPH_C32(0xc0160ad8), SPH_C32(0x98a60000), SPH_C32(0xbcb00000), + SPH_C32(0xdeb37575), SPH_C32(0xe01ad5ec), SPH_C32(0xe33702e6), + SPH_C32(0xfbc35198) }, + { SPH_C32(0xb9dd0000), SPH_C32(0x267e05d4), SPH_C32(0x7e1e0000), + SPH_C32(0xc1d70000), SPH_C32(0xce0850e8), SPH_C32(0x8c8ba1d7), + SPH_C32(0x6bbce515), SPH_C32(0x7805807b), SPH_C32(0xcf510000), + SPH_C32(0x3c2d0ac0), SPH_C32(0x81250000), SPH_C32(0x6dbb0000), + SPH_C32(0x70ab0db1), SPH_C32(0xa2bc4dba), SPH_C32(0xe325d8d1), + SPH_C32(0xd7f801d6) }, + { SPH_C32(0xf2500000), SPH_C32(0xeebd0a00), SPH_C32(0x67a80000), + SPH_C32(0xab8a0000), SPH_C32(0xba9b48c0), SPH_C32(0x0a56dd74), + SPH_C32(0xdb73e86e), SPH_C32(0x1568ff0f), SPH_C32(0x0c720000), + SPH_C32(0x49e50f00), SPH_C32(0x42790000), SPH_C32(0x5cea0000), + SPH_C32(0x33aa301a), SPH_C32(0x15822514), SPH_C32(0x95a34b7b), + SPH_C32(0xb44b0090) }, + { SPH_C32(0xa6000000), SPH_C32(0xe8cc0a5c), SPH_C32(0x42060000), + SPH_C32(0xc1940000), SPH_C32(0x943e061f), SPH_C32(0x6c185866), + SPH_C32(0x64c9f0ad), SPH_C32(0x6b19a218), SPH_C32(0xb0ff0000), + SPH_C32(0xb5de0f18), SPH_C32(0x5bfa0000), SPH_C32(0x8de10000), + SPH_C32(0x9db248de), SPH_C32(0x5724bd42), SPH_C32(0x95b1914c), + SPH_C32(0x987050de) }, + { SPH_C32(0x4edd0000), SPH_C32(0x12860a18), SPH_C32(0x7e2b0000), + SPH_C32(0x7a810000), SPH_C32(0x14833004), SPH_C32(0x48f04522), + SPH_C32(0xdb613259), SPH_C32(0x3953af41), SPH_C32(0xe4af0000), + SPH_C32(0xb3af0f44), SPH_C32(0x7e540000), SPH_C32(0xe7ff0000), + SPH_C32(0xb3170601), SPH_C32(0x316a3850), SPH_C32(0x2a0b898f), + SPH_C32(0xe6010dc9) }, + { SPH_C32(0x1a8d0000), SPH_C32(0x14f70a44), SPH_C32(0x5b850000), + SPH_C32(0x109f0000), SPH_C32(0x3a267edb), SPH_C32(0x2ebec030), + SPH_C32(0x64db2a9a), SPH_C32(0x4722f256), SPH_C32(0x58220000), + SPH_C32(0x4f940f5c), SPH_C32(0x67d70000), SPH_C32(0x36f40000), + SPH_C32(0x1d0f7ec5), SPH_C32(0x73cca006), SPH_C32(0x2a1953b8), + SPH_C32(0xca3a5d87) }, + { SPH_C32(0x9b010000), SPH_C32(0x3a5c0a9c), SPH_C32(0xa48b0000), + SPH_C32(0x07a50000), SPH_C32(0x5e0e436e), SPH_C32(0xc4f2c8a8), + SPH_C32(0x5c9fc012), SPH_C32(0xa9895cc1), SPH_C32(0xca010000), + SPH_C32(0xe6680f0c), SPH_C32(0xe6b80000), SPH_C32(0x7d670000), + SPH_C32(0x10bb259d), SPH_C32(0x6c91743b), SPH_C32(0x888be7f3), + SPH_C32(0x83c6d1e3) }, + { SPH_C32(0xcf510000), SPH_C32(0x3c2d0ac0), SPH_C32(0x81250000), + SPH_C32(0x6dbb0000), SPH_C32(0x70ab0db1), SPH_C32(0xa2bc4dba), + SPH_C32(0xe325d8d1), SPH_C32(0xd7f801d6), SPH_C32(0x768c0000), + SPH_C32(0x1a530f14), SPH_C32(0xff3b0000), SPH_C32(0xac6c0000), + SPH_C32(0xbea35d59), SPH_C32(0x2e37ec6d), SPH_C32(0x88993dc4), + SPH_C32(0xaffd81ad) }, + { SPH_C32(0x278c0000), SPH_C32(0xc6670a84), SPH_C32(0xbd080000), + SPH_C32(0xd6ae0000), SPH_C32(0xf0163baa), SPH_C32(0x865450fe), + SPH_C32(0x5c8d1a25), SPH_C32(0x85b20c8f), SPH_C32(0x22dc0000), + SPH_C32(0x1c220f48), SPH_C32(0xda950000), SPH_C32(0xc6720000), + SPH_C32(0x90061386), SPH_C32(0x4879697f), SPH_C32(0x37232507), + SPH_C32(0xd18cdcba) }, + { SPH_C32(0x73dc0000), SPH_C32(0xc0160ad8), SPH_C32(0x98a60000), + SPH_C32(0xbcb00000), SPH_C32(0xdeb37575), SPH_C32(0xe01ad5ec), + SPH_C32(0xe33702e6), SPH_C32(0xfbc35198), SPH_C32(0x9e510000), + SPH_C32(0xe0190f50), SPH_C32(0xc3160000), SPH_C32(0x17790000), + SPH_C32(0x3e1e6b42), SPH_C32(0x0adff129), SPH_C32(0x3731ff30), + SPH_C32(0xfdb78cf4) }, + { SPH_C32(0x34230000), SPH_C32(0x41300a0c), SPH_C32(0xc3690000), + SPH_C32(0x8a070000), SPH_C32(0x998a5d47), SPH_C32(0x73458c5b), + SPH_C32(0xc65b44e6), SPH_C32(0x22e52e7c), SPH_C32(0xa3500000), + SPH_C32(0x32890f90), SPH_C32(0x259b0000), SPH_C32(0xd1480000), + SPH_C32(0xf42e2e33), SPH_C32(0xa23561e7), SPH_C32(0x0f67cf8f), + SPH_C32(0x3f27722d) }, + { SPH_C32(0x60730000), SPH_C32(0x47410a50), SPH_C32(0xe6c70000), + SPH_C32(0xe0190000), SPH_C32(0xb72f1398), SPH_C32(0x150b0949), + SPH_C32(0x79e15c25), SPH_C32(0x5c94736b), SPH_C32(0x1fdd0000), + SPH_C32(0xceb20f88), SPH_C32(0x3c180000), SPH_C32(0x00430000), + SPH_C32(0x5a3656f7), SPH_C32(0xe093f9b1), SPH_C32(0x0f7515b8), + SPH_C32(0x131c2263) }, + { SPH_C32(0x88ae0000), SPH_C32(0xbd0b0a14), SPH_C32(0xdaea0000), + SPH_C32(0x5b0c0000), SPH_C32(0x37922583), SPH_C32(0x31e3140d), + SPH_C32(0xc6499ed1), SPH_C32(0x0ede7e32), SPH_C32(0x4b8d0000), + SPH_C32(0xc8c30fd4), SPH_C32(0x19b60000), SPH_C32(0x6a5d0000), + SPH_C32(0x74931828), SPH_C32(0x86dd7ca3), SPH_C32(0xb0cf0d7b), + SPH_C32(0x6d6d7f74) }, + { SPH_C32(0xdcfe0000), SPH_C32(0xbb7a0a48), SPH_C32(0xff440000), + SPH_C32(0x31120000), SPH_C32(0x19376b5c), SPH_C32(0x57ad911f), + SPH_C32(0x79f38612), SPH_C32(0x70af2325), SPH_C32(0xf7000000), + SPH_C32(0x34f80fcc), SPH_C32(0x00350000), SPH_C32(0xbb560000), + SPH_C32(0xda8b60ec), SPH_C32(0xc47be4f5), SPH_C32(0xb0ddd74c), + SPH_C32(0x41562f3a) }, + { SPH_C32(0x5d720000), SPH_C32(0x95d10a90), SPH_C32(0x004a0000), + SPH_C32(0x26280000), SPH_C32(0x7d1f56e9), SPH_C32(0xbde19987), + SPH_C32(0x41b76c9a), SPH_C32(0x9e048db2), SPH_C32(0x65230000), + SPH_C32(0x9d040f9c), SPH_C32(0x815a0000), SPH_C32(0xf0c50000), + SPH_C32(0xd73f3bb4), SPH_C32(0xdb2630c8), SPH_C32(0x124f6307), + SPH_C32(0x08aaa35e) }, + { SPH_C32(0x09220000), SPH_C32(0x93a00acc), SPH_C32(0x25e40000), + SPH_C32(0x4c360000), SPH_C32(0x53ba1836), SPH_C32(0xdbaf1c95), + SPH_C32(0xfe0d7459), SPH_C32(0xe075d0a5), SPH_C32(0xd9ae0000), + SPH_C32(0x613f0f84), SPH_C32(0x98d90000), SPH_C32(0x21ce0000), + SPH_C32(0x79274370), SPH_C32(0x9980a89e), SPH_C32(0x125db930), + SPH_C32(0x2491f310) }, + { SPH_C32(0xe1ff0000), SPH_C32(0x69ea0a88), SPH_C32(0x19c90000), + SPH_C32(0xf7230000), SPH_C32(0xd3072e2d), SPH_C32(0xff4701d1), + SPH_C32(0x41a5b6ad), SPH_C32(0xb23fddfc), SPH_C32(0x8dfe0000), + SPH_C32(0x674e0fd8), SPH_C32(0xbd770000), SPH_C32(0x4bd00000), + SPH_C32(0x57820daf), SPH_C32(0xffce2d8c), SPH_C32(0xade7a1f3), + SPH_C32(0x5ae0ae07) }, + { SPH_C32(0xb5af0000), SPH_C32(0x6f9b0ad4), SPH_C32(0x3c670000), + SPH_C32(0x9d3d0000), SPH_C32(0xfda260f2), SPH_C32(0x990984c3), + SPH_C32(0xfe1fae6e), SPH_C32(0xcc4e80eb), SPH_C32(0x31730000), + SPH_C32(0x9b750fc0), SPH_C32(0xa4f40000), SPH_C32(0x9adb0000), + SPH_C32(0xf99a756b), SPH_C32(0xbd68b5da), SPH_C32(0xadf57bc4), + SPH_C32(0x76dbfe49) }, + { SPH_C32(0x45180000), SPH_C32(0xa5b51700), SPH_C32(0xf96a0000), + SPH_C32(0x3b480000), SPH_C32(0x1ecc142c), SPH_C32(0x231395d6), + SPH_C32(0x16bca6b0), SPH_C32(0xdf33f4df), SPH_C32(0xb83d0000), + SPH_C32(0x16710600), SPH_C32(0x379a0000), SPH_C32(0xf5b10000), + SPH_C32(0x228161ac), SPH_C32(0xae48f145), SPH_C32(0x66241616), + SPH_C32(0xc5c1eb3e) }, + { SPH_C32(0x11480000), SPH_C32(0xa3c4175c), SPH_C32(0xdcc40000), + SPH_C32(0x51560000), SPH_C32(0x30695af3), SPH_C32(0x455d10c4), + SPH_C32(0xa906be73), SPH_C32(0xa142a9c8), SPH_C32(0x04b00000), + SPH_C32(0xea4a0618), SPH_C32(0x2e190000), SPH_C32(0x24ba0000), + SPH_C32(0x8c991968), SPH_C32(0xecee6913), SPH_C32(0x6636cc21), + SPH_C32(0xe9fabb70) }, + { SPH_C32(0xf9950000), SPH_C32(0x598e1718), SPH_C32(0xe0e90000), + SPH_C32(0xea430000), SPH_C32(0xb0d46ce8), SPH_C32(0x61b50d80), + SPH_C32(0x16ae7c87), SPH_C32(0xf308a491), SPH_C32(0x50e00000), + SPH_C32(0xec3b0644), SPH_C32(0x0bb70000), SPH_C32(0x4ea40000), + SPH_C32(0xa23c57b7), SPH_C32(0x8aa0ec01), SPH_C32(0xd98cd4e2), + SPH_C32(0x978be667) }, + { SPH_C32(0xadc50000), SPH_C32(0x5fff1744), SPH_C32(0xc5470000), + SPH_C32(0x805d0000), SPH_C32(0x9e712237), SPH_C32(0x07fb8892), + SPH_C32(0xa9146444), SPH_C32(0x8d79f986), SPH_C32(0xec6d0000), + SPH_C32(0x1000065c), SPH_C32(0x12340000), SPH_C32(0x9faf0000), + SPH_C32(0x0c242f73), SPH_C32(0xc8067457), SPH_C32(0xd99e0ed5), + SPH_C32(0xbbb0b629) }, + { SPH_C32(0x2c490000), SPH_C32(0x7154179c), SPH_C32(0x3a490000), + SPH_C32(0x97670000), SPH_C32(0xfa591f82), SPH_C32(0xedb7800a), + SPH_C32(0x91508ecc), SPH_C32(0x63d25711), SPH_C32(0x7e4e0000), + SPH_C32(0xb9fc060c), SPH_C32(0x935b0000), SPH_C32(0xd43c0000), + SPH_C32(0x0190742b), SPH_C32(0xd75ba06a), SPH_C32(0x7b0cba9e), + SPH_C32(0xf24c3a4d) }, + { SPH_C32(0x78190000), SPH_C32(0x772517c0), SPH_C32(0x1fe70000), + SPH_C32(0xfd790000), SPH_C32(0xd4fc515d), SPH_C32(0x8bf90518), + SPH_C32(0x2eea960f), SPH_C32(0x1da30a06), SPH_C32(0xc2c30000), + SPH_C32(0x45c70614), SPH_C32(0x8ad80000), SPH_C32(0x05370000), + SPH_C32(0xaf880cef), SPH_C32(0x95fd383c), SPH_C32(0x7b1e60a9), + SPH_C32(0xde776a03) }, + { SPH_C32(0x90c40000), SPH_C32(0x8d6f1784), SPH_C32(0x23ca0000), + SPH_C32(0x466c0000), SPH_C32(0x54416746), SPH_C32(0xaf11185c), + SPH_C32(0x914254fb), SPH_C32(0x4fe9075f), SPH_C32(0x96930000), + SPH_C32(0x43b60648), SPH_C32(0xaf760000), SPH_C32(0x6f290000), + SPH_C32(0x812d4230), SPH_C32(0xf3b3bd2e), SPH_C32(0xc4a4786a), + SPH_C32(0xa0063714) }, + { SPH_C32(0xc4940000), SPH_C32(0x8b1e17d8), SPH_C32(0x06640000), + SPH_C32(0x2c720000), SPH_C32(0x7ae42999), SPH_C32(0xc95f9d4e), + SPH_C32(0x2ef84c38), SPH_C32(0x31985a48), SPH_C32(0x2a1e0000), + SPH_C32(0xbf8d0650), SPH_C32(0xb6f50000), SPH_C32(0xbe220000), + SPH_C32(0x2f353af4), SPH_C32(0xb1152578), SPH_C32(0xc4b6a25d), + SPH_C32(0x8c3d675a) }, + { SPH_C32(0x836b0000), SPH_C32(0x0a38170c), SPH_C32(0x5dab0000), + SPH_C32(0x1ac50000), SPH_C32(0x3ddd01ab), SPH_C32(0x5a00c4f9), + SPH_C32(0x0b940a38), SPH_C32(0xe8be25ac), SPH_C32(0x171f0000), + SPH_C32(0x6d1d0690), SPH_C32(0x50780000), SPH_C32(0x78130000), + SPH_C32(0xe5057f85), SPH_C32(0x19ffb5b6), SPH_C32(0xfce092e2), + SPH_C32(0x4ead9983) }, + { SPH_C32(0xd73b0000), SPH_C32(0x0c491750), SPH_C32(0x78050000), + SPH_C32(0x70db0000), SPH_C32(0x13784f74), SPH_C32(0x3c4e41eb), + SPH_C32(0xb42e12fb), SPH_C32(0x96cf78bb), SPH_C32(0xab920000), + SPH_C32(0x91260688), SPH_C32(0x49fb0000), SPH_C32(0xa9180000), + SPH_C32(0x4b1d0741), SPH_C32(0x5b592de0), SPH_C32(0xfcf248d5), + SPH_C32(0x6296c9cd) }, + { SPH_C32(0x3fe60000), SPH_C32(0xf6031714), SPH_C32(0x44280000), + SPH_C32(0xcbce0000), SPH_C32(0x93c5796f), SPH_C32(0x18a65caf), + SPH_C32(0x0b86d00f), SPH_C32(0xc48575e2), SPH_C32(0xffc20000), + SPH_C32(0x975706d4), SPH_C32(0x6c550000), SPH_C32(0xc3060000), + SPH_C32(0x65b8499e), SPH_C32(0x3d17a8f2), SPH_C32(0x43485016), + SPH_C32(0x1ce794da) }, + { SPH_C32(0x6bb60000), SPH_C32(0xf0721748), SPH_C32(0x61860000), + SPH_C32(0xa1d00000), SPH_C32(0xbd6037b0), SPH_C32(0x7ee8d9bd), + SPH_C32(0xb43cc8cc), SPH_C32(0xbaf428f5), SPH_C32(0x434f0000), + SPH_C32(0x6b6c06cc), SPH_C32(0x75d60000), SPH_C32(0x120d0000), + SPH_C32(0xcba0315a), SPH_C32(0x7fb130a4), SPH_C32(0x435a8a21), + SPH_C32(0x30dcc494) }, + { SPH_C32(0xea3a0000), SPH_C32(0xded91790), SPH_C32(0x9e880000), + SPH_C32(0xb6ea0000), SPH_C32(0xd9480a05), SPH_C32(0x94a4d125), + SPH_C32(0x8c782244), SPH_C32(0x545f8662), SPH_C32(0xd16c0000), + SPH_C32(0xc290069c), SPH_C32(0xf4b90000), SPH_C32(0x599e0000), + SPH_C32(0xc6146a02), SPH_C32(0x60ece499), SPH_C32(0xe1c83e6a), + SPH_C32(0x792048f0) }, + { SPH_C32(0xbe6a0000), SPH_C32(0xd8a817cc), SPH_C32(0xbb260000), + SPH_C32(0xdcf40000), SPH_C32(0xf7ed44da), SPH_C32(0xf2ea5437), + SPH_C32(0x33c23a87), SPH_C32(0x2a2edb75), SPH_C32(0x6de10000), + SPH_C32(0x3eab0684), SPH_C32(0xed3a0000), SPH_C32(0x88950000), + SPH_C32(0x680c12c6), SPH_C32(0x224a7ccf), SPH_C32(0xe1dae45d), + SPH_C32(0x551b18be) }, + { SPH_C32(0x56b70000), SPH_C32(0x22e21788), SPH_C32(0x870b0000), + SPH_C32(0x67e10000), SPH_C32(0x775072c1), SPH_C32(0xd6024973), + SPH_C32(0x8c6af873), SPH_C32(0x7864d62c), SPH_C32(0x39b10000), + SPH_C32(0x38da06d8), SPH_C32(0xc8940000), SPH_C32(0xe28b0000), + SPH_C32(0x46a95c19), SPH_C32(0x4404f9dd), SPH_C32(0x5e60fc9e), + SPH_C32(0x2b6a45a9) }, + { SPH_C32(0x02e70000), SPH_C32(0x249317d4), SPH_C32(0xa2a50000), + SPH_C32(0x0dff0000), SPH_C32(0x59f53c1e), SPH_C32(0xb04ccc61), + SPH_C32(0x33d0e0b0), SPH_C32(0x06158b3b), SPH_C32(0x853c0000), + SPH_C32(0xc4e106c0), SPH_C32(0xd1170000), SPH_C32(0x33800000), + SPH_C32(0xe8b124dd), SPH_C32(0x06a2618b), SPH_C32(0x5e7226a9), + SPH_C32(0x075115e7) }, + { SPH_C32(0x496a0000), SPH_C32(0xec501800), SPH_C32(0xbb130000), + SPH_C32(0x67a20000), SPH_C32(0x2d662436), SPH_C32(0x3691b0c2), + SPH_C32(0x831fedcb), SPH_C32(0x6b78f44f), SPH_C32(0x461f0000), + SPH_C32(0xb1290300), SPH_C32(0x124b0000), SPH_C32(0x02d10000), + SPH_C32(0xabb01976), SPH_C32(0xb19c0925), SPH_C32(0x28f4b503), + SPH_C32(0x64e214a1) }, + { SPH_C32(0x1d3a0000), SPH_C32(0xea21185c), SPH_C32(0x9ebd0000), + SPH_C32(0x0dbc0000), SPH_C32(0x03c36ae9), SPH_C32(0x50df35d0), + SPH_C32(0x3ca5f508), SPH_C32(0x1509a958), SPH_C32(0xfa920000), + SPH_C32(0x4d120318), SPH_C32(0x0bc80000), SPH_C32(0xd3da0000), + SPH_C32(0x05a861b2), SPH_C32(0xf33a9173), SPH_C32(0x28e66f34), + SPH_C32(0x48d944ef) }, + { SPH_C32(0xf5e70000), SPH_C32(0x106b1818), SPH_C32(0xa2900000), + SPH_C32(0xb6a90000), SPH_C32(0x837e5cf2), SPH_C32(0x74372894), + SPH_C32(0x830d37fc), SPH_C32(0x4743a401), SPH_C32(0xaec20000), + SPH_C32(0x4b630344), SPH_C32(0x2e660000), SPH_C32(0xb9c40000), + SPH_C32(0x2b0d2f6d), SPH_C32(0x95741461), SPH_C32(0x975c77f7), + SPH_C32(0x36a819f8) }, + { SPH_C32(0xa1b70000), SPH_C32(0x161a1844), SPH_C32(0x873e0000), + SPH_C32(0xdcb70000), SPH_C32(0xaddb122d), SPH_C32(0x1279ad86), + SPH_C32(0x3cb72f3f), SPH_C32(0x3932f916), SPH_C32(0x124f0000), + SPH_C32(0xb758035c), SPH_C32(0x37e50000), SPH_C32(0x68cf0000), + SPH_C32(0x851557a9), SPH_C32(0xd7d28c37), SPH_C32(0x974eadc0), + SPH_C32(0x1a9349b6) }, + { SPH_C32(0x203b0000), SPH_C32(0x38b1189c), SPH_C32(0x78300000), + SPH_C32(0xcb8d0000), SPH_C32(0xc9f32f98), SPH_C32(0xf835a51e), + SPH_C32(0x04f3c5b7), SPH_C32(0xd7995781), SPH_C32(0x806c0000), + SPH_C32(0x1ea4030c), SPH_C32(0xb68a0000), SPH_C32(0x235c0000), + SPH_C32(0x88a10cf1), SPH_C32(0xc88f580a), SPH_C32(0x35dc198b), + SPH_C32(0x536fc5d2) }, + { SPH_C32(0x746b0000), SPH_C32(0x3ec018c0), SPH_C32(0x5d9e0000), + SPH_C32(0xa1930000), SPH_C32(0xe7566147), SPH_C32(0x9e7b200c), + SPH_C32(0xbb49dd74), SPH_C32(0xa9e80a96), SPH_C32(0x3ce10000), + SPH_C32(0xe29f0314), SPH_C32(0xaf090000), SPH_C32(0xf2570000), + SPH_C32(0x26b97435), SPH_C32(0x8a29c05c), SPH_C32(0x35cec3bc), + SPH_C32(0x7f54959c) }, + { SPH_C32(0x9cb60000), SPH_C32(0xc48a1884), SPH_C32(0x61b30000), + SPH_C32(0x1a860000), SPH_C32(0x67eb575c), SPH_C32(0xba933d48), + SPH_C32(0x04e11f80), SPH_C32(0xfba207cf), SPH_C32(0x68b10000), + SPH_C32(0xe4ee0348), SPH_C32(0x8aa70000), SPH_C32(0x98490000), + SPH_C32(0x081c3aea), SPH_C32(0xec67454e), SPH_C32(0x8a74db7f), + SPH_C32(0x0125c88b) }, + { SPH_C32(0xc8e60000), SPH_C32(0xc2fb18d8), SPH_C32(0x441d0000), + SPH_C32(0x70980000), SPH_C32(0x494e1983), SPH_C32(0xdcddb85a), + SPH_C32(0xbb5b0743), SPH_C32(0x85d35ad8), SPH_C32(0xd43c0000), + SPH_C32(0x18d50350), SPH_C32(0x93240000), SPH_C32(0x49420000), + SPH_C32(0xa604422e), SPH_C32(0xaec1dd18), SPH_C32(0x8a660148), + SPH_C32(0x2d1e98c5) }, + { SPH_C32(0x8f190000), SPH_C32(0x43dd180c), SPH_C32(0x1fd20000), + SPH_C32(0x462f0000), SPH_C32(0x0e7731b1), SPH_C32(0x4f82e1ed), + SPH_C32(0x9e374143), SPH_C32(0x5cf5253c), SPH_C32(0xe93d0000), + SPH_C32(0xca450390), SPH_C32(0x75a90000), SPH_C32(0x8f730000), + SPH_C32(0x6c34075f), SPH_C32(0x062b4dd6), SPH_C32(0xb23031f7), + SPH_C32(0xef8e661c) }, + { SPH_C32(0xdb490000), SPH_C32(0x45ac1850), SPH_C32(0x3a7c0000), + SPH_C32(0x2c310000), SPH_C32(0x20d27f6e), SPH_C32(0x29cc64ff), + SPH_C32(0x218d5980), SPH_C32(0x2284782b), SPH_C32(0x55b00000), + SPH_C32(0x367e0388), SPH_C32(0x6c2a0000), SPH_C32(0x5e780000), + SPH_C32(0xc22c7f9b), SPH_C32(0x448dd580), SPH_C32(0xb222ebc0), + SPH_C32(0xc3b53652) }, + { SPH_C32(0x33940000), SPH_C32(0xbfe61814), SPH_C32(0x06510000), + SPH_C32(0x97240000), SPH_C32(0xa06f4975), SPH_C32(0x0d2479bb), + SPH_C32(0x9e259b74), SPH_C32(0x70ce7572), SPH_C32(0x01e00000), + SPH_C32(0x300f03d4), SPH_C32(0x49840000), SPH_C32(0x34660000), + SPH_C32(0xec893144), SPH_C32(0x22c35092), SPH_C32(0x0d98f303), + SPH_C32(0xbdc46b45) }, + { SPH_C32(0x67c40000), SPH_C32(0xb9971848), SPH_C32(0x23ff0000), + SPH_C32(0xfd3a0000), SPH_C32(0x8eca07aa), SPH_C32(0x6b6afca9), + SPH_C32(0x219f83b7), SPH_C32(0x0ebf2865), SPH_C32(0xbd6d0000), + SPH_C32(0xcc3403cc), SPH_C32(0x50070000), SPH_C32(0xe56d0000), + SPH_C32(0x42914980), SPH_C32(0x6065c8c4), SPH_C32(0x0d8a2934), + SPH_C32(0x91ff3b0b) }, + { SPH_C32(0xe6480000), SPH_C32(0x973c1890), SPH_C32(0xdcf10000), + SPH_C32(0xea000000), SPH_C32(0xeae23a1f), SPH_C32(0x8126f431), + SPH_C32(0x19db693f), SPH_C32(0xe01486f2), SPH_C32(0x2f4e0000), + SPH_C32(0x65c8039c), SPH_C32(0xd1680000), SPH_C32(0xaefe0000), + SPH_C32(0x4f2512d8), SPH_C32(0x7f381cf9), SPH_C32(0xaf189d7f), + SPH_C32(0xd803b76f) }, + { SPH_C32(0xb2180000), SPH_C32(0x914d18cc), SPH_C32(0xf95f0000), + SPH_C32(0x801e0000), SPH_C32(0xc44774c0), SPH_C32(0xe7687123), + SPH_C32(0xa66171fc), SPH_C32(0x9e65dbe5), SPH_C32(0x93c30000), + SPH_C32(0x99f30384), SPH_C32(0xc8eb0000), SPH_C32(0x7ff50000), + SPH_C32(0xe13d6a1c), SPH_C32(0x3d9e84af), SPH_C32(0xaf0a4748), + SPH_C32(0xf438e721) }, + { SPH_C32(0x5ac50000), SPH_C32(0x6b071888), SPH_C32(0xc5720000), + SPH_C32(0x3b0b0000), SPH_C32(0x44fa42db), SPH_C32(0xc3806c67), + SPH_C32(0x19c9b308), SPH_C32(0xcc2fd6bc), SPH_C32(0xc7930000), + SPH_C32(0x9f8203d8), SPH_C32(0xed450000), SPH_C32(0x15eb0000), + SPH_C32(0xcf9824c3), SPH_C32(0x5bd001bd), SPH_C32(0x10b05f8b), + SPH_C32(0x8a49ba36) }, + { SPH_C32(0x0e950000), SPH_C32(0x6d7618d4), SPH_C32(0xe0dc0000), + SPH_C32(0x51150000), SPH_C32(0x6a5f0c04), SPH_C32(0xa5cee975), + SPH_C32(0xa673abcb), SPH_C32(0xb25e8bab), SPH_C32(0x7b1e0000), + SPH_C32(0x63b903c0), SPH_C32(0xf4c60000), SPH_C32(0xc4e00000), + SPH_C32(0x61805c07), SPH_C32(0x197699eb), SPH_C32(0x10a285bc), + SPH_C32(0xa672ea78) }, + { SPH_C32(0xbb3a0000), SPH_C32(0x02ed1200), SPH_C32(0xdcbb0000), + SPH_C32(0xcc280000), SPH_C32(0x97fd6cf6), SPH_C32(0x3cc76db6), + SPH_C32(0x586c05a5), SPH_C32(0x7e100b40), SPH_C32(0x4a6d0000), + SPH_C32(0xf8cc0c00), SPH_C32(0x50320000), SPH_C32(0x5e3b0000), + SPH_C32(0x981a296c), SPH_C32(0xa41e2c31), SPH_C32(0xbd57fe78), + SPH_C32(0xd0a91431) }, + { SPH_C32(0xef6a0000), SPH_C32(0x049c125c), SPH_C32(0xf9150000), + SPH_C32(0xa6360000), SPH_C32(0xb9582229), SPH_C32(0x5a89e8a4), + SPH_C32(0xe7d61d66), SPH_C32(0x00615657), SPH_C32(0xf6e00000), + SPH_C32(0x04f70c18), SPH_C32(0x49b10000), SPH_C32(0x8f300000), + SPH_C32(0x360251a8), SPH_C32(0xe6b8b467), SPH_C32(0xbd45244f), + SPH_C32(0xfc92447f) }, + { SPH_C32(0x07b70000), SPH_C32(0xfed61218), SPH_C32(0xc5380000), + SPH_C32(0x1d230000), SPH_C32(0x39e51432), SPH_C32(0x7e61f5e0), + SPH_C32(0x587edf92), SPH_C32(0x522b5b0e), SPH_C32(0xa2b00000), + SPH_C32(0x02860c44), SPH_C32(0x6c1f0000), SPH_C32(0xe52e0000), + SPH_C32(0x18a71f77), SPH_C32(0x80f63175), SPH_C32(0x02ff3c8c), + SPH_C32(0x82e31968) }, + { SPH_C32(0x53e70000), SPH_C32(0xf8a71244), SPH_C32(0xe0960000), + SPH_C32(0x773d0000), SPH_C32(0x17405aed), SPH_C32(0x182f70f2), + SPH_C32(0xe7c4c751), SPH_C32(0x2c5a0619), SPH_C32(0x1e3d0000), + SPH_C32(0xfebd0c5c), SPH_C32(0x759c0000), SPH_C32(0x34250000), + SPH_C32(0xb6bf67b3), SPH_C32(0xc250a923), SPH_C32(0x02ede6bb), + SPH_C32(0xaed84926) }, + { SPH_C32(0xd26b0000), SPH_C32(0xd60c129c), SPH_C32(0x1f980000), + SPH_C32(0x60070000), SPH_C32(0x73686758), SPH_C32(0xf263786a), + SPH_C32(0xdf802dd9), SPH_C32(0xc2f1a88e), SPH_C32(0x8c1e0000), + SPH_C32(0x57410c0c), SPH_C32(0xf4f30000), SPH_C32(0x7fb60000), + SPH_C32(0xbb0b3ceb), SPH_C32(0xdd0d7d1e), SPH_C32(0xa07f52f0), + SPH_C32(0xe724c542) }, + { SPH_C32(0x863b0000), SPH_C32(0xd07d12c0), SPH_C32(0x3a360000), + SPH_C32(0x0a190000), SPH_C32(0x5dcd2987), SPH_C32(0x942dfd78), + SPH_C32(0x603a351a), SPH_C32(0xbc80f599), SPH_C32(0x30930000), + SPH_C32(0xab7a0c14), SPH_C32(0xed700000), SPH_C32(0xaebd0000), + SPH_C32(0x1513442f), SPH_C32(0x9fabe548), SPH_C32(0xa06d88c7), + SPH_C32(0xcb1f950c) }, + { SPH_C32(0x6ee60000), SPH_C32(0x2a371284), SPH_C32(0x061b0000), + SPH_C32(0xb10c0000), SPH_C32(0xdd701f9c), SPH_C32(0xb0c5e03c), + SPH_C32(0xdf92f7ee), SPH_C32(0xeecaf8c0), SPH_C32(0x64c30000), + SPH_C32(0xad0b0c48), SPH_C32(0xc8de0000), SPH_C32(0xc4a30000), + SPH_C32(0x3bb60af0), SPH_C32(0xf9e5605a), SPH_C32(0x1fd79004), + SPH_C32(0xb56ec81b) }, + { SPH_C32(0x3ab60000), SPH_C32(0x2c4612d8), SPH_C32(0x23b50000), + SPH_C32(0xdb120000), SPH_C32(0xf3d55143), SPH_C32(0xd68b652e), + SPH_C32(0x6028ef2d), SPH_C32(0x90bba5d7), SPH_C32(0xd84e0000), + SPH_C32(0x51300c50), SPH_C32(0xd15d0000), SPH_C32(0x15a80000), + SPH_C32(0x95ae7234), SPH_C32(0xbb43f80c), SPH_C32(0x1fc54a33), + SPH_C32(0x99559855) }, + { SPH_C32(0x7d490000), SPH_C32(0xad60120c), SPH_C32(0x787a0000), + SPH_C32(0xeda50000), SPH_C32(0xb4ec7971), SPH_C32(0x45d43c99), + SPH_C32(0x4544a92d), SPH_C32(0x499dda33), SPH_C32(0xe54f0000), + SPH_C32(0x83a00c90), SPH_C32(0x37d00000), SPH_C32(0xd3990000), + SPH_C32(0x5f9e3745), SPH_C32(0x13a968c2), SPH_C32(0x27937a8c), + SPH_C32(0x5bc5668c) }, + { SPH_C32(0x29190000), SPH_C32(0xab111250), SPH_C32(0x5dd40000), + SPH_C32(0x87bb0000), SPH_C32(0x9a4937ae), SPH_C32(0x239ab98b), + SPH_C32(0xfafeb1ee), SPH_C32(0x37ec8724), SPH_C32(0x59c20000), + SPH_C32(0x7f9b0c88), SPH_C32(0x2e530000), SPH_C32(0x02920000), + SPH_C32(0xf1864f81), SPH_C32(0x510ff094), SPH_C32(0x2781a0bb), + SPH_C32(0x77fe36c2) }, + { SPH_C32(0xc1c40000), SPH_C32(0x515b1214), SPH_C32(0x61f90000), + SPH_C32(0x3cae0000), SPH_C32(0x1af401b5), SPH_C32(0x0772a4cf), + SPH_C32(0x4556731a), SPH_C32(0x65a68a7d), SPH_C32(0x0d920000), + SPH_C32(0x79ea0cd4), SPH_C32(0x0bfd0000), SPH_C32(0x688c0000), + SPH_C32(0xdf23015e), SPH_C32(0x37417586), SPH_C32(0x983bb878), + SPH_C32(0x098f6bd5) }, + { SPH_C32(0x95940000), SPH_C32(0x572a1248), SPH_C32(0x44570000), + SPH_C32(0x56b00000), SPH_C32(0x34514f6a), SPH_C32(0x613c21dd), + SPH_C32(0xfaec6bd9), SPH_C32(0x1bd7d76a), SPH_C32(0xb11f0000), + SPH_C32(0x85d10ccc), SPH_C32(0x127e0000), SPH_C32(0xb9870000), + SPH_C32(0x713b799a), SPH_C32(0x75e7edd0), SPH_C32(0x9829624f), + SPH_C32(0x25b43b9b) }, + { SPH_C32(0x14180000), SPH_C32(0x79811290), SPH_C32(0xbb590000), + SPH_C32(0x418a0000), SPH_C32(0x507972df), SPH_C32(0x8b702945), + SPH_C32(0xc2a88151), SPH_C32(0xf57c79fd), SPH_C32(0x233c0000), + SPH_C32(0x2c2d0c9c), SPH_C32(0x93110000), SPH_C32(0xf2140000), + SPH_C32(0x7c8f22c2), SPH_C32(0x6aba39ed), SPH_C32(0x3abbd604), + SPH_C32(0x6c48b7ff) }, + { SPH_C32(0x40480000), SPH_C32(0x7ff012cc), SPH_C32(0x9ef70000), + SPH_C32(0x2b940000), SPH_C32(0x7edc3c00), SPH_C32(0xed3eac57), + SPH_C32(0x7d129992), SPH_C32(0x8b0d24ea), SPH_C32(0x9fb10000), + SPH_C32(0xd0160c84), SPH_C32(0x8a920000), SPH_C32(0x231f0000), + SPH_C32(0xd2975a06), SPH_C32(0x281ca1bb), SPH_C32(0x3aa90c33), + SPH_C32(0x4073e7b1) }, + { SPH_C32(0xa8950000), SPH_C32(0x85ba1288), SPH_C32(0xa2da0000), + SPH_C32(0x90810000), SPH_C32(0xfe610a1b), SPH_C32(0xc9d6b113), + SPH_C32(0xc2ba5b66), SPH_C32(0xd94729b3), SPH_C32(0xcbe10000), + SPH_C32(0xd6670cd8), SPH_C32(0xaf3c0000), SPH_C32(0x49010000), + SPH_C32(0xfc3214d9), SPH_C32(0x4e5224a9), SPH_C32(0x851314f0), + SPH_C32(0x3e02baa6) }, + { SPH_C32(0xfcc50000), SPH_C32(0x83cb12d4), SPH_C32(0x87740000), + SPH_C32(0xfa9f0000), SPH_C32(0xd0c444c4), SPH_C32(0xaf983401), + SPH_C32(0x7d0043a5), SPH_C32(0xa73674a4), SPH_C32(0x776c0000), + SPH_C32(0x2a5c0cc0), SPH_C32(0xb6bf0000), SPH_C32(0x980a0000), + SPH_C32(0x522a6c1d), SPH_C32(0x0cf4bcff), SPH_C32(0x8501cec7), + SPH_C32(0x1239eae8) }, + { SPH_C32(0xb7480000), SPH_C32(0x4b081d00), SPH_C32(0x9ec20000), + SPH_C32(0x90c20000), SPH_C32(0xa4575cec), SPH_C32(0x294548a2), + SPH_C32(0xcdcf4ede), SPH_C32(0xca5b0bd0), SPH_C32(0xb44f0000), + SPH_C32(0x5f940900), SPH_C32(0x75e30000), SPH_C32(0xa95b0000), + SPH_C32(0x112b51b6), SPH_C32(0xbbcad451), SPH_C32(0xf3875d6d), + SPH_C32(0x718aebae) }, + { SPH_C32(0xe3180000), SPH_C32(0x4d791d5c), SPH_C32(0xbb6c0000), + SPH_C32(0xfadc0000), SPH_C32(0x8af21233), SPH_C32(0x4f0bcdb0), + SPH_C32(0x7275561d), SPH_C32(0xb42a56c7), SPH_C32(0x08c20000), + SPH_C32(0xa3af0918), SPH_C32(0x6c600000), SPH_C32(0x78500000), + SPH_C32(0xbf332972), SPH_C32(0xf96c4c07), SPH_C32(0xf395875a), + SPH_C32(0x5db1bbe0) }, + { SPH_C32(0x0bc50000), SPH_C32(0xb7331d18), SPH_C32(0x87410000), + SPH_C32(0x41c90000), SPH_C32(0x0a4f2428), SPH_C32(0x6be3d0f4), + SPH_C32(0xcddd94e9), SPH_C32(0xe6605b9e), SPH_C32(0x5c920000), + SPH_C32(0xa5de0944), SPH_C32(0x49ce0000), SPH_C32(0x124e0000), + SPH_C32(0x919667ad), SPH_C32(0x9f22c915), SPH_C32(0x4c2f9f99), + SPH_C32(0x23c0e6f7) }, + { SPH_C32(0x5f950000), SPH_C32(0xb1421d44), SPH_C32(0xa2ef0000), + SPH_C32(0x2bd70000), SPH_C32(0x24ea6af7), SPH_C32(0x0dad55e6), + SPH_C32(0x72678c2a), SPH_C32(0x98110689), SPH_C32(0xe01f0000), + SPH_C32(0x59e5095c), SPH_C32(0x504d0000), SPH_C32(0xc3450000), + SPH_C32(0x3f8e1f69), SPH_C32(0xdd845143), SPH_C32(0x4c3d45ae), + SPH_C32(0x0ffbb6b9) }, + { SPH_C32(0xde190000), SPH_C32(0x9fe91d9c), SPH_C32(0x5de10000), + SPH_C32(0x3ced0000), SPH_C32(0x40c25742), SPH_C32(0xe7e15d7e), + SPH_C32(0x4a2366a2), SPH_C32(0x76baa81e), SPH_C32(0x723c0000), + SPH_C32(0xf019090c), SPH_C32(0xd1220000), SPH_C32(0x88d60000), + SPH_C32(0x323a4431), SPH_C32(0xc2d9857e), SPH_C32(0xeeaff1e5), + SPH_C32(0x46073add) }, + { SPH_C32(0x8a490000), SPH_C32(0x99981dc0), SPH_C32(0x784f0000), + SPH_C32(0x56f30000), SPH_C32(0x6e67199d), SPH_C32(0x81afd86c), + SPH_C32(0xf5997e61), SPH_C32(0x08cbf509), SPH_C32(0xceb10000), + SPH_C32(0x0c220914), SPH_C32(0xc8a10000), SPH_C32(0x59dd0000), + SPH_C32(0x9c223cf5), SPH_C32(0x807f1d28), SPH_C32(0xeebd2bd2), + SPH_C32(0x6a3c6a93) }, + { SPH_C32(0x62940000), SPH_C32(0x63d21d84), SPH_C32(0x44620000), + SPH_C32(0xede60000), SPH_C32(0xeeda2f86), SPH_C32(0xa547c528), + SPH_C32(0x4a31bc95), SPH_C32(0x5a81f850), SPH_C32(0x9ae10000), + SPH_C32(0x0a530948), SPH_C32(0xed0f0000), SPH_C32(0x33c30000), + SPH_C32(0xb287722a), SPH_C32(0xe631983a), SPH_C32(0x51073311), + SPH_C32(0x144d3784) }, + { SPH_C32(0x36c40000), SPH_C32(0x65a31dd8), SPH_C32(0x61cc0000), + SPH_C32(0x87f80000), SPH_C32(0xc07f6159), SPH_C32(0xc309403a), + SPH_C32(0xf58ba456), SPH_C32(0x24f0a547), SPH_C32(0x266c0000), + SPH_C32(0xf6680950), SPH_C32(0xf48c0000), SPH_C32(0xe2c80000), + SPH_C32(0x1c9f0aee), SPH_C32(0xa497006c), SPH_C32(0x5115e926), + SPH_C32(0x387667ca) }, + { SPH_C32(0x713b0000), SPH_C32(0xe4851d0c), SPH_C32(0x3a030000), + SPH_C32(0xb14f0000), SPH_C32(0x8746496b), SPH_C32(0x5056198d), + SPH_C32(0xd0e7e256), SPH_C32(0xfdd6daa3), SPH_C32(0x1b6d0000), + SPH_C32(0x24f80990), SPH_C32(0x12010000), SPH_C32(0x24f90000), + SPH_C32(0xd6af4f9f), SPH_C32(0x0c7d90a2), SPH_C32(0x6943d999), + SPH_C32(0xfae69913) }, + { SPH_C32(0x256b0000), SPH_C32(0xe2f41d50), SPH_C32(0x1fad0000), + SPH_C32(0xdb510000), SPH_C32(0xa9e307b4), SPH_C32(0x36189c9f), + SPH_C32(0x6f5dfa95), SPH_C32(0x83a787b4), SPH_C32(0xa7e00000), + SPH_C32(0xd8c30988), SPH_C32(0x0b820000), SPH_C32(0xf5f20000), + SPH_C32(0x78b7375b), SPH_C32(0x4edb08f4), SPH_C32(0x695103ae), + SPH_C32(0xd6ddc95d) }, + { SPH_C32(0xcdb60000), SPH_C32(0x18be1d14), SPH_C32(0x23800000), + SPH_C32(0x60440000), SPH_C32(0x295e31af), SPH_C32(0x12f081db), + SPH_C32(0xd0f53861), SPH_C32(0xd1ed8aed), SPH_C32(0xf3b00000), + SPH_C32(0xdeb209d4), SPH_C32(0x2e2c0000), SPH_C32(0x9fec0000), + SPH_C32(0x56127984), SPH_C32(0x28958de6), SPH_C32(0xd6eb1b6d), + SPH_C32(0xa8ac944a) }, + { SPH_C32(0x99e60000), SPH_C32(0x1ecf1d48), SPH_C32(0x062e0000), + SPH_C32(0x0a5a0000), SPH_C32(0x07fb7f70), SPH_C32(0x74be04c9), + SPH_C32(0x6f4f20a2), SPH_C32(0xaf9cd7fa), SPH_C32(0x4f3d0000), + SPH_C32(0x228909cc), SPH_C32(0x37af0000), SPH_C32(0x4ee70000), + SPH_C32(0xf80a0140), SPH_C32(0x6a3315b0), SPH_C32(0xd6f9c15a), + SPH_C32(0x8497c404) }, + { SPH_C32(0x186a0000), SPH_C32(0x30641d90), SPH_C32(0xf9200000), + SPH_C32(0x1d600000), SPH_C32(0x63d342c5), SPH_C32(0x9ef20c51), + SPH_C32(0x570bca2a), SPH_C32(0x4137796d), SPH_C32(0xdd1e0000), + SPH_C32(0x8b75099c), SPH_C32(0xb6c00000), SPH_C32(0x05740000), + SPH_C32(0xf5be5a18), SPH_C32(0x756ec18d), SPH_C32(0x746b7511), + SPH_C32(0xcd6b4860) }, + { SPH_C32(0x4c3a0000), SPH_C32(0x36151dcc), SPH_C32(0xdc8e0000), + SPH_C32(0x777e0000), SPH_C32(0x4d760c1a), SPH_C32(0xf8bc8943), + SPH_C32(0xe8b1d2e9), SPH_C32(0x3f46247a), SPH_C32(0x61930000), + SPH_C32(0x774e0984), SPH_C32(0xaf430000), SPH_C32(0xd47f0000), + SPH_C32(0x5ba622dc), SPH_C32(0x37c859db), SPH_C32(0x7479af26), + SPH_C32(0xe150182e) }, + { SPH_C32(0xa4e70000), SPH_C32(0xcc5f1d88), SPH_C32(0xe0a30000), + SPH_C32(0xcc6b0000), SPH_C32(0xcdcb3a01), SPH_C32(0xdc549407), + SPH_C32(0x5719101d), SPH_C32(0x6d0c2923), SPH_C32(0x35c30000), + SPH_C32(0x713f09d8), SPH_C32(0x8aed0000), SPH_C32(0xbe610000), + SPH_C32(0x75036c03), SPH_C32(0x5186dcc9), SPH_C32(0xcbc3b7e5), + SPH_C32(0x9f214539) }, + { SPH_C32(0xf0b70000), SPH_C32(0xca2e1dd4), SPH_C32(0xc50d0000), + SPH_C32(0xa6750000), SPH_C32(0xe36e74de), SPH_C32(0xba1a1115), + SPH_C32(0xe8a308de), SPH_C32(0x137d7434), SPH_C32(0x894e0000), + SPH_C32(0x8d0409c0), SPH_C32(0x936e0000), SPH_C32(0x6f6a0000), + SPH_C32(0xdb1b14c7), SPH_C32(0x1320449f), SPH_C32(0xcbd16dd2), + SPH_C32(0xb31a1577) } +}; + +static const sph_u32 T512_28[128][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0x1e4e0000), SPH_C32(0xdecf0000), SPH_C32(0x6df80180), + SPH_C32(0x77240000), SPH_C32(0xec47079e), SPH_C32(0xf4a0694e), + SPH_C32(0xcda31812), SPH_C32(0x98aa496e), SPH_C32(0xb2060000), + SPH_C32(0xc5690000), SPH_C32(0x28031200), SPH_C32(0x74670000), + SPH_C32(0xb6c236f4), SPH_C32(0xeb1239f8), SPH_C32(0x33d1dfec), + SPH_C32(0x094e3198) }, + { SPH_C32(0xaec30000), SPH_C32(0x9c4f0001), SPH_C32(0x79d1e000), + SPH_C32(0x2c150000), SPH_C32(0x45cc75b3), SPH_C32(0x6650b736), + SPH_C32(0xab92f78f), SPH_C32(0xa312567b), SPH_C32(0xdb250000), + SPH_C32(0x09290000), SPH_C32(0x49aac000), SPH_C32(0x81e10000), + SPH_C32(0xcafe6b59), SPH_C32(0x42793431), SPH_C32(0x43566b76), + SPH_C32(0xe86cba2e) }, + { SPH_C32(0xb08d0000), SPH_C32(0x42800001), SPH_C32(0x1429e180), + SPH_C32(0x5b310000), SPH_C32(0xa98b722d), SPH_C32(0x92f0de78), + SPH_C32(0x6631ef9d), SPH_C32(0x3bb81f15), SPH_C32(0x69230000), + SPH_C32(0xcc400000), SPH_C32(0x61a9d200), SPH_C32(0xf5860000), + SPH_C32(0x7c3c5dad), SPH_C32(0xa96b0dc9), SPH_C32(0x7087b49a), + SPH_C32(0xe1228bb6) }, + { SPH_C32(0xdb250000), SPH_C32(0x09290000), SPH_C32(0x49aac000), + SPH_C32(0x81e10000), SPH_C32(0xcafe6b59), SPH_C32(0x42793431), + SPH_C32(0x43566b76), SPH_C32(0xe86cba2e), SPH_C32(0x75e60000), + SPH_C32(0x95660001), SPH_C32(0x307b2000), SPH_C32(0xadf40000), + SPH_C32(0x8f321eea), SPH_C32(0x24298307), SPH_C32(0xe8c49cf9), + SPH_C32(0x4b7eec55) }, + { SPH_C32(0xc56b0000), SPH_C32(0xd7e60000), SPH_C32(0x2452c180), + SPH_C32(0xf6c50000), SPH_C32(0x26b96cc7), SPH_C32(0xb6d95d7f), + SPH_C32(0x8ef57364), SPH_C32(0x70c6f340), SPH_C32(0xc7e00000), + SPH_C32(0x500f0001), SPH_C32(0x18783200), SPH_C32(0xd9930000), + SPH_C32(0x39f0281e), SPH_C32(0xcf3bbaff), SPH_C32(0xdb154315), + SPH_C32(0x4230ddcd) }, + { SPH_C32(0x75e60000), SPH_C32(0x95660001), SPH_C32(0x307b2000), + SPH_C32(0xadf40000), SPH_C32(0x8f321eea), SPH_C32(0x24298307), + SPH_C32(0xe8c49cf9), SPH_C32(0x4b7eec55), SPH_C32(0xaec30000), + SPH_C32(0x9c4f0001), SPH_C32(0x79d1e000), SPH_C32(0x2c150000), + SPH_C32(0x45cc75b3), SPH_C32(0x6650b736), SPH_C32(0xab92f78f), + SPH_C32(0xa312567b) }, + { SPH_C32(0x6ba80000), SPH_C32(0x4ba90001), SPH_C32(0x5d832180), + SPH_C32(0xdad00000), SPH_C32(0x63751974), SPH_C32(0xd089ea49), + SPH_C32(0x256784eb), SPH_C32(0xd3d4a53b), SPH_C32(0x1cc50000), + SPH_C32(0x59260001), SPH_C32(0x51d2f200), SPH_C32(0x58720000), + SPH_C32(0xf30e4347), SPH_C32(0x8d428ece), SPH_C32(0x98432863), + SPH_C32(0xaa5c67e3) }, + { SPH_C32(0x86790000), SPH_C32(0x3f390002), SPH_C32(0xe19ae000), + SPH_C32(0x98560000), SPH_C32(0x9565670e), SPH_C32(0x4e88c8ea), + SPH_C32(0xd3dd4944), SPH_C32(0x161ddab9), SPH_C32(0x30b70000), + SPH_C32(0xe5d00000), SPH_C32(0xf4f46000), SPH_C32(0x42c40000), + SPH_C32(0x63b83d6a), SPH_C32(0x78ba9460), SPH_C32(0x21afa1ea), + SPH_C32(0xb0a51834) }, + { SPH_C32(0x98370000), SPH_C32(0xe1f60002), SPH_C32(0x8c62e180), + SPH_C32(0xef720000), SPH_C32(0x79226090), SPH_C32(0xba28a1a4), + SPH_C32(0x1e7e5156), SPH_C32(0x8eb793d7), SPH_C32(0x82b10000), + SPH_C32(0x20b90000), SPH_C32(0xdcf77200), SPH_C32(0x36a30000), + SPH_C32(0xd57a0b9e), SPH_C32(0x93a8ad98), SPH_C32(0x127e7e06), + SPH_C32(0xb9eb29ac) }, + { SPH_C32(0x28ba0000), SPH_C32(0xa3760003), SPH_C32(0x984b0000), + SPH_C32(0xb4430000), SPH_C32(0xd0a912bd), SPH_C32(0x28d87fdc), + SPH_C32(0x784fbecb), SPH_C32(0xb50f8cc2), SPH_C32(0xeb920000), + SPH_C32(0xecf90000), SPH_C32(0xbd5ea000), SPH_C32(0xc3250000), + SPH_C32(0xa9465633), SPH_C32(0x3ac3a051), SPH_C32(0x62f9ca9c), + SPH_C32(0x58c9a21a) }, + { SPH_C32(0x36f40000), SPH_C32(0x7db90003), SPH_C32(0xf5b30180), + SPH_C32(0xc3670000), SPH_C32(0x3cee1523), SPH_C32(0xdc781692), + SPH_C32(0xb5eca6d9), SPH_C32(0x2da5c5ac), SPH_C32(0x59940000), + SPH_C32(0x29900000), SPH_C32(0x955db200), SPH_C32(0xb7420000), + SPH_C32(0x1f8460c7), SPH_C32(0xd1d199a9), SPH_C32(0x51281570), + SPH_C32(0x51879382) }, + { SPH_C32(0x5d5c0000), SPH_C32(0x36100002), SPH_C32(0xa8302000), + SPH_C32(0x19b70000), SPH_C32(0x5f9b0c57), SPH_C32(0x0cf1fcdb), + SPH_C32(0x908b2232), SPH_C32(0xfe716097), SPH_C32(0x45510000), + SPH_C32(0x70b60001), SPH_C32(0xc48f4000), SPH_C32(0xef300000), + SPH_C32(0xec8a2380), SPH_C32(0x5c931767), SPH_C32(0xc96b3d13), + SPH_C32(0xfbdbf461) }, + { SPH_C32(0x43120000), SPH_C32(0xe8df0002), SPH_C32(0xc5c82180), + SPH_C32(0x6e930000), SPH_C32(0xb3dc0bc9), SPH_C32(0xf8519595), + SPH_C32(0x5d283a20), SPH_C32(0x66db29f9), SPH_C32(0xf7570000), + SPH_C32(0xb5df0001), SPH_C32(0xec8c5200), SPH_C32(0x9b570000), + SPH_C32(0x5a481574), SPH_C32(0xb7812e9f), SPH_C32(0xfabae2ff), + SPH_C32(0xf295c5f9) }, + { SPH_C32(0xf39f0000), SPH_C32(0xaa5f0003), SPH_C32(0xd1e1c000), + SPH_C32(0x35a20000), SPH_C32(0x1a5779e4), SPH_C32(0x6aa14bed), + SPH_C32(0x3b19d5bd), SPH_C32(0x5d6336ec), SPH_C32(0x9e740000), + SPH_C32(0x799f0001), SPH_C32(0x8d258000), SPH_C32(0x6ed10000), + SPH_C32(0x267448d9), SPH_C32(0x1eea2356), SPH_C32(0x8a3d5665), + SPH_C32(0x13b74e4f) }, + { SPH_C32(0xedd10000), SPH_C32(0x74900003), SPH_C32(0xbc19c180), + SPH_C32(0x42860000), SPH_C32(0xf6107e7a), SPH_C32(0x9e0122a3), + SPH_C32(0xf6bacdaf), SPH_C32(0xc5c97f82), SPH_C32(0x2c720000), + SPH_C32(0xbcf60001), SPH_C32(0xa5269200), SPH_C32(0x1ab60000), + SPH_C32(0x90b67e2d), SPH_C32(0xf5f81aae), SPH_C32(0xb9ec8989), + SPH_C32(0x1af97fd7) }, + { SPH_C32(0x30b70000), SPH_C32(0xe5d00000), SPH_C32(0xf4f46000), + SPH_C32(0x42c40000), SPH_C32(0x63b83d6a), SPH_C32(0x78ba9460), + SPH_C32(0x21afa1ea), SPH_C32(0xb0a51834), SPH_C32(0xb6ce0000), + SPH_C32(0xdae90002), SPH_C32(0x156e8000), SPH_C32(0xda920000), + SPH_C32(0xf6dd5a64), SPH_C32(0x36325c8a), SPH_C32(0xf272e8ae), + SPH_C32(0xa6b8c28d) }, + { SPH_C32(0x2ef90000), SPH_C32(0x3b1f0000), SPH_C32(0x990c6180), + SPH_C32(0x35e00000), SPH_C32(0x8fff3af4), SPH_C32(0x8c1afd2e), + SPH_C32(0xec0cb9f8), SPH_C32(0x280f515a), SPH_C32(0x04c80000), + SPH_C32(0x1f800002), SPH_C32(0x3d6d9200), SPH_C32(0xaef50000), + SPH_C32(0x401f6c90), SPH_C32(0xdd206572), SPH_C32(0xc1a33742), + SPH_C32(0xaff6f315) }, + { SPH_C32(0x9e740000), SPH_C32(0x799f0001), SPH_C32(0x8d258000), + SPH_C32(0x6ed10000), SPH_C32(0x267448d9), SPH_C32(0x1eea2356), + SPH_C32(0x8a3d5665), SPH_C32(0x13b74e4f), SPH_C32(0x6deb0000), + SPH_C32(0xd3c00002), SPH_C32(0x5cc44000), SPH_C32(0x5b730000), + SPH_C32(0x3c23313d), SPH_C32(0x744b68bb), SPH_C32(0xb12483d8), + SPH_C32(0x4ed478a3) }, + { SPH_C32(0x803a0000), SPH_C32(0xa7500001), SPH_C32(0xe0dd8180), + SPH_C32(0x19f50000), SPH_C32(0xca334f47), SPH_C32(0xea4a4a18), + SPH_C32(0x479e4e77), SPH_C32(0x8b1d0721), SPH_C32(0xdfed0000), + SPH_C32(0x16a90002), SPH_C32(0x74c75200), SPH_C32(0x2f140000), + SPH_C32(0x8ae107c9), SPH_C32(0x9f595143), SPH_C32(0x82f55c34), + SPH_C32(0x479a493b) }, + { SPH_C32(0xeb920000), SPH_C32(0xecf90000), SPH_C32(0xbd5ea000), + SPH_C32(0xc3250000), SPH_C32(0xa9465633), SPH_C32(0x3ac3a051), + SPH_C32(0x62f9ca9c), SPH_C32(0x58c9a21a), SPH_C32(0xc3280000), + SPH_C32(0x4f8f0003), SPH_C32(0x2515a000), SPH_C32(0x77660000), + SPH_C32(0x79ef448e), SPH_C32(0x121bdf8d), SPH_C32(0x1ab67457), + SPH_C32(0xedc62ed8) }, + { SPH_C32(0xf5dc0000), SPH_C32(0x32360000), SPH_C32(0xd0a6a180), + SPH_C32(0xb4010000), SPH_C32(0x450151ad), SPH_C32(0xce63c91f), + SPH_C32(0xaf5ad28e), SPH_C32(0xc063eb74), SPH_C32(0x712e0000), + SPH_C32(0x8ae60003), SPH_C32(0x0d16b200), SPH_C32(0x03010000), + SPH_C32(0xcf2d727a), SPH_C32(0xf909e675), SPH_C32(0x2967abbb), + SPH_C32(0xe4881f40) }, + { SPH_C32(0x45510000), SPH_C32(0x70b60001), SPH_C32(0xc48f4000), + SPH_C32(0xef300000), SPH_C32(0xec8a2380), SPH_C32(0x5c931767), + SPH_C32(0xc96b3d13), SPH_C32(0xfbdbf461), SPH_C32(0x180d0000), + SPH_C32(0x46a60003), SPH_C32(0x6cbf6000), SPH_C32(0xf6870000), + SPH_C32(0xb3112fd7), SPH_C32(0x5062ebbc), SPH_C32(0x59e01f21), + SPH_C32(0x05aa94f6) }, + { SPH_C32(0x5b1f0000), SPH_C32(0xae790001), SPH_C32(0xa9774180), + SPH_C32(0x98140000), SPH_C32(0x00cd241e), SPH_C32(0xa8337e29), + SPH_C32(0x04c82501), SPH_C32(0x6371bd0f), SPH_C32(0xaa0b0000), + SPH_C32(0x83cf0003), SPH_C32(0x44bc7200), SPH_C32(0x82e00000), + SPH_C32(0x05d31923), SPH_C32(0xbb70d244), SPH_C32(0x6a31c0cd), + SPH_C32(0x0ce4a56e) }, + { SPH_C32(0xb6ce0000), SPH_C32(0xdae90002), SPH_C32(0x156e8000), + SPH_C32(0xda920000), SPH_C32(0xf6dd5a64), SPH_C32(0x36325c8a), + SPH_C32(0xf272e8ae), SPH_C32(0xa6b8c28d), SPH_C32(0x86790000), + SPH_C32(0x3f390002), SPH_C32(0xe19ae000), SPH_C32(0x98560000), + SPH_C32(0x9565670e), SPH_C32(0x4e88c8ea), SPH_C32(0xd3dd4944), + SPH_C32(0x161ddab9) }, + { SPH_C32(0xa8800000), SPH_C32(0x04260002), SPH_C32(0x78968180), + SPH_C32(0xadb60000), SPH_C32(0x1a9a5dfa), SPH_C32(0xc29235c4), + SPH_C32(0x3fd1f0bc), SPH_C32(0x3e128be3), SPH_C32(0x347f0000), + SPH_C32(0xfa500002), SPH_C32(0xc999f200), SPH_C32(0xec310000), + SPH_C32(0x23a751fa), SPH_C32(0xa59af112), SPH_C32(0xe00c96a8), + SPH_C32(0x1f53eb21) }, + { SPH_C32(0x180d0000), SPH_C32(0x46a60003), SPH_C32(0x6cbf6000), + SPH_C32(0xf6870000), SPH_C32(0xb3112fd7), SPH_C32(0x5062ebbc), + SPH_C32(0x59e01f21), SPH_C32(0x05aa94f6), SPH_C32(0x5d5c0000), + SPH_C32(0x36100002), SPH_C32(0xa8302000), SPH_C32(0x19b70000), + SPH_C32(0x5f9b0c57), SPH_C32(0x0cf1fcdb), SPH_C32(0x908b2232), + SPH_C32(0xfe716097) }, + { SPH_C32(0x06430000), SPH_C32(0x98690003), SPH_C32(0x01476180), + SPH_C32(0x81a30000), SPH_C32(0x5f562849), SPH_C32(0xa4c282f2), + SPH_C32(0x94430733), SPH_C32(0x9d00dd98), SPH_C32(0xef5a0000), + SPH_C32(0xf3790002), SPH_C32(0x80333200), SPH_C32(0x6dd00000), + SPH_C32(0xe9593aa3), SPH_C32(0xe7e3c523), SPH_C32(0xa35afdde), + SPH_C32(0xf73f510f) }, + { SPH_C32(0x6deb0000), SPH_C32(0xd3c00002), SPH_C32(0x5cc44000), + SPH_C32(0x5b730000), SPH_C32(0x3c23313d), SPH_C32(0x744b68bb), + SPH_C32(0xb12483d8), SPH_C32(0x4ed478a3), SPH_C32(0xf39f0000), + SPH_C32(0xaa5f0003), SPH_C32(0xd1e1c000), SPH_C32(0x35a20000), + SPH_C32(0x1a5779e4), SPH_C32(0x6aa14bed), SPH_C32(0x3b19d5bd), + SPH_C32(0x5d6336ec) }, + { SPH_C32(0x73a50000), SPH_C32(0x0d0f0002), SPH_C32(0x313c4180), + SPH_C32(0x2c570000), SPH_C32(0xd06436a3), SPH_C32(0x80eb01f5), + SPH_C32(0x7c879bca), SPH_C32(0xd67e31cd), SPH_C32(0x41990000), + SPH_C32(0x6f360003), SPH_C32(0xf9e2d200), SPH_C32(0x41c50000), + SPH_C32(0xac954f10), SPH_C32(0x81b37215), SPH_C32(0x08c80a51), + SPH_C32(0x542d0774) }, + { SPH_C32(0xc3280000), SPH_C32(0x4f8f0003), SPH_C32(0x2515a000), + SPH_C32(0x77660000), SPH_C32(0x79ef448e), SPH_C32(0x121bdf8d), + SPH_C32(0x1ab67457), SPH_C32(0xedc62ed8), SPH_C32(0x28ba0000), + SPH_C32(0xa3760003), SPH_C32(0x984b0000), SPH_C32(0xb4430000), + SPH_C32(0xd0a912bd), SPH_C32(0x28d87fdc), SPH_C32(0x784fbecb), + SPH_C32(0xb50f8cc2) }, + { SPH_C32(0xdd660000), SPH_C32(0x91400003), SPH_C32(0x48eda180), + SPH_C32(0x00420000), SPH_C32(0x95a84310), SPH_C32(0xe6bbb6c3), + SPH_C32(0xd7156c45), SPH_C32(0x756c67b6), SPH_C32(0x9abc0000), + SPH_C32(0x661f0003), SPH_C32(0xb0481200), SPH_C32(0xc0240000), + SPH_C32(0x666b2449), SPH_C32(0xc3ca4624), SPH_C32(0x4b9e6127), + SPH_C32(0xbc41bd5a) }, + { SPH_C32(0x14190000), SPH_C32(0x23ca003c), SPH_C32(0x50df0000), + SPH_C32(0x44b60000), SPH_C32(0x1b6c67b0), SPH_C32(0x3cf3ac75), + SPH_C32(0x61e610b0), SPH_C32(0xdbcadb80), SPH_C32(0xe3430000), + SPH_C32(0x3a4e0014), SPH_C32(0xf2c60000), SPH_C32(0xaa4e0000), + SPH_C32(0xdb1e42a6), SPH_C32(0x256bbe15), SPH_C32(0x123db156), + SPH_C32(0x3a4e99d7) }, + { SPH_C32(0x0a570000), SPH_C32(0xfd05003c), SPH_C32(0x3d270180), + SPH_C32(0x33920000), SPH_C32(0xf72b602e), SPH_C32(0xc853c53b), + SPH_C32(0xac4508a2), SPH_C32(0x436092ee), SPH_C32(0x51450000), + SPH_C32(0xff270014), SPH_C32(0xdac51200), SPH_C32(0xde290000), + SPH_C32(0x6ddc7452), SPH_C32(0xce7987ed), SPH_C32(0x21ec6eba), + SPH_C32(0x3300a84f) }, + { SPH_C32(0xbada0000), SPH_C32(0xbf85003d), SPH_C32(0x290ee000), + SPH_C32(0x68a30000), SPH_C32(0x5ea01203), SPH_C32(0x5aa31b43), + SPH_C32(0xca74e73f), SPH_C32(0x78d88dfb), SPH_C32(0x38660000), + SPH_C32(0x33670014), SPH_C32(0xbb6cc000), SPH_C32(0x2baf0000), + SPH_C32(0x11e029ff), SPH_C32(0x67128a24), SPH_C32(0x516bda20), + SPH_C32(0xd22223f9) }, + { SPH_C32(0xa4940000), SPH_C32(0x614a003d), SPH_C32(0x44f6e180), + SPH_C32(0x1f870000), SPH_C32(0xb2e7159d), SPH_C32(0xae03720d), + SPH_C32(0x07d7ff2d), SPH_C32(0xe072c495), SPH_C32(0x8a600000), + SPH_C32(0xf60e0014), SPH_C32(0x936fd200), SPH_C32(0x5fc80000), + SPH_C32(0xa7221f0b), SPH_C32(0x8c00b3dc), SPH_C32(0x62ba05cc), + SPH_C32(0xdb6c1261) }, + { SPH_C32(0xcf3c0000), SPH_C32(0x2ae3003c), SPH_C32(0x1975c000), + SPH_C32(0xc5570000), SPH_C32(0xd1920ce9), SPH_C32(0x7e8a9844), + SPH_C32(0x22b07bc6), SPH_C32(0x33a661ae), SPH_C32(0x96a50000), + SPH_C32(0xaf280015), SPH_C32(0xc2bd2000), SPH_C32(0x07ba0000), + SPH_C32(0x542c5c4c), SPH_C32(0x01423d12), SPH_C32(0xfaf92daf), + SPH_C32(0x71307582) }, + { SPH_C32(0xd1720000), SPH_C32(0xf42c003c), SPH_C32(0x748dc180), + SPH_C32(0xb2730000), SPH_C32(0x3dd50b77), SPH_C32(0x8a2af10a), + SPH_C32(0xef1363d4), SPH_C32(0xab0c28c0), SPH_C32(0x24a30000), + SPH_C32(0x6a410015), SPH_C32(0xeabe3200), SPH_C32(0x73dd0000), + SPH_C32(0xe2ee6ab8), SPH_C32(0xea5004ea), SPH_C32(0xc928f243), + SPH_C32(0x787e441a) }, + { SPH_C32(0x61ff0000), SPH_C32(0xb6ac003d), SPH_C32(0x60a42000), + SPH_C32(0xe9420000), SPH_C32(0x945e795a), SPH_C32(0x18da2f72), + SPH_C32(0x89228c49), SPH_C32(0x90b437d5), SPH_C32(0x4d800000), + SPH_C32(0xa6010015), SPH_C32(0x8b17e000), SPH_C32(0x865b0000), + SPH_C32(0x9ed23715), SPH_C32(0x433b0923), SPH_C32(0xb9af46d9), + SPH_C32(0x995ccfac) }, + { SPH_C32(0x7fb10000), SPH_C32(0x6863003d), SPH_C32(0x0d5c2180), + SPH_C32(0x9e660000), SPH_C32(0x78197ec4), SPH_C32(0xec7a463c), + SPH_C32(0x4481945b), SPH_C32(0x081e7ebb), SPH_C32(0xff860000), + SPH_C32(0x63680015), SPH_C32(0xa314f200), SPH_C32(0xf23c0000), + SPH_C32(0x281001e1), SPH_C32(0xa82930db), SPH_C32(0x8a7e9935), + SPH_C32(0x9012fe34) }, + { SPH_C32(0x92600000), SPH_C32(0x1cf3003e), SPH_C32(0xb145e000), + SPH_C32(0xdce00000), SPH_C32(0x8e0900be), SPH_C32(0x727b649f), + SPH_C32(0xb23b59f4), SPH_C32(0xcdd70139), SPH_C32(0xd3f40000), + SPH_C32(0xdf9e0014), SPH_C32(0x06326000), SPH_C32(0xe88a0000), + SPH_C32(0xb8a67fcc), SPH_C32(0x5dd12a75), SPH_C32(0x339210bc), + SPH_C32(0x8aeb81e3) }, + { SPH_C32(0x8c2e0000), SPH_C32(0xc23c003e), SPH_C32(0xdcbde180), + SPH_C32(0xabc40000), SPH_C32(0x624e0720), SPH_C32(0x86db0dd1), + SPH_C32(0x7f9841e6), SPH_C32(0x557d4857), SPH_C32(0x61f20000), + SPH_C32(0x1af70014), SPH_C32(0x2e317200), SPH_C32(0x9ced0000), + SPH_C32(0x0e644938), SPH_C32(0xb6c3138d), SPH_C32(0x0043cf50), + SPH_C32(0x83a5b07b) }, + { SPH_C32(0x3ca30000), SPH_C32(0x80bc003f), SPH_C32(0xc8940000), + SPH_C32(0xf0f50000), SPH_C32(0xcbc5750d), SPH_C32(0x142bd3a9), + SPH_C32(0x19a9ae7b), SPH_C32(0x6ec55742), SPH_C32(0x08d10000), + SPH_C32(0xd6b70014), SPH_C32(0x4f98a000), SPH_C32(0x696b0000), + SPH_C32(0x72581495), SPH_C32(0x1fa81e44), SPH_C32(0x70c47bca), + SPH_C32(0x62873bcd) }, + { SPH_C32(0x22ed0000), SPH_C32(0x5e73003f), SPH_C32(0xa56c0180), + SPH_C32(0x87d10000), SPH_C32(0x27827293), SPH_C32(0xe08bbae7), + SPH_C32(0xd40ab669), SPH_C32(0xf66f1e2c), SPH_C32(0xbad70000), + SPH_C32(0x13de0014), SPH_C32(0x679bb200), SPH_C32(0x1d0c0000), + SPH_C32(0xc49a2261), SPH_C32(0xf4ba27bc), SPH_C32(0x4315a426), + SPH_C32(0x6bc90a55) }, + { SPH_C32(0x49450000), SPH_C32(0x15da003e), SPH_C32(0xf8ef2000), + SPH_C32(0x5d010000), SPH_C32(0x44f76be7), SPH_C32(0x300250ae), + SPH_C32(0xf16d3282), SPH_C32(0x25bbbb17), SPH_C32(0xa6120000), + SPH_C32(0x4af80015), SPH_C32(0x36494000), SPH_C32(0x457e0000), + SPH_C32(0x37946126), SPH_C32(0x79f8a972), SPH_C32(0xdb568c45), + SPH_C32(0xc1956db6) }, + { SPH_C32(0x570b0000), SPH_C32(0xcb15003e), SPH_C32(0x95172180), + SPH_C32(0x2a250000), SPH_C32(0xa8b06c79), SPH_C32(0xc4a239e0), + SPH_C32(0x3cce2a90), SPH_C32(0xbd11f279), SPH_C32(0x14140000), + SPH_C32(0x8f910015), SPH_C32(0x1e4a5200), SPH_C32(0x31190000), + SPH_C32(0x815657d2), SPH_C32(0x92ea908a), SPH_C32(0xe88753a9), + SPH_C32(0xc8db5c2e) }, + { SPH_C32(0xe7860000), SPH_C32(0x8995003f), SPH_C32(0x813ec000), + SPH_C32(0x71140000), SPH_C32(0x013b1e54), SPH_C32(0x5652e798), + SPH_C32(0x5affc50d), SPH_C32(0x86a9ed6c), SPH_C32(0x7d370000), + SPH_C32(0x43d10015), SPH_C32(0x7fe38000), SPH_C32(0xc49f0000), + SPH_C32(0xfd6a0a7f), SPH_C32(0x3b819d43), SPH_C32(0x9800e733), + SPH_C32(0x29f9d798) }, + { SPH_C32(0xf9c80000), SPH_C32(0x575a003f), SPH_C32(0xecc6c180), + SPH_C32(0x06300000), SPH_C32(0xed7c19ca), SPH_C32(0xa2f28ed6), + SPH_C32(0x975cdd1f), SPH_C32(0x1e03a402), SPH_C32(0xcf310000), + SPH_C32(0x86b80015), SPH_C32(0x57e09200), SPH_C32(0xb0f80000), + SPH_C32(0x4ba83c8b), SPH_C32(0xd093a4bb), SPH_C32(0xabd138df), + SPH_C32(0x20b7e600) }, + { SPH_C32(0x24ae0000), SPH_C32(0xc61a003c), SPH_C32(0xa42b6000), + SPH_C32(0x06720000), SPH_C32(0x78d45ada), SPH_C32(0x44493815), + SPH_C32(0x4049b15a), SPH_C32(0x6b6fc3b4), SPH_C32(0x558d0000), + SPH_C32(0xe0a70016), SPH_C32(0xe7a88000), SPH_C32(0x70dc0000), + SPH_C32(0x2dc318c2), SPH_C32(0x1359e29f), SPH_C32(0xe04f59f8), + SPH_C32(0x9cf65b5a) }, + { SPH_C32(0x3ae00000), SPH_C32(0x18d5003c), SPH_C32(0xc9d36180), + SPH_C32(0x71560000), SPH_C32(0x94935d44), SPH_C32(0xb0e9515b), + SPH_C32(0x8deaa948), SPH_C32(0xf3c58ada), SPH_C32(0xe78b0000), + SPH_C32(0x25ce0016), SPH_C32(0xcfab9200), SPH_C32(0x04bb0000), + SPH_C32(0x9b012e36), SPH_C32(0xf84bdb67), SPH_C32(0xd39e8614), + SPH_C32(0x95b86ac2) }, + { SPH_C32(0x8a6d0000), SPH_C32(0x5a55003d), SPH_C32(0xddfa8000), + SPH_C32(0x2a670000), SPH_C32(0x3d182f69), SPH_C32(0x22198f23), + SPH_C32(0xebdb46d5), SPH_C32(0xc87d95cf), SPH_C32(0x8ea80000), + SPH_C32(0xe98e0016), SPH_C32(0xae024000), SPH_C32(0xf13d0000), + SPH_C32(0xe73d739b), SPH_C32(0x5120d6ae), SPH_C32(0xa319328e), + SPH_C32(0x749ae174) }, + { SPH_C32(0x94230000), SPH_C32(0x849a003d), SPH_C32(0xb0028180), + SPH_C32(0x5d430000), SPH_C32(0xd15f28f7), SPH_C32(0xd6b9e66d), + SPH_C32(0x26785ec7), SPH_C32(0x50d7dca1), SPH_C32(0x3cae0000), + SPH_C32(0x2ce70016), SPH_C32(0x86015200), SPH_C32(0x855a0000), + SPH_C32(0x51ff456f), SPH_C32(0xba32ef56), SPH_C32(0x90c8ed62), + SPH_C32(0x7dd4d0ec) }, + { SPH_C32(0xff8b0000), SPH_C32(0xcf33003c), SPH_C32(0xed81a000), + SPH_C32(0x87930000), SPH_C32(0xb22a3183), SPH_C32(0x06300c24), + SPH_C32(0x031fda2c), SPH_C32(0x8303799a), SPH_C32(0x206b0000), + SPH_C32(0x75c10017), SPH_C32(0xd7d3a000), SPH_C32(0xdd280000), + SPH_C32(0xa2f10628), SPH_C32(0x37706198), SPH_C32(0x088bc501), + SPH_C32(0xd788b70f) }, + { SPH_C32(0xe1c50000), SPH_C32(0x11fc003c), SPH_C32(0x8079a180), + SPH_C32(0xf0b70000), SPH_C32(0x5e6d361d), SPH_C32(0xf290656a), + SPH_C32(0xcebcc23e), SPH_C32(0x1ba930f4), SPH_C32(0x926d0000), + SPH_C32(0xb0a80017), SPH_C32(0xffd0b200), SPH_C32(0xa94f0000), + SPH_C32(0x143330dc), SPH_C32(0xdc625860), SPH_C32(0x3b5a1aed), + SPH_C32(0xdec68697) }, + { SPH_C32(0x51480000), SPH_C32(0x537c003d), SPH_C32(0x94504000), + SPH_C32(0xab860000), SPH_C32(0xf7e64430), SPH_C32(0x6060bb12), + SPH_C32(0xa88d2da3), SPH_C32(0x20112fe1), SPH_C32(0xfb4e0000), + SPH_C32(0x7ce80017), SPH_C32(0x9e796000), SPH_C32(0x5cc90000), + SPH_C32(0x680f6d71), SPH_C32(0x750955a9), SPH_C32(0x4bddae77), + SPH_C32(0x3fe40d21) }, + { SPH_C32(0x4f060000), SPH_C32(0x8db3003d), SPH_C32(0xf9a84180), + SPH_C32(0xdca20000), SPH_C32(0x1ba143ae), SPH_C32(0x94c0d25c), + SPH_C32(0x652e35b1), SPH_C32(0xb8bb668f), SPH_C32(0x49480000), + SPH_C32(0xb9810017), SPH_C32(0xb67a7200), SPH_C32(0x28ae0000), + SPH_C32(0xdecd5b85), SPH_C32(0x9e1b6c51), SPH_C32(0x780c719b), + SPH_C32(0x36aa3cb9) }, + { SPH_C32(0xa2d70000), SPH_C32(0xf923003e), SPH_C32(0x45b18000), + SPH_C32(0x9e240000), SPH_C32(0xedb13dd4), SPH_C32(0x0ac1f0ff), + SPH_C32(0x9394f81e), SPH_C32(0x7d72190d), SPH_C32(0x653a0000), + SPH_C32(0x05770016), SPH_C32(0x135ce000), SPH_C32(0x32180000), + SPH_C32(0x4e7b25a8), SPH_C32(0x6be376ff), SPH_C32(0xc1e0f812), + SPH_C32(0x2c53436e) }, + { SPH_C32(0xbc990000), SPH_C32(0x27ec003e), SPH_C32(0x28498180), + SPH_C32(0xe9000000), SPH_C32(0x01f63a4a), SPH_C32(0xfe6199b1), + SPH_C32(0x5e37e00c), SPH_C32(0xe5d85063), SPH_C32(0xd73c0000), + SPH_C32(0xc01e0016), SPH_C32(0x3b5ff200), SPH_C32(0x467f0000), + SPH_C32(0xf8b9135c), SPH_C32(0x80f14f07), SPH_C32(0xf23127fe), + SPH_C32(0x251d72f6) }, + { SPH_C32(0x0c140000), SPH_C32(0x656c003f), SPH_C32(0x3c606000), + SPH_C32(0xb2310000), SPH_C32(0xa87d4867), SPH_C32(0x6c9147c9), + SPH_C32(0x38060f91), SPH_C32(0xde604f76), SPH_C32(0xbe1f0000), + SPH_C32(0x0c5e0016), SPH_C32(0x5af62000), SPH_C32(0xb3f90000), + SPH_C32(0x84854ef1), SPH_C32(0x299a42ce), SPH_C32(0x82b69364), + SPH_C32(0xc43ff940) }, + { SPH_C32(0x125a0000), SPH_C32(0xbba3003f), SPH_C32(0x51986180), + SPH_C32(0xc5150000), SPH_C32(0x443a4ff9), SPH_C32(0x98312e87), + SPH_C32(0xf5a51783), SPH_C32(0x46ca0618), SPH_C32(0x0c190000), + SPH_C32(0xc9370016), SPH_C32(0x72f53200), SPH_C32(0xc79e0000), + SPH_C32(0x32477805), SPH_C32(0xc2887b36), SPH_C32(0xb1674c88), + SPH_C32(0xcd71c8d8) }, + { SPH_C32(0x79f20000), SPH_C32(0xf00a003e), SPH_C32(0x0c1b4000), + SPH_C32(0x1fc50000), SPH_C32(0x274f568d), SPH_C32(0x48b8c4ce), + SPH_C32(0xd0c29368), SPH_C32(0x951ea323), SPH_C32(0x10dc0000), + SPH_C32(0x90110017), SPH_C32(0x2327c000), SPH_C32(0x9fec0000), + SPH_C32(0xc1493b42), SPH_C32(0x4fcaf5f8), SPH_C32(0x292464eb), + SPH_C32(0x672daf3b) }, + { SPH_C32(0x67bc0000), SPH_C32(0x2ec5003e), SPH_C32(0x61e34180), + SPH_C32(0x68e10000), SPH_C32(0xcb085113), SPH_C32(0xbc18ad80), + SPH_C32(0x1d618b7a), SPH_C32(0x0db4ea4d), SPH_C32(0xa2da0000), + SPH_C32(0x55780017), SPH_C32(0x0b24d200), SPH_C32(0xeb8b0000), + SPH_C32(0x778b0db6), SPH_C32(0xa4d8cc00), SPH_C32(0x1af5bb07), + SPH_C32(0x6e639ea3) }, + { SPH_C32(0xd7310000), SPH_C32(0x6c45003f), SPH_C32(0x75caa000), + SPH_C32(0x33d00000), SPH_C32(0x6283233e), SPH_C32(0x2ee873f8), + SPH_C32(0x7b5064e7), SPH_C32(0x360cf558), SPH_C32(0xcbf90000), + SPH_C32(0x99380017), SPH_C32(0x6a8d0000), SPH_C32(0x1e0d0000), + SPH_C32(0x0bb7501b), SPH_C32(0x0db3c1c9), SPH_C32(0x6a720f9d), + SPH_C32(0x8f411515) }, + { SPH_C32(0xc97f0000), SPH_C32(0xb28a003f), SPH_C32(0x1832a180), + SPH_C32(0x44f40000), SPH_C32(0x8ec424a0), SPH_C32(0xda481ab6), + SPH_C32(0xb6f37cf5), SPH_C32(0xaea6bc36), SPH_C32(0x79ff0000), + SPH_C32(0x5c510017), SPH_C32(0x428e1200), SPH_C32(0x6a6a0000), + SPH_C32(0xbd7566ef), SPH_C32(0xe6a1f831), SPH_C32(0x59a3d071), + SPH_C32(0x860f248d) }, + { SPH_C32(0xe3430000), SPH_C32(0x3a4e0014), SPH_C32(0xf2c60000), + SPH_C32(0xaa4e0000), SPH_C32(0xdb1e42a6), SPH_C32(0x256bbe15), + SPH_C32(0x123db156), SPH_C32(0x3a4e99d7), SPH_C32(0xf75a0000), + SPH_C32(0x19840028), SPH_C32(0xa2190000), SPH_C32(0xeef80000), + SPH_C32(0xc0722516), SPH_C32(0x19981260), SPH_C32(0x73dba1e6), + SPH_C32(0xe1844257) }, + { SPH_C32(0xfd0d0000), SPH_C32(0xe4810014), SPH_C32(0x9f3e0180), + SPH_C32(0xdd6a0000), SPH_C32(0x37594538), SPH_C32(0xd1cbd75b), + SPH_C32(0xdf9ea944), SPH_C32(0xa2e4d0b9), SPH_C32(0x455c0000), + SPH_C32(0xdced0028), SPH_C32(0x8a1a1200), SPH_C32(0x9a9f0000), + SPH_C32(0x76b013e2), SPH_C32(0xf28a2b98), SPH_C32(0x400a7e0a), + SPH_C32(0xe8ca73cf) }, + { SPH_C32(0x4d800000), SPH_C32(0xa6010015), SPH_C32(0x8b17e000), + SPH_C32(0x865b0000), SPH_C32(0x9ed23715), SPH_C32(0x433b0923), + SPH_C32(0xb9af46d9), SPH_C32(0x995ccfac), SPH_C32(0x2c7f0000), + SPH_C32(0x10ad0028), SPH_C32(0xebb3c000), SPH_C32(0x6f190000), + SPH_C32(0x0a8c4e4f), SPH_C32(0x5be12651), SPH_C32(0x308dca90), + SPH_C32(0x09e8f879) }, + { SPH_C32(0x53ce0000), SPH_C32(0x78ce0015), SPH_C32(0xe6efe180), + SPH_C32(0xf17f0000), SPH_C32(0x7295308b), SPH_C32(0xb79b606d), + SPH_C32(0x740c5ecb), SPH_C32(0x01f686c2), SPH_C32(0x9e790000), + SPH_C32(0xd5c40028), SPH_C32(0xc3b0d200), SPH_C32(0x1b7e0000), + SPH_C32(0xbc4e78bb), SPH_C32(0xb0f31fa9), SPH_C32(0x035c157c), + SPH_C32(0x00a6c9e1) }, + { SPH_C32(0x38660000), SPH_C32(0x33670014), SPH_C32(0xbb6cc000), + SPH_C32(0x2baf0000), SPH_C32(0x11e029ff), SPH_C32(0x67128a24), + SPH_C32(0x516bda20), SPH_C32(0xd22223f9), SPH_C32(0x82bc0000), + SPH_C32(0x8ce20029), SPH_C32(0x92622000), SPH_C32(0x430c0000), + SPH_C32(0x4f403bfc), SPH_C32(0x3db19167), SPH_C32(0x9b1f3d1f), + SPH_C32(0xaafaae02) }, + { SPH_C32(0x26280000), SPH_C32(0xeda80014), SPH_C32(0xd694c180), + SPH_C32(0x5c8b0000), SPH_C32(0xfda72e61), SPH_C32(0x93b2e36a), + SPH_C32(0x9cc8c232), SPH_C32(0x4a886a97), SPH_C32(0x30ba0000), + SPH_C32(0x498b0029), SPH_C32(0xba613200), SPH_C32(0x376b0000), + SPH_C32(0xf9820d08), SPH_C32(0xd6a3a89f), SPH_C32(0xa8cee2f3), + SPH_C32(0xa3b49f9a) }, + { SPH_C32(0x96a50000), SPH_C32(0xaf280015), SPH_C32(0xc2bd2000), + SPH_C32(0x07ba0000), SPH_C32(0x542c5c4c), SPH_C32(0x01423d12), + SPH_C32(0xfaf92daf), SPH_C32(0x71307582), SPH_C32(0x59990000), + SPH_C32(0x85cb0029), SPH_C32(0xdbc8e000), SPH_C32(0xc2ed0000), + SPH_C32(0x85be50a5), SPH_C32(0x7fc8a556), SPH_C32(0xd8495669), + SPH_C32(0x4296142c) }, + { SPH_C32(0x88eb0000), SPH_C32(0x71e70015), SPH_C32(0xaf452180), + SPH_C32(0x709e0000), SPH_C32(0xb86b5bd2), SPH_C32(0xf5e2545c), + SPH_C32(0x375a35bd), SPH_C32(0xe99a3cec), SPH_C32(0xeb9f0000), + SPH_C32(0x40a20029), SPH_C32(0xf3cbf200), SPH_C32(0xb68a0000), + SPH_C32(0x337c6651), SPH_C32(0x94da9cae), SPH_C32(0xeb988985), + SPH_C32(0x4bd825b4) }, + { SPH_C32(0x653a0000), SPH_C32(0x05770016), SPH_C32(0x135ce000), + SPH_C32(0x32180000), SPH_C32(0x4e7b25a8), SPH_C32(0x6be376ff), + SPH_C32(0xc1e0f812), SPH_C32(0x2c53436e), SPH_C32(0xc7ed0000), + SPH_C32(0xfc540028), SPH_C32(0x56ed6000), SPH_C32(0xac3c0000), + SPH_C32(0xa3ca187c), SPH_C32(0x61228600), SPH_C32(0x5274000c), + SPH_C32(0x51215a63) }, + { SPH_C32(0x7b740000), SPH_C32(0xdbb80016), SPH_C32(0x7ea4e180), + SPH_C32(0x453c0000), SPH_C32(0xa23c2236), SPH_C32(0x9f431fb1), + SPH_C32(0x0c43e000), SPH_C32(0xb4f90a00), SPH_C32(0x75eb0000), + SPH_C32(0x393d0028), SPH_C32(0x7eee7200), SPH_C32(0xd85b0000), + SPH_C32(0x15082e88), SPH_C32(0x8a30bff8), SPH_C32(0x61a5dfe0), + SPH_C32(0x586f6bfb) }, + { SPH_C32(0xcbf90000), SPH_C32(0x99380017), SPH_C32(0x6a8d0000), + SPH_C32(0x1e0d0000), SPH_C32(0x0bb7501b), SPH_C32(0x0db3c1c9), + SPH_C32(0x6a720f9d), SPH_C32(0x8f411515), SPH_C32(0x1cc80000), + SPH_C32(0xf57d0028), SPH_C32(0x1f47a000), SPH_C32(0x2ddd0000), + SPH_C32(0x69347325), SPH_C32(0x235bb231), SPH_C32(0x11226b7a), + SPH_C32(0xb94de04d) }, + { SPH_C32(0xd5b70000), SPH_C32(0x47f70017), SPH_C32(0x07750180), + SPH_C32(0x69290000), SPH_C32(0xe7f05785), SPH_C32(0xf913a887), + SPH_C32(0xa7d1178f), SPH_C32(0x17eb5c7b), SPH_C32(0xaece0000), + SPH_C32(0x30140028), SPH_C32(0x3744b200), SPH_C32(0x59ba0000), + SPH_C32(0xdff645d1), SPH_C32(0xc8498bc9), SPH_C32(0x22f3b496), + SPH_C32(0xb003d1d5) }, + { SPH_C32(0xbe1f0000), SPH_C32(0x0c5e0016), SPH_C32(0x5af62000), + SPH_C32(0xb3f90000), SPH_C32(0x84854ef1), SPH_C32(0x299a42ce), + SPH_C32(0x82b69364), SPH_C32(0xc43ff940), SPH_C32(0xb20b0000), + SPH_C32(0x69320029), SPH_C32(0x66964000), SPH_C32(0x01c80000), + SPH_C32(0x2cf80696), SPH_C32(0x450b0507), SPH_C32(0xbab09cf5), + SPH_C32(0x1a5fb636) }, + { SPH_C32(0xa0510000), SPH_C32(0xd2910016), SPH_C32(0x370e2180), + SPH_C32(0xc4dd0000), SPH_C32(0x68c2496f), SPH_C32(0xdd3a2b80), + SPH_C32(0x4f158b76), SPH_C32(0x5c95b02e), SPH_C32(0x000d0000), + SPH_C32(0xac5b0029), SPH_C32(0x4e955200), SPH_C32(0x75af0000), + SPH_C32(0x9a3a3062), SPH_C32(0xae193cff), SPH_C32(0x89614319), + SPH_C32(0x131187ae) }, + { SPH_C32(0x10dc0000), SPH_C32(0x90110017), SPH_C32(0x2327c000), + SPH_C32(0x9fec0000), SPH_C32(0xc1493b42), SPH_C32(0x4fcaf5f8), + SPH_C32(0x292464eb), SPH_C32(0x672daf3b), SPH_C32(0x692e0000), + SPH_C32(0x601b0029), SPH_C32(0x2f3c8000), SPH_C32(0x80290000), + SPH_C32(0xe6066dcf), SPH_C32(0x07723136), SPH_C32(0xf9e6f783), + SPH_C32(0xf2330c18) }, + { SPH_C32(0x0e920000), SPH_C32(0x4ede0017), SPH_C32(0x4edfc180), + SPH_C32(0xe8c80000), SPH_C32(0x2d0e3cdc), SPH_C32(0xbb6a9cb6), + SPH_C32(0xe4877cf9), SPH_C32(0xff87e655), SPH_C32(0xdb280000), + SPH_C32(0xa5720029), SPH_C32(0x073f9200), SPH_C32(0xf44e0000), + SPH_C32(0x50c45b3b), SPH_C32(0xec6008ce), SPH_C32(0xca37286f), + SPH_C32(0xfb7d3d80) }, + { SPH_C32(0xd3f40000), SPH_C32(0xdf9e0014), SPH_C32(0x06326000), + SPH_C32(0xe88a0000), SPH_C32(0xb8a67fcc), SPH_C32(0x5dd12a75), + SPH_C32(0x339210bc), SPH_C32(0x8aeb81e3), SPH_C32(0x41940000), + SPH_C32(0xc36d002a), SPH_C32(0xb7778000), SPH_C32(0x346a0000), + SPH_C32(0x36af7f72), SPH_C32(0x2faa4eea), SPH_C32(0x81a94948), + SPH_C32(0x473c80da) }, + { SPH_C32(0xcdba0000), SPH_C32(0x01510014), SPH_C32(0x6bca6180), + SPH_C32(0x9fae0000), SPH_C32(0x54e17852), SPH_C32(0xa971433b), + SPH_C32(0xfe3108ae), SPH_C32(0x1241c88d), SPH_C32(0xf3920000), + SPH_C32(0x0604002a), SPH_C32(0x9f749200), SPH_C32(0x400d0000), + SPH_C32(0x806d4986), SPH_C32(0xc4b87712), SPH_C32(0xb27896a4), + SPH_C32(0x4e72b142) }, + { SPH_C32(0x7d370000), SPH_C32(0x43d10015), SPH_C32(0x7fe38000), + SPH_C32(0xc49f0000), SPH_C32(0xfd6a0a7f), SPH_C32(0x3b819d43), + SPH_C32(0x9800e733), SPH_C32(0x29f9d798), SPH_C32(0x9ab10000), + SPH_C32(0xca44002a), SPH_C32(0xfedd4000), SPH_C32(0xb58b0000), + SPH_C32(0xfc51142b), SPH_C32(0x6dd37adb), SPH_C32(0xc2ff223e), + SPH_C32(0xaf503af4) }, + { SPH_C32(0x63790000), SPH_C32(0x9d1e0015), SPH_C32(0x121b8180), + SPH_C32(0xb3bb0000), SPH_C32(0x112d0de1), SPH_C32(0xcf21f40d), + SPH_C32(0x55a3ff21), SPH_C32(0xb1539ef6), SPH_C32(0x28b70000), + SPH_C32(0x0f2d002a), SPH_C32(0xd6de5200), SPH_C32(0xc1ec0000), + SPH_C32(0x4a9322df), SPH_C32(0x86c14323), SPH_C32(0xf12efdd2), + SPH_C32(0xa61e0b6c) }, + { SPH_C32(0x08d10000), SPH_C32(0xd6b70014), SPH_C32(0x4f98a000), + SPH_C32(0x696b0000), SPH_C32(0x72581495), SPH_C32(0x1fa81e44), + SPH_C32(0x70c47bca), SPH_C32(0x62873bcd), SPH_C32(0x34720000), + SPH_C32(0x560b002b), SPH_C32(0x870ca000), SPH_C32(0x999e0000), + SPH_C32(0xb99d6198), SPH_C32(0x0b83cded), SPH_C32(0x696dd5b1), + SPH_C32(0x0c426c8f) }, + { SPH_C32(0x169f0000), SPH_C32(0x08780014), SPH_C32(0x2260a180), + SPH_C32(0x1e4f0000), SPH_C32(0x9e1f130b), SPH_C32(0xeb08770a), + SPH_C32(0xbd6763d8), SPH_C32(0xfa2d72a3), SPH_C32(0x86740000), + SPH_C32(0x9362002b), SPH_C32(0xaf0fb200), SPH_C32(0xedf90000), + SPH_C32(0x0f5f576c), SPH_C32(0xe091f415), SPH_C32(0x5abc0a5d), + SPH_C32(0x050c5d17) }, + { SPH_C32(0xa6120000), SPH_C32(0x4af80015), SPH_C32(0x36494000), + SPH_C32(0x457e0000), SPH_C32(0x37946126), SPH_C32(0x79f8a972), + SPH_C32(0xdb568c45), SPH_C32(0xc1956db6), SPH_C32(0xef570000), + SPH_C32(0x5f22002b), SPH_C32(0xcea66000), SPH_C32(0x187f0000), + SPH_C32(0x73630ac1), SPH_C32(0x49faf9dc), SPH_C32(0x2a3bbec7), + SPH_C32(0xe42ed6a1) }, + { SPH_C32(0xb85c0000), SPH_C32(0x94370015), SPH_C32(0x5bb14180), + SPH_C32(0x325a0000), SPH_C32(0xdbd366b8), SPH_C32(0x8d58c03c), + SPH_C32(0x16f59457), SPH_C32(0x593f24d8), SPH_C32(0x5d510000), + SPH_C32(0x9a4b002b), SPH_C32(0xe6a57200), SPH_C32(0x6c180000), + SPH_C32(0xc5a13c35), SPH_C32(0xa2e8c024), SPH_C32(0x19ea612b), + SPH_C32(0xed60e739) }, + { SPH_C32(0x558d0000), SPH_C32(0xe0a70016), SPH_C32(0xe7a88000), + SPH_C32(0x70dc0000), SPH_C32(0x2dc318c2), SPH_C32(0x1359e29f), + SPH_C32(0xe04f59f8), SPH_C32(0x9cf65b5a), SPH_C32(0x71230000), + SPH_C32(0x26bd002a), SPH_C32(0x4383e000), SPH_C32(0x76ae0000), + SPH_C32(0x55174218), SPH_C32(0x5710da8a), SPH_C32(0xa006e8a2), + SPH_C32(0xf79998ee) }, + { SPH_C32(0x4bc30000), SPH_C32(0x3e680016), SPH_C32(0x8a508180), + SPH_C32(0x07f80000), SPH_C32(0xc1841f5c), SPH_C32(0xe7f98bd1), + SPH_C32(0x2dec41ea), SPH_C32(0x045c1234), SPH_C32(0xc3250000), + SPH_C32(0xe3d4002a), SPH_C32(0x6b80f200), SPH_C32(0x02c90000), + SPH_C32(0xe3d574ec), SPH_C32(0xbc02e372), SPH_C32(0x93d7374e), + SPH_C32(0xfed7a976) }, + { SPH_C32(0xfb4e0000), SPH_C32(0x7ce80017), SPH_C32(0x9e796000), + SPH_C32(0x5cc90000), SPH_C32(0x680f6d71), SPH_C32(0x750955a9), + SPH_C32(0x4bddae77), SPH_C32(0x3fe40d21), SPH_C32(0xaa060000), + SPH_C32(0x2f94002a), SPH_C32(0x0a292000), SPH_C32(0xf74f0000), + SPH_C32(0x9fe92941), SPH_C32(0x1569eebb), SPH_C32(0xe35083d4), + SPH_C32(0x1ff522c0) }, + { SPH_C32(0xe5000000), SPH_C32(0xa2270017), SPH_C32(0xf3816180), + SPH_C32(0x2bed0000), SPH_C32(0x84486aef), SPH_C32(0x81a93ce7), + SPH_C32(0x867eb665), SPH_C32(0xa74e444f), SPH_C32(0x18000000), + SPH_C32(0xeafd002a), SPH_C32(0x222a3200), SPH_C32(0x83280000), + SPH_C32(0x292b1fb5), SPH_C32(0xfe7bd743), SPH_C32(0xd0815c38), + SPH_C32(0x16bb1358) }, + { SPH_C32(0x8ea80000), SPH_C32(0xe98e0016), SPH_C32(0xae024000), + SPH_C32(0xf13d0000), SPH_C32(0xe73d739b), SPH_C32(0x5120d6ae), + SPH_C32(0xa319328e), SPH_C32(0x749ae174), SPH_C32(0x04c50000), + SPH_C32(0xb3db002b), SPH_C32(0x73f8c000), SPH_C32(0xdb5a0000), + SPH_C32(0xda255cf2), SPH_C32(0x7339598d), SPH_C32(0x48c2745b), + SPH_C32(0xbce774bb) }, + { SPH_C32(0x90e60000), SPH_C32(0x37410016), SPH_C32(0xc3fa4180), + SPH_C32(0x86190000), SPH_C32(0x0b7a7405), SPH_C32(0xa580bfe0), + SPH_C32(0x6eba2a9c), SPH_C32(0xec30a81a), SPH_C32(0xb6c30000), + SPH_C32(0x76b2002b), SPH_C32(0x5bfbd200), SPH_C32(0xaf3d0000), + SPH_C32(0x6ce76a06), SPH_C32(0x982b6075), SPH_C32(0x7b13abb7), + SPH_C32(0xb5a94523) }, + { SPH_C32(0x206b0000), SPH_C32(0x75c10017), SPH_C32(0xd7d3a000), + SPH_C32(0xdd280000), SPH_C32(0xa2f10628), SPH_C32(0x37706198), + SPH_C32(0x088bc501), SPH_C32(0xd788b70f), SPH_C32(0xdfe00000), + SPH_C32(0xbaf2002b), SPH_C32(0x3a520000), SPH_C32(0x5abb0000), + SPH_C32(0x10db37ab), SPH_C32(0x31406dbc), SPH_C32(0x0b941f2d), + SPH_C32(0x548bce95) }, + { SPH_C32(0x3e250000), SPH_C32(0xab0e0017), SPH_C32(0xba2ba180), + SPH_C32(0xaa0c0000), SPH_C32(0x4eb601b6), SPH_C32(0xc3d008d6), + SPH_C32(0xc528dd13), SPH_C32(0x4f22fe61), SPH_C32(0x6de60000), + SPH_C32(0x7f9b002b), SPH_C32(0x12511200), SPH_C32(0x2edc0000), + SPH_C32(0xa619015f), SPH_C32(0xda525444), SPH_C32(0x3845c0c1), + SPH_C32(0x5dc5ff0d) }, + { SPH_C32(0xf75a0000), SPH_C32(0x19840028), SPH_C32(0xa2190000), + SPH_C32(0xeef80000), SPH_C32(0xc0722516), SPH_C32(0x19981260), + SPH_C32(0x73dba1e6), SPH_C32(0xe1844257), SPH_C32(0x14190000), + SPH_C32(0x23ca003c), SPH_C32(0x50df0000), SPH_C32(0x44b60000), + SPH_C32(0x1b6c67b0), SPH_C32(0x3cf3ac75), SPH_C32(0x61e610b0), + SPH_C32(0xdbcadb80) }, + { SPH_C32(0xe9140000), SPH_C32(0xc74b0028), SPH_C32(0xcfe10180), + SPH_C32(0x99dc0000), SPH_C32(0x2c352288), SPH_C32(0xed387b2e), + SPH_C32(0xbe78b9f4), SPH_C32(0x792e0b39), SPH_C32(0xa61f0000), + SPH_C32(0xe6a3003c), SPH_C32(0x78dc1200), SPH_C32(0x30d10000), + SPH_C32(0xadae5144), SPH_C32(0xd7e1958d), SPH_C32(0x5237cf5c), + SPH_C32(0xd284ea18) }, + { SPH_C32(0x59990000), SPH_C32(0x85cb0029), SPH_C32(0xdbc8e000), + SPH_C32(0xc2ed0000), SPH_C32(0x85be50a5), SPH_C32(0x7fc8a556), + SPH_C32(0xd8495669), SPH_C32(0x4296142c), SPH_C32(0xcf3c0000), + SPH_C32(0x2ae3003c), SPH_C32(0x1975c000), SPH_C32(0xc5570000), + SPH_C32(0xd1920ce9), SPH_C32(0x7e8a9844), SPH_C32(0x22b07bc6), + SPH_C32(0x33a661ae) }, + { SPH_C32(0x47d70000), SPH_C32(0x5b040029), SPH_C32(0xb630e180), + SPH_C32(0xb5c90000), SPH_C32(0x69f9573b), SPH_C32(0x8b68cc18), + SPH_C32(0x15ea4e7b), SPH_C32(0xda3c5d42), SPH_C32(0x7d3a0000), + SPH_C32(0xef8a003c), SPH_C32(0x3176d200), SPH_C32(0xb1300000), + SPH_C32(0x67503a1d), SPH_C32(0x9598a1bc), SPH_C32(0x1161a42a), + SPH_C32(0x3ae85036) }, + { SPH_C32(0x2c7f0000), SPH_C32(0x10ad0028), SPH_C32(0xebb3c000), + SPH_C32(0x6f190000), SPH_C32(0x0a8c4e4f), SPH_C32(0x5be12651), + SPH_C32(0x308dca90), SPH_C32(0x09e8f879), SPH_C32(0x61ff0000), + SPH_C32(0xb6ac003d), SPH_C32(0x60a42000), SPH_C32(0xe9420000), + SPH_C32(0x945e795a), SPH_C32(0x18da2f72), SPH_C32(0x89228c49), + SPH_C32(0x90b437d5) }, + { SPH_C32(0x32310000), SPH_C32(0xce620028), SPH_C32(0x864bc180), + SPH_C32(0x183d0000), SPH_C32(0xe6cb49d1), SPH_C32(0xaf414f1f), + SPH_C32(0xfd2ed282), SPH_C32(0x9142b117), SPH_C32(0xd3f90000), + SPH_C32(0x73c5003d), SPH_C32(0x48a73200), SPH_C32(0x9d250000), + SPH_C32(0x229c4fae), SPH_C32(0xf3c8168a), SPH_C32(0xbaf353a5), + SPH_C32(0x99fa064d) }, + { SPH_C32(0x82bc0000), SPH_C32(0x8ce20029), SPH_C32(0x92622000), + SPH_C32(0x430c0000), SPH_C32(0x4f403bfc), SPH_C32(0x3db19167), + SPH_C32(0x9b1f3d1f), SPH_C32(0xaafaae02), SPH_C32(0xbada0000), + SPH_C32(0xbf85003d), SPH_C32(0x290ee000), SPH_C32(0x68a30000), + SPH_C32(0x5ea01203), SPH_C32(0x5aa31b43), SPH_C32(0xca74e73f), + SPH_C32(0x78d88dfb) }, + { SPH_C32(0x9cf20000), SPH_C32(0x522d0029), SPH_C32(0xff9a2180), + SPH_C32(0x34280000), SPH_C32(0xa3073c62), SPH_C32(0xc911f829), + SPH_C32(0x56bc250d), SPH_C32(0x3250e76c), SPH_C32(0x08dc0000), + SPH_C32(0x7aec003d), SPH_C32(0x010df200), SPH_C32(0x1cc40000), + SPH_C32(0xe86224f7), SPH_C32(0xb1b122bb), SPH_C32(0xf9a538d3), + SPH_C32(0x7196bc63) }, + { SPH_C32(0x71230000), SPH_C32(0x26bd002a), SPH_C32(0x4383e000), + SPH_C32(0x76ae0000), SPH_C32(0x55174218), SPH_C32(0x5710da8a), + SPH_C32(0xa006e8a2), SPH_C32(0xf79998ee), SPH_C32(0x24ae0000), + SPH_C32(0xc61a003c), SPH_C32(0xa42b6000), SPH_C32(0x06720000), + SPH_C32(0x78d45ada), SPH_C32(0x44493815), SPH_C32(0x4049b15a), + SPH_C32(0x6b6fc3b4) }, + { SPH_C32(0x6f6d0000), SPH_C32(0xf872002a), SPH_C32(0x2e7be180), + SPH_C32(0x018a0000), SPH_C32(0xb9504586), SPH_C32(0xa3b0b3c4), + SPH_C32(0x6da5f0b0), SPH_C32(0x6f33d180), SPH_C32(0x96a80000), + SPH_C32(0x0373003c), SPH_C32(0x8c287200), SPH_C32(0x72150000), + SPH_C32(0xce166c2e), SPH_C32(0xaf5b01ed), SPH_C32(0x73986eb6), + SPH_C32(0x6221f22c) }, + { SPH_C32(0xdfe00000), SPH_C32(0xbaf2002b), SPH_C32(0x3a520000), + SPH_C32(0x5abb0000), SPH_C32(0x10db37ab), SPH_C32(0x31406dbc), + SPH_C32(0x0b941f2d), SPH_C32(0x548bce95), SPH_C32(0xff8b0000), + SPH_C32(0xcf33003c), SPH_C32(0xed81a000), SPH_C32(0x87930000), + SPH_C32(0xb22a3183), SPH_C32(0x06300c24), SPH_C32(0x031fda2c), + SPH_C32(0x8303799a) }, + { SPH_C32(0xc1ae0000), SPH_C32(0x643d002b), SPH_C32(0x57aa0180), + SPH_C32(0x2d9f0000), SPH_C32(0xfc9c3035), SPH_C32(0xc5e004f2), + SPH_C32(0xc637073f), SPH_C32(0xcc2187fb), SPH_C32(0x4d8d0000), + SPH_C32(0x0a5a003c), SPH_C32(0xc582b200), SPH_C32(0xf3f40000), + SPH_C32(0x04e80777), SPH_C32(0xed2235dc), SPH_C32(0x30ce05c0), + SPH_C32(0x8a4d4802) }, + { SPH_C32(0xaa060000), SPH_C32(0x2f94002a), SPH_C32(0x0a292000), + SPH_C32(0xf74f0000), SPH_C32(0x9fe92941), SPH_C32(0x1569eebb), + SPH_C32(0xe35083d4), SPH_C32(0x1ff522c0), SPH_C32(0x51480000), + SPH_C32(0x537c003d), SPH_C32(0x94504000), SPH_C32(0xab860000), + SPH_C32(0xf7e64430), SPH_C32(0x6060bb12), SPH_C32(0xa88d2da3), + SPH_C32(0x20112fe1) }, + { SPH_C32(0xb4480000), SPH_C32(0xf15b002a), SPH_C32(0x67d12180), + SPH_C32(0x806b0000), SPH_C32(0x73ae2edf), SPH_C32(0xe1c987f5), + SPH_C32(0x2ef39bc6), SPH_C32(0x875f6bae), SPH_C32(0xe34e0000), + SPH_C32(0x9615003d), SPH_C32(0xbc535200), SPH_C32(0xdfe10000), + SPH_C32(0x412472c4), SPH_C32(0x8b7282ea), SPH_C32(0x9b5cf24f), + SPH_C32(0x295f1e79) }, + { SPH_C32(0x04c50000), SPH_C32(0xb3db002b), SPH_C32(0x73f8c000), + SPH_C32(0xdb5a0000), SPH_C32(0xda255cf2), SPH_C32(0x7339598d), + SPH_C32(0x48c2745b), SPH_C32(0xbce774bb), SPH_C32(0x8a6d0000), + SPH_C32(0x5a55003d), SPH_C32(0xddfa8000), SPH_C32(0x2a670000), + SPH_C32(0x3d182f69), SPH_C32(0x22198f23), SPH_C32(0xebdb46d5), + SPH_C32(0xc87d95cf) }, + { SPH_C32(0x1a8b0000), SPH_C32(0x6d14002b), SPH_C32(0x1e00c180), + SPH_C32(0xac7e0000), SPH_C32(0x36625b6c), SPH_C32(0x879930c3), + SPH_C32(0x85616c49), SPH_C32(0x244d3dd5), SPH_C32(0x386b0000), + SPH_C32(0x9f3c003d), SPH_C32(0xf5f99200), SPH_C32(0x5e000000), + SPH_C32(0x8bda199d), SPH_C32(0xc90bb6db), SPH_C32(0xd80a9939), + SPH_C32(0xc133a457) }, + { SPH_C32(0xc7ed0000), SPH_C32(0xfc540028), SPH_C32(0x56ed6000), + SPH_C32(0xac3c0000), SPH_C32(0xa3ca187c), SPH_C32(0x61228600), + SPH_C32(0x5274000c), SPH_C32(0x51215a63), SPH_C32(0xa2d70000), + SPH_C32(0xf923003e), SPH_C32(0x45b18000), SPH_C32(0x9e240000), + SPH_C32(0xedb13dd4), SPH_C32(0x0ac1f0ff), SPH_C32(0x9394f81e), + SPH_C32(0x7d72190d) }, + { SPH_C32(0xd9a30000), SPH_C32(0x229b0028), SPH_C32(0x3b156180), + SPH_C32(0xdb180000), SPH_C32(0x4f8d1fe2), SPH_C32(0x9582ef4e), + SPH_C32(0x9fd7181e), SPH_C32(0xc98b130d), SPH_C32(0x10d10000), + SPH_C32(0x3c4a003e), SPH_C32(0x6db29200), SPH_C32(0xea430000), + SPH_C32(0x5b730b20), SPH_C32(0xe1d3c907), SPH_C32(0xa04527f2), + SPH_C32(0x743c2895) }, + { SPH_C32(0x692e0000), SPH_C32(0x601b0029), SPH_C32(0x2f3c8000), + SPH_C32(0x80290000), SPH_C32(0xe6066dcf), SPH_C32(0x07723136), + SPH_C32(0xf9e6f783), SPH_C32(0xf2330c18), SPH_C32(0x79f20000), + SPH_C32(0xf00a003e), SPH_C32(0x0c1b4000), SPH_C32(0x1fc50000), + SPH_C32(0x274f568d), SPH_C32(0x48b8c4ce), SPH_C32(0xd0c29368), + SPH_C32(0x951ea323) }, + { SPH_C32(0x77600000), SPH_C32(0xbed40029), SPH_C32(0x42c48180), + SPH_C32(0xf70d0000), SPH_C32(0x0a416a51), SPH_C32(0xf3d25878), + SPH_C32(0x3445ef91), SPH_C32(0x6a994576), SPH_C32(0xcbf40000), + SPH_C32(0x3563003e), SPH_C32(0x24185200), SPH_C32(0x6ba20000), + SPH_C32(0x918d6079), SPH_C32(0xa3aafd36), SPH_C32(0xe3134c84), + SPH_C32(0x9c5092bb) }, + { SPH_C32(0x1cc80000), SPH_C32(0xf57d0028), SPH_C32(0x1f47a000), + SPH_C32(0x2ddd0000), SPH_C32(0x69347325), SPH_C32(0x235bb231), + SPH_C32(0x11226b7a), SPH_C32(0xb94de04d), SPH_C32(0xd7310000), + SPH_C32(0x6c45003f), SPH_C32(0x75caa000), SPH_C32(0x33d00000), + SPH_C32(0x6283233e), SPH_C32(0x2ee873f8), SPH_C32(0x7b5064e7), + SPH_C32(0x360cf558) }, + { SPH_C32(0x02860000), SPH_C32(0x2bb20028), SPH_C32(0x72bfa180), + SPH_C32(0x5af90000), SPH_C32(0x857374bb), SPH_C32(0xd7fbdb7f), + SPH_C32(0xdc817368), SPH_C32(0x21e7a923), SPH_C32(0x65370000), + SPH_C32(0xa92c003f), SPH_C32(0x5dc9b200), SPH_C32(0x47b70000), + SPH_C32(0xd44115ca), SPH_C32(0xc5fa4a00), SPH_C32(0x4881bb0b), + SPH_C32(0x3f42c4c0) }, + { SPH_C32(0xb20b0000), SPH_C32(0x69320029), SPH_C32(0x66964000), + SPH_C32(0x01c80000), SPH_C32(0x2cf80696), SPH_C32(0x450b0507), + SPH_C32(0xbab09cf5), SPH_C32(0x1a5fb636), SPH_C32(0x0c140000), + SPH_C32(0x656c003f), SPH_C32(0x3c606000), SPH_C32(0xb2310000), + SPH_C32(0xa87d4867), SPH_C32(0x6c9147c9), SPH_C32(0x38060f91), + SPH_C32(0xde604f76) }, + { SPH_C32(0xac450000), SPH_C32(0xb7fd0029), SPH_C32(0x0b6e4180), + SPH_C32(0x76ec0000), SPH_C32(0xc0bf0108), SPH_C32(0xb1ab6c49), + SPH_C32(0x771384e7), SPH_C32(0x82f5ff58), SPH_C32(0xbe120000), + SPH_C32(0xa005003f), SPH_C32(0x14637200), SPH_C32(0xc6560000), + SPH_C32(0x1ebf7e93), SPH_C32(0x87837e31), SPH_C32(0x0bd7d07d), + SPH_C32(0xd72e7eee) }, + { SPH_C32(0x41940000), SPH_C32(0xc36d002a), SPH_C32(0xb7778000), + SPH_C32(0x346a0000), SPH_C32(0x36af7f72), SPH_C32(0x2faa4eea), + SPH_C32(0x81a94948), SPH_C32(0x473c80da), SPH_C32(0x92600000), + SPH_C32(0x1cf3003e), SPH_C32(0xb145e000), SPH_C32(0xdce00000), + SPH_C32(0x8e0900be), SPH_C32(0x727b649f), SPH_C32(0xb23b59f4), + SPH_C32(0xcdd70139) }, + { SPH_C32(0x5fda0000), SPH_C32(0x1da2002a), SPH_C32(0xda8f8180), + SPH_C32(0x434e0000), SPH_C32(0xdae878ec), SPH_C32(0xdb0a27a4), + SPH_C32(0x4c0a515a), SPH_C32(0xdf96c9b4), SPH_C32(0x20660000), + SPH_C32(0xd99a003e), SPH_C32(0x9946f200), SPH_C32(0xa8870000), + SPH_C32(0x38cb364a), SPH_C32(0x99695d67), SPH_C32(0x81ea8618), + SPH_C32(0xc49930a1) }, + { SPH_C32(0xef570000), SPH_C32(0x5f22002b), SPH_C32(0xcea66000), + SPH_C32(0x187f0000), SPH_C32(0x73630ac1), SPH_C32(0x49faf9dc), + SPH_C32(0x2a3bbec7), SPH_C32(0xe42ed6a1), SPH_C32(0x49450000), + SPH_C32(0x15da003e), SPH_C32(0xf8ef2000), SPH_C32(0x5d010000), + SPH_C32(0x44f76be7), SPH_C32(0x300250ae), SPH_C32(0xf16d3282), + SPH_C32(0x25bbbb17) }, + { SPH_C32(0xf1190000), SPH_C32(0x81ed002b), SPH_C32(0xa35e6180), + SPH_C32(0x6f5b0000), SPH_C32(0x9f240d5f), SPH_C32(0xbd5a9092), + SPH_C32(0xe798a6d5), SPH_C32(0x7c849fcf), SPH_C32(0xfb430000), + SPH_C32(0xd0b3003e), SPH_C32(0xd0ec3200), SPH_C32(0x29660000), + SPH_C32(0xf2355d13), SPH_C32(0xdb106956), SPH_C32(0xc2bced6e), + SPH_C32(0x2cf58a8f) }, + { SPH_C32(0x9ab10000), SPH_C32(0xca44002a), SPH_C32(0xfedd4000), + SPH_C32(0xb58b0000), SPH_C32(0xfc51142b), SPH_C32(0x6dd37adb), + SPH_C32(0xc2ff223e), SPH_C32(0xaf503af4), SPH_C32(0xe7860000), + SPH_C32(0x8995003f), SPH_C32(0x813ec000), SPH_C32(0x71140000), + SPH_C32(0x013b1e54), SPH_C32(0x5652e798), SPH_C32(0x5affc50d), + SPH_C32(0x86a9ed6c) }, + { SPH_C32(0x84ff0000), SPH_C32(0x148b002a), SPH_C32(0x93254180), + SPH_C32(0xc2af0000), SPH_C32(0x101613b5), SPH_C32(0x99731395), + SPH_C32(0x0f5c3a2c), SPH_C32(0x37fa739a), SPH_C32(0x55800000), + SPH_C32(0x4cfc003f), SPH_C32(0xa93dd200), SPH_C32(0x05730000), + SPH_C32(0xb7f928a0), SPH_C32(0xbd40de60), SPH_C32(0x692e1ae1), + SPH_C32(0x8fe7dcf4) }, + { SPH_C32(0x34720000), SPH_C32(0x560b002b), SPH_C32(0x870ca000), + SPH_C32(0x999e0000), SPH_C32(0xb99d6198), SPH_C32(0x0b83cded), + SPH_C32(0x696dd5b1), SPH_C32(0x0c426c8f), SPH_C32(0x3ca30000), + SPH_C32(0x80bc003f), SPH_C32(0xc8940000), SPH_C32(0xf0f50000), + SPH_C32(0xcbc5750d), SPH_C32(0x142bd3a9), SPH_C32(0x19a9ae7b), + SPH_C32(0x6ec55742) }, + { SPH_C32(0x2a3c0000), SPH_C32(0x88c4002b), SPH_C32(0xeaf4a180), + SPH_C32(0xeeba0000), SPH_C32(0x55da6606), SPH_C32(0xff23a4a3), + SPH_C32(0xa4cecda3), SPH_C32(0x94e825e1), SPH_C32(0x8ea50000), + SPH_C32(0x45d5003f), SPH_C32(0xe0971200), SPH_C32(0x84920000), + SPH_C32(0x7d0743f9), SPH_C32(0xff39ea51), SPH_C32(0x2a787197), + SPH_C32(0x678b66da) } +}; + +static const sph_u32 T512_35[128][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0x52500000), SPH_C32(0x29540000), SPH_C32(0x6a61004e), + SPH_C32(0xf0ff0000), SPH_C32(0x9a317eec), SPH_C32(0x452341ce), + SPH_C32(0xcf568fe5), SPH_C32(0x5303130f), SPH_C32(0x538d0000), + SPH_C32(0xa9fc0000), SPH_C32(0x9ef70006), SPH_C32(0x56ff0000), + SPH_C32(0x0ae4004e), SPH_C32(0x92c5cdf9), SPH_C32(0xa9444018), + SPH_C32(0x7f975691) }, + { SPH_C32(0x538d0000), SPH_C32(0xa9fc0000), SPH_C32(0x9ef70006), + SPH_C32(0x56ff0000), SPH_C32(0x0ae4004e), SPH_C32(0x92c5cdf9), + SPH_C32(0xa9444018), SPH_C32(0x7f975691), SPH_C32(0x01dd0000), + SPH_C32(0x80a80000), SPH_C32(0xf4960048), SPH_C32(0xa6000000), + SPH_C32(0x90d57ea2), SPH_C32(0xd7e68c37), SPH_C32(0x6612cffd), + SPH_C32(0x2c94459e) }, + { SPH_C32(0x01dd0000), SPH_C32(0x80a80000), SPH_C32(0xf4960048), + SPH_C32(0xa6000000), SPH_C32(0x90d57ea2), SPH_C32(0xd7e68c37), + SPH_C32(0x6612cffd), SPH_C32(0x2c94459e), SPH_C32(0x52500000), + SPH_C32(0x29540000), SPH_C32(0x6a61004e), SPH_C32(0xf0ff0000), + SPH_C32(0x9a317eec), SPH_C32(0x452341ce), SPH_C32(0xcf568fe5), + SPH_C32(0x5303130f) }, + { SPH_C32(0xcc140000), SPH_C32(0xa5630000), SPH_C32(0x5ab90780), + SPH_C32(0x3b500000), SPH_C32(0x4bd013ff), SPH_C32(0x879b3418), + SPH_C32(0x694348c1), SPH_C32(0xca5a87fe), SPH_C32(0x819e0000), + SPH_C32(0xec570000), SPH_C32(0x66320280), SPH_C32(0x95f30000), + SPH_C32(0x5da92802), SPH_C32(0x48f43cbc), SPH_C32(0xe65aa22d), + SPH_C32(0x8e67b7fa) }, + { SPH_C32(0x9e440000), SPH_C32(0x8c370000), SPH_C32(0x30d807ce), + SPH_C32(0xcbaf0000), SPH_C32(0xd1e16d13), SPH_C32(0xc2b875d6), + SPH_C32(0xa615c724), SPH_C32(0x995994f1), SPH_C32(0xd2130000), + SPH_C32(0x45ab0000), SPH_C32(0xf8c50286), SPH_C32(0xc30c0000), + SPH_C32(0x574d284c), SPH_C32(0xda31f145), SPH_C32(0x4f1ee235), + SPH_C32(0xf1f0e16b) }, + { SPH_C32(0x9f990000), SPH_C32(0x0c9f0000), SPH_C32(0xc44e0786), + SPH_C32(0x6daf0000), SPH_C32(0x413413b1), SPH_C32(0x155ef9e1), + SPH_C32(0xc00708d9), SPH_C32(0xb5cdd16f), SPH_C32(0x80430000), + SPH_C32(0x6cff0000), SPH_C32(0x92a402c8), SPH_C32(0x33f30000), + SPH_C32(0xcd7c56a0), SPH_C32(0x9f12b08b), SPH_C32(0x80486dd0), + SPH_C32(0xa2f3f264) }, + { SPH_C32(0xcdc90000), SPH_C32(0x25cb0000), SPH_C32(0xae2f07c8), + SPH_C32(0x9d500000), SPH_C32(0xdb056d5d), SPH_C32(0x507db82f), + SPH_C32(0x0f51873c), SPH_C32(0xe6cec260), SPH_C32(0xd3ce0000), + SPH_C32(0xc5030000), SPH_C32(0x0c5302ce), SPH_C32(0x650c0000), + SPH_C32(0xc79856ee), SPH_C32(0x0dd77d72), SPH_C32(0x290c2dc8), + SPH_C32(0xdd64a4f5) }, + { SPH_C32(0x819e0000), SPH_C32(0xec570000), SPH_C32(0x66320280), + SPH_C32(0x95f30000), SPH_C32(0x5da92802), SPH_C32(0x48f43cbc), + SPH_C32(0xe65aa22d), SPH_C32(0x8e67b7fa), SPH_C32(0x4d8a0000), + SPH_C32(0x49340000), SPH_C32(0x3c8b0500), SPH_C32(0xaea30000), + SPH_C32(0x16793bfd), SPH_C32(0xcf6f08a4), SPH_C32(0x8f19eaec), + SPH_C32(0x443d3004) }, + { SPH_C32(0xd3ce0000), SPH_C32(0xc5030000), SPH_C32(0x0c5302ce), + SPH_C32(0x650c0000), SPH_C32(0xc79856ee), SPH_C32(0x0dd77d72), + SPH_C32(0x290c2dc8), SPH_C32(0xdd64a4f5), SPH_C32(0x1e070000), + SPH_C32(0xe0c80000), SPH_C32(0xa27c0506), SPH_C32(0xf85c0000), + SPH_C32(0x1c9d3bb3), SPH_C32(0x5daac55d), SPH_C32(0x265daaf4), + SPH_C32(0x3baa6695) }, + { SPH_C32(0xd2130000), SPH_C32(0x45ab0000), SPH_C32(0xf8c50286), + SPH_C32(0xc30c0000), SPH_C32(0x574d284c), SPH_C32(0xda31f145), + SPH_C32(0x4f1ee235), SPH_C32(0xf1f0e16b), SPH_C32(0x4c570000), + SPH_C32(0xc99c0000), SPH_C32(0xc81d0548), SPH_C32(0x08a30000), + SPH_C32(0x86ac455f), SPH_C32(0x18898493), SPH_C32(0xe90b2511), + SPH_C32(0x68a9759a) }, + { SPH_C32(0x80430000), SPH_C32(0x6cff0000), SPH_C32(0x92a402c8), + SPH_C32(0x33f30000), SPH_C32(0xcd7c56a0), SPH_C32(0x9f12b08b), + SPH_C32(0x80486dd0), SPH_C32(0xa2f3f264), SPH_C32(0x1fda0000), + SPH_C32(0x60600000), SPH_C32(0x56ea054e), SPH_C32(0x5e5c0000), + SPH_C32(0x8c484511), SPH_C32(0x8a4c496a), SPH_C32(0x404f6509), + SPH_C32(0x173e230b) }, + { SPH_C32(0x4d8a0000), SPH_C32(0x49340000), SPH_C32(0x3c8b0500), + SPH_C32(0xaea30000), SPH_C32(0x16793bfd), SPH_C32(0xcf6f08a4), + SPH_C32(0x8f19eaec), SPH_C32(0x443d3004), SPH_C32(0xcc140000), + SPH_C32(0xa5630000), SPH_C32(0x5ab90780), SPH_C32(0x3b500000), + SPH_C32(0x4bd013ff), SPH_C32(0x879b3418), SPH_C32(0x694348c1), + SPH_C32(0xca5a87fe) }, + { SPH_C32(0x1fda0000), SPH_C32(0x60600000), SPH_C32(0x56ea054e), + SPH_C32(0x5e5c0000), SPH_C32(0x8c484511), SPH_C32(0x8a4c496a), + SPH_C32(0x404f6509), SPH_C32(0x173e230b), SPH_C32(0x9f990000), + SPH_C32(0x0c9f0000), SPH_C32(0xc44e0786), SPH_C32(0x6daf0000), + SPH_C32(0x413413b1), SPH_C32(0x155ef9e1), SPH_C32(0xc00708d9), + SPH_C32(0xb5cdd16f) }, + { SPH_C32(0x1e070000), SPH_C32(0xe0c80000), SPH_C32(0xa27c0506), + SPH_C32(0xf85c0000), SPH_C32(0x1c9d3bb3), SPH_C32(0x5daac55d), + SPH_C32(0x265daaf4), SPH_C32(0x3baa6695), SPH_C32(0xcdc90000), + SPH_C32(0x25cb0000), SPH_C32(0xae2f07c8), SPH_C32(0x9d500000), + SPH_C32(0xdb056d5d), SPH_C32(0x507db82f), SPH_C32(0x0f51873c), + SPH_C32(0xe6cec260) }, + { SPH_C32(0x4c570000), SPH_C32(0xc99c0000), SPH_C32(0xc81d0548), + SPH_C32(0x08a30000), SPH_C32(0x86ac455f), SPH_C32(0x18898493), + SPH_C32(0xe90b2511), SPH_C32(0x68a9759a), SPH_C32(0x9e440000), + SPH_C32(0x8c370000), SPH_C32(0x30d807ce), SPH_C32(0xcbaf0000), + SPH_C32(0xd1e16d13), SPH_C32(0xc2b875d6), SPH_C32(0xa615c724), + SPH_C32(0x995994f1) }, + { SPH_C32(0x78230000), SPH_C32(0x12fc0000), SPH_C32(0xa93a0b80), + SPH_C32(0x90a50000), SPH_C32(0x713e2879), SPH_C32(0x7ee98924), + SPH_C32(0xf08ca062), SPH_C32(0x636f8bab), SPH_C32(0x02af0000), + SPH_C32(0xb7280000), SPH_C32(0xba1c0300), SPH_C32(0x56980000), + SPH_C32(0xba8d45d3), SPH_C32(0x8048c667), SPH_C32(0xa95c149a), + SPH_C32(0xf4f6ea7b) }, + { SPH_C32(0x2a730000), SPH_C32(0x3ba80000), SPH_C32(0xc35b0bce), + SPH_C32(0x605a0000), SPH_C32(0xeb0f5695), SPH_C32(0x3bcac8ea), + SPH_C32(0x3fda2f87), SPH_C32(0x306c98a4), SPH_C32(0x51220000), + SPH_C32(0x1ed40000), SPH_C32(0x24eb0306), SPH_C32(0x00670000), + SPH_C32(0xb069459d), SPH_C32(0x128d0b9e), SPH_C32(0x00185482), + SPH_C32(0x8b61bcea) }, + { SPH_C32(0x2bae0000), SPH_C32(0xbb000000), SPH_C32(0x37cd0b86), + SPH_C32(0xc65a0000), SPH_C32(0x7bda2837), SPH_C32(0xec2c44dd), + SPH_C32(0x59c8e07a), SPH_C32(0x1cf8dd3a), SPH_C32(0x03720000), + SPH_C32(0x37800000), SPH_C32(0x4e8a0348), SPH_C32(0xf0980000), + SPH_C32(0x2a583b71), SPH_C32(0x57ae4a50), SPH_C32(0xcf4edb67), + SPH_C32(0xd862afe5) }, + { SPH_C32(0x79fe0000), SPH_C32(0x92540000), SPH_C32(0x5dac0bc8), + SPH_C32(0x36a50000), SPH_C32(0xe1eb56db), SPH_C32(0xa90f0513), + SPH_C32(0x969e6f9f), SPH_C32(0x4ffbce35), SPH_C32(0x50ff0000), + SPH_C32(0x9e7c0000), SPH_C32(0xd07d034e), SPH_C32(0xa6670000), + SPH_C32(0x20bc3b3f), SPH_C32(0xc56b87a9), SPH_C32(0x660a9b7f), + SPH_C32(0xa7f5f974) }, + { SPH_C32(0xb4370000), SPH_C32(0xb79f0000), SPH_C32(0xf3830c00), + SPH_C32(0xabf50000), SPH_C32(0x3aee3b86), SPH_C32(0xf972bd3c), + SPH_C32(0x99cfe8a3), SPH_C32(0xa9350c55), SPH_C32(0x83310000), + SPH_C32(0x5b7f0000), SPH_C32(0xdc2e0180), SPH_C32(0xc36b0000), + SPH_C32(0xe7246dd1), SPH_C32(0xc8bcfadb), SPH_C32(0x4f06b6b7), + SPH_C32(0x7a915d81) }, + { SPH_C32(0xe6670000), SPH_C32(0x9ecb0000), SPH_C32(0x99e20c4e), + SPH_C32(0x5b0a0000), SPH_C32(0xa0df456a), SPH_C32(0xbc51fcf2), + SPH_C32(0x56996746), SPH_C32(0xfa361f5a), SPH_C32(0xd0bc0000), + SPH_C32(0xf2830000), SPH_C32(0x42d90186), SPH_C32(0x95940000), + SPH_C32(0xedc06d9f), SPH_C32(0x5a793722), SPH_C32(0xe642f6af), + SPH_C32(0x05060b10) }, + { SPH_C32(0xe7ba0000), SPH_C32(0x1e630000), SPH_C32(0x6d740c06), + SPH_C32(0xfd0a0000), SPH_C32(0x300a3bc8), SPH_C32(0x6bb770c5), + SPH_C32(0x308ba8bb), SPH_C32(0xd6a25ac4), SPH_C32(0x82ec0000), + SPH_C32(0xdbd70000), SPH_C32(0x28b801c8), SPH_C32(0x656b0000), + SPH_C32(0x77f11373), SPH_C32(0x1f5a76ec), SPH_C32(0x2914794a), + SPH_C32(0x5605181f) }, + { SPH_C32(0xb5ea0000), SPH_C32(0x37370000), SPH_C32(0x07150c48), + SPH_C32(0x0df50000), SPH_C32(0xaa3b4524), SPH_C32(0x2e94310b), + SPH_C32(0xffdd275e), SPH_C32(0x85a149cb), SPH_C32(0xd1610000), + SPH_C32(0x722b0000), SPH_C32(0xb64f01ce), SPH_C32(0x33940000), + SPH_C32(0x7d15133d), SPH_C32(0x8d9fbb15), SPH_C32(0x80503952), + SPH_C32(0x29924e8e) }, + { SPH_C32(0xf9bd0000), SPH_C32(0xfeab0000), SPH_C32(0xcf080900), + SPH_C32(0x05560000), SPH_C32(0x2c97007b), SPH_C32(0x361db598), + SPH_C32(0x16d6024f), SPH_C32(0xed083c51), SPH_C32(0x4f250000), + SPH_C32(0xfe1c0000), SPH_C32(0x86970600), SPH_C32(0xf83b0000), + SPH_C32(0xacf47e2e), SPH_C32(0x4f27cec3), SPH_C32(0x2645fe76), + SPH_C32(0xb0cbda7f) }, + { SPH_C32(0xabed0000), SPH_C32(0xd7ff0000), SPH_C32(0xa569094e), + SPH_C32(0xf5a90000), SPH_C32(0xb6a67e97), SPH_C32(0x733ef456), + SPH_C32(0xd9808daa), SPH_C32(0xbe0b2f5e), SPH_C32(0x1ca80000), + SPH_C32(0x57e00000), SPH_C32(0x18600606), SPH_C32(0xaec40000), + SPH_C32(0xa6107e60), SPH_C32(0xdde2033a), SPH_C32(0x8f01be6e), + SPH_C32(0xcf5c8cee) }, + { SPH_C32(0xaa300000), SPH_C32(0x57570000), SPH_C32(0x51ff0906), + SPH_C32(0x53a90000), SPH_C32(0x26730035), SPH_C32(0xa4d87861), + SPH_C32(0xbf924257), SPH_C32(0x929f6ac0), SPH_C32(0x4ef80000), + SPH_C32(0x7eb40000), SPH_C32(0x72010648), SPH_C32(0x5e3b0000), + SPH_C32(0x3c21008c), SPH_C32(0x98c142f4), SPH_C32(0x4057318b), + SPH_C32(0x9c5f9fe1) }, + { SPH_C32(0xf8600000), SPH_C32(0x7e030000), SPH_C32(0x3b9e0948), + SPH_C32(0xa3560000), SPH_C32(0xbc427ed9), SPH_C32(0xe1fb39af), + SPH_C32(0x70c4cdb2), SPH_C32(0xc19c79cf), SPH_C32(0x1d750000), + SPH_C32(0xd7480000), SPH_C32(0xecf6064e), SPH_C32(0x08c40000), + SPH_C32(0x36c500c2), SPH_C32(0x0a048f0d), SPH_C32(0xe9137193), + SPH_C32(0xe3c8c970) }, + { SPH_C32(0x35a90000), SPH_C32(0x5bc80000), SPH_C32(0x95b10e80), + SPH_C32(0x3e060000), SPH_C32(0x67471384), SPH_C32(0xb1868180), + SPH_C32(0x7f954a8e), SPH_C32(0x2752bbaf), SPH_C32(0xcebb0000), + SPH_C32(0x124b0000), SPH_C32(0xe0a50480), SPH_C32(0x6dc80000), + SPH_C32(0xf15d562c), SPH_C32(0x07d3f27f), SPH_C32(0xc01f5c5b), + SPH_C32(0x3eac6d85) }, + { SPH_C32(0x67f90000), SPH_C32(0x729c0000), SPH_C32(0xffd00ece), + SPH_C32(0xcef90000), SPH_C32(0xfd766d68), SPH_C32(0xf4a5c04e), + SPH_C32(0xb0c3c56b), SPH_C32(0x7451a8a0), SPH_C32(0x9d360000), + SPH_C32(0xbbb70000), SPH_C32(0x7e520486), SPH_C32(0x3b370000), + SPH_C32(0xfbb95662), SPH_C32(0x95163f86), SPH_C32(0x695b1c43), + SPH_C32(0x413b3b14) }, + { SPH_C32(0x66240000), SPH_C32(0xf2340000), SPH_C32(0x0b460e86), + SPH_C32(0x68f90000), SPH_C32(0x6da313ca), SPH_C32(0x23434c79), + SPH_C32(0xd6d10a96), SPH_C32(0x58c5ed3e), SPH_C32(0xcf660000), + SPH_C32(0x92e30000), SPH_C32(0x143304c8), SPH_C32(0xcbc80000), + SPH_C32(0x6188288e), SPH_C32(0xd0357e48), SPH_C32(0xa60d93a6), + SPH_C32(0x1238281b) }, + { SPH_C32(0x34740000), SPH_C32(0xdb600000), SPH_C32(0x61270ec8), + SPH_C32(0x98060000), SPH_C32(0xf7926d26), SPH_C32(0x66600db7), + SPH_C32(0x19878573), SPH_C32(0x0bc6fe31), SPH_C32(0x9ceb0000), + SPH_C32(0x3b1f0000), SPH_C32(0x8ac404ce), SPH_C32(0x9d370000), + SPH_C32(0x6b6c28c0), SPH_C32(0x42f0b3b1), SPH_C32(0x0f49d3be), + SPH_C32(0x6daf7e8a) }, + { SPH_C32(0x02af0000), SPH_C32(0xb7280000), SPH_C32(0xba1c0300), + SPH_C32(0x56980000), SPH_C32(0xba8d45d3), SPH_C32(0x8048c667), + SPH_C32(0xa95c149a), SPH_C32(0xf4f6ea7b), SPH_C32(0x7a8c0000), + SPH_C32(0xa5d40000), SPH_C32(0x13260880), SPH_C32(0xc63d0000), + SPH_C32(0xcbb36daa), SPH_C32(0xfea14f43), SPH_C32(0x59d0b4f8), + SPH_C32(0x979961d0) }, + { SPH_C32(0x50ff0000), SPH_C32(0x9e7c0000), SPH_C32(0xd07d034e), + SPH_C32(0xa6670000), SPH_C32(0x20bc3b3f), SPH_C32(0xc56b87a9), + SPH_C32(0x660a9b7f), SPH_C32(0xa7f5f974), SPH_C32(0x29010000), + SPH_C32(0x0c280000), SPH_C32(0x8dd10886), SPH_C32(0x90c20000), + SPH_C32(0xc1576de4), SPH_C32(0x6c6482ba), SPH_C32(0xf094f4e0), + SPH_C32(0xe80e3741) }, + { SPH_C32(0x51220000), SPH_C32(0x1ed40000), SPH_C32(0x24eb0306), + SPH_C32(0x00670000), SPH_C32(0xb069459d), SPH_C32(0x128d0b9e), + SPH_C32(0x00185482), SPH_C32(0x8b61bcea), SPH_C32(0x7b510000), + SPH_C32(0x257c0000), SPH_C32(0xe7b008c8), SPH_C32(0x603d0000), + SPH_C32(0x5b661308), SPH_C32(0x2947c374), SPH_C32(0x3fc27b05), + SPH_C32(0xbb0d244e) }, + { SPH_C32(0x03720000), SPH_C32(0x37800000), SPH_C32(0x4e8a0348), + SPH_C32(0xf0980000), SPH_C32(0x2a583b71), SPH_C32(0x57ae4a50), + SPH_C32(0xcf4edb67), SPH_C32(0xd862afe5), SPH_C32(0x28dc0000), + SPH_C32(0x8c800000), SPH_C32(0x794708ce), SPH_C32(0x36c20000), + SPH_C32(0x51821346), SPH_C32(0xbb820e8d), SPH_C32(0x96863b1d), + SPH_C32(0xc49a72df) }, + { SPH_C32(0xcebb0000), SPH_C32(0x124b0000), SPH_C32(0xe0a50480), + SPH_C32(0x6dc80000), SPH_C32(0xf15d562c), SPH_C32(0x07d3f27f), + SPH_C32(0xc01f5c5b), SPH_C32(0x3eac6d85), SPH_C32(0xfb120000), + SPH_C32(0x49830000), SPH_C32(0x75140a00), SPH_C32(0x53ce0000), + SPH_C32(0x961a45a8), SPH_C32(0xb65573ff), SPH_C32(0xbf8a16d5), + SPH_C32(0x19fed62a) }, + { SPH_C32(0x9ceb0000), SPH_C32(0x3b1f0000), SPH_C32(0x8ac404ce), + SPH_C32(0x9d370000), SPH_C32(0x6b6c28c0), SPH_C32(0x42f0b3b1), + SPH_C32(0x0f49d3be), SPH_C32(0x6daf7e8a), SPH_C32(0xa89f0000), + SPH_C32(0xe07f0000), SPH_C32(0xebe30a06), SPH_C32(0x05310000), + SPH_C32(0x9cfe45e6), SPH_C32(0x2490be06), SPH_C32(0x16ce56cd), + SPH_C32(0x666980bb) }, + { SPH_C32(0x9d360000), SPH_C32(0xbbb70000), SPH_C32(0x7e520486), + SPH_C32(0x3b370000), SPH_C32(0xfbb95662), SPH_C32(0x95163f86), + SPH_C32(0x695b1c43), SPH_C32(0x413b3b14), SPH_C32(0xfacf0000), + SPH_C32(0xc92b0000), SPH_C32(0x81820a48), SPH_C32(0xf5ce0000), + SPH_C32(0x06cf3b0a), SPH_C32(0x61b3ffc8), SPH_C32(0xd998d928), + SPH_C32(0x356a93b4) }, + { SPH_C32(0xcf660000), SPH_C32(0x92e30000), SPH_C32(0x143304c8), + SPH_C32(0xcbc80000), SPH_C32(0x6188288e), SPH_C32(0xd0357e48), + SPH_C32(0xa60d93a6), SPH_C32(0x1238281b), SPH_C32(0xa9420000), + SPH_C32(0x60d70000), SPH_C32(0x1f750a4e), SPH_C32(0xa3310000), + SPH_C32(0x0c2b3b44), SPH_C32(0xf3763231), SPH_C32(0x70dc9930), + SPH_C32(0x4afdc525) }, + { SPH_C32(0x83310000), SPH_C32(0x5b7f0000), SPH_C32(0xdc2e0180), + SPH_C32(0xc36b0000), SPH_C32(0xe7246dd1), SPH_C32(0xc8bcfadb), + SPH_C32(0x4f06b6b7), SPH_C32(0x7a915d81), SPH_C32(0x37060000), + SPH_C32(0xece00000), SPH_C32(0x2fad0d80), SPH_C32(0x689e0000), + SPH_C32(0xddca5657), SPH_C32(0x31ce47e7), SPH_C32(0xd6c95e14), + SPH_C32(0xd3a451d4) }, + { SPH_C32(0xd1610000), SPH_C32(0x722b0000), SPH_C32(0xb64f01ce), + SPH_C32(0x33940000), SPH_C32(0x7d15133d), SPH_C32(0x8d9fbb15), + SPH_C32(0x80503952), SPH_C32(0x29924e8e), SPH_C32(0x648b0000), + SPH_C32(0x451c0000), SPH_C32(0xb15a0d86), SPH_C32(0x3e610000), + SPH_C32(0xd72e5619), SPH_C32(0xa30b8a1e), SPH_C32(0x7f8d1e0c), + SPH_C32(0xac330745) }, + { SPH_C32(0xd0bc0000), SPH_C32(0xf2830000), SPH_C32(0x42d90186), + SPH_C32(0x95940000), SPH_C32(0xedc06d9f), SPH_C32(0x5a793722), + SPH_C32(0xe642f6af), SPH_C32(0x05060b10), SPH_C32(0x36db0000), + SPH_C32(0x6c480000), SPH_C32(0xdb3b0dc8), SPH_C32(0xce9e0000), + SPH_C32(0x4d1f28f5), SPH_C32(0xe628cbd0), SPH_C32(0xb0db91e9), + SPH_C32(0xff30144a) }, + { SPH_C32(0x82ec0000), SPH_C32(0xdbd70000), SPH_C32(0x28b801c8), + SPH_C32(0x656b0000), SPH_C32(0x77f11373), SPH_C32(0x1f5a76ec), + SPH_C32(0x2914794a), SPH_C32(0x5605181f), SPH_C32(0x65560000), + SPH_C32(0xc5b40000), SPH_C32(0x45cc0dce), SPH_C32(0x98610000), + SPH_C32(0x47fb28bb), SPH_C32(0x74ed0629), SPH_C32(0x199fd1f1), + SPH_C32(0x80a742db) }, + { SPH_C32(0x4f250000), SPH_C32(0xfe1c0000), SPH_C32(0x86970600), + SPH_C32(0xf83b0000), SPH_C32(0xacf47e2e), SPH_C32(0x4f27cec3), + SPH_C32(0x2645fe76), SPH_C32(0xb0cbda7f), SPH_C32(0xb6980000), + SPH_C32(0x00b70000), SPH_C32(0x499f0f00), SPH_C32(0xfd6d0000), + SPH_C32(0x80637e55), SPH_C32(0x793a7b5b), SPH_C32(0x3093fc39), + SPH_C32(0x5dc3e62e) }, + { SPH_C32(0x1d750000), SPH_C32(0xd7480000), SPH_C32(0xecf6064e), + SPH_C32(0x08c40000), SPH_C32(0x36c500c2), SPH_C32(0x0a048f0d), + SPH_C32(0xe9137193), SPH_C32(0xe3c8c970), SPH_C32(0xe5150000), + SPH_C32(0xa94b0000), SPH_C32(0xd7680f06), SPH_C32(0xab920000), + SPH_C32(0x8a877e1b), SPH_C32(0xebffb6a2), SPH_C32(0x99d7bc21), + SPH_C32(0x2254b0bf) }, + { SPH_C32(0x1ca80000), SPH_C32(0x57e00000), SPH_C32(0x18600606), + SPH_C32(0xaec40000), SPH_C32(0xa6107e60), SPH_C32(0xdde2033a), + SPH_C32(0x8f01be6e), SPH_C32(0xcf5c8cee), SPH_C32(0xb7450000), + SPH_C32(0x801f0000), SPH_C32(0xbd090f48), SPH_C32(0x5b6d0000), + SPH_C32(0x10b600f7), SPH_C32(0xaedcf76c), SPH_C32(0x568133c4), + SPH_C32(0x7157a3b0) }, + { SPH_C32(0x4ef80000), SPH_C32(0x7eb40000), SPH_C32(0x72010648), + SPH_C32(0x5e3b0000), SPH_C32(0x3c21008c), SPH_C32(0x98c142f4), + SPH_C32(0x4057318b), SPH_C32(0x9c5f9fe1), SPH_C32(0xe4c80000), + SPH_C32(0x29e30000), SPH_C32(0x23fe0f4e), SPH_C32(0x0d920000), + SPH_C32(0x1a5200b9), SPH_C32(0x3c193a95), SPH_C32(0xffc573dc), + SPH_C32(0x0ec0f521) }, + { SPH_C32(0x7a8c0000), SPH_C32(0xa5d40000), SPH_C32(0x13260880), + SPH_C32(0xc63d0000), SPH_C32(0xcbb36daa), SPH_C32(0xfea14f43), + SPH_C32(0x59d0b4f8), SPH_C32(0x979961d0), SPH_C32(0x78230000), + SPH_C32(0x12fc0000), SPH_C32(0xa93a0b80), SPH_C32(0x90a50000), + SPH_C32(0x713e2879), SPH_C32(0x7ee98924), SPH_C32(0xf08ca062), + SPH_C32(0x636f8bab) }, + { SPH_C32(0x28dc0000), SPH_C32(0x8c800000), SPH_C32(0x794708ce), + SPH_C32(0x36c20000), SPH_C32(0x51821346), SPH_C32(0xbb820e8d), + SPH_C32(0x96863b1d), SPH_C32(0xc49a72df), SPH_C32(0x2bae0000), + SPH_C32(0xbb000000), SPH_C32(0x37cd0b86), SPH_C32(0xc65a0000), + SPH_C32(0x7bda2837), SPH_C32(0xec2c44dd), SPH_C32(0x59c8e07a), + SPH_C32(0x1cf8dd3a) }, + { SPH_C32(0x29010000), SPH_C32(0x0c280000), SPH_C32(0x8dd10886), + SPH_C32(0x90c20000), SPH_C32(0xc1576de4), SPH_C32(0x6c6482ba), + SPH_C32(0xf094f4e0), SPH_C32(0xe80e3741), SPH_C32(0x79fe0000), + SPH_C32(0x92540000), SPH_C32(0x5dac0bc8), SPH_C32(0x36a50000), + SPH_C32(0xe1eb56db), SPH_C32(0xa90f0513), SPH_C32(0x969e6f9f), + SPH_C32(0x4ffbce35) }, + { SPH_C32(0x7b510000), SPH_C32(0x257c0000), SPH_C32(0xe7b008c8), + SPH_C32(0x603d0000), SPH_C32(0x5b661308), SPH_C32(0x2947c374), + SPH_C32(0x3fc27b05), SPH_C32(0xbb0d244e), SPH_C32(0x2a730000), + SPH_C32(0x3ba80000), SPH_C32(0xc35b0bce), SPH_C32(0x605a0000), + SPH_C32(0xeb0f5695), SPH_C32(0x3bcac8ea), SPH_C32(0x3fda2f87), + SPH_C32(0x306c98a4) }, + { SPH_C32(0xb6980000), SPH_C32(0x00b70000), SPH_C32(0x499f0f00), + SPH_C32(0xfd6d0000), SPH_C32(0x80637e55), SPH_C32(0x793a7b5b), + SPH_C32(0x3093fc39), SPH_C32(0x5dc3e62e), SPH_C32(0xf9bd0000), + SPH_C32(0xfeab0000), SPH_C32(0xcf080900), SPH_C32(0x05560000), + SPH_C32(0x2c97007b), SPH_C32(0x361db598), SPH_C32(0x16d6024f), + SPH_C32(0xed083c51) }, + { SPH_C32(0xe4c80000), SPH_C32(0x29e30000), SPH_C32(0x23fe0f4e), + SPH_C32(0x0d920000), SPH_C32(0x1a5200b9), SPH_C32(0x3c193a95), + SPH_C32(0xffc573dc), SPH_C32(0x0ec0f521), SPH_C32(0xaa300000), + SPH_C32(0x57570000), SPH_C32(0x51ff0906), SPH_C32(0x53a90000), + SPH_C32(0x26730035), SPH_C32(0xa4d87861), SPH_C32(0xbf924257), + SPH_C32(0x929f6ac0) }, + { SPH_C32(0xe5150000), SPH_C32(0xa94b0000), SPH_C32(0xd7680f06), + SPH_C32(0xab920000), SPH_C32(0x8a877e1b), SPH_C32(0xebffb6a2), + SPH_C32(0x99d7bc21), SPH_C32(0x2254b0bf), SPH_C32(0xf8600000), + SPH_C32(0x7e030000), SPH_C32(0x3b9e0948), SPH_C32(0xa3560000), + SPH_C32(0xbc427ed9), SPH_C32(0xe1fb39af), SPH_C32(0x70c4cdb2), + SPH_C32(0xc19c79cf) }, + { SPH_C32(0xb7450000), SPH_C32(0x801f0000), SPH_C32(0xbd090f48), + SPH_C32(0x5b6d0000), SPH_C32(0x10b600f7), SPH_C32(0xaedcf76c), + SPH_C32(0x568133c4), SPH_C32(0x7157a3b0), SPH_C32(0xabed0000), + SPH_C32(0xd7ff0000), SPH_C32(0xa569094e), SPH_C32(0xf5a90000), + SPH_C32(0xb6a67e97), SPH_C32(0x733ef456), SPH_C32(0xd9808daa), + SPH_C32(0xbe0b2f5e) }, + { SPH_C32(0xfb120000), SPH_C32(0x49830000), SPH_C32(0x75140a00), + SPH_C32(0x53ce0000), SPH_C32(0x961a45a8), SPH_C32(0xb65573ff), + SPH_C32(0xbf8a16d5), SPH_C32(0x19fed62a), SPH_C32(0x35a90000), + SPH_C32(0x5bc80000), SPH_C32(0x95b10e80), SPH_C32(0x3e060000), + SPH_C32(0x67471384), SPH_C32(0xb1868180), SPH_C32(0x7f954a8e), + SPH_C32(0x2752bbaf) }, + { SPH_C32(0xa9420000), SPH_C32(0x60d70000), SPH_C32(0x1f750a4e), + SPH_C32(0xa3310000), SPH_C32(0x0c2b3b44), SPH_C32(0xf3763231), + SPH_C32(0x70dc9930), SPH_C32(0x4afdc525), SPH_C32(0x66240000), + SPH_C32(0xf2340000), SPH_C32(0x0b460e86), SPH_C32(0x68f90000), + SPH_C32(0x6da313ca), SPH_C32(0x23434c79), SPH_C32(0xd6d10a96), + SPH_C32(0x58c5ed3e) }, + { SPH_C32(0xa89f0000), SPH_C32(0xe07f0000), SPH_C32(0xebe30a06), + SPH_C32(0x05310000), SPH_C32(0x9cfe45e6), SPH_C32(0x2490be06), + SPH_C32(0x16ce56cd), SPH_C32(0x666980bb), SPH_C32(0x34740000), + SPH_C32(0xdb600000), SPH_C32(0x61270ec8), SPH_C32(0x98060000), + SPH_C32(0xf7926d26), SPH_C32(0x66600db7), SPH_C32(0x19878573), + SPH_C32(0x0bc6fe31) }, + { SPH_C32(0xfacf0000), SPH_C32(0xc92b0000), SPH_C32(0x81820a48), + SPH_C32(0xf5ce0000), SPH_C32(0x06cf3b0a), SPH_C32(0x61b3ffc8), + SPH_C32(0xd998d928), SPH_C32(0x356a93b4), SPH_C32(0x67f90000), + SPH_C32(0x729c0000), SPH_C32(0xffd00ece), SPH_C32(0xcef90000), + SPH_C32(0xfd766d68), SPH_C32(0xf4a5c04e), SPH_C32(0xb0c3c56b), + SPH_C32(0x7451a8a0) }, + { SPH_C32(0x37060000), SPH_C32(0xece00000), SPH_C32(0x2fad0d80), + SPH_C32(0x689e0000), SPH_C32(0xddca5657), SPH_C32(0x31ce47e7), + SPH_C32(0xd6c95e14), SPH_C32(0xd3a451d4), SPH_C32(0xb4370000), + SPH_C32(0xb79f0000), SPH_C32(0xf3830c00), SPH_C32(0xabf50000), + SPH_C32(0x3aee3b86), SPH_C32(0xf972bd3c), SPH_C32(0x99cfe8a3), + SPH_C32(0xa9350c55) }, + { SPH_C32(0x65560000), SPH_C32(0xc5b40000), SPH_C32(0x45cc0dce), + SPH_C32(0x98610000), SPH_C32(0x47fb28bb), SPH_C32(0x74ed0629), + SPH_C32(0x199fd1f1), SPH_C32(0x80a742db), SPH_C32(0xe7ba0000), + SPH_C32(0x1e630000), SPH_C32(0x6d740c06), SPH_C32(0xfd0a0000), + SPH_C32(0x300a3bc8), SPH_C32(0x6bb770c5), SPH_C32(0x308ba8bb), + SPH_C32(0xd6a25ac4) }, + { SPH_C32(0x648b0000), SPH_C32(0x451c0000), SPH_C32(0xb15a0d86), + SPH_C32(0x3e610000), SPH_C32(0xd72e5619), SPH_C32(0xa30b8a1e), + SPH_C32(0x7f8d1e0c), SPH_C32(0xac330745), SPH_C32(0xb5ea0000), + SPH_C32(0x37370000), SPH_C32(0x07150c48), SPH_C32(0x0df50000), + SPH_C32(0xaa3b4524), SPH_C32(0x2e94310b), SPH_C32(0xffdd275e), + SPH_C32(0x85a149cb) }, + { SPH_C32(0x36db0000), SPH_C32(0x6c480000), SPH_C32(0xdb3b0dc8), + SPH_C32(0xce9e0000), SPH_C32(0x4d1f28f5), SPH_C32(0xe628cbd0), + SPH_C32(0xb0db91e9), SPH_C32(0xff30144a), SPH_C32(0xe6670000), + SPH_C32(0x9ecb0000), SPH_C32(0x99e20c4e), SPH_C32(0x5b0a0000), + SPH_C32(0xa0df456a), SPH_C32(0xbc51fcf2), SPH_C32(0x56996746), + SPH_C32(0xfa361f5a) }, + { SPH_C32(0xac480000), SPH_C32(0x1ba60000), SPH_C32(0x45fb1380), + SPH_C32(0x03430000), SPH_C32(0x5a85316a), SPH_C32(0x1fb250b6), + SPH_C32(0xfe72c7fe), SPH_C32(0x91e478f6), SPH_C32(0x1e4e0000), + SPH_C32(0xdecf0000), SPH_C32(0x6df80180), SPH_C32(0x77240000), + SPH_C32(0xec47079e), SPH_C32(0xf4a0694e), SPH_C32(0xcda31812), + SPH_C32(0x98aa496e) }, + { SPH_C32(0xfe180000), SPH_C32(0x32f20000), SPH_C32(0x2f9a13ce), + SPH_C32(0xf3bc0000), SPH_C32(0xc0b44f86), SPH_C32(0x5a911178), + SPH_C32(0x3124481b), SPH_C32(0xc2e76bf9), SPH_C32(0x4dc30000), + SPH_C32(0x77330000), SPH_C32(0xf30f0186), SPH_C32(0x21db0000), + SPH_C32(0xe6a307d0), SPH_C32(0x6665a4b7), SPH_C32(0x64e7580a), + SPH_C32(0xe73d1fff) }, + { SPH_C32(0xffc50000), SPH_C32(0xb25a0000), SPH_C32(0xdb0c1386), + SPH_C32(0x55bc0000), SPH_C32(0x50613124), SPH_C32(0x8d779d4f), + SPH_C32(0x573687e6), SPH_C32(0xee732e67), SPH_C32(0x1f930000), + SPH_C32(0x5e670000), SPH_C32(0x996e01c8), SPH_C32(0xd1240000), + SPH_C32(0x7c92793c), SPH_C32(0x2346e579), SPH_C32(0xabb1d7ef), + SPH_C32(0xb43e0cf0) }, + { SPH_C32(0xad950000), SPH_C32(0x9b0e0000), SPH_C32(0xb16d13c8), + SPH_C32(0xa5430000), SPH_C32(0xca504fc8), SPH_C32(0xc854dc81), + SPH_C32(0x98600803), SPH_C32(0xbd703d68), SPH_C32(0x4c1e0000), + SPH_C32(0xf79b0000), SPH_C32(0x079901ce), SPH_C32(0x87db0000), + SPH_C32(0x76767972), SPH_C32(0xb1832880), SPH_C32(0x02f597f7), + SPH_C32(0xcba95a61) }, + { SPH_C32(0x605c0000), SPH_C32(0xbec50000), SPH_C32(0x1f421400), + SPH_C32(0x38130000), SPH_C32(0x11552295), SPH_C32(0x982964ae), + SPH_C32(0x97318f3f), SPH_C32(0x5bbeff08), SPH_C32(0x9fd00000), + SPH_C32(0x32980000), SPH_C32(0x0bca0300), SPH_C32(0xe2d70000), + SPH_C32(0xb1ee2f9c), SPH_C32(0xbc5455f2), SPH_C32(0x2bf9ba3f), + SPH_C32(0x16cdfe94) }, + { SPH_C32(0x320c0000), SPH_C32(0x97910000), SPH_C32(0x7523144e), + SPH_C32(0xc8ec0000), SPH_C32(0x8b645c79), SPH_C32(0xdd0a2560), + SPH_C32(0x586700da), SPH_C32(0x08bdec07), SPH_C32(0xcc5d0000), + SPH_C32(0x9b640000), SPH_C32(0x953d0306), SPH_C32(0xb4280000), + SPH_C32(0xbb0a2fd2), SPH_C32(0x2e91980b), SPH_C32(0x82bdfa27), + SPH_C32(0x695aa805) }, + { SPH_C32(0x33d10000), SPH_C32(0x17390000), SPH_C32(0x81b51406), + SPH_C32(0x6eec0000), SPH_C32(0x1bb122db), SPH_C32(0x0aeca957), + SPH_C32(0x3e75cf27), SPH_C32(0x2429a999), SPH_C32(0x9e0d0000), + SPH_C32(0xb2300000), SPH_C32(0xff5c0348), SPH_C32(0x44d70000), + SPH_C32(0x213b513e), SPH_C32(0x6bb2d9c5), SPH_C32(0x4deb75c2), + SPH_C32(0x3a59bb0a) }, + { SPH_C32(0x61810000), SPH_C32(0x3e6d0000), SPH_C32(0xebd41448), + SPH_C32(0x9e130000), SPH_C32(0x81805c37), SPH_C32(0x4fcfe899), + SPH_C32(0xf12340c2), SPH_C32(0x772aba96), SPH_C32(0xcd800000), + SPH_C32(0x1bcc0000), SPH_C32(0x61ab034e), SPH_C32(0x12280000), + SPH_C32(0x2bdf5170), SPH_C32(0xf977143c), SPH_C32(0xe4af35da), + SPH_C32(0x45ceed9b) }, + { SPH_C32(0x2dd60000), SPH_C32(0xf7f10000), SPH_C32(0x23c91100), + SPH_C32(0x96b00000), SPH_C32(0x072c1968), SPH_C32(0x57466c0a), + SPH_C32(0x182865d3), SPH_C32(0x1f83cf0c), SPH_C32(0x53c40000), + SPH_C32(0x97fb0000), SPH_C32(0x51730480), SPH_C32(0xd9870000), + SPH_C32(0xfa3e3c63), SPH_C32(0x3bcf61ea), SPH_C32(0x42baf2fe), + SPH_C32(0xdc97796a) }, + { SPH_C32(0x7f860000), SPH_C32(0xdea50000), SPH_C32(0x49a8114e), + SPH_C32(0x664f0000), SPH_C32(0x9d1d6784), SPH_C32(0x12652dc4), + SPH_C32(0xd77eea36), SPH_C32(0x4c80dc03), SPH_C32(0x00490000), + SPH_C32(0x3e070000), SPH_C32(0xcf840486), SPH_C32(0x8f780000), + SPH_C32(0xf0da3c2d), SPH_C32(0xa90aac13), SPH_C32(0xebfeb2e6), + SPH_C32(0xa3002ffb) }, + { SPH_C32(0x7e5b0000), SPH_C32(0x5e0d0000), SPH_C32(0xbd3e1106), + SPH_C32(0xc04f0000), SPH_C32(0x0dc81926), SPH_C32(0xc583a1f3), + SPH_C32(0xb16c25cb), SPH_C32(0x6014999d), SPH_C32(0x52190000), + SPH_C32(0x17530000), SPH_C32(0xa5e504c8), SPH_C32(0x7f870000), + SPH_C32(0x6aeb42c1), SPH_C32(0xec29eddd), SPH_C32(0x24a83d03), + SPH_C32(0xf0033cf4) }, + { SPH_C32(0x2c0b0000), SPH_C32(0x77590000), SPH_C32(0xd75f1148), + SPH_C32(0x30b00000), SPH_C32(0x97f967ca), SPH_C32(0x80a0e03d), + SPH_C32(0x7e3aaa2e), SPH_C32(0x33178a92), SPH_C32(0x01940000), + SPH_C32(0xbeaf0000), SPH_C32(0x3b1204ce), SPH_C32(0x29780000), + SPH_C32(0x600f428f), SPH_C32(0x7eec2024), SPH_C32(0x8dec7d1b), + SPH_C32(0x8f946a65) }, + { SPH_C32(0xe1c20000), SPH_C32(0x52920000), SPH_C32(0x79701680), + SPH_C32(0xade00000), SPH_C32(0x4cfc0a97), SPH_C32(0xd0dd5812), + SPH_C32(0x716b2d12), SPH_C32(0xd5d948f2), SPH_C32(0xd25a0000), + SPH_C32(0x7bac0000), SPH_C32(0x37410600), SPH_C32(0x4c740000), + SPH_C32(0xa7971461), SPH_C32(0x733b5d56), SPH_C32(0xa4e050d3), + SPH_C32(0x52f0ce90) }, + { SPH_C32(0xb3920000), SPH_C32(0x7bc60000), SPH_C32(0x131116ce), + SPH_C32(0x5d1f0000), SPH_C32(0xd6cd747b), SPH_C32(0x95fe19dc), + SPH_C32(0xbe3da2f7), SPH_C32(0x86da5bfd), SPH_C32(0x81d70000), + SPH_C32(0xd2500000), SPH_C32(0xa9b60606), SPH_C32(0x1a8b0000), + SPH_C32(0xad73142f), SPH_C32(0xe1fe90af), SPH_C32(0x0da410cb), + SPH_C32(0x2d679801) }, + { SPH_C32(0xb24f0000), SPH_C32(0xfb6e0000), SPH_C32(0xe7871686), + SPH_C32(0xfb1f0000), SPH_C32(0x46180ad9), SPH_C32(0x421895eb), + SPH_C32(0xd82f6d0a), SPH_C32(0xaa4e1e63), SPH_C32(0xd3870000), + SPH_C32(0xfb040000), SPH_C32(0xc3d70648), SPH_C32(0xea740000), + SPH_C32(0x37426ac3), SPH_C32(0xa4ddd161), SPH_C32(0xc2f29f2e), + SPH_C32(0x7e648b0e) }, + { SPH_C32(0xe01f0000), SPH_C32(0xd23a0000), SPH_C32(0x8de616c8), + SPH_C32(0x0be00000), SPH_C32(0xdc297435), SPH_C32(0x073bd425), + SPH_C32(0x1779e2ef), SPH_C32(0xf94d0d6c), SPH_C32(0x800a0000), + SPH_C32(0x52f80000), SPH_C32(0x5d20064e), SPH_C32(0xbc8b0000), + SPH_C32(0x3da66a8d), SPH_C32(0x36181c98), SPH_C32(0x6bb6df36), + SPH_C32(0x01f3dd9f) }, + { SPH_C32(0xd46b0000), SPH_C32(0x095a0000), SPH_C32(0xecc11800), + SPH_C32(0x93e60000), SPH_C32(0x2bbb1913), SPH_C32(0x615bd992), + SPH_C32(0x0efe679c), SPH_C32(0xf28bf35d), SPH_C32(0x1ce10000), + SPH_C32(0x69e70000), SPH_C32(0xd7e40280), SPH_C32(0x21bc0000), + SPH_C32(0x56ca424d), SPH_C32(0x74e8af29), SPH_C32(0x64ff0c88), + SPH_C32(0x6c5ca315) }, + { SPH_C32(0x863b0000), SPH_C32(0x200e0000), SPH_C32(0x86a0184e), + SPH_C32(0x63190000), SPH_C32(0xb18a67ff), SPH_C32(0x2478985c), + SPH_C32(0xc1a8e879), SPH_C32(0xa188e052), SPH_C32(0x4f6c0000), + SPH_C32(0xc01b0000), SPH_C32(0x49130286), SPH_C32(0x77430000), + SPH_C32(0x5c2e4203), SPH_C32(0xe62d62d0), SPH_C32(0xcdbb4c90), + SPH_C32(0x13cbf584) }, + { SPH_C32(0x87e60000), SPH_C32(0xa0a60000), SPH_C32(0x72361806), + SPH_C32(0xc5190000), SPH_C32(0x215f195d), SPH_C32(0xf39e146b), + SPH_C32(0xa7ba2784), SPH_C32(0x8d1ca5cc), SPH_C32(0x1d3c0000), + SPH_C32(0xe94f0000), SPH_C32(0x237202c8), SPH_C32(0x87bc0000), + SPH_C32(0xc61f3cef), SPH_C32(0xa30e231e), SPH_C32(0x02edc375), + SPH_C32(0x40c8e68b) }, + { SPH_C32(0xd5b60000), SPH_C32(0x89f20000), SPH_C32(0x18571848), + SPH_C32(0x35e60000), SPH_C32(0xbb6e67b1), SPH_C32(0xb6bd55a5), + SPH_C32(0x68eca861), SPH_C32(0xde1fb6c3), SPH_C32(0x4eb10000), + SPH_C32(0x40b30000), SPH_C32(0xbd8502ce), SPH_C32(0xd1430000), + SPH_C32(0xccfb3ca1), SPH_C32(0x31cbeee7), SPH_C32(0xaba9836d), + SPH_C32(0x3f5fb01a) }, + { SPH_C32(0x187f0000), SPH_C32(0xac390000), SPH_C32(0xb6781f80), + SPH_C32(0xa8b60000), SPH_C32(0x606b0aec), SPH_C32(0xe6c0ed8a), + SPH_C32(0x67bd2f5d), SPH_C32(0x38d174a3), SPH_C32(0x9d7f0000), + SPH_C32(0x85b00000), SPH_C32(0xb1d60000), SPH_C32(0xb44f0000), + SPH_C32(0x0b636a4f), SPH_C32(0x3c1c9395), SPH_C32(0x82a5aea5), + SPH_C32(0xe23b14ef) }, + { SPH_C32(0x4a2f0000), SPH_C32(0x856d0000), SPH_C32(0xdc191fce), + SPH_C32(0x58490000), SPH_C32(0xfa5a7400), SPH_C32(0xa3e3ac44), + SPH_C32(0xa8eba0b8), SPH_C32(0x6bd267ac), SPH_C32(0xcef20000), + SPH_C32(0x2c4c0000), SPH_C32(0x2f210006), SPH_C32(0xe2b00000), + SPH_C32(0x01876a01), SPH_C32(0xaed95e6c), SPH_C32(0x2be1eebd), + SPH_C32(0x9dac427e) }, + { SPH_C32(0x4bf20000), SPH_C32(0x05c50000), SPH_C32(0x288f1f86), + SPH_C32(0xfe490000), SPH_C32(0x6a8f0aa2), SPH_C32(0x74052073), + SPH_C32(0xcef96f45), SPH_C32(0x47462232), SPH_C32(0x9ca20000), + SPH_C32(0x05180000), SPH_C32(0x45400048), SPH_C32(0x124f0000), + SPH_C32(0x9bb614ed), SPH_C32(0xebfa1fa2), SPH_C32(0xe4b76158), + SPH_C32(0xceaf5171) }, + { SPH_C32(0x19a20000), SPH_C32(0x2c910000), SPH_C32(0x42ee1fc8), + SPH_C32(0x0eb60000), SPH_C32(0xf0be744e), SPH_C32(0x312661bd), + SPH_C32(0x01afe0a0), SPH_C32(0x1445313d), SPH_C32(0xcf2f0000), + SPH_C32(0xace40000), SPH_C32(0xdbb7004e), SPH_C32(0x44b00000), + SPH_C32(0x915214a3), SPH_C32(0x793fd25b), SPH_C32(0x4df32140), + SPH_C32(0xb13807e0) }, + { SPH_C32(0x55f50000), SPH_C32(0xe50d0000), SPH_C32(0x8af31a80), + SPH_C32(0x06150000), SPH_C32(0x76123111), SPH_C32(0x29afe52e), + SPH_C32(0xe8a4c5b1), SPH_C32(0x7cec44a7), SPH_C32(0x516b0000), + SPH_C32(0x20d30000), SPH_C32(0xeb6f0780), SPH_C32(0x8f1f0000), + SPH_C32(0x40b379b0), SPH_C32(0xbb87a78d), SPH_C32(0xebe6e664), + SPH_C32(0x28619311) }, + { SPH_C32(0x07a50000), SPH_C32(0xcc590000), SPH_C32(0xe0921ace), + SPH_C32(0xf6ea0000), SPH_C32(0xec234ffd), SPH_C32(0x6c8ca4e0), + SPH_C32(0x27f24a54), SPH_C32(0x2fef57a8), SPH_C32(0x02e60000), + SPH_C32(0x892f0000), SPH_C32(0x75980786), SPH_C32(0xd9e00000), + SPH_C32(0x4a5779fe), SPH_C32(0x29426a74), SPH_C32(0x42a2a67c), + SPH_C32(0x57f6c580) }, + { SPH_C32(0x06780000), SPH_C32(0x4cf10000), SPH_C32(0x14041a86), + SPH_C32(0x50ea0000), SPH_C32(0x7cf6315f), SPH_C32(0xbb6a28d7), + SPH_C32(0x41e085a9), SPH_C32(0x037b1236), SPH_C32(0x50b60000), + SPH_C32(0xa07b0000), SPH_C32(0x1ff907c8), SPH_C32(0x291f0000), + SPH_C32(0xd0660712), SPH_C32(0x6c612bba), SPH_C32(0x8df42999), + SPH_C32(0x04f5d68f) }, + { SPH_C32(0x54280000), SPH_C32(0x65a50000), SPH_C32(0x7e651ac8), + SPH_C32(0xa0150000), SPH_C32(0xe6c74fb3), SPH_C32(0xfe496919), + SPH_C32(0x8eb60a4c), SPH_C32(0x50780139), SPH_C32(0x033b0000), + SPH_C32(0x09870000), SPH_C32(0x810e07ce), SPH_C32(0x7fe00000), + SPH_C32(0xda82075c), SPH_C32(0xfea4e643), SPH_C32(0x24b06981), + SPH_C32(0x7b62801e) }, + { SPH_C32(0x99e10000), SPH_C32(0x406e0000), SPH_C32(0xd04a1d00), + SPH_C32(0x3d450000), SPH_C32(0x3dc222ee), SPH_C32(0xae34d136), + SPH_C32(0x81e78d70), SPH_C32(0xb6b6c359), SPH_C32(0xd0f50000), + SPH_C32(0xcc840000), SPH_C32(0x8d5d0500), SPH_C32(0x1aec0000), + SPH_C32(0x1d1a51b2), SPH_C32(0xf3739b31), SPH_C32(0x0dbc4449), + SPH_C32(0xa60624eb) }, + { SPH_C32(0xcbb10000), SPH_C32(0x693a0000), SPH_C32(0xba2b1d4e), + SPH_C32(0xcdba0000), SPH_C32(0xa7f35c02), SPH_C32(0xeb1790f8), + SPH_C32(0x4eb10295), SPH_C32(0xe5b5d056), SPH_C32(0x83780000), + SPH_C32(0x65780000), SPH_C32(0x13aa0506), SPH_C32(0x4c130000), + SPH_C32(0x17fe51fc), SPH_C32(0x61b656c8), SPH_C32(0xa4f80451), + SPH_C32(0xd991727a) }, + { SPH_C32(0xca6c0000), SPH_C32(0xe9920000), SPH_C32(0x4ebd1d06), + SPH_C32(0x6bba0000), SPH_C32(0x372622a0), SPH_C32(0x3cf11ccf), + SPH_C32(0x28a3cd68), SPH_C32(0xc92195c8), SPH_C32(0xd1280000), + SPH_C32(0x4c2c0000), SPH_C32(0x79cb0548), SPH_C32(0xbcec0000), + SPH_C32(0x8dcf2f10), SPH_C32(0x24951706), SPH_C32(0x6bae8bb4), + SPH_C32(0x8a926175) }, + { SPH_C32(0x983c0000), SPH_C32(0xc0c60000), SPH_C32(0x24dc1d48), + SPH_C32(0x9b450000), SPH_C32(0xad175c4c), SPH_C32(0x79d25d01), + SPH_C32(0xe7f5428d), SPH_C32(0x9a2286c7), SPH_C32(0x82a50000), + SPH_C32(0xe5d00000), SPH_C32(0xe73c054e), SPH_C32(0xea130000), + SPH_C32(0x872b2f5e), SPH_C32(0xb650daff), SPH_C32(0xc2eacbac), + SPH_C32(0xf50537e4) }, + { SPH_C32(0xaee70000), SPH_C32(0xac8e0000), SPH_C32(0xffe71080), + SPH_C32(0x55db0000), SPH_C32(0xe00874b9), SPH_C32(0x9ffa96d1), + SPH_C32(0x572ed364), SPH_C32(0x6512928d), SPH_C32(0x64c20000), + SPH_C32(0x7b1b0000), SPH_C32(0x7ede0900), SPH_C32(0xb1190000), + SPH_C32(0x27f46a34), SPH_C32(0x0a01260d), SPH_C32(0x9473acea), + SPH_C32(0x0f3328be) }, + { SPH_C32(0xfcb70000), SPH_C32(0x85da0000), SPH_C32(0x958610ce), + SPH_C32(0xa5240000), SPH_C32(0x7a390a55), SPH_C32(0xdad9d71f), + SPH_C32(0x98785c81), SPH_C32(0x36118182), SPH_C32(0x374f0000), + SPH_C32(0xd2e70000), SPH_C32(0xe0290906), SPH_C32(0xe7e60000), + SPH_C32(0x2d106a7a), SPH_C32(0x98c4ebf4), SPH_C32(0x3d37ecf2), + SPH_C32(0x70a47e2f) }, + { SPH_C32(0xfd6a0000), SPH_C32(0x05720000), SPH_C32(0x61101086), + SPH_C32(0x03240000), SPH_C32(0xeaec74f7), SPH_C32(0x0d3f5b28), + SPH_C32(0xfe6a937c), SPH_C32(0x1a85c41c), SPH_C32(0x651f0000), + SPH_C32(0xfbb30000), SPH_C32(0x8a480948), SPH_C32(0x17190000), + SPH_C32(0xb7211496), SPH_C32(0xdde7aa3a), SPH_C32(0xf2616317), + SPH_C32(0x23a76d20) }, + { SPH_C32(0xaf3a0000), SPH_C32(0x2c260000), SPH_C32(0x0b7110c8), + SPH_C32(0xf3db0000), SPH_C32(0x70dd0a1b), SPH_C32(0x481c1ae6), + SPH_C32(0x313c1c99), SPH_C32(0x4986d713), SPH_C32(0x36920000), + SPH_C32(0x524f0000), SPH_C32(0x14bf094e), SPH_C32(0x41e60000), + SPH_C32(0xbdc514d8), SPH_C32(0x4f2267c3), SPH_C32(0x5b25230f), + SPH_C32(0x5c303bb1) }, + { SPH_C32(0x62f30000), SPH_C32(0x09ed0000), SPH_C32(0xa55e1700), + SPH_C32(0x6e8b0000), SPH_C32(0xabd86746), SPH_C32(0x1861a2c9), + SPH_C32(0x3e6d9ba5), SPH_C32(0xaf481573), SPH_C32(0xe55c0000), + SPH_C32(0x974c0000), SPH_C32(0x18ec0b80), SPH_C32(0x24ea0000), + SPH_C32(0x7a5d4236), SPH_C32(0x42f51ab1), SPH_C32(0x72290ec7), + SPH_C32(0x81549f44) }, + { SPH_C32(0x30a30000), SPH_C32(0x20b90000), SPH_C32(0xcf3f174e), + SPH_C32(0x9e740000), SPH_C32(0x31e919aa), SPH_C32(0x5d42e307), + SPH_C32(0xf13b1440), SPH_C32(0xfc4b067c), SPH_C32(0xb6d10000), + SPH_C32(0x3eb00000), SPH_C32(0x861b0b86), SPH_C32(0x72150000), + SPH_C32(0x70b94278), SPH_C32(0xd030d748), SPH_C32(0xdb6d4edf), + SPH_C32(0xfec3c9d5) }, + { SPH_C32(0x317e0000), SPH_C32(0xa0110000), SPH_C32(0x3ba91706), + SPH_C32(0x38740000), SPH_C32(0xa13c6708), SPH_C32(0x8aa46f30), + SPH_C32(0x9729dbbd), SPH_C32(0xd0df43e2), SPH_C32(0xe4810000), + SPH_C32(0x17e40000), SPH_C32(0xec7a0bc8), SPH_C32(0x82ea0000), + SPH_C32(0xea883c94), SPH_C32(0x95139686), SPH_C32(0x143bc13a), + SPH_C32(0xadc0dada) }, + { SPH_C32(0x632e0000), SPH_C32(0x89450000), SPH_C32(0x51c81748), + SPH_C32(0xc88b0000), SPH_C32(0x3b0d19e4), SPH_C32(0xcf872efe), + SPH_C32(0x587f5458), SPH_C32(0x83dc50ed), SPH_C32(0xb70c0000), + SPH_C32(0xbe180000), SPH_C32(0x728d0bce), SPH_C32(0xd4150000), + SPH_C32(0xe06c3cda), SPH_C32(0x07d65b7f), SPH_C32(0xbd7f8122), + SPH_C32(0xd2578c4b) }, + { SPH_C32(0x2f790000), SPH_C32(0x40d90000), SPH_C32(0x99d51200), + SPH_C32(0xc0280000), SPH_C32(0xbda15cbb), SPH_C32(0xd70eaa6d), + SPH_C32(0xb1747149), SPH_C32(0xeb752577), SPH_C32(0x29480000), + SPH_C32(0x322f0000), SPH_C32(0x42550c00), SPH_C32(0x1fba0000), + SPH_C32(0x318d51c9), SPH_C32(0xc56e2ea9), SPH_C32(0x1b6a4606), + SPH_C32(0x4b0e18ba) }, + { SPH_C32(0x7d290000), SPH_C32(0x698d0000), SPH_C32(0xf3b4124e), + SPH_C32(0x30d70000), SPH_C32(0x27902257), SPH_C32(0x922deba3), + SPH_C32(0x7e22feac), SPH_C32(0xb8763678), SPH_C32(0x7ac50000), + SPH_C32(0x9bd30000), SPH_C32(0xdca20c06), SPH_C32(0x49450000), + SPH_C32(0x3b695187), SPH_C32(0x57abe350), SPH_C32(0xb22e061e), + SPH_C32(0x34994e2b) }, + { SPH_C32(0x7cf40000), SPH_C32(0xe9250000), SPH_C32(0x07221206), + SPH_C32(0x96d70000), SPH_C32(0xb7455cf5), SPH_C32(0x45cb6794), + SPH_C32(0x18303151), SPH_C32(0x94e273e6), SPH_C32(0x28950000), + SPH_C32(0xb2870000), SPH_C32(0xb6c30c48), SPH_C32(0xb9ba0000), + SPH_C32(0xa1582f6b), SPH_C32(0x1288a29e), SPH_C32(0x7d7889fb), + SPH_C32(0x679a5d24) }, + { SPH_C32(0x2ea40000), SPH_C32(0xc0710000), SPH_C32(0x6d431248), + SPH_C32(0x66280000), SPH_C32(0x2d742219), SPH_C32(0x00e8265a), + SPH_C32(0xd766beb4), SPH_C32(0xc7e160e9), SPH_C32(0x7b180000), + SPH_C32(0x1b7b0000), SPH_C32(0x28340c4e), SPH_C32(0xef450000), + SPH_C32(0xabbc2f25), SPH_C32(0x804d6f67), SPH_C32(0xd43cc9e3), + SPH_C32(0x180d0bb5) }, + { SPH_C32(0xe36d0000), SPH_C32(0xe5ba0000), SPH_C32(0xc36c1580), + SPH_C32(0xfb780000), SPH_C32(0xf6714f44), SPH_C32(0x50959e75), + SPH_C32(0xd8373988), SPH_C32(0x212fa289), SPH_C32(0xa8d60000), + SPH_C32(0xde780000), SPH_C32(0x24670e80), SPH_C32(0x8a490000), + SPH_C32(0x6c2479cb), SPH_C32(0x8d9a1215), SPH_C32(0xfd30e42b), + SPH_C32(0xc569af40) }, + { SPH_C32(0xb13d0000), SPH_C32(0xccee0000), SPH_C32(0xa90d15ce), + SPH_C32(0x0b870000), SPH_C32(0x6c4031a8), SPH_C32(0x15b6dfbb), + SPH_C32(0x1761b66d), SPH_C32(0x722cb186), SPH_C32(0xfb5b0000), + SPH_C32(0x77840000), SPH_C32(0xba900e86), SPH_C32(0xdcb60000), + SPH_C32(0x66c07985), SPH_C32(0x1f5fdfec), SPH_C32(0x5474a433), + SPH_C32(0xbafef9d1) }, + { SPH_C32(0xb0e00000), SPH_C32(0x4c460000), SPH_C32(0x5d9b1586), + SPH_C32(0xad870000), SPH_C32(0xfc954f0a), SPH_C32(0xc250538c), + SPH_C32(0x71737990), SPH_C32(0x5eb8f418), SPH_C32(0xa90b0000), + SPH_C32(0x5ed00000), SPH_C32(0xd0f10ec8), SPH_C32(0x2c490000), + SPH_C32(0xfcf10769), SPH_C32(0x5a7c9e22), SPH_C32(0x9b222bd6), + SPH_C32(0xe9fdeade) }, + { SPH_C32(0xe2b00000), SPH_C32(0x65120000), SPH_C32(0x37fa15c8), + SPH_C32(0x5d780000), SPH_C32(0x66a431e6), SPH_C32(0x87731242), + SPH_C32(0xbe25f675), SPH_C32(0x0dbbe717), SPH_C32(0xfa860000), + SPH_C32(0xf72c0000), SPH_C32(0x4e060ece), SPH_C32(0x7ab60000), + SPH_C32(0xf6150727), SPH_C32(0xc8b953db), SPH_C32(0x32666bce), + SPH_C32(0x966abc4f) }, + { SPH_C32(0xd6c40000), SPH_C32(0xbe720000), SPH_C32(0x56dd1b00), + SPH_C32(0xc57e0000), SPH_C32(0x91365cc0), SPH_C32(0xe1131ff5), + SPH_C32(0xa7a27306), SPH_C32(0x067d1926), SPH_C32(0x666d0000), + SPH_C32(0xcc330000), SPH_C32(0xc4c20a00), SPH_C32(0xe7810000), + SPH_C32(0x9d792fe7), SPH_C32(0x8a49e06a), SPH_C32(0x3d2fb870), + SPH_C32(0xfbc5c2c5) }, + { SPH_C32(0x84940000), SPH_C32(0x97260000), SPH_C32(0x3cbc1b4e), + SPH_C32(0x35810000), SPH_C32(0x0b07222c), SPH_C32(0xa4305e3b), + SPH_C32(0x68f4fce3), SPH_C32(0x557e0a29), SPH_C32(0x35e00000), + SPH_C32(0x65cf0000), SPH_C32(0x5a350a06), SPH_C32(0xb17e0000), + SPH_C32(0x979d2fa9), SPH_C32(0x188c2d93), SPH_C32(0x946bf868), + SPH_C32(0x84529454) }, + { SPH_C32(0x85490000), SPH_C32(0x178e0000), SPH_C32(0xc82a1b06), + SPH_C32(0x93810000), SPH_C32(0x9bd25c8e), SPH_C32(0x73d6d20c), + SPH_C32(0x0ee6331e), SPH_C32(0x79ea4fb7), SPH_C32(0x67b00000), + SPH_C32(0x4c9b0000), SPH_C32(0x30540a48), SPH_C32(0x41810000), + SPH_C32(0x0dac5145), SPH_C32(0x5daf6c5d), SPH_C32(0x5b3d778d), + SPH_C32(0xd751875b) }, + { SPH_C32(0xd7190000), SPH_C32(0x3eda0000), SPH_C32(0xa24b1b48), + SPH_C32(0x637e0000), SPH_C32(0x01e32262), SPH_C32(0x36f593c2), + SPH_C32(0xc1b0bcfb), SPH_C32(0x2ae95cb8), SPH_C32(0x343d0000), + SPH_C32(0xe5670000), SPH_C32(0xaea30a4e), SPH_C32(0x177e0000), + SPH_C32(0x0748510b), SPH_C32(0xcf6aa1a4), SPH_C32(0xf2793795), + SPH_C32(0xa8c6d1ca) }, + { SPH_C32(0x1ad00000), SPH_C32(0x1b110000), SPH_C32(0x0c641c80), + SPH_C32(0xfe2e0000), SPH_C32(0xdae64f3f), SPH_C32(0x66882bed), + SPH_C32(0xcee13bc7), SPH_C32(0xcc279ed8), SPH_C32(0xe7f30000), + SPH_C32(0x20640000), SPH_C32(0xa2f00880), SPH_C32(0x72720000), + SPH_C32(0xc0d007e5), SPH_C32(0xc2bddcd6), SPH_C32(0xdb751a5d), + SPH_C32(0x75a2753f) }, + { SPH_C32(0x48800000), SPH_C32(0x32450000), SPH_C32(0x66051cce), + SPH_C32(0x0ed10000), SPH_C32(0x40d731d3), SPH_C32(0x23ab6a23), + SPH_C32(0x01b7b422), SPH_C32(0x9f248dd7), SPH_C32(0xb47e0000), + SPH_C32(0x89980000), SPH_C32(0x3c070886), SPH_C32(0x248d0000), + SPH_C32(0xca3407ab), SPH_C32(0x5078112f), SPH_C32(0x72315a45), + SPH_C32(0x0a3523ae) }, + { SPH_C32(0x495d0000), SPH_C32(0xb2ed0000), SPH_C32(0x92931c86), + SPH_C32(0xa8d10000), SPH_C32(0xd0024f71), SPH_C32(0xf44de614), + SPH_C32(0x67a57bdf), SPH_C32(0xb3b0c849), SPH_C32(0xe62e0000), + SPH_C32(0xa0cc0000), SPH_C32(0x566608c8), SPH_C32(0xd4720000), + SPH_C32(0x50057947), SPH_C32(0x155b50e1), SPH_C32(0xbd67d5a0), + SPH_C32(0x593630a1) }, + { SPH_C32(0x1b0d0000), SPH_C32(0x9bb90000), SPH_C32(0xf8f21cc8), + SPH_C32(0x582e0000), SPH_C32(0x4a33319d), SPH_C32(0xb16ea7da), + SPH_C32(0xa8f3f43a), SPH_C32(0xe0b3db46), SPH_C32(0xb5a30000), + SPH_C32(0x09300000), SPH_C32(0xc89108ce), SPH_C32(0x828d0000), + SPH_C32(0x5ae17909), SPH_C32(0x879e9d18), SPH_C32(0x142395b8), + SPH_C32(0x26a16630) }, + { SPH_C32(0x575a0000), SPH_C32(0x52250000), SPH_C32(0x30ef1980), + SPH_C32(0x508d0000), SPH_C32(0xcc9f74c2), SPH_C32(0xa9e72349), + SPH_C32(0x41f8d12b), SPH_C32(0x881aaedc), SPH_C32(0x2be70000), + SPH_C32(0x85070000), SPH_C32(0xf8490f00), SPH_C32(0x49220000), + SPH_C32(0x8b00141a), SPH_C32(0x4526e8ce), SPH_C32(0xb236529c), + SPH_C32(0xbff8f2c1) }, + { SPH_C32(0x050a0000), SPH_C32(0x7b710000), SPH_C32(0x5a8e19ce), + SPH_C32(0xa0720000), SPH_C32(0x56ae0a2e), SPH_C32(0xecc46287), + SPH_C32(0x8eae5ece), SPH_C32(0xdb19bdd3), SPH_C32(0x786a0000), + SPH_C32(0x2cfb0000), SPH_C32(0x66be0f06), SPH_C32(0x1fdd0000), + SPH_C32(0x81e41454), SPH_C32(0xd7e32537), SPH_C32(0x1b721284), + SPH_C32(0xc06fa450) }, + { SPH_C32(0x04d70000), SPH_C32(0xfbd90000), SPH_C32(0xae181986), + SPH_C32(0x06720000), SPH_C32(0xc67b748c), SPH_C32(0x3b22eeb0), + SPH_C32(0xe8bc9133), SPH_C32(0xf78df84d), SPH_C32(0x2a3a0000), + SPH_C32(0x05af0000), SPH_C32(0x0cdf0f48), SPH_C32(0xef220000), + SPH_C32(0x1bd56ab8), SPH_C32(0x92c064f9), SPH_C32(0xd4249d61), + SPH_C32(0x936cb75f) }, + { SPH_C32(0x56870000), SPH_C32(0xd28d0000), SPH_C32(0xc47919c8), + SPH_C32(0xf68d0000), SPH_C32(0x5c4a0a60), SPH_C32(0x7e01af7e), + SPH_C32(0x27ea1ed6), SPH_C32(0xa48eeb42), SPH_C32(0x79b70000), + SPH_C32(0xac530000), SPH_C32(0x92280f4e), SPH_C32(0xb9dd0000), + SPH_C32(0x11316af6), SPH_C32(0x0005a900), SPH_C32(0x7d60dd79), + SPH_C32(0xecfbe1ce) }, + { SPH_C32(0x9b4e0000), SPH_C32(0xf7460000), SPH_C32(0x6a561e00), + SPH_C32(0x6bdd0000), SPH_C32(0x874f673d), SPH_C32(0x2e7c1751), + SPH_C32(0x28bb99ea), SPH_C32(0x42402922), SPH_C32(0xaa790000), + SPH_C32(0x69500000), SPH_C32(0x9e7b0d80), SPH_C32(0xdcd10000), + SPH_C32(0xd6a93c18), SPH_C32(0x0dd2d472), SPH_C32(0x546cf0b1), + SPH_C32(0x319f453b) }, + { SPH_C32(0xc91e0000), SPH_C32(0xde120000), SPH_C32(0x00371e4e), + SPH_C32(0x9b220000), SPH_C32(0x1d7e19d1), SPH_C32(0x6b5f569f), + SPH_C32(0xe7ed160f), SPH_C32(0x11433a2d), SPH_C32(0xf9f40000), + SPH_C32(0xc0ac0000), SPH_C32(0x008c0d86), SPH_C32(0x8a2e0000), + SPH_C32(0xdc4d3c56), SPH_C32(0x9f17198b), SPH_C32(0xfd28b0a9), + SPH_C32(0x4e0813aa) }, + { SPH_C32(0xc8c30000), SPH_C32(0x5eba0000), SPH_C32(0xf4a11e06), + SPH_C32(0x3d220000), SPH_C32(0x8dab6773), SPH_C32(0xbcb9daa8), + SPH_C32(0x81ffd9f2), SPH_C32(0x3dd77fb3), SPH_C32(0xaba40000), + SPH_C32(0xe9f80000), SPH_C32(0x6aed0dc8), SPH_C32(0x7ad10000), + SPH_C32(0x467c42ba), SPH_C32(0xda345845), SPH_C32(0x327e3f4c), + SPH_C32(0x1d0b00a5) }, + { SPH_C32(0x9a930000), SPH_C32(0x77ee0000), SPH_C32(0x9ec01e48), + SPH_C32(0xcddd0000), SPH_C32(0x179a199f), SPH_C32(0xf99a9b66), + SPH_C32(0x4ea95617), SPH_C32(0x6ed46cbc), SPH_C32(0xf8290000), + SPH_C32(0x40040000), SPH_C32(0xf41a0dce), SPH_C32(0x2c2e0000), + SPH_C32(0x4c9842f4), SPH_C32(0x48f195bc), SPH_C32(0x9b3a7f54), + SPH_C32(0x629c5634) } +}; + +static const sph_u32 T512_42[128][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0x92560000), SPH_C32(0x1eda0000), SPH_C32(0xea510000), + SPH_C32(0xe8b13000), SPH_C32(0xa93556a5), SPH_C32(0xebfb6199), + SPH_C32(0xb15c2254), SPH_C32(0x33c5244f), SPH_C32(0x8c3a0000), + SPH_C32(0xda980000), SPH_C32(0x607f0000), SPH_C32(0x54078800), + SPH_C32(0x85714513), SPH_C32(0x6006b243), SPH_C32(0xdb50399c), + SPH_C32(0x8a58e6a4) }, + { SPH_C32(0x58430000), SPH_C32(0x807e0000), SPH_C32(0x78330001), + SPH_C32(0xc66b3800), SPH_C32(0xe7375cdc), SPH_C32(0x79ad3fdd), + SPH_C32(0xac73fe6f), SPH_C32(0x3a4479b1), SPH_C32(0x1d5a0000), + SPH_C32(0x2b720000), SPH_C32(0x488d0000), SPH_C32(0xaf611800), + SPH_C32(0x25cb2ec5), SPH_C32(0xc879bfd0), SPH_C32(0x81a20429), + SPH_C32(0x1e7536a6) }, + { SPH_C32(0xca150000), SPH_C32(0x9ea40000), SPH_C32(0x92620001), + SPH_C32(0x2eda0800), SPH_C32(0x4e020a79), SPH_C32(0x92565e44), + SPH_C32(0x1d2fdc3b), SPH_C32(0x09815dfe), SPH_C32(0x91600000), + SPH_C32(0xf1ea0000), SPH_C32(0x28f20000), SPH_C32(0xfb669000), + SPH_C32(0xa0ba6bd6), SPH_C32(0xa87f0d93), SPH_C32(0x5af23db5), + SPH_C32(0x942dd002) }, + { SPH_C32(0x1d5a0000), SPH_C32(0x2b720000), SPH_C32(0x488d0000), + SPH_C32(0xaf611800), SPH_C32(0x25cb2ec5), SPH_C32(0xc879bfd0), + SPH_C32(0x81a20429), SPH_C32(0x1e7536a6), SPH_C32(0x45190000), + SPH_C32(0xab0c0000), SPH_C32(0x30be0001), SPH_C32(0x690a2000), + SPH_C32(0xc2fc7219), SPH_C32(0xb1d4800d), SPH_C32(0x2dd1fa46), + SPH_C32(0x24314f17) }, + { SPH_C32(0x8f0c0000), SPH_C32(0x35a80000), SPH_C32(0xa2dc0000), + SPH_C32(0x47d02800), SPH_C32(0x8cfe7860), SPH_C32(0x2382de49), + SPH_C32(0x30fe267d), SPH_C32(0x2db012e9), SPH_C32(0xc9230000), + SPH_C32(0x71940000), SPH_C32(0x50c10001), SPH_C32(0x3d0da800), + SPH_C32(0x478d370a), SPH_C32(0xd1d2324e), SPH_C32(0xf681c3da), + SPH_C32(0xae69a9b3) }, + { SPH_C32(0x45190000), SPH_C32(0xab0c0000), SPH_C32(0x30be0001), + SPH_C32(0x690a2000), SPH_C32(0xc2fc7219), SPH_C32(0xb1d4800d), + SPH_C32(0x2dd1fa46), SPH_C32(0x24314f17), SPH_C32(0x58430000), + SPH_C32(0x807e0000), SPH_C32(0x78330001), SPH_C32(0xc66b3800), + SPH_C32(0xe7375cdc), SPH_C32(0x79ad3fdd), SPH_C32(0xac73fe6f), + SPH_C32(0x3a4479b1) }, + { SPH_C32(0xd74f0000), SPH_C32(0xb5d60000), SPH_C32(0xdaef0001), + SPH_C32(0x81bb1000), SPH_C32(0x6bc924bc), SPH_C32(0x5a2fe194), + SPH_C32(0x9c8dd812), SPH_C32(0x17f46b58), SPH_C32(0xd4790000), + SPH_C32(0x5ae60000), SPH_C32(0x184c0001), SPH_C32(0x926cb000), + SPH_C32(0x624619cf), SPH_C32(0x19ab8d9e), SPH_C32(0x7723c7f3), + SPH_C32(0xb01c9f15) }, + { SPH_C32(0xa53b0000), SPH_C32(0x14260000), SPH_C32(0x4e30001e), + SPH_C32(0x7cae0000), SPH_C32(0x8f9e0dd5), SPH_C32(0x78dfaa3d), + SPH_C32(0xf73168d8), SPH_C32(0x0b1b4946), SPH_C32(0x07ed0000), + SPH_C32(0xb2500000), SPH_C32(0x8774000a), SPH_C32(0x970d0000), + SPH_C32(0x437223ae), SPH_C32(0x48c76ea4), SPH_C32(0xf4786222), + SPH_C32(0x9075b1ce) }, + { SPH_C32(0x376d0000), SPH_C32(0x0afc0000), SPH_C32(0xa461001e), + SPH_C32(0x941f3000), SPH_C32(0x26ab5b70), SPH_C32(0x9324cba4), + SPH_C32(0x466d4a8c), SPH_C32(0x38de6d09), SPH_C32(0x8bd70000), + SPH_C32(0x68c80000), SPH_C32(0xe70b000a), SPH_C32(0xc30a8800), + SPH_C32(0xc60366bd), SPH_C32(0x28c1dce7), SPH_C32(0x2f285bbe), + SPH_C32(0x1a2d576a) }, + { SPH_C32(0xfd780000), SPH_C32(0x94580000), SPH_C32(0x3603001f), + SPH_C32(0xbac53800), SPH_C32(0x68a95109), SPH_C32(0x017295e0), + SPH_C32(0x5b4296b7), SPH_C32(0x315f30f7), SPH_C32(0x1ab70000), + SPH_C32(0x99220000), SPH_C32(0xcff9000a), SPH_C32(0x386c1800), + SPH_C32(0x66b90d6b), SPH_C32(0x80bed174), SPH_C32(0x75da660b), + SPH_C32(0x8e008768) }, + { SPH_C32(0x6f2e0000), SPH_C32(0x8a820000), SPH_C32(0xdc52001f), + SPH_C32(0x52740800), SPH_C32(0xc19c07ac), SPH_C32(0xea89f479), + SPH_C32(0xea1eb4e3), SPH_C32(0x029a14b8), SPH_C32(0x968d0000), + SPH_C32(0x43ba0000), SPH_C32(0xaf86000a), SPH_C32(0x6c6b9000), + SPH_C32(0xe3c84878), SPH_C32(0xe0b86337), SPH_C32(0xae8a5f97), + SPH_C32(0x045861cc) }, + { SPH_C32(0xb8610000), SPH_C32(0x3f540000), SPH_C32(0x06bd001e), + SPH_C32(0xd3cf1800), SPH_C32(0xaa552310), SPH_C32(0xb0a615ed), + SPH_C32(0x76936cf1), SPH_C32(0x156e7fe0), SPH_C32(0x42f40000), + SPH_C32(0x195c0000), SPH_C32(0xb7ca000b), SPH_C32(0xfe072000), + SPH_C32(0x818e51b7), SPH_C32(0xf913eea9), SPH_C32(0xd9a99864), + SPH_C32(0xb444fed9) }, + { SPH_C32(0x2a370000), SPH_C32(0x218e0000), SPH_C32(0xecec001e), + SPH_C32(0x3b7e2800), SPH_C32(0x036075b5), SPH_C32(0x5b5d7474), + SPH_C32(0xc7cf4ea5), SPH_C32(0x26ab5baf), SPH_C32(0xcece0000), + SPH_C32(0xc3c40000), SPH_C32(0xd7b5000b), SPH_C32(0xaa00a800), + SPH_C32(0x04ff14a4), SPH_C32(0x99155cea), SPH_C32(0x02f9a1f8), + SPH_C32(0x3e1c187d) }, + { SPH_C32(0xe0220000), SPH_C32(0xbf2a0000), SPH_C32(0x7e8e001f), + SPH_C32(0x15a42000), SPH_C32(0x4d627fcc), SPH_C32(0xc90b2a30), + SPH_C32(0xdae0929e), SPH_C32(0x2f2a0651), SPH_C32(0x5fae0000), + SPH_C32(0x322e0000), SPH_C32(0xff47000b), SPH_C32(0x51663800), + SPH_C32(0xa4457f72), SPH_C32(0x316a5179), SPH_C32(0x580b9c4d), + SPH_C32(0xaa31c87f) }, + { SPH_C32(0x72740000), SPH_C32(0xa1f00000), SPH_C32(0x94df001f), + SPH_C32(0xfd151000), SPH_C32(0xe4572969), SPH_C32(0x22f04ba9), + SPH_C32(0x6bbcb0ca), SPH_C32(0x1cef221e), SPH_C32(0xd3940000), + SPH_C32(0xe8b60000), SPH_C32(0x9f38000b), SPH_C32(0x0561b000), + SPH_C32(0x21343a61), SPH_C32(0x516ce33a), SPH_C32(0x835ba5d1), + SPH_C32(0x20692edb) }, + { SPH_C32(0x07ed0000), SPH_C32(0xb2500000), SPH_C32(0x8774000a), + SPH_C32(0x970d0000), SPH_C32(0x437223ae), SPH_C32(0x48c76ea4), + SPH_C32(0xf4786222), SPH_C32(0x9075b1ce), SPH_C32(0xa2d60000), + SPH_C32(0xa6760000), SPH_C32(0xc9440014), SPH_C32(0xeba30000), + SPH_C32(0xccec2e7b), SPH_C32(0x3018c499), SPH_C32(0x03490afa), + SPH_C32(0x9b6ef888) }, + { SPH_C32(0x95bb0000), SPH_C32(0xac8a0000), SPH_C32(0x6d25000a), + SPH_C32(0x7fbc3000), SPH_C32(0xea47750b), SPH_C32(0xa33c0f3d), + SPH_C32(0x45244076), SPH_C32(0xa3b09581), SPH_C32(0x2eec0000), + SPH_C32(0x7cee0000), SPH_C32(0xa93b0014), SPH_C32(0xbfa48800), + SPH_C32(0x499d6b68), SPH_C32(0x501e76da), SPH_C32(0xd8193366), + SPH_C32(0x11361e2c) }, + { SPH_C32(0x5fae0000), SPH_C32(0x322e0000), SPH_C32(0xff47000b), + SPH_C32(0x51663800), SPH_C32(0xa4457f72), SPH_C32(0x316a5179), + SPH_C32(0x580b9c4d), SPH_C32(0xaa31c87f), SPH_C32(0xbf8c0000), + SPH_C32(0x8d040000), SPH_C32(0x81c90014), SPH_C32(0x44c21800), + SPH_C32(0xe92700be), SPH_C32(0xf8617b49), SPH_C32(0x82eb0ed3), + SPH_C32(0x851bce2e) }, + { SPH_C32(0xcdf80000), SPH_C32(0x2cf40000), SPH_C32(0x1516000b), + SPH_C32(0xb9d70800), SPH_C32(0x0d7029d7), SPH_C32(0xda9130e0), + SPH_C32(0xe957be19), SPH_C32(0x99f4ec30), SPH_C32(0x33b60000), + SPH_C32(0x579c0000), SPH_C32(0xe1b60014), SPH_C32(0x10c59000), + SPH_C32(0x6c5645ad), SPH_C32(0x9867c90a), SPH_C32(0x59bb374f), + SPH_C32(0x0f43288a) }, + { SPH_C32(0x1ab70000), SPH_C32(0x99220000), SPH_C32(0xcff9000a), + SPH_C32(0x386c1800), SPH_C32(0x66b90d6b), SPH_C32(0x80bed174), + SPH_C32(0x75da660b), SPH_C32(0x8e008768), SPH_C32(0xe7cf0000), + SPH_C32(0x0d7a0000), SPH_C32(0xf9fa0015), SPH_C32(0x82a92000), + SPH_C32(0x0e105c62), SPH_C32(0x81cc4494), SPH_C32(0x2e98f0bc), + SPH_C32(0xbf5fb79f) }, + { SPH_C32(0x88e10000), SPH_C32(0x87f80000), SPH_C32(0x25a8000a), + SPH_C32(0xd0dd2800), SPH_C32(0xcf8c5bce), SPH_C32(0x6b45b0ed), + SPH_C32(0xc486445f), SPH_C32(0xbdc5a327), SPH_C32(0x6bf50000), + SPH_C32(0xd7e20000), SPH_C32(0x99850015), SPH_C32(0xd6aea800), + SPH_C32(0x8b611971), SPH_C32(0xe1caf6d7), SPH_C32(0xf5c8c920), + SPH_C32(0x3507513b) }, + { SPH_C32(0x42f40000), SPH_C32(0x195c0000), SPH_C32(0xb7ca000b), + SPH_C32(0xfe072000), SPH_C32(0x818e51b7), SPH_C32(0xf913eea9), + SPH_C32(0xd9a99864), SPH_C32(0xb444fed9), SPH_C32(0xfa950000), + SPH_C32(0x26080000), SPH_C32(0xb1770015), SPH_C32(0x2dc83800), + SPH_C32(0x2bdb72a7), SPH_C32(0x49b5fb44), SPH_C32(0xaf3af495), + SPH_C32(0xa12a8139) }, + { SPH_C32(0xd0a20000), SPH_C32(0x07860000), SPH_C32(0x5d9b000b), + SPH_C32(0x16b61000), SPH_C32(0x28bb0712), SPH_C32(0x12e88f30), + SPH_C32(0x68f5ba30), SPH_C32(0x8781da96), SPH_C32(0x76af0000), + SPH_C32(0xfc900000), SPH_C32(0xd1080015), SPH_C32(0x79cfb000), + SPH_C32(0xaeaa37b4), SPH_C32(0x29b34907), SPH_C32(0x746acd09), + SPH_C32(0x2b72679d) }, + { SPH_C32(0xa2d60000), SPH_C32(0xa6760000), SPH_C32(0xc9440014), + SPH_C32(0xeba30000), SPH_C32(0xccec2e7b), SPH_C32(0x3018c499), + SPH_C32(0x03490afa), SPH_C32(0x9b6ef888), SPH_C32(0xa53b0000), + SPH_C32(0x14260000), SPH_C32(0x4e30001e), SPH_C32(0x7cae0000), + SPH_C32(0x8f9e0dd5), SPH_C32(0x78dfaa3d), SPH_C32(0xf73168d8), + SPH_C32(0x0b1b4946) }, + { SPH_C32(0x30800000), SPH_C32(0xb8ac0000), SPH_C32(0x23150014), + SPH_C32(0x03123000), SPH_C32(0x65d978de), SPH_C32(0xdbe3a500), + SPH_C32(0xb21528ae), SPH_C32(0xa8abdcc7), SPH_C32(0x29010000), + SPH_C32(0xcebe0000), SPH_C32(0x2e4f001e), SPH_C32(0x28a98800), + SPH_C32(0x0aef48c6), SPH_C32(0x18d9187e), SPH_C32(0x2c615144), + SPH_C32(0x8143afe2) }, + { SPH_C32(0xfa950000), SPH_C32(0x26080000), SPH_C32(0xb1770015), + SPH_C32(0x2dc83800), SPH_C32(0x2bdb72a7), SPH_C32(0x49b5fb44), + SPH_C32(0xaf3af495), SPH_C32(0xa12a8139), SPH_C32(0xb8610000), + SPH_C32(0x3f540000), SPH_C32(0x06bd001e), SPH_C32(0xd3cf1800), + SPH_C32(0xaa552310), SPH_C32(0xb0a615ed), SPH_C32(0x76936cf1), + SPH_C32(0x156e7fe0) }, + { SPH_C32(0x68c30000), SPH_C32(0x38d20000), SPH_C32(0x5b260015), + SPH_C32(0xc5790800), SPH_C32(0x82ee2402), SPH_C32(0xa24e9add), + SPH_C32(0x1e66d6c1), SPH_C32(0x92efa576), SPH_C32(0x345b0000), + SPH_C32(0xe5cc0000), SPH_C32(0x66c2001e), SPH_C32(0x87c89000), + SPH_C32(0x2f246603), SPH_C32(0xd0a0a7ae), SPH_C32(0xadc3556d), + SPH_C32(0x9f369944) }, + { SPH_C32(0xbf8c0000), SPH_C32(0x8d040000), SPH_C32(0x81c90014), + SPH_C32(0x44c21800), SPH_C32(0xe92700be), SPH_C32(0xf8617b49), + SPH_C32(0x82eb0ed3), SPH_C32(0x851bce2e), SPH_C32(0xe0220000), + SPH_C32(0xbf2a0000), SPH_C32(0x7e8e001f), SPH_C32(0x15a42000), + SPH_C32(0x4d627fcc), SPH_C32(0xc90b2a30), SPH_C32(0xdae0929e), + SPH_C32(0x2f2a0651) }, + { SPH_C32(0x2dda0000), SPH_C32(0x93de0000), SPH_C32(0x6b980014), + SPH_C32(0xac732800), SPH_C32(0x4012561b), SPH_C32(0x139a1ad0), + SPH_C32(0x33b72c87), SPH_C32(0xb6deea61), SPH_C32(0x6c180000), + SPH_C32(0x65b20000), SPH_C32(0x1ef1001f), SPH_C32(0x41a3a800), + SPH_C32(0xc8133adf), SPH_C32(0xa90d9873), SPH_C32(0x01b0ab02), + SPH_C32(0xa572e0f5) }, + { SPH_C32(0xe7cf0000), SPH_C32(0x0d7a0000), SPH_C32(0xf9fa0015), + SPH_C32(0x82a92000), SPH_C32(0x0e105c62), SPH_C32(0x81cc4494), + SPH_C32(0x2e98f0bc), SPH_C32(0xbf5fb79f), SPH_C32(0xfd780000), + SPH_C32(0x94580000), SPH_C32(0x3603001f), SPH_C32(0xbac53800), + SPH_C32(0x68a95109), SPH_C32(0x017295e0), SPH_C32(0x5b4296b7), + SPH_C32(0x315f30f7) }, + { SPH_C32(0x75990000), SPH_C32(0x13a00000), SPH_C32(0x13ab0015), + SPH_C32(0x6a181000), SPH_C32(0xa7250ac7), SPH_C32(0x6a37250d), + SPH_C32(0x9fc4d2e8), SPH_C32(0x8c9a93d0), SPH_C32(0x71420000), + SPH_C32(0x4ec00000), SPH_C32(0x567c001f), SPH_C32(0xeec2b000), + SPH_C32(0xedd8141a), SPH_C32(0x617427a3), SPH_C32(0x8012af2b), + SPH_C32(0xbb07d653) }, + { SPH_C32(0x88980000), SPH_C32(0x1f940000), SPH_C32(0x7fcf002e), + SPH_C32(0xfb4e0000), SPH_C32(0xf158079a), SPH_C32(0x61ae9167), + SPH_C32(0xa895706c), SPH_C32(0xe6107494), SPH_C32(0x0bc20000), + SPH_C32(0xdb630000), SPH_C32(0x7e88000c), SPH_C32(0x15860000), + SPH_C32(0x91fd48f3), SPH_C32(0x7581bb43), SPH_C32(0xf460449e), + SPH_C32(0xd8b61463) }, + { SPH_C32(0x1ace0000), SPH_C32(0x014e0000), SPH_C32(0x959e002e), + SPH_C32(0x13ff3000), SPH_C32(0x586d513f), SPH_C32(0x8a55f0fe), + SPH_C32(0x19c95238), SPH_C32(0xd5d550db), SPH_C32(0x87f80000), + SPH_C32(0x01fb0000), SPH_C32(0x1ef7000c), SPH_C32(0x41818800), + SPH_C32(0x148c0de0), SPH_C32(0x15870900), SPH_C32(0x2f307d02), + SPH_C32(0x52eef2c7) }, + { SPH_C32(0xd0db0000), SPH_C32(0x9fea0000), SPH_C32(0x07fc002f), + SPH_C32(0x3d253800), SPH_C32(0x166f5b46), SPH_C32(0x1803aeba), + SPH_C32(0x04e68e03), SPH_C32(0xdc540d25), SPH_C32(0x16980000), + SPH_C32(0xf0110000), SPH_C32(0x3605000c), SPH_C32(0xbae71800), + SPH_C32(0xb4366636), SPH_C32(0xbdf80493), SPH_C32(0x75c240b7), + SPH_C32(0xc6c322c5) }, + { SPH_C32(0x428d0000), SPH_C32(0x81300000), SPH_C32(0xedad002f), + SPH_C32(0xd5940800), SPH_C32(0xbf5a0de3), SPH_C32(0xf3f8cf23), + SPH_C32(0xb5baac57), SPH_C32(0xef91296a), SPH_C32(0x9aa20000), + SPH_C32(0x2a890000), SPH_C32(0x567a000c), SPH_C32(0xeee09000), + SPH_C32(0x31472325), SPH_C32(0xddfeb6d0), SPH_C32(0xae92792b), + SPH_C32(0x4c9bc461) }, + { SPH_C32(0x95c20000), SPH_C32(0x34e60000), SPH_C32(0x3742002e), + SPH_C32(0x542f1800), SPH_C32(0xd493295f), SPH_C32(0xa9d72eb7), + SPH_C32(0x29377445), SPH_C32(0xf8654232), SPH_C32(0x4edb0000), + SPH_C32(0x706f0000), SPH_C32(0x4e36000d), SPH_C32(0x7c8c2000), + SPH_C32(0x53013aea), SPH_C32(0xc4553b4e), SPH_C32(0xd9b1bed8), + SPH_C32(0xfc875b74) }, + { SPH_C32(0x07940000), SPH_C32(0x2a3c0000), SPH_C32(0xdd13002e), + SPH_C32(0xbc9e2800), SPH_C32(0x7da67ffa), SPH_C32(0x422c4f2e), + SPH_C32(0x986b5611), SPH_C32(0xcba0667d), SPH_C32(0xc2e10000), + SPH_C32(0xaaf70000), SPH_C32(0x2e49000d), SPH_C32(0x288ba800), + SPH_C32(0xd6707ff9), SPH_C32(0xa453890d), SPH_C32(0x02e18744), + SPH_C32(0x76dfbdd0) }, + { SPH_C32(0xcd810000), SPH_C32(0xb4980000), SPH_C32(0x4f71002f), + SPH_C32(0x92442000), SPH_C32(0x33a47583), SPH_C32(0xd07a116a), + SPH_C32(0x85448a2a), SPH_C32(0xc2213b83), SPH_C32(0x53810000), + SPH_C32(0x5b1d0000), SPH_C32(0x06bb000d), SPH_C32(0xd3ed3800), + SPH_C32(0x76ca142f), SPH_C32(0x0c2c849e), SPH_C32(0x5813baf1), + SPH_C32(0xe2f26dd2) }, + { SPH_C32(0x5fd70000), SPH_C32(0xaa420000), SPH_C32(0xa520002f), + SPH_C32(0x7af51000), SPH_C32(0x9a912326), SPH_C32(0x3b8170f3), + SPH_C32(0x3418a87e), SPH_C32(0xf1e41fcc), SPH_C32(0xdfbb0000), + SPH_C32(0x81850000), SPH_C32(0x66c4000d), SPH_C32(0x87eab000), + SPH_C32(0xf3bb513c), SPH_C32(0x6c2a36dd), SPH_C32(0x8343836d), + SPH_C32(0x68aa8b76) }, + { SPH_C32(0x2da30000), SPH_C32(0x0bb20000), SPH_C32(0x31ff0030), + SPH_C32(0x87e00000), SPH_C32(0x7ec60a4f), SPH_C32(0x19713b5a), + SPH_C32(0x5fa418b4), SPH_C32(0xed0b3dd2), SPH_C32(0x0c2f0000), + SPH_C32(0x69330000), SPH_C32(0xf9fc0006), SPH_C32(0x828b0000), + SPH_C32(0xd28f6b5d), SPH_C32(0x3d46d5e7), SPH_C32(0x001826bc), + SPH_C32(0x48c3a5ad) }, + { SPH_C32(0xbff50000), SPH_C32(0x15680000), SPH_C32(0xdbae0030), + SPH_C32(0x6f513000), SPH_C32(0xd7f35cea), SPH_C32(0xf28a5ac3), + SPH_C32(0xeef83ae0), SPH_C32(0xdece199d), SPH_C32(0x80150000), + SPH_C32(0xb3ab0000), SPH_C32(0x99830006), SPH_C32(0xd68c8800), + SPH_C32(0x57fe2e4e), SPH_C32(0x5d4067a4), SPH_C32(0xdb481f20), + SPH_C32(0xc29b4309) }, + { SPH_C32(0x75e00000), SPH_C32(0x8bcc0000), SPH_C32(0x49cc0031), + SPH_C32(0x418b3800), SPH_C32(0x99f15693), SPH_C32(0x60dc0487), + SPH_C32(0xf3d7e6db), SPH_C32(0xd74f4463), SPH_C32(0x11750000), + SPH_C32(0x42410000), SPH_C32(0xb1710006), SPH_C32(0x2dea1800), + SPH_C32(0xf7444598), SPH_C32(0xf53f6a37), SPH_C32(0x81ba2295), + SPH_C32(0x56b6930b) }, + { SPH_C32(0xe7b60000), SPH_C32(0x95160000), SPH_C32(0xa39d0031), + SPH_C32(0xa93a0800), SPH_C32(0x30c40036), SPH_C32(0x8b27651e), + SPH_C32(0x428bc48f), SPH_C32(0xe48a602c), SPH_C32(0x9d4f0000), + SPH_C32(0x98d90000), SPH_C32(0xd10e0006), SPH_C32(0x79ed9000), + SPH_C32(0x7235008b), SPH_C32(0x9539d874), SPH_C32(0x5aea1b09), + SPH_C32(0xdcee75af) }, + { SPH_C32(0x30f90000), SPH_C32(0x20c00000), SPH_C32(0x79720030), + SPH_C32(0x28811800), SPH_C32(0x5b0d248a), SPH_C32(0xd108848a), + SPH_C32(0xde061c9d), SPH_C32(0xf37e0b74), SPH_C32(0x49360000), + SPH_C32(0xc23f0000), SPH_C32(0xc9420007), SPH_C32(0xeb812000), + SPH_C32(0x10731944), SPH_C32(0x8c9255ea), SPH_C32(0x2dc9dcfa), + SPH_C32(0x6cf2eaba) }, + { SPH_C32(0xa2af0000), SPH_C32(0x3e1a0000), SPH_C32(0x93230030), + SPH_C32(0xc0302800), SPH_C32(0xf238722f), SPH_C32(0x3af3e513), + SPH_C32(0x6f5a3ec9), SPH_C32(0xc0bb2f3b), SPH_C32(0xc50c0000), + SPH_C32(0x18a70000), SPH_C32(0xa93d0007), SPH_C32(0xbf86a800), + SPH_C32(0x95025c57), SPH_C32(0xec94e7a9), SPH_C32(0xf699e566), + SPH_C32(0xe6aa0c1e) }, + { SPH_C32(0x68ba0000), SPH_C32(0xa0be0000), SPH_C32(0x01410031), + SPH_C32(0xeeea2000), SPH_C32(0xbc3a7856), SPH_C32(0xa8a5bb57), + SPH_C32(0x7275e2f2), SPH_C32(0xc93a72c5), SPH_C32(0x546c0000), + SPH_C32(0xe94d0000), SPH_C32(0x81cf0007), SPH_C32(0x44e03800), + SPH_C32(0x35b83781), SPH_C32(0x44ebea3a), SPH_C32(0xac6bd8d3), + SPH_C32(0x7287dc1c) }, + { SPH_C32(0xfaec0000), SPH_C32(0xbe640000), SPH_C32(0xeb100031), + SPH_C32(0x065b1000), SPH_C32(0x150f2ef3), SPH_C32(0x435edace), + SPH_C32(0xc329c0a6), SPH_C32(0xfaff568a), SPH_C32(0xd8560000), + SPH_C32(0x33d50000), SPH_C32(0xe1b00007), SPH_C32(0x10e7b000), + SPH_C32(0xb0c97292), SPH_C32(0x24ed5879), SPH_C32(0x773be14f), + SPH_C32(0xf8df3ab8) }, + { SPH_C32(0x8f750000), SPH_C32(0xadc40000), SPH_C32(0xf8bb0024), + SPH_C32(0x6c430000), SPH_C32(0xb22a2434), SPH_C32(0x2969ffc3), + SPH_C32(0x5ced124e), SPH_C32(0x7665c55a), SPH_C32(0xa9140000), + SPH_C32(0x7d150000), SPH_C32(0xb7cc0018), SPH_C32(0xfe250000), + SPH_C32(0x5d116688), SPH_C32(0x45997fda), SPH_C32(0xf7294e64), + SPH_C32(0x43d8eceb) }, + { SPH_C32(0x1d230000), SPH_C32(0xb31e0000), SPH_C32(0x12ea0024), + SPH_C32(0x84f23000), SPH_C32(0x1b1f7291), SPH_C32(0xc2929e5a), + SPH_C32(0xedb1301a), SPH_C32(0x45a0e115), SPH_C32(0x252e0000), + SPH_C32(0xa78d0000), SPH_C32(0xd7b30018), SPH_C32(0xaa228800), + SPH_C32(0xd860239b), SPH_C32(0x259fcd99), SPH_C32(0x2c7977f8), + SPH_C32(0xc9800a4f) }, + { SPH_C32(0xd7360000), SPH_C32(0x2dba0000), SPH_C32(0x80880025), + SPH_C32(0xaa283800), SPH_C32(0x551d78e8), SPH_C32(0x50c4c01e), + SPH_C32(0xf09eec21), SPH_C32(0x4c21bceb), SPH_C32(0xb44e0000), + SPH_C32(0x56670000), SPH_C32(0xff410018), SPH_C32(0x51441800), + SPH_C32(0x78da484d), SPH_C32(0x8de0c00a), SPH_C32(0x768b4a4d), + SPH_C32(0x5dadda4d) }, + { SPH_C32(0x45600000), SPH_C32(0x33600000), SPH_C32(0x6ad90025), + SPH_C32(0x42990800), SPH_C32(0xfc282e4d), SPH_C32(0xbb3fa187), + SPH_C32(0x41c2ce75), SPH_C32(0x7fe498a4), SPH_C32(0x38740000), + SPH_C32(0x8cff0000), SPH_C32(0x9f3e0018), SPH_C32(0x05439000), + SPH_C32(0xfdab0d5e), SPH_C32(0xede67249), SPH_C32(0xaddb73d1), + SPH_C32(0xd7f53ce9) }, + { SPH_C32(0x922f0000), SPH_C32(0x86b60000), SPH_C32(0xb0360024), + SPH_C32(0xc3221800), SPH_C32(0x97e10af1), SPH_C32(0xe1104013), + SPH_C32(0xdd4f1667), SPH_C32(0x6810f3fc), SPH_C32(0xec0d0000), + SPH_C32(0xd6190000), SPH_C32(0x87720019), SPH_C32(0x972f2000), + SPH_C32(0x9fed1491), SPH_C32(0xf44dffd7), SPH_C32(0xdaf8b422), + SPH_C32(0x67e9a3fc) }, + { SPH_C32(0x00790000), SPH_C32(0x986c0000), SPH_C32(0x5a670024), + SPH_C32(0x2b932800), SPH_C32(0x3ed45c54), SPH_C32(0x0aeb218a), + SPH_C32(0x6c133433), SPH_C32(0x5bd5d7b3), SPH_C32(0x60370000), + SPH_C32(0x0c810000), SPH_C32(0xe70d0019), SPH_C32(0xc328a800), + SPH_C32(0x1a9c5182), SPH_C32(0x944b4d94), SPH_C32(0x01a88dbe), + SPH_C32(0xedb14558) }, + { SPH_C32(0xca6c0000), SPH_C32(0x06c80000), SPH_C32(0xc8050025), + SPH_C32(0x05492000), SPH_C32(0x70d6562d), SPH_C32(0x98bd7fce), + SPH_C32(0x713ce808), SPH_C32(0x52548a4d), SPH_C32(0xf1570000), + SPH_C32(0xfd6b0000), SPH_C32(0xcfff0019), SPH_C32(0x384e3800), + SPH_C32(0xba263a54), SPH_C32(0x3c344007), SPH_C32(0x5b5ab00b), + SPH_C32(0x799c955a) }, + { SPH_C32(0x583a0000), SPH_C32(0x18120000), SPH_C32(0x22540025), + SPH_C32(0xedf81000), SPH_C32(0xd9e30088), SPH_C32(0x73461e57), + SPH_C32(0xc060ca5c), SPH_C32(0x6191ae02), SPH_C32(0x7d6d0000), + SPH_C32(0x27f30000), SPH_C32(0xaf800019), SPH_C32(0x6c49b000), + SPH_C32(0x3f577f47), SPH_C32(0x5c32f244), SPH_C32(0x800a8997), + SPH_C32(0xf3c473fe) }, + { SPH_C32(0x2a4e0000), SPH_C32(0xb9e20000), SPH_C32(0xb68b003a), + SPH_C32(0x10ed0000), SPH_C32(0x3db429e1), SPH_C32(0x51b655fe), + SPH_C32(0xabdc7a96), SPH_C32(0x7d7e8c1c), SPH_C32(0xaef90000), + SPH_C32(0xcf450000), SPH_C32(0x30b80012), SPH_C32(0x69280000), + SPH_C32(0x1e634526), SPH_C32(0x0d5e117e), SPH_C32(0x03512c46), + SPH_C32(0xd3ad5d25) }, + { SPH_C32(0xb8180000), SPH_C32(0xa7380000), SPH_C32(0x5cda003a), + SPH_C32(0xf85c3000), SPH_C32(0x94817f44), SPH_C32(0xba4d3467), + SPH_C32(0x1a8058c2), SPH_C32(0x4ebba853), SPH_C32(0x22c30000), + SPH_C32(0x15dd0000), SPH_C32(0x50c70012), SPH_C32(0x3d2f8800), + SPH_C32(0x9b120035), SPH_C32(0x6d58a33d), SPH_C32(0xd80115da), + SPH_C32(0x59f5bb81) }, + { SPH_C32(0x720d0000), SPH_C32(0x399c0000), SPH_C32(0xceb8003b), + SPH_C32(0xd6863800), SPH_C32(0xda83753d), SPH_C32(0x281b6a23), + SPH_C32(0x07af84f9), SPH_C32(0x473af5ad), SPH_C32(0xb3a30000), + SPH_C32(0xe4370000), SPH_C32(0x78350012), SPH_C32(0xc6491800), + SPH_C32(0x3ba86be3), SPH_C32(0xc527aeae), SPH_C32(0x82f3286f), + SPH_C32(0xcdd86b83) }, + { SPH_C32(0xe05b0000), SPH_C32(0x27460000), SPH_C32(0x24e9003b), + SPH_C32(0x3e370800), SPH_C32(0x73b62398), SPH_C32(0xc3e00bba), + SPH_C32(0xb6f3a6ad), SPH_C32(0x74ffd1e2), SPH_C32(0x3f990000), + SPH_C32(0x3eaf0000), SPH_C32(0x184a0012), SPH_C32(0x924e9000), + SPH_C32(0xbed92ef0), SPH_C32(0xa5211ced), SPH_C32(0x59a311f3), + SPH_C32(0x47808d27) }, + { SPH_C32(0x37140000), SPH_C32(0x92900000), SPH_C32(0xfe06003a), + SPH_C32(0xbf8c1800), SPH_C32(0x187f0724), SPH_C32(0x99cfea2e), + SPH_C32(0x2a7e7ebf), SPH_C32(0x630bbaba), SPH_C32(0xebe00000), + SPH_C32(0x64490000), SPH_C32(0x00060013), SPH_C32(0x00222000), + SPH_C32(0xdc9f373f), SPH_C32(0xbc8a9173), SPH_C32(0x2e80d600), + SPH_C32(0xf79c1232) }, + { SPH_C32(0xa5420000), SPH_C32(0x8c4a0000), SPH_C32(0x1457003a), + SPH_C32(0x573d2800), SPH_C32(0xb14a5181), SPH_C32(0x72348bb7), + SPH_C32(0x9b225ceb), SPH_C32(0x50ce9ef5), SPH_C32(0x67da0000), + SPH_C32(0xbed10000), SPH_C32(0x60790013), SPH_C32(0x5425a800), + SPH_C32(0x59ee722c), SPH_C32(0xdc8c2330), SPH_C32(0xf5d0ef9c), + SPH_C32(0x7dc4f496) }, + { SPH_C32(0x6f570000), SPH_C32(0x12ee0000), SPH_C32(0x8635003b), + SPH_C32(0x79e72000), SPH_C32(0xff485bf8), SPH_C32(0xe062d5f3), + SPH_C32(0x860d80d0), SPH_C32(0x594fc30b), SPH_C32(0xf6ba0000), + SPH_C32(0x4f3b0000), SPH_C32(0x488b0013), SPH_C32(0xaf433800), + SPH_C32(0xf95419fa), SPH_C32(0x74f32ea3), SPH_C32(0xaf22d229), + SPH_C32(0xe9e92494) }, + { SPH_C32(0xfd010000), SPH_C32(0x0c340000), SPH_C32(0x6c64003b), + SPH_C32(0x91561000), SPH_C32(0x567d0d5d), SPH_C32(0x0b99b46a), + SPH_C32(0x3751a284), SPH_C32(0x6a8ae744), SPH_C32(0x7a800000), + SPH_C32(0x95a30000), SPH_C32(0x28f40013), SPH_C32(0xfb44b000), + SPH_C32(0x7c255ce9), SPH_C32(0x14f59ce0), SPH_C32(0x7472ebb5), + SPH_C32(0x63b1c230) }, + { SPH_C32(0x0bc20000), SPH_C32(0xdb630000), SPH_C32(0x7e88000c), + SPH_C32(0x15860000), SPH_C32(0x91fd48f3), SPH_C32(0x7581bb43), + SPH_C32(0xf460449e), SPH_C32(0xd8b61463), SPH_C32(0x835a0000), + SPH_C32(0xc4f70000), SPH_C32(0x01470022), SPH_C32(0xeec80000), + SPH_C32(0x60a54f69), SPH_C32(0x142f2a24), SPH_C32(0x5cf534f2), + SPH_C32(0x3ea660f7) }, + { SPH_C32(0x99940000), SPH_C32(0xc5b90000), SPH_C32(0x94d9000c), + SPH_C32(0xfd373000), SPH_C32(0x38c81e56), SPH_C32(0x9e7adada), + SPH_C32(0x453c66ca), SPH_C32(0xeb73302c), SPH_C32(0x0f600000), + SPH_C32(0x1e6f0000), SPH_C32(0x61380022), SPH_C32(0xbacf8800), + SPH_C32(0xe5d40a7a), SPH_C32(0x74299867), SPH_C32(0x87a50d6e), + SPH_C32(0xb4fe8653) }, + { SPH_C32(0x53810000), SPH_C32(0x5b1d0000), SPH_C32(0x06bb000d), + SPH_C32(0xd3ed3800), SPH_C32(0x76ca142f), SPH_C32(0x0c2c849e), + SPH_C32(0x5813baf1), SPH_C32(0xe2f26dd2), SPH_C32(0x9e000000), + SPH_C32(0xef850000), SPH_C32(0x49ca0022), SPH_C32(0x41a91800), + SPH_C32(0x456e61ac), SPH_C32(0xdc5695f4), SPH_C32(0xdd5730db), + SPH_C32(0x20d35651) }, + { SPH_C32(0xc1d70000), SPH_C32(0x45c70000), SPH_C32(0xecea000d), + SPH_C32(0x3b5c0800), SPH_C32(0xdfff428a), SPH_C32(0xe7d7e507), + SPH_C32(0xe94f98a5), SPH_C32(0xd137499d), SPH_C32(0x123a0000), + SPH_C32(0x351d0000), SPH_C32(0x29b50022), SPH_C32(0x15ae9000), + SPH_C32(0xc01f24bf), SPH_C32(0xbc5027b7), SPH_C32(0x06070947), + SPH_C32(0xaa8bb0f5) }, + { SPH_C32(0x16980000), SPH_C32(0xf0110000), SPH_C32(0x3605000c), + SPH_C32(0xbae71800), SPH_C32(0xb4366636), SPH_C32(0xbdf80493), + SPH_C32(0x75c240b7), SPH_C32(0xc6c322c5), SPH_C32(0xc6430000), + SPH_C32(0x6ffb0000), SPH_C32(0x31f90023), SPH_C32(0x87c22000), + SPH_C32(0xa2593d70), SPH_C32(0xa5fbaa29), SPH_C32(0x7124ceb4), + SPH_C32(0x1a972fe0) }, + { SPH_C32(0x84ce0000), SPH_C32(0xeecb0000), SPH_C32(0xdc54000c), + SPH_C32(0x52562800), SPH_C32(0x1d033093), SPH_C32(0x5603650a), + SPH_C32(0xc49e62e3), SPH_C32(0xf506068a), SPH_C32(0x4a790000), + SPH_C32(0xb5630000), SPH_C32(0x51860023), SPH_C32(0xd3c5a800), + SPH_C32(0x27287863), SPH_C32(0xc5fd186a), SPH_C32(0xaa74f728), + SPH_C32(0x90cfc944) }, + { SPH_C32(0x4edb0000), SPH_C32(0x706f0000), SPH_C32(0x4e36000d), + SPH_C32(0x7c8c2000), SPH_C32(0x53013aea), SPH_C32(0xc4553b4e), + SPH_C32(0xd9b1bed8), SPH_C32(0xfc875b74), SPH_C32(0xdb190000), + SPH_C32(0x44890000), SPH_C32(0x79740023), SPH_C32(0x28a33800), + SPH_C32(0x879213b5), SPH_C32(0x6d8215f9), SPH_C32(0xf086ca9d), + SPH_C32(0x04e21946) }, + { SPH_C32(0xdc8d0000), SPH_C32(0x6eb50000), SPH_C32(0xa467000d), + SPH_C32(0x943d1000), SPH_C32(0xfa346c4f), SPH_C32(0x2fae5ad7), + SPH_C32(0x68ed9c8c), SPH_C32(0xcf427f3b), SPH_C32(0x57230000), + SPH_C32(0x9e110000), SPH_C32(0x190b0023), SPH_C32(0x7ca4b000), + SPH_C32(0x02e356a6), SPH_C32(0x0d84a7ba), SPH_C32(0x2bd6f301), + SPH_C32(0x8ebaffe2) }, + { SPH_C32(0xaef90000), SPH_C32(0xcf450000), SPH_C32(0x30b80012), + SPH_C32(0x69280000), SPH_C32(0x1e634526), SPH_C32(0x0d5e117e), + SPH_C32(0x03512c46), SPH_C32(0xd3ad5d25), SPH_C32(0x84b70000), + SPH_C32(0x76a70000), SPH_C32(0x86330028), SPH_C32(0x79c50000), + SPH_C32(0x23d76cc7), SPH_C32(0x5ce84480), SPH_C32(0xa88d56d0), + SPH_C32(0xaed3d139) }, + { SPH_C32(0x3caf0000), SPH_C32(0xd19f0000), SPH_C32(0xdae90012), + SPH_C32(0x81993000), SPH_C32(0xb7561383), SPH_C32(0xe6a570e7), + SPH_C32(0xb20d0e12), SPH_C32(0xe068796a), SPH_C32(0x088d0000), + SPH_C32(0xac3f0000), SPH_C32(0xe64c0028), SPH_C32(0x2dc28800), + SPH_C32(0xa6a629d4), SPH_C32(0x3ceef6c3), SPH_C32(0x73dd6f4c), + SPH_C32(0x248b379d) }, + { SPH_C32(0xf6ba0000), SPH_C32(0x4f3b0000), SPH_C32(0x488b0013), + SPH_C32(0xaf433800), SPH_C32(0xf95419fa), SPH_C32(0x74f32ea3), + SPH_C32(0xaf22d229), SPH_C32(0xe9e92494), SPH_C32(0x99ed0000), + SPH_C32(0x5dd50000), SPH_C32(0xcebe0028), SPH_C32(0xd6a41800), + SPH_C32(0x061c4202), SPH_C32(0x9491fb50), SPH_C32(0x292f52f9), + SPH_C32(0xb0a6e79f) }, + { SPH_C32(0x64ec0000), SPH_C32(0x51e10000), SPH_C32(0xa2da0013), + SPH_C32(0x47f20800), SPH_C32(0x50614f5f), SPH_C32(0x9f084f3a), + SPH_C32(0x1e7ef07d), SPH_C32(0xda2c00db), SPH_C32(0x15d70000), + SPH_C32(0x874d0000), SPH_C32(0xaec10028), SPH_C32(0x82a39000), + SPH_C32(0x836d0711), SPH_C32(0xf4974913), SPH_C32(0xf27f6b65), + SPH_C32(0x3afe013b) }, + { SPH_C32(0xb3a30000), SPH_C32(0xe4370000), SPH_C32(0x78350012), + SPH_C32(0xc6491800), SPH_C32(0x3ba86be3), SPH_C32(0xc527aeae), + SPH_C32(0x82f3286f), SPH_C32(0xcdd86b83), SPH_C32(0xc1ae0000), + SPH_C32(0xddab0000), SPH_C32(0xb68d0029), SPH_C32(0x10cf2000), + SPH_C32(0xe12b1ede), SPH_C32(0xed3cc48d), SPH_C32(0x855cac96), + SPH_C32(0x8ae29e2e) }, + { SPH_C32(0x21f50000), SPH_C32(0xfaed0000), SPH_C32(0x92640012), + SPH_C32(0x2ef82800), SPH_C32(0x929d3d46), SPH_C32(0x2edccf37), + SPH_C32(0x33af0a3b), SPH_C32(0xfe1d4fcc), SPH_C32(0x4d940000), + SPH_C32(0x07330000), SPH_C32(0xd6f20029), SPH_C32(0x44c8a800), + SPH_C32(0x645a5bcd), SPH_C32(0x8d3a76ce), SPH_C32(0x5e0c950a), + SPH_C32(0x00ba788a) }, + { SPH_C32(0xebe00000), SPH_C32(0x64490000), SPH_C32(0x00060013), + SPH_C32(0x00222000), SPH_C32(0xdc9f373f), SPH_C32(0xbc8a9173), + SPH_C32(0x2e80d600), SPH_C32(0xf79c1232), SPH_C32(0xdcf40000), + SPH_C32(0xf6d90000), SPH_C32(0xfe000029), SPH_C32(0xbfae3800), + SPH_C32(0xc4e0301b), SPH_C32(0x25457b5d), SPH_C32(0x04fea8bf), + SPH_C32(0x9497a888) }, + { SPH_C32(0x79b60000), SPH_C32(0x7a930000), SPH_C32(0xea570013), + SPH_C32(0xe8931000), SPH_C32(0x75aa619a), SPH_C32(0x5771f0ea), + SPH_C32(0x9fdcf454), SPH_C32(0xc459367d), SPH_C32(0x50ce0000), + SPH_C32(0x2c410000), SPH_C32(0x9e7f0029), SPH_C32(0xeba9b000), + SPH_C32(0x41917508), SPH_C32(0x4543c91e), SPH_C32(0xdfae9123), + SPH_C32(0x1ecf4e2c) }, + { SPH_C32(0x0c2f0000), SPH_C32(0x69330000), SPH_C32(0xf9fc0006), + SPH_C32(0x828b0000), SPH_C32(0xd28f6b5d), SPH_C32(0x3d46d5e7), + SPH_C32(0x001826bc), SPH_C32(0x48c3a5ad), SPH_C32(0x218c0000), + SPH_C32(0x62810000), SPH_C32(0xc8030036), SPH_C32(0x056b0000), + SPH_C32(0xac496112), SPH_C32(0x2437eebd), SPH_C32(0x5fbc3e08), + SPH_C32(0xa5c8987f) }, + { SPH_C32(0x9e790000), SPH_C32(0x77e90000), SPH_C32(0x13ad0006), + SPH_C32(0x6a3a3000), SPH_C32(0x7bba3df8), SPH_C32(0xd6bdb47e), + SPH_C32(0xb14404e8), SPH_C32(0x7b0681e2), SPH_C32(0xadb60000), + SPH_C32(0xb8190000), SPH_C32(0xa87c0036), SPH_C32(0x516c8800), + SPH_C32(0x29382401), SPH_C32(0x44315cfe), SPH_C32(0x84ec0794), + SPH_C32(0x2f907edb) }, + { SPH_C32(0x546c0000), SPH_C32(0xe94d0000), SPH_C32(0x81cf0007), + SPH_C32(0x44e03800), SPH_C32(0x35b83781), SPH_C32(0x44ebea3a), + SPH_C32(0xac6bd8d3), SPH_C32(0x7287dc1c), SPH_C32(0x3cd60000), + SPH_C32(0x49f30000), SPH_C32(0x808e0036), SPH_C32(0xaa0a1800), + SPH_C32(0x89824fd7), SPH_C32(0xec4e516d), SPH_C32(0xde1e3a21), + SPH_C32(0xbbbdaed9) }, + { SPH_C32(0xc63a0000), SPH_C32(0xf7970000), SPH_C32(0x6b9e0007), + SPH_C32(0xac510800), SPH_C32(0x9c8d6124), SPH_C32(0xaf108ba3), + SPH_C32(0x1d37fa87), SPH_C32(0x4142f853), SPH_C32(0xb0ec0000), + SPH_C32(0x936b0000), SPH_C32(0xe0f10036), SPH_C32(0xfe0d9000), + SPH_C32(0x0cf30ac4), SPH_C32(0x8c48e32e), SPH_C32(0x054e03bd), + SPH_C32(0x31e5487d) }, + { SPH_C32(0x11750000), SPH_C32(0x42410000), SPH_C32(0xb1710006), + SPH_C32(0x2dea1800), SPH_C32(0xf7444598), SPH_C32(0xf53f6a37), + SPH_C32(0x81ba2295), SPH_C32(0x56b6930b), SPH_C32(0x64950000), + SPH_C32(0xc98d0000), SPH_C32(0xf8bd0037), SPH_C32(0x6c612000), + SPH_C32(0x6eb5130b), SPH_C32(0x95e36eb0), SPH_C32(0x726dc44e), + SPH_C32(0x81f9d768) }, + { SPH_C32(0x83230000), SPH_C32(0x5c9b0000), SPH_C32(0x5b200006), + SPH_C32(0xc55b2800), SPH_C32(0x5e71133d), SPH_C32(0x1ec40bae), + SPH_C32(0x30e600c1), SPH_C32(0x6573b744), SPH_C32(0xe8af0000), + SPH_C32(0x13150000), SPH_C32(0x98c20037), SPH_C32(0x3866a800), + SPH_C32(0xebc45618), SPH_C32(0xf5e5dcf3), SPH_C32(0xa93dfdd2), + SPH_C32(0x0ba131cc) }, + { SPH_C32(0x49360000), SPH_C32(0xc23f0000), SPH_C32(0xc9420007), + SPH_C32(0xeb812000), SPH_C32(0x10731944), SPH_C32(0x8c9255ea), + SPH_C32(0x2dc9dcfa), SPH_C32(0x6cf2eaba), SPH_C32(0x79cf0000), + SPH_C32(0xe2ff0000), SPH_C32(0xb0300037), SPH_C32(0xc3003800), + SPH_C32(0x4b7e3dce), SPH_C32(0x5d9ad160), SPH_C32(0xf3cfc067), + SPH_C32(0x9f8ce1ce) }, + { SPH_C32(0xdb600000), SPH_C32(0xdce50000), SPH_C32(0x23130007), + SPH_C32(0x03301000), SPH_C32(0xb9464fe1), SPH_C32(0x67693473), + SPH_C32(0x9c95feae), SPH_C32(0x5f37cef5), SPH_C32(0xf5f50000), + SPH_C32(0x38670000), SPH_C32(0xd04f0037), SPH_C32(0x9707b000), + SPH_C32(0xce0f78dd), SPH_C32(0x3d9c6323), SPH_C32(0x289ff9fb), + SPH_C32(0x15d4076a) }, + { SPH_C32(0xa9140000), SPH_C32(0x7d150000), SPH_C32(0xb7cc0018), + SPH_C32(0xfe250000), SPH_C32(0x5d116688), SPH_C32(0x45997fda), + SPH_C32(0xf7294e64), SPH_C32(0x43d8eceb), SPH_C32(0x26610000), + SPH_C32(0xd0d10000), SPH_C32(0x4f77003c), SPH_C32(0x92660000), + SPH_C32(0xef3b42bc), SPH_C32(0x6cf08019), SPH_C32(0xabc45c2a), + SPH_C32(0x35bd29b1) }, + { SPH_C32(0x3b420000), SPH_C32(0x63cf0000), SPH_C32(0x5d9d0018), + SPH_C32(0x16943000), SPH_C32(0xf424302d), SPH_C32(0xae621e43), + SPH_C32(0x46756c30), SPH_C32(0x701dc8a4), SPH_C32(0xaa5b0000), + SPH_C32(0x0a490000), SPH_C32(0x2f08003c), SPH_C32(0xc6618800), + SPH_C32(0x6a4a07af), SPH_C32(0x0cf6325a), SPH_C32(0x709465b6), + SPH_C32(0xbfe5cf15) }, + { SPH_C32(0xf1570000), SPH_C32(0xfd6b0000), SPH_C32(0xcfff0019), + SPH_C32(0x384e3800), SPH_C32(0xba263a54), SPH_C32(0x3c344007), + SPH_C32(0x5b5ab00b), SPH_C32(0x799c955a), SPH_C32(0x3b3b0000), + SPH_C32(0xfba30000), SPH_C32(0x07fa003c), SPH_C32(0x3d071800), + SPH_C32(0xcaf06c79), SPH_C32(0xa4893fc9), SPH_C32(0x2a665803), + SPH_C32(0x2bc81f17) }, + { SPH_C32(0x63010000), SPH_C32(0xe3b10000), SPH_C32(0x25ae0019), + SPH_C32(0xd0ff0800), SPH_C32(0x13136cf1), SPH_C32(0xd7cf219e), + SPH_C32(0xea06925f), SPH_C32(0x4a59b115), SPH_C32(0xb7010000), + SPH_C32(0x213b0000), SPH_C32(0x6785003c), SPH_C32(0x69009000), + SPH_C32(0x4f81296a), SPH_C32(0xc48f8d8a), SPH_C32(0xf136619f), + SPH_C32(0xa190f9b3) }, + { SPH_C32(0xb44e0000), SPH_C32(0x56670000), SPH_C32(0xff410018), + SPH_C32(0x51441800), SPH_C32(0x78da484d), SPH_C32(0x8de0c00a), + SPH_C32(0x768b4a4d), SPH_C32(0x5dadda4d), SPH_C32(0x63780000), + SPH_C32(0x7bdd0000), SPH_C32(0x7fc9003d), SPH_C32(0xfb6c2000), + SPH_C32(0x2dc730a5), SPH_C32(0xdd240014), SPH_C32(0x8615a66c), + SPH_C32(0x118c66a6) }, + { SPH_C32(0x26180000), SPH_C32(0x48bd0000), SPH_C32(0x15100018), + SPH_C32(0xb9f52800), SPH_C32(0xd1ef1ee8), SPH_C32(0x661ba193), + SPH_C32(0xc7d76819), SPH_C32(0x6e68fe02), SPH_C32(0xef420000), + SPH_C32(0xa1450000), SPH_C32(0x1fb6003d), SPH_C32(0xaf6ba800), + SPH_C32(0xa8b675b6), SPH_C32(0xbd22b257), SPH_C32(0x5d459ff0), + SPH_C32(0x9bd48002) }, + { SPH_C32(0xec0d0000), SPH_C32(0xd6190000), SPH_C32(0x87720019), + SPH_C32(0x972f2000), SPH_C32(0x9fed1491), SPH_C32(0xf44dffd7), + SPH_C32(0xdaf8b422), SPH_C32(0x67e9a3fc), SPH_C32(0x7e220000), + SPH_C32(0x50af0000), SPH_C32(0x3744003d), SPH_C32(0x540d3800), + SPH_C32(0x080c1e60), SPH_C32(0x155dbfc4), SPH_C32(0x07b7a245), + SPH_C32(0x0ff95000) }, + { SPH_C32(0x7e5b0000), SPH_C32(0xc8c30000), SPH_C32(0x6d230019), + SPH_C32(0x7f9e1000), SPH_C32(0x36d84234), SPH_C32(0x1fb69e4e), + SPH_C32(0x6ba49676), SPH_C32(0x542c87b3), SPH_C32(0xf2180000), + SPH_C32(0x8a370000), SPH_C32(0x573b003d), SPH_C32(0x000ab000), + SPH_C32(0x8d7d5b73), SPH_C32(0x755b0d87), SPH_C32(0xdce79bd9), + SPH_C32(0x85a1b6a4) }, + { SPH_C32(0x835a0000), SPH_C32(0xc4f70000), SPH_C32(0x01470022), + SPH_C32(0xeec80000), SPH_C32(0x60a54f69), SPH_C32(0x142f2a24), + SPH_C32(0x5cf534f2), SPH_C32(0x3ea660f7), SPH_C32(0x88980000), + SPH_C32(0x1f940000), SPH_C32(0x7fcf002e), SPH_C32(0xfb4e0000), + SPH_C32(0xf158079a), SPH_C32(0x61ae9167), SPH_C32(0xa895706c), + SPH_C32(0xe6107494) }, + { SPH_C32(0x110c0000), SPH_C32(0xda2d0000), SPH_C32(0xeb160022), + SPH_C32(0x06793000), SPH_C32(0xc99019cc), SPH_C32(0xffd44bbd), + SPH_C32(0xeda916a6), SPH_C32(0x0d6344b8), SPH_C32(0x04a20000), + SPH_C32(0xc50c0000), SPH_C32(0x1fb0002e), SPH_C32(0xaf498800), + SPH_C32(0x74294289), SPH_C32(0x01a82324), SPH_C32(0x73c549f0), + SPH_C32(0x6c489230) }, + { SPH_C32(0xdb190000), SPH_C32(0x44890000), SPH_C32(0x79740023), + SPH_C32(0x28a33800), SPH_C32(0x879213b5), SPH_C32(0x6d8215f9), + SPH_C32(0xf086ca9d), SPH_C32(0x04e21946), SPH_C32(0x95c20000), + SPH_C32(0x34e60000), SPH_C32(0x3742002e), SPH_C32(0x542f1800), + SPH_C32(0xd493295f), SPH_C32(0xa9d72eb7), SPH_C32(0x29377445), + SPH_C32(0xf8654232) }, + { SPH_C32(0x494f0000), SPH_C32(0x5a530000), SPH_C32(0x93250023), + SPH_C32(0xc0120800), SPH_C32(0x2ea74510), SPH_C32(0x86797460), + SPH_C32(0x41dae8c9), SPH_C32(0x37273d09), SPH_C32(0x19f80000), + SPH_C32(0xee7e0000), SPH_C32(0x573d002e), SPH_C32(0x00289000), + SPH_C32(0x51e26c4c), SPH_C32(0xc9d19cf4), SPH_C32(0xf2674dd9), + SPH_C32(0x723da496) }, + { SPH_C32(0x9e000000), SPH_C32(0xef850000), SPH_C32(0x49ca0022), + SPH_C32(0x41a91800), SPH_C32(0x456e61ac), SPH_C32(0xdc5695f4), + SPH_C32(0xdd5730db), SPH_C32(0x20d35651), SPH_C32(0xcd810000), + SPH_C32(0xb4980000), SPH_C32(0x4f71002f), SPH_C32(0x92442000), + SPH_C32(0x33a47583), SPH_C32(0xd07a116a), SPH_C32(0x85448a2a), + SPH_C32(0xc2213b83) }, + { SPH_C32(0x0c560000), SPH_C32(0xf15f0000), SPH_C32(0xa39b0022), + SPH_C32(0xa9182800), SPH_C32(0xec5b3709), SPH_C32(0x37adf46d), + SPH_C32(0x6c0b128f), SPH_C32(0x1316721e), SPH_C32(0x41bb0000), + SPH_C32(0x6e000000), SPH_C32(0x2f0e002f), SPH_C32(0xc643a800), + SPH_C32(0xb6d53090), SPH_C32(0xb07ca329), SPH_C32(0x5e14b3b6), + SPH_C32(0x4879dd27) }, + { SPH_C32(0xc6430000), SPH_C32(0x6ffb0000), SPH_C32(0x31f90023), + SPH_C32(0x87c22000), SPH_C32(0xa2593d70), SPH_C32(0xa5fbaa29), + SPH_C32(0x7124ceb4), SPH_C32(0x1a972fe0), SPH_C32(0xd0db0000), + SPH_C32(0x9fea0000), SPH_C32(0x07fc002f), SPH_C32(0x3d253800), + SPH_C32(0x166f5b46), SPH_C32(0x1803aeba), SPH_C32(0x04e68e03), + SPH_C32(0xdc540d25) }, + { SPH_C32(0x54150000), SPH_C32(0x71210000), SPH_C32(0xdba80023), + SPH_C32(0x6f731000), SPH_C32(0x0b6c6bd5), SPH_C32(0x4e00cbb0), + SPH_C32(0xc078ece0), SPH_C32(0x29520baf), SPH_C32(0x5ce10000), + SPH_C32(0x45720000), SPH_C32(0x6783002f), SPH_C32(0x6922b000), + SPH_C32(0x931e1e55), SPH_C32(0x78051cf9), SPH_C32(0xdfb6b79f), + SPH_C32(0x560ceb81) }, + { SPH_C32(0x26610000), SPH_C32(0xd0d10000), SPH_C32(0x4f77003c), + SPH_C32(0x92660000), SPH_C32(0xef3b42bc), SPH_C32(0x6cf08019), + SPH_C32(0xabc45c2a), SPH_C32(0x35bd29b1), SPH_C32(0x8f750000), + SPH_C32(0xadc40000), SPH_C32(0xf8bb0024), SPH_C32(0x6c430000), + SPH_C32(0xb22a2434), SPH_C32(0x2969ffc3), SPH_C32(0x5ced124e), + SPH_C32(0x7665c55a) }, + { SPH_C32(0xb4370000), SPH_C32(0xce0b0000), SPH_C32(0xa526003c), + SPH_C32(0x7ad73000), SPH_C32(0x460e1419), SPH_C32(0x870be180), + SPH_C32(0x1a987e7e), SPH_C32(0x06780dfe), SPH_C32(0x034f0000), + SPH_C32(0x775c0000), SPH_C32(0x98c40024), SPH_C32(0x38448800), + SPH_C32(0x375b6127), SPH_C32(0x496f4d80), SPH_C32(0x87bd2bd2), + SPH_C32(0xfc3d23fe) }, + { SPH_C32(0x7e220000), SPH_C32(0x50af0000), SPH_C32(0x3744003d), + SPH_C32(0x540d3800), SPH_C32(0x080c1e60), SPH_C32(0x155dbfc4), + SPH_C32(0x07b7a245), SPH_C32(0x0ff95000), SPH_C32(0x922f0000), + SPH_C32(0x86b60000), SPH_C32(0xb0360024), SPH_C32(0xc3221800), + SPH_C32(0x97e10af1), SPH_C32(0xe1104013), SPH_C32(0xdd4f1667), + SPH_C32(0x6810f3fc) }, + { SPH_C32(0xec740000), SPH_C32(0x4e750000), SPH_C32(0xdd15003d), + SPH_C32(0xbcbc0800), SPH_C32(0xa13948c5), SPH_C32(0xfea6de5d), + SPH_C32(0xb6eb8011), SPH_C32(0x3c3c744f), SPH_C32(0x1e150000), + SPH_C32(0x5c2e0000), SPH_C32(0xd0490024), SPH_C32(0x97259000), + SPH_C32(0x12904fe2), SPH_C32(0x8116f250), SPH_C32(0x061f2ffb), + SPH_C32(0xe2481558) }, + { SPH_C32(0x3b3b0000), SPH_C32(0xfba30000), SPH_C32(0x07fa003c), + SPH_C32(0x3d071800), SPH_C32(0xcaf06c79), SPH_C32(0xa4893fc9), + SPH_C32(0x2a665803), SPH_C32(0x2bc81f17), SPH_C32(0xca6c0000), + SPH_C32(0x06c80000), SPH_C32(0xc8050025), SPH_C32(0x05492000), + SPH_C32(0x70d6562d), SPH_C32(0x98bd7fce), SPH_C32(0x713ce808), + SPH_C32(0x52548a4d) }, + { SPH_C32(0xa96d0000), SPH_C32(0xe5790000), SPH_C32(0xedab003c), + SPH_C32(0xd5b62800), SPH_C32(0x63c53adc), SPH_C32(0x4f725e50), + SPH_C32(0x9b3a7a57), SPH_C32(0x180d3b58), SPH_C32(0x46560000), + SPH_C32(0xdc500000), SPH_C32(0xa87a0025), SPH_C32(0x514ea800), + SPH_C32(0xf5a7133e), SPH_C32(0xf8bbcd8d), SPH_C32(0xaa6cd194), + SPH_C32(0xd80c6ce9) }, + { SPH_C32(0x63780000), SPH_C32(0x7bdd0000), SPH_C32(0x7fc9003d), + SPH_C32(0xfb6c2000), SPH_C32(0x2dc730a5), SPH_C32(0xdd240014), + SPH_C32(0x8615a66c), SPH_C32(0x118c66a6), SPH_C32(0xd7360000), + SPH_C32(0x2dba0000), SPH_C32(0x80880025), SPH_C32(0xaa283800), + SPH_C32(0x551d78e8), SPH_C32(0x50c4c01e), SPH_C32(0xf09eec21), + SPH_C32(0x4c21bceb) }, + { SPH_C32(0xf12e0000), SPH_C32(0x65070000), SPH_C32(0x9598003d), + SPH_C32(0x13dd1000), SPH_C32(0x84f26600), SPH_C32(0x36df618d), + SPH_C32(0x37498438), SPH_C32(0x224942e9), SPH_C32(0x5b0c0000), + SPH_C32(0xf7220000), SPH_C32(0xe0f70025), SPH_C32(0xfe2fb000), + SPH_C32(0xd06c3dfb), SPH_C32(0x30c2725d), SPH_C32(0x2bced5bd), + SPH_C32(0xc6795a4f) }, + { SPH_C32(0x84b70000), SPH_C32(0x76a70000), SPH_C32(0x86330028), + SPH_C32(0x79c50000), SPH_C32(0x23d76cc7), SPH_C32(0x5ce84480), + SPH_C32(0xa88d56d0), SPH_C32(0xaed3d139), SPH_C32(0x2a4e0000), + SPH_C32(0xb9e20000), SPH_C32(0xb68b003a), SPH_C32(0x10ed0000), + SPH_C32(0x3db429e1), SPH_C32(0x51b655fe), SPH_C32(0xabdc7a96), + SPH_C32(0x7d7e8c1c) }, + { SPH_C32(0x16e10000), SPH_C32(0x687d0000), SPH_C32(0x6c620028), + SPH_C32(0x91743000), SPH_C32(0x8ae23a62), SPH_C32(0xb7132519), + SPH_C32(0x19d17484), SPH_C32(0x9d16f576), SPH_C32(0xa6740000), + SPH_C32(0x637a0000), SPH_C32(0xd6f4003a), SPH_C32(0x44ea8800), + SPH_C32(0xb8c56cf2), SPH_C32(0x31b0e7bd), SPH_C32(0x708c430a), + SPH_C32(0xf7266ab8) }, + { SPH_C32(0xdcf40000), SPH_C32(0xf6d90000), SPH_C32(0xfe000029), + SPH_C32(0xbfae3800), SPH_C32(0xc4e0301b), SPH_C32(0x25457b5d), + SPH_C32(0x04fea8bf), SPH_C32(0x9497a888), SPH_C32(0x37140000), + SPH_C32(0x92900000), SPH_C32(0xfe06003a), SPH_C32(0xbf8c1800), + SPH_C32(0x187f0724), SPH_C32(0x99cfea2e), SPH_C32(0x2a7e7ebf), + SPH_C32(0x630bbaba) }, + { SPH_C32(0x4ea20000), SPH_C32(0xe8030000), SPH_C32(0x14510029), + SPH_C32(0x571f0800), SPH_C32(0x6dd566be), SPH_C32(0xcebe1ac4), + SPH_C32(0xb5a28aeb), SPH_C32(0xa7528cc7), SPH_C32(0xbb2e0000), + SPH_C32(0x48080000), SPH_C32(0x9e79003a), SPH_C32(0xeb8b9000), + SPH_C32(0x9d0e4237), SPH_C32(0xf9c9586d), SPH_C32(0xf12e4723), + SPH_C32(0xe9535c1e) }, + { SPH_C32(0x99ed0000), SPH_C32(0x5dd50000), SPH_C32(0xcebe0028), + SPH_C32(0xd6a41800), SPH_C32(0x061c4202), SPH_C32(0x9491fb50), + SPH_C32(0x292f52f9), SPH_C32(0xb0a6e79f), SPH_C32(0x6f570000), + SPH_C32(0x12ee0000), SPH_C32(0x8635003b), SPH_C32(0x79e72000), + SPH_C32(0xff485bf8), SPH_C32(0xe062d5f3), SPH_C32(0x860d80d0), + SPH_C32(0x594fc30b) }, + { SPH_C32(0x0bbb0000), SPH_C32(0x430f0000), SPH_C32(0x24ef0028), + SPH_C32(0x3e152800), SPH_C32(0xaf2914a7), SPH_C32(0x7f6a9ac9), + SPH_C32(0x987370ad), SPH_C32(0x8363c3d0), SPH_C32(0xe36d0000), + SPH_C32(0xc8760000), SPH_C32(0xe64a003b), SPH_C32(0x2de0a800), + SPH_C32(0x7a391eeb), SPH_C32(0x806467b0), SPH_C32(0x5d5db94c), + SPH_C32(0xd31725af) }, + { SPH_C32(0xc1ae0000), SPH_C32(0xddab0000), SPH_C32(0xb68d0029), + SPH_C32(0x10cf2000), SPH_C32(0xe12b1ede), SPH_C32(0xed3cc48d), + SPH_C32(0x855cac96), SPH_C32(0x8ae29e2e), SPH_C32(0x720d0000), + SPH_C32(0x399c0000), SPH_C32(0xceb8003b), SPH_C32(0xd6863800), + SPH_C32(0xda83753d), SPH_C32(0x281b6a23), SPH_C32(0x07af84f9), + SPH_C32(0x473af5ad) }, + { SPH_C32(0x53f80000), SPH_C32(0xc3710000), SPH_C32(0x5cdc0029), + SPH_C32(0xf87e1000), SPH_C32(0x481e487b), SPH_C32(0x06c7a514), + SPH_C32(0x34008ec2), SPH_C32(0xb927ba61), SPH_C32(0xfe370000), + SPH_C32(0xe3040000), SPH_C32(0xaec7003b), SPH_C32(0x8281b000), + SPH_C32(0x5ff2302e), SPH_C32(0x481dd860), SPH_C32(0xdcffbd65), + SPH_C32(0xcd621309) }, + { SPH_C32(0x218c0000), SPH_C32(0x62810000), SPH_C32(0xc8030036), + SPH_C32(0x056b0000), SPH_C32(0xac496112), SPH_C32(0x2437eebd), + SPH_C32(0x5fbc3e08), SPH_C32(0xa5c8987f), SPH_C32(0x2da30000), + SPH_C32(0x0bb20000), SPH_C32(0x31ff0030), SPH_C32(0x87e00000), + SPH_C32(0x7ec60a4f), SPH_C32(0x19713b5a), SPH_C32(0x5fa418b4), + SPH_C32(0xed0b3dd2) }, + { SPH_C32(0xb3da0000), SPH_C32(0x7c5b0000), SPH_C32(0x22520036), + SPH_C32(0xedda3000), SPH_C32(0x057c37b7), SPH_C32(0xcfcc8f24), + SPH_C32(0xeee01c5c), SPH_C32(0x960dbc30), SPH_C32(0xa1990000), + SPH_C32(0xd12a0000), SPH_C32(0x51800030), SPH_C32(0xd3e78800), + SPH_C32(0xfbb74f5c), SPH_C32(0x79778919), SPH_C32(0x84f42128), + SPH_C32(0x6753db76) }, + { SPH_C32(0x79cf0000), SPH_C32(0xe2ff0000), SPH_C32(0xb0300037), + SPH_C32(0xc3003800), SPH_C32(0x4b7e3dce), SPH_C32(0x5d9ad160), + SPH_C32(0xf3cfc067), SPH_C32(0x9f8ce1ce), SPH_C32(0x30f90000), + SPH_C32(0x20c00000), SPH_C32(0x79720030), SPH_C32(0x28811800), + SPH_C32(0x5b0d248a), SPH_C32(0xd108848a), SPH_C32(0xde061c9d), + SPH_C32(0xf37e0b74) }, + { SPH_C32(0xeb990000), SPH_C32(0xfc250000), SPH_C32(0x5a610037), + SPH_C32(0x2bb10800), SPH_C32(0xe24b6b6b), SPH_C32(0xb661b0f9), + SPH_C32(0x4293e233), SPH_C32(0xac49c581), SPH_C32(0xbcc30000), + SPH_C32(0xfa580000), SPH_C32(0x190d0030), SPH_C32(0x7c869000), + SPH_C32(0xde7c6199), SPH_C32(0xb10e36c9), SPH_C32(0x05562501), + SPH_C32(0x7926edd0) }, + { SPH_C32(0x3cd60000), SPH_C32(0x49f30000), SPH_C32(0x808e0036), + SPH_C32(0xaa0a1800), SPH_C32(0x89824fd7), SPH_C32(0xec4e516d), + SPH_C32(0xde1e3a21), SPH_C32(0xbbbdaed9), SPH_C32(0x68ba0000), + SPH_C32(0xa0be0000), SPH_C32(0x01410031), SPH_C32(0xeeea2000), + SPH_C32(0xbc3a7856), SPH_C32(0xa8a5bb57), SPH_C32(0x7275e2f2), + SPH_C32(0xc93a72c5) }, + { SPH_C32(0xae800000), SPH_C32(0x57290000), SPH_C32(0x6adf0036), + SPH_C32(0x42bb2800), SPH_C32(0x20b71972), SPH_C32(0x07b530f4), + SPH_C32(0x6f421875), SPH_C32(0x88788a96), SPH_C32(0xe4800000), + SPH_C32(0x7a260000), SPH_C32(0x613e0031), SPH_C32(0xbaeda800), + SPH_C32(0x394b3d45), SPH_C32(0xc8a30914), SPH_C32(0xa925db6e), + SPH_C32(0x43629461) }, + { SPH_C32(0x64950000), SPH_C32(0xc98d0000), SPH_C32(0xf8bd0037), + SPH_C32(0x6c612000), SPH_C32(0x6eb5130b), SPH_C32(0x95e36eb0), + SPH_C32(0x726dc44e), SPH_C32(0x81f9d768), SPH_C32(0x75e00000), + SPH_C32(0x8bcc0000), SPH_C32(0x49cc0031), SPH_C32(0x418b3800), + SPH_C32(0x99f15693), SPH_C32(0x60dc0487), SPH_C32(0xf3d7e6db), + SPH_C32(0xd74f4463) }, + { SPH_C32(0xf6c30000), SPH_C32(0xd7570000), SPH_C32(0x12ec0037), + SPH_C32(0x84d01000), SPH_C32(0xc78045ae), SPH_C32(0x7e180f29), + SPH_C32(0xc331e61a), SPH_C32(0xb23cf327), SPH_C32(0xf9da0000), + SPH_C32(0x51540000), SPH_C32(0x29b30031), SPH_C32(0x158cb000), + SPH_C32(0x1c801380), SPH_C32(0x00dab6c4), SPH_C32(0x2887df47), + SPH_C32(0x5d17a2c7) } +}; + +static const sph_u32 T512_49[128][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0xe6280000), SPH_C32(0x4c4b0000), SPH_C32(0xa8550000), + SPH_C32(0xd3d002e0), SPH_C32(0xd86130b8), SPH_C32(0x98a7b0da), + SPH_C32(0x289506b4), SPH_C32(0xd75a4897), SPH_C32(0xf0c50000), + SPH_C32(0x59230000), SPH_C32(0x45820000), SPH_C32(0xe18d00c0), + SPH_C32(0x3b6d0631), SPH_C32(0xc2ed5699), SPH_C32(0xcbe0fe1c), + SPH_C32(0x56a7b19f) }, + { SPH_C32(0xf0c50000), SPH_C32(0x59230000), SPH_C32(0x45820000), + SPH_C32(0xe18d00c0), SPH_C32(0x3b6d0631), SPH_C32(0xc2ed5699), + SPH_C32(0xcbe0fe1c), SPH_C32(0x56a7b19f), SPH_C32(0x16ed0000), + SPH_C32(0x15680000), SPH_C32(0xedd70000), SPH_C32(0x325d0220), + SPH_C32(0xe30c3689), SPH_C32(0x5a4ae643), SPH_C32(0xe375f8a8), + SPH_C32(0x81fdf908) }, + { SPH_C32(0x16ed0000), SPH_C32(0x15680000), SPH_C32(0xedd70000), + SPH_C32(0x325d0220), SPH_C32(0xe30c3689), SPH_C32(0x5a4ae643), + SPH_C32(0xe375f8a8), SPH_C32(0x81fdf908), SPH_C32(0xe6280000), + SPH_C32(0x4c4b0000), SPH_C32(0xa8550000), SPH_C32(0xd3d002e0), + SPH_C32(0xd86130b8), SPH_C32(0x98a7b0da), SPH_C32(0x289506b4), + SPH_C32(0xd75a4897) }, + { SPH_C32(0xb4310000), SPH_C32(0x77330000), SPH_C32(0xb15d0000), + SPH_C32(0x7fd004e0), SPH_C32(0x78a26138), SPH_C32(0xd116c35d), + SPH_C32(0xd256d489), SPH_C32(0x4e6f74de), SPH_C32(0xe3060000), + SPH_C32(0xbdc10000), SPH_C32(0x87130000), SPH_C32(0xbff20060), + SPH_C32(0x2eba0a1a), SPH_C32(0x8db53751), SPH_C32(0x73c5ab06), + SPH_C32(0x5bd61539) }, + { SPH_C32(0x52190000), SPH_C32(0x3b780000), SPH_C32(0x19080000), + SPH_C32(0xac000600), SPH_C32(0xa0c35180), SPH_C32(0x49b17387), + SPH_C32(0xfac3d23d), SPH_C32(0x99353c49), SPH_C32(0x13c30000), + SPH_C32(0xe4e20000), SPH_C32(0xc2910000), SPH_C32(0x5e7f00a0), + SPH_C32(0x15d70c2b), SPH_C32(0x4f5861c8), SPH_C32(0xb825551a), + SPH_C32(0x0d71a4a6) }, + { SPH_C32(0x44f40000), SPH_C32(0x2e100000), SPH_C32(0xf4df0000), + SPH_C32(0x9e5d0420), SPH_C32(0x43cf6709), SPH_C32(0x13fb95c4), + SPH_C32(0x19b62a95), SPH_C32(0x18c8c541), SPH_C32(0xf5eb0000), + SPH_C32(0xa8a90000), SPH_C32(0x6ac40000), SPH_C32(0x8daf0240), + SPH_C32(0xcdb63c93), SPH_C32(0xd7ffd112), SPH_C32(0x90b053ae), + SPH_C32(0xda2bec31) }, + { SPH_C32(0xa2dc0000), SPH_C32(0x625b0000), SPH_C32(0x5c8a0000), + SPH_C32(0x4d8d06c0), SPH_C32(0x9bae57b1), SPH_C32(0x8b5c251e), + SPH_C32(0x31232c21), SPH_C32(0xcf928dd6), SPH_C32(0x052e0000), + SPH_C32(0xf18a0000), SPH_C32(0x2f460000), SPH_C32(0x6c220280), + SPH_C32(0xf6db3aa2), SPH_C32(0x1512878b), SPH_C32(0x5b50adb2), + SPH_C32(0x8c8c5dae) }, + { SPH_C32(0xe3060000), SPH_C32(0xbdc10000), SPH_C32(0x87130000), + SPH_C32(0xbff20060), SPH_C32(0x2eba0a1a), SPH_C32(0x8db53751), + SPH_C32(0x73c5ab06), SPH_C32(0x5bd61539), SPH_C32(0x57370000), + SPH_C32(0xcaf20000), SPH_C32(0x364e0000), SPH_C32(0xc0220480), + SPH_C32(0x56186b22), SPH_C32(0x5ca3f40c), SPH_C32(0xa1937f8f), + SPH_C32(0x15b961e7) }, + { SPH_C32(0x052e0000), SPH_C32(0xf18a0000), SPH_C32(0x2f460000), + SPH_C32(0x6c220280), SPH_C32(0xf6db3aa2), SPH_C32(0x1512878b), + SPH_C32(0x5b50adb2), SPH_C32(0x8c8c5dae), SPH_C32(0xa7f20000), + SPH_C32(0x93d10000), SPH_C32(0x73cc0000), SPH_C32(0x21af0440), + SPH_C32(0x6d756d13), SPH_C32(0x9e4ea295), SPH_C32(0x6a738193), + SPH_C32(0x431ed078) }, + { SPH_C32(0x13c30000), SPH_C32(0xe4e20000), SPH_C32(0xc2910000), + SPH_C32(0x5e7f00a0), SPH_C32(0x15d70c2b), SPH_C32(0x4f5861c8), + SPH_C32(0xb825551a), SPH_C32(0x0d71a4a6), SPH_C32(0x41da0000), + SPH_C32(0xdf9a0000), SPH_C32(0xdb990000), SPH_C32(0xf27f06a0), + SPH_C32(0xb5145dab), SPH_C32(0x06e9124f), SPH_C32(0x42e68727), + SPH_C32(0x944498ef) }, + { SPH_C32(0xf5eb0000), SPH_C32(0xa8a90000), SPH_C32(0x6ac40000), + SPH_C32(0x8daf0240), SPH_C32(0xcdb63c93), SPH_C32(0xd7ffd112), + SPH_C32(0x90b053ae), SPH_C32(0xda2bec31), SPH_C32(0xb11f0000), + SPH_C32(0x86b90000), SPH_C32(0x9e1b0000), SPH_C32(0x13f20660), + SPH_C32(0x8e795b9a), SPH_C32(0xc40444d6), SPH_C32(0x8906793b), + SPH_C32(0xc2e32970) }, + { SPH_C32(0x57370000), SPH_C32(0xcaf20000), SPH_C32(0x364e0000), + SPH_C32(0xc0220480), SPH_C32(0x56186b22), SPH_C32(0x5ca3f40c), + SPH_C32(0xa1937f8f), SPH_C32(0x15b961e7), SPH_C32(0xb4310000), + SPH_C32(0x77330000), SPH_C32(0xb15d0000), SPH_C32(0x7fd004e0), + SPH_C32(0x78a26138), SPH_C32(0xd116c35d), SPH_C32(0xd256d489), + SPH_C32(0x4e6f74de) }, + { SPH_C32(0xb11f0000), SPH_C32(0x86b90000), SPH_C32(0x9e1b0000), + SPH_C32(0x13f20660), SPH_C32(0x8e795b9a), SPH_C32(0xc40444d6), + SPH_C32(0x8906793b), SPH_C32(0xc2e32970), SPH_C32(0x44f40000), + SPH_C32(0x2e100000), SPH_C32(0xf4df0000), SPH_C32(0x9e5d0420), + SPH_C32(0x43cf6709), SPH_C32(0x13fb95c4), SPH_C32(0x19b62a95), + SPH_C32(0x18c8c541) }, + { SPH_C32(0xa7f20000), SPH_C32(0x93d10000), SPH_C32(0x73cc0000), + SPH_C32(0x21af0440), SPH_C32(0x6d756d13), SPH_C32(0x9e4ea295), + SPH_C32(0x6a738193), SPH_C32(0x431ed078), SPH_C32(0xa2dc0000), + SPH_C32(0x625b0000), SPH_C32(0x5c8a0000), SPH_C32(0x4d8d06c0), + SPH_C32(0x9bae57b1), SPH_C32(0x8b5c251e), SPH_C32(0x31232c21), + SPH_C32(0xcf928dd6) }, + { SPH_C32(0x41da0000), SPH_C32(0xdf9a0000), SPH_C32(0xdb990000), + SPH_C32(0xf27f06a0), SPH_C32(0xb5145dab), SPH_C32(0x06e9124f), + SPH_C32(0x42e68727), SPH_C32(0x944498ef), SPH_C32(0x52190000), + SPH_C32(0x3b780000), SPH_C32(0x19080000), SPH_C32(0xac000600), + SPH_C32(0xa0c35180), SPH_C32(0x49b17387), SPH_C32(0xfac3d23d), + SPH_C32(0x99353c49) }, + { SPH_C32(0x02f20000), SPH_C32(0xa2810000), SPH_C32(0x873f0000), + SPH_C32(0xe36c7800), SPH_C32(0x1e1d74ef), SPH_C32(0x073d2bd6), + SPH_C32(0xc4c23237), SPH_C32(0x7f32259e), SPH_C32(0xbadd0000), + SPH_C32(0x13ad0000), SPH_C32(0xb7e70000), SPH_C32(0xf7282800), + SPH_C32(0xdf45144d), SPH_C32(0x361ac33a), SPH_C32(0xea5a8d14), + SPH_C32(0x2a2c18f0) }, + { SPH_C32(0xe4da0000), SPH_C32(0xeeca0000), SPH_C32(0x2f6a0000), + SPH_C32(0x30bc7ae0), SPH_C32(0xc67c4457), SPH_C32(0x9f9a9b0c), + SPH_C32(0xec573483), SPH_C32(0xa8686d09), SPH_C32(0x4a180000), + SPH_C32(0x4a8e0000), SPH_C32(0xf2650000), SPH_C32(0x16a528c0), + SPH_C32(0xe428127c), SPH_C32(0xf4f795a3), SPH_C32(0x21ba7308), + SPH_C32(0x7c8ba96f) }, + { SPH_C32(0xf2370000), SPH_C32(0xfba20000), SPH_C32(0xc2bd0000), + SPH_C32(0x02e178c0), SPH_C32(0x257072de), SPH_C32(0xc5d07d4f), + SPH_C32(0x0f22cc2b), SPH_C32(0x29959401), SPH_C32(0xac300000), + SPH_C32(0x06c50000), SPH_C32(0x5a300000), SPH_C32(0xc5752a20), + SPH_C32(0x3c4922c4), SPH_C32(0x6c502579), SPH_C32(0x092f75bc), + SPH_C32(0xabd1e1f8) }, + { SPH_C32(0x141f0000), SPH_C32(0xb7e90000), SPH_C32(0x6ae80000), + SPH_C32(0xd1317a20), SPH_C32(0xfd114266), SPH_C32(0x5d77cd95), + SPH_C32(0x27b7ca9f), SPH_C32(0xfecfdc96), SPH_C32(0x5cf50000), + SPH_C32(0x5fe60000), SPH_C32(0x1fb20000), SPH_C32(0x24f82ae0), + SPH_C32(0x072424f5), SPH_C32(0xaebd73e0), SPH_C32(0xc2cf8ba0), + SPH_C32(0xfd765067) }, + { SPH_C32(0xb6c30000), SPH_C32(0xd5b20000), SPH_C32(0x36620000), + SPH_C32(0x9cbc7ce0), SPH_C32(0x66bf15d7), SPH_C32(0xd62be88b), + SPH_C32(0x1694e6be), SPH_C32(0x315d5140), SPH_C32(0x59db0000), + SPH_C32(0xae6c0000), SPH_C32(0x30f40000), SPH_C32(0x48da2860), + SPH_C32(0xf1ff1e57), SPH_C32(0xbbaff46b), SPH_C32(0x999f2612), + SPH_C32(0x71fa0dc9) }, + { SPH_C32(0x50eb0000), SPH_C32(0x99f90000), SPH_C32(0x9e370000), + SPH_C32(0x4f6c7e00), SPH_C32(0xbede256f), SPH_C32(0x4e8c5851), + SPH_C32(0x3e01e00a), SPH_C32(0xe60719d7), SPH_C32(0xa91e0000), + SPH_C32(0xf74f0000), SPH_C32(0x75760000), SPH_C32(0xa95728a0), + SPH_C32(0xca921866), SPH_C32(0x7942a2f2), SPH_C32(0x527fd80e), + SPH_C32(0x275dbc56) }, + { SPH_C32(0x46060000), SPH_C32(0x8c910000), SPH_C32(0x73e00000), + SPH_C32(0x7d317c20), SPH_C32(0x5dd213e6), SPH_C32(0x14c6be12), + SPH_C32(0xdd7418a2), SPH_C32(0x67fae0df), SPH_C32(0x4f360000), + SPH_C32(0xbb040000), SPH_C32(0xdd230000), SPH_C32(0x7a872a40), + SPH_C32(0x12f328de), SPH_C32(0xe1e51228), SPH_C32(0x7aeadeba), + SPH_C32(0xf007f4c1) }, + { SPH_C32(0xa02e0000), SPH_C32(0xc0da0000), SPH_C32(0xdbb50000), + SPH_C32(0xaee17ec0), SPH_C32(0x85b3235e), SPH_C32(0x8c610ec8), + SPH_C32(0xf5e11e16), SPH_C32(0xb0a0a848), SPH_C32(0xbff30000), + SPH_C32(0xe2270000), SPH_C32(0x98a10000), SPH_C32(0x9b0a2a80), + SPH_C32(0x299e2eef), SPH_C32(0x230844b1), SPH_C32(0xb10a20a6), + SPH_C32(0xa6a0455e) }, + { SPH_C32(0xe1f40000), SPH_C32(0x1f400000), SPH_C32(0x002c0000), + SPH_C32(0x5c9e7860), SPH_C32(0x30a77ef5), SPH_C32(0x8a881c87), + SPH_C32(0xb7079931), SPH_C32(0x24e430a7), SPH_C32(0xedea0000), + SPH_C32(0xd95f0000), SPH_C32(0x81a90000), SPH_C32(0x370a2c80), + SPH_C32(0x895d7f6f), SPH_C32(0x6ab93736), SPH_C32(0x4bc9f29b), + SPH_C32(0x3f957917) }, + { SPH_C32(0x07dc0000), SPH_C32(0x530b0000), SPH_C32(0xa8790000), + SPH_C32(0x8f4e7a80), SPH_C32(0xe8c64e4d), SPH_C32(0x122fac5d), + SPH_C32(0x9f929f85), SPH_C32(0xf3be7830), SPH_C32(0x1d2f0000), + SPH_C32(0x807c0000), SPH_C32(0xc42b0000), SPH_C32(0xd6872c40), + SPH_C32(0xb230795e), SPH_C32(0xa85461af), SPH_C32(0x80290c87), + SPH_C32(0x6932c888) }, + { SPH_C32(0x11310000), SPH_C32(0x46630000), SPH_C32(0x45ae0000), + SPH_C32(0xbd1378a0), SPH_C32(0x0bca78c4), SPH_C32(0x48654a1e), + SPH_C32(0x7ce7672d), SPH_C32(0x72438138), SPH_C32(0xfb070000), + SPH_C32(0xcc370000), SPH_C32(0x6c7e0000), SPH_C32(0x05572ea0), + SPH_C32(0x6a5149e6), SPH_C32(0x30f3d175), SPH_C32(0xa8bc0a33), + SPH_C32(0xbe68801f) }, + { SPH_C32(0xf7190000), SPH_C32(0x0a280000), SPH_C32(0xedfb0000), + SPH_C32(0x6ec37a40), SPH_C32(0xd3ab487c), SPH_C32(0xd0c2fac4), + SPH_C32(0x54726199), SPH_C32(0xa519c9af), SPH_C32(0x0bc20000), + SPH_C32(0x95140000), SPH_C32(0x29fc0000), SPH_C32(0xe4da2e60), + SPH_C32(0x513c4fd7), SPH_C32(0xf21e87ec), SPH_C32(0x635cf42f), + SPH_C32(0xe8cf3180) }, + { SPH_C32(0x55c50000), SPH_C32(0x68730000), SPH_C32(0xb1710000), + SPH_C32(0x234e7c80), SPH_C32(0x48051fcd), SPH_C32(0x5b9edfda), + SPH_C32(0x65514db8), SPH_C32(0x6a8b4479), SPH_C32(0x0eec0000), + SPH_C32(0x649e0000), SPH_C32(0x06ba0000), SPH_C32(0x88f82ce0), + SPH_C32(0xa7e77575), SPH_C32(0xe70c0067), SPH_C32(0x380c599d), + SPH_C32(0x64436c2e) }, + { SPH_C32(0xb3ed0000), SPH_C32(0x24380000), SPH_C32(0x19240000), + SPH_C32(0xf09e7e60), SPH_C32(0x90642f75), SPH_C32(0xc3396f00), + SPH_C32(0x4dc44b0c), SPH_C32(0xbdd10cee), SPH_C32(0xfe290000), + SPH_C32(0x3dbd0000), SPH_C32(0x43380000), SPH_C32(0x69752c20), + SPH_C32(0x9c8a7344), SPH_C32(0x25e156fe), SPH_C32(0xf3eca781), + SPH_C32(0x32e4ddb1) }, + { SPH_C32(0xa5000000), SPH_C32(0x31500000), SPH_C32(0xf4f30000), + SPH_C32(0xc2c37c40), SPH_C32(0x736819fc), SPH_C32(0x99738943), + SPH_C32(0xaeb1b3a4), SPH_C32(0x3c2cf5e6), SPH_C32(0x18010000), + SPH_C32(0x71f60000), SPH_C32(0xeb6d0000), SPH_C32(0xbaa52ec0), + SPH_C32(0x44eb43fc), SPH_C32(0xbd46e624), SPH_C32(0xdb79a135), + SPH_C32(0xe5be9526) }, + { SPH_C32(0x43280000), SPH_C32(0x7d1b0000), SPH_C32(0x5ca60000), + SPH_C32(0x11137ea0), SPH_C32(0xab092944), SPH_C32(0x01d43999), + SPH_C32(0x8624b510), SPH_C32(0xeb76bd71), SPH_C32(0xe8c40000), + SPH_C32(0x28d50000), SPH_C32(0xaeef0000), SPH_C32(0x5b282e00), + SPH_C32(0x7f8645cd), SPH_C32(0x7fabb0bd), SPH_C32(0x10995f29), + SPH_C32(0xb31924b9) }, + { SPH_C32(0xbadd0000), SPH_C32(0x13ad0000), SPH_C32(0xb7e70000), + SPH_C32(0xf7282800), SPH_C32(0xdf45144d), SPH_C32(0x361ac33a), + SPH_C32(0xea5a8d14), SPH_C32(0x2a2c18f0), SPH_C32(0xb82f0000), + SPH_C32(0xb12c0000), SPH_C32(0x30d80000), SPH_C32(0x14445000), + SPH_C32(0xc15860a2), SPH_C32(0x3127e8ec), SPH_C32(0x2e98bf23), + SPH_C32(0x551e3d6e) }, + { SPH_C32(0x5cf50000), SPH_C32(0x5fe60000), SPH_C32(0x1fb20000), + SPH_C32(0x24f82ae0), SPH_C32(0x072424f5), SPH_C32(0xaebd73e0), + SPH_C32(0xc2cf8ba0), SPH_C32(0xfd765067), SPH_C32(0x48ea0000), + SPH_C32(0xe80f0000), SPH_C32(0x755a0000), SPH_C32(0xf5c950c0), + SPH_C32(0xfa356693), SPH_C32(0xf3cabe75), SPH_C32(0xe578413f), + SPH_C32(0x03b98cf1) }, + { SPH_C32(0x4a180000), SPH_C32(0x4a8e0000), SPH_C32(0xf2650000), + SPH_C32(0x16a528c0), SPH_C32(0xe428127c), SPH_C32(0xf4f795a3), + SPH_C32(0x21ba7308), SPH_C32(0x7c8ba96f), SPH_C32(0xaec20000), + SPH_C32(0xa4440000), SPH_C32(0xdd0f0000), SPH_C32(0x26195220), + SPH_C32(0x2254562b), SPH_C32(0x6b6d0eaf), SPH_C32(0xcded478b), + SPH_C32(0xd4e3c466) }, + { SPH_C32(0xac300000), SPH_C32(0x06c50000), SPH_C32(0x5a300000), + SPH_C32(0xc5752a20), SPH_C32(0x3c4922c4), SPH_C32(0x6c502579), + SPH_C32(0x092f75bc), SPH_C32(0xabd1e1f8), SPH_C32(0x5e070000), + SPH_C32(0xfd670000), SPH_C32(0x988d0000), SPH_C32(0xc79452e0), + SPH_C32(0x1939501a), SPH_C32(0xa9805836), SPH_C32(0x060db997), + SPH_C32(0x824475f9) }, + { SPH_C32(0x0eec0000), SPH_C32(0x649e0000), SPH_C32(0x06ba0000), + SPH_C32(0x88f82ce0), SPH_C32(0xa7e77575), SPH_C32(0xe70c0067), + SPH_C32(0x380c599d), SPH_C32(0x64436c2e), SPH_C32(0x5b290000), + SPH_C32(0x0ced0000), SPH_C32(0xb7cb0000), SPH_C32(0xabb65060), + SPH_C32(0xefe26ab8), SPH_C32(0xbc92dfbd), SPH_C32(0x5d5d1425), + SPH_C32(0x0ec82857) }, + { SPH_C32(0xe8c40000), SPH_C32(0x28d50000), SPH_C32(0xaeef0000), + SPH_C32(0x5b282e00), SPH_C32(0x7f8645cd), SPH_C32(0x7fabb0bd), + SPH_C32(0x10995f29), SPH_C32(0xb31924b9), SPH_C32(0xabec0000), + SPH_C32(0x55ce0000), SPH_C32(0xf2490000), SPH_C32(0x4a3b50a0), + SPH_C32(0xd48f6c89), SPH_C32(0x7e7f8924), SPH_C32(0x96bdea39), + SPH_C32(0x586f99c8) }, + { SPH_C32(0xfe290000), SPH_C32(0x3dbd0000), SPH_C32(0x43380000), + SPH_C32(0x69752c20), SPH_C32(0x9c8a7344), SPH_C32(0x25e156fe), + SPH_C32(0xf3eca781), SPH_C32(0x32e4ddb1), SPH_C32(0x4dc40000), + SPH_C32(0x19850000), SPH_C32(0x5a1c0000), SPH_C32(0x99eb5240), + SPH_C32(0x0cee5c31), SPH_C32(0xe6d839fe), SPH_C32(0xbe28ec8d), + SPH_C32(0x8f35d15f) }, + { SPH_C32(0x18010000), SPH_C32(0x71f60000), SPH_C32(0xeb6d0000), + SPH_C32(0xbaa52ec0), SPH_C32(0x44eb43fc), SPH_C32(0xbd46e624), + SPH_C32(0xdb79a135), SPH_C32(0xe5be9526), SPH_C32(0xbd010000), + SPH_C32(0x40a60000), SPH_C32(0x1f9e0000), SPH_C32(0x78665280), + SPH_C32(0x37835a00), SPH_C32(0x24356f67), SPH_C32(0x75c81291), + SPH_C32(0xd99260c0) }, + { SPH_C32(0x59db0000), SPH_C32(0xae6c0000), SPH_C32(0x30f40000), + SPH_C32(0x48da2860), SPH_C32(0xf1ff1e57), SPH_C32(0xbbaff46b), + SPH_C32(0x999f2612), SPH_C32(0x71fa0dc9), SPH_C32(0xef180000), + SPH_C32(0x7bde0000), SPH_C32(0x06960000), SPH_C32(0xd4665480), + SPH_C32(0x97400b80), SPH_C32(0x6d841ce0), SPH_C32(0x8f0bc0ac), + SPH_C32(0x40a75c89) }, + { SPH_C32(0xbff30000), SPH_C32(0xe2270000), SPH_C32(0x98a10000), + SPH_C32(0x9b0a2a80), SPH_C32(0x299e2eef), SPH_C32(0x230844b1), + SPH_C32(0xb10a20a6), SPH_C32(0xa6a0455e), SPH_C32(0x1fdd0000), + SPH_C32(0x22fd0000), SPH_C32(0x43140000), SPH_C32(0x35eb5440), + SPH_C32(0xac2d0db1), SPH_C32(0xaf694a79), SPH_C32(0x44eb3eb0), + SPH_C32(0x1600ed16) }, + { SPH_C32(0xa91e0000), SPH_C32(0xf74f0000), SPH_C32(0x75760000), + SPH_C32(0xa95728a0), SPH_C32(0xca921866), SPH_C32(0x7942a2f2), + SPH_C32(0x527fd80e), SPH_C32(0x275dbc56), SPH_C32(0xf9f50000), + SPH_C32(0x6eb60000), SPH_C32(0xeb410000), SPH_C32(0xe63b56a0), + SPH_C32(0x744c3d09), SPH_C32(0x37cefaa3), SPH_C32(0x6c7e3804), + SPH_C32(0xc15aa581) }, + { SPH_C32(0x4f360000), SPH_C32(0xbb040000), SPH_C32(0xdd230000), + SPH_C32(0x7a872a40), SPH_C32(0x12f328de), SPH_C32(0xe1e51228), + SPH_C32(0x7aeadeba), SPH_C32(0xf007f4c1), SPH_C32(0x09300000), + SPH_C32(0x37950000), SPH_C32(0xaec30000), SPH_C32(0x07b65660), + SPH_C32(0x4f213b38), SPH_C32(0xf523ac3a), SPH_C32(0xa79ec618), + SPH_C32(0x97fd141e) }, + { SPH_C32(0xedea0000), SPH_C32(0xd95f0000), SPH_C32(0x81a90000), + SPH_C32(0x370a2c80), SPH_C32(0x895d7f6f), SPH_C32(0x6ab93736), + SPH_C32(0x4bc9f29b), SPH_C32(0x3f957917), SPH_C32(0x0c1e0000), + SPH_C32(0xc61f0000), SPH_C32(0x81850000), SPH_C32(0x6b9454e0), + SPH_C32(0xb9fa019a), SPH_C32(0xe0312bb1), SPH_C32(0xfcce6baa), + SPH_C32(0x1b7149b0) }, + { SPH_C32(0x0bc20000), SPH_C32(0x95140000), SPH_C32(0x29fc0000), + SPH_C32(0xe4da2e60), SPH_C32(0x513c4fd7), SPH_C32(0xf21e87ec), + SPH_C32(0x635cf42f), SPH_C32(0xe8cf3180), SPH_C32(0xfcdb0000), + SPH_C32(0x9f3c0000), SPH_C32(0xc4070000), SPH_C32(0x8a195420), + SPH_C32(0x829707ab), SPH_C32(0x22dc7d28), SPH_C32(0x372e95b6), + SPH_C32(0x4dd6f82f) }, + { SPH_C32(0x1d2f0000), SPH_C32(0x807c0000), SPH_C32(0xc42b0000), + SPH_C32(0xd6872c40), SPH_C32(0xb230795e), SPH_C32(0xa85461af), + SPH_C32(0x80290c87), SPH_C32(0x6932c888), SPH_C32(0x1af30000), + SPH_C32(0xd3770000), SPH_C32(0x6c520000), SPH_C32(0x59c956c0), + SPH_C32(0x5af63713), SPH_C32(0xba7bcdf2), SPH_C32(0x1fbb9302), + SPH_C32(0x9a8cb0b8) }, + { SPH_C32(0xfb070000), SPH_C32(0xcc370000), SPH_C32(0x6c7e0000), + SPH_C32(0x05572ea0), SPH_C32(0x6a5149e6), SPH_C32(0x30f3d175), + SPH_C32(0xa8bc0a33), SPH_C32(0xbe68801f), SPH_C32(0xea360000), + SPH_C32(0x8a540000), SPH_C32(0x29d00000), SPH_C32(0xb8445600), + SPH_C32(0x619b3122), SPH_C32(0x78969b6b), SPH_C32(0xd45b6d1e), + SPH_C32(0xcc2b0127) }, + { SPH_C32(0xb82f0000), SPH_C32(0xb12c0000), SPH_C32(0x30d80000), + SPH_C32(0x14445000), SPH_C32(0xc15860a2), SPH_C32(0x3127e8ec), + SPH_C32(0x2e98bf23), SPH_C32(0x551e3d6e), SPH_C32(0x02f20000), + SPH_C32(0xa2810000), SPH_C32(0x873f0000), SPH_C32(0xe36c7800), + SPH_C32(0x1e1d74ef), SPH_C32(0x073d2bd6), SPH_C32(0xc4c23237), + SPH_C32(0x7f32259e) }, + { SPH_C32(0x5e070000), SPH_C32(0xfd670000), SPH_C32(0x988d0000), + SPH_C32(0xc79452e0), SPH_C32(0x1939501a), SPH_C32(0xa9805836), + SPH_C32(0x060db997), SPH_C32(0x824475f9), SPH_C32(0xf2370000), + SPH_C32(0xfba20000), SPH_C32(0xc2bd0000), SPH_C32(0x02e178c0), + SPH_C32(0x257072de), SPH_C32(0xc5d07d4f), SPH_C32(0x0f22cc2b), + SPH_C32(0x29959401) }, + { SPH_C32(0x48ea0000), SPH_C32(0xe80f0000), SPH_C32(0x755a0000), + SPH_C32(0xf5c950c0), SPH_C32(0xfa356693), SPH_C32(0xf3cabe75), + SPH_C32(0xe578413f), SPH_C32(0x03b98cf1), SPH_C32(0x141f0000), + SPH_C32(0xb7e90000), SPH_C32(0x6ae80000), SPH_C32(0xd1317a20), + SPH_C32(0xfd114266), SPH_C32(0x5d77cd95), SPH_C32(0x27b7ca9f), + SPH_C32(0xfecfdc96) }, + { SPH_C32(0xaec20000), SPH_C32(0xa4440000), SPH_C32(0xdd0f0000), + SPH_C32(0x26195220), SPH_C32(0x2254562b), SPH_C32(0x6b6d0eaf), + SPH_C32(0xcded478b), SPH_C32(0xd4e3c466), SPH_C32(0xe4da0000), + SPH_C32(0xeeca0000), SPH_C32(0x2f6a0000), SPH_C32(0x30bc7ae0), + SPH_C32(0xc67c4457), SPH_C32(0x9f9a9b0c), SPH_C32(0xec573483), + SPH_C32(0xa8686d09) }, + { SPH_C32(0x0c1e0000), SPH_C32(0xc61f0000), SPH_C32(0x81850000), + SPH_C32(0x6b9454e0), SPH_C32(0xb9fa019a), SPH_C32(0xe0312bb1), + SPH_C32(0xfcce6baa), SPH_C32(0x1b7149b0), SPH_C32(0xe1f40000), + SPH_C32(0x1f400000), SPH_C32(0x002c0000), SPH_C32(0x5c9e7860), + SPH_C32(0x30a77ef5), SPH_C32(0x8a881c87), SPH_C32(0xb7079931), + SPH_C32(0x24e430a7) }, + { SPH_C32(0xea360000), SPH_C32(0x8a540000), SPH_C32(0x29d00000), + SPH_C32(0xb8445600), SPH_C32(0x619b3122), SPH_C32(0x78969b6b), + SPH_C32(0xd45b6d1e), SPH_C32(0xcc2b0127), SPH_C32(0x11310000), + SPH_C32(0x46630000), SPH_C32(0x45ae0000), SPH_C32(0xbd1378a0), + SPH_C32(0x0bca78c4), SPH_C32(0x48654a1e), SPH_C32(0x7ce7672d), + SPH_C32(0x72438138) }, + { SPH_C32(0xfcdb0000), SPH_C32(0x9f3c0000), SPH_C32(0xc4070000), + SPH_C32(0x8a195420), SPH_C32(0x829707ab), SPH_C32(0x22dc7d28), + SPH_C32(0x372e95b6), SPH_C32(0x4dd6f82f), SPH_C32(0xf7190000), + SPH_C32(0x0a280000), SPH_C32(0xedfb0000), SPH_C32(0x6ec37a40), + SPH_C32(0xd3ab487c), SPH_C32(0xd0c2fac4), SPH_C32(0x54726199), + SPH_C32(0xa519c9af) }, + { SPH_C32(0x1af30000), SPH_C32(0xd3770000), SPH_C32(0x6c520000), + SPH_C32(0x59c956c0), SPH_C32(0x5af63713), SPH_C32(0xba7bcdf2), + SPH_C32(0x1fbb9302), SPH_C32(0x9a8cb0b8), SPH_C32(0x07dc0000), + SPH_C32(0x530b0000), SPH_C32(0xa8790000), SPH_C32(0x8f4e7a80), + SPH_C32(0xe8c64e4d), SPH_C32(0x122fac5d), SPH_C32(0x9f929f85), + SPH_C32(0xf3be7830) }, + { SPH_C32(0x5b290000), SPH_C32(0x0ced0000), SPH_C32(0xb7cb0000), + SPH_C32(0xabb65060), SPH_C32(0xefe26ab8), SPH_C32(0xbc92dfbd), + SPH_C32(0x5d5d1425), SPH_C32(0x0ec82857), SPH_C32(0x55c50000), + SPH_C32(0x68730000), SPH_C32(0xb1710000), SPH_C32(0x234e7c80), + SPH_C32(0x48051fcd), SPH_C32(0x5b9edfda), SPH_C32(0x65514db8), + SPH_C32(0x6a8b4479) }, + { SPH_C32(0xbd010000), SPH_C32(0x40a60000), SPH_C32(0x1f9e0000), + SPH_C32(0x78665280), SPH_C32(0x37835a00), SPH_C32(0x24356f67), + SPH_C32(0x75c81291), SPH_C32(0xd99260c0), SPH_C32(0xa5000000), + SPH_C32(0x31500000), SPH_C32(0xf4f30000), SPH_C32(0xc2c37c40), + SPH_C32(0x736819fc), SPH_C32(0x99738943), SPH_C32(0xaeb1b3a4), + SPH_C32(0x3c2cf5e6) }, + { SPH_C32(0xabec0000), SPH_C32(0x55ce0000), SPH_C32(0xf2490000), + SPH_C32(0x4a3b50a0), SPH_C32(0xd48f6c89), SPH_C32(0x7e7f8924), + SPH_C32(0x96bdea39), SPH_C32(0x586f99c8), SPH_C32(0x43280000), + SPH_C32(0x7d1b0000), SPH_C32(0x5ca60000), SPH_C32(0x11137ea0), + SPH_C32(0xab092944), SPH_C32(0x01d43999), SPH_C32(0x8624b510), + SPH_C32(0xeb76bd71) }, + { SPH_C32(0x4dc40000), SPH_C32(0x19850000), SPH_C32(0x5a1c0000), + SPH_C32(0x99eb5240), SPH_C32(0x0cee5c31), SPH_C32(0xe6d839fe), + SPH_C32(0xbe28ec8d), SPH_C32(0x8f35d15f), SPH_C32(0xb3ed0000), + SPH_C32(0x24380000), SPH_C32(0x19240000), SPH_C32(0xf09e7e60), + SPH_C32(0x90642f75), SPH_C32(0xc3396f00), SPH_C32(0x4dc44b0c), + SPH_C32(0xbdd10cee) }, + { SPH_C32(0xef180000), SPH_C32(0x7bde0000), SPH_C32(0x06960000), + SPH_C32(0xd4665480), SPH_C32(0x97400b80), SPH_C32(0x6d841ce0), + SPH_C32(0x8f0bc0ac), SPH_C32(0x40a75c89), SPH_C32(0xb6c30000), + SPH_C32(0xd5b20000), SPH_C32(0x36620000), SPH_C32(0x9cbc7ce0), + SPH_C32(0x66bf15d7), SPH_C32(0xd62be88b), SPH_C32(0x1694e6be), + SPH_C32(0x315d5140) }, + { SPH_C32(0x09300000), SPH_C32(0x37950000), SPH_C32(0xaec30000), + SPH_C32(0x07b65660), SPH_C32(0x4f213b38), SPH_C32(0xf523ac3a), + SPH_C32(0xa79ec618), SPH_C32(0x97fd141e), SPH_C32(0x46060000), + SPH_C32(0x8c910000), SPH_C32(0x73e00000), SPH_C32(0x7d317c20), + SPH_C32(0x5dd213e6), SPH_C32(0x14c6be12), SPH_C32(0xdd7418a2), + SPH_C32(0x67fae0df) }, + { SPH_C32(0x1fdd0000), SPH_C32(0x22fd0000), SPH_C32(0x43140000), + SPH_C32(0x35eb5440), SPH_C32(0xac2d0db1), SPH_C32(0xaf694a79), + SPH_C32(0x44eb3eb0), SPH_C32(0x1600ed16), SPH_C32(0xa02e0000), + SPH_C32(0xc0da0000), SPH_C32(0xdbb50000), SPH_C32(0xaee17ec0), + SPH_C32(0x85b3235e), SPH_C32(0x8c610ec8), SPH_C32(0xf5e11e16), + SPH_C32(0xb0a0a848) }, + { SPH_C32(0xf9f50000), SPH_C32(0x6eb60000), SPH_C32(0xeb410000), + SPH_C32(0xe63b56a0), SPH_C32(0x744c3d09), SPH_C32(0x37cefaa3), + SPH_C32(0x6c7e3804), SPH_C32(0xc15aa581), SPH_C32(0x50eb0000), + SPH_C32(0x99f90000), SPH_C32(0x9e370000), SPH_C32(0x4f6c7e00), + SPH_C32(0xbede256f), SPH_C32(0x4e8c5851), SPH_C32(0x3e01e00a), + SPH_C32(0xe60719d7) }, + { SPH_C32(0x1e6c0000), SPH_C32(0xc4420000), SPH_C32(0x8a2e0000), + SPH_C32(0xbcb6b800), SPH_C32(0x2c4413b6), SPH_C32(0x8bfdd3da), + SPH_C32(0x6a0c1bc8), SPH_C32(0xb99dc2eb), SPH_C32(0x92560000), + SPH_C32(0x1eda0000), SPH_C32(0xea510000), SPH_C32(0xe8b13000), + SPH_C32(0xa93556a5), SPH_C32(0xebfb6199), SPH_C32(0xb15c2254), + SPH_C32(0x33c5244f) }, + { SPH_C32(0xf8440000), SPH_C32(0x88090000), SPH_C32(0x227b0000), + SPH_C32(0x6f66bae0), SPH_C32(0xf425230e), SPH_C32(0x135a6300), + SPH_C32(0x42991d7c), SPH_C32(0x6ec78a7c), SPH_C32(0x62930000), + SPH_C32(0x47f90000), SPH_C32(0xafd30000), SPH_C32(0x093c30c0), + SPH_C32(0x92585094), SPH_C32(0x29163700), SPH_C32(0x7abcdc48), + SPH_C32(0x656295d0) }, + { SPH_C32(0xeea90000), SPH_C32(0x9d610000), SPH_C32(0xcfac0000), + SPH_C32(0x5d3bb8c0), SPH_C32(0x17291587), SPH_C32(0x49108543), + SPH_C32(0xa1ece5d4), SPH_C32(0xef3a7374), SPH_C32(0x84bb0000), + SPH_C32(0x0bb20000), SPH_C32(0x07860000), SPH_C32(0xdaec3220), + SPH_C32(0x4a39602c), SPH_C32(0xb1b187da), SPH_C32(0x5229dafc), + SPH_C32(0xb238dd47) }, + { SPH_C32(0x08810000), SPH_C32(0xd12a0000), SPH_C32(0x67f90000), + SPH_C32(0x8eebba20), SPH_C32(0xcf48253f), SPH_C32(0xd1b73599), + SPH_C32(0x8979e360), SPH_C32(0x38603be3), SPH_C32(0x747e0000), + SPH_C32(0x52910000), SPH_C32(0x42040000), SPH_C32(0x3b6132e0), + SPH_C32(0x7154661d), SPH_C32(0x735cd143), SPH_C32(0x99c924e0), + SPH_C32(0xe49f6cd8) }, + { SPH_C32(0xaa5d0000), SPH_C32(0xb3710000), SPH_C32(0x3b730000), + SPH_C32(0xc366bce0), SPH_C32(0x54e6728e), SPH_C32(0x5aeb1087), + SPH_C32(0xb85acf41), SPH_C32(0xf7f2b635), SPH_C32(0x71500000), + SPH_C32(0xa31b0000), SPH_C32(0x6d420000), SPH_C32(0x57433060), + SPH_C32(0x878f5cbf), SPH_C32(0x664e56c8), SPH_C32(0xc2998952), + SPH_C32(0x68133176) }, + { SPH_C32(0x4c750000), SPH_C32(0xff3a0000), SPH_C32(0x93260000), + SPH_C32(0x10b6be00), SPH_C32(0x8c874236), SPH_C32(0xc24ca05d), + SPH_C32(0x90cfc9f5), SPH_C32(0x20a8fea2), SPH_C32(0x81950000), + SPH_C32(0xfa380000), SPH_C32(0x28c00000), SPH_C32(0xb6ce30a0), + SPH_C32(0xbce25a8e), SPH_C32(0xa4a30051), SPH_C32(0x0979774e), + SPH_C32(0x3eb480e9) }, + { SPH_C32(0x5a980000), SPH_C32(0xea520000), SPH_C32(0x7ef10000), + SPH_C32(0x22ebbc20), SPH_C32(0x6f8b74bf), SPH_C32(0x9806461e), + SPH_C32(0x73ba315d), SPH_C32(0xa15507aa), SPH_C32(0x67bd0000), + SPH_C32(0xb6730000), SPH_C32(0x80950000), SPH_C32(0x651e3240), + SPH_C32(0x64836a36), SPH_C32(0x3c04b08b), SPH_C32(0x21ec71fa), + SPH_C32(0xe9eec87e) }, + { SPH_C32(0xbcb00000), SPH_C32(0xa6190000), SPH_C32(0xd6a40000), + SPH_C32(0xf13bbec0), SPH_C32(0xb7ea4407), SPH_C32(0x00a1f6c4), + SPH_C32(0x5b2f37e9), SPH_C32(0x760f4f3d), SPH_C32(0x97780000), + SPH_C32(0xef500000), SPH_C32(0xc5170000), SPH_C32(0x84933280), + SPH_C32(0x5fee6c07), SPH_C32(0xfee9e612), SPH_C32(0xea0c8fe6), + SPH_C32(0xbf4979e1) }, + { SPH_C32(0xfd6a0000), SPH_C32(0x79830000), SPH_C32(0x0d3d0000), + SPH_C32(0x0344b860), SPH_C32(0x02fe19ac), SPH_C32(0x0648e48b), + SPH_C32(0x19c9b0ce), SPH_C32(0xe24bd7d2), SPH_C32(0xc5610000), + SPH_C32(0xd4280000), SPH_C32(0xdc1f0000), SPH_C32(0x28933480), + SPH_C32(0xff2d3d87), SPH_C32(0xb7589595), SPH_C32(0x10cf5ddb), + SPH_C32(0x267c45a8) }, + { SPH_C32(0x1b420000), SPH_C32(0x35c80000), SPH_C32(0xa5680000), + SPH_C32(0xd094ba80), SPH_C32(0xda9f2914), SPH_C32(0x9eef5451), + SPH_C32(0x315cb67a), SPH_C32(0x35119f45), SPH_C32(0x35a40000), + SPH_C32(0x8d0b0000), SPH_C32(0x999d0000), SPH_C32(0xc91e3440), + SPH_C32(0xc4403bb6), SPH_C32(0x75b5c30c), SPH_C32(0xdb2fa3c7), + SPH_C32(0x70dbf437) }, + { SPH_C32(0x0daf0000), SPH_C32(0x20a00000), SPH_C32(0x48bf0000), + SPH_C32(0xe2c9b8a0), SPH_C32(0x39931f9d), SPH_C32(0xc4a5b212), + SPH_C32(0xd2294ed2), SPH_C32(0xb4ec664d), SPH_C32(0xd38c0000), + SPH_C32(0xc1400000), SPH_C32(0x31c80000), SPH_C32(0x1ace36a0), + SPH_C32(0x1c210b0e), SPH_C32(0xed1273d6), SPH_C32(0xf3baa573), + SPH_C32(0xa781bca0) }, + { SPH_C32(0xeb870000), SPH_C32(0x6ceb0000), SPH_C32(0xe0ea0000), + SPH_C32(0x3119ba40), SPH_C32(0xe1f22f25), SPH_C32(0x5c0202c8), + SPH_C32(0xfabc4866), SPH_C32(0x63b62eda), SPH_C32(0x23490000), + SPH_C32(0x98630000), SPH_C32(0x744a0000), SPH_C32(0xfb433660), + SPH_C32(0x274c0d3f), SPH_C32(0x2fff254f), SPH_C32(0x385a5b6f), + SPH_C32(0xf1260d3f) }, + { SPH_C32(0x495b0000), SPH_C32(0x0eb00000), SPH_C32(0xbc600000), + SPH_C32(0x7c94bc80), SPH_C32(0x7a5c7894), SPH_C32(0xd75e27d6), + SPH_C32(0xcb9f6447), SPH_C32(0xac24a30c), SPH_C32(0x26670000), + SPH_C32(0x69e90000), SPH_C32(0x5b0c0000), SPH_C32(0x976134e0), + SPH_C32(0xd197379d), SPH_C32(0x3aeda2c4), SPH_C32(0x630af6dd), + SPH_C32(0x7daa5091) }, + { SPH_C32(0xaf730000), SPH_C32(0x42fb0000), SPH_C32(0x14350000), + SPH_C32(0xaf44be60), SPH_C32(0xa23d482c), SPH_C32(0x4ff9970c), + SPH_C32(0xe30a62f3), SPH_C32(0x7b7eeb9b), SPH_C32(0xd6a20000), + SPH_C32(0x30ca0000), SPH_C32(0x1e8e0000), SPH_C32(0x76ec3420), + SPH_C32(0xeafa31ac), SPH_C32(0xf800f45d), SPH_C32(0xa8ea08c1), + SPH_C32(0x2b0de10e) }, + { SPH_C32(0xb99e0000), SPH_C32(0x57930000), SPH_C32(0xf9e20000), + SPH_C32(0x9d19bc40), SPH_C32(0x41317ea5), SPH_C32(0x15b3714f), + SPH_C32(0x007f9a5b), SPH_C32(0xfa831293), SPH_C32(0x308a0000), + SPH_C32(0x7c810000), SPH_C32(0xb6db0000), SPH_C32(0xa53c36c0), + SPH_C32(0x329b0114), SPH_C32(0x60a74487), SPH_C32(0x807f0e75), + SPH_C32(0xfc57a999) }, + { SPH_C32(0x5fb60000), SPH_C32(0x1bd80000), SPH_C32(0x51b70000), + SPH_C32(0x4ec9bea0), SPH_C32(0x99504e1d), SPH_C32(0x8d14c195), + SPH_C32(0x28ea9cef), SPH_C32(0x2dd95a04), SPH_C32(0xc04f0000), + SPH_C32(0x25a20000), SPH_C32(0xf3590000), SPH_C32(0x44b13600), + SPH_C32(0x09f60725), SPH_C32(0xa24a121e), SPH_C32(0x4b9ff069), + SPH_C32(0xaaf01806) }, + { SPH_C32(0x1c9e0000), SPH_C32(0x66c30000), SPH_C32(0x0d110000), + SPH_C32(0x5fdac000), SPH_C32(0x32596759), SPH_C32(0x8cc0f80c), + SPH_C32(0xaece29ff), SPH_C32(0xc6afe775), SPH_C32(0x288b0000), + SPH_C32(0x0d770000), SPH_C32(0x5db60000), SPH_C32(0x1f991800), + SPH_C32(0x767042e8), SPH_C32(0xdde1a2a3), SPH_C32(0x5b06af40), + SPH_C32(0x19e93cbf) }, + { SPH_C32(0xfab60000), SPH_C32(0x2a880000), SPH_C32(0xa5440000), + SPH_C32(0x8c0ac2e0), SPH_C32(0xea3857e1), SPH_C32(0x146748d6), + SPH_C32(0x865b2f4b), SPH_C32(0x11f5afe2), SPH_C32(0xd84e0000), + SPH_C32(0x54540000), SPH_C32(0x18340000), SPH_C32(0xfe1418c0), + SPH_C32(0x4d1d44d9), SPH_C32(0x1f0cf43a), SPH_C32(0x90e6515c), + SPH_C32(0x4f4e8d20) }, + { SPH_C32(0xec5b0000), SPH_C32(0x3fe00000), SPH_C32(0x48930000), + SPH_C32(0xbe57c0c0), SPH_C32(0x09346168), SPH_C32(0x4e2dae95), + SPH_C32(0x652ed7e3), SPH_C32(0x900856ea), SPH_C32(0x3e660000), + SPH_C32(0x181f0000), SPH_C32(0xb0610000), SPH_C32(0x2dc41a20), + SPH_C32(0x957c7461), SPH_C32(0x87ab44e0), SPH_C32(0xb87357e8), + SPH_C32(0x9814c5b7) }, + { SPH_C32(0x0a730000), SPH_C32(0x73ab0000), SPH_C32(0xe0c60000), + SPH_C32(0x6d87c220), SPH_C32(0xd15551d0), SPH_C32(0xd68a1e4f), + SPH_C32(0x4dbbd157), SPH_C32(0x47521e7d), SPH_C32(0xcea30000), + SPH_C32(0x413c0000), SPH_C32(0xf5e30000), SPH_C32(0xcc491ae0), + SPH_C32(0xae117250), SPH_C32(0x45461279), SPH_C32(0x7393a9f4), + SPH_C32(0xceb37428) }, + { SPH_C32(0xa8af0000), SPH_C32(0x11f00000), SPH_C32(0xbc4c0000), + SPH_C32(0x200ac4e0), SPH_C32(0x4afb0661), SPH_C32(0x5dd63b51), + SPH_C32(0x7c98fd76), SPH_C32(0x88c093ab), SPH_C32(0xcb8d0000), + SPH_C32(0xb0b60000), SPH_C32(0xdaa50000), SPH_C32(0xa06b1860), + SPH_C32(0x58ca48f2), SPH_C32(0x505495f2), SPH_C32(0x28c30446), + SPH_C32(0x423f2986) }, + { SPH_C32(0x4e870000), SPH_C32(0x5dbb0000), SPH_C32(0x14190000), + SPH_C32(0xf3dac600), SPH_C32(0x929a36d9), SPH_C32(0xc5718b8b), + SPH_C32(0x540dfbc2), SPH_C32(0x5f9adb3c), SPH_C32(0x3b480000), + SPH_C32(0xe9950000), SPH_C32(0x9f270000), SPH_C32(0x41e618a0), + SPH_C32(0x63a74ec3), SPH_C32(0x92b9c36b), SPH_C32(0xe323fa5a), + SPH_C32(0x14989819) }, + { SPH_C32(0x586a0000), SPH_C32(0x48d30000), SPH_C32(0xf9ce0000), + SPH_C32(0xc187c420), SPH_C32(0x71960050), SPH_C32(0x9f3b6dc8), + SPH_C32(0xb778036a), SPH_C32(0xde672234), SPH_C32(0xdd600000), + SPH_C32(0xa5de0000), SPH_C32(0x37720000), SPH_C32(0x92361a40), + SPH_C32(0xbbc67e7b), SPH_C32(0x0a1e73b1), SPH_C32(0xcbb6fcee), + SPH_C32(0xc3c2d08e) }, + { SPH_C32(0xbe420000), SPH_C32(0x04980000), SPH_C32(0x519b0000), + SPH_C32(0x1257c6c0), SPH_C32(0xa9f730e8), SPH_C32(0x079cdd12), + SPH_C32(0x9fed05de), SPH_C32(0x093d6aa3), SPH_C32(0x2da50000), + SPH_C32(0xfcfd0000), SPH_C32(0x72f00000), SPH_C32(0x73bb1a80), + SPH_C32(0x80ab784a), SPH_C32(0xc8f32528), SPH_C32(0x005602f2), + SPH_C32(0x95656111) }, + { SPH_C32(0xff980000), SPH_C32(0xdb020000), SPH_C32(0x8a020000), + SPH_C32(0xe028c060), SPH_C32(0x1ce36d43), SPH_C32(0x0175cf5d), + SPH_C32(0xdd0b82f9), SPH_C32(0x9d79f24c), SPH_C32(0x7fbc0000), + SPH_C32(0xc7850000), SPH_C32(0x6bf80000), SPH_C32(0xdfbb1c80), + SPH_C32(0x206829ca), SPH_C32(0x814256af), SPH_C32(0xfa95d0cf), + SPH_C32(0x0c505d58) }, + { SPH_C32(0x19b00000), SPH_C32(0x97490000), SPH_C32(0x22570000), + SPH_C32(0x33f8c280), SPH_C32(0xc4825dfb), SPH_C32(0x99d27f87), + SPH_C32(0xf59e844d), SPH_C32(0x4a23badb), SPH_C32(0x8f790000), + SPH_C32(0x9ea60000), SPH_C32(0x2e7a0000), SPH_C32(0x3e361c40), + SPH_C32(0x1b052ffb), SPH_C32(0x43af0036), SPH_C32(0x31752ed3), + SPH_C32(0x5af7ecc7) }, + { SPH_C32(0x0f5d0000), SPH_C32(0x82210000), SPH_C32(0xcf800000), + SPH_C32(0x01a5c0a0), SPH_C32(0x278e6b72), SPH_C32(0xc39899c4), + SPH_C32(0x16eb7ce5), SPH_C32(0xcbde43d3), SPH_C32(0x69510000), + SPH_C32(0xd2ed0000), SPH_C32(0x862f0000), SPH_C32(0xede61ea0), + SPH_C32(0xc3641f43), SPH_C32(0xdb08b0ec), SPH_C32(0x19e02867), + SPH_C32(0x8dada450) }, + { SPH_C32(0xe9750000), SPH_C32(0xce6a0000), SPH_C32(0x67d50000), + SPH_C32(0xd275c240), SPH_C32(0xffef5bca), SPH_C32(0x5b3f291e), + SPH_C32(0x3e7e7a51), SPH_C32(0x1c840b44), SPH_C32(0x99940000), + SPH_C32(0x8bce0000), SPH_C32(0xc3ad0000), SPH_C32(0x0c6b1e60), + SPH_C32(0xf8091972), SPH_C32(0x19e5e675), SPH_C32(0xd200d67b), + SPH_C32(0xdb0a15cf) }, + { SPH_C32(0x4ba90000), SPH_C32(0xac310000), SPH_C32(0x3b5f0000), + SPH_C32(0x9ff8c480), SPH_C32(0x64410c7b), SPH_C32(0xd0630c00), + SPH_C32(0x0f5d5670), SPH_C32(0xd3168692), SPH_C32(0x9cba0000), + SPH_C32(0x7a440000), SPH_C32(0xeceb0000), SPH_C32(0x60491ce0), + SPH_C32(0x0ed223d0), SPH_C32(0x0cf761fe), SPH_C32(0x89507bc9), + SPH_C32(0x57864861) }, + { SPH_C32(0xad810000), SPH_C32(0xe07a0000), SPH_C32(0x930a0000), + SPH_C32(0x4c28c660), SPH_C32(0xbc203cc3), SPH_C32(0x48c4bcda), + SPH_C32(0x27c850c4), SPH_C32(0x044cce05), SPH_C32(0x6c7f0000), + SPH_C32(0x23670000), SPH_C32(0xa9690000), SPH_C32(0x81c41c20), + SPH_C32(0x35bf25e1), SPH_C32(0xce1a3767), SPH_C32(0x42b085d5), + SPH_C32(0x0121f9fe) }, + { SPH_C32(0xbb6c0000), SPH_C32(0xf5120000), SPH_C32(0x7edd0000), + SPH_C32(0x7e75c440), SPH_C32(0x5f2c0a4a), SPH_C32(0x128e5a99), + SPH_C32(0xc4bda86c), SPH_C32(0x85b1370d), SPH_C32(0x8a570000), + SPH_C32(0x6f2c0000), SPH_C32(0x013c0000), SPH_C32(0x52141ec0), + SPH_C32(0xedde1559), SPH_C32(0x56bd87bd), SPH_C32(0x6a258361), + SPH_C32(0xd67bb169) }, + { SPH_C32(0x5d440000), SPH_C32(0xb9590000), SPH_C32(0xd6880000), + SPH_C32(0xada5c6a0), SPH_C32(0x874d3af2), SPH_C32(0x8a29ea43), + SPH_C32(0xec28aed8), SPH_C32(0x52eb7f9a), SPH_C32(0x7a920000), + SPH_C32(0x360f0000), SPH_C32(0x44be0000), SPH_C32(0xb3991e00), + SPH_C32(0xd6b31368), SPH_C32(0x9450d124), SPH_C32(0xa1c57d7d), + SPH_C32(0x80dc00f6) }, + { SPH_C32(0xa4b10000), SPH_C32(0xd7ef0000), SPH_C32(0x3dc90000), + SPH_C32(0x4b9e9000), SPH_C32(0xf30107fb), SPH_C32(0xbde710e0), + SPH_C32(0x805696dc), SPH_C32(0x93b1da1b), SPH_C32(0x2a790000), + SPH_C32(0xaff60000), SPH_C32(0xda890000), SPH_C32(0xfcf56000), + SPH_C32(0x686d3607), SPH_C32(0xdadc8975), SPH_C32(0x9fc49d77), + SPH_C32(0x66db1921) }, + { SPH_C32(0x42990000), SPH_C32(0x9ba40000), SPH_C32(0x959c0000), + SPH_C32(0x984e92e0), SPH_C32(0x2b603743), SPH_C32(0x2540a03a), + SPH_C32(0xa8c39068), SPH_C32(0x44eb928c), SPH_C32(0xdabc0000), + SPH_C32(0xf6d50000), SPH_C32(0x9f0b0000), SPH_C32(0x1d7860c0), + SPH_C32(0x53003036), SPH_C32(0x1831dfec), SPH_C32(0x5424636b), + SPH_C32(0x307ca8be) }, + { SPH_C32(0x54740000), SPH_C32(0x8ecc0000), SPH_C32(0x784b0000), + SPH_C32(0xaa1390c0), SPH_C32(0xc86c01ca), SPH_C32(0x7f0a4679), + SPH_C32(0x4bb668c0), SPH_C32(0xc5166b84), SPH_C32(0x3c940000), + SPH_C32(0xba9e0000), SPH_C32(0x375e0000), SPH_C32(0xcea86220), + SPH_C32(0x8b61008e), SPH_C32(0x80966f36), SPH_C32(0x7cb165df), + SPH_C32(0xe726e029) }, + { SPH_C32(0xb25c0000), SPH_C32(0xc2870000), SPH_C32(0xd01e0000), + SPH_C32(0x79c39220), SPH_C32(0x100d3172), SPH_C32(0xe7adf6a3), + SPH_C32(0x63236e74), SPH_C32(0x124c2313), SPH_C32(0xcc510000), + SPH_C32(0xe3bd0000), SPH_C32(0x72dc0000), SPH_C32(0x2f2562e0), + SPH_C32(0xb00c06bf), SPH_C32(0x427b39af), SPH_C32(0xb7519bc3), + SPH_C32(0xb18151b6) }, + { SPH_C32(0x10800000), SPH_C32(0xa0dc0000), SPH_C32(0x8c940000), + SPH_C32(0x344e94e0), SPH_C32(0x8ba366c3), SPH_C32(0x6cf1d3bd), + SPH_C32(0x52004255), SPH_C32(0xdddeaec5), SPH_C32(0xc97f0000), + SPH_C32(0x12370000), SPH_C32(0x5d9a0000), SPH_C32(0x43076060), + SPH_C32(0x46d73c1d), SPH_C32(0x5769be24), SPH_C32(0xec013671), + SPH_C32(0x3d0d0c18) }, + { SPH_C32(0xf6a80000), SPH_C32(0xec970000), SPH_C32(0x24c10000), + SPH_C32(0xe79e9600), SPH_C32(0x53c2567b), SPH_C32(0xf4566367), + SPH_C32(0x7a9544e1), SPH_C32(0x0a84e652), SPH_C32(0x39ba0000), + SPH_C32(0x4b140000), SPH_C32(0x18180000), SPH_C32(0xa28a60a0), + SPH_C32(0x7dba3a2c), SPH_C32(0x9584e8bd), SPH_C32(0x27e1c86d), + SPH_C32(0x6baabd87) }, + { SPH_C32(0xe0450000), SPH_C32(0xf9ff0000), SPH_C32(0xc9160000), + SPH_C32(0xd5c39420), SPH_C32(0xb0ce60f2), SPH_C32(0xae1c8524), + SPH_C32(0x99e0bc49), SPH_C32(0x8b791f5a), SPH_C32(0xdf920000), + SPH_C32(0x075f0000), SPH_C32(0xb04d0000), SPH_C32(0x715a6240), + SPH_C32(0xa5db0a94), SPH_C32(0x0d235867), SPH_C32(0x0f74ced9), + SPH_C32(0xbcf0f510) }, + { SPH_C32(0x066d0000), SPH_C32(0xb5b40000), SPH_C32(0x61430000), + SPH_C32(0x061396c0), SPH_C32(0x68af504a), SPH_C32(0x36bb35fe), + SPH_C32(0xb175bafd), SPH_C32(0x5c2357cd), SPH_C32(0x2f570000), + SPH_C32(0x5e7c0000), SPH_C32(0xf5cf0000), SPH_C32(0x90d76280), + SPH_C32(0x9eb60ca5), SPH_C32(0xcfce0efe), SPH_C32(0xc49430c5), + SPH_C32(0xea57448f) }, + { SPH_C32(0x47b70000), SPH_C32(0x6a2e0000), SPH_C32(0xbada0000), + SPH_C32(0xf46c9060), SPH_C32(0xddbb0de1), SPH_C32(0x305227b1), + SPH_C32(0xf3933dda), SPH_C32(0xc867cf22), SPH_C32(0x7d4e0000), + SPH_C32(0x65040000), SPH_C32(0xecc70000), SPH_C32(0x3cd76480), + SPH_C32(0x3e755d25), SPH_C32(0x867f7d79), SPH_C32(0x3e57e2f8), + SPH_C32(0x736278c6) }, + { SPH_C32(0xa19f0000), SPH_C32(0x26650000), SPH_C32(0x128f0000), + SPH_C32(0x27bc9280), SPH_C32(0x05da3d59), SPH_C32(0xa8f5976b), + SPH_C32(0xdb063b6e), SPH_C32(0x1f3d87b5), SPH_C32(0x8d8b0000), + SPH_C32(0x3c270000), SPH_C32(0xa9450000), SPH_C32(0xdd5a6440), + SPH_C32(0x05185b14), SPH_C32(0x44922be0), SPH_C32(0xf5b71ce4), + SPH_C32(0x25c5c959) }, + { SPH_C32(0xb7720000), SPH_C32(0x330d0000), SPH_C32(0xff580000), + SPH_C32(0x15e190a0), SPH_C32(0xe6d60bd0), SPH_C32(0xf2bf7128), + SPH_C32(0x3873c3c6), SPH_C32(0x9ec07ebd), SPH_C32(0x6ba30000), + SPH_C32(0x706c0000), SPH_C32(0x01100000), SPH_C32(0x0e8a66a0), + SPH_C32(0xdd796bac), SPH_C32(0xdc359b3a), SPH_C32(0xdd221a50), + SPH_C32(0xf29f81ce) }, + { SPH_C32(0x515a0000), SPH_C32(0x7f460000), SPH_C32(0x570d0000), + SPH_C32(0xc6319240), SPH_C32(0x3eb73b68), SPH_C32(0x6a18c1f2), + SPH_C32(0x10e6c572), SPH_C32(0x499a362a), SPH_C32(0x9b660000), + SPH_C32(0x294f0000), SPH_C32(0x44920000), SPH_C32(0xef076660), + SPH_C32(0xe6146d9d), SPH_C32(0x1ed8cda3), SPH_C32(0x16c2e44c), + SPH_C32(0xa4383051) }, + { SPH_C32(0xf3860000), SPH_C32(0x1d1d0000), SPH_C32(0x0b870000), + SPH_C32(0x8bbc9480), SPH_C32(0xa5196cd9), SPH_C32(0xe144e4ec), + SPH_C32(0x21c5e953), SPH_C32(0x8608bbfc), SPH_C32(0x9e480000), + SPH_C32(0xd8c50000), SPH_C32(0x6bd40000), SPH_C32(0x832564e0), + SPH_C32(0x10cf573f), SPH_C32(0x0bca4a28), SPH_C32(0x4d9249fe), + SPH_C32(0x28b46dff) }, + { SPH_C32(0x15ae0000), SPH_C32(0x51560000), SPH_C32(0xa3d20000), + SPH_C32(0x586c9660), SPH_C32(0x7d785c61), SPH_C32(0x79e35436), + SPH_C32(0x0950efe7), SPH_C32(0x5152f36b), SPH_C32(0x6e8d0000), + SPH_C32(0x81e60000), SPH_C32(0x2e560000), SPH_C32(0x62a86420), + SPH_C32(0x2ba2510e), SPH_C32(0xc9271cb1), SPH_C32(0x8672b7e2), + SPH_C32(0x7e13dc60) }, + { SPH_C32(0x03430000), SPH_C32(0x443e0000), SPH_C32(0x4e050000), + SPH_C32(0x6a319440), SPH_C32(0x9e746ae8), SPH_C32(0x23a9b275), + SPH_C32(0xea25174f), SPH_C32(0xd0af0a63), SPH_C32(0x88a50000), + SPH_C32(0xcdad0000), SPH_C32(0x86030000), SPH_C32(0xb17866c0), + SPH_C32(0xf3c361b6), SPH_C32(0x5180ac6b), SPH_C32(0xaee7b156), + SPH_C32(0xa94994f7) }, + { SPH_C32(0xe56b0000), SPH_C32(0x08750000), SPH_C32(0xe6500000), + SPH_C32(0xb9e196a0), SPH_C32(0x46155a50), SPH_C32(0xbb0e02af), + SPH_C32(0xc2b011fb), SPH_C32(0x07f542f4), SPH_C32(0x78600000), + SPH_C32(0x948e0000), SPH_C32(0xc3810000), SPH_C32(0x50f56600), + SPH_C32(0xc8ae6787), SPH_C32(0x936dfaf2), SPH_C32(0x65074f4a), + SPH_C32(0xffee2568) }, + { SPH_C32(0xa6430000), SPH_C32(0x756e0000), SPH_C32(0xbaf60000), + SPH_C32(0xa8f2e800), SPH_C32(0xed1c7314), SPH_C32(0xbada3b36), + SPH_C32(0x4494a4eb), SPH_C32(0xec83ff85), SPH_C32(0x90a40000), + SPH_C32(0xbc5b0000), SPH_C32(0x6d6e0000), SPH_C32(0x0bdd4800), + SPH_C32(0xb728224a), SPH_C32(0xecc64a4f), SPH_C32(0x759e1063), + SPH_C32(0x4cf701d1) }, + { SPH_C32(0x406b0000), SPH_C32(0x39250000), SPH_C32(0x12a30000), + SPH_C32(0x7b22eae0), SPH_C32(0x357d43ac), SPH_C32(0x227d8bec), + SPH_C32(0x6c01a25f), SPH_C32(0x3bd9b712), SPH_C32(0x60610000), + SPH_C32(0xe5780000), SPH_C32(0x28ec0000), SPH_C32(0xea5048c0), + SPH_C32(0x8c45247b), SPH_C32(0x2e2b1cd6), SPH_C32(0xbe7eee7f), + SPH_C32(0x1a50b04e) }, + { SPH_C32(0x56860000), SPH_C32(0x2c4d0000), SPH_C32(0xff740000), + SPH_C32(0x497fe8c0), SPH_C32(0xd6717525), SPH_C32(0x78376daf), + SPH_C32(0x8f745af7), SPH_C32(0xba244e1a), SPH_C32(0x86490000), + SPH_C32(0xa9330000), SPH_C32(0x80b90000), SPH_C32(0x39804a20), + SPH_C32(0x542414c3), SPH_C32(0xb68cac0c), SPH_C32(0x96ebe8cb), + SPH_C32(0xcd0af8d9) }, + { SPH_C32(0xb0ae0000), SPH_C32(0x60060000), SPH_C32(0x57210000), + SPH_C32(0x9aafea20), SPH_C32(0x0e10459d), SPH_C32(0xe090dd75), + SPH_C32(0xa7e15c43), SPH_C32(0x6d7e068d), SPH_C32(0x768c0000), + SPH_C32(0xf0100000), SPH_C32(0xc53b0000), SPH_C32(0xd80d4ae0), + SPH_C32(0x6f4912f2), SPH_C32(0x7461fa95), SPH_C32(0x5d0b16d7), + SPH_C32(0x9bad4946) }, + { SPH_C32(0x12720000), SPH_C32(0x025d0000), SPH_C32(0x0bab0000), + SPH_C32(0xd722ece0), SPH_C32(0x95be122c), SPH_C32(0x6bccf86b), + SPH_C32(0x96c27062), SPH_C32(0xa2ec8b5b), SPH_C32(0x73a20000), + SPH_C32(0x019a0000), SPH_C32(0xea7d0000), SPH_C32(0xb42f4860), + SPH_C32(0x99922850), SPH_C32(0x61737d1e), SPH_C32(0x065bbb65), + SPH_C32(0x172114e8) }, + { SPH_C32(0xf45a0000), SPH_C32(0x4e160000), SPH_C32(0xa3fe0000), + SPH_C32(0x04f2ee00), SPH_C32(0x4ddf2294), SPH_C32(0xf36b48b1), + SPH_C32(0xbe5776d6), SPH_C32(0x75b6c3cc), SPH_C32(0x83670000), + SPH_C32(0x58b90000), SPH_C32(0xafff0000), SPH_C32(0x55a248a0), + SPH_C32(0xa2ff2e61), SPH_C32(0xa39e2b87), SPH_C32(0xcdbb4579), + SPH_C32(0x4186a577) }, + { SPH_C32(0xe2b70000), SPH_C32(0x5b7e0000), SPH_C32(0x4e290000), + SPH_C32(0x36afec20), SPH_C32(0xaed3141d), SPH_C32(0xa921aef2), + SPH_C32(0x5d228e7e), SPH_C32(0xf44b3ac4), SPH_C32(0x654f0000), + SPH_C32(0x14f20000), SPH_C32(0x07aa0000), SPH_C32(0x86724a40), + SPH_C32(0x7a9e1ed9), SPH_C32(0x3b399b5d), SPH_C32(0xe52e43cd), + SPH_C32(0x96dcede0) }, + { SPH_C32(0x049f0000), SPH_C32(0x17350000), SPH_C32(0xe67c0000), + SPH_C32(0xe57feec0), SPH_C32(0x76b224a5), SPH_C32(0x31861e28), + SPH_C32(0x75b788ca), SPH_C32(0x23117253), SPH_C32(0x958a0000), + SPH_C32(0x4dd10000), SPH_C32(0x42280000), SPH_C32(0x67ff4a80), + SPH_C32(0x41f318e8), SPH_C32(0xf9d4cdc4), SPH_C32(0x2ecebdd1), + SPH_C32(0xc07b5c7f) }, + { SPH_C32(0x45450000), SPH_C32(0xc8af0000), SPH_C32(0x3de50000), + SPH_C32(0x1700e860), SPH_C32(0xc3a6790e), SPH_C32(0x376f0c67), + SPH_C32(0x37510fed), SPH_C32(0xb755eabc), SPH_C32(0xc7930000), + SPH_C32(0x76a90000), SPH_C32(0x5b200000), SPH_C32(0xcbff4c80), + SPH_C32(0xe1304968), SPH_C32(0xb065be43), SPH_C32(0xd40d6fec), + SPH_C32(0x594e6036) }, + { SPH_C32(0xa36d0000), SPH_C32(0x84e40000), SPH_C32(0x95b00000), + SPH_C32(0xc4d0ea80), SPH_C32(0x1bc749b6), SPH_C32(0xafc8bcbd), + SPH_C32(0x1fc40959), SPH_C32(0x600fa22b), SPH_C32(0x37560000), + SPH_C32(0x2f8a0000), SPH_C32(0x1ea20000), SPH_C32(0x2a724c40), + SPH_C32(0xda5d4f59), SPH_C32(0x7288e8da), SPH_C32(0x1fed91f0), + SPH_C32(0x0fe9d1a9) }, + { SPH_C32(0xb5800000), SPH_C32(0x918c0000), SPH_C32(0x78670000), + SPH_C32(0xf68de8a0), SPH_C32(0xf8cb7f3f), SPH_C32(0xf5825afe), + SPH_C32(0xfcb1f1f1), SPH_C32(0xe1f25b23), SPH_C32(0xd17e0000), + SPH_C32(0x63c10000), SPH_C32(0xb6f70000), SPH_C32(0xf9a24ea0), + SPH_C32(0x023c7fe1), SPH_C32(0xea2f5800), SPH_C32(0x37789744), + SPH_C32(0xd8b3993e) }, + { SPH_C32(0x53a80000), SPH_C32(0xddc70000), SPH_C32(0xd0320000), + SPH_C32(0x255dea40), SPH_C32(0x20aa4f87), SPH_C32(0x6d25ea24), + SPH_C32(0xd424f745), SPH_C32(0x36a813b4), SPH_C32(0x21bb0000), + SPH_C32(0x3ae20000), SPH_C32(0xf3750000), SPH_C32(0x182f4e60), + SPH_C32(0x395179d0), SPH_C32(0x28c20e99), SPH_C32(0xfc986958), + SPH_C32(0x8e1428a1) }, + { SPH_C32(0xf1740000), SPH_C32(0xbf9c0000), SPH_C32(0x8cb80000), + SPH_C32(0x68d0ec80), SPH_C32(0xbb041836), SPH_C32(0xe679cf3a), + SPH_C32(0xe507db64), SPH_C32(0xf93a9e62), SPH_C32(0x24950000), + SPH_C32(0xcb680000), SPH_C32(0xdc330000), SPH_C32(0x740d4ce0), + SPH_C32(0xcf8a4372), SPH_C32(0x3dd08912), SPH_C32(0xa7c8c4ea), + SPH_C32(0x0298750f) }, + { SPH_C32(0x175c0000), SPH_C32(0xf3d70000), SPH_C32(0x24ed0000), + SPH_C32(0xbb00ee60), SPH_C32(0x6365288e), SPH_C32(0x7ede7fe0), + SPH_C32(0xcd92ddd0), SPH_C32(0x2e60d6f5), SPH_C32(0xd4500000), + SPH_C32(0x924b0000), SPH_C32(0x99b10000), SPH_C32(0x95804c20), + SPH_C32(0xf4e74543), SPH_C32(0xff3ddf8b), SPH_C32(0x6c283af6), + SPH_C32(0x543fc490) }, + { SPH_C32(0x01b10000), SPH_C32(0xe6bf0000), SPH_C32(0xc93a0000), + SPH_C32(0x895dec40), SPH_C32(0x80691e07), SPH_C32(0x249499a3), + SPH_C32(0x2ee72578), SPH_C32(0xaf9d2ffd), SPH_C32(0x32780000), + SPH_C32(0xde000000), SPH_C32(0x31e40000), SPH_C32(0x46504ec0), + SPH_C32(0x2c8675fb), SPH_C32(0x679a6f51), SPH_C32(0x44bd3c42), + SPH_C32(0x83658c07) }, + { SPH_C32(0xe7990000), SPH_C32(0xaaf40000), SPH_C32(0x616f0000), + SPH_C32(0x5a8deea0), SPH_C32(0x58082ebf), SPH_C32(0xbc332979), + SPH_C32(0x067223cc), SPH_C32(0x78c7676a), SPH_C32(0xc2bd0000), + SPH_C32(0x87230000), SPH_C32(0x74660000), SPH_C32(0xa7dd4e00), + SPH_C32(0x17eb73ca), SPH_C32(0xa57739c8), SPH_C32(0x8f5dc25e), + SPH_C32(0xd5c23d98) } +}; + +static const sph_u32 T512_56[128][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0xa8da0000), SPH_C32(0x96be0000), SPH_C32(0x5c1d0000), + SPH_C32(0x07da0002), SPH_C32(0x7d669583), SPH_C32(0x1f98708a), + SPH_C32(0xbb668808), SPH_C32(0xda878000), SPH_C32(0xabe70000), + SPH_C32(0x9e0d0000), SPH_C32(0xaf270000), SPH_C32(0x3d180005), + SPH_C32(0x2c4f1fd3), SPH_C32(0x74f61695), SPH_C32(0xb5c347eb), + SPH_C32(0x3c5dfffe) }, + { SPH_C32(0x01930000), SPH_C32(0xe7820000), SPH_C32(0xedfb0000), + SPH_C32(0xcf0c000b), SPH_C32(0x8dd08d58), SPH_C32(0xbca3b42e), + SPH_C32(0x063661e1), SPH_C32(0x536f9e7b), SPH_C32(0x92280000), + SPH_C32(0xdc850000), SPH_C32(0x57fa0000), SPH_C32(0x56dc0003), + SPH_C32(0xbae92316), SPH_C32(0x5aefa30c), SPH_C32(0x90cef752), + SPH_C32(0x7b1675d7) }, + { SPH_C32(0xa9490000), SPH_C32(0x713c0000), SPH_C32(0xb1e60000), + SPH_C32(0xc8d60009), SPH_C32(0xf0b618db), SPH_C32(0xa33bc4a4), + SPH_C32(0xbd50e9e9), SPH_C32(0x89e81e7b), SPH_C32(0x39cf0000), + SPH_C32(0x42880000), SPH_C32(0xf8dd0000), SPH_C32(0x6bc40006), + SPH_C32(0x96a63cc5), SPH_C32(0x2e19b599), SPH_C32(0x250db0b9), + SPH_C32(0x474b8a29) }, + { SPH_C32(0x92280000), SPH_C32(0xdc850000), SPH_C32(0x57fa0000), + SPH_C32(0x56dc0003), SPH_C32(0xbae92316), SPH_C32(0x5aefa30c), + SPH_C32(0x90cef752), SPH_C32(0x7b1675d7), SPH_C32(0x93bb0000), + SPH_C32(0x3b070000), SPH_C32(0xba010000), SPH_C32(0x99d00008), + SPH_C32(0x3739ae4e), SPH_C32(0xe64c1722), SPH_C32(0x96f896b3), + SPH_C32(0x2879ebac) }, + { SPH_C32(0x3af20000), SPH_C32(0x4a3b0000), SPH_C32(0x0be70000), + SPH_C32(0x51060001), SPH_C32(0xc78fb695), SPH_C32(0x4577d386), + SPH_C32(0x2ba87f5a), SPH_C32(0xa191f5d7), SPH_C32(0x385c0000), + SPH_C32(0xa50a0000), SPH_C32(0x15260000), SPH_C32(0xa4c8000d), + SPH_C32(0x1b76b19d), SPH_C32(0x92ba01b7), SPH_C32(0x233bd158), + SPH_C32(0x14241452) }, + { SPH_C32(0x93bb0000), SPH_C32(0x3b070000), SPH_C32(0xba010000), + SPH_C32(0x99d00008), SPH_C32(0x3739ae4e), SPH_C32(0xe64c1722), + SPH_C32(0x96f896b3), SPH_C32(0x2879ebac), SPH_C32(0x01930000), + SPH_C32(0xe7820000), SPH_C32(0xedfb0000), SPH_C32(0xcf0c000b), + SPH_C32(0x8dd08d58), SPH_C32(0xbca3b42e), SPH_C32(0x063661e1), + SPH_C32(0x536f9e7b) }, + { SPH_C32(0x3b610000), SPH_C32(0xadb90000), SPH_C32(0xe61c0000), + SPH_C32(0x9e0a000a), SPH_C32(0x4a5f3bcd), SPH_C32(0xf9d467a8), + SPH_C32(0x2d9e1ebb), SPH_C32(0xf2fe6bac), SPH_C32(0xaa740000), + SPH_C32(0x798f0000), SPH_C32(0x42dc0000), SPH_C32(0xf214000e), + SPH_C32(0xa19f928b), SPH_C32(0xc855a2bb), SPH_C32(0xb3f5260a), + SPH_C32(0x6f326185) }, + { SPH_C32(0x5fa80000), SPH_C32(0x56030000), SPH_C32(0x43ae0000), + SPH_C32(0x64f30013), SPH_C32(0x257e86bf), SPH_C32(0x1311944e), + SPH_C32(0x541e95bf), SPH_C32(0x8ea4db69), SPH_C32(0x00440000), + SPH_C32(0x7f480000), SPH_C32(0xda7c0000), SPH_C32(0x2a230001), + SPH_C32(0x3badc9cc), SPH_C32(0xa9b69c87), SPH_C32(0x030a9e60), + SPH_C32(0xbe0a679e) }, + { SPH_C32(0xf7720000), SPH_C32(0xc0bd0000), SPH_C32(0x1fb30000), + SPH_C32(0x63290011), SPH_C32(0x5818133c), SPH_C32(0x0c89e4c4), + SPH_C32(0xef781db7), SPH_C32(0x54235b69), SPH_C32(0xaba30000), + SPH_C32(0xe1450000), SPH_C32(0x755b0000), SPH_C32(0x173b0004), + SPH_C32(0x17e2d61f), SPH_C32(0xdd408a12), SPH_C32(0xb6c9d98b), + SPH_C32(0x82579860) }, + { SPH_C32(0x5e3b0000), SPH_C32(0xb1810000), SPH_C32(0xae550000), + SPH_C32(0xabff0018), SPH_C32(0xa8ae0be7), SPH_C32(0xafb22060), + SPH_C32(0x5228f45e), SPH_C32(0xddcb4512), SPH_C32(0x926c0000), + SPH_C32(0xa3cd0000), SPH_C32(0x8d860000), SPH_C32(0x7cff0002), + SPH_C32(0x8144eada), SPH_C32(0xf3593f8b), SPH_C32(0x93c46932), + SPH_C32(0xc51c1249) }, + { SPH_C32(0xf6e10000), SPH_C32(0x273f0000), SPH_C32(0xf2480000), + SPH_C32(0xac25001a), SPH_C32(0xd5c89e64), SPH_C32(0xb02a50ea), + SPH_C32(0xe94e7c56), SPH_C32(0x074cc512), SPH_C32(0x398b0000), + SPH_C32(0x3dc00000), SPH_C32(0x22a10000), SPH_C32(0x41e70007), + SPH_C32(0xad0bf509), SPH_C32(0x87af291e), SPH_C32(0x26072ed9), + SPH_C32(0xf941edb7) }, + { SPH_C32(0xcd800000), SPH_C32(0x8a860000), SPH_C32(0x14540000), + SPH_C32(0x322f0010), SPH_C32(0x9f97a5a9), SPH_C32(0x49fe3742), + SPH_C32(0xc4d062ed), SPH_C32(0xf5b2aebe), SPH_C32(0x93ff0000), + SPH_C32(0x444f0000), SPH_C32(0x607d0000), SPH_C32(0xb3f30009), + SPH_C32(0x0c946782), SPH_C32(0x4ffa8ba5), SPH_C32(0x95f208d3), + SPH_C32(0x96738c32) }, + { SPH_C32(0x655a0000), SPH_C32(0x1c380000), SPH_C32(0x48490000), + SPH_C32(0x35f50012), SPH_C32(0xe2f1302a), SPH_C32(0x566647c8), + SPH_C32(0x7fb6eae5), SPH_C32(0x2f352ebe), SPH_C32(0x38180000), + SPH_C32(0xda420000), SPH_C32(0xcf5a0000), SPH_C32(0x8eeb000c), + SPH_C32(0x20db7851), SPH_C32(0x3b0c9d30), SPH_C32(0x20314f38), + SPH_C32(0xaa2e73cc) }, + { SPH_C32(0xcc130000), SPH_C32(0x6d040000), SPH_C32(0xf9af0000), + SPH_C32(0xfd23001b), SPH_C32(0x124728f1), SPH_C32(0xf55d836c), + SPH_C32(0xc2e6030c), SPH_C32(0xa6dd30c5), SPH_C32(0x01d70000), + SPH_C32(0x98ca0000), SPH_C32(0x37870000), SPH_C32(0xe52f000a), + SPH_C32(0xb67d4494), SPH_C32(0x151528a9), SPH_C32(0x053cff81), + SPH_C32(0xed65f9e5) }, + { SPH_C32(0x64c90000), SPH_C32(0xfbba0000), SPH_C32(0xa5b20000), + SPH_C32(0xfaf90019), SPH_C32(0x6f21bd72), SPH_C32(0xeac5f3e6), + SPH_C32(0x79808b04), SPH_C32(0x7c5ab0c5), SPH_C32(0xaa300000), + SPH_C32(0x06c70000), SPH_C32(0x98a00000), SPH_C32(0xd837000f), + SPH_C32(0x9a325b47), SPH_C32(0x61e33e3c), SPH_C32(0xb0ffb86a), + SPH_C32(0xd138061b) }, + { SPH_C32(0x00440000), SPH_C32(0x7f480000), SPH_C32(0xda7c0000), + SPH_C32(0x2a230001), SPH_C32(0x3badc9cc), SPH_C32(0xa9b69c87), + SPH_C32(0x030a9e60), SPH_C32(0xbe0a679e), SPH_C32(0x5fec0000), + SPH_C32(0x294b0000), SPH_C32(0x99d20000), SPH_C32(0x4ed00012), + SPH_C32(0x1ed34f73), SPH_C32(0xbaa708c9), SPH_C32(0x57140bdf), + SPH_C32(0x30aebcf7) }, + { SPH_C32(0xa89e0000), SPH_C32(0xe9f60000), SPH_C32(0x86610000), + SPH_C32(0x2df90003), SPH_C32(0x46cb5c4f), SPH_C32(0xb62eec0d), + SPH_C32(0xb86c1668), SPH_C32(0x648de79e), SPH_C32(0xf40b0000), + SPH_C32(0xb7460000), SPH_C32(0x36f50000), SPH_C32(0x73c80017), + SPH_C32(0x329c50a0), SPH_C32(0xce511e5c), SPH_C32(0xe2d74c34), + SPH_C32(0x0cf34309) }, + { SPH_C32(0x01d70000), SPH_C32(0x98ca0000), SPH_C32(0x37870000), + SPH_C32(0xe52f000a), SPH_C32(0xb67d4494), SPH_C32(0x151528a9), + SPH_C32(0x053cff81), SPH_C32(0xed65f9e5), SPH_C32(0xcdc40000), + SPH_C32(0xf5ce0000), SPH_C32(0xce280000), SPH_C32(0x180c0011), + SPH_C32(0xa43a6c65), SPH_C32(0xe048abc5), SPH_C32(0xc7dafc8d), + SPH_C32(0x4bb8c920) }, + { SPH_C32(0xa90d0000), SPH_C32(0x0e740000), SPH_C32(0x6b9a0000), + SPH_C32(0xe2f50008), SPH_C32(0xcb1bd117), SPH_C32(0x0a8d5823), + SPH_C32(0xbe5a7789), SPH_C32(0x37e279e5), SPH_C32(0x66230000), + SPH_C32(0x6bc30000), SPH_C32(0x610f0000), SPH_C32(0x25140014), + SPH_C32(0x887573b6), SPH_C32(0x94bebd50), SPH_C32(0x7219bb66), + SPH_C32(0x77e536de) }, + { SPH_C32(0x926c0000), SPH_C32(0xa3cd0000), SPH_C32(0x8d860000), + SPH_C32(0x7cff0002), SPH_C32(0x8144eada), SPH_C32(0xf3593f8b), + SPH_C32(0x93c46932), SPH_C32(0xc51c1249), SPH_C32(0xcc570000), + SPH_C32(0x124c0000), SPH_C32(0x23d30000), SPH_C32(0xd700001a), + SPH_C32(0x29eae13d), SPH_C32(0x5ceb1feb), SPH_C32(0xc1ec9d6c), + SPH_C32(0x18d7575b) }, + { SPH_C32(0x3ab60000), SPH_C32(0x35730000), SPH_C32(0xd19b0000), + SPH_C32(0x7b250000), SPH_C32(0xfc227f59), SPH_C32(0xecc14f01), + SPH_C32(0x28a2e13a), SPH_C32(0x1f9b9249), SPH_C32(0x67b00000), + SPH_C32(0x8c410000), SPH_C32(0x8cf40000), SPH_C32(0xea18001f), + SPH_C32(0x05a5feee), SPH_C32(0x281d097e), SPH_C32(0x742fda87), + SPH_C32(0x248aa8a5) }, + { SPH_C32(0x93ff0000), SPH_C32(0x444f0000), SPH_C32(0x607d0000), + SPH_C32(0xb3f30009), SPH_C32(0x0c946782), SPH_C32(0x4ffa8ba5), + SPH_C32(0x95f208d3), SPH_C32(0x96738c32), SPH_C32(0x5e7f0000), + SPH_C32(0xcec90000), SPH_C32(0x74290000), SPH_C32(0x81dc0019), + SPH_C32(0x9303c22b), SPH_C32(0x0604bce7), SPH_C32(0x51226a3e), + SPH_C32(0x63c1228c) }, + { SPH_C32(0x3b250000), SPH_C32(0xd2f10000), SPH_C32(0x3c600000), + SPH_C32(0xb429000b), SPH_C32(0x71f2f201), SPH_C32(0x5062fb2f), + SPH_C32(0x2e9480db), SPH_C32(0x4cf40c32), SPH_C32(0xf5980000), + SPH_C32(0x50c40000), SPH_C32(0xdb0e0000), SPH_C32(0xbcc4001c), + SPH_C32(0xbf4cddf8), SPH_C32(0x72f2aa72), SPH_C32(0xe4e12dd5), + SPH_C32(0x5f9cdd72) }, + { SPH_C32(0x5fec0000), SPH_C32(0x294b0000), SPH_C32(0x99d20000), + SPH_C32(0x4ed00012), SPH_C32(0x1ed34f73), SPH_C32(0xbaa708c9), + SPH_C32(0x57140bdf), SPH_C32(0x30aebcf7), SPH_C32(0x5fa80000), + SPH_C32(0x56030000), SPH_C32(0x43ae0000), SPH_C32(0x64f30013), + SPH_C32(0x257e86bf), SPH_C32(0x1311944e), SPH_C32(0x541e95bf), + SPH_C32(0x8ea4db69) }, + { SPH_C32(0xf7360000), SPH_C32(0xbff50000), SPH_C32(0xc5cf0000), + SPH_C32(0x490a0010), SPH_C32(0x63b5daf0), SPH_C32(0xa53f7843), + SPH_C32(0xec7283d7), SPH_C32(0xea293cf7), SPH_C32(0xf44f0000), + SPH_C32(0xc80e0000), SPH_C32(0xec890000), SPH_C32(0x59eb0016), + SPH_C32(0x0931996c), SPH_C32(0x67e782db), SPH_C32(0xe1ddd254), + SPH_C32(0xb2f92497) }, + { SPH_C32(0x5e7f0000), SPH_C32(0xcec90000), SPH_C32(0x74290000), + SPH_C32(0x81dc0019), SPH_C32(0x9303c22b), SPH_C32(0x0604bce7), + SPH_C32(0x51226a3e), SPH_C32(0x63c1228c), SPH_C32(0xcd800000), + SPH_C32(0x8a860000), SPH_C32(0x14540000), SPH_C32(0x322f0010), + SPH_C32(0x9f97a5a9), SPH_C32(0x49fe3742), SPH_C32(0xc4d062ed), + SPH_C32(0xf5b2aebe) }, + { SPH_C32(0xf6a50000), SPH_C32(0x58770000), SPH_C32(0x28340000), + SPH_C32(0x8606001b), SPH_C32(0xee6557a8), SPH_C32(0x199ccc6d), + SPH_C32(0xea44e236), SPH_C32(0xb946a28c), SPH_C32(0x66670000), + SPH_C32(0x148b0000), SPH_C32(0xbb730000), SPH_C32(0x0f370015), + SPH_C32(0xb3d8ba7a), SPH_C32(0x3d0821d7), SPH_C32(0x71132506), + SPH_C32(0xc9ef5140) }, + { SPH_C32(0xcdc40000), SPH_C32(0xf5ce0000), SPH_C32(0xce280000), + SPH_C32(0x180c0011), SPH_C32(0xa43a6c65), SPH_C32(0xe048abc5), + SPH_C32(0xc7dafc8d), SPH_C32(0x4bb8c920), SPH_C32(0xcc130000), + SPH_C32(0x6d040000), SPH_C32(0xf9af0000), SPH_C32(0xfd23001b), + SPH_C32(0x124728f1), SPH_C32(0xf55d836c), SPH_C32(0xc2e6030c), + SPH_C32(0xa6dd30c5) }, + { SPH_C32(0x651e0000), SPH_C32(0x63700000), SPH_C32(0x92350000), + SPH_C32(0x1fd60013), SPH_C32(0xd95cf9e6), SPH_C32(0xffd0db4f), + SPH_C32(0x7cbc7485), SPH_C32(0x913f4920), SPH_C32(0x67f40000), + SPH_C32(0xf3090000), SPH_C32(0x56880000), SPH_C32(0xc03b001e), + SPH_C32(0x3e083722), SPH_C32(0x81ab95f9), SPH_C32(0x772544e7), + SPH_C32(0x9a80cf3b) }, + { SPH_C32(0xcc570000), SPH_C32(0x124c0000), SPH_C32(0x23d30000), + SPH_C32(0xd700001a), SPH_C32(0x29eae13d), SPH_C32(0x5ceb1feb), + SPH_C32(0xc1ec9d6c), SPH_C32(0x18d7575b), SPH_C32(0x5e3b0000), + SPH_C32(0xb1810000), SPH_C32(0xae550000), SPH_C32(0xabff0018), + SPH_C32(0xa8ae0be7), SPH_C32(0xafb22060), SPH_C32(0x5228f45e), + SPH_C32(0xddcb4512) }, + { SPH_C32(0x648d0000), SPH_C32(0x84f20000), SPH_C32(0x7fce0000), + SPH_C32(0xd0da0018), SPH_C32(0x548c74be), SPH_C32(0x43736f61), + SPH_C32(0x7a8a1564), SPH_C32(0xc250d75b), SPH_C32(0xf5dc0000), + SPH_C32(0x2f8c0000), SPH_C32(0x01720000), SPH_C32(0x96e7001d), + SPH_C32(0x84e11434), SPH_C32(0xdb4436f5), SPH_C32(0xe7ebb3b5), + SPH_C32(0xe196baec) }, + { SPH_C32(0xee930000), SPH_C32(0xd6070000), SPH_C32(0x92c10000), + SPH_C32(0x2b9801e0), SPH_C32(0x9451287c), SPH_C32(0x3b6cfb57), + SPH_C32(0x45312374), SPH_C32(0x201f6a64), SPH_C32(0x7b280000), + SPH_C32(0x57420000), SPH_C32(0xa9e50000), SPH_C32(0x634300a0), + SPH_C32(0x9edb442f), SPH_C32(0x6d9995bb), SPH_C32(0x27f83b03), + SPH_C32(0xc7ff60f0) }, + { SPH_C32(0x46490000), SPH_C32(0x40b90000), SPH_C32(0xcedc0000), + SPH_C32(0x2c4201e2), SPH_C32(0xe937bdff), SPH_C32(0x24f48bdd), + SPH_C32(0xfe57ab7c), SPH_C32(0xfa98ea64), SPH_C32(0xd0cf0000), + SPH_C32(0xc94f0000), SPH_C32(0x06c20000), SPH_C32(0x5e5b00a5), + SPH_C32(0xb2945bfc), SPH_C32(0x196f832e), SPH_C32(0x923b7ce8), + SPH_C32(0xfba29f0e) }, + { SPH_C32(0xef000000), SPH_C32(0x31850000), SPH_C32(0x7f3a0000), + SPH_C32(0xe49401eb), SPH_C32(0x1981a524), SPH_C32(0x87cf4f79), + SPH_C32(0x43074295), SPH_C32(0x7370f41f), SPH_C32(0xe9000000), + SPH_C32(0x8bc70000), SPH_C32(0xfe1f0000), SPH_C32(0x359f00a3), + SPH_C32(0x24326739), SPH_C32(0x377636b7), SPH_C32(0xb736cc51), + SPH_C32(0xbce91527) }, + { SPH_C32(0x47da0000), SPH_C32(0xa73b0000), SPH_C32(0x23270000), + SPH_C32(0xe34e01e9), SPH_C32(0x64e730a7), SPH_C32(0x98573ff3), + SPH_C32(0xf861ca9d), SPH_C32(0xa9f7741f), SPH_C32(0x42e70000), + SPH_C32(0x15ca0000), SPH_C32(0x51380000), SPH_C32(0x088700a6), + SPH_C32(0x087d78ea), SPH_C32(0x43802022), SPH_C32(0x02f58bba), + SPH_C32(0x80b4ead9) }, + { SPH_C32(0x7cbb0000), SPH_C32(0x0a820000), SPH_C32(0xc53b0000), + SPH_C32(0x7d4401e3), SPH_C32(0x2eb80b6a), SPH_C32(0x6183585b), + SPH_C32(0xd5ffd426), SPH_C32(0x5b091fb3), SPH_C32(0xe8930000), + SPH_C32(0x6c450000), SPH_C32(0x13e40000), SPH_C32(0xfa9300a8), + SPH_C32(0xa9e2ea61), SPH_C32(0x8bd58299), SPH_C32(0xb100adb0), + SPH_C32(0xef868b5c) }, + { SPH_C32(0xd4610000), SPH_C32(0x9c3c0000), SPH_C32(0x99260000), + SPH_C32(0x7a9e01e1), SPH_C32(0x53de9ee9), SPH_C32(0x7e1b28d1), + SPH_C32(0x6e995c2e), SPH_C32(0x818e9fb3), SPH_C32(0x43740000), + SPH_C32(0xf2480000), SPH_C32(0xbcc30000), SPH_C32(0xc78b00ad), + SPH_C32(0x85adf5b2), SPH_C32(0xff23940c), SPH_C32(0x04c3ea5b), + SPH_C32(0xd3db74a2) }, + { SPH_C32(0x7d280000), SPH_C32(0xed000000), SPH_C32(0x28c00000), + SPH_C32(0xb24801e8), SPH_C32(0xa3688632), SPH_C32(0xdd20ec75), + SPH_C32(0xd3c9b5c7), SPH_C32(0x086681c8), SPH_C32(0x7abb0000), + SPH_C32(0xb0c00000), SPH_C32(0x441e0000), SPH_C32(0xac4f00ab), + SPH_C32(0x130bc977), SPH_C32(0xd13a2195), SPH_C32(0x21ce5ae2), + SPH_C32(0x9490fe8b) }, + { SPH_C32(0xd5f20000), SPH_C32(0x7bbe0000), SPH_C32(0x74dd0000), + SPH_C32(0xb59201ea), SPH_C32(0xde0e13b1), SPH_C32(0xc2b89cff), + SPH_C32(0x68af3dcf), SPH_C32(0xd2e101c8), SPH_C32(0xd15c0000), + SPH_C32(0x2ecd0000), SPH_C32(0xeb390000), SPH_C32(0x915700ae), + SPH_C32(0x3f44d6a4), SPH_C32(0xa5cc3700), SPH_C32(0x940d1d09), + SPH_C32(0xa8cd0175) }, + { SPH_C32(0xb13b0000), SPH_C32(0x80040000), SPH_C32(0xd16f0000), + SPH_C32(0x4f6b01f3), SPH_C32(0xb12faec3), SPH_C32(0x287d6f19), + SPH_C32(0x112fb6cb), SPH_C32(0xaebbb10d), SPH_C32(0x7b6c0000), + SPH_C32(0x280a0000), SPH_C32(0x73990000), SPH_C32(0x496000a1), + SPH_C32(0xa5768de3), SPH_C32(0xc42f093c), SPH_C32(0x24f2a563), + SPH_C32(0x79f5076e) }, + { SPH_C32(0x19e10000), SPH_C32(0x16ba0000), SPH_C32(0x8d720000), + SPH_C32(0x48b101f1), SPH_C32(0xcc493b40), SPH_C32(0x37e51f93), + SPH_C32(0xaa493ec3), SPH_C32(0x743c310d), SPH_C32(0xd08b0000), + SPH_C32(0xb6070000), SPH_C32(0xdcbe0000), SPH_C32(0x747800a4), + SPH_C32(0x89399230), SPH_C32(0xb0d91fa9), SPH_C32(0x9131e288), + SPH_C32(0x45a8f890) }, + { SPH_C32(0xb0a80000), SPH_C32(0x67860000), SPH_C32(0x3c940000), + SPH_C32(0x806701f8), SPH_C32(0x3cff239b), SPH_C32(0x94dedb37), + SPH_C32(0x1719d72a), SPH_C32(0xfdd42f76), SPH_C32(0xe9440000), + SPH_C32(0xf48f0000), SPH_C32(0x24630000), SPH_C32(0x1fbc00a2), + SPH_C32(0x1f9faef5), SPH_C32(0x9ec0aa30), SPH_C32(0xb43c5231), + SPH_C32(0x02e372b9) }, + { SPH_C32(0x18720000), SPH_C32(0xf1380000), SPH_C32(0x60890000), + SPH_C32(0x87bd01fa), SPH_C32(0x4199b618), SPH_C32(0x8b46abbd), + SPH_C32(0xac7f5f22), SPH_C32(0x2753af76), SPH_C32(0x42a30000), + SPH_C32(0x6a820000), SPH_C32(0x8b440000), SPH_C32(0x22a400a7), + SPH_C32(0x33d0b126), SPH_C32(0xea36bca5), SPH_C32(0x01ff15da), + SPH_C32(0x3ebe8d47) }, + { SPH_C32(0x23130000), SPH_C32(0x5c810000), SPH_C32(0x86950000), + SPH_C32(0x19b701f0), SPH_C32(0x0bc68dd5), SPH_C32(0x7292cc15), + SPH_C32(0x81e14199), SPH_C32(0xd5adc4da), SPH_C32(0xe8d70000), + SPH_C32(0x130d0000), SPH_C32(0xc9980000), SPH_C32(0xd0b000a9), + SPH_C32(0x924f23ad), SPH_C32(0x22631e1e), SPH_C32(0xb20a33d0), + SPH_C32(0x518cecc2) }, + { SPH_C32(0x8bc90000), SPH_C32(0xca3f0000), SPH_C32(0xda880000), + SPH_C32(0x1e6d01f2), SPH_C32(0x76a01856), SPH_C32(0x6d0abc9f), + SPH_C32(0x3a87c991), SPH_C32(0x0f2a44da), SPH_C32(0x43300000), + SPH_C32(0x8d000000), SPH_C32(0x66bf0000), SPH_C32(0xeda800ac), + SPH_C32(0xbe003c7e), SPH_C32(0x5695088b), SPH_C32(0x07c9743b), + SPH_C32(0x6dd1133c) }, + { SPH_C32(0x22800000), SPH_C32(0xbb030000), SPH_C32(0x6b6e0000), + SPH_C32(0xd6bb01fb), SPH_C32(0x8616008d), SPH_C32(0xce31783b), + SPH_C32(0x87d72078), SPH_C32(0x86c25aa1), SPH_C32(0x7aff0000), + SPH_C32(0xcf880000), SPH_C32(0x9e620000), SPH_C32(0x866c00aa), + SPH_C32(0x28a600bb), SPH_C32(0x788cbd12), SPH_C32(0x22c4c482), + SPH_C32(0x2a9a9915) }, + { SPH_C32(0x8a5a0000), SPH_C32(0x2dbd0000), SPH_C32(0x37730000), + SPH_C32(0xd16101f9), SPH_C32(0xfb70950e), SPH_C32(0xd1a908b1), + SPH_C32(0x3cb1a870), SPH_C32(0x5c45daa1), SPH_C32(0xd1180000), + SPH_C32(0x51850000), SPH_C32(0x31450000), SPH_C32(0xbb7400af), + SPH_C32(0x04e91f68), SPH_C32(0x0c7aab87), SPH_C32(0x97078369), + SPH_C32(0x16c766eb) }, + { SPH_C32(0xeed70000), SPH_C32(0xa94f0000), SPH_C32(0x48bd0000), + SPH_C32(0x01bb01e1), SPH_C32(0xaffce1b0), SPH_C32(0x92da67d0), + SPH_C32(0x463bbd14), SPH_C32(0x9e150dfa), SPH_C32(0x24c40000), + SPH_C32(0x7e090000), SPH_C32(0x30370000), SPH_C32(0x2d9300b2), + SPH_C32(0x80080b5c), SPH_C32(0xd73e9d72), SPH_C32(0x70ec30dc), + SPH_C32(0xf751dc07) }, + { SPH_C32(0x460d0000), SPH_C32(0x3ff10000), SPH_C32(0x14a00000), + SPH_C32(0x066101e3), SPH_C32(0xd29a7433), SPH_C32(0x8d42175a), + SPH_C32(0xfd5d351c), SPH_C32(0x44928dfa), SPH_C32(0x8f230000), + SPH_C32(0xe0040000), SPH_C32(0x9f100000), SPH_C32(0x108b00b7), + SPH_C32(0xac47148f), SPH_C32(0xa3c88be7), SPH_C32(0xc52f7737), + SPH_C32(0xcb0c23f9) }, + { SPH_C32(0xef440000), SPH_C32(0x4ecd0000), SPH_C32(0xa5460000), + SPH_C32(0xceb701ea), SPH_C32(0x222c6ce8), SPH_C32(0x2e79d3fe), + SPH_C32(0x400ddcf5), SPH_C32(0xcd7a9381), SPH_C32(0xb6ec0000), + SPH_C32(0xa28c0000), SPH_C32(0x67cd0000), SPH_C32(0x7b4f00b1), + SPH_C32(0x3ae1284a), SPH_C32(0x8dd13e7e), SPH_C32(0xe022c78e), + SPH_C32(0x8c47a9d0) }, + { SPH_C32(0x479e0000), SPH_C32(0xd8730000), SPH_C32(0xf95b0000), + SPH_C32(0xc96d01e8), SPH_C32(0x5f4af96b), SPH_C32(0x31e1a374), + SPH_C32(0xfb6b54fd), SPH_C32(0x17fd1381), SPH_C32(0x1d0b0000), + SPH_C32(0x3c810000), SPH_C32(0xc8ea0000), SPH_C32(0x465700b4), + SPH_C32(0x16ae3799), SPH_C32(0xf92728eb), SPH_C32(0x55e18065), + SPH_C32(0xb01a562e) }, + { SPH_C32(0x7cff0000), SPH_C32(0x75ca0000), SPH_C32(0x1f470000), + SPH_C32(0x576701e2), SPH_C32(0x1515c2a6), SPH_C32(0xc835c4dc), + SPH_C32(0xd6f54a46), SPH_C32(0xe503782d), SPH_C32(0xb77f0000), + SPH_C32(0x450e0000), SPH_C32(0x8a360000), SPH_C32(0xb44300ba), + SPH_C32(0xb731a512), SPH_C32(0x31728a50), SPH_C32(0xe614a66f), + SPH_C32(0xdf2837ab) }, + { SPH_C32(0xd4250000), SPH_C32(0xe3740000), SPH_C32(0x435a0000), + SPH_C32(0x50bd01e0), SPH_C32(0x68735725), SPH_C32(0xd7adb456), + SPH_C32(0x6d93c24e), SPH_C32(0x3f84f82d), SPH_C32(0x1c980000), + SPH_C32(0xdb030000), SPH_C32(0x25110000), SPH_C32(0x895b00bf), + SPH_C32(0x9b7ebac1), SPH_C32(0x45849cc5), SPH_C32(0x53d7e184), + SPH_C32(0xe375c855) }, + { SPH_C32(0x7d6c0000), SPH_C32(0x92480000), SPH_C32(0xf2bc0000), + SPH_C32(0x986b01e9), SPH_C32(0x98c54ffe), SPH_C32(0x749670f2), + SPH_C32(0xd0c32ba7), SPH_C32(0xb66ce656), SPH_C32(0x25570000), + SPH_C32(0x998b0000), SPH_C32(0xddcc0000), SPH_C32(0xe29f00b9), + SPH_C32(0x0dd88604), SPH_C32(0x6b9d295c), SPH_C32(0x76da513d), + SPH_C32(0xa43e427c) }, + { SPH_C32(0xd5b60000), SPH_C32(0x04f60000), SPH_C32(0xaea10000), + SPH_C32(0x9fb101eb), SPH_C32(0xe5a3da7d), SPH_C32(0x6b0e0078), + SPH_C32(0x6ba5a3af), SPH_C32(0x6ceb6656), SPH_C32(0x8eb00000), + SPH_C32(0x07860000), SPH_C32(0x72eb0000), SPH_C32(0xdf8700bc), + SPH_C32(0x219799d7), SPH_C32(0x1f6b3fc9), SPH_C32(0xc31916d6), + SPH_C32(0x9863bd82) }, + { SPH_C32(0xb17f0000), SPH_C32(0xff4c0000), SPH_C32(0x0b130000), + SPH_C32(0x654801f2), SPH_C32(0x8a82670f), SPH_C32(0x81cbf39e), + SPH_C32(0x122528ab), SPH_C32(0x10b1d693), SPH_C32(0x24800000), + SPH_C32(0x01410000), SPH_C32(0xea4b0000), SPH_C32(0x07b000b3), + SPH_C32(0xbba5c290), SPH_C32(0x7e8801f5), SPH_C32(0x73e6aebc), + SPH_C32(0x495bbb99) }, + { SPH_C32(0x19a50000), SPH_C32(0x69f20000), SPH_C32(0x570e0000), + SPH_C32(0x629201f0), SPH_C32(0xf7e4f28c), SPH_C32(0x9e538314), + SPH_C32(0xa943a0a3), SPH_C32(0xca365693), SPH_C32(0x8f670000), + SPH_C32(0x9f4c0000), SPH_C32(0x456c0000), SPH_C32(0x3aa800b6), + SPH_C32(0x97eadd43), SPH_C32(0x0a7e1760), SPH_C32(0xc625e957), + SPH_C32(0x75064467) }, + { SPH_C32(0xb0ec0000), SPH_C32(0x18ce0000), SPH_C32(0xe6e80000), + SPH_C32(0xaa4401f9), SPH_C32(0x0752ea57), SPH_C32(0x3d6847b0), + SPH_C32(0x1413494a), SPH_C32(0x43de48e8), SPH_C32(0xb6a80000), + SPH_C32(0xddc40000), SPH_C32(0xbdb10000), SPH_C32(0x516c00b0), + SPH_C32(0x014ce186), SPH_C32(0x2467a2f9), SPH_C32(0xe32859ee), + SPH_C32(0x324dce4e) }, + { SPH_C32(0x18360000), SPH_C32(0x8e700000), SPH_C32(0xbaf50000), + SPH_C32(0xad9e01fb), SPH_C32(0x7a347fd4), SPH_C32(0x22f0373a), + SPH_C32(0xaf75c142), SPH_C32(0x9959c8e8), SPH_C32(0x1d4f0000), + SPH_C32(0x43c90000), SPH_C32(0x12960000), SPH_C32(0x6c7400b5), + SPH_C32(0x2d03fe55), SPH_C32(0x5091b46c), SPH_C32(0x56eb1e05), + SPH_C32(0x0e1031b0) }, + { SPH_C32(0x23570000), SPH_C32(0x23c90000), SPH_C32(0x5ce90000), + SPH_C32(0x339401f1), SPH_C32(0x306b4419), SPH_C32(0xdb245092), + SPH_C32(0x82ebdff9), SPH_C32(0x6ba7a344), SPH_C32(0xb73b0000), + SPH_C32(0x3a460000), SPH_C32(0x504a0000), SPH_C32(0x9e6000bb), + SPH_C32(0x8c9c6cde), SPH_C32(0x98c416d7), SPH_C32(0xe51e380f), + SPH_C32(0x61225035) }, + { SPH_C32(0x8b8d0000), SPH_C32(0xb5770000), SPH_C32(0x00f40000), + SPH_C32(0x344e01f3), SPH_C32(0x4d0dd19a), SPH_C32(0xc4bc2018), + SPH_C32(0x398d57f1), SPH_C32(0xb1202344), SPH_C32(0x1cdc0000), + SPH_C32(0xa44b0000), SPH_C32(0xff6d0000), SPH_C32(0xa37800be), + SPH_C32(0xa0d3730d), SPH_C32(0xec320042), SPH_C32(0x50dd7fe4), + SPH_C32(0x5d7fafcb) }, + { SPH_C32(0x22c40000), SPH_C32(0xc44b0000), SPH_C32(0xb1120000), + SPH_C32(0xfc9801fa), SPH_C32(0xbdbbc941), SPH_C32(0x6787e4bc), + SPH_C32(0x84ddbe18), SPH_C32(0x38c83d3f), SPH_C32(0x25130000), + SPH_C32(0xe6c30000), SPH_C32(0x07b00000), SPH_C32(0xc8bc00b8), + SPH_C32(0x36754fc8), SPH_C32(0xc22bb5db), SPH_C32(0x75d0cf5d), + SPH_C32(0x1a3425e2) }, + { SPH_C32(0x8a1e0000), SPH_C32(0x52f50000), SPH_C32(0xed0f0000), + SPH_C32(0xfb4201f8), SPH_C32(0xc0dd5cc2), SPH_C32(0x781f9436), + SPH_C32(0x3fbb3610), SPH_C32(0xe24fbd3f), SPH_C32(0x8ef40000), + SPH_C32(0x78ce0000), SPH_C32(0xa8970000), SPH_C32(0xf5a400bd), + SPH_C32(0x1a3a501b), SPH_C32(0xb6dda34e), SPH_C32(0xc01388b6), + SPH_C32(0x2669da1c) }, + { SPH_C32(0x7b280000), SPH_C32(0x57420000), SPH_C32(0xa9e50000), + SPH_C32(0x634300a0), SPH_C32(0x9edb442f), SPH_C32(0x6d9995bb), + SPH_C32(0x27f83b03), SPH_C32(0xc7ff60f0), SPH_C32(0x95bb0000), + SPH_C32(0x81450000), SPH_C32(0x3b240000), SPH_C32(0x48db0140), + SPH_C32(0x0a8a6c53), SPH_C32(0x56f56eec), SPH_C32(0x62c91877), + SPH_C32(0xe7e00a94) }, + { SPH_C32(0xd3f20000), SPH_C32(0xc1fc0000), SPH_C32(0xf5f80000), + SPH_C32(0x649900a2), SPH_C32(0xe3bdd1ac), SPH_C32(0x7201e531), + SPH_C32(0x9c9eb30b), SPH_C32(0x1d78e0f0), SPH_C32(0x3e5c0000), + SPH_C32(0x1f480000), SPH_C32(0x94030000), SPH_C32(0x75c30145), + SPH_C32(0x26c57380), SPH_C32(0x22037879), SPH_C32(0xd70a5f9c), + SPH_C32(0xdbbdf56a) }, + { SPH_C32(0x7abb0000), SPH_C32(0xb0c00000), SPH_C32(0x441e0000), + SPH_C32(0xac4f00ab), SPH_C32(0x130bc977), SPH_C32(0xd13a2195), + SPH_C32(0x21ce5ae2), SPH_C32(0x9490fe8b), SPH_C32(0x07930000), + SPH_C32(0x5dc00000), SPH_C32(0x6cde0000), SPH_C32(0x1e070143), + SPH_C32(0xb0634f45), SPH_C32(0x0c1acde0), SPH_C32(0xf207ef25), + SPH_C32(0x9cf67f43) }, + { SPH_C32(0xd2610000), SPH_C32(0x267e0000), SPH_C32(0x18030000), + SPH_C32(0xab9500a9), SPH_C32(0x6e6d5cf4), SPH_C32(0xcea2511f), + SPH_C32(0x9aa8d2ea), SPH_C32(0x4e177e8b), SPH_C32(0xac740000), + SPH_C32(0xc3cd0000), SPH_C32(0xc3f90000), SPH_C32(0x231f0146), + SPH_C32(0x9c2c5096), SPH_C32(0x78ecdb75), SPH_C32(0x47c4a8ce), + SPH_C32(0xa0ab80bd) }, + { SPH_C32(0xe9000000), SPH_C32(0x8bc70000), SPH_C32(0xfe1f0000), + SPH_C32(0x359f00a3), SPH_C32(0x24326739), SPH_C32(0x377636b7), + SPH_C32(0xb736cc51), SPH_C32(0xbce91527), SPH_C32(0x06000000), + SPH_C32(0xba420000), SPH_C32(0x81250000), SPH_C32(0xd10b0148), + SPH_C32(0x3db3c21d), SPH_C32(0xb0b979ce), SPH_C32(0xf4318ec4), + SPH_C32(0xcf99e138) }, + { SPH_C32(0x41da0000), SPH_C32(0x1d790000), SPH_C32(0xa2020000), + SPH_C32(0x324500a1), SPH_C32(0x5954f2ba), SPH_C32(0x28ee463d), + SPH_C32(0x0c504459), SPH_C32(0x666e9527), SPH_C32(0xade70000), + SPH_C32(0x244f0000), SPH_C32(0x2e020000), SPH_C32(0xec13014d), + SPH_C32(0x11fcddce), SPH_C32(0xc44f6f5b), SPH_C32(0x41f2c92f), + SPH_C32(0xf3c41ec6) }, + { SPH_C32(0xe8930000), SPH_C32(0x6c450000), SPH_C32(0x13e40000), + SPH_C32(0xfa9300a8), SPH_C32(0xa9e2ea61), SPH_C32(0x8bd58299), + SPH_C32(0xb100adb0), SPH_C32(0xef868b5c), SPH_C32(0x94280000), + SPH_C32(0x66c70000), SPH_C32(0xd6df0000), SPH_C32(0x87d7014b), + SPH_C32(0x875ae10b), SPH_C32(0xea56dac2), SPH_C32(0x64ff7996), + SPH_C32(0xb48f94ef) }, + { SPH_C32(0x40490000), SPH_C32(0xfafb0000), SPH_C32(0x4ff90000), + SPH_C32(0xfd4900aa), SPH_C32(0xd4847fe2), SPH_C32(0x944df213), + SPH_C32(0x0a6625b8), SPH_C32(0x35010b5c), SPH_C32(0x3fcf0000), + SPH_C32(0xf8ca0000), SPH_C32(0x79f80000), SPH_C32(0xbacf014e), + SPH_C32(0xab15fed8), SPH_C32(0x9ea0cc57), SPH_C32(0xd13c3e7d), + SPH_C32(0x88d26b11) }, + { SPH_C32(0x24800000), SPH_C32(0x01410000), SPH_C32(0xea4b0000), + SPH_C32(0x07b000b3), SPH_C32(0xbba5c290), SPH_C32(0x7e8801f5), + SPH_C32(0x73e6aebc), SPH_C32(0x495bbb99), SPH_C32(0x95ff0000), + SPH_C32(0xfe0d0000), SPH_C32(0xe1580000), SPH_C32(0x62f80141), + SPH_C32(0x3127a59f), SPH_C32(0xff43f26b), SPH_C32(0x61c38617), + SPH_C32(0x59ea6d0a) }, + { SPH_C32(0x8c5a0000), SPH_C32(0x97ff0000), SPH_C32(0xb6560000), + SPH_C32(0x006a00b1), SPH_C32(0xc6c35713), SPH_C32(0x6110717f), + SPH_C32(0xc88026b4), SPH_C32(0x93dc3b99), SPH_C32(0x3e180000), + SPH_C32(0x60000000), SPH_C32(0x4e7f0000), SPH_C32(0x5fe00144), + SPH_C32(0x1d68ba4c), SPH_C32(0x8bb5e4fe), SPH_C32(0xd400c1fc), + SPH_C32(0x65b792f4) }, + { SPH_C32(0x25130000), SPH_C32(0xe6c30000), SPH_C32(0x07b00000), + SPH_C32(0xc8bc00b8), SPH_C32(0x36754fc8), SPH_C32(0xc22bb5db), + SPH_C32(0x75d0cf5d), SPH_C32(0x1a3425e2), SPH_C32(0x07d70000), + SPH_C32(0x22880000), SPH_C32(0xb6a20000), SPH_C32(0x34240142), + SPH_C32(0x8bce8689), SPH_C32(0xa5ac5167), SPH_C32(0xf10d7145), + SPH_C32(0x22fc18dd) }, + { SPH_C32(0x8dc90000), SPH_C32(0x707d0000), SPH_C32(0x5bad0000), + SPH_C32(0xcf6600ba), SPH_C32(0x4b13da4b), SPH_C32(0xddb3c551), + SPH_C32(0xceb64755), SPH_C32(0xc0b3a5e2), SPH_C32(0xac300000), + SPH_C32(0xbc850000), SPH_C32(0x19850000), SPH_C32(0x093c0147), + SPH_C32(0xa781995a), SPH_C32(0xd15a47f2), SPH_C32(0x44ce36ae), + SPH_C32(0x1ea1e723) }, + { SPH_C32(0xb6a80000), SPH_C32(0xddc40000), SPH_C32(0xbdb10000), + SPH_C32(0x516c00b0), SPH_C32(0x014ce186), SPH_C32(0x2467a2f9), + SPH_C32(0xe32859ee), SPH_C32(0x324dce4e), SPH_C32(0x06440000), + SPH_C32(0xc50a0000), SPH_C32(0x5b590000), SPH_C32(0xfb280149), + SPH_C32(0x061e0bd1), SPH_C32(0x190fe549), SPH_C32(0xf73b10a4), + SPH_C32(0x719386a6) }, + { SPH_C32(0x1e720000), SPH_C32(0x4b7a0000), SPH_C32(0xe1ac0000), + SPH_C32(0x56b600b2), SPH_C32(0x7c2a7405), SPH_C32(0x3bffd273), + SPH_C32(0x584ed1e6), SPH_C32(0xe8ca4e4e), SPH_C32(0xada30000), + SPH_C32(0x5b070000), SPH_C32(0xf47e0000), SPH_C32(0xc630014c), + SPH_C32(0x2a511402), SPH_C32(0x6df9f3dc), SPH_C32(0x42f8574f), + SPH_C32(0x4dce7958) }, + { SPH_C32(0xb73b0000), SPH_C32(0x3a460000), SPH_C32(0x504a0000), + SPH_C32(0x9e6000bb), SPH_C32(0x8c9c6cde), SPH_C32(0x98c416d7), + SPH_C32(0xe51e380f), SPH_C32(0x61225035), SPH_C32(0x946c0000), + SPH_C32(0x198f0000), SPH_C32(0x0ca30000), SPH_C32(0xadf4014a), + SPH_C32(0xbcf728c7), SPH_C32(0x43e04645), SPH_C32(0x67f5e7f6), + SPH_C32(0x0a85f371) }, + { SPH_C32(0x1fe10000), SPH_C32(0xacf80000), SPH_C32(0x0c570000), + SPH_C32(0x99ba00b9), SPH_C32(0xf1faf95d), SPH_C32(0x875c665d), + SPH_C32(0x5e78b007), SPH_C32(0xbba5d035), SPH_C32(0x3f8b0000), + SPH_C32(0x87820000), SPH_C32(0xa3840000), SPH_C32(0x90ec014f), + SPH_C32(0x90b83714), SPH_C32(0x371650d0), SPH_C32(0xd236a01d), + SPH_C32(0x36d80c8f) }, + { SPH_C32(0x7b6c0000), SPH_C32(0x280a0000), SPH_C32(0x73990000), + SPH_C32(0x496000a1), SPH_C32(0xa5768de3), SPH_C32(0xc42f093c), + SPH_C32(0x24f2a563), SPH_C32(0x79f5076e), SPH_C32(0xca570000), + SPH_C32(0xa80e0000), SPH_C32(0xa2f60000), SPH_C32(0x060b0152), + SPH_C32(0x14592320), SPH_C32(0xec526625), SPH_C32(0x35dd13a8), + SPH_C32(0xd74eb663) }, + { SPH_C32(0xd3b60000), SPH_C32(0xbeb40000), SPH_C32(0x2f840000), + SPH_C32(0x4eba00a3), SPH_C32(0xd8101860), SPH_C32(0xdbb779b6), + SPH_C32(0x9f942d6b), SPH_C32(0xa372876e), SPH_C32(0x61b00000), + SPH_C32(0x36030000), SPH_C32(0x0dd10000), SPH_C32(0x3b130157), + SPH_C32(0x38163cf3), SPH_C32(0x98a470b0), SPH_C32(0x801e5443), + SPH_C32(0xeb13499d) }, + { SPH_C32(0x7aff0000), SPH_C32(0xcf880000), SPH_C32(0x9e620000), + SPH_C32(0x866c00aa), SPH_C32(0x28a600bb), SPH_C32(0x788cbd12), + SPH_C32(0x22c4c482), SPH_C32(0x2a9a9915), SPH_C32(0x587f0000), + SPH_C32(0x748b0000), SPH_C32(0xf50c0000), SPH_C32(0x50d70151), + SPH_C32(0xaeb00036), SPH_C32(0xb6bdc529), SPH_C32(0xa513e4fa), + SPH_C32(0xac58c3b4) }, + { SPH_C32(0xd2250000), SPH_C32(0x59360000), SPH_C32(0xc27f0000), + SPH_C32(0x81b600a8), SPH_C32(0x55c09538), SPH_C32(0x6714cd98), + SPH_C32(0x99a24c8a), SPH_C32(0xf01d1915), SPH_C32(0xf3980000), + SPH_C32(0xea860000), SPH_C32(0x5a2b0000), SPH_C32(0x6dcf0154), + SPH_C32(0x82ff1fe5), SPH_C32(0xc24bd3bc), SPH_C32(0x10d0a311), + SPH_C32(0x90053c4a) }, + { SPH_C32(0xe9440000), SPH_C32(0xf48f0000), SPH_C32(0x24630000), + SPH_C32(0x1fbc00a2), SPH_C32(0x1f9faef5), SPH_C32(0x9ec0aa30), + SPH_C32(0xb43c5231), SPH_C32(0x02e372b9), SPH_C32(0x59ec0000), + SPH_C32(0x93090000), SPH_C32(0x18f70000), SPH_C32(0x9fdb015a), + SPH_C32(0x23608d6e), SPH_C32(0x0a1e7107), SPH_C32(0xa325851b), + SPH_C32(0xff375dcf) }, + { SPH_C32(0x419e0000), SPH_C32(0x62310000), SPH_C32(0x787e0000), + SPH_C32(0x186600a0), SPH_C32(0x62f93b76), SPH_C32(0x8158daba), + SPH_C32(0x0f5ada39), SPH_C32(0xd864f2b9), SPH_C32(0xf20b0000), + SPH_C32(0x0d040000), SPH_C32(0xb7d00000), SPH_C32(0xa2c3015f), + SPH_C32(0x0f2f92bd), SPH_C32(0x7ee86792), SPH_C32(0x16e6c2f0), + SPH_C32(0xc36aa231) }, + { SPH_C32(0xe8d70000), SPH_C32(0x130d0000), SPH_C32(0xc9980000), + SPH_C32(0xd0b000a9), SPH_C32(0x924f23ad), SPH_C32(0x22631e1e), + SPH_C32(0xb20a33d0), SPH_C32(0x518cecc2), SPH_C32(0xcbc40000), + SPH_C32(0x4f8c0000), SPH_C32(0x4f0d0000), SPH_C32(0xc9070159), + SPH_C32(0x9989ae78), SPH_C32(0x50f1d20b), SPH_C32(0x33eb7249), + SPH_C32(0x84212818) }, + { SPH_C32(0x400d0000), SPH_C32(0x85b30000), SPH_C32(0x95850000), + SPH_C32(0xd76a00ab), SPH_C32(0xef29b62e), SPH_C32(0x3dfb6e94), + SPH_C32(0x096cbbd8), SPH_C32(0x8b0b6cc2), SPH_C32(0x60230000), + SPH_C32(0xd1810000), SPH_C32(0xe02a0000), SPH_C32(0xf41f015c), + SPH_C32(0xb5c6b1ab), SPH_C32(0x2407c49e), SPH_C32(0x862835a2), + SPH_C32(0xb87cd7e6) }, + { SPH_C32(0x24c40000), SPH_C32(0x7e090000), SPH_C32(0x30370000), + SPH_C32(0x2d9300b2), SPH_C32(0x80080b5c), SPH_C32(0xd73e9d72), + SPH_C32(0x70ec30dc), SPH_C32(0xf751dc07), SPH_C32(0xca130000), + SPH_C32(0xd7460000), SPH_C32(0x788a0000), SPH_C32(0x2c280153), + SPH_C32(0x2ff4eaec), SPH_C32(0x45e4faa2), SPH_C32(0x36d78dc8), + SPH_C32(0x6944d1fd) }, + { SPH_C32(0x8c1e0000), SPH_C32(0xe8b70000), SPH_C32(0x6c2a0000), + SPH_C32(0x2a4900b0), SPH_C32(0xfd6e9edf), SPH_C32(0xc8a6edf8), + SPH_C32(0xcb8ab8d4), SPH_C32(0x2dd65c07), SPH_C32(0x61f40000), + SPH_C32(0x494b0000), SPH_C32(0xd7ad0000), SPH_C32(0x11300156), + SPH_C32(0x03bbf53f), SPH_C32(0x3112ec37), SPH_C32(0x8314ca23), + SPH_C32(0x55192e03) }, + { SPH_C32(0x25570000), SPH_C32(0x998b0000), SPH_C32(0xddcc0000), + SPH_C32(0xe29f00b9), SPH_C32(0x0dd88604), SPH_C32(0x6b9d295c), + SPH_C32(0x76da513d), SPH_C32(0xa43e427c), SPH_C32(0x583b0000), + SPH_C32(0x0bc30000), SPH_C32(0x2f700000), SPH_C32(0x7af40150), + SPH_C32(0x951dc9fa), SPH_C32(0x1f0b59ae), SPH_C32(0xa6197a9a), + SPH_C32(0x1252a42a) }, + { SPH_C32(0x8d8d0000), SPH_C32(0x0f350000), SPH_C32(0x81d10000), + SPH_C32(0xe54500bb), SPH_C32(0x70be1387), SPH_C32(0x740559d6), + SPH_C32(0xcdbcd935), SPH_C32(0x7eb9c27c), SPH_C32(0xf3dc0000), + SPH_C32(0x95ce0000), SPH_C32(0x80570000), SPH_C32(0x47ec0155), + SPH_C32(0xb952d629), SPH_C32(0x6bfd4f3b), SPH_C32(0x13da3d71), + SPH_C32(0x2e0f5bd4) }, + { SPH_C32(0xb6ec0000), SPH_C32(0xa28c0000), SPH_C32(0x67cd0000), + SPH_C32(0x7b4f00b1), SPH_C32(0x3ae1284a), SPH_C32(0x8dd13e7e), + SPH_C32(0xe022c78e), SPH_C32(0x8c47a9d0), SPH_C32(0x59a80000), + SPH_C32(0xec410000), SPH_C32(0xc28b0000), SPH_C32(0xb5f8015b), + SPH_C32(0x18cd44a2), SPH_C32(0xa3a8ed80), SPH_C32(0xa02f1b7b), + SPH_C32(0x413d3a51) }, + { SPH_C32(0x1e360000), SPH_C32(0x34320000), SPH_C32(0x3bd00000), + SPH_C32(0x7c9500b3), SPH_C32(0x4787bdc9), SPH_C32(0x92494ef4), + SPH_C32(0x5b444f86), SPH_C32(0x56c029d0), SPH_C32(0xf24f0000), + SPH_C32(0x724c0000), SPH_C32(0x6dac0000), SPH_C32(0x88e0015e), + SPH_C32(0x34825b71), SPH_C32(0xd75efb15), SPH_C32(0x15ec5c90), + SPH_C32(0x7d60c5af) }, + { SPH_C32(0xb77f0000), SPH_C32(0x450e0000), SPH_C32(0x8a360000), + SPH_C32(0xb44300ba), SPH_C32(0xb731a512), SPH_C32(0x31728a50), + SPH_C32(0xe614a66f), SPH_C32(0xdf2837ab), SPH_C32(0xcb800000), + SPH_C32(0x30c40000), SPH_C32(0x95710000), SPH_C32(0xe3240158), + SPH_C32(0xa22467b4), SPH_C32(0xf9474e8c), SPH_C32(0x30e1ec29), + SPH_C32(0x3a2b4f86) }, + { SPH_C32(0x1fa50000), SPH_C32(0xd3b00000), SPH_C32(0xd62b0000), + SPH_C32(0xb39900b8), SPH_C32(0xca573091), SPH_C32(0x2eeafada), + SPH_C32(0x5d722e67), SPH_C32(0x05afb7ab), SPH_C32(0x60670000), + SPH_C32(0xaec90000), SPH_C32(0x3a560000), SPH_C32(0xde3c015d), + SPH_C32(0x8e6b7867), SPH_C32(0x8db15819), SPH_C32(0x8522abc2), + SPH_C32(0x0676b078) }, + { SPH_C32(0x95bb0000), SPH_C32(0x81450000), SPH_C32(0x3b240000), + SPH_C32(0x48db0140), SPH_C32(0x0a8a6c53), SPH_C32(0x56f56eec), + SPH_C32(0x62c91877), SPH_C32(0xe7e00a94), SPH_C32(0xee930000), + SPH_C32(0xd6070000), SPH_C32(0x92c10000), SPH_C32(0x2b9801e0), + SPH_C32(0x9451287c), SPH_C32(0x3b6cfb57), SPH_C32(0x45312374), + SPH_C32(0x201f6a64) }, + { SPH_C32(0x3d610000), SPH_C32(0x17fb0000), SPH_C32(0x67390000), + SPH_C32(0x4f010142), SPH_C32(0x77ecf9d0), SPH_C32(0x496d1e66), + SPH_C32(0xd9af907f), SPH_C32(0x3d678a94), SPH_C32(0x45740000), + SPH_C32(0x480a0000), SPH_C32(0x3de60000), SPH_C32(0x168001e5), + SPH_C32(0xb81e37af), SPH_C32(0x4f9aedc2), SPH_C32(0xf0f2649f), + SPH_C32(0x1c42959a) }, + { SPH_C32(0x94280000), SPH_C32(0x66c70000), SPH_C32(0xd6df0000), + SPH_C32(0x87d7014b), SPH_C32(0x875ae10b), SPH_C32(0xea56dac2), + SPH_C32(0x64ff7996), SPH_C32(0xb48f94ef), SPH_C32(0x7cbb0000), + SPH_C32(0x0a820000), SPH_C32(0xc53b0000), SPH_C32(0x7d4401e3), + SPH_C32(0x2eb80b6a), SPH_C32(0x6183585b), SPH_C32(0xd5ffd426), + SPH_C32(0x5b091fb3) }, + { SPH_C32(0x3cf20000), SPH_C32(0xf0790000), SPH_C32(0x8ac20000), + SPH_C32(0x800d0149), SPH_C32(0xfa3c7488), SPH_C32(0xf5ceaa48), + SPH_C32(0xdf99f19e), SPH_C32(0x6e0814ef), SPH_C32(0xd75c0000), + SPH_C32(0x948f0000), SPH_C32(0x6a1c0000), SPH_C32(0x405c01e6), + SPH_C32(0x02f714b9), SPH_C32(0x15754ece), SPH_C32(0x603c93cd), + SPH_C32(0x6754e04d) }, + { SPH_C32(0x07930000), SPH_C32(0x5dc00000), SPH_C32(0x6cde0000), + SPH_C32(0x1e070143), SPH_C32(0xb0634f45), SPH_C32(0x0c1acde0), + SPH_C32(0xf207ef25), SPH_C32(0x9cf67f43), SPH_C32(0x7d280000), + SPH_C32(0xed000000), SPH_C32(0x28c00000), SPH_C32(0xb24801e8), + SPH_C32(0xa3688632), SPH_C32(0xdd20ec75), SPH_C32(0xd3c9b5c7), + SPH_C32(0x086681c8) }, + { SPH_C32(0xaf490000), SPH_C32(0xcb7e0000), SPH_C32(0x30c30000), + SPH_C32(0x19dd0141), SPH_C32(0xcd05dac6), SPH_C32(0x1382bd6a), + SPH_C32(0x4961672d), SPH_C32(0x4671ff43), SPH_C32(0xd6cf0000), + SPH_C32(0x730d0000), SPH_C32(0x87e70000), SPH_C32(0x8f5001ed), + SPH_C32(0x8f2799e1), SPH_C32(0xa9d6fae0), SPH_C32(0x660af22c), + SPH_C32(0x343b7e36) }, + { SPH_C32(0x06000000), SPH_C32(0xba420000), SPH_C32(0x81250000), + SPH_C32(0xd10b0148), SPH_C32(0x3db3c21d), SPH_C32(0xb0b979ce), + SPH_C32(0xf4318ec4), SPH_C32(0xcf99e138), SPH_C32(0xef000000), + SPH_C32(0x31850000), SPH_C32(0x7f3a0000), SPH_C32(0xe49401eb), + SPH_C32(0x1981a524), SPH_C32(0x87cf4f79), SPH_C32(0x43074295), + SPH_C32(0x7370f41f) }, + { SPH_C32(0xaeda0000), SPH_C32(0x2cfc0000), SPH_C32(0xdd380000), + SPH_C32(0xd6d1014a), SPH_C32(0x40d5579e), SPH_C32(0xaf210944), + SPH_C32(0x4f5706cc), SPH_C32(0x151e6138), SPH_C32(0x44e70000), + SPH_C32(0xaf880000), SPH_C32(0xd01d0000), SPH_C32(0xd98c01ee), + SPH_C32(0x35cebaf7), SPH_C32(0xf33959ec), SPH_C32(0xf6c4057e), + SPH_C32(0x4f2d0be1) }, + { SPH_C32(0xca130000), SPH_C32(0xd7460000), SPH_C32(0x788a0000), + SPH_C32(0x2c280153), SPH_C32(0x2ff4eaec), SPH_C32(0x45e4faa2), + SPH_C32(0x36d78dc8), SPH_C32(0x6944d1fd), SPH_C32(0xeed70000), + SPH_C32(0xa94f0000), SPH_C32(0x48bd0000), SPH_C32(0x01bb01e1), + SPH_C32(0xaffce1b0), SPH_C32(0x92da67d0), SPH_C32(0x463bbd14), + SPH_C32(0x9e150dfa) }, + { SPH_C32(0x62c90000), SPH_C32(0x41f80000), SPH_C32(0x24970000), + SPH_C32(0x2bf20151), SPH_C32(0x52927f6f), SPH_C32(0x5a7c8a28), + SPH_C32(0x8db105c0), SPH_C32(0xb3c351fd), SPH_C32(0x45300000), + SPH_C32(0x37420000), SPH_C32(0xe79a0000), SPH_C32(0x3ca301e4), + SPH_C32(0x83b3fe63), SPH_C32(0xe62c7145), SPH_C32(0xf3f8faff), + SPH_C32(0xa248f204) }, + { SPH_C32(0xcb800000), SPH_C32(0x30c40000), SPH_C32(0x95710000), + SPH_C32(0xe3240158), SPH_C32(0xa22467b4), SPH_C32(0xf9474e8c), + SPH_C32(0x30e1ec29), SPH_C32(0x3a2b4f86), SPH_C32(0x7cff0000), + SPH_C32(0x75ca0000), SPH_C32(0x1f470000), SPH_C32(0x576701e2), + SPH_C32(0x1515c2a6), SPH_C32(0xc835c4dc), SPH_C32(0xd6f54a46), + SPH_C32(0xe503782d) }, + { SPH_C32(0x635a0000), SPH_C32(0xa67a0000), SPH_C32(0xc96c0000), + SPH_C32(0xe4fe015a), SPH_C32(0xdf42f237), SPH_C32(0xe6df3e06), + SPH_C32(0x8b876421), SPH_C32(0xe0accf86), SPH_C32(0xd7180000), + SPH_C32(0xebc70000), SPH_C32(0xb0600000), SPH_C32(0x6a7f01e7), + SPH_C32(0x395add75), SPH_C32(0xbcc3d249), SPH_C32(0x63360dad), + SPH_C32(0xd95e87d3) }, + { SPH_C32(0x583b0000), SPH_C32(0x0bc30000), SPH_C32(0x2f700000), + SPH_C32(0x7af40150), SPH_C32(0x951dc9fa), SPH_C32(0x1f0b59ae), + SPH_C32(0xa6197a9a), SPH_C32(0x1252a42a), SPH_C32(0x7d6c0000), + SPH_C32(0x92480000), SPH_C32(0xf2bc0000), SPH_C32(0x986b01e9), + SPH_C32(0x98c54ffe), SPH_C32(0x749670f2), SPH_C32(0xd0c32ba7), + SPH_C32(0xb66ce656) }, + { SPH_C32(0xf0e10000), SPH_C32(0x9d7d0000), SPH_C32(0x736d0000), + SPH_C32(0x7d2e0152), SPH_C32(0xe87b5c79), SPH_C32(0x00932924), + SPH_C32(0x1d7ff292), SPH_C32(0xc8d5242a), SPH_C32(0xd68b0000), + SPH_C32(0x0c450000), SPH_C32(0x5d9b0000), SPH_C32(0xa57301ec), + SPH_C32(0xb48a502d), SPH_C32(0x00606667), SPH_C32(0x65006c4c), + SPH_C32(0x8a3119a8) }, + { SPH_C32(0x59a80000), SPH_C32(0xec410000), SPH_C32(0xc28b0000), + SPH_C32(0xb5f8015b), SPH_C32(0x18cd44a2), SPH_C32(0xa3a8ed80), + SPH_C32(0xa02f1b7b), SPH_C32(0x413d3a51), SPH_C32(0xef440000), + SPH_C32(0x4ecd0000), SPH_C32(0xa5460000), SPH_C32(0xceb701ea), + SPH_C32(0x222c6ce8), SPH_C32(0x2e79d3fe), SPH_C32(0x400ddcf5), + SPH_C32(0xcd7a9381) }, + { SPH_C32(0xf1720000), SPH_C32(0x7aff0000), SPH_C32(0x9e960000), + SPH_C32(0xb2220159), SPH_C32(0x65abd121), SPH_C32(0xbc309d0a), + SPH_C32(0x1b499373), SPH_C32(0x9bbaba51), SPH_C32(0x44a30000), + SPH_C32(0xd0c00000), SPH_C32(0x0a610000), SPH_C32(0xf3af01ef), + SPH_C32(0x0e63733b), SPH_C32(0x5a8fc56b), SPH_C32(0xf5ce9b1e), + SPH_C32(0xf1276c7f) }, + { SPH_C32(0x95ff0000), SPH_C32(0xfe0d0000), SPH_C32(0xe1580000), + SPH_C32(0x62f80141), SPH_C32(0x3127a59f), SPH_C32(0xff43f26b), + SPH_C32(0x61c38617), SPH_C32(0x59ea6d0a), SPH_C32(0xb17f0000), + SPH_C32(0xff4c0000), SPH_C32(0x0b130000), SPH_C32(0x654801f2), + SPH_C32(0x8a82670f), SPH_C32(0x81cbf39e), SPH_C32(0x122528ab), + SPH_C32(0x10b1d693) }, + { SPH_C32(0x3d250000), SPH_C32(0x68b30000), SPH_C32(0xbd450000), + SPH_C32(0x65220143), SPH_C32(0x4c41301c), SPH_C32(0xe0db82e1), + SPH_C32(0xdaa50e1f), SPH_C32(0x836ded0a), SPH_C32(0x1a980000), + SPH_C32(0x61410000), SPH_C32(0xa4340000), SPH_C32(0x585001f7), + SPH_C32(0xa6cd78dc), SPH_C32(0xf53de50b), SPH_C32(0xa7e66f40), + SPH_C32(0x2cec296d) }, + { SPH_C32(0x946c0000), SPH_C32(0x198f0000), SPH_C32(0x0ca30000), + SPH_C32(0xadf4014a), SPH_C32(0xbcf728c7), SPH_C32(0x43e04645), + SPH_C32(0x67f5e7f6), SPH_C32(0x0a85f371), SPH_C32(0x23570000), + SPH_C32(0x23c90000), SPH_C32(0x5ce90000), SPH_C32(0x339401f1), + SPH_C32(0x306b4419), SPH_C32(0xdb245092), SPH_C32(0x82ebdff9), + SPH_C32(0x6ba7a344) }, + { SPH_C32(0x3cb60000), SPH_C32(0x8f310000), SPH_C32(0x50be0000), + SPH_C32(0xaa2e0148), SPH_C32(0xc191bd44), SPH_C32(0x5c7836cf), + SPH_C32(0xdc936ffe), SPH_C32(0xd0027371), SPH_C32(0x88b00000), + SPH_C32(0xbdc40000), SPH_C32(0xf3ce0000), SPH_C32(0x0e8c01f4), + SPH_C32(0x1c245bca), SPH_C32(0xafd24607), SPH_C32(0x37289812), + SPH_C32(0x57fa5cba) }, + { SPH_C32(0x07d70000), SPH_C32(0x22880000), SPH_C32(0xb6a20000), + SPH_C32(0x34240142), SPH_C32(0x8bce8689), SPH_C32(0xa5ac5167), + SPH_C32(0xf10d7145), SPH_C32(0x22fc18dd), SPH_C32(0x22c40000), + SPH_C32(0xc44b0000), SPH_C32(0xb1120000), SPH_C32(0xfc9801fa), + SPH_C32(0xbdbbc941), SPH_C32(0x6787e4bc), SPH_C32(0x84ddbe18), + SPH_C32(0x38c83d3f) }, + { SPH_C32(0xaf0d0000), SPH_C32(0xb4360000), SPH_C32(0xeabf0000), + SPH_C32(0x33fe0140), SPH_C32(0xf6a8130a), SPH_C32(0xba3421ed), + SPH_C32(0x4a6bf94d), SPH_C32(0xf87b98dd), SPH_C32(0x89230000), + SPH_C32(0x5a460000), SPH_C32(0x1e350000), SPH_C32(0xc18001ff), + SPH_C32(0x91f4d692), SPH_C32(0x1371f229), SPH_C32(0x311ef9f3), + SPH_C32(0x0495c2c1) }, + { SPH_C32(0x06440000), SPH_C32(0xc50a0000), SPH_C32(0x5b590000), + SPH_C32(0xfb280149), SPH_C32(0x061e0bd1), SPH_C32(0x190fe549), + SPH_C32(0xf73b10a4), SPH_C32(0x719386a6), SPH_C32(0xb0ec0000), + SPH_C32(0x18ce0000), SPH_C32(0xe6e80000), SPH_C32(0xaa4401f9), + SPH_C32(0x0752ea57), SPH_C32(0x3d6847b0), SPH_C32(0x1413494a), + SPH_C32(0x43de48e8) }, + { SPH_C32(0xae9e0000), SPH_C32(0x53b40000), SPH_C32(0x07440000), + SPH_C32(0xfcf2014b), SPH_C32(0x7b789e52), SPH_C32(0x069795c3), + SPH_C32(0x4c5d98ac), SPH_C32(0xab1406a6), SPH_C32(0x1b0b0000), + SPH_C32(0x86c30000), SPH_C32(0x49cf0000), SPH_C32(0x975c01fc), + SPH_C32(0x2b1df584), SPH_C32(0x499e5125), SPH_C32(0xa1d00ea1), + SPH_C32(0x7f83b716) }, + { SPH_C32(0xca570000), SPH_C32(0xa80e0000), SPH_C32(0xa2f60000), + SPH_C32(0x060b0152), SPH_C32(0x14592320), SPH_C32(0xec526625), + SPH_C32(0x35dd13a8), SPH_C32(0xd74eb663), SPH_C32(0xb13b0000), + SPH_C32(0x80040000), SPH_C32(0xd16f0000), SPH_C32(0x4f6b01f3), + SPH_C32(0xb12faec3), SPH_C32(0x287d6f19), SPH_C32(0x112fb6cb), + SPH_C32(0xaebbb10d) }, + { SPH_C32(0x628d0000), SPH_C32(0x3eb00000), SPH_C32(0xfeeb0000), + SPH_C32(0x01d10150), SPH_C32(0x693fb6a3), SPH_C32(0xf3ca16af), + SPH_C32(0x8ebb9ba0), SPH_C32(0x0dc93663), SPH_C32(0x1adc0000), + SPH_C32(0x1e090000), SPH_C32(0x7e480000), SPH_C32(0x727301f6), + SPH_C32(0x9d60b110), SPH_C32(0x5c8b798c), SPH_C32(0xa4ecf120), + SPH_C32(0x92e64ef3) }, + { SPH_C32(0xcbc40000), SPH_C32(0x4f8c0000), SPH_C32(0x4f0d0000), + SPH_C32(0xc9070159), SPH_C32(0x9989ae78), SPH_C32(0x50f1d20b), + SPH_C32(0x33eb7249), SPH_C32(0x84212818), SPH_C32(0x23130000), + SPH_C32(0x5c810000), SPH_C32(0x86950000), SPH_C32(0x19b701f0), + SPH_C32(0x0bc68dd5), SPH_C32(0x7292cc15), SPH_C32(0x81e14199), + SPH_C32(0xd5adc4da) }, + { SPH_C32(0x631e0000), SPH_C32(0xd9320000), SPH_C32(0x13100000), + SPH_C32(0xcedd015b), SPH_C32(0xe4ef3bfb), SPH_C32(0x4f69a281), + SPH_C32(0x888dfa41), SPH_C32(0x5ea6a818), SPH_C32(0x88f40000), + SPH_C32(0xc28c0000), SPH_C32(0x29b20000), SPH_C32(0x24af01f5), + SPH_C32(0x27899206), SPH_C32(0x0664da80), SPH_C32(0x34220672), + SPH_C32(0xe9f03b24) }, + { SPH_C32(0x587f0000), SPH_C32(0x748b0000), SPH_C32(0xf50c0000), + SPH_C32(0x50d70151), SPH_C32(0xaeb00036), SPH_C32(0xb6bdc529), + SPH_C32(0xa513e4fa), SPH_C32(0xac58c3b4), SPH_C32(0x22800000), + SPH_C32(0xbb030000), SPH_C32(0x6b6e0000), SPH_C32(0xd6bb01fb), + SPH_C32(0x8616008d), SPH_C32(0xce31783b), SPH_C32(0x87d72078), + SPH_C32(0x86c25aa1) }, + { SPH_C32(0xf0a50000), SPH_C32(0xe2350000), SPH_C32(0xa9110000), + SPH_C32(0x570d0153), SPH_C32(0xd3d695b5), SPH_C32(0xa925b5a3), + SPH_C32(0x1e756cf2), SPH_C32(0x76df43b4), SPH_C32(0x89670000), + SPH_C32(0x250e0000), SPH_C32(0xc4490000), SPH_C32(0xeba301fe), + SPH_C32(0xaa591f5e), SPH_C32(0xbac76eae), SPH_C32(0x32146793), + SPH_C32(0xba9fa55f) }, + { SPH_C32(0x59ec0000), SPH_C32(0x93090000), SPH_C32(0x18f70000), + SPH_C32(0x9fdb015a), SPH_C32(0x23608d6e), SPH_C32(0x0a1e7107), + SPH_C32(0xa325851b), SPH_C32(0xff375dcf), SPH_C32(0xb0a80000), + SPH_C32(0x67860000), SPH_C32(0x3c940000), SPH_C32(0x806701f8), + SPH_C32(0x3cff239b), SPH_C32(0x94dedb37), SPH_C32(0x1719d72a), + SPH_C32(0xfdd42f76) }, + { SPH_C32(0xf1360000), SPH_C32(0x05b70000), SPH_C32(0x44ea0000), + SPH_C32(0x98010158), SPH_C32(0x5e0618ed), SPH_C32(0x1586018d), + SPH_C32(0x18430d13), SPH_C32(0x25b0ddcf), SPH_C32(0x1b4f0000), + SPH_C32(0xf98b0000), SPH_C32(0x93b30000), SPH_C32(0xbd7f01fd), + SPH_C32(0x10b03c48), SPH_C32(0xe028cda2), SPH_C32(0xa2da90c1), + SPH_C32(0xc189d088) } +}; + +static const sph_u32 T512_63[2][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0x033d0000), SPH_C32(0x08b30000), SPH_C32(0xf33a0000), + SPH_C32(0x3ac20007), SPH_C32(0x51298a50), SPH_C32(0x6b6e661f), + SPH_C32(0x0ea5cfe3), SPH_C32(0xe6da7ffe), SPH_C32(0xa8da0000), + SPH_C32(0x96be0000), SPH_C32(0x5c1d0000), SPH_C32(0x07da0002), + SPH_C32(0x7d669583), SPH_C32(0x1f98708a), SPH_C32(0xbb668808), + SPH_C32(0xda878000) } +}; + +#define INPUT_BIG do { \ + unsigned acc = buf[0]; \ + const sph_u32 *rp; \ + rp = &T512_0[acc >> 1][0]; \ + m0 = rp[0]; \ + m1 = rp[1]; \ + m2 = rp[2]; \ + m3 = rp[3]; \ + m4 = rp[4]; \ + m5 = rp[5]; \ + m6 = rp[6]; \ + m7 = rp[7]; \ + m8 = rp[8]; \ + m9 = rp[9]; \ + mA = rp[10]; \ + mB = rp[11]; \ + mC = rp[12]; \ + mD = rp[13]; \ + mE = rp[14]; \ + mF = rp[15]; \ + acc = (acc << 8) | buf[1]; \ + rp = &T512_7[(acc >> 2) & 0x7f][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + m8 ^= rp[8]; \ + m9 ^= rp[9]; \ + mA ^= rp[10]; \ + mB ^= rp[11]; \ + mC ^= rp[12]; \ + mD ^= rp[13]; \ + mE ^= rp[14]; \ + mF ^= rp[15]; \ + acc = (acc << 8) | buf[2]; \ + rp = &T512_14[(acc >> 3) & 0x7f][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + m8 ^= rp[8]; \ + m9 ^= rp[9]; \ + mA ^= rp[10]; \ + mB ^= rp[11]; \ + mC ^= rp[12]; \ + mD ^= rp[13]; \ + mE ^= rp[14]; \ + mF ^= rp[15]; \ + acc = (acc << 8) | buf[3]; \ + rp = &T512_21[(acc >> 4) & 0x7f][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + m8 ^= rp[8]; \ + m9 ^= rp[9]; \ + mA ^= rp[10]; \ + mB ^= rp[11]; \ + mC ^= rp[12]; \ + mD ^= rp[13]; \ + mE ^= rp[14]; \ + mF ^= rp[15]; \ + acc = (acc << 8) | buf[4]; \ + rp = &T512_28[(acc >> 5) & 0x7f][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + m8 ^= rp[8]; \ + m9 ^= rp[9]; \ + mA ^= rp[10]; \ + mB ^= rp[11]; \ + mC ^= rp[12]; \ + mD ^= rp[13]; \ + mE ^= rp[14]; \ + mF ^= rp[15]; \ + acc = (acc << 8) | buf[5]; \ + rp = &T512_35[(acc >> 6) & 0x7f][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + m8 ^= rp[8]; \ + m9 ^= rp[9]; \ + mA ^= rp[10]; \ + mB ^= rp[11]; \ + mC ^= rp[12]; \ + mD ^= rp[13]; \ + mE ^= rp[14]; \ + mF ^= rp[15]; \ + acc = (acc << 8) | buf[6]; \ + rp = &T512_42[(acc >> 7) & 0x7f][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + m8 ^= rp[8]; \ + m9 ^= rp[9]; \ + mA ^= rp[10]; \ + mB ^= rp[11]; \ + mC ^= rp[12]; \ + mD ^= rp[13]; \ + mE ^= rp[14]; \ + mF ^= rp[15]; \ + rp = &T512_49[acc & 0x7f][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + m8 ^= rp[8]; \ + m9 ^= rp[9]; \ + mA ^= rp[10]; \ + mB ^= rp[11]; \ + mC ^= rp[12]; \ + mD ^= rp[13]; \ + mE ^= rp[14]; \ + mF ^= rp[15]; \ + acc = buf[7]; \ + rp = &T512_56[acc >> 1][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + m8 ^= rp[8]; \ + m9 ^= rp[9]; \ + mA ^= rp[10]; \ + mB ^= rp[11]; \ + mC ^= rp[12]; \ + mD ^= rp[13]; \ + mE ^= rp[14]; \ + mF ^= rp[15]; \ + rp = &T512_63[acc & 0x01][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + m8 ^= rp[8]; \ + m9 ^= rp[9]; \ + mA ^= rp[10]; \ + mB ^= rp[11]; \ + mC ^= rp[12]; \ + mD ^= rp[13]; \ + mE ^= rp[14]; \ + mF ^= rp[15]; \ + } while (0) + +#endif + +#if SPH_HAMSI_EXPAND_BIG == 8 + +static const sph_u32 T512_0[256][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0xef0b0270), SPH_C32(0x3afd0000), SPH_C32(0x5dae0000), + SPH_C32(0x69490000), SPH_C32(0x9b0f3c06), SPH_C32(0x4405b5f9), + SPH_C32(0x66140a51), SPH_C32(0x924f5d0a), SPH_C32(0xc96b0030), + SPH_C32(0xe7250000), SPH_C32(0x2f840000), SPH_C32(0x264f0000), + SPH_C32(0x08695bf9), SPH_C32(0x6dfcf137), SPH_C32(0x509f6984), + SPH_C32(0x9e69af68) }, + { SPH_C32(0xc96b0030), SPH_C32(0xe7250000), SPH_C32(0x2f840000), + SPH_C32(0x264f0000), SPH_C32(0x08695bf9), SPH_C32(0x6dfcf137), + SPH_C32(0x509f6984), SPH_C32(0x9e69af68), SPH_C32(0x26600240), + SPH_C32(0xddd80000), SPH_C32(0x722a0000), SPH_C32(0x4f060000), + SPH_C32(0x936667ff), SPH_C32(0x29f944ce), SPH_C32(0x368b63d5), + SPH_C32(0x0c26f262) }, + { SPH_C32(0x26600240), SPH_C32(0xddd80000), SPH_C32(0x722a0000), + SPH_C32(0x4f060000), SPH_C32(0x936667ff), SPH_C32(0x29f944ce), + SPH_C32(0x368b63d5), SPH_C32(0x0c26f262), SPH_C32(0xef0b0270), + SPH_C32(0x3afd0000), SPH_C32(0x5dae0000), SPH_C32(0x69490000), + SPH_C32(0x9b0f3c06), SPH_C32(0x4405b5f9), SPH_C32(0x66140a51), + SPH_C32(0x924f5d0a) }, + { SPH_C32(0x145a3c00), SPH_C32(0xb9e90000), SPH_C32(0x61270000), + SPH_C32(0xf1610000), SPH_C32(0xce613d6c), SPH_C32(0xb0493d78), + SPH_C32(0x47a96720), SPH_C32(0xe18e24c5), SPH_C32(0x23671400), + SPH_C32(0xc8b90000), SPH_C32(0xf4c70000), SPH_C32(0xfb750000), + SPH_C32(0x73cd2465), SPH_C32(0xf8a6a549), SPH_C32(0x02c40a3f), + SPH_C32(0xdc24e61f) }, + { SPH_C32(0xfb513e70), SPH_C32(0x83140000), SPH_C32(0x3c890000), + SPH_C32(0x98280000), SPH_C32(0x556e016a), SPH_C32(0xf44c8881), + SPH_C32(0x21bd6d71), SPH_C32(0x73c179cf), SPH_C32(0xea0c1430), + SPH_C32(0x2f9c0000), SPH_C32(0xdb430000), SPH_C32(0xdd3a0000), + SPH_C32(0x7ba47f9c), SPH_C32(0x955a547e), SPH_C32(0x525b63bb), + SPH_C32(0x424d4977) }, + { SPH_C32(0xdd313c30), SPH_C32(0x5ecc0000), SPH_C32(0x4ea30000), + SPH_C32(0xd72e0000), SPH_C32(0xc6086695), SPH_C32(0xddb5cc4f), + SPH_C32(0x17360ea4), SPH_C32(0x7fe78bad), SPH_C32(0x05071640), + SPH_C32(0x15610000), SPH_C32(0x86ed0000), SPH_C32(0xb4730000), + SPH_C32(0xe0ab439a), SPH_C32(0xd15fe187), SPH_C32(0x344f69ea), + SPH_C32(0xd002147d) }, + { SPH_C32(0x323a3e40), SPH_C32(0x64310000), SPH_C32(0x130d0000), + SPH_C32(0xbe670000), SPH_C32(0x5d075a93), SPH_C32(0x99b079b6), + SPH_C32(0x712204f5), SPH_C32(0xeda8d6a7), SPH_C32(0xcc6c1670), + SPH_C32(0xf2440000), SPH_C32(0xa9690000), SPH_C32(0x923c0000), + SPH_C32(0xe8c21863), SPH_C32(0xbca310b0), SPH_C32(0x64d0006e), + SPH_C32(0x4e6bbb15) }, + { SPH_C32(0x23671400), SPH_C32(0xc8b90000), SPH_C32(0xf4c70000), + SPH_C32(0xfb750000), SPH_C32(0x73cd2465), SPH_C32(0xf8a6a549), + SPH_C32(0x02c40a3f), SPH_C32(0xdc24e61f), SPH_C32(0x373d2800), + SPH_C32(0x71500000), SPH_C32(0x95e00000), SPH_C32(0x0a140000), + SPH_C32(0xbdac1909), SPH_C32(0x48ef9831), SPH_C32(0x456d6d1f), + SPH_C32(0x3daac2da) }, + { SPH_C32(0xcc6c1670), SPH_C32(0xf2440000), SPH_C32(0xa9690000), + SPH_C32(0x923c0000), SPH_C32(0xe8c21863), SPH_C32(0xbca310b0), + SPH_C32(0x64d0006e), SPH_C32(0x4e6bbb15), SPH_C32(0xfe562830), + SPH_C32(0x96750000), SPH_C32(0xba640000), SPH_C32(0x2c5b0000), + SPH_C32(0xb5c542f0), SPH_C32(0x25136906), SPH_C32(0x15f2049b), + SPH_C32(0xa3c36db2) }, + { SPH_C32(0xea0c1430), SPH_C32(0x2f9c0000), SPH_C32(0xdb430000), + SPH_C32(0xdd3a0000), SPH_C32(0x7ba47f9c), SPH_C32(0x955a547e), + SPH_C32(0x525b63bb), SPH_C32(0x424d4977), SPH_C32(0x115d2a40), + SPH_C32(0xac880000), SPH_C32(0xe7ca0000), SPH_C32(0x45120000), + SPH_C32(0x2eca7ef6), SPH_C32(0x6116dcff), SPH_C32(0x73e60eca), + SPH_C32(0x318c30b8) }, + { SPH_C32(0x05071640), SPH_C32(0x15610000), SPH_C32(0x86ed0000), + SPH_C32(0xb4730000), SPH_C32(0xe0ab439a), SPH_C32(0xd15fe187), + SPH_C32(0x344f69ea), SPH_C32(0xd002147d), SPH_C32(0xd8362a70), + SPH_C32(0x4bad0000), SPH_C32(0xc84e0000), SPH_C32(0x635d0000), + SPH_C32(0x26a3250f), SPH_C32(0x0cea2dc8), SPH_C32(0x2379674e), + SPH_C32(0xafe59fd0) }, + { SPH_C32(0x373d2800), SPH_C32(0x71500000), SPH_C32(0x95e00000), + SPH_C32(0x0a140000), SPH_C32(0xbdac1909), SPH_C32(0x48ef9831), + SPH_C32(0x456d6d1f), SPH_C32(0x3daac2da), SPH_C32(0x145a3c00), + SPH_C32(0xb9e90000), SPH_C32(0x61270000), SPH_C32(0xf1610000), + SPH_C32(0xce613d6c), SPH_C32(0xb0493d78), SPH_C32(0x47a96720), + SPH_C32(0xe18e24c5) }, + { SPH_C32(0xd8362a70), SPH_C32(0x4bad0000), SPH_C32(0xc84e0000), + SPH_C32(0x635d0000), SPH_C32(0x26a3250f), SPH_C32(0x0cea2dc8), + SPH_C32(0x2379674e), SPH_C32(0xafe59fd0), SPH_C32(0xdd313c30), + SPH_C32(0x5ecc0000), SPH_C32(0x4ea30000), SPH_C32(0xd72e0000), + SPH_C32(0xc6086695), SPH_C32(0xddb5cc4f), SPH_C32(0x17360ea4), + SPH_C32(0x7fe78bad) }, + { SPH_C32(0xfe562830), SPH_C32(0x96750000), SPH_C32(0xba640000), + SPH_C32(0x2c5b0000), SPH_C32(0xb5c542f0), SPH_C32(0x25136906), + SPH_C32(0x15f2049b), SPH_C32(0xa3c36db2), SPH_C32(0x323a3e40), + SPH_C32(0x64310000), SPH_C32(0x130d0000), SPH_C32(0xbe670000), + SPH_C32(0x5d075a93), SPH_C32(0x99b079b6), SPH_C32(0x712204f5), + SPH_C32(0xeda8d6a7) }, + { SPH_C32(0x115d2a40), SPH_C32(0xac880000), SPH_C32(0xe7ca0000), + SPH_C32(0x45120000), SPH_C32(0x2eca7ef6), SPH_C32(0x6116dcff), + SPH_C32(0x73e60eca), SPH_C32(0x318c30b8), SPH_C32(0xfb513e70), + SPH_C32(0x83140000), SPH_C32(0x3c890000), SPH_C32(0x98280000), + SPH_C32(0x556e016a), SPH_C32(0xf44c8881), SPH_C32(0x21bd6d71), + SPH_C32(0x73c179cf) }, + { SPH_C32(0x54285c00), SPH_C32(0xeaed0000), SPH_C32(0xc5d60000), + SPH_C32(0xa1c50000), SPH_C32(0xb3a26770), SPH_C32(0x94a5c4e1), + SPH_C32(0x6bb0419d), SPH_C32(0x551b3782), SPH_C32(0x9cbb1800), + SPH_C32(0xb0d30000), SPH_C32(0x92510000), SPH_C32(0xed930000), + SPH_C32(0x593a4345), SPH_C32(0xe114d5f4), SPH_C32(0x430633da), + SPH_C32(0x78cace29) }, + { SPH_C32(0xbb235e70), SPH_C32(0xd0100000), SPH_C32(0x98780000), + SPH_C32(0xc88c0000), SPH_C32(0x28ad5b76), SPH_C32(0xd0a07118), + SPH_C32(0x0da44bcc), SPH_C32(0xc7546a88), SPH_C32(0x55d01830), + SPH_C32(0x57f60000), SPH_C32(0xbdd50000), SPH_C32(0xcbdc0000), + SPH_C32(0x515318bc), SPH_C32(0x8ce824c3), SPH_C32(0x13995a5e), + SPH_C32(0xe6a36141) }, + { SPH_C32(0x9d435c30), SPH_C32(0x0dc80000), SPH_C32(0xea520000), + SPH_C32(0x878a0000), SPH_C32(0xbbcb3c89), SPH_C32(0xf95935d6), + SPH_C32(0x3b2f2819), SPH_C32(0xcb7298ea), SPH_C32(0xbadb1a40), + SPH_C32(0x6d0b0000), SPH_C32(0xe07b0000), SPH_C32(0xa2950000), + SPH_C32(0xca5c24ba), SPH_C32(0xc8ed913a), SPH_C32(0x758d500f), + SPH_C32(0x74ec3c4b) }, + { SPH_C32(0x72485e40), SPH_C32(0x37350000), SPH_C32(0xb7fc0000), + SPH_C32(0xeec30000), SPH_C32(0x20c4008f), SPH_C32(0xbd5c802f), + SPH_C32(0x5d3b2248), SPH_C32(0x593dc5e0), SPH_C32(0x73b01a70), + SPH_C32(0x8a2e0000), SPH_C32(0xcfff0000), SPH_C32(0x84da0000), + SPH_C32(0xc2357f43), SPH_C32(0xa511600d), SPH_C32(0x2512398b), + SPH_C32(0xea859323) }, + { SPH_C32(0x40726000), SPH_C32(0x53040000), SPH_C32(0xa4f10000), + SPH_C32(0x50a40000), SPH_C32(0x7dc35a1c), SPH_C32(0x24ecf999), + SPH_C32(0x2c1926bd), SPH_C32(0xb4951347), SPH_C32(0xbfdc0c00), + SPH_C32(0x786a0000), SPH_C32(0x66960000), SPH_C32(0x16e60000), + SPH_C32(0x2af76720), SPH_C32(0x19b270bd), SPH_C32(0x41c239e5), + SPH_C32(0xa4ee2836) }, + { SPH_C32(0xaf796270), SPH_C32(0x69f90000), SPH_C32(0xf95f0000), + SPH_C32(0x39ed0000), SPH_C32(0xe6cc661a), SPH_C32(0x60e94c60), + SPH_C32(0x4a0d2cec), SPH_C32(0x26da4e4d), SPH_C32(0x76b70c30), + SPH_C32(0x9f4f0000), SPH_C32(0x49120000), SPH_C32(0x30a90000), + SPH_C32(0x229e3cd9), SPH_C32(0x744e818a), SPH_C32(0x115d5061), + SPH_C32(0x3a87875e) }, + { SPH_C32(0x89196030), SPH_C32(0xb4210000), SPH_C32(0x8b750000), + SPH_C32(0x76eb0000), SPH_C32(0x75aa01e5), SPH_C32(0x491008ae), + SPH_C32(0x7c864f39), SPH_C32(0x2afcbc2f), SPH_C32(0x99bc0e40), + SPH_C32(0xa5b20000), SPH_C32(0x14bc0000), SPH_C32(0x59e00000), + SPH_C32(0xb99100df), SPH_C32(0x304b3473), SPH_C32(0x77495a30), + SPH_C32(0xa8c8da54) }, + { SPH_C32(0x66126240), SPH_C32(0x8edc0000), SPH_C32(0xd6db0000), + SPH_C32(0x1fa20000), SPH_C32(0xeea53de3), SPH_C32(0x0d15bd57), + SPH_C32(0x1a924568), SPH_C32(0xb8b3e125), SPH_C32(0x50d70e70), + SPH_C32(0x42970000), SPH_C32(0x3b380000), SPH_C32(0x7faf0000), + SPH_C32(0xb1f85b26), SPH_C32(0x5db7c544), SPH_C32(0x27d633b4), + SPH_C32(0x36a1753c) }, + { SPH_C32(0x774f4800), SPH_C32(0x22540000), SPH_C32(0x31110000), + SPH_C32(0x5ab00000), SPH_C32(0xc06f4315), SPH_C32(0x6c0361a8), + SPH_C32(0x69744ba2), SPH_C32(0x893fd19d), SPH_C32(0xab863000), + SPH_C32(0xc1830000), SPH_C32(0x07b10000), SPH_C32(0xe7870000), + SPH_C32(0xe4965a4c), SPH_C32(0xa9fb4dc5), SPH_C32(0x066b5ec5), + SPH_C32(0x45600cf3) }, + { SPH_C32(0x98444a70), SPH_C32(0x18a90000), SPH_C32(0x6cbf0000), + SPH_C32(0x33f90000), SPH_C32(0x5b607f13), SPH_C32(0x2806d451), + SPH_C32(0x0f6041f3), SPH_C32(0x1b708c97), SPH_C32(0x62ed3030), + SPH_C32(0x26a60000), SPH_C32(0x28350000), SPH_C32(0xc1c80000), + SPH_C32(0xecff01b5), SPH_C32(0xc407bcf2), SPH_C32(0x56f43741), + SPH_C32(0xdb09a39b) }, + { SPH_C32(0xbe244830), SPH_C32(0xc5710000), SPH_C32(0x1e950000), + SPH_C32(0x7cff0000), SPH_C32(0xc80618ec), SPH_C32(0x01ff909f), + SPH_C32(0x39eb2226), SPH_C32(0x17567ef5), SPH_C32(0x8de63240), + SPH_C32(0x1c5b0000), SPH_C32(0x759b0000), SPH_C32(0xa8810000), + SPH_C32(0x77f03db3), SPH_C32(0x8002090b), SPH_C32(0x30e03d10), + SPH_C32(0x4946fe91) }, + { SPH_C32(0x512f4a40), SPH_C32(0xff8c0000), SPH_C32(0x433b0000), + SPH_C32(0x15b60000), SPH_C32(0x530924ea), SPH_C32(0x45fa2566), + SPH_C32(0x5fff2877), SPH_C32(0x851923ff), SPH_C32(0x448d3270), + SPH_C32(0xfb7e0000), SPH_C32(0x5a1f0000), SPH_C32(0x8ece0000), + SPH_C32(0x7f99664a), SPH_C32(0xedfef83c), SPH_C32(0x607f5494), + SPH_C32(0xd72f51f9) }, + { SPH_C32(0x63157400), SPH_C32(0x9bbd0000), SPH_C32(0x50360000), + SPH_C32(0xabd10000), SPH_C32(0x0e0e7e79), SPH_C32(0xdc4a5cd0), + SPH_C32(0x2edd2c82), SPH_C32(0x68b1f558), SPH_C32(0x88e12400), + SPH_C32(0x093a0000), SPH_C32(0xf3760000), SPH_C32(0x1cf20000), + SPH_C32(0x975b7e29), SPH_C32(0x515de88c), SPH_C32(0x04af54fa), + SPH_C32(0x9944eaec) }, + { SPH_C32(0x8c1e7670), SPH_C32(0xa1400000), SPH_C32(0x0d980000), + SPH_C32(0xc2980000), SPH_C32(0x9501427f), SPH_C32(0x984fe929), + SPH_C32(0x48c926d3), SPH_C32(0xfafea852), SPH_C32(0x418a2430), + SPH_C32(0xee1f0000), SPH_C32(0xdcf20000), SPH_C32(0x3abd0000), + SPH_C32(0x9f3225d0), SPH_C32(0x3ca119bb), SPH_C32(0x54303d7e), + SPH_C32(0x072d4584) }, + { SPH_C32(0xaa7e7430), SPH_C32(0x7c980000), SPH_C32(0x7fb20000), + SPH_C32(0x8d9e0000), SPH_C32(0x06672580), SPH_C32(0xb1b6ade7), + SPH_C32(0x7e424506), SPH_C32(0xf6d85a30), SPH_C32(0xae812640), + SPH_C32(0xd4e20000), SPH_C32(0x815c0000), SPH_C32(0x53f40000), + SPH_C32(0x043d19d6), SPH_C32(0x78a4ac42), SPH_C32(0x3224372f), + SPH_C32(0x9562188e) }, + { SPH_C32(0x45757640), SPH_C32(0x46650000), SPH_C32(0x221c0000), + SPH_C32(0xe4d70000), SPH_C32(0x9d681986), SPH_C32(0xf5b3181e), + SPH_C32(0x18564f57), SPH_C32(0x6497073a), SPH_C32(0x67ea2670), + SPH_C32(0x33c70000), SPH_C32(0xaed80000), SPH_C32(0x75bb0000), + SPH_C32(0x0c54422f), SPH_C32(0x15585d75), SPH_C32(0x62bb5eab), + SPH_C32(0x0b0bb7e6) }, + { SPH_C32(0x9cbb1800), SPH_C32(0xb0d30000), SPH_C32(0x92510000), + SPH_C32(0xed930000), SPH_C32(0x593a4345), SPH_C32(0xe114d5f4), + SPH_C32(0x430633da), SPH_C32(0x78cace29), SPH_C32(0xc8934400), + SPH_C32(0x5a3e0000), SPH_C32(0x57870000), SPH_C32(0x4c560000), + SPH_C32(0xea982435), SPH_C32(0x75b11115), SPH_C32(0x28b67247), + SPH_C32(0x2dd1f9ab) }, + { SPH_C32(0x73b01a70), SPH_C32(0x8a2e0000), SPH_C32(0xcfff0000), + SPH_C32(0x84da0000), SPH_C32(0xc2357f43), SPH_C32(0xa511600d), + SPH_C32(0x2512398b), SPH_C32(0xea859323), SPH_C32(0x01f84430), + SPH_C32(0xbd1b0000), SPH_C32(0x78030000), SPH_C32(0x6a190000), + SPH_C32(0xe2f17fcc), SPH_C32(0x184de022), SPH_C32(0x78291bc3), + SPH_C32(0xb3b856c3) }, + { SPH_C32(0x55d01830), SPH_C32(0x57f60000), SPH_C32(0xbdd50000), + SPH_C32(0xcbdc0000), SPH_C32(0x515318bc), SPH_C32(0x8ce824c3), + SPH_C32(0x13995a5e), SPH_C32(0xe6a36141), SPH_C32(0xeef34640), + SPH_C32(0x87e60000), SPH_C32(0x25ad0000), SPH_C32(0x03500000), + SPH_C32(0x79fe43ca), SPH_C32(0x5c4855db), SPH_C32(0x1e3d1192), + SPH_C32(0x21f70bc9) }, + { SPH_C32(0xbadb1a40), SPH_C32(0x6d0b0000), SPH_C32(0xe07b0000), + SPH_C32(0xa2950000), SPH_C32(0xca5c24ba), SPH_C32(0xc8ed913a), + SPH_C32(0x758d500f), SPH_C32(0x74ec3c4b), SPH_C32(0x27984670), + SPH_C32(0x60c30000), SPH_C32(0x0a290000), SPH_C32(0x251f0000), + SPH_C32(0x71971833), SPH_C32(0x31b4a4ec), SPH_C32(0x4ea27816), + SPH_C32(0xbf9ea4a1) }, + { SPH_C32(0x88e12400), SPH_C32(0x093a0000), SPH_C32(0xf3760000), + SPH_C32(0x1cf20000), SPH_C32(0x975b7e29), SPH_C32(0x515de88c), + SPH_C32(0x04af54fa), SPH_C32(0x9944eaec), SPH_C32(0xebf45000), + SPH_C32(0x92870000), SPH_C32(0xa3400000), SPH_C32(0xb7230000), + SPH_C32(0x99550050), SPH_C32(0x8d17b45c), SPH_C32(0x2a727878), + SPH_C32(0xf1f51fb4) }, + { SPH_C32(0x67ea2670), SPH_C32(0x33c70000), SPH_C32(0xaed80000), + SPH_C32(0x75bb0000), SPH_C32(0x0c54422f), SPH_C32(0x15585d75), + SPH_C32(0x62bb5eab), SPH_C32(0x0b0bb7e6), SPH_C32(0x229f5030), + SPH_C32(0x75a20000), SPH_C32(0x8cc40000), SPH_C32(0x916c0000), + SPH_C32(0x913c5ba9), SPH_C32(0xe0eb456b), SPH_C32(0x7aed11fc), + SPH_C32(0x6f9cb0dc) }, + { SPH_C32(0x418a2430), SPH_C32(0xee1f0000), SPH_C32(0xdcf20000), + SPH_C32(0x3abd0000), SPH_C32(0x9f3225d0), SPH_C32(0x3ca119bb), + SPH_C32(0x54303d7e), SPH_C32(0x072d4584), SPH_C32(0xcd945240), + SPH_C32(0x4f5f0000), SPH_C32(0xd16a0000), SPH_C32(0xf8250000), + SPH_C32(0x0a3367af), SPH_C32(0xa4eef092), SPH_C32(0x1cf91bad), + SPH_C32(0xfdd3edd6) }, + { SPH_C32(0xae812640), SPH_C32(0xd4e20000), SPH_C32(0x815c0000), + SPH_C32(0x53f40000), SPH_C32(0x043d19d6), SPH_C32(0x78a4ac42), + SPH_C32(0x3224372f), SPH_C32(0x9562188e), SPH_C32(0x04ff5270), + SPH_C32(0xa87a0000), SPH_C32(0xfeee0000), SPH_C32(0xde6a0000), + SPH_C32(0x025a3c56), SPH_C32(0xc91201a5), SPH_C32(0x4c667229), + SPH_C32(0x63ba42be) }, + { SPH_C32(0xbfdc0c00), SPH_C32(0x786a0000), SPH_C32(0x66960000), + SPH_C32(0x16e60000), SPH_C32(0x2af76720), SPH_C32(0x19b270bd), + SPH_C32(0x41c239e5), SPH_C32(0xa4ee2836), SPH_C32(0xffae6c00), + SPH_C32(0x2b6e0000), SPH_C32(0xc2670000), SPH_C32(0x46420000), + SPH_C32(0x57343d3c), SPH_C32(0x3d5e8924), SPH_C32(0x6ddb1f58), + SPH_C32(0x107b3b71) }, + { SPH_C32(0x50d70e70), SPH_C32(0x42970000), SPH_C32(0x3b380000), + SPH_C32(0x7faf0000), SPH_C32(0xb1f85b26), SPH_C32(0x5db7c544), + SPH_C32(0x27d633b4), SPH_C32(0x36a1753c), SPH_C32(0x36c56c30), + SPH_C32(0xcc4b0000), SPH_C32(0xede30000), SPH_C32(0x600d0000), + SPH_C32(0x5f5d66c5), SPH_C32(0x50a27813), SPH_C32(0x3d4476dc), + SPH_C32(0x8e129419) }, + { SPH_C32(0x76b70c30), SPH_C32(0x9f4f0000), SPH_C32(0x49120000), + SPH_C32(0x30a90000), SPH_C32(0x229e3cd9), SPH_C32(0x744e818a), + SPH_C32(0x115d5061), SPH_C32(0x3a87875e), SPH_C32(0xd9ce6e40), + SPH_C32(0xf6b60000), SPH_C32(0xb04d0000), SPH_C32(0x09440000), + SPH_C32(0xc4525ac3), SPH_C32(0x14a7cdea), SPH_C32(0x5b507c8d), + SPH_C32(0x1c5dc913) }, + { SPH_C32(0x99bc0e40), SPH_C32(0xa5b20000), SPH_C32(0x14bc0000), + SPH_C32(0x59e00000), SPH_C32(0xb99100df), SPH_C32(0x304b3473), + SPH_C32(0x77495a30), SPH_C32(0xa8c8da54), SPH_C32(0x10a56e70), + SPH_C32(0x11930000), SPH_C32(0x9fc90000), SPH_C32(0x2f0b0000), + SPH_C32(0xcc3b013a), SPH_C32(0x795b3cdd), SPH_C32(0x0bcf1509), + SPH_C32(0x8234667b) }, + { SPH_C32(0xab863000), SPH_C32(0xc1830000), SPH_C32(0x07b10000), + SPH_C32(0xe7870000), SPH_C32(0xe4965a4c), SPH_C32(0xa9fb4dc5), + SPH_C32(0x066b5ec5), SPH_C32(0x45600cf3), SPH_C32(0xdcc97800), + SPH_C32(0xe3d70000), SPH_C32(0x36a00000), SPH_C32(0xbd370000), + SPH_C32(0x24f91959), SPH_C32(0xc5f82c6d), SPH_C32(0x6f1f1567), + SPH_C32(0xcc5fdd6e) }, + { SPH_C32(0x448d3270), SPH_C32(0xfb7e0000), SPH_C32(0x5a1f0000), + SPH_C32(0x8ece0000), SPH_C32(0x7f99664a), SPH_C32(0xedfef83c), + SPH_C32(0x607f5494), SPH_C32(0xd72f51f9), SPH_C32(0x15a27830), + SPH_C32(0x04f20000), SPH_C32(0x19240000), SPH_C32(0x9b780000), + SPH_C32(0x2c9042a0), SPH_C32(0xa804dd5a), SPH_C32(0x3f807ce3), + SPH_C32(0x52367206) }, + { SPH_C32(0x62ed3030), SPH_C32(0x26a60000), SPH_C32(0x28350000), + SPH_C32(0xc1c80000), SPH_C32(0xecff01b5), SPH_C32(0xc407bcf2), + SPH_C32(0x56f43741), SPH_C32(0xdb09a39b), SPH_C32(0xfaa97a40), + SPH_C32(0x3e0f0000), SPH_C32(0x448a0000), SPH_C32(0xf2310000), + SPH_C32(0xb79f7ea6), SPH_C32(0xec0168a3), SPH_C32(0x599476b2), + SPH_C32(0xc0792f0c) }, + { SPH_C32(0x8de63240), SPH_C32(0x1c5b0000), SPH_C32(0x759b0000), + SPH_C32(0xa8810000), SPH_C32(0x77f03db3), SPH_C32(0x8002090b), + SPH_C32(0x30e03d10), SPH_C32(0x4946fe91), SPH_C32(0x33c27a70), + SPH_C32(0xd92a0000), SPH_C32(0x6b0e0000), SPH_C32(0xd47e0000), + SPH_C32(0xbff6255f), SPH_C32(0x81fd9994), SPH_C32(0x090b1f36), + SPH_C32(0x5e108064) }, + { SPH_C32(0xc8934400), SPH_C32(0x5a3e0000), SPH_C32(0x57870000), + SPH_C32(0x4c560000), SPH_C32(0xea982435), SPH_C32(0x75b11115), + SPH_C32(0x28b67247), SPH_C32(0x2dd1f9ab), SPH_C32(0x54285c00), + SPH_C32(0xeaed0000), SPH_C32(0xc5d60000), SPH_C32(0xa1c50000), + SPH_C32(0xb3a26770), SPH_C32(0x94a5c4e1), SPH_C32(0x6bb0419d), + SPH_C32(0x551b3782) }, + { SPH_C32(0x27984670), SPH_C32(0x60c30000), SPH_C32(0x0a290000), + SPH_C32(0x251f0000), SPH_C32(0x71971833), SPH_C32(0x31b4a4ec), + SPH_C32(0x4ea27816), SPH_C32(0xbf9ea4a1), SPH_C32(0x9d435c30), + SPH_C32(0x0dc80000), SPH_C32(0xea520000), SPH_C32(0x878a0000), + SPH_C32(0xbbcb3c89), SPH_C32(0xf95935d6), SPH_C32(0x3b2f2819), + SPH_C32(0xcb7298ea) }, + { SPH_C32(0x01f84430), SPH_C32(0xbd1b0000), SPH_C32(0x78030000), + SPH_C32(0x6a190000), SPH_C32(0xe2f17fcc), SPH_C32(0x184de022), + SPH_C32(0x78291bc3), SPH_C32(0xb3b856c3), SPH_C32(0x72485e40), + SPH_C32(0x37350000), SPH_C32(0xb7fc0000), SPH_C32(0xeec30000), + SPH_C32(0x20c4008f), SPH_C32(0xbd5c802f), SPH_C32(0x5d3b2248), + SPH_C32(0x593dc5e0) }, + { SPH_C32(0xeef34640), SPH_C32(0x87e60000), SPH_C32(0x25ad0000), + SPH_C32(0x03500000), SPH_C32(0x79fe43ca), SPH_C32(0x5c4855db), + SPH_C32(0x1e3d1192), SPH_C32(0x21f70bc9), SPH_C32(0xbb235e70), + SPH_C32(0xd0100000), SPH_C32(0x98780000), SPH_C32(0xc88c0000), + SPH_C32(0x28ad5b76), SPH_C32(0xd0a07118), SPH_C32(0x0da44bcc), + SPH_C32(0xc7546a88) }, + { SPH_C32(0xdcc97800), SPH_C32(0xe3d70000), SPH_C32(0x36a00000), + SPH_C32(0xbd370000), SPH_C32(0x24f91959), SPH_C32(0xc5f82c6d), + SPH_C32(0x6f1f1567), SPH_C32(0xcc5fdd6e), SPH_C32(0x774f4800), + SPH_C32(0x22540000), SPH_C32(0x31110000), SPH_C32(0x5ab00000), + SPH_C32(0xc06f4315), SPH_C32(0x6c0361a8), SPH_C32(0x69744ba2), + SPH_C32(0x893fd19d) }, + { SPH_C32(0x33c27a70), SPH_C32(0xd92a0000), SPH_C32(0x6b0e0000), + SPH_C32(0xd47e0000), SPH_C32(0xbff6255f), SPH_C32(0x81fd9994), + SPH_C32(0x090b1f36), SPH_C32(0x5e108064), SPH_C32(0xbe244830), + SPH_C32(0xc5710000), SPH_C32(0x1e950000), SPH_C32(0x7cff0000), + SPH_C32(0xc80618ec), SPH_C32(0x01ff909f), SPH_C32(0x39eb2226), + SPH_C32(0x17567ef5) }, + { SPH_C32(0x15a27830), SPH_C32(0x04f20000), SPH_C32(0x19240000), + SPH_C32(0x9b780000), SPH_C32(0x2c9042a0), SPH_C32(0xa804dd5a), + SPH_C32(0x3f807ce3), SPH_C32(0x52367206), SPH_C32(0x512f4a40), + SPH_C32(0xff8c0000), SPH_C32(0x433b0000), SPH_C32(0x15b60000), + SPH_C32(0x530924ea), SPH_C32(0x45fa2566), SPH_C32(0x5fff2877), + SPH_C32(0x851923ff) }, + { SPH_C32(0xfaa97a40), SPH_C32(0x3e0f0000), SPH_C32(0x448a0000), + SPH_C32(0xf2310000), SPH_C32(0xb79f7ea6), SPH_C32(0xec0168a3), + SPH_C32(0x599476b2), SPH_C32(0xc0792f0c), SPH_C32(0x98444a70), + SPH_C32(0x18a90000), SPH_C32(0x6cbf0000), SPH_C32(0x33f90000), + SPH_C32(0x5b607f13), SPH_C32(0x2806d451), SPH_C32(0x0f6041f3), + SPH_C32(0x1b708c97) }, + { SPH_C32(0xebf45000), SPH_C32(0x92870000), SPH_C32(0xa3400000), + SPH_C32(0xb7230000), SPH_C32(0x99550050), SPH_C32(0x8d17b45c), + SPH_C32(0x2a727878), SPH_C32(0xf1f51fb4), SPH_C32(0x63157400), + SPH_C32(0x9bbd0000), SPH_C32(0x50360000), SPH_C32(0xabd10000), + SPH_C32(0x0e0e7e79), SPH_C32(0xdc4a5cd0), SPH_C32(0x2edd2c82), + SPH_C32(0x68b1f558) }, + { SPH_C32(0x04ff5270), SPH_C32(0xa87a0000), SPH_C32(0xfeee0000), + SPH_C32(0xde6a0000), SPH_C32(0x025a3c56), SPH_C32(0xc91201a5), + SPH_C32(0x4c667229), SPH_C32(0x63ba42be), SPH_C32(0xaa7e7430), + SPH_C32(0x7c980000), SPH_C32(0x7fb20000), SPH_C32(0x8d9e0000), + SPH_C32(0x06672580), SPH_C32(0xb1b6ade7), SPH_C32(0x7e424506), + SPH_C32(0xf6d85a30) }, + { SPH_C32(0x229f5030), SPH_C32(0x75a20000), SPH_C32(0x8cc40000), + SPH_C32(0x916c0000), SPH_C32(0x913c5ba9), SPH_C32(0xe0eb456b), + SPH_C32(0x7aed11fc), SPH_C32(0x6f9cb0dc), SPH_C32(0x45757640), + SPH_C32(0x46650000), SPH_C32(0x221c0000), SPH_C32(0xe4d70000), + SPH_C32(0x9d681986), SPH_C32(0xf5b3181e), SPH_C32(0x18564f57), + SPH_C32(0x6497073a) }, + { SPH_C32(0xcd945240), SPH_C32(0x4f5f0000), SPH_C32(0xd16a0000), + SPH_C32(0xf8250000), SPH_C32(0x0a3367af), SPH_C32(0xa4eef092), + SPH_C32(0x1cf91bad), SPH_C32(0xfdd3edd6), SPH_C32(0x8c1e7670), + SPH_C32(0xa1400000), SPH_C32(0x0d980000), SPH_C32(0xc2980000), + SPH_C32(0x9501427f), SPH_C32(0x984fe929), SPH_C32(0x48c926d3), + SPH_C32(0xfafea852) }, + { SPH_C32(0xffae6c00), SPH_C32(0x2b6e0000), SPH_C32(0xc2670000), + SPH_C32(0x46420000), SPH_C32(0x57343d3c), SPH_C32(0x3d5e8924), + SPH_C32(0x6ddb1f58), SPH_C32(0x107b3b71), SPH_C32(0x40726000), + SPH_C32(0x53040000), SPH_C32(0xa4f10000), SPH_C32(0x50a40000), + SPH_C32(0x7dc35a1c), SPH_C32(0x24ecf999), SPH_C32(0x2c1926bd), + SPH_C32(0xb4951347) }, + { SPH_C32(0x10a56e70), SPH_C32(0x11930000), SPH_C32(0x9fc90000), + SPH_C32(0x2f0b0000), SPH_C32(0xcc3b013a), SPH_C32(0x795b3cdd), + SPH_C32(0x0bcf1509), SPH_C32(0x8234667b), SPH_C32(0x89196030), + SPH_C32(0xb4210000), SPH_C32(0x8b750000), SPH_C32(0x76eb0000), + SPH_C32(0x75aa01e5), SPH_C32(0x491008ae), SPH_C32(0x7c864f39), + SPH_C32(0x2afcbc2f) }, + { SPH_C32(0x36c56c30), SPH_C32(0xcc4b0000), SPH_C32(0xede30000), + SPH_C32(0x600d0000), SPH_C32(0x5f5d66c5), SPH_C32(0x50a27813), + SPH_C32(0x3d4476dc), SPH_C32(0x8e129419), SPH_C32(0x66126240), + SPH_C32(0x8edc0000), SPH_C32(0xd6db0000), SPH_C32(0x1fa20000), + SPH_C32(0xeea53de3), SPH_C32(0x0d15bd57), SPH_C32(0x1a924568), + SPH_C32(0xb8b3e125) }, + { SPH_C32(0xd9ce6e40), SPH_C32(0xf6b60000), SPH_C32(0xb04d0000), + SPH_C32(0x09440000), SPH_C32(0xc4525ac3), SPH_C32(0x14a7cdea), + SPH_C32(0x5b507c8d), SPH_C32(0x1c5dc913), SPH_C32(0xaf796270), + SPH_C32(0x69f90000), SPH_C32(0xf95f0000), SPH_C32(0x39ed0000), + SPH_C32(0xe6cc661a), SPH_C32(0x60e94c60), SPH_C32(0x4a0d2cec), + SPH_C32(0x26da4e4d) }, + { SPH_C32(0x29449c00), SPH_C32(0x64e70000), SPH_C32(0xf24b0000), + SPH_C32(0xc2f30000), SPH_C32(0x0ede4e8f), SPH_C32(0x56c23745), + SPH_C32(0xf3e04259), SPH_C32(0x8d0d9ec4), SPH_C32(0x466d0c00), + SPH_C32(0x08620000), SPH_C32(0xdd5d0000), SPH_C32(0xbadd0000), + SPH_C32(0x6a927942), SPH_C32(0x441f2b93), SPH_C32(0x218ace6f), + SPH_C32(0xbf2c0be2) }, + { SPH_C32(0xc64f9e70), SPH_C32(0x5e1a0000), SPH_C32(0xafe50000), + SPH_C32(0xabba0000), SPH_C32(0x95d17289), SPH_C32(0x12c782bc), + SPH_C32(0x95f44808), SPH_C32(0x1f42c3ce), SPH_C32(0x8f060c30), + SPH_C32(0xef470000), SPH_C32(0xf2d90000), SPH_C32(0x9c920000), + SPH_C32(0x62fb22bb), SPH_C32(0x29e3daa4), SPH_C32(0x7115a7eb), + SPH_C32(0x2145a48a) }, + { SPH_C32(0xe02f9c30), SPH_C32(0x83c20000), SPH_C32(0xddcf0000), + SPH_C32(0xe4bc0000), SPH_C32(0x06b71576), SPH_C32(0x3b3ec672), + SPH_C32(0xa37f2bdd), SPH_C32(0x136431ac), SPH_C32(0x600d0e40), + SPH_C32(0xd5ba0000), SPH_C32(0xaf770000), SPH_C32(0xf5db0000), + SPH_C32(0xf9f41ebd), SPH_C32(0x6de66f5d), SPH_C32(0x1701adba), + SPH_C32(0xb30af980) }, + { SPH_C32(0x0f249e40), SPH_C32(0xb93f0000), SPH_C32(0x80610000), + SPH_C32(0x8df50000), SPH_C32(0x9db82970), SPH_C32(0x7f3b738b), + SPH_C32(0xc56b218c), SPH_C32(0x812b6ca6), SPH_C32(0xa9660e70), + SPH_C32(0x329f0000), SPH_C32(0x80f30000), SPH_C32(0xd3940000), + SPH_C32(0xf19d4544), SPH_C32(0x001a9e6a), SPH_C32(0x479ec43e), + SPH_C32(0x2d6356e8) }, + { SPH_C32(0x3d1ea000), SPH_C32(0xdd0e0000), SPH_C32(0x936c0000), + SPH_C32(0x33920000), SPH_C32(0xc0bf73e3), SPH_C32(0xe68b0a3d), + SPH_C32(0xb4492579), SPH_C32(0x6c83ba01), SPH_C32(0x650a1800), + SPH_C32(0xc0db0000), SPH_C32(0x299a0000), SPH_C32(0x41a80000), + SPH_C32(0x195f5d27), SPH_C32(0xbcb98eda), SPH_C32(0x234ec450), + SPH_C32(0x6308edfd) }, + { SPH_C32(0xd215a270), SPH_C32(0xe7f30000), SPH_C32(0xcec20000), + SPH_C32(0x5adb0000), SPH_C32(0x5bb04fe5), SPH_C32(0xa28ebfc4), + SPH_C32(0xd25d2f28), SPH_C32(0xfecce70b), SPH_C32(0xac611830), + SPH_C32(0x27fe0000), SPH_C32(0x061e0000), SPH_C32(0x67e70000), + SPH_C32(0x113606de), SPH_C32(0xd1457fed), SPH_C32(0x73d1add4), + SPH_C32(0xfd614295) }, + { SPH_C32(0xf475a030), SPH_C32(0x3a2b0000), SPH_C32(0xbce80000), + SPH_C32(0x15dd0000), SPH_C32(0xc8d6281a), SPH_C32(0x8b77fb0a), + SPH_C32(0xe4d64cfd), SPH_C32(0xf2ea1569), SPH_C32(0x436a1a40), + SPH_C32(0x1d030000), SPH_C32(0x5bb00000), SPH_C32(0x0eae0000), + SPH_C32(0x8a393ad8), SPH_C32(0x9540ca14), SPH_C32(0x15c5a785), + SPH_C32(0x6f2e1f9f) }, + { SPH_C32(0x1b7ea240), SPH_C32(0x00d60000), SPH_C32(0xe1460000), + SPH_C32(0x7c940000), SPH_C32(0x53d9141c), SPH_C32(0xcf724ef3), + SPH_C32(0x82c246ac), SPH_C32(0x60a54863), SPH_C32(0x8a011a70), + SPH_C32(0xfa260000), SPH_C32(0x74340000), SPH_C32(0x28e10000), + SPH_C32(0x82506121), SPH_C32(0xf8bc3b23), SPH_C32(0x455ace01), + SPH_C32(0xf147b0f7) }, + { SPH_C32(0x0a238800), SPH_C32(0xac5e0000), SPH_C32(0x068c0000), + SPH_C32(0x39860000), SPH_C32(0x7d136aea), SPH_C32(0xae64920c), + SPH_C32(0xf1244866), SPH_C32(0x512978db), SPH_C32(0x71502400), + SPH_C32(0x79320000), SPH_C32(0x48bd0000), SPH_C32(0xb0c90000), + SPH_C32(0xd73e604b), SPH_C32(0x0cf0b3a2), SPH_C32(0x64e7a370), + SPH_C32(0x8286c938) }, + { SPH_C32(0xe5288a70), SPH_C32(0x96a30000), SPH_C32(0x5b220000), + SPH_C32(0x50cf0000), SPH_C32(0xe61c56ec), SPH_C32(0xea6127f5), + SPH_C32(0x97304237), SPH_C32(0xc36625d1), SPH_C32(0xb83b2430), + SPH_C32(0x9e170000), SPH_C32(0x67390000), SPH_C32(0x96860000), + SPH_C32(0xdf573bb2), SPH_C32(0x610c4295), SPH_C32(0x3478caf4), + SPH_C32(0x1cef6650) }, + { SPH_C32(0xc3488830), SPH_C32(0x4b7b0000), SPH_C32(0x29080000), + SPH_C32(0x1fc90000), SPH_C32(0x757a3113), SPH_C32(0xc398633b), + SPH_C32(0xa1bb21e2), SPH_C32(0xcf40d7b3), SPH_C32(0x57302640), + SPH_C32(0xa4ea0000), SPH_C32(0x3a970000), SPH_C32(0xffcf0000), + SPH_C32(0x445807b4), SPH_C32(0x2509f76c), SPH_C32(0x526cc0a5), + SPH_C32(0x8ea03b5a) }, + { SPH_C32(0x2c438a40), SPH_C32(0x71860000), SPH_C32(0x74a60000), + SPH_C32(0x76800000), SPH_C32(0xee750d15), SPH_C32(0x879dd6c2), + SPH_C32(0xc7af2bb3), SPH_C32(0x5d0f8ab9), SPH_C32(0x9e5b2670), + SPH_C32(0x43cf0000), SPH_C32(0x15130000), SPH_C32(0xd9800000), + SPH_C32(0x4c315c4d), SPH_C32(0x48f5065b), SPH_C32(0x02f3a921), + SPH_C32(0x10c99432) }, + { SPH_C32(0x1e79b400), SPH_C32(0x15b70000), SPH_C32(0x67ab0000), + SPH_C32(0xc8e70000), SPH_C32(0xb3725786), SPH_C32(0x1e2daf74), + SPH_C32(0xb68d2f46), SPH_C32(0xb0a75c1e), SPH_C32(0x52373000), + SPH_C32(0xb18b0000), SPH_C32(0xbc7a0000), SPH_C32(0x4bbc0000), + SPH_C32(0xa4f3442e), SPH_C32(0xf45616eb), SPH_C32(0x6623a94f), + SPH_C32(0x5ea22f27) }, + { SPH_C32(0xf172b670), SPH_C32(0x2f4a0000), SPH_C32(0x3a050000), + SPH_C32(0xa1ae0000), SPH_C32(0x287d6b80), SPH_C32(0x5a281a8d), + SPH_C32(0xd0992517), SPH_C32(0x22e80114), SPH_C32(0x9b5c3030), + SPH_C32(0x56ae0000), SPH_C32(0x93fe0000), SPH_C32(0x6df30000), + SPH_C32(0xac9a1fd7), SPH_C32(0x99aae7dc), SPH_C32(0x36bcc0cb), + SPH_C32(0xc0cb804f) }, + { SPH_C32(0xd712b430), SPH_C32(0xf2920000), SPH_C32(0x482f0000), + SPH_C32(0xeea80000), SPH_C32(0xbb1b0c7f), SPH_C32(0x73d15e43), + SPH_C32(0xe61246c2), SPH_C32(0x2ecef376), SPH_C32(0x74573240), + SPH_C32(0x6c530000), SPH_C32(0xce500000), SPH_C32(0x04ba0000), + SPH_C32(0x379523d1), SPH_C32(0xddaf5225), SPH_C32(0x50a8ca9a), + SPH_C32(0x5284dd45) }, + { SPH_C32(0x3819b640), SPH_C32(0xc86f0000), SPH_C32(0x15810000), + SPH_C32(0x87e10000), SPH_C32(0x20143079), SPH_C32(0x37d4ebba), + SPH_C32(0x80064c93), SPH_C32(0xbc81ae7c), SPH_C32(0xbd3c3270), + SPH_C32(0x8b760000), SPH_C32(0xe1d40000), SPH_C32(0x22f50000), + SPH_C32(0x3ffc7828), SPH_C32(0xb053a312), SPH_C32(0x0037a31e), + SPH_C32(0xcced722d) }, + { SPH_C32(0x7d6cc000), SPH_C32(0x8e0a0000), SPH_C32(0x379d0000), + SPH_C32(0x63360000), SPH_C32(0xbd7c29ff), SPH_C32(0xc267f3a4), + SPH_C32(0x985003c4), SPH_C32(0xd816a946), SPH_C32(0xdad61400), + SPH_C32(0xb8b10000), SPH_C32(0x4f0c0000), SPH_C32(0x574e0000), + SPH_C32(0x33a83a07), SPH_C32(0xa50bfe67), SPH_C32(0x628cfdb5), + SPH_C32(0xc7e6c5cb) }, + { SPH_C32(0x9267c270), SPH_C32(0xb4f70000), SPH_C32(0x6a330000), + SPH_C32(0x0a7f0000), SPH_C32(0x267315f9), SPH_C32(0x8662465d), + SPH_C32(0xfe440995), SPH_C32(0x4a59f44c), SPH_C32(0x13bd1430), + SPH_C32(0x5f940000), SPH_C32(0x60880000), SPH_C32(0x71010000), + SPH_C32(0x3bc161fe), SPH_C32(0xc8f70f50), SPH_C32(0x32139431), + SPH_C32(0x598f6aa3) }, + { SPH_C32(0xb407c030), SPH_C32(0x692f0000), SPH_C32(0x18190000), + SPH_C32(0x45790000), SPH_C32(0xb5157206), SPH_C32(0xaf9b0293), + SPH_C32(0xc8cf6a40), SPH_C32(0x467f062e), SPH_C32(0xfcb61640), + SPH_C32(0x65690000), SPH_C32(0x3d260000), SPH_C32(0x18480000), + SPH_C32(0xa0ce5df8), SPH_C32(0x8cf2baa9), SPH_C32(0x54079e60), + SPH_C32(0xcbc037a9) }, + { SPH_C32(0x5b0cc240), SPH_C32(0x53d20000), SPH_C32(0x45b70000), + SPH_C32(0x2c300000), SPH_C32(0x2e1a4e00), SPH_C32(0xeb9eb76a), + SPH_C32(0xaedb6011), SPH_C32(0xd4305b24), SPH_C32(0x35dd1670), + SPH_C32(0x824c0000), SPH_C32(0x12a20000), SPH_C32(0x3e070000), + SPH_C32(0xa8a70601), SPH_C32(0xe10e4b9e), SPH_C32(0x0498f7e4), + SPH_C32(0x55a998c1) }, + { SPH_C32(0x6936fc00), SPH_C32(0x37e30000), SPH_C32(0x56ba0000), + SPH_C32(0x92570000), SPH_C32(0x731d1493), SPH_C32(0x722ecedc), + SPH_C32(0xdff964e4), SPH_C32(0x39988d83), SPH_C32(0xf9b10000), + SPH_C32(0x70080000), SPH_C32(0xbbcb0000), SPH_C32(0xac3b0000), + SPH_C32(0x40651e62), SPH_C32(0x5dad5b2e), SPH_C32(0x6048f78a), + SPH_C32(0x1bc223d4) }, + { SPH_C32(0x863dfe70), SPH_C32(0x0d1e0000), SPH_C32(0x0b140000), + SPH_C32(0xfb1e0000), SPH_C32(0xe8122895), SPH_C32(0x362b7b25), + SPH_C32(0xb9ed6eb5), SPH_C32(0xabd7d089), SPH_C32(0x30da0030), + SPH_C32(0x972d0000), SPH_C32(0x944f0000), SPH_C32(0x8a740000), + SPH_C32(0x480c459b), SPH_C32(0x3051aa19), SPH_C32(0x30d79e0e), + SPH_C32(0x85ab8cbc) }, + { SPH_C32(0xa05dfc30), SPH_C32(0xd0c60000), SPH_C32(0x793e0000), + SPH_C32(0xb4180000), SPH_C32(0x7b744f6a), SPH_C32(0x1fd23feb), + SPH_C32(0x8f660d60), SPH_C32(0xa7f122eb), SPH_C32(0xdfd10240), + SPH_C32(0xadd00000), SPH_C32(0xc9e10000), SPH_C32(0xe33d0000), + SPH_C32(0xd303799d), SPH_C32(0x74541fe0), SPH_C32(0x56c3945f), + SPH_C32(0x17e4d1b6) }, + { SPH_C32(0x4f56fe40), SPH_C32(0xea3b0000), SPH_C32(0x24900000), + SPH_C32(0xdd510000), SPH_C32(0xe07b736c), SPH_C32(0x5bd78a12), + SPH_C32(0xe9720731), SPH_C32(0x35be7fe1), SPH_C32(0x16ba0270), + SPH_C32(0x4af50000), SPH_C32(0xe6650000), SPH_C32(0xc5720000), + SPH_C32(0xdb6a2264), SPH_C32(0x19a8eed7), SPH_C32(0x065cfddb), + SPH_C32(0x898d7ede) }, + { SPH_C32(0x5e0bd400), SPH_C32(0x46b30000), SPH_C32(0xc35a0000), + SPH_C32(0x98430000), SPH_C32(0xceb10d9a), SPH_C32(0x3ac156ed), + SPH_C32(0x9a9409fb), SPH_C32(0x04324f59), SPH_C32(0xedeb3c00), + SPH_C32(0xc9e10000), SPH_C32(0xdaec0000), SPH_C32(0x5d5a0000), + SPH_C32(0x8e04230e), SPH_C32(0xede46656), SPH_C32(0x27e190aa), + SPH_C32(0xfa4c0711) }, + { SPH_C32(0xb100d670), SPH_C32(0x7c4e0000), SPH_C32(0x9ef40000), + SPH_C32(0xf10a0000), SPH_C32(0x55be319c), SPH_C32(0x7ec4e314), + SPH_C32(0xfc8003aa), SPH_C32(0x967d1253), SPH_C32(0x24803c30), + SPH_C32(0x2ec40000), SPH_C32(0xf5680000), SPH_C32(0x7b150000), + SPH_C32(0x866d78f7), SPH_C32(0x80189761), SPH_C32(0x777ef92e), + SPH_C32(0x6425a879) }, + { SPH_C32(0x9760d430), SPH_C32(0xa1960000), SPH_C32(0xecde0000), + SPH_C32(0xbe0c0000), SPH_C32(0xc6d85663), SPH_C32(0x573da7da), + SPH_C32(0xca0b607f), SPH_C32(0x9a5be031), SPH_C32(0xcb8b3e40), + SPH_C32(0x14390000), SPH_C32(0xa8c60000), SPH_C32(0x125c0000), + SPH_C32(0x1d6244f1), SPH_C32(0xc41d2298), SPH_C32(0x116af37f), + SPH_C32(0xf66af573) }, + { SPH_C32(0x786bd640), SPH_C32(0x9b6b0000), SPH_C32(0xb1700000), + SPH_C32(0xd7450000), SPH_C32(0x5dd76a65), SPH_C32(0x13381223), + SPH_C32(0xac1f6a2e), SPH_C32(0x0814bd3b), SPH_C32(0x02e03e70), + SPH_C32(0xf31c0000), SPH_C32(0x87420000), SPH_C32(0x34130000), + SPH_C32(0x150b1f08), SPH_C32(0xa9e1d3af), SPH_C32(0x41f59afb), + SPH_C32(0x68035a1b) }, + { SPH_C32(0x4a51e800), SPH_C32(0xff5a0000), SPH_C32(0xa27d0000), + SPH_C32(0x69220000), SPH_C32(0x00d030f6), SPH_C32(0x8a886b95), + SPH_C32(0xdd3d6edb), SPH_C32(0xe5bc6b9c), SPH_C32(0xce8c2800), + SPH_C32(0x01580000), SPH_C32(0x2e2b0000), SPH_C32(0xa62f0000), + SPH_C32(0xfdc9076b), SPH_C32(0x1542c31f), SPH_C32(0x25259a95), + SPH_C32(0x2668e10e) }, + { SPH_C32(0xa55aea70), SPH_C32(0xc5a70000), SPH_C32(0xffd30000), + SPH_C32(0x006b0000), SPH_C32(0x9bdf0cf0), SPH_C32(0xce8dde6c), + SPH_C32(0xbb29648a), SPH_C32(0x77f33696), SPH_C32(0x07e72830), + SPH_C32(0xe67d0000), SPH_C32(0x01af0000), SPH_C32(0x80600000), + SPH_C32(0xf5a05c92), SPH_C32(0x78be3228), SPH_C32(0x75baf311), + SPH_C32(0xb8014e66) }, + { SPH_C32(0x833ae830), SPH_C32(0x187f0000), SPH_C32(0x8df90000), + SPH_C32(0x4f6d0000), SPH_C32(0x08b96b0f), SPH_C32(0xe7749aa2), + SPH_C32(0x8da2075f), SPH_C32(0x7bd5c4f4), SPH_C32(0xe8ec2a40), + SPH_C32(0xdc800000), SPH_C32(0x5c010000), SPH_C32(0xe9290000), + SPH_C32(0x6eaf6094), SPH_C32(0x3cbb87d1), SPH_C32(0x13aef940), + SPH_C32(0x2a4e136c) }, + { SPH_C32(0x6c31ea40), SPH_C32(0x22820000), SPH_C32(0xd0570000), + SPH_C32(0x26240000), SPH_C32(0x93b65709), SPH_C32(0xa3712f5b), + SPH_C32(0xebb60d0e), SPH_C32(0xe99a99fe), SPH_C32(0x21872a70), + SPH_C32(0x3ba50000), SPH_C32(0x73850000), SPH_C32(0xcf660000), + SPH_C32(0x66c63b6d), SPH_C32(0x514776e6), SPH_C32(0x433190c4), + SPH_C32(0xb427bc04) }, + { SPH_C32(0xb5ff8400), SPH_C32(0xd4340000), SPH_C32(0x601a0000), + SPH_C32(0x2f600000), SPH_C32(0x57e40dca), SPH_C32(0xb7d6e2b1), + SPH_C32(0xb0e67183), SPH_C32(0xf5c750ed), SPH_C32(0x8efe4800), + SPH_C32(0x525c0000), SPH_C32(0x8ada0000), SPH_C32(0xf68b0000), + SPH_C32(0x800a5d77), SPH_C32(0x31ae3a86), SPH_C32(0x093cbc28), + SPH_C32(0x92fdf249) }, + { SPH_C32(0x5af48670), SPH_C32(0xeec90000), SPH_C32(0x3db40000), + SPH_C32(0x46290000), SPH_C32(0xcceb31cc), SPH_C32(0xf3d35748), + SPH_C32(0xd6f27bd2), SPH_C32(0x67880de7), SPH_C32(0x47954830), + SPH_C32(0xb5790000), SPH_C32(0xa55e0000), SPH_C32(0xd0c40000), + SPH_C32(0x8863068e), SPH_C32(0x5c52cbb1), SPH_C32(0x59a3d5ac), + SPH_C32(0x0c945d21) }, + { SPH_C32(0x7c948430), SPH_C32(0x33110000), SPH_C32(0x4f9e0000), + SPH_C32(0x092f0000), SPH_C32(0x5f8d5633), SPH_C32(0xda2a1386), + SPH_C32(0xe0791807), SPH_C32(0x6baeff85), SPH_C32(0xa89e4a40), + SPH_C32(0x8f840000), SPH_C32(0xf8f00000), SPH_C32(0xb98d0000), + SPH_C32(0x136c3a88), SPH_C32(0x18577e48), SPH_C32(0x3fb7dffd), + SPH_C32(0x9edb002b) }, + { SPH_C32(0x939f8640), SPH_C32(0x09ec0000), SPH_C32(0x12300000), + SPH_C32(0x60660000), SPH_C32(0xc4826a35), SPH_C32(0x9e2fa67f), + SPH_C32(0x866d1256), SPH_C32(0xf9e1a28f), SPH_C32(0x61f54a70), + SPH_C32(0x68a10000), SPH_C32(0xd7740000), SPH_C32(0x9fc20000), + SPH_C32(0x1b056171), SPH_C32(0x75ab8f7f), SPH_C32(0x6f28b679), + SPH_C32(0x00b2af43) }, + { SPH_C32(0xa1a5b800), SPH_C32(0x6ddd0000), SPH_C32(0x013d0000), + SPH_C32(0xde010000), SPH_C32(0x998530a6), SPH_C32(0x079fdfc9), + SPH_C32(0xf74f16a3), SPH_C32(0x14497428), SPH_C32(0xad995c00), + SPH_C32(0x9ae50000), SPH_C32(0x7e1d0000), SPH_C32(0x0dfe0000), + SPH_C32(0xf3c77912), SPH_C32(0xc9089fcf), SPH_C32(0x0bf8b617), + SPH_C32(0x4ed91456) }, + { SPH_C32(0x4eaeba70), SPH_C32(0x57200000), SPH_C32(0x5c930000), + SPH_C32(0xb7480000), SPH_C32(0x028a0ca0), SPH_C32(0x439a6a30), + SPH_C32(0x915b1cf2), SPH_C32(0x86062922), SPH_C32(0x64f25c30), + SPH_C32(0x7dc00000), SPH_C32(0x51990000), SPH_C32(0x2bb10000), + SPH_C32(0xfbae22eb), SPH_C32(0xa4f46ef8), SPH_C32(0x5b67df93), + SPH_C32(0xd0b0bb3e) }, + { SPH_C32(0x68ceb830), SPH_C32(0x8af80000), SPH_C32(0x2eb90000), + SPH_C32(0xf84e0000), SPH_C32(0x91ec6b5f), SPH_C32(0x6a632efe), + SPH_C32(0xa7d07f27), SPH_C32(0x8a20db40), SPH_C32(0x8bf95e40), + SPH_C32(0x473d0000), SPH_C32(0x0c370000), SPH_C32(0x42f80000), + SPH_C32(0x60a11eed), SPH_C32(0xe0f1db01), SPH_C32(0x3d73d5c2), + SPH_C32(0x42ffe634) }, + { SPH_C32(0x87c5ba40), SPH_C32(0xb0050000), SPH_C32(0x73170000), + SPH_C32(0x91070000), SPH_C32(0x0ae35759), SPH_C32(0x2e669b07), + SPH_C32(0xc1c47576), SPH_C32(0x186f864a), SPH_C32(0x42925e70), + SPH_C32(0xa0180000), SPH_C32(0x23b30000), SPH_C32(0x64b70000), + SPH_C32(0x68c84514), SPH_C32(0x8d0d2a36), SPH_C32(0x6decbc46), + SPH_C32(0xdc96495c) }, + { SPH_C32(0x96989000), SPH_C32(0x1c8d0000), SPH_C32(0x94dd0000), + SPH_C32(0xd4150000), SPH_C32(0x242929af), SPH_C32(0x4f7047f8), + SPH_C32(0xb2227bbc), SPH_C32(0x29e3b6f2), SPH_C32(0xb9c36000), + SPH_C32(0x230c0000), SPH_C32(0x1f3a0000), SPH_C32(0xfc9f0000), + SPH_C32(0x3da6447e), SPH_C32(0x7941a2b7), SPH_C32(0x4c51d137), + SPH_C32(0xaf573093) }, + { SPH_C32(0x79939270), SPH_C32(0x26700000), SPH_C32(0xc9730000), + SPH_C32(0xbd5c0000), SPH_C32(0xbf2615a9), SPH_C32(0x0b75f201), + SPH_C32(0xd43671ed), SPH_C32(0xbbacebf8), SPH_C32(0x70a86030), + SPH_C32(0xc4290000), SPH_C32(0x30be0000), SPH_C32(0xdad00000), + SPH_C32(0x35cf1f87), SPH_C32(0x14bd5380), SPH_C32(0x1cceb8b3), + SPH_C32(0x313e9ffb) }, + { SPH_C32(0x5ff39030), SPH_C32(0xfba80000), SPH_C32(0xbb590000), + SPH_C32(0xf25a0000), SPH_C32(0x2c407256), SPH_C32(0x228cb6cf), + SPH_C32(0xe2bd1238), SPH_C32(0xb78a199a), SPH_C32(0x9fa36240), + SPH_C32(0xfed40000), SPH_C32(0x6d100000), SPH_C32(0xb3990000), + SPH_C32(0xaec02381), SPH_C32(0x50b8e679), SPH_C32(0x7adab2e2), + SPH_C32(0xa371c2f1) }, + { SPH_C32(0xb0f89240), SPH_C32(0xc1550000), SPH_C32(0xe6f70000), + SPH_C32(0x9b130000), SPH_C32(0xb74f4e50), SPH_C32(0x66890336), + SPH_C32(0x84a91869), SPH_C32(0x25c54490), SPH_C32(0x56c86270), + SPH_C32(0x19f10000), SPH_C32(0x42940000), SPH_C32(0x95d60000), + SPH_C32(0xa6a97878), SPH_C32(0x3d44174e), SPH_C32(0x2a45db66), + SPH_C32(0x3d186d99) }, + { SPH_C32(0x82c2ac00), SPH_C32(0xa5640000), SPH_C32(0xf5fa0000), + SPH_C32(0x25740000), SPH_C32(0xea4814c3), SPH_C32(0xff397a80), + SPH_C32(0xf58b1c9c), SPH_C32(0xc86d9237), SPH_C32(0x9aa47400), + SPH_C32(0xebb50000), SPH_C32(0xebfd0000), SPH_C32(0x07ea0000), + SPH_C32(0x4e6b601b), SPH_C32(0x81e707fe), SPH_C32(0x4e95db08), + SPH_C32(0x7373d68c) }, + { SPH_C32(0x6dc9ae70), SPH_C32(0x9f990000), SPH_C32(0xa8540000), + SPH_C32(0x4c3d0000), SPH_C32(0x714728c5), SPH_C32(0xbb3ccf79), + SPH_C32(0x939f16cd), SPH_C32(0x5a22cf3d), SPH_C32(0x53cf7430), + SPH_C32(0x0c900000), SPH_C32(0xc4790000), SPH_C32(0x21a50000), + SPH_C32(0x46023be2), SPH_C32(0xec1bf6c9), SPH_C32(0x1e0ab28c), + SPH_C32(0xed1a79e4) }, + { SPH_C32(0x4ba9ac30), SPH_C32(0x42410000), SPH_C32(0xda7e0000), + SPH_C32(0x033b0000), SPH_C32(0xe2214f3a), SPH_C32(0x92c58bb7), + SPH_C32(0xa5147518), SPH_C32(0x56043d5f), SPH_C32(0xbcc47640), + SPH_C32(0x366d0000), SPH_C32(0x99d70000), SPH_C32(0x48ec0000), + SPH_C32(0xdd0d07e4), SPH_C32(0xa81e4330), SPH_C32(0x781eb8dd), + SPH_C32(0x7f5524ee) }, + { SPH_C32(0xa4a2ae40), SPH_C32(0x78bc0000), SPH_C32(0x87d00000), + SPH_C32(0x6a720000), SPH_C32(0x792e733c), SPH_C32(0xd6c03e4e), + SPH_C32(0xc3007f49), SPH_C32(0xc44b6055), SPH_C32(0x75af7670), + SPH_C32(0xd1480000), SPH_C32(0xb6530000), SPH_C32(0x6ea30000), + SPH_C32(0xd5645c1d), SPH_C32(0xc5e2b207), SPH_C32(0x2881d159), + SPH_C32(0xe13c8b86) }, + { SPH_C32(0xe1d7d800), SPH_C32(0x3ed90000), SPH_C32(0xa5cc0000), + SPH_C32(0x8ea50000), SPH_C32(0xe4466aba), SPH_C32(0x23732650), + SPH_C32(0xdb56301e), SPH_C32(0xa0dc676f), SPH_C32(0x12455000), + SPH_C32(0xe28f0000), SPH_C32(0x188b0000), SPH_C32(0x1b180000), + SPH_C32(0xd9301e32), SPH_C32(0xd0baef72), SPH_C32(0x4a3a8ff2), + SPH_C32(0xea373c60) }, + { SPH_C32(0x0edcda70), SPH_C32(0x04240000), SPH_C32(0xf8620000), + SPH_C32(0xe7ec0000), SPH_C32(0x7f4956bc), SPH_C32(0x677693a9), + SPH_C32(0xbd423a4f), SPH_C32(0x32933a65), SPH_C32(0xdb2e5030), + SPH_C32(0x05aa0000), SPH_C32(0x370f0000), SPH_C32(0x3d570000), + SPH_C32(0xd15945cb), SPH_C32(0xbd461e45), SPH_C32(0x1aa5e676), + SPH_C32(0x745e9308) }, + { SPH_C32(0x28bcd830), SPH_C32(0xd9fc0000), SPH_C32(0x8a480000), + SPH_C32(0xa8ea0000), SPH_C32(0xec2f3143), SPH_C32(0x4e8fd767), + SPH_C32(0x8bc9599a), SPH_C32(0x3eb5c807), SPH_C32(0x34255240), + SPH_C32(0x3f570000), SPH_C32(0x6aa10000), SPH_C32(0x541e0000), + SPH_C32(0x4a5679cd), SPH_C32(0xf943abbc), SPH_C32(0x7cb1ec27), + SPH_C32(0xe611ce02) }, + { SPH_C32(0xc7b7da40), SPH_C32(0xe3010000), SPH_C32(0xd7e60000), + SPH_C32(0xc1a30000), SPH_C32(0x77200d45), SPH_C32(0x0a8a629e), + SPH_C32(0xeddd53cb), SPH_C32(0xacfa950d), SPH_C32(0xfd4e5270), + SPH_C32(0xd8720000), SPH_C32(0x45250000), SPH_C32(0x72510000), + SPH_C32(0x423f2234), SPH_C32(0x94bf5a8b), SPH_C32(0x2c2e85a3), + SPH_C32(0x7878616a) }, + { SPH_C32(0xf58de400), SPH_C32(0x87300000), SPH_C32(0xc4eb0000), + SPH_C32(0x7fc40000), SPH_C32(0x2a2757d6), SPH_C32(0x933a1b28), + SPH_C32(0x9cff573e), SPH_C32(0x415243aa), SPH_C32(0x31224400), + SPH_C32(0x2a360000), SPH_C32(0xec4c0000), SPH_C32(0xe06d0000), + SPH_C32(0xaafd3a57), SPH_C32(0x281c4a3b), SPH_C32(0x48fe85cd), + SPH_C32(0x3613da7f) }, + { SPH_C32(0x1a86e670), SPH_C32(0xbdcd0000), SPH_C32(0x99450000), + SPH_C32(0x168d0000), SPH_C32(0xb1286bd0), SPH_C32(0xd73faed1), + SPH_C32(0xfaeb5d6f), SPH_C32(0xd31d1ea0), SPH_C32(0xf8494430), + SPH_C32(0xcd130000), SPH_C32(0xc3c80000), SPH_C32(0xc6220000), + SPH_C32(0xa29461ae), SPH_C32(0x45e0bb0c), SPH_C32(0x1861ec49), + SPH_C32(0xa87a7517) }, + { SPH_C32(0x3ce6e430), SPH_C32(0x60150000), SPH_C32(0xeb6f0000), + SPH_C32(0x598b0000), SPH_C32(0x224e0c2f), SPH_C32(0xfec6ea1f), + SPH_C32(0xcc603eba), SPH_C32(0xdf3becc2), SPH_C32(0x17424640), + SPH_C32(0xf7ee0000), SPH_C32(0x9e660000), SPH_C32(0xaf6b0000), + SPH_C32(0x399b5da8), SPH_C32(0x01e50ef5), SPH_C32(0x7e75e618), + SPH_C32(0x3a35281d) }, + { SPH_C32(0xd3ede640), SPH_C32(0x5ae80000), SPH_C32(0xb6c10000), + SPH_C32(0x30c20000), SPH_C32(0xb9413029), SPH_C32(0xbac35fe6), + SPH_C32(0xaa7434eb), SPH_C32(0x4d74b1c8), SPH_C32(0xde294670), + SPH_C32(0x10cb0000), SPH_C32(0xb1e20000), SPH_C32(0x89240000), + SPH_C32(0x31f20651), SPH_C32(0x6c19ffc2), SPH_C32(0x2eea8f9c), + SPH_C32(0xa45c8775) }, + { SPH_C32(0xc2b0cc00), SPH_C32(0xf6600000), SPH_C32(0x510b0000), + SPH_C32(0x75d00000), SPH_C32(0x978b4edf), SPH_C32(0xdbd58319), + SPH_C32(0xd9923a21), SPH_C32(0x7cf88170), SPH_C32(0x25787800), + SPH_C32(0x93df0000), SPH_C32(0x8d6b0000), SPH_C32(0x110c0000), + SPH_C32(0x649c073b), SPH_C32(0x98557743), SPH_C32(0x0f57e2ed), + SPH_C32(0xd79dfeba) }, + { SPH_C32(0x2dbbce70), SPH_C32(0xcc9d0000), SPH_C32(0x0ca50000), + SPH_C32(0x1c990000), SPH_C32(0x0c8472d9), SPH_C32(0x9fd036e0), + SPH_C32(0xbf863070), SPH_C32(0xeeb7dc7a), SPH_C32(0xec137830), + SPH_C32(0x74fa0000), SPH_C32(0xa2ef0000), SPH_C32(0x37430000), + SPH_C32(0x6cf55cc2), SPH_C32(0xf5a98674), SPH_C32(0x5fc88b69), + SPH_C32(0x49f451d2) }, + { SPH_C32(0x0bdbcc30), SPH_C32(0x11450000), SPH_C32(0x7e8f0000), + SPH_C32(0x539f0000), SPH_C32(0x9fe21526), SPH_C32(0xb629722e), + SPH_C32(0x890d53a5), SPH_C32(0xe2912e18), SPH_C32(0x03187a40), + SPH_C32(0x4e070000), SPH_C32(0xff410000), SPH_C32(0x5e0a0000), + SPH_C32(0xf7fa60c4), SPH_C32(0xb1ac338d), SPH_C32(0x39dc8138), + SPH_C32(0xdbbb0cd8) }, + { SPH_C32(0xe4d0ce40), SPH_C32(0x2bb80000), SPH_C32(0x23210000), + SPH_C32(0x3ad60000), SPH_C32(0x04ed2920), SPH_C32(0xf22cc7d7), + SPH_C32(0xef1959f4), SPH_C32(0x70de7312), SPH_C32(0xca737a70), + SPH_C32(0xa9220000), SPH_C32(0xd0c50000), SPH_C32(0x78450000), + SPH_C32(0xff933b3d), SPH_C32(0xdc50c2ba), SPH_C32(0x6943e8bc), + SPH_C32(0x45d2a3b0) }, + { SPH_C32(0xd6eaf000), SPH_C32(0x4f890000), SPH_C32(0x302c0000), + SPH_C32(0x84b10000), SPH_C32(0x59ea73b3), SPH_C32(0x6b9cbe61), + SPH_C32(0x9e3b5d01), SPH_C32(0x9d76a5b5), SPH_C32(0x061f6c00), + SPH_C32(0x5b660000), SPH_C32(0x79ac0000), SPH_C32(0xea790000), + SPH_C32(0x1751235e), SPH_C32(0x60f3d20a), SPH_C32(0x0d93e8d2), + SPH_C32(0x0bb918a5) }, + { SPH_C32(0x39e1f270), SPH_C32(0x75740000), SPH_C32(0x6d820000), + SPH_C32(0xedf80000), SPH_C32(0xc2e54fb5), SPH_C32(0x2f990b98), + SPH_C32(0xf82f5750), SPH_C32(0x0f39f8bf), SPH_C32(0xcf746c30), + SPH_C32(0xbc430000), SPH_C32(0x56280000), SPH_C32(0xcc360000), + SPH_C32(0x1f3878a7), SPH_C32(0x0d0f233d), SPH_C32(0x5d0c8156), + SPH_C32(0x95d0b7cd) }, + { SPH_C32(0x1f81f030), SPH_C32(0xa8ac0000), SPH_C32(0x1fa80000), + SPH_C32(0xa2fe0000), SPH_C32(0x5183284a), SPH_C32(0x06604f56), + SPH_C32(0xcea43485), SPH_C32(0x031f0add), SPH_C32(0x207f6e40), + SPH_C32(0x86be0000), SPH_C32(0x0b860000), SPH_C32(0xa57f0000), + SPH_C32(0x843744a1), SPH_C32(0x490a96c4), SPH_C32(0x3b188b07), + SPH_C32(0x079feac7) }, + { SPH_C32(0xf08af240), SPH_C32(0x92510000), SPH_C32(0x42060000), + SPH_C32(0xcbb70000), SPH_C32(0xca8c144c), SPH_C32(0x4265faaf), + SPH_C32(0xa8b03ed4), SPH_C32(0x915057d7), SPH_C32(0xe9146e70), + SPH_C32(0x619b0000), SPH_C32(0x24020000), SPH_C32(0x83300000), + SPH_C32(0x8c5e1f58), SPH_C32(0x24f667f3), SPH_C32(0x6b87e283), + SPH_C32(0x99f645af) }, + { SPH_C32(0x466d0c00), SPH_C32(0x08620000), SPH_C32(0xdd5d0000), + SPH_C32(0xbadd0000), SPH_C32(0x6a927942), SPH_C32(0x441f2b93), + SPH_C32(0x218ace6f), SPH_C32(0xbf2c0be2), SPH_C32(0x6f299000), + SPH_C32(0x6c850000), SPH_C32(0x2f160000), SPH_C32(0x782e0000), + SPH_C32(0x644c37cd), SPH_C32(0x12dd1cd6), SPH_C32(0xd26a8c36), + SPH_C32(0x32219526) }, + { SPH_C32(0xa9660e70), SPH_C32(0x329f0000), SPH_C32(0x80f30000), + SPH_C32(0xd3940000), SPH_C32(0xf19d4544), SPH_C32(0x001a9e6a), + SPH_C32(0x479ec43e), SPH_C32(0x2d6356e8), SPH_C32(0xa6429030), + SPH_C32(0x8ba00000), SPH_C32(0x00920000), SPH_C32(0x5e610000), + SPH_C32(0x6c256c34), SPH_C32(0x7f21ede1), SPH_C32(0x82f5e5b2), + SPH_C32(0xac483a4e) }, + { SPH_C32(0x8f060c30), SPH_C32(0xef470000), SPH_C32(0xf2d90000), + SPH_C32(0x9c920000), SPH_C32(0x62fb22bb), SPH_C32(0x29e3daa4), + SPH_C32(0x7115a7eb), SPH_C32(0x2145a48a), SPH_C32(0x49499240), + SPH_C32(0xb15d0000), SPH_C32(0x5d3c0000), SPH_C32(0x37280000), + SPH_C32(0xf72a5032), SPH_C32(0x3b245818), SPH_C32(0xe4e1efe3), + SPH_C32(0x3e076744) }, + { SPH_C32(0x600d0e40), SPH_C32(0xd5ba0000), SPH_C32(0xaf770000), + SPH_C32(0xf5db0000), SPH_C32(0xf9f41ebd), SPH_C32(0x6de66f5d), + SPH_C32(0x1701adba), SPH_C32(0xb30af980), SPH_C32(0x80229270), + SPH_C32(0x56780000), SPH_C32(0x72b80000), SPH_C32(0x11670000), + SPH_C32(0xff430bcb), SPH_C32(0x56d8a92f), SPH_C32(0xb47e8667), + SPH_C32(0xa06ec82c) }, + { SPH_C32(0x52373000), SPH_C32(0xb18b0000), SPH_C32(0xbc7a0000), + SPH_C32(0x4bbc0000), SPH_C32(0xa4f3442e), SPH_C32(0xf45616eb), + SPH_C32(0x6623a94f), SPH_C32(0x5ea22f27), SPH_C32(0x4c4e8400), + SPH_C32(0xa43c0000), SPH_C32(0xdbd10000), SPH_C32(0x835b0000), + SPH_C32(0x178113a8), SPH_C32(0xea7bb99f), SPH_C32(0xd0ae8609), + SPH_C32(0xee057339) }, + { SPH_C32(0xbd3c3270), SPH_C32(0x8b760000), SPH_C32(0xe1d40000), + SPH_C32(0x22f50000), SPH_C32(0x3ffc7828), SPH_C32(0xb053a312), + SPH_C32(0x0037a31e), SPH_C32(0xcced722d), SPH_C32(0x85258430), + SPH_C32(0x43190000), SPH_C32(0xf4550000), SPH_C32(0xa5140000), + SPH_C32(0x1fe84851), SPH_C32(0x878748a8), SPH_C32(0x8031ef8d), + SPH_C32(0x706cdc51) }, + { SPH_C32(0x9b5c3030), SPH_C32(0x56ae0000), SPH_C32(0x93fe0000), + SPH_C32(0x6df30000), SPH_C32(0xac9a1fd7), SPH_C32(0x99aae7dc), + SPH_C32(0x36bcc0cb), SPH_C32(0xc0cb804f), SPH_C32(0x6a2e8640), + SPH_C32(0x79e40000), SPH_C32(0xa9fb0000), SPH_C32(0xcc5d0000), + SPH_C32(0x84e77457), SPH_C32(0xc382fd51), SPH_C32(0xe625e5dc), + SPH_C32(0xe223815b) }, + { SPH_C32(0x74573240), SPH_C32(0x6c530000), SPH_C32(0xce500000), + SPH_C32(0x04ba0000), SPH_C32(0x379523d1), SPH_C32(0xddaf5225), + SPH_C32(0x50a8ca9a), SPH_C32(0x5284dd45), SPH_C32(0xa3458670), + SPH_C32(0x9ec10000), SPH_C32(0x867f0000), SPH_C32(0xea120000), + SPH_C32(0x8c8e2fae), SPH_C32(0xae7e0c66), SPH_C32(0xb6ba8c58), + SPH_C32(0x7c4a2e33) }, + { SPH_C32(0x650a1800), SPH_C32(0xc0db0000), SPH_C32(0x299a0000), + SPH_C32(0x41a80000), SPH_C32(0x195f5d27), SPH_C32(0xbcb98eda), + SPH_C32(0x234ec450), SPH_C32(0x6308edfd), SPH_C32(0x5814b800), + SPH_C32(0x1dd50000), SPH_C32(0xbaf60000), SPH_C32(0x723a0000), + SPH_C32(0xd9e02ec4), SPH_C32(0x5a3284e7), SPH_C32(0x9707e129), + SPH_C32(0x0f8b57fc) }, + { SPH_C32(0x8a011a70), SPH_C32(0xfa260000), SPH_C32(0x74340000), + SPH_C32(0x28e10000), SPH_C32(0x82506121), SPH_C32(0xf8bc3b23), + SPH_C32(0x455ace01), SPH_C32(0xf147b0f7), SPH_C32(0x917fb830), + SPH_C32(0xfaf00000), SPH_C32(0x95720000), SPH_C32(0x54750000), + SPH_C32(0xd189753d), SPH_C32(0x37ce75d0), SPH_C32(0xc79888ad), + SPH_C32(0x91e2f894) }, + { SPH_C32(0xac611830), SPH_C32(0x27fe0000), SPH_C32(0x061e0000), + SPH_C32(0x67e70000), SPH_C32(0x113606de), SPH_C32(0xd1457fed), + SPH_C32(0x73d1add4), SPH_C32(0xfd614295), SPH_C32(0x7e74ba40), + SPH_C32(0xc00d0000), SPH_C32(0xc8dc0000), SPH_C32(0x3d3c0000), + SPH_C32(0x4a86493b), SPH_C32(0x73cbc029), SPH_C32(0xa18c82fc), + SPH_C32(0x03ada59e) }, + { SPH_C32(0x436a1a40), SPH_C32(0x1d030000), SPH_C32(0x5bb00000), + SPH_C32(0x0eae0000), SPH_C32(0x8a393ad8), SPH_C32(0x9540ca14), + SPH_C32(0x15c5a785), SPH_C32(0x6f2e1f9f), SPH_C32(0xb71fba70), + SPH_C32(0x27280000), SPH_C32(0xe7580000), SPH_C32(0x1b730000), + SPH_C32(0x42ef12c2), SPH_C32(0x1e37311e), SPH_C32(0xf113eb78), + SPH_C32(0x9dc40af6) }, + { SPH_C32(0x71502400), SPH_C32(0x79320000), SPH_C32(0x48bd0000), + SPH_C32(0xb0c90000), SPH_C32(0xd73e604b), SPH_C32(0x0cf0b3a2), + SPH_C32(0x64e7a370), SPH_C32(0x8286c938), SPH_C32(0x7b73ac00), + SPH_C32(0xd56c0000), SPH_C32(0x4e310000), SPH_C32(0x894f0000), + SPH_C32(0xaa2d0aa1), SPH_C32(0xa29421ae), SPH_C32(0x95c3eb16), + SPH_C32(0xd3afb1e3) }, + { SPH_C32(0x9e5b2670), SPH_C32(0x43cf0000), SPH_C32(0x15130000), + SPH_C32(0xd9800000), SPH_C32(0x4c315c4d), SPH_C32(0x48f5065b), + SPH_C32(0x02f3a921), SPH_C32(0x10c99432), SPH_C32(0xb218ac30), + SPH_C32(0x32490000), SPH_C32(0x61b50000), SPH_C32(0xaf000000), + SPH_C32(0xa2445158), SPH_C32(0xcf68d099), SPH_C32(0xc55c8292), + SPH_C32(0x4dc61e8b) }, + { SPH_C32(0xb83b2430), SPH_C32(0x9e170000), SPH_C32(0x67390000), + SPH_C32(0x96860000), SPH_C32(0xdf573bb2), SPH_C32(0x610c4295), + SPH_C32(0x3478caf4), SPH_C32(0x1cef6650), SPH_C32(0x5d13ae40), + SPH_C32(0x08b40000), SPH_C32(0x3c1b0000), SPH_C32(0xc6490000), + SPH_C32(0x394b6d5e), SPH_C32(0x8b6d6560), SPH_C32(0xa34888c3), + SPH_C32(0xdf894381) }, + { SPH_C32(0x57302640), SPH_C32(0xa4ea0000), SPH_C32(0x3a970000), + SPH_C32(0xffcf0000), SPH_C32(0x445807b4), SPH_C32(0x2509f76c), + SPH_C32(0x526cc0a5), SPH_C32(0x8ea03b5a), SPH_C32(0x9478ae70), + SPH_C32(0xef910000), SPH_C32(0x139f0000), SPH_C32(0xe0060000), + SPH_C32(0x312236a7), SPH_C32(0xe6919457), SPH_C32(0xf3d7e147), + SPH_C32(0x41e0ece9) }, + { SPH_C32(0x12455000), SPH_C32(0xe28f0000), SPH_C32(0x188b0000), + SPH_C32(0x1b180000), SPH_C32(0xd9301e32), SPH_C32(0xd0baef72), + SPH_C32(0x4a3a8ff2), SPH_C32(0xea373c60), SPH_C32(0xf3928800), + SPH_C32(0xdc560000), SPH_C32(0xbd470000), SPH_C32(0x95bd0000), + SPH_C32(0x3d767488), SPH_C32(0xf3c9c922), SPH_C32(0x916cbfec), + SPH_C32(0x4aeb5b0f) }, + { SPH_C32(0xfd4e5270), SPH_C32(0xd8720000), SPH_C32(0x45250000), + SPH_C32(0x72510000), SPH_C32(0x423f2234), SPH_C32(0x94bf5a8b), + SPH_C32(0x2c2e85a3), SPH_C32(0x7878616a), SPH_C32(0x3af98830), + SPH_C32(0x3b730000), SPH_C32(0x92c30000), SPH_C32(0xb3f20000), + SPH_C32(0x351f2f71), SPH_C32(0x9e353815), SPH_C32(0xc1f3d668), + SPH_C32(0xd482f467) }, + { SPH_C32(0xdb2e5030), SPH_C32(0x05aa0000), SPH_C32(0x370f0000), + SPH_C32(0x3d570000), SPH_C32(0xd15945cb), SPH_C32(0xbd461e45), + SPH_C32(0x1aa5e676), SPH_C32(0x745e9308), SPH_C32(0xd5f28a40), + SPH_C32(0x018e0000), SPH_C32(0xcf6d0000), SPH_C32(0xdabb0000), + SPH_C32(0xae101377), SPH_C32(0xda308dec), SPH_C32(0xa7e7dc39), + SPH_C32(0x46cda96d) }, + { SPH_C32(0x34255240), SPH_C32(0x3f570000), SPH_C32(0x6aa10000), + SPH_C32(0x541e0000), SPH_C32(0x4a5679cd), SPH_C32(0xf943abbc), + SPH_C32(0x7cb1ec27), SPH_C32(0xe611ce02), SPH_C32(0x1c998a70), + SPH_C32(0xe6ab0000), SPH_C32(0xe0e90000), SPH_C32(0xfcf40000), + SPH_C32(0xa679488e), SPH_C32(0xb7cc7cdb), SPH_C32(0xf778b5bd), + SPH_C32(0xd8a40605) }, + { SPH_C32(0x061f6c00), SPH_C32(0x5b660000), SPH_C32(0x79ac0000), + SPH_C32(0xea790000), SPH_C32(0x1751235e), SPH_C32(0x60f3d20a), + SPH_C32(0x0d93e8d2), SPH_C32(0x0bb918a5), SPH_C32(0xd0f59c00), + SPH_C32(0x14ef0000), SPH_C32(0x49800000), SPH_C32(0x6ec80000), + SPH_C32(0x4ebb50ed), SPH_C32(0x0b6f6c6b), SPH_C32(0x93a8b5d3), + SPH_C32(0x96cfbd10) }, + { SPH_C32(0xe9146e70), SPH_C32(0x619b0000), SPH_C32(0x24020000), + SPH_C32(0x83300000), SPH_C32(0x8c5e1f58), SPH_C32(0x24f667f3), + SPH_C32(0x6b87e283), SPH_C32(0x99f645af), SPH_C32(0x199e9c30), + SPH_C32(0xf3ca0000), SPH_C32(0x66040000), SPH_C32(0x48870000), + SPH_C32(0x46d20b14), SPH_C32(0x66939d5c), SPH_C32(0xc337dc57), + SPH_C32(0x08a61278) }, + { SPH_C32(0xcf746c30), SPH_C32(0xbc430000), SPH_C32(0x56280000), + SPH_C32(0xcc360000), SPH_C32(0x1f3878a7), SPH_C32(0x0d0f233d), + SPH_C32(0x5d0c8156), SPH_C32(0x95d0b7cd), SPH_C32(0xf6959e40), + SPH_C32(0xc9370000), SPH_C32(0x3baa0000), SPH_C32(0x21ce0000), + SPH_C32(0xdddd3712), SPH_C32(0x229628a5), SPH_C32(0xa523d606), + SPH_C32(0x9ae94f72) }, + { SPH_C32(0x207f6e40), SPH_C32(0x86be0000), SPH_C32(0x0b860000), + SPH_C32(0xa57f0000), SPH_C32(0x843744a1), SPH_C32(0x490a96c4), + SPH_C32(0x3b188b07), SPH_C32(0x079feac7), SPH_C32(0x3ffe9e70), + SPH_C32(0x2e120000), SPH_C32(0x142e0000), SPH_C32(0x07810000), + SPH_C32(0xd5b46ceb), SPH_C32(0x4f6ad992), SPH_C32(0xf5bcbf82), + SPH_C32(0x0480e01a) }, + { SPH_C32(0x31224400), SPH_C32(0x2a360000), SPH_C32(0xec4c0000), + SPH_C32(0xe06d0000), SPH_C32(0xaafd3a57), SPH_C32(0x281c4a3b), + SPH_C32(0x48fe85cd), SPH_C32(0x3613da7f), SPH_C32(0xc4afa000), + SPH_C32(0xad060000), SPH_C32(0x28a70000), SPH_C32(0x9fa90000), + SPH_C32(0x80da6d81), SPH_C32(0xbb265113), SPH_C32(0xd401d2f3), + SPH_C32(0x774199d5) }, + { SPH_C32(0xde294670), SPH_C32(0x10cb0000), SPH_C32(0xb1e20000), + SPH_C32(0x89240000), SPH_C32(0x31f20651), SPH_C32(0x6c19ffc2), + SPH_C32(0x2eea8f9c), SPH_C32(0xa45c8775), SPH_C32(0x0dc4a030), + SPH_C32(0x4a230000), SPH_C32(0x07230000), SPH_C32(0xb9e60000), + SPH_C32(0x88b33678), SPH_C32(0xd6daa024), SPH_C32(0x849ebb77), + SPH_C32(0xe92836bd) }, + { SPH_C32(0xf8494430), SPH_C32(0xcd130000), SPH_C32(0xc3c80000), + SPH_C32(0xc6220000), SPH_C32(0xa29461ae), SPH_C32(0x45e0bb0c), + SPH_C32(0x1861ec49), SPH_C32(0xa87a7517), SPH_C32(0xe2cfa240), + SPH_C32(0x70de0000), SPH_C32(0x5a8d0000), SPH_C32(0xd0af0000), + SPH_C32(0x13bc0a7e), SPH_C32(0x92df15dd), SPH_C32(0xe28ab126), + SPH_C32(0x7b676bb7) }, + { SPH_C32(0x17424640), SPH_C32(0xf7ee0000), SPH_C32(0x9e660000), + SPH_C32(0xaf6b0000), SPH_C32(0x399b5da8), SPH_C32(0x01e50ef5), + SPH_C32(0x7e75e618), SPH_C32(0x3a35281d), SPH_C32(0x2ba4a270), + SPH_C32(0x97fb0000), SPH_C32(0x75090000), SPH_C32(0xf6e00000), + SPH_C32(0x1bd55187), SPH_C32(0xff23e4ea), SPH_C32(0xb215d8a2), + SPH_C32(0xe50ec4df) }, + { SPH_C32(0x25787800), SPH_C32(0x93df0000), SPH_C32(0x8d6b0000), + SPH_C32(0x110c0000), SPH_C32(0x649c073b), SPH_C32(0x98557743), + SPH_C32(0x0f57e2ed), SPH_C32(0xd79dfeba), SPH_C32(0xe7c8b400), + SPH_C32(0x65bf0000), SPH_C32(0xdc600000), SPH_C32(0x64dc0000), + SPH_C32(0xf31749e4), SPH_C32(0x4380f45a), SPH_C32(0xd6c5d8cc), + SPH_C32(0xab657fca) }, + { SPH_C32(0xca737a70), SPH_C32(0xa9220000), SPH_C32(0xd0c50000), + SPH_C32(0x78450000), SPH_C32(0xff933b3d), SPH_C32(0xdc50c2ba), + SPH_C32(0x6943e8bc), SPH_C32(0x45d2a3b0), SPH_C32(0x2ea3b430), + SPH_C32(0x829a0000), SPH_C32(0xf3e40000), SPH_C32(0x42930000), + SPH_C32(0xfb7e121d), SPH_C32(0x2e7c056d), SPH_C32(0x865ab148), + SPH_C32(0x350cd0a2) }, + { SPH_C32(0xec137830), SPH_C32(0x74fa0000), SPH_C32(0xa2ef0000), + SPH_C32(0x37430000), SPH_C32(0x6cf55cc2), SPH_C32(0xf5a98674), + SPH_C32(0x5fc88b69), SPH_C32(0x49f451d2), SPH_C32(0xc1a8b640), + SPH_C32(0xb8670000), SPH_C32(0xae4a0000), SPH_C32(0x2bda0000), + SPH_C32(0x60712e1b), SPH_C32(0x6a79b094), SPH_C32(0xe04ebb19), + SPH_C32(0xa7438da8) }, + { SPH_C32(0x03187a40), SPH_C32(0x4e070000), SPH_C32(0xff410000), + SPH_C32(0x5e0a0000), SPH_C32(0xf7fa60c4), SPH_C32(0xb1ac338d), + SPH_C32(0x39dc8138), SPH_C32(0xdbbb0cd8), SPH_C32(0x08c3b670), + SPH_C32(0x5f420000), SPH_C32(0x81ce0000), SPH_C32(0x0d950000), + SPH_C32(0x681875e2), SPH_C32(0x078541a3), SPH_C32(0xb0d1d29d), + SPH_C32(0x392a22c0) }, + { SPH_C32(0xdad61400), SPH_C32(0xb8b10000), SPH_C32(0x4f0c0000), + SPH_C32(0x574e0000), SPH_C32(0x33a83a07), SPH_C32(0xa50bfe67), + SPH_C32(0x628cfdb5), SPH_C32(0xc7e6c5cb), SPH_C32(0xa7bad400), + SPH_C32(0x36bb0000), SPH_C32(0x78910000), SPH_C32(0x34780000), + SPH_C32(0x8ed413f8), SPH_C32(0x676c0dc3), SPH_C32(0xfadcfe71), + SPH_C32(0x1ff06c8d) }, + { SPH_C32(0x35dd1670), SPH_C32(0x824c0000), SPH_C32(0x12a20000), + SPH_C32(0x3e070000), SPH_C32(0xa8a70601), SPH_C32(0xe10e4b9e), + SPH_C32(0x0498f7e4), SPH_C32(0x55a998c1), SPH_C32(0x6ed1d430), + SPH_C32(0xd19e0000), SPH_C32(0x57150000), SPH_C32(0x12370000), + SPH_C32(0x86bd4801), SPH_C32(0x0a90fcf4), SPH_C32(0xaa4397f5), + SPH_C32(0x8199c3e5) }, + { SPH_C32(0x13bd1430), SPH_C32(0x5f940000), SPH_C32(0x60880000), + SPH_C32(0x71010000), SPH_C32(0x3bc161fe), SPH_C32(0xc8f70f50), + SPH_C32(0x32139431), SPH_C32(0x598f6aa3), SPH_C32(0x81dad640), + SPH_C32(0xeb630000), SPH_C32(0x0abb0000), SPH_C32(0x7b7e0000), + SPH_C32(0x1db27407), SPH_C32(0x4e95490d), SPH_C32(0xcc579da4), + SPH_C32(0x13d69eef) }, + { SPH_C32(0xfcb61640), SPH_C32(0x65690000), SPH_C32(0x3d260000), + SPH_C32(0x18480000), SPH_C32(0xa0ce5df8), SPH_C32(0x8cf2baa9), + SPH_C32(0x54079e60), SPH_C32(0xcbc037a9), SPH_C32(0x48b1d670), + SPH_C32(0x0c460000), SPH_C32(0x253f0000), SPH_C32(0x5d310000), + SPH_C32(0x15db2ffe), SPH_C32(0x2369b83a), SPH_C32(0x9cc8f420), + SPH_C32(0x8dbf3187) }, + { SPH_C32(0xce8c2800), SPH_C32(0x01580000), SPH_C32(0x2e2b0000), + SPH_C32(0xa62f0000), SPH_C32(0xfdc9076b), SPH_C32(0x1542c31f), + SPH_C32(0x25259a95), SPH_C32(0x2668e10e), SPH_C32(0x84ddc000), + SPH_C32(0xfe020000), SPH_C32(0x8c560000), SPH_C32(0xcf0d0000), + SPH_C32(0xfd19379d), SPH_C32(0x9fcaa88a), SPH_C32(0xf818f44e), + SPH_C32(0xc3d48a92) }, + { SPH_C32(0x21872a70), SPH_C32(0x3ba50000), SPH_C32(0x73850000), + SPH_C32(0xcf660000), SPH_C32(0x66c63b6d), SPH_C32(0x514776e6), + SPH_C32(0x433190c4), SPH_C32(0xb427bc04), SPH_C32(0x4db6c030), + SPH_C32(0x19270000), SPH_C32(0xa3d20000), SPH_C32(0xe9420000), + SPH_C32(0xf5706c64), SPH_C32(0xf23659bd), SPH_C32(0xa8879dca), + SPH_C32(0x5dbd25fa) }, + { SPH_C32(0x07e72830), SPH_C32(0xe67d0000), SPH_C32(0x01af0000), + SPH_C32(0x80600000), SPH_C32(0xf5a05c92), SPH_C32(0x78be3228), + SPH_C32(0x75baf311), SPH_C32(0xb8014e66), SPH_C32(0xa2bdc240), + SPH_C32(0x23da0000), SPH_C32(0xfe7c0000), SPH_C32(0x800b0000), + SPH_C32(0x6e7f5062), SPH_C32(0xb633ec44), SPH_C32(0xce93979b), + SPH_C32(0xcff278f0) }, + { SPH_C32(0xe8ec2a40), SPH_C32(0xdc800000), SPH_C32(0x5c010000), + SPH_C32(0xe9290000), SPH_C32(0x6eaf6094), SPH_C32(0x3cbb87d1), + SPH_C32(0x13aef940), SPH_C32(0x2a4e136c), SPH_C32(0x6bd6c270), + SPH_C32(0xc4ff0000), SPH_C32(0xd1f80000), SPH_C32(0xa6440000), + SPH_C32(0x66160b9b), SPH_C32(0xdbcf1d73), SPH_C32(0x9e0cfe1f), + SPH_C32(0x519bd798) }, + { SPH_C32(0xf9b10000), SPH_C32(0x70080000), SPH_C32(0xbbcb0000), + SPH_C32(0xac3b0000), SPH_C32(0x40651e62), SPH_C32(0x5dad5b2e), + SPH_C32(0x6048f78a), SPH_C32(0x1bc223d4), SPH_C32(0x9087fc00), + SPH_C32(0x47eb0000), SPH_C32(0xed710000), SPH_C32(0x3e6c0000), + SPH_C32(0x33780af1), SPH_C32(0x2f8395f2), SPH_C32(0xbfb1936e), + SPH_C32(0x225aae57) }, + { SPH_C32(0x16ba0270), SPH_C32(0x4af50000), SPH_C32(0xe6650000), + SPH_C32(0xc5720000), SPH_C32(0xdb6a2264), SPH_C32(0x19a8eed7), + SPH_C32(0x065cfddb), SPH_C32(0x898d7ede), SPH_C32(0x59ecfc30), + SPH_C32(0xa0ce0000), SPH_C32(0xc2f50000), SPH_C32(0x18230000), + SPH_C32(0x3b115108), SPH_C32(0x427f64c5), SPH_C32(0xef2efaea), + SPH_C32(0xbc33013f) }, + { SPH_C32(0x30da0030), SPH_C32(0x972d0000), SPH_C32(0x944f0000), + SPH_C32(0x8a740000), SPH_C32(0x480c459b), SPH_C32(0x3051aa19), + SPH_C32(0x30d79e0e), SPH_C32(0x85ab8cbc), SPH_C32(0xb6e7fe40), + SPH_C32(0x9a330000), SPH_C32(0x9f5b0000), SPH_C32(0x716a0000), + SPH_C32(0xa01e6d0e), SPH_C32(0x067ad13c), SPH_C32(0x893af0bb), + SPH_C32(0x2e7c5c35) }, + { SPH_C32(0xdfd10240), SPH_C32(0xadd00000), SPH_C32(0xc9e10000), + SPH_C32(0xe33d0000), SPH_C32(0xd303799d), SPH_C32(0x74541fe0), + SPH_C32(0x56c3945f), SPH_C32(0x17e4d1b6), SPH_C32(0x7f8cfe70), + SPH_C32(0x7d160000), SPH_C32(0xb0df0000), SPH_C32(0x57250000), + SPH_C32(0xa87736f7), SPH_C32(0x6b86200b), SPH_C32(0xd9a5993f), + SPH_C32(0xb015f35d) }, + { SPH_C32(0xedeb3c00), SPH_C32(0xc9e10000), SPH_C32(0xdaec0000), + SPH_C32(0x5d5a0000), SPH_C32(0x8e04230e), SPH_C32(0xede46656), + SPH_C32(0x27e190aa), SPH_C32(0xfa4c0711), SPH_C32(0xb3e0e800), + SPH_C32(0x8f520000), SPH_C32(0x19b60000), SPH_C32(0xc5190000), + SPH_C32(0x40b52e94), SPH_C32(0xd72530bb), SPH_C32(0xbd759951), + SPH_C32(0xfe7e4848) }, + { SPH_C32(0x02e03e70), SPH_C32(0xf31c0000), SPH_C32(0x87420000), + SPH_C32(0x34130000), SPH_C32(0x150b1f08), SPH_C32(0xa9e1d3af), + SPH_C32(0x41f59afb), SPH_C32(0x68035a1b), SPH_C32(0x7a8be830), + SPH_C32(0x68770000), SPH_C32(0x36320000), SPH_C32(0xe3560000), + SPH_C32(0x48dc756d), SPH_C32(0xbad9c18c), SPH_C32(0xedeaf0d5), + SPH_C32(0x6017e720) }, + { SPH_C32(0x24803c30), SPH_C32(0x2ec40000), SPH_C32(0xf5680000), + SPH_C32(0x7b150000), SPH_C32(0x866d78f7), SPH_C32(0x80189761), + SPH_C32(0x777ef92e), SPH_C32(0x6425a879), SPH_C32(0x9580ea40), + SPH_C32(0x528a0000), SPH_C32(0x6b9c0000), SPH_C32(0x8a1f0000), + SPH_C32(0xd3d3496b), SPH_C32(0xfedc7475), SPH_C32(0x8bfefa84), + SPH_C32(0xf258ba2a) }, + { SPH_C32(0xcb8b3e40), SPH_C32(0x14390000), SPH_C32(0xa8c60000), + SPH_C32(0x125c0000), SPH_C32(0x1d6244f1), SPH_C32(0xc41d2298), + SPH_C32(0x116af37f), SPH_C32(0xf66af573), SPH_C32(0x5cebea70), + SPH_C32(0xb5af0000), SPH_C32(0x44180000), SPH_C32(0xac500000), + SPH_C32(0xdbba1292), SPH_C32(0x93208542), SPH_C32(0xdb619300), + SPH_C32(0x6c311542) }, + { SPH_C32(0x8efe4800), SPH_C32(0x525c0000), SPH_C32(0x8ada0000), + SPH_C32(0xf68b0000), SPH_C32(0x800a5d77), SPH_C32(0x31ae3a86), + SPH_C32(0x093cbc28), SPH_C32(0x92fdf249), SPH_C32(0x3b01cc00), + SPH_C32(0x86680000), SPH_C32(0xeac00000), SPH_C32(0xd9eb0000), + SPH_C32(0xd7ee50bd), SPH_C32(0x8678d837), SPH_C32(0xb9dacdab), + SPH_C32(0x673aa2a4) }, + { SPH_C32(0x61f54a70), SPH_C32(0x68a10000), SPH_C32(0xd7740000), + SPH_C32(0x9fc20000), SPH_C32(0x1b056171), SPH_C32(0x75ab8f7f), + SPH_C32(0x6f28b679), SPH_C32(0x00b2af43), SPH_C32(0xf26acc30), + SPH_C32(0x614d0000), SPH_C32(0xc5440000), SPH_C32(0xffa40000), + SPH_C32(0xdf870b44), SPH_C32(0xeb842900), SPH_C32(0xe945a42f), + SPH_C32(0xf9530dcc) }, + { SPH_C32(0x47954830), SPH_C32(0xb5790000), SPH_C32(0xa55e0000), + SPH_C32(0xd0c40000), SPH_C32(0x8863068e), SPH_C32(0x5c52cbb1), + SPH_C32(0x59a3d5ac), SPH_C32(0x0c945d21), SPH_C32(0x1d61ce40), + SPH_C32(0x5bb00000), SPH_C32(0x98ea0000), SPH_C32(0x96ed0000), + SPH_C32(0x44883742), SPH_C32(0xaf819cf9), SPH_C32(0x8f51ae7e), + SPH_C32(0x6b1c50c6) }, + { SPH_C32(0xa89e4a40), SPH_C32(0x8f840000), SPH_C32(0xf8f00000), + SPH_C32(0xb98d0000), SPH_C32(0x136c3a88), SPH_C32(0x18577e48), + SPH_C32(0x3fb7dffd), SPH_C32(0x9edb002b), SPH_C32(0xd40ace70), + SPH_C32(0xbc950000), SPH_C32(0xb76e0000), SPH_C32(0xb0a20000), + SPH_C32(0x4ce16cbb), SPH_C32(0xc27d6dce), SPH_C32(0xdfcec7fa), + SPH_C32(0xf575ffae) }, + { SPH_C32(0x9aa47400), SPH_C32(0xebb50000), SPH_C32(0xebfd0000), + SPH_C32(0x07ea0000), SPH_C32(0x4e6b601b), SPH_C32(0x81e707fe), + SPH_C32(0x4e95db08), SPH_C32(0x7373d68c), SPH_C32(0x1866d800), + SPH_C32(0x4ed10000), SPH_C32(0x1e070000), SPH_C32(0x229e0000), + SPH_C32(0xa42374d8), SPH_C32(0x7ede7d7e), SPH_C32(0xbb1ec794), + SPH_C32(0xbb1e44bb) }, + { SPH_C32(0x75af7670), SPH_C32(0xd1480000), SPH_C32(0xb6530000), + SPH_C32(0x6ea30000), SPH_C32(0xd5645c1d), SPH_C32(0xc5e2b207), + SPH_C32(0x2881d159), SPH_C32(0xe13c8b86), SPH_C32(0xd10dd830), + SPH_C32(0xa9f40000), SPH_C32(0x31830000), SPH_C32(0x04d10000), + SPH_C32(0xac4a2f21), SPH_C32(0x13228c49), SPH_C32(0xeb81ae10), + SPH_C32(0x2577ebd3) }, + { SPH_C32(0x53cf7430), SPH_C32(0x0c900000), SPH_C32(0xc4790000), + SPH_C32(0x21a50000), SPH_C32(0x46023be2), SPH_C32(0xec1bf6c9), + SPH_C32(0x1e0ab28c), SPH_C32(0xed1a79e4), SPH_C32(0x3e06da40), + SPH_C32(0x93090000), SPH_C32(0x6c2d0000), SPH_C32(0x6d980000), + SPH_C32(0x37451327), SPH_C32(0x572739b0), SPH_C32(0x8d95a441), + SPH_C32(0xb738b6d9) }, + { SPH_C32(0xbcc47640), SPH_C32(0x366d0000), SPH_C32(0x99d70000), + SPH_C32(0x48ec0000), SPH_C32(0xdd0d07e4), SPH_C32(0xa81e4330), + SPH_C32(0x781eb8dd), SPH_C32(0x7f5524ee), SPH_C32(0xf76dda70), + SPH_C32(0x742c0000), SPH_C32(0x43a90000), SPH_C32(0x4bd70000), + SPH_C32(0x3f2c48de), SPH_C32(0x3adbc887), SPH_C32(0xdd0acdc5), + SPH_C32(0x295119b1) }, + { SPH_C32(0xad995c00), SPH_C32(0x9ae50000), SPH_C32(0x7e1d0000), + SPH_C32(0x0dfe0000), SPH_C32(0xf3c77912), SPH_C32(0xc9089fcf), + SPH_C32(0x0bf8b617), SPH_C32(0x4ed91456), SPH_C32(0x0c3ce400), + SPH_C32(0xf7380000), SPH_C32(0x7f200000), SPH_C32(0xd3ff0000), + SPH_C32(0x6a4249b4), SPH_C32(0xce974006), SPH_C32(0xfcb7a0b4), + SPH_C32(0x5a90607e) }, + { SPH_C32(0x42925e70), SPH_C32(0xa0180000), SPH_C32(0x23b30000), + SPH_C32(0x64b70000), SPH_C32(0x68c84514), SPH_C32(0x8d0d2a36), + SPH_C32(0x6decbc46), SPH_C32(0xdc96495c), SPH_C32(0xc557e430), + SPH_C32(0x101d0000), SPH_C32(0x50a40000), SPH_C32(0xf5b00000), + SPH_C32(0x622b124d), SPH_C32(0xa36bb131), SPH_C32(0xac28c930), + SPH_C32(0xc4f9cf16) }, + { SPH_C32(0x64f25c30), SPH_C32(0x7dc00000), SPH_C32(0x51990000), + SPH_C32(0x2bb10000), SPH_C32(0xfbae22eb), SPH_C32(0xa4f46ef8), + SPH_C32(0x5b67df93), SPH_C32(0xd0b0bb3e), SPH_C32(0x2a5ce640), + SPH_C32(0x2ae00000), SPH_C32(0x0d0a0000), SPH_C32(0x9cf90000), + SPH_C32(0xf9242e4b), SPH_C32(0xe76e04c8), SPH_C32(0xca3cc361), + SPH_C32(0x56b6921c) }, + { SPH_C32(0x8bf95e40), SPH_C32(0x473d0000), SPH_C32(0x0c370000), + SPH_C32(0x42f80000), SPH_C32(0x60a11eed), SPH_C32(0xe0f1db01), + SPH_C32(0x3d73d5c2), SPH_C32(0x42ffe634), SPH_C32(0xe337e670), + SPH_C32(0xcdc50000), SPH_C32(0x228e0000), SPH_C32(0xbab60000), + SPH_C32(0xf14d75b2), SPH_C32(0x8a92f5ff), SPH_C32(0x9aa3aae5), + SPH_C32(0xc8df3d74) }, + { SPH_C32(0xb9c36000), SPH_C32(0x230c0000), SPH_C32(0x1f3a0000), + SPH_C32(0xfc9f0000), SPH_C32(0x3da6447e), SPH_C32(0x7941a2b7), + SPH_C32(0x4c51d137), SPH_C32(0xaf573093), SPH_C32(0x2f5bf000), + SPH_C32(0x3f810000), SPH_C32(0x8be70000), SPH_C32(0x288a0000), + SPH_C32(0x198f6dd1), SPH_C32(0x3631e54f), SPH_C32(0xfe73aa8b), + SPH_C32(0x86b48661) }, + { SPH_C32(0x56c86270), SPH_C32(0x19f10000), SPH_C32(0x42940000), + SPH_C32(0x95d60000), SPH_C32(0xa6a97878), SPH_C32(0x3d44174e), + SPH_C32(0x2a45db66), SPH_C32(0x3d186d99), SPH_C32(0xe630f030), + SPH_C32(0xd8a40000), SPH_C32(0xa4630000), SPH_C32(0x0ec50000), + SPH_C32(0x11e63628), SPH_C32(0x5bcd1478), SPH_C32(0xaeecc30f), + SPH_C32(0x18dd2909) }, + { SPH_C32(0x70a86030), SPH_C32(0xc4290000), SPH_C32(0x30be0000), + SPH_C32(0xdad00000), SPH_C32(0x35cf1f87), SPH_C32(0x14bd5380), + SPH_C32(0x1cceb8b3), SPH_C32(0x313e9ffb), SPH_C32(0x093bf240), + SPH_C32(0xe2590000), SPH_C32(0xf9cd0000), SPH_C32(0x678c0000), + SPH_C32(0x8ae90a2e), SPH_C32(0x1fc8a181), SPH_C32(0xc8f8c95e), + SPH_C32(0x8a927403) }, + { SPH_C32(0x9fa36240), SPH_C32(0xfed40000), SPH_C32(0x6d100000), + SPH_C32(0xb3990000), SPH_C32(0xaec02381), SPH_C32(0x50b8e679), + SPH_C32(0x7adab2e2), SPH_C32(0xa371c2f1), SPH_C32(0xc050f270), + SPH_C32(0x057c0000), SPH_C32(0xd6490000), SPH_C32(0x41c30000), + SPH_C32(0x828051d7), SPH_C32(0x723450b6), SPH_C32(0x9867a0da), + SPH_C32(0x14fbdb6b) }, + { SPH_C32(0x6f299000), SPH_C32(0x6c850000), SPH_C32(0x2f160000), + SPH_C32(0x782e0000), SPH_C32(0x644c37cd), SPH_C32(0x12dd1cd6), + SPH_C32(0xd26a8c36), SPH_C32(0x32219526), SPH_C32(0x29449c00), + SPH_C32(0x64e70000), SPH_C32(0xf24b0000), SPH_C32(0xc2f30000), + SPH_C32(0x0ede4e8f), SPH_C32(0x56c23745), SPH_C32(0xf3e04259), + SPH_C32(0x8d0d9ec4) }, + { SPH_C32(0x80229270), SPH_C32(0x56780000), SPH_C32(0x72b80000), + SPH_C32(0x11670000), SPH_C32(0xff430bcb), SPH_C32(0x56d8a92f), + SPH_C32(0xb47e8667), SPH_C32(0xa06ec82c), SPH_C32(0xe02f9c30), + SPH_C32(0x83c20000), SPH_C32(0xddcf0000), SPH_C32(0xe4bc0000), + SPH_C32(0x06b71576), SPH_C32(0x3b3ec672), SPH_C32(0xa37f2bdd), + SPH_C32(0x136431ac) }, + { SPH_C32(0xa6429030), SPH_C32(0x8ba00000), SPH_C32(0x00920000), + SPH_C32(0x5e610000), SPH_C32(0x6c256c34), SPH_C32(0x7f21ede1), + SPH_C32(0x82f5e5b2), SPH_C32(0xac483a4e), SPH_C32(0x0f249e40), + SPH_C32(0xb93f0000), SPH_C32(0x80610000), SPH_C32(0x8df50000), + SPH_C32(0x9db82970), SPH_C32(0x7f3b738b), SPH_C32(0xc56b218c), + SPH_C32(0x812b6ca6) }, + { SPH_C32(0x49499240), SPH_C32(0xb15d0000), SPH_C32(0x5d3c0000), + SPH_C32(0x37280000), SPH_C32(0xf72a5032), SPH_C32(0x3b245818), + SPH_C32(0xe4e1efe3), SPH_C32(0x3e076744), SPH_C32(0xc64f9e70), + SPH_C32(0x5e1a0000), SPH_C32(0xafe50000), SPH_C32(0xabba0000), + SPH_C32(0x95d17289), SPH_C32(0x12c782bc), SPH_C32(0x95f44808), + SPH_C32(0x1f42c3ce) }, + { SPH_C32(0x7b73ac00), SPH_C32(0xd56c0000), SPH_C32(0x4e310000), + SPH_C32(0x894f0000), SPH_C32(0xaa2d0aa1), SPH_C32(0xa29421ae), + SPH_C32(0x95c3eb16), SPH_C32(0xd3afb1e3), SPH_C32(0x0a238800), + SPH_C32(0xac5e0000), SPH_C32(0x068c0000), SPH_C32(0x39860000), + SPH_C32(0x7d136aea), SPH_C32(0xae64920c), SPH_C32(0xf1244866), + SPH_C32(0x512978db) }, + { SPH_C32(0x9478ae70), SPH_C32(0xef910000), SPH_C32(0x139f0000), + SPH_C32(0xe0060000), SPH_C32(0x312236a7), SPH_C32(0xe6919457), + SPH_C32(0xf3d7e147), SPH_C32(0x41e0ece9), SPH_C32(0xc3488830), + SPH_C32(0x4b7b0000), SPH_C32(0x29080000), SPH_C32(0x1fc90000), + SPH_C32(0x757a3113), SPH_C32(0xc398633b), SPH_C32(0xa1bb21e2), + SPH_C32(0xcf40d7b3) }, + { SPH_C32(0xb218ac30), SPH_C32(0x32490000), SPH_C32(0x61b50000), + SPH_C32(0xaf000000), SPH_C32(0xa2445158), SPH_C32(0xcf68d099), + SPH_C32(0xc55c8292), SPH_C32(0x4dc61e8b), SPH_C32(0x2c438a40), + SPH_C32(0x71860000), SPH_C32(0x74a60000), SPH_C32(0x76800000), + SPH_C32(0xee750d15), SPH_C32(0x879dd6c2), SPH_C32(0xc7af2bb3), + SPH_C32(0x5d0f8ab9) }, + { SPH_C32(0x5d13ae40), SPH_C32(0x08b40000), SPH_C32(0x3c1b0000), + SPH_C32(0xc6490000), SPH_C32(0x394b6d5e), SPH_C32(0x8b6d6560), + SPH_C32(0xa34888c3), SPH_C32(0xdf894381), SPH_C32(0xe5288a70), + SPH_C32(0x96a30000), SPH_C32(0x5b220000), SPH_C32(0x50cf0000), + SPH_C32(0xe61c56ec), SPH_C32(0xea6127f5), SPH_C32(0x97304237), + SPH_C32(0xc36625d1) }, + { SPH_C32(0x4c4e8400), SPH_C32(0xa43c0000), SPH_C32(0xdbd10000), + SPH_C32(0x835b0000), SPH_C32(0x178113a8), SPH_C32(0xea7bb99f), + SPH_C32(0xd0ae8609), SPH_C32(0xee057339), SPH_C32(0x1e79b400), + SPH_C32(0x15b70000), SPH_C32(0x67ab0000), SPH_C32(0xc8e70000), + SPH_C32(0xb3725786), SPH_C32(0x1e2daf74), SPH_C32(0xb68d2f46), + SPH_C32(0xb0a75c1e) }, + { SPH_C32(0xa3458670), SPH_C32(0x9ec10000), SPH_C32(0x867f0000), + SPH_C32(0xea120000), SPH_C32(0x8c8e2fae), SPH_C32(0xae7e0c66), + SPH_C32(0xb6ba8c58), SPH_C32(0x7c4a2e33), SPH_C32(0xd712b430), + SPH_C32(0xf2920000), SPH_C32(0x482f0000), SPH_C32(0xeea80000), + SPH_C32(0xbb1b0c7f), SPH_C32(0x73d15e43), SPH_C32(0xe61246c2), + SPH_C32(0x2ecef376) }, + { SPH_C32(0x85258430), SPH_C32(0x43190000), SPH_C32(0xf4550000), + SPH_C32(0xa5140000), SPH_C32(0x1fe84851), SPH_C32(0x878748a8), + SPH_C32(0x8031ef8d), SPH_C32(0x706cdc51), SPH_C32(0x3819b640), + SPH_C32(0xc86f0000), SPH_C32(0x15810000), SPH_C32(0x87e10000), + SPH_C32(0x20143079), SPH_C32(0x37d4ebba), SPH_C32(0x80064c93), + SPH_C32(0xbc81ae7c) }, + { SPH_C32(0x6a2e8640), SPH_C32(0x79e40000), SPH_C32(0xa9fb0000), + SPH_C32(0xcc5d0000), SPH_C32(0x84e77457), SPH_C32(0xc382fd51), + SPH_C32(0xe625e5dc), SPH_C32(0xe223815b), SPH_C32(0xf172b670), + SPH_C32(0x2f4a0000), SPH_C32(0x3a050000), SPH_C32(0xa1ae0000), + SPH_C32(0x287d6b80), SPH_C32(0x5a281a8d), SPH_C32(0xd0992517), + SPH_C32(0x22e80114) }, + { SPH_C32(0x5814b800), SPH_C32(0x1dd50000), SPH_C32(0xbaf60000), + SPH_C32(0x723a0000), SPH_C32(0xd9e02ec4), SPH_C32(0x5a3284e7), + SPH_C32(0x9707e129), SPH_C32(0x0f8b57fc), SPH_C32(0x3d1ea000), + SPH_C32(0xdd0e0000), SPH_C32(0x936c0000), SPH_C32(0x33920000), + SPH_C32(0xc0bf73e3), SPH_C32(0xe68b0a3d), SPH_C32(0xb4492579), + SPH_C32(0x6c83ba01) }, + { SPH_C32(0xb71fba70), SPH_C32(0x27280000), SPH_C32(0xe7580000), + SPH_C32(0x1b730000), SPH_C32(0x42ef12c2), SPH_C32(0x1e37311e), + SPH_C32(0xf113eb78), SPH_C32(0x9dc40af6), SPH_C32(0xf475a030), + SPH_C32(0x3a2b0000), SPH_C32(0xbce80000), SPH_C32(0x15dd0000), + SPH_C32(0xc8d6281a), SPH_C32(0x8b77fb0a), SPH_C32(0xe4d64cfd), + SPH_C32(0xf2ea1569) }, + { SPH_C32(0x917fb830), SPH_C32(0xfaf00000), SPH_C32(0x95720000), + SPH_C32(0x54750000), SPH_C32(0xd189753d), SPH_C32(0x37ce75d0), + SPH_C32(0xc79888ad), SPH_C32(0x91e2f894), SPH_C32(0x1b7ea240), + SPH_C32(0x00d60000), SPH_C32(0xe1460000), SPH_C32(0x7c940000), + SPH_C32(0x53d9141c), SPH_C32(0xcf724ef3), SPH_C32(0x82c246ac), + SPH_C32(0x60a54863) }, + { SPH_C32(0x7e74ba40), SPH_C32(0xc00d0000), SPH_C32(0xc8dc0000), + SPH_C32(0x3d3c0000), SPH_C32(0x4a86493b), SPH_C32(0x73cbc029), + SPH_C32(0xa18c82fc), SPH_C32(0x03ada59e), SPH_C32(0xd215a270), + SPH_C32(0xe7f30000), SPH_C32(0xcec20000), SPH_C32(0x5adb0000), + SPH_C32(0x5bb04fe5), SPH_C32(0xa28ebfc4), SPH_C32(0xd25d2f28), + SPH_C32(0xfecce70b) }, + { SPH_C32(0x3b01cc00), SPH_C32(0x86680000), SPH_C32(0xeac00000), + SPH_C32(0xd9eb0000), SPH_C32(0xd7ee50bd), SPH_C32(0x8678d837), + SPH_C32(0xb9dacdab), SPH_C32(0x673aa2a4), SPH_C32(0xb5ff8400), + SPH_C32(0xd4340000), SPH_C32(0x601a0000), SPH_C32(0x2f600000), + SPH_C32(0x57e40dca), SPH_C32(0xb7d6e2b1), SPH_C32(0xb0e67183), + SPH_C32(0xf5c750ed) }, + { SPH_C32(0xd40ace70), SPH_C32(0xbc950000), SPH_C32(0xb76e0000), + SPH_C32(0xb0a20000), SPH_C32(0x4ce16cbb), SPH_C32(0xc27d6dce), + SPH_C32(0xdfcec7fa), SPH_C32(0xf575ffae), SPH_C32(0x7c948430), + SPH_C32(0x33110000), SPH_C32(0x4f9e0000), SPH_C32(0x092f0000), + SPH_C32(0x5f8d5633), SPH_C32(0xda2a1386), SPH_C32(0xe0791807), + SPH_C32(0x6baeff85) }, + { SPH_C32(0xf26acc30), SPH_C32(0x614d0000), SPH_C32(0xc5440000), + SPH_C32(0xffa40000), SPH_C32(0xdf870b44), SPH_C32(0xeb842900), + SPH_C32(0xe945a42f), SPH_C32(0xf9530dcc), SPH_C32(0x939f8640), + SPH_C32(0x09ec0000), SPH_C32(0x12300000), SPH_C32(0x60660000), + SPH_C32(0xc4826a35), SPH_C32(0x9e2fa67f), SPH_C32(0x866d1256), + SPH_C32(0xf9e1a28f) }, + { SPH_C32(0x1d61ce40), SPH_C32(0x5bb00000), SPH_C32(0x98ea0000), + SPH_C32(0x96ed0000), SPH_C32(0x44883742), SPH_C32(0xaf819cf9), + SPH_C32(0x8f51ae7e), SPH_C32(0x6b1c50c6), SPH_C32(0x5af48670), + SPH_C32(0xeec90000), SPH_C32(0x3db40000), SPH_C32(0x46290000), + SPH_C32(0xcceb31cc), SPH_C32(0xf3d35748), SPH_C32(0xd6f27bd2), + SPH_C32(0x67880de7) }, + { SPH_C32(0x2f5bf000), SPH_C32(0x3f810000), SPH_C32(0x8be70000), + SPH_C32(0x288a0000), SPH_C32(0x198f6dd1), SPH_C32(0x3631e54f), + SPH_C32(0xfe73aa8b), SPH_C32(0x86b48661), SPH_C32(0x96989000), + SPH_C32(0x1c8d0000), SPH_C32(0x94dd0000), SPH_C32(0xd4150000), + SPH_C32(0x242929af), SPH_C32(0x4f7047f8), SPH_C32(0xb2227bbc), + SPH_C32(0x29e3b6f2) }, + { SPH_C32(0xc050f270), SPH_C32(0x057c0000), SPH_C32(0xd6490000), + SPH_C32(0x41c30000), SPH_C32(0x828051d7), SPH_C32(0x723450b6), + SPH_C32(0x9867a0da), SPH_C32(0x14fbdb6b), SPH_C32(0x5ff39030), + SPH_C32(0xfba80000), SPH_C32(0xbb590000), SPH_C32(0xf25a0000), + SPH_C32(0x2c407256), SPH_C32(0x228cb6cf), SPH_C32(0xe2bd1238), + SPH_C32(0xb78a199a) }, + { SPH_C32(0xe630f030), SPH_C32(0xd8a40000), SPH_C32(0xa4630000), + SPH_C32(0x0ec50000), SPH_C32(0x11e63628), SPH_C32(0x5bcd1478), + SPH_C32(0xaeecc30f), SPH_C32(0x18dd2909), SPH_C32(0xb0f89240), + SPH_C32(0xc1550000), SPH_C32(0xe6f70000), SPH_C32(0x9b130000), + SPH_C32(0xb74f4e50), SPH_C32(0x66890336), SPH_C32(0x84a91869), + SPH_C32(0x25c54490) }, + { SPH_C32(0x093bf240), SPH_C32(0xe2590000), SPH_C32(0xf9cd0000), + SPH_C32(0x678c0000), SPH_C32(0x8ae90a2e), SPH_C32(0x1fc8a181), + SPH_C32(0xc8f8c95e), SPH_C32(0x8a927403), SPH_C32(0x79939270), + SPH_C32(0x26700000), SPH_C32(0xc9730000), SPH_C32(0xbd5c0000), + SPH_C32(0xbf2615a9), SPH_C32(0x0b75f201), SPH_C32(0xd43671ed), + SPH_C32(0xbbacebf8) }, + { SPH_C32(0x1866d800), SPH_C32(0x4ed10000), SPH_C32(0x1e070000), + SPH_C32(0x229e0000), SPH_C32(0xa42374d8), SPH_C32(0x7ede7d7e), + SPH_C32(0xbb1ec794), SPH_C32(0xbb1e44bb), SPH_C32(0x82c2ac00), + SPH_C32(0xa5640000), SPH_C32(0xf5fa0000), SPH_C32(0x25740000), + SPH_C32(0xea4814c3), SPH_C32(0xff397a80), SPH_C32(0xf58b1c9c), + SPH_C32(0xc86d9237) }, + { SPH_C32(0xf76dda70), SPH_C32(0x742c0000), SPH_C32(0x43a90000), + SPH_C32(0x4bd70000), SPH_C32(0x3f2c48de), SPH_C32(0x3adbc887), + SPH_C32(0xdd0acdc5), SPH_C32(0x295119b1), SPH_C32(0x4ba9ac30), + SPH_C32(0x42410000), SPH_C32(0xda7e0000), SPH_C32(0x033b0000), + SPH_C32(0xe2214f3a), SPH_C32(0x92c58bb7), SPH_C32(0xa5147518), + SPH_C32(0x56043d5f) }, + { SPH_C32(0xd10dd830), SPH_C32(0xa9f40000), SPH_C32(0x31830000), + SPH_C32(0x04d10000), SPH_C32(0xac4a2f21), SPH_C32(0x13228c49), + SPH_C32(0xeb81ae10), SPH_C32(0x2577ebd3), SPH_C32(0xa4a2ae40), + SPH_C32(0x78bc0000), SPH_C32(0x87d00000), SPH_C32(0x6a720000), + SPH_C32(0x792e733c), SPH_C32(0xd6c03e4e), SPH_C32(0xc3007f49), + SPH_C32(0xc44b6055) }, + { SPH_C32(0x3e06da40), SPH_C32(0x93090000), SPH_C32(0x6c2d0000), + SPH_C32(0x6d980000), SPH_C32(0x37451327), SPH_C32(0x572739b0), + SPH_C32(0x8d95a441), SPH_C32(0xb738b6d9), SPH_C32(0x6dc9ae70), + SPH_C32(0x9f990000), SPH_C32(0xa8540000), SPH_C32(0x4c3d0000), + SPH_C32(0x714728c5), SPH_C32(0xbb3ccf79), SPH_C32(0x939f16cd), + SPH_C32(0x5a22cf3d) }, + { SPH_C32(0x0c3ce400), SPH_C32(0xf7380000), SPH_C32(0x7f200000), + SPH_C32(0xd3ff0000), SPH_C32(0x6a4249b4), SPH_C32(0xce974006), + SPH_C32(0xfcb7a0b4), SPH_C32(0x5a90607e), SPH_C32(0xa1a5b800), + SPH_C32(0x6ddd0000), SPH_C32(0x013d0000), SPH_C32(0xde010000), + SPH_C32(0x998530a6), SPH_C32(0x079fdfc9), SPH_C32(0xf74f16a3), + SPH_C32(0x14497428) }, + { SPH_C32(0xe337e670), SPH_C32(0xcdc50000), SPH_C32(0x228e0000), + SPH_C32(0xbab60000), SPH_C32(0xf14d75b2), SPH_C32(0x8a92f5ff), + SPH_C32(0x9aa3aae5), SPH_C32(0xc8df3d74), SPH_C32(0x68ceb830), + SPH_C32(0x8af80000), SPH_C32(0x2eb90000), SPH_C32(0xf84e0000), + SPH_C32(0x91ec6b5f), SPH_C32(0x6a632efe), SPH_C32(0xa7d07f27), + SPH_C32(0x8a20db40) }, + { SPH_C32(0xc557e430), SPH_C32(0x101d0000), SPH_C32(0x50a40000), + SPH_C32(0xf5b00000), SPH_C32(0x622b124d), SPH_C32(0xa36bb131), + SPH_C32(0xac28c930), SPH_C32(0xc4f9cf16), SPH_C32(0x87c5ba40), + SPH_C32(0xb0050000), SPH_C32(0x73170000), SPH_C32(0x91070000), + SPH_C32(0x0ae35759), SPH_C32(0x2e669b07), SPH_C32(0xc1c47576), + SPH_C32(0x186f864a) }, + { SPH_C32(0x2a5ce640), SPH_C32(0x2ae00000), SPH_C32(0x0d0a0000), + SPH_C32(0x9cf90000), SPH_C32(0xf9242e4b), SPH_C32(0xe76e04c8), + SPH_C32(0xca3cc361), SPH_C32(0x56b6921c), SPH_C32(0x4eaeba70), + SPH_C32(0x57200000), SPH_C32(0x5c930000), SPH_C32(0xb7480000), + SPH_C32(0x028a0ca0), SPH_C32(0x439a6a30), SPH_C32(0x915b1cf2), + SPH_C32(0x86062922) }, + { SPH_C32(0xf3928800), SPH_C32(0xdc560000), SPH_C32(0xbd470000), + SPH_C32(0x95bd0000), SPH_C32(0x3d767488), SPH_C32(0xf3c9c922), + SPH_C32(0x916cbfec), SPH_C32(0x4aeb5b0f), SPH_C32(0xe1d7d800), + SPH_C32(0x3ed90000), SPH_C32(0xa5cc0000), SPH_C32(0x8ea50000), + SPH_C32(0xe4466aba), SPH_C32(0x23732650), SPH_C32(0xdb56301e), + SPH_C32(0xa0dc676f) }, + { SPH_C32(0x1c998a70), SPH_C32(0xe6ab0000), SPH_C32(0xe0e90000), + SPH_C32(0xfcf40000), SPH_C32(0xa679488e), SPH_C32(0xb7cc7cdb), + SPH_C32(0xf778b5bd), SPH_C32(0xd8a40605), SPH_C32(0x28bcd830), + SPH_C32(0xd9fc0000), SPH_C32(0x8a480000), SPH_C32(0xa8ea0000), + SPH_C32(0xec2f3143), SPH_C32(0x4e8fd767), SPH_C32(0x8bc9599a), + SPH_C32(0x3eb5c807) }, + { SPH_C32(0x3af98830), SPH_C32(0x3b730000), SPH_C32(0x92c30000), + SPH_C32(0xb3f20000), SPH_C32(0x351f2f71), SPH_C32(0x9e353815), + SPH_C32(0xc1f3d668), SPH_C32(0xd482f467), SPH_C32(0xc7b7da40), + SPH_C32(0xe3010000), SPH_C32(0xd7e60000), SPH_C32(0xc1a30000), + SPH_C32(0x77200d45), SPH_C32(0x0a8a629e), SPH_C32(0xeddd53cb), + SPH_C32(0xacfa950d) }, + { SPH_C32(0xd5f28a40), SPH_C32(0x018e0000), SPH_C32(0xcf6d0000), + SPH_C32(0xdabb0000), SPH_C32(0xae101377), SPH_C32(0xda308dec), + SPH_C32(0xa7e7dc39), SPH_C32(0x46cda96d), SPH_C32(0x0edcda70), + SPH_C32(0x04240000), SPH_C32(0xf8620000), SPH_C32(0xe7ec0000), + SPH_C32(0x7f4956bc), SPH_C32(0x677693a9), SPH_C32(0xbd423a4f), + SPH_C32(0x32933a65) }, + { SPH_C32(0xe7c8b400), SPH_C32(0x65bf0000), SPH_C32(0xdc600000), + SPH_C32(0x64dc0000), SPH_C32(0xf31749e4), SPH_C32(0x4380f45a), + SPH_C32(0xd6c5d8cc), SPH_C32(0xab657fca), SPH_C32(0xc2b0cc00), + SPH_C32(0xf6600000), SPH_C32(0x510b0000), SPH_C32(0x75d00000), + SPH_C32(0x978b4edf), SPH_C32(0xdbd58319), SPH_C32(0xd9923a21), + SPH_C32(0x7cf88170) }, + { SPH_C32(0x08c3b670), SPH_C32(0x5f420000), SPH_C32(0x81ce0000), + SPH_C32(0x0d950000), SPH_C32(0x681875e2), SPH_C32(0x078541a3), + SPH_C32(0xb0d1d29d), SPH_C32(0x392a22c0), SPH_C32(0x0bdbcc30), + SPH_C32(0x11450000), SPH_C32(0x7e8f0000), SPH_C32(0x539f0000), + SPH_C32(0x9fe21526), SPH_C32(0xb629722e), SPH_C32(0x890d53a5), + SPH_C32(0xe2912e18) }, + { SPH_C32(0x2ea3b430), SPH_C32(0x829a0000), SPH_C32(0xf3e40000), + SPH_C32(0x42930000), SPH_C32(0xfb7e121d), SPH_C32(0x2e7c056d), + SPH_C32(0x865ab148), SPH_C32(0x350cd0a2), SPH_C32(0xe4d0ce40), + SPH_C32(0x2bb80000), SPH_C32(0x23210000), SPH_C32(0x3ad60000), + SPH_C32(0x04ed2920), SPH_C32(0xf22cc7d7), SPH_C32(0xef1959f4), + SPH_C32(0x70de7312) }, + { SPH_C32(0xc1a8b640), SPH_C32(0xb8670000), SPH_C32(0xae4a0000), + SPH_C32(0x2bda0000), SPH_C32(0x60712e1b), SPH_C32(0x6a79b094), + SPH_C32(0xe04ebb19), SPH_C32(0xa7438da8), SPH_C32(0x2dbbce70), + SPH_C32(0xcc9d0000), SPH_C32(0x0ca50000), SPH_C32(0x1c990000), + SPH_C32(0x0c8472d9), SPH_C32(0x9fd036e0), SPH_C32(0xbf863070), + SPH_C32(0xeeb7dc7a) }, + { SPH_C32(0xd0f59c00), SPH_C32(0x14ef0000), SPH_C32(0x49800000), + SPH_C32(0x6ec80000), SPH_C32(0x4ebb50ed), SPH_C32(0x0b6f6c6b), + SPH_C32(0x93a8b5d3), SPH_C32(0x96cfbd10), SPH_C32(0xd6eaf000), + SPH_C32(0x4f890000), SPH_C32(0x302c0000), SPH_C32(0x84b10000), + SPH_C32(0x59ea73b3), SPH_C32(0x6b9cbe61), SPH_C32(0x9e3b5d01), + SPH_C32(0x9d76a5b5) }, + { SPH_C32(0x3ffe9e70), SPH_C32(0x2e120000), SPH_C32(0x142e0000), + SPH_C32(0x07810000), SPH_C32(0xd5b46ceb), SPH_C32(0x4f6ad992), + SPH_C32(0xf5bcbf82), SPH_C32(0x0480e01a), SPH_C32(0x1f81f030), + SPH_C32(0xa8ac0000), SPH_C32(0x1fa80000), SPH_C32(0xa2fe0000), + SPH_C32(0x5183284a), SPH_C32(0x06604f56), SPH_C32(0xcea43485), + SPH_C32(0x031f0add) }, + { SPH_C32(0x199e9c30), SPH_C32(0xf3ca0000), SPH_C32(0x66040000), + SPH_C32(0x48870000), SPH_C32(0x46d20b14), SPH_C32(0x66939d5c), + SPH_C32(0xc337dc57), SPH_C32(0x08a61278), SPH_C32(0xf08af240), + SPH_C32(0x92510000), SPH_C32(0x42060000), SPH_C32(0xcbb70000), + SPH_C32(0xca8c144c), SPH_C32(0x4265faaf), SPH_C32(0xa8b03ed4), + SPH_C32(0x915057d7) }, + { SPH_C32(0xf6959e40), SPH_C32(0xc9370000), SPH_C32(0x3baa0000), + SPH_C32(0x21ce0000), SPH_C32(0xdddd3712), SPH_C32(0x229628a5), + SPH_C32(0xa523d606), SPH_C32(0x9ae94f72), SPH_C32(0x39e1f270), + SPH_C32(0x75740000), SPH_C32(0x6d820000), SPH_C32(0xedf80000), + SPH_C32(0xc2e54fb5), SPH_C32(0x2f990b98), SPH_C32(0xf82f5750), + SPH_C32(0x0f39f8bf) }, + { SPH_C32(0xc4afa000), SPH_C32(0xad060000), SPH_C32(0x28a70000), + SPH_C32(0x9fa90000), SPH_C32(0x80da6d81), SPH_C32(0xbb265113), + SPH_C32(0xd401d2f3), SPH_C32(0x774199d5), SPH_C32(0xf58de400), + SPH_C32(0x87300000), SPH_C32(0xc4eb0000), SPH_C32(0x7fc40000), + SPH_C32(0x2a2757d6), SPH_C32(0x933a1b28), SPH_C32(0x9cff573e), + SPH_C32(0x415243aa) }, + { SPH_C32(0x2ba4a270), SPH_C32(0x97fb0000), SPH_C32(0x75090000), + SPH_C32(0xf6e00000), SPH_C32(0x1bd55187), SPH_C32(0xff23e4ea), + SPH_C32(0xb215d8a2), SPH_C32(0xe50ec4df), SPH_C32(0x3ce6e430), + SPH_C32(0x60150000), SPH_C32(0xeb6f0000), SPH_C32(0x598b0000), + SPH_C32(0x224e0c2f), SPH_C32(0xfec6ea1f), SPH_C32(0xcc603eba), + SPH_C32(0xdf3becc2) }, + { SPH_C32(0x0dc4a030), SPH_C32(0x4a230000), SPH_C32(0x07230000), + SPH_C32(0xb9e60000), SPH_C32(0x88b33678), SPH_C32(0xd6daa024), + SPH_C32(0x849ebb77), SPH_C32(0xe92836bd), SPH_C32(0xd3ede640), + SPH_C32(0x5ae80000), SPH_C32(0xb6c10000), SPH_C32(0x30c20000), + SPH_C32(0xb9413029), SPH_C32(0xbac35fe6), SPH_C32(0xaa7434eb), + SPH_C32(0x4d74b1c8) }, + { SPH_C32(0xe2cfa240), SPH_C32(0x70de0000), SPH_C32(0x5a8d0000), + SPH_C32(0xd0af0000), SPH_C32(0x13bc0a7e), SPH_C32(0x92df15dd), + SPH_C32(0xe28ab126), SPH_C32(0x7b676bb7), SPH_C32(0x1a86e670), + SPH_C32(0xbdcd0000), SPH_C32(0x99450000), SPH_C32(0x168d0000), + SPH_C32(0xb1286bd0), SPH_C32(0xd73faed1), SPH_C32(0xfaeb5d6f), + SPH_C32(0xd31d1ea0) }, + { SPH_C32(0xa7bad400), SPH_C32(0x36bb0000), SPH_C32(0x78910000), + SPH_C32(0x34780000), SPH_C32(0x8ed413f8), SPH_C32(0x676c0dc3), + SPH_C32(0xfadcfe71), SPH_C32(0x1ff06c8d), SPH_C32(0x7d6cc000), + SPH_C32(0x8e0a0000), SPH_C32(0x379d0000), SPH_C32(0x63360000), + SPH_C32(0xbd7c29ff), SPH_C32(0xc267f3a4), SPH_C32(0x985003c4), + SPH_C32(0xd816a946) }, + { SPH_C32(0x48b1d670), SPH_C32(0x0c460000), SPH_C32(0x253f0000), + SPH_C32(0x5d310000), SPH_C32(0x15db2ffe), SPH_C32(0x2369b83a), + SPH_C32(0x9cc8f420), SPH_C32(0x8dbf3187), SPH_C32(0xb407c030), + SPH_C32(0x692f0000), SPH_C32(0x18190000), SPH_C32(0x45790000), + SPH_C32(0xb5157206), SPH_C32(0xaf9b0293), SPH_C32(0xc8cf6a40), + SPH_C32(0x467f062e) }, + { SPH_C32(0x6ed1d430), SPH_C32(0xd19e0000), SPH_C32(0x57150000), + SPH_C32(0x12370000), SPH_C32(0x86bd4801), SPH_C32(0x0a90fcf4), + SPH_C32(0xaa4397f5), SPH_C32(0x8199c3e5), SPH_C32(0x5b0cc240), + SPH_C32(0x53d20000), SPH_C32(0x45b70000), SPH_C32(0x2c300000), + SPH_C32(0x2e1a4e00), SPH_C32(0xeb9eb76a), SPH_C32(0xaedb6011), + SPH_C32(0xd4305b24) }, + { SPH_C32(0x81dad640), SPH_C32(0xeb630000), SPH_C32(0x0abb0000), + SPH_C32(0x7b7e0000), SPH_C32(0x1db27407), SPH_C32(0x4e95490d), + SPH_C32(0xcc579da4), SPH_C32(0x13d69eef), SPH_C32(0x9267c270), + SPH_C32(0xb4f70000), SPH_C32(0x6a330000), SPH_C32(0x0a7f0000), + SPH_C32(0x267315f9), SPH_C32(0x8662465d), SPH_C32(0xfe440995), + SPH_C32(0x4a59f44c) }, + { SPH_C32(0xb3e0e800), SPH_C32(0x8f520000), SPH_C32(0x19b60000), + SPH_C32(0xc5190000), SPH_C32(0x40b52e94), SPH_C32(0xd72530bb), + SPH_C32(0xbd759951), SPH_C32(0xfe7e4848), SPH_C32(0x5e0bd400), + SPH_C32(0x46b30000), SPH_C32(0xc35a0000), SPH_C32(0x98430000), + SPH_C32(0xceb10d9a), SPH_C32(0x3ac156ed), SPH_C32(0x9a9409fb), + SPH_C32(0x04324f59) }, + { SPH_C32(0x5cebea70), SPH_C32(0xb5af0000), SPH_C32(0x44180000), + SPH_C32(0xac500000), SPH_C32(0xdbba1292), SPH_C32(0x93208542), + SPH_C32(0xdb619300), SPH_C32(0x6c311542), SPH_C32(0x9760d430), + SPH_C32(0xa1960000), SPH_C32(0xecde0000), SPH_C32(0xbe0c0000), + SPH_C32(0xc6d85663), SPH_C32(0x573da7da), SPH_C32(0xca0b607f), + SPH_C32(0x9a5be031) }, + { SPH_C32(0x7a8be830), SPH_C32(0x68770000), SPH_C32(0x36320000), + SPH_C32(0xe3560000), SPH_C32(0x48dc756d), SPH_C32(0xbad9c18c), + SPH_C32(0xedeaf0d5), SPH_C32(0x6017e720), SPH_C32(0x786bd640), + SPH_C32(0x9b6b0000), SPH_C32(0xb1700000), SPH_C32(0xd7450000), + SPH_C32(0x5dd76a65), SPH_C32(0x13381223), SPH_C32(0xac1f6a2e), + SPH_C32(0x0814bd3b) }, + { SPH_C32(0x9580ea40), SPH_C32(0x528a0000), SPH_C32(0x6b9c0000), + SPH_C32(0x8a1f0000), SPH_C32(0xd3d3496b), SPH_C32(0xfedc7475), + SPH_C32(0x8bfefa84), SPH_C32(0xf258ba2a), SPH_C32(0xb100d670), + SPH_C32(0x7c4e0000), SPH_C32(0x9ef40000), SPH_C32(0xf10a0000), + SPH_C32(0x55be319c), SPH_C32(0x7ec4e314), SPH_C32(0xfc8003aa), + SPH_C32(0x967d1253) }, + { SPH_C32(0x84ddc000), SPH_C32(0xfe020000), SPH_C32(0x8c560000), + SPH_C32(0xcf0d0000), SPH_C32(0xfd19379d), SPH_C32(0x9fcaa88a), + SPH_C32(0xf818f44e), SPH_C32(0xc3d48a92), SPH_C32(0x4a51e800), + SPH_C32(0xff5a0000), SPH_C32(0xa27d0000), SPH_C32(0x69220000), + SPH_C32(0x00d030f6), SPH_C32(0x8a886b95), SPH_C32(0xdd3d6edb), + SPH_C32(0xe5bc6b9c) }, + { SPH_C32(0x6bd6c270), SPH_C32(0xc4ff0000), SPH_C32(0xd1f80000), + SPH_C32(0xa6440000), SPH_C32(0x66160b9b), SPH_C32(0xdbcf1d73), + SPH_C32(0x9e0cfe1f), SPH_C32(0x519bd798), SPH_C32(0x833ae830), + SPH_C32(0x187f0000), SPH_C32(0x8df90000), SPH_C32(0x4f6d0000), + SPH_C32(0x08b96b0f), SPH_C32(0xe7749aa2), SPH_C32(0x8da2075f), + SPH_C32(0x7bd5c4f4) }, + { SPH_C32(0x4db6c030), SPH_C32(0x19270000), SPH_C32(0xa3d20000), + SPH_C32(0xe9420000), SPH_C32(0xf5706c64), SPH_C32(0xf23659bd), + SPH_C32(0xa8879dca), SPH_C32(0x5dbd25fa), SPH_C32(0x6c31ea40), + SPH_C32(0x22820000), SPH_C32(0xd0570000), SPH_C32(0x26240000), + SPH_C32(0x93b65709), SPH_C32(0xa3712f5b), SPH_C32(0xebb60d0e), + SPH_C32(0xe99a99fe) }, + { SPH_C32(0xa2bdc240), SPH_C32(0x23da0000), SPH_C32(0xfe7c0000), + SPH_C32(0x800b0000), SPH_C32(0x6e7f5062), SPH_C32(0xb633ec44), + SPH_C32(0xce93979b), SPH_C32(0xcff278f0), SPH_C32(0xa55aea70), + SPH_C32(0xc5a70000), SPH_C32(0xffd30000), SPH_C32(0x006b0000), + SPH_C32(0x9bdf0cf0), SPH_C32(0xce8dde6c), SPH_C32(0xbb29648a), + SPH_C32(0x77f33696) }, + { SPH_C32(0x9087fc00), SPH_C32(0x47eb0000), SPH_C32(0xed710000), + SPH_C32(0x3e6c0000), SPH_C32(0x33780af1), SPH_C32(0x2f8395f2), + SPH_C32(0xbfb1936e), SPH_C32(0x225aae57), SPH_C32(0x6936fc00), + SPH_C32(0x37e30000), SPH_C32(0x56ba0000), SPH_C32(0x92570000), + SPH_C32(0x731d1493), SPH_C32(0x722ecedc), SPH_C32(0xdff964e4), + SPH_C32(0x39988d83) }, + { SPH_C32(0x7f8cfe70), SPH_C32(0x7d160000), SPH_C32(0xb0df0000), + SPH_C32(0x57250000), SPH_C32(0xa87736f7), SPH_C32(0x6b86200b), + SPH_C32(0xd9a5993f), SPH_C32(0xb015f35d), SPH_C32(0xa05dfc30), + SPH_C32(0xd0c60000), SPH_C32(0x793e0000), SPH_C32(0xb4180000), + SPH_C32(0x7b744f6a), SPH_C32(0x1fd23feb), SPH_C32(0x8f660d60), + SPH_C32(0xa7f122eb) }, + { SPH_C32(0x59ecfc30), SPH_C32(0xa0ce0000), SPH_C32(0xc2f50000), + SPH_C32(0x18230000), SPH_C32(0x3b115108), SPH_C32(0x427f64c5), + SPH_C32(0xef2efaea), SPH_C32(0xbc33013f), SPH_C32(0x4f56fe40), + SPH_C32(0xea3b0000), SPH_C32(0x24900000), SPH_C32(0xdd510000), + SPH_C32(0xe07b736c), SPH_C32(0x5bd78a12), SPH_C32(0xe9720731), + SPH_C32(0x35be7fe1) }, + { SPH_C32(0xb6e7fe40), SPH_C32(0x9a330000), SPH_C32(0x9f5b0000), + SPH_C32(0x716a0000), SPH_C32(0xa01e6d0e), SPH_C32(0x067ad13c), + SPH_C32(0x893af0bb), SPH_C32(0x2e7c5c35), SPH_C32(0x863dfe70), + SPH_C32(0x0d1e0000), SPH_C32(0x0b140000), SPH_C32(0xfb1e0000), + SPH_C32(0xe8122895), SPH_C32(0x362b7b25), SPH_C32(0xb9ed6eb5), + SPH_C32(0xabd7d089) } +}; + +static const sph_u32 T512_8[256][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0xf6800005), SPH_C32(0x3443c000), SPH_C32(0x24070000), + SPH_C32(0x8f3d0000), SPH_C32(0x21373bfb), SPH_C32(0x0ab8d5ae), + SPH_C32(0xcdc58b19), SPH_C32(0xd795ba31), SPH_C32(0xa67f0001), + SPH_C32(0x71378000), SPH_C32(0x19fc0000), SPH_C32(0x96db0000), + SPH_C32(0x3a8b6dfd), SPH_C32(0xebcaaef3), SPH_C32(0x2c6d478f), + SPH_C32(0xac8e6c88) }, + { SPH_C32(0xa67f0001), SPH_C32(0x71378000), SPH_C32(0x19fc0000), + SPH_C32(0x96db0000), SPH_C32(0x3a8b6dfd), SPH_C32(0xebcaaef3), + SPH_C32(0x2c6d478f), SPH_C32(0xac8e6c88), SPH_C32(0x50ff0004), + SPH_C32(0x45744000), SPH_C32(0x3dfb0000), SPH_C32(0x19e60000), + SPH_C32(0x1bbc5606), SPH_C32(0xe1727b5d), SPH_C32(0xe1a8cc96), + SPH_C32(0x7b1bd6b9) }, + { SPH_C32(0x50ff0004), SPH_C32(0x45744000), SPH_C32(0x3dfb0000), + SPH_C32(0x19e60000), SPH_C32(0x1bbc5606), SPH_C32(0xe1727b5d), + SPH_C32(0xe1a8cc96), SPH_C32(0x7b1bd6b9), SPH_C32(0xf6800005), + SPH_C32(0x3443c000), SPH_C32(0x24070000), SPH_C32(0x8f3d0000), + SPH_C32(0x21373bfb), SPH_C32(0x0ab8d5ae), SPH_C32(0xcdc58b19), + SPH_C32(0xd795ba31) }, + { SPH_C32(0xf7750009), SPH_C32(0xcf3cc000), SPH_C32(0xc3d60000), + SPH_C32(0x04920000), SPH_C32(0x029519a9), SPH_C32(0xf8e836ba), + SPH_C32(0x7a87f14e), SPH_C32(0x9e16981a), SPH_C32(0xd46a0000), + SPH_C32(0x8dc8c000), SPH_C32(0xa5af0000), SPH_C32(0x4a290000), + SPH_C32(0xfc4e427a), SPH_C32(0xc9b4866c), SPH_C32(0x98369604), + SPH_C32(0xf746c320) }, + { SPH_C32(0x01f5000c), SPH_C32(0xfb7f0000), SPH_C32(0xe7d10000), + SPH_C32(0x8baf0000), SPH_C32(0x23a22252), SPH_C32(0xf250e314), + SPH_C32(0xb7427a57), SPH_C32(0x4983222b), SPH_C32(0x72150001), + SPH_C32(0xfcff4000), SPH_C32(0xbc530000), SPH_C32(0xdcf20000), + SPH_C32(0xc6c52f87), SPH_C32(0x227e289f), SPH_C32(0xb45bd18b), + SPH_C32(0x5bc8afa8) }, + { SPH_C32(0x510a0008), SPH_C32(0xbe0b4000), SPH_C32(0xda2a0000), + SPH_C32(0x92490000), SPH_C32(0x381e7454), SPH_C32(0x13229849), + SPH_C32(0x56eab6c1), SPH_C32(0x3298f492), SPH_C32(0x84950004), + SPH_C32(0xc8bc8000), SPH_C32(0x98540000), SPH_C32(0x53cf0000), + SPH_C32(0xe7f2147c), SPH_C32(0x28c6fd31), SPH_C32(0x799e5a92), + SPH_C32(0x8c5d1599) }, + { SPH_C32(0xa78a000d), SPH_C32(0x8a488000), SPH_C32(0xfe2d0000), + SPH_C32(0x1d740000), SPH_C32(0x19294faf), SPH_C32(0x199a4de7), + SPH_C32(0x9b2f3dd8), SPH_C32(0xe50d4ea3), SPH_C32(0x22ea0005), + SPH_C32(0xb98b0000), SPH_C32(0x81a80000), SPH_C32(0xc5140000), + SPH_C32(0xdd797981), SPH_C32(0xc30c53c2), SPH_C32(0x55f31d1d), + SPH_C32(0x20d37911) }, + { SPH_C32(0xd46a0000), SPH_C32(0x8dc8c000), SPH_C32(0xa5af0000), + SPH_C32(0x4a290000), SPH_C32(0xfc4e427a), SPH_C32(0xc9b4866c), + SPH_C32(0x98369604), SPH_C32(0xf746c320), SPH_C32(0x231f0009), + SPH_C32(0x42f40000), SPH_C32(0x66790000), SPH_C32(0x4ebb0000), + SPH_C32(0xfedb5bd3), SPH_C32(0x315cb0d6), SPH_C32(0xe2b1674a), + SPH_C32(0x69505b3a) }, + { SPH_C32(0x22ea0005), SPH_C32(0xb98b0000), SPH_C32(0x81a80000), + SPH_C32(0xc5140000), SPH_C32(0xdd797981), SPH_C32(0xc30c53c2), + SPH_C32(0x55f31d1d), SPH_C32(0x20d37911), SPH_C32(0x85600008), + SPH_C32(0x33c38000), SPH_C32(0x7f850000), SPH_C32(0xd8600000), + SPH_C32(0xc450362e), SPH_C32(0xda961e25), SPH_C32(0xcedc20c5), + SPH_C32(0xc5de37b2) }, + { SPH_C32(0x72150001), SPH_C32(0xfcff4000), SPH_C32(0xbc530000), + SPH_C32(0xdcf20000), SPH_C32(0xc6c52f87), SPH_C32(0x227e289f), + SPH_C32(0xb45bd18b), SPH_C32(0x5bc8afa8), SPH_C32(0x73e0000d), + SPH_C32(0x07804000), SPH_C32(0x5b820000), SPH_C32(0x575d0000), + SPH_C32(0xe5670dd5), SPH_C32(0xd02ecb8b), SPH_C32(0x0319abdc), + SPH_C32(0x124b8d83) }, + { SPH_C32(0x84950004), SPH_C32(0xc8bc8000), SPH_C32(0x98540000), + SPH_C32(0x53cf0000), SPH_C32(0xe7f2147c), SPH_C32(0x28c6fd31), + SPH_C32(0x799e5a92), SPH_C32(0x8c5d1599), SPH_C32(0xd59f000c), + SPH_C32(0x76b7c000), SPH_C32(0x427e0000), SPH_C32(0xc1860000), + SPH_C32(0xdfec6028), SPH_C32(0x3be46578), SPH_C32(0x2f74ec53), + SPH_C32(0xbec5e10b) }, + { SPH_C32(0x231f0009), SPH_C32(0x42f40000), SPH_C32(0x66790000), + SPH_C32(0x4ebb0000), SPH_C32(0xfedb5bd3), SPH_C32(0x315cb0d6), + SPH_C32(0xe2b1674a), SPH_C32(0x69505b3a), SPH_C32(0xf7750009), + SPH_C32(0xcf3cc000), SPH_C32(0xc3d60000), SPH_C32(0x04920000), + SPH_C32(0x029519a9), SPH_C32(0xf8e836ba), SPH_C32(0x7a87f14e), + SPH_C32(0x9e16981a) }, + { SPH_C32(0xd59f000c), SPH_C32(0x76b7c000), SPH_C32(0x427e0000), + SPH_C32(0xc1860000), SPH_C32(0xdfec6028), SPH_C32(0x3be46578), + SPH_C32(0x2f74ec53), SPH_C32(0xbec5e10b), SPH_C32(0x510a0008), + SPH_C32(0xbe0b4000), SPH_C32(0xda2a0000), SPH_C32(0x92490000), + SPH_C32(0x381e7454), SPH_C32(0x13229849), SPH_C32(0x56eab6c1), + SPH_C32(0x3298f492) }, + { SPH_C32(0x85600008), SPH_C32(0x33c38000), SPH_C32(0x7f850000), + SPH_C32(0xd8600000), SPH_C32(0xc450362e), SPH_C32(0xda961e25), + SPH_C32(0xcedc20c5), SPH_C32(0xc5de37b2), SPH_C32(0xa78a000d), + SPH_C32(0x8a488000), SPH_C32(0xfe2d0000), SPH_C32(0x1d740000), + SPH_C32(0x19294faf), SPH_C32(0x199a4de7), SPH_C32(0x9b2f3dd8), + SPH_C32(0xe50d4ea3) }, + { SPH_C32(0x73e0000d), SPH_C32(0x07804000), SPH_C32(0x5b820000), + SPH_C32(0x575d0000), SPH_C32(0xe5670dd5), SPH_C32(0xd02ecb8b), + SPH_C32(0x0319abdc), SPH_C32(0x124b8d83), SPH_C32(0x01f5000c), + SPH_C32(0xfb7f0000), SPH_C32(0xe7d10000), SPH_C32(0x8baf0000), + SPH_C32(0x23a22252), SPH_C32(0xf250e314), SPH_C32(0xb7427a57), + SPH_C32(0x4983222b) }, + { SPH_C32(0x774400f0), SPH_C32(0xf15a0000), SPH_C32(0xf5b20000), + SPH_C32(0x34140000), SPH_C32(0x89377e8c), SPH_C32(0x5a8bec25), + SPH_C32(0x0bc3cd1e), SPH_C32(0xcf3775cb), SPH_C32(0xf46c0050), + SPH_C32(0x96180000), SPH_C32(0x14a50000), SPH_C32(0x031f0000), + SPH_C32(0x42947eb8), SPH_C32(0x66bf7e19), SPH_C32(0x9ca470d2), + SPH_C32(0x8a341574) }, + { SPH_C32(0x81c400f5), SPH_C32(0xc519c000), SPH_C32(0xd1b50000), + SPH_C32(0xbb290000), SPH_C32(0xa8004577), SPH_C32(0x5033398b), + SPH_C32(0xc6064607), SPH_C32(0x18a2cffa), SPH_C32(0x52130051), + SPH_C32(0xe72f8000), SPH_C32(0x0d590000), SPH_C32(0x95c40000), + SPH_C32(0x781f1345), SPH_C32(0x8d75d0ea), SPH_C32(0xb0c9375d), + SPH_C32(0x26ba79fc) }, + { SPH_C32(0xd13b00f1), SPH_C32(0x806d8000), SPH_C32(0xec4e0000), + SPH_C32(0xa2cf0000), SPH_C32(0xb3bc1371), SPH_C32(0xb14142d6), + SPH_C32(0x27ae8a91), SPH_C32(0x63b91943), SPH_C32(0xa4930054), + SPH_C32(0xd36c4000), SPH_C32(0x295e0000), SPH_C32(0x1af90000), + SPH_C32(0x592828be), SPH_C32(0x87cd0544), SPH_C32(0x7d0cbc44), + SPH_C32(0xf12fc3cd) }, + { SPH_C32(0x27bb00f4), SPH_C32(0xb42e4000), SPH_C32(0xc8490000), + SPH_C32(0x2df20000), SPH_C32(0x928b288a), SPH_C32(0xbbf99778), + SPH_C32(0xea6b0188), SPH_C32(0xb42ca372), SPH_C32(0x02ec0055), + SPH_C32(0xa25bc000), SPH_C32(0x30a20000), SPH_C32(0x8c220000), + SPH_C32(0x63a34543), SPH_C32(0x6c07abb7), SPH_C32(0x5161fbcb), + SPH_C32(0x5da1af45) }, + { SPH_C32(0x803100f9), SPH_C32(0x3e66c000), SPH_C32(0x36640000), + SPH_C32(0x30860000), SPH_C32(0x8ba26725), SPH_C32(0xa263da9f), + SPH_C32(0x71443c50), SPH_C32(0x5121edd1), SPH_C32(0x20060050), + SPH_C32(0x1bd0c000), SPH_C32(0xb10a0000), SPH_C32(0x49360000), + SPH_C32(0xbeda3cc2), SPH_C32(0xaf0bf875), SPH_C32(0x0492e6d6), + SPH_C32(0x7d72d654) }, + { SPH_C32(0x76b100fc), SPH_C32(0x0a250000), SPH_C32(0x12630000), + SPH_C32(0xbfbb0000), SPH_C32(0xaa955cde), SPH_C32(0xa8db0f31), + SPH_C32(0xbc81b749), SPH_C32(0x86b457e0), SPH_C32(0x86790051), + SPH_C32(0x6ae74000), SPH_C32(0xa8f60000), SPH_C32(0xdfed0000), + SPH_C32(0x8451513f), SPH_C32(0x44c15686), SPH_C32(0x28ffa159), + SPH_C32(0xd1fcbadc) }, + { SPH_C32(0x264e00f8), SPH_C32(0x4f514000), SPH_C32(0x2f980000), + SPH_C32(0xa65d0000), SPH_C32(0xb1290ad8), SPH_C32(0x49a9746c), + SPH_C32(0x5d297bdf), SPH_C32(0xfdaf8159), SPH_C32(0x70f90054), + SPH_C32(0x5ea48000), SPH_C32(0x8cf10000), SPH_C32(0x50d00000), + SPH_C32(0xa5666ac4), SPH_C32(0x4e798328), SPH_C32(0xe53a2a40), + SPH_C32(0x066900ed) }, + { SPH_C32(0xd0ce00fd), SPH_C32(0x7b128000), SPH_C32(0x0b9f0000), + SPH_C32(0x29600000), SPH_C32(0x901e3123), SPH_C32(0x4311a1c2), + SPH_C32(0x90ecf0c6), SPH_C32(0x2a3a3b68), SPH_C32(0xd6860055), + SPH_C32(0x2f930000), SPH_C32(0x950d0000), SPH_C32(0xc60b0000), + SPH_C32(0x9fed0739), SPH_C32(0xa5b32ddb), SPH_C32(0xc9576dcf), + SPH_C32(0xaae76c65) }, + { SPH_C32(0xa32e00f0), SPH_C32(0x7c92c000), SPH_C32(0x501d0000), + SPH_C32(0x7e3d0000), SPH_C32(0x75793cf6), SPH_C32(0x933f6a49), + SPH_C32(0x93f55b1a), SPH_C32(0x3871b6eb), SPH_C32(0xd7730059), + SPH_C32(0xd4ec0000), SPH_C32(0x72dc0000), SPH_C32(0x4da40000), + SPH_C32(0xbc4f256b), SPH_C32(0x57e3cecf), SPH_C32(0x7e151798), + SPH_C32(0xe3644e4e) }, + { SPH_C32(0x55ae00f5), SPH_C32(0x48d10000), SPH_C32(0x741a0000), + SPH_C32(0xf1000000), SPH_C32(0x544e070d), SPH_C32(0x9987bfe7), + SPH_C32(0x5e30d003), SPH_C32(0xefe40cda), SPH_C32(0x710c0058), + SPH_C32(0xa5db8000), SPH_C32(0x6b200000), SPH_C32(0xdb7f0000), + SPH_C32(0x86c44896), SPH_C32(0xbc29603c), SPH_C32(0x52785017), + SPH_C32(0x4fea22c6) }, + { SPH_C32(0x055100f1), SPH_C32(0x0da54000), SPH_C32(0x49e10000), + SPH_C32(0xe8e60000), SPH_C32(0x4ff2510b), SPH_C32(0x78f5c4ba), + SPH_C32(0xbf981c95), SPH_C32(0x94ffda63), SPH_C32(0x878c005d), + SPH_C32(0x91984000), SPH_C32(0x4f270000), SPH_C32(0x54420000), + SPH_C32(0xa7f3736d), SPH_C32(0xb691b592), SPH_C32(0x9fbddb0e), + SPH_C32(0x987f98f7) }, + { SPH_C32(0xf3d100f4), SPH_C32(0x39e68000), SPH_C32(0x6de60000), + SPH_C32(0x67db0000), SPH_C32(0x6ec56af0), SPH_C32(0x724d1114), + SPH_C32(0x725d978c), SPH_C32(0x436a6052), SPH_C32(0x21f3005c), + SPH_C32(0xe0afc000), SPH_C32(0x56db0000), SPH_C32(0xc2990000), + SPH_C32(0x9d781e90), SPH_C32(0x5d5b1b61), SPH_C32(0xb3d09c81), + SPH_C32(0x34f1f47f) }, + { SPH_C32(0x545b00f9), SPH_C32(0xb3ae0000), SPH_C32(0x93cb0000), + SPH_C32(0x7aaf0000), SPH_C32(0x77ec255f), SPH_C32(0x6bd75cf3), + SPH_C32(0xe972aa54), SPH_C32(0xa6672ef1), SPH_C32(0x03190059), + SPH_C32(0x5924c000), SPH_C32(0xd7730000), SPH_C32(0x078d0000), + SPH_C32(0x40016711), SPH_C32(0x9e5748a3), SPH_C32(0xe623819c), + SPH_C32(0x14228d6e) }, + { SPH_C32(0xa2db00fc), SPH_C32(0x87edc000), SPH_C32(0xb7cc0000), + SPH_C32(0xf5920000), SPH_C32(0x56db1ea4), SPH_C32(0x616f895d), + SPH_C32(0x24b7214d), SPH_C32(0x71f294c0), SPH_C32(0xa5660058), + SPH_C32(0x28134000), SPH_C32(0xce8f0000), SPH_C32(0x91560000), + SPH_C32(0x7a8a0aec), SPH_C32(0x759de650), SPH_C32(0xca4ec613), + SPH_C32(0xb8ace1e6) }, + { SPH_C32(0xf22400f8), SPH_C32(0xc2998000), SPH_C32(0x8a370000), + SPH_C32(0xec740000), SPH_C32(0x4d6748a2), SPH_C32(0x801df200), + SPH_C32(0xc51feddb), SPH_C32(0x0ae94279), SPH_C32(0x53e6005d), + SPH_C32(0x1c508000), SPH_C32(0xea880000), SPH_C32(0x1e6b0000), + SPH_C32(0x5bbd3117), SPH_C32(0x7f2533fe), SPH_C32(0x078b4d0a), + SPH_C32(0x6f395bd7) }, + { SPH_C32(0x04a400fd), SPH_C32(0xf6da4000), SPH_C32(0xae300000), + SPH_C32(0x63490000), SPH_C32(0x6c507359), SPH_C32(0x8aa527ae), + SPH_C32(0x08da66c2), SPH_C32(0xdd7cf848), SPH_C32(0xf599005c), + SPH_C32(0x6d670000), SPH_C32(0xf3740000), SPH_C32(0x88b00000), + SPH_C32(0x61365cea), SPH_C32(0x94ef9d0d), SPH_C32(0x2be60a85), + SPH_C32(0xc3b7375f) }, + { SPH_C32(0xf46c0050), SPH_C32(0x96180000), SPH_C32(0x14a50000), + SPH_C32(0x031f0000), SPH_C32(0x42947eb8), SPH_C32(0x66bf7e19), + SPH_C32(0x9ca470d2), SPH_C32(0x8a341574), SPH_C32(0x832800a0), + SPH_C32(0x67420000), SPH_C32(0xe1170000), SPH_C32(0x370b0000), + SPH_C32(0xcba30034), SPH_C32(0x3c34923c), SPH_C32(0x9767bdcc), + SPH_C32(0x450360bf) }, + { SPH_C32(0x02ec0055), SPH_C32(0xa25bc000), SPH_C32(0x30a20000), + SPH_C32(0x8c220000), SPH_C32(0x63a34543), SPH_C32(0x6c07abb7), + SPH_C32(0x5161fbcb), SPH_C32(0x5da1af45), SPH_C32(0x255700a1), + SPH_C32(0x16758000), SPH_C32(0xf8eb0000), SPH_C32(0xa1d00000), + SPH_C32(0xf1286dc9), SPH_C32(0xd7fe3ccf), SPH_C32(0xbb0afa43), + SPH_C32(0xe98d0c37) }, + { SPH_C32(0x52130051), SPH_C32(0xe72f8000), SPH_C32(0x0d590000), + SPH_C32(0x95c40000), SPH_C32(0x781f1345), SPH_C32(0x8d75d0ea), + SPH_C32(0xb0c9375d), SPH_C32(0x26ba79fc), SPH_C32(0xd3d700a4), + SPH_C32(0x22364000), SPH_C32(0xdcec0000), SPH_C32(0x2eed0000), + SPH_C32(0xd01f5632), SPH_C32(0xdd46e961), SPH_C32(0x76cf715a), + SPH_C32(0x3e18b606) }, + { SPH_C32(0xa4930054), SPH_C32(0xd36c4000), SPH_C32(0x295e0000), + SPH_C32(0x1af90000), SPH_C32(0x592828be), SPH_C32(0x87cd0544), + SPH_C32(0x7d0cbc44), SPH_C32(0xf12fc3cd), SPH_C32(0x75a800a5), + SPH_C32(0x5301c000), SPH_C32(0xc5100000), SPH_C32(0xb8360000), + SPH_C32(0xea943bcf), SPH_C32(0x368c4792), SPH_C32(0x5aa236d5), + SPH_C32(0x9296da8e) }, + { SPH_C32(0x03190059), SPH_C32(0x5924c000), SPH_C32(0xd7730000), + SPH_C32(0x078d0000), SPH_C32(0x40016711), SPH_C32(0x9e5748a3), + SPH_C32(0xe623819c), SPH_C32(0x14228d6e), SPH_C32(0x574200a0), + SPH_C32(0xea8ac000), SPH_C32(0x44b80000), SPH_C32(0x7d220000), + SPH_C32(0x37ed424e), SPH_C32(0xf5801450), SPH_C32(0x0f512bc8), + SPH_C32(0xb245a39f) }, + { SPH_C32(0xf599005c), SPH_C32(0x6d670000), SPH_C32(0xf3740000), + SPH_C32(0x88b00000), SPH_C32(0x61365cea), SPH_C32(0x94ef9d0d), + SPH_C32(0x2be60a85), SPH_C32(0xc3b7375f), SPH_C32(0xf13d00a1), + SPH_C32(0x9bbd4000), SPH_C32(0x5d440000), SPH_C32(0xebf90000), + SPH_C32(0x0d662fb3), SPH_C32(0x1e4abaa3), SPH_C32(0x233c6c47), + SPH_C32(0x1ecbcf17) }, + { SPH_C32(0xa5660058), SPH_C32(0x28134000), SPH_C32(0xce8f0000), + SPH_C32(0x91560000), SPH_C32(0x7a8a0aec), SPH_C32(0x759de650), + SPH_C32(0xca4ec613), SPH_C32(0xb8ace1e6), SPH_C32(0x07bd00a4), + SPH_C32(0xaffe8000), SPH_C32(0x79430000), SPH_C32(0x64c40000), + SPH_C32(0x2c511448), SPH_C32(0x14f26f0d), SPH_C32(0xeef9e75e), + SPH_C32(0xc95e7526) }, + { SPH_C32(0x53e6005d), SPH_C32(0x1c508000), SPH_C32(0xea880000), + SPH_C32(0x1e6b0000), SPH_C32(0x5bbd3117), SPH_C32(0x7f2533fe), + SPH_C32(0x078b4d0a), SPH_C32(0x6f395bd7), SPH_C32(0xa1c200a5), + SPH_C32(0xdec90000), SPH_C32(0x60bf0000), SPH_C32(0xf21f0000), + SPH_C32(0x16da79b5), SPH_C32(0xff38c1fe), SPH_C32(0xc294a0d1), + SPH_C32(0x65d019ae) }, + { SPH_C32(0x20060050), SPH_C32(0x1bd0c000), SPH_C32(0xb10a0000), + SPH_C32(0x49360000), SPH_C32(0xbeda3cc2), SPH_C32(0xaf0bf875), + SPH_C32(0x0492e6d6), SPH_C32(0x7d72d654), SPH_C32(0xa03700a9), + SPH_C32(0x25b60000), SPH_C32(0x876e0000), SPH_C32(0x79b00000), + SPH_C32(0x35785be7), SPH_C32(0x0d6822ea), SPH_C32(0x75d6da86), + SPH_C32(0x2c533b85) }, + { SPH_C32(0xd6860055), SPH_C32(0x2f930000), SPH_C32(0x950d0000), + SPH_C32(0xc60b0000), SPH_C32(0x9fed0739), SPH_C32(0xa5b32ddb), + SPH_C32(0xc9576dcf), SPH_C32(0xaae76c65), SPH_C32(0x064800a8), + SPH_C32(0x54818000), SPH_C32(0x9e920000), SPH_C32(0xef6b0000), + SPH_C32(0x0ff3361a), SPH_C32(0xe6a28c19), SPH_C32(0x59bb9d09), + SPH_C32(0x80dd570d) }, + { SPH_C32(0x86790051), SPH_C32(0x6ae74000), SPH_C32(0xa8f60000), + SPH_C32(0xdfed0000), SPH_C32(0x8451513f), SPH_C32(0x44c15686), + SPH_C32(0x28ffa159), SPH_C32(0xd1fcbadc), SPH_C32(0xf0c800ad), + SPH_C32(0x60c24000), SPH_C32(0xba950000), SPH_C32(0x60560000), + SPH_C32(0x2ec40de1), SPH_C32(0xec1a59b7), SPH_C32(0x947e1610), + SPH_C32(0x5748ed3c) }, + { SPH_C32(0x70f90054), SPH_C32(0x5ea48000), SPH_C32(0x8cf10000), + SPH_C32(0x50d00000), SPH_C32(0xa5666ac4), SPH_C32(0x4e798328), + SPH_C32(0xe53a2a40), SPH_C32(0x066900ed), SPH_C32(0x56b700ac), + SPH_C32(0x11f5c000), SPH_C32(0xa3690000), SPH_C32(0xf68d0000), + SPH_C32(0x144f601c), SPH_C32(0x07d0f744), SPH_C32(0xb813519f), + SPH_C32(0xfbc681b4) }, + { SPH_C32(0xd7730059), SPH_C32(0xd4ec0000), SPH_C32(0x72dc0000), + SPH_C32(0x4da40000), SPH_C32(0xbc4f256b), SPH_C32(0x57e3cecf), + SPH_C32(0x7e151798), SPH_C32(0xe3644e4e), SPH_C32(0x745d00a9), + SPH_C32(0xa87ec000), SPH_C32(0x22c10000), SPH_C32(0x33990000), + SPH_C32(0xc936199d), SPH_C32(0xc4dca486), SPH_C32(0xede04c82), + SPH_C32(0xdb15f8a5) }, + { SPH_C32(0x21f3005c), SPH_C32(0xe0afc000), SPH_C32(0x56db0000), + SPH_C32(0xc2990000), SPH_C32(0x9d781e90), SPH_C32(0x5d5b1b61), + SPH_C32(0xb3d09c81), SPH_C32(0x34f1f47f), SPH_C32(0xd22200a8), + SPH_C32(0xd9494000), SPH_C32(0x3b3d0000), SPH_C32(0xa5420000), + SPH_C32(0xf3bd7460), SPH_C32(0x2f160a75), SPH_C32(0xc18d0b0d), + SPH_C32(0x779b942d) }, + { SPH_C32(0x710c0058), SPH_C32(0xa5db8000), SPH_C32(0x6b200000), + SPH_C32(0xdb7f0000), SPH_C32(0x86c44896), SPH_C32(0xbc29603c), + SPH_C32(0x52785017), SPH_C32(0x4fea22c6), SPH_C32(0x24a200ad), + SPH_C32(0xed0a8000), SPH_C32(0x1f3a0000), SPH_C32(0x2a7f0000), + SPH_C32(0xd28a4f9b), SPH_C32(0x25aedfdb), SPH_C32(0x0c488014), + SPH_C32(0xa00e2e1c) }, + { SPH_C32(0x878c005d), SPH_C32(0x91984000), SPH_C32(0x4f270000), + SPH_C32(0x54420000), SPH_C32(0xa7f3736d), SPH_C32(0xb691b592), + SPH_C32(0x9fbddb0e), SPH_C32(0x987f98f7), SPH_C32(0x82dd00ac), + SPH_C32(0x9c3d0000), SPH_C32(0x06c60000), SPH_C32(0xbca40000), + SPH_C32(0xe8012266), SPH_C32(0xce647128), SPH_C32(0x2025c79b), + SPH_C32(0x0c804294) }, + { SPH_C32(0x832800a0), SPH_C32(0x67420000), SPH_C32(0xe1170000), + SPH_C32(0x370b0000), SPH_C32(0xcba30034), SPH_C32(0x3c34923c), + SPH_C32(0x9767bdcc), SPH_C32(0x450360bf), SPH_C32(0x774400f0), + SPH_C32(0xf15a0000), SPH_C32(0xf5b20000), SPH_C32(0x34140000), + SPH_C32(0x89377e8c), SPH_C32(0x5a8bec25), SPH_C32(0x0bc3cd1e), + SPH_C32(0xcf3775cb) }, + { SPH_C32(0x75a800a5), SPH_C32(0x5301c000), SPH_C32(0xc5100000), + SPH_C32(0xb8360000), SPH_C32(0xea943bcf), SPH_C32(0x368c4792), + SPH_C32(0x5aa236d5), SPH_C32(0x9296da8e), SPH_C32(0xd13b00f1), + SPH_C32(0x806d8000), SPH_C32(0xec4e0000), SPH_C32(0xa2cf0000), + SPH_C32(0xb3bc1371), SPH_C32(0xb14142d6), SPH_C32(0x27ae8a91), + SPH_C32(0x63b91943) }, + { SPH_C32(0x255700a1), SPH_C32(0x16758000), SPH_C32(0xf8eb0000), + SPH_C32(0xa1d00000), SPH_C32(0xf1286dc9), SPH_C32(0xd7fe3ccf), + SPH_C32(0xbb0afa43), SPH_C32(0xe98d0c37), SPH_C32(0x27bb00f4), + SPH_C32(0xb42e4000), SPH_C32(0xc8490000), SPH_C32(0x2df20000), + SPH_C32(0x928b288a), SPH_C32(0xbbf99778), SPH_C32(0xea6b0188), + SPH_C32(0xb42ca372) }, + { SPH_C32(0xd3d700a4), SPH_C32(0x22364000), SPH_C32(0xdcec0000), + SPH_C32(0x2eed0000), SPH_C32(0xd01f5632), SPH_C32(0xdd46e961), + SPH_C32(0x76cf715a), SPH_C32(0x3e18b606), SPH_C32(0x81c400f5), + SPH_C32(0xc519c000), SPH_C32(0xd1b50000), SPH_C32(0xbb290000), + SPH_C32(0xa8004577), SPH_C32(0x5033398b), SPH_C32(0xc6064607), + SPH_C32(0x18a2cffa) }, + { SPH_C32(0x745d00a9), SPH_C32(0xa87ec000), SPH_C32(0x22c10000), + SPH_C32(0x33990000), SPH_C32(0xc936199d), SPH_C32(0xc4dca486), + SPH_C32(0xede04c82), SPH_C32(0xdb15f8a5), SPH_C32(0xa32e00f0), + SPH_C32(0x7c92c000), SPH_C32(0x501d0000), SPH_C32(0x7e3d0000), + SPH_C32(0x75793cf6), SPH_C32(0x933f6a49), SPH_C32(0x93f55b1a), + SPH_C32(0x3871b6eb) }, + { SPH_C32(0x82dd00ac), SPH_C32(0x9c3d0000), SPH_C32(0x06c60000), + SPH_C32(0xbca40000), SPH_C32(0xe8012266), SPH_C32(0xce647128), + SPH_C32(0x2025c79b), SPH_C32(0x0c804294), SPH_C32(0x055100f1), + SPH_C32(0x0da54000), SPH_C32(0x49e10000), SPH_C32(0xe8e60000), + SPH_C32(0x4ff2510b), SPH_C32(0x78f5c4ba), SPH_C32(0xbf981c95), + SPH_C32(0x94ffda63) }, + { SPH_C32(0xd22200a8), SPH_C32(0xd9494000), SPH_C32(0x3b3d0000), + SPH_C32(0xa5420000), SPH_C32(0xf3bd7460), SPH_C32(0x2f160a75), + SPH_C32(0xc18d0b0d), SPH_C32(0x779b942d), SPH_C32(0xf3d100f4), + SPH_C32(0x39e68000), SPH_C32(0x6de60000), SPH_C32(0x67db0000), + SPH_C32(0x6ec56af0), SPH_C32(0x724d1114), SPH_C32(0x725d978c), + SPH_C32(0x436a6052) }, + { SPH_C32(0x24a200ad), SPH_C32(0xed0a8000), SPH_C32(0x1f3a0000), + SPH_C32(0x2a7f0000), SPH_C32(0xd28a4f9b), SPH_C32(0x25aedfdb), + SPH_C32(0x0c488014), SPH_C32(0xa00e2e1c), SPH_C32(0x55ae00f5), + SPH_C32(0x48d10000), SPH_C32(0x741a0000), SPH_C32(0xf1000000), + SPH_C32(0x544e070d), SPH_C32(0x9987bfe7), SPH_C32(0x5e30d003), + SPH_C32(0xefe40cda) }, + { SPH_C32(0x574200a0), SPH_C32(0xea8ac000), SPH_C32(0x44b80000), + SPH_C32(0x7d220000), SPH_C32(0x37ed424e), SPH_C32(0xf5801450), + SPH_C32(0x0f512bc8), SPH_C32(0xb245a39f), SPH_C32(0x545b00f9), + SPH_C32(0xb3ae0000), SPH_C32(0x93cb0000), SPH_C32(0x7aaf0000), + SPH_C32(0x77ec255f), SPH_C32(0x6bd75cf3), SPH_C32(0xe972aa54), + SPH_C32(0xa6672ef1) }, + { SPH_C32(0xa1c200a5), SPH_C32(0xdec90000), SPH_C32(0x60bf0000), + SPH_C32(0xf21f0000), SPH_C32(0x16da79b5), SPH_C32(0xff38c1fe), + SPH_C32(0xc294a0d1), SPH_C32(0x65d019ae), SPH_C32(0xf22400f8), + SPH_C32(0xc2998000), SPH_C32(0x8a370000), SPH_C32(0xec740000), + SPH_C32(0x4d6748a2), SPH_C32(0x801df200), SPH_C32(0xc51feddb), + SPH_C32(0x0ae94279) }, + { SPH_C32(0xf13d00a1), SPH_C32(0x9bbd4000), SPH_C32(0x5d440000), + SPH_C32(0xebf90000), SPH_C32(0x0d662fb3), SPH_C32(0x1e4abaa3), + SPH_C32(0x233c6c47), SPH_C32(0x1ecbcf17), SPH_C32(0x04a400fd), + SPH_C32(0xf6da4000), SPH_C32(0xae300000), SPH_C32(0x63490000), + SPH_C32(0x6c507359), SPH_C32(0x8aa527ae), SPH_C32(0x08da66c2), + SPH_C32(0xdd7cf848) }, + { SPH_C32(0x07bd00a4), SPH_C32(0xaffe8000), SPH_C32(0x79430000), + SPH_C32(0x64c40000), SPH_C32(0x2c511448), SPH_C32(0x14f26f0d), + SPH_C32(0xeef9e75e), SPH_C32(0xc95e7526), SPH_C32(0xa2db00fc), + SPH_C32(0x87edc000), SPH_C32(0xb7cc0000), SPH_C32(0xf5920000), + SPH_C32(0x56db1ea4), SPH_C32(0x616f895d), SPH_C32(0x24b7214d), + SPH_C32(0x71f294c0) }, + { SPH_C32(0xa03700a9), SPH_C32(0x25b60000), SPH_C32(0x876e0000), + SPH_C32(0x79b00000), SPH_C32(0x35785be7), SPH_C32(0x0d6822ea), + SPH_C32(0x75d6da86), SPH_C32(0x2c533b85), SPH_C32(0x803100f9), + SPH_C32(0x3e66c000), SPH_C32(0x36640000), SPH_C32(0x30860000), + SPH_C32(0x8ba26725), SPH_C32(0xa263da9f), SPH_C32(0x71443c50), + SPH_C32(0x5121edd1) }, + { SPH_C32(0x56b700ac), SPH_C32(0x11f5c000), SPH_C32(0xa3690000), + SPH_C32(0xf68d0000), SPH_C32(0x144f601c), SPH_C32(0x07d0f744), + SPH_C32(0xb813519f), SPH_C32(0xfbc681b4), SPH_C32(0x264e00f8), + SPH_C32(0x4f514000), SPH_C32(0x2f980000), SPH_C32(0xa65d0000), + SPH_C32(0xb1290ad8), SPH_C32(0x49a9746c), SPH_C32(0x5d297bdf), + SPH_C32(0xfdaf8159) }, + { SPH_C32(0x064800a8), SPH_C32(0x54818000), SPH_C32(0x9e920000), + SPH_C32(0xef6b0000), SPH_C32(0x0ff3361a), SPH_C32(0xe6a28c19), + SPH_C32(0x59bb9d09), SPH_C32(0x80dd570d), SPH_C32(0xd0ce00fd), + SPH_C32(0x7b128000), SPH_C32(0x0b9f0000), SPH_C32(0x29600000), + SPH_C32(0x901e3123), SPH_C32(0x4311a1c2), SPH_C32(0x90ecf0c6), + SPH_C32(0x2a3a3b68) }, + { SPH_C32(0xf0c800ad), SPH_C32(0x60c24000), SPH_C32(0xba950000), + SPH_C32(0x60560000), SPH_C32(0x2ec40de1), SPH_C32(0xec1a59b7), + SPH_C32(0x947e1610), SPH_C32(0x5748ed3c), SPH_C32(0x76b100fc), + SPH_C32(0x0a250000), SPH_C32(0x12630000), SPH_C32(0xbfbb0000), + SPH_C32(0xaa955cde), SPH_C32(0xa8db0f31), SPH_C32(0xbc81b749), + SPH_C32(0x86b457e0) }, + { SPH_C32(0xe8870170), SPH_C32(0x9d720000), SPH_C32(0x12db0000), + SPH_C32(0xd4220000), SPH_C32(0xf2886b27), SPH_C32(0xa921e543), + SPH_C32(0x4ef8b518), SPH_C32(0x618813b1), SPH_C32(0xb4370060), + SPH_C32(0x0c4c0000), SPH_C32(0x56c20000), SPH_C32(0x5cae0000), + SPH_C32(0x94541f3f), SPH_C32(0x3b3ef825), SPH_C32(0x1b365f3d), + SPH_C32(0xf3d45758) }, + { SPH_C32(0x1e070175), SPH_C32(0xa931c000), SPH_C32(0x36dc0000), + SPH_C32(0x5b1f0000), SPH_C32(0xd3bf50dc), SPH_C32(0xa39930ed), + SPH_C32(0x833d3e01), SPH_C32(0xb61da980), SPH_C32(0x12480061), + SPH_C32(0x7d7b8000), SPH_C32(0x4f3e0000), SPH_C32(0xca750000), + SPH_C32(0xaedf72c2), SPH_C32(0xd0f456d6), SPH_C32(0x375b18b2), + SPH_C32(0x5f5a3bd0) }, + { SPH_C32(0x4ef80171), SPH_C32(0xec458000), SPH_C32(0x0b270000), + SPH_C32(0x42f90000), SPH_C32(0xc80306da), SPH_C32(0x42eb4bb0), + SPH_C32(0x6295f297), SPH_C32(0xcd067f39), SPH_C32(0xe4c80064), + SPH_C32(0x49384000), SPH_C32(0x6b390000), SPH_C32(0x45480000), + SPH_C32(0x8fe84939), SPH_C32(0xda4c8378), SPH_C32(0xfa9e93ab), + SPH_C32(0x88cf81e1) }, + { SPH_C32(0xb8780174), SPH_C32(0xd8064000), SPH_C32(0x2f200000), + SPH_C32(0xcdc40000), SPH_C32(0xe9343d21), SPH_C32(0x48539e1e), + SPH_C32(0xaf50798e), SPH_C32(0x1a93c508), SPH_C32(0x42b70065), + SPH_C32(0x380fc000), SPH_C32(0x72c50000), SPH_C32(0xd3930000), + SPH_C32(0xb56324c4), SPH_C32(0x31862d8b), SPH_C32(0xd6f3d424), + SPH_C32(0x2441ed69) }, + { SPH_C32(0x1ff20179), SPH_C32(0x524ec000), SPH_C32(0xd10d0000), + SPH_C32(0xd0b00000), SPH_C32(0xf01d728e), SPH_C32(0x51c9d3f9), + SPH_C32(0x347f4456), SPH_C32(0xff9e8bab), SPH_C32(0x605d0060), + SPH_C32(0x8184c000), SPH_C32(0xf36d0000), SPH_C32(0x16870000), + SPH_C32(0x681a5d45), SPH_C32(0xf28a7e49), SPH_C32(0x8300c939), + SPH_C32(0x04929478) }, + { SPH_C32(0xe972017c), SPH_C32(0x660d0000), SPH_C32(0xf50a0000), + SPH_C32(0x5f8d0000), SPH_C32(0xd12a4975), SPH_C32(0x5b710657), + SPH_C32(0xf9bacf4f), SPH_C32(0x280b319a), SPH_C32(0xc6220061), + SPH_C32(0xf0b34000), SPH_C32(0xea910000), SPH_C32(0x805c0000), + SPH_C32(0x529130b8), SPH_C32(0x1940d0ba), SPH_C32(0xaf6d8eb6), + SPH_C32(0xa81cf8f0) }, + { SPH_C32(0xb98d0178), SPH_C32(0x23794000), SPH_C32(0xc8f10000), + SPH_C32(0x466b0000), SPH_C32(0xca961f73), SPH_C32(0xba037d0a), + SPH_C32(0x181203d9), SPH_C32(0x5310e723), SPH_C32(0x30a20064), + SPH_C32(0xc4f08000), SPH_C32(0xce960000), SPH_C32(0x0f610000), + SPH_C32(0x73a60b43), SPH_C32(0x13f80514), SPH_C32(0x62a805af), + SPH_C32(0x7f8942c1) }, + { SPH_C32(0x4f0d017d), SPH_C32(0x173a8000), SPH_C32(0xecf60000), + SPH_C32(0xc9560000), SPH_C32(0xeba12488), SPH_C32(0xb0bba8a4), + SPH_C32(0xd5d788c0), SPH_C32(0x84855d12), SPH_C32(0x96dd0065), + SPH_C32(0xb5c70000), SPH_C32(0xd76a0000), SPH_C32(0x99ba0000), + SPH_C32(0x492d66be), SPH_C32(0xf832abe7), SPH_C32(0x4ec54220), + SPH_C32(0xd3072e49) }, + { SPH_C32(0x3ced0170), SPH_C32(0x10bac000), SPH_C32(0xb7740000), + SPH_C32(0x9e0b0000), SPH_C32(0x0ec6295d), SPH_C32(0x6095632f), + SPH_C32(0xd6ce231c), SPH_C32(0x96ced091), SPH_C32(0x97280069), + SPH_C32(0x4eb80000), SPH_C32(0x30bb0000), SPH_C32(0x12150000), + SPH_C32(0x6a8f44ec), SPH_C32(0x0a6248f3), SPH_C32(0xf9873877), + SPH_C32(0x9a840c62) }, + { SPH_C32(0xca6d0175), SPH_C32(0x24f90000), SPH_C32(0x93730000), + SPH_C32(0x11360000), SPH_C32(0x2ff112a6), SPH_C32(0x6a2db681), + SPH_C32(0x1b0ba805), SPH_C32(0x415b6aa0), SPH_C32(0x31570068), + SPH_C32(0x3f8f8000), SPH_C32(0x29470000), SPH_C32(0x84ce0000), + SPH_C32(0x50042911), SPH_C32(0xe1a8e600), SPH_C32(0xd5ea7ff8), + SPH_C32(0x360a60ea) }, + { SPH_C32(0x9a920171), SPH_C32(0x618d4000), SPH_C32(0xae880000), + SPH_C32(0x08d00000), SPH_C32(0x344d44a0), SPH_C32(0x8b5fcddc), + SPH_C32(0xfaa36493), SPH_C32(0x3a40bc19), SPH_C32(0xc7d7006d), + SPH_C32(0x0bcc4000), SPH_C32(0x0d400000), SPH_C32(0x0bf30000), + SPH_C32(0x713312ea), SPH_C32(0xeb1033ae), SPH_C32(0x182ff4e1), + SPH_C32(0xe19fdadb) }, + { SPH_C32(0x6c120174), SPH_C32(0x55ce8000), SPH_C32(0x8a8f0000), + SPH_C32(0x87ed0000), SPH_C32(0x157a7f5b), SPH_C32(0x81e71872), + SPH_C32(0x3766ef8a), SPH_C32(0xedd50628), SPH_C32(0x61a8006c), + SPH_C32(0x7afbc000), SPH_C32(0x14bc0000), SPH_C32(0x9d280000), + SPH_C32(0x4bb87f17), SPH_C32(0x00da9d5d), SPH_C32(0x3442b36e), + SPH_C32(0x4d11b653) }, + { SPH_C32(0xcb980179), SPH_C32(0xdf860000), SPH_C32(0x74a20000), + SPH_C32(0x9a990000), SPH_C32(0x0c5330f4), SPH_C32(0x987d5595), + SPH_C32(0xac49d252), SPH_C32(0x08d8488b), SPH_C32(0x43420069), + SPH_C32(0xc370c000), SPH_C32(0x95140000), SPH_C32(0x583c0000), + SPH_C32(0x96c10696), SPH_C32(0xc3d6ce9f), SPH_C32(0x61b1ae73), + SPH_C32(0x6dc2cf42) }, + { SPH_C32(0x3d18017c), SPH_C32(0xebc5c000), SPH_C32(0x50a50000), + SPH_C32(0x15a40000), SPH_C32(0x2d640b0f), SPH_C32(0x92c5803b), + SPH_C32(0x618c594b), SPH_C32(0xdf4df2ba), SPH_C32(0xe53d0068), + SPH_C32(0xb2474000), SPH_C32(0x8ce80000), SPH_C32(0xcee70000), + SPH_C32(0xac4a6b6b), SPH_C32(0x281c606c), SPH_C32(0x4ddce9fc), + SPH_C32(0xc14ca3ca) }, + { SPH_C32(0x6de70178), SPH_C32(0xaeb18000), SPH_C32(0x6d5e0000), + SPH_C32(0x0c420000), SPH_C32(0x36d85d09), SPH_C32(0x73b7fb66), + SPH_C32(0x802495dd), SPH_C32(0xa4562403), SPH_C32(0x13bd006d), + SPH_C32(0x86048000), SPH_C32(0xa8ef0000), SPH_C32(0x41da0000), + SPH_C32(0x8d7d5090), SPH_C32(0x22a4b5c2), SPH_C32(0x801962e5), + SPH_C32(0x16d919fb) }, + { SPH_C32(0x9b67017d), SPH_C32(0x9af24000), SPH_C32(0x49590000), + SPH_C32(0x837f0000), SPH_C32(0x17ef66f2), SPH_C32(0x790f2ec8), + SPH_C32(0x4de11ec4), SPH_C32(0x73c39e32), SPH_C32(0xb5c2006c), + SPH_C32(0xf7330000), SPH_C32(0xb1130000), SPH_C32(0xd7010000), + SPH_C32(0xb7f63d6d), SPH_C32(0xc96e1b31), SPH_C32(0xac74256a), + SPH_C32(0xba577573) }, + { SPH_C32(0x9fc30180), SPH_C32(0x6c280000), SPH_C32(0xe7690000), + SPH_C32(0xe0360000), SPH_C32(0x7bbf15ab), SPH_C32(0xf3aa0966), + SPH_C32(0x453b7806), SPH_C32(0xaebf667a), SPH_C32(0x405b0030), + SPH_C32(0x9a540000), SPH_C32(0x42670000), SPH_C32(0x5fb10000), + SPH_C32(0xd6c06187), SPH_C32(0x5d81863c), SPH_C32(0x87922fef), + SPH_C32(0x79e0422c) }, + { SPH_C32(0x69430185), SPH_C32(0x586bc000), SPH_C32(0xc36e0000), + SPH_C32(0x6f0b0000), SPH_C32(0x5a882e50), SPH_C32(0xf912dcc8), + SPH_C32(0x88fef31f), SPH_C32(0x792adc4b), SPH_C32(0xe6240031), + SPH_C32(0xeb638000), SPH_C32(0x5b9b0000), SPH_C32(0xc96a0000), + SPH_C32(0xec4b0c7a), SPH_C32(0xb64b28cf), SPH_C32(0xabff6860), + SPH_C32(0xd56e2ea4) }, + { SPH_C32(0x39bc0181), SPH_C32(0x1d1f8000), SPH_C32(0xfe950000), + SPH_C32(0x76ed0000), SPH_C32(0x41347856), SPH_C32(0x1860a795), + SPH_C32(0x69563f89), SPH_C32(0x02310af2), SPH_C32(0x10a40034), + SPH_C32(0xdf204000), SPH_C32(0x7f9c0000), SPH_C32(0x46570000), + SPH_C32(0xcd7c3781), SPH_C32(0xbcf3fd61), SPH_C32(0x663ae379), + SPH_C32(0x02fb9495) }, + { SPH_C32(0xcf3c0184), SPH_C32(0x295c4000), SPH_C32(0xda920000), + SPH_C32(0xf9d00000), SPH_C32(0x600343ad), SPH_C32(0x12d8723b), + SPH_C32(0xa493b490), SPH_C32(0xd5a4b0c3), SPH_C32(0xb6db0035), + SPH_C32(0xae17c000), SPH_C32(0x66600000), SPH_C32(0xd08c0000), + SPH_C32(0xf7f75a7c), SPH_C32(0x57395392), SPH_C32(0x4a57a4f6), + SPH_C32(0xae75f81d) }, + { SPH_C32(0x68b60189), SPH_C32(0xa314c000), SPH_C32(0x24bf0000), + SPH_C32(0xe4a40000), SPH_C32(0x792a0c02), SPH_C32(0x0b423fdc), + SPH_C32(0x3fbc8948), SPH_C32(0x30a9fe60), SPH_C32(0x94310030), + SPH_C32(0x179cc000), SPH_C32(0xe7c80000), SPH_C32(0x15980000), + SPH_C32(0x2a8e23fd), SPH_C32(0x94350050), SPH_C32(0x1fa4b9eb), + SPH_C32(0x8ea6810c) }, + { SPH_C32(0x9e36018c), SPH_C32(0x97570000), SPH_C32(0x00b80000), + SPH_C32(0x6b990000), SPH_C32(0x581d37f9), SPH_C32(0x01faea72), + SPH_C32(0xf2790251), SPH_C32(0xe73c4451), SPH_C32(0x324e0031), + SPH_C32(0x66ab4000), SPH_C32(0xfe340000), SPH_C32(0x83430000), + SPH_C32(0x10054e00), SPH_C32(0x7fffaea3), SPH_C32(0x33c9fe64), + SPH_C32(0x2228ed84) }, + { SPH_C32(0xcec90188), SPH_C32(0xd2234000), SPH_C32(0x3d430000), + SPH_C32(0x727f0000), SPH_C32(0x43a161ff), SPH_C32(0xe088912f), + SPH_C32(0x13d1cec7), SPH_C32(0x9c2792e8), SPH_C32(0xc4ce0034), + SPH_C32(0x52e88000), SPH_C32(0xda330000), SPH_C32(0x0c7e0000), + SPH_C32(0x313275fb), SPH_C32(0x75477b0d), SPH_C32(0xfe0c757d), + SPH_C32(0xf5bd57b5) }, + { SPH_C32(0x3849018d), SPH_C32(0xe6608000), SPH_C32(0x19440000), + SPH_C32(0xfd420000), SPH_C32(0x62965a04), SPH_C32(0xea304481), + SPH_C32(0xde1445de), SPH_C32(0x4bb228d9), SPH_C32(0x62b10035), + SPH_C32(0x23df0000), SPH_C32(0xc3cf0000), SPH_C32(0x9aa50000), + SPH_C32(0x0bb91806), SPH_C32(0x9e8dd5fe), SPH_C32(0xd26132f2), + SPH_C32(0x59333b3d) }, + { SPH_C32(0x4ba90180), SPH_C32(0xe1e0c000), SPH_C32(0x42c60000), + SPH_C32(0xaa1f0000), SPH_C32(0x87f157d1), SPH_C32(0x3a1e8f0a), + SPH_C32(0xdd0dee02), SPH_C32(0x59f9a55a), SPH_C32(0x63440039), + SPH_C32(0xd8a00000), SPH_C32(0x241e0000), SPH_C32(0x110a0000), + SPH_C32(0x281b3a54), SPH_C32(0x6cdd36ea), SPH_C32(0x652348a5), + SPH_C32(0x10b01916) }, + { SPH_C32(0xbd290185), SPH_C32(0xd5a30000), SPH_C32(0x66c10000), + SPH_C32(0x25220000), SPH_C32(0xa6c66c2a), SPH_C32(0x30a65aa4), + SPH_C32(0x10c8651b), SPH_C32(0x8e6c1f6b), SPH_C32(0xc53b0038), + SPH_C32(0xa9978000), SPH_C32(0x3de20000), SPH_C32(0x87d10000), + SPH_C32(0x129057a9), SPH_C32(0x87179819), SPH_C32(0x494e0f2a), + SPH_C32(0xbc3e759e) }, + { SPH_C32(0xedd60181), SPH_C32(0x90d74000), SPH_C32(0x5b3a0000), + SPH_C32(0x3cc40000), SPH_C32(0xbd7a3a2c), SPH_C32(0xd1d421f9), + SPH_C32(0xf160a98d), SPH_C32(0xf577c9d2), SPH_C32(0x33bb003d), + SPH_C32(0x9dd44000), SPH_C32(0x19e50000), SPH_C32(0x08ec0000), + SPH_C32(0x33a76c52), SPH_C32(0x8daf4db7), SPH_C32(0x848b8433), + SPH_C32(0x6babcfaf) }, + { SPH_C32(0x1b560184), SPH_C32(0xa4948000), SPH_C32(0x7f3d0000), + SPH_C32(0xb3f90000), SPH_C32(0x9c4d01d7), SPH_C32(0xdb6cf457), + SPH_C32(0x3ca52294), SPH_C32(0x22e273e3), SPH_C32(0x95c4003c), + SPH_C32(0xece3c000), SPH_C32(0x00190000), SPH_C32(0x9e370000), + SPH_C32(0x092c01af), SPH_C32(0x6665e344), SPH_C32(0xa8e6c3bc), + SPH_C32(0xc725a327) }, + { SPH_C32(0xbcdc0189), SPH_C32(0x2edc0000), SPH_C32(0x81100000), + SPH_C32(0xae8d0000), SPH_C32(0x85644e78), SPH_C32(0xc2f6b9b0), + SPH_C32(0xa78a1f4c), SPH_C32(0xc7ef3d40), SPH_C32(0xb72e0039), + SPH_C32(0x5568c000), SPH_C32(0x81b10000), SPH_C32(0x5b230000), + SPH_C32(0xd455782e), SPH_C32(0xa569b086), SPH_C32(0xfd15dea1), + SPH_C32(0xe7f6da36) }, + { SPH_C32(0x4a5c018c), SPH_C32(0x1a9fc000), SPH_C32(0xa5170000), + SPH_C32(0x21b00000), SPH_C32(0xa4537583), SPH_C32(0xc84e6c1e), + SPH_C32(0x6a4f9455), SPH_C32(0x107a8771), SPH_C32(0x11510038), + SPH_C32(0x245f4000), SPH_C32(0x984d0000), SPH_C32(0xcdf80000), + SPH_C32(0xeede15d3), SPH_C32(0x4ea31e75), SPH_C32(0xd178992e), + SPH_C32(0x4b78b6be) }, + { SPH_C32(0x1aa30188), SPH_C32(0x5feb8000), SPH_C32(0x98ec0000), + SPH_C32(0x38560000), SPH_C32(0xbfef2385), SPH_C32(0x293c1743), + SPH_C32(0x8be758c3), SPH_C32(0x6b6151c8), SPH_C32(0xe7d1003d), + SPH_C32(0x101c8000), SPH_C32(0xbc4a0000), SPH_C32(0x42c50000), + SPH_C32(0xcfe92e28), SPH_C32(0x441bcbdb), SPH_C32(0x1cbd1237), + SPH_C32(0x9ced0c8f) }, + { SPH_C32(0xec23018d), SPH_C32(0x6ba84000), SPH_C32(0xbceb0000), + SPH_C32(0xb76b0000), SPH_C32(0x9ed8187e), SPH_C32(0x2384c2ed), + SPH_C32(0x4622d3da), SPH_C32(0xbcf4ebf9), SPH_C32(0x41ae003c), + SPH_C32(0x612b0000), SPH_C32(0xa5b60000), SPH_C32(0xd41e0000), + SPH_C32(0xf56243d5), SPH_C32(0xafd16528), SPH_C32(0x30d055b8), + SPH_C32(0x30636007) }, + { SPH_C32(0x1ceb0120), SPH_C32(0x0b6a0000), SPH_C32(0x067e0000), + SPH_C32(0xd73d0000), SPH_C32(0xb01c159f), SPH_C32(0xcf9e9b5a), + SPH_C32(0xd25cc5ca), SPH_C32(0xebbc06c5), SPH_C32(0x371f00c0), + SPH_C32(0x6b0e0000), SPH_C32(0xb7d50000), SPH_C32(0x6ba50000), + SPH_C32(0x5ff71f0b), SPH_C32(0x070a6a19), SPH_C32(0x8c51e2f1), + SPH_C32(0xb6d737e7) }, + { SPH_C32(0xea6b0125), SPH_C32(0x3f29c000), SPH_C32(0x22790000), + SPH_C32(0x58000000), SPH_C32(0x912b2e64), SPH_C32(0xc5264ef4), + SPH_C32(0x1f994ed3), SPH_C32(0x3c29bcf4), SPH_C32(0x916000c1), + SPH_C32(0x1a398000), SPH_C32(0xae290000), SPH_C32(0xfd7e0000), + SPH_C32(0x657c72f6), SPH_C32(0xecc0c4ea), SPH_C32(0xa03ca57e), + SPH_C32(0x1a595b6f) }, + { SPH_C32(0xba940121), SPH_C32(0x7a5d8000), SPH_C32(0x1f820000), + SPH_C32(0x41e60000), SPH_C32(0x8a977862), SPH_C32(0x245435a9), + SPH_C32(0xfe318245), SPH_C32(0x47326a4d), SPH_C32(0x67e000c4), + SPH_C32(0x2e7a4000), SPH_C32(0x8a2e0000), SPH_C32(0x72430000), + SPH_C32(0x444b490d), SPH_C32(0xe6781144), SPH_C32(0x6df92e67), + SPH_C32(0xcdcce15e) }, + { SPH_C32(0x4c140124), SPH_C32(0x4e1e4000), SPH_C32(0x3b850000), + SPH_C32(0xcedb0000), SPH_C32(0xaba04399), SPH_C32(0x2eece007), + SPH_C32(0x33f4095c), SPH_C32(0x90a7d07c), SPH_C32(0xc19f00c5), + SPH_C32(0x5f4dc000), SPH_C32(0x93d20000), SPH_C32(0xe4980000), + SPH_C32(0x7ec024f0), SPH_C32(0x0db2bfb7), SPH_C32(0x419469e8), + SPH_C32(0x61428dd6) }, + { SPH_C32(0xeb9e0129), SPH_C32(0xc456c000), SPH_C32(0xc5a80000), + SPH_C32(0xd3af0000), SPH_C32(0xb2890c36), SPH_C32(0x3776ade0), + SPH_C32(0xa8db3484), SPH_C32(0x75aa9edf), SPH_C32(0xe37500c0), + SPH_C32(0xe6c6c000), SPH_C32(0x127a0000), SPH_C32(0x218c0000), + SPH_C32(0xa3b95d71), SPH_C32(0xcebeec75), SPH_C32(0x146774f5), + SPH_C32(0x4191f4c7) }, + { SPH_C32(0x1d1e012c), SPH_C32(0xf0150000), SPH_C32(0xe1af0000), + SPH_C32(0x5c920000), SPH_C32(0x93be37cd), SPH_C32(0x3dce784e), + SPH_C32(0x651ebf9d), SPH_C32(0xa23f24ee), SPH_C32(0x450a00c1), + SPH_C32(0x97f14000), SPH_C32(0x0b860000), SPH_C32(0xb7570000), + SPH_C32(0x9932308c), SPH_C32(0x25744286), SPH_C32(0x380a337a), + SPH_C32(0xed1f984f) }, + { SPH_C32(0x4de10128), SPH_C32(0xb5614000), SPH_C32(0xdc540000), + SPH_C32(0x45740000), SPH_C32(0x880261cb), SPH_C32(0xdcbc0313), + SPH_C32(0x84b6730b), SPH_C32(0xd924f257), SPH_C32(0xb38a00c4), + SPH_C32(0xa3b28000), SPH_C32(0x2f810000), SPH_C32(0x386a0000), + SPH_C32(0xb8050b77), SPH_C32(0x2fcc9728), SPH_C32(0xf5cfb863), + SPH_C32(0x3a8a227e) }, + { SPH_C32(0xbb61012d), SPH_C32(0x81228000), SPH_C32(0xf8530000), + SPH_C32(0xca490000), SPH_C32(0xa9355a30), SPH_C32(0xd604d6bd), + SPH_C32(0x4973f812), SPH_C32(0x0eb14866), SPH_C32(0x15f500c5), + SPH_C32(0xd2850000), SPH_C32(0x367d0000), SPH_C32(0xaeb10000), + SPH_C32(0x828e668a), SPH_C32(0xc40639db), SPH_C32(0xd9a2ffec), + SPH_C32(0x96044ef6) }, + { SPH_C32(0xc8810120), SPH_C32(0x86a2c000), SPH_C32(0xa3d10000), + SPH_C32(0x9d140000), SPH_C32(0x4c5257e5), SPH_C32(0x062a1d36), + SPH_C32(0x4a6a53ce), SPH_C32(0x1cfac5e5), SPH_C32(0x140000c9), + SPH_C32(0x29fa0000), SPH_C32(0xd1ac0000), SPH_C32(0x251e0000), + SPH_C32(0xa12c44d8), SPH_C32(0x3656dacf), SPH_C32(0x6ee085bb), + SPH_C32(0xdf876cdd) }, + { SPH_C32(0x3e010125), SPH_C32(0xb2e10000), SPH_C32(0x87d60000), + SPH_C32(0x12290000), SPH_C32(0x6d656c1e), SPH_C32(0x0c92c898), + SPH_C32(0x87afd8d7), SPH_C32(0xcb6f7fd4), SPH_C32(0xb27f00c8), + SPH_C32(0x58cd8000), SPH_C32(0xc8500000), SPH_C32(0xb3c50000), + SPH_C32(0x9ba72925), SPH_C32(0xdd9c743c), SPH_C32(0x428dc234), + SPH_C32(0x73090055) }, + { SPH_C32(0x6efe0121), SPH_C32(0xf7954000), SPH_C32(0xba2d0000), + SPH_C32(0x0bcf0000), SPH_C32(0x76d93a18), SPH_C32(0xede0b3c5), + SPH_C32(0x66071441), SPH_C32(0xb074a96d), SPH_C32(0x44ff00cd), + SPH_C32(0x6c8e4000), SPH_C32(0xec570000), SPH_C32(0x3cf80000), + SPH_C32(0xba9012de), SPH_C32(0xd724a192), SPH_C32(0x8f48492d), + SPH_C32(0xa49cba64) }, + { SPH_C32(0x987e0124), SPH_C32(0xc3d68000), SPH_C32(0x9e2a0000), + SPH_C32(0x84f20000), SPH_C32(0x57ee01e3), SPH_C32(0xe758666b), + SPH_C32(0xabc29f58), SPH_C32(0x67e1135c), SPH_C32(0xe28000cc), + SPH_C32(0x1db9c000), SPH_C32(0xf5ab0000), SPH_C32(0xaa230000), + SPH_C32(0x801b7f23), SPH_C32(0x3cee0f61), SPH_C32(0xa3250ea2), + SPH_C32(0x0812d6ec) }, + { SPH_C32(0x3ff40129), SPH_C32(0x499e0000), SPH_C32(0x60070000), + SPH_C32(0x99860000), SPH_C32(0x4ec74e4c), SPH_C32(0xfec22b8c), + SPH_C32(0x30eda280), SPH_C32(0x82ec5dff), SPH_C32(0xc06a00c9), + SPH_C32(0xa432c000), SPH_C32(0x74030000), SPH_C32(0x6f370000), + SPH_C32(0x5d6206a2), SPH_C32(0xffe25ca3), SPH_C32(0xf6d613bf), + SPH_C32(0x28c1affd) }, + { SPH_C32(0xc974012c), SPH_C32(0x7dddc000), SPH_C32(0x44000000), + SPH_C32(0x16bb0000), SPH_C32(0x6ff075b7), SPH_C32(0xf47afe22), + SPH_C32(0xfd282999), SPH_C32(0x5579e7ce), SPH_C32(0x661500c8), + SPH_C32(0xd5054000), SPH_C32(0x6dff0000), SPH_C32(0xf9ec0000), + SPH_C32(0x67e96b5f), SPH_C32(0x1428f250), SPH_C32(0xdabb5430), + SPH_C32(0x844fc375) }, + { SPH_C32(0x998b0128), SPH_C32(0x38a98000), SPH_C32(0x79fb0000), + SPH_C32(0x0f5d0000), SPH_C32(0x744c23b1), SPH_C32(0x1508857f), + SPH_C32(0x1c80e50f), SPH_C32(0x2e623177), SPH_C32(0x909500cd), + SPH_C32(0xe1468000), SPH_C32(0x49f80000), SPH_C32(0x76d10000), + SPH_C32(0x46de50a4), SPH_C32(0x1e9027fe), SPH_C32(0x177edf29), + SPH_C32(0x53da7944) }, + { SPH_C32(0x6f0b012d), SPH_C32(0x0cea4000), SPH_C32(0x5dfc0000), + SPH_C32(0x80600000), SPH_C32(0x557b184a), SPH_C32(0x1fb050d1), + SPH_C32(0xd1456e16), SPH_C32(0xf9f78b46), SPH_C32(0x36ea00cc), + SPH_C32(0x90710000), SPH_C32(0x50040000), SPH_C32(0xe00a0000), + SPH_C32(0x7c553d59), SPH_C32(0xf55a890d), SPH_C32(0x3b1398a6), + SPH_C32(0xff5415cc) }, + { SPH_C32(0x6baf01d0), SPH_C32(0xfa300000), SPH_C32(0xf3cc0000), + SPH_C32(0xe3290000), SPH_C32(0x392b6b13), SPH_C32(0x9515777f), + SPH_C32(0xd99f08d4), SPH_C32(0x248b730e), SPH_C32(0xc3730090), + SPH_C32(0xfd160000), SPH_C32(0xa3700000), SPH_C32(0x68ba0000), + SPH_C32(0x1d6361b3), SPH_C32(0x61b51400), SPH_C32(0x10f59223), + SPH_C32(0x3ce32293) }, + { SPH_C32(0x9d2f01d5), SPH_C32(0xce73c000), SPH_C32(0xd7cb0000), + SPH_C32(0x6c140000), SPH_C32(0x181c50e8), SPH_C32(0x9fada2d1), + SPH_C32(0x145a83cd), SPH_C32(0xf31ec93f), SPH_C32(0x650c0091), + SPH_C32(0x8c218000), SPH_C32(0xba8c0000), SPH_C32(0xfe610000), + SPH_C32(0x27e80c4e), SPH_C32(0x8a7fbaf3), SPH_C32(0x3c98d5ac), + SPH_C32(0x906d4e1b) }, + { SPH_C32(0xcdd001d1), SPH_C32(0x8b078000), SPH_C32(0xea300000), + SPH_C32(0x75f20000), SPH_C32(0x03a006ee), SPH_C32(0x7edfd98c), + SPH_C32(0xf5f24f5b), SPH_C32(0x88051f86), SPH_C32(0x938c0094), + SPH_C32(0xb8624000), SPH_C32(0x9e8b0000), SPH_C32(0x715c0000), + SPH_C32(0x06df37b5), SPH_C32(0x80c76f5d), SPH_C32(0xf15d5eb5), + SPH_C32(0x47f8f42a) }, + { SPH_C32(0x3b5001d4), SPH_C32(0xbf444000), SPH_C32(0xce370000), + SPH_C32(0xfacf0000), SPH_C32(0x22973d15), SPH_C32(0x74670c22), + SPH_C32(0x3837c442), SPH_C32(0x5f90a5b7), SPH_C32(0x35f30095), + SPH_C32(0xc955c000), SPH_C32(0x87770000), SPH_C32(0xe7870000), + SPH_C32(0x3c545a48), SPH_C32(0x6b0dc1ae), SPH_C32(0xdd30193a), + SPH_C32(0xeb7698a2) }, + { SPH_C32(0x9cda01d9), SPH_C32(0x350cc000), SPH_C32(0x301a0000), + SPH_C32(0xe7bb0000), SPH_C32(0x3bbe72ba), SPH_C32(0x6dfd41c5), + SPH_C32(0xa318f99a), SPH_C32(0xba9deb14), SPH_C32(0x17190090), + SPH_C32(0x70dec000), SPH_C32(0x06df0000), SPH_C32(0x22930000), + SPH_C32(0xe12d23c9), SPH_C32(0xa801926c), SPH_C32(0x88c30427), + SPH_C32(0xcba5e1b3) }, + { SPH_C32(0x6a5a01dc), SPH_C32(0x014f0000), SPH_C32(0x141d0000), + SPH_C32(0x68860000), SPH_C32(0x1a894941), SPH_C32(0x6745946b), + SPH_C32(0x6edd7283), SPH_C32(0x6d085125), SPH_C32(0xb1660091), + SPH_C32(0x01e94000), SPH_C32(0x1f230000), SPH_C32(0xb4480000), + SPH_C32(0xdba64e34), SPH_C32(0x43cb3c9f), SPH_C32(0xa4ae43a8), + SPH_C32(0x672b8d3b) }, + { SPH_C32(0x3aa501d8), SPH_C32(0x443b4000), SPH_C32(0x29e60000), + SPH_C32(0x71600000), SPH_C32(0x01351f47), SPH_C32(0x8637ef36), + SPH_C32(0x8f75be15), SPH_C32(0x1613879c), SPH_C32(0x47e60094), + SPH_C32(0x35aa8000), SPH_C32(0x3b240000), SPH_C32(0x3b750000), + SPH_C32(0xfa9175cf), SPH_C32(0x4973e931), SPH_C32(0x696bc8b1), + SPH_C32(0xb0be370a) }, + { SPH_C32(0xcc2501dd), SPH_C32(0x70788000), SPH_C32(0x0de10000), + SPH_C32(0xfe5d0000), SPH_C32(0x200224bc), SPH_C32(0x8c8f3a98), + SPH_C32(0x42b0350c), SPH_C32(0xc1863dad), SPH_C32(0xe1990095), + SPH_C32(0x449d0000), SPH_C32(0x22d80000), SPH_C32(0xadae0000), + SPH_C32(0xc01a1832), SPH_C32(0xa2b947c2), SPH_C32(0x45068f3e), + SPH_C32(0x1c305b82) }, + { SPH_C32(0xbfc501d0), SPH_C32(0x77f8c000), SPH_C32(0x56630000), + SPH_C32(0xa9000000), SPH_C32(0xc5652969), SPH_C32(0x5ca1f113), + SPH_C32(0x41a99ed0), SPH_C32(0xd3cdb02e), SPH_C32(0xe06c0099), + SPH_C32(0xbfe20000), SPH_C32(0xc5090000), SPH_C32(0x26010000), + SPH_C32(0xe3b83a60), SPH_C32(0x50e9a4d6), SPH_C32(0xf244f569), + SPH_C32(0x55b379a9) }, + { SPH_C32(0x494501d5), SPH_C32(0x43bb0000), SPH_C32(0x72640000), + SPH_C32(0x263d0000), SPH_C32(0xe4521292), SPH_C32(0x561924bd), + SPH_C32(0x8c6c15c9), SPH_C32(0x04580a1f), SPH_C32(0x46130098), + SPH_C32(0xced58000), SPH_C32(0xdcf50000), SPH_C32(0xb0da0000), + SPH_C32(0xd933579d), SPH_C32(0xbb230a25), SPH_C32(0xde29b2e6), + SPH_C32(0xf93d1521) }, + { SPH_C32(0x19ba01d1), SPH_C32(0x06cf4000), SPH_C32(0x4f9f0000), + SPH_C32(0x3fdb0000), SPH_C32(0xffee4494), SPH_C32(0xb76b5fe0), + SPH_C32(0x6dc4d95f), SPH_C32(0x7f43dca6), SPH_C32(0xb093009d), + SPH_C32(0xfa964000), SPH_C32(0xf8f20000), SPH_C32(0x3fe70000), + SPH_C32(0xf8046c66), SPH_C32(0xb19bdf8b), SPH_C32(0x13ec39ff), + SPH_C32(0x2ea8af10) }, + { SPH_C32(0xef3a01d4), SPH_C32(0x328c8000), SPH_C32(0x6b980000), + SPH_C32(0xb0e60000), SPH_C32(0xded97f6f), SPH_C32(0xbdd38a4e), + SPH_C32(0xa0015246), SPH_C32(0xa8d66697), SPH_C32(0x16ec009c), + SPH_C32(0x8ba1c000), SPH_C32(0xe10e0000), SPH_C32(0xa93c0000), + SPH_C32(0xc28f019b), SPH_C32(0x5a517178), SPH_C32(0x3f817e70), + SPH_C32(0x8226c398) }, + { SPH_C32(0x48b001d9), SPH_C32(0xb8c40000), SPH_C32(0x95b50000), + SPH_C32(0xad920000), SPH_C32(0xc7f030c0), SPH_C32(0xa449c7a9), + SPH_C32(0x3b2e6f9e), SPH_C32(0x4ddb2834), SPH_C32(0x34060099), + SPH_C32(0x322ac000), SPH_C32(0x60a60000), SPH_C32(0x6c280000), + SPH_C32(0x1ff6781a), SPH_C32(0x995d22ba), SPH_C32(0x6a72636d), + SPH_C32(0xa2f5ba89) }, + { SPH_C32(0xbe3001dc), SPH_C32(0x8c87c000), SPH_C32(0xb1b20000), + SPH_C32(0x22af0000), SPH_C32(0xe6c70b3b), SPH_C32(0xaef11207), + SPH_C32(0xf6ebe487), SPH_C32(0x9a4e9205), SPH_C32(0x92790098), + SPH_C32(0x431d4000), SPH_C32(0x795a0000), SPH_C32(0xfaf30000), + SPH_C32(0x257d15e7), SPH_C32(0x72978c49), SPH_C32(0x461f24e2), + SPH_C32(0x0e7bd601) }, + { SPH_C32(0xeecf01d8), SPH_C32(0xc9f38000), SPH_C32(0x8c490000), + SPH_C32(0x3b490000), SPH_C32(0xfd7b5d3d), SPH_C32(0x4f83695a), + SPH_C32(0x17432811), SPH_C32(0xe15544bc), SPH_C32(0x64f9009d), + SPH_C32(0x775e8000), SPH_C32(0x5d5d0000), SPH_C32(0x75ce0000), + SPH_C32(0x044a2e1c), SPH_C32(0x782f59e7), SPH_C32(0x8bdaaffb), + SPH_C32(0xd9ee6c30) }, + { SPH_C32(0x184f01dd), SPH_C32(0xfdb04000), SPH_C32(0xa84e0000), + SPH_C32(0xb4740000), SPH_C32(0xdc4c66c6), SPH_C32(0x453bbcf4), + SPH_C32(0xda86a308), SPH_C32(0x36c0fe8d), SPH_C32(0xc286009c), + SPH_C32(0x06690000), SPH_C32(0x44a10000), SPH_C32(0xe3150000), + SPH_C32(0x3ec143e1), SPH_C32(0x93e5f714), SPH_C32(0xa7b7e874), + SPH_C32(0x756000b8) }, + { SPH_C32(0xb4370060), SPH_C32(0x0c4c0000), SPH_C32(0x56c20000), + SPH_C32(0x5cae0000), SPH_C32(0x94541f3f), SPH_C32(0x3b3ef825), + SPH_C32(0x1b365f3d), SPH_C32(0xf3d45758), SPH_C32(0x5cb00110), + SPH_C32(0x913e0000), SPH_C32(0x44190000), SPH_C32(0x888c0000), + SPH_C32(0x66dc7418), SPH_C32(0x921f1d66), SPH_C32(0x55ceea25), + SPH_C32(0x925c44e9) }, + { SPH_C32(0x42b70065), SPH_C32(0x380fc000), SPH_C32(0x72c50000), + SPH_C32(0xd3930000), SPH_C32(0xb56324c4), SPH_C32(0x31862d8b), + SPH_C32(0xd6f3d424), SPH_C32(0x2441ed69), SPH_C32(0xfacf0111), + SPH_C32(0xe0098000), SPH_C32(0x5de50000), SPH_C32(0x1e570000), + SPH_C32(0x5c5719e5), SPH_C32(0x79d5b395), SPH_C32(0x79a3adaa), + SPH_C32(0x3ed22861) }, + { SPH_C32(0x12480061), SPH_C32(0x7d7b8000), SPH_C32(0x4f3e0000), + SPH_C32(0xca750000), SPH_C32(0xaedf72c2), SPH_C32(0xd0f456d6), + SPH_C32(0x375b18b2), SPH_C32(0x5f5a3bd0), SPH_C32(0x0c4f0114), + SPH_C32(0xd44a4000), SPH_C32(0x79e20000), SPH_C32(0x916a0000), + SPH_C32(0x7d60221e), SPH_C32(0x736d663b), SPH_C32(0xb46626b3), + SPH_C32(0xe9479250) }, + { SPH_C32(0xe4c80064), SPH_C32(0x49384000), SPH_C32(0x6b390000), + SPH_C32(0x45480000), SPH_C32(0x8fe84939), SPH_C32(0xda4c8378), + SPH_C32(0xfa9e93ab), SPH_C32(0x88cf81e1), SPH_C32(0xaa300115), + SPH_C32(0xa57dc000), SPH_C32(0x601e0000), SPH_C32(0x07b10000), + SPH_C32(0x47eb4fe3), SPH_C32(0x98a7c8c8), SPH_C32(0x980b613c), + SPH_C32(0x45c9fed8) }, + { SPH_C32(0x43420069), SPH_C32(0xc370c000), SPH_C32(0x95140000), + SPH_C32(0x583c0000), SPH_C32(0x96c10696), SPH_C32(0xc3d6ce9f), + SPH_C32(0x61b1ae73), SPH_C32(0x6dc2cf42), SPH_C32(0x88da0110), + SPH_C32(0x1cf6c000), SPH_C32(0xe1b60000), SPH_C32(0xc2a50000), + SPH_C32(0x9a923662), SPH_C32(0x5bab9b0a), SPH_C32(0xcdf87c21), + SPH_C32(0x651a87c9) }, + { SPH_C32(0xb5c2006c), SPH_C32(0xf7330000), SPH_C32(0xb1130000), + SPH_C32(0xd7010000), SPH_C32(0xb7f63d6d), SPH_C32(0xc96e1b31), + SPH_C32(0xac74256a), SPH_C32(0xba577573), SPH_C32(0x2ea50111), + SPH_C32(0x6dc14000), SPH_C32(0xf84a0000), SPH_C32(0x547e0000), + SPH_C32(0xa0195b9f), SPH_C32(0xb06135f9), SPH_C32(0xe1953bae), + SPH_C32(0xc994eb41) }, + { SPH_C32(0xe53d0068), SPH_C32(0xb2474000), SPH_C32(0x8ce80000), + SPH_C32(0xcee70000), SPH_C32(0xac4a6b6b), SPH_C32(0x281c606c), + SPH_C32(0x4ddce9fc), SPH_C32(0xc14ca3ca), SPH_C32(0xd8250114), + SPH_C32(0x59828000), SPH_C32(0xdc4d0000), SPH_C32(0xdb430000), + SPH_C32(0x812e6064), SPH_C32(0xbad9e057), SPH_C32(0x2c50b0b7), + SPH_C32(0x1e015170) }, + { SPH_C32(0x13bd006d), SPH_C32(0x86048000), SPH_C32(0xa8ef0000), + SPH_C32(0x41da0000), SPH_C32(0x8d7d5090), SPH_C32(0x22a4b5c2), + SPH_C32(0x801962e5), SPH_C32(0x16d919fb), SPH_C32(0x7e5a0115), + SPH_C32(0x28b50000), SPH_C32(0xc5b10000), SPH_C32(0x4d980000), + SPH_C32(0xbba50d99), SPH_C32(0x51134ea4), SPH_C32(0x003df738), + SPH_C32(0xb28f3df8) }, + { SPH_C32(0x605d0060), SPH_C32(0x8184c000), SPH_C32(0xf36d0000), + SPH_C32(0x16870000), SPH_C32(0x681a5d45), SPH_C32(0xf28a7e49), + SPH_C32(0x8300c939), SPH_C32(0x04929478), SPH_C32(0x7faf0119), + SPH_C32(0xd3ca0000), SPH_C32(0x22600000), SPH_C32(0xc6370000), + SPH_C32(0x98072fcb), SPH_C32(0xa343adb0), SPH_C32(0xb77f8d6f), + SPH_C32(0xfb0c1fd3) }, + { SPH_C32(0x96dd0065), SPH_C32(0xb5c70000), SPH_C32(0xd76a0000), + SPH_C32(0x99ba0000), SPH_C32(0x492d66be), SPH_C32(0xf832abe7), + SPH_C32(0x4ec54220), SPH_C32(0xd3072e49), SPH_C32(0xd9d00118), + SPH_C32(0xa2fd8000), SPH_C32(0x3b9c0000), SPH_C32(0x50ec0000), + SPH_C32(0xa28c4236), SPH_C32(0x48890343), SPH_C32(0x9b12cae0), + SPH_C32(0x5782735b) }, + { SPH_C32(0xc6220061), SPH_C32(0xf0b34000), SPH_C32(0xea910000), + SPH_C32(0x805c0000), SPH_C32(0x529130b8), SPH_C32(0x1940d0ba), + SPH_C32(0xaf6d8eb6), SPH_C32(0xa81cf8f0), SPH_C32(0x2f50011d), + SPH_C32(0x96be4000), SPH_C32(0x1f9b0000), SPH_C32(0xdfd10000), + SPH_C32(0x83bb79cd), SPH_C32(0x4231d6ed), SPH_C32(0x56d741f9), + SPH_C32(0x8017c96a) }, + { SPH_C32(0x30a20064), SPH_C32(0xc4f08000), SPH_C32(0xce960000), + SPH_C32(0x0f610000), SPH_C32(0x73a60b43), SPH_C32(0x13f80514), + SPH_C32(0x62a805af), SPH_C32(0x7f8942c1), SPH_C32(0x892f011c), + SPH_C32(0xe789c000), SPH_C32(0x06670000), SPH_C32(0x490a0000), + SPH_C32(0xb9301430), SPH_C32(0xa9fb781e), SPH_C32(0x7aba0676), + SPH_C32(0x2c99a5e2) }, + { SPH_C32(0x97280069), SPH_C32(0x4eb80000), SPH_C32(0x30bb0000), + SPH_C32(0x12150000), SPH_C32(0x6a8f44ec), SPH_C32(0x0a6248f3), + SPH_C32(0xf9873877), SPH_C32(0x9a840c62), SPH_C32(0xabc50119), + SPH_C32(0x5e02c000), SPH_C32(0x87cf0000), SPH_C32(0x8c1e0000), + SPH_C32(0x64496db1), SPH_C32(0x6af72bdc), SPH_C32(0x2f491b6b), + SPH_C32(0x0c4adcf3) }, + { SPH_C32(0x61a8006c), SPH_C32(0x7afbc000), SPH_C32(0x14bc0000), + SPH_C32(0x9d280000), SPH_C32(0x4bb87f17), SPH_C32(0x00da9d5d), + SPH_C32(0x3442b36e), SPH_C32(0x4d11b653), SPH_C32(0x0dba0118), + SPH_C32(0x2f354000), SPH_C32(0x9e330000), SPH_C32(0x1ac50000), + SPH_C32(0x5ec2004c), SPH_C32(0x813d852f), SPH_C32(0x03245ce4), + SPH_C32(0xa0c4b07b) }, + { SPH_C32(0x31570068), SPH_C32(0x3f8f8000), SPH_C32(0x29470000), + SPH_C32(0x84ce0000), SPH_C32(0x50042911), SPH_C32(0xe1a8e600), + SPH_C32(0xd5ea7ff8), SPH_C32(0x360a60ea), SPH_C32(0xfb3a011d), + SPH_C32(0x1b768000), SPH_C32(0xba340000), SPH_C32(0x95f80000), + SPH_C32(0x7ff53bb7), SPH_C32(0x8b855081), SPH_C32(0xcee1d7fd), + SPH_C32(0x77510a4a) }, + { SPH_C32(0xc7d7006d), SPH_C32(0x0bcc4000), SPH_C32(0x0d400000), + SPH_C32(0x0bf30000), SPH_C32(0x713312ea), SPH_C32(0xeb1033ae), + SPH_C32(0x182ff4e1), SPH_C32(0xe19fdadb), SPH_C32(0x5d45011c), + SPH_C32(0x6a410000), SPH_C32(0xa3c80000), SPH_C32(0x03230000), + SPH_C32(0x457e564a), SPH_C32(0x604ffe72), SPH_C32(0xe28c9072), + SPH_C32(0xdbdf66c2) }, + { SPH_C32(0xc3730090), SPH_C32(0xfd160000), SPH_C32(0xa3700000), + SPH_C32(0x68ba0000), SPH_C32(0x1d6361b3), SPH_C32(0x61b51400), + SPH_C32(0x10f59223), SPH_C32(0x3ce32293), SPH_C32(0xa8dc0140), + SPH_C32(0x07260000), SPH_C32(0x50bc0000), SPH_C32(0x8b930000), + SPH_C32(0x24480aa0), SPH_C32(0xf4a0637f), SPH_C32(0xc96a9af7), + SPH_C32(0x1868519d) }, + { SPH_C32(0x35f30095), SPH_C32(0xc955c000), SPH_C32(0x87770000), + SPH_C32(0xe7870000), SPH_C32(0x3c545a48), SPH_C32(0x6b0dc1ae), + SPH_C32(0xdd30193a), SPH_C32(0xeb7698a2), SPH_C32(0x0ea30141), + SPH_C32(0x76118000), SPH_C32(0x49400000), SPH_C32(0x1d480000), + SPH_C32(0x1ec3675d), SPH_C32(0x1f6acd8c), SPH_C32(0xe507dd78), + SPH_C32(0xb4e63d15) }, + { SPH_C32(0x650c0091), SPH_C32(0x8c218000), SPH_C32(0xba8c0000), + SPH_C32(0xfe610000), SPH_C32(0x27e80c4e), SPH_C32(0x8a7fbaf3), + SPH_C32(0x3c98d5ac), SPH_C32(0x906d4e1b), SPH_C32(0xf8230144), + SPH_C32(0x42524000), SPH_C32(0x6d470000), SPH_C32(0x92750000), + SPH_C32(0x3ff45ca6), SPH_C32(0x15d21822), SPH_C32(0x28c25661), + SPH_C32(0x63738724) }, + { SPH_C32(0x938c0094), SPH_C32(0xb8624000), SPH_C32(0x9e8b0000), + SPH_C32(0x715c0000), SPH_C32(0x06df37b5), SPH_C32(0x80c76f5d), + SPH_C32(0xf15d5eb5), SPH_C32(0x47f8f42a), SPH_C32(0x5e5c0145), + SPH_C32(0x3365c000), SPH_C32(0x74bb0000), SPH_C32(0x04ae0000), + SPH_C32(0x057f315b), SPH_C32(0xfe18b6d1), SPH_C32(0x04af11ee), + SPH_C32(0xcffdebac) }, + { SPH_C32(0x34060099), SPH_C32(0x322ac000), SPH_C32(0x60a60000), + SPH_C32(0x6c280000), SPH_C32(0x1ff6781a), SPH_C32(0x995d22ba), + SPH_C32(0x6a72636d), SPH_C32(0xa2f5ba89), SPH_C32(0x7cb60140), + SPH_C32(0x8aeec000), SPH_C32(0xf5130000), SPH_C32(0xc1ba0000), + SPH_C32(0xd80648da), SPH_C32(0x3d14e513), SPH_C32(0x515c0cf3), + SPH_C32(0xef2e92bd) }, + { SPH_C32(0xc286009c), SPH_C32(0x06690000), SPH_C32(0x44a10000), + SPH_C32(0xe3150000), SPH_C32(0x3ec143e1), SPH_C32(0x93e5f714), + SPH_C32(0xa7b7e874), SPH_C32(0x756000b8), SPH_C32(0xdac90141), + SPH_C32(0xfbd94000), SPH_C32(0xecef0000), SPH_C32(0x57610000), + SPH_C32(0xe28d2527), SPH_C32(0xd6de4be0), SPH_C32(0x7d314b7c), + SPH_C32(0x43a0fe35) }, + { SPH_C32(0x92790098), SPH_C32(0x431d4000), SPH_C32(0x795a0000), + SPH_C32(0xfaf30000), SPH_C32(0x257d15e7), SPH_C32(0x72978c49), + SPH_C32(0x461f24e2), SPH_C32(0x0e7bd601), SPH_C32(0x2c490144), + SPH_C32(0xcf9a8000), SPH_C32(0xc8e80000), SPH_C32(0xd85c0000), + SPH_C32(0xc3ba1edc), SPH_C32(0xdc669e4e), SPH_C32(0xb0f4c065), + SPH_C32(0x94354404) }, + { SPH_C32(0x64f9009d), SPH_C32(0x775e8000), SPH_C32(0x5d5d0000), + SPH_C32(0x75ce0000), SPH_C32(0x044a2e1c), SPH_C32(0x782f59e7), + SPH_C32(0x8bdaaffb), SPH_C32(0xd9ee6c30), SPH_C32(0x8a360145), + SPH_C32(0xbead0000), SPH_C32(0xd1140000), SPH_C32(0x4e870000), + SPH_C32(0xf9317321), SPH_C32(0x37ac30bd), SPH_C32(0x9c9987ea), + SPH_C32(0x38bb288c) }, + { SPH_C32(0x17190090), SPH_C32(0x70dec000), SPH_C32(0x06df0000), + SPH_C32(0x22930000), SPH_C32(0xe12d23c9), SPH_C32(0xa801926c), + SPH_C32(0x88c30427), SPH_C32(0xcba5e1b3), SPH_C32(0x8bc30149), + SPH_C32(0x45d20000), SPH_C32(0x36c50000), SPH_C32(0xc5280000), + SPH_C32(0xda935173), SPH_C32(0xc5fcd3a9), SPH_C32(0x2bdbfdbd), + SPH_C32(0x71380aa7) }, + { SPH_C32(0xe1990095), SPH_C32(0x449d0000), SPH_C32(0x22d80000), + SPH_C32(0xadae0000), SPH_C32(0xc01a1832), SPH_C32(0xa2b947c2), + SPH_C32(0x45068f3e), SPH_C32(0x1c305b82), SPH_C32(0x2dbc0148), + SPH_C32(0x34e58000), SPH_C32(0x2f390000), SPH_C32(0x53f30000), + SPH_C32(0xe0183c8e), SPH_C32(0x2e367d5a), SPH_C32(0x07b6ba32), + SPH_C32(0xddb6662f) }, + { SPH_C32(0xb1660091), SPH_C32(0x01e94000), SPH_C32(0x1f230000), + SPH_C32(0xb4480000), SPH_C32(0xdba64e34), SPH_C32(0x43cb3c9f), + SPH_C32(0xa4ae43a8), SPH_C32(0x672b8d3b), SPH_C32(0xdb3c014d), + SPH_C32(0x00a64000), SPH_C32(0x0b3e0000), SPH_C32(0xdcce0000), + SPH_C32(0xc12f0775), SPH_C32(0x248ea8f4), SPH_C32(0xca73312b), + SPH_C32(0x0a23dc1e) }, + { SPH_C32(0x47e60094), SPH_C32(0x35aa8000), SPH_C32(0x3b240000), + SPH_C32(0x3b750000), SPH_C32(0xfa9175cf), SPH_C32(0x4973e931), + SPH_C32(0x696bc8b1), SPH_C32(0xb0be370a), SPH_C32(0x7d43014c), + SPH_C32(0x7191c000), SPH_C32(0x12c20000), SPH_C32(0x4a150000), + SPH_C32(0xfba46a88), SPH_C32(0xcf440607), SPH_C32(0xe61e76a4), + SPH_C32(0xa6adb096) }, + { SPH_C32(0xe06c0099), SPH_C32(0xbfe20000), SPH_C32(0xc5090000), + SPH_C32(0x26010000), SPH_C32(0xe3b83a60), SPH_C32(0x50e9a4d6), + SPH_C32(0xf244f569), SPH_C32(0x55b379a9), SPH_C32(0x5fa90149), + SPH_C32(0xc81ac000), SPH_C32(0x936a0000), SPH_C32(0x8f010000), + SPH_C32(0x26dd1309), SPH_C32(0x0c4855c5), SPH_C32(0xb3ed6bb9), + SPH_C32(0x867ec987) }, + { SPH_C32(0x16ec009c), SPH_C32(0x8ba1c000), SPH_C32(0xe10e0000), + SPH_C32(0xa93c0000), SPH_C32(0xc28f019b), SPH_C32(0x5a517178), + SPH_C32(0x3f817e70), SPH_C32(0x8226c398), SPH_C32(0xf9d60148), + SPH_C32(0xb92d4000), SPH_C32(0x8a960000), SPH_C32(0x19da0000), + SPH_C32(0x1c567ef4), SPH_C32(0xe782fb36), SPH_C32(0x9f802c36), + SPH_C32(0x2af0a50f) }, + { SPH_C32(0x46130098), SPH_C32(0xced58000), SPH_C32(0xdcf50000), + SPH_C32(0xb0da0000), SPH_C32(0xd933579d), SPH_C32(0xbb230a25), + SPH_C32(0xde29b2e6), SPH_C32(0xf93d1521), SPH_C32(0x0f56014d), + SPH_C32(0x8d6e8000), SPH_C32(0xae910000), SPH_C32(0x96e70000), + SPH_C32(0x3d61450f), SPH_C32(0xed3a2e98), SPH_C32(0x5245a72f), + SPH_C32(0xfd651f3e) }, + { SPH_C32(0xb093009d), SPH_C32(0xfa964000), SPH_C32(0xf8f20000), + SPH_C32(0x3fe70000), SPH_C32(0xf8046c66), SPH_C32(0xb19bdf8b), + SPH_C32(0x13ec39ff), SPH_C32(0x2ea8af10), SPH_C32(0xa929014c), + SPH_C32(0xfc590000), SPH_C32(0xb76d0000), SPH_C32(0x003c0000), + SPH_C32(0x07ea28f2), SPH_C32(0x06f0806b), SPH_C32(0x7e28e0a0), + SPH_C32(0x51eb73b6) }, + { SPH_C32(0x405b0030), SPH_C32(0x9a540000), SPH_C32(0x42670000), + SPH_C32(0x5fb10000), SPH_C32(0xd6c06187), SPH_C32(0x5d81863c), + SPH_C32(0x87922fef), SPH_C32(0x79e0422c), SPH_C32(0xdf9801b0), + SPH_C32(0xf67c0000), SPH_C32(0xa50e0000), SPH_C32(0xbf870000), + SPH_C32(0xad7f742c), SPH_C32(0xae2b8f5a), SPH_C32(0xc2a957e9), + SPH_C32(0xd75f2456) }, + { SPH_C32(0xb6db0035), SPH_C32(0xae17c000), SPH_C32(0x66600000), + SPH_C32(0xd08c0000), SPH_C32(0xf7f75a7c), SPH_C32(0x57395392), + SPH_C32(0x4a57a4f6), SPH_C32(0xae75f81d), SPH_C32(0x79e701b1), + SPH_C32(0x874b8000), SPH_C32(0xbcf20000), SPH_C32(0x295c0000), + SPH_C32(0x97f419d1), SPH_C32(0x45e121a9), SPH_C32(0xeec41066), + SPH_C32(0x7bd148de) }, + { SPH_C32(0xe6240031), SPH_C32(0xeb638000), SPH_C32(0x5b9b0000), + SPH_C32(0xc96a0000), SPH_C32(0xec4b0c7a), SPH_C32(0xb64b28cf), + SPH_C32(0xabff6860), SPH_C32(0xd56e2ea4), SPH_C32(0x8f6701b4), + SPH_C32(0xb3084000), SPH_C32(0x98f50000), SPH_C32(0xa6610000), + SPH_C32(0xb6c3222a), SPH_C32(0x4f59f407), SPH_C32(0x23019b7f), + SPH_C32(0xac44f2ef) }, + { SPH_C32(0x10a40034), SPH_C32(0xdf204000), SPH_C32(0x7f9c0000), + SPH_C32(0x46570000), SPH_C32(0xcd7c3781), SPH_C32(0xbcf3fd61), + SPH_C32(0x663ae379), SPH_C32(0x02fb9495), SPH_C32(0x291801b5), + SPH_C32(0xc23fc000), SPH_C32(0x81090000), SPH_C32(0x30ba0000), + SPH_C32(0x8c484fd7), SPH_C32(0xa4935af4), SPH_C32(0x0f6cdcf0), + SPH_C32(0x00ca9e67) }, + { SPH_C32(0xb72e0039), SPH_C32(0x5568c000), SPH_C32(0x81b10000), + SPH_C32(0x5b230000), SPH_C32(0xd455782e), SPH_C32(0xa569b086), + SPH_C32(0xfd15dea1), SPH_C32(0xe7f6da36), SPH_C32(0x0bf201b0), + SPH_C32(0x7bb4c000), SPH_C32(0x00a10000), SPH_C32(0xf5ae0000), + SPH_C32(0x51313656), SPH_C32(0x679f0936), SPH_C32(0x5a9fc1ed), + SPH_C32(0x2019e776) }, + { SPH_C32(0x41ae003c), SPH_C32(0x612b0000), SPH_C32(0xa5b60000), + SPH_C32(0xd41e0000), SPH_C32(0xf56243d5), SPH_C32(0xafd16528), + SPH_C32(0x30d055b8), SPH_C32(0x30636007), SPH_C32(0xad8d01b1), + SPH_C32(0x0a834000), SPH_C32(0x195d0000), SPH_C32(0x63750000), + SPH_C32(0x6bba5bab), SPH_C32(0x8c55a7c5), SPH_C32(0x76f28662), + SPH_C32(0x8c978bfe) }, + { SPH_C32(0x11510038), SPH_C32(0x245f4000), SPH_C32(0x984d0000), + SPH_C32(0xcdf80000), SPH_C32(0xeede15d3), SPH_C32(0x4ea31e75), + SPH_C32(0xd178992e), SPH_C32(0x4b78b6be), SPH_C32(0x5b0d01b4), + SPH_C32(0x3ec08000), SPH_C32(0x3d5a0000), SPH_C32(0xec480000), + SPH_C32(0x4a8d6050), SPH_C32(0x86ed726b), SPH_C32(0xbb370d7b), + SPH_C32(0x5b0231cf) }, + { SPH_C32(0xe7d1003d), SPH_C32(0x101c8000), SPH_C32(0xbc4a0000), + SPH_C32(0x42c50000), SPH_C32(0xcfe92e28), SPH_C32(0x441bcbdb), + SPH_C32(0x1cbd1237), SPH_C32(0x9ced0c8f), SPH_C32(0xfd7201b5), + SPH_C32(0x4ff70000), SPH_C32(0x24a60000), SPH_C32(0x7a930000), + SPH_C32(0x70060dad), SPH_C32(0x6d27dc98), SPH_C32(0x975a4af4), + SPH_C32(0xf78c5d47) }, + { SPH_C32(0x94310030), SPH_C32(0x179cc000), SPH_C32(0xe7c80000), + SPH_C32(0x15980000), SPH_C32(0x2a8e23fd), SPH_C32(0x94350050), + SPH_C32(0x1fa4b9eb), SPH_C32(0x8ea6810c), SPH_C32(0xfc8701b9), + SPH_C32(0xb4880000), SPH_C32(0xc3770000), SPH_C32(0xf13c0000), + SPH_C32(0x53a42fff), SPH_C32(0x9f773f8c), SPH_C32(0x201830a3), + SPH_C32(0xbe0f7f6c) }, + { SPH_C32(0x62b10035), SPH_C32(0x23df0000), SPH_C32(0xc3cf0000), + SPH_C32(0x9aa50000), SPH_C32(0x0bb91806), SPH_C32(0x9e8dd5fe), + SPH_C32(0xd26132f2), SPH_C32(0x59333b3d), SPH_C32(0x5af801b8), + SPH_C32(0xc5bf8000), SPH_C32(0xda8b0000), SPH_C32(0x67e70000), + SPH_C32(0x692f4202), SPH_C32(0x74bd917f), SPH_C32(0x0c75772c), + SPH_C32(0x128113e4) }, + { SPH_C32(0x324e0031), SPH_C32(0x66ab4000), SPH_C32(0xfe340000), + SPH_C32(0x83430000), SPH_C32(0x10054e00), SPH_C32(0x7fffaea3), + SPH_C32(0x33c9fe64), SPH_C32(0x2228ed84), SPH_C32(0xac7801bd), + SPH_C32(0xf1fc4000), SPH_C32(0xfe8c0000), SPH_C32(0xe8da0000), + SPH_C32(0x481879f9), SPH_C32(0x7e0544d1), SPH_C32(0xc1b0fc35), + SPH_C32(0xc514a9d5) }, + { SPH_C32(0xc4ce0034), SPH_C32(0x52e88000), SPH_C32(0xda330000), + SPH_C32(0x0c7e0000), SPH_C32(0x313275fb), SPH_C32(0x75477b0d), + SPH_C32(0xfe0c757d), SPH_C32(0xf5bd57b5), SPH_C32(0x0a0701bc), + SPH_C32(0x80cbc000), SPH_C32(0xe7700000), SPH_C32(0x7e010000), + SPH_C32(0x72931404), SPH_C32(0x95cfea22), SPH_C32(0xedddbbba), + SPH_C32(0x699ac55d) }, + { SPH_C32(0x63440039), SPH_C32(0xd8a00000), SPH_C32(0x241e0000), + SPH_C32(0x110a0000), SPH_C32(0x281b3a54), SPH_C32(0x6cdd36ea), + SPH_C32(0x652348a5), SPH_C32(0x10b01916), SPH_C32(0x28ed01b9), + SPH_C32(0x3940c000), SPH_C32(0x66d80000), SPH_C32(0xbb150000), + SPH_C32(0xafea6d85), SPH_C32(0x56c3b9e0), SPH_C32(0xb82ea6a7), + SPH_C32(0x4949bc4c) }, + { SPH_C32(0x95c4003c), SPH_C32(0xece3c000), SPH_C32(0x00190000), + SPH_C32(0x9e370000), SPH_C32(0x092c01af), SPH_C32(0x6665e344), + SPH_C32(0xa8e6c3bc), SPH_C32(0xc725a327), SPH_C32(0x8e9201b8), + SPH_C32(0x48774000), SPH_C32(0x7f240000), SPH_C32(0x2dce0000), + SPH_C32(0x95610078), SPH_C32(0xbd091713), SPH_C32(0x9443e128), + SPH_C32(0xe5c7d0c4) }, + { SPH_C32(0xc53b0038), SPH_C32(0xa9978000), SPH_C32(0x3de20000), + SPH_C32(0x87d10000), SPH_C32(0x129057a9), SPH_C32(0x87179819), + SPH_C32(0x494e0f2a), SPH_C32(0xbc3e759e), SPH_C32(0x781201bd), + SPH_C32(0x7c348000), SPH_C32(0x5b230000), SPH_C32(0xa2f30000), + SPH_C32(0xb4563b83), SPH_C32(0xb7b1c2bd), SPH_C32(0x59866a31), + SPH_C32(0x32526af5) }, + { SPH_C32(0x33bb003d), SPH_C32(0x9dd44000), SPH_C32(0x19e50000), + SPH_C32(0x08ec0000), SPH_C32(0x33a76c52), SPH_C32(0x8daf4db7), + SPH_C32(0x848b8433), SPH_C32(0x6babcfaf), SPH_C32(0xde6d01bc), + SPH_C32(0x0d030000), SPH_C32(0x42df0000), SPH_C32(0x34280000), + SPH_C32(0x8edd567e), SPH_C32(0x5c7b6c4e), SPH_C32(0x75eb2dbe), + SPH_C32(0x9edc067d) }, + { SPH_C32(0x371f00c0), SPH_C32(0x6b0e0000), SPH_C32(0xb7d50000), + SPH_C32(0x6ba50000), SPH_C32(0x5ff71f0b), SPH_C32(0x070a6a19), + SPH_C32(0x8c51e2f1), SPH_C32(0xb6d737e7), SPH_C32(0x2bf401e0), + SPH_C32(0x60640000), SPH_C32(0xb1ab0000), SPH_C32(0xbc980000), + SPH_C32(0xefeb0a94), SPH_C32(0xc894f143), SPH_C32(0x5e0d273b), + SPH_C32(0x5d6b3122) }, + { SPH_C32(0xc19f00c5), SPH_C32(0x5f4dc000), SPH_C32(0x93d20000), + SPH_C32(0xe4980000), SPH_C32(0x7ec024f0), SPH_C32(0x0db2bfb7), + SPH_C32(0x419469e8), SPH_C32(0x61428dd6), SPH_C32(0x8d8b01e1), + SPH_C32(0x11538000), SPH_C32(0xa8570000), SPH_C32(0x2a430000), + SPH_C32(0xd5606769), SPH_C32(0x235e5fb0), SPH_C32(0x726060b4), + SPH_C32(0xf1e55daa) }, + { SPH_C32(0x916000c1), SPH_C32(0x1a398000), SPH_C32(0xae290000), + SPH_C32(0xfd7e0000), SPH_C32(0x657c72f6), SPH_C32(0xecc0c4ea), + SPH_C32(0xa03ca57e), SPH_C32(0x1a595b6f), SPH_C32(0x7b0b01e4), + SPH_C32(0x25104000), SPH_C32(0x8c500000), SPH_C32(0xa57e0000), + SPH_C32(0xf4575c92), SPH_C32(0x29e68a1e), SPH_C32(0xbfa5ebad), + SPH_C32(0x2670e79b) }, + { SPH_C32(0x67e000c4), SPH_C32(0x2e7a4000), SPH_C32(0x8a2e0000), + SPH_C32(0x72430000), SPH_C32(0x444b490d), SPH_C32(0xe6781144), + SPH_C32(0x6df92e67), SPH_C32(0xcdcce15e), SPH_C32(0xdd7401e5), + SPH_C32(0x5427c000), SPH_C32(0x95ac0000), SPH_C32(0x33a50000), + SPH_C32(0xcedc316f), SPH_C32(0xc22c24ed), SPH_C32(0x93c8ac22), + SPH_C32(0x8afe8b13) }, + { SPH_C32(0xc06a00c9), SPH_C32(0xa432c000), SPH_C32(0x74030000), + SPH_C32(0x6f370000), SPH_C32(0x5d6206a2), SPH_C32(0xffe25ca3), + SPH_C32(0xf6d613bf), SPH_C32(0x28c1affd), SPH_C32(0xff9e01e0), + SPH_C32(0xedacc000), SPH_C32(0x14040000), SPH_C32(0xf6b10000), + SPH_C32(0x13a548ee), SPH_C32(0x0120772f), SPH_C32(0xc63bb13f), + SPH_C32(0xaa2df202) }, + { SPH_C32(0x36ea00cc), SPH_C32(0x90710000), SPH_C32(0x50040000), + SPH_C32(0xe00a0000), SPH_C32(0x7c553d59), SPH_C32(0xf55a890d), + SPH_C32(0x3b1398a6), SPH_C32(0xff5415cc), SPH_C32(0x59e101e1), + SPH_C32(0x9c9b4000), SPH_C32(0x0df80000), SPH_C32(0x606a0000), + SPH_C32(0x292e2513), SPH_C32(0xeaead9dc), SPH_C32(0xea56f6b0), + SPH_C32(0x06a39e8a) }, + { SPH_C32(0x661500c8), SPH_C32(0xd5054000), SPH_C32(0x6dff0000), + SPH_C32(0xf9ec0000), SPH_C32(0x67e96b5f), SPH_C32(0x1428f250), + SPH_C32(0xdabb5430), SPH_C32(0x844fc375), SPH_C32(0xaf6101e4), + SPH_C32(0xa8d88000), SPH_C32(0x29ff0000), SPH_C32(0xef570000), + SPH_C32(0x08191ee8), SPH_C32(0xe0520c72), SPH_C32(0x27937da9), + SPH_C32(0xd13624bb) }, + { SPH_C32(0x909500cd), SPH_C32(0xe1468000), SPH_C32(0x49f80000), + SPH_C32(0x76d10000), SPH_C32(0x46de50a4), SPH_C32(0x1e9027fe), + SPH_C32(0x177edf29), SPH_C32(0x53da7944), SPH_C32(0x091e01e5), + SPH_C32(0xd9ef0000), SPH_C32(0x30030000), SPH_C32(0x798c0000), + SPH_C32(0x32927315), SPH_C32(0x0b98a281), SPH_C32(0x0bfe3a26), + SPH_C32(0x7db84833) }, + { SPH_C32(0xe37500c0), SPH_C32(0xe6c6c000), SPH_C32(0x127a0000), + SPH_C32(0x218c0000), SPH_C32(0xa3b95d71), SPH_C32(0xcebeec75), + SPH_C32(0x146774f5), SPH_C32(0x4191f4c7), SPH_C32(0x08eb01e9), + SPH_C32(0x22900000), SPH_C32(0xd7d20000), SPH_C32(0xf2230000), + SPH_C32(0x11305147), SPH_C32(0xf9c84195), SPH_C32(0xbcbc4071), + SPH_C32(0x343b6a18) }, + { SPH_C32(0x15f500c5), SPH_C32(0xd2850000), SPH_C32(0x367d0000), + SPH_C32(0xaeb10000), SPH_C32(0x828e668a), SPH_C32(0xc40639db), + SPH_C32(0xd9a2ffec), SPH_C32(0x96044ef6), SPH_C32(0xae9401e8), + SPH_C32(0x53a78000), SPH_C32(0xce2e0000), SPH_C32(0x64f80000), + SPH_C32(0x2bbb3cba), SPH_C32(0x1202ef66), SPH_C32(0x90d107fe), + SPH_C32(0x98b50690) }, + { SPH_C32(0x450a00c1), SPH_C32(0x97f14000), SPH_C32(0x0b860000), + SPH_C32(0xb7570000), SPH_C32(0x9932308c), SPH_C32(0x25744286), + SPH_C32(0x380a337a), SPH_C32(0xed1f984f), SPH_C32(0x581401ed), + SPH_C32(0x67e44000), SPH_C32(0xea290000), SPH_C32(0xebc50000), + SPH_C32(0x0a8c0741), SPH_C32(0x18ba3ac8), SPH_C32(0x5d148ce7), + SPH_C32(0x4f20bca1) }, + { SPH_C32(0xb38a00c4), SPH_C32(0xa3b28000), SPH_C32(0x2f810000), + SPH_C32(0x386a0000), SPH_C32(0xb8050b77), SPH_C32(0x2fcc9728), + SPH_C32(0xf5cfb863), SPH_C32(0x3a8a227e), SPH_C32(0xfe6b01ec), + SPH_C32(0x16d3c000), SPH_C32(0xf3d50000), SPH_C32(0x7d1e0000), + SPH_C32(0x30076abc), SPH_C32(0xf370943b), SPH_C32(0x7179cb68), + SPH_C32(0xe3aed029) }, + { SPH_C32(0x140000c9), SPH_C32(0x29fa0000), SPH_C32(0xd1ac0000), + SPH_C32(0x251e0000), SPH_C32(0xa12c44d8), SPH_C32(0x3656dacf), + SPH_C32(0x6ee085bb), SPH_C32(0xdf876cdd), SPH_C32(0xdc8101e9), + SPH_C32(0xaf58c000), SPH_C32(0x727d0000), SPH_C32(0xb80a0000), + SPH_C32(0xed7e133d), SPH_C32(0x307cc7f9), SPH_C32(0x248ad675), + SPH_C32(0xc37da938) }, + { SPH_C32(0xe28000cc), SPH_C32(0x1db9c000), SPH_C32(0xf5ab0000), + SPH_C32(0xaa230000), SPH_C32(0x801b7f23), SPH_C32(0x3cee0f61), + SPH_C32(0xa3250ea2), SPH_C32(0x0812d6ec), SPH_C32(0x7afe01e8), + SPH_C32(0xde6f4000), SPH_C32(0x6b810000), SPH_C32(0x2ed10000), + SPH_C32(0xd7f57ec0), SPH_C32(0xdbb6690a), SPH_C32(0x08e791fa), + SPH_C32(0x6ff3c5b0) }, + { SPH_C32(0xb27f00c8), SPH_C32(0x58cd8000), SPH_C32(0xc8500000), + SPH_C32(0xb3c50000), SPH_C32(0x9ba72925), SPH_C32(0xdd9c743c), + SPH_C32(0x428dc234), SPH_C32(0x73090055), SPH_C32(0x8c7e01ed), + SPH_C32(0xea2c8000), SPH_C32(0x4f860000), SPH_C32(0xa1ec0000), + SPH_C32(0xf6c2453b), SPH_C32(0xd10ebca4), SPH_C32(0xc5221ae3), + SPH_C32(0xb8667f81) }, + { SPH_C32(0x44ff00cd), SPH_C32(0x6c8e4000), SPH_C32(0xec570000), + SPH_C32(0x3cf80000), SPH_C32(0xba9012de), SPH_C32(0xd724a192), + SPH_C32(0x8f48492d), SPH_C32(0xa49cba64), SPH_C32(0x2a0101ec), + SPH_C32(0x9b1b0000), SPH_C32(0x567a0000), SPH_C32(0x37370000), + SPH_C32(0xcc4928c6), SPH_C32(0x3ac41257), SPH_C32(0xe94f5d6c), + SPH_C32(0x14e81309) }, + { SPH_C32(0x5cb00110), SPH_C32(0x913e0000), SPH_C32(0x44190000), + SPH_C32(0x888c0000), SPH_C32(0x66dc7418), SPH_C32(0x921f1d66), + SPH_C32(0x55ceea25), SPH_C32(0x925c44e9), SPH_C32(0xe8870170), + SPH_C32(0x9d720000), SPH_C32(0x12db0000), SPH_C32(0xd4220000), + SPH_C32(0xf2886b27), SPH_C32(0xa921e543), SPH_C32(0x4ef8b518), + SPH_C32(0x618813b1) }, + { SPH_C32(0xaa300115), SPH_C32(0xa57dc000), SPH_C32(0x601e0000), + SPH_C32(0x07b10000), SPH_C32(0x47eb4fe3), SPH_C32(0x98a7c8c8), + SPH_C32(0x980b613c), SPH_C32(0x45c9fed8), SPH_C32(0x4ef80171), + SPH_C32(0xec458000), SPH_C32(0x0b270000), SPH_C32(0x42f90000), + SPH_C32(0xc80306da), SPH_C32(0x42eb4bb0), SPH_C32(0x6295f297), + SPH_C32(0xcd067f39) }, + { SPH_C32(0xfacf0111), SPH_C32(0xe0098000), SPH_C32(0x5de50000), + SPH_C32(0x1e570000), SPH_C32(0x5c5719e5), SPH_C32(0x79d5b395), + SPH_C32(0x79a3adaa), SPH_C32(0x3ed22861), SPH_C32(0xb8780174), + SPH_C32(0xd8064000), SPH_C32(0x2f200000), SPH_C32(0xcdc40000), + SPH_C32(0xe9343d21), SPH_C32(0x48539e1e), SPH_C32(0xaf50798e), + SPH_C32(0x1a93c508) }, + { SPH_C32(0x0c4f0114), SPH_C32(0xd44a4000), SPH_C32(0x79e20000), + SPH_C32(0x916a0000), SPH_C32(0x7d60221e), SPH_C32(0x736d663b), + SPH_C32(0xb46626b3), SPH_C32(0xe9479250), SPH_C32(0x1e070175), + SPH_C32(0xa931c000), SPH_C32(0x36dc0000), SPH_C32(0x5b1f0000), + SPH_C32(0xd3bf50dc), SPH_C32(0xa39930ed), SPH_C32(0x833d3e01), + SPH_C32(0xb61da980) }, + { SPH_C32(0xabc50119), SPH_C32(0x5e02c000), SPH_C32(0x87cf0000), + SPH_C32(0x8c1e0000), SPH_C32(0x64496db1), SPH_C32(0x6af72bdc), + SPH_C32(0x2f491b6b), SPH_C32(0x0c4adcf3), SPH_C32(0x3ced0170), + SPH_C32(0x10bac000), SPH_C32(0xb7740000), SPH_C32(0x9e0b0000), + SPH_C32(0x0ec6295d), SPH_C32(0x6095632f), SPH_C32(0xd6ce231c), + SPH_C32(0x96ced091) }, + { SPH_C32(0x5d45011c), SPH_C32(0x6a410000), SPH_C32(0xa3c80000), + SPH_C32(0x03230000), SPH_C32(0x457e564a), SPH_C32(0x604ffe72), + SPH_C32(0xe28c9072), SPH_C32(0xdbdf66c2), SPH_C32(0x9a920171), + SPH_C32(0x618d4000), SPH_C32(0xae880000), SPH_C32(0x08d00000), + SPH_C32(0x344d44a0), SPH_C32(0x8b5fcddc), SPH_C32(0xfaa36493), + SPH_C32(0x3a40bc19) }, + { SPH_C32(0x0dba0118), SPH_C32(0x2f354000), SPH_C32(0x9e330000), + SPH_C32(0x1ac50000), SPH_C32(0x5ec2004c), SPH_C32(0x813d852f), + SPH_C32(0x03245ce4), SPH_C32(0xa0c4b07b), SPH_C32(0x6c120174), + SPH_C32(0x55ce8000), SPH_C32(0x8a8f0000), SPH_C32(0x87ed0000), + SPH_C32(0x157a7f5b), SPH_C32(0x81e71872), SPH_C32(0x3766ef8a), + SPH_C32(0xedd50628) }, + { SPH_C32(0xfb3a011d), SPH_C32(0x1b768000), SPH_C32(0xba340000), + SPH_C32(0x95f80000), SPH_C32(0x7ff53bb7), SPH_C32(0x8b855081), + SPH_C32(0xcee1d7fd), SPH_C32(0x77510a4a), SPH_C32(0xca6d0175), + SPH_C32(0x24f90000), SPH_C32(0x93730000), SPH_C32(0x11360000), + SPH_C32(0x2ff112a6), SPH_C32(0x6a2db681), SPH_C32(0x1b0ba805), + SPH_C32(0x415b6aa0) }, + { SPH_C32(0x88da0110), SPH_C32(0x1cf6c000), SPH_C32(0xe1b60000), + SPH_C32(0xc2a50000), SPH_C32(0x9a923662), SPH_C32(0x5bab9b0a), + SPH_C32(0xcdf87c21), SPH_C32(0x651a87c9), SPH_C32(0xcb980179), + SPH_C32(0xdf860000), SPH_C32(0x74a20000), SPH_C32(0x9a990000), + SPH_C32(0x0c5330f4), SPH_C32(0x987d5595), SPH_C32(0xac49d252), + SPH_C32(0x08d8488b) }, + { SPH_C32(0x7e5a0115), SPH_C32(0x28b50000), SPH_C32(0xc5b10000), + SPH_C32(0x4d980000), SPH_C32(0xbba50d99), SPH_C32(0x51134ea4), + SPH_C32(0x003df738), SPH_C32(0xb28f3df8), SPH_C32(0x6de70178), + SPH_C32(0xaeb18000), SPH_C32(0x6d5e0000), SPH_C32(0x0c420000), + SPH_C32(0x36d85d09), SPH_C32(0x73b7fb66), SPH_C32(0x802495dd), + SPH_C32(0xa4562403) }, + { SPH_C32(0x2ea50111), SPH_C32(0x6dc14000), SPH_C32(0xf84a0000), + SPH_C32(0x547e0000), SPH_C32(0xa0195b9f), SPH_C32(0xb06135f9), + SPH_C32(0xe1953bae), SPH_C32(0xc994eb41), SPH_C32(0x9b67017d), + SPH_C32(0x9af24000), SPH_C32(0x49590000), SPH_C32(0x837f0000), + SPH_C32(0x17ef66f2), SPH_C32(0x790f2ec8), SPH_C32(0x4de11ec4), + SPH_C32(0x73c39e32) }, + { SPH_C32(0xd8250114), SPH_C32(0x59828000), SPH_C32(0xdc4d0000), + SPH_C32(0xdb430000), SPH_C32(0x812e6064), SPH_C32(0xbad9e057), + SPH_C32(0x2c50b0b7), SPH_C32(0x1e015170), SPH_C32(0x3d18017c), + SPH_C32(0xebc5c000), SPH_C32(0x50a50000), SPH_C32(0x15a40000), + SPH_C32(0x2d640b0f), SPH_C32(0x92c5803b), SPH_C32(0x618c594b), + SPH_C32(0xdf4df2ba) }, + { SPH_C32(0x7faf0119), SPH_C32(0xd3ca0000), SPH_C32(0x22600000), + SPH_C32(0xc6370000), SPH_C32(0x98072fcb), SPH_C32(0xa343adb0), + SPH_C32(0xb77f8d6f), SPH_C32(0xfb0c1fd3), SPH_C32(0x1ff20179), + SPH_C32(0x524ec000), SPH_C32(0xd10d0000), SPH_C32(0xd0b00000), + SPH_C32(0xf01d728e), SPH_C32(0x51c9d3f9), SPH_C32(0x347f4456), + SPH_C32(0xff9e8bab) }, + { SPH_C32(0x892f011c), SPH_C32(0xe789c000), SPH_C32(0x06670000), + SPH_C32(0x490a0000), SPH_C32(0xb9301430), SPH_C32(0xa9fb781e), + SPH_C32(0x7aba0676), SPH_C32(0x2c99a5e2), SPH_C32(0xb98d0178), + SPH_C32(0x23794000), SPH_C32(0xc8f10000), SPH_C32(0x466b0000), + SPH_C32(0xca961f73), SPH_C32(0xba037d0a), SPH_C32(0x181203d9), + SPH_C32(0x5310e723) }, + { SPH_C32(0xd9d00118), SPH_C32(0xa2fd8000), SPH_C32(0x3b9c0000), + SPH_C32(0x50ec0000), SPH_C32(0xa28c4236), SPH_C32(0x48890343), + SPH_C32(0x9b12cae0), SPH_C32(0x5782735b), SPH_C32(0x4f0d017d), + SPH_C32(0x173a8000), SPH_C32(0xecf60000), SPH_C32(0xc9560000), + SPH_C32(0xeba12488), SPH_C32(0xb0bba8a4), SPH_C32(0xd5d788c0), + SPH_C32(0x84855d12) }, + { SPH_C32(0x2f50011d), SPH_C32(0x96be4000), SPH_C32(0x1f9b0000), + SPH_C32(0xdfd10000), SPH_C32(0x83bb79cd), SPH_C32(0x4231d6ed), + SPH_C32(0x56d741f9), SPH_C32(0x8017c96a), SPH_C32(0xe972017c), + SPH_C32(0x660d0000), SPH_C32(0xf50a0000), SPH_C32(0x5f8d0000), + SPH_C32(0xd12a4975), SPH_C32(0x5b710657), SPH_C32(0xf9bacf4f), + SPH_C32(0x280b319a) }, + { SPH_C32(0x2bf401e0), SPH_C32(0x60640000), SPH_C32(0xb1ab0000), + SPH_C32(0xbc980000), SPH_C32(0xefeb0a94), SPH_C32(0xc894f143), + SPH_C32(0x5e0d273b), SPH_C32(0x5d6b3122), SPH_C32(0x1ceb0120), + SPH_C32(0x0b6a0000), SPH_C32(0x067e0000), SPH_C32(0xd73d0000), + SPH_C32(0xb01c159f), SPH_C32(0xcf9e9b5a), SPH_C32(0xd25cc5ca), + SPH_C32(0xebbc06c5) }, + { SPH_C32(0xdd7401e5), SPH_C32(0x5427c000), SPH_C32(0x95ac0000), + SPH_C32(0x33a50000), SPH_C32(0xcedc316f), SPH_C32(0xc22c24ed), + SPH_C32(0x93c8ac22), SPH_C32(0x8afe8b13), SPH_C32(0xba940121), + SPH_C32(0x7a5d8000), SPH_C32(0x1f820000), SPH_C32(0x41e60000), + SPH_C32(0x8a977862), SPH_C32(0x245435a9), SPH_C32(0xfe318245), + SPH_C32(0x47326a4d) }, + { SPH_C32(0x8d8b01e1), SPH_C32(0x11538000), SPH_C32(0xa8570000), + SPH_C32(0x2a430000), SPH_C32(0xd5606769), SPH_C32(0x235e5fb0), + SPH_C32(0x726060b4), SPH_C32(0xf1e55daa), SPH_C32(0x4c140124), + SPH_C32(0x4e1e4000), SPH_C32(0x3b850000), SPH_C32(0xcedb0000), + SPH_C32(0xaba04399), SPH_C32(0x2eece007), SPH_C32(0x33f4095c), + SPH_C32(0x90a7d07c) }, + { SPH_C32(0x7b0b01e4), SPH_C32(0x25104000), SPH_C32(0x8c500000), + SPH_C32(0xa57e0000), SPH_C32(0xf4575c92), SPH_C32(0x29e68a1e), + SPH_C32(0xbfa5ebad), SPH_C32(0x2670e79b), SPH_C32(0xea6b0125), + SPH_C32(0x3f29c000), SPH_C32(0x22790000), SPH_C32(0x58000000), + SPH_C32(0x912b2e64), SPH_C32(0xc5264ef4), SPH_C32(0x1f994ed3), + SPH_C32(0x3c29bcf4) }, + { SPH_C32(0xdc8101e9), SPH_C32(0xaf58c000), SPH_C32(0x727d0000), + SPH_C32(0xb80a0000), SPH_C32(0xed7e133d), SPH_C32(0x307cc7f9), + SPH_C32(0x248ad675), SPH_C32(0xc37da938), SPH_C32(0xc8810120), + SPH_C32(0x86a2c000), SPH_C32(0xa3d10000), SPH_C32(0x9d140000), + SPH_C32(0x4c5257e5), SPH_C32(0x062a1d36), SPH_C32(0x4a6a53ce), + SPH_C32(0x1cfac5e5) }, + { SPH_C32(0x2a0101ec), SPH_C32(0x9b1b0000), SPH_C32(0x567a0000), + SPH_C32(0x37370000), SPH_C32(0xcc4928c6), SPH_C32(0x3ac41257), + SPH_C32(0xe94f5d6c), SPH_C32(0x14e81309), SPH_C32(0x6efe0121), + SPH_C32(0xf7954000), SPH_C32(0xba2d0000), SPH_C32(0x0bcf0000), + SPH_C32(0x76d93a18), SPH_C32(0xede0b3c5), SPH_C32(0x66071441), + SPH_C32(0xb074a96d) }, + { SPH_C32(0x7afe01e8), SPH_C32(0xde6f4000), SPH_C32(0x6b810000), + SPH_C32(0x2ed10000), SPH_C32(0xd7f57ec0), SPH_C32(0xdbb6690a), + SPH_C32(0x08e791fa), SPH_C32(0x6ff3c5b0), SPH_C32(0x987e0124), + SPH_C32(0xc3d68000), SPH_C32(0x9e2a0000), SPH_C32(0x84f20000), + SPH_C32(0x57ee01e3), SPH_C32(0xe758666b), SPH_C32(0xabc29f58), + SPH_C32(0x67e1135c) }, + { SPH_C32(0x8c7e01ed), SPH_C32(0xea2c8000), SPH_C32(0x4f860000), + SPH_C32(0xa1ec0000), SPH_C32(0xf6c2453b), SPH_C32(0xd10ebca4), + SPH_C32(0xc5221ae3), SPH_C32(0xb8667f81), SPH_C32(0x3e010125), + SPH_C32(0xb2e10000), SPH_C32(0x87d60000), SPH_C32(0x12290000), + SPH_C32(0x6d656c1e), SPH_C32(0x0c92c898), SPH_C32(0x87afd8d7), + SPH_C32(0xcb6f7fd4) }, + { SPH_C32(0xff9e01e0), SPH_C32(0xedacc000), SPH_C32(0x14040000), + SPH_C32(0xf6b10000), SPH_C32(0x13a548ee), SPH_C32(0x0120772f), + SPH_C32(0xc63bb13f), SPH_C32(0xaa2df202), SPH_C32(0x3ff40129), + SPH_C32(0x499e0000), SPH_C32(0x60070000), SPH_C32(0x99860000), + SPH_C32(0x4ec74e4c), SPH_C32(0xfec22b8c), SPH_C32(0x30eda280), + SPH_C32(0x82ec5dff) }, + { SPH_C32(0x091e01e5), SPH_C32(0xd9ef0000), SPH_C32(0x30030000), + SPH_C32(0x798c0000), SPH_C32(0x32927315), SPH_C32(0x0b98a281), + SPH_C32(0x0bfe3a26), SPH_C32(0x7db84833), SPH_C32(0x998b0128), + SPH_C32(0x38a98000), SPH_C32(0x79fb0000), SPH_C32(0x0f5d0000), + SPH_C32(0x744c23b1), SPH_C32(0x1508857f), SPH_C32(0x1c80e50f), + SPH_C32(0x2e623177) }, + { SPH_C32(0x59e101e1), SPH_C32(0x9c9b4000), SPH_C32(0x0df80000), + SPH_C32(0x606a0000), SPH_C32(0x292e2513), SPH_C32(0xeaead9dc), + SPH_C32(0xea56f6b0), SPH_C32(0x06a39e8a), SPH_C32(0x6f0b012d), + SPH_C32(0x0cea4000), SPH_C32(0x5dfc0000), SPH_C32(0x80600000), + SPH_C32(0x557b184a), SPH_C32(0x1fb050d1), SPH_C32(0xd1456e16), + SPH_C32(0xf9f78b46) }, + { SPH_C32(0xaf6101e4), SPH_C32(0xa8d88000), SPH_C32(0x29ff0000), + SPH_C32(0xef570000), SPH_C32(0x08191ee8), SPH_C32(0xe0520c72), + SPH_C32(0x27937da9), SPH_C32(0xd13624bb), SPH_C32(0xc974012c), + SPH_C32(0x7dddc000), SPH_C32(0x44000000), SPH_C32(0x16bb0000), + SPH_C32(0x6ff075b7), SPH_C32(0xf47afe22), SPH_C32(0xfd282999), + SPH_C32(0x5579e7ce) }, + { SPH_C32(0x08eb01e9), SPH_C32(0x22900000), SPH_C32(0xd7d20000), + SPH_C32(0xf2230000), SPH_C32(0x11305147), SPH_C32(0xf9c84195), + SPH_C32(0xbcbc4071), SPH_C32(0x343b6a18), SPH_C32(0xeb9e0129), + SPH_C32(0xc456c000), SPH_C32(0xc5a80000), SPH_C32(0xd3af0000), + SPH_C32(0xb2890c36), SPH_C32(0x3776ade0), SPH_C32(0xa8db3484), + SPH_C32(0x75aa9edf) }, + { SPH_C32(0xfe6b01ec), SPH_C32(0x16d3c000), SPH_C32(0xf3d50000), + SPH_C32(0x7d1e0000), SPH_C32(0x30076abc), SPH_C32(0xf370943b), + SPH_C32(0x7179cb68), SPH_C32(0xe3aed029), SPH_C32(0x4de10128), + SPH_C32(0xb5614000), SPH_C32(0xdc540000), SPH_C32(0x45740000), + SPH_C32(0x880261cb), SPH_C32(0xdcbc0313), SPH_C32(0x84b6730b), + SPH_C32(0xd924f257) }, + { SPH_C32(0xae9401e8), SPH_C32(0x53a78000), SPH_C32(0xce2e0000), + SPH_C32(0x64f80000), SPH_C32(0x2bbb3cba), SPH_C32(0x1202ef66), + SPH_C32(0x90d107fe), SPH_C32(0x98b50690), SPH_C32(0xbb61012d), + SPH_C32(0x81228000), SPH_C32(0xf8530000), SPH_C32(0xca490000), + SPH_C32(0xa9355a30), SPH_C32(0xd604d6bd), SPH_C32(0x4973f812), + SPH_C32(0x0eb14866) }, + { SPH_C32(0x581401ed), SPH_C32(0x67e44000), SPH_C32(0xea290000), + SPH_C32(0xebc50000), SPH_C32(0x0a8c0741), SPH_C32(0x18ba3ac8), + SPH_C32(0x5d148ce7), SPH_C32(0x4f20bca1), SPH_C32(0x1d1e012c), + SPH_C32(0xf0150000), SPH_C32(0xe1af0000), SPH_C32(0x5c920000), + SPH_C32(0x93be37cd), SPH_C32(0x3dce784e), SPH_C32(0x651ebf9d), + SPH_C32(0xa23f24ee) }, + { SPH_C32(0xa8dc0140), SPH_C32(0x07260000), SPH_C32(0x50bc0000), + SPH_C32(0x8b930000), SPH_C32(0x24480aa0), SPH_C32(0xf4a0637f), + SPH_C32(0xc96a9af7), SPH_C32(0x1868519d), SPH_C32(0x6baf01d0), + SPH_C32(0xfa300000), SPH_C32(0xf3cc0000), SPH_C32(0xe3290000), + SPH_C32(0x392b6b13), SPH_C32(0x9515777f), SPH_C32(0xd99f08d4), + SPH_C32(0x248b730e) }, + { SPH_C32(0x5e5c0145), SPH_C32(0x3365c000), SPH_C32(0x74bb0000), + SPH_C32(0x04ae0000), SPH_C32(0x057f315b), SPH_C32(0xfe18b6d1), + SPH_C32(0x04af11ee), SPH_C32(0xcffdebac), SPH_C32(0xcdd001d1), + SPH_C32(0x8b078000), SPH_C32(0xea300000), SPH_C32(0x75f20000), + SPH_C32(0x03a006ee), SPH_C32(0x7edfd98c), SPH_C32(0xf5f24f5b), + SPH_C32(0x88051f86) }, + { SPH_C32(0x0ea30141), SPH_C32(0x76118000), SPH_C32(0x49400000), + SPH_C32(0x1d480000), SPH_C32(0x1ec3675d), SPH_C32(0x1f6acd8c), + SPH_C32(0xe507dd78), SPH_C32(0xb4e63d15), SPH_C32(0x3b5001d4), + SPH_C32(0xbf444000), SPH_C32(0xce370000), SPH_C32(0xfacf0000), + SPH_C32(0x22973d15), SPH_C32(0x74670c22), SPH_C32(0x3837c442), + SPH_C32(0x5f90a5b7) }, + { SPH_C32(0xf8230144), SPH_C32(0x42524000), SPH_C32(0x6d470000), + SPH_C32(0x92750000), SPH_C32(0x3ff45ca6), SPH_C32(0x15d21822), + SPH_C32(0x28c25661), SPH_C32(0x63738724), SPH_C32(0x9d2f01d5), + SPH_C32(0xce73c000), SPH_C32(0xd7cb0000), SPH_C32(0x6c140000), + SPH_C32(0x181c50e8), SPH_C32(0x9fada2d1), SPH_C32(0x145a83cd), + SPH_C32(0xf31ec93f) }, + { SPH_C32(0x5fa90149), SPH_C32(0xc81ac000), SPH_C32(0x936a0000), + SPH_C32(0x8f010000), SPH_C32(0x26dd1309), SPH_C32(0x0c4855c5), + SPH_C32(0xb3ed6bb9), SPH_C32(0x867ec987), SPH_C32(0xbfc501d0), + SPH_C32(0x77f8c000), SPH_C32(0x56630000), SPH_C32(0xa9000000), + SPH_C32(0xc5652969), SPH_C32(0x5ca1f113), SPH_C32(0x41a99ed0), + SPH_C32(0xd3cdb02e) }, + { SPH_C32(0xa929014c), SPH_C32(0xfc590000), SPH_C32(0xb76d0000), + SPH_C32(0x003c0000), SPH_C32(0x07ea28f2), SPH_C32(0x06f0806b), + SPH_C32(0x7e28e0a0), SPH_C32(0x51eb73b6), SPH_C32(0x19ba01d1), + SPH_C32(0x06cf4000), SPH_C32(0x4f9f0000), SPH_C32(0x3fdb0000), + SPH_C32(0xffee4494), SPH_C32(0xb76b5fe0), SPH_C32(0x6dc4d95f), + SPH_C32(0x7f43dca6) }, + { SPH_C32(0xf9d60148), SPH_C32(0xb92d4000), SPH_C32(0x8a960000), + SPH_C32(0x19da0000), SPH_C32(0x1c567ef4), SPH_C32(0xe782fb36), + SPH_C32(0x9f802c36), SPH_C32(0x2af0a50f), SPH_C32(0xef3a01d4), + SPH_C32(0x328c8000), SPH_C32(0x6b980000), SPH_C32(0xb0e60000), + SPH_C32(0xded97f6f), SPH_C32(0xbdd38a4e), SPH_C32(0xa0015246), + SPH_C32(0xa8d66697) }, + { SPH_C32(0x0f56014d), SPH_C32(0x8d6e8000), SPH_C32(0xae910000), + SPH_C32(0x96e70000), SPH_C32(0x3d61450f), SPH_C32(0xed3a2e98), + SPH_C32(0x5245a72f), SPH_C32(0xfd651f3e), SPH_C32(0x494501d5), + SPH_C32(0x43bb0000), SPH_C32(0x72640000), SPH_C32(0x263d0000), + SPH_C32(0xe4521292), SPH_C32(0x561924bd), SPH_C32(0x8c6c15c9), + SPH_C32(0x04580a1f) }, + { SPH_C32(0x7cb60140), SPH_C32(0x8aeec000), SPH_C32(0xf5130000), + SPH_C32(0xc1ba0000), SPH_C32(0xd80648da), SPH_C32(0x3d14e513), + SPH_C32(0x515c0cf3), SPH_C32(0xef2e92bd), SPH_C32(0x48b001d9), + SPH_C32(0xb8c40000), SPH_C32(0x95b50000), SPH_C32(0xad920000), + SPH_C32(0xc7f030c0), SPH_C32(0xa449c7a9), SPH_C32(0x3b2e6f9e), + SPH_C32(0x4ddb2834) }, + { SPH_C32(0x8a360145), SPH_C32(0xbead0000), SPH_C32(0xd1140000), + SPH_C32(0x4e870000), SPH_C32(0xf9317321), SPH_C32(0x37ac30bd), + SPH_C32(0x9c9987ea), SPH_C32(0x38bb288c), SPH_C32(0xeecf01d8), + SPH_C32(0xc9f38000), SPH_C32(0x8c490000), SPH_C32(0x3b490000), + SPH_C32(0xfd7b5d3d), SPH_C32(0x4f83695a), SPH_C32(0x17432811), + SPH_C32(0xe15544bc) }, + { SPH_C32(0xdac90141), SPH_C32(0xfbd94000), SPH_C32(0xecef0000), + SPH_C32(0x57610000), SPH_C32(0xe28d2527), SPH_C32(0xd6de4be0), + SPH_C32(0x7d314b7c), SPH_C32(0x43a0fe35), SPH_C32(0x184f01dd), + SPH_C32(0xfdb04000), SPH_C32(0xa84e0000), SPH_C32(0xb4740000), + SPH_C32(0xdc4c66c6), SPH_C32(0x453bbcf4), SPH_C32(0xda86a308), + SPH_C32(0x36c0fe8d) }, + { SPH_C32(0x2c490144), SPH_C32(0xcf9a8000), SPH_C32(0xc8e80000), + SPH_C32(0xd85c0000), SPH_C32(0xc3ba1edc), SPH_C32(0xdc669e4e), + SPH_C32(0xb0f4c065), SPH_C32(0x94354404), SPH_C32(0xbe3001dc), + SPH_C32(0x8c87c000), SPH_C32(0xb1b20000), SPH_C32(0x22af0000), + SPH_C32(0xe6c70b3b), SPH_C32(0xaef11207), SPH_C32(0xf6ebe487), + SPH_C32(0x9a4e9205) }, + { SPH_C32(0x8bc30149), SPH_C32(0x45d20000), SPH_C32(0x36c50000), + SPH_C32(0xc5280000), SPH_C32(0xda935173), SPH_C32(0xc5fcd3a9), + SPH_C32(0x2bdbfdbd), SPH_C32(0x71380aa7), SPH_C32(0x9cda01d9), + SPH_C32(0x350cc000), SPH_C32(0x301a0000), SPH_C32(0xe7bb0000), + SPH_C32(0x3bbe72ba), SPH_C32(0x6dfd41c5), SPH_C32(0xa318f99a), + SPH_C32(0xba9deb14) }, + { SPH_C32(0x7d43014c), SPH_C32(0x7191c000), SPH_C32(0x12c20000), + SPH_C32(0x4a150000), SPH_C32(0xfba46a88), SPH_C32(0xcf440607), + SPH_C32(0xe61e76a4), SPH_C32(0xa6adb096), SPH_C32(0x3aa501d8), + SPH_C32(0x443b4000), SPH_C32(0x29e60000), SPH_C32(0x71600000), + SPH_C32(0x01351f47), SPH_C32(0x8637ef36), SPH_C32(0x8f75be15), + SPH_C32(0x1613879c) }, + { SPH_C32(0x2dbc0148), SPH_C32(0x34e58000), SPH_C32(0x2f390000), + SPH_C32(0x53f30000), SPH_C32(0xe0183c8e), SPH_C32(0x2e367d5a), + SPH_C32(0x07b6ba32), SPH_C32(0xddb6662f), SPH_C32(0xcc2501dd), + SPH_C32(0x70788000), SPH_C32(0x0de10000), SPH_C32(0xfe5d0000), + SPH_C32(0x200224bc), SPH_C32(0x8c8f3a98), SPH_C32(0x42b0350c), + SPH_C32(0xc1863dad) }, + { SPH_C32(0xdb3c014d), SPH_C32(0x00a64000), SPH_C32(0x0b3e0000), + SPH_C32(0xdcce0000), SPH_C32(0xc12f0775), SPH_C32(0x248ea8f4), + SPH_C32(0xca73312b), SPH_C32(0x0a23dc1e), SPH_C32(0x6a5a01dc), + SPH_C32(0x014f0000), SPH_C32(0x141d0000), SPH_C32(0x68860000), + SPH_C32(0x1a894941), SPH_C32(0x6745946b), SPH_C32(0x6edd7283), + SPH_C32(0x6d085125) }, + { SPH_C32(0xdf9801b0), SPH_C32(0xf67c0000), SPH_C32(0xa50e0000), + SPH_C32(0xbf870000), SPH_C32(0xad7f742c), SPH_C32(0xae2b8f5a), + SPH_C32(0xc2a957e9), SPH_C32(0xd75f2456), SPH_C32(0x9fc30180), + SPH_C32(0x6c280000), SPH_C32(0xe7690000), SPH_C32(0xe0360000), + SPH_C32(0x7bbf15ab), SPH_C32(0xf3aa0966), SPH_C32(0x453b7806), + SPH_C32(0xaebf667a) }, + { SPH_C32(0x291801b5), SPH_C32(0xc23fc000), SPH_C32(0x81090000), + SPH_C32(0x30ba0000), SPH_C32(0x8c484fd7), SPH_C32(0xa4935af4), + SPH_C32(0x0f6cdcf0), SPH_C32(0x00ca9e67), SPH_C32(0x39bc0181), + SPH_C32(0x1d1f8000), SPH_C32(0xfe950000), SPH_C32(0x76ed0000), + SPH_C32(0x41347856), SPH_C32(0x1860a795), SPH_C32(0x69563f89), + SPH_C32(0x02310af2) }, + { SPH_C32(0x79e701b1), SPH_C32(0x874b8000), SPH_C32(0xbcf20000), + SPH_C32(0x295c0000), SPH_C32(0x97f419d1), SPH_C32(0x45e121a9), + SPH_C32(0xeec41066), SPH_C32(0x7bd148de), SPH_C32(0xcf3c0184), + SPH_C32(0x295c4000), SPH_C32(0xda920000), SPH_C32(0xf9d00000), + SPH_C32(0x600343ad), SPH_C32(0x12d8723b), SPH_C32(0xa493b490), + SPH_C32(0xd5a4b0c3) }, + { SPH_C32(0x8f6701b4), SPH_C32(0xb3084000), SPH_C32(0x98f50000), + SPH_C32(0xa6610000), SPH_C32(0xb6c3222a), SPH_C32(0x4f59f407), + SPH_C32(0x23019b7f), SPH_C32(0xac44f2ef), SPH_C32(0x69430185), + SPH_C32(0x586bc000), SPH_C32(0xc36e0000), SPH_C32(0x6f0b0000), + SPH_C32(0x5a882e50), SPH_C32(0xf912dcc8), SPH_C32(0x88fef31f), + SPH_C32(0x792adc4b) }, + { SPH_C32(0x28ed01b9), SPH_C32(0x3940c000), SPH_C32(0x66d80000), + SPH_C32(0xbb150000), SPH_C32(0xafea6d85), SPH_C32(0x56c3b9e0), + SPH_C32(0xb82ea6a7), SPH_C32(0x4949bc4c), SPH_C32(0x4ba90180), + SPH_C32(0xe1e0c000), SPH_C32(0x42c60000), SPH_C32(0xaa1f0000), + SPH_C32(0x87f157d1), SPH_C32(0x3a1e8f0a), SPH_C32(0xdd0dee02), + SPH_C32(0x59f9a55a) }, + { SPH_C32(0xde6d01bc), SPH_C32(0x0d030000), SPH_C32(0x42df0000), + SPH_C32(0x34280000), SPH_C32(0x8edd567e), SPH_C32(0x5c7b6c4e), + SPH_C32(0x75eb2dbe), SPH_C32(0x9edc067d), SPH_C32(0xedd60181), + SPH_C32(0x90d74000), SPH_C32(0x5b3a0000), SPH_C32(0x3cc40000), + SPH_C32(0xbd7a3a2c), SPH_C32(0xd1d421f9), SPH_C32(0xf160a98d), + SPH_C32(0xf577c9d2) }, + { SPH_C32(0x8e9201b8), SPH_C32(0x48774000), SPH_C32(0x7f240000), + SPH_C32(0x2dce0000), SPH_C32(0x95610078), SPH_C32(0xbd091713), + SPH_C32(0x9443e128), SPH_C32(0xe5c7d0c4), SPH_C32(0x1b560184), + SPH_C32(0xa4948000), SPH_C32(0x7f3d0000), SPH_C32(0xb3f90000), + SPH_C32(0x9c4d01d7), SPH_C32(0xdb6cf457), SPH_C32(0x3ca52294), + SPH_C32(0x22e273e3) }, + { SPH_C32(0x781201bd), SPH_C32(0x7c348000), SPH_C32(0x5b230000), + SPH_C32(0xa2f30000), SPH_C32(0xb4563b83), SPH_C32(0xb7b1c2bd), + SPH_C32(0x59866a31), SPH_C32(0x32526af5), SPH_C32(0xbd290185), + SPH_C32(0xd5a30000), SPH_C32(0x66c10000), SPH_C32(0x25220000), + SPH_C32(0xa6c66c2a), SPH_C32(0x30a65aa4), SPH_C32(0x10c8651b), + SPH_C32(0x8e6c1f6b) }, + { SPH_C32(0x0bf201b0), SPH_C32(0x7bb4c000), SPH_C32(0x00a10000), + SPH_C32(0xf5ae0000), SPH_C32(0x51313656), SPH_C32(0x679f0936), + SPH_C32(0x5a9fc1ed), SPH_C32(0x2019e776), SPH_C32(0xbcdc0189), + SPH_C32(0x2edc0000), SPH_C32(0x81100000), SPH_C32(0xae8d0000), + SPH_C32(0x85644e78), SPH_C32(0xc2f6b9b0), SPH_C32(0xa78a1f4c), + SPH_C32(0xc7ef3d40) }, + { SPH_C32(0xfd7201b5), SPH_C32(0x4ff70000), SPH_C32(0x24a60000), + SPH_C32(0x7a930000), SPH_C32(0x70060dad), SPH_C32(0x6d27dc98), + SPH_C32(0x975a4af4), SPH_C32(0xf78c5d47), SPH_C32(0x1aa30188), + SPH_C32(0x5feb8000), SPH_C32(0x98ec0000), SPH_C32(0x38560000), + SPH_C32(0xbfef2385), SPH_C32(0x293c1743), SPH_C32(0x8be758c3), + SPH_C32(0x6b6151c8) }, + { SPH_C32(0xad8d01b1), SPH_C32(0x0a834000), SPH_C32(0x195d0000), + SPH_C32(0x63750000), SPH_C32(0x6bba5bab), SPH_C32(0x8c55a7c5), + SPH_C32(0x76f28662), SPH_C32(0x8c978bfe), SPH_C32(0xec23018d), + SPH_C32(0x6ba84000), SPH_C32(0xbceb0000), SPH_C32(0xb76b0000), + SPH_C32(0x9ed8187e), SPH_C32(0x2384c2ed), SPH_C32(0x4622d3da), + SPH_C32(0xbcf4ebf9) }, + { SPH_C32(0x5b0d01b4), SPH_C32(0x3ec08000), SPH_C32(0x3d5a0000), + SPH_C32(0xec480000), SPH_C32(0x4a8d6050), SPH_C32(0x86ed726b), + SPH_C32(0xbb370d7b), SPH_C32(0x5b0231cf), SPH_C32(0x4a5c018c), + SPH_C32(0x1a9fc000), SPH_C32(0xa5170000), SPH_C32(0x21b00000), + SPH_C32(0xa4537583), SPH_C32(0xc84e6c1e), SPH_C32(0x6a4f9455), + SPH_C32(0x107a8771) }, + { SPH_C32(0xfc8701b9), SPH_C32(0xb4880000), SPH_C32(0xc3770000), + SPH_C32(0xf13c0000), SPH_C32(0x53a42fff), SPH_C32(0x9f773f8c), + SPH_C32(0x201830a3), SPH_C32(0xbe0f7f6c), SPH_C32(0x68b60189), + SPH_C32(0xa314c000), SPH_C32(0x24bf0000), SPH_C32(0xe4a40000), + SPH_C32(0x792a0c02), SPH_C32(0x0b423fdc), SPH_C32(0x3fbc8948), + SPH_C32(0x30a9fe60) }, + { SPH_C32(0x0a0701bc), SPH_C32(0x80cbc000), SPH_C32(0xe7700000), + SPH_C32(0x7e010000), SPH_C32(0x72931404), SPH_C32(0x95cfea22), + SPH_C32(0xedddbbba), SPH_C32(0x699ac55d), SPH_C32(0xcec90188), + SPH_C32(0xd2234000), SPH_C32(0x3d430000), SPH_C32(0x727f0000), + SPH_C32(0x43a161ff), SPH_C32(0xe088912f), SPH_C32(0x13d1cec7), + SPH_C32(0x9c2792e8) }, + { SPH_C32(0x5af801b8), SPH_C32(0xc5bf8000), SPH_C32(0xda8b0000), + SPH_C32(0x67e70000), SPH_C32(0x692f4202), SPH_C32(0x74bd917f), + SPH_C32(0x0c75772c), SPH_C32(0x128113e4), SPH_C32(0x3849018d), + SPH_C32(0xe6608000), SPH_C32(0x19440000), SPH_C32(0xfd420000), + SPH_C32(0x62965a04), SPH_C32(0xea304481), SPH_C32(0xde1445de), + SPH_C32(0x4bb228d9) }, + { SPH_C32(0xac7801bd), SPH_C32(0xf1fc4000), SPH_C32(0xfe8c0000), + SPH_C32(0xe8da0000), SPH_C32(0x481879f9), SPH_C32(0x7e0544d1), + SPH_C32(0xc1b0fc35), SPH_C32(0xc514a9d5), SPH_C32(0x9e36018c), + SPH_C32(0x97570000), SPH_C32(0x00b80000), SPH_C32(0x6b990000), + SPH_C32(0x581d37f9), SPH_C32(0x01faea72), SPH_C32(0xf2790251), + SPH_C32(0xe73c4451) } +}; + +static const sph_u32 T512_16[256][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0x0c720000), SPH_C32(0x49e50f00), SPH_C32(0x42790000), + SPH_C32(0x5cea0000), SPH_C32(0x33aa301a), SPH_C32(0x15822514), + SPH_C32(0x95a34b7b), SPH_C32(0xb44b0090), SPH_C32(0xfe220000), + SPH_C32(0xa7580500), SPH_C32(0x25d10000), SPH_C32(0xf7600000), + SPH_C32(0x893178da), SPH_C32(0x1fd4f860), SPH_C32(0x4ed0a315), + SPH_C32(0xa123ff9f) }, + { SPH_C32(0xfe220000), SPH_C32(0xa7580500), SPH_C32(0x25d10000), + SPH_C32(0xf7600000), SPH_C32(0x893178da), SPH_C32(0x1fd4f860), + SPH_C32(0x4ed0a315), SPH_C32(0xa123ff9f), SPH_C32(0xf2500000), + SPH_C32(0xeebd0a00), SPH_C32(0x67a80000), SPH_C32(0xab8a0000), + SPH_C32(0xba9b48c0), SPH_C32(0x0a56dd74), SPH_C32(0xdb73e86e), + SPH_C32(0x1568ff0f) }, + { SPH_C32(0xf2500000), SPH_C32(0xeebd0a00), SPH_C32(0x67a80000), + SPH_C32(0xab8a0000), SPH_C32(0xba9b48c0), SPH_C32(0x0a56dd74), + SPH_C32(0xdb73e86e), SPH_C32(0x1568ff0f), SPH_C32(0x0c720000), + SPH_C32(0x49e50f00), SPH_C32(0x42790000), SPH_C32(0x5cea0000), + SPH_C32(0x33aa301a), SPH_C32(0x15822514), SPH_C32(0x95a34b7b), + SPH_C32(0xb44b0090) }, + { SPH_C32(0x45180000), SPH_C32(0xa5b51700), SPH_C32(0xf96a0000), + SPH_C32(0x3b480000), SPH_C32(0x1ecc142c), SPH_C32(0x231395d6), + SPH_C32(0x16bca6b0), SPH_C32(0xdf33f4df), SPH_C32(0xb83d0000), + SPH_C32(0x16710600), SPH_C32(0x379a0000), SPH_C32(0xf5b10000), + SPH_C32(0x228161ac), SPH_C32(0xae48f145), SPH_C32(0x66241616), + SPH_C32(0xc5c1eb3e) }, + { SPH_C32(0x496a0000), SPH_C32(0xec501800), SPH_C32(0xbb130000), + SPH_C32(0x67a20000), SPH_C32(0x2d662436), SPH_C32(0x3691b0c2), + SPH_C32(0x831fedcb), SPH_C32(0x6b78f44f), SPH_C32(0x461f0000), + SPH_C32(0xb1290300), SPH_C32(0x124b0000), SPH_C32(0x02d10000), + SPH_C32(0xabb01976), SPH_C32(0xb19c0925), SPH_C32(0x28f4b503), + SPH_C32(0x64e214a1) }, + { SPH_C32(0xbb3a0000), SPH_C32(0x02ed1200), SPH_C32(0xdcbb0000), + SPH_C32(0xcc280000), SPH_C32(0x97fd6cf6), SPH_C32(0x3cc76db6), + SPH_C32(0x586c05a5), SPH_C32(0x7e100b40), SPH_C32(0x4a6d0000), + SPH_C32(0xf8cc0c00), SPH_C32(0x50320000), SPH_C32(0x5e3b0000), + SPH_C32(0x981a296c), SPH_C32(0xa41e2c31), SPH_C32(0xbd57fe78), + SPH_C32(0xd0a91431) }, + { SPH_C32(0xb7480000), SPH_C32(0x4b081d00), SPH_C32(0x9ec20000), + SPH_C32(0x90c20000), SPH_C32(0xa4575cec), SPH_C32(0x294548a2), + SPH_C32(0xcdcf4ede), SPH_C32(0xca5b0bd0), SPH_C32(0xb44f0000), + SPH_C32(0x5f940900), SPH_C32(0x75e30000), SPH_C32(0xa95b0000), + SPH_C32(0x112b51b6), SPH_C32(0xbbcad451), SPH_C32(0xf3875d6d), + SPH_C32(0x718aebae) }, + { SPH_C32(0xb83d0000), SPH_C32(0x16710600), SPH_C32(0x379a0000), + SPH_C32(0xf5b10000), SPH_C32(0x228161ac), SPH_C32(0xae48f145), + SPH_C32(0x66241616), SPH_C32(0xc5c1eb3e), SPH_C32(0xfd250000), + SPH_C32(0xb3c41100), SPH_C32(0xcef00000), SPH_C32(0xcef90000), + SPH_C32(0x3c4d7580), SPH_C32(0x8d5b6493), SPH_C32(0x7098b0a6), + SPH_C32(0x1af21fe1) }, + { SPH_C32(0xb44f0000), SPH_C32(0x5f940900), SPH_C32(0x75e30000), + SPH_C32(0xa95b0000), SPH_C32(0x112b51b6), SPH_C32(0xbbcad451), + SPH_C32(0xf3875d6d), SPH_C32(0x718aebae), SPH_C32(0x03070000), + SPH_C32(0x149c1400), SPH_C32(0xeb210000), SPH_C32(0x39990000), + SPH_C32(0xb57c0d5a), SPH_C32(0x928f9cf3), SPH_C32(0x3e4813b3), + SPH_C32(0xbbd1e07e) }, + { SPH_C32(0x461f0000), SPH_C32(0xb1290300), SPH_C32(0x124b0000), + SPH_C32(0x02d10000), SPH_C32(0xabb01976), SPH_C32(0xb19c0925), + SPH_C32(0x28f4b503), SPH_C32(0x64e214a1), SPH_C32(0x0f750000), + SPH_C32(0x5d791b00), SPH_C32(0xa9580000), SPH_C32(0x65730000), + SPH_C32(0x86d63d40), SPH_C32(0x870db9e7), SPH_C32(0xabeb58c8), + SPH_C32(0x0f9ae0ee) }, + { SPH_C32(0x4a6d0000), SPH_C32(0xf8cc0c00), SPH_C32(0x50320000), + SPH_C32(0x5e3b0000), SPH_C32(0x981a296c), SPH_C32(0xa41e2c31), + SPH_C32(0xbd57fe78), SPH_C32(0xd0a91431), SPH_C32(0xf1570000), + SPH_C32(0xfa211e00), SPH_C32(0x8c890000), SPH_C32(0x92130000), + SPH_C32(0x0fe7459a), SPH_C32(0x98d94187), SPH_C32(0xe53bfbdd), + SPH_C32(0xaeb91f71) }, + { SPH_C32(0xfd250000), SPH_C32(0xb3c41100), SPH_C32(0xcef00000), + SPH_C32(0xcef90000), SPH_C32(0x3c4d7580), SPH_C32(0x8d5b6493), + SPH_C32(0x7098b0a6), SPH_C32(0x1af21fe1), SPH_C32(0x45180000), + SPH_C32(0xa5b51700), SPH_C32(0xf96a0000), SPH_C32(0x3b480000), + SPH_C32(0x1ecc142c), SPH_C32(0x231395d6), SPH_C32(0x16bca6b0), + SPH_C32(0xdf33f4df) }, + { SPH_C32(0xf1570000), SPH_C32(0xfa211e00), SPH_C32(0x8c890000), + SPH_C32(0x92130000), SPH_C32(0x0fe7459a), SPH_C32(0x98d94187), + SPH_C32(0xe53bfbdd), SPH_C32(0xaeb91f71), SPH_C32(0xbb3a0000), + SPH_C32(0x02ed1200), SPH_C32(0xdcbb0000), SPH_C32(0xcc280000), + SPH_C32(0x97fd6cf6), SPH_C32(0x3cc76db6), SPH_C32(0x586c05a5), + SPH_C32(0x7e100b40) }, + { SPH_C32(0x03070000), SPH_C32(0x149c1400), SPH_C32(0xeb210000), + SPH_C32(0x39990000), SPH_C32(0xb57c0d5a), SPH_C32(0x928f9cf3), + SPH_C32(0x3e4813b3), SPH_C32(0xbbd1e07e), SPH_C32(0xb7480000), + SPH_C32(0x4b081d00), SPH_C32(0x9ec20000), SPH_C32(0x90c20000), + SPH_C32(0xa4575cec), SPH_C32(0x294548a2), SPH_C32(0xcdcf4ede), + SPH_C32(0xca5b0bd0) }, + { SPH_C32(0x0f750000), SPH_C32(0x5d791b00), SPH_C32(0xa9580000), + SPH_C32(0x65730000), SPH_C32(0x86d63d40), SPH_C32(0x870db9e7), + SPH_C32(0xabeb58c8), SPH_C32(0x0f9ae0ee), SPH_C32(0x496a0000), + SPH_C32(0xec501800), SPH_C32(0xbb130000), SPH_C32(0x67a20000), + SPH_C32(0x2d662436), SPH_C32(0x3691b0c2), SPH_C32(0x831fedcb), + SPH_C32(0x6b78f44f) }, + { SPH_C32(0x75a40000), SPH_C32(0xc28b2700), SPH_C32(0x94a40000), + SPH_C32(0x90f50000), SPH_C32(0xfb7857e0), SPH_C32(0x49ce0bae), + SPH_C32(0x1767c483), SPH_C32(0xaedf667e), SPH_C32(0xd1660000), + SPH_C32(0x1bbc0300), SPH_C32(0x9eec0000), SPH_C32(0xf6940000), + SPH_C32(0x03024527), SPH_C32(0xcf70fcf2), SPH_C32(0xb4431b17), + SPH_C32(0x857f3c2b) }, + { SPH_C32(0x79d60000), SPH_C32(0x8b6e2800), SPH_C32(0xd6dd0000), + SPH_C32(0xcc1f0000), SPH_C32(0xc8d267fa), SPH_C32(0x5c4c2eba), + SPH_C32(0x82c48ff8), SPH_C32(0x1a9466ee), SPH_C32(0x2f440000), + SPH_C32(0xbce40600), SPH_C32(0xbb3d0000), SPH_C32(0x01f40000), + SPH_C32(0x8a333dfd), SPH_C32(0xd0a40492), SPH_C32(0xfa93b802), + SPH_C32(0x245cc3b4) }, + { SPH_C32(0x8b860000), SPH_C32(0x65d32200), SPH_C32(0xb1750000), + SPH_C32(0x67950000), SPH_C32(0x72492f3a), SPH_C32(0x561af3ce), + SPH_C32(0x59b76796), SPH_C32(0x0ffc99e1), SPH_C32(0x23360000), + SPH_C32(0xf5010900), SPH_C32(0xf9440000), SPH_C32(0x5d1e0000), + SPH_C32(0xb9990de7), SPH_C32(0xc5262186), SPH_C32(0x6f30f379), + SPH_C32(0x9017c324) }, + { SPH_C32(0x87f40000), SPH_C32(0x2c362d00), SPH_C32(0xf30c0000), + SPH_C32(0x3b7f0000), SPH_C32(0x41e31f20), SPH_C32(0x4398d6da), + SPH_C32(0xcc142ced), SPH_C32(0xbbb79971), SPH_C32(0xdd140000), + SPH_C32(0x52590c00), SPH_C32(0xdc950000), SPH_C32(0xaa7e0000), + SPH_C32(0x30a8753d), SPH_C32(0xdaf2d9e6), SPH_C32(0x21e0506c), + SPH_C32(0x31343cbb) }, + { SPH_C32(0x30bc0000), SPH_C32(0x673e3000), SPH_C32(0x6dce0000), + SPH_C32(0xabbd0000), SPH_C32(0xe5b443cc), SPH_C32(0x6add9e78), + SPH_C32(0x01db6233), SPH_C32(0x71ec92a1), SPH_C32(0x695b0000), + SPH_C32(0x0dcd0500), SPH_C32(0xa9760000), SPH_C32(0x03250000), + SPH_C32(0x2183248b), SPH_C32(0x61380db7), SPH_C32(0xd2670d01), + SPH_C32(0x40bed715) }, + { SPH_C32(0x3cce0000), SPH_C32(0x2edb3f00), SPH_C32(0x2fb70000), + SPH_C32(0xf7570000), SPH_C32(0xd61e73d6), SPH_C32(0x7f5fbb6c), + SPH_C32(0x94782948), SPH_C32(0xc5a79231), SPH_C32(0x97790000), + SPH_C32(0xaa950000), SPH_C32(0x8ca70000), SPH_C32(0xf4450000), + SPH_C32(0xa8b25c51), SPH_C32(0x7eecf5d7), SPH_C32(0x9cb7ae14), + SPH_C32(0xe19d288a) }, + { SPH_C32(0xce9e0000), SPH_C32(0xc0663500), SPH_C32(0x481f0000), + SPH_C32(0x5cdd0000), SPH_C32(0x6c853b16), SPH_C32(0x75096618), + SPH_C32(0x4f0bc126), SPH_C32(0xd0cf6d3e), SPH_C32(0x9b0b0000), + SPH_C32(0xe3700f00), SPH_C32(0xcede0000), SPH_C32(0xa8af0000), + SPH_C32(0x9b186c4b), SPH_C32(0x6b6ed0c3), SPH_C32(0x0914e56f), + SPH_C32(0x55d6281a) }, + { SPH_C32(0xc2ec0000), SPH_C32(0x89833a00), SPH_C32(0x0a660000), + SPH_C32(0x00370000), SPH_C32(0x5f2f0b0c), SPH_C32(0x608b430c), + SPH_C32(0xdaa88a5d), SPH_C32(0x64846dae), SPH_C32(0x65290000), + SPH_C32(0x44280a00), SPH_C32(0xeb0f0000), SPH_C32(0x5fcf0000), + SPH_C32(0x12291491), SPH_C32(0x74ba28a3), SPH_C32(0x47c4467a), + SPH_C32(0xf4f5d785) }, + { SPH_C32(0xcd990000), SPH_C32(0xd4fa2100), SPH_C32(0xa33e0000), + SPH_C32(0x65440000), SPH_C32(0xd9f9364c), SPH_C32(0xe786faeb), + SPH_C32(0x7143d295), SPH_C32(0x6b1e8d40), SPH_C32(0x2c430000), + SPH_C32(0xa8781200), SPH_C32(0x501c0000), SPH_C32(0x386d0000), + SPH_C32(0x3f4f30a7), SPH_C32(0x422b9861), SPH_C32(0xc4dbabb1), + SPH_C32(0x9f8d23ca) }, + { SPH_C32(0xc1eb0000), SPH_C32(0x9d1f2e00), SPH_C32(0xe1470000), + SPH_C32(0x39ae0000), SPH_C32(0xea530656), SPH_C32(0xf204dfff), + SPH_C32(0xe4e099ee), SPH_C32(0xdf558dd0), SPH_C32(0xd2610000), + SPH_C32(0x0f201700), SPH_C32(0x75cd0000), SPH_C32(0xcf0d0000), + SPH_C32(0xb67e487d), SPH_C32(0x5dff6001), SPH_C32(0x8a0b08a4), + SPH_C32(0x3eaedc55) }, + { SPH_C32(0x33bb0000), SPH_C32(0x73a22400), SPH_C32(0x86ef0000), + SPH_C32(0x92240000), SPH_C32(0x50c84e96), SPH_C32(0xf852028b), + SPH_C32(0x3f937180), SPH_C32(0xca3d72df), SPH_C32(0xde130000), + SPH_C32(0x46c51800), SPH_C32(0x37b40000), SPH_C32(0x93e70000), + SPH_C32(0x85d47867), SPH_C32(0x487d4515), SPH_C32(0x1fa843df), + SPH_C32(0x8ae5dcc5) }, + { SPH_C32(0x3fc90000), SPH_C32(0x3a472b00), SPH_C32(0xc4960000), + SPH_C32(0xcece0000), SPH_C32(0x63627e8c), SPH_C32(0xedd0279f), + SPH_C32(0xaa303afb), SPH_C32(0x7e76724f), SPH_C32(0x20310000), + SPH_C32(0xe19d1d00), SPH_C32(0x12650000), SPH_C32(0x64870000), + SPH_C32(0x0ce500bd), SPH_C32(0x57a9bd75), SPH_C32(0x5178e0ca), + SPH_C32(0x2bc6235a) }, + { SPH_C32(0x88810000), SPH_C32(0x714f3600), SPH_C32(0x5a540000), + SPH_C32(0x5e0c0000), SPH_C32(0xc7352260), SPH_C32(0xc4956f3d), + SPH_C32(0x67ff7425), SPH_C32(0xb42d799f), SPH_C32(0x947e0000), + SPH_C32(0xbe091400), SPH_C32(0x67860000), SPH_C32(0xcddc0000), + SPH_C32(0x1dce510b), SPH_C32(0xec636924), SPH_C32(0xa2ffbda7), + SPH_C32(0x5a4cc8f4) }, + { SPH_C32(0x84f30000), SPH_C32(0x38aa3900), SPH_C32(0x182d0000), + SPH_C32(0x02e60000), SPH_C32(0xf49f127a), SPH_C32(0xd1174a29), + SPH_C32(0xf25c3f5e), SPH_C32(0x0066790f), SPH_C32(0x6a5c0000), + SPH_C32(0x19511100), SPH_C32(0x42570000), SPH_C32(0x3abc0000), + SPH_C32(0x94ff29d1), SPH_C32(0xf3b79144), SPH_C32(0xec2f1eb2), + SPH_C32(0xfb6f376b) }, + { SPH_C32(0x76a30000), SPH_C32(0xd6173300), SPH_C32(0x7f850000), + SPH_C32(0xa96c0000), SPH_C32(0x4e045aba), SPH_C32(0xdb41975d), + SPH_C32(0x292fd730), SPH_C32(0x150e8600), SPH_C32(0x662e0000), + SPH_C32(0x50b41e00), SPH_C32(0x002e0000), SPH_C32(0x66560000), + SPH_C32(0xa75519cb), SPH_C32(0xe635b450), SPH_C32(0x798c55c9), + SPH_C32(0x4f2437fb) }, + { SPH_C32(0x7ad10000), SPH_C32(0x9ff23c00), SPH_C32(0x3dfc0000), + SPH_C32(0xf5860000), SPH_C32(0x7dae6aa0), SPH_C32(0xcec3b249), + SPH_C32(0xbc8c9c4b), SPH_C32(0xa1458690), SPH_C32(0x980c0000), + SPH_C32(0xf7ec1b00), SPH_C32(0x25ff0000), SPH_C32(0x91360000), + SPH_C32(0x2e646111), SPH_C32(0xf9e14c30), SPH_C32(0x375cf6dc), + SPH_C32(0xee07c864) }, + { SPH_C32(0xd1660000), SPH_C32(0x1bbc0300), SPH_C32(0x9eec0000), + SPH_C32(0xf6940000), SPH_C32(0x03024527), SPH_C32(0xcf70fcf2), + SPH_C32(0xb4431b17), SPH_C32(0x857f3c2b), SPH_C32(0xa4c20000), + SPH_C32(0xd9372400), SPH_C32(0x0a480000), SPH_C32(0x66610000), + SPH_C32(0xf87a12c7), SPH_C32(0x86bef75c), SPH_C32(0xa324df94), + SPH_C32(0x2ba05a55) }, + { SPH_C32(0xdd140000), SPH_C32(0x52590c00), SPH_C32(0xdc950000), + SPH_C32(0xaa7e0000), SPH_C32(0x30a8753d), SPH_C32(0xdaf2d9e6), + SPH_C32(0x21e0506c), SPH_C32(0x31343cbb), SPH_C32(0x5ae00000), + SPH_C32(0x7e6f2100), SPH_C32(0x2f990000), SPH_C32(0x91010000), + SPH_C32(0x714b6a1d), SPH_C32(0x996a0f3c), SPH_C32(0xedf47c81), + SPH_C32(0x8a83a5ca) }, + { SPH_C32(0x2f440000), SPH_C32(0xbce40600), SPH_C32(0xbb3d0000), + SPH_C32(0x01f40000), SPH_C32(0x8a333dfd), SPH_C32(0xd0a40492), + SPH_C32(0xfa93b802), SPH_C32(0x245cc3b4), SPH_C32(0x56920000), + SPH_C32(0x378a2e00), SPH_C32(0x6de00000), SPH_C32(0xcdeb0000), + SPH_C32(0x42e15a07), SPH_C32(0x8ce82a28), SPH_C32(0x785737fa), + SPH_C32(0x3ec8a55a) }, + { SPH_C32(0x23360000), SPH_C32(0xf5010900), SPH_C32(0xf9440000), + SPH_C32(0x5d1e0000), SPH_C32(0xb9990de7), SPH_C32(0xc5262186), + SPH_C32(0x6f30f379), SPH_C32(0x9017c324), SPH_C32(0xa8b00000), + SPH_C32(0x90d22b00), SPH_C32(0x48310000), SPH_C32(0x3a8b0000), + SPH_C32(0xcbd022dd), SPH_C32(0x933cd248), SPH_C32(0x368794ef), + SPH_C32(0x9feb5ac5) }, + { SPH_C32(0x947e0000), SPH_C32(0xbe091400), SPH_C32(0x67860000), + SPH_C32(0xcddc0000), SPH_C32(0x1dce510b), SPH_C32(0xec636924), + SPH_C32(0xa2ffbda7), SPH_C32(0x5a4cc8f4), SPH_C32(0x1cff0000), + SPH_C32(0xcf462200), SPH_C32(0x3dd20000), SPH_C32(0x93d00000), + SPH_C32(0xdafb736b), SPH_C32(0x28f60619), SPH_C32(0xc500c982), + SPH_C32(0xee61b16b) }, + { SPH_C32(0x980c0000), SPH_C32(0xf7ec1b00), SPH_C32(0x25ff0000), + SPH_C32(0x91360000), SPH_C32(0x2e646111), SPH_C32(0xf9e14c30), + SPH_C32(0x375cf6dc), SPH_C32(0xee07c864), SPH_C32(0xe2dd0000), + SPH_C32(0x681e2700), SPH_C32(0x18030000), SPH_C32(0x64b00000), + SPH_C32(0x53ca0bb1), SPH_C32(0x3722fe79), SPH_C32(0x8bd06a97), + SPH_C32(0x4f424ef4) }, + { SPH_C32(0x6a5c0000), SPH_C32(0x19511100), SPH_C32(0x42570000), + SPH_C32(0x3abc0000), SPH_C32(0x94ff29d1), SPH_C32(0xf3b79144), + SPH_C32(0xec2f1eb2), SPH_C32(0xfb6f376b), SPH_C32(0xeeaf0000), + SPH_C32(0x21fb2800), SPH_C32(0x5a7a0000), SPH_C32(0x385a0000), + SPH_C32(0x60603bab), SPH_C32(0x22a0db6d), SPH_C32(0x1e7321ec), + SPH_C32(0xfb094e64) }, + { SPH_C32(0x662e0000), SPH_C32(0x50b41e00), SPH_C32(0x002e0000), + SPH_C32(0x66560000), SPH_C32(0xa75519cb), SPH_C32(0xe635b450), + SPH_C32(0x798c55c9), SPH_C32(0x4f2437fb), SPH_C32(0x108d0000), + SPH_C32(0x86a32d00), SPH_C32(0x7fab0000), SPH_C32(0xcf3a0000), + SPH_C32(0xe9514371), SPH_C32(0x3d74230d), SPH_C32(0x50a382f9), + SPH_C32(0x5a2ab1fb) }, + { SPH_C32(0x695b0000), SPH_C32(0x0dcd0500), SPH_C32(0xa9760000), + SPH_C32(0x03250000), SPH_C32(0x2183248b), SPH_C32(0x61380db7), + SPH_C32(0xd2670d01), SPH_C32(0x40bed715), SPH_C32(0x59e70000), + SPH_C32(0x6af33500), SPH_C32(0xc4b80000), SPH_C32(0xa8980000), + SPH_C32(0xc4376747), SPH_C32(0x0be593cf), SPH_C32(0xd3bc6f32), + SPH_C32(0x315245b4) }, + { SPH_C32(0x65290000), SPH_C32(0x44280a00), SPH_C32(0xeb0f0000), + SPH_C32(0x5fcf0000), SPH_C32(0x12291491), SPH_C32(0x74ba28a3), + SPH_C32(0x47c4467a), SPH_C32(0xf4f5d785), SPH_C32(0xa7c50000), + SPH_C32(0xcdab3000), SPH_C32(0xe1690000), SPH_C32(0x5ff80000), + SPH_C32(0x4d061f9d), SPH_C32(0x14316baf), SPH_C32(0x9d6ccc27), + SPH_C32(0x9071ba2b) }, + { SPH_C32(0x97790000), SPH_C32(0xaa950000), SPH_C32(0x8ca70000), + SPH_C32(0xf4450000), SPH_C32(0xa8b25c51), SPH_C32(0x7eecf5d7), + SPH_C32(0x9cb7ae14), SPH_C32(0xe19d288a), SPH_C32(0xabb70000), + SPH_C32(0x844e3f00), SPH_C32(0xa3100000), SPH_C32(0x03120000), + SPH_C32(0x7eac2f87), SPH_C32(0x01b34ebb), SPH_C32(0x08cf875c), + SPH_C32(0x243ababb) }, + { SPH_C32(0x9b0b0000), SPH_C32(0xe3700f00), SPH_C32(0xcede0000), + SPH_C32(0xa8af0000), SPH_C32(0x9b186c4b), SPH_C32(0x6b6ed0c3), + SPH_C32(0x0914e56f), SPH_C32(0x55d6281a), SPH_C32(0x55950000), + SPH_C32(0x23163a00), SPH_C32(0x86c10000), SPH_C32(0xf4720000), + SPH_C32(0xf79d575d), SPH_C32(0x1e67b6db), SPH_C32(0x461f2449), + SPH_C32(0x85194524) }, + { SPH_C32(0x2c430000), SPH_C32(0xa8781200), SPH_C32(0x501c0000), + SPH_C32(0x386d0000), SPH_C32(0x3f4f30a7), SPH_C32(0x422b9861), + SPH_C32(0xc4dbabb1), SPH_C32(0x9f8d23ca), SPH_C32(0xe1da0000), + SPH_C32(0x7c823300), SPH_C32(0xf3220000), SPH_C32(0x5d290000), + SPH_C32(0xe6b606eb), SPH_C32(0xa5ad628a), SPH_C32(0xb5987924), + SPH_C32(0xf493ae8a) }, + { SPH_C32(0x20310000), SPH_C32(0xe19d1d00), SPH_C32(0x12650000), + SPH_C32(0x64870000), SPH_C32(0x0ce500bd), SPH_C32(0x57a9bd75), + SPH_C32(0x5178e0ca), SPH_C32(0x2bc6235a), SPH_C32(0x1ff80000), + SPH_C32(0xdbda3600), SPH_C32(0xd6f30000), SPH_C32(0xaa490000), + SPH_C32(0x6f877e31), SPH_C32(0xba799aea), SPH_C32(0xfb48da31), + SPH_C32(0x55b05115) }, + { SPH_C32(0xd2610000), SPH_C32(0x0f201700), SPH_C32(0x75cd0000), + SPH_C32(0xcf0d0000), SPH_C32(0xb67e487d), SPH_C32(0x5dff6001), + SPH_C32(0x8a0b08a4), SPH_C32(0x3eaedc55), SPH_C32(0x138a0000), + SPH_C32(0x923f3900), SPH_C32(0x948a0000), SPH_C32(0xf6a30000), + SPH_C32(0x5c2d4e2b), SPH_C32(0xaffbbffe), SPH_C32(0x6eeb914a), + SPH_C32(0xe1fb5185) }, + { SPH_C32(0xde130000), SPH_C32(0x46c51800), SPH_C32(0x37b40000), + SPH_C32(0x93e70000), SPH_C32(0x85d47867), SPH_C32(0x487d4515), + SPH_C32(0x1fa843df), SPH_C32(0x8ae5dcc5), SPH_C32(0xeda80000), + SPH_C32(0x35673c00), SPH_C32(0xb15b0000), SPH_C32(0x01c30000), + SPH_C32(0xd51c36f1), SPH_C32(0xb02f479e), SPH_C32(0x203b325f), + SPH_C32(0x40d8ae1a) }, + { SPH_C32(0xa4c20000), SPH_C32(0xd9372400), SPH_C32(0x0a480000), + SPH_C32(0x66610000), SPH_C32(0xf87a12c7), SPH_C32(0x86bef75c), + SPH_C32(0xa324df94), SPH_C32(0x2ba05a55), SPH_C32(0x75a40000), + SPH_C32(0xc28b2700), SPH_C32(0x94a40000), SPH_C32(0x90f50000), + SPH_C32(0xfb7857e0), SPH_C32(0x49ce0bae), SPH_C32(0x1767c483), + SPH_C32(0xaedf667e) }, + { SPH_C32(0xa8b00000), SPH_C32(0x90d22b00), SPH_C32(0x48310000), + SPH_C32(0x3a8b0000), SPH_C32(0xcbd022dd), SPH_C32(0x933cd248), + SPH_C32(0x368794ef), SPH_C32(0x9feb5ac5), SPH_C32(0x8b860000), + SPH_C32(0x65d32200), SPH_C32(0xb1750000), SPH_C32(0x67950000), + SPH_C32(0x72492f3a), SPH_C32(0x561af3ce), SPH_C32(0x59b76796), + SPH_C32(0x0ffc99e1) }, + { SPH_C32(0x5ae00000), SPH_C32(0x7e6f2100), SPH_C32(0x2f990000), + SPH_C32(0x91010000), SPH_C32(0x714b6a1d), SPH_C32(0x996a0f3c), + SPH_C32(0xedf47c81), SPH_C32(0x8a83a5ca), SPH_C32(0x87f40000), + SPH_C32(0x2c362d00), SPH_C32(0xf30c0000), SPH_C32(0x3b7f0000), + SPH_C32(0x41e31f20), SPH_C32(0x4398d6da), SPH_C32(0xcc142ced), + SPH_C32(0xbbb79971) }, + { SPH_C32(0x56920000), SPH_C32(0x378a2e00), SPH_C32(0x6de00000), + SPH_C32(0xcdeb0000), SPH_C32(0x42e15a07), SPH_C32(0x8ce82a28), + SPH_C32(0x785737fa), SPH_C32(0x3ec8a55a), SPH_C32(0x79d60000), + SPH_C32(0x8b6e2800), SPH_C32(0xd6dd0000), SPH_C32(0xcc1f0000), + SPH_C32(0xc8d267fa), SPH_C32(0x5c4c2eba), SPH_C32(0x82c48ff8), + SPH_C32(0x1a9466ee) }, + { SPH_C32(0xe1da0000), SPH_C32(0x7c823300), SPH_C32(0xf3220000), + SPH_C32(0x5d290000), SPH_C32(0xe6b606eb), SPH_C32(0xa5ad628a), + SPH_C32(0xb5987924), SPH_C32(0xf493ae8a), SPH_C32(0xcd990000), + SPH_C32(0xd4fa2100), SPH_C32(0xa33e0000), SPH_C32(0x65440000), + SPH_C32(0xd9f9364c), SPH_C32(0xe786faeb), SPH_C32(0x7143d295), + SPH_C32(0x6b1e8d40) }, + { SPH_C32(0xeda80000), SPH_C32(0x35673c00), SPH_C32(0xb15b0000), + SPH_C32(0x01c30000), SPH_C32(0xd51c36f1), SPH_C32(0xb02f479e), + SPH_C32(0x203b325f), SPH_C32(0x40d8ae1a), SPH_C32(0x33bb0000), + SPH_C32(0x73a22400), SPH_C32(0x86ef0000), SPH_C32(0x92240000), + SPH_C32(0x50c84e96), SPH_C32(0xf852028b), SPH_C32(0x3f937180), + SPH_C32(0xca3d72df) }, + { SPH_C32(0x1ff80000), SPH_C32(0xdbda3600), SPH_C32(0xd6f30000), + SPH_C32(0xaa490000), SPH_C32(0x6f877e31), SPH_C32(0xba799aea), + SPH_C32(0xfb48da31), SPH_C32(0x55b05115), SPH_C32(0x3fc90000), + SPH_C32(0x3a472b00), SPH_C32(0xc4960000), SPH_C32(0xcece0000), + SPH_C32(0x63627e8c), SPH_C32(0xedd0279f), SPH_C32(0xaa303afb), + SPH_C32(0x7e76724f) }, + { SPH_C32(0x138a0000), SPH_C32(0x923f3900), SPH_C32(0x948a0000), + SPH_C32(0xf6a30000), SPH_C32(0x5c2d4e2b), SPH_C32(0xaffbbffe), + SPH_C32(0x6eeb914a), SPH_C32(0xe1fb5185), SPH_C32(0xc1eb0000), + SPH_C32(0x9d1f2e00), SPH_C32(0xe1470000), SPH_C32(0x39ae0000), + SPH_C32(0xea530656), SPH_C32(0xf204dfff), SPH_C32(0xe4e099ee), + SPH_C32(0xdf558dd0) }, + { SPH_C32(0x1cff0000), SPH_C32(0xcf462200), SPH_C32(0x3dd20000), + SPH_C32(0x93d00000), SPH_C32(0xdafb736b), SPH_C32(0x28f60619), + SPH_C32(0xc500c982), SPH_C32(0xee61b16b), SPH_C32(0x88810000), + SPH_C32(0x714f3600), SPH_C32(0x5a540000), SPH_C32(0x5e0c0000), + SPH_C32(0xc7352260), SPH_C32(0xc4956f3d), SPH_C32(0x67ff7425), + SPH_C32(0xb42d799f) }, + { SPH_C32(0x108d0000), SPH_C32(0x86a32d00), SPH_C32(0x7fab0000), + SPH_C32(0xcf3a0000), SPH_C32(0xe9514371), SPH_C32(0x3d74230d), + SPH_C32(0x50a382f9), SPH_C32(0x5a2ab1fb), SPH_C32(0x76a30000), + SPH_C32(0xd6173300), SPH_C32(0x7f850000), SPH_C32(0xa96c0000), + SPH_C32(0x4e045aba), SPH_C32(0xdb41975d), SPH_C32(0x292fd730), + SPH_C32(0x150e8600) }, + { SPH_C32(0xe2dd0000), SPH_C32(0x681e2700), SPH_C32(0x18030000), + SPH_C32(0x64b00000), SPH_C32(0x53ca0bb1), SPH_C32(0x3722fe79), + SPH_C32(0x8bd06a97), SPH_C32(0x4f424ef4), SPH_C32(0x7ad10000), + SPH_C32(0x9ff23c00), SPH_C32(0x3dfc0000), SPH_C32(0xf5860000), + SPH_C32(0x7dae6aa0), SPH_C32(0xcec3b249), SPH_C32(0xbc8c9c4b), + SPH_C32(0xa1458690) }, + { SPH_C32(0xeeaf0000), SPH_C32(0x21fb2800), SPH_C32(0x5a7a0000), + SPH_C32(0x385a0000), SPH_C32(0x60603bab), SPH_C32(0x22a0db6d), + SPH_C32(0x1e7321ec), SPH_C32(0xfb094e64), SPH_C32(0x84f30000), + SPH_C32(0x38aa3900), SPH_C32(0x182d0000), SPH_C32(0x02e60000), + SPH_C32(0xf49f127a), SPH_C32(0xd1174a29), SPH_C32(0xf25c3f5e), + SPH_C32(0x0066790f) }, + { SPH_C32(0x59e70000), SPH_C32(0x6af33500), SPH_C32(0xc4b80000), + SPH_C32(0xa8980000), SPH_C32(0xc4376747), SPH_C32(0x0be593cf), + SPH_C32(0xd3bc6f32), SPH_C32(0x315245b4), SPH_C32(0x30bc0000), + SPH_C32(0x673e3000), SPH_C32(0x6dce0000), SPH_C32(0xabbd0000), + SPH_C32(0xe5b443cc), SPH_C32(0x6add9e78), SPH_C32(0x01db6233), + SPH_C32(0x71ec92a1) }, + { SPH_C32(0x55950000), SPH_C32(0x23163a00), SPH_C32(0x86c10000), + SPH_C32(0xf4720000), SPH_C32(0xf79d575d), SPH_C32(0x1e67b6db), + SPH_C32(0x461f2449), SPH_C32(0x85194524), SPH_C32(0xce9e0000), + SPH_C32(0xc0663500), SPH_C32(0x481f0000), SPH_C32(0x5cdd0000), + SPH_C32(0x6c853b16), SPH_C32(0x75096618), SPH_C32(0x4f0bc126), + SPH_C32(0xd0cf6d3e) }, + { SPH_C32(0xa7c50000), SPH_C32(0xcdab3000), SPH_C32(0xe1690000), + SPH_C32(0x5ff80000), SPH_C32(0x4d061f9d), SPH_C32(0x14316baf), + SPH_C32(0x9d6ccc27), SPH_C32(0x9071ba2b), SPH_C32(0xc2ec0000), + SPH_C32(0x89833a00), SPH_C32(0x0a660000), SPH_C32(0x00370000), + SPH_C32(0x5f2f0b0c), SPH_C32(0x608b430c), SPH_C32(0xdaa88a5d), + SPH_C32(0x64846dae) }, + { SPH_C32(0xabb70000), SPH_C32(0x844e3f00), SPH_C32(0xa3100000), + SPH_C32(0x03120000), SPH_C32(0x7eac2f87), SPH_C32(0x01b34ebb), + SPH_C32(0x08cf875c), SPH_C32(0x243ababb), SPH_C32(0x3cce0000), + SPH_C32(0x2edb3f00), SPH_C32(0x2fb70000), SPH_C32(0xf7570000), + SPH_C32(0xd61e73d6), SPH_C32(0x7f5fbb6c), SPH_C32(0x94782948), + SPH_C32(0xc5a79231) }, + { SPH_C32(0x75c90003), SPH_C32(0x0e10c000), SPH_C32(0xd1200000), + SPH_C32(0xbaea0000), SPH_C32(0x8bc42f3e), SPH_C32(0x8758b757), + SPH_C32(0xbb28761d), SPH_C32(0x00b72e2b), SPH_C32(0xeecf0001), + SPH_C32(0x6f564000), SPH_C32(0xf33e0000), SPH_C32(0xa79e0000), + SPH_C32(0xbdb57219), SPH_C32(0xb711ebc5), SPH_C32(0x4a3b40ba), + SPH_C32(0xfeabf254) }, + { SPH_C32(0x79bb0003), SPH_C32(0x47f5cf00), SPH_C32(0x93590000), + SPH_C32(0xe6000000), SPH_C32(0xb86e1f24), SPH_C32(0x92da9243), + SPH_C32(0x2e8b3d66), SPH_C32(0xb4fc2ebb), SPH_C32(0x10ed0001), + SPH_C32(0xc80e4500), SPH_C32(0xd6ef0000), SPH_C32(0x50fe0000), + SPH_C32(0x34840ac3), SPH_C32(0xa8c513a5), SPH_C32(0x04ebe3af), + SPH_C32(0x5f880dcb) }, + { SPH_C32(0x8beb0003), SPH_C32(0xa948c500), SPH_C32(0xf4f10000), + SPH_C32(0x4d8a0000), SPH_C32(0x02f557e4), SPH_C32(0x988c4f37), + SPH_C32(0xf5f8d508), SPH_C32(0xa194d1b4), SPH_C32(0x1c9f0001), + SPH_C32(0x81eb4a00), SPH_C32(0x94960000), SPH_C32(0x0c140000), + SPH_C32(0x072e3ad9), SPH_C32(0xbd4736b1), SPH_C32(0x9148a8d4), + SPH_C32(0xebc30d5b) }, + { SPH_C32(0x87990003), SPH_C32(0xe0adca00), SPH_C32(0xb6880000), + SPH_C32(0x11600000), SPH_C32(0x315f67fe), SPH_C32(0x8d0e6a23), + SPH_C32(0x605b9e73), SPH_C32(0x15dfd124), SPH_C32(0xe2bd0001), + SPH_C32(0x26b34f00), SPH_C32(0xb1470000), SPH_C32(0xfb740000), + SPH_C32(0x8e1f4203), SPH_C32(0xa293ced1), SPH_C32(0xdf980bc1), + SPH_C32(0x4ae0f2c4) }, + { SPH_C32(0x30d10003), SPH_C32(0xaba5d700), SPH_C32(0x284a0000), + SPH_C32(0x81a20000), SPH_C32(0x95083b12), SPH_C32(0xa44b2281), + SPH_C32(0xad94d0ad), SPH_C32(0xdf84daf4), SPH_C32(0x56f20001), + SPH_C32(0x79274600), SPH_C32(0xc4a40000), SPH_C32(0x522f0000), + SPH_C32(0x9f3413b5), SPH_C32(0x19591a80), SPH_C32(0x2c1f56ac), + SPH_C32(0x3b6a196a) }, + { SPH_C32(0x3ca30003), SPH_C32(0xe240d800), SPH_C32(0x6a330000), + SPH_C32(0xdd480000), SPH_C32(0xa6a20b08), SPH_C32(0xb1c90795), + SPH_C32(0x38379bd6), SPH_C32(0x6bcfda64), SPH_C32(0xa8d00001), + SPH_C32(0xde7f4300), SPH_C32(0xe1750000), SPH_C32(0xa54f0000), + SPH_C32(0x16056b6f), SPH_C32(0x068de2e0), SPH_C32(0x62cff5b9), + SPH_C32(0x9a49e6f5) }, + { SPH_C32(0xcef30003), SPH_C32(0x0cfdd200), SPH_C32(0x0d9b0000), + SPH_C32(0x76c20000), SPH_C32(0x1c3943c8), SPH_C32(0xbb9fdae1), + SPH_C32(0xe34473b8), SPH_C32(0x7ea7256b), SPH_C32(0xa4a20001), + SPH_C32(0x979a4c00), SPH_C32(0xa30c0000), SPH_C32(0xf9a50000), + SPH_C32(0x25af5b75), SPH_C32(0x130fc7f4), SPH_C32(0xf76cbec2), + SPH_C32(0x2e02e665) }, + { SPH_C32(0xc2810003), SPH_C32(0x4518dd00), SPH_C32(0x4fe20000), + SPH_C32(0x2a280000), SPH_C32(0x2f9373d2), SPH_C32(0xae1dfff5), + SPH_C32(0x76e738c3), SPH_C32(0xcaec25fb), SPH_C32(0x5a800001), + SPH_C32(0x30c24900), SPH_C32(0x86dd0000), SPH_C32(0x0ec50000), + SPH_C32(0xac9e23af), SPH_C32(0x0cdb3f94), SPH_C32(0xb9bc1dd7), + SPH_C32(0x8f2119fa) }, + { SPH_C32(0xcdf40003), SPH_C32(0x1861c600), SPH_C32(0xe6ba0000), + SPH_C32(0x4f5b0000), SPH_C32(0xa9454e92), SPH_C32(0x29104612), + SPH_C32(0xdd0c600b), SPH_C32(0xc576c515), SPH_C32(0x13ea0001), + SPH_C32(0xdc925100), SPH_C32(0x3dce0000), SPH_C32(0x69670000), + SPH_C32(0x81f80799), SPH_C32(0x3a4a8f56), SPH_C32(0x3aa3f01c), + SPH_C32(0xe459edb5) }, + { SPH_C32(0xc1860003), SPH_C32(0x5184c900), SPH_C32(0xa4c30000), + SPH_C32(0x13b10000), SPH_C32(0x9aef7e88), SPH_C32(0x3c926306), + SPH_C32(0x48af2b70), SPH_C32(0x713dc585), SPH_C32(0xedc80001), + SPH_C32(0x7bca5400), SPH_C32(0x181f0000), SPH_C32(0x9e070000), + SPH_C32(0x08c97f43), SPH_C32(0x259e7736), SPH_C32(0x74735309), + SPH_C32(0x457a122a) }, + { SPH_C32(0x33d60003), SPH_C32(0xbf39c300), SPH_C32(0xc36b0000), + SPH_C32(0xb83b0000), SPH_C32(0x20743648), SPH_C32(0x36c4be72), + SPH_C32(0x93dcc31e), SPH_C32(0x64553a8a), SPH_C32(0xe1ba0001), + SPH_C32(0x322f5b00), SPH_C32(0x5a660000), SPH_C32(0xc2ed0000), + SPH_C32(0x3b634f59), SPH_C32(0x301c5222), SPH_C32(0xe1d01872), + SPH_C32(0xf13112ba) }, + { SPH_C32(0x3fa40003), SPH_C32(0xf6dccc00), SPH_C32(0x81120000), + SPH_C32(0xe4d10000), SPH_C32(0x13de0652), SPH_C32(0x23469b66), + SPH_C32(0x067f8865), SPH_C32(0xd01e3a1a), SPH_C32(0x1f980001), + SPH_C32(0x95775e00), SPH_C32(0x7fb70000), SPH_C32(0x358d0000), + SPH_C32(0xb2523783), SPH_C32(0x2fc8aa42), SPH_C32(0xaf00bb67), + SPH_C32(0x5012ed25) }, + { SPH_C32(0x88ec0003), SPH_C32(0xbdd4d100), SPH_C32(0x1fd00000), + SPH_C32(0x74130000), SPH_C32(0xb7895abe), SPH_C32(0x0a03d3c4), + SPH_C32(0xcbb0c6bb), SPH_C32(0x1a4531ca), SPH_C32(0xabd70001), + SPH_C32(0xcae35700), SPH_C32(0x0a540000), SPH_C32(0x9cd60000), + SPH_C32(0xa3796635), SPH_C32(0x94027e13), SPH_C32(0x5c87e60a), + SPH_C32(0x2198068b) }, + { SPH_C32(0x849e0003), SPH_C32(0xf431de00), SPH_C32(0x5da90000), + SPH_C32(0x28f90000), SPH_C32(0x84236aa4), SPH_C32(0x1f81f6d0), + SPH_C32(0x5e138dc0), SPH_C32(0xae0e315a), SPH_C32(0x55f50001), + SPH_C32(0x6dbb5200), SPH_C32(0x2f850000), SPH_C32(0x6bb60000), + SPH_C32(0x2a481eef), SPH_C32(0x8bd68673), SPH_C32(0x1257451f), + SPH_C32(0x80bbf914) }, + { SPH_C32(0x76ce0003), SPH_C32(0x1a8cd400), SPH_C32(0x3a010000), + SPH_C32(0x83730000), SPH_C32(0x3eb82264), SPH_C32(0x15d72ba4), + SPH_C32(0x856065ae), SPH_C32(0xbb66ce55), SPH_C32(0x59870001), + SPH_C32(0x245e5d00), SPH_C32(0x6dfc0000), SPH_C32(0x375c0000), + SPH_C32(0x19e22ef5), SPH_C32(0x9e54a367), SPH_C32(0x87f40e64), + SPH_C32(0x34f0f984) }, + { SPH_C32(0x7abc0003), SPH_C32(0x5369db00), SPH_C32(0x78780000), + SPH_C32(0xdf990000), SPH_C32(0x0d12127e), SPH_C32(0x00550eb0), + SPH_C32(0x10c32ed5), SPH_C32(0x0f2dcec5), SPH_C32(0xa7a50001), + SPH_C32(0x83065800), SPH_C32(0x482d0000), SPH_C32(0xc03c0000), + SPH_C32(0x90d3562f), SPH_C32(0x81805b07), SPH_C32(0xc924ad71), + SPH_C32(0x95d3061b) }, + { SPH_C32(0x006d0003), SPH_C32(0xcc9be700), SPH_C32(0x45840000), + SPH_C32(0x2a1f0000), SPH_C32(0x70bc78de), SPH_C32(0xce96bcf9), + SPH_C32(0xac4fb29e), SPH_C32(0xae684855), SPH_C32(0x3fa90001), + SPH_C32(0x74ea4300), SPH_C32(0x6dd20000), SPH_C32(0x510a0000), + SPH_C32(0xbeb7373e), SPH_C32(0x78611737), SPH_C32(0xfe785bad), + SPH_C32(0x7bd4ce7f) }, + { SPH_C32(0x0c1f0003), SPH_C32(0x857ee800), SPH_C32(0x07fd0000), + SPH_C32(0x76f50000), SPH_C32(0x431648c4), SPH_C32(0xdb1499ed), + SPH_C32(0x39ecf9e5), SPH_C32(0x1a2348c5), SPH_C32(0xc18b0001), + SPH_C32(0xd3b24600), SPH_C32(0x48030000), SPH_C32(0xa66a0000), + SPH_C32(0x37864fe4), SPH_C32(0x67b5ef57), SPH_C32(0xb0a8f8b8), + SPH_C32(0xdaf731e0) }, + { SPH_C32(0xfe4f0003), SPH_C32(0x6bc3e200), SPH_C32(0x60550000), + SPH_C32(0xdd7f0000), SPH_C32(0xf98d0004), SPH_C32(0xd1424499), + SPH_C32(0xe29f118b), SPH_C32(0x0f4bb7ca), SPH_C32(0xcdf90001), + SPH_C32(0x9a574900), SPH_C32(0x0a7a0000), SPH_C32(0xfa800000), + SPH_C32(0x042c7ffe), SPH_C32(0x7237ca43), SPH_C32(0x250bb3c3), + SPH_C32(0x6ebc3170) }, + { SPH_C32(0xf23d0003), SPH_C32(0x2226ed00), SPH_C32(0x222c0000), + SPH_C32(0x81950000), SPH_C32(0xca27301e), SPH_C32(0xc4c0618d), + SPH_C32(0x773c5af0), SPH_C32(0xbb00b75a), SPH_C32(0x33db0001), + SPH_C32(0x3d0f4c00), SPH_C32(0x2fab0000), SPH_C32(0x0de00000), + SPH_C32(0x8d1d0724), SPH_C32(0x6de33223), SPH_C32(0x6bdb10d6), + SPH_C32(0xcf9fceef) }, + { SPH_C32(0x45750003), SPH_C32(0x692ef000), SPH_C32(0xbcee0000), + SPH_C32(0x11570000), SPH_C32(0x6e706cf2), SPH_C32(0xed85292f), + SPH_C32(0xbaf3142e), SPH_C32(0x715bbc8a), SPH_C32(0x87940001), + SPH_C32(0x629b4500), SPH_C32(0x5a480000), SPH_C32(0xa4bb0000), + SPH_C32(0x9c365692), SPH_C32(0xd629e672), SPH_C32(0x985c4dbb), + SPH_C32(0xbe152541) }, + { SPH_C32(0x49070003), SPH_C32(0x20cbff00), SPH_C32(0xfe970000), + SPH_C32(0x4dbd0000), SPH_C32(0x5dda5ce8), SPH_C32(0xf8070c3b), + SPH_C32(0x2f505f55), SPH_C32(0xc510bc1a), SPH_C32(0x79b60001), + SPH_C32(0xc5c34000), SPH_C32(0x7f990000), SPH_C32(0x53db0000), + SPH_C32(0x15072e48), SPH_C32(0xc9fd1e12), SPH_C32(0xd68ceeae), + SPH_C32(0x1f36dade) }, + { SPH_C32(0xbb570003), SPH_C32(0xce76f500), SPH_C32(0x993f0000), + SPH_C32(0xe6370000), SPH_C32(0xe7411428), SPH_C32(0xf251d14f), + SPH_C32(0xf423b73b), SPH_C32(0xd0784315), SPH_C32(0x75c40001), + SPH_C32(0x8c264f00), SPH_C32(0x3de00000), SPH_C32(0x0f310000), + SPH_C32(0x26ad1e52), SPH_C32(0xdc7f3b06), SPH_C32(0x432fa5d5), + SPH_C32(0xab7dda4e) }, + { SPH_C32(0xb7250003), SPH_C32(0x8793fa00), SPH_C32(0xdb460000), + SPH_C32(0xbadd0000), SPH_C32(0xd4eb2432), SPH_C32(0xe7d3f45b), + SPH_C32(0x6180fc40), SPH_C32(0x64334385), SPH_C32(0x8be60001), + SPH_C32(0x2b7e4a00), SPH_C32(0x18310000), SPH_C32(0xf8510000), + SPH_C32(0xaf9c6688), SPH_C32(0xc3abc366), SPH_C32(0x0dff06c0), + SPH_C32(0x0a5e25d1) }, + { SPH_C32(0xb8500003), SPH_C32(0xdaeae100), SPH_C32(0x721e0000), + SPH_C32(0xdfae0000), SPH_C32(0x523d1972), SPH_C32(0x60de4dbc), + SPH_C32(0xca6ba488), SPH_C32(0x6ba9a36b), SPH_C32(0xc28c0001), + SPH_C32(0xc72e5200), SPH_C32(0xa3220000), SPH_C32(0x9ff30000), + SPH_C32(0x82fa42be), SPH_C32(0xf53a73a4), SPH_C32(0x8ee0eb0b), + SPH_C32(0x6126d19e) }, + { SPH_C32(0xb4220003), SPH_C32(0x930fee00), SPH_C32(0x30670000), + SPH_C32(0x83440000), SPH_C32(0x61972968), SPH_C32(0x755c68a8), + SPH_C32(0x5fc8eff3), SPH_C32(0xdfe2a3fb), SPH_C32(0x3cae0001), + SPH_C32(0x60765700), SPH_C32(0x86f30000), SPH_C32(0x68930000), + SPH_C32(0x0bcb3a64), SPH_C32(0xeaee8bc4), SPH_C32(0xc030481e), + SPH_C32(0xc0052e01) }, + { SPH_C32(0x46720003), SPH_C32(0x7db2e400), SPH_C32(0x57cf0000), + SPH_C32(0x28ce0000), SPH_C32(0xdb0c61a8), SPH_C32(0x7f0ab5dc), + SPH_C32(0x84bb079d), SPH_C32(0xca8a5cf4), SPH_C32(0x30dc0001), + SPH_C32(0x29935800), SPH_C32(0xc48a0000), SPH_C32(0x34790000), + SPH_C32(0x38610a7e), SPH_C32(0xff6caed0), SPH_C32(0x55930365), + SPH_C32(0x744e2e91) }, + { SPH_C32(0x4a000003), SPH_C32(0x3457eb00), SPH_C32(0x15b60000), + SPH_C32(0x74240000), SPH_C32(0xe8a651b2), SPH_C32(0x6a8890c8), + SPH_C32(0x11184ce6), SPH_C32(0x7ec15c64), SPH_C32(0xcefe0001), + SPH_C32(0x8ecb5d00), SPH_C32(0xe15b0000), SPH_C32(0xc3190000), + SPH_C32(0xb15072a4), SPH_C32(0xe0b856b0), SPH_C32(0x1b43a070), + SPH_C32(0xd56dd10e) }, + { SPH_C32(0xfd480003), SPH_C32(0x7f5ff600), SPH_C32(0x8b740000), + SPH_C32(0xe4e60000), SPH_C32(0x4cf10d5e), SPH_C32(0x43cdd86a), + SPH_C32(0xdcd70238), SPH_C32(0xb49a57b4), SPH_C32(0x7ab10001), + SPH_C32(0xd15f5400), SPH_C32(0x94b80000), SPH_C32(0x6a420000), + SPH_C32(0xa07b2312), SPH_C32(0x5b7282e1), SPH_C32(0xe8c4fd1d), + SPH_C32(0xa4e73aa0) }, + { SPH_C32(0xf13a0003), SPH_C32(0x36baf900), SPH_C32(0xc90d0000), + SPH_C32(0xb80c0000), SPH_C32(0x7f5b3d44), SPH_C32(0x564ffd7e), + SPH_C32(0x49744943), SPH_C32(0x00d15724), SPH_C32(0x84930001), + SPH_C32(0x76075100), SPH_C32(0xb1690000), SPH_C32(0x9d220000), + SPH_C32(0x294a5bc8), SPH_C32(0x44a67a81), SPH_C32(0xa6145e08), + SPH_C32(0x05c4c53f) }, + { SPH_C32(0x036a0003), SPH_C32(0xd807f300), SPH_C32(0xaea50000), + SPH_C32(0x13860000), SPH_C32(0xc5c07584), SPH_C32(0x5c19200a), + SPH_C32(0x9207a12d), SPH_C32(0x15b9a82b), SPH_C32(0x88e10001), + SPH_C32(0x3fe25e00), SPH_C32(0xf3100000), SPH_C32(0xc1c80000), + SPH_C32(0x1ae06bd2), SPH_C32(0x51245f95), SPH_C32(0x33b71573), + SPH_C32(0xb18fc5af) }, + { SPH_C32(0x0f180003), SPH_C32(0x91e2fc00), SPH_C32(0xecdc0000), + SPH_C32(0x4f6c0000), SPH_C32(0xf66a459e), SPH_C32(0x499b051e), + SPH_C32(0x07a4ea56), SPH_C32(0xa1f2a8bb), SPH_C32(0x76c30001), + SPH_C32(0x98ba5b00), SPH_C32(0xd6c10000), SPH_C32(0x36a80000), + SPH_C32(0x93d11308), SPH_C32(0x4ef0a7f5), SPH_C32(0x7d67b666), + SPH_C32(0x10ac3a30) }, + { SPH_C32(0xa4af0003), SPH_C32(0x15acc300), SPH_C32(0x4fcc0000), + SPH_C32(0x4c7e0000), SPH_C32(0x88c66a19), SPH_C32(0x48284ba5), + SPH_C32(0x0f6b6d0a), SPH_C32(0x85c81200), SPH_C32(0x4a0d0001), + SPH_C32(0xb6616400), SPH_C32(0xf9760000), SPH_C32(0xc1ff0000), + SPH_C32(0x45cf60de), SPH_C32(0x31af1c99), SPH_C32(0xe91f9f2e), + SPH_C32(0xd50ba801) }, + { SPH_C32(0xa8dd0003), SPH_C32(0x5c49cc00), SPH_C32(0x0db50000), + SPH_C32(0x10940000), SPH_C32(0xbb6c5a03), SPH_C32(0x5daa6eb1), + SPH_C32(0x9ac82671), SPH_C32(0x31831290), SPH_C32(0xb42f0001), + SPH_C32(0x11396100), SPH_C32(0xdca70000), SPH_C32(0x369f0000), + SPH_C32(0xccfe1804), SPH_C32(0x2e7be4f9), SPH_C32(0xa7cf3c3b), + SPH_C32(0x7428579e) }, + { SPH_C32(0x5a8d0003), SPH_C32(0xb2f4c600), SPH_C32(0x6a1d0000), + SPH_C32(0xbb1e0000), SPH_C32(0x01f712c3), SPH_C32(0x57fcb3c5), + SPH_C32(0x41bbce1f), SPH_C32(0x24ebed9f), SPH_C32(0xb85d0001), + SPH_C32(0x58dc6e00), SPH_C32(0x9ede0000), SPH_C32(0x6a750000), + SPH_C32(0xff54281e), SPH_C32(0x3bf9c1ed), SPH_C32(0x326c7740), + SPH_C32(0xc063570e) }, + { SPH_C32(0x56ff0003), SPH_C32(0xfb11c900), SPH_C32(0x28640000), + SPH_C32(0xe7f40000), SPH_C32(0x325d22d9), SPH_C32(0x427e96d1), + SPH_C32(0xd4188564), SPH_C32(0x90a0ed0f), SPH_C32(0x467f0001), + SPH_C32(0xff846b00), SPH_C32(0xbb0f0000), SPH_C32(0x9d150000), + SPH_C32(0x766550c4), SPH_C32(0x242d398d), SPH_C32(0x7cbcd455), + SPH_C32(0x6140a891) }, + { SPH_C32(0xe1b70003), SPH_C32(0xb019d400), SPH_C32(0xb6a60000), + SPH_C32(0x77360000), SPH_C32(0x960a7e35), SPH_C32(0x6b3bde73), + SPH_C32(0x19d7cbba), SPH_C32(0x5afbe6df), SPH_C32(0xf2300001), + SPH_C32(0xa0106200), SPH_C32(0xceec0000), SPH_C32(0x344e0000), + SPH_C32(0x674e0172), SPH_C32(0x9fe7eddc), SPH_C32(0x8f3b8938), + SPH_C32(0x10ca433f) }, + { SPH_C32(0xedc50003), SPH_C32(0xf9fcdb00), SPH_C32(0xf4df0000), + SPH_C32(0x2bdc0000), SPH_C32(0xa5a04e2f), SPH_C32(0x7eb9fb67), + SPH_C32(0x8c7480c1), SPH_C32(0xeeb0e64f), SPH_C32(0x0c120001), + SPH_C32(0x07486700), SPH_C32(0xeb3d0000), SPH_C32(0xc32e0000), + SPH_C32(0xee7f79a8), SPH_C32(0x803315bc), SPH_C32(0xc1eb2a2d), + SPH_C32(0xb1e9bca0) }, + { SPH_C32(0x1f950003), SPH_C32(0x1741d100), SPH_C32(0x93770000), + SPH_C32(0x80560000), SPH_C32(0x1f3b06ef), SPH_C32(0x74ef2613), + SPH_C32(0x570768af), SPH_C32(0xfbd81940), SPH_C32(0x00600001), + SPH_C32(0x4ead6800), SPH_C32(0xa9440000), SPH_C32(0x9fc40000), + SPH_C32(0xddd549b2), SPH_C32(0x95b130a8), SPH_C32(0x54486156), + SPH_C32(0x05a2bc30) }, + { SPH_C32(0x13e70003), SPH_C32(0x5ea4de00), SPH_C32(0xd10e0000), + SPH_C32(0xdcbc0000), SPH_C32(0x2c9136f5), SPH_C32(0x616d0307), + SPH_C32(0xc2a423d4), SPH_C32(0x4f9319d0), SPH_C32(0xfe420001), + SPH_C32(0xe9f56d00), SPH_C32(0x8c950000), SPH_C32(0x68a40000), + SPH_C32(0x54e43168), SPH_C32(0x8a65c8c8), SPH_C32(0x1a98c243), + SPH_C32(0xa48143af) }, + { SPH_C32(0x1c920003), SPH_C32(0x03ddc500), SPH_C32(0x78560000), + SPH_C32(0xb9cf0000), SPH_C32(0xaa470bb5), SPH_C32(0xe660bae0), + SPH_C32(0x694f7b1c), SPH_C32(0x4009f93e), SPH_C32(0xb7280001), + SPH_C32(0x05a57500), SPH_C32(0x37860000), SPH_C32(0x0f060000), + SPH_C32(0x7982155e), SPH_C32(0xbcf4780a), SPH_C32(0x99872f88), + SPH_C32(0xcff9b7e0) }, + { SPH_C32(0x10e00003), SPH_C32(0x4a38ca00), SPH_C32(0x3a2f0000), + SPH_C32(0xe5250000), SPH_C32(0x99ed3baf), SPH_C32(0xf3e29ff4), + SPH_C32(0xfcec3067), SPH_C32(0xf442f9ae), SPH_C32(0x490a0001), + SPH_C32(0xa2fd7000), SPH_C32(0x12570000), SPH_C32(0xf8660000), + SPH_C32(0xf0b36d84), SPH_C32(0xa320806a), SPH_C32(0xd7578c9d), + SPH_C32(0x6eda487f) }, + { SPH_C32(0xe2b00003), SPH_C32(0xa485c000), SPH_C32(0x5d870000), + SPH_C32(0x4eaf0000), SPH_C32(0x2376736f), SPH_C32(0xf9b44280), + SPH_C32(0x279fd809), SPH_C32(0xe12a06a1), SPH_C32(0x45780001), + SPH_C32(0xeb187f00), SPH_C32(0x502e0000), SPH_C32(0xa48c0000), + SPH_C32(0xc3195d9e), SPH_C32(0xb6a2a57e), SPH_C32(0x42f4c7e6), + SPH_C32(0xda9148ef) }, + { SPH_C32(0xeec20003), SPH_C32(0xed60cf00), SPH_C32(0x1ffe0000), + SPH_C32(0x12450000), SPH_C32(0x10dc4375), SPH_C32(0xec366794), + SPH_C32(0xb23c9372), SPH_C32(0x55610631), SPH_C32(0xbb5a0001), + SPH_C32(0x4c407a00), SPH_C32(0x75ff0000), SPH_C32(0x53ec0000), + SPH_C32(0x4a282544), SPH_C32(0xa9765d1e), SPH_C32(0x0c2464f3), + SPH_C32(0x7bb2b770) }, + { SPH_C32(0x598a0003), SPH_C32(0xa668d200), SPH_C32(0x813c0000), + SPH_C32(0x82870000), SPH_C32(0xb48b1f99), SPH_C32(0xc5732f36), + SPH_C32(0x7ff3ddac), SPH_C32(0x9f3a0de1), SPH_C32(0x0f150001), + SPH_C32(0x13d47300), SPH_C32(0x001c0000), SPH_C32(0xfab70000), + SPH_C32(0x5b0374f2), SPH_C32(0x12bc894f), SPH_C32(0xffa3399e), + SPH_C32(0x0a385cde) }, + { SPH_C32(0x55f80003), SPH_C32(0xef8ddd00), SPH_C32(0xc3450000), + SPH_C32(0xde6d0000), SPH_C32(0x87212f83), SPH_C32(0xd0f10a22), + SPH_C32(0xea5096d7), SPH_C32(0x2b710d71), SPH_C32(0xf1370001), + SPH_C32(0xb48c7600), SPH_C32(0x25cd0000), SPH_C32(0x0dd70000), + SPH_C32(0xd2320c28), SPH_C32(0x0d68712f), SPH_C32(0xb1739a8b), + SPH_C32(0xab1ba341) }, + { SPH_C32(0xa7a80003), SPH_C32(0x0130d700), SPH_C32(0xa4ed0000), + SPH_C32(0x75e70000), SPH_C32(0x3dba6743), SPH_C32(0xdaa7d756), + SPH_C32(0x31237eb9), SPH_C32(0x3e19f27e), SPH_C32(0xfd450001), + SPH_C32(0xfd697900), SPH_C32(0x67b40000), SPH_C32(0x513d0000), + SPH_C32(0xe1983c32), SPH_C32(0x18ea543b), SPH_C32(0x24d0d1f0), + SPH_C32(0x1f50a3d1) }, + { SPH_C32(0xabda0003), SPH_C32(0x48d5d800), SPH_C32(0xe6940000), + SPH_C32(0x290d0000), SPH_C32(0x0e105759), SPH_C32(0xcf25f242), + SPH_C32(0xa48035c2), SPH_C32(0x8a52f2ee), SPH_C32(0x03670001), + SPH_C32(0x5a317c00), SPH_C32(0x42650000), SPH_C32(0xa65d0000), + SPH_C32(0x68a944e8), SPH_C32(0x073eac5b), SPH_C32(0x6a0072e5), + SPH_C32(0xbe735c4e) }, + { SPH_C32(0xd10b0003), SPH_C32(0xd727e400), SPH_C32(0xdb680000), + SPH_C32(0xdc8b0000), SPH_C32(0x73be3df9), SPH_C32(0x01e6400b), + SPH_C32(0x180ca989), SPH_C32(0x2b17747e), SPH_C32(0x9b6b0001), + SPH_C32(0xaddd6700), SPH_C32(0x679a0000), SPH_C32(0x376b0000), + SPH_C32(0x46cd25f9), SPH_C32(0xfedfe06b), SPH_C32(0x5d5c8439), + SPH_C32(0x5074942a) }, + { SPH_C32(0xdd790003), SPH_C32(0x9ec2eb00), SPH_C32(0x99110000), + SPH_C32(0x80610000), SPH_C32(0x40140de3), SPH_C32(0x1464651f), + SPH_C32(0x8dafe2f2), SPH_C32(0x9f5c74ee), SPH_C32(0x65490001), + SPH_C32(0x0a856200), SPH_C32(0x424b0000), SPH_C32(0xc00b0000), + SPH_C32(0xcffc5d23), SPH_C32(0xe10b180b), SPH_C32(0x138c272c), + SPH_C32(0xf1576bb5) }, + { SPH_C32(0x2f290003), SPH_C32(0x707fe100), SPH_C32(0xfeb90000), + SPH_C32(0x2beb0000), SPH_C32(0xfa8f4523), SPH_C32(0x1e32b86b), + SPH_C32(0x56dc0a9c), SPH_C32(0x8a348be1), SPH_C32(0x693b0001), + SPH_C32(0x43606d00), SPH_C32(0x00320000), SPH_C32(0x9ce10000), + SPH_C32(0xfc566d39), SPH_C32(0xf4893d1f), SPH_C32(0x862f6c57), + SPH_C32(0x451c6b25) }, + { SPH_C32(0x235b0003), SPH_C32(0x399aee00), SPH_C32(0xbcc00000), + SPH_C32(0x77010000), SPH_C32(0xc9257539), SPH_C32(0x0bb09d7f), + SPH_C32(0xc37f41e7), SPH_C32(0x3e7f8b71), SPH_C32(0x97190001), + SPH_C32(0xe4386800), SPH_C32(0x25e30000), SPH_C32(0x6b810000), + SPH_C32(0x756715e3), SPH_C32(0xeb5dc57f), SPH_C32(0xc8ffcf42), + SPH_C32(0xe43f94ba) }, + { SPH_C32(0x94130003), SPH_C32(0x7292f300), SPH_C32(0x22020000), + SPH_C32(0xe7c30000), SPH_C32(0x6d7229d5), SPH_C32(0x22f5d5dd), + SPH_C32(0x0eb00f39), SPH_C32(0xf42480a1), SPH_C32(0x23560001), + SPH_C32(0xbbac6100), SPH_C32(0x50000000), SPH_C32(0xc2da0000), + SPH_C32(0x644c4455), SPH_C32(0x5097112e), SPH_C32(0x3b78922f), + SPH_C32(0x95b57f14) }, + { SPH_C32(0x98610003), SPH_C32(0x3b77fc00), SPH_C32(0x607b0000), + SPH_C32(0xbb290000), SPH_C32(0x5ed819cf), SPH_C32(0x3777f0c9), + SPH_C32(0x9b134442), SPH_C32(0x406f8031), SPH_C32(0xdd740001), + SPH_C32(0x1cf46400), SPH_C32(0x75d10000), SPH_C32(0x35ba0000), + SPH_C32(0xed7d3c8f), SPH_C32(0x4f43e94e), SPH_C32(0x75a8313a), + SPH_C32(0x3496808b) }, + { SPH_C32(0x6a310003), SPH_C32(0xd5caf600), SPH_C32(0x07d30000), + SPH_C32(0x10a30000), SPH_C32(0xe443510f), SPH_C32(0x3d212dbd), + SPH_C32(0x4060ac2c), SPH_C32(0x55077f3e), SPH_C32(0xd1060001), + SPH_C32(0x55116b00), SPH_C32(0x37a80000), SPH_C32(0x69500000), + SPH_C32(0xded70c95), SPH_C32(0x5ac1cc5a), SPH_C32(0xe00b7a41), + SPH_C32(0x80dd801b) }, + { SPH_C32(0x66430003), SPH_C32(0x9c2ff900), SPH_C32(0x45aa0000), + SPH_C32(0x4c490000), SPH_C32(0xd7e96115), SPH_C32(0x28a308a9), + SPH_C32(0xd5c3e757), SPH_C32(0xe14c7fae), SPH_C32(0x2f240001), + SPH_C32(0xf2496e00), SPH_C32(0x12790000), SPH_C32(0x9e300000), + SPH_C32(0x57e6744f), SPH_C32(0x4515343a), SPH_C32(0xaedbd954), + SPH_C32(0x21fe7f84) }, + { SPH_C32(0x69360003), SPH_C32(0xc156e200), SPH_C32(0xecf20000), + SPH_C32(0x293a0000), SPH_C32(0x513f5c55), SPH_C32(0xafaeb14e), + SPH_C32(0x7e28bf9f), SPH_C32(0xeed69f40), SPH_C32(0x664e0001), + SPH_C32(0x1e197600), SPH_C32(0xa96a0000), SPH_C32(0xf9920000), + SPH_C32(0x7a805079), SPH_C32(0x738484f8), SPH_C32(0x2dc4349f), + SPH_C32(0x4a868bcb) }, + { SPH_C32(0x65440003), SPH_C32(0x88b3ed00), SPH_C32(0xae8b0000), + SPH_C32(0x75d00000), SPH_C32(0x62956c4f), SPH_C32(0xba2c945a), + SPH_C32(0xeb8bf4e4), SPH_C32(0x5a9d9fd0), SPH_C32(0x986c0001), + SPH_C32(0xb9417300), SPH_C32(0x8cbb0000), SPH_C32(0x0ef20000), + SPH_C32(0xf3b128a3), SPH_C32(0x6c507c98), SPH_C32(0x6314978a), + SPH_C32(0xeba57454) }, + { SPH_C32(0x97140003), SPH_C32(0x660ee700), SPH_C32(0xc9230000), + SPH_C32(0xde5a0000), SPH_C32(0xd80e248f), SPH_C32(0xb07a492e), + SPH_C32(0x30f81c8a), SPH_C32(0x4ff560df), SPH_C32(0x941e0001), + SPH_C32(0xf0a47c00), SPH_C32(0xcec20000), SPH_C32(0x52180000), + SPH_C32(0xc01b18b9), SPH_C32(0x79d2598c), SPH_C32(0xf6b7dcf1), + SPH_C32(0x5fee74c4) }, + { SPH_C32(0x9b660003), SPH_C32(0x2febe800), SPH_C32(0x8b5a0000), + SPH_C32(0x82b00000), SPH_C32(0xeba41495), SPH_C32(0xa5f86c3a), + SPH_C32(0xa55b57f1), SPH_C32(0xfbbe604f), SPH_C32(0x6a3c0001), + SPH_C32(0x57fc7900), SPH_C32(0xeb130000), SPH_C32(0xa5780000), + SPH_C32(0x492a6063), SPH_C32(0x6606a1ec), SPH_C32(0xb8677fe4), + SPH_C32(0xfecd8b5b) }, + { SPH_C32(0x2c2e0003), SPH_C32(0x64e3f500), SPH_C32(0x15980000), + SPH_C32(0x12720000), SPH_C32(0x4ff34879), SPH_C32(0x8cbd2498), + SPH_C32(0x6894192f), SPH_C32(0x31e56b9f), SPH_C32(0xde730001), + SPH_C32(0x08687000), SPH_C32(0x9ef00000), SPH_C32(0x0c230000), + SPH_C32(0x580131d5), SPH_C32(0xddcc75bd), SPH_C32(0x4be02289), + SPH_C32(0x8f4760f5) }, + { SPH_C32(0x205c0003), SPH_C32(0x2d06fa00), SPH_C32(0x57e10000), + SPH_C32(0x4e980000), SPH_C32(0x7c597863), SPH_C32(0x993f018c), + SPH_C32(0xfd375254), SPH_C32(0x85ae6b0f), SPH_C32(0x20510001), + SPH_C32(0xaf307500), SPH_C32(0xbb210000), SPH_C32(0xfb430000), + SPH_C32(0xd130490f), SPH_C32(0xc2188ddd), SPH_C32(0x0530819c), + SPH_C32(0x2e649f6a) }, + { SPH_C32(0xd20c0003), SPH_C32(0xc3bbf000), SPH_C32(0x30490000), + SPH_C32(0xe5120000), SPH_C32(0xc6c230a3), SPH_C32(0x9369dcf8), + SPH_C32(0x2644ba3a), SPH_C32(0x90c69400), SPH_C32(0x2c230001), + SPH_C32(0xe6d57a00), SPH_C32(0xf9580000), SPH_C32(0xa7a90000), + SPH_C32(0xe29a7915), SPH_C32(0xd79aa8c9), SPH_C32(0x9093cae7), + SPH_C32(0x9a2f9ffa) }, + { SPH_C32(0xde7e0003), SPH_C32(0x8a5eff00), SPH_C32(0x72300000), + SPH_C32(0xb9f80000), SPH_C32(0xf56800b9), SPH_C32(0x86ebf9ec), + SPH_C32(0xb3e7f141), SPH_C32(0x248d9490), SPH_C32(0xd2010001), + SPH_C32(0x418d7f00), SPH_C32(0xdc890000), SPH_C32(0x50c90000), + SPH_C32(0x6bab01cf), SPH_C32(0xc84e50a9), SPH_C32(0xde4369f2), + SPH_C32(0x3b0c6065) }, + { SPH_C32(0xeecf0001), SPH_C32(0x6f564000), SPH_C32(0xf33e0000), + SPH_C32(0xa79e0000), SPH_C32(0xbdb57219), SPH_C32(0xb711ebc5), + SPH_C32(0x4a3b40ba), SPH_C32(0xfeabf254), SPH_C32(0x9b060002), + SPH_C32(0x61468000), SPH_C32(0x221e0000), SPH_C32(0x1d740000), + SPH_C32(0x36715d27), SPH_C32(0x30495c92), SPH_C32(0xf11336a7), + SPH_C32(0xfe1cdc7f) }, + { SPH_C32(0xe2bd0001), SPH_C32(0x26b34f00), SPH_C32(0xb1470000), + SPH_C32(0xfb740000), SPH_C32(0x8e1f4203), SPH_C32(0xa293ced1), + SPH_C32(0xdf980bc1), SPH_C32(0x4ae0f2c4), SPH_C32(0x65240002), + SPH_C32(0xc61e8500), SPH_C32(0x07cf0000), SPH_C32(0xea140000), + SPH_C32(0xbf4025fd), SPH_C32(0x2f9da4f2), SPH_C32(0xbfc395b2), + SPH_C32(0x5f3f23e0) }, + { SPH_C32(0x10ed0001), SPH_C32(0xc80e4500), SPH_C32(0xd6ef0000), + SPH_C32(0x50fe0000), SPH_C32(0x34840ac3), SPH_C32(0xa8c513a5), + SPH_C32(0x04ebe3af), SPH_C32(0x5f880dcb), SPH_C32(0x69560002), + SPH_C32(0x8ffb8a00), SPH_C32(0x45b60000), SPH_C32(0xb6fe0000), + SPH_C32(0x8cea15e7), SPH_C32(0x3a1f81e6), SPH_C32(0x2a60dec9), + SPH_C32(0xeb742370) }, + { SPH_C32(0x1c9f0001), SPH_C32(0x81eb4a00), SPH_C32(0x94960000), + SPH_C32(0x0c140000), SPH_C32(0x072e3ad9), SPH_C32(0xbd4736b1), + SPH_C32(0x9148a8d4), SPH_C32(0xebc30d5b), SPH_C32(0x97740002), + SPH_C32(0x28a38f00), SPH_C32(0x60670000), SPH_C32(0x419e0000), + SPH_C32(0x05db6d3d), SPH_C32(0x25cb7986), SPH_C32(0x64b07ddc), + SPH_C32(0x4a57dcef) }, + { SPH_C32(0xabd70001), SPH_C32(0xcae35700), SPH_C32(0x0a540000), + SPH_C32(0x9cd60000), SPH_C32(0xa3796635), SPH_C32(0x94027e13), + SPH_C32(0x5c87e60a), SPH_C32(0x2198068b), SPH_C32(0x233b0002), + SPH_C32(0x77378600), SPH_C32(0x15840000), SPH_C32(0xe8c50000), + SPH_C32(0x14f03c8b), SPH_C32(0x9e01add7), SPH_C32(0x973720b1), + SPH_C32(0x3bdd3741) }, + { SPH_C32(0xa7a50001), SPH_C32(0x83065800), SPH_C32(0x482d0000), + SPH_C32(0xc03c0000), SPH_C32(0x90d3562f), SPH_C32(0x81805b07), + SPH_C32(0xc924ad71), SPH_C32(0x95d3061b), SPH_C32(0xdd190002), + SPH_C32(0xd06f8300), SPH_C32(0x30550000), SPH_C32(0x1fa50000), + SPH_C32(0x9dc14451), SPH_C32(0x81d555b7), SPH_C32(0xd9e783a4), + SPH_C32(0x9afec8de) }, + { SPH_C32(0x55f50001), SPH_C32(0x6dbb5200), SPH_C32(0x2f850000), + SPH_C32(0x6bb60000), SPH_C32(0x2a481eef), SPH_C32(0x8bd68673), + SPH_C32(0x1257451f), SPH_C32(0x80bbf914), SPH_C32(0xd16b0002), + SPH_C32(0x998a8c00), SPH_C32(0x722c0000), SPH_C32(0x434f0000), + SPH_C32(0xae6b744b), SPH_C32(0x945770a3), SPH_C32(0x4c44c8df), + SPH_C32(0x2eb5c84e) }, + { SPH_C32(0x59870001), SPH_C32(0x245e5d00), SPH_C32(0x6dfc0000), + SPH_C32(0x375c0000), SPH_C32(0x19e22ef5), SPH_C32(0x9e54a367), + SPH_C32(0x87f40e64), SPH_C32(0x34f0f984), SPH_C32(0x2f490002), + SPH_C32(0x3ed28900), SPH_C32(0x57fd0000), SPH_C32(0xb42f0000), + SPH_C32(0x275a0c91), SPH_C32(0x8b8388c3), SPH_C32(0x02946bca), + SPH_C32(0x8f9637d1) }, + { SPH_C32(0x56f20001), SPH_C32(0x79274600), SPH_C32(0xc4a40000), + SPH_C32(0x522f0000), SPH_C32(0x9f3413b5), SPH_C32(0x19591a80), + SPH_C32(0x2c1f56ac), SPH_C32(0x3b6a196a), SPH_C32(0x66230002), + SPH_C32(0xd2829100), SPH_C32(0xecee0000), SPH_C32(0xd38d0000), + SPH_C32(0x0a3c28a7), SPH_C32(0xbd123801), SPH_C32(0x818b8601), + SPH_C32(0xe4eec39e) }, + { SPH_C32(0x5a800001), SPH_C32(0x30c24900), SPH_C32(0x86dd0000), + SPH_C32(0x0ec50000), SPH_C32(0xac9e23af), SPH_C32(0x0cdb3f94), + SPH_C32(0xb9bc1dd7), SPH_C32(0x8f2119fa), SPH_C32(0x98010002), + SPH_C32(0x75da9400), SPH_C32(0xc93f0000), SPH_C32(0x24ed0000), + SPH_C32(0x830d507d), SPH_C32(0xa2c6c061), SPH_C32(0xcf5b2514), + SPH_C32(0x45cd3c01) }, + { SPH_C32(0xa8d00001), SPH_C32(0xde7f4300), SPH_C32(0xe1750000), + SPH_C32(0xa54f0000), SPH_C32(0x16056b6f), SPH_C32(0x068de2e0), + SPH_C32(0x62cff5b9), SPH_C32(0x9a49e6f5), SPH_C32(0x94730002), + SPH_C32(0x3c3f9b00), SPH_C32(0x8b460000), SPH_C32(0x78070000), + SPH_C32(0xb0a76067), SPH_C32(0xb744e575), SPH_C32(0x5af86e6f), + SPH_C32(0xf1863c91) }, + { SPH_C32(0xa4a20001), SPH_C32(0x979a4c00), SPH_C32(0xa30c0000), + SPH_C32(0xf9a50000), SPH_C32(0x25af5b75), SPH_C32(0x130fc7f4), + SPH_C32(0xf76cbec2), SPH_C32(0x2e02e665), SPH_C32(0x6a510002), + SPH_C32(0x9b679e00), SPH_C32(0xae970000), SPH_C32(0x8f670000), + SPH_C32(0x399618bd), SPH_C32(0xa8901d15), SPH_C32(0x1428cd7a), + SPH_C32(0x50a5c30e) }, + { SPH_C32(0x13ea0001), SPH_C32(0xdc925100), SPH_C32(0x3dce0000), + SPH_C32(0x69670000), SPH_C32(0x81f80799), SPH_C32(0x3a4a8f56), + SPH_C32(0x3aa3f01c), SPH_C32(0xe459edb5), SPH_C32(0xde1e0002), + SPH_C32(0xc4f39700), SPH_C32(0xdb740000), SPH_C32(0x263c0000), + SPH_C32(0x28bd490b), SPH_C32(0x135ac944), SPH_C32(0xe7af9017), + SPH_C32(0x212f28a0) }, + { SPH_C32(0x1f980001), SPH_C32(0x95775e00), SPH_C32(0x7fb70000), + SPH_C32(0x358d0000), SPH_C32(0xb2523783), SPH_C32(0x2fc8aa42), + SPH_C32(0xaf00bb67), SPH_C32(0x5012ed25), SPH_C32(0x203c0002), + SPH_C32(0x63ab9200), SPH_C32(0xfea50000), SPH_C32(0xd15c0000), + SPH_C32(0xa18c31d1), SPH_C32(0x0c8e3124), SPH_C32(0xa97f3302), + SPH_C32(0x800cd73f) }, + { SPH_C32(0xedc80001), SPH_C32(0x7bca5400), SPH_C32(0x181f0000), + SPH_C32(0x9e070000), SPH_C32(0x08c97f43), SPH_C32(0x259e7736), + SPH_C32(0x74735309), SPH_C32(0x457a122a), SPH_C32(0x2c4e0002), + SPH_C32(0x2a4e9d00), SPH_C32(0xbcdc0000), SPH_C32(0x8db60000), + SPH_C32(0x922601cb), SPH_C32(0x190c1430), SPH_C32(0x3cdc7879), + SPH_C32(0x3447d7af) }, + { SPH_C32(0xe1ba0001), SPH_C32(0x322f5b00), SPH_C32(0x5a660000), + SPH_C32(0xc2ed0000), SPH_C32(0x3b634f59), SPH_C32(0x301c5222), + SPH_C32(0xe1d01872), SPH_C32(0xf13112ba), SPH_C32(0xd26c0002), + SPH_C32(0x8d169800), SPH_C32(0x990d0000), SPH_C32(0x7ad60000), + SPH_C32(0x1b177911), SPH_C32(0x06d8ec50), SPH_C32(0x720cdb6c), + SPH_C32(0x95642830) }, + { SPH_C32(0x9b6b0001), SPH_C32(0xaddd6700), SPH_C32(0x679a0000), + SPH_C32(0x376b0000), SPH_C32(0x46cd25f9), SPH_C32(0xfedfe06b), + SPH_C32(0x5d5c8439), SPH_C32(0x5074942a), SPH_C32(0x4a600002), + SPH_C32(0x7afa8300), SPH_C32(0xbcf20000), SPH_C32(0xebe00000), + SPH_C32(0x35731800), SPH_C32(0xff39a060), SPH_C32(0x45502db0), + SPH_C32(0x7b63e054) }, + { SPH_C32(0x97190001), SPH_C32(0xe4386800), SPH_C32(0x25e30000), + SPH_C32(0x6b810000), SPH_C32(0x756715e3), SPH_C32(0xeb5dc57f), + SPH_C32(0xc8ffcf42), SPH_C32(0xe43f94ba), SPH_C32(0xb4420002), + SPH_C32(0xdda28600), SPH_C32(0x99230000), SPH_C32(0x1c800000), + SPH_C32(0xbc4260da), SPH_C32(0xe0ed5800), SPH_C32(0x0b808ea5), + SPH_C32(0xda401fcb) }, + { SPH_C32(0x65490001), SPH_C32(0x0a856200), SPH_C32(0x424b0000), + SPH_C32(0xc00b0000), SPH_C32(0xcffc5d23), SPH_C32(0xe10b180b), + SPH_C32(0x138c272c), SPH_C32(0xf1576bb5), SPH_C32(0xb8300002), + SPH_C32(0x94478900), SPH_C32(0xdb5a0000), SPH_C32(0x406a0000), + SPH_C32(0x8fe850c0), SPH_C32(0xf56f7d14), SPH_C32(0x9e23c5de), + SPH_C32(0x6e0b1f5b) }, + { SPH_C32(0x693b0001), SPH_C32(0x43606d00), SPH_C32(0x00320000), + SPH_C32(0x9ce10000), SPH_C32(0xfc566d39), SPH_C32(0xf4893d1f), + SPH_C32(0x862f6c57), SPH_C32(0x451c6b25), SPH_C32(0x46120002), + SPH_C32(0x331f8c00), SPH_C32(0xfe8b0000), SPH_C32(0xb70a0000), + SPH_C32(0x06d9281a), SPH_C32(0xeabb8574), SPH_C32(0xd0f366cb), + SPH_C32(0xcf28e0c4) }, + { SPH_C32(0xde730001), SPH_C32(0x08687000), SPH_C32(0x9ef00000), + SPH_C32(0x0c230000), SPH_C32(0x580131d5), SPH_C32(0xddcc75bd), + SPH_C32(0x4be02289), SPH_C32(0x8f4760f5), SPH_C32(0xf25d0002), + SPH_C32(0x6c8b8500), SPH_C32(0x8b680000), SPH_C32(0x1e510000), + SPH_C32(0x17f279ac), SPH_C32(0x51715125), SPH_C32(0x23743ba6), + SPH_C32(0xbea20b6a) }, + { SPH_C32(0xd2010001), SPH_C32(0x418d7f00), SPH_C32(0xdc890000), + SPH_C32(0x50c90000), SPH_C32(0x6bab01cf), SPH_C32(0xc84e50a9), + SPH_C32(0xde4369f2), SPH_C32(0x3b0c6065), SPH_C32(0x0c7f0002), + SPH_C32(0xcbd38000), SPH_C32(0xaeb90000), SPH_C32(0xe9310000), + SPH_C32(0x9ec30176), SPH_C32(0x4ea5a945), SPH_C32(0x6da498b3), + SPH_C32(0x1f81f4f5) }, + { SPH_C32(0x20510001), SPH_C32(0xaf307500), SPH_C32(0xbb210000), + SPH_C32(0xfb430000), SPH_C32(0xd130490f), SPH_C32(0xc2188ddd), + SPH_C32(0x0530819c), SPH_C32(0x2e649f6a), SPH_C32(0x000d0002), + SPH_C32(0x82368f00), SPH_C32(0xecc00000), SPH_C32(0xb5db0000), + SPH_C32(0xad69316c), SPH_C32(0x5b278c51), SPH_C32(0xf807d3c8), + SPH_C32(0xabcaf465) }, + { SPH_C32(0x2c230001), SPH_C32(0xe6d57a00), SPH_C32(0xf9580000), + SPH_C32(0xa7a90000), SPH_C32(0xe29a7915), SPH_C32(0xd79aa8c9), + SPH_C32(0x9093cae7), SPH_C32(0x9a2f9ffa), SPH_C32(0xfe2f0002), + SPH_C32(0x256e8a00), SPH_C32(0xc9110000), SPH_C32(0x42bb0000), + SPH_C32(0x245849b6), SPH_C32(0x44f37431), SPH_C32(0xb6d770dd), + SPH_C32(0x0ae90bfa) }, + { SPH_C32(0x23560001), SPH_C32(0xbbac6100), SPH_C32(0x50000000), + SPH_C32(0xc2da0000), SPH_C32(0x644c4455), SPH_C32(0x5097112e), + SPH_C32(0x3b78922f), SPH_C32(0x95b57f14), SPH_C32(0xb7450002), + SPH_C32(0xc93e9200), SPH_C32(0x72020000), SPH_C32(0x25190000), + SPH_C32(0x093e6d80), SPH_C32(0x7262c4f3), SPH_C32(0x35c89d16), + SPH_C32(0x6191ffb5) }, + { SPH_C32(0x2f240001), SPH_C32(0xf2496e00), SPH_C32(0x12790000), + SPH_C32(0x9e300000), SPH_C32(0x57e6744f), SPH_C32(0x4515343a), + SPH_C32(0xaedbd954), SPH_C32(0x21fe7f84), SPH_C32(0x49670002), + SPH_C32(0x6e669700), SPH_C32(0x57d30000), SPH_C32(0xd2790000), + SPH_C32(0x800f155a), SPH_C32(0x6db63c93), SPH_C32(0x7b183e03), + SPH_C32(0xc0b2002a) }, + { SPH_C32(0xdd740001), SPH_C32(0x1cf46400), SPH_C32(0x75d10000), + SPH_C32(0x35ba0000), SPH_C32(0xed7d3c8f), SPH_C32(0x4f43e94e), + SPH_C32(0x75a8313a), SPH_C32(0x3496808b), SPH_C32(0x45150002), + SPH_C32(0x27839800), SPH_C32(0x15aa0000), SPH_C32(0x8e930000), + SPH_C32(0xb3a52540), SPH_C32(0x78341987), SPH_C32(0xeebb7578), + SPH_C32(0x74f900ba) }, + { SPH_C32(0xd1060001), SPH_C32(0x55116b00), SPH_C32(0x37a80000), + SPH_C32(0x69500000), SPH_C32(0xded70c95), SPH_C32(0x5ac1cc5a), + SPH_C32(0xe00b7a41), SPH_C32(0x80dd801b), SPH_C32(0xbb370002), + SPH_C32(0x80db9d00), SPH_C32(0x307b0000), SPH_C32(0x79f30000), + SPH_C32(0x3a945d9a), SPH_C32(0x67e0e1e7), SPH_C32(0xa06bd66d), + SPH_C32(0xd5daff25) }, + { SPH_C32(0x664e0001), SPH_C32(0x1e197600), SPH_C32(0xa96a0000), + SPH_C32(0xf9920000), SPH_C32(0x7a805079), SPH_C32(0x738484f8), + SPH_C32(0x2dc4349f), SPH_C32(0x4a868bcb), SPH_C32(0x0f780002), + SPH_C32(0xdf4f9400), SPH_C32(0x45980000), SPH_C32(0xd0a80000), + SPH_C32(0x2bbf0c2c), SPH_C32(0xdc2a35b6), SPH_C32(0x53ec8b00), + SPH_C32(0xa450148b) }, + { SPH_C32(0x6a3c0001), SPH_C32(0x57fc7900), SPH_C32(0xeb130000), + SPH_C32(0xa5780000), SPH_C32(0x492a6063), SPH_C32(0x6606a1ec), + SPH_C32(0xb8677fe4), SPH_C32(0xfecd8b5b), SPH_C32(0xf15a0002), + SPH_C32(0x78179100), SPH_C32(0x60490000), SPH_C32(0x27c80000), + SPH_C32(0xa28e74f6), SPH_C32(0xc3fecdd6), SPH_C32(0x1d3c2815), + SPH_C32(0x0573eb14) }, + { SPH_C32(0x986c0001), SPH_C32(0xb9417300), SPH_C32(0x8cbb0000), + SPH_C32(0x0ef20000), SPH_C32(0xf3b128a3), SPH_C32(0x6c507c98), + SPH_C32(0x6314978a), SPH_C32(0xeba57454), SPH_C32(0xfd280002), + SPH_C32(0x31f29e00), SPH_C32(0x22300000), SPH_C32(0x7b220000), + SPH_C32(0x912444ec), SPH_C32(0xd67ce8c2), SPH_C32(0x889f636e), + SPH_C32(0xb138eb84) }, + { SPH_C32(0x941e0001), SPH_C32(0xf0a47c00), SPH_C32(0xcec20000), + SPH_C32(0x52180000), SPH_C32(0xc01b18b9), SPH_C32(0x79d2598c), + SPH_C32(0xf6b7dcf1), SPH_C32(0x5fee74c4), SPH_C32(0x030a0002), + SPH_C32(0x96aa9b00), SPH_C32(0x07e10000), SPH_C32(0x8c420000), + SPH_C32(0x18153c36), SPH_C32(0xc9a810a2), SPH_C32(0xc64fc07b), + SPH_C32(0x101b141b) }, + { SPH_C32(0x3fa90001), SPH_C32(0x74ea4300), SPH_C32(0x6dd20000), + SPH_C32(0x510a0000), SPH_C32(0xbeb7373e), SPH_C32(0x78611737), + SPH_C32(0xfe785bad), SPH_C32(0x7bd4ce7f), SPH_C32(0x3fc40002), + SPH_C32(0xb871a400), SPH_C32(0x28560000), SPH_C32(0x7b150000), + SPH_C32(0xce0b4fe0), SPH_C32(0xb6f7abce), SPH_C32(0x5237e933), + SPH_C32(0xd5bc862a) }, + { SPH_C32(0x33db0001), SPH_C32(0x3d0f4c00), SPH_C32(0x2fab0000), + SPH_C32(0x0de00000), SPH_C32(0x8d1d0724), SPH_C32(0x6de33223), + SPH_C32(0x6bdb10d6), SPH_C32(0xcf9fceef), SPH_C32(0xc1e60002), + SPH_C32(0x1f29a100), SPH_C32(0x0d870000), SPH_C32(0x8c750000), + SPH_C32(0x473a373a), SPH_C32(0xa92353ae), SPH_C32(0x1ce74a26), + SPH_C32(0x749f79b5) }, + { SPH_C32(0xc18b0001), SPH_C32(0xd3b24600), SPH_C32(0x48030000), + SPH_C32(0xa66a0000), SPH_C32(0x37864fe4), SPH_C32(0x67b5ef57), + SPH_C32(0xb0a8f8b8), SPH_C32(0xdaf731e0), SPH_C32(0xcd940002), + SPH_C32(0x56ccae00), SPH_C32(0x4ffe0000), SPH_C32(0xd09f0000), + SPH_C32(0x74900720), SPH_C32(0xbca176ba), SPH_C32(0x8944015d), + SPH_C32(0xc0d47925) }, + { SPH_C32(0xcdf90001), SPH_C32(0x9a574900), SPH_C32(0x0a7a0000), + SPH_C32(0xfa800000), SPH_C32(0x042c7ffe), SPH_C32(0x7237ca43), + SPH_C32(0x250bb3c3), SPH_C32(0x6ebc3170), SPH_C32(0x33b60002), + SPH_C32(0xf194ab00), SPH_C32(0x6a2f0000), SPH_C32(0x27ff0000), + SPH_C32(0xfda17ffa), SPH_C32(0xa3758eda), SPH_C32(0xc794a248), + SPH_C32(0x61f786ba) }, + { SPH_C32(0x7ab10001), SPH_C32(0xd15f5400), SPH_C32(0x94b80000), + SPH_C32(0x6a420000), SPH_C32(0xa07b2312), SPH_C32(0x5b7282e1), + SPH_C32(0xe8c4fd1d), SPH_C32(0xa4e73aa0), SPH_C32(0x87f90002), + SPH_C32(0xae00a200), SPH_C32(0x1fcc0000), SPH_C32(0x8ea40000), + SPH_C32(0xec8a2e4c), SPH_C32(0x18bf5a8b), SPH_C32(0x3413ff25), + SPH_C32(0x107d6d14) }, + { SPH_C32(0x76c30001), SPH_C32(0x98ba5b00), SPH_C32(0xd6c10000), + SPH_C32(0x36a80000), SPH_C32(0x93d11308), SPH_C32(0x4ef0a7f5), + SPH_C32(0x7d67b666), SPH_C32(0x10ac3a30), SPH_C32(0x79db0002), + SPH_C32(0x0958a700), SPH_C32(0x3a1d0000), SPH_C32(0x79c40000), + SPH_C32(0x65bb5696), SPH_C32(0x076ba2eb), SPH_C32(0x7ac35c30), + SPH_C32(0xb15e928b) }, + { SPH_C32(0x84930001), SPH_C32(0x76075100), SPH_C32(0xb1690000), + SPH_C32(0x9d220000), SPH_C32(0x294a5bc8), SPH_C32(0x44a67a81), + SPH_C32(0xa6145e08), SPH_C32(0x05c4c53f), SPH_C32(0x75a90002), + SPH_C32(0x40bda800), SPH_C32(0x78640000), SPH_C32(0x252e0000), + SPH_C32(0x5611668c), SPH_C32(0x12e987ff), SPH_C32(0xef60174b), + SPH_C32(0x0515921b) }, + { SPH_C32(0x88e10001), SPH_C32(0x3fe25e00), SPH_C32(0xf3100000), + SPH_C32(0xc1c80000), SPH_C32(0x1ae06bd2), SPH_C32(0x51245f95), + SPH_C32(0x33b71573), SPH_C32(0xb18fc5af), SPH_C32(0x8b8b0002), + SPH_C32(0xe7e5ad00), SPH_C32(0x5db50000), SPH_C32(0xd24e0000), + SPH_C32(0xdf201e56), SPH_C32(0x0d3d7f9f), SPH_C32(0xa1b0b45e), + SPH_C32(0xa4366d84) }, + { SPH_C32(0x87940001), SPH_C32(0x629b4500), SPH_C32(0x5a480000), + SPH_C32(0xa4bb0000), SPH_C32(0x9c365692), SPH_C32(0xd629e672), + SPH_C32(0x985c4dbb), SPH_C32(0xbe152541), SPH_C32(0xc2e10002), + SPH_C32(0x0bb5b500), SPH_C32(0xe6a60000), SPH_C32(0xb5ec0000), + SPH_C32(0xf2463a60), SPH_C32(0x3baccf5d), SPH_C32(0x22af5995), + SPH_C32(0xcf4e99cb) }, + { SPH_C32(0x8be60001), SPH_C32(0x2b7e4a00), SPH_C32(0x18310000), + SPH_C32(0xf8510000), SPH_C32(0xaf9c6688), SPH_C32(0xc3abc366), + SPH_C32(0x0dff06c0), SPH_C32(0x0a5e25d1), SPH_C32(0x3cc30002), + SPH_C32(0xacedb000), SPH_C32(0xc3770000), SPH_C32(0x428c0000), + SPH_C32(0x7b7742ba), SPH_C32(0x2478373d), SPH_C32(0x6c7ffa80), + SPH_C32(0x6e6d6654) }, + { SPH_C32(0x79b60001), SPH_C32(0xc5c34000), SPH_C32(0x7f990000), + SPH_C32(0x53db0000), SPH_C32(0x15072e48), SPH_C32(0xc9fd1e12), + SPH_C32(0xd68ceeae), SPH_C32(0x1f36dade), SPH_C32(0x30b10002), + SPH_C32(0xe508bf00), SPH_C32(0x810e0000), SPH_C32(0x1e660000), + SPH_C32(0x48dd72a0), SPH_C32(0x31fa1229), SPH_C32(0xf9dcb1fb), + SPH_C32(0xda2666c4) }, + { SPH_C32(0x75c40001), SPH_C32(0x8c264f00), SPH_C32(0x3de00000), + SPH_C32(0x0f310000), SPH_C32(0x26ad1e52), SPH_C32(0xdc7f3b06), + SPH_C32(0x432fa5d5), SPH_C32(0xab7dda4e), SPH_C32(0xce930002), + SPH_C32(0x4250ba00), SPH_C32(0xa4df0000), SPH_C32(0xe9060000), + SPH_C32(0xc1ec0a7a), SPH_C32(0x2e2eea49), SPH_C32(0xb70c12ee), + SPH_C32(0x7b05995b) }, + { SPH_C32(0xc28c0001), SPH_C32(0xc72e5200), SPH_C32(0xa3220000), + SPH_C32(0x9ff30000), SPH_C32(0x82fa42be), SPH_C32(0xf53a73a4), + SPH_C32(0x8ee0eb0b), SPH_C32(0x6126d19e), SPH_C32(0x7adc0002), + SPH_C32(0x1dc4b300), SPH_C32(0xd13c0000), SPH_C32(0x405d0000), + SPH_C32(0xd0c75bcc), SPH_C32(0x95e43e18), SPH_C32(0x448b4f83), + SPH_C32(0x0a8f72f5) }, + { SPH_C32(0xcefe0001), SPH_C32(0x8ecb5d00), SPH_C32(0xe15b0000), + SPH_C32(0xc3190000), SPH_C32(0xb15072a4), SPH_C32(0xe0b856b0), + SPH_C32(0x1b43a070), SPH_C32(0xd56dd10e), SPH_C32(0x84fe0002), + SPH_C32(0xba9cb600), SPH_C32(0xf4ed0000), SPH_C32(0xb73d0000), + SPH_C32(0x59f62316), SPH_C32(0x8a30c678), SPH_C32(0x0a5bec96), + SPH_C32(0xabac8d6a) }, + { SPH_C32(0x3cae0001), SPH_C32(0x60765700), SPH_C32(0x86f30000), + SPH_C32(0x68930000), SPH_C32(0x0bcb3a64), SPH_C32(0xeaee8bc4), + SPH_C32(0xc030481e), SPH_C32(0xc0052e01), SPH_C32(0x888c0002), + SPH_C32(0xf379b900), SPH_C32(0xb6940000), SPH_C32(0xebd70000), + SPH_C32(0x6a5c130c), SPH_C32(0x9fb2e36c), SPH_C32(0x9ff8a7ed), + SPH_C32(0x1fe78dfa) }, + { SPH_C32(0x30dc0001), SPH_C32(0x29935800), SPH_C32(0xc48a0000), + SPH_C32(0x34790000), SPH_C32(0x38610a7e), SPH_C32(0xff6caed0), + SPH_C32(0x55930365), SPH_C32(0x744e2e91), SPH_C32(0x76ae0002), + SPH_C32(0x5421bc00), SPH_C32(0x93450000), SPH_C32(0x1cb70000), + SPH_C32(0xe36d6bd6), SPH_C32(0x80661b0c), SPH_C32(0xd12804f8), + SPH_C32(0xbec47265) }, + { SPH_C32(0x4a0d0001), SPH_C32(0xb6616400), SPH_C32(0xf9760000), + SPH_C32(0xc1ff0000), SPH_C32(0x45cf60de), SPH_C32(0x31af1c99), + SPH_C32(0xe91f9f2e), SPH_C32(0xd50ba801), SPH_C32(0xeea20002), + SPH_C32(0xa3cda700), SPH_C32(0xb6ba0000), SPH_C32(0x8d810000), + SPH_C32(0xcd090ac7), SPH_C32(0x7987573c), SPH_C32(0xe674f224), + SPH_C32(0x50c3ba01) }, + { SPH_C32(0x467f0001), SPH_C32(0xff846b00), SPH_C32(0xbb0f0000), + SPH_C32(0x9d150000), SPH_C32(0x766550c4), SPH_C32(0x242d398d), + SPH_C32(0x7cbcd455), SPH_C32(0x6140a891), SPH_C32(0x10800002), + SPH_C32(0x0495a200), SPH_C32(0x936b0000), SPH_C32(0x7ae10000), + SPH_C32(0x4438721d), SPH_C32(0x6653af5c), SPH_C32(0xa8a45131), + SPH_C32(0xf1e0459e) }, + { SPH_C32(0xb42f0001), SPH_C32(0x11396100), SPH_C32(0xdca70000), + SPH_C32(0x369f0000), SPH_C32(0xccfe1804), SPH_C32(0x2e7be4f9), + SPH_C32(0xa7cf3c3b), SPH_C32(0x7428579e), SPH_C32(0x1cf20002), + SPH_C32(0x4d70ad00), SPH_C32(0xd1120000), SPH_C32(0x260b0000), + SPH_C32(0x77924207), SPH_C32(0x73d18a48), SPH_C32(0x3d071a4a), + SPH_C32(0x45ab450e) }, + { SPH_C32(0xb85d0001), SPH_C32(0x58dc6e00), SPH_C32(0x9ede0000), + SPH_C32(0x6a750000), SPH_C32(0xff54281e), SPH_C32(0x3bf9c1ed), + SPH_C32(0x326c7740), SPH_C32(0xc063570e), SPH_C32(0xe2d00002), + SPH_C32(0xea28a800), SPH_C32(0xf4c30000), SPH_C32(0xd16b0000), + SPH_C32(0xfea33add), SPH_C32(0x6c057228), SPH_C32(0x73d7b95f), + SPH_C32(0xe488ba91) }, + { SPH_C32(0x0f150001), SPH_C32(0x13d47300), SPH_C32(0x001c0000), + SPH_C32(0xfab70000), SPH_C32(0x5b0374f2), SPH_C32(0x12bc894f), + SPH_C32(0xffa3399e), SPH_C32(0x0a385cde), SPH_C32(0x569f0002), + SPH_C32(0xb5bca100), SPH_C32(0x81200000), SPH_C32(0x78300000), + SPH_C32(0xef886b6b), SPH_C32(0xd7cfa679), SPH_C32(0x8050e432), + SPH_C32(0x9502513f) }, + { SPH_C32(0x03670001), SPH_C32(0x5a317c00), SPH_C32(0x42650000), + SPH_C32(0xa65d0000), SPH_C32(0x68a944e8), SPH_C32(0x073eac5b), + SPH_C32(0x6a0072e5), SPH_C32(0xbe735c4e), SPH_C32(0xa8bd0002), + SPH_C32(0x12e4a400), SPH_C32(0xa4f10000), SPH_C32(0x8f500000), + SPH_C32(0x66b913b1), SPH_C32(0xc81b5e19), SPH_C32(0xce804727), + SPH_C32(0x3421aea0) }, + { SPH_C32(0xf1370001), SPH_C32(0xb48c7600), SPH_C32(0x25cd0000), + SPH_C32(0x0dd70000), SPH_C32(0xd2320c28), SPH_C32(0x0d68712f), + SPH_C32(0xb1739a8b), SPH_C32(0xab1ba341), SPH_C32(0xa4cf0002), + SPH_C32(0x5b01ab00), SPH_C32(0xe6880000), SPH_C32(0xd3ba0000), + SPH_C32(0x551323ab), SPH_C32(0xdd997b0d), SPH_C32(0x5b230c5c), + SPH_C32(0x806aae30) }, + { SPH_C32(0xfd450001), SPH_C32(0xfd697900), SPH_C32(0x67b40000), + SPH_C32(0x513d0000), SPH_C32(0xe1983c32), SPH_C32(0x18ea543b), + SPH_C32(0x24d0d1f0), SPH_C32(0x1f50a3d1), SPH_C32(0x5aed0002), + SPH_C32(0xfc59ae00), SPH_C32(0xc3590000), SPH_C32(0x24da0000), + SPH_C32(0xdc225b71), SPH_C32(0xc24d836d), SPH_C32(0x15f3af49), + SPH_C32(0x214951af) }, + { SPH_C32(0xf2300001), SPH_C32(0xa0106200), SPH_C32(0xceec0000), + SPH_C32(0x344e0000), SPH_C32(0x674e0172), SPH_C32(0x9fe7eddc), + SPH_C32(0x8f3b8938), SPH_C32(0x10ca433f), SPH_C32(0x13870002), + SPH_C32(0x1009b600), SPH_C32(0x784a0000), SPH_C32(0x43780000), + SPH_C32(0xf1447f47), SPH_C32(0xf4dc33af), SPH_C32(0x96ec4282), + SPH_C32(0x4a31a5e0) }, + { SPH_C32(0xfe420001), SPH_C32(0xe9f56d00), SPH_C32(0x8c950000), + SPH_C32(0x68a40000), SPH_C32(0x54e43168), SPH_C32(0x8a65c8c8), + SPH_C32(0x1a98c243), SPH_C32(0xa48143af), SPH_C32(0xeda50002), + SPH_C32(0xb751b300), SPH_C32(0x5d9b0000), SPH_C32(0xb4180000), + SPH_C32(0x7875079d), SPH_C32(0xeb08cbcf), SPH_C32(0xd83ce197), + SPH_C32(0xeb125a7f) }, + { SPH_C32(0x0c120001), SPH_C32(0x07486700), SPH_C32(0xeb3d0000), + SPH_C32(0xc32e0000), SPH_C32(0xee7f79a8), SPH_C32(0x803315bc), + SPH_C32(0xc1eb2a2d), SPH_C32(0xb1e9bca0), SPH_C32(0xe1d70002), + SPH_C32(0xfeb4bc00), SPH_C32(0x1fe20000), SPH_C32(0xe8f20000), + SPH_C32(0x4bdf3787), SPH_C32(0xfe8aeedb), SPH_C32(0x4d9faaec), + SPH_C32(0x5f595aef) }, + { SPH_C32(0x00600001), SPH_C32(0x4ead6800), SPH_C32(0xa9440000), + SPH_C32(0x9fc40000), SPH_C32(0xddd549b2), SPH_C32(0x95b130a8), + SPH_C32(0x54486156), SPH_C32(0x05a2bc30), SPH_C32(0x1ff50002), + SPH_C32(0x59ecb900), SPH_C32(0x3a330000), SPH_C32(0x1f920000), + SPH_C32(0xc2ee4f5d), SPH_C32(0xe15e16bb), SPH_C32(0x034f09f9), + SPH_C32(0xfe7aa570) }, + { SPH_C32(0xb7280001), SPH_C32(0x05a57500), SPH_C32(0x37860000), + SPH_C32(0x0f060000), SPH_C32(0x7982155e), SPH_C32(0xbcf4780a), + SPH_C32(0x99872f88), SPH_C32(0xcff9b7e0), SPH_C32(0xabba0002), + SPH_C32(0x0678b000), SPH_C32(0x4fd00000), SPH_C32(0xb6c90000), + SPH_C32(0xd3c51eeb), SPH_C32(0x5a94c2ea), SPH_C32(0xf0c85494), + SPH_C32(0x8ff04ede) }, + { SPH_C32(0xbb5a0001), SPH_C32(0x4c407a00), SPH_C32(0x75ff0000), + SPH_C32(0x53ec0000), SPH_C32(0x4a282544), SPH_C32(0xa9765d1e), + SPH_C32(0x0c2464f3), SPH_C32(0x7bb2b770), SPH_C32(0x55980002), + SPH_C32(0xa120b500), SPH_C32(0x6a010000), SPH_C32(0x41a90000), + SPH_C32(0x5af46631), SPH_C32(0x45403a8a), SPH_C32(0xbe18f781), + SPH_C32(0x2ed3b141) }, + { SPH_C32(0x490a0001), SPH_C32(0xa2fd7000), SPH_C32(0x12570000), + SPH_C32(0xf8660000), SPH_C32(0xf0b36d84), SPH_C32(0xa320806a), + SPH_C32(0xd7578c9d), SPH_C32(0x6eda487f), SPH_C32(0x59ea0002), + SPH_C32(0xe8c5ba00), SPH_C32(0x28780000), SPH_C32(0x1d430000), + SPH_C32(0x695e562b), SPH_C32(0x50c21f9e), SPH_C32(0x2bbbbcfa), + SPH_C32(0x9a98b1d1) }, + { SPH_C32(0x45780001), SPH_C32(0xeb187f00), SPH_C32(0x502e0000), + SPH_C32(0xa48c0000), SPH_C32(0xc3195d9e), SPH_C32(0xb6a2a57e), + SPH_C32(0x42f4c7e6), SPH_C32(0xda9148ef), SPH_C32(0xa7c80002), + SPH_C32(0x4f9dbf00), SPH_C32(0x0da90000), SPH_C32(0xea230000), + SPH_C32(0xe06f2ef1), SPH_C32(0x4f16e7fe), SPH_C32(0x656b1fef), + SPH_C32(0x3bbb4e4e) }, + { SPH_C32(0x9b060002), SPH_C32(0x61468000), SPH_C32(0x221e0000), + SPH_C32(0x1d740000), SPH_C32(0x36715d27), SPH_C32(0x30495c92), + SPH_C32(0xf11336a7), SPH_C32(0xfe1cdc7f), SPH_C32(0x75c90003), + SPH_C32(0x0e10c000), SPH_C32(0xd1200000), SPH_C32(0xbaea0000), + SPH_C32(0x8bc42f3e), SPH_C32(0x8758b757), SPH_C32(0xbb28761d), + SPH_C32(0x00b72e2b) }, + { SPH_C32(0x97740002), SPH_C32(0x28a38f00), SPH_C32(0x60670000), + SPH_C32(0x419e0000), SPH_C32(0x05db6d3d), SPH_C32(0x25cb7986), + SPH_C32(0x64b07ddc), SPH_C32(0x4a57dcef), SPH_C32(0x8beb0003), + SPH_C32(0xa948c500), SPH_C32(0xf4f10000), SPH_C32(0x4d8a0000), + SPH_C32(0x02f557e4), SPH_C32(0x988c4f37), SPH_C32(0xf5f8d508), + SPH_C32(0xa194d1b4) }, + { SPH_C32(0x65240002), SPH_C32(0xc61e8500), SPH_C32(0x07cf0000), + SPH_C32(0xea140000), SPH_C32(0xbf4025fd), SPH_C32(0x2f9da4f2), + SPH_C32(0xbfc395b2), SPH_C32(0x5f3f23e0), SPH_C32(0x87990003), + SPH_C32(0xe0adca00), SPH_C32(0xb6880000), SPH_C32(0x11600000), + SPH_C32(0x315f67fe), SPH_C32(0x8d0e6a23), SPH_C32(0x605b9e73), + SPH_C32(0x15dfd124) }, + { SPH_C32(0x69560002), SPH_C32(0x8ffb8a00), SPH_C32(0x45b60000), + SPH_C32(0xb6fe0000), SPH_C32(0x8cea15e7), SPH_C32(0x3a1f81e6), + SPH_C32(0x2a60dec9), SPH_C32(0xeb742370), SPH_C32(0x79bb0003), + SPH_C32(0x47f5cf00), SPH_C32(0x93590000), SPH_C32(0xe6000000), + SPH_C32(0xb86e1f24), SPH_C32(0x92da9243), SPH_C32(0x2e8b3d66), + SPH_C32(0xb4fc2ebb) }, + { SPH_C32(0xde1e0002), SPH_C32(0xc4f39700), SPH_C32(0xdb740000), + SPH_C32(0x263c0000), SPH_C32(0x28bd490b), SPH_C32(0x135ac944), + SPH_C32(0xe7af9017), SPH_C32(0x212f28a0), SPH_C32(0xcdf40003), + SPH_C32(0x1861c600), SPH_C32(0xe6ba0000), SPH_C32(0x4f5b0000), + SPH_C32(0xa9454e92), SPH_C32(0x29104612), SPH_C32(0xdd0c600b), + SPH_C32(0xc576c515) }, + { SPH_C32(0xd26c0002), SPH_C32(0x8d169800), SPH_C32(0x990d0000), + SPH_C32(0x7ad60000), SPH_C32(0x1b177911), SPH_C32(0x06d8ec50), + SPH_C32(0x720cdb6c), SPH_C32(0x95642830), SPH_C32(0x33d60003), + SPH_C32(0xbf39c300), SPH_C32(0xc36b0000), SPH_C32(0xb83b0000), + SPH_C32(0x20743648), SPH_C32(0x36c4be72), SPH_C32(0x93dcc31e), + SPH_C32(0x64553a8a) }, + { SPH_C32(0x203c0002), SPH_C32(0x63ab9200), SPH_C32(0xfea50000), + SPH_C32(0xd15c0000), SPH_C32(0xa18c31d1), SPH_C32(0x0c8e3124), + SPH_C32(0xa97f3302), SPH_C32(0x800cd73f), SPH_C32(0x3fa40003), + SPH_C32(0xf6dccc00), SPH_C32(0x81120000), SPH_C32(0xe4d10000), + SPH_C32(0x13de0652), SPH_C32(0x23469b66), SPH_C32(0x067f8865), + SPH_C32(0xd01e3a1a) }, + { SPH_C32(0x2c4e0002), SPH_C32(0x2a4e9d00), SPH_C32(0xbcdc0000), + SPH_C32(0x8db60000), SPH_C32(0x922601cb), SPH_C32(0x190c1430), + SPH_C32(0x3cdc7879), SPH_C32(0x3447d7af), SPH_C32(0xc1860003), + SPH_C32(0x5184c900), SPH_C32(0xa4c30000), SPH_C32(0x13b10000), + SPH_C32(0x9aef7e88), SPH_C32(0x3c926306), SPH_C32(0x48af2b70), + SPH_C32(0x713dc585) }, + { SPH_C32(0x233b0002), SPH_C32(0x77378600), SPH_C32(0x15840000), + SPH_C32(0xe8c50000), SPH_C32(0x14f03c8b), SPH_C32(0x9e01add7), + SPH_C32(0x973720b1), SPH_C32(0x3bdd3741), SPH_C32(0x88ec0003), + SPH_C32(0xbdd4d100), SPH_C32(0x1fd00000), SPH_C32(0x74130000), + SPH_C32(0xb7895abe), SPH_C32(0x0a03d3c4), SPH_C32(0xcbb0c6bb), + SPH_C32(0x1a4531ca) }, + { SPH_C32(0x2f490002), SPH_C32(0x3ed28900), SPH_C32(0x57fd0000), + SPH_C32(0xb42f0000), SPH_C32(0x275a0c91), SPH_C32(0x8b8388c3), + SPH_C32(0x02946bca), SPH_C32(0x8f9637d1), SPH_C32(0x76ce0003), + SPH_C32(0x1a8cd400), SPH_C32(0x3a010000), SPH_C32(0x83730000), + SPH_C32(0x3eb82264), SPH_C32(0x15d72ba4), SPH_C32(0x856065ae), + SPH_C32(0xbb66ce55) }, + { SPH_C32(0xdd190002), SPH_C32(0xd06f8300), SPH_C32(0x30550000), + SPH_C32(0x1fa50000), SPH_C32(0x9dc14451), SPH_C32(0x81d555b7), + SPH_C32(0xd9e783a4), SPH_C32(0x9afec8de), SPH_C32(0x7abc0003), + SPH_C32(0x5369db00), SPH_C32(0x78780000), SPH_C32(0xdf990000), + SPH_C32(0x0d12127e), SPH_C32(0x00550eb0), SPH_C32(0x10c32ed5), + SPH_C32(0x0f2dcec5) }, + { SPH_C32(0xd16b0002), SPH_C32(0x998a8c00), SPH_C32(0x722c0000), + SPH_C32(0x434f0000), SPH_C32(0xae6b744b), SPH_C32(0x945770a3), + SPH_C32(0x4c44c8df), SPH_C32(0x2eb5c84e), SPH_C32(0x849e0003), + SPH_C32(0xf431de00), SPH_C32(0x5da90000), SPH_C32(0x28f90000), + SPH_C32(0x84236aa4), SPH_C32(0x1f81f6d0), SPH_C32(0x5e138dc0), + SPH_C32(0xae0e315a) }, + { SPH_C32(0x66230002), SPH_C32(0xd2829100), SPH_C32(0xecee0000), + SPH_C32(0xd38d0000), SPH_C32(0x0a3c28a7), SPH_C32(0xbd123801), + SPH_C32(0x818b8601), SPH_C32(0xe4eec39e), SPH_C32(0x30d10003), + SPH_C32(0xaba5d700), SPH_C32(0x284a0000), SPH_C32(0x81a20000), + SPH_C32(0x95083b12), SPH_C32(0xa44b2281), SPH_C32(0xad94d0ad), + SPH_C32(0xdf84daf4) }, + { SPH_C32(0x6a510002), SPH_C32(0x9b679e00), SPH_C32(0xae970000), + SPH_C32(0x8f670000), SPH_C32(0x399618bd), SPH_C32(0xa8901d15), + SPH_C32(0x1428cd7a), SPH_C32(0x50a5c30e), SPH_C32(0xcef30003), + SPH_C32(0x0cfdd200), SPH_C32(0x0d9b0000), SPH_C32(0x76c20000), + SPH_C32(0x1c3943c8), SPH_C32(0xbb9fdae1), SPH_C32(0xe34473b8), + SPH_C32(0x7ea7256b) }, + { SPH_C32(0x98010002), SPH_C32(0x75da9400), SPH_C32(0xc93f0000), + SPH_C32(0x24ed0000), SPH_C32(0x830d507d), SPH_C32(0xa2c6c061), + SPH_C32(0xcf5b2514), SPH_C32(0x45cd3c01), SPH_C32(0xc2810003), + SPH_C32(0x4518dd00), SPH_C32(0x4fe20000), SPH_C32(0x2a280000), + SPH_C32(0x2f9373d2), SPH_C32(0xae1dfff5), SPH_C32(0x76e738c3), + SPH_C32(0xcaec25fb) }, + { SPH_C32(0x94730002), SPH_C32(0x3c3f9b00), SPH_C32(0x8b460000), + SPH_C32(0x78070000), SPH_C32(0xb0a76067), SPH_C32(0xb744e575), + SPH_C32(0x5af86e6f), SPH_C32(0xf1863c91), SPH_C32(0x3ca30003), + SPH_C32(0xe240d800), SPH_C32(0x6a330000), SPH_C32(0xdd480000), + SPH_C32(0xa6a20b08), SPH_C32(0xb1c90795), SPH_C32(0x38379bd6), + SPH_C32(0x6bcfda64) }, + { SPH_C32(0xeea20002), SPH_C32(0xa3cda700), SPH_C32(0xb6ba0000), + SPH_C32(0x8d810000), SPH_C32(0xcd090ac7), SPH_C32(0x7987573c), + SPH_C32(0xe674f224), SPH_C32(0x50c3ba01), SPH_C32(0xa4af0003), + SPH_C32(0x15acc300), SPH_C32(0x4fcc0000), SPH_C32(0x4c7e0000), + SPH_C32(0x88c66a19), SPH_C32(0x48284ba5), SPH_C32(0x0f6b6d0a), + SPH_C32(0x85c81200) }, + { SPH_C32(0xe2d00002), SPH_C32(0xea28a800), SPH_C32(0xf4c30000), + SPH_C32(0xd16b0000), SPH_C32(0xfea33add), SPH_C32(0x6c057228), + SPH_C32(0x73d7b95f), SPH_C32(0xe488ba91), SPH_C32(0x5a8d0003), + SPH_C32(0xb2f4c600), SPH_C32(0x6a1d0000), SPH_C32(0xbb1e0000), + SPH_C32(0x01f712c3), SPH_C32(0x57fcb3c5), SPH_C32(0x41bbce1f), + SPH_C32(0x24ebed9f) }, + { SPH_C32(0x10800002), SPH_C32(0x0495a200), SPH_C32(0x936b0000), + SPH_C32(0x7ae10000), SPH_C32(0x4438721d), SPH_C32(0x6653af5c), + SPH_C32(0xa8a45131), SPH_C32(0xf1e0459e), SPH_C32(0x56ff0003), + SPH_C32(0xfb11c900), SPH_C32(0x28640000), SPH_C32(0xe7f40000), + SPH_C32(0x325d22d9), SPH_C32(0x427e96d1), SPH_C32(0xd4188564), + SPH_C32(0x90a0ed0f) }, + { SPH_C32(0x1cf20002), SPH_C32(0x4d70ad00), SPH_C32(0xd1120000), + SPH_C32(0x260b0000), SPH_C32(0x77924207), SPH_C32(0x73d18a48), + SPH_C32(0x3d071a4a), SPH_C32(0x45ab450e), SPH_C32(0xa8dd0003), + SPH_C32(0x5c49cc00), SPH_C32(0x0db50000), SPH_C32(0x10940000), + SPH_C32(0xbb6c5a03), SPH_C32(0x5daa6eb1), SPH_C32(0x9ac82671), + SPH_C32(0x31831290) }, + { SPH_C32(0xabba0002), SPH_C32(0x0678b000), SPH_C32(0x4fd00000), + SPH_C32(0xb6c90000), SPH_C32(0xd3c51eeb), SPH_C32(0x5a94c2ea), + SPH_C32(0xf0c85494), SPH_C32(0x8ff04ede), SPH_C32(0x1c920003), + SPH_C32(0x03ddc500), SPH_C32(0x78560000), SPH_C32(0xb9cf0000), + SPH_C32(0xaa470bb5), SPH_C32(0xe660bae0), SPH_C32(0x694f7b1c), + SPH_C32(0x4009f93e) }, + { SPH_C32(0xa7c80002), SPH_C32(0x4f9dbf00), SPH_C32(0x0da90000), + SPH_C32(0xea230000), SPH_C32(0xe06f2ef1), SPH_C32(0x4f16e7fe), + SPH_C32(0x656b1fef), SPH_C32(0x3bbb4e4e), SPH_C32(0xe2b00003), + SPH_C32(0xa485c000), SPH_C32(0x5d870000), SPH_C32(0x4eaf0000), + SPH_C32(0x2376736f), SPH_C32(0xf9b44280), SPH_C32(0x279fd809), + SPH_C32(0xe12a06a1) }, + { SPH_C32(0x55980002), SPH_C32(0xa120b500), SPH_C32(0x6a010000), + SPH_C32(0x41a90000), SPH_C32(0x5af46631), SPH_C32(0x45403a8a), + SPH_C32(0xbe18f781), SPH_C32(0x2ed3b141), SPH_C32(0xeec20003), + SPH_C32(0xed60cf00), SPH_C32(0x1ffe0000), SPH_C32(0x12450000), + SPH_C32(0x10dc4375), SPH_C32(0xec366794), SPH_C32(0xb23c9372), + SPH_C32(0x55610631) }, + { SPH_C32(0x59ea0002), SPH_C32(0xe8c5ba00), SPH_C32(0x28780000), + SPH_C32(0x1d430000), SPH_C32(0x695e562b), SPH_C32(0x50c21f9e), + SPH_C32(0x2bbbbcfa), SPH_C32(0x9a98b1d1), SPH_C32(0x10e00003), + SPH_C32(0x4a38ca00), SPH_C32(0x3a2f0000), SPH_C32(0xe5250000), + SPH_C32(0x99ed3baf), SPH_C32(0xf3e29ff4), SPH_C32(0xfcec3067), + SPH_C32(0xf442f9ae) }, + { SPH_C32(0x569f0002), SPH_C32(0xb5bca100), SPH_C32(0x81200000), + SPH_C32(0x78300000), SPH_C32(0xef886b6b), SPH_C32(0xd7cfa679), + SPH_C32(0x8050e432), SPH_C32(0x9502513f), SPH_C32(0x598a0003), + SPH_C32(0xa668d200), SPH_C32(0x813c0000), SPH_C32(0x82870000), + SPH_C32(0xb48b1f99), SPH_C32(0xc5732f36), SPH_C32(0x7ff3ddac), + SPH_C32(0x9f3a0de1) }, + { SPH_C32(0x5aed0002), SPH_C32(0xfc59ae00), SPH_C32(0xc3590000), + SPH_C32(0x24da0000), SPH_C32(0xdc225b71), SPH_C32(0xc24d836d), + SPH_C32(0x15f3af49), SPH_C32(0x214951af), SPH_C32(0xa7a80003), + SPH_C32(0x0130d700), SPH_C32(0xa4ed0000), SPH_C32(0x75e70000), + SPH_C32(0x3dba6743), SPH_C32(0xdaa7d756), SPH_C32(0x31237eb9), + SPH_C32(0x3e19f27e) }, + { SPH_C32(0xa8bd0002), SPH_C32(0x12e4a400), SPH_C32(0xa4f10000), + SPH_C32(0x8f500000), SPH_C32(0x66b913b1), SPH_C32(0xc81b5e19), + SPH_C32(0xce804727), SPH_C32(0x3421aea0), SPH_C32(0xabda0003), + SPH_C32(0x48d5d800), SPH_C32(0xe6940000), SPH_C32(0x290d0000), + SPH_C32(0x0e105759), SPH_C32(0xcf25f242), SPH_C32(0xa48035c2), + SPH_C32(0x8a52f2ee) }, + { SPH_C32(0xa4cf0002), SPH_C32(0x5b01ab00), SPH_C32(0xe6880000), + SPH_C32(0xd3ba0000), SPH_C32(0x551323ab), SPH_C32(0xdd997b0d), + SPH_C32(0x5b230c5c), SPH_C32(0x806aae30), SPH_C32(0x55f80003), + SPH_C32(0xef8ddd00), SPH_C32(0xc3450000), SPH_C32(0xde6d0000), + SPH_C32(0x87212f83), SPH_C32(0xd0f10a22), SPH_C32(0xea5096d7), + SPH_C32(0x2b710d71) }, + { SPH_C32(0x13870002), SPH_C32(0x1009b600), SPH_C32(0x784a0000), + SPH_C32(0x43780000), SPH_C32(0xf1447f47), SPH_C32(0xf4dc33af), + SPH_C32(0x96ec4282), SPH_C32(0x4a31a5e0), SPH_C32(0xe1b70003), + SPH_C32(0xb019d400), SPH_C32(0xb6a60000), SPH_C32(0x77360000), + SPH_C32(0x960a7e35), SPH_C32(0x6b3bde73), SPH_C32(0x19d7cbba), + SPH_C32(0x5afbe6df) }, + { SPH_C32(0x1ff50002), SPH_C32(0x59ecb900), SPH_C32(0x3a330000), + SPH_C32(0x1f920000), SPH_C32(0xc2ee4f5d), SPH_C32(0xe15e16bb), + SPH_C32(0x034f09f9), SPH_C32(0xfe7aa570), SPH_C32(0x1f950003), + SPH_C32(0x1741d100), SPH_C32(0x93770000), SPH_C32(0x80560000), + SPH_C32(0x1f3b06ef), SPH_C32(0x74ef2613), SPH_C32(0x570768af), + SPH_C32(0xfbd81940) }, + { SPH_C32(0xeda50002), SPH_C32(0xb751b300), SPH_C32(0x5d9b0000), + SPH_C32(0xb4180000), SPH_C32(0x7875079d), SPH_C32(0xeb08cbcf), + SPH_C32(0xd83ce197), SPH_C32(0xeb125a7f), SPH_C32(0x13e70003), + SPH_C32(0x5ea4de00), SPH_C32(0xd10e0000), SPH_C32(0xdcbc0000), + SPH_C32(0x2c9136f5), SPH_C32(0x616d0307), SPH_C32(0xc2a423d4), + SPH_C32(0x4f9319d0) }, + { SPH_C32(0xe1d70002), SPH_C32(0xfeb4bc00), SPH_C32(0x1fe20000), + SPH_C32(0xe8f20000), SPH_C32(0x4bdf3787), SPH_C32(0xfe8aeedb), + SPH_C32(0x4d9faaec), SPH_C32(0x5f595aef), SPH_C32(0xedc50003), + SPH_C32(0xf9fcdb00), SPH_C32(0xf4df0000), SPH_C32(0x2bdc0000), + SPH_C32(0xa5a04e2f), SPH_C32(0x7eb9fb67), SPH_C32(0x8c7480c1), + SPH_C32(0xeeb0e64f) }, + { SPH_C32(0x4a600002), SPH_C32(0x7afa8300), SPH_C32(0xbcf20000), + SPH_C32(0xebe00000), SPH_C32(0x35731800), SPH_C32(0xff39a060), + SPH_C32(0x45502db0), SPH_C32(0x7b63e054), SPH_C32(0xd10b0003), + SPH_C32(0xd727e400), SPH_C32(0xdb680000), SPH_C32(0xdc8b0000), + SPH_C32(0x73be3df9), SPH_C32(0x01e6400b), SPH_C32(0x180ca989), + SPH_C32(0x2b17747e) }, + { SPH_C32(0x46120002), SPH_C32(0x331f8c00), SPH_C32(0xfe8b0000), + SPH_C32(0xb70a0000), SPH_C32(0x06d9281a), SPH_C32(0xeabb8574), + SPH_C32(0xd0f366cb), SPH_C32(0xcf28e0c4), SPH_C32(0x2f290003), + SPH_C32(0x707fe100), SPH_C32(0xfeb90000), SPH_C32(0x2beb0000), + SPH_C32(0xfa8f4523), SPH_C32(0x1e32b86b), SPH_C32(0x56dc0a9c), + SPH_C32(0x8a348be1) }, + { SPH_C32(0xb4420002), SPH_C32(0xdda28600), SPH_C32(0x99230000), + SPH_C32(0x1c800000), SPH_C32(0xbc4260da), SPH_C32(0xe0ed5800), + SPH_C32(0x0b808ea5), SPH_C32(0xda401fcb), SPH_C32(0x235b0003), + SPH_C32(0x399aee00), SPH_C32(0xbcc00000), SPH_C32(0x77010000), + SPH_C32(0xc9257539), SPH_C32(0x0bb09d7f), SPH_C32(0xc37f41e7), + SPH_C32(0x3e7f8b71) }, + { SPH_C32(0xb8300002), SPH_C32(0x94478900), SPH_C32(0xdb5a0000), + SPH_C32(0x406a0000), SPH_C32(0x8fe850c0), SPH_C32(0xf56f7d14), + SPH_C32(0x9e23c5de), SPH_C32(0x6e0b1f5b), SPH_C32(0xdd790003), + SPH_C32(0x9ec2eb00), SPH_C32(0x99110000), SPH_C32(0x80610000), + SPH_C32(0x40140de3), SPH_C32(0x1464651f), SPH_C32(0x8dafe2f2), + SPH_C32(0x9f5c74ee) }, + { SPH_C32(0x0f780002), SPH_C32(0xdf4f9400), SPH_C32(0x45980000), + SPH_C32(0xd0a80000), SPH_C32(0x2bbf0c2c), SPH_C32(0xdc2a35b6), + SPH_C32(0x53ec8b00), SPH_C32(0xa450148b), SPH_C32(0x69360003), + SPH_C32(0xc156e200), SPH_C32(0xecf20000), SPH_C32(0x293a0000), + SPH_C32(0x513f5c55), SPH_C32(0xafaeb14e), SPH_C32(0x7e28bf9f), + SPH_C32(0xeed69f40) }, + { SPH_C32(0x030a0002), SPH_C32(0x96aa9b00), SPH_C32(0x07e10000), + SPH_C32(0x8c420000), SPH_C32(0x18153c36), SPH_C32(0xc9a810a2), + SPH_C32(0xc64fc07b), SPH_C32(0x101b141b), SPH_C32(0x97140003), + SPH_C32(0x660ee700), SPH_C32(0xc9230000), SPH_C32(0xde5a0000), + SPH_C32(0xd80e248f), SPH_C32(0xb07a492e), SPH_C32(0x30f81c8a), + SPH_C32(0x4ff560df) }, + { SPH_C32(0xf15a0002), SPH_C32(0x78179100), SPH_C32(0x60490000), + SPH_C32(0x27c80000), SPH_C32(0xa28e74f6), SPH_C32(0xc3fecdd6), + SPH_C32(0x1d3c2815), SPH_C32(0x0573eb14), SPH_C32(0x9b660003), + SPH_C32(0x2febe800), SPH_C32(0x8b5a0000), SPH_C32(0x82b00000), + SPH_C32(0xeba41495), SPH_C32(0xa5f86c3a), SPH_C32(0xa55b57f1), + SPH_C32(0xfbbe604f) }, + { SPH_C32(0xfd280002), SPH_C32(0x31f29e00), SPH_C32(0x22300000), + SPH_C32(0x7b220000), SPH_C32(0x912444ec), SPH_C32(0xd67ce8c2), + SPH_C32(0x889f636e), SPH_C32(0xb138eb84), SPH_C32(0x65440003), + SPH_C32(0x88b3ed00), SPH_C32(0xae8b0000), SPH_C32(0x75d00000), + SPH_C32(0x62956c4f), SPH_C32(0xba2c945a), SPH_C32(0xeb8bf4e4), + SPH_C32(0x5a9d9fd0) }, + { SPH_C32(0xf25d0002), SPH_C32(0x6c8b8500), SPH_C32(0x8b680000), + SPH_C32(0x1e510000), SPH_C32(0x17f279ac), SPH_C32(0x51715125), + SPH_C32(0x23743ba6), SPH_C32(0xbea20b6a), SPH_C32(0x2c2e0003), + SPH_C32(0x64e3f500), SPH_C32(0x15980000), SPH_C32(0x12720000), + SPH_C32(0x4ff34879), SPH_C32(0x8cbd2498), SPH_C32(0x6894192f), + SPH_C32(0x31e56b9f) }, + { SPH_C32(0xfe2f0002), SPH_C32(0x256e8a00), SPH_C32(0xc9110000), + SPH_C32(0x42bb0000), SPH_C32(0x245849b6), SPH_C32(0x44f37431), + SPH_C32(0xb6d770dd), SPH_C32(0x0ae90bfa), SPH_C32(0xd20c0003), + SPH_C32(0xc3bbf000), SPH_C32(0x30490000), SPH_C32(0xe5120000), + SPH_C32(0xc6c230a3), SPH_C32(0x9369dcf8), SPH_C32(0x2644ba3a), + SPH_C32(0x90c69400) }, + { SPH_C32(0x0c7f0002), SPH_C32(0xcbd38000), SPH_C32(0xaeb90000), + SPH_C32(0xe9310000), SPH_C32(0x9ec30176), SPH_C32(0x4ea5a945), + SPH_C32(0x6da498b3), SPH_C32(0x1f81f4f5), SPH_C32(0xde7e0003), + SPH_C32(0x8a5eff00), SPH_C32(0x72300000), SPH_C32(0xb9f80000), + SPH_C32(0xf56800b9), SPH_C32(0x86ebf9ec), SPH_C32(0xb3e7f141), + SPH_C32(0x248d9490) }, + { SPH_C32(0x000d0002), SPH_C32(0x82368f00), SPH_C32(0xecc00000), + SPH_C32(0xb5db0000), SPH_C32(0xad69316c), SPH_C32(0x5b278c51), + SPH_C32(0xf807d3c8), SPH_C32(0xabcaf465), SPH_C32(0x205c0003), + SPH_C32(0x2d06fa00), SPH_C32(0x57e10000), SPH_C32(0x4e980000), + SPH_C32(0x7c597863), SPH_C32(0x993f018c), SPH_C32(0xfd375254), + SPH_C32(0x85ae6b0f) }, + { SPH_C32(0xb7450002), SPH_C32(0xc93e9200), SPH_C32(0x72020000), + SPH_C32(0x25190000), SPH_C32(0x093e6d80), SPH_C32(0x7262c4f3), + SPH_C32(0x35c89d16), SPH_C32(0x6191ffb5), SPH_C32(0x94130003), + SPH_C32(0x7292f300), SPH_C32(0x22020000), SPH_C32(0xe7c30000), + SPH_C32(0x6d7229d5), SPH_C32(0x22f5d5dd), SPH_C32(0x0eb00f39), + SPH_C32(0xf42480a1) }, + { SPH_C32(0xbb370002), SPH_C32(0x80db9d00), SPH_C32(0x307b0000), + SPH_C32(0x79f30000), SPH_C32(0x3a945d9a), SPH_C32(0x67e0e1e7), + SPH_C32(0xa06bd66d), SPH_C32(0xd5daff25), SPH_C32(0x6a310003), + SPH_C32(0xd5caf600), SPH_C32(0x07d30000), SPH_C32(0x10a30000), + SPH_C32(0xe443510f), SPH_C32(0x3d212dbd), SPH_C32(0x4060ac2c), + SPH_C32(0x55077f3e) }, + { SPH_C32(0x49670002), SPH_C32(0x6e669700), SPH_C32(0x57d30000), + SPH_C32(0xd2790000), SPH_C32(0x800f155a), SPH_C32(0x6db63c93), + SPH_C32(0x7b183e03), SPH_C32(0xc0b2002a), SPH_C32(0x66430003), + SPH_C32(0x9c2ff900), SPH_C32(0x45aa0000), SPH_C32(0x4c490000), + SPH_C32(0xd7e96115), SPH_C32(0x28a308a9), SPH_C32(0xd5c3e757), + SPH_C32(0xe14c7fae) }, + { SPH_C32(0x45150002), SPH_C32(0x27839800), SPH_C32(0x15aa0000), + SPH_C32(0x8e930000), SPH_C32(0xb3a52540), SPH_C32(0x78341987), + SPH_C32(0xeebb7578), SPH_C32(0x74f900ba), SPH_C32(0x98610003), + SPH_C32(0x3b77fc00), SPH_C32(0x607b0000), SPH_C32(0xbb290000), + SPH_C32(0x5ed819cf), SPH_C32(0x3777f0c9), SPH_C32(0x9b134442), + SPH_C32(0x406f8031) }, + { SPH_C32(0x3fc40002), SPH_C32(0xb871a400), SPH_C32(0x28560000), + SPH_C32(0x7b150000), SPH_C32(0xce0b4fe0), SPH_C32(0xb6f7abce), + SPH_C32(0x5237e933), SPH_C32(0xd5bc862a), SPH_C32(0x006d0003), + SPH_C32(0xcc9be700), SPH_C32(0x45840000), SPH_C32(0x2a1f0000), + SPH_C32(0x70bc78de), SPH_C32(0xce96bcf9), SPH_C32(0xac4fb29e), + SPH_C32(0xae684855) }, + { SPH_C32(0x33b60002), SPH_C32(0xf194ab00), SPH_C32(0x6a2f0000), + SPH_C32(0x27ff0000), SPH_C32(0xfda17ffa), SPH_C32(0xa3758eda), + SPH_C32(0xc794a248), SPH_C32(0x61f786ba), SPH_C32(0xfe4f0003), + SPH_C32(0x6bc3e200), SPH_C32(0x60550000), SPH_C32(0xdd7f0000), + SPH_C32(0xf98d0004), SPH_C32(0xd1424499), SPH_C32(0xe29f118b), + SPH_C32(0x0f4bb7ca) }, + { SPH_C32(0xc1e60002), SPH_C32(0x1f29a100), SPH_C32(0x0d870000), + SPH_C32(0x8c750000), SPH_C32(0x473a373a), SPH_C32(0xa92353ae), + SPH_C32(0x1ce74a26), SPH_C32(0x749f79b5), SPH_C32(0xf23d0003), + SPH_C32(0x2226ed00), SPH_C32(0x222c0000), SPH_C32(0x81950000), + SPH_C32(0xca27301e), SPH_C32(0xc4c0618d), SPH_C32(0x773c5af0), + SPH_C32(0xbb00b75a) }, + { SPH_C32(0xcd940002), SPH_C32(0x56ccae00), SPH_C32(0x4ffe0000), + SPH_C32(0xd09f0000), SPH_C32(0x74900720), SPH_C32(0xbca176ba), + SPH_C32(0x8944015d), SPH_C32(0xc0d47925), SPH_C32(0x0c1f0003), + SPH_C32(0x857ee800), SPH_C32(0x07fd0000), SPH_C32(0x76f50000), + SPH_C32(0x431648c4), SPH_C32(0xdb1499ed), SPH_C32(0x39ecf9e5), + SPH_C32(0x1a2348c5) }, + { SPH_C32(0x7adc0002), SPH_C32(0x1dc4b300), SPH_C32(0xd13c0000), + SPH_C32(0x405d0000), SPH_C32(0xd0c75bcc), SPH_C32(0x95e43e18), + SPH_C32(0x448b4f83), SPH_C32(0x0a8f72f5), SPH_C32(0xb8500003), + SPH_C32(0xdaeae100), SPH_C32(0x721e0000), SPH_C32(0xdfae0000), + SPH_C32(0x523d1972), SPH_C32(0x60de4dbc), SPH_C32(0xca6ba488), + SPH_C32(0x6ba9a36b) }, + { SPH_C32(0x76ae0002), SPH_C32(0x5421bc00), SPH_C32(0x93450000), + SPH_C32(0x1cb70000), SPH_C32(0xe36d6bd6), SPH_C32(0x80661b0c), + SPH_C32(0xd12804f8), SPH_C32(0xbec47265), SPH_C32(0x46720003), + SPH_C32(0x7db2e400), SPH_C32(0x57cf0000), SPH_C32(0x28ce0000), + SPH_C32(0xdb0c61a8), SPH_C32(0x7f0ab5dc), SPH_C32(0x84bb079d), + SPH_C32(0xca8a5cf4) }, + { SPH_C32(0x84fe0002), SPH_C32(0xba9cb600), SPH_C32(0xf4ed0000), + SPH_C32(0xb73d0000), SPH_C32(0x59f62316), SPH_C32(0x8a30c678), + SPH_C32(0x0a5bec96), SPH_C32(0xabac8d6a), SPH_C32(0x4a000003), + SPH_C32(0x3457eb00), SPH_C32(0x15b60000), SPH_C32(0x74240000), + SPH_C32(0xe8a651b2), SPH_C32(0x6a8890c8), SPH_C32(0x11184ce6), + SPH_C32(0x7ec15c64) }, + { SPH_C32(0x888c0002), SPH_C32(0xf379b900), SPH_C32(0xb6940000), + SPH_C32(0xebd70000), SPH_C32(0x6a5c130c), SPH_C32(0x9fb2e36c), + SPH_C32(0x9ff8a7ed), SPH_C32(0x1fe78dfa), SPH_C32(0xb4220003), + SPH_C32(0x930fee00), SPH_C32(0x30670000), SPH_C32(0x83440000), + SPH_C32(0x61972968), SPH_C32(0x755c68a8), SPH_C32(0x5fc8eff3), + SPH_C32(0xdfe2a3fb) }, + { SPH_C32(0x87f90002), SPH_C32(0xae00a200), SPH_C32(0x1fcc0000), + SPH_C32(0x8ea40000), SPH_C32(0xec8a2e4c), SPH_C32(0x18bf5a8b), + SPH_C32(0x3413ff25), SPH_C32(0x107d6d14), SPH_C32(0xfd480003), + SPH_C32(0x7f5ff600), SPH_C32(0x8b740000), SPH_C32(0xe4e60000), + SPH_C32(0x4cf10d5e), SPH_C32(0x43cdd86a), SPH_C32(0xdcd70238), + SPH_C32(0xb49a57b4) }, + { SPH_C32(0x8b8b0002), SPH_C32(0xe7e5ad00), SPH_C32(0x5db50000), + SPH_C32(0xd24e0000), SPH_C32(0xdf201e56), SPH_C32(0x0d3d7f9f), + SPH_C32(0xa1b0b45e), SPH_C32(0xa4366d84), SPH_C32(0x036a0003), + SPH_C32(0xd807f300), SPH_C32(0xaea50000), SPH_C32(0x13860000), + SPH_C32(0xc5c07584), SPH_C32(0x5c19200a), SPH_C32(0x9207a12d), + SPH_C32(0x15b9a82b) }, + { SPH_C32(0x79db0002), SPH_C32(0x0958a700), SPH_C32(0x3a1d0000), + SPH_C32(0x79c40000), SPH_C32(0x65bb5696), SPH_C32(0x076ba2eb), + SPH_C32(0x7ac35c30), SPH_C32(0xb15e928b), SPH_C32(0x0f180003), + SPH_C32(0x91e2fc00), SPH_C32(0xecdc0000), SPH_C32(0x4f6c0000), + SPH_C32(0xf66a459e), SPH_C32(0x499b051e), SPH_C32(0x07a4ea56), + SPH_C32(0xa1f2a8bb) }, + { SPH_C32(0x75a90002), SPH_C32(0x40bda800), SPH_C32(0x78640000), + SPH_C32(0x252e0000), SPH_C32(0x5611668c), SPH_C32(0x12e987ff), + SPH_C32(0xef60174b), SPH_C32(0x0515921b), SPH_C32(0xf13a0003), + SPH_C32(0x36baf900), SPH_C32(0xc90d0000), SPH_C32(0xb80c0000), + SPH_C32(0x7f5b3d44), SPH_C32(0x564ffd7e), SPH_C32(0x49744943), + SPH_C32(0x00d15724) }, + { SPH_C32(0xc2e10002), SPH_C32(0x0bb5b500), SPH_C32(0xe6a60000), + SPH_C32(0xb5ec0000), SPH_C32(0xf2463a60), SPH_C32(0x3baccf5d), + SPH_C32(0x22af5995), SPH_C32(0xcf4e99cb), SPH_C32(0x45750003), + SPH_C32(0x692ef000), SPH_C32(0xbcee0000), SPH_C32(0x11570000), + SPH_C32(0x6e706cf2), SPH_C32(0xed85292f), SPH_C32(0xbaf3142e), + SPH_C32(0x715bbc8a) }, + { SPH_C32(0xce930002), SPH_C32(0x4250ba00), SPH_C32(0xa4df0000), + SPH_C32(0xe9060000), SPH_C32(0xc1ec0a7a), SPH_C32(0x2e2eea49), + SPH_C32(0xb70c12ee), SPH_C32(0x7b05995b), SPH_C32(0xbb570003), + SPH_C32(0xce76f500), SPH_C32(0x993f0000), SPH_C32(0xe6370000), + SPH_C32(0xe7411428), SPH_C32(0xf251d14f), SPH_C32(0xf423b73b), + SPH_C32(0xd0784315) }, + { SPH_C32(0x3cc30002), SPH_C32(0xacedb000), SPH_C32(0xc3770000), + SPH_C32(0x428c0000), SPH_C32(0x7b7742ba), SPH_C32(0x2478373d), + SPH_C32(0x6c7ffa80), SPH_C32(0x6e6d6654), SPH_C32(0xb7250003), + SPH_C32(0x8793fa00), SPH_C32(0xdb460000), SPH_C32(0xbadd0000), + SPH_C32(0xd4eb2432), SPH_C32(0xe7d3f45b), SPH_C32(0x6180fc40), + SPH_C32(0x64334385) }, + { SPH_C32(0x30b10002), SPH_C32(0xe508bf00), SPH_C32(0x810e0000), + SPH_C32(0x1e660000), SPH_C32(0x48dd72a0), SPH_C32(0x31fa1229), + SPH_C32(0xf9dcb1fb), SPH_C32(0xda2666c4), SPH_C32(0x49070003), + SPH_C32(0x20cbff00), SPH_C32(0xfe970000), SPH_C32(0x4dbd0000), + SPH_C32(0x5dda5ce8), SPH_C32(0xf8070c3b), SPH_C32(0x2f505f55), + SPH_C32(0xc510bc1a) } +}; + +static const sph_u32 T512_24[256][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0x86790000), SPH_C32(0x3f390002), SPH_C32(0xe19ae000), + SPH_C32(0x98560000), SPH_C32(0x9565670e), SPH_C32(0x4e88c8ea), + SPH_C32(0xd3dd4944), SPH_C32(0x161ddab9), SPH_C32(0x30b70000), + SPH_C32(0xe5d00000), SPH_C32(0xf4f46000), SPH_C32(0x42c40000), + SPH_C32(0x63b83d6a), SPH_C32(0x78ba9460), SPH_C32(0x21afa1ea), + SPH_C32(0xb0a51834) }, + { SPH_C32(0x30b70000), SPH_C32(0xe5d00000), SPH_C32(0xf4f46000), + SPH_C32(0x42c40000), SPH_C32(0x63b83d6a), SPH_C32(0x78ba9460), + SPH_C32(0x21afa1ea), SPH_C32(0xb0a51834), SPH_C32(0xb6ce0000), + SPH_C32(0xdae90002), SPH_C32(0x156e8000), SPH_C32(0xda920000), + SPH_C32(0xf6dd5a64), SPH_C32(0x36325c8a), SPH_C32(0xf272e8ae), + SPH_C32(0xa6b8c28d) }, + { SPH_C32(0xb6ce0000), SPH_C32(0xdae90002), SPH_C32(0x156e8000), + SPH_C32(0xda920000), SPH_C32(0xf6dd5a64), SPH_C32(0x36325c8a), + SPH_C32(0xf272e8ae), SPH_C32(0xa6b8c28d), SPH_C32(0x86790000), + SPH_C32(0x3f390002), SPH_C32(0xe19ae000), SPH_C32(0x98560000), + SPH_C32(0x9565670e), SPH_C32(0x4e88c8ea), SPH_C32(0xd3dd4944), + SPH_C32(0x161ddab9) }, + { SPH_C32(0x14190000), SPH_C32(0x23ca003c), SPH_C32(0x50df0000), + SPH_C32(0x44b60000), SPH_C32(0x1b6c67b0), SPH_C32(0x3cf3ac75), + SPH_C32(0x61e610b0), SPH_C32(0xdbcadb80), SPH_C32(0xe3430000), + SPH_C32(0x3a4e0014), SPH_C32(0xf2c60000), SPH_C32(0xaa4e0000), + SPH_C32(0xdb1e42a6), SPH_C32(0x256bbe15), SPH_C32(0x123db156), + SPH_C32(0x3a4e99d7) }, + { SPH_C32(0x92600000), SPH_C32(0x1cf3003e), SPH_C32(0xb145e000), + SPH_C32(0xdce00000), SPH_C32(0x8e0900be), SPH_C32(0x727b649f), + SPH_C32(0xb23b59f4), SPH_C32(0xcdd70139), SPH_C32(0xd3f40000), + SPH_C32(0xdf9e0014), SPH_C32(0x06326000), SPH_C32(0xe88a0000), + SPH_C32(0xb8a67fcc), SPH_C32(0x5dd12a75), SPH_C32(0x339210bc), + SPH_C32(0x8aeb81e3) }, + { SPH_C32(0x24ae0000), SPH_C32(0xc61a003c), SPH_C32(0xa42b6000), + SPH_C32(0x06720000), SPH_C32(0x78d45ada), SPH_C32(0x44493815), + SPH_C32(0x4049b15a), SPH_C32(0x6b6fc3b4), SPH_C32(0x558d0000), + SPH_C32(0xe0a70016), SPH_C32(0xe7a88000), SPH_C32(0x70dc0000), + SPH_C32(0x2dc318c2), SPH_C32(0x1359e29f), SPH_C32(0xe04f59f8), + SPH_C32(0x9cf65b5a) }, + { SPH_C32(0xa2d70000), SPH_C32(0xf923003e), SPH_C32(0x45b18000), + SPH_C32(0x9e240000), SPH_C32(0xedb13dd4), SPH_C32(0x0ac1f0ff), + SPH_C32(0x9394f81e), SPH_C32(0x7d72190d), SPH_C32(0x653a0000), + SPH_C32(0x05770016), SPH_C32(0x135ce000), SPH_C32(0x32180000), + SPH_C32(0x4e7b25a8), SPH_C32(0x6be376ff), SPH_C32(0xc1e0f812), + SPH_C32(0x2c53436e) }, + { SPH_C32(0xe3430000), SPH_C32(0x3a4e0014), SPH_C32(0xf2c60000), + SPH_C32(0xaa4e0000), SPH_C32(0xdb1e42a6), SPH_C32(0x256bbe15), + SPH_C32(0x123db156), SPH_C32(0x3a4e99d7), SPH_C32(0xf75a0000), + SPH_C32(0x19840028), SPH_C32(0xa2190000), SPH_C32(0xeef80000), + SPH_C32(0xc0722516), SPH_C32(0x19981260), SPH_C32(0x73dba1e6), + SPH_C32(0xe1844257) }, + { SPH_C32(0x653a0000), SPH_C32(0x05770016), SPH_C32(0x135ce000), + SPH_C32(0x32180000), SPH_C32(0x4e7b25a8), SPH_C32(0x6be376ff), + SPH_C32(0xc1e0f812), SPH_C32(0x2c53436e), SPH_C32(0xc7ed0000), + SPH_C32(0xfc540028), SPH_C32(0x56ed6000), SPH_C32(0xac3c0000), + SPH_C32(0xa3ca187c), SPH_C32(0x61228600), SPH_C32(0x5274000c), + SPH_C32(0x51215a63) }, + { SPH_C32(0xd3f40000), SPH_C32(0xdf9e0014), SPH_C32(0x06326000), + SPH_C32(0xe88a0000), SPH_C32(0xb8a67fcc), SPH_C32(0x5dd12a75), + SPH_C32(0x339210bc), SPH_C32(0x8aeb81e3), SPH_C32(0x41940000), + SPH_C32(0xc36d002a), SPH_C32(0xb7778000), SPH_C32(0x346a0000), + SPH_C32(0x36af7f72), SPH_C32(0x2faa4eea), SPH_C32(0x81a94948), + SPH_C32(0x473c80da) }, + { SPH_C32(0x558d0000), SPH_C32(0xe0a70016), SPH_C32(0xe7a88000), + SPH_C32(0x70dc0000), SPH_C32(0x2dc318c2), SPH_C32(0x1359e29f), + SPH_C32(0xe04f59f8), SPH_C32(0x9cf65b5a), SPH_C32(0x71230000), + SPH_C32(0x26bd002a), SPH_C32(0x4383e000), SPH_C32(0x76ae0000), + SPH_C32(0x55174218), SPH_C32(0x5710da8a), SPH_C32(0xa006e8a2), + SPH_C32(0xf79998ee) }, + { SPH_C32(0xf75a0000), SPH_C32(0x19840028), SPH_C32(0xa2190000), + SPH_C32(0xeef80000), SPH_C32(0xc0722516), SPH_C32(0x19981260), + SPH_C32(0x73dba1e6), SPH_C32(0xe1844257), SPH_C32(0x14190000), + SPH_C32(0x23ca003c), SPH_C32(0x50df0000), SPH_C32(0x44b60000), + SPH_C32(0x1b6c67b0), SPH_C32(0x3cf3ac75), SPH_C32(0x61e610b0), + SPH_C32(0xdbcadb80) }, + { SPH_C32(0x71230000), SPH_C32(0x26bd002a), SPH_C32(0x4383e000), + SPH_C32(0x76ae0000), SPH_C32(0x55174218), SPH_C32(0x5710da8a), + SPH_C32(0xa006e8a2), SPH_C32(0xf79998ee), SPH_C32(0x24ae0000), + SPH_C32(0xc61a003c), SPH_C32(0xa42b6000), SPH_C32(0x06720000), + SPH_C32(0x78d45ada), SPH_C32(0x44493815), SPH_C32(0x4049b15a), + SPH_C32(0x6b6fc3b4) }, + { SPH_C32(0xc7ed0000), SPH_C32(0xfc540028), SPH_C32(0x56ed6000), + SPH_C32(0xac3c0000), SPH_C32(0xa3ca187c), SPH_C32(0x61228600), + SPH_C32(0x5274000c), SPH_C32(0x51215a63), SPH_C32(0xa2d70000), + SPH_C32(0xf923003e), SPH_C32(0x45b18000), SPH_C32(0x9e240000), + SPH_C32(0xedb13dd4), SPH_C32(0x0ac1f0ff), SPH_C32(0x9394f81e), + SPH_C32(0x7d72190d) }, + { SPH_C32(0x41940000), SPH_C32(0xc36d002a), SPH_C32(0xb7778000), + SPH_C32(0x346a0000), SPH_C32(0x36af7f72), SPH_C32(0x2faa4eea), + SPH_C32(0x81a94948), SPH_C32(0x473c80da), SPH_C32(0x92600000), + SPH_C32(0x1cf3003e), SPH_C32(0xb145e000), SPH_C32(0xdce00000), + SPH_C32(0x8e0900be), SPH_C32(0x727b649f), SPH_C32(0xb23b59f4), + SPH_C32(0xcdd70139) }, + { SPH_C32(0x54500000), SPH_C32(0x0671005c), SPH_C32(0x25ae0000), + SPH_C32(0x6a1e0000), SPH_C32(0x2ea54edf), SPH_C32(0x664e8512), + SPH_C32(0xbfba18c3), SPH_C32(0x7e715d17), SPH_C32(0xbc8d0000), + SPH_C32(0xfc3b0018), SPH_C32(0x19830000), SPH_C32(0xd10b0000), + SPH_C32(0xae1878c4), SPH_C32(0x42a69856), SPH_C32(0x0012da37), + SPH_C32(0x2c3b504e) }, + { SPH_C32(0xd2290000), SPH_C32(0x3948005e), SPH_C32(0xc434e000), + SPH_C32(0xf2480000), SPH_C32(0xbbc029d1), SPH_C32(0x28c64df8), + SPH_C32(0x6c675187), SPH_C32(0x686c87ae), SPH_C32(0x8c3a0000), + SPH_C32(0x19eb0018), SPH_C32(0xed776000), SPH_C32(0x93cf0000), + SPH_C32(0xcda045ae), SPH_C32(0x3a1c0c36), SPH_C32(0x21bd7bdd), + SPH_C32(0x9c9e487a) }, + { SPH_C32(0x64e70000), SPH_C32(0xe3a1005c), SPH_C32(0xd15a6000), + SPH_C32(0x28da0000), SPH_C32(0x4d1d73b5), SPH_C32(0x1ef41172), + SPH_C32(0x9e15b929), SPH_C32(0xced44523), SPH_C32(0x0a430000), + SPH_C32(0x26d2001a), SPH_C32(0x0ced8000), SPH_C32(0x0b990000), + SPH_C32(0x58c522a0), SPH_C32(0x7494c4dc), SPH_C32(0xf2603299), + SPH_C32(0x8a8392c3) }, + { SPH_C32(0xe29e0000), SPH_C32(0xdc98005e), SPH_C32(0x30c08000), + SPH_C32(0xb08c0000), SPH_C32(0xd87814bb), SPH_C32(0x507cd998), + SPH_C32(0x4dc8f06d), SPH_C32(0xd8c99f9a), SPH_C32(0x3af40000), + SPH_C32(0xc302001a), SPH_C32(0xf819e000), SPH_C32(0x495d0000), + SPH_C32(0x3b7d1fca), SPH_C32(0x0c2e50bc), SPH_C32(0xd3cf9373), + SPH_C32(0x3a268af7) }, + { SPH_C32(0x40490000), SPH_C32(0x25bb0060), SPH_C32(0x75710000), + SPH_C32(0x2ea80000), SPH_C32(0x35c9296f), SPH_C32(0x5abd2967), + SPH_C32(0xde5c0873), SPH_C32(0xa5bb8697), SPH_C32(0x5fce0000), + SPH_C32(0xc675000c), SPH_C32(0xeb450000), SPH_C32(0x7b450000), + SPH_C32(0x75063a62), SPH_C32(0x67cd2643), SPH_C32(0x122f6b61), + SPH_C32(0x1675c999) }, + { SPH_C32(0xc6300000), SPH_C32(0x1a820062), SPH_C32(0x94ebe000), + SPH_C32(0xb6fe0000), SPH_C32(0xa0ac4e61), SPH_C32(0x1435e18d), + SPH_C32(0x0d814137), SPH_C32(0xb3a65c2e), SPH_C32(0x6f790000), + SPH_C32(0x23a5000c), SPH_C32(0x1fb16000), SPH_C32(0x39810000), + SPH_C32(0x16be0708), SPH_C32(0x1f77b223), SPH_C32(0x3380ca8b), + SPH_C32(0xa6d0d1ad) }, + { SPH_C32(0x70fe0000), SPH_C32(0xc06b0060), SPH_C32(0x81856000), + SPH_C32(0x6c6c0000), SPH_C32(0x56711405), SPH_C32(0x2207bd07), + SPH_C32(0xfff3a999), SPH_C32(0x151e9ea3), SPH_C32(0xe9000000), + SPH_C32(0x1c9c000e), SPH_C32(0xfe2b8000), SPH_C32(0xa1d70000), + SPH_C32(0x83db6006), SPH_C32(0x51ff7ac9), SPH_C32(0xe05d83cf), + SPH_C32(0xb0cd0b14) }, + { SPH_C32(0xf6870000), SPH_C32(0xff520062), SPH_C32(0x601f8000), + SPH_C32(0xf43a0000), SPH_C32(0xc314730b), SPH_C32(0x6c8f75ed), + SPH_C32(0x2c2ee0dd), SPH_C32(0x0303441a), SPH_C32(0xd9b70000), + SPH_C32(0xf94c000e), SPH_C32(0x0adfe000), SPH_C32(0xe3130000), + SPH_C32(0xe0635d6c), SPH_C32(0x2945eea9), SPH_C32(0xc1f22225), + SPH_C32(0x00681320) }, + { SPH_C32(0xb7130000), SPH_C32(0x3c3f0048), SPH_C32(0xd7680000), + SPH_C32(0xc0500000), SPH_C32(0xf5bb0c79), SPH_C32(0x43253b07), + SPH_C32(0xad87a995), SPH_C32(0x443fc4c0), SPH_C32(0x4bd70000), + SPH_C32(0xe5bf0030), SPH_C32(0xbb9a0000), SPH_C32(0x3ff30000), + SPH_C32(0x6e6a5dd2), SPH_C32(0x5b3e8a36), SPH_C32(0x73c97bd1), + SPH_C32(0xcdbf1219) }, + { SPH_C32(0x316a0000), SPH_C32(0x0306004a), SPH_C32(0x36f2e000), + SPH_C32(0x58060000), SPH_C32(0x60de6b77), SPH_C32(0x0dadf3ed), + SPH_C32(0x7e5ae0d1), SPH_C32(0x52221e79), SPH_C32(0x7b600000), + SPH_C32(0x006f0030), SPH_C32(0x4f6e6000), SPH_C32(0x7d370000), + SPH_C32(0x0dd260b8), SPH_C32(0x23841e56), SPH_C32(0x5266da3b), + SPH_C32(0x7d1a0a2d) }, + { SPH_C32(0x87a40000), SPH_C32(0xd9ef0048), SPH_C32(0x239c6000), + SPH_C32(0x82940000), SPH_C32(0x96033113), SPH_C32(0x3b9faf67), + SPH_C32(0x8c28087f), SPH_C32(0xf49adcf4), SPH_C32(0xfd190000), + SPH_C32(0x3f560032), SPH_C32(0xaef48000), SPH_C32(0xe5610000), + SPH_C32(0x98b707b6), SPH_C32(0x6d0cd6bc), SPH_C32(0x81bb937f), + SPH_C32(0x6b07d094) }, + { SPH_C32(0x01dd0000), SPH_C32(0xe6d6004a), SPH_C32(0xc2068000), + SPH_C32(0x1ac20000), SPH_C32(0x0366561d), SPH_C32(0x7517678d), + SPH_C32(0x5ff5413b), SPH_C32(0xe287064d), SPH_C32(0xcdae0000), + SPH_C32(0xda860032), SPH_C32(0x5a00e000), SPH_C32(0xa7a50000), + SPH_C32(0xfb0f3adc), SPH_C32(0x15b642dc), SPH_C32(0xa0143295), + SPH_C32(0xdba2c8a0) }, + { SPH_C32(0xa30a0000), SPH_C32(0x1ff50074), SPH_C32(0x87b70000), + SPH_C32(0x84e60000), SPH_C32(0xeed76bc9), SPH_C32(0x7fd69772), + SPH_C32(0xcc61b925), SPH_C32(0x9ff51f40), SPH_C32(0xa8940000), + SPH_C32(0xdff10024), SPH_C32(0x495c0000), SPH_C32(0x95bd0000), + SPH_C32(0xb5741f74), SPH_C32(0x7e553423), SPH_C32(0x61f4ca87), + SPH_C32(0xf7f18bce) }, + { SPH_C32(0x25730000), SPH_C32(0x20cc0076), SPH_C32(0x662de000), + SPH_C32(0x1cb00000), SPH_C32(0x7bb20cc7), SPH_C32(0x315e5f98), + SPH_C32(0x1fbcf061), SPH_C32(0x89e8c5f9), SPH_C32(0x98230000), + SPH_C32(0x3a210024), SPH_C32(0xbda86000), SPH_C32(0xd7790000), + SPH_C32(0xd6cc221e), SPH_C32(0x06efa043), SPH_C32(0x405b6b6d), + SPH_C32(0x475493fa) }, + { SPH_C32(0x93bd0000), SPH_C32(0xfa250074), SPH_C32(0x73436000), + SPH_C32(0xc6220000), SPH_C32(0x8d6f56a3), SPH_C32(0x076c0312), + SPH_C32(0xedce18cf), SPH_C32(0x2f500774), SPH_C32(0x1e5a0000), + SPH_C32(0x05180026), SPH_C32(0x5c328000), SPH_C32(0x4f2f0000), + SPH_C32(0x43a94510), SPH_C32(0x486768a9), SPH_C32(0x93862229), + SPH_C32(0x51494943) }, + { SPH_C32(0x15c40000), SPH_C32(0xc51c0076), SPH_C32(0x92d98000), + SPH_C32(0x5e740000), SPH_C32(0x180a31ad), SPH_C32(0x49e4cbf8), + SPH_C32(0x3e13518b), SPH_C32(0x394dddcd), SPH_C32(0x2eed0000), + SPH_C32(0xe0c80026), SPH_C32(0xa8c6e000), SPH_C32(0x0deb0000), + SPH_C32(0x2011787a), SPH_C32(0x30ddfcc9), SPH_C32(0xb22983c3), + SPH_C32(0xe1ec5177) }, + { SPH_C32(0xbc8d0000), SPH_C32(0xfc3b0018), SPH_C32(0x19830000), + SPH_C32(0xd10b0000), SPH_C32(0xae1878c4), SPH_C32(0x42a69856), + SPH_C32(0x0012da37), SPH_C32(0x2c3b504e), SPH_C32(0xe8dd0000), + SPH_C32(0xfa4a0044), SPH_C32(0x3c2d0000), SPH_C32(0xbb150000), + SPH_C32(0x80bd361b), SPH_C32(0x24e81d44), SPH_C32(0xbfa8c2f4), + SPH_C32(0x524a0d59) }, + { SPH_C32(0x3af40000), SPH_C32(0xc302001a), SPH_C32(0xf819e000), + SPH_C32(0x495d0000), SPH_C32(0x3b7d1fca), SPH_C32(0x0c2e50bc), + SPH_C32(0xd3cf9373), SPH_C32(0x3a268af7), SPH_C32(0xd86a0000), + SPH_C32(0x1f9a0044), SPH_C32(0xc8d96000), SPH_C32(0xf9d10000), + SPH_C32(0xe3050b71), SPH_C32(0x5c528924), SPH_C32(0x9e07631e), + SPH_C32(0xe2ef156d) }, + { SPH_C32(0x8c3a0000), SPH_C32(0x19eb0018), SPH_C32(0xed776000), + SPH_C32(0x93cf0000), SPH_C32(0xcda045ae), SPH_C32(0x3a1c0c36), + SPH_C32(0x21bd7bdd), SPH_C32(0x9c9e487a), SPH_C32(0x5e130000), + SPH_C32(0x20a30046), SPH_C32(0x29438000), SPH_C32(0x61870000), + SPH_C32(0x76606c7f), SPH_C32(0x12da41ce), SPH_C32(0x4dda2a5a), + SPH_C32(0xf4f2cfd4) }, + { SPH_C32(0x0a430000), SPH_C32(0x26d2001a), SPH_C32(0x0ced8000), + SPH_C32(0x0b990000), SPH_C32(0x58c522a0), SPH_C32(0x7494c4dc), + SPH_C32(0xf2603299), SPH_C32(0x8a8392c3), SPH_C32(0x6ea40000), + SPH_C32(0xc5730046), SPH_C32(0xddb7e000), SPH_C32(0x23430000), + SPH_C32(0x15d85115), SPH_C32(0x6a60d5ae), SPH_C32(0x6c758bb0), + SPH_C32(0x4457d7e0) }, + { SPH_C32(0xa8940000), SPH_C32(0xdff10024), SPH_C32(0x495c0000), + SPH_C32(0x95bd0000), SPH_C32(0xb5741f74), SPH_C32(0x7e553423), + SPH_C32(0x61f4ca87), SPH_C32(0xf7f18bce), SPH_C32(0x0b9e0000), + SPH_C32(0xc0040050), SPH_C32(0xceeb0000), SPH_C32(0x115b0000), + SPH_C32(0x5ba374bd), SPH_C32(0x0183a351), SPH_C32(0xad9573a2), + SPH_C32(0x6804948e) }, + { SPH_C32(0x2eed0000), SPH_C32(0xe0c80026), SPH_C32(0xa8c6e000), + SPH_C32(0x0deb0000), SPH_C32(0x2011787a), SPH_C32(0x30ddfcc9), + SPH_C32(0xb22983c3), SPH_C32(0xe1ec5177), SPH_C32(0x3b290000), + SPH_C32(0x25d40050), SPH_C32(0x3a1f6000), SPH_C32(0x539f0000), + SPH_C32(0x381b49d7), SPH_C32(0x79393731), SPH_C32(0x8c3ad248), + SPH_C32(0xd8a18cba) }, + { SPH_C32(0x98230000), SPH_C32(0x3a210024), SPH_C32(0xbda86000), + SPH_C32(0xd7790000), SPH_C32(0xd6cc221e), SPH_C32(0x06efa043), + SPH_C32(0x405b6b6d), SPH_C32(0x475493fa), SPH_C32(0xbd500000), + SPH_C32(0x1aed0052), SPH_C32(0xdb858000), SPH_C32(0xcbc90000), + SPH_C32(0xad7e2ed9), SPH_C32(0x37b1ffdb), SPH_C32(0x5fe79b0c), + SPH_C32(0xcebc5603) }, + { SPH_C32(0x1e5a0000), SPH_C32(0x05180026), SPH_C32(0x5c328000), + SPH_C32(0x4f2f0000), SPH_C32(0x43a94510), SPH_C32(0x486768a9), + SPH_C32(0x93862229), SPH_C32(0x51494943), SPH_C32(0x8de70000), + SPH_C32(0xff3d0052), SPH_C32(0x2f71e000), SPH_C32(0x890d0000), + SPH_C32(0xcec613b3), SPH_C32(0x4f0b6bbb), SPH_C32(0x7e483ae6), + SPH_C32(0x7e194e37) }, + { SPH_C32(0x5fce0000), SPH_C32(0xc675000c), SPH_C32(0xeb450000), + SPH_C32(0x7b450000), SPH_C32(0x75063a62), SPH_C32(0x67cd2643), + SPH_C32(0x122f6b61), SPH_C32(0x1675c999), SPH_C32(0x1f870000), + SPH_C32(0xe3ce006c), SPH_C32(0x9e340000), SPH_C32(0x55ed0000), + SPH_C32(0x40cf130d), SPH_C32(0x3d700f24), SPH_C32(0xcc736312), + SPH_C32(0xb3ce4f0e) }, + { SPH_C32(0xd9b70000), SPH_C32(0xf94c000e), SPH_C32(0x0adfe000), + SPH_C32(0xe3130000), SPH_C32(0xe0635d6c), SPH_C32(0x2945eea9), + SPH_C32(0xc1f22225), SPH_C32(0x00681320), SPH_C32(0x2f300000), + SPH_C32(0x061e006c), SPH_C32(0x6ac06000), SPH_C32(0x17290000), + SPH_C32(0x23772e67), SPH_C32(0x45ca9b44), SPH_C32(0xeddcc2f8), + SPH_C32(0x036b573a) }, + { SPH_C32(0x6f790000), SPH_C32(0x23a5000c), SPH_C32(0x1fb16000), + SPH_C32(0x39810000), SPH_C32(0x16be0708), SPH_C32(0x1f77b223), + SPH_C32(0x3380ca8b), SPH_C32(0xa6d0d1ad), SPH_C32(0xa9490000), + SPH_C32(0x3927006e), SPH_C32(0x8b5a8000), SPH_C32(0x8f7f0000), + SPH_C32(0xb6124969), SPH_C32(0x0b4253ae), SPH_C32(0x3e018bbc), + SPH_C32(0x15768d83) }, + { SPH_C32(0xe9000000), SPH_C32(0x1c9c000e), SPH_C32(0xfe2b8000), + SPH_C32(0xa1d70000), SPH_C32(0x83db6006), SPH_C32(0x51ff7ac9), + SPH_C32(0xe05d83cf), SPH_C32(0xb0cd0b14), SPH_C32(0x99fe0000), + SPH_C32(0xdcf7006e), SPH_C32(0x7faee000), SPH_C32(0xcdbb0000), + SPH_C32(0xd5aa7403), SPH_C32(0x73f8c7ce), SPH_C32(0x1fae2a56), + SPH_C32(0xa5d395b7) }, + { SPH_C32(0x4bd70000), SPH_C32(0xe5bf0030), SPH_C32(0xbb9a0000), + SPH_C32(0x3ff30000), SPH_C32(0x6e6a5dd2), SPH_C32(0x5b3e8a36), + SPH_C32(0x73c97bd1), SPH_C32(0xcdbf1219), SPH_C32(0xfcc40000), + SPH_C32(0xd9800078), SPH_C32(0x6cf20000), SPH_C32(0xffa30000), + SPH_C32(0x9bd151ab), SPH_C32(0x181bb131), SPH_C32(0xde4ed244), + SPH_C32(0x8980d6d9) }, + { SPH_C32(0xcdae0000), SPH_C32(0xda860032), SPH_C32(0x5a00e000), + SPH_C32(0xa7a50000), SPH_C32(0xfb0f3adc), SPH_C32(0x15b642dc), + SPH_C32(0xa0143295), SPH_C32(0xdba2c8a0), SPH_C32(0xcc730000), + SPH_C32(0x3c500078), SPH_C32(0x98066000), SPH_C32(0xbd670000), + SPH_C32(0xf8696cc1), SPH_C32(0x60a12551), SPH_C32(0xffe173ae), + SPH_C32(0x3925ceed) }, + { SPH_C32(0x7b600000), SPH_C32(0x006f0030), SPH_C32(0x4f6e6000), + SPH_C32(0x7d370000), SPH_C32(0x0dd260b8), SPH_C32(0x23841e56), + SPH_C32(0x5266da3b), SPH_C32(0x7d1a0a2d), SPH_C32(0x4a0a0000), + SPH_C32(0x0369007a), SPH_C32(0x799c8000), SPH_C32(0x25310000), + SPH_C32(0x6d0c0bcf), SPH_C32(0x2e29edbb), SPH_C32(0x2c3c3aea), + SPH_C32(0x2f381454) }, + { SPH_C32(0xfd190000), SPH_C32(0x3f560032), SPH_C32(0xaef48000), + SPH_C32(0xe5610000), SPH_C32(0x98b707b6), SPH_C32(0x6d0cd6bc), + SPH_C32(0x81bb937f), SPH_C32(0x6b07d094), SPH_C32(0x7abd0000), + SPH_C32(0xe6b9007a), SPH_C32(0x8d68e000), SPH_C32(0x67f50000), + SPH_C32(0x0eb436a5), SPH_C32(0x569379db), SPH_C32(0x0d939b00), + SPH_C32(0x9f9d0c60) }, + { SPH_C32(0xe8dd0000), SPH_C32(0xfa4a0044), SPH_C32(0x3c2d0000), + SPH_C32(0xbb150000), SPH_C32(0x80bd361b), SPH_C32(0x24e81d44), + SPH_C32(0xbfa8c2f4), SPH_C32(0x524a0d59), SPH_C32(0x54500000), + SPH_C32(0x0671005c), SPH_C32(0x25ae0000), SPH_C32(0x6a1e0000), + SPH_C32(0x2ea54edf), SPH_C32(0x664e8512), SPH_C32(0xbfba18c3), + SPH_C32(0x7e715d17) }, + { SPH_C32(0x6ea40000), SPH_C32(0xc5730046), SPH_C32(0xddb7e000), + SPH_C32(0x23430000), SPH_C32(0x15d85115), SPH_C32(0x6a60d5ae), + SPH_C32(0x6c758bb0), SPH_C32(0x4457d7e0), SPH_C32(0x64e70000), + SPH_C32(0xe3a1005c), SPH_C32(0xd15a6000), SPH_C32(0x28da0000), + SPH_C32(0x4d1d73b5), SPH_C32(0x1ef41172), SPH_C32(0x9e15b929), + SPH_C32(0xced44523) }, + { SPH_C32(0xd86a0000), SPH_C32(0x1f9a0044), SPH_C32(0xc8d96000), + SPH_C32(0xf9d10000), SPH_C32(0xe3050b71), SPH_C32(0x5c528924), + SPH_C32(0x9e07631e), SPH_C32(0xe2ef156d), SPH_C32(0xe29e0000), + SPH_C32(0xdc98005e), SPH_C32(0x30c08000), SPH_C32(0xb08c0000), + SPH_C32(0xd87814bb), SPH_C32(0x507cd998), SPH_C32(0x4dc8f06d), + SPH_C32(0xd8c99f9a) }, + { SPH_C32(0x5e130000), SPH_C32(0x20a30046), SPH_C32(0x29438000), + SPH_C32(0x61870000), SPH_C32(0x76606c7f), SPH_C32(0x12da41ce), + SPH_C32(0x4dda2a5a), SPH_C32(0xf4f2cfd4), SPH_C32(0xd2290000), + SPH_C32(0x3948005e), SPH_C32(0xc434e000), SPH_C32(0xf2480000), + SPH_C32(0xbbc029d1), SPH_C32(0x28c64df8), SPH_C32(0x6c675187), + SPH_C32(0x686c87ae) }, + { SPH_C32(0xfcc40000), SPH_C32(0xd9800078), SPH_C32(0x6cf20000), + SPH_C32(0xffa30000), SPH_C32(0x9bd151ab), SPH_C32(0x181bb131), + SPH_C32(0xde4ed244), SPH_C32(0x8980d6d9), SPH_C32(0xb7130000), + SPH_C32(0x3c3f0048), SPH_C32(0xd7680000), SPH_C32(0xc0500000), + SPH_C32(0xf5bb0c79), SPH_C32(0x43253b07), SPH_C32(0xad87a995), + SPH_C32(0x443fc4c0) }, + { SPH_C32(0x7abd0000), SPH_C32(0xe6b9007a), SPH_C32(0x8d68e000), + SPH_C32(0x67f50000), SPH_C32(0x0eb436a5), SPH_C32(0x569379db), + SPH_C32(0x0d939b00), SPH_C32(0x9f9d0c60), SPH_C32(0x87a40000), + SPH_C32(0xd9ef0048), SPH_C32(0x239c6000), SPH_C32(0x82940000), + SPH_C32(0x96033113), SPH_C32(0x3b9faf67), SPH_C32(0x8c28087f), + SPH_C32(0xf49adcf4) }, + { SPH_C32(0xcc730000), SPH_C32(0x3c500078), SPH_C32(0x98066000), + SPH_C32(0xbd670000), SPH_C32(0xf8696cc1), SPH_C32(0x60a12551), + SPH_C32(0xffe173ae), SPH_C32(0x3925ceed), SPH_C32(0x01dd0000), + SPH_C32(0xe6d6004a), SPH_C32(0xc2068000), SPH_C32(0x1ac20000), + SPH_C32(0x0366561d), SPH_C32(0x7517678d), SPH_C32(0x5ff5413b), + SPH_C32(0xe287064d) }, + { SPH_C32(0x4a0a0000), SPH_C32(0x0369007a), SPH_C32(0x799c8000), + SPH_C32(0x25310000), SPH_C32(0x6d0c0bcf), SPH_C32(0x2e29edbb), + SPH_C32(0x2c3c3aea), SPH_C32(0x2f381454), SPH_C32(0x316a0000), + SPH_C32(0x0306004a), SPH_C32(0x36f2e000), SPH_C32(0x58060000), + SPH_C32(0x60de6b77), SPH_C32(0x0dadf3ed), SPH_C32(0x7e5ae0d1), + SPH_C32(0x52221e79) }, + { SPH_C32(0x0b9e0000), SPH_C32(0xc0040050), SPH_C32(0xceeb0000), + SPH_C32(0x115b0000), SPH_C32(0x5ba374bd), SPH_C32(0x0183a351), + SPH_C32(0xad9573a2), SPH_C32(0x6804948e), SPH_C32(0xa30a0000), + SPH_C32(0x1ff50074), SPH_C32(0x87b70000), SPH_C32(0x84e60000), + SPH_C32(0xeed76bc9), SPH_C32(0x7fd69772), SPH_C32(0xcc61b925), + SPH_C32(0x9ff51f40) }, + { SPH_C32(0x8de70000), SPH_C32(0xff3d0052), SPH_C32(0x2f71e000), + SPH_C32(0x890d0000), SPH_C32(0xcec613b3), SPH_C32(0x4f0b6bbb), + SPH_C32(0x7e483ae6), SPH_C32(0x7e194e37), SPH_C32(0x93bd0000), + SPH_C32(0xfa250074), SPH_C32(0x73436000), SPH_C32(0xc6220000), + SPH_C32(0x8d6f56a3), SPH_C32(0x076c0312), SPH_C32(0xedce18cf), + SPH_C32(0x2f500774) }, + { SPH_C32(0x3b290000), SPH_C32(0x25d40050), SPH_C32(0x3a1f6000), + SPH_C32(0x539f0000), SPH_C32(0x381b49d7), SPH_C32(0x79393731), + SPH_C32(0x8c3ad248), SPH_C32(0xd8a18cba), SPH_C32(0x15c40000), + SPH_C32(0xc51c0076), SPH_C32(0x92d98000), SPH_C32(0x5e740000), + SPH_C32(0x180a31ad), SPH_C32(0x49e4cbf8), SPH_C32(0x3e13518b), + SPH_C32(0x394dddcd) }, + { SPH_C32(0xbd500000), SPH_C32(0x1aed0052), SPH_C32(0xdb858000), + SPH_C32(0xcbc90000), SPH_C32(0xad7e2ed9), SPH_C32(0x37b1ffdb), + SPH_C32(0x5fe79b0c), SPH_C32(0xcebc5603), SPH_C32(0x25730000), + SPH_C32(0x20cc0076), SPH_C32(0x662de000), SPH_C32(0x1cb00000), + SPH_C32(0x7bb20cc7), SPH_C32(0x315e5f98), SPH_C32(0x1fbcf061), + SPH_C32(0x89e8c5f9) }, + { SPH_C32(0x1f870000), SPH_C32(0xe3ce006c), SPH_C32(0x9e340000), + SPH_C32(0x55ed0000), SPH_C32(0x40cf130d), SPH_C32(0x3d700f24), + SPH_C32(0xcc736312), SPH_C32(0xb3ce4f0e), SPH_C32(0x40490000), + SPH_C32(0x25bb0060), SPH_C32(0x75710000), SPH_C32(0x2ea80000), + SPH_C32(0x35c9296f), SPH_C32(0x5abd2967), SPH_C32(0xde5c0873), + SPH_C32(0xa5bb8697) }, + { SPH_C32(0x99fe0000), SPH_C32(0xdcf7006e), SPH_C32(0x7faee000), + SPH_C32(0xcdbb0000), SPH_C32(0xd5aa7403), SPH_C32(0x73f8c7ce), + SPH_C32(0x1fae2a56), SPH_C32(0xa5d395b7), SPH_C32(0x70fe0000), + SPH_C32(0xc06b0060), SPH_C32(0x81856000), SPH_C32(0x6c6c0000), + SPH_C32(0x56711405), SPH_C32(0x2207bd07), SPH_C32(0xfff3a999), + SPH_C32(0x151e9ea3) }, + { SPH_C32(0x2f300000), SPH_C32(0x061e006c), SPH_C32(0x6ac06000), + SPH_C32(0x17290000), SPH_C32(0x23772e67), SPH_C32(0x45ca9b44), + SPH_C32(0xeddcc2f8), SPH_C32(0x036b573a), SPH_C32(0xf6870000), + SPH_C32(0xff520062), SPH_C32(0x601f8000), SPH_C32(0xf43a0000), + SPH_C32(0xc314730b), SPH_C32(0x6c8f75ed), SPH_C32(0x2c2ee0dd), + SPH_C32(0x0303441a) }, + { SPH_C32(0xa9490000), SPH_C32(0x3927006e), SPH_C32(0x8b5a8000), + SPH_C32(0x8f7f0000), SPH_C32(0xb6124969), SPH_C32(0x0b4253ae), + SPH_C32(0x3e018bbc), SPH_C32(0x15768d83), SPH_C32(0xc6300000), + SPH_C32(0x1a820062), SPH_C32(0x94ebe000), SPH_C32(0xb6fe0000), + SPH_C32(0xa0ac4e61), SPH_C32(0x1435e18d), SPH_C32(0x0d814137), + SPH_C32(0xb3a65c2e) }, + { SPH_C32(0x69510000), SPH_C32(0xd4e1009c), SPH_C32(0xc3230000), + SPH_C32(0xac2f0000), SPH_C32(0xe4950bae), SPH_C32(0xcea415dc), + SPH_C32(0x87ec287c), SPH_C32(0xbce1a3ce), SPH_C32(0xc6730000), + SPH_C32(0xaf8d000c), SPH_C32(0xa4c10000), SPH_C32(0x218d0000), + SPH_C32(0x23111587), SPH_C32(0x7913512f), SPH_C32(0x1d28ac88), + SPH_C32(0x378dd173) }, + { SPH_C32(0xef280000), SPH_C32(0xebd8009e), SPH_C32(0x22b9e000), + SPH_C32(0x34790000), SPH_C32(0x71f06ca0), SPH_C32(0x802cdd36), + SPH_C32(0x54316138), SPH_C32(0xaafc7977), SPH_C32(0xf6c40000), + SPH_C32(0x4a5d000c), SPH_C32(0x50356000), SPH_C32(0x63490000), + SPH_C32(0x40a928ed), SPH_C32(0x01a9c54f), SPH_C32(0x3c870d62), + SPH_C32(0x8728c947) }, + { SPH_C32(0x59e60000), SPH_C32(0x3131009c), SPH_C32(0x37d76000), + SPH_C32(0xeeeb0000), SPH_C32(0x872d36c4), SPH_C32(0xb61e81bc), + SPH_C32(0xa6438996), SPH_C32(0x0c44bbfa), SPH_C32(0x70bd0000), + SPH_C32(0x7564000e), SPH_C32(0xb1af8000), SPH_C32(0xfb1f0000), + SPH_C32(0xd5cc4fe3), SPH_C32(0x4f210da5), SPH_C32(0xef5a4426), + SPH_C32(0x913513fe) }, + { SPH_C32(0xdf9f0000), SPH_C32(0x0e08009e), SPH_C32(0xd64d8000), + SPH_C32(0x76bd0000), SPH_C32(0x124851ca), SPH_C32(0xf8964956), + SPH_C32(0x759ec0d2), SPH_C32(0x1a596143), SPH_C32(0x400a0000), + SPH_C32(0x90b4000e), SPH_C32(0x455be000), SPH_C32(0xb9db0000), + SPH_C32(0xb6747289), SPH_C32(0x379b99c5), SPH_C32(0xcef5e5cc), + SPH_C32(0x21900bca) }, + { SPH_C32(0x7d480000), SPH_C32(0xf72b00a0), SPH_C32(0x93fc0000), + SPH_C32(0xe8990000), SPH_C32(0xfff96c1e), SPH_C32(0xf257b9a9), + SPH_C32(0xe60a38cc), SPH_C32(0x672b784e), SPH_C32(0x25300000), + SPH_C32(0x95c30018), SPH_C32(0x56070000), SPH_C32(0x8bc30000), + SPH_C32(0xf80f5721), SPH_C32(0x5c78ef3a), SPH_C32(0x0f151dde), + SPH_C32(0x0dc348a4) }, + { SPH_C32(0xfb310000), SPH_C32(0xc81200a2), SPH_C32(0x7266e000), + SPH_C32(0x70cf0000), SPH_C32(0x6a9c0b10), SPH_C32(0xbcdf7143), + SPH_C32(0x35d77188), SPH_C32(0x7136a2f7), SPH_C32(0x15870000), + SPH_C32(0x70130018), SPH_C32(0xa2f36000), SPH_C32(0xc9070000), + SPH_C32(0x9bb76a4b), SPH_C32(0x24c27b5a), SPH_C32(0x2ebabc34), + SPH_C32(0xbd665090) }, + { SPH_C32(0x4dff0000), SPH_C32(0x12fb00a0), SPH_C32(0x67086000), + SPH_C32(0xaa5d0000), SPH_C32(0x9c415174), SPH_C32(0x8aed2dc9), + SPH_C32(0xc7a59926), SPH_C32(0xd78e607a), SPH_C32(0x93fe0000), + SPH_C32(0x4f2a001a), SPH_C32(0x43698000), SPH_C32(0x51510000), + SPH_C32(0x0ed20d45), SPH_C32(0x6a4ab3b0), SPH_C32(0xfd67f570), + SPH_C32(0xab7b8a29) }, + { SPH_C32(0xcb860000), SPH_C32(0x2dc200a2), SPH_C32(0x86928000), + SPH_C32(0x320b0000), SPH_C32(0x0924367a), SPH_C32(0xc465e523), + SPH_C32(0x1478d062), SPH_C32(0xc193bac3), SPH_C32(0xa3490000), + SPH_C32(0xaafa001a), SPH_C32(0xb79de000), SPH_C32(0x13950000), + SPH_C32(0x6d6a302f), SPH_C32(0x12f027d0), SPH_C32(0xdcc8549a), + SPH_C32(0x1bde921d) }, + { SPH_C32(0x8a120000), SPH_C32(0xeeaf0088), SPH_C32(0x31e50000), + SPH_C32(0x06610000), SPH_C32(0x3f8b4908), SPH_C32(0xebcfabc9), + SPH_C32(0x95d1992a), SPH_C32(0x86af3a19), SPH_C32(0x31290000), + SPH_C32(0xb6090024), SPH_C32(0x06d80000), SPH_C32(0xcf750000), + SPH_C32(0xe3633091), SPH_C32(0x608b434f), SPH_C32(0x6ef30d6e), + SPH_C32(0xd6099324) }, + { SPH_C32(0x0c6b0000), SPH_C32(0xd196008a), SPH_C32(0xd07fe000), + SPH_C32(0x9e370000), SPH_C32(0xaaee2e06), SPH_C32(0xa5476323), + SPH_C32(0x460cd06e), SPH_C32(0x90b2e0a0), SPH_C32(0x019e0000), + SPH_C32(0x53d90024), SPH_C32(0xf22c6000), SPH_C32(0x8db10000), + SPH_C32(0x80db0dfb), SPH_C32(0x1831d72f), SPH_C32(0x4f5cac84), + SPH_C32(0x66ac8b10) }, + { SPH_C32(0xbaa50000), SPH_C32(0x0b7f0088), SPH_C32(0xc5116000), + SPH_C32(0x44a50000), SPH_C32(0x5c337462), SPH_C32(0x93753fa9), + SPH_C32(0xb47e38c0), SPH_C32(0x360a222d), SPH_C32(0x87e70000), + SPH_C32(0x6ce00026), SPH_C32(0x13b68000), SPH_C32(0x15e70000), + SPH_C32(0x15be6af5), SPH_C32(0x56b91fc5), SPH_C32(0x9c81e5c0), + SPH_C32(0x70b151a9) }, + { SPH_C32(0x3cdc0000), SPH_C32(0x3446008a), SPH_C32(0x248b8000), + SPH_C32(0xdcf30000), SPH_C32(0xc956136c), SPH_C32(0xddfdf743), + SPH_C32(0x67a37184), SPH_C32(0x2017f894), SPH_C32(0xb7500000), + SPH_C32(0x89300026), SPH_C32(0xe742e000), SPH_C32(0x57230000), + SPH_C32(0x7606579f), SPH_C32(0x2e038ba5), SPH_C32(0xbd2e442a), + SPH_C32(0xc014499d) }, + { SPH_C32(0x9e0b0000), SPH_C32(0xcd6500b4), SPH_C32(0x613a0000), + SPH_C32(0x42d70000), SPH_C32(0x24e72eb8), SPH_C32(0xd73c07bc), + SPH_C32(0xf437899a), SPH_C32(0x5d65e199), SPH_C32(0xd26a0000), + SPH_C32(0x8c470030), SPH_C32(0xf41e0000), SPH_C32(0x653b0000), + SPH_C32(0x387d7237), SPH_C32(0x45e0fd5a), SPH_C32(0x7ccebc38), + SPH_C32(0xec470af3) }, + { SPH_C32(0x18720000), SPH_C32(0xf25c00b6), SPH_C32(0x80a0e000), + SPH_C32(0xda810000), SPH_C32(0xb18249b6), SPH_C32(0x99b4cf56), + SPH_C32(0x27eac0de), SPH_C32(0x4b783b20), SPH_C32(0xe2dd0000), + SPH_C32(0x69970030), SPH_C32(0x00ea6000), SPH_C32(0x27ff0000), + SPH_C32(0x5bc54f5d), SPH_C32(0x3d5a693a), SPH_C32(0x5d611dd2), + SPH_C32(0x5ce212c7) }, + { SPH_C32(0xaebc0000), SPH_C32(0x28b500b4), SPH_C32(0x95ce6000), + SPH_C32(0x00130000), SPH_C32(0x475f13d2), SPH_C32(0xaf8693dc), + SPH_C32(0xd5982870), SPH_C32(0xedc0f9ad), SPH_C32(0x64a40000), + SPH_C32(0x56ae0032), SPH_C32(0xe1708000), SPH_C32(0xbfa90000), + SPH_C32(0xcea02853), SPH_C32(0x73d2a1d0), SPH_C32(0x8ebc5496), + SPH_C32(0x4affc87e) }, + { SPH_C32(0x28c50000), SPH_C32(0x178c00b6), SPH_C32(0x74548000), + SPH_C32(0x98450000), SPH_C32(0xd23a74dc), SPH_C32(0xe10e5b36), + SPH_C32(0x06456134), SPH_C32(0xfbdd2314), SPH_C32(0x54130000), + SPH_C32(0xb37e0032), SPH_C32(0x1584e000), SPH_C32(0xfd6d0000), + SPH_C32(0xad181539), SPH_C32(0x0b6835b0), SPH_C32(0xaf13f57c), + SPH_C32(0xfa5ad04a) }, + { SPH_C32(0x3d010000), SPH_C32(0xd29000c0), SPH_C32(0xe68d0000), + SPH_C32(0xc6310000), SPH_C32(0xca304571), SPH_C32(0xa8ea90ce), + SPH_C32(0x385630bf), SPH_C32(0xc290fed9), SPH_C32(0x7afe0000), + SPH_C32(0x53b60014), SPH_C32(0xbd420000), SPH_C32(0xf0860000), + SPH_C32(0x8d096d43), SPH_C32(0x3bb5c979), SPH_C32(0x1d3a76bf), + SPH_C32(0x1bb6813d) }, + { SPH_C32(0xbb780000), SPH_C32(0xeda900c2), SPH_C32(0x0717e000), + SPH_C32(0x5e670000), SPH_C32(0x5f55227f), SPH_C32(0xe6625824), + SPH_C32(0xeb8b79fb), SPH_C32(0xd48d2460), SPH_C32(0x4a490000), + SPH_C32(0xb6660014), SPH_C32(0x49b66000), SPH_C32(0xb2420000), + SPH_C32(0xeeb15029), SPH_C32(0x430f5d19), SPH_C32(0x3c95d755), + SPH_C32(0xab139909) }, + { SPH_C32(0x0db60000), SPH_C32(0x374000c0), SPH_C32(0x12796000), + SPH_C32(0x84f50000), SPH_C32(0xa988781b), SPH_C32(0xd05004ae), + SPH_C32(0x19f99155), SPH_C32(0x7235e6ed), SPH_C32(0xcc300000), + SPH_C32(0x895f0016), SPH_C32(0xa82c8000), SPH_C32(0x2a140000), + SPH_C32(0x7bd43727), SPH_C32(0x0d8795f3), SPH_C32(0xef489e11), + SPH_C32(0xbd0e43b0) }, + { SPH_C32(0x8bcf0000), SPH_C32(0x087900c2), SPH_C32(0xf3e38000), + SPH_C32(0x1ca30000), SPH_C32(0x3ced1f15), SPH_C32(0x9ed8cc44), + SPH_C32(0xca24d811), SPH_C32(0x64283c54), SPH_C32(0xfc870000), + SPH_C32(0x6c8f0016), SPH_C32(0x5cd8e000), SPH_C32(0x68d00000), + SPH_C32(0x186c0a4d), SPH_C32(0x753d0193), SPH_C32(0xcee73ffb), + SPH_C32(0x0dab5b84) }, + { SPH_C32(0x29180000), SPH_C32(0xf15a00fc), SPH_C32(0xb6520000), + SPH_C32(0x82870000), SPH_C32(0xd15c22c1), SPH_C32(0x94193cbb), + SPH_C32(0x59b0200f), SPH_C32(0x195a2559), SPH_C32(0x99bd0000), + SPH_C32(0x69f80000), SPH_C32(0x4f840000), SPH_C32(0x5ac80000), + SPH_C32(0x56172fe5), SPH_C32(0x1ede776c), SPH_C32(0x0f07c7e9), + SPH_C32(0x21f818ea) }, + { SPH_C32(0xaf610000), SPH_C32(0xce6300fe), SPH_C32(0x57c8e000), + SPH_C32(0x1ad10000), SPH_C32(0x443945cf), SPH_C32(0xda91f451), + SPH_C32(0x8a6d694b), SPH_C32(0x0f47ffe0), SPH_C32(0xa90a0000), + SPH_C32(0x8c280000), SPH_C32(0xbb706000), SPH_C32(0x180c0000), + SPH_C32(0x35af128f), SPH_C32(0x6664e30c), SPH_C32(0x2ea86603), + SPH_C32(0x915d00de) }, + { SPH_C32(0x19af0000), SPH_C32(0x148a00fc), SPH_C32(0x42a66000), + SPH_C32(0xc0430000), SPH_C32(0xb2e41fab), SPH_C32(0xeca3a8db), + SPH_C32(0x781f81e5), SPH_C32(0xa9ff3d6d), SPH_C32(0x2f730000), + SPH_C32(0xb3110002), SPH_C32(0x5aea8000), SPH_C32(0x805a0000), + SPH_C32(0xa0ca7581), SPH_C32(0x28ec2be6), SPH_C32(0xfd752f47), + SPH_C32(0x8740da67) }, + { SPH_C32(0x9fd60000), SPH_C32(0x2bb300fe), SPH_C32(0xa33c8000), + SPH_C32(0x58150000), SPH_C32(0x278178a5), SPH_C32(0xa22b6031), + SPH_C32(0xabc2c8a1), SPH_C32(0xbfe2e7d4), SPH_C32(0x1fc40000), + SPH_C32(0x56c10002), SPH_C32(0xae1ee000), SPH_C32(0xc29e0000), + SPH_C32(0xc37248eb), SPH_C32(0x5056bf86), SPH_C32(0xdcda8ead), + SPH_C32(0x37e5c253) }, + { SPH_C32(0xde420000), SPH_C32(0xe8de00d4), SPH_C32(0x144b0000), + SPH_C32(0x6c7f0000), SPH_C32(0x112e07d7), SPH_C32(0x8d812edb), + SPH_C32(0x2a6b81e9), SPH_C32(0xf8de670e), SPH_C32(0x8da40000), + SPH_C32(0x4a32003c), SPH_C32(0x1f5b0000), SPH_C32(0x1e7e0000), + SPH_C32(0x4d7b4855), SPH_C32(0x222ddb19), SPH_C32(0x6ee1d759), + SPH_C32(0xfa32c36a) }, + { SPH_C32(0x583b0000), SPH_C32(0xd7e700d6), SPH_C32(0xf5d1e000), + SPH_C32(0xf4290000), SPH_C32(0x844b60d9), SPH_C32(0xc309e631), + SPH_C32(0xf9b6c8ad), SPH_C32(0xeec3bdb7), SPH_C32(0xbd130000), + SPH_C32(0xafe2003c), SPH_C32(0xebaf6000), SPH_C32(0x5cba0000), + SPH_C32(0x2ec3753f), SPH_C32(0x5a974f79), SPH_C32(0x4f4e76b3), + SPH_C32(0x4a97db5e) }, + { SPH_C32(0xeef50000), SPH_C32(0x0d0e00d4), SPH_C32(0xe0bf6000), + SPH_C32(0x2ebb0000), SPH_C32(0x72963abd), SPH_C32(0xf53bbabb), + SPH_C32(0x0bc42003), SPH_C32(0x487b7f3a), SPH_C32(0x3b6a0000), + SPH_C32(0x90db003e), SPH_C32(0x0a358000), SPH_C32(0xc4ec0000), + SPH_C32(0xbba61231), SPH_C32(0x141f8793), SPH_C32(0x9c933ff7), + SPH_C32(0x5c8a01e7) }, + { SPH_C32(0x688c0000), SPH_C32(0x323700d6), SPH_C32(0x01258000), + SPH_C32(0xb6ed0000), SPH_C32(0xe7f35db3), SPH_C32(0xbbb37251), + SPH_C32(0xd8196947), SPH_C32(0x5e66a583), SPH_C32(0x0bdd0000), + SPH_C32(0x750b003e), SPH_C32(0xfec1e000), SPH_C32(0x86280000), + SPH_C32(0xd81e2f5b), SPH_C32(0x6ca513f3), SPH_C32(0xbd3c9e1d), + SPH_C32(0xec2f19d3) }, + { SPH_C32(0xca5b0000), SPH_C32(0xcb1400e8), SPH_C32(0x44940000), + SPH_C32(0x28c90000), SPH_C32(0x0a426067), SPH_C32(0xb17282ae), + SPH_C32(0x4b8d9159), SPH_C32(0x2314bc8e), SPH_C32(0x6ee70000), + SPH_C32(0x707c0028), SPH_C32(0xed9d0000), SPH_C32(0xb4300000), + SPH_C32(0x96650af3), SPH_C32(0x0746650c), SPH_C32(0x7cdc660f), + SPH_C32(0xc07c5abd) }, + { SPH_C32(0x4c220000), SPH_C32(0xf42d00ea), SPH_C32(0xa50ee000), + SPH_C32(0xb09f0000), SPH_C32(0x9f270769), SPH_C32(0xfffa4a44), + SPH_C32(0x9850d81d), SPH_C32(0x35096637), SPH_C32(0x5e500000), + SPH_C32(0x95ac0028), SPH_C32(0x19696000), SPH_C32(0xf6f40000), + SPH_C32(0xf5dd3799), SPH_C32(0x7ffcf16c), SPH_C32(0x5d73c7e5), + SPH_C32(0x70d94289) }, + { SPH_C32(0xfaec0000), SPH_C32(0x2ec400e8), SPH_C32(0xb0606000), + SPH_C32(0x6a0d0000), SPH_C32(0x69fa5d0d), SPH_C32(0xc9c816ce), + SPH_C32(0x6a2230b3), SPH_C32(0x93b1a4ba), SPH_C32(0xd8290000), + SPH_C32(0xaa95002a), SPH_C32(0xf8f38000), SPH_C32(0x6ea20000), + SPH_C32(0x60b85097), SPH_C32(0x31743986), SPH_C32(0x8eae8ea1), + SPH_C32(0x66c49830) }, + { SPH_C32(0x7c950000), SPH_C32(0x11fd00ea), SPH_C32(0x51fa8000), + SPH_C32(0xf25b0000), SPH_C32(0xfc9f3a03), SPH_C32(0x8740de24), + SPH_C32(0xb9ff79f7), SPH_C32(0x85ac7e03), SPH_C32(0xe89e0000), + SPH_C32(0x4f45002a), SPH_C32(0x0c07e000), SPH_C32(0x2c660000), + SPH_C32(0x03006dfd), SPH_C32(0x49ceade6), SPH_C32(0xaf012f4b), + SPH_C32(0xd6618004) }, + { SPH_C32(0xd5dc0000), SPH_C32(0x28da0084), SPH_C32(0xdaa00000), + SPH_C32(0x7d240000), SPH_C32(0x4a8d736a), SPH_C32(0x8c028d8a), + SPH_C32(0x87fef24b), SPH_C32(0x90daf380), SPH_C32(0x2eae0000), + SPH_C32(0x55c70048), SPH_C32(0x98ec0000), SPH_C32(0x9a980000), + SPH_C32(0xa3ac239c), SPH_C32(0x5dfb4c6b), SPH_C32(0xa2806e7c), + SPH_C32(0x65c7dc2a) }, + { SPH_C32(0x53a50000), SPH_C32(0x17e30086), SPH_C32(0x3b3ae000), + SPH_C32(0xe5720000), SPH_C32(0xdfe81464), SPH_C32(0xc28a4560), + SPH_C32(0x5423bb0f), SPH_C32(0x86c72939), SPH_C32(0x1e190000), + SPH_C32(0xb0170048), SPH_C32(0x6c186000), SPH_C32(0xd85c0000), + SPH_C32(0xc0141ef6), SPH_C32(0x2541d80b), SPH_C32(0x832fcf96), + SPH_C32(0xd562c41e) }, + { SPH_C32(0xe56b0000), SPH_C32(0xcd0a0084), SPH_C32(0x2e546000), + SPH_C32(0x3fe00000), SPH_C32(0x29354e00), SPH_C32(0xf4b819ea), + SPH_C32(0xa65153a1), SPH_C32(0x207febb4), SPH_C32(0x98600000), + SPH_C32(0x8f2e004a), SPH_C32(0x8d828000), SPH_C32(0x400a0000), + SPH_C32(0x557179f8), SPH_C32(0x6bc910e1), SPH_C32(0x50f286d2), + SPH_C32(0xc37f1ea7) }, + { SPH_C32(0x63120000), SPH_C32(0xf2330086), SPH_C32(0xcfce8000), + SPH_C32(0xa7b60000), SPH_C32(0xbc50290e), SPH_C32(0xba30d100), + SPH_C32(0x758c1ae5), SPH_C32(0x3662310d), SPH_C32(0xa8d70000), + SPH_C32(0x6afe004a), SPH_C32(0x7976e000), SPH_C32(0x02ce0000), + SPH_C32(0x36c94492), SPH_C32(0x13738481), SPH_C32(0x715d2738), + SPH_C32(0x73da0693) }, + { SPH_C32(0xc1c50000), SPH_C32(0x0b1000b8), SPH_C32(0x8a7f0000), + SPH_C32(0x39920000), SPH_C32(0x51e114da), SPH_C32(0xb0f121ff), + SPH_C32(0xe618e2fb), SPH_C32(0x4b102800), SPH_C32(0xcded0000), + SPH_C32(0x6f89005c), SPH_C32(0x6a2a0000), SPH_C32(0x30d60000), + SPH_C32(0x78b2613a), SPH_C32(0x7890f27e), SPH_C32(0xb0bddf2a), + SPH_C32(0x5f8945fd) }, + { SPH_C32(0x47bc0000), SPH_C32(0x342900ba), SPH_C32(0x6be5e000), + SPH_C32(0xa1c40000), SPH_C32(0xc48473d4), SPH_C32(0xfe79e915), + SPH_C32(0x35c5abbf), SPH_C32(0x5d0df2b9), SPH_C32(0xfd5a0000), + SPH_C32(0x8a59005c), SPH_C32(0x9ede6000), SPH_C32(0x72120000), + SPH_C32(0x1b0a5c50), SPH_C32(0x002a661e), SPH_C32(0x91127ec0), + SPH_C32(0xef2c5dc9) }, + { SPH_C32(0xf1720000), SPH_C32(0xeec000b8), SPH_C32(0x7e8b6000), + SPH_C32(0x7b560000), SPH_C32(0x325929b0), SPH_C32(0xc84bb59f), + SPH_C32(0xc7b74311), SPH_C32(0xfbb53034), SPH_C32(0x7b230000), + SPH_C32(0xb560005e), SPH_C32(0x7f448000), SPH_C32(0xea440000), + SPH_C32(0x8e6f3b5e), SPH_C32(0x4ea2aef4), SPH_C32(0x42cf3784), + SPH_C32(0xf9318770) }, + { SPH_C32(0x770b0000), SPH_C32(0xd1f900ba), SPH_C32(0x9f118000), + SPH_C32(0xe3000000), SPH_C32(0xa73c4ebe), SPH_C32(0x86c37d75), + SPH_C32(0x146a0a55), SPH_C32(0xeda8ea8d), SPH_C32(0x4b940000), + SPH_C32(0x50b0005e), SPH_C32(0x8bb0e000), SPH_C32(0xa8800000), + SPH_C32(0xedd70634), SPH_C32(0x36183a94), SPH_C32(0x6360966e), + SPH_C32(0x49949f44) }, + { SPH_C32(0x369f0000), SPH_C32(0x12940090), SPH_C32(0x28660000), + SPH_C32(0xd76a0000), SPH_C32(0x919331cc), SPH_C32(0xa969339f), + SPH_C32(0x95c3431d), SPH_C32(0xaa946a57), SPH_C32(0xd9f40000), + SPH_C32(0x4c430060), SPH_C32(0x3af50000), SPH_C32(0x74600000), + SPH_C32(0x63de068a), SPH_C32(0x44635e0b), SPH_C32(0xd15bcf9a), + SPH_C32(0x84439e7d) }, + { SPH_C32(0xb0e60000), SPH_C32(0x2dad0092), SPH_C32(0xc9fce000), + SPH_C32(0x4f3c0000), SPH_C32(0x04f656c2), SPH_C32(0xe7e1fb75), + SPH_C32(0x461e0a59), SPH_C32(0xbc89b0ee), SPH_C32(0xe9430000), + SPH_C32(0xa9930060), SPH_C32(0xce016000), SPH_C32(0x36a40000), + SPH_C32(0x00663be0), SPH_C32(0x3cd9ca6b), SPH_C32(0xf0f46e70), + SPH_C32(0x34e68649) }, + { SPH_C32(0x06280000), SPH_C32(0xf7440090), SPH_C32(0xdc926000), + SPH_C32(0x95ae0000), SPH_C32(0xf22b0ca6), SPH_C32(0xd1d3a7ff), + SPH_C32(0xb46ce2f7), SPH_C32(0x1a317263), SPH_C32(0x6f3a0000), + SPH_C32(0x96aa0062), SPH_C32(0x2f9b8000), SPH_C32(0xaef20000), + SPH_C32(0x95035cee), SPH_C32(0x72510281), SPH_C32(0x23292734), + SPH_C32(0x22fb5cf0) }, + { SPH_C32(0x80510000), SPH_C32(0xc87d0092), SPH_C32(0x3d088000), + SPH_C32(0x0df80000), SPH_C32(0x674e6ba8), SPH_C32(0x9f5b6f15), + SPH_C32(0x67b1abb3), SPH_C32(0x0c2ca8da), SPH_C32(0x5f8d0000), + SPH_C32(0x737a0062), SPH_C32(0xdb6fe000), SPH_C32(0xec360000), + SPH_C32(0xf6bb6184), SPH_C32(0x0aeb96e1), SPH_C32(0x028686de), + SPH_C32(0x925e44c4) }, + { SPH_C32(0x22860000), SPH_C32(0x315e00ac), SPH_C32(0x78b90000), + SPH_C32(0x93dc0000), SPH_C32(0x8aff567c), SPH_C32(0x959a9fea), + SPH_C32(0xf42553ad), SPH_C32(0x715eb1d7), SPH_C32(0x3ab70000), + SPH_C32(0x760d0074), SPH_C32(0xc8330000), SPH_C32(0xde2e0000), + SPH_C32(0xb8c0442c), SPH_C32(0x6108e01e), SPH_C32(0xc3667ecc), + SPH_C32(0xbe0d07aa) }, + { SPH_C32(0xa4ff0000), SPH_C32(0x0e6700ae), SPH_C32(0x9923e000), + SPH_C32(0x0b8a0000), SPH_C32(0x1f9a3172), SPH_C32(0xdb125700), + SPH_C32(0x27f81ae9), SPH_C32(0x67436b6e), SPH_C32(0x0a000000), + SPH_C32(0x93dd0074), SPH_C32(0x3cc76000), SPH_C32(0x9cea0000), + SPH_C32(0xdb787946), SPH_C32(0x19b2747e), SPH_C32(0xe2c9df26), + SPH_C32(0x0ea81f9e) }, + { SPH_C32(0x12310000), SPH_C32(0xd48e00ac), SPH_C32(0x8c4d6000), + SPH_C32(0xd1180000), SPH_C32(0xe9476b16), SPH_C32(0xed200b8a), + SPH_C32(0xd58af247), SPH_C32(0xc1fba9e3), SPH_C32(0x8c790000), + SPH_C32(0xace40076), SPH_C32(0xdd5d8000), SPH_C32(0x04bc0000), + SPH_C32(0x4e1d1e48), SPH_C32(0x573abc94), SPH_C32(0x31149662), + SPH_C32(0x18b5c527) }, + { SPH_C32(0x94480000), SPH_C32(0xebb700ae), SPH_C32(0x6dd78000), + SPH_C32(0x494e0000), SPH_C32(0x7c220c18), SPH_C32(0xa3a8c360), + SPH_C32(0x0657bb03), SPH_C32(0xd7e6735a), SPH_C32(0xbcce0000), + SPH_C32(0x49340076), SPH_C32(0x29a9e000), SPH_C32(0x46780000), + SPH_C32(0x2da52322), SPH_C32(0x2f8028f4), SPH_C32(0x10bb3788), + SPH_C32(0xa810dd13) }, + { SPH_C32(0x818c0000), SPH_C32(0x2eab00d8), SPH_C32(0xff0e0000), + SPH_C32(0x173a0000), SPH_C32(0x64283db5), SPH_C32(0xea4c0898), + SPH_C32(0x3844ea88), SPH_C32(0xeeabae97), SPH_C32(0x92230000), + SPH_C32(0xa9fc0050), SPH_C32(0x816f0000), SPH_C32(0x4b930000), + SPH_C32(0x0db45b58), SPH_C32(0x1f5dd43d), SPH_C32(0xa292b44b), + SPH_C32(0x49fc8c64) }, + { SPH_C32(0x07f50000), SPH_C32(0x119200da), SPH_C32(0x1e94e000), + SPH_C32(0x8f6c0000), SPH_C32(0xf14d5abb), SPH_C32(0xa4c4c072), + SPH_C32(0xeb99a3cc), SPH_C32(0xf8b6742e), SPH_C32(0xa2940000), + SPH_C32(0x4c2c0050), SPH_C32(0x759b6000), SPH_C32(0x09570000), + SPH_C32(0x6e0c6632), SPH_C32(0x67e7405d), SPH_C32(0x833d15a1), + SPH_C32(0xf9599450) }, + { SPH_C32(0xb13b0000), SPH_C32(0xcb7b00d8), SPH_C32(0x0bfa6000), + SPH_C32(0x55fe0000), SPH_C32(0x079000df), SPH_C32(0x92f69cf8), + SPH_C32(0x19eb4b62), SPH_C32(0x5e0eb6a3), SPH_C32(0x24ed0000), + SPH_C32(0x73150052), SPH_C32(0x94018000), SPH_C32(0x91010000), + SPH_C32(0xfb69013c), SPH_C32(0x296f88b7), SPH_C32(0x50e05ce5), + SPH_C32(0xef444ee9) }, + { SPH_C32(0x37420000), SPH_C32(0xf44200da), SPH_C32(0xea608000), + SPH_C32(0xcda80000), SPH_C32(0x92f567d1), SPH_C32(0xdc7e5412), + SPH_C32(0xca360226), SPH_C32(0x48136c1a), SPH_C32(0x145a0000), + SPH_C32(0x96c50052), SPH_C32(0x60f5e000), SPH_C32(0xd3c50000), + SPH_C32(0x98d13c56), SPH_C32(0x51d51cd7), SPH_C32(0x714ffd0f), + SPH_C32(0x5fe156dd) }, + { SPH_C32(0x95950000), SPH_C32(0x0d6100e4), SPH_C32(0xafd10000), + SPH_C32(0x538c0000), SPH_C32(0x7f445a05), SPH_C32(0xd6bfa4ed), + SPH_C32(0x59a2fa38), SPH_C32(0x35617517), SPH_C32(0x71600000), + SPH_C32(0x93b20044), SPH_C32(0x73a90000), SPH_C32(0xe1dd0000), + SPH_C32(0xd6aa19fe), SPH_C32(0x3a366a28), SPH_C32(0xb0af051d), + SPH_C32(0x73b215b3) }, + { SPH_C32(0x13ec0000), SPH_C32(0x325800e6), SPH_C32(0x4e4be000), + SPH_C32(0xcbda0000), SPH_C32(0xea213d0b), SPH_C32(0x98376c07), + SPH_C32(0x8a7fb37c), SPH_C32(0x237cafae), SPH_C32(0x41d70000), + SPH_C32(0x76620044), SPH_C32(0x875d6000), SPH_C32(0xa3190000), + SPH_C32(0xb5122494), SPH_C32(0x428cfe48), SPH_C32(0x9100a4f7), + SPH_C32(0xc3170d87) }, + { SPH_C32(0xa5220000), SPH_C32(0xe8b100e4), SPH_C32(0x5b256000), + SPH_C32(0x11480000), SPH_C32(0x1cfc676f), SPH_C32(0xae05308d), + SPH_C32(0x780d5bd2), SPH_C32(0x85c46d23), SPH_C32(0xc7ae0000), + SPH_C32(0x495b0046), SPH_C32(0x66c78000), SPH_C32(0x3b4f0000), + SPH_C32(0x2077439a), SPH_C32(0x0c0436a2), SPH_C32(0x42ddedb3), + SPH_C32(0xd50ad73e) }, + { SPH_C32(0x235b0000), SPH_C32(0xd78800e6), SPH_C32(0xbabf8000), + SPH_C32(0x891e0000), SPH_C32(0x89990061), SPH_C32(0xe08df867), + SPH_C32(0xabd01296), SPH_C32(0x93d9b79a), SPH_C32(0xf7190000), + SPH_C32(0xac8b0046), SPH_C32(0x9233e000), SPH_C32(0x798b0000), + SPH_C32(0x43cf7ef0), SPH_C32(0x74bea2c2), SPH_C32(0x63724c59), + SPH_C32(0x65afcf0a) }, + { SPH_C32(0x62cf0000), SPH_C32(0x14e500cc), SPH_C32(0x0dc80000), + SPH_C32(0xbd740000), SPH_C32(0xbf367f13), SPH_C32(0xcf27b68d), + SPH_C32(0x2a795bde), SPH_C32(0xd4e53740), SPH_C32(0x65790000), + SPH_C32(0xb0780078), SPH_C32(0x23760000), SPH_C32(0xa56b0000), + SPH_C32(0xcdc67e4e), SPH_C32(0x06c5c65d), SPH_C32(0xd14915ad), + SPH_C32(0xa878ce33) }, + { SPH_C32(0xe4b60000), SPH_C32(0x2bdc00ce), SPH_C32(0xec52e000), + SPH_C32(0x25220000), SPH_C32(0x2a53181d), SPH_C32(0x81af7e67), + SPH_C32(0xf9a4129a), SPH_C32(0xc2f8edf9), SPH_C32(0x55ce0000), + SPH_C32(0x55a80078), SPH_C32(0xd7826000), SPH_C32(0xe7af0000), + SPH_C32(0xae7e4324), SPH_C32(0x7e7f523d), SPH_C32(0xf0e6b447), + SPH_C32(0x18ddd607) }, + { SPH_C32(0x52780000), SPH_C32(0xf13500cc), SPH_C32(0xf93c6000), + SPH_C32(0xffb00000), SPH_C32(0xdc8e4279), SPH_C32(0xb79d22ed), + SPH_C32(0x0bd6fa34), SPH_C32(0x64402f74), SPH_C32(0xd3b70000), + SPH_C32(0x6a91007a), SPH_C32(0x36188000), SPH_C32(0x7ff90000), + SPH_C32(0x3b1b242a), SPH_C32(0x30f79ad7), SPH_C32(0x233bfd03), + SPH_C32(0x0ec00cbe) }, + { SPH_C32(0xd4010000), SPH_C32(0xce0c00ce), SPH_C32(0x18a68000), + SPH_C32(0x67e60000), SPH_C32(0x49eb2577), SPH_C32(0xf915ea07), + SPH_C32(0xd80bb370), SPH_C32(0x725df5cd), SPH_C32(0xe3000000), + SPH_C32(0x8f41007a), SPH_C32(0xc2ece000), SPH_C32(0x3d3d0000), + SPH_C32(0x58a31940), SPH_C32(0x484d0eb7), SPH_C32(0x02945ce9), + SPH_C32(0xbe65148a) }, + { SPH_C32(0x76d60000), SPH_C32(0x372f00f0), SPH_C32(0x5d170000), + SPH_C32(0xf9c20000), SPH_C32(0xa45a18a3), SPH_C32(0xf3d41af8), + SPH_C32(0x4b9f4b6e), SPH_C32(0x0f2fecc0), SPH_C32(0x863a0000), + SPH_C32(0x8a36006c), SPH_C32(0xd1b00000), SPH_C32(0x0f250000), + SPH_C32(0x16d83ce8), SPH_C32(0x23ae7848), SPH_C32(0xc374a4fb), + SPH_C32(0x923657e4) }, + { SPH_C32(0xf0af0000), SPH_C32(0x081600f2), SPH_C32(0xbc8de000), + SPH_C32(0x61940000), SPH_C32(0x313f7fad), SPH_C32(0xbd5cd212), + SPH_C32(0x9842022a), SPH_C32(0x19323679), SPH_C32(0xb68d0000), + SPH_C32(0x6fe6006c), SPH_C32(0x25446000), SPH_C32(0x4de10000), + SPH_C32(0x75600182), SPH_C32(0x5b14ec28), SPH_C32(0xe2db0511), + SPH_C32(0x22934fd0) }, + { SPH_C32(0x46610000), SPH_C32(0xd2ff00f0), SPH_C32(0xa9e36000), + SPH_C32(0xbb060000), SPH_C32(0xc7e225c9), SPH_C32(0x8b6e8e98), + SPH_C32(0x6a30ea84), SPH_C32(0xbf8af4f4), SPH_C32(0x30f40000), + SPH_C32(0x50df006e), SPH_C32(0xc4de8000), SPH_C32(0xd5b70000), + SPH_C32(0xe005668c), SPH_C32(0x159c24c2), SPH_C32(0x31064c55), + SPH_C32(0x348e9569) }, + { SPH_C32(0xc0180000), SPH_C32(0xedc600f2), SPH_C32(0x48798000), + SPH_C32(0x23500000), SPH_C32(0x528742c7), SPH_C32(0xc5e64672), + SPH_C32(0xb9eda3c0), SPH_C32(0xa9972e4d), SPH_C32(0x00430000), + SPH_C32(0xb50f006e), SPH_C32(0x302ae000), SPH_C32(0x97730000), + SPH_C32(0x83bd5be6), SPH_C32(0x6d26b0a2), SPH_C32(0x10a9edbf), + SPH_C32(0x842b8d5d) }, + { SPH_C32(0xc6730000), SPH_C32(0xaf8d000c), SPH_C32(0xa4c10000), + SPH_C32(0x218d0000), SPH_C32(0x23111587), SPH_C32(0x7913512f), + SPH_C32(0x1d28ac88), SPH_C32(0x378dd173), SPH_C32(0xaf220000), + SPH_C32(0x7b6c0090), SPH_C32(0x67e20000), SPH_C32(0x8da20000), + SPH_C32(0xc7841e29), SPH_C32(0xb7b744f3), SPH_C32(0x9ac484f4), + SPH_C32(0x8b6c72bd) }, + { SPH_C32(0x400a0000), SPH_C32(0x90b4000e), SPH_C32(0x455be000), + SPH_C32(0xb9db0000), SPH_C32(0xb6747289), SPH_C32(0x379b99c5), + SPH_C32(0xcef5e5cc), SPH_C32(0x21900bca), SPH_C32(0x9f950000), + SPH_C32(0x9ebc0090), SPH_C32(0x93166000), SPH_C32(0xcf660000), + SPH_C32(0xa43c2343), SPH_C32(0xcf0dd093), SPH_C32(0xbb6b251e), + SPH_C32(0x3bc96a89) }, + { SPH_C32(0xf6c40000), SPH_C32(0x4a5d000c), SPH_C32(0x50356000), + SPH_C32(0x63490000), SPH_C32(0x40a928ed), SPH_C32(0x01a9c54f), + SPH_C32(0x3c870d62), SPH_C32(0x8728c947), SPH_C32(0x19ec0000), + SPH_C32(0xa1850092), SPH_C32(0x728c8000), SPH_C32(0x57300000), + SPH_C32(0x3159444d), SPH_C32(0x81851879), SPH_C32(0x68b66c5a), + SPH_C32(0x2dd4b030) }, + { SPH_C32(0x70bd0000), SPH_C32(0x7564000e), SPH_C32(0xb1af8000), + SPH_C32(0xfb1f0000), SPH_C32(0xd5cc4fe3), SPH_C32(0x4f210da5), + SPH_C32(0xef5a4426), SPH_C32(0x913513fe), SPH_C32(0x295b0000), + SPH_C32(0x44550092), SPH_C32(0x8678e000), SPH_C32(0x15f40000), + SPH_C32(0x52e17927), SPH_C32(0xf93f8c19), SPH_C32(0x4919cdb0), + SPH_C32(0x9d71a804) }, + { SPH_C32(0xd26a0000), SPH_C32(0x8c470030), SPH_C32(0xf41e0000), + SPH_C32(0x653b0000), SPH_C32(0x387d7237), SPH_C32(0x45e0fd5a), + SPH_C32(0x7ccebc38), SPH_C32(0xec470af3), SPH_C32(0x4c610000), + SPH_C32(0x41220084), SPH_C32(0x95240000), SPH_C32(0x27ec0000), + SPH_C32(0x1c9a5c8f), SPH_C32(0x92dcfae6), SPH_C32(0x88f935a2), + SPH_C32(0xb122eb6a) }, + { SPH_C32(0x54130000), SPH_C32(0xb37e0032), SPH_C32(0x1584e000), + SPH_C32(0xfd6d0000), SPH_C32(0xad181539), SPH_C32(0x0b6835b0), + SPH_C32(0xaf13f57c), SPH_C32(0xfa5ad04a), SPH_C32(0x7cd60000), + SPH_C32(0xa4f20084), SPH_C32(0x61d06000), SPH_C32(0x65280000), + SPH_C32(0x7f2261e5), SPH_C32(0xea666e86), SPH_C32(0xa9569448), + SPH_C32(0x0187f35e) }, + { SPH_C32(0xe2dd0000), SPH_C32(0x69970030), SPH_C32(0x00ea6000), + SPH_C32(0x27ff0000), SPH_C32(0x5bc54f5d), SPH_C32(0x3d5a693a), + SPH_C32(0x5d611dd2), SPH_C32(0x5ce212c7), SPH_C32(0xfaaf0000), + SPH_C32(0x9bcb0086), SPH_C32(0x804a8000), SPH_C32(0xfd7e0000), + SPH_C32(0xea4706eb), SPH_C32(0xa4eea66c), SPH_C32(0x7a8bdd0c), + SPH_C32(0x179a29e7) }, + { SPH_C32(0x64a40000), SPH_C32(0x56ae0032), SPH_C32(0xe1708000), + SPH_C32(0xbfa90000), SPH_C32(0xcea02853), SPH_C32(0x73d2a1d0), + SPH_C32(0x8ebc5496), SPH_C32(0x4affc87e), SPH_C32(0xca180000), + SPH_C32(0x7e1b0086), SPH_C32(0x74bee000), SPH_C32(0xbfba0000), + SPH_C32(0x89ff3b81), SPH_C32(0xdc54320c), SPH_C32(0x5b247ce6), + SPH_C32(0xa73f31d3) }, + { SPH_C32(0x25300000), SPH_C32(0x95c30018), SPH_C32(0x56070000), + SPH_C32(0x8bc30000), SPH_C32(0xf80f5721), SPH_C32(0x5c78ef3a), + SPH_C32(0x0f151dde), SPH_C32(0x0dc348a4), SPH_C32(0x58780000), + SPH_C32(0x62e800b8), SPH_C32(0xc5fb0000), SPH_C32(0x635a0000), + SPH_C32(0x07f63b3f), SPH_C32(0xae2f5693), SPH_C32(0xe91f2512), + SPH_C32(0x6ae830ea) }, + { SPH_C32(0xa3490000), SPH_C32(0xaafa001a), SPH_C32(0xb79de000), + SPH_C32(0x13950000), SPH_C32(0x6d6a302f), SPH_C32(0x12f027d0), + SPH_C32(0xdcc8549a), SPH_C32(0x1bde921d), SPH_C32(0x68cf0000), + SPH_C32(0x873800b8), SPH_C32(0x310f6000), SPH_C32(0x219e0000), + SPH_C32(0x644e0655), SPH_C32(0xd695c2f3), SPH_C32(0xc8b084f8), + SPH_C32(0xda4d28de) }, + { SPH_C32(0x15870000), SPH_C32(0x70130018), SPH_C32(0xa2f36000), + SPH_C32(0xc9070000), SPH_C32(0x9bb76a4b), SPH_C32(0x24c27b5a), + SPH_C32(0x2ebabc34), SPH_C32(0xbd665090), SPH_C32(0xeeb60000), + SPH_C32(0xb80100ba), SPH_C32(0xd0958000), SPH_C32(0xb9c80000), + SPH_C32(0xf12b615b), SPH_C32(0x981d0a19), SPH_C32(0x1b6dcdbc), + SPH_C32(0xcc50f267) }, + { SPH_C32(0x93fe0000), SPH_C32(0x4f2a001a), SPH_C32(0x43698000), + SPH_C32(0x51510000), SPH_C32(0x0ed20d45), SPH_C32(0x6a4ab3b0), + SPH_C32(0xfd67f570), SPH_C32(0xab7b8a29), SPH_C32(0xde010000), + SPH_C32(0x5dd100ba), SPH_C32(0x2461e000), SPH_C32(0xfb0c0000), + SPH_C32(0x92935c31), SPH_C32(0xe0a79e79), SPH_C32(0x3ac26c56), + SPH_C32(0x7cf5ea53) }, + { SPH_C32(0x31290000), SPH_C32(0xb6090024), SPH_C32(0x06d80000), + SPH_C32(0xcf750000), SPH_C32(0xe3633091), SPH_C32(0x608b434f), + SPH_C32(0x6ef30d6e), SPH_C32(0xd6099324), SPH_C32(0xbb3b0000), + SPH_C32(0x58a600ac), SPH_C32(0x373d0000), SPH_C32(0xc9140000), + SPH_C32(0xdce87999), SPH_C32(0x8b44e886), SPH_C32(0xfb229444), + SPH_C32(0x50a6a93d) }, + { SPH_C32(0xb7500000), SPH_C32(0x89300026), SPH_C32(0xe742e000), + SPH_C32(0x57230000), SPH_C32(0x7606579f), SPH_C32(0x2e038ba5), + SPH_C32(0xbd2e442a), SPH_C32(0xc014499d), SPH_C32(0x8b8c0000), + SPH_C32(0xbd7600ac), SPH_C32(0xc3c96000), SPH_C32(0x8bd00000), + SPH_C32(0xbf5044f3), SPH_C32(0xf3fe7ce6), SPH_C32(0xda8d35ae), + SPH_C32(0xe003b109) }, + { SPH_C32(0x019e0000), SPH_C32(0x53d90024), SPH_C32(0xf22c6000), + SPH_C32(0x8db10000), SPH_C32(0x80db0dfb), SPH_C32(0x1831d72f), + SPH_C32(0x4f5cac84), SPH_C32(0x66ac8b10), SPH_C32(0x0df50000), + SPH_C32(0x824f00ae), SPH_C32(0x22538000), SPH_C32(0x13860000), + SPH_C32(0x2a3523fd), SPH_C32(0xbd76b40c), SPH_C32(0x09507cea), + SPH_C32(0xf61e6bb0) }, + { SPH_C32(0x87e70000), SPH_C32(0x6ce00026), SPH_C32(0x13b68000), + SPH_C32(0x15e70000), SPH_C32(0x15be6af5), SPH_C32(0x56b91fc5), + SPH_C32(0x9c81e5c0), SPH_C32(0x70b151a9), SPH_C32(0x3d420000), + SPH_C32(0x679f00ae), SPH_C32(0xd6a7e000), SPH_C32(0x51420000), + SPH_C32(0x498d1e97), SPH_C32(0xc5cc206c), SPH_C32(0x28ffdd00), + SPH_C32(0x46bb7384) }, + { SPH_C32(0x92230000), SPH_C32(0xa9fc0050), SPH_C32(0x816f0000), + SPH_C32(0x4b930000), SPH_C32(0x0db45b58), SPH_C32(0x1f5dd43d), + SPH_C32(0xa292b44b), SPH_C32(0x49fc8c64), SPH_C32(0x13af0000), + SPH_C32(0x87570088), SPH_C32(0x7e610000), SPH_C32(0x5ca90000), + SPH_C32(0x699c66ed), SPH_C32(0xf511dca5), SPH_C32(0x9ad65ec3), + SPH_C32(0xa75722f3) }, + { SPH_C32(0x145a0000), SPH_C32(0x96c50052), SPH_C32(0x60f5e000), + SPH_C32(0xd3c50000), SPH_C32(0x98d13c56), SPH_C32(0x51d51cd7), + SPH_C32(0x714ffd0f), SPH_C32(0x5fe156dd), SPH_C32(0x23180000), + SPH_C32(0x62870088), SPH_C32(0x8a956000), SPH_C32(0x1e6d0000), + SPH_C32(0x0a245b87), SPH_C32(0x8dab48c5), SPH_C32(0xbb79ff29), + SPH_C32(0x17f23ac7) }, + { SPH_C32(0xa2940000), SPH_C32(0x4c2c0050), SPH_C32(0x759b6000), + SPH_C32(0x09570000), SPH_C32(0x6e0c6632), SPH_C32(0x67e7405d), + SPH_C32(0x833d15a1), SPH_C32(0xf9599450), SPH_C32(0xa5610000), + SPH_C32(0x5dbe008a), SPH_C32(0x6b0f8000), SPH_C32(0x863b0000), + SPH_C32(0x9f413c89), SPH_C32(0xc323802f), SPH_C32(0x68a4b66d), + SPH_C32(0x01efe07e) }, + { SPH_C32(0x24ed0000), SPH_C32(0x73150052), SPH_C32(0x94018000), + SPH_C32(0x91010000), SPH_C32(0xfb69013c), SPH_C32(0x296f88b7), + SPH_C32(0x50e05ce5), SPH_C32(0xef444ee9), SPH_C32(0x95d60000), + SPH_C32(0xb86e008a), SPH_C32(0x9ffbe000), SPH_C32(0xc4ff0000), + SPH_C32(0xfcf901e3), SPH_C32(0xbb99144f), SPH_C32(0x490b1787), + SPH_C32(0xb14af84a) }, + { SPH_C32(0x863a0000), SPH_C32(0x8a36006c), SPH_C32(0xd1b00000), + SPH_C32(0x0f250000), SPH_C32(0x16d83ce8), SPH_C32(0x23ae7848), + SPH_C32(0xc374a4fb), SPH_C32(0x923657e4), SPH_C32(0xf0ec0000), + SPH_C32(0xbd19009c), SPH_C32(0x8ca70000), SPH_C32(0xf6e70000), + SPH_C32(0xb282244b), SPH_C32(0xd07a62b0), SPH_C32(0x88ebef95), + SPH_C32(0x9d19bb24) }, + { SPH_C32(0x00430000), SPH_C32(0xb50f006e), SPH_C32(0x302ae000), + SPH_C32(0x97730000), SPH_C32(0x83bd5be6), SPH_C32(0x6d26b0a2), + SPH_C32(0x10a9edbf), SPH_C32(0x842b8d5d), SPH_C32(0xc05b0000), + SPH_C32(0x58c9009c), SPH_C32(0x78536000), SPH_C32(0xb4230000), + SPH_C32(0xd13a1921), SPH_C32(0xa8c0f6d0), SPH_C32(0xa9444e7f), + SPH_C32(0x2dbca310) }, + { SPH_C32(0xb68d0000), SPH_C32(0x6fe6006c), SPH_C32(0x25446000), + SPH_C32(0x4de10000), SPH_C32(0x75600182), SPH_C32(0x5b14ec28), + SPH_C32(0xe2db0511), SPH_C32(0x22934fd0), SPH_C32(0x46220000), + SPH_C32(0x67f0009e), SPH_C32(0x99c98000), SPH_C32(0x2c750000), + SPH_C32(0x445f7e2f), SPH_C32(0xe6483e3a), SPH_C32(0x7a99073b), + SPH_C32(0x3ba179a9) }, + { SPH_C32(0x30f40000), SPH_C32(0x50df006e), SPH_C32(0xc4de8000), + SPH_C32(0xd5b70000), SPH_C32(0xe005668c), SPH_C32(0x159c24c2), + SPH_C32(0x31064c55), SPH_C32(0x348e9569), SPH_C32(0x76950000), + SPH_C32(0x8220009e), SPH_C32(0x6d3de000), SPH_C32(0x6eb10000), + SPH_C32(0x27e74345), SPH_C32(0x9ef2aa5a), SPH_C32(0x5b36a6d1), + SPH_C32(0x8b04619d) }, + { SPH_C32(0x71600000), SPH_C32(0x93b20044), SPH_C32(0x73a90000), + SPH_C32(0xe1dd0000), SPH_C32(0xd6aa19fe), SPH_C32(0x3a366a28), + SPH_C32(0xb0af051d), SPH_C32(0x73b215b3), SPH_C32(0xe4f50000), + SPH_C32(0x9ed300a0), SPH_C32(0xdc780000), SPH_C32(0xb2510000), + SPH_C32(0xa9ee43fb), SPH_C32(0xec89cec5), SPH_C32(0xe90dff25), + SPH_C32(0x46d360a4) }, + { SPH_C32(0xf7190000), SPH_C32(0xac8b0046), SPH_C32(0x9233e000), + SPH_C32(0x798b0000), SPH_C32(0x43cf7ef0), SPH_C32(0x74bea2c2), + SPH_C32(0x63724c59), SPH_C32(0x65afcf0a), SPH_C32(0xd4420000), + SPH_C32(0x7b0300a0), SPH_C32(0x288c6000), SPH_C32(0xf0950000), + SPH_C32(0xca567e91), SPH_C32(0x94335aa5), SPH_C32(0xc8a25ecf), + SPH_C32(0xf6767890) }, + { SPH_C32(0x41d70000), SPH_C32(0x76620044), SPH_C32(0x875d6000), + SPH_C32(0xa3190000), SPH_C32(0xb5122494), SPH_C32(0x428cfe48), + SPH_C32(0x9100a4f7), SPH_C32(0xc3170d87), SPH_C32(0x523b0000), + SPH_C32(0x443a00a2), SPH_C32(0xc9168000), SPH_C32(0x68c30000), + SPH_C32(0x5f33199f), SPH_C32(0xdabb924f), SPH_C32(0x1b7f178b), + SPH_C32(0xe06ba229) }, + { SPH_C32(0xc7ae0000), SPH_C32(0x495b0046), SPH_C32(0x66c78000), + SPH_C32(0x3b4f0000), SPH_C32(0x2077439a), SPH_C32(0x0c0436a2), + SPH_C32(0x42ddedb3), SPH_C32(0xd50ad73e), SPH_C32(0x628c0000), + SPH_C32(0xa1ea00a2), SPH_C32(0x3de2e000), SPH_C32(0x2a070000), + SPH_C32(0x3c8b24f5), SPH_C32(0xa201062f), SPH_C32(0x3ad0b661), + SPH_C32(0x50ceba1d) }, + { SPH_C32(0x65790000), SPH_C32(0xb0780078), SPH_C32(0x23760000), + SPH_C32(0xa56b0000), SPH_C32(0xcdc67e4e), SPH_C32(0x06c5c65d), + SPH_C32(0xd14915ad), SPH_C32(0xa878ce33), SPH_C32(0x07b60000), + SPH_C32(0xa49d00b4), SPH_C32(0x2ebe0000), SPH_C32(0x181f0000), + SPH_C32(0x72f0015d), SPH_C32(0xc9e270d0), SPH_C32(0xfb304e73), + SPH_C32(0x7c9df973) }, + { SPH_C32(0xe3000000), SPH_C32(0x8f41007a), SPH_C32(0xc2ece000), + SPH_C32(0x3d3d0000), SPH_C32(0x58a31940), SPH_C32(0x484d0eb7), + SPH_C32(0x02945ce9), SPH_C32(0xbe65148a), SPH_C32(0x37010000), + SPH_C32(0x414d00b4), SPH_C32(0xda4a6000), SPH_C32(0x5adb0000), + SPH_C32(0x11483c37), SPH_C32(0xb158e4b0), SPH_C32(0xda9fef99), + SPH_C32(0xcc38e147) }, + { SPH_C32(0x55ce0000), SPH_C32(0x55a80078), SPH_C32(0xd7826000), + SPH_C32(0xe7af0000), SPH_C32(0xae7e4324), SPH_C32(0x7e7f523d), + SPH_C32(0xf0e6b447), SPH_C32(0x18ddd607), SPH_C32(0xb1780000), + SPH_C32(0x7e7400b6), SPH_C32(0x3bd08000), SPH_C32(0xc28d0000), + SPH_C32(0x842d5b39), SPH_C32(0xffd02c5a), SPH_C32(0x0942a6dd), + SPH_C32(0xda253bfe) }, + { SPH_C32(0xd3b70000), SPH_C32(0x6a91007a), SPH_C32(0x36188000), + SPH_C32(0x7ff90000), SPH_C32(0x3b1b242a), SPH_C32(0x30f79ad7), + SPH_C32(0x233bfd03), SPH_C32(0x0ec00cbe), SPH_C32(0x81cf0000), + SPH_C32(0x9ba400b6), SPH_C32(0xcf24e000), SPH_C32(0x80490000), + SPH_C32(0xe7956653), SPH_C32(0x876ab83a), SPH_C32(0x28ed0737), + SPH_C32(0x6a8023ca) }, + { SPH_C32(0x7afe0000), SPH_C32(0x53b60014), SPH_C32(0xbd420000), + SPH_C32(0xf0860000), SPH_C32(0x8d096d43), SPH_C32(0x3bb5c979), + SPH_C32(0x1d3a76bf), SPH_C32(0x1bb6813d), SPH_C32(0x47ff0000), + SPH_C32(0x812600d4), SPH_C32(0x5bcf0000), SPH_C32(0x36b70000), + SPH_C32(0x47392832), SPH_C32(0x935f59b7), SPH_C32(0x256c4600), + SPH_C32(0xd9267fe4) }, + { SPH_C32(0xfc870000), SPH_C32(0x6c8f0016), SPH_C32(0x5cd8e000), + SPH_C32(0x68d00000), SPH_C32(0x186c0a4d), SPH_C32(0x753d0193), + SPH_C32(0xcee73ffb), SPH_C32(0x0dab5b84), SPH_C32(0x77480000), + SPH_C32(0x64f600d4), SPH_C32(0xaf3b6000), SPH_C32(0x74730000), + SPH_C32(0x24811558), SPH_C32(0xebe5cdd7), SPH_C32(0x04c3e7ea), + SPH_C32(0x698367d0) }, + { SPH_C32(0x4a490000), SPH_C32(0xb6660014), SPH_C32(0x49b66000), + SPH_C32(0xb2420000), SPH_C32(0xeeb15029), SPH_C32(0x430f5d19), + SPH_C32(0x3c95d755), SPH_C32(0xab139909), SPH_C32(0xf1310000), + SPH_C32(0x5bcf00d6), SPH_C32(0x4ea18000), SPH_C32(0xec250000), + SPH_C32(0xb1e47256), SPH_C32(0xa56d053d), SPH_C32(0xd71eaeae), + SPH_C32(0x7f9ebd69) }, + { SPH_C32(0xcc300000), SPH_C32(0x895f0016), SPH_C32(0xa82c8000), + SPH_C32(0x2a140000), SPH_C32(0x7bd43727), SPH_C32(0x0d8795f3), + SPH_C32(0xef489e11), SPH_C32(0xbd0e43b0), SPH_C32(0xc1860000), + SPH_C32(0xbe1f00d6), SPH_C32(0xba55e000), SPH_C32(0xaee10000), + SPH_C32(0xd25c4f3c), SPH_C32(0xddd7915d), SPH_C32(0xf6b10f44), + SPH_C32(0xcf3ba55d) }, + { SPH_C32(0x6ee70000), SPH_C32(0x707c0028), SPH_C32(0xed9d0000), + SPH_C32(0xb4300000), SPH_C32(0x96650af3), SPH_C32(0x0746650c), + SPH_C32(0x7cdc660f), SPH_C32(0xc07c5abd), SPH_C32(0xa4bc0000), + SPH_C32(0xbb6800c0), SPH_C32(0xa9090000), SPH_C32(0x9cf90000), + SPH_C32(0x9c276a94), SPH_C32(0xb634e7a2), SPH_C32(0x3751f756), + SPH_C32(0xe368e633) }, + { SPH_C32(0xe89e0000), SPH_C32(0x4f45002a), SPH_C32(0x0c07e000), + SPH_C32(0x2c660000), SPH_C32(0x03006dfd), SPH_C32(0x49ceade6), + SPH_C32(0xaf012f4b), SPH_C32(0xd6618004), SPH_C32(0x940b0000), + SPH_C32(0x5eb800c0), SPH_C32(0x5dfd6000), SPH_C32(0xde3d0000), + SPH_C32(0xff9f57fe), SPH_C32(0xce8e73c2), SPH_C32(0x16fe56bc), + SPH_C32(0x53cdfe07) }, + { SPH_C32(0x5e500000), SPH_C32(0x95ac0028), SPH_C32(0x19696000), + SPH_C32(0xf6f40000), SPH_C32(0xf5dd3799), SPH_C32(0x7ffcf16c), + SPH_C32(0x5d73c7e5), SPH_C32(0x70d94289), SPH_C32(0x12720000), + SPH_C32(0x618100c2), SPH_C32(0xbc678000), SPH_C32(0x466b0000), + SPH_C32(0x6afa30f0), SPH_C32(0x8006bb28), SPH_C32(0xc5231ff8), + SPH_C32(0x45d024be) }, + { SPH_C32(0xd8290000), SPH_C32(0xaa95002a), SPH_C32(0xf8f38000), + SPH_C32(0x6ea20000), SPH_C32(0x60b85097), SPH_C32(0x31743986), + SPH_C32(0x8eae8ea1), SPH_C32(0x66c49830), SPH_C32(0x22c50000), + SPH_C32(0x845100c2), SPH_C32(0x4893e000), SPH_C32(0x04af0000), + SPH_C32(0x09420d9a), SPH_C32(0xf8bc2f48), SPH_C32(0xe48cbe12), + SPH_C32(0xf5753c8a) }, + { SPH_C32(0x99bd0000), SPH_C32(0x69f80000), SPH_C32(0x4f840000), + SPH_C32(0x5ac80000), SPH_C32(0x56172fe5), SPH_C32(0x1ede776c), + SPH_C32(0x0f07c7e9), SPH_C32(0x21f818ea), SPH_C32(0xb0a50000), + SPH_C32(0x98a200fc), SPH_C32(0xf9d60000), SPH_C32(0xd84f0000), + SPH_C32(0x874b0d24), SPH_C32(0x8ac74bd7), SPH_C32(0x56b7e7e6), + SPH_C32(0x38a23db3) }, + { SPH_C32(0x1fc40000), SPH_C32(0x56c10002), SPH_C32(0xae1ee000), + SPH_C32(0xc29e0000), SPH_C32(0xc37248eb), SPH_C32(0x5056bf86), + SPH_C32(0xdcda8ead), SPH_C32(0x37e5c253), SPH_C32(0x80120000), + SPH_C32(0x7d7200fc), SPH_C32(0x0d226000), SPH_C32(0x9a8b0000), + SPH_C32(0xe4f3304e), SPH_C32(0xf27ddfb7), SPH_C32(0x7718460c), + SPH_C32(0x88072587) }, + { SPH_C32(0xa90a0000), SPH_C32(0x8c280000), SPH_C32(0xbb706000), + SPH_C32(0x180c0000), SPH_C32(0x35af128f), SPH_C32(0x6664e30c), + SPH_C32(0x2ea86603), SPH_C32(0x915d00de), SPH_C32(0x066b0000), + SPH_C32(0x424b00fe), SPH_C32(0xecb88000), SPH_C32(0x02dd0000), + SPH_C32(0x71965740), SPH_C32(0xbcf5175d), SPH_C32(0xa4c50f48), + SPH_C32(0x9e1aff3e) }, + { SPH_C32(0x2f730000), SPH_C32(0xb3110002), SPH_C32(0x5aea8000), + SPH_C32(0x805a0000), SPH_C32(0xa0ca7581), SPH_C32(0x28ec2be6), + SPH_C32(0xfd752f47), SPH_C32(0x8740da67), SPH_C32(0x36dc0000), + SPH_C32(0xa79b00fe), SPH_C32(0x184ce000), SPH_C32(0x40190000), + SPH_C32(0x122e6a2a), SPH_C32(0xc44f833d), SPH_C32(0x856aaea2), + SPH_C32(0x2ebfe70a) }, + { SPH_C32(0x8da40000), SPH_C32(0x4a32003c), SPH_C32(0x1f5b0000), + SPH_C32(0x1e7e0000), SPH_C32(0x4d7b4855), SPH_C32(0x222ddb19), + SPH_C32(0x6ee1d759), SPH_C32(0xfa32c36a), SPH_C32(0x53e60000), + SPH_C32(0xa2ec00e8), SPH_C32(0x0b100000), SPH_C32(0x72010000), + SPH_C32(0x5c554f82), SPH_C32(0xafacf5c2), SPH_C32(0x448a56b0), + SPH_C32(0x02eca464) }, + { SPH_C32(0x0bdd0000), SPH_C32(0x750b003e), SPH_C32(0xfec1e000), + SPH_C32(0x86280000), SPH_C32(0xd81e2f5b), SPH_C32(0x6ca513f3), + SPH_C32(0xbd3c9e1d), SPH_C32(0xec2f19d3), SPH_C32(0x63510000), + SPH_C32(0x473c00e8), SPH_C32(0xffe46000), SPH_C32(0x30c50000), + SPH_C32(0x3fed72e8), SPH_C32(0xd71661a2), SPH_C32(0x6525f75a), + SPH_C32(0xb249bc50) }, + { SPH_C32(0xbd130000), SPH_C32(0xafe2003c), SPH_C32(0xebaf6000), + SPH_C32(0x5cba0000), SPH_C32(0x2ec3753f), SPH_C32(0x5a974f79), + SPH_C32(0x4f4e76b3), SPH_C32(0x4a97db5e), SPH_C32(0xe5280000), + SPH_C32(0x780500ea), SPH_C32(0x1e7e8000), SPH_C32(0xa8930000), + SPH_C32(0xaa8815e6), SPH_C32(0x999ea948), SPH_C32(0xb6f8be1e), + SPH_C32(0xa45466e9) }, + { SPH_C32(0x3b6a0000), SPH_C32(0x90db003e), SPH_C32(0x0a358000), + SPH_C32(0xc4ec0000), SPH_C32(0xbba61231), SPH_C32(0x141f8793), + SPH_C32(0x9c933ff7), SPH_C32(0x5c8a01e7), SPH_C32(0xd59f0000), + SPH_C32(0x9dd500ea), SPH_C32(0xea8ae000), SPH_C32(0xea570000), + SPH_C32(0xc930288c), SPH_C32(0xe1243d28), SPH_C32(0x97571ff4), + SPH_C32(0x14f17edd) }, + { SPH_C32(0x2eae0000), SPH_C32(0x55c70048), SPH_C32(0x98ec0000), + SPH_C32(0x9a980000), SPH_C32(0xa3ac239c), SPH_C32(0x5dfb4c6b), + SPH_C32(0xa2806e7c), SPH_C32(0x65c7dc2a), SPH_C32(0xfb720000), + SPH_C32(0x7d1d00cc), SPH_C32(0x424c0000), SPH_C32(0xe7bc0000), + SPH_C32(0xe92150f6), SPH_C32(0xd1f9c1e1), SPH_C32(0x257e9c37), + SPH_C32(0xf51d2faa) }, + { SPH_C32(0xa8d70000), SPH_C32(0x6afe004a), SPH_C32(0x7976e000), + SPH_C32(0x02ce0000), SPH_C32(0x36c94492), SPH_C32(0x13738481), + SPH_C32(0x715d2738), SPH_C32(0x73da0693), SPH_C32(0xcbc50000), + SPH_C32(0x98cd00cc), SPH_C32(0xb6b86000), SPH_C32(0xa5780000), + SPH_C32(0x8a996d9c), SPH_C32(0xa9435581), SPH_C32(0x04d13ddd), + SPH_C32(0x45b8379e) }, + { SPH_C32(0x1e190000), SPH_C32(0xb0170048), SPH_C32(0x6c186000), + SPH_C32(0xd85c0000), SPH_C32(0xc0141ef6), SPH_C32(0x2541d80b), + SPH_C32(0x832fcf96), SPH_C32(0xd562c41e), SPH_C32(0x4dbc0000), + SPH_C32(0xa7f400ce), SPH_C32(0x57228000), SPH_C32(0x3d2e0000), + SPH_C32(0x1ffc0a92), SPH_C32(0xe7cb9d6b), SPH_C32(0xd70c7499), + SPH_C32(0x53a5ed27) }, + { SPH_C32(0x98600000), SPH_C32(0x8f2e004a), SPH_C32(0x8d828000), + SPH_C32(0x400a0000), SPH_C32(0x557179f8), SPH_C32(0x6bc910e1), + SPH_C32(0x50f286d2), SPH_C32(0xc37f1ea7), SPH_C32(0x7d0b0000), + SPH_C32(0x422400ce), SPH_C32(0xa3d6e000), SPH_C32(0x7fea0000), + SPH_C32(0x7c4437f8), SPH_C32(0x9f71090b), SPH_C32(0xf6a3d573), + SPH_C32(0xe300f513) }, + { SPH_C32(0x3ab70000), SPH_C32(0x760d0074), SPH_C32(0xc8330000), + SPH_C32(0xde2e0000), SPH_C32(0xb8c0442c), SPH_C32(0x6108e01e), + SPH_C32(0xc3667ecc), SPH_C32(0xbe0d07aa), SPH_C32(0x18310000), + SPH_C32(0x475300d8), SPH_C32(0xb08a0000), SPH_C32(0x4df20000), + SPH_C32(0x323f1250), SPH_C32(0xf4927ff4), SPH_C32(0x37432d61), + SPH_C32(0xcf53b67d) }, + { SPH_C32(0xbcce0000), SPH_C32(0x49340076), SPH_C32(0x29a9e000), + SPH_C32(0x46780000), SPH_C32(0x2da52322), SPH_C32(0x2f8028f4), + SPH_C32(0x10bb3788), SPH_C32(0xa810dd13), SPH_C32(0x28860000), + SPH_C32(0xa28300d8), SPH_C32(0x447e6000), SPH_C32(0x0f360000), + SPH_C32(0x51872f3a), SPH_C32(0x8c28eb94), SPH_C32(0x16ec8c8b), + SPH_C32(0x7ff6ae49) }, + { SPH_C32(0x0a000000), SPH_C32(0x93dd0074), SPH_C32(0x3cc76000), + SPH_C32(0x9cea0000), SPH_C32(0xdb787946), SPH_C32(0x19b2747e), + SPH_C32(0xe2c9df26), SPH_C32(0x0ea81f9e), SPH_C32(0xaeff0000), + SPH_C32(0x9dba00da), SPH_C32(0xa5e48000), SPH_C32(0x97600000), + SPH_C32(0xc4e24834), SPH_C32(0xc2a0237e), SPH_C32(0xc531c5cf), + SPH_C32(0x69eb74f0) }, + { SPH_C32(0x8c790000), SPH_C32(0xace40076), SPH_C32(0xdd5d8000), + SPH_C32(0x04bc0000), SPH_C32(0x4e1d1e48), SPH_C32(0x573abc94), + SPH_C32(0x31149662), SPH_C32(0x18b5c527), SPH_C32(0x9e480000), + SPH_C32(0x786a00da), SPH_C32(0x5110e000), SPH_C32(0xd5a40000), + SPH_C32(0xa75a755e), SPH_C32(0xba1ab71e), SPH_C32(0xe49e6425), + SPH_C32(0xd94e6cc4) }, + { SPH_C32(0xcded0000), SPH_C32(0x6f89005c), SPH_C32(0x6a2a0000), + SPH_C32(0x30d60000), SPH_C32(0x78b2613a), SPH_C32(0x7890f27e), + SPH_C32(0xb0bddf2a), SPH_C32(0x5f8945fd), SPH_C32(0x0c280000), + SPH_C32(0x649900e4), SPH_C32(0xe0550000), SPH_C32(0x09440000), + SPH_C32(0x295375e0), SPH_C32(0xc861d381), SPH_C32(0x56a53dd1), + SPH_C32(0x14996dfd) }, + { SPH_C32(0x4b940000), SPH_C32(0x50b0005e), SPH_C32(0x8bb0e000), + SPH_C32(0xa8800000), SPH_C32(0xedd70634), SPH_C32(0x36183a94), + SPH_C32(0x6360966e), SPH_C32(0x49949f44), SPH_C32(0x3c9f0000), + SPH_C32(0x814900e4), SPH_C32(0x14a16000), SPH_C32(0x4b800000), + SPH_C32(0x4aeb488a), SPH_C32(0xb0db47e1), SPH_C32(0x770a9c3b), + SPH_C32(0xa43c75c9) }, + { SPH_C32(0xfd5a0000), SPH_C32(0x8a59005c), SPH_C32(0x9ede6000), + SPH_C32(0x72120000), SPH_C32(0x1b0a5c50), SPH_C32(0x002a661e), + SPH_C32(0x91127ec0), SPH_C32(0xef2c5dc9), SPH_C32(0xbae60000), + SPH_C32(0xbe7000e6), SPH_C32(0xf53b8000), SPH_C32(0xd3d60000), + SPH_C32(0xdf8e2f84), SPH_C32(0xfe538f0b), SPH_C32(0xa4d7d57f), + SPH_C32(0xb221af70) }, + { SPH_C32(0x7b230000), SPH_C32(0xb560005e), SPH_C32(0x7f448000), + SPH_C32(0xea440000), SPH_C32(0x8e6f3b5e), SPH_C32(0x4ea2aef4), + SPH_C32(0x42cf3784), SPH_C32(0xf9318770), SPH_C32(0x8a510000), + SPH_C32(0x5ba000e6), SPH_C32(0x01cfe000), SPH_C32(0x91120000), + SPH_C32(0xbc3612ee), SPH_C32(0x86e91b6b), SPH_C32(0x85787495), + SPH_C32(0x0284b744) }, + { SPH_C32(0xd9f40000), SPH_C32(0x4c430060), SPH_C32(0x3af50000), + SPH_C32(0x74600000), SPH_C32(0x63de068a), SPH_C32(0x44635e0b), + SPH_C32(0xd15bcf9a), SPH_C32(0x84439e7d), SPH_C32(0xef6b0000), + SPH_C32(0x5ed700f0), SPH_C32(0x12930000), SPH_C32(0xa30a0000), + SPH_C32(0xf24d3746), SPH_C32(0xed0a6d94), SPH_C32(0x44988c87), + SPH_C32(0x2ed7f42a) }, + { SPH_C32(0x5f8d0000), SPH_C32(0x737a0062), SPH_C32(0xdb6fe000), + SPH_C32(0xec360000), SPH_C32(0xf6bb6184), SPH_C32(0x0aeb96e1), + SPH_C32(0x028686de), SPH_C32(0x925e44c4), SPH_C32(0xdfdc0000), + SPH_C32(0xbb0700f0), SPH_C32(0xe6676000), SPH_C32(0xe1ce0000), + SPH_C32(0x91f50a2c), SPH_C32(0x95b0f9f4), SPH_C32(0x65372d6d), + SPH_C32(0x9e72ec1e) }, + { SPH_C32(0xe9430000), SPH_C32(0xa9930060), SPH_C32(0xce016000), + SPH_C32(0x36a40000), SPH_C32(0x00663be0), SPH_C32(0x3cd9ca6b), + SPH_C32(0xf0f46e70), SPH_C32(0x34e68649), SPH_C32(0x59a50000), + SPH_C32(0x843e00f2), SPH_C32(0x07fd8000), SPH_C32(0x79980000), + SPH_C32(0x04906d22), SPH_C32(0xdb38311e), SPH_C32(0xb6ea6429), + SPH_C32(0x886f36a7) }, + { SPH_C32(0x6f3a0000), SPH_C32(0x96aa0062), SPH_C32(0x2f9b8000), + SPH_C32(0xaef20000), SPH_C32(0x95035cee), SPH_C32(0x72510281), + SPH_C32(0x23292734), SPH_C32(0x22fb5cf0), SPH_C32(0x69120000), + SPH_C32(0x61ee00f2), SPH_C32(0xf309e000), SPH_C32(0x3b5c0000), + SPH_C32(0x67285048), SPH_C32(0xa382a57e), SPH_C32(0x9745c5c3), + SPH_C32(0x38ca2e93) }, + { SPH_C32(0xaf220000), SPH_C32(0x7b6c0090), SPH_C32(0x67e20000), + SPH_C32(0x8da20000), SPH_C32(0xc7841e29), SPH_C32(0xb7b744f3), + SPH_C32(0x9ac484f4), SPH_C32(0x8b6c72bd), SPH_C32(0x69510000), + SPH_C32(0xd4e1009c), SPH_C32(0xc3230000), SPH_C32(0xac2f0000), + SPH_C32(0xe4950bae), SPH_C32(0xcea415dc), SPH_C32(0x87ec287c), + SPH_C32(0xbce1a3ce) }, + { SPH_C32(0x295b0000), SPH_C32(0x44550092), SPH_C32(0x8678e000), + SPH_C32(0x15f40000), SPH_C32(0x52e17927), SPH_C32(0xf93f8c19), + SPH_C32(0x4919cdb0), SPH_C32(0x9d71a804), SPH_C32(0x59e60000), + SPH_C32(0x3131009c), SPH_C32(0x37d76000), SPH_C32(0xeeeb0000), + SPH_C32(0x872d36c4), SPH_C32(0xb61e81bc), SPH_C32(0xa6438996), + SPH_C32(0x0c44bbfa) }, + { SPH_C32(0x9f950000), SPH_C32(0x9ebc0090), SPH_C32(0x93166000), + SPH_C32(0xcf660000), SPH_C32(0xa43c2343), SPH_C32(0xcf0dd093), + SPH_C32(0xbb6b251e), SPH_C32(0x3bc96a89), SPH_C32(0xdf9f0000), + SPH_C32(0x0e08009e), SPH_C32(0xd64d8000), SPH_C32(0x76bd0000), + SPH_C32(0x124851ca), SPH_C32(0xf8964956), SPH_C32(0x759ec0d2), + SPH_C32(0x1a596143) }, + { SPH_C32(0x19ec0000), SPH_C32(0xa1850092), SPH_C32(0x728c8000), + SPH_C32(0x57300000), SPH_C32(0x3159444d), SPH_C32(0x81851879), + SPH_C32(0x68b66c5a), SPH_C32(0x2dd4b030), SPH_C32(0xef280000), + SPH_C32(0xebd8009e), SPH_C32(0x22b9e000), SPH_C32(0x34790000), + SPH_C32(0x71f06ca0), SPH_C32(0x802cdd36), SPH_C32(0x54316138), + SPH_C32(0xaafc7977) }, + { SPH_C32(0xbb3b0000), SPH_C32(0x58a600ac), SPH_C32(0x373d0000), + SPH_C32(0xc9140000), SPH_C32(0xdce87999), SPH_C32(0x8b44e886), + SPH_C32(0xfb229444), SPH_C32(0x50a6a93d), SPH_C32(0x8a120000), + SPH_C32(0xeeaf0088), SPH_C32(0x31e50000), SPH_C32(0x06610000), + SPH_C32(0x3f8b4908), SPH_C32(0xebcfabc9), SPH_C32(0x95d1992a), + SPH_C32(0x86af3a19) }, + { SPH_C32(0x3d420000), SPH_C32(0x679f00ae), SPH_C32(0xd6a7e000), + SPH_C32(0x51420000), SPH_C32(0x498d1e97), SPH_C32(0xc5cc206c), + SPH_C32(0x28ffdd00), SPH_C32(0x46bb7384), SPH_C32(0xbaa50000), + SPH_C32(0x0b7f0088), SPH_C32(0xc5116000), SPH_C32(0x44a50000), + SPH_C32(0x5c337462), SPH_C32(0x93753fa9), SPH_C32(0xb47e38c0), + SPH_C32(0x360a222d) }, + { SPH_C32(0x8b8c0000), SPH_C32(0xbd7600ac), SPH_C32(0xc3c96000), + SPH_C32(0x8bd00000), SPH_C32(0xbf5044f3), SPH_C32(0xf3fe7ce6), + SPH_C32(0xda8d35ae), SPH_C32(0xe003b109), SPH_C32(0x3cdc0000), + SPH_C32(0x3446008a), SPH_C32(0x248b8000), SPH_C32(0xdcf30000), + SPH_C32(0xc956136c), SPH_C32(0xddfdf743), SPH_C32(0x67a37184), + SPH_C32(0x2017f894) }, + { SPH_C32(0x0df50000), SPH_C32(0x824f00ae), SPH_C32(0x22538000), + SPH_C32(0x13860000), SPH_C32(0x2a3523fd), SPH_C32(0xbd76b40c), + SPH_C32(0x09507cea), SPH_C32(0xf61e6bb0), SPH_C32(0x0c6b0000), + SPH_C32(0xd196008a), SPH_C32(0xd07fe000), SPH_C32(0x9e370000), + SPH_C32(0xaaee2e06), SPH_C32(0xa5476323), SPH_C32(0x460cd06e), + SPH_C32(0x90b2e0a0) }, + { SPH_C32(0x4c610000), SPH_C32(0x41220084), SPH_C32(0x95240000), + SPH_C32(0x27ec0000), SPH_C32(0x1c9a5c8f), SPH_C32(0x92dcfae6), + SPH_C32(0x88f935a2), SPH_C32(0xb122eb6a), SPH_C32(0x9e0b0000), + SPH_C32(0xcd6500b4), SPH_C32(0x613a0000), SPH_C32(0x42d70000), + SPH_C32(0x24e72eb8), SPH_C32(0xd73c07bc), SPH_C32(0xf437899a), + SPH_C32(0x5d65e199) }, + { SPH_C32(0xca180000), SPH_C32(0x7e1b0086), SPH_C32(0x74bee000), + SPH_C32(0xbfba0000), SPH_C32(0x89ff3b81), SPH_C32(0xdc54320c), + SPH_C32(0x5b247ce6), SPH_C32(0xa73f31d3), SPH_C32(0xaebc0000), + SPH_C32(0x28b500b4), SPH_C32(0x95ce6000), SPH_C32(0x00130000), + SPH_C32(0x475f13d2), SPH_C32(0xaf8693dc), SPH_C32(0xd5982870), + SPH_C32(0xedc0f9ad) }, + { SPH_C32(0x7cd60000), SPH_C32(0xa4f20084), SPH_C32(0x61d06000), + SPH_C32(0x65280000), SPH_C32(0x7f2261e5), SPH_C32(0xea666e86), + SPH_C32(0xa9569448), SPH_C32(0x0187f35e), SPH_C32(0x28c50000), + SPH_C32(0x178c00b6), SPH_C32(0x74548000), SPH_C32(0x98450000), + SPH_C32(0xd23a74dc), SPH_C32(0xe10e5b36), SPH_C32(0x06456134), + SPH_C32(0xfbdd2314) }, + { SPH_C32(0xfaaf0000), SPH_C32(0x9bcb0086), SPH_C32(0x804a8000), + SPH_C32(0xfd7e0000), SPH_C32(0xea4706eb), SPH_C32(0xa4eea66c), + SPH_C32(0x7a8bdd0c), SPH_C32(0x179a29e7), SPH_C32(0x18720000), + SPH_C32(0xf25c00b6), SPH_C32(0x80a0e000), SPH_C32(0xda810000), + SPH_C32(0xb18249b6), SPH_C32(0x99b4cf56), SPH_C32(0x27eac0de), + SPH_C32(0x4b783b20) }, + { SPH_C32(0x58780000), SPH_C32(0x62e800b8), SPH_C32(0xc5fb0000), + SPH_C32(0x635a0000), SPH_C32(0x07f63b3f), SPH_C32(0xae2f5693), + SPH_C32(0xe91f2512), SPH_C32(0x6ae830ea), SPH_C32(0x7d480000), + SPH_C32(0xf72b00a0), SPH_C32(0x93fc0000), SPH_C32(0xe8990000), + SPH_C32(0xfff96c1e), SPH_C32(0xf257b9a9), SPH_C32(0xe60a38cc), + SPH_C32(0x672b784e) }, + { SPH_C32(0xde010000), SPH_C32(0x5dd100ba), SPH_C32(0x2461e000), + SPH_C32(0xfb0c0000), SPH_C32(0x92935c31), SPH_C32(0xe0a79e79), + SPH_C32(0x3ac26c56), SPH_C32(0x7cf5ea53), SPH_C32(0x4dff0000), + SPH_C32(0x12fb00a0), SPH_C32(0x67086000), SPH_C32(0xaa5d0000), + SPH_C32(0x9c415174), SPH_C32(0x8aed2dc9), SPH_C32(0xc7a59926), + SPH_C32(0xd78e607a) }, + { SPH_C32(0x68cf0000), SPH_C32(0x873800b8), SPH_C32(0x310f6000), + SPH_C32(0x219e0000), SPH_C32(0x644e0655), SPH_C32(0xd695c2f3), + SPH_C32(0xc8b084f8), SPH_C32(0xda4d28de), SPH_C32(0xcb860000), + SPH_C32(0x2dc200a2), SPH_C32(0x86928000), SPH_C32(0x320b0000), + SPH_C32(0x0924367a), SPH_C32(0xc465e523), SPH_C32(0x1478d062), + SPH_C32(0xc193bac3) }, + { SPH_C32(0xeeb60000), SPH_C32(0xb80100ba), SPH_C32(0xd0958000), + SPH_C32(0xb9c80000), SPH_C32(0xf12b615b), SPH_C32(0x981d0a19), + SPH_C32(0x1b6dcdbc), SPH_C32(0xcc50f267), SPH_C32(0xfb310000), + SPH_C32(0xc81200a2), SPH_C32(0x7266e000), SPH_C32(0x70cf0000), + SPH_C32(0x6a9c0b10), SPH_C32(0xbcdf7143), SPH_C32(0x35d77188), + SPH_C32(0x7136a2f7) }, + { SPH_C32(0xfb720000), SPH_C32(0x7d1d00cc), SPH_C32(0x424c0000), + SPH_C32(0xe7bc0000), SPH_C32(0xe92150f6), SPH_C32(0xd1f9c1e1), + SPH_C32(0x257e9c37), SPH_C32(0xf51d2faa), SPH_C32(0xd5dc0000), + SPH_C32(0x28da0084), SPH_C32(0xdaa00000), SPH_C32(0x7d240000), + SPH_C32(0x4a8d736a), SPH_C32(0x8c028d8a), SPH_C32(0x87fef24b), + SPH_C32(0x90daf380) }, + { SPH_C32(0x7d0b0000), SPH_C32(0x422400ce), SPH_C32(0xa3d6e000), + SPH_C32(0x7fea0000), SPH_C32(0x7c4437f8), SPH_C32(0x9f71090b), + SPH_C32(0xf6a3d573), SPH_C32(0xe300f513), SPH_C32(0xe56b0000), + SPH_C32(0xcd0a0084), SPH_C32(0x2e546000), SPH_C32(0x3fe00000), + SPH_C32(0x29354e00), SPH_C32(0xf4b819ea), SPH_C32(0xa65153a1), + SPH_C32(0x207febb4) }, + { SPH_C32(0xcbc50000), SPH_C32(0x98cd00cc), SPH_C32(0xb6b86000), + SPH_C32(0xa5780000), SPH_C32(0x8a996d9c), SPH_C32(0xa9435581), + SPH_C32(0x04d13ddd), SPH_C32(0x45b8379e), SPH_C32(0x63120000), + SPH_C32(0xf2330086), SPH_C32(0xcfce8000), SPH_C32(0xa7b60000), + SPH_C32(0xbc50290e), SPH_C32(0xba30d100), SPH_C32(0x758c1ae5), + SPH_C32(0x3662310d) }, + { SPH_C32(0x4dbc0000), SPH_C32(0xa7f400ce), SPH_C32(0x57228000), + SPH_C32(0x3d2e0000), SPH_C32(0x1ffc0a92), SPH_C32(0xe7cb9d6b), + SPH_C32(0xd70c7499), SPH_C32(0x53a5ed27), SPH_C32(0x53a50000), + SPH_C32(0x17e30086), SPH_C32(0x3b3ae000), SPH_C32(0xe5720000), + SPH_C32(0xdfe81464), SPH_C32(0xc28a4560), SPH_C32(0x5423bb0f), + SPH_C32(0x86c72939) }, + { SPH_C32(0xef6b0000), SPH_C32(0x5ed700f0), SPH_C32(0x12930000), + SPH_C32(0xa30a0000), SPH_C32(0xf24d3746), SPH_C32(0xed0a6d94), + SPH_C32(0x44988c87), SPH_C32(0x2ed7f42a), SPH_C32(0x369f0000), + SPH_C32(0x12940090), SPH_C32(0x28660000), SPH_C32(0xd76a0000), + SPH_C32(0x919331cc), SPH_C32(0xa969339f), SPH_C32(0x95c3431d), + SPH_C32(0xaa946a57) }, + { SPH_C32(0x69120000), SPH_C32(0x61ee00f2), SPH_C32(0xf309e000), + SPH_C32(0x3b5c0000), SPH_C32(0x67285048), SPH_C32(0xa382a57e), + SPH_C32(0x9745c5c3), SPH_C32(0x38ca2e93), SPH_C32(0x06280000), + SPH_C32(0xf7440090), SPH_C32(0xdc926000), SPH_C32(0x95ae0000), + SPH_C32(0xf22b0ca6), SPH_C32(0xd1d3a7ff), SPH_C32(0xb46ce2f7), + SPH_C32(0x1a317263) }, + { SPH_C32(0xdfdc0000), SPH_C32(0xbb0700f0), SPH_C32(0xe6676000), + SPH_C32(0xe1ce0000), SPH_C32(0x91f50a2c), SPH_C32(0x95b0f9f4), + SPH_C32(0x65372d6d), SPH_C32(0x9e72ec1e), SPH_C32(0x80510000), + SPH_C32(0xc87d0092), SPH_C32(0x3d088000), SPH_C32(0x0df80000), + SPH_C32(0x674e6ba8), SPH_C32(0x9f5b6f15), SPH_C32(0x67b1abb3), + SPH_C32(0x0c2ca8da) }, + { SPH_C32(0x59a50000), SPH_C32(0x843e00f2), SPH_C32(0x07fd8000), + SPH_C32(0x79980000), SPH_C32(0x04906d22), SPH_C32(0xdb38311e), + SPH_C32(0xb6ea6429), SPH_C32(0x886f36a7), SPH_C32(0xb0e60000), + SPH_C32(0x2dad0092), SPH_C32(0xc9fce000), SPH_C32(0x4f3c0000), + SPH_C32(0x04f656c2), SPH_C32(0xe7e1fb75), SPH_C32(0x461e0a59), + SPH_C32(0xbc89b0ee) }, + { SPH_C32(0x18310000), SPH_C32(0x475300d8), SPH_C32(0xb08a0000), + SPH_C32(0x4df20000), SPH_C32(0x323f1250), SPH_C32(0xf4927ff4), + SPH_C32(0x37432d61), SPH_C32(0xcf53b67d), SPH_C32(0x22860000), + SPH_C32(0x315e00ac), SPH_C32(0x78b90000), SPH_C32(0x93dc0000), + SPH_C32(0x8aff567c), SPH_C32(0x959a9fea), SPH_C32(0xf42553ad), + SPH_C32(0x715eb1d7) }, + { SPH_C32(0x9e480000), SPH_C32(0x786a00da), SPH_C32(0x5110e000), + SPH_C32(0xd5a40000), SPH_C32(0xa75a755e), SPH_C32(0xba1ab71e), + SPH_C32(0xe49e6425), SPH_C32(0xd94e6cc4), SPH_C32(0x12310000), + SPH_C32(0xd48e00ac), SPH_C32(0x8c4d6000), SPH_C32(0xd1180000), + SPH_C32(0xe9476b16), SPH_C32(0xed200b8a), SPH_C32(0xd58af247), + SPH_C32(0xc1fba9e3) }, + { SPH_C32(0x28860000), SPH_C32(0xa28300d8), SPH_C32(0x447e6000), + SPH_C32(0x0f360000), SPH_C32(0x51872f3a), SPH_C32(0x8c28eb94), + SPH_C32(0x16ec8c8b), SPH_C32(0x7ff6ae49), SPH_C32(0x94480000), + SPH_C32(0xebb700ae), SPH_C32(0x6dd78000), SPH_C32(0x494e0000), + SPH_C32(0x7c220c18), SPH_C32(0xa3a8c360), SPH_C32(0x0657bb03), + SPH_C32(0xd7e6735a) }, + { SPH_C32(0xaeff0000), SPH_C32(0x9dba00da), SPH_C32(0xa5e48000), + SPH_C32(0x97600000), SPH_C32(0xc4e24834), SPH_C32(0xc2a0237e), + SPH_C32(0xc531c5cf), SPH_C32(0x69eb74f0), SPH_C32(0xa4ff0000), + SPH_C32(0x0e6700ae), SPH_C32(0x9923e000), SPH_C32(0x0b8a0000), + SPH_C32(0x1f9a3172), SPH_C32(0xdb125700), SPH_C32(0x27f81ae9), + SPH_C32(0x67436b6e) }, + { SPH_C32(0x0c280000), SPH_C32(0x649900e4), SPH_C32(0xe0550000), + SPH_C32(0x09440000), SPH_C32(0x295375e0), SPH_C32(0xc861d381), + SPH_C32(0x56a53dd1), SPH_C32(0x14996dfd), SPH_C32(0xc1c50000), + SPH_C32(0x0b1000b8), SPH_C32(0x8a7f0000), SPH_C32(0x39920000), + SPH_C32(0x51e114da), SPH_C32(0xb0f121ff), SPH_C32(0xe618e2fb), + SPH_C32(0x4b102800) }, + { SPH_C32(0x8a510000), SPH_C32(0x5ba000e6), SPH_C32(0x01cfe000), + SPH_C32(0x91120000), SPH_C32(0xbc3612ee), SPH_C32(0x86e91b6b), + SPH_C32(0x85787495), SPH_C32(0x0284b744), SPH_C32(0xf1720000), + SPH_C32(0xeec000b8), SPH_C32(0x7e8b6000), SPH_C32(0x7b560000), + SPH_C32(0x325929b0), SPH_C32(0xc84bb59f), SPH_C32(0xc7b74311), + SPH_C32(0xfbb53034) }, + { SPH_C32(0x3c9f0000), SPH_C32(0x814900e4), SPH_C32(0x14a16000), + SPH_C32(0x4b800000), SPH_C32(0x4aeb488a), SPH_C32(0xb0db47e1), + SPH_C32(0x770a9c3b), SPH_C32(0xa43c75c9), SPH_C32(0x770b0000), + SPH_C32(0xd1f900ba), SPH_C32(0x9f118000), SPH_C32(0xe3000000), + SPH_C32(0xa73c4ebe), SPH_C32(0x86c37d75), SPH_C32(0x146a0a55), + SPH_C32(0xeda8ea8d) }, + { SPH_C32(0xbae60000), SPH_C32(0xbe7000e6), SPH_C32(0xf53b8000), + SPH_C32(0xd3d60000), SPH_C32(0xdf8e2f84), SPH_C32(0xfe538f0b), + SPH_C32(0xa4d7d57f), SPH_C32(0xb221af70), SPH_C32(0x47bc0000), + SPH_C32(0x342900ba), SPH_C32(0x6be5e000), SPH_C32(0xa1c40000), + SPH_C32(0xc48473d4), SPH_C32(0xfe79e915), SPH_C32(0x35c5abbf), + SPH_C32(0x5d0df2b9) }, + { SPH_C32(0x13af0000), SPH_C32(0x87570088), SPH_C32(0x7e610000), + SPH_C32(0x5ca90000), SPH_C32(0x699c66ed), SPH_C32(0xf511dca5), + SPH_C32(0x9ad65ec3), SPH_C32(0xa75722f3), SPH_C32(0x818c0000), + SPH_C32(0x2eab00d8), SPH_C32(0xff0e0000), SPH_C32(0x173a0000), + SPH_C32(0x64283db5), SPH_C32(0xea4c0898), SPH_C32(0x3844ea88), + SPH_C32(0xeeabae97) }, + { SPH_C32(0x95d60000), SPH_C32(0xb86e008a), SPH_C32(0x9ffbe000), + SPH_C32(0xc4ff0000), SPH_C32(0xfcf901e3), SPH_C32(0xbb99144f), + SPH_C32(0x490b1787), SPH_C32(0xb14af84a), SPH_C32(0xb13b0000), + SPH_C32(0xcb7b00d8), SPH_C32(0x0bfa6000), SPH_C32(0x55fe0000), + SPH_C32(0x079000df), SPH_C32(0x92f69cf8), SPH_C32(0x19eb4b62), + SPH_C32(0x5e0eb6a3) }, + { SPH_C32(0x23180000), SPH_C32(0x62870088), SPH_C32(0x8a956000), + SPH_C32(0x1e6d0000), SPH_C32(0x0a245b87), SPH_C32(0x8dab48c5), + SPH_C32(0xbb79ff29), SPH_C32(0x17f23ac7), SPH_C32(0x37420000), + SPH_C32(0xf44200da), SPH_C32(0xea608000), SPH_C32(0xcda80000), + SPH_C32(0x92f567d1), SPH_C32(0xdc7e5412), SPH_C32(0xca360226), + SPH_C32(0x48136c1a) }, + { SPH_C32(0xa5610000), SPH_C32(0x5dbe008a), SPH_C32(0x6b0f8000), + SPH_C32(0x863b0000), SPH_C32(0x9f413c89), SPH_C32(0xc323802f), + SPH_C32(0x68a4b66d), SPH_C32(0x01efe07e), SPH_C32(0x07f50000), + SPH_C32(0x119200da), SPH_C32(0x1e94e000), SPH_C32(0x8f6c0000), + SPH_C32(0xf14d5abb), SPH_C32(0xa4c4c072), SPH_C32(0xeb99a3cc), + SPH_C32(0xf8b6742e) }, + { SPH_C32(0x07b60000), SPH_C32(0xa49d00b4), SPH_C32(0x2ebe0000), + SPH_C32(0x181f0000), SPH_C32(0x72f0015d), SPH_C32(0xc9e270d0), + SPH_C32(0xfb304e73), SPH_C32(0x7c9df973), SPH_C32(0x62cf0000), + SPH_C32(0x14e500cc), SPH_C32(0x0dc80000), SPH_C32(0xbd740000), + SPH_C32(0xbf367f13), SPH_C32(0xcf27b68d), SPH_C32(0x2a795bde), + SPH_C32(0xd4e53740) }, + { SPH_C32(0x81cf0000), SPH_C32(0x9ba400b6), SPH_C32(0xcf24e000), + SPH_C32(0x80490000), SPH_C32(0xe7956653), SPH_C32(0x876ab83a), + SPH_C32(0x28ed0737), SPH_C32(0x6a8023ca), SPH_C32(0x52780000), + SPH_C32(0xf13500cc), SPH_C32(0xf93c6000), SPH_C32(0xffb00000), + SPH_C32(0xdc8e4279), SPH_C32(0xb79d22ed), SPH_C32(0x0bd6fa34), + SPH_C32(0x64402f74) }, + { SPH_C32(0x37010000), SPH_C32(0x414d00b4), SPH_C32(0xda4a6000), + SPH_C32(0x5adb0000), SPH_C32(0x11483c37), SPH_C32(0xb158e4b0), + SPH_C32(0xda9fef99), SPH_C32(0xcc38e147), SPH_C32(0xd4010000), + SPH_C32(0xce0c00ce), SPH_C32(0x18a68000), SPH_C32(0x67e60000), + SPH_C32(0x49eb2577), SPH_C32(0xf915ea07), SPH_C32(0xd80bb370), + SPH_C32(0x725df5cd) }, + { SPH_C32(0xb1780000), SPH_C32(0x7e7400b6), SPH_C32(0x3bd08000), + SPH_C32(0xc28d0000), SPH_C32(0x842d5b39), SPH_C32(0xffd02c5a), + SPH_C32(0x0942a6dd), SPH_C32(0xda253bfe), SPH_C32(0xe4b60000), + SPH_C32(0x2bdc00ce), SPH_C32(0xec52e000), SPH_C32(0x25220000), + SPH_C32(0x2a53181d), SPH_C32(0x81af7e67), SPH_C32(0xf9a4129a), + SPH_C32(0xc2f8edf9) }, + { SPH_C32(0xf0ec0000), SPH_C32(0xbd19009c), SPH_C32(0x8ca70000), + SPH_C32(0xf6e70000), SPH_C32(0xb282244b), SPH_C32(0xd07a62b0), + SPH_C32(0x88ebef95), SPH_C32(0x9d19bb24), SPH_C32(0x76d60000), + SPH_C32(0x372f00f0), SPH_C32(0x5d170000), SPH_C32(0xf9c20000), + SPH_C32(0xa45a18a3), SPH_C32(0xf3d41af8), SPH_C32(0x4b9f4b6e), + SPH_C32(0x0f2fecc0) }, + { SPH_C32(0x76950000), SPH_C32(0x8220009e), SPH_C32(0x6d3de000), + SPH_C32(0x6eb10000), SPH_C32(0x27e74345), SPH_C32(0x9ef2aa5a), + SPH_C32(0x5b36a6d1), SPH_C32(0x8b04619d), SPH_C32(0x46610000), + SPH_C32(0xd2ff00f0), SPH_C32(0xa9e36000), SPH_C32(0xbb060000), + SPH_C32(0xc7e225c9), SPH_C32(0x8b6e8e98), SPH_C32(0x6a30ea84), + SPH_C32(0xbf8af4f4) }, + { SPH_C32(0xc05b0000), SPH_C32(0x58c9009c), SPH_C32(0x78536000), + SPH_C32(0xb4230000), SPH_C32(0xd13a1921), SPH_C32(0xa8c0f6d0), + SPH_C32(0xa9444e7f), SPH_C32(0x2dbca310), SPH_C32(0xc0180000), + SPH_C32(0xedc600f2), SPH_C32(0x48798000), SPH_C32(0x23500000), + SPH_C32(0x528742c7), SPH_C32(0xc5e64672), SPH_C32(0xb9eda3c0), + SPH_C32(0xa9972e4d) }, + { SPH_C32(0x46220000), SPH_C32(0x67f0009e), SPH_C32(0x99c98000), + SPH_C32(0x2c750000), SPH_C32(0x445f7e2f), SPH_C32(0xe6483e3a), + SPH_C32(0x7a99073b), SPH_C32(0x3ba179a9), SPH_C32(0xf0af0000), + SPH_C32(0x081600f2), SPH_C32(0xbc8de000), SPH_C32(0x61940000), + SPH_C32(0x313f7fad), SPH_C32(0xbd5cd212), SPH_C32(0x9842022a), + SPH_C32(0x19323679) }, + { SPH_C32(0xe4f50000), SPH_C32(0x9ed300a0), SPH_C32(0xdc780000), + SPH_C32(0xb2510000), SPH_C32(0xa9ee43fb), SPH_C32(0xec89cec5), + SPH_C32(0xe90dff25), SPH_C32(0x46d360a4), SPH_C32(0x95950000), + SPH_C32(0x0d6100e4), SPH_C32(0xafd10000), SPH_C32(0x538c0000), + SPH_C32(0x7f445a05), SPH_C32(0xd6bfa4ed), SPH_C32(0x59a2fa38), + SPH_C32(0x35617517) }, + { SPH_C32(0x628c0000), SPH_C32(0xa1ea00a2), SPH_C32(0x3de2e000), + SPH_C32(0x2a070000), SPH_C32(0x3c8b24f5), SPH_C32(0xa201062f), + SPH_C32(0x3ad0b661), SPH_C32(0x50ceba1d), SPH_C32(0xa5220000), + SPH_C32(0xe8b100e4), SPH_C32(0x5b256000), SPH_C32(0x11480000), + SPH_C32(0x1cfc676f), SPH_C32(0xae05308d), SPH_C32(0x780d5bd2), + SPH_C32(0x85c46d23) }, + { SPH_C32(0xd4420000), SPH_C32(0x7b0300a0), SPH_C32(0x288c6000), + SPH_C32(0xf0950000), SPH_C32(0xca567e91), SPH_C32(0x94335aa5), + SPH_C32(0xc8a25ecf), SPH_C32(0xf6767890), SPH_C32(0x235b0000), + SPH_C32(0xd78800e6), SPH_C32(0xbabf8000), SPH_C32(0x891e0000), + SPH_C32(0x89990061), SPH_C32(0xe08df867), SPH_C32(0xabd01296), + SPH_C32(0x93d9b79a) }, + { SPH_C32(0x523b0000), SPH_C32(0x443a00a2), SPH_C32(0xc9168000), + SPH_C32(0x68c30000), SPH_C32(0x5f33199f), SPH_C32(0xdabb924f), + SPH_C32(0x1b7f178b), SPH_C32(0xe06ba229), SPH_C32(0x13ec0000), + SPH_C32(0x325800e6), SPH_C32(0x4e4be000), SPH_C32(0xcbda0000), + SPH_C32(0xea213d0b), SPH_C32(0x98376c07), SPH_C32(0x8a7fb37c), + SPH_C32(0x237cafae) }, + { SPH_C32(0x47ff0000), SPH_C32(0x812600d4), SPH_C32(0x5bcf0000), + SPH_C32(0x36b70000), SPH_C32(0x47392832), SPH_C32(0x935f59b7), + SPH_C32(0x256c4600), SPH_C32(0xd9267fe4), SPH_C32(0x3d010000), + SPH_C32(0xd29000c0), SPH_C32(0xe68d0000), SPH_C32(0xc6310000), + SPH_C32(0xca304571), SPH_C32(0xa8ea90ce), SPH_C32(0x385630bf), + SPH_C32(0xc290fed9) }, + { SPH_C32(0xc1860000), SPH_C32(0xbe1f00d6), SPH_C32(0xba55e000), + SPH_C32(0xaee10000), SPH_C32(0xd25c4f3c), SPH_C32(0xddd7915d), + SPH_C32(0xf6b10f44), SPH_C32(0xcf3ba55d), SPH_C32(0x0db60000), + SPH_C32(0x374000c0), SPH_C32(0x12796000), SPH_C32(0x84f50000), + SPH_C32(0xa988781b), SPH_C32(0xd05004ae), SPH_C32(0x19f99155), + SPH_C32(0x7235e6ed) }, + { SPH_C32(0x77480000), SPH_C32(0x64f600d4), SPH_C32(0xaf3b6000), + SPH_C32(0x74730000), SPH_C32(0x24811558), SPH_C32(0xebe5cdd7), + SPH_C32(0x04c3e7ea), SPH_C32(0x698367d0), SPH_C32(0x8bcf0000), + SPH_C32(0x087900c2), SPH_C32(0xf3e38000), SPH_C32(0x1ca30000), + SPH_C32(0x3ced1f15), SPH_C32(0x9ed8cc44), SPH_C32(0xca24d811), + SPH_C32(0x64283c54) }, + { SPH_C32(0xf1310000), SPH_C32(0x5bcf00d6), SPH_C32(0x4ea18000), + SPH_C32(0xec250000), SPH_C32(0xb1e47256), SPH_C32(0xa56d053d), + SPH_C32(0xd71eaeae), SPH_C32(0x7f9ebd69), SPH_C32(0xbb780000), + SPH_C32(0xeda900c2), SPH_C32(0x0717e000), SPH_C32(0x5e670000), + SPH_C32(0x5f55227f), SPH_C32(0xe6625824), SPH_C32(0xeb8b79fb), + SPH_C32(0xd48d2460) }, + { SPH_C32(0x53e60000), SPH_C32(0xa2ec00e8), SPH_C32(0x0b100000), + SPH_C32(0x72010000), SPH_C32(0x5c554f82), SPH_C32(0xafacf5c2), + SPH_C32(0x448a56b0), SPH_C32(0x02eca464), SPH_C32(0xde420000), + SPH_C32(0xe8de00d4), SPH_C32(0x144b0000), SPH_C32(0x6c7f0000), + SPH_C32(0x112e07d7), SPH_C32(0x8d812edb), SPH_C32(0x2a6b81e9), + SPH_C32(0xf8de670e) }, + { SPH_C32(0xd59f0000), SPH_C32(0x9dd500ea), SPH_C32(0xea8ae000), + SPH_C32(0xea570000), SPH_C32(0xc930288c), SPH_C32(0xe1243d28), + SPH_C32(0x97571ff4), SPH_C32(0x14f17edd), SPH_C32(0xeef50000), + SPH_C32(0x0d0e00d4), SPH_C32(0xe0bf6000), SPH_C32(0x2ebb0000), + SPH_C32(0x72963abd), SPH_C32(0xf53bbabb), SPH_C32(0x0bc42003), + SPH_C32(0x487b7f3a) }, + { SPH_C32(0x63510000), SPH_C32(0x473c00e8), SPH_C32(0xffe46000), + SPH_C32(0x30c50000), SPH_C32(0x3fed72e8), SPH_C32(0xd71661a2), + SPH_C32(0x6525f75a), SPH_C32(0xb249bc50), SPH_C32(0x688c0000), + SPH_C32(0x323700d6), SPH_C32(0x01258000), SPH_C32(0xb6ed0000), + SPH_C32(0xe7f35db3), SPH_C32(0xbbb37251), SPH_C32(0xd8196947), + SPH_C32(0x5e66a583) }, + { SPH_C32(0xe5280000), SPH_C32(0x780500ea), SPH_C32(0x1e7e8000), + SPH_C32(0xa8930000), SPH_C32(0xaa8815e6), SPH_C32(0x999ea948), + SPH_C32(0xb6f8be1e), SPH_C32(0xa45466e9), SPH_C32(0x583b0000), + SPH_C32(0xd7e700d6), SPH_C32(0xf5d1e000), SPH_C32(0xf4290000), + SPH_C32(0x844b60d9), SPH_C32(0xc309e631), SPH_C32(0xf9b6c8ad), + SPH_C32(0xeec3bdb7) }, + { SPH_C32(0xa4bc0000), SPH_C32(0xbb6800c0), SPH_C32(0xa9090000), + SPH_C32(0x9cf90000), SPH_C32(0x9c276a94), SPH_C32(0xb634e7a2), + SPH_C32(0x3751f756), SPH_C32(0xe368e633), SPH_C32(0xca5b0000), + SPH_C32(0xcb1400e8), SPH_C32(0x44940000), SPH_C32(0x28c90000), + SPH_C32(0x0a426067), SPH_C32(0xb17282ae), SPH_C32(0x4b8d9159), + SPH_C32(0x2314bc8e) }, + { SPH_C32(0x22c50000), SPH_C32(0x845100c2), SPH_C32(0x4893e000), + SPH_C32(0x04af0000), SPH_C32(0x09420d9a), SPH_C32(0xf8bc2f48), + SPH_C32(0xe48cbe12), SPH_C32(0xf5753c8a), SPH_C32(0xfaec0000), + SPH_C32(0x2ec400e8), SPH_C32(0xb0606000), SPH_C32(0x6a0d0000), + SPH_C32(0x69fa5d0d), SPH_C32(0xc9c816ce), SPH_C32(0x6a2230b3), + SPH_C32(0x93b1a4ba) }, + { SPH_C32(0x940b0000), SPH_C32(0x5eb800c0), SPH_C32(0x5dfd6000), + SPH_C32(0xde3d0000), SPH_C32(0xff9f57fe), SPH_C32(0xce8e73c2), + SPH_C32(0x16fe56bc), SPH_C32(0x53cdfe07), SPH_C32(0x7c950000), + SPH_C32(0x11fd00ea), SPH_C32(0x51fa8000), SPH_C32(0xf25b0000), + SPH_C32(0xfc9f3a03), SPH_C32(0x8740de24), SPH_C32(0xb9ff79f7), + SPH_C32(0x85ac7e03) }, + { SPH_C32(0x12720000), SPH_C32(0x618100c2), SPH_C32(0xbc678000), + SPH_C32(0x466b0000), SPH_C32(0x6afa30f0), SPH_C32(0x8006bb28), + SPH_C32(0xc5231ff8), SPH_C32(0x45d024be), SPH_C32(0x4c220000), + SPH_C32(0xf42d00ea), SPH_C32(0xa50ee000), SPH_C32(0xb09f0000), + SPH_C32(0x9f270769), SPH_C32(0xfffa4a44), SPH_C32(0x9850d81d), + SPH_C32(0x35096637) }, + { SPH_C32(0xb0a50000), SPH_C32(0x98a200fc), SPH_C32(0xf9d60000), + SPH_C32(0xd84f0000), SPH_C32(0x874b0d24), SPH_C32(0x8ac74bd7), + SPH_C32(0x56b7e7e6), SPH_C32(0x38a23db3), SPH_C32(0x29180000), + SPH_C32(0xf15a00fc), SPH_C32(0xb6520000), SPH_C32(0x82870000), + SPH_C32(0xd15c22c1), SPH_C32(0x94193cbb), SPH_C32(0x59b0200f), + SPH_C32(0x195a2559) }, + { SPH_C32(0x36dc0000), SPH_C32(0xa79b00fe), SPH_C32(0x184ce000), + SPH_C32(0x40190000), SPH_C32(0x122e6a2a), SPH_C32(0xc44f833d), + SPH_C32(0x856aaea2), SPH_C32(0x2ebfe70a), SPH_C32(0x19af0000), + SPH_C32(0x148a00fc), SPH_C32(0x42a66000), SPH_C32(0xc0430000), + SPH_C32(0xb2e41fab), SPH_C32(0xeca3a8db), SPH_C32(0x781f81e5), + SPH_C32(0xa9ff3d6d) }, + { SPH_C32(0x80120000), SPH_C32(0x7d7200fc), SPH_C32(0x0d226000), + SPH_C32(0x9a8b0000), SPH_C32(0xe4f3304e), SPH_C32(0xf27ddfb7), + SPH_C32(0x7718460c), SPH_C32(0x88072587), SPH_C32(0x9fd60000), + SPH_C32(0x2bb300fe), SPH_C32(0xa33c8000), SPH_C32(0x58150000), + SPH_C32(0x278178a5), SPH_C32(0xa22b6031), SPH_C32(0xabc2c8a1), + SPH_C32(0xbfe2e7d4) }, + { SPH_C32(0x066b0000), SPH_C32(0x424b00fe), SPH_C32(0xecb88000), + SPH_C32(0x02dd0000), SPH_C32(0x71965740), SPH_C32(0xbcf5175d), + SPH_C32(0xa4c50f48), SPH_C32(0x9e1aff3e), SPH_C32(0xaf610000), + SPH_C32(0xce6300fe), SPH_C32(0x57c8e000), SPH_C32(0x1ad10000), + SPH_C32(0x443945cf), SPH_C32(0xda91f451), SPH_C32(0x8a6d694b), + SPH_C32(0x0f47ffe0) } +}; + +static const sph_u32 T512_32[256][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0xcc140000), SPH_C32(0xa5630000), SPH_C32(0x5ab90780), + SPH_C32(0x3b500000), SPH_C32(0x4bd013ff), SPH_C32(0x879b3418), + SPH_C32(0x694348c1), SPH_C32(0xca5a87fe), SPH_C32(0x819e0000), + SPH_C32(0xec570000), SPH_C32(0x66320280), SPH_C32(0x95f30000), + SPH_C32(0x5da92802), SPH_C32(0x48f43cbc), SPH_C32(0xe65aa22d), + SPH_C32(0x8e67b7fa) }, + { SPH_C32(0x819e0000), SPH_C32(0xec570000), SPH_C32(0x66320280), + SPH_C32(0x95f30000), SPH_C32(0x5da92802), SPH_C32(0x48f43cbc), + SPH_C32(0xe65aa22d), SPH_C32(0x8e67b7fa), SPH_C32(0x4d8a0000), + SPH_C32(0x49340000), SPH_C32(0x3c8b0500), SPH_C32(0xaea30000), + SPH_C32(0x16793bfd), SPH_C32(0xcf6f08a4), SPH_C32(0x8f19eaec), + SPH_C32(0x443d3004) }, + { SPH_C32(0x4d8a0000), SPH_C32(0x49340000), SPH_C32(0x3c8b0500), + SPH_C32(0xaea30000), SPH_C32(0x16793bfd), SPH_C32(0xcf6f08a4), + SPH_C32(0x8f19eaec), SPH_C32(0x443d3004), SPH_C32(0xcc140000), + SPH_C32(0xa5630000), SPH_C32(0x5ab90780), SPH_C32(0x3b500000), + SPH_C32(0x4bd013ff), SPH_C32(0x879b3418), SPH_C32(0x694348c1), + SPH_C32(0xca5a87fe) }, + { SPH_C32(0x78230000), SPH_C32(0x12fc0000), SPH_C32(0xa93a0b80), + SPH_C32(0x90a50000), SPH_C32(0x713e2879), SPH_C32(0x7ee98924), + SPH_C32(0xf08ca062), SPH_C32(0x636f8bab), SPH_C32(0x02af0000), + SPH_C32(0xb7280000), SPH_C32(0xba1c0300), SPH_C32(0x56980000), + SPH_C32(0xba8d45d3), SPH_C32(0x8048c667), SPH_C32(0xa95c149a), + SPH_C32(0xf4f6ea7b) }, + { SPH_C32(0xb4370000), SPH_C32(0xb79f0000), SPH_C32(0xf3830c00), + SPH_C32(0xabf50000), SPH_C32(0x3aee3b86), SPH_C32(0xf972bd3c), + SPH_C32(0x99cfe8a3), SPH_C32(0xa9350c55), SPH_C32(0x83310000), + SPH_C32(0x5b7f0000), SPH_C32(0xdc2e0180), SPH_C32(0xc36b0000), + SPH_C32(0xe7246dd1), SPH_C32(0xc8bcfadb), SPH_C32(0x4f06b6b7), + SPH_C32(0x7a915d81) }, + { SPH_C32(0xf9bd0000), SPH_C32(0xfeab0000), SPH_C32(0xcf080900), + SPH_C32(0x05560000), SPH_C32(0x2c97007b), SPH_C32(0x361db598), + SPH_C32(0x16d6024f), SPH_C32(0xed083c51), SPH_C32(0x4f250000), + SPH_C32(0xfe1c0000), SPH_C32(0x86970600), SPH_C32(0xf83b0000), + SPH_C32(0xacf47e2e), SPH_C32(0x4f27cec3), SPH_C32(0x2645fe76), + SPH_C32(0xb0cbda7f) }, + { SPH_C32(0x35a90000), SPH_C32(0x5bc80000), SPH_C32(0x95b10e80), + SPH_C32(0x3e060000), SPH_C32(0x67471384), SPH_C32(0xb1868180), + SPH_C32(0x7f954a8e), SPH_C32(0x2752bbaf), SPH_C32(0xcebb0000), + SPH_C32(0x124b0000), SPH_C32(0xe0a50480), SPH_C32(0x6dc80000), + SPH_C32(0xf15d562c), SPH_C32(0x07d3f27f), SPH_C32(0xc01f5c5b), + SPH_C32(0x3eac6d85) }, + { SPH_C32(0x02af0000), SPH_C32(0xb7280000), SPH_C32(0xba1c0300), + SPH_C32(0x56980000), SPH_C32(0xba8d45d3), SPH_C32(0x8048c667), + SPH_C32(0xa95c149a), SPH_C32(0xf4f6ea7b), SPH_C32(0x7a8c0000), + SPH_C32(0xa5d40000), SPH_C32(0x13260880), SPH_C32(0xc63d0000), + SPH_C32(0xcbb36daa), SPH_C32(0xfea14f43), SPH_C32(0x59d0b4f8), + SPH_C32(0x979961d0) }, + { SPH_C32(0xcebb0000), SPH_C32(0x124b0000), SPH_C32(0xe0a50480), + SPH_C32(0x6dc80000), SPH_C32(0xf15d562c), SPH_C32(0x07d3f27f), + SPH_C32(0xc01f5c5b), SPH_C32(0x3eac6d85), SPH_C32(0xfb120000), + SPH_C32(0x49830000), SPH_C32(0x75140a00), SPH_C32(0x53ce0000), + SPH_C32(0x961a45a8), SPH_C32(0xb65573ff), SPH_C32(0xbf8a16d5), + SPH_C32(0x19fed62a) }, + { SPH_C32(0x83310000), SPH_C32(0x5b7f0000), SPH_C32(0xdc2e0180), + SPH_C32(0xc36b0000), SPH_C32(0xe7246dd1), SPH_C32(0xc8bcfadb), + SPH_C32(0x4f06b6b7), SPH_C32(0x7a915d81), SPH_C32(0x37060000), + SPH_C32(0xece00000), SPH_C32(0x2fad0d80), SPH_C32(0x689e0000), + SPH_C32(0xddca5657), SPH_C32(0x31ce47e7), SPH_C32(0xd6c95e14), + SPH_C32(0xd3a451d4) }, + { SPH_C32(0x4f250000), SPH_C32(0xfe1c0000), SPH_C32(0x86970600), + SPH_C32(0xf83b0000), SPH_C32(0xacf47e2e), SPH_C32(0x4f27cec3), + SPH_C32(0x2645fe76), SPH_C32(0xb0cbda7f), SPH_C32(0xb6980000), + SPH_C32(0x00b70000), SPH_C32(0x499f0f00), SPH_C32(0xfd6d0000), + SPH_C32(0x80637e55), SPH_C32(0x793a7b5b), SPH_C32(0x3093fc39), + SPH_C32(0x5dc3e62e) }, + { SPH_C32(0x7a8c0000), SPH_C32(0xa5d40000), SPH_C32(0x13260880), + SPH_C32(0xc63d0000), SPH_C32(0xcbb36daa), SPH_C32(0xfea14f43), + SPH_C32(0x59d0b4f8), SPH_C32(0x979961d0), SPH_C32(0x78230000), + SPH_C32(0x12fc0000), SPH_C32(0xa93a0b80), SPH_C32(0x90a50000), + SPH_C32(0x713e2879), SPH_C32(0x7ee98924), SPH_C32(0xf08ca062), + SPH_C32(0x636f8bab) }, + { SPH_C32(0xb6980000), SPH_C32(0x00b70000), SPH_C32(0x499f0f00), + SPH_C32(0xfd6d0000), SPH_C32(0x80637e55), SPH_C32(0x793a7b5b), + SPH_C32(0x3093fc39), SPH_C32(0x5dc3e62e), SPH_C32(0xf9bd0000), + SPH_C32(0xfeab0000), SPH_C32(0xcf080900), SPH_C32(0x05560000), + SPH_C32(0x2c97007b), SPH_C32(0x361db598), SPH_C32(0x16d6024f), + SPH_C32(0xed083c51) }, + { SPH_C32(0xfb120000), SPH_C32(0x49830000), SPH_C32(0x75140a00), + SPH_C32(0x53ce0000), SPH_C32(0x961a45a8), SPH_C32(0xb65573ff), + SPH_C32(0xbf8a16d5), SPH_C32(0x19fed62a), SPH_C32(0x35a90000), + SPH_C32(0x5bc80000), SPH_C32(0x95b10e80), SPH_C32(0x3e060000), + SPH_C32(0x67471384), SPH_C32(0xb1868180), SPH_C32(0x7f954a8e), + SPH_C32(0x2752bbaf) }, + { SPH_C32(0x37060000), SPH_C32(0xece00000), SPH_C32(0x2fad0d80), + SPH_C32(0x689e0000), SPH_C32(0xddca5657), SPH_C32(0x31ce47e7), + SPH_C32(0xd6c95e14), SPH_C32(0xd3a451d4), SPH_C32(0xb4370000), + SPH_C32(0xb79f0000), SPH_C32(0xf3830c00), SPH_C32(0xabf50000), + SPH_C32(0x3aee3b86), SPH_C32(0xf972bd3c), SPH_C32(0x99cfe8a3), + SPH_C32(0xa9350c55) }, + { SPH_C32(0xac480000), SPH_C32(0x1ba60000), SPH_C32(0x45fb1380), + SPH_C32(0x03430000), SPH_C32(0x5a85316a), SPH_C32(0x1fb250b6), + SPH_C32(0xfe72c7fe), SPH_C32(0x91e478f6), SPH_C32(0x1e4e0000), + SPH_C32(0xdecf0000), SPH_C32(0x6df80180), SPH_C32(0x77240000), + SPH_C32(0xec47079e), SPH_C32(0xf4a0694e), SPH_C32(0xcda31812), + SPH_C32(0x98aa496e) }, + { SPH_C32(0x605c0000), SPH_C32(0xbec50000), SPH_C32(0x1f421400), + SPH_C32(0x38130000), SPH_C32(0x11552295), SPH_C32(0x982964ae), + SPH_C32(0x97318f3f), SPH_C32(0x5bbeff08), SPH_C32(0x9fd00000), + SPH_C32(0x32980000), SPH_C32(0x0bca0300), SPH_C32(0xe2d70000), + SPH_C32(0xb1ee2f9c), SPH_C32(0xbc5455f2), SPH_C32(0x2bf9ba3f), + SPH_C32(0x16cdfe94) }, + { SPH_C32(0x2dd60000), SPH_C32(0xf7f10000), SPH_C32(0x23c91100), + SPH_C32(0x96b00000), SPH_C32(0x072c1968), SPH_C32(0x57466c0a), + SPH_C32(0x182865d3), SPH_C32(0x1f83cf0c), SPH_C32(0x53c40000), + SPH_C32(0x97fb0000), SPH_C32(0x51730480), SPH_C32(0xd9870000), + SPH_C32(0xfa3e3c63), SPH_C32(0x3bcf61ea), SPH_C32(0x42baf2fe), + SPH_C32(0xdc97796a) }, + { SPH_C32(0xe1c20000), SPH_C32(0x52920000), SPH_C32(0x79701680), + SPH_C32(0xade00000), SPH_C32(0x4cfc0a97), SPH_C32(0xd0dd5812), + SPH_C32(0x716b2d12), SPH_C32(0xd5d948f2), SPH_C32(0xd25a0000), + SPH_C32(0x7bac0000), SPH_C32(0x37410600), SPH_C32(0x4c740000), + SPH_C32(0xa7971461), SPH_C32(0x733b5d56), SPH_C32(0xa4e050d3), + SPH_C32(0x52f0ce90) }, + { SPH_C32(0xd46b0000), SPH_C32(0x095a0000), SPH_C32(0xecc11800), + SPH_C32(0x93e60000), SPH_C32(0x2bbb1913), SPH_C32(0x615bd992), + SPH_C32(0x0efe679c), SPH_C32(0xf28bf35d), SPH_C32(0x1ce10000), + SPH_C32(0x69e70000), SPH_C32(0xd7e40280), SPH_C32(0x21bc0000), + SPH_C32(0x56ca424d), SPH_C32(0x74e8af29), SPH_C32(0x64ff0c88), + SPH_C32(0x6c5ca315) }, + { SPH_C32(0x187f0000), SPH_C32(0xac390000), SPH_C32(0xb6781f80), + SPH_C32(0xa8b60000), SPH_C32(0x606b0aec), SPH_C32(0xe6c0ed8a), + SPH_C32(0x67bd2f5d), SPH_C32(0x38d174a3), SPH_C32(0x9d7f0000), + SPH_C32(0x85b00000), SPH_C32(0xb1d60000), SPH_C32(0xb44f0000), + SPH_C32(0x0b636a4f), SPH_C32(0x3c1c9395), SPH_C32(0x82a5aea5), + SPH_C32(0xe23b14ef) }, + { SPH_C32(0x55f50000), SPH_C32(0xe50d0000), SPH_C32(0x8af31a80), + SPH_C32(0x06150000), SPH_C32(0x76123111), SPH_C32(0x29afe52e), + SPH_C32(0xe8a4c5b1), SPH_C32(0x7cec44a7), SPH_C32(0x516b0000), + SPH_C32(0x20d30000), SPH_C32(0xeb6f0780), SPH_C32(0x8f1f0000), + SPH_C32(0x40b379b0), SPH_C32(0xbb87a78d), SPH_C32(0xebe6e664), + SPH_C32(0x28619311) }, + { SPH_C32(0x99e10000), SPH_C32(0x406e0000), SPH_C32(0xd04a1d00), + SPH_C32(0x3d450000), SPH_C32(0x3dc222ee), SPH_C32(0xae34d136), + SPH_C32(0x81e78d70), SPH_C32(0xb6b6c359), SPH_C32(0xd0f50000), + SPH_C32(0xcc840000), SPH_C32(0x8d5d0500), SPH_C32(0x1aec0000), + SPH_C32(0x1d1a51b2), SPH_C32(0xf3739b31), SPH_C32(0x0dbc4449), + SPH_C32(0xa60624eb) }, + { SPH_C32(0xaee70000), SPH_C32(0xac8e0000), SPH_C32(0xffe71080), + SPH_C32(0x55db0000), SPH_C32(0xe00874b9), SPH_C32(0x9ffa96d1), + SPH_C32(0x572ed364), SPH_C32(0x6512928d), SPH_C32(0x64c20000), + SPH_C32(0x7b1b0000), SPH_C32(0x7ede0900), SPH_C32(0xb1190000), + SPH_C32(0x27f46a34), SPH_C32(0x0a01260d), SPH_C32(0x9473acea), + SPH_C32(0x0f3328be) }, + { SPH_C32(0x62f30000), SPH_C32(0x09ed0000), SPH_C32(0xa55e1700), + SPH_C32(0x6e8b0000), SPH_C32(0xabd86746), SPH_C32(0x1861a2c9), + SPH_C32(0x3e6d9ba5), SPH_C32(0xaf481573), SPH_C32(0xe55c0000), + SPH_C32(0x974c0000), SPH_C32(0x18ec0b80), SPH_C32(0x24ea0000), + SPH_C32(0x7a5d4236), SPH_C32(0x42f51ab1), SPH_C32(0x72290ec7), + SPH_C32(0x81549f44) }, + { SPH_C32(0x2f790000), SPH_C32(0x40d90000), SPH_C32(0x99d51200), + SPH_C32(0xc0280000), SPH_C32(0xbda15cbb), SPH_C32(0xd70eaa6d), + SPH_C32(0xb1747149), SPH_C32(0xeb752577), SPH_C32(0x29480000), + SPH_C32(0x322f0000), SPH_C32(0x42550c00), SPH_C32(0x1fba0000), + SPH_C32(0x318d51c9), SPH_C32(0xc56e2ea9), SPH_C32(0x1b6a4606), + SPH_C32(0x4b0e18ba) }, + { SPH_C32(0xe36d0000), SPH_C32(0xe5ba0000), SPH_C32(0xc36c1580), + SPH_C32(0xfb780000), SPH_C32(0xf6714f44), SPH_C32(0x50959e75), + SPH_C32(0xd8373988), SPH_C32(0x212fa289), SPH_C32(0xa8d60000), + SPH_C32(0xde780000), SPH_C32(0x24670e80), SPH_C32(0x8a490000), + SPH_C32(0x6c2479cb), SPH_C32(0x8d9a1215), SPH_C32(0xfd30e42b), + SPH_C32(0xc569af40) }, + { SPH_C32(0xd6c40000), SPH_C32(0xbe720000), SPH_C32(0x56dd1b00), + SPH_C32(0xc57e0000), SPH_C32(0x91365cc0), SPH_C32(0xe1131ff5), + SPH_C32(0xa7a27306), SPH_C32(0x067d1926), SPH_C32(0x666d0000), + SPH_C32(0xcc330000), SPH_C32(0xc4c20a00), SPH_C32(0xe7810000), + SPH_C32(0x9d792fe7), SPH_C32(0x8a49e06a), SPH_C32(0x3d2fb870), + SPH_C32(0xfbc5c2c5) }, + { SPH_C32(0x1ad00000), SPH_C32(0x1b110000), SPH_C32(0x0c641c80), + SPH_C32(0xfe2e0000), SPH_C32(0xdae64f3f), SPH_C32(0x66882bed), + SPH_C32(0xcee13bc7), SPH_C32(0xcc279ed8), SPH_C32(0xe7f30000), + SPH_C32(0x20640000), SPH_C32(0xa2f00880), SPH_C32(0x72720000), + SPH_C32(0xc0d007e5), SPH_C32(0xc2bddcd6), SPH_C32(0xdb751a5d), + SPH_C32(0x75a2753f) }, + { SPH_C32(0x575a0000), SPH_C32(0x52250000), SPH_C32(0x30ef1980), + SPH_C32(0x508d0000), SPH_C32(0xcc9f74c2), SPH_C32(0xa9e72349), + SPH_C32(0x41f8d12b), SPH_C32(0x881aaedc), SPH_C32(0x2be70000), + SPH_C32(0x85070000), SPH_C32(0xf8490f00), SPH_C32(0x49220000), + SPH_C32(0x8b00141a), SPH_C32(0x4526e8ce), SPH_C32(0xb236529c), + SPH_C32(0xbff8f2c1) }, + { SPH_C32(0x9b4e0000), SPH_C32(0xf7460000), SPH_C32(0x6a561e00), + SPH_C32(0x6bdd0000), SPH_C32(0x874f673d), SPH_C32(0x2e7c1751), + SPH_C32(0x28bb99ea), SPH_C32(0x42402922), SPH_C32(0xaa790000), + SPH_C32(0x69500000), SPH_C32(0x9e7b0d80), SPH_C32(0xdcd10000), + SPH_C32(0xd6a93c18), SPH_C32(0x0dd2d472), SPH_C32(0x546cf0b1), + SPH_C32(0x319f453b) }, + { SPH_C32(0x1e4e0000), SPH_C32(0xdecf0000), SPH_C32(0x6df80180), + SPH_C32(0x77240000), SPH_C32(0xec47079e), SPH_C32(0xf4a0694e), + SPH_C32(0xcda31812), SPH_C32(0x98aa496e), SPH_C32(0xb2060000), + SPH_C32(0xc5690000), SPH_C32(0x28031200), SPH_C32(0x74670000), + SPH_C32(0xb6c236f4), SPH_C32(0xeb1239f8), SPH_C32(0x33d1dfec), + SPH_C32(0x094e3198) }, + { SPH_C32(0xd25a0000), SPH_C32(0x7bac0000), SPH_C32(0x37410600), + SPH_C32(0x4c740000), SPH_C32(0xa7971461), SPH_C32(0x733b5d56), + SPH_C32(0xa4e050d3), SPH_C32(0x52f0ce90), SPH_C32(0x33980000), + SPH_C32(0x293e0000), SPH_C32(0x4e311080), SPH_C32(0xe1940000), + SPH_C32(0xeb6b1ef6), SPH_C32(0xa3e60544), SPH_C32(0xd58b7dc1), + SPH_C32(0x87298662) }, + { SPH_C32(0x9fd00000), SPH_C32(0x32980000), SPH_C32(0x0bca0300), + SPH_C32(0xe2d70000), SPH_C32(0xb1ee2f9c), SPH_C32(0xbc5455f2), + SPH_C32(0x2bf9ba3f), SPH_C32(0x16cdfe94), SPH_C32(0xff8c0000), + SPH_C32(0x8c5d0000), SPH_C32(0x14881700), SPH_C32(0xdac40000), + SPH_C32(0xa0bb0d09), SPH_C32(0x247d315c), SPH_C32(0xbcc83500), + SPH_C32(0x4d73019c) }, + { SPH_C32(0x53c40000), SPH_C32(0x97fb0000), SPH_C32(0x51730480), + SPH_C32(0xd9870000), SPH_C32(0xfa3e3c63), SPH_C32(0x3bcf61ea), + SPH_C32(0x42baf2fe), SPH_C32(0xdc97796a), SPH_C32(0x7e120000), + SPH_C32(0x600a0000), SPH_C32(0x72ba1580), SPH_C32(0x4f370000), + SPH_C32(0xfd12250b), SPH_C32(0x6c890de0), SPH_C32(0x5a92972d), + SPH_C32(0xc314b666) }, + { SPH_C32(0x666d0000), SPH_C32(0xcc330000), SPH_C32(0xc4c20a00), + SPH_C32(0xe7810000), SPH_C32(0x9d792fe7), SPH_C32(0x8a49e06a), + SPH_C32(0x3d2fb870), SPH_C32(0xfbc5c2c5), SPH_C32(0xb0a90000), + SPH_C32(0x72410000), SPH_C32(0x921f1100), SPH_C32(0x22ff0000), + SPH_C32(0x0c4f7327), SPH_C32(0x6b5aff9f), SPH_C32(0x9a8dcb76), + SPH_C32(0xfdb8dbe3) }, + { SPH_C32(0xaa790000), SPH_C32(0x69500000), SPH_C32(0x9e7b0d80), + SPH_C32(0xdcd10000), SPH_C32(0xd6a93c18), SPH_C32(0x0dd2d472), + SPH_C32(0x546cf0b1), SPH_C32(0x319f453b), SPH_C32(0x31370000), + SPH_C32(0x9e160000), SPH_C32(0xf42d1380), SPH_C32(0xb70c0000), + SPH_C32(0x51e65b25), SPH_C32(0x23aec323), SPH_C32(0x7cd7695b), + SPH_C32(0x73df6c19) }, + { SPH_C32(0xe7f30000), SPH_C32(0x20640000), SPH_C32(0xa2f00880), + SPH_C32(0x72720000), SPH_C32(0xc0d007e5), SPH_C32(0xc2bddcd6), + SPH_C32(0xdb751a5d), SPH_C32(0x75a2753f), SPH_C32(0xfd230000), + SPH_C32(0x3b750000), SPH_C32(0xae941400), SPH_C32(0x8c5c0000), + SPH_C32(0x1a3648da), SPH_C32(0xa435f73b), SPH_C32(0x1594219a), + SPH_C32(0xb985ebe7) }, + { SPH_C32(0x2be70000), SPH_C32(0x85070000), SPH_C32(0xf8490f00), + SPH_C32(0x49220000), SPH_C32(0x8b00141a), SPH_C32(0x4526e8ce), + SPH_C32(0xb236529c), SPH_C32(0xbff8f2c1), SPH_C32(0x7cbd0000), + SPH_C32(0xd7220000), SPH_C32(0xc8a61680), SPH_C32(0x19af0000), + SPH_C32(0x479f60d8), SPH_C32(0xecc1cb87), SPH_C32(0xf3ce83b7), + SPH_C32(0x37e25c1d) }, + { SPH_C32(0x1ce10000), SPH_C32(0x69e70000), SPH_C32(0xd7e40280), + SPH_C32(0x21bc0000), SPH_C32(0x56ca424d), SPH_C32(0x74e8af29), + SPH_C32(0x64ff0c88), SPH_C32(0x6c5ca315), SPH_C32(0xc88a0000), + SPH_C32(0x60bd0000), SPH_C32(0x3b251a80), SPH_C32(0xb25a0000), + SPH_C32(0x7d715b5e), SPH_C32(0x15b376bb), SPH_C32(0x6a016b14), + SPH_C32(0x9ed75048) }, + { SPH_C32(0xd0f50000), SPH_C32(0xcc840000), SPH_C32(0x8d5d0500), + SPH_C32(0x1aec0000), SPH_C32(0x1d1a51b2), SPH_C32(0xf3739b31), + SPH_C32(0x0dbc4449), SPH_C32(0xa60624eb), SPH_C32(0x49140000), + SPH_C32(0x8cea0000), SPH_C32(0x5d171800), SPH_C32(0x27a90000), + SPH_C32(0x20d8735c), SPH_C32(0x5d474a07), SPH_C32(0x8c5bc939), + SPH_C32(0x10b0e7b2) }, + { SPH_C32(0x9d7f0000), SPH_C32(0x85b00000), SPH_C32(0xb1d60000), + SPH_C32(0xb44f0000), SPH_C32(0x0b636a4f), SPH_C32(0x3c1c9395), + SPH_C32(0x82a5aea5), SPH_C32(0xe23b14ef), SPH_C32(0x85000000), + SPH_C32(0x29890000), SPH_C32(0x07ae1f80), SPH_C32(0x1cf90000), + SPH_C32(0x6b0860a3), SPH_C32(0xdadc7e1f), SPH_C32(0xe51881f8), + SPH_C32(0xdaea604c) }, + { SPH_C32(0x516b0000), SPH_C32(0x20d30000), SPH_C32(0xeb6f0780), + SPH_C32(0x8f1f0000), SPH_C32(0x40b379b0), SPH_C32(0xbb87a78d), + SPH_C32(0xebe6e664), SPH_C32(0x28619311), SPH_C32(0x049e0000), + SPH_C32(0xc5de0000), SPH_C32(0x619c1d00), SPH_C32(0x890a0000), + SPH_C32(0x36a148a1), SPH_C32(0x922842a3), SPH_C32(0x034223d5), + SPH_C32(0x548dd7b6) }, + { SPH_C32(0x64c20000), SPH_C32(0x7b1b0000), SPH_C32(0x7ede0900), + SPH_C32(0xb1190000), SPH_C32(0x27f46a34), SPH_C32(0x0a01260d), + SPH_C32(0x9473acea), SPH_C32(0x0f3328be), SPH_C32(0xca250000), + SPH_C32(0xd7950000), SPH_C32(0x81391980), SPH_C32(0xe4c20000), + SPH_C32(0xc7fc1e8d), SPH_C32(0x95fbb0dc), SPH_C32(0xc35d7f8e), + SPH_C32(0x6a21ba33) }, + { SPH_C32(0xa8d60000), SPH_C32(0xde780000), SPH_C32(0x24670e80), + SPH_C32(0x8a490000), SPH_C32(0x6c2479cb), SPH_C32(0x8d9a1215), + SPH_C32(0xfd30e42b), SPH_C32(0xc569af40), SPH_C32(0x4bbb0000), + SPH_C32(0x3bc20000), SPH_C32(0xe70b1b00), SPH_C32(0x71310000), + SPH_C32(0x9a55368f), SPH_C32(0xdd0f8c60), SPH_C32(0x2507dda3), + SPH_C32(0xe4460dc9) }, + { SPH_C32(0xe55c0000), SPH_C32(0x974c0000), SPH_C32(0x18ec0b80), + SPH_C32(0x24ea0000), SPH_C32(0x7a5d4236), SPH_C32(0x42f51ab1), + SPH_C32(0x72290ec7), SPH_C32(0x81549f44), SPH_C32(0x87af0000), + SPH_C32(0x9ea10000), SPH_C32(0xbdb21c80), SPH_C32(0x4a610000), + SPH_C32(0xd1852570), SPH_C32(0x5a94b878), SPH_C32(0x4c449562), + SPH_C32(0x2e1c8a37) }, + { SPH_C32(0x29480000), SPH_C32(0x322f0000), SPH_C32(0x42550c00), + SPH_C32(0x1fba0000), SPH_C32(0x318d51c9), SPH_C32(0xc56e2ea9), + SPH_C32(0x1b6a4606), SPH_C32(0x4b0e18ba), SPH_C32(0x06310000), + SPH_C32(0x72f60000), SPH_C32(0xdb801e00), SPH_C32(0xdf920000), + SPH_C32(0x8c2c0d72), SPH_C32(0x126084c4), SPH_C32(0xaa1e374f), + SPH_C32(0xa07b3dcd) }, + { SPH_C32(0xb2060000), SPH_C32(0xc5690000), SPH_C32(0x28031200), + SPH_C32(0x74670000), SPH_C32(0xb6c236f4), SPH_C32(0xeb1239f8), + SPH_C32(0x33d1dfec), SPH_C32(0x094e3198), SPH_C32(0xac480000), + SPH_C32(0x1ba60000), SPH_C32(0x45fb1380), SPH_C32(0x03430000), + SPH_C32(0x5a85316a), SPH_C32(0x1fb250b6), SPH_C32(0xfe72c7fe), + SPH_C32(0x91e478f6) }, + { SPH_C32(0x7e120000), SPH_C32(0x600a0000), SPH_C32(0x72ba1580), + SPH_C32(0x4f370000), SPH_C32(0xfd12250b), SPH_C32(0x6c890de0), + SPH_C32(0x5a92972d), SPH_C32(0xc314b666), SPH_C32(0x2dd60000), + SPH_C32(0xf7f10000), SPH_C32(0x23c91100), SPH_C32(0x96b00000), + SPH_C32(0x072c1968), SPH_C32(0x57466c0a), SPH_C32(0x182865d3), + SPH_C32(0x1f83cf0c) }, + { SPH_C32(0x33980000), SPH_C32(0x293e0000), SPH_C32(0x4e311080), + SPH_C32(0xe1940000), SPH_C32(0xeb6b1ef6), SPH_C32(0xa3e60544), + SPH_C32(0xd58b7dc1), SPH_C32(0x87298662), SPH_C32(0xe1c20000), + SPH_C32(0x52920000), SPH_C32(0x79701680), SPH_C32(0xade00000), + SPH_C32(0x4cfc0a97), SPH_C32(0xd0dd5812), SPH_C32(0x716b2d12), + SPH_C32(0xd5d948f2) }, + { SPH_C32(0xff8c0000), SPH_C32(0x8c5d0000), SPH_C32(0x14881700), + SPH_C32(0xdac40000), SPH_C32(0xa0bb0d09), SPH_C32(0x247d315c), + SPH_C32(0xbcc83500), SPH_C32(0x4d73019c), SPH_C32(0x605c0000), + SPH_C32(0xbec50000), SPH_C32(0x1f421400), SPH_C32(0x38130000), + SPH_C32(0x11552295), SPH_C32(0x982964ae), SPH_C32(0x97318f3f), + SPH_C32(0x5bbeff08) }, + { SPH_C32(0xca250000), SPH_C32(0xd7950000), SPH_C32(0x81391980), + SPH_C32(0xe4c20000), SPH_C32(0xc7fc1e8d), SPH_C32(0x95fbb0dc), + SPH_C32(0xc35d7f8e), SPH_C32(0x6a21ba33), SPH_C32(0xaee70000), + SPH_C32(0xac8e0000), SPH_C32(0xffe71080), SPH_C32(0x55db0000), + SPH_C32(0xe00874b9), SPH_C32(0x9ffa96d1), SPH_C32(0x572ed364), + SPH_C32(0x6512928d) }, + { SPH_C32(0x06310000), SPH_C32(0x72f60000), SPH_C32(0xdb801e00), + SPH_C32(0xdf920000), SPH_C32(0x8c2c0d72), SPH_C32(0x126084c4), + SPH_C32(0xaa1e374f), SPH_C32(0xa07b3dcd), SPH_C32(0x2f790000), + SPH_C32(0x40d90000), SPH_C32(0x99d51200), SPH_C32(0xc0280000), + SPH_C32(0xbda15cbb), SPH_C32(0xd70eaa6d), SPH_C32(0xb1747149), + SPH_C32(0xeb752577) }, + { SPH_C32(0x4bbb0000), SPH_C32(0x3bc20000), SPH_C32(0xe70b1b00), + SPH_C32(0x71310000), SPH_C32(0x9a55368f), SPH_C32(0xdd0f8c60), + SPH_C32(0x2507dda3), SPH_C32(0xe4460dc9), SPH_C32(0xe36d0000), + SPH_C32(0xe5ba0000), SPH_C32(0xc36c1580), SPH_C32(0xfb780000), + SPH_C32(0xf6714f44), SPH_C32(0x50959e75), SPH_C32(0xd8373988), + SPH_C32(0x212fa289) }, + { SPH_C32(0x87af0000), SPH_C32(0x9ea10000), SPH_C32(0xbdb21c80), + SPH_C32(0x4a610000), SPH_C32(0xd1852570), SPH_C32(0x5a94b878), + SPH_C32(0x4c449562), SPH_C32(0x2e1c8a37), SPH_C32(0x62f30000), + SPH_C32(0x09ed0000), SPH_C32(0xa55e1700), SPH_C32(0x6e8b0000), + SPH_C32(0xabd86746), SPH_C32(0x1861a2c9), SPH_C32(0x3e6d9ba5), + SPH_C32(0xaf481573) }, + { SPH_C32(0xb0a90000), SPH_C32(0x72410000), SPH_C32(0x921f1100), + SPH_C32(0x22ff0000), SPH_C32(0x0c4f7327), SPH_C32(0x6b5aff9f), + SPH_C32(0x9a8dcb76), SPH_C32(0xfdb8dbe3), SPH_C32(0xd6c40000), + SPH_C32(0xbe720000), SPH_C32(0x56dd1b00), SPH_C32(0xc57e0000), + SPH_C32(0x91365cc0), SPH_C32(0xe1131ff5), SPH_C32(0xa7a27306), + SPH_C32(0x067d1926) }, + { SPH_C32(0x7cbd0000), SPH_C32(0xd7220000), SPH_C32(0xc8a61680), + SPH_C32(0x19af0000), SPH_C32(0x479f60d8), SPH_C32(0xecc1cb87), + SPH_C32(0xf3ce83b7), SPH_C32(0x37e25c1d), SPH_C32(0x575a0000), + SPH_C32(0x52250000), SPH_C32(0x30ef1980), SPH_C32(0x508d0000), + SPH_C32(0xcc9f74c2), SPH_C32(0xa9e72349), SPH_C32(0x41f8d12b), + SPH_C32(0x881aaedc) }, + { SPH_C32(0x31370000), SPH_C32(0x9e160000), SPH_C32(0xf42d1380), + SPH_C32(0xb70c0000), SPH_C32(0x51e65b25), SPH_C32(0x23aec323), + SPH_C32(0x7cd7695b), SPH_C32(0x73df6c19), SPH_C32(0x9b4e0000), + SPH_C32(0xf7460000), SPH_C32(0x6a561e00), SPH_C32(0x6bdd0000), + SPH_C32(0x874f673d), SPH_C32(0x2e7c1751), SPH_C32(0x28bb99ea), + SPH_C32(0x42402922) }, + { SPH_C32(0xfd230000), SPH_C32(0x3b750000), SPH_C32(0xae941400), + SPH_C32(0x8c5c0000), SPH_C32(0x1a3648da), SPH_C32(0xa435f73b), + SPH_C32(0x1594219a), SPH_C32(0xb985ebe7), SPH_C32(0x1ad00000), + SPH_C32(0x1b110000), SPH_C32(0x0c641c80), SPH_C32(0xfe2e0000), + SPH_C32(0xdae64f3f), SPH_C32(0x66882bed), SPH_C32(0xcee13bc7), + SPH_C32(0xcc279ed8) }, + { SPH_C32(0xc88a0000), SPH_C32(0x60bd0000), SPH_C32(0x3b251a80), + SPH_C32(0xb25a0000), SPH_C32(0x7d715b5e), SPH_C32(0x15b376bb), + SPH_C32(0x6a016b14), SPH_C32(0x9ed75048), SPH_C32(0xd46b0000), + SPH_C32(0x095a0000), SPH_C32(0xecc11800), SPH_C32(0x93e60000), + SPH_C32(0x2bbb1913), SPH_C32(0x615bd992), SPH_C32(0x0efe679c), + SPH_C32(0xf28bf35d) }, + { SPH_C32(0x049e0000), SPH_C32(0xc5de0000), SPH_C32(0x619c1d00), + SPH_C32(0x890a0000), SPH_C32(0x36a148a1), SPH_C32(0x922842a3), + SPH_C32(0x034223d5), SPH_C32(0x548dd7b6), SPH_C32(0x55f50000), + SPH_C32(0xe50d0000), SPH_C32(0x8af31a80), SPH_C32(0x06150000), + SPH_C32(0x76123111), SPH_C32(0x29afe52e), SPH_C32(0xe8a4c5b1), + SPH_C32(0x7cec44a7) }, + { SPH_C32(0x49140000), SPH_C32(0x8cea0000), SPH_C32(0x5d171800), + SPH_C32(0x27a90000), SPH_C32(0x20d8735c), SPH_C32(0x5d474a07), + SPH_C32(0x8c5bc939), SPH_C32(0x10b0e7b2), SPH_C32(0x99e10000), + SPH_C32(0x406e0000), SPH_C32(0xd04a1d00), SPH_C32(0x3d450000), + SPH_C32(0x3dc222ee), SPH_C32(0xae34d136), SPH_C32(0x81e78d70), + SPH_C32(0xb6b6c359) }, + { SPH_C32(0x85000000), SPH_C32(0x29890000), SPH_C32(0x07ae1f80), + SPH_C32(0x1cf90000), SPH_C32(0x6b0860a3), SPH_C32(0xdadc7e1f), + SPH_C32(0xe51881f8), SPH_C32(0xdaea604c), SPH_C32(0x187f0000), + SPH_C32(0xac390000), SPH_C32(0xb6781f80), SPH_C32(0xa8b60000), + SPH_C32(0x606b0aec), SPH_C32(0xe6c0ed8a), SPH_C32(0x67bd2f5d), + SPH_C32(0x38d174a3) }, + { SPH_C32(0xaec30000), SPH_C32(0x9c4f0001), SPH_C32(0x79d1e000), + SPH_C32(0x2c150000), SPH_C32(0x45cc75b3), SPH_C32(0x6650b736), + SPH_C32(0xab92f78f), SPH_C32(0xa312567b), SPH_C32(0xdb250000), + SPH_C32(0x09290000), SPH_C32(0x49aac000), SPH_C32(0x81e10000), + SPH_C32(0xcafe6b59), SPH_C32(0x42793431), SPH_C32(0x43566b76), + SPH_C32(0xe86cba2e) }, + { SPH_C32(0x62d70000), SPH_C32(0x392c0001), SPH_C32(0x2368e780), + SPH_C32(0x17450000), SPH_C32(0x0e1c664c), SPH_C32(0xe1cb832e), + SPH_C32(0xc2d1bf4e), SPH_C32(0x6948d185), SPH_C32(0x5abb0000), + SPH_C32(0xe57e0000), SPH_C32(0x2f98c280), SPH_C32(0x14120000), + SPH_C32(0x9757435b), SPH_C32(0x0a8d088d), SPH_C32(0xa50cc95b), + SPH_C32(0x660b0dd4) }, + { SPH_C32(0x2f5d0000), SPH_C32(0x70180001), SPH_C32(0x1fe3e280), + SPH_C32(0xb9e60000), SPH_C32(0x18655db1), SPH_C32(0x2ea48b8a), + SPH_C32(0x4dc855a2), SPH_C32(0x2d75e181), SPH_C32(0x96af0000), + SPH_C32(0x401d0000), SPH_C32(0x7521c500), SPH_C32(0x2f420000), + SPH_C32(0xdc8750a4), SPH_C32(0x8d163c95), SPH_C32(0xcc4f819a), + SPH_C32(0xac518a2a) }, + { SPH_C32(0xe3490000), SPH_C32(0xd57b0001), SPH_C32(0x455ae500), + SPH_C32(0x82b60000), SPH_C32(0x53b54e4e), SPH_C32(0xa93fbf92), + SPH_C32(0x248b1d63), SPH_C32(0xe72f667f), SPH_C32(0x17310000), + SPH_C32(0xac4a0000), SPH_C32(0x1313c780), SPH_C32(0xbab10000), + SPH_C32(0x812e78a6), SPH_C32(0xc5e20029), SPH_C32(0x2a1523b7), + SPH_C32(0x22363dd0) }, + { SPH_C32(0xd6e00000), SPH_C32(0x8eb30001), SPH_C32(0xd0ebeb80), + SPH_C32(0xbcb00000), SPH_C32(0x34f25dca), SPH_C32(0x18b93e12), + SPH_C32(0x5b1e57ed), SPH_C32(0xc07dddd0), SPH_C32(0xd98a0000), + SPH_C32(0xbe010000), SPH_C32(0xf3b6c300), SPH_C32(0xd7790000), + SPH_C32(0x70732e8a), SPH_C32(0xc231f256), SPH_C32(0xea0a7fec), + SPH_C32(0x1c9a5055) }, + { SPH_C32(0x1af40000), SPH_C32(0x2bd00001), SPH_C32(0x8a52ec00), + SPH_C32(0x87e00000), SPH_C32(0x7f224e35), SPH_C32(0x9f220a0a), + SPH_C32(0x325d1f2c), SPH_C32(0x0a275a2e), SPH_C32(0x58140000), + SPH_C32(0x52560000), SPH_C32(0x9584c180), SPH_C32(0x428a0000), + SPH_C32(0x2dda0688), SPH_C32(0x8ac5ceea), SPH_C32(0x0c50ddc1), + SPH_C32(0x92fde7af) }, + { SPH_C32(0x577e0000), SPH_C32(0x62e40001), SPH_C32(0xb6d9e900), + SPH_C32(0x29430000), SPH_C32(0x695b75c8), SPH_C32(0x504d02ae), + SPH_C32(0xbd44f5c0), SPH_C32(0x4e1a6a2a), SPH_C32(0x94000000), + SPH_C32(0xf7350000), SPH_C32(0xcf3dc600), SPH_C32(0x79da0000), + SPH_C32(0x660a1577), SPH_C32(0x0d5efaf2), SPH_C32(0x65139500), + SPH_C32(0x58a76051) }, + { SPH_C32(0x9b6a0000), SPH_C32(0xc7870001), SPH_C32(0xec60ee80), + SPH_C32(0x12130000), SPH_C32(0x228b6637), SPH_C32(0xd7d636b6), + SPH_C32(0xd407bd01), SPH_C32(0x8440edd4), SPH_C32(0x159e0000), + SPH_C32(0x1b620000), SPH_C32(0xa90fc480), SPH_C32(0xec290000), + SPH_C32(0x3ba33d75), SPH_C32(0x45aac64e), SPH_C32(0x8349372d), + SPH_C32(0xd6c0d7ab) }, + { SPH_C32(0xac6c0000), SPH_C32(0x2b670001), SPH_C32(0xc3cde300), + SPH_C32(0x7a8d0000), SPH_C32(0xff413060), SPH_C32(0xe6187151), + SPH_C32(0x02cee315), SPH_C32(0x57e4bc00), SPH_C32(0xa1a90000), + SPH_C32(0xacfd0000), SPH_C32(0x5a8cc880), SPH_C32(0x47dc0000), + SPH_C32(0x014d06f3), SPH_C32(0xbcd87b72), SPH_C32(0x1a86df8e), + SPH_C32(0x7ff5dbfe) }, + { SPH_C32(0x60780000), SPH_C32(0x8e040001), SPH_C32(0x9974e480), + SPH_C32(0x41dd0000), SPH_C32(0xb491239f), SPH_C32(0x61834549), + SPH_C32(0x6b8dabd4), SPH_C32(0x9dbe3bfe), SPH_C32(0x20370000), + SPH_C32(0x40aa0000), SPH_C32(0x3cbeca00), SPH_C32(0xd22f0000), + SPH_C32(0x5ce42ef1), SPH_C32(0xf42c47ce), SPH_C32(0xfcdc7da3), + SPH_C32(0xf1926c04) }, + { SPH_C32(0x2df20000), SPH_C32(0xc7300001), SPH_C32(0xa5ffe180), + SPH_C32(0xef7e0000), SPH_C32(0xa2e81862), SPH_C32(0xaeec4ded), + SPH_C32(0xe4944138), SPH_C32(0xd9830bfa), SPH_C32(0xec230000), + SPH_C32(0xe5c90000), SPH_C32(0x6607cd80), SPH_C32(0xe97f0000), + SPH_C32(0x17343d0e), SPH_C32(0x73b773d6), SPH_C32(0x959f3562), + SPH_C32(0x3bc8ebfa) }, + { SPH_C32(0xe1e60000), SPH_C32(0x62530001), SPH_C32(0xff46e600), + SPH_C32(0xd42e0000), SPH_C32(0xe9380b9d), SPH_C32(0x297779f5), + SPH_C32(0x8dd709f9), SPH_C32(0x13d98c04), SPH_C32(0x6dbd0000), + SPH_C32(0x099e0000), SPH_C32(0x0035cf00), SPH_C32(0x7c8c0000), + SPH_C32(0x4a9d150c), SPH_C32(0x3b434f6a), SPH_C32(0x73c5974f), + SPH_C32(0xb5af5c00) }, + { SPH_C32(0xd44f0000), SPH_C32(0x399b0001), SPH_C32(0x6af7e880), + SPH_C32(0xea280000), SPH_C32(0x8e7f1819), SPH_C32(0x98f1f875), + SPH_C32(0xf2424377), SPH_C32(0x348b37ab), SPH_C32(0xa3060000), + SPH_C32(0x1bd50000), SPH_C32(0xe090cb80), SPH_C32(0x11440000), + SPH_C32(0xbbc04320), SPH_C32(0x3c90bd15), SPH_C32(0xb3dacb14), + SPH_C32(0x8b033185) }, + { SPH_C32(0x185b0000), SPH_C32(0x9cf80001), SPH_C32(0x304eef00), + SPH_C32(0xd1780000), SPH_C32(0xc5af0be6), SPH_C32(0x1f6acc6d), + SPH_C32(0x9b010bb6), SPH_C32(0xfed1b055), SPH_C32(0x22980000), + SPH_C32(0xf7820000), SPH_C32(0x86a2c900), SPH_C32(0x84b70000), + SPH_C32(0xe6696b22), SPH_C32(0x746481a9), SPH_C32(0x55806939), + SPH_C32(0x0564867f) }, + { SPH_C32(0x55d10000), SPH_C32(0xd5cc0001), SPH_C32(0x0cc5ea00), + SPH_C32(0x7fdb0000), SPH_C32(0xd3d6301b), SPH_C32(0xd005c4c9), + SPH_C32(0x1418e15a), SPH_C32(0xbaec8051), SPH_C32(0xee8c0000), + SPH_C32(0x52e10000), SPH_C32(0xdc1bce80), SPH_C32(0xbfe70000), + SPH_C32(0xadb978dd), SPH_C32(0xf3ffb5b1), SPH_C32(0x3cc321f8), + SPH_C32(0xcf3e0181) }, + { SPH_C32(0x99c50000), SPH_C32(0x70af0001), SPH_C32(0x567ced80), + SPH_C32(0x448b0000), SPH_C32(0x980623e4), SPH_C32(0x579ef0d1), + SPH_C32(0x7d5ba99b), SPH_C32(0x70b607af), SPH_C32(0x6f120000), + SPH_C32(0xbeb60000), SPH_C32(0xba29cc00), SPH_C32(0x2a140000), + SPH_C32(0xf01050df), SPH_C32(0xbb0b890d), SPH_C32(0xda9983d5), + SPH_C32(0x4159b67b) }, + { SPH_C32(0x028b0000), SPH_C32(0x87e90001), SPH_C32(0x3c2af380), + SPH_C32(0x2f560000), SPH_C32(0x1f4944d9), SPH_C32(0x79e2e780), + SPH_C32(0x55e03071), SPH_C32(0x32f62e8d), SPH_C32(0xc56b0000), + SPH_C32(0xd7e60000), SPH_C32(0x2452c180), SPH_C32(0xf6c50000), + SPH_C32(0x26b96cc7), SPH_C32(0xb6d95d7f), SPH_C32(0x8ef57364), + SPH_C32(0x70c6f340) }, + { SPH_C32(0xce9f0000), SPH_C32(0x228a0001), SPH_C32(0x6693f400), + SPH_C32(0x14060000), SPH_C32(0x54995726), SPH_C32(0xfe79d398), + SPH_C32(0x3ca378b0), SPH_C32(0xf8aca973), SPH_C32(0x44f50000), + SPH_C32(0x3bb10000), SPH_C32(0x4260c300), SPH_C32(0x63360000), + SPH_C32(0x7b1044c5), SPH_C32(0xfe2d61c3), SPH_C32(0x68afd149), + SPH_C32(0xfea144ba) }, + { SPH_C32(0x83150000), SPH_C32(0x6bbe0001), SPH_C32(0x5a18f100), + SPH_C32(0xbaa50000), SPH_C32(0x42e06cdb), SPH_C32(0x3116db3c), + SPH_C32(0xb3ba925c), SPH_C32(0xbc919977), SPH_C32(0x88e10000), + SPH_C32(0x9ed20000), SPH_C32(0x18d9c480), SPH_C32(0x58660000), + SPH_C32(0x30c0573a), SPH_C32(0x79b655db), SPH_C32(0x01ec9988), + SPH_C32(0x34fbc344) }, + { SPH_C32(0x4f010000), SPH_C32(0xcedd0001), SPH_C32(0x00a1f680), + SPH_C32(0x81f50000), SPH_C32(0x09307f24), SPH_C32(0xb68def24), + SPH_C32(0xdaf9da9d), SPH_C32(0x76cb1e89), SPH_C32(0x097f0000), + SPH_C32(0x72850000), SPH_C32(0x7eebc600), SPH_C32(0xcd950000), + SPH_C32(0x6d697f38), SPH_C32(0x31426967), SPH_C32(0xe7b63ba5), + SPH_C32(0xba9c74be) }, + { SPH_C32(0x7aa80000), SPH_C32(0x95150001), SPH_C32(0x9510f800), + SPH_C32(0xbff30000), SPH_C32(0x6e776ca0), SPH_C32(0x070b6ea4), + SPH_C32(0xa56c9013), SPH_C32(0x5199a526), SPH_C32(0xc7c40000), + SPH_C32(0x60ce0000), SPH_C32(0x9e4ec280), SPH_C32(0xa05d0000), + SPH_C32(0x9c342914), SPH_C32(0x36919b18), SPH_C32(0x27a967fe), + SPH_C32(0x8430193b) }, + { SPH_C32(0xb6bc0000), SPH_C32(0x30760001), SPH_C32(0xcfa9ff80), + SPH_C32(0x84a30000), SPH_C32(0x25a77f5f), SPH_C32(0x80905abc), + SPH_C32(0xcc2fd8d2), SPH_C32(0x9bc322d8), SPH_C32(0x465a0000), + SPH_C32(0x8c990000), SPH_C32(0xf87cc000), SPH_C32(0x35ae0000), + SPH_C32(0xc19d0116), SPH_C32(0x7e65a7a4), SPH_C32(0xc1f3c5d3), + SPH_C32(0x0a57aec1) }, + { SPH_C32(0xfb360000), SPH_C32(0x79420001), SPH_C32(0xf322fa80), + SPH_C32(0x2a000000), SPH_C32(0x33de44a2), SPH_C32(0x4fff5218), + SPH_C32(0x4336323e), SPH_C32(0xdffe12dc), SPH_C32(0x8a4e0000), + SPH_C32(0x29fa0000), SPH_C32(0xa2c5c780), SPH_C32(0x0efe0000), + SPH_C32(0x8a4d12e9), SPH_C32(0xf9fe93bc), SPH_C32(0xa8b08d12), + SPH_C32(0xc00d293f) }, + { SPH_C32(0x37220000), SPH_C32(0xdc210001), SPH_C32(0xa99bfd00), + SPH_C32(0x11500000), SPH_C32(0x780e575d), SPH_C32(0xc8646600), + SPH_C32(0x2a757aff), SPH_C32(0x15a49522), SPH_C32(0x0bd00000), + SPH_C32(0xc5ad0000), SPH_C32(0xc4f7c500), SPH_C32(0x9b0d0000), + SPH_C32(0xd7e43aeb), SPH_C32(0xb10aaf00), SPH_C32(0x4eea2f3f), + SPH_C32(0x4e6a9ec5) }, + { SPH_C32(0x00240000), SPH_C32(0x30c10001), SPH_C32(0x8636f080), + SPH_C32(0x79ce0000), SPH_C32(0xa5c4010a), SPH_C32(0xf9aa21e7), + SPH_C32(0xfcbc24eb), SPH_C32(0xc600c4f6), SPH_C32(0xbfe70000), + SPH_C32(0x72320000), SPH_C32(0x3774c900), SPH_C32(0x30f80000), + SPH_C32(0xed0a016d), SPH_C32(0x4878123c), SPH_C32(0xd725c79c), + SPH_C32(0xe75f9290) }, + { SPH_C32(0xcc300000), SPH_C32(0x95a20001), SPH_C32(0xdc8ff700), + SPH_C32(0x429e0000), SPH_C32(0xee1412f5), SPH_C32(0x7e3115ff), + SPH_C32(0x95ff6c2a), SPH_C32(0x0c5a4308), SPH_C32(0x3e790000), + SPH_C32(0x9e650000), SPH_C32(0x5146cb80), SPH_C32(0xa50b0000), + SPH_C32(0xb0a3296f), SPH_C32(0x008c2e80), SPH_C32(0x317f65b1), + SPH_C32(0x6938256a) }, + { SPH_C32(0x81ba0000), SPH_C32(0xdc960001), SPH_C32(0xe004f200), + SPH_C32(0xec3d0000), SPH_C32(0xf86d2908), SPH_C32(0xb15e1d5b), + SPH_C32(0x1ae686c6), SPH_C32(0x4867730c), SPH_C32(0xf26d0000), + SPH_C32(0x3b060000), SPH_C32(0x0bffcc00), SPH_C32(0x9e5b0000), + SPH_C32(0xfb733a90), SPH_C32(0x87171a98), SPH_C32(0x583c2d70), + SPH_C32(0xa362a294) }, + { SPH_C32(0x4dae0000), SPH_C32(0x79f50001), SPH_C32(0xbabdf580), + SPH_C32(0xd76d0000), SPH_C32(0xb3bd3af7), SPH_C32(0x36c52943), + SPH_C32(0x73a5ce07), SPH_C32(0x823df4f2), SPH_C32(0x73f30000), + SPH_C32(0xd7510000), SPH_C32(0x6dcdce80), SPH_C32(0x0ba80000), + SPH_C32(0xa6da1292), SPH_C32(0xcfe32624), SPH_C32(0xbe668f5d), + SPH_C32(0x2d05156e) }, + { SPH_C32(0x78070000), SPH_C32(0x223d0001), SPH_C32(0x2f0cfb00), + SPH_C32(0xe96b0000), SPH_C32(0xd4fa2973), SPH_C32(0x8743a8c3), + SPH_C32(0x0c308489), SPH_C32(0xa56f4f5d), SPH_C32(0xbd480000), + SPH_C32(0xc51a0000), SPH_C32(0x8d68ca00), SPH_C32(0x66600000), + SPH_C32(0x578744be), SPH_C32(0xc830d45b), SPH_C32(0x7e79d306), + SPH_C32(0x13a978eb) }, + { SPH_C32(0xb4130000), SPH_C32(0x875e0001), SPH_C32(0x75b5fc80), + SPH_C32(0xd23b0000), SPH_C32(0x9f2a3a8c), SPH_C32(0x00d89cdb), + SPH_C32(0x6573cc48), SPH_C32(0x6f35c8a3), SPH_C32(0x3cd60000), + SPH_C32(0x294d0000), SPH_C32(0xeb5ac880), SPH_C32(0xf3930000), + SPH_C32(0x0a2e6cbc), SPH_C32(0x80c4e8e7), SPH_C32(0x9823712b), + SPH_C32(0x9dcecf11) }, + { SPH_C32(0xf9990000), SPH_C32(0xce6a0001), SPH_C32(0x493ef980), + SPH_C32(0x7c980000), SPH_C32(0x89530171), SPH_C32(0xcfb7947f), + SPH_C32(0xea6a26a4), SPH_C32(0x2b08f8a7), SPH_C32(0xf0c20000), + SPH_C32(0x8c2e0000), SPH_C32(0xb1e3cf00), SPH_C32(0xc8c30000), + SPH_C32(0x41fe7f43), SPH_C32(0x075fdcff), SPH_C32(0xf16039ea), + SPH_C32(0x579448ef) }, + { SPH_C32(0x358d0000), SPH_C32(0x6b090001), SPH_C32(0x1387fe00), + SPH_C32(0x47c80000), SPH_C32(0xc283128e), SPH_C32(0x482ca067), + SPH_C32(0x83296e65), SPH_C32(0xe1527f59), SPH_C32(0x715c0000), + SPH_C32(0x60790000), SPH_C32(0xd7d1cd80), SPH_C32(0x5d300000), + SPH_C32(0x1c575741), SPH_C32(0x4fabe043), SPH_C32(0x173a9bc7), + SPH_C32(0xd9f3ff15) }, + { SPH_C32(0xb08d0000), SPH_C32(0x42800001), SPH_C32(0x1429e180), + SPH_C32(0x5b310000), SPH_C32(0xa98b722d), SPH_C32(0x92f0de78), + SPH_C32(0x6631ef9d), SPH_C32(0x3bb81f15), SPH_C32(0x69230000), + SPH_C32(0xcc400000), SPH_C32(0x61a9d200), SPH_C32(0xf5860000), + SPH_C32(0x7c3c5dad), SPH_C32(0xa96b0dc9), SPH_C32(0x7087b49a), + SPH_C32(0xe1228bb6) }, + { SPH_C32(0x7c990000), SPH_C32(0xe7e30001), SPH_C32(0x4e90e600), + SPH_C32(0x60610000), SPH_C32(0xe25b61d2), SPH_C32(0x156bea60), + SPH_C32(0x0f72a75c), SPH_C32(0xf1e298eb), SPH_C32(0xe8bd0000), + SPH_C32(0x20170000), SPH_C32(0x079bd080), SPH_C32(0x60750000), + SPH_C32(0x219575af), SPH_C32(0xe19f3175), SPH_C32(0x96dd16b7), + SPH_C32(0x6f453c4c) }, + { SPH_C32(0x31130000), SPH_C32(0xaed70001), SPH_C32(0x721be300), + SPH_C32(0xcec20000), SPH_C32(0xf4225a2f), SPH_C32(0xda04e2c4), + SPH_C32(0x806b4db0), SPH_C32(0xb5dfa8ef), SPH_C32(0x24a90000), + SPH_C32(0x85740000), SPH_C32(0x5d22d700), SPH_C32(0x5b250000), + SPH_C32(0x6a456650), SPH_C32(0x6604056d), SPH_C32(0xff9e5e76), + SPH_C32(0xa51fbbb2) }, + { SPH_C32(0xfd070000), SPH_C32(0x0bb40001), SPH_C32(0x28a2e480), + SPH_C32(0xf5920000), SPH_C32(0xbff249d0), SPH_C32(0x5d9fd6dc), + SPH_C32(0xe9280571), SPH_C32(0x7f852f11), SPH_C32(0xa5370000), + SPH_C32(0x69230000), SPH_C32(0x3b10d580), SPH_C32(0xced60000), + SPH_C32(0x37ec4e52), SPH_C32(0x2ef039d1), SPH_C32(0x19c4fc5b), + SPH_C32(0x2b780c48) }, + { SPH_C32(0xc8ae0000), SPH_C32(0x507c0001), SPH_C32(0xbd13ea00), + SPH_C32(0xcb940000), SPH_C32(0xd8b55a54), SPH_C32(0xec19575c), + SPH_C32(0x96bd4fff), SPH_C32(0x58d794be), SPH_C32(0x6b8c0000), + SPH_C32(0x7b680000), SPH_C32(0xdbb5d100), SPH_C32(0xa31e0000), + SPH_C32(0xc6b1187e), SPH_C32(0x2923cbae), SPH_C32(0xd9dba000), + SPH_C32(0x15d461cd) }, + { SPH_C32(0x04ba0000), SPH_C32(0xf51f0001), SPH_C32(0xe7aaed80), + SPH_C32(0xf0c40000), SPH_C32(0x936549ab), SPH_C32(0x6b826344), + SPH_C32(0xfffe073e), SPH_C32(0x928d1340), SPH_C32(0xea120000), + SPH_C32(0x973f0000), SPH_C32(0xbd87d380), SPH_C32(0x36ed0000), + SPH_C32(0x9b18307c), SPH_C32(0x61d7f712), SPH_C32(0x3f81022d), + SPH_C32(0x9bb3d637) }, + { SPH_C32(0x49300000), SPH_C32(0xbc2b0001), SPH_C32(0xdb21e880), + SPH_C32(0x5e670000), SPH_C32(0x851c7256), SPH_C32(0xa4ed6be0), + SPH_C32(0x70e7edd2), SPH_C32(0xd6b02344), SPH_C32(0x26060000), + SPH_C32(0x325c0000), SPH_C32(0xe73ed400), SPH_C32(0x0dbd0000), + SPH_C32(0xd0c82383), SPH_C32(0xe64cc30a), SPH_C32(0x56c24aec), + SPH_C32(0x51e951c9) }, + { SPH_C32(0x85240000), SPH_C32(0x19480001), SPH_C32(0x8198ef00), + SPH_C32(0x65370000), SPH_C32(0xcecc61a9), SPH_C32(0x23765ff8), + SPH_C32(0x19a4a513), SPH_C32(0x1ceaa4ba), SPH_C32(0xa7980000), + SPH_C32(0xde0b0000), SPH_C32(0x810cd680), SPH_C32(0x984e0000), + SPH_C32(0x8d610b81), SPH_C32(0xaeb8ffb6), SPH_C32(0xb098e8c1), + SPH_C32(0xdf8ee633) }, + { SPH_C32(0xb2220000), SPH_C32(0xf5a80001), SPH_C32(0xae35e280), + SPH_C32(0x0da90000), SPH_C32(0x130637fe), SPH_C32(0x12b8181f), + SPH_C32(0xcf6dfb07), SPH_C32(0xcf4ef56e), SPH_C32(0x13af0000), + SPH_C32(0x69940000), SPH_C32(0x728fda80), SPH_C32(0x33bb0000), + SPH_C32(0xb78f3007), SPH_C32(0x57ca428a), SPH_C32(0x29570062), + SPH_C32(0x76bbea66) }, + { SPH_C32(0x7e360000), SPH_C32(0x50cb0001), SPH_C32(0xf48ce500), + SPH_C32(0x36f90000), SPH_C32(0x58d62401), SPH_C32(0x95232c07), + SPH_C32(0xa62eb3c6), SPH_C32(0x05147290), SPH_C32(0x92310000), + SPH_C32(0x85c30000), SPH_C32(0x14bdd800), SPH_C32(0xa6480000), + SPH_C32(0xea261805), SPH_C32(0x1f3e7e36), SPH_C32(0xcf0da24f), + SPH_C32(0xf8dc5d9c) }, + { SPH_C32(0x33bc0000), SPH_C32(0x19ff0001), SPH_C32(0xc807e000), + SPH_C32(0x985a0000), SPH_C32(0x4eaf1ffc), SPH_C32(0x5a4c24a3), + SPH_C32(0x2937592a), SPH_C32(0x41294294), SPH_C32(0x5e250000), + SPH_C32(0x20a00000), SPH_C32(0x4e04df80), SPH_C32(0x9d180000), + SPH_C32(0xa1f60bfa), SPH_C32(0x98a54a2e), SPH_C32(0xa64eea8e), + SPH_C32(0x3286da62) }, + { SPH_C32(0xffa80000), SPH_C32(0xbc9c0001), SPH_C32(0x92bee780), + SPH_C32(0xa30a0000), SPH_C32(0x057f0c03), SPH_C32(0xddd710bb), + SPH_C32(0x407411eb), SPH_C32(0x8b73c56a), SPH_C32(0xdfbb0000), + SPH_C32(0xccf70000), SPH_C32(0x2836dd00), SPH_C32(0x08eb0000), + SPH_C32(0xfc5f23f8), SPH_C32(0xd0517692), SPH_C32(0x401448a3), + SPH_C32(0xbce16d98) }, + { SPH_C32(0xca010000), SPH_C32(0xe7540001), SPH_C32(0x070fe900), + SPH_C32(0x9d0c0000), SPH_C32(0x62381f87), SPH_C32(0x6c51913b), + SPH_C32(0x3fe15b65), SPH_C32(0xac217ec5), SPH_C32(0x11000000), + SPH_C32(0xdebc0000), SPH_C32(0xc893d980), SPH_C32(0x65230000), + SPH_C32(0x0d0275d4), SPH_C32(0xd78284ed), SPH_C32(0x800b14f8), + SPH_C32(0x824d001d) }, + { SPH_C32(0x06150000), SPH_C32(0x42370001), SPH_C32(0x5db6ee80), + SPH_C32(0xa65c0000), SPH_C32(0x29e80c78), SPH_C32(0xebcaa523), + SPH_C32(0x56a213a4), SPH_C32(0x667bf93b), SPH_C32(0x909e0000), + SPH_C32(0x32eb0000), SPH_C32(0xaea1db00), SPH_C32(0xf0d00000), + SPH_C32(0x50ab5dd6), SPH_C32(0x9f76b851), SPH_C32(0x6651b6d5), + SPH_C32(0x0c2ab7e7) }, + { SPH_C32(0x4b9f0000), SPH_C32(0x0b030001), SPH_C32(0x613deb80), + SPH_C32(0x08ff0000), SPH_C32(0x3f913785), SPH_C32(0x24a5ad87), + SPH_C32(0xd9bbf948), SPH_C32(0x2246c93f), SPH_C32(0x5c8a0000), + SPH_C32(0x97880000), SPH_C32(0xf418dc80), SPH_C32(0xcb800000), + SPH_C32(0x1b7b4e29), SPH_C32(0x18ed8c49), SPH_C32(0x0f12fe14), + SPH_C32(0xc6703019) }, + { SPH_C32(0x878b0000), SPH_C32(0xae600001), SPH_C32(0x3b84ec00), + SPH_C32(0x33af0000), SPH_C32(0x7441247a), SPH_C32(0xa33e999f), + SPH_C32(0xb0f8b189), SPH_C32(0xe81c4ec1), SPH_C32(0xdd140000), + SPH_C32(0x7bdf0000), SPH_C32(0x922ade00), SPH_C32(0x5e730000), + SPH_C32(0x46d2662b), SPH_C32(0x5019b0f5), SPH_C32(0xe9485c39), + SPH_C32(0x481787e3) }, + { SPH_C32(0x1cc50000), SPH_C32(0x59260001), SPH_C32(0x51d2f200), + SPH_C32(0x58720000), SPH_C32(0xf30e4347), SPH_C32(0x8d428ece), + SPH_C32(0x98432863), SPH_C32(0xaa5c67e3), SPH_C32(0x776d0000), + SPH_C32(0x128f0000), SPH_C32(0x0c51d380), SPH_C32(0x82a20000), + SPH_C32(0x907b5a33), SPH_C32(0x5dcb6487), SPH_C32(0xbd24ac88), + SPH_C32(0x7988c2d8) }, + { SPH_C32(0xd0d10000), SPH_C32(0xfc450001), SPH_C32(0x0b6bf580), + SPH_C32(0x63220000), SPH_C32(0xb8de50b8), SPH_C32(0x0ad9bad6), + SPH_C32(0xf10060a2), SPH_C32(0x6006e01d), SPH_C32(0xf6f30000), + SPH_C32(0xfed80000), SPH_C32(0x6a63d100), SPH_C32(0x17510000), + SPH_C32(0xcdd27231), SPH_C32(0x153f583b), SPH_C32(0x5b7e0ea5), + SPH_C32(0xf7ef7522) }, + { SPH_C32(0x9d5b0000), SPH_C32(0xb5710001), SPH_C32(0x37e0f080), + SPH_C32(0xcd810000), SPH_C32(0xaea76b45), SPH_C32(0xc5b6b272), + SPH_C32(0x7e198a4e), SPH_C32(0x243bd019), SPH_C32(0x3ae70000), + SPH_C32(0x5bbb0000), SPH_C32(0x30dad680), SPH_C32(0x2c010000), + SPH_C32(0x860261ce), SPH_C32(0x92a46c23), SPH_C32(0x323d4664), + SPH_C32(0x3db5f2dc) }, + { SPH_C32(0x514f0000), SPH_C32(0x10120001), SPH_C32(0x6d59f700), + SPH_C32(0xf6d10000), SPH_C32(0xe57778ba), SPH_C32(0x422d866a), + SPH_C32(0x175ac28f), SPH_C32(0xee6157e7), SPH_C32(0xbb790000), + SPH_C32(0xb7ec0000), SPH_C32(0x56e8d400), SPH_C32(0xb9f20000), + SPH_C32(0xdbab49cc), SPH_C32(0xda50509f), SPH_C32(0xd467e449), + SPH_C32(0xb3d24526) }, + { SPH_C32(0x64e60000), SPH_C32(0x4bda0001), SPH_C32(0xf8e8f980), + SPH_C32(0xc8d70000), SPH_C32(0x82306b3e), SPH_C32(0xf3ab07ea), + SPH_C32(0x68cf8801), SPH_C32(0xc933ec48), SPH_C32(0x75c20000), + SPH_C32(0xa5a70000), SPH_C32(0xb64dd080), SPH_C32(0xd43a0000), + SPH_C32(0x2af61fe0), SPH_C32(0xdd83a2e0), SPH_C32(0x1478b812), + SPH_C32(0x8d7e28a3) }, + { SPH_C32(0xa8f20000), SPH_C32(0xeeb90001), SPH_C32(0xa251fe00), + SPH_C32(0xf3870000), SPH_C32(0xc9e078c1), SPH_C32(0x743033f2), + SPH_C32(0x018cc0c0), SPH_C32(0x03696bb6), SPH_C32(0xf45c0000), + SPH_C32(0x49f00000), SPH_C32(0xd07fd200), SPH_C32(0x41c90000), + SPH_C32(0x775f37e2), SPH_C32(0x95779e5c), SPH_C32(0xf2221a3f), + SPH_C32(0x03199f59) }, + { SPH_C32(0xe5780000), SPH_C32(0xa78d0001), SPH_C32(0x9edafb00), + SPH_C32(0x5d240000), SPH_C32(0xdf99433c), SPH_C32(0xbb5f3b56), + SPH_C32(0x8e952a2c), SPH_C32(0x47545bb2), SPH_C32(0x38480000), + SPH_C32(0xec930000), SPH_C32(0x8ac6d580), SPH_C32(0x7a990000), + SPH_C32(0x3c8f241d), SPH_C32(0x12ecaa44), SPH_C32(0x9b6152fe), + SPH_C32(0xc94318a7) }, + { SPH_C32(0x296c0000), SPH_C32(0x02ee0001), SPH_C32(0xc463fc80), + SPH_C32(0x66740000), SPH_C32(0x944950c3), SPH_C32(0x3cc40f4e), + SPH_C32(0xe7d662ed), SPH_C32(0x8d0edc4c), SPH_C32(0xb9d60000), + SPH_C32(0x00c40000), SPH_C32(0xecf4d700), SPH_C32(0xef6a0000), + SPH_C32(0x61260c1f), SPH_C32(0x5a1896f8), SPH_C32(0x7d3bf0d3), + SPH_C32(0x4724af5d) }, + { SPH_C32(0x1e6a0000), SPH_C32(0xee0e0001), SPH_C32(0xebcef100), + SPH_C32(0x0eea0000), SPH_C32(0x49830694), SPH_C32(0x0d0a48a9), + SPH_C32(0x311f3cf9), SPH_C32(0x5eaa8d98), SPH_C32(0x0de10000), + SPH_C32(0xb75b0000), SPH_C32(0x1f77db00), SPH_C32(0x449f0000), + SPH_C32(0x5bc83799), SPH_C32(0xa36a2bc4), SPH_C32(0xe4f41870), + SPH_C32(0xee11a308) }, + { SPH_C32(0xd27e0000), SPH_C32(0x4b6d0001), SPH_C32(0xb177f680), + SPH_C32(0x35ba0000), SPH_C32(0x0253156b), SPH_C32(0x8a917cb1), + SPH_C32(0x585c7438), SPH_C32(0x94f00a66), SPH_C32(0x8c7f0000), + SPH_C32(0x5b0c0000), SPH_C32(0x7945d980), SPH_C32(0xd16c0000), + SPH_C32(0x06611f9b), SPH_C32(0xeb9e1778), SPH_C32(0x02aeba5d), + SPH_C32(0x607614f2) }, + { SPH_C32(0x9ff40000), SPH_C32(0x02590001), SPH_C32(0x8dfcf380), + SPH_C32(0x9b190000), SPH_C32(0x142a2e96), SPH_C32(0x45fe7415), + SPH_C32(0xd7459ed4), SPH_C32(0xd0cd3a62), SPH_C32(0x406b0000), + SPH_C32(0xfe6f0000), SPH_C32(0x23fcde00), SPH_C32(0xea3c0000), + SPH_C32(0x4db10c64), SPH_C32(0x6c052360), SPH_C32(0x6bedf29c), + SPH_C32(0xaa2c930c) }, + { SPH_C32(0x53e00000), SPH_C32(0xa73a0001), SPH_C32(0xd745f400), + SPH_C32(0xa0490000), SPH_C32(0x5ffa3d69), SPH_C32(0xc265400d), + SPH_C32(0xbe06d615), SPH_C32(0x1a97bd9c), SPH_C32(0xc1f50000), + SPH_C32(0x12380000), SPH_C32(0x45cedc80), SPH_C32(0x7fcf0000), + SPH_C32(0x10182466), SPH_C32(0x24f11fdc), SPH_C32(0x8db750b1), + SPH_C32(0x244b24f6) }, + { SPH_C32(0x66490000), SPH_C32(0xfcf20001), SPH_C32(0x42f4fa80), + SPH_C32(0x9e4f0000), SPH_C32(0x38bd2eed), SPH_C32(0x73e3c18d), + SPH_C32(0xc1939c9b), SPH_C32(0x3dc50633), SPH_C32(0x0f4e0000), + SPH_C32(0x00730000), SPH_C32(0xa56bd800), SPH_C32(0x12070000), + SPH_C32(0xe145724a), SPH_C32(0x2322eda3), SPH_C32(0x4da80cea), + SPH_C32(0x1ae74973) }, + { SPH_C32(0xaa5d0000), SPH_C32(0x59910001), SPH_C32(0x184dfd00), + SPH_C32(0xa51f0000), SPH_C32(0x736d3d12), SPH_C32(0xf478f595), + SPH_C32(0xa8d0d45a), SPH_C32(0xf79f81cd), SPH_C32(0x8ed00000), + SPH_C32(0xec240000), SPH_C32(0xc359da80), SPH_C32(0x87f40000), + SPH_C32(0xbcec5a48), SPH_C32(0x6bd6d11f), SPH_C32(0xabf2aec7), + SPH_C32(0x9480fe89) }, + { SPH_C32(0xe7d70000), SPH_C32(0x10a50001), SPH_C32(0x24c6f800), + SPH_C32(0x0bbc0000), SPH_C32(0x651406ef), SPH_C32(0x3b17fd31), + SPH_C32(0x27c93eb6), SPH_C32(0xb3a2b1c9), SPH_C32(0x42c40000), + SPH_C32(0x49470000), SPH_C32(0x99e0dd00), SPH_C32(0xbca40000), + SPH_C32(0xf73c49b7), SPH_C32(0xec4de507), SPH_C32(0xc2b1e606), + SPH_C32(0x5eda7977) }, + { SPH_C32(0x2bc30000), SPH_C32(0xb5c60001), SPH_C32(0x7e7fff80), + SPH_C32(0x30ec0000), SPH_C32(0x2ec41510), SPH_C32(0xbc8cc929), + SPH_C32(0x4e8a7677), SPH_C32(0x79f83637), SPH_C32(0xc35a0000), + SPH_C32(0xa5100000), SPH_C32(0xffd2df80), SPH_C32(0x29570000), + SPH_C32(0xaa9561b5), SPH_C32(0xa4b9d9bb), SPH_C32(0x24eb442b), + SPH_C32(0xd0bdce8d) }, + { SPH_C32(0xdb250000), SPH_C32(0x09290000), SPH_C32(0x49aac000), + SPH_C32(0x81e10000), SPH_C32(0xcafe6b59), SPH_C32(0x42793431), + SPH_C32(0x43566b76), SPH_C32(0xe86cba2e), SPH_C32(0x75e60000), + SPH_C32(0x95660001), SPH_C32(0x307b2000), SPH_C32(0xadf40000), + SPH_C32(0x8f321eea), SPH_C32(0x24298307), SPH_C32(0xe8c49cf9), + SPH_C32(0x4b7eec55) }, + { SPH_C32(0x17310000), SPH_C32(0xac4a0000), SPH_C32(0x1313c780), + SPH_C32(0xbab10000), SPH_C32(0x812e78a6), SPH_C32(0xc5e20029), + SPH_C32(0x2a1523b7), SPH_C32(0x22363dd0), SPH_C32(0xf4780000), + SPH_C32(0x79310001), SPH_C32(0x56492280), SPH_C32(0x38070000), + SPH_C32(0xd29b36e8), SPH_C32(0x6cddbfbb), SPH_C32(0x0e9e3ed4), + SPH_C32(0xc5195baf) }, + { SPH_C32(0x5abb0000), SPH_C32(0xe57e0000), SPH_C32(0x2f98c280), + SPH_C32(0x14120000), SPH_C32(0x9757435b), SPH_C32(0x0a8d088d), + SPH_C32(0xa50cc95b), SPH_C32(0x660b0dd4), SPH_C32(0x386c0000), + SPH_C32(0xdc520001), SPH_C32(0x0cf02500), SPH_C32(0x03570000), + SPH_C32(0x994b2517), SPH_C32(0xeb468ba3), SPH_C32(0x67dd7615), + SPH_C32(0x0f43dc51) }, + { SPH_C32(0x96af0000), SPH_C32(0x401d0000), SPH_C32(0x7521c500), + SPH_C32(0x2f420000), SPH_C32(0xdc8750a4), SPH_C32(0x8d163c95), + SPH_C32(0xcc4f819a), SPH_C32(0xac518a2a), SPH_C32(0xb9f20000), + SPH_C32(0x30050001), SPH_C32(0x6ac22780), SPH_C32(0x96a40000), + SPH_C32(0xc4e20d15), SPH_C32(0xa3b2b71f), SPH_C32(0x8187d438), + SPH_C32(0x81246bab) }, + { SPH_C32(0xa3060000), SPH_C32(0x1bd50000), SPH_C32(0xe090cb80), + SPH_C32(0x11440000), SPH_C32(0xbbc04320), SPH_C32(0x3c90bd15), + SPH_C32(0xb3dacb14), SPH_C32(0x8b033185), SPH_C32(0x77490000), + SPH_C32(0x224e0001), SPH_C32(0x8a672300), SPH_C32(0xfb6c0000), + SPH_C32(0x35bf5b39), SPH_C32(0xa4614560), SPH_C32(0x41988863), + SPH_C32(0xbf88062e) }, + { SPH_C32(0x6f120000), SPH_C32(0xbeb60000), SPH_C32(0xba29cc00), + SPH_C32(0x2a140000), SPH_C32(0xf01050df), SPH_C32(0xbb0b890d), + SPH_C32(0xda9983d5), SPH_C32(0x4159b67b), SPH_C32(0xf6d70000), + SPH_C32(0xce190001), SPH_C32(0xec552180), SPH_C32(0x6e9f0000), + SPH_C32(0x6816733b), SPH_C32(0xec9579dc), SPH_C32(0xa7c22a4e), + SPH_C32(0x31efb1d4) }, + { SPH_C32(0x22980000), SPH_C32(0xf7820000), SPH_C32(0x86a2c900), + SPH_C32(0x84b70000), SPH_C32(0xe6696b22), SPH_C32(0x746481a9), + SPH_C32(0x55806939), SPH_C32(0x0564867f), SPH_C32(0x3ac30000), + SPH_C32(0x6b7a0001), SPH_C32(0xb6ec2600), SPH_C32(0x55cf0000), + SPH_C32(0x23c660c4), SPH_C32(0x6b0e4dc4), SPH_C32(0xce81628f), + SPH_C32(0xfbb5362a) }, + { SPH_C32(0xee8c0000), SPH_C32(0x52e10000), SPH_C32(0xdc1bce80), + SPH_C32(0xbfe70000), SPH_C32(0xadb978dd), SPH_C32(0xf3ffb5b1), + SPH_C32(0x3cc321f8), SPH_C32(0xcf3e0181), SPH_C32(0xbb5d0000), + SPH_C32(0x872d0001), SPH_C32(0xd0de2480), SPH_C32(0xc03c0000), + SPH_C32(0x7e6f48c6), SPH_C32(0x23fa7178), SPH_C32(0x28dbc0a2), + SPH_C32(0x75d281d0) }, + { SPH_C32(0xd98a0000), SPH_C32(0xbe010000), SPH_C32(0xf3b6c300), + SPH_C32(0xd7790000), SPH_C32(0x70732e8a), SPH_C32(0xc231f256), + SPH_C32(0xea0a7fec), SPH_C32(0x1c9a5055), SPH_C32(0x0f6a0000), + SPH_C32(0x30b20001), SPH_C32(0x235d2880), SPH_C32(0x6bc90000), + SPH_C32(0x44817340), SPH_C32(0xda88cc44), SPH_C32(0xb1142801), + SPH_C32(0xdce78d85) }, + { SPH_C32(0x159e0000), SPH_C32(0x1b620000), SPH_C32(0xa90fc480), + SPH_C32(0xec290000), SPH_C32(0x3ba33d75), SPH_C32(0x45aac64e), + SPH_C32(0x8349372d), SPH_C32(0xd6c0d7ab), SPH_C32(0x8ef40000), + SPH_C32(0xdce50001), SPH_C32(0x456f2a00), SPH_C32(0xfe3a0000), + SPH_C32(0x19285b42), SPH_C32(0x927cf0f8), SPH_C32(0x574e8a2c), + SPH_C32(0x52803a7f) }, + { SPH_C32(0x58140000), SPH_C32(0x52560000), SPH_C32(0x9584c180), + SPH_C32(0x428a0000), SPH_C32(0x2dda0688), SPH_C32(0x8ac5ceea), + SPH_C32(0x0c50ddc1), SPH_C32(0x92fde7af), SPH_C32(0x42e00000), + SPH_C32(0x79860001), SPH_C32(0x1fd62d80), SPH_C32(0xc56a0000), + SPH_C32(0x52f848bd), SPH_C32(0x15e7c4e0), SPH_C32(0x3e0dc2ed), + SPH_C32(0x98dabd81) }, + { SPH_C32(0x94000000), SPH_C32(0xf7350000), SPH_C32(0xcf3dc600), + SPH_C32(0x79da0000), SPH_C32(0x660a1577), SPH_C32(0x0d5efaf2), + SPH_C32(0x65139500), SPH_C32(0x58a76051), SPH_C32(0xc37e0000), + SPH_C32(0x95d10001), SPH_C32(0x79e42f00), SPH_C32(0x50990000), + SPH_C32(0x0f5160bf), SPH_C32(0x5d13f85c), SPH_C32(0xd85760c0), + SPH_C32(0x16bd0a7b) }, + { SPH_C32(0xa1a90000), SPH_C32(0xacfd0000), SPH_C32(0x5a8cc880), + SPH_C32(0x47dc0000), SPH_C32(0x014d06f3), SPH_C32(0xbcd87b72), + SPH_C32(0x1a86df8e), SPH_C32(0x7ff5dbfe), SPH_C32(0x0dc50000), + SPH_C32(0x879a0001), SPH_C32(0x99412b80), SPH_C32(0x3d510000), + SPH_C32(0xfe0c3693), SPH_C32(0x5ac00a23), SPH_C32(0x18483c9b), + SPH_C32(0x281167fe) }, + { SPH_C32(0x6dbd0000), SPH_C32(0x099e0000), SPH_C32(0x0035cf00), + SPH_C32(0x7c8c0000), SPH_C32(0x4a9d150c), SPH_C32(0x3b434f6a), + SPH_C32(0x73c5974f), SPH_C32(0xb5af5c00), SPH_C32(0x8c5b0000), + SPH_C32(0x6bcd0001), SPH_C32(0xff732900), SPH_C32(0xa8a20000), + SPH_C32(0xa3a51e91), SPH_C32(0x1234369f), SPH_C32(0xfe129eb6), + SPH_C32(0xa676d004) }, + { SPH_C32(0x20370000), SPH_C32(0x40aa0000), SPH_C32(0x3cbeca00), + SPH_C32(0xd22f0000), SPH_C32(0x5ce42ef1), SPH_C32(0xf42c47ce), + SPH_C32(0xfcdc7da3), SPH_C32(0xf1926c04), SPH_C32(0x404f0000), + SPH_C32(0xceae0001), SPH_C32(0xa5ca2e80), SPH_C32(0x93f20000), + SPH_C32(0xe8750d6e), SPH_C32(0x95af0287), SPH_C32(0x9751d677), + SPH_C32(0x6c2c57fa) }, + { SPH_C32(0xec230000), SPH_C32(0xe5c90000), SPH_C32(0x6607cd80), + SPH_C32(0xe97f0000), SPH_C32(0x17343d0e), SPH_C32(0x73b773d6), + SPH_C32(0x959f3562), SPH_C32(0x3bc8ebfa), SPH_C32(0xc1d10000), + SPH_C32(0x22f90001), SPH_C32(0xc3f82c00), SPH_C32(0x06010000), + SPH_C32(0xb5dc256c), SPH_C32(0xdd5b3e3b), SPH_C32(0x710b745a), + SPH_C32(0xe24be000) }, + { SPH_C32(0x776d0000), SPH_C32(0x128f0000), SPH_C32(0x0c51d380), + SPH_C32(0x82a20000), SPH_C32(0x907b5a33), SPH_C32(0x5dcb6487), + SPH_C32(0xbd24ac88), SPH_C32(0x7988c2d8), SPH_C32(0x6ba80000), + SPH_C32(0x4ba90001), SPH_C32(0x5d832180), SPH_C32(0xdad00000), + SPH_C32(0x63751974), SPH_C32(0xd089ea49), SPH_C32(0x256784eb), + SPH_C32(0xd3d4a53b) }, + { SPH_C32(0xbb790000), SPH_C32(0xb7ec0000), SPH_C32(0x56e8d400), + SPH_C32(0xb9f20000), SPH_C32(0xdbab49cc), SPH_C32(0xda50509f), + SPH_C32(0xd467e449), SPH_C32(0xb3d24526), SPH_C32(0xea360000), + SPH_C32(0xa7fe0001), SPH_C32(0x3bb12300), SPH_C32(0x4f230000), + SPH_C32(0x3edc3176), SPH_C32(0x987dd6f5), SPH_C32(0xc33d26c6), + SPH_C32(0x5db312c1) }, + { SPH_C32(0xf6f30000), SPH_C32(0xfed80000), SPH_C32(0x6a63d100), + SPH_C32(0x17510000), SPH_C32(0xcdd27231), SPH_C32(0x153f583b), + SPH_C32(0x5b7e0ea5), SPH_C32(0xf7ef7522), SPH_C32(0x26220000), + SPH_C32(0x029d0001), SPH_C32(0x61082480), SPH_C32(0x74730000), + SPH_C32(0x750c2289), SPH_C32(0x1fe6e2ed), SPH_C32(0xaa7e6e07), + SPH_C32(0x97e9953f) }, + { SPH_C32(0x3ae70000), SPH_C32(0x5bbb0000), SPH_C32(0x30dad680), + SPH_C32(0x2c010000), SPH_C32(0x860261ce), SPH_C32(0x92a46c23), + SPH_C32(0x323d4664), SPH_C32(0x3db5f2dc), SPH_C32(0xa7bc0000), + SPH_C32(0xeeca0001), SPH_C32(0x073a2600), SPH_C32(0xe1800000), + SPH_C32(0x28a50a8b), SPH_C32(0x5712de51), SPH_C32(0x4c24cc2a), + SPH_C32(0x198e22c5) }, + { SPH_C32(0x0f4e0000), SPH_C32(0x00730000), SPH_C32(0xa56bd800), + SPH_C32(0x12070000), SPH_C32(0xe145724a), SPH_C32(0x2322eda3), + SPH_C32(0x4da80cea), SPH_C32(0x1ae74973), SPH_C32(0x69070000), + SPH_C32(0xfc810001), SPH_C32(0xe79f2280), SPH_C32(0x8c480000), + SPH_C32(0xd9f85ca7), SPH_C32(0x50c12c2e), SPH_C32(0x8c3b9071), + SPH_C32(0x27224f40) }, + { SPH_C32(0xc35a0000), SPH_C32(0xa5100000), SPH_C32(0xffd2df80), + SPH_C32(0x29570000), SPH_C32(0xaa9561b5), SPH_C32(0xa4b9d9bb), + SPH_C32(0x24eb442b), SPH_C32(0xd0bdce8d), SPH_C32(0xe8990000), + SPH_C32(0x10d60001), SPH_C32(0x81ad2000), SPH_C32(0x19bb0000), + SPH_C32(0x845174a5), SPH_C32(0x18351092), SPH_C32(0x6a61325c), + SPH_C32(0xa945f8ba) }, + { SPH_C32(0x8ed00000), SPH_C32(0xec240000), SPH_C32(0xc359da80), + SPH_C32(0x87f40000), SPH_C32(0xbcec5a48), SPH_C32(0x6bd6d11f), + SPH_C32(0xabf2aec7), SPH_C32(0x9480fe89), SPH_C32(0x248d0000), + SPH_C32(0xb5b50001), SPH_C32(0xdb142780), SPH_C32(0x22eb0000), + SPH_C32(0xcf81675a), SPH_C32(0x9fae248a), SPH_C32(0x03227a9d), + SPH_C32(0x631f7f44) }, + { SPH_C32(0x42c40000), SPH_C32(0x49470000), SPH_C32(0x99e0dd00), + SPH_C32(0xbca40000), SPH_C32(0xf73c49b7), SPH_C32(0xec4de507), + SPH_C32(0xc2b1e606), SPH_C32(0x5eda7977), SPH_C32(0xa5130000), + SPH_C32(0x59e20001), SPH_C32(0xbd262500), SPH_C32(0xb7180000), + SPH_C32(0x92284f58), SPH_C32(0xd75a1836), SPH_C32(0xe578d8b0), + SPH_C32(0xed78c8be) }, + { SPH_C32(0x75c20000), SPH_C32(0xa5a70000), SPH_C32(0xb64dd080), + SPH_C32(0xd43a0000), SPH_C32(0x2af61fe0), SPH_C32(0xdd83a2e0), + SPH_C32(0x1478b812), SPH_C32(0x8d7e28a3), SPH_C32(0x11240000), + SPH_C32(0xee7d0001), SPH_C32(0x4ea52900), SPH_C32(0x1ced0000), + SPH_C32(0xa8c674de), SPH_C32(0x2e28a50a), SPH_C32(0x7cb73013), + SPH_C32(0x444dc4eb) }, + { SPH_C32(0xb9d60000), SPH_C32(0x00c40000), SPH_C32(0xecf4d700), + SPH_C32(0xef6a0000), SPH_C32(0x61260c1f), SPH_C32(0x5a1896f8), + SPH_C32(0x7d3bf0d3), SPH_C32(0x4724af5d), SPH_C32(0x90ba0000), + SPH_C32(0x022a0001), SPH_C32(0x28972b80), SPH_C32(0x891e0000), + SPH_C32(0xf56f5cdc), SPH_C32(0x66dc99b6), SPH_C32(0x9aed923e), + SPH_C32(0xca2a7311) }, + { SPH_C32(0xf45c0000), SPH_C32(0x49f00000), SPH_C32(0xd07fd200), + SPH_C32(0x41c90000), SPH_C32(0x775f37e2), SPH_C32(0x95779e5c), + SPH_C32(0xf2221a3f), SPH_C32(0x03199f59), SPH_C32(0x5cae0000), + SPH_C32(0xa7490001), SPH_C32(0x722e2c00), SPH_C32(0xb24e0000), + SPH_C32(0xbebf4f23), SPH_C32(0xe147adae), SPH_C32(0xf3aedaff), + SPH_C32(0x0070f4ef) }, + { SPH_C32(0x38480000), SPH_C32(0xec930000), SPH_C32(0x8ac6d580), + SPH_C32(0x7a990000), SPH_C32(0x3c8f241d), SPH_C32(0x12ecaa44), + SPH_C32(0x9b6152fe), SPH_C32(0xc94318a7), SPH_C32(0xdd300000), + SPH_C32(0x4b1e0001), SPH_C32(0x141c2e80), SPH_C32(0x27bd0000), + SPH_C32(0xe3166721), SPH_C32(0xa9b39112), SPH_C32(0x15f478d2), + SPH_C32(0x8e174315) }, + { SPH_C32(0x0de10000), SPH_C32(0xb75b0000), SPH_C32(0x1f77db00), + SPH_C32(0x449f0000), SPH_C32(0x5bc83799), SPH_C32(0xa36a2bc4), + SPH_C32(0xe4f41870), SPH_C32(0xee11a308), SPH_C32(0x138b0000), + SPH_C32(0x59550001), SPH_C32(0xf4b92a00), SPH_C32(0x4a750000), + SPH_C32(0x124b310d), SPH_C32(0xae60636d), SPH_C32(0xd5eb2489), + SPH_C32(0xb0bb2e90) }, + { SPH_C32(0xc1f50000), SPH_C32(0x12380000), SPH_C32(0x45cedc80), + SPH_C32(0x7fcf0000), SPH_C32(0x10182466), SPH_C32(0x24f11fdc), + SPH_C32(0x8db750b1), SPH_C32(0x244b24f6), SPH_C32(0x92150000), + SPH_C32(0xb5020001), SPH_C32(0x928b2880), SPH_C32(0xdf860000), + SPH_C32(0x4fe2190f), SPH_C32(0xe6945fd1), SPH_C32(0x33b186a4), + SPH_C32(0x3edc996a) }, + { SPH_C32(0x8c7f0000), SPH_C32(0x5b0c0000), SPH_C32(0x7945d980), + SPH_C32(0xd16c0000), SPH_C32(0x06611f9b), SPH_C32(0xeb9e1778), + SPH_C32(0x02aeba5d), SPH_C32(0x607614f2), SPH_C32(0x5e010000), + SPH_C32(0x10610001), SPH_C32(0xc8322f00), SPH_C32(0xe4d60000), + SPH_C32(0x04320af0), SPH_C32(0x610f6bc9), SPH_C32(0x5af2ce65), + SPH_C32(0xf4861e94) }, + { SPH_C32(0x406b0000), SPH_C32(0xfe6f0000), SPH_C32(0x23fcde00), + SPH_C32(0xea3c0000), SPH_C32(0x4db10c64), SPH_C32(0x6c052360), + SPH_C32(0x6bedf29c), SPH_C32(0xaa2c930c), SPH_C32(0xdf9f0000), + SPH_C32(0xfc360001), SPH_C32(0xae002d80), SPH_C32(0x71250000), + SPH_C32(0x599b22f2), SPH_C32(0x29fb5775), SPH_C32(0xbca86c48), + SPH_C32(0x7ae1a96e) }, + { SPH_C32(0xc56b0000), SPH_C32(0xd7e60000), SPH_C32(0x2452c180), + SPH_C32(0xf6c50000), SPH_C32(0x26b96cc7), SPH_C32(0xb6d95d7f), + SPH_C32(0x8ef57364), SPH_C32(0x70c6f340), SPH_C32(0xc7e00000), + SPH_C32(0x500f0001), SPH_C32(0x18783200), SPH_C32(0xd9930000), + SPH_C32(0x39f0281e), SPH_C32(0xcf3bbaff), SPH_C32(0xdb154315), + SPH_C32(0x4230ddcd) }, + { SPH_C32(0x097f0000), SPH_C32(0x72850000), SPH_C32(0x7eebc600), + SPH_C32(0xcd950000), SPH_C32(0x6d697f38), SPH_C32(0x31426967), + SPH_C32(0xe7b63ba5), SPH_C32(0xba9c74be), SPH_C32(0x467e0000), + SPH_C32(0xbc580001), SPH_C32(0x7e4a3080), SPH_C32(0x4c600000), + SPH_C32(0x6459001c), SPH_C32(0x87cf8643), SPH_C32(0x3d4fe138), + SPH_C32(0xcc576a37) }, + { SPH_C32(0x44f50000), SPH_C32(0x3bb10000), SPH_C32(0x4260c300), + SPH_C32(0x63360000), SPH_C32(0x7b1044c5), SPH_C32(0xfe2d61c3), + SPH_C32(0x68afd149), SPH_C32(0xfea144ba), SPH_C32(0x8a6a0000), + SPH_C32(0x193b0001), SPH_C32(0x24f33700), SPH_C32(0x77300000), + SPH_C32(0x2f8913e3), SPH_C32(0x0054b25b), SPH_C32(0x540ca9f9), + SPH_C32(0x060dedc9) }, + { SPH_C32(0x88e10000), SPH_C32(0x9ed20000), SPH_C32(0x18d9c480), + SPH_C32(0x58660000), SPH_C32(0x30c0573a), SPH_C32(0x79b655db), + SPH_C32(0x01ec9988), SPH_C32(0x34fbc344), SPH_C32(0x0bf40000), + SPH_C32(0xf56c0001), SPH_C32(0x42c13580), SPH_C32(0xe2c30000), + SPH_C32(0x72203be1), SPH_C32(0x48a08ee7), SPH_C32(0xb2560bd4), + SPH_C32(0x886a5a33) }, + { SPH_C32(0xbd480000), SPH_C32(0xc51a0000), SPH_C32(0x8d68ca00), + SPH_C32(0x66600000), SPH_C32(0x578744be), SPH_C32(0xc830d45b), + SPH_C32(0x7e79d306), SPH_C32(0x13a978eb), SPH_C32(0xc54f0000), + SPH_C32(0xe7270001), SPH_C32(0xa2643100), SPH_C32(0x8f0b0000), + SPH_C32(0x837d6dcd), SPH_C32(0x4f737c98), SPH_C32(0x7249578f), + SPH_C32(0xb6c637b6) }, + { SPH_C32(0x715c0000), SPH_C32(0x60790000), SPH_C32(0xd7d1cd80), + SPH_C32(0x5d300000), SPH_C32(0x1c575741), SPH_C32(0x4fabe043), + SPH_C32(0x173a9bc7), SPH_C32(0xd9f3ff15), SPH_C32(0x44d10000), + SPH_C32(0x0b700001), SPH_C32(0xc4563380), SPH_C32(0x1af80000), + SPH_C32(0xded445cf), SPH_C32(0x07874024), SPH_C32(0x9413f5a2), + SPH_C32(0x38a1804c) }, + { SPH_C32(0x3cd60000), SPH_C32(0x294d0000), SPH_C32(0xeb5ac880), + SPH_C32(0xf3930000), SPH_C32(0x0a2e6cbc), SPH_C32(0x80c4e8e7), + SPH_C32(0x9823712b), SPH_C32(0x9dcecf11), SPH_C32(0x88c50000), + SPH_C32(0xae130001), SPH_C32(0x9eef3400), SPH_C32(0x21a80000), + SPH_C32(0x95045630), SPH_C32(0x801c743c), SPH_C32(0xfd50bd63), + SPH_C32(0xf2fb07b2) }, + { SPH_C32(0xf0c20000), SPH_C32(0x8c2e0000), SPH_C32(0xb1e3cf00), + SPH_C32(0xc8c30000), SPH_C32(0x41fe7f43), SPH_C32(0x075fdcff), + SPH_C32(0xf16039ea), SPH_C32(0x579448ef), SPH_C32(0x095b0000), + SPH_C32(0x42440001), SPH_C32(0xf8dd3680), SPH_C32(0xb45b0000), + SPH_C32(0xc8ad7e32), SPH_C32(0xc8e84880), SPH_C32(0x1b0a1f4e), + SPH_C32(0x7c9cb048) }, + { SPH_C32(0xc7c40000), SPH_C32(0x60ce0000), SPH_C32(0x9e4ec280), + SPH_C32(0xa05d0000), SPH_C32(0x9c342914), SPH_C32(0x36919b18), + SPH_C32(0x27a967fe), SPH_C32(0x8430193b), SPH_C32(0xbd6c0000), + SPH_C32(0xf5db0001), SPH_C32(0x0b5e3a80), SPH_C32(0x1fae0000), + SPH_C32(0xf24345b4), SPH_C32(0x319af5bc), SPH_C32(0x82c5f7ed), + SPH_C32(0xd5a9bc1d) }, + { SPH_C32(0x0bd00000), SPH_C32(0xc5ad0000), SPH_C32(0xc4f7c500), + SPH_C32(0x9b0d0000), SPH_C32(0xd7e43aeb), SPH_C32(0xb10aaf00), + SPH_C32(0x4eea2f3f), SPH_C32(0x4e6a9ec5), SPH_C32(0x3cf20000), + SPH_C32(0x198c0001), SPH_C32(0x6d6c3800), SPH_C32(0x8a5d0000), + SPH_C32(0xafea6db6), SPH_C32(0x796ec900), SPH_C32(0x649f55c0), + SPH_C32(0x5bce0be7) }, + { SPH_C32(0x465a0000), SPH_C32(0x8c990000), SPH_C32(0xf87cc000), + SPH_C32(0x35ae0000), SPH_C32(0xc19d0116), SPH_C32(0x7e65a7a4), + SPH_C32(0xc1f3c5d3), SPH_C32(0x0a57aec1), SPH_C32(0xf0e60000), + SPH_C32(0xbcef0001), SPH_C32(0x37d53f80), SPH_C32(0xb10d0000), + SPH_C32(0xe43a7e49), SPH_C32(0xfef5fd18), SPH_C32(0x0ddc1d01), + SPH_C32(0x91948c19) }, + { SPH_C32(0x8a4e0000), SPH_C32(0x29fa0000), SPH_C32(0xa2c5c780), + SPH_C32(0x0efe0000), SPH_C32(0x8a4d12e9), SPH_C32(0xf9fe93bc), + SPH_C32(0xa8b08d12), SPH_C32(0xc00d293f), SPH_C32(0x71780000), + SPH_C32(0x50b80001), SPH_C32(0x51e73d00), SPH_C32(0x24fe0000), + SPH_C32(0xb993564b), SPH_C32(0xb601c1a4), SPH_C32(0xeb86bf2c), + SPH_C32(0x1ff33be3) }, + { SPH_C32(0xbfe70000), SPH_C32(0x72320000), SPH_C32(0x3774c900), + SPH_C32(0x30f80000), SPH_C32(0xed0a016d), SPH_C32(0x4878123c), + SPH_C32(0xd725c79c), SPH_C32(0xe75f9290), SPH_C32(0xbfc30000), + SPH_C32(0x42f30001), SPH_C32(0xb1423980), SPH_C32(0x49360000), + SPH_C32(0x48ce0067), SPH_C32(0xb1d233db), SPH_C32(0x2b99e377), + SPH_C32(0x215f5666) }, + { SPH_C32(0x73f30000), SPH_C32(0xd7510000), SPH_C32(0x6dcdce80), + SPH_C32(0x0ba80000), SPH_C32(0xa6da1292), SPH_C32(0xcfe32624), + SPH_C32(0xbe668f5d), SPH_C32(0x2d05156e), SPH_C32(0x3e5d0000), + SPH_C32(0xaea40001), SPH_C32(0xd7703b00), SPH_C32(0xdcc50000), + SPH_C32(0x15672865), SPH_C32(0xf9260f67), SPH_C32(0xcdc3415a), + SPH_C32(0xaf38e19c) }, + { SPH_C32(0x3e790000), SPH_C32(0x9e650000), SPH_C32(0x5146cb80), + SPH_C32(0xa50b0000), SPH_C32(0xb0a3296f), SPH_C32(0x008c2e80), + SPH_C32(0x317f65b1), SPH_C32(0x6938256a), SPH_C32(0xf2490000), + SPH_C32(0x0bc70001), SPH_C32(0x8dc93c80), SPH_C32(0xe7950000), + SPH_C32(0x5eb73b9a), SPH_C32(0x7ebd3b7f), SPH_C32(0xa480099b), + SPH_C32(0x65626662) }, + { SPH_C32(0xf26d0000), SPH_C32(0x3b060000), SPH_C32(0x0bffcc00), + SPH_C32(0x9e5b0000), SPH_C32(0xfb733a90), SPH_C32(0x87171a98), + SPH_C32(0x583c2d70), SPH_C32(0xa362a294), SPH_C32(0x73d70000), + SPH_C32(0xe7900001), SPH_C32(0xebfb3e00), SPH_C32(0x72660000), + SPH_C32(0x031e1398), SPH_C32(0x364907c3), SPH_C32(0x42daabb6), + SPH_C32(0xeb05d198) }, + { SPH_C32(0x69230000), SPH_C32(0xcc400000), SPH_C32(0x61a9d200), + SPH_C32(0xf5860000), SPH_C32(0x7c3c5dad), SPH_C32(0xa96b0dc9), + SPH_C32(0x7087b49a), SPH_C32(0xe1228bb6), SPH_C32(0xd9ae0000), + SPH_C32(0x8ec00001), SPH_C32(0x75803380), SPH_C32(0xaeb70000), + SPH_C32(0xd5b72f80), SPH_C32(0x3b9bd3b1), SPH_C32(0x16b65b07), + SPH_C32(0xda9a94a3) }, + { SPH_C32(0xa5370000), SPH_C32(0x69230000), SPH_C32(0x3b10d580), + SPH_C32(0xced60000), SPH_C32(0x37ec4e52), SPH_C32(0x2ef039d1), + SPH_C32(0x19c4fc5b), SPH_C32(0x2b780c48), SPH_C32(0x58300000), + SPH_C32(0x62970001), SPH_C32(0x13b23100), SPH_C32(0x3b440000), + SPH_C32(0x881e0782), SPH_C32(0x736fef0d), SPH_C32(0xf0ecf92a), + SPH_C32(0x54fd2359) }, + { SPH_C32(0xe8bd0000), SPH_C32(0x20170000), SPH_C32(0x079bd080), + SPH_C32(0x60750000), SPH_C32(0x219575af), SPH_C32(0xe19f3175), + SPH_C32(0x96dd16b7), SPH_C32(0x6f453c4c), SPH_C32(0x94240000), + SPH_C32(0xc7f40001), SPH_C32(0x490b3680), SPH_C32(0x00140000), + SPH_C32(0xc3ce147d), SPH_C32(0xf4f4db15), SPH_C32(0x99afb1eb), + SPH_C32(0x9ea7a4a7) }, + { SPH_C32(0x24a90000), SPH_C32(0x85740000), SPH_C32(0x5d22d700), + SPH_C32(0x5b250000), SPH_C32(0x6a456650), SPH_C32(0x6604056d), + SPH_C32(0xff9e5e76), SPH_C32(0xa51fbbb2), SPH_C32(0x15ba0000), + SPH_C32(0x2ba30001), SPH_C32(0x2f393400), SPH_C32(0x95e70000), + SPH_C32(0x9e673c7f), SPH_C32(0xbc00e7a9), SPH_C32(0x7ff513c6), + SPH_C32(0x10c0135d) }, + { SPH_C32(0x11000000), SPH_C32(0xdebc0000), SPH_C32(0xc893d980), + SPH_C32(0x65230000), SPH_C32(0x0d0275d4), SPH_C32(0xd78284ed), + SPH_C32(0x800b14f8), SPH_C32(0x824d001d), SPH_C32(0xdb010000), + SPH_C32(0x39e80001), SPH_C32(0xcf9c3080), SPH_C32(0xf82f0000), + SPH_C32(0x6f3a6a53), SPH_C32(0xbbd315d6), SPH_C32(0xbfea4f9d), + SPH_C32(0x2e6c7ed8) }, + { SPH_C32(0xdd140000), SPH_C32(0x7bdf0000), SPH_C32(0x922ade00), + SPH_C32(0x5e730000), SPH_C32(0x46d2662b), SPH_C32(0x5019b0f5), + SPH_C32(0xe9485c39), SPH_C32(0x481787e3), SPH_C32(0x5a9f0000), + SPH_C32(0xd5bf0001), SPH_C32(0xa9ae3200), SPH_C32(0x6ddc0000), + SPH_C32(0x32934251), SPH_C32(0xf327296a), SPH_C32(0x59b0edb0), + SPH_C32(0xa00bc922) }, + { SPH_C32(0x909e0000), SPH_C32(0x32eb0000), SPH_C32(0xaea1db00), + SPH_C32(0xf0d00000), SPH_C32(0x50ab5dd6), SPH_C32(0x9f76b851), + SPH_C32(0x6651b6d5), SPH_C32(0x0c2ab7e7), SPH_C32(0x968b0000), + SPH_C32(0x70dc0001), SPH_C32(0xf3173580), SPH_C32(0x568c0000), + SPH_C32(0x794351ae), SPH_C32(0x74bc1d72), SPH_C32(0x30f3a571), + SPH_C32(0x6a514edc) }, + { SPH_C32(0x5c8a0000), SPH_C32(0x97880000), SPH_C32(0xf418dc80), + SPH_C32(0xcb800000), SPH_C32(0x1b7b4e29), SPH_C32(0x18ed8c49), + SPH_C32(0x0f12fe14), SPH_C32(0xc6703019), SPH_C32(0x17150000), + SPH_C32(0x9c8b0001), SPH_C32(0x95253700), SPH_C32(0xc37f0000), + SPH_C32(0x24ea79ac), SPH_C32(0x3c4821ce), SPH_C32(0xd6a9075c), + SPH_C32(0xe436f926) }, + { SPH_C32(0x6b8c0000), SPH_C32(0x7b680000), SPH_C32(0xdbb5d100), + SPH_C32(0xa31e0000), SPH_C32(0xc6b1187e), SPH_C32(0x2923cbae), + SPH_C32(0xd9dba000), SPH_C32(0x15d461cd), SPH_C32(0xa3220000), + SPH_C32(0x2b140001), SPH_C32(0x66a63b00), SPH_C32(0x688a0000), + SPH_C32(0x1e04422a), SPH_C32(0xc53a9cf2), SPH_C32(0x4f66efff), + SPH_C32(0x4d03f573) }, + { SPH_C32(0xa7980000), SPH_C32(0xde0b0000), SPH_C32(0x810cd680), + SPH_C32(0x984e0000), SPH_C32(0x8d610b81), SPH_C32(0xaeb8ffb6), + SPH_C32(0xb098e8c1), SPH_C32(0xdf8ee633), SPH_C32(0x22bc0000), + SPH_C32(0xc7430001), SPH_C32(0x00943980), SPH_C32(0xfd790000), + SPH_C32(0x43ad6a28), SPH_C32(0x8dcea04e), SPH_C32(0xa93c4dd2), + SPH_C32(0xc3644289) }, + { SPH_C32(0xea120000), SPH_C32(0x973f0000), SPH_C32(0xbd87d380), + SPH_C32(0x36ed0000), SPH_C32(0x9b18307c), SPH_C32(0x61d7f712), + SPH_C32(0x3f81022d), SPH_C32(0x9bb3d637), SPH_C32(0xeea80000), + SPH_C32(0x62200001), SPH_C32(0x5a2d3e00), SPH_C32(0xc6290000), + SPH_C32(0x087d79d7), SPH_C32(0x0a559456), SPH_C32(0xc07f0513), + SPH_C32(0x093ec577) }, + { SPH_C32(0x26060000), SPH_C32(0x325c0000), SPH_C32(0xe73ed400), + SPH_C32(0x0dbd0000), SPH_C32(0xd0c82383), SPH_C32(0xe64cc30a), + SPH_C32(0x56c24aec), SPH_C32(0x51e951c9), SPH_C32(0x6f360000), + SPH_C32(0x8e770001), SPH_C32(0x3c1f3c80), SPH_C32(0x53da0000), + SPH_C32(0x55d451d5), SPH_C32(0x42a1a8ea), SPH_C32(0x2625a73e), + SPH_C32(0x8759728d) }, + { SPH_C32(0x13af0000), SPH_C32(0x69940000), SPH_C32(0x728fda80), + SPH_C32(0x33bb0000), SPH_C32(0xb78f3007), SPH_C32(0x57ca428a), + SPH_C32(0x29570062), SPH_C32(0x76bbea66), SPH_C32(0xa18d0000), + SPH_C32(0x9c3c0001), SPH_C32(0xdcba3800), SPH_C32(0x3e120000), + SPH_C32(0xa48907f9), SPH_C32(0x45725a95), SPH_C32(0xe63afb65), + SPH_C32(0xb9f51f08) }, + { SPH_C32(0xdfbb0000), SPH_C32(0xccf70000), SPH_C32(0x2836dd00), + SPH_C32(0x08eb0000), SPH_C32(0xfc5f23f8), SPH_C32(0xd0517692), + SPH_C32(0x401448a3), SPH_C32(0xbce16d98), SPH_C32(0x20130000), + SPH_C32(0x706b0001), SPH_C32(0xba883a80), SPH_C32(0xabe10000), + SPH_C32(0xf9202ffb), SPH_C32(0x0d866629), SPH_C32(0x00605948), + SPH_C32(0x3792a8f2) }, + { SPH_C32(0x92310000), SPH_C32(0x85c30000), SPH_C32(0x14bdd800), + SPH_C32(0xa6480000), SPH_C32(0xea261805), SPH_C32(0x1f3e7e36), + SPH_C32(0xcf0da24f), SPH_C32(0xf8dc5d9c), SPH_C32(0xec070000), + SPH_C32(0xd5080001), SPH_C32(0xe0313d00), SPH_C32(0x90b10000), + SPH_C32(0xb2f03c04), SPH_C32(0x8a1d5231), SPH_C32(0x69231189), + SPH_C32(0xfdc82f0c) }, + { SPH_C32(0x5e250000), SPH_C32(0x20a00000), SPH_C32(0x4e04df80), + SPH_C32(0x9d180000), SPH_C32(0xa1f60bfa), SPH_C32(0x98a54a2e), + SPH_C32(0xa64eea8e), SPH_C32(0x3286da62), SPH_C32(0x6d990000), + SPH_C32(0x395f0001), SPH_C32(0x86033f80), SPH_C32(0x05420000), + SPH_C32(0xef591406), SPH_C32(0xc2e96e8d), SPH_C32(0x8f79b3a4), + SPH_C32(0x73af98f6) }, + { SPH_C32(0x75e60000), SPH_C32(0x95660001), SPH_C32(0x307b2000), + SPH_C32(0xadf40000), SPH_C32(0x8f321eea), SPH_C32(0x24298307), + SPH_C32(0xe8c49cf9), SPH_C32(0x4b7eec55), SPH_C32(0xaec30000), + SPH_C32(0x9c4f0001), SPH_C32(0x79d1e000), SPH_C32(0x2c150000), + SPH_C32(0x45cc75b3), SPH_C32(0x6650b736), SPH_C32(0xab92f78f), + SPH_C32(0xa312567b) }, + { SPH_C32(0xb9f20000), SPH_C32(0x30050001), SPH_C32(0x6ac22780), + SPH_C32(0x96a40000), SPH_C32(0xc4e20d15), SPH_C32(0xa3b2b71f), + SPH_C32(0x8187d438), SPH_C32(0x81246bab), SPH_C32(0x2f5d0000), + SPH_C32(0x70180001), SPH_C32(0x1fe3e280), SPH_C32(0xb9e60000), + SPH_C32(0x18655db1), SPH_C32(0x2ea48b8a), SPH_C32(0x4dc855a2), + SPH_C32(0x2d75e181) }, + { SPH_C32(0xf4780000), SPH_C32(0x79310001), SPH_C32(0x56492280), + SPH_C32(0x38070000), SPH_C32(0xd29b36e8), SPH_C32(0x6cddbfbb), + SPH_C32(0x0e9e3ed4), SPH_C32(0xc5195baf), SPH_C32(0xe3490000), + SPH_C32(0xd57b0001), SPH_C32(0x455ae500), SPH_C32(0x82b60000), + SPH_C32(0x53b54e4e), SPH_C32(0xa93fbf92), SPH_C32(0x248b1d63), + SPH_C32(0xe72f667f) }, + { SPH_C32(0x386c0000), SPH_C32(0xdc520001), SPH_C32(0x0cf02500), + SPH_C32(0x03570000), SPH_C32(0x994b2517), SPH_C32(0xeb468ba3), + SPH_C32(0x67dd7615), SPH_C32(0x0f43dc51), SPH_C32(0x62d70000), + SPH_C32(0x392c0001), SPH_C32(0x2368e780), SPH_C32(0x17450000), + SPH_C32(0x0e1c664c), SPH_C32(0xe1cb832e), SPH_C32(0xc2d1bf4e), + SPH_C32(0x6948d185) }, + { SPH_C32(0x0dc50000), SPH_C32(0x879a0001), SPH_C32(0x99412b80), + SPH_C32(0x3d510000), SPH_C32(0xfe0c3693), SPH_C32(0x5ac00a23), + SPH_C32(0x18483c9b), SPH_C32(0x281167fe), SPH_C32(0xac6c0000), + SPH_C32(0x2b670001), SPH_C32(0xc3cde300), SPH_C32(0x7a8d0000), + SPH_C32(0xff413060), SPH_C32(0xe6187151), SPH_C32(0x02cee315), + SPH_C32(0x57e4bc00) }, + { SPH_C32(0xc1d10000), SPH_C32(0x22f90001), SPH_C32(0xc3f82c00), + SPH_C32(0x06010000), SPH_C32(0xb5dc256c), SPH_C32(0xdd5b3e3b), + SPH_C32(0x710b745a), SPH_C32(0xe24be000), SPH_C32(0x2df20000), + SPH_C32(0xc7300001), SPH_C32(0xa5ffe180), SPH_C32(0xef7e0000), + SPH_C32(0xa2e81862), SPH_C32(0xaeec4ded), SPH_C32(0xe4944138), + SPH_C32(0xd9830bfa) }, + { SPH_C32(0x8c5b0000), SPH_C32(0x6bcd0001), SPH_C32(0xff732900), + SPH_C32(0xa8a20000), SPH_C32(0xa3a51e91), SPH_C32(0x1234369f), + SPH_C32(0xfe129eb6), SPH_C32(0xa676d004), SPH_C32(0xe1e60000), + SPH_C32(0x62530001), SPH_C32(0xff46e600), SPH_C32(0xd42e0000), + SPH_C32(0xe9380b9d), SPH_C32(0x297779f5), SPH_C32(0x8dd709f9), + SPH_C32(0x13d98c04) }, + { SPH_C32(0x404f0000), SPH_C32(0xceae0001), SPH_C32(0xa5ca2e80), + SPH_C32(0x93f20000), SPH_C32(0xe8750d6e), SPH_C32(0x95af0287), + SPH_C32(0x9751d677), SPH_C32(0x6c2c57fa), SPH_C32(0x60780000), + SPH_C32(0x8e040001), SPH_C32(0x9974e480), SPH_C32(0x41dd0000), + SPH_C32(0xb491239f), SPH_C32(0x61834549), SPH_C32(0x6b8dabd4), + SPH_C32(0x9dbe3bfe) }, + { SPH_C32(0x77490000), SPH_C32(0x224e0001), SPH_C32(0x8a672300), + SPH_C32(0xfb6c0000), SPH_C32(0x35bf5b39), SPH_C32(0xa4614560), + SPH_C32(0x41988863), SPH_C32(0xbf88062e), SPH_C32(0xd44f0000), + SPH_C32(0x399b0001), SPH_C32(0x6af7e880), SPH_C32(0xea280000), + SPH_C32(0x8e7f1819), SPH_C32(0x98f1f875), SPH_C32(0xf2424377), + SPH_C32(0x348b37ab) }, + { SPH_C32(0xbb5d0000), SPH_C32(0x872d0001), SPH_C32(0xd0de2480), + SPH_C32(0xc03c0000), SPH_C32(0x7e6f48c6), SPH_C32(0x23fa7178), + SPH_C32(0x28dbc0a2), SPH_C32(0x75d281d0), SPH_C32(0x55d10000), + SPH_C32(0xd5cc0001), SPH_C32(0x0cc5ea00), SPH_C32(0x7fdb0000), + SPH_C32(0xd3d6301b), SPH_C32(0xd005c4c9), SPH_C32(0x1418e15a), + SPH_C32(0xbaec8051) }, + { SPH_C32(0xf6d70000), SPH_C32(0xce190001), SPH_C32(0xec552180), + SPH_C32(0x6e9f0000), SPH_C32(0x6816733b), SPH_C32(0xec9579dc), + SPH_C32(0xa7c22a4e), SPH_C32(0x31efb1d4), SPH_C32(0x99c50000), + SPH_C32(0x70af0001), SPH_C32(0x567ced80), SPH_C32(0x448b0000), + SPH_C32(0x980623e4), SPH_C32(0x579ef0d1), SPH_C32(0x7d5ba99b), + SPH_C32(0x70b607af) }, + { SPH_C32(0x3ac30000), SPH_C32(0x6b7a0001), SPH_C32(0xb6ec2600), + SPH_C32(0x55cf0000), SPH_C32(0x23c660c4), SPH_C32(0x6b0e4dc4), + SPH_C32(0xce81628f), SPH_C32(0xfbb5362a), SPH_C32(0x185b0000), + SPH_C32(0x9cf80001), SPH_C32(0x304eef00), SPH_C32(0xd1780000), + SPH_C32(0xc5af0be6), SPH_C32(0x1f6acc6d), SPH_C32(0x9b010bb6), + SPH_C32(0xfed1b055) }, + { SPH_C32(0x0f6a0000), SPH_C32(0x30b20001), SPH_C32(0x235d2880), + SPH_C32(0x6bc90000), SPH_C32(0x44817340), SPH_C32(0xda88cc44), + SPH_C32(0xb1142801), SPH_C32(0xdce78d85), SPH_C32(0xd6e00000), + SPH_C32(0x8eb30001), SPH_C32(0xd0ebeb80), SPH_C32(0xbcb00000), + SPH_C32(0x34f25dca), SPH_C32(0x18b93e12), SPH_C32(0x5b1e57ed), + SPH_C32(0xc07dddd0) }, + { SPH_C32(0xc37e0000), SPH_C32(0x95d10001), SPH_C32(0x79e42f00), + SPH_C32(0x50990000), SPH_C32(0x0f5160bf), SPH_C32(0x5d13f85c), + SPH_C32(0xd85760c0), SPH_C32(0x16bd0a7b), SPH_C32(0x577e0000), + SPH_C32(0x62e40001), SPH_C32(0xb6d9e900), SPH_C32(0x29430000), + SPH_C32(0x695b75c8), SPH_C32(0x504d02ae), SPH_C32(0xbd44f5c0), + SPH_C32(0x4e1a6a2a) }, + { SPH_C32(0x8ef40000), SPH_C32(0xdce50001), SPH_C32(0x456f2a00), + SPH_C32(0xfe3a0000), SPH_C32(0x19285b42), SPH_C32(0x927cf0f8), + SPH_C32(0x574e8a2c), SPH_C32(0x52803a7f), SPH_C32(0x9b6a0000), + SPH_C32(0xc7870001), SPH_C32(0xec60ee80), SPH_C32(0x12130000), + SPH_C32(0x228b6637), SPH_C32(0xd7d636b6), SPH_C32(0xd407bd01), + SPH_C32(0x8440edd4) }, + { SPH_C32(0x42e00000), SPH_C32(0x79860001), SPH_C32(0x1fd62d80), + SPH_C32(0xc56a0000), SPH_C32(0x52f848bd), SPH_C32(0x15e7c4e0), + SPH_C32(0x3e0dc2ed), SPH_C32(0x98dabd81), SPH_C32(0x1af40000), + SPH_C32(0x2bd00001), SPH_C32(0x8a52ec00), SPH_C32(0x87e00000), + SPH_C32(0x7f224e35), SPH_C32(0x9f220a0a), SPH_C32(0x325d1f2c), + SPH_C32(0x0a275a2e) }, + { SPH_C32(0xd9ae0000), SPH_C32(0x8ec00001), SPH_C32(0x75803380), + SPH_C32(0xaeb70000), SPH_C32(0xd5b72f80), SPH_C32(0x3b9bd3b1), + SPH_C32(0x16b65b07), SPH_C32(0xda9a94a3), SPH_C32(0xb08d0000), + SPH_C32(0x42800001), SPH_C32(0x1429e180), SPH_C32(0x5b310000), + SPH_C32(0xa98b722d), SPH_C32(0x92f0de78), SPH_C32(0x6631ef9d), + SPH_C32(0x3bb81f15) }, + { SPH_C32(0x15ba0000), SPH_C32(0x2ba30001), SPH_C32(0x2f393400), + SPH_C32(0x95e70000), SPH_C32(0x9e673c7f), SPH_C32(0xbc00e7a9), + SPH_C32(0x7ff513c6), SPH_C32(0x10c0135d), SPH_C32(0x31130000), + SPH_C32(0xaed70001), SPH_C32(0x721be300), SPH_C32(0xcec20000), + SPH_C32(0xf4225a2f), SPH_C32(0xda04e2c4), SPH_C32(0x806b4db0), + SPH_C32(0xb5dfa8ef) }, + { SPH_C32(0x58300000), SPH_C32(0x62970001), SPH_C32(0x13b23100), + SPH_C32(0x3b440000), SPH_C32(0x881e0782), SPH_C32(0x736fef0d), + SPH_C32(0xf0ecf92a), SPH_C32(0x54fd2359), SPH_C32(0xfd070000), + SPH_C32(0x0bb40001), SPH_C32(0x28a2e480), SPH_C32(0xf5920000), + SPH_C32(0xbff249d0), SPH_C32(0x5d9fd6dc), SPH_C32(0xe9280571), + SPH_C32(0x7f852f11) }, + { SPH_C32(0x94240000), SPH_C32(0xc7f40001), SPH_C32(0x490b3680), + SPH_C32(0x00140000), SPH_C32(0xc3ce147d), SPH_C32(0xf4f4db15), + SPH_C32(0x99afb1eb), SPH_C32(0x9ea7a4a7), SPH_C32(0x7c990000), + SPH_C32(0xe7e30001), SPH_C32(0x4e90e600), SPH_C32(0x60610000), + SPH_C32(0xe25b61d2), SPH_C32(0x156bea60), SPH_C32(0x0f72a75c), + SPH_C32(0xf1e298eb) }, + { SPH_C32(0xa18d0000), SPH_C32(0x9c3c0001), SPH_C32(0xdcba3800), + SPH_C32(0x3e120000), SPH_C32(0xa48907f9), SPH_C32(0x45725a95), + SPH_C32(0xe63afb65), SPH_C32(0xb9f51f08), SPH_C32(0xb2220000), + SPH_C32(0xf5a80001), SPH_C32(0xae35e280), SPH_C32(0x0da90000), + SPH_C32(0x130637fe), SPH_C32(0x12b8181f), SPH_C32(0xcf6dfb07), + SPH_C32(0xcf4ef56e) }, + { SPH_C32(0x6d990000), SPH_C32(0x395f0001), SPH_C32(0x86033f80), + SPH_C32(0x05420000), SPH_C32(0xef591406), SPH_C32(0xc2e96e8d), + SPH_C32(0x8f79b3a4), SPH_C32(0x73af98f6), SPH_C32(0x33bc0000), + SPH_C32(0x19ff0001), SPH_C32(0xc807e000), SPH_C32(0x985a0000), + SPH_C32(0x4eaf1ffc), SPH_C32(0x5a4c24a3), SPH_C32(0x2937592a), + SPH_C32(0x41294294) }, + { SPH_C32(0x20130000), SPH_C32(0x706b0001), SPH_C32(0xba883a80), + SPH_C32(0xabe10000), SPH_C32(0xf9202ffb), SPH_C32(0x0d866629), + SPH_C32(0x00605948), SPH_C32(0x3792a8f2), SPH_C32(0xffa80000), + SPH_C32(0xbc9c0001), SPH_C32(0x92bee780), SPH_C32(0xa30a0000), + SPH_C32(0x057f0c03), SPH_C32(0xddd710bb), SPH_C32(0x407411eb), + SPH_C32(0x8b73c56a) }, + { SPH_C32(0xec070000), SPH_C32(0xd5080001), SPH_C32(0xe0313d00), + SPH_C32(0x90b10000), SPH_C32(0xb2f03c04), SPH_C32(0x8a1d5231), + SPH_C32(0x69231189), SPH_C32(0xfdc82f0c), SPH_C32(0x7e360000), + SPH_C32(0x50cb0001), SPH_C32(0xf48ce500), SPH_C32(0x36f90000), + SPH_C32(0x58d62401), SPH_C32(0x95232c07), SPH_C32(0xa62eb3c6), + SPH_C32(0x05147290) }, + { SPH_C32(0xdb010000), SPH_C32(0x39e80001), SPH_C32(0xcf9c3080), + SPH_C32(0xf82f0000), SPH_C32(0x6f3a6a53), SPH_C32(0xbbd315d6), + SPH_C32(0xbfea4f9d), SPH_C32(0x2e6c7ed8), SPH_C32(0xca010000), + SPH_C32(0xe7540001), SPH_C32(0x070fe900), SPH_C32(0x9d0c0000), + SPH_C32(0x62381f87), SPH_C32(0x6c51913b), SPH_C32(0x3fe15b65), + SPH_C32(0xac217ec5) }, + { SPH_C32(0x17150000), SPH_C32(0x9c8b0001), SPH_C32(0x95253700), + SPH_C32(0xc37f0000), SPH_C32(0x24ea79ac), SPH_C32(0x3c4821ce), + SPH_C32(0xd6a9075c), SPH_C32(0xe436f926), SPH_C32(0x4b9f0000), + SPH_C32(0x0b030001), SPH_C32(0x613deb80), SPH_C32(0x08ff0000), + SPH_C32(0x3f913785), SPH_C32(0x24a5ad87), SPH_C32(0xd9bbf948), + SPH_C32(0x2246c93f) }, + { SPH_C32(0x5a9f0000), SPH_C32(0xd5bf0001), SPH_C32(0xa9ae3200), + SPH_C32(0x6ddc0000), SPH_C32(0x32934251), SPH_C32(0xf327296a), + SPH_C32(0x59b0edb0), SPH_C32(0xa00bc922), SPH_C32(0x878b0000), + SPH_C32(0xae600001), SPH_C32(0x3b84ec00), SPH_C32(0x33af0000), + SPH_C32(0x7441247a), SPH_C32(0xa33e999f), SPH_C32(0xb0f8b189), + SPH_C32(0xe81c4ec1) }, + { SPH_C32(0x968b0000), SPH_C32(0x70dc0001), SPH_C32(0xf3173580), + SPH_C32(0x568c0000), SPH_C32(0x794351ae), SPH_C32(0x74bc1d72), + SPH_C32(0x30f3a571), SPH_C32(0x6a514edc), SPH_C32(0x06150000), + SPH_C32(0x42370001), SPH_C32(0x5db6ee80), SPH_C32(0xa65c0000), + SPH_C32(0x29e80c78), SPH_C32(0xebcaa523), SPH_C32(0x56a213a4), + SPH_C32(0x667bf93b) }, + { SPH_C32(0xa3220000), SPH_C32(0x2b140001), SPH_C32(0x66a63b00), + SPH_C32(0x688a0000), SPH_C32(0x1e04422a), SPH_C32(0xc53a9cf2), + SPH_C32(0x4f66efff), SPH_C32(0x4d03f573), SPH_C32(0xc8ae0000), + SPH_C32(0x507c0001), SPH_C32(0xbd13ea00), SPH_C32(0xcb940000), + SPH_C32(0xd8b55a54), SPH_C32(0xec19575c), SPH_C32(0x96bd4fff), + SPH_C32(0x58d794be) }, + { SPH_C32(0x6f360000), SPH_C32(0x8e770001), SPH_C32(0x3c1f3c80), + SPH_C32(0x53da0000), SPH_C32(0x55d451d5), SPH_C32(0x42a1a8ea), + SPH_C32(0x2625a73e), SPH_C32(0x8759728d), SPH_C32(0x49300000), + SPH_C32(0xbc2b0001), SPH_C32(0xdb21e880), SPH_C32(0x5e670000), + SPH_C32(0x851c7256), SPH_C32(0xa4ed6be0), SPH_C32(0x70e7edd2), + SPH_C32(0xd6b02344) }, + { SPH_C32(0x22bc0000), SPH_C32(0xc7430001), SPH_C32(0x00943980), + SPH_C32(0xfd790000), SPH_C32(0x43ad6a28), SPH_C32(0x8dcea04e), + SPH_C32(0xa93c4dd2), SPH_C32(0xc3644289), SPH_C32(0x85240000), + SPH_C32(0x19480001), SPH_C32(0x8198ef00), SPH_C32(0x65370000), + SPH_C32(0xcecc61a9), SPH_C32(0x23765ff8), SPH_C32(0x19a4a513), + SPH_C32(0x1ceaa4ba) }, + { SPH_C32(0xeea80000), SPH_C32(0x62200001), SPH_C32(0x5a2d3e00), + SPH_C32(0xc6290000), SPH_C32(0x087d79d7), SPH_C32(0x0a559456), + SPH_C32(0xc07f0513), SPH_C32(0x093ec577), SPH_C32(0x04ba0000), + SPH_C32(0xf51f0001), SPH_C32(0xe7aaed80), SPH_C32(0xf0c40000), + SPH_C32(0x936549ab), SPH_C32(0x6b826344), SPH_C32(0xfffe073e), + SPH_C32(0x928d1340) }, + { SPH_C32(0x6ba80000), SPH_C32(0x4ba90001), SPH_C32(0x5d832180), + SPH_C32(0xdad00000), SPH_C32(0x63751974), SPH_C32(0xd089ea49), + SPH_C32(0x256784eb), SPH_C32(0xd3d4a53b), SPH_C32(0x1cc50000), + SPH_C32(0x59260001), SPH_C32(0x51d2f200), SPH_C32(0x58720000), + SPH_C32(0xf30e4347), SPH_C32(0x8d428ece), SPH_C32(0x98432863), + SPH_C32(0xaa5c67e3) }, + { SPH_C32(0xa7bc0000), SPH_C32(0xeeca0001), SPH_C32(0x073a2600), + SPH_C32(0xe1800000), SPH_C32(0x28a50a8b), SPH_C32(0x5712de51), + SPH_C32(0x4c24cc2a), SPH_C32(0x198e22c5), SPH_C32(0x9d5b0000), + SPH_C32(0xb5710001), SPH_C32(0x37e0f080), SPH_C32(0xcd810000), + SPH_C32(0xaea76b45), SPH_C32(0xc5b6b272), SPH_C32(0x7e198a4e), + SPH_C32(0x243bd019) }, + { SPH_C32(0xea360000), SPH_C32(0xa7fe0001), SPH_C32(0x3bb12300), + SPH_C32(0x4f230000), SPH_C32(0x3edc3176), SPH_C32(0x987dd6f5), + SPH_C32(0xc33d26c6), SPH_C32(0x5db312c1), SPH_C32(0x514f0000), + SPH_C32(0x10120001), SPH_C32(0x6d59f700), SPH_C32(0xf6d10000), + SPH_C32(0xe57778ba), SPH_C32(0x422d866a), SPH_C32(0x175ac28f), + SPH_C32(0xee6157e7) }, + { SPH_C32(0x26220000), SPH_C32(0x029d0001), SPH_C32(0x61082480), + SPH_C32(0x74730000), SPH_C32(0x750c2289), SPH_C32(0x1fe6e2ed), + SPH_C32(0xaa7e6e07), SPH_C32(0x97e9953f), SPH_C32(0xd0d10000), + SPH_C32(0xfc450001), SPH_C32(0x0b6bf580), SPH_C32(0x63220000), + SPH_C32(0xb8de50b8), SPH_C32(0x0ad9bad6), SPH_C32(0xf10060a2), + SPH_C32(0x6006e01d) }, + { SPH_C32(0x138b0000), SPH_C32(0x59550001), SPH_C32(0xf4b92a00), + SPH_C32(0x4a750000), SPH_C32(0x124b310d), SPH_C32(0xae60636d), + SPH_C32(0xd5eb2489), SPH_C32(0xb0bb2e90), SPH_C32(0x1e6a0000), + SPH_C32(0xee0e0001), SPH_C32(0xebcef100), SPH_C32(0x0eea0000), + SPH_C32(0x49830694), SPH_C32(0x0d0a48a9), SPH_C32(0x311f3cf9), + SPH_C32(0x5eaa8d98) }, + { SPH_C32(0xdf9f0000), SPH_C32(0xfc360001), SPH_C32(0xae002d80), + SPH_C32(0x71250000), SPH_C32(0x599b22f2), SPH_C32(0x29fb5775), + SPH_C32(0xbca86c48), SPH_C32(0x7ae1a96e), SPH_C32(0x9ff40000), + SPH_C32(0x02590001), SPH_C32(0x8dfcf380), SPH_C32(0x9b190000), + SPH_C32(0x142a2e96), SPH_C32(0x45fe7415), SPH_C32(0xd7459ed4), + SPH_C32(0xd0cd3a62) }, + { SPH_C32(0x92150000), SPH_C32(0xb5020001), SPH_C32(0x928b2880), + SPH_C32(0xdf860000), SPH_C32(0x4fe2190f), SPH_C32(0xe6945fd1), + SPH_C32(0x33b186a4), SPH_C32(0x3edc996a), SPH_C32(0x53e00000), + SPH_C32(0xa73a0001), SPH_C32(0xd745f400), SPH_C32(0xa0490000), + SPH_C32(0x5ffa3d69), SPH_C32(0xc265400d), SPH_C32(0xbe06d615), + SPH_C32(0x1a97bd9c) }, + { SPH_C32(0x5e010000), SPH_C32(0x10610001), SPH_C32(0xc8322f00), + SPH_C32(0xe4d60000), SPH_C32(0x04320af0), SPH_C32(0x610f6bc9), + SPH_C32(0x5af2ce65), SPH_C32(0xf4861e94), SPH_C32(0xd27e0000), + SPH_C32(0x4b6d0001), SPH_C32(0xb177f680), SPH_C32(0x35ba0000), + SPH_C32(0x0253156b), SPH_C32(0x8a917cb1), SPH_C32(0x585c7438), + SPH_C32(0x94f00a66) }, + { SPH_C32(0x69070000), SPH_C32(0xfc810001), SPH_C32(0xe79f2280), + SPH_C32(0x8c480000), SPH_C32(0xd9f85ca7), SPH_C32(0x50c12c2e), + SPH_C32(0x8c3b9071), SPH_C32(0x27224f40), SPH_C32(0x66490000), + SPH_C32(0xfcf20001), SPH_C32(0x42f4fa80), SPH_C32(0x9e4f0000), + SPH_C32(0x38bd2eed), SPH_C32(0x73e3c18d), SPH_C32(0xc1939c9b), + SPH_C32(0x3dc50633) }, + { SPH_C32(0xa5130000), SPH_C32(0x59e20001), SPH_C32(0xbd262500), + SPH_C32(0xb7180000), SPH_C32(0x92284f58), SPH_C32(0xd75a1836), + SPH_C32(0xe578d8b0), SPH_C32(0xed78c8be), SPH_C32(0xe7d70000), + SPH_C32(0x10a50001), SPH_C32(0x24c6f800), SPH_C32(0x0bbc0000), + SPH_C32(0x651406ef), SPH_C32(0x3b17fd31), SPH_C32(0x27c93eb6), + SPH_C32(0xb3a2b1c9) }, + { SPH_C32(0xe8990000), SPH_C32(0x10d60001), SPH_C32(0x81ad2000), + SPH_C32(0x19bb0000), SPH_C32(0x845174a5), SPH_C32(0x18351092), + SPH_C32(0x6a61325c), SPH_C32(0xa945f8ba), SPH_C32(0x2bc30000), + SPH_C32(0xb5c60001), SPH_C32(0x7e7fff80), SPH_C32(0x30ec0000), + SPH_C32(0x2ec41510), SPH_C32(0xbc8cc929), SPH_C32(0x4e8a7677), + SPH_C32(0x79f83637) }, + { SPH_C32(0x248d0000), SPH_C32(0xb5b50001), SPH_C32(0xdb142780), + SPH_C32(0x22eb0000), SPH_C32(0xcf81675a), SPH_C32(0x9fae248a), + SPH_C32(0x03227a9d), SPH_C32(0x631f7f44), SPH_C32(0xaa5d0000), + SPH_C32(0x59910001), SPH_C32(0x184dfd00), SPH_C32(0xa51f0000), + SPH_C32(0x736d3d12), SPH_C32(0xf478f595), SPH_C32(0xa8d0d45a), + SPH_C32(0xf79f81cd) }, + { SPH_C32(0x11240000), SPH_C32(0xee7d0001), SPH_C32(0x4ea52900), + SPH_C32(0x1ced0000), SPH_C32(0xa8c674de), SPH_C32(0x2e28a50a), + SPH_C32(0x7cb73013), SPH_C32(0x444dc4eb), SPH_C32(0x64e60000), + SPH_C32(0x4bda0001), SPH_C32(0xf8e8f980), SPH_C32(0xc8d70000), + SPH_C32(0x82306b3e), SPH_C32(0xf3ab07ea), SPH_C32(0x68cf8801), + SPH_C32(0xc933ec48) }, + { SPH_C32(0xdd300000), SPH_C32(0x4b1e0001), SPH_C32(0x141c2e80), + SPH_C32(0x27bd0000), SPH_C32(0xe3166721), SPH_C32(0xa9b39112), + SPH_C32(0x15f478d2), SPH_C32(0x8e174315), SPH_C32(0xe5780000), + SPH_C32(0xa78d0001), SPH_C32(0x9edafb00), SPH_C32(0x5d240000), + SPH_C32(0xdf99433c), SPH_C32(0xbb5f3b56), SPH_C32(0x8e952a2c), + SPH_C32(0x47545bb2) }, + { SPH_C32(0x90ba0000), SPH_C32(0x022a0001), SPH_C32(0x28972b80), + SPH_C32(0x891e0000), SPH_C32(0xf56f5cdc), SPH_C32(0x66dc99b6), + SPH_C32(0x9aed923e), SPH_C32(0xca2a7311), SPH_C32(0x296c0000), + SPH_C32(0x02ee0001), SPH_C32(0xc463fc80), SPH_C32(0x66740000), + SPH_C32(0x944950c3), SPH_C32(0x3cc40f4e), SPH_C32(0xe7d662ed), + SPH_C32(0x8d0edc4c) }, + { SPH_C32(0x5cae0000), SPH_C32(0xa7490001), SPH_C32(0x722e2c00), + SPH_C32(0xb24e0000), SPH_C32(0xbebf4f23), SPH_C32(0xe147adae), + SPH_C32(0xf3aedaff), SPH_C32(0x0070f4ef), SPH_C32(0xa8f20000), + SPH_C32(0xeeb90001), SPH_C32(0xa251fe00), SPH_C32(0xf3870000), + SPH_C32(0xc9e078c1), SPH_C32(0x743033f2), SPH_C32(0x018cc0c0), + SPH_C32(0x03696bb6) }, + { SPH_C32(0xc7e00000), SPH_C32(0x500f0001), SPH_C32(0x18783200), + SPH_C32(0xd9930000), SPH_C32(0x39f0281e), SPH_C32(0xcf3bbaff), + SPH_C32(0xdb154315), SPH_C32(0x4230ddcd), SPH_C32(0x028b0000), + SPH_C32(0x87e90001), SPH_C32(0x3c2af380), SPH_C32(0x2f560000), + SPH_C32(0x1f4944d9), SPH_C32(0x79e2e780), SPH_C32(0x55e03071), + SPH_C32(0x32f62e8d) }, + { SPH_C32(0x0bf40000), SPH_C32(0xf56c0001), SPH_C32(0x42c13580), + SPH_C32(0xe2c30000), SPH_C32(0x72203be1), SPH_C32(0x48a08ee7), + SPH_C32(0xb2560bd4), SPH_C32(0x886a5a33), SPH_C32(0x83150000), + SPH_C32(0x6bbe0001), SPH_C32(0x5a18f100), SPH_C32(0xbaa50000), + SPH_C32(0x42e06cdb), SPH_C32(0x3116db3c), SPH_C32(0xb3ba925c), + SPH_C32(0xbc919977) }, + { SPH_C32(0x467e0000), SPH_C32(0xbc580001), SPH_C32(0x7e4a3080), + SPH_C32(0x4c600000), SPH_C32(0x6459001c), SPH_C32(0x87cf8643), + SPH_C32(0x3d4fe138), SPH_C32(0xcc576a37), SPH_C32(0x4f010000), + SPH_C32(0xcedd0001), SPH_C32(0x00a1f680), SPH_C32(0x81f50000), + SPH_C32(0x09307f24), SPH_C32(0xb68def24), SPH_C32(0xdaf9da9d), + SPH_C32(0x76cb1e89) }, + { SPH_C32(0x8a6a0000), SPH_C32(0x193b0001), SPH_C32(0x24f33700), + SPH_C32(0x77300000), SPH_C32(0x2f8913e3), SPH_C32(0x0054b25b), + SPH_C32(0x540ca9f9), SPH_C32(0x060dedc9), SPH_C32(0xce9f0000), + SPH_C32(0x228a0001), SPH_C32(0x6693f400), SPH_C32(0x14060000), + SPH_C32(0x54995726), SPH_C32(0xfe79d398), SPH_C32(0x3ca378b0), + SPH_C32(0xf8aca973) }, + { SPH_C32(0xbfc30000), SPH_C32(0x42f30001), SPH_C32(0xb1423980), + SPH_C32(0x49360000), SPH_C32(0x48ce0067), SPH_C32(0xb1d233db), + SPH_C32(0x2b99e377), SPH_C32(0x215f5666), SPH_C32(0x00240000), + SPH_C32(0x30c10001), SPH_C32(0x8636f080), SPH_C32(0x79ce0000), + SPH_C32(0xa5c4010a), SPH_C32(0xf9aa21e7), SPH_C32(0xfcbc24eb), + SPH_C32(0xc600c4f6) }, + { SPH_C32(0x73d70000), SPH_C32(0xe7900001), SPH_C32(0xebfb3e00), + SPH_C32(0x72660000), SPH_C32(0x031e1398), SPH_C32(0x364907c3), + SPH_C32(0x42daabb6), SPH_C32(0xeb05d198), SPH_C32(0x81ba0000), + SPH_C32(0xdc960001), SPH_C32(0xe004f200), SPH_C32(0xec3d0000), + SPH_C32(0xf86d2908), SPH_C32(0xb15e1d5b), SPH_C32(0x1ae686c6), + SPH_C32(0x4867730c) }, + { SPH_C32(0x3e5d0000), SPH_C32(0xaea40001), SPH_C32(0xd7703b00), + SPH_C32(0xdcc50000), SPH_C32(0x15672865), SPH_C32(0xf9260f67), + SPH_C32(0xcdc3415a), SPH_C32(0xaf38e19c), SPH_C32(0x4dae0000), + SPH_C32(0x79f50001), SPH_C32(0xbabdf580), SPH_C32(0xd76d0000), + SPH_C32(0xb3bd3af7), SPH_C32(0x36c52943), SPH_C32(0x73a5ce07), + SPH_C32(0x823df4f2) }, + { SPH_C32(0xf2490000), SPH_C32(0x0bc70001), SPH_C32(0x8dc93c80), + SPH_C32(0xe7950000), SPH_C32(0x5eb73b9a), SPH_C32(0x7ebd3b7f), + SPH_C32(0xa480099b), SPH_C32(0x65626662), SPH_C32(0xcc300000), + SPH_C32(0x95a20001), SPH_C32(0xdc8ff700), SPH_C32(0x429e0000), + SPH_C32(0xee1412f5), SPH_C32(0x7e3115ff), SPH_C32(0x95ff6c2a), + SPH_C32(0x0c5a4308) }, + { SPH_C32(0xc54f0000), SPH_C32(0xe7270001), SPH_C32(0xa2643100), + SPH_C32(0x8f0b0000), SPH_C32(0x837d6dcd), SPH_C32(0x4f737c98), + SPH_C32(0x7249578f), SPH_C32(0xb6c637b6), SPH_C32(0x78070000), + SPH_C32(0x223d0001), SPH_C32(0x2f0cfb00), SPH_C32(0xe96b0000), + SPH_C32(0xd4fa2973), SPH_C32(0x8743a8c3), SPH_C32(0x0c308489), + SPH_C32(0xa56f4f5d) }, + { SPH_C32(0x095b0000), SPH_C32(0x42440001), SPH_C32(0xf8dd3680), + SPH_C32(0xb45b0000), SPH_C32(0xc8ad7e32), SPH_C32(0xc8e84880), + SPH_C32(0x1b0a1f4e), SPH_C32(0x7c9cb048), SPH_C32(0xf9990000), + SPH_C32(0xce6a0001), SPH_C32(0x493ef980), SPH_C32(0x7c980000), + SPH_C32(0x89530171), SPH_C32(0xcfb7947f), SPH_C32(0xea6a26a4), + SPH_C32(0x2b08f8a7) }, + { SPH_C32(0x44d10000), SPH_C32(0x0b700001), SPH_C32(0xc4563380), + SPH_C32(0x1af80000), SPH_C32(0xded445cf), SPH_C32(0x07874024), + SPH_C32(0x9413f5a2), SPH_C32(0x38a1804c), SPH_C32(0x358d0000), + SPH_C32(0x6b090001), SPH_C32(0x1387fe00), SPH_C32(0x47c80000), + SPH_C32(0xc283128e), SPH_C32(0x482ca067), SPH_C32(0x83296e65), + SPH_C32(0xe1527f59) }, + { SPH_C32(0x88c50000), SPH_C32(0xae130001), SPH_C32(0x9eef3400), + SPH_C32(0x21a80000), SPH_C32(0x95045630), SPH_C32(0x801c743c), + SPH_C32(0xfd50bd63), SPH_C32(0xf2fb07b2), SPH_C32(0xb4130000), + SPH_C32(0x875e0001), SPH_C32(0x75b5fc80), SPH_C32(0xd23b0000), + SPH_C32(0x9f2a3a8c), SPH_C32(0x00d89cdb), SPH_C32(0x6573cc48), + SPH_C32(0x6f35c8a3) }, + { SPH_C32(0xbd6c0000), SPH_C32(0xf5db0001), SPH_C32(0x0b5e3a80), + SPH_C32(0x1fae0000), SPH_C32(0xf24345b4), SPH_C32(0x319af5bc), + SPH_C32(0x82c5f7ed), SPH_C32(0xd5a9bc1d), SPH_C32(0x7aa80000), + SPH_C32(0x95150001), SPH_C32(0x9510f800), SPH_C32(0xbff30000), + SPH_C32(0x6e776ca0), SPH_C32(0x070b6ea4), SPH_C32(0xa56c9013), + SPH_C32(0x5199a526) }, + { SPH_C32(0x71780000), SPH_C32(0x50b80001), SPH_C32(0x51e73d00), + SPH_C32(0x24fe0000), SPH_C32(0xb993564b), SPH_C32(0xb601c1a4), + SPH_C32(0xeb86bf2c), SPH_C32(0x1ff33be3), SPH_C32(0xfb360000), + SPH_C32(0x79420001), SPH_C32(0xf322fa80), SPH_C32(0x2a000000), + SPH_C32(0x33de44a2), SPH_C32(0x4fff5218), SPH_C32(0x4336323e), + SPH_C32(0xdffe12dc) }, + { SPH_C32(0x3cf20000), SPH_C32(0x198c0001), SPH_C32(0x6d6c3800), + SPH_C32(0x8a5d0000), SPH_C32(0xafea6db6), SPH_C32(0x796ec900), + SPH_C32(0x649f55c0), SPH_C32(0x5bce0be7), SPH_C32(0x37220000), + SPH_C32(0xdc210001), SPH_C32(0xa99bfd00), SPH_C32(0x11500000), + SPH_C32(0x780e575d), SPH_C32(0xc8646600), SPH_C32(0x2a757aff), + SPH_C32(0x15a49522) }, + { SPH_C32(0xf0e60000), SPH_C32(0xbcef0001), SPH_C32(0x37d53f80), + SPH_C32(0xb10d0000), SPH_C32(0xe43a7e49), SPH_C32(0xfef5fd18), + SPH_C32(0x0ddc1d01), SPH_C32(0x91948c19), SPH_C32(0xb6bc0000), + SPH_C32(0x30760001), SPH_C32(0xcfa9ff80), SPH_C32(0x84a30000), + SPH_C32(0x25a77f5f), SPH_C32(0x80905abc), SPH_C32(0xcc2fd8d2), + SPH_C32(0x9bc322d8) } +}; + +static const sph_u32 T512_40[256][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0x58430000), SPH_C32(0x807e0000), SPH_C32(0x78330001), + SPH_C32(0xc66b3800), SPH_C32(0xe7375cdc), SPH_C32(0x79ad3fdd), + SPH_C32(0xac73fe6f), SPH_C32(0x3a4479b1), SPH_C32(0x1d5a0000), + SPH_C32(0x2b720000), SPH_C32(0x488d0000), SPH_C32(0xaf611800), + SPH_C32(0x25cb2ec5), SPH_C32(0xc879bfd0), SPH_C32(0x81a20429), + SPH_C32(0x1e7536a6) }, + { SPH_C32(0x1d5a0000), SPH_C32(0x2b720000), SPH_C32(0x488d0000), + SPH_C32(0xaf611800), SPH_C32(0x25cb2ec5), SPH_C32(0xc879bfd0), + SPH_C32(0x81a20429), SPH_C32(0x1e7536a6), SPH_C32(0x45190000), + SPH_C32(0xab0c0000), SPH_C32(0x30be0001), SPH_C32(0x690a2000), + SPH_C32(0xc2fc7219), SPH_C32(0xb1d4800d), SPH_C32(0x2dd1fa46), + SPH_C32(0x24314f17) }, + { SPH_C32(0x45190000), SPH_C32(0xab0c0000), SPH_C32(0x30be0001), + SPH_C32(0x690a2000), SPH_C32(0xc2fc7219), SPH_C32(0xb1d4800d), + SPH_C32(0x2dd1fa46), SPH_C32(0x24314f17), SPH_C32(0x58430000), + SPH_C32(0x807e0000), SPH_C32(0x78330001), SPH_C32(0xc66b3800), + SPH_C32(0xe7375cdc), SPH_C32(0x79ad3fdd), SPH_C32(0xac73fe6f), + SPH_C32(0x3a4479b1) }, + { SPH_C32(0xa53b0000), SPH_C32(0x14260000), SPH_C32(0x4e30001e), + SPH_C32(0x7cae0000), SPH_C32(0x8f9e0dd5), SPH_C32(0x78dfaa3d), + SPH_C32(0xf73168d8), SPH_C32(0x0b1b4946), SPH_C32(0x07ed0000), + SPH_C32(0xb2500000), SPH_C32(0x8774000a), SPH_C32(0x970d0000), + SPH_C32(0x437223ae), SPH_C32(0x48c76ea4), SPH_C32(0xf4786222), + SPH_C32(0x9075b1ce) }, + { SPH_C32(0xfd780000), SPH_C32(0x94580000), SPH_C32(0x3603001f), + SPH_C32(0xbac53800), SPH_C32(0x68a95109), SPH_C32(0x017295e0), + SPH_C32(0x5b4296b7), SPH_C32(0x315f30f7), SPH_C32(0x1ab70000), + SPH_C32(0x99220000), SPH_C32(0xcff9000a), SPH_C32(0x386c1800), + SPH_C32(0x66b90d6b), SPH_C32(0x80bed174), SPH_C32(0x75da660b), + SPH_C32(0x8e008768) }, + { SPH_C32(0xb8610000), SPH_C32(0x3f540000), SPH_C32(0x06bd001e), + SPH_C32(0xd3cf1800), SPH_C32(0xaa552310), SPH_C32(0xb0a615ed), + SPH_C32(0x76936cf1), SPH_C32(0x156e7fe0), SPH_C32(0x42f40000), + SPH_C32(0x195c0000), SPH_C32(0xb7ca000b), SPH_C32(0xfe072000), + SPH_C32(0x818e51b7), SPH_C32(0xf913eea9), SPH_C32(0xd9a99864), + SPH_C32(0xb444fed9) }, + { SPH_C32(0xe0220000), SPH_C32(0xbf2a0000), SPH_C32(0x7e8e001f), + SPH_C32(0x15a42000), SPH_C32(0x4d627fcc), SPH_C32(0xc90b2a30), + SPH_C32(0xdae0929e), SPH_C32(0x2f2a0651), SPH_C32(0x5fae0000), + SPH_C32(0x322e0000), SPH_C32(0xff47000b), SPH_C32(0x51663800), + SPH_C32(0xa4457f72), SPH_C32(0x316a5179), SPH_C32(0x580b9c4d), + SPH_C32(0xaa31c87f) }, + { SPH_C32(0x07ed0000), SPH_C32(0xb2500000), SPH_C32(0x8774000a), + SPH_C32(0x970d0000), SPH_C32(0x437223ae), SPH_C32(0x48c76ea4), + SPH_C32(0xf4786222), SPH_C32(0x9075b1ce), SPH_C32(0xa2d60000), + SPH_C32(0xa6760000), SPH_C32(0xc9440014), SPH_C32(0xeba30000), + SPH_C32(0xccec2e7b), SPH_C32(0x3018c499), SPH_C32(0x03490afa), + SPH_C32(0x9b6ef888) }, + { SPH_C32(0x5fae0000), SPH_C32(0x322e0000), SPH_C32(0xff47000b), + SPH_C32(0x51663800), SPH_C32(0xa4457f72), SPH_C32(0x316a5179), + SPH_C32(0x580b9c4d), SPH_C32(0xaa31c87f), SPH_C32(0xbf8c0000), + SPH_C32(0x8d040000), SPH_C32(0x81c90014), SPH_C32(0x44c21800), + SPH_C32(0xe92700be), SPH_C32(0xf8617b49), SPH_C32(0x82eb0ed3), + SPH_C32(0x851bce2e) }, + { SPH_C32(0x1ab70000), SPH_C32(0x99220000), SPH_C32(0xcff9000a), + SPH_C32(0x386c1800), SPH_C32(0x66b90d6b), SPH_C32(0x80bed174), + SPH_C32(0x75da660b), SPH_C32(0x8e008768), SPH_C32(0xe7cf0000), + SPH_C32(0x0d7a0000), SPH_C32(0xf9fa0015), SPH_C32(0x82a92000), + SPH_C32(0x0e105c62), SPH_C32(0x81cc4494), SPH_C32(0x2e98f0bc), + SPH_C32(0xbf5fb79f) }, + { SPH_C32(0x42f40000), SPH_C32(0x195c0000), SPH_C32(0xb7ca000b), + SPH_C32(0xfe072000), SPH_C32(0x818e51b7), SPH_C32(0xf913eea9), + SPH_C32(0xd9a99864), SPH_C32(0xb444fed9), SPH_C32(0xfa950000), + SPH_C32(0x26080000), SPH_C32(0xb1770015), SPH_C32(0x2dc83800), + SPH_C32(0x2bdb72a7), SPH_C32(0x49b5fb44), SPH_C32(0xaf3af495), + SPH_C32(0xa12a8139) }, + { SPH_C32(0xa2d60000), SPH_C32(0xa6760000), SPH_C32(0xc9440014), + SPH_C32(0xeba30000), SPH_C32(0xccec2e7b), SPH_C32(0x3018c499), + SPH_C32(0x03490afa), SPH_C32(0x9b6ef888), SPH_C32(0xa53b0000), + SPH_C32(0x14260000), SPH_C32(0x4e30001e), SPH_C32(0x7cae0000), + SPH_C32(0x8f9e0dd5), SPH_C32(0x78dfaa3d), SPH_C32(0xf73168d8), + SPH_C32(0x0b1b4946) }, + { SPH_C32(0xfa950000), SPH_C32(0x26080000), SPH_C32(0xb1770015), + SPH_C32(0x2dc83800), SPH_C32(0x2bdb72a7), SPH_C32(0x49b5fb44), + SPH_C32(0xaf3af495), SPH_C32(0xa12a8139), SPH_C32(0xb8610000), + SPH_C32(0x3f540000), SPH_C32(0x06bd001e), SPH_C32(0xd3cf1800), + SPH_C32(0xaa552310), SPH_C32(0xb0a615ed), SPH_C32(0x76936cf1), + SPH_C32(0x156e7fe0) }, + { SPH_C32(0xbf8c0000), SPH_C32(0x8d040000), SPH_C32(0x81c90014), + SPH_C32(0x44c21800), SPH_C32(0xe92700be), SPH_C32(0xf8617b49), + SPH_C32(0x82eb0ed3), SPH_C32(0x851bce2e), SPH_C32(0xe0220000), + SPH_C32(0xbf2a0000), SPH_C32(0x7e8e001f), SPH_C32(0x15a42000), + SPH_C32(0x4d627fcc), SPH_C32(0xc90b2a30), SPH_C32(0xdae0929e), + SPH_C32(0x2f2a0651) }, + { SPH_C32(0xe7cf0000), SPH_C32(0x0d7a0000), SPH_C32(0xf9fa0015), + SPH_C32(0x82a92000), SPH_C32(0x0e105c62), SPH_C32(0x81cc4494), + SPH_C32(0x2e98f0bc), SPH_C32(0xbf5fb79f), SPH_C32(0xfd780000), + SPH_C32(0x94580000), SPH_C32(0x3603001f), SPH_C32(0xbac53800), + SPH_C32(0x68a95109), SPH_C32(0x017295e0), SPH_C32(0x5b4296b7), + SPH_C32(0x315f30f7) }, + { SPH_C32(0x88980000), SPH_C32(0x1f940000), SPH_C32(0x7fcf002e), + SPH_C32(0xfb4e0000), SPH_C32(0xf158079a), SPH_C32(0x61ae9167), + SPH_C32(0xa895706c), SPH_C32(0xe6107494), SPH_C32(0x0bc20000), + SPH_C32(0xdb630000), SPH_C32(0x7e88000c), SPH_C32(0x15860000), + SPH_C32(0x91fd48f3), SPH_C32(0x7581bb43), SPH_C32(0xf460449e), + SPH_C32(0xd8b61463) }, + { SPH_C32(0xd0db0000), SPH_C32(0x9fea0000), SPH_C32(0x07fc002f), + SPH_C32(0x3d253800), SPH_C32(0x166f5b46), SPH_C32(0x1803aeba), + SPH_C32(0x04e68e03), SPH_C32(0xdc540d25), SPH_C32(0x16980000), + SPH_C32(0xf0110000), SPH_C32(0x3605000c), SPH_C32(0xbae71800), + SPH_C32(0xb4366636), SPH_C32(0xbdf80493), SPH_C32(0x75c240b7), + SPH_C32(0xc6c322c5) }, + { SPH_C32(0x95c20000), SPH_C32(0x34e60000), SPH_C32(0x3742002e), + SPH_C32(0x542f1800), SPH_C32(0xd493295f), SPH_C32(0xa9d72eb7), + SPH_C32(0x29377445), SPH_C32(0xf8654232), SPH_C32(0x4edb0000), + SPH_C32(0x706f0000), SPH_C32(0x4e36000d), SPH_C32(0x7c8c2000), + SPH_C32(0x53013aea), SPH_C32(0xc4553b4e), SPH_C32(0xd9b1bed8), + SPH_C32(0xfc875b74) }, + { SPH_C32(0xcd810000), SPH_C32(0xb4980000), SPH_C32(0x4f71002f), + SPH_C32(0x92442000), SPH_C32(0x33a47583), SPH_C32(0xd07a116a), + SPH_C32(0x85448a2a), SPH_C32(0xc2213b83), SPH_C32(0x53810000), + SPH_C32(0x5b1d0000), SPH_C32(0x06bb000d), SPH_C32(0xd3ed3800), + SPH_C32(0x76ca142f), SPH_C32(0x0c2c849e), SPH_C32(0x5813baf1), + SPH_C32(0xe2f26dd2) }, + { SPH_C32(0x2da30000), SPH_C32(0x0bb20000), SPH_C32(0x31ff0030), + SPH_C32(0x87e00000), SPH_C32(0x7ec60a4f), SPH_C32(0x19713b5a), + SPH_C32(0x5fa418b4), SPH_C32(0xed0b3dd2), SPH_C32(0x0c2f0000), + SPH_C32(0x69330000), SPH_C32(0xf9fc0006), SPH_C32(0x828b0000), + SPH_C32(0xd28f6b5d), SPH_C32(0x3d46d5e7), SPH_C32(0x001826bc), + SPH_C32(0x48c3a5ad) }, + { SPH_C32(0x75e00000), SPH_C32(0x8bcc0000), SPH_C32(0x49cc0031), + SPH_C32(0x418b3800), SPH_C32(0x99f15693), SPH_C32(0x60dc0487), + SPH_C32(0xf3d7e6db), SPH_C32(0xd74f4463), SPH_C32(0x11750000), + SPH_C32(0x42410000), SPH_C32(0xb1710006), SPH_C32(0x2dea1800), + SPH_C32(0xf7444598), SPH_C32(0xf53f6a37), SPH_C32(0x81ba2295), + SPH_C32(0x56b6930b) }, + { SPH_C32(0x30f90000), SPH_C32(0x20c00000), SPH_C32(0x79720030), + SPH_C32(0x28811800), SPH_C32(0x5b0d248a), SPH_C32(0xd108848a), + SPH_C32(0xde061c9d), SPH_C32(0xf37e0b74), SPH_C32(0x49360000), + SPH_C32(0xc23f0000), SPH_C32(0xc9420007), SPH_C32(0xeb812000), + SPH_C32(0x10731944), SPH_C32(0x8c9255ea), SPH_C32(0x2dc9dcfa), + SPH_C32(0x6cf2eaba) }, + { SPH_C32(0x68ba0000), SPH_C32(0xa0be0000), SPH_C32(0x01410031), + SPH_C32(0xeeea2000), SPH_C32(0xbc3a7856), SPH_C32(0xa8a5bb57), + SPH_C32(0x7275e2f2), SPH_C32(0xc93a72c5), SPH_C32(0x546c0000), + SPH_C32(0xe94d0000), SPH_C32(0x81cf0007), SPH_C32(0x44e03800), + SPH_C32(0x35b83781), SPH_C32(0x44ebea3a), SPH_C32(0xac6bd8d3), + SPH_C32(0x7287dc1c) }, + { SPH_C32(0x8f750000), SPH_C32(0xadc40000), SPH_C32(0xf8bb0024), + SPH_C32(0x6c430000), SPH_C32(0xb22a2434), SPH_C32(0x2969ffc3), + SPH_C32(0x5ced124e), SPH_C32(0x7665c55a), SPH_C32(0xa9140000), + SPH_C32(0x7d150000), SPH_C32(0xb7cc0018), SPH_C32(0xfe250000), + SPH_C32(0x5d116688), SPH_C32(0x45997fda), SPH_C32(0xf7294e64), + SPH_C32(0x43d8eceb) }, + { SPH_C32(0xd7360000), SPH_C32(0x2dba0000), SPH_C32(0x80880025), + SPH_C32(0xaa283800), SPH_C32(0x551d78e8), SPH_C32(0x50c4c01e), + SPH_C32(0xf09eec21), SPH_C32(0x4c21bceb), SPH_C32(0xb44e0000), + SPH_C32(0x56670000), SPH_C32(0xff410018), SPH_C32(0x51441800), + SPH_C32(0x78da484d), SPH_C32(0x8de0c00a), SPH_C32(0x768b4a4d), + SPH_C32(0x5dadda4d) }, + { SPH_C32(0x922f0000), SPH_C32(0x86b60000), SPH_C32(0xb0360024), + SPH_C32(0xc3221800), SPH_C32(0x97e10af1), SPH_C32(0xe1104013), + SPH_C32(0xdd4f1667), SPH_C32(0x6810f3fc), SPH_C32(0xec0d0000), + SPH_C32(0xd6190000), SPH_C32(0x87720019), SPH_C32(0x972f2000), + SPH_C32(0x9fed1491), SPH_C32(0xf44dffd7), SPH_C32(0xdaf8b422), + SPH_C32(0x67e9a3fc) }, + { SPH_C32(0xca6c0000), SPH_C32(0x06c80000), SPH_C32(0xc8050025), + SPH_C32(0x05492000), SPH_C32(0x70d6562d), SPH_C32(0x98bd7fce), + SPH_C32(0x713ce808), SPH_C32(0x52548a4d), SPH_C32(0xf1570000), + SPH_C32(0xfd6b0000), SPH_C32(0xcfff0019), SPH_C32(0x384e3800), + SPH_C32(0xba263a54), SPH_C32(0x3c344007), SPH_C32(0x5b5ab00b), + SPH_C32(0x799c955a) }, + { SPH_C32(0x2a4e0000), SPH_C32(0xb9e20000), SPH_C32(0xb68b003a), + SPH_C32(0x10ed0000), SPH_C32(0x3db429e1), SPH_C32(0x51b655fe), + SPH_C32(0xabdc7a96), SPH_C32(0x7d7e8c1c), SPH_C32(0xaef90000), + SPH_C32(0xcf450000), SPH_C32(0x30b80012), SPH_C32(0x69280000), + SPH_C32(0x1e634526), SPH_C32(0x0d5e117e), SPH_C32(0x03512c46), + SPH_C32(0xd3ad5d25) }, + { SPH_C32(0x720d0000), SPH_C32(0x399c0000), SPH_C32(0xceb8003b), + SPH_C32(0xd6863800), SPH_C32(0xda83753d), SPH_C32(0x281b6a23), + SPH_C32(0x07af84f9), SPH_C32(0x473af5ad), SPH_C32(0xb3a30000), + SPH_C32(0xe4370000), SPH_C32(0x78350012), SPH_C32(0xc6491800), + SPH_C32(0x3ba86be3), SPH_C32(0xc527aeae), SPH_C32(0x82f3286f), + SPH_C32(0xcdd86b83) }, + { SPH_C32(0x37140000), SPH_C32(0x92900000), SPH_C32(0xfe06003a), + SPH_C32(0xbf8c1800), SPH_C32(0x187f0724), SPH_C32(0x99cfea2e), + SPH_C32(0x2a7e7ebf), SPH_C32(0x630bbaba), SPH_C32(0xebe00000), + SPH_C32(0x64490000), SPH_C32(0x00060013), SPH_C32(0x00222000), + SPH_C32(0xdc9f373f), SPH_C32(0xbc8a9173), SPH_C32(0x2e80d600), + SPH_C32(0xf79c1232) }, + { SPH_C32(0x6f570000), SPH_C32(0x12ee0000), SPH_C32(0x8635003b), + SPH_C32(0x79e72000), SPH_C32(0xff485bf8), SPH_C32(0xe062d5f3), + SPH_C32(0x860d80d0), SPH_C32(0x594fc30b), SPH_C32(0xf6ba0000), + SPH_C32(0x4f3b0000), SPH_C32(0x488b0013), SPH_C32(0xaf433800), + SPH_C32(0xf95419fa), SPH_C32(0x74f32ea3), SPH_C32(0xaf22d229), + SPH_C32(0xe9e92494) }, + { SPH_C32(0x0bc20000), SPH_C32(0xdb630000), SPH_C32(0x7e88000c), + SPH_C32(0x15860000), SPH_C32(0x91fd48f3), SPH_C32(0x7581bb43), + SPH_C32(0xf460449e), SPH_C32(0xd8b61463), SPH_C32(0x835a0000), + SPH_C32(0xc4f70000), SPH_C32(0x01470022), SPH_C32(0xeec80000), + SPH_C32(0x60a54f69), SPH_C32(0x142f2a24), SPH_C32(0x5cf534f2), + SPH_C32(0x3ea660f7) }, + { SPH_C32(0x53810000), SPH_C32(0x5b1d0000), SPH_C32(0x06bb000d), + SPH_C32(0xd3ed3800), SPH_C32(0x76ca142f), SPH_C32(0x0c2c849e), + SPH_C32(0x5813baf1), SPH_C32(0xe2f26dd2), SPH_C32(0x9e000000), + SPH_C32(0xef850000), SPH_C32(0x49ca0022), SPH_C32(0x41a91800), + SPH_C32(0x456e61ac), SPH_C32(0xdc5695f4), SPH_C32(0xdd5730db), + SPH_C32(0x20d35651) }, + { SPH_C32(0x16980000), SPH_C32(0xf0110000), SPH_C32(0x3605000c), + SPH_C32(0xbae71800), SPH_C32(0xb4366636), SPH_C32(0xbdf80493), + SPH_C32(0x75c240b7), SPH_C32(0xc6c322c5), SPH_C32(0xc6430000), + SPH_C32(0x6ffb0000), SPH_C32(0x31f90023), SPH_C32(0x87c22000), + SPH_C32(0xa2593d70), SPH_C32(0xa5fbaa29), SPH_C32(0x7124ceb4), + SPH_C32(0x1a972fe0) }, + { SPH_C32(0x4edb0000), SPH_C32(0x706f0000), SPH_C32(0x4e36000d), + SPH_C32(0x7c8c2000), SPH_C32(0x53013aea), SPH_C32(0xc4553b4e), + SPH_C32(0xd9b1bed8), SPH_C32(0xfc875b74), SPH_C32(0xdb190000), + SPH_C32(0x44890000), SPH_C32(0x79740023), SPH_C32(0x28a33800), + SPH_C32(0x879213b5), SPH_C32(0x6d8215f9), SPH_C32(0xf086ca9d), + SPH_C32(0x04e21946) }, + { SPH_C32(0xaef90000), SPH_C32(0xcf450000), SPH_C32(0x30b80012), + SPH_C32(0x69280000), SPH_C32(0x1e634526), SPH_C32(0x0d5e117e), + SPH_C32(0x03512c46), SPH_C32(0xd3ad5d25), SPH_C32(0x84b70000), + SPH_C32(0x76a70000), SPH_C32(0x86330028), SPH_C32(0x79c50000), + SPH_C32(0x23d76cc7), SPH_C32(0x5ce84480), SPH_C32(0xa88d56d0), + SPH_C32(0xaed3d139) }, + { SPH_C32(0xf6ba0000), SPH_C32(0x4f3b0000), SPH_C32(0x488b0013), + SPH_C32(0xaf433800), SPH_C32(0xf95419fa), SPH_C32(0x74f32ea3), + SPH_C32(0xaf22d229), SPH_C32(0xe9e92494), SPH_C32(0x99ed0000), + SPH_C32(0x5dd50000), SPH_C32(0xcebe0028), SPH_C32(0xd6a41800), + SPH_C32(0x061c4202), SPH_C32(0x9491fb50), SPH_C32(0x292f52f9), + SPH_C32(0xb0a6e79f) }, + { SPH_C32(0xb3a30000), SPH_C32(0xe4370000), SPH_C32(0x78350012), + SPH_C32(0xc6491800), SPH_C32(0x3ba86be3), SPH_C32(0xc527aeae), + SPH_C32(0x82f3286f), SPH_C32(0xcdd86b83), SPH_C32(0xc1ae0000), + SPH_C32(0xddab0000), SPH_C32(0xb68d0029), SPH_C32(0x10cf2000), + SPH_C32(0xe12b1ede), SPH_C32(0xed3cc48d), SPH_C32(0x855cac96), + SPH_C32(0x8ae29e2e) }, + { SPH_C32(0xebe00000), SPH_C32(0x64490000), SPH_C32(0x00060013), + SPH_C32(0x00222000), SPH_C32(0xdc9f373f), SPH_C32(0xbc8a9173), + SPH_C32(0x2e80d600), SPH_C32(0xf79c1232), SPH_C32(0xdcf40000), + SPH_C32(0xf6d90000), SPH_C32(0xfe000029), SPH_C32(0xbfae3800), + SPH_C32(0xc4e0301b), SPH_C32(0x25457b5d), SPH_C32(0x04fea8bf), + SPH_C32(0x9497a888) }, + { SPH_C32(0x0c2f0000), SPH_C32(0x69330000), SPH_C32(0xf9fc0006), + SPH_C32(0x828b0000), SPH_C32(0xd28f6b5d), SPH_C32(0x3d46d5e7), + SPH_C32(0x001826bc), SPH_C32(0x48c3a5ad), SPH_C32(0x218c0000), + SPH_C32(0x62810000), SPH_C32(0xc8030036), SPH_C32(0x056b0000), + SPH_C32(0xac496112), SPH_C32(0x2437eebd), SPH_C32(0x5fbc3e08), + SPH_C32(0xa5c8987f) }, + { SPH_C32(0x546c0000), SPH_C32(0xe94d0000), SPH_C32(0x81cf0007), + SPH_C32(0x44e03800), SPH_C32(0x35b83781), SPH_C32(0x44ebea3a), + SPH_C32(0xac6bd8d3), SPH_C32(0x7287dc1c), SPH_C32(0x3cd60000), + SPH_C32(0x49f30000), SPH_C32(0x808e0036), SPH_C32(0xaa0a1800), + SPH_C32(0x89824fd7), SPH_C32(0xec4e516d), SPH_C32(0xde1e3a21), + SPH_C32(0xbbbdaed9) }, + { SPH_C32(0x11750000), SPH_C32(0x42410000), SPH_C32(0xb1710006), + SPH_C32(0x2dea1800), SPH_C32(0xf7444598), SPH_C32(0xf53f6a37), + SPH_C32(0x81ba2295), SPH_C32(0x56b6930b), SPH_C32(0x64950000), + SPH_C32(0xc98d0000), SPH_C32(0xf8bd0037), SPH_C32(0x6c612000), + SPH_C32(0x6eb5130b), SPH_C32(0x95e36eb0), SPH_C32(0x726dc44e), + SPH_C32(0x81f9d768) }, + { SPH_C32(0x49360000), SPH_C32(0xc23f0000), SPH_C32(0xc9420007), + SPH_C32(0xeb812000), SPH_C32(0x10731944), SPH_C32(0x8c9255ea), + SPH_C32(0x2dc9dcfa), SPH_C32(0x6cf2eaba), SPH_C32(0x79cf0000), + SPH_C32(0xe2ff0000), SPH_C32(0xb0300037), SPH_C32(0xc3003800), + SPH_C32(0x4b7e3dce), SPH_C32(0x5d9ad160), SPH_C32(0xf3cfc067), + SPH_C32(0x9f8ce1ce) }, + { SPH_C32(0xa9140000), SPH_C32(0x7d150000), SPH_C32(0xb7cc0018), + SPH_C32(0xfe250000), SPH_C32(0x5d116688), SPH_C32(0x45997fda), + SPH_C32(0xf7294e64), SPH_C32(0x43d8eceb), SPH_C32(0x26610000), + SPH_C32(0xd0d10000), SPH_C32(0x4f77003c), SPH_C32(0x92660000), + SPH_C32(0xef3b42bc), SPH_C32(0x6cf08019), SPH_C32(0xabc45c2a), + SPH_C32(0x35bd29b1) }, + { SPH_C32(0xf1570000), SPH_C32(0xfd6b0000), SPH_C32(0xcfff0019), + SPH_C32(0x384e3800), SPH_C32(0xba263a54), SPH_C32(0x3c344007), + SPH_C32(0x5b5ab00b), SPH_C32(0x799c955a), SPH_C32(0x3b3b0000), + SPH_C32(0xfba30000), SPH_C32(0x07fa003c), SPH_C32(0x3d071800), + SPH_C32(0xcaf06c79), SPH_C32(0xa4893fc9), SPH_C32(0x2a665803), + SPH_C32(0x2bc81f17) }, + { SPH_C32(0xb44e0000), SPH_C32(0x56670000), SPH_C32(0xff410018), + SPH_C32(0x51441800), SPH_C32(0x78da484d), SPH_C32(0x8de0c00a), + SPH_C32(0x768b4a4d), SPH_C32(0x5dadda4d), SPH_C32(0x63780000), + SPH_C32(0x7bdd0000), SPH_C32(0x7fc9003d), SPH_C32(0xfb6c2000), + SPH_C32(0x2dc730a5), SPH_C32(0xdd240014), SPH_C32(0x8615a66c), + SPH_C32(0x118c66a6) }, + { SPH_C32(0xec0d0000), SPH_C32(0xd6190000), SPH_C32(0x87720019), + SPH_C32(0x972f2000), SPH_C32(0x9fed1491), SPH_C32(0xf44dffd7), + SPH_C32(0xdaf8b422), SPH_C32(0x67e9a3fc), SPH_C32(0x7e220000), + SPH_C32(0x50af0000), SPH_C32(0x3744003d), SPH_C32(0x540d3800), + SPH_C32(0x080c1e60), SPH_C32(0x155dbfc4), SPH_C32(0x07b7a245), + SPH_C32(0x0ff95000) }, + { SPH_C32(0x835a0000), SPH_C32(0xc4f70000), SPH_C32(0x01470022), + SPH_C32(0xeec80000), SPH_C32(0x60a54f69), SPH_C32(0x142f2a24), + SPH_C32(0x5cf534f2), SPH_C32(0x3ea660f7), SPH_C32(0x88980000), + SPH_C32(0x1f940000), SPH_C32(0x7fcf002e), SPH_C32(0xfb4e0000), + SPH_C32(0xf158079a), SPH_C32(0x61ae9167), SPH_C32(0xa895706c), + SPH_C32(0xe6107494) }, + { SPH_C32(0xdb190000), SPH_C32(0x44890000), SPH_C32(0x79740023), + SPH_C32(0x28a33800), SPH_C32(0x879213b5), SPH_C32(0x6d8215f9), + SPH_C32(0xf086ca9d), SPH_C32(0x04e21946), SPH_C32(0x95c20000), + SPH_C32(0x34e60000), SPH_C32(0x3742002e), SPH_C32(0x542f1800), + SPH_C32(0xd493295f), SPH_C32(0xa9d72eb7), SPH_C32(0x29377445), + SPH_C32(0xf8654232) }, + { SPH_C32(0x9e000000), SPH_C32(0xef850000), SPH_C32(0x49ca0022), + SPH_C32(0x41a91800), SPH_C32(0x456e61ac), SPH_C32(0xdc5695f4), + SPH_C32(0xdd5730db), SPH_C32(0x20d35651), SPH_C32(0xcd810000), + SPH_C32(0xb4980000), SPH_C32(0x4f71002f), SPH_C32(0x92442000), + SPH_C32(0x33a47583), SPH_C32(0xd07a116a), SPH_C32(0x85448a2a), + SPH_C32(0xc2213b83) }, + { SPH_C32(0xc6430000), SPH_C32(0x6ffb0000), SPH_C32(0x31f90023), + SPH_C32(0x87c22000), SPH_C32(0xa2593d70), SPH_C32(0xa5fbaa29), + SPH_C32(0x7124ceb4), SPH_C32(0x1a972fe0), SPH_C32(0xd0db0000), + SPH_C32(0x9fea0000), SPH_C32(0x07fc002f), SPH_C32(0x3d253800), + SPH_C32(0x166f5b46), SPH_C32(0x1803aeba), SPH_C32(0x04e68e03), + SPH_C32(0xdc540d25) }, + { SPH_C32(0x26610000), SPH_C32(0xd0d10000), SPH_C32(0x4f77003c), + SPH_C32(0x92660000), SPH_C32(0xef3b42bc), SPH_C32(0x6cf08019), + SPH_C32(0xabc45c2a), SPH_C32(0x35bd29b1), SPH_C32(0x8f750000), + SPH_C32(0xadc40000), SPH_C32(0xf8bb0024), SPH_C32(0x6c430000), + SPH_C32(0xb22a2434), SPH_C32(0x2969ffc3), SPH_C32(0x5ced124e), + SPH_C32(0x7665c55a) }, + { SPH_C32(0x7e220000), SPH_C32(0x50af0000), SPH_C32(0x3744003d), + SPH_C32(0x540d3800), SPH_C32(0x080c1e60), SPH_C32(0x155dbfc4), + SPH_C32(0x07b7a245), SPH_C32(0x0ff95000), SPH_C32(0x922f0000), + SPH_C32(0x86b60000), SPH_C32(0xb0360024), SPH_C32(0xc3221800), + SPH_C32(0x97e10af1), SPH_C32(0xe1104013), SPH_C32(0xdd4f1667), + SPH_C32(0x6810f3fc) }, + { SPH_C32(0x3b3b0000), SPH_C32(0xfba30000), SPH_C32(0x07fa003c), + SPH_C32(0x3d071800), SPH_C32(0xcaf06c79), SPH_C32(0xa4893fc9), + SPH_C32(0x2a665803), SPH_C32(0x2bc81f17), SPH_C32(0xca6c0000), + SPH_C32(0x06c80000), SPH_C32(0xc8050025), SPH_C32(0x05492000), + SPH_C32(0x70d6562d), SPH_C32(0x98bd7fce), SPH_C32(0x713ce808), + SPH_C32(0x52548a4d) }, + { SPH_C32(0x63780000), SPH_C32(0x7bdd0000), SPH_C32(0x7fc9003d), + SPH_C32(0xfb6c2000), SPH_C32(0x2dc730a5), SPH_C32(0xdd240014), + SPH_C32(0x8615a66c), SPH_C32(0x118c66a6), SPH_C32(0xd7360000), + SPH_C32(0x2dba0000), SPH_C32(0x80880025), SPH_C32(0xaa283800), + SPH_C32(0x551d78e8), SPH_C32(0x50c4c01e), SPH_C32(0xf09eec21), + SPH_C32(0x4c21bceb) }, + { SPH_C32(0x84b70000), SPH_C32(0x76a70000), SPH_C32(0x86330028), + SPH_C32(0x79c50000), SPH_C32(0x23d76cc7), SPH_C32(0x5ce84480), + SPH_C32(0xa88d56d0), SPH_C32(0xaed3d139), SPH_C32(0x2a4e0000), + SPH_C32(0xb9e20000), SPH_C32(0xb68b003a), SPH_C32(0x10ed0000), + SPH_C32(0x3db429e1), SPH_C32(0x51b655fe), SPH_C32(0xabdc7a96), + SPH_C32(0x7d7e8c1c) }, + { SPH_C32(0xdcf40000), SPH_C32(0xf6d90000), SPH_C32(0xfe000029), + SPH_C32(0xbfae3800), SPH_C32(0xc4e0301b), SPH_C32(0x25457b5d), + SPH_C32(0x04fea8bf), SPH_C32(0x9497a888), SPH_C32(0x37140000), + SPH_C32(0x92900000), SPH_C32(0xfe06003a), SPH_C32(0xbf8c1800), + SPH_C32(0x187f0724), SPH_C32(0x99cfea2e), SPH_C32(0x2a7e7ebf), + SPH_C32(0x630bbaba) }, + { SPH_C32(0x99ed0000), SPH_C32(0x5dd50000), SPH_C32(0xcebe0028), + SPH_C32(0xd6a41800), SPH_C32(0x061c4202), SPH_C32(0x9491fb50), + SPH_C32(0x292f52f9), SPH_C32(0xb0a6e79f), SPH_C32(0x6f570000), + SPH_C32(0x12ee0000), SPH_C32(0x8635003b), SPH_C32(0x79e72000), + SPH_C32(0xff485bf8), SPH_C32(0xe062d5f3), SPH_C32(0x860d80d0), + SPH_C32(0x594fc30b) }, + { SPH_C32(0xc1ae0000), SPH_C32(0xddab0000), SPH_C32(0xb68d0029), + SPH_C32(0x10cf2000), SPH_C32(0xe12b1ede), SPH_C32(0xed3cc48d), + SPH_C32(0x855cac96), SPH_C32(0x8ae29e2e), SPH_C32(0x720d0000), + SPH_C32(0x399c0000), SPH_C32(0xceb8003b), SPH_C32(0xd6863800), + SPH_C32(0xda83753d), SPH_C32(0x281b6a23), SPH_C32(0x07af84f9), + SPH_C32(0x473af5ad) }, + { SPH_C32(0x218c0000), SPH_C32(0x62810000), SPH_C32(0xc8030036), + SPH_C32(0x056b0000), SPH_C32(0xac496112), SPH_C32(0x2437eebd), + SPH_C32(0x5fbc3e08), SPH_C32(0xa5c8987f), SPH_C32(0x2da30000), + SPH_C32(0x0bb20000), SPH_C32(0x31ff0030), SPH_C32(0x87e00000), + SPH_C32(0x7ec60a4f), SPH_C32(0x19713b5a), SPH_C32(0x5fa418b4), + SPH_C32(0xed0b3dd2) }, + { SPH_C32(0x79cf0000), SPH_C32(0xe2ff0000), SPH_C32(0xb0300037), + SPH_C32(0xc3003800), SPH_C32(0x4b7e3dce), SPH_C32(0x5d9ad160), + SPH_C32(0xf3cfc067), SPH_C32(0x9f8ce1ce), SPH_C32(0x30f90000), + SPH_C32(0x20c00000), SPH_C32(0x79720030), SPH_C32(0x28811800), + SPH_C32(0x5b0d248a), SPH_C32(0xd108848a), SPH_C32(0xde061c9d), + SPH_C32(0xf37e0b74) }, + { SPH_C32(0x3cd60000), SPH_C32(0x49f30000), SPH_C32(0x808e0036), + SPH_C32(0xaa0a1800), SPH_C32(0x89824fd7), SPH_C32(0xec4e516d), + SPH_C32(0xde1e3a21), SPH_C32(0xbbbdaed9), SPH_C32(0x68ba0000), + SPH_C32(0xa0be0000), SPH_C32(0x01410031), SPH_C32(0xeeea2000), + SPH_C32(0xbc3a7856), SPH_C32(0xa8a5bb57), SPH_C32(0x7275e2f2), + SPH_C32(0xc93a72c5) }, + { SPH_C32(0x64950000), SPH_C32(0xc98d0000), SPH_C32(0xf8bd0037), + SPH_C32(0x6c612000), SPH_C32(0x6eb5130b), SPH_C32(0x95e36eb0), + SPH_C32(0x726dc44e), SPH_C32(0x81f9d768), SPH_C32(0x75e00000), + SPH_C32(0x8bcc0000), SPH_C32(0x49cc0031), SPH_C32(0x418b3800), + SPH_C32(0x99f15693), SPH_C32(0x60dc0487), SPH_C32(0xf3d7e6db), + SPH_C32(0xd74f4463) }, + { SPH_C32(0x52500000), SPH_C32(0x29540000), SPH_C32(0x6a61004e), + SPH_C32(0xf0ff0000), SPH_C32(0x9a317eec), SPH_C32(0x452341ce), + SPH_C32(0xcf568fe5), SPH_C32(0x5303130f), SPH_C32(0x538d0000), + SPH_C32(0xa9fc0000), SPH_C32(0x9ef70006), SPH_C32(0x56ff0000), + SPH_C32(0x0ae4004e), SPH_C32(0x92c5cdf9), SPH_C32(0xa9444018), + SPH_C32(0x7f975691) }, + { SPH_C32(0x0a130000), SPH_C32(0xa92a0000), SPH_C32(0x1252004f), + SPH_C32(0x36943800), SPH_C32(0x7d062230), SPH_C32(0x3c8e7e13), + SPH_C32(0x6325718a), SPH_C32(0x69476abe), SPH_C32(0x4ed70000), + SPH_C32(0x828e0000), SPH_C32(0xd67a0006), SPH_C32(0xf99e1800), + SPH_C32(0x2f2f2e8b), SPH_C32(0x5abc7229), SPH_C32(0x28e64431), + SPH_C32(0x61e26037) }, + { SPH_C32(0x4f0a0000), SPH_C32(0x02260000), SPH_C32(0x22ec004e), + SPH_C32(0x5f9e1800), SPH_C32(0xbffa5029), SPH_C32(0x8d5afe1e), + SPH_C32(0x4ef48bcc), SPH_C32(0x4d7625a9), SPH_C32(0x16940000), + SPH_C32(0x02f00000), SPH_C32(0xae490007), SPH_C32(0x3ff52000), + SPH_C32(0xc8187257), SPH_C32(0x23114df4), SPH_C32(0x8495ba5e), + SPH_C32(0x5ba61986) }, + { SPH_C32(0x17490000), SPH_C32(0x82580000), SPH_C32(0x5adf004f), + SPH_C32(0x99f52000), SPH_C32(0x58cd0cf5), SPH_C32(0xf4f7c1c3), + SPH_C32(0xe28775a3), SPH_C32(0x77325c18), SPH_C32(0x0bce0000), + SPH_C32(0x29820000), SPH_C32(0xe6c40007), SPH_C32(0x90943800), + SPH_C32(0xedd35c92), SPH_C32(0xeb68f224), SPH_C32(0x0537be77), + SPH_C32(0x45d32f20) }, + { SPH_C32(0xf76b0000), SPH_C32(0x3d720000), SPH_C32(0x24510050), + SPH_C32(0x8c510000), SPH_C32(0x15af7339), SPH_C32(0x3dfcebf3), + SPH_C32(0x3867e73d), SPH_C32(0x58185a49), SPH_C32(0x54600000), + SPH_C32(0x1bac0000), SPH_C32(0x1983000c), SPH_C32(0xc1f20000), + SPH_C32(0x499623e0), SPH_C32(0xda02a35d), SPH_C32(0x5d3c223a), + SPH_C32(0xefe2e75f) }, + { SPH_C32(0xaf280000), SPH_C32(0xbd0c0000), SPH_C32(0x5c620051), + SPH_C32(0x4a3a3800), SPH_C32(0xf2982fe5), SPH_C32(0x4451d42e), + SPH_C32(0x94141952), SPH_C32(0x625c23f8), SPH_C32(0x493a0000), + SPH_C32(0x30de0000), SPH_C32(0x510e000c), SPH_C32(0x6e931800), + SPH_C32(0x6c5d0d25), SPH_C32(0x127b1c8d), SPH_C32(0xdc9e2613), + SPH_C32(0xf197d1f9) }, + { SPH_C32(0xea310000), SPH_C32(0x16000000), SPH_C32(0x6cdc0050), + SPH_C32(0x23301800), SPH_C32(0x30645dfc), SPH_C32(0xf5855423), + SPH_C32(0xb9c5e314), SPH_C32(0x466d6cef), SPH_C32(0x11790000), + SPH_C32(0xb0a00000), SPH_C32(0x293d000d), SPH_C32(0xa8f82000), + SPH_C32(0x8b6a51f9), SPH_C32(0x6bd62350), SPH_C32(0x70edd87c), + SPH_C32(0xcbd3a848) }, + { SPH_C32(0xb2720000), SPH_C32(0x967e0000), SPH_C32(0x14ef0051), + SPH_C32(0xe55b2000), SPH_C32(0xd7530120), SPH_C32(0x8c286bfe), + SPH_C32(0x15b61d7b), SPH_C32(0x7c29155e), SPH_C32(0x0c230000), + SPH_C32(0x9bd20000), SPH_C32(0x61b0000d), SPH_C32(0x07993800), + SPH_C32(0xaea17f3c), SPH_C32(0xa3af9c80), SPH_C32(0xf14fdc55), + SPH_C32(0xd5a69eee) }, + { SPH_C32(0x55bd0000), SPH_C32(0x9b040000), SPH_C32(0xed150044), + SPH_C32(0x67f20000), SPH_C32(0xd9435d42), SPH_C32(0x0de42f6a), + SPH_C32(0x3b2eedc7), SPH_C32(0xc376a2c1), SPH_C32(0xf15b0000), + SPH_C32(0x0f8a0000), SPH_C32(0x57b30012), SPH_C32(0xbd5c0000), + SPH_C32(0xc6082e35), SPH_C32(0xa2dd0960), SPH_C32(0xaa0d4ae2), + SPH_C32(0xe4f9ae19) }, + { SPH_C32(0x0dfe0000), SPH_C32(0x1b7a0000), SPH_C32(0x95260045), + SPH_C32(0xa1993800), SPH_C32(0x3e74019e), SPH_C32(0x744910b7), + SPH_C32(0x975d13a8), SPH_C32(0xf932db70), SPH_C32(0xec010000), + SPH_C32(0x24f80000), SPH_C32(0x1f3e0012), SPH_C32(0x123d1800), + SPH_C32(0xe3c300f0), SPH_C32(0x6aa4b6b0), SPH_C32(0x2baf4ecb), + SPH_C32(0xfa8c98bf) }, + { SPH_C32(0x48e70000), SPH_C32(0xb0760000), SPH_C32(0xa5980044), + SPH_C32(0xc8931800), SPH_C32(0xfc887387), SPH_C32(0xc59d90ba), + SPH_C32(0xba8ce9ee), SPH_C32(0xdd039467), SPH_C32(0xb4420000), + SPH_C32(0xa4860000), SPH_C32(0x670d0013), SPH_C32(0xd4562000), + SPH_C32(0x04f45c2c), SPH_C32(0x1309896d), SPH_C32(0x87dcb0a4), + SPH_C32(0xc0c8e10e) }, + { SPH_C32(0x10a40000), SPH_C32(0x30080000), SPH_C32(0xddab0045), + SPH_C32(0x0ef82000), SPH_C32(0x1bbf2f5b), SPH_C32(0xbc30af67), + SPH_C32(0x16ff1781), SPH_C32(0xe747edd6), SPH_C32(0xa9180000), + SPH_C32(0x8ff40000), SPH_C32(0x2f800013), SPH_C32(0x7b373800), + SPH_C32(0x213f72e9), SPH_C32(0xdb7036bd), SPH_C32(0x067eb48d), + SPH_C32(0xdebdd7a8) }, + { SPH_C32(0xf0860000), SPH_C32(0x8f220000), SPH_C32(0xa325005a), + SPH_C32(0x1b5c0000), SPH_C32(0x56dd5097), SPH_C32(0x753b8557), + SPH_C32(0xcc1f851f), SPH_C32(0xc86deb87), SPH_C32(0xf6b60000), + SPH_C32(0xbdda0000), SPH_C32(0xd0c70018), SPH_C32(0x2a510000), + SPH_C32(0x857a0d9b), SPH_C32(0xea1a67c4), SPH_C32(0x5e7528c0), + SPH_C32(0x748c1fd7) }, + { SPH_C32(0xa8c50000), SPH_C32(0x0f5c0000), SPH_C32(0xdb16005b), + SPH_C32(0xdd373800), SPH_C32(0xb1ea0c4b), SPH_C32(0x0c96ba8a), + SPH_C32(0x606c7b70), SPH_C32(0xf2299236), SPH_C32(0xebec0000), + SPH_C32(0x96a80000), SPH_C32(0x984a0018), SPH_C32(0x85301800), + SPH_C32(0xa0b1235e), SPH_C32(0x2263d814), SPH_C32(0xdfd72ce9), + SPH_C32(0x6af92971) }, + { SPH_C32(0xeddc0000), SPH_C32(0xa4500000), SPH_C32(0xeba8005a), + SPH_C32(0xb43d1800), SPH_C32(0x73167e52), SPH_C32(0xbd423a87), + SPH_C32(0x4dbd8136), SPH_C32(0xd618dd21), SPH_C32(0xb3af0000), + SPH_C32(0x16d60000), SPH_C32(0xe0790019), SPH_C32(0x435b2000), + SPH_C32(0x47867f82), SPH_C32(0x5bcee7c9), SPH_C32(0x73a4d286), + SPH_C32(0x50bd50c0) }, + { SPH_C32(0xb59f0000), SPH_C32(0x242e0000), SPH_C32(0x939b005b), + SPH_C32(0x72562000), SPH_C32(0x9421228e), SPH_C32(0xc4ef055a), + SPH_C32(0xe1ce7f59), SPH_C32(0xec5ca490), SPH_C32(0xaef50000), + SPH_C32(0x3da40000), SPH_C32(0xa8f40019), SPH_C32(0xec3a3800), + SPH_C32(0x624d5147), SPH_C32(0x93b75819), SPH_C32(0xf206d6af), + SPH_C32(0x4ec86666) }, + { SPH_C32(0xdac80000), SPH_C32(0x36c00000), SPH_C32(0x15ae0060), + SPH_C32(0x0bb10000), SPH_C32(0x6b697976), SPH_C32(0x248dd0a9), + SPH_C32(0x67c3ff89), SPH_C32(0xb513679b), SPH_C32(0x584f0000), + SPH_C32(0x729f0000), SPH_C32(0xe07f000a), SPH_C32(0x43790000), + SPH_C32(0x9b1948bd), SPH_C32(0xe74476ba), SPH_C32(0x5d240486), + SPH_C32(0xa72142f2) }, + { SPH_C32(0x828b0000), SPH_C32(0xb6be0000), SPH_C32(0x6d9d0061), + SPH_C32(0xcdda3800), SPH_C32(0x8c5e25aa), SPH_C32(0x5d20ef74), + SPH_C32(0xcbb001e6), SPH_C32(0x8f571e2a), SPH_C32(0x45150000), + SPH_C32(0x59ed0000), SPH_C32(0xa8f2000a), SPH_C32(0xec181800), + SPH_C32(0xbed26678), SPH_C32(0x2f3dc96a), SPH_C32(0xdc8600af), + SPH_C32(0xb9547454) }, + { SPH_C32(0xc7920000), SPH_C32(0x1db20000), SPH_C32(0x5d230060), + SPH_C32(0xa4d01800), SPH_C32(0x4ea257b3), SPH_C32(0xecf46f79), + SPH_C32(0xe661fba0), SPH_C32(0xab66513d), SPH_C32(0x1d560000), + SPH_C32(0xd9930000), SPH_C32(0xd0c1000b), SPH_C32(0x2a732000), + SPH_C32(0x59e53aa4), SPH_C32(0x5690f6b7), SPH_C32(0x70f5fec0), + SPH_C32(0x83100de5) }, + { SPH_C32(0x9fd10000), SPH_C32(0x9dcc0000), SPH_C32(0x25100061), + SPH_C32(0x62bb2000), SPH_C32(0xa9950b6f), SPH_C32(0x955950a4), + SPH_C32(0x4a1205cf), SPH_C32(0x9122288c), SPH_C32(0x000c0000), + SPH_C32(0xf2e10000), SPH_C32(0x984c000b), SPH_C32(0x85123800), + SPH_C32(0x7c2e1461), SPH_C32(0x9ee94967), SPH_C32(0xf157fae9), + SPH_C32(0x9d653b43) }, + { SPH_C32(0x7ff30000), SPH_C32(0x22e60000), SPH_C32(0x5b9e007e), + SPH_C32(0x771f0000), SPH_C32(0xe4f774a3), SPH_C32(0x5c527a94), + SPH_C32(0x90f29751), SPH_C32(0xbe082edd), SPH_C32(0x5fa20000), + SPH_C32(0xc0cf0000), SPH_C32(0x670b0000), SPH_C32(0xd4740000), + SPH_C32(0xd86b6b13), SPH_C32(0xaf83181e), SPH_C32(0xa95c66a4), + SPH_C32(0x3754f33c) }, + { SPH_C32(0x27b00000), SPH_C32(0xa2980000), SPH_C32(0x23ad007f), + SPH_C32(0xb1743800), SPH_C32(0x03c0287f), SPH_C32(0x25ff4549), + SPH_C32(0x3c81693e), SPH_C32(0x844c576c), SPH_C32(0x42f80000), + SPH_C32(0xebbd0000), SPH_C32(0x2f860000), SPH_C32(0x7b151800), + SPH_C32(0xfda045d6), SPH_C32(0x67faa7ce), SPH_C32(0x28fe628d), + SPH_C32(0x2921c59a) }, + { SPH_C32(0x62a90000), SPH_C32(0x09940000), SPH_C32(0x1313007e), + SPH_C32(0xd87e1800), SPH_C32(0xc13c5a66), SPH_C32(0x942bc544), + SPH_C32(0x11509378), SPH_C32(0xa07d187b), SPH_C32(0x1abb0000), + SPH_C32(0x6bc30000), SPH_C32(0x57b50001), SPH_C32(0xbd7e2000), + SPH_C32(0x1a97190a), SPH_C32(0x1e579813), SPH_C32(0x848d9ce2), + SPH_C32(0x1365bc2b) }, + { SPH_C32(0x3aea0000), SPH_C32(0x89ea0000), SPH_C32(0x6b20007f), + SPH_C32(0x1e152000), SPH_C32(0x260b06ba), SPH_C32(0xed86fa99), + SPH_C32(0xbd236d17), SPH_C32(0x9a3961ca), SPH_C32(0x07e10000), + SPH_C32(0x40b10000), SPH_C32(0x1f380001), SPH_C32(0x121f3800), + SPH_C32(0x3f5c37cf), SPH_C32(0xd62e27c3), SPH_C32(0x052f98cb), + SPH_C32(0x0d108a8d) }, + { SPH_C32(0xdd250000), SPH_C32(0x84900000), SPH_C32(0x92da006a), + SPH_C32(0x9cbc0000), SPH_C32(0x281b5ad8), SPH_C32(0x6c4abe0d), + SPH_C32(0x93bb9dab), SPH_C32(0x2566d655), SPH_C32(0xfa990000), + SPH_C32(0xd4e90000), SPH_C32(0x293b001e), SPH_C32(0xa8da0000), + SPH_C32(0x57f566c6), SPH_C32(0xd75cb223), SPH_C32(0x5e6d0e7c), + SPH_C32(0x3c4fba7a) }, + { SPH_C32(0x85660000), SPH_C32(0x04ee0000), SPH_C32(0xeae9006b), + SPH_C32(0x5ad73800), SPH_C32(0xcf2c0604), SPH_C32(0x15e781d0), + SPH_C32(0x3fc863c4), SPH_C32(0x1f22afe4), SPH_C32(0xe7c30000), + SPH_C32(0xff9b0000), SPH_C32(0x61b6001e), SPH_C32(0x07bb1800), + SPH_C32(0x723e4803), SPH_C32(0x1f250df3), SPH_C32(0xdfcf0a55), + SPH_C32(0x223a8cdc) }, + { SPH_C32(0xc07f0000), SPH_C32(0xafe20000), SPH_C32(0xda57006a), + SPH_C32(0x33dd1800), SPH_C32(0x0dd0741d), SPH_C32(0xa43301dd), + SPH_C32(0x12199982), SPH_C32(0x3b13e0f3), SPH_C32(0xbf800000), + SPH_C32(0x7fe50000), SPH_C32(0x1985001f), SPH_C32(0xc1d02000), + SPH_C32(0x950914df), SPH_C32(0x6688322e), SPH_C32(0x73bcf43a), + SPH_C32(0x187ef56d) }, + { SPH_C32(0x983c0000), SPH_C32(0x2f9c0000), SPH_C32(0xa264006b), + SPH_C32(0xf5b62000), SPH_C32(0xeae728c1), SPH_C32(0xdd9e3e00), + SPH_C32(0xbe6a67ed), SPH_C32(0x01579942), SPH_C32(0xa2da0000), + SPH_C32(0x54970000), SPH_C32(0x5108001f), SPH_C32(0x6eb13800), + SPH_C32(0xb0c23a1a), SPH_C32(0xaef18dfe), SPH_C32(0xf21ef013), + SPH_C32(0x060bc3cb) }, + { SPH_C32(0x781e0000), SPH_C32(0x90b60000), SPH_C32(0xdcea0074), + SPH_C32(0xe0120000), SPH_C32(0xa785570d), SPH_C32(0x14951430), + SPH_C32(0x648af573), SPH_C32(0x2e7d9f13), SPH_C32(0xfd740000), + SPH_C32(0x66b90000), SPH_C32(0xae4f0014), SPH_C32(0x3fd70000), + SPH_C32(0x14874568), SPH_C32(0x9f9bdc87), SPH_C32(0xaa156c5e), + SPH_C32(0xac3a0bb4) }, + { SPH_C32(0x205d0000), SPH_C32(0x10c80000), SPH_C32(0xa4d90075), + SPH_C32(0x26793800), SPH_C32(0x40b20bd1), SPH_C32(0x6d382bed), + SPH_C32(0xc8f90b1c), SPH_C32(0x1439e6a2), SPH_C32(0xe02e0000), + SPH_C32(0x4dcb0000), SPH_C32(0xe6c20014), SPH_C32(0x90b61800), + SPH_C32(0x314c6bad), SPH_C32(0x57e26357), SPH_C32(0x2bb76877), + SPH_C32(0xb24f3d12) }, + { SPH_C32(0x65440000), SPH_C32(0xbbc40000), SPH_C32(0x94670074), + SPH_C32(0x4f731800), SPH_C32(0x824e79c8), SPH_C32(0xdcecabe0), + SPH_C32(0xe528f15a), SPH_C32(0x3008a9b5), SPH_C32(0xb86d0000), + SPH_C32(0xcdb50000), SPH_C32(0x9ef10015), SPH_C32(0x56dd2000), + SPH_C32(0xd67b3771), SPH_C32(0x2e4f5c8a), SPH_C32(0x87c49618), + SPH_C32(0x880b44a3) }, + { SPH_C32(0x3d070000), SPH_C32(0x3bba0000), SPH_C32(0xec540075), + SPH_C32(0x89182000), SPH_C32(0x65792514), SPH_C32(0xa541943d), + SPH_C32(0x495b0f35), SPH_C32(0x0a4cd004), SPH_C32(0xa5370000), + SPH_C32(0xe6c70000), SPH_C32(0xd67c0015), SPH_C32(0xf9bc3800), + SPH_C32(0xf3b019b4), SPH_C32(0xe636e35a), SPH_C32(0x06669231), + SPH_C32(0x967e7205) }, + { SPH_C32(0x59920000), SPH_C32(0xf2370000), SPH_C32(0x14e90042), + SPH_C32(0xe5790000), SPH_C32(0x0bcc361f), SPH_C32(0x30a2fa8d), + SPH_C32(0x3b36cb7b), SPH_C32(0x8bb5076c), SPH_C32(0xd0d70000), + SPH_C32(0x6d0b0000), SPH_C32(0x9fb00024), SPH_C32(0xb8370000), + SPH_C32(0x6a414f27), SPH_C32(0x86eae7dd), SPH_C32(0xf5b174ea), + SPH_C32(0x41313666) }, + { SPH_C32(0x01d10000), SPH_C32(0x72490000), SPH_C32(0x6cda0043), + SPH_C32(0x23123800), SPH_C32(0xecfb6ac3), SPH_C32(0x490fc550), + SPH_C32(0x97453514), SPH_C32(0xb1f17edd), SPH_C32(0xcd8d0000), + SPH_C32(0x46790000), SPH_C32(0xd73d0024), SPH_C32(0x17561800), + SPH_C32(0x4f8a61e2), SPH_C32(0x4e93580d), SPH_C32(0x741370c3), + SPH_C32(0x5f4400c0) }, + { SPH_C32(0x44c80000), SPH_C32(0xd9450000), SPH_C32(0x5c640042), + SPH_C32(0x4a181800), SPH_C32(0x2e0718da), SPH_C32(0xf8db455d), + SPH_C32(0xba94cf52), SPH_C32(0x95c031ca), SPH_C32(0x95ce0000), + SPH_C32(0xc6070000), SPH_C32(0xaf0e0025), SPH_C32(0xd13d2000), + SPH_C32(0xa8bd3d3e), SPH_C32(0x373e67d0), SPH_C32(0xd8608eac), + SPH_C32(0x65007971) }, + { SPH_C32(0x1c8b0000), SPH_C32(0x593b0000), SPH_C32(0x24570043), + SPH_C32(0x8c732000), SPH_C32(0xc9304406), SPH_C32(0x81767a80), + SPH_C32(0x16e7313d), SPH_C32(0xaf84487b), SPH_C32(0x88940000), + SPH_C32(0xed750000), SPH_C32(0xe7830025), SPH_C32(0x7e5c3800), + SPH_C32(0x8d7613fb), SPH_C32(0xff47d800), SPH_C32(0x59c28a85), + SPH_C32(0x7b754fd7) }, + { SPH_C32(0xfca90000), SPH_C32(0xe6110000), SPH_C32(0x5ad9005c), + SPH_C32(0x99d70000), SPH_C32(0x84523bca), SPH_C32(0x487d50b0), + SPH_C32(0xcc07a3a3), SPH_C32(0x80ae4e2a), SPH_C32(0xd73a0000), + SPH_C32(0xdf5b0000), SPH_C32(0x18c4002e), SPH_C32(0x2f3a0000), + SPH_C32(0x29336c89), SPH_C32(0xce2d8979), SPH_C32(0x01c916c8), + SPH_C32(0xd14487a8) }, + { SPH_C32(0xa4ea0000), SPH_C32(0x666f0000), SPH_C32(0x22ea005d), + SPH_C32(0x5fbc3800), SPH_C32(0x63656716), SPH_C32(0x31d06f6d), + SPH_C32(0x60745dcc), SPH_C32(0xbaea379b), SPH_C32(0xca600000), + SPH_C32(0xf4290000), SPH_C32(0x5049002e), SPH_C32(0x805b1800), + SPH_C32(0x0cf8424c), SPH_C32(0x065436a9), SPH_C32(0x806b12e1), + SPH_C32(0xcf31b10e) }, + { SPH_C32(0xe1f30000), SPH_C32(0xcd630000), SPH_C32(0x1254005c), + SPH_C32(0x36b61800), SPH_C32(0xa199150f), SPH_C32(0x8004ef60), + SPH_C32(0x4da5a78a), SPH_C32(0x9edb788c), SPH_C32(0x92230000), + SPH_C32(0x74570000), SPH_C32(0x287a002f), SPH_C32(0x46302000), + SPH_C32(0xebcf1e90), SPH_C32(0x7ff90974), SPH_C32(0x2c18ec8e), + SPH_C32(0xf575c8bf) }, + { SPH_C32(0xb9b00000), SPH_C32(0x4d1d0000), SPH_C32(0x6a67005d), + SPH_C32(0xf0dd2000), SPH_C32(0x46ae49d3), SPH_C32(0xf9a9d0bd), + SPH_C32(0xe1d659e5), SPH_C32(0xa49f013d), SPH_C32(0x8f790000), + SPH_C32(0x5f250000), SPH_C32(0x60f7002f), SPH_C32(0xe9513800), + SPH_C32(0xce043055), SPH_C32(0xb780b6a4), SPH_C32(0xadbae8a7), + SPH_C32(0xeb00fe19) }, + { SPH_C32(0x5e7f0000), SPH_C32(0x40670000), SPH_C32(0x939d0048), + SPH_C32(0x72740000), SPH_C32(0x48be15b1), SPH_C32(0x78659429), + SPH_C32(0xcf4ea959), SPH_C32(0x1bc0b6a2), SPH_C32(0x72010000), + SPH_C32(0xcb7d0000), SPH_C32(0x56f40030), SPH_C32(0x53940000), + SPH_C32(0xa6ad615c), SPH_C32(0xb6f22344), SPH_C32(0xf6f87e10), + SPH_C32(0xda5fceee) }, + { SPH_C32(0x063c0000), SPH_C32(0xc0190000), SPH_C32(0xebae0049), + SPH_C32(0xb41f3800), SPH_C32(0xaf89496d), SPH_C32(0x01c8abf4), + SPH_C32(0x633d5736), SPH_C32(0x2184cf13), SPH_C32(0x6f5b0000), + SPH_C32(0xe00f0000), SPH_C32(0x1e790030), SPH_C32(0xfcf51800), + SPH_C32(0x83664f99), SPH_C32(0x7e8b9c94), SPH_C32(0x775a7a39), + SPH_C32(0xc42af848) }, + { SPH_C32(0x43250000), SPH_C32(0x6b150000), SPH_C32(0xdb100048), + SPH_C32(0xdd151800), SPH_C32(0x6d753b74), SPH_C32(0xb01c2bf9), + SPH_C32(0x4eecad70), SPH_C32(0x05b58004), SPH_C32(0x37180000), + SPH_C32(0x60710000), SPH_C32(0x664a0031), SPH_C32(0x3a9e2000), + SPH_C32(0x64511345), SPH_C32(0x0726a349), SPH_C32(0xdb298456), + SPH_C32(0xfe6e81f9) }, + { SPH_C32(0x1b660000), SPH_C32(0xeb6b0000), SPH_C32(0xa3230049), + SPH_C32(0x1b7e2000), SPH_C32(0x8a4267a8), SPH_C32(0xc9b11424), + SPH_C32(0xe29f531f), SPH_C32(0x3ff1f9b5), SPH_C32(0x2a420000), + SPH_C32(0x4b030000), SPH_C32(0x2ec70031), SPH_C32(0x95ff3800), + SPH_C32(0x419a3d80), SPH_C32(0xcf5f1c99), SPH_C32(0x5a8b807f), + SPH_C32(0xe01bb75f) }, + { SPH_C32(0xfb440000), SPH_C32(0x54410000), SPH_C32(0xddad0056), + SPH_C32(0x0eda0000), SPH_C32(0xc7201864), SPH_C32(0x00ba3e14), + SPH_C32(0x387fc181), SPH_C32(0x10dbffe4), SPH_C32(0x75ec0000), + SPH_C32(0x792d0000), SPH_C32(0xd180003a), SPH_C32(0xc4990000), + SPH_C32(0xe5df42f2), SPH_C32(0xfe354de0), SPH_C32(0x02801c32), + SPH_C32(0x4a2a7f20) }, + { SPH_C32(0xa3070000), SPH_C32(0xd43f0000), SPH_C32(0xa59e0057), + SPH_C32(0xc8b13800), SPH_C32(0x201744b8), SPH_C32(0x791701c9), + SPH_C32(0x940c3fee), SPH_C32(0x2a9f8655), SPH_C32(0x68b60000), + SPH_C32(0x525f0000), SPH_C32(0x990d003a), SPH_C32(0x6bf81800), + SPH_C32(0xc0146c37), SPH_C32(0x364cf230), SPH_C32(0x8322181b), + SPH_C32(0x545f4986) }, + { SPH_C32(0xe61e0000), SPH_C32(0x7f330000), SPH_C32(0x95200056), + SPH_C32(0xa1bb1800), SPH_C32(0xe2eb36a1), SPH_C32(0xc8c381c4), + SPH_C32(0xb9ddc5a8), SPH_C32(0x0eaec942), SPH_C32(0x30f50000), + SPH_C32(0xd2210000), SPH_C32(0xe13e003b), SPH_C32(0xad932000), + SPH_C32(0x272330eb), SPH_C32(0x4fe1cded), SPH_C32(0x2f51e674), + SPH_C32(0x6e1b3037) }, + { SPH_C32(0xbe5d0000), SPH_C32(0xff4d0000), SPH_C32(0xed130057), + SPH_C32(0x67d02000), SPH_C32(0x05dc6a7d), SPH_C32(0xb16ebe19), + SPH_C32(0x15ae3bc7), SPH_C32(0x34eab0f3), SPH_C32(0x2daf0000), + SPH_C32(0xf9530000), SPH_C32(0xa9b3003b), SPH_C32(0x02f23800), + SPH_C32(0x02e81e2e), SPH_C32(0x8798723d), SPH_C32(0xaef3e25d), + SPH_C32(0x706e0691) }, + { SPH_C32(0xd10a0000), SPH_C32(0xeda30000), SPH_C32(0x6b26006c), + SPH_C32(0x1e370000), SPH_C32(0xfa943185), SPH_C32(0x510c6bea), + SPH_C32(0x93a3bb17), SPH_C32(0x6da573f8), SPH_C32(0xdb150000), + SPH_C32(0xb6680000), SPH_C32(0xe1380028), SPH_C32(0xadb10000), + SPH_C32(0xfbbc07d4), SPH_C32(0xf36b5c9e), SPH_C32(0x01d13074), + SPH_C32(0x99872205) }, + { SPH_C32(0x89490000), SPH_C32(0x6ddd0000), SPH_C32(0x1315006d), + SPH_C32(0xd85c3800), SPH_C32(0x1da36d59), SPH_C32(0x28a15437), + SPH_C32(0x3fd04578), SPH_C32(0x57e10a49), SPH_C32(0xc64f0000), + SPH_C32(0x9d1a0000), SPH_C32(0xa9b50028), SPH_C32(0x02d01800), + SPH_C32(0xde772911), SPH_C32(0x3b12e34e), SPH_C32(0x8073345d), + SPH_C32(0x87f214a3) }, + { SPH_C32(0xcc500000), SPH_C32(0xc6d10000), SPH_C32(0x23ab006c), + SPH_C32(0xb1561800), SPH_C32(0xdf5f1f40), SPH_C32(0x9975d43a), + SPH_C32(0x1201bf3e), SPH_C32(0x73d0455e), SPH_C32(0x9e0c0000), + SPH_C32(0x1d640000), SPH_C32(0xd1860029), SPH_C32(0xc4bb2000), + SPH_C32(0x394075cd), SPH_C32(0x42bfdc93), SPH_C32(0x2c00ca32), + SPH_C32(0xbdb66d12) }, + { SPH_C32(0x94130000), SPH_C32(0x46af0000), SPH_C32(0x5b98006d), + SPH_C32(0x773d2000), SPH_C32(0x3868439c), SPH_C32(0xe0d8ebe7), + SPH_C32(0xbe724151), SPH_C32(0x49943cef), SPH_C32(0x83560000), + SPH_C32(0x36160000), SPH_C32(0x990b0029), SPH_C32(0x6bda3800), + SPH_C32(0x1c8b5b08), SPH_C32(0x8ac66343), SPH_C32(0xada2ce1b), + SPH_C32(0xa3c35bb4) }, + { SPH_C32(0x74310000), SPH_C32(0xf9850000), SPH_C32(0x25160072), + SPH_C32(0x62990000), SPH_C32(0x750a3c50), SPH_C32(0x29d3c1d7), + SPH_C32(0x6492d3cf), SPH_C32(0x66be3abe), SPH_C32(0xdcf80000), + SPH_C32(0x04380000), SPH_C32(0x664c0022), SPH_C32(0x3abc0000), + SPH_C32(0xb8ce247a), SPH_C32(0xbbac323a), SPH_C32(0xf5a95256), + SPH_C32(0x09f293cb) }, + { SPH_C32(0x2c720000), SPH_C32(0x79fb0000), SPH_C32(0x5d250073), + SPH_C32(0xa4f23800), SPH_C32(0x923d608c), SPH_C32(0x507efe0a), + SPH_C32(0xc8e12da0), SPH_C32(0x5cfa430f), SPH_C32(0xc1a20000), + SPH_C32(0x2f4a0000), SPH_C32(0x2ec10022), SPH_C32(0x95dd1800), + SPH_C32(0x9d050abf), SPH_C32(0x73d58dea), SPH_C32(0x740b567f), + SPH_C32(0x1787a56d) }, + { SPH_C32(0x696b0000), SPH_C32(0xd2f70000), SPH_C32(0x6d9b0072), + SPH_C32(0xcdf81800), SPH_C32(0x50c11295), SPH_C32(0xe1aa7e07), + SPH_C32(0xe530d7e6), SPH_C32(0x78cb0c18), SPH_C32(0x99e10000), + SPH_C32(0xaf340000), SPH_C32(0x56f20023), SPH_C32(0x53b62000), + SPH_C32(0x7a325663), SPH_C32(0x0a78b237), SPH_C32(0xd878a810), + SPH_C32(0x2dc3dcdc) }, + { SPH_C32(0x31280000), SPH_C32(0x52890000), SPH_C32(0x15a80073), + SPH_C32(0x0b932000), SPH_C32(0xb7f64e49), SPH_C32(0x980741da), + SPH_C32(0x49432989), SPH_C32(0x428f75a9), SPH_C32(0x84bb0000), + SPH_C32(0x84460000), SPH_C32(0x1e7f0023), SPH_C32(0xfcd73800), + SPH_C32(0x5ff978a6), SPH_C32(0xc2010de7), SPH_C32(0x59daac39), + SPH_C32(0x33b6ea7a) }, + { SPH_C32(0xd6e70000), SPH_C32(0x5ff30000), SPH_C32(0xec520066), + SPH_C32(0x893a0000), SPH_C32(0xb9e6122b), SPH_C32(0x19cb054e), + SPH_C32(0x67dbd935), SPH_C32(0xfdd0c236), SPH_C32(0x79c30000), + SPH_C32(0x101e0000), SPH_C32(0x287c003c), SPH_C32(0x46120000), + SPH_C32(0x375029af), SPH_C32(0xc3739807), SPH_C32(0x02983a8e), + SPH_C32(0x02e9da8d) }, + { SPH_C32(0x8ea40000), SPH_C32(0xdf8d0000), SPH_C32(0x94610067), + SPH_C32(0x4f513800), SPH_C32(0x5ed14ef7), SPH_C32(0x60663a93), + SPH_C32(0xcba8275a), SPH_C32(0xc794bb87), SPH_C32(0x64990000), + SPH_C32(0x3b6c0000), SPH_C32(0x60f1003c), SPH_C32(0xe9731800), + SPH_C32(0x129b076a), SPH_C32(0x0b0a27d7), SPH_C32(0x833a3ea7), + SPH_C32(0x1c9cec2b) }, + { SPH_C32(0xcbbd0000), SPH_C32(0x74810000), SPH_C32(0xa4df0066), + SPH_C32(0x265b1800), SPH_C32(0x9c2d3cee), SPH_C32(0xd1b2ba9e), + SPH_C32(0xe679dd1c), SPH_C32(0xe3a5f490), SPH_C32(0x3cda0000), + SPH_C32(0xbb120000), SPH_C32(0x18c2003d), SPH_C32(0x2f182000), + SPH_C32(0xf5ac5bb6), SPH_C32(0x72a7180a), SPH_C32(0x2f49c0c8), + SPH_C32(0x26d8959a) }, + { SPH_C32(0x93fe0000), SPH_C32(0xf4ff0000), SPH_C32(0xdcec0067), + SPH_C32(0xe0302000), SPH_C32(0x7b1a6032), SPH_C32(0xa81f8543), + SPH_C32(0x4a0a2373), SPH_C32(0xd9e18d21), SPH_C32(0x21800000), + SPH_C32(0x90600000), SPH_C32(0x504f003d), SPH_C32(0x80793800), + SPH_C32(0xd0677573), SPH_C32(0xbadea7da), SPH_C32(0xaeebc4e1), + SPH_C32(0x38ada33c) }, + { SPH_C32(0x73dc0000), SPH_C32(0x4bd50000), SPH_C32(0xa2620078), + SPH_C32(0xf5940000), SPH_C32(0x36781ffe), SPH_C32(0x6114af73), + SPH_C32(0x90eab1ed), SPH_C32(0xf6cb8b70), SPH_C32(0x7e2e0000), + SPH_C32(0xa24e0000), SPH_C32(0xaf080036), SPH_C32(0xd11f0000), + SPH_C32(0x74220a01), SPH_C32(0x8bb4f6a3), SPH_C32(0xf6e058ac), + SPH_C32(0x929c6b43) }, + { SPH_C32(0x2b9f0000), SPH_C32(0xcbab0000), SPH_C32(0xda510079), + SPH_C32(0x33ff3800), SPH_C32(0xd14f4322), SPH_C32(0x18b990ae), + SPH_C32(0x3c994f82), SPH_C32(0xcc8ff2c1), SPH_C32(0x63740000), + SPH_C32(0x893c0000), SPH_C32(0xe7850036), SPH_C32(0x7e7e1800), + SPH_C32(0x51e924c4), SPH_C32(0x43cd4973), SPH_C32(0x77425c85), + SPH_C32(0x8ce95de5) }, + { SPH_C32(0x6e860000), SPH_C32(0x60a70000), SPH_C32(0xeaef0078), + SPH_C32(0x5af51800), SPH_C32(0x13b3313b), SPH_C32(0xa96d10a3), + SPH_C32(0x1148b5c4), SPH_C32(0xe8bebdd6), SPH_C32(0x3b370000), + SPH_C32(0x09420000), SPH_C32(0x9fb60037), SPH_C32(0xb8152000), + SPH_C32(0xb6de7818), SPH_C32(0x3a6076ae), SPH_C32(0xdb31a2ea), + SPH_C32(0xb6ad2454) }, + { SPH_C32(0x36c50000), SPH_C32(0xe0d90000), SPH_C32(0x92dc0079), + SPH_C32(0x9c9e2000), SPH_C32(0xf4846de7), SPH_C32(0xd0c02f7e), + SPH_C32(0xbd3b4bab), SPH_C32(0xd2fac467), SPH_C32(0x266d0000), + SPH_C32(0x22300000), SPH_C32(0xd73b0037), SPH_C32(0x17743800), + SPH_C32(0x931556dd), SPH_C32(0xf219c97e), SPH_C32(0x5a93a6c3), + SPH_C32(0xa8d812f2) }, + { SPH_C32(0x538d0000), SPH_C32(0xa9fc0000), SPH_C32(0x9ef70006), + SPH_C32(0x56ff0000), SPH_C32(0x0ae4004e), SPH_C32(0x92c5cdf9), + SPH_C32(0xa9444018), SPH_C32(0x7f975691), SPH_C32(0x01dd0000), + SPH_C32(0x80a80000), SPH_C32(0xf4960048), SPH_C32(0xa6000000), + SPH_C32(0x90d57ea2), SPH_C32(0xd7e68c37), SPH_C32(0x6612cffd), + SPH_C32(0x2c94459e) }, + { SPH_C32(0x0bce0000), SPH_C32(0x29820000), SPH_C32(0xe6c40007), + SPH_C32(0x90943800), SPH_C32(0xedd35c92), SPH_C32(0xeb68f224), + SPH_C32(0x0537be77), SPH_C32(0x45d32f20), SPH_C32(0x1c870000), + SPH_C32(0xabda0000), SPH_C32(0xbc1b0048), SPH_C32(0x09611800), + SPH_C32(0xb51e5067), SPH_C32(0x1f9f33e7), SPH_C32(0xe7b0cbd4), + SPH_C32(0x32e17338) }, + { SPH_C32(0x4ed70000), SPH_C32(0x828e0000), SPH_C32(0xd67a0006), + SPH_C32(0xf99e1800), SPH_C32(0x2f2f2e8b), SPH_C32(0x5abc7229), + SPH_C32(0x28e64431), SPH_C32(0x61e26037), SPH_C32(0x44c40000), + SPH_C32(0x2ba40000), SPH_C32(0xc4280049), SPH_C32(0xcf0a2000), + SPH_C32(0x52290cbb), SPH_C32(0x66320c3a), SPH_C32(0x4bc335bb), + SPH_C32(0x08a50a89) }, + { SPH_C32(0x16940000), SPH_C32(0x02f00000), SPH_C32(0xae490007), + SPH_C32(0x3ff52000), SPH_C32(0xc8187257), SPH_C32(0x23114df4), + SPH_C32(0x8495ba5e), SPH_C32(0x5ba61986), SPH_C32(0x599e0000), + SPH_C32(0x00d60000), SPH_C32(0x8ca50049), SPH_C32(0x606b3800), + SPH_C32(0x77e2227e), SPH_C32(0xae4bb3ea), SPH_C32(0xca613192), + SPH_C32(0x16d03c2f) }, + { SPH_C32(0xf6b60000), SPH_C32(0xbdda0000), SPH_C32(0xd0c70018), + SPH_C32(0x2a510000), SPH_C32(0x857a0d9b), SPH_C32(0xea1a67c4), + SPH_C32(0x5e7528c0), SPH_C32(0x748c1fd7), SPH_C32(0x06300000), + SPH_C32(0x32f80000), SPH_C32(0x73e20042), SPH_C32(0x310d0000), + SPH_C32(0xd3a75d0c), SPH_C32(0x9f21e293), SPH_C32(0x926aaddf), + SPH_C32(0xbce1f450) }, + { SPH_C32(0xaef50000), SPH_C32(0x3da40000), SPH_C32(0xa8f40019), + SPH_C32(0xec3a3800), SPH_C32(0x624d5147), SPH_C32(0x93b75819), + SPH_C32(0xf206d6af), SPH_C32(0x4ec86666), SPH_C32(0x1b6a0000), + SPH_C32(0x198a0000), SPH_C32(0x3b6f0042), SPH_C32(0x9e6c1800), + SPH_C32(0xf66c73c9), SPH_C32(0x57585d43), SPH_C32(0x13c8a9f6), + SPH_C32(0xa294c2f6) }, + { SPH_C32(0xebec0000), SPH_C32(0x96a80000), SPH_C32(0x984a0018), + SPH_C32(0x85301800), SPH_C32(0xa0b1235e), SPH_C32(0x2263d814), + SPH_C32(0xdfd72ce9), SPH_C32(0x6af92971), SPH_C32(0x43290000), + SPH_C32(0x99f40000), SPH_C32(0x435c0043), SPH_C32(0x58072000), + SPH_C32(0x115b2f15), SPH_C32(0x2ef5629e), SPH_C32(0xbfbb5799), + SPH_C32(0x98d0bb47) }, + { SPH_C32(0xb3af0000), SPH_C32(0x16d60000), SPH_C32(0xe0790019), + SPH_C32(0x435b2000), SPH_C32(0x47867f82), SPH_C32(0x5bcee7c9), + SPH_C32(0x73a4d286), SPH_C32(0x50bd50c0), SPH_C32(0x5e730000), + SPH_C32(0xb2860000), SPH_C32(0x0bd10043), SPH_C32(0xf7663800), + SPH_C32(0x349001d0), SPH_C32(0xe68cdd4e), SPH_C32(0x3e1953b0), + SPH_C32(0x86a58de1) }, + { SPH_C32(0x54600000), SPH_C32(0x1bac0000), SPH_C32(0x1983000c), + SPH_C32(0xc1f20000), SPH_C32(0x499623e0), SPH_C32(0xda02a35d), + SPH_C32(0x5d3c223a), SPH_C32(0xefe2e75f), SPH_C32(0xa30b0000), + SPH_C32(0x26de0000), SPH_C32(0x3dd2005c), SPH_C32(0x4da30000), + SPH_C32(0x5c3950d9), SPH_C32(0xe7fe48ae), SPH_C32(0x655bc507), + SPH_C32(0xb7fabd16) }, + { SPH_C32(0x0c230000), SPH_C32(0x9bd20000), SPH_C32(0x61b0000d), + SPH_C32(0x07993800), SPH_C32(0xaea17f3c), SPH_C32(0xa3af9c80), + SPH_C32(0xf14fdc55), SPH_C32(0xd5a69eee), SPH_C32(0xbe510000), + SPH_C32(0x0dac0000), SPH_C32(0x755f005c), SPH_C32(0xe2c21800), + SPH_C32(0x79f27e1c), SPH_C32(0x2f87f77e), SPH_C32(0xe4f9c12e), + SPH_C32(0xa98f8bb0) }, + { SPH_C32(0x493a0000), SPH_C32(0x30de0000), SPH_C32(0x510e000c), + SPH_C32(0x6e931800), SPH_C32(0x6c5d0d25), SPH_C32(0x127b1c8d), + SPH_C32(0xdc9e2613), SPH_C32(0xf197d1f9), SPH_C32(0xe6120000), + SPH_C32(0x8dd20000), SPH_C32(0x0d6c005d), SPH_C32(0x24a92000), + SPH_C32(0x9ec522c0), SPH_C32(0x562ac8a3), SPH_C32(0x488a3f41), + SPH_C32(0x93cbf201) }, + { SPH_C32(0x11790000), SPH_C32(0xb0a00000), SPH_C32(0x293d000d), + SPH_C32(0xa8f82000), SPH_C32(0x8b6a51f9), SPH_C32(0x6bd62350), + SPH_C32(0x70edd87c), SPH_C32(0xcbd3a848), SPH_C32(0xfb480000), + SPH_C32(0xa6a00000), SPH_C32(0x45e1005d), SPH_C32(0x8bc83800), + SPH_C32(0xbb0e0c05), SPH_C32(0x9e537773), SPH_C32(0xc9283b68), + SPH_C32(0x8dbec4a7) }, + { SPH_C32(0xf15b0000), SPH_C32(0x0f8a0000), SPH_C32(0x57b30012), + SPH_C32(0xbd5c0000), SPH_C32(0xc6082e35), SPH_C32(0xa2dd0960), + SPH_C32(0xaa0d4ae2), SPH_C32(0xe4f9ae19), SPH_C32(0xa4e60000), + SPH_C32(0x948e0000), SPH_C32(0xbaa60056), SPH_C32(0xdaae0000), + SPH_C32(0x1f4b7377), SPH_C32(0xaf39260a), SPH_C32(0x9123a725), + SPH_C32(0x278f0cd8) }, + { SPH_C32(0xa9180000), SPH_C32(0x8ff40000), SPH_C32(0x2f800013), + SPH_C32(0x7b373800), SPH_C32(0x213f72e9), SPH_C32(0xdb7036bd), + SPH_C32(0x067eb48d), SPH_C32(0xdebdd7a8), SPH_C32(0xb9bc0000), + SPH_C32(0xbffc0000), SPH_C32(0xf22b0056), SPH_C32(0x75cf1800), + SPH_C32(0x3a805db2), SPH_C32(0x674099da), SPH_C32(0x1081a30c), + SPH_C32(0x39fa3a7e) }, + { SPH_C32(0xec010000), SPH_C32(0x24f80000), SPH_C32(0x1f3e0012), + SPH_C32(0x123d1800), SPH_C32(0xe3c300f0), SPH_C32(0x6aa4b6b0), + SPH_C32(0x2baf4ecb), SPH_C32(0xfa8c98bf), SPH_C32(0xe1ff0000), + SPH_C32(0x3f820000), SPH_C32(0x8a180057), SPH_C32(0xb3a42000), + SPH_C32(0xddb7016e), SPH_C32(0x1eeda607), SPH_C32(0xbcf25d63), + SPH_C32(0x03be43cf) }, + { SPH_C32(0xb4420000), SPH_C32(0xa4860000), SPH_C32(0x670d0013), + SPH_C32(0xd4562000), SPH_C32(0x04f45c2c), SPH_C32(0x1309896d), + SPH_C32(0x87dcb0a4), SPH_C32(0xc0c8e10e), SPH_C32(0xfca50000), + SPH_C32(0x14f00000), SPH_C32(0xc2950057), SPH_C32(0x1cc53800), + SPH_C32(0xf87c2fab), SPH_C32(0xd69419d7), SPH_C32(0x3d50594a), + SPH_C32(0x1dcb7569) }, + { SPH_C32(0xdb150000), SPH_C32(0xb6680000), SPH_C32(0xe1380028), + SPH_C32(0xadb10000), SPH_C32(0xfbbc07d4), SPH_C32(0xf36b5c9e), + SPH_C32(0x01d13074), SPH_C32(0x99872205), SPH_C32(0x0a1f0000), + SPH_C32(0x5bcb0000), SPH_C32(0x8a1e0044), SPH_C32(0xb3860000), + SPH_C32(0x01283651), SPH_C32(0xa2673774), SPH_C32(0x92728b63), + SPH_C32(0xf42251fd) }, + { SPH_C32(0x83560000), SPH_C32(0x36160000), SPH_C32(0x990b0029), + SPH_C32(0x6bda3800), SPH_C32(0x1c8b5b08), SPH_C32(0x8ac66343), + SPH_C32(0xada2ce1b), SPH_C32(0xa3c35bb4), SPH_C32(0x17450000), + SPH_C32(0x70b90000), SPH_C32(0xc2930044), SPH_C32(0x1ce71800), + SPH_C32(0x24e31894), SPH_C32(0x6a1e88a4), SPH_C32(0x13d08f4a), + SPH_C32(0xea57675b) }, + { SPH_C32(0xc64f0000), SPH_C32(0x9d1a0000), SPH_C32(0xa9b50028), + SPH_C32(0x02d01800), SPH_C32(0xde772911), SPH_C32(0x3b12e34e), + SPH_C32(0x8073345d), SPH_C32(0x87f214a3), SPH_C32(0x4f060000), + SPH_C32(0xf0c70000), SPH_C32(0xbaa00045), SPH_C32(0xda8c2000), + SPH_C32(0xc3d44448), SPH_C32(0x13b3b779), SPH_C32(0xbfa37125), + SPH_C32(0xd0131eea) }, + { SPH_C32(0x9e0c0000), SPH_C32(0x1d640000), SPH_C32(0xd1860029), + SPH_C32(0xc4bb2000), SPH_C32(0x394075cd), SPH_C32(0x42bfdc93), + SPH_C32(0x2c00ca32), SPH_C32(0xbdb66d12), SPH_C32(0x525c0000), + SPH_C32(0xdbb50000), SPH_C32(0xf22d0045), SPH_C32(0x75ed3800), + SPH_C32(0xe61f6a8d), SPH_C32(0xdbca08a9), SPH_C32(0x3e01750c), + SPH_C32(0xce66284c) }, + { SPH_C32(0x7e2e0000), SPH_C32(0xa24e0000), SPH_C32(0xaf080036), + SPH_C32(0xd11f0000), SPH_C32(0x74220a01), SPH_C32(0x8bb4f6a3), + SPH_C32(0xf6e058ac), SPH_C32(0x929c6b43), SPH_C32(0x0df20000), + SPH_C32(0xe99b0000), SPH_C32(0x0d6a004e), SPH_C32(0x248b0000), + SPH_C32(0x425a15ff), SPH_C32(0xeaa059d0), SPH_C32(0x660ae941), + SPH_C32(0x6457e033) }, + { SPH_C32(0x266d0000), SPH_C32(0x22300000), SPH_C32(0xd73b0037), + SPH_C32(0x17743800), SPH_C32(0x931556dd), SPH_C32(0xf219c97e), + SPH_C32(0x5a93a6c3), SPH_C32(0xa8d812f2), SPH_C32(0x10a80000), + SPH_C32(0xc2e90000), SPH_C32(0x45e7004e), SPH_C32(0x8bea1800), + SPH_C32(0x67913b3a), SPH_C32(0x22d9e600), SPH_C32(0xe7a8ed68), + SPH_C32(0x7a22d695) }, + { SPH_C32(0x63740000), SPH_C32(0x893c0000), SPH_C32(0xe7850036), + SPH_C32(0x7e7e1800), SPH_C32(0x51e924c4), SPH_C32(0x43cd4973), + SPH_C32(0x77425c85), SPH_C32(0x8ce95de5), SPH_C32(0x48eb0000), + SPH_C32(0x42970000), SPH_C32(0x3dd4004f), SPH_C32(0x4d812000), + SPH_C32(0x80a667e6), SPH_C32(0x5b74d9dd), SPH_C32(0x4bdb1307), + SPH_C32(0x4066af24) }, + { SPH_C32(0x3b370000), SPH_C32(0x09420000), SPH_C32(0x9fb60037), + SPH_C32(0xb8152000), SPH_C32(0xb6de7818), SPH_C32(0x3a6076ae), + SPH_C32(0xdb31a2ea), SPH_C32(0xb6ad2454), SPH_C32(0x55b10000), + SPH_C32(0x69e50000), SPH_C32(0x7559004f), SPH_C32(0xe2e03800), + SPH_C32(0xa56d4923), SPH_C32(0x930d660d), SPH_C32(0xca79172e), + SPH_C32(0x5e139982) }, + { SPH_C32(0xdcf80000), SPH_C32(0x04380000), SPH_C32(0x664c0022), + SPH_C32(0x3abc0000), SPH_C32(0xb8ce247a), SPH_C32(0xbbac323a), + SPH_C32(0xf5a95256), SPH_C32(0x09f293cb), SPH_C32(0xa8c90000), + SPH_C32(0xfdbd0000), SPH_C32(0x435a0050), SPH_C32(0x58250000), + SPH_C32(0xcdc4182a), SPH_C32(0x927ff3ed), SPH_C32(0x913b8199), + SPH_C32(0x6f4ca975) }, + { SPH_C32(0x84bb0000), SPH_C32(0x84460000), SPH_C32(0x1e7f0023), + SPH_C32(0xfcd73800), SPH_C32(0x5ff978a6), SPH_C32(0xc2010de7), + SPH_C32(0x59daac39), SPH_C32(0x33b6ea7a), SPH_C32(0xb5930000), + SPH_C32(0xd6cf0000), SPH_C32(0x0bd70050), SPH_C32(0xf7441800), + SPH_C32(0xe80f36ef), SPH_C32(0x5a064c3d), SPH_C32(0x109985b0), + SPH_C32(0x71399fd3) }, + { SPH_C32(0xc1a20000), SPH_C32(0x2f4a0000), SPH_C32(0x2ec10022), + SPH_C32(0x95dd1800), SPH_C32(0x9d050abf), SPH_C32(0x73d58dea), + SPH_C32(0x740b567f), SPH_C32(0x1787a56d), SPH_C32(0xedd00000), + SPH_C32(0x56b10000), SPH_C32(0x73e40051), SPH_C32(0x312f2000), + SPH_C32(0x0f386a33), SPH_C32(0x23ab73e0), SPH_C32(0xbcea7bdf), + SPH_C32(0x4b7de662) }, + { SPH_C32(0x99e10000), SPH_C32(0xaf340000), SPH_C32(0x56f20023), + SPH_C32(0x53b62000), SPH_C32(0x7a325663), SPH_C32(0x0a78b237), + SPH_C32(0xd878a810), SPH_C32(0x2dc3dcdc), SPH_C32(0xf08a0000), + SPH_C32(0x7dc30000), SPH_C32(0x3b690051), SPH_C32(0x9e4e3800), + SPH_C32(0x2af344f6), SPH_C32(0xebd2cc30), SPH_C32(0x3d487ff6), + SPH_C32(0x5508d0c4) }, + { SPH_C32(0x79c30000), SPH_C32(0x101e0000), SPH_C32(0x287c003c), + SPH_C32(0x46120000), SPH_C32(0x375029af), SPH_C32(0xc3739807), + SPH_C32(0x02983a8e), SPH_C32(0x02e9da8d), SPH_C32(0xaf240000), + SPH_C32(0x4fed0000), SPH_C32(0xc42e005a), SPH_C32(0xcf280000), + SPH_C32(0x8eb63b84), SPH_C32(0xdab89d49), SPH_C32(0x6543e3bb), + SPH_C32(0xff3918bb) }, + { SPH_C32(0x21800000), SPH_C32(0x90600000), SPH_C32(0x504f003d), + SPH_C32(0x80793800), SPH_C32(0xd0677573), SPH_C32(0xbadea7da), + SPH_C32(0xaeebc4e1), SPH_C32(0x38ada33c), SPH_C32(0xb27e0000), + SPH_C32(0x649f0000), SPH_C32(0x8ca3005a), SPH_C32(0x60491800), + SPH_C32(0xab7d1541), SPH_C32(0x12c12299), SPH_C32(0xe4e1e792), + SPH_C32(0xe14c2e1d) }, + { SPH_C32(0x64990000), SPH_C32(0x3b6c0000), SPH_C32(0x60f1003c), + SPH_C32(0xe9731800), SPH_C32(0x129b076a), SPH_C32(0x0b0a27d7), + SPH_C32(0x833a3ea7), SPH_C32(0x1c9cec2b), SPH_C32(0xea3d0000), + SPH_C32(0xe4e10000), SPH_C32(0xf490005b), SPH_C32(0xa6222000), + SPH_C32(0x4c4a499d), SPH_C32(0x6b6c1d44), SPH_C32(0x489219fd), + SPH_C32(0xdb0857ac) }, + { SPH_C32(0x3cda0000), SPH_C32(0xbb120000), SPH_C32(0x18c2003d), + SPH_C32(0x2f182000), SPH_C32(0xf5ac5bb6), SPH_C32(0x72a7180a), + SPH_C32(0x2f49c0c8), SPH_C32(0x26d8959a), SPH_C32(0xf7670000), + SPH_C32(0xcf930000), SPH_C32(0xbc1d005b), SPH_C32(0x09433800), + SPH_C32(0x69816758), SPH_C32(0xa315a294), SPH_C32(0xc9301dd4), + SPH_C32(0xc57d610a) }, + { SPH_C32(0x584f0000), SPH_C32(0x729f0000), SPH_C32(0xe07f000a), + SPH_C32(0x43790000), SPH_C32(0x9b1948bd), SPH_C32(0xe74476ba), + SPH_C32(0x5d240486), SPH_C32(0xa72142f2), SPH_C32(0x82870000), + SPH_C32(0x445f0000), SPH_C32(0xf5d1006a), SPH_C32(0x48c80000), + SPH_C32(0xf07031cb), SPH_C32(0xc3c9a613), SPH_C32(0x3ae7fb0f), + SPH_C32(0x12322569) }, + { SPH_C32(0x000c0000), SPH_C32(0xf2e10000), SPH_C32(0x984c000b), + SPH_C32(0x85123800), SPH_C32(0x7c2e1461), SPH_C32(0x9ee94967), + SPH_C32(0xf157fae9), SPH_C32(0x9d653b43), SPH_C32(0x9fdd0000), + SPH_C32(0x6f2d0000), SPH_C32(0xbd5c006a), SPH_C32(0xe7a91800), + SPH_C32(0xd5bb1f0e), SPH_C32(0x0bb019c3), SPH_C32(0xbb45ff26), + SPH_C32(0x0c4713cf) }, + { SPH_C32(0x45150000), SPH_C32(0x59ed0000), SPH_C32(0xa8f2000a), + SPH_C32(0xec181800), SPH_C32(0xbed26678), SPH_C32(0x2f3dc96a), + SPH_C32(0xdc8600af), SPH_C32(0xb9547454), SPH_C32(0xc79e0000), + SPH_C32(0xef530000), SPH_C32(0xc56f006b), SPH_C32(0x21c22000), + SPH_C32(0x328c43d2), SPH_C32(0x721d261e), SPH_C32(0x17360149), + SPH_C32(0x36036a7e) }, + { SPH_C32(0x1d560000), SPH_C32(0xd9930000), SPH_C32(0xd0c1000b), + SPH_C32(0x2a732000), SPH_C32(0x59e53aa4), SPH_C32(0x5690f6b7), + SPH_C32(0x70f5fec0), SPH_C32(0x83100de5), SPH_C32(0xdac40000), + SPH_C32(0xc4210000), SPH_C32(0x8de2006b), SPH_C32(0x8ea33800), + SPH_C32(0x17476d17), SPH_C32(0xba6499ce), SPH_C32(0x96940560), + SPH_C32(0x28765cd8) }, + { SPH_C32(0xfd740000), SPH_C32(0x66b90000), SPH_C32(0xae4f0014), + SPH_C32(0x3fd70000), SPH_C32(0x14874568), SPH_C32(0x9f9bdc87), + SPH_C32(0xaa156c5e), SPH_C32(0xac3a0bb4), SPH_C32(0x856a0000), + SPH_C32(0xf60f0000), SPH_C32(0x72a50060), SPH_C32(0xdfc50000), + SPH_C32(0xb3021265), SPH_C32(0x8b0ec8b7), SPH_C32(0xce9f992d), + SPH_C32(0x824794a7) }, + { SPH_C32(0xa5370000), SPH_C32(0xe6c70000), SPH_C32(0xd67c0015), + SPH_C32(0xf9bc3800), SPH_C32(0xf3b019b4), SPH_C32(0xe636e35a), + SPH_C32(0x06669231), SPH_C32(0x967e7205), SPH_C32(0x98300000), + SPH_C32(0xdd7d0000), SPH_C32(0x3a280060), SPH_C32(0x70a41800), + SPH_C32(0x96c93ca0), SPH_C32(0x43777767), SPH_C32(0x4f3d9d04), + SPH_C32(0x9c32a201) }, + { SPH_C32(0xe02e0000), SPH_C32(0x4dcb0000), SPH_C32(0xe6c20014), + SPH_C32(0x90b61800), SPH_C32(0x314c6bad), SPH_C32(0x57e26357), + SPH_C32(0x2bb76877), SPH_C32(0xb24f3d12), SPH_C32(0xc0730000), + SPH_C32(0x5d030000), SPH_C32(0x421b0061), SPH_C32(0xb6cf2000), + SPH_C32(0x71fe607c), SPH_C32(0x3ada48ba), SPH_C32(0xe34e636b), + SPH_C32(0xa676dbb0) }, + { SPH_C32(0xb86d0000), SPH_C32(0xcdb50000), SPH_C32(0x9ef10015), + SPH_C32(0x56dd2000), SPH_C32(0xd67b3771), SPH_C32(0x2e4f5c8a), + SPH_C32(0x87c49618), SPH_C32(0x880b44a3), SPH_C32(0xdd290000), + SPH_C32(0x76710000), SPH_C32(0x0a960061), SPH_C32(0x19ae3800), + SPH_C32(0x54354eb9), SPH_C32(0xf2a3f76a), SPH_C32(0x62ec6742), + SPH_C32(0xb803ed16) }, + { SPH_C32(0x5fa20000), SPH_C32(0xc0cf0000), SPH_C32(0x670b0000), + SPH_C32(0xd4740000), SPH_C32(0xd86b6b13), SPH_C32(0xaf83181e), + SPH_C32(0xa95c66a4), SPH_C32(0x3754f33c), SPH_C32(0x20510000), + SPH_C32(0xe2290000), SPH_C32(0x3c95007e), SPH_C32(0xa36b0000), + SPH_C32(0x3c9c1fb0), SPH_C32(0xf3d1628a), SPH_C32(0x39aef1f5), + SPH_C32(0x895cdde1) }, + { SPH_C32(0x07e10000), SPH_C32(0x40b10000), SPH_C32(0x1f380001), + SPH_C32(0x121f3800), SPH_C32(0x3f5c37cf), SPH_C32(0xd62e27c3), + SPH_C32(0x052f98cb), SPH_C32(0x0d108a8d), SPH_C32(0x3d0b0000), + SPH_C32(0xc95b0000), SPH_C32(0x7418007e), SPH_C32(0x0c0a1800), + SPH_C32(0x19573175), SPH_C32(0x3ba8dd5a), SPH_C32(0xb80cf5dc), + SPH_C32(0x9729eb47) }, + { SPH_C32(0x42f80000), SPH_C32(0xebbd0000), SPH_C32(0x2f860000), + SPH_C32(0x7b151800), SPH_C32(0xfda045d6), SPH_C32(0x67faa7ce), + SPH_C32(0x28fe628d), SPH_C32(0x2921c59a), SPH_C32(0x65480000), + SPH_C32(0x49250000), SPH_C32(0x0c2b007f), SPH_C32(0xca612000), + SPH_C32(0xfe606da9), SPH_C32(0x4205e287), SPH_C32(0x147f0bb3), + SPH_C32(0xad6d92f6) }, + { SPH_C32(0x1abb0000), SPH_C32(0x6bc30000), SPH_C32(0x57b50001), + SPH_C32(0xbd7e2000), SPH_C32(0x1a97190a), SPH_C32(0x1e579813), + SPH_C32(0x848d9ce2), SPH_C32(0x1365bc2b), SPH_C32(0x78120000), + SPH_C32(0x62570000), SPH_C32(0x44a6007f), SPH_C32(0x65003800), + SPH_C32(0xdbab436c), SPH_C32(0x8a7c5d57), SPH_C32(0x95dd0f9a), + SPH_C32(0xb318a450) }, + { SPH_C32(0xfa990000), SPH_C32(0xd4e90000), SPH_C32(0x293b001e), + SPH_C32(0xa8da0000), SPH_C32(0x57f566c6), SPH_C32(0xd75cb223), + SPH_C32(0x5e6d0e7c), SPH_C32(0x3c4fba7a), SPH_C32(0x27bc0000), + SPH_C32(0x50790000), SPH_C32(0xbbe10074), SPH_C32(0x34660000), + SPH_C32(0x7fee3c1e), SPH_C32(0xbb160c2e), SPH_C32(0xcdd693d7), + SPH_C32(0x19296c2f) }, + { SPH_C32(0xa2da0000), SPH_C32(0x54970000), SPH_C32(0x5108001f), + SPH_C32(0x6eb13800), SPH_C32(0xb0c23a1a), SPH_C32(0xaef18dfe), + SPH_C32(0xf21ef013), SPH_C32(0x060bc3cb), SPH_C32(0x3ae60000), + SPH_C32(0x7b0b0000), SPH_C32(0xf36c0074), SPH_C32(0x9b071800), + SPH_C32(0x5a2512db), SPH_C32(0x736fb3fe), SPH_C32(0x4c7497fe), + SPH_C32(0x075c5a89) }, + { SPH_C32(0xe7c30000), SPH_C32(0xff9b0000), SPH_C32(0x61b6001e), + SPH_C32(0x07bb1800), SPH_C32(0x723e4803), SPH_C32(0x1f250df3), + SPH_C32(0xdfcf0a55), SPH_C32(0x223a8cdc), SPH_C32(0x62a50000), + SPH_C32(0xfb750000), SPH_C32(0x8b5f0075), SPH_C32(0x5d6c2000), + SPH_C32(0xbd124e07), SPH_C32(0x0ac28c23), SPH_C32(0xe0076991), + SPH_C32(0x3d182338) }, + { SPH_C32(0xbf800000), SPH_C32(0x7fe50000), SPH_C32(0x1985001f), + SPH_C32(0xc1d02000), SPH_C32(0x950914df), SPH_C32(0x6688322e), + SPH_C32(0x73bcf43a), SPH_C32(0x187ef56d), SPH_C32(0x7fff0000), + SPH_C32(0xd0070000), SPH_C32(0xc3d20075), SPH_C32(0xf20d3800), + SPH_C32(0x98d960c2), SPH_C32(0xc2bb33f3), SPH_C32(0x61a56db8), + SPH_C32(0x236d159e) }, + { SPH_C32(0xd0d70000), SPH_C32(0x6d0b0000), SPH_C32(0x9fb00024), + SPH_C32(0xb8370000), SPH_C32(0x6a414f27), SPH_C32(0x86eae7dd), + SPH_C32(0xf5b174ea), SPH_C32(0x41313666), SPH_C32(0x89450000), + SPH_C32(0x9f3c0000), SPH_C32(0x8b590066), SPH_C32(0x5d4e0000), + SPH_C32(0x618d7938), SPH_C32(0xb6481d50), SPH_C32(0xce87bf91), + SPH_C32(0xca84310a) }, + { SPH_C32(0x88940000), SPH_C32(0xed750000), SPH_C32(0xe7830025), + SPH_C32(0x7e5c3800), SPH_C32(0x8d7613fb), SPH_C32(0xff47d800), + SPH_C32(0x59c28a85), SPH_C32(0x7b754fd7), SPH_C32(0x941f0000), + SPH_C32(0xb44e0000), SPH_C32(0xc3d40066), SPH_C32(0xf22f1800), + SPH_C32(0x444657fd), SPH_C32(0x7e31a280), SPH_C32(0x4f25bbb8), + SPH_C32(0xd4f107ac) }, + { SPH_C32(0xcd8d0000), SPH_C32(0x46790000), SPH_C32(0xd73d0024), + SPH_C32(0x17561800), SPH_C32(0x4f8a61e2), SPH_C32(0x4e93580d), + SPH_C32(0x741370c3), SPH_C32(0x5f4400c0), SPH_C32(0xcc5c0000), + SPH_C32(0x34300000), SPH_C32(0xbbe70067), SPH_C32(0x34442000), + SPH_C32(0xa3710b21), SPH_C32(0x079c9d5d), SPH_C32(0xe35645d7), + SPH_C32(0xeeb57e1d) }, + { SPH_C32(0x95ce0000), SPH_C32(0xc6070000), SPH_C32(0xaf0e0025), + SPH_C32(0xd13d2000), SPH_C32(0xa8bd3d3e), SPH_C32(0x373e67d0), + SPH_C32(0xd8608eac), SPH_C32(0x65007971), SPH_C32(0xd1060000), + SPH_C32(0x1f420000), SPH_C32(0xf36a0067), SPH_C32(0x9b253800), + SPH_C32(0x86ba25e4), SPH_C32(0xcfe5228d), SPH_C32(0x62f441fe), + SPH_C32(0xf0c048bb) }, + { SPH_C32(0x75ec0000), SPH_C32(0x792d0000), SPH_C32(0xd180003a), + SPH_C32(0xc4990000), SPH_C32(0xe5df42f2), SPH_C32(0xfe354de0), + SPH_C32(0x02801c32), SPH_C32(0x4a2a7f20), SPH_C32(0x8ea80000), + SPH_C32(0x2d6c0000), SPH_C32(0x0c2d006c), SPH_C32(0xca430000), + SPH_C32(0x22ff5a96), SPH_C32(0xfe8f73f4), SPH_C32(0x3affddb3), + SPH_C32(0x5af180c4) }, + { SPH_C32(0x2daf0000), SPH_C32(0xf9530000), SPH_C32(0xa9b3003b), + SPH_C32(0x02f23800), SPH_C32(0x02e81e2e), SPH_C32(0x8798723d), + SPH_C32(0xaef3e25d), SPH_C32(0x706e0691), SPH_C32(0x93f20000), + SPH_C32(0x061e0000), SPH_C32(0x44a0006c), SPH_C32(0x65221800), + SPH_C32(0x07347453), SPH_C32(0x36f6cc24), SPH_C32(0xbb5dd99a), + SPH_C32(0x4484b662) }, + { SPH_C32(0x68b60000), SPH_C32(0x525f0000), SPH_C32(0x990d003a), + SPH_C32(0x6bf81800), SPH_C32(0xc0146c37), SPH_C32(0x364cf230), + SPH_C32(0x8322181b), SPH_C32(0x545f4986), SPH_C32(0xcbb10000), + SPH_C32(0x86600000), SPH_C32(0x3c93006d), SPH_C32(0xa3492000), + SPH_C32(0xe003288f), SPH_C32(0x4f5bf3f9), SPH_C32(0x172e27f5), + SPH_C32(0x7ec0cfd3) }, + { SPH_C32(0x30f50000), SPH_C32(0xd2210000), SPH_C32(0xe13e003b), + SPH_C32(0xad932000), SPH_C32(0x272330eb), SPH_C32(0x4fe1cded), + SPH_C32(0x2f51e674), SPH_C32(0x6e1b3037), SPH_C32(0xd6eb0000), + SPH_C32(0xad120000), SPH_C32(0x741e006d), SPH_C32(0x0c283800), + SPH_C32(0xc5c8064a), SPH_C32(0x87224c29), SPH_C32(0x968c23dc), + SPH_C32(0x60b5f975) }, + { SPH_C32(0xd73a0000), SPH_C32(0xdf5b0000), SPH_C32(0x18c4002e), + SPH_C32(0x2f3a0000), SPH_C32(0x29336c89), SPH_C32(0xce2d8979), + SPH_C32(0x01c916c8), SPH_C32(0xd14487a8), SPH_C32(0x2b930000), + SPH_C32(0x394a0000), SPH_C32(0x421d0072), SPH_C32(0xb6ed0000), + SPH_C32(0xad615743), SPH_C32(0x8650d9c9), SPH_C32(0xcdceb56b), + SPH_C32(0x51eac982) }, + { SPH_C32(0x8f790000), SPH_C32(0x5f250000), SPH_C32(0x60f7002f), + SPH_C32(0xe9513800), SPH_C32(0xce043055), SPH_C32(0xb780b6a4), + SPH_C32(0xadbae8a7), SPH_C32(0xeb00fe19), SPH_C32(0x36c90000), + SPH_C32(0x12380000), SPH_C32(0x0a900072), SPH_C32(0x198c1800), + SPH_C32(0x88aa7986), SPH_C32(0x4e296619), SPH_C32(0x4c6cb142), + SPH_C32(0x4f9fff24) }, + { SPH_C32(0xca600000), SPH_C32(0xf4290000), SPH_C32(0x5049002e), + SPH_C32(0x805b1800), SPH_C32(0x0cf8424c), SPH_C32(0x065436a9), + SPH_C32(0x806b12e1), SPH_C32(0xcf31b10e), SPH_C32(0x6e8a0000), + SPH_C32(0x92460000), SPH_C32(0x72a30073), SPH_C32(0xdfe72000), + SPH_C32(0x6f9d255a), SPH_C32(0x378459c4), SPH_C32(0xe01f4f2d), + SPH_C32(0x75db8695) }, + { SPH_C32(0x92230000), SPH_C32(0x74570000), SPH_C32(0x287a002f), + SPH_C32(0x46302000), SPH_C32(0xebcf1e90), SPH_C32(0x7ff90974), + SPH_C32(0x2c18ec8e), SPH_C32(0xf575c8bf), SPH_C32(0x73d00000), + SPH_C32(0xb9340000), SPH_C32(0x3a2e0073), SPH_C32(0x70863800), + SPH_C32(0x4a560b9f), SPH_C32(0xfffde614), SPH_C32(0x61bd4b04), + SPH_C32(0x6baeb033) }, + { SPH_C32(0x72010000), SPH_C32(0xcb7d0000), SPH_C32(0x56f40030), + SPH_C32(0x53940000), SPH_C32(0xa6ad615c), SPH_C32(0xb6f22344), + SPH_C32(0xf6f87e10), SPH_C32(0xda5fceee), SPH_C32(0x2c7e0000), + SPH_C32(0x8b1a0000), SPH_C32(0xc5690078), SPH_C32(0x21e00000), + SPH_C32(0xee1374ed), SPH_C32(0xce97b76d), SPH_C32(0x39b6d749), + SPH_C32(0xc19f784c) }, + { SPH_C32(0x2a420000), SPH_C32(0x4b030000), SPH_C32(0x2ec70031), + SPH_C32(0x95ff3800), SPH_C32(0x419a3d80), SPH_C32(0xcf5f1c99), + SPH_C32(0x5a8b807f), SPH_C32(0xe01bb75f), SPH_C32(0x31240000), + SPH_C32(0xa0680000), SPH_C32(0x8de40078), SPH_C32(0x8e811800), + SPH_C32(0xcbd85a28), SPH_C32(0x06ee08bd), SPH_C32(0xb814d360), + SPH_C32(0xdfea4eea) }, + { SPH_C32(0x6f5b0000), SPH_C32(0xe00f0000), SPH_C32(0x1e790030), + SPH_C32(0xfcf51800), SPH_C32(0x83664f99), SPH_C32(0x7e8b9c94), + SPH_C32(0x775a7a39), SPH_C32(0xc42af848), SPH_C32(0x69670000), + SPH_C32(0x20160000), SPH_C32(0xf5d70079), SPH_C32(0x48ea2000), + SPH_C32(0x2cef06f4), SPH_C32(0x7f433760), SPH_C32(0x14672d0f), + SPH_C32(0xe5ae375b) }, + { SPH_C32(0x37180000), SPH_C32(0x60710000), SPH_C32(0x664a0031), + SPH_C32(0x3a9e2000), SPH_C32(0x64511345), SPH_C32(0x0726a349), + SPH_C32(0xdb298456), SPH_C32(0xfe6e81f9), SPH_C32(0x743d0000), + SPH_C32(0x0b640000), SPH_C32(0xbd5a0079), SPH_C32(0xe78b3800), + SPH_C32(0x09242831), SPH_C32(0xb73a88b0), SPH_C32(0x95c52926), + SPH_C32(0xfbdb01fd) }, + { SPH_C32(0x01dd0000), SPH_C32(0x80a80000), SPH_C32(0xf4960048), + SPH_C32(0xa6000000), SPH_C32(0x90d57ea2), SPH_C32(0xd7e68c37), + SPH_C32(0x6612cffd), SPH_C32(0x2c94459e), SPH_C32(0x52500000), + SPH_C32(0x29540000), SPH_C32(0x6a61004e), SPH_C32(0xf0ff0000), + SPH_C32(0x9a317eec), SPH_C32(0x452341ce), SPH_C32(0xcf568fe5), + SPH_C32(0x5303130f) }, + { SPH_C32(0x599e0000), SPH_C32(0x00d60000), SPH_C32(0x8ca50049), + SPH_C32(0x606b3800), SPH_C32(0x77e2227e), SPH_C32(0xae4bb3ea), + SPH_C32(0xca613192), SPH_C32(0x16d03c2f), SPH_C32(0x4f0a0000), + SPH_C32(0x02260000), SPH_C32(0x22ec004e), SPH_C32(0x5f9e1800), + SPH_C32(0xbffa5029), SPH_C32(0x8d5afe1e), SPH_C32(0x4ef48bcc), + SPH_C32(0x4d7625a9) }, + { SPH_C32(0x1c870000), SPH_C32(0xabda0000), SPH_C32(0xbc1b0048), + SPH_C32(0x09611800), SPH_C32(0xb51e5067), SPH_C32(0x1f9f33e7), + SPH_C32(0xe7b0cbd4), SPH_C32(0x32e17338), SPH_C32(0x17490000), + SPH_C32(0x82580000), SPH_C32(0x5adf004f), SPH_C32(0x99f52000), + SPH_C32(0x58cd0cf5), SPH_C32(0xf4f7c1c3), SPH_C32(0xe28775a3), + SPH_C32(0x77325c18) }, + { SPH_C32(0x44c40000), SPH_C32(0x2ba40000), SPH_C32(0xc4280049), + SPH_C32(0xcf0a2000), SPH_C32(0x52290cbb), SPH_C32(0x66320c3a), + SPH_C32(0x4bc335bb), SPH_C32(0x08a50a89), SPH_C32(0x0a130000), + SPH_C32(0xa92a0000), SPH_C32(0x1252004f), SPH_C32(0x36943800), + SPH_C32(0x7d062230), SPH_C32(0x3c8e7e13), SPH_C32(0x6325718a), + SPH_C32(0x69476abe) }, + { SPH_C32(0xa4e60000), SPH_C32(0x948e0000), SPH_C32(0xbaa60056), + SPH_C32(0xdaae0000), SPH_C32(0x1f4b7377), SPH_C32(0xaf39260a), + SPH_C32(0x9123a725), SPH_C32(0x278f0cd8), SPH_C32(0x55bd0000), + SPH_C32(0x9b040000), SPH_C32(0xed150044), SPH_C32(0x67f20000), + SPH_C32(0xd9435d42), SPH_C32(0x0de42f6a), SPH_C32(0x3b2eedc7), + SPH_C32(0xc376a2c1) }, + { SPH_C32(0xfca50000), SPH_C32(0x14f00000), SPH_C32(0xc2950057), + SPH_C32(0x1cc53800), SPH_C32(0xf87c2fab), SPH_C32(0xd69419d7), + SPH_C32(0x3d50594a), SPH_C32(0x1dcb7569), SPH_C32(0x48e70000), + SPH_C32(0xb0760000), SPH_C32(0xa5980044), SPH_C32(0xc8931800), + SPH_C32(0xfc887387), SPH_C32(0xc59d90ba), SPH_C32(0xba8ce9ee), + SPH_C32(0xdd039467) }, + { SPH_C32(0xb9bc0000), SPH_C32(0xbffc0000), SPH_C32(0xf22b0056), + SPH_C32(0x75cf1800), SPH_C32(0x3a805db2), SPH_C32(0x674099da), + SPH_C32(0x1081a30c), SPH_C32(0x39fa3a7e), SPH_C32(0x10a40000), + SPH_C32(0x30080000), SPH_C32(0xddab0045), SPH_C32(0x0ef82000), + SPH_C32(0x1bbf2f5b), SPH_C32(0xbc30af67), SPH_C32(0x16ff1781), + SPH_C32(0xe747edd6) }, + { SPH_C32(0xe1ff0000), SPH_C32(0x3f820000), SPH_C32(0x8a180057), + SPH_C32(0xb3a42000), SPH_C32(0xddb7016e), SPH_C32(0x1eeda607), + SPH_C32(0xbcf25d63), SPH_C32(0x03be43cf), SPH_C32(0x0dfe0000), + SPH_C32(0x1b7a0000), SPH_C32(0x95260045), SPH_C32(0xa1993800), + SPH_C32(0x3e74019e), SPH_C32(0x744910b7), SPH_C32(0x975d13a8), + SPH_C32(0xf932db70) }, + { SPH_C32(0x06300000), SPH_C32(0x32f80000), SPH_C32(0x73e20042), + SPH_C32(0x310d0000), SPH_C32(0xd3a75d0c), SPH_C32(0x9f21e293), + SPH_C32(0x926aaddf), SPH_C32(0xbce1f450), SPH_C32(0xf0860000), + SPH_C32(0x8f220000), SPH_C32(0xa325005a), SPH_C32(0x1b5c0000), + SPH_C32(0x56dd5097), SPH_C32(0x753b8557), SPH_C32(0xcc1f851f), + SPH_C32(0xc86deb87) }, + { SPH_C32(0x5e730000), SPH_C32(0xb2860000), SPH_C32(0x0bd10043), + SPH_C32(0xf7663800), SPH_C32(0x349001d0), SPH_C32(0xe68cdd4e), + SPH_C32(0x3e1953b0), SPH_C32(0x86a58de1), SPH_C32(0xeddc0000), + SPH_C32(0xa4500000), SPH_C32(0xeba8005a), SPH_C32(0xb43d1800), + SPH_C32(0x73167e52), SPH_C32(0xbd423a87), SPH_C32(0x4dbd8136), + SPH_C32(0xd618dd21) }, + { SPH_C32(0x1b6a0000), SPH_C32(0x198a0000), SPH_C32(0x3b6f0042), + SPH_C32(0x9e6c1800), SPH_C32(0xf66c73c9), SPH_C32(0x57585d43), + SPH_C32(0x13c8a9f6), SPH_C32(0xa294c2f6), SPH_C32(0xb59f0000), + SPH_C32(0x242e0000), SPH_C32(0x939b005b), SPH_C32(0x72562000), + SPH_C32(0x9421228e), SPH_C32(0xc4ef055a), SPH_C32(0xe1ce7f59), + SPH_C32(0xec5ca490) }, + { SPH_C32(0x43290000), SPH_C32(0x99f40000), SPH_C32(0x435c0043), + SPH_C32(0x58072000), SPH_C32(0x115b2f15), SPH_C32(0x2ef5629e), + SPH_C32(0xbfbb5799), SPH_C32(0x98d0bb47), SPH_C32(0xa8c50000), + SPH_C32(0x0f5c0000), SPH_C32(0xdb16005b), SPH_C32(0xdd373800), + SPH_C32(0xb1ea0c4b), SPH_C32(0x0c96ba8a), SPH_C32(0x606c7b70), + SPH_C32(0xf2299236) }, + { SPH_C32(0xa30b0000), SPH_C32(0x26de0000), SPH_C32(0x3dd2005c), + SPH_C32(0x4da30000), SPH_C32(0x5c3950d9), SPH_C32(0xe7fe48ae), + SPH_C32(0x655bc507), SPH_C32(0xb7fabd16), SPH_C32(0xf76b0000), + SPH_C32(0x3d720000), SPH_C32(0x24510050), SPH_C32(0x8c510000), + SPH_C32(0x15af7339), SPH_C32(0x3dfcebf3), SPH_C32(0x3867e73d), + SPH_C32(0x58185a49) }, + { SPH_C32(0xfb480000), SPH_C32(0xa6a00000), SPH_C32(0x45e1005d), + SPH_C32(0x8bc83800), SPH_C32(0xbb0e0c05), SPH_C32(0x9e537773), + SPH_C32(0xc9283b68), SPH_C32(0x8dbec4a7), SPH_C32(0xea310000), + SPH_C32(0x16000000), SPH_C32(0x6cdc0050), SPH_C32(0x23301800), + SPH_C32(0x30645dfc), SPH_C32(0xf5855423), SPH_C32(0xb9c5e314), + SPH_C32(0x466d6cef) }, + { SPH_C32(0xbe510000), SPH_C32(0x0dac0000), SPH_C32(0x755f005c), + SPH_C32(0xe2c21800), SPH_C32(0x79f27e1c), SPH_C32(0x2f87f77e), + SPH_C32(0xe4f9c12e), SPH_C32(0xa98f8bb0), SPH_C32(0xb2720000), + SPH_C32(0x967e0000), SPH_C32(0x14ef0051), SPH_C32(0xe55b2000), + SPH_C32(0xd7530120), SPH_C32(0x8c286bfe), SPH_C32(0x15b61d7b), + SPH_C32(0x7c29155e) }, + { SPH_C32(0xe6120000), SPH_C32(0x8dd20000), SPH_C32(0x0d6c005d), + SPH_C32(0x24a92000), SPH_C32(0x9ec522c0), SPH_C32(0x562ac8a3), + SPH_C32(0x488a3f41), SPH_C32(0x93cbf201), SPH_C32(0xaf280000), + SPH_C32(0xbd0c0000), SPH_C32(0x5c620051), SPH_C32(0x4a3a3800), + SPH_C32(0xf2982fe5), SPH_C32(0x4451d42e), SPH_C32(0x94141952), + SPH_C32(0x625c23f8) }, + { SPH_C32(0x89450000), SPH_C32(0x9f3c0000), SPH_C32(0x8b590066), + SPH_C32(0x5d4e0000), SPH_C32(0x618d7938), SPH_C32(0xb6481d50), + SPH_C32(0xce87bf91), SPH_C32(0xca84310a), SPH_C32(0x59920000), + SPH_C32(0xf2370000), SPH_C32(0x14e90042), SPH_C32(0xe5790000), + SPH_C32(0x0bcc361f), SPH_C32(0x30a2fa8d), SPH_C32(0x3b36cb7b), + SPH_C32(0x8bb5076c) }, + { SPH_C32(0xd1060000), SPH_C32(0x1f420000), SPH_C32(0xf36a0067), + SPH_C32(0x9b253800), SPH_C32(0x86ba25e4), SPH_C32(0xcfe5228d), + SPH_C32(0x62f441fe), SPH_C32(0xf0c048bb), SPH_C32(0x44c80000), + SPH_C32(0xd9450000), SPH_C32(0x5c640042), SPH_C32(0x4a181800), + SPH_C32(0x2e0718da), SPH_C32(0xf8db455d), SPH_C32(0xba94cf52), + SPH_C32(0x95c031ca) }, + { SPH_C32(0x941f0000), SPH_C32(0xb44e0000), SPH_C32(0xc3d40066), + SPH_C32(0xf22f1800), SPH_C32(0x444657fd), SPH_C32(0x7e31a280), + SPH_C32(0x4f25bbb8), SPH_C32(0xd4f107ac), SPH_C32(0x1c8b0000), + SPH_C32(0x593b0000), SPH_C32(0x24570043), SPH_C32(0x8c732000), + SPH_C32(0xc9304406), SPH_C32(0x81767a80), SPH_C32(0x16e7313d), + SPH_C32(0xaf84487b) }, + { SPH_C32(0xcc5c0000), SPH_C32(0x34300000), SPH_C32(0xbbe70067), + SPH_C32(0x34442000), SPH_C32(0xa3710b21), SPH_C32(0x079c9d5d), + SPH_C32(0xe35645d7), SPH_C32(0xeeb57e1d), SPH_C32(0x01d10000), + SPH_C32(0x72490000), SPH_C32(0x6cda0043), SPH_C32(0x23123800), + SPH_C32(0xecfb6ac3), SPH_C32(0x490fc550), SPH_C32(0x97453514), + SPH_C32(0xb1f17edd) }, + { SPH_C32(0x2c7e0000), SPH_C32(0x8b1a0000), SPH_C32(0xc5690078), + SPH_C32(0x21e00000), SPH_C32(0xee1374ed), SPH_C32(0xce97b76d), + SPH_C32(0x39b6d749), SPH_C32(0xc19f784c), SPH_C32(0x5e7f0000), + SPH_C32(0x40670000), SPH_C32(0x939d0048), SPH_C32(0x72740000), + SPH_C32(0x48be15b1), SPH_C32(0x78659429), SPH_C32(0xcf4ea959), + SPH_C32(0x1bc0b6a2) }, + { SPH_C32(0x743d0000), SPH_C32(0x0b640000), SPH_C32(0xbd5a0079), + SPH_C32(0xe78b3800), SPH_C32(0x09242831), SPH_C32(0xb73a88b0), + SPH_C32(0x95c52926), SPH_C32(0xfbdb01fd), SPH_C32(0x43250000), + SPH_C32(0x6b150000), SPH_C32(0xdb100048), SPH_C32(0xdd151800), + SPH_C32(0x6d753b74), SPH_C32(0xb01c2bf9), SPH_C32(0x4eecad70), + SPH_C32(0x05b58004) }, + { SPH_C32(0x31240000), SPH_C32(0xa0680000), SPH_C32(0x8de40078), + SPH_C32(0x8e811800), SPH_C32(0xcbd85a28), SPH_C32(0x06ee08bd), + SPH_C32(0xb814d360), SPH_C32(0xdfea4eea), SPH_C32(0x1b660000), + SPH_C32(0xeb6b0000), SPH_C32(0xa3230049), SPH_C32(0x1b7e2000), + SPH_C32(0x8a4267a8), SPH_C32(0xc9b11424), SPH_C32(0xe29f531f), + SPH_C32(0x3ff1f9b5) }, + { SPH_C32(0x69670000), SPH_C32(0x20160000), SPH_C32(0xf5d70079), + SPH_C32(0x48ea2000), SPH_C32(0x2cef06f4), SPH_C32(0x7f433760), + SPH_C32(0x14672d0f), SPH_C32(0xe5ae375b), SPH_C32(0x063c0000), + SPH_C32(0xc0190000), SPH_C32(0xebae0049), SPH_C32(0xb41f3800), + SPH_C32(0xaf89496d), SPH_C32(0x01c8abf4), SPH_C32(0x633d5736), + SPH_C32(0x2184cf13) }, + { SPH_C32(0x8ea80000), SPH_C32(0x2d6c0000), SPH_C32(0x0c2d006c), + SPH_C32(0xca430000), SPH_C32(0x22ff5a96), SPH_C32(0xfe8f73f4), + SPH_C32(0x3affddb3), SPH_C32(0x5af180c4), SPH_C32(0xfb440000), + SPH_C32(0x54410000), SPH_C32(0xddad0056), SPH_C32(0x0eda0000), + SPH_C32(0xc7201864), SPH_C32(0x00ba3e14), SPH_C32(0x387fc181), + SPH_C32(0x10dbffe4) }, + { SPH_C32(0xd6eb0000), SPH_C32(0xad120000), SPH_C32(0x741e006d), + SPH_C32(0x0c283800), SPH_C32(0xc5c8064a), SPH_C32(0x87224c29), + SPH_C32(0x968c23dc), SPH_C32(0x60b5f975), SPH_C32(0xe61e0000), + SPH_C32(0x7f330000), SPH_C32(0x95200056), SPH_C32(0xa1bb1800), + SPH_C32(0xe2eb36a1), SPH_C32(0xc8c381c4), SPH_C32(0xb9ddc5a8), + SPH_C32(0x0eaec942) }, + { SPH_C32(0x93f20000), SPH_C32(0x061e0000), SPH_C32(0x44a0006c), + SPH_C32(0x65221800), SPH_C32(0x07347453), SPH_C32(0x36f6cc24), + SPH_C32(0xbb5dd99a), SPH_C32(0x4484b662), SPH_C32(0xbe5d0000), + SPH_C32(0xff4d0000), SPH_C32(0xed130057), SPH_C32(0x67d02000), + SPH_C32(0x05dc6a7d), SPH_C32(0xb16ebe19), SPH_C32(0x15ae3bc7), + SPH_C32(0x34eab0f3) }, + { SPH_C32(0xcbb10000), SPH_C32(0x86600000), SPH_C32(0x3c93006d), + SPH_C32(0xa3492000), SPH_C32(0xe003288f), SPH_C32(0x4f5bf3f9), + SPH_C32(0x172e27f5), SPH_C32(0x7ec0cfd3), SPH_C32(0xa3070000), + SPH_C32(0xd43f0000), SPH_C32(0xa59e0057), SPH_C32(0xc8b13800), + SPH_C32(0x201744b8), SPH_C32(0x791701c9), SPH_C32(0x940c3fee), + SPH_C32(0x2a9f8655) }, + { SPH_C32(0x2b930000), SPH_C32(0x394a0000), SPH_C32(0x421d0072), + SPH_C32(0xb6ed0000), SPH_C32(0xad615743), SPH_C32(0x8650d9c9), + SPH_C32(0xcdceb56b), SPH_C32(0x51eac982), SPH_C32(0xfca90000), + SPH_C32(0xe6110000), SPH_C32(0x5ad9005c), SPH_C32(0x99d70000), + SPH_C32(0x84523bca), SPH_C32(0x487d50b0), SPH_C32(0xcc07a3a3), + SPH_C32(0x80ae4e2a) }, + { SPH_C32(0x73d00000), SPH_C32(0xb9340000), SPH_C32(0x3a2e0073), + SPH_C32(0x70863800), SPH_C32(0x4a560b9f), SPH_C32(0xfffde614), + SPH_C32(0x61bd4b04), SPH_C32(0x6baeb033), SPH_C32(0xe1f30000), + SPH_C32(0xcd630000), SPH_C32(0x1254005c), SPH_C32(0x36b61800), + SPH_C32(0xa199150f), SPH_C32(0x8004ef60), SPH_C32(0x4da5a78a), + SPH_C32(0x9edb788c) }, + { SPH_C32(0x36c90000), SPH_C32(0x12380000), SPH_C32(0x0a900072), + SPH_C32(0x198c1800), SPH_C32(0x88aa7986), SPH_C32(0x4e296619), + SPH_C32(0x4c6cb142), SPH_C32(0x4f9fff24), SPH_C32(0xb9b00000), + SPH_C32(0x4d1d0000), SPH_C32(0x6a67005d), SPH_C32(0xf0dd2000), + SPH_C32(0x46ae49d3), SPH_C32(0xf9a9d0bd), SPH_C32(0xe1d659e5), + SPH_C32(0xa49f013d) }, + { SPH_C32(0x6e8a0000), SPH_C32(0x92460000), SPH_C32(0x72a30073), + SPH_C32(0xdfe72000), SPH_C32(0x6f9d255a), SPH_C32(0x378459c4), + SPH_C32(0xe01f4f2d), SPH_C32(0x75db8695), SPH_C32(0xa4ea0000), + SPH_C32(0x666f0000), SPH_C32(0x22ea005d), SPH_C32(0x5fbc3800), + SPH_C32(0x63656716), SPH_C32(0x31d06f6d), SPH_C32(0x60745dcc), + SPH_C32(0xbaea379b) }, + { SPH_C32(0x0a1f0000), SPH_C32(0x5bcb0000), SPH_C32(0x8a1e0044), + SPH_C32(0xb3860000), SPH_C32(0x01283651), SPH_C32(0xa2673774), + SPH_C32(0x92728b63), SPH_C32(0xf42251fd), SPH_C32(0xd10a0000), + SPH_C32(0xeda30000), SPH_C32(0x6b26006c), SPH_C32(0x1e370000), + SPH_C32(0xfa943185), SPH_C32(0x510c6bea), SPH_C32(0x93a3bb17), + SPH_C32(0x6da573f8) }, + { SPH_C32(0x525c0000), SPH_C32(0xdbb50000), SPH_C32(0xf22d0045), + SPH_C32(0x75ed3800), SPH_C32(0xe61f6a8d), SPH_C32(0xdbca08a9), + SPH_C32(0x3e01750c), SPH_C32(0xce66284c), SPH_C32(0xcc500000), + SPH_C32(0xc6d10000), SPH_C32(0x23ab006c), SPH_C32(0xb1561800), + SPH_C32(0xdf5f1f40), SPH_C32(0x9975d43a), SPH_C32(0x1201bf3e), + SPH_C32(0x73d0455e) }, + { SPH_C32(0x17450000), SPH_C32(0x70b90000), SPH_C32(0xc2930044), + SPH_C32(0x1ce71800), SPH_C32(0x24e31894), SPH_C32(0x6a1e88a4), + SPH_C32(0x13d08f4a), SPH_C32(0xea57675b), SPH_C32(0x94130000), + SPH_C32(0x46af0000), SPH_C32(0x5b98006d), SPH_C32(0x773d2000), + SPH_C32(0x3868439c), SPH_C32(0xe0d8ebe7), SPH_C32(0xbe724151), + SPH_C32(0x49943cef) }, + { SPH_C32(0x4f060000), SPH_C32(0xf0c70000), SPH_C32(0xbaa00045), + SPH_C32(0xda8c2000), SPH_C32(0xc3d44448), SPH_C32(0x13b3b779), + SPH_C32(0xbfa37125), SPH_C32(0xd0131eea), SPH_C32(0x89490000), + SPH_C32(0x6ddd0000), SPH_C32(0x1315006d), SPH_C32(0xd85c3800), + SPH_C32(0x1da36d59), SPH_C32(0x28a15437), SPH_C32(0x3fd04578), + SPH_C32(0x57e10a49) }, + { SPH_C32(0xaf240000), SPH_C32(0x4fed0000), SPH_C32(0xc42e005a), + SPH_C32(0xcf280000), SPH_C32(0x8eb63b84), SPH_C32(0xdab89d49), + SPH_C32(0x6543e3bb), SPH_C32(0xff3918bb), SPH_C32(0xd6e70000), + SPH_C32(0x5ff30000), SPH_C32(0xec520066), SPH_C32(0x893a0000), + SPH_C32(0xb9e6122b), SPH_C32(0x19cb054e), SPH_C32(0x67dbd935), + SPH_C32(0xfdd0c236) }, + { SPH_C32(0xf7670000), SPH_C32(0xcf930000), SPH_C32(0xbc1d005b), + SPH_C32(0x09433800), SPH_C32(0x69816758), SPH_C32(0xa315a294), + SPH_C32(0xc9301dd4), SPH_C32(0xc57d610a), SPH_C32(0xcbbd0000), + SPH_C32(0x74810000), SPH_C32(0xa4df0066), SPH_C32(0x265b1800), + SPH_C32(0x9c2d3cee), SPH_C32(0xd1b2ba9e), SPH_C32(0xe679dd1c), + SPH_C32(0xe3a5f490) }, + { SPH_C32(0xb27e0000), SPH_C32(0x649f0000), SPH_C32(0x8ca3005a), + SPH_C32(0x60491800), SPH_C32(0xab7d1541), SPH_C32(0x12c12299), + SPH_C32(0xe4e1e792), SPH_C32(0xe14c2e1d), SPH_C32(0x93fe0000), + SPH_C32(0xf4ff0000), SPH_C32(0xdcec0067), SPH_C32(0xe0302000), + SPH_C32(0x7b1a6032), SPH_C32(0xa81f8543), SPH_C32(0x4a0a2373), + SPH_C32(0xd9e18d21) }, + { SPH_C32(0xea3d0000), SPH_C32(0xe4e10000), SPH_C32(0xf490005b), + SPH_C32(0xa6222000), SPH_C32(0x4c4a499d), SPH_C32(0x6b6c1d44), + SPH_C32(0x489219fd), SPH_C32(0xdb0857ac), SPH_C32(0x8ea40000), + SPH_C32(0xdf8d0000), SPH_C32(0x94610067), SPH_C32(0x4f513800), + SPH_C32(0x5ed14ef7), SPH_C32(0x60663a93), SPH_C32(0xcba8275a), + SPH_C32(0xc794bb87) }, + { SPH_C32(0x0df20000), SPH_C32(0xe99b0000), SPH_C32(0x0d6a004e), + SPH_C32(0x248b0000), SPH_C32(0x425a15ff), SPH_C32(0xeaa059d0), + SPH_C32(0x660ae941), SPH_C32(0x6457e033), SPH_C32(0x73dc0000), + SPH_C32(0x4bd50000), SPH_C32(0xa2620078), SPH_C32(0xf5940000), + SPH_C32(0x36781ffe), SPH_C32(0x6114af73), SPH_C32(0x90eab1ed), + SPH_C32(0xf6cb8b70) }, + { SPH_C32(0x55b10000), SPH_C32(0x69e50000), SPH_C32(0x7559004f), + SPH_C32(0xe2e03800), SPH_C32(0xa56d4923), SPH_C32(0x930d660d), + SPH_C32(0xca79172e), SPH_C32(0x5e139982), SPH_C32(0x6e860000), + SPH_C32(0x60a70000), SPH_C32(0xeaef0078), SPH_C32(0x5af51800), + SPH_C32(0x13b3313b), SPH_C32(0xa96d10a3), SPH_C32(0x1148b5c4), + SPH_C32(0xe8bebdd6) }, + { SPH_C32(0x10a80000), SPH_C32(0xc2e90000), SPH_C32(0x45e7004e), + SPH_C32(0x8bea1800), SPH_C32(0x67913b3a), SPH_C32(0x22d9e600), + SPH_C32(0xe7a8ed68), SPH_C32(0x7a22d695), SPH_C32(0x36c50000), + SPH_C32(0xe0d90000), SPH_C32(0x92dc0079), SPH_C32(0x9c9e2000), + SPH_C32(0xf4846de7), SPH_C32(0xd0c02f7e), SPH_C32(0xbd3b4bab), + SPH_C32(0xd2fac467) }, + { SPH_C32(0x48eb0000), SPH_C32(0x42970000), SPH_C32(0x3dd4004f), + SPH_C32(0x4d812000), SPH_C32(0x80a667e6), SPH_C32(0x5b74d9dd), + SPH_C32(0x4bdb1307), SPH_C32(0x4066af24), SPH_C32(0x2b9f0000), + SPH_C32(0xcbab0000), SPH_C32(0xda510079), SPH_C32(0x33ff3800), + SPH_C32(0xd14f4322), SPH_C32(0x18b990ae), SPH_C32(0x3c994f82), + SPH_C32(0xcc8ff2c1) }, + { SPH_C32(0xa8c90000), SPH_C32(0xfdbd0000), SPH_C32(0x435a0050), + SPH_C32(0x58250000), SPH_C32(0xcdc4182a), SPH_C32(0x927ff3ed), + SPH_C32(0x913b8199), SPH_C32(0x6f4ca975), SPH_C32(0x74310000), + SPH_C32(0xf9850000), SPH_C32(0x25160072), SPH_C32(0x62990000), + SPH_C32(0x750a3c50), SPH_C32(0x29d3c1d7), SPH_C32(0x6492d3cf), + SPH_C32(0x66be3abe) }, + { SPH_C32(0xf08a0000), SPH_C32(0x7dc30000), SPH_C32(0x3b690051), + SPH_C32(0x9e4e3800), SPH_C32(0x2af344f6), SPH_C32(0xebd2cc30), + SPH_C32(0x3d487ff6), SPH_C32(0x5508d0c4), SPH_C32(0x696b0000), + SPH_C32(0xd2f70000), SPH_C32(0x6d9b0072), SPH_C32(0xcdf81800), + SPH_C32(0x50c11295), SPH_C32(0xe1aa7e07), SPH_C32(0xe530d7e6), + SPH_C32(0x78cb0c18) }, + { SPH_C32(0xb5930000), SPH_C32(0xd6cf0000), SPH_C32(0x0bd70050), + SPH_C32(0xf7441800), SPH_C32(0xe80f36ef), SPH_C32(0x5a064c3d), + SPH_C32(0x109985b0), SPH_C32(0x71399fd3), SPH_C32(0x31280000), + SPH_C32(0x52890000), SPH_C32(0x15a80073), SPH_C32(0x0b932000), + SPH_C32(0xb7f64e49), SPH_C32(0x980741da), SPH_C32(0x49432989), + SPH_C32(0x428f75a9) }, + { SPH_C32(0xedd00000), SPH_C32(0x56b10000), SPH_C32(0x73e40051), + SPH_C32(0x312f2000), SPH_C32(0x0f386a33), SPH_C32(0x23ab73e0), + SPH_C32(0xbcea7bdf), SPH_C32(0x4b7de662), SPH_C32(0x2c720000), + SPH_C32(0x79fb0000), SPH_C32(0x5d250073), SPH_C32(0xa4f23800), + SPH_C32(0x923d608c), SPH_C32(0x507efe0a), SPH_C32(0xc8e12da0), + SPH_C32(0x5cfa430f) }, + { SPH_C32(0x82870000), SPH_C32(0x445f0000), SPH_C32(0xf5d1006a), + SPH_C32(0x48c80000), SPH_C32(0xf07031cb), SPH_C32(0xc3c9a613), + SPH_C32(0x3ae7fb0f), SPH_C32(0x12322569), SPH_C32(0xdac80000), + SPH_C32(0x36c00000), SPH_C32(0x15ae0060), SPH_C32(0x0bb10000), + SPH_C32(0x6b697976), SPH_C32(0x248dd0a9), SPH_C32(0x67c3ff89), + SPH_C32(0xb513679b) }, + { SPH_C32(0xdac40000), SPH_C32(0xc4210000), SPH_C32(0x8de2006b), + SPH_C32(0x8ea33800), SPH_C32(0x17476d17), SPH_C32(0xba6499ce), + SPH_C32(0x96940560), SPH_C32(0x28765cd8), SPH_C32(0xc7920000), + SPH_C32(0x1db20000), SPH_C32(0x5d230060), SPH_C32(0xa4d01800), + SPH_C32(0x4ea257b3), SPH_C32(0xecf46f79), SPH_C32(0xe661fba0), + SPH_C32(0xab66513d) }, + { SPH_C32(0x9fdd0000), SPH_C32(0x6f2d0000), SPH_C32(0xbd5c006a), + SPH_C32(0xe7a91800), SPH_C32(0xd5bb1f0e), SPH_C32(0x0bb019c3), + SPH_C32(0xbb45ff26), SPH_C32(0x0c4713cf), SPH_C32(0x9fd10000), + SPH_C32(0x9dcc0000), SPH_C32(0x25100061), SPH_C32(0x62bb2000), + SPH_C32(0xa9950b6f), SPH_C32(0x955950a4), SPH_C32(0x4a1205cf), + SPH_C32(0x9122288c) }, + { SPH_C32(0xc79e0000), SPH_C32(0xef530000), SPH_C32(0xc56f006b), + SPH_C32(0x21c22000), SPH_C32(0x328c43d2), SPH_C32(0x721d261e), + SPH_C32(0x17360149), SPH_C32(0x36036a7e), SPH_C32(0x828b0000), + SPH_C32(0xb6be0000), SPH_C32(0x6d9d0061), SPH_C32(0xcdda3800), + SPH_C32(0x8c5e25aa), SPH_C32(0x5d20ef74), SPH_C32(0xcbb001e6), + SPH_C32(0x8f571e2a) }, + { SPH_C32(0x27bc0000), SPH_C32(0x50790000), SPH_C32(0xbbe10074), + SPH_C32(0x34660000), SPH_C32(0x7fee3c1e), SPH_C32(0xbb160c2e), + SPH_C32(0xcdd693d7), SPH_C32(0x19296c2f), SPH_C32(0xdd250000), + SPH_C32(0x84900000), SPH_C32(0x92da006a), SPH_C32(0x9cbc0000), + SPH_C32(0x281b5ad8), SPH_C32(0x6c4abe0d), SPH_C32(0x93bb9dab), + SPH_C32(0x2566d655) }, + { SPH_C32(0x7fff0000), SPH_C32(0xd0070000), SPH_C32(0xc3d20075), + SPH_C32(0xf20d3800), SPH_C32(0x98d960c2), SPH_C32(0xc2bb33f3), + SPH_C32(0x61a56db8), SPH_C32(0x236d159e), SPH_C32(0xc07f0000), + SPH_C32(0xafe20000), SPH_C32(0xda57006a), SPH_C32(0x33dd1800), + SPH_C32(0x0dd0741d), SPH_C32(0xa43301dd), SPH_C32(0x12199982), + SPH_C32(0x3b13e0f3) }, + { SPH_C32(0x3ae60000), SPH_C32(0x7b0b0000), SPH_C32(0xf36c0074), + SPH_C32(0x9b071800), SPH_C32(0x5a2512db), SPH_C32(0x736fb3fe), + SPH_C32(0x4c7497fe), SPH_C32(0x075c5a89), SPH_C32(0x983c0000), + SPH_C32(0x2f9c0000), SPH_C32(0xa264006b), SPH_C32(0xf5b62000), + SPH_C32(0xeae728c1), SPH_C32(0xdd9e3e00), SPH_C32(0xbe6a67ed), + SPH_C32(0x01579942) }, + { SPH_C32(0x62a50000), SPH_C32(0xfb750000), SPH_C32(0x8b5f0075), + SPH_C32(0x5d6c2000), SPH_C32(0xbd124e07), SPH_C32(0x0ac28c23), + SPH_C32(0xe0076991), SPH_C32(0x3d182338), SPH_C32(0x85660000), + SPH_C32(0x04ee0000), SPH_C32(0xeae9006b), SPH_C32(0x5ad73800), + SPH_C32(0xcf2c0604), SPH_C32(0x15e781d0), SPH_C32(0x3fc863c4), + SPH_C32(0x1f22afe4) }, + { SPH_C32(0x856a0000), SPH_C32(0xf60f0000), SPH_C32(0x72a50060), + SPH_C32(0xdfc50000), SPH_C32(0xb3021265), SPH_C32(0x8b0ec8b7), + SPH_C32(0xce9f992d), SPH_C32(0x824794a7), SPH_C32(0x781e0000), + SPH_C32(0x90b60000), SPH_C32(0xdcea0074), SPH_C32(0xe0120000), + SPH_C32(0xa785570d), SPH_C32(0x14951430), SPH_C32(0x648af573), + SPH_C32(0x2e7d9f13) }, + { SPH_C32(0xdd290000), SPH_C32(0x76710000), SPH_C32(0x0a960061), + SPH_C32(0x19ae3800), SPH_C32(0x54354eb9), SPH_C32(0xf2a3f76a), + SPH_C32(0x62ec6742), SPH_C32(0xb803ed16), SPH_C32(0x65440000), + SPH_C32(0xbbc40000), SPH_C32(0x94670074), SPH_C32(0x4f731800), + SPH_C32(0x824e79c8), SPH_C32(0xdcecabe0), SPH_C32(0xe528f15a), + SPH_C32(0x3008a9b5) }, + { SPH_C32(0x98300000), SPH_C32(0xdd7d0000), SPH_C32(0x3a280060), + SPH_C32(0x70a41800), SPH_C32(0x96c93ca0), SPH_C32(0x43777767), + SPH_C32(0x4f3d9d04), SPH_C32(0x9c32a201), SPH_C32(0x3d070000), + SPH_C32(0x3bba0000), SPH_C32(0xec540075), SPH_C32(0x89182000), + SPH_C32(0x65792514), SPH_C32(0xa541943d), SPH_C32(0x495b0f35), + SPH_C32(0x0a4cd004) }, + { SPH_C32(0xc0730000), SPH_C32(0x5d030000), SPH_C32(0x421b0061), + SPH_C32(0xb6cf2000), SPH_C32(0x71fe607c), SPH_C32(0x3ada48ba), + SPH_C32(0xe34e636b), SPH_C32(0xa676dbb0), SPH_C32(0x205d0000), + SPH_C32(0x10c80000), SPH_C32(0xa4d90075), SPH_C32(0x26793800), + SPH_C32(0x40b20bd1), SPH_C32(0x6d382bed), SPH_C32(0xc8f90b1c), + SPH_C32(0x1439e6a2) }, + { SPH_C32(0x20510000), SPH_C32(0xe2290000), SPH_C32(0x3c95007e), + SPH_C32(0xa36b0000), SPH_C32(0x3c9c1fb0), SPH_C32(0xf3d1628a), + SPH_C32(0x39aef1f5), SPH_C32(0x895cdde1), SPH_C32(0x7ff30000), + SPH_C32(0x22e60000), SPH_C32(0x5b9e007e), SPH_C32(0x771f0000), + SPH_C32(0xe4f774a3), SPH_C32(0x5c527a94), SPH_C32(0x90f29751), + SPH_C32(0xbe082edd) }, + { SPH_C32(0x78120000), SPH_C32(0x62570000), SPH_C32(0x44a6007f), + SPH_C32(0x65003800), SPH_C32(0xdbab436c), SPH_C32(0x8a7c5d57), + SPH_C32(0x95dd0f9a), SPH_C32(0xb318a450), SPH_C32(0x62a90000), + SPH_C32(0x09940000), SPH_C32(0x1313007e), SPH_C32(0xd87e1800), + SPH_C32(0xc13c5a66), SPH_C32(0x942bc544), SPH_C32(0x11509378), + SPH_C32(0xa07d187b) }, + { SPH_C32(0x3d0b0000), SPH_C32(0xc95b0000), SPH_C32(0x7418007e), + SPH_C32(0x0c0a1800), SPH_C32(0x19573175), SPH_C32(0x3ba8dd5a), + SPH_C32(0xb80cf5dc), SPH_C32(0x9729eb47), SPH_C32(0x3aea0000), + SPH_C32(0x89ea0000), SPH_C32(0x6b20007f), SPH_C32(0x1e152000), + SPH_C32(0x260b06ba), SPH_C32(0xed86fa99), SPH_C32(0xbd236d17), + SPH_C32(0x9a3961ca) }, + { SPH_C32(0x65480000), SPH_C32(0x49250000), SPH_C32(0x0c2b007f), + SPH_C32(0xca612000), SPH_C32(0xfe606da9), SPH_C32(0x4205e287), + SPH_C32(0x147f0bb3), SPH_C32(0xad6d92f6), SPH_C32(0x27b00000), + SPH_C32(0xa2980000), SPH_C32(0x23ad007f), SPH_C32(0xb1743800), + SPH_C32(0x03c0287f), SPH_C32(0x25ff4549), SPH_C32(0x3c81693e), + SPH_C32(0x844c576c) } +}; + +static const sph_u32 T512_48[256][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0xe6280000), SPH_C32(0x4c4b0000), SPH_C32(0xa8550000), + SPH_C32(0xd3d002e0), SPH_C32(0xd86130b8), SPH_C32(0x98a7b0da), + SPH_C32(0x289506b4), SPH_C32(0xd75a4897), SPH_C32(0xf0c50000), + SPH_C32(0x59230000), SPH_C32(0x45820000), SPH_C32(0xe18d00c0), + SPH_C32(0x3b6d0631), SPH_C32(0xc2ed5699), SPH_C32(0xcbe0fe1c), + SPH_C32(0x56a7b19f) }, + { SPH_C32(0xf0c50000), SPH_C32(0x59230000), SPH_C32(0x45820000), + SPH_C32(0xe18d00c0), SPH_C32(0x3b6d0631), SPH_C32(0xc2ed5699), + SPH_C32(0xcbe0fe1c), SPH_C32(0x56a7b19f), SPH_C32(0x16ed0000), + SPH_C32(0x15680000), SPH_C32(0xedd70000), SPH_C32(0x325d0220), + SPH_C32(0xe30c3689), SPH_C32(0x5a4ae643), SPH_C32(0xe375f8a8), + SPH_C32(0x81fdf908) }, + { SPH_C32(0x16ed0000), SPH_C32(0x15680000), SPH_C32(0xedd70000), + SPH_C32(0x325d0220), SPH_C32(0xe30c3689), SPH_C32(0x5a4ae643), + SPH_C32(0xe375f8a8), SPH_C32(0x81fdf908), SPH_C32(0xe6280000), + SPH_C32(0x4c4b0000), SPH_C32(0xa8550000), SPH_C32(0xd3d002e0), + SPH_C32(0xd86130b8), SPH_C32(0x98a7b0da), SPH_C32(0x289506b4), + SPH_C32(0xd75a4897) }, + { SPH_C32(0xb4310000), SPH_C32(0x77330000), SPH_C32(0xb15d0000), + SPH_C32(0x7fd004e0), SPH_C32(0x78a26138), SPH_C32(0xd116c35d), + SPH_C32(0xd256d489), SPH_C32(0x4e6f74de), SPH_C32(0xe3060000), + SPH_C32(0xbdc10000), SPH_C32(0x87130000), SPH_C32(0xbff20060), + SPH_C32(0x2eba0a1a), SPH_C32(0x8db53751), SPH_C32(0x73c5ab06), + SPH_C32(0x5bd61539) }, + { SPH_C32(0x52190000), SPH_C32(0x3b780000), SPH_C32(0x19080000), + SPH_C32(0xac000600), SPH_C32(0xa0c35180), SPH_C32(0x49b17387), + SPH_C32(0xfac3d23d), SPH_C32(0x99353c49), SPH_C32(0x13c30000), + SPH_C32(0xe4e20000), SPH_C32(0xc2910000), SPH_C32(0x5e7f00a0), + SPH_C32(0x15d70c2b), SPH_C32(0x4f5861c8), SPH_C32(0xb825551a), + SPH_C32(0x0d71a4a6) }, + { SPH_C32(0x44f40000), SPH_C32(0x2e100000), SPH_C32(0xf4df0000), + SPH_C32(0x9e5d0420), SPH_C32(0x43cf6709), SPH_C32(0x13fb95c4), + SPH_C32(0x19b62a95), SPH_C32(0x18c8c541), SPH_C32(0xf5eb0000), + SPH_C32(0xa8a90000), SPH_C32(0x6ac40000), SPH_C32(0x8daf0240), + SPH_C32(0xcdb63c93), SPH_C32(0xd7ffd112), SPH_C32(0x90b053ae), + SPH_C32(0xda2bec31) }, + { SPH_C32(0xa2dc0000), SPH_C32(0x625b0000), SPH_C32(0x5c8a0000), + SPH_C32(0x4d8d06c0), SPH_C32(0x9bae57b1), SPH_C32(0x8b5c251e), + SPH_C32(0x31232c21), SPH_C32(0xcf928dd6), SPH_C32(0x052e0000), + SPH_C32(0xf18a0000), SPH_C32(0x2f460000), SPH_C32(0x6c220280), + SPH_C32(0xf6db3aa2), SPH_C32(0x1512878b), SPH_C32(0x5b50adb2), + SPH_C32(0x8c8c5dae) }, + { SPH_C32(0xe3060000), SPH_C32(0xbdc10000), SPH_C32(0x87130000), + SPH_C32(0xbff20060), SPH_C32(0x2eba0a1a), SPH_C32(0x8db53751), + SPH_C32(0x73c5ab06), SPH_C32(0x5bd61539), SPH_C32(0x57370000), + SPH_C32(0xcaf20000), SPH_C32(0x364e0000), SPH_C32(0xc0220480), + SPH_C32(0x56186b22), SPH_C32(0x5ca3f40c), SPH_C32(0xa1937f8f), + SPH_C32(0x15b961e7) }, + { SPH_C32(0x052e0000), SPH_C32(0xf18a0000), SPH_C32(0x2f460000), + SPH_C32(0x6c220280), SPH_C32(0xf6db3aa2), SPH_C32(0x1512878b), + SPH_C32(0x5b50adb2), SPH_C32(0x8c8c5dae), SPH_C32(0xa7f20000), + SPH_C32(0x93d10000), SPH_C32(0x73cc0000), SPH_C32(0x21af0440), + SPH_C32(0x6d756d13), SPH_C32(0x9e4ea295), SPH_C32(0x6a738193), + SPH_C32(0x431ed078) }, + { SPH_C32(0x13c30000), SPH_C32(0xe4e20000), SPH_C32(0xc2910000), + SPH_C32(0x5e7f00a0), SPH_C32(0x15d70c2b), SPH_C32(0x4f5861c8), + SPH_C32(0xb825551a), SPH_C32(0x0d71a4a6), SPH_C32(0x41da0000), + SPH_C32(0xdf9a0000), SPH_C32(0xdb990000), SPH_C32(0xf27f06a0), + SPH_C32(0xb5145dab), SPH_C32(0x06e9124f), SPH_C32(0x42e68727), + SPH_C32(0x944498ef) }, + { SPH_C32(0xf5eb0000), SPH_C32(0xa8a90000), SPH_C32(0x6ac40000), + SPH_C32(0x8daf0240), SPH_C32(0xcdb63c93), SPH_C32(0xd7ffd112), + SPH_C32(0x90b053ae), SPH_C32(0xda2bec31), SPH_C32(0xb11f0000), + SPH_C32(0x86b90000), SPH_C32(0x9e1b0000), SPH_C32(0x13f20660), + SPH_C32(0x8e795b9a), SPH_C32(0xc40444d6), SPH_C32(0x8906793b), + SPH_C32(0xc2e32970) }, + { SPH_C32(0x57370000), SPH_C32(0xcaf20000), SPH_C32(0x364e0000), + SPH_C32(0xc0220480), SPH_C32(0x56186b22), SPH_C32(0x5ca3f40c), + SPH_C32(0xa1937f8f), SPH_C32(0x15b961e7), SPH_C32(0xb4310000), + SPH_C32(0x77330000), SPH_C32(0xb15d0000), SPH_C32(0x7fd004e0), + SPH_C32(0x78a26138), SPH_C32(0xd116c35d), SPH_C32(0xd256d489), + SPH_C32(0x4e6f74de) }, + { SPH_C32(0xb11f0000), SPH_C32(0x86b90000), SPH_C32(0x9e1b0000), + SPH_C32(0x13f20660), SPH_C32(0x8e795b9a), SPH_C32(0xc40444d6), + SPH_C32(0x8906793b), SPH_C32(0xc2e32970), SPH_C32(0x44f40000), + SPH_C32(0x2e100000), SPH_C32(0xf4df0000), SPH_C32(0x9e5d0420), + SPH_C32(0x43cf6709), SPH_C32(0x13fb95c4), SPH_C32(0x19b62a95), + SPH_C32(0x18c8c541) }, + { SPH_C32(0xa7f20000), SPH_C32(0x93d10000), SPH_C32(0x73cc0000), + SPH_C32(0x21af0440), SPH_C32(0x6d756d13), SPH_C32(0x9e4ea295), + SPH_C32(0x6a738193), SPH_C32(0x431ed078), SPH_C32(0xa2dc0000), + SPH_C32(0x625b0000), SPH_C32(0x5c8a0000), SPH_C32(0x4d8d06c0), + SPH_C32(0x9bae57b1), SPH_C32(0x8b5c251e), SPH_C32(0x31232c21), + SPH_C32(0xcf928dd6) }, + { SPH_C32(0x41da0000), SPH_C32(0xdf9a0000), SPH_C32(0xdb990000), + SPH_C32(0xf27f06a0), SPH_C32(0xb5145dab), SPH_C32(0x06e9124f), + SPH_C32(0x42e68727), SPH_C32(0x944498ef), SPH_C32(0x52190000), + SPH_C32(0x3b780000), SPH_C32(0x19080000), SPH_C32(0xac000600), + SPH_C32(0xa0c35180), SPH_C32(0x49b17387), SPH_C32(0xfac3d23d), + SPH_C32(0x99353c49) }, + { SPH_C32(0x02f20000), SPH_C32(0xa2810000), SPH_C32(0x873f0000), + SPH_C32(0xe36c7800), SPH_C32(0x1e1d74ef), SPH_C32(0x073d2bd6), + SPH_C32(0xc4c23237), SPH_C32(0x7f32259e), SPH_C32(0xbadd0000), + SPH_C32(0x13ad0000), SPH_C32(0xb7e70000), SPH_C32(0xf7282800), + SPH_C32(0xdf45144d), SPH_C32(0x361ac33a), SPH_C32(0xea5a8d14), + SPH_C32(0x2a2c18f0) }, + { SPH_C32(0xe4da0000), SPH_C32(0xeeca0000), SPH_C32(0x2f6a0000), + SPH_C32(0x30bc7ae0), SPH_C32(0xc67c4457), SPH_C32(0x9f9a9b0c), + SPH_C32(0xec573483), SPH_C32(0xa8686d09), SPH_C32(0x4a180000), + SPH_C32(0x4a8e0000), SPH_C32(0xf2650000), SPH_C32(0x16a528c0), + SPH_C32(0xe428127c), SPH_C32(0xf4f795a3), SPH_C32(0x21ba7308), + SPH_C32(0x7c8ba96f) }, + { SPH_C32(0xf2370000), SPH_C32(0xfba20000), SPH_C32(0xc2bd0000), + SPH_C32(0x02e178c0), SPH_C32(0x257072de), SPH_C32(0xc5d07d4f), + SPH_C32(0x0f22cc2b), SPH_C32(0x29959401), SPH_C32(0xac300000), + SPH_C32(0x06c50000), SPH_C32(0x5a300000), SPH_C32(0xc5752a20), + SPH_C32(0x3c4922c4), SPH_C32(0x6c502579), SPH_C32(0x092f75bc), + SPH_C32(0xabd1e1f8) }, + { SPH_C32(0x141f0000), SPH_C32(0xb7e90000), SPH_C32(0x6ae80000), + SPH_C32(0xd1317a20), SPH_C32(0xfd114266), SPH_C32(0x5d77cd95), + SPH_C32(0x27b7ca9f), SPH_C32(0xfecfdc96), SPH_C32(0x5cf50000), + SPH_C32(0x5fe60000), SPH_C32(0x1fb20000), SPH_C32(0x24f82ae0), + SPH_C32(0x072424f5), SPH_C32(0xaebd73e0), SPH_C32(0xc2cf8ba0), + SPH_C32(0xfd765067) }, + { SPH_C32(0xb6c30000), SPH_C32(0xd5b20000), SPH_C32(0x36620000), + SPH_C32(0x9cbc7ce0), SPH_C32(0x66bf15d7), SPH_C32(0xd62be88b), + SPH_C32(0x1694e6be), SPH_C32(0x315d5140), SPH_C32(0x59db0000), + SPH_C32(0xae6c0000), SPH_C32(0x30f40000), SPH_C32(0x48da2860), + SPH_C32(0xf1ff1e57), SPH_C32(0xbbaff46b), SPH_C32(0x999f2612), + SPH_C32(0x71fa0dc9) }, + { SPH_C32(0x50eb0000), SPH_C32(0x99f90000), SPH_C32(0x9e370000), + SPH_C32(0x4f6c7e00), SPH_C32(0xbede256f), SPH_C32(0x4e8c5851), + SPH_C32(0x3e01e00a), SPH_C32(0xe60719d7), SPH_C32(0xa91e0000), + SPH_C32(0xf74f0000), SPH_C32(0x75760000), SPH_C32(0xa95728a0), + SPH_C32(0xca921866), SPH_C32(0x7942a2f2), SPH_C32(0x527fd80e), + SPH_C32(0x275dbc56) }, + { SPH_C32(0x46060000), SPH_C32(0x8c910000), SPH_C32(0x73e00000), + SPH_C32(0x7d317c20), SPH_C32(0x5dd213e6), SPH_C32(0x14c6be12), + SPH_C32(0xdd7418a2), SPH_C32(0x67fae0df), SPH_C32(0x4f360000), + SPH_C32(0xbb040000), SPH_C32(0xdd230000), SPH_C32(0x7a872a40), + SPH_C32(0x12f328de), SPH_C32(0xe1e51228), SPH_C32(0x7aeadeba), + SPH_C32(0xf007f4c1) }, + { SPH_C32(0xa02e0000), SPH_C32(0xc0da0000), SPH_C32(0xdbb50000), + SPH_C32(0xaee17ec0), SPH_C32(0x85b3235e), SPH_C32(0x8c610ec8), + SPH_C32(0xf5e11e16), SPH_C32(0xb0a0a848), SPH_C32(0xbff30000), + SPH_C32(0xe2270000), SPH_C32(0x98a10000), SPH_C32(0x9b0a2a80), + SPH_C32(0x299e2eef), SPH_C32(0x230844b1), SPH_C32(0xb10a20a6), + SPH_C32(0xa6a0455e) }, + { SPH_C32(0xe1f40000), SPH_C32(0x1f400000), SPH_C32(0x002c0000), + SPH_C32(0x5c9e7860), SPH_C32(0x30a77ef5), SPH_C32(0x8a881c87), + SPH_C32(0xb7079931), SPH_C32(0x24e430a7), SPH_C32(0xedea0000), + SPH_C32(0xd95f0000), SPH_C32(0x81a90000), SPH_C32(0x370a2c80), + SPH_C32(0x895d7f6f), SPH_C32(0x6ab93736), SPH_C32(0x4bc9f29b), + SPH_C32(0x3f957917) }, + { SPH_C32(0x07dc0000), SPH_C32(0x530b0000), SPH_C32(0xa8790000), + SPH_C32(0x8f4e7a80), SPH_C32(0xe8c64e4d), SPH_C32(0x122fac5d), + SPH_C32(0x9f929f85), SPH_C32(0xf3be7830), SPH_C32(0x1d2f0000), + SPH_C32(0x807c0000), SPH_C32(0xc42b0000), SPH_C32(0xd6872c40), + SPH_C32(0xb230795e), SPH_C32(0xa85461af), SPH_C32(0x80290c87), + SPH_C32(0x6932c888) }, + { SPH_C32(0x11310000), SPH_C32(0x46630000), SPH_C32(0x45ae0000), + SPH_C32(0xbd1378a0), SPH_C32(0x0bca78c4), SPH_C32(0x48654a1e), + SPH_C32(0x7ce7672d), SPH_C32(0x72438138), SPH_C32(0xfb070000), + SPH_C32(0xcc370000), SPH_C32(0x6c7e0000), SPH_C32(0x05572ea0), + SPH_C32(0x6a5149e6), SPH_C32(0x30f3d175), SPH_C32(0xa8bc0a33), + SPH_C32(0xbe68801f) }, + { SPH_C32(0xf7190000), SPH_C32(0x0a280000), SPH_C32(0xedfb0000), + SPH_C32(0x6ec37a40), SPH_C32(0xd3ab487c), SPH_C32(0xd0c2fac4), + SPH_C32(0x54726199), SPH_C32(0xa519c9af), SPH_C32(0x0bc20000), + SPH_C32(0x95140000), SPH_C32(0x29fc0000), SPH_C32(0xe4da2e60), + SPH_C32(0x513c4fd7), SPH_C32(0xf21e87ec), SPH_C32(0x635cf42f), + SPH_C32(0xe8cf3180) }, + { SPH_C32(0x55c50000), SPH_C32(0x68730000), SPH_C32(0xb1710000), + SPH_C32(0x234e7c80), SPH_C32(0x48051fcd), SPH_C32(0x5b9edfda), + SPH_C32(0x65514db8), SPH_C32(0x6a8b4479), SPH_C32(0x0eec0000), + SPH_C32(0x649e0000), SPH_C32(0x06ba0000), SPH_C32(0x88f82ce0), + SPH_C32(0xa7e77575), SPH_C32(0xe70c0067), SPH_C32(0x380c599d), + SPH_C32(0x64436c2e) }, + { SPH_C32(0xb3ed0000), SPH_C32(0x24380000), SPH_C32(0x19240000), + SPH_C32(0xf09e7e60), SPH_C32(0x90642f75), SPH_C32(0xc3396f00), + SPH_C32(0x4dc44b0c), SPH_C32(0xbdd10cee), SPH_C32(0xfe290000), + SPH_C32(0x3dbd0000), SPH_C32(0x43380000), SPH_C32(0x69752c20), + SPH_C32(0x9c8a7344), SPH_C32(0x25e156fe), SPH_C32(0xf3eca781), + SPH_C32(0x32e4ddb1) }, + { SPH_C32(0xa5000000), SPH_C32(0x31500000), SPH_C32(0xf4f30000), + SPH_C32(0xc2c37c40), SPH_C32(0x736819fc), SPH_C32(0x99738943), + SPH_C32(0xaeb1b3a4), SPH_C32(0x3c2cf5e6), SPH_C32(0x18010000), + SPH_C32(0x71f60000), SPH_C32(0xeb6d0000), SPH_C32(0xbaa52ec0), + SPH_C32(0x44eb43fc), SPH_C32(0xbd46e624), SPH_C32(0xdb79a135), + SPH_C32(0xe5be9526) }, + { SPH_C32(0x43280000), SPH_C32(0x7d1b0000), SPH_C32(0x5ca60000), + SPH_C32(0x11137ea0), SPH_C32(0xab092944), SPH_C32(0x01d43999), + SPH_C32(0x8624b510), SPH_C32(0xeb76bd71), SPH_C32(0xe8c40000), + SPH_C32(0x28d50000), SPH_C32(0xaeef0000), SPH_C32(0x5b282e00), + SPH_C32(0x7f8645cd), SPH_C32(0x7fabb0bd), SPH_C32(0x10995f29), + SPH_C32(0xb31924b9) }, + { SPH_C32(0xbadd0000), SPH_C32(0x13ad0000), SPH_C32(0xb7e70000), + SPH_C32(0xf7282800), SPH_C32(0xdf45144d), SPH_C32(0x361ac33a), + SPH_C32(0xea5a8d14), SPH_C32(0x2a2c18f0), SPH_C32(0xb82f0000), + SPH_C32(0xb12c0000), SPH_C32(0x30d80000), SPH_C32(0x14445000), + SPH_C32(0xc15860a2), SPH_C32(0x3127e8ec), SPH_C32(0x2e98bf23), + SPH_C32(0x551e3d6e) }, + { SPH_C32(0x5cf50000), SPH_C32(0x5fe60000), SPH_C32(0x1fb20000), + SPH_C32(0x24f82ae0), SPH_C32(0x072424f5), SPH_C32(0xaebd73e0), + SPH_C32(0xc2cf8ba0), SPH_C32(0xfd765067), SPH_C32(0x48ea0000), + SPH_C32(0xe80f0000), SPH_C32(0x755a0000), SPH_C32(0xf5c950c0), + SPH_C32(0xfa356693), SPH_C32(0xf3cabe75), SPH_C32(0xe578413f), + SPH_C32(0x03b98cf1) }, + { SPH_C32(0x4a180000), SPH_C32(0x4a8e0000), SPH_C32(0xf2650000), + SPH_C32(0x16a528c0), SPH_C32(0xe428127c), SPH_C32(0xf4f795a3), + SPH_C32(0x21ba7308), SPH_C32(0x7c8ba96f), SPH_C32(0xaec20000), + SPH_C32(0xa4440000), SPH_C32(0xdd0f0000), SPH_C32(0x26195220), + SPH_C32(0x2254562b), SPH_C32(0x6b6d0eaf), SPH_C32(0xcded478b), + SPH_C32(0xd4e3c466) }, + { SPH_C32(0xac300000), SPH_C32(0x06c50000), SPH_C32(0x5a300000), + SPH_C32(0xc5752a20), SPH_C32(0x3c4922c4), SPH_C32(0x6c502579), + SPH_C32(0x092f75bc), SPH_C32(0xabd1e1f8), SPH_C32(0x5e070000), + SPH_C32(0xfd670000), SPH_C32(0x988d0000), SPH_C32(0xc79452e0), + SPH_C32(0x1939501a), SPH_C32(0xa9805836), SPH_C32(0x060db997), + SPH_C32(0x824475f9) }, + { SPH_C32(0x0eec0000), SPH_C32(0x649e0000), SPH_C32(0x06ba0000), + SPH_C32(0x88f82ce0), SPH_C32(0xa7e77575), SPH_C32(0xe70c0067), + SPH_C32(0x380c599d), SPH_C32(0x64436c2e), SPH_C32(0x5b290000), + SPH_C32(0x0ced0000), SPH_C32(0xb7cb0000), SPH_C32(0xabb65060), + SPH_C32(0xefe26ab8), SPH_C32(0xbc92dfbd), SPH_C32(0x5d5d1425), + SPH_C32(0x0ec82857) }, + { SPH_C32(0xe8c40000), SPH_C32(0x28d50000), SPH_C32(0xaeef0000), + SPH_C32(0x5b282e00), SPH_C32(0x7f8645cd), SPH_C32(0x7fabb0bd), + SPH_C32(0x10995f29), SPH_C32(0xb31924b9), SPH_C32(0xabec0000), + SPH_C32(0x55ce0000), SPH_C32(0xf2490000), SPH_C32(0x4a3b50a0), + SPH_C32(0xd48f6c89), SPH_C32(0x7e7f8924), SPH_C32(0x96bdea39), + SPH_C32(0x586f99c8) }, + { SPH_C32(0xfe290000), SPH_C32(0x3dbd0000), SPH_C32(0x43380000), + SPH_C32(0x69752c20), SPH_C32(0x9c8a7344), SPH_C32(0x25e156fe), + SPH_C32(0xf3eca781), SPH_C32(0x32e4ddb1), SPH_C32(0x4dc40000), + SPH_C32(0x19850000), SPH_C32(0x5a1c0000), SPH_C32(0x99eb5240), + SPH_C32(0x0cee5c31), SPH_C32(0xe6d839fe), SPH_C32(0xbe28ec8d), + SPH_C32(0x8f35d15f) }, + { SPH_C32(0x18010000), SPH_C32(0x71f60000), SPH_C32(0xeb6d0000), + SPH_C32(0xbaa52ec0), SPH_C32(0x44eb43fc), SPH_C32(0xbd46e624), + SPH_C32(0xdb79a135), SPH_C32(0xe5be9526), SPH_C32(0xbd010000), + SPH_C32(0x40a60000), SPH_C32(0x1f9e0000), SPH_C32(0x78665280), + SPH_C32(0x37835a00), SPH_C32(0x24356f67), SPH_C32(0x75c81291), + SPH_C32(0xd99260c0) }, + { SPH_C32(0x59db0000), SPH_C32(0xae6c0000), SPH_C32(0x30f40000), + SPH_C32(0x48da2860), SPH_C32(0xf1ff1e57), SPH_C32(0xbbaff46b), + SPH_C32(0x999f2612), SPH_C32(0x71fa0dc9), SPH_C32(0xef180000), + SPH_C32(0x7bde0000), SPH_C32(0x06960000), SPH_C32(0xd4665480), + SPH_C32(0x97400b80), SPH_C32(0x6d841ce0), SPH_C32(0x8f0bc0ac), + SPH_C32(0x40a75c89) }, + { SPH_C32(0xbff30000), SPH_C32(0xe2270000), SPH_C32(0x98a10000), + SPH_C32(0x9b0a2a80), SPH_C32(0x299e2eef), SPH_C32(0x230844b1), + SPH_C32(0xb10a20a6), SPH_C32(0xa6a0455e), SPH_C32(0x1fdd0000), + SPH_C32(0x22fd0000), SPH_C32(0x43140000), SPH_C32(0x35eb5440), + SPH_C32(0xac2d0db1), SPH_C32(0xaf694a79), SPH_C32(0x44eb3eb0), + SPH_C32(0x1600ed16) }, + { SPH_C32(0xa91e0000), SPH_C32(0xf74f0000), SPH_C32(0x75760000), + SPH_C32(0xa95728a0), SPH_C32(0xca921866), SPH_C32(0x7942a2f2), + SPH_C32(0x527fd80e), SPH_C32(0x275dbc56), SPH_C32(0xf9f50000), + SPH_C32(0x6eb60000), SPH_C32(0xeb410000), SPH_C32(0xe63b56a0), + SPH_C32(0x744c3d09), SPH_C32(0x37cefaa3), SPH_C32(0x6c7e3804), + SPH_C32(0xc15aa581) }, + { SPH_C32(0x4f360000), SPH_C32(0xbb040000), SPH_C32(0xdd230000), + SPH_C32(0x7a872a40), SPH_C32(0x12f328de), SPH_C32(0xe1e51228), + SPH_C32(0x7aeadeba), SPH_C32(0xf007f4c1), SPH_C32(0x09300000), + SPH_C32(0x37950000), SPH_C32(0xaec30000), SPH_C32(0x07b65660), + SPH_C32(0x4f213b38), SPH_C32(0xf523ac3a), SPH_C32(0xa79ec618), + SPH_C32(0x97fd141e) }, + { SPH_C32(0xedea0000), SPH_C32(0xd95f0000), SPH_C32(0x81a90000), + SPH_C32(0x370a2c80), SPH_C32(0x895d7f6f), SPH_C32(0x6ab93736), + SPH_C32(0x4bc9f29b), SPH_C32(0x3f957917), SPH_C32(0x0c1e0000), + SPH_C32(0xc61f0000), SPH_C32(0x81850000), SPH_C32(0x6b9454e0), + SPH_C32(0xb9fa019a), SPH_C32(0xe0312bb1), SPH_C32(0xfcce6baa), + SPH_C32(0x1b7149b0) }, + { SPH_C32(0x0bc20000), SPH_C32(0x95140000), SPH_C32(0x29fc0000), + SPH_C32(0xe4da2e60), SPH_C32(0x513c4fd7), SPH_C32(0xf21e87ec), + SPH_C32(0x635cf42f), SPH_C32(0xe8cf3180), SPH_C32(0xfcdb0000), + SPH_C32(0x9f3c0000), SPH_C32(0xc4070000), SPH_C32(0x8a195420), + SPH_C32(0x829707ab), SPH_C32(0x22dc7d28), SPH_C32(0x372e95b6), + SPH_C32(0x4dd6f82f) }, + { SPH_C32(0x1d2f0000), SPH_C32(0x807c0000), SPH_C32(0xc42b0000), + SPH_C32(0xd6872c40), SPH_C32(0xb230795e), SPH_C32(0xa85461af), + SPH_C32(0x80290c87), SPH_C32(0x6932c888), SPH_C32(0x1af30000), + SPH_C32(0xd3770000), SPH_C32(0x6c520000), SPH_C32(0x59c956c0), + SPH_C32(0x5af63713), SPH_C32(0xba7bcdf2), SPH_C32(0x1fbb9302), + SPH_C32(0x9a8cb0b8) }, + { SPH_C32(0xfb070000), SPH_C32(0xcc370000), SPH_C32(0x6c7e0000), + SPH_C32(0x05572ea0), SPH_C32(0x6a5149e6), SPH_C32(0x30f3d175), + SPH_C32(0xa8bc0a33), SPH_C32(0xbe68801f), SPH_C32(0xea360000), + SPH_C32(0x8a540000), SPH_C32(0x29d00000), SPH_C32(0xb8445600), + SPH_C32(0x619b3122), SPH_C32(0x78969b6b), SPH_C32(0xd45b6d1e), + SPH_C32(0xcc2b0127) }, + { SPH_C32(0xb82f0000), SPH_C32(0xb12c0000), SPH_C32(0x30d80000), + SPH_C32(0x14445000), SPH_C32(0xc15860a2), SPH_C32(0x3127e8ec), + SPH_C32(0x2e98bf23), SPH_C32(0x551e3d6e), SPH_C32(0x02f20000), + SPH_C32(0xa2810000), SPH_C32(0x873f0000), SPH_C32(0xe36c7800), + SPH_C32(0x1e1d74ef), SPH_C32(0x073d2bd6), SPH_C32(0xc4c23237), + SPH_C32(0x7f32259e) }, + { SPH_C32(0x5e070000), SPH_C32(0xfd670000), SPH_C32(0x988d0000), + SPH_C32(0xc79452e0), SPH_C32(0x1939501a), SPH_C32(0xa9805836), + SPH_C32(0x060db997), SPH_C32(0x824475f9), SPH_C32(0xf2370000), + SPH_C32(0xfba20000), SPH_C32(0xc2bd0000), SPH_C32(0x02e178c0), + SPH_C32(0x257072de), SPH_C32(0xc5d07d4f), SPH_C32(0x0f22cc2b), + SPH_C32(0x29959401) }, + { SPH_C32(0x48ea0000), SPH_C32(0xe80f0000), SPH_C32(0x755a0000), + SPH_C32(0xf5c950c0), SPH_C32(0xfa356693), SPH_C32(0xf3cabe75), + SPH_C32(0xe578413f), SPH_C32(0x03b98cf1), SPH_C32(0x141f0000), + SPH_C32(0xb7e90000), SPH_C32(0x6ae80000), SPH_C32(0xd1317a20), + SPH_C32(0xfd114266), SPH_C32(0x5d77cd95), SPH_C32(0x27b7ca9f), + SPH_C32(0xfecfdc96) }, + { SPH_C32(0xaec20000), SPH_C32(0xa4440000), SPH_C32(0xdd0f0000), + SPH_C32(0x26195220), SPH_C32(0x2254562b), SPH_C32(0x6b6d0eaf), + SPH_C32(0xcded478b), SPH_C32(0xd4e3c466), SPH_C32(0xe4da0000), + SPH_C32(0xeeca0000), SPH_C32(0x2f6a0000), SPH_C32(0x30bc7ae0), + SPH_C32(0xc67c4457), SPH_C32(0x9f9a9b0c), SPH_C32(0xec573483), + SPH_C32(0xa8686d09) }, + { SPH_C32(0x0c1e0000), SPH_C32(0xc61f0000), SPH_C32(0x81850000), + SPH_C32(0x6b9454e0), SPH_C32(0xb9fa019a), SPH_C32(0xe0312bb1), + SPH_C32(0xfcce6baa), SPH_C32(0x1b7149b0), SPH_C32(0xe1f40000), + SPH_C32(0x1f400000), SPH_C32(0x002c0000), SPH_C32(0x5c9e7860), + SPH_C32(0x30a77ef5), SPH_C32(0x8a881c87), SPH_C32(0xb7079931), + SPH_C32(0x24e430a7) }, + { SPH_C32(0xea360000), SPH_C32(0x8a540000), SPH_C32(0x29d00000), + SPH_C32(0xb8445600), SPH_C32(0x619b3122), SPH_C32(0x78969b6b), + SPH_C32(0xd45b6d1e), SPH_C32(0xcc2b0127), SPH_C32(0x11310000), + SPH_C32(0x46630000), SPH_C32(0x45ae0000), SPH_C32(0xbd1378a0), + SPH_C32(0x0bca78c4), SPH_C32(0x48654a1e), SPH_C32(0x7ce7672d), + SPH_C32(0x72438138) }, + { SPH_C32(0xfcdb0000), SPH_C32(0x9f3c0000), SPH_C32(0xc4070000), + SPH_C32(0x8a195420), SPH_C32(0x829707ab), SPH_C32(0x22dc7d28), + SPH_C32(0x372e95b6), SPH_C32(0x4dd6f82f), SPH_C32(0xf7190000), + SPH_C32(0x0a280000), SPH_C32(0xedfb0000), SPH_C32(0x6ec37a40), + SPH_C32(0xd3ab487c), SPH_C32(0xd0c2fac4), SPH_C32(0x54726199), + SPH_C32(0xa519c9af) }, + { SPH_C32(0x1af30000), SPH_C32(0xd3770000), SPH_C32(0x6c520000), + SPH_C32(0x59c956c0), SPH_C32(0x5af63713), SPH_C32(0xba7bcdf2), + SPH_C32(0x1fbb9302), SPH_C32(0x9a8cb0b8), SPH_C32(0x07dc0000), + SPH_C32(0x530b0000), SPH_C32(0xa8790000), SPH_C32(0x8f4e7a80), + SPH_C32(0xe8c64e4d), SPH_C32(0x122fac5d), SPH_C32(0x9f929f85), + SPH_C32(0xf3be7830) }, + { SPH_C32(0x5b290000), SPH_C32(0x0ced0000), SPH_C32(0xb7cb0000), + SPH_C32(0xabb65060), SPH_C32(0xefe26ab8), SPH_C32(0xbc92dfbd), + SPH_C32(0x5d5d1425), SPH_C32(0x0ec82857), SPH_C32(0x55c50000), + SPH_C32(0x68730000), SPH_C32(0xb1710000), SPH_C32(0x234e7c80), + SPH_C32(0x48051fcd), SPH_C32(0x5b9edfda), SPH_C32(0x65514db8), + SPH_C32(0x6a8b4479) }, + { SPH_C32(0xbd010000), SPH_C32(0x40a60000), SPH_C32(0x1f9e0000), + SPH_C32(0x78665280), SPH_C32(0x37835a00), SPH_C32(0x24356f67), + SPH_C32(0x75c81291), SPH_C32(0xd99260c0), SPH_C32(0xa5000000), + SPH_C32(0x31500000), SPH_C32(0xf4f30000), SPH_C32(0xc2c37c40), + SPH_C32(0x736819fc), SPH_C32(0x99738943), SPH_C32(0xaeb1b3a4), + SPH_C32(0x3c2cf5e6) }, + { SPH_C32(0xabec0000), SPH_C32(0x55ce0000), SPH_C32(0xf2490000), + SPH_C32(0x4a3b50a0), SPH_C32(0xd48f6c89), SPH_C32(0x7e7f8924), + SPH_C32(0x96bdea39), SPH_C32(0x586f99c8), SPH_C32(0x43280000), + SPH_C32(0x7d1b0000), SPH_C32(0x5ca60000), SPH_C32(0x11137ea0), + SPH_C32(0xab092944), SPH_C32(0x01d43999), SPH_C32(0x8624b510), + SPH_C32(0xeb76bd71) }, + { SPH_C32(0x4dc40000), SPH_C32(0x19850000), SPH_C32(0x5a1c0000), + SPH_C32(0x99eb5240), SPH_C32(0x0cee5c31), SPH_C32(0xe6d839fe), + SPH_C32(0xbe28ec8d), SPH_C32(0x8f35d15f), SPH_C32(0xb3ed0000), + SPH_C32(0x24380000), SPH_C32(0x19240000), SPH_C32(0xf09e7e60), + SPH_C32(0x90642f75), SPH_C32(0xc3396f00), SPH_C32(0x4dc44b0c), + SPH_C32(0xbdd10cee) }, + { SPH_C32(0xef180000), SPH_C32(0x7bde0000), SPH_C32(0x06960000), + SPH_C32(0xd4665480), SPH_C32(0x97400b80), SPH_C32(0x6d841ce0), + SPH_C32(0x8f0bc0ac), SPH_C32(0x40a75c89), SPH_C32(0xb6c30000), + SPH_C32(0xd5b20000), SPH_C32(0x36620000), SPH_C32(0x9cbc7ce0), + SPH_C32(0x66bf15d7), SPH_C32(0xd62be88b), SPH_C32(0x1694e6be), + SPH_C32(0x315d5140) }, + { SPH_C32(0x09300000), SPH_C32(0x37950000), SPH_C32(0xaec30000), + SPH_C32(0x07b65660), SPH_C32(0x4f213b38), SPH_C32(0xf523ac3a), + SPH_C32(0xa79ec618), SPH_C32(0x97fd141e), SPH_C32(0x46060000), + SPH_C32(0x8c910000), SPH_C32(0x73e00000), SPH_C32(0x7d317c20), + SPH_C32(0x5dd213e6), SPH_C32(0x14c6be12), SPH_C32(0xdd7418a2), + SPH_C32(0x67fae0df) }, + { SPH_C32(0x1fdd0000), SPH_C32(0x22fd0000), SPH_C32(0x43140000), + SPH_C32(0x35eb5440), SPH_C32(0xac2d0db1), SPH_C32(0xaf694a79), + SPH_C32(0x44eb3eb0), SPH_C32(0x1600ed16), SPH_C32(0xa02e0000), + SPH_C32(0xc0da0000), SPH_C32(0xdbb50000), SPH_C32(0xaee17ec0), + SPH_C32(0x85b3235e), SPH_C32(0x8c610ec8), SPH_C32(0xf5e11e16), + SPH_C32(0xb0a0a848) }, + { SPH_C32(0xf9f50000), SPH_C32(0x6eb60000), SPH_C32(0xeb410000), + SPH_C32(0xe63b56a0), SPH_C32(0x744c3d09), SPH_C32(0x37cefaa3), + SPH_C32(0x6c7e3804), SPH_C32(0xc15aa581), SPH_C32(0x50eb0000), + SPH_C32(0x99f90000), SPH_C32(0x9e370000), SPH_C32(0x4f6c7e00), + SPH_C32(0xbede256f), SPH_C32(0x4e8c5851), SPH_C32(0x3e01e00a), + SPH_C32(0xe60719d7) }, + { SPH_C32(0x1e6c0000), SPH_C32(0xc4420000), SPH_C32(0x8a2e0000), + SPH_C32(0xbcb6b800), SPH_C32(0x2c4413b6), SPH_C32(0x8bfdd3da), + SPH_C32(0x6a0c1bc8), SPH_C32(0xb99dc2eb), SPH_C32(0x92560000), + SPH_C32(0x1eda0000), SPH_C32(0xea510000), SPH_C32(0xe8b13000), + SPH_C32(0xa93556a5), SPH_C32(0xebfb6199), SPH_C32(0xb15c2254), + SPH_C32(0x33c5244f) }, + { SPH_C32(0xf8440000), SPH_C32(0x88090000), SPH_C32(0x227b0000), + SPH_C32(0x6f66bae0), SPH_C32(0xf425230e), SPH_C32(0x135a6300), + SPH_C32(0x42991d7c), SPH_C32(0x6ec78a7c), SPH_C32(0x62930000), + SPH_C32(0x47f90000), SPH_C32(0xafd30000), SPH_C32(0x093c30c0), + SPH_C32(0x92585094), SPH_C32(0x29163700), SPH_C32(0x7abcdc48), + SPH_C32(0x656295d0) }, + { SPH_C32(0xeea90000), SPH_C32(0x9d610000), SPH_C32(0xcfac0000), + SPH_C32(0x5d3bb8c0), SPH_C32(0x17291587), SPH_C32(0x49108543), + SPH_C32(0xa1ece5d4), SPH_C32(0xef3a7374), SPH_C32(0x84bb0000), + SPH_C32(0x0bb20000), SPH_C32(0x07860000), SPH_C32(0xdaec3220), + SPH_C32(0x4a39602c), SPH_C32(0xb1b187da), SPH_C32(0x5229dafc), + SPH_C32(0xb238dd47) }, + { SPH_C32(0x08810000), SPH_C32(0xd12a0000), SPH_C32(0x67f90000), + SPH_C32(0x8eebba20), SPH_C32(0xcf48253f), SPH_C32(0xd1b73599), + SPH_C32(0x8979e360), SPH_C32(0x38603be3), SPH_C32(0x747e0000), + SPH_C32(0x52910000), SPH_C32(0x42040000), SPH_C32(0x3b6132e0), + SPH_C32(0x7154661d), SPH_C32(0x735cd143), SPH_C32(0x99c924e0), + SPH_C32(0xe49f6cd8) }, + { SPH_C32(0xaa5d0000), SPH_C32(0xb3710000), SPH_C32(0x3b730000), + SPH_C32(0xc366bce0), SPH_C32(0x54e6728e), SPH_C32(0x5aeb1087), + SPH_C32(0xb85acf41), SPH_C32(0xf7f2b635), SPH_C32(0x71500000), + SPH_C32(0xa31b0000), SPH_C32(0x6d420000), SPH_C32(0x57433060), + SPH_C32(0x878f5cbf), SPH_C32(0x664e56c8), SPH_C32(0xc2998952), + SPH_C32(0x68133176) }, + { SPH_C32(0x4c750000), SPH_C32(0xff3a0000), SPH_C32(0x93260000), + SPH_C32(0x10b6be00), SPH_C32(0x8c874236), SPH_C32(0xc24ca05d), + SPH_C32(0x90cfc9f5), SPH_C32(0x20a8fea2), SPH_C32(0x81950000), + SPH_C32(0xfa380000), SPH_C32(0x28c00000), SPH_C32(0xb6ce30a0), + SPH_C32(0xbce25a8e), SPH_C32(0xa4a30051), SPH_C32(0x0979774e), + SPH_C32(0x3eb480e9) }, + { SPH_C32(0x5a980000), SPH_C32(0xea520000), SPH_C32(0x7ef10000), + SPH_C32(0x22ebbc20), SPH_C32(0x6f8b74bf), SPH_C32(0x9806461e), + SPH_C32(0x73ba315d), SPH_C32(0xa15507aa), SPH_C32(0x67bd0000), + SPH_C32(0xb6730000), SPH_C32(0x80950000), SPH_C32(0x651e3240), + SPH_C32(0x64836a36), SPH_C32(0x3c04b08b), SPH_C32(0x21ec71fa), + SPH_C32(0xe9eec87e) }, + { SPH_C32(0xbcb00000), SPH_C32(0xa6190000), SPH_C32(0xd6a40000), + SPH_C32(0xf13bbec0), SPH_C32(0xb7ea4407), SPH_C32(0x00a1f6c4), + SPH_C32(0x5b2f37e9), SPH_C32(0x760f4f3d), SPH_C32(0x97780000), + SPH_C32(0xef500000), SPH_C32(0xc5170000), SPH_C32(0x84933280), + SPH_C32(0x5fee6c07), SPH_C32(0xfee9e612), SPH_C32(0xea0c8fe6), + SPH_C32(0xbf4979e1) }, + { SPH_C32(0xfd6a0000), SPH_C32(0x79830000), SPH_C32(0x0d3d0000), + SPH_C32(0x0344b860), SPH_C32(0x02fe19ac), SPH_C32(0x0648e48b), + SPH_C32(0x19c9b0ce), SPH_C32(0xe24bd7d2), SPH_C32(0xc5610000), + SPH_C32(0xd4280000), SPH_C32(0xdc1f0000), SPH_C32(0x28933480), + SPH_C32(0xff2d3d87), SPH_C32(0xb7589595), SPH_C32(0x10cf5ddb), + SPH_C32(0x267c45a8) }, + { SPH_C32(0x1b420000), SPH_C32(0x35c80000), SPH_C32(0xa5680000), + SPH_C32(0xd094ba80), SPH_C32(0xda9f2914), SPH_C32(0x9eef5451), + SPH_C32(0x315cb67a), SPH_C32(0x35119f45), SPH_C32(0x35a40000), + SPH_C32(0x8d0b0000), SPH_C32(0x999d0000), SPH_C32(0xc91e3440), + SPH_C32(0xc4403bb6), SPH_C32(0x75b5c30c), SPH_C32(0xdb2fa3c7), + SPH_C32(0x70dbf437) }, + { SPH_C32(0x0daf0000), SPH_C32(0x20a00000), SPH_C32(0x48bf0000), + SPH_C32(0xe2c9b8a0), SPH_C32(0x39931f9d), SPH_C32(0xc4a5b212), + SPH_C32(0xd2294ed2), SPH_C32(0xb4ec664d), SPH_C32(0xd38c0000), + SPH_C32(0xc1400000), SPH_C32(0x31c80000), SPH_C32(0x1ace36a0), + SPH_C32(0x1c210b0e), SPH_C32(0xed1273d6), SPH_C32(0xf3baa573), + SPH_C32(0xa781bca0) }, + { SPH_C32(0xeb870000), SPH_C32(0x6ceb0000), SPH_C32(0xe0ea0000), + SPH_C32(0x3119ba40), SPH_C32(0xe1f22f25), SPH_C32(0x5c0202c8), + SPH_C32(0xfabc4866), SPH_C32(0x63b62eda), SPH_C32(0x23490000), + SPH_C32(0x98630000), SPH_C32(0x744a0000), SPH_C32(0xfb433660), + SPH_C32(0x274c0d3f), SPH_C32(0x2fff254f), SPH_C32(0x385a5b6f), + SPH_C32(0xf1260d3f) }, + { SPH_C32(0x495b0000), SPH_C32(0x0eb00000), SPH_C32(0xbc600000), + SPH_C32(0x7c94bc80), SPH_C32(0x7a5c7894), SPH_C32(0xd75e27d6), + SPH_C32(0xcb9f6447), SPH_C32(0xac24a30c), SPH_C32(0x26670000), + SPH_C32(0x69e90000), SPH_C32(0x5b0c0000), SPH_C32(0x976134e0), + SPH_C32(0xd197379d), SPH_C32(0x3aeda2c4), SPH_C32(0x630af6dd), + SPH_C32(0x7daa5091) }, + { SPH_C32(0xaf730000), SPH_C32(0x42fb0000), SPH_C32(0x14350000), + SPH_C32(0xaf44be60), SPH_C32(0xa23d482c), SPH_C32(0x4ff9970c), + SPH_C32(0xe30a62f3), SPH_C32(0x7b7eeb9b), SPH_C32(0xd6a20000), + SPH_C32(0x30ca0000), SPH_C32(0x1e8e0000), SPH_C32(0x76ec3420), + SPH_C32(0xeafa31ac), SPH_C32(0xf800f45d), SPH_C32(0xa8ea08c1), + SPH_C32(0x2b0de10e) }, + { SPH_C32(0xb99e0000), SPH_C32(0x57930000), SPH_C32(0xf9e20000), + SPH_C32(0x9d19bc40), SPH_C32(0x41317ea5), SPH_C32(0x15b3714f), + SPH_C32(0x007f9a5b), SPH_C32(0xfa831293), SPH_C32(0x308a0000), + SPH_C32(0x7c810000), SPH_C32(0xb6db0000), SPH_C32(0xa53c36c0), + SPH_C32(0x329b0114), SPH_C32(0x60a74487), SPH_C32(0x807f0e75), + SPH_C32(0xfc57a999) }, + { SPH_C32(0x5fb60000), SPH_C32(0x1bd80000), SPH_C32(0x51b70000), + SPH_C32(0x4ec9bea0), SPH_C32(0x99504e1d), SPH_C32(0x8d14c195), + SPH_C32(0x28ea9cef), SPH_C32(0x2dd95a04), SPH_C32(0xc04f0000), + SPH_C32(0x25a20000), SPH_C32(0xf3590000), SPH_C32(0x44b13600), + SPH_C32(0x09f60725), SPH_C32(0xa24a121e), SPH_C32(0x4b9ff069), + SPH_C32(0xaaf01806) }, + { SPH_C32(0x1c9e0000), SPH_C32(0x66c30000), SPH_C32(0x0d110000), + SPH_C32(0x5fdac000), SPH_C32(0x32596759), SPH_C32(0x8cc0f80c), + SPH_C32(0xaece29ff), SPH_C32(0xc6afe775), SPH_C32(0x288b0000), + SPH_C32(0x0d770000), SPH_C32(0x5db60000), SPH_C32(0x1f991800), + SPH_C32(0x767042e8), SPH_C32(0xdde1a2a3), SPH_C32(0x5b06af40), + SPH_C32(0x19e93cbf) }, + { SPH_C32(0xfab60000), SPH_C32(0x2a880000), SPH_C32(0xa5440000), + SPH_C32(0x8c0ac2e0), SPH_C32(0xea3857e1), SPH_C32(0x146748d6), + SPH_C32(0x865b2f4b), SPH_C32(0x11f5afe2), SPH_C32(0xd84e0000), + SPH_C32(0x54540000), SPH_C32(0x18340000), SPH_C32(0xfe1418c0), + SPH_C32(0x4d1d44d9), SPH_C32(0x1f0cf43a), SPH_C32(0x90e6515c), + SPH_C32(0x4f4e8d20) }, + { SPH_C32(0xec5b0000), SPH_C32(0x3fe00000), SPH_C32(0x48930000), + SPH_C32(0xbe57c0c0), SPH_C32(0x09346168), SPH_C32(0x4e2dae95), + SPH_C32(0x652ed7e3), SPH_C32(0x900856ea), SPH_C32(0x3e660000), + SPH_C32(0x181f0000), SPH_C32(0xb0610000), SPH_C32(0x2dc41a20), + SPH_C32(0x957c7461), SPH_C32(0x87ab44e0), SPH_C32(0xb87357e8), + SPH_C32(0x9814c5b7) }, + { SPH_C32(0x0a730000), SPH_C32(0x73ab0000), SPH_C32(0xe0c60000), + SPH_C32(0x6d87c220), SPH_C32(0xd15551d0), SPH_C32(0xd68a1e4f), + SPH_C32(0x4dbbd157), SPH_C32(0x47521e7d), SPH_C32(0xcea30000), + SPH_C32(0x413c0000), SPH_C32(0xf5e30000), SPH_C32(0xcc491ae0), + SPH_C32(0xae117250), SPH_C32(0x45461279), SPH_C32(0x7393a9f4), + SPH_C32(0xceb37428) }, + { SPH_C32(0xa8af0000), SPH_C32(0x11f00000), SPH_C32(0xbc4c0000), + SPH_C32(0x200ac4e0), SPH_C32(0x4afb0661), SPH_C32(0x5dd63b51), + SPH_C32(0x7c98fd76), SPH_C32(0x88c093ab), SPH_C32(0xcb8d0000), + SPH_C32(0xb0b60000), SPH_C32(0xdaa50000), SPH_C32(0xa06b1860), + SPH_C32(0x58ca48f2), SPH_C32(0x505495f2), SPH_C32(0x28c30446), + SPH_C32(0x423f2986) }, + { SPH_C32(0x4e870000), SPH_C32(0x5dbb0000), SPH_C32(0x14190000), + SPH_C32(0xf3dac600), SPH_C32(0x929a36d9), SPH_C32(0xc5718b8b), + SPH_C32(0x540dfbc2), SPH_C32(0x5f9adb3c), SPH_C32(0x3b480000), + SPH_C32(0xe9950000), SPH_C32(0x9f270000), SPH_C32(0x41e618a0), + SPH_C32(0x63a74ec3), SPH_C32(0x92b9c36b), SPH_C32(0xe323fa5a), + SPH_C32(0x14989819) }, + { SPH_C32(0x586a0000), SPH_C32(0x48d30000), SPH_C32(0xf9ce0000), + SPH_C32(0xc187c420), SPH_C32(0x71960050), SPH_C32(0x9f3b6dc8), + SPH_C32(0xb778036a), SPH_C32(0xde672234), SPH_C32(0xdd600000), + SPH_C32(0xa5de0000), SPH_C32(0x37720000), SPH_C32(0x92361a40), + SPH_C32(0xbbc67e7b), SPH_C32(0x0a1e73b1), SPH_C32(0xcbb6fcee), + SPH_C32(0xc3c2d08e) }, + { SPH_C32(0xbe420000), SPH_C32(0x04980000), SPH_C32(0x519b0000), + SPH_C32(0x1257c6c0), SPH_C32(0xa9f730e8), SPH_C32(0x079cdd12), + SPH_C32(0x9fed05de), SPH_C32(0x093d6aa3), SPH_C32(0x2da50000), + SPH_C32(0xfcfd0000), SPH_C32(0x72f00000), SPH_C32(0x73bb1a80), + SPH_C32(0x80ab784a), SPH_C32(0xc8f32528), SPH_C32(0x005602f2), + SPH_C32(0x95656111) }, + { SPH_C32(0xff980000), SPH_C32(0xdb020000), SPH_C32(0x8a020000), + SPH_C32(0xe028c060), SPH_C32(0x1ce36d43), SPH_C32(0x0175cf5d), + SPH_C32(0xdd0b82f9), SPH_C32(0x9d79f24c), SPH_C32(0x7fbc0000), + SPH_C32(0xc7850000), SPH_C32(0x6bf80000), SPH_C32(0xdfbb1c80), + SPH_C32(0x206829ca), SPH_C32(0x814256af), SPH_C32(0xfa95d0cf), + SPH_C32(0x0c505d58) }, + { SPH_C32(0x19b00000), SPH_C32(0x97490000), SPH_C32(0x22570000), + SPH_C32(0x33f8c280), SPH_C32(0xc4825dfb), SPH_C32(0x99d27f87), + SPH_C32(0xf59e844d), SPH_C32(0x4a23badb), SPH_C32(0x8f790000), + SPH_C32(0x9ea60000), SPH_C32(0x2e7a0000), SPH_C32(0x3e361c40), + SPH_C32(0x1b052ffb), SPH_C32(0x43af0036), SPH_C32(0x31752ed3), + SPH_C32(0x5af7ecc7) }, + { SPH_C32(0x0f5d0000), SPH_C32(0x82210000), SPH_C32(0xcf800000), + SPH_C32(0x01a5c0a0), SPH_C32(0x278e6b72), SPH_C32(0xc39899c4), + SPH_C32(0x16eb7ce5), SPH_C32(0xcbde43d3), SPH_C32(0x69510000), + SPH_C32(0xd2ed0000), SPH_C32(0x862f0000), SPH_C32(0xede61ea0), + SPH_C32(0xc3641f43), SPH_C32(0xdb08b0ec), SPH_C32(0x19e02867), + SPH_C32(0x8dada450) }, + { SPH_C32(0xe9750000), SPH_C32(0xce6a0000), SPH_C32(0x67d50000), + SPH_C32(0xd275c240), SPH_C32(0xffef5bca), SPH_C32(0x5b3f291e), + SPH_C32(0x3e7e7a51), SPH_C32(0x1c840b44), SPH_C32(0x99940000), + SPH_C32(0x8bce0000), SPH_C32(0xc3ad0000), SPH_C32(0x0c6b1e60), + SPH_C32(0xf8091972), SPH_C32(0x19e5e675), SPH_C32(0xd200d67b), + SPH_C32(0xdb0a15cf) }, + { SPH_C32(0x4ba90000), SPH_C32(0xac310000), SPH_C32(0x3b5f0000), + SPH_C32(0x9ff8c480), SPH_C32(0x64410c7b), SPH_C32(0xd0630c00), + SPH_C32(0x0f5d5670), SPH_C32(0xd3168692), SPH_C32(0x9cba0000), + SPH_C32(0x7a440000), SPH_C32(0xeceb0000), SPH_C32(0x60491ce0), + SPH_C32(0x0ed223d0), SPH_C32(0x0cf761fe), SPH_C32(0x89507bc9), + SPH_C32(0x57864861) }, + { SPH_C32(0xad810000), SPH_C32(0xe07a0000), SPH_C32(0x930a0000), + SPH_C32(0x4c28c660), SPH_C32(0xbc203cc3), SPH_C32(0x48c4bcda), + SPH_C32(0x27c850c4), SPH_C32(0x044cce05), SPH_C32(0x6c7f0000), + SPH_C32(0x23670000), SPH_C32(0xa9690000), SPH_C32(0x81c41c20), + SPH_C32(0x35bf25e1), SPH_C32(0xce1a3767), SPH_C32(0x42b085d5), + SPH_C32(0x0121f9fe) }, + { SPH_C32(0xbb6c0000), SPH_C32(0xf5120000), SPH_C32(0x7edd0000), + SPH_C32(0x7e75c440), SPH_C32(0x5f2c0a4a), SPH_C32(0x128e5a99), + SPH_C32(0xc4bda86c), SPH_C32(0x85b1370d), SPH_C32(0x8a570000), + SPH_C32(0x6f2c0000), SPH_C32(0x013c0000), SPH_C32(0x52141ec0), + SPH_C32(0xedde1559), SPH_C32(0x56bd87bd), SPH_C32(0x6a258361), + SPH_C32(0xd67bb169) }, + { SPH_C32(0x5d440000), SPH_C32(0xb9590000), SPH_C32(0xd6880000), + SPH_C32(0xada5c6a0), SPH_C32(0x874d3af2), SPH_C32(0x8a29ea43), + SPH_C32(0xec28aed8), SPH_C32(0x52eb7f9a), SPH_C32(0x7a920000), + SPH_C32(0x360f0000), SPH_C32(0x44be0000), SPH_C32(0xb3991e00), + SPH_C32(0xd6b31368), SPH_C32(0x9450d124), SPH_C32(0xa1c57d7d), + SPH_C32(0x80dc00f6) }, + { SPH_C32(0xa4b10000), SPH_C32(0xd7ef0000), SPH_C32(0x3dc90000), + SPH_C32(0x4b9e9000), SPH_C32(0xf30107fb), SPH_C32(0xbde710e0), + SPH_C32(0x805696dc), SPH_C32(0x93b1da1b), SPH_C32(0x2a790000), + SPH_C32(0xaff60000), SPH_C32(0xda890000), SPH_C32(0xfcf56000), + SPH_C32(0x686d3607), SPH_C32(0xdadc8975), SPH_C32(0x9fc49d77), + SPH_C32(0x66db1921) }, + { SPH_C32(0x42990000), SPH_C32(0x9ba40000), SPH_C32(0x959c0000), + SPH_C32(0x984e92e0), SPH_C32(0x2b603743), SPH_C32(0x2540a03a), + SPH_C32(0xa8c39068), SPH_C32(0x44eb928c), SPH_C32(0xdabc0000), + SPH_C32(0xf6d50000), SPH_C32(0x9f0b0000), SPH_C32(0x1d7860c0), + SPH_C32(0x53003036), SPH_C32(0x1831dfec), SPH_C32(0x5424636b), + SPH_C32(0x307ca8be) }, + { SPH_C32(0x54740000), SPH_C32(0x8ecc0000), SPH_C32(0x784b0000), + SPH_C32(0xaa1390c0), SPH_C32(0xc86c01ca), SPH_C32(0x7f0a4679), + SPH_C32(0x4bb668c0), SPH_C32(0xc5166b84), SPH_C32(0x3c940000), + SPH_C32(0xba9e0000), SPH_C32(0x375e0000), SPH_C32(0xcea86220), + SPH_C32(0x8b61008e), SPH_C32(0x80966f36), SPH_C32(0x7cb165df), + SPH_C32(0xe726e029) }, + { SPH_C32(0xb25c0000), SPH_C32(0xc2870000), SPH_C32(0xd01e0000), + SPH_C32(0x79c39220), SPH_C32(0x100d3172), SPH_C32(0xe7adf6a3), + SPH_C32(0x63236e74), SPH_C32(0x124c2313), SPH_C32(0xcc510000), + SPH_C32(0xe3bd0000), SPH_C32(0x72dc0000), SPH_C32(0x2f2562e0), + SPH_C32(0xb00c06bf), SPH_C32(0x427b39af), SPH_C32(0xb7519bc3), + SPH_C32(0xb18151b6) }, + { SPH_C32(0x10800000), SPH_C32(0xa0dc0000), SPH_C32(0x8c940000), + SPH_C32(0x344e94e0), SPH_C32(0x8ba366c3), SPH_C32(0x6cf1d3bd), + SPH_C32(0x52004255), SPH_C32(0xdddeaec5), SPH_C32(0xc97f0000), + SPH_C32(0x12370000), SPH_C32(0x5d9a0000), SPH_C32(0x43076060), + SPH_C32(0x46d73c1d), SPH_C32(0x5769be24), SPH_C32(0xec013671), + SPH_C32(0x3d0d0c18) }, + { SPH_C32(0xf6a80000), SPH_C32(0xec970000), SPH_C32(0x24c10000), + SPH_C32(0xe79e9600), SPH_C32(0x53c2567b), SPH_C32(0xf4566367), + SPH_C32(0x7a9544e1), SPH_C32(0x0a84e652), SPH_C32(0x39ba0000), + SPH_C32(0x4b140000), SPH_C32(0x18180000), SPH_C32(0xa28a60a0), + SPH_C32(0x7dba3a2c), SPH_C32(0x9584e8bd), SPH_C32(0x27e1c86d), + SPH_C32(0x6baabd87) }, + { SPH_C32(0xe0450000), SPH_C32(0xf9ff0000), SPH_C32(0xc9160000), + SPH_C32(0xd5c39420), SPH_C32(0xb0ce60f2), SPH_C32(0xae1c8524), + SPH_C32(0x99e0bc49), SPH_C32(0x8b791f5a), SPH_C32(0xdf920000), + SPH_C32(0x075f0000), SPH_C32(0xb04d0000), SPH_C32(0x715a6240), + SPH_C32(0xa5db0a94), SPH_C32(0x0d235867), SPH_C32(0x0f74ced9), + SPH_C32(0xbcf0f510) }, + { SPH_C32(0x066d0000), SPH_C32(0xb5b40000), SPH_C32(0x61430000), + SPH_C32(0x061396c0), SPH_C32(0x68af504a), SPH_C32(0x36bb35fe), + SPH_C32(0xb175bafd), SPH_C32(0x5c2357cd), SPH_C32(0x2f570000), + SPH_C32(0x5e7c0000), SPH_C32(0xf5cf0000), SPH_C32(0x90d76280), + SPH_C32(0x9eb60ca5), SPH_C32(0xcfce0efe), SPH_C32(0xc49430c5), + SPH_C32(0xea57448f) }, + { SPH_C32(0x47b70000), SPH_C32(0x6a2e0000), SPH_C32(0xbada0000), + SPH_C32(0xf46c9060), SPH_C32(0xddbb0de1), SPH_C32(0x305227b1), + SPH_C32(0xf3933dda), SPH_C32(0xc867cf22), SPH_C32(0x7d4e0000), + SPH_C32(0x65040000), SPH_C32(0xecc70000), SPH_C32(0x3cd76480), + SPH_C32(0x3e755d25), SPH_C32(0x867f7d79), SPH_C32(0x3e57e2f8), + SPH_C32(0x736278c6) }, + { SPH_C32(0xa19f0000), SPH_C32(0x26650000), SPH_C32(0x128f0000), + SPH_C32(0x27bc9280), SPH_C32(0x05da3d59), SPH_C32(0xa8f5976b), + SPH_C32(0xdb063b6e), SPH_C32(0x1f3d87b5), SPH_C32(0x8d8b0000), + SPH_C32(0x3c270000), SPH_C32(0xa9450000), SPH_C32(0xdd5a6440), + SPH_C32(0x05185b14), SPH_C32(0x44922be0), SPH_C32(0xf5b71ce4), + SPH_C32(0x25c5c959) }, + { SPH_C32(0xb7720000), SPH_C32(0x330d0000), SPH_C32(0xff580000), + SPH_C32(0x15e190a0), SPH_C32(0xe6d60bd0), SPH_C32(0xf2bf7128), + SPH_C32(0x3873c3c6), SPH_C32(0x9ec07ebd), SPH_C32(0x6ba30000), + SPH_C32(0x706c0000), SPH_C32(0x01100000), SPH_C32(0x0e8a66a0), + SPH_C32(0xdd796bac), SPH_C32(0xdc359b3a), SPH_C32(0xdd221a50), + SPH_C32(0xf29f81ce) }, + { SPH_C32(0x515a0000), SPH_C32(0x7f460000), SPH_C32(0x570d0000), + SPH_C32(0xc6319240), SPH_C32(0x3eb73b68), SPH_C32(0x6a18c1f2), + SPH_C32(0x10e6c572), SPH_C32(0x499a362a), SPH_C32(0x9b660000), + SPH_C32(0x294f0000), SPH_C32(0x44920000), SPH_C32(0xef076660), + SPH_C32(0xe6146d9d), SPH_C32(0x1ed8cda3), SPH_C32(0x16c2e44c), + SPH_C32(0xa4383051) }, + { SPH_C32(0xf3860000), SPH_C32(0x1d1d0000), SPH_C32(0x0b870000), + SPH_C32(0x8bbc9480), SPH_C32(0xa5196cd9), SPH_C32(0xe144e4ec), + SPH_C32(0x21c5e953), SPH_C32(0x8608bbfc), SPH_C32(0x9e480000), + SPH_C32(0xd8c50000), SPH_C32(0x6bd40000), SPH_C32(0x832564e0), + SPH_C32(0x10cf573f), SPH_C32(0x0bca4a28), SPH_C32(0x4d9249fe), + SPH_C32(0x28b46dff) }, + { SPH_C32(0x15ae0000), SPH_C32(0x51560000), SPH_C32(0xa3d20000), + SPH_C32(0x586c9660), SPH_C32(0x7d785c61), SPH_C32(0x79e35436), + SPH_C32(0x0950efe7), SPH_C32(0x5152f36b), SPH_C32(0x6e8d0000), + SPH_C32(0x81e60000), SPH_C32(0x2e560000), SPH_C32(0x62a86420), + SPH_C32(0x2ba2510e), SPH_C32(0xc9271cb1), SPH_C32(0x8672b7e2), + SPH_C32(0x7e13dc60) }, + { SPH_C32(0x03430000), SPH_C32(0x443e0000), SPH_C32(0x4e050000), + SPH_C32(0x6a319440), SPH_C32(0x9e746ae8), SPH_C32(0x23a9b275), + SPH_C32(0xea25174f), SPH_C32(0xd0af0a63), SPH_C32(0x88a50000), + SPH_C32(0xcdad0000), SPH_C32(0x86030000), SPH_C32(0xb17866c0), + SPH_C32(0xf3c361b6), SPH_C32(0x5180ac6b), SPH_C32(0xaee7b156), + SPH_C32(0xa94994f7) }, + { SPH_C32(0xe56b0000), SPH_C32(0x08750000), SPH_C32(0xe6500000), + SPH_C32(0xb9e196a0), SPH_C32(0x46155a50), SPH_C32(0xbb0e02af), + SPH_C32(0xc2b011fb), SPH_C32(0x07f542f4), SPH_C32(0x78600000), + SPH_C32(0x948e0000), SPH_C32(0xc3810000), SPH_C32(0x50f56600), + SPH_C32(0xc8ae6787), SPH_C32(0x936dfaf2), SPH_C32(0x65074f4a), + SPH_C32(0xffee2568) }, + { SPH_C32(0xa6430000), SPH_C32(0x756e0000), SPH_C32(0xbaf60000), + SPH_C32(0xa8f2e800), SPH_C32(0xed1c7314), SPH_C32(0xbada3b36), + SPH_C32(0x4494a4eb), SPH_C32(0xec83ff85), SPH_C32(0x90a40000), + SPH_C32(0xbc5b0000), SPH_C32(0x6d6e0000), SPH_C32(0x0bdd4800), + SPH_C32(0xb728224a), SPH_C32(0xecc64a4f), SPH_C32(0x759e1063), + SPH_C32(0x4cf701d1) }, + { SPH_C32(0x406b0000), SPH_C32(0x39250000), SPH_C32(0x12a30000), + SPH_C32(0x7b22eae0), SPH_C32(0x357d43ac), SPH_C32(0x227d8bec), + SPH_C32(0x6c01a25f), SPH_C32(0x3bd9b712), SPH_C32(0x60610000), + SPH_C32(0xe5780000), SPH_C32(0x28ec0000), SPH_C32(0xea5048c0), + SPH_C32(0x8c45247b), SPH_C32(0x2e2b1cd6), SPH_C32(0xbe7eee7f), + SPH_C32(0x1a50b04e) }, + { SPH_C32(0x56860000), SPH_C32(0x2c4d0000), SPH_C32(0xff740000), + SPH_C32(0x497fe8c0), SPH_C32(0xd6717525), SPH_C32(0x78376daf), + SPH_C32(0x8f745af7), SPH_C32(0xba244e1a), SPH_C32(0x86490000), + SPH_C32(0xa9330000), SPH_C32(0x80b90000), SPH_C32(0x39804a20), + SPH_C32(0x542414c3), SPH_C32(0xb68cac0c), SPH_C32(0x96ebe8cb), + SPH_C32(0xcd0af8d9) }, + { SPH_C32(0xb0ae0000), SPH_C32(0x60060000), SPH_C32(0x57210000), + SPH_C32(0x9aafea20), SPH_C32(0x0e10459d), SPH_C32(0xe090dd75), + SPH_C32(0xa7e15c43), SPH_C32(0x6d7e068d), SPH_C32(0x768c0000), + SPH_C32(0xf0100000), SPH_C32(0xc53b0000), SPH_C32(0xd80d4ae0), + SPH_C32(0x6f4912f2), SPH_C32(0x7461fa95), SPH_C32(0x5d0b16d7), + SPH_C32(0x9bad4946) }, + { SPH_C32(0x12720000), SPH_C32(0x025d0000), SPH_C32(0x0bab0000), + SPH_C32(0xd722ece0), SPH_C32(0x95be122c), SPH_C32(0x6bccf86b), + SPH_C32(0x96c27062), SPH_C32(0xa2ec8b5b), SPH_C32(0x73a20000), + SPH_C32(0x019a0000), SPH_C32(0xea7d0000), SPH_C32(0xb42f4860), + SPH_C32(0x99922850), SPH_C32(0x61737d1e), SPH_C32(0x065bbb65), + SPH_C32(0x172114e8) }, + { SPH_C32(0xf45a0000), SPH_C32(0x4e160000), SPH_C32(0xa3fe0000), + SPH_C32(0x04f2ee00), SPH_C32(0x4ddf2294), SPH_C32(0xf36b48b1), + SPH_C32(0xbe5776d6), SPH_C32(0x75b6c3cc), SPH_C32(0x83670000), + SPH_C32(0x58b90000), SPH_C32(0xafff0000), SPH_C32(0x55a248a0), + SPH_C32(0xa2ff2e61), SPH_C32(0xa39e2b87), SPH_C32(0xcdbb4579), + SPH_C32(0x4186a577) }, + { SPH_C32(0xe2b70000), SPH_C32(0x5b7e0000), SPH_C32(0x4e290000), + SPH_C32(0x36afec20), SPH_C32(0xaed3141d), SPH_C32(0xa921aef2), + SPH_C32(0x5d228e7e), SPH_C32(0xf44b3ac4), SPH_C32(0x654f0000), + SPH_C32(0x14f20000), SPH_C32(0x07aa0000), SPH_C32(0x86724a40), + SPH_C32(0x7a9e1ed9), SPH_C32(0x3b399b5d), SPH_C32(0xe52e43cd), + SPH_C32(0x96dcede0) }, + { SPH_C32(0x049f0000), SPH_C32(0x17350000), SPH_C32(0xe67c0000), + SPH_C32(0xe57feec0), SPH_C32(0x76b224a5), SPH_C32(0x31861e28), + SPH_C32(0x75b788ca), SPH_C32(0x23117253), SPH_C32(0x958a0000), + SPH_C32(0x4dd10000), SPH_C32(0x42280000), SPH_C32(0x67ff4a80), + SPH_C32(0x41f318e8), SPH_C32(0xf9d4cdc4), SPH_C32(0x2ecebdd1), + SPH_C32(0xc07b5c7f) }, + { SPH_C32(0x45450000), SPH_C32(0xc8af0000), SPH_C32(0x3de50000), + SPH_C32(0x1700e860), SPH_C32(0xc3a6790e), SPH_C32(0x376f0c67), + SPH_C32(0x37510fed), SPH_C32(0xb755eabc), SPH_C32(0xc7930000), + SPH_C32(0x76a90000), SPH_C32(0x5b200000), SPH_C32(0xcbff4c80), + SPH_C32(0xe1304968), SPH_C32(0xb065be43), SPH_C32(0xd40d6fec), + SPH_C32(0x594e6036) }, + { SPH_C32(0xa36d0000), SPH_C32(0x84e40000), SPH_C32(0x95b00000), + SPH_C32(0xc4d0ea80), SPH_C32(0x1bc749b6), SPH_C32(0xafc8bcbd), + SPH_C32(0x1fc40959), SPH_C32(0x600fa22b), SPH_C32(0x37560000), + SPH_C32(0x2f8a0000), SPH_C32(0x1ea20000), SPH_C32(0x2a724c40), + SPH_C32(0xda5d4f59), SPH_C32(0x7288e8da), SPH_C32(0x1fed91f0), + SPH_C32(0x0fe9d1a9) }, + { SPH_C32(0xb5800000), SPH_C32(0x918c0000), SPH_C32(0x78670000), + SPH_C32(0xf68de8a0), SPH_C32(0xf8cb7f3f), SPH_C32(0xf5825afe), + SPH_C32(0xfcb1f1f1), SPH_C32(0xe1f25b23), SPH_C32(0xd17e0000), + SPH_C32(0x63c10000), SPH_C32(0xb6f70000), SPH_C32(0xf9a24ea0), + SPH_C32(0x023c7fe1), SPH_C32(0xea2f5800), SPH_C32(0x37789744), + SPH_C32(0xd8b3993e) }, + { SPH_C32(0x53a80000), SPH_C32(0xddc70000), SPH_C32(0xd0320000), + SPH_C32(0x255dea40), SPH_C32(0x20aa4f87), SPH_C32(0x6d25ea24), + SPH_C32(0xd424f745), SPH_C32(0x36a813b4), SPH_C32(0x21bb0000), + SPH_C32(0x3ae20000), SPH_C32(0xf3750000), SPH_C32(0x182f4e60), + SPH_C32(0x395179d0), SPH_C32(0x28c20e99), SPH_C32(0xfc986958), + SPH_C32(0x8e1428a1) }, + { SPH_C32(0xf1740000), SPH_C32(0xbf9c0000), SPH_C32(0x8cb80000), + SPH_C32(0x68d0ec80), SPH_C32(0xbb041836), SPH_C32(0xe679cf3a), + SPH_C32(0xe507db64), SPH_C32(0xf93a9e62), SPH_C32(0x24950000), + SPH_C32(0xcb680000), SPH_C32(0xdc330000), SPH_C32(0x740d4ce0), + SPH_C32(0xcf8a4372), SPH_C32(0x3dd08912), SPH_C32(0xa7c8c4ea), + SPH_C32(0x0298750f) }, + { SPH_C32(0x175c0000), SPH_C32(0xf3d70000), SPH_C32(0x24ed0000), + SPH_C32(0xbb00ee60), SPH_C32(0x6365288e), SPH_C32(0x7ede7fe0), + SPH_C32(0xcd92ddd0), SPH_C32(0x2e60d6f5), SPH_C32(0xd4500000), + SPH_C32(0x924b0000), SPH_C32(0x99b10000), SPH_C32(0x95804c20), + SPH_C32(0xf4e74543), SPH_C32(0xff3ddf8b), SPH_C32(0x6c283af6), + SPH_C32(0x543fc490) }, + { SPH_C32(0x01b10000), SPH_C32(0xe6bf0000), SPH_C32(0xc93a0000), + SPH_C32(0x895dec40), SPH_C32(0x80691e07), SPH_C32(0x249499a3), + SPH_C32(0x2ee72578), SPH_C32(0xaf9d2ffd), SPH_C32(0x32780000), + SPH_C32(0xde000000), SPH_C32(0x31e40000), SPH_C32(0x46504ec0), + SPH_C32(0x2c8675fb), SPH_C32(0x679a6f51), SPH_C32(0x44bd3c42), + SPH_C32(0x83658c07) }, + { SPH_C32(0xe7990000), SPH_C32(0xaaf40000), SPH_C32(0x616f0000), + SPH_C32(0x5a8deea0), SPH_C32(0x58082ebf), SPH_C32(0xbc332979), + SPH_C32(0x067223cc), SPH_C32(0x78c7676a), SPH_C32(0xc2bd0000), + SPH_C32(0x87230000), SPH_C32(0x74660000), SPH_C32(0xa7dd4e00), + SPH_C32(0x17eb73ca), SPH_C32(0xa57739c8), SPH_C32(0x8f5dc25e), + SPH_C32(0xd5c23d98) }, + { SPH_C32(0x92560000), SPH_C32(0x1eda0000), SPH_C32(0xea510000), + SPH_C32(0xe8b13000), SPH_C32(0xa93556a5), SPH_C32(0xebfb6199), + SPH_C32(0xb15c2254), SPH_C32(0x33c5244f), SPH_C32(0x8c3a0000), + SPH_C32(0xda980000), SPH_C32(0x607f0000), SPH_C32(0x54078800), + SPH_C32(0x85714513), SPH_C32(0x6006b243), SPH_C32(0xdb50399c), + SPH_C32(0x8a58e6a4) }, + { SPH_C32(0x747e0000), SPH_C32(0x52910000), SPH_C32(0x42040000), + SPH_C32(0x3b6132e0), SPH_C32(0x7154661d), SPH_C32(0x735cd143), + SPH_C32(0x99c924e0), SPH_C32(0xe49f6cd8), SPH_C32(0x7cff0000), + SPH_C32(0x83bb0000), SPH_C32(0x25fd0000), SPH_C32(0xb58a88c0), + SPH_C32(0xbe1c4322), SPH_C32(0xa2ebe4da), SPH_C32(0x10b0c780), + SPH_C32(0xdcff573b) }, + { SPH_C32(0x62930000), SPH_C32(0x47f90000), SPH_C32(0xafd30000), + SPH_C32(0x093c30c0), SPH_C32(0x92585094), SPH_C32(0x29163700), + SPH_C32(0x7abcdc48), SPH_C32(0x656295d0), SPH_C32(0x9ad70000), + SPH_C32(0xcff00000), SPH_C32(0x8da80000), SPH_C32(0x665a8a20), + SPH_C32(0x667d739a), SPH_C32(0x3a4c5400), SPH_C32(0x3825c134), + SPH_C32(0x0ba51fac) }, + { SPH_C32(0x84bb0000), SPH_C32(0x0bb20000), SPH_C32(0x07860000), + SPH_C32(0xdaec3220), SPH_C32(0x4a39602c), SPH_C32(0xb1b187da), + SPH_C32(0x5229dafc), SPH_C32(0xb238dd47), SPH_C32(0x6a120000), + SPH_C32(0x96d30000), SPH_C32(0xc82a0000), SPH_C32(0x87d78ae0), + SPH_C32(0x5d1075ab), SPH_C32(0xf8a10299), SPH_C32(0xf3c53f28), + SPH_C32(0x5d02ae33) }, + { SPH_C32(0x26670000), SPH_C32(0x69e90000), SPH_C32(0x5b0c0000), + SPH_C32(0x976134e0), SPH_C32(0xd197379d), SPH_C32(0x3aeda2c4), + SPH_C32(0x630af6dd), SPH_C32(0x7daa5091), SPH_C32(0x6f3c0000), + SPH_C32(0x67590000), SPH_C32(0xe76c0000), SPH_C32(0xebf58860), + SPH_C32(0xabcb4f09), SPH_C32(0xedb38512), SPH_C32(0xa895929a), + SPH_C32(0xd18ef39d) }, + { SPH_C32(0xc04f0000), SPH_C32(0x25a20000), SPH_C32(0xf3590000), + SPH_C32(0x44b13600), SPH_C32(0x09f60725), SPH_C32(0xa24a121e), + SPH_C32(0x4b9ff069), SPH_C32(0xaaf01806), SPH_C32(0x9ff90000), + SPH_C32(0x3e7a0000), SPH_C32(0xa2ee0000), SPH_C32(0x0a7888a0), + SPH_C32(0x90a64938), SPH_C32(0x2f5ed38b), SPH_C32(0x63756c86), + SPH_C32(0x87294202) }, + { SPH_C32(0xd6a20000), SPH_C32(0x30ca0000), SPH_C32(0x1e8e0000), + SPH_C32(0x76ec3420), SPH_C32(0xeafa31ac), SPH_C32(0xf800f45d), + SPH_C32(0xa8ea08c1), SPH_C32(0x2b0de10e), SPH_C32(0x79d10000), + SPH_C32(0x72310000), SPH_C32(0x0abb0000), SPH_C32(0xd9a88a40), + SPH_C32(0x48c77980), SPH_C32(0xb7f96351), SPH_C32(0x4be06a32), + SPH_C32(0x50730a95) }, + { SPH_C32(0x308a0000), SPH_C32(0x7c810000), SPH_C32(0xb6db0000), + SPH_C32(0xa53c36c0), SPH_C32(0x329b0114), SPH_C32(0x60a74487), + SPH_C32(0x807f0e75), SPH_C32(0xfc57a999), SPH_C32(0x89140000), + SPH_C32(0x2b120000), SPH_C32(0x4f390000), SPH_C32(0x38258a80), + SPH_C32(0x73aa7fb1), SPH_C32(0x751435c8), SPH_C32(0x8000942e), + SPH_C32(0x06d4bb0a) }, + { SPH_C32(0x71500000), SPH_C32(0xa31b0000), SPH_C32(0x6d420000), + SPH_C32(0x57433060), SPH_C32(0x878f5cbf), SPH_C32(0x664e56c8), + SPH_C32(0xc2998952), SPH_C32(0x68133176), SPH_C32(0xdb0d0000), + SPH_C32(0x106a0000), SPH_C32(0x56310000), SPH_C32(0x94258c80), + SPH_C32(0xd3692e31), SPH_C32(0x3ca5464f), SPH_C32(0x7ac34613), + SPH_C32(0x9fe18743) }, + { SPH_C32(0x97780000), SPH_C32(0xef500000), SPH_C32(0xc5170000), + SPH_C32(0x84933280), SPH_C32(0x5fee6c07), SPH_C32(0xfee9e612), + SPH_C32(0xea0c8fe6), SPH_C32(0xbf4979e1), SPH_C32(0x2bc80000), + SPH_C32(0x49490000), SPH_C32(0x13b30000), SPH_C32(0x75a88c40), + SPH_C32(0xe8042800), SPH_C32(0xfe4810d6), SPH_C32(0xb123b80f), + SPH_C32(0xc94636dc) }, + { SPH_C32(0x81950000), SPH_C32(0xfa380000), SPH_C32(0x28c00000), + SPH_C32(0xb6ce30a0), SPH_C32(0xbce25a8e), SPH_C32(0xa4a30051), + SPH_C32(0x0979774e), SPH_C32(0x3eb480e9), SPH_C32(0xcde00000), + SPH_C32(0x05020000), SPH_C32(0xbbe60000), SPH_C32(0xa6788ea0), + SPH_C32(0x306518b8), SPH_C32(0x66efa00c), SPH_C32(0x99b6bebb), + SPH_C32(0x1e1c7e4b) }, + { SPH_C32(0x67bd0000), SPH_C32(0xb6730000), SPH_C32(0x80950000), + SPH_C32(0x651e3240), SPH_C32(0x64836a36), SPH_C32(0x3c04b08b), + SPH_C32(0x21ec71fa), SPH_C32(0xe9eec87e), SPH_C32(0x3d250000), + SPH_C32(0x5c210000), SPH_C32(0xfe640000), SPH_C32(0x47f58e60), + SPH_C32(0x0b081e89), SPH_C32(0xa402f695), SPH_C32(0x525640a7), + SPH_C32(0x48bbcfd4) }, + { SPH_C32(0xc5610000), SPH_C32(0xd4280000), SPH_C32(0xdc1f0000), + SPH_C32(0x28933480), SPH_C32(0xff2d3d87), SPH_C32(0xb7589595), + SPH_C32(0x10cf5ddb), SPH_C32(0x267c45a8), SPH_C32(0x380b0000), + SPH_C32(0xadab0000), SPH_C32(0xd1220000), SPH_C32(0x2bd78ce0), + SPH_C32(0xfdd3242b), SPH_C32(0xb110711e), SPH_C32(0x0906ed15), + SPH_C32(0xc437927a) }, + { SPH_C32(0x23490000), SPH_C32(0x98630000), SPH_C32(0x744a0000), + SPH_C32(0xfb433660), SPH_C32(0x274c0d3f), SPH_C32(0x2fff254f), + SPH_C32(0x385a5b6f), SPH_C32(0xf1260d3f), SPH_C32(0xc8ce0000), + SPH_C32(0xf4880000), SPH_C32(0x94a00000), SPH_C32(0xca5a8c20), + SPH_C32(0xc6be221a), SPH_C32(0x73fd2787), SPH_C32(0xc2e61309), + SPH_C32(0x929023e5) }, + { SPH_C32(0x35a40000), SPH_C32(0x8d0b0000), SPH_C32(0x999d0000), + SPH_C32(0xc91e3440), SPH_C32(0xc4403bb6), SPH_C32(0x75b5c30c), + SPH_C32(0xdb2fa3c7), SPH_C32(0x70dbf437), SPH_C32(0x2ee60000), + SPH_C32(0xb8c30000), SPH_C32(0x3cf50000), SPH_C32(0x198a8ec0), + SPH_C32(0x1edf12a2), SPH_C32(0xeb5a975d), SPH_C32(0xea7315bd), + SPH_C32(0x45ca6b72) }, + { SPH_C32(0xd38c0000), SPH_C32(0xc1400000), SPH_C32(0x31c80000), + SPH_C32(0x1ace36a0), SPH_C32(0x1c210b0e), SPH_C32(0xed1273d6), + SPH_C32(0xf3baa573), SPH_C32(0xa781bca0), SPH_C32(0xde230000), + SPH_C32(0xe1e00000), SPH_C32(0x79770000), SPH_C32(0xf8078e00), + SPH_C32(0x25b21493), SPH_C32(0x29b7c1c4), SPH_C32(0x2193eba1), + SPH_C32(0x136ddaed) }, + { SPH_C32(0x90a40000), SPH_C32(0xbc5b0000), SPH_C32(0x6d6e0000), + SPH_C32(0x0bdd4800), SPH_C32(0xb728224a), SPH_C32(0xecc64a4f), + SPH_C32(0x759e1063), SPH_C32(0x4cf701d1), SPH_C32(0x36e70000), + SPH_C32(0xc9350000), SPH_C32(0xd7980000), SPH_C32(0xa32fa000), + SPH_C32(0x5a34515e), SPH_C32(0x561c7179), SPH_C32(0x310ab488), + SPH_C32(0xa074fe54) }, + { SPH_C32(0x768c0000), SPH_C32(0xf0100000), SPH_C32(0xc53b0000), + SPH_C32(0xd80d4ae0), SPH_C32(0x6f4912f2), SPH_C32(0x7461fa95), + SPH_C32(0x5d0b16d7), SPH_C32(0x9bad4946), SPH_C32(0xc6220000), + SPH_C32(0x90160000), SPH_C32(0x921a0000), SPH_C32(0x42a2a0c0), + SPH_C32(0x6159576f), SPH_C32(0x94f127e0), SPH_C32(0xfaea4a94), + SPH_C32(0xf6d34fcb) }, + { SPH_C32(0x60610000), SPH_C32(0xe5780000), SPH_C32(0x28ec0000), + SPH_C32(0xea5048c0), SPH_C32(0x8c45247b), SPH_C32(0x2e2b1cd6), + SPH_C32(0xbe7eee7f), SPH_C32(0x1a50b04e), SPH_C32(0x200a0000), + SPH_C32(0xdc5d0000), SPH_C32(0x3a4f0000), SPH_C32(0x9172a220), + SPH_C32(0xb93867d7), SPH_C32(0x0c56973a), SPH_C32(0xd27f4c20), + SPH_C32(0x2189075c) }, + { SPH_C32(0x86490000), SPH_C32(0xa9330000), SPH_C32(0x80b90000), + SPH_C32(0x39804a20), SPH_C32(0x542414c3), SPH_C32(0xb68cac0c), + SPH_C32(0x96ebe8cb), SPH_C32(0xcd0af8d9), SPH_C32(0xd0cf0000), + SPH_C32(0x857e0000), SPH_C32(0x7fcd0000), SPH_C32(0x70ffa2e0), + SPH_C32(0x825561e6), SPH_C32(0xcebbc1a3), SPH_C32(0x199fb23c), + SPH_C32(0x772eb6c3) }, + { SPH_C32(0x24950000), SPH_C32(0xcb680000), SPH_C32(0xdc330000), + SPH_C32(0x740d4ce0), SPH_C32(0xcf8a4372), SPH_C32(0x3dd08912), + SPH_C32(0xa7c8c4ea), SPH_C32(0x0298750f), SPH_C32(0xd5e10000), + SPH_C32(0x74f40000), SPH_C32(0x508b0000), SPH_C32(0x1cdda060), + SPH_C32(0x748e5b44), SPH_C32(0xdba94628), SPH_C32(0x42cf1f8e), + SPH_C32(0xfba2eb6d) }, + { SPH_C32(0xc2bd0000), SPH_C32(0x87230000), SPH_C32(0x74660000), + SPH_C32(0xa7dd4e00), SPH_C32(0x17eb73ca), SPH_C32(0xa57739c8), + SPH_C32(0x8f5dc25e), SPH_C32(0xd5c23d98), SPH_C32(0x25240000), + SPH_C32(0x2dd70000), SPH_C32(0x15090000), SPH_C32(0xfd50a0a0), + SPH_C32(0x4fe35d75), SPH_C32(0x194410b1), SPH_C32(0x892fe192), + SPH_C32(0xad055af2) }, + { SPH_C32(0xd4500000), SPH_C32(0x924b0000), SPH_C32(0x99b10000), + SPH_C32(0x95804c20), SPH_C32(0xf4e74543), SPH_C32(0xff3ddf8b), + SPH_C32(0x6c283af6), SPH_C32(0x543fc490), SPH_C32(0xc30c0000), + SPH_C32(0x619c0000), SPH_C32(0xbd5c0000), SPH_C32(0x2e80a240), + SPH_C32(0x97826dcd), SPH_C32(0x81e3a06b), SPH_C32(0xa1bae726), + SPH_C32(0x7a5f1265) }, + { SPH_C32(0x32780000), SPH_C32(0xde000000), SPH_C32(0x31e40000), + SPH_C32(0x46504ec0), SPH_C32(0x2c8675fb), SPH_C32(0x679a6f51), + SPH_C32(0x44bd3c42), SPH_C32(0x83658c07), SPH_C32(0x33c90000), + SPH_C32(0x38bf0000), SPH_C32(0xf8de0000), SPH_C32(0xcf0da280), + SPH_C32(0xacef6bfc), SPH_C32(0x430ef6f2), SPH_C32(0x6a5a193a), + SPH_C32(0x2cf8a3fa) }, + { SPH_C32(0x73a20000), SPH_C32(0x019a0000), SPH_C32(0xea7d0000), + SPH_C32(0xb42f4860), SPH_C32(0x99922850), SPH_C32(0x61737d1e), + SPH_C32(0x065bbb65), SPH_C32(0x172114e8), SPH_C32(0x61d00000), + SPH_C32(0x03c70000), SPH_C32(0xe1d60000), SPH_C32(0x630da480), + SPH_C32(0x0c2c3a7c), SPH_C32(0x0abf8575), SPH_C32(0x9099cb07), + SPH_C32(0xb5cd9fb3) }, + { SPH_C32(0x958a0000), SPH_C32(0x4dd10000), SPH_C32(0x42280000), + SPH_C32(0x67ff4a80), SPH_C32(0x41f318e8), SPH_C32(0xf9d4cdc4), + SPH_C32(0x2ecebdd1), SPH_C32(0xc07b5c7f), SPH_C32(0x91150000), + SPH_C32(0x5ae40000), SPH_C32(0xa4540000), SPH_C32(0x8280a440), + SPH_C32(0x37413c4d), SPH_C32(0xc852d3ec), SPH_C32(0x5b79351b), + SPH_C32(0xe36a2e2c) }, + { SPH_C32(0x83670000), SPH_C32(0x58b90000), SPH_C32(0xafff0000), + SPH_C32(0x55a248a0), SPH_C32(0xa2ff2e61), SPH_C32(0xa39e2b87), + SPH_C32(0xcdbb4579), SPH_C32(0x4186a577), SPH_C32(0x773d0000), + SPH_C32(0x16af0000), SPH_C32(0x0c010000), SPH_C32(0x5150a6a0), + SPH_C32(0xef200cf5), SPH_C32(0x50f56336), SPH_C32(0x73ec33af), + SPH_C32(0x343066bb) }, + { SPH_C32(0x654f0000), SPH_C32(0x14f20000), SPH_C32(0x07aa0000), + SPH_C32(0x86724a40), SPH_C32(0x7a9e1ed9), SPH_C32(0x3b399b5d), + SPH_C32(0xe52e43cd), SPH_C32(0x96dcede0), SPH_C32(0x87f80000), + SPH_C32(0x4f8c0000), SPH_C32(0x49830000), SPH_C32(0xb0dda660), + SPH_C32(0xd44d0ac4), SPH_C32(0x921835af), SPH_C32(0xb80ccdb3), + SPH_C32(0x6297d724) }, + { SPH_C32(0xc7930000), SPH_C32(0x76a90000), SPH_C32(0x5b200000), + SPH_C32(0xcbff4c80), SPH_C32(0xe1304968), SPH_C32(0xb065be43), + SPH_C32(0xd40d6fec), SPH_C32(0x594e6036), SPH_C32(0x82d60000), + SPH_C32(0xbe060000), SPH_C32(0x66c50000), SPH_C32(0xdcffa4e0), + SPH_C32(0x22963066), SPH_C32(0x870ab224), SPH_C32(0xe35c6001), + SPH_C32(0xee1b8a8a) }, + { SPH_C32(0x21bb0000), SPH_C32(0x3ae20000), SPH_C32(0xf3750000), + SPH_C32(0x182f4e60), SPH_C32(0x395179d0), SPH_C32(0x28c20e99), + SPH_C32(0xfc986958), SPH_C32(0x8e1428a1), SPH_C32(0x72130000), + SPH_C32(0xe7250000), SPH_C32(0x23470000), SPH_C32(0x3d72a420), + SPH_C32(0x19fb3657), SPH_C32(0x45e7e4bd), SPH_C32(0x28bc9e1d), + SPH_C32(0xb8bc3b15) }, + { SPH_C32(0x37560000), SPH_C32(0x2f8a0000), SPH_C32(0x1ea20000), + SPH_C32(0x2a724c40), SPH_C32(0xda5d4f59), SPH_C32(0x7288e8da), + SPH_C32(0x1fed91f0), SPH_C32(0x0fe9d1a9), SPH_C32(0x943b0000), + SPH_C32(0xab6e0000), SPH_C32(0x8b120000), SPH_C32(0xeea2a6c0), + SPH_C32(0xc19a06ef), SPH_C32(0xdd405467), SPH_C32(0x002998a9), + SPH_C32(0x6fe67382) }, + { SPH_C32(0xd17e0000), SPH_C32(0x63c10000), SPH_C32(0xb6f70000), + SPH_C32(0xf9a24ea0), SPH_C32(0x023c7fe1), SPH_C32(0xea2f5800), + SPH_C32(0x37789744), SPH_C32(0xd8b3993e), SPH_C32(0x64fe0000), + SPH_C32(0xf24d0000), SPH_C32(0xce900000), SPH_C32(0x0f2fa600), + SPH_C32(0xfaf700de), SPH_C32(0x1fad02fe), SPH_C32(0xcbc966b5), + SPH_C32(0x3941c21d) }, + { SPH_C32(0x288b0000), SPH_C32(0x0d770000), SPH_C32(0x5db60000), + SPH_C32(0x1f991800), SPH_C32(0x767042e8), SPH_C32(0xdde1a2a3), + SPH_C32(0x5b06af40), SPH_C32(0x19e93cbf), SPH_C32(0x34150000), + SPH_C32(0x6bb40000), SPH_C32(0x50a70000), SPH_C32(0x4043d800), + SPH_C32(0x442925b1), SPH_C32(0x51215aaf), SPH_C32(0xf5c886bf), + SPH_C32(0xdf46dbca) }, + { SPH_C32(0xcea30000), SPH_C32(0x413c0000), SPH_C32(0xf5e30000), + SPH_C32(0xcc491ae0), SPH_C32(0xae117250), SPH_C32(0x45461279), + SPH_C32(0x7393a9f4), SPH_C32(0xceb37428), SPH_C32(0xc4d00000), + SPH_C32(0x32970000), SPH_C32(0x15250000), SPH_C32(0xa1ced8c0), + SPH_C32(0x7f442380), SPH_C32(0x93cc0c36), SPH_C32(0x3e2878a3), + SPH_C32(0x89e16a55) }, + { SPH_C32(0xd84e0000), SPH_C32(0x54540000), SPH_C32(0x18340000), + SPH_C32(0xfe1418c0), SPH_C32(0x4d1d44d9), SPH_C32(0x1f0cf43a), + SPH_C32(0x90e6515c), SPH_C32(0x4f4e8d20), SPH_C32(0x22f80000), + SPH_C32(0x7edc0000), SPH_C32(0xbd700000), SPH_C32(0x721eda20), + SPH_C32(0xa7251338), SPH_C32(0x0b6bbcec), SPH_C32(0x16bd7e17), + SPH_C32(0x5ebb22c2) }, + { SPH_C32(0x3e660000), SPH_C32(0x181f0000), SPH_C32(0xb0610000), + SPH_C32(0x2dc41a20), SPH_C32(0x957c7461), SPH_C32(0x87ab44e0), + SPH_C32(0xb87357e8), SPH_C32(0x9814c5b7), SPH_C32(0xd23d0000), + SPH_C32(0x27ff0000), SPH_C32(0xf8f20000), SPH_C32(0x9393dae0), + SPH_C32(0x9c481509), SPH_C32(0xc986ea75), SPH_C32(0xdd5d800b), + SPH_C32(0x081c935d) }, + { SPH_C32(0x9cba0000), SPH_C32(0x7a440000), SPH_C32(0xeceb0000), + SPH_C32(0x60491ce0), SPH_C32(0x0ed223d0), SPH_C32(0x0cf761fe), + SPH_C32(0x89507bc9), SPH_C32(0x57864861), SPH_C32(0xd7130000), + SPH_C32(0xd6750000), SPH_C32(0xd7b40000), SPH_C32(0xffb1d860), + SPH_C32(0x6a932fab), SPH_C32(0xdc946dfe), SPH_C32(0x860d2db9), + SPH_C32(0x8490cef3) }, + { SPH_C32(0x7a920000), SPH_C32(0x360f0000), SPH_C32(0x44be0000), + SPH_C32(0xb3991e00), SPH_C32(0xd6b31368), SPH_C32(0x9450d124), + SPH_C32(0xa1c57d7d), SPH_C32(0x80dc00f6), SPH_C32(0x27d60000), + SPH_C32(0x8f560000), SPH_C32(0x92360000), SPH_C32(0x1e3cd8a0), + SPH_C32(0x51fe299a), SPH_C32(0x1e793b67), SPH_C32(0x4dedd3a5), + SPH_C32(0xd2377f6c) }, + { SPH_C32(0x6c7f0000), SPH_C32(0x23670000), SPH_C32(0xa9690000), + SPH_C32(0x81c41c20), SPH_C32(0x35bf25e1), SPH_C32(0xce1a3767), + SPH_C32(0x42b085d5), SPH_C32(0x0121f9fe), SPH_C32(0xc1fe0000), + SPH_C32(0xc31d0000), SPH_C32(0x3a630000), SPH_C32(0xcdecda40), + SPH_C32(0x899f1922), SPH_C32(0x86de8bbd), SPH_C32(0x6578d511), + SPH_C32(0x056d37fb) }, + { SPH_C32(0x8a570000), SPH_C32(0x6f2c0000), SPH_C32(0x013c0000), + SPH_C32(0x52141ec0), SPH_C32(0xedde1559), SPH_C32(0x56bd87bd), + SPH_C32(0x6a258361), SPH_C32(0xd67bb169), SPH_C32(0x313b0000), + SPH_C32(0x9a3e0000), SPH_C32(0x7fe10000), SPH_C32(0x2c61da80), + SPH_C32(0xb2f21f13), SPH_C32(0x4433dd24), SPH_C32(0xae982b0d), + SPH_C32(0x53ca8664) }, + { SPH_C32(0xcb8d0000), SPH_C32(0xb0b60000), SPH_C32(0xdaa50000), + SPH_C32(0xa06b1860), SPH_C32(0x58ca48f2), SPH_C32(0x505495f2), + SPH_C32(0x28c30446), SPH_C32(0x423f2986), SPH_C32(0x63220000), + SPH_C32(0xa1460000), SPH_C32(0x66e90000), SPH_C32(0x8061dc80), + SPH_C32(0x12314e93), SPH_C32(0x0d82aea3), SPH_C32(0x545bf930), + SPH_C32(0xcaffba2d) }, + { SPH_C32(0x2da50000), SPH_C32(0xfcfd0000), SPH_C32(0x72f00000), + SPH_C32(0x73bb1a80), SPH_C32(0x80ab784a), SPH_C32(0xc8f32528), + SPH_C32(0x005602f2), SPH_C32(0x95656111), SPH_C32(0x93e70000), + SPH_C32(0xf8650000), SPH_C32(0x236b0000), SPH_C32(0x61ecdc40), + SPH_C32(0x295c48a2), SPH_C32(0xcf6ff83a), SPH_C32(0x9fbb072c), + SPH_C32(0x9c580bb2) }, + { SPH_C32(0x3b480000), SPH_C32(0xe9950000), SPH_C32(0x9f270000), + SPH_C32(0x41e618a0), SPH_C32(0x63a74ec3), SPH_C32(0x92b9c36b), + SPH_C32(0xe323fa5a), SPH_C32(0x14989819), SPH_C32(0x75cf0000), + SPH_C32(0xb42e0000), SPH_C32(0x8b3e0000), SPH_C32(0xb23cdea0), + SPH_C32(0xf13d781a), SPH_C32(0x57c848e0), SPH_C32(0xb72e0198), + SPH_C32(0x4b024325) }, + { SPH_C32(0xdd600000), SPH_C32(0xa5de0000), SPH_C32(0x37720000), + SPH_C32(0x92361a40), SPH_C32(0xbbc67e7b), SPH_C32(0x0a1e73b1), + SPH_C32(0xcbb6fcee), SPH_C32(0xc3c2d08e), SPH_C32(0x850a0000), + SPH_C32(0xed0d0000), SPH_C32(0xcebc0000), SPH_C32(0x53b1de60), + SPH_C32(0xca507e2b), SPH_C32(0x95251e79), SPH_C32(0x7cceff84), + SPH_C32(0x1da5f2ba) }, + { SPH_C32(0x7fbc0000), SPH_C32(0xc7850000), SPH_C32(0x6bf80000), + SPH_C32(0xdfbb1c80), SPH_C32(0x206829ca), SPH_C32(0x814256af), + SPH_C32(0xfa95d0cf), SPH_C32(0x0c505d58), SPH_C32(0x80240000), + SPH_C32(0x1c870000), SPH_C32(0xe1fa0000), SPH_C32(0x3f93dce0), + SPH_C32(0x3c8b4489), SPH_C32(0x803799f2), SPH_C32(0x279e5236), + SPH_C32(0x9129af14) }, + { SPH_C32(0x99940000), SPH_C32(0x8bce0000), SPH_C32(0xc3ad0000), + SPH_C32(0x0c6b1e60), SPH_C32(0xf8091972), SPH_C32(0x19e5e675), + SPH_C32(0xd200d67b), SPH_C32(0xdb0a15cf), SPH_C32(0x70e10000), + SPH_C32(0x45a40000), SPH_C32(0xa4780000), SPH_C32(0xde1edc20), + SPH_C32(0x07e642b8), SPH_C32(0x42dacf6b), SPH_C32(0xec7eac2a), + SPH_C32(0xc78e1e8b) }, + { SPH_C32(0x8f790000), SPH_C32(0x9ea60000), SPH_C32(0x2e7a0000), + SPH_C32(0x3e361c40), SPH_C32(0x1b052ffb), SPH_C32(0x43af0036), + SPH_C32(0x31752ed3), SPH_C32(0x5af7ecc7), SPH_C32(0x96c90000), + SPH_C32(0x09ef0000), SPH_C32(0x0c2d0000), SPH_C32(0x0dcedec0), + SPH_C32(0xdf877200), SPH_C32(0xda7d7fb1), SPH_C32(0xc4ebaa9e), + SPH_C32(0x10d4561c) }, + { SPH_C32(0x69510000), SPH_C32(0xd2ed0000), SPH_C32(0x862f0000), + SPH_C32(0xede61ea0), SPH_C32(0xc3641f43), SPH_C32(0xdb08b0ec), + SPH_C32(0x19e02867), SPH_C32(0x8dada450), SPH_C32(0x660c0000), + SPH_C32(0x50cc0000), SPH_C32(0x49af0000), SPH_C32(0xec43de00), + SPH_C32(0xe4ea7431), SPH_C32(0x18902928), SPH_C32(0x0f0b5482), + SPH_C32(0x4673e783) }, + { SPH_C32(0x2a790000), SPH_C32(0xaff60000), SPH_C32(0xda890000), + SPH_C32(0xfcf56000), SPH_C32(0x686d3607), SPH_C32(0xdadc8975), + SPH_C32(0x9fc49d77), SPH_C32(0x66db1921), SPH_C32(0x8ec80000), + SPH_C32(0x78190000), SPH_C32(0xe7400000), SPH_C32(0xb76bf000), + SPH_C32(0x9b6c31fc), SPH_C32(0x673b9995), SPH_C32(0x1f920bab), + SPH_C32(0xf56ac33a) }, + { SPH_C32(0xcc510000), SPH_C32(0xe3bd0000), SPH_C32(0x72dc0000), + SPH_C32(0x2f2562e0), SPH_C32(0xb00c06bf), SPH_C32(0x427b39af), + SPH_C32(0xb7519bc3), SPH_C32(0xb18151b6), SPH_C32(0x7e0d0000), + SPH_C32(0x213a0000), SPH_C32(0xa2c20000), SPH_C32(0x56e6f0c0), + SPH_C32(0xa00137cd), SPH_C32(0xa5d6cf0c), SPH_C32(0xd472f5b7), + SPH_C32(0xa3cd72a5) }, + { SPH_C32(0xdabc0000), SPH_C32(0xf6d50000), SPH_C32(0x9f0b0000), + SPH_C32(0x1d7860c0), SPH_C32(0x53003036), SPH_C32(0x1831dfec), + SPH_C32(0x5424636b), SPH_C32(0x307ca8be), SPH_C32(0x98250000), + SPH_C32(0x6d710000), SPH_C32(0x0a970000), SPH_C32(0x8536f220), + SPH_C32(0x78600775), SPH_C32(0x3d717fd6), SPH_C32(0xfce7f303), + SPH_C32(0x74973a32) }, + { SPH_C32(0x3c940000), SPH_C32(0xba9e0000), SPH_C32(0x375e0000), + SPH_C32(0xcea86220), SPH_C32(0x8b61008e), SPH_C32(0x80966f36), + SPH_C32(0x7cb165df), SPH_C32(0xe726e029), SPH_C32(0x68e00000), + SPH_C32(0x34520000), SPH_C32(0x4f150000), SPH_C32(0x64bbf2e0), + SPH_C32(0x430d0144), SPH_C32(0xff9c294f), SPH_C32(0x37070d1f), + SPH_C32(0x22308bad) }, + { SPH_C32(0x9e480000), SPH_C32(0xd8c50000), SPH_C32(0x6bd40000), + SPH_C32(0x832564e0), SPH_C32(0x10cf573f), SPH_C32(0x0bca4a28), + SPH_C32(0x4d9249fe), SPH_C32(0x28b46dff), SPH_C32(0x6dce0000), + SPH_C32(0xc5d80000), SPH_C32(0x60530000), SPH_C32(0x0899f060), + SPH_C32(0xb5d63be6), SPH_C32(0xea8eaec4), SPH_C32(0x6c57a0ad), + SPH_C32(0xaebcd603) }, + { SPH_C32(0x78600000), SPH_C32(0x948e0000), SPH_C32(0xc3810000), + SPH_C32(0x50f56600), SPH_C32(0xc8ae6787), SPH_C32(0x936dfaf2), + SPH_C32(0x65074f4a), SPH_C32(0xffee2568), SPH_C32(0x9d0b0000), + SPH_C32(0x9cfb0000), SPH_C32(0x25d10000), SPH_C32(0xe914f0a0), + SPH_C32(0x8ebb3dd7), SPH_C32(0x2863f85d), SPH_C32(0xa7b75eb1), + SPH_C32(0xf81b679c) }, + { SPH_C32(0x6e8d0000), SPH_C32(0x81e60000), SPH_C32(0x2e560000), + SPH_C32(0x62a86420), SPH_C32(0x2ba2510e), SPH_C32(0xc9271cb1), + SPH_C32(0x8672b7e2), SPH_C32(0x7e13dc60), SPH_C32(0x7b230000), + SPH_C32(0xd0b00000), SPH_C32(0x8d840000), SPH_C32(0x3ac4f240), + SPH_C32(0x56da0d6f), SPH_C32(0xb0c44887), SPH_C32(0x8f225805), + SPH_C32(0x2f412f0b) }, + { SPH_C32(0x88a50000), SPH_C32(0xcdad0000), SPH_C32(0x86030000), + SPH_C32(0xb17866c0), SPH_C32(0xf3c361b6), SPH_C32(0x5180ac6b), + SPH_C32(0xaee7b156), SPH_C32(0xa94994f7), SPH_C32(0x8be60000), + SPH_C32(0x89930000), SPH_C32(0xc8060000), SPH_C32(0xdb49f280), + SPH_C32(0x6db70b5e), SPH_C32(0x72291e1e), SPH_C32(0x44c2a619), + SPH_C32(0x79e69e94) }, + { SPH_C32(0xc97f0000), SPH_C32(0x12370000), SPH_C32(0x5d9a0000), + SPH_C32(0x43076060), SPH_C32(0x46d73c1d), SPH_C32(0x5769be24), + SPH_C32(0xec013671), SPH_C32(0x3d0d0c18), SPH_C32(0xd9ff0000), + SPH_C32(0xb2eb0000), SPH_C32(0xd10e0000), SPH_C32(0x7749f480), + SPH_C32(0xcd745ade), SPH_C32(0x3b986d99), SPH_C32(0xbe017424), + SPH_C32(0xe0d3a2dd) }, + { SPH_C32(0x2f570000), SPH_C32(0x5e7c0000), SPH_C32(0xf5cf0000), + SPH_C32(0x90d76280), SPH_C32(0x9eb60ca5), SPH_C32(0xcfce0efe), + SPH_C32(0xc49430c5), SPH_C32(0xea57448f), SPH_C32(0x293a0000), + SPH_C32(0xebc80000), SPH_C32(0x948c0000), SPH_C32(0x96c4f440), + SPH_C32(0xf6195cef), SPH_C32(0xf9753b00), SPH_C32(0x75e18a38), + SPH_C32(0xb6741342) }, + { SPH_C32(0x39ba0000), SPH_C32(0x4b140000), SPH_C32(0x18180000), + SPH_C32(0xa28a60a0), SPH_C32(0x7dba3a2c), SPH_C32(0x9584e8bd), + SPH_C32(0x27e1c86d), SPH_C32(0x6baabd87), SPH_C32(0xcf120000), + SPH_C32(0xa7830000), SPH_C32(0x3cd90000), SPH_C32(0x4514f6a0), + SPH_C32(0x2e786c57), SPH_C32(0x61d28bda), SPH_C32(0x5d748c8c), + SPH_C32(0x612e5bd5) }, + { SPH_C32(0xdf920000), SPH_C32(0x075f0000), SPH_C32(0xb04d0000), + SPH_C32(0x715a6240), SPH_C32(0xa5db0a94), SPH_C32(0x0d235867), + SPH_C32(0x0f74ced9), SPH_C32(0xbcf0f510), SPH_C32(0x3fd70000), + SPH_C32(0xfea00000), SPH_C32(0x795b0000), SPH_C32(0xa499f660), + SPH_C32(0x15156a66), SPH_C32(0xa33fdd43), SPH_C32(0x96947290), + SPH_C32(0x3789ea4a) }, + { SPH_C32(0x7d4e0000), SPH_C32(0x65040000), SPH_C32(0xecc70000), + SPH_C32(0x3cd76480), SPH_C32(0x3e755d25), SPH_C32(0x867f7d79), + SPH_C32(0x3e57e2f8), SPH_C32(0x736278c6), SPH_C32(0x3af90000), + SPH_C32(0x0f2a0000), SPH_C32(0x561d0000), SPH_C32(0xc8bbf4e0), + SPH_C32(0xe3ce50c4), SPH_C32(0xb62d5ac8), SPH_C32(0xcdc4df22), + SPH_C32(0xbb05b7e4) }, + { SPH_C32(0x9b660000), SPH_C32(0x294f0000), SPH_C32(0x44920000), + SPH_C32(0xef076660), SPH_C32(0xe6146d9d), SPH_C32(0x1ed8cda3), + SPH_C32(0x16c2e44c), SPH_C32(0xa4383051), SPH_C32(0xca3c0000), + SPH_C32(0x56090000), SPH_C32(0x139f0000), SPH_C32(0x2936f420), + SPH_C32(0xd8a356f5), SPH_C32(0x74c00c51), SPH_C32(0x0624213e), + SPH_C32(0xeda2067b) }, + { SPH_C32(0x8d8b0000), SPH_C32(0x3c270000), SPH_C32(0xa9450000), + SPH_C32(0xdd5a6440), SPH_C32(0x05185b14), SPH_C32(0x44922be0), + SPH_C32(0xf5b71ce4), SPH_C32(0x25c5c959), SPH_C32(0x2c140000), + SPH_C32(0x1a420000), SPH_C32(0xbbca0000), SPH_C32(0xfae6f6c0), + SPH_C32(0x00c2664d), SPH_C32(0xec67bc8b), SPH_C32(0x2eb1278a), + SPH_C32(0x3af84eec) }, + { SPH_C32(0x6ba30000), SPH_C32(0x706c0000), SPH_C32(0x01100000), + SPH_C32(0x0e8a66a0), SPH_C32(0xdd796bac), SPH_C32(0xdc359b3a), + SPH_C32(0xdd221a50), SPH_C32(0xf29f81ce), SPH_C32(0xdcd10000), + SPH_C32(0x43610000), SPH_C32(0xfe480000), SPH_C32(0x1b6bf600), + SPH_C32(0x3baf607c), SPH_C32(0x2e8aea12), SPH_C32(0xe551d996), + SPH_C32(0x6c5fff73) }, + { SPH_C32(0x8c3a0000), SPH_C32(0xda980000), SPH_C32(0x607f0000), + SPH_C32(0x54078800), SPH_C32(0x85714513), SPH_C32(0x6006b243), + SPH_C32(0xdb50399c), SPH_C32(0x8a58e6a4), SPH_C32(0x1e6c0000), + SPH_C32(0xc4420000), SPH_C32(0x8a2e0000), SPH_C32(0xbcb6b800), + SPH_C32(0x2c4413b6), SPH_C32(0x8bfdd3da), SPH_C32(0x6a0c1bc8), + SPH_C32(0xb99dc2eb) }, + { SPH_C32(0x6a120000), SPH_C32(0x96d30000), SPH_C32(0xc82a0000), + SPH_C32(0x87d78ae0), SPH_C32(0x5d1075ab), SPH_C32(0xf8a10299), + SPH_C32(0xf3c53f28), SPH_C32(0x5d02ae33), SPH_C32(0xeea90000), + SPH_C32(0x9d610000), SPH_C32(0xcfac0000), SPH_C32(0x5d3bb8c0), + SPH_C32(0x17291587), SPH_C32(0x49108543), SPH_C32(0xa1ece5d4), + SPH_C32(0xef3a7374) }, + { SPH_C32(0x7cff0000), SPH_C32(0x83bb0000), SPH_C32(0x25fd0000), + SPH_C32(0xb58a88c0), SPH_C32(0xbe1c4322), SPH_C32(0xa2ebe4da), + SPH_C32(0x10b0c780), SPH_C32(0xdcff573b), SPH_C32(0x08810000), + SPH_C32(0xd12a0000), SPH_C32(0x67f90000), SPH_C32(0x8eebba20), + SPH_C32(0xcf48253f), SPH_C32(0xd1b73599), SPH_C32(0x8979e360), + SPH_C32(0x38603be3) }, + { SPH_C32(0x9ad70000), SPH_C32(0xcff00000), SPH_C32(0x8da80000), + SPH_C32(0x665a8a20), SPH_C32(0x667d739a), SPH_C32(0x3a4c5400), + SPH_C32(0x3825c134), SPH_C32(0x0ba51fac), SPH_C32(0xf8440000), + SPH_C32(0x88090000), SPH_C32(0x227b0000), SPH_C32(0x6f66bae0), + SPH_C32(0xf425230e), SPH_C32(0x135a6300), SPH_C32(0x42991d7c), + SPH_C32(0x6ec78a7c) }, + { SPH_C32(0x380b0000), SPH_C32(0xadab0000), SPH_C32(0xd1220000), + SPH_C32(0x2bd78ce0), SPH_C32(0xfdd3242b), SPH_C32(0xb110711e), + SPH_C32(0x0906ed15), SPH_C32(0xc437927a), SPH_C32(0xfd6a0000), + SPH_C32(0x79830000), SPH_C32(0x0d3d0000), SPH_C32(0x0344b860), + SPH_C32(0x02fe19ac), SPH_C32(0x0648e48b), SPH_C32(0x19c9b0ce), + SPH_C32(0xe24bd7d2) }, + { SPH_C32(0xde230000), SPH_C32(0xe1e00000), SPH_C32(0x79770000), + SPH_C32(0xf8078e00), SPH_C32(0x25b21493), SPH_C32(0x29b7c1c4), + SPH_C32(0x2193eba1), SPH_C32(0x136ddaed), SPH_C32(0x0daf0000), + SPH_C32(0x20a00000), SPH_C32(0x48bf0000), SPH_C32(0xe2c9b8a0), + SPH_C32(0x39931f9d), SPH_C32(0xc4a5b212), SPH_C32(0xd2294ed2), + SPH_C32(0xb4ec664d) }, + { SPH_C32(0xc8ce0000), SPH_C32(0xf4880000), SPH_C32(0x94a00000), + SPH_C32(0xca5a8c20), SPH_C32(0xc6be221a), SPH_C32(0x73fd2787), + SPH_C32(0xc2e61309), SPH_C32(0x929023e5), SPH_C32(0xeb870000), + SPH_C32(0x6ceb0000), SPH_C32(0xe0ea0000), SPH_C32(0x3119ba40), + SPH_C32(0xe1f22f25), SPH_C32(0x5c0202c8), SPH_C32(0xfabc4866), + SPH_C32(0x63b62eda) }, + { SPH_C32(0x2ee60000), SPH_C32(0xb8c30000), SPH_C32(0x3cf50000), + SPH_C32(0x198a8ec0), SPH_C32(0x1edf12a2), SPH_C32(0xeb5a975d), + SPH_C32(0xea7315bd), SPH_C32(0x45ca6b72), SPH_C32(0x1b420000), + SPH_C32(0x35c80000), SPH_C32(0xa5680000), SPH_C32(0xd094ba80), + SPH_C32(0xda9f2914), SPH_C32(0x9eef5451), SPH_C32(0x315cb67a), + SPH_C32(0x35119f45) }, + { SPH_C32(0x6f3c0000), SPH_C32(0x67590000), SPH_C32(0xe76c0000), + SPH_C32(0xebf58860), SPH_C32(0xabcb4f09), SPH_C32(0xedb38512), + SPH_C32(0xa895929a), SPH_C32(0xd18ef39d), SPH_C32(0x495b0000), + SPH_C32(0x0eb00000), SPH_C32(0xbc600000), SPH_C32(0x7c94bc80), + SPH_C32(0x7a5c7894), SPH_C32(0xd75e27d6), SPH_C32(0xcb9f6447), + SPH_C32(0xac24a30c) }, + { SPH_C32(0x89140000), SPH_C32(0x2b120000), SPH_C32(0x4f390000), + SPH_C32(0x38258a80), SPH_C32(0x73aa7fb1), SPH_C32(0x751435c8), + SPH_C32(0x8000942e), SPH_C32(0x06d4bb0a), SPH_C32(0xb99e0000), + SPH_C32(0x57930000), SPH_C32(0xf9e20000), SPH_C32(0x9d19bc40), + SPH_C32(0x41317ea5), SPH_C32(0x15b3714f), SPH_C32(0x007f9a5b), + SPH_C32(0xfa831293) }, + { SPH_C32(0x9ff90000), SPH_C32(0x3e7a0000), SPH_C32(0xa2ee0000), + SPH_C32(0x0a7888a0), SPH_C32(0x90a64938), SPH_C32(0x2f5ed38b), + SPH_C32(0x63756c86), SPH_C32(0x87294202), SPH_C32(0x5fb60000), + SPH_C32(0x1bd80000), SPH_C32(0x51b70000), SPH_C32(0x4ec9bea0), + SPH_C32(0x99504e1d), SPH_C32(0x8d14c195), SPH_C32(0x28ea9cef), + SPH_C32(0x2dd95a04) }, + { SPH_C32(0x79d10000), SPH_C32(0x72310000), SPH_C32(0x0abb0000), + SPH_C32(0xd9a88a40), SPH_C32(0x48c77980), SPH_C32(0xb7f96351), + SPH_C32(0x4be06a32), SPH_C32(0x50730a95), SPH_C32(0xaf730000), + SPH_C32(0x42fb0000), SPH_C32(0x14350000), SPH_C32(0xaf44be60), + SPH_C32(0xa23d482c), SPH_C32(0x4ff9970c), SPH_C32(0xe30a62f3), + SPH_C32(0x7b7eeb9b) }, + { SPH_C32(0xdb0d0000), SPH_C32(0x106a0000), SPH_C32(0x56310000), + SPH_C32(0x94258c80), SPH_C32(0xd3692e31), SPH_C32(0x3ca5464f), + SPH_C32(0x7ac34613), SPH_C32(0x9fe18743), SPH_C32(0xaa5d0000), + SPH_C32(0xb3710000), SPH_C32(0x3b730000), SPH_C32(0xc366bce0), + SPH_C32(0x54e6728e), SPH_C32(0x5aeb1087), SPH_C32(0xb85acf41), + SPH_C32(0xf7f2b635) }, + { SPH_C32(0x3d250000), SPH_C32(0x5c210000), SPH_C32(0xfe640000), + SPH_C32(0x47f58e60), SPH_C32(0x0b081e89), SPH_C32(0xa402f695), + SPH_C32(0x525640a7), SPH_C32(0x48bbcfd4), SPH_C32(0x5a980000), + SPH_C32(0xea520000), SPH_C32(0x7ef10000), SPH_C32(0x22ebbc20), + SPH_C32(0x6f8b74bf), SPH_C32(0x9806461e), SPH_C32(0x73ba315d), + SPH_C32(0xa15507aa) }, + { SPH_C32(0x2bc80000), SPH_C32(0x49490000), SPH_C32(0x13b30000), + SPH_C32(0x75a88c40), SPH_C32(0xe8042800), SPH_C32(0xfe4810d6), + SPH_C32(0xb123b80f), SPH_C32(0xc94636dc), SPH_C32(0xbcb00000), + SPH_C32(0xa6190000), SPH_C32(0xd6a40000), SPH_C32(0xf13bbec0), + SPH_C32(0xb7ea4407), SPH_C32(0x00a1f6c4), SPH_C32(0x5b2f37e9), + SPH_C32(0x760f4f3d) }, + { SPH_C32(0xcde00000), SPH_C32(0x05020000), SPH_C32(0xbbe60000), + SPH_C32(0xa6788ea0), SPH_C32(0x306518b8), SPH_C32(0x66efa00c), + SPH_C32(0x99b6bebb), SPH_C32(0x1e1c7e4b), SPH_C32(0x4c750000), + SPH_C32(0xff3a0000), SPH_C32(0x93260000), SPH_C32(0x10b6be00), + SPH_C32(0x8c874236), SPH_C32(0xc24ca05d), SPH_C32(0x90cfc9f5), + SPH_C32(0x20a8fea2) }, + { SPH_C32(0x8ec80000), SPH_C32(0x78190000), SPH_C32(0xe7400000), + SPH_C32(0xb76bf000), SPH_C32(0x9b6c31fc), SPH_C32(0x673b9995), + SPH_C32(0x1f920bab), SPH_C32(0xf56ac33a), SPH_C32(0xa4b10000), + SPH_C32(0xd7ef0000), SPH_C32(0x3dc90000), SPH_C32(0x4b9e9000), + SPH_C32(0xf30107fb), SPH_C32(0xbde710e0), SPH_C32(0x805696dc), + SPH_C32(0x93b1da1b) }, + { SPH_C32(0x68e00000), SPH_C32(0x34520000), SPH_C32(0x4f150000), + SPH_C32(0x64bbf2e0), SPH_C32(0x430d0144), SPH_C32(0xff9c294f), + SPH_C32(0x37070d1f), SPH_C32(0x22308bad), SPH_C32(0x54740000), + SPH_C32(0x8ecc0000), SPH_C32(0x784b0000), SPH_C32(0xaa1390c0), + SPH_C32(0xc86c01ca), SPH_C32(0x7f0a4679), SPH_C32(0x4bb668c0), + SPH_C32(0xc5166b84) }, + { SPH_C32(0x7e0d0000), SPH_C32(0x213a0000), SPH_C32(0xa2c20000), + SPH_C32(0x56e6f0c0), SPH_C32(0xa00137cd), SPH_C32(0xa5d6cf0c), + SPH_C32(0xd472f5b7), SPH_C32(0xa3cd72a5), SPH_C32(0xb25c0000), + SPH_C32(0xc2870000), SPH_C32(0xd01e0000), SPH_C32(0x79c39220), + SPH_C32(0x100d3172), SPH_C32(0xe7adf6a3), SPH_C32(0x63236e74), + SPH_C32(0x124c2313) }, + { SPH_C32(0x98250000), SPH_C32(0x6d710000), SPH_C32(0x0a970000), + SPH_C32(0x8536f220), SPH_C32(0x78600775), SPH_C32(0x3d717fd6), + SPH_C32(0xfce7f303), SPH_C32(0x74973a32), SPH_C32(0x42990000), + SPH_C32(0x9ba40000), SPH_C32(0x959c0000), SPH_C32(0x984e92e0), + SPH_C32(0x2b603743), SPH_C32(0x2540a03a), SPH_C32(0xa8c39068), + SPH_C32(0x44eb928c) }, + { SPH_C32(0x3af90000), SPH_C32(0x0f2a0000), SPH_C32(0x561d0000), + SPH_C32(0xc8bbf4e0), SPH_C32(0xe3ce50c4), SPH_C32(0xb62d5ac8), + SPH_C32(0xcdc4df22), SPH_C32(0xbb05b7e4), SPH_C32(0x47b70000), + SPH_C32(0x6a2e0000), SPH_C32(0xbada0000), SPH_C32(0xf46c9060), + SPH_C32(0xddbb0de1), SPH_C32(0x305227b1), SPH_C32(0xf3933dda), + SPH_C32(0xc867cf22) }, + { SPH_C32(0xdcd10000), SPH_C32(0x43610000), SPH_C32(0xfe480000), + SPH_C32(0x1b6bf600), SPH_C32(0x3baf607c), SPH_C32(0x2e8aea12), + SPH_C32(0xe551d996), SPH_C32(0x6c5fff73), SPH_C32(0xb7720000), + SPH_C32(0x330d0000), SPH_C32(0xff580000), SPH_C32(0x15e190a0), + SPH_C32(0xe6d60bd0), SPH_C32(0xf2bf7128), SPH_C32(0x3873c3c6), + SPH_C32(0x9ec07ebd) }, + { SPH_C32(0xca3c0000), SPH_C32(0x56090000), SPH_C32(0x139f0000), + SPH_C32(0x2936f420), SPH_C32(0xd8a356f5), SPH_C32(0x74c00c51), + SPH_C32(0x0624213e), SPH_C32(0xeda2067b), SPH_C32(0x515a0000), + SPH_C32(0x7f460000), SPH_C32(0x570d0000), SPH_C32(0xc6319240), + SPH_C32(0x3eb73b68), SPH_C32(0x6a18c1f2), SPH_C32(0x10e6c572), + SPH_C32(0x499a362a) }, + { SPH_C32(0x2c140000), SPH_C32(0x1a420000), SPH_C32(0xbbca0000), + SPH_C32(0xfae6f6c0), SPH_C32(0x00c2664d), SPH_C32(0xec67bc8b), + SPH_C32(0x2eb1278a), SPH_C32(0x3af84eec), SPH_C32(0xa19f0000), + SPH_C32(0x26650000), SPH_C32(0x128f0000), SPH_C32(0x27bc9280), + SPH_C32(0x05da3d59), SPH_C32(0xa8f5976b), SPH_C32(0xdb063b6e), + SPH_C32(0x1f3d87b5) }, + { SPH_C32(0x6dce0000), SPH_C32(0xc5d80000), SPH_C32(0x60530000), + SPH_C32(0x0899f060), SPH_C32(0xb5d63be6), SPH_C32(0xea8eaec4), + SPH_C32(0x6c57a0ad), SPH_C32(0xaebcd603), SPH_C32(0xf3860000), + SPH_C32(0x1d1d0000), SPH_C32(0x0b870000), SPH_C32(0x8bbc9480), + SPH_C32(0xa5196cd9), SPH_C32(0xe144e4ec), SPH_C32(0x21c5e953), + SPH_C32(0x8608bbfc) }, + { SPH_C32(0x8be60000), SPH_C32(0x89930000), SPH_C32(0xc8060000), + SPH_C32(0xdb49f280), SPH_C32(0x6db70b5e), SPH_C32(0x72291e1e), + SPH_C32(0x44c2a619), SPH_C32(0x79e69e94), SPH_C32(0x03430000), + SPH_C32(0x443e0000), SPH_C32(0x4e050000), SPH_C32(0x6a319440), + SPH_C32(0x9e746ae8), SPH_C32(0x23a9b275), SPH_C32(0xea25174f), + SPH_C32(0xd0af0a63) }, + { SPH_C32(0x9d0b0000), SPH_C32(0x9cfb0000), SPH_C32(0x25d10000), + SPH_C32(0xe914f0a0), SPH_C32(0x8ebb3dd7), SPH_C32(0x2863f85d), + SPH_C32(0xa7b75eb1), SPH_C32(0xf81b679c), SPH_C32(0xe56b0000), + SPH_C32(0x08750000), SPH_C32(0xe6500000), SPH_C32(0xb9e196a0), + SPH_C32(0x46155a50), SPH_C32(0xbb0e02af), SPH_C32(0xc2b011fb), + SPH_C32(0x07f542f4) }, + { SPH_C32(0x7b230000), SPH_C32(0xd0b00000), SPH_C32(0x8d840000), + SPH_C32(0x3ac4f240), SPH_C32(0x56da0d6f), SPH_C32(0xb0c44887), + SPH_C32(0x8f225805), SPH_C32(0x2f412f0b), SPH_C32(0x15ae0000), + SPH_C32(0x51560000), SPH_C32(0xa3d20000), SPH_C32(0x586c9660), + SPH_C32(0x7d785c61), SPH_C32(0x79e35436), SPH_C32(0x0950efe7), + SPH_C32(0x5152f36b) }, + { SPH_C32(0xd9ff0000), SPH_C32(0xb2eb0000), SPH_C32(0xd10e0000), + SPH_C32(0x7749f480), SPH_C32(0xcd745ade), SPH_C32(0x3b986d99), + SPH_C32(0xbe017424), SPH_C32(0xe0d3a2dd), SPH_C32(0x10800000), + SPH_C32(0xa0dc0000), SPH_C32(0x8c940000), SPH_C32(0x344e94e0), + SPH_C32(0x8ba366c3), SPH_C32(0x6cf1d3bd), SPH_C32(0x52004255), + SPH_C32(0xdddeaec5) }, + { SPH_C32(0x3fd70000), SPH_C32(0xfea00000), SPH_C32(0x795b0000), + SPH_C32(0xa499f660), SPH_C32(0x15156a66), SPH_C32(0xa33fdd43), + SPH_C32(0x96947290), SPH_C32(0x3789ea4a), SPH_C32(0xe0450000), + SPH_C32(0xf9ff0000), SPH_C32(0xc9160000), SPH_C32(0xd5c39420), + SPH_C32(0xb0ce60f2), SPH_C32(0xae1c8524), SPH_C32(0x99e0bc49), + SPH_C32(0x8b791f5a) }, + { SPH_C32(0x293a0000), SPH_C32(0xebc80000), SPH_C32(0x948c0000), + SPH_C32(0x96c4f440), SPH_C32(0xf6195cef), SPH_C32(0xf9753b00), + SPH_C32(0x75e18a38), SPH_C32(0xb6741342), SPH_C32(0x066d0000), + SPH_C32(0xb5b40000), SPH_C32(0x61430000), SPH_C32(0x061396c0), + SPH_C32(0x68af504a), SPH_C32(0x36bb35fe), SPH_C32(0xb175bafd), + SPH_C32(0x5c2357cd) }, + { SPH_C32(0xcf120000), SPH_C32(0xa7830000), SPH_C32(0x3cd90000), + SPH_C32(0x4514f6a0), SPH_C32(0x2e786c57), SPH_C32(0x61d28bda), + SPH_C32(0x5d748c8c), SPH_C32(0x612e5bd5), SPH_C32(0xf6a80000), + SPH_C32(0xec970000), SPH_C32(0x24c10000), SPH_C32(0xe79e9600), + SPH_C32(0x53c2567b), SPH_C32(0xf4566367), SPH_C32(0x7a9544e1), + SPH_C32(0x0a84e652) }, + { SPH_C32(0x36e70000), SPH_C32(0xc9350000), SPH_C32(0xd7980000), + SPH_C32(0xa32fa000), SPH_C32(0x5a34515e), SPH_C32(0x561c7179), + SPH_C32(0x310ab488), SPH_C32(0xa074fe54), SPH_C32(0xa6430000), + SPH_C32(0x756e0000), SPH_C32(0xbaf60000), SPH_C32(0xa8f2e800), + SPH_C32(0xed1c7314), SPH_C32(0xbada3b36), SPH_C32(0x4494a4eb), + SPH_C32(0xec83ff85) }, + { SPH_C32(0xd0cf0000), SPH_C32(0x857e0000), SPH_C32(0x7fcd0000), + SPH_C32(0x70ffa2e0), SPH_C32(0x825561e6), SPH_C32(0xcebbc1a3), + SPH_C32(0x199fb23c), SPH_C32(0x772eb6c3), SPH_C32(0x56860000), + SPH_C32(0x2c4d0000), SPH_C32(0xff740000), SPH_C32(0x497fe8c0), + SPH_C32(0xd6717525), SPH_C32(0x78376daf), SPH_C32(0x8f745af7), + SPH_C32(0xba244e1a) }, + { SPH_C32(0xc6220000), SPH_C32(0x90160000), SPH_C32(0x921a0000), + SPH_C32(0x42a2a0c0), SPH_C32(0x6159576f), SPH_C32(0x94f127e0), + SPH_C32(0xfaea4a94), SPH_C32(0xf6d34fcb), SPH_C32(0xb0ae0000), + SPH_C32(0x60060000), SPH_C32(0x57210000), SPH_C32(0x9aafea20), + SPH_C32(0x0e10459d), SPH_C32(0xe090dd75), SPH_C32(0xa7e15c43), + SPH_C32(0x6d7e068d) }, + { SPH_C32(0x200a0000), SPH_C32(0xdc5d0000), SPH_C32(0x3a4f0000), + SPH_C32(0x9172a220), SPH_C32(0xb93867d7), SPH_C32(0x0c56973a), + SPH_C32(0xd27f4c20), SPH_C32(0x2189075c), SPH_C32(0x406b0000), + SPH_C32(0x39250000), SPH_C32(0x12a30000), SPH_C32(0x7b22eae0), + SPH_C32(0x357d43ac), SPH_C32(0x227d8bec), SPH_C32(0x6c01a25f), + SPH_C32(0x3bd9b712) }, + { SPH_C32(0x82d60000), SPH_C32(0xbe060000), SPH_C32(0x66c50000), + SPH_C32(0xdcffa4e0), SPH_C32(0x22963066), SPH_C32(0x870ab224), + SPH_C32(0xe35c6001), SPH_C32(0xee1b8a8a), SPH_C32(0x45450000), + SPH_C32(0xc8af0000), SPH_C32(0x3de50000), SPH_C32(0x1700e860), + SPH_C32(0xc3a6790e), SPH_C32(0x376f0c67), SPH_C32(0x37510fed), + SPH_C32(0xb755eabc) }, + { SPH_C32(0x64fe0000), SPH_C32(0xf24d0000), SPH_C32(0xce900000), + SPH_C32(0x0f2fa600), SPH_C32(0xfaf700de), SPH_C32(0x1fad02fe), + SPH_C32(0xcbc966b5), SPH_C32(0x3941c21d), SPH_C32(0xb5800000), + SPH_C32(0x918c0000), SPH_C32(0x78670000), SPH_C32(0xf68de8a0), + SPH_C32(0xf8cb7f3f), SPH_C32(0xf5825afe), SPH_C32(0xfcb1f1f1), + SPH_C32(0xe1f25b23) }, + { SPH_C32(0x72130000), SPH_C32(0xe7250000), SPH_C32(0x23470000), + SPH_C32(0x3d72a420), SPH_C32(0x19fb3657), SPH_C32(0x45e7e4bd), + SPH_C32(0x28bc9e1d), SPH_C32(0xb8bc3b15), SPH_C32(0x53a80000), + SPH_C32(0xddc70000), SPH_C32(0xd0320000), SPH_C32(0x255dea40), + SPH_C32(0x20aa4f87), SPH_C32(0x6d25ea24), SPH_C32(0xd424f745), + SPH_C32(0x36a813b4) }, + { SPH_C32(0x943b0000), SPH_C32(0xab6e0000), SPH_C32(0x8b120000), + SPH_C32(0xeea2a6c0), SPH_C32(0xc19a06ef), SPH_C32(0xdd405467), + SPH_C32(0x002998a9), SPH_C32(0x6fe67382), SPH_C32(0xa36d0000), + SPH_C32(0x84e40000), SPH_C32(0x95b00000), SPH_C32(0xc4d0ea80), + SPH_C32(0x1bc749b6), SPH_C32(0xafc8bcbd), SPH_C32(0x1fc40959), + SPH_C32(0x600fa22b) }, + { SPH_C32(0xd5e10000), SPH_C32(0x74f40000), SPH_C32(0x508b0000), + SPH_C32(0x1cdda060), SPH_C32(0x748e5b44), SPH_C32(0xdba94628), + SPH_C32(0x42cf1f8e), SPH_C32(0xfba2eb6d), SPH_C32(0xf1740000), + SPH_C32(0xbf9c0000), SPH_C32(0x8cb80000), SPH_C32(0x68d0ec80), + SPH_C32(0xbb041836), SPH_C32(0xe679cf3a), SPH_C32(0xe507db64), + SPH_C32(0xf93a9e62) }, + { SPH_C32(0x33c90000), SPH_C32(0x38bf0000), SPH_C32(0xf8de0000), + SPH_C32(0xcf0da280), SPH_C32(0xacef6bfc), SPH_C32(0x430ef6f2), + SPH_C32(0x6a5a193a), SPH_C32(0x2cf8a3fa), SPH_C32(0x01b10000), + SPH_C32(0xe6bf0000), SPH_C32(0xc93a0000), SPH_C32(0x895dec40), + SPH_C32(0x80691e07), SPH_C32(0x249499a3), SPH_C32(0x2ee72578), + SPH_C32(0xaf9d2ffd) }, + { SPH_C32(0x25240000), SPH_C32(0x2dd70000), SPH_C32(0x15090000), + SPH_C32(0xfd50a0a0), SPH_C32(0x4fe35d75), SPH_C32(0x194410b1), + SPH_C32(0x892fe192), SPH_C32(0xad055af2), SPH_C32(0xe7990000), + SPH_C32(0xaaf40000), SPH_C32(0x616f0000), SPH_C32(0x5a8deea0), + SPH_C32(0x58082ebf), SPH_C32(0xbc332979), SPH_C32(0x067223cc), + SPH_C32(0x78c7676a) }, + { SPH_C32(0xc30c0000), SPH_C32(0x619c0000), SPH_C32(0xbd5c0000), + SPH_C32(0x2e80a240), SPH_C32(0x97826dcd), SPH_C32(0x81e3a06b), + SPH_C32(0xa1bae726), SPH_C32(0x7a5f1265), SPH_C32(0x175c0000), + SPH_C32(0xf3d70000), SPH_C32(0x24ed0000), SPH_C32(0xbb00ee60), + SPH_C32(0x6365288e), SPH_C32(0x7ede7fe0), SPH_C32(0xcd92ddd0), + SPH_C32(0x2e60d6f5) }, + { SPH_C32(0x61d00000), SPH_C32(0x03c70000), SPH_C32(0xe1d60000), + SPH_C32(0x630da480), SPH_C32(0x0c2c3a7c), SPH_C32(0x0abf8575), + SPH_C32(0x9099cb07), SPH_C32(0xb5cd9fb3), SPH_C32(0x12720000), + SPH_C32(0x025d0000), SPH_C32(0x0bab0000), SPH_C32(0xd722ece0), + SPH_C32(0x95be122c), SPH_C32(0x6bccf86b), SPH_C32(0x96c27062), + SPH_C32(0xa2ec8b5b) }, + { SPH_C32(0x87f80000), SPH_C32(0x4f8c0000), SPH_C32(0x49830000), + SPH_C32(0xb0dda660), SPH_C32(0xd44d0ac4), SPH_C32(0x921835af), + SPH_C32(0xb80ccdb3), SPH_C32(0x6297d724), SPH_C32(0xe2b70000), + SPH_C32(0x5b7e0000), SPH_C32(0x4e290000), SPH_C32(0x36afec20), + SPH_C32(0xaed3141d), SPH_C32(0xa921aef2), SPH_C32(0x5d228e7e), + SPH_C32(0xf44b3ac4) }, + { SPH_C32(0x91150000), SPH_C32(0x5ae40000), SPH_C32(0xa4540000), + SPH_C32(0x8280a440), SPH_C32(0x37413c4d), SPH_C32(0xc852d3ec), + SPH_C32(0x5b79351b), SPH_C32(0xe36a2e2c), SPH_C32(0x049f0000), + SPH_C32(0x17350000), SPH_C32(0xe67c0000), SPH_C32(0xe57feec0), + SPH_C32(0x76b224a5), SPH_C32(0x31861e28), SPH_C32(0x75b788ca), + SPH_C32(0x23117253) }, + { SPH_C32(0x773d0000), SPH_C32(0x16af0000), SPH_C32(0x0c010000), + SPH_C32(0x5150a6a0), SPH_C32(0xef200cf5), SPH_C32(0x50f56336), + SPH_C32(0x73ec33af), SPH_C32(0x343066bb), SPH_C32(0xf45a0000), + SPH_C32(0x4e160000), SPH_C32(0xa3fe0000), SPH_C32(0x04f2ee00), + SPH_C32(0x4ddf2294), SPH_C32(0xf36b48b1), SPH_C32(0xbe5776d6), + SPH_C32(0x75b6c3cc) }, + { SPH_C32(0x34150000), SPH_C32(0x6bb40000), SPH_C32(0x50a70000), + SPH_C32(0x4043d800), SPH_C32(0x442925b1), SPH_C32(0x51215aaf), + SPH_C32(0xf5c886bf), SPH_C32(0xdf46dbca), SPH_C32(0x1c9e0000), + SPH_C32(0x66c30000), SPH_C32(0x0d110000), SPH_C32(0x5fdac000), + SPH_C32(0x32596759), SPH_C32(0x8cc0f80c), SPH_C32(0xaece29ff), + SPH_C32(0xc6afe775) }, + { SPH_C32(0xd23d0000), SPH_C32(0x27ff0000), SPH_C32(0xf8f20000), + SPH_C32(0x9393dae0), SPH_C32(0x9c481509), SPH_C32(0xc986ea75), + SPH_C32(0xdd5d800b), SPH_C32(0x081c935d), SPH_C32(0xec5b0000), + SPH_C32(0x3fe00000), SPH_C32(0x48930000), SPH_C32(0xbe57c0c0), + SPH_C32(0x09346168), SPH_C32(0x4e2dae95), SPH_C32(0x652ed7e3), + SPH_C32(0x900856ea) }, + { SPH_C32(0xc4d00000), SPH_C32(0x32970000), SPH_C32(0x15250000), + SPH_C32(0xa1ced8c0), SPH_C32(0x7f442380), SPH_C32(0x93cc0c36), + SPH_C32(0x3e2878a3), SPH_C32(0x89e16a55), SPH_C32(0x0a730000), + SPH_C32(0x73ab0000), SPH_C32(0xe0c60000), SPH_C32(0x6d87c220), + SPH_C32(0xd15551d0), SPH_C32(0xd68a1e4f), SPH_C32(0x4dbbd157), + SPH_C32(0x47521e7d) }, + { SPH_C32(0x22f80000), SPH_C32(0x7edc0000), SPH_C32(0xbd700000), + SPH_C32(0x721eda20), SPH_C32(0xa7251338), SPH_C32(0x0b6bbcec), + SPH_C32(0x16bd7e17), SPH_C32(0x5ebb22c2), SPH_C32(0xfab60000), + SPH_C32(0x2a880000), SPH_C32(0xa5440000), SPH_C32(0x8c0ac2e0), + SPH_C32(0xea3857e1), SPH_C32(0x146748d6), SPH_C32(0x865b2f4b), + SPH_C32(0x11f5afe2) }, + { SPH_C32(0x80240000), SPH_C32(0x1c870000), SPH_C32(0xe1fa0000), + SPH_C32(0x3f93dce0), SPH_C32(0x3c8b4489), SPH_C32(0x803799f2), + SPH_C32(0x279e5236), SPH_C32(0x9129af14), SPH_C32(0xff980000), + SPH_C32(0xdb020000), SPH_C32(0x8a020000), SPH_C32(0xe028c060), + SPH_C32(0x1ce36d43), SPH_C32(0x0175cf5d), SPH_C32(0xdd0b82f9), + SPH_C32(0x9d79f24c) }, + { SPH_C32(0x660c0000), SPH_C32(0x50cc0000), SPH_C32(0x49af0000), + SPH_C32(0xec43de00), SPH_C32(0xe4ea7431), SPH_C32(0x18902928), + SPH_C32(0x0f0b5482), SPH_C32(0x4673e783), SPH_C32(0x0f5d0000), + SPH_C32(0x82210000), SPH_C32(0xcf800000), SPH_C32(0x01a5c0a0), + SPH_C32(0x278e6b72), SPH_C32(0xc39899c4), SPH_C32(0x16eb7ce5), + SPH_C32(0xcbde43d3) }, + { SPH_C32(0x70e10000), SPH_C32(0x45a40000), SPH_C32(0xa4780000), + SPH_C32(0xde1edc20), SPH_C32(0x07e642b8), SPH_C32(0x42dacf6b), + SPH_C32(0xec7eac2a), SPH_C32(0xc78e1e8b), SPH_C32(0xe9750000), + SPH_C32(0xce6a0000), SPH_C32(0x67d50000), SPH_C32(0xd275c240), + SPH_C32(0xffef5bca), SPH_C32(0x5b3f291e), SPH_C32(0x3e7e7a51), + SPH_C32(0x1c840b44) }, + { SPH_C32(0x96c90000), SPH_C32(0x09ef0000), SPH_C32(0x0c2d0000), + SPH_C32(0x0dcedec0), SPH_C32(0xdf877200), SPH_C32(0xda7d7fb1), + SPH_C32(0xc4ebaa9e), SPH_C32(0x10d4561c), SPH_C32(0x19b00000), + SPH_C32(0x97490000), SPH_C32(0x22570000), SPH_C32(0x33f8c280), + SPH_C32(0xc4825dfb), SPH_C32(0x99d27f87), SPH_C32(0xf59e844d), + SPH_C32(0x4a23badb) }, + { SPH_C32(0xd7130000), SPH_C32(0xd6750000), SPH_C32(0xd7b40000), + SPH_C32(0xffb1d860), SPH_C32(0x6a932fab), SPH_C32(0xdc946dfe), + SPH_C32(0x860d2db9), SPH_C32(0x8490cef3), SPH_C32(0x4ba90000), + SPH_C32(0xac310000), SPH_C32(0x3b5f0000), SPH_C32(0x9ff8c480), + SPH_C32(0x64410c7b), SPH_C32(0xd0630c00), SPH_C32(0x0f5d5670), + SPH_C32(0xd3168692) }, + { SPH_C32(0x313b0000), SPH_C32(0x9a3e0000), SPH_C32(0x7fe10000), + SPH_C32(0x2c61da80), SPH_C32(0xb2f21f13), SPH_C32(0x4433dd24), + SPH_C32(0xae982b0d), SPH_C32(0x53ca8664), SPH_C32(0xbb6c0000), + SPH_C32(0xf5120000), SPH_C32(0x7edd0000), SPH_C32(0x7e75c440), + SPH_C32(0x5f2c0a4a), SPH_C32(0x128e5a99), SPH_C32(0xc4bda86c), + SPH_C32(0x85b1370d) }, + { SPH_C32(0x27d60000), SPH_C32(0x8f560000), SPH_C32(0x92360000), + SPH_C32(0x1e3cd8a0), SPH_C32(0x51fe299a), SPH_C32(0x1e793b67), + SPH_C32(0x4dedd3a5), SPH_C32(0xd2377f6c), SPH_C32(0x5d440000), + SPH_C32(0xb9590000), SPH_C32(0xd6880000), SPH_C32(0xada5c6a0), + SPH_C32(0x874d3af2), SPH_C32(0x8a29ea43), SPH_C32(0xec28aed8), + SPH_C32(0x52eb7f9a) }, + { SPH_C32(0xc1fe0000), SPH_C32(0xc31d0000), SPH_C32(0x3a630000), + SPH_C32(0xcdecda40), SPH_C32(0x899f1922), SPH_C32(0x86de8bbd), + SPH_C32(0x6578d511), SPH_C32(0x056d37fb), SPH_C32(0xad810000), + SPH_C32(0xe07a0000), SPH_C32(0x930a0000), SPH_C32(0x4c28c660), + SPH_C32(0xbc203cc3), SPH_C32(0x48c4bcda), SPH_C32(0x27c850c4), + SPH_C32(0x044cce05) }, + { SPH_C32(0x63220000), SPH_C32(0xa1460000), SPH_C32(0x66e90000), + SPH_C32(0x8061dc80), SPH_C32(0x12314e93), SPH_C32(0x0d82aea3), + SPH_C32(0x545bf930), SPH_C32(0xcaffba2d), SPH_C32(0xa8af0000), + SPH_C32(0x11f00000), SPH_C32(0xbc4c0000), SPH_C32(0x200ac4e0), + SPH_C32(0x4afb0661), SPH_C32(0x5dd63b51), SPH_C32(0x7c98fd76), + SPH_C32(0x88c093ab) }, + { SPH_C32(0x850a0000), SPH_C32(0xed0d0000), SPH_C32(0xcebc0000), + SPH_C32(0x53b1de60), SPH_C32(0xca507e2b), SPH_C32(0x95251e79), + SPH_C32(0x7cceff84), SPH_C32(0x1da5f2ba), SPH_C32(0x586a0000), + SPH_C32(0x48d30000), SPH_C32(0xf9ce0000), SPH_C32(0xc187c420), + SPH_C32(0x71960050), SPH_C32(0x9f3b6dc8), SPH_C32(0xb778036a), + SPH_C32(0xde672234) }, + { SPH_C32(0x93e70000), SPH_C32(0xf8650000), SPH_C32(0x236b0000), + SPH_C32(0x61ecdc40), SPH_C32(0x295c48a2), SPH_C32(0xcf6ff83a), + SPH_C32(0x9fbb072c), SPH_C32(0x9c580bb2), SPH_C32(0xbe420000), + SPH_C32(0x04980000), SPH_C32(0x519b0000), SPH_C32(0x1257c6c0), + SPH_C32(0xa9f730e8), SPH_C32(0x079cdd12), SPH_C32(0x9fed05de), + SPH_C32(0x093d6aa3) }, + { SPH_C32(0x75cf0000), SPH_C32(0xb42e0000), SPH_C32(0x8b3e0000), + SPH_C32(0xb23cdea0), SPH_C32(0xf13d781a), SPH_C32(0x57c848e0), + SPH_C32(0xb72e0198), SPH_C32(0x4b024325), SPH_C32(0x4e870000), + SPH_C32(0x5dbb0000), SPH_C32(0x14190000), SPH_C32(0xf3dac600), + SPH_C32(0x929a36d9), SPH_C32(0xc5718b8b), SPH_C32(0x540dfbc2), + SPH_C32(0x5f9adb3c) } +}; + +static const sph_u32 T512_56[256][16] = { + { SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000), SPH_C32(0x00000000), SPH_C32(0x00000000), + SPH_C32(0x00000000) }, + { SPH_C32(0x033d0000), SPH_C32(0x08b30000), SPH_C32(0xf33a0000), + SPH_C32(0x3ac20007), SPH_C32(0x51298a50), SPH_C32(0x6b6e661f), + SPH_C32(0x0ea5cfe3), SPH_C32(0xe6da7ffe), SPH_C32(0xa8da0000), + SPH_C32(0x96be0000), SPH_C32(0x5c1d0000), SPH_C32(0x07da0002), + SPH_C32(0x7d669583), SPH_C32(0x1f98708a), SPH_C32(0xbb668808), + SPH_C32(0xda878000) }, + { SPH_C32(0xa8da0000), SPH_C32(0x96be0000), SPH_C32(0x5c1d0000), + SPH_C32(0x07da0002), SPH_C32(0x7d669583), SPH_C32(0x1f98708a), + SPH_C32(0xbb668808), SPH_C32(0xda878000), SPH_C32(0xabe70000), + SPH_C32(0x9e0d0000), SPH_C32(0xaf270000), SPH_C32(0x3d180005), + SPH_C32(0x2c4f1fd3), SPH_C32(0x74f61695), SPH_C32(0xb5c347eb), + SPH_C32(0x3c5dfffe) }, + { SPH_C32(0xabe70000), SPH_C32(0x9e0d0000), SPH_C32(0xaf270000), + SPH_C32(0x3d180005), SPH_C32(0x2c4f1fd3), SPH_C32(0x74f61695), + SPH_C32(0xb5c347eb), SPH_C32(0x3c5dfffe), SPH_C32(0x033d0000), + SPH_C32(0x08b30000), SPH_C32(0xf33a0000), SPH_C32(0x3ac20007), + SPH_C32(0x51298a50), SPH_C32(0x6b6e661f), SPH_C32(0x0ea5cfe3), + SPH_C32(0xe6da7ffe) }, + { SPH_C32(0x01930000), SPH_C32(0xe7820000), SPH_C32(0xedfb0000), + SPH_C32(0xcf0c000b), SPH_C32(0x8dd08d58), SPH_C32(0xbca3b42e), + SPH_C32(0x063661e1), SPH_C32(0x536f9e7b), SPH_C32(0x92280000), + SPH_C32(0xdc850000), SPH_C32(0x57fa0000), SPH_C32(0x56dc0003), + SPH_C32(0xbae92316), SPH_C32(0x5aefa30c), SPH_C32(0x90cef752), + SPH_C32(0x7b1675d7) }, + { SPH_C32(0x02ae0000), SPH_C32(0xef310000), SPH_C32(0x1ec10000), + SPH_C32(0xf5ce000c), SPH_C32(0xdcf90708), SPH_C32(0xd7cdd231), + SPH_C32(0x0893ae02), SPH_C32(0xb5b5e185), SPH_C32(0x3af20000), + SPH_C32(0x4a3b0000), SPH_C32(0x0be70000), SPH_C32(0x51060001), + SPH_C32(0xc78fb695), SPH_C32(0x4577d386), SPH_C32(0x2ba87f5a), + SPH_C32(0xa191f5d7) }, + { SPH_C32(0xa9490000), SPH_C32(0x713c0000), SPH_C32(0xb1e60000), + SPH_C32(0xc8d60009), SPH_C32(0xf0b618db), SPH_C32(0xa33bc4a4), + SPH_C32(0xbd50e9e9), SPH_C32(0x89e81e7b), SPH_C32(0x39cf0000), + SPH_C32(0x42880000), SPH_C32(0xf8dd0000), SPH_C32(0x6bc40006), + SPH_C32(0x96a63cc5), SPH_C32(0x2e19b599), SPH_C32(0x250db0b9), + SPH_C32(0x474b8a29) }, + { SPH_C32(0xaa740000), SPH_C32(0x798f0000), SPH_C32(0x42dc0000), + SPH_C32(0xf214000e), SPH_C32(0xa19f928b), SPH_C32(0xc855a2bb), + SPH_C32(0xb3f5260a), SPH_C32(0x6f326185), SPH_C32(0x91150000), + SPH_C32(0xd4360000), SPH_C32(0xa4c00000), SPH_C32(0x6c1e0004), + SPH_C32(0xebc0a946), SPH_C32(0x3181c513), SPH_C32(0x9e6b38b1), + SPH_C32(0x9dcc0a29) }, + { SPH_C32(0x92280000), SPH_C32(0xdc850000), SPH_C32(0x57fa0000), + SPH_C32(0x56dc0003), SPH_C32(0xbae92316), SPH_C32(0x5aefa30c), + SPH_C32(0x90cef752), SPH_C32(0x7b1675d7), SPH_C32(0x93bb0000), + SPH_C32(0x3b070000), SPH_C32(0xba010000), SPH_C32(0x99d00008), + SPH_C32(0x3739ae4e), SPH_C32(0xe64c1722), SPH_C32(0x96f896b3), + SPH_C32(0x2879ebac) }, + { SPH_C32(0x91150000), SPH_C32(0xd4360000), SPH_C32(0xa4c00000), + SPH_C32(0x6c1e0004), SPH_C32(0xebc0a946), SPH_C32(0x3181c513), + SPH_C32(0x9e6b38b1), SPH_C32(0x9dcc0a29), SPH_C32(0x3b610000), + SPH_C32(0xadb90000), SPH_C32(0xe61c0000), SPH_C32(0x9e0a000a), + SPH_C32(0x4a5f3bcd), SPH_C32(0xf9d467a8), SPH_C32(0x2d9e1ebb), + SPH_C32(0xf2fe6bac) }, + { SPH_C32(0x3af20000), SPH_C32(0x4a3b0000), SPH_C32(0x0be70000), + SPH_C32(0x51060001), SPH_C32(0xc78fb695), SPH_C32(0x4577d386), + SPH_C32(0x2ba87f5a), SPH_C32(0xa191f5d7), SPH_C32(0x385c0000), + SPH_C32(0xa50a0000), SPH_C32(0x15260000), SPH_C32(0xa4c8000d), + SPH_C32(0x1b76b19d), SPH_C32(0x92ba01b7), SPH_C32(0x233bd158), + SPH_C32(0x14241452) }, + { SPH_C32(0x39cf0000), SPH_C32(0x42880000), SPH_C32(0xf8dd0000), + SPH_C32(0x6bc40006), SPH_C32(0x96a63cc5), SPH_C32(0x2e19b599), + SPH_C32(0x250db0b9), SPH_C32(0x474b8a29), SPH_C32(0x90860000), + SPH_C32(0x33b40000), SPH_C32(0x493b0000), SPH_C32(0xa312000f), + SPH_C32(0x6610241e), SPH_C32(0x8d22713d), SPH_C32(0x985d5950), + SPH_C32(0xcea39452) }, + { SPH_C32(0x93bb0000), SPH_C32(0x3b070000), SPH_C32(0xba010000), + SPH_C32(0x99d00008), SPH_C32(0x3739ae4e), SPH_C32(0xe64c1722), + SPH_C32(0x96f896b3), SPH_C32(0x2879ebac), SPH_C32(0x01930000), + SPH_C32(0xe7820000), SPH_C32(0xedfb0000), SPH_C32(0xcf0c000b), + SPH_C32(0x8dd08d58), SPH_C32(0xbca3b42e), SPH_C32(0x063661e1), + SPH_C32(0x536f9e7b) }, + { SPH_C32(0x90860000), SPH_C32(0x33b40000), SPH_C32(0x493b0000), + SPH_C32(0xa312000f), SPH_C32(0x6610241e), SPH_C32(0x8d22713d), + SPH_C32(0x985d5950), SPH_C32(0xcea39452), SPH_C32(0xa9490000), + SPH_C32(0x713c0000), SPH_C32(0xb1e60000), SPH_C32(0xc8d60009), + SPH_C32(0xf0b618db), SPH_C32(0xa33bc4a4), SPH_C32(0xbd50e9e9), + SPH_C32(0x89e81e7b) }, + { SPH_C32(0x3b610000), SPH_C32(0xadb90000), SPH_C32(0xe61c0000), + SPH_C32(0x9e0a000a), SPH_C32(0x4a5f3bcd), SPH_C32(0xf9d467a8), + SPH_C32(0x2d9e1ebb), SPH_C32(0xf2fe6bac), SPH_C32(0xaa740000), + SPH_C32(0x798f0000), SPH_C32(0x42dc0000), SPH_C32(0xf214000e), + SPH_C32(0xa19f928b), SPH_C32(0xc855a2bb), SPH_C32(0xb3f5260a), + SPH_C32(0x6f326185) }, + { SPH_C32(0x385c0000), SPH_C32(0xa50a0000), SPH_C32(0x15260000), + SPH_C32(0xa4c8000d), SPH_C32(0x1b76b19d), SPH_C32(0x92ba01b7), + SPH_C32(0x233bd158), SPH_C32(0x14241452), SPH_C32(0x02ae0000), + SPH_C32(0xef310000), SPH_C32(0x1ec10000), SPH_C32(0xf5ce000c), + SPH_C32(0xdcf90708), SPH_C32(0xd7cdd231), SPH_C32(0x0893ae02), + SPH_C32(0xb5b5e185) }, + { SPH_C32(0x5fa80000), SPH_C32(0x56030000), SPH_C32(0x43ae0000), + SPH_C32(0x64f30013), SPH_C32(0x257e86bf), SPH_C32(0x1311944e), + SPH_C32(0x541e95bf), SPH_C32(0x8ea4db69), SPH_C32(0x00440000), + SPH_C32(0x7f480000), SPH_C32(0xda7c0000), SPH_C32(0x2a230001), + SPH_C32(0x3badc9cc), SPH_C32(0xa9b69c87), SPH_C32(0x030a9e60), + SPH_C32(0xbe0a679e) }, + { SPH_C32(0x5c950000), SPH_C32(0x5eb00000), SPH_C32(0xb0940000), + SPH_C32(0x5e310014), SPH_C32(0x74570cef), SPH_C32(0x787ff251), + SPH_C32(0x5abb5a5c), SPH_C32(0x687ea497), SPH_C32(0xa89e0000), + SPH_C32(0xe9f60000), SPH_C32(0x86610000), SPH_C32(0x2df90003), + SPH_C32(0x46cb5c4f), SPH_C32(0xb62eec0d), SPH_C32(0xb86c1668), + SPH_C32(0x648de79e) }, + { SPH_C32(0xf7720000), SPH_C32(0xc0bd0000), SPH_C32(0x1fb30000), + SPH_C32(0x63290011), SPH_C32(0x5818133c), SPH_C32(0x0c89e4c4), + SPH_C32(0xef781db7), SPH_C32(0x54235b69), SPH_C32(0xaba30000), + SPH_C32(0xe1450000), SPH_C32(0x755b0000), SPH_C32(0x173b0004), + SPH_C32(0x17e2d61f), SPH_C32(0xdd408a12), SPH_C32(0xb6c9d98b), + SPH_C32(0x82579860) }, + { SPH_C32(0xf44f0000), SPH_C32(0xc80e0000), SPH_C32(0xec890000), + SPH_C32(0x59eb0016), SPH_C32(0x0931996c), SPH_C32(0x67e782db), + SPH_C32(0xe1ddd254), SPH_C32(0xb2f92497), SPH_C32(0x03790000), + SPH_C32(0x77fb0000), SPH_C32(0x29460000), SPH_C32(0x10e10006), + SPH_C32(0x6a84439c), SPH_C32(0xc2d8fa98), SPH_C32(0x0daf5183), + SPH_C32(0x58d01860) }, + { SPH_C32(0x5e3b0000), SPH_C32(0xb1810000), SPH_C32(0xae550000), + SPH_C32(0xabff0018), SPH_C32(0xa8ae0be7), SPH_C32(0xafb22060), + SPH_C32(0x5228f45e), SPH_C32(0xddcb4512), SPH_C32(0x926c0000), + SPH_C32(0xa3cd0000), SPH_C32(0x8d860000), SPH_C32(0x7cff0002), + SPH_C32(0x8144eada), SPH_C32(0xf3593f8b), SPH_C32(0x93c46932), + SPH_C32(0xc51c1249) }, + { SPH_C32(0x5d060000), SPH_C32(0xb9320000), SPH_C32(0x5d6f0000), + SPH_C32(0x913d001f), SPH_C32(0xf98781b7), SPH_C32(0xc4dc467f), + SPH_C32(0x5c8d3bbd), SPH_C32(0x3b113aec), SPH_C32(0x3ab60000), + SPH_C32(0x35730000), SPH_C32(0xd19b0000), SPH_C32(0x7b250000), + SPH_C32(0xfc227f59), SPH_C32(0xecc14f01), SPH_C32(0x28a2e13a), + SPH_C32(0x1f9b9249) }, + { SPH_C32(0xf6e10000), SPH_C32(0x273f0000), SPH_C32(0xf2480000), + SPH_C32(0xac25001a), SPH_C32(0xd5c89e64), SPH_C32(0xb02a50ea), + SPH_C32(0xe94e7c56), SPH_C32(0x074cc512), SPH_C32(0x398b0000), + SPH_C32(0x3dc00000), SPH_C32(0x22a10000), SPH_C32(0x41e70007), + SPH_C32(0xad0bf509), SPH_C32(0x87af291e), SPH_C32(0x26072ed9), + SPH_C32(0xf941edb7) }, + { SPH_C32(0xf5dc0000), SPH_C32(0x2f8c0000), SPH_C32(0x01720000), + SPH_C32(0x96e7001d), SPH_C32(0x84e11434), SPH_C32(0xdb4436f5), + SPH_C32(0xe7ebb3b5), SPH_C32(0xe196baec), SPH_C32(0x91510000), + SPH_C32(0xab7e0000), SPH_C32(0x7ebc0000), SPH_C32(0x463d0005), + SPH_C32(0xd06d608a), SPH_C32(0x98375994), SPH_C32(0x9d61a6d1), + SPH_C32(0x23c66db7) }, + { SPH_C32(0xcd800000), SPH_C32(0x8a860000), SPH_C32(0x14540000), + SPH_C32(0x322f0010), SPH_C32(0x9f97a5a9), SPH_C32(0x49fe3742), + SPH_C32(0xc4d062ed), SPH_C32(0xf5b2aebe), SPH_C32(0x93ff0000), + SPH_C32(0x444f0000), SPH_C32(0x607d0000), SPH_C32(0xb3f30009), + SPH_C32(0x0c946782), SPH_C32(0x4ffa8ba5), SPH_C32(0x95f208d3), + SPH_C32(0x96738c32) }, + { SPH_C32(0xcebd0000), SPH_C32(0x82350000), SPH_C32(0xe76e0000), + SPH_C32(0x08ed0017), SPH_C32(0xcebe2ff9), SPH_C32(0x2290515d), + SPH_C32(0xca75ad0e), SPH_C32(0x1368d140), SPH_C32(0x3b250000), + SPH_C32(0xd2f10000), SPH_C32(0x3c600000), SPH_C32(0xb429000b), + SPH_C32(0x71f2f201), SPH_C32(0x5062fb2f), SPH_C32(0x2e9480db), + SPH_C32(0x4cf40c32) }, + { SPH_C32(0x655a0000), SPH_C32(0x1c380000), SPH_C32(0x48490000), + SPH_C32(0x35f50012), SPH_C32(0xe2f1302a), SPH_C32(0x566647c8), + SPH_C32(0x7fb6eae5), SPH_C32(0x2f352ebe), SPH_C32(0x38180000), + SPH_C32(0xda420000), SPH_C32(0xcf5a0000), SPH_C32(0x8eeb000c), + SPH_C32(0x20db7851), SPH_C32(0x3b0c9d30), SPH_C32(0x20314f38), + SPH_C32(0xaa2e73cc) }, + { SPH_C32(0x66670000), SPH_C32(0x148b0000), SPH_C32(0xbb730000), + SPH_C32(0x0f370015), SPH_C32(0xb3d8ba7a), SPH_C32(0x3d0821d7), + SPH_C32(0x71132506), SPH_C32(0xc9ef5140), SPH_C32(0x90c20000), + SPH_C32(0x4cfc0000), SPH_C32(0x93470000), SPH_C32(0x8931000e), + SPH_C32(0x5dbdedd2), SPH_C32(0x2494edba), SPH_C32(0x9b57c730), + SPH_C32(0x70a9f3cc) }, + { SPH_C32(0xcc130000), SPH_C32(0x6d040000), SPH_C32(0xf9af0000), + SPH_C32(0xfd23001b), SPH_C32(0x124728f1), SPH_C32(0xf55d836c), + SPH_C32(0xc2e6030c), SPH_C32(0xa6dd30c5), SPH_C32(0x01d70000), + SPH_C32(0x98ca0000), SPH_C32(0x37870000), SPH_C32(0xe52f000a), + SPH_C32(0xb67d4494), SPH_C32(0x151528a9), SPH_C32(0x053cff81), + SPH_C32(0xed65f9e5) }, + { SPH_C32(0xcf2e0000), SPH_C32(0x65b70000), SPH_C32(0x0a950000), + SPH_C32(0xc7e1001c), SPH_C32(0x436ea2a1), SPH_C32(0x9e33e573), + SPH_C32(0xcc43ccef), SPH_C32(0x40074f3b), SPH_C32(0xa90d0000), + SPH_C32(0x0e740000), SPH_C32(0x6b9a0000), SPH_C32(0xe2f50008), + SPH_C32(0xcb1bd117), SPH_C32(0x0a8d5823), SPH_C32(0xbe5a7789), + SPH_C32(0x37e279e5) }, + { SPH_C32(0x64c90000), SPH_C32(0xfbba0000), SPH_C32(0xa5b20000), + SPH_C32(0xfaf90019), SPH_C32(0x6f21bd72), SPH_C32(0xeac5f3e6), + SPH_C32(0x79808b04), SPH_C32(0x7c5ab0c5), SPH_C32(0xaa300000), + SPH_C32(0x06c70000), SPH_C32(0x98a00000), SPH_C32(0xd837000f), + SPH_C32(0x9a325b47), SPH_C32(0x61e33e3c), SPH_C32(0xb0ffb86a), + SPH_C32(0xd138061b) }, + { SPH_C32(0x67f40000), SPH_C32(0xf3090000), SPH_C32(0x56880000), + SPH_C32(0xc03b001e), SPH_C32(0x3e083722), SPH_C32(0x81ab95f9), + SPH_C32(0x772544e7), SPH_C32(0x9a80cf3b), SPH_C32(0x02ea0000), + SPH_C32(0x90790000), SPH_C32(0xc4bd0000), SPH_C32(0xdfed000d), + SPH_C32(0xe754cec4), SPH_C32(0x7e7b4eb6), SPH_C32(0x0b993062), + SPH_C32(0x0bbf861b) }, + { SPH_C32(0x00440000), SPH_C32(0x7f480000), SPH_C32(0xda7c0000), + SPH_C32(0x2a230001), SPH_C32(0x3badc9cc), SPH_C32(0xa9b69c87), + SPH_C32(0x030a9e60), SPH_C32(0xbe0a679e), SPH_C32(0x5fec0000), + SPH_C32(0x294b0000), SPH_C32(0x99d20000), SPH_C32(0x4ed00012), + SPH_C32(0x1ed34f73), SPH_C32(0xbaa708c9), SPH_C32(0x57140bdf), + SPH_C32(0x30aebcf7) }, + { SPH_C32(0x03790000), SPH_C32(0x77fb0000), SPH_C32(0x29460000), + SPH_C32(0x10e10006), SPH_C32(0x6a84439c), SPH_C32(0xc2d8fa98), + SPH_C32(0x0daf5183), SPH_C32(0x58d01860), SPH_C32(0xf7360000), + SPH_C32(0xbff50000), SPH_C32(0xc5cf0000), SPH_C32(0x490a0010), + SPH_C32(0x63b5daf0), SPH_C32(0xa53f7843), SPH_C32(0xec7283d7), + SPH_C32(0xea293cf7) }, + { SPH_C32(0xa89e0000), SPH_C32(0xe9f60000), SPH_C32(0x86610000), + SPH_C32(0x2df90003), SPH_C32(0x46cb5c4f), SPH_C32(0xb62eec0d), + SPH_C32(0xb86c1668), SPH_C32(0x648de79e), SPH_C32(0xf40b0000), + SPH_C32(0xb7460000), SPH_C32(0x36f50000), SPH_C32(0x73c80017), + SPH_C32(0x329c50a0), SPH_C32(0xce511e5c), SPH_C32(0xe2d74c34), + SPH_C32(0x0cf34309) }, + { SPH_C32(0xaba30000), SPH_C32(0xe1450000), SPH_C32(0x755b0000), + SPH_C32(0x173b0004), SPH_C32(0x17e2d61f), SPH_C32(0xdd408a12), + SPH_C32(0xb6c9d98b), SPH_C32(0x82579860), SPH_C32(0x5cd10000), + SPH_C32(0x21f80000), SPH_C32(0x6ae80000), SPH_C32(0x74120015), + SPH_C32(0x4ffac523), SPH_C32(0xd1c96ed6), SPH_C32(0x59b1c43c), + SPH_C32(0xd674c309) }, + { SPH_C32(0x01d70000), SPH_C32(0x98ca0000), SPH_C32(0x37870000), + SPH_C32(0xe52f000a), SPH_C32(0xb67d4494), SPH_C32(0x151528a9), + SPH_C32(0x053cff81), SPH_C32(0xed65f9e5), SPH_C32(0xcdc40000), + SPH_C32(0xf5ce0000), SPH_C32(0xce280000), SPH_C32(0x180c0011), + SPH_C32(0xa43a6c65), SPH_C32(0xe048abc5), SPH_C32(0xc7dafc8d), + SPH_C32(0x4bb8c920) }, + { SPH_C32(0x02ea0000), SPH_C32(0x90790000), SPH_C32(0xc4bd0000), + SPH_C32(0xdfed000d), SPH_C32(0xe754cec4), SPH_C32(0x7e7b4eb6), + SPH_C32(0x0b993062), SPH_C32(0x0bbf861b), SPH_C32(0x651e0000), + SPH_C32(0x63700000), SPH_C32(0x92350000), SPH_C32(0x1fd60013), + SPH_C32(0xd95cf9e6), SPH_C32(0xffd0db4f), SPH_C32(0x7cbc7485), + SPH_C32(0x913f4920) }, + { SPH_C32(0xa90d0000), SPH_C32(0x0e740000), SPH_C32(0x6b9a0000), + SPH_C32(0xe2f50008), SPH_C32(0xcb1bd117), SPH_C32(0x0a8d5823), + SPH_C32(0xbe5a7789), SPH_C32(0x37e279e5), SPH_C32(0x66230000), + SPH_C32(0x6bc30000), SPH_C32(0x610f0000), SPH_C32(0x25140014), + SPH_C32(0x887573b6), SPH_C32(0x94bebd50), SPH_C32(0x7219bb66), + SPH_C32(0x77e536de) }, + { SPH_C32(0xaa300000), SPH_C32(0x06c70000), SPH_C32(0x98a00000), + SPH_C32(0xd837000f), SPH_C32(0x9a325b47), SPH_C32(0x61e33e3c), + SPH_C32(0xb0ffb86a), SPH_C32(0xd138061b), SPH_C32(0xcef90000), + SPH_C32(0xfd7d0000), SPH_C32(0x3d120000), SPH_C32(0x22ce0016), + SPH_C32(0xf513e635), SPH_C32(0x8b26cdda), SPH_C32(0xc97f336e), + SPH_C32(0xad62b6de) }, + { SPH_C32(0x926c0000), SPH_C32(0xa3cd0000), SPH_C32(0x8d860000), + SPH_C32(0x7cff0002), SPH_C32(0x8144eada), SPH_C32(0xf3593f8b), + SPH_C32(0x93c46932), SPH_C32(0xc51c1249), SPH_C32(0xcc570000), + SPH_C32(0x124c0000), SPH_C32(0x23d30000), SPH_C32(0xd700001a), + SPH_C32(0x29eae13d), SPH_C32(0x5ceb1feb), SPH_C32(0xc1ec9d6c), + SPH_C32(0x18d7575b) }, + { SPH_C32(0x91510000), SPH_C32(0xab7e0000), SPH_C32(0x7ebc0000), + SPH_C32(0x463d0005), SPH_C32(0xd06d608a), SPH_C32(0x98375994), + SPH_C32(0x9d61a6d1), SPH_C32(0x23c66db7), SPH_C32(0x648d0000), + SPH_C32(0x84f20000), SPH_C32(0x7fce0000), SPH_C32(0xd0da0018), + SPH_C32(0x548c74be), SPH_C32(0x43736f61), SPH_C32(0x7a8a1564), + SPH_C32(0xc250d75b) }, + { SPH_C32(0x3ab60000), SPH_C32(0x35730000), SPH_C32(0xd19b0000), + SPH_C32(0x7b250000), SPH_C32(0xfc227f59), SPH_C32(0xecc14f01), + SPH_C32(0x28a2e13a), SPH_C32(0x1f9b9249), SPH_C32(0x67b00000), + SPH_C32(0x8c410000), SPH_C32(0x8cf40000), SPH_C32(0xea18001f), + SPH_C32(0x05a5feee), SPH_C32(0x281d097e), SPH_C32(0x742fda87), + SPH_C32(0x248aa8a5) }, + { SPH_C32(0x398b0000), SPH_C32(0x3dc00000), SPH_C32(0x22a10000), + SPH_C32(0x41e70007), SPH_C32(0xad0bf509), SPH_C32(0x87af291e), + SPH_C32(0x26072ed9), SPH_C32(0xf941edb7), SPH_C32(0xcf6a0000), + SPH_C32(0x1aff0000), SPH_C32(0xd0e90000), SPH_C32(0xedc2001d), + SPH_C32(0x78c36b6d), SPH_C32(0x378579f4), SPH_C32(0xcf49528f), + SPH_C32(0xfe0d28a5) }, + { SPH_C32(0x93ff0000), SPH_C32(0x444f0000), SPH_C32(0x607d0000), + SPH_C32(0xb3f30009), SPH_C32(0x0c946782), SPH_C32(0x4ffa8ba5), + SPH_C32(0x95f208d3), SPH_C32(0x96738c32), SPH_C32(0x5e7f0000), + SPH_C32(0xcec90000), SPH_C32(0x74290000), SPH_C32(0x81dc0019), + SPH_C32(0x9303c22b), SPH_C32(0x0604bce7), SPH_C32(0x51226a3e), + SPH_C32(0x63c1228c) }, + { SPH_C32(0x90c20000), SPH_C32(0x4cfc0000), SPH_C32(0x93470000), + SPH_C32(0x8931000e), SPH_C32(0x5dbdedd2), SPH_C32(0x2494edba), + SPH_C32(0x9b57c730), SPH_C32(0x70a9f3cc), SPH_C32(0xf6a50000), + SPH_C32(0x58770000), SPH_C32(0x28340000), SPH_C32(0x8606001b), + SPH_C32(0xee6557a8), SPH_C32(0x199ccc6d), SPH_C32(0xea44e236), + SPH_C32(0xb946a28c) }, + { SPH_C32(0x3b250000), SPH_C32(0xd2f10000), SPH_C32(0x3c600000), + SPH_C32(0xb429000b), SPH_C32(0x71f2f201), SPH_C32(0x5062fb2f), + SPH_C32(0x2e9480db), SPH_C32(0x4cf40c32), SPH_C32(0xf5980000), + SPH_C32(0x50c40000), SPH_C32(0xdb0e0000), SPH_C32(0xbcc4001c), + SPH_C32(0xbf4cddf8), SPH_C32(0x72f2aa72), SPH_C32(0xe4e12dd5), + SPH_C32(0x5f9cdd72) }, + { SPH_C32(0x38180000), SPH_C32(0xda420000), SPH_C32(0xcf5a0000), + SPH_C32(0x8eeb000c), SPH_C32(0x20db7851), SPH_C32(0x3b0c9d30), + SPH_C32(0x20314f38), SPH_C32(0xaa2e73cc), SPH_C32(0x5d420000), + SPH_C32(0xc67a0000), SPH_C32(0x87130000), SPH_C32(0xbb1e001e), + SPH_C32(0xc22a487b), SPH_C32(0x6d6adaf8), SPH_C32(0x5f87a5dd), + SPH_C32(0x851b5d72) }, + { SPH_C32(0x5fec0000), SPH_C32(0x294b0000), SPH_C32(0x99d20000), + SPH_C32(0x4ed00012), SPH_C32(0x1ed34f73), SPH_C32(0xbaa708c9), + SPH_C32(0x57140bdf), SPH_C32(0x30aebcf7), SPH_C32(0x5fa80000), + SPH_C32(0x56030000), SPH_C32(0x43ae0000), SPH_C32(0x64f30013), + SPH_C32(0x257e86bf), SPH_C32(0x1311944e), SPH_C32(0x541e95bf), + SPH_C32(0x8ea4db69) }, + { SPH_C32(0x5cd10000), SPH_C32(0x21f80000), SPH_C32(0x6ae80000), + SPH_C32(0x74120015), SPH_C32(0x4ffac523), SPH_C32(0xd1c96ed6), + SPH_C32(0x59b1c43c), SPH_C32(0xd674c309), SPH_C32(0xf7720000), + SPH_C32(0xc0bd0000), SPH_C32(0x1fb30000), SPH_C32(0x63290011), + SPH_C32(0x5818133c), SPH_C32(0x0c89e4c4), SPH_C32(0xef781db7), + SPH_C32(0x54235b69) }, + { SPH_C32(0xf7360000), SPH_C32(0xbff50000), SPH_C32(0xc5cf0000), + SPH_C32(0x490a0010), SPH_C32(0x63b5daf0), SPH_C32(0xa53f7843), + SPH_C32(0xec7283d7), SPH_C32(0xea293cf7), SPH_C32(0xf44f0000), + SPH_C32(0xc80e0000), SPH_C32(0xec890000), SPH_C32(0x59eb0016), + SPH_C32(0x0931996c), SPH_C32(0x67e782db), SPH_C32(0xe1ddd254), + SPH_C32(0xb2f92497) }, + { SPH_C32(0xf40b0000), SPH_C32(0xb7460000), SPH_C32(0x36f50000), + SPH_C32(0x73c80017), SPH_C32(0x329c50a0), SPH_C32(0xce511e5c), + SPH_C32(0xe2d74c34), SPH_C32(0x0cf34309), SPH_C32(0x5c950000), + SPH_C32(0x5eb00000), SPH_C32(0xb0940000), SPH_C32(0x5e310014), + SPH_C32(0x74570cef), SPH_C32(0x787ff251), SPH_C32(0x5abb5a5c), + SPH_C32(0x687ea497) }, + { SPH_C32(0x5e7f0000), SPH_C32(0xcec90000), SPH_C32(0x74290000), + SPH_C32(0x81dc0019), SPH_C32(0x9303c22b), SPH_C32(0x0604bce7), + SPH_C32(0x51226a3e), SPH_C32(0x63c1228c), SPH_C32(0xcd800000), + SPH_C32(0x8a860000), SPH_C32(0x14540000), SPH_C32(0x322f0010), + SPH_C32(0x9f97a5a9), SPH_C32(0x49fe3742), SPH_C32(0xc4d062ed), + SPH_C32(0xf5b2aebe) }, + { SPH_C32(0x5d420000), SPH_C32(0xc67a0000), SPH_C32(0x87130000), + SPH_C32(0xbb1e001e), SPH_C32(0xc22a487b), SPH_C32(0x6d6adaf8), + SPH_C32(0x5f87a5dd), SPH_C32(0x851b5d72), SPH_C32(0x655a0000), + SPH_C32(0x1c380000), SPH_C32(0x48490000), SPH_C32(0x35f50012), + SPH_C32(0xe2f1302a), SPH_C32(0x566647c8), SPH_C32(0x7fb6eae5), + SPH_C32(0x2f352ebe) }, + { SPH_C32(0xf6a50000), SPH_C32(0x58770000), SPH_C32(0x28340000), + SPH_C32(0x8606001b), SPH_C32(0xee6557a8), SPH_C32(0x199ccc6d), + SPH_C32(0xea44e236), SPH_C32(0xb946a28c), SPH_C32(0x66670000), + SPH_C32(0x148b0000), SPH_C32(0xbb730000), SPH_C32(0x0f370015), + SPH_C32(0xb3d8ba7a), SPH_C32(0x3d0821d7), SPH_C32(0x71132506), + SPH_C32(0xc9ef5140) }, + { SPH_C32(0xf5980000), SPH_C32(0x50c40000), SPH_C32(0xdb0e0000), + SPH_C32(0xbcc4001c), SPH_C32(0xbf4cddf8), SPH_C32(0x72f2aa72), + SPH_C32(0xe4e12dd5), SPH_C32(0x5f9cdd72), SPH_C32(0xcebd0000), + SPH_C32(0x82350000), SPH_C32(0xe76e0000), SPH_C32(0x08ed0017), + SPH_C32(0xcebe2ff9), SPH_C32(0x2290515d), SPH_C32(0xca75ad0e), + SPH_C32(0x1368d140) }, + { SPH_C32(0xcdc40000), SPH_C32(0xf5ce0000), SPH_C32(0xce280000), + SPH_C32(0x180c0011), SPH_C32(0xa43a6c65), SPH_C32(0xe048abc5), + SPH_C32(0xc7dafc8d), SPH_C32(0x4bb8c920), SPH_C32(0xcc130000), + SPH_C32(0x6d040000), SPH_C32(0xf9af0000), SPH_C32(0xfd23001b), + SPH_C32(0x124728f1), SPH_C32(0xf55d836c), SPH_C32(0xc2e6030c), + SPH_C32(0xa6dd30c5) }, + { SPH_C32(0xcef90000), SPH_C32(0xfd7d0000), SPH_C32(0x3d120000), + SPH_C32(0x22ce0016), SPH_C32(0xf513e635), SPH_C32(0x8b26cdda), + SPH_C32(0xc97f336e), SPH_C32(0xad62b6de), SPH_C32(0x64c90000), + SPH_C32(0xfbba0000), SPH_C32(0xa5b20000), SPH_C32(0xfaf90019), + SPH_C32(0x6f21bd72), SPH_C32(0xeac5f3e6), SPH_C32(0x79808b04), + SPH_C32(0x7c5ab0c5) }, + { SPH_C32(0x651e0000), SPH_C32(0x63700000), SPH_C32(0x92350000), + SPH_C32(0x1fd60013), SPH_C32(0xd95cf9e6), SPH_C32(0xffd0db4f), + SPH_C32(0x7cbc7485), SPH_C32(0x913f4920), SPH_C32(0x67f40000), + SPH_C32(0xf3090000), SPH_C32(0x56880000), SPH_C32(0xc03b001e), + SPH_C32(0x3e083722), SPH_C32(0x81ab95f9), SPH_C32(0x772544e7), + SPH_C32(0x9a80cf3b) }, + { SPH_C32(0x66230000), SPH_C32(0x6bc30000), SPH_C32(0x610f0000), + SPH_C32(0x25140014), SPH_C32(0x887573b6), SPH_C32(0x94bebd50), + SPH_C32(0x7219bb66), SPH_C32(0x77e536de), SPH_C32(0xcf2e0000), + SPH_C32(0x65b70000), SPH_C32(0x0a950000), SPH_C32(0xc7e1001c), + SPH_C32(0x436ea2a1), SPH_C32(0x9e33e573), SPH_C32(0xcc43ccef), + SPH_C32(0x40074f3b) }, + { SPH_C32(0xcc570000), SPH_C32(0x124c0000), SPH_C32(0x23d30000), + SPH_C32(0xd700001a), SPH_C32(0x29eae13d), SPH_C32(0x5ceb1feb), + SPH_C32(0xc1ec9d6c), SPH_C32(0x18d7575b), SPH_C32(0x5e3b0000), + SPH_C32(0xb1810000), SPH_C32(0xae550000), SPH_C32(0xabff0018), + SPH_C32(0xa8ae0be7), SPH_C32(0xafb22060), SPH_C32(0x5228f45e), + SPH_C32(0xddcb4512) }, + { SPH_C32(0xcf6a0000), SPH_C32(0x1aff0000), SPH_C32(0xd0e90000), + SPH_C32(0xedc2001d), SPH_C32(0x78c36b6d), SPH_C32(0x378579f4), + SPH_C32(0xcf49528f), SPH_C32(0xfe0d28a5), SPH_C32(0xf6e10000), + SPH_C32(0x273f0000), SPH_C32(0xf2480000), SPH_C32(0xac25001a), + SPH_C32(0xd5c89e64), SPH_C32(0xb02a50ea), SPH_C32(0xe94e7c56), + SPH_C32(0x074cc512) }, + { SPH_C32(0x648d0000), SPH_C32(0x84f20000), SPH_C32(0x7fce0000), + SPH_C32(0xd0da0018), SPH_C32(0x548c74be), SPH_C32(0x43736f61), + SPH_C32(0x7a8a1564), SPH_C32(0xc250d75b), SPH_C32(0xf5dc0000), + SPH_C32(0x2f8c0000), SPH_C32(0x01720000), SPH_C32(0x96e7001d), + SPH_C32(0x84e11434), SPH_C32(0xdb4436f5), SPH_C32(0xe7ebb3b5), + SPH_C32(0xe196baec) }, + { SPH_C32(0x67b00000), SPH_C32(0x8c410000), SPH_C32(0x8cf40000), + SPH_C32(0xea18001f), SPH_C32(0x05a5feee), SPH_C32(0x281d097e), + SPH_C32(0x742fda87), SPH_C32(0x248aa8a5), SPH_C32(0x5d060000), + SPH_C32(0xb9320000), SPH_C32(0x5d6f0000), SPH_C32(0x913d001f), + SPH_C32(0xf98781b7), SPH_C32(0xc4dc467f), SPH_C32(0x5c8d3bbd), + SPH_C32(0x3b113aec) }, + { SPH_C32(0xee930000), SPH_C32(0xd6070000), SPH_C32(0x92c10000), + SPH_C32(0x2b9801e0), SPH_C32(0x9451287c), SPH_C32(0x3b6cfb57), + SPH_C32(0x45312374), SPH_C32(0x201f6a64), SPH_C32(0x7b280000), + SPH_C32(0x57420000), SPH_C32(0xa9e50000), SPH_C32(0x634300a0), + SPH_C32(0x9edb442f), SPH_C32(0x6d9995bb), SPH_C32(0x27f83b03), + SPH_C32(0xc7ff60f0) }, + { SPH_C32(0xedae0000), SPH_C32(0xdeb40000), SPH_C32(0x61fb0000), + SPH_C32(0x115a01e7), SPH_C32(0xc578a22c), SPH_C32(0x50029d48), + SPH_C32(0x4b94ec97), SPH_C32(0xc6c5159a), SPH_C32(0xd3f20000), + SPH_C32(0xc1fc0000), SPH_C32(0xf5f80000), SPH_C32(0x649900a2), + SPH_C32(0xe3bdd1ac), SPH_C32(0x7201e531), SPH_C32(0x9c9eb30b), + SPH_C32(0x1d78e0f0) }, + { SPH_C32(0x46490000), SPH_C32(0x40b90000), SPH_C32(0xcedc0000), + SPH_C32(0x2c4201e2), SPH_C32(0xe937bdff), SPH_C32(0x24f48bdd), + SPH_C32(0xfe57ab7c), SPH_C32(0xfa98ea64), SPH_C32(0xd0cf0000), + SPH_C32(0xc94f0000), SPH_C32(0x06c20000), SPH_C32(0x5e5b00a5), + SPH_C32(0xb2945bfc), SPH_C32(0x196f832e), SPH_C32(0x923b7ce8), + SPH_C32(0xfba29f0e) }, + { SPH_C32(0x45740000), SPH_C32(0x480a0000), SPH_C32(0x3de60000), + SPH_C32(0x168001e5), SPH_C32(0xb81e37af), SPH_C32(0x4f9aedc2), + SPH_C32(0xf0f2649f), SPH_C32(0x1c42959a), SPH_C32(0x78150000), + SPH_C32(0x5ff10000), SPH_C32(0x5adf0000), SPH_C32(0x598100a7), + SPH_C32(0xcff2ce7f), SPH_C32(0x06f7f3a4), SPH_C32(0x295df4e0), + SPH_C32(0x21251f0e) }, + { SPH_C32(0xef000000), SPH_C32(0x31850000), SPH_C32(0x7f3a0000), + SPH_C32(0xe49401eb), SPH_C32(0x1981a524), SPH_C32(0x87cf4f79), + SPH_C32(0x43074295), SPH_C32(0x7370f41f), SPH_C32(0xe9000000), + SPH_C32(0x8bc70000), SPH_C32(0xfe1f0000), SPH_C32(0x359f00a3), + SPH_C32(0x24326739), SPH_C32(0x377636b7), SPH_C32(0xb736cc51), + SPH_C32(0xbce91527) }, + { SPH_C32(0xec3d0000), SPH_C32(0x39360000), SPH_C32(0x8c000000), + SPH_C32(0xde5601ec), SPH_C32(0x48a82f74), SPH_C32(0xeca12966), + SPH_C32(0x4da28d76), SPH_C32(0x95aa8be1), SPH_C32(0x41da0000), + SPH_C32(0x1d790000), SPH_C32(0xa2020000), SPH_C32(0x324500a1), + SPH_C32(0x5954f2ba), SPH_C32(0x28ee463d), SPH_C32(0x0c504459), + SPH_C32(0x666e9527) }, + { SPH_C32(0x47da0000), SPH_C32(0xa73b0000), SPH_C32(0x23270000), + SPH_C32(0xe34e01e9), SPH_C32(0x64e730a7), SPH_C32(0x98573ff3), + SPH_C32(0xf861ca9d), SPH_C32(0xa9f7741f), SPH_C32(0x42e70000), + SPH_C32(0x15ca0000), SPH_C32(0x51380000), SPH_C32(0x088700a6), + SPH_C32(0x087d78ea), SPH_C32(0x43802022), SPH_C32(0x02f58bba), + SPH_C32(0x80b4ead9) }, + { SPH_C32(0x44e70000), SPH_C32(0xaf880000), SPH_C32(0xd01d0000), + SPH_C32(0xd98c01ee), SPH_C32(0x35cebaf7), SPH_C32(0xf33959ec), + SPH_C32(0xf6c4057e), SPH_C32(0x4f2d0be1), SPH_C32(0xea3d0000), + SPH_C32(0x83740000), SPH_C32(0x0d250000), SPH_C32(0x0f5d00a4), + SPH_C32(0x751bed69), SPH_C32(0x5c1850a8), SPH_C32(0xb99303b2), + SPH_C32(0x5a336ad9) }, + { SPH_C32(0x7cbb0000), SPH_C32(0x0a820000), SPH_C32(0xc53b0000), + SPH_C32(0x7d4401e3), SPH_C32(0x2eb80b6a), SPH_C32(0x6183585b), + SPH_C32(0xd5ffd426), SPH_C32(0x5b091fb3), SPH_C32(0xe8930000), + SPH_C32(0x6c450000), SPH_C32(0x13e40000), SPH_C32(0xfa9300a8), + SPH_C32(0xa9e2ea61), SPH_C32(0x8bd58299), SPH_C32(0xb100adb0), + SPH_C32(0xef868b5c) }, + { SPH_C32(0x7f860000), SPH_C32(0x02310000), SPH_C32(0x36010000), + SPH_C32(0x478601e4), SPH_C32(0x7f91813a), SPH_C32(0x0aed3e44), + SPH_C32(0xdb5a1bc5), SPH_C32(0xbdd3604d), SPH_C32(0x40490000), + SPH_C32(0xfafb0000), SPH_C32(0x4ff90000), SPH_C32(0xfd4900aa), + SPH_C32(0xd4847fe2), SPH_C32(0x944df213), SPH_C32(0x0a6625b8), + SPH_C32(0x35010b5c) }, + { SPH_C32(0xd4610000), SPH_C32(0x9c3c0000), SPH_C32(0x99260000), + SPH_C32(0x7a9e01e1), SPH_C32(0x53de9ee9), SPH_C32(0x7e1b28d1), + SPH_C32(0x6e995c2e), SPH_C32(0x818e9fb3), SPH_C32(0x43740000), + SPH_C32(0xf2480000), SPH_C32(0xbcc30000), SPH_C32(0xc78b00ad), + SPH_C32(0x85adf5b2), SPH_C32(0xff23940c), SPH_C32(0x04c3ea5b), + SPH_C32(0xd3db74a2) }, + { SPH_C32(0xd75c0000), SPH_C32(0x948f0000), SPH_C32(0x6a1c0000), + SPH_C32(0x405c01e6), SPH_C32(0x02f714b9), SPH_C32(0x15754ece), + SPH_C32(0x603c93cd), SPH_C32(0x6754e04d), SPH_C32(0xebae0000), + SPH_C32(0x64f60000), SPH_C32(0xe0de0000), SPH_C32(0xc05100af), + SPH_C32(0xf8cb6031), SPH_C32(0xe0bbe486), SPH_C32(0xbfa56253), + SPH_C32(0x095cf4a2) }, + { SPH_C32(0x7d280000), SPH_C32(0xed000000), SPH_C32(0x28c00000), + SPH_C32(0xb24801e8), SPH_C32(0xa3688632), SPH_C32(0xdd20ec75), + SPH_C32(0xd3c9b5c7), SPH_C32(0x086681c8), SPH_C32(0x7abb0000), + SPH_C32(0xb0c00000), SPH_C32(0x441e0000), SPH_C32(0xac4f00ab), + SPH_C32(0x130bc977), SPH_C32(0xd13a2195), SPH_C32(0x21ce5ae2), + SPH_C32(0x9490fe8b) }, + { SPH_C32(0x7e150000), SPH_C32(0xe5b30000), SPH_C32(0xdbfa0000), + SPH_C32(0x888a01ef), SPH_C32(0xf2410c62), SPH_C32(0xb64e8a6a), + SPH_C32(0xdd6c7a24), SPH_C32(0xeebcfe36), SPH_C32(0xd2610000), + SPH_C32(0x267e0000), SPH_C32(0x18030000), SPH_C32(0xab9500a9), + SPH_C32(0x6e6d5cf4), SPH_C32(0xcea2511f), SPH_C32(0x9aa8d2ea), + SPH_C32(0x4e177e8b) }, + { SPH_C32(0xd5f20000), SPH_C32(0x7bbe0000), SPH_C32(0x74dd0000), + SPH_C32(0xb59201ea), SPH_C32(0xde0e13b1), SPH_C32(0xc2b89cff), + SPH_C32(0x68af3dcf), SPH_C32(0xd2e101c8), SPH_C32(0xd15c0000), + SPH_C32(0x2ecd0000), SPH_C32(0xeb390000), SPH_C32(0x915700ae), + SPH_C32(0x3f44d6a4), SPH_C32(0xa5cc3700), SPH_C32(0x940d1d09), + SPH_C32(0xa8cd0175) }, + { SPH_C32(0xd6cf0000), SPH_C32(0x730d0000), SPH_C32(0x87e70000), + SPH_C32(0x8f5001ed), SPH_C32(0x8f2799e1), SPH_C32(0xa9d6fae0), + SPH_C32(0x660af22c), SPH_C32(0x343b7e36), SPH_C32(0x79860000), + SPH_C32(0xb8730000), SPH_C32(0xb7240000), SPH_C32(0x968d00ac), + SPH_C32(0x42224327), SPH_C32(0xba54478a), SPH_C32(0x2f6b9501), + SPH_C32(0x724a8175) }, + { SPH_C32(0xb13b0000), SPH_C32(0x80040000), SPH_C32(0xd16f0000), + SPH_C32(0x4f6b01f3), SPH_C32(0xb12faec3), SPH_C32(0x287d6f19), + SPH_C32(0x112fb6cb), SPH_C32(0xaebbb10d), SPH_C32(0x7b6c0000), + SPH_C32(0x280a0000), SPH_C32(0x73990000), SPH_C32(0x496000a1), + SPH_C32(0xa5768de3), SPH_C32(0xc42f093c), SPH_C32(0x24f2a563), + SPH_C32(0x79f5076e) }, + { SPH_C32(0xb2060000), SPH_C32(0x88b70000), SPH_C32(0x22550000), + SPH_C32(0x75a901f4), SPH_C32(0xe0062493), SPH_C32(0x43130906), + SPH_C32(0x1f8a7928), SPH_C32(0x4861cef3), SPH_C32(0xd3b60000), + SPH_C32(0xbeb40000), SPH_C32(0x2f840000), SPH_C32(0x4eba00a3), + SPH_C32(0xd8101860), SPH_C32(0xdbb779b6), SPH_C32(0x9f942d6b), + SPH_C32(0xa372876e) }, + { SPH_C32(0x19e10000), SPH_C32(0x16ba0000), SPH_C32(0x8d720000), + SPH_C32(0x48b101f1), SPH_C32(0xcc493b40), SPH_C32(0x37e51f93), + SPH_C32(0xaa493ec3), SPH_C32(0x743c310d), SPH_C32(0xd08b0000), + SPH_C32(0xb6070000), SPH_C32(0xdcbe0000), SPH_C32(0x747800a4), + SPH_C32(0x89399230), SPH_C32(0xb0d91fa9), SPH_C32(0x9131e288), + SPH_C32(0x45a8f890) }, + { SPH_C32(0x1adc0000), SPH_C32(0x1e090000), SPH_C32(0x7e480000), + SPH_C32(0x727301f6), SPH_C32(0x9d60b110), SPH_C32(0x5c8b798c), + SPH_C32(0xa4ecf120), SPH_C32(0x92e64ef3), SPH_C32(0x78510000), + SPH_C32(0x20b90000), SPH_C32(0x80a30000), SPH_C32(0x73a200a6), + SPH_C32(0xf45f07b3), SPH_C32(0xaf416f23), SPH_C32(0x2a576a80), + SPH_C32(0x9f2f7890) }, + { SPH_C32(0xb0a80000), SPH_C32(0x67860000), SPH_C32(0x3c940000), + SPH_C32(0x806701f8), SPH_C32(0x3cff239b), SPH_C32(0x94dedb37), + SPH_C32(0x1719d72a), SPH_C32(0xfdd42f76), SPH_C32(0xe9440000), + SPH_C32(0xf48f0000), SPH_C32(0x24630000), SPH_C32(0x1fbc00a2), + SPH_C32(0x1f9faef5), SPH_C32(0x9ec0aa30), SPH_C32(0xb43c5231), + SPH_C32(0x02e372b9) }, + { SPH_C32(0xb3950000), SPH_C32(0x6f350000), SPH_C32(0xcfae0000), + SPH_C32(0xbaa501ff), SPH_C32(0x6dd6a9cb), SPH_C32(0xffb0bd28), + SPH_C32(0x19bc18c9), SPH_C32(0x1b0e5088), SPH_C32(0x419e0000), + SPH_C32(0x62310000), SPH_C32(0x787e0000), SPH_C32(0x186600a0), + SPH_C32(0x62f93b76), SPH_C32(0x8158daba), SPH_C32(0x0f5ada39), + SPH_C32(0xd864f2b9) }, + { SPH_C32(0x18720000), SPH_C32(0xf1380000), SPH_C32(0x60890000), + SPH_C32(0x87bd01fa), SPH_C32(0x4199b618), SPH_C32(0x8b46abbd), + SPH_C32(0xac7f5f22), SPH_C32(0x2753af76), SPH_C32(0x42a30000), + SPH_C32(0x6a820000), SPH_C32(0x8b440000), SPH_C32(0x22a400a7), + SPH_C32(0x33d0b126), SPH_C32(0xea36bca5), SPH_C32(0x01ff15da), + SPH_C32(0x3ebe8d47) }, + { SPH_C32(0x1b4f0000), SPH_C32(0xf98b0000), SPH_C32(0x93b30000), + SPH_C32(0xbd7f01fd), SPH_C32(0x10b03c48), SPH_C32(0xe028cda2), + SPH_C32(0xa2da90c1), SPH_C32(0xc189d088), SPH_C32(0xea790000), + SPH_C32(0xfc3c0000), SPH_C32(0xd7590000), SPH_C32(0x257e00a5), + SPH_C32(0x4eb624a5), SPH_C32(0xf5aecc2f), SPH_C32(0xba999dd2), + SPH_C32(0xe4390d47) }, + { SPH_C32(0x23130000), SPH_C32(0x5c810000), SPH_C32(0x86950000), + SPH_C32(0x19b701f0), SPH_C32(0x0bc68dd5), SPH_C32(0x7292cc15), + SPH_C32(0x81e14199), SPH_C32(0xd5adc4da), SPH_C32(0xe8d70000), + SPH_C32(0x130d0000), SPH_C32(0xc9980000), SPH_C32(0xd0b000a9), + SPH_C32(0x924f23ad), SPH_C32(0x22631e1e), SPH_C32(0xb20a33d0), + SPH_C32(0x518cecc2) }, + { SPH_C32(0x202e0000), SPH_C32(0x54320000), SPH_C32(0x75af0000), + SPH_C32(0x237501f7), SPH_C32(0x5aef0785), SPH_C32(0x19fcaa0a), + SPH_C32(0x8f448e7a), SPH_C32(0x3377bb24), SPH_C32(0x400d0000), + SPH_C32(0x85b30000), SPH_C32(0x95850000), SPH_C32(0xd76a00ab), + SPH_C32(0xef29b62e), SPH_C32(0x3dfb6e94), SPH_C32(0x096cbbd8), + SPH_C32(0x8b0b6cc2) }, + { SPH_C32(0x8bc90000), SPH_C32(0xca3f0000), SPH_C32(0xda880000), + SPH_C32(0x1e6d01f2), SPH_C32(0x76a01856), SPH_C32(0x6d0abc9f), + SPH_C32(0x3a87c991), SPH_C32(0x0f2a44da), SPH_C32(0x43300000), + SPH_C32(0x8d000000), SPH_C32(0x66bf0000), SPH_C32(0xeda800ac), + SPH_C32(0xbe003c7e), SPH_C32(0x5695088b), SPH_C32(0x07c9743b), + SPH_C32(0x6dd1133c) }, + { SPH_C32(0x88f40000), SPH_C32(0xc28c0000), SPH_C32(0x29b20000), + SPH_C32(0x24af01f5), SPH_C32(0x27899206), SPH_C32(0x0664da80), + SPH_C32(0x34220672), SPH_C32(0xe9f03b24), SPH_C32(0xebea0000), + SPH_C32(0x1bbe0000), SPH_C32(0x3aa20000), SPH_C32(0xea7200ae), + SPH_C32(0xc366a9fd), SPH_C32(0x490d7801), SPH_C32(0xbcaffc33), + SPH_C32(0xb756933c) }, + { SPH_C32(0x22800000), SPH_C32(0xbb030000), SPH_C32(0x6b6e0000), + SPH_C32(0xd6bb01fb), SPH_C32(0x8616008d), SPH_C32(0xce31783b), + SPH_C32(0x87d72078), SPH_C32(0x86c25aa1), SPH_C32(0x7aff0000), + SPH_C32(0xcf880000), SPH_C32(0x9e620000), SPH_C32(0x866c00aa), + SPH_C32(0x28a600bb), SPH_C32(0x788cbd12), SPH_C32(0x22c4c482), + SPH_C32(0x2a9a9915) }, + { SPH_C32(0x21bd0000), SPH_C32(0xb3b00000), SPH_C32(0x98540000), + SPH_C32(0xec7901fc), SPH_C32(0xd73f8add), SPH_C32(0xa55f1e24), + SPH_C32(0x8972ef9b), SPH_C32(0x6018255f), SPH_C32(0xd2250000), + SPH_C32(0x59360000), SPH_C32(0xc27f0000), SPH_C32(0x81b600a8), + SPH_C32(0x55c09538), SPH_C32(0x6714cd98), SPH_C32(0x99a24c8a), + SPH_C32(0xf01d1915) }, + { SPH_C32(0x8a5a0000), SPH_C32(0x2dbd0000), SPH_C32(0x37730000), + SPH_C32(0xd16101f9), SPH_C32(0xfb70950e), SPH_C32(0xd1a908b1), + SPH_C32(0x3cb1a870), SPH_C32(0x5c45daa1), SPH_C32(0xd1180000), + SPH_C32(0x51850000), SPH_C32(0x31450000), SPH_C32(0xbb7400af), + SPH_C32(0x04e91f68), SPH_C32(0x0c7aab87), SPH_C32(0x97078369), + SPH_C32(0x16c766eb) }, + { SPH_C32(0x89670000), SPH_C32(0x250e0000), SPH_C32(0xc4490000), + SPH_C32(0xeba301fe), SPH_C32(0xaa591f5e), SPH_C32(0xbac76eae), + SPH_C32(0x32146793), SPH_C32(0xba9fa55f), SPH_C32(0x79c20000), + SPH_C32(0xc73b0000), SPH_C32(0x6d580000), SPH_C32(0xbcae00ad), + SPH_C32(0x798f8aeb), SPH_C32(0x13e2db0d), SPH_C32(0x2c610b61), + SPH_C32(0xcc40e6eb) }, + { SPH_C32(0xeed70000), SPH_C32(0xa94f0000), SPH_C32(0x48bd0000), + SPH_C32(0x01bb01e1), SPH_C32(0xaffce1b0), SPH_C32(0x92da67d0), + SPH_C32(0x463bbd14), SPH_C32(0x9e150dfa), SPH_C32(0x24c40000), + SPH_C32(0x7e090000), SPH_C32(0x30370000), SPH_C32(0x2d9300b2), + SPH_C32(0x80080b5c), SPH_C32(0xd73e9d72), SPH_C32(0x70ec30dc), + SPH_C32(0xf751dc07) }, + { SPH_C32(0xedea0000), SPH_C32(0xa1fc0000), SPH_C32(0xbb870000), + SPH_C32(0x3b7901e6), SPH_C32(0xfed56be0), SPH_C32(0xf9b401cf), + SPH_C32(0x489e72f7), SPH_C32(0x78cf7204), SPH_C32(0x8c1e0000), + SPH_C32(0xe8b70000), SPH_C32(0x6c2a0000), SPH_C32(0x2a4900b0), + SPH_C32(0xfd6e9edf), SPH_C32(0xc8a6edf8), SPH_C32(0xcb8ab8d4), + SPH_C32(0x2dd65c07) }, + { SPH_C32(0x460d0000), SPH_C32(0x3ff10000), SPH_C32(0x14a00000), + SPH_C32(0x066101e3), SPH_C32(0xd29a7433), SPH_C32(0x8d42175a), + SPH_C32(0xfd5d351c), SPH_C32(0x44928dfa), SPH_C32(0x8f230000), + SPH_C32(0xe0040000), SPH_C32(0x9f100000), SPH_C32(0x108b00b7), + SPH_C32(0xac47148f), SPH_C32(0xa3c88be7), SPH_C32(0xc52f7737), + SPH_C32(0xcb0c23f9) }, + { SPH_C32(0x45300000), SPH_C32(0x37420000), SPH_C32(0xe79a0000), + SPH_C32(0x3ca301e4), SPH_C32(0x83b3fe63), SPH_C32(0xe62c7145), + SPH_C32(0xf3f8faff), SPH_C32(0xa248f204), SPH_C32(0x27f90000), + SPH_C32(0x76ba0000), SPH_C32(0xc30d0000), SPH_C32(0x175100b5), + SPH_C32(0xd121810c), SPH_C32(0xbc50fb6d), SPH_C32(0x7e49ff3f), + SPH_C32(0x118ba3f9) }, + { SPH_C32(0xef440000), SPH_C32(0x4ecd0000), SPH_C32(0xa5460000), + SPH_C32(0xceb701ea), SPH_C32(0x222c6ce8), SPH_C32(0x2e79d3fe), + SPH_C32(0x400ddcf5), SPH_C32(0xcd7a9381), SPH_C32(0xb6ec0000), + SPH_C32(0xa28c0000), SPH_C32(0x67cd0000), SPH_C32(0x7b4f00b1), + SPH_C32(0x3ae1284a), SPH_C32(0x8dd13e7e), SPH_C32(0xe022c78e), + SPH_C32(0x8c47a9d0) }, + { SPH_C32(0xec790000), SPH_C32(0x467e0000), SPH_C32(0x567c0000), + SPH_C32(0xf47501ed), SPH_C32(0x7305e6b8), SPH_C32(0x4517b5e1), + SPH_C32(0x4ea81316), SPH_C32(0x2ba0ec7f), SPH_C32(0x1e360000), + SPH_C32(0x34320000), SPH_C32(0x3bd00000), SPH_C32(0x7c9500b3), + SPH_C32(0x4787bdc9), SPH_C32(0x92494ef4), SPH_C32(0x5b444f86), + SPH_C32(0x56c029d0) }, + { SPH_C32(0x479e0000), SPH_C32(0xd8730000), SPH_C32(0xf95b0000), + SPH_C32(0xc96d01e8), SPH_C32(0x5f4af96b), SPH_C32(0x31e1a374), + SPH_C32(0xfb6b54fd), SPH_C32(0x17fd1381), SPH_C32(0x1d0b0000), + SPH_C32(0x3c810000), SPH_C32(0xc8ea0000), SPH_C32(0x465700b4), + SPH_C32(0x16ae3799), SPH_C32(0xf92728eb), SPH_C32(0x55e18065), + SPH_C32(0xb01a562e) }, + { SPH_C32(0x44a30000), SPH_C32(0xd0c00000), SPH_C32(0x0a610000), + SPH_C32(0xf3af01ef), SPH_C32(0x0e63733b), SPH_C32(0x5a8fc56b), + SPH_C32(0xf5ce9b1e), SPH_C32(0xf1276c7f), SPH_C32(0xb5d10000), + SPH_C32(0xaa3f0000), SPH_C32(0x94f70000), SPH_C32(0x418d00b6), + SPH_C32(0x6bc8a21a), SPH_C32(0xe6bf5861), SPH_C32(0xee87086d), + SPH_C32(0x6a9dd62e) }, + { SPH_C32(0x7cff0000), SPH_C32(0x75ca0000), SPH_C32(0x1f470000), + SPH_C32(0x576701e2), SPH_C32(0x1515c2a6), SPH_C32(0xc835c4dc), + SPH_C32(0xd6f54a46), SPH_C32(0xe503782d), SPH_C32(0xb77f0000), + SPH_C32(0x450e0000), SPH_C32(0x8a360000), SPH_C32(0xb44300ba), + SPH_C32(0xb731a512), SPH_C32(0x31728a50), SPH_C32(0xe614a66f), + SPH_C32(0xdf2837ab) }, + { SPH_C32(0x7fc20000), SPH_C32(0x7d790000), SPH_C32(0xec7d0000), + SPH_C32(0x6da501e5), SPH_C32(0x443c48f6), SPH_C32(0xa35ba2c3), + SPH_C32(0xd85085a5), SPH_C32(0x03d907d3), SPH_C32(0x1fa50000), + SPH_C32(0xd3b00000), SPH_C32(0xd62b0000), SPH_C32(0xb39900b8), + SPH_C32(0xca573091), SPH_C32(0x2eeafada), SPH_C32(0x5d722e67), + SPH_C32(0x05afb7ab) }, + { SPH_C32(0xd4250000), SPH_C32(0xe3740000), SPH_C32(0x435a0000), + SPH_C32(0x50bd01e0), SPH_C32(0x68735725), SPH_C32(0xd7adb456), + SPH_C32(0x6d93c24e), SPH_C32(0x3f84f82d), SPH_C32(0x1c980000), + SPH_C32(0xdb030000), SPH_C32(0x25110000), SPH_C32(0x895b00bf), + SPH_C32(0x9b7ebac1), SPH_C32(0x45849cc5), SPH_C32(0x53d7e184), + SPH_C32(0xe375c855) }, + { SPH_C32(0xd7180000), SPH_C32(0xebc70000), SPH_C32(0xb0600000), + SPH_C32(0x6a7f01e7), SPH_C32(0x395add75), SPH_C32(0xbcc3d249), + SPH_C32(0x63360dad), SPH_C32(0xd95e87d3), SPH_C32(0xb4420000), + SPH_C32(0x4dbd0000), SPH_C32(0x790c0000), SPH_C32(0x8e8100bd), + SPH_C32(0xe6182f42), SPH_C32(0x5a1cec4f), SPH_C32(0xe8b1698c), + SPH_C32(0x39f24855) }, + { SPH_C32(0x7d6c0000), SPH_C32(0x92480000), SPH_C32(0xf2bc0000), + SPH_C32(0x986b01e9), SPH_C32(0x98c54ffe), SPH_C32(0x749670f2), + SPH_C32(0xd0c32ba7), SPH_C32(0xb66ce656), SPH_C32(0x25570000), + SPH_C32(0x998b0000), SPH_C32(0xddcc0000), SPH_C32(0xe29f00b9), + SPH_C32(0x0dd88604), SPH_C32(0x6b9d295c), SPH_C32(0x76da513d), + SPH_C32(0xa43e427c) }, + { SPH_C32(0x7e510000), SPH_C32(0x9afb0000), SPH_C32(0x01860000), + SPH_C32(0xa2a901ee), SPH_C32(0xc9ecc5ae), SPH_C32(0x1ff816ed), + SPH_C32(0xde66e444), SPH_C32(0x50b699a8), SPH_C32(0x8d8d0000), + SPH_C32(0x0f350000), SPH_C32(0x81d10000), SPH_C32(0xe54500bb), + SPH_C32(0x70be1387), SPH_C32(0x740559d6), SPH_C32(0xcdbcd935), + SPH_C32(0x7eb9c27c) }, + { SPH_C32(0xd5b60000), SPH_C32(0x04f60000), SPH_C32(0xaea10000), + SPH_C32(0x9fb101eb), SPH_C32(0xe5a3da7d), SPH_C32(0x6b0e0078), + SPH_C32(0x6ba5a3af), SPH_C32(0x6ceb6656), SPH_C32(0x8eb00000), + SPH_C32(0x07860000), SPH_C32(0x72eb0000), SPH_C32(0xdf8700bc), + SPH_C32(0x219799d7), SPH_C32(0x1f6b3fc9), SPH_C32(0xc31916d6), + SPH_C32(0x9863bd82) }, + { SPH_C32(0xd68b0000), SPH_C32(0x0c450000), SPH_C32(0x5d9b0000), + SPH_C32(0xa57301ec), SPH_C32(0xb48a502d), SPH_C32(0x00606667), + SPH_C32(0x65006c4c), SPH_C32(0x8a3119a8), SPH_C32(0x266a0000), + SPH_C32(0x91380000), SPH_C32(0x2ef60000), SPH_C32(0xd85d00be), + SPH_C32(0x5cf10c54), SPH_C32(0x00f34f43), SPH_C32(0x787f9ede), + SPH_C32(0x42e43d82) }, + { SPH_C32(0xb17f0000), SPH_C32(0xff4c0000), SPH_C32(0x0b130000), + SPH_C32(0x654801f2), SPH_C32(0x8a82670f), SPH_C32(0x81cbf39e), + SPH_C32(0x122528ab), SPH_C32(0x10b1d693), SPH_C32(0x24800000), + SPH_C32(0x01410000), SPH_C32(0xea4b0000), SPH_C32(0x07b000b3), + SPH_C32(0xbba5c290), SPH_C32(0x7e8801f5), SPH_C32(0x73e6aebc), + SPH_C32(0x495bbb99) }, + { SPH_C32(0xb2420000), SPH_C32(0xf7ff0000), SPH_C32(0xf8290000), + SPH_C32(0x5f8a01f5), SPH_C32(0xdbabed5f), SPH_C32(0xeaa59581), + SPH_C32(0x1c80e748), SPH_C32(0xf66ba96d), SPH_C32(0x8c5a0000), + SPH_C32(0x97ff0000), SPH_C32(0xb6560000), SPH_C32(0x006a00b1), + SPH_C32(0xc6c35713), SPH_C32(0x6110717f), SPH_C32(0xc88026b4), + SPH_C32(0x93dc3b99) }, + { SPH_C32(0x19a50000), SPH_C32(0x69f20000), SPH_C32(0x570e0000), + SPH_C32(0x629201f0), SPH_C32(0xf7e4f28c), SPH_C32(0x9e538314), + SPH_C32(0xa943a0a3), SPH_C32(0xca365693), SPH_C32(0x8f670000), + SPH_C32(0x9f4c0000), SPH_C32(0x456c0000), SPH_C32(0x3aa800b6), + SPH_C32(0x97eadd43), SPH_C32(0x0a7e1760), SPH_C32(0xc625e957), + SPH_C32(0x75064467) }, + { SPH_C32(0x1a980000), SPH_C32(0x61410000), SPH_C32(0xa4340000), + SPH_C32(0x585001f7), SPH_C32(0xa6cd78dc), SPH_C32(0xf53de50b), + SPH_C32(0xa7e66f40), SPH_C32(0x2cec296d), SPH_C32(0x27bd0000), + SPH_C32(0x09f20000), SPH_C32(0x19710000), SPH_C32(0x3d7200b4), + SPH_C32(0xea8c48c0), SPH_C32(0x15e667ea), SPH_C32(0x7d43615f), + SPH_C32(0xaf81c467) }, + { SPH_C32(0xb0ec0000), SPH_C32(0x18ce0000), SPH_C32(0xe6e80000), + SPH_C32(0xaa4401f9), SPH_C32(0x0752ea57), SPH_C32(0x3d6847b0), + SPH_C32(0x1413494a), SPH_C32(0x43de48e8), SPH_C32(0xb6a80000), + SPH_C32(0xddc40000), SPH_C32(0xbdb10000), SPH_C32(0x516c00b0), + SPH_C32(0x014ce186), SPH_C32(0x2467a2f9), SPH_C32(0xe32859ee), + SPH_C32(0x324dce4e) }, + { SPH_C32(0xb3d10000), SPH_C32(0x107d0000), SPH_C32(0x15d20000), + SPH_C32(0x908601fe), SPH_C32(0x567b6007), SPH_C32(0x560621af), + SPH_C32(0x1ab686a9), SPH_C32(0xa5043716), SPH_C32(0x1e720000), + SPH_C32(0x4b7a0000), SPH_C32(0xe1ac0000), SPH_C32(0x56b600b2), + SPH_C32(0x7c2a7405), SPH_C32(0x3bffd273), SPH_C32(0x584ed1e6), + SPH_C32(0xe8ca4e4e) }, + { SPH_C32(0x18360000), SPH_C32(0x8e700000), SPH_C32(0xbaf50000), + SPH_C32(0xad9e01fb), SPH_C32(0x7a347fd4), SPH_C32(0x22f0373a), + SPH_C32(0xaf75c142), SPH_C32(0x9959c8e8), SPH_C32(0x1d4f0000), + SPH_C32(0x43c90000), SPH_C32(0x12960000), SPH_C32(0x6c7400b5), + SPH_C32(0x2d03fe55), SPH_C32(0x5091b46c), SPH_C32(0x56eb1e05), + SPH_C32(0x0e1031b0) }, + { SPH_C32(0x1b0b0000), SPH_C32(0x86c30000), SPH_C32(0x49cf0000), + SPH_C32(0x975c01fc), SPH_C32(0x2b1df584), SPH_C32(0x499e5125), + SPH_C32(0xa1d00ea1), SPH_C32(0x7f83b716), SPH_C32(0xb5950000), + SPH_C32(0xd5770000), SPH_C32(0x4e8b0000), SPH_C32(0x6bae00b7), + SPH_C32(0x50656bd6), SPH_C32(0x4f09c4e6), SPH_C32(0xed8d960d), + SPH_C32(0xd497b1b0) }, + { SPH_C32(0x23570000), SPH_C32(0x23c90000), SPH_C32(0x5ce90000), + SPH_C32(0x339401f1), SPH_C32(0x306b4419), SPH_C32(0xdb245092), + SPH_C32(0x82ebdff9), SPH_C32(0x6ba7a344), SPH_C32(0xb73b0000), + SPH_C32(0x3a460000), SPH_C32(0x504a0000), SPH_C32(0x9e6000bb), + SPH_C32(0x8c9c6cde), SPH_C32(0x98c416d7), SPH_C32(0xe51e380f), + SPH_C32(0x61225035) }, + { SPH_C32(0x206a0000), SPH_C32(0x2b7a0000), SPH_C32(0xafd30000), + SPH_C32(0x095601f6), SPH_C32(0x6142ce49), SPH_C32(0xb04a368d), + SPH_C32(0x8c4e101a), SPH_C32(0x8d7ddcba), SPH_C32(0x1fe10000), + SPH_C32(0xacf80000), SPH_C32(0x0c570000), SPH_C32(0x99ba00b9), + SPH_C32(0xf1faf95d), SPH_C32(0x875c665d), SPH_C32(0x5e78b007), + SPH_C32(0xbba5d035) }, + { SPH_C32(0x8b8d0000), SPH_C32(0xb5770000), SPH_C32(0x00f40000), + SPH_C32(0x344e01f3), SPH_C32(0x4d0dd19a), SPH_C32(0xc4bc2018), + SPH_C32(0x398d57f1), SPH_C32(0xb1202344), SPH_C32(0x1cdc0000), + SPH_C32(0xa44b0000), SPH_C32(0xff6d0000), SPH_C32(0xa37800be), + SPH_C32(0xa0d3730d), SPH_C32(0xec320042), SPH_C32(0x50dd7fe4), + SPH_C32(0x5d7fafcb) }, + { SPH_C32(0x88b00000), SPH_C32(0xbdc40000), SPH_C32(0xf3ce0000), + SPH_C32(0x0e8c01f4), SPH_C32(0x1c245bca), SPH_C32(0xafd24607), + SPH_C32(0x37289812), SPH_C32(0x57fa5cba), SPH_C32(0xb4060000), + SPH_C32(0x32f50000), SPH_C32(0xa3700000), SPH_C32(0xa4a200bc), + SPH_C32(0xddb5e68e), SPH_C32(0xf3aa70c8), SPH_C32(0xebbbf7ec), + SPH_C32(0x87f82fcb) }, + { SPH_C32(0x22c40000), SPH_C32(0xc44b0000), SPH_C32(0xb1120000), + SPH_C32(0xfc9801fa), SPH_C32(0xbdbbc941), SPH_C32(0x6787e4bc), + SPH_C32(0x84ddbe18), SPH_C32(0x38c83d3f), SPH_C32(0x25130000), + SPH_C32(0xe6c30000), SPH_C32(0x07b00000), SPH_C32(0xc8bc00b8), + SPH_C32(0x36754fc8), SPH_C32(0xc22bb5db), SPH_C32(0x75d0cf5d), + SPH_C32(0x1a3425e2) }, + { SPH_C32(0x21f90000), SPH_C32(0xccf80000), SPH_C32(0x42280000), + SPH_C32(0xc65a01fd), SPH_C32(0xec924311), SPH_C32(0x0ce982a3), + SPH_C32(0x8a7871fb), SPH_C32(0xde1242c1), SPH_C32(0x8dc90000), + SPH_C32(0x707d0000), SPH_C32(0x5bad0000), SPH_C32(0xcf6600ba), + SPH_C32(0x4b13da4b), SPH_C32(0xddb3c551), SPH_C32(0xceb64755), + SPH_C32(0xc0b3a5e2) }, + { SPH_C32(0x8a1e0000), SPH_C32(0x52f50000), SPH_C32(0xed0f0000), + SPH_C32(0xfb4201f8), SPH_C32(0xc0dd5cc2), SPH_C32(0x781f9436), + SPH_C32(0x3fbb3610), SPH_C32(0xe24fbd3f), SPH_C32(0x8ef40000), + SPH_C32(0x78ce0000), SPH_C32(0xa8970000), SPH_C32(0xf5a400bd), + SPH_C32(0x1a3a501b), SPH_C32(0xb6dda34e), SPH_C32(0xc01388b6), + SPH_C32(0x2669da1c) }, + { SPH_C32(0x89230000), SPH_C32(0x5a460000), SPH_C32(0x1e350000), + SPH_C32(0xc18001ff), SPH_C32(0x91f4d692), SPH_C32(0x1371f229), + SPH_C32(0x311ef9f3), SPH_C32(0x0495c2c1), SPH_C32(0x262e0000), + SPH_C32(0xee700000), SPH_C32(0xf48a0000), SPH_C32(0xf27e00bf), + SPH_C32(0x675cc598), SPH_C32(0xa945d3c4), SPH_C32(0x7b7500be), + SPH_C32(0xfcee5a1c) }, + { SPH_C32(0x7b280000), SPH_C32(0x57420000), SPH_C32(0xa9e50000), + SPH_C32(0x634300a0), SPH_C32(0x9edb442f), SPH_C32(0x6d9995bb), + SPH_C32(0x27f83b03), SPH_C32(0xc7ff60f0), SPH_C32(0x95bb0000), + SPH_C32(0x81450000), SPH_C32(0x3b240000), SPH_C32(0x48db0140), + SPH_C32(0x0a8a6c53), SPH_C32(0x56f56eec), SPH_C32(0x62c91877), + SPH_C32(0xe7e00a94) }, + { SPH_C32(0x78150000), SPH_C32(0x5ff10000), SPH_C32(0x5adf0000), + SPH_C32(0x598100a7), SPH_C32(0xcff2ce7f), SPH_C32(0x06f7f3a4), + SPH_C32(0x295df4e0), SPH_C32(0x21251f0e), SPH_C32(0x3d610000), + SPH_C32(0x17fb0000), SPH_C32(0x67390000), SPH_C32(0x4f010142), + SPH_C32(0x77ecf9d0), SPH_C32(0x496d1e66), SPH_C32(0xd9af907f), + SPH_C32(0x3d678a94) }, + { SPH_C32(0xd3f20000), SPH_C32(0xc1fc0000), SPH_C32(0xf5f80000), + SPH_C32(0x649900a2), SPH_C32(0xe3bdd1ac), SPH_C32(0x7201e531), + SPH_C32(0x9c9eb30b), SPH_C32(0x1d78e0f0), SPH_C32(0x3e5c0000), + SPH_C32(0x1f480000), SPH_C32(0x94030000), SPH_C32(0x75c30145), + SPH_C32(0x26c57380), SPH_C32(0x22037879), SPH_C32(0xd70a5f9c), + SPH_C32(0xdbbdf56a) }, + { SPH_C32(0xd0cf0000), SPH_C32(0xc94f0000), SPH_C32(0x06c20000), + SPH_C32(0x5e5b00a5), SPH_C32(0xb2945bfc), SPH_C32(0x196f832e), + SPH_C32(0x923b7ce8), SPH_C32(0xfba29f0e), SPH_C32(0x96860000), + SPH_C32(0x89f60000), SPH_C32(0xc81e0000), SPH_C32(0x72190147), + SPH_C32(0x5ba3e603), SPH_C32(0x3d9b08f3), SPH_C32(0x6c6cd794), + SPH_C32(0x013a756a) }, + { SPH_C32(0x7abb0000), SPH_C32(0xb0c00000), SPH_C32(0x441e0000), + SPH_C32(0xac4f00ab), SPH_C32(0x130bc977), SPH_C32(0xd13a2195), + SPH_C32(0x21ce5ae2), SPH_C32(0x9490fe8b), SPH_C32(0x07930000), + SPH_C32(0x5dc00000), SPH_C32(0x6cde0000), SPH_C32(0x1e070143), + SPH_C32(0xb0634f45), SPH_C32(0x0c1acde0), SPH_C32(0xf207ef25), + SPH_C32(0x9cf67f43) }, + { SPH_C32(0x79860000), SPH_C32(0xb8730000), SPH_C32(0xb7240000), + SPH_C32(0x968d00ac), SPH_C32(0x42224327), SPH_C32(0xba54478a), + SPH_C32(0x2f6b9501), SPH_C32(0x724a8175), SPH_C32(0xaf490000), + SPH_C32(0xcb7e0000), SPH_C32(0x30c30000), SPH_C32(0x19dd0141), + SPH_C32(0xcd05dac6), SPH_C32(0x1382bd6a), SPH_C32(0x4961672d), + SPH_C32(0x4671ff43) }, + { SPH_C32(0xd2610000), SPH_C32(0x267e0000), SPH_C32(0x18030000), + SPH_C32(0xab9500a9), SPH_C32(0x6e6d5cf4), SPH_C32(0xcea2511f), + SPH_C32(0x9aa8d2ea), SPH_C32(0x4e177e8b), SPH_C32(0xac740000), + SPH_C32(0xc3cd0000), SPH_C32(0xc3f90000), SPH_C32(0x231f0146), + SPH_C32(0x9c2c5096), SPH_C32(0x78ecdb75), SPH_C32(0x47c4a8ce), + SPH_C32(0xa0ab80bd) }, + { SPH_C32(0xd15c0000), SPH_C32(0x2ecd0000), SPH_C32(0xeb390000), + SPH_C32(0x915700ae), SPH_C32(0x3f44d6a4), SPH_C32(0xa5cc3700), + SPH_C32(0x940d1d09), SPH_C32(0xa8cd0175), SPH_C32(0x04ae0000), + SPH_C32(0x55730000), SPH_C32(0x9fe40000), SPH_C32(0x24c50144), + SPH_C32(0xe14ac515), SPH_C32(0x6774abff), SPH_C32(0xfca220c6), + SPH_C32(0x7a2c00bd) }, + { SPH_C32(0xe9000000), SPH_C32(0x8bc70000), SPH_C32(0xfe1f0000), + SPH_C32(0x359f00a3), SPH_C32(0x24326739), SPH_C32(0x377636b7), + SPH_C32(0xb736cc51), SPH_C32(0xbce91527), SPH_C32(0x06000000), + SPH_C32(0xba420000), SPH_C32(0x81250000), SPH_C32(0xd10b0148), + SPH_C32(0x3db3c21d), SPH_C32(0xb0b979ce), SPH_C32(0xf4318ec4), + SPH_C32(0xcf99e138) }, + { SPH_C32(0xea3d0000), SPH_C32(0x83740000), SPH_C32(0x0d250000), + SPH_C32(0x0f5d00a4), SPH_C32(0x751bed69), SPH_C32(0x5c1850a8), + SPH_C32(0xb99303b2), SPH_C32(0x5a336ad9), SPH_C32(0xaeda0000), + SPH_C32(0x2cfc0000), SPH_C32(0xdd380000), SPH_C32(0xd6d1014a), + SPH_C32(0x40d5579e), SPH_C32(0xaf210944), SPH_C32(0x4f5706cc), + SPH_C32(0x151e6138) }, + { SPH_C32(0x41da0000), SPH_C32(0x1d790000), SPH_C32(0xa2020000), + SPH_C32(0x324500a1), SPH_C32(0x5954f2ba), SPH_C32(0x28ee463d), + SPH_C32(0x0c504459), SPH_C32(0x666e9527), SPH_C32(0xade70000), + SPH_C32(0x244f0000), SPH_C32(0x2e020000), SPH_C32(0xec13014d), + SPH_C32(0x11fcddce), SPH_C32(0xc44f6f5b), SPH_C32(0x41f2c92f), + SPH_C32(0xf3c41ec6) }, + { SPH_C32(0x42e70000), SPH_C32(0x15ca0000), SPH_C32(0x51380000), + SPH_C32(0x088700a6), SPH_C32(0x087d78ea), SPH_C32(0x43802022), + SPH_C32(0x02f58bba), SPH_C32(0x80b4ead9), SPH_C32(0x053d0000), + SPH_C32(0xb2f10000), SPH_C32(0x721f0000), SPH_C32(0xebc9014f), + SPH_C32(0x6c9a484d), SPH_C32(0xdbd71fd1), SPH_C32(0xfa944127), + SPH_C32(0x29439ec6) }, + { SPH_C32(0xe8930000), SPH_C32(0x6c450000), SPH_C32(0x13e40000), + SPH_C32(0xfa9300a8), SPH_C32(0xa9e2ea61), SPH_C32(0x8bd58299), + SPH_C32(0xb100adb0), SPH_C32(0xef868b5c), SPH_C32(0x94280000), + SPH_C32(0x66c70000), SPH_C32(0xd6df0000), SPH_C32(0x87d7014b), + SPH_C32(0x875ae10b), SPH_C32(0xea56dac2), SPH_C32(0x64ff7996), + SPH_C32(0xb48f94ef) }, + { SPH_C32(0xebae0000), SPH_C32(0x64f60000), SPH_C32(0xe0de0000), + SPH_C32(0xc05100af), SPH_C32(0xf8cb6031), SPH_C32(0xe0bbe486), + SPH_C32(0xbfa56253), SPH_C32(0x095cf4a2), SPH_C32(0x3cf20000), + SPH_C32(0xf0790000), SPH_C32(0x8ac20000), SPH_C32(0x800d0149), + SPH_C32(0xfa3c7488), SPH_C32(0xf5ceaa48), SPH_C32(0xdf99f19e), + SPH_C32(0x6e0814ef) }, + { SPH_C32(0x40490000), SPH_C32(0xfafb0000), SPH_C32(0x4ff90000), + SPH_C32(0xfd4900aa), SPH_C32(0xd4847fe2), SPH_C32(0x944df213), + SPH_C32(0x0a6625b8), SPH_C32(0x35010b5c), SPH_C32(0x3fcf0000), + SPH_C32(0xf8ca0000), SPH_C32(0x79f80000), SPH_C32(0xbacf014e), + SPH_C32(0xab15fed8), SPH_C32(0x9ea0cc57), SPH_C32(0xd13c3e7d), + SPH_C32(0x88d26b11) }, + { SPH_C32(0x43740000), SPH_C32(0xf2480000), SPH_C32(0xbcc30000), + SPH_C32(0xc78b00ad), SPH_C32(0x85adf5b2), SPH_C32(0xff23940c), + SPH_C32(0x04c3ea5b), SPH_C32(0xd3db74a2), SPH_C32(0x97150000), + SPH_C32(0x6e740000), SPH_C32(0x25e50000), SPH_C32(0xbd15014c), + SPH_C32(0xd6736b5b), SPH_C32(0x8138bcdd), SPH_C32(0x6a5ab675), + SPH_C32(0x5255eb11) }, + { SPH_C32(0x24800000), SPH_C32(0x01410000), SPH_C32(0xea4b0000), + SPH_C32(0x07b000b3), SPH_C32(0xbba5c290), SPH_C32(0x7e8801f5), + SPH_C32(0x73e6aebc), SPH_C32(0x495bbb99), SPH_C32(0x95ff0000), + SPH_C32(0xfe0d0000), SPH_C32(0xe1580000), SPH_C32(0x62f80141), + SPH_C32(0x3127a59f), SPH_C32(0xff43f26b), SPH_C32(0x61c38617), + SPH_C32(0x59ea6d0a) }, + { SPH_C32(0x27bd0000), SPH_C32(0x09f20000), SPH_C32(0x19710000), + SPH_C32(0x3d7200b4), SPH_C32(0xea8c48c0), SPH_C32(0x15e667ea), + SPH_C32(0x7d43615f), SPH_C32(0xaf81c467), SPH_C32(0x3d250000), + SPH_C32(0x68b30000), SPH_C32(0xbd450000), SPH_C32(0x65220143), + SPH_C32(0x4c41301c), SPH_C32(0xe0db82e1), SPH_C32(0xdaa50e1f), + SPH_C32(0x836ded0a) }, + { SPH_C32(0x8c5a0000), SPH_C32(0x97ff0000), SPH_C32(0xb6560000), + SPH_C32(0x006a00b1), SPH_C32(0xc6c35713), SPH_C32(0x6110717f), + SPH_C32(0xc88026b4), SPH_C32(0x93dc3b99), SPH_C32(0x3e180000), + SPH_C32(0x60000000), SPH_C32(0x4e7f0000), SPH_C32(0x5fe00144), + SPH_C32(0x1d68ba4c), SPH_C32(0x8bb5e4fe), SPH_C32(0xd400c1fc), + SPH_C32(0x65b792f4) }, + { SPH_C32(0x8f670000), SPH_C32(0x9f4c0000), SPH_C32(0x456c0000), + SPH_C32(0x3aa800b6), SPH_C32(0x97eadd43), SPH_C32(0x0a7e1760), + SPH_C32(0xc625e957), SPH_C32(0x75064467), SPH_C32(0x96c20000), + SPH_C32(0xf6be0000), SPH_C32(0x12620000), SPH_C32(0x583a0146), + SPH_C32(0x600e2fcf), SPH_C32(0x942d9474), SPH_C32(0x6f6649f4), + SPH_C32(0xbf3012f4) }, + { SPH_C32(0x25130000), SPH_C32(0xe6c30000), SPH_C32(0x07b00000), + SPH_C32(0xc8bc00b8), SPH_C32(0x36754fc8), SPH_C32(0xc22bb5db), + SPH_C32(0x75d0cf5d), SPH_C32(0x1a3425e2), SPH_C32(0x07d70000), + SPH_C32(0x22880000), SPH_C32(0xb6a20000), SPH_C32(0x34240142), + SPH_C32(0x8bce8689), SPH_C32(0xa5ac5167), SPH_C32(0xf10d7145), + SPH_C32(0x22fc18dd) }, + { SPH_C32(0x262e0000), SPH_C32(0xee700000), SPH_C32(0xf48a0000), + SPH_C32(0xf27e00bf), SPH_C32(0x675cc598), SPH_C32(0xa945d3c4), + SPH_C32(0x7b7500be), SPH_C32(0xfcee5a1c), SPH_C32(0xaf0d0000), + SPH_C32(0xb4360000), SPH_C32(0xeabf0000), SPH_C32(0x33fe0140), + SPH_C32(0xf6a8130a), SPH_C32(0xba3421ed), SPH_C32(0x4a6bf94d), + SPH_C32(0xf87b98dd) }, + { SPH_C32(0x8dc90000), SPH_C32(0x707d0000), SPH_C32(0x5bad0000), + SPH_C32(0xcf6600ba), SPH_C32(0x4b13da4b), SPH_C32(0xddb3c551), + SPH_C32(0xceb64755), SPH_C32(0xc0b3a5e2), SPH_C32(0xac300000), + SPH_C32(0xbc850000), SPH_C32(0x19850000), SPH_C32(0x093c0147), + SPH_C32(0xa781995a), SPH_C32(0xd15a47f2), SPH_C32(0x44ce36ae), + SPH_C32(0x1ea1e723) }, + { SPH_C32(0x8ef40000), SPH_C32(0x78ce0000), SPH_C32(0xa8970000), + SPH_C32(0xf5a400bd), SPH_C32(0x1a3a501b), SPH_C32(0xb6dda34e), + SPH_C32(0xc01388b6), SPH_C32(0x2669da1c), SPH_C32(0x04ea0000), + SPH_C32(0x2a3b0000), SPH_C32(0x45980000), SPH_C32(0x0ee60145), + SPH_C32(0xdae70cd9), SPH_C32(0xcec23778), SPH_C32(0xffa8bea6), + SPH_C32(0xc4266723) }, + { SPH_C32(0xb6a80000), SPH_C32(0xddc40000), SPH_C32(0xbdb10000), + SPH_C32(0x516c00b0), SPH_C32(0x014ce186), SPH_C32(0x2467a2f9), + SPH_C32(0xe32859ee), SPH_C32(0x324dce4e), SPH_C32(0x06440000), + SPH_C32(0xc50a0000), SPH_C32(0x5b590000), SPH_C32(0xfb280149), + SPH_C32(0x061e0bd1), SPH_C32(0x190fe549), SPH_C32(0xf73b10a4), + SPH_C32(0x719386a6) }, + { SPH_C32(0xb5950000), SPH_C32(0xd5770000), SPH_C32(0x4e8b0000), + SPH_C32(0x6bae00b7), SPH_C32(0x50656bd6), SPH_C32(0x4f09c4e6), + SPH_C32(0xed8d960d), SPH_C32(0xd497b1b0), SPH_C32(0xae9e0000), + SPH_C32(0x53b40000), SPH_C32(0x07440000), SPH_C32(0xfcf2014b), + SPH_C32(0x7b789e52), SPH_C32(0x069795c3), SPH_C32(0x4c5d98ac), + SPH_C32(0xab1406a6) }, + { SPH_C32(0x1e720000), SPH_C32(0x4b7a0000), SPH_C32(0xe1ac0000), + SPH_C32(0x56b600b2), SPH_C32(0x7c2a7405), SPH_C32(0x3bffd273), + SPH_C32(0x584ed1e6), SPH_C32(0xe8ca4e4e), SPH_C32(0xada30000), + SPH_C32(0x5b070000), SPH_C32(0xf47e0000), SPH_C32(0xc630014c), + SPH_C32(0x2a511402), SPH_C32(0x6df9f3dc), SPH_C32(0x42f8574f), + SPH_C32(0x4dce7958) }, + { SPH_C32(0x1d4f0000), SPH_C32(0x43c90000), SPH_C32(0x12960000), + SPH_C32(0x6c7400b5), SPH_C32(0x2d03fe55), SPH_C32(0x5091b46c), + SPH_C32(0x56eb1e05), SPH_C32(0x0e1031b0), SPH_C32(0x05790000), + SPH_C32(0xcdb90000), SPH_C32(0xa8630000), SPH_C32(0xc1ea014e), + SPH_C32(0x57378181), SPH_C32(0x72618356), SPH_C32(0xf99edf47), + SPH_C32(0x9749f958) }, + { SPH_C32(0xb73b0000), SPH_C32(0x3a460000), SPH_C32(0x504a0000), + SPH_C32(0x9e6000bb), SPH_C32(0x8c9c6cde), SPH_C32(0x98c416d7), + SPH_C32(0xe51e380f), SPH_C32(0x61225035), SPH_C32(0x946c0000), + SPH_C32(0x198f0000), SPH_C32(0x0ca30000), SPH_C32(0xadf4014a), + SPH_C32(0xbcf728c7), SPH_C32(0x43e04645), SPH_C32(0x67f5e7f6), + SPH_C32(0x0a85f371) }, + { SPH_C32(0xb4060000), SPH_C32(0x32f50000), SPH_C32(0xa3700000), + SPH_C32(0xa4a200bc), SPH_C32(0xddb5e68e), SPH_C32(0xf3aa70c8), + SPH_C32(0xebbbf7ec), SPH_C32(0x87f82fcb), SPH_C32(0x3cb60000), + SPH_C32(0x8f310000), SPH_C32(0x50be0000), SPH_C32(0xaa2e0148), + SPH_C32(0xc191bd44), SPH_C32(0x5c7836cf), SPH_C32(0xdc936ffe), + SPH_C32(0xd0027371) }, + { SPH_C32(0x1fe10000), SPH_C32(0xacf80000), SPH_C32(0x0c570000), + SPH_C32(0x99ba00b9), SPH_C32(0xf1faf95d), SPH_C32(0x875c665d), + SPH_C32(0x5e78b007), SPH_C32(0xbba5d035), SPH_C32(0x3f8b0000), + SPH_C32(0x87820000), SPH_C32(0xa3840000), SPH_C32(0x90ec014f), + SPH_C32(0x90b83714), SPH_C32(0x371650d0), SPH_C32(0xd236a01d), + SPH_C32(0x36d80c8f) }, + { SPH_C32(0x1cdc0000), SPH_C32(0xa44b0000), SPH_C32(0xff6d0000), + SPH_C32(0xa37800be), SPH_C32(0xa0d3730d), SPH_C32(0xec320042), + SPH_C32(0x50dd7fe4), SPH_C32(0x5d7fafcb), SPH_C32(0x97510000), + SPH_C32(0x113c0000), SPH_C32(0xff990000), SPH_C32(0x9736014d), + SPH_C32(0xeddea297), SPH_C32(0x288e205a), SPH_C32(0x69502815), + SPH_C32(0xec5f8c8f) }, + { SPH_C32(0x7b6c0000), SPH_C32(0x280a0000), SPH_C32(0x73990000), + SPH_C32(0x496000a1), SPH_C32(0xa5768de3), SPH_C32(0xc42f093c), + SPH_C32(0x24f2a563), SPH_C32(0x79f5076e), SPH_C32(0xca570000), + SPH_C32(0xa80e0000), SPH_C32(0xa2f60000), SPH_C32(0x060b0152), + SPH_C32(0x14592320), SPH_C32(0xec526625), SPH_C32(0x35dd13a8), + SPH_C32(0xd74eb663) }, + { SPH_C32(0x78510000), SPH_C32(0x20b90000), SPH_C32(0x80a30000), + SPH_C32(0x73a200a6), SPH_C32(0xf45f07b3), SPH_C32(0xaf416f23), + SPH_C32(0x2a576a80), SPH_C32(0x9f2f7890), SPH_C32(0x628d0000), + SPH_C32(0x3eb00000), SPH_C32(0xfeeb0000), SPH_C32(0x01d10150), + SPH_C32(0x693fb6a3), SPH_C32(0xf3ca16af), SPH_C32(0x8ebb9ba0), + SPH_C32(0x0dc93663) }, + { SPH_C32(0xd3b60000), SPH_C32(0xbeb40000), SPH_C32(0x2f840000), + SPH_C32(0x4eba00a3), SPH_C32(0xd8101860), SPH_C32(0xdbb779b6), + SPH_C32(0x9f942d6b), SPH_C32(0xa372876e), SPH_C32(0x61b00000), + SPH_C32(0x36030000), SPH_C32(0x0dd10000), SPH_C32(0x3b130157), + SPH_C32(0x38163cf3), SPH_C32(0x98a470b0), SPH_C32(0x801e5443), + SPH_C32(0xeb13499d) }, + { SPH_C32(0xd08b0000), SPH_C32(0xb6070000), SPH_C32(0xdcbe0000), + SPH_C32(0x747800a4), SPH_C32(0x89399230), SPH_C32(0xb0d91fa9), + SPH_C32(0x9131e288), SPH_C32(0x45a8f890), SPH_C32(0xc96a0000), + SPH_C32(0xa0bd0000), SPH_C32(0x51cc0000), SPH_C32(0x3cc90155), + SPH_C32(0x4570a970), SPH_C32(0x873c003a), SPH_C32(0x3b78dc4b), + SPH_C32(0x3194c99d) }, + { SPH_C32(0x7aff0000), SPH_C32(0xcf880000), SPH_C32(0x9e620000), + SPH_C32(0x866c00aa), SPH_C32(0x28a600bb), SPH_C32(0x788cbd12), + SPH_C32(0x22c4c482), SPH_C32(0x2a9a9915), SPH_C32(0x587f0000), + SPH_C32(0x748b0000), SPH_C32(0xf50c0000), SPH_C32(0x50d70151), + SPH_C32(0xaeb00036), SPH_C32(0xb6bdc529), SPH_C32(0xa513e4fa), + SPH_C32(0xac58c3b4) }, + { SPH_C32(0x79c20000), SPH_C32(0xc73b0000), SPH_C32(0x6d580000), + SPH_C32(0xbcae00ad), SPH_C32(0x798f8aeb), SPH_C32(0x13e2db0d), + SPH_C32(0x2c610b61), SPH_C32(0xcc40e6eb), SPH_C32(0xf0a50000), + SPH_C32(0xe2350000), SPH_C32(0xa9110000), SPH_C32(0x570d0153), + SPH_C32(0xd3d695b5), SPH_C32(0xa925b5a3), SPH_C32(0x1e756cf2), + SPH_C32(0x76df43b4) }, + { SPH_C32(0xd2250000), SPH_C32(0x59360000), SPH_C32(0xc27f0000), + SPH_C32(0x81b600a8), SPH_C32(0x55c09538), SPH_C32(0x6714cd98), + SPH_C32(0x99a24c8a), SPH_C32(0xf01d1915), SPH_C32(0xf3980000), + SPH_C32(0xea860000), SPH_C32(0x5a2b0000), SPH_C32(0x6dcf0154), + SPH_C32(0x82ff1fe5), SPH_C32(0xc24bd3bc), SPH_C32(0x10d0a311), + SPH_C32(0x90053c4a) }, + { SPH_C32(0xd1180000), SPH_C32(0x51850000), SPH_C32(0x31450000), + SPH_C32(0xbb7400af), SPH_C32(0x04e91f68), SPH_C32(0x0c7aab87), + SPH_C32(0x97078369), SPH_C32(0x16c766eb), SPH_C32(0x5b420000), + SPH_C32(0x7c380000), SPH_C32(0x06360000), SPH_C32(0x6a150156), + SPH_C32(0xff998a66), SPH_C32(0xddd3a336), SPH_C32(0xabb62b19), + SPH_C32(0x4a82bc4a) }, + { SPH_C32(0xe9440000), SPH_C32(0xf48f0000), SPH_C32(0x24630000), + SPH_C32(0x1fbc00a2), SPH_C32(0x1f9faef5), SPH_C32(0x9ec0aa30), + SPH_C32(0xb43c5231), SPH_C32(0x02e372b9), SPH_C32(0x59ec0000), + SPH_C32(0x93090000), SPH_C32(0x18f70000), SPH_C32(0x9fdb015a), + SPH_C32(0x23608d6e), SPH_C32(0x0a1e7107), SPH_C32(0xa325851b), + SPH_C32(0xff375dcf) }, + { SPH_C32(0xea790000), SPH_C32(0xfc3c0000), SPH_C32(0xd7590000), + SPH_C32(0x257e00a5), SPH_C32(0x4eb624a5), SPH_C32(0xf5aecc2f), + SPH_C32(0xba999dd2), SPH_C32(0xe4390d47), SPH_C32(0xf1360000), + SPH_C32(0x05b70000), SPH_C32(0x44ea0000), SPH_C32(0x98010158), + SPH_C32(0x5e0618ed), SPH_C32(0x1586018d), SPH_C32(0x18430d13), + SPH_C32(0x25b0ddcf) }, + { SPH_C32(0x419e0000), SPH_C32(0x62310000), SPH_C32(0x787e0000), + SPH_C32(0x186600a0), SPH_C32(0x62f93b76), SPH_C32(0x8158daba), + SPH_C32(0x0f5ada39), SPH_C32(0xd864f2b9), SPH_C32(0xf20b0000), + SPH_C32(0x0d040000), SPH_C32(0xb7d00000), SPH_C32(0xa2c3015f), + SPH_C32(0x0f2f92bd), SPH_C32(0x7ee86792), SPH_C32(0x16e6c2f0), + SPH_C32(0xc36aa231) }, + { SPH_C32(0x42a30000), SPH_C32(0x6a820000), SPH_C32(0x8b440000), + SPH_C32(0x22a400a7), SPH_C32(0x33d0b126), SPH_C32(0xea36bca5), + SPH_C32(0x01ff15da), SPH_C32(0x3ebe8d47), SPH_C32(0x5ad10000), + SPH_C32(0x9bba0000), SPH_C32(0xebcd0000), SPH_C32(0xa519015d), + SPH_C32(0x7249073e), SPH_C32(0x61701718), SPH_C32(0xad804af8), + SPH_C32(0x19ed2231) }, + { SPH_C32(0xe8d70000), SPH_C32(0x130d0000), SPH_C32(0xc9980000), + SPH_C32(0xd0b000a9), SPH_C32(0x924f23ad), SPH_C32(0x22631e1e), + SPH_C32(0xb20a33d0), SPH_C32(0x518cecc2), SPH_C32(0xcbc40000), + SPH_C32(0x4f8c0000), SPH_C32(0x4f0d0000), SPH_C32(0xc9070159), + SPH_C32(0x9989ae78), SPH_C32(0x50f1d20b), SPH_C32(0x33eb7249), + SPH_C32(0x84212818) }, + { SPH_C32(0xebea0000), SPH_C32(0x1bbe0000), SPH_C32(0x3aa20000), + SPH_C32(0xea7200ae), SPH_C32(0xc366a9fd), SPH_C32(0x490d7801), + SPH_C32(0xbcaffc33), SPH_C32(0xb756933c), SPH_C32(0x631e0000), + SPH_C32(0xd9320000), SPH_C32(0x13100000), SPH_C32(0xcedd015b), + SPH_C32(0xe4ef3bfb), SPH_C32(0x4f69a281), SPH_C32(0x888dfa41), + SPH_C32(0x5ea6a818) }, + { SPH_C32(0x400d0000), SPH_C32(0x85b30000), SPH_C32(0x95850000), + SPH_C32(0xd76a00ab), SPH_C32(0xef29b62e), SPH_C32(0x3dfb6e94), + SPH_C32(0x096cbbd8), SPH_C32(0x8b0b6cc2), SPH_C32(0x60230000), + SPH_C32(0xd1810000), SPH_C32(0xe02a0000), SPH_C32(0xf41f015c), + SPH_C32(0xb5c6b1ab), SPH_C32(0x2407c49e), SPH_C32(0x862835a2), + SPH_C32(0xb87cd7e6) }, + { SPH_C32(0x43300000), SPH_C32(0x8d000000), SPH_C32(0x66bf0000), + SPH_C32(0xeda800ac), SPH_C32(0xbe003c7e), SPH_C32(0x5695088b), + SPH_C32(0x07c9743b), SPH_C32(0x6dd1133c), SPH_C32(0xc8f90000), + SPH_C32(0x473f0000), SPH_C32(0xbc370000), SPH_C32(0xf3c5015e), + SPH_C32(0xc8a02428), SPH_C32(0x3b9fb414), SPH_C32(0x3d4ebdaa), + SPH_C32(0x62fb57e6) }, + { SPH_C32(0x24c40000), SPH_C32(0x7e090000), SPH_C32(0x30370000), + SPH_C32(0x2d9300b2), SPH_C32(0x80080b5c), SPH_C32(0xd73e9d72), + SPH_C32(0x70ec30dc), SPH_C32(0xf751dc07), SPH_C32(0xca130000), + SPH_C32(0xd7460000), SPH_C32(0x788a0000), SPH_C32(0x2c280153), + SPH_C32(0x2ff4eaec), SPH_C32(0x45e4faa2), SPH_C32(0x36d78dc8), + SPH_C32(0x6944d1fd) }, + { SPH_C32(0x27f90000), SPH_C32(0x76ba0000), SPH_C32(0xc30d0000), + SPH_C32(0x175100b5), SPH_C32(0xd121810c), SPH_C32(0xbc50fb6d), + SPH_C32(0x7e49ff3f), SPH_C32(0x118ba3f9), SPH_C32(0x62c90000), + SPH_C32(0x41f80000), SPH_C32(0x24970000), SPH_C32(0x2bf20151), + SPH_C32(0x52927f6f), SPH_C32(0x5a7c8a28), SPH_C32(0x8db105c0), + SPH_C32(0xb3c351fd) }, + { SPH_C32(0x8c1e0000), SPH_C32(0xe8b70000), SPH_C32(0x6c2a0000), + SPH_C32(0x2a4900b0), SPH_C32(0xfd6e9edf), SPH_C32(0xc8a6edf8), + SPH_C32(0xcb8ab8d4), SPH_C32(0x2dd65c07), SPH_C32(0x61f40000), + SPH_C32(0x494b0000), SPH_C32(0xd7ad0000), SPH_C32(0x11300156), + SPH_C32(0x03bbf53f), SPH_C32(0x3112ec37), SPH_C32(0x8314ca23), + SPH_C32(0x55192e03) }, + { SPH_C32(0x8f230000), SPH_C32(0xe0040000), SPH_C32(0x9f100000), + SPH_C32(0x108b00b7), SPH_C32(0xac47148f), SPH_C32(0xa3c88be7), + SPH_C32(0xc52f7737), SPH_C32(0xcb0c23f9), SPH_C32(0xc92e0000), + SPH_C32(0xdff50000), SPH_C32(0x8bb00000), SPH_C32(0x16ea0154), + SPH_C32(0x7edd60bc), SPH_C32(0x2e8a9cbd), SPH_C32(0x3872422b), + SPH_C32(0x8f9eae03) }, + { SPH_C32(0x25570000), SPH_C32(0x998b0000), SPH_C32(0xddcc0000), + SPH_C32(0xe29f00b9), SPH_C32(0x0dd88604), SPH_C32(0x6b9d295c), + SPH_C32(0x76da513d), SPH_C32(0xa43e427c), SPH_C32(0x583b0000), + SPH_C32(0x0bc30000), SPH_C32(0x2f700000), SPH_C32(0x7af40150), + SPH_C32(0x951dc9fa), SPH_C32(0x1f0b59ae), SPH_C32(0xa6197a9a), + SPH_C32(0x1252a42a) }, + { SPH_C32(0x266a0000), SPH_C32(0x91380000), SPH_C32(0x2ef60000), + SPH_C32(0xd85d00be), SPH_C32(0x5cf10c54), SPH_C32(0x00f34f43), + SPH_C32(0x787f9ede), SPH_C32(0x42e43d82), SPH_C32(0xf0e10000), + SPH_C32(0x9d7d0000), SPH_C32(0x736d0000), SPH_C32(0x7d2e0152), + SPH_C32(0xe87b5c79), SPH_C32(0x00932924), SPH_C32(0x1d7ff292), + SPH_C32(0xc8d5242a) }, + { SPH_C32(0x8d8d0000), SPH_C32(0x0f350000), SPH_C32(0x81d10000), + SPH_C32(0xe54500bb), SPH_C32(0x70be1387), SPH_C32(0x740559d6), + SPH_C32(0xcdbcd935), SPH_C32(0x7eb9c27c), SPH_C32(0xf3dc0000), + SPH_C32(0x95ce0000), SPH_C32(0x80570000), SPH_C32(0x47ec0155), + SPH_C32(0xb952d629), SPH_C32(0x6bfd4f3b), SPH_C32(0x13da3d71), + SPH_C32(0x2e0f5bd4) }, + { SPH_C32(0x8eb00000), SPH_C32(0x07860000), SPH_C32(0x72eb0000), + SPH_C32(0xdf8700bc), SPH_C32(0x219799d7), SPH_C32(0x1f6b3fc9), + SPH_C32(0xc31916d6), SPH_C32(0x9863bd82), SPH_C32(0x5b060000), + SPH_C32(0x03700000), SPH_C32(0xdc4a0000), SPH_C32(0x40360157), + SPH_C32(0xc43443aa), SPH_C32(0x74653fb1), SPH_C32(0xa8bcb579), + SPH_C32(0xf488dbd4) }, + { SPH_C32(0xb6ec0000), SPH_C32(0xa28c0000), SPH_C32(0x67cd0000), + SPH_C32(0x7b4f00b1), SPH_C32(0x3ae1284a), SPH_C32(0x8dd13e7e), + SPH_C32(0xe022c78e), SPH_C32(0x8c47a9d0), SPH_C32(0x59a80000), + SPH_C32(0xec410000), SPH_C32(0xc28b0000), SPH_C32(0xb5f8015b), + SPH_C32(0x18cd44a2), SPH_C32(0xa3a8ed80), SPH_C32(0xa02f1b7b), + SPH_C32(0x413d3a51) }, + { SPH_C32(0xb5d10000), SPH_C32(0xaa3f0000), SPH_C32(0x94f70000), + SPH_C32(0x418d00b6), SPH_C32(0x6bc8a21a), SPH_C32(0xe6bf5861), + SPH_C32(0xee87086d), SPH_C32(0x6a9dd62e), SPH_C32(0xf1720000), + SPH_C32(0x7aff0000), SPH_C32(0x9e960000), SPH_C32(0xb2220159), + SPH_C32(0x65abd121), SPH_C32(0xbc309d0a), SPH_C32(0x1b499373), + SPH_C32(0x9bbaba51) }, + { SPH_C32(0x1e360000), SPH_C32(0x34320000), SPH_C32(0x3bd00000), + SPH_C32(0x7c9500b3), SPH_C32(0x4787bdc9), SPH_C32(0x92494ef4), + SPH_C32(0x5b444f86), SPH_C32(0x56c029d0), SPH_C32(0xf24f0000), + SPH_C32(0x724c0000), SPH_C32(0x6dac0000), SPH_C32(0x88e0015e), + SPH_C32(0x34825b71), SPH_C32(0xd75efb15), SPH_C32(0x15ec5c90), + SPH_C32(0x7d60c5af) }, + { SPH_C32(0x1d0b0000), SPH_C32(0x3c810000), SPH_C32(0xc8ea0000), + SPH_C32(0x465700b4), SPH_C32(0x16ae3799), SPH_C32(0xf92728eb), + SPH_C32(0x55e18065), SPH_C32(0xb01a562e), SPH_C32(0x5a950000), + SPH_C32(0xe4f20000), SPH_C32(0x31b10000), SPH_C32(0x8f3a015c), + SPH_C32(0x49e4cef2), SPH_C32(0xc8c68b9f), SPH_C32(0xae8ad498), + SPH_C32(0xa7e745af) }, + { SPH_C32(0xb77f0000), SPH_C32(0x450e0000), SPH_C32(0x8a360000), + SPH_C32(0xb44300ba), SPH_C32(0xb731a512), SPH_C32(0x31728a50), + SPH_C32(0xe614a66f), SPH_C32(0xdf2837ab), SPH_C32(0xcb800000), + SPH_C32(0x30c40000), SPH_C32(0x95710000), SPH_C32(0xe3240158), + SPH_C32(0xa22467b4), SPH_C32(0xf9474e8c), SPH_C32(0x30e1ec29), + SPH_C32(0x3a2b4f86) }, + { SPH_C32(0xb4420000), SPH_C32(0x4dbd0000), SPH_C32(0x790c0000), + SPH_C32(0x8e8100bd), SPH_C32(0xe6182f42), SPH_C32(0x5a1cec4f), + SPH_C32(0xe8b1698c), SPH_C32(0x39f24855), SPH_C32(0x635a0000), + SPH_C32(0xa67a0000), SPH_C32(0xc96c0000), SPH_C32(0xe4fe015a), + SPH_C32(0xdf42f237), SPH_C32(0xe6df3e06), SPH_C32(0x8b876421), + SPH_C32(0xe0accf86) }, + { SPH_C32(0x1fa50000), SPH_C32(0xd3b00000), SPH_C32(0xd62b0000), + SPH_C32(0xb39900b8), SPH_C32(0xca573091), SPH_C32(0x2eeafada), + SPH_C32(0x5d722e67), SPH_C32(0x05afb7ab), SPH_C32(0x60670000), + SPH_C32(0xaec90000), SPH_C32(0x3a560000), SPH_C32(0xde3c015d), + SPH_C32(0x8e6b7867), SPH_C32(0x8db15819), SPH_C32(0x8522abc2), + SPH_C32(0x0676b078) }, + { SPH_C32(0x1c980000), SPH_C32(0xdb030000), SPH_C32(0x25110000), + SPH_C32(0x895b00bf), SPH_C32(0x9b7ebac1), SPH_C32(0x45849cc5), + SPH_C32(0x53d7e184), SPH_C32(0xe375c855), SPH_C32(0xc8bd0000), + SPH_C32(0x38770000), SPH_C32(0x664b0000), SPH_C32(0xd9e6015f), + SPH_C32(0xf30dede4), SPH_C32(0x92292893), SPH_C32(0x3e4423ca), + SPH_C32(0xdcf13078) }, + { SPH_C32(0x95bb0000), SPH_C32(0x81450000), SPH_C32(0x3b240000), + SPH_C32(0x48db0140), SPH_C32(0x0a8a6c53), SPH_C32(0x56f56eec), + SPH_C32(0x62c91877), SPH_C32(0xe7e00a94), SPH_C32(0xee930000), + SPH_C32(0xd6070000), SPH_C32(0x92c10000), SPH_C32(0x2b9801e0), + SPH_C32(0x9451287c), SPH_C32(0x3b6cfb57), SPH_C32(0x45312374), + SPH_C32(0x201f6a64) }, + { SPH_C32(0x96860000), SPH_C32(0x89f60000), SPH_C32(0xc81e0000), + SPH_C32(0x72190147), SPH_C32(0x5ba3e603), SPH_C32(0x3d9b08f3), + SPH_C32(0x6c6cd794), SPH_C32(0x013a756a), SPH_C32(0x46490000), + SPH_C32(0x40b90000), SPH_C32(0xcedc0000), SPH_C32(0x2c4201e2), + SPH_C32(0xe937bdff), SPH_C32(0x24f48bdd), SPH_C32(0xfe57ab7c), + SPH_C32(0xfa98ea64) }, + { SPH_C32(0x3d610000), SPH_C32(0x17fb0000), SPH_C32(0x67390000), + SPH_C32(0x4f010142), SPH_C32(0x77ecf9d0), SPH_C32(0x496d1e66), + SPH_C32(0xd9af907f), SPH_C32(0x3d678a94), SPH_C32(0x45740000), + SPH_C32(0x480a0000), SPH_C32(0x3de60000), SPH_C32(0x168001e5), + SPH_C32(0xb81e37af), SPH_C32(0x4f9aedc2), SPH_C32(0xf0f2649f), + SPH_C32(0x1c42959a) }, + { SPH_C32(0x3e5c0000), SPH_C32(0x1f480000), SPH_C32(0x94030000), + SPH_C32(0x75c30145), SPH_C32(0x26c57380), SPH_C32(0x22037879), + SPH_C32(0xd70a5f9c), SPH_C32(0xdbbdf56a), SPH_C32(0xedae0000), + SPH_C32(0xdeb40000), SPH_C32(0x61fb0000), SPH_C32(0x115a01e7), + SPH_C32(0xc578a22c), SPH_C32(0x50029d48), SPH_C32(0x4b94ec97), + SPH_C32(0xc6c5159a) }, + { SPH_C32(0x94280000), SPH_C32(0x66c70000), SPH_C32(0xd6df0000), + SPH_C32(0x87d7014b), SPH_C32(0x875ae10b), SPH_C32(0xea56dac2), + SPH_C32(0x64ff7996), SPH_C32(0xb48f94ef), SPH_C32(0x7cbb0000), + SPH_C32(0x0a820000), SPH_C32(0xc53b0000), SPH_C32(0x7d4401e3), + SPH_C32(0x2eb80b6a), SPH_C32(0x6183585b), SPH_C32(0xd5ffd426), + SPH_C32(0x5b091fb3) }, + { SPH_C32(0x97150000), SPH_C32(0x6e740000), SPH_C32(0x25e50000), + SPH_C32(0xbd15014c), SPH_C32(0xd6736b5b), SPH_C32(0x8138bcdd), + SPH_C32(0x6a5ab675), SPH_C32(0x5255eb11), SPH_C32(0xd4610000), + SPH_C32(0x9c3c0000), SPH_C32(0x99260000), SPH_C32(0x7a9e01e1), + SPH_C32(0x53de9ee9), SPH_C32(0x7e1b28d1), SPH_C32(0x6e995c2e), + SPH_C32(0x818e9fb3) }, + { SPH_C32(0x3cf20000), SPH_C32(0xf0790000), SPH_C32(0x8ac20000), + SPH_C32(0x800d0149), SPH_C32(0xfa3c7488), SPH_C32(0xf5ceaa48), + SPH_C32(0xdf99f19e), SPH_C32(0x6e0814ef), SPH_C32(0xd75c0000), + SPH_C32(0x948f0000), SPH_C32(0x6a1c0000), SPH_C32(0x405c01e6), + SPH_C32(0x02f714b9), SPH_C32(0x15754ece), SPH_C32(0x603c93cd), + SPH_C32(0x6754e04d) }, + { SPH_C32(0x3fcf0000), SPH_C32(0xf8ca0000), SPH_C32(0x79f80000), + SPH_C32(0xbacf014e), SPH_C32(0xab15fed8), SPH_C32(0x9ea0cc57), + SPH_C32(0xd13c3e7d), SPH_C32(0x88d26b11), SPH_C32(0x7f860000), + SPH_C32(0x02310000), SPH_C32(0x36010000), SPH_C32(0x478601e4), + SPH_C32(0x7f91813a), SPH_C32(0x0aed3e44), SPH_C32(0xdb5a1bc5), + SPH_C32(0xbdd3604d) }, + { SPH_C32(0x07930000), SPH_C32(0x5dc00000), SPH_C32(0x6cde0000), + SPH_C32(0x1e070143), SPH_C32(0xb0634f45), SPH_C32(0x0c1acde0), + SPH_C32(0xf207ef25), SPH_C32(0x9cf67f43), SPH_C32(0x7d280000), + SPH_C32(0xed000000), SPH_C32(0x28c00000), SPH_C32(0xb24801e8), + SPH_C32(0xa3688632), SPH_C32(0xdd20ec75), SPH_C32(0xd3c9b5c7), + SPH_C32(0x086681c8) }, + { SPH_C32(0x04ae0000), SPH_C32(0x55730000), SPH_C32(0x9fe40000), + SPH_C32(0x24c50144), SPH_C32(0xe14ac515), SPH_C32(0x6774abff), + SPH_C32(0xfca220c6), SPH_C32(0x7a2c00bd), SPH_C32(0xd5f20000), + SPH_C32(0x7bbe0000), SPH_C32(0x74dd0000), SPH_C32(0xb59201ea), + SPH_C32(0xde0e13b1), SPH_C32(0xc2b89cff), SPH_C32(0x68af3dcf), + SPH_C32(0xd2e101c8) }, + { SPH_C32(0xaf490000), SPH_C32(0xcb7e0000), SPH_C32(0x30c30000), + SPH_C32(0x19dd0141), SPH_C32(0xcd05dac6), SPH_C32(0x1382bd6a), + SPH_C32(0x4961672d), SPH_C32(0x4671ff43), SPH_C32(0xd6cf0000), + SPH_C32(0x730d0000), SPH_C32(0x87e70000), SPH_C32(0x8f5001ed), + SPH_C32(0x8f2799e1), SPH_C32(0xa9d6fae0), SPH_C32(0x660af22c), + SPH_C32(0x343b7e36) }, + { SPH_C32(0xac740000), SPH_C32(0xc3cd0000), SPH_C32(0xc3f90000), + SPH_C32(0x231f0146), SPH_C32(0x9c2c5096), SPH_C32(0x78ecdb75), + SPH_C32(0x47c4a8ce), SPH_C32(0xa0ab80bd), SPH_C32(0x7e150000), + SPH_C32(0xe5b30000), SPH_C32(0xdbfa0000), SPH_C32(0x888a01ef), + SPH_C32(0xf2410c62), SPH_C32(0xb64e8a6a), SPH_C32(0xdd6c7a24), + SPH_C32(0xeebcfe36) }, + { SPH_C32(0x06000000), SPH_C32(0xba420000), SPH_C32(0x81250000), + SPH_C32(0xd10b0148), SPH_C32(0x3db3c21d), SPH_C32(0xb0b979ce), + SPH_C32(0xf4318ec4), SPH_C32(0xcf99e138), SPH_C32(0xef000000), + SPH_C32(0x31850000), SPH_C32(0x7f3a0000), SPH_C32(0xe49401eb), + SPH_C32(0x1981a524), SPH_C32(0x87cf4f79), SPH_C32(0x43074295), + SPH_C32(0x7370f41f) }, + { SPH_C32(0x053d0000), SPH_C32(0xb2f10000), SPH_C32(0x721f0000), + SPH_C32(0xebc9014f), SPH_C32(0x6c9a484d), SPH_C32(0xdbd71fd1), + SPH_C32(0xfa944127), SPH_C32(0x29439ec6), SPH_C32(0x47da0000), + SPH_C32(0xa73b0000), SPH_C32(0x23270000), SPH_C32(0xe34e01e9), + SPH_C32(0x64e730a7), SPH_C32(0x98573ff3), SPH_C32(0xf861ca9d), + SPH_C32(0xa9f7741f) }, + { SPH_C32(0xaeda0000), SPH_C32(0x2cfc0000), SPH_C32(0xdd380000), + SPH_C32(0xd6d1014a), SPH_C32(0x40d5579e), SPH_C32(0xaf210944), + SPH_C32(0x4f5706cc), SPH_C32(0x151e6138), SPH_C32(0x44e70000), + SPH_C32(0xaf880000), SPH_C32(0xd01d0000), SPH_C32(0xd98c01ee), + SPH_C32(0x35cebaf7), SPH_C32(0xf33959ec), SPH_C32(0xf6c4057e), + SPH_C32(0x4f2d0be1) }, + { SPH_C32(0xade70000), SPH_C32(0x244f0000), SPH_C32(0x2e020000), + SPH_C32(0xec13014d), SPH_C32(0x11fcddce), SPH_C32(0xc44f6f5b), + SPH_C32(0x41f2c92f), SPH_C32(0xf3c41ec6), SPH_C32(0xec3d0000), + SPH_C32(0x39360000), SPH_C32(0x8c000000), SPH_C32(0xde5601ec), + SPH_C32(0x48a82f74), SPH_C32(0xeca12966), SPH_C32(0x4da28d76), + SPH_C32(0x95aa8be1) }, + { SPH_C32(0xca130000), SPH_C32(0xd7460000), SPH_C32(0x788a0000), + SPH_C32(0x2c280153), SPH_C32(0x2ff4eaec), SPH_C32(0x45e4faa2), + SPH_C32(0x36d78dc8), SPH_C32(0x6944d1fd), SPH_C32(0xeed70000), + SPH_C32(0xa94f0000), SPH_C32(0x48bd0000), SPH_C32(0x01bb01e1), + SPH_C32(0xaffce1b0), SPH_C32(0x92da67d0), SPH_C32(0x463bbd14), + SPH_C32(0x9e150dfa) }, + { SPH_C32(0xc92e0000), SPH_C32(0xdff50000), SPH_C32(0x8bb00000), + SPH_C32(0x16ea0154), SPH_C32(0x7edd60bc), SPH_C32(0x2e8a9cbd), + SPH_C32(0x3872422b), SPH_C32(0x8f9eae03), SPH_C32(0x460d0000), + SPH_C32(0x3ff10000), SPH_C32(0x14a00000), SPH_C32(0x066101e3), + SPH_C32(0xd29a7433), SPH_C32(0x8d42175a), SPH_C32(0xfd5d351c), + SPH_C32(0x44928dfa) }, + { SPH_C32(0x62c90000), SPH_C32(0x41f80000), SPH_C32(0x24970000), + SPH_C32(0x2bf20151), SPH_C32(0x52927f6f), SPH_C32(0x5a7c8a28), + SPH_C32(0x8db105c0), SPH_C32(0xb3c351fd), SPH_C32(0x45300000), + SPH_C32(0x37420000), SPH_C32(0xe79a0000), SPH_C32(0x3ca301e4), + SPH_C32(0x83b3fe63), SPH_C32(0xe62c7145), SPH_C32(0xf3f8faff), + SPH_C32(0xa248f204) }, + { SPH_C32(0x61f40000), SPH_C32(0x494b0000), SPH_C32(0xd7ad0000), + SPH_C32(0x11300156), SPH_C32(0x03bbf53f), SPH_C32(0x3112ec37), + SPH_C32(0x8314ca23), SPH_C32(0x55192e03), SPH_C32(0xedea0000), + SPH_C32(0xa1fc0000), SPH_C32(0xbb870000), SPH_C32(0x3b7901e6), + SPH_C32(0xfed56be0), SPH_C32(0xf9b401cf), SPH_C32(0x489e72f7), + SPH_C32(0x78cf7204) }, + { SPH_C32(0xcb800000), SPH_C32(0x30c40000), SPH_C32(0x95710000), + SPH_C32(0xe3240158), SPH_C32(0xa22467b4), SPH_C32(0xf9474e8c), + SPH_C32(0x30e1ec29), SPH_C32(0x3a2b4f86), SPH_C32(0x7cff0000), + SPH_C32(0x75ca0000), SPH_C32(0x1f470000), SPH_C32(0x576701e2), + SPH_C32(0x1515c2a6), SPH_C32(0xc835c4dc), SPH_C32(0xd6f54a46), + SPH_C32(0xe503782d) }, + { SPH_C32(0xc8bd0000), SPH_C32(0x38770000), SPH_C32(0x664b0000), + SPH_C32(0xd9e6015f), SPH_C32(0xf30dede4), SPH_C32(0x92292893), + SPH_C32(0x3e4423ca), SPH_C32(0xdcf13078), SPH_C32(0xd4250000), + SPH_C32(0xe3740000), SPH_C32(0x435a0000), SPH_C32(0x50bd01e0), + SPH_C32(0x68735725), SPH_C32(0xd7adb456), SPH_C32(0x6d93c24e), + SPH_C32(0x3f84f82d) }, + { SPH_C32(0x635a0000), SPH_C32(0xa67a0000), SPH_C32(0xc96c0000), + SPH_C32(0xe4fe015a), SPH_C32(0xdf42f237), SPH_C32(0xe6df3e06), + SPH_C32(0x8b876421), SPH_C32(0xe0accf86), SPH_C32(0xd7180000), + SPH_C32(0xebc70000), SPH_C32(0xb0600000), SPH_C32(0x6a7f01e7), + SPH_C32(0x395add75), SPH_C32(0xbcc3d249), SPH_C32(0x63360dad), + SPH_C32(0xd95e87d3) }, + { SPH_C32(0x60670000), SPH_C32(0xaec90000), SPH_C32(0x3a560000), + SPH_C32(0xde3c015d), SPH_C32(0x8e6b7867), SPH_C32(0x8db15819), + SPH_C32(0x8522abc2), SPH_C32(0x0676b078), SPH_C32(0x7fc20000), + SPH_C32(0x7d790000), SPH_C32(0xec7d0000), SPH_C32(0x6da501e5), + SPH_C32(0x443c48f6), SPH_C32(0xa35ba2c3), SPH_C32(0xd85085a5), + SPH_C32(0x03d907d3) }, + { SPH_C32(0x583b0000), SPH_C32(0x0bc30000), SPH_C32(0x2f700000), + SPH_C32(0x7af40150), SPH_C32(0x951dc9fa), SPH_C32(0x1f0b59ae), + SPH_C32(0xa6197a9a), SPH_C32(0x1252a42a), SPH_C32(0x7d6c0000), + SPH_C32(0x92480000), SPH_C32(0xf2bc0000), SPH_C32(0x986b01e9), + SPH_C32(0x98c54ffe), SPH_C32(0x749670f2), SPH_C32(0xd0c32ba7), + SPH_C32(0xb66ce656) }, + { SPH_C32(0x5b060000), SPH_C32(0x03700000), SPH_C32(0xdc4a0000), + SPH_C32(0x40360157), SPH_C32(0xc43443aa), SPH_C32(0x74653fb1), + SPH_C32(0xa8bcb579), SPH_C32(0xf488dbd4), SPH_C32(0xd5b60000), + SPH_C32(0x04f60000), SPH_C32(0xaea10000), SPH_C32(0x9fb101eb), + SPH_C32(0xe5a3da7d), SPH_C32(0x6b0e0078), SPH_C32(0x6ba5a3af), + SPH_C32(0x6ceb6656) }, + { SPH_C32(0xf0e10000), SPH_C32(0x9d7d0000), SPH_C32(0x736d0000), + SPH_C32(0x7d2e0152), SPH_C32(0xe87b5c79), SPH_C32(0x00932924), + SPH_C32(0x1d7ff292), SPH_C32(0xc8d5242a), SPH_C32(0xd68b0000), + SPH_C32(0x0c450000), SPH_C32(0x5d9b0000), SPH_C32(0xa57301ec), + SPH_C32(0xb48a502d), SPH_C32(0x00606667), SPH_C32(0x65006c4c), + SPH_C32(0x8a3119a8) }, + { SPH_C32(0xf3dc0000), SPH_C32(0x95ce0000), SPH_C32(0x80570000), + SPH_C32(0x47ec0155), SPH_C32(0xb952d629), SPH_C32(0x6bfd4f3b), + SPH_C32(0x13da3d71), SPH_C32(0x2e0f5bd4), SPH_C32(0x7e510000), + SPH_C32(0x9afb0000), SPH_C32(0x01860000), SPH_C32(0xa2a901ee), + SPH_C32(0xc9ecc5ae), SPH_C32(0x1ff816ed), SPH_C32(0xde66e444), + SPH_C32(0x50b699a8) }, + { SPH_C32(0x59a80000), SPH_C32(0xec410000), SPH_C32(0xc28b0000), + SPH_C32(0xb5f8015b), SPH_C32(0x18cd44a2), SPH_C32(0xa3a8ed80), + SPH_C32(0xa02f1b7b), SPH_C32(0x413d3a51), SPH_C32(0xef440000), + SPH_C32(0x4ecd0000), SPH_C32(0xa5460000), SPH_C32(0xceb701ea), + SPH_C32(0x222c6ce8), SPH_C32(0x2e79d3fe), SPH_C32(0x400ddcf5), + SPH_C32(0xcd7a9381) }, + { SPH_C32(0x5a950000), SPH_C32(0xe4f20000), SPH_C32(0x31b10000), + SPH_C32(0x8f3a015c), SPH_C32(0x49e4cef2), SPH_C32(0xc8c68b9f), + SPH_C32(0xae8ad498), SPH_C32(0xa7e745af), SPH_C32(0x479e0000), + SPH_C32(0xd8730000), SPH_C32(0xf95b0000), SPH_C32(0xc96d01e8), + SPH_C32(0x5f4af96b), SPH_C32(0x31e1a374), SPH_C32(0xfb6b54fd), + SPH_C32(0x17fd1381) }, + { SPH_C32(0xf1720000), SPH_C32(0x7aff0000), SPH_C32(0x9e960000), + SPH_C32(0xb2220159), SPH_C32(0x65abd121), SPH_C32(0xbc309d0a), + SPH_C32(0x1b499373), SPH_C32(0x9bbaba51), SPH_C32(0x44a30000), + SPH_C32(0xd0c00000), SPH_C32(0x0a610000), SPH_C32(0xf3af01ef), + SPH_C32(0x0e63733b), SPH_C32(0x5a8fc56b), SPH_C32(0xf5ce9b1e), + SPH_C32(0xf1276c7f) }, + { SPH_C32(0xf24f0000), SPH_C32(0x724c0000), SPH_C32(0x6dac0000), + SPH_C32(0x88e0015e), SPH_C32(0x34825b71), SPH_C32(0xd75efb15), + SPH_C32(0x15ec5c90), SPH_C32(0x7d60c5af), SPH_C32(0xec790000), + SPH_C32(0x467e0000), SPH_C32(0x567c0000), SPH_C32(0xf47501ed), + SPH_C32(0x7305e6b8), SPH_C32(0x4517b5e1), SPH_C32(0x4ea81316), + SPH_C32(0x2ba0ec7f) }, + { SPH_C32(0x95ff0000), SPH_C32(0xfe0d0000), SPH_C32(0xe1580000), + SPH_C32(0x62f80141), SPH_C32(0x3127a59f), SPH_C32(0xff43f26b), + SPH_C32(0x61c38617), SPH_C32(0x59ea6d0a), SPH_C32(0xb17f0000), + SPH_C32(0xff4c0000), SPH_C32(0x0b130000), SPH_C32(0x654801f2), + SPH_C32(0x8a82670f), SPH_C32(0x81cbf39e), SPH_C32(0x122528ab), + SPH_C32(0x10b1d693) }, + { SPH_C32(0x96c20000), SPH_C32(0xf6be0000), SPH_C32(0x12620000), + SPH_C32(0x583a0146), SPH_C32(0x600e2fcf), SPH_C32(0x942d9474), + SPH_C32(0x6f6649f4), SPH_C32(0xbf3012f4), SPH_C32(0x19a50000), + SPH_C32(0x69f20000), SPH_C32(0x570e0000), SPH_C32(0x629201f0), + SPH_C32(0xf7e4f28c), SPH_C32(0x9e538314), SPH_C32(0xa943a0a3), + SPH_C32(0xca365693) }, + { SPH_C32(0x3d250000), SPH_C32(0x68b30000), SPH_C32(0xbd450000), + SPH_C32(0x65220143), SPH_C32(0x4c41301c), SPH_C32(0xe0db82e1), + SPH_C32(0xdaa50e1f), SPH_C32(0x836ded0a), SPH_C32(0x1a980000), + SPH_C32(0x61410000), SPH_C32(0xa4340000), SPH_C32(0x585001f7), + SPH_C32(0xa6cd78dc), SPH_C32(0xf53de50b), SPH_C32(0xa7e66f40), + SPH_C32(0x2cec296d) }, + { SPH_C32(0x3e180000), SPH_C32(0x60000000), SPH_C32(0x4e7f0000), + SPH_C32(0x5fe00144), SPH_C32(0x1d68ba4c), SPH_C32(0x8bb5e4fe), + SPH_C32(0xd400c1fc), SPH_C32(0x65b792f4), SPH_C32(0xb2420000), + SPH_C32(0xf7ff0000), SPH_C32(0xf8290000), SPH_C32(0x5f8a01f5), + SPH_C32(0xdbabed5f), SPH_C32(0xeaa59581), SPH_C32(0x1c80e748), + SPH_C32(0xf66ba96d) }, + { SPH_C32(0x946c0000), SPH_C32(0x198f0000), SPH_C32(0x0ca30000), + SPH_C32(0xadf4014a), SPH_C32(0xbcf728c7), SPH_C32(0x43e04645), + SPH_C32(0x67f5e7f6), SPH_C32(0x0a85f371), SPH_C32(0x23570000), + SPH_C32(0x23c90000), SPH_C32(0x5ce90000), SPH_C32(0x339401f1), + SPH_C32(0x306b4419), SPH_C32(0xdb245092), SPH_C32(0x82ebdff9), + SPH_C32(0x6ba7a344) }, + { SPH_C32(0x97510000), SPH_C32(0x113c0000), SPH_C32(0xff990000), + SPH_C32(0x9736014d), SPH_C32(0xeddea297), SPH_C32(0x288e205a), + SPH_C32(0x69502815), SPH_C32(0xec5f8c8f), SPH_C32(0x8b8d0000), + SPH_C32(0xb5770000), SPH_C32(0x00f40000), SPH_C32(0x344e01f3), + SPH_C32(0x4d0dd19a), SPH_C32(0xc4bc2018), SPH_C32(0x398d57f1), + SPH_C32(0xb1202344) }, + { SPH_C32(0x3cb60000), SPH_C32(0x8f310000), SPH_C32(0x50be0000), + SPH_C32(0xaa2e0148), SPH_C32(0xc191bd44), SPH_C32(0x5c7836cf), + SPH_C32(0xdc936ffe), SPH_C32(0xd0027371), SPH_C32(0x88b00000), + SPH_C32(0xbdc40000), SPH_C32(0xf3ce0000), SPH_C32(0x0e8c01f4), + SPH_C32(0x1c245bca), SPH_C32(0xafd24607), SPH_C32(0x37289812), + SPH_C32(0x57fa5cba) }, + { SPH_C32(0x3f8b0000), SPH_C32(0x87820000), SPH_C32(0xa3840000), + SPH_C32(0x90ec014f), SPH_C32(0x90b83714), SPH_C32(0x371650d0), + SPH_C32(0xd236a01d), SPH_C32(0x36d80c8f), SPH_C32(0x206a0000), + SPH_C32(0x2b7a0000), SPH_C32(0xafd30000), SPH_C32(0x095601f6), + SPH_C32(0x6142ce49), SPH_C32(0xb04a368d), SPH_C32(0x8c4e101a), + SPH_C32(0x8d7ddcba) }, + { SPH_C32(0x07d70000), SPH_C32(0x22880000), SPH_C32(0xb6a20000), + SPH_C32(0x34240142), SPH_C32(0x8bce8689), SPH_C32(0xa5ac5167), + SPH_C32(0xf10d7145), SPH_C32(0x22fc18dd), SPH_C32(0x22c40000), + SPH_C32(0xc44b0000), SPH_C32(0xb1120000), SPH_C32(0xfc9801fa), + SPH_C32(0xbdbbc941), SPH_C32(0x6787e4bc), SPH_C32(0x84ddbe18), + SPH_C32(0x38c83d3f) }, + { SPH_C32(0x04ea0000), SPH_C32(0x2a3b0000), SPH_C32(0x45980000), + SPH_C32(0x0ee60145), SPH_C32(0xdae70cd9), SPH_C32(0xcec23778), + SPH_C32(0xffa8bea6), SPH_C32(0xc4266723), SPH_C32(0x8a1e0000), + SPH_C32(0x52f50000), SPH_C32(0xed0f0000), SPH_C32(0xfb4201f8), + SPH_C32(0xc0dd5cc2), SPH_C32(0x781f9436), SPH_C32(0x3fbb3610), + SPH_C32(0xe24fbd3f) }, + { SPH_C32(0xaf0d0000), SPH_C32(0xb4360000), SPH_C32(0xeabf0000), + SPH_C32(0x33fe0140), SPH_C32(0xf6a8130a), SPH_C32(0xba3421ed), + SPH_C32(0x4a6bf94d), SPH_C32(0xf87b98dd), SPH_C32(0x89230000), + SPH_C32(0x5a460000), SPH_C32(0x1e350000), SPH_C32(0xc18001ff), + SPH_C32(0x91f4d692), SPH_C32(0x1371f229), SPH_C32(0x311ef9f3), + SPH_C32(0x0495c2c1) }, + { SPH_C32(0xac300000), SPH_C32(0xbc850000), SPH_C32(0x19850000), + SPH_C32(0x093c0147), SPH_C32(0xa781995a), SPH_C32(0xd15a47f2), + SPH_C32(0x44ce36ae), SPH_C32(0x1ea1e723), SPH_C32(0x21f90000), + SPH_C32(0xccf80000), SPH_C32(0x42280000), SPH_C32(0xc65a01fd), + SPH_C32(0xec924311), SPH_C32(0x0ce982a3), SPH_C32(0x8a7871fb), + SPH_C32(0xde1242c1) }, + { SPH_C32(0x06440000), SPH_C32(0xc50a0000), SPH_C32(0x5b590000), + SPH_C32(0xfb280149), SPH_C32(0x061e0bd1), SPH_C32(0x190fe549), + SPH_C32(0xf73b10a4), SPH_C32(0x719386a6), SPH_C32(0xb0ec0000), + SPH_C32(0x18ce0000), SPH_C32(0xe6e80000), SPH_C32(0xaa4401f9), + SPH_C32(0x0752ea57), SPH_C32(0x3d6847b0), SPH_C32(0x1413494a), + SPH_C32(0x43de48e8) }, + { SPH_C32(0x05790000), SPH_C32(0xcdb90000), SPH_C32(0xa8630000), + SPH_C32(0xc1ea014e), SPH_C32(0x57378181), SPH_C32(0x72618356), + SPH_C32(0xf99edf47), SPH_C32(0x9749f958), SPH_C32(0x18360000), + SPH_C32(0x8e700000), SPH_C32(0xbaf50000), SPH_C32(0xad9e01fb), + SPH_C32(0x7a347fd4), SPH_C32(0x22f0373a), SPH_C32(0xaf75c142), + SPH_C32(0x9959c8e8) }, + { SPH_C32(0xae9e0000), SPH_C32(0x53b40000), SPH_C32(0x07440000), + SPH_C32(0xfcf2014b), SPH_C32(0x7b789e52), SPH_C32(0x069795c3), + SPH_C32(0x4c5d98ac), SPH_C32(0xab1406a6), SPH_C32(0x1b0b0000), + SPH_C32(0x86c30000), SPH_C32(0x49cf0000), SPH_C32(0x975c01fc), + SPH_C32(0x2b1df584), SPH_C32(0x499e5125), SPH_C32(0xa1d00ea1), + SPH_C32(0x7f83b716) }, + { SPH_C32(0xada30000), SPH_C32(0x5b070000), SPH_C32(0xf47e0000), + SPH_C32(0xc630014c), SPH_C32(0x2a511402), SPH_C32(0x6df9f3dc), + SPH_C32(0x42f8574f), SPH_C32(0x4dce7958), SPH_C32(0xb3d10000), + SPH_C32(0x107d0000), SPH_C32(0x15d20000), SPH_C32(0x908601fe), + SPH_C32(0x567b6007), SPH_C32(0x560621af), SPH_C32(0x1ab686a9), + SPH_C32(0xa5043716) }, + { SPH_C32(0xca570000), SPH_C32(0xa80e0000), SPH_C32(0xa2f60000), + SPH_C32(0x060b0152), SPH_C32(0x14592320), SPH_C32(0xec526625), + SPH_C32(0x35dd13a8), SPH_C32(0xd74eb663), SPH_C32(0xb13b0000), + SPH_C32(0x80040000), SPH_C32(0xd16f0000), SPH_C32(0x4f6b01f3), + SPH_C32(0xb12faec3), SPH_C32(0x287d6f19), SPH_C32(0x112fb6cb), + SPH_C32(0xaebbb10d) }, + { SPH_C32(0xc96a0000), SPH_C32(0xa0bd0000), SPH_C32(0x51cc0000), + SPH_C32(0x3cc90155), SPH_C32(0x4570a970), SPH_C32(0x873c003a), + SPH_C32(0x3b78dc4b), SPH_C32(0x3194c99d), SPH_C32(0x19e10000), + SPH_C32(0x16ba0000), SPH_C32(0x8d720000), SPH_C32(0x48b101f1), + SPH_C32(0xcc493b40), SPH_C32(0x37e51f93), SPH_C32(0xaa493ec3), + SPH_C32(0x743c310d) }, + { SPH_C32(0x628d0000), SPH_C32(0x3eb00000), SPH_C32(0xfeeb0000), + SPH_C32(0x01d10150), SPH_C32(0x693fb6a3), SPH_C32(0xf3ca16af), + SPH_C32(0x8ebb9ba0), SPH_C32(0x0dc93663), SPH_C32(0x1adc0000), + SPH_C32(0x1e090000), SPH_C32(0x7e480000), SPH_C32(0x727301f6), + SPH_C32(0x9d60b110), SPH_C32(0x5c8b798c), SPH_C32(0xa4ecf120), + SPH_C32(0x92e64ef3) }, + { SPH_C32(0x61b00000), SPH_C32(0x36030000), SPH_C32(0x0dd10000), + SPH_C32(0x3b130157), SPH_C32(0x38163cf3), SPH_C32(0x98a470b0), + SPH_C32(0x801e5443), SPH_C32(0xeb13499d), SPH_C32(0xb2060000), + SPH_C32(0x88b70000), SPH_C32(0x22550000), SPH_C32(0x75a901f4), + SPH_C32(0xe0062493), SPH_C32(0x43130906), SPH_C32(0x1f8a7928), + SPH_C32(0x4861cef3) }, + { SPH_C32(0xcbc40000), SPH_C32(0x4f8c0000), SPH_C32(0x4f0d0000), + SPH_C32(0xc9070159), SPH_C32(0x9989ae78), SPH_C32(0x50f1d20b), + SPH_C32(0x33eb7249), SPH_C32(0x84212818), SPH_C32(0x23130000), + SPH_C32(0x5c810000), SPH_C32(0x86950000), SPH_C32(0x19b701f0), + SPH_C32(0x0bc68dd5), SPH_C32(0x7292cc15), SPH_C32(0x81e14199), + SPH_C32(0xd5adc4da) }, + { SPH_C32(0xc8f90000), SPH_C32(0x473f0000), SPH_C32(0xbc370000), + SPH_C32(0xf3c5015e), SPH_C32(0xc8a02428), SPH_C32(0x3b9fb414), + SPH_C32(0x3d4ebdaa), SPH_C32(0x62fb57e6), SPH_C32(0x8bc90000), + SPH_C32(0xca3f0000), SPH_C32(0xda880000), SPH_C32(0x1e6d01f2), + SPH_C32(0x76a01856), SPH_C32(0x6d0abc9f), SPH_C32(0x3a87c991), + SPH_C32(0x0f2a44da) }, + { SPH_C32(0x631e0000), SPH_C32(0xd9320000), SPH_C32(0x13100000), + SPH_C32(0xcedd015b), SPH_C32(0xe4ef3bfb), SPH_C32(0x4f69a281), + SPH_C32(0x888dfa41), SPH_C32(0x5ea6a818), SPH_C32(0x88f40000), + SPH_C32(0xc28c0000), SPH_C32(0x29b20000), SPH_C32(0x24af01f5), + SPH_C32(0x27899206), SPH_C32(0x0664da80), SPH_C32(0x34220672), + SPH_C32(0xe9f03b24) }, + { SPH_C32(0x60230000), SPH_C32(0xd1810000), SPH_C32(0xe02a0000), + SPH_C32(0xf41f015c), SPH_C32(0xb5c6b1ab), SPH_C32(0x2407c49e), + SPH_C32(0x862835a2), SPH_C32(0xb87cd7e6), SPH_C32(0x202e0000), + SPH_C32(0x54320000), SPH_C32(0x75af0000), SPH_C32(0x237501f7), + SPH_C32(0x5aef0785), SPH_C32(0x19fcaa0a), SPH_C32(0x8f448e7a), + SPH_C32(0x3377bb24) }, + { SPH_C32(0x587f0000), SPH_C32(0x748b0000), SPH_C32(0xf50c0000), + SPH_C32(0x50d70151), SPH_C32(0xaeb00036), SPH_C32(0xb6bdc529), + SPH_C32(0xa513e4fa), SPH_C32(0xac58c3b4), SPH_C32(0x22800000), + SPH_C32(0xbb030000), SPH_C32(0x6b6e0000), SPH_C32(0xd6bb01fb), + SPH_C32(0x8616008d), SPH_C32(0xce31783b), SPH_C32(0x87d72078), + SPH_C32(0x86c25aa1) }, + { SPH_C32(0x5b420000), SPH_C32(0x7c380000), SPH_C32(0x06360000), + SPH_C32(0x6a150156), SPH_C32(0xff998a66), SPH_C32(0xddd3a336), + SPH_C32(0xabb62b19), SPH_C32(0x4a82bc4a), SPH_C32(0x8a5a0000), + SPH_C32(0x2dbd0000), SPH_C32(0x37730000), SPH_C32(0xd16101f9), + SPH_C32(0xfb70950e), SPH_C32(0xd1a908b1), SPH_C32(0x3cb1a870), + SPH_C32(0x5c45daa1) }, + { SPH_C32(0xf0a50000), SPH_C32(0xe2350000), SPH_C32(0xa9110000), + SPH_C32(0x570d0153), SPH_C32(0xd3d695b5), SPH_C32(0xa925b5a3), + SPH_C32(0x1e756cf2), SPH_C32(0x76df43b4), SPH_C32(0x89670000), + SPH_C32(0x250e0000), SPH_C32(0xc4490000), SPH_C32(0xeba301fe), + SPH_C32(0xaa591f5e), SPH_C32(0xbac76eae), SPH_C32(0x32146793), + SPH_C32(0xba9fa55f) }, + { SPH_C32(0xf3980000), SPH_C32(0xea860000), SPH_C32(0x5a2b0000), + SPH_C32(0x6dcf0154), SPH_C32(0x82ff1fe5), SPH_C32(0xc24bd3bc), + SPH_C32(0x10d0a311), SPH_C32(0x90053c4a), SPH_C32(0x21bd0000), + SPH_C32(0xb3b00000), SPH_C32(0x98540000), SPH_C32(0xec7901fc), + SPH_C32(0xd73f8add), SPH_C32(0xa55f1e24), SPH_C32(0x8972ef9b), + SPH_C32(0x6018255f) }, + { SPH_C32(0x59ec0000), SPH_C32(0x93090000), SPH_C32(0x18f70000), + SPH_C32(0x9fdb015a), SPH_C32(0x23608d6e), SPH_C32(0x0a1e7107), + SPH_C32(0xa325851b), SPH_C32(0xff375dcf), SPH_C32(0xb0a80000), + SPH_C32(0x67860000), SPH_C32(0x3c940000), SPH_C32(0x806701f8), + SPH_C32(0x3cff239b), SPH_C32(0x94dedb37), SPH_C32(0x1719d72a), + SPH_C32(0xfdd42f76) }, + { SPH_C32(0x5ad10000), SPH_C32(0x9bba0000), SPH_C32(0xebcd0000), + SPH_C32(0xa519015d), SPH_C32(0x7249073e), SPH_C32(0x61701718), + SPH_C32(0xad804af8), SPH_C32(0x19ed2231), SPH_C32(0x18720000), + SPH_C32(0xf1380000), SPH_C32(0x60890000), SPH_C32(0x87bd01fa), + SPH_C32(0x4199b618), SPH_C32(0x8b46abbd), SPH_C32(0xac7f5f22), + SPH_C32(0x2753af76) }, + { SPH_C32(0xf1360000), SPH_C32(0x05b70000), SPH_C32(0x44ea0000), + SPH_C32(0x98010158), SPH_C32(0x5e0618ed), SPH_C32(0x1586018d), + SPH_C32(0x18430d13), SPH_C32(0x25b0ddcf), SPH_C32(0x1b4f0000), + SPH_C32(0xf98b0000), SPH_C32(0x93b30000), SPH_C32(0xbd7f01fd), + SPH_C32(0x10b03c48), SPH_C32(0xe028cda2), SPH_C32(0xa2da90c1), + SPH_C32(0xc189d088) }, + { SPH_C32(0xf20b0000), SPH_C32(0x0d040000), SPH_C32(0xb7d00000), + SPH_C32(0xa2c3015f), SPH_C32(0x0f2f92bd), SPH_C32(0x7ee86792), + SPH_C32(0x16e6c2f0), SPH_C32(0xc36aa231), SPH_C32(0xb3950000), + SPH_C32(0x6f350000), SPH_C32(0xcfae0000), SPH_C32(0xbaa501ff), + SPH_C32(0x6dd6a9cb), SPH_C32(0xffb0bd28), SPH_C32(0x19bc18c9), + SPH_C32(0x1b0e5088) } +}; + +#define INPUT_BIG do { \ + unsigned acc = buf[0]; \ + const sph_u32 *rp; \ + rp = &T512_0[acc][0]; \ + m0 = rp[0]; \ + m1 = rp[1]; \ + m2 = rp[2]; \ + m3 = rp[3]; \ + m4 = rp[4]; \ + m5 = rp[5]; \ + m6 = rp[6]; \ + m7 = rp[7]; \ + m8 = rp[8]; \ + m9 = rp[9]; \ + mA = rp[10]; \ + mB = rp[11]; \ + mC = rp[12]; \ + mD = rp[13]; \ + mE = rp[14]; \ + mF = rp[15]; \ + acc = buf[1]; \ + rp = &T512_8[acc][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + m8 ^= rp[8]; \ + m9 ^= rp[9]; \ + mA ^= rp[10]; \ + mB ^= rp[11]; \ + mC ^= rp[12]; \ + mD ^= rp[13]; \ + mE ^= rp[14]; \ + mF ^= rp[15]; \ + acc = buf[2]; \ + rp = &T512_16[acc][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + m8 ^= rp[8]; \ + m9 ^= rp[9]; \ + mA ^= rp[10]; \ + mB ^= rp[11]; \ + mC ^= rp[12]; \ + mD ^= rp[13]; \ + mE ^= rp[14]; \ + mF ^= rp[15]; \ + acc = buf[3]; \ + rp = &T512_24[acc][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + m8 ^= rp[8]; \ + m9 ^= rp[9]; \ + mA ^= rp[10]; \ + mB ^= rp[11]; \ + mC ^= rp[12]; \ + mD ^= rp[13]; \ + mE ^= rp[14]; \ + mF ^= rp[15]; \ + acc = buf[4]; \ + rp = &T512_32[acc][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + m8 ^= rp[8]; \ + m9 ^= rp[9]; \ + mA ^= rp[10]; \ + mB ^= rp[11]; \ + mC ^= rp[12]; \ + mD ^= rp[13]; \ + mE ^= rp[14]; \ + mF ^= rp[15]; \ + acc = buf[5]; \ + rp = &T512_40[acc][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + m8 ^= rp[8]; \ + m9 ^= rp[9]; \ + mA ^= rp[10]; \ + mB ^= rp[11]; \ + mC ^= rp[12]; \ + mD ^= rp[13]; \ + mE ^= rp[14]; \ + mF ^= rp[15]; \ + acc = buf[6]; \ + rp = &T512_48[acc][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + m8 ^= rp[8]; \ + m9 ^= rp[9]; \ + mA ^= rp[10]; \ + mB ^= rp[11]; \ + mC ^= rp[12]; \ + mD ^= rp[13]; \ + mE ^= rp[14]; \ + mF ^= rp[15]; \ + acc = buf[7]; \ + rp = &T512_56[acc][0]; \ + m0 ^= rp[0]; \ + m1 ^= rp[1]; \ + m2 ^= rp[2]; \ + m3 ^= rp[3]; \ + m4 ^= rp[4]; \ + m5 ^= rp[5]; \ + m6 ^= rp[6]; \ + m7 ^= rp[7]; \ + m8 ^= rp[8]; \ + m9 ^= rp[9]; \ + mA ^= rp[10]; \ + mB ^= rp[11]; \ + mC ^= rp[12]; \ + mD ^= rp[13]; \ + mE ^= rp[14]; \ + mF ^= rp[15]; \ + } while (0) + +#endif + +#ifdef __cplusplus +} +#endif diff --git a/src/hashblock.h b/src/hashblock.h new file mode 100644 index 0000000..570d911 --- /dev/null +++ b/src/hashblock.h @@ -0,0 +1,155 @@ +#ifndef HASHBLOCK_H +#define HASHBLOCK_H + +#include "uint256.h" +#include "sph_blake.h" +#include "sph_bmw.h" +#include "sph_groestl.h" +#include "sph_jh.h" +#include "sph_keccak.h" +#include "sph_skein.h" +#include "sph_luffa.h" +#include "sph_cubehash.h" +#include "sph_shavite.h" +#include "sph_simd.h" +#include "sph_echo.h" +#include "sph_hamsi.h" +#include "sph_fugue.h" + +#ifndef QT_NO_DEBUG +#include +#endif + +#ifdef GLOBALDEFINED +#define GLOBAL +#else +#define GLOBAL extern +#endif + +GLOBAL sph_blake512_context z_blake; +GLOBAL sph_bmw512_context z_bmw; +GLOBAL sph_groestl512_context z_groestl; +GLOBAL sph_jh512_context z_jh; +GLOBAL sph_keccak512_context z_keccak; +GLOBAL sph_skein512_context z_skein; +GLOBAL sph_luffa512_context z_luffa; +GLOBAL sph_cubehash512_context z_cubehash; +GLOBAL sph_shavite512_context z_shavite; +GLOBAL sph_simd512_context z_simd; +GLOBAL sph_echo512_context z_echo; +GLOBAL sph_hamsi512_context z_hamsi; +GLOBAL sph_fugue512_context z_fugue; + +#define fillz() do { \ + sph_blake512_init(&z_blake); \ + sph_bmw512_init(&z_bmw); \ + sph_groestl512_init(&z_groestl); \ + sph_jh512_init(&z_jh); \ + sph_keccak512_init(&z_keccak); \ + sph_skein512_init(&z_skein); \ + sph_luffa512_init(&z_luffa); \ + sph_cubehash512_init(&z_cubehash); \ + sph_shavite512_init(&z_shavite); \ + sph_simd512_init(&z_simd); \ + sph_echo512_init(&z_echo); \ + sph_hamsi512_init(&z_hamsi); \ + sph_fugue512_init(&z_fugue); \ +} while (0) + + +#define ZBLAKE (memcpy(&ctx_blake, &z_blake, sizeof(z_blake))) +#define ZBMW (memcpy(&ctx_bmw, &z_bmw, sizeof(z_bmw))) +#define ZGROESTL (memcpy(&ctx_groestl, &z_groestl, sizeof(z_groestl))) +#define ZJH (memcpy(&ctx_jh, &z_jh, sizeof(z_jh))) +#define ZKECCAK (memcpy(&ctx_keccak, &z_keccak, sizeof(z_keccak))) +#define ZSKEIN (memcpy(&ctx_skein, &z_skein, sizeof(z_skein))) +#define ZHAMSI (memcpy(&ctx_hamsi, &z_hamsi, sizeof(z_hamsi))) +#define ZFUGUE (memcpy(&ctx_fugue, &z_fugue, sizeof(z_fugue))) +template +inline uint256 Hash9(const T1 pbegin, const T1 pend) + +{ + sph_blake512_context ctx_blake; + sph_bmw512_context ctx_bmw; + sph_groestl512_context ctx_groestl; + sph_jh512_context ctx_jh; + sph_keccak512_context ctx_keccak; + sph_skein512_context ctx_skein; + sph_luffa512_context ctx_luffa; + sph_cubehash512_context ctx_cubehash; + sph_shavite512_context ctx_shavite; + sph_simd512_context ctx_simd; + sph_echo512_context ctx_echo; + sph_hamsi512_context ctx_hamsi; + sph_fugue512_context ctx_fugue; + static unsigned char pblank[1]; + +#ifndef QT_NO_DEBUG + //std::string strhash; + //strhash = ""; +#endif + + uint512 hash[17]; + + sph_blake512_init(&ctx_blake); + sph_blake512 (&ctx_blake, (pbegin == pend ? pblank : static_cast(&pbegin[0])), (pend - pbegin) * sizeof(pbegin[0])); + sph_blake512_close(&ctx_blake, static_cast(&hash[0])); + + sph_bmw512_init(&ctx_bmw); + sph_bmw512 (&ctx_bmw, static_cast(&hash[0]), 64); + sph_bmw512_close(&ctx_bmw, static_cast(&hash[1])); + + sph_groestl512_init(&ctx_groestl); + sph_groestl512 (&ctx_groestl, static_cast(&hash[1]), 64); + sph_groestl512_close(&ctx_groestl, static_cast(&hash[2])); + + sph_skein512_init(&ctx_skein); + sph_skein512 (&ctx_skein, static_cast(&hash[2]), 64); + sph_skein512_close(&ctx_skein, static_cast(&hash[3])); + + sph_jh512_init(&ctx_jh); + sph_jh512 (&ctx_jh, static_cast(&hash[3]), 64); + sph_jh512_close(&ctx_jh, static_cast(&hash[4])); + + sph_keccak512_init(&ctx_keccak); + sph_keccak512 (&ctx_keccak, static_cast(&hash[4]), 64); + sph_keccak512_close(&ctx_keccak, static_cast(&hash[5])); + + sph_luffa512_init(&ctx_luffa); + sph_luffa512 (&ctx_luffa, static_cast(&hash[5]), 64); + sph_luffa512_close(&ctx_luffa, static_cast(&hash[6])); + + sph_cubehash512_init(&ctx_cubehash); + sph_cubehash512 (&ctx_cubehash, static_cast(&hash[6]), 64); + sph_cubehash512_close(&ctx_cubehash, static_cast(&hash[7])); + + sph_shavite512_init(&ctx_shavite); + sph_shavite512(&ctx_shavite, static_cast(&hash[7]), 64); + sph_shavite512_close(&ctx_shavite, static_cast(&hash[8])); + + sph_simd512_init(&ctx_simd); + sph_simd512 (&ctx_simd, static_cast(&hash[8]), 64); + sph_simd512_close(&ctx_simd, static_cast(&hash[9])); + + sph_echo512_init(&ctx_echo); + sph_echo512 (&ctx_echo, static_cast(&hash[9]), 64); + sph_echo512_close(&ctx_echo, static_cast(&hash[10])); + + sph_hamsi512_init(&ctx_hamsi); + sph_hamsi512 (&ctx_hamsi, static_cast(&hash[10]), 64); + sph_hamsi512_close(&ctx_hamsi, static_cast(&hash[11])); + + sph_fugue512_init(&ctx_fugue); + sph_fugue512 (&ctx_fugue, static_cast(&hash[11]), 64); + sph_fugue512_close(&ctx_fugue, static_cast(&hash[12])); + + + return hash[12].trim256(); +} + + + + + + +#endif // HASHBLOCK_H diff --git a/src/init.cpp b/src/init.cpp new file mode 100644 index 0000000..790bfe0 --- /dev/null +++ b/src/init.cpp @@ -0,0 +1,847 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2012 The Bitcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include "db.h" +#include "walletdb.h" +#include "bitcoinrpc.h" +#include "net.h" +#include "init.h" +#include "util.h" +#include "ui_interface.h" +#include "checkpoints.h" +#include +#include +#include +#include +#include +#include + +#ifndef WIN32 +#include +#endif + +using namespace std; +using namespace boost; + +CWallet* pwalletMain; +CClientUIInterface uiInterface; + +////////////////////////////////////////////////////////////////////////////// +// +// Shutdown +// + +void ExitTimeout(void* parg) +{ +#ifdef WIN32 + Sleep(5000); + ExitProcess(0); +#endif +} + +void StartShutdown() +{ +#ifdef QT_GUI + // ensure we leave the Qt main loop for a clean GUI exit (Shutdown() is called in bitcoin.cpp afterwards) + uiInterface.QueueShutdown(); +#else + // Without UI, Shutdown() can simply be started in a new thread + NewThread(Shutdown, NULL); +#endif +} + +void Shutdown(void* parg) +{ + static CCriticalSection cs_Shutdown; + static bool fTaken; + + // Make this thread recognisable as the shutdown thread + RenameThread("bitcoin-shutoff"); + + bool fFirstThread = false; + { + TRY_LOCK(cs_Shutdown, lockShutdown); + if (lockShutdown) + { + fFirstThread = !fTaken; + fTaken = true; + } + } + static bool fExit; + if (fFirstThread) + { + fShutdown = true; + nTransactionsUpdated++; + bitdb.Flush(false); + StopNode(); + bitdb.Flush(true); + boost::filesystem::remove(GetPidFile()); + UnregisterWallet(pwalletMain); + delete pwalletMain; + NewThread(ExitTimeout, NULL); + Sleep(50); + printf("triangles exited\n\n"); + fExit = true; +#ifndef QT_GUI + // ensure non-UI client gets exited here, but let Bitcoin-Qt reach 'return 0;' in bitcoin.cpp + exit(0); +#endif + } + else + { + while (!fExit) + Sleep(500); + Sleep(100); + ExitThread(0); + } +} + +void HandleSIGTERM(int) +{ + fRequestShutdown = true; +} + +void HandleSIGHUP(int) +{ + fReopenDebugLog = true; +} + + + + + +////////////////////////////////////////////////////////////////////////////// +// +// Start +// +#if !defined(QT_GUI) +bool AppInit(int argc, char* argv[]) +{ + bool fRet = false; + try + { + // + // Parameters + // + // If Qt is used, parameters/bitcoin.conf are parsed in qt/bitcoin.cpp's main() + ParseParameters(argc, argv); + if (!boost::filesystem::is_directory(GetDataDir(false))) + { + fprintf(stderr, "Error: Specified directory does not exist\n"); + Shutdown(NULL); + } + ReadConfigFile(mapArgs, mapMultiArgs); + + if (mapArgs.count("-?") || mapArgs.count("--help")) + { + // First part of help message is specific to bitcoind / RPC client + std::string strUsage = _("triangles version") + " " + FormatFullVersion() + "\n\n" + + _("Usage:") + "\n" + + " trianglesd [options] " + "\n" + + " trianglesd [options] [params] " + _("Send command to -server or trianglesd") + "\n" + + " trianglesd [options] help " + _("List commands") + "\n" + + " trianglesd [options] help " + _("Get help for a command") + "\n"; + + strUsage += "\n" + HelpMessage(); + + fprintf(stdout, "%s", strUsage.c_str()); + return false; + } + + // Command-line RPC + for (int i = 1; i < argc; i++) + if (!IsSwitchChar(argv[i][0]) && !boost::algorithm::istarts_with(argv[i], "triangles:")) + fCommandLine = true; + + if (fCommandLine) + { + int ret = CommandLineRPC(argc, argv); + exit(ret); + } + + fRet = AppInit2(); + } + catch (std::exception& e) { + PrintException(&e, "AppInit()"); + } catch (...) { + PrintException(NULL, "AppInit()"); + } + if (!fRet) + Shutdown(NULL); + return fRet; +} + +extern void noui_connect(); +int main(int argc, char* argv[]) +{ + bool fRet = false; + + // Connect bitcoind signal handlers + noui_connect(); + + fRet = AppInit(argc, argv); + + if (fRet && fDaemon) + return 0; + + return 1; +} +#endif + +bool static InitError(const std::string &str) +{ + uiInterface.ThreadSafeMessageBox(str, _("triangles"), CClientUIInterface::OK | CClientUIInterface::MODAL); + return false; +} + +bool static InitWarning(const std::string &str) +{ + uiInterface.ThreadSafeMessageBox(str, _("triangles"), CClientUIInterface::OK | CClientUIInterface::ICON_EXCLAMATION | CClientUIInterface::MODAL); + return true; +} + + +bool static Bind(const CService &addr, bool fError = true) { + if (IsLimited(addr)) + return false; + std::string strError; + if (!BindListenPort(addr, strError)) { + if (fError) + return InitError(strError); + return false; + } + return true; +} + +// Core-specific options shared between UI and daemon +std::string HelpMessage() +{ + string strUsage = _("Options:") + "\n" + + " -? " + _("This help message") + "\n" + + " -conf= " + _("Specify configuration file (default: triangles.conf)") + "\n" + + " -pid= " + _("Specify pid file (default: trianglesd.pid)") + "\n" + + " -gen " + _("Generate coins") + "\n" + + " -gen=0 " + _("Don't generate coins") + "\n" + + " -stake " + _("Stake coins") + "\n" + + " -stake=0 " + _("Turn off staking") + "\n" + + " -datadir= " + _("Specify data directory") + "\n" + + " -dbcache= " + _("Set database cache size in megabytes (default: 25)") + "\n" + + " -dblogsize= " + _("Set database disk log size in megabytes (default: 100)") + "\n" + + " -timeout= " + _("Specify connection timeout in milliseconds (default: 5000)") + "\n" + + " -socks= " + _("Select the version of socks proxy to use (4-5, default: 5)") + "\n" + + " -tor= " + _("Use proxy to reach tor hidden services") + "\n" + " -dns " + _("Allow DNS lookups for -addnode, -seednode and -connect") + "\n" + + " -port= " + _("Listen for connections on (default: 24242 or testnet: 24495)") + "\n" + + " -maxconnections= " + _("Maintain at most connections to peers (default: 125)") + "\n" + + " -addnode= " + _("Add a node to connect to and attempt to keep the connection open") + "\n" + + " -connect= " + _("Connect only to the specified node(s)") + "\n" + + " -seednode= " + _("Connect to a node to retrieve peer addresses, and disconnect") + "\n" + + " -externalip= " + _("Specify your own public address") + "\n" + + " -onionseed " + _("Find peers using .onion seeds (default: 1 unless -connect)") + "\n" + + " -nosynccheckpoints " + _("Disable sync checkpoints (default: 0)") + "\n" + + " -banscore= " + _("Threshold for disconnecting misbehaving peers (default: 100)") + "\n" + + " -bantime= " + _("Number of seconds to keep misbehaving peers from reconnecting (default: 86400)") + "\n" + + " -maxreceivebuffer= " + _("Maximum per-connection receive buffer, *1000 bytes (default: 5000)") + "\n" + + " -maxsendbuffer= " + _("Maximum per-connection send buffer, *1000 bytes (default: 1000)") + "\n" + +#ifdef USE_UPNP +#if USE_UPNP + " -upnp " + _("Use UPnP to map the listening port (default: 1 when listening)") + "\n" + +#else + " -upnp " + _("Use UPnP to map the listening port (default: 0)") + "\n" + +#endif +#endif + " -detachdb " + _("Detach block and address databases. Increases shutdown time (default: 0)") + "\n" + + " -paytxfee= " + _("Fee per KB to add to transactions you send") + "\n" + +#ifdef QT_GUI + " -server " + _("Accept command line and JSON-RPC commands") + "\n" + +#endif +#if !defined(WIN32) && !defined(QT_GUI) + " -daemon " + _("Run in the background as a daemon and accept commands") + "\n" + +#endif + " -testnet " + _("Use the test network") + "\n" + + " -debug " + _("Output extra debugging information. Implies all other -debug* options") + "\n" + + " -debugnet " + _("Output extra network debugging information") + "\n" + + " -logtimestamps " + _("Prepend debug output with timestamp") + "\n" + + " -shrinkdebugfile " + _("Shrink debug.log file on client startup (default: 1 when no -debug)") + "\n" + + " -printtoconsole " + _("Send trace/debug info to console instead of debug.log file") + "\n" + +#ifdef WIN32 + " -printtodebugger " + _("Send trace/debug info to debugger") + "\n" + +#endif + " -rpcuser= " + _("Username for JSON-RPC connections") + "\n" + + " -rpcpassword= " + _("Password for JSON-RPC connections") + "\n" + + " -rpcport= " + _("Listen for JSON-RPC connections on (default: 24444 or testnet: 24445)") + "\n" + + " -rpcallowip= " + _("Allow JSON-RPC connections from specified IP address") + "\n" + + " -rpcconnect= " + _("Send commands to node running on (default: 127.0.0.1)") + "\n" + + " -blocknotify= " + _("Execute command when the best block changes (%s in cmd is replaced by block hash)") + "\n" + + " -walletnotify= " + _("Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)") + "\n" + + " -upgradewallet " + _("Upgrade wallet to latest format") + "\n" + + " -keypool= " + _("Set key pool size to (default: 100)") + "\n" + + " -rescan " + _("Rescan the block chain for missing wallet transactions") + "\n" + + " -salvagewallet " + _("Attempt to recover private keys from a corrupt wallet.dat") + "\n" + + " -checkblocks= " + _("How many blocks to check at startup (default: 2500, 0 = all)") + "\n" + + " -checklevel= " + _("How thorough the block verification is (0-6, default: 1)") + "\n" + + " -loadblock= " + _("Imports blocks from external blk000?.dat file") + "\n" + + + "\n" + _("Block creation options:") + "\n" + + " -blockminsize= " + _("Set minimum block size in bytes (default: 0)") + "\n" + + " -blockmaxsize= " + _("Set maximum block size in bytes (default: 250000)") + "\n" + + " -blockprioritysize= " + _("Set maximum size of high-priority/low-fee transactions in bytes (default: 27000)") + "\n" + + + "\n" + _("SSL options: (see the Bitcoin Wiki for SSL setup instructions)") + "\n" + + " -rpcssl " + _("Use OpenSSL (https) for JSON-RPC connections") + "\n" + + " -rpcsslcertificatechainfile= " + _("Server certificate file (default: server.cert)") + "\n" + + " -rpcsslprivatekeyfile= " + _("Server private key (default: server.pem)") + "\n" + + " -rpcsslciphers= " + _("Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH)") + "\n"; + + return strUsage; +} + +/** Initialize bitcoin. + * @pre Parameters should be parsed and config file should be read. + */ +bool AppInit2() +{ + // ********************************************************* Step 1: setup +#ifdef _MSC_VER + // Turn off Microsoft heap dump noise + _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE); + _CrtSetReportFile(_CRT_WARN, CreateFileA("NUL", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0)); +#endif +#if _MSC_VER >= 1400 + // Disable confusing "helpful" text message on abort, Ctrl-C + _set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT); +#endif +#ifdef WIN32 + // Enable Data Execution Prevention (DEP) + // Minimum supported OS versions: WinXP SP3, WinVista >= SP1, Win Server 2008 + // A failure is non-critical and needs no further attention! +#ifndef PROCESS_DEP_ENABLE +// We define this here, because GCCs winbase.h limits this to _WIN32_WINNT >= 0x0601 (Windows 7), +// which is not correct. Can be removed, when GCCs winbase.h is fixed! +#define PROCESS_DEP_ENABLE 0x00000001 +#endif + typedef BOOL (WINAPI *PSETPROCDEPPOL)(DWORD); + PSETPROCDEPPOL setProcDEPPol = (PSETPROCDEPPOL)GetProcAddress(GetModuleHandleA("Kernel32.dll"), "SetProcessDEPPolicy"); + if (setProcDEPPol != NULL) setProcDEPPol(PROCESS_DEP_ENABLE); +#endif +#ifndef WIN32 + umask(077); + + // Clean shutdown on SIGTERM + struct sigaction sa; + sa.sa_handler = HandleSIGTERM; + sigemptyset(&sa.sa_mask); + sa.sa_flags = 0; + sigaction(SIGTERM, &sa, NULL); + sigaction(SIGINT, &sa, NULL); + + // Reopen debug.log on SIGHUP + struct sigaction sa_hup; + sa_hup.sa_handler = HandleSIGHUP; + sigemptyset(&sa_hup.sa_mask); + sa_hup.sa_flags = 0; + sigaction(SIGHUP, &sa_hup, NULL); +#endif + + // ********************************************************* Step 2: parameter interactions + + fTestNet = GetBoolArg("-testnet"); + if (fTestNet) { + SoftSetBoolArg("-irc", true); + } + + if (mapArgs.count("-connect") && mapMultiArgs["-connect"].size() > 0) { + // when only connecting to trusted nodes, do not seed via .onion, or listen by default + SoftSetBoolArg("-onionseed", false); + } + + if (GetBoolArg("-salvagewallet")) { + // Rewrite just private keys: rescan to find transactions + SoftSetBoolArg("-rescan", true); + } + + // ********************************************************* Step 3: parameter-to-internal-flags + + fDebug = GetBoolArg("-debug"); + + // -debug implies fDebug* + if (fDebug) + fDebugNet = true; + else + fDebugNet = GetBoolArg("-debugnet"); + + //fStaking = GetBoolArg("-staking", true); + + bitdb.SetDetach(GetBoolArg("-detachdb", false)); + +#if !defined(WIN32) && !defined(QT_GUI) + fDaemon = GetBoolArg("-daemon"); +#else + fDaemon = false; +#endif + + if (fDaemon) + fServer = true; + else + fServer = GetBoolArg("-server"); + + /* force fServer when running without GUI */ +#if !defined(QT_GUI) + fServer = true; +#endif + fPrintToConsole = GetBoolArg("-printtoconsole"); + fPrintToDebugger = GetBoolArg("-printtodebugger"); + fLogTimestamps = GetBoolArg("-logtimestamps"); + + if (mapArgs.count("-timeout")) + { + int nNewTimeout = GetArg("-timeout", 5000); + if (nNewTimeout > 0 && nNewTimeout < 600000) + nConnectTimeout = nNewTimeout; + } + + // Continue to put "/P2SH/" in the coinbase to monitor + // BIP16 support. + // This can be removed eventually... + const char* pszP2SH = "/P2SH/"; + COINBASE_FLAGS << std::vector(pszP2SH, pszP2SH+strlen(pszP2SH)); + + + if (mapArgs.count("-paytxfee")) + { + if (!ParseMoney(mapArgs["-paytxfee"], nTransactionFee)) + return InitError(strprintf(_("Invalid amount for -paytxfee=: '%s'"), mapArgs["-paytxfee"].c_str())); + if (nTransactionFee > 0.25 * COIN) + InitWarning(_("Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction.")); + } + + // ********************************************************* Step 4: application initialization: dir lock, daemonize, pidfile, debug log + + std::string strDataDir = GetDataDir().string(); + + // Make sure only a single Bitcoin process is using the data directory. + boost::filesystem::path pathLockFile = GetDataDir() / ".lock"; + FILE* file = fopen(pathLockFile.string().c_str(), "a"); // empty lock file; created if it doesn't exist. + if (file) fclose(file); + static boost::interprocess::file_lock lock(pathLockFile.string().c_str()); + if (!lock.try_lock()) + return InitError(strprintf(_("Cannot obtain a lock on data directory %s. triangles is probably already running."), strDataDir.c_str())); + +#if !defined(WIN32) && !defined(QT_GUI) + if (fDaemon) + { + // Daemonize + pid_t pid = fork(); + if (pid < 0) + { + fprintf(stderr, "Error: fork() returned %d errno %d\n", pid, errno); + return false; + } + if (pid > 0) + { + CreatePidFile(GetPidFile(), pid); + return true; + } + + pid_t sid = setsid(); + if (sid < 0) + fprintf(stderr, "Error: setsid() returned %d errno %d\n", sid, errno); + } +#endif + + if (GetBoolArg("-shrinkdebugfile", !fDebug)) + ShrinkDebugFile(); + printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"); + printf("triangles version %s (%s)\n", FormatFullVersion().c_str(), CLIENT_DATE.c_str()); + printf("Using OpenSSL version %s\n", SSLeay_version(SSLEAY_VERSION)); + if (!fLogTimestamps) + printf("Startup time: %s\n", DateTimeStrFormat("%x %H:%M:%S", GetTime()).c_str()); + printf("Default data directory %s\n", GetDefaultDataDir().string().c_str()); + printf("Used data directory %s\n", strDataDir.c_str()); + std::ostringstream strErrors; + + if (fDaemon) + fprintf(stdout, "triangles server starting\n"); + + int64 nStart; + + // ********************************************************* Step 5: verify database integrity + + uiInterface.InitMessage(_("Verifying database integrity...")); + + if (!bitdb.Open(GetDataDir())) + { + string msg = strprintf(_("Error initializing database environment %s!" + " To recover, BACKUP THAT DIRECTORY, then remove" + " everything from it except for wallet.dat."), strDataDir.c_str()); + return InitError(msg); + } + + if (GetBoolArg("-salvagewallet")) + { + // Recover readable keypairs: + if (!CWalletDB::Recover(bitdb, "wallet.dat", true)) + return false; + } + + if (filesystem::exists(GetDataDir() / "wallet.dat")) + { + CDBEnv::VerifyResult r = bitdb.Verify("wallet.dat", CWalletDB::Recover); + if (r == CDBEnv::RECOVER_OK) + { + string msg = strprintf(_("Warning: wallet.dat corrupt, data salvaged!" + " Original wallet.dat saved as wallet.{timestamp}.bak in %s; if" + " your balance or transactions are incorrect you should" + " restore from a backup."), strDataDir.c_str()); + uiInterface.ThreadSafeMessageBox(msg, _("triangles"), CClientUIInterface::OK | CClientUIInterface::ICON_EXCLAMATION | CClientUIInterface::MODAL); + } + if (r == CDBEnv::RECOVER_FAIL) + return InitError(_("wallet.dat corrupt, salvage failed")); + } + + // ********************************************************* Step 6: network initialization + + int nSocksVersion = GetArg("-socks", 5); + if (nSocksVersion != 4 && nSocksVersion != 5) + return InitError(strprintf(_("Unknown -socks proxy version requested: %i"), nSocksVersion)); + + do { + std::set nets; + nets.insert( + NET_TOR + ); + for (int n = 0; n < NET_MAX; n++) { + enum Network net = (enum Network)n; + if (!nets.count(net)) + SetLimited(net); + } + } while ( + false + ); + + + CService addrOnion; + // need to move onion_port to a header + unsigned short const onion_port = 19099; + + if (mapArgs.count("-tor") && mapArgs["-tor"] != "0") { + addrOnion = CService(mapArgs["-tor"], onion_port); + if (!addrOnion.IsValid()) + return InitError(strprintf(_("Invalid -tor address: '%s'"), mapArgs["-tor"].c_str())); + } else { + addrOnion = CService("127.0.0.1", onion_port); + } + + if (true) { + SetProxy(NET_TOR, addrOnion, 5); + SetReachable(NET_TOR); + } + + // see Step 2: parameter interactions for more information about these + fNameLookup = GetBoolArg("-dns", true); + + bool fBound = false; + if (true) { + if (true) { + do { + CService addrBind; + if (!Lookup("127.0.0.1", addrBind, GetListenPort(), false)) + return InitError(strprintf(_("Cannot resolve binding address: '%s'"), "127.0.0.1")); + fBound |= Bind(addrBind); + } while ( + false + ); + } + if (!fBound) + return InitError(_("Failed to listen on any port.")); + } + + + // start up tor + if (!(mapArgs.count("-tor") && mapArgs["-tor"] != "0")) { + if (!NewThread(StartTor, NULL)) + InitError(_("Error: could not start tor")); + } + + wait_initialized(); + + + if (mapArgs.count("-externalip")) + { + BOOST_FOREACH(string strAddr, mapMultiArgs["-externalip"]) { + CService addrLocal(strAddr, GetListenPort(), fNameLookup); + if (!addrLocal.IsValid()) + return InitError(strprintf(_("Cannot resolve -externalip address: '%s'"), strAddr.c_str())); + AddLocal(CService(strAddr, GetListenPort(), fNameLookup), LOCAL_MANUAL); + } + } else { + string automatic_onion; + filesystem::path const hostname_path = GetDataDir( + ) / "onion" / "hostname"; + if ( + !filesystem::exists( + hostname_path + ) + ) { + return InitError(strprintf(_("No external address found. %s"), hostname_path.string().c_str())); + } + ifstream file( + hostname_path.string( + ).c_str( + ) + ); + file >> automatic_onion; + AddLocal(CService(automatic_onion, GetListenPort(), fNameLookup), LOCAL_MANUAL); + } + + BOOST_FOREACH(string strDest, mapMultiArgs["-seednode"]) + AddOneShot(strDest); + + + if (mapArgs.count("-reservebalance")) // triangles: reserve balance amount + { + int64 nReserveBalance = 0; + if (!ParseMoney(mapArgs["-reservebalance"], nReserveBalance)) + { + InitError(_("Invalid amount for -reservebalance=")); + return false; + } + } + + + if (mapArgs.count("-checkpointkey")) // triangles: checkpoint master priv key + { + if (!Checkpoints::SetCheckpointPrivKey(GetArg("-checkpointkey", ""))) + InitError(_("Unable to sign checkpoint, wrong checkpointkey?\n")); + } + + //AddOneShot(string("")); + + // ********************************************************* Step 7: load blockchain + + if (!bitdb.Open(GetDataDir())) + { + string msg = strprintf(_("Error initializing database environment %s!" + " To recover, BACKUP THAT DIRECTORY, then remove" + " everything from it except for wallet.dat."), strDataDir.c_str()); + return InitError(msg); + } + + if (GetBoolArg("-loadblockindextest")) + { + CTxDB txdb("r"); + txdb.LoadBlockIndex(); + PrintBlockTree(); + return false; + } + + uiInterface.InitMessage(_("Loading block index...")); + printf("Loading block index...\n"); + nStart = GetTimeMillis(); + if (!LoadBlockIndex()) + return InitError(_("Error loading blkindex.dat")); + + // as LoadBlockIndex can take several minutes, it's possible the user + // requested to kill bitcoin-qt during the last operation. If so, exit. + // As the program has not fully started yet, Shutdown() is possibly overkill. + if (fRequestShutdown) + { + printf("Shutdown requested. Exiting.\n"); + return false; + } + printf(" block index %15"PRI64d"ms\n", GetTimeMillis() - nStart); + + if (GetBoolArg("-printblockindex") || GetBoolArg("-printblocktree")) + { + PrintBlockTree(); + return false; + } + + if (mapArgs.count("-printblock")) + { + string strMatch = mapArgs["-printblock"]; + int nFound = 0; + for (map::iterator mi = mapBlockIndex.begin(); mi != mapBlockIndex.end(); ++mi) + { + uint256 hash = (*mi).first; + if (strncmp(hash.ToString().c_str(), strMatch.c_str(), strMatch.size()) == 0) + { + CBlockIndex* pindex = (*mi).second; + CBlock block; + block.ReadFromDisk(pindex); + block.BuildMerkleTree(); + block.print(); + printf("\n"); + nFound++; + } + } + if (nFound == 0) + printf("No blocks matching %s were found\n", strMatch.c_str()); + return false; + } + + // ********************************************************* Step 8: load wallet + + uiInterface.InitMessage(_("Loading wallet...")); + printf("Loading wallet...\n"); + nStart = GetTimeMillis(); + bool fFirstRun = true; + pwalletMain = new CWallet("wallet.dat"); + DBErrors nLoadWalletRet = pwalletMain->LoadWallet(fFirstRun); + if (nLoadWalletRet != DB_LOAD_OK) + { + if (nLoadWalletRet == DB_CORRUPT) + strErrors << _("Error loading wallet.dat: Wallet corrupted") << "\n"; + else if (nLoadWalletRet == DB_NONCRITICAL_ERROR) + { + string msg(_("Warning: error reading wallet.dat! All keys read correctly, but transaction data" + " or address book entries might be missing or incorrect.")); + uiInterface.ThreadSafeMessageBox(msg, _("triangles"), CClientUIInterface::OK | CClientUIInterface::ICON_EXCLAMATION | CClientUIInterface::MODAL); + } + else if (nLoadWalletRet == DB_TOO_NEW) + strErrors << _("Error loading wallet.dat: Wallet requires newer version of triangles") << "\n"; + else if (nLoadWalletRet == DB_NEED_REWRITE) + { + strErrors << _("Wallet needed to be rewritten: restart triangles to complete") << "\n"; + printf("%s", strErrors.str().c_str()); + return InitError(strErrors.str()); + } + else + strErrors << _("Error loading wallet.dat") << "\n"; + } + + if (GetBoolArg("-upgradewallet", fFirstRun)) + { + int nMaxVersion = GetArg("-upgradewallet", 0); + if (nMaxVersion == 0) // the -upgradewallet without argument case + { + printf("Performing wallet upgrade to %i\n", FEATURE_LATEST); + nMaxVersion = CLIENT_VERSION; + pwalletMain->SetMinVersion(FEATURE_LATEST); // permanently upgrade the wallet immediately + } + else + printf("Allowing wallet upgrade up to %i\n", nMaxVersion); + if (nMaxVersion < pwalletMain->GetVersion()) + strErrors << _("Cannot downgrade wallet") << "\n"; + pwalletMain->SetMaxVersion(nMaxVersion); + } + + if (fFirstRun) + { + // Create new keyUser and set as default key + RandAddSeedPerfmon(); + + CPubKey newDefaultKey; + if (!pwalletMain->GetKeyFromPool(newDefaultKey, false)) + strErrors << _("Cannot initialize keypool") << "\n"; + pwalletMain->SetDefaultKey(newDefaultKey); + if (!pwalletMain->SetAddressBookName(pwalletMain->vchDefaultKey.GetID(), "")) + strErrors << _("Cannot write default address") << "\n"; + } + + printf("%s", strErrors.str().c_str()); + printf(" wallet %15"PRI64d"ms\n", GetTimeMillis() - nStart); + + RegisterWallet(pwalletMain); + + CBlockIndex *pindexRescan = pindexBest; + if (GetBoolArg("-rescan")) + pindexRescan = pindexGenesisBlock; + else + { + CWalletDB walletdb("wallet.dat"); + CBlockLocator locator; + if (walletdb.ReadBestBlock(locator)) + pindexRescan = locator.GetBlockIndex(); + } + if (pindexBest != pindexRescan && pindexBest && pindexRescan && pindexBest->nHeight > pindexRescan->nHeight) + { + uiInterface.InitMessage(_("Rescanning...")); + printf("Rescanning last %i blocks (from block %i)...\n", pindexBest->nHeight - pindexRescan->nHeight, pindexRescan->nHeight); + nStart = GetTimeMillis(); + pwalletMain->ScanForWalletTransactions(pindexRescan, true); + printf(" rescan %15"PRI64d"ms\n", GetTimeMillis() - nStart); + } + + // ********************************************************* Step 9: import blocks + + if (mapArgs.count("-loadblock")) + { + uiInterface.InitMessage(_("Importing blockchain data file.")); + + BOOST_FOREACH(string strFile, mapMultiArgs["-loadblock"]) + { + FILE *file = fopen(strFile.c_str(), "rb"); + if (file) + LoadExternalBlockFile(file); + } + } + + filesystem::path pathBootstrap = GetDataDir() / "bootstrap.dat"; + if (filesystem::exists(pathBootstrap)) { + uiInterface.InitMessage(_("Importing bootstrap blockchain data file.")); + + FILE *file = fopen(pathBootstrap.string().c_str(), "rb"); + if (file) { + filesystem::path pathBootstrapOld = GetDataDir() / "bootstrap.dat.old"; + LoadExternalBlockFile(file); + RenameOver(pathBootstrap, pathBootstrapOld); + } + } + + // ********************************************************* Step 10: load peers + + uiInterface.InitMessage(_("Loading addresses...")); + printf("Loading addresses...\n"); + nStart = GetTimeMillis(); + + { + CAddrDB adb; + if (!adb.Read(addrman)) + printf("Invalid or missing peers.dat; recreating\n"); + } + + printf("Loaded %i addresses from peers.dat %"PRI64d"ms\n", + addrman.size(), GetTimeMillis() - nStart); + + // ********************************************************* Step 11: start node + + if (!CheckDiskSpace()) + return false; + + RandAddSeedPerfmon(); + + //// debug print + printf("mapBlockIndex.size() = %"PRIszu"\n", mapBlockIndex.size()); + printf("nBestHeight = %d\n", nBestHeight); + printf("setKeyPool.size() = %"PRIszu"\n", pwalletMain->setKeyPool.size()); + printf("mapWallet.size() = %"PRIszu"\n", pwalletMain->mapWallet.size()); + printf("mapAddressBook.size() = %"PRIszu"\n", pwalletMain->mapAddressBook.size()); + + if (!NewThread(StartNode, NULL)) + InitError(_("Error: could not start node")); + + if (fServer) + NewThread(ThreadRPCServer, NULL); + + // ********************************************************* Step 12: finished + + uiInterface.InitMessage(_("Done loading")); + printf("Done loading\n"); + + if (!strErrors.str().empty()) + return InitError(strErrors.str()); + + // Add wallet transactions that aren't already in a block to mapTransactions + pwalletMain->ReacceptWalletTransactions(); + +#if !defined(QT_GUI) + // Loop until process is exit()ed from shutdown() function, + // called from ThreadRPCServer thread when a "stop" command is received. + while (1) + Sleep(5000); +#endif + + return true; +} diff --git a/src/init.h b/src/init.h new file mode 100644 index 0000000..d74d5b7 --- /dev/null +++ b/src/init.h @@ -0,0 +1,18 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2012 The Bitcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. +#ifndef BITCOIN_INIT_H +#define BITCOIN_INIT_H + +#include "wallet.h" +#include "anonymize.h" + +extern CWallet* pwalletMain; + +void StartShutdown(); +void Shutdown(void* parg); +bool AppInit2(); +std::string HelpMessage(); + +#endif diff --git a/src/irc.cpp b/src/irc.cpp new file mode 100644 index 0000000..c59a61a --- /dev/null +++ b/src/irc.cpp @@ -0,0 +1,393 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2012 The Bitcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "irc.h" +#include "net.h" +#include "strlcpy.h" +#include "base58.h" + +using namespace std; +using namespace boost; + +int nGotIRCAddresses = 0; + +void ThreadIRCSeed2(void* parg); + + + + +#pragma pack(push, 1) +struct ircaddr +{ + struct in_addr ip; + short port; +}; +#pragma pack(pop) + +string EncodeAddress(const CService& addr) +{ + struct ircaddr tmp; + if (addr.GetInAddr(&tmp.ip)) + { + tmp.port = htons(addr.GetPort()); + + vector vch(UBEGIN(tmp), UEND(tmp)); + return string("u") + EncodeBase58Check(vch); + } + return ""; +} + +bool DecodeAddress(string str, CService& addr) +{ + vector vch; + if (!DecodeBase58Check(str.substr(1), vch)) + return false; + + struct ircaddr tmp; + if (vch.size() != sizeof(tmp)) + return false; + memcpy(&tmp, &vch[0], sizeof(tmp)); + + addr = CService(tmp.ip, ntohs(tmp.port)); + return true; +} + + +static bool Send(SOCKET hSocket, const char* pszSend) +{ + if (strstr(pszSend, "PONG") != pszSend) + printf("IRC SENDING: %s\n", pszSend); + const char* psz = pszSend; + const char* pszEnd = psz + strlen(psz); + while (psz < pszEnd) + { + int ret = send(hSocket, psz, pszEnd - psz, MSG_NOSIGNAL); + if (ret < 0) + return false; + psz += ret; + } + return true; +} + +bool RecvLineIRC(SOCKET hSocket, string& strLine) +{ + loop + { + bool fRet = RecvLine(hSocket, strLine); + if (fRet) + { + if (fShutdown) + return false; + vector vWords; + ParseString(strLine, ' ', vWords); + if (vWords.size() >= 1 && vWords[0] == "PING") + { + strLine[1] = 'O'; + strLine += '\r'; + Send(hSocket, strLine.c_str()); + continue; + } + } + return fRet; + } +} + +int RecvUntil(SOCKET hSocket, const char* psz1, const char* psz2=NULL, const char* psz3=NULL, const char* psz4=NULL) +{ + loop + { + string strLine; + strLine.reserve(10000); + if (!RecvLineIRC(hSocket, strLine)) + return 0; + printf("IRC %s\n", strLine.c_str()); + if (psz1 && strLine.find(psz1) != string::npos) + return 1; + if (psz2 && strLine.find(psz2) != string::npos) + return 2; + if (psz3 && strLine.find(psz3) != string::npos) + return 3; + if (psz4 && strLine.find(psz4) != string::npos) + return 4; + } +} + +bool Wait(int nSeconds) +{ + if (fShutdown) + return false; + printf("IRC waiting %d seconds to reconnect\n", nSeconds); + for (int i = 0; i < nSeconds; i++) + { + if (fShutdown) + return false; + Sleep(1000); + } + return true; +} + +bool RecvCodeLine(SOCKET hSocket, const char* psz1, string& strRet) +{ + strRet.clear(); + loop + { + string strLine; + if (!RecvLineIRC(hSocket, strLine)) + return false; + + vector vWords; + ParseString(strLine, ' ', vWords); + if (vWords.size() < 2) + continue; + + if (vWords[1] == psz1) + { + printf("IRC %s\n", strLine.c_str()); + strRet = strLine; + return true; + } + } +} + +bool GetIPFromIRC(SOCKET hSocket, string strMyName, CNetAddr& ipRet) +{ + Send(hSocket, strprintf("USERHOST %s\r", strMyName.c_str()).c_str()); + + string strLine; + if (!RecvCodeLine(hSocket, "302", strLine)) + return false; + + vector vWords; + ParseString(strLine, ' ', vWords); + if (vWords.size() < 4) + return false; + + string str = vWords[3]; + if (str.rfind("@") == string::npos) + return false; + string strHost = str.substr(str.rfind("@")+1); + + // Hybrid IRC used by lfnet always returns IP when you userhost yourself, + // but in case another IRC is ever used this should work. + printf("GetIPFromIRC() got userhost %s\n", strHost.c_str()); + CNetAddr addr(strHost, true); + if (!addr.IsValid()) + return false; + ipRet = addr; + + return true; +} + + + +void ThreadIRCSeed(void* parg) +{ + // Make this thread recognisable as the IRC seeding thread + RenameThread("bitcoin-ircseed"); + + try + { + ThreadIRCSeed2(parg); + } + catch (std::exception& e) { + PrintExceptionContinue(&e, "ThreadIRCSeed()"); + } catch (...) { + PrintExceptionContinue(NULL, "ThreadIRCSeed()"); + } + printf("ThreadIRCSeed exited\n"); +} + +void ThreadIRCSeed2(void* parg) +{ + // Don't connect to IRC if we won't use IPv4 connections. + if (IsLimited(NET_IPV4)) + return; + + // ... or if we won't make outbound connections and won't accept inbound ones. + if (mapArgs.count("-connect")) + return; + + // ... or if IRC is not enabled. + if (!GetBoolArg("-irc", true)) + return; + + printf("ThreadIRCSeed started\n"); + int nErrorWait = 10; + int nRetryWait = 10; + int nNameRetry = 0; + + while (!fShutdown) + { + CService addrConnect("92.243.23.21", 6667); // irc.lfnet.org + + CService addrIRC("irc.lfnet.org", 6667, true); + if (addrIRC.IsValid()) + addrConnect = addrIRC; + + SOCKET hSocket; + if (!ConnectSocket(addrConnect, hSocket)) + { + printf("IRC connect failed\n"); + nErrorWait = nErrorWait * 11 / 10; + if (Wait(nErrorWait += 60)) + continue; + else + return; + } + + if (!RecvUntil(hSocket, "Found your hostname", "using your IP address instead", "Couldn't look up your hostname", "ignoring hostname")) + { + closesocket(hSocket); + hSocket = INVALID_SOCKET; + nErrorWait = nErrorWait * 11 / 10; + if (Wait(nErrorWait += 60)) + continue; + else + return; + } + + CNetAddr addrIPv4("1.2.3.4"); // arbitrary IPv4 address to make GetLocal prefer IPv4 addresses + CService addrLocal; + string strMyName; + // Don't use our IP as our nick if we're not listening + // or if it keeps failing because the nick is already in use. + if (GetLocal(addrLocal, &addrIPv4) && nNameRetry<3) + strMyName = EncodeAddress(GetLocalAddress(&addrConnect)); + if (strMyName == "") + strMyName = strprintf("x%"PRI64u"", GetRand(1000000000)); + + Send(hSocket, strprintf("NICK %s\r", strMyName.c_str()).c_str()); + Send(hSocket, strprintf("USER %s 8 * : %s\r", strMyName.c_str(), strMyName.c_str()).c_str()); + + int nRet = RecvUntil(hSocket, " 004 ", " 433 "); + if (nRet != 1) + { + closesocket(hSocket); + hSocket = INVALID_SOCKET; + if (nRet == 2) + { + printf("IRC name already in use\n"); + nNameRetry++; + Wait(10); + continue; + } + nErrorWait = nErrorWait * 11 / 10; + if (Wait(nErrorWait += 60)) + continue; + else + return; + } + nNameRetry = 0; + Sleep(500); + + // Get our external IP from the IRC server and re-nick before joining the channel + CNetAddr addrFromIRC; + if (GetIPFromIRC(hSocket, strMyName, addrFromIRC)) + { + printf("GetIPFromIRC() returned %s\n", addrFromIRC.ToString().c_str()); + // Don't use our IP as our nick if we're not listening + if (addrFromIRC.IsRoutable()) + { + // IRC lets you to re-nick + AddLocal(addrFromIRC, LOCAL_IRC); + strMyName = EncodeAddress(GetLocalAddress(&addrConnect)); + Send(hSocket, strprintf("NICK %s\r", strMyName.c_str()).c_str()); + } + } + + if (fTestNet) { + Send(hSocket, "JOIN #triangles-00\r"); + Send(hSocket, "WHO #triangles-01\r"); + } else { + // randomly join + // int channel_number = GetRandInt(5); + + // Channel number is always 0 for initial release + int channel_number = 0; + Send(hSocket, strprintf("JOIN #triangles-00%02d\r", channel_number).c_str()); + Send(hSocket, strprintf("WHO #triangles-01%02d\r", channel_number).c_str()); + } + + int64 nStart = GetTime(); + string strLine; + strLine.reserve(10000); + while (!fShutdown && RecvLineIRC(hSocket, strLine)) + { + if (strLine.empty() || strLine.size() > 900 || strLine[0] != ':') + continue; + + vector vWords; + ParseString(strLine, ' ', vWords); + if (vWords.size() < 2) + continue; + + char pszName[10000]; + pszName[0] = '\0'; + + if (vWords[1] == "352" && vWords.size() >= 8) + { + // index 7 is limited to 16 characters + // could get full length name at index 10, but would be different from join messages + strlcpy(pszName, vWords[7].c_str(), sizeof(pszName)); + printf("IRC got who\n"); + } + + if (vWords[1] == "JOIN" && vWords[0].size() > 1) + { + // :username!username@50000007.F000000B.90000002.IP JOIN :#channelname + strlcpy(pszName, vWords[0].c_str() + 1, sizeof(pszName)); + if (strchr(pszName, '!')) + *strchr(pszName, '!') = '\0'; + printf("IRC got join\n"); + } + + if (pszName[0] == 'u') + { + CAddress addr; + if (DecodeAddress(pszName, addr)) + { + addr.nTime = GetAdjustedTime(); + if (addrman.Add(addr, addrConnect, 51 * 60)) + printf("IRC got new address: %s\n", addr.ToString().c_str()); + nGotIRCAddresses++; + } + else + { + printf("IRC decode failed\n"); + } + } + } + closesocket(hSocket); + hSocket = INVALID_SOCKET; + + if (GetTime() - nStart > 20 * 60) + { + nErrorWait /= 3; + nRetryWait /= 3; + } + + nRetryWait = nRetryWait * 11 / 10; + if (!Wait(nRetryWait += 60)) + return; + } +} + + +#ifdef TEST +int main(int argc, char *argv[]) +{ + WSADATA wsadata; + if (WSAStartup(MAKEWORD(2,2), &wsadata) != NO_ERROR) + { + printf("Error at WSAStartup()\n"); + return false; + } + + ThreadIRCSeed(NULL); + + WSACleanup(); + return 0; +} +#endif diff --git a/src/irc.h b/src/irc.h new file mode 100644 index 0000000..119aeb3 --- /dev/null +++ b/src/irc.h @@ -0,0 +1,12 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2012 The Bitcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. +#ifndef BITCOIN_IRC_H +#define BITCOIN_IRC_H + +void ThreadIRCSeed(void* parg); + +extern int nGotIRCAddresses; + +#endif diff --git a/src/jh.c b/src/jh.c new file mode 100644 index 0000000..41487a5 --- /dev/null +++ b/src/jh.c @@ -0,0 +1,1116 @@ +/* $Id: jh.c 255 2011-06-07 19:50:20Z tp $ */ +/* + * JH implementation. + * + * ==========================(LICENSE BEGIN)============================ + * + * Copyright (c) 2007-2010 Projet RNRT SAPHIR + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * ===========================(LICENSE END)============================= + * + * @author Thomas Pornin + */ + +#include +#include + +#include "sph_jh.h" + +#ifdef __cplusplus +extern "C"{ +#endif + + +#if SPH_SMALL_FOOTPRINT && !defined SPH_SMALL_FOOTPRINT_JH +#define SPH_SMALL_FOOTPRINT_JH 1 +#endif + +#if !defined SPH_JH_64 && SPH_64_TRUE +#define SPH_JH_64 1 +#endif + +#if !SPH_64 +#undef SPH_JH_64 +#endif + +#ifdef _MSC_VER +#pragma warning (disable: 4146) +#endif + +/* + * The internal bitslice representation may use either big-endian or + * little-endian (true bitslice operations do not care about the bit + * ordering, and the bit-swapping linear operations in JH happen to + * be invariant through endianness-swapping). The constants must be + * defined according to the chosen endianness; we use some + * byte-swapping macros for that. + */ + +#if SPH_LITTLE_ENDIAN + +#define C32e(x) ((SPH_C32(x) >> 24) \ + | ((SPH_C32(x) >> 8) & SPH_C32(0x0000FF00)) \ + | ((SPH_C32(x) << 8) & SPH_C32(0x00FF0000)) \ + | ((SPH_C32(x) << 24) & SPH_C32(0xFF000000))) +#define dec32e_aligned sph_dec32le_aligned +#define enc32e sph_enc32le + +#if SPH_64 +#define C64e(x) ((SPH_C64(x) >> 56) \ + | ((SPH_C64(x) >> 40) & SPH_C64(0x000000000000FF00)) \ + | ((SPH_C64(x) >> 24) & SPH_C64(0x0000000000FF0000)) \ + | ((SPH_C64(x) >> 8) & SPH_C64(0x00000000FF000000)) \ + | ((SPH_C64(x) << 8) & SPH_C64(0x000000FF00000000)) \ + | ((SPH_C64(x) << 24) & SPH_C64(0x0000FF0000000000)) \ + | ((SPH_C64(x) << 40) & SPH_C64(0x00FF000000000000)) \ + | ((SPH_C64(x) << 56) & SPH_C64(0xFF00000000000000))) +#define dec64e_aligned sph_dec64le_aligned +#define enc64e sph_enc64le +#endif + +#else + +#define C32e(x) SPH_C32(x) +#define dec32e_aligned sph_dec32be_aligned +#define enc32e sph_enc32be +#if SPH_64 +#define C64e(x) SPH_C64(x) +#define dec64e_aligned sph_dec64be_aligned +#define enc64e sph_enc64be +#endif + +#endif + +#define Sb(x0, x1, x2, x3, c) do { \ + x3 = ~x3; \ + x0 ^= (c) & ~x2; \ + tmp = (c) ^ (x0 & x1); \ + x0 ^= x2 & x3; \ + x3 ^= ~x1 & x2; \ + x1 ^= x0 & x2; \ + x2 ^= x0 & ~x3; \ + x0 ^= x1 | x3; \ + x3 ^= x1 & x2; \ + x1 ^= tmp & x0; \ + x2 ^= tmp; \ + } while (0) + +#define Lb(x0, x1, x2, x3, x4, x5, x6, x7) do { \ + x4 ^= x1; \ + x5 ^= x2; \ + x6 ^= x3 ^ x0; \ + x7 ^= x0; \ + x0 ^= x5; \ + x1 ^= x6; \ + x2 ^= x7 ^ x4; \ + x3 ^= x4; \ + } while (0) + +#if SPH_JH_64 + +static const sph_u64 C[] = { + C64e(0x72d5dea2df15f867), C64e(0x7b84150ab7231557), + C64e(0x81abd6904d5a87f6), C64e(0x4e9f4fc5c3d12b40), + C64e(0xea983ae05c45fa9c), C64e(0x03c5d29966b2999a), + C64e(0x660296b4f2bb538a), C64e(0xb556141a88dba231), + C64e(0x03a35a5c9a190edb), C64e(0x403fb20a87c14410), + C64e(0x1c051980849e951d), C64e(0x6f33ebad5ee7cddc), + C64e(0x10ba139202bf6b41), C64e(0xdc786515f7bb27d0), + C64e(0x0a2c813937aa7850), C64e(0x3f1abfd2410091d3), + C64e(0x422d5a0df6cc7e90), C64e(0xdd629f9c92c097ce), + C64e(0x185ca70bc72b44ac), C64e(0xd1df65d663c6fc23), + C64e(0x976e6c039ee0b81a), C64e(0x2105457e446ceca8), + C64e(0xeef103bb5d8e61fa), C64e(0xfd9697b294838197), + C64e(0x4a8e8537db03302f), C64e(0x2a678d2dfb9f6a95), + C64e(0x8afe7381f8b8696c), C64e(0x8ac77246c07f4214), + C64e(0xc5f4158fbdc75ec4), C64e(0x75446fa78f11bb80), + C64e(0x52de75b7aee488bc), C64e(0x82b8001e98a6a3f4), + C64e(0x8ef48f33a9a36315), C64e(0xaa5f5624d5b7f989), + C64e(0xb6f1ed207c5ae0fd), C64e(0x36cae95a06422c36), + C64e(0xce2935434efe983d), C64e(0x533af974739a4ba7), + C64e(0xd0f51f596f4e8186), C64e(0x0e9dad81afd85a9f), + C64e(0xa7050667ee34626a), C64e(0x8b0b28be6eb91727), + C64e(0x47740726c680103f), C64e(0xe0a07e6fc67e487b), + C64e(0x0d550aa54af8a4c0), C64e(0x91e3e79f978ef19e), + C64e(0x8676728150608dd4), C64e(0x7e9e5a41f3e5b062), + C64e(0xfc9f1fec4054207a), C64e(0xe3e41a00cef4c984), + C64e(0x4fd794f59dfa95d8), C64e(0x552e7e1124c354a5), + C64e(0x5bdf7228bdfe6e28), C64e(0x78f57fe20fa5c4b2), + C64e(0x05897cefee49d32e), C64e(0x447e9385eb28597f), + C64e(0x705f6937b324314a), C64e(0x5e8628f11dd6e465), + C64e(0xc71b770451b920e7), C64e(0x74fe43e823d4878a), + C64e(0x7d29e8a3927694f2), C64e(0xddcb7a099b30d9c1), + C64e(0x1d1b30fb5bdc1be0), C64e(0xda24494ff29c82bf), + C64e(0xa4e7ba31b470bfff), C64e(0x0d324405def8bc48), + C64e(0x3baefc3253bbd339), C64e(0x459fc3c1e0298ba0), + C64e(0xe5c905fdf7ae090f), C64e(0x947034124290f134), + C64e(0xa271b701e344ed95), C64e(0xe93b8e364f2f984a), + C64e(0x88401d63a06cf615), C64e(0x47c1444b8752afff), + C64e(0x7ebb4af1e20ac630), C64e(0x4670b6c5cc6e8ce6), + C64e(0xa4d5a456bd4fca00), C64e(0xda9d844bc83e18ae), + C64e(0x7357ce453064d1ad), C64e(0xe8a6ce68145c2567), + C64e(0xa3da8cf2cb0ee116), C64e(0x33e906589a94999a), + C64e(0x1f60b220c26f847b), C64e(0xd1ceac7fa0d18518), + C64e(0x32595ba18ddd19d3), C64e(0x509a1cc0aaa5b446), + C64e(0x9f3d6367e4046bba), C64e(0xf6ca19ab0b56ee7e), + C64e(0x1fb179eaa9282174), C64e(0xe9bdf7353b3651ee), + C64e(0x1d57ac5a7550d376), C64e(0x3a46c2fea37d7001), + C64e(0xf735c1af98a4d842), C64e(0x78edec209e6b6779), + C64e(0x41836315ea3adba8), C64e(0xfac33b4d32832c83), + C64e(0xa7403b1f1c2747f3), C64e(0x5940f034b72d769a), + C64e(0xe73e4e6cd2214ffd), C64e(0xb8fd8d39dc5759ef), + C64e(0x8d9b0c492b49ebda), C64e(0x5ba2d74968f3700d), + C64e(0x7d3baed07a8d5584), C64e(0xf5a5e9f0e4f88e65), + C64e(0xa0b8a2f436103b53), C64e(0x0ca8079e753eec5a), + C64e(0x9168949256e8884f), C64e(0x5bb05c55f8babc4c), + C64e(0xe3bb3b99f387947b), C64e(0x75daf4d6726b1c5d), + C64e(0x64aeac28dc34b36d), C64e(0x6c34a550b828db71), + C64e(0xf861e2f2108d512a), C64e(0xe3db643359dd75fc), + C64e(0x1cacbcf143ce3fa2), C64e(0x67bbd13c02e843b0), + C64e(0x330a5bca8829a175), C64e(0x7f34194db416535c), + C64e(0x923b94c30e794d1e), C64e(0x797475d7b6eeaf3f), + C64e(0xeaa8d4f7be1a3921), C64e(0x5cf47e094c232751), + C64e(0x26a32453ba323cd2), C64e(0x44a3174a6da6d5ad), + C64e(0xb51d3ea6aff2c908), C64e(0x83593d98916b3c56), + C64e(0x4cf87ca17286604d), C64e(0x46e23ecc086ec7f6), + C64e(0x2f9833b3b1bc765e), C64e(0x2bd666a5efc4e62a), + C64e(0x06f4b6e8bec1d436), C64e(0x74ee8215bcef2163), + C64e(0xfdc14e0df453c969), C64e(0xa77d5ac406585826), + C64e(0x7ec1141606e0fa16), C64e(0x7e90af3d28639d3f), + C64e(0xd2c9f2e3009bd20c), C64e(0x5faace30b7d40c30), + C64e(0x742a5116f2e03298), C64e(0x0deb30d8e3cef89a), + C64e(0x4bc59e7bb5f17992), C64e(0xff51e66e048668d3), + C64e(0x9b234d57e6966731), C64e(0xcce6a6f3170a7505), + C64e(0xb17681d913326cce), C64e(0x3c175284f805a262), + C64e(0xf42bcbb378471547), C64e(0xff46548223936a48), + C64e(0x38df58074e5e6565), C64e(0xf2fc7c89fc86508e), + C64e(0x31702e44d00bca86), C64e(0xf04009a23078474e), + C64e(0x65a0ee39d1f73883), C64e(0xf75ee937e42c3abd), + C64e(0x2197b2260113f86f), C64e(0xa344edd1ef9fdee7), + C64e(0x8ba0df15762592d9), C64e(0x3c85f7f612dc42be), + C64e(0xd8a7ec7cab27b07e), C64e(0x538d7ddaaa3ea8de), + C64e(0xaa25ce93bd0269d8), C64e(0x5af643fd1a7308f9), + C64e(0xc05fefda174a19a5), C64e(0x974d66334cfd216a), + C64e(0x35b49831db411570), C64e(0xea1e0fbbedcd549b), + C64e(0x9ad063a151974072), C64e(0xf6759dbf91476fe2) +}; + +#define Ceven_hi(r) (C[((r) << 2) + 0]) +#define Ceven_lo(r) (C[((r) << 2) + 1]) +#define Codd_hi(r) (C[((r) << 2) + 2]) +#define Codd_lo(r) (C[((r) << 2) + 3]) + +#define S(x0, x1, x2, x3, cb, r) do { \ + Sb(x0 ## h, x1 ## h, x2 ## h, x3 ## h, cb ## hi(r)); \ + Sb(x0 ## l, x1 ## l, x2 ## l, x3 ## l, cb ## lo(r)); \ + } while (0) + +#define L(x0, x1, x2, x3, x4, x5, x6, x7) do { \ + Lb(x0 ## h, x1 ## h, x2 ## h, x3 ## h, \ + x4 ## h, x5 ## h, x6 ## h, x7 ## h); \ + Lb(x0 ## l, x1 ## l, x2 ## l, x3 ## l, \ + x4 ## l, x5 ## l, x6 ## l, x7 ## l); \ + } while (0) + +#define Wz(x, c, n) do { \ + sph_u64 t = (x ## h & (c)) << (n); \ + x ## h = ((x ## h >> (n)) & (c)) | t; \ + t = (x ## l & (c)) << (n); \ + x ## l = ((x ## l >> (n)) & (c)) | t; \ + } while (0) + +#define W0(x) Wz(x, SPH_C64(0x5555555555555555), 1) +#define W1(x) Wz(x, SPH_C64(0x3333333333333333), 2) +#define W2(x) Wz(x, SPH_C64(0x0F0F0F0F0F0F0F0F), 4) +#define W3(x) Wz(x, SPH_C64(0x00FF00FF00FF00FF), 8) +#define W4(x) Wz(x, SPH_C64(0x0000FFFF0000FFFF), 16) +#define W5(x) Wz(x, SPH_C64(0x00000000FFFFFFFF), 32) +#define W6(x) do { \ + sph_u64 t = x ## h; \ + x ## h = x ## l; \ + x ## l = t; \ + } while (0) + +#define DECL_STATE \ + sph_u64 h0h, h1h, h2h, h3h, h4h, h5h, h6h, h7h; \ + sph_u64 h0l, h1l, h2l, h3l, h4l, h5l, h6l, h7l; \ + sph_u64 tmp; + +#define READ_STATE(state) do { \ + h0h = (state)->H.wide[ 0]; \ + h0l = (state)->H.wide[ 1]; \ + h1h = (state)->H.wide[ 2]; \ + h1l = (state)->H.wide[ 3]; \ + h2h = (state)->H.wide[ 4]; \ + h2l = (state)->H.wide[ 5]; \ + h3h = (state)->H.wide[ 6]; \ + h3l = (state)->H.wide[ 7]; \ + h4h = (state)->H.wide[ 8]; \ + h4l = (state)->H.wide[ 9]; \ + h5h = (state)->H.wide[10]; \ + h5l = (state)->H.wide[11]; \ + h6h = (state)->H.wide[12]; \ + h6l = (state)->H.wide[13]; \ + h7h = (state)->H.wide[14]; \ + h7l = (state)->H.wide[15]; \ + } while (0) + +#define WRITE_STATE(state) do { \ + (state)->H.wide[ 0] = h0h; \ + (state)->H.wide[ 1] = h0l; \ + (state)->H.wide[ 2] = h1h; \ + (state)->H.wide[ 3] = h1l; \ + (state)->H.wide[ 4] = h2h; \ + (state)->H.wide[ 5] = h2l; \ + (state)->H.wide[ 6] = h3h; \ + (state)->H.wide[ 7] = h3l; \ + (state)->H.wide[ 8] = h4h; \ + (state)->H.wide[ 9] = h4l; \ + (state)->H.wide[10] = h5h; \ + (state)->H.wide[11] = h5l; \ + (state)->H.wide[12] = h6h; \ + (state)->H.wide[13] = h6l; \ + (state)->H.wide[14] = h7h; \ + (state)->H.wide[15] = h7l; \ + } while (0) + +#define INPUT_BUF1 \ + sph_u64 m0h = dec64e_aligned(buf + 0); \ + sph_u64 m0l = dec64e_aligned(buf + 8); \ + sph_u64 m1h = dec64e_aligned(buf + 16); \ + sph_u64 m1l = dec64e_aligned(buf + 24); \ + sph_u64 m2h = dec64e_aligned(buf + 32); \ + sph_u64 m2l = dec64e_aligned(buf + 40); \ + sph_u64 m3h = dec64e_aligned(buf + 48); \ + sph_u64 m3l = dec64e_aligned(buf + 56); \ + h0h ^= m0h; \ + h0l ^= m0l; \ + h1h ^= m1h; \ + h1l ^= m1l; \ + h2h ^= m2h; \ + h2l ^= m2l; \ + h3h ^= m3h; \ + h3l ^= m3l; + +#define INPUT_BUF2 \ + h4h ^= m0h; \ + h4l ^= m0l; \ + h5h ^= m1h; \ + h5l ^= m1l; \ + h6h ^= m2h; \ + h6l ^= m2l; \ + h7h ^= m3h; \ + h7l ^= m3l; + +static const sph_u64 IV224[] = { + C64e(0x2dfedd62f99a98ac), C64e(0xae7cacd619d634e7), + C64e(0xa4831005bc301216), C64e(0xb86038c6c9661494), + C64e(0x66d9899f2580706f), C64e(0xce9ea31b1d9b1adc), + C64e(0x11e8325f7b366e10), C64e(0xf994857f02fa06c1), + C64e(0x1b4f1b5cd8c840b3), C64e(0x97f6a17f6e738099), + C64e(0xdcdf93a5adeaa3d3), C64e(0xa431e8dec9539a68), + C64e(0x22b4a98aec86a1e4), C64e(0xd574ac959ce56cf0), + C64e(0x15960deab5ab2bbf), C64e(0x9611dcf0dd64ea6e) +}; + +static const sph_u64 IV256[] = { + C64e(0xeb98a3412c20d3eb), C64e(0x92cdbe7b9cb245c1), + C64e(0x1c93519160d4c7fa), C64e(0x260082d67e508a03), + C64e(0xa4239e267726b945), C64e(0xe0fb1a48d41a9477), + C64e(0xcdb5ab26026b177a), C64e(0x56f024420fff2fa8), + C64e(0x71a396897f2e4d75), C64e(0x1d144908f77de262), + C64e(0x277695f776248f94), C64e(0x87d5b6574780296c), + C64e(0x5c5e272dac8e0d6c), C64e(0x518450c657057a0f), + C64e(0x7be4d367702412ea), C64e(0x89e3ab13d31cd769) +}; + +static const sph_u64 IV384[] = { + C64e(0x481e3bc6d813398a), C64e(0x6d3b5e894ade879b), + C64e(0x63faea68d480ad2e), C64e(0x332ccb21480f8267), + C64e(0x98aec84d9082b928), C64e(0xd455ea3041114249), + C64e(0x36f555b2924847ec), C64e(0xc7250a93baf43ce1), + C64e(0x569b7f8a27db454c), C64e(0x9efcbd496397af0e), + C64e(0x589fc27d26aa80cd), C64e(0x80c08b8c9deb2eda), + C64e(0x8a7981e8f8d5373a), C64e(0xf43967adddd17a71), + C64e(0xa9b4d3bda475d394), C64e(0x976c3fba9842737f) +}; + +static const sph_u64 IV512[] = { + C64e(0x6fd14b963e00aa17), C64e(0x636a2e057a15d543), + C64e(0x8a225e8d0c97ef0b), C64e(0xe9341259f2b3c361), + C64e(0x891da0c1536f801e), C64e(0x2aa9056bea2b6d80), + C64e(0x588eccdb2075baa6), C64e(0xa90f3a76baf83bf7), + C64e(0x0169e60541e34a69), C64e(0x46b58a8e2e6fe65a), + C64e(0x1047a7d0c1843c24), C64e(0x3b6e71b12d5ac199), + C64e(0xcf57f6ec9db1f856), C64e(0xa706887c5716b156), + C64e(0xe3c2fcdfe68517fb), C64e(0x545a4678cc8cdd4b) +}; + +#else + +static const sph_u32 C[] = { + C32e(0x72d5dea2), C32e(0xdf15f867), C32e(0x7b84150a), + C32e(0xb7231557), C32e(0x81abd690), C32e(0x4d5a87f6), + C32e(0x4e9f4fc5), C32e(0xc3d12b40), C32e(0xea983ae0), + C32e(0x5c45fa9c), C32e(0x03c5d299), C32e(0x66b2999a), + C32e(0x660296b4), C32e(0xf2bb538a), C32e(0xb556141a), + C32e(0x88dba231), C32e(0x03a35a5c), C32e(0x9a190edb), + C32e(0x403fb20a), C32e(0x87c14410), C32e(0x1c051980), + C32e(0x849e951d), C32e(0x6f33ebad), C32e(0x5ee7cddc), + C32e(0x10ba1392), C32e(0x02bf6b41), C32e(0xdc786515), + C32e(0xf7bb27d0), C32e(0x0a2c8139), C32e(0x37aa7850), + C32e(0x3f1abfd2), C32e(0x410091d3), C32e(0x422d5a0d), + C32e(0xf6cc7e90), C32e(0xdd629f9c), C32e(0x92c097ce), + C32e(0x185ca70b), C32e(0xc72b44ac), C32e(0xd1df65d6), + C32e(0x63c6fc23), C32e(0x976e6c03), C32e(0x9ee0b81a), + C32e(0x2105457e), C32e(0x446ceca8), C32e(0xeef103bb), + C32e(0x5d8e61fa), C32e(0xfd9697b2), C32e(0x94838197), + C32e(0x4a8e8537), C32e(0xdb03302f), C32e(0x2a678d2d), + C32e(0xfb9f6a95), C32e(0x8afe7381), C32e(0xf8b8696c), + C32e(0x8ac77246), C32e(0xc07f4214), C32e(0xc5f4158f), + C32e(0xbdc75ec4), C32e(0x75446fa7), C32e(0x8f11bb80), + C32e(0x52de75b7), C32e(0xaee488bc), C32e(0x82b8001e), + C32e(0x98a6a3f4), C32e(0x8ef48f33), C32e(0xa9a36315), + C32e(0xaa5f5624), C32e(0xd5b7f989), C32e(0xb6f1ed20), + C32e(0x7c5ae0fd), C32e(0x36cae95a), C32e(0x06422c36), + C32e(0xce293543), C32e(0x4efe983d), C32e(0x533af974), + C32e(0x739a4ba7), C32e(0xd0f51f59), C32e(0x6f4e8186), + C32e(0x0e9dad81), C32e(0xafd85a9f), C32e(0xa7050667), + C32e(0xee34626a), C32e(0x8b0b28be), C32e(0x6eb91727), + C32e(0x47740726), C32e(0xc680103f), C32e(0xe0a07e6f), + C32e(0xc67e487b), C32e(0x0d550aa5), C32e(0x4af8a4c0), + C32e(0x91e3e79f), C32e(0x978ef19e), C32e(0x86767281), + C32e(0x50608dd4), C32e(0x7e9e5a41), C32e(0xf3e5b062), + C32e(0xfc9f1fec), C32e(0x4054207a), C32e(0xe3e41a00), + C32e(0xcef4c984), C32e(0x4fd794f5), C32e(0x9dfa95d8), + C32e(0x552e7e11), C32e(0x24c354a5), C32e(0x5bdf7228), + C32e(0xbdfe6e28), C32e(0x78f57fe2), C32e(0x0fa5c4b2), + C32e(0x05897cef), C32e(0xee49d32e), C32e(0x447e9385), + C32e(0xeb28597f), C32e(0x705f6937), C32e(0xb324314a), + C32e(0x5e8628f1), C32e(0x1dd6e465), C32e(0xc71b7704), + C32e(0x51b920e7), C32e(0x74fe43e8), C32e(0x23d4878a), + C32e(0x7d29e8a3), C32e(0x927694f2), C32e(0xddcb7a09), + C32e(0x9b30d9c1), C32e(0x1d1b30fb), C32e(0x5bdc1be0), + C32e(0xda24494f), C32e(0xf29c82bf), C32e(0xa4e7ba31), + C32e(0xb470bfff), C32e(0x0d324405), C32e(0xdef8bc48), + C32e(0x3baefc32), C32e(0x53bbd339), C32e(0x459fc3c1), + C32e(0xe0298ba0), C32e(0xe5c905fd), C32e(0xf7ae090f), + C32e(0x94703412), C32e(0x4290f134), C32e(0xa271b701), + C32e(0xe344ed95), C32e(0xe93b8e36), C32e(0x4f2f984a), + C32e(0x88401d63), C32e(0xa06cf615), C32e(0x47c1444b), + C32e(0x8752afff), C32e(0x7ebb4af1), C32e(0xe20ac630), + C32e(0x4670b6c5), C32e(0xcc6e8ce6), C32e(0xa4d5a456), + C32e(0xbd4fca00), C32e(0xda9d844b), C32e(0xc83e18ae), + C32e(0x7357ce45), C32e(0x3064d1ad), C32e(0xe8a6ce68), + C32e(0x145c2567), C32e(0xa3da8cf2), C32e(0xcb0ee116), + C32e(0x33e90658), C32e(0x9a94999a), C32e(0x1f60b220), + C32e(0xc26f847b), C32e(0xd1ceac7f), C32e(0xa0d18518), + C32e(0x32595ba1), C32e(0x8ddd19d3), C32e(0x509a1cc0), + C32e(0xaaa5b446), C32e(0x9f3d6367), C32e(0xe4046bba), + C32e(0xf6ca19ab), C32e(0x0b56ee7e), C32e(0x1fb179ea), + C32e(0xa9282174), C32e(0xe9bdf735), C32e(0x3b3651ee), + C32e(0x1d57ac5a), C32e(0x7550d376), C32e(0x3a46c2fe), + C32e(0xa37d7001), C32e(0xf735c1af), C32e(0x98a4d842), + C32e(0x78edec20), C32e(0x9e6b6779), C32e(0x41836315), + C32e(0xea3adba8), C32e(0xfac33b4d), C32e(0x32832c83), + C32e(0xa7403b1f), C32e(0x1c2747f3), C32e(0x5940f034), + C32e(0xb72d769a), C32e(0xe73e4e6c), C32e(0xd2214ffd), + C32e(0xb8fd8d39), C32e(0xdc5759ef), C32e(0x8d9b0c49), + C32e(0x2b49ebda), C32e(0x5ba2d749), C32e(0x68f3700d), + C32e(0x7d3baed0), C32e(0x7a8d5584), C32e(0xf5a5e9f0), + C32e(0xe4f88e65), C32e(0xa0b8a2f4), C32e(0x36103b53), + C32e(0x0ca8079e), C32e(0x753eec5a), C32e(0x91689492), + C32e(0x56e8884f), C32e(0x5bb05c55), C32e(0xf8babc4c), + C32e(0xe3bb3b99), C32e(0xf387947b), C32e(0x75daf4d6), + C32e(0x726b1c5d), C32e(0x64aeac28), C32e(0xdc34b36d), + C32e(0x6c34a550), C32e(0xb828db71), C32e(0xf861e2f2), + C32e(0x108d512a), C32e(0xe3db6433), C32e(0x59dd75fc), + C32e(0x1cacbcf1), C32e(0x43ce3fa2), C32e(0x67bbd13c), + C32e(0x02e843b0), C32e(0x330a5bca), C32e(0x8829a175), + C32e(0x7f34194d), C32e(0xb416535c), C32e(0x923b94c3), + C32e(0x0e794d1e), C32e(0x797475d7), C32e(0xb6eeaf3f), + C32e(0xeaa8d4f7), C32e(0xbe1a3921), C32e(0x5cf47e09), + C32e(0x4c232751), C32e(0x26a32453), C32e(0xba323cd2), + C32e(0x44a3174a), C32e(0x6da6d5ad), C32e(0xb51d3ea6), + C32e(0xaff2c908), C32e(0x83593d98), C32e(0x916b3c56), + C32e(0x4cf87ca1), C32e(0x7286604d), C32e(0x46e23ecc), + C32e(0x086ec7f6), C32e(0x2f9833b3), C32e(0xb1bc765e), + C32e(0x2bd666a5), C32e(0xefc4e62a), C32e(0x06f4b6e8), + C32e(0xbec1d436), C32e(0x74ee8215), C32e(0xbcef2163), + C32e(0xfdc14e0d), C32e(0xf453c969), C32e(0xa77d5ac4), + C32e(0x06585826), C32e(0x7ec11416), C32e(0x06e0fa16), + C32e(0x7e90af3d), C32e(0x28639d3f), C32e(0xd2c9f2e3), + C32e(0x009bd20c), C32e(0x5faace30), C32e(0xb7d40c30), + C32e(0x742a5116), C32e(0xf2e03298), C32e(0x0deb30d8), + C32e(0xe3cef89a), C32e(0x4bc59e7b), C32e(0xb5f17992), + C32e(0xff51e66e), C32e(0x048668d3), C32e(0x9b234d57), + C32e(0xe6966731), C32e(0xcce6a6f3), C32e(0x170a7505), + C32e(0xb17681d9), C32e(0x13326cce), C32e(0x3c175284), + C32e(0xf805a262), C32e(0xf42bcbb3), C32e(0x78471547), + C32e(0xff465482), C32e(0x23936a48), C32e(0x38df5807), + C32e(0x4e5e6565), C32e(0xf2fc7c89), C32e(0xfc86508e), + C32e(0x31702e44), C32e(0xd00bca86), C32e(0xf04009a2), + C32e(0x3078474e), C32e(0x65a0ee39), C32e(0xd1f73883), + C32e(0xf75ee937), C32e(0xe42c3abd), C32e(0x2197b226), + C32e(0x0113f86f), C32e(0xa344edd1), C32e(0xef9fdee7), + C32e(0x8ba0df15), C32e(0x762592d9), C32e(0x3c85f7f6), + C32e(0x12dc42be), C32e(0xd8a7ec7c), C32e(0xab27b07e), + C32e(0x538d7dda), C32e(0xaa3ea8de), C32e(0xaa25ce93), + C32e(0xbd0269d8), C32e(0x5af643fd), C32e(0x1a7308f9), + C32e(0xc05fefda), C32e(0x174a19a5), C32e(0x974d6633), + C32e(0x4cfd216a), C32e(0x35b49831), C32e(0xdb411570), + C32e(0xea1e0fbb), C32e(0xedcd549b), C32e(0x9ad063a1), + C32e(0x51974072), C32e(0xf6759dbf), C32e(0x91476fe2) +}; + +#define Ceven_w3(r) (C[((r) << 3) + 0]) +#define Ceven_w2(r) (C[((r) << 3) + 1]) +#define Ceven_w1(r) (C[((r) << 3) + 2]) +#define Ceven_w0(r) (C[((r) << 3) + 3]) +#define Codd_w3(r) (C[((r) << 3) + 4]) +#define Codd_w2(r) (C[((r) << 3) + 5]) +#define Codd_w1(r) (C[((r) << 3) + 6]) +#define Codd_w0(r) (C[((r) << 3) + 7]) + +#define S(x0, x1, x2, x3, cb, r) do { \ + Sb(x0 ## 3, x1 ## 3, x2 ## 3, x3 ## 3, cb ## w3(r)); \ + Sb(x0 ## 2, x1 ## 2, x2 ## 2, x3 ## 2, cb ## w2(r)); \ + Sb(x0 ## 1, x1 ## 1, x2 ## 1, x3 ## 1, cb ## w1(r)); \ + Sb(x0 ## 0, x1 ## 0, x2 ## 0, x3 ## 0, cb ## w0(r)); \ + } while (0) + +#define L(x0, x1, x2, x3, x4, x5, x6, x7) do { \ + Lb(x0 ## 3, x1 ## 3, x2 ## 3, x3 ## 3, \ + x4 ## 3, x5 ## 3, x6 ## 3, x7 ## 3); \ + Lb(x0 ## 2, x1 ## 2, x2 ## 2, x3 ## 2, \ + x4 ## 2, x5 ## 2, x6 ## 2, x7 ## 2); \ + Lb(x0 ## 1, x1 ## 1, x2 ## 1, x3 ## 1, \ + x4 ## 1, x5 ## 1, x6 ## 1, x7 ## 1); \ + Lb(x0 ## 0, x1 ## 0, x2 ## 0, x3 ## 0, \ + x4 ## 0, x5 ## 0, x6 ## 0, x7 ## 0); \ + } while (0) + +#define Wz(x, c, n) do { \ + sph_u32 t = (x ## 3 & (c)) << (n); \ + x ## 3 = ((x ## 3 >> (n)) & (c)) | t; \ + t = (x ## 2 & (c)) << (n); \ + x ## 2 = ((x ## 2 >> (n)) & (c)) | t; \ + t = (x ## 1 & (c)) << (n); \ + x ## 1 = ((x ## 1 >> (n)) & (c)) | t; \ + t = (x ## 0 & (c)) << (n); \ + x ## 0 = ((x ## 0 >> (n)) & (c)) | t; \ + } while (0) + +#define W0(x) Wz(x, SPH_C32(0x55555555), 1) +#define W1(x) Wz(x, SPH_C32(0x33333333), 2) +#define W2(x) Wz(x, SPH_C32(0x0F0F0F0F), 4) +#define W3(x) Wz(x, SPH_C32(0x00FF00FF), 8) +#define W4(x) Wz(x, SPH_C32(0x0000FFFF), 16) +#define W5(x) do { \ + sph_u32 t = x ## 3; \ + x ## 3 = x ## 2; \ + x ## 2 = t; \ + t = x ## 1; \ + x ## 1 = x ## 0; \ + x ## 0 = t; \ + } while (0) +#define W6(x) do { \ + sph_u32 t = x ## 3; \ + x ## 3 = x ## 1; \ + x ## 1 = t; \ + t = x ## 2; \ + x ## 2 = x ## 0; \ + x ## 0 = t; \ + } while (0) + +#define DECL_STATE \ + sph_u32 h03, h02, h01, h00, h13, h12, h11, h10; \ + sph_u32 h23, h22, h21, h20, h33, h32, h31, h30; \ + sph_u32 h43, h42, h41, h40, h53, h52, h51, h50; \ + sph_u32 h63, h62, h61, h60, h73, h72, h71, h70; \ + sph_u32 tmp; + +#define READ_STATE(state) do { \ + h03 = (state)->H.narrow[ 0]; \ + h02 = (state)->H.narrow[ 1]; \ + h01 = (state)->H.narrow[ 2]; \ + h00 = (state)->H.narrow[ 3]; \ + h13 = (state)->H.narrow[ 4]; \ + h12 = (state)->H.narrow[ 5]; \ + h11 = (state)->H.narrow[ 6]; \ + h10 = (state)->H.narrow[ 7]; \ + h23 = (state)->H.narrow[ 8]; \ + h22 = (state)->H.narrow[ 9]; \ + h21 = (state)->H.narrow[10]; \ + h20 = (state)->H.narrow[11]; \ + h33 = (state)->H.narrow[12]; \ + h32 = (state)->H.narrow[13]; \ + h31 = (state)->H.narrow[14]; \ + h30 = (state)->H.narrow[15]; \ + h43 = (state)->H.narrow[16]; \ + h42 = (state)->H.narrow[17]; \ + h41 = (state)->H.narrow[18]; \ + h40 = (state)->H.narrow[19]; \ + h53 = (state)->H.narrow[20]; \ + h52 = (state)->H.narrow[21]; \ + h51 = (state)->H.narrow[22]; \ + h50 = (state)->H.narrow[23]; \ + h63 = (state)->H.narrow[24]; \ + h62 = (state)->H.narrow[25]; \ + h61 = (state)->H.narrow[26]; \ + h60 = (state)->H.narrow[27]; \ + h73 = (state)->H.narrow[28]; \ + h72 = (state)->H.narrow[29]; \ + h71 = (state)->H.narrow[30]; \ + h70 = (state)->H.narrow[31]; \ + } while (0) + +#define WRITE_STATE(state) do { \ + (state)->H.narrow[ 0] = h03; \ + (state)->H.narrow[ 1] = h02; \ + (state)->H.narrow[ 2] = h01; \ + (state)->H.narrow[ 3] = h00; \ + (state)->H.narrow[ 4] = h13; \ + (state)->H.narrow[ 5] = h12; \ + (state)->H.narrow[ 6] = h11; \ + (state)->H.narrow[ 7] = h10; \ + (state)->H.narrow[ 8] = h23; \ + (state)->H.narrow[ 9] = h22; \ + (state)->H.narrow[10] = h21; \ + (state)->H.narrow[11] = h20; \ + (state)->H.narrow[12] = h33; \ + (state)->H.narrow[13] = h32; \ + (state)->H.narrow[14] = h31; \ + (state)->H.narrow[15] = h30; \ + (state)->H.narrow[16] = h43; \ + (state)->H.narrow[17] = h42; \ + (state)->H.narrow[18] = h41; \ + (state)->H.narrow[19] = h40; \ + (state)->H.narrow[20] = h53; \ + (state)->H.narrow[21] = h52; \ + (state)->H.narrow[22] = h51; \ + (state)->H.narrow[23] = h50; \ + (state)->H.narrow[24] = h63; \ + (state)->H.narrow[25] = h62; \ + (state)->H.narrow[26] = h61; \ + (state)->H.narrow[27] = h60; \ + (state)->H.narrow[28] = h73; \ + (state)->H.narrow[29] = h72; \ + (state)->H.narrow[30] = h71; \ + (state)->H.narrow[31] = h70; \ + } while (0) + +#define INPUT_BUF1 \ + sph_u32 m03 = dec32e_aligned(buf + 0); \ + sph_u32 m02 = dec32e_aligned(buf + 4); \ + sph_u32 m01 = dec32e_aligned(buf + 8); \ + sph_u32 m00 = dec32e_aligned(buf + 12); \ + sph_u32 m13 = dec32e_aligned(buf + 16); \ + sph_u32 m12 = dec32e_aligned(buf + 20); \ + sph_u32 m11 = dec32e_aligned(buf + 24); \ + sph_u32 m10 = dec32e_aligned(buf + 28); \ + sph_u32 m23 = dec32e_aligned(buf + 32); \ + sph_u32 m22 = dec32e_aligned(buf + 36); \ + sph_u32 m21 = dec32e_aligned(buf + 40); \ + sph_u32 m20 = dec32e_aligned(buf + 44); \ + sph_u32 m33 = dec32e_aligned(buf + 48); \ + sph_u32 m32 = dec32e_aligned(buf + 52); \ + sph_u32 m31 = dec32e_aligned(buf + 56); \ + sph_u32 m30 = dec32e_aligned(buf + 60); \ + h03 ^= m03; \ + h02 ^= m02; \ + h01 ^= m01; \ + h00 ^= m00; \ + h13 ^= m13; \ + h12 ^= m12; \ + h11 ^= m11; \ + h10 ^= m10; \ + h23 ^= m23; \ + h22 ^= m22; \ + h21 ^= m21; \ + h20 ^= m20; \ + h33 ^= m33; \ + h32 ^= m32; \ + h31 ^= m31; \ + h30 ^= m30; + +#define INPUT_BUF2 \ + h43 ^= m03; \ + h42 ^= m02; \ + h41 ^= m01; \ + h40 ^= m00; \ + h53 ^= m13; \ + h52 ^= m12; \ + h51 ^= m11; \ + h50 ^= m10; \ + h63 ^= m23; \ + h62 ^= m22; \ + h61 ^= m21; \ + h60 ^= m20; \ + h73 ^= m33; \ + h72 ^= m32; \ + h71 ^= m31; \ + h70 ^= m30; + +static const sph_u32 IV224[] = { + C32e(0x2dfedd62), C32e(0xf99a98ac), C32e(0xae7cacd6), C32e(0x19d634e7), + C32e(0xa4831005), C32e(0xbc301216), C32e(0xb86038c6), C32e(0xc9661494), + C32e(0x66d9899f), C32e(0x2580706f), C32e(0xce9ea31b), C32e(0x1d9b1adc), + C32e(0x11e8325f), C32e(0x7b366e10), C32e(0xf994857f), C32e(0x02fa06c1), + C32e(0x1b4f1b5c), C32e(0xd8c840b3), C32e(0x97f6a17f), C32e(0x6e738099), + C32e(0xdcdf93a5), C32e(0xadeaa3d3), C32e(0xa431e8de), C32e(0xc9539a68), + C32e(0x22b4a98a), C32e(0xec86a1e4), C32e(0xd574ac95), C32e(0x9ce56cf0), + C32e(0x15960dea), C32e(0xb5ab2bbf), C32e(0x9611dcf0), C32e(0xdd64ea6e) +}; + +static const sph_u32 IV256[] = { + C32e(0xeb98a341), C32e(0x2c20d3eb), C32e(0x92cdbe7b), C32e(0x9cb245c1), + C32e(0x1c935191), C32e(0x60d4c7fa), C32e(0x260082d6), C32e(0x7e508a03), + C32e(0xa4239e26), C32e(0x7726b945), C32e(0xe0fb1a48), C32e(0xd41a9477), + C32e(0xcdb5ab26), C32e(0x026b177a), C32e(0x56f02442), C32e(0x0fff2fa8), + C32e(0x71a39689), C32e(0x7f2e4d75), C32e(0x1d144908), C32e(0xf77de262), + C32e(0x277695f7), C32e(0x76248f94), C32e(0x87d5b657), C32e(0x4780296c), + C32e(0x5c5e272d), C32e(0xac8e0d6c), C32e(0x518450c6), C32e(0x57057a0f), + C32e(0x7be4d367), C32e(0x702412ea), C32e(0x89e3ab13), C32e(0xd31cd769) +}; + +static const sph_u32 IV384[] = { + C32e(0x481e3bc6), C32e(0xd813398a), C32e(0x6d3b5e89), C32e(0x4ade879b), + C32e(0x63faea68), C32e(0xd480ad2e), C32e(0x332ccb21), C32e(0x480f8267), + C32e(0x98aec84d), C32e(0x9082b928), C32e(0xd455ea30), C32e(0x41114249), + C32e(0x36f555b2), C32e(0x924847ec), C32e(0xc7250a93), C32e(0xbaf43ce1), + C32e(0x569b7f8a), C32e(0x27db454c), C32e(0x9efcbd49), C32e(0x6397af0e), + C32e(0x589fc27d), C32e(0x26aa80cd), C32e(0x80c08b8c), C32e(0x9deb2eda), + C32e(0x8a7981e8), C32e(0xf8d5373a), C32e(0xf43967ad), C32e(0xddd17a71), + C32e(0xa9b4d3bd), C32e(0xa475d394), C32e(0x976c3fba), C32e(0x9842737f) +}; + +static const sph_u32 IV512[] = { + C32e(0x6fd14b96), C32e(0x3e00aa17), C32e(0x636a2e05), C32e(0x7a15d543), + C32e(0x8a225e8d), C32e(0x0c97ef0b), C32e(0xe9341259), C32e(0xf2b3c361), + C32e(0x891da0c1), C32e(0x536f801e), C32e(0x2aa9056b), C32e(0xea2b6d80), + C32e(0x588eccdb), C32e(0x2075baa6), C32e(0xa90f3a76), C32e(0xbaf83bf7), + C32e(0x0169e605), C32e(0x41e34a69), C32e(0x46b58a8e), C32e(0x2e6fe65a), + C32e(0x1047a7d0), C32e(0xc1843c24), C32e(0x3b6e71b1), C32e(0x2d5ac199), + C32e(0xcf57f6ec), C32e(0x9db1f856), C32e(0xa706887c), C32e(0x5716b156), + C32e(0xe3c2fcdf), C32e(0xe68517fb), C32e(0x545a4678), C32e(0xcc8cdd4b) +}; + +#endif + +#define SL(ro) SLu(r + ro, ro) + +#define SLu(r, ro) do { \ + S(h0, h2, h4, h6, Ceven_, r); \ + S(h1, h3, h5, h7, Codd_, r); \ + L(h0, h2, h4, h6, h1, h3, h5, h7); \ + W ## ro(h1); \ + W ## ro(h3); \ + W ## ro(h5); \ + W ## ro(h7); \ + } while (0) + +#if SPH_SMALL_FOOTPRINT_JH + +#if SPH_JH_64 + +/* + * The "small footprint" 64-bit version just uses a partially unrolled + * loop. + */ + +#define E8 do { \ + unsigned r; \ + for (r = 0; r < 42; r += 7) { \ + SL(0); \ + SL(1); \ + SL(2); \ + SL(3); \ + SL(4); \ + SL(5); \ + SL(6); \ + } \ + } while (0) + +#else + +#define E8 do { \ + unsigned r, g; \ + for (r = g = 0; r < 42; r ++) { \ + S(h0, h2, h4, h6, Ceven_, r); \ + S(h1, h3, h5, h7, Codd_, r); \ + L(h0, h2, h4, h6, h1, h3, h5, h7); \ + switch (g) { \ + case 0: \ + W0(h1); \ + W0(h3); \ + W0(h5); \ + W0(h7); \ + break; \ + case 1: \ + W1(h1); \ + W1(h3); \ + W1(h5); \ + W1(h7); \ + break; \ + case 2: \ + W2(h1); \ + W2(h3); \ + W2(h5); \ + W2(h7); \ + break; \ + case 3: \ + W3(h1); \ + W3(h3); \ + W3(h5); \ + W3(h7); \ + break; \ + case 4: \ + W4(h1); \ + W4(h3); \ + W4(h5); \ + W4(h7); \ + break; \ + case 5: \ + W5(h1); \ + W5(h3); \ + W5(h5); \ + W5(h7); \ + break; \ + case 6: \ + W6(h1); \ + W6(h3); \ + W6(h5); \ + W6(h7); \ + break; \ + } \ + if (++ g == 7) \ + g = 0; \ + } \ + } while (0) + +#endif + +#else + +#if SPH_JH_64 + +/* + * On a "true 64-bit" architecture, we can unroll at will. + */ + +#define E8 do { \ + SLu( 0, 0); \ + SLu( 1, 1); \ + SLu( 2, 2); \ + SLu( 3, 3); \ + SLu( 4, 4); \ + SLu( 5, 5); \ + SLu( 6, 6); \ + SLu( 7, 0); \ + SLu( 8, 1); \ + SLu( 9, 2); \ + SLu(10, 3); \ + SLu(11, 4); \ + SLu(12, 5); \ + SLu(13, 6); \ + SLu(14, 0); \ + SLu(15, 1); \ + SLu(16, 2); \ + SLu(17, 3); \ + SLu(18, 4); \ + SLu(19, 5); \ + SLu(20, 6); \ + SLu(21, 0); \ + SLu(22, 1); \ + SLu(23, 2); \ + SLu(24, 3); \ + SLu(25, 4); \ + SLu(26, 5); \ + SLu(27, 6); \ + SLu(28, 0); \ + SLu(29, 1); \ + SLu(30, 2); \ + SLu(31, 3); \ + SLu(32, 4); \ + SLu(33, 5); \ + SLu(34, 6); \ + SLu(35, 0); \ + SLu(36, 1); \ + SLu(37, 2); \ + SLu(38, 3); \ + SLu(39, 4); \ + SLu(40, 5); \ + SLu(41, 6); \ + } while (0) + +#else + +/* + * We are not aiming at a small footprint, but we are still using a + * 32-bit implementation. Full loop unrolling would smash the L1 + * cache on some "big" architectures (32 kB L1 cache). + */ + +#define E8 do { \ + unsigned r; \ + for (r = 0; r < 42; r += 7) { \ + SL(0); \ + SL(1); \ + SL(2); \ + SL(3); \ + SL(4); \ + SL(5); \ + SL(6); \ + } \ + } while (0) + +#endif + +#endif + +static void +jh_init(sph_jh_context *sc, const void *iv) +{ + sc->ptr = 0; +#if SPH_JH_64 + memcpy(sc->H.wide, iv, sizeof sc->H.wide); +#else + memcpy(sc->H.narrow, iv, sizeof sc->H.narrow); +#endif +#if SPH_64 + sc->block_count = 0; +#else + sc->block_count_high = 0; + sc->block_count_low = 0; +#endif +} + +static void +jh_core(sph_jh_context *sc, const void *data, size_t len) +{ + unsigned char *buf; + size_t ptr; + DECL_STATE + + buf = sc->buf; + ptr = sc->ptr; + if (len < (sizeof sc->buf) - ptr) { + memcpy(buf + ptr, data, len); + ptr += len; + sc->ptr = ptr; + return; + } + + READ_STATE(sc); + while (len > 0) { + size_t clen; + + clen = (sizeof sc->buf) - ptr; + if (clen > len) + clen = len; + memcpy(buf + ptr, data, clen); + ptr += clen; + data = (const unsigned char *)data + clen; + len -= clen; + if (ptr == sizeof sc->buf) { + INPUT_BUF1; + E8; + INPUT_BUF2; +#if SPH_64 + sc->block_count ++; +#else + if ((sc->block_count_low = SPH_T32( + sc->block_count_low + 1)) == 0) + sc->block_count_high ++; +#endif + ptr = 0; + } + } + WRITE_STATE(sc); + sc->ptr = ptr; +} + +static void +jh_close(sph_jh_context *sc, unsigned ub, unsigned n, + void *dst, size_t out_size_w32, const void *iv) +{ + unsigned z; + unsigned char buf[128]; + size_t numz, u; +#if SPH_64 + sph_u64 l0, l1; +#else + sph_u32 l0, l1, l2, l3; +#endif + + z = 0x80 >> n; + buf[0] = ((ub & -z) | z) & 0xFF; + if (sc->ptr == 0 && n == 0) { + numz = 47; + } else { + numz = 111 - sc->ptr; + } + memset(buf + 1, 0, numz); +#if SPH_64 + l0 = SPH_T64(sc->block_count << 9) + (sc->ptr << 3) + n; + l1 = SPH_T64(sc->block_count >> 55); + sph_enc64be(buf + numz + 1, l1); + sph_enc64be(buf + numz + 9, l0); +#else + l0 = SPH_T32(sc->block_count_low << 9) + (sc->ptr << 3) + n; + l1 = SPH_T32(sc->block_count_low >> 23) + + SPH_T32(sc->block_count_high << 9); + l2 = SPH_T32(sc->block_count_high >> 23); + l3 = 0; + sph_enc32be(buf + numz + 1, l3); + sph_enc32be(buf + numz + 5, l2); + sph_enc32be(buf + numz + 9, l1); + sph_enc32be(buf + numz + 13, l0); +#endif + jh_core(sc, buf, numz + 17); +#if SPH_JH_64 + for (u = 0; u < 8; u ++) + enc64e(buf + (u << 3), sc->H.wide[u + 8]); +#else + for (u = 0; u < 16; u ++) + enc32e(buf + (u << 2), sc->H.narrow[u + 16]); +#endif + memcpy(dst, buf + ((16 - out_size_w32) << 2), out_size_w32 << 2); + jh_init(sc, iv); +} + +/* see sph_jh.h */ +void +sph_jh224_init(void *cc) +{ + jh_init(cc, IV224); +} + +/* see sph_jh.h */ +void +sph_jh224(void *cc, const void *data, size_t len) +{ + jh_core(cc, data, len); +} + +/* see sph_jh.h */ +void +sph_jh224_close(void *cc, void *dst) +{ + jh_close(cc, 0, 0, dst, 7, IV224); +} + +/* see sph_jh.h */ +void +sph_jh224_addbits_and_close(void *cc, unsigned ub, unsigned n, void *dst) +{ + jh_close(cc, ub, n, dst, 7, IV224); +} + +/* see sph_jh.h */ +void +sph_jh256_init(void *cc) +{ + jh_init(cc, IV256); +} + +/* see sph_jh.h */ +void +sph_jh256(void *cc, const void *data, size_t len) +{ + jh_core(cc, data, len); +} + +/* see sph_jh.h */ +void +sph_jh256_close(void *cc, void *dst) +{ + jh_close(cc, 0, 0, dst, 8, IV256); +} + +/* see sph_jh.h */ +void +sph_jh256_addbits_and_close(void *cc, unsigned ub, unsigned n, void *dst) +{ + jh_close(cc, ub, n, dst, 8, IV256); +} + +/* see sph_jh.h */ +void +sph_jh384_init(void *cc) +{ + jh_init(cc, IV384); +} + +/* see sph_jh.h */ +void +sph_jh384(void *cc, const void *data, size_t len) +{ + jh_core(cc, data, len); +} + +/* see sph_jh.h */ +void +sph_jh384_close(void *cc, void *dst) +{ + jh_close(cc, 0, 0, dst, 12, IV384); +} + +/* see sph_jh.h */ +void +sph_jh384_addbits_and_close(void *cc, unsigned ub, unsigned n, void *dst) +{ + jh_close(cc, ub, n, dst, 12, IV384); +} + +/* see sph_jh.h */ +void +sph_jh512_init(void *cc) +{ + jh_init(cc, IV512); +} + +/* see sph_jh.h */ +void +sph_jh512(void *cc, const void *data, size_t len) +{ + jh_core(cc, data, len); +} + +/* see sph_jh.h */ +void +sph_jh512_close(void *cc, void *dst) +{ + jh_close(cc, 0, 0, dst, 16, IV512); +} + +/* see sph_jh.h */ +void +sph_jh512_addbits_and_close(void *cc, unsigned ub, unsigned n, void *dst) +{ + jh_close(cc, ub, n, dst, 16, IV512); +} + +#ifdef __cplusplus +} +#endif diff --git a/src/json/LICENSE.txt b/src/json/LICENSE.txt new file mode 100644 index 0000000..797d536 --- /dev/null +++ b/src/json/LICENSE.txt @@ -0,0 +1,24 @@ +The MIT License + +Copyright (c) 2007 - 2009 John W. Wilkinson + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. diff --git a/src/json/json_spirit.h b/src/json/json_spirit.h new file mode 100644 index 0000000..ac1879d --- /dev/null +++ b/src/json/json_spirit.h @@ -0,0 +1,18 @@ +#ifndef JSON_SPIRIT +#define JSON_SPIRIT + +// Copyright John W. Wilkinson 2007 - 2009. +// Distributed under the MIT License, see accompanying file LICENSE.txt + +// json spirit version 4.03 + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include "json_spirit_value.h" +#include "json_spirit_reader.h" +#include "json_spirit_writer.h" +#include "json_spirit_utils.h" + +#endif diff --git a/src/json/json_spirit_error_position.h b/src/json/json_spirit_error_position.h new file mode 100644 index 0000000..1720850 --- /dev/null +++ b/src/json/json_spirit_error_position.h @@ -0,0 +1,54 @@ +#ifndef JSON_SPIRIT_ERROR_POSITION +#define JSON_SPIRIT_ERROR_POSITION + +// Copyright John W. Wilkinson 2007 - 2009. +// Distributed under the MIT License, see accompanying file LICENSE.txt + +// json spirit version 4.03 + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include + +namespace json_spirit +{ + // An Error_position exception is thrown by the "read_or_throw" functions below on finding an error. + // Note the "read_or_throw" functions are around 3 times slower than the standard functions "read" + // functions that return a bool. + // + struct Error_position + { + Error_position(); + Error_position( unsigned int line, unsigned int column, const std::string& reason ); + bool operator==( const Error_position& lhs ) const; + unsigned int line_; + unsigned int column_; + std::string reason_; + }; + + inline Error_position::Error_position() + : line_( 0 ) + , column_( 0 ) + { + } + + inline Error_position::Error_position( unsigned int line, unsigned int column, const std::string& reason ) + : line_( line ) + , column_( column ) + , reason_( reason ) + { + } + + inline bool Error_position::operator==( const Error_position& lhs ) const + { + if( this == &lhs ) return true; + + return ( reason_ == lhs.reason_ ) && + ( line_ == lhs.line_ ) && + ( column_ == lhs.column_ ); +} +} + +#endif diff --git a/src/json/json_spirit_reader.cpp b/src/json/json_spirit_reader.cpp new file mode 100644 index 0000000..aa4f637 --- /dev/null +++ b/src/json/json_spirit_reader.cpp @@ -0,0 +1,137 @@ +// Copyright John W. Wilkinson 2007 - 2009. +// Distributed under the MIT License, see accompanying file LICENSE.txt + +// json spirit version 4.03 + +#include "json_spirit_reader.h" +#include "json_spirit_reader_template.h" + +using namespace json_spirit; + +bool json_spirit::read( const std::string& s, Value& value ) +{ + return read_string( s, value ); +} + +void json_spirit::read_or_throw( const std::string& s, Value& value ) +{ + read_string_or_throw( s, value ); +} + +bool json_spirit::read( std::istream& is, Value& value ) +{ + return read_stream( is, value ); +} + +void json_spirit::read_or_throw( std::istream& is, Value& value ) +{ + read_stream_or_throw( is, value ); +} + +bool json_spirit::read( std::string::const_iterator& begin, std::string::const_iterator end, Value& value ) +{ + return read_range( begin, end, value ); +} + +void json_spirit::read_or_throw( std::string::const_iterator& begin, std::string::const_iterator end, Value& value ) +{ + begin = read_range_or_throw( begin, end, value ); +} + +#ifndef BOOST_NO_STD_WSTRING + +bool json_spirit::read( const std::wstring& s, wValue& value ) +{ + return read_string( s, value ); +} + +void json_spirit::read_or_throw( const std::wstring& s, wValue& value ) +{ + read_string_or_throw( s, value ); +} + +bool json_spirit::read( std::wistream& is, wValue& value ) +{ + return read_stream( is, value ); +} + +void json_spirit::read_or_throw( std::wistream& is, wValue& value ) +{ + read_stream_or_throw( is, value ); +} + +bool json_spirit::read( std::wstring::const_iterator& begin, std::wstring::const_iterator end, wValue& value ) +{ + return read_range( begin, end, value ); +} + +void json_spirit::read_or_throw( std::wstring::const_iterator& begin, std::wstring::const_iterator end, wValue& value ) +{ + begin = read_range_or_throw( begin, end, value ); +} + +#endif + +bool json_spirit::read( const std::string& s, mValue& value ) +{ + return read_string( s, value ); +} + +void json_spirit::read_or_throw( const std::string& s, mValue& value ) +{ + read_string_or_throw( s, value ); +} + +bool json_spirit::read( std::istream& is, mValue& value ) +{ + return read_stream( is, value ); +} + +void json_spirit::read_or_throw( std::istream& is, mValue& value ) +{ + read_stream_or_throw( is, value ); +} + +bool json_spirit::read( std::string::const_iterator& begin, std::string::const_iterator end, mValue& value ) +{ + return read_range( begin, end, value ); +} + +void json_spirit::read_or_throw( std::string::const_iterator& begin, std::string::const_iterator end, mValue& value ) +{ + begin = read_range_or_throw( begin, end, value ); +} + +#ifndef BOOST_NO_STD_WSTRING + +bool json_spirit::read( const std::wstring& s, wmValue& value ) +{ + return read_string( s, value ); +} + +void json_spirit::read_or_throw( const std::wstring& s, wmValue& value ) +{ + read_string_or_throw( s, value ); +} + +bool json_spirit::read( std::wistream& is, wmValue& value ) +{ + return read_stream( is, value ); +} + +void json_spirit::read_or_throw( std::wistream& is, wmValue& value ) +{ + read_stream_or_throw( is, value ); +} + +bool json_spirit::read( std::wstring::const_iterator& begin, std::wstring::const_iterator end, wmValue& value ) +{ + return read_range( begin, end, value ); +} + +void json_spirit::read_or_throw( std::wstring::const_iterator& begin, std::wstring::const_iterator end, wmValue& value ) +{ + begin = read_range_or_throw( begin, end, value ); +} + +#endif diff --git a/src/json/json_spirit_reader.h b/src/json/json_spirit_reader.h new file mode 100644 index 0000000..96494a9 --- /dev/null +++ b/src/json/json_spirit_reader.h @@ -0,0 +1,62 @@ +#ifndef JSON_SPIRIT_READER +#define JSON_SPIRIT_READER + +// Copyright John W. Wilkinson 2007 - 2009. +// Distributed under the MIT License, see accompanying file LICENSE.txt + +// json spirit version 4.03 + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include "json_spirit_value.h" +#include "json_spirit_error_position.h" +#include + +namespace json_spirit +{ + // functions to reads a JSON values + + bool read( const std::string& s, Value& value ); + bool read( std::istream& is, Value& value ); + bool read( std::string::const_iterator& begin, std::string::const_iterator end, Value& value ); + + void read_or_throw( const std::string& s, Value& value ); + void read_or_throw( std::istream& is, Value& value ); + void read_or_throw( std::string::const_iterator& begin, std::string::const_iterator end, Value& value ); + +#ifndef BOOST_NO_STD_WSTRING + + bool read( const std::wstring& s, wValue& value ); + bool read( std::wistream& is, wValue& value ); + bool read( std::wstring::const_iterator& begin, std::wstring::const_iterator end, wValue& value ); + + void read_or_throw( const std::wstring& s, wValue& value ); + void read_or_throw( std::wistream& is, wValue& value ); + void read_or_throw( std::wstring::const_iterator& begin, std::wstring::const_iterator end, wValue& value ); + +#endif + + bool read( const std::string& s, mValue& value ); + bool read( std::istream& is, mValue& value ); + bool read( std::string::const_iterator& begin, std::string::const_iterator end, mValue& value ); + + void read_or_throw( const std::string& s, mValue& value ); + void read_or_throw( std::istream& is, mValue& value ); + void read_or_throw( std::string::const_iterator& begin, std::string::const_iterator end, mValue& value ); + +#ifndef BOOST_NO_STD_WSTRING + + bool read( const std::wstring& s, wmValue& value ); + bool read( std::wistream& is, wmValue& value ); + bool read( std::wstring::const_iterator& begin, std::wstring::const_iterator end, wmValue& value ); + + void read_or_throw( const std::wstring& s, wmValue& value ); + void read_or_throw( std::wistream& is, wmValue& value ); + void read_or_throw( std::wstring::const_iterator& begin, std::wstring::const_iterator end, wmValue& value ); + +#endif +} + +#endif diff --git a/src/json/json_spirit_reader_template.h b/src/json/json_spirit_reader_template.h new file mode 100644 index 0000000..4dec00e --- /dev/null +++ b/src/json/json_spirit_reader_template.h @@ -0,0 +1,612 @@ +#ifndef JSON_SPIRIT_READER_TEMPLATE +#define JSON_SPIRIT_READER_TEMPLATE + +// Copyright John W. Wilkinson 2007 - 2009. +// Distributed under the MIT License, see accompanying file LICENSE.txt + +// json spirit version 4.03 + +#include "json_spirit_value.h" +#include "json_spirit_error_position.h" + +//#define BOOST_SPIRIT_THREADSAFE // uncomment for multithreaded use, requires linking to boost.thread + +#include +#include +#include + +#if BOOST_VERSION >= 103800 + #include + #include + #include + #include + #include + #define spirit_namespace boost::spirit::classic +#else + #include + #include + #include + #include + #include + #define spirit_namespace boost::spirit +#endif + +namespace json_spirit +{ + const spirit_namespace::int_parser < boost::int64_t > int64_p = spirit_namespace::int_parser < boost::int64_t >(); + const spirit_namespace::uint_parser< boost::uint64_t > uint64_p = spirit_namespace::uint_parser< boost::uint64_t >(); + + template< class Iter_type > + bool is_eq( Iter_type first, Iter_type last, const char* c_str ) + { + for( Iter_type i = first; i != last; ++i, ++c_str ) + { + if( *c_str == 0 ) return false; + + if( *i != *c_str ) return false; + } + + return true; + } + + template< class Char_type > + Char_type hex_to_num( const Char_type c ) + { + if( ( c >= '0' ) && ( c <= '9' ) ) return c - '0'; + if( ( c >= 'a' ) && ( c <= 'f' ) ) return c - 'a' + 10; + if( ( c >= 'A' ) && ( c <= 'F' ) ) return c - 'A' + 10; + return 0; + } + + template< class Char_type, class Iter_type > + Char_type hex_str_to_char( Iter_type& begin ) + { + const Char_type c1( *( ++begin ) ); + const Char_type c2( *( ++begin ) ); + + return ( hex_to_num( c1 ) << 4 ) + hex_to_num( c2 ); + } + + template< class Char_type, class Iter_type > + Char_type unicode_str_to_char( Iter_type& begin ) + { + const Char_type c1( *( ++begin ) ); + const Char_type c2( *( ++begin ) ); + const Char_type c3( *( ++begin ) ); + const Char_type c4( *( ++begin ) ); + + return ( hex_to_num( c1 ) << 12 ) + + ( hex_to_num( c2 ) << 8 ) + + ( hex_to_num( c3 ) << 4 ) + + hex_to_num( c4 ); + } + + template< class String_type > + void append_esc_char_and_incr_iter( String_type& s, + typename String_type::const_iterator& begin, + typename String_type::const_iterator end ) + { + typedef typename String_type::value_type Char_type; + + const Char_type c2( *begin ); + + switch( c2 ) + { + case 't': s += '\t'; break; + case 'b': s += '\b'; break; + case 'f': s += '\f'; break; + case 'n': s += '\n'; break; + case 'r': s += '\r'; break; + case '\\': s += '\\'; break; + case '/': s += '/'; break; + case '"': s += '"'; break; + case 'x': + { + if( end - begin >= 3 ) // expecting "xHH..." + { + s += hex_str_to_char< Char_type >( begin ); + } + break; + } + case 'u': + { + if( end - begin >= 5 ) // expecting "uHHHH..." + { + s += unicode_str_to_char< Char_type >( begin ); + } + break; + } + } + } + + template< class String_type > + String_type substitute_esc_chars( typename String_type::const_iterator begin, + typename String_type::const_iterator end ) + { + typedef typename String_type::const_iterator Iter_type; + + if( end - begin < 2 ) return String_type( begin, end ); + + String_type result; + + result.reserve( end - begin ); + + const Iter_type end_minus_1( end - 1 ); + + Iter_type substr_start = begin; + Iter_type i = begin; + + for( ; i < end_minus_1; ++i ) + { + if( *i == '\\' ) + { + result.append( substr_start, i ); + + ++i; // skip the '\' + + append_esc_char_and_incr_iter( result, i, end ); + + substr_start = i + 1; + } + } + + result.append( substr_start, end ); + + return result; + } + + template< class String_type > + String_type get_str_( typename String_type::const_iterator begin, + typename String_type::const_iterator end ) + { + assert( end - begin >= 2 ); + + typedef typename String_type::const_iterator Iter_type; + + Iter_type str_without_quotes( ++begin ); + Iter_type end_without_quotes( --end ); + + return substitute_esc_chars< String_type >( str_without_quotes, end_without_quotes ); + } + + inline std::string get_str( std::string::const_iterator begin, std::string::const_iterator end ) + { + return get_str_< std::string >( begin, end ); + } + + inline std::wstring get_str( std::wstring::const_iterator begin, std::wstring::const_iterator end ) + { + return get_str_< std::wstring >( begin, end ); + } + + template< class String_type, class Iter_type > + String_type get_str( Iter_type begin, Iter_type end ) + { + const String_type tmp( begin, end ); // convert multipass iterators to string iterators + + return get_str( tmp.begin(), tmp.end() ); + } + + // this class's methods get called by the spirit parse resulting + // in the creation of a JSON object or array + // + // NB Iter_type could be a std::string iterator, wstring iterator, a position iterator or a multipass iterator + // + template< class Value_type, class Iter_type > + class Semantic_actions + { + public: + + typedef typename Value_type::Config_type Config_type; + typedef typename Config_type::String_type String_type; + typedef typename Config_type::Object_type Object_type; + typedef typename Config_type::Array_type Array_type; + typedef typename String_type::value_type Char_type; + + Semantic_actions( Value_type& value ) + : value_( value ) + , current_p_( 0 ) + { + } + + void begin_obj( Char_type c ) + { + assert( c == '{' ); + + begin_compound< Object_type >(); + } + + void end_obj( Char_type c ) + { + assert( c == '}' ); + + end_compound(); + } + + void begin_array( Char_type c ) + { + assert( c == '[' ); + + begin_compound< Array_type >(); + } + + void end_array( Char_type c ) + { + assert( c == ']' ); + + end_compound(); + } + + void new_name( Iter_type begin, Iter_type end ) + { + assert( current_p_->type() == obj_type ); + + name_ = get_str< String_type >( begin, end ); + } + + void new_str( Iter_type begin, Iter_type end ) + { + add_to_current( get_str< String_type >( begin, end ) ); + } + + void new_true( Iter_type begin, Iter_type end ) + { + assert( is_eq( begin, end, "true" ) ); + + add_to_current( true ); + } + + void new_false( Iter_type begin, Iter_type end ) + { + assert( is_eq( begin, end, "false" ) ); + + add_to_current( false ); + } + + void new_null( Iter_type begin, Iter_type end ) + { + assert( is_eq( begin, end, "null" ) ); + + add_to_current( Value_type() ); + } + + void new_int( boost::int64_t i ) + { + add_to_current( i ); + } + + void new_uint64( boost::uint64_t ui ) + { + add_to_current( ui ); + } + + void new_real( double d ) + { + add_to_current( d ); + } + + private: + + Semantic_actions& operator=( const Semantic_actions& ); + // to prevent "assignment operator could not be generated" warning + + Value_type* add_first( const Value_type& value ) + { + assert( current_p_ == 0 ); + + value_ = value; + current_p_ = &value_; + return current_p_; + } + + template< class Array_or_obj > + void begin_compound() + { + if( current_p_ == 0 ) + { + add_first( Array_or_obj() ); + } + else + { + stack_.push_back( current_p_ ); + + Array_or_obj new_array_or_obj; // avoid copy by building new array or object in place + + current_p_ = add_to_current( new_array_or_obj ); + } + } + + void end_compound() + { + if( current_p_ != &value_ ) + { + current_p_ = stack_.back(); + + stack_.pop_back(); + } + } + + Value_type* add_to_current( const Value_type& value ) + { + if( current_p_ == 0 ) + { + return add_first( value ); + } + else if( current_p_->type() == array_type ) + { + current_p_->get_array().push_back( value ); + + return ¤t_p_->get_array().back(); + } + + assert( current_p_->type() == obj_type ); + + return &Config_type::add( current_p_->get_obj(), name_, value ); + } + + Value_type& value_; // this is the object or array that is being created + Value_type* current_p_; // the child object or array that is currently being constructed + + std::vector< Value_type* > stack_; // previous child objects and arrays + + String_type name_; // of current name/value pair + }; + + template< typename Iter_type > + void throw_error( spirit_namespace::position_iterator< Iter_type > i, const std::string& reason ) + { + throw Error_position( i.get_position().line, i.get_position().column, reason ); + } + + template< typename Iter_type > + void throw_error( Iter_type i, const std::string& reason ) + { + throw reason; + } + + // the spirit grammer + // + template< class Value_type, class Iter_type > + class Json_grammer : public spirit_namespace::grammar< Json_grammer< Value_type, Iter_type > > + { + public: + + typedef Semantic_actions< Value_type, Iter_type > Semantic_actions_t; + + Json_grammer( Semantic_actions_t& semantic_actions ) + : actions_( semantic_actions ) + { + } + + static void throw_not_value( Iter_type begin, Iter_type end ) + { + throw_error( begin, "not a value" ); + } + + static void throw_not_array( Iter_type begin, Iter_type end ) + { + throw_error( begin, "not an array" ); + } + + static void throw_not_object( Iter_type begin, Iter_type end ) + { + throw_error( begin, "not an object" ); + } + + static void throw_not_pair( Iter_type begin, Iter_type end ) + { + throw_error( begin, "not a pair" ); + } + + static void throw_not_colon( Iter_type begin, Iter_type end ) + { + throw_error( begin, "no colon in pair" ); + } + + static void throw_not_string( Iter_type begin, Iter_type end ) + { + throw_error( begin, "not a string" ); + } + + template< typename ScannerT > + class definition + { + public: + + definition( const Json_grammer& self ) + { + using namespace spirit_namespace; + + typedef typename Value_type::String_type::value_type Char_type; + + // first we convert the semantic action class methods to functors with the + // parameter signature expected by spirit + + typedef boost::function< void( Char_type ) > Char_action; + typedef boost::function< void( Iter_type, Iter_type ) > Str_action; + typedef boost::function< void( double ) > Real_action; + typedef boost::function< void( boost::int64_t ) > Int_action; + typedef boost::function< void( boost::uint64_t ) > Uint64_action; + + Char_action begin_obj ( boost::bind( &Semantic_actions_t::begin_obj, &self.actions_, _1 ) ); + Char_action end_obj ( boost::bind( &Semantic_actions_t::end_obj, &self.actions_, _1 ) ); + Char_action begin_array( boost::bind( &Semantic_actions_t::begin_array, &self.actions_, _1 ) ); + Char_action end_array ( boost::bind( &Semantic_actions_t::end_array, &self.actions_, _1 ) ); + Str_action new_name ( boost::bind( &Semantic_actions_t::new_name, &self.actions_, _1, _2 ) ); + Str_action new_str ( boost::bind( &Semantic_actions_t::new_str, &self.actions_, _1, _2 ) ); + Str_action new_true ( boost::bind( &Semantic_actions_t::new_true, &self.actions_, _1, _2 ) ); + Str_action new_false ( boost::bind( &Semantic_actions_t::new_false, &self.actions_, _1, _2 ) ); + Str_action new_null ( boost::bind( &Semantic_actions_t::new_null, &self.actions_, _1, _2 ) ); + Real_action new_real ( boost::bind( &Semantic_actions_t::new_real, &self.actions_, _1 ) ); + Int_action new_int ( boost::bind( &Semantic_actions_t::new_int, &self.actions_, _1 ) ); + Uint64_action new_uint64 ( boost::bind( &Semantic_actions_t::new_uint64, &self.actions_, _1 ) ); + + // actual grammer + + json_ + = value_ | eps_p[ &throw_not_value ] + ; + + value_ + = string_[ new_str ] + | number_ + | object_ + | array_ + | str_p( "true" ) [ new_true ] + | str_p( "false" )[ new_false ] + | str_p( "null" ) [ new_null ] + ; + + object_ + = ch_p('{')[ begin_obj ] + >> !members_ + >> ( ch_p('}')[ end_obj ] | eps_p[ &throw_not_object ] ) + ; + + members_ + = pair_ >> *( ',' >> pair_ ) + ; + + pair_ + = string_[ new_name ] + >> ( ':' | eps_p[ &throw_not_colon ] ) + >> ( value_ | eps_p[ &throw_not_value ] ) + ; + + array_ + = ch_p('[')[ begin_array ] + >> !elements_ + >> ( ch_p(']')[ end_array ] | eps_p[ &throw_not_array ] ) + ; + + elements_ + = value_ >> *( ',' >> value_ ) + ; + + string_ + = lexeme_d // this causes white space inside a string to be retained + [ + confix_p + ( + '"', + *lex_escape_ch_p, + '"' + ) + ] + ; + + number_ + = strict_real_p[ new_real ] + | int64_p [ new_int ] + | uint64_p [ new_uint64 ] + ; + } + + spirit_namespace::rule< ScannerT > json_, object_, members_, pair_, array_, elements_, value_, string_, number_; + + const spirit_namespace::rule< ScannerT >& start() const { return json_; } + }; + + private: + + Json_grammer& operator=( const Json_grammer& ); // to prevent "assignment operator could not be generated" warning + + Semantic_actions_t& actions_; + }; + + template< class Iter_type, class Value_type > + Iter_type read_range_or_throw( Iter_type begin, Iter_type end, Value_type& value ) + { + Semantic_actions< Value_type, Iter_type > semantic_actions( value ); + + const spirit_namespace::parse_info< Iter_type > info = + spirit_namespace::parse( begin, end, + Json_grammer< Value_type, Iter_type >( semantic_actions ), + spirit_namespace::space_p ); + + if( !info.hit ) + { + assert( false ); // in theory exception should already have been thrown + throw_error( info.stop, "error" ); + } + + return info.stop; + } + + template< class Iter_type, class Value_type > + void add_posn_iter_and_read_range_or_throw( Iter_type begin, Iter_type end, Value_type& value ) + { + typedef spirit_namespace::position_iterator< Iter_type > Posn_iter_t; + + const Posn_iter_t posn_begin( begin, end ); + const Posn_iter_t posn_end( end, end ); + + read_range_or_throw( posn_begin, posn_end, value ); + } + + template< class Iter_type, class Value_type > + bool read_range( Iter_type& begin, Iter_type end, Value_type& value ) + { + try + { + begin = read_range_or_throw( begin, end, value ); + + return true; + } + catch( ... ) + { + return false; + } + } + + template< class String_type, class Value_type > + void read_string_or_throw( const String_type& s, Value_type& value ) + { + add_posn_iter_and_read_range_or_throw( s.begin(), s.end(), value ); + } + + template< class String_type, class Value_type > + bool read_string( const String_type& s, Value_type& value ) + { + typename String_type::const_iterator begin = s.begin(); + + return read_range( begin, s.end(), value ); + } + + template< class Istream_type > + struct Multi_pass_iters + { + typedef typename Istream_type::char_type Char_type; + typedef std::istream_iterator< Char_type, Char_type > istream_iter; + typedef spirit_namespace::multi_pass< istream_iter > Mp_iter; + + Multi_pass_iters( Istream_type& is ) + { + is.unsetf( std::ios::skipws ); + + begin_ = spirit_namespace::make_multi_pass( istream_iter( is ) ); + end_ = spirit_namespace::make_multi_pass( istream_iter() ); + } + + Mp_iter begin_; + Mp_iter end_; + }; + + template< class Istream_type, class Value_type > + bool read_stream( Istream_type& is, Value_type& value ) + { + Multi_pass_iters< Istream_type > mp_iters( is ); + + return read_range( mp_iters.begin_, mp_iters.end_, value ); + } + + template< class Istream_type, class Value_type > + void read_stream_or_throw( Istream_type& is, Value_type& value ) + { + const Multi_pass_iters< Istream_type > mp_iters( is ); + + add_posn_iter_and_read_range_or_throw( mp_iters.begin_, mp_iters.end_, value ); + } +} + +#endif diff --git a/src/json/json_spirit_stream_reader.h b/src/json/json_spirit_stream_reader.h new file mode 100644 index 0000000..7e59c9a --- /dev/null +++ b/src/json/json_spirit_stream_reader.h @@ -0,0 +1,70 @@ +#ifndef JSON_SPIRIT_READ_STREAM +#define JSON_SPIRIT_READ_STREAM + +// Copyright John W. Wilkinson 2007 - 2009. +// Distributed under the MIT License, see accompanying file LICENSE.txt + +// json spirit version 4.03 + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include "json_spirit_reader_template.h" + +namespace json_spirit +{ + // these classes allows you to read multiple top level contiguous values from a stream, + // the normal stream read functions have a bug that prevent multiple top level values + // from being read unless they are separated by spaces + + template< class Istream_type, class Value_type > + class Stream_reader + { + public: + + Stream_reader( Istream_type& is ) + : iters_( is ) + { + } + + bool read_next( Value_type& value ) + { + return read_range( iters_.begin_, iters_.end_, value ); + } + + private: + + typedef Multi_pass_iters< Istream_type > Mp_iters; + + Mp_iters iters_; + }; + + template< class Istream_type, class Value_type > + class Stream_reader_thrower + { + public: + + Stream_reader_thrower( Istream_type& is ) + : iters_( is ) + , posn_begin_( iters_.begin_, iters_.end_ ) + , posn_end_( iters_.end_, iters_.end_ ) + { + } + + void read_next( Value_type& value ) + { + posn_begin_ = read_range_or_throw( posn_begin_, posn_end_, value ); + } + + private: + + typedef Multi_pass_iters< Istream_type > Mp_iters; + typedef spirit_namespace::position_iterator< typename Mp_iters::Mp_iter > Posn_iter_t; + + Mp_iters iters_; + Posn_iter_t posn_begin_, posn_end_; + }; +} + +#endif diff --git a/src/json/json_spirit_utils.h b/src/json/json_spirit_utils.h new file mode 100644 index 0000000..553e3b9 --- /dev/null +++ b/src/json/json_spirit_utils.h @@ -0,0 +1,61 @@ +#ifndef JSON_SPIRIT_UTILS +#define JSON_SPIRIT_UTILS + +// Copyright John W. Wilkinson 2007 - 2009. +// Distributed under the MIT License, see accompanying file LICENSE.txt + +// json spirit version 4.03 + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include "json_spirit_value.h" +#include + +namespace json_spirit +{ + template< class Obj_t, class Map_t > + void obj_to_map( const Obj_t& obj, Map_t& mp_obj ) + { + mp_obj.clear(); + + for( typename Obj_t::const_iterator i = obj.begin(); i != obj.end(); ++i ) + { + mp_obj[ i->name_ ] = i->value_; + } + } + + template< class Obj_t, class Map_t > + void map_to_obj( const Map_t& mp_obj, Obj_t& obj ) + { + obj.clear(); + + for( typename Map_t::const_iterator i = mp_obj.begin(); i != mp_obj.end(); ++i ) + { + obj.push_back( typename Obj_t::value_type( i->first, i->second ) ); + } + } + + typedef std::map< std::string, Value > Mapped_obj; + +#ifndef BOOST_NO_STD_WSTRING + typedef std::map< std::wstring, wValue > wMapped_obj; +#endif + + template< class Object_type, class String_type > + const typename Object_type::value_type::Value_type& find_value( const Object_type& obj, const String_type& name ) + { + for( typename Object_type::const_iterator i = obj.begin(); i != obj.end(); ++i ) + { + if( i->name_ == name ) + { + return i->value_; + } + } + + return Object_type::value_type::Value_type::null; + } +} + +#endif diff --git a/src/json/json_spirit_value.cpp b/src/json/json_spirit_value.cpp new file mode 100644 index 0000000..44d2f06 --- /dev/null +++ b/src/json/json_spirit_value.cpp @@ -0,0 +1,8 @@ +/* Copyright (c) 2007 John W Wilkinson + + This source code can be used for any purpose as long as + this comment is retained. */ + +// json spirit version 2.00 + +#include "json_spirit_value.h" diff --git a/src/json/json_spirit_value.h b/src/json/json_spirit_value.h new file mode 100644 index 0000000..7e83a2a --- /dev/null +++ b/src/json/json_spirit_value.h @@ -0,0 +1,534 @@ +#ifndef JSON_SPIRIT_VALUE +#define JSON_SPIRIT_VALUE + +// Copyright John W. Wilkinson 2007 - 2009. +// Distributed under the MIT License, see accompanying file LICENSE.txt + +// json spirit version 4.03 + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace json_spirit +{ + enum Value_type{ obj_type, array_type, str_type, bool_type, int_type, real_type, null_type }; + static const char* Value_type_name[]={"obj", "array", "str", "bool", "int", "real", "null"}; + + template< class Config > // Config determines whether the value uses std::string or std::wstring and + // whether JSON Objects are represented as vectors or maps + class Value_impl + { + public: + + typedef Config Config_type; + typedef typename Config::String_type String_type; + typedef typename Config::Object_type Object; + typedef typename Config::Array_type Array; + typedef typename String_type::const_pointer Const_str_ptr; // eg const char* + + Value_impl(); // creates null value + Value_impl( Const_str_ptr value ); + Value_impl( const String_type& value ); + Value_impl( const Object& value ); + Value_impl( const Array& value ); + Value_impl( bool value ); + Value_impl( int value ); + Value_impl( boost::int64_t value ); + Value_impl( boost::uint64_t value ); + Value_impl( double value ); + + Value_impl( const Value_impl& other ); + + bool operator==( const Value_impl& lhs ) const; + + Value_impl& operator=( const Value_impl& lhs ); + + Value_type type() const; + + bool is_uint64() const; + bool is_null() const; + + const String_type& get_str() const; + const Object& get_obj() const; + const Array& get_array() const; + bool get_bool() const; + int get_int() const; + boost::int64_t get_int64() const; + boost::uint64_t get_uint64() const; + double get_real() const; + + Object& get_obj(); + Array& get_array(); + + template< typename T > T get_value() const; // example usage: int i = value.get_value< int >(); + // or double d = value.get_value< double >(); + + static const Value_impl null; + + private: + + void check_type( const Value_type vtype ) const; + + typedef boost::variant< String_type, + boost::recursive_wrapper< Object >, boost::recursive_wrapper< Array >, + bool, boost::int64_t, double > Variant; + + Value_type type_; + Variant v_; + bool is_uint64_; + }; + + // vector objects + + template< class Config > + struct Pair_impl + { + typedef typename Config::String_type String_type; + typedef typename Config::Value_type Value_type; + + Pair_impl( const String_type& name, const Value_type& value ); + + bool operator==( const Pair_impl& lhs ) const; + + String_type name_; + Value_type value_; + }; + + template< class String > + struct Config_vector + { + typedef String String_type; + typedef Value_impl< Config_vector > Value_type; + typedef Pair_impl < Config_vector > Pair_type; + typedef std::vector< Value_type > Array_type; + typedef std::vector< Pair_type > Object_type; + + static Value_type& add( Object_type& obj, const String_type& name, const Value_type& value ) + { + obj.push_back( Pair_type( name , value ) ); + + return obj.back().value_; + } + + static String_type get_name( const Pair_type& pair ) + { + return pair.name_; + } + + static Value_type get_value( const Pair_type& pair ) + { + return pair.value_; + } + }; + + // typedefs for ASCII + + typedef Config_vector< std::string > Config; + + typedef Config::Value_type Value; + typedef Config::Pair_type Pair; + typedef Config::Object_type Object; + typedef Config::Array_type Array; + + // typedefs for Unicode + +#ifndef BOOST_NO_STD_WSTRING + + typedef Config_vector< std::wstring > wConfig; + + typedef wConfig::Value_type wValue; + typedef wConfig::Pair_type wPair; + typedef wConfig::Object_type wObject; + typedef wConfig::Array_type wArray; +#endif + + // map objects + + template< class String > + struct Config_map + { + typedef String String_type; + typedef Value_impl< Config_map > Value_type; + typedef std::vector< Value_type > Array_type; + typedef std::map< String_type, Value_type > Object_type; + typedef typename Object_type::value_type Pair_type; + + static Value_type& add( Object_type& obj, const String_type& name, const Value_type& value ) + { + return obj[ name ] = value; + } + + static String_type get_name( const Pair_type& pair ) + { + return pair.first; + } + + static Value_type get_value( const Pair_type& pair ) + { + return pair.second; + } + }; + + // typedefs for ASCII + + typedef Config_map< std::string > mConfig; + + typedef mConfig::Value_type mValue; + typedef mConfig::Object_type mObject; + typedef mConfig::Array_type mArray; + + // typedefs for Unicode + +#ifndef BOOST_NO_STD_WSTRING + + typedef Config_map< std::wstring > wmConfig; + + typedef wmConfig::Value_type wmValue; + typedef wmConfig::Object_type wmObject; + typedef wmConfig::Array_type wmArray; + +#endif + + /////////////////////////////////////////////////////////////////////////////////////////////// + // + // implementation + + template< class Config > + const Value_impl< Config > Value_impl< Config >::null; + + template< class Config > + Value_impl< Config >::Value_impl() + : type_( null_type ) + , is_uint64_( false ) + { + } + + template< class Config > + Value_impl< Config >::Value_impl( const Const_str_ptr value ) + : type_( str_type ) + , v_( String_type( value ) ) + , is_uint64_( false ) + { + } + + template< class Config > + Value_impl< Config >::Value_impl( const String_type& value ) + : type_( str_type ) + , v_( value ) + , is_uint64_( false ) + { + } + + template< class Config > + Value_impl< Config >::Value_impl( const Object& value ) + : type_( obj_type ) + , v_( value ) + , is_uint64_( false ) + { + } + + template< class Config > + Value_impl< Config >::Value_impl( const Array& value ) + : type_( array_type ) + , v_( value ) + , is_uint64_( false ) + { + } + + template< class Config > + Value_impl< Config >::Value_impl( bool value ) + : type_( bool_type ) + , v_( value ) + , is_uint64_( false ) + { + } + + template< class Config > + Value_impl< Config >::Value_impl( int value ) + : type_( int_type ) + , v_( static_cast< boost::int64_t >( value ) ) + , is_uint64_( false ) + { + } + + template< class Config > + Value_impl< Config >::Value_impl( boost::int64_t value ) + : type_( int_type ) + , v_( value ) + , is_uint64_( false ) + { + } + + template< class Config > + Value_impl< Config >::Value_impl( boost::uint64_t value ) + : type_( int_type ) + , v_( static_cast< boost::int64_t >( value ) ) + , is_uint64_( true ) + { + } + + template< class Config > + Value_impl< Config >::Value_impl( double value ) + : type_( real_type ) + , v_( value ) + , is_uint64_( false ) + { + } + + template< class Config > + Value_impl< Config >::Value_impl( const Value_impl< Config >& other ) + : type_( other.type() ) + , v_( other.v_ ) + , is_uint64_( other.is_uint64_ ) + { + } + + template< class Config > + Value_impl< Config >& Value_impl< Config >::operator=( const Value_impl& lhs ) + { + Value_impl tmp( lhs ); + + std::swap( type_, tmp.type_ ); + std::swap( v_, tmp.v_ ); + std::swap( is_uint64_, tmp.is_uint64_ ); + + return *this; + } + + template< class Config > + bool Value_impl< Config >::operator==( const Value_impl& lhs ) const + { + if( this == &lhs ) return true; + + if( type() != lhs.type() ) return false; + + return v_ == lhs.v_; + } + + template< class Config > + Value_type Value_impl< Config >::type() const + { + return type_; + } + + template< class Config > + bool Value_impl< Config >::is_uint64() const + { + return is_uint64_; + } + + template< class Config > + bool Value_impl< Config >::is_null() const + { + return type() == null_type; + } + + template< class Config > + void Value_impl< Config >::check_type( const Value_type vtype ) const + { + if( type() != vtype ) + { + std::ostringstream os; + + ///// Bitcoin: Tell the types by name instead of by number + os << "value is type " << Value_type_name[type()] << ", expected " << Value_type_name[vtype]; + + throw std::runtime_error( os.str() ); + } + } + + template< class Config > + const typename Config::String_type& Value_impl< Config >::get_str() const + { + check_type( str_type ); + + return *boost::get< String_type >( &v_ ); + } + + template< class Config > + const typename Value_impl< Config >::Object& Value_impl< Config >::get_obj() const + { + check_type( obj_type ); + + return *boost::get< Object >( &v_ ); + } + + template< class Config > + const typename Value_impl< Config >::Array& Value_impl< Config >::get_array() const + { + check_type( array_type ); + + return *boost::get< Array >( &v_ ); + } + + template< class Config > + bool Value_impl< Config >::get_bool() const + { + check_type( bool_type ); + + return boost::get< bool >( v_ ); + } + + template< class Config > + int Value_impl< Config >::get_int() const + { + check_type( int_type ); + + return static_cast< int >( get_int64() ); + } + + template< class Config > + boost::int64_t Value_impl< Config >::get_int64() const + { + check_type( int_type ); + + return boost::get< boost::int64_t >( v_ ); + } + + template< class Config > + boost::uint64_t Value_impl< Config >::get_uint64() const + { + check_type( int_type ); + + return static_cast< boost::uint64_t >( get_int64() ); + } + + template< class Config > + double Value_impl< Config >::get_real() const + { + if( type() == int_type ) + { + return is_uint64() ? static_cast< double >( get_uint64() ) + : static_cast< double >( get_int64() ); + } + + check_type( real_type ); + + return boost::get< double >( v_ ); + } + + template< class Config > + typename Value_impl< Config >::Object& Value_impl< Config >::get_obj() + { + check_type( obj_type ); + + return *boost::get< Object >( &v_ ); + } + + template< class Config > + typename Value_impl< Config >::Array& Value_impl< Config >::get_array() + { + check_type( array_type ); + + return *boost::get< Array >( &v_ ); + } + + template< class Config > + Pair_impl< Config >::Pair_impl( const String_type& name, const Value_type& value ) + : name_( name ) + , value_( value ) + { + } + + template< class Config > + bool Pair_impl< Config >::operator==( const Pair_impl< Config >& lhs ) const + { + if( this == &lhs ) return true; + + return ( name_ == lhs.name_ ) && ( value_ == lhs.value_ ); + } + + // converts a C string, ie. 8 bit char array, to a string object + // + template < class String_type > + String_type to_str( const char* c_str ) + { + String_type result; + + for( const char* p = c_str; *p != 0; ++p ) + { + result += *p; + } + + return result; + } + + // + + namespace internal_ + { + template< typename T > + struct Type_to_type + { + }; + + template< class Value > + int get_value( const Value& value, Type_to_type< int > ) + { + return value.get_int(); + } + + template< class Value > + boost::int64_t get_value( const Value& value, Type_to_type< boost::int64_t > ) + { + return value.get_int64(); + } + + template< class Value > + boost::uint64_t get_value( const Value& value, Type_to_type< boost::uint64_t > ) + { + return value.get_uint64(); + } + + template< class Value > + double get_value( const Value& value, Type_to_type< double > ) + { + return value.get_real(); + } + + template< class Value > + typename Value::String_type get_value( const Value& value, Type_to_type< typename Value::String_type > ) + { + return value.get_str(); + } + + template< class Value > + typename Value::Array get_value( const Value& value, Type_to_type< typename Value::Array > ) + { + return value.get_array(); + } + + template< class Value > + typename Value::Object get_value( const Value& value, Type_to_type< typename Value::Object > ) + { + return value.get_obj(); + } + + template< class Value > + bool get_value( const Value& value, Type_to_type< bool > ) + { + return value.get_bool(); + } + } + + template< class Config > + template< typename T > + T Value_impl< Config >::get_value() const + { + return internal_::get_value( *this, internal_::Type_to_type< T >() ); + } +} + +#endif diff --git a/src/json/json_spirit_writer.cpp b/src/json/json_spirit_writer.cpp new file mode 100644 index 0000000..d24a632 --- /dev/null +++ b/src/json/json_spirit_writer.cpp @@ -0,0 +1,95 @@ +// Copyright John W. Wilkinson 2007 - 2009. +// Distributed under the MIT License, see accompanying file LICENSE.txt + +// json spirit version 4.03 + +#include "json_spirit_writer.h" +#include "json_spirit_writer_template.h" + +void json_spirit::write( const Value& value, std::ostream& os ) +{ + write_stream( value, os, false ); +} + +void json_spirit::write_formatted( const Value& value, std::ostream& os ) +{ + write_stream( value, os, true ); +} + +std::string json_spirit::write( const Value& value ) +{ + return write_string( value, false ); +} + +std::string json_spirit::write_formatted( const Value& value ) +{ + return write_string( value, true ); +} + +#ifndef BOOST_NO_STD_WSTRING + +void json_spirit::write( const wValue& value, std::wostream& os ) +{ + write_stream( value, os, false ); +} + +void json_spirit::write_formatted( const wValue& value, std::wostream& os ) +{ + write_stream( value, os, true ); +} + +std::wstring json_spirit::write( const wValue& value ) +{ + return write_string( value, false ); +} + +std::wstring json_spirit::write_formatted( const wValue& value ) +{ + return write_string( value, true ); +} + +#endif + +void json_spirit::write( const mValue& value, std::ostream& os ) +{ + write_stream( value, os, false ); +} + +void json_spirit::write_formatted( const mValue& value, std::ostream& os ) +{ + write_stream( value, os, true ); +} + +std::string json_spirit::write( const mValue& value ) +{ + return write_string( value, false ); +} + +std::string json_spirit::write_formatted( const mValue& value ) +{ + return write_string( value, true ); +} + +#ifndef BOOST_NO_STD_WSTRING + +void json_spirit::write( const wmValue& value, std::wostream& os ) +{ + write_stream( value, os, false ); +} + +void json_spirit::write_formatted( const wmValue& value, std::wostream& os ) +{ + write_stream( value, os, true ); +} + +std::wstring json_spirit::write( const wmValue& value ) +{ + return write_string( value, false ); +} + +std::wstring json_spirit::write_formatted( const wmValue& value ) +{ + return write_string( value, true ); +} + +#endif diff --git a/src/json/json_spirit_writer.h b/src/json/json_spirit_writer.h new file mode 100644 index 0000000..52e1406 --- /dev/null +++ b/src/json/json_spirit_writer.h @@ -0,0 +1,50 @@ +#ifndef JSON_SPIRIT_WRITER +#define JSON_SPIRIT_WRITER + +// Copyright John W. Wilkinson 2007 - 2009. +// Distributed under the MIT License, see accompanying file LICENSE.txt + +// json spirit version 4.03 + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include "json_spirit_value.h" +#include + +namespace json_spirit +{ + // functions to convert JSON Values to text, + // the "formatted" versions add whitespace to format the output nicely + + void write ( const Value& value, std::ostream& os ); + void write_formatted( const Value& value, std::ostream& os ); + std::string write ( const Value& value ); + std::string write_formatted( const Value& value ); + +#ifndef BOOST_NO_STD_WSTRING + + void write ( const wValue& value, std::wostream& os ); + void write_formatted( const wValue& value, std::wostream& os ); + std::wstring write ( const wValue& value ); + std::wstring write_formatted( const wValue& value ); + +#endif + + void write ( const mValue& value, std::ostream& os ); + void write_formatted( const mValue& value, std::ostream& os ); + std::string write ( const mValue& value ); + std::string write_formatted( const mValue& value ); + +#ifndef BOOST_NO_STD_WSTRING + + void write ( const wmValue& value, std::wostream& os ); + void write_formatted( const wmValue& value, std::wostream& os ); + std::wstring write ( const wmValue& value ); + std::wstring write_formatted( const wmValue& value ); + +#endif +} + +#endif diff --git a/src/json/json_spirit_writer_template.h b/src/json/json_spirit_writer_template.h new file mode 100644 index 0000000..28c49dd --- /dev/null +++ b/src/json/json_spirit_writer_template.h @@ -0,0 +1,248 @@ +#ifndef JSON_SPIRIT_WRITER_TEMPLATE +#define JSON_SPIRIT_WRITER_TEMPLATE + +// Copyright John W. Wilkinson 2007 - 2009. +// Distributed under the MIT License, see accompanying file LICENSE.txt + +// json spirit version 4.03 + +#include "json_spirit_value.h" + +#include +#include +#include + +namespace json_spirit +{ + inline char to_hex_char( unsigned int c ) + { + assert( c <= 0xF ); + + const char ch = static_cast< char >( c ); + + if( ch < 10 ) return '0' + ch; + + return 'A' - 10 + ch; + } + + template< class String_type > + String_type non_printable_to_string( unsigned int c ) + { + typedef typename String_type::value_type Char_type; + + String_type result( 6, '\\' ); + + result[1] = 'u'; + + result[ 5 ] = to_hex_char( c & 0x000F ); c >>= 4; + result[ 4 ] = to_hex_char( c & 0x000F ); c >>= 4; + result[ 3 ] = to_hex_char( c & 0x000F ); c >>= 4; + result[ 2 ] = to_hex_char( c & 0x000F ); + + return result; + } + + template< typename Char_type, class String_type > + bool add_esc_char( Char_type c, String_type& s ) + { + switch( c ) + { + case '"': s += to_str< String_type >( "\\\"" ); return true; + case '\\': s += to_str< String_type >( "\\\\" ); return true; + case '\b': s += to_str< String_type >( "\\b" ); return true; + case '\f': s += to_str< String_type >( "\\f" ); return true; + case '\n': s += to_str< String_type >( "\\n" ); return true; + case '\r': s += to_str< String_type >( "\\r" ); return true; + case '\t': s += to_str< String_type >( "\\t" ); return true; + } + + return false; + } + + template< class String_type > + String_type add_esc_chars( const String_type& s ) + { + typedef typename String_type::const_iterator Iter_type; + typedef typename String_type::value_type Char_type; + + String_type result; + + const Iter_type end( s.end() ); + + for( Iter_type i = s.begin(); i != end; ++i ) + { + const Char_type c( *i ); + + if( add_esc_char( c, result ) ) continue; + + const wint_t unsigned_c( ( c >= 0 ) ? c : 256 + c ); + + if( iswprint( unsigned_c ) ) + { + result += c; + } + else + { + result += non_printable_to_string< String_type >( unsigned_c ); + } + } + + return result; + } + + // this class generates the JSON text, + // it keeps track of the indentation level etc. + // + template< class Value_type, class Ostream_type > + class Generator + { + typedef typename Value_type::Config_type Config_type; + typedef typename Config_type::String_type String_type; + typedef typename Config_type::Object_type Object_type; + typedef typename Config_type::Array_type Array_type; + typedef typename String_type::value_type Char_type; + typedef typename Object_type::value_type Obj_member_type; + + public: + + Generator( const Value_type& value, Ostream_type& os, bool pretty ) + : os_( os ) + , indentation_level_( 0 ) + , pretty_( pretty ) + { + output( value ); + } + + private: + + void output( const Value_type& value ) + { + switch( value.type() ) + { + case obj_type: output( value.get_obj() ); break; + case array_type: output( value.get_array() ); break; + case str_type: output( value.get_str() ); break; + case bool_type: output( value.get_bool() ); break; + case int_type: output_int( value ); break; + + /// Bitcoin: Added std::fixed and changed precision from 16 to 8 + case real_type: os_ << std::showpoint << std::fixed << std::setprecision(8) + << value.get_real(); break; + + case null_type: os_ << "null"; break; + default: assert( false ); + } + } + + void output( const Object_type& obj ) + { + output_array_or_obj( obj, '{', '}' ); + } + + void output( const Array_type& arr ) + { + output_array_or_obj( arr, '[', ']' ); + } + + void output( const Obj_member_type& member ) + { + output( Config_type::get_name( member ) ); space(); + os_ << ':'; space(); + output( Config_type::get_value( member ) ); + } + + void output_int( const Value_type& value ) + { + if( value.is_uint64() ) + { + os_ << value.get_uint64(); + } + else + { + os_ << value.get_int64(); + } + } + + void output( const String_type& s ) + { + os_ << '"' << add_esc_chars( s ) << '"'; + } + + void output( bool b ) + { + os_ << to_str< String_type >( b ? "true" : "false" ); + } + + template< class T > + void output_array_or_obj( const T& t, Char_type start_char, Char_type end_char ) + { + os_ << start_char; new_line(); + + ++indentation_level_; + + for( typename T::const_iterator i = t.begin(); i != t.end(); ++i ) + { + indent(); output( *i ); + + typename T::const_iterator next = i; + + if( ++next != t.end()) + { + os_ << ','; + } + + new_line(); + } + + --indentation_level_; + + indent(); os_ << end_char; + } + + void indent() + { + if( !pretty_ ) return; + + for( int i = 0; i < indentation_level_; ++i ) + { + os_ << " "; + } + } + + void space() + { + if( pretty_ ) os_ << ' '; + } + + void new_line() + { + if( pretty_ ) os_ << '\n'; + } + + Generator& operator=( const Generator& ); // to prevent "assignment operator could not be generated" warning + + Ostream_type& os_; + int indentation_level_; + bool pretty_; + }; + + template< class Value_type, class Ostream_type > + void write_stream( const Value_type& value, Ostream_type& os, bool pretty ) + { + Generator< Value_type, Ostream_type >( value, os, pretty ); + } + + template< class Value_type > + typename Value_type::String_type write_string( const Value_type& value, bool pretty ) + { + typedef typename Value_type::String_type::value_type Char_type; + + std::basic_ostringstream< Char_type > os; + + write_stream( value, os, pretty ); + + return os.str(); + } +} + +#endif diff --git a/src/keccak.c b/src/keccak.c new file mode 100644 index 0000000..cff9f87 --- /dev/null +++ b/src/keccak.c @@ -0,0 +1,1824 @@ +/* $Id: keccak.c 259 2011-07-19 22:11:27Z tp $ */ +/* + * Keccak implementation. + * + * ==========================(LICENSE BEGIN)============================ + * + * Copyright (c) 2007-2010 Projet RNRT SAPHIR + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * ===========================(LICENSE END)============================= + * + * @author Thomas Pornin + */ + +#include +#include + +#include "sph_keccak.h" + +#ifdef __cplusplus +extern "C"{ +#endif + +/* + * Parameters: + * + * SPH_KECCAK_64 use a 64-bit type + * SPH_KECCAK_UNROLL number of loops to unroll (0/undef for full unroll) + * SPH_KECCAK_INTERLEAVE use bit-interleaving (32-bit type only) + * SPH_KECCAK_NOCOPY do not copy the state into local variables + * + * If there is no usable 64-bit type, the code automatically switches + * back to the 32-bit implementation. + * + * Some tests on an Intel Core2 Q6600 (both 64-bit and 32-bit, 32 kB L1 + * code cache), a PowerPC (G3, 32 kB L1 code cache), an ARM920T core + * (16 kB L1 code cache), and a small MIPS-compatible CPU (Broadcom BCM3302, + * 8 kB L1 code cache), seem to show that the following are optimal: + * + * -- x86, 64-bit: use the 64-bit implementation, unroll 8 rounds, + * do not copy the state; unrolling 2, 6 or all rounds also provides + * near-optimal performance. + * -- x86, 32-bit: use the 32-bit implementation, unroll 6 rounds, + * interleave, do not copy the state. Unrolling 1, 2, 4 or 8 rounds + * also provides near-optimal performance. + * -- PowerPC: use the 64-bit implementation, unroll 8 rounds, + * copy the state. Unrolling 4 or 6 rounds is near-optimal. + * -- ARM: use the 64-bit implementation, unroll 2 or 4 rounds, + * copy the state. + * -- MIPS: use the 64-bit implementation, unroll 2 rounds, copy + * the state. Unrolling only 1 round is also near-optimal. + * + * Also, interleaving does not always yield actual improvements when + * using a 32-bit implementation; in particular when the architecture + * does not offer a native rotation opcode (interleaving replaces one + * 64-bit rotation with two 32-bit rotations, which is a gain only if + * there is a native 32-bit rotation opcode and not a native 64-bit + * rotation opcode; also, interleaving implies a small overhead when + * processing input words). + * + * To sum up: + * -- when possible, use the 64-bit code + * -- exception: on 32-bit x86, use 32-bit code + * -- when using 32-bit code, use interleaving + * -- copy the state, except on x86 + * -- unroll 8 rounds on "big" machine, 2 rounds on "small" machines + */ + +#if SPH_SMALL_FOOTPRINT && !defined SPH_SMALL_FOOTPRINT_KECCAK +#define SPH_SMALL_FOOTPRINT_KECCAK 1 +#endif + +/* + * By default, we select the 64-bit implementation if a 64-bit type + * is available, unless a 32-bit x86 is detected. + */ +#if !defined SPH_KECCAK_64 && SPH_64 \ + && !(defined __i386__ || SPH_I386_GCC || SPH_I386_MSVC) +#define SPH_KECCAK_64 1 +#endif + +/* + * If using a 32-bit implementation, we prefer to interleave. + */ +#if !SPH_KECCAK_64 && !defined SPH_KECCAK_INTERLEAVE +#define SPH_KECCAK_INTERLEAVE 1 +#endif + +/* + * Unroll 8 rounds on big systems, 2 rounds on small systems. + */ +#ifndef SPH_KECCAK_UNROLL +#if SPH_SMALL_FOOTPRINT_KECCAK +#define SPH_KECCAK_UNROLL 2 +#else +#define SPH_KECCAK_UNROLL 8 +#endif +#endif + +/* + * We do not want to copy the state to local variables on x86 (32-bit + * and 64-bit alike). + */ +#ifndef SPH_KECCAK_NOCOPY +#if defined __i386__ || defined __x86_64 || SPH_I386_MSVC || SPH_I386_GCC +#define SPH_KECCAK_NOCOPY 1 +#else +#define SPH_KECCAK_NOCOPY 0 +#endif +#endif + +#ifdef _MSC_VER +#pragma warning (disable: 4146) +#endif + +#if SPH_KECCAK_64 + +static const sph_u64 RC[] = { + SPH_C64(0x0000000000000001), SPH_C64(0x0000000000008082), + SPH_C64(0x800000000000808A), SPH_C64(0x8000000080008000), + SPH_C64(0x000000000000808B), SPH_C64(0x0000000080000001), + SPH_C64(0x8000000080008081), SPH_C64(0x8000000000008009), + SPH_C64(0x000000000000008A), SPH_C64(0x0000000000000088), + SPH_C64(0x0000000080008009), SPH_C64(0x000000008000000A), + SPH_C64(0x000000008000808B), SPH_C64(0x800000000000008B), + SPH_C64(0x8000000000008089), SPH_C64(0x8000000000008003), + SPH_C64(0x8000000000008002), SPH_C64(0x8000000000000080), + SPH_C64(0x000000000000800A), SPH_C64(0x800000008000000A), + SPH_C64(0x8000000080008081), SPH_C64(0x8000000000008080), + SPH_C64(0x0000000080000001), SPH_C64(0x8000000080008008) +}; + +#if SPH_KECCAK_NOCOPY + +#define a00 (kc->u.wide[ 0]) +#define a10 (kc->u.wide[ 1]) +#define a20 (kc->u.wide[ 2]) +#define a30 (kc->u.wide[ 3]) +#define a40 (kc->u.wide[ 4]) +#define a01 (kc->u.wide[ 5]) +#define a11 (kc->u.wide[ 6]) +#define a21 (kc->u.wide[ 7]) +#define a31 (kc->u.wide[ 8]) +#define a41 (kc->u.wide[ 9]) +#define a02 (kc->u.wide[10]) +#define a12 (kc->u.wide[11]) +#define a22 (kc->u.wide[12]) +#define a32 (kc->u.wide[13]) +#define a42 (kc->u.wide[14]) +#define a03 (kc->u.wide[15]) +#define a13 (kc->u.wide[16]) +#define a23 (kc->u.wide[17]) +#define a33 (kc->u.wide[18]) +#define a43 (kc->u.wide[19]) +#define a04 (kc->u.wide[20]) +#define a14 (kc->u.wide[21]) +#define a24 (kc->u.wide[22]) +#define a34 (kc->u.wide[23]) +#define a44 (kc->u.wide[24]) + +#define DECL_STATE +#define READ_STATE(sc) +#define WRITE_STATE(sc) + +#define INPUT_BUF(size) do { \ + size_t j; \ + for (j = 0; j < (size); j += 8) { \ + kc->u.wide[j >> 3] ^= sph_dec64le_aligned(buf + j); \ + } \ + } while (0) + +#define INPUT_BUF144 INPUT_BUF(144) +#define INPUT_BUF136 INPUT_BUF(136) +#define INPUT_BUF104 INPUT_BUF(104) +#define INPUT_BUF72 INPUT_BUF(72) + +#else + +#define DECL_STATE \ + sph_u64 a00, a01, a02, a03, a04; \ + sph_u64 a10, a11, a12, a13, a14; \ + sph_u64 a20, a21, a22, a23, a24; \ + sph_u64 a30, a31, a32, a33, a34; \ + sph_u64 a40, a41, a42, a43, a44; + +#define READ_STATE(state) do { \ + a00 = (state)->u.wide[ 0]; \ + a10 = (state)->u.wide[ 1]; \ + a20 = (state)->u.wide[ 2]; \ + a30 = (state)->u.wide[ 3]; \ + a40 = (state)->u.wide[ 4]; \ + a01 = (state)->u.wide[ 5]; \ + a11 = (state)->u.wide[ 6]; \ + a21 = (state)->u.wide[ 7]; \ + a31 = (state)->u.wide[ 8]; \ + a41 = (state)->u.wide[ 9]; \ + a02 = (state)->u.wide[10]; \ + a12 = (state)->u.wide[11]; \ + a22 = (state)->u.wide[12]; \ + a32 = (state)->u.wide[13]; \ + a42 = (state)->u.wide[14]; \ + a03 = (state)->u.wide[15]; \ + a13 = (state)->u.wide[16]; \ + a23 = (state)->u.wide[17]; \ + a33 = (state)->u.wide[18]; \ + a43 = (state)->u.wide[19]; \ + a04 = (state)->u.wide[20]; \ + a14 = (state)->u.wide[21]; \ + a24 = (state)->u.wide[22]; \ + a34 = (state)->u.wide[23]; \ + a44 = (state)->u.wide[24]; \ + } while (0) + +#define WRITE_STATE(state) do { \ + (state)->u.wide[ 0] = a00; \ + (state)->u.wide[ 1] = a10; \ + (state)->u.wide[ 2] = a20; \ + (state)->u.wide[ 3] = a30; \ + (state)->u.wide[ 4] = a40; \ + (state)->u.wide[ 5] = a01; \ + (state)->u.wide[ 6] = a11; \ + (state)->u.wide[ 7] = a21; \ + (state)->u.wide[ 8] = a31; \ + (state)->u.wide[ 9] = a41; \ + (state)->u.wide[10] = a02; \ + (state)->u.wide[11] = a12; \ + (state)->u.wide[12] = a22; \ + (state)->u.wide[13] = a32; \ + (state)->u.wide[14] = a42; \ + (state)->u.wide[15] = a03; \ + (state)->u.wide[16] = a13; \ + (state)->u.wide[17] = a23; \ + (state)->u.wide[18] = a33; \ + (state)->u.wide[19] = a43; \ + (state)->u.wide[20] = a04; \ + (state)->u.wide[21] = a14; \ + (state)->u.wide[22] = a24; \ + (state)->u.wide[23] = a34; \ + (state)->u.wide[24] = a44; \ + } while (0) + +#define INPUT_BUF144 do { \ + a00 ^= sph_dec64le_aligned(buf + 0); \ + a10 ^= sph_dec64le_aligned(buf + 8); \ + a20 ^= sph_dec64le_aligned(buf + 16); \ + a30 ^= sph_dec64le_aligned(buf + 24); \ + a40 ^= sph_dec64le_aligned(buf + 32); \ + a01 ^= sph_dec64le_aligned(buf + 40); \ + a11 ^= sph_dec64le_aligned(buf + 48); \ + a21 ^= sph_dec64le_aligned(buf + 56); \ + a31 ^= sph_dec64le_aligned(buf + 64); \ + a41 ^= sph_dec64le_aligned(buf + 72); \ + a02 ^= sph_dec64le_aligned(buf + 80); \ + a12 ^= sph_dec64le_aligned(buf + 88); \ + a22 ^= sph_dec64le_aligned(buf + 96); \ + a32 ^= sph_dec64le_aligned(buf + 104); \ + a42 ^= sph_dec64le_aligned(buf + 112); \ + a03 ^= sph_dec64le_aligned(buf + 120); \ + a13 ^= sph_dec64le_aligned(buf + 128); \ + a23 ^= sph_dec64le_aligned(buf + 136); \ + } while (0) + +#define INPUT_BUF136 do { \ + a00 ^= sph_dec64le_aligned(buf + 0); \ + a10 ^= sph_dec64le_aligned(buf + 8); \ + a20 ^= sph_dec64le_aligned(buf + 16); \ + a30 ^= sph_dec64le_aligned(buf + 24); \ + a40 ^= sph_dec64le_aligned(buf + 32); \ + a01 ^= sph_dec64le_aligned(buf + 40); \ + a11 ^= sph_dec64le_aligned(buf + 48); \ + a21 ^= sph_dec64le_aligned(buf + 56); \ + a31 ^= sph_dec64le_aligned(buf + 64); \ + a41 ^= sph_dec64le_aligned(buf + 72); \ + a02 ^= sph_dec64le_aligned(buf + 80); \ + a12 ^= sph_dec64le_aligned(buf + 88); \ + a22 ^= sph_dec64le_aligned(buf + 96); \ + a32 ^= sph_dec64le_aligned(buf + 104); \ + a42 ^= sph_dec64le_aligned(buf + 112); \ + a03 ^= sph_dec64le_aligned(buf + 120); \ + a13 ^= sph_dec64le_aligned(buf + 128); \ + } while (0) + +#define INPUT_BUF104 do { \ + a00 ^= sph_dec64le_aligned(buf + 0); \ + a10 ^= sph_dec64le_aligned(buf + 8); \ + a20 ^= sph_dec64le_aligned(buf + 16); \ + a30 ^= sph_dec64le_aligned(buf + 24); \ + a40 ^= sph_dec64le_aligned(buf + 32); \ + a01 ^= sph_dec64le_aligned(buf + 40); \ + a11 ^= sph_dec64le_aligned(buf + 48); \ + a21 ^= sph_dec64le_aligned(buf + 56); \ + a31 ^= sph_dec64le_aligned(buf + 64); \ + a41 ^= sph_dec64le_aligned(buf + 72); \ + a02 ^= sph_dec64le_aligned(buf + 80); \ + a12 ^= sph_dec64le_aligned(buf + 88); \ + a22 ^= sph_dec64le_aligned(buf + 96); \ + } while (0) + +#define INPUT_BUF72 do { \ + a00 ^= sph_dec64le_aligned(buf + 0); \ + a10 ^= sph_dec64le_aligned(buf + 8); \ + a20 ^= sph_dec64le_aligned(buf + 16); \ + a30 ^= sph_dec64le_aligned(buf + 24); \ + a40 ^= sph_dec64le_aligned(buf + 32); \ + a01 ^= sph_dec64le_aligned(buf + 40); \ + a11 ^= sph_dec64le_aligned(buf + 48); \ + a21 ^= sph_dec64le_aligned(buf + 56); \ + a31 ^= sph_dec64le_aligned(buf + 64); \ + } while (0) + +#define INPUT_BUF(lim) do { \ + a00 ^= sph_dec64le_aligned(buf + 0); \ + a10 ^= sph_dec64le_aligned(buf + 8); \ + a20 ^= sph_dec64le_aligned(buf + 16); \ + a30 ^= sph_dec64le_aligned(buf + 24); \ + a40 ^= sph_dec64le_aligned(buf + 32); \ + a01 ^= sph_dec64le_aligned(buf + 40); \ + a11 ^= sph_dec64le_aligned(buf + 48); \ + a21 ^= sph_dec64le_aligned(buf + 56); \ + a31 ^= sph_dec64le_aligned(buf + 64); \ + if ((lim) == 72) \ + break; \ + a41 ^= sph_dec64le_aligned(buf + 72); \ + a02 ^= sph_dec64le_aligned(buf + 80); \ + a12 ^= sph_dec64le_aligned(buf + 88); \ + a22 ^= sph_dec64le_aligned(buf + 96); \ + if ((lim) == 104) \ + break; \ + a32 ^= sph_dec64le_aligned(buf + 104); \ + a42 ^= sph_dec64le_aligned(buf + 112); \ + a03 ^= sph_dec64le_aligned(buf + 120); \ + a13 ^= sph_dec64le_aligned(buf + 128); \ + if ((lim) == 136) \ + break; \ + a23 ^= sph_dec64le_aligned(buf + 136); \ + } while (0) + +#endif + +#define DECL64(x) sph_u64 x +#define MOV64(d, s) (d = s) +#define XOR64(d, a, b) (d = a ^ b) +#define AND64(d, a, b) (d = a & b) +#define OR64(d, a, b) (d = a | b) +#define NOT64(d, s) (d = SPH_T64(~s)) +#define ROL64(d, v, n) (d = SPH_ROTL64(v, n)) +#define XOR64_IOTA XOR64 + +#else + +static const struct { + sph_u32 high, low; +} RC[] = { +#if SPH_KECCAK_INTERLEAVE + { SPH_C32(0x00000000), SPH_C32(0x00000001) }, + { SPH_C32(0x00000089), SPH_C32(0x00000000) }, + { SPH_C32(0x8000008B), SPH_C32(0x00000000) }, + { SPH_C32(0x80008080), SPH_C32(0x00000000) }, + { SPH_C32(0x0000008B), SPH_C32(0x00000001) }, + { SPH_C32(0x00008000), SPH_C32(0x00000001) }, + { SPH_C32(0x80008088), SPH_C32(0x00000001) }, + { SPH_C32(0x80000082), SPH_C32(0x00000001) }, + { SPH_C32(0x0000000B), SPH_C32(0x00000000) }, + { SPH_C32(0x0000000A), SPH_C32(0x00000000) }, + { SPH_C32(0x00008082), SPH_C32(0x00000001) }, + { SPH_C32(0x00008003), SPH_C32(0x00000000) }, + { SPH_C32(0x0000808B), SPH_C32(0x00000001) }, + { SPH_C32(0x8000000B), SPH_C32(0x00000001) }, + { SPH_C32(0x8000008A), SPH_C32(0x00000001) }, + { SPH_C32(0x80000081), SPH_C32(0x00000001) }, + { SPH_C32(0x80000081), SPH_C32(0x00000000) }, + { SPH_C32(0x80000008), SPH_C32(0x00000000) }, + { SPH_C32(0x00000083), SPH_C32(0x00000000) }, + { SPH_C32(0x80008003), SPH_C32(0x00000000) }, + { SPH_C32(0x80008088), SPH_C32(0x00000001) }, + { SPH_C32(0x80000088), SPH_C32(0x00000000) }, + { SPH_C32(0x00008000), SPH_C32(0x00000001) }, + { SPH_C32(0x80008082), SPH_C32(0x00000000) } +#else + { SPH_C32(0x00000000), SPH_C32(0x00000001) }, + { SPH_C32(0x00000000), SPH_C32(0x00008082) }, + { SPH_C32(0x80000000), SPH_C32(0x0000808A) }, + { SPH_C32(0x80000000), SPH_C32(0x80008000) }, + { SPH_C32(0x00000000), SPH_C32(0x0000808B) }, + { SPH_C32(0x00000000), SPH_C32(0x80000001) }, + { SPH_C32(0x80000000), SPH_C32(0x80008081) }, + { SPH_C32(0x80000000), SPH_C32(0x00008009) }, + { SPH_C32(0x00000000), SPH_C32(0x0000008A) }, + { SPH_C32(0x00000000), SPH_C32(0x00000088) }, + { SPH_C32(0x00000000), SPH_C32(0x80008009) }, + { SPH_C32(0x00000000), SPH_C32(0x8000000A) }, + { SPH_C32(0x00000000), SPH_C32(0x8000808B) }, + { SPH_C32(0x80000000), SPH_C32(0x0000008B) }, + { SPH_C32(0x80000000), SPH_C32(0x00008089) }, + { SPH_C32(0x80000000), SPH_C32(0x00008003) }, + { SPH_C32(0x80000000), SPH_C32(0x00008002) }, + { SPH_C32(0x80000000), SPH_C32(0x00000080) }, + { SPH_C32(0x00000000), SPH_C32(0x0000800A) }, + { SPH_C32(0x80000000), SPH_C32(0x8000000A) }, + { SPH_C32(0x80000000), SPH_C32(0x80008081) }, + { SPH_C32(0x80000000), SPH_C32(0x00008080) }, + { SPH_C32(0x00000000), SPH_C32(0x80000001) }, + { SPH_C32(0x80000000), SPH_C32(0x80008008) } +#endif +}; + +#if SPH_KECCAK_INTERLEAVE + +#define INTERLEAVE(xl, xh) do { \ + sph_u32 l, h, t; \ + l = (xl); h = (xh); \ + t = (l ^ (l >> 1)) & SPH_C32(0x22222222); l ^= t ^ (t << 1); \ + t = (h ^ (h >> 1)) & SPH_C32(0x22222222); h ^= t ^ (t << 1); \ + t = (l ^ (l >> 2)) & SPH_C32(0x0C0C0C0C); l ^= t ^ (t << 2); \ + t = (h ^ (h >> 2)) & SPH_C32(0x0C0C0C0C); h ^= t ^ (t << 2); \ + t = (l ^ (l >> 4)) & SPH_C32(0x00F000F0); l ^= t ^ (t << 4); \ + t = (h ^ (h >> 4)) & SPH_C32(0x00F000F0); h ^= t ^ (t << 4); \ + t = (l ^ (l >> 8)) & SPH_C32(0x0000FF00); l ^= t ^ (t << 8); \ + t = (h ^ (h >> 8)) & SPH_C32(0x0000FF00); h ^= t ^ (t << 8); \ + t = (l ^ SPH_T32(h << 16)) & SPH_C32(0xFFFF0000); \ + l ^= t; h ^= t >> 16; \ + (xl) = l; (xh) = h; \ + } while (0) + +#define UNINTERLEAVE(xl, xh) do { \ + sph_u32 l, h, t; \ + l = (xl); h = (xh); \ + t = (l ^ SPH_T32(h << 16)) & SPH_C32(0xFFFF0000); \ + l ^= t; h ^= t >> 16; \ + t = (l ^ (l >> 8)) & SPH_C32(0x0000FF00); l ^= t ^ (t << 8); \ + t = (h ^ (h >> 8)) & SPH_C32(0x0000FF00); h ^= t ^ (t << 8); \ + t = (l ^ (l >> 4)) & SPH_C32(0x00F000F0); l ^= t ^ (t << 4); \ + t = (h ^ (h >> 4)) & SPH_C32(0x00F000F0); h ^= t ^ (t << 4); \ + t = (l ^ (l >> 2)) & SPH_C32(0x0C0C0C0C); l ^= t ^ (t << 2); \ + t = (h ^ (h >> 2)) & SPH_C32(0x0C0C0C0C); h ^= t ^ (t << 2); \ + t = (l ^ (l >> 1)) & SPH_C32(0x22222222); l ^= t ^ (t << 1); \ + t = (h ^ (h >> 1)) & SPH_C32(0x22222222); h ^= t ^ (t << 1); \ + (xl) = l; (xh) = h; \ + } while (0) + +#else + +#define INTERLEAVE(l, h) +#define UNINTERLEAVE(l, h) + +#endif + +#if SPH_KECCAK_NOCOPY + +#define a00l (kc->u.narrow[2 * 0 + 0]) +#define a00h (kc->u.narrow[2 * 0 + 1]) +#define a10l (kc->u.narrow[2 * 1 + 0]) +#define a10h (kc->u.narrow[2 * 1 + 1]) +#define a20l (kc->u.narrow[2 * 2 + 0]) +#define a20h (kc->u.narrow[2 * 2 + 1]) +#define a30l (kc->u.narrow[2 * 3 + 0]) +#define a30h (kc->u.narrow[2 * 3 + 1]) +#define a40l (kc->u.narrow[2 * 4 + 0]) +#define a40h (kc->u.narrow[2 * 4 + 1]) +#define a01l (kc->u.narrow[2 * 5 + 0]) +#define a01h (kc->u.narrow[2 * 5 + 1]) +#define a11l (kc->u.narrow[2 * 6 + 0]) +#define a11h (kc->u.narrow[2 * 6 + 1]) +#define a21l (kc->u.narrow[2 * 7 + 0]) +#define a21h (kc->u.narrow[2 * 7 + 1]) +#define a31l (kc->u.narrow[2 * 8 + 0]) +#define a31h (kc->u.narrow[2 * 8 + 1]) +#define a41l (kc->u.narrow[2 * 9 + 0]) +#define a41h (kc->u.narrow[2 * 9 + 1]) +#define a02l (kc->u.narrow[2 * 10 + 0]) +#define a02h (kc->u.narrow[2 * 10 + 1]) +#define a12l (kc->u.narrow[2 * 11 + 0]) +#define a12h (kc->u.narrow[2 * 11 + 1]) +#define a22l (kc->u.narrow[2 * 12 + 0]) +#define a22h (kc->u.narrow[2 * 12 + 1]) +#define a32l (kc->u.narrow[2 * 13 + 0]) +#define a32h (kc->u.narrow[2 * 13 + 1]) +#define a42l (kc->u.narrow[2 * 14 + 0]) +#define a42h (kc->u.narrow[2 * 14 + 1]) +#define a03l (kc->u.narrow[2 * 15 + 0]) +#define a03h (kc->u.narrow[2 * 15 + 1]) +#define a13l (kc->u.narrow[2 * 16 + 0]) +#define a13h (kc->u.narrow[2 * 16 + 1]) +#define a23l (kc->u.narrow[2 * 17 + 0]) +#define a23h (kc->u.narrow[2 * 17 + 1]) +#define a33l (kc->u.narrow[2 * 18 + 0]) +#define a33h (kc->u.narrow[2 * 18 + 1]) +#define a43l (kc->u.narrow[2 * 19 + 0]) +#define a43h (kc->u.narrow[2 * 19 + 1]) +#define a04l (kc->u.narrow[2 * 20 + 0]) +#define a04h (kc->u.narrow[2 * 20 + 1]) +#define a14l (kc->u.narrow[2 * 21 + 0]) +#define a14h (kc->u.narrow[2 * 21 + 1]) +#define a24l (kc->u.narrow[2 * 22 + 0]) +#define a24h (kc->u.narrow[2 * 22 + 1]) +#define a34l (kc->u.narrow[2 * 23 + 0]) +#define a34h (kc->u.narrow[2 * 23 + 1]) +#define a44l (kc->u.narrow[2 * 24 + 0]) +#define a44h (kc->u.narrow[2 * 24 + 1]) + +#define DECL_STATE +#define READ_STATE(state) +#define WRITE_STATE(state) + +#define INPUT_BUF(size) do { \ + size_t j; \ + for (j = 0; j < (size); j += 8) { \ + sph_u32 tl, th; \ + tl = sph_dec32le_aligned(buf + j + 0); \ + th = sph_dec32le_aligned(buf + j + 4); \ + INTERLEAVE(tl, th); \ + kc->u.narrow[(j >> 2) + 0] ^= tl; \ + kc->u.narrow[(j >> 2) + 1] ^= th; \ + } \ + } while (0) + +#define INPUT_BUF144 INPUT_BUF(144) +#define INPUT_BUF136 INPUT_BUF(136) +#define INPUT_BUF104 INPUT_BUF(104) +#define INPUT_BUF72 INPUT_BUF(72) + +#else + +#define DECL_STATE \ + sph_u32 a00l, a00h, a01l, a01h, a02l, a02h, a03l, a03h, a04l, a04h; \ + sph_u32 a10l, a10h, a11l, a11h, a12l, a12h, a13l, a13h, a14l, a14h; \ + sph_u32 a20l, a20h, a21l, a21h, a22l, a22h, a23l, a23h, a24l, a24h; \ + sph_u32 a30l, a30h, a31l, a31h, a32l, a32h, a33l, a33h, a34l, a34h; \ + sph_u32 a40l, a40h, a41l, a41h, a42l, a42h, a43l, a43h, a44l, a44h; + +#define READ_STATE(state) do { \ + a00l = (state)->u.narrow[2 * 0 + 0]; \ + a00h = (state)->u.narrow[2 * 0 + 1]; \ + a10l = (state)->u.narrow[2 * 1 + 0]; \ + a10h = (state)->u.narrow[2 * 1 + 1]; \ + a20l = (state)->u.narrow[2 * 2 + 0]; \ + a20h = (state)->u.narrow[2 * 2 + 1]; \ + a30l = (state)->u.narrow[2 * 3 + 0]; \ + a30h = (state)->u.narrow[2 * 3 + 1]; \ + a40l = (state)->u.narrow[2 * 4 + 0]; \ + a40h = (state)->u.narrow[2 * 4 + 1]; \ + a01l = (state)->u.narrow[2 * 5 + 0]; \ + a01h = (state)->u.narrow[2 * 5 + 1]; \ + a11l = (state)->u.narrow[2 * 6 + 0]; \ + a11h = (state)->u.narrow[2 * 6 + 1]; \ + a21l = (state)->u.narrow[2 * 7 + 0]; \ + a21h = (state)->u.narrow[2 * 7 + 1]; \ + a31l = (state)->u.narrow[2 * 8 + 0]; \ + a31h = (state)->u.narrow[2 * 8 + 1]; \ + a41l = (state)->u.narrow[2 * 9 + 0]; \ + a41h = (state)->u.narrow[2 * 9 + 1]; \ + a02l = (state)->u.narrow[2 * 10 + 0]; \ + a02h = (state)->u.narrow[2 * 10 + 1]; \ + a12l = (state)->u.narrow[2 * 11 + 0]; \ + a12h = (state)->u.narrow[2 * 11 + 1]; \ + a22l = (state)->u.narrow[2 * 12 + 0]; \ + a22h = (state)->u.narrow[2 * 12 + 1]; \ + a32l = (state)->u.narrow[2 * 13 + 0]; \ + a32h = (state)->u.narrow[2 * 13 + 1]; \ + a42l = (state)->u.narrow[2 * 14 + 0]; \ + a42h = (state)->u.narrow[2 * 14 + 1]; \ + a03l = (state)->u.narrow[2 * 15 + 0]; \ + a03h = (state)->u.narrow[2 * 15 + 1]; \ + a13l = (state)->u.narrow[2 * 16 + 0]; \ + a13h = (state)->u.narrow[2 * 16 + 1]; \ + a23l = (state)->u.narrow[2 * 17 + 0]; \ + a23h = (state)->u.narrow[2 * 17 + 1]; \ + a33l = (state)->u.narrow[2 * 18 + 0]; \ + a33h = (state)->u.narrow[2 * 18 + 1]; \ + a43l = (state)->u.narrow[2 * 19 + 0]; \ + a43h = (state)->u.narrow[2 * 19 + 1]; \ + a04l = (state)->u.narrow[2 * 20 + 0]; \ + a04h = (state)->u.narrow[2 * 20 + 1]; \ + a14l = (state)->u.narrow[2 * 21 + 0]; \ + a14h = (state)->u.narrow[2 * 21 + 1]; \ + a24l = (state)->u.narrow[2 * 22 + 0]; \ + a24h = (state)->u.narrow[2 * 22 + 1]; \ + a34l = (state)->u.narrow[2 * 23 + 0]; \ + a34h = (state)->u.narrow[2 * 23 + 1]; \ + a44l = (state)->u.narrow[2 * 24 + 0]; \ + a44h = (state)->u.narrow[2 * 24 + 1]; \ + } while (0) + +#define WRITE_STATE(state) do { \ + (state)->u.narrow[2 * 0 + 0] = a00l; \ + (state)->u.narrow[2 * 0 + 1] = a00h; \ + (state)->u.narrow[2 * 1 + 0] = a10l; \ + (state)->u.narrow[2 * 1 + 1] = a10h; \ + (state)->u.narrow[2 * 2 + 0] = a20l; \ + (state)->u.narrow[2 * 2 + 1] = a20h; \ + (state)->u.narrow[2 * 3 + 0] = a30l; \ + (state)->u.narrow[2 * 3 + 1] = a30h; \ + (state)->u.narrow[2 * 4 + 0] = a40l; \ + (state)->u.narrow[2 * 4 + 1] = a40h; \ + (state)->u.narrow[2 * 5 + 0] = a01l; \ + (state)->u.narrow[2 * 5 + 1] = a01h; \ + (state)->u.narrow[2 * 6 + 0] = a11l; \ + (state)->u.narrow[2 * 6 + 1] = a11h; \ + (state)->u.narrow[2 * 7 + 0] = a21l; \ + (state)->u.narrow[2 * 7 + 1] = a21h; \ + (state)->u.narrow[2 * 8 + 0] = a31l; \ + (state)->u.narrow[2 * 8 + 1] = a31h; \ + (state)->u.narrow[2 * 9 + 0] = a41l; \ + (state)->u.narrow[2 * 9 + 1] = a41h; \ + (state)->u.narrow[2 * 10 + 0] = a02l; \ + (state)->u.narrow[2 * 10 + 1] = a02h; \ + (state)->u.narrow[2 * 11 + 0] = a12l; \ + (state)->u.narrow[2 * 11 + 1] = a12h; \ + (state)->u.narrow[2 * 12 + 0] = a22l; \ + (state)->u.narrow[2 * 12 + 1] = a22h; \ + (state)->u.narrow[2 * 13 + 0] = a32l; \ + (state)->u.narrow[2 * 13 + 1] = a32h; \ + (state)->u.narrow[2 * 14 + 0] = a42l; \ + (state)->u.narrow[2 * 14 + 1] = a42h; \ + (state)->u.narrow[2 * 15 + 0] = a03l; \ + (state)->u.narrow[2 * 15 + 1] = a03h; \ + (state)->u.narrow[2 * 16 + 0] = a13l; \ + (state)->u.narrow[2 * 16 + 1] = a13h; \ + (state)->u.narrow[2 * 17 + 0] = a23l; \ + (state)->u.narrow[2 * 17 + 1] = a23h; \ + (state)->u.narrow[2 * 18 + 0] = a33l; \ + (state)->u.narrow[2 * 18 + 1] = a33h; \ + (state)->u.narrow[2 * 19 + 0] = a43l; \ + (state)->u.narrow[2 * 19 + 1] = a43h; \ + (state)->u.narrow[2 * 20 + 0] = a04l; \ + (state)->u.narrow[2 * 20 + 1] = a04h; \ + (state)->u.narrow[2 * 21 + 0] = a14l; \ + (state)->u.narrow[2 * 21 + 1] = a14h; \ + (state)->u.narrow[2 * 22 + 0] = a24l; \ + (state)->u.narrow[2 * 22 + 1] = a24h; \ + (state)->u.narrow[2 * 23 + 0] = a34l; \ + (state)->u.narrow[2 * 23 + 1] = a34h; \ + (state)->u.narrow[2 * 24 + 0] = a44l; \ + (state)->u.narrow[2 * 24 + 1] = a44h; \ + } while (0) + +#define READ64(d, off) do { \ + sph_u32 tl, th; \ + tl = sph_dec32le_aligned(buf + (off)); \ + th = sph_dec32le_aligned(buf + (off) + 4); \ + INTERLEAVE(tl, th); \ + d ## l ^= tl; \ + d ## h ^= th; \ + } while (0) + +#define INPUT_BUF144 do { \ + READ64(a00, 0); \ + READ64(a10, 8); \ + READ64(a20, 16); \ + READ64(a30, 24); \ + READ64(a40, 32); \ + READ64(a01, 40); \ + READ64(a11, 48); \ + READ64(a21, 56); \ + READ64(a31, 64); \ + READ64(a41, 72); \ + READ64(a02, 80); \ + READ64(a12, 88); \ + READ64(a22, 96); \ + READ64(a32, 104); \ + READ64(a42, 112); \ + READ64(a03, 120); \ + READ64(a13, 128); \ + READ64(a23, 136); \ + } while (0) + +#define INPUT_BUF136 do { \ + READ64(a00, 0); \ + READ64(a10, 8); \ + READ64(a20, 16); \ + READ64(a30, 24); \ + READ64(a40, 32); \ + READ64(a01, 40); \ + READ64(a11, 48); \ + READ64(a21, 56); \ + READ64(a31, 64); \ + READ64(a41, 72); \ + READ64(a02, 80); \ + READ64(a12, 88); \ + READ64(a22, 96); \ + READ64(a32, 104); \ + READ64(a42, 112); \ + READ64(a03, 120); \ + READ64(a13, 128); \ + } while (0) + +#define INPUT_BUF104 do { \ + READ64(a00, 0); \ + READ64(a10, 8); \ + READ64(a20, 16); \ + READ64(a30, 24); \ + READ64(a40, 32); \ + READ64(a01, 40); \ + READ64(a11, 48); \ + READ64(a21, 56); \ + READ64(a31, 64); \ + READ64(a41, 72); \ + READ64(a02, 80); \ + READ64(a12, 88); \ + READ64(a22, 96); \ + } while (0) + +#define INPUT_BUF72 do { \ + READ64(a00, 0); \ + READ64(a10, 8); \ + READ64(a20, 16); \ + READ64(a30, 24); \ + READ64(a40, 32); \ + READ64(a01, 40); \ + READ64(a11, 48); \ + READ64(a21, 56); \ + READ64(a31, 64); \ + } while (0) + +#define INPUT_BUF(lim) do { \ + READ64(a00, 0); \ + READ64(a10, 8); \ + READ64(a20, 16); \ + READ64(a30, 24); \ + READ64(a40, 32); \ + READ64(a01, 40); \ + READ64(a11, 48); \ + READ64(a21, 56); \ + READ64(a31, 64); \ + if ((lim) == 72) \ + break; \ + READ64(a41, 72); \ + READ64(a02, 80); \ + READ64(a12, 88); \ + READ64(a22, 96); \ + if ((lim) == 104) \ + break; \ + READ64(a32, 104); \ + READ64(a42, 112); \ + READ64(a03, 120); \ + READ64(a13, 128); \ + if ((lim) == 136) \ + break; \ + READ64(a23, 136); \ + } while (0) + +#endif + +#define DECL64(x) sph_u64 x ## l, x ## h +#define MOV64(d, s) (d ## l = s ## l, d ## h = s ## h) +#define XOR64(d, a, b) (d ## l = a ## l ^ b ## l, d ## h = a ## h ^ b ## h) +#define AND64(d, a, b) (d ## l = a ## l & b ## l, d ## h = a ## h & b ## h) +#define OR64(d, a, b) (d ## l = a ## l | b ## l, d ## h = a ## h | b ## h) +#define NOT64(d, s) (d ## l = SPH_T32(~s ## l), d ## h = SPH_T32(~s ## h)) +#define ROL64(d, v, n) ROL64_ ## n(d, v) + +#if SPH_KECCAK_INTERLEAVE + +#define ROL64_odd1(d, v) do { \ + sph_u32 tmp; \ + tmp = v ## l; \ + d ## l = SPH_T32(v ## h << 1) | (v ## h >> 31); \ + d ## h = tmp; \ + } while (0) + +#define ROL64_odd63(d, v) do { \ + sph_u32 tmp; \ + tmp = SPH_T32(v ## l << 31) | (v ## l >> 1); \ + d ## l = v ## h; \ + d ## h = tmp; \ + } while (0) + +#define ROL64_odd(d, v, n) do { \ + sph_u32 tmp; \ + tmp = SPH_T32(v ## l << (n - 1)) | (v ## l >> (33 - n)); \ + d ## l = SPH_T32(v ## h << n) | (v ## h >> (32 - n)); \ + d ## h = tmp; \ + } while (0) + +#define ROL64_even(d, v, n) do { \ + d ## l = SPH_T32(v ## l << n) | (v ## l >> (32 - n)); \ + d ## h = SPH_T32(v ## h << n) | (v ## h >> (32 - n)); \ + } while (0) + +#define ROL64_0(d, v) +#define ROL64_1(d, v) ROL64_odd1(d, v) +#define ROL64_2(d, v) ROL64_even(d, v, 1) +#define ROL64_3(d, v) ROL64_odd( d, v, 2) +#define ROL64_4(d, v) ROL64_even(d, v, 2) +#define ROL64_5(d, v) ROL64_odd( d, v, 3) +#define ROL64_6(d, v) ROL64_even(d, v, 3) +#define ROL64_7(d, v) ROL64_odd( d, v, 4) +#define ROL64_8(d, v) ROL64_even(d, v, 4) +#define ROL64_9(d, v) ROL64_odd( d, v, 5) +#define ROL64_10(d, v) ROL64_even(d, v, 5) +#define ROL64_11(d, v) ROL64_odd( d, v, 6) +#define ROL64_12(d, v) ROL64_even(d, v, 6) +#define ROL64_13(d, v) ROL64_odd( d, v, 7) +#define ROL64_14(d, v) ROL64_even(d, v, 7) +#define ROL64_15(d, v) ROL64_odd( d, v, 8) +#define ROL64_16(d, v) ROL64_even(d, v, 8) +#define ROL64_17(d, v) ROL64_odd( d, v, 9) +#define ROL64_18(d, v) ROL64_even(d, v, 9) +#define ROL64_19(d, v) ROL64_odd( d, v, 10) +#define ROL64_20(d, v) ROL64_even(d, v, 10) +#define ROL64_21(d, v) ROL64_odd( d, v, 11) +#define ROL64_22(d, v) ROL64_even(d, v, 11) +#define ROL64_23(d, v) ROL64_odd( d, v, 12) +#define ROL64_24(d, v) ROL64_even(d, v, 12) +#define ROL64_25(d, v) ROL64_odd( d, v, 13) +#define ROL64_26(d, v) ROL64_even(d, v, 13) +#define ROL64_27(d, v) ROL64_odd( d, v, 14) +#define ROL64_28(d, v) ROL64_even(d, v, 14) +#define ROL64_29(d, v) ROL64_odd( d, v, 15) +#define ROL64_30(d, v) ROL64_even(d, v, 15) +#define ROL64_31(d, v) ROL64_odd( d, v, 16) +#define ROL64_32(d, v) ROL64_even(d, v, 16) +#define ROL64_33(d, v) ROL64_odd( d, v, 17) +#define ROL64_34(d, v) ROL64_even(d, v, 17) +#define ROL64_35(d, v) ROL64_odd( d, v, 18) +#define ROL64_36(d, v) ROL64_even(d, v, 18) +#define ROL64_37(d, v) ROL64_odd( d, v, 19) +#define ROL64_38(d, v) ROL64_even(d, v, 19) +#define ROL64_39(d, v) ROL64_odd( d, v, 20) +#define ROL64_40(d, v) ROL64_even(d, v, 20) +#define ROL64_41(d, v) ROL64_odd( d, v, 21) +#define ROL64_42(d, v) ROL64_even(d, v, 21) +#define ROL64_43(d, v) ROL64_odd( d, v, 22) +#define ROL64_44(d, v) ROL64_even(d, v, 22) +#define ROL64_45(d, v) ROL64_odd( d, v, 23) +#define ROL64_46(d, v) ROL64_even(d, v, 23) +#define ROL64_47(d, v) ROL64_odd( d, v, 24) +#define ROL64_48(d, v) ROL64_even(d, v, 24) +#define ROL64_49(d, v) ROL64_odd( d, v, 25) +#define ROL64_50(d, v) ROL64_even(d, v, 25) +#define ROL64_51(d, v) ROL64_odd( d, v, 26) +#define ROL64_52(d, v) ROL64_even(d, v, 26) +#define ROL64_53(d, v) ROL64_odd( d, v, 27) +#define ROL64_54(d, v) ROL64_even(d, v, 27) +#define ROL64_55(d, v) ROL64_odd( d, v, 28) +#define ROL64_56(d, v) ROL64_even(d, v, 28) +#define ROL64_57(d, v) ROL64_odd( d, v, 29) +#define ROL64_58(d, v) ROL64_even(d, v, 29) +#define ROL64_59(d, v) ROL64_odd( d, v, 30) +#define ROL64_60(d, v) ROL64_even(d, v, 30) +#define ROL64_61(d, v) ROL64_odd( d, v, 31) +#define ROL64_62(d, v) ROL64_even(d, v, 31) +#define ROL64_63(d, v) ROL64_odd63(d, v) + +#else + +#define ROL64_small(d, v, n) do { \ + sph_u32 tmp; \ + tmp = SPH_T32(v ## l << n) | (v ## h >> (32 - n)); \ + d ## h = SPH_T32(v ## h << n) | (v ## l >> (32 - n)); \ + d ## l = tmp; \ + } while (0) + +#define ROL64_0(d, v) 0 +#define ROL64_1(d, v) ROL64_small(d, v, 1) +#define ROL64_2(d, v) ROL64_small(d, v, 2) +#define ROL64_3(d, v) ROL64_small(d, v, 3) +#define ROL64_4(d, v) ROL64_small(d, v, 4) +#define ROL64_5(d, v) ROL64_small(d, v, 5) +#define ROL64_6(d, v) ROL64_small(d, v, 6) +#define ROL64_7(d, v) ROL64_small(d, v, 7) +#define ROL64_8(d, v) ROL64_small(d, v, 8) +#define ROL64_9(d, v) ROL64_small(d, v, 9) +#define ROL64_10(d, v) ROL64_small(d, v, 10) +#define ROL64_11(d, v) ROL64_small(d, v, 11) +#define ROL64_12(d, v) ROL64_small(d, v, 12) +#define ROL64_13(d, v) ROL64_small(d, v, 13) +#define ROL64_14(d, v) ROL64_small(d, v, 14) +#define ROL64_15(d, v) ROL64_small(d, v, 15) +#define ROL64_16(d, v) ROL64_small(d, v, 16) +#define ROL64_17(d, v) ROL64_small(d, v, 17) +#define ROL64_18(d, v) ROL64_small(d, v, 18) +#define ROL64_19(d, v) ROL64_small(d, v, 19) +#define ROL64_20(d, v) ROL64_small(d, v, 20) +#define ROL64_21(d, v) ROL64_small(d, v, 21) +#define ROL64_22(d, v) ROL64_small(d, v, 22) +#define ROL64_23(d, v) ROL64_small(d, v, 23) +#define ROL64_24(d, v) ROL64_small(d, v, 24) +#define ROL64_25(d, v) ROL64_small(d, v, 25) +#define ROL64_26(d, v) ROL64_small(d, v, 26) +#define ROL64_27(d, v) ROL64_small(d, v, 27) +#define ROL64_28(d, v) ROL64_small(d, v, 28) +#define ROL64_29(d, v) ROL64_small(d, v, 29) +#define ROL64_30(d, v) ROL64_small(d, v, 30) +#define ROL64_31(d, v) ROL64_small(d, v, 31) + +#define ROL64_32(d, v) do { \ + sph_u32 tmp; \ + tmp = v ## l; \ + d ## l = v ## h; \ + d ## h = tmp; \ + } while (0) + +#define ROL64_big(d, v, n) do { \ + sph_u32 trl, trh; \ + ROL64_small(tr, v, n); \ + d ## h = trl; \ + d ## l = trh; \ + } while (0) + +#define ROL64_33(d, v) ROL64_big(d, v, 1) +#define ROL64_34(d, v) ROL64_big(d, v, 2) +#define ROL64_35(d, v) ROL64_big(d, v, 3) +#define ROL64_36(d, v) ROL64_big(d, v, 4) +#define ROL64_37(d, v) ROL64_big(d, v, 5) +#define ROL64_38(d, v) ROL64_big(d, v, 6) +#define ROL64_39(d, v) ROL64_big(d, v, 7) +#define ROL64_40(d, v) ROL64_big(d, v, 8) +#define ROL64_41(d, v) ROL64_big(d, v, 9) +#define ROL64_42(d, v) ROL64_big(d, v, 10) +#define ROL64_43(d, v) ROL64_big(d, v, 11) +#define ROL64_44(d, v) ROL64_big(d, v, 12) +#define ROL64_45(d, v) ROL64_big(d, v, 13) +#define ROL64_46(d, v) ROL64_big(d, v, 14) +#define ROL64_47(d, v) ROL64_big(d, v, 15) +#define ROL64_48(d, v) ROL64_big(d, v, 16) +#define ROL64_49(d, v) ROL64_big(d, v, 17) +#define ROL64_50(d, v) ROL64_big(d, v, 18) +#define ROL64_51(d, v) ROL64_big(d, v, 19) +#define ROL64_52(d, v) ROL64_big(d, v, 20) +#define ROL64_53(d, v) ROL64_big(d, v, 21) +#define ROL64_54(d, v) ROL64_big(d, v, 22) +#define ROL64_55(d, v) ROL64_big(d, v, 23) +#define ROL64_56(d, v) ROL64_big(d, v, 24) +#define ROL64_57(d, v) ROL64_big(d, v, 25) +#define ROL64_58(d, v) ROL64_big(d, v, 26) +#define ROL64_59(d, v) ROL64_big(d, v, 27) +#define ROL64_60(d, v) ROL64_big(d, v, 28) +#define ROL64_61(d, v) ROL64_big(d, v, 29) +#define ROL64_62(d, v) ROL64_big(d, v, 30) +#define ROL64_63(d, v) ROL64_big(d, v, 31) + +#endif + +#define XOR64_IOTA(d, s, k) \ + (d ## l = s ## l ^ k.low, d ## h = s ## h ^ k.high) + +#endif + +#define TH_ELT(t, c0, c1, c2, c3, c4, d0, d1, d2, d3, d4) do { \ + DECL64(tt0); \ + DECL64(tt1); \ + DECL64(tt2); \ + DECL64(tt3); \ + XOR64(tt0, d0, d1); \ + XOR64(tt1, d2, d3); \ + XOR64(tt0, tt0, d4); \ + XOR64(tt0, tt0, tt1); \ + ROL64(tt0, tt0, 1); \ + XOR64(tt2, c0, c1); \ + XOR64(tt3, c2, c3); \ + XOR64(tt0, tt0, c4); \ + XOR64(tt2, tt2, tt3); \ + XOR64(t, tt0, tt2); \ + } while (0) + +#define THETA(b00, b01, b02, b03, b04, b10, b11, b12, b13, b14, \ + b20, b21, b22, b23, b24, b30, b31, b32, b33, b34, \ + b40, b41, b42, b43, b44) \ + do { \ + DECL64(t0); \ + DECL64(t1); \ + DECL64(t2); \ + DECL64(t3); \ + DECL64(t4); \ + TH_ELT(t0, b40, b41, b42, b43, b44, b10, b11, b12, b13, b14); \ + TH_ELT(t1, b00, b01, b02, b03, b04, b20, b21, b22, b23, b24); \ + TH_ELT(t2, b10, b11, b12, b13, b14, b30, b31, b32, b33, b34); \ + TH_ELT(t3, b20, b21, b22, b23, b24, b40, b41, b42, b43, b44); \ + TH_ELT(t4, b30, b31, b32, b33, b34, b00, b01, b02, b03, b04); \ + XOR64(b00, b00, t0); \ + XOR64(b01, b01, t0); \ + XOR64(b02, b02, t0); \ + XOR64(b03, b03, t0); \ + XOR64(b04, b04, t0); \ + XOR64(b10, b10, t1); \ + XOR64(b11, b11, t1); \ + XOR64(b12, b12, t1); \ + XOR64(b13, b13, t1); \ + XOR64(b14, b14, t1); \ + XOR64(b20, b20, t2); \ + XOR64(b21, b21, t2); \ + XOR64(b22, b22, t2); \ + XOR64(b23, b23, t2); \ + XOR64(b24, b24, t2); \ + XOR64(b30, b30, t3); \ + XOR64(b31, b31, t3); \ + XOR64(b32, b32, t3); \ + XOR64(b33, b33, t3); \ + XOR64(b34, b34, t3); \ + XOR64(b40, b40, t4); \ + XOR64(b41, b41, t4); \ + XOR64(b42, b42, t4); \ + XOR64(b43, b43, t4); \ + XOR64(b44, b44, t4); \ + } while (0) + +#define RHO(b00, b01, b02, b03, b04, b10, b11, b12, b13, b14, \ + b20, b21, b22, b23, b24, b30, b31, b32, b33, b34, \ + b40, b41, b42, b43, b44) \ + do { \ + /* ROL64(b00, b00, 0); */ \ + ROL64(b01, b01, 36); \ + ROL64(b02, b02, 3); \ + ROL64(b03, b03, 41); \ + ROL64(b04, b04, 18); \ + ROL64(b10, b10, 1); \ + ROL64(b11, b11, 44); \ + ROL64(b12, b12, 10); \ + ROL64(b13, b13, 45); \ + ROL64(b14, b14, 2); \ + ROL64(b20, b20, 62); \ + ROL64(b21, b21, 6); \ + ROL64(b22, b22, 43); \ + ROL64(b23, b23, 15); \ + ROL64(b24, b24, 61); \ + ROL64(b30, b30, 28); \ + ROL64(b31, b31, 55); \ + ROL64(b32, b32, 25); \ + ROL64(b33, b33, 21); \ + ROL64(b34, b34, 56); \ + ROL64(b40, b40, 27); \ + ROL64(b41, b41, 20); \ + ROL64(b42, b42, 39); \ + ROL64(b43, b43, 8); \ + ROL64(b44, b44, 14); \ + } while (0) + +/* + * The KHI macro integrates the "lane complement" optimization. On input, + * some words are complemented: + * a00 a01 a02 a04 a13 a20 a21 a22 a30 a33 a34 a43 + * On output, the following words are complemented: + * a04 a10 a20 a22 a23 a31 + * + * The (implicit) permutation and the theta expansion will bring back + * the input mask for the next round. + */ + +#define KHI_XO(d, a, b, c) do { \ + DECL64(kt); \ + OR64(kt, b, c); \ + XOR64(d, a, kt); \ + } while (0) + +#define KHI_XA(d, a, b, c) do { \ + DECL64(kt); \ + AND64(kt, b, c); \ + XOR64(d, a, kt); \ + } while (0) + +#define KHI(b00, b01, b02, b03, b04, b10, b11, b12, b13, b14, \ + b20, b21, b22, b23, b24, b30, b31, b32, b33, b34, \ + b40, b41, b42, b43, b44) \ + do { \ + DECL64(c0); \ + DECL64(c1); \ + DECL64(c2); \ + DECL64(c3); \ + DECL64(c4); \ + DECL64(bnn); \ + NOT64(bnn, b20); \ + KHI_XO(c0, b00, b10, b20); \ + KHI_XO(c1, b10, bnn, b30); \ + KHI_XA(c2, b20, b30, b40); \ + KHI_XO(c3, b30, b40, b00); \ + KHI_XA(c4, b40, b00, b10); \ + MOV64(b00, c0); \ + MOV64(b10, c1); \ + MOV64(b20, c2); \ + MOV64(b30, c3); \ + MOV64(b40, c4); \ + NOT64(bnn, b41); \ + KHI_XO(c0, b01, b11, b21); \ + KHI_XA(c1, b11, b21, b31); \ + KHI_XO(c2, b21, b31, bnn); \ + KHI_XO(c3, b31, b41, b01); \ + KHI_XA(c4, b41, b01, b11); \ + MOV64(b01, c0); \ + MOV64(b11, c1); \ + MOV64(b21, c2); \ + MOV64(b31, c3); \ + MOV64(b41, c4); \ + NOT64(bnn, b32); \ + KHI_XO(c0, b02, b12, b22); \ + KHI_XA(c1, b12, b22, b32); \ + KHI_XA(c2, b22, bnn, b42); \ + KHI_XO(c3, bnn, b42, b02); \ + KHI_XA(c4, b42, b02, b12); \ + MOV64(b02, c0); \ + MOV64(b12, c1); \ + MOV64(b22, c2); \ + MOV64(b32, c3); \ + MOV64(b42, c4); \ + NOT64(bnn, b33); \ + KHI_XA(c0, b03, b13, b23); \ + KHI_XO(c1, b13, b23, b33); \ + KHI_XO(c2, b23, bnn, b43); \ + KHI_XA(c3, bnn, b43, b03); \ + KHI_XO(c4, b43, b03, b13); \ + MOV64(b03, c0); \ + MOV64(b13, c1); \ + MOV64(b23, c2); \ + MOV64(b33, c3); \ + MOV64(b43, c4); \ + NOT64(bnn, b14); \ + KHI_XA(c0, b04, bnn, b24); \ + KHI_XO(c1, bnn, b24, b34); \ + KHI_XA(c2, b24, b34, b44); \ + KHI_XO(c3, b34, b44, b04); \ + KHI_XA(c4, b44, b04, b14); \ + MOV64(b04, c0); \ + MOV64(b14, c1); \ + MOV64(b24, c2); \ + MOV64(b34, c3); \ + MOV64(b44, c4); \ + } while (0) + +#define IOTA(r) XOR64_IOTA(a00, a00, r) + +#define P0 a00, a01, a02, a03, a04, a10, a11, a12, a13, a14, a20, a21, \ + a22, a23, a24, a30, a31, a32, a33, a34, a40, a41, a42, a43, a44 +#define P1 a00, a30, a10, a40, a20, a11, a41, a21, a01, a31, a22, a02, \ + a32, a12, a42, a33, a13, a43, a23, a03, a44, a24, a04, a34, a14 +#define P2 a00, a33, a11, a44, a22, a41, a24, a02, a30, a13, a32, a10, \ + a43, a21, a04, a23, a01, a34, a12, a40, a14, a42, a20, a03, a31 +#define P3 a00, a23, a41, a14, a32, a24, a42, a10, a33, a01, a43, a11, \ + a34, a02, a20, a12, a30, a03, a21, a44, a31, a04, a22, a40, a13 +#define P4 a00, a12, a24, a31, a43, a42, a04, a11, a23, a30, a34, a41, \ + a03, a10, a22, a21, a33, a40, a02, a14, a13, a20, a32, a44, a01 +#define P5 a00, a21, a42, a13, a34, a04, a20, a41, a12, a33, a03, a24, \ + a40, a11, a32, a02, a23, a44, a10, a31, a01, a22, a43, a14, a30 +#define P6 a00, a02, a04, a01, a03, a20, a22, a24, a21, a23, a40, a42, \ + a44, a41, a43, a10, a12, a14, a11, a13, a30, a32, a34, a31, a33 +#define P7 a00, a10, a20, a30, a40, a22, a32, a42, a02, a12, a44, a04, \ + a14, a24, a34, a11, a21, a31, a41, a01, a33, a43, a03, a13, a23 +#define P8 a00, a11, a22, a33, a44, a32, a43, a04, a10, a21, a14, a20, \ + a31, a42, a03, a41, a02, a13, a24, a30, a23, a34, a40, a01, a12 +#define P9 a00, a41, a32, a23, a14, a43, a34, a20, a11, a02, a31, a22, \ + a13, a04, a40, a24, a10, a01, a42, a33, a12, a03, a44, a30, a21 +#define P10 a00, a24, a43, a12, a31, a34, a03, a22, a41, a10, a13, a32, \ + a01, a20, a44, a42, a11, a30, a04, a23, a21, a40, a14, a33, a02 +#define P11 a00, a42, a34, a21, a13, a03, a40, a32, a24, a11, a01, a43, \ + a30, a22, a14, a04, a41, a33, a20, a12, a02, a44, a31, a23, a10 +#define P12 a00, a04, a03, a02, a01, a40, a44, a43, a42, a41, a30, a34, \ + a33, a32, a31, a20, a24, a23, a22, a21, a10, a14, a13, a12, a11 +#define P13 a00, a20, a40, a10, a30, a44, a14, a34, a04, a24, a33, a03, \ + a23, a43, a13, a22, a42, a12, a32, a02, a11, a31, a01, a21, a41 +#define P14 a00, a22, a44, a11, a33, a14, a31, a03, a20, a42, a23, a40, \ + a12, a34, a01, a32, a04, a21, a43, a10, a41, a13, a30, a02, a24 +#define P15 a00, a32, a14, a41, a23, a31, a13, a40, a22, a04, a12, a44, \ + a21, a03, a30, a43, a20, a02, a34, a11, a24, a01, a33, a10, a42 +#define P16 a00, a43, a31, a24, a12, a13, a01, a44, a32, a20, a21, a14, \ + a02, a40, a33, a34, a22, a10, a03, a41, a42, a30, a23, a11, a04 +#define P17 a00, a34, a13, a42, a21, a01, a30, a14, a43, a22, a02, a31, \ + a10, a44, a23, a03, a32, a11, a40, a24, a04, a33, a12, a41, a20 +#define P18 a00, a03, a01, a04, a02, a30, a33, a31, a34, a32, a10, a13, \ + a11, a14, a12, a40, a43, a41, a44, a42, a20, a23, a21, a24, a22 +#define P19 a00, a40, a30, a20, a10, a33, a23, a13, a03, a43, a11, a01, \ + a41, a31, a21, a44, a34, a24, a14, a04, a22, a12, a02, a42, a32 +#define P20 a00, a44, a33, a22, a11, a23, a12, a01, a40, a34, a41, a30, \ + a24, a13, a02, a14, a03, a42, a31, a20, a32, a21, a10, a04, a43 +#define P21 a00, a14, a23, a32, a41, a12, a21, a30, a44, a03, a24, a33, \ + a42, a01, a10, a31, a40, a04, a13, a22, a43, a02, a11, a20, a34 +#define P22 a00, a31, a12, a43, a24, a21, a02, a33, a14, a40, a42, a23, \ + a04, a30, a11, a13, a44, a20, a01, a32, a34, a10, a41, a22, a03 +#define P23 a00, a13, a21, a34, a42, a02, a10, a23, a31, a44, a04, a12, \ + a20, a33, a41, a01, a14, a22, a30, a43, a03, a11, a24, a32, a40 + +#define P1_TO_P0 do { \ + DECL64(t); \ + MOV64(t, a01); \ + MOV64(a01, a30); \ + MOV64(a30, a33); \ + MOV64(a33, a23); \ + MOV64(a23, a12); \ + MOV64(a12, a21); \ + MOV64(a21, a02); \ + MOV64(a02, a10); \ + MOV64(a10, a11); \ + MOV64(a11, a41); \ + MOV64(a41, a24); \ + MOV64(a24, a42); \ + MOV64(a42, a04); \ + MOV64(a04, a20); \ + MOV64(a20, a22); \ + MOV64(a22, a32); \ + MOV64(a32, a43); \ + MOV64(a43, a34); \ + MOV64(a34, a03); \ + MOV64(a03, a40); \ + MOV64(a40, a44); \ + MOV64(a44, a14); \ + MOV64(a14, a31); \ + MOV64(a31, a13); \ + MOV64(a13, t); \ + } while (0) + +#define P2_TO_P0 do { \ + DECL64(t); \ + MOV64(t, a01); \ + MOV64(a01, a33); \ + MOV64(a33, a12); \ + MOV64(a12, a02); \ + MOV64(a02, a11); \ + MOV64(a11, a24); \ + MOV64(a24, a04); \ + MOV64(a04, a22); \ + MOV64(a22, a43); \ + MOV64(a43, a03); \ + MOV64(a03, a44); \ + MOV64(a44, a31); \ + MOV64(a31, t); \ + MOV64(t, a10); \ + MOV64(a10, a41); \ + MOV64(a41, a42); \ + MOV64(a42, a20); \ + MOV64(a20, a32); \ + MOV64(a32, a34); \ + MOV64(a34, a40); \ + MOV64(a40, a14); \ + MOV64(a14, a13); \ + MOV64(a13, a30); \ + MOV64(a30, a23); \ + MOV64(a23, a21); \ + MOV64(a21, t); \ + } while (0) + +#define P4_TO_P0 do { \ + DECL64(t); \ + MOV64(t, a01); \ + MOV64(a01, a12); \ + MOV64(a12, a11); \ + MOV64(a11, a04); \ + MOV64(a04, a43); \ + MOV64(a43, a44); \ + MOV64(a44, t); \ + MOV64(t, a02); \ + MOV64(a02, a24); \ + MOV64(a24, a22); \ + MOV64(a22, a03); \ + MOV64(a03, a31); \ + MOV64(a31, a33); \ + MOV64(a33, t); \ + MOV64(t, a10); \ + MOV64(a10, a42); \ + MOV64(a42, a32); \ + MOV64(a32, a40); \ + MOV64(a40, a13); \ + MOV64(a13, a23); \ + MOV64(a23, t); \ + MOV64(t, a14); \ + MOV64(a14, a30); \ + MOV64(a30, a21); \ + MOV64(a21, a41); \ + MOV64(a41, a20); \ + MOV64(a20, a34); \ + MOV64(a34, t); \ + } while (0) + +#define P6_TO_P0 do { \ + DECL64(t); \ + MOV64(t, a01); \ + MOV64(a01, a02); \ + MOV64(a02, a04); \ + MOV64(a04, a03); \ + MOV64(a03, t); \ + MOV64(t, a10); \ + MOV64(a10, a20); \ + MOV64(a20, a40); \ + MOV64(a40, a30); \ + MOV64(a30, t); \ + MOV64(t, a11); \ + MOV64(a11, a22); \ + MOV64(a22, a44); \ + MOV64(a44, a33); \ + MOV64(a33, t); \ + MOV64(t, a12); \ + MOV64(a12, a24); \ + MOV64(a24, a43); \ + MOV64(a43, a31); \ + MOV64(a31, t); \ + MOV64(t, a13); \ + MOV64(a13, a21); \ + MOV64(a21, a42); \ + MOV64(a42, a34); \ + MOV64(a34, t); \ + MOV64(t, a14); \ + MOV64(a14, a23); \ + MOV64(a23, a41); \ + MOV64(a41, a32); \ + MOV64(a32, t); \ + } while (0) + +#define P8_TO_P0 do { \ + DECL64(t); \ + MOV64(t, a01); \ + MOV64(a01, a11); \ + MOV64(a11, a43); \ + MOV64(a43, t); \ + MOV64(t, a02); \ + MOV64(a02, a22); \ + MOV64(a22, a31); \ + MOV64(a31, t); \ + MOV64(t, a03); \ + MOV64(a03, a33); \ + MOV64(a33, a24); \ + MOV64(a24, t); \ + MOV64(t, a04); \ + MOV64(a04, a44); \ + MOV64(a44, a12); \ + MOV64(a12, t); \ + MOV64(t, a10); \ + MOV64(a10, a32); \ + MOV64(a32, a13); \ + MOV64(a13, t); \ + MOV64(t, a14); \ + MOV64(a14, a21); \ + MOV64(a21, a20); \ + MOV64(a20, t); \ + MOV64(t, a23); \ + MOV64(a23, a42); \ + MOV64(a42, a40); \ + MOV64(a40, t); \ + MOV64(t, a30); \ + MOV64(a30, a41); \ + MOV64(a41, a34); \ + MOV64(a34, t); \ + } while (0) + +#define P12_TO_P0 do { \ + DECL64(t); \ + MOV64(t, a01); \ + MOV64(a01, a04); \ + MOV64(a04, t); \ + MOV64(t, a02); \ + MOV64(a02, a03); \ + MOV64(a03, t); \ + MOV64(t, a10); \ + MOV64(a10, a40); \ + MOV64(a40, t); \ + MOV64(t, a11); \ + MOV64(a11, a44); \ + MOV64(a44, t); \ + MOV64(t, a12); \ + MOV64(a12, a43); \ + MOV64(a43, t); \ + MOV64(t, a13); \ + MOV64(a13, a42); \ + MOV64(a42, t); \ + MOV64(t, a14); \ + MOV64(a14, a41); \ + MOV64(a41, t); \ + MOV64(t, a20); \ + MOV64(a20, a30); \ + MOV64(a30, t); \ + MOV64(t, a21); \ + MOV64(a21, a34); \ + MOV64(a34, t); \ + MOV64(t, a22); \ + MOV64(a22, a33); \ + MOV64(a33, t); \ + MOV64(t, a23); \ + MOV64(a23, a32); \ + MOV64(a32, t); \ + MOV64(t, a24); \ + MOV64(a24, a31); \ + MOV64(a31, t); \ + } while (0) + +#define LPAR ( +#define RPAR ) + +#define KF_ELT(r, s, k) do { \ + THETA LPAR P ## r RPAR; \ + RHO LPAR P ## r RPAR; \ + KHI LPAR P ## s RPAR; \ + IOTA(k); \ + } while (0) + +#define DO(x) x + +#define KECCAK_F_1600 DO(KECCAK_F_1600_) + +#if SPH_KECCAK_UNROLL == 1 + +#define KECCAK_F_1600_ do { \ + int j; \ + for (j = 0; j < 24; j ++) { \ + KF_ELT( 0, 1, RC[j + 0]); \ + P1_TO_P0; \ + } \ + } while (0) + +#elif SPH_KECCAK_UNROLL == 2 + +#define KECCAK_F_1600_ do { \ + int j; \ + for (j = 0; j < 24; j += 2) { \ + KF_ELT( 0, 1, RC[j + 0]); \ + KF_ELT( 1, 2, RC[j + 1]); \ + P2_TO_P0; \ + } \ + } while (0) + +#elif SPH_KECCAK_UNROLL == 4 + +#define KECCAK_F_1600_ do { \ + int j; \ + for (j = 0; j < 24; j += 4) { \ + KF_ELT( 0, 1, RC[j + 0]); \ + KF_ELT( 1, 2, RC[j + 1]); \ + KF_ELT( 2, 3, RC[j + 2]); \ + KF_ELT( 3, 4, RC[j + 3]); \ + P4_TO_P0; \ + } \ + } while (0) + +#elif SPH_KECCAK_UNROLL == 6 + +#define KECCAK_F_1600_ do { \ + int j; \ + for (j = 0; j < 24; j += 6) { \ + KF_ELT( 0, 1, RC[j + 0]); \ + KF_ELT( 1, 2, RC[j + 1]); \ + KF_ELT( 2, 3, RC[j + 2]); \ + KF_ELT( 3, 4, RC[j + 3]); \ + KF_ELT( 4, 5, RC[j + 4]); \ + KF_ELT( 5, 6, RC[j + 5]); \ + P6_TO_P0; \ + } \ + } while (0) + +#elif SPH_KECCAK_UNROLL == 8 + +#define KECCAK_F_1600_ do { \ + int j; \ + for (j = 0; j < 24; j += 8) { \ + KF_ELT( 0, 1, RC[j + 0]); \ + KF_ELT( 1, 2, RC[j + 1]); \ + KF_ELT( 2, 3, RC[j + 2]); \ + KF_ELT( 3, 4, RC[j + 3]); \ + KF_ELT( 4, 5, RC[j + 4]); \ + KF_ELT( 5, 6, RC[j + 5]); \ + KF_ELT( 6, 7, RC[j + 6]); \ + KF_ELT( 7, 8, RC[j + 7]); \ + P8_TO_P0; \ + } \ + } while (0) + +#elif SPH_KECCAK_UNROLL == 12 + +#define KECCAK_F_1600_ do { \ + int j; \ + for (j = 0; j < 24; j += 12) { \ + KF_ELT( 0, 1, RC[j + 0]); \ + KF_ELT( 1, 2, RC[j + 1]); \ + KF_ELT( 2, 3, RC[j + 2]); \ + KF_ELT( 3, 4, RC[j + 3]); \ + KF_ELT( 4, 5, RC[j + 4]); \ + KF_ELT( 5, 6, RC[j + 5]); \ + KF_ELT( 6, 7, RC[j + 6]); \ + KF_ELT( 7, 8, RC[j + 7]); \ + KF_ELT( 8, 9, RC[j + 8]); \ + KF_ELT( 9, 10, RC[j + 9]); \ + KF_ELT(10, 11, RC[j + 10]); \ + KF_ELT(11, 12, RC[j + 11]); \ + P12_TO_P0; \ + } \ + } while (0) + +#elif SPH_KECCAK_UNROLL == 0 + +#define KECCAK_F_1600_ do { \ + KF_ELT( 0, 1, RC[ 0]); \ + KF_ELT( 1, 2, RC[ 1]); \ + KF_ELT( 2, 3, RC[ 2]); \ + KF_ELT( 3, 4, RC[ 3]); \ + KF_ELT( 4, 5, RC[ 4]); \ + KF_ELT( 5, 6, RC[ 5]); \ + KF_ELT( 6, 7, RC[ 6]); \ + KF_ELT( 7, 8, RC[ 7]); \ + KF_ELT( 8, 9, RC[ 8]); \ + KF_ELT( 9, 10, RC[ 9]); \ + KF_ELT(10, 11, RC[10]); \ + KF_ELT(11, 12, RC[11]); \ + KF_ELT(12, 13, RC[12]); \ + KF_ELT(13, 14, RC[13]); \ + KF_ELT(14, 15, RC[14]); \ + KF_ELT(15, 16, RC[15]); \ + KF_ELT(16, 17, RC[16]); \ + KF_ELT(17, 18, RC[17]); \ + KF_ELT(18, 19, RC[18]); \ + KF_ELT(19, 20, RC[19]); \ + KF_ELT(20, 21, RC[20]); \ + KF_ELT(21, 22, RC[21]); \ + KF_ELT(22, 23, RC[22]); \ + KF_ELT(23, 0, RC[23]); \ + } while (0) + +#else + +#error Unimplemented unroll count for Keccak. + +#endif + +static void +keccak_init(sph_keccak_context *kc, unsigned out_size) +{ + int i; + +#if SPH_KECCAK_64 + for (i = 0; i < 25; i ++) + kc->u.wide[i] = 0; + /* + * Initialization for the "lane complement". + */ + kc->u.wide[ 1] = SPH_C64(0xFFFFFFFFFFFFFFFF); + kc->u.wide[ 2] = SPH_C64(0xFFFFFFFFFFFFFFFF); + kc->u.wide[ 8] = SPH_C64(0xFFFFFFFFFFFFFFFF); + kc->u.wide[12] = SPH_C64(0xFFFFFFFFFFFFFFFF); + kc->u.wide[17] = SPH_C64(0xFFFFFFFFFFFFFFFF); + kc->u.wide[20] = SPH_C64(0xFFFFFFFFFFFFFFFF); +#else + + for (i = 0; i < 50; i ++) + kc->u.narrow[i] = 0; + /* + * Initialization for the "lane complement". + * Note: since we set to all-one full 64-bit words, + * interleaving (if applicable) is a no-op. + */ + kc->u.narrow[ 2] = SPH_C32(0xFFFFFFFF); + kc->u.narrow[ 3] = SPH_C32(0xFFFFFFFF); + kc->u.narrow[ 4] = SPH_C32(0xFFFFFFFF); + kc->u.narrow[ 5] = SPH_C32(0xFFFFFFFF); + kc->u.narrow[16] = SPH_C32(0xFFFFFFFF); + kc->u.narrow[17] = SPH_C32(0xFFFFFFFF); + kc->u.narrow[24] = SPH_C32(0xFFFFFFFF); + kc->u.narrow[25] = SPH_C32(0xFFFFFFFF); + kc->u.narrow[34] = SPH_C32(0xFFFFFFFF); + kc->u.narrow[35] = SPH_C32(0xFFFFFFFF); + kc->u.narrow[40] = SPH_C32(0xFFFFFFFF); + kc->u.narrow[41] = SPH_C32(0xFFFFFFFF); +#endif + kc->ptr = 0; + kc->lim = 200 - (out_size >> 2); +} + +static void +keccak_core(sph_keccak_context *kc, const void *data, size_t len, size_t lim) +{ + unsigned char *buf; + size_t ptr; + DECL_STATE + + buf = kc->buf; + ptr = kc->ptr; + + if (len < (lim - ptr)) { + memcpy(buf + ptr, data, len); + kc->ptr = ptr + len; + return; + } + + READ_STATE(kc); + while (len > 0) { + size_t clen; + + clen = (lim - ptr); + if (clen > len) + clen = len; + memcpy(buf + ptr, data, clen); + ptr += clen; + data = (const unsigned char *)data + clen; + len -= clen; + if (ptr == lim) { + INPUT_BUF(lim); + KECCAK_F_1600; + ptr = 0; + } + } + WRITE_STATE(kc); + kc->ptr = ptr; +} + +#if SPH_KECCAK_64 + +#define DEFCLOSE(d, lim) \ + static void keccak_close ## d( \ + sph_keccak_context *kc, unsigned ub, unsigned n, void *dst) \ + { \ + unsigned eb; \ + union { \ + unsigned char tmp[lim + 1]; \ + sph_u64 dummy; /* for alignment */ \ + } u; \ + size_t j; \ + \ + eb = (0x100 | (ub & 0xFF)) >> (8 - n); \ + if (kc->ptr == (lim - 1)) { \ + if (n == 7) { \ + u.tmp[0] = eb; \ + memset(u.tmp + 1, 0, lim - 1); \ + u.tmp[lim] = 0x80; \ + j = 1 + lim; \ + } else { \ + u.tmp[0] = eb | 0x80; \ + j = 1; \ + } \ + } else { \ + j = lim - kc->ptr; \ + u.tmp[0] = eb; \ + memset(u.tmp + 1, 0, j - 2); \ + u.tmp[j - 1] = 0x80; \ + } \ + keccak_core(kc, u.tmp, j, lim); \ + /* Finalize the "lane complement" */ \ + kc->u.wide[ 1] = ~kc->u.wide[ 1]; \ + kc->u.wide[ 2] = ~kc->u.wide[ 2]; \ + kc->u.wide[ 8] = ~kc->u.wide[ 8]; \ + kc->u.wide[12] = ~kc->u.wide[12]; \ + kc->u.wide[17] = ~kc->u.wide[17]; \ + kc->u.wide[20] = ~kc->u.wide[20]; \ + for (j = 0; j < d; j += 8) \ + sph_enc64le_aligned(u.tmp + j, kc->u.wide[j >> 3]); \ + memcpy(dst, u.tmp, d); \ + keccak_init(kc, (unsigned)d << 3); \ + } \ + +#else + +#define DEFCLOSE(d, lim) \ + static void keccak_close ## d( \ + sph_keccak_context *kc, unsigned ub, unsigned n, void *dst) \ + { \ + unsigned eb; \ + union { \ + unsigned char tmp[lim + 1]; \ + sph_u64 dummy; /* for alignment */ \ + } u; \ + size_t j; \ + \ + eb = (0x100 | (ub & 0xFF)) >> (8 - n); \ + if (kc->ptr == (lim - 1)) { \ + if (n == 7) { \ + u.tmp[0] = eb; \ + memset(u.tmp + 1, 0, lim - 1); \ + u.tmp[lim] = 0x80; \ + j = 1 + lim; \ + } else { \ + u.tmp[0] = eb | 0x80; \ + j = 1; \ + } \ + } else { \ + j = lim - kc->ptr; \ + u.tmp[0] = eb; \ + memset(u.tmp + 1, 0, j - 2); \ + u.tmp[j - 1] = 0x80; \ + } \ + keccak_core(kc, u.tmp, j, lim); \ + /* Finalize the "lane complement" */ \ + kc->u.narrow[ 2] = ~kc->u.narrow[ 2]; \ + kc->u.narrow[ 3] = ~kc->u.narrow[ 3]; \ + kc->u.narrow[ 4] = ~kc->u.narrow[ 4]; \ + kc->u.narrow[ 5] = ~kc->u.narrow[ 5]; \ + kc->u.narrow[16] = ~kc->u.narrow[16]; \ + kc->u.narrow[17] = ~kc->u.narrow[17]; \ + kc->u.narrow[24] = ~kc->u.narrow[24]; \ + kc->u.narrow[25] = ~kc->u.narrow[25]; \ + kc->u.narrow[34] = ~kc->u.narrow[34]; \ + kc->u.narrow[35] = ~kc->u.narrow[35]; \ + kc->u.narrow[40] = ~kc->u.narrow[40]; \ + kc->u.narrow[41] = ~kc->u.narrow[41]; \ + /* un-interleave */ \ + for (j = 0; j < 50; j += 2) \ + UNINTERLEAVE(kc->u.narrow[j], kc->u.narrow[j + 1]); \ + for (j = 0; j < d; j += 4) \ + sph_enc32le_aligned(u.tmp + j, kc->u.narrow[j >> 2]); \ + memcpy(dst, u.tmp, d); \ + keccak_init(kc, (unsigned)d << 3); \ + } \ + +#endif + +DEFCLOSE(28, 144) +DEFCLOSE(32, 136) +DEFCLOSE(48, 104) +DEFCLOSE(64, 72) + +/* see sph_keccak.h */ +void +sph_keccak224_init(void *cc) +{ + keccak_init(cc, 224); +} + +/* see sph_keccak.h */ +void +sph_keccak224(void *cc, const void *data, size_t len) +{ + keccak_core(cc, data, len, 144); +} + +/* see sph_keccak.h */ +void +sph_keccak224_close(void *cc, void *dst) +{ + sph_keccak224_addbits_and_close(cc, 0, 0, dst); +} + +/* see sph_keccak.h */ +void +sph_keccak224_addbits_and_close(void *cc, unsigned ub, unsigned n, void *dst) +{ + keccak_close28(cc, ub, n, dst); +} + +/* see sph_keccak.h */ +void +sph_keccak256_init(void *cc) +{ + keccak_init(cc, 256); +} + +/* see sph_keccak.h */ +void +sph_keccak256(void *cc, const void *data, size_t len) +{ + keccak_core(cc, data, len, 136); +} + +/* see sph_keccak.h */ +void +sph_keccak256_close(void *cc, void *dst) +{ + sph_keccak256_addbits_and_close(cc, 0, 0, dst); +} + +/* see sph_keccak.h */ +void +sph_keccak256_addbits_and_close(void *cc, unsigned ub, unsigned n, void *dst) +{ + keccak_close32(cc, ub, n, dst); +} + +/* see sph_keccak.h */ +void +sph_keccak384_init(void *cc) +{ + keccak_init(cc, 384); +} + +/* see sph_keccak.h */ +void +sph_keccak384(void *cc, const void *data, size_t len) +{ + keccak_core(cc, data, len, 104); +} + +/* see sph_keccak.h */ +void +sph_keccak384_close(void *cc, void *dst) +{ + sph_keccak384_addbits_and_close(cc, 0, 0, dst); +} + +/* see sph_keccak.h */ +void +sph_keccak384_addbits_and_close(void *cc, unsigned ub, unsigned n, void *dst) +{ + keccak_close48(cc, ub, n, dst); +} + +/* see sph_keccak.h */ +void +sph_keccak512_init(void *cc) +{ + keccak_init(cc, 512); +} + +/* see sph_keccak.h */ +void +sph_keccak512(void *cc, const void *data, size_t len) +{ + keccak_core(cc, data, len, 72); +} + +/* see sph_keccak.h */ +void +sph_keccak512_close(void *cc, void *dst) +{ + sph_keccak512_addbits_and_close(cc, 0, 0, dst); +} + +/* see sph_keccak.h */ +void +sph_keccak512_addbits_and_close(void *cc, unsigned ub, unsigned n, void *dst) +{ + keccak_close64(cc, ub, n, dst); +} + + +#ifdef __cplusplus +} +#endif diff --git a/src/kernel.cpp b/src/kernel.cpp new file mode 100644 index 0000000..c60fc8b --- /dev/null +++ b/src/kernel.cpp @@ -0,0 +1,432 @@ +// Copyright (c) 2012-2013 The PPCoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include + +#include "kernel.h" +#include "db.h" + +using namespace std; + +extern int nStakeMaxAge; +extern int nStakeTargetSpacing; + +// Modifier interval: time to elapse before new modifier is computed +// Set to 3-hour for production network and 20-minute for test network + +unsigned int nModifierInterval = MODIFIER_INTERVAL; + +// Hard checkpoints of stake modifiers to ensure they are deterministic +static std::map mapStakeModifierCheckpoints = + boost::assign::map_list_of + ( 0, 0x000000000e00670b ) + ; + +// Get time weight +int64 GetWeight(int64 nIntervalBeginning, int64 nIntervalEnd) +{ + // Kernel hash weight starts from 0 at the min age + // this change increases active coins participating the hash and helps + // to secure the network when proof-of-stake difficulty is low + + return min(nIntervalEnd - nIntervalBeginning - nStakeMinAge, (int64)nStakeMaxAge); +} + +// Get the last stake modifier and its generation time from a given block +static bool GetLastStakeModifier(const CBlockIndex* pindex, uint64& nStakeModifier, int64& nModifierTime) +{ + if (!pindex) + return error("GetLastStakeModifier: null pindex"); + while (pindex && pindex->pprev && !pindex->GeneratedStakeModifier()) + pindex = pindex->pprev; + if (!pindex->GeneratedStakeModifier()) + return error("GetLastStakeModifier: no generation at genesis block"); + nStakeModifier = pindex->nStakeModifier; + nModifierTime = pindex->GetBlockTime(); + return true; +} + +// Get selection interval section (in seconds) +static int64 GetStakeModifierSelectionIntervalSection(int nSection) +{ + assert (nSection >= 0 && nSection < 64); + int64 a = nModifierInterval * 63 / (63 + ((63 - nSection) * (MODIFIER_INTERVAL_RATIO - 1))); + return a; +} + +// Get stake modifier selection interval (in seconds) +static int64 GetStakeModifierSelectionInterval() +{ + int64 nSelectionInterval = 0; + for (int nSection=0; nSection<64; nSection++) + { + nSelectionInterval += GetStakeModifierSelectionIntervalSection(nSection); + } + return nSelectionInterval; +} + +// select a block from the candidate blocks in vSortedByTimestamp, excluding +// already selected blocks in vSelectedBlocks, and with timestamp up to +// nSelectionIntervalStop. +static bool SelectBlockFromCandidates( + vector >& vSortedByTimestamp, + map& mapSelectedBlocks, + int64 nSelectionIntervalStop, uint64 nStakeModifierPrev, + const CBlockIndex** pindexSelected) +{ + bool fSelected = false; + uint256 hashBest = 0; + *pindexSelected = (const CBlockIndex*) 0; + BOOST_FOREACH(const PAIRTYPE(int64, uint256)& item, vSortedByTimestamp) + { + if (!mapBlockIndex.count(item.second)) + return error("SelectBlockFromCandidates: failed to find block index for candidate block %s", item.second.ToString().c_str()); + const CBlockIndex* pindex = mapBlockIndex[item.second]; + if (fSelected && pindex->GetBlockTime() > nSelectionIntervalStop) + break; + if (mapSelectedBlocks.count(pindex->GetBlockHash()) > 0) + continue; + // compute the selection hash by hashing its proof-hash and the + // previous proof-of-stake modifier + uint256 hashProof = pindex->IsProofOfStake()? pindex->hashProofOfStake : pindex->GetBlockHash(); + CDataStream ss(SER_GETHASH, 0); + ss << hashProof << nStakeModifierPrev; + uint256 hashSelection = Hash(ss.begin(), ss.end()); + // the selection hash is divided by 2**32 so that proof-of-stake block + // is always favored over proof-of-work block. this is to preserve + // the energy efficiency property + if (pindex->IsProofOfStake()) + hashSelection >>= 32; + if (fSelected && hashSelection < hashBest) + { + hashBest = hashSelection; + *pindexSelected = (const CBlockIndex*) pindex; + } + else if (!fSelected) + { + fSelected = true; + hashBest = hashSelection; + *pindexSelected = (const CBlockIndex*) pindex; + } + } + if (fDebug && GetBoolArg("-printstakemodifier")) + printf("SelectBlockFromCandidates: selection hash=%s\n", hashBest.ToString().c_str()); + return fSelected; +} + +// Stake Modifier (hash modifier of proof-of-stake): +// The purpose of stake modifier is to prevent a txout (coin) owner from +// computing future proof-of-stake generated by this txout at the time +// of transaction confirmation. To meet kernel protocol, the txout +// must hash with a future stake modifier to generate the proof. +// Stake modifier consists of bits each of which is contributed from a +// selected block of a given block group in the past. +// The selection of a block is based on a hash of the block's proof-hash and +// the previous stake modifier. +// Stake modifier is recomputed at a fixed time interval instead of every +// block. This is to make it difficult for an attacker to gain control of +// additional bits in the stake modifier, even after generating a chain of +// blocks. +bool ComputeNextStakeModifier(const CBlockIndex* pindexPrev, uint64& nStakeModifier, bool& fGeneratedStakeModifier) +{ + nStakeModifier = 0; + fGeneratedStakeModifier = false; + if (!pindexPrev) + { + fGeneratedStakeModifier = true; + return true; // genesis block's modifier is 0 + } + // First find current stake modifier and its generation block time + // if it's not old enough, return the same stake modifier + int64 nModifierTime = 0; + if (!GetLastStakeModifier(pindexPrev, nStakeModifier, nModifierTime)) + return error("ComputeNextStakeModifier: unable to get last modifier"); + if (fDebug) + { + printf("ComputeNextStakeModifier: prev modifier=0x%016"PRI64x" time=%s\n", nStakeModifier, DateTimeStrFormat(nModifierTime).c_str()); + } + if (nModifierTime / nModifierInterval >= pindexPrev->GetBlockTime() / nModifierInterval) + return true; + + // Sort candidate blocks by timestamp + vector > vSortedByTimestamp; + vSortedByTimestamp.reserve(64 * nModifierInterval / nStakeTargetSpacing); + int64 nSelectionInterval = GetStakeModifierSelectionInterval(); + int64 nSelectionIntervalStart = (pindexPrev->GetBlockTime() / nModifierInterval) * nModifierInterval - nSelectionInterval; + const CBlockIndex* pindex = pindexPrev; + while (pindex && pindex->GetBlockTime() >= nSelectionIntervalStart) + { + vSortedByTimestamp.push_back(make_pair(pindex->GetBlockTime(), pindex->GetBlockHash())); + pindex = pindex->pprev; + } + int nHeightFirstCandidate = pindex ? (pindex->nHeight + 1) : 0; + reverse(vSortedByTimestamp.begin(), vSortedByTimestamp.end()); + sort(vSortedByTimestamp.begin(), vSortedByTimestamp.end()); + + // Select 64 blocks from candidate blocks to generate stake modifier + uint64 nStakeModifierNew = 0; + int64 nSelectionIntervalStop = nSelectionIntervalStart; + map mapSelectedBlocks; + for (int nRound=0; nRoundGetStakeEntropyBit()) << nRound); + // add the selected block from candidates to selected list + mapSelectedBlocks.insert(make_pair(pindex->GetBlockHash(), pindex)); + if (fDebug && GetBoolArg("-printstakemodifier")) + printf("ComputeNextStakeModifier: selected round %d stop=%s height=%d bit=%d\n", + nRound, DateTimeStrFormat(nSelectionIntervalStop).c_str(), pindex->nHeight, pindex->GetStakeEntropyBit()); + } + + // Print selection map for visualization of the selected blocks + if (fDebug && GetBoolArg("-printstakemodifier")) + { + string strSelectionMap = ""; + // '-' indicates proof-of-work blocks not selected + strSelectionMap.insert(0, pindexPrev->nHeight - nHeightFirstCandidate + 1, '-'); + pindex = pindexPrev; + while (pindex && pindex->nHeight >= nHeightFirstCandidate) + { + // '=' indicates proof-of-stake blocks not selected + if (pindex->IsProofOfStake()) + strSelectionMap.replace(pindex->nHeight - nHeightFirstCandidate, 1, "="); + pindex = pindex->pprev; + } + BOOST_FOREACH(const PAIRTYPE(uint256, const CBlockIndex*)& item, mapSelectedBlocks) + { + // 'S' indicates selected proof-of-stake blocks + // 'W' indicates selected proof-of-work blocks + strSelectionMap.replace(item.second->nHeight - nHeightFirstCandidate, 1, item.second->IsProofOfStake()? "S" : "W"); + } + printf("ComputeNextStakeModifier: selection height [%d, %d] map %s\n", nHeightFirstCandidate, pindexPrev->nHeight, strSelectionMap.c_str()); + } + if (fDebug) + { + printf("ComputeNextStakeModifier: new modifier=0x%016"PRI64x" time=%s\n", nStakeModifierNew, DateTimeStrFormat(pindexPrev->GetBlockTime()).c_str()); + } + + nStakeModifier = nStakeModifierNew; + fGeneratedStakeModifier = true; + return true; +} + +// The stake modifier used to hash for a stake kernel is chosen as the stake +// modifier about a selection interval later than the coin generating the kernel +static bool GetKernelStakeModifier(uint256 hashBlockFrom, uint64& nStakeModifier, int& nStakeModifierHeight, int64& nStakeModifierTime, bool fPrintProofOfStake) +{ + nStakeModifier = 0; + if (!mapBlockIndex.count(hashBlockFrom)) + return error("GetKernelStakeModifier() : block not indexed"); + const CBlockIndex* pindexFrom = mapBlockIndex[hashBlockFrom]; + nStakeModifierHeight = pindexFrom->nHeight; + nStakeModifierTime = pindexFrom->GetBlockTime(); + int64 nStakeModifierSelectionInterval = GetStakeModifierSelectionInterval(); + const CBlockIndex* pindex = pindexFrom; + + // loop to find the stake modifier later by a selection interval + while (nStakeModifierTime < pindexFrom->GetBlockTime() + nStakeModifierSelectionInterval) + { + if (!pindex->pnext) + { // reached best block; may happen if node is behind on block chain + if (fPrintProofOfStake || (pindex->GetBlockTime() + nStakeMinAge - nStakeModifierSelectionInterval > GetAdjustedTime())) + return error("GetKernelStakeModifier() : reached best block %s at height %d from block %s", + pindex->GetBlockHash().ToString().c_str(), pindex->nHeight, hashBlockFrom.ToString().c_str()); + else + { + if(fDebug) + printf(">> nStakeModifierTime = %"PRI64d", pindexFrom->GetBlockTime() = %"PRI64d", nStakeModifierSelectionInterval = %"PRI64d"\n", + nStakeModifierTime, pindexFrom->GetBlockTime(), nStakeModifierSelectionInterval); + + return false; + } + } + pindex = pindex->pnext; + if (pindex->GeneratedStakeModifier()) + { + nStakeModifierHeight = pindex->nHeight; + nStakeModifierTime = pindex->GetBlockTime(); + } + } + nStakeModifier = pindex->nStakeModifier; + return true; +} + +// triangles kernel protocol +// coinstake must meet hash target according to the protocol: +// kernel (input 0) must meet the formula +// hash(nStakeModifier + txPrev.block.nTime + txPrev.offset + txPrev.nTime + txPrev.vout.n + nTime) < bnTarget * nCoinDayWeight +// this ensures that the chance of getting a coinstake is proportional to the +// amount of coin age one owns. +// The reason this hash is chosen is the following: +// nStakeModifier: +// (v0.3) scrambles computation to make it very difficult to precompute +// future proof-of-stake at the time of the coin's confirmation +// (v0.2) nBits (deprecated): encodes all past block timestamps +// txPrev.block.nTime: prevent nodes from guessing a good timestamp to +// generate transaction for future advantage +// txPrev.offset: offset of txPrev inside block, to reduce the chance of +// nodes generating coinstake at the same time +// txPrev.nTime: reduce the chance of nodes generating coinstake at the same +// time +// txPrev.vout.n: output number of txPrev, to reduce the chance of nodes +// generating coinstake at the same time +// block/tx hash should not be used here as they can be generated in vast +// quantities so as to generate blocks faster, degrading the system back into +// a proof-of-work situation. +// +bool CheckStakeKernelHash(unsigned int nBits, const CBlock& blockFrom, unsigned int nTxPrevOffset, const CTransaction& txPrev, const COutPoint& prevout, unsigned int nTimeTx, uint256& hashProofOfStake, bool fPrintProofOfStake) +{ + if (nTimeTx < txPrev.nTime) // Transaction timestamp violation + return error("CheckStakeKernelHash() : nTime violation"); + + unsigned int nTimeBlockFrom = blockFrom.GetBlockTime(); + if (nTimeBlockFrom + nStakeMinAge > nTimeTx) // Min age requirement + return error("CheckStakeKernelHash() : min age violation"); + + CBigNum bnTargetPerCoinDay; + bnTargetPerCoinDay.SetCompact(nBits); + int64 nValueIn = txPrev.vout[prevout.n].nValue; + + // v0.3 protocol kernel hash weight starts from 0 at the min age + // this change increases active coins participating the hash and helps + // to secure the network when proof-of-stake difficulty is low + int64 nTimeWeight = min((int64)nTimeTx - txPrev.nTime, (int64)nStakeMaxAge) - nStakeMinAge; + CBigNum bnCoinDayWeight = CBigNum(nValueIn) * nTimeWeight / COIN / (24 * 60 * 60); + + // printf(">>> CheckStakeKernelHash: nTimeWeight = %"PRI64d"\n", nTimeWeight); + // Calculate hash + int boolean = 1337; + CDataStream ss(SER_GETHASH, 0); + uint64 nStakeModifier = 0; + int nStakeModifierHeight = 0; + int64 nStakeModifierTime = 0; + + if (!GetKernelStakeModifier(blockFrom.GetHash(), nStakeModifier, nStakeModifierHeight, nStakeModifierTime, fPrintProofOfStake)) + { + if(fDebug) + printf(">>> CheckStakeKernelHash: GetKernelStakeModifier return false\n"); + + return false; + } + if (boolean == 0) + { + printf(">>> CheckStakeKernelHash: passed GetKernelStakeModifier\n"); + ss << nStakeModifier; + } + + ss << nTimeBlockFrom << nTxPrevOffset << txPrev.nTime << prevout.n << nTimeTx; + hashProofOfStake = Hash(ss.begin(), ss.end()); + if (fPrintProofOfStake) + { + printf("CheckStakeKernelHash() : using modifier 0x%016"PRI64x" at height=%d timestamp=%s for block from height=%d timestamp=%s\n", + nStakeModifier, nStakeModifierHeight, + DateTimeStrFormat(nStakeModifierTime).c_str(), + mapBlockIndex[blockFrom.GetHash()]->nHeight, + DateTimeStrFormat(blockFrom.GetBlockTime()).c_str()); + printf("CheckStakeKernelHash() : check protocol=%s modifier=0x%016"PRI64x" nTimeBlockFrom=%u nTxPrevOffset=%u nTimeTxPrev=%u nPrevout=%u nTimeTx=%u hashProof=%s\n", + "0.3", + nStakeModifier, + nTimeBlockFrom, nTxPrevOffset, txPrev.nTime, prevout.n, nTimeTx, + hashProofOfStake.ToString().c_str()); + } + + // Now check if proof-of-stake hash meets target protocol + if (CBigNum(hashProofOfStake) > bnCoinDayWeight * bnTargetPerCoinDay) + { + if(fDebug) + { + printf(">>> bnCoinDayWeight = %s, bnTargetPerCoinDay=%s\n", + bnCoinDayWeight.ToString().c_str(), bnTargetPerCoinDay.ToString().c_str()); + printf(">>> CheckStakeKernelHash - hashProofOfStake too much\n"); + } + return false; + } + + + if (fDebug && !fPrintProofOfStake) + { + printf("CheckStakeKernelHash() : using modifier 0x%016"PRI64x" at height=%d timestamp=%s for block from height=%d timestamp=%s\n", + nStakeModifier, nStakeModifierHeight, + DateTimeStrFormat(nStakeModifierTime).c_str(), + mapBlockIndex[blockFrom.GetHash()]->nHeight, + DateTimeStrFormat(blockFrom.GetBlockTime()).c_str()); + printf("CheckStakeKernelHash() : pass protocol=%s modifier=0x%016"PRI64x" nTimeBlockFrom=%u nTxPrevOffset=%u nTimeTxPrev=%u nPrevout=%u nTimeTx=%u hashProof=%s\n", + "0.3", + nStakeModifier, + nTimeBlockFrom, nTxPrevOffset, txPrev.nTime, prevout.n, nTimeTx, + hashProofOfStake.ToString().c_str()); + } + return true; +} + +// Check kernel hash target and coinstake signature +bool CheckProofOfStake(const CTransaction& tx, unsigned int nBits, uint256& hashProofOfStake) +{ + if (!tx.IsCoinStake()) + return error("CheckProofOfStake() : called on non-coinstake %s", tx.GetHash().ToString().c_str()); + + // Kernel (input 0) must match the stake hash target per coin age (nBits) + const CTxIn& txin = tx.vin[0]; + + // First try finding the previous transaction in database + CTxDB txdb("r"); + CTransaction txPrev; + CTxIndex txindex; + if (!txPrev.ReadFromDisk(txdb, txin.prevout, txindex)) + return tx.DoS(1, error("CheckProofOfStake() : INFO: read txPrev failed")); // previous transaction not in main chain, may occur during initial download + txdb.Close(); + + // Verify signature + if (!VerifySignature(txPrev, tx, 0, true, 0)) + return tx.DoS(100, error("CheckProofOfStake() : VerifySignature failed on coinstake %s", tx.GetHash().ToString().c_str())); + + // Read block header + CBlock block; + if (!block.ReadFromDisk(txindex.pos.nFile, txindex.pos.nBlockPos, false)) + return fDebug? error("CheckProofOfStake() : read block failed") : false; // unable to read block of previous transaction + + if (!CheckStakeKernelHash(nBits, block, txindex.pos.nTxPos - txindex.pos.nBlockPos, txPrev, txin.prevout, tx.nTime, hashProofOfStake, fDebug)) + return tx.DoS(1, error("CheckProofOfStake() : INFO: check kernel failed on coinstake %s, hashProof=%s", tx.GetHash().ToString().c_str(), hashProofOfStake.ToString().c_str())); // may occur during initial download or if behind on block chain sync + + return true; +} + +// Check whether the coinstake timestamp meets protocol +bool CheckCoinStakeTimestamp(int64 nTimeBlock, int64 nTimeTx) +{ + // v0.3 protocol + return (nTimeBlock == nTimeTx); +} + +// Get stake modifier checksum +unsigned int GetStakeModifierChecksum(const CBlockIndex* pindex) +{ + assert (pindex->pprev || pindex->GetBlockHash() == (!fTestNet ? hashGenesisBlock : hashGenesisBlockTestNet)); + // Hash previous checksum with flags, hashProofOfStake and nStakeModifier + CDataStream ss(SER_GETHASH, 0); + if (pindex->pprev) + ss << pindex->pprev->nStakeModifierChecksum; + ss << pindex->nFlags << pindex->hashProofOfStake << pindex->nStakeModifier; + uint256 hashChecksum = Hash(ss.begin(), ss.end()); + hashChecksum >>= (256 - 32); + if(fDebug) + printf("stake checksum: 0x%016"PRI64x"", hashChecksum.Get64()); + return hashChecksum.Get64(); +} + +// Check stake modifier hard checkpoints +bool CheckStakeModifierCheckpoints(int nHeight, unsigned int nStakeModifierChecksum) +{ + if (fTestNet) return true; // Testnet has no checkpoints + if (mapStakeModifierCheckpoints.count(nHeight)) + { + return nStakeModifierChecksum == mapStakeModifierCheckpoints[nHeight]; + } + return true; +} diff --git a/src/kernel.h b/src/kernel.h new file mode 100644 index 0000000..1bc1f2d --- /dev/null +++ b/src/kernel.h @@ -0,0 +1,40 @@ +// Copyright (c) 2012-2013 The PPCoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. +#ifndef PPCOIN_KERNEL_H +#define PPCOIN_KERNEL_H + +#include "main.h" + +// MODIFIER_INTERVAL: time to elapse before new modifier is computed +static const unsigned int MODIFIER_INTERVAL = 20 * 60; // 20 minutes +extern unsigned int nModifierInterval; + +// MODIFIER_INTERVAL_RATIO: +// ratio of group interval length between the last group and the first group +static const int MODIFIER_INTERVAL_RATIO = 3; + +// Compute the hash modifier for proof-of-stake +bool ComputeNextStakeModifier(const CBlockIndex* pindexPrev, uint64& nStakeModifier, bool& fGeneratedStakeModifier); + +// Check whether stake kernel meets hash target +// Sets hashProofOfStake on success return +bool CheckStakeKernelHash(unsigned int nBits, const CBlock& blockFrom, unsigned int nTxPrevOffset, const CTransaction& txPrev, const COutPoint& prevout, unsigned int nTimeTx, uint256& hashProofOfStake, bool fPrintProofOfStake=false); + +// Check kernel hash target and coinstake signature +// Sets hashProofOfStake on success return +bool CheckProofOfStake(const CTransaction& tx, unsigned int nBits, uint256& hashProofOfStake); + +// Check whether the coinstake timestamp meets protocol +bool CheckCoinStakeTimestamp(int64 nTimeBlock, int64 nTimeTx); + +// Get stake modifier checksum +unsigned int GetStakeModifierChecksum(const CBlockIndex* pindex); + +// Check stake modifier hard checkpoints +bool CheckStakeModifierCheckpoints(int nHeight, unsigned int nStakeModifierChecksum); + +// Get time weight using supplied timestamps +int64 GetWeight(int64 nIntervalBeginning, int64 nIntervalEnd); + +#endif // PPCOIN_KERNEL_H diff --git a/src/key.cpp b/src/key.cpp new file mode 100644 index 0000000..23f3152 --- /dev/null +++ b/src/key.cpp @@ -0,0 +1,406 @@ +// Copyright (c) 2009-2012 The Bitcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include + +#include +#include + +#include "key.h" + +// Generate a private key from just the secret parameter +int EC_KEY_regenerate_key(EC_KEY *eckey, BIGNUM *priv_key) +{ + int ok = 0; + BN_CTX *ctx = NULL; + EC_POINT *pub_key = NULL; + + if (!eckey) return 0; + + const EC_GROUP *group = EC_KEY_get0_group(eckey); + + if ((ctx = BN_CTX_new()) == NULL) + goto err; + + pub_key = EC_POINT_new(group); + + if (pub_key == NULL) + goto err; + + if (!EC_POINT_mul(group, pub_key, priv_key, NULL, NULL, ctx)) + goto err; + + EC_KEY_set_private_key(eckey,priv_key); + EC_KEY_set_public_key(eckey,pub_key); + + ok = 1; + +err: + + if (pub_key) + EC_POINT_free(pub_key); + if (ctx != NULL) + BN_CTX_free(ctx); + + return(ok); +} + +// Perform ECDSA key recovery (see SEC1 4.1.6) for curves over (mod p)-fields +// recid selects which key is recovered +// if check is non-zero, additional checks are performed +int ECDSA_SIG_recover_key_GFp(EC_KEY *eckey, ECDSA_SIG *ecsig, const unsigned char *msg, int msglen, int recid, int check) +{ + if (!eckey) return 0; + + int ret = 0; + BN_CTX *ctx = NULL; + + BIGNUM *x = NULL; + BIGNUM *e = NULL; + BIGNUM *order = NULL; + BIGNUM *sor = NULL; + BIGNUM *eor = NULL; + BIGNUM *field = NULL; + EC_POINT *R = NULL; + EC_POINT *O = NULL; + EC_POINT *Q = NULL; + BIGNUM *rr = NULL; + BIGNUM *zero = NULL; + int n = 0; + int i = recid / 2; + + const EC_GROUP *group = EC_KEY_get0_group(eckey); + if ((ctx = BN_CTX_new()) == NULL) { ret = -1; goto err; } + BN_CTX_start(ctx); + order = BN_CTX_get(ctx); + if (!EC_GROUP_get_order(group, order, ctx)) { ret = -2; goto err; } + x = BN_CTX_get(ctx); + if (!BN_copy(x, order)) { ret=-1; goto err; } + if (!BN_mul_word(x, i)) { ret=-1; goto err; } + if (!BN_add(x, x, ecsig->r)) { ret=-1; goto err; } + field = BN_CTX_get(ctx); + if (!EC_GROUP_get_curve_GFp(group, field, NULL, NULL, ctx)) { ret=-2; goto err; } + if (BN_cmp(x, field) >= 0) { ret=0; goto err; } + if ((R = EC_POINT_new(group)) == NULL) { ret = -2; goto err; } + if (!EC_POINT_set_compressed_coordinates_GFp(group, R, x, recid % 2, ctx)) { ret=0; goto err; } + if (check) + { + if ((O = EC_POINT_new(group)) == NULL) { ret = -2; goto err; } + if (!EC_POINT_mul(group, O, NULL, R, order, ctx)) { ret=-2; goto err; } + if (!EC_POINT_is_at_infinity(group, O)) { ret = 0; goto err; } + } + if ((Q = EC_POINT_new(group)) == NULL) { ret = -2; goto err; } + n = EC_GROUP_get_degree(group); + e = BN_CTX_get(ctx); + if (!BN_bin2bn(msg, msglen, e)) { ret=-1; goto err; } + if (8*msglen > n) BN_rshift(e, e, 8-(n & 7)); + zero = BN_CTX_get(ctx); + if (!BN_zero(zero)) { ret=-1; goto err; } + if (!BN_mod_sub(e, zero, e, order, ctx)) { ret=-1; goto err; } + rr = BN_CTX_get(ctx); + if (!BN_mod_inverse(rr, ecsig->r, order, ctx)) { ret=-1; goto err; } + sor = BN_CTX_get(ctx); + if (!BN_mod_mul(sor, ecsig->s, rr, order, ctx)) { ret=-1; goto err; } + eor = BN_CTX_get(ctx); + if (!BN_mod_mul(eor, e, rr, order, ctx)) { ret=-1; goto err; } + if (!EC_POINT_mul(group, Q, eor, R, sor, ctx)) { ret=-2; goto err; } + if (!EC_KEY_set_public_key(eckey, Q)) { ret=-2; goto err; } + + ret = 1; + +err: + if (ctx) { + BN_CTX_end(ctx); + BN_CTX_free(ctx); + } + if (R != NULL) EC_POINT_free(R); + if (O != NULL) EC_POINT_free(O); + if (Q != NULL) EC_POINT_free(Q); + return ret; +} + +void CKey::SetCompressedPubKey() +{ + EC_KEY_set_conv_form(pkey, POINT_CONVERSION_COMPRESSED); + fCompressedPubKey = true; +} + +void CKey::Reset() +{ + fCompressedPubKey = false; + if (pkey != NULL) + EC_KEY_free(pkey); + pkey = EC_KEY_new_by_curve_name(NID_secp256k1); + if (pkey == NULL) + throw key_error("CKey::CKey() : EC_KEY_new_by_curve_name failed"); + fSet = false; +} + +CKey::CKey() +{ + pkey = NULL; + Reset(); +} + +CKey::CKey(const CKey& b) +{ + pkey = EC_KEY_dup(b.pkey); + if (pkey == NULL) + throw key_error("CKey::CKey(const CKey&) : EC_KEY_dup failed"); + fSet = b.fSet; +} + +CKey& CKey::operator=(const CKey& b) +{ + if (!EC_KEY_copy(pkey, b.pkey)) + throw key_error("CKey::operator=(const CKey&) : EC_KEY_copy failed"); + fSet = b.fSet; + return (*this); +} + +CKey::~CKey() +{ + EC_KEY_free(pkey); +} + +bool CKey::IsNull() const +{ + return !fSet; +} + +bool CKey::IsCompressed() const +{ + return fCompressedPubKey; +} + +void CKey::MakeNewKey(bool fCompressed) +{ + if (!EC_KEY_generate_key(pkey)) + throw key_error("CKey::MakeNewKey() : EC_KEY_generate_key failed"); + if (fCompressed) + SetCompressedPubKey(); + fSet = true; +} + +bool CKey::SetPrivKey(const CPrivKey& vchPrivKey) +{ + const unsigned char* pbegin = &vchPrivKey[0]; + if (d2i_ECPrivateKey(&pkey, &pbegin, vchPrivKey.size())) + { + // In testing, d2i_ECPrivateKey can return true + // but fill in pkey with a key that fails + // EC_KEY_check_key, so: + if (EC_KEY_check_key(pkey)) + { + fSet = true; + return true; + } + } + // If vchPrivKey data is bad d2i_ECPrivateKey() can + // leave pkey in a state where calling EC_KEY_free() + // crashes. To avoid that, set pkey to NULL and + // leak the memory (a leak is better than a crash) + pkey = NULL; + Reset(); + return false; +} + +bool CKey::SetSecret(const CSecret& vchSecret, bool fCompressed) +{ + EC_KEY_free(pkey); + pkey = EC_KEY_new_by_curve_name(NID_secp256k1); + if (pkey == NULL) + throw key_error("CKey::SetSecret() : EC_KEY_new_by_curve_name failed"); + if (vchSecret.size() != 32) + throw key_error("CKey::SetSecret() : secret must be 32 bytes"); + BIGNUM *bn = BN_bin2bn(&vchSecret[0],32,BN_new()); + if (bn == NULL) + throw key_error("CKey::SetSecret() : BN_bin2bn failed"); + if (!EC_KEY_regenerate_key(pkey,bn)) + { + BN_clear_free(bn); + throw key_error("CKey::SetSecret() : EC_KEY_regenerate_key failed"); + } + BN_clear_free(bn); + fSet = true; + if (fCompressed || fCompressedPubKey) + SetCompressedPubKey(); + return true; +} + +CSecret CKey::GetSecret(bool &fCompressed) const +{ + CSecret vchRet; + vchRet.resize(32); + const BIGNUM *bn = EC_KEY_get0_private_key(pkey); + int nBytes = BN_num_bytes(bn); + if (bn == NULL) + throw key_error("CKey::GetSecret() : EC_KEY_get0_private_key failed"); + int n=BN_bn2bin(bn,&vchRet[32 - nBytes]); + if (n != nBytes) + throw key_error("CKey::GetSecret(): BN_bn2bin failed"); + fCompressed = fCompressedPubKey; + return vchRet; +} + +CPrivKey CKey::GetPrivKey() const +{ + int nSize = i2d_ECPrivateKey(pkey, NULL); + if (!nSize) + throw key_error("CKey::GetPrivKey() : i2d_ECPrivateKey failed"); + CPrivKey vchPrivKey(nSize, 0); + unsigned char* pbegin = &vchPrivKey[0]; + if (i2d_ECPrivateKey(pkey, &pbegin) != nSize) + throw key_error("CKey::GetPrivKey() : i2d_ECPrivateKey returned unexpected size"); + return vchPrivKey; +} + +bool CKey::SetPubKey(const CPubKey& vchPubKey) +{ + const unsigned char* pbegin = &vchPubKey.vchPubKey[0]; + if (o2i_ECPublicKey(&pkey, &pbegin, vchPubKey.vchPubKey.size())) + { + fSet = true; + if (vchPubKey.vchPubKey.size() == 33) + SetCompressedPubKey(); + return true; + } + pkey = NULL; + Reset(); + return false; +} + +CPubKey CKey::GetPubKey() const +{ + int nSize = i2o_ECPublicKey(pkey, NULL); + if (!nSize) + throw key_error("CKey::GetPubKey() : i2o_ECPublicKey failed"); + std::vector vchPubKey(nSize, 0); + unsigned char* pbegin = &vchPubKey[0]; + if (i2o_ECPublicKey(pkey, &pbegin) != nSize) + throw key_error("CKey::GetPubKey() : i2o_ECPublicKey returned unexpected size"); + return CPubKey(vchPubKey); +} + +bool CKey::Sign(uint256 hash, std::vector& vchSig) +{ + unsigned int nSize = ECDSA_size(pkey); + vchSig.resize(nSize); // Make sure it is big enough + if (!ECDSA_sign(0, (unsigned char*)&hash, sizeof(hash), &vchSig[0], &nSize, pkey)) + { + vchSig.clear(); + return false; + } + vchSig.resize(nSize); // Shrink to fit actual size + return true; +} + +// create a compact signature (65 bytes), which allows reconstructing the used public key +// The format is one header byte, followed by two times 32 bytes for the serialized r and s values. +// The header byte: 0x1B = first key with even y, 0x1C = first key with odd y, +// 0x1D = second key with even y, 0x1E = second key with odd y +bool CKey::SignCompact(uint256 hash, std::vector& vchSig) +{ + bool fOk = false; + ECDSA_SIG *sig = ECDSA_do_sign((unsigned char*)&hash, sizeof(hash), pkey); + if (sig==NULL) + return false; + vchSig.clear(); + vchSig.resize(65,0); + int nBitsR = BN_num_bits(sig->r); + int nBitsS = BN_num_bits(sig->s); + if (nBitsR <= 256 && nBitsS <= 256) + { + int nRecId = -1; + for (int i=0; i<4; i++) + { + CKey keyRec; + keyRec.fSet = true; + if (fCompressedPubKey) + keyRec.SetCompressedPubKey(); + if (ECDSA_SIG_recover_key_GFp(keyRec.pkey, sig, (unsigned char*)&hash, sizeof(hash), i, 1) == 1) + if (keyRec.GetPubKey() == this->GetPubKey()) + { + nRecId = i; + break; + } + } + + if (nRecId == -1) + throw key_error("CKey::SignCompact() : unable to construct recoverable key"); + + vchSig[0] = nRecId+27+(fCompressedPubKey ? 4 : 0); + BN_bn2bin(sig->r,&vchSig[33-(nBitsR+7)/8]); + BN_bn2bin(sig->s,&vchSig[65-(nBitsS+7)/8]); + fOk = true; + } + ECDSA_SIG_free(sig); + return fOk; +} + +// reconstruct public key from a compact signature +// This is only slightly more CPU intensive than just verifying it. +// If this function succeeds, the recovered public key is guaranteed to be valid +// (the signature is a valid signature of the given data for that key) +bool CKey::SetCompactSignature(uint256 hash, const std::vector& vchSig) +{ + if (vchSig.size() != 65) + return false; + int nV = vchSig[0]; + if (nV<27 || nV>=35) + return false; + ECDSA_SIG *sig = ECDSA_SIG_new(); + BN_bin2bn(&vchSig[1],32,sig->r); + BN_bin2bn(&vchSig[33],32,sig->s); + + EC_KEY_free(pkey); + pkey = EC_KEY_new_by_curve_name(NID_secp256k1); + if (nV >= 31) + { + SetCompressedPubKey(); + nV -= 4; + } + if (ECDSA_SIG_recover_key_GFp(pkey, sig, (unsigned char*)&hash, sizeof(hash), nV - 27, 0) == 1) + { + fSet = true; + ECDSA_SIG_free(sig); + return true; + } + return false; +} + +bool CKey::Verify(uint256 hash, const std::vector& vchSig) +{ + // -1 = error, 0 = bad sig, 1 = good + if (ECDSA_verify(0, (unsigned char*)&hash, sizeof(hash), &vchSig[0], vchSig.size(), pkey) != 1) + return false; + + return true; +} + +bool CKey::VerifyCompact(uint256 hash, const std::vector& vchSig) +{ + CKey key; + if (!key.SetCompactSignature(hash, vchSig)) + return false; + if (GetPubKey() != key.GetPubKey()) + return false; + + return true; +} + +bool CKey::IsValid() +{ + if (!fSet) + return false; + + if (!EC_KEY_check_key(pkey)) + return false; + + bool fCompr; + CSecret secret = GetSecret(fCompr); + CKey key2; + key2.SetSecret(secret, fCompr); + return GetPubKey() == key2.GetPubKey(); +} diff --git a/src/key.h b/src/key.h new file mode 100644 index 0000000..c98f52e --- /dev/null +++ b/src/key.h @@ -0,0 +1,162 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2012 The Bitcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. +#ifndef BITCOIN_KEY_H +#define BITCOIN_KEY_H + +#include +#include + +#include "allocators.h" +#include "serialize.h" +#include "uint256.h" +#include "util.h" + +#include // for EC_KEY definition + +// secp160k1 +// const unsigned int PRIVATE_KEY_SIZE = 192; +// const unsigned int PUBLIC_KEY_SIZE = 41; +// const unsigned int SIGNATURE_SIZE = 48; +// +// secp192k1 +// const unsigned int PRIVATE_KEY_SIZE = 222; +// const unsigned int PUBLIC_KEY_SIZE = 49; +// const unsigned int SIGNATURE_SIZE = 57; +// +// secp224k1 +// const unsigned int PRIVATE_KEY_SIZE = 250; +// const unsigned int PUBLIC_KEY_SIZE = 57; +// const unsigned int SIGNATURE_SIZE = 66; +// +// secp256k1: +// const unsigned int PRIVATE_KEY_SIZE = 279; +// const unsigned int PUBLIC_KEY_SIZE = 65; +// const unsigned int SIGNATURE_SIZE = 72; +// +// see www.keylength.com +// script supports up to 75 for single byte push + +class key_error : public std::runtime_error +{ +public: + explicit key_error(const std::string& str) : std::runtime_error(str) {} +}; + +/** A reference to a CKey: the Hash160 of its serialized public key */ +class CKeyID : public uint160 +{ +public: + CKeyID() : uint160(0) { } + CKeyID(const uint160 &in) : uint160(in) { } +}; + +/** A reference to a CScript: the Hash160 of its serialization (see script.h) */ +class CScriptID : public uint160 +{ +public: + CScriptID() : uint160(0) { } + CScriptID(const uint160 &in) : uint160(in) { } +}; + +/** An encapsulated public key. */ +class CPubKey { +private: + std::vector vchPubKey; + friend class CKey; + +public: + CPubKey() { } + CPubKey(const std::vector &vchPubKeyIn) : vchPubKey(vchPubKeyIn) { } + friend bool operator==(const CPubKey &a, const CPubKey &b) { return a.vchPubKey == b.vchPubKey; } + friend bool operator!=(const CPubKey &a, const CPubKey &b) { return a.vchPubKey != b.vchPubKey; } + friend bool operator<(const CPubKey &a, const CPubKey &b) { return a.vchPubKey < b.vchPubKey; } + + IMPLEMENT_SERIALIZE( + READWRITE(vchPubKey); + ) + + CKeyID GetID() const { + return CKeyID(Hash160(vchPubKey)); + } + + uint256 GetHash() const { + return Hash(vchPubKey.begin(), vchPubKey.end()); + } + + bool IsValid() const { + return vchPubKey.size() == 33 || vchPubKey.size() == 65; + } + + bool IsCompressed() const { + return vchPubKey.size() == 33; + } + + std::vector Raw() const { + return vchPubKey; + } +}; + + +// secure_allocator is defined in allocators.h +// CPrivKey is a serialized private key, with all parameters included (279 bytes) +typedef std::vector > CPrivKey; +// CSecret is a serialization of just the secret parameter (32 bytes) +typedef std::vector > CSecret; + +/** An encapsulated OpenSSL Elliptic Curve key (public and/or private) */ +class CKey +{ +protected: + EC_KEY* pkey; + bool fSet; + bool fCompressedPubKey; + + void SetCompressedPubKey(); + +public: + + void Reset(); + + CKey(); + CKey(const CKey& b); + + CKey& operator=(const CKey& b); + + ~CKey(); + + bool IsNull() const; + bool IsCompressed() const; + + void MakeNewKey(bool fCompressed); + bool SetPrivKey(const CPrivKey& vchPrivKey); + bool SetSecret(const CSecret& vchSecret, bool fCompressed = false); + CSecret GetSecret(bool &fCompressed) const; + CPrivKey GetPrivKey() const; + bool SetPubKey(const CPubKey& vchPubKey); + CPubKey GetPubKey() const; + + bool Sign(uint256 hash, std::vector& vchSig); + + // create a compact signature (65 bytes), which allows reconstructing the used public key + // The format is one header byte, followed by two times 32 bytes for the serialized r and s values. + // The header byte: 0x1B = first key with even y, 0x1C = first key with odd y, + // 0x1D = second key with even y, 0x1E = second key with odd y + bool SignCompact(uint256 hash, std::vector& vchSig); + + // reconstruct public key from a compact signature + // This is only slightly more CPU intensive than just verifying it. + // If this function succeeds, the recovered public key is guaranteed to be valid + // (the signature is a valid signature of the given data for that key) + bool SetCompactSignature(uint256 hash, const std::vector& vchSig); + + bool Verify(uint256 hash, const std::vector& vchSig); + + // Verify a compact signature + bool VerifyCompact(uint256 hash, const std::vector& vchSig); + + bool IsValid(); +}; + +#endif diff --git a/src/keystore.cpp b/src/keystore.cpp new file mode 100644 index 0000000..e0cf805 --- /dev/null +++ b/src/keystore.cpp @@ -0,0 +1,221 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2012 The Bitcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "keystore.h" +#include "script.h" + +bool CKeyStore::GetPubKey(const CKeyID &address, CPubKey &vchPubKeyOut) const +{ + CKey key; + if (!GetKey(address, key)) + return false; + vchPubKeyOut = key.GetPubKey(); + return true; +} + +bool CBasicKeyStore::AddKey(const CKey& key) +{ + bool fCompressed = false; + CSecret secret = key.GetSecret(fCompressed); + { + LOCK(cs_KeyStore); + mapKeys[key.GetPubKey().GetID()] = make_pair(secret, fCompressed); + } + return true; +} + +bool CBasicKeyStore::AddCScript(const CScript& redeemScript) +{ + { + LOCK(cs_KeyStore); + mapScripts[redeemScript.GetID()] = redeemScript; + } + return true; +} + +bool CBasicKeyStore::HaveCScript(const CScriptID& hash) const +{ + bool result; + { + LOCK(cs_KeyStore); + result = (mapScripts.count(hash) > 0); + } + return result; +} + + +bool CBasicKeyStore::GetCScript(const CScriptID &hash, CScript& redeemScriptOut) const +{ + { + LOCK(cs_KeyStore); + ScriptMap::const_iterator mi = mapScripts.find(hash); + if (mi != mapScripts.end()) + { + redeemScriptOut = (*mi).second; + return true; + } + } + return false; +} + +bool CCryptoKeyStore::SetCrypted() +{ + { + LOCK(cs_KeyStore); + if (fUseCrypto) + return true; + if (!mapKeys.empty()) + return false; + fUseCrypto = true; + } + return true; +} + +bool CCryptoKeyStore::Lock() +{ + if (!SetCrypted()) + return false; + + { + LOCK(cs_KeyStore); + vMasterKey.clear(); + } + + NotifyStatusChanged(this); + return true; +} + +bool CCryptoKeyStore::Unlock(const CKeyingMaterial& vMasterKeyIn) +{ + { + LOCK(cs_KeyStore); + if (!SetCrypted()) + return false; + + CryptedKeyMap::const_iterator mi = mapCryptedKeys.begin(); + for (; mi != mapCryptedKeys.end(); ++mi) + { + const CPubKey &vchPubKey = (*mi).second.first; + const std::vector &vchCryptedSecret = (*mi).second.second; + CSecret vchSecret; + if(!DecryptSecret(vMasterKeyIn, vchCryptedSecret, vchPubKey.GetHash(), vchSecret)) + return false; + if (vchSecret.size() != 32) + return false; + CKey key; + key.SetPubKey(vchPubKey); + key.SetSecret(vchSecret); + if (key.GetPubKey() == vchPubKey) + break; + return false; + } + vMasterKey = vMasterKeyIn; + } + NotifyStatusChanged(this); + return true; +} + +bool CCryptoKeyStore::AddKey(const CKey& key) +{ + { + LOCK(cs_KeyStore); + if (!IsCrypted()) + return CBasicKeyStore::AddKey(key); + + if (IsLocked()) + return false; + + std::vector vchCryptedSecret; + CPubKey vchPubKey = key.GetPubKey(); + bool fCompressed; + if (!EncryptSecret(vMasterKey, key.GetSecret(fCompressed), vchPubKey.GetHash(), vchCryptedSecret)) + return false; + + if (!AddCryptedKey(key.GetPubKey(), vchCryptedSecret)) + return false; + } + return true; +} + + +bool CCryptoKeyStore::AddCryptedKey(const CPubKey &vchPubKey, const std::vector &vchCryptedSecret) +{ + { + LOCK(cs_KeyStore); + if (!SetCrypted()) + return false; + + mapCryptedKeys[vchPubKey.GetID()] = make_pair(vchPubKey, vchCryptedSecret); + } + return true; +} + +bool CCryptoKeyStore::GetKey(const CKeyID &address, CKey& keyOut) const +{ + { + LOCK(cs_KeyStore); + if (!IsCrypted()) + return CBasicKeyStore::GetKey(address, keyOut); + + CryptedKeyMap::const_iterator mi = mapCryptedKeys.find(address); + if (mi != mapCryptedKeys.end()) + { + const CPubKey &vchPubKey = (*mi).second.first; + const std::vector &vchCryptedSecret = (*mi).second.second; + CSecret vchSecret; + if (!DecryptSecret(vMasterKey, vchCryptedSecret, vchPubKey.GetHash(), vchSecret)) + return false; + if (vchSecret.size() != 32) + return false; + keyOut.SetPubKey(vchPubKey); + keyOut.SetSecret(vchSecret); + return true; + } + } + return false; +} + +bool CCryptoKeyStore::GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const +{ + { + LOCK(cs_KeyStore); + if (!IsCrypted()) + return CKeyStore::GetPubKey(address, vchPubKeyOut); + + CryptedKeyMap::const_iterator mi = mapCryptedKeys.find(address); + if (mi != mapCryptedKeys.end()) + { + vchPubKeyOut = (*mi).second.first; + return true; + } + } + return false; +} + +bool CCryptoKeyStore::EncryptKeys(CKeyingMaterial& vMasterKeyIn) +{ + { + LOCK(cs_KeyStore); + if (!mapCryptedKeys.empty() || IsCrypted()) + return false; + + fUseCrypto = true; + BOOST_FOREACH(KeyMap::value_type& mKey, mapKeys) + { + CKey key; + if (!key.SetSecret(mKey.second.first, mKey.second.second)) + return false; + const CPubKey vchPubKey = key.GetPubKey(); + std::vector vchCryptedSecret; + bool fCompressed; + if (!EncryptSecret(vMasterKeyIn, key.GetSecret(fCompressed), vchPubKey.GetHash(), vchCryptedSecret)) + return false; + if (!AddCryptedKey(vchPubKey, vchCryptedSecret)) + return false; + } + mapKeys.clear(); + } + return true; +} diff --git a/src/keystore.h b/src/keystore.h new file mode 100644 index 0000000..ab369bb --- /dev/null +++ b/src/keystore.h @@ -0,0 +1,184 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2012 The Bitcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. +#ifndef BITCOIN_KEYSTORE_H +#define BITCOIN_KEYSTORE_H + +#include "crypter.h" +#include "sync.h" +#include + +class CScript; + +/** A virtual base class for key stores */ +class CKeyStore +{ +protected: + mutable CCriticalSection cs_KeyStore; + +public: + virtual ~CKeyStore() {} + + // Add a key to the store. + virtual bool AddKey(const CKey& key) =0; + + // Check whether a key corresponding to a given address is present in the store. + virtual bool HaveKey(const CKeyID &address) const =0; + virtual bool GetKey(const CKeyID &address, CKey& keyOut) const =0; + virtual void GetKeys(std::set &setAddress) const =0; + virtual bool GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const; + + // Support for BIP 0013 : see https://en.bitcoin.it/wiki/BIP_0013 + virtual bool AddCScript(const CScript& redeemScript) =0; + virtual bool HaveCScript(const CScriptID &hash) const =0; + virtual bool GetCScript(const CScriptID &hash, CScript& redeemScriptOut) const =0; + + virtual bool GetSecret(const CKeyID &address, CSecret& vchSecret, bool &fCompressed) const + { + CKey key; + if (!GetKey(address, key)) + return false; + vchSecret = key.GetSecret(fCompressed); + return true; + } +}; + +typedef std::map > KeyMap; +typedef std::map ScriptMap; + +/** Basic key store, that keeps keys in an address->secret map */ +class CBasicKeyStore : public CKeyStore +{ +protected: + KeyMap mapKeys; + ScriptMap mapScripts; + +public: + bool AddKey(const CKey& key); + bool HaveKey(const CKeyID &address) const + { + bool result; + { + LOCK(cs_KeyStore); + result = (mapKeys.count(address) > 0); + } + return result; + } + void GetKeys(std::set &setAddress) const + { + setAddress.clear(); + { + LOCK(cs_KeyStore); + KeyMap::const_iterator mi = mapKeys.begin(); + while (mi != mapKeys.end()) + { + setAddress.insert((*mi).first); + mi++; + } + } + } + bool GetKey(const CKeyID &address, CKey &keyOut) const + { + { + LOCK(cs_KeyStore); + KeyMap::const_iterator mi = mapKeys.find(address); + if (mi != mapKeys.end()) + { + keyOut.Reset(); + keyOut.SetSecret((*mi).second.first, (*mi).second.second); + return true; + } + } + return false; + } + virtual bool AddCScript(const CScript& redeemScript); + virtual bool HaveCScript(const CScriptID &hash) const; + virtual bool GetCScript(const CScriptID &hash, CScript& redeemScriptOut) const; +}; + +typedef std::map > > CryptedKeyMap; + +/** Keystore which keeps the private keys encrypted. + * It derives from the basic key store, which is used if no encryption is active. + */ +class CCryptoKeyStore : public CBasicKeyStore +{ +private: + CryptedKeyMap mapCryptedKeys; + + CKeyingMaterial vMasterKey; + + // if fUseCrypto is true, mapKeys must be empty + // if fUseCrypto is false, vMasterKey must be empty + bool fUseCrypto; + +protected: + bool SetCrypted(); + + // will encrypt previously unencrypted keys + bool EncryptKeys(CKeyingMaterial& vMasterKeyIn); + + bool Unlock(const CKeyingMaterial& vMasterKeyIn); + +public: + CCryptoKeyStore() : fUseCrypto(false) + { + } + + bool IsCrypted() const + { + return fUseCrypto; + } + + bool IsLocked() const + { + if (!IsCrypted()) + return false; + bool result; + { + LOCK(cs_KeyStore); + result = vMasterKey.empty(); + } + return result; + } + + bool Lock(); + + virtual bool AddCryptedKey(const CPubKey &vchPubKey, const std::vector &vchCryptedSecret); + bool AddKey(const CKey& key); + bool HaveKey(const CKeyID &address) const + { + { + LOCK(cs_KeyStore); + if (!IsCrypted()) + return CBasicKeyStore::HaveKey(address); + return mapCryptedKeys.count(address) > 0; + } + return false; + } + bool GetKey(const CKeyID &address, CKey& keyOut) const; + bool GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const; + void GetKeys(std::set &setAddress) const + { + if (!IsCrypted()) + { + CBasicKeyStore::GetKeys(setAddress); + return; + } + setAddress.clear(); + CryptedKeyMap::const_iterator mi = mapCryptedKeys.begin(); + while (mi != mapCryptedKeys.end()) + { + setAddress.insert((*mi).first); + mi++; + } + } + + /* Wallet status (encrypted, locked) changed. + * Note: Called without locks held. + */ + boost::signals2::signal NotifyStatusChanged; +}; + +#endif diff --git a/src/luffa.c b/src/luffa.c new file mode 100644 index 0000000..024bcd8 --- /dev/null +++ b/src/luffa.c @@ -0,0 +1,1426 @@ +/* $Id: luffa.c 219 2010-06-08 17:24:41Z tp $ */ +/* + * Luffa implementation. + * + * ==========================(LICENSE BEGIN)============================ + * + * Copyright (c) 2007-2010 Projet RNRT SAPHIR + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * ===========================(LICENSE END)============================= + * + * @author Thomas Pornin + */ + +#include +#include +#include + +#include "sph_luffa.h" + +#ifdef __cplusplus +extern "C"{ +#endif + +#if SPH_64_TRUE && !defined SPH_LUFFA_PARALLEL +#define SPH_LUFFA_PARALLEL 1 +#endif + +#ifdef _MSC_VER +#pragma warning (disable: 4146) +#endif + +static const sph_u32 V_INIT[5][8] = { + { + SPH_C32(0x6d251e69), SPH_C32(0x44b051e0), + SPH_C32(0x4eaa6fb4), SPH_C32(0xdbf78465), + SPH_C32(0x6e292011), SPH_C32(0x90152df4), + SPH_C32(0xee058139), SPH_C32(0xdef610bb) + }, { + SPH_C32(0xc3b44b95), SPH_C32(0xd9d2f256), + SPH_C32(0x70eee9a0), SPH_C32(0xde099fa3), + SPH_C32(0x5d9b0557), SPH_C32(0x8fc944b3), + SPH_C32(0xcf1ccf0e), SPH_C32(0x746cd581) + }, { + SPH_C32(0xf7efc89d), SPH_C32(0x5dba5781), + SPH_C32(0x04016ce5), SPH_C32(0xad659c05), + SPH_C32(0x0306194f), SPH_C32(0x666d1836), + SPH_C32(0x24aa230a), SPH_C32(0x8b264ae7) + }, { + SPH_C32(0x858075d5), SPH_C32(0x36d79cce), + SPH_C32(0xe571f7d7), SPH_C32(0x204b1f67), + SPH_C32(0x35870c6a), SPH_C32(0x57e9e923), + SPH_C32(0x14bcb808), SPH_C32(0x7cde72ce) + }, { + SPH_C32(0x6c68e9be), SPH_C32(0x5ec41e22), + SPH_C32(0xc825b7c7), SPH_C32(0xaffb4363), + SPH_C32(0xf5df3999), SPH_C32(0x0fc688f1), + SPH_C32(0xb07224cc), SPH_C32(0x03e86cea) + } +}; + +static const sph_u32 RC00[8] = { + SPH_C32(0x303994a6), SPH_C32(0xc0e65299), + SPH_C32(0x6cc33a12), SPH_C32(0xdc56983e), + SPH_C32(0x1e00108f), SPH_C32(0x7800423d), + SPH_C32(0x8f5b7882), SPH_C32(0x96e1db12) +}; + +static const sph_u32 RC04[8] = { + SPH_C32(0xe0337818), SPH_C32(0x441ba90d), + SPH_C32(0x7f34d442), SPH_C32(0x9389217f), + SPH_C32(0xe5a8bce6), SPH_C32(0x5274baf4), + SPH_C32(0x26889ba7), SPH_C32(0x9a226e9d) +}; + +static const sph_u32 RC10[8] = { + SPH_C32(0xb6de10ed), SPH_C32(0x70f47aae), + SPH_C32(0x0707a3d4), SPH_C32(0x1c1e8f51), + SPH_C32(0x707a3d45), SPH_C32(0xaeb28562), + SPH_C32(0xbaca1589), SPH_C32(0x40a46f3e) +}; + +static const sph_u32 RC14[8] = { + SPH_C32(0x01685f3d), SPH_C32(0x05a17cf4), + SPH_C32(0xbd09caca), SPH_C32(0xf4272b28), + SPH_C32(0x144ae5cc), SPH_C32(0xfaa7ae2b), + SPH_C32(0x2e48f1c1), SPH_C32(0xb923c704) +}; + +#if SPH_LUFFA_PARALLEL + +static const sph_u64 RCW010[8] = { + SPH_C64(0xb6de10ed303994a6), SPH_C64(0x70f47aaec0e65299), + SPH_C64(0x0707a3d46cc33a12), SPH_C64(0x1c1e8f51dc56983e), + SPH_C64(0x707a3d451e00108f), SPH_C64(0xaeb285627800423d), + SPH_C64(0xbaca15898f5b7882), SPH_C64(0x40a46f3e96e1db12) +}; + +static const sph_u64 RCW014[8] = { + SPH_C64(0x01685f3de0337818), SPH_C64(0x05a17cf4441ba90d), + SPH_C64(0xbd09caca7f34d442), SPH_C64(0xf4272b289389217f), + SPH_C64(0x144ae5cce5a8bce6), SPH_C64(0xfaa7ae2b5274baf4), + SPH_C64(0x2e48f1c126889ba7), SPH_C64(0xb923c7049a226e9d) +}; + +#endif + +static const sph_u32 RC20[8] = { + SPH_C32(0xfc20d9d2), SPH_C32(0x34552e25), + SPH_C32(0x7ad8818f), SPH_C32(0x8438764a), + SPH_C32(0xbb6de032), SPH_C32(0xedb780c8), + SPH_C32(0xd9847356), SPH_C32(0xa2c78434) +}; + +static const sph_u32 RC24[8] = { + SPH_C32(0xe25e72c1), SPH_C32(0xe623bb72), + SPH_C32(0x5c58a4a4), SPH_C32(0x1e38e2e7), + SPH_C32(0x78e38b9d), SPH_C32(0x27586719), + SPH_C32(0x36eda57f), SPH_C32(0x703aace7) +}; + +static const sph_u32 RC30[8] = { + SPH_C32(0xb213afa5), SPH_C32(0xc84ebe95), + SPH_C32(0x4e608a22), SPH_C32(0x56d858fe), + SPH_C32(0x343b138f), SPH_C32(0xd0ec4e3d), + SPH_C32(0x2ceb4882), SPH_C32(0xb3ad2208) +}; + +static const sph_u32 RC34[8] = { + SPH_C32(0xe028c9bf), SPH_C32(0x44756f91), + SPH_C32(0x7e8fce32), SPH_C32(0x956548be), + SPH_C32(0xfe191be2), SPH_C32(0x3cb226e5), + SPH_C32(0x5944a28e), SPH_C32(0xa1c4c355) +}; + +#if SPH_LUFFA_PARALLEL + +static const sph_u64 RCW230[8] = { + SPH_C64(0xb213afa5fc20d9d2), SPH_C64(0xc84ebe9534552e25), + SPH_C64(0x4e608a227ad8818f), SPH_C64(0x56d858fe8438764a), + SPH_C64(0x343b138fbb6de032), SPH_C64(0xd0ec4e3dedb780c8), + SPH_C64(0x2ceb4882d9847356), SPH_C64(0xb3ad2208a2c78434) +}; + + +static const sph_u64 RCW234[8] = { + SPH_C64(0xe028c9bfe25e72c1), SPH_C64(0x44756f91e623bb72), + SPH_C64(0x7e8fce325c58a4a4), SPH_C64(0x956548be1e38e2e7), + SPH_C64(0xfe191be278e38b9d), SPH_C64(0x3cb226e527586719), + SPH_C64(0x5944a28e36eda57f), SPH_C64(0xa1c4c355703aace7) +}; + +#endif + +static const sph_u32 RC40[8] = { + SPH_C32(0xf0d2e9e3), SPH_C32(0xac11d7fa), + SPH_C32(0x1bcb66f2), SPH_C32(0x6f2d9bc9), + SPH_C32(0x78602649), SPH_C32(0x8edae952), + SPH_C32(0x3b6ba548), SPH_C32(0xedae9520) +}; + +static const sph_u32 RC44[8] = { + SPH_C32(0x5090d577), SPH_C32(0x2d1925ab), + SPH_C32(0xb46496ac), SPH_C32(0xd1925ab0), + SPH_C32(0x29131ab6), SPH_C32(0x0fc053c3), + SPH_C32(0x3f014f0c), SPH_C32(0xfc053c31) +}; + +#define DECL_TMP8(w) \ + sph_u32 w ## 0, w ## 1, w ## 2, w ## 3, w ## 4, w ## 5, w ## 6, w ## 7; + +#define M2(d, s) do { \ + sph_u32 tmp = s ## 7; \ + d ## 7 = s ## 6; \ + d ## 6 = s ## 5; \ + d ## 5 = s ## 4; \ + d ## 4 = s ## 3 ^ tmp; \ + d ## 3 = s ## 2 ^ tmp; \ + d ## 2 = s ## 1; \ + d ## 1 = s ## 0 ^ tmp; \ + d ## 0 = tmp; \ + } while (0) + +#define XOR(d, s1, s2) do { \ + d ## 0 = s1 ## 0 ^ s2 ## 0; \ + d ## 1 = s1 ## 1 ^ s2 ## 1; \ + d ## 2 = s1 ## 2 ^ s2 ## 2; \ + d ## 3 = s1 ## 3 ^ s2 ## 3; \ + d ## 4 = s1 ## 4 ^ s2 ## 4; \ + d ## 5 = s1 ## 5 ^ s2 ## 5; \ + d ## 6 = s1 ## 6 ^ s2 ## 6; \ + d ## 7 = s1 ## 7 ^ s2 ## 7; \ + } while (0) + +#if SPH_LUFFA_PARALLEL + +#define SUB_CRUMB_GEN(a0, a1, a2, a3, width) do { \ + sph_u ## width tmp; \ + tmp = (a0); \ + (a0) |= (a1); \ + (a2) ^= (a3); \ + (a1) = SPH_T ## width(~(a1)); \ + (a0) ^= (a3); \ + (a3) &= tmp; \ + (a1) ^= (a3); \ + (a3) ^= (a2); \ + (a2) &= (a0); \ + (a0) = SPH_T ## width(~(a0)); \ + (a2) ^= (a1); \ + (a1) |= (a3); \ + tmp ^= (a1); \ + (a3) ^= (a2); \ + (a2) &= (a1); \ + (a1) ^= (a0); \ + (a0) = tmp; \ + } while (0) + +#define SUB_CRUMB(a0, a1, a2, a3) SUB_CRUMB_GEN(a0, a1, a2, a3, 32) +#define SUB_CRUMBW(a0, a1, a2, a3) SUB_CRUMB_GEN(a0, a1, a2, a3, 64) + + +#if 0 + +#define ROL32W(x, n) SPH_T64( \ + (((x) << (n)) \ + & ~((SPH_C64(0xFFFFFFFF) >> (32 - (n))) << 32)) \ + | (((x) >> (32 - (n))) \ + & ~((SPH_C64(0xFFFFFFFF) >> (n)) << (n)))) + +#define MIX_WORDW(u, v) do { \ + (v) ^= (u); \ + (u) = ROL32W((u), 2) ^ (v); \ + (v) = ROL32W((v), 14) ^ (u); \ + (u) = ROL32W((u), 10) ^ (v); \ + (v) = ROL32W((v), 1); \ + } while (0) + +#endif + +#define MIX_WORDW(u, v) do { \ + sph_u32 ul, uh, vl, vh; \ + (v) ^= (u); \ + ul = SPH_T32((sph_u32)(u)); \ + uh = SPH_T32((sph_u32)((u) >> 32)); \ + vl = SPH_T32((sph_u32)(v)); \ + vh = SPH_T32((sph_u32)((v) >> 32)); \ + ul = SPH_ROTL32(ul, 2) ^ vl; \ + vl = SPH_ROTL32(vl, 14) ^ ul; \ + ul = SPH_ROTL32(ul, 10) ^ vl; \ + vl = SPH_ROTL32(vl, 1); \ + uh = SPH_ROTL32(uh, 2) ^ vh; \ + vh = SPH_ROTL32(vh, 14) ^ uh; \ + uh = SPH_ROTL32(uh, 10) ^ vh; \ + vh = SPH_ROTL32(vh, 1); \ + (u) = (sph_u64)ul | ((sph_u64)uh << 32); \ + (v) = (sph_u64)vl | ((sph_u64)vh << 32); \ + } while (0) + +#else + +#define SUB_CRUMB(a0, a1, a2, a3) do { \ + sph_u32 tmp; \ + tmp = (a0); \ + (a0) |= (a1); \ + (a2) ^= (a3); \ + (a1) = SPH_T32(~(a1)); \ + (a0) ^= (a3); \ + (a3) &= tmp; \ + (a1) ^= (a3); \ + (a3) ^= (a2); \ + (a2) &= (a0); \ + (a0) = SPH_T32(~(a0)); \ + (a2) ^= (a1); \ + (a1) |= (a3); \ + tmp ^= (a1); \ + (a3) ^= (a2); \ + (a2) &= (a1); \ + (a1) ^= (a0); \ + (a0) = tmp; \ + } while (0) + +#endif + +#define MIX_WORD(u, v) do { \ + (v) ^= (u); \ + (u) = SPH_ROTL32((u), 2) ^ (v); \ + (v) = SPH_ROTL32((v), 14) ^ (u); \ + (u) = SPH_ROTL32((u), 10) ^ (v); \ + (v) = SPH_ROTL32((v), 1); \ + } while (0) + +#define DECL_STATE3 \ + sph_u32 V00, V01, V02, V03, V04, V05, V06, V07; \ + sph_u32 V10, V11, V12, V13, V14, V15, V16, V17; \ + sph_u32 V20, V21, V22, V23, V24, V25, V26, V27; + +#define READ_STATE3(state) do { \ + V00 = (state)->V[0][0]; \ + V01 = (state)->V[0][1]; \ + V02 = (state)->V[0][2]; \ + V03 = (state)->V[0][3]; \ + V04 = (state)->V[0][4]; \ + V05 = (state)->V[0][5]; \ + V06 = (state)->V[0][6]; \ + V07 = (state)->V[0][7]; \ + V10 = (state)->V[1][0]; \ + V11 = (state)->V[1][1]; \ + V12 = (state)->V[1][2]; \ + V13 = (state)->V[1][3]; \ + V14 = (state)->V[1][4]; \ + V15 = (state)->V[1][5]; \ + V16 = (state)->V[1][6]; \ + V17 = (state)->V[1][7]; \ + V20 = (state)->V[2][0]; \ + V21 = (state)->V[2][1]; \ + V22 = (state)->V[2][2]; \ + V23 = (state)->V[2][3]; \ + V24 = (state)->V[2][4]; \ + V25 = (state)->V[2][5]; \ + V26 = (state)->V[2][6]; \ + V27 = (state)->V[2][7]; \ + } while (0) + +#define WRITE_STATE3(state) do { \ + (state)->V[0][0] = V00; \ + (state)->V[0][1] = V01; \ + (state)->V[0][2] = V02; \ + (state)->V[0][3] = V03; \ + (state)->V[0][4] = V04; \ + (state)->V[0][5] = V05; \ + (state)->V[0][6] = V06; \ + (state)->V[0][7] = V07; \ + (state)->V[1][0] = V10; \ + (state)->V[1][1] = V11; \ + (state)->V[1][2] = V12; \ + (state)->V[1][3] = V13; \ + (state)->V[1][4] = V14; \ + (state)->V[1][5] = V15; \ + (state)->V[1][6] = V16; \ + (state)->V[1][7] = V17; \ + (state)->V[2][0] = V20; \ + (state)->V[2][1] = V21; \ + (state)->V[2][2] = V22; \ + (state)->V[2][3] = V23; \ + (state)->V[2][4] = V24; \ + (state)->V[2][5] = V25; \ + (state)->V[2][6] = V26; \ + (state)->V[2][7] = V27; \ + } while (0) + +#define MI3 do { \ + DECL_TMP8(M) \ + DECL_TMP8(a) \ + M0 = sph_dec32be_aligned(buf + 0); \ + M1 = sph_dec32be_aligned(buf + 4); \ + M2 = sph_dec32be_aligned(buf + 8); \ + M3 = sph_dec32be_aligned(buf + 12); \ + M4 = sph_dec32be_aligned(buf + 16); \ + M5 = sph_dec32be_aligned(buf + 20); \ + M6 = sph_dec32be_aligned(buf + 24); \ + M7 = sph_dec32be_aligned(buf + 28); \ + XOR(a, V0, V1); \ + XOR(a, a, V2); \ + M2(a, a); \ + XOR(V0, a, V0); \ + XOR(V0, M, V0); \ + M2(M, M); \ + XOR(V1, a, V1); \ + XOR(V1, M, V1); \ + M2(M, M); \ + XOR(V2, a, V2); \ + XOR(V2, M, V2); \ + } while (0) + +#define TWEAK3 do { \ + V14 = SPH_ROTL32(V14, 1); \ + V15 = SPH_ROTL32(V15, 1); \ + V16 = SPH_ROTL32(V16, 1); \ + V17 = SPH_ROTL32(V17, 1); \ + V24 = SPH_ROTL32(V24, 2); \ + V25 = SPH_ROTL32(V25, 2); \ + V26 = SPH_ROTL32(V26, 2); \ + V27 = SPH_ROTL32(V27, 2); \ + } while (0) + +#if SPH_LUFFA_PARALLEL + +#define P3 do { \ + int r; \ + sph_u64 W0, W1, W2, W3, W4, W5, W6, W7; \ + TWEAK3; \ + W0 = (sph_u64)V00 | ((sph_u64)V10 << 32); \ + W1 = (sph_u64)V01 | ((sph_u64)V11 << 32); \ + W2 = (sph_u64)V02 | ((sph_u64)V12 << 32); \ + W3 = (sph_u64)V03 | ((sph_u64)V13 << 32); \ + W4 = (sph_u64)V04 | ((sph_u64)V14 << 32); \ + W5 = (sph_u64)V05 | ((sph_u64)V15 << 32); \ + W6 = (sph_u64)V06 | ((sph_u64)V16 << 32); \ + W7 = (sph_u64)V07 | ((sph_u64)V17 << 32); \ + for (r = 0; r < 8; r ++) { \ + SUB_CRUMBW(W0, W1, W2, W3); \ + SUB_CRUMBW(W5, W6, W7, W4); \ + MIX_WORDW(W0, W4); \ + MIX_WORDW(W1, W5); \ + MIX_WORDW(W2, W6); \ + MIX_WORDW(W3, W7); \ + W0 ^= RCW010[r]; \ + W4 ^= RCW014[r]; \ + } \ + V00 = SPH_T32((sph_u32)W0); \ + V10 = SPH_T32((sph_u32)(W0 >> 32)); \ + V01 = SPH_T32((sph_u32)W1); \ + V11 = SPH_T32((sph_u32)(W1 >> 32)); \ + V02 = SPH_T32((sph_u32)W2); \ + V12 = SPH_T32((sph_u32)(W2 >> 32)); \ + V03 = SPH_T32((sph_u32)W3); \ + V13 = SPH_T32((sph_u32)(W3 >> 32)); \ + V04 = SPH_T32((sph_u32)W4); \ + V14 = SPH_T32((sph_u32)(W4 >> 32)); \ + V05 = SPH_T32((sph_u32)W5); \ + V15 = SPH_T32((sph_u32)(W5 >> 32)); \ + V06 = SPH_T32((sph_u32)W6); \ + V16 = SPH_T32((sph_u32)(W6 >> 32)); \ + V07 = SPH_T32((sph_u32)W7); \ + V17 = SPH_T32((sph_u32)(W7 >> 32)); \ + for (r = 0; r < 8; r ++) { \ + SUB_CRUMB(V20, V21, V22, V23); \ + SUB_CRUMB(V25, V26, V27, V24); \ + MIX_WORD(V20, V24); \ + MIX_WORD(V21, V25); \ + MIX_WORD(V22, V26); \ + MIX_WORD(V23, V27); \ + V20 ^= RC20[r]; \ + V24 ^= RC24[r]; \ + } \ + } while (0) + +#else + +#define P3 do { \ + int r; \ + TWEAK3; \ + for (r = 0; r < 8; r ++) { \ + SUB_CRUMB(V00, V01, V02, V03); \ + SUB_CRUMB(V05, V06, V07, V04); \ + MIX_WORD(V00, V04); \ + MIX_WORD(V01, V05); \ + MIX_WORD(V02, V06); \ + MIX_WORD(V03, V07); \ + V00 ^= RC00[r]; \ + V04 ^= RC04[r]; \ + } \ + for (r = 0; r < 8; r ++) { \ + SUB_CRUMB(V10, V11, V12, V13); \ + SUB_CRUMB(V15, V16, V17, V14); \ + MIX_WORD(V10, V14); \ + MIX_WORD(V11, V15); \ + MIX_WORD(V12, V16); \ + MIX_WORD(V13, V17); \ + V10 ^= RC10[r]; \ + V14 ^= RC14[r]; \ + } \ + for (r = 0; r < 8; r ++) { \ + SUB_CRUMB(V20, V21, V22, V23); \ + SUB_CRUMB(V25, V26, V27, V24); \ + MIX_WORD(V20, V24); \ + MIX_WORD(V21, V25); \ + MIX_WORD(V22, V26); \ + MIX_WORD(V23, V27); \ + V20 ^= RC20[r]; \ + V24 ^= RC24[r]; \ + } \ + } while (0) + +#endif + +#define DECL_STATE4 \ + sph_u32 V00, V01, V02, V03, V04, V05, V06, V07; \ + sph_u32 V10, V11, V12, V13, V14, V15, V16, V17; \ + sph_u32 V20, V21, V22, V23, V24, V25, V26, V27; \ + sph_u32 V30, V31, V32, V33, V34, V35, V36, V37; + +#define READ_STATE4(state) do { \ + V00 = (state)->V[0][0]; \ + V01 = (state)->V[0][1]; \ + V02 = (state)->V[0][2]; \ + V03 = (state)->V[0][3]; \ + V04 = (state)->V[0][4]; \ + V05 = (state)->V[0][5]; \ + V06 = (state)->V[0][6]; \ + V07 = (state)->V[0][7]; \ + V10 = (state)->V[1][0]; \ + V11 = (state)->V[1][1]; \ + V12 = (state)->V[1][2]; \ + V13 = (state)->V[1][3]; \ + V14 = (state)->V[1][4]; \ + V15 = (state)->V[1][5]; \ + V16 = (state)->V[1][6]; \ + V17 = (state)->V[1][7]; \ + V20 = (state)->V[2][0]; \ + V21 = (state)->V[2][1]; \ + V22 = (state)->V[2][2]; \ + V23 = (state)->V[2][3]; \ + V24 = (state)->V[2][4]; \ + V25 = (state)->V[2][5]; \ + V26 = (state)->V[2][6]; \ + V27 = (state)->V[2][7]; \ + V30 = (state)->V[3][0]; \ + V31 = (state)->V[3][1]; \ + V32 = (state)->V[3][2]; \ + V33 = (state)->V[3][3]; \ + V34 = (state)->V[3][4]; \ + V35 = (state)->V[3][5]; \ + V36 = (state)->V[3][6]; \ + V37 = (state)->V[3][7]; \ + } while (0) + +#define WRITE_STATE4(state) do { \ + (state)->V[0][0] = V00; \ + (state)->V[0][1] = V01; \ + (state)->V[0][2] = V02; \ + (state)->V[0][3] = V03; \ + (state)->V[0][4] = V04; \ + (state)->V[0][5] = V05; \ + (state)->V[0][6] = V06; \ + (state)->V[0][7] = V07; \ + (state)->V[1][0] = V10; \ + (state)->V[1][1] = V11; \ + (state)->V[1][2] = V12; \ + (state)->V[1][3] = V13; \ + (state)->V[1][4] = V14; \ + (state)->V[1][5] = V15; \ + (state)->V[1][6] = V16; \ + (state)->V[1][7] = V17; \ + (state)->V[2][0] = V20; \ + (state)->V[2][1] = V21; \ + (state)->V[2][2] = V22; \ + (state)->V[2][3] = V23; \ + (state)->V[2][4] = V24; \ + (state)->V[2][5] = V25; \ + (state)->V[2][6] = V26; \ + (state)->V[2][7] = V27; \ + (state)->V[3][0] = V30; \ + (state)->V[3][1] = V31; \ + (state)->V[3][2] = V32; \ + (state)->V[3][3] = V33; \ + (state)->V[3][4] = V34; \ + (state)->V[3][5] = V35; \ + (state)->V[3][6] = V36; \ + (state)->V[3][7] = V37; \ + } while (0) + +#define MI4 do { \ + DECL_TMP8(M) \ + DECL_TMP8(a) \ + DECL_TMP8(b) \ + M0 = sph_dec32be_aligned(buf + 0); \ + M1 = sph_dec32be_aligned(buf + 4); \ + M2 = sph_dec32be_aligned(buf + 8); \ + M3 = sph_dec32be_aligned(buf + 12); \ + M4 = sph_dec32be_aligned(buf + 16); \ + M5 = sph_dec32be_aligned(buf + 20); \ + M6 = sph_dec32be_aligned(buf + 24); \ + M7 = sph_dec32be_aligned(buf + 28); \ + XOR(a, V0, V1); \ + XOR(b, V2, V3); \ + XOR(a, a, b); \ + M2(a, a); \ + XOR(V0, a, V0); \ + XOR(V1, a, V1); \ + XOR(V2, a, V2); \ + XOR(V3, a, V3); \ + M2(b, V0); \ + XOR(b, b, V3); \ + M2(V3, V3); \ + XOR(V3, V3, V2); \ + M2(V2, V2); \ + XOR(V2, V2, V1); \ + M2(V1, V1); \ + XOR(V1, V1, V0); \ + XOR(V0, b, M); \ + M2(M, M); \ + XOR(V1, V1, M); \ + M2(M, M); \ + XOR(V2, V2, M); \ + M2(M, M); \ + XOR(V3, V3, M); \ + } while (0) + +#define TWEAK4 do { \ + V14 = SPH_ROTL32(V14, 1); \ + V15 = SPH_ROTL32(V15, 1); \ + V16 = SPH_ROTL32(V16, 1); \ + V17 = SPH_ROTL32(V17, 1); \ + V24 = SPH_ROTL32(V24, 2); \ + V25 = SPH_ROTL32(V25, 2); \ + V26 = SPH_ROTL32(V26, 2); \ + V27 = SPH_ROTL32(V27, 2); \ + V34 = SPH_ROTL32(V34, 3); \ + V35 = SPH_ROTL32(V35, 3); \ + V36 = SPH_ROTL32(V36, 3); \ + V37 = SPH_ROTL32(V37, 3); \ + } while (0) + +#if SPH_LUFFA_PARALLEL + +#define P4 do { \ + int r; \ + sph_u64 W0, W1, W2, W3, W4, W5, W6, W7; \ + TWEAK4; \ + W0 = (sph_u64)V00 | ((sph_u64)V10 << 32); \ + W1 = (sph_u64)V01 | ((sph_u64)V11 << 32); \ + W2 = (sph_u64)V02 | ((sph_u64)V12 << 32); \ + W3 = (sph_u64)V03 | ((sph_u64)V13 << 32); \ + W4 = (sph_u64)V04 | ((sph_u64)V14 << 32); \ + W5 = (sph_u64)V05 | ((sph_u64)V15 << 32); \ + W6 = (sph_u64)V06 | ((sph_u64)V16 << 32); \ + W7 = (sph_u64)V07 | ((sph_u64)V17 << 32); \ + for (r = 0; r < 8; r ++) { \ + SUB_CRUMBW(W0, W1, W2, W3); \ + SUB_CRUMBW(W5, W6, W7, W4); \ + MIX_WORDW(W0, W4); \ + MIX_WORDW(W1, W5); \ + MIX_WORDW(W2, W6); \ + MIX_WORDW(W3, W7); \ + W0 ^= RCW010[r]; \ + W4 ^= RCW014[r]; \ + } \ + V00 = SPH_T32((sph_u32)W0); \ + V10 = SPH_T32((sph_u32)(W0 >> 32)); \ + V01 = SPH_T32((sph_u32)W1); \ + V11 = SPH_T32((sph_u32)(W1 >> 32)); \ + V02 = SPH_T32((sph_u32)W2); \ + V12 = SPH_T32((sph_u32)(W2 >> 32)); \ + V03 = SPH_T32((sph_u32)W3); \ + V13 = SPH_T32((sph_u32)(W3 >> 32)); \ + V04 = SPH_T32((sph_u32)W4); \ + V14 = SPH_T32((sph_u32)(W4 >> 32)); \ + V05 = SPH_T32((sph_u32)W5); \ + V15 = SPH_T32((sph_u32)(W5 >> 32)); \ + V06 = SPH_T32((sph_u32)W6); \ + V16 = SPH_T32((sph_u32)(W6 >> 32)); \ + V07 = SPH_T32((sph_u32)W7); \ + V17 = SPH_T32((sph_u32)(W7 >> 32)); \ + W0 = (sph_u64)V20 | ((sph_u64)V30 << 32); \ + W1 = (sph_u64)V21 | ((sph_u64)V31 << 32); \ + W2 = (sph_u64)V22 | ((sph_u64)V32 << 32); \ + W3 = (sph_u64)V23 | ((sph_u64)V33 << 32); \ + W4 = (sph_u64)V24 | ((sph_u64)V34 << 32); \ + W5 = (sph_u64)V25 | ((sph_u64)V35 << 32); \ + W6 = (sph_u64)V26 | ((sph_u64)V36 << 32); \ + W7 = (sph_u64)V27 | ((sph_u64)V37 << 32); \ + for (r = 0; r < 8; r ++) { \ + SUB_CRUMBW(W0, W1, W2, W3); \ + SUB_CRUMBW(W5, W6, W7, W4); \ + MIX_WORDW(W0, W4); \ + MIX_WORDW(W1, W5); \ + MIX_WORDW(W2, W6); \ + MIX_WORDW(W3, W7); \ + W0 ^= RCW230[r]; \ + W4 ^= RCW234[r]; \ + } \ + V20 = SPH_T32((sph_u32)W0); \ + V30 = SPH_T32((sph_u32)(W0 >> 32)); \ + V21 = SPH_T32((sph_u32)W1); \ + V31 = SPH_T32((sph_u32)(W1 >> 32)); \ + V22 = SPH_T32((sph_u32)W2); \ + V32 = SPH_T32((sph_u32)(W2 >> 32)); \ + V23 = SPH_T32((sph_u32)W3); \ + V33 = SPH_T32((sph_u32)(W3 >> 32)); \ + V24 = SPH_T32((sph_u32)W4); \ + V34 = SPH_T32((sph_u32)(W4 >> 32)); \ + V25 = SPH_T32((sph_u32)W5); \ + V35 = SPH_T32((sph_u32)(W5 >> 32)); \ + V26 = SPH_T32((sph_u32)W6); \ + V36 = SPH_T32((sph_u32)(W6 >> 32)); \ + V27 = SPH_T32((sph_u32)W7); \ + V37 = SPH_T32((sph_u32)(W7 >> 32)); \ + } while (0) + +#else + +#define P4 do { \ + int r; \ + TWEAK4; \ + for (r = 0; r < 8; r ++) { \ + SUB_CRUMB(V00, V01, V02, V03); \ + SUB_CRUMB(V05, V06, V07, V04); \ + MIX_WORD(V00, V04); \ + MIX_WORD(V01, V05); \ + MIX_WORD(V02, V06); \ + MIX_WORD(V03, V07); \ + V00 ^= RC00[r]; \ + V04 ^= RC04[r]; \ + } \ + for (r = 0; r < 8; r ++) { \ + SUB_CRUMB(V10, V11, V12, V13); \ + SUB_CRUMB(V15, V16, V17, V14); \ + MIX_WORD(V10, V14); \ + MIX_WORD(V11, V15); \ + MIX_WORD(V12, V16); \ + MIX_WORD(V13, V17); \ + V10 ^= RC10[r]; \ + V14 ^= RC14[r]; \ + } \ + for (r = 0; r < 8; r ++) { \ + SUB_CRUMB(V20, V21, V22, V23); \ + SUB_CRUMB(V25, V26, V27, V24); \ + MIX_WORD(V20, V24); \ + MIX_WORD(V21, V25); \ + MIX_WORD(V22, V26); \ + MIX_WORD(V23, V27); \ + V20 ^= RC20[r]; \ + V24 ^= RC24[r]; \ + } \ + for (r = 0; r < 8; r ++) { \ + SUB_CRUMB(V30, V31, V32, V33); \ + SUB_CRUMB(V35, V36, V37, V34); \ + MIX_WORD(V30, V34); \ + MIX_WORD(V31, V35); \ + MIX_WORD(V32, V36); \ + MIX_WORD(V33, V37); \ + V30 ^= RC30[r]; \ + V34 ^= RC34[r]; \ + } \ + } while (0) + +#endif + +#define DECL_STATE5 \ + sph_u32 V00, V01, V02, V03, V04, V05, V06, V07; \ + sph_u32 V10, V11, V12, V13, V14, V15, V16, V17; \ + sph_u32 V20, V21, V22, V23, V24, V25, V26, V27; \ + sph_u32 V30, V31, V32, V33, V34, V35, V36, V37; \ + sph_u32 V40, V41, V42, V43, V44, V45, V46, V47; + +#define READ_STATE5(state) do { \ + V00 = (state)->V[0][0]; \ + V01 = (state)->V[0][1]; \ + V02 = (state)->V[0][2]; \ + V03 = (state)->V[0][3]; \ + V04 = (state)->V[0][4]; \ + V05 = (state)->V[0][5]; \ + V06 = (state)->V[0][6]; \ + V07 = (state)->V[0][7]; \ + V10 = (state)->V[1][0]; \ + V11 = (state)->V[1][1]; \ + V12 = (state)->V[1][2]; \ + V13 = (state)->V[1][3]; \ + V14 = (state)->V[1][4]; \ + V15 = (state)->V[1][5]; \ + V16 = (state)->V[1][6]; \ + V17 = (state)->V[1][7]; \ + V20 = (state)->V[2][0]; \ + V21 = (state)->V[2][1]; \ + V22 = (state)->V[2][2]; \ + V23 = (state)->V[2][3]; \ + V24 = (state)->V[2][4]; \ + V25 = (state)->V[2][5]; \ + V26 = (state)->V[2][6]; \ + V27 = (state)->V[2][7]; \ + V30 = (state)->V[3][0]; \ + V31 = (state)->V[3][1]; \ + V32 = (state)->V[3][2]; \ + V33 = (state)->V[3][3]; \ + V34 = (state)->V[3][4]; \ + V35 = (state)->V[3][5]; \ + V36 = (state)->V[3][6]; \ + V37 = (state)->V[3][7]; \ + V40 = (state)->V[4][0]; \ + V41 = (state)->V[4][1]; \ + V42 = (state)->V[4][2]; \ + V43 = (state)->V[4][3]; \ + V44 = (state)->V[4][4]; \ + V45 = (state)->V[4][5]; \ + V46 = (state)->V[4][6]; \ + V47 = (state)->V[4][7]; \ + } while (0) + +#define WRITE_STATE5(state) do { \ + (state)->V[0][0] = V00; \ + (state)->V[0][1] = V01; \ + (state)->V[0][2] = V02; \ + (state)->V[0][3] = V03; \ + (state)->V[0][4] = V04; \ + (state)->V[0][5] = V05; \ + (state)->V[0][6] = V06; \ + (state)->V[0][7] = V07; \ + (state)->V[1][0] = V10; \ + (state)->V[1][1] = V11; \ + (state)->V[1][2] = V12; \ + (state)->V[1][3] = V13; \ + (state)->V[1][4] = V14; \ + (state)->V[1][5] = V15; \ + (state)->V[1][6] = V16; \ + (state)->V[1][7] = V17; \ + (state)->V[2][0] = V20; \ + (state)->V[2][1] = V21; \ + (state)->V[2][2] = V22; \ + (state)->V[2][3] = V23; \ + (state)->V[2][4] = V24; \ + (state)->V[2][5] = V25; \ + (state)->V[2][6] = V26; \ + (state)->V[2][7] = V27; \ + (state)->V[3][0] = V30; \ + (state)->V[3][1] = V31; \ + (state)->V[3][2] = V32; \ + (state)->V[3][3] = V33; \ + (state)->V[3][4] = V34; \ + (state)->V[3][5] = V35; \ + (state)->V[3][6] = V36; \ + (state)->V[3][7] = V37; \ + (state)->V[4][0] = V40; \ + (state)->V[4][1] = V41; \ + (state)->V[4][2] = V42; \ + (state)->V[4][3] = V43; \ + (state)->V[4][4] = V44; \ + (state)->V[4][5] = V45; \ + (state)->V[4][6] = V46; \ + (state)->V[4][7] = V47; \ + } while (0) + +#define MI5 do { \ + DECL_TMP8(M) \ + DECL_TMP8(a) \ + DECL_TMP8(b) \ + M0 = sph_dec32be_aligned(buf + 0); \ + M1 = sph_dec32be_aligned(buf + 4); \ + M2 = sph_dec32be_aligned(buf + 8); \ + M3 = sph_dec32be_aligned(buf + 12); \ + M4 = sph_dec32be_aligned(buf + 16); \ + M5 = sph_dec32be_aligned(buf + 20); \ + M6 = sph_dec32be_aligned(buf + 24); \ + M7 = sph_dec32be_aligned(buf + 28); \ + XOR(a, V0, V1); \ + XOR(b, V2, V3); \ + XOR(a, a, b); \ + XOR(a, a, V4); \ + M2(a, a); \ + XOR(V0, a, V0); \ + XOR(V1, a, V1); \ + XOR(V2, a, V2); \ + XOR(V3, a, V3); \ + XOR(V4, a, V4); \ + M2(b, V0); \ + XOR(b, b, V1); \ + M2(V1, V1); \ + XOR(V1, V1, V2); \ + M2(V2, V2); \ + XOR(V2, V2, V3); \ + M2(V3, V3); \ + XOR(V3, V3, V4); \ + M2(V4, V4); \ + XOR(V4, V4, V0); \ + M2(V0, b); \ + XOR(V0, V0, V4); \ + M2(V4, V4); \ + XOR(V4, V4, V3); \ + M2(V3, V3); \ + XOR(V3, V3, V2); \ + M2(V2, V2); \ + XOR(V2, V2, V1); \ + M2(V1, V1); \ + XOR(V1, V1, b); \ + XOR(V0, V0, M); \ + M2(M, M); \ + XOR(V1, V1, M); \ + M2(M, M); \ + XOR(V2, V2, M); \ + M2(M, M); \ + XOR(V3, V3, M); \ + M2(M, M); \ + XOR(V4, V4, M); \ + } while (0) + +#define TWEAK5 do { \ + V14 = SPH_ROTL32(V14, 1); \ + V15 = SPH_ROTL32(V15, 1); \ + V16 = SPH_ROTL32(V16, 1); \ + V17 = SPH_ROTL32(V17, 1); \ + V24 = SPH_ROTL32(V24, 2); \ + V25 = SPH_ROTL32(V25, 2); \ + V26 = SPH_ROTL32(V26, 2); \ + V27 = SPH_ROTL32(V27, 2); \ + V34 = SPH_ROTL32(V34, 3); \ + V35 = SPH_ROTL32(V35, 3); \ + V36 = SPH_ROTL32(V36, 3); \ + V37 = SPH_ROTL32(V37, 3); \ + V44 = SPH_ROTL32(V44, 4); \ + V45 = SPH_ROTL32(V45, 4); \ + V46 = SPH_ROTL32(V46, 4); \ + V47 = SPH_ROTL32(V47, 4); \ + } while (0) + +#if SPH_LUFFA_PARALLEL + +#define P5 do { \ + int r; \ + sph_u64 W0, W1, W2, W3, W4, W5, W6, W7; \ + TWEAK5; \ + W0 = (sph_u64)V00 | ((sph_u64)V10 << 32); \ + W1 = (sph_u64)V01 | ((sph_u64)V11 << 32); \ + W2 = (sph_u64)V02 | ((sph_u64)V12 << 32); \ + W3 = (sph_u64)V03 | ((sph_u64)V13 << 32); \ + W4 = (sph_u64)V04 | ((sph_u64)V14 << 32); \ + W5 = (sph_u64)V05 | ((sph_u64)V15 << 32); \ + W6 = (sph_u64)V06 | ((sph_u64)V16 << 32); \ + W7 = (sph_u64)V07 | ((sph_u64)V17 << 32); \ + for (r = 0; r < 8; r ++) { \ + SUB_CRUMBW(W0, W1, W2, W3); \ + SUB_CRUMBW(W5, W6, W7, W4); \ + MIX_WORDW(W0, W4); \ + MIX_WORDW(W1, W5); \ + MIX_WORDW(W2, W6); \ + MIX_WORDW(W3, W7); \ + W0 ^= RCW010[r]; \ + W4 ^= RCW014[r]; \ + } \ + V00 = SPH_T32((sph_u32)W0); \ + V10 = SPH_T32((sph_u32)(W0 >> 32)); \ + V01 = SPH_T32((sph_u32)W1); \ + V11 = SPH_T32((sph_u32)(W1 >> 32)); \ + V02 = SPH_T32((sph_u32)W2); \ + V12 = SPH_T32((sph_u32)(W2 >> 32)); \ + V03 = SPH_T32((sph_u32)W3); \ + V13 = SPH_T32((sph_u32)(W3 >> 32)); \ + V04 = SPH_T32((sph_u32)W4); \ + V14 = SPH_T32((sph_u32)(W4 >> 32)); \ + V05 = SPH_T32((sph_u32)W5); \ + V15 = SPH_T32((sph_u32)(W5 >> 32)); \ + V06 = SPH_T32((sph_u32)W6); \ + V16 = SPH_T32((sph_u32)(W6 >> 32)); \ + V07 = SPH_T32((sph_u32)W7); \ + V17 = SPH_T32((sph_u32)(W7 >> 32)); \ + W0 = (sph_u64)V20 | ((sph_u64)V30 << 32); \ + W1 = (sph_u64)V21 | ((sph_u64)V31 << 32); \ + W2 = (sph_u64)V22 | ((sph_u64)V32 << 32); \ + W3 = (sph_u64)V23 | ((sph_u64)V33 << 32); \ + W4 = (sph_u64)V24 | ((sph_u64)V34 << 32); \ + W5 = (sph_u64)V25 | ((sph_u64)V35 << 32); \ + W6 = (sph_u64)V26 | ((sph_u64)V36 << 32); \ + W7 = (sph_u64)V27 | ((sph_u64)V37 << 32); \ + for (r = 0; r < 8; r ++) { \ + SUB_CRUMBW(W0, W1, W2, W3); \ + SUB_CRUMBW(W5, W6, W7, W4); \ + MIX_WORDW(W0, W4); \ + MIX_WORDW(W1, W5); \ + MIX_WORDW(W2, W6); \ + MIX_WORDW(W3, W7); \ + W0 ^= RCW230[r]; \ + W4 ^= RCW234[r]; \ + } \ + V20 = SPH_T32((sph_u32)W0); \ + V30 = SPH_T32((sph_u32)(W0 >> 32)); \ + V21 = SPH_T32((sph_u32)W1); \ + V31 = SPH_T32((sph_u32)(W1 >> 32)); \ + V22 = SPH_T32((sph_u32)W2); \ + V32 = SPH_T32((sph_u32)(W2 >> 32)); \ + V23 = SPH_T32((sph_u32)W3); \ + V33 = SPH_T32((sph_u32)(W3 >> 32)); \ + V24 = SPH_T32((sph_u32)W4); \ + V34 = SPH_T32((sph_u32)(W4 >> 32)); \ + V25 = SPH_T32((sph_u32)W5); \ + V35 = SPH_T32((sph_u32)(W5 >> 32)); \ + V26 = SPH_T32((sph_u32)W6); \ + V36 = SPH_T32((sph_u32)(W6 >> 32)); \ + V27 = SPH_T32((sph_u32)W7); \ + V37 = SPH_T32((sph_u32)(W7 >> 32)); \ + for (r = 0; r < 8; r ++) { \ + SUB_CRUMB(V40, V41, V42, V43); \ + SUB_CRUMB(V45, V46, V47, V44); \ + MIX_WORD(V40, V44); \ + MIX_WORD(V41, V45); \ + MIX_WORD(V42, V46); \ + MIX_WORD(V43, V47); \ + V40 ^= RC40[r]; \ + V44 ^= RC44[r]; \ + } \ + } while (0) + +#else + +#define P5 do { \ + int r; \ + TWEAK5; \ + for (r = 0; r < 8; r ++) { \ + SUB_CRUMB(V00, V01, V02, V03); \ + SUB_CRUMB(V05, V06, V07, V04); \ + MIX_WORD(V00, V04); \ + MIX_WORD(V01, V05); \ + MIX_WORD(V02, V06); \ + MIX_WORD(V03, V07); \ + V00 ^= RC00[r]; \ + V04 ^= RC04[r]; \ + } \ + for (r = 0; r < 8; r ++) { \ + SUB_CRUMB(V10, V11, V12, V13); \ + SUB_CRUMB(V15, V16, V17, V14); \ + MIX_WORD(V10, V14); \ + MIX_WORD(V11, V15); \ + MIX_WORD(V12, V16); \ + MIX_WORD(V13, V17); \ + V10 ^= RC10[r]; \ + V14 ^= RC14[r]; \ + } \ + for (r = 0; r < 8; r ++) { \ + SUB_CRUMB(V20, V21, V22, V23); \ + SUB_CRUMB(V25, V26, V27, V24); \ + MIX_WORD(V20, V24); \ + MIX_WORD(V21, V25); \ + MIX_WORD(V22, V26); \ + MIX_WORD(V23, V27); \ + V20 ^= RC20[r]; \ + V24 ^= RC24[r]; \ + } \ + for (r = 0; r < 8; r ++) { \ + SUB_CRUMB(V30, V31, V32, V33); \ + SUB_CRUMB(V35, V36, V37, V34); \ + MIX_WORD(V30, V34); \ + MIX_WORD(V31, V35); \ + MIX_WORD(V32, V36); \ + MIX_WORD(V33, V37); \ + V30 ^= RC30[r]; \ + V34 ^= RC34[r]; \ + } \ + for (r = 0; r < 8; r ++) { \ + SUB_CRUMB(V40, V41, V42, V43); \ + SUB_CRUMB(V45, V46, V47, V44); \ + MIX_WORD(V40, V44); \ + MIX_WORD(V41, V45); \ + MIX_WORD(V42, V46); \ + MIX_WORD(V43, V47); \ + V40 ^= RC40[r]; \ + V44 ^= RC44[r]; \ + } \ + } while (0) + +#endif + +static void +luffa3(sph_luffa224_context *sc, const void *data, size_t len) +{ + unsigned char *buf; + size_t ptr; + DECL_STATE3 + + buf = sc->buf; + ptr = sc->ptr; + if (len < (sizeof sc->buf) - ptr) { + memcpy(buf + ptr, data, len); + ptr += len; + sc->ptr = ptr; + return; + } + + READ_STATE3(sc); + while (len > 0) { + size_t clen; + + clen = (sizeof sc->buf) - ptr; + if (clen > len) + clen = len; + memcpy(buf + ptr, data, clen); + ptr += clen; + data = (const unsigned char *)data + clen; + len -= clen; + if (ptr == sizeof sc->buf) { + MI3; + P3; + ptr = 0; + } + } + WRITE_STATE3(sc); + sc->ptr = ptr; +} + +static void +luffa3_close(sph_luffa224_context *sc, unsigned ub, unsigned n, + void *dst, unsigned out_size_w32) +{ + unsigned char *buf, *out; + size_t ptr; + unsigned z; + int i; + DECL_STATE3 + + buf = sc->buf; + ptr = sc->ptr; + z = 0x80 >> n; + buf[ptr ++] = ((ub & -z) | z) & 0xFF; + memset(buf + ptr, 0, (sizeof sc->buf) - ptr); + READ_STATE3(sc); + for (i = 0; i < 2; i ++) { + MI3; + P3; + memset(buf, 0, sizeof sc->buf); + } + out = dst; + sph_enc32be(out + 0, V00 ^ V10 ^ V20); + sph_enc32be(out + 4, V01 ^ V11 ^ V21); + sph_enc32be(out + 8, V02 ^ V12 ^ V22); + sph_enc32be(out + 12, V03 ^ V13 ^ V23); + sph_enc32be(out + 16, V04 ^ V14 ^ V24); + sph_enc32be(out + 20, V05 ^ V15 ^ V25); + sph_enc32be(out + 24, V06 ^ V16 ^ V26); + if (out_size_w32 > 7) + sph_enc32be(out + 28, V07 ^ V17 ^ V27); +} + +static void +luffa4(sph_luffa384_context *sc, const void *data, size_t len) +{ + unsigned char *buf; + size_t ptr; + DECL_STATE4 + + buf = sc->buf; + ptr = sc->ptr; + if (len < (sizeof sc->buf) - ptr) { + memcpy(buf + ptr, data, len); + ptr += len; + sc->ptr = ptr; + return; + } + + READ_STATE4(sc); + while (len > 0) { + size_t clen; + + clen = (sizeof sc->buf) - ptr; + if (clen > len) + clen = len; + memcpy(buf + ptr, data, clen); + ptr += clen; + data = (const unsigned char *)data + clen; + len -= clen; + if (ptr == sizeof sc->buf) { + MI4; + P4; + ptr = 0; + } + } + WRITE_STATE4(sc); + sc->ptr = ptr; +} + +static void +luffa4_close(sph_luffa384_context *sc, unsigned ub, unsigned n, void *dst) +{ + unsigned char *buf, *out; + size_t ptr; + unsigned z; + int i; + DECL_STATE4 + + buf = sc->buf; + ptr = sc->ptr; + out = dst; + z = 0x80 >> n; + buf[ptr ++] = ((ub & -z) | z) & 0xFF; + memset(buf + ptr, 0, (sizeof sc->buf) - ptr); + READ_STATE4(sc); + for (i = 0; i < 3; i ++) { + MI4; + P4; + switch (i) { + case 0: + memset(buf, 0, sizeof sc->buf); + break; + case 1: + sph_enc32be(out + 0, V00 ^ V10 ^ V20 ^ V30); + sph_enc32be(out + 4, V01 ^ V11 ^ V21 ^ V31); + sph_enc32be(out + 8, V02 ^ V12 ^ V22 ^ V32); + sph_enc32be(out + 12, V03 ^ V13 ^ V23 ^ V33); + sph_enc32be(out + 16, V04 ^ V14 ^ V24 ^ V34); + sph_enc32be(out + 20, V05 ^ V15 ^ V25 ^ V35); + sph_enc32be(out + 24, V06 ^ V16 ^ V26 ^ V36); + sph_enc32be(out + 28, V07 ^ V17 ^ V27 ^ V37); + break; + case 2: + sph_enc32be(out + 32, V00 ^ V10 ^ V20 ^ V30); + sph_enc32be(out + 36, V01 ^ V11 ^ V21 ^ V31); + sph_enc32be(out + 40, V02 ^ V12 ^ V22 ^ V32); + sph_enc32be(out + 44, V03 ^ V13 ^ V23 ^ V33); + break; + } + } +} + +static void +luffa5(sph_luffa512_context *sc, const void *data, size_t len) +{ + unsigned char *buf; + size_t ptr; + DECL_STATE5 + + buf = sc->buf; + ptr = sc->ptr; + if (len < (sizeof sc->buf) - ptr) { + memcpy(buf + ptr, data, len); + ptr += len; + sc->ptr = ptr; + return; + } + + READ_STATE5(sc); + while (len > 0) { + size_t clen; + + clen = (sizeof sc->buf) - ptr; + if (clen > len) + clen = len; + memcpy(buf + ptr, data, clen); + ptr += clen; + data = (const unsigned char *)data + clen; + len -= clen; + if (ptr == sizeof sc->buf) { + MI5; + P5; + ptr = 0; + } + } + WRITE_STATE5(sc); + sc->ptr = ptr; +} + +static void +luffa5_close(sph_luffa512_context *sc, unsigned ub, unsigned n, void *dst) +{ + unsigned char *buf, *out; + size_t ptr; + unsigned z; + int i; + DECL_STATE5 + + buf = sc->buf; + ptr = sc->ptr; + out = dst; + z = 0x80 >> n; + buf[ptr ++] = ((ub & -z) | z) & 0xFF; + memset(buf + ptr, 0, (sizeof sc->buf) - ptr); + READ_STATE5(sc); + for (i = 0; i < 3; i ++) { + MI5; + P5; + switch (i) { + case 0: + memset(buf, 0, sizeof sc->buf); + break; + case 1: + sph_enc32be(out + 0, V00 ^ V10 ^ V20 ^ V30 ^ V40); + sph_enc32be(out + 4, V01 ^ V11 ^ V21 ^ V31 ^ V41); + sph_enc32be(out + 8, V02 ^ V12 ^ V22 ^ V32 ^ V42); + sph_enc32be(out + 12, V03 ^ V13 ^ V23 ^ V33 ^ V43); + sph_enc32be(out + 16, V04 ^ V14 ^ V24 ^ V34 ^ V44); + sph_enc32be(out + 20, V05 ^ V15 ^ V25 ^ V35 ^ V45); + sph_enc32be(out + 24, V06 ^ V16 ^ V26 ^ V36 ^ V46); + sph_enc32be(out + 28, V07 ^ V17 ^ V27 ^ V37 ^ V47); + break; + case 2: + sph_enc32be(out + 32, V00 ^ V10 ^ V20 ^ V30 ^ V40); + sph_enc32be(out + 36, V01 ^ V11 ^ V21 ^ V31 ^ V41); + sph_enc32be(out + 40, V02 ^ V12 ^ V22 ^ V32 ^ V42); + sph_enc32be(out + 44, V03 ^ V13 ^ V23 ^ V33 ^ V43); + sph_enc32be(out + 48, V04 ^ V14 ^ V24 ^ V34 ^ V44); + sph_enc32be(out + 52, V05 ^ V15 ^ V25 ^ V35 ^ V45); + sph_enc32be(out + 56, V06 ^ V16 ^ V26 ^ V36 ^ V46); + sph_enc32be(out + 60, V07 ^ V17 ^ V27 ^ V37 ^ V47); + break; + } + } +} + +/* see sph_luffa.h */ +void +sph_luffa224_init(void *cc) +{ + sph_luffa224_context *sc; + + sc = cc; + memcpy(sc->V, V_INIT, sizeof(sc->V)); + sc->ptr = 0; +} + +/* see sph_luffa.h */ +void +sph_luffa224(void *cc, const void *data, size_t len) +{ + luffa3(cc, data, len); +} + +/* see sph_luffa.h */ +void +sph_luffa224_close(void *cc, void *dst) +{ + sph_luffa224_addbits_and_close(cc, 0, 0, dst); +} + +/* see sph_luffa.h */ +void +sph_luffa224_addbits_and_close(void *cc, unsigned ub, unsigned n, void *dst) +{ + luffa3_close(cc, ub, n, dst, 7); + sph_luffa224_init(cc); +} + +/* see sph_luffa.h */ +void +sph_luffa256_init(void *cc) +{ + sph_luffa256_context *sc; + + sc = cc; + memcpy(sc->V, V_INIT, sizeof(sc->V)); + sc->ptr = 0; +} + +/* see sph_luffa.h */ +void +sph_luffa256(void *cc, const void *data, size_t len) +{ + luffa3(cc, data, len); +} + +/* see sph_luffa.h */ +void +sph_luffa256_close(void *cc, void *dst) +{ + sph_luffa256_addbits_and_close(cc, 0, 0, dst); +} + +/* see sph_luffa.h */ +void +sph_luffa256_addbits_and_close(void *cc, unsigned ub, unsigned n, void *dst) +{ + luffa3_close(cc, ub, n, dst, 8); + sph_luffa256_init(cc); +} + +/* see sph_luffa.h */ +void +sph_luffa384_init(void *cc) +{ + sph_luffa384_context *sc; + + sc = cc; + memcpy(sc->V, V_INIT, sizeof(sc->V)); + sc->ptr = 0; +} + +/* see sph_luffa.h */ +void +sph_luffa384(void *cc, const void *data, size_t len) +{ + luffa4(cc, data, len); +} + +/* see sph_luffa.h */ +void +sph_luffa384_close(void *cc, void *dst) +{ + sph_luffa384_addbits_and_close(cc, 0, 0, dst); +} + +/* see sph_luffa.h */ +void +sph_luffa384_addbits_and_close(void *cc, unsigned ub, unsigned n, void *dst) +{ + luffa4_close(cc, ub, n, dst); + sph_luffa384_init(cc); +} + +/* see sph_luffa.h */ +void +sph_luffa512_init(void *cc) +{ + sph_luffa512_context *sc; + + sc = cc; + memcpy(sc->V, V_INIT, sizeof(sc->V)); + sc->ptr = 0; +} + +/* see sph_luffa.h */ +void +sph_luffa512(void *cc, const void *data, size_t len) +{ + luffa5(cc, data, len); +} + +/* see sph_luffa.h */ +void +sph_luffa512_close(void *cc, void *dst) +{ + sph_luffa512_addbits_and_close(cc, 0, 0, dst); +} + +/* see sph_luffa.h */ +void +sph_luffa512_addbits_and_close(void *cc, unsigned ub, unsigned n, void *dst) +{ + luffa5_close(cc, ub, n, dst); + sph_luffa512_init(cc); +} + +#ifdef __cplusplus +} +#endif diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..b988414 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,4507 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2012 The Bitcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "alert.h" +#include "checkpoints.h" +#include "db.h" +#include "net.h" +#include "init.h" +#include "ui_interface.h" +#include "kernel.h" +#include +#include +#include +#include +#include + +using namespace std; +using namespace boost; + +// +// Global state +// + +CCriticalSection cs_setpwalletRegistered; +set setpwalletRegistered; + +CCriticalSection cs_main; + +CTxMemPool mempool; +unsigned int nTransactionsUpdated = 0; + +map mapBlockIndex; +set > setStakeSeen; +uint256 hashGenesisBlock = hashGenesisBlockOfficial; +static CBigNum bnProofOfWorkLimit(~uint256(0) >> 8); +static CBigNum bnProofOfStakeLimit(~uint256(0) >> 8); + +static CBigNum bnProofOfWorkLimitTestNet(~uint256(0) >> 8); +static CBigNum bnProofOfStakeLimitTestNet(~uint256(0) >> 8); + +unsigned int nStakeMinAge = 60 * 60 * 3; +unsigned int nStakeMaxAge = 60 * 60 * 12; +unsigned int nStakeTargetSpacing = 60; + +int64 nChainStartTime = 1405500418; +int nCoinbaseMaturity = 33; +CBlockIndex* pindexGenesisBlock = NULL; +int nBestHeight = -1; +CBigNum bnBestChainTrust = 0; +CBigNum bnBestInvalidTrust = 0; +uint256 hashBestChain = 0; +CBlockIndex* pindexBest = NULL; +int64 nTimeBestReceived = 0; + +CMedianFilter cPeerBlockCounts(5, 0); // Amount of blocks that other nodes claim to have + +map mapOrphanBlocks; +multimap mapOrphanBlocksByPrev; +set > setStakeSeenOrphan; +map mapProofOfStake; + +map mapOrphanTransactions; +map > mapOrphanTransactionsByPrev; + +// Constant stuff for coinbase transactions we create: +CScript COINBASE_FLAGS; + +const string strMessageMagic = "Triangles Signed Message:\n"; + +double dHashesPerSec; +int64 nHPSTimerStart; + +// Settings +int64 nTransactionFee = MIN_TX_FEE; + + +////////////////////////////////////////////////////////////////////////////// +// +// dispatching functions +// + +// These functions dispatch to one or all registered wallets + + +void RegisterWallet(CWallet* pwalletIn) +{ + { + LOCK(cs_setpwalletRegistered); + setpwalletRegistered.insert(pwalletIn); + } +} + +void UnregisterWallet(CWallet* pwalletIn) +{ + { + LOCK(cs_setpwalletRegistered); + setpwalletRegistered.erase(pwalletIn); + } +} + +// check whether the passed transaction is from us +bool static IsFromMe(CTransaction& tx) +{ + BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered) + if (pwallet->IsFromMe(tx)) + return true; + return false; +} + +// get the wallet transaction with the given hash (if it exists) +bool static GetTransaction(const uint256& hashTx, CWalletTx& wtx) +{ + BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered) + if (pwallet->GetTransaction(hashTx,wtx)) + return true; + return false; +} + +// erases transaction with the given hash from all wallets +void static EraseFromWallets(uint256 hash) +{ + BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered) + pwallet->EraseFromWallet(hash); +} + +// make sure all wallets know about the given transaction, in the given block +void SyncWithWallets(const CTransaction& tx, const CBlock* pblock, bool fUpdate, bool fConnect) +{ + if (!fConnect) + { + // triangles: wallets need to refund inputs when disconnecting coinstake + if (tx.IsCoinStake()) + { + BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered) + if (pwallet->IsFromMe(tx)) + pwallet->DisableTransaction(tx); + } + return; + } + + BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered) + pwallet->AddToWalletIfInvolvingMe(tx, pblock, fUpdate); +} + +// notify wallets about a new best chain +void static SetBestChain(const CBlockLocator& loc) +{ + BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered) + pwallet->SetBestChain(loc); +} + +// notify wallets about an updated transaction +void static UpdatedTransaction(const uint256& hashTx) +{ + BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered) + pwallet->UpdatedTransaction(hashTx); +} + +// dump all wallets +void static PrintWallets(const CBlock& block) +{ + BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered) + pwallet->PrintWallet(block); +} + +// notify wallets about an incoming inventory (for request counts) +void static Inventory(const uint256& hash) +{ + BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered) + pwallet->Inventory(hash); +} + +// ask wallets to resend their transactions +void ResendWalletTransactions() +{ + BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered) + pwallet->ResendWalletTransactions(); +} + + + +////////////////////////////////////////////////////////////////////////////// +// +// mapOrphanTransactions +// + +bool AddOrphanTx(const CDataStream& vMsg) +{ + CTransaction tx; + CDataStream(vMsg) >> tx; + uint256 hash = tx.GetHash(); + if (mapOrphanTransactions.count(hash)) + return false; + + CDataStream* pvMsg = new CDataStream(vMsg); + + // Ignore big transactions, to avoid a + // send-big-orphans memory exhaustion attack. If a peer has a legitimate + // large transaction with a missing parent then we assume + // it will rebroadcast it later, after the parent transaction(s) + // have been mined or received. + // 10,000 orphans, each of which is at most 5,000 bytes big is + // at most 500 megabytes of orphans: + if (pvMsg->size() > 5000) + { + printf("ignoring large orphan tx (size: %"PRIszu", hash: %s)\n", pvMsg->size(), hash.ToString().substr(0,10).c_str()); + delete pvMsg; + return false; + } + + mapOrphanTransactions[hash] = pvMsg; + BOOST_FOREACH(const CTxIn& txin, tx.vin) + mapOrphanTransactionsByPrev[txin.prevout.hash].insert(make_pair(hash, pvMsg)); + + printf("stored orphan tx %s (mapsz %"PRIszu")\n", hash.ToString().substr(0,10).c_str(), + mapOrphanTransactions.size()); + return true; +} + +void static EraseOrphanTx(uint256 hash) +{ + if (!mapOrphanTransactions.count(hash)) + return; + const CDataStream* pvMsg = mapOrphanTransactions[hash]; + CTransaction tx; + CDataStream(*pvMsg) >> tx; + BOOST_FOREACH(const CTxIn& txin, tx.vin) + { + mapOrphanTransactionsByPrev[txin.prevout.hash].erase(hash); + if (mapOrphanTransactionsByPrev[txin.prevout.hash].empty()) + mapOrphanTransactionsByPrev.erase(txin.prevout.hash); + } + delete pvMsg; + mapOrphanTransactions.erase(hash); +} + +unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans) +{ + unsigned int nEvicted = 0; + while (mapOrphanTransactions.size() > nMaxOrphans) + { + // Evict a random orphan: + uint256 randomhash = GetRandHash(); + map::iterator it = mapOrphanTransactions.lower_bound(randomhash); + if (it == mapOrphanTransactions.end()) + it = mapOrphanTransactions.begin(); + EraseOrphanTx(it->first); + ++nEvicted; + } + return nEvicted; +} + + + +////////////////////////////////////////////////////////////////////////////// +// +// CTransaction and CTxIndex +// + +bool CTransaction::ReadFromDisk(CTxDB& txdb, COutPoint prevout, CTxIndex& txindexRet) +{ + SetNull(); + if (!txdb.ReadTxIndex(prevout.hash, txindexRet)) + return false; + if (!ReadFromDisk(txindexRet.pos)) + return false; + if (prevout.n >= vout.size()) + { + SetNull(); + return false; + } + return true; +} + +bool CTransaction::ReadFromDisk(CTxDB& txdb, COutPoint prevout) +{ + CTxIndex txindex; + return ReadFromDisk(txdb, prevout, txindex); +} + +bool CTransaction::ReadFromDisk(COutPoint prevout) +{ + CTxDB txdb("r"); + CTxIndex txindex; + return ReadFromDisk(txdb, prevout, txindex); +} + +bool CTransaction::IsStandard() const +{ + if (nVersion > CTransaction::CURRENT_VERSION) + return false; + + BOOST_FOREACH(const CTxIn& txin, vin) + { + // Biggest 'standard' txin is a 3-signature 3-of-3 CHECKMULTISIG + // pay-to-script-hash, which is 3 ~80-byte signatures, 3 + // ~65-byte public keys, plus a few script ops. + if (txin.scriptSig.size() > 500) + return false; + if (!txin.scriptSig.IsPushOnly()) + return false; + } + BOOST_FOREACH(const CTxOut& txout, vout) { + if (!::IsStandard(txout.scriptPubKey)) + return false; + if (txout.nValue == 0) + return false; + } + return true; +} + +// +// Check transaction inputs, and make sure any +// pay-to-script-hash transactions are evaluating IsStandard scripts +// +// Why bother? To avoid denial-of-service attacks; an attacker +// can submit a standard HASH... OP_EQUAL transaction, +// which will get accepted into blocks. The redemption +// script can be anything; an attacker could use a very +// expensive-to-check-upon-redemption script like: +// DUP CHECKSIG DROP ... repeated 100 times... OP_1 +// +bool CTransaction::AreInputsStandard(const MapPrevTx& mapInputs) const +{ + if (IsCoinBase()) + return true; // Coinbases don't use vin normally + + for (unsigned int i = 0; i < vin.size(); i++) + { + const CTxOut& prev = GetOutputFor(vin[i], mapInputs); + + vector > vSolutions; + txnouttype whichType; + // get the scriptPubKey corresponding to this input: + const CScript& prevScript = prev.scriptPubKey; + if (!Solver(prevScript, whichType, vSolutions)) + return false; + int nArgsExpected = ScriptSigArgsExpected(whichType, vSolutions); + if (nArgsExpected < 0) + return false; + + // Transactions with extra stuff in their scriptSigs are + // non-standard. Note that this EvalScript() call will + // be quick, because if there are any operations + // beside "push data" in the scriptSig the + // IsStandard() call returns false + vector > stack; + if (!EvalScript(stack, vin[i].scriptSig, *this, i, 0)) + return false; + + if (whichType == TX_SCRIPTHASH) + { + if (stack.empty()) + return false; + CScript subscript(stack.back().begin(), stack.back().end()); + vector > vSolutions2; + txnouttype whichType2; + if (!Solver(subscript, whichType2, vSolutions2)) + return false; + if (whichType2 == TX_SCRIPTHASH) + return false; + + int tmpExpected; + tmpExpected = ScriptSigArgsExpected(whichType2, vSolutions2); + if (tmpExpected < 0) + return false; + nArgsExpected += tmpExpected; + } + + if (stack.size() != (unsigned int)nArgsExpected) + return false; + } + + return true; +} + +unsigned int +CTransaction::GetLegacySigOpCount() const +{ + unsigned int nSigOps = 0; + BOOST_FOREACH(const CTxIn& txin, vin) + { + nSigOps += txin.scriptSig.GetSigOpCount(false); + } + BOOST_FOREACH(const CTxOut& txout, vout) + { + nSigOps += txout.scriptPubKey.GetSigOpCount(false); + } + return nSigOps; +} + + +int CMerkleTx::SetMerkleBranch(const CBlock* pblock) +{ + if (fClient) + { + if (hashBlock == 0) + return 0; + } + else + { + CBlock blockTmp; + if (pblock == NULL) + { + // Load the block this tx is in + CTxIndex txindex; + if (!CTxDB("r").ReadTxIndex(GetHash(), txindex)) + return 0; + if (!blockTmp.ReadFromDisk(txindex.pos.nFile, txindex.pos.nBlockPos)) + return 0; + pblock = &blockTmp; + } + + // Update the tx's hashBlock + hashBlock = pblock->GetHash(); + + // Locate the transaction + for (nIndex = 0; nIndex < (int)pblock->vtx.size(); nIndex++) + if (pblock->vtx[nIndex] == *(CTransaction*)this) + break; + if (nIndex == (int)pblock->vtx.size()) + { + vMerkleBranch.clear(); + nIndex = -1; + printf("ERROR: SetMerkleBranch() : couldn't find tx in block\n"); + return 0; + } + + // Fill in merkle branch + vMerkleBranch = pblock->GetMerkleBranch(nIndex); + } + + // Is the tx in a block that's in the main chain + map::iterator mi = mapBlockIndex.find(hashBlock); + if (mi == mapBlockIndex.end()) + return 0; + CBlockIndex* pindex = (*mi).second; + if (!pindex || !pindex->IsInMainChain()) + return 0; + + return pindexBest->nHeight - pindex->nHeight + 1; +} + + + + +bool CTransaction::CheckTransaction() const +{ + // Basic checks that don't depend on any context + if (vin.empty()) + return DoS(10, error("CTransaction::CheckTransaction() : vin empty")); + if (vout.empty()) + return DoS(10, error("CTransaction::CheckTransaction() : vout empty")); + // Size limits + if (::GetSerializeSize(*this, SER_NETWORK, PROTOCOL_VERSION) > MAX_BLOCK_SIZE) + return DoS(100, error("CTransaction::CheckTransaction() : size limits failed")); + + // Check for negative or overflow output values + int64 nValueOut = 0; + for (unsigned int i = 0; i < vout.size(); i++) + { + const CTxOut& txout = vout[i]; + if (txout.IsEmpty() && !IsCoinBase() && !IsCoinStake()) + return DoS(100, error("CTransaction::CheckTransaction() : txout empty for user transaction")); + + // triangles: enforce minimum output amount + if ((!txout.IsEmpty()) && txout.nValue < MIN_TXOUT_AMOUNT) + return DoS(100, error("CTransaction::CheckTransaction() : txout.nValue below minimum")); + + if (txout.nValue > MAX_MONEY) + return DoS(100, error("CTransaction::CheckTransaction() : txout.nValue too high")); + nValueOut += txout.nValue; + if (!MoneyRange(nValueOut)) + return DoS(100, error("CTransaction::CheckTransaction() : txout total out of range")); + } + + // Check for duplicate inputs + set vInOutPoints; + BOOST_FOREACH(const CTxIn& txin, vin) + { + if (vInOutPoints.count(txin.prevout)) + return false; + vInOutPoints.insert(txin.prevout); + } + + if (IsCoinBase()) + { + if (vin[0].scriptSig.size() < 2 || vin[0].scriptSig.size() > 100) + return DoS(100, error("CTransaction::CheckTransaction() : coinbase script size")); + } + else + { + BOOST_FOREACH(const CTxIn& txin, vin) + if (txin.prevout.IsNull()) + return DoS(10, error("CTransaction::CheckTransaction() : prevout is null")); + } + + return true; +} + + +int64 CTransaction::GetMinFee(unsigned int nBlockSize, bool fAllowFree, + enum GetMinFee_mode mode, unsigned int nBytes) const +{ + // Base fee is either MIN_TX_FEE or MIN_RELAY_TX_FEE + int64 nBaseFee = (mode == GMF_RELAY) ? MIN_RELAY_TX_FEE : MIN_TX_FEE; + + unsigned int nNewBlockSize = nBlockSize + nBytes; + int64 nMinFee = (1 + (int64)nBytes / 1000) * nBaseFee; + + // To limit dust spam, require MIN_TX_FEE/MIN_RELAY_TX_FEE if any output is less than 0.01 + if (nMinFee < nBaseFee) + { + BOOST_FOREACH(const CTxOut& txout, vout) + if (txout.nValue < CENT) + nMinFee = nBaseFee; + } + + // Raise the price as the block approaches full + if (nBlockSize != 1 && nNewBlockSize >= MAX_BLOCK_SIZE_GEN/2) + { + if (nNewBlockSize >= MAX_BLOCK_SIZE_GEN) + return MAX_MONEY; + nMinFee *= MAX_BLOCK_SIZE_GEN / (MAX_BLOCK_SIZE_GEN - nNewBlockSize); + } + + if (!MoneyRange(nMinFee)) + nMinFee = MAX_MONEY; + return nMinFee; +} + + +bool CTxMemPool::accept(CTxDB& txdb, CTransaction &tx, bool fCheckInputs, + bool* pfMissingInputs) +{ + if (pfMissingInputs) + *pfMissingInputs = false; + + if (!tx.CheckTransaction()) + return error("CTxMemPool::accept() : CheckTransaction failed"); + + // Coinbase is only valid in a block, not as a loose transaction + if (tx.IsCoinBase()) + return tx.DoS(100, error("CTxMemPool::accept() : coinbase as individual tx")); + + // triangles: coinstake is also only valid in a block, not as a loose transaction + if (tx.IsCoinStake()) + return tx.DoS(100, error("CTxMemPool::accept() : coinstake as individual tx")); + + // To help v0.1.5 clients who would see it as a negative number + if ((int64)tx.nLockTime > std::numeric_limits::max()) + return error("CTxMemPool::accept() : not accepting nLockTime beyond 2038 yet"); + + // Rather not work on nonstandard transactions (unless -testnet) + if (!fTestNet && !tx.IsStandard()) + return error("CTxMemPool::accept() : nonstandard transaction type"); + + // Do we already have it? + uint256 hash = tx.GetHash(); + { + LOCK(cs); + if (mapTx.count(hash)) + return false; + } + if (fCheckInputs) + if (txdb.ContainsTx(hash)) + return false; + + // Check for conflicts with in-memory transactions + CTransaction* ptxOld = NULL; + for (unsigned int i = 0; i < tx.vin.size(); i++) + { + COutPoint outpoint = tx.vin[i].prevout; + if (mapNextTx.count(outpoint)) + { + // Disable replacement feature for now + return false; + + // Allow replacing with a newer version of the same transaction + if (i != 0) + return false; + ptxOld = mapNextTx[outpoint].ptx; + if (ptxOld->IsFinal()) + return false; + if (!tx.IsNewerThan(*ptxOld)) + return false; + for (unsigned int i = 0; i < tx.vin.size(); i++) + { + COutPoint outpoint = tx.vin[i].prevout; + if (!mapNextTx.count(outpoint) || mapNextTx[outpoint].ptx != ptxOld) + return false; + } + break; + } + } + + if (fCheckInputs) + { + MapPrevTx mapInputs; + map mapUnused; + bool fInvalid = false; + if (!tx.FetchInputs(txdb, mapUnused, false, false, mapInputs, fInvalid)) + { + if (fInvalid) + return error("CTxMemPool::accept() : FetchInputs found invalid tx %s", hash.ToString().substr(0,10).c_str()); + if (pfMissingInputs) + *pfMissingInputs = true; + return false; + } + + // Check for non-standard pay-to-script-hash in inputs + if (!tx.AreInputsStandard(mapInputs) && !fTestNet) + return error("CTxMemPool::accept() : nonstandard transaction input"); + + // Note: if you modify this code to accept non-standard transactions, then + // you should add code here to check that the transaction does a + // reasonable number of ECDSA signature verifications. + + int64 nFees = tx.GetValueIn(mapInputs)-tx.GetValueOut(); + unsigned int nSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION); + + // Don't accept it if it can't get into a block + int64 txMinFee = tx.GetMinFee(1000, false, GMF_RELAY, nSize); + if (nFees < txMinFee) + return error("CTxMemPool::accept() : not enough fees %s, %"PRI64d" < %"PRI64d, + hash.ToString().c_str(), + nFees, txMinFee); + + // Continuously rate-limit free transactions + // This mitigates 'penny-flooding' -- sending thousands of free transactions just to + // be annoying or make others' transactions take longer to confirm. + if (nFees < MIN_RELAY_TX_FEE) + { + static CCriticalSection cs; + static double dFreeCount; + static int64 nLastTime; + int64 nNow = GetTime(); + + { + LOCK(cs); + // Use an exponentially decaying ~10-minute window: + dFreeCount *= pow(1.0 - 1.0/600.0, (double)(nNow - nLastTime)); + nLastTime = nNow; + // -limitfreerelay unit is thousand-bytes-per-minute + // At default rate it would take over a month to fill 1GB + if (dFreeCount > GetArg("-limitfreerelay", 15)*10*1000 && !IsFromMe(tx)) + return error("CTxMemPool::accept() : free transaction rejected by rate limiter"); + if (fDebug) + printf("Rate limit dFreeCount: %g => %g\n", dFreeCount, dFreeCount+nSize); + dFreeCount += nSize; + } + } + + // Check against previous transactions + // This is done last to help prevent CPU exhaustion denial-of-service attacks. + if (!tx.ConnectInputs(txdb, mapInputs, mapUnused, CDiskTxPos(1,1,1), pindexBest, false, false)) + { + return error("CTxMemPool::accept() : ConnectInputs failed %s", hash.ToString().substr(0,10).c_str()); + } + } + + // Store transaction in memory + { + LOCK(cs); + if (ptxOld) + { + printf("CTxMemPool::accept() : replacing tx %s with new version\n", ptxOld->GetHash().ToString().c_str()); + remove(*ptxOld); + } + addUnchecked(hash, tx); + } + + ///// are we sure this is ok when loading transactions or restoring block txes + // If updated, erase old tx from wallet + if (ptxOld) + EraseFromWallets(ptxOld->GetHash()); + + printf("CTxMemPool::accept() : accepted %s (poolsz %"PRIszu")\n", + hash.ToString().substr(0,10).c_str(), + mapTx.size()); + return true; +} + +bool CTransaction::AcceptToMemoryPool(CTxDB& txdb, bool fCheckInputs, bool* pfMissingInputs) +{ + return mempool.accept(txdb, *this, fCheckInputs, pfMissingInputs); +} + +bool CTxMemPool::addUnchecked(const uint256& hash, CTransaction &tx) +{ + // Add to memory pool without checking anything. Don't call this directly, + // call CTxMemPool::accept to properly check the transaction first. + { + mapTx[hash] = tx; + for (unsigned int i = 0; i < tx.vin.size(); i++) + mapNextTx[tx.vin[i].prevout] = CInPoint(&mapTx[hash], i); + nTransactionsUpdated++; + } + return true; +} + + +bool CTxMemPool::remove(CTransaction &tx) +{ + // Remove transaction from memory pool + { + LOCK(cs); + uint256 hash = tx.GetHash(); + if (mapTx.count(hash)) + { + BOOST_FOREACH(const CTxIn& txin, tx.vin) + mapNextTx.erase(txin.prevout); + mapTx.erase(hash); + nTransactionsUpdated++; + } + } + return true; +} + +void CTxMemPool::clear() +{ + LOCK(cs); + mapTx.clear(); + mapNextTx.clear(); + ++nTransactionsUpdated; +} + +void CTxMemPool::queryHashes(std::vector& vtxid) +{ + vtxid.clear(); + + LOCK(cs); + vtxid.reserve(mapTx.size()); + for (map::iterator mi = mapTx.begin(); mi != mapTx.end(); ++mi) + vtxid.push_back((*mi).first); +} + + + + +int CMerkleTx::GetDepthInMainChain(CBlockIndex* &pindexRet) const +{ + if (hashBlock == 0 || nIndex == -1) + return 0; + + // Find the block it claims to be in + map::iterator mi = mapBlockIndex.find(hashBlock); + if (mi == mapBlockIndex.end()) + return 0; + CBlockIndex* pindex = (*mi).second; + if (!pindex || !pindex->IsInMainChain()) + return 0; + + // Make sure the merkle branch connects to this block + if (!fMerkleVerified) + { + if (CBlock::CheckMerkleBranch(GetHash(), vMerkleBranch, nIndex) != pindex->hashMerkleRoot) + return 0; + fMerkleVerified = true; + } + + pindexRet = pindex; + return pindexBest->nHeight - pindex->nHeight + 1; +} + + +int CMerkleTx::GetBlocksToMaturity() const +{ + if (!(IsCoinBase() || IsCoinStake())) + return 0; + return max(0, (nCoinbaseMaturity+20) - GetDepthInMainChain()); +} + + +bool CMerkleTx::AcceptToMemoryPool(CTxDB& txdb, bool fCheckInputs) +{ + if (fClient) + { + if (!IsInMainChain() && !ClientConnectInputs()) + return false; + return CTransaction::AcceptToMemoryPool(txdb, false); + } + else + { + return CTransaction::AcceptToMemoryPool(txdb, fCheckInputs); + } +} + +bool CMerkleTx::AcceptToMemoryPool() +{ + CTxDB txdb("r"); + return AcceptToMemoryPool(txdb); +} + + + +bool CWalletTx::AcceptWalletTransaction(CTxDB& txdb, bool fCheckInputs) +{ + + { + LOCK(mempool.cs); + // Add previous supporting transactions first + BOOST_FOREACH(CMerkleTx& tx, vtxPrev) + { + if (!(tx.IsCoinBase() || tx.IsCoinStake())) + { + uint256 hash = tx.GetHash(); + if (!mempool.exists(hash) && !txdb.ContainsTx(hash)) + tx.AcceptToMemoryPool(txdb, fCheckInputs); + } + } + return AcceptToMemoryPool(txdb, fCheckInputs); + } + return false; +} + + +bool CWalletTx::AcceptWalletTransaction() +{ + CTxDB txdb("r"); + return AcceptWalletTransaction(txdb); +} + + +int CTxIndex::GetDepthInMainChain() const +{ + // Read block header + CBlock block; + if (!block.ReadFromDisk(pos.nFile, pos.nBlockPos, false)) + return 0; + // Find the block in the index + map::iterator mi = mapBlockIndex.find(block.GetHash()); + if (mi == mapBlockIndex.end()) + return 0; + CBlockIndex* pindex = (*mi).second; + if (!pindex || !pindex->IsInMainChain()) + return 0; + return 1 + nBestHeight - pindex->nHeight; +} + +// Return transaction in tx, and if it was found inside a block, its hash is placed in hashBlock +bool GetTransaction(const uint256 &hash, CTransaction &tx, uint256 &hashBlock) +{ + { + LOCK(cs_main); + { + LOCK(mempool.cs); + if (mempool.exists(hash)) + { + tx = mempool.lookup(hash); + return true; + } + } + CTxDB txdb("r"); + CTxIndex txindex; + if (tx.ReadFromDisk(txdb, COutPoint(hash, 0), txindex)) + { + CBlock block; + if (block.ReadFromDisk(txindex.pos.nFile, txindex.pos.nBlockPos, false)) + hashBlock = block.GetHash(); + return true; + } + } + return false; +} + + +////////////////////////////////////////////////////////////////////////////// +// +// CBlock and CBlockIndex +// + +static CBlockIndex* pblockindexFBBHLast; +CBlockIndex* FindBlockByHeight(int nHeight) +{ + CBlockIndex *pblockindex; + if (nHeight < nBestHeight / 2) + pblockindex = pindexGenesisBlock; + else + pblockindex = pindexBest; + if (pblockindexFBBHLast && abs(nHeight - pblockindex->nHeight) > abs(nHeight - pblockindexFBBHLast->nHeight)) + pblockindex = pblockindexFBBHLast; + while (pblockindex->nHeight > nHeight) + pblockindex = pblockindex->pprev; + while (pblockindex->nHeight < nHeight) + pblockindex = pblockindex->pnext; + pblockindexFBBHLast = pblockindex; + return pblockindex; +} + + +bool CBlock::ReadFromDisk(const CBlockIndex* pindex, bool fReadTransactions) +{ + if (!fReadTransactions) + { + *this = pindex->GetBlockHeader(); + return true; + } + if (!ReadFromDisk(pindex->nFile, pindex->nBlockPos, fReadTransactions)) + return false; + if (GetHash() != pindex->GetBlockHash()) + return error("CBlock::ReadFromDisk() : GetHash() doesn't match index"); + return true; +} + + +uint256 static GetOrphanRoot(const CBlock* pblock) +{ + // Work back to the first block in the orphan chain + while (mapOrphanBlocks.count(pblock->hashPrevBlock)) + pblock = mapOrphanBlocks[pblock->hashPrevBlock]; + return pblock->GetHash(); +} + + +// triangles: find block wanted by given orphan block +uint256 WantedByOrphan(const CBlock* pblockOrphan) +{ + // Work back to the first block in the orphan chain + while (mapOrphanBlocks.count(pblockOrphan->hashPrevBlock)) + pblockOrphan = mapOrphanBlocks[pblockOrphan->hashPrevBlock]; + return pblockOrphan->hashPrevBlock; +} + + +int generateMTRandom(unsigned int s, int range) +{ + random::mt19937 gen(s); + random::uniform_int_distribution<> dist(0, range); + return dist(gen); +} + + + +static const int64 nMinSubsidy = 1 * COIN; +// miner's coin base reward based on nBits +int64 GetProofOfWorkReward(int nHeight, int64 nFees, uint256 prevHash) +{ + int64_t nSubsidy = 1 * COIN; + + if(nHeight >= 1 && nHeight <= 100) nSubsidy = 1 * COIN; + else if(nHeight > 100 && nHeight <= 1000) nSubsidy = 20 * COIN; + else if(nHeight > 1000 && nHeight <= 3000) nSubsidy = 10 * COIN; + else if(nHeight > 3000 && nHeight <= 7000) nSubsidy = 5 * COIN; + else if(nHeight > 7000 && nHeight <= 9000) nSubsidy = 10 * COIN; + + return nSubsidy + nFees; +} + +// miner's coin stake reward based on nBits and coin age spent (coin-days) +// simple algorithm, not depend on the diff +int64 GetProofOfStakeReward(int64 nCoinAge, unsigned int nBits, unsigned int nTime, int nHeight) +{ + int64 nRewardCoinYear; + nRewardCoinYear = MAX_TRI_PROOF_OF_STAKE; + int64 nSubsidy = nCoinAge * nRewardCoinYear / 365; + + if (fDebug && GetBoolArg("-printcreation")) + printf("GetProofOfStakeReward(): create=%s nCoinAge=%"PRI64d" nBits=%d\n", FormatMoney(nSubsidy).c_str(), nCoinAge, nBits); + + return nSubsidy; +} + +static const int64 nTargetTimespan = 60 * 30; // 30 blocks +static const int64 nTargetSpacingWorkMax = 3 * nStakeTargetSpacing; + +// +// maximum nBits value could possible be required nTime after +// minimum proof-of-work required was nBase +// +unsigned int ComputeMaxBits(CBigNum bnTargetLimit, unsigned int nBase, int64 nTime) +{ + CBigNum bnResult; + bnResult.SetCompact(nBase); + bnResult *= 2; + while (nTime > 0 && bnResult < bnTargetLimit) + { + // Maximum 200% adjustment per day... + bnResult *= 2; + nTime -= 24 * 60 * 60; + } + if (bnResult > bnTargetLimit) + bnResult = bnTargetLimit; + return bnResult.GetCompact(); +} + +// +// minimum amount of work that could possibly be required nTime after +// minimum proof-of-work required was nBase +// +unsigned int ComputeMinWork(unsigned int nBase, int64 nTime) +{ + return ComputeMaxBits(bnProofOfWorkLimit, nBase, nTime); +} + +// +// minimum amount of stake that could possibly be required nTime after +// minimum proof-of-stake required was nBase +// +unsigned int ComputeMinStake(unsigned int nBase, int64 nTime, unsigned int nBlockTime) +{ + return ComputeMaxBits(bnProofOfStakeLimit, nBase, nTime); +} + + +// triangles: find last block index up to pindex +const CBlockIndex* GetLastBlockIndex(const CBlockIndex* pindex, bool fProofOfStake) +{ + while (pindex && pindex->pprev && (pindex->IsProofOfStake() != fProofOfStake)) + pindex = pindex->pprev; + return pindex; +} + +unsigned int GetNextTargetRequired(const CBlockIndex* pindexLast, bool fProofOfStake) +{ + CBigNum bnTargetLimit = bnProofOfWorkLimit; + + if(fProofOfStake) + { + // Proof-of-Stake blocks has own target limit since nVersion=3 supermajority on mainNet and always on testNet + bnTargetLimit = bnProofOfStakeLimit; + } + + if (pindexLast == NULL) + return bnTargetLimit.GetCompact(); // genesis block + + const CBlockIndex* pindexPrev = GetLastBlockIndex(pindexLast, fProofOfStake); + if (pindexPrev->pprev == NULL) + return bnTargetLimit.GetCompact(); // first block + const CBlockIndex* pindexPrevPrev = GetLastBlockIndex(pindexPrev->pprev, fProofOfStake); + if (pindexPrevPrev->pprev == NULL) + return bnTargetLimit.GetCompact(); // second block + + int64 nActualSpacing = pindexPrev->GetBlockTime() - pindexPrevPrev->GetBlockTime(); + if(nActualSpacing < 0) + { + // printf(">> nActualSpacing = %"PRI64d" corrected to 1.\n", nActualSpacing); + nActualSpacing = 1; + } + + // triangles: target change every block + // triangles: retarget with exponential moving toward target spacing + CBigNum bnNew; + bnNew.SetCompact(pindexPrev->nBits); + + int64 nTargetSpacing = fProofOfStake? nStakeTargetSpacing : min(nTargetSpacingWorkMax, (int64) nStakeTargetSpacing * (1 + pindexLast->nHeight - pindexPrev->nHeight)); + int64 nInterval = nTargetTimespan / nTargetSpacing; + bnNew *= ((nInterval - 1) * nTargetSpacing + nActualSpacing + nActualSpacing); + bnNew /= ((nInterval + 1) * nTargetSpacing); + + /* + printf(">> Height = %d, fProofOfStake = %d, nInterval = %"PRI64d", nTargetSpacing = %"PRI64d", nActualSpacing = %"PRI64d"\n", + pindexPrev->nHeight, fProofOfStake, nInterval, nTargetSpacing, nActualSpacing); + printf(">> pindexPrev->GetBlockTime() = %"PRI64d", pindexPrev->nHeight = %d, pindexPrevPrev->GetBlockTime() = %"PRI64d", pindexPrevPrev->nHeight = %d\n", + pindexPrev->GetBlockTime(), pindexPrev->nHeight, pindexPrevPrev->GetBlockTime(), pindexPrevPrev->nHeight); + */ + + if (bnNew > bnTargetLimit) + bnNew = bnTargetLimit; + + return bnNew.GetCompact(); +} + +bool CheckProofOfWork(uint256 hash, unsigned int nBits) +{ + CBigNum bnTarget; + bnTarget.SetCompact(nBits); + + // Check range + if (bnTarget <= 0 || bnTarget > bnProofOfWorkLimit) + return error("CheckProofOfWork() : nBits below minimum work"); + + // Check proof of work matches claimed amount + if (hash > bnTarget.getuint256()) + return error("CheckProofOfWork() : hash doesn't match nBits"); + + return true; +} + +// Return maximum amount of blocks that other nodes claim to have +int GetNumBlocksOfPeers() +{ + return std::max(cPeerBlockCounts.median(), Checkpoints::GetTotalBlocksEstimate()); +} + +bool IsInitialBlockDownload() +{ + if (pindexBest == NULL || nBestHeight < Checkpoints::GetTotalBlocksEstimate()) + return true; + static int64 nLastUpdate; + static CBlockIndex* pindexLastBest; + if (pindexBest != pindexLastBest) + { + pindexLastBest = pindexBest; + nLastUpdate = GetTime(); + } + return (GetTime() - nLastUpdate < 10 && + pindexBest->GetBlockTime() < GetTime() - 24 * 60 * 60); +} + +void static InvalidChainFound(CBlockIndex* pindexNew) +{ + if (pindexNew->bnChainTrust > bnBestInvalidTrust) + { + bnBestInvalidTrust = pindexNew->bnChainTrust; + CTxDB().WriteBestInvalidTrust(bnBestInvalidTrust); + uiInterface.NotifyBlocksChanged(); + } + + printf("InvalidChainFound: invalid block=%s height=%d trust=%s date=%s\n", + pindexNew->GetBlockHash().ToString().substr(0,20).c_str(), pindexNew->nHeight, + pindexNew->bnChainTrust.ToString().c_str(), DateTimeStrFormat("%x %H:%M:%S", + pindexNew->GetBlockTime()).c_str()); + printf("InvalidChainFound: current best=%s height=%d trust=%s date=%s\n", + hashBestChain.ToString().substr(0,20).c_str(), nBestHeight, bnBestChainTrust.ToString().c_str(), + DateTimeStrFormat("%x %H:%M:%S", pindexBest->GetBlockTime()).c_str()); +} + +void CBlock::UpdateTime(const CBlockIndex* pindexPrev) +{ + nTime = max(GetBlockTime(), GetAdjustedTime()); +} + + +bool CTransaction::DisconnectInputs(CTxDB& txdb) +{ + // Relinquish previous transactions' spent pointers + if (!IsCoinBase()) + { + BOOST_FOREACH(const CTxIn& txin, vin) + { + COutPoint prevout = txin.prevout; + + // Get prev txindex from disk + CTxIndex txindex; + if (!txdb.ReadTxIndex(prevout.hash, txindex)) + return error("DisconnectInputs() : ReadTxIndex failed"); + + if (prevout.n >= txindex.vSpent.size()) + return error("DisconnectInputs() : prevout.n out of range"); + + // Mark outpoint as not spent + txindex.vSpent[prevout.n].SetNull(); + + // Write back + if (!txdb.UpdateTxIndex(prevout.hash, txindex)) + return error("DisconnectInputs() : UpdateTxIndex failed"); + } + } + + // Remove transaction from index + // This can fail if a duplicate of this transaction was in a chain that got + // reorganized away. This is only possible if this transaction was completely + // spent, so erasing it would be a no-op anyway. + txdb.EraseTxIndex(*this); + + return true; +} + + +bool CTransaction::FetchInputs(CTxDB& txdb, const map& mapTestPool, + bool fBlock, bool fMiner, MapPrevTx& inputsRet, bool& fInvalid) +{ + // FetchInputs can return false either because we just haven't seen some inputs + // (in which case the transaction should be stored as an orphan) + // or because the transaction is malformed (in which case the transaction should + // be dropped). If tx is definitely invalid, fInvalid will be set to true. + fInvalid = false; + + if (IsCoinBase()) + return true; // Coinbase transactions have no inputs to fetch. + + for (unsigned int i = 0; i < vin.size(); i++) + { + COutPoint prevout = vin[i].prevout; + if (inputsRet.count(prevout.hash)) + continue; // Got it already + + // Read txindex + CTxIndex& txindex = inputsRet[prevout.hash].first; + bool fFound = true; + if ((fBlock || fMiner) && mapTestPool.count(prevout.hash)) + { + // Get txindex from current proposed changes + txindex = mapTestPool.find(prevout.hash)->second; + } + else + { + // Read txindex from txdb + fFound = txdb.ReadTxIndex(prevout.hash, txindex); + } + if (!fFound && (fBlock || fMiner)) + return fMiner ? false : error("FetchInputs() : %s prev tx %s index entry not found", GetHash().ToString().substr(0,10).c_str(), prevout.hash.ToString().substr(0,10).c_str()); + + // Read txPrev + CTransaction& txPrev = inputsRet[prevout.hash].second; + if (!fFound || txindex.pos == CDiskTxPos(1,1,1)) + { + // Get prev tx from single transactions in memory + { + LOCK(mempool.cs); + if (!mempool.exists(prevout.hash)) + return error("FetchInputs() : %s mempool Tx prev not found %s", GetHash().ToString().substr(0,10).c_str(), prevout.hash.ToString().substr(0,10).c_str()); + txPrev = mempool.lookup(prevout.hash); + } + if (!fFound) + txindex.vSpent.resize(txPrev.vout.size()); + } + else + { + // Get prev tx from disk + if (!txPrev.ReadFromDisk(txindex.pos)) + return error("FetchInputs() : %s ReadFromDisk prev tx %s failed", GetHash().ToString().substr(0,10).c_str(), prevout.hash.ToString().substr(0,10).c_str()); + } + } + + // Make sure all prevout.n indexes are valid: + for (unsigned int i = 0; i < vin.size(); i++) + { + const COutPoint prevout = vin[i].prevout; + assert(inputsRet.count(prevout.hash) != 0); + const CTxIndex& txindex = inputsRet[prevout.hash].first; + const CTransaction& txPrev = inputsRet[prevout.hash].second; + if (prevout.n >= txPrev.vout.size() || prevout.n >= txindex.vSpent.size()) + { + // Revisit this if/when transaction replacement is implemented and allows + // adding inputs: + fInvalid = true; + return DoS(100, error("FetchInputs() : %s prevout.n out of range %d %"PRIszu" %"PRIszu" prev tx %s\n%s", GetHash().ToString().substr(0,10).c_str(), prevout.n, txPrev.vout.size(), txindex.vSpent.size(), prevout.hash.ToString().substr(0,10).c_str(), txPrev.ToString().c_str())); + } + } + + return true; +} + + +const CTxOut& CTransaction::GetOutputFor(const CTxIn& input, const MapPrevTx& inputs) const +{ + MapPrevTx::const_iterator mi = inputs.find(input.prevout.hash); + if (mi == inputs.end()) + throw std::runtime_error("CTransaction::GetOutputFor() : prevout.hash not found"); + + const CTransaction& txPrev = (mi->second).second; + if (input.prevout.n >= txPrev.vout.size()) + throw std::runtime_error("CTransaction::GetOutputFor() : prevout.n out of range"); + + return txPrev.vout[input.prevout.n]; +} + + +int64 CTransaction::GetValueIn(const MapPrevTx& inputs) const +{ + if (IsCoinBase()) + return 0; + + int64 nResult = 0; + for (unsigned int i = 0; i < vin.size(); i++) + { + nResult += GetOutputFor(vin[i], inputs).nValue; + } + return nResult; + +} + + +unsigned int CTransaction::GetP2SHSigOpCount(const MapPrevTx& inputs) const +{ + if (IsCoinBase()) + return 0; + + unsigned int nSigOps = 0; + for (unsigned int i = 0; i < vin.size(); i++) + { + const CTxOut& prevout = GetOutputFor(vin[i], inputs); + if (prevout.scriptPubKey.IsPayToScriptHash()) + nSigOps += prevout.scriptPubKey.GetSigOpCount(vin[i].scriptSig); + } + return nSigOps; +} + + +bool CTransaction::ConnectInputs(CTxDB& txdb, MapPrevTx inputs, + map& mapTestPool, const CDiskTxPos& posThisTx, + const CBlockIndex* pindexBlock, bool fBlock, bool fMiner, bool fStrictPayToScriptHash) +{ + // Take over previous transactions' spent pointers + // fBlock is true when this is called from AcceptBlock when a new best-block is added to the blockchain + // fMiner is true when called from the internal bitcoin miner + // ... both are false when called from CTransaction::AcceptToMemoryPool + if (!IsCoinBase()) + { + int64 nValueIn = 0; + int64 nFees = 0; + for (unsigned int i = 0; i < vin.size(); i++) + { + COutPoint prevout = vin[i].prevout; + assert(inputs.count(prevout.hash) > 0); + CTxIndex& txindex = inputs[prevout.hash].first; + CTransaction& txPrev = inputs[prevout.hash].second; + + if (prevout.n >= txPrev.vout.size() || prevout.n >= txindex.vSpent.size()) + return DoS(100, error("ConnectInputs() : %s prevout.n out of range %d %"PRIszu" %"PRIszu" prev tx %s\n%s", GetHash().ToString().substr(0,10).c_str(), prevout.n, txPrev.vout.size(), txindex.vSpent.size(), prevout.hash.ToString().substr(0,10).c_str(), txPrev.ToString().c_str())); + + // If prev is coinbase or coinstake, check that it's matured + if (txPrev.IsCoinBase() || txPrev.IsCoinStake()) + for (const CBlockIndex* pindex = pindexBlock; pindex && pindexBlock->nHeight - pindex->nHeight < nCoinbaseMaturity; pindex = pindex->pprev) + if (pindex->nBlockPos == txindex.pos.nBlockPos && pindex->nFile == txindex.pos.nFile) + return error("ConnectInputs() : tried to spend %s at depth %d", txPrev.IsCoinBase() ? "coinbase" : "coinstake", pindexBlock->nHeight - pindex->nHeight); + + // triangles: check transaction timestamp + if (txPrev.nTime > nTime) + return DoS(100, error("ConnectInputs() : transaction timestamp earlier than input transaction")); + + // Check for negative or overflow input values + nValueIn += txPrev.vout[prevout.n].nValue; + if (!MoneyRange(txPrev.vout[prevout.n].nValue) || !MoneyRange(nValueIn)) + return DoS(100, error("ConnectInputs() : txin values out of range")); + + } + // The first loop above does all the inexpensive checks. + // Only if ALL inputs pass do we perform expensive ECDSA signature checks. + // Helps prevent CPU exhaustion attacks. + for (unsigned int i = 0; i < vin.size(); i++) + { + COutPoint prevout = vin[i].prevout; + assert(inputs.count(prevout.hash) > 0); + CTxIndex& txindex = inputs[prevout.hash].first; + CTransaction& txPrev = inputs[prevout.hash].second; + + // Check for conflicts (double-spend) + // This doesn't trigger the DoS code on purpose; if it did, it would make it easier + // for an attacker to attempt to split the network. + if (!txindex.vSpent[prevout.n].IsNull()) + return fMiner ? false : error("ConnectInputs() : %s prev tx already used at %s", GetHash().ToString().substr(0,10).c_str(), txindex.vSpent[prevout.n].ToString().c_str()); + + // Skip ECDSA signature verification when connecting blocks (fBlock=true) + // before the last blockchain checkpoint. This is safe because block merkle hashes are + // still computed and checked, and any change will be caught at the next checkpoint. + if (!(fBlock && (nBestHeight < Checkpoints::GetTotalBlocksEstimate()))) + { + // Verify signature + if (!VerifySignature(txPrev, *this, i, fStrictPayToScriptHash, 0)) + { + // only during transition phase for P2SH: do not invoke anti-DoS code for + // potentially old clients relaying bad P2SH transactions + if (fStrictPayToScriptHash && VerifySignature(txPrev, *this, i, false, 0)) + return error("ConnectInputs() : %s P2SH VerifySignature failed", GetHash().ToString().substr(0,10).c_str()); + + return DoS(100,error("ConnectInputs() : %s VerifySignature failed", GetHash().ToString().substr(0,10).c_str())); + } + } + + // Mark outpoints as spent + txindex.vSpent[prevout.n] = posThisTx; + + // Write back + if (fBlock || fMiner) + { + mapTestPool[prevout.hash] = txindex; + } + } + + if (IsCoinStake()) + { + // triangles: coin stake tx earns reward instead of paying fee + uint64 nCoinAge; + if (!GetCoinAge(txdb, nCoinAge)) + return error("ConnectInputs() : %s unable to get coin age for coinstake", GetHash().ToString().substr(0,10).c_str()); + int64 nStakeReward = GetValueOut() - nValueIn; + if (nStakeReward > GetProofOfStakeReward(nCoinAge, pindexBlock->nBits, nTime, pindexBlock->nHeight) - GetMinFee() + MIN_TX_FEE) + return DoS(100, error("ConnectInputs() : %s stake reward exceeded", GetHash().ToString().substr(0,10).c_str())); + } + else + { + if (nValueIn < GetValueOut()) + return DoS(100, error("ConnectInputs() : %s value in < value out", GetHash().ToString().substr(0,10).c_str())); + + // Tally transaction fees + int64 nTxFee = nValueIn - GetValueOut(); + if (nTxFee < 0) + return DoS(100, error("ConnectInputs() : %s nTxFee < 0", GetHash().ToString().substr(0,10).c_str())); + // triangles: enforce transaction fees for every block + if (nTxFee < GetMinFee()) + return fBlock? DoS(100, error("ConnectInputs() : %s not paying required fee=%s, paid=%s", GetHash().ToString().substr(0,10).c_str(), FormatMoney(GetMinFee()).c_str(), FormatMoney(nTxFee).c_str())) : false; + + nFees += nTxFee; + if (!MoneyRange(nFees)) + return DoS(100, error("ConnectInputs() : nFees out of range")); + } + } + + return true; +} + + +bool CTransaction::ClientConnectInputs() +{ + if (IsCoinBase()) + return false; + + // Take over previous transactions' spent pointers + { + LOCK(mempool.cs); + int64 nValueIn = 0; + for (unsigned int i = 0; i < vin.size(); i++) + { + // Get prev tx from single transactions in memory + COutPoint prevout = vin[i].prevout; + if (!mempool.exists(prevout.hash)) + return false; + CTransaction& txPrev = mempool.lookup(prevout.hash); + + if (prevout.n >= txPrev.vout.size()) + return false; + + // Verify signature + if (!VerifySignature(txPrev, *this, i, true, 0)) + return error("ConnectInputs() : VerifySignature failed"); + + ///// this is redundant with the mempool.mapNextTx stuff, + ///// not sure which I want to get rid of + ///// this has to go away now that posNext is gone + // // Check for conflicts + // if (!txPrev.vout[prevout.n].posNext.IsNull()) + // return error("ConnectInputs() : prev tx already used"); + // + // // Flag outpoints as used + // txPrev.vout[prevout.n].posNext = posThisTx; + + nValueIn += txPrev.vout[prevout.n].nValue; + + if (!MoneyRange(txPrev.vout[prevout.n].nValue) || !MoneyRange(nValueIn)) + return error("ClientConnectInputs() : txin values out of range"); + } + if (GetValueOut() > nValueIn) + return false; + } + + return true; +} + + +bool CBlock::DisconnectBlock(CTxDB& txdb, CBlockIndex* pindex) +{ + // Disconnect in reverse order + for (int i = vtx.size()-1; i >= 0; i--) + if (!vtx[i].DisconnectInputs(txdb)) + return false; + + // Update block index on disk without changing it in memory. + // The memory index structure will be changed after the db commits. + if (pindex->pprev) + { + CDiskBlockIndex blockindexPrev(pindex->pprev); + blockindexPrev.hashNext = 0; + if (!txdb.WriteBlockIndex(blockindexPrev)) + return error("DisconnectBlock() : WriteBlockIndex failed"); + } + + // triangles: clean up wallet after disconnecting coinstake + BOOST_FOREACH(CTransaction& tx, vtx) + SyncWithWallets(tx, this, false, false); + + return true; +} + +bool CBlock::ConnectBlock(CTxDB& txdb, CBlockIndex* pindex, bool fJustCheck) +{ + // Check it again in case a previous version let a bad block in + if (!CheckBlock(!fJustCheck, !fJustCheck)) + return false; + + // Do not allow blocks that contain transactions which 'overwrite' older transactions, + // unless those are already completely spent. + // If such overwrites are allowed, coinbases and transactions depending upon those + // can be duplicated to remove the ability to spend the first instance -- even after + // being sent to another address. + // See BIP30 and http://r6.ca/blog/20120206T005236Z.html for more information. + // This logic is not necessary for memory pool transactions, as AcceptToMemoryPool + // already refuses previously-known transaction ids entirely. + // This rule was originally applied all blocks whose timestamp was after March 15, 2012, 0:00 UTC. + // Now that the whole chain is irreversibly beyond that time it is applied to all blocks except the + // two in the chain that violate it. This prevents exploiting the issue against nodes in their + // initial block download. + bool fEnforceBIP30 = true; // Always active in triangles + bool fStrictPayToScriptHash = true; // Always active in triangles + + //// issue here: it doesn't know the version + unsigned int nTxPos; + if (fJustCheck) + // FetchInputs treats CDiskTxPos(1,1,1) as a special "refer to memorypool" indicator + // Since we're just checking the block and not actually connecting it, it might not (and probably shouldn't) be on the disk to get the transaction from + nTxPos = 1; + else + nTxPos = pindex->nBlockPos + ::GetSerializeSize(CBlock(), SER_DISK, CLIENT_VERSION) - (2 * GetSizeOfCompactSize(0)) + GetSizeOfCompactSize(vtx.size()); + + map mapQueuedChanges; + int64 nFees = 0; + int64 nValueIn = 0; + int64 nValueOut = 0; + unsigned int nSigOps = 0; + BOOST_FOREACH(CTransaction& tx, vtx) + { + uint256 hashTx = tx.GetHash(); + + if (fEnforceBIP30) { + CTxIndex txindexOld; + if (txdb.ReadTxIndex(hashTx, txindexOld)) { + BOOST_FOREACH(CDiskTxPos &pos, txindexOld.vSpent) + if (pos.IsNull()) + return false; + } + } + + nSigOps += tx.GetLegacySigOpCount(); + if (nSigOps > MAX_BLOCK_SIGOPS) + return DoS(100, error("ConnectBlock() : too many sigops")); + + CDiskTxPos posThisTx(pindex->nFile, pindex->nBlockPos, nTxPos); + if (!fJustCheck) + nTxPos += ::GetSerializeSize(tx, SER_DISK, CLIENT_VERSION); + + MapPrevTx mapInputs; + if (tx.IsCoinBase()) + nValueOut += tx.GetValueOut(); + else + { + bool fInvalid; + if (!tx.FetchInputs(txdb, mapQueuedChanges, true, false, mapInputs, fInvalid)) + return false; + + if (fStrictPayToScriptHash) + { + // Add in sigops done by pay-to-script-hash inputs; + // this is to prevent a "rogue miner" from creating + // an incredibly-expensive-to-validate block. + nSigOps += tx.GetP2SHSigOpCount(mapInputs); + if (nSigOps > MAX_BLOCK_SIGOPS) + return DoS(100, error("ConnectBlock() : too many sigops")); + } + + int64 nTxValueIn = tx.GetValueIn(mapInputs); + int64 nTxValueOut = tx.GetValueOut(); + nValueIn += nTxValueIn; + nValueOut += nTxValueOut; + if (!tx.IsCoinStake()) + nFees += nTxValueIn - nTxValueOut; + + if (!tx.ConnectInputs(txdb, mapInputs, mapQueuedChanges, posThisTx, pindex, true, false, fStrictPayToScriptHash)) + return false; + } + + mapQueuedChanges[hashTx] = CTxIndex(posThisTx, tx.vout.size()); + } + + // triangles: track money supply and mint amount info + pindex->nMint = nValueOut - nValueIn + nFees; + pindex->nMoneySupply = (pindex->pprev? pindex->pprev->nMoneySupply : 0) + nValueOut - nValueIn; + if (!txdb.WriteBlockIndex(CDiskBlockIndex(pindex))) + return error("Connect() : WriteBlockIndex for pindex failed"); + + // triangles: fees are not collected by miners as in bitcoin + // triangles: fees are destroyed to compensate the entire network + if (fDebug && GetBoolArg("-printcreation")) + printf("ConnectBlock() : destroy=%s nFees=%"PRI64d"\n", FormatMoney(nFees).c_str(), nFees); + + if (fJustCheck) + return true; + + // Write queued txindex changes + for (map::iterator mi = mapQueuedChanges.begin(); mi != mapQueuedChanges.end(); ++mi) + { + if (!txdb.UpdateTxIndex((*mi).first, (*mi).second)) + return error("ConnectBlock() : UpdateTxIndex failed"); + } + + uint256 prevHash = 0; + if(pindex->pprev) + { + prevHash = pindex->pprev->GetBlockHash(); + // printf("==> Got prevHash = %s\n", prevHash.ToString().c_str()); + } + + if (vtx[0].GetValueOut() > GetProofOfWorkReward(pindex->nHeight, nFees, prevHash)) + return false; + + // Update block index on disk without changing it in memory. + // The memory index structure will be changed after the db commits. + if (pindex->pprev) + { + CDiskBlockIndex blockindexPrev(pindex->pprev); + blockindexPrev.hashNext = pindex->GetBlockHash(); + if (!txdb.WriteBlockIndex(blockindexPrev)) + return error("ConnectBlock() : WriteBlockIndex failed"); + } + + // Watch for transactions paying to me + BOOST_FOREACH(CTransaction& tx, vtx) + SyncWithWallets(tx, this, true); + + return true; +} + +bool static Reorganize(CTxDB& txdb, CBlockIndex* pindexNew) +{ + printf("REORGANIZE\n"); + + // Find the fork + CBlockIndex* pfork = pindexBest; + CBlockIndex* plonger = pindexNew; + while (pfork != plonger) + { + while (plonger->nHeight > pfork->nHeight) + if (!(plonger = plonger->pprev)) + return error("Reorganize() : plonger->pprev is null"); + if (pfork == plonger) + break; + if (!(pfork = pfork->pprev)) + return error("Reorganize() : pfork->pprev is null"); + } + + // List of what to disconnect + vector vDisconnect; + for (CBlockIndex* pindex = pindexBest; pindex != pfork; pindex = pindex->pprev) + vDisconnect.push_back(pindex); + + // List of what to connect + vector vConnect; + for (CBlockIndex* pindex = pindexNew; pindex != pfork; pindex = pindex->pprev) + vConnect.push_back(pindex); + reverse(vConnect.begin(), vConnect.end()); + + printf("REORGANIZE: Disconnect %"PRIszu" blocks; %s..%s\n", vDisconnect.size(), pfork->GetBlockHash().ToString().substr(0,20).c_str(), pindexBest->GetBlockHash().ToString().substr(0,20).c_str()); + printf("REORGANIZE: Connect %"PRIszu" blocks; %s..%s\n", vConnect.size(), pfork->GetBlockHash().ToString().substr(0,20).c_str(), pindexNew->GetBlockHash().ToString().substr(0,20).c_str()); + + // Disconnect shorter branch + vector vResurrect; + BOOST_FOREACH(CBlockIndex* pindex, vDisconnect) + { + CBlock block; + if (!block.ReadFromDisk(pindex)) + return error("Reorganize() : ReadFromDisk for disconnect failed"); + if (!block.DisconnectBlock(txdb, pindex)) + return error("Reorganize() : DisconnectBlock %s failed", pindex->GetBlockHash().ToString().substr(0,20).c_str()); + + // Queue memory transactions to resurrect + BOOST_FOREACH(const CTransaction& tx, block.vtx) + if (!(tx.IsCoinBase() || tx.IsCoinStake())) + vResurrect.push_back(tx); + } + + // Connect longer branch + vector vDelete; + for (unsigned int i = 0; i < vConnect.size(); i++) + { + CBlockIndex* pindex = vConnect[i]; + CBlock block; + if (!block.ReadFromDisk(pindex)) + return error("Reorganize() : ReadFromDisk for connect failed"); + if (!block.ConnectBlock(txdb, pindex)) + { + // Invalid block + return error("Reorganize() : ConnectBlock %s failed", pindex->GetBlockHash().ToString().substr(0,20).c_str()); + } + + // Queue memory transactions to delete + BOOST_FOREACH(const CTransaction& tx, block.vtx) + vDelete.push_back(tx); + } + if (!txdb.WriteHashBestChain(pindexNew->GetBlockHash())) + return error("Reorganize() : WriteHashBestChain failed"); + + // Make sure it's successfully written to disk before changing memory structure + if (!txdb.TxnCommit()) + return error("Reorganize() : TxnCommit failed"); + + // Disconnect shorter branch + BOOST_FOREACH(CBlockIndex* pindex, vDisconnect) + if (pindex->pprev) + pindex->pprev->pnext = NULL; + + // Connect longer branch + BOOST_FOREACH(CBlockIndex* pindex, vConnect) + if (pindex->pprev) + pindex->pprev->pnext = pindex; + + // Resurrect memory transactions that were in the disconnected branch + BOOST_FOREACH(CTransaction& tx, vResurrect) + tx.AcceptToMemoryPool(txdb, false); + + // Delete redundant memory transactions that are in the connected branch + BOOST_FOREACH(CTransaction& tx, vDelete) + mempool.remove(tx); + + printf("REORGANIZE: done\n"); + + return true; +} + + +// Called from inside SetBestChain: attaches a block to the new best chain being built +bool CBlock::SetBestChainInner(CTxDB& txdb, CBlockIndex *pindexNew) +{ + uint256 hash = GetHash(); + + // Adding to current best branch + if (!ConnectBlock(txdb, pindexNew) || !txdb.WriteHashBestChain(hash)) + { + txdb.TxnAbort(); + InvalidChainFound(pindexNew); + return false; + } + if (!txdb.TxnCommit()) + return error("SetBestChain() : TxnCommit failed"); + + // Add to current best branch + pindexNew->pprev->pnext = pindexNew; + + // Delete redundant memory transactions + BOOST_FOREACH(CTransaction& tx, vtx) + mempool.remove(tx); + + return true; +} + + +bool CBlock::SetBestChain(CTxDB& txdb, CBlockIndex* pindexNew) +{ + uint256 hash = GetHash(); + + if (!txdb.TxnBegin()) + return error("SetBestChain() : TxnBegin failed"); + + if (pindexGenesisBlock == NULL && hash == (!fTestNet ? hashGenesisBlock : hashGenesisBlockTestNet)) + { + txdb.WriteHashBestChain(hash); + if (!txdb.TxnCommit()) + return error("SetBestChain() : TxnCommit failed"); + pindexGenesisBlock = pindexNew; + } + else if (hashPrevBlock == hashBestChain) + { + if (!SetBestChainInner(txdb, pindexNew)) + return error("SetBestChain() : SetBestChainInner failed"); + } + else + { + // the first block in the new chain that will cause it to become the new best chain + CBlockIndex *pindexIntermediate = pindexNew; + + // list of blocks that need to be connected afterwards + std::vector vpindexSecondary; + + // Reorganize is costly in terms of db load, as it works in a single db transaction. + // Try to limit how much needs to be done inside + while (pindexIntermediate->pprev && pindexIntermediate->pprev->bnChainTrust > pindexBest->bnChainTrust) + { + vpindexSecondary.push_back(pindexIntermediate); + pindexIntermediate = pindexIntermediate->pprev; + } + + if (!vpindexSecondary.empty()) + printf("Postponing %"PRIszu" reconnects\n", vpindexSecondary.size()); + + // Switch to new best branch + if (!Reorganize(txdb, pindexIntermediate)) + { + txdb.TxnAbort(); + InvalidChainFound(pindexNew); + return error("SetBestChain() : Reorganize failed"); + } + + // Connect further blocks + BOOST_REVERSE_FOREACH(CBlockIndex *pindex, vpindexSecondary) + { + CBlock block; + if (!block.ReadFromDisk(pindex)) + { + printf("SetBestChain() : ReadFromDisk failed\n"); + break; + } + if (!txdb.TxnBegin()) { + printf("SetBestChain() : TxnBegin 2 failed\n"); + break; + } + // errors now are not fatal, we still did a reorganisation to a new chain in a valid way + if (!block.SetBestChainInner(txdb, pindex)) + break; + } + } + + // Update best block in wallet (so we can detect restored wallets) + bool fIsInitialDownload = IsInitialBlockDownload(); + if (!fIsInitialDownload) + { + const CBlockLocator locator(pindexNew); + ::SetBestChain(locator); + } + + // New best block + hashBestChain = hash; + pindexBest = pindexNew; + pblockindexFBBHLast = NULL; + nBestHeight = pindexBest->nHeight; + bnBestChainTrust = pindexNew->bnChainTrust; + nTimeBestReceived = GetTime(); + nTransactionsUpdated++; + printf("SetBestChain: new best=%s height=%d trust=%s date=%s\n", + hashBestChain.ToString().c_str(), nBestHeight, bnBestChainTrust.ToString().c_str(), + DateTimeStrFormat("%x %H:%M:%S", pindexBest->GetBlockTime()).c_str()); + + printf("Stake checkpoint: %x\n", pindexBest->nStakeModifierChecksum); + + // Check the version of the last 100 blocks to see if we need to upgrade: + if (!fIsInitialDownload) + { + int nUpgraded = 0; + const CBlockIndex* pindex = pindexBest; + for (int i = 0; i < 100 && pindex != NULL; i++) + { + if (pindex->nVersion > CBlock::CURRENT_VERSION) + ++nUpgraded; + pindex = pindex->pprev; + } + if (nUpgraded > 0) + printf("SetBestChain: %d of last 100 blocks above version %d\n", nUpgraded, CBlock::CURRENT_VERSION); + if (nUpgraded > 100/2) + // strMiscWarning is read by GetWarnings(), called by Qt and the JSON-RPC code to warn the user: + strMiscWarning = _("Warning: This version is obsolete, upgrade required!"); + } + + std::string strCmd = GetArg("-blocknotify", ""); + + if (!fIsInitialDownload && !strCmd.empty()) + { + boost::replace_all(strCmd, "%s", hashBestChain.GetHex()); + boost::thread t(runCommand, strCmd); // thread runs free + } + + return true; +} + +// triangles: total coin age spent in transaction, in the unit of coin-days. +// Only those coins meeting minimum age requirement counts. As those +// transactions not in main chain are not currently indexed so we +// might not find out about their coin age. Older transactions are +// guaranteed to be in main chain by sync-checkpoint. This rule is +// introduced to help nodes establish a consistent view of the coin +// age (trust score) of competing branches. +bool CTransaction::GetCoinAge(CTxDB& txdb, uint64& nCoinAge) const +{ + CBigNum bnCentSecond = 0; // coin age in the unit of cent-seconds + nCoinAge = 0; + + if (IsCoinBase()) + return true; + + BOOST_FOREACH(const CTxIn& txin, vin) + { + // First try finding the previous transaction in database + CTransaction txPrev; + CTxIndex txindex; + if (!txPrev.ReadFromDisk(txdb, txin.prevout, txindex)) + continue; // previous transaction not in main chain + if (nTime < txPrev.nTime) + return false; // Transaction timestamp violation + + // Read block header + CBlock block; + if (!block.ReadFromDisk(txindex.pos.nFile, txindex.pos.nBlockPos, false)) + return false; // unable to read block of previous transaction + if (block.GetBlockTime() + nStakeMinAge > nTime) + continue; // only count coins meeting min age requirement + + int64 nValueIn = txPrev.vout[txin.prevout.n].nValue; + bnCentSecond += CBigNum(nValueIn) * (nTime-txPrev.nTime) / CENT; + + if (fDebug && GetBoolArg("-printcoinage")) + printf("coin age nValueIn=%"PRI64d" nTimeDiff=%d bnCentSecond=%s\n", nValueIn, nTime - txPrev.nTime, bnCentSecond.ToString().c_str()); + } + + CBigNum bnCoinDay = bnCentSecond * CENT / COIN / (24 * 60 * 60); + if (fDebug && GetBoolArg("-printcoinage")) + printf("coin age bnCoinDay=%s\n", bnCoinDay.ToString().c_str()); + nCoinAge = bnCoinDay.getuint64(); + return true; +} + +// triangles: total coin age spent in block, in the unit of coin-days. +bool CBlock::GetCoinAge(uint64& nCoinAge) const +{ + nCoinAge = 0; + + CTxDB txdb("r"); + BOOST_FOREACH(const CTransaction& tx, vtx) + { + uint64 nTxCoinAge; + if (tx.GetCoinAge(txdb, nTxCoinAge)) + nCoinAge += nTxCoinAge; + else + return false; + } + + if (nCoinAge == 0) // block coin age minimum 1 coin-day + nCoinAge = 1; + if (fDebug && GetBoolArg("-printcoinage")) + printf("block coin age total nCoinDays=%"PRI64d"\n", nCoinAge); + return true; +} + +bool CBlock::AddToBlockIndex(unsigned int nFile, unsigned int nBlockPos) +{ + // Check for duplicate + uint256 hash = GetHash(); + if (mapBlockIndex.count(hash)) + return error("AddToBlockIndex() : %s already exists", hash.ToString().substr(0,20).c_str()); + + // Construct new block index object + CBlockIndex* pindexNew = new CBlockIndex(nFile, nBlockPos, *this); + if (!pindexNew) + return error("AddToBlockIndex() : new CBlockIndex failed"); + pindexNew->phashBlock = &hash; + map::iterator miPrev = mapBlockIndex.find(hashPrevBlock); + if (miPrev != mapBlockIndex.end()) + { + pindexNew->pprev = (*miPrev).second; + pindexNew->nHeight = pindexNew->pprev->nHeight + 1; + } + + // triangles: compute chain trust score + pindexNew->bnChainTrust = (pindexNew->pprev ? pindexNew->pprev->bnChainTrust : 0) + pindexNew->GetBlockTrust(); + + // triangles: compute stake entropy bit for stake modifier + if (!pindexNew->SetStakeEntropyBit(GetStakeEntropyBit(pindexNew->nHeight))) + return error("AddToBlockIndex() : SetStakeEntropyBit() failed"); + + // triangles: record proof-of-stake hash value + if (pindexNew->IsProofOfStake()) + { + if (!mapProofOfStake.count(hash)) + return error("AddToBlockIndex() : hashProofOfStake not found in map"); + pindexNew->hashProofOfStake = mapProofOfStake[hash]; + } + + // triangles: compute stake modifier + uint64 nStakeModifier = 0; + bool fGeneratedStakeModifier = false; + if (!ComputeNextStakeModifier(pindexNew->pprev, nStakeModifier, fGeneratedStakeModifier)) + return error("AddToBlockIndex() : ComputeNextStakeModifier() failed"); + pindexNew->SetStakeModifier(nStakeModifier, fGeneratedStakeModifier); + pindexNew->nStakeModifierChecksum = GetStakeModifierChecksum(pindexNew); + if (!CheckStakeModifierCheckpoints(pindexNew->nHeight, pindexNew->nStakeModifierChecksum)) + return error("AddToBlockIndex() : Rejected by stake modifier checkpoint height=%d, modifier=0x%016"PRI64x, pindexNew->nHeight, nStakeModifier); + + // Add to mapBlockIndex + map::iterator mi = mapBlockIndex.insert(make_pair(hash, pindexNew)).first; + if (pindexNew->IsProofOfStake()) + setStakeSeen.insert(make_pair(pindexNew->prevoutStake, pindexNew->nStakeTime)); + pindexNew->phashBlock = &((*mi).first); + + // Write to disk block index + CTxDB txdb; + if (!txdb.TxnBegin()) + return false; + txdb.WriteBlockIndex(CDiskBlockIndex(pindexNew)); + if (!txdb.TxnCommit()) + return false; + + // New best + if (pindexNew->bnChainTrust > bnBestChainTrust) + if (!SetBestChain(txdb, pindexNew)) + return false; + + txdb.Close(); + + if (pindexNew == pindexBest) + { + // Notify UI to display prev block's coinbase if it was ours + static uint256 hashPrevBestCoinBase; + UpdatedTransaction(hashPrevBestCoinBase); + hashPrevBestCoinBase = vtx[0].GetHash(); + } + + uiInterface.NotifyBlocksChanged(); + return true; +} + + +bool CBlock::CheckBlock(bool fCheckPOW, bool fCheckMerkleRoot) const +{ + // These are checks that are independent of context + // that can be verified before saving an orphan block. + + // Size limits + if (vtx.empty() || vtx.size() > MAX_BLOCK_SIZE || ::GetSerializeSize(*this, SER_NETWORK, PROTOCOL_VERSION) > MAX_BLOCK_SIZE) + return DoS(100, error("CheckBlock() : size limits failed")); + + // Check proof of work matches claimed amount + if (fCheckPOW && IsProofOfWork() && !CheckProofOfWork(GetHash(), nBits)) + return DoS(50, error("CheckBlock() : proof of work failed")); + + // Check timestamp + if (GetBlockTime() > GetAdjustedTime() + nMaxClockDrift) + return error("CheckBlock() : block timestamp too far in the future"); + + // First transaction must be coinbase, the rest must not be + if (vtx.empty() || !vtx[0].IsCoinBase()) + return DoS(100, error("CheckBlock() : first tx is not coinbase")); + for (unsigned int i = 1; i < vtx.size(); i++) + if (vtx[i].IsCoinBase()) + return DoS(100, error("CheckBlock() : more than one coinbase")); + + // triangles: only the second transaction can be the optional coinstake + for (unsigned int i = 2; i < vtx.size(); i++) + if (vtx[i].IsCoinStake()) + return DoS(100, error("CheckBlock() : coinstake in wrong position")); + + // triangles: coinbase output should be empty if proof-of-stake block + if (IsProofOfStake() && (vtx[0].vout.size() != 1 || !vtx[0].vout[0].IsEmpty())) + return error("CheckBlock() : coinbase output not empty for proof-of-stake block"); + + // Check coinbase timestamp + if (GetBlockTime() > (int64)vtx[0].nTime + nMaxClockDrift) + return DoS(50, error("CheckBlock() : coinbase timestamp is too early")); + + // Check coinstake timestamp + if (IsProofOfStake() && !CheckCoinStakeTimestamp(GetBlockTime(), (int64)vtx[1].nTime)) + return DoS(50, error("CheckBlock() : coinstake timestamp violation nTimeBlock=%"PRI64d" nTimeTx=%u", GetBlockTime(), vtx[1].nTime)); + + CBlockIndex* pindexPrev = pindexBest; + if ((pindexPrev->nHeight >= (int) CUTOFF_POW_BLOCK) && (IsProofOfWork())) + return DoS(100, error("CheckBlock() : Proof of work (%f XST) on or after block %d.\n", + ((double) vtx[0].GetValueOut() / (double) COIN), (int) CUTOFF_POW_BLOCK)); + + // Check transactions + BOOST_FOREACH(const CTransaction& tx, vtx) + { + if (!tx.CheckTransaction()) + return DoS(tx.nDoS, error("CheckBlock() : CheckTransaction failed")); + + // triangles: check transaction timestamp + if (GetBlockTime() < (int64)tx.nTime) + return DoS(50, error("CheckBlock() : block timestamp earlier than transaction timestamp")); + } + + // Check for duplicate txids. This is caught by ConnectInputs(), + // but catching it earlier avoids a potential DoS attack: + set uniqueTx; + BOOST_FOREACH(const CTransaction& tx, vtx) + { + uniqueTx.insert(tx.GetHash()); + } + if (uniqueTx.size() != vtx.size()) + return DoS(100, error("CheckBlock() : duplicate transaction")); + + unsigned int nSigOps = 0; + BOOST_FOREACH(const CTransaction& tx, vtx) + { + nSigOps += tx.GetLegacySigOpCount(); + } + if (nSigOps > MAX_BLOCK_SIGOPS) + return DoS(100, error("CheckBlock() : out-of-bounds SigOpCount")); + + // Check merkle root + if (fCheckMerkleRoot && hashMerkleRoot != BuildMerkleTree()) + return DoS(100, error("CheckBlock() : hashMerkleRoot mismatch")); + + // triangles: check block signature + if (!CheckBlockSignature()) + return DoS(100, error("CheckBlock() : bad block signature")); + + return true; +} + + +bool CBlock::AcceptBlock() +{ + // Check for duplicate + uint256 hash = GetHash(); + if (mapBlockIndex.count(hash)) + return error("AcceptBlock() : block already in mapBlockIndex"); + + // Get prev block index + map::iterator mi = mapBlockIndex.find(hashPrevBlock); + if (mi == mapBlockIndex.end()) + return DoS(10, error("AcceptBlock() : prev block not found")); + CBlockIndex* pindexPrev = (*mi).second; + int nHeight = pindexPrev->nHeight+1; + + if (IsProofOfWork() && nHeight > CUTOFF_POW_BLOCK) + return DoS(100, error("AcceptBlock() : No proof-of-work allowed anymore (height = %d)", nHeight)); + + // Check proof-of-work or proof-of-stake + if (nBits != GetNextTargetRequired(pindexPrev, IsProofOfStake())) + return DoS(100, error("AcceptBlock() : incorrect %s", IsProofOfWork() ? "proof-of-work" : "proof-of-stake")); + + // Check timestamp against prev + if (GetBlockTime() <= pindexPrev->GetMedianTimePast() || GetBlockTime() + nMaxClockDrift < pindexPrev->GetBlockTime()) + return error("AcceptBlock() : block's timestamp is too early"); + + // Check that all transactions are finalized + BOOST_FOREACH(const CTransaction& tx, vtx) + if (!tx.IsFinal(nHeight, GetBlockTime())) + return DoS(10, error("AcceptBlock() : contains a non-final transaction")); + + // Check that the block chain matches the known block chain up to a checkpoint + if (!Checkpoints::CheckHardened(nHeight, hash)) + return DoS(100, error("AcceptBlock() : rejected by hardened checkpoint lock-in at %d", nHeight)); + + // triangles: check that the block satisfies synchronized checkpoint + if (!Checkpoints::CheckSync(hash, pindexPrev)) + { + if(!GetBoolArg("-nosynccheckpoints", false)) + { + return error("AcceptBlock() : rejected by synchronized checkpoint"); + } + else + { + strMiscWarning = _("WARNING: syncronized checkpoint violation detected, but skipped!"); + } + } + + // Reject block.nVersion < 3 blocks since 95% threshold on mainNet and always on testNet: + if (nVersion < 3 && ((!fTestNet && nHeight > 14060) || (fTestNet && nHeight > 0))) + return error("CheckBlock() : rejected nVersion < 3 block"); + + // Enforce rule that the coinbase starts with serialized block height + CScript expect = CScript() << nHeight; + if (!std::equal(expect.begin(), expect.end(), vtx[0].vin[0].scriptSig.begin())) + return DoS(100, error("AcceptBlock() : block height mismatch in coinbase")); + + // Write block to history file + if (!CheckDiskSpace(::GetSerializeSize(*this, SER_DISK, CLIENT_VERSION))) + return error("AcceptBlock() : out of disk space"); + unsigned int nFile = -1; + unsigned int nBlockPos = 0; + if (!WriteToDisk(nFile, nBlockPos)) + return error("AcceptBlock() : WriteToDisk failed"); + if (!AddToBlockIndex(nFile, nBlockPos)) + return error("AcceptBlock() : AddToBlockIndex failed"); + + // Relay inventory, but don't relay old inventory during initial block download + int nBlockEstimate = Checkpoints::GetTotalBlocksEstimate(); + if (hashBestChain == hash) + { + LOCK(cs_vNodes); + BOOST_FOREACH(CNode* pnode, vNodes) + if (nBestHeight > (pnode->nStartingHeight != -1 ? pnode->nStartingHeight - 2000 : nBlockEstimate)) + pnode->PushInventory(CInv(MSG_BLOCK, hash)); + } + + // triangles: check pending sync-checkpoint + Checkpoints::AcceptPendingSyncCheckpoint(); + + return true; +} + + +CBigNum CBlockIndex::GetBlockTrust() const +{ + CBigNum bnTarget; + bnTarget.SetCompact(nBits); + if (bnTarget <= 0) + return 0; + + if (IsProofOfStake()) + { + // Return trust score as usual + return (CBigNum(1)<<256) / (bnTarget+1); + } + else + { + // Calculate work amount for block + CBigNum bnPoWTrust = (bnProofOfWorkLimit / (bnTarget+1)); + return bnPoWTrust > 1 ? bnPoWTrust : 1; + } +} + +bool CBlockIndex::IsSuperMajority(int minVersion, const CBlockIndex* pstart, unsigned int nRequired, unsigned int nToCheck) +{ + unsigned int nFound = 0; + for (unsigned int i = 0; i < nToCheck && nFound < nRequired && pstart != NULL; i++) + { + if (pstart->nVersion >= minVersion) + ++nFound; + pstart = pstart->pprev; + } + return (nFound >= nRequired); +} + + +bool ProcessBlock(CNode* pfrom, CBlock* pblock) +{ + // Check for duplicate + uint256 hash = pblock->GetHash(); + if (mapBlockIndex.count(hash)) + return error("ProcessBlock() : already have block %d %s", mapBlockIndex[hash]->nHeight, hash.ToString().substr(0,20).c_str()); + if (mapOrphanBlocks.count(hash)) + return error("ProcessBlock() : already have block (orphan) %s", hash.ToString().substr(0,20).c_str()); + + // triangles: check proof-of-stake + // Limited duplicity on stake: prevents block flood attack + // Duplicate stake allowed only when there is orphan child block + if (pblock->IsProofOfStake() && setStakeSeen.count(pblock->GetProofOfStake()) && !mapOrphanBlocksByPrev.count(hash) && !Checkpoints::WantedByPendingSyncCheckpoint(hash)) + return error("ProcessBlock() : duplicate proof-of-stake (%s, %d) for block %s", pblock->GetProofOfStake().first.ToString().c_str(), pblock->GetProofOfStake().second, hash.ToString().c_str()); + + // Preliminary checks + if (!pblock->CheckBlock()) + return error("ProcessBlock() : CheckBlock FAILED"); + + // triangles: verify hash target and signature of coinstake tx + if (pblock->IsProofOfStake()) + { + uint256 hashProofOfStake = 0; + if (!CheckProofOfStake(pblock->vtx[1], pblock->nBits, hashProofOfStake)) + { + printf("WARNING: ProcessBlock(): check proof-of-stake failed for block %s\n", hash.ToString().c_str()); + return false; // do not error here as we expect this during initial block download + } + if (!mapProofOfStake.count(hash)) // add to mapProofOfStake + mapProofOfStake.insert(make_pair(hash, hashProofOfStake)); + } + + CBlockIndex* pcheckpoint = Checkpoints::GetLastSyncCheckpoint(); + + if(pcheckpoint && fDebug) + { + const CBlockIndex* pindexLastPos = GetLastBlockIndex(pcheckpoint, true); + if(pindexLastPos) + { + printf("ProcessBlock(): Last POS Block Height: %d \n", pindexLastPos->nHeight); + } + else + { + printf("ProcessBlock(): Previous POS block not found.\n"); + } + } + + if (pcheckpoint && pblock->hashPrevBlock != hashBestChain && !Checkpoints::WantedByPendingSyncCheckpoint(hash)) + { + // Extra checks to prevent "fill up memory by spamming with bogus blocks" + int64 deltaTime = pblock->GetBlockTime() - pcheckpoint->nTime; + CBigNum bnNewBlock; + bnNewBlock.SetCompact(pblock->nBits); + CBigNum bnRequired; + + if (pblock->IsProofOfStake()) + bnRequired.SetCompact(ComputeMinStake(GetLastBlockIndex(pcheckpoint, true)->nBits, deltaTime, pblock->nTime)); + else + bnRequired.SetCompact(ComputeMinWork(GetLastBlockIndex(pcheckpoint, false)->nBits, deltaTime)); + + if (bnNewBlock > bnRequired) + { + if (pfrom) + pfrom->Misbehaving(100); + return error("ProcessBlock() : block with too little %s", pblock->IsProofOfStake()? "proof-of-stake" : "proof-of-work"); + } + } + + // triangles: ask for pending sync-checkpoint if any + if (!IsInitialBlockDownload()) + Checkpoints::AskForPendingSyncCheckpoint(pfrom); + + // If don't already have its previous block, shunt it off to holding area until we get it + if (!mapBlockIndex.count(pblock->hashPrevBlock)) + { + printf("ProcessBlock: ORPHAN BLOCK, prev=%s\n", pblock->hashPrevBlock.ToString().substr(0,20).c_str()); + CBlock* pblock2 = new CBlock(*pblock); + // triangles: check proof-of-stake + if (pblock2->IsProofOfStake()) + { + // Limited duplicity on stake: prevents block flood attack + // Duplicate stake allowed only when there is orphan child block + if (setStakeSeenOrphan.count(pblock2->GetProofOfStake()) && !mapOrphanBlocksByPrev.count(hash) && !Checkpoints::WantedByPendingSyncCheckpoint(hash)) + return error("ProcessBlock() : duplicate proof-of-stake (%s, %d) for orphan block %s", pblock2->GetProofOfStake().first.ToString().c_str(), pblock2->GetProofOfStake().second, hash.ToString().c_str()); + else + setStakeSeenOrphan.insert(pblock2->GetProofOfStake()); + } + mapOrphanBlocks.insert(make_pair(hash, pblock2)); + mapOrphanBlocksByPrev.insert(make_pair(pblock2->hashPrevBlock, pblock2)); + + // Ask this guy to fill in what we're missing + if (pfrom) + { + pfrom->PushGetBlocks(pindexBest, GetOrphanRoot(pblock2)); + // triangles: getblocks may not obtain the ancestor block rejected + // earlier by duplicate-stake check so we ask for it again directly + if (!IsInitialBlockDownload()) + pfrom->AskFor(CInv(MSG_BLOCK, WantedByOrphan(pblock2))); + } + return true; + } + + // Store to disk + if (!pblock->AcceptBlock()) + return error("ProcessBlock() : AcceptBlock FAILED"); + + // Recursively process any orphan blocks that depended on this one + vector vWorkQueue; + vWorkQueue.push_back(hash); + for (unsigned int i = 0; i < vWorkQueue.size(); i++) + { + uint256 hashPrev = vWorkQueue[i]; + for (multimap::iterator mi = mapOrphanBlocksByPrev.lower_bound(hashPrev); + mi != mapOrphanBlocksByPrev.upper_bound(hashPrev); + ++mi) + { + CBlock* pblockOrphan = (*mi).second; + if (pblockOrphan->AcceptBlock()) + vWorkQueue.push_back(pblockOrphan->GetHash()); + mapOrphanBlocks.erase(pblockOrphan->GetHash()); + setStakeSeenOrphan.erase(pblockOrphan->GetProofOfStake()); + delete pblockOrphan; + } + mapOrphanBlocksByPrev.erase(hashPrev); + } + + printf("ProcessBlock: ACCEPTED\n"); + + // triangles: if responsible for sync-checkpoint send it + if (pfrom && !CSyncCheckpoint::strMasterPrivKey.empty()) + Checkpoints::SendSyncCheckpoint(Checkpoints::AutoSelectSyncCheckpoint()); + + return true; +} + +// triangles: sign block +bool CBlock::SignBlock(const CKeyStore& keystore) +{ + vector vSolutions; + txnouttype whichType; + + if(!IsProofOfStake()) + { + for(unsigned int i = 0; i < vtx[0].vout.size(); i++) + { + const CTxOut& txout = vtx[0].vout[i]; + + if (!Solver(txout.scriptPubKey, whichType, vSolutions)) + continue; + + if (whichType == TX_PUBKEY) + { + // Sign + valtype& vchPubKey = vSolutions[0]; + CKey key; + + if (!keystore.GetKey(Hash160(vchPubKey), key)) + continue; + if (key.GetPubKey() != vchPubKey) + continue; + if(!key.Sign(GetHash(), vchBlockSig)) + continue; + + return true; + } + } + } + else + { + const CTxOut& txout = vtx[1].vout[1]; + + if (!Solver(txout.scriptPubKey, whichType, vSolutions)) + return false; + + if (whichType == TX_PUBKEY) + { + // Sign + valtype& vchPubKey = vSolutions[0]; + CKey key; + + if (!keystore.GetKey(Hash160(vchPubKey), key)) + return false; + if (key.GetPubKey() != vchPubKey) + return false; + + return key.Sign(GetHash(), vchBlockSig); + } + } + + printf("Sign failed\n"); + return false; +} + +// triangles: check block signature +bool CBlock::CheckBlockSignature() const +{ + if (GetHash() == (!fTestNet ? hashGenesisBlock : hashGenesisBlockTestNet)) + return vchBlockSig.empty(); + + vector vSolutions; + txnouttype whichType; + + if(IsProofOfStake()) + { + const CTxOut& txout = vtx[1].vout[1]; + + if (!Solver(txout.scriptPubKey, whichType, vSolutions)) + return false; + if (whichType == TX_PUBKEY) + { + valtype& vchPubKey = vSolutions[0]; + CKey key; + if (!key.SetPubKey(vchPubKey)) + return false; + if (vchBlockSig.empty()) + return false; + return key.Verify(GetHash(), vchBlockSig); + } + } + else + { + for(unsigned int i = 0; i < vtx[0].vout.size(); i++) + { + const CTxOut& txout = vtx[0].vout[i]; + + if (!Solver(txout.scriptPubKey, whichType, vSolutions)) + return false; + + if (whichType == TX_PUBKEY) + { + // Verify + valtype& vchPubKey = vSolutions[0]; + CKey key; + if (!key.SetPubKey(vchPubKey)) + continue; + if (vchBlockSig.empty()) + continue; + if(!key.Verify(GetHash(), vchBlockSig)) + continue; + + return true; + } + } + } + return false; +} + + +bool CheckDiskSpace(uint64 nAdditionalBytes) +{ + uint64 nFreeBytesAvailable = filesystem::space(GetDataDir()).available; + + // Check for nMinDiskSpace bytes (currently 50MB) + if (nFreeBytesAvailable < nMinDiskSpace + nAdditionalBytes) + { + fShutdown = true; + string strMessage = _("Warning: Disk space is low!"); + strMiscWarning = strMessage; + printf("*** %s\n", strMessage.c_str()); + uiInterface.ThreadSafeMessageBox(strMessage, "triangles", CClientUIInterface::OK | CClientUIInterface::ICON_EXCLAMATION | CClientUIInterface::MODAL); + StartShutdown(); + return false; + } + return true; +} + + +static filesystem::path BlockFilePath(unsigned int nFile) +{ + string strBlockFn = strprintf("blk%04u.dat", nFile); + return GetDataDir() / strBlockFn; +} + + +FILE* OpenBlockFile(unsigned int nFile, unsigned int nBlockPos, const char* pszMode) +{ + if ((nFile < 1) || (nFile == (unsigned int) -1)) + return NULL; + FILE* file = fopen(BlockFilePath(nFile).string().c_str(), pszMode); + if (!file) + return NULL; + if (nBlockPos != 0 && !strchr(pszMode, 'a') && !strchr(pszMode, 'w')) + { + if (fseek(file, nBlockPos, SEEK_SET) != 0) + { + fclose(file); + return NULL; + } + } + return file; +} + + +static unsigned int nCurrentBlockFile = 1; + +FILE* AppendBlockFile(unsigned int& nFileRet) +{ + nFileRet = 0; + loop + { + FILE* file = OpenBlockFile(nCurrentBlockFile, 0, "ab"); + if (!file) + return NULL; + if (fseek(file, 0, SEEK_END) != 0) + return NULL; + // FAT32 file size max 4GB, fseek and ftell max 2GB, so we must stay under 2GB + if (ftell(file) < (long)(0x7F000000 - MAX_SIZE)) + { + nFileRet = nCurrentBlockFile; + return file; + } + fclose(file); + nCurrentBlockFile++; + } +} + + +bool LoadBlockIndex(bool fAllowNew) +{ + if (fTestNet) + { + pchMessageStart[0] = 0x6f; + pchMessageStart[1] = 0x3e; + pchMessageStart[2] = 0x04; + pchMessageStart[3] = 0x13; + + bnProofOfStakeLimit = bnProofOfStakeLimitTestNet; // 0x00000fff PoS base target is fixed in testnet + bnProofOfWorkLimit = bnProofOfWorkLimitTestNet; // 0x0000ffff PoW base target is fixed in testnet + nStakeMinAge = 10 * 60; // test net min age is 10 min + nStakeMaxAge = 30 * 60; // test net min age is 30 min + nModifierInterval = 60; // test modifier interval is 1 minutes + nCoinbaseMaturity = 10; // test maturity is 10 blocks + nStakeTargetSpacing = 1 * 60; // test block spacing is 1 minutes + } + + // + // Load block index + // + CTxDB txdb("cr"); + if (!txdb.LoadBlockIndex()) + return false; + txdb.Close(); + + // + // Init with genesis block + // + if (mapBlockIndex.empty()) + { + if (!fAllowNew) + return false; + + // Genesis block + const char* pszTimestamp = "july 16 2014, I'm deh besht mang, I deeed et!"; + CTransaction txNew; + txNew.nTime = nChainStartTime; + txNew.vin.resize(1); + txNew.vout.resize(1); + txNew.vin[0].scriptSig = CScript() << 486604799 << CBigNum(9999) << vector((const unsigned char*)pszTimestamp, (const unsigned char*)pszTimestamp + strlen(pszTimestamp)); + txNew.vout[0].SetEmpty(); + + CBlock block; + block.vtx.push_back(txNew); + block.hashPrevBlock = 0; + block.hashMerkleRoot = block.BuildMerkleTree(); + block.nVersion = 1; + block.nTime = 1405500418; + block.nBits = bnProofOfWorkLimit.GetCompact(); + block.nNonce = 43; + + if (false && (block.GetHash() != hashGenesisBlock)) { + + // This will figure out a valid hash and Nonce if you're + // creating a different genesis block: + uint256 hashTarget = CBigNum().SetCompact(block.nBits).getuint256(); + while (block.GetHash() > hashTarget) + { + ++block.nNonce; + if (block.nNonce == 0) + { + printf("NONCE WRAPPED, incrementing time"); + ++block.nTime; + } + } + } + + //// debug print + block.print(); + printf("block.GetHash() == %s\n", block.GetHash().ToString().c_str()); + printf("block.hashMerkleRoot == %s\n", block.hashMerkleRoot.ToString().c_str()); + printf("block.nTime = %u \n", block.nTime); + printf("block.nNonce = %u \n", block.nNonce); + + assert(block.hashMerkleRoot == uint256("0x27f77273afc4e7cca700b8564eed9a7cc7ee38e81189a8d57a98bc42f848d51e")); + assert(block.GetHash() == (!fTestNet ? hashGenesisBlock : hashGenesisBlockTestNet)); + + // Start new block file + unsigned int nFile; + unsigned int nBlockPos; + if (!block.WriteToDisk(nFile, nBlockPos)) + return error("LoadBlockIndex() : writing genesis block to disk failed"); + if (!block.AddToBlockIndex(nFile, nBlockPos)) + return error("LoadBlockIndex() : genesis block not accepted"); + + // triangles: initialize synchronized checkpoint + if (!Checkpoints::WriteSyncCheckpoint((!fTestNet ? hashGenesisBlock : hashGenesisBlockTestNet))) + return error("LoadBlockIndex() : failed to init sync checkpoint"); + } + + // triangles: if checkpoint master key changed must reset sync-checkpoint + { + CTxDB txdb; + string strPubKey = ""; + if (!txdb.ReadCheckpointPubKey(strPubKey) || strPubKey != CSyncCheckpoint::strMasterPubKey) + { + // write checkpoint master key to db + txdb.TxnBegin(); + if (!txdb.WriteCheckpointPubKey(CSyncCheckpoint::strMasterPubKey)) + return error("LoadBlockIndex() : failed to write new checkpoint master key to db"); + if (!txdb.TxnCommit()) + return error("LoadBlockIndex() : failed to commit new checkpoint master key to db"); + if ((!fTestNet) && !Checkpoints::ResetSyncCheckpoint()) + return error("LoadBlockIndex() : failed to reset sync-checkpoint"); + } + txdb.Close(); + } + + return true; +} + + + +void PrintBlockTree() +{ + // pre-compute tree structure + map > mapNext; + for (map::iterator mi = mapBlockIndex.begin(); mi != mapBlockIndex.end(); ++mi) + { + CBlockIndex* pindex = (*mi).second; + mapNext[pindex->pprev].push_back(pindex); + // test + //while (rand() % 3 == 0) + // mapNext[pindex->pprev].push_back(pindex); + } + + vector > vStack; + vStack.push_back(make_pair(0, pindexGenesisBlock)); + + int nPrevCol = 0; + while (!vStack.empty()) + { + int nCol = vStack.back().first; + CBlockIndex* pindex = vStack.back().second; + vStack.pop_back(); + + // print split or gap + if (nCol > nPrevCol) + { + for (int i = 0; i < nCol-1; i++) + printf("| "); + printf("|\\\n"); + } + else if (nCol < nPrevCol) + { + for (int i = 0; i < nCol; i++) + printf("| "); + printf("|\n"); + } + nPrevCol = nCol; + + // print columns + for (int i = 0; i < nCol; i++) + printf("| "); + + // print item + CBlock block; + block.ReadFromDisk(pindex); + printf("%d (%u,%u) %s %08x %s mint %7s tx %"PRIszu"", + pindex->nHeight, + pindex->nFile, + pindex->nBlockPos, + block.GetHash().ToString().c_str(), + block.nBits, + DateTimeStrFormat("%x %H:%M:%S", block.GetBlockTime()).c_str(), + FormatMoney(pindex->nMint).c_str(), + block.vtx.size()); + + PrintWallets(block); + + // put the main time-chain first + vector& vNext = mapNext[pindex]; + for (unsigned int i = 0; i < vNext.size(); i++) + { + if (vNext[i]->pnext) + { + swap(vNext[0], vNext[i]); + break; + } + } + + // iterate children + for (unsigned int i = 0; i < vNext.size(); i++) + vStack.push_back(make_pair(nCol+i, vNext[i])); + } +} + +bool LoadExternalBlockFile(FILE* fileIn) +{ + int64 nStart = GetTimeMillis(); + + int nLoaded = 0; + { + LOCK(cs_main); + try { + CAutoFile blkdat(fileIn, SER_DISK, CLIENT_VERSION); + unsigned int nPos = 0; + while (nPos != (unsigned int)-1 && blkdat.good() && !fRequestShutdown) + { + unsigned char pchData[65536]; + do { + fseek(blkdat, nPos, SEEK_SET); + int nRead = fread(pchData, 1, sizeof(pchData), blkdat); + if (nRead <= 8) + { + nPos = (unsigned int)-1; + break; + } + void* nFind = memchr(pchData, pchMessageStart[0], nRead+1-sizeof(pchMessageStart)); + if (nFind) + { + if (memcmp(nFind, pchMessageStart, sizeof(pchMessageStart))==0) + { + nPos += ((unsigned char*)nFind - pchData) + sizeof(pchMessageStart); + break; + } + nPos += ((unsigned char*)nFind - pchData) + 1; + } + else + nPos += sizeof(pchData) - sizeof(pchMessageStart) + 1; + } while(!fRequestShutdown); + if (nPos == (unsigned int)-1) + break; + fseek(blkdat, nPos, SEEK_SET); + unsigned int nSize; + blkdat >> nSize; + if (nSize > 0 && nSize <= MAX_BLOCK_SIZE) + { + CBlock block; + blkdat >> block; + if (ProcessBlock(NULL,&block)) + { + nLoaded++; + nPos += 4 + nSize; + } + } + } + } + catch (std::exception &e) { + printf("%s() : Deserialize or I/O error caught during load\n", + __PRETTY_FUNCTION__); + } + } + printf("Loaded %i blocks from external file in %"PRI64d"ms\n", nLoaded, GetTimeMillis() - nStart); + return nLoaded > 0; +} + + + + +////////////////////////////////////////////////////////////////////////////// +// +// CAlert +// + +extern map mapAlerts; +extern CCriticalSection cs_mapAlerts; + +string GetWarnings(string strFor) +{ + int nPriority = 0; + string strStatusBar; + string strRPC; + + if (GetBoolArg("-testsafemode")) + strRPC = "test"; + + // Misc warnings like out of disk space and clock is wrong + if (strMiscWarning != "") + { + nPriority = 1000; + strStatusBar = strMiscWarning; + } + + // triangles: should not enter safe mode for longer invalid chain + // triangles: if sync-checkpoint is too old do not enter safe mode + if (Checkpoints::IsSyncCheckpointTooOld(60 * 60 * 24 * 365) && !fTestNet && !IsInitialBlockDownload()) + { + nPriority = 100; + strStatusBar = "WARNING: Checkpoint is too old. Wait for block chain to download, or notify developers."; + } + + // triangles: if detected invalid checkpoint enter safe mode + if (Checkpoints::hashInvalidCheckpoint != 0) + { + nPriority = 3000; + strStatusBar = strRPC = "WARNING: Invalid checkpoint found! Displayed transactions may not be correct! You may need to upgrade, or notify developers."; + } + + // Alerts + { + LOCK(cs_mapAlerts); + BOOST_FOREACH(PAIRTYPE(const uint256, CAlert)& item, mapAlerts) + { + const CAlert& alert = item.second; + if (alert.AppliesToMe() && alert.nPriority > nPriority) + { + nPriority = alert.nPriority; + strStatusBar = alert.strStatusBar; + if (nPriority > 1000) + strRPC = strStatusBar; // triangles: safe mode for high alert + } + } + } + + if (strFor == "statusbar") + return strStatusBar; + else if (strFor == "rpc") + return strRPC; + assert(!"GetWarnings() : invalid parameter"); + return "error"; +} + + + + +////////////////////////////////////////////////////////////////////////////// +// +// Messages +// + + +bool static AlreadyHave(CTxDB& txdb, const CInv& inv) +{ + switch (inv.type) + { + case MSG_TX: + { + bool txInMap = false; + { + LOCK(mempool.cs); + txInMap = (mempool.exists(inv.hash)); + } + return txInMap || + mapOrphanTransactions.count(inv.hash) || + txdb.ContainsTx(inv.hash); + } + + case MSG_BLOCK: + return mapBlockIndex.count(inv.hash) || + mapOrphanBlocks.count(inv.hash); + } + // Don't know what it is, just say we already got one + return true; +} + + + + +// The message start string is designed to be unlikely to occur in normal data. +// The characters are rarely used upper ASCII, not valid as UTF-8, and produce +// a large 4-byte int at any alignment. +unsigned char pchMessageStart[4] = { 0x70, 0x35, 0x22, 0x05 }; + +bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) +{ + static map mapReuseKey; + RandAddSeedPerfmon(); + if (fDebug) + printf("received: %s (%"PRIszu" bytes)\n", strCommand.c_str(), vRecv.size()); + if (mapArgs.count("-dropmessagestest") && GetRand(atoi(mapArgs["-dropmessagestest"])) == 0) + { + printf("dropmessagestest DROPPING RECV MESSAGE\n"); + return true; + } + + if (strCommand == "version") + { + // Each connection can only send one version message + if (pfrom->nVersion != 0) + { + pfrom->Misbehaving(1); + return false; + } + + int64 nTime; + CAddress addrMe; + CAddress addrFrom; + uint64 nNonce = 1; + uint64 verification_token = 0; + vRecv >> pfrom->nVersion >> pfrom->nServices >> nTime >> addrMe; + if (pfrom->nVersion < MIN_PROTO_VERSION) + { + // Since February 20, 2012, the protocol is initiated at version 209, + // and earlier versions are no longer supported + printf("partner %s using obsolete version %i; disconnecting\n", pfrom->addr.ToString().c_str(), pfrom->nVersion); + pfrom->fDisconnect = true; + return false; + } + + if (pfrom->nVersion == 10300) + pfrom->nVersion = 300; + if (!vRecv.empty()) + vRecv >> addrFrom >> verification_token >> nNonce; + if (!vRecv.empty()) { + vRecv >> pfrom->strSubVer; + pfrom->cleanSubVer = SanitizeString(pfrom->strSubVer); + } + if (!vRecv.empty()) + vRecv >> pfrom->nStartingHeight; + + // if (!vRecv.empty()) + // // set to true after we get the first filter* message + // vRecv >> pfrom->fRelayTxes; + // else + // pfrom->fRelayTxes = true; + + if (pfrom->fInbound && addrMe.IsRoutable()) + { + pfrom->addrLocal = addrMe; + SeenLocal(addrMe); + } + + // Disconnect if we connected to ourself + if (nNonce == nLocalHostNonce && nNonce > 1) + { + printf("connected to self at %s, disconnecting\n", pfrom->addr.ToString().c_str()); + pfrom->fDisconnect = true; + return true; + } + + // triangles: record my external IP reported by peer + if (addrFrom.IsRoutable() && addrMe.IsRoutable()) + addrSeenByPeer = addrMe; + + // Be shy and don't send version until we hear + if (pfrom->fInbound) + pfrom->PushVersion(); + + pfrom->fClient = !(pfrom->nServices & NODE_NETWORK); + + AddTimeData(pfrom->addr, nTime); + + // Change version + pfrom->PushMessage("verack"); + pfrom->vSend.SetVersion(min(pfrom->nVersion, PROTOCOL_VERSION)); + + if (!pfrom->fInbound) + { + // Advertise our address + if (!IsInitialBlockDownload()) + { + CAddress addr = GetLocalAddress(&pfrom->addr); + if (addr.IsRoutable()) + pfrom->PushAddress(addr); + } + + // Get recent addresses + if (pfrom->fOneShot || pfrom->nVersion >= CADDR_TIME_VERSION || addrman.size() < 1000) + { + pfrom->PushMessage("getaddr"); + pfrom->fGetAddr = true; + } + addrman.Good(pfrom->addr); + } else { + addrFrom.SetPort(GetDefaultPort()); + pfrom->addr = addrFrom; + if (CNode::IsBanned(addrFrom)) + { + printf("connection from %s dropped (banned)\n", addrFrom.ToString().c_str()); + pfrom->fDisconnect = true; + return true; + } + if (addrman.CheckVerificationToken(addrFrom, verification_token)) { + printf("connection from %s verified\n", addrFrom.ToString().c_str()); + pfrom->fVerified = true; + addrman.Good(pfrom->addr); + } else { + printf("couldn't verify %s\n", addrFrom.ToString().c_str()); + addrman.SetReconnectToken(addrFrom, verification_token); + } + + } + + // Ask the first connected node for block updates + static int nAskedForBlocks = 0; + if (!pfrom->fClient && !pfrom->fOneShot && + (pfrom->nStartingHeight > (nBestHeight - 144)) && + (pfrom->nVersion < NOBLKS_VERSION_START || + pfrom->nVersion >= NOBLKS_VERSION_END) && + (nAskedForBlocks < 1 || vNodes.size() <= 1)) + { + nAskedForBlocks++; + pfrom->PushGetBlocks(pindexBest, uint256(0)); + } + + // Relay alerts + { + LOCK(cs_mapAlerts); + BOOST_FOREACH(PAIRTYPE(const uint256, CAlert)& item, mapAlerts) + item.second.RelayTo(pfrom); + } + + // triangles: relay sync-checkpoint + { + LOCK(Checkpoints::cs_hashSyncCheckpoint); + if (!Checkpoints::checkpointMessage.IsNull()) + Checkpoints::checkpointMessage.RelayTo(pfrom); + } + + pfrom->fSuccessfullyConnected = true; + + printf("receive version message: version %d, blocks=%d, us=%s, them=%s, peer=%s\n", pfrom->nVersion, pfrom->nStartingHeight, addrMe.ToString().c_str(), addrFrom.ToString().c_str(), pfrom->addr.ToString().c_str()); + + cPeerBlockCounts.input(pfrom->nStartingHeight); + + // triangles: ask for pending sync-checkpoint if any + if (!IsInitialBlockDownload()) + Checkpoints::AskForPendingSyncCheckpoint(pfrom); + } + + + else if (pfrom->nVersion == 0) + { + // Must have a version message before anything else + pfrom->Misbehaving(1); + return false; + } + + + else if (strCommand == "verack") + { + pfrom->vRecv.SetVersion(min(pfrom->nVersion, PROTOCOL_VERSION)); + } + + + else if (strCommand == "addr") + { + vector vAddr; + vRecv >> vAddr; + + // Don't want addr from older versions unless seeding + if (pfrom->nVersion < CADDR_TIME_VERSION && addrman.size() > 1000) + return true; + if (vAddr.size() > 1000) + { + pfrom->Misbehaving(20); + return error("message addr size() = %"PRIszu"", vAddr.size()); + } + + // Store the new addresses + vector vAddrOk; + int64 nNow = GetAdjustedTime(); + int64 nSince = nNow - 10 * 60; + BOOST_FOREACH(CAddress& addr, vAddr) + { + if (fShutdown) + return true; + if (addr.nTime <= 100000000 || addr.nTime > nNow + 10 * 60) + addr.nTime = nNow - 5 * 24 * 60 * 60; + pfrom->AddAddressKnown(addr); + bool fReachable = IsReachable(addr); + if (addr.nTime > nSince && !pfrom->fGetAddr && vAddr.size() <= 10 && addr.IsRoutable()) + { + // Relay to a limited number of other nodes + { + LOCK(cs_vNodes); + // Use deterministic randomness to send to the same nodes for 24 hours + // at a time so the setAddrKnowns of the chosen nodes prevent repeats + static uint256 hashSalt; + if (hashSalt == 0) + hashSalt = GetRandHash(); + uint64 hashAddr = addr.GetHash(); + uint256 hashRand = hashSalt ^ (hashAddr<<32) ^ ((GetTime()+hashAddr)/(24*60*60)); + hashRand = Hash(BEGIN(hashRand), END(hashRand)); + multimap mapMix; + BOOST_FOREACH(CNode* pnode, vNodes) + { + if (pnode->nVersion < CADDR_TIME_VERSION) + continue; + unsigned int nPointer; + memcpy(&nPointer, &pnode, sizeof(nPointer)); + uint256 hashKey = hashRand ^ nPointer; + hashKey = Hash(BEGIN(hashKey), END(hashKey)); + mapMix.insert(make_pair(hashKey, pnode)); + } + int nRelayNodes = fReachable ? 2 : 1; // limited relaying of addresses outside our network(s) + for (multimap::iterator mi = mapMix.begin(); mi != mapMix.end() && nRelayNodes-- > 0; ++mi) + ((*mi).second)->PushAddress(addr); + } + } + // Do not store addresses outside our network + if (fReachable) + vAddrOk.push_back(addr); + } + addrman.Add(vAddrOk, pfrom->addr, 2 * 60 * 60); + if (vAddr.size() < 1000) + pfrom->fGetAddr = false; + if (pfrom->fOneShot) + pfrom->fDisconnect = true; + } + + + else if (strCommand == "inv") + { + vector vInv; + vRecv >> vInv; + if (vInv.size() > MAX_INV_SZ) + { + pfrom->Misbehaving(20); + return error("message inv size() = %"PRIszu"", vInv.size()); + } + + // find last block in inv vector + unsigned int nLastBlock = (unsigned int)(-1); + for (unsigned int nInv = 0; nInv < vInv.size(); nInv++) { + if (vInv[vInv.size() - 1 - nInv].type == MSG_BLOCK) { + nLastBlock = vInv.size() - 1 - nInv; + break; + } + } + CTxDB txdb("r"); + for (unsigned int nInv = 0; nInv < vInv.size(); nInv++) + { + const CInv &inv = vInv[nInv]; + + if (fShutdown) + return true; + pfrom->AddInventoryKnown(inv); + + bool fAlreadyHave = AlreadyHave(txdb, inv); + if (fDebug) + printf(" got inventory: %s %s\n", inv.ToString().c_str(), fAlreadyHave ? "have" : "new"); + + if (!fAlreadyHave) + pfrom->AskFor(inv); + else if (inv.type == MSG_BLOCK && mapOrphanBlocks.count(inv.hash)) { + pfrom->PushGetBlocks(pindexBest, GetOrphanRoot(mapOrphanBlocks[inv.hash])); + } else if (nInv == nLastBlock) { + // In case we are on a very long side-chain, it is possible that we already have + // the last block in an inv bundle sent in response to getblocks. Try to detect + // this situation and push another getblocks to continue. + pfrom->PushGetBlocks(mapBlockIndex[inv.hash], uint256(0)); + if (fDebug) + printf("force request: %s\n", inv.ToString().c_str()); + } + + // Track requests for our stuff + Inventory(inv.hash); + } + } + + + else if (strCommand == "getdata") + { + vector vInv; + vRecv >> vInv; + if (vInv.size() > MAX_INV_SZ) + { + pfrom->Misbehaving(20); + return error("message getdata size() = %"PRIszu"", vInv.size()); + } + + if (fDebugNet || (vInv.size() != 1)) + printf("received getdata (%"PRIszu" invsz)\n", vInv.size()); + + BOOST_FOREACH(const CInv& inv, vInv) + { + if (fShutdown) + return true; + if (fDebugNet || (vInv.size() == 1)) + printf("received getdata for: %s\n", inv.ToString().c_str()); + + if (inv.type == MSG_BLOCK) + { + // Send block from disk + map::iterator mi = mapBlockIndex.find(inv.hash); + if (mi != mapBlockIndex.end()) + { + CBlock block; + block.ReadFromDisk((*mi).second); + pfrom->PushMessage("block", block); + + // Trigger them to send a getblocks request for the next batch of inventory + if (inv.hash == pfrom->hashContinue) + { + // triangles: send latest proof-of-work block to allow the + // download node to accept as orphan (proof-of-stake + // block might be rejected by stake connection check) + vector vInv; + vInv.push_back(CInv(MSG_BLOCK, GetLastBlockIndex(pindexBest, false)->GetBlockHash())); + pfrom->PushMessage("inv", vInv); + pfrom->hashContinue = 0; + } + } + } + else if (inv.IsKnownType()) + { + // Send stream from relay memory + bool pushed = false; + { + LOCK(cs_mapRelay); + map::iterator mi = mapRelay.find(inv); + if (mi != mapRelay.end()) { + pfrom->PushMessage(inv.GetCommand(), (*mi).second); + pushed = true; + } + } + if (!pushed && inv.type == MSG_TX) { + LOCK(mempool.cs); + if (mempool.exists(inv.hash)) { + CTransaction tx = mempool.lookup(inv.hash); + CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); + ss.reserve(1000); + ss << tx; + pfrom->PushMessage("tx", ss); + } + } + } + + // Track requests for our stuff + Inventory(inv.hash); + } + } + + + else if (strCommand == "getblocks") + { + CBlockLocator locator; + uint256 hashStop; + vRecv >> locator >> hashStop; + + // Find the last block the caller has in the main chain + CBlockIndex* pindex = locator.GetBlockIndex(); + + // Send the rest of the chain + if (pindex) + pindex = pindex->pnext; + int nLimit = 500; + printf("getblocks %d to %s limit %d\n", (pindex ? pindex->nHeight : -1), hashStop.ToString().substr(0,20).c_str(), nLimit); + for (; pindex; pindex = pindex->pnext) + { + if (pindex->GetBlockHash() == hashStop) + { + printf(" getblocks stopping at %d %s\n", pindex->nHeight, pindex->GetBlockHash().ToString().substr(0,20).c_str()); + // triangles: tell downloading node about the latest block if it's + // without risk being rejected due to stake connection check + if (hashStop != hashBestChain && pindex->GetBlockTime() + nStakeMinAge > pindexBest->GetBlockTime()) + pfrom->PushInventory(CInv(MSG_BLOCK, hashBestChain)); + break; + } + pfrom->PushInventory(CInv(MSG_BLOCK, pindex->GetBlockHash())); + if (--nLimit <= 0) + { + // When this block is requested, we'll send an inv that'll make them + // getblocks the next batch of inventory. + printf(" getblocks stopping at limit %d %s\n", pindex->nHeight, pindex->GetBlockHash().ToString().substr(0,20).c_str()); + pfrom->hashContinue = pindex->GetBlockHash(); + break; + } + } + } + else if (strCommand == "checkpoint") + { + CSyncCheckpoint checkpoint; + vRecv >> checkpoint; + + if (checkpoint.ProcessSyncCheckpoint(pfrom)) + { + // Relay + pfrom->hashCheckpointKnown = checkpoint.hashCheckpoint; + LOCK(cs_vNodes); + BOOST_FOREACH(CNode* pnode, vNodes) + checkpoint.RelayTo(pnode); + } + } + + else if (strCommand == "getheaders") + { + CBlockLocator locator; + uint256 hashStop; + vRecv >> locator >> hashStop; + + CBlockIndex* pindex = NULL; + if (locator.IsNull()) + { + // If locator is null, return the hashStop block + map::iterator mi = mapBlockIndex.find(hashStop); + if (mi == mapBlockIndex.end()) + return true; + pindex = (*mi).second; + } + else + { + // Find the last block the caller has in the main chain + pindex = locator.GetBlockIndex(); + if (pindex) + pindex = pindex->pnext; + } + + vector vHeaders; + int nLimit = 2000; + printf("getheaders %d to %s\n", (pindex ? pindex->nHeight : -1), hashStop.ToString().substr(0,20).c_str()); + for (; pindex; pindex = pindex->pnext) + { + vHeaders.push_back(pindex->GetBlockHeader()); + if (--nLimit <= 0 || pindex->GetBlockHash() == hashStop) + break; + } + pfrom->PushMessage("headers", vHeaders); + } + + + else if (strCommand == "tx") + { + vector vWorkQueue; + vector vEraseQueue; + CDataStream vMsg(vRecv); + CTxDB txdb("r"); + CTransaction tx; + vRecv >> tx; + + CInv inv(MSG_TX, tx.GetHash()); + pfrom->AddInventoryKnown(inv); + + bool fMissingInputs = false; + if (tx.AcceptToMemoryPool(txdb, true, &fMissingInputs)) + { + SyncWithWallets(tx, NULL, true); + RelayMessage(inv, vMsg); + mapAlreadyAskedFor.erase(inv); + vWorkQueue.push_back(inv.hash); + vEraseQueue.push_back(inv.hash); + + // Recursively process any orphan transactions that depended on this one + for (unsigned int i = 0; i < vWorkQueue.size(); i++) + { + uint256 hashPrev = vWorkQueue[i]; + for (map::iterator mi = mapOrphanTransactionsByPrev[hashPrev].begin(); + mi != mapOrphanTransactionsByPrev[hashPrev].end(); + ++mi) + { + const CDataStream& vMsg = *((*mi).second); + CTransaction tx; + CDataStream(vMsg) >> tx; + CInv inv(MSG_TX, tx.GetHash()); + bool fMissingInputs2 = false; + + if (tx.AcceptToMemoryPool(txdb, true, &fMissingInputs2)) + { + printf(" accepted orphan tx %s\n", inv.hash.ToString().substr(0,10).c_str()); + SyncWithWallets(tx, NULL, true); + RelayMessage(inv, vMsg); + mapAlreadyAskedFor.erase(inv); + vWorkQueue.push_back(inv.hash); + vEraseQueue.push_back(inv.hash); + } + else if (!fMissingInputs2) + { + // invalid orphan + vEraseQueue.push_back(inv.hash); + printf(" removed invalid orphan tx %s\n", inv.hash.ToString().substr(0,10).c_str()); + } + } + } + + BOOST_FOREACH(uint256 hash, vEraseQueue) + EraseOrphanTx(hash); + } + else if (fMissingInputs) + { + AddOrphanTx(vMsg); + + // DoS prevention: do not allow mapOrphanTransactions to grow unbounded + unsigned int nEvicted = LimitOrphanTxSize(MAX_ORPHAN_TRANSACTIONS); + if (nEvicted > 0) + printf("mapOrphan overflow, removed %u tx\n", nEvicted); + } + if (tx.nDoS) pfrom->Misbehaving(tx.nDoS); + } + + + else if (strCommand == "block") + { + CBlock block; + vRecv >> block; + + printf("received block %s\n", block.GetHash().ToString().substr(0,20).c_str()); + // block.print(); + + CInv inv(MSG_BLOCK, block.GetHash()); + pfrom->AddInventoryKnown(inv); + + if (ProcessBlock(pfrom, &block)) + mapAlreadyAskedFor.erase(inv); + if (block.nDoS) pfrom->Misbehaving(block.nDoS); + } + + + else if (strCommand == "getaddr") + { + pfrom->vAddrToSend.clear(); + vector vAddr = addrman.GetAddr(); + BOOST_FOREACH(const CAddress &addr, vAddr) + pfrom->PushAddress(addr); + } + + + else if (strCommand == "mempool") + { + std::vector vtxid; + mempool.queryHashes(vtxid); + vector vInv; + for (unsigned int i = 0; i < vtxid.size(); i++) { + CInv inv(MSG_TX, vtxid[i]); + vInv.push_back(inv); + if (i == (MAX_INV_SZ - 1)) + break; + } + if (vInv.size() > 0) + pfrom->PushMessage("inv", vInv); + } + + + else if (strCommand == "checkorder") + { + uint256 hashReply; + vRecv >> hashReply; + + if (!GetBoolArg("-allowreceivebyip")) + { + pfrom->PushMessage("reply", hashReply, (int)2, string("")); + return true; + } + + CWalletTx order; + vRecv >> order; + + /// we have a chance to check the order here + + // Keep giving the same key to the same ip until they use it + if (!mapReuseKey.count(pfrom->addr)) + pwalletMain->GetKeyFromPool(mapReuseKey[pfrom->addr], true); + + // Send back approval of order and pubkey to use + CScript scriptPubKey; + scriptPubKey << mapReuseKey[pfrom->addr] << OP_CHECKSIG; + pfrom->PushMessage("reply", hashReply, (int)0, scriptPubKey); + } + + + else if (strCommand == "reply") + { + uint256 hashReply; + vRecv >> hashReply; + + CRequestTracker tracker; + { + LOCK(pfrom->cs_mapRequests); + map::iterator mi = pfrom->mapRequests.find(hashReply); + if (mi != pfrom->mapRequests.end()) + { + tracker = (*mi).second; + pfrom->mapRequests.erase(mi); + } + } + if (!tracker.IsNull()) + tracker.fn(tracker.param1, vRecv); + } + + + else if (strCommand == "ping") + { + if (pfrom->nVersion > BIP0031_VERSION) + { + uint64 nonce = 0; + vRecv >> nonce; + // Echo the message back with the nonce. This allows for two useful features: + // + // 1) A remote node can quickly check if the connection is operational + // 2) Remote nodes can measure the latency of the network thread. If this node + // is overloaded it won't respond to pings quickly and the remote node can + // avoid sending us more work, like chain download requests. + // + // The nonce stops the remote getting confused between different pings: without + // it, if the remote node sends a ping once per second and this node takes 5 + // seconds to respond to each, the 5th ping the remote sends would appear to + // return very quickly. + pfrom->PushMessage("pong", nonce); + } + } + + + else if (strCommand == "alert") + { + CAlert alert; + vRecv >> alert; + + uint256 alertHash = alert.GetHash(); + if (pfrom->setKnown.count(alertHash) == 0) + { + if (alert.ProcessAlert()) + { + // Relay + pfrom->setKnown.insert(alertHash); + { + LOCK(cs_vNodes); + BOOST_FOREACH(CNode* pnode, vNodes) + alert.RelayTo(pnode); + } + } + else { + // Small DoS penalty so peers that send us lots of + // duplicate/expired/invalid-signature/whatever alerts + // eventually get banned. + // This isn't a Misbehaving(100) (immediate ban) because the + // peer might be an older or different implementation with + // a different signature key, etc. + pfrom->Misbehaving(10); + } + } + } + + + else + { + // Ignore unknown commands for extensibility + } + + + // Update the last seen time for this node's address + if (pfrom->fNetworkNode) + if (strCommand == "version" || strCommand == "addr" || strCommand == "inv" || strCommand == "getdata" || strCommand == "ping") + AddressCurrentlyConnected(pfrom->addr); + + + return true; +} + +bool ProcessMessages(CNode* pfrom) +{ + if (fDebug) { + printf("ProcessMessages: %s\n", + pfrom->addr.ToString().c_str()); + } + CDataStream& vRecv = pfrom->vRecv; + if (vRecv.empty()) { + if (fDebug) { + printf("ProcessMessages: %s message empty\n", + pfrom->addr.ToString().c_str()); + } + return true; + } + //if (fDebug) + // printf("ProcessMessages(%u bytes)\n", vRecv.size()); + + // + // Message format + // (4) message start + // (12) command + // (4) size + // (4) checksum + // (x) data + // + + loop + { + // Don't bother if send buffer is too full to respond anyway + if (pfrom->vSend.size() >= SendBufferSize()) + break; + + // Scan for message start + CDataStream::iterator pstart = search(vRecv.begin(), vRecv.end(), BEGIN(pchMessageStart), END(pchMessageStart)); + int nHeaderSize = vRecv.GetSerializeSize(CMessageHeader()); + if (vRecv.end() - pstart < nHeaderSize) + { + if ((int)vRecv.size() > nHeaderSize) + { + printf("\n\nPROCESSMESSAGE MESSAGESTART NOT FOUND\n\n"); + vRecv.erase(vRecv.begin(), vRecv.end() - nHeaderSize); + } + break; + } + if (pstart - vRecv.begin() > 0) + printf("\n\nPROCESSMESSAGE SKIPPED %"PRIpdd" BYTES\n\n", pstart - vRecv.begin()); + vRecv.erase(vRecv.begin(), pstart); + + // Read header + vector vHeaderSave(vRecv.begin(), vRecv.begin() + nHeaderSize); + CMessageHeader hdr; + vRecv >> hdr; + if (!hdr.IsValid()) + { + printf("\n\nPROCESSMESSAGE: ERRORS IN HEADER %s\n\n\n", hdr.GetCommand().c_str()); + continue; + } + string strCommand = hdr.GetCommand(); + + // Message size + unsigned int nMessageSize = hdr.nMessageSize; + if (nMessageSize > MAX_SIZE) + { + printf("ProcessMessages(%s, %u bytes) : nMessageSize > MAX_SIZE\n", strCommand.c_str(), nMessageSize); + continue; + } + if (nMessageSize > vRecv.size()) + { + // Rewind and wait for rest of message + vRecv.insert(vRecv.begin(), vHeaderSave.begin(), vHeaderSave.end()); + break; + } + + // Checksum + uint256 hash = Hash(vRecv.begin(), vRecv.begin() + nMessageSize); + unsigned int nChecksum = 0; + memcpy(&nChecksum, &hash, sizeof(nChecksum)); + if (nChecksum != hdr.nChecksum) + { + printf("ProcessMessages(%s, %u bytes) : CHECKSUM ERROR nChecksum=%08x hdr.nChecksum=%08x\n", + strCommand.c_str(), nMessageSize, nChecksum, hdr.nChecksum); + continue; + } + + // Copy message to its own buffer + CDataStream vMsg(vRecv.begin(), vRecv.begin() + nMessageSize, vRecv.nType, vRecv.nVersion); + vRecv.ignore(nMessageSize); + + // Process message + bool fRet = false; + try + { + { + LOCK(cs_main); + fRet = ProcessMessage(pfrom, strCommand, vMsg); + } + if (fShutdown) + return true; + } + catch (std::ios_base::failure& e) + { + if (strstr(e.what(), "end of data")) + { + // Allow exceptions from under-length message on vRecv + printf("ProcessMessages(%s, %u bytes) : Exception '%s' caught, normally caused by a message being shorter than its stated length\n", strCommand.c_str(), nMessageSize, e.what()); + } + else if (strstr(e.what(), "size too large")) + { + // Allow exceptions from over-long size + printf("ProcessMessages(%s, %u bytes) : Exception '%s' caught\n", strCommand.c_str(), nMessageSize, e.what()); + } + else + { + PrintExceptionContinue(&e, "ProcessMessages()"); + } + } + catch (std::exception& e) { + PrintExceptionContinue(&e, "ProcessMessages()"); + } catch (...) { + PrintExceptionContinue(NULL, "ProcessMessages()"); + } + + if (!fRet) + printf("ProcessMessage(%s, %u bytes) FAILED\n", strCommand.c_str(), nMessageSize); + } + + vRecv.Compact(); + return true; +} + + +bool SendMessages(CNode* pto, bool fSendTrickle) +{ + TRY_LOCK(cs_main, lockMain); + if (lockMain) { + // Don't send anything until we get their version message + if (pto->nVersion == 0) + return true; + + // Keep-alive ping. We send a nonce of zero because we don't use it anywhere + // right now. + if (pto->nLastSend && GetTime() - pto->nLastSend > 30 * 60 && pto->vSend.empty()) { + uint64 nonce = 0; + if (pto->nVersion > BIP0031_VERSION) + pto->PushMessage("ping", nonce); + else + pto->PushMessage("ping"); + } + + // Resend wallet transactions that haven't gotten in a block yet + ResendWalletTransactions(); + + // Address refresh broadcast + static int64 nLastRebroadcast; + if (!IsInitialBlockDownload() && (GetTime() - nLastRebroadcast > 24 * 60 * 60)) + { + { + LOCK(cs_vNodes); + BOOST_FOREACH(CNode* pnode, vNodes) + { + // Periodically clear setAddrKnown to allow refresh broadcasts + if (nLastRebroadcast) + pnode->setAddrKnown.clear(); + + // Rebroadcast our address + if (true) + { + CAddress addr = GetLocalAddress(&pnode->addr); + if (addr.IsRoutable()) + pnode->PushAddress(addr); + } + } + } + nLastRebroadcast = GetTime(); + } + + // + // Message: addr + // + if (fSendTrickle) + { + vector vAddr; + vAddr.reserve(pto->vAddrToSend.size()); + BOOST_FOREACH(const CAddress& addr, pto->vAddrToSend) + { + // returns true if wasn't already contained in the set + if (pto->setAddrKnown.insert(addr).second) + { + vAddr.push_back(addr); + // receiver rejects addr messages larger than 1000 + if (vAddr.size() >= 1000) + { + pto->PushMessage("addr", vAddr); + vAddr.clear(); + } + } + } + pto->vAddrToSend.clear(); + if (!vAddr.empty()) + pto->PushMessage("addr", vAddr); + } + + + // + // Message: inventory + // + vector vInv; + vector vInvWait; + { + LOCK(pto->cs_inventory); + vInv.reserve(pto->vInventoryToSend.size()); + vInvWait.reserve(pto->vInventoryToSend.size()); + BOOST_FOREACH(const CInv& inv, pto->vInventoryToSend) + { + if (pto->setInventoryKnown.count(inv)) + continue; + + // trickle out tx inv to protect privacy + if (inv.type == MSG_TX && !fSendTrickle) + { + // 1/4 of tx invs blast to all immediately + static uint256 hashSalt; + if (hashSalt == 0) + hashSalt = GetRandHash(); + uint256 hashRand = inv.hash ^ hashSalt; + hashRand = Hash(BEGIN(hashRand), END(hashRand)); + bool fTrickleWait = ((hashRand & 3) != 0); + + // always trickle our own transactions + if (!fTrickleWait) + { + CWalletTx wtx; + if (GetTransaction(inv.hash, wtx)) + if (wtx.fFromMe) + fTrickleWait = true; + } + + if (fTrickleWait) + { + vInvWait.push_back(inv); + continue; + } + } + + // returns true if wasn't already contained in the set + if (pto->setInventoryKnown.insert(inv).second) + { + vInv.push_back(inv); + if (vInv.size() >= 1000) + { + pto->PushMessage("inv", vInv); + vInv.clear(); + } + } + } + pto->vInventoryToSend = vInvWait; + } + if (!vInv.empty()) + pto->PushMessage("inv", vInv); + + + // + // Message: getdata + // + vector vGetData; + int64 nNow = GetTime() * 1000000; + CTxDB txdb("r"); + while (!pto->mapAskFor.empty() && (*pto->mapAskFor.begin()).first <= nNow) + { + const CInv& inv = (*pto->mapAskFor.begin()).second; + if (!AlreadyHave(txdb, inv)) + { + if (fDebugNet) + printf("sending getdata: %s\n", inv.ToString().c_str()); + vGetData.push_back(inv); + if (vGetData.size() >= 1000) + { + pto->PushMessage("getdata", vGetData); + vGetData.clear(); + } + mapAlreadyAskedFor[inv] = nNow; + } + pto->mapAskFor.erase(pto->mapAskFor.begin()); + } + if (!vGetData.empty()) + pto->PushMessage("getdata", vGetData); + + } + return true; +} + + + + + +////////////////////////////////////////////////////////////////////////////// +// +// BitcoinMiner +// + +int static FormatHashBlocks(void* pbuffer, unsigned int len) +{ + unsigned char* pdata = (unsigned char*)pbuffer; + unsigned int blocks = 1 + ((len + 8) / 64); + unsigned char* pend = pdata + 64 * blocks; + memset(pdata + len, 0, 64 * blocks - len); + pdata[len] = 0x80; + unsigned int bits = len * 8; + pend[-1] = (bits >> 0) & 0xff; + pend[-2] = (bits >> 8) & 0xff; + pend[-3] = (bits >> 16) & 0xff; + pend[-4] = (bits >> 24) & 0xff; + return blocks; +} + +static const unsigned int pSHA256InitState[8] = +{0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19}; + +void SHA256Transform(void* pstate, void* pinput, const void* pinit) +{ + SHA256_CTX ctx; + unsigned char data[64]; + + SHA256_Init(&ctx); + + for (int i = 0; i < 16; i++) + ((uint32_t*)data)[i] = ByteReverse(((uint32_t*)pinput)[i]); + + for (int i = 0; i < 8; i++) + ctx.h[i] = ((uint32_t*)pinit)[i]; + + SHA256_Update(&ctx, data, sizeof(data)); + for (int i = 0; i < 8; i++) + ((uint32_t*)pstate)[i] = ctx.h[i]; +} + +// Some explaining would be appreciated +class COrphan +{ +public: + CTransaction* ptx; + set setDependsOn; + double dPriority; + double dFeePerKb; + + COrphan(CTransaction* ptxIn) + { + ptx = ptxIn; + dPriority = dFeePerKb = 0; + } + + void print() const + { + printf("COrphan(hash=%s, dPriority=%.1f, dFeePerKb=%.1f)\n", + ptx->GetHash().ToString().substr(0,10).c_str(), dPriority, dFeePerKb); + BOOST_FOREACH(uint256 hash, setDependsOn) + printf(" setDependsOn %s\n", hash.ToString().substr(0,10).c_str()); + } +}; + + +uint64 nLastBlockTx = 0; +uint64 nLastBlockSize = 0; +int64 nLastCoinStakeSearchInterval = 0; + +// We want to sort transactions by priority and fee, so: +typedef boost::tuple TxPriority; +class TxPriorityCompare +{ + bool byFee; +public: + TxPriorityCompare(bool _byFee) : byFee(_byFee) { } + bool operator()(const TxPriority& a, const TxPriority& b) + { + if (byFee) + { + if (a.get<1>() == b.get<1>()) + return a.get<0>() < b.get<0>(); + return a.get<1>() < b.get<1>(); + } + else + { + if (a.get<0>() == b.get<0>()) + return a.get<1>() < b.get<1>(); + return a.get<0>() < b.get<0>(); + } + } +}; + +// CreateNewBlock: +// fProofOfStake: try (best effort) to make a proof-of-stake block +CBlock* CreateNewBlock(CWallet* pwallet, bool fProofOfStake) +{ + CReserveKey reservekey(pwallet); + + // Create new block + auto_ptr pblock(new CBlock()); + if (!pblock.get()) + return NULL; + + // Create coinbase tx + CTransaction txNew; + txNew.vin.resize(1); + txNew.vin[0].prevout.SetNull(); + txNew.vout.resize(1); + txNew.vout[0].scriptPubKey << reservekey.GetReservedKey() << OP_CHECKSIG; + + // Add our coinbase tx as first transaction + pblock->vtx.push_back(txNew); + + // Largest block you're willing to create: + unsigned int nBlockMaxSize = GetArg("-blockmaxsize", MAX_BLOCK_SIZE_GEN/2); + // Limit to betweeen 1K and MAX_BLOCK_SIZE-1K for sanity: + nBlockMaxSize = std::max((unsigned int)1000, std::min((unsigned int)(MAX_BLOCK_SIZE-1000), nBlockMaxSize)); + + // How much of the block should be dedicated to high-priority transactions, + // included regardless of the fees they pay + unsigned int nBlockPrioritySize = GetArg("-blockprioritysize", 27000); + nBlockPrioritySize = std::min(nBlockMaxSize, nBlockPrioritySize); + + // Minimum block size you want to create; block will be filled with free transactions + // until there are no more or the block reaches this size: + unsigned int nBlockMinSize = GetArg("-blockminsize", 0); + nBlockMinSize = std::min(nBlockMaxSize, nBlockMinSize); + + // Fee-per-kilobyte amount considered the same as "free" + // Be careful setting this: if you set it to zero then + // a transaction spammer can cheaply fill blocks using + // 1-satoshi-fee transactions. It should be set above the real + // cost to you of processing a transaction. + int64 nMinTxFee = MIN_TX_FEE; + if (mapArgs.count("-mintxfee")) + ParseMoney(mapArgs["-mintxfee"], nMinTxFee); + + // triangles: if coinstake available add coinstake tx + static int64 nLastCoinStakeSearchTime = GetAdjustedTime(); // only initialized at startup + CBlockIndex* pindexPrev = pindexBest; + + if (fProofOfStake) // attempt to find a coinstake + { + pblock->nBits = GetNextTargetRequired(pindexPrev, true); + CTransaction txCoinStake; + int64 nSearchTime = txCoinStake.nTime; // search to current time + if (nSearchTime > nLastCoinStakeSearchTime) + { + // printf(">>> OK1\n"); + if (pwallet->CreateCoinStake(*pwallet, pblock->nBits, nSearchTime-nLastCoinStakeSearchTime, txCoinStake)) + { + if (txCoinStake.nTime >= max(pindexPrev->GetMedianTimePast()+1, pindexPrev->GetBlockTime() - nMaxClockDrift)) + { // make sure coinstake would meet timestamp protocol + // as it would be the same as the block timestamp + pblock->vtx[0].vout[0].SetEmpty(); + pblock->vtx[0].nTime = txCoinStake.nTime; + pblock->vtx.push_back(txCoinStake); + } + } + nLastCoinStakeSearchInterval = nSearchTime - nLastCoinStakeSearchTime; + nLastCoinStakeSearchTime = nSearchTime; + } + } + + pblock->nBits = GetNextTargetRequired(pindexPrev, pblock->IsProofOfStake()); + + // Collect memory pool transactions into the block + int64 nFees = 0; + { + LOCK2(cs_main, mempool.cs); + CBlockIndex* pindexPrev = pindexBest; + CTxDB txdb("r"); + + // Priority order to process transactions + list vOrphan; // list memory doesn't move + map > mapDependers; + + // This vector will be sorted into a priority queue: + vector vecPriority; + vecPriority.reserve(mempool.mapTx.size()); + for (map::iterator mi = mempool.mapTx.begin(); mi != mempool.mapTx.end(); ++mi) + { + CTransaction& tx = (*mi).second; + if (tx.IsCoinBase() || tx.IsCoinStake() || !tx.IsFinal()) + continue; + + COrphan* porphan = NULL; + double dPriority = 0; + int64 nTotalIn = 0; + bool fMissingInputs = false; + BOOST_FOREACH(const CTxIn& txin, tx.vin) + { + // Read prev transaction + CTransaction txPrev; + CTxIndex txindex; + if (!txPrev.ReadFromDisk(txdb, txin.prevout, txindex)) + { + // This should never happen; all transactions in the memory + // pool should connect to either transactions in the chain + // or other transactions in the memory pool. + if (!mempool.mapTx.count(txin.prevout.hash)) + { + printf("ERROR: mempool transaction missing input\n"); + if (fDebug) assert("mempool transaction missing input" == 0); + fMissingInputs = true; + if (porphan) + vOrphan.pop_back(); + break; + } + + // Has to wait for dependencies + if (!porphan) + { + // Use list for automatic deletion + vOrphan.push_back(COrphan(&tx)); + porphan = &vOrphan.back(); + } + mapDependers[txin.prevout.hash].push_back(porphan); + porphan->setDependsOn.insert(txin.prevout.hash); + nTotalIn += mempool.mapTx[txin.prevout.hash].vout[txin.prevout.n].nValue; + continue; + } + int64 nValueIn = txPrev.vout[txin.prevout.n].nValue; + nTotalIn += nValueIn; + + int nConf = txindex.GetDepthInMainChain(); + dPriority += (double)nValueIn * nConf; + } + if (fMissingInputs) continue; + + // Priority is sum(valuein * age) / txsize + unsigned int nTxSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION); + dPriority /= nTxSize; + + // This is a more accurate fee-per-kilobyte than is used by the client code, because the + // client code rounds up the size to the nearest 1K. That's good, because it gives an + // incentive to create smaller transactions. + double dFeePerKb = double(nTotalIn-tx.GetValueOut()) / (double(nTxSize)/1000.0); + + if (porphan) + { + porphan->dPriority = dPriority; + porphan->dFeePerKb = dFeePerKb; + } + else + vecPriority.push_back(TxPriority(dPriority, dFeePerKb, &(*mi).second)); + } + + // Collect transactions into block + map mapTestPool; + uint64 nBlockSize = 1000; + uint64 nBlockTx = 0; + int nBlockSigOps = 100; + bool fSortedByFee = (nBlockPrioritySize <= 0); + + TxPriorityCompare comparer(fSortedByFee); + std::make_heap(vecPriority.begin(), vecPriority.end(), comparer); + + while (!vecPriority.empty()) + { + // Take highest priority transaction off the priority queue: + double dPriority = vecPriority.front().get<0>(); + double dFeePerKb = vecPriority.front().get<1>(); + CTransaction& tx = *(vecPriority.front().get<2>()); + + std::pop_heap(vecPriority.begin(), vecPriority.end(), comparer); + vecPriority.pop_back(); + + // Size limits + unsigned int nTxSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION); + if (nBlockSize + nTxSize >= nBlockMaxSize) + continue; + + // Legacy limits on sigOps: + unsigned int nTxSigOps = tx.GetLegacySigOpCount(); + if (nBlockSigOps + nTxSigOps >= MAX_BLOCK_SIGOPS) + continue; + + // Timestamp limit + if (tx.nTime > GetAdjustedTime() || (pblock->IsProofOfStake() && tx.nTime > pblock->vtx[1].nTime)) + continue; + + // triangles: simplify transaction fee - allow free = false + int64 nMinFee = tx.GetMinFee(nBlockSize, false, GMF_BLOCK); + + // Skip free transactions if we're past the minimum block size: + if (fSortedByFee && (dFeePerKb < nMinTxFee) && (nBlockSize + nTxSize >= nBlockMinSize)) + continue; + + // Prioritize by fee once past the priority size or we run out of high-priority + // transactions: + if (!fSortedByFee && + ((nBlockSize + nTxSize >= nBlockPrioritySize) || (dPriority < COIN * 300 / 250))) + { + fSortedByFee = true; + comparer = TxPriorityCompare(fSortedByFee); + std::make_heap(vecPriority.begin(), vecPriority.end(), comparer); + } + + // Connecting shouldn't fail due to dependency on other memory pool transactions + // because we're already processing them in order of dependency + map mapTestPoolTmp(mapTestPool); + MapPrevTx mapInputs; + bool fInvalid; + if (!tx.FetchInputs(txdb, mapTestPoolTmp, false, true, mapInputs, fInvalid)) + continue; + + int64 nTxFees = tx.GetValueIn(mapInputs)-tx.GetValueOut(); + if (nTxFees < nMinFee) + continue; + + nTxSigOps += tx.GetP2SHSigOpCount(mapInputs); + if (nBlockSigOps + nTxSigOps >= MAX_BLOCK_SIGOPS) + continue; + + if (!tx.ConnectInputs(txdb, mapInputs, mapTestPoolTmp, CDiskTxPos(1,1,1), pindexPrev, false, true)) + continue; + mapTestPoolTmp[tx.GetHash()] = CTxIndex(CDiskTxPos(1,1,1), tx.vout.size()); + swap(mapTestPool, mapTestPoolTmp); + + // Added + pblock->vtx.push_back(tx); + nBlockSize += nTxSize; + ++nBlockTx; + nBlockSigOps += nTxSigOps; + nFees += nTxFees; + + if (fDebug && GetBoolArg("-printpriority")) + { + printf("priority %.1f feeperkb %.1f txid %s\n", + dPriority, dFeePerKb, tx.GetHash().ToString().c_str()); + } + + // Add transactions that depend on this one to the priority queue + uint256 hash = tx.GetHash(); + if (mapDependers.count(hash)) + { + BOOST_FOREACH(COrphan* porphan, mapDependers[hash]) + { + if (!porphan->setDependsOn.empty()) + { + porphan->setDependsOn.erase(hash); + if (porphan->setDependsOn.empty()) + { + vecPriority.push_back(TxPriority(porphan->dPriority, porphan->dFeePerKb, porphan->ptx)); + std::push_heap(vecPriority.begin(), vecPriority.end(), comparer); + } + } + } + } + } + + nLastBlockTx = nBlockTx; + nLastBlockSize = nBlockSize; + + if (fDebug && GetBoolArg("-printpriority")) + printf("CreateNewBlock(): total size %"PRI64u"\n", nBlockSize); + + if (pblock->IsProofOfWork()) + pblock->vtx[0].vout[0].nValue = GetProofOfWorkReward(pindexPrev->nHeight+1, nFees, pindexPrev->GetBlockHash()); + + // Fill in header + pblock->hashPrevBlock = pindexPrev->GetBlockHash(); + if (pblock->IsProofOfStake()) + pblock->nTime = pblock->vtx[1].nTime; //same as coinstake timestamp + pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, pblock->GetMaxTransactionTime()); + pblock->nTime = max(pblock->GetBlockTime(), pindexPrev->GetBlockTime() - nMaxClockDrift); + if (pblock->IsProofOfWork()) + pblock->UpdateTime(pindexPrev); + pblock->nNonce = 0; + } + + return pblock.release(); +} + + +void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int& nExtraNonce) +{ + // Update nExtraNonce + static uint256 hashPrevBlock; + if (hashPrevBlock != pblock->hashPrevBlock) + { + nExtraNonce = 0; + hashPrevBlock = pblock->hashPrevBlock; + } + ++nExtraNonce; + unsigned int nHeight = pindexPrev->nHeight+1; // Height first in coinbase required for block.version=2 + pblock->vtx[0].vin[0].scriptSig = (CScript() << nHeight << CBigNum(nExtraNonce)) + COINBASE_FLAGS; + assert(pblock->vtx[0].vin[0].scriptSig.size() <= 100); + + pblock->hashMerkleRoot = pblock->BuildMerkleTree(); +} + + +void FormatHashBuffers(CBlock* pblock, char* pmidstate, char* pdata, char* phash1) +{ + // + // Pre-build hash buffers + // + struct + { + struct unnamed2 + { + int nVersion; + uint256 hashPrevBlock; + uint256 hashMerkleRoot; + unsigned int nTime; + unsigned int nBits; + unsigned int nNonce; + } + block; + unsigned char pchPadding0[64]; + uint256 hash1; + unsigned char pchPadding1[64]; + } + tmp; + memset(&tmp, 0, sizeof(tmp)); + + tmp.block.nVersion = pblock->nVersion; + tmp.block.hashPrevBlock = pblock->hashPrevBlock; + tmp.block.hashMerkleRoot = pblock->hashMerkleRoot; + tmp.block.nTime = pblock->nTime; + tmp.block.nBits = pblock->nBits; + tmp.block.nNonce = pblock->nNonce; + + FormatHashBlocks(&tmp.block, sizeof(tmp.block)); + FormatHashBlocks(&tmp.hash1, sizeof(tmp.hash1)); + + // Byte swap all the input buffer + for (unsigned int i = 0; i < sizeof(tmp)/4; i++) + ((unsigned int*)&tmp)[i] = ByteReverse(((unsigned int*)&tmp)[i]); + + // Precalc the first half of the first hash, which stays constant + SHA256Transform(pmidstate, &tmp.block, pSHA256InitState); + + memcpy(pdata, &tmp.block, 128); + memcpy(phash1, &tmp.hash1, 64); +} + + +bool CheckWork(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey) +{ + uint256 hash = pblock->GetHash(); + uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256(); + + if (hash > hashTarget && pblock->IsProofOfWork()) + return error("BitcoinMiner : proof-of-work not meeting target"); + + //// debug print + printf("BitcoinMiner:\n"); + printf("new block found \n hash: %s \ntarget: %s\n", hash.GetHex().c_str(), hashTarget.GetHex().c_str()); + pblock->print(); + printf("generated %s\n", FormatMoney(pblock->vtx[0].vout[0].nValue).c_str()); + + // Found a solution + { + LOCK(cs_main); + if (pblock->hashPrevBlock != hashBestChain) + return error("BitcoinMiner : generated block is stale"); + + // Remove key from key pool + reservekey.KeepKey(); + + // Track how many getdata requests this block gets + { + LOCK(wallet.cs_wallet); + wallet.mapRequestCount[pblock->GetHash()] = 0; + } + + // Process this block the same as if we had received it from another node + if (!ProcessBlock(NULL, pblock)) + return error("BitcoinMiner : ProcessBlock, block not accepted"); + } + + return true; +} + +void static ThreadBitcoinMiner(void* parg); + +static bool fGenerateBitcoins = false; +static bool fLimitProcessors = false; +static int nLimitProcessors = -1; + +void BitcoinMiner(CWallet *pwallet, bool fProofOfStake) +{ + printf("CPUMiner started for proof-of-%s\n", fProofOfStake? "stake" : "work"); + SetThreadPriority(THREAD_PRIORITY_LOWEST); + + // Make this thread recognisable as the mining thread + RenameThread("bitcoin-miner"); + + // Each thread has its own key and counter + CReserveKey reservekey(pwallet); + unsigned int nExtraNonce = 0; + + while (fGenerateBitcoins || fProofOfStake) + { + if (fShutdown) + return; + + while (vNodes.empty() || IsInitialBlockDownload() || pwallet->IsLocked()) + { + nLastCoinStakeSearchInterval = 0; + Sleep(1000); + if (fShutdown) + return; + if (!fGenerateBitcoins && !fProofOfStake) + return; + } + + // + // Create new block + // + unsigned int nTransactionsUpdatedLast = nTransactionsUpdated; + CBlockIndex* pindexPrev = pindexBest; + + auto_ptr pblock(CreateNewBlock(pwallet, fProofOfStake)); + if (!pblock.get()) + return; + IncrementExtraNonce(pblock.get(), pindexPrev, nExtraNonce); + + if (fProofOfStake) + { + // triangles: if proof-of-stake block found then process block + if (pblock->IsProofOfStake()) + { + if (!pblock->SignBlock(*pwalletMain)) + continue; + printf("CPUMINER: A proof-of-stake block has been found! %s\n", pblock->GetHash().ToString().c_str()); + SetThreadPriority(THREAD_PRIORITY_NORMAL); + CheckWork(pblock.get(), *pwalletMain, reservekey); + SetThreadPriority(THREAD_PRIORITY_LOWEST); + } + Sleep(300); + continue; + } + + printf("Running BitcoinMiner with %"PRIszu" transactions in block (%u bytes)\n", pblock->vtx.size(), + ::GetSerializeSize(*pblock, SER_NETWORK, PROTOCOL_VERSION)); + + // + // Search + // + int64 nStart = GetTime(); + uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256(); + uint256 hash; + + loop + { + hash = pblock->GetHash(); + if (hash <= hashTarget){ + // nHashesDone += pblock->nNonce; + if (!pblock->SignBlock(*pwalletMain)) + break; + + SetThreadPriority(THREAD_PRIORITY_NORMAL); + + printf("proof-of-work found \n hash: %s \ntarget: %s\n", hash.GetHex().c_str(), hashTarget.GetHex().c_str()); + pblock->print(); + + CheckWork(pblock.get(), *pwalletMain, reservekey); + SetThreadPriority(THREAD_PRIORITY_NORMAL); + break; + } + ++pblock->nNonce; + + + // Meter hashes/sec + static int64 nHashCounter; + if (nHPSTimerStart == 0) + { + nHPSTimerStart = GetTimeMillis(); + nHashCounter = 0; + } + else + nHashCounter += 1; + + if (GetTimeMillis() - nHPSTimerStart > 4000) + { + static CCriticalSection cs; + { + LOCK(cs); + if (GetTimeMillis() - nHPSTimerStart > 4000) + { + dHashesPerSec = 1000.0 * nHashCounter / (GetTimeMillis() - nHPSTimerStart); + nHPSTimerStart = GetTimeMillis(); + nHashCounter = 0; + + printf("hashmeter %3d CPUs %6.0f khash/s\n", vnThreadsRunning[THREAD_MINER], dHashesPerSec/1000.0); + + } + } + } + + // Check for stop or if block needs to be rebuilt + if (fShutdown) + return; + if (!fGenerateBitcoins) + return; + if (fLimitProcessors && vnThreadsRunning[THREAD_MINER] > nLimitProcessors) + return; + if (vNodes.empty()) + break; + if (++pblock->nNonce >= 0xffff0000) + break; + if (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 60) + break; + if (pindexPrev != pindexBest) + break; + + // Update nTime every few seconds + pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, pblock->GetMaxTransactionTime()); + pblock->nTime = max(pblock->GetBlockTime(), pindexPrev->GetBlockTime() - nMaxClockDrift); + pblock->UpdateTime(pindexPrev); + + if (pblock->GetBlockTime() >= (int64)pblock->vtx[0].nTime + nMaxClockDrift) + break; // need to update coinbase timestamp + } + } +} + +void static ThreadBitcoinMiner(void* parg) +{ + CWallet* pwallet = (CWallet*)parg; + try + { + vnThreadsRunning[THREAD_MINER]++; + BitcoinMiner(pwallet, false); + vnThreadsRunning[THREAD_MINER]--; + } + catch (std::exception& e) { + vnThreadsRunning[THREAD_MINER]--; + PrintException(&e, "ThreadBitcoinMiner()"); + } catch (...) { + vnThreadsRunning[THREAD_MINER]--; + PrintException(NULL, "ThreadBitcoinMiner()"); + } + nHPSTimerStart = 0; + if (vnThreadsRunning[THREAD_MINER] == 0) + dHashesPerSec = 0; + printf("ThreadBitcoinMiner exiting, %d threads remaining\n", vnThreadsRunning[THREAD_MINER]); +} + + +void GenerateBitcoins(bool fGenerate, CWallet* pwallet) +{ + fGenerateBitcoins = fGenerate; + nLimitProcessors = GetArg("-genproclimit", -1); + if (nLimitProcessors == 0) + fGenerateBitcoins = false; + fLimitProcessors = (nLimitProcessors != -1); + + if (fGenerate) + { + int nProcessors = boost::thread::hardware_concurrency(); + printf("%d processors\n", nProcessors); + if (nProcessors < 1) + nProcessors = 1; + if (fLimitProcessors && nProcessors > nLimitProcessors) + nProcessors = nLimitProcessors; + int nAddThreads = nProcessors - vnThreadsRunning[THREAD_MINER]; + printf("Starting %d BitcoinMiner threads\n", nAddThreads); + for (int i = 0; i < nAddThreads; i++) + { + if (!NewThread(ThreadBitcoinMiner, pwallet)) + printf("Error: NewThread(ThreadBitcoinMiner) failed\n"); + Sleep(10); + } + } +} diff --git a/src/main.h b/src/main.h new file mode 100644 index 0000000..b8fde6d --- /dev/null +++ b/src/main.h @@ -0,0 +1,1604 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2012 The Bitcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. +#ifndef BITCOIN_MAIN_H +#define BITCOIN_MAIN_H + +#include "bignum.h" +#include "sync.h" +#include "net.h" +#include "script.h" +#include "scrypt.h" +#include "hashblock.h" + +#include + +class CWallet; +class CBlock; +class CBlockIndex; +class CKeyItem; +class CReserveKey; +class COutPoint; + +class CAddress; +class CInv; +class CRequestTracker; +class CNode; + +static const unsigned int MAX_BLOCK_SIZE = 1000000; +static const unsigned int MAX_BLOCK_SIZE_GEN = MAX_BLOCK_SIZE/2; +static const unsigned int MAX_BLOCK_SIGOPS = MAX_BLOCK_SIZE/50; +static const unsigned int MAX_ORPHAN_TRANSACTIONS = MAX_BLOCK_SIZE/100; +static const unsigned int MAX_INV_SZ = 50000; +static const int64 MIN_TX_FEE = 1 * CENT / 100; +static const int64 MIN_RELAY_TX_FEE = 1 * CENT; +static const int64 MAX_MONEY = 120000 * COIN; +static const int64 CIRCULATION_MONEY = MAX_MONEY; +static const double TAX_PERCENTAGE = 0.00; //no tax. who likes tax? +static const int64 MAX_TRI_PROOF_OF_STAKE = 0.33 * COIN; +static const int CUTOFF_POW_BLOCK = 9000; + +static const int64 MIN_TXOUT_AMOUNT = MIN_TX_FEE; + +inline bool MoneyRange(int64 nValue) { return (nValue >= 0 && nValue <= MAX_MONEY); } +// Threshold for nLockTime: below this value it is interpreted as block number, otherwise as UNIX timestamp. +static const unsigned int LOCKTIME_THRESHOLD = 500000000; // Tue Nov 5 00:53:20 1985 UTC + +#ifdef USE_UPNP +static const int fHaveUPnP = true; +#else +static const int fHaveUPnP = false; +#endif + +static const uint256 hashGenesisBlockOfficial("0x7e7a6e4dd5fe895106fca912dfbacaeaf2a89e76c6a588df8ff96e0e18b96021"); +static const uint256 hashGenesisBlockTestNet ("0x7e7a6e4dd5fe895106fca912dfbacaeaf2a89e76c6a588df8ff96e0e18b96021"); + +static const int64 nMaxClockDrift = 1 * 60 * 60; // one hour + +extern CScript COINBASE_FLAGS; + + +extern CCriticalSection cs_main; +extern std::map mapBlockIndex; +extern std::set > setStakeSeen; +extern uint256 hashGenesisBlock; +extern CBlockIndex* pindexGenesisBlock; +extern unsigned int nStakeMinAge; +extern int nCoinbaseMaturity; +extern int nBestHeight; +extern CBigNum bnBestChainTrust; +extern CBigNum bnBestInvalidTrust; +extern uint256 hashBestChain; +extern CBlockIndex* pindexBest; +extern unsigned int nTransactionsUpdated; +extern uint64 nLastBlockTx; +extern uint64 nLastBlockSize; +extern int64 nLastCoinStakeSearchInterval; +extern const std::string strMessageMagic; +extern double dHashesPerSec; +extern int64 nHPSTimerStart; +extern int64 nTimeBestReceived; +extern CCriticalSection cs_setpwalletRegistered; +extern std::set setpwalletRegistered; +extern unsigned char pchMessageStart[4]; +extern std::map mapOrphanBlocks; + +// Settings +extern int64 nTransactionFee; + +// Minimum disk space required - used in CheckDiskSpace() +static const uint64 nMinDiskSpace = 52428800; + + +class CReserveKey; +class CTxDB; +class CTxIndex; + +void RegisterWallet(CWallet* pwalletIn); +void UnregisterWallet(CWallet* pwalletIn); +void SyncWithWallets(const CTransaction& tx, const CBlock* pblock = NULL, bool fUpdate = false, bool fConnect = true); +bool ProcessBlock(CNode* pfrom, CBlock* pblock); +bool CheckDiskSpace(uint64 nAdditionalBytes=0); +FILE* OpenBlockFile(unsigned int nFile, unsigned int nBlockPos, const char* pszMode="rb"); +FILE* AppendBlockFile(unsigned int& nFileRet); +bool LoadBlockIndex(bool fAllowNew=true); +void PrintBlockTree(); +CBlockIndex* FindBlockByHeight(int nHeight); +bool ProcessMessages(CNode* pfrom); +bool SendMessages(CNode* pto, bool fSendTrickle); +bool LoadExternalBlockFile(FILE* fileIn); +void GenerateBitcoins(bool fGenerate, CWallet* pwallet); +CBlock* CreateNewBlock(CWallet* pwallet, bool fProofOfStake=false); +void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int& nExtraNonce); +void FormatHashBuffers(CBlock* pblock, char* pmidstate, char* pdata, char* phash1); +bool CheckWork(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey); +bool CheckProofOfWork(uint256 hash, unsigned int nBits); +int64 GetProofOfWorkReward(int nHeight, int64 nFees, uint256 prevHash); +int64 GetProofOfStakeReward(int64 nCoinAge, unsigned int nBits, unsigned int nTime, int nHeight); +unsigned int ComputeMinWork(unsigned int nBase, int64 nTime); +unsigned int ComputeMinStake(unsigned int nBase, int64 nTime, unsigned int nBlockTime); +int GetNumBlocksOfPeers(); +bool IsInitialBlockDownload(); +std::string GetWarnings(std::string strFor); +bool GetTransaction(const uint256 &hash, CTransaction &tx, uint256 &hashBlock); +uint256 WantedByOrphan(const CBlock* pblockOrphan); +const CBlockIndex* GetLastBlockIndex(const CBlockIndex* pindex, bool fProofOfStake); +void BitcoinMiner(CWallet *pwallet, bool fProofOfStake); +void ResendWalletTransactions(); + + + + + + + + + + +bool GetWalletFile(CWallet* pwallet, std::string &strWalletFileOut); + +/** Position on disk for a particular transaction. */ +class CDiskTxPos +{ +public: + unsigned int nFile; + unsigned int nBlockPos; + unsigned int nTxPos; + + CDiskTxPos() + { + SetNull(); + } + + CDiskTxPos(unsigned int nFileIn, unsigned int nBlockPosIn, unsigned int nTxPosIn) + { + nFile = nFileIn; + nBlockPos = nBlockPosIn; + nTxPos = nTxPosIn; + } + + IMPLEMENT_SERIALIZE( READWRITE(FLATDATA(*this)); ) + void SetNull() { nFile = (unsigned int) -1; nBlockPos = 0; nTxPos = 0; } + bool IsNull() const { return (nFile == (unsigned int) -1); } + + friend bool operator==(const CDiskTxPos& a, const CDiskTxPos& b) + { + return (a.nFile == b.nFile && + a.nBlockPos == b.nBlockPos && + a.nTxPos == b.nTxPos); + } + + friend bool operator!=(const CDiskTxPos& a, const CDiskTxPos& b) + { + return !(a == b); + } + + + std::string ToString() const + { + if (IsNull()) + return "null"; + else + return strprintf("(nFile=%u, nBlockPos=%u, nTxPos=%u)", nFile, nBlockPos, nTxPos); + } + + void print() const + { + printf("%s", ToString().c_str()); + } +}; + + + +/** An inpoint - a combination of a transaction and an index n into its vin */ +class CInPoint +{ +public: + CTransaction* ptx; + unsigned int n; + + CInPoint() { SetNull(); } + CInPoint(CTransaction* ptxIn, unsigned int nIn) { ptx = ptxIn; n = nIn; } + void SetNull() { ptx = NULL; n = (unsigned int) -1; } + bool IsNull() const { return (ptx == NULL && n == (unsigned int) -1); } +}; + + + +/** An outpoint - a combination of a transaction hash and an index n into its vout */ +class COutPoint +{ +public: + uint256 hash; + unsigned int n; + + COutPoint() { SetNull(); } + COutPoint(uint256 hashIn, unsigned int nIn) { hash = hashIn; n = nIn; } + IMPLEMENT_SERIALIZE( READWRITE(FLATDATA(*this)); ) + void SetNull() { hash = 0; n = (unsigned int) -1; } + bool IsNull() const { return (hash == 0 && n == (unsigned int) -1); } + + friend bool operator<(const COutPoint& a, const COutPoint& b) + { + return (a.hash < b.hash || (a.hash == b.hash && a.n < b.n)); + } + + friend bool operator==(const COutPoint& a, const COutPoint& b) + { + return (a.hash == b.hash && a.n == b.n); + } + + friend bool operator!=(const COutPoint& a, const COutPoint& b) + { + return !(a == b); + } + + std::string ToString() const + { + return strprintf("COutPoint(%s, %u)", hash.ToString().substr(0,10).c_str(), n); + } + + void print() const + { + printf("%s\n", ToString().c_str()); + } +}; + + + + +/** An input of a transaction. It contains the location of the previous + * transaction's output that it claims and a signature that matches the + * output's public key. + */ +class CTxIn +{ +public: + COutPoint prevout; + CScript scriptSig; + unsigned int nSequence; + + CTxIn() + { + nSequence = std::numeric_limits::max(); + } + + explicit CTxIn(COutPoint prevoutIn, CScript scriptSigIn=CScript(), unsigned int nSequenceIn=std::numeric_limits::max()) + { + prevout = prevoutIn; + scriptSig = scriptSigIn; + nSequence = nSequenceIn; + } + + CTxIn(uint256 hashPrevTx, unsigned int nOut, CScript scriptSigIn=CScript(), unsigned int nSequenceIn=std::numeric_limits::max()) + { + prevout = COutPoint(hashPrevTx, nOut); + scriptSig = scriptSigIn; + nSequence = nSequenceIn; + } + + IMPLEMENT_SERIALIZE + ( + READWRITE(prevout); + READWRITE(scriptSig); + READWRITE(nSequence); + ) + + bool IsFinal() const + { + return (nSequence == std::numeric_limits::max()); + } + + friend bool operator==(const CTxIn& a, const CTxIn& b) + { + return (a.prevout == b.prevout && + a.scriptSig == b.scriptSig && + a.nSequence == b.nSequence); + } + + friend bool operator!=(const CTxIn& a, const CTxIn& b) + { + return !(a == b); + } + + std::string ToStringShort() const + { + return strprintf(" %s %d", prevout.hash.ToString().c_str(), prevout.n); + } + + std::string ToString() const + { + std::string str; + str += "CTxIn("; + str += prevout.ToString(); + if (prevout.IsNull()) + str += strprintf(", coinbase %s", HexStr(scriptSig).c_str()); + else + str += strprintf(", scriptSig=%s", scriptSig.ToString().substr(0,24).c_str()); + if (nSequence != std::numeric_limits::max()) + str += strprintf(", nSequence=%u", nSequence); + str += ")"; + return str; + } + + void print() const + { + printf("%s\n", ToString().c_str()); + } +}; + + + + +/** An output of a transaction. It contains the public key that the next input + * must be able to sign with to claim it. + */ +class CTxOut +{ +public: + int64 nValue; + CScript scriptPubKey; + + CTxOut() + { + SetNull(); + } + + CTxOut(int64 nValueIn, CScript scriptPubKeyIn) + { + nValue = nValueIn; + scriptPubKey = scriptPubKeyIn; + } + + IMPLEMENT_SERIALIZE + ( + READWRITE(nValue); + READWRITE(scriptPubKey); + ) + + void SetNull() + { + nValue = -1; + scriptPubKey.clear(); + } + + bool IsNull() + { + return (nValue == -1); + } + + void SetEmpty() + { + nValue = 0; + scriptPubKey.clear(); + } + + bool IsEmpty() const + { + return (nValue == 0 && scriptPubKey.empty()); + } + + uint256 GetHash() const + { + return SerializeHash(*this); + } + + friend bool operator==(const CTxOut& a, const CTxOut& b) + { + return (a.nValue == b.nValue && + a.scriptPubKey == b.scriptPubKey); + } + + friend bool operator!=(const CTxOut& a, const CTxOut& b) + { + return !(a == b); + } + + std::string ToStringShort() const + { + return strprintf(" out %s %s", FormatMoney(nValue).c_str(), scriptPubKey.ToString(true).c_str()); + } + + std::string ToString() const + { + if (IsEmpty()) return "CTxOut(empty)"; + if (scriptPubKey.size() < 6) + return "CTxOut(error)"; + return strprintf("CTxOut(nValue=%s, scriptPubKey=%s)", FormatMoney(nValue).c_str(), scriptPubKey.ToString().c_str()); + } + + void print() const + { + printf("%s\n", ToString().c_str()); + } +}; + + + + +enum GetMinFee_mode +{ + GMF_BLOCK, + GMF_RELAY, + GMF_SEND, +}; + +typedef std::map > MapPrevTx; + +/** The basic transaction that is broadcasted on the network and contained in + * blocks. A transaction can contain multiple inputs and outputs. + */ +class CTransaction +{ +public: + static const int CURRENT_VERSION=1; + + int nVersion; + unsigned int nTime; + std::vector vin; + std::vector vout; + unsigned int nLockTime; + + // Denial-of-service detection: + mutable int nDoS; + bool DoS(int nDoSIn, bool fIn) const { nDoS += nDoSIn; return fIn; } + + CTransaction() + { + SetNull(); + } + + IMPLEMENT_SERIALIZE + ( + READWRITE(this->nVersion); + nVersion = this->nVersion; + READWRITE(nTime); + READWRITE(vin); + READWRITE(vout); + READWRITE(nLockTime); + ) + + void SetNull() + { + nVersion = CTransaction::CURRENT_VERSION; + nTime = GetAdjustedTime(); + vin.clear(); + vout.clear(); + nLockTime = 0; + nDoS = 0; // Denial-of-service prevention + } + + bool IsNull() const + { + return (vin.empty() && vout.empty()); + } + + uint256 GetHash() const + { + return SerializeHash(*this); + } + + bool IsFinal(int nBlockHeight=0, int64 nBlockTime=0) const + { + // Time based nLockTime implemented in 0.1.6 + if (nLockTime == 0) + return true; + if (nBlockHeight == 0) + nBlockHeight = nBestHeight; + if (nBlockTime == 0) + nBlockTime = GetAdjustedTime(); + if ((int64)nLockTime < ((int64)nLockTime < LOCKTIME_THRESHOLD ? (int64)nBlockHeight : nBlockTime)) + return true; + BOOST_FOREACH(const CTxIn& txin, vin) + if (!txin.IsFinal()) + return false; + return true; + } + + bool IsNewerThan(const CTransaction& old) const + { + if (vin.size() != old.vin.size()) + return false; + for (unsigned int i = 0; i < vin.size(); i++) + if (vin[i].prevout != old.vin[i].prevout) + return false; + + bool fNewer = false; + unsigned int nLowest = std::numeric_limits::max(); + for (unsigned int i = 0; i < vin.size(); i++) + { + if (vin[i].nSequence != old.vin[i].nSequence) + { + if (vin[i].nSequence <= nLowest) + { + fNewer = false; + nLowest = vin[i].nSequence; + } + if (old.vin[i].nSequence < nLowest) + { + fNewer = true; + nLowest = old.vin[i].nSequence; + } + } + } + return fNewer; + } + + bool IsCoinBase() const + { + return (vin.size() == 1 && vin[0].prevout.IsNull() && vout.size() >= 1); + } + + bool IsCoinStake() const + { + // triangles: the coin stake transaction is marked with the first output empty + return (vin.size() > 0 && (!vin[0].prevout.IsNull()) && vout.size() >= 2 && vout[0].IsEmpty()); + } + + bool IsCoinBaseOrStake() const + { + return (IsCoinBase() || IsCoinStake()); + } + + + /** Check for standard transaction types + @return True if all outputs (scriptPubKeys) use only standard transaction forms + */ + bool IsStandard() const; + + /** Check for standard transaction types + @param[in] mapInputs Map of previous transactions that have outputs we're spending + @return True if all inputs (scriptSigs) use only standard transaction forms + @see CTransaction::FetchInputs + */ + bool AreInputsStandard(const MapPrevTx& mapInputs) const; + + /** Count ECDSA signature operations the old-fashioned (pre-0.6) way + @return number of sigops this transaction's outputs will produce when spent + @see CTransaction::FetchInputs + */ + unsigned int GetLegacySigOpCount() const; + + /** Count ECDSA signature operations in pay-to-script-hash inputs. + + @param[in] mapInputs Map of previous transactions that have outputs we're spending + @return maximum number of sigops required to validate this transaction's inputs + @see CTransaction::FetchInputs + */ + unsigned int GetP2SHSigOpCount(const MapPrevTx& mapInputs) const; + + /** Amount of bitcoins spent by this transaction. + @return sum of all outputs (note: does not include fees) + */ + int64 GetValueOut() const + { + int64 nValueOut = 0; + BOOST_FOREACH(const CTxOut& txout, vout) + { + nValueOut += txout.nValue; + if (!MoneyRange(txout.nValue) || !MoneyRange(nValueOut)) + throw std::runtime_error("CTransaction::GetValueOut() : value out of range"); + } + return nValueOut; + } + + /** Amount of bitcoins coming in to this transaction + Note that lightweight clients may not know anything besides the hash of previous transactions, + so may not be able to calculate this. + + @param[in] mapInputs Map of previous transactions that have outputs we're spending + @return Sum of value of all inputs (scriptSigs) + @see CTransaction::FetchInputs + */ + int64 GetValueIn(const MapPrevTx& mapInputs) const; + + static bool AllowFree(double dPriority) + { + // Large (in bytes) low-priority (new, small-coin) transactions + // need a fee. + return dPriority > COIN * 300 / 250; + } + + int64 GetMinFee(unsigned int nBlockSize=1, bool fAllowFree=false, enum GetMinFee_mode mode=GMF_BLOCK, unsigned int nBytes = 0) const; + + bool ReadFromDisk(CDiskTxPos pos, FILE** pfileRet=NULL) + { + CAutoFile filein = CAutoFile(OpenBlockFile(pos.nFile, 0, pfileRet ? "rb+" : "rb"), SER_DISK, CLIENT_VERSION); + if (!filein) + return error("CTransaction::ReadFromDisk() : OpenBlockFile failed"); + + // Read transaction + if (fseek(filein, pos.nTxPos, SEEK_SET) != 0) + return error("CTransaction::ReadFromDisk() : fseek failed"); + + try { + filein >> *this; + } + catch (std::exception &e) { + return error("%s() : deserialize or I/O error", __PRETTY_FUNCTION__); + } + + // Return file pointer + if (pfileRet) + { + if (fseek(filein, pos.nTxPos, SEEK_SET) != 0) + return error("CTransaction::ReadFromDisk() : second fseek failed"); + *pfileRet = filein.release(); + } + return true; + } + + friend bool operator==(const CTransaction& a, const CTransaction& b) + { + return (a.nVersion == b.nVersion && + a.nTime == b.nTime && + a.vin == b.vin && + a.vout == b.vout && + a.nLockTime == b.nLockTime); + } + + friend bool operator!=(const CTransaction& a, const CTransaction& b) + { + return !(a == b); + } + + std::string ToStringShort() const + { + std::string str; + str += strprintf("%s %s", GetHash().ToString().c_str(), IsCoinBase()? "base" : (IsCoinStake()? "stake" : "user")); + return str; + } + + std::string ToString() const + { + std::string str; + str += IsCoinBase()? "Coinbase" : (IsCoinStake()? "Coinstake" : "CTransaction"); + str += strprintf("(hash=%s, nTime=%d, ver=%d, vin.size=%"PRIszu", vout.size=%"PRIszu", nLockTime=%d)\n", + GetHash().ToString().substr(0,10).c_str(), + nTime, + nVersion, + vin.size(), + vout.size(), + nLockTime + ); + + for (unsigned int i = 0; i < vin.size(); i++) + str += " " + vin[i].ToString() + "\n"; + for (unsigned int i = 0; i < vout.size(); i++) + str += " " + vout[i].ToString() + "\n"; + return str; + } + + void print() const + { + printf("%s", ToString().c_str()); + } + + + bool ReadFromDisk(CTxDB& txdb, COutPoint prevout, CTxIndex& txindexRet); + bool ReadFromDisk(CTxDB& txdb, COutPoint prevout); + bool ReadFromDisk(COutPoint prevout); + bool DisconnectInputs(CTxDB& txdb); + + /** Fetch from memory and/or disk. inputsRet keys are transaction hashes. + + @param[in] txdb Transaction database + @param[in] mapTestPool List of pending changes to the transaction index database + @param[in] fBlock True if being called to add a new best-block to the chain + @param[in] fMiner True if being called by CreateNewBlock + @param[out] inputsRet Pointers to this transaction's inputs + @param[out] fInvalid returns true if transaction is invalid + @return Returns true if all inputs are in txdb or mapTestPool + */ + bool FetchInputs(CTxDB& txdb, const std::map& mapTestPool, + bool fBlock, bool fMiner, MapPrevTx& inputsRet, bool& fInvalid); + + /** Sanity check previous transactions, then, if all checks succeed, + mark them as spent by this transaction. + + @param[in] inputs Previous transactions (from FetchInputs) + @param[out] mapTestPool Keeps track of inputs that need to be updated on disk + @param[in] posThisTx Position of this transaction on disk + @param[in] pindexBlock + @param[in] fBlock true if called from ConnectBlock + @param[in] fMiner true if called from CreateNewBlock + @param[in] fStrictPayToScriptHash true if fully validating p2sh transactions + @return Returns true if all checks succeed + */ + bool ConnectInputs(CTxDB& txdb, MapPrevTx inputs, + std::map& mapTestPool, const CDiskTxPos& posThisTx, + const CBlockIndex* pindexBlock, bool fBlock, bool fMiner, bool fStrictPayToScriptHash=true); + bool ClientConnectInputs(); + bool CheckTransaction() const; + bool AcceptToMemoryPool(CTxDB& txdb, bool fCheckInputs=true, bool* pfMissingInputs=NULL); + bool GetCoinAge(CTxDB& txdb, uint64& nCoinAge) const; // triangles: get transaction coin age + +protected: + const CTxOut& GetOutputFor(const CTxIn& input, const MapPrevTx& inputs) const; +}; + + + + + +/** A transaction with a merkle branch linking it to the block chain. */ +class CMerkleTx : public CTransaction +{ +public: + uint256 hashBlock; + std::vector vMerkleBranch; + int nIndex; + + // memory only + mutable bool fMerkleVerified; + + + CMerkleTx() + { + Init(); + } + + CMerkleTx(const CTransaction& txIn) : CTransaction(txIn) + { + Init(); + } + + void Init() + { + hashBlock = 0; + nIndex = -1; + fMerkleVerified = false; + } + + + IMPLEMENT_SERIALIZE + ( + nSerSize += SerReadWrite(s, *(CTransaction*)this, nType, nVersion, ser_action); + nVersion = this->nVersion; + READWRITE(hashBlock); + READWRITE(vMerkleBranch); + READWRITE(nIndex); + ) + + + int SetMerkleBranch(const CBlock* pblock=NULL); + int GetDepthInMainChain(CBlockIndex* &pindexRet) const; + int GetDepthInMainChain() const { CBlockIndex *pindexRet; return GetDepthInMainChain(pindexRet); } + bool IsInMainChain() const { return GetDepthInMainChain() > 0; } + int GetBlocksToMaturity() const; + bool AcceptToMemoryPool(CTxDB& txdb, bool fCheckInputs=true); + bool AcceptToMemoryPool(); +}; + + + + +/** A txdb record that contains the disk location of a transaction and the + * locations of transactions that spend its outputs. vSpent is really only + * used as a flag, but having the location is very helpful for debugging. + */ +class CTxIndex +{ +public: + CDiskTxPos pos; + std::vector vSpent; + + CTxIndex() + { + SetNull(); + } + + CTxIndex(const CDiskTxPos& posIn, unsigned int nOutputs) + { + pos = posIn; + vSpent.resize(nOutputs); + } + + IMPLEMENT_SERIALIZE + ( + if (!(nType & SER_GETHASH)) + READWRITE(nVersion); + READWRITE(pos); + READWRITE(vSpent); + ) + + void SetNull() + { + pos.SetNull(); + vSpent.clear(); + } + + bool IsNull() + { + return pos.IsNull(); + } + + friend bool operator==(const CTxIndex& a, const CTxIndex& b) + { + return (a.pos == b.pos && + a.vSpent == b.vSpent); + } + + friend bool operator!=(const CTxIndex& a, const CTxIndex& b) + { + return !(a == b); + } + int GetDepthInMainChain() const; + +}; + + + + + +/** Nodes collect new transactions into a block, hash them into a hash tree, + * and scan through nonce values to make the block's hash satisfy proof-of-work + * requirements. When they solve the proof-of-work, they broadcast the block + * to everyone and the block is added to the block chain. The first transaction + * in the block is a special one that creates a new coin owned by the creator + * of the block. + * + * Blocks are appended to blk0001.dat files on disk. Their location on disk + * is indexed by CBlockIndex objects in memory. + */ +class CBlock +{ +public: + // header + static const int CURRENT_VERSION=4; + int nVersion; + uint256 hashPrevBlock; + uint256 hashMerkleRoot; + unsigned int nTime; + unsigned int nBits; + unsigned int nNonce; + + // network and disk + std::vector vtx; + + // triangles: block signature - signed by one of the coin base txout[N]'s owner + std::vector vchBlockSig; + + // memory only + mutable std::vector vMerkleTree; + + // Denial-of-service detection: + mutable int nDoS; + bool DoS(int nDoSIn, bool fIn) const { nDoS += nDoSIn; return fIn; } + + CBlock() + { + SetNull(); + } + + IMPLEMENT_SERIALIZE + ( + READWRITE(this->nVersion); + nVersion = this->nVersion; + READWRITE(hashPrevBlock); + READWRITE(hashMerkleRoot); + READWRITE(nTime); + READWRITE(nBits); + READWRITE(nNonce); + + // ConnectBlock depends on vtx following header to generate CDiskTxPos + if (!(nType & (SER_GETHASH|SER_BLOCKHEADERONLY))) + { + READWRITE(vtx); + READWRITE(vchBlockSig); + } + else if (fRead) + { + const_cast(this)->vtx.clear(); + const_cast(this)->vchBlockSig.clear(); + } + ) + + void SetNull() + { + nVersion = CBlock::CURRENT_VERSION; + hashPrevBlock = 0; + hashMerkleRoot = 0; + nTime = 0; + nBits = 0; + nNonce = 0; + vtx.clear(); + vchBlockSig.clear(); + vMerkleTree.clear(); + nDoS = 0; + } + + bool IsNull() const + { + return (nBits == 0); + } + + uint256 GetHash() const + { + return Hash9(BEGIN(nVersion), END(nNonce)); + } + + int64 GetBlockTime() const + { + return (int64)nTime; + } + + void UpdateTime(const CBlockIndex* pindexPrev); + + // triangles: entropy bit for stake modifier if chosen by modifier + unsigned int GetStakeEntropyBit(unsigned int nHeight) const + { + // Take last bit of block hash as entropy bit + unsigned int nEntropyBit = ((GetHash().Get64()) & 1llu); + if (fDebug && GetBoolArg("-printstakemodifier")) + printf("GetStakeEntropyBit: nHeight=%u hashBlock=%s nEntropyBit=%u\n", nHeight, GetHash().ToString().c_str(), nEntropyBit); + return nEntropyBit; + } + + // triangles: two types of block: proof-of-work or proof-of-stake + bool IsProofOfStake() const + { + return (vtx.size() > 1 && vtx[1].IsCoinStake()); + } + + bool IsProofOfWork() const + { + return !IsProofOfStake(); + } + + std::pair GetProofOfStake() const + { + return IsProofOfStake()? std::make_pair(vtx[1].vin[0].prevout, vtx[1].nTime) : std::make_pair(COutPoint(), (unsigned int)0); + } + + // triangles: get max transaction timestamp + int64 GetMaxTransactionTime() const + { + int64 maxTransactionTime = 0; + BOOST_FOREACH(const CTransaction& tx, vtx) + maxTransactionTime = std::max(maxTransactionTime, (int64)tx.nTime); + return maxTransactionTime; + } + + uint256 BuildMerkleTree() const + { + vMerkleTree.clear(); + BOOST_FOREACH(const CTransaction& tx, vtx) + vMerkleTree.push_back(tx.GetHash()); + int j = 0; + for (int nSize = vtx.size(); nSize > 1; nSize = (nSize + 1) / 2) + { + for (int i = 0; i < nSize; i += 2) + { + int i2 = std::min(i+1, nSize-1); + vMerkleTree.push_back(Hash(BEGIN(vMerkleTree[j+i]), END(vMerkleTree[j+i]), + BEGIN(vMerkleTree[j+i2]), END(vMerkleTree[j+i2]))); + } + j += nSize; + } + return (vMerkleTree.empty() ? 0 : vMerkleTree.back()); + } + + std::vector GetMerkleBranch(int nIndex) const + { + if (vMerkleTree.empty()) + BuildMerkleTree(); + std::vector vMerkleBranch; + int j = 0; + for (int nSize = vtx.size(); nSize > 1; nSize = (nSize + 1) / 2) + { + int i = std::min(nIndex^1, nSize-1); + vMerkleBranch.push_back(vMerkleTree[j+i]); + nIndex >>= 1; + j += nSize; + } + return vMerkleBranch; + } + + static uint256 CheckMerkleBranch(uint256 hash, const std::vector& vMerkleBranch, int nIndex) + { + if (nIndex == -1) + return 0; + BOOST_FOREACH(const uint256& otherside, vMerkleBranch) + { + if (nIndex & 1) + hash = Hash(BEGIN(otherside), END(otherside), BEGIN(hash), END(hash)); + else + hash = Hash(BEGIN(hash), END(hash), BEGIN(otherside), END(otherside)); + nIndex >>= 1; + } + return hash; + } + + + bool WriteToDisk(unsigned int& nFileRet, unsigned int& nBlockPosRet) + { + // Open history file to append + CAutoFile fileout = CAutoFile(AppendBlockFile(nFileRet), SER_DISK, CLIENT_VERSION); + if (!fileout) + return error("CBlock::WriteToDisk() : AppendBlockFile failed"); + + // Write index header + unsigned int nSize = fileout.GetSerializeSize(*this); + fileout << FLATDATA(pchMessageStart) << nSize; + + // Write block + long fileOutPos = ftell(fileout); + if (fileOutPos < 0) + return error("CBlock::WriteToDisk() : ftell failed"); + nBlockPosRet = fileOutPos; + fileout << *this; + + // Flush stdio buffers and commit to disk before returning + fflush(fileout); + if (!IsInitialBlockDownload() || (nBestHeight+1) % 500 == 0) + FileCommit(fileout); + + return true; + } + + bool ReadFromDisk(unsigned int nFile, unsigned int nBlockPos, bool fReadTransactions=true) + { + SetNull(); + + // Open history file to read + CAutoFile filein = CAutoFile(OpenBlockFile(nFile, nBlockPos, "rb"), SER_DISK, CLIENT_VERSION); + if (!filein) + return error("CBlock::ReadFromDisk() : OpenBlockFile failed"); + if (!fReadTransactions) + filein.nType |= SER_BLOCKHEADERONLY; + + // Read block + try { + filein >> *this; + } + catch (std::exception &e) { + return error("%s() : deserialize or I/O error", __PRETTY_FUNCTION__); + } + + // Check the header + if (fReadTransactions && IsProofOfWork() && !CheckProofOfWork(GetHash(), nBits)) + return error("CBlock::ReadFromDisk() : errors in block header"); + + return true; + } + + + + void print() const + { + printf("CBlock(hash=%s, ver=%d, hashPrevBlock=%s, hashMerkleRoot=%s, nTime=%u, nBits=%08x, nNonce=%u, vtx=%"PRIszu", vchBlockSig=%s)\n", + GetHash().ToString().c_str(), + nVersion, + hashPrevBlock.ToString().c_str(), + hashMerkleRoot.ToString().c_str(), + nTime, nBits, nNonce, + vtx.size(), + HexStr(vchBlockSig.begin(), vchBlockSig.end()).c_str()); + for (unsigned int i = 0; i < vtx.size(); i++) + { + printf(" "); + vtx[i].print(); + } + printf(" vMerkleTree: "); + for (unsigned int i = 0; i < vMerkleTree.size(); i++) + printf("%s ", vMerkleTree[i].ToString().substr(0,10).c_str()); + printf("\n"); + } + + + bool DisconnectBlock(CTxDB& txdb, CBlockIndex* pindex); + bool ConnectBlock(CTxDB& txdb, CBlockIndex* pindex, bool fJustCheck=false); + bool ReadFromDisk(const CBlockIndex* pindex, bool fReadTransactions=true); + bool SetBestChain(CTxDB& txdb, CBlockIndex* pindexNew); + bool AddToBlockIndex(unsigned int nFile, unsigned int nBlockPos); + bool CheckBlock(bool fCheckPOW=true, bool fCheckMerkleRoot=true) const; + bool AcceptBlock(); + bool GetCoinAge(uint64& nCoinAge) const; // triangles: calculate total coin age spent in block + bool SignBlock(const CKeyStore& keystore); + bool CheckBlockSignature() const; + +private: + bool SetBestChainInner(CTxDB& txdb, CBlockIndex *pindexNew); +}; + + + + + + +/** The block chain is a tree shaped structure starting with the + * genesis block at the root, with each block potentially having multiple + * candidates to be the next block. pprev and pnext link a path through the + * main/longest chain. A blockindex may have multiple pprev pointing back + * to it, but pnext will only point forward to the longest branch, or will + * be null if the block is not part of the longest chain. + */ +class CBlockIndex +{ +public: + const uint256* phashBlock; + CBlockIndex* pprev; + CBlockIndex* pnext; + unsigned int nFile; + unsigned int nBlockPos; + CBigNum bnChainTrust; // triangles: trust score of block chain + int nHeight; + + int64 nMint; + int64 nMoneySupply; + + unsigned int nFlags; // triangles: block index flags + enum + { + BLOCK_PROOF_OF_STAKE = (1 << 0), // is proof-of-stake block + BLOCK_STAKE_ENTROPY = (1 << 1), // entropy bit for stake modifier + BLOCK_STAKE_MODIFIER = (1 << 2), // regenerated stake modifier + }; + + uint64 nStakeModifier; // hash modifier for proof-of-stake + unsigned int nStakeModifierChecksum; // checksum of index; in-memeory only + + // proof-of-stake specific fields + COutPoint prevoutStake; + unsigned int nStakeTime; + uint256 hashProofOfStake; + + // block header + int nVersion; + uint256 hashMerkleRoot; + unsigned int nTime; + unsigned int nBits; + unsigned int nNonce; + + CBlockIndex() + { + phashBlock = NULL; + pprev = NULL; + pnext = NULL; + nFile = 0; + nBlockPos = 0; + nHeight = 0; + bnChainTrust = 0; + nMint = 0; + nMoneySupply = 0; + nFlags = 0; + nStakeModifier = 0; + nStakeModifierChecksum = 0; + hashProofOfStake = 0; + prevoutStake.SetNull(); + nStakeTime = 0; + + nVersion = 0; + hashMerkleRoot = 0; + nTime = 0; + nBits = 0; + nNonce = 0; + } + + CBlockIndex(unsigned int nFileIn, unsigned int nBlockPosIn, CBlock& block) + { + phashBlock = NULL; + pprev = NULL; + pnext = NULL; + nFile = nFileIn; + nBlockPos = nBlockPosIn; + nHeight = 0; + bnChainTrust = 0; + nMint = 0; + nMoneySupply = 0; + nFlags = 0; + nStakeModifier = 0; + nStakeModifierChecksum = 0; + hashProofOfStake = 0; + if (block.IsProofOfStake()) + { + SetProofOfStake(); + prevoutStake = block.vtx[1].vin[0].prevout; + nStakeTime = block.vtx[1].nTime; + } + else + { + prevoutStake.SetNull(); + nStakeTime = 0; + } + + nVersion = block.nVersion; + hashMerkleRoot = block.hashMerkleRoot; + nTime = block.nTime; + nBits = block.nBits; + nNonce = block.nNonce; + } + + CBlock GetBlockHeader() const + { + CBlock block; + block.nVersion = nVersion; + if (pprev) + block.hashPrevBlock = pprev->GetBlockHash(); + block.hashMerkleRoot = hashMerkleRoot; + block.nTime = nTime; + block.nBits = nBits; + block.nNonce = nNonce; + return block; + } + + uint256 GetBlockHash() const + { + return *phashBlock; + } + + int64 GetBlockTime() const + { + return (int64)nTime; + } + + CBigNum GetBlockTrust() const; + + bool IsInMainChain() const + { + return (pnext || this == pindexBest); + } + + bool CheckIndex() const + { + return true; + } + + enum { nMedianTimeSpan=11 }; + + int64 GetMedianTimePast() const + { + int64 pmedian[nMedianTimeSpan]; + int64* pbegin = &pmedian[nMedianTimeSpan]; + int64* pend = &pmedian[nMedianTimeSpan]; + + const CBlockIndex* pindex = this; + for (int i = 0; i < nMedianTimeSpan && pindex; i++, pindex = pindex->pprev) + *(--pbegin) = pindex->GetBlockTime(); + + std::sort(pbegin, pend); + return pbegin[(pend - pbegin)/2]; + } + + int64 GetMedianTime() const + { + const CBlockIndex* pindex = this; + for (int i = 0; i < nMedianTimeSpan/2; i++) + { + if (!pindex->pnext) + return GetBlockTime(); + pindex = pindex->pnext; + } + return pindex->GetMedianTimePast(); + } + + /** + * Returns true if there are nRequired or more blocks of minVersion or above + * in the last nToCheck blocks, starting at pstart and going backwards. + */ + static bool IsSuperMajority(int minVersion, const CBlockIndex* pstart, + unsigned int nRequired, unsigned int nToCheck); + + + bool IsProofOfWork() const + { + return !(nFlags & BLOCK_PROOF_OF_STAKE); + } + + bool IsProofOfStake() const + { + return (nFlags & BLOCK_PROOF_OF_STAKE); + } + + void SetProofOfStake() + { + nFlags |= BLOCK_PROOF_OF_STAKE; + } + + unsigned int GetStakeEntropyBit() const + { + return ((nFlags & BLOCK_STAKE_ENTROPY) >> 1); + } + + bool SetStakeEntropyBit(unsigned int nEntropyBit) + { + if (nEntropyBit > 1) + return false; + nFlags |= (nEntropyBit? BLOCK_STAKE_ENTROPY : 0); + return true; + } + + bool GeneratedStakeModifier() const + { + return (nFlags & BLOCK_STAKE_MODIFIER); + } + + void SetStakeModifier(uint64 nModifier, bool fGeneratedStakeModifier) + { + nStakeModifier = nModifier; + if (fGeneratedStakeModifier) + nFlags |= BLOCK_STAKE_MODIFIER; + } + + std::string ToString() const + { + return strprintf("CBlockIndex(nprev=%p, pnext=%p, nFile=%u, nBlockPos=%-6d nHeight=%d, nMint=%s, nMoneySupply=%s, nFlags=(%s)(%d)(%s), nStakeModifier=%016"PRI64x", nStakeModifierChecksum=%08x, hashProofOfStake=%s, prevoutStake=(%s), nStakeTime=%d merkle=%s, hashBlock=%s)", + pprev, pnext, nFile, nBlockPos, nHeight, + FormatMoney(nMint).c_str(), FormatMoney(nMoneySupply).c_str(), + GeneratedStakeModifier() ? "MOD" : "-", GetStakeEntropyBit(), IsProofOfStake()? "PoS" : "PoW", + nStakeModifier, nStakeModifierChecksum, + hashProofOfStake.ToString().c_str(), + prevoutStake.ToString().c_str(), nStakeTime, + hashMerkleRoot.ToString().c_str(), + GetBlockHash().ToString().c_str()); + } + + void print() const + { + printf("%s\n", ToString().c_str()); + } +}; + + + +/** Used to marshal pointers into hashes for db storage. */ +class CDiskBlockIndex : public CBlockIndex +{ +public: + uint256 hashPrev; + uint256 hashNext; + + CDiskBlockIndex() + { + hashPrev = 0; + hashNext = 0; + } + + explicit CDiskBlockIndex(CBlockIndex* pindex) : CBlockIndex(*pindex) + { + hashPrev = (pprev ? pprev->GetBlockHash() : 0); + hashNext = (pnext ? pnext->GetBlockHash() : 0); + } + + IMPLEMENT_SERIALIZE + ( + if (!(nType & SER_GETHASH)) + READWRITE(nVersion); + + READWRITE(hashNext); + READWRITE(nFile); + READWRITE(nBlockPos); + READWRITE(nHeight); + READWRITE(nMint); + READWRITE(nMoneySupply); + READWRITE(nFlags); + READWRITE(nStakeModifier); + if (IsProofOfStake()) + { + READWRITE(prevoutStake); + READWRITE(nStakeTime); + READWRITE(hashProofOfStake); + } + else if (fRead) + { + const_cast(this)->prevoutStake.SetNull(); + const_cast(this)->nStakeTime = 0; + const_cast(this)->hashProofOfStake = 0; + } + + // block header + READWRITE(this->nVersion); + READWRITE(hashPrev); + READWRITE(hashMerkleRoot); + READWRITE(nTime); + READWRITE(nBits); + READWRITE(nNonce); + ) + + uint256 GetBlockHash() const + { + CBlock block; + block.nVersion = nVersion; + block.hashPrevBlock = hashPrev; + block.hashMerkleRoot = hashMerkleRoot; + block.nTime = nTime; + block.nBits = nBits; + block.nNonce = nNonce; + return block.GetHash(); + } + + + std::string ToString() const + { + std::string str = "CDiskBlockIndex("; + str += CBlockIndex::ToString(); + str += strprintf("\n hashBlock=%s, hashPrev=%s, hashNext=%s)", + GetBlockHash().ToString().c_str(), + hashPrev.ToString().c_str(), + hashNext.ToString().c_str()); + return str; + } + + void print() const + { + printf("%s\n", ToString().c_str()); + } +}; + + + + + + + + +/** Describes a place in the block chain to another node such that if the + * other node doesn't have the same branch, it can find a recent common trunk. + * The further back it is, the further before the fork it may be. + */ +class CBlockLocator +{ +protected: + std::vector vHave; +public: + + CBlockLocator() + { + } + + explicit CBlockLocator(const CBlockIndex* pindex) + { + Set(pindex); + } + + explicit CBlockLocator(uint256 hashBlock) + { + std::map::iterator mi = mapBlockIndex.find(hashBlock); + if (mi != mapBlockIndex.end()) + Set((*mi).second); + } + + CBlockLocator(const std::vector& vHaveIn) + { + vHave = vHaveIn; + } + + IMPLEMENT_SERIALIZE + ( + if (!(nType & SER_GETHASH)) + READWRITE(nVersion); + READWRITE(vHave); + ) + + void SetNull() + { + vHave.clear(); + } + + bool IsNull() + { + return vHave.empty(); + } + + void Set(const CBlockIndex* pindex) + { + vHave.clear(); + int nStep = 1; + while (pindex) + { + vHave.push_back(pindex->GetBlockHash()); + + // Exponentially larger steps back + for (int i = 0; pindex && i < nStep; i++) + pindex = pindex->pprev; + if (vHave.size() > 10) + nStep *= 2; + } + vHave.push_back((!fTestNet ? hashGenesisBlock : hashGenesisBlockTestNet)); + } + + int GetDistanceBack() + { + // Retrace how far back it was in the sender's branch + int nDistance = 0; + int nStep = 1; + BOOST_FOREACH(const uint256& hash, vHave) + { + std::map::iterator mi = mapBlockIndex.find(hash); + if (mi != mapBlockIndex.end()) + { + CBlockIndex* pindex = (*mi).second; + if (pindex->IsInMainChain()) + return nDistance; + } + nDistance += nStep; + if (nDistance > 10) + nStep *= 2; + } + return nDistance; + } + + CBlockIndex* GetBlockIndex() + { + // Find the first block the caller has in the main chain + BOOST_FOREACH(const uint256& hash, vHave) + { + std::map::iterator mi = mapBlockIndex.find(hash); + if (mi != mapBlockIndex.end()) + { + CBlockIndex* pindex = (*mi).second; + if (pindex->IsInMainChain()) + return pindex; + } + } + return pindexGenesisBlock; + } + + uint256 GetBlockHash() + { + // Find the first block the caller has in the main chain + BOOST_FOREACH(const uint256& hash, vHave) + { + std::map::iterator mi = mapBlockIndex.find(hash); + if (mi != mapBlockIndex.end()) + { + CBlockIndex* pindex = (*mi).second; + if (pindex->IsInMainChain()) + return hash; + } + } + return (!fTestNet ? hashGenesisBlock : hashGenesisBlockTestNet); + } + + int GetHeight() + { + CBlockIndex* pindex = GetBlockIndex(); + if (!pindex) + return 0; + return pindex->nHeight; + } +}; + + + + + + + + +class CTxMemPool +{ +public: + mutable CCriticalSection cs; + std::map mapTx; + std::map mapNextTx; + + bool accept(CTxDB& txdb, CTransaction &tx, + bool fCheckInputs, bool* pfMissingInputs); + bool addUnchecked(const uint256& hash, CTransaction &tx); + bool remove(CTransaction &tx); + void clear(); + void queryHashes(std::vector& vtxid); + + unsigned long size() + { + LOCK(cs); + return mapTx.size(); + } + + bool exists(uint256 hash) + { + return (mapTx.count(hash) != 0); + } + + CTransaction& lookup(uint256 hash) + { + return mapTx[hash]; + } +}; + +extern CTxMemPool mempool; + +#endif diff --git a/src/makefile.bsd b/src/makefile.bsd new file mode 100644 index 0000000..86a83f1 --- /dev/null +++ b/src/makefile.bsd @@ -0,0 +1,189 @@ +# Copyright (c) 2009-2010 Satoshi Nakamoto +# Distributed under the MIT/X11 software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +USE_UPNP:=0 +USE_IPV6:=1 + +LINK:=$(CXX) + +DEFS=-DBOOST_SPIRIT_THREADSAFE + +DEFS += $(addprefix -I,$(CURDIR) $(CURDIR)/obj $(BOOST_INCLUDE_PATH) $(BDB_INCLUDE_PATH) $(OPENSSL_INCLUDE_PATH)) +LIBS = $(addprefix -L,$(BOOST_LIB_PATH) $(BDB_LIB_PATH) $(OPENSSL_LIB_PATH)) + +TESTDEFS = -DTEST_DATA_DIR=$(abspath test/data) + +LMODE = dynamic +LMODE2 = dynamic +ifdef STATIC + LMODE = static + ifeq (${STATIC}, all) + LMODE2 = static + endif +else + TESTDEFS += -DBOOST_TEST_DYN_LINK +endif + +# for boost 1.37, add -mt to the boost libraries +LIBS += \ + -Wl,-B$(LMODE) \ + -l boost_system$(BOOST_LIB_SUFFIX) \ + -l boost_filesystem$(BOOST_LIB_SUFFIX) \ + -l boost_program_options$(BOOST_LIB_SUFFIX) \ + -l boost_thread$(BOOST_LIB_SUFFIX) \ + -l db_cxx$(BDB_LIB_SUFFIX) \ + -l ssl \ + -l crypto \ + -l execinfo + +ifndef USE_UPNP + override USE_UPNP = - +endif +ifneq (${USE_UPNP}, -) + LIBS += -l miniupnpc + DEFS += -DUSE_UPNP=$(USE_UPNP) +endif + +ifneq (${USE_IPV6}, -) + DEFS += -DUSE_IPV6=$(USE_IPV6) +endif + +LIBS+= \ + -Wl,-B$(LMODE2) \ + -l z \ + -l dl \ + -l pthread + + +# Hardening +# Make some classes of vulnerabilities unexploitable in case one is discovered. +# + # This is a workaround for Ubuntu bug #691722, the default -fstack-protector causes + # -fstack-protector-all to be ignored unless -fno-stack-protector is used first. + # see: https://bugs.launchpad.net/ubuntu/+source/gcc-4.5/+bug/691722 + HARDENING=-fno-stack-protector + + # Stack Canaries + # Put numbers at the beginning of each stack frame and check that they are the same. + # If a stack buffer if overflowed, it writes over the canary number and then on return + # when that number is checked, it won't be the same and the program will exit with + # a "Stack smashing detected" error instead of being exploited. + HARDENING+=-fstack-protector-all -Wstack-protector + + # Make some important things such as the global offset table read only as soon as + # the dynamic linker is finished building it. This will prevent overwriting of addresses + # which would later be jumped to. + LDHARDENING+=-Wl,-z,relro -Wl,-z,now + + # Build position independent code to take advantage of Address Space Layout Randomization + # offered by some kernels. + # see doc/build-unix.txt for more information. + ifdef PIE + HARDENING+=-fPIE + LDHARDENING+=-pie + endif + + # -D_FORTIFY_SOURCE=2 does some checking for potentially exploitable code patterns in + # the source such overflowing a statically defined buffer. + HARDENING+=-D_FORTIFY_SOURCE=2 +# + + +DEBUGFLAGS=-g + +# CXXFLAGS can be specified on the make command line, so we use xCXXFLAGS that only +# adds some defaults in front. Unfortunately, CXXFLAGS=... $(CXXFLAGS) does not work. +xCXXFLAGS=-O0 -msse2 -pthread -Wall -Wextra -Wformat -Wformat-security -Wno-unused-parameter \ + $(DEBUGFLAGS) $(DEFS) $(HARDENING) $(CXXFLAGS) + +# LDFLAGS can be specified on the make command line, so we use xLDFLAGS that only +# adds some defaults in front. Unfortunately, LDFLAGS=... $(LDFLAGS) does not work. +xLDFLAGS=$(LDHARDENING) $(LDFLAGS) + +OBJS= \ + obj/alert.o \ + obj/version.o \ + obj/checkpoints.o \ + obj/netbase.o \ + obj/addrman.o \ + obj/crypter.o \ + obj/key.o \ + obj/db.o \ + obj/init.o \ + obj/irc.o \ + obj/keystore.o \ + obj/main.o \ + obj/net.o \ + obj/protocol.o \ + obj/bitcoinrpc.o \ + obj/rpcdump.o \ + obj/rpcnet.o \ + obj/rpcmining.o \ + obj/rpcwallet.o \ + obj/rpcblockchain.o \ + obj/rpcrawtransaction.o \ + obj/script.o \ + obj/sync.o \ + obj/util.o \ + obj/wallet.o \ + obj/walletdb.o \ + obj/noui.o \ + obj/kernel.o \ + obj/pbkdf2.o \ + obj/scrypt_mine.o \ + obj/scrypt-x86.o \ + obj/scrypt-x86_64.o + + +all: trianglesd + +test check: test_triangles FORCE + ./test_BottleCaps + +# auto-generated dependencies: +-include obj/*.P +-include obj-test/*.P + +obj/build.h: FORCE + /bin/sh ../share/genbuild.sh obj/build.h +version.cpp: obj/build.h +DEFS += -DHAVE_BUILD_INFO + +obj/scrypt-x86.o: scrypt-x86.S + $(CXX) -c $(xCXXFLAGS) -MMD -o $@ $< + +obj/scrypt-x86_64.o: scrypt-x86_64.S + $(CXX) -c $(xCXXFLAGS) -MMD -o $@ $< + +obj/%.o: %.cpp + $(CXX) -c $(xCXXFLAGS) -MMD -MF $(@:%.o=%.d) -o $@ $< + @cp $(@:%.o=%.d) $(@:%.o=%.P); \ + sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \ + -e '/^$$/ d' -e 's/$$/ :/' < $(@:%.o=%.d) >> $(@:%.o=%.P); \ + rm -f $(@:%.o=%.d) + +trianglesd: $(OBJS:obj/%=obj/%) + $(LINK) $(xCXXFLAGS) -o $@ $^ $(xLDFLAGS) $(LIBS) + +TESTOBJS := $(patsubst test/%.cpp,obj-test/%.o,$(wildcard test/*.cpp)) + +obj-test/%.o: test/%.cpp + $(CXX) -c $(TESTDEFS) $(xCXXFLAGS) -MMD -MF $(@:%.o=%.d) -o $@ $< + @cp $(@:%.o=%.d) $(@:%.o=%.P); \ + sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \ + -e '/^$$/ d' -e 's/$$/ :/' < $(@:%.o=%.d) >> $(@:%.o=%.P); \ + rm -f $(@:%.o=%.d) + +test_triangles: $(TESTOBJS) $(filter-out obj/init.o,$(OBJS:obj/%=obj/%)) + $(LINK) $(xCXXFLAGS) -o $@ $(LIBPATHS) $^ -Wl,-B$(LMODE) -lboost_unit_test_framework $(xLDFLAGS) $(LIBS) + +clean: + -rm -f trianglesd test_triangles + -rm -f obj/*.o + -rm -f obj-test/*.o + -rm -f obj/*.P + -rm -f obj-test/*.P + -rm -f obj/build.h + +FORCE: diff --git a/src/makefile.linux-mingw b/src/makefile.linux-mingw new file mode 100644 index 0000000..4757858 --- /dev/null +++ b/src/makefile.linux-mingw @@ -0,0 +1,226 @@ +# Copyright (c) 2009-2010 Satoshi Nakamoto +# Distributed under the MIT/X11 software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +DEPSDIR:=/usr/i586-mingw32msvc + +USE_UPNP:=0 +USE_IPV6:=1 + +INCLUDEPATHS= \ + -I"$(CURDIR)" \ + -I"$(CURDIR)"/obj \ + -I"$(CURDIR)"/tor \ + -I"$(DEPSDIR)/boost_1_50_0" \ + -I"$(DEPSDIR)/db-4.8.30.NC/build_unix" \ + -I"$(DEPSDIR)/openssl-1.0.1g/include" \ + -I"$(DEPSDIR)" + +LIBPATHS= \ + -L"$(DEPSDIR)/boost_1_50_0/stage/lib" \ + -L"$(DEPSDIR)/db-4.8.30.NC/build_unix" \ + -L"$(DEPSDIR)/openssl-1.0.1g" + +LIBS= \ + -l boost_system-mt-s \ + -l boost_filesystem-mt-s \ + -l boost_program_options-mt-s \ + -l boost_thread_win32-mt-s \ + -l boost_chrono-mt-s \ + -l db_cxx \ + -l ssl \ + -l crypto + +DEFS=-D_MT -DWIN32 -D_WINDOWS -DBOOST_THREAD_USE_LIB -DBOOST_SPIRIT_THREADSAFE +DEBUGFLAGS=-g +CFLAGS=-O2 -msse2 -w -Wall -Wextra -Wformat -Wformat-security -Wno-unused-parameter $(DEBUGFLAGS) $(DEFS) $(INCLUDEPATHS) +LDFLAGS=-Wl,--dynamicbase -Wl,--nxcompat + +TESTDEFS = -DTEST_DATA_DIR=$(abspath test/data) + +ifndef USE_UPNP + override USE_UPNP = - +endif +ifneq (${USE_UPNP}, -) + LIBPATHS += -L"$(DEPSDIR)/miniupnpc" + LIBS += -l miniupnpc -l iphlpapi + DEFS += -DSTATICLIB -DUSE_UPNP=$(USE_UPNP) +endif + +ifneq (${USE_IPV6}, -) + DEFS += -DUSE_IPV6=$(USE_IPV6) +endif + +LIBS += -l mingwthrd -l kernel32 -l user32 -l gdi32 -l comdlg32 -l winspool -l winmm -l shell32 -l comctl32 -l ole32 -l oleaut32 -l uuid -l rpcrt4 -l advapi32 -l ws2_32 -l mswsock -l shlwapi + +# TODO: make the mingw builds smarter about dependencies, like the linux/osx builds are +HEADERS = $(wildcard *.h) + +OBJS= \ + obj/address.o \ + obj/addressmap.o \ + obj/aes.o \ + obj/backtrace.o \ + obj/buffers.o \ + obj/channel.o \ + obj/channeltls.o \ + obj/circpathbias.o \ + obj/circuitbuild.o \ + obj/circuitlist.o \ + obj/circuitmux.o \ + obj/circuitmux_ewma.o \ + obj/circuitstats.o \ + obj/circuituse.o \ + obj/command.o \ + obj/compat.o \ + obj/compat_libevent.o \ + obj/config.o \ + obj/config_codedigest.o \ + obj/confparse.o \ + obj/connection.o \ + obj/connection_edge.o \ + obj/connection_or.o \ + obj/container.o \ + obj/control.o \ + obj/cpuworker.o \ + obj/crypto.o \ + obj/crypto_curve25519.o \ + obj/crypto_format.o \ + obj/curve25519-donna.o \ + obj/di_ops.o \ + obj/directory.o \ + obj/dirserv.o \ + obj/dirvote.o \ + obj/dns.o \ + obj/dnsserv.o \ + obj/entrynodes.o \ + obj/ext_orport.o \ + obj/fp_pair.o \ + obj/geoip.o \ + obj/hibernate.o \ + obj/log.o \ + obj/memarea.o \ + obj/mempool.o \ + obj/microdesc.o \ + obj/networkstatus.o \ + obj/nodelist.o \ + obj/onion.o \ + obj/onion_fast.o \ + obj/onion_main.o \ + obj/onion_ntor.o \ + obj/onion_tap.o \ + obj/policies.o \ + obj/procmon.o \ + obj/reasons.o \ + obj/relay.o \ + obj/rendclient.o \ + obj/rendcommon.o \ + obj/rendmid.o \ + obj/rendservice.o \ + obj/rephist.o \ + obj/replaycache.o \ + obj/router.o \ + obj/routerlist.o \ + obj/routerparse.o \ + obj/routerset.o \ + obj/sandbox.o \ + obj/statefile.o \ + obj/status.o \ + obj/tor_util.o \ + obj/torgzip.o \ + obj/tortls.o \ + obj/transports.o \ + obj/util_codedigest.o \ + obj/aes_helper.o \ + obj/fugue.o \ + obj/hamsi.o \ + obj/groestl.o \ + obj/blake.o \ + obj/bmw.o \ + obj/skein.o \ + obj/keccak.o \ + obj/shavite.o \ + obj/jh.o \ + obj/luffa.o \ + obj/cubehash.o \ + obj/echo.o \ + obj/simd.o \ + obj/alert.o \ + obj/version.o \ + obj/checkpoints.o \ + obj/netbase.o \ + obj/addrman.o \ + obj/crypter.o \ + obj/key.o \ + obj/db.o \ + obj/init.o \ + obj/irc.o \ + obj/keystore.o \ + obj/main.o \ + obj/net.o \ + obj/protocol.o \ + obj/bitcoinrpc.o \ + obj/rpcdump.o \ + obj/rpcnet.o \ + obj/rpcmining.o \ + obj/rpcwallet.o \ + obj/rpcblockchain.o \ + obj/rpcrawtransaction.o \ + obj/script.o \ + obj/sync.o \ + obj/util.o \ + obj/wallet.o \ + obj/walletdb.o \ + obj/noui.o \ + obj/kernel.o \ + obj/pbkdf2.o \ + obj/scrypt.o \ + obj/scrypt_mine.o \ + obj/scrypt-x86.o \ + obj/scrypt-x86_64.o + +all: StealthCoind.exe + +obj/build.h: FORCE + /bin/sh ../share/genbuild.sh obj/build.h +version.cpp: obj/build.h +DEFS += -DHAVE_BUILD_INFO + +obj/%.o: %.cpp $(HEADERS) + i586-mingw32msvc-g++ -c $(CFLAGS) -o $@ $< + +obj/%.o: %.c $(HEADERS) + i586-mingw32msvc-g++ -c $(CFLAGS) -fpermissive -o $@ $< + +obj/%.o: tor/%.c + $(CC) -c $(xCXXFLAGS) -o $@ $< + +obj/%.o: tor/anonymize.cpp + $(CXX) -c $(xCXXFLAGS) -o $@ $< + + +StealthCoind.exe: $(OBJS:obj/%=obj/%) + i586-mingw32msvc-g++ $(CFLAGS) $(LDFLAGS) -o $@ $(LIBPATHS) $^ $(LIBS) + +TESTOBJS := $(patsubst test/%.cpp,obj-test/%.o,$(wildcard test/*.cpp)) + +obj-test/%.o: test/%.cpp $(HEADERS) + i586-mingw32msvc-g++ -c $(TESTDEFS) $(CFLAGS) -o $@ $< + +test_triangles.exe: $(TESTOBJS) $(filter-out obj/init.o,$(OBJS:obj/%=obj/%)) + i586-mingw32msvc-g++ $(CFLAGS) $(LDFLAGS) -o $@ $(LIBPATHS) $^ -lboost_unit_test_framework-mt-s $(LIBS) + +obj/scrypt-x86.o: scrypt-x86.S + i586-mingw32msvc-g++ -c $(CFLAGS) -MMD -o $@ $< + +obj/scrypt-x86_64.o: scrypt-x86_64.S + i586-mingw32msvc-g++ -c $(CFLAGS) -MMD -o $@ $< + +clean: + -rm -f obj/*.o + -rm -f StealthCoind.exe + -rm -f obj-test/*.o + -rm -f test_triangles.exe + -rm -f obj/build.h + +FORCE: diff --git a/src/makefile.mingw b/src/makefile.mingw new file mode 100644 index 0000000..8b7fcc7 --- /dev/null +++ b/src/makefile.mingw @@ -0,0 +1,118 @@ +# Copyright (c) 2009-2010 Satoshi Nakamoto +# Distributed under the MIT/X11 software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +USE_UPNP:=0 +USE_IPV6:=0 + +INCLUDEPATHS= \ + -I"C:/deps/boost_1_53_0" \ + -I"C:/deps/db-4.8.30.NC/build_unix" \ + -I"C:/deps/openssl-1.0.1g/include" + +LIBPATHS= \ + -L"C:/deps/boost_1_53_0/stage/lib" \ + -L"C:/deps/db-4.8.30.NC/build_unix" \ + -L"C:/deps/openssl-1.0.1g" + + +LIBS= \ + -l boost_system-mgw48-mt-s-1_53 \ + -l boost_filesystem-mgw48-mt-s-1_53 \ + -l boost_program_options-mgw48-mt-s-1_53 \ + -l boost_thread-mgw48-mt-s-1_53 \ + -l db_cxx \ + -l ssl \ + -l crypto + +DEFS=-DWIN32 -D_WINDOWS -DBOOST_THREAD_USE_LIB -DBOOST_SPIRIT_THREADSAFE -D__NO_SYSTEM_INCLUDES +DEBUGFLAGS=-g +CFLAGS=-mthreads -O2 -msse2 -w -Wall -Wextra -Wformat -Wformat-security -Wno-unused-parameter $(DEBUGFLAGS) $(DEFS) $(INCLUDEPATHS) +LDFLAGS=-Wl,--dynamicbase -Wl,--nxcompat + +TESTDEFS = -DTEST_DATA_DIR=$(abspath test/data) + +ifndef USE_UPNP + override USE_UPNP = - +endif +ifneq (${USE_UPNP}, -) + INCLUDEPATHS += -I"C:/deps/" + LIBPATHS += -L"C:/deps/miniupnpc" + LIBS += -l miniupnpc -l iphlpapi + DEFS += -DSTATICLIB -DUSE_UPNP=$(USE_UPNP) +endif + +ifneq (${USE_IPV6}, -) + DEFS += -DUSE_IPV6=$(USE_IPV6) +endif + +LIBS += -l kernel32 -l user32 -l gdi32 -l comdlg32 -l winspool -l winmm -l shell32 -l comctl32 -l ole32 -l oleaut32 -l uuid -l rpcrt4 -l advapi32 -l ws2_32 -l mswsock -l shlwapi + +# TODO: make the mingw builds smarter about dependencies, like the linux/osx builds are +HEADERS = $(wildcard *.h) + +OBJS= \ + obj/alert.o \ + obj/version.o \ + obj/checkpoints.o \ + obj/netbase.o \ + obj/addrman.o \ + obj/crypter.o \ + obj/key.o \ + obj/db.o \ + obj/init.o \ + obj/irc.o \ + obj/keystore.o \ + obj/main.o \ + obj/net.o \ + obj/protocol.o \ + obj/bitcoinrpc.o \ + obj/rpcdump.o \ + obj/rpcnet.o \ + obj/rpcmining.o \ + obj/rpcwallet.o \ + obj/rpcblockchain.o \ + obj/rpcrawtransaction.o \ + obj/script.o \ + obj/sync.o \ + obj/util.o \ + obj/wallet.o \ + obj/walletdb.o \ + obj/noui.o \ + obj/kernel.o \ + obj/pbkdf2.o \ + obj/scrypt_mine.o \ + obj/scrypt-x86.o \ + obj/scrypt-x86_64.o + +all: trianglesd.exe + +test check: test_triangles.exe FORCE + test_triangles.exe + +obj/%.o: %.cpp $(HEADERS) + g++ -c $(CFLAGS) -o $@ $< + +obj/scrypt-x86.o: scrypt-x86.S + $(CXX) -c $(xCXXFLAGS) -MMD -o $@ $< + +obj/scrypt-x86_64.o: scrypt-x86_64.S + $(CXX) -c $(xCXXFLAGS) -MMD -o $@ $< + +trianglesd.exe: $(OBJS:obj/%=obj/%) + g++ $(CFLAGS) $(LDFLAGS) -o $@ $(LIBPATHS) $^ $(LIBS) + +TESTOBJS := $(patsubst test/%.cpp,obj-test/%.o,$(wildcard test/*.cpp)) + +obj-test/%.o: test/%.cpp $(HEADERS) + g++ -c $(TESTDEFS) $(CFLAGS) -o $@ $< + +test_triangles.exe: $(TESTOBJS) $(filter-out obj/init.o,$(OBJS:obj/%=obj/%)) + g++ $(CFLAGS) $(LDFLAGS) -o $@ $(LIBPATHS) $^ -lboost_unit_test_framework $(LIBS) + +clean: + -del /Q triangles test_triangles + -del /Q obj\* + -del /Q obj-test\* + +FORCE: diff --git a/src/makefile.osx b/src/makefile.osx new file mode 100644 index 0000000..e449984 --- /dev/null +++ b/src/makefile.osx @@ -0,0 +1,286 @@ +# -*- mode: Makefile; -*- +# Copyright (c) 2011 Bitcoin Developers +# Distributed under the MIT/X11 software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +# Mac OS X makefile for bitcoin +# Originally by Laszlo Hanyecz (solar@heliacal.net) + +CXX=llvm-g++ +CC=llvm-gcc +DEPSDIR=/opt/local + +INCLUDEPATHS= \ + -I"$(CURDIR)" \ + -I"$(CURDIR)/obj" \ + -I"$(CURDIR)/tor" \ + -I"$(DEPSDIR)/include" \ + -I"$(DEPSDIR)/include/db48" \ + -I"$(DEPSDIR)/include/boost" + +LIBPATHS= \ + -L"$(DEPSDIR)/lib" \ + -L"$(DEPSDIR)/lib/db48" + +USE_UPNP:=1 +USE_IPV6:=1 + +LIBS= -dead_strip + +TESTDEFS = -DTEST_DATA_DIR=$(abspath test/data) + +ifdef STATIC +# Build STATIC if you are redistributing the bitcoind binary +TESTLIBS += \ + $(DEPSDIR)/lib/libboost_unit_test_framework-mt.a + +LIBS += \ + $(DEPSDIR)/lib/db48/libdb_cxx-4.8.a \ + $(DEPSDIR)/lib/libboost_system-mt.a \ + $(DEPSDIR)/lib/libboost_filesystem-mt.a \ + $(DEPSDIR)/lib/libboost_program_options-mt.a \ + $(DEPSDIR)/lib/libboost_thread-mt.a \ + $(DEPSDIR)/lib/libssl.a \ + $(DEPSDIR)/lib/libcrypto.a \ + -lz +else +TESTLIBS += \ + -lboost_unit_test_framework-mt +LIBS += \ + -ldb_cxx-4.8 \ + -lboost_system-mt \ + -lboost_filesystem-mt \ + -lboost_program_options-mt \ + -lboost_thread-mt \ + -lssl \ + -lcrypto \ + -lz \ + -levent +TESTDEFS += -DBOOST_TEST_DYN_LINK +endif + +DEFS=-DMAC_OSX -DMSG_NOSIGNAL=0 -DBOOST_SPIRIT_THREADSAFE + +ifdef RELEASE +# Compile for maximum compatibility and smallest size. +# This requires that dependencies are compiled +# the same way. +CFLAGS = -mmacosx-version-min=10.5 -arch x86_64 -O3 -msse2 +else +CFLAGS = -g -msse2 +endif + +# ppc doesn't work because we don't support big-endian +CFLAGS += -Wall -Wextra -Wformat -Wformat-security -Wno-unused-parameter \ + $(DEBUGFLAGS) $(DEFS) $(INCLUDEPATHS) + +OBJS= \ + obj/address.o \ + obj/addressmap.o \ + obj/aes.o \ + obj/backtrace.o \ + obj/buffers.o \ + obj/channel.o \ + obj/channeltls.o \ + obj/circpathbias.o \ + obj/circuitbuild.o \ + obj/circuitlist.o \ + obj/circuitmux.o \ + obj/circuitmux_ewma.o \ + obj/circuitstats.o \ + obj/circuituse.o \ + obj/command.o \ + obj/compat.o \ + obj/compat_libevent.o \ + obj/config.o \ + obj/config_codedigest.o \ + obj/confparse.o \ + obj/connection.o \ + obj/connection_edge.o \ + obj/connection_or.o \ + obj/container.o \ + obj/control.o \ + obj/cpuworker.o \ + obj/crypto.o \ + obj/crypto_curve25519.o \ + obj/crypto_format.o \ + obj/curve25519-donna.o \ + obj/di_ops.o \ + obj/directory.o \ + obj/dirserv.o \ + obj/dirvote.o \ + obj/dns.o \ + obj/dnsserv.o \ + obj/entrynodes.o \ + obj/ext_orport.o \ + obj/fp_pair.o \ + obj/geoip.o \ + obj/hibernate.o \ + obj/log.o \ + obj/memarea.o \ + obj/mempool.o \ + obj/microdesc.o \ + obj/networkstatus.o \ + obj/nodelist.o \ + obj/onion.o \ + obj/onion_fast.o \ + obj/onion_main.o \ + obj/onion_ntor.o \ + obj/onion_tap.o \ + obj/policies.o \ + obj/procmon.o \ + obj/reasons.o \ + obj/relay.o \ + obj/rendclient.o \ + obj/rendcommon.o \ + obj/rendmid.o \ + obj/rendservice.o \ + obj/rephist.o \ + obj/replaycache.o \ + obj/router.o \ + obj/routerlist.o \ + obj/routerparse.o \ + obj/routerset.o \ + obj/sandbox.o \ + obj/statefile.o \ + obj/status.o \ + obj/tor_util.o \ + obj/torgzip.o \ + obj/tortls.o \ + obj/transports.o \ + obj/util_codedigest.o \ + obj/aes_helper.o \ + obj/fugue.o \ + obj/hamsi.o \ + obj/groestl.o \ + obj/blake.o \ + obj/bmw.o \ + obj/skein.o \ + obj/keccak.o \ + obj/shavite.o \ + obj/jh.o \ + obj/luffa.o \ + obj/cubehash.o \ + obj/echo.o \ + obj/simd.o \ + obj/alert.o \ + obj/version.o \ + obj/checkpoints.o \ + obj/netbase.o \ + obj/addrman.o \ + obj/crypter.o \ + obj/key.o \ + obj/db.o \ + obj/init.o \ + obj/irc.o \ + obj/keystore.o \ + obj/main.o \ + obj/net.o \ + obj/protocol.o \ + obj/bitcoinrpc.o \ + obj/rpcdump.o \ + obj/rpcnet.o \ + obj/rpcmining.o \ + obj/rpcwallet.o \ + obj/rpcblockchain.o \ + obj/rpcrawtransaction.o \ + obj/script.o \ + obj/sync.o \ + obj/util.o \ + obj/wallet.o \ + obj/walletdb.o \ + obj/noui.o \ + obj/pbkdf2.o \ + obj/kernel.o \ + obj/scrypt_mine.o \ + obj/scrypt-x86.o \ + obj/scrypt-x86_64.o + +ifndef USE_UPNP + override USE_UPNP = - +endif +ifneq (${USE_UPNP}, -) + DEFS += -DUSE_UPNP=$(USE_UPNP) +ifdef STATIC + LIBS += $(DEPSDIR)/lib/libminiupnpc.a +else + LIBS += -lminiupnpc +endif +endif + +ifneq (${USE_IPV6}, -) + DEFS += -DUSE_IPV6=$(USE_IPV6) +endif + +all: trianglesd + +test check: test_triangles FORCE + ./test_triangles + +# auto-generated dependencies: +-include obj/*.P +-include obj-test/*.P + +obj/build.h: FORCE + /bin/sh ../share/genbuild.sh obj/build.h +version.cpp: obj/build.h +DEFS += -DHAVE_BUILD_INFO + +obj/%.o: %.cpp + $(CXX) -c $(CFLAGS) -MMD -MF $(@:%.o=%.d) -o $@ $< + @cp $(@:%.o=%.d) $(@:%.o=%.P); \ + sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \ + -e '/^$$/ d' -e 's/$$/ :/' < $(@:%.o=%.d) >> $(@:%.o=%.P); \ + rm -f $(@:%.o=%.d) + +obj/%.o: %.c + $(CC) -c $(CFLAGS) -MMD -MF $(@:%.o=%.d) -o $@ $< + @cp $(@:%.o=%.d) $(@:%.o=%.P); \ + sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \ + -e '/^$$/ d' -e 's/$$/ :/' < $(@:%.o=%.d) >> $(@:%.o=%.P); \ + rm -f $(@:%.o=%.d) + +obj/%.o: tor/%.c + $(CC) -c $(CFLAGS) -MMD -MF $(@:%.o=%.d) -o $@ $< + @cp $(@:%.o=%.d) $(@:%.o=%.P); \ + sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \ + -e '/^$$/ d' -e 's/$$/ :/' < $(@:%.o=%.d) >> $(@:%.o=%.P); \ + rm -f $(@:%.o=%.d) + +obj/anonymize.o: tor/anonymize.cpp + $(CXX) -c $(CFLAGS) -MMD -MF $(@:%.o=%.d) -o $@ $< + @cp $(@:%.o=%.d) $(@:%.o=%.P); \ + sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \ + -e '/^$$/ d' -e 's/$$/ :/' < $(@:%.o=%.d) >> $(@:%.o=%.P); \ + rm -f $(@:%.o=%.d) + +obj/scrypt-x86.o: scrypt-x86.S + $(CXX) -c $(xCXXFLAGS) -MMD -o $@ $< + +obj/scrypt-x86_64.o: scrypt-x86_64.S + $(CXX) -c $(xCXXFLAGS) -MMD -o $@ $< + +trianglesd: $(OBJS:obj/%=obj/%) obj/anonymize.o + $(CXX) $(CFLAGS) -o $@ $(LIBPATHS) $^ $(LIBS) + +TESTOBJS := $(patsubst test/%.cpp,obj-test/%.o,$(wildcard test/*.cpp)) + +obj-test/%.o: test/%.cpp + $(CXX) -c $(TESTDEFS) $(CFLAGS) -MMD -MF $(@:%.o=%.d) -o $@ $< + @cp $(@:%.o=%.d) $(@:%.o=%.P); \ + sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \ + -e '/^$$/ d' -e 's/$$/ :/' < $(@:%.o=%.d) >> $(@:%.o=%.P); \ + rm -f $(@:%.o=%.d) + +test_triangles: $(TESTOBJS) $(filter-out obj/init.o,$(OBJS:obj/%=obj/%)) + $(CXX) $(CFLAGS) -o $@ $(LIBPATHS) $^ $(LIBS) $(TESTLIBS) + +clean: + -rm -f trianglesd test_triangles + -rm -f obj/*.o + -rm -f obj-test/*.o + -rm -f obj/*.P + -rm -f obj-test/*.P + -rm -f obj/build.h + +FORCE: diff --git a/src/makefile.unix b/src/makefile.unix new file mode 100644 index 0000000..63abf39 --- /dev/null +++ b/src/makefile.unix @@ -0,0 +1,304 @@ +# Copyright (c) 2009-2010 Satoshi Nakamoto +# Distributed under the MIT/X11 software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +USE_UPNP:=1 +USE_IPV6:=1 + +LINK:=$(CXX) + +DEFS=-DBOOST_SPIRIT_THREADSAFE + +DEFS += $(addprefix -I,$(CURDIR) $(CURDIR)/tor $(CURDIR)/obj $(BOOST_INCLUDE_PATH) $(BDB_INCLUDE_PATH) $(OPENSSL_INCLUDE_PATH)) +LIBS = $(addprefix -L,$(BOOST_LIB_PATH) $(BDB_LIB_PATH) $(OPENSSL_LIB_PATH)) + +# libevent +EVENTDIR = /usr/local +DEFS += $(addprefix -I,$(EVENTDIR)/include) +LIBS += -levent $(addprefix -L,$(EVENTDIR)/lib) + +TESTDEFS = -DTEST_DATA_DIR=$(abspath test/data) + +LMODE = dynamic +LMODE2 = dynamic +ifdef STATIC + LMODE = static + ifeq (${STATIC}, all) + LMODE2 = static + endif +else + TESTDEFS += -DBOOST_TEST_DYN_LINK +endif + +# for boost 1.37, add -mt to the boost libraries +LIBS += \ + -Wl,-B$(LMODE) \ + -l boost_system$(BOOST_LIB_SUFFIX) \ + -l boost_filesystem$(BOOST_LIB_SUFFIX) \ + -l boost_program_options$(BOOST_LIB_SUFFIX) \ + -l boost_thread$(BOOST_LIB_SUFFIX) \ + -l db_cxx$(BDB_LIB_SUFFIX) \ + -l ssl \ + -l event \ + -l crypto + +ifndef USE_UPNP + override USE_UPNP = - +endif +ifneq (${USE_UPNP}, -) + LIBS += -l miniupnpc + DEFS += -DUSE_UPNP=$(USE_UPNP) +endif + +ifneq (${USE_IPV6}, -) + DEFS += -DUSE_IPV6=$(USE_IPV6) +endif + +LIBS+= \ + -Wl,-B$(LMODE2) \ + -l z \ + -l dl \ + -l pthread + + +# Hardening +# Make some classes of vulnerabilities unexploitable in case one is discovered. +# + # This is a workaround for Ubuntu bug #691722, the default -fstack-protector causes + # -fstack-protector-all to be ignored unless -fno-stack-protector is used first. + # see: https://bugs.launchpad.net/ubuntu/+source/gcc-4.5/+bug/691722 + HARDENING=-fno-stack-protector + + # Stack Canaries + # Put numbers at the beginning of each stack frame and check that they are the same. + # If a stack buffer if overflowed, it writes over the canary number and then on return + # when that number is checked, it won't be the same and the program will exit with + # a "Stack smashing detected" error instead of being exploited. + HARDENING+=-fstack-protector-all -Wstack-protector + + # Make some important things such as the global offset table read only as soon as + # the dynamic linker is finished building it. This will prevent overwriting of addresses + # which would later be jumped to. + LDHARDENING+=-Wl,-z,relro -Wl,-z,now + + # Build position independent code to take advantage of Address Space Layout Randomization + # offered by some kernels. + # see doc/build-unix.txt for more information. + ifdef PIE + HARDENING+=-fPIE + LDHARDENING+=-pie + endif + + # -D_FORTIFY_SOURCE=2 does some checking for potentially exploitable code patterns in + # the source such overflowing a statically defined buffer. + HARDENING+=-D_FORTIFY_SOURCE=2 +# + + +DEBUGFLAGS=-g + +# CXXFLAGS can be specified on the make command line, so we use xCXXFLAGS that only +# adds some defaults in front. Unfortunately, CXXFLAGS=... $(CXXFLAGS) does not work. +xCXXFLAGS=-O2 -msse2 -pthread -Wall -Wextra -Wformat -Wformat-security -Wno-unused-parameter \ + $(DEBUGFLAGS) $(DEFS) $(HARDENING) $(CXXFLAGS) + +# LDFLAGS can be specified on the make command line, so we use xLDFLAGS that only +# adds some defaults in front. Unfortunately, LDFLAGS=... $(LDFLAGS) does not work. +xLDFLAGS=$(LDHARDENING) $(LDFLAGS) + +OBJS= \ +obj/address.o \ + obj/addressmap.o \ + obj/aes.o \ + obj/backtrace.o \ + obj/buffers.o \ + obj/channel.o \ + obj/channeltls.o \ + obj/circpathbias.o \ + obj/circuitbuild.o \ + obj/circuitlist.o \ + obj/circuitmux.o \ + obj/circuitmux_ewma.o \ + obj/circuitstats.o \ + obj/circuituse.o \ + obj/command.o \ + obj/compat.o \ + obj/compat_libevent.o \ + obj/config.o \ + obj/config_codedigest.o \ + obj/confparse.o \ + obj/connection.o \ + obj/connection_edge.o \ + obj/connection_or.o \ + obj/container.o \ + obj/control.o \ + obj/cpuworker.o \ + obj/crypto.o \ + obj/crypto_curve25519.o \ + obj/crypto_format.o \ + obj/curve25519-donna.o \ + obj/di_ops.o \ + obj/directory.o \ + obj/dirserv.o \ + obj/dirvote.o \ + obj/dns.o \ + obj/dnsserv.o \ + obj/entrynodes.o \ + obj/ext_orport.o \ + obj/fp_pair.o \ + obj/geoip.o \ + obj/hibernate.o \ + obj/log.o \ + obj/memarea.o \ + obj/mempool.o \ + obj/microdesc.o \ + obj/networkstatus.o \ + obj/nodelist.o \ + obj/onion.o \ + obj/onion_fast.o \ + obj/onion_main.o \ + obj/onion_ntor.o \ + obj/onion_tap.o \ + obj/policies.o \ + obj/procmon.o \ + obj/reasons.o \ + obj/relay.o \ + obj/rendclient.o \ + obj/rendcommon.o \ + obj/rendmid.o \ + obj/rendservice.o \ + obj/rephist.o \ + obj/replaycache.o \ + obj/router.o \ + obj/routerlist.o \ + obj/routerparse.o \ + obj/routerset.o \ + obj/sandbox.o \ + obj/statefile.o \ + obj/status.o \ + obj/tor_util.o \ + obj/torgzip.o \ + obj/tortls.o \ + obj/transports.o \ + obj/util_codedigest.o \ + obj/fugue.o \ + obj/hamsi.o \ + obj/groestl.o \ + obj/blake.o \ + obj/bmw.o \ + obj/skein.o \ + obj/keccak.o \ + obj/shavite.o \ + obj/jh.o \ + obj/luffa.o \ + obj/cubehash.o \ + obj/echo.o \ + obj/simd.o \ + obj/alert.o \ + obj/version.o \ + obj/checkpoints.o \ + obj/netbase.o \ + obj/addrman.o \ + obj/crypter.o \ + obj/key.o \ + obj/db.o \ + obj/init.o \ + obj/irc.o \ + obj/keystore.o \ + obj/main.o \ + obj/net.o \ + obj/protocol.o \ + obj/bitcoinrpc.o \ + obj/rpcdump.o \ + obj/rpcnet.o \ + obj/rpcmining.o \ + obj/rpcwallet.o \ + obj/rpcblockchain.o \ + obj/rpcrawtransaction.o \ + obj/script.o \ + obj/sync.o \ + obj/util.o \ + obj/wallet.o \ + obj/walletdb.o \ + obj/noui.o \ + obj/kernel.o \ + obj/pbkdf2.o \ + obj/scrypt.o \ + obj/scrypt_mine.o \ + obj/scrypt-x86.o \ + obj/scrypt-x86_64.o + + +all: trianglesd + +test check: test_triangles FORCE + ./test_triangles + +# auto-generated dependencies: +-include obj/*.P +-include obj-test/*.P + +obj/build.h: FORCE + /bin/sh ../share/genbuild.sh obj/build.h +version.cpp: obj/build.h +DEFS += -DHAVE_BUILD_INFO + +obj/scrypt-x86.o: scrypt-x86.S + $(CXX) -c $(xCXXFLAGS) -MMD -o $@ $< + +obj/scrypt-x86_64.o: scrypt-x86_64.S + $(CXX) -c $(xCXXFLAGS) -MMD -o $@ $< + +obj/%.o: %.cpp + $(CXX) -c $(xCXXFLAGS) -MMD -MF $(@:%.o=%.d) -o $@ $< + @cp $(@:%.o=%.d) $(@:%.o=%.P); \ + sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \ + -e '/^$$/ d' -e 's/$$/ :/' < $(@:%.o=%.d) >> $(@:%.o=%.P); \ + rm -f $(@:%.o=%.d) + +obj/%.o: %.c + $(CXX) -c $(xCXXFLAGS) -fpermissive -MMD -MF $(@:%.o=%.d) -o $@ $< + @cp $(@:%.o=%.d) $(@:%.o=%.P); \ + sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \ + -e '/^$$/ d' -e 's/$$/ :/' < $(@:%.o=%.d) >> $(@:%.o=%.P); \ + rm -f $(@:%.o=%.d) + + +obj/%.o: tor/%.c + $(CC) -c $(xCXXFLAGS) -MMD -MF $(@:%.o=%.d) -o $@ $< + @cp $(@:%.o=%.d) $(@:%.o=%.P); \ + sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \ + -e '/^$$/ d' -e 's/$$/ :/' < $(@:%.o=%.d) >> $(@:%.o=%.P); \ + rm -f $(@:%.o=%.d) + +obj/anonymize.o: tor/anonymize.cpp + $(CXX) -c $(xCXXFLAGS) -MMD -MF $(@:%.o=%.d) -o $@ $< + @cp $(@:%.o=%.d) $(@:%.o=%.P); \ + sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \ + -e '/^$$/ d' -e 's/$$/ :/' < $(@:%.o=%.d) >> $(@:%.o=%.P); \ + rm -f $(@:%.o=%.d) + +trianglesd: $(OBJS:obj/%=obj/%) obj/anonymize.o + $(LINK) $(xCXXFLAGS) -o $@ $^ $(xLDFLAGS) $(LIBS) + +TESTOBJS := $(patsubst test/%.cpp,obj-test/%.o,$(wildcard test/*.cpp)) + +obj-test/%.o: test/%.cpp + $(CXX) -c $(TESTDEFS) $(xCXXFLAGS) -MMD -MF $(@:%.o=%.d) -o $@ $< + @cp $(@:%.o=%.d) $(@:%.o=%.P); \ + sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \ + -e '/^$$/ d' -e 's/$$/ :/' < $(@:%.o=%.d) >> $(@:%.o=%.P); \ + rm -f $(@:%.o=%.d) + +test_triangles: $(TESTOBJS) $(filter-out obj/init.o,$(OBJS:obj/%=obj/%)) + $(LINK) $(xCXXFLAGS) -o $@ $(LIBPATHS) $^ -Wl,-B$(LMODE) -lboost_unit_test_framework $(xLDFLAGS) $(LIBS) + +clean: + -rm -f trianglesd test_triangles + -rm -f obj/*.o + -rm -f obj-test/*.o + -rm -f obj/*.P + -rm -f obj-test/*.P + -rm -f obj/build.h + +FORCE: diff --git a/src/mruset.h b/src/mruset.h new file mode 100644 index 0000000..a527351 --- /dev/null +++ b/src/mruset.h @@ -0,0 +1,64 @@ +// Copyright (c) 2012 The Bitcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. +#ifndef BITCOIN_MRUSET_H +#define BITCOIN_MRUSET_H + +#include +#include + +/** STL-like set container that only keeps the most recent N elements. */ +template class mruset +{ +public: + typedef T key_type; + typedef T value_type; + typedef typename std::set::iterator iterator; + typedef typename std::set::const_iterator const_iterator; + typedef typename std::set::size_type size_type; + +protected: + std::set set; + std::deque queue; + size_type nMaxSize; + +public: + mruset(size_type nMaxSizeIn = 0) { nMaxSize = nMaxSizeIn; } + iterator begin() const { return set.begin(); } + iterator end() const { return set.end(); } + size_type size() const { return set.size(); } + bool empty() const { return set.empty(); } + iterator find(const key_type& k) const { return set.find(k); } + size_type count(const key_type& k) const { return set.count(k); } + bool inline friend operator==(const mruset& a, const mruset& b) { return a.set == b.set; } + bool inline friend operator==(const mruset& a, const std::set& b) { return a.set == b; } + bool inline friend operator<(const mruset& a, const mruset& b) { return a.set < b.set; } + std::pair insert(const key_type& x) + { + std::pair ret = set.insert(x); + if (ret.second) + { + if (nMaxSize && queue.size() == nMaxSize) + { + set.erase(queue.front()); + queue.pop_front(); + } + queue.push_back(x); + } + return ret; + } + size_type max_size() const { return nMaxSize; } + size_type max_size(size_type s) + { + if (s) + while (queue.size() > s) + { + set.erase(queue.front()); + queue.pop_front(); + } + nMaxSize = s; + return nMaxSize; + } +}; + +#endif diff --git a/src/net.cpp b/src/net.cpp new file mode 100644 index 0000000..440a57e --- /dev/null +++ b/src/net.cpp @@ -0,0 +1,1938 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2012 The Bitcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "irc.h" +#include "db.h" +#include "net.h" +#include "init.h" +#include "strlcpy.h" +#include "addrman.h" +#include "ui_interface.h" +#include "onionseed.h" + +#ifdef WIN32 +#include +#endif + +#ifdef USE_UPNP +#include +#include +#include +#include +#endif + +using namespace std; +using namespace boost; + +extern "C" { + int tor_main(int argc, char *argv[]); +} + +static const int MAX_OUTBOUND_CONNECTIONS = 12; + +void ThreadMessageHandler2(void* parg); +void ThreadSocketHandler2(void* parg); +void ThreadOpenConnections2(void* parg); +void ThreadOpenAddedConnections2(void* parg); +#ifdef USE_UPNP +void ThreadMapPort2(void* parg); +#endif +void ThreadDNSAddressSeed2(void* parg); +bool OpenNetworkConnection(const CAddress& addrConnect, CSemaphoreGrant *grantOutbound = NULL, const char *strDest = NULL, bool fOneShot = false); + + +struct LocalServiceInfo { + int nScore; + int nPort; +}; + +// +// Global state variables +// +bool fClient = false; + +// bool fUseUPnP = GetBoolArg("-upnp", USE_UPNP); +bool fUseUPnP = false; + +uint64 nLocalServices = (fClient ? 0 : NODE_NETWORK); +static CCriticalSection cs_mapLocalHost; +static map mapLocalHost; +static bool vfReachable[NET_MAX] = {}; +static bool vfLimited[NET_MAX] = {}; +static CNode* pnodeLocalHost = NULL; +CAddress addrSeenByPeer(CService("0.0.0.0", 0), nLocalServices); +uint64 nLocalHostNonce = 0; +boost::array vnThreadsRunning; +static std::vector vhListenSocket; +CAddrMan addrman; + +vector vNodes; +CCriticalSection cs_vNodes; +map mapRelay; +deque > vRelayExpiration; +CCriticalSection cs_mapRelay; +map mapAlreadyAskedFor; + +static deque vOneShots; +CCriticalSection cs_vOneShots; + +set setservAddNodeAddresses; +CCriticalSection cs_setservAddNodeAddresses; + +static CSemaphore *semOutbound = NULL; + +void AddOneShot(string strDest) +{ + LOCK(cs_vOneShots); + vOneShots.push_back(strDest); +} + +unsigned short GetListenPort() +{ + return (unsigned short)(GetArg("-port", GetDefaultPort())); +} + +void CNode::PushGetBlocks(CBlockIndex* pindexBegin, uint256 hashEnd) +{ + // Filter out duplicate requests + if (pindexBegin == pindexLastGetBlocksBegin && hashEnd == hashLastGetBlocksEnd) + return; + pindexLastGetBlocksBegin = pindexBegin; + hashLastGetBlocksEnd = hashEnd; + + PushMessage("getblocks", CBlockLocator(pindexBegin), hashEnd); +} + +// find 'best' local address for a particular peer +bool GetLocal(CService& addr, const CNetAddr *paddrPeer) +{ + int nBestScore = -1; + int nBestReachability = -1; + { + LOCK(cs_mapLocalHost); + for (map::iterator it = mapLocalHost.begin(); it != mapLocalHost.end(); it++) + { + int nScore = (*it).second.nScore; + int nReachability = (*it).first.GetReachabilityFrom(paddrPeer); + if (nReachability > nBestReachability || (nReachability == nBestReachability && nScore > nBestScore)) + { + addr = CService((*it).first, (*it).second.nPort); + nBestReachability = nReachability; + nBestScore = nScore; + } + } + } + return nBestScore >= 0; +} + +// get best local address for a particular peer as a CAddress +CAddress GetLocalAddress(const CNetAddr *paddrPeer) +{ + CAddress ret(CService("0.0.0.0",0),0); + CService addr; + if (GetLocal(addr, paddrPeer)) + { + ret = CAddress(addr); + ret.nServices = nLocalServices; + ret.nTime = GetAdjustedTime(); + } + return ret; +} + +bool RecvLine(SOCKET hSocket, string& strLine) +{ + strLine = ""; + loop + { + char c; + int nBytes = recv(hSocket, &c, 1, 0); + if (nBytes > 0) + { + if (c == '\n') + continue; + if (c == '\r') + return true; + strLine += c; + if (strLine.size() >= 9000) + return true; + } + else if (nBytes <= 0) + { + if (fShutdown) + return false; + if (nBytes < 0) + { + int nErr = WSAGetLastError(); + if (nErr == WSAEMSGSIZE) + continue; + if (nErr == WSAEWOULDBLOCK || nErr == WSAEINTR || nErr == WSAEINPROGRESS) + { + Sleep(10); + continue; + } + } + if (!strLine.empty()) + return true; + if (nBytes == 0) + { + // socket closed + printf("socket closed\n"); + return false; + } + else + { + // socket error + int nErr = WSAGetLastError(); + printf("recv failed: %d\n", nErr); + return false; + } + } + } +} + +// used when scores of local addresses may have changed +// pushes better local address to peers +void static AdvertizeLocal() +{ + LOCK(cs_vNodes); + BOOST_FOREACH(CNode* pnode, vNodes) + { + if (pnode->fSuccessfullyConnected) + { + CAddress addrLocal = GetLocalAddress(&pnode->addr); + if (addrLocal.IsRoutable() && (CService)addrLocal != (CService)pnode->addrLocal) + { + pnode->PushAddress(addrLocal); + pnode->addrLocal = addrLocal; + } + } + } +} + +void SetReachable(enum Network net, bool fFlag) +{ + LOCK(cs_mapLocalHost); + vfReachable[net] = fFlag; + if (net == NET_IPV6 && fFlag) + vfReachable[NET_IPV4] = true; +} + +// learn a new local address +bool AddLocal(const CService& addr, int nScore) +{ + if (!addr.IsRoutable()) + return false; + + if (nScore < LOCAL_MANUAL) + return false; + + if (IsLimited(addr)) + return false; + + printf("AddLocal(%s,%i)\n", addr.ToString().c_str(), nScore); + + { + LOCK(cs_mapLocalHost); + bool fAlready = mapLocalHost.count(addr) > 0; + LocalServiceInfo &info = mapLocalHost[addr]; + if (!fAlready || nScore >= info.nScore) { + info.nScore = nScore + (fAlready ? 1 : 0); + info.nPort = addr.GetPort(); + } + SetReachable(addr.GetNetwork()); + } + + AdvertizeLocal(); + + return true; +} + +bool AddLocal(const CNetAddr &addr, int nScore) +{ + return AddLocal(CService(addr, GetListenPort()), nScore); +} + +/** Make a particular network entirely off-limits (no automatic connects to it) */ +void SetLimited(enum Network net, bool fLimited) +{ + if (net == NET_UNROUTABLE) + return; + LOCK(cs_mapLocalHost); + vfLimited[net] = fLimited; +} + +bool IsLimited(enum Network net) +{ + LOCK(cs_mapLocalHost); + return vfLimited[net]; +} + +bool IsLimited(const CNetAddr &addr) +{ + return IsLimited(addr.GetNetwork()); +} + +/** vote for a local address */ +bool SeenLocal(const CService& addr) +{ + { + LOCK(cs_mapLocalHost); + if (mapLocalHost.count(addr) == 0) + return false; + mapLocalHost[addr].nScore++; + } + + AdvertizeLocal(); + + return true; +} + +/** check whether a given address is potentially local */ +bool IsLocal(const CService& addr) +{ + LOCK(cs_mapLocalHost); + return mapLocalHost.count(addr) > 0; +} + +/** check whether a given address is in a network we can probably connect to */ +bool IsReachable(const CNetAddr& addr) +{ + LOCK(cs_mapLocalHost); + enum Network net = addr.GetNetwork(); + return vfReachable[net] && !vfLimited[net]; +} + +bool GetMyExternalIP2(const CService& addrConnect, const char* pszGet, const char* pszKeyword, CNetAddr& ipRet) +{ + SOCKET hSocket; + if (!ConnectSocket(addrConnect, hSocket)) + return error("GetMyExternalIP() : connection to %s failed", addrConnect.ToString().c_str()); + + send(hSocket, pszGet, strlen(pszGet), MSG_NOSIGNAL); + + string strLine; + while (RecvLine(hSocket, strLine)) + { + if (strLine.empty()) // HTTP response is separated from headers by blank line + { + loop + { + if (!RecvLine(hSocket, strLine)) + { + closesocket(hSocket); + return false; + } + if (pszKeyword == NULL) + break; + if (strLine.find(pszKeyword) != string::npos) + { + strLine = strLine.substr(strLine.find(pszKeyword) + strlen(pszKeyword)); + break; + } + } + closesocket(hSocket); + if (strLine.find("<") != string::npos) + strLine = strLine.substr(0, strLine.find("<")); + strLine = strLine.substr(strspn(strLine.c_str(), " \t\n\r")); + while (strLine.size() > 0 && isspace(strLine[strLine.size()-1])) + strLine.resize(strLine.size()-1); + CService addr(strLine,0,true); + printf("GetMyExternalIP() received [%s] %s\n", strLine.c_str(), addr.ToString().c_str()); + if (!addr.IsValid() || !addr.IsRoutable()) + return false; + ipRet.SetIP(addr); + return true; + } + } + closesocket(hSocket); + return error("GetMyExternalIP() : connection closed"); +} + +// We now get our external IP from the IRC server first and only use this as a backup +bool GetMyExternalIP(CNetAddr& ipRet) +{ + CService addrConnect; + const char* pszGet; + const char* pszKeyword; + + for (int nLookup = 0; nLookup <= 1; nLookup++) + for (int nHost = 1; nHost <= 2; nHost++) + { + // We should be phasing out our use of sites like these. If we need + // replacements, we should ask for volunteers to put this simple + // php file on their web server that prints the client IP: + // + if (nHost == 1) + { + addrConnect = CService("91.198.22.70",80); // checkip.dyndns.org + + if (nLookup == 1) + { + CService addrIP("checkip.dyndns.org", 80, true); + if (addrIP.IsValid()) + addrConnect = addrIP; + } + + pszGet = "GET / HTTP/1.1\r\n" + "Host: checkip.dyndns.org\r\n" + "User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)\r\n" + "Connection: close\r\n" + "\r\n"; + + pszKeyword = "Address:"; + } + else if (nHost == 2) + { + addrConnect = CService("74.208.43.192", 80); // www.showmyip.com + + if (nLookup == 1) + { + CService addrIP("www.showmyip.com", 80, true); + if (addrIP.IsValid()) + addrConnect = addrIP; + } + + pszGet = "GET /simple/ HTTP/1.1\r\n" + "Host: www.showmyip.com\r\n" + "User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)\r\n" + "Connection: close\r\n" + "\r\n"; + + pszKeyword = NULL; // Returns just IP address + } + + if (GetMyExternalIP2(addrConnect, pszGet, pszKeyword, ipRet)) + return true; + } + + return false; +} + +void ThreadGetMyExternalIP(void* parg) +{ + // Make this thread recognisable as the external IP detection thread + RenameThread("bitcoin-ext-ip"); + + CNetAddr addrLocalHost; + if (GetMyExternalIP(addrLocalHost)) + { + printf("GetMyExternalIP() returned %s\n", addrLocalHost.ToStringIP().c_str()); + AddLocal(addrLocalHost, LOCAL_HTTP); + } +} + +void AddressCurrentlyConnected(const CService& addr) +{ + addrman.Connected(addr); +} + +CNode* FindNode(const CNetAddr& ip) +{ + { + LOCK(cs_vNodes); + BOOST_FOREACH(CNode* pnode, vNodes) + if ((CNetAddr)pnode->addr == ip) + return (pnode); + } + return NULL; +} + +CNode* FindNode(std::string addrName) +{ + LOCK(cs_vNodes); + BOOST_FOREACH(CNode* pnode, vNodes) + if (pnode->addrName == addrName) + return (pnode); + return NULL; +} + +CNode* FindNode(const CService& addr) +{ + { + LOCK(cs_vNodes); + BOOST_FOREACH(CNode* pnode, vNodes) + if ((CService)pnode->addr == addr) + return (pnode); + } + return NULL; +} + +CNode* ConnectNode(CAddress addrConnect, const char *pszDest, int64 nTimeout) +{ + + if (pszDest == NULL) { + if (IsLocal(addrConnect)) + return NULL; + + // Look for an existing connection + CNode* pnode = FindNode((CService)addrConnect); + if (pnode) + { + if (nTimeout != 0) + pnode->AddRef(nTimeout); + else + pnode->AddRef(); + return pnode; + } + } + + if (fDebug) { + printf("ConnectNode(): pszDest: %s\n", pszDest); + } + + + /// debug print + printf("trying connection %s lastseen=%.1fhrs\n", + pszDest ? pszDest : addrConnect.ToString().c_str(), + pszDest ? 0 : (double)(GetAdjustedTime() - addrConnect.nTime)/3600.0); + + // Connect + SOCKET hSocket; + if (pszDest ? + ConnectSocketByName(addrConnect, hSocket, + pszDest, GetDefaultPort()) : + ConnectSocket(addrConnect, hSocket)) + { + addrman.Attempt(addrConnect); + + /// debug print + printf("connected %s\n", pszDest ? pszDest : addrConnect.ToString().c_str()); + + // Set to non-blocking +#ifdef WIN32 + u_long nOne = 1; + if (ioctlsocket(hSocket, FIONBIO, &nOne) == SOCKET_ERROR) + printf("ConnectSocket() : ioctlsocket non-blocking setting failed, error %d\n", WSAGetLastError()); +#else + if (fcntl(hSocket, F_SETFL, O_NONBLOCK) == SOCKET_ERROR) + printf("ConnectSocket() : fcntl non-blocking setting failed, error %d\n", errno); +#endif + + // Add node + CNode* pnode = new CNode(hSocket, addrConnect, pszDest ? pszDest : "", false); + if (nTimeout != 0) + pnode->AddRef(nTimeout); + else + pnode->AddRef(); + + { + LOCK(cs_vNodes); + vNodes.push_back(pnode); + } + + pnode->nTimeConnected = GetTime(); + return pnode; + } + else + { + return NULL; + } +} + +void CNode::CloseSocketDisconnect() +{ + fDisconnect = true; + if (hSocket != INVALID_SOCKET) + { + printf("disconnecting node %s\n", addrName.c_str()); + closesocket(hSocket); + hSocket = INVALID_SOCKET; + vRecv.clear(); + } +} + +void CNode::Cleanup() +{ +} + + +void CNode::PushVersion() +{ + /// when NTP implemented, change to just nTime = GetAdjustedTime() + int64 nTime = (fInbound ? GetAdjustedTime() : GetTime()); + uint64 verification_token = 0; + if ( + !fInbound + ) { + if (!addrman.GetReconnectToken(addr, verification_token)) { + RAND_bytes((unsigned char*)&verification_token, sizeof(verification_token)); + addrman.SetVerificationToken( + addr, + verification_token + ); + } + } + + if (fDebug) { + if (addr.IsRoutable()) { + printf("PushVersion(): Address is routable (good)\n"); + } else { + printf("PushVersion(): Address not routable (bad)\n"); + } + + if (IsProxy(addr)) { + printf("PushVersion(): Address is proxy (bad)\n"); + } else { + printf("PushVersion(): Address not proxy (good)\n"); + } + } + + CAddress addrYou = (addr.IsRoutable() && !IsProxy(addr) ? addr : CAddress(CService("0.0.0.0",0))); + CAddress addrMe = GetLocalAddress(&addr); + RAND_bytes((unsigned char*)&nLocalHostNonce, sizeof(nLocalHostNonce)); + printf("send version message: version %d, blocks=%d, us=%s, them=%s, peer=%s, verification=%" PRI64d "\n", PROTOCOL_VERSION, nBestHeight, addrMe.ToString().c_str(), addrYou.ToString().c_str(), addr.ToString().c_str(), verification_token); + PushMessage("version", PROTOCOL_VERSION, nLocalServices, nTime, addrYou, addrMe, + verification_token, nLocalHostNonce, FormatSubVersion(CLIENT_NAME, CLIENT_VERSION, std::vector()), nBestHeight); +} + + + + + +std::map CNode::setBanned; +CCriticalSection CNode::cs_setBanned; + +void CNode::ClearBanned() +{ + setBanned.clear(); +} + +bool CNode::IsBanned(CNetAddr ip) +{ + bool fResult = false; + { + LOCK(cs_setBanned); + std::map::iterator i = setBanned.find(ip); + if (i != setBanned.end()) + { + int64 t = (*i).second; + if (GetTime() < t) + fResult = true; + } + } + return fResult; +} + +extern CMedianFilter cPeerBlockCounts; + +bool CNode::Misbehaving(int howmuch) +{ + if (addr.IsLocal()) + { + printf("Warning: Local node %s misbehaving (delta: %d)!\n", addrName.c_str(), howmuch); + return false; + } + + nMisbehavior += howmuch; + if (nMisbehavior >= GetArg("-banscore", 100)) + { + int64 banTime = GetTime()+GetArg("-bantime", 60*60*24); // Default 24-hour ban + printf("Misbehaving: %s (%d -> %d) DISCONNECTING\n", addr.ToString().c_str(), nMisbehavior-howmuch, nMisbehavior); + { + LOCK(cs_setBanned); + if (setBanned[addr] < banTime) + setBanned[addr] = banTime; + } + CloseSocketDisconnect(); + + cPeerBlockCounts.removeLast(nStartingHeight); // remove this node's reported number of blocks + + return true; + } else + printf("Misbehaving: %s (%d -> %d)\n", addr.ToString().c_str(), nMisbehavior-howmuch, nMisbehavior); + return false; +} + +#undef X +#define X(name) stats.name = name +void CNode::copyStats(CNodeStats &stats) +{ + X(nServices); + X(nLastSend); + X(nLastRecv); + X(nTimeConnected); + X(addrName); + X(nVersion); + X(cleanSubVer); + X(fInbound); + X(nReleaseTime); + X(nStartingHeight); + X(nMisbehavior); +} +#undef X + + + +void ThreadSocketHandler(void* parg) +{ + // Make this thread recognisable as the networking thread + RenameThread("bitcoin-net"); + + try + { + vnThreadsRunning[THREAD_SOCKETHANDLER]++; + ThreadSocketHandler2(parg); + vnThreadsRunning[THREAD_SOCKETHANDLER]--; + } + catch (std::exception& e) { + vnThreadsRunning[THREAD_SOCKETHANDLER]--; + PrintException(&e, "ThreadSocketHandler()"); + } catch (...) { + vnThreadsRunning[THREAD_SOCKETHANDLER]--; + throw; // support pthread_cancel() + } + printf("ThreadSocketHandler exited\n"); +} + +void ThreadSocketHandler2(void* parg) +{ + printf("ThreadSocketHandler started\n"); + list vNodesDisconnected; + unsigned int nPrevNodeCount = 0; + + loop + { + // + // Disconnect nodes + // + { + LOCK(cs_vNodes); + // Disconnect unused nodes + vector const vNodesCopy = vNodes; + BOOST_FOREACH(CNode* pnode, vNodesCopy) + { + if (pnode->fDisconnect || + (pnode->GetRefCount() <= 0 && pnode->vRecv.empty() && pnode->vSend.empty())) + { + // remove from vNodes + vNodes.erase(remove(vNodes.begin(), vNodes.end(), pnode), vNodes.end()); + + // release outbound grant (if any) + pnode->grantOutbound.Release(); + + // close socket and cleanup + pnode->CloseSocketDisconnect(); + pnode->Cleanup(); + + // hold in disconnected pool until all refs are released + pnode->nReleaseTime = max(pnode->nReleaseTime, GetTime() + 15 * 60); + if (pnode->fNetworkNode || pnode->fInbound) + pnode->Release(); + vNodesDisconnected.push_back(pnode); + } + } + + // Delete disconnected nodes + list vNodesDisconnectedCopy = vNodesDisconnected; + BOOST_FOREACH(CNode* pnode, vNodesDisconnectedCopy) + { + // wait until threads are done using it + if (pnode->GetRefCount() <= 0) + { + bool fDelete = false; + { + TRY_LOCK(pnode->cs_vSend, lockSend); + if (lockSend) + { + TRY_LOCK(pnode->cs_vRecv, lockRecv); + if (lockRecv) + { + TRY_LOCK(pnode->cs_mapRequests, lockReq); + if (lockReq) + { + TRY_LOCK(pnode->cs_inventory, lockInv); + if (lockInv) + fDelete = true; + } + } + } + } + if (fDelete) + { + vNodesDisconnected.remove(pnode); + delete pnode; + } + } + } + // count secured connections + int unsecured = 0; + int secured = 0; + vector vNodesUnsecure; + BOOST_FOREACH(CNode* pnode, vNodesCopy) + { + if (GetTime() - pnode->nTimeConnected < 60) { + continue; + } + if ( + !pnode->fInbound || pnode->fVerified + ) { + secured++; + } else { + unsecured++; + vNodesUnsecure.push_back(pnode); + } + } + if ( + 0 > 2 * secured - 3 * unsecured + ) { + random_shuffle(vNodesUnsecure.begin(), vNodesUnsecure.end(), GetRandInt); + printf("removing unsecured connection %s\n", (*vNodesUnsecure.begin())->addr.ToString().c_str()); + (*vNodesUnsecure.begin())->fDisconnect = true; + } + } + if (vNodes.size() != nPrevNodeCount) + { + nPrevNodeCount = vNodes.size(); + uiInterface.NotifyNumConnectionsChanged(vNodes.size()); + } + + + // + // Find which sockets have data to receive + // + struct timeval timeout; + timeout.tv_sec = 0; + timeout.tv_usec = 50000; // frequency to poll pnode->vSend + + fd_set fdsetRecv; + fd_set fdsetSend; + fd_set fdsetError; + FD_ZERO(&fdsetRecv); + FD_ZERO(&fdsetSend); + FD_ZERO(&fdsetError); + SOCKET hSocketMax = 0; + bool have_fds = false; + + BOOST_FOREACH(SOCKET hListenSocket, vhListenSocket) { + FD_SET(hListenSocket, &fdsetRecv); + hSocketMax = max(hSocketMax, hListenSocket); + have_fds = true; + } + { + LOCK(cs_vNodes); + BOOST_FOREACH(CNode* pnode, vNodes) + { + if (pnode->hSocket == INVALID_SOCKET) + continue; + FD_SET(pnode->hSocket, &fdsetRecv); + FD_SET(pnode->hSocket, &fdsetError); + hSocketMax = max(hSocketMax, pnode->hSocket); + have_fds = true; + { + TRY_LOCK(pnode->cs_vSend, lockSend); + if (lockSend && !pnode->vSend.empty()) + FD_SET(pnode->hSocket, &fdsetSend); + } + } + } + + vnThreadsRunning[THREAD_SOCKETHANDLER]--; + int nSelect = select(have_fds ? hSocketMax + 1 : 0, + &fdsetRecv, &fdsetSend, &fdsetError, &timeout); + vnThreadsRunning[THREAD_SOCKETHANDLER]++; + if (fShutdown) + return; + if (nSelect == SOCKET_ERROR) + { + if (have_fds) + { + int nErr = WSAGetLastError(); + printf("socket select error %d\n", nErr); + for (unsigned int i = 0; i <= hSocketMax; i++) + FD_SET(i, &fdsetRecv); + } + FD_ZERO(&fdsetSend); + FD_ZERO(&fdsetError); + Sleep(timeout.tv_usec/1000); + } + + + // + // Accept new connections + // + BOOST_FOREACH(SOCKET hListenSocket, vhListenSocket) + if (hListenSocket != INVALID_SOCKET && FD_ISSET(hListenSocket, &fdsetRecv)) + { +#ifdef USE_IPV6 + struct sockaddr_storage sockaddr; +#else + struct sockaddr sockaddr; +#endif + socklen_t len = sizeof(sockaddr); + SOCKET hSocket = accept(hListenSocket, (struct sockaddr*)&sockaddr, &len); + CAddress addr; + int nInbound = 0; + + if (hSocket != INVALID_SOCKET) + if (!addr.SetSockAddr((const struct sockaddr*)&sockaddr)) + printf("Warning: Unknown socket family\n"); + + { + LOCK(cs_vNodes); + BOOST_FOREACH(CNode* pnode, vNodes) + if (pnode->fInbound) + nInbound++; + } + + if (hSocket == INVALID_SOCKET) + { + int nErr = WSAGetLastError(); + if (nErr != WSAEWOULDBLOCK) + printf("socket error accept failed: %d\n", nErr); + } + else if (nInbound >= GetArg("-maxconnections", 125) - MAX_OUTBOUND_CONNECTIONS) + { + { + LOCK(cs_setservAddNodeAddresses); + if (!setservAddNodeAddresses.count(addr)) + closesocket(hSocket); + } + } + else + { + printf("accepted connection %s\n", addr.ToString().c_str()); + CNode* pnode = new CNode(hSocket, addr, "", true); + pnode->AddRef(); + { + LOCK(cs_vNodes); + vNodes.push_back(pnode); + } + } + } + + + // + // Service each socket + // + vector vNodesCopy; + { + LOCK(cs_vNodes); + vNodesCopy = vNodes; + BOOST_FOREACH(CNode* pnode, vNodesCopy) + pnode->AddRef(); + } + BOOST_FOREACH(CNode* pnode, vNodesCopy) + { + if (fShutdown) + return; + + // + // Receive + // + if (pnode->hSocket == INVALID_SOCKET) + continue; + if (FD_ISSET(pnode->hSocket, &fdsetRecv) || FD_ISSET(pnode->hSocket, &fdsetError)) + { + TRY_LOCK(pnode->cs_vRecv, lockRecv); + if (lockRecv) + { + CDataStream& vRecv = pnode->vRecv; + unsigned int nPos = vRecv.size(); + + if (nPos > ReceiveBufferSize()) { + if (!pnode->fDisconnect) + printf("socket recv flood control disconnect (%"PRIszu" bytes)\n", vRecv.size()); + pnode->CloseSocketDisconnect(); + } + else { + // typical socket buffer is 8K-64K + char pchBuf[0x10000]; + int nBytes = recv(pnode->hSocket, pchBuf, sizeof(pchBuf), MSG_DONTWAIT); + if (nBytes > 0) + { + vRecv.resize(nPos + nBytes); + memcpy(&vRecv[nPos], pchBuf, nBytes); + pnode->nLastRecv = GetTime(); + } + else if (nBytes == 0) + { + // socket closed gracefully + if (!pnode->fDisconnect) + printf("socket closed\n"); + pnode->CloseSocketDisconnect(); + } + else if (nBytes < 0) + { + // error + int nErr = WSAGetLastError(); + if (nErr != WSAEWOULDBLOCK && nErr != WSAEMSGSIZE && nErr != WSAEINTR && nErr != WSAEINPROGRESS) + { + if (!pnode->fDisconnect) + printf("socket recv error %d\n", nErr); + pnode->CloseSocketDisconnect(); + } + } + } + } + } + + // + // Send + // + if (pnode->hSocket == INVALID_SOCKET) + continue; + if (FD_ISSET(pnode->hSocket, &fdsetSend)) + { + TRY_LOCK(pnode->cs_vSend, lockSend); + if (lockSend) + { + CDataStream& vSend = pnode->vSend; + if (!vSend.empty()) + { + int nBytes = send(pnode->hSocket, &vSend[0], vSend.size(), MSG_NOSIGNAL | MSG_DONTWAIT); + if (nBytes > 0) + { + vSend.erase(vSend.begin(), vSend.begin() + nBytes); + pnode->nLastSend = GetTime(); + } + else if (nBytes < 0) + { + // error + int nErr = WSAGetLastError(); + if (nErr != WSAEWOULDBLOCK && nErr != WSAEMSGSIZE && nErr != WSAEINTR && nErr != WSAEINPROGRESS) + { + printf("socket send error %d\n", nErr); + pnode->CloseSocketDisconnect(); + } + } + } + } + } + + // + // Inactivity checking + // + if (pnode->vSend.empty()) + pnode->nLastSendEmpty = GetTime(); + if (GetTime() - pnode->nTimeConnected > 60) + { + if (pnode->nLastRecv == 0 || pnode->nLastSend == 0) + { + printf("socket no message in first 60 seconds, %d %d\n", pnode->nLastRecv != 0, pnode->nLastSend != 0); + pnode->fDisconnect = true; + } + else if (GetTime() - pnode->nLastSend > 90*60 && GetTime() - pnode->nLastSendEmpty > 90*60) + { + printf("socket not sending\n"); + pnode->fDisconnect = true; + } + else if (GetTime() - pnode->nLastRecv > 90*60) + { + printf("socket inactivity timeout\n"); + pnode->fDisconnect = true; + } + } + } + { + LOCK(cs_vNodes); + BOOST_FOREACH(CNode* pnode, vNodesCopy) + pnode->Release(); + } + + Sleep(10); + } +} + + + + + + + + + +#ifdef USE_UPNP +void ThreadMapPort(void* parg) +{ + // Make this thread recognisable as the UPnP thread + RenameThread("bitcoin-UPnP"); + + printf("ThreadMapPort started\n"); + + try + { + vnThreadsRunning[THREAD_UPNP]++; + ThreadMapPort2(parg); + vnThreadsRunning[THREAD_UPNP]--; + } + catch (std::exception& e) { + vnThreadsRunning[THREAD_UPNP]--; + PrintException(&e, "ThreadMapPort()"); + } catch (...) { + vnThreadsRunning[THREAD_UPNP]--; + PrintException(NULL, "ThreadMapPort()"); + } + printf("ThreadMapPort exited\n"); +} + +void ThreadMapPort2(void* parg) +{ + printf("ThreadMapPort2 started\n"); + + std::string port = strprintf("%u", GetListenPort()); + const char * multicastif = 0; + const char * minissdpdpath = 0; + struct UPNPDev * devlist = 0; + char lanaddr[64]; + +#ifndef UPNPDISCOVER_SUCCESS + /* miniupnpc 1.5 */ + devlist = upnpDiscover(2000, multicastif, minissdpdpath, 0); +#else + /* miniupnpc 1.6 */ + int error = 0; + devlist = upnpDiscover(2000, multicastif, minissdpdpath, 0, 0, &error); +#endif + + struct UPNPUrls urls; + struct IGDdatas data; + int r; + + r = UPNP_GetValidIGD(devlist, &urls, &data, lanaddr, sizeof(lanaddr)); + if (r == 1) + { + + string strDesc = "triangles " + FormatFullVersion(); +#ifndef UPNPDISCOVER_SUCCESS + /* miniupnpc 1.5 */ + r = UPNP_AddPortMapping(urls.controlURL, data.first.servicetype, + port.c_str(), port.c_str(), lanaddr, strDesc.c_str(), "TCP", 0); +#else + /* miniupnpc 1.6 */ + r = UPNP_AddPortMapping(urls.controlURL, data.first.servicetype, + port.c_str(), port.c_str(), lanaddr, strDesc.c_str(), "TCP", 0, "0"); +#endif + + if(r!=UPNPCOMMAND_SUCCESS) + printf("AddPortMapping(%s, %s, %s) failed with code %d (%s)\n", + port.c_str(), port.c_str(), lanaddr, r, strupnperror(r)); + else + printf("UPnP Port Mapping successful.\n"); + int i = 1; + loop { + if (fShutdown || !fUseUPnP) + { + r = UPNP_DeletePortMapping(urls.controlURL, data.first.servicetype, port.c_str(), "TCP", 0); + printf("UPNP_DeletePortMapping() returned : %d\n", r); + freeUPNPDevlist(devlist); devlist = 0; + FreeUPNPUrls(&urls); + return; + } + if (i % 600 == 0) // Refresh every 20 minutes + { +#ifndef UPNPDISCOVER_SUCCESS + /* miniupnpc 1.5 */ + r = UPNP_AddPortMapping(urls.controlURL, data.first.servicetype, + port.c_str(), port.c_str(), lanaddr, strDesc.c_str(), "TCP", 0); +#else + /* miniupnpc 1.6 */ + r = UPNP_AddPortMapping(urls.controlURL, data.first.servicetype, + port.c_str(), port.c_str(), lanaddr, strDesc.c_str(), "TCP", 0, "0"); +#endif + + if(r!=UPNPCOMMAND_SUCCESS) + printf("AddPortMapping(%s, %s, %s) failed with code %d (%s)\n", + port.c_str(), port.c_str(), lanaddr, r, strupnperror(r)); + else + printf("UPnP Port Mapping successful.\n");; + } + Sleep(2000); + i++; + } + } else { + printf("No valid UPnP IGDs found\n"); + freeUPNPDevlist(devlist); devlist = 0; + if (r != 0) + FreeUPNPUrls(&urls); + loop { + if (fShutdown || !fUseUPnP) + return; + Sleep(2000); + } + } + printf("ThreadMapPort2 exited\n"); +} + +void MapPort(bool fUseUPnP) +{ + printf("MapPort()...\n"); + if (fUseUPnP && vnThreadsRunning[THREAD_UPNP] < 1) + { + if (!NewThread(ThreadMapPort, NULL)) + printf("Error: ThreadMapPort(ThreadMapPort) failed\n"); + } +} +#else +void MapPort() +{ + // Intentionally left blank. +} +#endif + + +void ThreadOnionSeed(void* parg) +{ + + // Make this thread recognisable as the tor thread + RenameThread("onionseed"); + + static const char *(*strOnionSeed)[1] = fTestNet ? strTestNetOnionSeed : strMainNetOnionSeed; + + int found = 0; + + printf("Loading addresses from .onion seeds\n"); + + for (unsigned int seed_idx = 0; strOnionSeed[seed_idx][0] != NULL; seed_idx++) { + CNetAddr parsed; + if ( + !parsed.SetSpecial( + strOnionSeed[seed_idx][0] + ) + ) { + throw runtime_error("ThreadOnionSeed() : invalid .onion seed"); + } + int nOneDay = 24*3600; + CAddress addr = CAddress(CService(parsed, GetDefaultPort())); + addr.nTime = GetTime() - 3*nOneDay - GetRand(4*nOneDay); // use a random age between 3 and 7 days old + found++; + addrman.Add(addr, parsed); + } + + printf("%d addresses found from .onion seeds\n", found); +} + + + +unsigned int pnSeed[] = +{ +}; + +void DumpAddresses() +{ + int64 nStart = GetTimeMillis(); + + CAddrDB adb; + adb.Write(addrman); + + printf("Flushed %d addresses to peers.dat %"PRI64d"ms\n", + addrman.size(), GetTimeMillis() - nStart); +} + +void ThreadDumpAddress2(void* parg) +{ + vnThreadsRunning[THREAD_DUMPADDRESS]++; + while (!fShutdown) + { + DumpAddresses(); + vnThreadsRunning[THREAD_DUMPADDRESS]--; + Sleep(100000); + vnThreadsRunning[THREAD_DUMPADDRESS]++; + } + vnThreadsRunning[THREAD_DUMPADDRESS]--; +} + +void ThreadDumpAddress(void* parg) +{ + // Make this thread recognisable as the address dumping thread + RenameThread("bitcoin-adrdump"); + + try + { + ThreadDumpAddress2(parg); + } + catch (std::exception& e) { + PrintException(&e, "ThreadDumpAddress()"); + } + printf("ThreadDumpAddress exited\n"); +} + +void ThreadOpenConnections(void* parg) +{ + // Make this thread recognisable as the connection opening thread + RenameThread("bitcoin-opencon"); + + try + { + vnThreadsRunning[THREAD_OPENCONNECTIONS]++; + ThreadOpenConnections2(parg); + vnThreadsRunning[THREAD_OPENCONNECTIONS]--; + } + catch (std::exception& e) { + vnThreadsRunning[THREAD_OPENCONNECTIONS]--; + PrintException(&e, "ThreadOpenConnections()"); + } catch (...) { + vnThreadsRunning[THREAD_OPENCONNECTIONS]--; + PrintException(NULL, "ThreadOpenConnections()"); + } + printf("ThreadOpenConnections exited\n"); +} + +void static ProcessOneShot() +{ + string strDest; + { + LOCK(cs_vOneShots); + if (vOneShots.empty()) + return; + strDest = vOneShots.front(); + vOneShots.pop_front(); + } + CAddress addr; + CSemaphoreGrant grant(*semOutbound, true); + if (grant) { + if (!OpenNetworkConnection(addr, &grant, strDest.c_str(), true)) + AddOneShot(strDest); + } +} + +// triangles: stake minter thread +void static ThreadStakeMinter(void* parg) +{ + printf("ThreadStakeMinter started\n"); + CWallet* pwallet = (CWallet*)parg; + try + { + vnThreadsRunning[THREAD_STAKER]++; + BitcoinMiner(pwallet, true); + vnThreadsRunning[THREAD_STAKER]--; + } + catch (std::exception& e) { + vnThreadsRunning[THREAD_STAKER]--; + PrintException(&e, "ThreadStakeMinter()"); + } catch (...) { + vnThreadsRunning[THREAD_STAKER]--; + PrintException(NULL, "ThreadStakeMinter()"); + } + printf("ThreadStakeMinter exiting, %d threads remaining\n", vnThreadsRunning[THREAD_STAKER]); +} + +void ThreadOpenConnections2(void* parg) +{ + printf("ThreadOpenConnections started\n"); + + // Connect to specific addresses + if (mapArgs.count("-connect") && mapMultiArgs["-connect"].size() > 0) + { + for (int64 nLoop = 0;; nLoop++) + { + ProcessOneShot(); + BOOST_FOREACH(string strAddr, mapMultiArgs["-connect"]) + { + CAddress addr; + OpenNetworkConnection(addr, NULL, strAddr.c_str()); + for (int i = 0; i < 10 && i < nLoop; i++) + { + Sleep(500); + if (fShutdown) + return; + } + } + Sleep(500); + } + } + + // Initiate network connections + int64 nStart = GetTime(); + loop + { + ProcessOneShot(); + + vnThreadsRunning[THREAD_OPENCONNECTIONS]--; + Sleep(500); + vnThreadsRunning[THREAD_OPENCONNECTIONS]++; + if (fShutdown) + return; + + + vnThreadsRunning[THREAD_OPENCONNECTIONS]--; + CSemaphoreGrant grant(*semOutbound); + vnThreadsRunning[THREAD_OPENCONNECTIONS]++; + if (fShutdown) + return; + + // Add seed nodes if IRC isn't working + if (addrman.size()==0 && (GetTime() - nStart > 60) && !fTestNet) + { + std::vector vAdd; + for (unsigned int i = 0; i < ARRAYLEN(pnSeed); i++) + { + // It'll only connect to one or two seed nodes because once it connects, + // it'll get a pile of addresses with newer timestamps. + // Seed nodes are given a random 'last seen time' of between one and two + // weeks ago. + const int64 nOneWeek = 7*24*60*60; + struct in_addr ip; + memcpy(&ip, &pnSeed[i], sizeof(ip)); + CAddress addr(CService(ip, GetDefaultPort())); + addr.nTime = GetTime()-GetRand(nOneWeek)-nOneWeek; + vAdd.push_back(addr); + } + addrman.Add(vAdd, CNetAddr("127.0.0.1")); + } + + // + // Choose an address to connect to based on most recently seen + // + CAddress addrConnect; + + // Only connect out to one peer per network group (/16 for IPv4). + // Do this here so we don't have to critsect vNodes inside mapAddresses critsect. + int nOutbound = 0; + set > setConnected; + { + LOCK(cs_vNodes); + BOOST_FOREACH(CNode* pnode, vNodes) { + if (!pnode->fInbound) { + setConnected.insert(pnode->addr.GetGroup()); + nOutbound++; + } + } + } + + int64 nANow = GetAdjustedTime(); + + int nTries = 0; + loop + { + // use an nUnkBias between 10 (no outgoing connections) and 90 (8 outgoing connections) + CAddress addr = addrman.Select(10 + min(nOutbound,8)*10); + + // if we selected an invalid address, restart + if (!addr.IsValid() || setConnected.count(addr.GetGroup()) || IsLocal(addr)) + break; + + // If we didn't find an appropriate destination after trying 100 addresses fetched from addrman, + // stop this loop, and let the outer loop run again (which sleeps, adds seed nodes, recalculates + // already-connected network ranges, ...) before trying new addrman addresses. + nTries++; + if (nTries > 100) + break; + + if (IsLimited(addr)) + continue; + + // only consider very recently tried nodes after 30 failed attempts + if (nANow - addr.nLastTry < 600 && nTries < 30) + continue; + + // do not allow non-default ports, unless after 50 invalid addresses selected already + if (addr.GetPort() != GetDefaultPort() && nTries < 50) + continue; + + addrConnect = addr; + break; + } + + if (addrConnect.IsValid()) + OpenNetworkConnection(addrConnect, &grant); + } +} + +void ThreadOpenAddedConnections(void* parg) +{ + // Make this thread recognisable as the connection opening thread + RenameThread("bitcoin-opencon"); + + printf("ThreadOpenAddedConnections started\n"); + + try + { + vnThreadsRunning[THREAD_ADDEDCONNECTIONS]++; + ThreadOpenAddedConnections2(parg); + vnThreadsRunning[THREAD_ADDEDCONNECTIONS]--; + } + catch (std::exception& e) { + vnThreadsRunning[THREAD_ADDEDCONNECTIONS]--; + PrintException(&e, "ThreadOpenAddedConnections()"); + } catch (...) { + vnThreadsRunning[THREAD_ADDEDCONNECTIONS]--; + PrintException(NULL, "ThreadOpenAddedConnections()"); + } + printf("ThreadOpenAddedConnections exited\n"); +} + +void ThreadOpenAddedConnections2(void* parg) +{ + printf("ThreadOpenAddedConnections2 started\n"); + + if (mapArgs.count("-addnode") == 0) + return; + + if (HaveNameProxy()) { + while(!fShutdown) { + BOOST_FOREACH(string& strAddNode, mapMultiArgs["-addnode"]) { + CAddress addr; + CSemaphoreGrant grant(*semOutbound); + OpenNetworkConnection(addr, &grant, strAddNode.c_str()); + Sleep(500); + } + vnThreadsRunning[THREAD_ADDEDCONNECTIONS]--; + Sleep(120000); // Retry every 2 minutes + vnThreadsRunning[THREAD_ADDEDCONNECTIONS]++; + } + return; + } + + vector > vservAddressesToAdd(0); + BOOST_FOREACH(string& strAddNode, mapMultiArgs["-addnode"]) + { + vector vservNode(0); + if(Lookup(strAddNode.c_str(), vservNode, GetDefaultPort(), fNameLookup, 0)) + { + vservAddressesToAdd.push_back(vservNode); + { + LOCK(cs_setservAddNodeAddresses); + BOOST_FOREACH(CService& serv, vservNode) + setservAddNodeAddresses.insert(serv); + } + } + } + loop + { + vector > vservConnectAddresses = vservAddressesToAdd; + // Attempt to connect to each IP for each addnode entry until at least one is successful per addnode entry + // (keeping in mind that addnode entries can have many IPs if fNameLookup) + { + LOCK(cs_vNodes); + BOOST_FOREACH(CNode* pnode, vNodes) + for (vector >::iterator it = vservConnectAddresses.begin(); it != vservConnectAddresses.end(); it++) + BOOST_FOREACH(CService& addrNode, *(it)) + if (pnode->addr == addrNode) + { + it = vservConnectAddresses.erase(it); + it--; + break; + } + } + BOOST_FOREACH(vector& vserv, vservConnectAddresses) + { + CSemaphoreGrant grant(*semOutbound); + OpenNetworkConnection(CAddress(*(vserv.begin())), &grant); + Sleep(500); + if (fShutdown) + return; + } + if (fShutdown) + return; + vnThreadsRunning[THREAD_ADDEDCONNECTIONS]--; + Sleep(120000); // Retry every 2 minutes + vnThreadsRunning[THREAD_ADDEDCONNECTIONS]++; + if (fShutdown) + return; + } + printf("ThreadOpenAddedConnections2 exited\n"); +} + +// if successful, this moves the passed grant to the constructed node +bool OpenNetworkConnection(const CAddress& addrConnect, CSemaphoreGrant *grantOutbound, const char *strDest, bool fOneShot) +{ + // + // Initiate outbound network connection + // + if (fShutdown) + return false; + if (!strDest) + if (IsLocal(addrConnect) || + FindNode((CNetAddr)addrConnect) || CNode::IsBanned(addrConnect) || + FindNode(addrConnect.ToStringIPPort().c_str())) + return false; + if (strDest && FindNode(strDest)) + return false; + + vnThreadsRunning[THREAD_OPENCONNECTIONS]--; + CNode* pnode = ConnectNode(addrConnect, strDest); + vnThreadsRunning[THREAD_OPENCONNECTIONS]++; + if (fShutdown) + return false; + if (!pnode) + return false; + if (grantOutbound) + grantOutbound->MoveTo(pnode->grantOutbound); + pnode->fNetworkNode = true; + if (fOneShot) + pnode->fOneShot = true; + + return true; +} + + + + + + + + +void ThreadMessageHandler(void* parg) +{ + // Make this thread recognisable as the message handling thread + RenameThread("bitcoin-msghand"); + + printf("ThreadMessageHandler started\n"); + + try + { + vnThreadsRunning[THREAD_MESSAGEHANDLER]++; + ThreadMessageHandler2(parg); + vnThreadsRunning[THREAD_MESSAGEHANDLER]--; + } + catch (std::exception& e) { + vnThreadsRunning[THREAD_MESSAGEHANDLER]--; + PrintException(&e, "ThreadMessageHandler()"); + } catch (...) { + vnThreadsRunning[THREAD_MESSAGEHANDLER]--; + PrintException(NULL, "ThreadMessageHandler()"); + } + printf("ThreadMessageHandler exited\n"); +} + +void ThreadMessageHandler2(void* parg) +{ + printf("ThreadMessageHandler2 started\n"); + SetThreadPriority(THREAD_PRIORITY_BELOW_NORMAL); + while (!fShutdown) + { + vector vNodesCopy; + { + LOCK(cs_vNodes); + vNodesCopy = vNodes; + BOOST_FOREACH(CNode* pnode, vNodesCopy) + pnode->AddRef(); + } + + // Poll the connected nodes for messages + CNode* pnodeTrickle = NULL; + if (!vNodesCopy.empty()) + pnodeTrickle = vNodesCopy[GetRand(vNodesCopy.size())]; + BOOST_FOREACH(CNode* pnode, vNodesCopy) + { + // Receive messages + { + TRY_LOCK(pnode->cs_vRecv, lockRecv); + if (lockRecv) + ProcessMessages(pnode); + } + if (fShutdown) + return; + + // Send messages + { + TRY_LOCK(pnode->cs_vSend, lockSend); + if (lockSend) + SendMessages(pnode, pnode == pnodeTrickle); + } + if (fShutdown) + return; + } + + { + LOCK(cs_vNodes); + BOOST_FOREACH(CNode* pnode, vNodesCopy) + pnode->Release(); + } + + // Wait and allow messages to bunch up. + // Reduce vnThreadsRunning so StopNode has permission to exit while + // we're sleeping, but we must always check fShutdown after doing this. + vnThreadsRunning[THREAD_MESSAGEHANDLER]--; + Sleep(100); + if (fRequestShutdown) + StartShutdown(); + vnThreadsRunning[THREAD_MESSAGEHANDLER]++; + if (fShutdown) + return; + } + printf("ThreadMessageHandler2 exited\n"); +} + + + + + + +bool BindListenPort(const CService &addrBind, string& strError) +{ + strError = ""; + int nOne = 1; + +#ifdef WIN32 + // Initialize Windows Sockets + WSADATA wsadata; + int ret = WSAStartup(MAKEWORD(2,2), &wsadata); + if (ret != NO_ERROR) + { + strError = strprintf("Error: TCP/IP socket library failed to start (WSAStartup returned error %d)", ret); + printf("%s\n", strError.c_str()); + return false; + } +#endif + + // Create socket for listening for incoming connections +#ifdef USE_IPV6 + struct sockaddr_storage sockaddr; +#else + struct sockaddr sockaddr; +#endif + socklen_t len = sizeof(sockaddr); + if (!addrBind.GetSockAddr((struct sockaddr*)&sockaddr, &len)) + { + strError = strprintf("Error: bind address family for %s not supported", addrBind.ToString().c_str()); + printf("%s\n", strError.c_str()); + return false; + } + + SOCKET hListenSocket = socket(((struct sockaddr*)&sockaddr)->sa_family, SOCK_STREAM, IPPROTO_TCP); + if (hListenSocket == INVALID_SOCKET) + { + strError = strprintf("Error: Couldn't open socket for incoming connections (socket returned error %d)", WSAGetLastError()); + printf("%s\n", strError.c_str()); + return false; + } + +#ifdef SO_NOSIGPIPE + // Different way of disabling SIGPIPE on BSD + setsockopt(hListenSocket, SOL_SOCKET, SO_NOSIGPIPE, (void*)&nOne, sizeof(int)); +#endif + +#ifndef WIN32 + // Allow binding if the port is still in TIME_WAIT state after + // the program was closed and restarted. Not an issue on windows. + setsockopt(hListenSocket, SOL_SOCKET, SO_REUSEADDR, (void*)&nOne, sizeof(int)); +#endif + + +#ifdef WIN32 + // Set to non-blocking, incoming connections will also inherit this + if (ioctlsocket(hListenSocket, FIONBIO, (u_long*)&nOne) == SOCKET_ERROR) +#else + if (fcntl(hListenSocket, F_SETFL, O_NONBLOCK) == SOCKET_ERROR) +#endif + { + strError = strprintf("Error: Couldn't set properties on socket for incoming connections (error %d)", WSAGetLastError()); + printf("%s\n", strError.c_str()); + return false; + } + +#ifdef USE_IPV6 + // some systems don't have IPV6_V6ONLY but are always v6only; others do have the option + // and enable it by default or not. Try to enable it, if possible. + if (addrBind.IsIPv6()) { +#ifdef IPV6_V6ONLY +#ifdef WIN32 + setsockopt(hListenSocket, IPPROTO_IPV6, IPV6_V6ONLY, (const char*)&nOne, sizeof(int)); +#else + setsockopt(hListenSocket, IPPROTO_IPV6, IPV6_V6ONLY, (void*)&nOne, sizeof(int)); +#endif +#endif +#ifdef WIN32 + int nProtLevel = 10 /* PROTECTION_LEVEL_UNRESTRICTED */; + int nParameterId = 23 /* IPV6_PROTECTION_LEVEl */; + // this call is allowed to fail + setsockopt(hListenSocket, IPPROTO_IPV6, nParameterId, (const char*)&nProtLevel, sizeof(int)); +#endif + } +#endif + + if (::bind(hListenSocket, (struct sockaddr*)&sockaddr, len) == SOCKET_ERROR) + { + int nErr = WSAGetLastError(); + if (nErr == WSAEADDRINUSE) + strError = strprintf(_("Unable to bind to %s on this computer. triangles is probably already running."), addrBind.ToString().c_str()); + else + strError = strprintf(_("Unable to bind to %s on this computer (bind returned error %d, %s)"), addrBind.ToString().c_str(), nErr, strerror(nErr)); + printf("%s\n", strError.c_str()); + return false; + } + printf("Bound to %s\n", addrBind.ToString().c_str()); + + // Listen for incoming connections + if (listen(hListenSocket, SOMAXCONN) == SOCKET_ERROR) + { + strError = strprintf("Error: Listening for incoming connections failed (listen returned error %d)", WSAGetLastError()); + printf("%s\n", strError.c_str()); + return false; + } + + vhListenSocket.push_back(hListenSocket); + + return true; +} + +void static Discover() +{ + // no network discovery +} + +static void run_tor() { + printf("TOR thread started.\n"); + + std::string logDecl = "notice file " + GetDataDir().string() + "/tor/tor.log"; + char *argvLogDecl = (char*) logDecl.c_str(); + + char* argv[] = { + "tor", + "--hush", + "--Log", + argvLogDecl + }; + + tor_main(4, argv); +} + + +void StartTor(void* parg) +{ + // Make this thread recognisable as the tor thread + RenameThread("onion"); + + try + { + run_tor(); + } + catch (std::exception& e) { + PrintException(&e, "StartTor()"); + } + + printf("Onion thread exited."); + +} + +void StartNode(void* parg) +{ + // Make this thread recognisable as the startup thread + RenameThread("bitcoin-start"); + + if (semOutbound == NULL) { + // initialize semaphore + int nMaxOutbound = min(MAX_OUTBOUND_CONNECTIONS, (int)GetArg("-maxconnections", 125)); + semOutbound = new CSemaphore(nMaxOutbound); + } + + if (pnodeLocalHost == NULL) + pnodeLocalHost = new CNode(INVALID_SOCKET, CAddress(CService("127.0.0.1", 0), nLocalServices)); + + printf("StartNode(): pnodeLocalHost addr: %s\n", + pnodeLocalHost->addr.ToString().c_str()); + + Discover(); + + // + // Start threads + // + + // start the onion seeder + if (!GetBoolArg("-onionseed", true)) + printf(".onion seeding disabled\n"); + else + if (!NewThread(ThreadOnionSeed, NULL)) + printf("Error: could not start .onion seeding\n"); + + // Map ports with UPnP (default) + if (fUseUPnP) + MapPort(fUseUPnP); + + // Get addresses from IRC and advertise ours + //if (!NewThread(ThreadIRCSeed, NULL)) + // printf("Error: NewThread(ThreadIRCSeed) failed\n"); + + // Send and receive from sockets, accept connections + if (!NewThread(ThreadSocketHandler, NULL)) + printf("Error: NewThread(ThreadSocketHandler) failed\n"); + + // Initiate outbound connections from -addnode + if (!NewThread(ThreadOpenAddedConnections, NULL)) + printf("Error: NewThread(ThreadOpenAddedConnections) failed\n"); + + // Initiate outbound connections + if (!NewThread(ThreadOpenConnections, NULL)) + printf("Error: NewThread(ThreadOpenConnections) failed\n"); + + // Process messages + if (!NewThread(ThreadMessageHandler, NULL)) + printf("Error: NewThread(ThreadMessageHandler) failed\n"); + + // Dump network addresses + if (!NewThread(ThreadDumpAddress, NULL)) + printf("Error; NewThread(ThreadDumpAddress) failed\n"); + + + // make sure conf allows it (stake=0 in conf) + if (GetBoolArg("-stake", true)) { + printf("Stake minting enabled at startup.\n"); + if (!NewThread(ThreadStakeMinter, pwalletMain)) + printf("Error: NewThread(ThreadStakeMinter) failed\n"); + } else { + printf("Stake minting disabled at startup (stake=0).\n"); + } + + // Generate coins in the background + GenerateBitcoins(GetBoolArg("-gen", false), pwalletMain); +} + + + +bool StopNode() +{ + printf("StopNode()\n"); + fShutdown = true; + nTransactionsUpdated++; + int64 nStart = GetTime(); + if (semOutbound) + for (int i=0; ipost(); + do + { + int nThreadsRunning = 0; + for (int n = 0; n < THREAD_MAX; n++) + nThreadsRunning += vnThreadsRunning[n]; + if (nThreadsRunning == 0) + break; + if (GetTime() - nStart > 20) + break; + Sleep(20); + } while(true); + if (vnThreadsRunning[THREAD_SOCKETHANDLER] > 0) printf("ThreadSocketHandler still running\n"); + if (vnThreadsRunning[THREAD_OPENCONNECTIONS] > 0) printf("ThreadOpenConnections still running\n"); + if (vnThreadsRunning[THREAD_MESSAGEHANDLER] > 0) printf("ThreadMessageHandler still running\n"); + if (vnThreadsRunning[THREAD_MINER] > 0) printf("ThreadBitcoinMiner still running\n"); + if (vnThreadsRunning[THREAD_RPCLISTENER] > 0) printf("ThreadRPCListener still running\n"); + if (vnThreadsRunning[THREAD_RPCHANDLER] > 0) printf("ThreadsRPCServer still running\n"); +#ifdef USE_UPNP + if (vnThreadsRunning[THREAD_UPNP] > 0) printf("ThreadMapPort still running\n"); +#endif + if (vnThreadsRunning[THREAD_DNSSEED] > 0) printf("ThreadDNSAddressSeed still running\n"); + if (vnThreadsRunning[THREAD_ADDEDCONNECTIONS] > 0) printf("ThreadOpenAddedConnections still running\n"); + if (vnThreadsRunning[THREAD_DUMPADDRESS] > 0) printf("ThreadDumpAddresses still running\n"); + if (vnThreadsRunning[THREAD_STAKER] > 0) printf("ThreadStakeMinter still running\n"); + while (vnThreadsRunning[THREAD_MESSAGEHANDLER] > 0 || vnThreadsRunning[THREAD_RPCHANDLER] > 0) + Sleep(20); + Sleep(50); + DumpAddresses(); + return true; +} + +class CNetCleanup +{ +public: + CNetCleanup() + { + } + ~CNetCleanup() + { + // Close sockets + BOOST_FOREACH(CNode* pnode, vNodes) + if (pnode->hSocket != INVALID_SOCKET) + closesocket(pnode->hSocket); + BOOST_FOREACH(SOCKET hListenSocket, vhListenSocket) + if (hListenSocket != INVALID_SOCKET) + if (closesocket(hListenSocket) == SOCKET_ERROR) + printf("closesocket(hListenSocket) failed with error %d\n", WSAGetLastError()); + +#ifdef WIN32 + // Shutdown Windows Sockets + WSACleanup(); +#endif + } +} +instance_of_cnetcleanup; diff --git a/src/net.h b/src/net.h new file mode 100644 index 0000000..6fb0f9f --- /dev/null +++ b/src/net.h @@ -0,0 +1,693 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2012 The Bitcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. +#ifndef BITCOIN_NET_H +#define BITCOIN_NET_H + +#include +#include +#include +#include + +#ifndef WIN32 +#include +#endif + +#include "mruset.h" +#include "netbase.h" +#include "protocol.h" +#include "addrman.h" + +class CRequestTracker; +class CNode; +class CBlockIndex; +extern int nBestHeight; + + +inline unsigned int ReceiveBufferSize() { return 1000*GetArg("-maxreceivebuffer", 5*1000); } +inline unsigned int SendBufferSize() { return 1000*GetArg("-maxsendbuffer", 1*1000); } + +void AddOneShot(std::string strDest); +bool RecvLine(SOCKET hSocket, std::string& strLine); +bool GetMyExternalIP(CNetAddr& ipRet); +void AddressCurrentlyConnected(const CService& addr); +CNode* FindNode(const CNetAddr& ip); +CNode* FindNode(const CService& ip); +CNode* ConnectNode(CAddress addrConnect, const char *strDest = NULL, int64 nTimeout=0); +void MapPort(bool fUseUPnP); +unsigned short GetListenPort(); +bool BindListenPort(const CService &bindAddr, std::string& strError=REF(std::string())); +void StartNode(void* parg); +void StartTor(void* parg); +bool StopNode(); + +enum +{ + LOCAL_NONE, // unknown + LOCAL_IF, // address a local interface listens on + LOCAL_BIND, // address explicit bound to + LOCAL_UPNP, // address reported by UPnP + LOCAL_IRC, // address reported by IRC (deprecated) + LOCAL_HTTP, // address reported by whatismyip.com and similar + LOCAL_MANUAL, // address explicitly specified (-externalip=) + + LOCAL_MAX +}; + +void SetLimited(enum Network net, bool fLimited = true); +bool IsLimited(enum Network net); +bool IsLimited(const CNetAddr& addr); +bool AddLocal(const CService& addr, int nScore = LOCAL_NONE); +bool AddLocal(const CNetAddr& addr, int nScore = LOCAL_NONE); +bool SeenLocal(const CService& addr); +bool IsLocal(const CService& addr); +bool GetLocal(CService &addr, const CNetAddr *paddrPeer = NULL); +bool IsReachable(const CNetAddr &addr); +void SetReachable(enum Network net, bool fFlag = true); +CAddress GetLocalAddress(const CNetAddr *paddrPeer = NULL); + + +enum +{ + MSG_TX = 1, + MSG_BLOCK, +}; + +class CRequestTracker +{ +public: + void (*fn)(void*, CDataStream&); + void* param1; + + explicit CRequestTracker(void (*fnIn)(void*, CDataStream&)=NULL, void* param1In=NULL) + { + fn = fnIn; + param1 = param1In; + } + + bool IsNull() + { + return fn == NULL; + } +}; + + +/** Thread types */ +enum threadId +{ + THREAD_SOCKETHANDLER, + THREAD_OPENCONNECTIONS, + THREAD_MESSAGEHANDLER, + THREAD_MINER, + THREAD_RPCLISTENER, + THREAD_UPNP, + THREAD_DNSSEED, + THREAD_ADDEDCONNECTIONS, + THREAD_DUMPADDRESS, + THREAD_RPCHANDLER, + THREAD_STAKER, + + THREAD_MAX +}; + +extern bool fClient; +extern uint64 nLocalServices; +extern uint64 nLocalHostNonce; +extern CAddress addrSeenByPeer; +extern boost::array vnThreadsRunning; +extern CAddrMan addrman; + +extern std::vector vNodes; +extern CCriticalSection cs_vNodes; +extern std::map mapRelay; +extern std::deque > vRelayExpiration; +extern CCriticalSection cs_mapRelay; +extern std::map mapAlreadyAskedFor; + + + + +class CNodeStats +{ +public: + uint64 nServices; + int64 nLastSend; + int64 nLastRecv; + int64 nTimeConnected; + std::string addrName; + int nVersion; + std::string cleanSubVer; + bool fInbound; + int64 nReleaseTime; + int nStartingHeight; + int nMisbehavior; +}; + + + + + +/** Information about a peer */ +class CNode +{ +public: + // socket + uint64 nServices; + SOCKET hSocket; + CDataStream vSend; + CDataStream vRecv; + CCriticalSection cs_vSend; + CCriticalSection cs_vRecv; + int64 nLastSend; + int64 nLastRecv; + int64 nLastSendEmpty; + int64 nTimeConnected; + int nHeaderStart; + unsigned int nMessageStart; + CAddress addr; + std::string addrName; + CService addrLocal; + int nVersion; + // strSubVer is whatever byte array we read from the wire. However, this field is intended + // to be printed out, displayed to humans in various forms and so on. So we sanitize it and + // store the sanitized version in cleanSubVer. The original should be used when dealing with + // the network or wire types and the cleaned string used when displayed or logged. + std::string strSubVer, cleanSubVer; + bool fOneShot; + bool fClient; + bool fInbound; + bool fVerified; + bool fNetworkNode; + bool fSuccessfullyConnected; + bool fDisconnect; + CSemaphoreGrant grantOutbound; +protected: + int nRefCount; + + // Denial-of-service detection/prevention + // Key is IP address, value is banned-until-time + static std::map setBanned; + static CCriticalSection cs_setBanned; + int nMisbehavior; + +public: + int64 nReleaseTime; + std::map mapRequests; + CCriticalSection cs_mapRequests; + uint256 hashContinue; + CBlockIndex* pindexLastGetBlocksBegin; + uint256 hashLastGetBlocksEnd; + int nStartingHeight; + + // flood relay + std::vector vAddrToSend; + std::set setAddrKnown; + bool fGetAddr; + std::set setKnown; + uint256 hashCheckpointKnown; // triangles: known sent sync-checkpoint + + // inventory based relay + mruset setInventoryKnown; + std::vector vInventoryToSend; + CCriticalSection cs_inventory; + std::multimap mapAskFor; + + CNode(SOCKET hSocketIn, CAddress addrIn, std::string addrNameIn = "", bool fInboundIn=false) : vSend(SER_NETWORK, MIN_PROTO_VERSION), vRecv(SER_NETWORK, MIN_PROTO_VERSION) + { + nServices = 0; + hSocket = hSocketIn; + nLastSend = 0; + nLastRecv = 0; + nLastSendEmpty = GetTime(); + nTimeConnected = GetTime(); + nHeaderStart = -1; + nMessageStart = -1; + addr = addrIn; + addrName = addrNameIn == "" ? addr.ToStringIPPort() : addrNameIn; + nVersion = 0; + strSubVer = ""; + fOneShot = false; + fClient = false; // set by version message + fInbound = fInboundIn; + fVerified = false; + fNetworkNode = false; + fSuccessfullyConnected = false; + fDisconnect = false; + nRefCount = 0; + nReleaseTime = 0; + hashContinue = 0; + pindexLastGetBlocksBegin = 0; + hashLastGetBlocksEnd = 0; + nStartingHeight = -1; + fGetAddr = false; + nMisbehavior = 0; + hashCheckpointKnown = 0; + setInventoryKnown.max_size(SendBufferSize() / 1000); + + // Be shy and don't send version until we hear + if (!fInbound) + printf("CNode(): pfrom-addr %s\n", addrName.c_str()); + PushVersion(); + } + + ~CNode() + { + if (hSocket != INVALID_SOCKET) + { + closesocket(hSocket); + hSocket = INVALID_SOCKET; + } + } + +private: + CNode(const CNode&); + void operator=(const CNode&); +public: + + + int GetRefCount() + { + return std::max(nRefCount, 0) + (GetTime() < nReleaseTime ? 1 : 0); + } + + CNode* AddRef(int64 nTimeout=0) + { + if (nTimeout != 0) + nReleaseTime = std::max(nReleaseTime, GetTime() + nTimeout); + else + nRefCount++; + return this; + } + + void Release() + { + nRefCount--; + } + + + + void AddAddressKnown(const CAddress& addr) + { + setAddrKnown.insert(addr); + } + + void PushAddress(const CAddress& addr) + { + // Known checking here is only to save space from duplicates. + // SendMessages will filter it again for knowns that were added + // after addresses were pushed. + if (addr.IsValid() && !setAddrKnown.count(addr)) + vAddrToSend.push_back(addr); + } + + + void AddInventoryKnown(const CInv& inv) + { + { + LOCK(cs_inventory); + setInventoryKnown.insert(inv); + } + } + + void PushInventory(const CInv& inv) + { + { + LOCK(cs_inventory); + if (!setInventoryKnown.count(inv)) + vInventoryToSend.push_back(inv); + } + } + + void AskFor(const CInv& inv) + { + // We're using mapAskFor as a priority queue, + // the key is the earliest time the request can be sent + int64& nRequestTime = mapAlreadyAskedFor[inv]; + if (fDebugNet) + printf("askfor %s %"PRI64d" (%s)\n", inv.ToString().c_str(), nRequestTime, DateTimeStrFormat("%H:%M:%S", nRequestTime/1000000).c_str()); + + // Make sure not to reuse time indexes to keep things in the same order + int64 nNow = (GetTime() - 1) * 1000000; + static int64 nLastTime; + ++nLastTime; + nNow = std::max(nNow, nLastTime); + nLastTime = nNow; + + // Each retry is 2 minutes after the last + nRequestTime = std::max(nRequestTime + 2 * 60 * 1000000, nNow); + mapAskFor.insert(std::make_pair(nRequestTime, inv)); + } + + + + void BeginMessage(const char* pszCommand) + { + ENTER_CRITICAL_SECTION(cs_vSend); + if (nHeaderStart != -1) + AbortMessage(); + nHeaderStart = vSend.size(); + vSend << CMessageHeader(pszCommand, 0); + nMessageStart = vSend.size(); + if (fDebug) + printf("sending: %s ", pszCommand); + } + + void AbortMessage() + { + if (nHeaderStart < 0) + return; + vSend.resize(nHeaderStart); + nHeaderStart = -1; + nMessageStart = -1; + LEAVE_CRITICAL_SECTION(cs_vSend); + + if (fDebug) + printf("(aborted)\n"); + } + + void EndMessage() + { + if (mapArgs.count("-dropmessagestest") && GetRand(atoi(mapArgs["-dropmessagestest"])) == 0) + { + printf("dropmessages DROPPING SEND MESSAGE\n"); + AbortMessage(); + return; + } + + if (nHeaderStart < 0) + return; + + // Set the size + unsigned int nSize = vSend.size() - nMessageStart; + memcpy((char*)&vSend[nHeaderStart] + CMessageHeader::MESSAGE_SIZE_OFFSET, &nSize, sizeof(nSize)); + + // Set the checksum + uint256 hash = Hash(vSend.begin() + nMessageStart, vSend.end()); + unsigned int nChecksum = 0; + memcpy(&nChecksum, &hash, sizeof(nChecksum)); + assert(nMessageStart - nHeaderStart >= CMessageHeader::CHECKSUM_OFFSET + sizeof(nChecksum)); + memcpy((char*)&vSend[nHeaderStart] + CMessageHeader::CHECKSUM_OFFSET, &nChecksum, sizeof(nChecksum)); + + if (fDebug) { + printf("(%d bytes)\n", nSize); + } + + nHeaderStart = -1; + nMessageStart = -1; + LEAVE_CRITICAL_SECTION(cs_vSend); + } + + void EndMessageAbortIfEmpty() + { + if (nHeaderStart < 0) + return; + int nSize = vSend.size() - nMessageStart; + if (nSize > 0) + EndMessage(); + else + AbortMessage(); + } + + + + void PushVersion(); + + + void PushMessage(const char* pszCommand) + { + try + { + BeginMessage(pszCommand); + EndMessage(); + } + catch (...) + { + AbortMessage(); + throw; + } + } + + template + void PushMessage(const char* pszCommand, const T1& a1) + { + try + { + BeginMessage(pszCommand); + vSend << a1; + EndMessage(); + } + catch (...) + { + AbortMessage(); + throw; + } + } + + template + void PushMessage(const char* pszCommand, const T1& a1, const T2& a2) + { + try + { + BeginMessage(pszCommand); + vSend << a1 << a2; + EndMessage(); + } + catch (...) + { + AbortMessage(); + throw; + } + } + + template + void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3) + { + try + { + BeginMessage(pszCommand); + vSend << a1 << a2 << a3; + EndMessage(); + } + catch (...) + { + AbortMessage(); + throw; + } + } + + template + void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3, const T4& a4) + { + try + { + BeginMessage(pszCommand); + vSend << a1 << a2 << a3 << a4; + EndMessage(); + } + catch (...) + { + AbortMessage(); + throw; + } + } + + template + void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3, const T4& a4, const T5& a5) + { + try + { + BeginMessage(pszCommand); + vSend << a1 << a2 << a3 << a4 << a5; + EndMessage(); + } + catch (...) + { + AbortMessage(); + throw; + } + } + + template + void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3, const T4& a4, const T5& a5, const T6& a6) + { + try + { + BeginMessage(pszCommand); + vSend << a1 << a2 << a3 << a4 << a5 << a6; + EndMessage(); + } + catch (...) + { + AbortMessage(); + throw; + } + } + + template + void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3, const T4& a4, const T5& a5, const T6& a6, const T7& a7) + { + try + { + BeginMessage(pszCommand); + vSend << a1 << a2 << a3 << a4 << a5 << a6 << a7; + EndMessage(); + } + catch (...) + { + AbortMessage(); + throw; + } + } + + template + void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3, const T4& a4, const T5& a5, const T6& a6, const T7& a7, const T8& a8) + { + try + { + BeginMessage(pszCommand); + vSend << a1 << a2 << a3 << a4 << a5 << a6 << a7 << a8; + EndMessage(); + } + catch (...) + { + AbortMessage(); + throw; + } + } + + template + void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3, const T4& a4, const T5& a5, const T6& a6, const T7& a7, const T8& a8, const T9& a9) + { + try + { + BeginMessage(pszCommand); + vSend << a1 << a2 << a3 << a4 << a5 << a6 << a7 << a8 << a9; + EndMessage(); + } + catch (...) + { + AbortMessage(); + throw; + } + } + + + void PushRequest(const char* pszCommand, + void (*fn)(void*, CDataStream&), void* param1) + { + uint256 hashReply; + RAND_bytes((unsigned char*)&hashReply, sizeof(hashReply)); + + { + LOCK(cs_mapRequests); + mapRequests[hashReply] = CRequestTracker(fn, param1); + } + + PushMessage(pszCommand, hashReply); + } + + template + void PushRequest(const char* pszCommand, const T1& a1, + void (*fn)(void*, CDataStream&), void* param1) + { + uint256 hashReply; + RAND_bytes((unsigned char*)&hashReply, sizeof(hashReply)); + + { + LOCK(cs_mapRequests); + mapRequests[hashReply] = CRequestTracker(fn, param1); + } + + PushMessage(pszCommand, hashReply, a1); + } + + template + void PushRequest(const char* pszCommand, const T1& a1, const T2& a2, + void (*fn)(void*, CDataStream&), void* param1) + { + uint256 hashReply; + RAND_bytes((unsigned char*)&hashReply, sizeof(hashReply)); + + { + LOCK(cs_mapRequests); + mapRequests[hashReply] = CRequestTracker(fn, param1); + } + + PushMessage(pszCommand, hashReply, a1, a2); + } + + + + void PushGetBlocks(CBlockIndex* pindexBegin, uint256 hashEnd); + bool IsSubscribed(unsigned int nChannel); + void Subscribe(unsigned int nChannel, unsigned int nHops=0); + void CancelSubscribe(unsigned int nChannel); + void CloseSocketDisconnect(); + void Cleanup(); + + + // Denial-of-service detection/prevention + // The idea is to detect peers that are behaving + // badly and disconnect/ban them, but do it in a + // one-coding-mistake-won't-shatter-the-entire-network + // way. + // IMPORTANT: There should be nothing I can give a + // node that it will forward on that will make that + // node's peers drop it. If there is, an attacker + // can isolate a node and/or try to split the network. + // Dropping a node for sending stuff that is invalid + // now but might be valid in a later version is also + // dangerous, because it can cause a network split + // between nodes running old code and nodes running + // new code. + static void ClearBanned(); // needed for unit testing + static bool IsBanned(CNetAddr ip); + bool Misbehaving(int howmuch); // 1 == a little, 100 == a lot + void copyStats(CNodeStats &stats); +}; + + + + +inline void RelayInventory(const CInv& inv) +{ + // Put on lists to offer to the other nodes + { + LOCK(cs_vNodes); + BOOST_FOREACH(CNode* pnode, vNodes) + pnode->PushInventory(inv); + } +} + +template +void RelayMessage(const CInv& inv, const T& a) +{ + CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); + ss.reserve(10000); + ss << a; + RelayMessage(inv, ss); +} + +template<> +inline void RelayMessage<>(const CInv& inv, const CDataStream& ss) +{ + { + LOCK(cs_mapRelay); + // Expire old relay messages + while (!vRelayExpiration.empty() && vRelayExpiration.front().first < GetTime()) + { + mapRelay.erase(vRelayExpiration.front().second); + vRelayExpiration.pop_front(); + } + + // Save original serialized message so newer versions are preserved + mapRelay.insert(std::make_pair(inv, ss)); + vRelayExpiration.push_back(std::make_pair(GetTime() + 15 * 60, inv)); + } + + RelayInventory(inv); +} + + +#endif diff --git a/src/netbase.cpp b/src/netbase.cpp new file mode 100644 index 0000000..e2ad5e0 --- /dev/null +++ b/src/netbase.cpp @@ -0,0 +1,1224 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2012 The Bitcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "netbase.h" +#include "util.h" +#include "sync.h" + +#ifndef WIN32 +#include +#endif + +#include "strlcpy.h" +#include // for to_lower() + +using namespace std; + +// Settings +static proxyType proxyInfo[NET_MAX]; +static proxyType nameproxyInfo; +static CCriticalSection cs_proxyInfos; +int nConnectTimeout = 5000; +bool fNameLookup = false; + +static const unsigned char pchIPv4[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff }; + +enum Network ParseNetwork(std::string net) { + boost::to_lower(net); + if (net == "ipv4") return NET_IPV4; + if (net == "ipv6") return NET_IPV6; + if (net == "tor") return NET_TOR; + if (net == "i2p") return NET_I2P; + return NET_UNROUTABLE; +} + +void SplitHostPort(std::string in, int &portOut, std::string &hostOut) { + size_t colon = in.find_last_of(':'); + // if a : is found, and it either follows a [...], or no other : is in the string, treat it as port separator + bool fHaveColon = colon != in.npos; + bool fBracketed = fHaveColon && (in[0]=='[' && in[colon-1]==']'); // if there is a colon, and in[0]=='[', colon is not 0, so in[colon-1] is safe + bool fMultiColon = fHaveColon && (in.find_last_of(':',colon-1) != in.npos); + if (fHaveColon && (colon==0 || fBracketed || !fMultiColon)) { + char *endp = NULL; + int n = strtol(in.c_str() + colon + 1, &endp, 10); + if (endp && *endp == 0 && n >= 0) { + in = in.substr(0, colon); + if (n > 0 && n < 0x10000) + portOut = n; + } + } + if (in.size()>0 && in[0] == '[' && in[in.size()-1] == ']') + hostOut = in.substr(1, in.size()-2); + else + hostOut = in; +} + +bool static LookupIntern(const char *pszName, std::vector& vIP, unsigned int nMaxSolutions, bool fAllowLookup) +{ + vIP.clear(); + + { + CNetAddr addr; + if (addr.SetSpecial(std::string(pszName))) { + vIP.push_back(addr); + return true; + } + } + + struct addrinfo aiHint; + memset(&aiHint, 0, sizeof(struct addrinfo)); + + aiHint.ai_socktype = SOCK_STREAM; + aiHint.ai_protocol = IPPROTO_TCP; +#ifdef WIN32 +# ifdef USE_IPV6 + aiHint.ai_family = AF_UNSPEC; +# else + aiHint.ai_family = AF_INET; +# endif + aiHint.ai_flags = fAllowLookup ? 0 : AI_NUMERICHOST; +#else +# ifdef USE_IPV6 + aiHint.ai_family = AF_UNSPEC; +# else + aiHint.ai_family = AF_INET; +# endif + aiHint.ai_flags = fAllowLookup ? AI_ADDRCONFIG : AI_NUMERICHOST; +#endif + struct addrinfo *aiRes = NULL; + int nErr = getaddrinfo(pszName, NULL, &aiHint, &aiRes); + if (nErr) + return false; + + struct addrinfo *aiTrav = aiRes; + while (aiTrav != NULL && (nMaxSolutions == 0 || vIP.size() < nMaxSolutions)) + { + if (aiTrav->ai_family == AF_INET) + { + assert(aiTrav->ai_addrlen >= sizeof(sockaddr_in)); + vIP.push_back(CNetAddr(((struct sockaddr_in*)(aiTrav->ai_addr))->sin_addr)); + } + +#ifdef USE_IPV6 + if (aiTrav->ai_family == AF_INET6) + { + assert(aiTrav->ai_addrlen >= sizeof(sockaddr_in6)); + vIP.push_back(CNetAddr(((struct sockaddr_in6*)(aiTrav->ai_addr))->sin6_addr)); + } +#endif + + aiTrav = aiTrav->ai_next; + } + + freeaddrinfo(aiRes); + + return (vIP.size() > 0); +} + +bool LookupHost(const char *pszName, std::vector& vIP, unsigned int nMaxSolutions, bool fAllowLookup) +{ + if (pszName[0] == 0) + return false; + char psz[256]; + char *pszHost = psz; + strlcpy(psz, pszName, sizeof(psz)); + if (psz[0] == '[' && psz[strlen(psz)-1] == ']') + { + pszHost = psz+1; + psz[strlen(psz)-1] = 0; + } + + return LookupIntern(pszHost, vIP, nMaxSolutions, fAllowLookup); +} + +bool LookupHostNumeric(const char *pszName, std::vector& vIP, unsigned int nMaxSolutions) +{ + return LookupHost(pszName, vIP, nMaxSolutions, false); +} + +bool Lookup(const char *pszName, std::vector& vAddr, int portDefault, bool fAllowLookup, unsigned int nMaxSolutions) +{ + if (pszName[0] == 0) + return false; + int port = portDefault; + std::string hostname = ""; + SplitHostPort(std::string(pszName), port, hostname); + + std::vector vIP; + bool fRet = LookupIntern(hostname.c_str(), vIP, nMaxSolutions, fAllowLookup); + if (!fRet) + return false; + vAddr.resize(vIP.size()); + for (unsigned int i = 0; i < vIP.size(); i++) + vAddr[i] = CService(vIP[i], port); + return true; +} + +bool Lookup(const char *pszName, CService& addr, int portDefault, bool fAllowLookup) +{ + std::vector vService; + bool fRet = Lookup(pszName, vService, portDefault, fAllowLookup, 1); + if (!fRet) + return false; + addr = vService[0]; + return true; +} + +bool LookupNumeric(const char *pszName, CService& addr, int portDefault) +{ + return Lookup(pszName, addr, portDefault, false); +} + +bool static Socks4(const CService &addrDest, SOCKET& hSocket) +{ + printf("SOCKS4 connecting %s\n", addrDest.ToString().c_str()); + if (!addrDest.IsIPv4()) + { + closesocket(hSocket); + return error("Proxy destination is not IPv4"); + } + char pszSocks4IP[] = "\4\1\0\0\0\0\0\0user"; + struct sockaddr_in addr; + socklen_t len = sizeof(addr); + if (!addrDest.GetSockAddr((struct sockaddr*)&addr, &len) || addr.sin_family != AF_INET) + { + closesocket(hSocket); + return error("Cannot get proxy destination address"); + } + memcpy(pszSocks4IP + 2, &addr.sin_port, 2); + memcpy(pszSocks4IP + 4, &addr.sin_addr, 4); + char* pszSocks4 = pszSocks4IP; + int nSize = sizeof(pszSocks4IP); + + int ret = send(hSocket, pszSocks4, nSize, MSG_NOSIGNAL); + if (ret != nSize) + { + closesocket(hSocket); + return error("Error sending to proxy"); + } + char pchRet[8]; + if (recv(hSocket, pchRet, 8, 0) != 8) + { + closesocket(hSocket); + return error("Error reading proxy response"); + } + if (pchRet[1] != 0x5a) + { + closesocket(hSocket); + if (pchRet[1] != 0x5b) + printf("ERROR: Proxy returned error %d\n", pchRet[1]); + return false; + } + printf("SOCKS4 connected %s\n", addrDest.ToString().c_str()); + return true; +} + +bool static Socks5(string strDest, int port, SOCKET& hSocket) +{ + printf("SOCKS5 connecting %s\n", strDest.c_str()); + if (strDest.size() > 255) + { + closesocket(hSocket); + return error("Hostname too long"); + } + char pszSocks5Init[] = "\5\1\0"; + if (fDebug) + { + printf("Socks5(): pszSocks5Init: %s\n", pszSocks5Init); + } + char *pszSocks5 = pszSocks5Init; + ssize_t nSize = sizeof(pszSocks5Init) - 1; + + ssize_t ret = send(hSocket, pszSocks5, nSize, MSG_NOSIGNAL); + if (ret != nSize) + { + closesocket(hSocket); + return error("Error sending to proxy"); + } + char pchRet1[2]; + if (recv(hSocket, pchRet1, 2, 0) != 2) + { + closesocket(hSocket); + return error("Error reading proxy response"); + } + if (fDebug) + { + printf("Socks5(): pchRet1: %s\n", pchRet1); + } + if (pchRet1[0] != 0x05 || pchRet1[1] != 0x00) + { + closesocket(hSocket); + return error("Proxy failed to initialize"); + } + string strSocks5("\5\1"); + if (fDebug) + { + printf("Socks5(): strSocks5: %s\n", strSocks5.c_str()); + } + strSocks5 += '\000'; strSocks5 += '\003'; + strSocks5 += static_cast(std::min((int)strDest.size(), 255)); + strSocks5 += strDest; + strSocks5 += static_cast((port >> 8) & 0xFF); + strSocks5 += static_cast((port >> 0) & 0xFF); + ret = send(hSocket, strSocks5.c_str(), strSocks5.size(), MSG_NOSIGNAL); + if (ret != (ssize_t)strSocks5.size()) + { + closesocket(hSocket); + return error("Error sending to proxy"); + } + char pchRet2[4]; + if (recv(hSocket, pchRet2, 4, 0) != 4) + { + closesocket(hSocket); + return error("Error reading proxy response"); + } + if (fDebug) + { + printf("Socks5(): pchRet2: %s\n", pchRet2); + } + if (pchRet2[0] != 0x05) + { + closesocket(hSocket); + return error("Proxy failed to accept request"); + } + if (pchRet2[1] != 0x00) + { + closesocket(hSocket); + switch (pchRet2[1]) + { + case 0x01: return error("Proxy error: general failure"); + case 0x02: return error("Proxy error: connection not allowed"); + case 0x03: return error("Proxy error: network unreachable"); + case 0x04: return error("Proxy error: host unreachable"); + case 0x05: return error("Proxy error: connection refused"); + case 0x06: return error("Proxy error: TTL expired"); + case 0x07: return error("Proxy error: protocol error"); + case 0x08: return error("Proxy error: address type not supported"); + default: return error("Proxy error: unknown"); + } + } + if (pchRet2[2] != 0x00) + { + closesocket(hSocket); + return error("Error: malformed proxy response"); + } + char pchRet3[256]; + switch (pchRet2[3]) + { + case 0x01: ret = recv(hSocket, pchRet3, 4, 0) != 4; break; + case 0x04: ret = recv(hSocket, pchRet3, 16, 0) != 16; break; + case 0x03: + { + ret = recv(hSocket, pchRet3, 1, 0) != 1; + if (ret) + return error("Error reading from proxy"); + int nRecv = pchRet3[0]; + ret = recv(hSocket, pchRet3, nRecv, 0) != nRecv; + break; + } + default: closesocket(hSocket); return error("Error: malformed proxy response"); + } + if (ret) + { + closesocket(hSocket); + return error("Error reading from proxy"); + } + if (recv(hSocket, pchRet3, 2, 0) != 2) + { + closesocket(hSocket); + return error("Error reading from proxy"); + } + printf("SOCKS5 connected %s\n", strDest.c_str()); + return true; +} + +bool static ConnectSocketDirectly(const CService &addrConnect, SOCKET& hSocketRet, int nTimeout) +{ + hSocketRet = INVALID_SOCKET; + +#ifdef USE_IPV6 + struct sockaddr_storage sockaddr; +#else + struct sockaddr sockaddr; +#endif + socklen_t len = sizeof(sockaddr); + if (!addrConnect.GetSockAddr((struct sockaddr*)&sockaddr, &len)) { + printf("Cannot connect to %s: unsupported network\n", addrConnect.ToString().c_str()); + return false; + } + + SOCKET hSocket = socket(((struct sockaddr*)&sockaddr)->sa_family, SOCK_STREAM, IPPROTO_TCP); + if (hSocket == INVALID_SOCKET) + return false; +#ifdef SO_NOSIGPIPE + int set = 1; + setsockopt(hSocket, SOL_SOCKET, SO_NOSIGPIPE, (void*)&set, sizeof(int)); +#endif + +#ifdef WIN32 + u_long fNonblock = 1; + if (ioctlsocket(hSocket, FIONBIO, &fNonblock) == SOCKET_ERROR) +#else + int fFlags = fcntl(hSocket, F_GETFL, 0); + if (fcntl(hSocket, F_SETFL, fFlags | O_NONBLOCK) == -1) +#endif + { + closesocket(hSocket); + return false; + } + + if (connect(hSocket, (struct sockaddr*)&sockaddr, len) == SOCKET_ERROR) + { + // WSAEINVAL is here because some legacy version of winsock uses it + if (WSAGetLastError() == WSAEINPROGRESS || WSAGetLastError() == WSAEWOULDBLOCK || WSAGetLastError() == WSAEINVAL) + { + struct timeval timeout; + timeout.tv_sec = nTimeout / 1000; + timeout.tv_usec = (nTimeout % 1000) * 1000; + + fd_set fdset; + FD_ZERO(&fdset); + FD_SET(hSocket, &fdset); + int nRet = select(hSocket + 1, NULL, &fdset, NULL, &timeout); + if (nRet == 0) + { + printf("connection timeout\n"); + closesocket(hSocket); + return false; + } + if (nRet == SOCKET_ERROR) + { + printf("select() for connection failed: %i\n",WSAGetLastError()); + closesocket(hSocket); + return false; + } + socklen_t nRetSize = sizeof(nRet); +#ifdef WIN32 + if (getsockopt(hSocket, SOL_SOCKET, SO_ERROR, (char*)(&nRet), &nRetSize) == SOCKET_ERROR) +#else + if (getsockopt(hSocket, SOL_SOCKET, SO_ERROR, &nRet, &nRetSize) == SOCKET_ERROR) +#endif + { + printf("getsockopt() for connection failed: %i\n",WSAGetLastError()); + closesocket(hSocket); + return false; + } + if (nRet != 0) + { + printf("connect() failed after select(): %s\n",strerror(nRet)); + closesocket(hSocket); + return false; + } + } +#ifdef WIN32 + else if (WSAGetLastError() != WSAEISCONN) +#else + else +#endif + { + printf("connect() failed: %i\n",WSAGetLastError()); + closesocket(hSocket); + return false; + } + } + + // this isn't even strictly necessary + // CNode::ConnectNode immediately turns the socket back to non-blocking + // but we'll turn it back to blocking just in case +#ifdef WIN32 + fNonblock = 0; + if (ioctlsocket(hSocket, FIONBIO, &fNonblock) == SOCKET_ERROR) +#else + fFlags = fcntl(hSocket, F_GETFL, 0); + if (fcntl(hSocket, F_SETFL, fFlags & ~O_NONBLOCK) == SOCKET_ERROR) +#endif + { + closesocket(hSocket); + return false; + } + + hSocketRet = hSocket; + return true; +} + +bool SetProxy(enum Network net, CService addrProxy, int nSocksVersion) { + printf("SetProxy(): nSocksVersion is %d\n", nSocksVersion); + assert(net >= 0 && net < NET_MAX); + if (nSocksVersion != 0 && nSocksVersion != 4 && nSocksVersion != 5) + return false; + if (nSocksVersion != 0 && !addrProxy.IsValid()) + return false; + LOCK(cs_proxyInfos); + proxyInfo[net] = std::make_pair(addrProxy, nSocksVersion); + return true; +} + +bool GetProxy(enum Network net, proxyType &proxyInfoOut) { + assert(net >= 0 && net < NET_MAX); + LOCK(cs_proxyInfos); + if (!proxyInfo[net].second) + return false; + proxyInfoOut = proxyInfo[net]; + return true; +} + +bool SetNameProxy(CService addrProxy, int nSocksVersion) { + if (nSocksVersion != 0 && nSocksVersion != 5) + return false; + if (nSocksVersion != 0 && !addrProxy.IsValid()) + return false; + LOCK(cs_proxyInfos); + nameproxyInfo = std::make_pair(addrProxy, nSocksVersion); + return true; +} + +bool GetNameProxy(proxyType &nameproxyInfoOut) { + LOCK(cs_proxyInfos); + if (!nameproxyInfo.second) + return false; + nameproxyInfoOut = nameproxyInfo; + return true; +} + +bool HaveNameProxy() { + LOCK(cs_proxyInfos); + return nameproxyInfo.second != 0; +} + +bool IsProxy(const CNetAddr &addr) { + LOCK(cs_proxyInfos); + for (int i = 0; i < NET_MAX; i++) { + if (proxyInfo[i].second && (addr == (CNetAddr)proxyInfo[i].first)) + return true; + } + return false; +} + +bool ConnectSocket(const CService &addrDest, SOCKET& hSocketRet, int nTimeout) +{ + proxyType proxy; + + // no proxy needed + if (!GetProxy(addrDest.GetNetwork(), proxy)) + return ConnectSocketDirectly(addrDest, hSocketRet, nTimeout); + + if (fDebug) + printf("ConnectSocket(): proxy\n"); + + SOCKET hSocket = INVALID_SOCKET; + + // first connect to proxy server + if (!ConnectSocketDirectly(proxy.first, hSocket, nTimeout)) + return false; + + if (fDebug) + printf("ConnectSocket(): connected %s to proxy (%d)\n", + addrDest.ToString().c_str(), proxy.second); + + // do socks negotiation + switch (proxy.second) { + case 4: + if (!Socks4(addrDest, hSocket)) + return false; + if (fDebug) + printf("ConnectSocket(): connected Socks 5\n"); + break; + case 5: + if (!Socks5(addrDest.ToStringIP(), addrDest.GetPort(), hSocket)) + { + if (fDebug) + printf("ConnectSocket(): Socks 5 failed %s\n", + addrDest.ToString().c_str()); + return false; + } + if (fDebug) + printf("ConnectSocket(): connected Socks 5\n"); + break; + default: + if (fDebug) + printf("ConnectSocket(): second is %d\n", proxy.second); + return false; + } + + if (fDebug) + printf("ConnectSocket(): connection succeeded\n"); + + hSocketRet = hSocket; + return true; +} + +bool ConnectSocketByName(CService &addr, SOCKET& hSocketRet, const char *pszDest, int portDefault, int nTimeout) +{ + string strDest; + int port = portDefault; + SplitHostPort(string(pszDest), port, strDest); + + SOCKET hSocket = INVALID_SOCKET; + + proxyType nameproxy; + GetNameProxy(nameproxy); + + CService addrResolved(CNetAddr(strDest, fNameLookup && !nameproxy.second), port); + if (addrResolved.IsValid()) { + addr = addrResolved; + printf("ConnectSocketByName(): address resolved: %s\n", + addr.ToString().c_str()); + return ConnectSocket(addr, hSocketRet, nTimeout); + } + addr = CService("0.0.0.0:0"); + if (!nameproxy.second) + return false; + printf("ConnectSocketByName(): does have second name proxy\n"); + if (!ConnectSocketDirectly(nameproxy.first, hSocket, nTimeout)) + return false; + + printf("ConnectSocketByName(): connected second name proxy\n"); + + switch(nameproxy.second) { + default: + case 4: return false; + case 5: + if (!Socks5(strDest, port, hSocket)) + return false; + printf("ConnectSocketByName(): connected socks 5\n"); + break; + } + + hSocketRet = hSocket; + return true; +} + +void CNetAddr::Init() +{ + memset(ip, 0, sizeof(ip)); +} + +void CNetAddr::SetIP(const CNetAddr& ipIn) +{ + memcpy(ip, ipIn.ip, sizeof(ip)); +} + +static const unsigned char pchOnionCat[] = {0xFD,0x87,0xD8,0x7E,0xEB,0x43}; +static const unsigned char pchGarliCat[] = {0xFD,0x60,0xDB,0x4D,0xDD,0xB5}; + +bool CNetAddr::SetSpecial(const std::string &strName) +{ + if (strName.size()>6 && strName.substr(strName.size() - 6, 6) == ".onion") { + std::vector vchAddr = DecodeBase32(strName.substr(0, strName.size() - 6).c_str()); + if (vchAddr.size() != 16-sizeof(pchOnionCat)) + return false; + memcpy(ip, pchOnionCat, sizeof(pchOnionCat)); + for (unsigned int i=0; i<16-sizeof(pchOnionCat); i++) + ip[i + sizeof(pchOnionCat)] = vchAddr[i]; + return true; + } + if (strName.size()>11 && strName.substr(strName.size() - 11, 11) == ".oc.b32.i2p") { + std::vector vchAddr = DecodeBase32(strName.substr(0, strName.size() - 11).c_str()); + if (vchAddr.size() != 16-sizeof(pchGarliCat)) + return false; + memcpy(ip, pchOnionCat, sizeof(pchGarliCat)); + for (unsigned int i=0; i<16-sizeof(pchGarliCat); i++) + ip[i + sizeof(pchGarliCat)] = vchAddr[i]; + return true; + } + return false; +} + +CNetAddr::CNetAddr() +{ + Init(); +} + +CNetAddr::CNetAddr(const struct in_addr& ipv4Addr) +{ + memcpy(ip, pchIPv4, 12); + memcpy(ip+12, &ipv4Addr, 4); +} + +#ifdef USE_IPV6 +CNetAddr::CNetAddr(const struct in6_addr& ipv6Addr) +{ + memcpy(ip, &ipv6Addr, 16); +} +#endif + +CNetAddr::CNetAddr(const char *pszIp, bool fAllowLookup) +{ + Init(); + std::vector vIP; + if (LookupHost(pszIp, vIP, 1, fAllowLookup)) + *this = vIP[0]; +} + +CNetAddr::CNetAddr(const std::string &strIp, bool fAllowLookup) +{ + Init(); + std::vector vIP; + if (LookupHost(strIp.c_str(), vIP, 1, fAllowLookup)) + *this = vIP[0]; +} + +unsigned int CNetAddr::GetByte(int n) const +{ + return ip[15-n]; +} + +bool CNetAddr::IsIPv4() const +{ + return (memcmp(ip, pchIPv4, sizeof(pchIPv4)) == 0); +} + +bool CNetAddr::IsIPv6() const +{ + return (!IsIPv4() && !IsTor() && !IsI2P()); +} + +bool CNetAddr::IsRFC1918() const +{ + return IsIPv4() && ( + GetByte(3) == 10 || + (GetByte(3) == 192 && GetByte(2) == 168) || + (GetByte(3) == 172 && (GetByte(2) >= 16 && GetByte(2) <= 31))); +} + +bool CNetAddr::IsRFC3927() const +{ + return IsIPv4() && (GetByte(3) == 169 && GetByte(2) == 254); +} + +bool CNetAddr::IsRFC3849() const +{ + return GetByte(15) == 0x20 && GetByte(14) == 0x01 && GetByte(13) == 0x0D && GetByte(12) == 0xB8; +} + +bool CNetAddr::IsRFC3964() const +{ + return (GetByte(15) == 0x20 && GetByte(14) == 0x02); +} + +bool CNetAddr::IsRFC6052() const +{ + static const unsigned char pchRFC6052[] = {0,0x64,0xFF,0x9B,0,0,0,0,0,0,0,0}; + return (memcmp(ip, pchRFC6052, sizeof(pchRFC6052)) == 0); +} + +bool CNetAddr::IsRFC4380() const +{ + return (GetByte(15) == 0x20 && GetByte(14) == 0x01 && GetByte(13) == 0 && GetByte(12) == 0); +} + +bool CNetAddr::IsRFC4862() const +{ + static const unsigned char pchRFC4862[] = {0xFE,0x80,0,0,0,0,0,0}; + return (memcmp(ip, pchRFC4862, sizeof(pchRFC4862)) == 0); +} + +bool CNetAddr::IsRFC4193() const +{ + return ((GetByte(15) & 0xFE) == 0xFC); +} + +bool CNetAddr::IsRFC6145() const +{ + static const unsigned char pchRFC6145[] = {0,0,0,0,0,0,0,0,0xFF,0xFF,0,0}; + return (memcmp(ip, pchRFC6145, sizeof(pchRFC6145)) == 0); +} + +bool CNetAddr::IsRFC4843() const +{ + return (GetByte(15) == 0x20 && GetByte(14) == 0x01 && GetByte(13) == 0x00 && (GetByte(12) & 0xF0) == 0x10); +} + +bool CNetAddr::IsTor() const +{ + return (memcmp(ip, pchOnionCat, sizeof(pchOnionCat)) == 0); +} + +bool CNetAddr::IsI2P() const +{ + return (memcmp(ip, pchGarliCat, sizeof(pchGarliCat)) == 0); +} + +bool CNetAddr::IsLocal() const +{ + // IPv4 loopback + if (IsIPv4() && (GetByte(3) == 127 || GetByte(3) == 0)) + return true; + + // IPv6 loopback (::1/128) + static const unsigned char pchLocal[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}; + if (memcmp(ip, pchLocal, 16) == 0) + return true; + + return false; +} + +bool CNetAddr::IsMulticast() const +{ + return (IsIPv4() && (GetByte(3) & 0xF0) == 0xE0) + || (GetByte(15) == 0xFF); +} + +bool CNetAddr::IsValid() const +{ + // Cleanup 3-byte shifted addresses caused by garbage in size field + // of addr messages from versions before 0.2.9 checksum. + // Two consecutive addr messages look like this: + // header20 vectorlen3 addr26 addr26 addr26 header20 vectorlen3 addr26 addr26 addr26... + // so if the first length field is garbled, it reads the second batch + // of addr misaligned by 3 bytes. + if (memcmp(ip, pchIPv4+3, sizeof(pchIPv4)-3) == 0) + return false; + + // unspecified IPv6 address (::/128) + unsigned char ipNone[16] = {}; + if (memcmp(ip, ipNone, 16) == 0) + return false; + + // documentation IPv6 address + if (IsRFC3849()) + return false; + + if (IsIPv4()) + { + // INADDR_NONE + uint32_t ipNone = INADDR_NONE; + if (memcmp(ip+12, &ipNone, 4) == 0) + return false; + + // 0 + ipNone = 0; + if (memcmp(ip+12, &ipNone, 4) == 0) + return false; + } + + return true; +} + +bool CNetAddr::IsRoutable() const +{ + return IsValid() && !(IsRFC1918() || IsRFC3927() || IsRFC4862() || (IsRFC4193() && !IsTor() && !IsI2P()) || IsRFC4843() || IsLocal()); +} + +enum Network CNetAddr::GetNetwork() const +{ + if (!IsRoutable()) + return NET_UNROUTABLE; + + if (IsIPv4()) + return NET_IPV4; + + if (IsTor()) + return NET_TOR; + + if (IsI2P()) + return NET_I2P; + + return NET_IPV6; +} + +std::string CNetAddr::ToStringIP() const +{ + if (IsTor()) + return EncodeBase32(&ip[6], 10) + ".onion"; + if (IsI2P()) + return EncodeBase32(&ip[6], 10) + ".oc.b32.i2p"; + CService serv(*this, 0); +#ifdef USE_IPV6 + struct sockaddr_storage sockaddr; +#else + struct sockaddr sockaddr; +#endif + socklen_t socklen = sizeof(sockaddr); + if (serv.GetSockAddr((struct sockaddr*)&sockaddr, &socklen)) { + char name[1025] = ""; + if (!getnameinfo((const struct sockaddr*)&sockaddr, socklen, name, sizeof(name), NULL, 0, NI_NUMERICHOST)) + return std::string(name); + } + if (IsIPv4()) + return strprintf("%u.%u.%u.%u", GetByte(3), GetByte(2), GetByte(1), GetByte(0)); + else + return strprintf("%x:%x:%x:%x:%x:%x:%x:%x", + GetByte(15) << 8 | GetByte(14), GetByte(13) << 8 | GetByte(12), + GetByte(11) << 8 | GetByte(10), GetByte(9) << 8 | GetByte(8), + GetByte(7) << 8 | GetByte(6), GetByte(5) << 8 | GetByte(4), + GetByte(3) << 8 | GetByte(2), GetByte(1) << 8 | GetByte(0)); +} + +std::string CNetAddr::ToString() const +{ + return ToStringIP(); +} + +bool operator==(const CNetAddr& a, const CNetAddr& b) +{ + return (memcmp(a.ip, b.ip, 16) == 0); +} + +bool operator!=(const CNetAddr& a, const CNetAddr& b) +{ + return (memcmp(a.ip, b.ip, 16) != 0); +} + +bool operator<(const CNetAddr& a, const CNetAddr& b) +{ + return (memcmp(a.ip, b.ip, 16) < 0); +} + +bool CNetAddr::GetInAddr(struct in_addr* pipv4Addr) const +{ + if (!IsIPv4()) + return false; + memcpy(pipv4Addr, ip+12, 4); + return true; +} + +#ifdef USE_IPV6 +bool CNetAddr::GetIn6Addr(struct in6_addr* pipv6Addr) const +{ + memcpy(pipv6Addr, ip, 16); + return true; +} +#endif + +// get canonical identifier of an address' group +// no two connections will be attempted to addresses with the same group +std::vector CNetAddr::GetGroup() const +{ + std::vector vchRet; + int nClass = NET_IPV6; + int nStartByte = 0; + int nBits = 16; + + // all local addresses belong to the same group + if (IsLocal()) + { + nClass = 255; + nBits = 0; + } + + // all unroutable addresses belong to the same group + if (!IsRoutable()) + { + nClass = NET_UNROUTABLE; + nBits = 0; + } + // for IPv4 addresses, '1' + the 16 higher-order bits of the IP + // includes mapped IPv4, SIIT translated IPv4, and the well-known prefix + else if (IsIPv4() || IsRFC6145() || IsRFC6052()) + { + nClass = NET_IPV4; + nStartByte = 12; + } + // for 6to4 tunnelled addresses, use the encapsulated IPv4 address + else if (IsRFC3964()) + { + nClass = NET_IPV4; + nStartByte = 2; + } + // for Teredo-tunnelled IPv6 addresses, use the encapsulated IPv4 address + else if (IsRFC4380()) + { + vchRet.push_back(NET_IPV4); + vchRet.push_back(GetByte(3) ^ 0xFF); + vchRet.push_back(GetByte(2) ^ 0xFF); + return vchRet; + } + else if (IsTor()) + { + nClass = NET_TOR; + nStartByte = 6; + nBits = 4; + } + else if (IsI2P()) + { + nClass = NET_I2P; + nStartByte = 6; + nBits = 4; + } + // for he.net, use /36 groups + else if (GetByte(15) == 0x20 && GetByte(14) == 0x11 && GetByte(13) == 0x04 && GetByte(12) == 0x70) + nBits = 36; + // for the rest of the IPv6 network, use /32 groups + else + nBits = 32; + + vchRet.push_back(nClass); + while (nBits >= 8) + { + vchRet.push_back(GetByte(15 - nStartByte)); + nStartByte++; + nBits -= 8; + } + if (nBits > 0) + vchRet.push_back(GetByte(15 - nStartByte) | ((1 << nBits) - 1)); + + return vchRet; +} + +uint64 CNetAddr::GetHash() const +{ + uint256 hash = Hash(&ip[0], &ip[16]); + uint64 nRet; + memcpy(&nRet, &hash, sizeof(nRet)); + return nRet; +} + +void CNetAddr::print() const +{ + printf("CNetAddr(%s)\n", ToString().c_str()); +} + +// private extensions to enum Network, only returned by GetExtNetwork, +// and only used in GetReachabilityFrom +static const int NET_UNKNOWN = NET_MAX + 0; +static const int NET_TEREDO = NET_MAX + 1; +int static GetExtNetwork(const CNetAddr *addr) +{ + if (addr == NULL) + return NET_UNKNOWN; + if (addr->IsRFC4380()) + return NET_TEREDO; + return addr->GetNetwork(); +} + +/** Calculates a metric for how reachable (*this) is from a given partner */ +int CNetAddr::GetReachabilityFrom(const CNetAddr *paddrPartner) const +{ + enum Reachability { + REACH_UNREACHABLE, + REACH_DEFAULT, + REACH_TEREDO, + REACH_IPV6_WEAK, + REACH_IPV4, + REACH_IPV6_STRONG, + REACH_PRIVATE + }; + + if (!IsRoutable()) + return REACH_UNREACHABLE; + + int ourNet = GetExtNetwork(this); + int theirNet = GetExtNetwork(paddrPartner); + bool fTunnel = IsRFC3964() || IsRFC6052() || IsRFC6145(); + + switch(theirNet) { + case NET_IPV4: + switch(ourNet) { + default: return REACH_DEFAULT; + case NET_IPV4: return REACH_IPV4; + } + case NET_IPV6: + switch(ourNet) { + default: return REACH_DEFAULT; + case NET_TEREDO: return REACH_TEREDO; + case NET_IPV4: return REACH_IPV4; + case NET_IPV6: return fTunnel ? REACH_IPV6_WEAK : REACH_IPV6_STRONG; // only prefer giving our IPv6 address if it's not tunnelled + } + case NET_TOR: + switch(ourNet) { + default: return REACH_DEFAULT; + case NET_IPV4: return REACH_IPV4; // Tor users can connect to IPv4 as well + case NET_TOR: return REACH_PRIVATE; + } + case NET_I2P: + switch(ourNet) { + default: return REACH_DEFAULT; + case NET_I2P: return REACH_PRIVATE; + } + case NET_TEREDO: + switch(ourNet) { + default: return REACH_DEFAULT; + case NET_TEREDO: return REACH_TEREDO; + case NET_IPV6: return REACH_IPV6_WEAK; + case NET_IPV4: return REACH_IPV4; + } + case NET_UNKNOWN: + case NET_UNROUTABLE: + default: + switch(ourNet) { + default: return REACH_DEFAULT; + case NET_TEREDO: return REACH_TEREDO; + case NET_IPV6: return REACH_IPV6_WEAK; + case NET_IPV4: return REACH_IPV4; + case NET_I2P: return REACH_PRIVATE; // assume connections from unroutable addresses are + case NET_TOR: return REACH_PRIVATE; // either from Tor/I2P, or don't care about our address + } + } +} + +void CService::Init() +{ + port = 0; +} + +CService::CService() +{ + Init(); +} + +CService::CService(const CNetAddr& cip, unsigned short portIn) : CNetAddr(cip), port(portIn) +{ +} + +CService::CService(const struct in_addr& ipv4Addr, unsigned short portIn) : CNetAddr(ipv4Addr), port(portIn) +{ +} + +#ifdef USE_IPV6 +CService::CService(const struct in6_addr& ipv6Addr, unsigned short portIn) : CNetAddr(ipv6Addr), port(portIn) +{ +} +#endif + +CService::CService(const struct sockaddr_in& addr) : CNetAddr(addr.sin_addr), port(ntohs(addr.sin_port)) +{ + assert(addr.sin_family == AF_INET); +} + +#ifdef USE_IPV6 +CService::CService(const struct sockaddr_in6 &addr) : CNetAddr(addr.sin6_addr), port(ntohs(addr.sin6_port)) +{ + assert(addr.sin6_family == AF_INET6); +} +#endif + +bool CService::SetSockAddr(const struct sockaddr *paddr) +{ + switch (paddr->sa_family) { + case AF_INET: + *this = CService(*(const struct sockaddr_in*)paddr); + return true; +#ifdef USE_IPV6 + case AF_INET6: + *this = CService(*(const struct sockaddr_in6*)paddr); + return true; +#endif + default: + return false; + } +} + +CService::CService(const char *pszIpPort, bool fAllowLookup) +{ + Init(); + CService ip; + if (Lookup(pszIpPort, ip, 0, fAllowLookup)) + *this = ip; +} + +CService::CService(const char *pszIpPort, int portDefault, bool fAllowLookup) +{ + Init(); + CService ip; + if (Lookup(pszIpPort, ip, portDefault, fAllowLookup)) + *this = ip; +} + +CService::CService(const std::string &strIpPort, bool fAllowLookup) +{ + Init(); + CService ip; + if (Lookup(strIpPort.c_str(), ip, 0, fAllowLookup)) + *this = ip; +} + +CService::CService(const std::string &strIpPort, int portDefault, bool fAllowLookup) +{ + Init(); + CService ip; + if (Lookup(strIpPort.c_str(), ip, portDefault, fAllowLookup)) + *this = ip; +} + +unsigned short CService::GetPort() const +{ + return port; +} + +bool operator==(const CService& a, const CService& b) +{ + return (CNetAddr)a == (CNetAddr)b && a.port == b.port; +} + +bool operator!=(const CService& a, const CService& b) +{ + return (CNetAddr)a != (CNetAddr)b || a.port != b.port; +} + +bool operator<(const CService& a, const CService& b) +{ + return (CNetAddr)a < (CNetAddr)b || ((CNetAddr)a == (CNetAddr)b && a.port < b.port); +} + +bool CService::GetSockAddr(struct sockaddr* paddr, socklen_t *addrlen) const +{ + if (IsIPv4()) { + if (*addrlen < (socklen_t)sizeof(struct sockaddr_in)) + return false; + *addrlen = sizeof(struct sockaddr_in); + struct sockaddr_in *paddrin = (struct sockaddr_in*)paddr; + memset(paddrin, 0, *addrlen); + if (!GetInAddr(&paddrin->sin_addr)) + return false; + paddrin->sin_family = AF_INET; + paddrin->sin_port = htons(port); + return true; + } +#ifdef USE_IPV6 + if (IsIPv6()) { + if (*addrlen < (socklen_t)sizeof(struct sockaddr_in6)) + return false; + *addrlen = sizeof(struct sockaddr_in6); + struct sockaddr_in6 *paddrin6 = (struct sockaddr_in6*)paddr; + memset(paddrin6, 0, *addrlen); + if (!GetIn6Addr(&paddrin6->sin6_addr)) + return false; + paddrin6->sin6_family = AF_INET6; + paddrin6->sin6_port = htons(port); + return true; + } +#endif + return false; +} + +std::vector CService::GetKey() const +{ + std::vector vKey; + vKey.resize(18); + memcpy(&vKey[0], ip, 16); + vKey[16] = port / 0x100; + vKey[17] = port & 0x0FF; + return vKey; +} + +std::string CService::ToStringPort() const +{ + return strprintf("%u", port); +} + +std::string CService::ToStringIPPort() const +{ + if (IsIPv4() || IsTor() || IsI2P()) { + return ToStringIP() + ":" + ToStringPort(); + } else { + return "[" + ToStringIP() + "]:" + ToStringPort(); + } +} + +std::string CService::ToString() const +{ + return ToStringIPPort(); +} + +void CService::print() const +{ + printf("CService(%s)\n", ToString().c_str()); +} + +void CService::SetPort(unsigned short portIn) +{ + port = portIn; +} diff --git a/src/netbase.h b/src/netbase.h new file mode 100644 index 0000000..0a29d4f --- /dev/null +++ b/src/netbase.h @@ -0,0 +1,153 @@ +// Copyright (c) 2009-2012 The Bitcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. +#ifndef BITCOIN_NETBASE_H +#define BITCOIN_NETBASE_H + +#include +#include + +#include "serialize.h" +#include "compat.h" + +extern int nConnectTimeout; + +#ifdef WIN32 +// In MSVC, this is defined as a macro, undefine it to prevent a compile and link error +#undef SetPort +#endif + +enum Network +{ + NET_UNROUTABLE, + NET_IPV4, + NET_IPV6, + NET_TOR, + NET_I2P, + + NET_MAX, +}; + +extern int nConnectTimeout; +extern bool fNameLookup; + +/** IP address (IPv6, or IPv4 using mapped IPv6 range (::FFFF:0:0/96)) */ +class CNetAddr +{ + protected: + unsigned char ip[16]; // in network byte order + + public: + CNetAddr(); + CNetAddr(const struct in_addr& ipv4Addr); + explicit CNetAddr(const char *pszIp, bool fAllowLookup = false); + explicit CNetAddr(const std::string &strIp, bool fAllowLookup = false); + void Init(); + void SetIP(const CNetAddr& ip); + bool SetSpecial(const std::string &strName); // for Tor and I2P addresses + bool IsIPv4() const; // IPv4 mapped address (::FFFF:0:0/96, 0.0.0.0/0) + bool IsIPv6() const; // IPv6 address (not mapped IPv4, not Tor/I2P) + bool IsRFC1918() const; // IPv4 private networks (10.0.0.0/8, 192.168.0.0/16, 172.16.0.0/12) + bool IsRFC3849() const; // IPv6 documentation address (2001:0DB8::/32) + bool IsRFC3927() const; // IPv4 autoconfig (169.254.0.0/16) + bool IsRFC3964() const; // IPv6 6to4 tunnelling (2002::/16) + bool IsRFC4193() const; // IPv6 unique local (FC00::/15) + bool IsRFC4380() const; // IPv6 Teredo tunnelling (2001::/32) + bool IsRFC4843() const; // IPv6 ORCHID (2001:10::/28) + bool IsRFC4862() const; // IPv6 autoconfig (FE80::/64) + bool IsRFC6052() const; // IPv6 well-known prefix (64:FF9B::/96) + bool IsRFC6145() const; // IPv6 IPv4-translated address (::FFFF:0:0:0/96) + bool IsTor() const; + bool IsI2P() const; + bool IsLocal() const; + bool IsRoutable() const; + bool IsValid() const; + bool IsMulticast() const; + enum Network GetNetwork() const; + std::string ToString() const; + std::string ToStringIP() const; + unsigned int GetByte(int n) const; + uint64 GetHash() const; + bool GetInAddr(struct in_addr* pipv4Addr) const; + std::vector GetGroup() const; + int GetReachabilityFrom(const CNetAddr *paddrPartner = NULL) const; + void print() const; + +#ifdef USE_IPV6 + CNetAddr(const struct in6_addr& pipv6Addr); + bool GetIn6Addr(struct in6_addr* pipv6Addr) const; +#endif + + friend bool operator==(const CNetAddr& a, const CNetAddr& b); + friend bool operator!=(const CNetAddr& a, const CNetAddr& b); + friend bool operator<(const CNetAddr& a, const CNetAddr& b); + + IMPLEMENT_SERIALIZE + ( + READWRITE(FLATDATA(ip)); + ) +}; + +/** A combination of a network address (CNetAddr) and a (TCP) port */ +class CService : public CNetAddr +{ + protected: + unsigned short port; // host order + + public: + CService(); + CService(const CNetAddr& ip, unsigned short port); + CService(const struct in_addr& ipv4Addr, unsigned short port); + CService(const struct sockaddr_in& addr); + explicit CService(const char *pszIpPort, int portDefault, bool fAllowLookup = false); + explicit CService(const char *pszIpPort, bool fAllowLookup = false); + explicit CService(const std::string& strIpPort, int portDefault, bool fAllowLookup = false); + explicit CService(const std::string& strIpPort, bool fAllowLookup = false); + void Init(); + void SetPort(unsigned short portIn); + unsigned short GetPort() const; + bool GetSockAddr(struct sockaddr* paddr, socklen_t *addrlen) const; + bool SetSockAddr(const struct sockaddr* paddr); + friend bool operator==(const CService& a, const CService& b); + friend bool operator!=(const CService& a, const CService& b); + friend bool operator<(const CService& a, const CService& b); + std::vector GetKey() const; + std::string ToString() const; + std::string ToStringPort() const; + std::string ToStringIPPort() const; + void print() const; + +#ifdef USE_IPV6 + CService(const struct in6_addr& ipv6Addr, unsigned short port); + CService(const struct sockaddr_in6& addr); +#endif + + IMPLEMENT_SERIALIZE + ( + CService* pthis = const_cast(this); + READWRITE(FLATDATA(ip)); + unsigned short portN = htons(port); + READWRITE(portN); + if (fRead) + pthis->port = ntohs(portN); + ) +}; + +typedef std::pair proxyType; + +enum Network ParseNetwork(std::string net); +void SplitHostPort(std::string in, int &portOut, std::string &hostOut); +bool SetProxy(enum Network net, CService addrProxy, int nSocksVersion = 5); +bool GetProxy(enum Network net, proxyType &proxyInfoOut); +bool IsProxy(const CNetAddr &addr); +bool SetNameProxy(CService addrProxy, int nSocksVersion = 5); +bool HaveNameProxy(); +bool LookupHost(const char *pszName, std::vector& vIP, unsigned int nMaxSolutions = 0, bool fAllowLookup = true); +bool LookupHostNumeric(const char *pszName, std::vector& vIP, unsigned int nMaxSolutions = 0); +bool Lookup(const char *pszName, CService& addr, int portDefault = 0, bool fAllowLookup = true); +bool Lookup(const char *pszName, std::vector& vAddr, int portDefault = 0, bool fAllowLookup = true, unsigned int nMaxSolutions = 0); +bool LookupNumeric(const char *pszName, CService& addr, int portDefault = 0); +bool ConnectSocket(const CService &addr, SOCKET& hSocketRet, int nTimeout = nConnectTimeout); +bool ConnectSocketByName(CService &addr, SOCKET& hSocketRet, const char *pszDest, int portDefault = 0, int nTimeout = nConnectTimeout); + +#endif diff --git a/src/noui.cpp b/src/noui.cpp new file mode 100644 index 0000000..db25f2d --- /dev/null +++ b/src/noui.cpp @@ -0,0 +1,28 @@ +// Copyright (c) 2010 Satoshi Nakamoto +// Copyright (c) 2009-2012 The Bitcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include "ui_interface.h" +#include "init.h" +#include "bitcoinrpc.h" + +#include + +static int noui_ThreadSafeMessageBox(const std::string& message, const std::string& caption, int style) +{ + printf("%s: %s\n", caption.c_str(), message.c_str()); + fprintf(stderr, "%s: %s\n", caption.c_str(), message.c_str()); + return 4; +} + +static bool noui_ThreadSafeAskFee(int64 nFeeRequired, const std::string& strCaption) +{ + return true; +} + +void noui_connect() +{ + // Connect bitcoind signal handlers + uiInterface.ThreadSafeMessageBox.connect(noui_ThreadSafeMessageBox); + uiInterface.ThreadSafeAskFee.connect(noui_ThreadSafeAskFee); +} diff --git a/src/onionseed.h b/src/onionseed.h new file mode 100644 index 0000000..ab13b55 --- /dev/null +++ b/src/onionseed.h @@ -0,0 +1,18 @@ + +#ifndef AR_ONIONSEED_H +#define AR_ONIONSEED_H + +// hidden service seeds +static const char *strMainNetOnionSeed[][1] = { + {"4mmbxrdk5xorxq4s.onion"}, + {"fzwpi2uqgauy225m.onion"}, + {NULL} +}; + +static const char *strTestNetOnionSeed[][1] = { + {"4mmbxrdk5xorxq4s.onion"}, + {"fzwpi2uqgauy225m.onion"}, + {NULL} +}; + +#endif diff --git a/src/pbkdf2.cpp b/src/pbkdf2.cpp new file mode 100644 index 0000000..b98e4e8 --- /dev/null +++ b/src/pbkdf2.cpp @@ -0,0 +1,148 @@ + + +#include +#include "pbkdf2.h" + +static inline uint32_t +be32dec(const void *pp) +{ + const uint8_t *p = (uint8_t const *)pp; + + return ((uint32_t)(p[3]) + ((uint32_t)(p[2]) << 8) + + ((uint32_t)(p[1]) << 16) + ((uint32_t)(p[0]) << 24)); +} + +static inline void +be32enc(void *pp, uint32_t x) +{ + uint8_t * p = (uint8_t *)pp; + + p[3] = x & 0xff; + p[2] = (x >> 8) & 0xff; + p[1] = (x >> 16) & 0xff; + p[0] = (x >> 24) & 0xff; +} + + + +/* Initialize an HMAC-SHA256 operation with the given key. */ +void +HMAC_SHA256_Init(HMAC_SHA256_CTX * ctx, const void * _K, size_t Klen) +{ + unsigned char pad[64]; + unsigned char khash[32]; + const unsigned char * K = (const unsigned char *)_K; + size_t i; + + /* If Klen > 64, the key is really SHA256(K). */ + if (Klen > 64) { + SHA256_Init(&ctx->ictx); + SHA256_Update(&ctx->ictx, K, Klen); + SHA256_Final(khash, &ctx->ictx); + K = khash; + Klen = 32; + } + + /* Inner SHA256 operation is SHA256(K xor [block of 0x36] || data). */ + SHA256_Init(&ctx->ictx); + memset(pad, 0x36, 64); + for (i = 0; i < Klen; i++) + pad[i] ^= K[i]; + SHA256_Update(&ctx->ictx, pad, 64); + + /* Outer SHA256 operation is SHA256(K xor [block of 0x5c] || hash). */ + SHA256_Init(&ctx->octx); + memset(pad, 0x5c, 64); + for (i = 0; i < Klen; i++) + pad[i] ^= K[i]; + SHA256_Update(&ctx->octx, pad, 64); + + /* Clean the stack. */ + memset(khash, 0, 32); +} + +/* Add bytes to the HMAC-SHA256 operation. */ +void +HMAC_SHA256_Update(HMAC_SHA256_CTX * ctx, const void *in, size_t len) +{ + + /* Feed data to the inner SHA256 operation. */ + SHA256_Update(&ctx->ictx, in, len); +} + +/* Finish an HMAC-SHA256 operation. */ +void +HMAC_SHA256_Final(unsigned char digest[32], HMAC_SHA256_CTX * ctx) +{ + unsigned char ihash[32]; + + /* Finish the inner SHA256 operation. */ + SHA256_Final(ihash, &ctx->ictx); + + /* Feed the inner hash to the outer SHA256 operation. */ + SHA256_Update(&ctx->octx, ihash, 32); + + /* Finish the outer SHA256 operation. */ + SHA256_Final(digest, &ctx->octx); + + /* Clean the stack. */ + memset(ihash, 0, 32); +} + +/** + * PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, c, buf, dkLen): + * Compute PBKDF2(passwd, salt, c, dkLen) using HMAC-SHA256 as the PRF, and + * write the output to buf. The value dkLen must be at most 32 * (2^32 - 1). + */ +void +PBKDF2_SHA256(const uint8_t * passwd, size_t passwdlen, const uint8_t * salt, + size_t saltlen, uint64_t c, uint8_t * buf, size_t dkLen) +{ + HMAC_SHA256_CTX PShctx, hctx; + size_t i; + uint8_t ivec[4]; + uint8_t U[32]; + uint8_t T[32]; + uint64_t j; + int k; + size_t clen; + + /* Compute HMAC state after processing P and S. */ + HMAC_SHA256_Init(&PShctx, passwd, passwdlen); + HMAC_SHA256_Update(&PShctx, salt, saltlen); + + /* Iterate through the blocks. */ + for (i = 0; i * 32 < dkLen; i++) { + /* Generate INT(i + 1). */ + be32enc(ivec, (uint32_t)(i + 1)); + + /* Compute U_1 = PRF(P, S || INT(i)). */ + memcpy(&hctx, &PShctx, sizeof(HMAC_SHA256_CTX)); + HMAC_SHA256_Update(&hctx, ivec, 4); + HMAC_SHA256_Final(U, &hctx); + + /* T_i = U_1 ... */ + memcpy(T, U, 32); + + for (j = 2; j <= c; j++) { + /* Compute U_j. */ + HMAC_SHA256_Init(&hctx, passwd, passwdlen); + HMAC_SHA256_Update(&hctx, U, 32); + HMAC_SHA256_Final(U, &hctx); + + /* ... xor U_j ... */ + for (k = 0; k < 32; k++) + T[k] ^= U[k]; + } + + /* Copy as many bytes as necessary into buf. */ + clen = dkLen - i * 32; + if (clen > 32) + clen = 32; + memcpy(&buf[i * 32], T, clen); + } + + /* Clean PShctx, since we never called _Final on it. */ + memset(&PShctx, 0, sizeof(HMAC_SHA256_CTX)); +} + diff --git a/src/pbkdf2.h b/src/pbkdf2.h new file mode 100644 index 0000000..88a6a25 --- /dev/null +++ b/src/pbkdf2.h @@ -0,0 +1,27 @@ + + +#ifndef PBKDF2_H +#define PBKDF2_H + +#include +#include + +typedef struct HMAC_SHA256Context { + SHA256_CTX ictx; + SHA256_CTX octx; +} HMAC_SHA256_CTX; + +void +HMAC_SHA256_Init(HMAC_SHA256_CTX * ctx, const void * _K, size_t Klen); + +void +HMAC_SHA256_Update(HMAC_SHA256_CTX * ctx, const void *in, size_t len); + +void +HMAC_SHA256_Final(unsigned char digest[32], HMAC_SHA256_CTX * ctx); + +void +PBKDF2_SHA256(const uint8_t * passwd, size_t passwdlen, const uint8_t * salt, + size_t saltlen, uint64_t c, uint8_t * buf, size_t dkLen); + +#endif // PBKDF2_H diff --git a/src/protocol.cpp b/src/protocol.cpp new file mode 100644 index 0000000..d6e340e --- /dev/null +++ b/src/protocol.cpp @@ -0,0 +1,150 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2012 The Bitcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "protocol.h" +#include "util.h" +#include "netbase.h" + +#ifndef WIN32 +# include +#endif + +static const char* ppszTypeName[] = +{ + "ERROR", + "tx", + "block", +}; + +CMessageHeader::CMessageHeader() +{ + memcpy(pchMessageStart, ::pchMessageStart, sizeof(pchMessageStart)); + memset(pchCommand, 0, sizeof(pchCommand)); + pchCommand[1] = 1; + nMessageSize = -1; + nChecksum = 0; +} + +CMessageHeader::CMessageHeader(const char* pszCommand, unsigned int nMessageSizeIn) +{ + memcpy(pchMessageStart, ::pchMessageStart, sizeof(pchMessageStart)); + strncpy(pchCommand, pszCommand, COMMAND_SIZE); + nMessageSize = nMessageSizeIn; + nChecksum = 0; +} + +std::string CMessageHeader::GetCommand() const +{ + if (pchCommand[COMMAND_SIZE-1] == 0) + return std::string(pchCommand, pchCommand + strlen(pchCommand)); + else + return std::string(pchCommand, pchCommand + COMMAND_SIZE); +} + +bool CMessageHeader::IsValid() const +{ + // Check start string + if (memcmp(pchMessageStart, ::pchMessageStart, sizeof(pchMessageStart)) != 0) + return false; + + // Check the command string for errors + for (const char* p1 = pchCommand; p1 < pchCommand + COMMAND_SIZE; p1++) + { + if (*p1 == 0) + { + // Must be all zeros after the first zero + for (; p1 < pchCommand + COMMAND_SIZE; p1++) + if (*p1 != 0) + return false; + } + else if (*p1 < ' ' || *p1 > 0x7E) + return false; + } + + // Message size + if (nMessageSize > MAX_SIZE) + { + printf("CMessageHeader::IsValid() : (%s, %u bytes) nMessageSize > MAX_SIZE\n", GetCommand().c_str(), nMessageSize); + return false; + } + + return true; +} + + + +CAddress::CAddress() : CService() +{ + Init(); +} + +CAddress::CAddress(CService ipIn, uint64 nServicesIn) : CService(ipIn) +{ + Init(); + nServices = nServicesIn; +} + +void CAddress::Init() +{ + nServices = NODE_NETWORK; + nTime = 100000000; + nLastTry = 0; +} + +CInv::CInv() +{ + type = 0; + hash = 0; +} + +CInv::CInv(int typeIn, const uint256& hashIn) +{ + type = typeIn; + hash = hashIn; +} + +CInv::CInv(const std::string& strType, const uint256& hashIn) +{ + unsigned int i; + for (i = 1; i < ARRAYLEN(ppszTypeName); i++) + { + if (strType == ppszTypeName[i]) + { + type = i; + break; + } + } + if (i == ARRAYLEN(ppszTypeName)) + throw std::out_of_range(strprintf("CInv::CInv(string, uint256) : unknown type '%s'", strType.c_str())); + hash = hashIn; +} + +bool operator<(const CInv& a, const CInv& b) +{ + return (a.type < b.type || (a.type == b.type && a.hash < b.hash)); +} + +bool CInv::IsKnownType() const +{ + return (type >= 1 && type < (int)ARRAYLEN(ppszTypeName)); +} + +const char* CInv::GetCommand() const +{ + if (!IsKnownType()) + throw std::out_of_range(strprintf("CInv::GetCommand() : type=%d unknown type", type)); + return ppszTypeName[type]; +} + +std::string CInv::ToString() const +{ + return strprintf("%s %s", GetCommand(), hash.ToString().substr(0,20).c_str()); +} + +void CInv::print() const +{ + printf("CInv(%s)\n", ToString().c_str()); +} + diff --git a/src/protocol.h b/src/protocol.h new file mode 100644 index 0000000..58bd83d --- /dev/null +++ b/src/protocol.h @@ -0,0 +1,137 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2012 The Bitcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef __cplusplus +# error This header can only be compiled as C++. +#endif + +#ifndef __INCLUDED_PROTOCOL_H__ +#define __INCLUDED_PROTOCOL_H__ + +#include "serialize.h" +#include "netbase.h" +#include +#include "uint256.h" + +extern bool fTestNet; +static inline unsigned short GetDefaultPort(const bool testnet = fTestNet) +{ + return testnet ? 24111 : 24112; +} + + +extern unsigned char pchMessageStart[4]; + +/** Message header. + * (4) message start. + * (12) command. + * (4) size. + * (4) checksum. + */ +class CMessageHeader +{ + public: + CMessageHeader(); + CMessageHeader(const char* pszCommand, unsigned int nMessageSizeIn); + + std::string GetCommand() const; + bool IsValid() const; + + IMPLEMENT_SERIALIZE + ( + READWRITE(FLATDATA(pchMessageStart)); + READWRITE(FLATDATA(pchCommand)); + READWRITE(nMessageSize); + READWRITE(nChecksum); + ) + + // TODO: make private (improves encapsulation) + public: + enum { + MESSAGE_START_SIZE=sizeof(::pchMessageStart), + COMMAND_SIZE=12, + MESSAGE_SIZE_SIZE=sizeof(int), + CHECKSUM_SIZE=sizeof(int), + + MESSAGE_SIZE_OFFSET=MESSAGE_START_SIZE+COMMAND_SIZE, + CHECKSUM_OFFSET=MESSAGE_SIZE_OFFSET+MESSAGE_SIZE_SIZE + }; + char pchMessageStart[MESSAGE_START_SIZE]; + char pchCommand[COMMAND_SIZE]; + unsigned int nMessageSize; + unsigned int nChecksum; +}; + +/** nServices flags */ +enum +{ + NODE_NETWORK = (1 << 0), +}; + +/** A CService with information about it as peer */ +class CAddress : public CService +{ + public: + CAddress(); + explicit CAddress(CService ipIn, uint64 nServicesIn=NODE_NETWORK); + + void Init(); + + IMPLEMENT_SERIALIZE + ( + CAddress* pthis = const_cast(this); + CService* pip = (CService*)pthis; + if (fRead) + pthis->Init(); + if (nType & SER_DISK) + READWRITE(nVersion); + if ((nType & SER_DISK) || + (nVersion >= CADDR_TIME_VERSION && !(nType & SER_GETHASH))) + READWRITE(nTime); + READWRITE(nServices); + READWRITE(*pip); + ) + + void print() const; + + // TODO: make private (improves encapsulation) + public: + uint64 nServices; + + // disk and network only + unsigned int nTime; + + // memory only + int64 nLastTry; +}; + +/** inv message data */ +class CInv +{ + public: + CInv(); + CInv(int typeIn, const uint256& hashIn); + CInv(const std::string& strType, const uint256& hashIn); + + IMPLEMENT_SERIALIZE + ( + READWRITE(type); + READWRITE(hash); + ) + + friend bool operator<(const CInv& a, const CInv& b); + + bool IsKnownType() const; + const char* GetCommand() const; + std::string ToString() const; + void print() const; + + // TODO: make private (improves encapsulation) + public: + int type; + uint256 hash; +}; + +#endif // __INCLUDED_PROTOCOL_H__ diff --git a/src/qt/aboutdialog.cpp b/src/qt/aboutdialog.cpp new file mode 100644 index 0000000..14ff9e9 --- /dev/null +++ b/src/qt/aboutdialog.cpp @@ -0,0 +1,31 @@ +#include "aboutdialog.h" +#include "ui_aboutdialog.h" +#include "clientmodel.h" + +#include "version.h" + +AboutDialog::AboutDialog(QWidget *parent) : + QDialog(parent), + ui(new Ui::AboutDialog) +{ + ui->setupUi(this); + // this->setStyleSheet("background-color: #effbef;"); +} + +void AboutDialog::setModel(ClientModel *model) +{ + if(model) + { + ui->versionLabel->setText(model->formatFullVersion()); + } +} + +AboutDialog::~AboutDialog() +{ + delete ui; +} + +void AboutDialog::on_buttonBox_accepted() +{ + close(); +} diff --git a/src/qt/aboutdialog.h b/src/qt/aboutdialog.h new file mode 100644 index 0000000..2ed9e9e --- /dev/null +++ b/src/qt/aboutdialog.h @@ -0,0 +1,28 @@ +#ifndef ABOUTDIALOG_H +#define ABOUTDIALOG_H + +#include + +namespace Ui { + class AboutDialog; +} +class ClientModel; + +/** "About" dialog box */ +class AboutDialog : public QDialog +{ + Q_OBJECT + +public: + explicit AboutDialog(QWidget *parent = 0); + ~AboutDialog(); + + void setModel(ClientModel *model); +private: + Ui::AboutDialog *ui; + +private slots: + void on_buttonBox_accepted(); +}; + +#endif // ABOUTDIALOG_H diff --git a/src/qt/addressbookpage.cpp b/src/qt/addressbookpage.cpp new file mode 100644 index 0000000..e20358c --- /dev/null +++ b/src/qt/addressbookpage.cpp @@ -0,0 +1,374 @@ +#include "addressbookpage.h" +#include "ui_addressbookpage.h" + +#include "addresstablemodel.h" +#include "optionsmodel.h" +#include "bitcoingui.h" +#include "editaddressdialog.h" +#include "csvmodelwriter.h" +#include "guiutil.h" + +#include +#include +#include +#include + +#ifdef USE_QRCODE +#include "qrcodedialog.h" +#endif + +AddressBookPage::AddressBookPage(Mode mode, Tabs tab, QWidget *parent) : + QDialog(parent), + ui(new Ui::AddressBookPage), + model(0), + optionsModel(0), + mode(mode), + tab(tab) +{ + ui->setupUi(this); + +#ifdef Q_OS_MAC // Icons on push buttons are very uncommon on Mac + ui->newAddressButton->setIcon(QIcon()); + ui->copyToClipboard->setIcon(QIcon()); + ui->deleteButton->setIcon(QIcon()); +#endif + +#ifndef USE_QRCODE + ui->showQRCode->setVisible(false); +#endif + + switch(mode) + { + case ForSending: + connect(ui->tableView, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(accept())); + ui->tableView->setEditTriggers(QAbstractItemView::NoEditTriggers); + ui->tableView->setFocus(); + break; + case ForEditing: + ui->buttonBox->setVisible(false); + break; + } + switch(tab) + { + case SendingTab: + ui->labelExplanation->setVisible(false); + ui->deleteButton->setVisible(true); + ui->signMessage->setVisible(false); + break; + case ReceivingTab: + ui->deleteButton->setVisible(false); + ui->signMessage->setVisible(true); + break; + } + + // Context menu actions + QAction *copyLabelAction = new QAction(tr("Copy &Label"), this); + QAction *copyAddressAction = new QAction(ui->copyToClipboard->text(), this); + QAction *editAction = new QAction(tr("&Edit"), this); + QAction *showQRCodeAction = new QAction(ui->showQRCode->text(), this); + QAction *signMessageAction = new QAction(ui->signMessage->text(), this); + QAction *verifyMessageAction = new QAction(ui->verifyMessage->text(), this); + deleteAction = new QAction(ui->deleteButton->text(), this); + + // Build context menu + contextMenu = new QMenu(); + contextMenu->addAction(copyAddressAction); + contextMenu->addAction(copyLabelAction); + contextMenu->addAction(editAction); + if(tab == SendingTab) + contextMenu->addAction(deleteAction); + contextMenu->addSeparator(); + contextMenu->addAction(showQRCodeAction); + if(tab == ReceivingTab) + contextMenu->addAction(signMessageAction); + else if(tab == SendingTab) + contextMenu->addAction(verifyMessageAction); + + // Connect signals for context menu actions + connect(copyAddressAction, SIGNAL(triggered()), this, SLOT(on_copyToClipboard_clicked())); + connect(copyLabelAction, SIGNAL(triggered()), this, SLOT(onCopyLabelAction())); + connect(editAction, SIGNAL(triggered()), this, SLOT(onEditAction())); + connect(deleteAction, SIGNAL(triggered()), this, SLOT(on_deleteButton_clicked())); + connect(showQRCodeAction, SIGNAL(triggered()), this, SLOT(on_showQRCode_clicked())); + connect(signMessageAction, SIGNAL(triggered()), this, SLOT(on_signMessage_clicked())); + connect(verifyMessageAction, SIGNAL(triggered()), this, SLOT(on_verifyMessage_clicked())); + + connect(ui->tableView, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(contextualMenu(QPoint))); + + // Pass through accept action from button box + connect(ui->buttonBox, SIGNAL(accepted()), this, SLOT(accept())); +} + +AddressBookPage::~AddressBookPage() +{ + delete ui; +} + +void AddressBookPage::setModel(AddressTableModel *model) +{ + this->model = model; + if(!model) + return; + + proxyModel = new QSortFilterProxyModel(this); + proxyModel->setSourceModel(model); + proxyModel->setDynamicSortFilter(true); + proxyModel->setSortCaseSensitivity(Qt::CaseInsensitive); + proxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive); + switch(tab) + { + case ReceivingTab: + // Receive filter + proxyModel->setFilterRole(AddressTableModel::TypeRole); + proxyModel->setFilterFixedString(AddressTableModel::Receive); + break; + case SendingTab: + // Send filter + proxyModel->setFilterRole(AddressTableModel::TypeRole); + proxyModel->setFilterFixedString(AddressTableModel::Send); + break; + } + ui->tableView->setModel(proxyModel); + ui->tableView->sortByColumn(0, Qt::AscendingOrder); + + // Set column widths + ui->tableView->horizontalHeader()->resizeSection( + AddressTableModel::Address, 320); + ui->tableView->horizontalHeader()->setResizeMode( + AddressTableModel::Label, QHeaderView::Stretch); + + connect(ui->tableView->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), + this, SLOT(selectionChanged())); + + // Select row for newly created address + connect(model, SIGNAL(rowsInserted(QModelIndex,int,int)), + this, SLOT(selectNewAddress(QModelIndex,int,int))); + + selectionChanged(); +} + +void AddressBookPage::setOptionsModel(OptionsModel *optionsModel) +{ + this->optionsModel = optionsModel; +} + +void AddressBookPage::on_copyToClipboard_clicked() +{ + GUIUtil::copyEntryData(ui->tableView, AddressTableModel::Address); +} + +void AddressBookPage::onCopyLabelAction() +{ + GUIUtil::copyEntryData(ui->tableView, AddressTableModel::Label); +} + +void AddressBookPage::onEditAction() +{ + if(!ui->tableView->selectionModel()) + return; + QModelIndexList indexes = ui->tableView->selectionModel()->selectedRows(); + if(indexes.isEmpty()) + return; + + EditAddressDialog dlg( + tab == SendingTab ? + EditAddressDialog::EditSendingAddress : + EditAddressDialog::EditReceivingAddress); + dlg.setModel(model); + QModelIndex origIndex = proxyModel->mapToSource(indexes.at(0)); + dlg.loadRow(origIndex.row()); + dlg.exec(); +} + +void AddressBookPage::on_signMessage_clicked() +{ + QTableView *table = ui->tableView; + QModelIndexList indexes = table->selectionModel()->selectedRows(AddressTableModel::Address); + QString addr; + + foreach (QModelIndex index, indexes) + { + QVariant address = index.data(); + addr = address.toString(); + } + + emit signMessage(addr); +} + +void AddressBookPage::on_verifyMessage_clicked() +{ + QTableView *table = ui->tableView; + QModelIndexList indexes = table->selectionModel()->selectedRows(AddressTableModel::Address); + QString addr; + + foreach (QModelIndex index, indexes) + { + QVariant address = index.data(); + addr = address.toString(); + } + + emit verifyMessage(addr); +} + +void AddressBookPage::on_newAddressButton_clicked() +{ + if(!model) + return; + EditAddressDialog dlg( + tab == SendingTab ? + EditAddressDialog::NewSendingAddress : + EditAddressDialog::NewReceivingAddress, this); + dlg.setModel(model); + if(dlg.exec()) + { + newAddressToSelect = dlg.getAddress(); + } +} + +void AddressBookPage::on_deleteButton_clicked() +{ + QTableView *table = ui->tableView; + if(!table->selectionModel()) + return; + QModelIndexList indexes = table->selectionModel()->selectedRows(); + if(!indexes.isEmpty()) + { + table->model()->removeRow(indexes.at(0).row()); + } +} + +void AddressBookPage::selectionChanged() +{ + // Set button states based on selected tab and selection + QTableView *table = ui->tableView; + if(!table->selectionModel()) + return; + + if(table->selectionModel()->hasSelection()) + { + switch(tab) + { + case SendingTab: + // In sending tab, allow deletion of selection + ui->deleteButton->setEnabled(true); + ui->deleteButton->setVisible(true); + deleteAction->setEnabled(true); + ui->signMessage->setEnabled(false); + ui->signMessage->setVisible(false); + ui->verifyMessage->setEnabled(true); + ui->verifyMessage->setVisible(true); + break; + case ReceivingTab: + // Deleting receiving addresses, however, is not allowed + ui->deleteButton->setEnabled(false); + ui->deleteButton->setVisible(false); + deleteAction->setEnabled(false); + ui->signMessage->setEnabled(true); + ui->signMessage->setVisible(true); + ui->verifyMessage->setEnabled(false); + ui->verifyMessage->setVisible(false); + break; + } + ui->copyToClipboard->setEnabled(true); + ui->showQRCode->setEnabled(true); + } + else + { + ui->deleteButton->setEnabled(false); + ui->showQRCode->setEnabled(false); + ui->copyToClipboard->setEnabled(false); + ui->signMessage->setEnabled(false); + ui->verifyMessage->setEnabled(false); + } +} + +void AddressBookPage::done(int retval) +{ + QTableView *table = ui->tableView; + if(!table->selectionModel() || !table->model()) + return; + // When this is a tab/widget and not a model dialog, ignore "done" + if(mode == ForEditing) + return; + + // Figure out which address was selected, and return it + QModelIndexList indexes = table->selectionModel()->selectedRows(AddressTableModel::Address); + + foreach (QModelIndex index, indexes) + { + QVariant address = table->model()->data(index); + returnValue = address.toString(); + } + + if(returnValue.isEmpty()) + { + // If no address entry selected, return rejected + retval = Rejected; + } + + QDialog::done(retval); +} + +void AddressBookPage::exportClicked() +{ + // CSV is currently the only supported format + QString filename = GUIUtil::getSaveFileName( + this, + tr("Export Address Book Data"), QString(), + tr("Comma separated file (*.csv)")); + + if (filename.isNull()) return; + + CSVModelWriter writer(filename); + + // name, column, role + writer.setModel(proxyModel); + writer.addColumn("Label", AddressTableModel::Label, Qt::EditRole); + writer.addColumn("Address", AddressTableModel::Address, Qt::EditRole); + + if(!writer.write()) + { + QMessageBox::critical(this, tr("Error exporting"), tr("Could not write to file %1.").arg(filename), + QMessageBox::Abort, QMessageBox::Abort); + } +} + +void AddressBookPage::on_showQRCode_clicked() +{ +#ifdef USE_QRCODE + QTableView *table = ui->tableView; + QModelIndexList indexes = table->selectionModel()->selectedRows(AddressTableModel::Address); + + foreach (QModelIndex index, indexes) + { + QString address = index.data().toString(), label = index.sibling(index.row(), 0).data(Qt::EditRole).toString(); + + QRCodeDialog *dialog = new QRCodeDialog(address, label, tab == ReceivingTab, this); + if(optionsModel) + dialog->setModel(optionsModel); + dialog->setAttribute(Qt::WA_DeleteOnClose); + dialog->show(); + } +#endif +} + +void AddressBookPage::contextualMenu(const QPoint &point) +{ + QModelIndex index = ui->tableView->indexAt(point); + if(index.isValid()) + { + contextMenu->exec(QCursor::pos()); + } +} + +void AddressBookPage::selectNewAddress(const QModelIndex &parent, int begin, int end) +{ + QModelIndex idx = proxyModel->mapFromSource(model->index(begin, AddressTableModel::Address, parent)); + if(idx.isValid() && (idx.data(Qt::EditRole).toString() == newAddressToSelect)) + { + // Select row of newly created address, once + ui->tableView->setFocus(); + ui->tableView->selectRow(idx.row()); + newAddressToSelect.clear(); + } +} diff --git a/src/qt/addressbookpage.h b/src/qt/addressbookpage.h new file mode 100644 index 0000000..df87486 --- /dev/null +++ b/src/qt/addressbookpage.h @@ -0,0 +1,85 @@ +#ifndef ADDRESSBOOKPAGE_H +#define ADDRESSBOOKPAGE_H + +#include + +namespace Ui { + class AddressBookPage; +} +class AddressTableModel; +class OptionsModel; + +QT_BEGIN_NAMESPACE +class QTableView; +class QItemSelection; +class QSortFilterProxyModel; +class QMenu; +class QModelIndex; +QT_END_NAMESPACE + +/** Widget that shows a list of sending or receiving addresses. + */ +class AddressBookPage : public QDialog +{ + Q_OBJECT + +public: + enum Tabs { + SendingTab = 0, + ReceivingTab = 1 + }; + + enum Mode { + ForSending, /**< Open address book to pick address for sending */ + ForEditing /**< Open address book for editing */ + }; + + explicit AddressBookPage(Mode mode, Tabs tab, QWidget *parent = 0); + ~AddressBookPage(); + + void setModel(AddressTableModel *model); + void setOptionsModel(OptionsModel *optionsModel); + const QString &getReturnValue() const { return returnValue; } + +public slots: + void done(int retval); + void exportClicked(); + +private: + Ui::AddressBookPage *ui; + AddressTableModel *model; + OptionsModel *optionsModel; + Mode mode; + Tabs tab; + QString returnValue; + QSortFilterProxyModel *proxyModel; + QMenu *contextMenu; + QAction *deleteAction; + QString newAddressToSelect; + +private slots: + void on_deleteButton_clicked(); + void on_newAddressButton_clicked(); + /** Copy address of currently selected address entry to clipboard */ + void on_copyToClipboard_clicked(); + void on_signMessage_clicked(); + void on_verifyMessage_clicked(); + void selectionChanged(); + void on_showQRCode_clicked(); + /** Spawn contextual menu (right mouse menu) for address book entry */ + void contextualMenu(const QPoint &point); + + /** Copy label of currently selected address entry to clipboard */ + void onCopyLabelAction(); + /** Edit currently selected address entry */ + void onEditAction(); + + /** New entry/entries were added to address table */ + void selectNewAddress(const QModelIndex &parent, int begin, int end); + +signals: + void signMessage(QString addr); + void verifyMessage(QString addr); +}; + +#endif // ADDRESSBOOKDIALOG_H diff --git a/src/qt/addresstablemodel.cpp b/src/qt/addresstablemodel.cpp new file mode 100644 index 0000000..e65d391 --- /dev/null +++ b/src/qt/addresstablemodel.cpp @@ -0,0 +1,406 @@ +#include "addresstablemodel.h" +#include "guiutil.h" +#include "walletmodel.h" + +#include "wallet.h" +#include "base58.h" + +#include +#include + +const QString AddressTableModel::Send = "S"; +const QString AddressTableModel::Receive = "R"; + +struct AddressTableEntry +{ + enum Type { + Sending, + Receiving + }; + + Type type; + QString label; + QString address; + + AddressTableEntry() {} + AddressTableEntry(Type type, const QString &label, const QString &address): + type(type), label(label), address(address) {} +}; + +struct AddressTableEntryLessThan +{ + bool operator()(const AddressTableEntry &a, const AddressTableEntry &b) const + { + return a.address < b.address; + } + bool operator()(const AddressTableEntry &a, const QString &b) const + { + return a.address < b; + } + bool operator()(const QString &a, const AddressTableEntry &b) const + { + return a < b.address; + } +}; + +// Private implementation +class AddressTablePriv +{ +public: + CWallet *wallet; + QList cachedAddressTable; + AddressTableModel *parent; + + AddressTablePriv(CWallet *wallet, AddressTableModel *parent): + wallet(wallet), parent(parent) {} + + void refreshAddressTable() + { + cachedAddressTable.clear(); + { + LOCK(wallet->cs_wallet); + BOOST_FOREACH(const PAIRTYPE(CTxDestination, std::string)& item, wallet->mapAddressBook) + { + const CBitcoinAddress& address = item.first; + const std::string& strName = item.second; + bool fMine = IsMine(*wallet, address.Get()); + cachedAddressTable.append(AddressTableEntry(fMine ? AddressTableEntry::Receiving : AddressTableEntry::Sending, + QString::fromStdString(strName), + QString::fromStdString(address.ToString()))); + } + } + } + + void updateEntry(const QString &address, const QString &label, bool isMine, int status) + { + // Find address / label in model + QList::iterator lower = qLowerBound( + cachedAddressTable.begin(), cachedAddressTable.end(), address, AddressTableEntryLessThan()); + QList::iterator upper = qUpperBound( + cachedAddressTable.begin(), cachedAddressTable.end(), address, AddressTableEntryLessThan()); + int lowerIndex = (lower - cachedAddressTable.begin()); + int upperIndex = (upper - cachedAddressTable.begin()); + bool inModel = (lower != upper); + AddressTableEntry::Type newEntryType = isMine ? AddressTableEntry::Receiving : AddressTableEntry::Sending; + + switch(status) + { + case CT_NEW: + if(inModel) + { + OutputDebugStringF("Warning: AddressTablePriv::updateEntry: Got CT_NOW, but entry is already in model\n"); + break; + } + parent->beginInsertRows(QModelIndex(), lowerIndex, lowerIndex); + cachedAddressTable.insert(lowerIndex, AddressTableEntry(newEntryType, label, address)); + parent->endInsertRows(); + break; + case CT_UPDATED: + if(!inModel) + { + OutputDebugStringF("Warning: AddressTablePriv::updateEntry: Got CT_UPDATED, but entry is not in model\n"); + break; + } + lower->type = newEntryType; + lower->label = label; + parent->emitDataChanged(lowerIndex); + break; + case CT_DELETED: + if(!inModel) + { + OutputDebugStringF("Warning: AddressTablePriv::updateEntry: Got CT_DELETED, but entry is not in model\n"); + break; + } + parent->beginRemoveRows(QModelIndex(), lowerIndex, upperIndex-1); + cachedAddressTable.erase(lower, upper); + parent->endRemoveRows(); + break; + } + } + + int size() + { + return cachedAddressTable.size(); + } + + AddressTableEntry *index(int idx) + { + if(idx >= 0 && idx < cachedAddressTable.size()) + { + return &cachedAddressTable[idx]; + } + else + { + return 0; + } + } +}; + +AddressTableModel::AddressTableModel(CWallet *wallet, WalletModel *parent) : + QAbstractTableModel(parent),walletModel(parent),wallet(wallet),priv(0) +{ + columns << tr("Label") << tr("Address"); + priv = new AddressTablePriv(wallet, this); + priv->refreshAddressTable(); +} + +AddressTableModel::~AddressTableModel() +{ + delete priv; +} + +int AddressTableModel::rowCount(const QModelIndex &parent) const +{ + Q_UNUSED(parent); + return priv->size(); +} + +int AddressTableModel::columnCount(const QModelIndex &parent) const +{ + Q_UNUSED(parent); + return columns.length(); +} + +QVariant AddressTableModel::data(const QModelIndex &index, int role) const +{ + if(!index.isValid()) + return QVariant(); + + AddressTableEntry *rec = static_cast(index.internalPointer()); + + if(role == Qt::DisplayRole || role == Qt::EditRole) + { + switch(index.column()) + { + case Label: + if(rec->label.isEmpty() && role == Qt::DisplayRole) + { + return tr("(no label)"); + } + else + { + return rec->label; + } + case Address: + return rec->address; + } + } + else if (role == Qt::FontRole) + { + QFont font; + if(index.column() == Address) + { + font = GUIUtil::bitcoinAddressFont(); + } + return font; + } + else if (role == TypeRole) + { + switch(rec->type) + { + case AddressTableEntry::Sending: + return Send; + case AddressTableEntry::Receiving: + return Receive; + default: break; + } + } + return QVariant(); +} + +bool AddressTableModel::setData(const QModelIndex & index, const QVariant & value, int role) +{ + if(!index.isValid()) + return false; + AddressTableEntry *rec = static_cast(index.internalPointer()); + + editStatus = OK; + + if(role == Qt::EditRole) + { + switch(index.column()) + { + case Label: + wallet->SetAddressBookName(CBitcoinAddress(rec->address.toStdString()).Get(), value.toString().toStdString()); + rec->label = value.toString(); + break; + case Address: + // Refuse to set invalid address, set error status and return false + if(!walletModel->validateAddress(value.toString())) + { + editStatus = INVALID_ADDRESS; + return false; + } + // Double-check that we're not overwriting a receiving address + if(rec->type == AddressTableEntry::Sending) + { + { + LOCK(wallet->cs_wallet); + // Remove old entry + wallet->DelAddressBookName(CBitcoinAddress(rec->address.toStdString()).Get()); + // Add new entry with new address + wallet->SetAddressBookName(CBitcoinAddress(value.toString().toStdString()).Get(), rec->label.toStdString()); + } + } + break; + } + + return true; + } + return false; +} + +QVariant AddressTableModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + if(orientation == Qt::Horizontal) + { + if(role == Qt::DisplayRole) + { + return columns[section]; + } + } + return QVariant(); +} + +Qt::ItemFlags AddressTableModel::flags(const QModelIndex & index) const +{ + if(!index.isValid()) + return 0; + AddressTableEntry *rec = static_cast(index.internalPointer()); + + Qt::ItemFlags retval = Qt::ItemIsSelectable | Qt::ItemIsEnabled; + // Can edit address and label for sending addresses, + // and only label for receiving addresses. + if(rec->type == AddressTableEntry::Sending || + (rec->type == AddressTableEntry::Receiving && index.column()==Label)) + { + retval |= Qt::ItemIsEditable; + } + return retval; +} + +QModelIndex AddressTableModel::index(int row, int column, const QModelIndex & parent) const +{ + Q_UNUSED(parent); + AddressTableEntry *data = priv->index(row); + if(data) + { + return createIndex(row, column, priv->index(row)); + } + else + { + return QModelIndex(); + } +} + +void AddressTableModel::updateEntry(const QString &address, const QString &label, bool isMine, int status) +{ + // Update address book model from Bitcoin core + priv->updateEntry(address, label, isMine, status); +} + +QString AddressTableModel::addRow(const QString &type, const QString &label, const QString &address) +{ + std::string strLabel = label.toStdString(); + std::string strAddress = address.toStdString(); + + editStatus = OK; + + if(type == Send) + { + if(!walletModel->validateAddress(address)) + { + editStatus = INVALID_ADDRESS; + return QString(); + } + // Check for duplicate addresses + { + LOCK(wallet->cs_wallet); + if(wallet->mapAddressBook.count(CBitcoinAddress(strAddress).Get())) + { + editStatus = DUPLICATE_ADDRESS; + return QString(); + } + } + } + else if(type == Receive) + { + // Generate a new address to associate with given label + WalletModel::UnlockContext ctx(walletModel->requestUnlock()); + if(!ctx.isValid()) + { + // Unlock wallet failed or was cancelled + editStatus = WALLET_UNLOCK_FAILURE; + return QString(); + } + CPubKey newKey; + if(!wallet->GetKeyFromPool(newKey, true)) + { + editStatus = KEY_GENERATION_FAILURE; + return QString(); + } + strAddress = CBitcoinAddress(newKey.GetID()).ToString(); + } + else + { + return QString(); + } + // Add entry + { + LOCK(wallet->cs_wallet); + wallet->SetAddressBookName(CBitcoinAddress(strAddress).Get(), strLabel); + } + return QString::fromStdString(strAddress); +} + +bool AddressTableModel::removeRows(int row, int count, const QModelIndex & parent) +{ + Q_UNUSED(parent); + AddressTableEntry *rec = priv->index(row); + if(count != 1 || !rec || rec->type == AddressTableEntry::Receiving) + { + // Can only remove one row at a time, and cannot remove rows not in model. + // Also refuse to remove receiving addresses. + return false; + } + { + LOCK(wallet->cs_wallet); + wallet->DelAddressBookName(CBitcoinAddress(rec->address.toStdString()).Get()); + } + return true; +} + +/* Look up label for address in address book, if not found return empty string. + */ +QString AddressTableModel::labelForAddress(const QString &address) const +{ + { + LOCK(wallet->cs_wallet); + CBitcoinAddress address_parsed(address.toStdString()); + std::map::iterator mi = wallet->mapAddressBook.find(address_parsed.Get()); + if (mi != wallet->mapAddressBook.end()) + { + return QString::fromStdString(mi->second); + } + } + return QString(); +} + +int AddressTableModel::lookupAddress(const QString &address) const +{ + QModelIndexList lst = match(index(0, Address, QModelIndex()), + Qt::EditRole, address, 1, Qt::MatchExactly); + if(lst.isEmpty()) + { + return -1; + } + else + { + return lst.at(0).row(); + } +} + +void AddressTableModel::emitDataChanged(int idx) +{ + emit dataChanged(index(idx, 0, QModelIndex()), index(idx, columns.length()-1, QModelIndex())); +} diff --git a/src/qt/addresstablemodel.h b/src/qt/addresstablemodel.h new file mode 100644 index 0000000..42974e3 --- /dev/null +++ b/src/qt/addresstablemodel.h @@ -0,0 +1,91 @@ +#ifndef ADDRESSTABLEMODEL_H +#define ADDRESSTABLEMODEL_H + +#include +#include + +class AddressTablePriv; +class CWallet; +class WalletModel; + +/** + Qt model of the address book in the core. This allows views to access and modify the address book. + */ +class AddressTableModel : public QAbstractTableModel +{ + Q_OBJECT +public: + explicit AddressTableModel(CWallet *wallet, WalletModel *parent = 0); + ~AddressTableModel(); + + enum ColumnIndex { + Label = 0, /**< User specified label */ + Address = 1 /**< Bitcoin address */ + }; + + enum RoleIndex { + TypeRole = Qt::UserRole /**< Type of address (#Send or #Receive) */ + }; + + /** Return status of edit/insert operation */ + enum EditStatus { + OK, + INVALID_ADDRESS, /**< Unparseable address */ + DUPLICATE_ADDRESS, /**< Address already in address book */ + WALLET_UNLOCK_FAILURE, /**< Wallet could not be unlocked to create new receiving address */ + KEY_GENERATION_FAILURE /**< Generating a new public key for a receiving address failed */ + }; + + static const QString Send; /**< Specifies send address */ + static const QString Receive; /**< Specifies receive address */ + + /** @name Methods overridden from QAbstractTableModel + @{*/ + int rowCount(const QModelIndex &parent) const; + int columnCount(const QModelIndex &parent) const; + QVariant data(const QModelIndex &index, int role) const; + bool setData(const QModelIndex & index, const QVariant & value, int role); + QVariant headerData(int section, Qt::Orientation orientation, int role) const; + QModelIndex index(int row, int column, const QModelIndex & parent) const; + bool removeRows(int row, int count, const QModelIndex & parent = QModelIndex()); + Qt::ItemFlags flags(const QModelIndex & index) const; + /*@}*/ + + /* Add an address to the model. + Returns the added address on success, and an empty string otherwise. + */ + QString addRow(const QString &type, const QString &label, const QString &address); + + /* Look up label for address in address book, if not found return empty string. + */ + QString labelForAddress(const QString &address) const; + + /* Look up row index of an address in the model. + Return -1 if not found. + */ + int lookupAddress(const QString &address) const; + + EditStatus getEditStatus() const { return editStatus; } + +private: + WalletModel *walletModel; + CWallet *wallet; + AddressTablePriv *priv; + QStringList columns; + EditStatus editStatus; + + /** Notify listeners that data changed. */ + void emitDataChanged(int index); + +signals: + void defaultAddressChanged(const QString &address); + +public slots: + /* Update address list from core. + */ + void updateEntry(const QString &address, const QString &label, bool isMine, int status); + + friend class AddressTablePriv; +}; + +#endif // ADDRESSTABLEMODEL_H diff --git a/src/qt/askpassphrasedialog.cpp b/src/qt/askpassphrasedialog.cpp new file mode 100644 index 0000000..27fb3db --- /dev/null +++ b/src/qt/askpassphrasedialog.cpp @@ -0,0 +1,257 @@ +#include "askpassphrasedialog.h" +#include "ui_askpassphrasedialog.h" + +#include "guiconstants.h" +#include "walletmodel.h" + +#include +#include +#include + +extern bool fWalletUnlockMintOnly; + +AskPassphraseDialog::AskPassphraseDialog(Mode mode, QWidget *parent) : + QDialog(parent), + ui(new Ui::AskPassphraseDialog), + mode(mode), + model(0), + fCapsLock(false) +{ + ui->setupUi(this); + ui->passEdit1->setMaxLength(MAX_PASSPHRASE_SIZE); + ui->passEdit2->setMaxLength(MAX_PASSPHRASE_SIZE); + ui->passEdit3->setMaxLength(MAX_PASSPHRASE_SIZE); + + // Setup Caps Lock detection. + ui->passEdit1->installEventFilter(this); + ui->passEdit2->installEventFilter(this); + ui->passEdit3->installEventFilter(this); + + switch(mode) + { + case Encrypt: // Ask passphrase x2 + ui->passLabel1->hide(); + ui->passEdit1->hide(); + ui->warningLabel->setText(tr("Enter the new passphrase to the wallet.
Please use a passphrase of 10 or more random characters, or eight or more words.")); + setWindowTitle(tr("Encrypt wallet")); + break; + case UnlockMinting: + ui->mintingCheckBox->setChecked(true); + ui->mintingCheckBox->show(); + // fallthru + case Unlock: // Ask passphrase + ui->warningLabel->setText(tr("This operation needs your wallet passphrase to unlock the wallet.")); + ui->passLabel2->hide(); + ui->passEdit2->hide(); + ui->passLabel3->hide(); + ui->passEdit3->hide(); + setWindowTitle(tr("Unlock wallet")); + break; + case Decrypt: // Ask passphrase + ui->warningLabel->setText(tr("This operation needs your wallet passphrase to decrypt the wallet.")); + ui->passLabel2->hide(); + ui->passEdit2->hide(); + ui->passLabel3->hide(); + ui->passEdit3->hide(); + setWindowTitle(tr("Decrypt wallet")); + break; + case ChangePass: // Ask old passphrase + new passphrase x2 + setWindowTitle(tr("Change passphrase")); + ui->warningLabel->setText(tr("Enter the old and new passphrase to the wallet.")); + break; + } + + textChanged(); + connect(ui->passEdit1, SIGNAL(textChanged(QString)), this, SLOT(textChanged())); + connect(ui->passEdit2, SIGNAL(textChanged(QString)), this, SLOT(textChanged())); + connect(ui->passEdit3, SIGNAL(textChanged(QString)), this, SLOT(textChanged())); +} + +AskPassphraseDialog::~AskPassphraseDialog() +{ + // Attempt to overwrite text so that they do not linger around in memory + ui->passEdit1->setText(QString(" ").repeated(ui->passEdit1->text().size())); + ui->passEdit2->setText(QString(" ").repeated(ui->passEdit2->text().size())); + ui->passEdit3->setText(QString(" ").repeated(ui->passEdit3->text().size())); + delete ui; +} + +void AskPassphraseDialog::setModel(WalletModel *model) +{ + this->model = model; +} + +void AskPassphraseDialog::accept() +{ + SecureString oldpass, newpass1, newpass2; + if(!model) + return; + oldpass.reserve(MAX_PASSPHRASE_SIZE); + newpass1.reserve(MAX_PASSPHRASE_SIZE); + newpass2.reserve(MAX_PASSPHRASE_SIZE); + // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string) + // Alternately, find a way to make this input mlock()'d to begin with. + oldpass.assign(ui->passEdit1->text().toStdString().c_str()); + newpass1.assign(ui->passEdit2->text().toStdString().c_str()); + newpass2.assign(ui->passEdit3->text().toStdString().c_str()); + + switch(mode) + { + case Encrypt: { + if(newpass1.empty() || newpass2.empty()) + { + // Cannot encrypt with empty passphrase + break; + } + QMessageBox::StandardButton retval = QMessageBox::question(this, tr("Confirm wallet encryption"), + tr("Warning: If you encrypt your wallet and lose your passphrase, you will LOSE ALL OF YOUR COINS!") + "

" + tr("Are you sure you wish to encrypt your wallet?"), + QMessageBox::Yes|QMessageBox::Cancel, + QMessageBox::Cancel); + if(retval == QMessageBox::Yes) + { + if(newpass1 == newpass2) + { + if(model->setWalletEncrypted(true, newpass1)) + { + QMessageBox::warning(this, tr("Wallet encrypted"), + "" + + tr("triangles will close now to finish the encryption process. " + "Remember that encrypting your wallet cannot fully protect " + "your coins from being stolen by malware infecting your computer.") + + "

" + + tr("IMPORTANT: Any previous backups you have made of your wallet file " + "should be replaced with the newly generated, encrypted wallet file. " + "For security reasons, previous backups of the unencrypted wallet file " + "will become useless as soon as you start using the new, encrypted wallet.") + + "
"); + QApplication::quit(); + } + else + { + QMessageBox::critical(this, tr("Wallet encryption failed"), + tr("Wallet encryption failed due to an internal error. Your wallet was not encrypted.")); + } + QDialog::accept(); // Success + } + else + { + QMessageBox::critical(this, tr("Wallet encryption failed"), + tr("The supplied passphrases do not match.")); + } + } + else + { + QDialog::reject(); // Cancelled + } + } break; + case UnlockMinting: + case Unlock: + if(!model->setWalletLocked(false, oldpass)) + { + QMessageBox::critical(this, tr("Wallet unlock failed"), + tr("The passphrase entered for the wallet decryption was incorrect.")); + } + else + { + fWalletUnlockMintOnly = ui->mintingCheckBox->isChecked(); + QDialog::accept(); // Success + } + break; + case Decrypt: + if(!model->setWalletEncrypted(false, oldpass)) + { + QMessageBox::critical(this, tr("Wallet decryption failed"), + tr("The passphrase entered for the wallet decryption was incorrect.")); + } + else + { + QDialog::accept(); // Success + } + break; + case ChangePass: + if(newpass1 == newpass2) + { + if(model->changePassphrase(oldpass, newpass1)) + { + QMessageBox::information(this, tr("Wallet encrypted"), + tr("Wallet passphrase was successfully changed.")); + QDialog::accept(); // Success + } + else + { + QMessageBox::critical(this, tr("Wallet encryption failed"), + tr("The passphrase entered for the wallet decryption was incorrect.")); + } + } + else + { + QMessageBox::critical(this, tr("Wallet encryption failed"), + tr("The supplied passphrases do not match.")); + } + break; + } +} + +void AskPassphraseDialog::textChanged() +{ + // Validate input, set Ok button to enabled when acceptable + bool acceptable = false; + switch(mode) + { + case Encrypt: // New passphrase x2 + acceptable = !ui->passEdit2->text().isEmpty() && !ui->passEdit3->text().isEmpty(); + break; + case UnlockMinting: + case Unlock: // Old passphrase x1 + case Decrypt: + acceptable = !ui->passEdit1->text().isEmpty(); + break; + case ChangePass: // Old passphrase x1, new passphrase x2 + acceptable = !ui->passEdit1->text().isEmpty() && !ui->passEdit2->text().isEmpty() && !ui->passEdit3->text().isEmpty(); + break; + } + ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(acceptable); +} + +bool AskPassphraseDialog::event(QEvent *event) +{ + // Detect Caps Lock key press. + if (event->type() == QEvent::KeyPress) { + QKeyEvent *ke = static_cast(event); + if (ke->key() == Qt::Key_CapsLock) { + fCapsLock = !fCapsLock; + } + if (fCapsLock) { + ui->capsLabel->setText(tr("Warning: The Caps Lock key is on!")); + } else { + ui->capsLabel->clear(); + } + } + return QWidget::event(event); +} + +bool AskPassphraseDialog::eventFilter(QObject *object, QEvent *event) +{ + /* Detect Caps Lock. + * There is no good OS-independent way to check a key state in Qt, but we + * can detect Caps Lock by checking for the following condition: + * Shift key is down and the result is a lower case character, or + * Shift key is not down and the result is an upper case character. + */ + if (event->type() == QEvent::KeyPress) { + QKeyEvent *ke = static_cast(event); + QString str = ke->text(); + if (str.length() != 0) { + const QChar *psz = str.unicode(); + bool fShift = (ke->modifiers() & Qt::ShiftModifier) != 0; + if ((fShift && psz->isLower()) || (!fShift && psz->isUpper())) { + fCapsLock = true; + ui->capsLabel->setText(tr("Warning: The Caps Lock key is on!")); + } else if (psz->isLetter()) { + fCapsLock = false; + ui->capsLabel->clear(); + } + } + } + return QDialog::eventFilter(object, event); +} diff --git a/src/qt/askpassphrasedialog.h b/src/qt/askpassphrasedialog.h new file mode 100644 index 0000000..ca01274 --- /dev/null +++ b/src/qt/askpassphrasedialog.h @@ -0,0 +1,46 @@ +#ifndef ASKPASSPHRASEDIALOG_H +#define ASKPASSPHRASEDIALOG_H + +#include + +namespace Ui { + class AskPassphraseDialog; +} + +class WalletModel; + +/** Multifunctional dialog to ask for passphrases. Used for encryption, unlocking, and changing the passphrase. + */ +class AskPassphraseDialog : public QDialog +{ + Q_OBJECT + +public: + enum Mode { + Encrypt, /**< Ask passphrase twice and encrypt */ + UnlockMinting, /**< Ask passphrase and unlock for minting only */ + Unlock, /**< Ask passphrase and unlock */ + ChangePass, /**< Ask old passphrase + new passphrase twice */ + Decrypt /**< Ask passphrase and decrypt wallet */ + }; + + explicit AskPassphraseDialog(Mode mode, QWidget *parent = 0); + ~AskPassphraseDialog(); + + void accept(); + + void setModel(WalletModel *model); + +private: + Ui::AskPassphraseDialog *ui; + Mode mode; + WalletModel *model; + bool fCapsLock; + +private slots: + void textChanged(); + bool event(QEvent *event); + bool eventFilter(QObject *, QEvent *event); +}; + +#endif // ASKPASSPHRASEDIALOG_H diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp new file mode 100644 index 0000000..81bf982 --- /dev/null +++ b/src/qt/bitcoin.cpp @@ -0,0 +1,270 @@ +/* + * W.J. van der Laan 2011-2012 + */ +#include "bitcoingui.h" +#include "clientmodel.h" +#include "walletmodel.h" +#include "optionsmodel.h" +#include "guiutil.h" +#include "guiconstants.h" + +#include "init.h" +#include "ui_interface.h" +#include "qtipcserver.h" + +#include +#include +#include +#include +#include +#include +#include + +#if defined(BITCOIN_NEED_QT_PLUGINS) && !defined(_BITCOIN_QT_PLUGINS_INCLUDED) +#define _BITCOIN_QT_PLUGINS_INCLUDED +#define __INSURE__ +#include +Q_IMPORT_PLUGIN(qcncodecs) +Q_IMPORT_PLUGIN(qjpcodecs) +Q_IMPORT_PLUGIN(qtwcodecs) +Q_IMPORT_PLUGIN(qkrcodecs) +Q_IMPORT_PLUGIN(qtaccessiblewidgets) +#endif + +// Need a global reference for the notifications to find the GUI +static BitcoinGUI *guiref; +static QSplashScreen *splashref; + +static void ThreadSafeMessageBox(const std::string& message, const std::string& caption, int style) +{ + // Message from network thread + if(guiref) + { + bool modal = (style & CClientUIInterface::MODAL); + // in case of modal message, use blocking connection to wait for user to click OK + QMetaObject::invokeMethod(guiref, "error", + modal ? GUIUtil::blockingGUIThreadConnection() : Qt::QueuedConnection, + Q_ARG(QString, QString::fromStdString(caption)), + Q_ARG(QString, QString::fromStdString(message)), + Q_ARG(bool, modal)); + } + else + { + printf("%s: %s\n", caption.c_str(), message.c_str()); + fprintf(stderr, "%s: %s\n", caption.c_str(), message.c_str()); + } +} + +static bool ThreadSafeAskFee(int64 nFeeRequired, const std::string& strCaption) +{ + if(!guiref) + return false; + if(nFeeRequired < MIN_TX_FEE || nFeeRequired <= nTransactionFee || fDaemon) + return true; + bool payFee = false; + + QMetaObject::invokeMethod(guiref, "askFee", GUIUtil::blockingGUIThreadConnection(), + Q_ARG(qint64, nFeeRequired), + Q_ARG(bool*, &payFee)); + + return payFee; +} + +static void ThreadSafeHandleURI(const std::string& strURI) +{ + if(!guiref) + return; + + QMetaObject::invokeMethod(guiref, "handleURI", GUIUtil::blockingGUIThreadConnection(), + Q_ARG(QString, QString::fromStdString(strURI))); +} + +static void InitMessage(const std::string &message) +{ + if(splashref) + { + splashref->showMessage(QString::fromStdString(message), Qt::AlignBottom|Qt::AlignHCenter, QColor(255,255,200)); + QApplication::instance()->processEvents(); + } +} + +static void QueueShutdown() +{ + QMetaObject::invokeMethod(QCoreApplication::instance(), "quit", Qt::QueuedConnection); +} + +/* + Translate string to current locale using Qt. + */ +static std::string Translate(const char* psz) +{ + return QCoreApplication::translate("bitcoin-core", psz).toStdString(); +} + +/* Handle runaway exceptions. Shows a message box with the problem and quits the program. + */ +static void handleRunawayException(std::exception *e) +{ + PrintExceptionContinue(e, "Runaway exception"); + QMessageBox::critical(0, "Runaway exception", BitcoinGUI::tr("A fatal error occurred. triangles can no longer continue safely and will quit.") + QString("\n\n") + QString::fromStdString(strMiscWarning)); + exit(1); +} + +#ifndef BITCOIN_QT_TEST +int main(int argc, char *argv[]) +{ + // Do this early as we don't want to bother initializing if we are just calling IPC + ipcScanRelay(argc, argv); + + // Internal string conversion is all UTF-8 + QTextCodec::setCodecForTr(QTextCodec::codecForName("UTF-8")); + QTextCodec::setCodecForCStrings(QTextCodec::codecForTr()); + + Q_INIT_RESOURCE(bitcoin); + QApplication app(argc, argv); + + // Install global event filter that makes sure that long tooltips can be word-wrapped + app.installEventFilter(new GUIUtil::ToolTipToRichTextFilter(TOOLTIP_WRAP_THRESHOLD, &app)); + + // Command-line options take precedence: + ParseParameters(argc, argv); + + // ... then bitcoin.conf: + if (!boost::filesystem::is_directory(GetDataDir(false))) + { + // This message can not be translated, as translation is not initialized yet + // (which not yet possible because lang=XX can be overridden in bitcoin.conf in the data directory) + QMessageBox::critical(0, "triangles", + QString("Error: Specified data directory \"%1\" does not exist.").arg(QString::fromStdString(mapArgs["-datadir"]))); + return 1; + } + ReadConfigFile(mapArgs, mapMultiArgs); + + // Application identification (must be set before OptionsModel is initialized, + // as it is used to locate QSettings) + app.setOrganizationName("triangles"); + app.setOrganizationDomain("triangles.su"); + if(GetBoolArg("-testnet")) // Separate UI settings for testnet + app.setApplicationName("triangles-qt-testnet"); + else + app.setApplicationName("triangles-qt"); + + // ... then GUI settings: + OptionsModel optionsModel; + + // Get desired locale (e.g. "de_DE") from command line or use system locale + QString lang_territory = QString::fromStdString(GetArg("-lang", QLocale::system().name().toStdString())); + QString lang = lang_territory; + // Convert to "de" only by truncating "_DE" + lang.truncate(lang_territory.lastIndexOf('_')); + + QTranslator qtTranslatorBase, qtTranslator, translatorBase, translator; + // Load language files for configured locale: + // - First load the translator for the base language, without territory + // - Then load the more specific locale translator + + // Load e.g. qt_de.qm + if (qtTranslatorBase.load("qt_" + lang, QLibraryInfo::location(QLibraryInfo::TranslationsPath))) + app.installTranslator(&qtTranslatorBase); + + // Load e.g. qt_de_DE.qm + if (qtTranslator.load("qt_" + lang_territory, QLibraryInfo::location(QLibraryInfo::TranslationsPath))) + app.installTranslator(&qtTranslator); + + // Load e.g. bitcoin_de.qm (shortcut "de" needs to be defined in bitcoin.qrc) + if (translatorBase.load(lang, ":/translations/")) + app.installTranslator(&translatorBase); + + // Load e.g. bitcoin_de_DE.qm (shortcut "de_DE" needs to be defined in bitcoin.qrc) + if (translator.load(lang_territory, ":/translations/")) + app.installTranslator(&translator); + + // Subscribe to global signals from core + uiInterface.ThreadSafeMessageBox.connect(ThreadSafeMessageBox); + uiInterface.ThreadSafeAskFee.connect(ThreadSafeAskFee); + uiInterface.ThreadSafeHandleURI.connect(ThreadSafeHandleURI); + uiInterface.InitMessage.connect(InitMessage); + uiInterface.QueueShutdown.connect(QueueShutdown); + uiInterface.Translate.connect(Translate); + + // Show help message immediately after parsing command-line options (for "-lang") and setting locale, + // but before showing splash screen. + if (mapArgs.count("-?") || mapArgs.count("--help")) + { + GUIUtil::HelpMessageBox help; + help.showOrPrint(); + return 1; + } + + QSplashScreen splash(QPixmap(":/images/splash"), 0); + if (GetBoolArg("-splash", true) && !GetBoolArg("-min")) + { + splash.show(); + splash.setAutoFillBackground(true); + splashref = &splash; + } + + app.processEvents(); + + app.setQuitOnLastWindowClosed(false); + + try + { + // Regenerate startup link, to fix links to old versions + if (GUIUtil::GetStartOnSystemStartup()) + GUIUtil::SetStartOnSystemStartup(true); + + BitcoinGUI window; + guiref = &window; + if(AppInit2()) + { + { + // Put this in a block, so that the Model objects are cleaned up before + // calling Shutdown(). + + optionsModel.Upgrade(); // Must be done after AppInit2 + + if (splashref) + splash.finish(&window); + + ClientModel clientModel(&optionsModel); + WalletModel walletModel(pwalletMain, &optionsModel); + + window.setClientModel(&clientModel); + window.setWalletModel(&walletModel); + + // If -min option passed, start window minimized. + if(GetBoolArg("-min")) + { + window.showMinimized(); + } + else + { + window.show(); + } + + // Place this here as guiref has to be defined if we don't want to lose URIs + ipcInit(argc, argv); + + app.exec(); + + window.hide(); + window.setClientModel(0); + window.setWalletModel(0); + guiref = 0; + } + // Shutdown the core and its threads, but don't exit Bitcoin-Qt here + Shutdown(NULL); + } + else + { + return 1; + } + } catch (std::exception& e) { + handleRunawayException(&e); + } catch (...) { + handleRunawayException(NULL); + } + return 0; +} +#endif // BITCOIN_QT_TEST diff --git a/src/qt/bitcoin.qrc b/src/qt/bitcoin.qrc new file mode 100644 index 0000000..4d06540 --- /dev/null +++ b/src/qt/bitcoin.qrc @@ -0,0 +1,57 @@ + + + res/icons/triangles-128.png + res/icons/address-book.png + res/icons/quit.png + res/icons/send.png + res/icons/triangles-16.png + res/icons/connect0_16.png + res/icons/connect1_16.png + res/icons/connect2_16.png + res/icons/connect3_16.png + res/icons/connect4_16.png + res/icons/transaction0.png + res/icons/transaction2.png + res/icons/clock1.png + res/icons/clock2.png + res/icons/clock3.png + res/icons/clock4.png + res/icons/clock5.png + res/icons/configure.png + res/icons/receive.png + res/icons/editpaste.png + res/icons/editcopy.png + res/icons/add.png + res/icons/triangles-128.png + res/icons/triangles-16.png + res/icons/edit.png + res/icons/history.png + res/icons/overview.png + res/icons/export.png + res/icons/synced.png + res/icons/remove.png + res/icons/tx_mined.png + res/icons/tx_input.png + res/icons/tx_output.png + res/icons/tx_inout.png + res/icons/lock_closed.png + res/icons/lock_open.png + res/icons/mining.png + res/icons/key.png + res/icons/filesave.png + res/icons/qrcode.png + res/icons/debugwindow.png + + + res/images/about.png + res/images/splash.png + res/images/wallet.png + + + res/movies/update_spinner.mng + + + locale/bitcoin_en.qm + locale/bitcoin_ru.qm + + diff --git a/src/qt/bitcoinaddressvalidator.cpp b/src/qt/bitcoinaddressvalidator.cpp new file mode 100644 index 0000000..5136ea0 --- /dev/null +++ b/src/qt/bitcoinaddressvalidator.cpp @@ -0,0 +1,77 @@ +#include "bitcoinaddressvalidator.h" + +/* Base58 characters are: + "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz" + + This is: + - All numbers except for '0' + - All upper-case letters except for 'I' and 'O' + - All lower-case letters except for 'l' + + User friendly Base58 input can map + - 'l' and 'I' to '1' + - '0' and 'O' to 'o' +*/ + +BitcoinAddressValidator::BitcoinAddressValidator(QObject *parent) : + QValidator(parent) +{ +} + +QValidator::State BitcoinAddressValidator::validate(QString &input, int &pos) const +{ + // Correction + for(int idx=0; idx= '0' && ch<='9') || + (ch >= 'a' && ch<='z') || + (ch >= 'A' && ch<='Z')) && + ch != 'l' && ch != 'I' && ch != '0' && ch != 'O') + { + // Alphanumeric and not a 'forbidden' character + } + else + { + state = QValidator::Invalid; + } + } + + // Empty address is "intermediate" input + if(input.isEmpty()) + { + state = QValidator::Intermediate; + } + + return state; +} diff --git a/src/qt/bitcoinaddressvalidator.h b/src/qt/bitcoinaddressvalidator.h new file mode 100644 index 0000000..9710d12 --- /dev/null +++ b/src/qt/bitcoinaddressvalidator.h @@ -0,0 +1,24 @@ +#ifndef BITCOINADDRESSVALIDATOR_H +#define BITCOINADDRESSVALIDATOR_H + +#include + +/** Base48 entry widget validator. + Corrects near-miss characters and refuses characters that are no part of base48. + */ +class BitcoinAddressValidator : public QValidator +{ + Q_OBJECT +public: + explicit BitcoinAddressValidator(QObject *parent = 0); + + State validate(QString &input, int &pos) const; + + static const int MaxAddressLength = 35; +signals: + +public slots: + +}; + +#endif // BITCOINADDRESSVALIDATOR_H diff --git a/src/qt/bitcoinamountfield.cpp b/src/qt/bitcoinamountfield.cpp new file mode 100644 index 0000000..9514ec8 --- /dev/null +++ b/src/qt/bitcoinamountfield.cpp @@ -0,0 +1,168 @@ +#include "bitcoinamountfield.h" +#include "qvaluecombobox.h" +#include "bitcoinunits.h" + +#include "guiconstants.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +BitcoinAmountField::BitcoinAmountField(QWidget *parent): + QWidget(parent), amount(0), currentUnit(-1) +{ + amount = new QDoubleSpinBox(this); + amount->setLocale(QLocale::c()); + amount->setDecimals(8); + amount->installEventFilter(this); + amount->setMaximumWidth(170); + amount->setSingleStep(0.001); + + QHBoxLayout *layout = new QHBoxLayout(this); + layout->addWidget(amount); + unit = new QValueComboBox(this); + unit->setModel(new BitcoinUnits(this)); + layout->addWidget(unit); + layout->addStretch(1); + layout->setContentsMargins(0,0,0,0); + + setLayout(layout); + + setFocusPolicy(Qt::TabFocus); + setFocusProxy(amount); + + // If one if the widgets changes, the combined content changes as well + connect(amount, SIGNAL(valueChanged(QString)), this, SIGNAL(textChanged())); + connect(unit, SIGNAL(currentIndexChanged(int)), this, SLOT(unitChanged(int))); + + // Set default based on configuration + unitChanged(unit->currentIndex()); +} + +void BitcoinAmountField::setText(const QString &text) +{ + if (text.isEmpty()) + amount->clear(); + else + amount->setValue(text.toDouble()); +} + +void BitcoinAmountField::clear() +{ + amount->clear(); + unit->setCurrentIndex(0); +} + +bool BitcoinAmountField::validate() +{ + bool valid = true; + if (amount->value() == 0.0) + valid = false; + if (valid && !BitcoinUnits::parse(currentUnit, text(), 0)) + valid = false; + + setValid(valid); + + return valid; +} + +void BitcoinAmountField::setValid(bool valid) +{ + if (valid) + amount->setStyleSheet(""); + else + amount->setStyleSheet(STYLE_INVALID); +} + +QString BitcoinAmountField::text() const +{ + if (amount->text().isEmpty()) + return QString(); + else + return amount->text(); +} + +bool BitcoinAmountField::eventFilter(QObject *object, QEvent *event) +{ + if (event->type() == QEvent::FocusIn) + { + // Clear invalid flag on focus + setValid(true); + } + else if (event->type() == QEvent::KeyPress || event->type() == QEvent::KeyRelease) + { + QKeyEvent *keyEvent = static_cast(event); + if (keyEvent->key() == Qt::Key_Comma) + { + // Translate a comma into a period + QKeyEvent periodKeyEvent(event->type(), Qt::Key_Period, keyEvent->modifiers(), ".", keyEvent->isAutoRepeat(), keyEvent->count()); + qApp->sendEvent(object, &periodKeyEvent); + return true; + } + } + return QWidget::eventFilter(object, event); +} + +QWidget *BitcoinAmountField::setupTabChain(QWidget *prev) +{ + QWidget::setTabOrder(prev, amount); + return amount; +} + +qint64 BitcoinAmountField::value(bool *valid_out) const +{ + qint64 val_out = 0; + bool valid = BitcoinUnits::parse(currentUnit, text(), &val_out); + if(valid_out) + { + *valid_out = valid; + } + return val_out; +} + +void BitcoinAmountField::setValue(qint64 value) +{ + setText(BitcoinUnits::format(currentUnit, value)); +} + +void BitcoinAmountField::unitChanged(int idx) +{ + // Use description tooltip for current unit for the combobox + unit->setToolTip(unit->itemData(idx, Qt::ToolTipRole).toString()); + + // Determine new unit ID + int newUnit = unit->itemData(idx, BitcoinUnits::UnitRole).toInt(); + + // Parse current value and convert to new unit + bool valid = false; + qint64 currentValue = value(&valid); + + currentUnit = newUnit; + + // Set max length after retrieving the value, to prevent truncation + amount->setDecimals(BitcoinUnits::decimals(currentUnit)); + amount->setMaximum(qPow(10, BitcoinUnits::amountDigits(currentUnit)) - qPow(10, -amount->decimals())); + + if(valid) + { + // If value was valid, re-place it in the widget with the new unit + setValue(currentValue); + } + else + { + // If current value is invalid, just clear field + setText(""); + } + setValid(true); +} + +void BitcoinAmountField::setDisplayUnit(int newUnit) +{ + unit->setValue(newUnit); +} diff --git a/src/qt/bitcoinamountfield.h b/src/qt/bitcoinamountfield.h new file mode 100644 index 0000000..8bf8535 --- /dev/null +++ b/src/qt/bitcoinamountfield.h @@ -0,0 +1,61 @@ +#ifndef BITCOINFIELD_H +#define BITCOINFIELD_H + +#include + +QT_BEGIN_NAMESPACE +class QDoubleSpinBox; +class QValueComboBox; +QT_END_NAMESPACE + +/** Widget for entering bitcoin amounts. + */ +class BitcoinAmountField: public QWidget +{ + Q_OBJECT + Q_PROPERTY(qint64 value READ value WRITE setValue NOTIFY textChanged USER true) +public: + explicit BitcoinAmountField(QWidget *parent = 0); + + qint64 value(bool *valid=0) const; + void setValue(qint64 value); + + /** Mark current value as invalid in UI. */ + void setValid(bool valid); + /** Perform input validation, mark field as invalid if entered value is not valid. */ + bool validate(); + + /** Change unit used to display amount. */ + void setDisplayUnit(int unit); + + /** Make field empty and ready for new input. */ + void clear(); + + /** Qt messes up the tab chain by default in some cases (issue https://bugreports.qt-project.org/browse/QTBUG-10907), + in these cases we have to set it up manually. + */ + QWidget *setupTabChain(QWidget *prev); + + QString text() const; + +signals: + void textChanged(); + +protected: + /** Intercept focus-in event and ',' key presses */ + bool eventFilter(QObject *object, QEvent *event); + +private: + QDoubleSpinBox *amount; + QValueComboBox *unit; + int currentUnit; + + void setText(const QString &text); + +private slots: + void unitChanged(int idx); + +}; + + +#endif // BITCOINFIELD_H diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp new file mode 100644 index 0000000..d070551 --- /dev/null +++ b/src/qt/bitcoingui.cpp @@ -0,0 +1,1009 @@ +/* + * Qt4 bitcoin GUI. + * + * W.J. van der Laan 2011-2012 + * The Bitcoin Developers 2011-2012 + */ +#include "bitcoingui.h" +#include "transactiontablemodel.h" +#include "addressbookpage.h" +#include "sendcoinsdialog.h" +#include "signverifymessagedialog.h" +#include "optionsdialog.h" +#include "aboutdialog.h" +#include "clientmodel.h" +#include "walletmodel.h" +#include "editaddressdialog.h" +#include "optionsmodel.h" +#include "transactiondescdialog.h" +#include "addresstablemodel.h" +#include "transactionview.h" +#include "overviewpage.h" +#include "bitcoinunits.h" +#include "guiconstants.h" +#include "askpassphrasedialog.h" +#include "notificator.h" +#include "guiutil.h" +#include "rpcconsole.h" +#include "wallet.h" +#include "bitcoinrpc.h" + +#ifdef Q_OS_MAC +#include "macdockiconhandler.hh" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +extern CWallet *pwalletMain; +extern int64 nLastCoinStakeSearchInterval; +extern unsigned int nStakeTargetSpacing; + +BitcoinGUI::BitcoinGUI(QWidget *parent): + QMainWindow(parent), + clientModel(0), + walletModel(0), + encryptWalletAction(0), + changePassphraseAction(0), + lockWalletToggleAction(0), + aboutQtAction(0), + trayIcon(0), + notificator(0), + rpcConsole(0) +{ + resize(850, 550); + setWindowTitle(tr("triangles") + " - " + tr("Wallet")); +#ifndef Q_OS_MAC + qApp->setWindowIcon(QIcon(":icons/bitcoin")); + setWindowIcon(QIcon(":icons/bitcoin")); +#else + setUnifiedTitleAndToolBarOnMac(true); + QApplication::setAttribute(Qt::AA_DontShowIconsInMenus); +#endif + // Accept D&D of URIs + setAcceptDrops(true); + + setObjectName("trianglesApp"); + //setStyleSheet("#trianglesApp { background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:1, stop:0 #757575, stop:1.0 #979797); } QToolTip { color: #121212; background-color: #545454; border:0px;} "); + setStyleSheet("#trianglesApp { background-color: #B2B2B2; } QToolTip { color: #121212; background-color: #545454; border:0px;} "); + + // Create actions for the toolbar, menu bar and tray/dock icon + createActions(); + + // Create application menu bar + createMenuBar(); + + // Create the toolbars + createToolBars(); + + // Create the tray icon (or setup the dock icon) + createTrayIcon(); + + // Create tabs + overviewPage = new OverviewPage(); + + transactionsPage = new QWidget(this); + QVBoxLayout *vbox = new QVBoxLayout(); + transactionView = new TransactionView(this); + vbox->addWidget(transactionView); + transactionsPage->setLayout(vbox); + + addressBookPage = new AddressBookPage(AddressBookPage::ForEditing, AddressBookPage::SendingTab); + + receiveCoinsPage = new AddressBookPage(AddressBookPage::ForEditing, AddressBookPage::ReceivingTab); + + sendCoinsPage = new SendCoinsDialog(this); + + signVerifyMessageDialog = new SignVerifyMessageDialog(this); + + centralWidget = new QStackedWidget(this); + centralWidget->addWidget(overviewPage); + centralWidget->addWidget(transactionsPage); + centralWidget->addWidget(addressBookPage); + centralWidget->addWidget(receiveCoinsPage); + centralWidget->addWidget(sendCoinsPage); + setCentralWidget(centralWidget); + + // Create status bar + statusBar(); + + // Status bar notification icons + QFrame *frameBlocks = new QFrame(); + frameBlocks->setContentsMargins(0,0,0,0); + frameBlocks->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred); + QHBoxLayout *frameBlocksLayout = new QHBoxLayout(frameBlocks); + frameBlocksLayout->setContentsMargins(3,0,3,0); + frameBlocksLayout->setSpacing(3); + labelEncryptionIcon = new QLabel(); + labelMintingIcon = new QLabel(); + labelConnectionsIcon = new QLabel(); + labelBlocksIcon = new QLabel(); + frameBlocksLayout->addStretch(); + frameBlocksLayout->addWidget(labelEncryptionIcon); + frameBlocksLayout->addStretch(); + frameBlocksLayout->addWidget(labelMintingIcon); + frameBlocksLayout->addStretch(); + frameBlocksLayout->addWidget(labelConnectionsIcon); + frameBlocksLayout->addStretch(); + frameBlocksLayout->addWidget(labelBlocksIcon); + frameBlocksLayout->addStretch(); + + labelEncryptionIcon->setObjectName("labelEncryptionIcon"); + labelConnectionsIcon->setObjectName("labelConnectionsIcon"); + labelBlocksIcon->setObjectName("labelBlocksIcon"); + labelMintingIcon->setObjectName("labelMintingIcon"); + labelEncryptionIcon->setStyleSheet("#labelEncryptionIcon QToolTip {color:#121212;background-color:#545454;border:0px;}"); + labelConnectionsIcon->setStyleSheet("#labelConnectionsIcon QToolTip {color:#121212;background-color:#545454;border:0px;}"); + labelBlocksIcon->setStyleSheet("#labelBlocksIcon QToolTip {color:#121212;background-color:#545454;border:0px;}"); + labelMintingIcon->setStyleSheet("#labelMintingIcon QToolTip {color:#121212;background-color:#545454;border:0px;}"); + + // Set minting pixmap + labelMintingIcon->setPixmap(QIcon(":/icons/minting").pixmap(STATUSBAR_ICONSIZE,STATUSBAR_ICONSIZE)); + labelMintingIcon->setEnabled(false); + // Add timer to update minting icon + QTimer *timerMintingIcon = new QTimer(labelMintingIcon); + timerMintingIcon->start(MODEL_UPDATE_DELAY); + connect(timerMintingIcon, SIGNAL(timeout()), this, SLOT(updateMintingIcon())); + // Add timer to update minting weights + QTimer *timerMintingWeights = new QTimer(labelMintingIcon); + timerMintingWeights->start(30 * 1000); + connect(timerMintingWeights, SIGNAL(timeout()), this, SLOT(updateMintingWeights())); + // Set initial values for user and network weights + nWeight, nNetworkWeight = 0; + + // Progress bar and label for blocks download + progressBarLabel = new QLabel(); + progressBarLabel->setVisible(false); + progressBar = new QProgressBar(); + progressBar->setAlignment(Qt::AlignCenter); + progressBar->setVisible(false); + + // Override style sheet for progress bar for styles that have a segmented progress bar, + // as they make the text unreadable (workaround for issue #1071) + // See https://qt-project.org/doc/qt-4.8/gallery.html + QString curStyle = qApp->style()->metaObject()->className(); + if(curStyle == "QWindowsStyle" || curStyle == "QWindowsXPStyle") + { + progressBar->setStyleSheet("QProgressBar { background-color: #e8e8e8; border: 1px solid grey; border-radius: 7px; padding: 1px; text-align: center; } QProgressBar::chunk { background: QLinearGradient(x1: 0, y1: 0, x2: 1, y2: 0, stop: 0 #FF8000, stop: 1 orange); border-radius: 7px; margin: 0px; }"); + } + + statusBar()->addWidget(progressBarLabel); + statusBar()->addWidget(progressBar); + statusBar()->addPermanentWidget(frameBlocks); + statusBar()->setObjectName("trianglesStatusBar"); + statusBar()->setStyleSheet("#trianglesStatusBar { border-top-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #303030, stop:0.5 #696969, stop:1.0 #696969); border-top-width: 1px; border-top-style: inset; background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #757575, stop:1.0 #979797); color: #b2b2b2; } QToolTip { color: #121212; background-color: #545454; border:0px;}"); + + syncIconMovie = new QMovie(":/movies/update_spinner", "mng", this); + + // Clicking on a transaction on the overview page simply sends you to transaction history page + connect(overviewPage, SIGNAL(transactionClicked(QModelIndex)), this, SLOT(gotoHistoryPage())); + connect(overviewPage, SIGNAL(transactionClicked(QModelIndex)), transactionView, SLOT(focusTransaction(QModelIndex))); + + // Double-clicking on a transaction on the transaction history page shows details + connect(transactionView, SIGNAL(doubleClicked(QModelIndex)), transactionView, SLOT(showDetails())); + + rpcConsole = new RPCConsole(this); + connect(openRPCConsoleAction, SIGNAL(triggered()), rpcConsole, SLOT(show())); + + // Clicking on "Verify Message" in the address book sends you to the verify message tab + connect(addressBookPage, SIGNAL(verifyMessage(QString)), this, SLOT(gotoVerifyMessageTab(QString))); + // Clicking on "Sign Message" in the receive coins page sends you to the sign message tab + connect(receiveCoinsPage, SIGNAL(signMessage(QString)), this, SLOT(gotoSignMessageTab(QString))); + + gotoOverviewPage(); +} + +BitcoinGUI::~BitcoinGUI() +{ + if(trayIcon) // Hide tray icon, as deleting will let it linger until quit (on Ubuntu) + trayIcon->hide(); +#ifdef Q_OS_MAC + delete appMenuBar; +#endif +} + +void BitcoinGUI::createActions() +{ + QActionGroup *tabGroup = new QActionGroup(this); + + overviewAction = new QAction(QIcon(":/icons/overview"), tr("&Overview"), this); + overviewAction->setToolTip(tr("Show general overview of wallet")); + overviewAction->setCheckable(true); + overviewAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_1)); + tabGroup->addAction(overviewAction); + + sendCoinsAction = new QAction(QIcon(":/icons/send"), tr("&Send coins"), this); + sendCoinsAction->setToolTip(tr("Send coins to a triangles address")); + sendCoinsAction->setCheckable(true); + sendCoinsAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_2)); + tabGroup->addAction(sendCoinsAction); + + receiveCoinsAction = new QAction(QIcon(":/icons/receiving_addresses"), tr("&Receive coins"), this); + receiveCoinsAction->setToolTip(tr("Show the list of addresses for receiving payments")); + receiveCoinsAction->setCheckable(true); + receiveCoinsAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_3)); + tabGroup->addAction(receiveCoinsAction); + + historyAction = new QAction(QIcon(":/icons/history"), tr("&Transactions"), this); + historyAction->setToolTip(tr("Browse transaction history")); + historyAction->setCheckable(true); + historyAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_4)); + tabGroup->addAction(historyAction); + + addressBookAction = new QAction(QIcon(":/icons/address-book"), tr("&Address Book"), this); + addressBookAction->setToolTip(tr("Edit the list of stored addresses and labels")); + addressBookAction->setCheckable(true); + addressBookAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_5)); + tabGroup->addAction(addressBookAction); + + connect(overviewAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized())); + connect(overviewAction, SIGNAL(triggered()), this, SLOT(gotoOverviewPage())); + connect(sendCoinsAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized())); + connect(sendCoinsAction, SIGNAL(triggered()), this, SLOT(gotoSendCoinsPage())); + connect(receiveCoinsAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized())); + connect(receiveCoinsAction, SIGNAL(triggered()), this, SLOT(gotoReceiveCoinsPage())); + connect(historyAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized())); + connect(historyAction, SIGNAL(triggered()), this, SLOT(gotoHistoryPage())); + connect(addressBookAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized())); + connect(addressBookAction, SIGNAL(triggered()), this, SLOT(gotoAddressBookPage())); + + quitAction = new QAction(QIcon(":/icons/quit"), tr("E&xit"), this); + quitAction->setToolTip(tr("Quit application")); + quitAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Q)); + quitAction->setMenuRole(QAction::QuitRole); + aboutAction = new QAction(QIcon(":/icons/bitcoin"), tr("&About triangles"), this); + aboutAction->setToolTip(tr("Show information about triangles")); + aboutAction->setMenuRole(QAction::AboutRole); + aboutQtAction = new QAction(QIcon(":/trolltech/qmessagebox/images/qtlogo-64.png"), tr("About &Qt"), this); + aboutQtAction->setToolTip(tr("Show information about Qt")); + aboutQtAction->setMenuRole(QAction::AboutQtRole); + optionsAction = new QAction(QIcon(":/icons/options"), tr("&Options..."), this); + optionsAction->setToolTip(tr("Modify configuration options for triangles")); + optionsAction->setMenuRole(QAction::PreferencesRole); + toggleHideAction = new QAction(QIcon(":/icons/bitcoin"), tr("&Show / Hide"), this); + encryptWalletAction = new QAction(QIcon(":/icons/lock_closed"), tr("&Encrypt Wallet..."), this); + encryptWalletAction->setToolTip(tr("Encrypt or decrypt wallet")); + encryptWalletAction->setCheckable(true); + backupWalletAction = new QAction(QIcon(":/icons/filesave"), tr("&Backup Wallet..."), this); + backupWalletAction->setToolTip(tr("Backup wallet to another location")); + changePassphraseAction = new QAction(QIcon(":/icons/key"), tr("&Change Passphrase..."), this); + changePassphraseAction->setToolTip(tr("Change the passphrase used for wallet encryption")); + lockWalletToggleAction = new QAction(this); + signMessageAction = new QAction(QIcon(":/icons/edit"), tr("Sign &message..."), this); + verifyMessageAction = new QAction(QIcon(":/icons/transaction_0"), tr("&Verify message..."), this); + + exportAction = new QAction(QIcon(":/icons/export"), tr("&Export..."), this); + exportAction->setToolTip(tr("Export the data in the current tab to a file")); + openRPCConsoleAction = new QAction(QIcon(":/icons/debugwindow"), tr("&Debug window"), this); + openRPCConsoleAction->setToolTip(tr("Open debugging and diagnostic console")); + + connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit())); + connect(aboutAction, SIGNAL(triggered()), this, SLOT(aboutClicked())); + connect(aboutQtAction, SIGNAL(triggered()), qApp, SLOT(aboutQt())); + connect(optionsAction, SIGNAL(triggered()), this, SLOT(optionsClicked())); + connect(toggleHideAction, SIGNAL(triggered()), this, SLOT(toggleHidden())); + connect(encryptWalletAction, SIGNAL(triggered(bool)), this, SLOT(encryptWallet(bool))); + connect(backupWalletAction, SIGNAL(triggered()), this, SLOT(backupWallet())); + connect(changePassphraseAction, SIGNAL(triggered()), this, SLOT(changePassphrase())); + connect(lockWalletToggleAction, SIGNAL(triggered()), this, SLOT(lockWalletToggle())); + connect(signMessageAction, SIGNAL(triggered()), this, SLOT(gotoSignMessageTab())); + connect(verifyMessageAction, SIGNAL(triggered()), this, SLOT(gotoVerifyMessageTab())); +} + +void BitcoinGUI::createMenuBar() +{ +#ifdef Q_OS_MAC + // Create a decoupled menu bar on Mac which stays even if the window is closed + appMenuBar = new QMenuBar(); +#else + // Get the main window's menu bar on other platforms + appMenuBar = menuBar(); +#endif + + // Configure the menus + QMenu *file = appMenuBar->addMenu(tr("&File")); + file->addAction(backupWalletAction); + file->addAction(exportAction); + file->addAction(signMessageAction); + file->addAction(verifyMessageAction); + file->addSeparator(); + file->addAction(quitAction); + + QMenu *settings = appMenuBar->addMenu(tr("&Settings")); + settings->addAction(encryptWalletAction); + settings->addAction(changePassphraseAction); + settings->addAction(lockWalletToggleAction); + settings->addSeparator(); + settings->addAction(optionsAction); + + QMenu *help = appMenuBar->addMenu(tr("&Help")); + help->addAction(openRPCConsoleAction); + help->addSeparator(); + help->addAction(aboutAction); + help->addAction(aboutQtAction); + + // QString ss("QMenuBar::item { background-color: #effbef; color: black }"); + // appMenuBar->setStyleSheet(ss); +} + +void BitcoinGUI::createToolBars() +{ + QToolBar *toolbar = addToolBar(tr("Tabs toolbar")); + toolbar->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); + toolbar->addAction(overviewAction); + toolbar->addAction(sendCoinsAction); + toolbar->addAction(receiveCoinsAction); + toolbar->addAction(historyAction); + toolbar->addAction(addressBookAction); + + QToolBar *toolbar2 = addToolBar(tr("Actions toolbar")); + toolbar2->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); + toolbar2->addAction(lockWalletToggleAction); + toolbar2->addAction(exportAction); + + toolbar->setObjectName("tabsToolbar"); + toolbar2->setObjectName("actionsToolbar"); + toolbar->setStyleSheet("QToolButton { min-height:36px;color:#b2b2b2;border:none;margin:0px;padding:0px;} QToolButton:hover { color: #A84408; background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #757575, stop:1.0 #979797); margin:0px; padding:0px; border:none; } QToolButton:checked { color: #A84408; background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #757575, stop:1.0 #979797); margin:0px; padding:0px; border-right-color: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 #3b3b3b, stop:0.5 #6c6c6f, stop:1.0 #6c6c6f);border-right-width:3px;border-right-style:inset; border-left-color: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 #2a2a2a, stop:0.5 #5f5b5b, stop:1.0 #5b5b5e);border-left-width:2px;border-left-style:inset; } QToolButton:pressed { color: #A84408; background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #757575, stop:1.0 #979797); margin:0px; padding:0px; border:none;} QToolButton:selected { color: #ffffff; background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #474748, stop:1.0 #353536); margin:0px;padding:0px;border:none; } #tabsToolbar { min-height:48px; color: #b2b2b2; background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #745445, stop:1.0 #757575); margin:0px; padding:0px; border-top-color: rgba(160, 160, 160, 191); border-top-width: 1px; border-top-style: inset; } QToolBar::handle { background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #745445, stop:1.0 #757575); }"); + toolbar2->setStyleSheet("QToolButton { min-height:36px;color:#b2b2b2;border:none;margin:0px;padding:0px;} QToolButton:hover { color: #A84408; background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #757575, stop:1.0 #979797); margin:0px; padding:0px; border:none; } QToolButton:checked { color: #A84408; background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #757575, stop:1.0 #979797); margin:0px; padding:0px; border-right-color: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 #3b3b3b, stop:0.5 #6c6c6f, stop:1.0 #6c6c6f);border-right-width:3px;border-right-style:inset; border-left-color: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 #2a2a2a, stop:0.5 #5f5b5b, stop:1.0 #5b5b5e);border-left-width:2px;border-left-style:inset; } QToolButton:pressed { color: #A84408; background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #757575, stop:1.0 #979797); margin:0px; padding:0px; border:none;} QToolButton:selected { color: #ffffff; background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #474748, stop:1.0 #353536); margin:0px;padding:0px;border:none; } #actionsToolbar { min-height:48px; color: #b2b2b2; background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #745445, stop:1.0 #757575); margin:0px; padding:0px; border-top-color: rgba(160, 160, 160, 191); border-top-width: 1px; border-top-style: inset; } QToolBar::handle { background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #745445, stop:1.0 #757575); }"); +} + +void BitcoinGUI::setClientModel(ClientModel *clientModel) +{ + this->clientModel = clientModel; + if(clientModel) + { + // Replace some strings and icons, when using the testnet + if(clientModel->isTestNet()) + { + setWindowTitle(windowTitle() + QString(" ") + tr("[testnet]")); +#ifndef Q_OS_MAC + qApp->setWindowIcon(QIcon(":icons/bitcoin_testnet")); + setWindowIcon(QIcon(":icons/bitcoin_testnet")); +#else + MacDockIconHandler::instance()->setIcon(QIcon(":icons/bitcoin_testnet")); +#endif + if(trayIcon) + { + trayIcon->setToolTip(tr("triangles client") + QString(" ") + tr("[testnet]")); + trayIcon->setIcon(QIcon(":/icons/toolbar_testnet")); + toggleHideAction->setIcon(QIcon(":/icons/toolbar_testnet")); + } + + aboutAction->setIcon(QIcon(":/icons/toolbar_testnet")); + } + + // Keep up to date with client + setNumConnections(clientModel->getNumConnections()); + connect(clientModel, SIGNAL(numConnectionsChanged(int)), this, SLOT(setNumConnections(int))); + + setNumBlocks(clientModel->getNumBlocks(), clientModel->getNumBlocksOfPeers()); + connect(clientModel, SIGNAL(numBlocksChanged(int,int)), this, SLOT(setNumBlocks(int,int))); + + // Report errors from network/worker thread + connect(clientModel, SIGNAL(error(QString,QString,bool)), this, SLOT(error(QString,QString,bool))); + + rpcConsole->setClientModel(clientModel); + addressBookPage->setOptionsModel(clientModel->getOptionsModel()); + receiveCoinsPage->setOptionsModel(clientModel->getOptionsModel()); + } +} + +void BitcoinGUI::setWalletModel(WalletModel *walletModel) +{ + this->walletModel = walletModel; + if(walletModel) + { + // Report errors from wallet thread + connect(walletModel, SIGNAL(error(QString,QString,bool)), this, SLOT(error(QString,QString,bool))); + + // Put transaction list in tabs + transactionView->setModel(walletModel); + + overviewPage->setModel(walletModel); + addressBookPage->setModel(walletModel->getAddressTableModel()); + receiveCoinsPage->setModel(walletModel->getAddressTableModel()); + sendCoinsPage->setModel(walletModel); + signVerifyMessageDialog->setModel(walletModel); + + setEncryptionStatus(walletModel->getEncryptionStatus()); + connect(walletModel, SIGNAL(encryptionStatusChanged(int)), this, SLOT(setEncryptionStatus(int))); + + // Balloon pop-up for new transaction + connect(walletModel->getTransactionTableModel(), SIGNAL(rowsInserted(QModelIndex,int,int)), + this, SLOT(incomingTransaction(QModelIndex,int,int))); + + // Ask for passphrase if needed + connect(walletModel, SIGNAL(requireUnlock()), this, SLOT(unlockWallet())); + } +} + +void BitcoinGUI::createTrayIcon() +{ + QMenu *trayIconMenu; +#ifndef Q_OS_MAC + trayIcon = new QSystemTrayIcon(this); + trayIconMenu = new QMenu(this); + trayIcon->setContextMenu(trayIconMenu); + trayIcon->setToolTip(tr("triangles client")); + trayIcon->setIcon(QIcon(":/icons/toolbar")); + connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), + this, SLOT(trayIconActivated(QSystemTrayIcon::ActivationReason))); + trayIcon->show(); +#else + // Note: On Mac, the dock icon is used to provide the tray's functionality. + MacDockIconHandler *dockIconHandler = MacDockIconHandler::instance(); + trayIconMenu = dockIconHandler->dockMenu(); + dockIconHandler->setMainWindow((QMainWindow*)this); +#endif + + // Configuration of the tray icon (or dock icon) icon menu + trayIconMenu->addAction(toggleHideAction); + trayIconMenu->addSeparator(); + trayIconMenu->addAction(sendCoinsAction); + trayIconMenu->addAction(receiveCoinsAction); + trayIconMenu->addSeparator(); + trayIconMenu->addAction(signMessageAction); + trayIconMenu->addAction(verifyMessageAction); + trayIconMenu->addSeparator(); + trayIconMenu->addAction(optionsAction); + trayIconMenu->addAction(openRPCConsoleAction); +#ifndef Q_OS_MAC // This is built-in on Mac + trayIconMenu->addSeparator(); + trayIconMenu->addAction(quitAction); +#endif + + notificator = new Notificator(qApp->applicationName(), trayIcon); +} + +#ifndef Q_OS_MAC +void BitcoinGUI::trayIconActivated(QSystemTrayIcon::ActivationReason reason) +{ + if(reason == QSystemTrayIcon::Trigger) + { + // Click on system tray icon triggers show/hide of the main window + toggleHideAction->trigger(); + } +} +#endif + +void BitcoinGUI::optionsClicked() +{ + if(!clientModel || !clientModel->getOptionsModel()) + return; + OptionsDialog dlg; + dlg.setModel(clientModel->getOptionsModel()); + dlg.exec(); +} + +void BitcoinGUI::aboutClicked() +{ + AboutDialog dlg; + dlg.setModel(clientModel); + dlg.exec(); +} + +void BitcoinGUI::setNumConnections(int count) +{ + QString icon; + switch(count) + { + case 0: icon = ":/icons/connect_0"; break; + case 1: case 2: case 3: icon = ":/icons/connect_1"; break; + case 4: case 5: case 6: icon = ":/icons/connect_2"; break; + case 7: case 8: case 9: icon = ":/icons/connect_3"; break; + default: icon = ":/icons/connect_4"; break; + } + labelConnectionsIcon->setPixmap(QIcon(icon).pixmap(STATUSBAR_ICONSIZE,STATUSBAR_ICONSIZE)); + labelConnectionsIcon->setToolTip(tr("%n active connection(s) to triangles network.", "", count)); +} + +void BitcoinGUI::setNumBlocks(int count, int nTotalBlocks) +{ + // don't show / hide progress bar and its label if we have no connection to the network + if (!clientModel || clientModel->getNumConnections() == 0) + { + progressBarLabel->setVisible(false); + progressBar->setVisible(false); + + return; + } + + QString strStatusBarWarnings = clientModel->getStatusBarWarnings(); + QString tooltip; + + if(count < nTotalBlocks) + { + int nRemainingBlocks = nTotalBlocks - count; + float nPercentageDone = count / (nTotalBlocks * 0.01f); + + if (strStatusBarWarnings.isEmpty()) + { + progressBarLabel->setText(tr("Synchronizing with network...")); + progressBarLabel->setVisible(true); + progressBar->setFormat(tr("~%n block(s) remaining", "", nRemainingBlocks)); + progressBar->setMaximum(nTotalBlocks); + progressBar->setValue(count); + progressBar->setVisible(true); + } + + tooltip = tr("Downloaded %1 of %2 blocks of transaction history (%3% done).").arg(count).arg(nTotalBlocks).arg(nPercentageDone, 0, 'f', 2); + } + else + { + if (strStatusBarWarnings.isEmpty()) + progressBarLabel->setVisible(false); + + progressBar->setVisible(false); + tooltip = tr("Downloaded %1 blocks of transaction history.").arg(count); + } + + // Override progressBarLabel text and hide progress bar, when we have warnings to display + if (!strStatusBarWarnings.isEmpty()) + { + progressBarLabel->setText(strStatusBarWarnings); + progressBarLabel->setVisible(true); + progressBar->setVisible(false); + } + + tooltip = tr("Current difficulty is %1.").arg(clientModel->GetDifficulty()) + QString("
") + tooltip; + + QDateTime lastBlockDate = clientModel->getLastBlockDate(); + int secs = lastBlockDate.secsTo(QDateTime::currentDateTime()); + QString text; + + // Represent time from last generated block in human readable text + if(secs <= 0) + { + // Fully up to date. Leave text empty. + } + else if(secs < 60) + { + text = tr("%n second(s) ago","",secs); + } + else if(secs < 60*60) + { + text = tr("%n minute(s) ago","",secs/60); + } + else if(secs < 24*60*60) + { + text = tr("%n hour(s) ago","",secs/(60*60)); + } + else + { + text = tr("%n day(s) ago","",secs/(60*60*24)); + } + + // Set icon state: spinning if catching up, tick otherwise + if(secs < 90*60 && count >= nTotalBlocks) + { + tooltip = tr("Up to date") + QString(".
") + tooltip; + labelBlocksIcon->setPixmap(QIcon(":/icons/synced").pixmap(STATUSBAR_ICONSIZE, STATUSBAR_ICONSIZE)); + + overviewPage->showOutOfSyncWarning(false); + } + else + { + tooltip = tr("Catching up...") + QString("
") + tooltip; + labelBlocksIcon->setMovie(syncIconMovie); + syncIconMovie->start(); + + overviewPage->showOutOfSyncWarning(true); + } + + if(!text.isEmpty()) + { + tooltip += QString("
"); + tooltip += tr("Last received block was generated %1.").arg(text); + } + + // Don't word-wrap this (fixed-width) tooltip + tooltip = QString("") + tooltip + QString(""); + + labelBlocksIcon->setToolTip(tooltip); + progressBarLabel->setToolTip(tooltip); + progressBar->setToolTip(tooltip); +} + +void BitcoinGUI::error(const QString &title, const QString &message, bool modal) +{ + // Report errors from network/worker thread + if(modal) + { + QMessageBox::critical(this, title, message, QMessageBox::Ok, QMessageBox::Ok); + } else { + notificator->notify(Notificator::Critical, title, message); + } +} + +void BitcoinGUI::changeEvent(QEvent *e) +{ + QMainWindow::changeEvent(e); +#ifndef Q_OS_MAC // Ignored on Mac + if(e->type() == QEvent::WindowStateChange) + { + if(clientModel && clientModel->getOptionsModel()->getMinimizeToTray()) + { + QWindowStateChangeEvent *wsevt = static_cast(e); + if(!(wsevt->oldState() & Qt::WindowMinimized) && isMinimized()) + { + QTimer::singleShot(0, this, SLOT(hide())); + e->ignore(); + } + } + } +#endif +} + +void BitcoinGUI::closeEvent(QCloseEvent *event) +{ + if(clientModel) + { +#ifndef Q_OS_MAC // Ignored on Mac + if(!clientModel->getOptionsModel()->getMinimizeToTray() && + !clientModel->getOptionsModel()->getMinimizeOnClose()) + { + qApp->quit(); + } +#endif + } + QMainWindow::closeEvent(event); +} + +void BitcoinGUI::askFee(qint64 nFeeRequired, bool *payFee) +{ + QString strMessage = + tr("This transaction is over the size limit. You can still send it for a fee of %1, " + "which goes to the nodes that process your transaction and helps to support the network. " + "Do you want to pay the fee?").arg( + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, nFeeRequired)); + QMessageBox::StandardButton retval = QMessageBox::question( + this, tr("Confirm transaction fee"), strMessage, + QMessageBox::Yes|QMessageBox::Cancel, QMessageBox::Yes); + *payFee = (retval == QMessageBox::Yes); +} + +void BitcoinGUI::incomingTransaction(const QModelIndex & parent, int start, int end) +{ + if(!walletModel || !clientModel) + return; + TransactionTableModel *ttm = walletModel->getTransactionTableModel(); + qint64 amount = ttm->index(start, TransactionTableModel::Amount, parent) + .data(Qt::EditRole).toULongLong(); + if(!clientModel->inInitialBlockDownload()) + { + // On new transaction, make an info balloon + // Unless the initial block download is in progress, to prevent balloon-spam + QString date = ttm->index(start, TransactionTableModel::Date, parent) + .data().toString(); + QString type = ttm->index(start, TransactionTableModel::Type, parent) + .data().toString(); + QString address = ttm->index(start, TransactionTableModel::ToAddress, parent) + .data().toString(); + QIcon icon = qvariant_cast(ttm->index(start, + TransactionTableModel::ToAddress, parent) + .data(Qt::DecorationRole)); + + notificator->notify(Notificator::Information, + (amount)<0 ? tr("Sent transaction") : + tr("Incoming transaction"), + tr("Date: %1\n" + "Amount: %2\n" + "Type: %3\n" + "Address: %4\n") + .arg(date) + .arg(BitcoinUnits::formatWithUnit(walletModel->getOptionsModel()->getDisplayUnit(), amount, true)) + .arg(type) + .arg(address), icon); + } +} + +void BitcoinGUI::gotoOverviewPage() +{ + overviewAction->setChecked(true); + centralWidget->setCurrentWidget(overviewPage); + + exportAction->setEnabled(false); + disconnect(exportAction, SIGNAL(triggered()), 0, 0); +} + +void BitcoinGUI::gotoHistoryPage() +{ + historyAction->setChecked(true); + centralWidget->setCurrentWidget(transactionsPage); + + exportAction->setEnabled(true); + disconnect(exportAction, SIGNAL(triggered()), 0, 0); + connect(exportAction, SIGNAL(triggered()), transactionView, SLOT(exportClicked())); +} + +void BitcoinGUI::gotoAddressBookPage() +{ + addressBookAction->setChecked(true); + centralWidget->setCurrentWidget(addressBookPage); + + exportAction->setEnabled(true); + disconnect(exportAction, SIGNAL(triggered()), 0, 0); + connect(exportAction, SIGNAL(triggered()), addressBookPage, SLOT(exportClicked())); +} + +void BitcoinGUI::gotoReceiveCoinsPage() +{ + receiveCoinsAction->setChecked(true); + centralWidget->setCurrentWidget(receiveCoinsPage); + + exportAction->setEnabled(true); + disconnect(exportAction, SIGNAL(triggered()), 0, 0); + connect(exportAction, SIGNAL(triggered()), receiveCoinsPage, SLOT(exportClicked())); +} + +void BitcoinGUI::gotoSendCoinsPage() +{ + sendCoinsAction->setChecked(true); + centralWidget->setCurrentWidget(sendCoinsPage); + + exportAction->setEnabled(false); + disconnect(exportAction, SIGNAL(triggered()), 0, 0); +} + +void BitcoinGUI::gotoSignMessageTab(QString addr) +{ + // call show() in showTab_SM() + signVerifyMessageDialog->showTab_SM(true); + + if(!addr.isEmpty()) + signVerifyMessageDialog->setAddress_SM(addr); +} + +void BitcoinGUI::gotoVerifyMessageTab(QString addr) +{ + // call show() in showTab_VM() + signVerifyMessageDialog->showTab_VM(true); + + if(!addr.isEmpty()) + signVerifyMessageDialog->setAddress_VM(addr); +} + +void BitcoinGUI::dragEnterEvent(QDragEnterEvent *event) +{ + // Accept only URIs + if(event->mimeData()->hasUrls()) + event->acceptProposedAction(); +} + +void BitcoinGUI::dropEvent(QDropEvent *event) +{ + if(event->mimeData()->hasUrls()) + { + int nValidUrisFound = 0; + QList uris = event->mimeData()->urls(); + foreach(const QUrl &uri, uris) + { + if (sendCoinsPage->handleURI(uri.toString())) + nValidUrisFound++; + } + + // if valid URIs were found + if (nValidUrisFound) + gotoSendCoinsPage(); + else + notificator->notify(Notificator::Warning, tr("URI handling"), tr("URI can not be parsed! This can be caused by an invalid triangles address or malformed URI parameters.")); + } + + event->acceptProposedAction(); +} + +void BitcoinGUI::handleURI(QString strURI) +{ + // URI has to be valid + if (sendCoinsPage->handleURI(strURI)) + { + showNormalIfMinimized(); + gotoSendCoinsPage(); + } + else + notificator->notify(Notificator::Warning, tr("URI handling"), tr("URI can not be parsed! This can be caused by an invalid triangles address or malformed URI parameters.")); +} + +void BitcoinGUI::setEncryptionStatus(int status) +{ + switch(status) + { + case WalletModel::Unencrypted: + labelEncryptionIcon->hide(); + encryptWalletAction->setChecked(false); + encryptWalletAction->setEnabled(true); + changePassphraseAction->setEnabled(false); + lockWalletToggleAction->setVisible(false); + break; + case WalletModel::Unlocked: + labelEncryptionIcon->show(); + labelEncryptionIcon->setPixmap(QIcon(":/icons/lock_open").pixmap(STATUSBAR_ICONSIZE,STATUSBAR_ICONSIZE)); + labelEncryptionIcon->setToolTip(tr("Wallet is encrypted and currently unlocked.")); + encryptWalletAction->setChecked(true); + encryptWalletAction->setEnabled(false); // TODO: decrypt currently not supported + changePassphraseAction->setEnabled(true); + lockWalletToggleAction->setVisible(true); + lockWalletToggleAction->setIcon(QIcon(":/icons/lock_closed")); + lockWalletToggleAction->setText(tr("&Lock Wallet")); + lockWalletToggleAction->setToolTip(tr("Lock wallet")); + break; + case WalletModel::Locked: + labelEncryptionIcon->show(); + labelEncryptionIcon->setPixmap(QIcon(":/icons/lock_closed").pixmap(STATUSBAR_ICONSIZE,STATUSBAR_ICONSIZE)); + labelEncryptionIcon->setToolTip(tr("Wallet is encrypted and currently locked.")); + encryptWalletAction->setChecked(true); + encryptWalletAction->setEnabled(false); // TODO: decrypt currently not supported + changePassphraseAction->setEnabled(true); + lockWalletToggleAction->setVisible(true); + lockWalletToggleAction->setIcon(QIcon(":/icons/lock_open")); + lockWalletToggleAction->setText(tr("&Unlock Wallet...")); + lockWalletToggleAction->setToolTip(tr("Unlock wallet")); + break; + } +} + +void BitcoinGUI::encryptWallet(bool status) +{ + if(!walletModel) + return; + AskPassphraseDialog dlg(status ? AskPassphraseDialog::Encrypt: + AskPassphraseDialog::Decrypt, this); + dlg.setModel(walletModel); + dlg.exec(); + + setEncryptionStatus(walletModel->getEncryptionStatus()); +} + +void BitcoinGUI::backupWallet() +{ + QString saveDir = QDesktopServices::storageLocation(QDesktopServices::DocumentsLocation); + QString filename = QFileDialog::getSaveFileName(this, tr("Backup Wallet"), saveDir, tr("Wallet Data (*.dat)")); + if(!filename.isEmpty()) { + if(!walletModel->backupWallet(filename)) { + QMessageBox::warning(this, tr("Backup Failed"), tr("There was an error trying to save the wallet data to the new location.")); + } + } +} + +void BitcoinGUI::changePassphrase() +{ + AskPassphraseDialog dlg(AskPassphraseDialog::ChangePass, this); + dlg.setModel(walletModel); + dlg.exec(); +} + +void BitcoinGUI::lockWalletToggle() +{ + if(!walletModel) + return; + + // Unlock wallet when requested by wallet model + if(walletModel->getEncryptionStatus() == WalletModel::Locked) + { + AskPassphraseDialog::Mode mode = AskPassphraseDialog::UnlockMinting; + AskPassphraseDialog dlg(mode, this); + dlg.setModel(walletModel); + dlg.exec(); + } + else + walletModel->setWalletLocked(true); +} + +void BitcoinGUI::showNormalIfMinimized(bool fToggleHidden) +{ + // activateWindow() (sometimes) helps with keyboard focus on Windows + if (isHidden()) + { + show(); + activateWindow(); + } + else if (isMinimized()) + { + showNormal(); + activateWindow(); + } + else if (GUIUtil::isObscured(this)) + { + raise(); + activateWindow(); + } + else if(fToggleHidden) + hide(); +} + +void BitcoinGUI::toggleHidden() +{ + showNormalIfMinimized(true); +} + +void BitcoinGUI::updateMintingIcon() +{ + if (pwalletMain && pwalletMain->IsLocked()) + { + labelMintingIcon->setToolTip(tr("Not minting because wallet is locked.")); + labelMintingIcon->setEnabled(false); + } + else if (vNodes.empty()) + { + labelMintingIcon->setToolTip(tr("Not minting because wallet is offline.")); + labelMintingIcon->setEnabled(false); + } + else if (IsInitialBlockDownload()) + { + labelMintingIcon->setToolTip(tr("Not minting because wallet is syncing.")); + labelMintingIcon->setEnabled(false); + } + else if (!nWeight) + { + labelMintingIcon->setToolTip(tr("Not minting because you don't have mature coins.")); + labelMintingIcon->setEnabled(false); + } + else if (nLastCoinStakeSearchInterval) + { + uint64 nEstimateTime = nStakeTargetSpacing * nNetworkWeight / nWeight; + + QString text; + if (nEstimateTime < 60) + { + text = tr("%n second(s)", "", nEstimateTime); + } + else if (nEstimateTime < 60*60) + { + text = tr("%n minute(s)", "", nEstimateTime/60); + } + else if (nEstimateTime < 24*60*60) + { + text = tr("%n hour(s)", "", nEstimateTime/(60*60)); + } + else + { + text = tr("%n day(s)", "", nEstimateTime/(60*60*24)); + } + + labelMintingIcon->setEnabled(true); + labelMintingIcon->setToolTip(tr("Minting.
Your weight is %1.
Network weight is %2.
Expected time to earn reward is %3.").arg(nWeight).arg(nNetworkWeight).arg(text)); + } + else + { + labelMintingIcon->setToolTip(tr("Not minting.")); + labelMintingIcon->setEnabled(false); + } +} + +void BitcoinGUI::updateMintingWeights() +{ + // Only update if we have the network's current number of blocks, or weight(s) are zero (fixes lagging GUI) + if ((clientModel && clientModel->getNumBlocks() == clientModel->getNumBlocksOfPeers()) || !nWeight || !nNetworkWeight) + { + nWeight = 0; + + if (pwalletMain) + pwalletMain->GetStakeWeight(*pwalletMain, nMinMax, nMinMax, nWeight); + + nNetworkWeight = GetPoSKernelPS(); + } +} diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h new file mode 100644 index 0000000..395c81a --- /dev/null +++ b/src/qt/bitcoingui.h @@ -0,0 +1,192 @@ +#ifndef BITCOINGUI_H +#define BITCOINGUI_H + +#include +#include + +#include "util.h" // for uint64 + +class TransactionTableModel; +class ClientModel; +class WalletModel; +class TransactionView; +class OverviewPage; +class AddressBookPage; +class SendCoinsDialog; +class SignVerifyMessageDialog; +class Notificator; +class RPCConsole; + +QT_BEGIN_NAMESPACE +class QLabel; +class QLineEdit; +class QTableView; +class QAbstractItemModel; +class QModelIndex; +class QProgressBar; +class QStackedWidget; +class QUrl; +QT_END_NAMESPACE + +/** + Bitcoin GUI main class. This class represents the main window of the Bitcoin UI. It communicates with both the client and + wallet models to give the user an up-to-date view of the current core state. +*/ +class BitcoinGUI : public QMainWindow +{ + Q_OBJECT +public: + explicit BitcoinGUI(QWidget *parent = 0); + ~BitcoinGUI(); + + /** Set the client model. + The client model represents the part of the core that communicates with the P2P network, and is wallet-agnostic. + */ + void setClientModel(ClientModel *clientModel); + /** Set the wallet model. + The wallet model represents a bitcoin wallet, and offers access to the list of transactions, address book and sending + functionality. + */ + void setWalletModel(WalletModel *walletModel); + +protected: + void changeEvent(QEvent *e); + void closeEvent(QCloseEvent *event); + void dragEnterEvent(QDragEnterEvent *event); + void dropEvent(QDropEvent *event); + +private: + ClientModel *clientModel; + WalletModel *walletModel; + + QStackedWidget *centralWidget; + + OverviewPage *overviewPage; + QWidget *transactionsPage; + AddressBookPage *addressBookPage; + AddressBookPage *receiveCoinsPage; + SendCoinsDialog *sendCoinsPage; + SignVerifyMessageDialog *signVerifyMessageDialog; + + QLabel *labelEncryptionIcon; + QLabel *labelMintingIcon; + QLabel *labelConnectionsIcon; + QLabel *labelBlocksIcon; + QLabel *progressBarLabel; + QProgressBar *progressBar; + + QMenuBar *appMenuBar; + QAction *overviewAction; + QAction *historyAction; + QAction *quitAction; + QAction *sendCoinsAction; + QAction *addressBookAction; + QAction *signMessageAction; + QAction *verifyMessageAction; + QAction *aboutAction; + QAction *receiveCoinsAction; + QAction *optionsAction; + QAction *toggleHideAction; + QAction *exportAction; + QAction *encryptWalletAction; + QAction *backupWalletAction; + QAction *changePassphraseAction; + QAction *lockWalletToggleAction; + QAction *aboutQtAction; + QAction *openRPCConsoleAction; + + QSystemTrayIcon *trayIcon; + Notificator *notificator; + TransactionView *transactionView; + RPCConsole *rpcConsole; + + QMovie *syncIconMovie; + + uint64 nMinMax; + uint64 nWeight; + uint64 nNetworkWeight; + + /** Create the main UI actions. */ + void createActions(); + /** Create the menu bar and sub-menus. */ + void createMenuBar(); + /** Create the toolbars */ + void createToolBars(); + /** Create system tray (notification) icon */ + void createTrayIcon(); + +public slots: + /** Set number of connections shown in the UI */ + void setNumConnections(int count); + /** Set number of blocks shown in the UI */ + void setNumBlocks(int count, int nTotalBlocks); + /** Set the encryption status as shown in the UI. + @param[in] status current encryption status + @see WalletModel::EncryptionStatus + */ + void setEncryptionStatus(int status); + + /** Notify the user of an error in the network or transaction handling code. */ + void error(const QString &title, const QString &message, bool modal); + /** Asks the user whether to pay the transaction fee or to cancel the transaction. + It is currently not possible to pass a return value to another thread through + BlockingQueuedConnection, so an indirected pointer is used. + https://bugreports.qt-project.org/browse/QTBUG-10440 + + @param[in] nFeeRequired the required fee + @param[out] payFee true to pay the fee, false to not pay the fee + */ + void askFee(qint64 nFeeRequired, bool *payFee); + void handleURI(QString strURI); + +private slots: + /** Switch to overview (home) page */ + void gotoOverviewPage(); + /** Switch to history (transactions) page */ + void gotoHistoryPage(); + /** Switch to address book page */ + void gotoAddressBookPage(); + /** Switch to receive coins page */ + void gotoReceiveCoinsPage(); + /** Switch to send coins page */ + void gotoSendCoinsPage(); + + /** Show Sign/Verify Message dialog and switch to sign message tab */ + void gotoSignMessageTab(QString addr = ""); + /** Show Sign/Verify Message dialog and switch to verify message tab */ + void gotoVerifyMessageTab(QString addr = ""); + + /** Show configuration dialog */ + void optionsClicked(); + /** Show about dialog */ + void aboutClicked(); +#ifndef Q_OS_MAC + /** Handle tray icon clicked */ + void trayIconActivated(QSystemTrayIcon::ActivationReason reason); +#endif + /** Show incoming transaction notification for new transactions. + + The new items are those between start and end inclusive, under the given parent item. + */ + void incomingTransaction(const QModelIndex & parent, int start, int end); + /** Encrypt the wallet */ + void encryptWallet(bool status); + /** Backup the wallet */ + void backupWallet(); + /** Change encrypted wallet passphrase */ + void changePassphrase(); + /** Toggle unlocking wallet temporarily */ + void lockWalletToggle(); + + /** Show window if hidden, unminimize when minimized, rise when obscured or show if hidden and fToggleHidden is true */ + void showNormalIfMinimized(bool fToggleHidden = false); + /** simply calls showNormalIfMinimized(true) for use in SLOT() macro */ + void toggleHidden(); + + /** Update info about minting */ + void updateMintingIcon(); + /** Update minting weight info */ + void updateMintingWeights(); +}; + +#endif diff --git a/src/qt/bitcoinstrings.cpp b/src/qt/bitcoinstrings.cpp new file mode 100644 index 0000000..bb5985e --- /dev/null +++ b/src/qt/bitcoinstrings.cpp @@ -0,0 +1,177 @@ +#include +// Automatically generated by extract_strings.py +#ifdef __GNUC__ +#define UNUSED __attribute__((unused)) +#else +#define UNUSED +#endif +static const char UNUSED *bitcoin_strings[] = { +QT_TRANSLATE_NOOP("bitcoin-core", "" +"%s, you must set a rpcpassword in the configuration file:\n" +" %s\n" +"It is recommended you use the following random password:\n" +"rpcuser=bitcoinrpc\n" +"rpcpassword=%s\n" +"(you do not need to remember this password)\n" +"If the file does not exist, create it with owner-readable-only file " +"permissions.\n"), +QT_TRANSLATE_NOOP("bitcoin-core", "" +"Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:" +"@STRENGTH)"), +QT_TRANSLATE_NOOP("bitcoin-core", "" +"An error occurred while setting up the RPC port %u for listening on IPv4: %s"), +QT_TRANSLATE_NOOP("bitcoin-core", "" +"An error occurred while setting up the RPC port %u for listening on IPv6, " +"falling back to IPv4: %s"), +QT_TRANSLATE_NOOP("bitcoin-core", "" +"Cannot obtain a lock on data directory %s. triangles is probably already " +"running."), +QT_TRANSLATE_NOOP("bitcoin-core", "" +"Detach block and address databases. Increases shutdown time (default: 0)"), +QT_TRANSLATE_NOOP("bitcoin-core", "" +"Error initializing database environment %s! To recover, BACKUP THAT " +"DIRECTORY, then remove everything from it except for wallet.dat."), +QT_TRANSLATE_NOOP("bitcoin-core", "" +"Error: The transaction was rejected. This might happen if some of the coins " +"in your wallet were already spent, such as if you used a copy of wallet.dat " +"and coins were spent in the copy but not marked as spent here."), +QT_TRANSLATE_NOOP("bitcoin-core", "" +"Error: This transaction requires a transaction fee of at least %s because of " +"its amount, complexity, or use of recently received funds "), +QT_TRANSLATE_NOOP("bitcoin-core", "" +"Error: Wallet unlocked for block minting only, unable to create transaction."), +QT_TRANSLATE_NOOP("bitcoin-core", "" +"Execute command when the best block changes (%s in cmd is replaced by block " +"hash)"), +QT_TRANSLATE_NOOP("bitcoin-core", "" +"Listen for JSON-RPC connections on (default: 33334 or testnet: 33333)"), +QT_TRANSLATE_NOOP("bitcoin-core", "" +"Number of seconds to keep misbehaving peers from reconnecting (default: " +"86400)"), +QT_TRANSLATE_NOOP("bitcoin-core", "" +"Set maximum size of high-priority/low-fee transactions in bytes (default: " +"27000)"), +QT_TRANSLATE_NOOP("bitcoin-core", "" +"Unable to bind to %s on this computer. triangles is probably already running."), +QT_TRANSLATE_NOOP("bitcoin-core", "" +"Warning: -paytxfee is set very high! This is the transaction fee you will " +"pay if you send a transaction."), +QT_TRANSLATE_NOOP("bitcoin-core", "" +"Warning: Please check that your computer's date and time are correct! If " +"your clock is wrong triangles will not work properly."), +QT_TRANSLATE_NOOP("bitcoin-core", "" +"Warning: error reading wallet.dat! All keys read correctly, but transaction " +"data or address book entries might be missing or incorrect."), +QT_TRANSLATE_NOOP("bitcoin-core", "" +"Warning: wallet.dat corrupt, data salvaged! Original wallet.dat saved as " +"wallet.{timestamp}.bak in %s; if your balance or transactions are incorrect " +"you should restore from a backup."), +QT_TRANSLATE_NOOP("bitcoin-core", "" +"You must set rpcpassword= in the configuration file:\n" +"%s\n" +"If the file does not exist, create it with owner-readable-only file " +"permissions."), +QT_TRANSLATE_NOOP("bitcoin-core", "Accept command line and JSON-RPC commands"), +QT_TRANSLATE_NOOP("bitcoin-core", "Accept connections from outside (default: 1 if no -proxy or -connect)"), +QT_TRANSLATE_NOOP("bitcoin-core", "Add a node to connect to and attempt to keep the connection open"), +QT_TRANSLATE_NOOP("bitcoin-core", "Allow DNS lookups for -addnode, -seednode and -connect"), +QT_TRANSLATE_NOOP("bitcoin-core", "Allow JSON-RPC connections from specified IP address"), +QT_TRANSLATE_NOOP("bitcoin-core", "Attempt to recover private keys from a corrupt wallet.dat"), +QT_TRANSLATE_NOOP("bitcoin-core", "Bind to given address. Use [host]:port notation for IPv6"), +QT_TRANSLATE_NOOP("bitcoin-core", "Block creation options:"), +QT_TRANSLATE_NOOP("bitcoin-core", "Cannot downgrade wallet"), +QT_TRANSLATE_NOOP("bitcoin-core", "Cannot initialize keypool"), +QT_TRANSLATE_NOOP("bitcoin-core", "Cannot resolve -bind address: '%s'"), +QT_TRANSLATE_NOOP("bitcoin-core", "Cannot resolve -externalip address: '%s'"), +QT_TRANSLATE_NOOP("bitcoin-core", "Cannot write default address"), +QT_TRANSLATE_NOOP("bitcoin-core", "Connect only to the specified node(s)"), +QT_TRANSLATE_NOOP("bitcoin-core", "Connect through socks proxy"), +QT_TRANSLATE_NOOP("bitcoin-core", "Connect to a node to retrieve peer addresses, and disconnect"), +QT_TRANSLATE_NOOP("bitcoin-core", "Discover own IP address (default: 1 when listening and no -externalip)"), +QT_TRANSLATE_NOOP("bitcoin-core", "Don't generate coins"), +QT_TRANSLATE_NOOP("bitcoin-core", "Done loading"), +QT_TRANSLATE_NOOP("bitcoin-core", "Error loading blkindex.dat"), +QT_TRANSLATE_NOOP("bitcoin-core", "Error loading wallet.dat"), +QT_TRANSLATE_NOOP("bitcoin-core", "Error loading wallet.dat: Wallet corrupted"), +QT_TRANSLATE_NOOP("bitcoin-core", "Error loading wallet.dat: Wallet requires newer version of triangles"), +QT_TRANSLATE_NOOP("bitcoin-core", "Error"), +QT_TRANSLATE_NOOP("bitcoin-core", "Error: Transaction creation failed "), +QT_TRANSLATE_NOOP("bitcoin-core", "Error: Wallet locked, unable to create transaction "), +QT_TRANSLATE_NOOP("bitcoin-core", "Error: could not start node"), +QT_TRANSLATE_NOOP("bitcoin-core", "Failed to listen on any port. Use -listen=0 if you want this."), +QT_TRANSLATE_NOOP("bitcoin-core", "Fee per KB to add to transactions you send"), +QT_TRANSLATE_NOOP("bitcoin-core", "Find peers using DNS lookup (default: 0)"), +QT_TRANSLATE_NOOP("bitcoin-core", "Find peers using internet relay chat (default: 1)"), +QT_TRANSLATE_NOOP("bitcoin-core", "Generate coins"), +QT_TRANSLATE_NOOP("bitcoin-core", "Get help for a command"), +QT_TRANSLATE_NOOP("bitcoin-core", "How many blocks to check at startup (default: 2500, 0 = all)"), +QT_TRANSLATE_NOOP("bitcoin-core", "How thorough the block verification is (0-6, default: 1)"), +QT_TRANSLATE_NOOP("bitcoin-core", "Importing blockchain data file."), +QT_TRANSLATE_NOOP("bitcoin-core", "Importing bootstrap blockchain data file."), +QT_TRANSLATE_NOOP("bitcoin-core", "Imports blocks from external blk000?.dat file"), +QT_TRANSLATE_NOOP("bitcoin-core", "Insufficient funds"), +QT_TRANSLATE_NOOP("bitcoin-core", "Invalid -proxy address: '%s'"), +QT_TRANSLATE_NOOP("bitcoin-core", "Invalid -tor address: '%s'"), +QT_TRANSLATE_NOOP("bitcoin-core", "Invalid amount for -paytxfee=: '%s'"), +QT_TRANSLATE_NOOP("bitcoin-core", "Invalid amount for -reservebalance="), +QT_TRANSLATE_NOOP("bitcoin-core", "Invalid amount"), +QT_TRANSLATE_NOOP("bitcoin-core", "List commands"), +QT_TRANSLATE_NOOP("bitcoin-core", "Listen for connections on (default: 12788 or testnet: 22788)"), +QT_TRANSLATE_NOOP("bitcoin-core", "Loading addresses..."), +QT_TRANSLATE_NOOP("bitcoin-core", "Loading block index..."), +QT_TRANSLATE_NOOP("bitcoin-core", "Loading wallet..."), +QT_TRANSLATE_NOOP("bitcoin-core", "Maintain at most connections to peers (default: 125)"), +QT_TRANSLATE_NOOP("bitcoin-core", "Maximum per-connection receive buffer, *1000 bytes (default: 5000)"), +QT_TRANSLATE_NOOP("bitcoin-core", "Maximum per-connection send buffer, *1000 bytes (default: 1000)"), +QT_TRANSLATE_NOOP("bitcoin-core", "triangles version"), +QT_TRANSLATE_NOOP("bitcoin-core", "triangles"), +QT_TRANSLATE_NOOP("bitcoin-core", "Only connect to nodes in network (IPv4, IPv6 or Tor)"), +QT_TRANSLATE_NOOP("bitcoin-core", "Options:"), +QT_TRANSLATE_NOOP("bitcoin-core", "Output extra debugging information. Implies all other -debug* options"), +QT_TRANSLATE_NOOP("bitcoin-core", "Output extra network debugging information"), +QT_TRANSLATE_NOOP("bitcoin-core", "Password for JSON-RPC connections"), +QT_TRANSLATE_NOOP("bitcoin-core", "Prepend debug output with timestamp"), +QT_TRANSLATE_NOOP("bitcoin-core", "Rescan the block chain for missing wallet transactions"), +QT_TRANSLATE_NOOP("bitcoin-core", "Rescanning..."), +QT_TRANSLATE_NOOP("bitcoin-core", "Run in the background as a daemon and accept commands"), +QT_TRANSLATE_NOOP("bitcoin-core", "SSL options: (see the Bitcoin Wiki for SSL setup instructions)"), +QT_TRANSLATE_NOOP("bitcoin-core", "Select the version of socks proxy to use (4-5, default: 5)"), +QT_TRANSLATE_NOOP("bitcoin-core", "Send command to -server or trianglesd"), +QT_TRANSLATE_NOOP("bitcoin-core", "Send commands to node running on (default: 127.0.0.1)"), +QT_TRANSLATE_NOOP("bitcoin-core", "Send trace/debug info to console instead of debug.log file"), +QT_TRANSLATE_NOOP("bitcoin-core", "Send trace/debug info to debugger"), +QT_TRANSLATE_NOOP("bitcoin-core", "Sending..."), +QT_TRANSLATE_NOOP("bitcoin-core", "Server certificate file (default: server.cert)"), +QT_TRANSLATE_NOOP("bitcoin-core", "Server private key (default: server.pem)"), +QT_TRANSLATE_NOOP("bitcoin-core", "Set database cache size in megabytes (default: 25)"), +QT_TRANSLATE_NOOP("bitcoin-core", "Set database disk log size in megabytes (default: 100)"), +QT_TRANSLATE_NOOP("bitcoin-core", "Set key pool size to (default: 100)"), +QT_TRANSLATE_NOOP("bitcoin-core", "Set maximum block size in bytes (default: 250000)"), +QT_TRANSLATE_NOOP("bitcoin-core", "Set minimum block size in bytes (default: 0)"), +QT_TRANSLATE_NOOP("bitcoin-core", "Shrink debug.log file on client startup (default: 1 when no -debug)"), +QT_TRANSLATE_NOOP("bitcoin-core", "Specify configuration file (default: triangles.conf)"), +QT_TRANSLATE_NOOP("bitcoin-core", "Specify connection timeout in milliseconds (default: 5000)"), +QT_TRANSLATE_NOOP("bitcoin-core", "Specify data directory"), +QT_TRANSLATE_NOOP("bitcoin-core", "Specify pid file (default: trianglesd.pid)"), +QT_TRANSLATE_NOOP("bitcoin-core", "Specify your own public address"), +QT_TRANSLATE_NOOP("bitcoin-core", "This help message"), +QT_TRANSLATE_NOOP("bitcoin-core", "Threshold for disconnecting misbehaving peers (default: 100)"), +QT_TRANSLATE_NOOP("bitcoin-core", "To use the %s option"), +QT_TRANSLATE_NOOP("bitcoin-core", "Unable to bind to %s on this computer (bind returned error %d, %s)"), +QT_TRANSLATE_NOOP("bitcoin-core", "Unable to sign checkpoint, wrong checkpointkey?\n"), +QT_TRANSLATE_NOOP("bitcoin-core", "Unknown -socks proxy version requested: %i"), +QT_TRANSLATE_NOOP("bitcoin-core", "Unknown network specified in -onlynet: '%s'"), +QT_TRANSLATE_NOOP("bitcoin-core", "Upgrade wallet to latest format"), +QT_TRANSLATE_NOOP("bitcoin-core", "Usage:"), +QT_TRANSLATE_NOOP("bitcoin-core", "Use OpenSSL (https) for JSON-RPC connections"), +QT_TRANSLATE_NOOP("bitcoin-core", "Use UPnP to map the listening port (default: 0)"), +QT_TRANSLATE_NOOP("bitcoin-core", "Use UPnP to map the listening port (default: 1 when listening)"), +QT_TRANSLATE_NOOP("bitcoin-core", "Use proxy to reach tor hidden services (default: same as -proxy)"), +QT_TRANSLATE_NOOP("bitcoin-core", "Use the test network"), +QT_TRANSLATE_NOOP("bitcoin-core", "Username for JSON-RPC connections"), +QT_TRANSLATE_NOOP("bitcoin-core", "Verifying database integrity..."), +QT_TRANSLATE_NOOP("bitcoin-core", "Wallet needed to be rewritten: restart triangles to complete"), +QT_TRANSLATE_NOOP("bitcoin-core", "Warning: Disk space is low!"), +QT_TRANSLATE_NOOP("bitcoin-core", "Warning: This version is obsolete, upgrade required!"), +QT_TRANSLATE_NOOP("bitcoin-core", "wallet.dat corrupt, salvage failed"), +}; diff --git a/src/qt/bitcoinunits.cpp b/src/qt/bitcoinunits.cpp new file mode 100644 index 0000000..7563194 --- /dev/null +++ b/src/qt/bitcoinunits.cpp @@ -0,0 +1,181 @@ +#include "bitcoinunits.h" + +#include + +BitcoinUnits::BitcoinUnits(QObject *parent): + QAbstractListModel(parent), + unitlist(availableUnits()) +{ +} + +QList BitcoinUnits::availableUnits() +{ + QList unitlist; + unitlist.append(BTC); + unitlist.append(mBTC); + unitlist.append(uBTC); + return unitlist; +} + +bool BitcoinUnits::valid(int unit) +{ + switch(unit) + { + case BTC: + case mBTC: + case uBTC: + return true; + default: + return false; + } +} + +QString BitcoinUnits::name(int unit) +{ + switch(unit) + { + case BTC: return QString("TRI"); + case mBTC: return QString("mTRI"); + case uBTC: return QString::fromUtf8("μTRI"); + default: return QString("???"); + } +} + +QString BitcoinUnits::description(int unit) +{ + switch(unit) + { + case BTC: return QString("triangles"); + case mBTC: return QString("Milli-triangles (1 / 1,000)"); + case uBTC: return QString("Micro-triangles (1 / 1,000,000)"); + default: return QString("???"); + } +} + +qint64 BitcoinUnits::factor(int unit) +{ + switch(unit) + { + case BTC: return 1000000; + case mBTC: return 1000; + case uBTC: return 1; + default: return 1000000; + } +} + +int BitcoinUnits::amountDigits(int unit) +{ + switch(unit) + { + case BTC: return 8; // 21,000,000 (# digits, without commas) + case mBTC: return 11; // 21,000,000,000 + case uBTC: return 14; // 21,000,000,000,000 + default: return 0; + } +} + +int BitcoinUnits::decimals(int unit) +{ + switch(unit) + { + case BTC: return 6; + case mBTC: return 3; + case uBTC: return 0; + default: return 0; + } +} + +QString BitcoinUnits::format(int unit, qint64 n, bool fPlus) +{ + // Note: not using straight sprintf here because we do NOT want + // localized number formatting. + if(!valid(unit)) + return QString(); // Refuse to format invalid unit + qint64 coin = factor(unit); + int num_decimals = decimals(unit); + qint64 n_abs = (n > 0 ? n : -n); + qint64 quotient = n_abs / coin; + qint64 remainder = n_abs % coin; + QString quotient_str = QString::number(quotient); + QString remainder_str = QString::number(remainder).rightJustified(num_decimals, '0'); + + // Right-trim excess zeros after the decimal point + int nTrim = 0; + for (int i = remainder_str.size()-1; i>=2 && (remainder_str.at(i) == '0'); --i) + ++nTrim; + remainder_str.chop(nTrim); + + if (n < 0) + quotient_str.insert(0, '-'); + else if (fPlus && n > 0) + quotient_str.insert(0, '+'); + return quotient_str + QString(".") + remainder_str; +} + +QString BitcoinUnits::formatWithUnit(int unit, qint64 amount, bool plussign) +{ + return format(unit, amount, plussign) + QString(" ") + name(unit); +} + +bool BitcoinUnits::parse(int unit, const QString &value, qint64 *val_out) +{ + if(!valid(unit) || value.isEmpty()) + return false; // Refuse to parse invalid unit or empty string + int num_decimals = decimals(unit); + QStringList parts = value.split("."); + + if(parts.size() > 2) + { + return false; // More than one dot + } + QString whole = parts[0]; + QString decimals; + + if(parts.size() > 1) + { + decimals = parts[1]; + } + if(decimals.size() > num_decimals) + { + return false; // Exceeds max precision + } + bool ok = false; + QString str = whole + decimals.leftJustified(num_decimals, '0'); + + if(str.size() > 18) + { + return false; // Longer numbers will exceed 63 bits + } + qint64 retvalue = str.toLongLong(&ok); + if(val_out) + { + *val_out = retvalue; + } + return ok; +} + +int BitcoinUnits::rowCount(const QModelIndex &parent) const +{ + Q_UNUSED(parent); + return unitlist.size(); +} + +QVariant BitcoinUnits::data(const QModelIndex &index, int role) const +{ + int row = index.row(); + if(row >= 0 && row < unitlist.size()) + { + Unit unit = unitlist.at(row); + switch(role) + { + case Qt::EditRole: + case Qt::DisplayRole: + return QVariant(name(unit)); + case Qt::ToolTipRole: + return QVariant(description(unit)); + case UnitRole: + return QVariant(static_cast(unit)); + } + } + return QVariant(); +} diff --git a/src/qt/bitcoinunits.h b/src/qt/bitcoinunits.h new file mode 100644 index 0000000..9b7c9e1 --- /dev/null +++ b/src/qt/bitcoinunits.h @@ -0,0 +1,66 @@ +#ifndef BITCOINUNITS_H +#define BITCOINUNITS_H + +#include +#include + +/** Bitcoin unit definitions. Encapsulates parsing and formatting + and serves as list model for drop-down selection boxes. +*/ +class BitcoinUnits: public QAbstractListModel +{ +public: + explicit BitcoinUnits(QObject *parent); + + /** Bitcoin units. + @note Source: https://en.bitcoin.it/wiki/Units . Please add only sensible ones + */ + enum Unit + { + BTC, + mBTC, + uBTC + }; + + //! @name Static API + //! Unit conversion and formatting + ///@{ + + //! Get list of units, for drop-down box + static QList availableUnits(); + //! Is unit ID valid? + static bool valid(int unit); + //! Short name + static QString name(int unit); + //! Longer description + static QString description(int unit); + //! Number of Satoshis (1e-8) per unit + static qint64 factor(int unit); + //! Number of amount digits (to represent max number of coins) + static int amountDigits(int unit); + //! Number of decimals left + static int decimals(int unit); + //! Format as string + static QString format(int unit, qint64 amount, bool plussign=false); + //! Format as string (with unit) + static QString formatWithUnit(int unit, qint64 amount, bool plussign=false); + //! Parse string to coin amount + static bool parse(int unit, const QString &value, qint64 *val_out); + ///@} + + //! @name AbstractListModel implementation + //! List model for unit drop-down selection box. + ///@{ + enum RoleIndex { + /** Unit identifier */ + UnitRole = Qt::UserRole + }; + int rowCount(const QModelIndex &parent) const; + QVariant data(const QModelIndex &index, int role) const; + ///@} +private: + QList unitlist; +}; +typedef BitcoinUnits::Unit BitcoinUnit; + +#endif // BITCOINUNITS_H diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp new file mode 100644 index 0000000..6ea4f83 --- /dev/null +++ b/src/qt/clientmodel.cpp @@ -0,0 +1,205 @@ +#include "clientmodel.h" +#include "guiconstants.h" +#include "optionsmodel.h" +#include "addresstablemodel.h" +#include "transactiontablemodel.h" + +#include "alert.h" +#include "main.h" +#include "ui_interface.h" + +#include +#include + +static const int64 nClientStartupTime = GetTime(); + +ClientModel::ClientModel(OptionsModel *optionsModel, QObject *parent) : + QObject(parent), optionsModel(optionsModel), + cachedNumBlocks(0), cachedNumBlocksOfPeers(0), pollTimer(0) +{ + numBlocksAtStartup = -1; + + pollTimer = new QTimer(this); + pollTimer->setInterval(MODEL_UPDATE_DELAY); + pollTimer->start(); + connect(pollTimer, SIGNAL(timeout()), this, SLOT(updateTimer())); + + subscribeToCoreSignals(); +} + +ClientModel::~ClientModel() +{ + unsubscribeFromCoreSignals(); +} + +int ClientModel::getNumConnections() const +{ + return vNodes.size(); +} + +int ClientModel::getNumBlocks() const +{ + return nBestHeight; +} + +int ClientModel::getNumBlocksAtStartup() +{ + if (numBlocksAtStartup == -1) numBlocksAtStartup = getNumBlocks(); + return numBlocksAtStartup; +} + +QDateTime ClientModel::getLastBlockDate() const +{ + return QDateTime::fromTime_t(pindexBest->GetBlockTime()); +} + +void ClientModel::updateTimer() +{ + // Some quantities (such as number of blocks) change so fast that we don't want to be notified for each change. + // Periodically check and update with a timer. + int newNumBlocks = getNumBlocks(); + int newNumBlocksOfPeers = getNumBlocksOfPeers(); + + if(cachedNumBlocks != newNumBlocks || cachedNumBlocksOfPeers != newNumBlocksOfPeers) + { + cachedNumBlocks = newNumBlocks; + cachedNumBlocksOfPeers = newNumBlocksOfPeers; + + emit numBlocksChanged(newNumBlocks, newNumBlocksOfPeers); + } +} + +void ClientModel::updateNumConnections(int numConnections) +{ + emit numConnectionsChanged(numConnections); +} + +void ClientModel::updateAlert(const QString &hash, int status) +{ + // Show error message notification for new alert + if(status == CT_NEW) + { + uint256 hash_256; + hash_256.SetHex(hash.toStdString()); + CAlert alert = CAlert::getAlertByHash(hash_256); + if(!alert.IsNull()) + { + emit error(tr("Network Alert"), QString::fromStdString(alert.strStatusBar), false); + } + } + + // Emit a numBlocksChanged when the status message changes, + // so that the view recomputes and updates the status bar. + emit numBlocksChanged(getNumBlocks(), getNumBlocksOfPeers()); +} + + +double ClientModel::GetDifficulty() const +{ + // Floating point number that is a multiple of the minimum difficulty, + // minimum difficulty = 1.0. + + if (pindexBest == NULL) + return 1.0; + int nShift = (pindexBest->nBits >> 24) & 0xff; + + double dDiff = + (double)0x0000ffff / (double)(pindexBest->nBits & 0x00ffffff); + + while (nShift < 29) + { + dDiff *= 256.0; + nShift++; + } + while (nShift > 29) + { + dDiff /= 256.0; + nShift--; + } + + return dDiff; +} + + +bool ClientModel::isTestNet() const +{ + return fTestNet; +} + +bool ClientModel::inInitialBlockDownload() const +{ + return IsInitialBlockDownload(); +} + +int ClientModel::getNumBlocksOfPeers() const +{ + return GetNumBlocksOfPeers(); +} + +QString ClientModel::getStatusBarWarnings() const +{ + return QString::fromStdString(GetWarnings("statusbar")); +} + +OptionsModel *ClientModel::getOptionsModel() +{ + return optionsModel; +} + +QString ClientModel::formatFullVersion() const +{ + return QString::fromStdString(FormatFullVersion()); +} + +QString ClientModel::formatBuildDate() const +{ + return QString::fromStdString(CLIENT_DATE); +} + +QString ClientModel::clientName() const +{ + return QString::fromStdString(CLIENT_NAME); +} + +QString ClientModel::formatClientStartupTime() const +{ + return QDateTime::fromTime_t(nClientStartupTime).toString(); +} + +// Handlers for core signals +static void NotifyBlocksChanged(ClientModel *clientmodel) +{ + // This notification is too frequent. Don't trigger a signal. + // Don't remove it, though, as it might be useful later. +} + +static void NotifyNumConnectionsChanged(ClientModel *clientmodel, int newNumConnections) +{ + // Too noisy: OutputDebugStringF("NotifyNumConnectionsChanged %i\n", newNumConnections); + QMetaObject::invokeMethod(clientmodel, "updateNumConnections", Qt::QueuedConnection, + Q_ARG(int, newNumConnections)); +} + +static void NotifyAlertChanged(ClientModel *clientmodel, const uint256 &hash, ChangeType status) +{ + OutputDebugStringF("NotifyAlertChanged %s status=%i\n", hash.GetHex().c_str(), status); + QMetaObject::invokeMethod(clientmodel, "updateAlert", Qt::QueuedConnection, + Q_ARG(QString, QString::fromStdString(hash.GetHex())), + Q_ARG(int, status)); +} + +void ClientModel::subscribeToCoreSignals() +{ + // Connect signals to client + uiInterface.NotifyBlocksChanged.connect(boost::bind(NotifyBlocksChanged, this)); + uiInterface.NotifyNumConnectionsChanged.connect(boost::bind(NotifyNumConnectionsChanged, this, _1)); + uiInterface.NotifyAlertChanged.connect(boost::bind(NotifyAlertChanged, this, _1, _2)); +} + +void ClientModel::unsubscribeFromCoreSignals() +{ + // Disconnect signals from client + uiInterface.NotifyBlocksChanged.disconnect(boost::bind(NotifyBlocksChanged, this)); + uiInterface.NotifyNumConnectionsChanged.disconnect(boost::bind(NotifyNumConnectionsChanged, this, _1)); + uiInterface.NotifyAlertChanged.disconnect(boost::bind(NotifyAlertChanged, this, _1, _2)); +} diff --git a/src/qt/clientmodel.h b/src/qt/clientmodel.h new file mode 100644 index 0000000..dd27de6 --- /dev/null +++ b/src/qt/clientmodel.h @@ -0,0 +1,72 @@ +#ifndef CLIENTMODEL_H +#define CLIENTMODEL_H + +#include + +class OptionsModel; +class AddressTableModel; +class TransactionTableModel; +class CWallet; + +QT_BEGIN_NAMESPACE +class QDateTime; +class QTimer; +QT_END_NAMESPACE + +/** Model for Bitcoin network client. */ +class ClientModel : public QObject +{ + Q_OBJECT +public: + explicit ClientModel(OptionsModel *optionsModel, QObject *parent = 0); + ~ClientModel(); + + OptionsModel *getOptionsModel(); + + int getNumConnections() const; + int getNumBlocks() const; + int getNumBlocksAtStartup(); + + QDateTime getLastBlockDate() const; + + //! Return true if client connected to testnet + bool isTestNet() const; + //! Return true if core is doing initial block download + bool inInitialBlockDownload() const; + //! Return conservative estimate of total number of blocks, or 0 if unknown + int getNumBlocksOfPeers() const; + //! Return warnings to be displayed in status bar + QString getStatusBarWarnings() const; + + QString formatFullVersion() const; + QString formatBuildDate() const; + QString clientName() const; + QString formatClientStartupTime() const; + double GetDifficulty() const; + +private: + OptionsModel *optionsModel; + + int cachedNumBlocks; + int cachedNumBlocksOfPeers; + + int numBlocksAtStartup; + + QTimer *pollTimer; + + void subscribeToCoreSignals(); + void unsubscribeFromCoreSignals(); +signals: + void numConnectionsChanged(int count); + void numBlocksChanged(int count, int countOfPeers); + + //! Asynchronous error notification + void error(const QString &title, const QString &message, bool modal); + +public slots: + void updateTimer(); + void updateNumConnections(int numConnections); + void updateAlert(const QString &hash, int status); +}; + +#endif // CLIENTMODEL_H diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp new file mode 100644 index 0000000..2df3c64 --- /dev/null +++ b/src/qt/coincontroldialog.cpp @@ -0,0 +1,738 @@ +#include "coincontroldialog.h" +#include "ui_coincontroldialog.h" + +#include "init.h" +#include "bitcoinunits.h" +#include "walletmodel.h" +#include "addresstablemodel.h" +#include "optionsmodel.h" +#include "coincontrol.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; +QList CoinControlDialog::payAmounts; +CCoinControl* CoinControlDialog::coinControl = new CCoinControl(); + +CoinControlDialog::CoinControlDialog(QWidget *parent) : + QDialog(parent), + ui(new Ui::CoinControlDialog), + model(0) +{ + ui->setupUi(this); + + // context menu actions + QAction *copyAddressAction = new QAction(tr("Copy address"), this); + QAction *copyLabelAction = new QAction(tr("Copy label"), this); + QAction *copyAmountAction = new QAction(tr("Copy amount"), this); + copyTransactionHashAction = new QAction(tr("Copy transaction ID"), this); // we need to enable/disable this + //lockAction = new QAction(tr("Lock unspent"), this); // we need to enable/disable this + //unlockAction = new QAction(tr("Unlock unspent"), this); // we need to enable/disable this + + // context menu + contextMenu = new QMenu(); + contextMenu->addAction(copyAddressAction); + contextMenu->addAction(copyLabelAction); + contextMenu->addAction(copyAmountAction); + contextMenu->addAction(copyTransactionHashAction); + //contextMenu->addSeparator(); + //contextMenu->addAction(lockAction); + //contextMenu->addAction(unlockAction); + + // context menu signals + connect(ui->treeWidget, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showMenu(QPoint))); + connect(copyAddressAction, SIGNAL(triggered()), this, SLOT(copyAddress())); + connect(copyLabelAction, SIGNAL(triggered()), this, SLOT(copyLabel())); + connect(copyAmountAction, SIGNAL(triggered()), this, SLOT(copyAmount())); + connect(copyTransactionHashAction, SIGNAL(triggered()), this, SLOT(copyTransactionHash())); + //connect(lockAction, SIGNAL(triggered()), this, SLOT(lockCoin())); + //connect(unlockAction, SIGNAL(triggered()), this, SLOT(unlockCoin())); + + // clipboard actions + QAction *clipboardQuantityAction = new QAction(tr("Copy quantity"), this); + QAction *clipboardAmountAction = new QAction(tr("Copy amount"), this); + QAction *clipboardFeeAction = new QAction(tr("Copy fee"), this); + QAction *clipboardAfterFeeAction = new QAction(tr("Copy after fee"), this); + QAction *clipboardBytesAction = new QAction(tr("Copy bytes"), this); + QAction *clipboardPriorityAction = new QAction(tr("Copy priority"), this); + QAction *clipboardLowOutputAction = new QAction(tr("Copy low output"), this); + QAction *clipboardChangeAction = new QAction(tr("Copy change"), this); + + connect(clipboardQuantityAction, SIGNAL(triggered()), this, SLOT(clipboardQuantity())); + connect(clipboardAmountAction, SIGNAL(triggered()), this, SLOT(clipboardAmount())); + connect(clipboardFeeAction, SIGNAL(triggered()), this, SLOT(clipboardFee())); + connect(clipboardAfterFeeAction, SIGNAL(triggered()), this, SLOT(clipboardAfterFee())); + connect(clipboardBytesAction, SIGNAL(triggered()), this, SLOT(clipboardBytes())); + connect(clipboardPriorityAction, SIGNAL(triggered()), this, SLOT(clipboardPriority())); + connect(clipboardLowOutputAction, SIGNAL(triggered()), this, SLOT(clipboardLowOutput())); + connect(clipboardChangeAction, SIGNAL(triggered()), this, SLOT(clipboardChange())); + + ui->labelCoinControlQuantity->addAction(clipboardQuantityAction); + ui->labelCoinControlAmount->addAction(clipboardAmountAction); + ui->labelCoinControlFee->addAction(clipboardFeeAction); + ui->labelCoinControlAfterFee->addAction(clipboardAfterFeeAction); + ui->labelCoinControlBytes->addAction(clipboardBytesAction); + ui->labelCoinControlPriority->addAction(clipboardPriorityAction); + ui->labelCoinControlLowOutput->addAction(clipboardLowOutputAction); + ui->labelCoinControlChange->addAction(clipboardChangeAction); + + // toggle tree/list mode + connect(ui->radioTreeMode, SIGNAL(toggled(bool)), this, SLOT(radioTreeMode(bool))); + connect(ui->radioListMode, SIGNAL(toggled(bool)), this, SLOT(radioListMode(bool))); + + // click on checkbox + connect(ui->treeWidget, SIGNAL(itemChanged( QTreeWidgetItem*, int)), this, SLOT(viewItemChanged( QTreeWidgetItem*, int))); + + // click on header + ui->treeWidget->header()->setClickable(true); + connect(ui->treeWidget->header(), SIGNAL(sectionClicked(int)), this, SLOT(headerSectionClicked(int))); + + // ok button + connect(ui->buttonBox, SIGNAL(clicked( QAbstractButton*)), this, SLOT(buttonBoxClicked(QAbstractButton*))); + + // (un)select all + connect(ui->pushButtonSelectAll, SIGNAL(clicked()), this, SLOT(buttonSelectAllClicked())); + + ui->treeWidget->setColumnWidth(COLUMN_CHECKBOX, 84); + ui->treeWidget->setColumnWidth(COLUMN_AMOUNT, 100); + ui->treeWidget->setColumnWidth(COLUMN_LABEL, 170); + ui->treeWidget->setColumnWidth(COLUMN_ADDRESS, 290); + ui->treeWidget->setColumnWidth(COLUMN_DATE, 110); + ui->treeWidget->setColumnWidth(COLUMN_CONFIRMATIONS, 100); + ui->treeWidget->setColumnWidth(COLUMN_PRIORITY, 100); + ui->treeWidget->setColumnHidden(COLUMN_TXHASH, true); // store transacton hash in this column, but dont show it + ui->treeWidget->setColumnHidden(COLUMN_VOUT_INDEX, true); // store vout index in this column, but dont show it + ui->treeWidget->setColumnHidden(COLUMN_AMOUNT_INT64, true); // store amount int64 in this column, but dont show it + ui->treeWidget->setColumnHidden(COLUMN_PRIORITY_INT64, true); // store priority int64 in this column, but dont show it + + // default view is sorted by amount desc + sortView(COLUMN_AMOUNT_INT64, Qt::DescendingOrder); +} + +CoinControlDialog::~CoinControlDialog() +{ + delete ui; +} + +void CoinControlDialog::setModel(WalletModel *model) +{ + this->model = model; + + if(model && model->getOptionsModel() && model->getAddressTableModel()) + { + updateView(); + //updateLabelLocked(); + CoinControlDialog::updateLabels(model, this); + } +} + +// helper function str_pad +QString CoinControlDialog::strPad(QString s, int nPadLength, QString sPadding) +{ + while (s.length() < nPadLength) + s = sPadding + s; + + return s; +} + +// ok button +void CoinControlDialog::buttonBoxClicked(QAbstractButton* button) +{ + if (ui->buttonBox->buttonRole(button) == QDialogButtonBox::AcceptRole) + done(QDialog::Accepted); // closes the dialog +} + +// (un)select all +void CoinControlDialog::buttonSelectAllClicked() +{ + Qt::CheckState state = Qt::Checked; + for (int i = 0; i < ui->treeWidget->topLevelItemCount(); i++) + { + if (ui->treeWidget->topLevelItem(i)->checkState(COLUMN_CHECKBOX) != Qt::Unchecked) + { + state = Qt::Unchecked; + break; + } + } + ui->treeWidget->setEnabled(false); + for (int i = 0; i < ui->treeWidget->topLevelItemCount(); i++) + if (ui->treeWidget->topLevelItem(i)->checkState(COLUMN_CHECKBOX) != state) + ui->treeWidget->topLevelItem(i)->setCheckState(COLUMN_CHECKBOX, state); + ui->treeWidget->setEnabled(true); + CoinControlDialog::updateLabels(model, this); +} + +// context menu +void CoinControlDialog::showMenu(const QPoint &point) +{ + QTreeWidgetItem *item = ui->treeWidget->itemAt(point); + if(item) + { + contextMenuItem = item; + + // disable some items (like Copy Transaction ID, lock, unlock) for tree roots in context menu + if (item->text(COLUMN_TXHASH).length() == 64) // transaction hash is 64 characters (this means its a child node, so its not a parent node in tree mode) + { + copyTransactionHashAction->setEnabled(true); + //if (model->isLockedCoin(uint256(item->text(COLUMN_TXHASH).toStdString()), item->text(COLUMN_VOUT_INDEX).toUInt())) + //{ + // lockAction->setEnabled(false); + // unlockAction->setEnabled(true); + //} + //else + //{ + // lockAction->setEnabled(true); + // unlockAction->setEnabled(false); + //} + } + else // this means click on parent node in tree mode -> disable all + { + copyTransactionHashAction->setEnabled(false); + //lockAction->setEnabled(false); + //unlockAction->setEnabled(false); + } + + // show context menu + contextMenu->exec(QCursor::pos()); + } +} + +// context menu action: copy amount +void CoinControlDialog::copyAmount() +{ + QApplication::clipboard()->setText(contextMenuItem->text(COLUMN_AMOUNT)); +} + +// context menu action: copy label +void CoinControlDialog::copyLabel() +{ + if (ui->radioTreeMode->isChecked() && contextMenuItem->text(COLUMN_LABEL).length() == 0 && contextMenuItem->parent()) + QApplication::clipboard()->setText(contextMenuItem->parent()->text(COLUMN_LABEL)); + else + QApplication::clipboard()->setText(contextMenuItem->text(COLUMN_LABEL)); +} + +// context menu action: copy address +void CoinControlDialog::copyAddress() +{ + if (ui->radioTreeMode->isChecked() && contextMenuItem->text(COLUMN_ADDRESS).length() == 0 && contextMenuItem->parent()) + QApplication::clipboard()->setText(contextMenuItem->parent()->text(COLUMN_ADDRESS)); + else + QApplication::clipboard()->setText(contextMenuItem->text(COLUMN_ADDRESS)); +} + +// context menu action: copy transaction id +void CoinControlDialog::copyTransactionHash() +{ + QApplication::clipboard()->setText(contextMenuItem->text(COLUMN_TXHASH)); +} + +// context menu action: lock coin +/*void CoinControlDialog::lockCoin() +{ + if (contextMenuItem->checkState(COLUMN_CHECKBOX) == Qt::Checked) + contextMenuItem->setCheckState(COLUMN_CHECKBOX, Qt::Unchecked); + + COutPoint outpt(uint256(contextMenuItem->text(COLUMN_TXHASH).toStdString()), contextMenuItem->text(COLUMN_VOUT_INDEX).toUInt()); + model->lockCoin(outpt); + contextMenuItem->setDisabled(true); + contextMenuItem->setIcon(COLUMN_CHECKBOX, QIcon(":/icons/lock_closed")); + updateLabelLocked(); +}*/ + +// context menu action: unlock coin +/*void CoinControlDialog::unlockCoin() +{ + COutPoint outpt(uint256(contextMenuItem->text(COLUMN_TXHASH).toStdString()), contextMenuItem->text(COLUMN_VOUT_INDEX).toUInt()); + model->unlockCoin(outpt); + contextMenuItem->setDisabled(false); + contextMenuItem->setIcon(COLUMN_CHECKBOX, QIcon()); + updateLabelLocked(); +}*/ + +// copy label "Quantity" to clipboard +void CoinControlDialog::clipboardQuantity() +{ + QApplication::clipboard()->setText(ui->labelCoinControlQuantity->text()); +} + +// copy label "Amount" to clipboard +void CoinControlDialog::clipboardAmount() +{ + QApplication::clipboard()->setText(ui->labelCoinControlAmount->text().left(ui->labelCoinControlAmount->text().indexOf(" "))); +} + +// copy label "Fee" to clipboard +void CoinControlDialog::clipboardFee() +{ + QApplication::clipboard()->setText(ui->labelCoinControlFee->text().left(ui->labelCoinControlFee->text().indexOf(" "))); +} + +// copy label "After fee" to clipboard +void CoinControlDialog::clipboardAfterFee() +{ + QApplication::clipboard()->setText(ui->labelCoinControlAfterFee->text().left(ui->labelCoinControlAfterFee->text().indexOf(" "))); +} + +// copy label "Bytes" to clipboard +void CoinControlDialog::clipboardBytes() +{ + QApplication::clipboard()->setText(ui->labelCoinControlBytes->text()); +} + +// copy label "Priority" to clipboard +void CoinControlDialog::clipboardPriority() +{ + QApplication::clipboard()->setText(ui->labelCoinControlPriority->text()); +} + +// copy label "Low output" to clipboard +void CoinControlDialog::clipboardLowOutput() +{ + QApplication::clipboard()->setText(ui->labelCoinControlLowOutput->text()); +} + +// copy label "Change" to clipboard +void CoinControlDialog::clipboardChange() +{ + QApplication::clipboard()->setText(ui->labelCoinControlChange->text().left(ui->labelCoinControlChange->text().indexOf(" "))); +} + +// treeview: sort +void CoinControlDialog::sortView(int column, Qt::SortOrder order) +{ + sortColumn = column; + sortOrder = order; + ui->treeWidget->sortItems(column, order); + ui->treeWidget->header()->setSortIndicator((sortColumn == COLUMN_AMOUNT_INT64 ? COLUMN_AMOUNT : (sortColumn == COLUMN_PRIORITY_INT64 ? COLUMN_PRIORITY : sortColumn)), sortOrder); +} + +// treeview: clicked on header +void CoinControlDialog::headerSectionClicked(int logicalIndex) +{ + if (logicalIndex == COLUMN_CHECKBOX) // click on most left column -> do nothing + { + ui->treeWidget->header()->setSortIndicator((sortColumn == COLUMN_AMOUNT_INT64 ? COLUMN_AMOUNT : (sortColumn == COLUMN_PRIORITY_INT64 ? COLUMN_PRIORITY : sortColumn)), sortOrder); + } + else + { + if (logicalIndex == COLUMN_AMOUNT) // sort by amount + logicalIndex = COLUMN_AMOUNT_INT64; + + if (logicalIndex == COLUMN_PRIORITY) // sort by priority + logicalIndex = COLUMN_PRIORITY_INT64; + + if (sortColumn == logicalIndex) + sortOrder = ((sortOrder == Qt::AscendingOrder) ? Qt::DescendingOrder : Qt::AscendingOrder); + else + { + sortColumn = logicalIndex; + sortOrder = ((sortColumn == COLUMN_AMOUNT_INT64 || sortColumn == COLUMN_PRIORITY_INT64 || sortColumn == COLUMN_DATE || sortColumn == COLUMN_CONFIRMATIONS) ? Qt::DescendingOrder : Qt::AscendingOrder); // if amount,date,conf,priority then default => desc, else default => asc + } + + sortView(sortColumn, sortOrder); + } +} + +// toggle tree mode +void CoinControlDialog::radioTreeMode(bool checked) +{ + if (checked && model) + updateView(); +} + +// toggle list mode +void CoinControlDialog::radioListMode(bool checked) +{ + if (checked && model) + updateView(); +} + +// checkbox clicked by user +void CoinControlDialog::viewItemChanged(QTreeWidgetItem* item, int column) +{ + if (column == COLUMN_CHECKBOX && item->text(COLUMN_TXHASH).length() == 64) // transaction hash is 64 characters (this means its a child node, so its not a parent node in tree mode) + { + COutPoint outpt(uint256(item->text(COLUMN_TXHASH).toStdString()), item->text(COLUMN_VOUT_INDEX).toUInt()); + + if (item->checkState(COLUMN_CHECKBOX) == Qt::Unchecked) + coinControl->UnSelect(outpt); + else if (item->isDisabled()) // locked (this happens if "check all" through parent node) + item->setCheckState(COLUMN_CHECKBOX, Qt::Unchecked); + else + coinControl->Select(outpt); + + // selection changed -> update labels + if (ui->treeWidget->isEnabled()) // do not update on every click for (un)select all + CoinControlDialog::updateLabels(model, this); + } +} + +// helper function, return human readable label for priority number +QString CoinControlDialog::getPriorityLabel(double dPriority) +{ + if (dPriority > 576000ULL) // at least medium, this number is from AllowFree(), the other thresholds are kinda random + { + if (dPriority > 5760000000ULL) return tr("highest"); + else if (dPriority > 576000000ULL) return tr("high"); + else if (dPriority > 57600000ULL) return tr("medium-high"); + else return tr("medium"); + } + else + { + if (dPriority > 5760ULL) return tr("low-medium"); + else if (dPriority > 58ULL) return tr("low"); + else return tr("lowest"); + } +} + +// shows count of locked unspent outputs +/*void CoinControlDialog::updateLabelLocked() +{ + vector vOutpts; + model->listLockedCoins(vOutpts); + if (vOutpts.size() > 0) + { + ui->labelLocked->setText(tr("(%1 locked)").arg(vOutpts.size())); + ui->labelLocked->setVisible(true); + } + else ui->labelLocked->setVisible(false); +}*/ + +void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog) +{ + if (!model) return; + + // nPayAmount + qint64 nPayAmount = 0; + bool fLowOutput = false; + bool fDust = false; + CTransaction txDummy; + foreach(const qint64 &amount, CoinControlDialog::payAmounts) + { + nPayAmount += amount; + + if (amount > 0) + { + if (amount < CENT) + fLowOutput = true; + + CTxOut txout(amount, (CScript)vector(24, 0)); + txDummy.vout.push_back(txout); + } + } + + QString sPriorityLabel = ""; + int64 nAmount = 0; + int64 nPayFee = 0; + int64 nAfterFee = 0; + int64 nChange = 0; + unsigned int nBytes = 0; + unsigned int nBytesInputs = 0; + double dPriority = 0; + double dPriorityInputs = 0; + unsigned int nQuantity = 0; + + vector vCoinControl; + vector vOutputs; + coinControl->ListSelected(vCoinControl); + model->getOutputs(vCoinControl, vOutputs); + + BOOST_FOREACH(const COutput& out, vOutputs) + { + // Quantity + nQuantity++; + + // Amount + nAmount += out.tx->vout[out.i].nValue; + + // Priority + dPriorityInputs += (double)out.tx->vout[out.i].nValue * (out.nDepth+1); + + // Bytes + CTxDestination address; + if(ExtractDestination(out.tx->vout[out.i].scriptPubKey, address)) + { + CPubKey pubkey; + CKeyID *keyid = boost::get< CKeyID >(&address); + if (keyid && model->getPubKey(*keyid, pubkey)) + nBytesInputs += (pubkey.IsCompressed() ? 148 : 180); + else + nBytesInputs += 148; // in all error cases, simply assume 148 here + } + else nBytesInputs += 148; + } + + // calculation + if (nQuantity > 0) + { + // Bytes + nBytes = nBytesInputs + ((CoinControlDialog::payAmounts.size() > 0 ? CoinControlDialog::payAmounts.size() + 1 : 2) * 34) + 10; // always assume +1 output for change here + + // Priority + dPriority = dPriorityInputs / nBytes; + sPriorityLabel = CoinControlDialog::getPriorityLabel(dPriority); + + // Fee + int64 nFee = nTransactionFee * (1 + (int64)nBytes / 1000); + + // Min Fee + int64 nMinFee = txDummy.GetMinFee(1, false, GMF_SEND, nBytes); + + nPayFee = max(nFee, nMinFee); + + if (nPayAmount > 0) + { + nChange = nAmount - nPayFee - nPayAmount; + + // if sub-cent change is required, the fee must be raised to at least CTransaction::nMinTxFee + if (nPayFee < CENT && nChange > 0 && nChange < CENT) + { + if (nChange < CENT) // change < 0.01 => simply move all change to fees + { + nPayFee = nChange; + nChange = 0; + } + else + { + nChange = nChange + nPayFee - CENT; + nPayFee = CENT; + } + } + + if (nChange == 0) + nBytes -= 34; + } + + // after fee + nAfterFee = nAmount - nPayFee; + if (nAfterFee < 0) + nAfterFee = 0; + } + + // actually update labels + int nDisplayUnit = BitcoinUnits::BTC; + if (model && model->getOptionsModel()) + nDisplayUnit = model->getOptionsModel()->getDisplayUnit(); + + QLabel *l1 = dialog->findChild("labelCoinControlQuantity"); + QLabel *l2 = dialog->findChild("labelCoinControlAmount"); + QLabel *l3 = dialog->findChild("labelCoinControlFee"); + QLabel *l4 = dialog->findChild("labelCoinControlAfterFee"); + QLabel *l5 = dialog->findChild("labelCoinControlBytes"); + QLabel *l6 = dialog->findChild("labelCoinControlPriority"); + QLabel *l7 = dialog->findChild("labelCoinControlLowOutput"); + QLabel *l8 = dialog->findChild("labelCoinControlChange"); + + // enable/disable "low output" and "change" + dialog->findChild("labelCoinControlLowOutputText")->setEnabled(nPayAmount > 0); + dialog->findChild("labelCoinControlLowOutput") ->setEnabled(nPayAmount > 0); + dialog->findChild("labelCoinControlChangeText") ->setEnabled(nPayAmount > 0); + dialog->findChild("labelCoinControlChange") ->setEnabled(nPayAmount > 0); + + // stats + l1->setText(QString::number(nQuantity)); // Quantity + l2->setText(BitcoinUnits::formatWithUnit(nDisplayUnit, nAmount)); // Amount + l3->setText(BitcoinUnits::formatWithUnit(nDisplayUnit, nPayFee)); // Fee + l4->setText(BitcoinUnits::formatWithUnit(nDisplayUnit, nAfterFee)); // After Fee + l5->setText(((nBytes > 0) ? "~" : "") + QString::number(nBytes)); // Bytes + l6->setText(sPriorityLabel); // Priority + l7->setText((fLowOutput ? (fDust ? tr("DUST") : tr("yes")) : tr("no"))); // Low Output / Dust + l8->setText(BitcoinUnits::formatWithUnit(nDisplayUnit, nChange)); // Change + + // turn labels "red" + l5->setStyleSheet((nBytes >= 10000) ? "color:red;" : ""); // Bytes >= 10000 + l6->setStyleSheet((dPriority <= 576000) ? "color:red;" : ""); // Priority < "medium" + l7->setStyleSheet((fLowOutput) ? "color:red;" : ""); // Low Output = "yes" + l8->setStyleSheet((nChange > 0 && nChange < CENT) ? "color:red;" : ""); // Change < 0.01BTC + + // tool tips + l5->setToolTip(tr("This label turns red, if the transaction size is bigger than 10000 bytes.\n\n This means a fee of at least %1 per kb is required.\n\n Can vary +/- 1 Byte per input.").arg(BitcoinUnits::formatWithUnit(nDisplayUnit, CENT))); + l6->setToolTip(tr("Transactions with higher priority get more likely into a block.\n\nThis label turns red, if the priority is smaller than \"medium\".\n\n This means a fee of at least %1 per kb is required.").arg(BitcoinUnits::formatWithUnit(nDisplayUnit, CENT))); + l7->setToolTip(tr("This label turns red, if any recipient receives an amount smaller than %1.\n\n This means a fee of at least %2 is required. \n\n Amounts below 0.546 times the minimum relay fee are shown as DUST.").arg(BitcoinUnits::formatWithUnit(nDisplayUnit, CENT)).arg(BitcoinUnits::formatWithUnit(nDisplayUnit, CENT))); + l8->setToolTip(tr("This label turns red, if the change is smaller than %1.\n\n This means a fee of at least %2 is required.").arg(BitcoinUnits::formatWithUnit(nDisplayUnit, CENT)).arg(BitcoinUnits::formatWithUnit(nDisplayUnit, CENT))); + dialog->findChild("labelCoinControlBytesText") ->setToolTip(l5->toolTip()); + dialog->findChild("labelCoinControlPriorityText") ->setToolTip(l6->toolTip()); + dialog->findChild("labelCoinControlLowOutputText")->setToolTip(l7->toolTip()); + dialog->findChild("labelCoinControlChangeText") ->setToolTip(l8->toolTip()); + + // Insufficient funds + QLabel *label = dialog->findChild("labelCoinControlInsuffFunds"); + if (label) + label->setVisible(nChange < 0); +} + +void CoinControlDialog::updateView() +{ + bool treeMode = ui->radioTreeMode->isChecked(); + + ui->treeWidget->clear(); + ui->treeWidget->setEnabled(false); // performance, otherwise updateLabels would be called for every checked checkbox + ui->treeWidget->setAlternatingRowColors(!treeMode); + QFlags flgCheckbox=Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsUserCheckable; + QFlags flgTristate=Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsUserCheckable | Qt::ItemIsTristate; + + int nDisplayUnit = BitcoinUnits::BTC; + if (model && model->getOptionsModel()) + nDisplayUnit = model->getOptionsModel()->getDisplayUnit(); + + map > mapCoins; + model->listCoins(mapCoins); + + BOOST_FOREACH(PAIRTYPE(QString, vector) coins, mapCoins) + { + QTreeWidgetItem *itemWalletAddress = new QTreeWidgetItem(); + QString sWalletAddress = coins.first; + QString sWalletLabel = ""; + if (model->getAddressTableModel()) + sWalletLabel = model->getAddressTableModel()->labelForAddress(sWalletAddress); + if (sWalletLabel.length() == 0) + sWalletLabel = tr("(no label)"); + + if (treeMode) + { + // wallet address + ui->treeWidget->addTopLevelItem(itemWalletAddress); + + itemWalletAddress->setFlags(flgTristate); + itemWalletAddress->setCheckState(COLUMN_CHECKBOX,Qt::Unchecked); + + for (int i = 0; i < ui->treeWidget->columnCount(); i++) + itemWalletAddress->setBackground(i, QColor(248, 247, 246)); + + // label + itemWalletAddress->setText(COLUMN_LABEL, sWalletLabel); + + // address + itemWalletAddress->setText(COLUMN_ADDRESS, sWalletAddress); + } + + int64 nSum = 0; + double dPrioritySum = 0; + int nChildren = 0; + int nInputSum = 0; + BOOST_FOREACH(const COutput& out, coins.second) + { + int nInputSize = 148; // 180 if uncompressed public key + nSum += out.tx->vout[out.i].nValue; + nChildren++; + + QTreeWidgetItem *itemOutput; + if (treeMode) itemOutput = new QTreeWidgetItem(itemWalletAddress); + else itemOutput = new QTreeWidgetItem(ui->treeWidget); + itemOutput->setFlags(flgCheckbox); + itemOutput->setCheckState(COLUMN_CHECKBOX,Qt::Unchecked); + + // address + CTxDestination outputAddress; + QString sAddress = ""; + if(ExtractDestination(out.tx->vout[out.i].scriptPubKey, outputAddress)) + { + sAddress = CBitcoinAddress(outputAddress).ToString().c_str(); + + // if listMode or change => show bitcoin address. In tree mode, address is not shown again for direct wallet address outputs + if (!treeMode || (!(sAddress == sWalletAddress))) + itemOutput->setText(COLUMN_ADDRESS, sAddress); + + CPubKey pubkey; + CKeyID *keyid = boost::get< CKeyID >(&outputAddress); + if (keyid && model->getPubKey(*keyid, pubkey) && !pubkey.IsCompressed()) + nInputSize = 180; + } + + // label + if (!(sAddress == sWalletAddress)) // change + { + // tooltip from where the change comes from + itemOutput->setToolTip(COLUMN_LABEL, tr("change from %1 (%2)").arg(sWalletLabel).arg(sWalletAddress)); + itemOutput->setText(COLUMN_LABEL, tr("(change)")); + } + else if (!treeMode) + { + QString sLabel = ""; + if (model->getAddressTableModel()) + sLabel = model->getAddressTableModel()->labelForAddress(sAddress); + if (sLabel.length() == 0) + sLabel = tr("(no label)"); + itemOutput->setText(COLUMN_LABEL, sLabel); + } + + // amount + itemOutput->setText(COLUMN_AMOUNT, BitcoinUnits::format(nDisplayUnit, out.tx->vout[out.i].nValue)); + itemOutput->setText(COLUMN_AMOUNT_INT64, strPad(QString::number(out.tx->vout[out.i].nValue), 15, " ")); // padding so that sorting works correctly + + // date + itemOutput->setText(COLUMN_DATE, QDateTime::fromTime_t(out.tx->GetTxTime()).toUTC().toString("yy-MM-dd hh:mm")); + + // immature PoS reward + if (out.tx->IsCoinStake() && out.tx->GetBlocksToMaturity() > 0 && out.tx->GetDepthInMainChain() > 0) { + itemOutput->setBackground(COLUMN_CONFIRMATIONS, Qt::red); + itemOutput->setDisabled(true); + } + + // confirmations + itemOutput->setText(COLUMN_CONFIRMATIONS, strPad(QString::number(out.nDepth), 8, " ")); + + // priority + double dPriority = ((double)out.tx->vout[out.i].nValue / (nInputSize + 78)) * (out.nDepth+1); // 78 = 2 * 34 + 10 + itemOutput->setText(COLUMN_PRIORITY, CoinControlDialog::getPriorityLabel(dPriority)); + itemOutput->setText(COLUMN_PRIORITY_INT64, strPad(QString::number((int64)dPriority), 20, " ")); + dPrioritySum += (double)out.tx->vout[out.i].nValue * (out.nDepth+1); + nInputSum += nInputSize; + + // transaction hash + uint256 txhash = out.tx->GetHash(); + itemOutput->setText(COLUMN_TXHASH, txhash.GetHex().c_str()); + + // vout index + itemOutput->setText(COLUMN_VOUT_INDEX, QString::number(out.i)); + + // disable locked coins + /*if (model->isLockedCoin(txhash, out.i)) + { + COutPoint outpt(txhash, out.i); + coinControl->UnSelect(outpt); // just to be sure + itemOutput->setDisabled(true); + itemOutput->setIcon(COLUMN_CHECKBOX, QIcon(":/icons/lock_closed")); + }*/ + + // set checkbox + if (coinControl->IsSelected(txhash, out.i)) + itemOutput->setCheckState(COLUMN_CHECKBOX,Qt::Checked); + } + + // amount + if (treeMode) + { + dPrioritySum = dPrioritySum / (nInputSum + 78); + itemWalletAddress->setText(COLUMN_CHECKBOX, "(" + QString::number(nChildren) + ")"); + itemWalletAddress->setText(COLUMN_AMOUNT, BitcoinUnits::format(nDisplayUnit, nSum)); + itemWalletAddress->setText(COLUMN_AMOUNT_INT64, strPad(QString::number(nSum), 15, " ")); + itemWalletAddress->setText(COLUMN_PRIORITY, CoinControlDialog::getPriorityLabel(dPrioritySum)); + itemWalletAddress->setText(COLUMN_PRIORITY_INT64, strPad(QString::number((int64)dPrioritySum), 20, " ")); + } + } + + // expand all partially selected + if (treeMode) + { + for (int i = 0; i < ui->treeWidget->topLevelItemCount(); i++) + if (ui->treeWidget->topLevelItem(i)->checkState(COLUMN_CHECKBOX) == Qt::PartiallyChecked) + ui->treeWidget->topLevelItem(i)->setExpanded(true); + } + + // sort view + sortView(sortColumn, sortOrder); + ui->treeWidget->setEnabled(true); +} diff --git a/src/qt/coincontroldialog.h b/src/qt/coincontroldialog.h new file mode 100644 index 0000000..5d0a90b --- /dev/null +++ b/src/qt/coincontroldialog.h @@ -0,0 +1,92 @@ +#ifndef COINCONTROLDIALOG_H +#define COINCONTROLDIALOG_H + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Ui { + class CoinControlDialog; +} +class WalletModel; +class CCoinControl; + +class CoinControlDialog : public QDialog +{ + Q_OBJECT + +public: + explicit CoinControlDialog(QWidget *parent = 0); + ~CoinControlDialog(); + + void setModel(WalletModel *model); + + // static because also called from sendcoinsdialog + static void updateLabels(WalletModel*, QDialog*); + static QString getPriorityLabel(double); + + static QList payAmounts; + static CCoinControl *coinControl; + +private: + Ui::CoinControlDialog *ui; + WalletModel *model; + int sortColumn; + Qt::SortOrder sortOrder; + + QMenu *contextMenu; + QTreeWidgetItem *contextMenuItem; + QAction *copyTransactionHashAction; + //QAction *lockAction; + //QAction *unlockAction; + + QString strPad(QString, int, QString); + void sortView(int, Qt::SortOrder); + void updateView(); + + enum + { + COLUMN_CHECKBOX, + COLUMN_AMOUNT, + COLUMN_LABEL, + COLUMN_ADDRESS, + COLUMN_DATE, + COLUMN_CONFIRMATIONS, + COLUMN_PRIORITY, + COLUMN_TXHASH, + COLUMN_VOUT_INDEX, + COLUMN_AMOUNT_INT64, + COLUMN_PRIORITY_INT64 + }; + +private slots: + void showMenu(const QPoint &); + void copyAmount(); + void copyLabel(); + void copyAddress(); + void copyTransactionHash(); + //void lockCoin(); + //void unlockCoin(); + void clipboardQuantity(); + void clipboardAmount(); + void clipboardFee(); + void clipboardAfterFee(); + void clipboardBytes(); + void clipboardPriority(); + void clipboardLowOutput(); + void clipboardChange(); + void radioTreeMode(bool); + void radioListMode(bool); + void viewItemChanged(QTreeWidgetItem*, int); + void headerSectionClicked(int); + void buttonBoxClicked(QAbstractButton*); + void buttonSelectAllClicked(); + //void updateLabelLocked(); +}; + +#endif // COINCONTROLDIALOG_H diff --git a/src/qt/coincontroltreewidget.cpp b/src/qt/coincontroltreewidget.cpp new file mode 100644 index 0000000..0c1b514 --- /dev/null +++ b/src/qt/coincontroltreewidget.cpp @@ -0,0 +1,28 @@ +#include "coincontroltreewidget.h" +#include "coincontroldialog.h" + +CoinControlTreeWidget::CoinControlTreeWidget(QWidget *parent) : + QTreeWidget(parent) +{ + +} + +void CoinControlTreeWidget::keyPressEvent(QKeyEvent *event) +{ + if (event->key() == Qt::Key_Space) // press spacebar -> select checkbox + { + event->ignore(); + int COLUMN_CHECKBOX = 0; + this->currentItem()->setCheckState(COLUMN_CHECKBOX, ((this->currentItem()->checkState(COLUMN_CHECKBOX) == Qt::Checked) ? Qt::Unchecked : Qt::Checked)); + } + else if (event->key() == Qt::Key_Escape) // press esc -> close dialog + { + event->ignore(); + CoinControlDialog *coinControlDialog = (CoinControlDialog*)this->parentWidget(); + coinControlDialog->done(QDialog::Accepted); + } + else + { + this->QTreeWidget::keyPressEvent(event); + } +} diff --git a/src/qt/coincontroltreewidget.h b/src/qt/coincontroltreewidget.h new file mode 100644 index 0000000..912e573 --- /dev/null +++ b/src/qt/coincontroltreewidget.h @@ -0,0 +1,17 @@ +#ifndef COINCONTROLTREEWIDGET_H +#define COINCONTROLTREEWIDGET_H + +#include +#include + +class CoinControlTreeWidget : public QTreeWidget { +Q_OBJECT + +public: + explicit CoinControlTreeWidget(QWidget *parent = 0); + +protected: + virtual void keyPressEvent(QKeyEvent *event); +}; + +#endif // COINCONTROLTREEWIDGET_H diff --git a/src/qt/csvmodelwriter.cpp b/src/qt/csvmodelwriter.cpp new file mode 100644 index 0000000..8a50bba --- /dev/null +++ b/src/qt/csvmodelwriter.cpp @@ -0,0 +1,88 @@ +#include "csvmodelwriter.h" + +#include +#include +#include + +CSVModelWriter::CSVModelWriter(const QString &filename, QObject *parent) : + QObject(parent), + filename(filename), model(0) +{ +} + +void CSVModelWriter::setModel(const QAbstractItemModel *model) +{ + this->model = model; +} + +void CSVModelWriter::addColumn(const QString &title, int column, int role) +{ + Column col; + col.title = title; + col.column = column; + col.role = role; + + columns.append(col); +} + +static void writeValue(QTextStream &f, const QString &value) +{ + QString escaped = value; + escaped.replace('"', "\"\""); + f << "\"" << escaped << "\""; +} + +static void writeSep(QTextStream &f) +{ + f << ","; +} + +static void writeNewline(QTextStream &f) +{ + f << "\n"; +} + +bool CSVModelWriter::write() +{ + QFile file(filename); + if(!file.open(QIODevice::WriteOnly | QIODevice::Text)) + return false; + QTextStream out(&file); + + int numRows = 0; + if(model) + { + numRows = model->rowCount(); + } + + // Header row + for(int i=0; iindex(j, columns[i].column).data(columns[i].role); + writeValue(out, data.toString()); + } + writeNewline(out); + } + + file.close(); + + return file.error() == QFile::NoError; +} + diff --git a/src/qt/csvmodelwriter.h b/src/qt/csvmodelwriter.h new file mode 100644 index 0000000..6c9dcba --- /dev/null +++ b/src/qt/csvmodelwriter.h @@ -0,0 +1,46 @@ +#ifndef CSVMODELWRITER_H +#define CSVMODELWRITER_H + +#include +#include + +QT_BEGIN_NAMESPACE +class QAbstractItemModel; +QT_END_NAMESPACE + +/** Export a Qt table model to a CSV file. This is useful for analyzing or post-processing the data in + a spreadsheet. + */ +class CSVModelWriter : public QObject +{ + Q_OBJECT +public: + explicit CSVModelWriter(const QString &filename, QObject *parent = 0); + + void setModel(const QAbstractItemModel *model); + void addColumn(const QString &title, int column, int role=Qt::EditRole); + + /** Perform export of the model to CSV. + @returns true on success, false otherwise + */ + bool write(); + +private: + QString filename; + const QAbstractItemModel *model; + + struct Column + { + QString title; + int column; + int role; + }; + QList columns; + +signals: + +public slots: + +}; + +#endif // CSVMODELWRITER_H diff --git a/src/qt/editaddressdialog.cpp b/src/qt/editaddressdialog.cpp new file mode 100644 index 0000000..19cb02a --- /dev/null +++ b/src/qt/editaddressdialog.cpp @@ -0,0 +1,128 @@ +#include "editaddressdialog.h" +#include "ui_editaddressdialog.h" +#include "addresstablemodel.h" +#include "guiutil.h" + +#include +#include + +EditAddressDialog::EditAddressDialog(Mode mode, QWidget *parent) : + QDialog(parent), + ui(new Ui::EditAddressDialog), mapper(0), mode(mode), model(0) +{ + ui->setupUi(this); + + GUIUtil::setupAddressWidget(ui->addressEdit, this); + + switch(mode) + { + case NewReceivingAddress: + setWindowTitle(tr("New receiving address")); + ui->addressEdit->setEnabled(false); + break; + case NewSendingAddress: + setWindowTitle(tr("New sending address")); + break; + case EditReceivingAddress: + setWindowTitle(tr("Edit receiving address")); + ui->addressEdit->setDisabled(true); + break; + case EditSendingAddress: + setWindowTitle(tr("Edit sending address")); + break; + } + + mapper = new QDataWidgetMapper(this); + mapper->setSubmitPolicy(QDataWidgetMapper::ManualSubmit); +} + +EditAddressDialog::~EditAddressDialog() +{ + delete ui; +} + +void EditAddressDialog::setModel(AddressTableModel *model) +{ + this->model = model; + mapper->setModel(model); + mapper->addMapping(ui->labelEdit, AddressTableModel::Label); + mapper->addMapping(ui->addressEdit, AddressTableModel::Address); +} + +void EditAddressDialog::loadRow(int row) +{ + mapper->setCurrentIndex(row); +} + +bool EditAddressDialog::saveCurrentRow() +{ + if(!model) + return false; + switch(mode) + { + case NewReceivingAddress: + case NewSendingAddress: + address = model->addRow( + mode == NewSendingAddress ? AddressTableModel::Send : AddressTableModel::Receive, + ui->labelEdit->text(), + ui->addressEdit->text()); + break; + case EditReceivingAddress: + case EditSendingAddress: + if(mapper->submit()) + { + address = ui->addressEdit->text(); + } + break; + } + return !address.isEmpty(); +} + +void EditAddressDialog::accept() +{ + if(!model) + return; + if(!saveCurrentRow()) + { + switch(model->getEditStatus()) + { + case AddressTableModel::DUPLICATE_ADDRESS: + QMessageBox::warning(this, windowTitle(), + tr("The entered address \"%1\" is already in the address book.").arg(ui->addressEdit->text()), + QMessageBox::Ok, QMessageBox::Ok); + break; + case AddressTableModel::INVALID_ADDRESS: + QMessageBox::warning(this, windowTitle(), + tr("The entered address \"%1\" is not a valid triangles address.").arg(ui->addressEdit->text()), + QMessageBox::Ok, QMessageBox::Ok); + return; + case AddressTableModel::WALLET_UNLOCK_FAILURE: + QMessageBox::critical(this, windowTitle(), + tr("Could not unlock wallet."), + QMessageBox::Ok, QMessageBox::Ok); + return; + case AddressTableModel::KEY_GENERATION_FAILURE: + QMessageBox::critical(this, windowTitle(), + tr("New key generation failed."), + QMessageBox::Ok, QMessageBox::Ok); + return; + case AddressTableModel::OK: + // Failed with unknown reason. Just reject. + break; + } + + return; + } + QDialog::accept(); +} + +QString EditAddressDialog::getAddress() const +{ + return address; +} + +void EditAddressDialog::setAddress(const QString &address) +{ + this->address = address; + ui->addressEdit->setText(address); +} diff --git a/src/qt/editaddressdialog.h b/src/qt/editaddressdialog.h new file mode 100644 index 0000000..7ec053f --- /dev/null +++ b/src/qt/editaddressdialog.h @@ -0,0 +1,50 @@ +#ifndef EDITADDRESSDIALOG_H +#define EDITADDRESSDIALOG_H + +#include + +QT_BEGIN_NAMESPACE +class QDataWidgetMapper; +QT_END_NAMESPACE + +namespace Ui { + class EditAddressDialog; +} +class AddressTableModel; + +/** Dialog for editing an address and associated information. + */ +class EditAddressDialog : public QDialog +{ + Q_OBJECT + +public: + enum Mode { + NewReceivingAddress, + NewSendingAddress, + EditReceivingAddress, + EditSendingAddress + }; + + explicit EditAddressDialog(Mode mode, QWidget *parent = 0); + ~EditAddressDialog(); + + void setModel(AddressTableModel *model); + void loadRow(int row); + + void accept(); + + QString getAddress() const; + void setAddress(const QString &address); +private: + bool saveCurrentRow(); + + Ui::EditAddressDialog *ui; + QDataWidgetMapper *mapper; + Mode mode; + AddressTableModel *model; + + QString address; +}; + +#endif // EDITADDRESSDIALOG_H diff --git a/src/qt/forms/aboutdialog.ui b/src/qt/forms/aboutdialog.ui new file mode 100644 index 0000000..3c2ce3d --- /dev/null +++ b/src/qt/forms/aboutdialog.ui @@ -0,0 +1,190 @@ + + + AboutDialog + + + + 0 + 0 + 593 + 331 + + + + About triangles + + + + + + + 0 + 0 + + + + :/images/about + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + IBeamCursor + + + <html><head/><body><p><span style=" font-weight:600;">Triangles</span> version</p></body></html> + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + + + IBeamCursor + + + 3.3.3.3-beta + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + IBeamCursor + + + +Copyright © 2009-2012 Bitcoin Developers +Copyright © 2012 PPCoin Developers +Copyright © 2014 Triangles Developers + + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + + + IBeamCursor + + + +This is experimental software. If you don't treat it as such, you're likely to put an eye out! + +Distributed under the MIT/X11 software license, see the accompanying file COPYING or http://www.opensource.org/licenses/mit-license.php. + +This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit (http://www.openssl.org/) and cryptographic software written by Eric Young (eay@cryptsoft.com) and UPnP software written by Thomas Bernard. + + + true + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Ok + + + + + + + + + + + + + buttonBox + accepted() + AboutDialog + accept() + + + 360 + 308 + + + 157 + 274 + + + + + buttonBox + rejected() + AboutDialog + reject() + + + 428 + 308 + + + 286 + 274 + + + + + diff --git a/src/qt/forms/addressbookpage.ui b/src/qt/forms/addressbookpage.ui new file mode 100644 index 0000000..ed06c95 --- /dev/null +++ b/src/qt/forms/addressbookpage.ui @@ -0,0 +1,178 @@ + + + AddressBookPage + + + + 0 + 0 + 852 + 380 + + + + Address Book + + + + + + #labelExplanation { color: #464747; } + + + These are your triangles addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. + + + Qt::PlainText + + + true + + + + + + + Qt::CustomContextMenu + + + Double-click to edit address or label + + + false + + + true + + + QAbstractItemView::SingleSelection + + + QAbstractItemView::SelectRows + + + true + + + false + + + + + + + + + Create a new address + + + &New Address + + + + :/icons/add:/icons/add + + + + + + + Copy the currently selected address to the system clipboard + + + &Copy Address + + + + :/icons/editcopy:/icons/editcopy + + + + + + + Show &QR Code + + + + :/icons/qrcode:/icons/qrcode + + + + + + + Sign a message to prove you own a triangles address + + + Sign &Message + + + + :/icons/edit:/icons/edit + + + + + + + Verify a message to ensure it was signed with a specified triangles address + + + &Verify Message + + + + :/icons/transaction_0:/icons/transaction_0 + + + + + + + Delete the currently selected address from the list + + + &Delete + + + + :/icons/remove:/icons/remove + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 0 + + + + QDialogButtonBox::Ok + + + + + + + + + + + + diff --git a/src/qt/forms/askpassphrasedialog.ui b/src/qt/forms/askpassphrasedialog.ui new file mode 100644 index 0000000..5fd8a4a --- /dev/null +++ b/src/qt/forms/askpassphrasedialog.ui @@ -0,0 +1,167 @@ + + + AskPassphraseDialog + + + + 0 + 0 + 598 + 198 + + + + + 0 + 0 + + + + + 550 + 0 + + + + Passphrase Dialog + + + + + + Qt::RichText + + + true + + + + + + + QFormLayout::AllNonFixedFieldsGrow + + + + + Enter passphrase + + + + + + + QLineEdit::Password + + + + + + + New passphrase + + + + + + + QLineEdit::Password + + + + + + + Repeat new passphrase + + + + + + + QLineEdit::Password + + + + + + + + 75 + true + + + + + + + Qt::AlignCenter + + + + + + + true + + + Serves to disable trivial use of sendmoney when the OS account is compromised. Provides no real security. + + + For staking only + + + false + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + AskPassphraseDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + AskPassphraseDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/src/qt/forms/coincontroldialog.ui b/src/qt/forms/coincontroldialog.ui new file mode 100644 index 0000000..f861553 --- /dev/null +++ b/src/qt/forms/coincontroldialog.ui @@ -0,0 +1,549 @@ + + + CoinControlDialog + + + + 0 + 0 + 1000 + 500 + + + + Coin Control + + + + + + 0 + + + 10 + + + + + 10 + + + 10 + + + 6 + + + 6 + + + + + font-weight:bold; + + + Quantity: + + + + + + + + Monospace + 10 + + + + IBeamCursor + + + Qt::ActionsContextMenu + + + 0 + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + + + font-weight:bold; + + + Bytes: + + + + + + + + Monospace + 10 + + + + IBeamCursor + + + Qt::ActionsContextMenu + + + 0 + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + + + + + 10 + + + 10 + + + 6 + + + 6 + + + + + font-weight:bold; + + + Amount: + + + + + + + + Monospace + 10 + + + + IBeamCursor + + + Qt::ActionsContextMenu + + + 0.00 TRI + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + + + font-weight:bold; + + + Priority: + + + + + + + + Monospace + 10 + + + + IBeamCursor + + + Qt::ActionsContextMenu + + + + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + + + + + 10 + + + 10 + + + 6 + + + 6 + + + + + font-weight:bold; + + + Fee: + + + + + + + + Monospace + 10 + + + + IBeamCursor + + + Qt::ActionsContextMenu + + + 0.00 TRI + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + + + false + + + font-weight:bold; + + + Low Output: + + + + + + + false + + + + Monospace + 10 + + + + IBeamCursor + + + Qt::ActionsContextMenu + + + no + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + + + + + 10 + + + 10 + + + 6 + + + 6 + + + + + font-weight:bold; + + + After Fee: + + + + + + + + Monospace + 10 + + + + IBeamCursor + + + Qt::ActionsContextMenu + + + 0.00 TRI + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + + + false + + + font-weight:bold; + + + Change: + + + + + + + false + + + + Monospace + 10 + + + + IBeamCursor + + + Qt::ActionsContextMenu + + + 0.00 TRI + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + + + + + + + + 0 + 40 + + + + QFrame::StyledPanel + + + QFrame::Sunken + + + + + 10 + 0 + 781 + 41 + + + + + 14 + + + + + + 0 + 0 + + + + (un)select all + + + + + + + + 0 + 0 + + + + Tree mode + + + true + + + + + + + + 0 + 0 + + + + List mode + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + Qt::CustomContextMenu + + + false + + + 11 + + + true + + + false + + + + + + + + + Amount + + + + + Label + + + + + Address + + + + + Date + + + + + Confirmations + + + Confirmed + + + + + Priority + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + 0 + + + + Qt::Horizontal + + + QDialogButtonBox::Ok + + + + + + + + CoinControlTreeWidget + QTreeWidget +
coincontroltreewidget.h
+
+
+ + +
diff --git a/src/qt/forms/editaddressdialog.ui b/src/qt/forms/editaddressdialog.ui new file mode 100644 index 0000000..b4a4c1b --- /dev/null +++ b/src/qt/forms/editaddressdialog.ui @@ -0,0 +1,105 @@ + + + EditAddressDialog + + + + 0 + 0 + 457 + 126 + + + + Edit Address + + + + + + QFormLayout::AllNonFixedFieldsGrow + + + + + &Label + + + labelEdit + + + + + + + The label associated with this address book entry + + + + + + + &Address + + + addressEdit + + + + + + + The address associated with this address book entry. This can only be modified for sending addresses. + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + EditAddressDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + EditAddressDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/src/qt/forms/optionsdialog.ui b/src/qt/forms/optionsdialog.ui new file mode 100644 index 0000000..0b4fe6d --- /dev/null +++ b/src/qt/forms/optionsdialog.ui @@ -0,0 +1,470 @@ + + + OptionsDialog + + + + 0 + 0 + 540 + 380 + + + + Options + + + true + + + + + + QTabWidget::North + + + 0 + + + + &Main + + + + + + Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. Fee 0.01 recommended. + + + Qt::PlainText + + + true + + + + + + + + + Pay transaction &fee + + + Qt::PlainText + + + transactionFee + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + Automatically start triangles after logging in to the system. + + + &Start triangles on system login + + + + + + + Detach block and address databases at shutdown. This means they can be moved to another data directory, but it slows down shutdown. The wallet is always detached. + + + &Detach databases at shutdown + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + &Network + + + + + + Automatically open the triangles client port on the router. This only works when your router supports UPnP and it is enabled. + + + Map port using &UPnP + + + + + + + Connect to the triangles network through a SOCKS proxy (e.g. when connecting through Tor). + + + &Connect through SOCKS proxy: + + + + + + + + + Proxy &IP: + + + Qt::PlainText + + + proxyIp + + + + + + + + 140 + 16777215 + + + + IP address of the proxy (e.g. 127.0.0.1) + + + + + + + &Port: + + + Qt::PlainText + + + proxyPort + + + + + + + + 55 + 16777215 + + + + Port of the proxy (e.g. 9050) + + + + + + + SOCKS &Version: + + + Qt::PlainText + + + socksVersion + + + + + + + SOCKS version of the proxy (e.g. 5) + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + &Window + + + + + + Show only a tray icon after minimizing the window. + + + &Minimize to the tray instead of the taskbar + + + + + + + Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu. + + + M&inimize on close + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + &Display + + + + + + + + User Interface &language: + + + Qt::PlainText + + + lang + + + + + + + The user interface language can be set here. This setting will take effect after restarting triangles. + + + + + + + + + + + &Unit to show amounts in: + + + Qt::PlainText + + + unit + + + + + + + Choose the default subdivision unit to show in the interface and when sending coins. + + + + + + + + + Whether to show triangles addresses in the transaction list or not. + + + &Display addresses in transaction list + + + + + + + Whether to show coin control features or not. + + + Display coin &control features (experts only!) + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 48 + + + + + + + + + 75 + true + + + + + + + Qt::PlainText + + + true + + + + + + + Qt::Horizontal + + + + 40 + 48 + + + + + + + + &OK + + + + + + + &Cancel + + + false + + + + + + + &Apply + + + false + + + + + + + + + + BitcoinAmountField + QSpinBox +
bitcoinamountfield.h
+
+ + QValueComboBox + QComboBox +
qvaluecombobox.h
+
+ + QValidatedLineEdit + QLineEdit +
qvalidatedlineedit.h
+
+
+ + +
diff --git a/src/qt/forms/overviewpage.ui b/src/qt/forms/overviewpage.ui new file mode 100644 index 0000000..eb38e13 --- /dev/null +++ b/src/qt/forms/overviewpage.ui @@ -0,0 +1,388 @@ + + + OverviewPage + + + + 0 + 0 + 573 + 492 + + + + Form + + + #OverviewPage { color: #464747; } + + + + + + + + #frame { background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(70,71,71,15), stop:1.0 rgba(70,71,71,0)); } + + + + + + + + + 11 + 75 + true + + + + color: #464747; + + + Wallet + + + + + + + The displayed information may be out of date. Your wallet automatically synchronizes with the triangles network after a connection is established, but this process has not completed yet. + + + QLabel { color: red; } + + + (out of sync) + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + QFormLayout::AllNonFixedFieldsGrow + + + 12 + + + 12 + + + + + color: #464747; + + + Balance: + + + + + + + + 75 + true + + + + IBeamCursor + + + Your current balance + + + color: #464747; + + + 0 TRI + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + + + color: #464747; + + + Stake: + + + + + + + + 75 + true + + + + IBeamCursor + + + Total of coins that was staked, and do not yet count toward the current balance + + + color: #464747; + + + 0 TRI + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + + + color: #464747; + + + Unconfirmed: + + + + + + + + 75 + true + + + + IBeamCursor + + + Total of transactions that have yet to be confirmed, and do not yet count toward the current balance + + + color: #464747; + + + 0 TRI + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + + + color: #464747; + + + Immature: + + + + + + + + 75 + true + + + + Mined balance that has not yet matured + + + color: #464747; + + + 0 TRI + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + + + color: #464747; + + + Number of transactions: + + + + + + + Total number of transactions in wallet + + + color: #464747; + + + 0 + + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + 260 + 260 + + + + + + + :/images/backg + + + Qt::AlignCenter + + + 2 + + + 1 + + + + + + + + + + + #frame_2 { background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(70,71,71,10), stop:1.0 rgba(70,71,71,0)); } + + + + + + + + color: #464747; + + + <b>Recent transactions</b> + + + + + + + The displayed information may be out of date. Your wallet automatically synchronizes with the triangles network after a connection is established, but this process has not completed yet. + + + QLabel { color: red; } + + + (out of sync) + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + QListView { background: transparent; } + + + QFrame::NoFrame + + + Qt::ScrollBarAlwaysOff + + + Qt::ScrollBarAlwaysOff + + + QAbstractItemView::NoSelection + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + + diff --git a/src/qt/forms/qrcodedialog.ui b/src/qt/forms/qrcodedialog.ui new file mode 100644 index 0000000..52e9db3 --- /dev/null +++ b/src/qt/forms/qrcodedialog.ui @@ -0,0 +1,212 @@ + + + QRCodeDialog + + + + 0 + 0 + 340 + 530 + + + + QR Code Dialog + + + + + + + 0 + 0 + + + + + 300 + 300 + + + + Qt::PlainText + + + Qt::AlignCenter + + + true + + + + + + + + 0 + 0 + + + + + 0 + 50 + + + + true + + + Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + + + + + + true + + + Request Payment + + + + + + + QFormLayout::AllNonFixedFieldsGrow + + + + + Label: + + + Qt::PlainText + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + lnLabel + + + + + + + + + + Message: + + + Qt::PlainText + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + lnMessage + + + + + + + + + + + 0 + 0 + + + + Amount: + + + Qt::PlainText + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + lnReqAmount + + + + + + + false + + + + 80 + 0 + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + &Save As... + + + + + + + + + + + + + BitcoinAmountField + QSpinBox +
bitcoinamountfield.h
+
+
+ + + + chkReqPayment + clicked(bool) + lnReqAmount + setEnabled(bool) + + + 92 + 285 + + + 98 + 311 + + + + +
diff --git a/src/qt/forms/rpcconsole.ui b/src/qt/forms/rpcconsole.ui new file mode 100644 index 0000000..9279548 --- /dev/null +++ b/src/qt/forms/rpcconsole.ui @@ -0,0 +1,456 @@ + + + RPCConsole + + + + 0 + 0 + 740 + 450 + + + + triangles - Debug window + + + + + + 0 + + + + &Information + + + + 12 + + + + + + 75 + true + + + + triangles Core + + + + + + + Client name + + + + + + + IBeamCursor + + + N/A + + + Qt::PlainText + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + + + Client version + + + + + + + IBeamCursor + + + N/A + + + Qt::PlainText + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + + + Using OpenSSL version + + + 10 + + + + + + + IBeamCursor + + + N/A + + + Qt::PlainText + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + + + Build date + + + + + + + IBeamCursor + + + N/A + + + Qt::PlainText + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + + + Startup time + + + + + + + IBeamCursor + + + N/A + + + Qt::PlainText + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + + + + 75 + true + + + + Network + + + + + + + Number of connections + + + + + + + IBeamCursor + + + N/A + + + Qt::PlainText + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + + + On testnet + + + + + + + false + + + + + + + + + + + 75 + true + + + + Block chain + + + + + + + Current number of blocks + + + + + + + IBeamCursor + + + N/A + + + Qt::PlainText + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + + + Estimated total blocks + + + + + + + IBeamCursor + + + N/A + + + Qt::PlainText + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + + + Last block time + + + + + + + IBeamCursor + + + N/A + + + Qt::PlainText + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + + + Qt::Vertical + + + + 20 + 20 + + + + + + + + + 75 + true + + + + Debug log file + + + + + + + Open the triangles debug log file from the current data directory. This can take a few seconds for large log files. + + + &Open + + + false + + + + + + + + 75 + true + + + + Command-line options + + + + + + + Show the triangles-qt help message to get a list with possible triangles command-line options. + + + &Show + + + false + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + &Console + + + + 3 + + + + + + 0 + 100 + + + + true + + + false + + + 2 + + + + + + + 3 + + + + + > + + + + + + + + + + + 24 + 24 + + + + Clear console + + + + + + + :/icons/remove:/icons/remove + + + Ctrl+L + + + false + + + + + + + + + + + + + + + + diff --git a/src/qt/forms/sendcoinsdialog.ui b/src/qt/forms/sendcoinsdialog.ui new file mode 100644 index 0000000..85c9097 --- /dev/null +++ b/src/qt/forms/sendcoinsdialog.ui @@ -0,0 +1,812 @@ + + + SendCoinsDialog + + + + 0 + 0 + 850 + 400 + + + + Send Coins + + + + 8 + + + + + + 0 + 0 + + + + + 16777215 + 16777215 + + + + QFrame::StyledPanel + + + QFrame::Sunken + + + + 6 + + + 0 + + + 0 + + + 0 + + + 6 + + + + + 0 + + + 10 + + + 10 + + + + + 15 + + + + + + 0 + 0 + + + + + 75 + true + + + + font-weight:bold; + + + Coin Control Features + + + + + + + + + 8 + + + 10 + + + + + + + + Inputs... + + + + + + + automatically selected + + + 5 + + + + + + + + 75 + true + + + + color:red;font-weight:bold; + + + Insufficient funds! + + + 5 + + + + + + + Qt::Horizontal + + + + 40 + 1 + + + + + + + + + + + 0 + 0 + + + + + 0 + 0 + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 20 + + + 0 + + + 10 + + + + + 10 + + + 14 + + + 10 + + + 4 + + + 6 + + + + + font-weight:bold; + + + Quantity: + + + 0 + + + + + + + + Monospace + 10 + + + + IBeamCursor + + + Qt::ActionsContextMenu + + + 0 + + + 0 + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + + + font-weight:bold; + + + Bytes: + + + + + + + + Monospace + 10 + + + + IBeamCursor + + + Qt::ActionsContextMenu + + + 0 + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + + + + + 10 + + + 14 + + + 6 + + + 4 + + + 6 + + + + + font-weight:bold; + + + Amount: + + + 0 + + + + + + + + Monospace + 10 + + + + IBeamCursor + + + Qt::ActionsContextMenu + + + 0.00 TRI + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + + + font-weight:bold; + + + Priority: + + + + + + + + Monospace + 10 + + + + IBeamCursor + + + Qt::ActionsContextMenu + + + medium + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + + + + + 10 + + + 14 + + + 6 + + + 4 + + + 6 + + + + + font-weight:bold; + + + Fee: + + + 0 + + + + + + + + Monospace + 10 + + + + IBeamCursor + + + Qt::ActionsContextMenu + + + 0.00 TRI + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + + + font-weight:bold; + + + Low Output: + + + + + + + + Monospace + 10 + + + + IBeamCursor + + + Qt::ActionsContextMenu + + + no + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + + + + + 10 + + + 14 + + + 6 + + + 4 + + + 6 + + + + + font-weight:bold; + + + After Fee: + + + 0 + + + + + + + + Monospace + 10 + + + + IBeamCursor + + + Qt::ActionsContextMenu + + + 0.00 TRI + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + + + font-weight:bold; + + + Change + + + + + + + + Monospace + 10 + + + + IBeamCursor + + + Qt::ActionsContextMenu + + + 0.00 TRI + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + + + + + + + + + + 12 + + + QLayout::SetDefaultConstraint + + + 5 + + + 5 + + + + + custom change address + + + + + + + false + + + + 0 + 0 + + + + + + + + + 0 + 0 + + + + + 0 + 0 + + + + + + + 3 + + + + + + + + + Qt::Vertical + + + + 800 + 1 + + + + + + + + + + + + + true + + + + + 0 + 0 + 824 + 141 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 6 + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + + + Send to multiple recipients at once + + + Add &Recipient + + + + :/icons/add:/icons/add + + + false + + + + + + + + 0 + 0 + + + + Remove all transaction fields + + + Clear &All + + + + :/icons/remove:/icons/remove + + + 300 + + + false + + + + + + + 3 + + + + + + 0 + 0 + + + + #label { color: #464747; } + + + Balance: + + + + + + + + 0 + 0 + + + + IBeamCursor + + + #label { color: #464747; } + + + 123.456 TRI + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 150 + 0 + + + + Confirm the send action + + + S&end over Tor + + + + :/icons/send:/icons/send + + + true + + + + + + + + + + + + diff --git a/src/qt/forms/sendcoinsentry.ui b/src/qt/forms/sendcoinsentry.ui new file mode 100644 index 0000000..6e2045a --- /dev/null +++ b/src/qt/forms/sendcoinsentry.ui @@ -0,0 +1,169 @@ + + + SendCoinsEntry + + + + 0 + 0 + 729 + 131 + + + + Form + + + QFrame::StyledPanel + + + QFrame::Sunken + + + + QFormLayout::AllNonFixedFieldsGrow + + + + + Pay &To: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + payTo + + + + + + + 0 + + + + + The address to send the payment to (e.g. 4Zo1ga6xuKuQ7JV7M9rGDoxdbYwV5zgQJ5) + + + 34 + + + + + + + Choose address from address book + + + + + + + :/icons/address-book:/icons/address-book + + + Alt+A + + + + + + + Paste address from clipboard + + + + + + + :/icons/editpaste:/icons/editpaste + + + Alt+P + + + + + + + Remove this recipient + + + + + + + :/icons/remove:/icons/remove + + + + + + + + + &Label: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + addAsLabel + + + + + + + 0 + + + + + true + + + Enter a label for this address to add it to your address book + + + + + + + + + A&mount: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + payAmount + + + + + + + + + + + BitcoinAmountField + QSpinBox +
bitcoinamountfield.h
+ 1 +
+ + QValidatedLineEdit + QLineEdit +
qvalidatedlineedit.h
+
+
+ + + + +
diff --git a/src/qt/forms/signverifymessagedialog.ui b/src/qt/forms/signverifymessagedialog.ui new file mode 100644 index 0000000..3f3ed40 --- /dev/null +++ b/src/qt/forms/signverifymessagedialog.ui @@ -0,0 +1,386 @@ + + + SignVerifyMessageDialog + + + + 0 + 0 + 700 + 380 + + + + Signatures - Sign / Verify a Message + + + true + + + + + + 1 + + + + &Sign Message + + + + + + You can sign messages with your addresses to prove you own them. Be careful not to sign anything vague, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to. + + + Qt::PlainText + + + true + + + + + + + 0 + + + + + The address to sign the message with (e.g. 4Zo1ga6xuKuQ7JV7M9rGDoxdbYwV5zgQJ5) + + + 34 + + + + + + + Choose an address from the address book + + + + + + + :/icons/address-book:/icons/address-book + + + Alt+A + + + false + + + + + + + Paste address from clipboard + + + + + + + :/icons/editpaste:/icons/editpaste + + + Alt+P + + + false + + + + + + + + + Enter the message you want to sign here + + + + + + + 0 + + + + + + true + + + + true + + + + + + + Copy the current signature to the system clipboard + + + + + + + :/icons/editcopy:/icons/editcopy + + + false + + + + + + + + + + + Sign the message to prove you own this triangles address + + + &Sign Message + + + + :/icons/edit:/icons/edit + + + false + + + + + + + Reset all sign message fields + + + Clear &All + + + + :/icons/remove:/icons/remove + + + false + + + + + + + Qt::Horizontal + + + + 40 + 48 + + + + + + + + + 75 + true + + + + + + + true + + + + + + + Qt::Horizontal + + + + 40 + 48 + + + + + + + + + + + &Verify Message + + + + + + Enter the signing address, message (ensure you copy line breaks, spaces, tabs, etc. exactly) and signature below to verify the message. Be careful not to read more into the signature than what is in the signed message itself, to avoid being tricked by a man-in-the-middle attack. + + + Qt::PlainText + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + true + + + + + + + 0 + + + + + The address the message was signed with (e.g. 4Zo1ga6xuKuQ7JV7M9rGDoxdbYwV5zgQJ5) + + + 34 + + + + + + + Choose an address from the address book + + + + + + + :/icons/address-book:/icons/address-book + + + Alt+A + + + false + + + + + + + + + + + + + + + + + Verify the message to ensure it was signed with the specified triangles address + + + &Verify Message + + + + :/icons/transaction_0:/icons/transaction_0 + + + false + + + + + + + Reset all verify message fields + + + Clear &All + + + + :/icons/remove:/icons/remove + + + false + + + + + + + Qt::Horizontal + + + + 40 + 48 + + + + + + + + + 75 + true + + + + + + + true + + + + + + + Qt::Horizontal + + + + 40 + 48 + + + + + + + + + + + + + + + QValidatedLineEdit + QLineEdit +
qvalidatedlineedit.h
+
+
+ + + + +
diff --git a/src/qt/forms/transactiondescdialog.ui b/src/qt/forms/transactiondescdialog.ui new file mode 100644 index 0000000..b38dffc --- /dev/null +++ b/src/qt/forms/transactiondescdialog.ui @@ -0,0 +1,74 @@ + + + TransactionDescDialog + + + + 0 + 0 + 620 + 250 + + + + Transaction details + + + + + + This pane shows a detailed description of the transaction + + + true + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Close + + + + + + + + + buttonBox + accepted() + TransactionDescDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + TransactionDescDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/src/qt/guiconstants.h b/src/qt/guiconstants.h new file mode 100644 index 0000000..405ba39 --- /dev/null +++ b/src/qt/guiconstants.h @@ -0,0 +1,34 @@ +#ifndef GUICONSTANTS_H +#define GUICONSTANTS_H + +/* Milliseconds between model updates */ +static const int MODEL_UPDATE_DELAY = 500; + +/* AskPassphraseDialog -- Maximum passphrase length */ +static const int MAX_PASSPHRASE_SIZE = 1024; + +/* BitcoinGUI -- Size of icons in status bar */ +static const int STATUSBAR_ICONSIZE = 16; + +/* Invalid field background style */ +#define STYLE_INVALID "background:#FF8080" + +/* Transaction list -- unconfirmed transaction */ +#define COLOR_UNCONFIRMED QColor(128, 128, 128) +/* Transaction list -- negative amount */ +#define COLOR_NEGATIVE QColor(255, 0, 0) +/* Transaction list -- bare address (without label) */ +#define COLOR_BAREADDRESS QColor(140, 140, 140) + +/* Tooltips longer than this (in characters) are converted into rich text, + so that they can be word-wrapped. + */ +static const int TOOLTIP_WRAP_THRESHOLD = 80; + +/* Maximum allowed URI length */ +static const int MAX_URI_LENGTH = 255; + +/* QRCodeDialog -- size of exported QR Code image */ +#define EXPORT_IMAGE_SIZE 256 + +#endif // GUICONSTANTS_H diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp new file mode 100644 index 0000000..7ec933b --- /dev/null +++ b/src/qt/guiutil.cpp @@ -0,0 +1,457 @@ +#include "guiutil.h" +#include "bitcoinaddressvalidator.h" +#include "walletmodel.h" +#include "bitcoinunits.h" +#include "util.h" +#include "init.h" + +#include +#include +#include +#include +#include +#include +#include // For Qt::escape +#include +#include +#include +#include +#include +#include + +#include +#include + +#ifdef WIN32 +#ifdef _WIN32_WINNT +#undef _WIN32_WINNT +#endif +#define _WIN32_WINNT 0x0501 +#ifdef _WIN32_IE +#undef _WIN32_IE +#endif +#define _WIN32_IE 0x0501 +#define WIN32_LEAN_AND_MEAN 1 +#ifndef NOMINMAX +#define NOMINMAX +#endif +#include "shlwapi.h" +#include "shlobj.h" +#include "shellapi.h" +#endif + +namespace GUIUtil { + +QString dateTimeStr(const QDateTime &date) +{ + return date.date().toString(Qt::SystemLocaleShortDate) + QString(" ") + date.toString("hh:mm"); +} + +QString dateTimeStr(qint64 nTime) +{ + return dateTimeStr(QDateTime::fromTime_t((qint32)nTime)); +} + +QFont bitcoinAddressFont() +{ + QFont font("Monospace"); + font.setStyleHint(QFont::TypeWriter); + return font; +} + +void setupAddressWidget(QLineEdit *widget, QWidget *parent) +{ + widget->setMaxLength(BitcoinAddressValidator::MaxAddressLength); + widget->setValidator(new BitcoinAddressValidator(parent)); + widget->setFont(bitcoinAddressFont()); +} + +void setupAmountWidget(QLineEdit *widget, QWidget *parent) +{ + QDoubleValidator *amountValidator = new QDoubleValidator(parent); + amountValidator->setDecimals(8); + amountValidator->setBottom(0.0); + widget->setValidator(amountValidator); + widget->setAlignment(Qt::AlignRight|Qt::AlignVCenter); +} + +bool parseBitcoinURI(const QUrl &uri, SendCoinsRecipient *out) +{ + if(uri.scheme() != QString("bitcoin")) + return false; + + SendCoinsRecipient rv; + rv.address = uri.path(); + rv.amount = 0; + QList > items = uri.queryItems(); + for (QList >::iterator i = items.begin(); i != items.end(); i++) + { + bool fShouldReturnFalse = false; + if (i->first.startsWith("req-")) + { + i->first.remove(0, 4); + fShouldReturnFalse = true; + } + + if (i->first == "label") + { + rv.label = i->second; + fShouldReturnFalse = false; + } + else if (i->first == "amount") + { + if(!i->second.isEmpty()) + { + if(!BitcoinUnits::parse(BitcoinUnits::BTC, i->second, &rv.amount)) + { + return false; + } + } + fShouldReturnFalse = false; + } + + if (fShouldReturnFalse) + return false; + } + if(out) + { + *out = rv; + } + return true; +} + +bool parseBitcoinURI(QString uri, SendCoinsRecipient *out) +{ + // Convert bitcoin:// to bitcoin: + // + // Cannot handle this later, because bitcoin:// will cause Qt to see the part after // as host, + // which will lower-case it (and thus invalidate the address). + if(uri.startsWith("bitcoin://")) + { + uri.replace(0, 10, "bitcoin:"); + } + QUrl uriInstance(uri); + return parseBitcoinURI(uriInstance, out); +} + +QString HtmlEscape(const QString& str, bool fMultiLine) +{ + QString escaped = Qt::escape(str); + if(fMultiLine) + { + escaped = escaped.replace("\n", "
\n"); + } + return escaped; +} + +QString HtmlEscape(const std::string& str, bool fMultiLine) +{ + return HtmlEscape(QString::fromStdString(str), fMultiLine); +} + +void copyEntryData(QAbstractItemView *view, int column, int role) +{ + if(!view || !view->selectionModel()) + return; + QModelIndexList selection = view->selectionModel()->selectedRows(column); + + if(!selection.isEmpty()) + { + // Copy first item + QApplication::clipboard()->setText(selection.at(0).data(role).toString()); + } +} + +QString getSaveFileName(QWidget *parent, const QString &caption, + const QString &dir, + const QString &filter, + QString *selectedSuffixOut) +{ + QString selectedFilter; + QString myDir; + if(dir.isEmpty()) // Default to user documents location + { + myDir = QDesktopServices::storageLocation(QDesktopServices::DocumentsLocation); + } + else + { + myDir = dir; + } + QString result = QFileDialog::getSaveFileName(parent, caption, myDir, filter, &selectedFilter); + + /* Extract first suffix from filter pattern "Description (*.foo)" or "Description (*.foo *.bar ...) */ + QRegExp filter_re(".* \\(\\*\\.(.*)[ \\)]"); + QString selectedSuffix; + if(filter_re.exactMatch(selectedFilter)) + { + selectedSuffix = filter_re.cap(1); + } + + /* Add suffix if needed */ + QFileInfo info(result); + if(!result.isEmpty()) + { + if(info.suffix().isEmpty() && !selectedSuffix.isEmpty()) + { + /* No suffix specified, add selected suffix */ + if(!result.endsWith(".")) + result.append("."); + result.append(selectedSuffix); + } + } + + /* Return selected suffix if asked to */ + if(selectedSuffixOut) + { + *selectedSuffixOut = selectedSuffix; + } + return result; +} + +Qt::ConnectionType blockingGUIThreadConnection() +{ + if(QThread::currentThread() != QCoreApplication::instance()->thread()) + { + return Qt::BlockingQueuedConnection; + } + else + { + return Qt::DirectConnection; + } +} + +bool checkPoint(const QPoint &p, const QWidget *w) +{ + QWidget *atW = qApp->widgetAt(w->mapToGlobal(p)); + if (!atW) return false; + return atW->topLevelWidget() == w; +} + +bool isObscured(QWidget *w) +{ + return !(checkPoint(QPoint(0, 0), w) + && checkPoint(QPoint(w->width() - 1, 0), w) + && checkPoint(QPoint(0, w->height() - 1), w) + && checkPoint(QPoint(w->width() - 1, w->height() - 1), w) + && checkPoint(QPoint(w->width() / 2, w->height() / 2), w)); +} + +void openDebugLogfile() +{ + boost::filesystem::path pathDebug = GetDataDir() / "debug.log"; + + /* Open debug.log with the associated application */ + if (boost::filesystem::exists(pathDebug)) + QDesktopServices::openUrl(QUrl::fromLocalFile(QString::fromStdString(pathDebug.string()))); +} + +ToolTipToRichTextFilter::ToolTipToRichTextFilter(int size_threshold, QObject *parent) : + QObject(parent), size_threshold(size_threshold) +{ + +} + +bool ToolTipToRichTextFilter::eventFilter(QObject *obj, QEvent *evt) +{ + if(evt->type() == QEvent::ToolTipChange) + { + QWidget *widget = static_cast(obj); + QString tooltip = widget->toolTip(); + if(tooltip.size() > size_threshold && !tooltip.startsWith("") && !Qt::mightBeRichText(tooltip)) + { + // Prefix to make sure Qt detects this as rich text + // Escape the current message as HTML and replace \n by
+ tooltip = "" + HtmlEscape(tooltip, true); + widget->setToolTip(tooltip); + return true; + } + } + return QObject::eventFilter(obj, evt); +} + +#ifdef WIN32 +boost::filesystem::path static StartupShortcutPath() +{ + return GetSpecialFolderPath(CSIDL_STARTUP) / "triangles.lnk"; +} + +bool GetStartOnSystemStartup() +{ + // check for Bitcoin.lnk + return boost::filesystem::exists(StartupShortcutPath()); +} + +bool SetStartOnSystemStartup(bool fAutoStart) +{ + // If the shortcut exists already, remove it for updating + boost::filesystem::remove(StartupShortcutPath()); + + if (fAutoStart) + { + CoInitialize(NULL); + + // Get a pointer to the IShellLink interface. + IShellLink* psl = NULL; + HRESULT hres = CoCreateInstance(CLSID_ShellLink, NULL, + CLSCTX_INPROC_SERVER, IID_IShellLink, + reinterpret_cast(&psl)); + + if (SUCCEEDED(hres)) + { + // Get the current executable path + TCHAR pszExePath[MAX_PATH]; + GetModuleFileName(NULL, pszExePath, sizeof(pszExePath)); + + TCHAR pszArgs[5] = TEXT("-min"); + + // Set the path to the shortcut target + psl->SetPath(pszExePath); + PathRemoveFileSpec(pszExePath); + psl->SetWorkingDirectory(pszExePath); + psl->SetShowCmd(SW_SHOWMINNOACTIVE); + psl->SetArguments(pszArgs); + + // Query IShellLink for the IPersistFile interface for + // saving the shortcut in persistent storage. + IPersistFile* ppf = NULL; + hres = psl->QueryInterface(IID_IPersistFile, + reinterpret_cast(&ppf)); + if (SUCCEEDED(hres)) + { + WCHAR pwsz[MAX_PATH]; + // Ensure that the string is ANSI. + MultiByteToWideChar(CP_ACP, 0, StartupShortcutPath().string().c_str(), -1, pwsz, MAX_PATH); + // Save the link by calling IPersistFile::Save. + hres = ppf->Save(pwsz, TRUE); + ppf->Release(); + psl->Release(); + CoUninitialize(); + return true; + } + psl->Release(); + } + CoUninitialize(); + return false; + } + return true; +} + +#elif defined(LINUX) + +// Follow the Desktop Application Autostart Spec: +// http://standards.freedesktop.org/autostart-spec/autostart-spec-latest.html + +boost::filesystem::path static GetAutostartDir() +{ + namespace fs = boost::filesystem; + + char* pszConfigHome = getenv("XDG_CONFIG_HOME"); + if (pszConfigHome) return fs::path(pszConfigHome) / "autostart"; + char* pszHome = getenv("HOME"); + if (pszHome) return fs::path(pszHome) / ".config" / "autostart"; + return fs::path(); +} + +boost::filesystem::path static GetAutostartFilePath() +{ + return GetAutostartDir() / "triangles.desktop"; +} + +bool GetStartOnSystemStartup() +{ + boost::filesystem::ifstream optionFile(GetAutostartFilePath()); + if (!optionFile.good()) + return false; + // Scan through file for "Hidden=true": + std::string line; + while (!optionFile.eof()) + { + getline(optionFile, line); + if (line.find("Hidden") != std::string::npos && + line.find("true") != std::string::npos) + return false; + } + optionFile.close(); + + return true; +} + +bool SetStartOnSystemStartup(bool fAutoStart) +{ + if (!fAutoStart) + boost::filesystem::remove(GetAutostartFilePath()); + else + { + char pszExePath[MAX_PATH+1]; + memset(pszExePath, 0, sizeof(pszExePath)); + if (readlink("/proc/self/exe", pszExePath, sizeof(pszExePath)-1) == -1) + return false; + + boost::filesystem::create_directories(GetAutostartDir()); + + boost::filesystem::ofstream optionFile(GetAutostartFilePath(), std::ios_base::out|std::ios_base::trunc); + if (!optionFile.good()) + return false; + // Write a bitcoin.desktop file to the autostart directory: + optionFile << "[Desktop Entry]\n"; + optionFile << "Type=Application\n"; + optionFile << "Name=triangles\n"; + optionFile << "Exec=" << pszExePath << " -min\n"; + optionFile << "Terminal=false\n"; + optionFile << "Hidden=false\n"; + optionFile.close(); + } + return true; +} +#else + +// TODO: OSX startup stuff; see: +// https://developer.apple.com/library/mac/#documentation/MacOSX/Conceptual/BPSystemStartup/Articles/CustomLogin.html + +bool GetStartOnSystemStartup() { return false; } +bool SetStartOnSystemStartup(bool fAutoStart) { return false; } + +#endif + +HelpMessageBox::HelpMessageBox(QWidget *parent) : + QMessageBox(parent) +{ + header = tr("triangles-qt") + " " + tr("version") + " " + + QString::fromStdString(FormatFullVersion()) + "\n\n" + + tr("Usage:") + "\n" + + " triangles-qt [" + tr("command-line options") + "] " + "\n"; + + coreOptions = QString::fromStdString(HelpMessage()); + + uiOptions = tr("UI options") + ":\n" + + " -lang= " + tr("Set language, for example \"de_DE\" (default: system locale)") + "\n" + + " -min " + tr("Start minimized") + "\n" + + " -splash " + tr("Show splash screen on startup (default: 1)") + "\n"; + + setWindowTitle(tr("triangles-qt")); + setTextFormat(Qt::PlainText); + // setMinimumWidth is ignored for QMessageBox so put in non-breaking spaces to make it wider. + setText(header + QString(QChar(0x2003)).repeated(50)); + setDetailedText(coreOptions + "\n" + uiOptions); +} + +void HelpMessageBox::printToConsole() +{ + // On other operating systems, the expected action is to print the message to the console. + QString strUsage = header + "\n" + coreOptions + "\n" + uiOptions; + fprintf(stdout, "%s", strUsage.toStdString().c_str()); +} + +void HelpMessageBox::showOrPrint() +{ +#if defined(WIN32) + // On Windows, show a message box, as there is no stderr/stdout in windowed applications + exec(); +#else + // On other operating systems, print help text to console + printToConsole(); +#endif +} + +} // namespace GUIUtil + diff --git a/src/qt/guiutil.h b/src/qt/guiutil.h new file mode 100644 index 0000000..db100bd --- /dev/null +++ b/src/qt/guiutil.h @@ -0,0 +1,120 @@ +#ifndef GUIUTIL_H +#define GUIUTIL_H + +#include +#include +#include + +QT_BEGIN_NAMESPACE +class QFont; +class QLineEdit; +class QWidget; +class QDateTime; +class QUrl; +class QAbstractItemView; +QT_END_NAMESPACE +class SendCoinsRecipient; + +/** Utility functions used by the Bitcoin Qt UI. + */ +namespace GUIUtil +{ + // Create human-readable string from date + QString dateTimeStr(const QDateTime &datetime); + QString dateTimeStr(qint64 nTime); + + // Render Bitcoin addresses in monospace font + QFont bitcoinAddressFont(); + + // Set up widgets for address and amounts + void setupAddressWidget(QLineEdit *widget, QWidget *parent); + void setupAmountWidget(QLineEdit *widget, QWidget *parent); + + // Parse "bitcoin:" URI into recipient object, return true on successful parsing + // See Bitcoin URI definition discussion here: https://bitcointalk.org/index.php?topic=33490.0 + bool parseBitcoinURI(const QUrl &uri, SendCoinsRecipient *out); + bool parseBitcoinURI(QString uri, SendCoinsRecipient *out); + + // HTML escaping for rich text controls + QString HtmlEscape(const QString& str, bool fMultiLine=false); + QString HtmlEscape(const std::string& str, bool fMultiLine=false); + + /** Copy a field of the currently selected entry of a view to the clipboard. Does nothing if nothing + is selected. + @param[in] column Data column to extract from the model + @param[in] role Data role to extract from the model + @see TransactionView::copyLabel, TransactionView::copyAmount, TransactionView::copyAddress + */ + void copyEntryData(QAbstractItemView *view, int column, int role=Qt::EditRole); + + /** Get save filename, mimics QFileDialog::getSaveFileName, except that it appends a default suffix + when no suffix is provided by the user. + + @param[in] parent Parent window (or 0) + @param[in] caption Window caption (or empty, for default) + @param[in] dir Starting directory (or empty, to default to documents directory) + @param[in] filter Filter specification such as "Comma Separated Files (*.csv)" + @param[out] selectedSuffixOut Pointer to return the suffix (file type) that was selected (or 0). + Can be useful when choosing the save file format based on suffix. + */ + QString getSaveFileName(QWidget *parent=0, const QString &caption=QString(), + const QString &dir=QString(), const QString &filter=QString(), + QString *selectedSuffixOut=0); + + /** Get connection type to call object slot in GUI thread with invokeMethod. The call will be blocking. + + @returns If called from the GUI thread, return a Qt::DirectConnection. + If called from another thread, return a Qt::BlockingQueuedConnection. + */ + Qt::ConnectionType blockingGUIThreadConnection(); + + // Determine whether a widget is hidden behind other windows + bool isObscured(QWidget *w); + + // Open debug.log + void openDebugLogfile(); + + /** Qt event filter that intercepts ToolTipChange events, and replaces the tooltip with a rich text + representation if needed. This assures that Qt can word-wrap long tooltip messages. + Tooltips longer than the provided size threshold (in characters) are wrapped. + */ + class ToolTipToRichTextFilter : public QObject + { + Q_OBJECT + + public: + explicit ToolTipToRichTextFilter(int size_threshold, QObject *parent = 0); + + protected: + bool eventFilter(QObject *obj, QEvent *evt); + + private: + int size_threshold; + }; + + bool GetStartOnSystemStartup(); + bool SetStartOnSystemStartup(bool fAutoStart); + + /** Help message for Bitcoin-Qt, shown with --help. */ + class HelpMessageBox : public QMessageBox + { + Q_OBJECT + + public: + HelpMessageBox(QWidget *parent = 0); + + /** Show message box or print help message to standard output, based on operating system. */ + void showOrPrint(); + + /** Print help message to console */ + void printToConsole(); + + private: + QString header; + QString coreOptions; + QString uiOptions; + }; + +} // namespace GUIUtil + +#endif // GUIUTIL_H diff --git a/src/qt/httpsocket.cpp b/src/qt/httpsocket.cpp new file mode 100755 index 0000000..b1d87f2 --- /dev/null +++ b/src/qt/httpsocket.cpp @@ -0,0 +1,46 @@ +#include "httpsocket.h" +#include + +httpsocket::httpsocket(QObject *parent) : + QObject(parent) +{ + response = ""; + useProxy = false; +} + +void httpsocket::getUrl(QString url) +{ + if(this->useProxy==true){ + QNetworkProxy proxy; + proxy.setType(QNetworkProxy::HttpProxy); + proxy.setHostName(this->proxyAddress);//"200.50.166.43" + proxy.setPort(this->proxyPort);//8080 + //proxy.setUser("username"); + //proxy.setPassword("password"); + QNetworkProxy::setApplicationProxy(proxy); + } + + qDebug()<< "Connecting..."; + QNetworkAccessManager *manager = new QNetworkAccessManager(this); + connect(manager,SIGNAL(finished(QNetworkReply*)),this,SLOT(replyFinished(QNetworkReply*))); + + manager->get(QNetworkRequest(QUrl(url))); +} + +void httpsocket::replyFinished(QNetworkReply *reply) +{ + if(reply->error()==QNetworkReply::NoError){ + qDebug() << "Response"; + if(reply->isOpen()){ + QString response = reply->readAll(); + this->response = response;//the contents of response = response. + reply->close(); + //qDebug()<<"Finished With Socket Data..."; + } + }else{ + qDebug()<<"Error Occured"; + this->response = "Error"; + this->error = reply->errorString(); + } + emit finished(); +} diff --git a/src/qt/httpsocket.h b/src/qt/httpsocket.h new file mode 100755 index 0000000..f4562d6 --- /dev/null +++ b/src/qt/httpsocket.h @@ -0,0 +1,29 @@ +#ifndef HTTPSOCKET_H +#define HTTPSOCKET_H + +#include +#include +#include +#include +#include + +#include + +class httpsocket : public QObject +{ + Q_OBJECT +public: + explicit httpsocket(QObject *parent = 0); + QString response; + QString error; + QString proxyAddress; + int proxyPort; + bool useProxy; +signals: + void finished(); +public slots: + void getUrl(QString url); + void replyFinished(QNetworkReply *reply); +}; + +#endif // HTTPSOCKET_H diff --git a/src/qt/locale/bitcoin_en.qm b/src/qt/locale/bitcoin_en.qm new file mode 100644 index 0000000000000000000000000000000000000000..3b7d608a6787f38cec9cb05ac12c595ded4fd95f GIT binary patch literal 74856 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 literal 0 HcmV?d00001 diff --git a/src/qt/locale/bitcoin_en.ts b/src/qt/locale/bitcoin_en.ts new file mode 100644 index 0000000..debf8a5 --- /dev/null +++ b/src/qt/locale/bitcoin_en.ts @@ -0,0 +1,2750 @@ + + + +UTF-8 + + AboutDialog + + + About BottleCaps + About BottleCaps + + + + <b>BottleCaps</b> version + <b>BottleCaps</b> version + + + + Copyright © 2009-2012 The BottleCaps developers + Copyright © 2009-2012 The BottleCaps developers + + + + +This is experimental software. + +Distributed under the MIT/X11 software license, see the accompanying file COPYING or http://www.opensource.org/licenses/mit-license.php. + +This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit (http://www.openssl.org/) and cryptographic software written by Eric Young (eay@cryptsoft.com) and UPnP software written by Thomas Bernard. + +This is experimental software. + +Distributed under the MIT/X11 software license, see the accompanying file COPYING or http://www.opensource.org/licenses/mit-license.php. + +This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit (http://www.openssl.org/) and cryptographic software written by Eric Young (eay@cryptsoft.com) and UPnP software written by Thomas Bernard. + + + + AddressBookPage + + + Address Book + Address Book + + + + Double-click to edit address or label + Double-click to edit address or label + + + + Create a new address + Create a new address + + + + Copy the currently selected address to the system clipboard + Copy the currently selected address to the system clipboard + + + + &New Address + &New Address + + + + These are your BottleCaps addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. + These are your BottleCaps addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. + + + + &Copy Address + &Copy Address + + + + Show &QR Code + Show &QR Code + + + + Sign a message to prove you own a BottleCaps address + Sign a message to prove you own a BottleCaps address + + + + Sign &Message + + + + + Delete the currently selected address from the list + + + + + Verify a message to ensure it was signed with a specified BottleCaps address + Verify a message to ensure it was signed with a specified BottleCaps address + + + + &Verify Message + &Verify Message + + + + &Delete + &Delete + + + + Copy &Label + Copy &Label + + + + &Edit + &Edit + + + + Export Address Book Data + Export Address Book Data + + + + Comma separated file (*.csv) + Comma separated file (*.csv) + + + + Error exporting + Error exporting + + + + Could not write to file %1. + Could not write to file %1. + + + + AddressTableModel + + + Label + Label + + + + Address + Address + + + + (no label) + (no label) + + + + AskPassphraseDialog + + + Passphrase Dialog + Passphrase Dialog + + + + Enter passphrase + Enter passphrase + + + + New passphrase + New passphrase + + + + Repeat new passphrase + Repeat new passphrase + + + + Enter the new passphrase to the wallet.<br/>Please use a passphrase of <b>10 or more random characters</b>, or <b>eight or more words</b>. + Enter the new passphrase to the wallet.<br/>Please use a passphrase of <b>10 or more random characters</b>, or <b>eight or more words</b>. + + + + Encrypt wallet + Encrypt wallet + + + + This operation needs your wallet passphrase to unlock the wallet. + This operation needs your wallet passphrase to unlock the wallet. + + + + Unlock wallet + Unlock wallet + + + + This operation needs your wallet passphrase to decrypt the wallet. + This operation needs your wallet passphrase to decrypt the wallet. + + + + Decrypt wallet + Decrypt wallet + + + + Change passphrase + Change passphrase + + + + Enter the old and new passphrase to the wallet. + Enter the old and new passphrase to the wallet. + + + + Confirm wallet encryption + Confirm wallet encryption + + + + Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR COINS</b>! + Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR COINS</b>! + + + + Are you sure you wish to encrypt your wallet? + Are you sure you wish to encrypt your wallet? + + + + IMPORTANT: Any previous backups you have made of your wallet file should be replaced with the newly generated, encrypted wallet file. For security reasons, previous backups of the unencrypted wallet file will become useless as soon as you start using the new, encrypted wallet. + + + + + + Warning: The Caps Lock key is on! + Warning: The Caps Lock key is on! + + + + + Wallet encrypted + Wallet encrypted + + + + BottleCaps will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your coins from being stolen by malware infecting your computer. + BottleCaps will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your coins from being stolen by malware infecting your computer. + + + + + + + Wallet encryption failed + Wallet encryption failed + + + + Wallet encryption failed due to an internal error. Your wallet was not encrypted. + Wallet encryption failed due to an internal error. Your wallet was not encrypted. + + + + + The supplied passphrases do not match. + The supplied passphrases do not match. + + + + Wallet unlock failed + Wallet unlock failed + + + + + + The passphrase entered for the wallet decryption was incorrect. + The passphrase entered for the wallet decryption was incorrect. + + + + Wallet decryption failed + Wallet decryption failed + + + + Wallet passphrase was successfully changed. + Wallet passphrase was successfully changed. + + + + BitcoinGUI + + + Sign &message... + Sign &message... + + + + Synchronizing with network... + Synchronizing with network... + + + + &Overview + &Overview + + + + Show general overview of wallet + Show general overview of wallet + + + + &Transactions + &Transactions + + + + Browse transaction history + Browse transaction history + + + + &Address Book + &Address Book + + + + Edit the list of stored addresses and labels + Edit the list of stored addresses and labels + + + + &Receive coins + &Receive coins + + + + Show the list of addresses for receiving payments + Show the list of addresses for receiving payments + + + + &Send coins + &Send coins + + + + E&xit + E&xit + + + + Quit application + Quit application + + + + Show information about BottleCaps + Show information about BottleCaps + + + + About &Qt + About &Qt + + + + Show information about Qt + Show information about Qt + + + + &Options... + &Options... + + + + &Encrypt Wallet... + &Encrypt Wallet... + + + + &Backup Wallet... + &Backup Wallet... + + + + &Change Passphrase... + &Change Passphrase... + + + + ~%n block(s) remaining + + ~%n block remaining + ~%n blocks remaining + + + + + Downloaded %1 of %2 blocks of transaction history (%3% done). + Downloaded %1 of %2 blocks of transaction history (%3% done). + + + + &Export... + &Export... + + + + Send coins to a BottleCaps address + Send coins to a BottleCaps address + + + + Modify configuration options for BottleCaps + Modify configuration options for BottleCaps + + + + Export the data in the current tab to a file + Export the data in the current tab to a file + + + + Encrypt or decrypt wallet + Encrypt or decrypt wallet + + + + Backup wallet to another location + Backup wallet to another location + + + + Change the passphrase used for wallet encryption + Change the passphrase used for wallet encryption + + + + &Debug window + &Debug window + + + + Open debugging and diagnostic console + Open debugging and diagnostic console + + + + &Verify message... + &Verify message... + + + + BottleCaps + BottleCaps + + + + Wallet + Wallet + + + + &About BottleCaps + &About BottleCaps + + + + &Show / Hide + &Show / Hide + + + + &File + &File + + + + &Settings + &Settings + + + + &Help + &Help + + + + Tabs toolbar + Tabs toolbar + + + + Actions toolbar + Actions toolbar + + + + + [testnet] + [testnet] + + + + + BottleCaps client + BottleCaps client + + + + %n active connection(s) to BottleCaps network + + %n active connection to BottleCaps network + %n active connections to BottleCaps network + + + + + Downloaded %1 blocks of transaction history. + Downloaded %1 blocks of transaction history. + + + + %n second(s) ago + + %n second ago + %n seconds ago + + + + + %n minute(s) ago + + %n minute ago + %n minutes ago + + + + + %n hour(s) ago + + %n hour ago + %n hours ago + + + + + %n day(s) ago + + %n day ago + %n days ago + + + + + Up to date + Up to date + + + + Catching up... + Catching up... + + + + Last received block was generated %1. + Last received block was generated %1. + + + + This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? + + + + + Confirm transaction fee + Confirm transaction fee + + + + Sent transaction + Sent transaction + + + + Incoming transaction + Incoming transaction + + + + Date: %1 +Amount: %2 +Type: %3 +Address: %4 + + Date: %1 +Amount: %2 +Type: %3 +Address: %4 + + + + + + URI handling + URI handling + + + + + URI can not be parsed! This can be caused by an invalid BottleCaps address or malformed URI parameters. + URI can not be parsed! This can be caused by an invalid BottleCaps address or malformed URI parameters. + + + + Wallet is <b>encrypted</b> and currently <b>unlocked</b> + Wallet is <b>encrypted</b> and currently <b>unlocked</b> + + + + Wallet is <b>encrypted</b> and currently <b>locked</b> + Wallet is <b>encrypted</b> and currently <b>locked</b> + + + + Backup Wallet + Backup Wallet + + + + Wallet Data (*.dat) + Wallet Data (*.dat) + + + + Backup Failed + Backup Failed + + + + There was an error trying to save the wallet data to the new location. + There was an error trying to save the wallet data to the new location. + + + + A fatal error occurred. BottleCaps can no longer continue safely and will quit. + A fatal error occurred. BottleCaps can no longer continue safely and will quit. + + + + ClientModel + + + Network Alert + Network Alert + + + + EditAddressDialog + + + Edit Address + Edit Address + + + + &Label + &Label + + + + The label associated with this address book entry + The label associated with this address book entry + + + + &Address + &Address + + + + The address associated with this address book entry. This can only be modified for sending addresses. + The address associated with this address book entry. This can only be modified for sending addresses. + + + + New receiving address + New receiving address + + + + New sending address + New sending address + + + + Edit receiving address + Edit receiving address + + + + Edit sending address + Edit sending address + + + + The entered address "%1" is already in the address book. + The entered address "%1" is already in the address book. + + + + The entered address "%1" is not a valid BottleCaps address. + The entered address "%1" is not a valid BottleCaps address. + + + + Could not unlock wallet. + Could not unlock wallet. + + + + New key generation failed. + New key generation failed. + + + + GUIUtil::HelpMessageBox + + + + BottleCaps-Qt + BottleCaps-Qt + + + + version + version + + + + Usage: + Usage: + + + + command-line options + command-line options + + + + UI options + UI options + + + + Set language, for example "de_DE" (default: system locale) + Set language, for example "de_DE" (default: system locale) + + + + Start minimized + Start minimized + + + + Show splash screen on startup (default: 1) + Show splash screen on startup (default: 1) + + + + OptionsDialog + + + Options + Options + + + + &Main + &Main + + + + Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. Fee 0.01 recommended. + Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. Fee 0.01 recommended. + + + + Pay transaction &fee + Pay transaction &fee + + + + Automatically start BottleCaps after logging in to the system. + Automatically start BottleCaps after logging in to the system. + + + + &Start BottleCaps on system login + &Start BottleCaps on system login + + + + Detach block and address databases at shutdown. This means they can be moved to another data directory, but it slows down shutdown. The wallet is always detached. + Detach block and address databases at shutdown. This means they can be moved to another data directory, but it slows down shutdown. The wallet is always detached. + + + + &Detach databases at shutdown + &Detach databases at shutdown + + + + &Network + &Network + + + + Automatically open the BottleCaps client port on the router. This only works when your router supports UPnP and it is enabled. + Automatically open the BottleCaps client port on the router. This only works when your router supports UPnP and it is enabled. + + + + Map port using &UPnP + Map port using &UPnP + + + + Connect to the BottleCaps network through a SOCKS proxy (e.g. when connecting through Tor). + Connect to the BottleCaps network through a SOCKS proxy (e.g. when connecting through Tor). + + + + &Connect through SOCKS proxy: + &Connect through SOCKS proxy: + + + + Proxy &IP: + Proxy &IP: + + + + IP address of the proxy (e.g. 127.0.0.1) + IP address of the proxy (e.g. 127.0.0.1) + + + + &Port: + &Port: + + + + Port of the proxy (e.g. 9050) + Port of the proxy (e.g. 9050) + + + + SOCKS &Version: + SOCKS &Version: + + + + SOCKS version of the proxy (e.g. 5) + SOCKS version of the proxy (e.g. 5) + + + + &Window + &Window + + + + Show only a tray icon after minimizing the window. + Show only a tray icon after minimizing the window. + + + + &Minimize to the tray instead of the taskbar + &Minimize to the tray instead of the taskbar + + + + Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu. + Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu. + + + + M&inimize on close + M&inimize on close + + + + &Display + &Display + + + + User Interface &language: + User Interface &language: + + + + The user interface language can be set here. This setting will take effect after restarting BottleCaps. + The user interface language can be set here. This setting will take effect after restarting BottleCaps. + + + + &Unit to show amounts in: + &Unit to show amounts in: + + + + Choose the default subdivision unit to show in the interface and when sending coins. + Choose the default subdivision unit to show in the interface and when sending coins. + + + + Whether to show BottleCaps addresses in the transaction list or not. + Whether to show BottleCaps addresses in the transaction list or not. + + + + &Display addresses in transaction list + &Display addresses in transaction list + + + + &OK + &OK + + + + &Cancel + &Cancel + + + + &Apply + &Apply + + + + default + default + + + + + Warning + Warning + + + + + This setting will take effect after restarting BottleCaps. + This setting will take effect after restarting BottleCaps. + + + + The supplied proxy address is invalid. + The supplied proxy address is invalid. + + + + OverviewPage + + + Form + Form + + + + + The displayed information may be out of date. Your wallet automatically synchronizes with the BottleCaps network after a connection is established, but this process has not completed yet. + The displayed information may be out of date. Your wallet automatically synchronizes with the BottleCaps network after a connection is established, but this process has not completed yet. + + + + Balance: + Balance: + + + + Stake: + Stake: + + + + Number of transactions: + Number of transactions: + + + + Unconfirmed: + Unconfirmed: + + + + Wallet + Wallet + + + + Immature: + Immature: + + + + Mined balance that has not yet matured + Mined balance that has not yet matured + + + + <b>Recent transactions</b> + <b>Recent transactions</b> + + + + Your current balance + Your current balance + + + + Total of transactions that have yet to be confirmed, and do not yet count toward the current balance + Total of transactions that have yet to be confirmed, and do not yet count toward the current balance + + + + Total of coins that was staked, and do not yet count toward the current balance + Total of coins that was staked, and do not yet count toward the current balance + + + + Total number of transactions in wallet + Total number of transactions in wallet + + + + + out of sync + out of sync + + + + QRCodeDialog + + + QR Code Dialog + QR Code Dialog + + + + Request Payment + Request Payment + + + + Amount: + Amount: + + + + Label: + Label: + + + + Message: + Message: + + + + &Save As... + &Save As... + + + + Error encoding URI into QR Code. + Error encoding URI into QR Code. + + + + The entered amount is invalid, please check. + The entered amount is invalid, please check. + + + + Resulting URI too long, try to reduce the text for label / message. + Resulting URI too long, try to reduce the text for label / message. + + + + Save QR Code + Save QR Code + + + + PNG Images (*.png) + PNG Images (*.png) + + + + RPCConsole + + + Client name + Client name + + + + + + + + + + + + + N/A + N/A + + + + Client version + Client version + + + + &Information + &Information + + + + Using OpenSSL version + Using OpenSSL version + + + + Startup time + Startup time + + + + Network + Network + + + + Number of connections + Number of connections + + + + On testnet + On testnet + + + + Block chain + Block chain + + + + Current number of blocks + Current number of blocks + + + + Estimated total blocks + Estimated total blocks + + + + Last block time + Last block time + + + + &Open + &Open + + + + Command-line options + Command-line options + + + + Show the BottleCaps-Qt help message to get a list with possible BottleCaps command-line options. + Show the BottleCaps-Qt help message to get a list with possible BottleCaps command-line options. + + + + &Show + &Show + + + + &Console + &Console + + + + Build date + Build date + + + + BottleCaps - Debug window + BottleCaps - Debug window + + + + BottleCaps Core + BottleCaps Core + + + + Debug log file + Debug log file + + + + Open the BottleCaps debug log file from the current data directory. This can take a few seconds for large log files. + Open the BottleCaps debug log file from the current data directory. This can take a few seconds for large log files. + + + + Clear console + Clear console + + + + Welcome to the BottleCaps RPC console. + Welcome to the BottleCaps RPC console. + + + + Use up and down arrows to navigate history, and <b>Ctrl-L</b> to clear screen. + Use up and down arrows to navigate history, and <b>Ctrl-L</b> to clear screen. + + + + Type <b>help</b> for an overview of available commands. + Type <b>help</b> for an overview of available commands. + + + + SendCoinsDialog + + + + + + + + + + Send Coins + Send Coins + + + + Send to multiple recipients at once + Send to multiple recipients at once + + + + Add &Recipient + + + + + Remove all transaction fields + Remove all transaction fields + + + + Clear &All + Clear &All + + + + Balance: + Balance: + + + + 123.456 BTC + 123.456 BTC + + + + Confirm the send action + Confirm the send action + + + + S&end + + + + + <b>%1</b> to %2 (%3) + <b>%1</b> to %2 (%3) + + + + Confirm send coins + Confirm send coins + + + + Are you sure you want to send %1? + Are you sure you want to send %1? + + + + and + and + + + + The recipient address is not valid, please recheck. + The recipient address is not valid, please recheck. + + + + The amount to pay must be larger than 0. + The amount to pay must be larger than 0. + + + + The amount exceeds your balance. + The amount exceeds your balance. + + + + The total exceeds your balance when the %1 transaction fee is included. + The total exceeds your balance when the %1 transaction fee is included. + + + + Duplicate address found, can only send to each address once per send operation. + Duplicate address found, can only send to each address once per send operation. + + + + Error: Transaction creation failed. + Error: Transaction creation failed. + + + + Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. + Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. + + + + SendCoinsEntry + + + Form + Form + + + + A&mount: + A&mount: + + + + Pay &To: + Pay &To: + + + + + Enter a label for this address to add it to your address book + Enter a label for this address to add it to your address book + + + + &Label: + &Label: + + + + The address to send the payment to (e.g. 4Zo1ga6xuKuQ7JV7M9rGDoxdbYwV5zgQJ5) + + + + + Choose address from address book + Choose address from address book + + + + Alt+A + Alt+A + + + + Paste address from clipboard + Paste address from clipboard + + + + Alt+P + Alt+P + + + + Remove this recipient + Remove this recipient + + + + Enter a valid BottleCaps address + Enter a valid BottleCaps address + + + + SignVerifyMessageDialog + + + Signatures - Sign / Verify a Message + Signatures - Sign / Verify a Message + + + + + &Sign Message + &Sign Message + + + + You can sign messages with your addresses to prove you own them. Be careful not to sign anything vague, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to. + You can sign messages with your addresses to prove you own them. Be careful not to sign anything vague, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to. + + + + The address to sign the message with + The address to sign the message with + + + + + Choose an address from the address book + Choose an address from the address book + + + + + Alt+A + Alt+A + + + + Paste address from clipboard + Paste address from clipboard + + + + Alt+P + Alt+P + + + + Enter the message you want to sign here + Enter the message you want to sign here + + + + Copy the current signature to the system clipboard + Copy the current signature to the system clipboard + + + + Sign the message to prove you own this BottleCaps address + Sign the message to prove you own this BottleCaps address + + + + Reset all sign message fields + Reset all sign message fields + + + + + Clear &All + Clear &All + + + + + &Verify Message + &Verify Message + + + + Enter the signing address, message (ensure you copy line breaks, spaces, tabs, etc. exactly) and signature below to verify the message. Be careful not to read more into the signature than what is in the signed message itself, to avoid being tricked by a man-in-the-middle attack. + Enter the signing address, message (ensure you copy line breaks, spaces, tabs, etc. exactly) and signature below to verify the message. Be careful not to read more into the signature than what is in the signed message itself, to avoid being tricked by a man-in-the-middle attack. + + + + The address the message was signed with + The address the message was signed with + + + + Verify the message to ensure it was signed with the specified BottleCaps address + Verify the message to ensure it was signed with the specified BottleCaps address + + + + Reset all verify message fields + Reset all verify message fields + + + + + Enter a valid BottleCaps address + Enter a valid BottleCaps address + + + + Click "Sign Message" to generate signature + Click "Sign Message" to generate signature + + + + Enter BottleCaps signature + Enter BottleCaps signature + + + + + The entered address is invalid. + The entered address is invalid. + + + + + + + Please check the address and try again. + Please check the address and try again. + + + + + The entered address does not refer to a key. + The entered address does not refer to a key. + + + + Wallet unlock was cancelled. + Wallet unlock was cancelled. + + + + Private key for the entered address is not available. + Private key for the entered address is not available. + + + + Message signing failed. + Message signing failed. + + + + Message signed. + Message signed. + + + + The signature could not be decoded. + The signature could not be decoded. + + + + + Please check the signature and try again. + Please check the signature and try again. + + + + The signature did not match the message digest. + The signature did not match the message digest. + + + + Message verification failed. + Message verification failed. + + + + Message verified. + Message verified. + + + + TransactionDesc + + + Open until %1 + Open until %1 + + + + Open for %n block(s) + + Open for %n block + Open for %n blocks + + + + + %1/offline + %1/offline + + + + %1/unconfirmed + %1/unconfirmed + + + + %1 confirmations + %1 confirmations + + + + Status + Status + + + + , broadcast through %n node(s) + + , broadcast through %n node + , broadcast through %n nodes + + + + + Date + Date + + + + Source + Source + + + + Generated + Generated + + + + + From + From + + + + + + To + To + + + + + own address + own address + + + + label + label + + + + + + + + Credit + Credit + + + + matures in %n more block(s) + + matures in %n more block + matures in %n more blocks + + + + + not accepted + not accepted + + + + + + + Debit + Debit + + + + Transaction fee + Transaction fee + + + + Net amount + Net amount + + + + Message + Message + + + + Comment + Comment + + + + Transaction ID + Transaction ID + + + + Generated coins must mature 520 blocks before they can be spent. When you generated this block, it was broadcast to the network to be added to the block chain. If it fails to get into the chain, its state will change to "not accepted" and it won't be spendable. This may occasionally happen if another node generates a block within a few seconds of yours. + Generated coins must mature 520 blocks before they can be spent. When you generated this block, it was broadcast to the network to be added to the block chain. If it fails to get into the chain, its state will change to "not accepted" and it won't be spendable. This may occasionally happen if another node generates a block within a few seconds of yours. + + + + Staked coins must wait 520 blocks before they can return to balance and be spent. When you generated this proof-of-stake block, it was broadcast to the network to be added to the block chain. If it fails to get into the chain, it will change to \"not accepted\" and not be a valid stake. This may occasionally happen if another node generates a proof-of-stake block within a few seconds of yours. + Staked coins must wait 520 blocks before they can return to balance and be spent. When you generated this proof-of-stake block, it was broadcast to the network to be added to the block chain. If it fails to get into the chain, it will change to \"not accepted\" and not be a valid stake. This may occasionally happen if another node generates a proof-of-stake block within a few seconds of yours. + + + + Debug information + Debug information + + + + Transaction + Transaction + + + + Inputs + Inputs + + + + Amount + Amount + + + + true + true + + + + false + false + + + + , has not been successfully broadcast yet + , has not been successfully broadcast yet + + + + unknown + unknown + + + + TransactionDescDialog + + + Transaction details + Transaction details + + + + This pane shows a detailed description of the transaction + This pane shows a detailed description of the transaction + + + + TransactionTableModel + + + Date + Date + + + + Type + Type + + + + Address + Address + + + + Amount + Amount + + + + Open for %n block(s) + + Open for %n block + Open for %n blocks + + + + + Open until %1 + Open until %1 + + + + Offline (%1 confirmations) + Offline (%1 confirmations) + + + + Unconfirmed (%1 of %2 confirmations) + Unconfirmed (%1 of %2 confirmations) + + + + Confirmed (%1 confirmations) + Confirmed (%1 confirmations) + + + + Mined balance will be available when it matures in %n more block(s) + + Mined balance will be available when it matures in %n more block + Mined balance will be available when it matures in %n more blocks + + + + + This block was not received by any other nodes and will probably not be accepted! + This block was not received by any other nodes and will probably not be accepted! + + + + Generated but not accepted + Generated but not accepted + + + + Received with + Received with + + + + Received from + Received from + + + + Sent to + Sent to + + + + Payment to yourself + Payment to yourself + + + + Mined + Mined + + + + Minted + Minted + + + + (n/a) + (n/a) + + + + Transaction status. Hover over this field to show number of confirmations. + Transaction status. Hover over this field to show number of confirmations. + + + + Date and time that the transaction was received. + Date and time that the transaction was received. + + + + Type of transaction. + Type of transaction. + + + + Destination address of transaction. + Destination address of transaction. + + + + Amount removed from or added to balance. + Amount removed from or added to balance. + + + + TransactionView + + + + All + All + + + + Today + Today + + + + This week + This week + + + + This month + This month + + + + Last month + Last month + + + + This year + This year + + + + Range... + Range... + + + + Received with + Received with + + + + Sent to + Sent to + + + + To yourself + To yourself + + + + Mined + Mined + + + + Minted + Minted + + + + Other + Other + + + + Enter address or label to search + Enter address or label to search + + + + Min amount + Min amount + + + + Copy address + Copy address + + + + Copy label + Copy label + + + + Copy amount + Copy amount + + + + Edit label + Edit label + + + + Show transaction details + Show transaction details + + + + Export Transaction Data + Export Transaction Data + + + + Comma separated file (*.csv) + Comma separated file (*.csv) + + + + Confirmed + Confirmed + + + + Date + Date + + + + Type + Type + + + + Label + Label + + + + Address + Address + + + + Amount + Amount + + + + ID + ID + + + + Error exporting + Error exporting + + + + Could not write to file %1. + Could not write to file %1. + + + + Range: + Range: + + + + to + to + + + + WalletModel + + + Sending... + Sending... + + + + bitcoin-core + + + BottleCaps version + BottleCaps version + + + + Usage: + Usage: + + + + Send command to -server or bitcoind + Send command to -server or bitcoind + + + + List commands + List commands + + + + Get help for a command + Get help for a command + + + + Options: + Options: + + + + Specify configuration file (default: BottleCaps.conf) + Specify configuration file (default: BottleCaps.conf) + + + + Specify pid file (default: BottleCapsd.pid) + Specify pid file (default: BottleCapsd.pid) + + + + Generate coins + Generate coins + + + + Don't generate coins + Don't generate coins + + + + Specify data directory + Specify data directory + + + + Set database cache size in megabytes (default: 25) + Set database cache size in megabytes (default: 25) + + + + Set database disk log size in megabytes (default: 100) + Set database disk log size in megabytes (default: 100) + + + + Listen for connections on <port> (default: 7777 or testnet: 17777) + Listen for connections on <port> (default: 8333 or testnet: 18333) + + + + Maintain at most <n> connections to peers (default: 125) + Maintain at most <n> connections to peers (default: 125) + + + + Connect to a node to retrieve peer addresses, and disconnect + Connect to a node to retrieve peer addresses, and disconnect + + + + Specify your own public address + Specify your own public address + + + + Bind to given address. Use [host]:port notation for IPv6 + Bind to given address. Use [host]:port notation for IPv6 + + + + Threshold for disconnecting misbehaving peers (default: 100) + Threshold for disconnecting misbehaving peers (default: 100) + + + + Number of seconds to keep misbehaving peers from reconnecting (default: 86400) + Number of seconds to keep misbehaving peers from reconnecting (default: 86400) + + + + An error occurred while setting up the RPC port %u for listening on IPv4: %s + + + + + Detach block and address databases. Increases shutdown time (default: 0) + Detach block and address databases. Increases shutdown time (default: 0) + + + + Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. + + + + + Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds + + + + + Listen for JSON-RPC connections on <port> (default: 8344 or testnet: 18344) + + + + + Accept command line and JSON-RPC commands + Accept command line and JSON-RPC commands + + + + Error: Transaction creation failed + + + + + Error: Wallet locked, unable to create transaction + + + + + Importing blockchain data file. + + + + + Importing bootstrap blockchain data file. + + + + + Run in the background as a daemon and accept commands + Run in the background as a daemon and accept commands + + + + Use the test network + Use the test network + + + + Accept connections from outside (default: 1 if no -proxy or -connect) + Accept connections from outside (default: 1 if no -proxy or -connect) + + + + An error occurred while setting up the RPC port %u for listening on IPv6, falling back to IPv4: %s + + + + + Error initializing database environment %s! To recover, BACKUP THAT DIRECTORY, then remove everything from it except for wallet.dat. + + + + + Set maximum size of high-priority/low-fee transactions in bytes (default: 27000) + Set maximum size of high-priority/low-fee transactions in bytes (default: 27000) + + + + Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. + Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. + + + + Warning: Displayed transactions may not be correct! You may need to upgrade, or other nodes may need to upgrade. + Warning: Displayed transactions may not be correct! You may need to upgrade, or other nodes may need to upgrade. + + + + Warning: Please check that your computer's date and time are correct! If your clock is wrong BottleCaps will not work properly. + Warning: Please check that your computer's date and time are correct! If your clock is wrong BottleCaps will not work properly. + + + + Warning: error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. + Warning: error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. + + + + Warning: wallet.dat corrupt, data salvaged! Original wallet.dat saved as wallet.{timestamp}.bak in %s; if your balance or transactions are incorrect you should restore from a backup. + Warning: wallet.dat corrupt, data salvaged! Original wallet.dat saved as wallet.{timestamp}.bak in %s; if your balance or transactions are incorrect you should restore from a backup. + + + + Attempt to recover private keys from a corrupt wallet.dat + Attempt to recover private keys from a corrupt wallet.dat + + + + Block creation options: + Block creation options: + + + + Connect only to the specified node(s) + Connect only to the specified node(s) + + + + Discover own IP address (default: 1 when listening and no -externalip) + Discover own IP address (default: 1 when listening and no -externalip) + + + + Failed to listen on any port. Use -listen=0 if you want this. + Failed to listen on any port. Use -listen=0 if you want this. + + + + Find peers using DNS lookup (default: 0) + Find peers using DNS lookup (default: 0) + + + + Invalid -tor address: '%s' + Invalid -tor address: '%s' + + + + Maximum per-connection receive buffer, <n>*1000 bytes (default: 5000) + Maximum per-connection receive buffer, <n>*1000 bytes (default: 5000) + + + + Maximum per-connection send buffer, <n>*1000 bytes (default: 1000) + Maximum per-connection send buffer, <n>*1000 bytes (default: 1000) + + + + Only connect to nodes in network <net> (IPv4, IPv6 or Tor) + Only connect to nodes in network <net> (IPv4, IPv6 or Tor) + + + + Output extra debugging information. Implies all other -debug* options + Output extra debugging information. Implies all other -debug* options + + + + Output extra network debugging information + Output extra network debugging information + + + + Prepend debug output with timestamp + Prepend debug output with timestamp + + + + SSL options: (see the Bitcoin Wiki for SSL setup instructions) + SSL options: (see the Bitcoin Wiki for SSL setup instructions) + + + + Select the version of socks proxy to use (4-5, default: 5) + Select the version of socks proxy to use (4-5, default: 5) + + + + Send trace/debug info to console instead of debug.log file + Send trace/debug info to console instead of debug.log file + + + + Send trace/debug info to debugger + Send trace/debug info to debugger + + + + Set maximum block size in bytes (default: 250000) + Set maximum block size in bytes (default: 250000) + + + + Set minimum block size in bytes (default: 0) + Set minimum block size in bytes (default: 0) + + + + Shrink debug.log file on client startup (default: 1 when no -debug) + Shrink debug.log file on client startup (default: 1 when no -debug) + + + + Specify connection timeout in milliseconds (default: 5000) + Specify connection timeout in milliseconds (default: 5000) + + + + Use UPnP to map the listening port (default: 0) + Use UPnP to map the listening port (default: 0) + + + + Use UPnP to map the listening port (default: 1 when listening) + Use UPnP to map the listening port (default: 1 when listening) + + + + Use proxy to reach tor hidden services (default: same as -proxy) + Use proxy to reach tor hidden services (default: same as -proxy) + + + + Username for JSON-RPC connections + Username for JSON-RPC connections + + + + Verifying database integrity... + + + + + Warning: Disk space is low! + Warning: Disk space is low! + + + + Warning: This version is obsolete, upgrade required! + Warning: This version is obsolete, upgrade required! + + + + wallet.dat corrupt, salvage failed + + + + + Password for JSON-RPC connections + Password for JSON-RPC connections + + + + Allow JSON-RPC connections from specified IP address + Allow JSON-RPC connections from specified IP address + + + + Send commands to node running on <ip> (default: 127.0.0.1) + Send commands to node running on <ip> (default: 127.0.0.1) + + + + Execute command when the best block changes (%s in cmd is replaced by block hash) + Execute command when the best block changes (%s in cmd is replaced by block hash) + + + + Upgrade wallet to latest format + Upgrade wallet to latest format + + + + Set key pool size to <n> (default: 100) + Set key pool size to <n> (default: 100) + + + + Rescan the block chain for missing wallet transactions + Rescan the block chain for missing wallet transactions + + + + How many blocks to check at startup (default: 2500, 0 = all) + How many blocks to check at startup (default: 2500, 0 = all) + + + + How thorough the block verification is (0-6, default: 1) + How thorough the block verification is (0-6, default: 1) + + + + Imports blocks from external blk000?.dat file + Imports blocks from external blk000?.dat file + + + + Use OpenSSL (https) for JSON-RPC connections + Use OpenSSL (https) for JSON-RPC connections + + + + Server certificate file (default: server.cert) + Server certificate file (default: server.cert) + + + + Server private key (default: server.pem) + Server private key (default: server.pem) + + + + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) + + + + This help message + This help message + + + + Cannot obtain a lock on data directory %s. BottleCaps is probably already running. + Cannot obtain a lock on data directory %s. BottleCaps is probably already running. + + + + BottleCaps + BottleCaps + + + + Unable to bind to %s on this computer (bind returned error %d, %s) + Unable to bind to %s on this computer (bind returned error %d, %s) + + + + Connect through socks proxy + Connect through socks proxy + + + + Allow DNS lookups for -addnode, -seednode and -connect + Allow DNS lookups for -addnode, -seednode and -connect + + + + Loading addresses... + Loading addresses... + + + + Error loading blkindex.dat + Error loading blkindex.dat + + + + Error loading wallet.dat: Wallet corrupted + Error loading wallet.dat: Wallet corrupted + + + + Error loading wallet.dat: Wallet requires newer version of BottleCaps + Error loading wallet.dat: Wallet requires newer version of BottleCaps + + + + Wallet needed to be rewritten: restart BottleCaps to complete + Wallet needed to be rewritten: restart BottleCaps to complete + + + + Error loading wallet.dat + Error loading wallet.dat + + + + Invalid -proxy address: '%s' + Invalid -proxy address: '%s' + + + + Unknown network specified in -onlynet: '%s' + Unknown network specified in -onlynet: '%s' + + + + Unknown -socks proxy version requested: %i + Unknown -socks proxy version requested: %i + + + + Cannot resolve -bind address: '%s' + Cannot resolve -bind address: '%s' + + + + Cannot resolve -externalip address: '%s' + Cannot resolve -externalip address: '%s' + + + + Invalid amount for -paytxfee=<amount>: '%s' + Invalid amount for -paytxfee=<amount>: '%s' + + + + Error: could not start node + Error: could not start node + + + + Sending... + Sending... + + + + Invalid amount + Invalid amount + + + + Insufficient funds + Insufficient funds + + + + Loading block index... + Loading block index... + + + + Add a node to connect to and attempt to keep the connection open + Add a node to connect to and attempt to keep the connection open + + + + Unable to bind to %s on this computer. BottleCaps is probably already running. + Unable to bind to %s on this computer. BottleCaps is probably already running. + + + + Find peers using internet relay chat (default: 1) + Find peers using internet relay chat (default: 1) + + + + Fee per KB to add to transactions you send + Fee per KB to add to transactions you send + + + + Loading wallet... + Loading wallet... + + + + Cannot downgrade wallet + Cannot downgrade wallet + + + + Cannot initialize keypool + Cannot initialize keypool + + + + Cannot write default address + Cannot write default address + + + + Rescanning... + Rescanning... + + + + Done loading + Done loading + + + + To use the %s option + To use the %s option + + + + %s, you must set a rpcpassword in the configuration file: + %s +It is recommended you use the following random password: +rpcuser=bitcoinrpc +rpcpassword=%s +(you do not need to remember this password) +If the file does not exist, create it with owner-readable-only file permissions. + + %s, you must set a rpcpassword in the configuration file: + %s +It is recommended you use the following random password: +rpcuser=bitcoinrpc +rpcpassword=%s +(you do not need to remember this password) +If the file does not exist, create it with owner-readable-only file permissions. + + + + + Error + Error + + + + You must set rpcpassword=<password> in the configuration file: +%s +If the file does not exist, create it with owner-readable-only file permissions. + You must set rpcpassword=<password> in the configuration file: +%s +If the file does not exist, create it with owner-readable-only file permissions. + + + diff --git a/src/qt/locale/bitcoin_ru.qm b/src/qt/locale/bitcoin_ru.qm new file mode 100644 index 0000000000000000000000000000000000000000..bfb4729337aa5802d0701d5b585c57fa9b9609e6 GIT binary patch literal 84243 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

qoUGrnuDd%@IT?@X5 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 literal 0 HcmV?d00001 diff --git a/src/qt/locale/bitcoin_ru.ts b/src/qt/locale/bitcoin_ru.ts new file mode 100644 index 0000000..752a5b3 --- /dev/null +++ b/src/qt/locale/bitcoin_ru.ts @@ -0,0 +1,2753 @@ + + + +UTF-8 + + AboutDialog + + + About BottleCaps + О BottleCaps + + + + <b>BottleCaps</b> version + <b>BottleCaps</b> версия + + + + Copyright © 2009-2012 The BottleCaps developers + Все права защищены © 2009-2012 Разработчики BottleCaps + + + + +This is experimental software. + +Distributed under the MIT/X11 software license, see the accompanying file COPYING or http://www.opensource.org/licenses/mit-license.php. + +This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit (http://www.openssl.org/) and cryptographic software written by Eric Young (eay@cryptsoft.com) and UPnP software written by Thomas Bernard. + +Это экспериментальная программа. + +Распространяется на правах лицензии MIT/X11, см. файл license.txt или http://www.opensource.org/licenses/mit-license.php. + +Этот продукт включает ПО, разработанное OpenSSL Project для использования в OpenSSL Toolkit (http://www.openssl.org/) и криптографическое ПО, написанное Eric Young (eay@cryptsoft.com) и ПО для работы с UPnP, написанное Thomas Bernard. + + + + AddressBookPage + + + Address Book + Адресная книга + + + + Double-click to edit address or label + Для того, чтобы изменить адрес или метку давжды кликните по изменяемому объекту + + + + Create a new address + Создать новый адрес + + + + Copy the currently selected address to the system clipboard + Копировать текущий выделенный адрес в буфер обмена + + + + &New Address + &Новый адрес + + + + These are your BottleCaps addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. + Это Ваши адреса для получения платежей. Вы можете дать разные адреса отправителям, чтобы отслеживать, кто именно вам платит. + + + + &Copy Address + &Копировать адрес + + + + Show &QR Code + Показать &QR код + + + + Sign a message to prove you own a BottleCaps address + Подписать сообщение, чтобы доказать владение адресом BottleCaps + + + + Sign &Message + &Подписать сообщение + + + + Delete the currently selected address from the list + Удалить выбранный адрес из списка + + + + Verify a message to ensure it was signed with a specified BottleCaps address + Проверить сообщение, чтобы убедиться, что оно было подписано указанным адресом BottleCaps + + + + &Verify Message + &Проверить сообщение + + + + &Delete + &Удалить + + + + Copy &Label + Копировать &метку + + + + &Edit + &Правка + + + + Export Address Book Data + Экспортировать адресную книгу + + + + Comma separated file (*.csv) + Текст, разделённый запятыми (*.csv) + + + + Error exporting + Ошибка экспорта + + + + Could not write to file %1. + Невозможно записать в файл %1. + + + + AddressTableModel + + + Label + Метка + + + + Address + Адрес + + + + (no label) + [нет метки] + + + + AskPassphraseDialog + + + Passphrase Dialog + Диалог ввода пароля + + + + Enter passphrase + Введите пароль + + + + New passphrase + Новый пароль + + + + Repeat new passphrase + Повторите новый пароль + + + + Enter the new passphrase to the wallet.<br/>Please use a passphrase of <b>10 or more random characters</b>, or <b>eight or more words</b>. + Введите новый пароль для бумажника. <br/> Пожалуйста, используйте фразы из <b>10 или более случайных символов,</b> или <b>восьми и более слов.</b> + + + + Encrypt wallet + Зашифровать бумажник + + + + This operation needs your wallet passphrase to unlock the wallet. + Для выполнения операции требуется пароль вашего бумажника. + + + + Unlock wallet + Разблокировать бумажник + + + + This operation needs your wallet passphrase to decrypt the wallet. + Для выполнения операции требуется пароль вашего бумажника. + + + + Decrypt wallet + Расшифровать бумажник + + + + Change passphrase + Сменить пароль + + + + Enter the old and new passphrase to the wallet. + Введите старый и новый пароль для бумажника. + + + + Confirm wallet encryption + Подтвердите шифрование бумажника + + + + Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR COINS</b>! + Внимание: если вы зашифруете бумажник и потеряете пароль, вы <b>ПОТЕРЯЕТЕ ВСЕ ВАШИ МОНЕТЫ</b>! + + + + Are you sure you wish to encrypt your wallet? + Вы уверены, что хотите зашифровать ваш бумажник? + + + + IMPORTANT: Any previous backups you have made of your wallet file should be replaced with the newly generated, encrypted wallet file. For security reasons, previous backups of the unencrypted wallet file will become useless as soon as you start using the new, encrypted wallet. + ВАЖНО: все предыдущие резервные копии вашего кошелька должны быть заменены новым зашифрованным файлом. В целях безопасности предыдущие резервные копии нешифрованного кошелька станут бесполезны, как только вы начнёте использовать новый шифрованный кошелёк. + + + + + Warning: The Caps Lock key is on! + Внимание: Caps Lock включен! + + + + + Wallet encrypted + Бумажник зашифрован + + + + BottleCaps will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your coins from being stolen by malware infecting your computer. + Сейчас программа закроется для завершения процесса шифрования. Помните, что шифрование вашего бумажника не может полностью защитить ваши монеты от кражи с помощью инфицирования вашего компьютера вредоносным ПО. + + + + + + + Wallet encryption failed + Не удалось зашифровать бумажник + + + + Wallet encryption failed due to an internal error. Your wallet was not encrypted. + Шифрование бумажника не удалось из-за внутренней ошибки. Ваш бумажник не был зашифрован. + + + + + The supplied passphrases do not match. + Введённые пароли не совпадают. + + + + Wallet unlock failed + Разблокировка бумажника не удалась + + + + + + The passphrase entered for the wallet decryption was incorrect. + Указанный пароль не подходит. + + + + Wallet decryption failed + Расшифрование бумажника не удалось + + + + Wallet passphrase was successfully changed. + Пароль бумажника успешно изменён. + + + + BitcoinGUI + + + Sign &message... + &Подписать сообщение + + + + Synchronizing with network... + Синхронизация с сетью... + + + + &Overview + О&бзор + + + + Show general overview of wallet + Показать общий обзор действий с бумажником + + + + &Transactions + &Транзакции + + + + Browse transaction history + Показать историю транзакций + + + + &Address Book + &Адресная книга + + + + Edit the list of stored addresses and labels + Изменить список сохранённых адресов и меток к ним + + + + &Receive coins + &Получение монет + + + + Show the list of addresses for receiving payments + Показать список адресов для получения платежей + + + + &Send coins + Отп&равка монет + + + + E&xit + В&ыход + + + + Quit application + Закрыть приложение + + + + Show information about BottleCaps + Показать информацию о BottleCaps'е + + + + About &Qt + О &Qt + + + + Show information about Qt + Показать информацию о Qt + + + + &Options... + Оп&ции... + + + + &Encrypt Wallet... + &Зашифровать бумажник + + + + &Backup Wallet... + &Сделать резервную копию бумажника + + + + &Change Passphrase... + &Изменить пароль + + + + ~%n block(s) remaining + + остался ~%n блок + осталось ~%n блоков + осталось ~%n блоков + + + + + Downloaded %1 of %2 blocks of transaction history (%3% done). + Загружено %1 из %2 блоков истории операций (%3% завершено). + + + + &Export... + &Экспорт... + + + + Send coins to a BottleCaps address + Отправить монеты на указанный адрес BottleCaps + + + + Modify configuration options for BottleCaps + Изменить параметры конфигурации BottleCaps + + + + Export the data in the current tab to a file + Экспортировать данные из вкладки в файл + + + + Encrypt or decrypt wallet + Зашифровать или расшифровать бумажник + + + + Backup wallet to another location + Сделать резервную копию бумажника в другом месте + + + + Change the passphrase used for wallet encryption + Изменить пароль шифрования бумажника + + + + &Debug window + &Окно отладки + + + + Open debugging and diagnostic console + Открыть консоль отладки и диагностики + + + + &Verify message... + &Проверить сообщение... + + + + BottleCaps + BottleCaps + + + + Wallet + Бумажник + + + + &About BottleCaps + &О BottleCaps + + + + &Show / Hide + &Показать / Скрыть + + + + &File + &Файл + + + + &Settings + &Настройки + + + + &Help + &Помощь + + + + Tabs toolbar + Панель вкладок + + + + Actions toolbar + Панель действий + + + + + [testnet] + [тестовая сеть] + + + + + BottleCaps client + BottleCaps клиент + + + + %n active connection(s) to BottleCaps network + + %n активное соединение с сетью + %n активных соединений с сетью + %n активных соединений с сетью + + + + + Downloaded %1 blocks of transaction history. + Загружено %1 блоков истории транзакций. + + + + %n second(s) ago + + %n секунду назад + %n секунды назад + %n секунд назад + + + + + %n minute(s) ago + + %n минуту назад + %n минуты назад + %n минут назад + + + + + %n hour(s) ago + + %n час назад + %n часа назад + %n часов назад + + + + + %n day(s) ago + + %n день назад + %n дня назад + %n дней назад + + + + + Up to date + Синхронизированно + + + + Catching up... + Синхронизируется... + + + + Last received block was generated %1. + Последний полученный блок был сгенерирован %1. + + + + This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee? + Данная транзакция превышает предельно допустимый размер. Но Вы можете всё равно совершить её, добавив комиссию в %1, которая отправится тем узлам, которые обработают Вашу транзакцию, и поможет поддержать сеть. Вы хотите добавить комиссию? + + + + Confirm transaction fee + Подтвердите комиссию + + + + Sent transaction + Исходящая транзакция + + + + Incoming transaction + Входящая транзакция + + + + Date: %1 +Amount: %2 +Type: %3 +Address: %4 + + Дата: %1 +Количество: %2 +Тип: %3 +Адрес: %4 + + + + + + URI handling + Обработка URI + + + + + URI can not be parsed! This can be caused by an invalid BottleCaps address or malformed URI parameters. + Не удалось обработать URI! Это может быть связано с неверным адресом BottleCaps или неправильными параметрами URI. + + + + Wallet is <b>encrypted</b> and currently <b>unlocked</b> + Бумажник <b>зашифрован</b> и в настоящее время <b>разблокирован</b> + + + + Wallet is <b>encrypted</b> and currently <b>locked</b> + Бумажник <b>зашифрован</b> и в настоящее время <b>заблокирован</b> + + + + Backup Wallet + Сделать резервную копию бумажника + + + + Wallet Data (*.dat) + Данные бумажника (*.dat) + + + + Backup Failed + Резервное копирование не удалось + + + + There was an error trying to save the wallet data to the new location. + При попытке сохранения данных бумажника в новое место произошла ошибка. + + + + A fatal error occurred. BottleCaps can no longer continue safely and will quit. + Произошла неисправимая ошибка. BottleCaps не может безопасно продолжать работу и будет закрыт. + + + + ClientModel + + + Network Alert + Сетевая Тревога + + + + EditAddressDialog + + + Edit Address + Изменить адрес + + + + &Label + &Метка + + + + The label associated with this address book entry + Метка, связанная с данной записью + + + + &Address + &Адрес + + + + The address associated with this address book entry. This can only be modified for sending addresses. + Адрес, связанный с данной записью. + + + + New receiving address + Новый адрес для получения + + + + New sending address + Новый адрес для отправки + + + + Edit receiving address + Изменение адреса для получения + + + + Edit sending address + Изменение адреса для отправки + + + + The entered address "%1" is already in the address book. + Введённый адрес «%1» уже находится в адресной книге. + + + + The entered address "%1" is not a valid BottleCaps address. + Введённый адрес "%1" не является правильным BottleCaps-адресом. + + + + Could not unlock wallet. + Не удается разблокировать бумажник. + + + + New key generation failed. + Генерация нового ключа не удалась. + + + + GUIUtil::HelpMessageBox + + + + BottleCaps-Qt + BottleCaps-Qt + + + + version + версия + + + + Usage: + Использование: + + + + command-line options + параметры командной строки + + + + UI options + Опции интерфейса + + + + Set language, for example "de_DE" (default: system locale) + Выберите язык, например "de_DE" (по умолчанию: как в системе) + + + + Start minimized + Запускать свёрнутым + + + + Show splash screen on startup (default: 1) + Показывать сплэш при запуске (по умолчанию: 1) + + + + OptionsDialog + + + Options + Опции + + + + &Main + &Главная + + + + Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. Fee 0.01 recommended. + Опциональная комиссия за каждый КБ транзакции, которая позволяет быть уверенным, что Ваша транзакция будет обработана быстро. Большинство транзакций занимают 1КБ. Рекомендуется комиссия 0.01. + + + + Pay transaction &fee + Заплатить ко&миссию + + + + Automatically start BottleCaps after logging in to the system. + Автоматически запускать BottleCaps после входа в систему + + + + &Start BottleCaps on system login + &Запускать BottleCaps при входе в систему + + + + Detach block and address databases at shutdown. This means they can be moved to another data directory, but it slows down shutdown. The wallet is always detached. + Отключить базы данных блоков и адресов при выходе. Это означает, что их можно будет переместить в другой каталог данных, но завершение работы будет медленнее. Бумажник всегда отключается. + + + + &Detach databases at shutdown + &Отключать базы данных при выходе + + + + &Network + &Сеть + + + + Automatically open the BottleCaps client port on the router. This only works when your router supports UPnP and it is enabled. + Автоматически открыть порт для BottleCaps-клиента на роутере. Работает только если Ваш роутер поддерживает UPnP, и данная функция включена. + + + + Map port using &UPnP + Пробросить порт через &UPnP + + + + Connect to the BottleCaps network through a SOCKS proxy (e.g. when connecting through Tor). + Подключаться к сети BottleCaps через прокси SOCKS (например, при подключении через Tor). + + + + &Connect through SOCKS proxy: + &Подключаться через SOCKS прокси: + + + + Proxy &IP: + &IP Прокси: + + + + IP address of the proxy (e.g. 127.0.0.1) + IP-адрес прокси (например 127.0.0.1) + + + + &Port: + По&рт: + + + + Port of the proxy (e.g. 9050) + Порт прокси-сервера (например, 9050) + + + + SOCKS &Version: + &Версия SOCKS: + + + + SOCKS version of the proxy (e.g. 5) + Версия SOCKS-прокси (например, 5) + + + + &Window + &Окно + + + + Show only a tray icon after minimizing the window. + Показывать только иконку в системном лотке после сворачивания окна. + + + + &Minimize to the tray instead of the taskbar + &Cворачивать в системный лоток вместо панели задач + + + + Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu. + Сворачивать вместо закрытия. Если данная опция будет выбрана — приложение закроется только после выбора соответствующего пункта в меню. + + + + M&inimize on close + С&ворачивать при закрытии + + + + &Display + О&тображение + + + + User Interface &language: + &Язык интерфейса: + + + + The user interface language can be set here. This setting will take effect after restarting BottleCaps. + Здесь можно выбрать язык интерфейса. Настройки вступят в силу после перезапуска BottleCaps. + + + + &Unit to show amounts in: + &Отображать суммы в единицах: + + + + Choose the default subdivision unit to show in the interface and when sending coins. + Выберите единицу измерения монет при отображении и отправке. + + + + Whether to show BottleCaps addresses in the transaction list or not. + Показывать ли адреса BottleCaps в списке транзакций. + + + + &Display addresses in transaction list + &Показывать адреса в списке транзакций + + + + &OK + О&К + + + + &Cancel + &Отмена + + + + &Apply + &Применить + + + + default + по умолчанию + + + + + Warning + Внимание + + + + + This setting will take effect after restarting BottleCaps. + Эта настройка вступит в силу после перезапуска BottleCaps + + + + The supplied proxy address is invalid. + Адрес прокси неверен. + + + + OverviewPage + + + Form + Форма + + + + + The displayed information may be out of date. Your wallet automatically synchronizes with the BottleCaps network after a connection is established, but this process has not completed yet. + Отображаемая информация может быть устаревшей. Ваш бумажник автоматически синхронизируется с сетью BottleCaps после подключения, но этот процесс пока не завершён. + + + + Balance: + Баланс: + + + + Stake: + Доля: + + + + Number of transactions: + Количество транзакций: + + + + Unconfirmed: + Не подтверждено: + + + + Wallet + Бумажник + + + + Immature: + Незрелые: + + + + Mined balance that has not yet matured + Баланс добытых монет, который ещё не созрел + + + + <b>Recent transactions</b> + <b>Последние транзакции</b> + + + + Your current balance + Ваш текущий баланс + + + + Total of transactions that have yet to be confirmed, and do not yet count toward the current balance + Общая сумма всех транзакций, которые до сих пор не подтверждены, и до сих пор не учитываются в текущем балансе + + + + Total of coins that was staked, and do not yet count toward the current balance + Общая сумма всех монет, используемых для Proof-of-Stake, и не учитывающихся на балансе + + + + Total number of transactions in wallet + Общее количество транзакций в Вашем бумажнике + + + + + out of sync + не синхронизировано + + + + QRCodeDialog + + + QR Code Dialog + Диалог QR-кода + + + + Request Payment + Запросить платёж + + + + Amount: + Количество: + + + + Label: + Метка: + + + + Message: + Сообщение: + + + + &Save As... + &Сохранить как... + + + + Error encoding URI into QR Code. + Ошибка кодирования URI в QR-код + + + + The entered amount is invalid, please check. + Введено неверное количество, проверьте ещё раз. + + + + Resulting URI too long, try to reduce the text for label / message. + Получившийся URI слишком длинный, попробуйте сократить текст метки / сообщения. + + + + Save QR Code + Сохранить QR-код + + + + PNG Images (*.png) + PNG Изображения (*.png) + + + + RPCConsole + + + Client name + Имя клиента + + + + + + + + + + + + + N/A + Н/Д + + + + Client version + Версия клиента + + + + &Information + &Информация + + + + Using OpenSSL version + Используется версия OpenSSL + + + + Startup time + Время запуска + + + + Network + Сеть + + + + Number of connections + Число подключений + + + + On testnet + В тестовой сети + + + + Block chain + Цепь блоков + + + + Current number of blocks + Текущее число блоков + + + + Estimated total blocks + Расчётное число блоков + + + + Last block time + Время последнего блока + + + + &Open + &Открыть + + + + Command-line options + Параметры командной строки + + + + Show the BottleCaps-Qt help message to get a list with possible BottleCaps command-line options. + Показать помощь по BottleCaps-Qt, чтобы получить список доступных параметров командной строки. + + + + &Show + &Показать + + + + &Console + Консоль + + + + Build date + Дата сборки + + + + BottleCaps - Debug window + BottleCaps - Окно отладки + + + + BottleCaps Core + Ядро BottleCaps + + + + Debug log file + Отладочный лог-файл + + + + Open the BottleCaps debug log file from the current data directory. This can take a few seconds for large log files. + Открыть отладочный лог-файл BottleCaps из текущего каталога данных. Это может занять несколько секунд для больших лог-файлов. + + + + Clear console + Очистить консоль + + + + Welcome to the BottleCaps RPC console. + Добро пожаловать в RPC-консоль BottleCaps. + + + + Use up and down arrows to navigate history, and <b>Ctrl-L</b> to clear screen. + Используйте стрелки вверх и вниз для просмотра истории и <b>Ctrl-L</b> для очистки экрана. + + + + Type <b>help</b> for an overview of available commands. + Напишите <b>help</b> для просмотра доступных команд. + + + + SendCoinsDialog + + + + + + + + + + Send Coins + Отправка + + + + Send to multiple recipients at once + Отправить нескольким получателям одновременно + + + + Add &Recipient + &Добавить получателя + + + + Remove all transaction fields + Удалить все поля транзакции + + + + Clear &All + Очистить &всё + + + + Balance: + Баланс: + + + + 123.456 BTC + 123.456 BTC + + + + Confirm the send action + Подтвердить отправку + + + + S&end + &Отправить + + + + <b>%1</b> to %2 (%3) + <b>%1</b> адресату %2 (%3) + + + + Confirm send coins + Подтвердите отправку монет + + + + Are you sure you want to send %1? + Вы уверены, что хотите отправить %1? + + + + and + и + + + + The recipient address is not valid, please recheck. + Адрес получателя неверный, пожалуйста, перепроверьте. + + + + The amount to pay must be larger than 0. + Количество монет для отправки должно быть больше 0. + + + + The amount exceeds your balance. + Количество отправляемых монет превышает Ваш баланс + + + + The total exceeds your balance when the %1 transaction fee is included. + Сумма превысит Ваш баланс, если комиссия в размере %1 будет добавлена к транзакции + + + + Duplicate address found, can only send to each address once per send operation. + Обнаружен дублирующийся адрес. Отправка на один и тот же адрес возможна только один раз за одну операцию отправки + + + + Error: Transaction creation failed. + Ошибка: не удалось создать транзакцию. + + + + Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. + Ошибка: В транзакции отказано. Такое может произойти, если некоторые монеты уже были потрачены, например, если Вы используете одну копию файла wallet.dat, а монеты были потрачены из другой копии, но не были отмечены как потраченные в этой. + + + + SendCoinsEntry + + + Form + Форма + + + + A&mount: + Ко&личество: + + + + Pay &To: + Полу&чатель: + + + + + Enter a label for this address to add it to your address book + Введите метку для данного адреса (для добавления в адресную книгу) + + + + &Label: + &Метка: + + + + The address to send the payment to (e.g. 4Zo1ga6xuKuQ7JV7M9rGDoxdbYwV5zgQJ5) + Адрес получателя платежа (например 4Zo1ga6xuKuQ7JV7M9rGDoxdbYwV5zgQJ5) + + + + Choose address from address book + Выберите адрес из адресной книги + + + + Alt+A + Alt+A + + + + Paste address from clipboard + Вставить адрес из буфера обмена + + + + Alt+P + Alt+P + + + + Remove this recipient + Удалить этого получателя + + + + Enter a BottleCaps address (e.g. 4Zo1ga6xuKuQ7JV7M9rGDoxdbYwV5zgQJ5) + Введите BottleCaps-адрес (например 4Zo1ga6xuKuQ7JV7M9rGDoxdbYwV5zgQJ5) + + + + SignVerifyMessageDialog + + + Signatures - Sign / Verify a Message + Подписи - подписать/проверить сообщение + + + + + &Sign Message + &Подписать сообщение + + + + You can sign messages with your addresses to prove you own them. Be careful not to sign anything vague, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to. + Вы можете подписывать сообщения своими адресами, чтобы доказать владение ими. Будьте осторожны, не подписывайте что-то неопределённое, так как фишинговые атаки могут обманным путём заставить вас подписать нежелательные сообщения. Подписывайте только те сообщения, с которыми вы согласны вплоть до мелочей. + + + + The address to sign the message with (e.g. 4Zo1ga6xuKuQ7JV7M9rGDoxdbYwV5zgQJ5) + Адрес, которым вы хотите подписать сообщение (напр. 4Zo1ga6xuKuQ7JV7M9rGDoxdbYwV5zgQJ5) + + + + + Choose an address from the address book + Выберите адрес из адресной книги + + + + + Alt+A + Alt+A + + + + Paste address from clipboard + Вставить адрес из буфера обмена + + + + Alt+P + Alt+P + + + + Enter the message you want to sign here + Введите сообщение для подписи + + + + Copy the current signature to the system clipboard + Скопировать текущую подпись в системный буфер обмена + + + + Sign the message to prove you own this BottleCaps address + Подписать сообщение, чтобы доказать владение адресом BottleCaps + + + + Reset all sign message fields + Сбросить значения всех полей подписывания сообщений + + + + + Clear &All + Очистить &всё + + + + + &Verify Message + &Проверить сообщение + + + + Enter the signing address, message (ensure you copy line breaks, spaces, tabs, etc. exactly) and signature below to verify the message. Be careful not to read more into the signature than what is in the signed message itself, to avoid being tricked by a man-in-the-middle attack. + Введите ниже адрес для подписи, сообщение (убедитесь, что переводы строк, пробелы, табы и т.п. в точности скопированы) и подпись, чтобы проверить сообщение. Убедитесь, что не скопировали лишнего в подпись, по сравнению с самим подписываемым сообщением, чтобы не стать жертвой атаки "man-in-the-middle". + + + + The address the message was signed with (e.g. 4Zo1ga6xuKuQ7JV7M9rGDoxdbYwV5zgQJ5) + Адрес, которым было подписано сообщение (напр. 4Zo1ga6xuKuQ7JV7M9rGDoxdbYwV5zgQJ5) + + + + Verify the message to ensure it was signed with the specified BottleCaps address + Проверить сообщение, чтобы убедиться, что оно было подписано указанным адресом BottleCaps + + + + Reset all verify message fields + Сбросить все поля проверки сообщения + + + + + Enter a BottleCaps address (e.g. 4Zo1ga6xuKuQ7JV7M9rGDoxdbYwV5zgQJ5) + Введите адрес BottleCaps (напр. 4Zo1ga6xuKuQ7JV7M9rGDoxdbYwV5zgQJ5) + + + + Click "Sign Message" to generate signature + Нажмите "Подписать сообщение" для создания подписи + + + + Enter BottleCaps signature + Введите подпись BottleCaps + + + + + The entered address is invalid. + Введённый адрес неверен + + + + + + + Please check the address and try again. + Пожалуйста, проверьте адрес и попробуйте ещё раз. + + + + + The entered address does not refer to a key. + Введённый адрес не связан с ключом + + + + Wallet unlock was cancelled. + Разблокировка бумажника была отменена. + + + + Private key for the entered address is not available. + Для введённого адреса недоступен закрытый ключ + + + + Message signing failed. + Не удалось подписать сообщение + + + + Message signed. + Сообщение подписано + + + + The signature could not be decoded. + Подпись не может быть раскодирована. + + + + + Please check the signature and try again. + Пожалуйста, проверьте подпись и попробуйте ещё раз. + + + + The signature did not match the message digest. + Подпись не соответствует отпечатку сообщения. + + + + Message verification failed. + Проверка сообщения не удалась. + + + + Message verified. + Сообщение проверено. + + + + TransactionDesc + + + Open until %1 + Открыто до %1 + + + + Open for %n block(s) + + Открыто для %n блока + Открыто для %n блоков + Открыто для %n блоков + + + + + %1/offline + %1/отключен + + + + %1/unconfirmed + %1/не подтверждено + + + + %1 confirmations + %1 подтверждений + + + + Status + Статус + + + + , broadcast through %n node(s) + + , разослано через %n узел + , разослано через %n узла + , разослано через %n узлов + + + + + Date + Дата + + + + Source + Источник + + + + Generated + Сгенерированно + + + + + From + От + + + + + + To + Для + + + + + own address + свой адрес + + + + label + метка + + + + + + + + Credit + Кредит + + + + matures in %n more block(s) + + будет доступно через %n блок + будет доступно через %n блока + будет доступно через %n блоков + + + + + not accepted + не принято + + + + + + + Debit + Дебет + + + + Transaction fee + Комиссия + + + + Net amount + Чистая сумма + + + + Message + Сообщение + + + + Comment + Комментарий: + + + + Transaction ID + ID транзакции + + + + Generated coins must mature 520 blocks before they can be spent. When you generated this block, it was broadcast to the network to be added to the block chain. If it fails to get into the chain, its state will change to "not accepted" and it won't be spendable. This may occasionally happen if another node generates a block within a few seconds of yours. + Сгенерированные монеты должны подождать 520 блоков, прежде чем они могут быть потрачены. Когда Вы сгенерировали этот блок, он был отправлен в сеть для добавления в цепочку блоков. Если данная процедура не удастся, статус изменится на «не подтверждено», и монеты будут недействительны. Это иногда происходит в случае, если другой узел сгенерирует блок на несколько секунд раньше вас. + + + + Staked coins must wait 520 blocks before they can return to balance and be spent. When you generated this proof-of-stake block, it was broadcast to the network to be added to the block chain. If it fails to get into the chain, it will change to \"not accepted\" and not be a valid stake. This may occasionally happen if another node generates a proof-of-stake block within a few seconds of yours. + Использованные в Proof-of-Stake монеты должны подождать 520 блоков, прежде чем они вернутся на баланс и смогут быть потрачены. Когда вы сгенерировали этот proof-of-stake блок, он был отправлен в сеть для добавления в цепочку блоков. Если данная процедура не удается, статус изменится на \"не подтверждени\" и блок будет недействителен. Это иногда происходит в случае, если другой узел сгенерирует блок на несколько секунд раньше вас. + + + + Debug information + Отладочная информация + + + + Transaction + Транзакция + + + + Inputs + Входы + + + + Amount + Количество + + + + true + истина + + + + false + ложь + + + + , has not been successfully broadcast yet + , ещё не было успешно разослано + + + + unknown + неизвестно + + + + TransactionDescDialog + + + Transaction details + Детали транзакции + + + + This pane shows a detailed description of the transaction + Данный диалог показывает детализированную статистику по выбранной транзакции + + + + TransactionTableModel + + + Date + Дата + + + + Type + Тип + + + + Address + Адрес + + + + Amount + Количество + + + + Open for %n block(s) + + Открыто для %n блока + Открыто для %n блоков + Открыто для %n блоков + + + + + Open until %1 + Открыто до %1 + + + + Offline (%1 confirmations) + Оффлайн (%1 подтверждений) + + + + Unconfirmed (%1 of %2 confirmations) + Не подтверждено (%1 из %2 подтверждений) + + + + Confirmed (%1 confirmations) + Подтверждено (%1 подтверждений) + + + + Mined balance will be available when it matures in %n more block(s) + + Добытыми монетами можно будет воспользоваться через %n блок + Добытыми монетами можно будет воспользоваться через %n блока + Добытыми монетами можно будет воспользоваться через %n блоков + + + + + This block was not received by any other nodes and will probably not be accepted! + Этот блок не был получен другими узлами и, возможно, не будет принят! + + + + Generated but not accepted + Сгенерированно, но не подтверждено + + + + Received with + Получено + + + + Received from + Получено от + + + + Sent to + Отправлено + + + + Payment to yourself + Отправлено себе + + + + Mined + Добыто + + + + (n/a) + [не доступно] + + + + Transaction status. Hover over this field to show number of confirmations. + Статус транзакции. Подведите курсор к нужному полю для того, чтобы увидеть количество подтверждений. + + + + Date and time that the transaction was received. + Дата и время, когда транзакция была получена. + + + + Type of transaction. + Тип транзакции. + + + + Destination address of transaction. + Адрес назначения транзакции. + + + + Amount removed from or added to balance. + Сумма, добавленная, или снятая с баланса. + + + + TransactionView + + + + All + Все + + + + Today + Сегодня + + + + This week + На этой неделе + + + + This month + В этом месяце + + + + Last month + За последний месяц + + + + This year + В этом году + + + + Range... + Промежуток... + + + + Received with + Получено на + + + + Sent to + Отправлено на + + + + To yourself + Отправленные себе + + + + Mined + Добытые + + + + Other + Другое + + + + Enter address or label to search + Введите адрес или метку для поиска + + + + Min amount + Мин. сумма + + + + Copy address + Копировать адрес + + + + Copy label + Копировать метку + + + + Copy amount + Скопировать сумму + + + + Edit label + Изменить метку + + + + Show transaction details + Показать подробности транзакции + + + + Export Transaction Data + Экспортировать данные транзакций + + + + Comma separated file (*.csv) + Текст, разделённый запятыми (*.csv) + + + + Confirmed + Подтверждено + + + + Date + Дата + + + + Type + Тип + + + + Label + Метка + + + + Address + Адрес + + + + Amount + Количество + + + + ID + ID + + + + Error exporting + Ошибка экспорта + + + + Could not write to file %1. + Невозможно записать в файл %1. + + + + Range: + Промежуток от: + + + + to + до + + + + WalletModel + + + Sending... + Отправка.... + + + + bitcoin-core + + + BottleCaps version + Версия + + + + Usage: + Использование: + + + + Send command to -server or bitcoind + Отправить команду на -server или bitcoind + + + + List commands + Список команд + + + + + Get help for a command + Получить помощь по команде + + + + Options: + Опции: + + + + Specify configuration file (default: BottleCaps.conf) + Указать конфигурационный файл (по умолчанию: BottleCaps.conf) + + + + Specify pid file (default: BottleCapsd.pid) + Указать pid-файл (по умолчанию: BottleCaps.pid) + + + + Generate coins + Генерировать монеты + + + + Don't generate coins + Не генерировать монеты + + + + Specify data directory + Укажите каталог данных + + + + Set database cache size in megabytes (default: 25) + Установить размер кэша базы данных в мегабайтах (по умолчанию: 25) + + + + Set database disk log size in megabytes (default: 100) + Установить размер лога базы данных в мегабайтах (по умолчанию: 100) + + + + Listen for connections on <port> (default: 7777 or testnet: 17777) + Принимать входящие подключения на <port> (по умолчанию: 7777 или 17777 в тестовой сети) + + + + Maintain at most <n> connections to peers (default: 125) + Поддерживать не более <n> подключений к узлам (по умолчанию: 125) + + + + Connect to a node to retrieve peer addresses, and disconnect + Подключиться к узлу, чтобы получить список адресов других участников и отключиться + + + + Specify your own public address + Укажите ваш собственный публичный адрес + + + + Bind to given address. Use [host]:port notation for IPv6 + Привязаться (bind) к указанному адресу. Используйте запись вида [хост]:порт для IPv6 + + + + Threshold for disconnecting misbehaving peers (default: 100) + Порог для отключения неправильно ведущих себя узлов (по умолчанию: 100) + + + + Number of seconds to keep misbehaving peers from reconnecting (default: 86400) + Число секунд блокирования неправильно ведущих себя узлов (по умолчанию: 86400) + + + + An error occurred while setting up the RPC port %u for listening on IPv4: %s + Произошла ошибка при открытии RPC-порта %u для прослушивания на IPv4: %s + + + + An error occurred while setting up the RPC port %u for listening on IPv6, falling back to IPv4: %s + Произошла ошибка при открытии на прослушивание IPv6 RCP-порта %u, возвращаемся к IPv4: %s + + + + Detach block and address databases. Increases shutdown time (default: 0) + Отключить базы данных блоков и адресов. Увеличивает время завершения работы (по умолчанию: 0) + + + + Error initializing database environment %s! To recover, BACKUP THAT DIRECTORY, then remove everything from it except for wallet.dat. + + + + + Listen for JSON-RPC connections on <port> (default: 8344 or testnet: 18344) + Прослушивать подключения JSON-RPC на <порту> (по умолчанию: 8344 или для testnet: 18344) + + + + Warning: error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. + Внимание: ошибка чтения wallet.dat! Все ключи восстановлены, но записи в адресной книге и истории транзакций могут быть некорректными. + + + + Warning: wallet.dat corrupt, data salvaged! Original wallet.dat saved as wallet.{timestamp}.bak in %s; if your balance or transactions are incorrect you should restore from a backup. + Внимание: wallet.dat был поврежден, данные восстановлены! Оригинальный wallet.dat сохранен как wallet.{timestamp}.bak в %s;, если ваши транзакции или баланс отображаются неправильно, следует восстановить его из данной копии. + + + + Accept command line and JSON-RPC commands + Принимать командную строку и команды JSON-RPC + + + + Attempt to recover private keys from a corrupt wallet.dat + Попытка восстановления ключей из поврежденного wallet.dat + + + + Importing blockchain data file. + Импортируется файл цепи блоков. + + + + Importing bootstrap blockchain data file. + Импортируется bootstrap-файл цепи блоков. + + + + Run in the background as a daemon and accept commands + Запускаться в фоне как демон и принимать команды + + + + Use the test network + Использовать тестовую сеть + + + + Accept connections from outside (default: 1 if no -proxy or -connect) + Принимать подключения извне (по умолчанию: 1, если не используется -proxy или -connect) + + + + Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. + Ошибка: В транзакции отказано. Такое может произойти, если некоторые монеты уже были потрачены, например, если Вы используете одну копию файла wallet.dat, а монеты были потрачены из другой копии, но не были отмечены как потраченные в этой. + + + + Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds + Ошибка: эта транзакция требует комиссию в размере как минимум %s из-за её объёма, сложности или использования недавно полученных средств + + + + Set maximum size of high-priority/low-fee transactions in bytes (default: 27000) + Максимальный размер высокоприоритетных/низкокомиссионных транзакций в байтах (по умолчанию: 27000) + + + + Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. + Внимание: установлено очень большое значение -paytxfee. Это комиссия, которую вы заплатите при проведении транзакции. + + + + Warning: Displayed transactions may not be correct! You may need to upgrade, or other nodes may need to upgrade. + Внимание: отображаемые транзакции могут быть некорректны! Вам или другим узлам, возможно, следует обновиться. + + + + Warning: Please check that your computer's date and time are correct! If your clock is wrong BottleCaps will not work properly. + Внимание: убедитесь, что дата и время на Вашем компьютере выставлены верно. Если Ваши часы идут неправильно, BottleCaps будет работать некорректно. + + + + Block creation options: + Параметры создания блоков: + + + + Connect only to the specified node(s) + Подключаться только к указанному узлу(ам) + + + + Discover own IP address (default: 1 when listening and no -externalip) + Определить свой IP (по умолчанию: 1 при прослушивании и если не используется -externalip) + + + + Error: Transaction creation failed + Ошибка: Создание транзакции не удалось + + + + Error: Wallet locked, unable to create transaction + Ошибка: бумажник заблокирован, невозможно создать транзакцию + + + + Failed to listen on any port. Use -listen=0 if you want this. + Не удалось начать прослушивание на порту. Используйте -listen=0 если вас это устраивает. + + + + Find peers using DNS lookup (default: 0 unless -connect) + Искать узлы с помощью DNS (по умолчанию: 0) + + + + Invalid -tor address: '%s' + Неверный адрес -tor: '%s' + + + + Maximum per-connection receive buffer, <n>*1000 bytes (default: 5000) + Максимальный размер буфера приёма на соединение, <n>*1000 байт (по умолчанию: 5000) + + + + Maximum per-connection send buffer, <n>*1000 bytes (default: 1000) + Максимальный размер буфера отправки на соединение, <n>*1000 байт (по умолчанию: 1000) + + + + Only connect to nodes in network <net> (IPv4, IPv6 or Tor) + Подключаться только к узлам из сети <net> (IPv4, IPv6 или Tor) + + + + Output extra debugging information. Implies all other -debug* options + Выводить больше отладочной информации. Включает все остальные опции -debug* + + + + Output extra network debugging information + Выводить дополнительную сетевую отладочную информацию + + + + Prepend debug output with timestamp + Дописывать отметки времени к отладочному выводу + + + + SSL options: (see the Bitcoin Wiki for SSL setup instructions) + +Параметры SSL: (см. Bitcoin Wiki для инструкций по настройке SSL) + + + + Select the version of socks proxy to use (4-5, default: 5) + Выберите версию SOCKS-прокси (4-5, по умолчанию: 5) + + + + Send trace/debug info to console instead of debug.log file + Выводить информацию трассировки/отладки на консоль вместо файла debug.log + + + + Send trace/debug info to debugger + Отправлять информацию трассировки/отладки в отладчик + + + + Set maximum block size in bytes (default: 250000) + Максимальный размер блока в байтах (по умолчанию: 250000) + + + + Set minimum block size in bytes (default: 0) + Минимальный размер блока в байтах (по умолчанию: 0) + + + + Shrink debug.log file on client startup (default: 1 when no -debug) + Сжимать файл debug.log при запуске клиента (по умолчанию: 1, если нет -debug) + + + + Specify connection timeout in milliseconds (default: 5000) + Таймаут соединения в миллисекундах (по умолчанию: 5000) + + + + Use UPnP to map the listening port (default: 0) + Использовать UPnP для проброса порта (по умолчанию: 0) + + + + Use UPnP to map the listening port (default: 1 when listening) + Использовать UPnP для проброса порта (по умолчанию: 1, если используется прослушивание) + + + + Use proxy to reach tor hidden services (default: same as -proxy) + Использовать прокси для скрытых сервисов (по умолчанию: тот же, что и в -proxy) + + + + Username for JSON-RPC connections + Имя для подключений JSON-RPC + + + + Verifying database integrity... + + + + + Warning: Disk space is low! + Внимание: мало места на диске! + + + + Warning: This version is obsolete, upgrade required! + Внимание: эта версия устарела, требуется обновление! + + + + wallet.dat corrupt, salvage failed + + + + + Password for JSON-RPC connections + Пароль для подключений JSON-RPC + + + + Allow JSON-RPC connections from specified IP address + Разрешить подключения JSON-RPC с указанного IP + + + + Send commands to node running on <ip> (default: 127.0.0.1) + Посылать команды узлу, запущенному на <ip> (по умолчанию: 127.0.0.1) + + + + Execute command when the best block changes (%s in cmd is replaced by block hash) + Выполнить команду, когда появляется новый блок (%s в команде заменяется на хэш блока) + + + + Upgrade wallet to latest format + Обновить бумажник до последнего формата + + + + Set key pool size to <n> (default: 100) + Установить размер запаса ключей в <n> (по умолчанию: 100) + + + + Rescan the block chain for missing wallet transactions + Перепроверить цепь блоков на предмет отсутствующих в бумажнике транзакций + + + + How many blocks to check at startup (default: 2500, 0 = all) + Сколько блоков проверять при запуске (по умолчанию: 2500, 0 = все) + + + + How thorough the block verification is (0-6, default: 1) + Насколько тщательно проверять блоки (0-6, по умолчанию: 1) + + + + Imports blocks from external blk000?.dat file + Импортировать блоки из внешнего файла blk000?.dat + + + + Use OpenSSL (https) for JSON-RPC connections + Использовать OpenSSL (https) для подключений JSON-RPC + + + + Server certificate file (default: server.cert) + Файл серверного сертификата (по умолчанию: server.cert) + + + + Server private key (default: server.pem) + Приватный ключ сервера (по умолчанию: server.pem) + + + + Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) + Разрешённые алгоритмы (по умолчанию: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) + + + + This help message + Эта справка + + + + Cannot obtain a lock on data directory %s. BottleCaps is probably already running. + Невозможно установить блокировку на рабочую директорию %s. Возможно, бумажник уже запущен. + + + + BottleCaps + BottleCaps + + + + Unable to bind to %s on this computer (bind returned error %d, %s) + Невозможно привязаться к %s на этом компьютере (bind вернул ошибку %d, %s) + + + + Connect through socks proxy + Подключаться через socks прокси + + + + Allow DNS lookups for -addnode, -seednode and -connect + Разрешить поиск в DNS для -addnode, -seednode и -connect + + + + Loading addresses... + Загрузка адресов... + + + + Error loading blkindex.dat + Ошибка чтения blkindex.dat + + + + Error loading wallet.dat: Wallet corrupted + Ошибка загрузки wallet.dat: Бумажник поврежден + + + + Error loading wallet.dat: Wallet requires newer version of BottleCaps + Ошибка загрузки wallet.dat: бумажник требует более новую версию BottleCaps + + + + Wallet needed to be rewritten: restart BottleCaps to complete + Необходимо перезаписать бумажник, перезапустите BottleCaps для завершения операции. + + + + Error loading wallet.dat + Ошибка при загрузке wallet.dat + + + + Invalid -proxy address: '%s' + Неверный адрес -proxy: '%s' + + + + Unknown network specified in -onlynet: '%s' + В параметре -onlynet указана неизвестная сеть: '%s' + + + + Unknown -socks proxy version requested: %i + В параметре -socks запрошена неизвестная версия: %i + + + + Cannot resolve -bind address: '%s' + Не удаётся разрешить адрес в параметре -bind: '%s' + + + + Cannot resolve -externalip address: '%s' + Не удаётся разрешить адрес в параметре -externalip: '%s' + + + + Invalid amount for -paytxfee=<amount>: '%s' + Неверное количество в параметре -paytxfee=<кол-во>: '%s' + + + + Error: could not start node + Ошибка: не удалось запустить узел + + + + Sending... + Отправка... + + + + Invalid amount + Неверное количество + + + + Insufficient funds + Недостаточно монет + + + + Loading block index... + Загрузка индекса блоков... + + + + Add a node to connect to and attempt to keep the connection open + Добавить узел для подключения и пытаться поддерживать соединение открытым + + + + Unable to bind to %s on this computer. BottleCaps is probably already running. + Невозможно привязаться к %s на этом компьютере. Возможно, BottleCaps уже работает. + + + + Find peers using internet relay chat (default: 1) + Найти участников через IRC (по умолчанию: 1) + + + + Fee per KB to add to transactions you send + Комиссия на килобайт, добавляемая к вашим транзакциям + + + + Loading wallet... + Загрузка бумажника... + + + + Cannot downgrade wallet + Не удаётся понизить версию бумажника + + + + Cannot initialize keypool + Не удаётся инициализировать массив ключей + + + + Cannot write default address + Не удаётся записать адрес по умолчанию + + + + Rescanning... + Сканирование... + + + + Done loading + Загрузка завершена + + + + To use the %s option + Чтобы использовать опцию %s + + + + %s, you must set a rpcpassword in the configuration file: + %s +It is recommended you use the following random password: +rpcuser=bitcoinrpc +rpcpassword=%s +(you do not need to remember this password) +If the file does not exist, create it with owner-readable-only file permissions. + + %s, вы должны установить опцию rpcpassword в конфигурационном файле: + %s +Рекомендуется использовать следующий случайный пароль: +rpcuser=bitcoinrpc +rpcpassword=%s +(вам не нужно запоминать этот пароль) +Если файл не существует, создайте его и установите права доступа только для владельца. + + + + + Error + Ошибка + + + + You must set rpcpassword=<password> in the configuration file: +%s +If the file does not exist, create it with owner-readable-only file permissions. + Вы должны установить rpcpassword=<password> в конфигурационном файле: +%s +Если файл не существует, создайте его и установите права доступа только для владельца. + + + diff --git a/src/qt/macdockiconhandler.h b/src/qt/macdockiconhandler.h new file mode 100644 index 0000000..b21a61c --- /dev/null +++ b/src/qt/macdockiconhandler.h @@ -0,0 +1,51 @@ +// Copyright (c) 2011-2013 The Bitcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef MACDOCKICONHANDLER_H +#define MACDOCKICONHANDLER_H + +#include +#include + +QT_BEGIN_NAMESPACE +class QIcon; +class QMenu; +class QWidget; +QT_END_NAMESPACE + +#ifdef __OBJC__ +@class DockIconClickEventHandler; +#else +class DockIconClickEventHandler; +#endif + +/** Macintosh-specific dock icon handler. + */ +class MacDockIconHandler : public QObject +{ + Q_OBJECT + +public: + ~MacDockIconHandler(); + + QMenu *dockMenu(); + void setIcon(const QIcon &icon); + void setMainWindow(QMainWindow *window); + static MacDockIconHandler *instance(); + + void handleDockIconClickEvent(); + +signals: + void dockIconClicked(); + +private: + MacDockIconHandler(); + + DockIconClickEventHandler *m_dockIconClickEventHandler; + QWidget *m_dummyWidget; + QMenu *m_dockMenu; + QMainWindow *mainWindow; +}; + +#endif // MACDOCKICONCLICKHANDLER_H diff --git a/src/qt/macdockiconhandler.hh b/src/qt/macdockiconhandler.hh new file mode 100644 index 0000000..b21a61c --- /dev/null +++ b/src/qt/macdockiconhandler.hh @@ -0,0 +1,51 @@ +// Copyright (c) 2011-2013 The Bitcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef MACDOCKICONHANDLER_H +#define MACDOCKICONHANDLER_H + +#include +#include + +QT_BEGIN_NAMESPACE +class QIcon; +class QMenu; +class QWidget; +QT_END_NAMESPACE + +#ifdef __OBJC__ +@class DockIconClickEventHandler; +#else +class DockIconClickEventHandler; +#endif + +/** Macintosh-specific dock icon handler. + */ +class MacDockIconHandler : public QObject +{ + Q_OBJECT + +public: + ~MacDockIconHandler(); + + QMenu *dockMenu(); + void setIcon(const QIcon &icon); + void setMainWindow(QMainWindow *window); + static MacDockIconHandler *instance(); + + void handleDockIconClickEvent(); + +signals: + void dockIconClicked(); + +private: + MacDockIconHandler(); + + DockIconClickEventHandler *m_dockIconClickEventHandler; + QWidget *m_dummyWidget; + QMenu *m_dockMenu; + QMainWindow *mainWindow; +}; + +#endif // MACDOCKICONCLICKHANDLER_H diff --git a/src/qt/macdockiconhandler.mm b/src/qt/macdockiconhandler.mm new file mode 100644 index 0000000..fd7ea40 --- /dev/null +++ b/src/qt/macdockiconhandler.mm @@ -0,0 +1,137 @@ +// Copyright (c) 2011-2013 The Bitcoin Core developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "macdockiconhandler.hh" + +#include +#include +#include +#include + +#undef slots +#include + +#if QT_VERSION < 0x050000 +extern void qt_mac_set_dock_menu(QMenu *); +#endif + +@interface DockIconClickEventHandler : NSObject +{ + MacDockIconHandler* dockIconHandler; +} + +@end + +@implementation DockIconClickEventHandler + +- (id)initWithDockIconHandler:(MacDockIconHandler *)aDockIconHandler +{ + self = [super init]; + if (self) { + dockIconHandler = aDockIconHandler; + + [[NSAppleEventManager sharedAppleEventManager] + setEventHandler:self + andSelector:@selector(handleDockClickEvent:withReplyEvent:) + forEventClass:kCoreEventClass + andEventID:kAEReopenApplication]; + } + return self; +} + +- (void)handleDockClickEvent:(NSAppleEventDescriptor*)event withReplyEvent:(NSAppleEventDescriptor*)replyEvent +{ + Q_UNUSED(event) + Q_UNUSED(replyEvent) + + if (dockIconHandler) { + dockIconHandler->handleDockIconClickEvent(); + } +} + +@end + +MacDockIconHandler::MacDockIconHandler() : QObject() +{ + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + + this->m_dockIconClickEventHandler = [[DockIconClickEventHandler alloc] initWithDockIconHandler:this]; + this->m_dummyWidget = new QWidget(); + this->m_dockMenu = new QMenu(this->m_dummyWidget); + this->setMainWindow(NULL); +#if QT_VERSION < 0x050000 + qt_mac_set_dock_menu(this->m_dockMenu); +#elif QT_VERSION >= 0x050200 + this->m_dockMenu->setAsDockMenu(); +#endif + [pool release]; +} + +void MacDockIconHandler::setMainWindow(QMainWindow *window) { + this->mainWindow = window; +} + +MacDockIconHandler::~MacDockIconHandler() +{ + [this->m_dockIconClickEventHandler release]; + delete this->m_dummyWidget; + this->setMainWindow(NULL); +} + +QMenu *MacDockIconHandler::dockMenu() +{ + return this->m_dockMenu; +} + +void MacDockIconHandler::setIcon(const QIcon &icon) +{ + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + NSImage *image = nil; + if (icon.isNull()) + image = [[NSImage imageNamed:@"NSApplicationIcon"] retain]; + else { + // generate NSImage from QIcon and use this as dock icon. + QSize size = icon.actualSize(QSize(128, 128)); + QPixmap pixmap = icon.pixmap(size); + + // write temp file hack (could also be done through QIODevice [memory]) + QTemporaryFile notificationIconFile; + if (!pixmap.isNull() && notificationIconFile.open()) { + QImageWriter writer(¬ificationIconFile, "PNG"); + if (writer.write(pixmap.toImage())) { + const char *cString = notificationIconFile.fileName().toUtf8().data(); + NSString *macString = [NSString stringWithCString:cString encoding:NSUTF8StringEncoding]; + image = [[NSImage alloc] initWithContentsOfFile:macString]; + } + } + + if(!image) { + // if testnet image could not be created, load std. app icon + image = [[NSImage imageNamed:@"NSApplicationIcon"] retain]; + } + } + + [NSApp setApplicationIconImage:image]; + [image release]; + [pool release]; +} + +MacDockIconHandler *MacDockIconHandler::instance() +{ + static MacDockIconHandler *s_instance = NULL; + if (!s_instance) + s_instance = new MacDockIconHandler(); + return s_instance; +} + +void MacDockIconHandler::handleDockIconClickEvent() +{ + if (this->mainWindow) + { + this->mainWindow->activateWindow(); + this->mainWindow->show(); + } + + emit this->dockIconClicked(); +} diff --git a/src/qt/macnotificationhandler.h b/src/qt/macnotificationhandler.h new file mode 100644 index 0000000..bc335ed --- /dev/null +++ b/src/qt/macnotificationhandler.h @@ -0,0 +1,30 @@ +// Copyright (c) 2011-2013 The Bitcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef MACNOTIFICATIONHANDLER_H +#define MACNOTIFICATIONHANDLER_H + +#include + +/** Macintosh-specific notification handler (supports UserNotificationCenter and Growl). + */ +class MacNotificationHandler : public QObject +{ + Q_OBJECT + +public: + /** shows a 10.8+ UserNotification in the UserNotificationCenter + */ + void showNotification(const QString &title, const QString &text); + + /** executes AppleScript */ + void sendAppleScript(const QString &script); + + /** check if OS can handle UserNotifications */ + bool hasUserNotificationCenterSupport(void); + static MacNotificationHandler *instance(); +}; + + +#endif // MACNOTIFICATIONHANDLER_H diff --git a/src/qt/macnotificationhandler.hh b/src/qt/macnotificationhandler.hh new file mode 100644 index 0000000..bc335ed --- /dev/null +++ b/src/qt/macnotificationhandler.hh @@ -0,0 +1,30 @@ +// Copyright (c) 2011-2013 The Bitcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef MACNOTIFICATIONHANDLER_H +#define MACNOTIFICATIONHANDLER_H + +#include + +/** Macintosh-specific notification handler (supports UserNotificationCenter and Growl). + */ +class MacNotificationHandler : public QObject +{ + Q_OBJECT + +public: + /** shows a 10.8+ UserNotification in the UserNotificationCenter + */ + void showNotification(const QString &title, const QString &text); + + /** executes AppleScript */ + void sendAppleScript(const QString &script); + + /** check if OS can handle UserNotifications */ + bool hasUserNotificationCenterSupport(void); + static MacNotificationHandler *instance(); +}; + + +#endif // MACNOTIFICATIONHANDLER_H diff --git a/src/qt/macnotificationhandler.mm b/src/qt/macnotificationhandler.mm new file mode 100644 index 0000000..8a4c94c --- /dev/null +++ b/src/qt/macnotificationhandler.mm @@ -0,0 +1,69 @@ +// Copyright (c) 2011-2013 The Bitcoin Core developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "macnotificationhandler.h" + +#undef slots +#include + +void MacNotificationHandler::showNotification(const QString &title, const QString &text) +{ + // check if users OS has support for NSUserNotification + if(this->hasUserNotificationCenterSupport()) { + // okay, seems like 10.8+ + QByteArray utf8 = title.toUtf8(); + char* cString = (char *)utf8.constData(); + NSString *titleMac = [[NSString alloc] initWithUTF8String:cString]; + + utf8 = text.toUtf8(); + cString = (char *)utf8.constData(); + NSString *textMac = [[NSString alloc] initWithUTF8String:cString]; + + // do everything weak linked (because we will keep <10.8 compatibility) + id userNotification = [[NSClassFromString(@"NSUserNotification") alloc] init]; + [userNotification performSelector:@selector(setTitle:) withObject:titleMac]; + [userNotification performSelector:@selector(setInformativeText:) withObject:textMac]; + + id notificationCenterInstance = [NSClassFromString(@"NSUserNotificationCenter") performSelector:@selector(defaultUserNotificationCenter)]; + [notificationCenterInstance performSelector:@selector(deliverNotification:) withObject:userNotification]; + + [titleMac release]; + [textMac release]; + [userNotification release]; + } +} + +// sendAppleScript just take a QString and executes it as apple script +void MacNotificationHandler::sendAppleScript(const QString &script) +{ + QByteArray utf8 = script.toUtf8(); + char* cString = (char *)utf8.constData(); + NSString *scriptApple = [[NSString alloc] initWithUTF8String:cString]; + + NSAppleScript *as = [[NSAppleScript alloc] initWithSource:scriptApple]; + NSDictionary *err = nil; + [as executeAndReturnError:&err]; + [as release]; + [scriptApple release]; +} + +bool MacNotificationHandler::hasUserNotificationCenterSupport(void) +{ + Class possibleClass = NSClassFromString(@"NSUserNotificationCenter"); + + // check if users OS has support for NSUserNotification + if(possibleClass!=nil) { + return true; + } + return false; +} + + +MacNotificationHandler *MacNotificationHandler::instance() +{ + static MacNotificationHandler *s_instance = NULL; + if (!s_instance) + s_instance = new MacNotificationHandler(); + return s_instance; +} diff --git a/src/qt/monitoreddatamapper.cpp b/src/qt/monitoreddatamapper.cpp new file mode 100644 index 0000000..88948d0 --- /dev/null +++ b/src/qt/monitoreddatamapper.cpp @@ -0,0 +1,36 @@ +#include "monitoreddatamapper.h" + +#include +#include +#include + +MonitoredDataMapper::MonitoredDataMapper(QObject *parent) : + QDataWidgetMapper(parent) +{ +} + + +void MonitoredDataMapper::addMapping(QWidget *widget, int section) +{ + QDataWidgetMapper::addMapping(widget, section); + addChangeMonitor(widget); +} + +void MonitoredDataMapper::addMapping(QWidget *widget, int section, const QByteArray &propertyName) +{ + QDataWidgetMapper::addMapping(widget, section, propertyName); + addChangeMonitor(widget); +} + +void MonitoredDataMapper::addChangeMonitor(QWidget *widget) +{ + // Watch user property of widget for changes, and connect + // the signal to our viewModified signal. + QMetaProperty prop = widget->metaObject()->userProperty(); + int signal = prop.notifySignalIndex(); + int method = this->metaObject()->indexOfMethod("viewModified()"); + if(signal != -1 && method != -1) + { + QMetaObject::connect(widget, signal, this, method); + } +} diff --git a/src/qt/monitoreddatamapper.h b/src/qt/monitoreddatamapper.h new file mode 100644 index 0000000..33a874e --- /dev/null +++ b/src/qt/monitoreddatamapper.h @@ -0,0 +1,31 @@ +#ifndef MONITOREDDATAMAPPER_H +#define MONITOREDDATAMAPPER_H + +#include + +QT_BEGIN_NAMESPACE +class QWidget; +QT_END_NAMESPACE + +/** Data to Widget mapper that watches for edits and notifies listeners when a field is edited. + This can be used, for example, to enable a commit/apply button in a configuration dialog. + */ +class MonitoredDataMapper : public QDataWidgetMapper +{ + Q_OBJECT +public: + explicit MonitoredDataMapper(QObject *parent=0); + + void addMapping(QWidget *widget, int section); + void addMapping(QWidget *widget, int section, const QByteArray &propertyName); +private: + void addChangeMonitor(QWidget *widget); + +signals: + void viewModified(); + +}; + + + +#endif // MONITOREDDATAMAPPER_H diff --git a/src/qt/notificator.cpp b/src/qt/notificator.cpp new file mode 100644 index 0000000..8028190 --- /dev/null +++ b/src/qt/notificator.cpp @@ -0,0 +1,302 @@ +#include "notificator.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef USE_DBUS +#include +#include +#endif + +#ifdef Q_OS_MAC +#include +extern bool qt_mac_execute_apple_script(const QString &script, AEDesc *ret); +#endif + +// https://wiki.ubuntu.com/NotificationDevelopmentGuidelines recommends at least 128 +const int FREEDESKTOP_NOTIFICATION_ICON_SIZE = 128; + +Notificator::Notificator(const QString &programName, QSystemTrayIcon *trayicon, QWidget *parent): + QObject(parent), + parent(parent), + programName(programName), + mode(None), + trayIcon(trayicon) +#ifdef USE_DBUS + ,interface(0) +#endif +{ + if(trayicon && trayicon->supportsMessages()) + { + mode = QSystemTray; + } +#ifdef USE_DBUS + interface = new QDBusInterface("org.freedesktop.Notifications", + "/org/freedesktop/Notifications", "org.freedesktop.Notifications"); + if(interface->isValid()) + { + mode = Freedesktop; + } +#endif +#ifdef Q_OS_MAC + // Check if Growl is installed (based on Qt's tray icon implementation) + CFURLRef cfurl; + OSStatus status = LSGetApplicationForInfo(kLSUnknownType, kLSUnknownCreator, CFSTR("growlTicket"), kLSRolesAll, 0, &cfurl); + if (status != kLSApplicationNotFoundErr) { + CFBundleRef bundle = CFBundleCreate(0, cfurl); + if (CFStringCompare(CFBundleGetIdentifier(bundle), CFSTR("com.Growl.GrowlHelperApp"), kCFCompareCaseInsensitive | kCFCompareBackwards) == kCFCompareEqualTo) { + if (CFStringHasSuffix(CFURLGetString(cfurl), CFSTR("/Growl.app/"))) + mode = Growl13; + else + mode = Growl12; + } + CFRelease(cfurl); + CFRelease(bundle); + } +#endif +} + +Notificator::~Notificator() +{ +#ifdef USE_DBUS + delete interface; +#endif +} + +#ifdef USE_DBUS + +// Loosely based on http://www.qtcentre.org/archive/index.php/t-25879.html +class FreedesktopImage +{ +public: + FreedesktopImage() {} + FreedesktopImage(const QImage &img); + + static int metaType(); + + // Image to variant that can be marshalled over DBus + static QVariant toVariant(const QImage &img); + +private: + int width, height, stride; + bool hasAlpha; + int channels; + int bitsPerSample; + QByteArray image; + + friend QDBusArgument &operator<<(QDBusArgument &a, const FreedesktopImage &i); + friend const QDBusArgument &operator>>(const QDBusArgument &a, FreedesktopImage &i); +}; + +Q_DECLARE_METATYPE(FreedesktopImage); + +// Image configuration settings +const int CHANNELS = 4; +const int BYTES_PER_PIXEL = 4; +const int BITS_PER_SAMPLE = 8; + +FreedesktopImage::FreedesktopImage(const QImage &img): + width(img.width()), + height(img.height()), + stride(img.width() * BYTES_PER_PIXEL), + hasAlpha(true), + channels(CHANNELS), + bitsPerSample(BITS_PER_SAMPLE) +{ + // Convert 00xAARRGGBB to RGBA bytewise (endian-independent) format + QImage tmp = img.convertToFormat(QImage::Format_ARGB32); + const uint32_t *data = reinterpret_cast(tmp.constBits()); + + unsigned int num_pixels = width * height; + image.resize(num_pixels * BYTES_PER_PIXEL); + + for(unsigned int ptr = 0; ptr < num_pixels; ++ptr) + { + image[ptr*BYTES_PER_PIXEL+0] = data[ptr] >> 16; // R + image[ptr*BYTES_PER_PIXEL+1] = data[ptr] >> 8; // G + image[ptr*BYTES_PER_PIXEL+2] = data[ptr]; // B + image[ptr*BYTES_PER_PIXEL+3] = data[ptr] >> 24; // A + } +} + +QDBusArgument &operator<<(QDBusArgument &a, const FreedesktopImage &i) +{ + a.beginStructure(); + a << i.width << i.height << i.stride << i.hasAlpha << i.bitsPerSample << i.channels << i.image; + a.endStructure(); + return a; +} + +const QDBusArgument &operator>>(const QDBusArgument &a, FreedesktopImage &i) +{ + a.beginStructure(); + a >> i.width >> i.height >> i.stride >> i.hasAlpha >> i.bitsPerSample >> i.channels >> i.image; + a.endStructure(); + return a; +} + +int FreedesktopImage::metaType() +{ + return qDBusRegisterMetaType(); +} + +QVariant FreedesktopImage::toVariant(const QImage &img) +{ + FreedesktopImage fimg(img); + return QVariant(FreedesktopImage::metaType(), &fimg); +} + +void Notificator::notifyDBus(Class cls, const QString &title, const QString &text, const QIcon &icon, int millisTimeout) +{ + Q_UNUSED(cls); + // Arguments for DBus call: + QList args; + + // Program Name: + args.append(programName); + + // Unique ID of this notification type: + args.append(0U); + + // Application Icon, empty string + args.append(QString()); + + // Summary + args.append(title); + + // Body + args.append(text); + + // Actions (none, actions are deprecated) + QStringList actions; + args.append(actions); + + // Hints + QVariantMap hints; + + // If no icon specified, set icon based on class + QIcon tmpicon; + if(icon.isNull()) + { + QStyle::StandardPixmap sicon = QStyle::SP_MessageBoxQuestion; + switch(cls) + { + case Information: sicon = QStyle::SP_MessageBoxInformation; break; + case Warning: sicon = QStyle::SP_MessageBoxWarning; break; + case Critical: sicon = QStyle::SP_MessageBoxCritical; break; + default: break; + } + tmpicon = QApplication::style()->standardIcon(sicon); + } + else + { + tmpicon = icon; + } + hints["icon_data"] = FreedesktopImage::toVariant(tmpicon.pixmap(FREEDESKTOP_NOTIFICATION_ICON_SIZE).toImage()); + args.append(hints); + + // Timeout (in msec) + args.append(millisTimeout); + + // "Fire and forget" + interface->callWithArgumentList(QDBus::NoBlock, "Notify", args); +} +#endif + +void Notificator::notifySystray(Class cls, const QString &title, const QString &text, const QIcon &icon, int millisTimeout) +{ + Q_UNUSED(icon); + QSystemTrayIcon::MessageIcon sicon = QSystemTrayIcon::NoIcon; + switch(cls) // Set icon based on class + { + case Information: sicon = QSystemTrayIcon::Information; break; + case Warning: sicon = QSystemTrayIcon::Warning; break; + case Critical: sicon = QSystemTrayIcon::Critical; break; + } + trayIcon->showMessage(title, text, sicon, millisTimeout); +} + +// Based on Qt's tray icon implementation +#ifdef Q_OS_MAC +void Notificator::notifyGrowl(Class cls, const QString &title, const QString &text, const QIcon &icon) +{ + const QString script( + "tell application \"%5\"\n" + " set the allNotificationsList to {\"Notification\"}\n" // -- Make a list of all the notification types (all) + " set the enabledNotificationsList to {\"Notification\"}\n" // -- Make a list of the notifications (enabled) + " register as application \"%1\" all notifications allNotificationsList default notifications enabledNotificationsList\n" // -- Register our script with Growl + " notify with name \"Notification\" title \"%2\" description \"%3\" application name \"%1\"%4\n" // -- Send a Notification + "end tell" + ); + + QString notificationApp(QApplication::applicationName()); + if (notificationApp.isEmpty()) + notificationApp = "Application"; + + QPixmap notificationIconPixmap; + if (icon.isNull()) { // If no icon specified, set icon based on class + QStyle::StandardPixmap sicon = QStyle::SP_MessageBoxQuestion; + switch (cls) + { + case Information: sicon = QStyle::SP_MessageBoxInformation; break; + case Warning: sicon = QStyle::SP_MessageBoxWarning; break; + case Critical: sicon = QStyle::SP_MessageBoxCritical; break; + } + notificationIconPixmap = QApplication::style()->standardPixmap(sicon); + } + else { + QSize size = icon.actualSize(QSize(48, 48)); + notificationIconPixmap = icon.pixmap(size); + } + + QString notificationIcon; + QTemporaryFile notificationIconFile; + if (!notificationIconPixmap.isNull() && notificationIconFile.open()) { + QImageWriter writer(¬ificationIconFile, "PNG"); + if (writer.write(notificationIconPixmap.toImage())) + notificationIcon = QString(" image from location \"file://%1\"").arg(notificationIconFile.fileName()); + } + + QString quotedTitle(title), quotedText(text); + quotedTitle.replace("\\", "\\\\").replace("\"", "\\"); + quotedText.replace("\\", "\\\\").replace("\"", "\\"); + QString growlApp(this->mode == Notificator::Growl13 ? "Growl" : "GrowlHelperApp"); + qt_mac_execute_apple_script(script.arg(notificationApp, quotedTitle, quotedText, notificationIcon, growlApp), 0); +} +#endif + +void Notificator::notify(Class cls, const QString &title, const QString &text, const QIcon &icon, int millisTimeout) +{ + switch(mode) + { +#ifdef USE_DBUS + case Freedesktop: + notifyDBus(cls, title, text, icon, millisTimeout); + break; +#endif + case QSystemTray: + notifySystray(cls, title, text, icon, millisTimeout); + break; +#ifdef Q_OS_MAC + case Growl12: + case Growl13: + notifyGrowl(cls, title, text, icon); + break; +#endif + default: + if(cls == Critical) + { + // Fall back to old fashioned pop-up dialog if critical and no other notification available + QMessageBox::critical(parent, title, text, QMessageBox::Ok, QMessageBox::Ok); + } + break; + } +} diff --git a/src/qt/notificator.h b/src/qt/notificator.h new file mode 100644 index 0000000..abb4710 --- /dev/null +++ b/src/qt/notificator.h @@ -0,0 +1,69 @@ +#ifndef NOTIFICATOR_H +#define NOTIFICATOR_H + +#include +#include + +QT_BEGIN_NAMESPACE +class QSystemTrayIcon; +#ifdef USE_DBUS +class QDBusInterface; +#endif +QT_END_NAMESPACE + +/** Cross-platform desktop notification client. */ +class Notificator: public QObject +{ + Q_OBJECT +public: + /** Create a new notificator. + @note Ownership of trayIcon is not transferred to this object. + */ + Notificator(const QString &programName=QString(), QSystemTrayIcon *trayIcon=0, QWidget *parent=0); + ~Notificator(); + + // Message class + enum Class + { + Information, /**< Informational message */ + Warning, /**< Notify user of potential problem */ + Critical /**< An error occurred */ + }; + +public slots: + + /** Show notification message. + @param[in] cls general message class + @param[in] title title shown with message + @param[in] text message content + @param[in] icon optional icon to show with message + @param[in] millisTimeout notification timeout in milliseconds (defaults to 10 seconds) + @note Platform implementations are free to ignore any of the provided fields except for \a text. + */ + void notify(Class cls, const QString &title, const QString &text, + const QIcon &icon = QIcon(), int millisTimeout = 10000); + +private: + QWidget *parent; + enum Mode { + None, /**< Ignore informational notifications, and show a modal pop-up dialog for Critical notifications. */ + Freedesktop, /**< Use DBus org.freedesktop.Notifications */ + QSystemTray, /**< Use QSystemTray::showMessage */ + Growl12, /**< Use the Growl 1.2 notification system (Mac only) */ + Growl13 /**< Use the Growl 1.3 notification system (Mac only) */ + }; + QString programName; + Mode mode; + QSystemTrayIcon *trayIcon; +#ifdef USE_DBUS + QDBusInterface *interface; + + void notifyDBus(Class cls, const QString &title, const QString &text, const QIcon &icon, int millisTimeout); +#endif + void notifySystray(Class cls, const QString &title, const QString &text, const QIcon &icon, int millisTimeout); +#ifdef Q_OS_MAC + void notifyGrowl(Class cls, const QString &title, const QString &text, const QIcon &icon); +#endif +}; + +#endif // NOTIFICATOR_H diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp new file mode 100644 index 0000000..b1e3850 --- /dev/null +++ b/src/qt/optionsdialog.cpp @@ -0,0 +1,257 @@ +#include "optionsdialog.h" +#include "ui_optionsdialog.h" + +#include "bitcoinunits.h" +#include "monitoreddatamapper.h" +#include "netbase.h" +#include "optionsmodel.h" + +#include +#include +#include +#include +#include +#include + +OptionsDialog::OptionsDialog(QWidget *parent) : + QDialog(parent), + ui(new Ui::OptionsDialog), + model(0), + mapper(0), + fRestartWarningDisplayed_Proxy(false), + fRestartWarningDisplayed_Lang(false), + fProxyIpValid(true) +{ + ui->setupUi(this); + + /* Network elements init */ +#ifndef USE_UPNP + ui->mapPortUpnp->setEnabled(false); +#endif + + ui->proxyIp->setEnabled(false); + ui->proxyPort->setEnabled(false); + ui->proxyPort->setValidator(new QIntValidator(1, 65535, this)); + + ui->socksVersion->setEnabled(false); + ui->socksVersion->addItem("5", 5); + ui->socksVersion->addItem("4", 4); + ui->socksVersion->setCurrentIndex(0); + + connect(ui->connectSocks, SIGNAL(toggled(bool)), ui->proxyIp, SLOT(setEnabled(bool))); + connect(ui->connectSocks, SIGNAL(toggled(bool)), ui->proxyPort, SLOT(setEnabled(bool))); + connect(ui->connectSocks, SIGNAL(toggled(bool)), ui->socksVersion, SLOT(setEnabled(bool))); + connect(ui->connectSocks, SIGNAL(clicked(bool)), this, SLOT(showRestartWarning_Proxy())); + + ui->proxyIp->installEventFilter(this); + + /* Window elements init */ +#ifdef Q_OS_MAC + ui->tabWindow->setVisible(false); +#endif + + /* Display elements init */ + QDir translations(":translations"); + ui->lang->addItem(QString("(") + tr("default") + QString(")"), QVariant("")); + foreach(const QString &langStr, translations.entryList()) + { + QLocale locale(langStr); + + /** check if the locale name consists of 2 parts (language_country) */ + if(langStr.contains("_")) + { +#if QT_VERSION >= 0x040800 + /** display language strings as "native language - native country (locale name)", e.g. "Deutsch - Deutschland (de)" */ + ui->lang->addItem(locale.nativeLanguageName() + QString(" - ") + locale.nativeCountryName() + QString(" (") + langStr + QString(")"), QVariant(langStr)); +#else + /** display language strings as "language - country (locale name)", e.g. "German - Germany (de)" */ + ui->lang->addItem(QLocale::languageToString(locale.language()) + QString(" - ") + QLocale::countryToString(locale.country()) + QString(" (") + langStr + QString(")"), QVariant(langStr)); +#endif + } + else + { +#if QT_VERSION >= 0x040800 + /** display language strings as "native language (locale name)", e.g. "Deutsch (de)" */ + ui->lang->addItem(locale.nativeLanguageName() + QString(" (") + langStr + QString(")"), QVariant(langStr)); +#else + /** display language strings as "language (locale name)", e.g. "German (de)" */ + ui->lang->addItem(QLocale::languageToString(locale.language()) + QString(" (") + langStr + QString(")"), QVariant(langStr)); +#endif + } + } + + ui->unit->setModel(new BitcoinUnits(this)); + + /* Widget-to-option mapper */ + mapper = new MonitoredDataMapper(this); + mapper->setSubmitPolicy(QDataWidgetMapper::ManualSubmit); + mapper->setOrientation(Qt::Vertical); + + /* enable apply button when data modified */ + connect(mapper, SIGNAL(viewModified()), this, SLOT(enableApplyButton())); + /* disable apply button when new data loaded */ + connect(mapper, SIGNAL(currentIndexChanged(int)), this, SLOT(disableApplyButton())); + /* setup/change UI elements when proxy IP is invalid/valid */ + connect(this, SIGNAL(proxyIpValid(QValidatedLineEdit *, bool)), this, SLOT(handleProxyIpValid(QValidatedLineEdit *, bool))); +} + +OptionsDialog::~OptionsDialog() +{ + delete ui; +} + +void OptionsDialog::setModel(OptionsModel *model) +{ + this->model = model; + + if(model) + { + connect(model, SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit())); + + mapper->setModel(model); + setMapper(); + mapper->toFirst(); + } + + /* update the display unit, to not use the default ("BTC") */ + updateDisplayUnit(); + + /* warn only when language selection changes by user action (placed here so init via mapper doesn't trigger this) */ + connect(ui->lang, SIGNAL(valueChanged()), this, SLOT(showRestartWarning_Lang())); + + /* disable apply button after settings are loaded as there is nothing to save */ + disableApplyButton(); +} + +void OptionsDialog::setMapper() +{ + /* Main */ + mapper->addMapping(ui->transactionFee, OptionsModel::Fee); + mapper->addMapping(ui->bitcoinAtStartup, OptionsModel::StartAtStartup); + mapper->addMapping(ui->detachDatabases, OptionsModel::DetachDatabases); + + /* Network */ + mapper->addMapping(ui->mapPortUpnp, OptionsModel::MapPortUPnP); + + mapper->addMapping(ui->connectSocks, OptionsModel::ProxyUse); + mapper->addMapping(ui->proxyIp, OptionsModel::ProxyIP); + mapper->addMapping(ui->proxyPort, OptionsModel::ProxyPort); + mapper->addMapping(ui->socksVersion, OptionsModel::ProxySocksVersion); + + /* Window */ +#ifndef Q_OS_MAC + mapper->addMapping(ui->minimizeToTray, OptionsModel::MinimizeToTray); + mapper->addMapping(ui->minimizeOnClose, OptionsModel::MinimizeOnClose); +#endif + + /* Display */ + mapper->addMapping(ui->lang, OptionsModel::Language); + mapper->addMapping(ui->unit, OptionsModel::DisplayUnit); + mapper->addMapping(ui->displayAddresses, OptionsModel::DisplayAddresses); + mapper->addMapping(ui->coinControlFeatures, OptionsModel::CoinControlFeatures); +} + +void OptionsDialog::enableApplyButton() +{ + ui->applyButton->setEnabled(true); +} + +void OptionsDialog::disableApplyButton() +{ + ui->applyButton->setEnabled(false); +} + +void OptionsDialog::enableSaveButtons() +{ + /* prevent enabling of the save buttons when data modified, if there is an invalid proxy address present */ + if(fProxyIpValid) + setSaveButtonState(true); +} + +void OptionsDialog::disableSaveButtons() +{ + setSaveButtonState(false); +} + +void OptionsDialog::setSaveButtonState(bool fState) +{ + ui->applyButton->setEnabled(fState); + ui->okButton->setEnabled(fState); +} + +void OptionsDialog::on_okButton_clicked() +{ + mapper->submit(); + accept(); +} + +void OptionsDialog::on_cancelButton_clicked() +{ + reject(); +} + +void OptionsDialog::on_applyButton_clicked() +{ + mapper->submit(); + disableApplyButton(); +} + +void OptionsDialog::showRestartWarning_Proxy() +{ + if(!fRestartWarningDisplayed_Proxy) + { + QMessageBox::warning(this, tr("Warning"), tr("This setting will take effect after restarting triangles."), QMessageBox::Ok); + fRestartWarningDisplayed_Proxy = true; + } +} + +void OptionsDialog::showRestartWarning_Lang() +{ + if(!fRestartWarningDisplayed_Lang) + { + QMessageBox::warning(this, tr("Warning"), tr("This setting will take effect after restarting triangles."), QMessageBox::Ok); + fRestartWarningDisplayed_Lang = true; + } +} + +void OptionsDialog::updateDisplayUnit() +{ + if(model) + { + /* Update transactionFee with the current unit */ + ui->transactionFee->setDisplayUnit(model->getDisplayUnit()); + } +} + +void OptionsDialog::handleProxyIpValid(QValidatedLineEdit *object, bool fState) +{ + // this is used in a check before re-enabling the save buttons + fProxyIpValid = fState; + + if(fProxyIpValid) + { + enableSaveButtons(); + ui->statusLabel->clear(); + } + else + { + disableSaveButtons(); + object->setValid(fProxyIpValid); + ui->statusLabel->setStyleSheet("QLabel { color: red; }"); + ui->statusLabel->setText(tr("The supplied proxy address is invalid.")); + } +} + +bool OptionsDialog::eventFilter(QObject *object, QEvent *event) +{ + if(event->type() == QEvent::FocusOut) + { + if(object == ui->proxyIp) + { + CService addr; + /* Check proxyIp for a valid IPv4/IPv6 address and emit the proxyIpValid signal */ + emit proxyIpValid(ui->proxyIp, LookupNumeric(ui->proxyIp->text().toStdString().c_str(), addr)); + } + } + return QDialog::eventFilter(object, event); +} diff --git a/src/qt/optionsdialog.h b/src/qt/optionsdialog.h new file mode 100644 index 0000000..18469f5 --- /dev/null +++ b/src/qt/optionsdialog.h @@ -0,0 +1,60 @@ +#ifndef OPTIONSDIALOG_H +#define OPTIONSDIALOG_H + +#include + +namespace Ui { +class OptionsDialog; +} +class OptionsModel; +class MonitoredDataMapper; +class QValidatedLineEdit; + +/** Preferences dialog. */ +class OptionsDialog : public QDialog +{ + Q_OBJECT + +public: + explicit OptionsDialog(QWidget *parent = 0); + ~OptionsDialog(); + + void setModel(OptionsModel *model); + void setMapper(); + +protected: + bool eventFilter(QObject *object, QEvent *event); + +private slots: + /* enable only apply button */ + void enableApplyButton(); + /* disable only apply button */ + void disableApplyButton(); + /* enable apply button and OK button */ + void enableSaveButtons(); + /* disable apply button and OK button */ + void disableSaveButtons(); + /* set apply button and OK button state (enabled / disabled) */ + void setSaveButtonState(bool fState); + void on_okButton_clicked(); + void on_cancelButton_clicked(); + void on_applyButton_clicked(); + + void showRestartWarning_Proxy(); + void showRestartWarning_Lang(); + void updateDisplayUnit(); + void handleProxyIpValid(QValidatedLineEdit *object, bool fState); + +signals: + void proxyIpValid(QValidatedLineEdit *object, bool fValid); + +private: + Ui::OptionsDialog *ui; + OptionsModel *model; + MonitoredDataMapper *mapper; + bool fRestartWarningDisplayed_Proxy; + bool fRestartWarningDisplayed_Lang; + bool fProxyIpValid; +}; + +#endif // OPTIONSDIALOG_H diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp new file mode 100644 index 0000000..e394fac --- /dev/null +++ b/src/qt/optionsmodel.cpp @@ -0,0 +1,308 @@ +#include "optionsmodel.h" +#include "bitcoinunits.h" +#include + +#include "init.h" +#include "walletdb.h" +#include "guiutil.h" + +OptionsModel::OptionsModel(QObject *parent) : + QAbstractListModel(parent) +{ + Init(); +} + +bool static ApplyProxySettings() +{ + QSettings settings; + CService addrProxy(settings.value("addrProxy", "127.0.0.1:9244").toString().toStdString()); + int nSocksVersion(settings.value("nSocksVersion", 5).toInt()); + if (!settings.value("fUseProxy", false).toBool()) { + addrProxy = CService(); + nSocksVersion = 0; + return false; + } + if (nSocksVersion && !addrProxy.IsValid()) + return false; + if (!IsLimited(NET_IPV4)) + SetProxy(NET_IPV4, addrProxy, nSocksVersion); + if (nSocksVersion > 4) { +#ifdef USE_IPV6 + if (!IsLimited(NET_IPV6)) + SetProxy(NET_IPV6, addrProxy, nSocksVersion); +#endif + SetNameProxy(addrProxy, nSocksVersion); + } + return true; +} + +void OptionsModel::Init() +{ + QSettings settings; + + // These are Qt-only settings: + nDisplayUnit = settings.value("nDisplayUnit", BitcoinUnits::BTC).toInt(); + bDisplayAddresses = settings.value("bDisplayAddresses", false).toBool(); + fMinimizeToTray = settings.value("fMinimizeToTray", false).toBool(); + fMinimizeOnClose = settings.value("fMinimizeOnClose", false).toBool(); + fCoinControlFeatures = settings.value("fCoinControlFeatures", false).toBool(); + nTransactionFee = settings.value("nTransactionFee").toLongLong(); + language = settings.value("language", "").toString(); + + // These are shared with core Bitcoin; we want + // command-line options to override the GUI settings: + if (settings.contains("fUseUPnP")) + SoftSetBoolArg("-upnp", settings.value("fUseUPnP").toBool()); + if (settings.contains("addrProxy") && settings.value("fUseProxy").toBool()) + SoftSetArg("-proxy", settings.value("addrProxy").toString().toStdString()); + if (settings.contains("nSocksVersion") && settings.value("fUseProxy").toBool()) + SoftSetArg("-socks", settings.value("nSocksVersion").toString().toStdString()); + if (settings.contains("detachDB")) + SoftSetBoolArg("-detachdb", settings.value("detachDB").toBool()); + if (!language.isEmpty()) + SoftSetArg("-lang", language.toStdString()); +} + +bool OptionsModel::Upgrade() +{ + QSettings settings; + + if (settings.contains("bImportFinished")) + return false; // Already upgraded + + settings.setValue("bImportFinished", true); + + // Move settings from old wallet.dat (if any): + CWalletDB walletdb("wallet.dat"); + + QList intOptions; + intOptions << "nDisplayUnit" << "nTransactionFee"; + foreach(QString key, intOptions) + { + int value = 0; + if (walletdb.ReadSetting(key.toStdString(), value)) + { + settings.setValue(key, value); + walletdb.EraseSetting(key.toStdString()); + } + } + QList boolOptions; + boolOptions << "bDisplayAddresses" << "fMinimizeToTray" << "fMinimizeOnClose" << "fUseProxy" << "fUseUPnP"; + foreach(QString key, boolOptions) + { + bool value = false; + if (walletdb.ReadSetting(key.toStdString(), value)) + { + settings.setValue(key, value); + walletdb.EraseSetting(key.toStdString()); + } + } + try + { + CAddress addrProxyAddress; + if (walletdb.ReadSetting("addrProxy", addrProxyAddress)) + { + settings.setValue("addrProxy", addrProxyAddress.ToStringIPPort().c_str()); + walletdb.EraseSetting("addrProxy"); + } + } + catch (std::ios_base::failure &e) + { + // 0.6.0rc1 saved this as a CService, which causes failure when parsing as a CAddress + CService addrProxy; + if (walletdb.ReadSetting("addrProxy", addrProxy)) + { + settings.setValue("addrProxy", addrProxy.ToStringIPPort().c_str()); + walletdb.EraseSetting("addrProxy"); + } + } + ApplyProxySettings(); + Init(); + + return true; +} + + +int OptionsModel::rowCount(const QModelIndex & parent) const +{ + return OptionIDRowCount; +} + +QVariant OptionsModel::data(const QModelIndex & index, int role) const +{ + if(role == Qt::EditRole) + { + QSettings settings; + switch(index.row()) + { + case StartAtStartup: + return QVariant(GUIUtil::GetStartOnSystemStartup()); + case MinimizeToTray: + return QVariant(fMinimizeToTray); + case MapPortUPnP: + return settings.value("fUseUPnP", GetBoolArg("-upnp", true)); + case MinimizeOnClose: + return QVariant(fMinimizeOnClose); + case ProxyUse: + return settings.value("fUseProxy", false); + case ProxyIP: { + proxyType proxy; + if (GetProxy(NET_IPV4, proxy)) + return QVariant(QString::fromStdString(proxy.first.ToStringIP())); + else + return QVariant(QString::fromStdString("127.0.0.1")); + } + case ProxyPort: { + proxyType proxy; + if (GetProxy(NET_IPV4, proxy)) + return QVariant(proxy.first.GetPort()); + else + return QVariant(9244); + } + case ProxySocksVersion: + return settings.value("nSocksVersion", 5); + case Fee: + return QVariant(nTransactionFee); + case DisplayUnit: + return QVariant(nDisplayUnit); + case DisplayAddresses: + return QVariant(bDisplayAddresses); + case DetachDatabases: + return QVariant(bitdb.GetDetach()); + case Language: + return settings.value("language", ""); + case CoinControlFeatures: + return QVariant(fCoinControlFeatures); + default: + return QVariant(); + } + } + return QVariant(); +} + +bool OptionsModel::setData(const QModelIndex & index, const QVariant & value, int role) +{ + bool successful = true; /* set to false on parse error */ + if(role == Qt::EditRole) + { + QSettings settings; + switch(index.row()) + { + case StartAtStartup: + successful = GUIUtil::SetStartOnSystemStartup(value.toBool()); + break; + case MinimizeToTray: + fMinimizeToTray = value.toBool(); + settings.setValue("fMinimizeToTray", fMinimizeToTray); + break; + case MapPortUPnP: + settings.setValue("fUseUPnP", value.toBool()); + MapPort(value.toBool()); + break; + case MinimizeOnClose: + fMinimizeOnClose = value.toBool(); + settings.setValue("fMinimizeOnClose", fMinimizeOnClose); + break; + case ProxyUse: + settings.setValue("fUseProxy", value.toBool()); + ApplyProxySettings(); + break; + case ProxyIP: { + proxyType proxy; + proxy.first = CService("127.0.0.1", 9244); + GetProxy(NET_IPV4, proxy); + + CNetAddr addr(value.toString().toStdString()); + proxy.first.SetIP(addr); + settings.setValue("addrProxy", proxy.first.ToStringIPPort().c_str()); + successful = ApplyProxySettings(); + } + break; + case ProxyPort: { + proxyType proxy; + proxy.first = CService("127.0.0.1", 9244); + GetProxy(NET_IPV4, proxy); + + proxy.first.SetPort(value.toInt()); + settings.setValue("addrProxy", proxy.first.ToStringIPPort().c_str()); + successful = ApplyProxySettings(); + } + break; + case ProxySocksVersion: { + proxyType proxy; + proxy.second = 5; + GetProxy(NET_IPV4, proxy); + + proxy.second = value.toInt(); + settings.setValue("nSocksVersion", proxy.second); + successful = ApplyProxySettings(); + } + break; + case Fee: + nTransactionFee = value.toLongLong(); + settings.setValue("nTransactionFee", nTransactionFee); + emit transactionFeeChanged(nTransactionFee); + break; + case DisplayUnit: + nDisplayUnit = value.toInt(); + settings.setValue("nDisplayUnit", nDisplayUnit); + emit displayUnitChanged(nDisplayUnit); + break; + case DisplayAddresses: + bDisplayAddresses = value.toBool(); + settings.setValue("bDisplayAddresses", bDisplayAddresses); + break; + case DetachDatabases: { + bool fDetachDB = value.toBool(); + bitdb.SetDetach(fDetachDB); + settings.setValue("detachDB", fDetachDB); + } + break; + case Language: + settings.setValue("language", value); + break; + case CoinControlFeatures: { + fCoinControlFeatures = value.toBool(); + settings.setValue("fCoinControlFeatures", fCoinControlFeatures); + emit coinControlFeaturesChanged(fCoinControlFeatures); + } + break; + default: + break; + } + } + emit dataChanged(index, index); + + return successful; +} + +qint64 OptionsModel::getTransactionFee() +{ + return nTransactionFee; +} + +bool OptionsModel::getCoinControlFeatures() +{ + return fCoinControlFeatures; +} + + +bool OptionsModel::getMinimizeToTray() +{ + return fMinimizeToTray; +} + +bool OptionsModel::getMinimizeOnClose() +{ + return fMinimizeOnClose; +} + +int OptionsModel::getDisplayUnit() +{ + return nDisplayUnit; +} + +bool OptionsModel::getDisplayAddresses() +{ + return bDisplayAddresses; +} diff --git a/src/qt/optionsmodel.h b/src/qt/optionsmodel.h new file mode 100644 index 0000000..263b95e --- /dev/null +++ b/src/qt/optionsmodel.h @@ -0,0 +1,69 @@ +#ifndef OPTIONSMODEL_H +#define OPTIONSMODEL_H + +#include + +/** Interface from Qt to configuration data structure for Bitcoin client. + To Qt, the options are presented as a list with the different options + laid out vertically. + This can be changed to a tree once the settings become sufficiently + complex. + */ +class OptionsModel : public QAbstractListModel +{ + Q_OBJECT + +public: + explicit OptionsModel(QObject *parent = 0); + + enum OptionID { + StartAtStartup, // bool + MinimizeToTray, // bool + MapPortUPnP, // bool + MinimizeOnClose, // bool + ProxyUse, // bool + ProxyIP, // QString + ProxyPort, // int + ProxySocksVersion, // int + Fee, // qint64 + DisplayUnit, // BitcoinUnits::Unit + DisplayAddresses, // bool + DetachDatabases, // bool + Language, // QString + CoinControlFeatures, // bool + OptionIDRowCount, + }; + + void Init(); + + /* Migrate settings from wallet.dat after app initialization */ + bool Upgrade(); /* returns true if settings upgraded */ + + int rowCount(const QModelIndex & parent = QModelIndex()) const; + QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const; + bool setData(const QModelIndex & index, const QVariant & value, int role = Qt::EditRole); + + /* Explicit getters */ + qint64 getTransactionFee(); + bool getMinimizeToTray(); + bool getMinimizeOnClose(); + int getDisplayUnit(); + bool getDisplayAddresses(); + bool getCoinControlFeatures(); + QString getLanguage() { return language; } + +private: + int nDisplayUnit; + bool bDisplayAddresses; + bool fMinimizeToTray; + bool fMinimizeOnClose; + bool fCoinControlFeatures; + QString language; + +signals: + void displayUnitChanged(int unit); + void transactionFeeChanged(qint64); + void coinControlFeaturesChanged(bool); +}; + +#endif // OPTIONSMODEL_H diff --git a/src/qt/overviewpage.cpp b/src/qt/overviewpage.cpp new file mode 100644 index 0000000..55f358d --- /dev/null +++ b/src/qt/overviewpage.cpp @@ -0,0 +1,204 @@ +#include "overviewpage.h" +#include "ui_overviewpage.h" + +#include "walletmodel.h" +#include "bitcoinunits.h" +#include "optionsmodel.h" +#include "transactiontablemodel.h" +#include "transactionfilterproxy.h" +#include "guiutil.h" +#include "guiconstants.h" +#include "askpassphrasedialog.h" + +#include +#include + +#define DECORATION_SIZE 64 +#define NUM_ITEMS 6 + +class TxViewDelegate : public QAbstractItemDelegate +{ + Q_OBJECT +public: + TxViewDelegate(): QAbstractItemDelegate(), unit(BitcoinUnits::BTC) + { + + } + + inline void paint(QPainter *painter, const QStyleOptionViewItem &option, + const QModelIndex &index ) const + { + painter->save(); + + QIcon icon = qvariant_cast(index.data(Qt::DecorationRole)); + QRect mainRect = option.rect; + QRect decorationRect(mainRect.topLeft(), QSize(DECORATION_SIZE, DECORATION_SIZE)); + int xspace = DECORATION_SIZE + 8; + int ypad = 6; + int halfheight = (mainRect.height() - 2*ypad)/2; + QRect amountRect(mainRect.left() + xspace, mainRect.top()+ypad, mainRect.width() - xspace, halfheight); + QRect addressRect(mainRect.left() + xspace, mainRect.top()+ypad+halfheight, mainRect.width() - xspace, halfheight); + icon.paint(painter, decorationRect); + + QDateTime date = index.data(TransactionTableModel::DateRole).toDateTime(); + QString address = index.data(Qt::DisplayRole).toString(); + qint64 amount = index.data(TransactionTableModel::AmountRole).toLongLong(); + bool confirmed = index.data(TransactionTableModel::ConfirmedRole).toBool(); + QVariant value = index.data(Qt::ForegroundRole); + QColor foreground = option.palette.color(QPalette::Text); + if(qVariantCanConvert(value)) + { + foreground = qvariant_cast(value); + } + + painter->setPen(foreground); + painter->drawText(addressRect, Qt::AlignLeft|Qt::AlignVCenter, address); + + if(amount < 0) + { + foreground = COLOR_NEGATIVE; + } + else if(!confirmed) + { + foreground = COLOR_UNCONFIRMED; + } + else + { + foreground = option.palette.color(QPalette::Text); + } + painter->setPen(foreground); + QString amountText = BitcoinUnits::formatWithUnit(unit, amount, true); + if(!confirmed) + { + amountText = QString("[") + amountText + QString("]"); + } + painter->drawText(amountRect, Qt::AlignRight|Qt::AlignVCenter, amountText); + + painter->setPen(option.palette.color(QPalette::Text)); + painter->drawText(amountRect, Qt::AlignLeft|Qt::AlignVCenter, GUIUtil::dateTimeStr(date)); + + painter->restore(); + } + + inline QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const + { + return QSize(DECORATION_SIZE, DECORATION_SIZE); + } + + int unit; + +}; +#include "overviewpage.moc" + +OverviewPage::OverviewPage(QWidget *parent) : + QWidget(parent), + ui(new Ui::OverviewPage), + currentBalance(-1), + currentStake(0), + currentUnconfirmedBalance(-1), + currentImmatureBalance(-1), + txdelegate(new TxViewDelegate()), + filter(0) +{ + ui->setupUi(this); + + // Recent transactions + ui->listTransactions->setItemDelegate(txdelegate); + ui->listTransactions->setIconSize(QSize(DECORATION_SIZE, DECORATION_SIZE)); + ui->listTransactions->setMinimumHeight(NUM_ITEMS * (DECORATION_SIZE + 2)); + ui->listTransactions->setAttribute(Qt::WA_MacShowFocusRect, false); + + connect(ui->listTransactions, SIGNAL(clicked(QModelIndex)), this, SLOT(handleTransactionClicked(QModelIndex))); + + // init "out of sync" warning labels + ui->labelWalletStatus->setText("(" + tr("out of sync") + ")"); + ui->labelTransactionsStatus->setText("(" + tr("out of sync") + ")"); + + // start with displaying the "out of sync" warnings + showOutOfSyncWarning(true); +} + +void OverviewPage::handleTransactionClicked(const QModelIndex &index) +{ + if(filter) + emit transactionClicked(filter->mapToSource(index)); +} + +OverviewPage::~OverviewPage() +{ + delete ui; +} + +void OverviewPage::setBalance(qint64 balance, qint64 stake, qint64 unconfirmedBalance, qint64 immatureBalance) +{ + int unit = model->getOptionsModel()->getDisplayUnit(); + currentBalance = balance; + currentStake = stake; + currentUnconfirmedBalance = unconfirmedBalance; + currentImmatureBalance = immatureBalance; + ui->labelBalance->setText(BitcoinUnits::formatWithUnit(unit, balance)); + ui->labelStake->setText(BitcoinUnits::formatWithUnit(unit, stake)); + ui->labelUnconfirmed->setText(BitcoinUnits::formatWithUnit(unit, unconfirmedBalance)); + ui->labelImmature->setText(BitcoinUnits::formatWithUnit(unit, immatureBalance)); + + // only show immature (newly mined) balance if it's non-zero, so as not to complicate things + // for the non-mining users + bool showImmature = immatureBalance != 0; + ui->labelImmature->setVisible(showImmature); + ui->labelImmatureText->setVisible(showImmature); +} + +void OverviewPage::setNumTransactions(int count) +{ + ui->labelNumTransactions->setText(QLocale::system().toString(count)); +} + +void OverviewPage::setModel(WalletModel *model) +{ + this->model = model; + if(model && model->getOptionsModel()) + { + // Set up transaction list + filter = new TransactionFilterProxy(); + filter->setSourceModel(model->getTransactionTableModel()); + filter->setLimit(NUM_ITEMS); + filter->setDynamicSortFilter(true); + filter->setSortRole(Qt::EditRole); + filter->sort(TransactionTableModel::Date, Qt::DescendingOrder); + + ui->listTransactions->setModel(filter); + ui->listTransactions->setModelColumn(TransactionTableModel::ToAddress); + + // Keep up to date with wallet + setBalance(model->getBalance(), model->getStake(), model->getUnconfirmedBalance(), model->getImmatureBalance()); + connect(model, SIGNAL(balanceChanged(qint64, qint64, qint64, qint64)), this, SLOT(setBalance(qint64, qint64, qint64, qint64))); + + setNumTransactions(model->getNumTransactions()); + connect(model, SIGNAL(numTransactionsChanged(int)), this, SLOT(setNumTransactions(int))); + + connect(model->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit())); + } + + // update the display unit, to not use the default + updateDisplayUnit(); +} + +void OverviewPage::updateDisplayUnit() +{ + if(model && model->getOptionsModel()) + { + if(currentBalance != -1) + setBalance(currentBalance, model->getStake(), currentUnconfirmedBalance, currentImmatureBalance); + + // Update txdelegate->unit with the current unit + txdelegate->unit = model->getOptionsModel()->getDisplayUnit(); + + ui->listTransactions->update(); + } +} + +void OverviewPage::showOutOfSyncWarning(bool fShow) +{ + ui->labelWalletStatus->setVisible(fShow); + ui->labelTransactionsStatus->setVisible(fShow); +} diff --git a/src/qt/overviewpage.h b/src/qt/overviewpage.h new file mode 100644 index 0000000..59fbb1d --- /dev/null +++ b/src/qt/overviewpage.h @@ -0,0 +1,52 @@ +#ifndef OVERVIEWPAGE_H +#define OVERVIEWPAGE_H + +#include + +QT_BEGIN_NAMESPACE +class QModelIndex; +QT_END_NAMESPACE + +namespace Ui { + class OverviewPage; +} +class WalletModel; +class TxViewDelegate; +class TransactionFilterProxy; + +/** Overview ("home") page widget */ +class OverviewPage : public QWidget +{ + Q_OBJECT + +public: + explicit OverviewPage(QWidget *parent = 0); + ~OverviewPage(); + + void setModel(WalletModel *model); + void showOutOfSyncWarning(bool fShow); + +public slots: + void setBalance(qint64 balance, qint64 stake, qint64 unconfirmedBalance, qint64 immatureBalance); + void setNumTransactions(int count); + +signals: + void transactionClicked(const QModelIndex &index); + +private: + Ui::OverviewPage *ui; + WalletModel *model; + qint64 currentBalance; + qint64 currentStake; + qint64 currentUnconfirmedBalance; + qint64 currentImmatureBalance; + + TxViewDelegate *txdelegate; + TransactionFilterProxy *filter; + +private slots: + void updateDisplayUnit(); + void handleTransactionClicked(const QModelIndex &index); +}; + +#endif // OVERVIEWPAGE_H diff --git a/src/qt/qrcodedialog.cpp b/src/qt/qrcodedialog.cpp new file mode 100644 index 0000000..fc055d4 --- /dev/null +++ b/src/qt/qrcodedialog.cpp @@ -0,0 +1,171 @@ +#include "qrcodedialog.h" +#include "ui_qrcodedialog.h" + +#include "bitcoinunits.h" +#include "guiconstants.h" +#include "guiutil.h" +#include "optionsmodel.h" + +#include +#include + +#include + +QRCodeDialog::QRCodeDialog(const QString &addr, const QString &label, bool enableReq, QWidget *parent) : + QDialog(parent), + ui(new Ui::QRCodeDialog), + model(0), + address(addr) +{ + ui->setupUi(this); + + setWindowTitle(QString("%1").arg(address)); + + ui->chkReqPayment->setVisible(enableReq); + ui->lblAmount->setVisible(enableReq); + ui->lnReqAmount->setVisible(enableReq); + + ui->lnLabel->setText(label); + + ui->btnSaveAs->setEnabled(false); + + genCode(); +} + +QRCodeDialog::~QRCodeDialog() +{ + delete ui; +} + +void QRCodeDialog::setModel(OptionsModel *model) +{ + this->model = model; + + if (model) + connect(model, SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit())); + + // update the display unit, to not use the default ("BTC") + updateDisplayUnit(); +} + +void QRCodeDialog::genCode() +{ + QString uri = getURI(); + + if (uri != "") + { + ui->lblQRCode->setText(""); + + QRcode *code = QRcode_encodeString(uri.toUtf8().constData(), 0, QR_ECLEVEL_L, QR_MODE_8, 1); + if (!code) + { + ui->lblQRCode->setText(tr("Error encoding URI into QR Code.")); + return; + } + myImage = QImage(code->width + 8, code->width + 8, QImage::Format_RGB32); + myImage.fill(0xffffff); + unsigned char *p = code->data; + for (int y = 0; y < code->width; y++) + { + for (int x = 0; x < code->width; x++) + { + myImage.setPixel(x + 4, y + 4, ((*p & 1) ? 0x0 : 0xffffff)); + p++; + } + } + QRcode_free(code); + + ui->lblQRCode->setPixmap(QPixmap::fromImage(myImage).scaled(300, 300)); + + ui->outUri->setPlainText(uri); + } +} + +QString QRCodeDialog::getURI() +{ + QString ret = QString("triangle:%1").arg(address); + int paramCount = 0; + + ui->outUri->clear(); + + if (ui->chkReqPayment->isChecked()) + { + if (ui->lnReqAmount->validate()) + { + // even if we allow a non BTC unit input in lnReqAmount, we generate the URI with BTC as unit (as defined in BIP21) + ret += QString("?amount=%1").arg(BitcoinUnits::format(BitcoinUnits::BTC, ui->lnReqAmount->value())); + paramCount++; + } + else + { + ui->btnSaveAs->setEnabled(false); + ui->lblQRCode->setText(tr("The entered amount is invalid, please check.")); + return QString(""); + } + } + + if (!ui->lnLabel->text().isEmpty()) + { + QString lbl(QUrl::toPercentEncoding(ui->lnLabel->text())); + ret += QString("%1label=%2").arg(paramCount == 0 ? "?" : "&").arg(lbl); + paramCount++; + } + + if (!ui->lnMessage->text().isEmpty()) + { + QString msg(QUrl::toPercentEncoding(ui->lnMessage->text())); + ret += QString("%1message=%2").arg(paramCount == 0 ? "?" : "&").arg(msg); + paramCount++; + } + + // limit URI length to prevent a DoS against the QR-Code dialog + if (ret.length() > MAX_URI_LENGTH) + { + ui->btnSaveAs->setEnabled(false); + ui->lblQRCode->setText(tr("Resulting URI too long, try to reduce the text for label / message.")); + return QString(""); + } + + ui->btnSaveAs->setEnabled(true); + return ret; +} + +void QRCodeDialog::on_lnReqAmount_textChanged() +{ + genCode(); +} + +void QRCodeDialog::on_lnLabel_textChanged() +{ + genCode(); +} + +void QRCodeDialog::on_lnMessage_textChanged() +{ + genCode(); +} + +void QRCodeDialog::on_btnSaveAs_clicked() +{ + QString fn = GUIUtil::getSaveFileName(this, tr("Save QR Code"), QString(), tr("PNG Images (*.png)")); + if (!fn.isEmpty()) + myImage.scaled(EXPORT_IMAGE_SIZE, EXPORT_IMAGE_SIZE).save(fn); +} + +void QRCodeDialog::on_chkReqPayment_toggled(bool fChecked) +{ + if (!fChecked) + // if chkReqPayment is not active, don't display lnReqAmount as invalid + ui->lnReqAmount->setValid(true); + + genCode(); +} + +void QRCodeDialog::updateDisplayUnit() +{ + if (model) + { + // Update lnReqAmount with the current unit + ui->lnReqAmount->setDisplayUnit(model->getDisplayUnit()); + } +} diff --git a/src/qt/qrcodedialog.h b/src/qt/qrcodedialog.h new file mode 100644 index 0000000..c55c34b --- /dev/null +++ b/src/qt/qrcodedialog.h @@ -0,0 +1,41 @@ +#ifndef QRCODEDIALOG_H +#define QRCODEDIALOG_H + +#include +#include + +namespace Ui { + class QRCodeDialog; +} +class OptionsModel; + +class QRCodeDialog : public QDialog +{ + Q_OBJECT + +public: + explicit QRCodeDialog(const QString &addr, const QString &label, bool enableReq, QWidget *parent = 0); + ~QRCodeDialog(); + + void setModel(OptionsModel *model); + +private slots: + void on_lnReqAmount_textChanged(); + void on_lnLabel_textChanged(); + void on_lnMessage_textChanged(); + void on_btnSaveAs_clicked(); + void on_chkReqPayment_toggled(bool fChecked); + + void updateDisplayUnit(); + +private: + Ui::QRCodeDialog *ui; + OptionsModel *model; + QString address; + QImage myImage; + + void genCode(); + QString getURI(); +}; + +#endif // QRCODEDIALOG_H diff --git a/src/qt/qtipcserver.cpp b/src/qt/qtipcserver.cpp new file mode 100644 index 0000000..b26c375 --- /dev/null +++ b/src/qt/qtipcserver.cpp @@ -0,0 +1,162 @@ +// Copyright (c) 2009-2012 The Bitcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include +#if defined(WIN32) && BOOST_VERSION == 104900 +#define BOOST_INTERPROCESS_HAS_WINDOWS_KERNEL_BOOTTIME +#define BOOST_INTERPROCESS_HAS_KERNEL_BOOTTIME +#endif + +#include "qtipcserver.h" +#include "guiconstants.h" +#include "ui_interface.h" +#include "util.h" + +#include +#include +#include +#include + +#if defined(WIN32) && (!defined(BOOST_INTERPROCESS_HAS_WINDOWS_KERNEL_BOOTTIME) || !defined(BOOST_INTERPROCESS_HAS_KERNEL_BOOTTIME) || BOOST_VERSION < 104900) +#warning Compiling without BOOST_INTERPROCESS_HAS_WINDOWS_KERNEL_BOOTTIME and BOOST_INTERPROCESS_HAS_KERNEL_BOOTTIME uncommented in boost/interprocess/detail/tmp_dir_helpers.hpp or using a boost version before 1.49 may have unintended results see svn.boost.org/trac/boost/ticket/5392 +#endif + +using namespace boost; +using namespace boost::interprocess; +using namespace boost::posix_time; + +#if defined MAC_OSX || defined __FreeBSD__ +// URI handling not implemented on OSX yet + +void ipcScanRelay(int argc, char *argv[]) { } +void ipcInit(int argc, char *argv[]) { } + +#else + +static void ipcThread2(void* pArg); + +static bool ipcScanCmd(int argc, char *argv[], bool fRelay) +{ + // Check for URI in argv + bool fSent = false; + for (int i = 1; i < argc; i++) + { + if (boost::algorithm::istarts_with(argv[i], "bitcoin:")) + { + const char *strURI = argv[i]; + try { + boost::interprocess::message_queue mq(boost::interprocess::open_only, BITCOINURI_QUEUE_NAME); + if (mq.try_send(strURI, strlen(strURI), 0)) + fSent = true; + else if (fRelay) + break; + } + catch (boost::interprocess::interprocess_exception &ex) { + // don't log the "file not found" exception, because that's normal for + // the first start of the first instance + if (ex.get_error_code() != boost::interprocess::not_found_error || !fRelay) + { + printf("main() - boost interprocess exception #%d: %s\n", ex.get_error_code(), ex.what()); + break; + } + } + } + } + return fSent; +} + +void ipcScanRelay(int argc, char *argv[]) +{ + if (ipcScanCmd(argc, argv, true)) + exit(0); +} + +static void ipcThread(void* pArg) +{ + // Make this thread recognisable as the GUI-IPC thread + RenameThread("bitcoin-gui-ipc"); + + try + { + ipcThread2(pArg); + } + catch (std::exception& e) { + PrintExceptionContinue(&e, "ipcThread()"); + } catch (...) { + PrintExceptionContinue(NULL, "ipcThread()"); + } + printf("ipcThread exited\n"); +} + +static void ipcThread2(void* pArg) +{ + printf("ipcThread started\n"); + + message_queue* mq = (message_queue*)pArg; + char buffer[MAX_URI_LENGTH + 1] = ""; + size_t nSize = 0; + unsigned int nPriority = 0; + + loop + { + ptime d = boost::posix_time::microsec_clock::universal_time() + millisec(100); + if (mq->timed_receive(&buffer, sizeof(buffer), nSize, nPriority, d)) + { + uiInterface.ThreadSafeHandleURI(std::string(buffer, nSize)); + Sleep(1000); + } + + if (fShutdown) + break; + } + + // Remove message queue + message_queue::remove(BITCOINURI_QUEUE_NAME); + // Cleanup allocated memory + delete mq; +} + +void ipcInit(int argc, char *argv[]) +{ + message_queue* mq = NULL; + char buffer[MAX_URI_LENGTH + 1] = ""; + size_t nSize = 0; + unsigned int nPriority = 0; + + try { + mq = new message_queue(open_or_create, BITCOINURI_QUEUE_NAME, 2, MAX_URI_LENGTH); + + // Make sure we don't lose any bitcoin: URIs + for (int i = 0; i < 2; i++) + { + ptime d = boost::posix_time::microsec_clock::universal_time() + millisec(1); + if (mq->timed_receive(&buffer, sizeof(buffer), nSize, nPriority, d)) + { + uiInterface.ThreadSafeHandleURI(std::string(buffer, nSize)); + } + else + break; + } + + // Make sure only one bitcoin instance is listening + message_queue::remove(BITCOINURI_QUEUE_NAME); + delete mq; + + mq = new message_queue(open_or_create, BITCOINURI_QUEUE_NAME, 2, MAX_URI_LENGTH); + } + catch (interprocess_exception &ex) { + printf("ipcInit() - boost interprocess exception #%d: %s\n", ex.get_error_code(), ex.what()); + return; + } + + if (!NewThread(ipcThread, mq)) + { + delete mq; + return; + } + + ipcScanCmd(argc, argv, false); +} + +#endif diff --git a/src/qt/qtipcserver.h b/src/qt/qtipcserver.h new file mode 100644 index 0000000..cccf200 --- /dev/null +++ b/src/qt/qtipcserver.h @@ -0,0 +1,10 @@ +#ifndef QTIPCSERVER_H +#define QTIPCSERVER_H + +// Define Bitcoin-Qt message queue name +#define BITCOINURI_QUEUE_NAME "BitcoinURI" + +void ipcScanRelay(int argc, char *argv[]); +void ipcInit(int argc, char *argv[]); + +#endif // QTIPCSERVER_H diff --git a/src/qt/qvalidatedlineedit.cpp b/src/qt/qvalidatedlineedit.cpp new file mode 100644 index 0000000..8ca230c --- /dev/null +++ b/src/qt/qvalidatedlineedit.cpp @@ -0,0 +1,45 @@ +#include "qvalidatedlineedit.h" + +#include "guiconstants.h" + +QValidatedLineEdit::QValidatedLineEdit(QWidget *parent) : + QLineEdit(parent), valid(true) +{ + connect(this, SIGNAL(textChanged(QString)), this, SLOT(markValid())); +} + +void QValidatedLineEdit::setValid(bool valid) +{ + if(valid == this->valid) + { + return; + } + + if(valid) + { + setStyleSheet(""); + } + else + { + setStyleSheet(STYLE_INVALID); + } + this->valid = valid; +} + +void QValidatedLineEdit::focusInEvent(QFocusEvent *evt) +{ + // Clear invalid flag on focus + setValid(true); + QLineEdit::focusInEvent(evt); +} + +void QValidatedLineEdit::markValid() +{ + setValid(true); +} + +void QValidatedLineEdit::clear() +{ + setValid(true); + QLineEdit::clear(); +} diff --git a/src/qt/qvalidatedlineedit.h b/src/qt/qvalidatedlineedit.h new file mode 100644 index 0000000..66e26be --- /dev/null +++ b/src/qt/qvalidatedlineedit.h @@ -0,0 +1,29 @@ +#ifndef QVALIDATEDLINEEDIT_H +#define QVALIDATEDLINEEDIT_H + +#include + +/** Line edit that can be marked as "invalid" to show input validation feedback. When marked as invalid, + it will get a red background until it is focused. + */ +class QValidatedLineEdit : public QLineEdit +{ + Q_OBJECT +public: + explicit QValidatedLineEdit(QWidget *parent = 0); + void clear(); + +protected: + void focusInEvent(QFocusEvent *evt); + +private: + bool valid; + +public slots: + void setValid(bool valid); + +private slots: + void markValid(); +}; + +#endif // QVALIDATEDLINEEDIT_H diff --git a/src/qt/qvaluecombobox.cpp b/src/qt/qvaluecombobox.cpp new file mode 100644 index 0000000..d7ce3d0 --- /dev/null +++ b/src/qt/qvaluecombobox.cpp @@ -0,0 +1,27 @@ +#include "qvaluecombobox.h" + +QValueComboBox::QValueComboBox(QWidget *parent) : + QComboBox(parent), role(Qt::UserRole) +{ + connect(this, SIGNAL(currentIndexChanged(int)), this, SLOT(handleSelectionChanged(int))); +} + +QVariant QValueComboBox::value() const +{ + return itemData(currentIndex(), role); +} + +void QValueComboBox::setValue(const QVariant &value) +{ + setCurrentIndex(findData(value, role)); +} + +void QValueComboBox::setRole(int role) +{ + this->role = role; +} + +void QValueComboBox::handleSelectionChanged(int idx) +{ + emit valueChanged(); +} diff --git a/src/qt/qvaluecombobox.h b/src/qt/qvaluecombobox.h new file mode 100644 index 0000000..1a47bb6 --- /dev/null +++ b/src/qt/qvaluecombobox.h @@ -0,0 +1,33 @@ +#ifndef QVALUECOMBOBOX_H +#define QVALUECOMBOBOX_H + +#include +#include + +/* QComboBox that can be used with QDataWidgetMapper to select ordinal values from a model. */ +class QValueComboBox : public QComboBox +{ + Q_OBJECT + Q_PROPERTY(QVariant value READ value WRITE setValue NOTIFY valueChanged USER true) +public: + explicit QValueComboBox(QWidget *parent = 0); + + QVariant value() const; + void setValue(const QVariant &value); + + /** Specify model role to use as ordinal value (defaults to Qt::UserRole) */ + void setRole(int role); + +signals: + void valueChanged(); + +public slots: + +private: + int role; + +private slots: + void handleSelectionChanged(int idx); +}; + +#endif // QVALUECOMBOBOX_H diff --git a/src/qt/res/.!37041!icons.zip b/src/qt/res/.!37041!icons.zip new file mode 100644 index 0000000..2400e38 --- /dev/null +++ b/src/qt/res/.!37041!icons.zip @@ -0,0 +1 @@ +PK diff --git a/src/qt/res/.!37364!icons.zip b/src/qt/res/.!37364!icons.zip new file mode 100644 index 0000000..2400e38 --- /dev/null +++ b/src/qt/res/.!37364!icons.zip @@ -0,0 +1 @@ +PK diff --git a/src/qt/res/bitcoin-qt.rc b/src/qt/res/bitcoin-qt.rc new file mode 100644 index 0000000..1c39874 --- /dev/null +++ b/src/qt/res/bitcoin-qt.rc @@ -0,0 +1,37 @@ +IDI_ICON1 ICON DISCARDABLE "icons/triangles.ico" + +#include // needed for VERSIONINFO +#include "../../clientversion.h" // holds the needed client version information + +#define VER_PRODUCTVERSION CLIENT_VERSION_MAJOR,CLIENT_VERSION_MINOR,CLIENT_VERSION_REVISION,CLIENT_VERSION_BUILD +#define VER_PRODUCTVERSION_STR STRINGIZE(CLIENT_VERSION_MAJOR) "." STRINGIZE(CLIENT_VERSION_MINOR) "." STRINGIZE(CLIENT_VERSION_REVISION) "." STRINGIZE(CLIENT_VERSION_BUILD) +#define VER_FILEVERSION VER_PRODUCTVERSION +#define VER_FILEVERSION_STR VER_PRODUCTVERSION_STR + +VS_VERSION_INFO VERSIONINFO +FILEVERSION VER_FILEVERSION +PRODUCTVERSION VER_PRODUCTVERSION +FILEOS VOS_NT_WINDOWS32 +FILETYPE VFT_APP +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904E4" // U.S. English - multilingual (hex) + BEGIN + VALUE "CompanyName", "triangles" + VALUE "FileDescription", "triangles-qt (OSS GUI client for triangles)" + VALUE "FileVersion", VER_FILEVERSION_STR + VALUE "InternalName", "triangles-qt" + VALUE "LegalCopyright", "2009-2012 The Bitcoin developers, 2012-2013 The triangles & PPCoin developers" + VALUE "LegalTrademarks1", "Distributed under the MIT/X11 software license, see the accompanying file COPYING or http://www.opensource.org/licenses/mit-license.php." + VALUE "OriginalFilename", "triangles-qt.exe" + VALUE "ProductName", "triangles-qt" + VALUE "ProductVersion", VER_PRODUCTVERSION_STR + END + END + + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0, 1252 // language neutral - multilingual (decimal) + END +END diff --git a/src/qt/res/icons/add.png b/src/qt/res/icons/add.png new file mode 100644 index 0000000000000000000000000000000000000000..f98e2a8ca7386c19292423b94c97818052a38674 GIT binary patch literal 1279 zcmV-i5SR2M2sP1Q8DgD*PY4i$8=S_9=hi%Zn8a+)G%E|(Y(Ls{k>Jy-J+^gZRuz6 zDMVfr6%hp!3OZK*1J_>+Nw9kpW4RBBPTyNef0EVViE#Mz~k^Z z98Me_&xM=cKGS})@#W@g{hzADHB|u+7LOe`R65Lr`O%3-o?TQ_l|Y~v zDN4|w0p5`4rb{=aV!G*jO_P7$nhjOcFQQIlO(YQPX#BsUz1D7@~A*RS$Q3S?U8O{k< z1w-4S{3q*?=*W>Fz*NOYeLvjc{Q5Vn^jFYGArb_gf&f9K5FbGRR-Nj=4+`3%bG?6kRMTPBD))hq$kAJt;&u(6^0DryJy|T~E z95~ZDyw`I+vl*GqsN0Oh#%K`f(!IQXcJu4~V#17%<4FKPXeDi0NsC6@Ad557D8&WG zjjBOs0`QbiwxV^?4xMzKR@$Z+H_76RdQ@k}Z_gk<%PZMLYbGt)B|sNlZc-)u>1H!i}U!C!HsYvzZc_ z1z??=U4tQ#2y5)~lB>U8{bKFyjistF{{@~KDQfpwvA_TT002ovPDHLkV1nEmR^I>s literal 0 HcmV?d00001 diff --git a/src/qt/res/icons/address-book.png b/src/qt/res/icons/address-book.png new file mode 100644 index 0000000000000000000000000000000000000000..d41dbe6539f64829c004d0f7fc9bf0ba1aa4d7df GIT binary patch literal 1916 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 U3^ThEGXMYp07*qoM6N<$g34vUH2?qr literal 0 HcmV?d00001 diff --git a/src/qt/res/icons/clock2.png b/src/qt/res/icons/clock2.png new file mode 100644 index 0000000000000000000000000000000000000000..c1a6e99f7f28d66f4dd6901f4c09a2e4325ac3b7 GIT binary patch literal 944 zcmV;h15f;kP)Z$OUJg1324BT5lxs2GsJ|8 zhaDFZHJA{RCA%9hCR{x1qSx9(JrNEb)RP`GM$`nzB9zh05p{96Wei$2V6hhqM zk=e+S@HOq`BiczvkjOFI8s^{CRmgh07D%?AwHfjSAEa$U2hA^@pFh6{Ec!wSIg&|VJ)Fvo$}mRyKGK(1 zYuH#{C#Rc?B)W{aCPH=i<)P+mU&~vH5c^=#VpAW`bwqzVA;*FySD+hH4*&gw}dV?(FQ8mx=#*eLQy}_B?blfs#H>JFK-> zPhhN|6-Tr>A^Eo^u)^@;t!uR?YW(aKi^X`e5q=nL-7};4F=RHw&AZF2Y~Cl9l6%!E zp%AQXZSm8M>qNd!yiu_$kJ}f@<#NjdC=?3I*H*Vb()X7wo@3zX5rRV_v<3WDzQuN@ z&EXSy&b@yQHWux7ceg%WSXj8>oO3UoX?Aw@^k^Wzo_KZSxJ_r+^#Y7Fq@y~nvBk|l z*J>+Io?mz&+n3(B$IQ%3Z#tcx)>==dggs-7_Uj#0)><#^?(SZ#R4PrkPx=ps^~c_I S7%Wc!0000+gKKBb;;WWpZ*-`M!TtYdxf-J08ceYs99kwVscn=*ra8RJ?aDb`OLQ zqEspkv}Mz;p6bmXY0c$n&KBqk)(LlRvAVh8zWY7;dwt8DDwRrC-2+kW%Ee;w)L?Js z>;YNG_}Y^3EcMz3^~B=KJe{QC?dO-D{`Q~xm3U&}Eg{4w&N-(5N~O}k;A737b!w%O z`WAPLVSh&lH~+m3Jst-;7609-)8ScOIh15f-1w+AHZ}{)dO`?wpwRq7UrW&A=@_Lv zl;>fsWo3DZ_H0O3py_H25w5|{Wy6Vqs+_-_IZ^ub{5cr}!SEBk!B7&0+*)5JF$N1H z#t>FQ;@UkhRj_r^q(MG+pLP*5`pnLt=XoQ_7&9zwhE!_&d^^U0uqjwez0pAH7*YW) zLCJ_`4@Xp^n8SsXG;JA@N}A(QqKJ$|WSY>aMH`DwEn7QxDP34#;=MUO{9*xI#NArN zJD)db^XfD!Gpww0P1;IU*ER@Rvh2?XU>#V;3nxc-uInO6qDhSg5z*cj^TBHdztv!j z@l>^@FR4u9rJl$85k{kp0VlwLl^!aS(v&e^QxKY)w<8dmdrnflZ|4*+m*@({E3mS- zL}6bWel816;E-4hQp6w=Kr_1-VO>O_Yahm#d9}U0J@eNMbG^U6Fc1rg@tV+5;he!b zi^_uApK9Xs^1<^|Dj^GN zlCLiXtBafN^aI&GRO2qAqoXakTyDe|GnCEPV_L^Dtf#ZanE6Vj@>9874&5Hk07*qoM6N<$g2J7>Bme*a literal 0 HcmV?d00001 diff --git a/src/qt/res/icons/clock4.png b/src/qt/res/icons/clock4.png new file mode 100644 index 0000000000000000000000000000000000000000..ba036f47d33e7ac9a3db80ccdec293e0ee3be034 GIT binary patch literal 962 zcmV;z13mnSP)D(iwsmO+s?$ftr*sTFZ0xRGYjMF_~`(Ig8SE6t;MA*OkKU%t$p zd;jof4%Nvl9&cX7ZnT1xwRQgeruuVzjr)QinB|9{e*g~;5BIgV zC%?}p>ivvok&p)Q-Wt?~L$)dlEv*>%XtC?JTk&|M^5K9G;%jDR9{_?NXlrfrzdIp) z-^3f(2no5|aooH6H=LDdI_YEMpBVKyhYN3*gr@SBdwcIq0GNW!xGey!=Y!&E84876d!CPy4B=XYKwDR#w+w zh~OMx3?U3dsLBo?BCv>IT^X5U`^eT*aQ>aG4k_h1pNM*FrB+B0B3*k7YxP*xpt6^lBN^sTj#5_4w9W--5BUypGJ#D&*=ifMZBWxKe0FeLe|eG{|YNr;yE6 z@W~LNCQBe9>Bq4xS;6l%Hnl)F4Q&av=@4z5Ge{=)01*5X0kB}9v9PG%JdGXl5Jhg% z2QUe_2I2-REzINTXLiu_!aM*1v-#hJ0fYeyjj7uTRw!g2s|68F`WX@QEBwQ}eKExG zCc=#ygwaugOAy8<6s$D3J*)89&>mdE;QFCbzd zbPctC2whzTtgf!$S@n0e6eAe4u>1p||IOHY@N4kabokYEFPqJlil=I)dG}pxY;Hhn zf^~pageZ#8l)KP~q0xl2Ed;rJWO5QOkM0clzJHDrQ7O~C&v-UQp#*qA1Ljc?b}xly zvjw3f6k{;ZFkGPLRe>m$C>%F1COOQVuU|{%6u4Ld?3ZxaJQP2?J zMF9!0Goa_Jxm|@8{Nq5VyT@xhxxx+}IztI&}Y8LdP+}>~+HL zKN2J(-1|j9I*t2Pfty$NprBEi$(s5@cBxXS#LPJd#u%HJnE0UgjooWQ7wUX#MIzND zk<1gO#~V2Rxrf~I22vO-%w){+jb}cYot^v4IcJ|b)A;!KnPivxa^Rhvq3l46bniYa z6n54b9^dnD_v`HX_5*imZf@>p=bU}&jR%a5jwTa{#5p1wW`QmdX}=ZQMIu^iG#cMm etJTOIlKurBK+b`Ue8F7+0000)u014Kkn1^4&({_*ki{s#vI#oXNG@BRJ!JR2Jo2NM$z00II4 zG}hMN*7*4P)cN`R0Q>v<0P^zn02db$03#zD00M{!XvlJ)nWmpVe`UCO^$x?+r!OX* zIdkpghYz2@Hpt0IG4Swkdj9zFgZbC5Uku;A|72ieV`Gq#5(CQv1Q3&qjCioDtoX`b zzkcif{ri`JgM+==+S<^DmzNvpt>0ipKyS#t|MZjl>(}oLpFVzJ;N|6H(9ux>%K-!s z3mY5rH&<6%MPQ(Vf4!IgG^xblzj4+9&+XLuk21Q4^BnC74V{~3HWG~^jXLgw-0|Nj64_V)My>gw$P_xJb!1_=-V1MJ2C8Rd}x8TjQ701*dC^Y#Yx^6BZv@#xt9 z0R##E0*Em*w3Ok?moGpKKfO6QIqZ3Pxir3h{rN&jOwusSLBK@j)g%U~-}e|qfYyEE zWMz27$ouE+ZRX;yUw=&c{OvCTKmf6T{K3e`#K6kRvK1K0TR(mJ#`%wt>ATp!z2^Tf z-rT07^-+kIoeS(=?*9x7%1l34{{H9eyK8D>l|NF+q!{#cX#>&jV&(6RAq?rHyXAtH3#q^Jf+2i?Z#+LvA#KM3B z{AXZf`1O}*%8@e+Y`^|9^q9J_GBUjT!NBm~3j^by{|vgqzZoA3ayJ455KaTYQN+x^ z08Cqb`;IXD`T6}vpN;BYW(E#m;(h;{feDz%xS9S60R#|U17L;#y*6pr5e9~z&;Iv0 zTd^=Ru>WUx|B`{>$|L4W00BhM0C0K-TKbO>Xvi&2hI=o6)Cuu0u-|*ne*NtarW}9( Z0|4(~c&K0)VI}|o002ovPDHLkV1f~|8dU%Q literal 0 HcmV?d00001 diff --git a/src/qt/res/icons/connect0_16.png b/src/qt/res/icons/connect0_16.png new file mode 100644 index 0000000000000000000000000000000000000000..66f3ae4f86a864755c59d0622cfb1bec43b018d2 GIT binary patch literal 702 zcmV;v0zv(WP)9K!-r$RAa3cUz=h$kx*p%C;S)QeO+MyOGc6l=R-OQ@Re53~ES`+5kQCRIByFqiqf zna@0ewkVZK_lw2iTV2!L? zP6z=21VI4b_u)8B6QHW9>@6jIAmGw5EldilF1}iS65Lkm(kVL z)dUD3Mt630vX0|iI&%235CVgPgNR0>sMqUoT^B-#rUToyVOiFd;zF43`{10zbzOL# z_gA82S^qU30zA({KA%6RR4S&TC~zF-pksniTD!bZTCCAPVrdDLg@yCr^wd0+`hO{{Pp!2Due)I42&@-iUL`dJDMq_pa86L8DDZa3`|Ub zA06TQ+8TZbL4*_vg?ZO?M^#k?V=TP?O~%-DLdY>8@6;0cybb- zb2;&KZmviG;QjJ)^l3Jm;G8FH+wO5)_jPx7_hZ8_^2ua!(cItXrKzd;YyJIqzin-S z4GoF2TFv;W>(35w7&@TB#=yqVr2_~C7G9tW z8!WsBQ+WUeCY~Yb5~x&?CY39Kt426~pmN*DwYm2m1~MRJC_VEzAN`KbQCzb`!x zh@z-6i>L>KK~-xV02%Q0@bJ(A>fe5Ee|!6B+Gso%ty$gL`t)uxnE(bbX_|(;UT+G- zfK#v6L#31gJiwGnCC7`K%_lcDH(wUhDc_n+JzZb_I0K5&Xyld4i#^JhCtp66k;S~Wlp*f0!3W6Z*AB^v}m#k;6fOfAbW zN|7%v+M*~bMNwpqsR7n?UB_Bm1{MM1`+iBi+1R-IeSiNU!0r3@Tki*h yDewRgrBrJ?9t&^}Kq>WQd3o6Z9s!P0>hmAqc@oq2xll4QHqyuv1=lpU`&ZD@XMC2Bb z0Su6EE($m^zXMK0J`BTVv)QzPKG64l-#HiHd0u=Lxm&B%EZ_GN zzyOHq^?Ee1Lht>;i%z%m2!X5Di=VzU8jZQRxg+3oe}CW6TBm?9P^(s}mnIUlyT`AJ zH)mIh#TzTFAMIy5J39&B1Q;|LjdZ8e5ugg_>FMe01mHM`L65+UI2w%cJkJJ(KvXW5 zM`0KOSb!xWlPe4Y0}_LY8H5nWaS8~5?Y+G{1E_!RoyzL!)BeWBbBSZFEH8ho{9Xsq zAckQCySuw1zyqv8q2MZ|6yN|lkw{pMS1LWZwzTwe6a*ZUN^x)xL=2cQ!D&P~opym7 zU~;)!+8C4M?>lSPbzSGz;USmT)-X!ZOC||!k0A~LA&4NG&1QiJFs|#mTI;E^N+y*` zWt?FqqjO=1R*EQ}H-oSzBbfr=bUYNxveF`w1B`9kmN6y`vaDU$3T>l)mfja<7sjo9LGZyd=u#{4pe*n6I6nJ9G$GZRk002ov JPDHLkV1jPI6o&u+ literal 0 HcmV?d00001 diff --git a/src/qt/res/icons/connect3_16.png b/src/qt/res/icons/connect3_16.png new file mode 100644 index 0000000000000000000000000000000000000000..a211700785d4f811bd535432234fcb76acdf2f46 GIT binary patch literal 625 zcmV-%0*?KOP)2L+d?h)FCT*>tVx`haXp0VY(7~xtJ1Dq`;M_mp z;tz217jzMX;_RTfH-lITF(rf0q&34iNli&|PR{51z7BQ}GK4sxUAaqya4C{zVG|PnGWXvu3^! zMKPsx05T$oGCa?-ff10kTCHRXaJIMhve)lDLBow(x4(}2ZRWEP$b=x0NGXdz1{^h; z&ABOn-#>r7w6wg5%II``*HIbd5vZ6j(e!#f4Kx8&tJNw~8JveX$P`q{V3aY5CCC`1 z6yqQwiXs35Ftpajl!H;IKvZQHO;>h)(gH#c9UVaRd4o`(-WYXvGJoFt@< zg)j}!noJ2?*LC?HCQ1lV0;+&?9LE-K*49=!jmATO z<@NO+$Hk+{&);%Y02?dj!JYZsuK!|H15ela{_fi~A9w^9LWqOE9sC=h=ivQ^00000 LNkvXXu0mjfwnP^- literal 0 HcmV?d00001 diff --git a/src/qt/res/icons/connect4_16.png b/src/qt/res/icons/connect4_16.png new file mode 100644 index 0000000000000000000000000000000000000000..c1232f5682289555dc5b221c34fa27e3b6820ff0 GIT binary patch literal 673 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 RSZ9Jjnrb?#mC7j0{{UqMhiCu* literal 0 HcmV?d00001 diff --git a/src/qt/res/icons/edit.png b/src/qt/res/icons/edit.png new file mode 100644 index 0000000000000000000000000000000000000000..1d691451514079074d6c1a4b057d8c1406e5621d GIT binary patch literal 1627 zcmW+%dr(tn7XNZ@$OA4UJT&n|l2T1t=n}w+f@>}{izxDtIu&heQXak^5m-S%a+4?z z&GJyodneR!)v>J&)6P__ySX8t7(u9Y#-g?4(x6bbHGm+Hz!0nkxX z=H7N;AtE;=D-D2?D*+%30L(!jjsfs@IRL+_0Z3>9KydWDsyi6~zaKX%leU*U%~@YS zjcHl2*1nI6|CCk^M#f|UfK)M@#1P~fw76&b34})#&<&l_{V+bfd|o@+`2aqMUvUDj z_5wy1^DSX@=Ipo#wGCNt&npEVqPh1I*I~bQvYn={56)?eKcYSFvoQb52|!Gc5?5sv ze>N~c7Y%7ese2s$ac~E%eQtBXq0k>7+`XKJulh#dtD3*imir&BJ`?6>|)VSXZ+D=tF5br%g49AeRWrRP|)2om~lD&Fm;XkjyYCd=J0#) zPxlx1G{4`?RqOMETRSFY+Xk13iIf5$TS|YjlO!eZqK=9jm{j1spi49>41ezKBwy^b ziz8M(6t8;suIojh?1<3FZT97ex_l-3O5@j<@jU)Yk!#?Tp%oxB(N?&>l(mL?qC%^M zaq`%hki)BRQ12uZwLx<8m*6*ADnM<#_UL{QJ1z`ucO{KZ{5Qf zKH5f#sr;L#pwvKEqRmZozl*o@O)qS&KJKd~c!YqaaJig*istoz_vpaaZ^{4Ex?(-_ zR4sM&vjkKc7bh=8#yOcMT%u8a@&^(zuRtOfI>&%9Th=>6Rd5BXCWHRU4;0FD_nPG0;b}z3< z4<}G2e>dBM+^(OqhOqYRUsp8(b?G_GVFiLki=OZ0Pdq?&WEzdVj@1BTi(7S+yHuSoKt8`Rsna1N1iQ||Q#@>PXg%f-tC5yzlZhJa zK8IbRPhr|}xMy~LI??vVq!7}`VecE!rTXgX*6rEKOFL=nyytRz*_r_EMb45W>$D)7&)C>fe=P@unY5OL8C*sB@@Khcwi)4}-#d|!Zx_)9JDPkbImZt$PE&*>h0%pY zjcmP;D!Jm>OY8!@pOaB+>u1fC+={KZUx?-78_ Me@j>1_&}}yALD7)0RR91 literal 0 HcmV?d00001 diff --git a/src/qt/res/icons/editcopy.png b/src/qt/res/icons/editcopy.png new file mode 100644 index 0000000000000000000000000000000000000000..f882aa2ad8a378c229aecf7c2651a42a2f8d25b8 GIT binary patch literal 879 zcmV-#1CacQP)`L67Pgx?s>x;iesW>}d@Y9b!$flFK zd-Zkk>eAOO7q2e;&6~gd=U;yHZ3qZ=y-cN&e=KU>SIztBbb7fB5n)vW z34xep#4PL7AAfmtu(LCLy{U*n0V0Bk5JW%(X|>$l-C^(ZM||`3S5F`BKKgSL5%ErS znV`uLAZ8h=iL>(sXXl+}U)0YN;N?~YG?54aO$mVSzxx(b=j!T;5C7%>{Pz1F{4Wvc zL_>ru6U-pbbIMYy`cUo7>FJBb(eq6bL#z@RECX>lV*oNNpScl%+DT;!!RLrXV4w;a}Q2h=85vk4U_rf;zxgMY> z5=Bv<>b21fJRk(j6@n9}1l{gC2HRc=QmLer>J@=`CBn=I!Evi64Nj1(6aKN-_HKcy zwsOEyh>%vdnnK*A7hCAZc2IyO!|MUsgS9({a1-tuT|NriK@WJJCxR2KGG$Xws3vU* zakD{eO)8?oE#Yy9f|X}E){UGhX2aNCdnmhw=aK+31NUaN?v5Ls)eoH+eb|Blf?JoA zUIESOMZkS28fI2MJ6EbE6P9H;3fmu6-X^Rql)JRs?jg z?MY&HVY|^5Yy;bk1Z)di0J+ZB_b4ZuPVVk6Ah-k0b!!>2u`=#sX6F{*6jNk)@_~vx7?lsl>Q0C|FG!;2p|?1g030pJ(1Q6T--+=)H*9-*m(hLmC=CPBWtKbg!#_$8^sb9Yt z7@?M9&F26Cgc1VC4xkA9{RfH@hM&LwG5r4XAFon?0740Ye?%lUqQFOBx&fN?SWf?f>l?CkIa333F;F@Ht>0kic#27Q@-3{02rge+RLnKdrXHxU#$Pz(nE z0mOs|0f+;L#s7dw9Ar5U4>uU|@^Ulq@$oS5^Yegd2<8UW6%6X?s{ZrlZ3JZ}J|JdB zb^t&C!5#1e90k9L#{Yoj#Q*<zgHg^ z{ylvQp<(#lCx(CDeiD}>fl&ae=|PS#Fi>WYmX-?W?Og$P1V8|>pcW#CJoEoE(1Opn zE&0ntTomx~ax!e%bQ~NKAjg1cAt8|fpi~7YGXVq;3${}1|3_e!_=-PA{A2!0R1_E) zse#kMj~~C`>TlnE2BP?Z_!U3^p*r96Bh!ktgJu>{AOTbVF71R zq@)M3n+YI*P#geCZ2w<>Wgy1nzhDOtR`>fiB&0wM9wsJ4p#=i~0fg#+k3h?R6IU4h z`|}sCJO2RXfByUfwh&=C1KbfX01!Z^QSjj_BtH_9x>-;|0A%Q|Uw?r3FW7RJPeD0= ziHQ-(a?}6@2q3g5AigL@4gr|O2um@2jO++xhXVu<)?7f81OEPjTMo)vn3gi&bOdq; z00a<<13rBG%fQd|kGLrK{RbS>kQOy&FynIsvI77Dhy~Gx_1#Pm2A3^067oFkA!03d+i4%mI; z{^0@X4m5=wB`Xygz82q0ujK&k2jwEfP8UQwX~9v;E>AcL@5 zhTjp$Apj6S=)MG{s;^K?por!80W*kHM<6=@Ab^<2ZFhny807u}$TCQDAkz>_(Z!LY z03d)^$ZmN9tJcexA2U37@CM!%M8=@9;UCbum}38d9iEqPa{vMi0Q+WtY{NEovH$=8 M07*qoM6N<$f=oDrEdT%j literal 0 HcmV?d00001 diff --git a/src/qt/res/icons/export.png b/src/qt/res/icons/export.png new file mode 100644 index 0000000000000000000000000000000000000000..1df9c2398d3b579d329792fef85b3cfc5a3b8340 GIT binary patch literal 2148 zcmV-q2%GnbP)c$192;$bmO>dVP_?XM?aGR@KQ?JorEZ<7 zX%f@4uBx_n6BLy)=+;sNFz82wOd!F?mgN5>OK#9jevTuNo=e_QTJsC(Q`tG(W7GTA3hbQTVmpN4Gww4 z)mzQtT5GfD?skgMSVVjyEgn%-h=?pid=cl`RI%^%WAVM-5bpXCe+iTt0mCG01Aupw zlVi>xbesoE7ON_JG&BuyyQ~HIESOcz{F&8En^sC%mIYOSqJa<~fT#kCs|<`4h0Gk0b4vUZ8lmkVe)1yM7P%#6_9)kAQS-f03<0h%5{Un2^HWT;WcDh^@d!m>MYV(| zSk8a0q%-~L>bz}f?9l*eG6P5i28a37+ZBe+i(t;+(dk|q{_DQW`IH1}I$Tb`$19`6 z;FxScj_`#1ioF z2*sdw2BenN@$budEZkBtbz=&Sx5lMtHCA@bOMN*FG851V29(5x(E$&~`+LIB-wdVg)dBRLgQ$hNnIp8f zIq*e5l9D}F^of_XBs7_Q@;(xQC+mwic2#RXgbMVRx)^5z4xe}hby$S|MWD<=B zpbU8VXLtK3jM~AN&YD@h9RI?Fq8pXtp(cQLi=+t>Yd8e;k6Ss?QjapffM+WV`wd_s zX&|woPX>S}9KCi84Q~_38Pv@h#M#k_!Hc82~yHq8nzytYE@z8qSzrKVG8!{Kv z!Ul224Coh9V!dW>kuFDi?I6oc$&XN(-pSd^0gR@J+1~9wIjE8WOyL|Ly$VKX?P%661baGGWLQ^|ljmnnRx2Nz@bbcze4K7UnNQ3koFy(@j4VncM4Pt(X48@}l!u=2#gy;x_BM?*xxdn&c zl>@JKi`p?E+Qus|26O?{x&b3Nx-Kh?V_mJQvlp#{wA~=PDKD`A5-7oV3`3|J|f|?2FH71}*ARmH#2?}N;pMop}hB72t{zDuGi6Vp; z*sOoQ8Ke~T8Duq#8UFwMgOTL`0&qnJNdSN#2-Ga6|36rhED|7bcOl0=`Q_o}VI6Wd+pB9(8B07A<3e@GgD6;jMt%3Xi}!bpU$-~=T?Mn*J8FhW8CB>ESUY2b$ZgQf3(&}<4$ zsEpt!fTa-@EDit&AdED?0L=v~u)K!_fKoFo3o=0yBsdX5qXsPYAL2@o17HOtHsb&S z2qO)^asd-C!oGg_!SL(fFJSQf162$RpnBmytXKwSe300`e-I3k`wR3cSS={k1NqFr zqL`JHg#lD(#W#n3o}6;g1={6~ZsObx_Q;0g(xRsQ^E zX7~wAI7}?qLjWLvFdP61LQtGN`~=htOlhCL154E3h};3A|3cFWm=7%lL4^`1de~VJ zYW_j%4PH)22%`gl0K%FGK?No=Q0B$`-wfRE-ZRLE0v+)eQQ09^zlbWBfdLrW4EJ9! zF&w|j&cH9k%phsN$-oFqOMm|0PJ{pfgpmedK?-s`-*<+iXMo23f)+r~90996(E&gJv7qHLuutGY4CMU;`ux{F7KXPUe=__6 zN^r6=GjMRQVa*+^z@P(#o}eHD13w=VymEp?9k!wvAb^f;_k9AEaK9M7f5*h%zWoB{1U_CS25xR9c>4jCNU?#W^@rU8Z4=mvcDhGh_{J;=k=VoMh4NcI0 zp^23dixz+YV!;&!;2IAY1;2qI@bf3o$3G!e;O{>W{?DIGSRDXzARiAC11m5J{(WPF zG*qB1Dr_MD5J1@51OFhY1C(&S{rJW3<^wZ>x7jxaJ%vvUYLb5$-o9rB=XrGS8`xj~ zrvW}-9l#091>Zm=A|t$>z?KF80tnRsOpGj`77ftTz}7H?{_^<;!`pWZ4B83|3|^aL$)Sv_DA>hJ$QzZp2bKLZx6pmLv)U@r$4 z*bG1Zu`~SRkpLzaU=I2VZNjlKFh9Qj;^E~JkIVo6FWrf(2OxkL2fA+v5I_UoHv|Zv j0e1jE01dbU00ImEejxC)$7P#?00000NkvXXu0mjfTPNqK literal 0 HcmV?d00001 diff --git a/src/qt/res/icons/history.png b/src/qt/res/icons/history.png new file mode 100644 index 0000000000000000000000000000000000000000..10ac0e159228d08a8b4425dec4559f19583db936 GIT binary patch literal 1432 zcmV;J1!ww+P)bj12TuVZIRrvt zU~@4+3O=L3C$}PPO`zIYbD9h|N+>uF3B=$OgGbx%?Kx?RdrboL zYL7xzYeW4OXf3JT&hZ<7yMF`l4vm-E6oc#Fm}StT&4GCTz_p%L4M5t1F;YhiNQo>L z`1q4wuzGhDkmdfCDefuQ2-qp_l>*SJf{jz7E@lKFguyY#2Ea$f#lhkP4(lzi;1s{Vm=< z{ecV0iEQ6KkAnx_M4&5IuHxj$Q!cS}5-6gg)9GOE-j^)D2;+fiq#CS%;0gqH6O$9z zv*!gDfUB{2^Ck?^`1m+>?b;2c*h%T+ELdvRv#f`yscCM5BW(n?BPJjv$cTOdTeeIy zuSb)UE$rXF5C4X=X6BZeJcEEAQz-^pAbH-acmS17%B6Qb_Py3VsP?vFw~s(%P_GR6 z3II^aUvkXz!% zkrVV|SOQ@vOQlj_j%1K$ImiQ2RT9*yl@jWSiV2XmlGeUYyFD(Ia_GPRMg;#bT5YFj z-&;kG2i0?Y*XI85pZ2qFLf={X{N<=XAfi`WbBV!Y zKTv}ert84&6An)`#;^abfN(3R(Irr0_(EA``TFOhIbPX<9vkex_cfFGRJ|xq9;zL@ zyvpaw{O)e4Xywl||4%i?zKPRH@&e|Oj|fPqrriWZ;<+`?jz1AxVA^ndc>y;_V}-Qz z^o?Fbe?^aDeWgkHEn8(@@plaWOHonr!#c$}kNKvUEuafh3N0=#U%6%CC(Aa(pcnAj z%VP_8K+gS;ZO;_vx4#@MUFFrhxg~KQp;DMC^^#rHp#%HXL*F_lJKho2ky!##3a6Js zc@L`lAKNyb!6={rX|v(>-qp#1#@p%u3BJe)~u8+fLFLZR!a6&fD zXrdoTn-QpJ9{lGS5M1s1UEtW_2RvJ|S0ur(;eNnv!=*5g3-0Na599!OVEEzM?-}`H zf<2d%mYY~-fjct-aYX_FLIMOx074*P?}b2y#L4#f&Z5_X>%LT=X1j6(1RyDa%OxSp zHk=$_0gwrVfkn_>iFLW1Bd3*-Q$C0raVVRsQytZLz(j+oLjB5E%mX0u&YnQNjy>+*#o1eIfKTK;uCo@5R_(?`-cu zpN2O9rY(@#V`Hhx*Vcb7x~KG+F_}yl834Twa!P_o%L;%z;C@>mAIvaZe*+r-K;L_U zifVWNTdG!Nr~WQ>I8uUZ^4C{yiSA$Xg)s-y@P5!QLe8Vp@CWQm7KE-VkX{7-`{3#? zFfTW8`K*)j3sT$Bq*`f0CD5JnVVah z3nUu*aCuu${6~piO7Qk^@7=u}dTj@K74R-_3lJ#@SohMtW5edi-nCmJ5Q3rGK&wRd z>JStxgsws8839*2(ME%+-vqV1T-~)e+vN2c-_WlHlGPJfl|UU3P5C(%0)!>Ku<5fS z`!;PImC1m?Zg6zLeWd}&2}5TOk@qLL@opNqSvrT$`i9Hf;-~I!mZJGirSM!laoxIi z+phsyY7L1E*EHoDn?F6WXVcSD@O0?!0B7$Me5nkvIJERI-UNpZrcb_cU2VvAD_Z?T ztT~COYSn3O)%6fy0)zIKlmvtT%amVu{E5->%})*^f-uwto&gB24nrbI+nWX-Ty^Ug z+m(q|Z^Wv{h5lBnO1pi^0l)wz{;jT9*X12$TSi|lv*G=n;2o0)uM0sS1DbpJQ=LD) z`%I!HV#XSDVg1>z>G*%#6`Q8~#Wfqp4wOAL1^2^1C!|Fov`B(T3_8Y1{#D`jh;(XA=jzbXoK7gPp5q#K*dQ<1hX*aj-_{^?5@?=d%yveTR=$y_4 z4yOpnE{mZlcmSE;BOw@z^OyQGb{tf$bWg_XRbk#XF;H%=>J3;@a?wz;Pf5ShJetVPJ6H1%wb9aD)GH{0)7D V&>E0bEnWZs002ovPDHLkV1iUoI3EB2 literal 0 HcmV?d00001 diff --git a/src/qt/res/icons/lock_closed.png b/src/qt/res/icons/lock_closed.png new file mode 100644 index 0000000000000000000000000000000000000000..c566510c408b5ece254fdc528a2326a50f038ba3 GIT binary patch literal 1679 zcmV;A25|X_P)qkbu`{)JGFvyd=g4VR z#$Z`CW{WLbUTF}}QfRFZ1i@{$-n!khOKX6Kx<`|r7D!w1Wjt<2eRDq z*WSFKuWyOvy58pP+jk!%{=NU%0i`7C?(Tef!Ggu@!^6L0|NifPEf&u|9EsQmY4-rk zd5hhnqh|+q?)>KCSS-4#ukVJ~(9rPfBO`yTr{7#$CK^0qTo}9S0D-SsxbXV>YPA4E zL&s#XSbUPs{-7b&;L|YSIPu|1rTplD0|zI3U!lK$=~~;iH*&LH9ZcBG1=y+v2@6^q z>&?Q6jp=k-g3cSc+}NOPTVDYhidl&2GGeGeSt$@1qS5G2qocVG&z>DaXJ?1VWHOty zMo7+SzAQBtFc9oQlDiOg3`B-RB5|W>seC?fYGIHI3raYM=_>lmgIH1Bf%)DMfJceQ zra9^hYDwuhF{IP!TZFJI0uagK+Np1w3y7;pvV@5Rm7rc3Y$DNt>lS?uqo)zG#|%w3tuW}RZOq*(Fve!;a@s|NnW`1yC9{yg{5WgVE)nSJA~ z$2avknG_HNpj=29KyYSh)<2*_qB<`Jv?54?CNR(knDQu9LWnGf=)H-OAp?dT@9*jb zaCrf#Y`i1WmH@KL09gf81(u>wmjPLueuj1d5OjfH=72!slm&PZfB~0wyaF=aNYBZn zn!k#r4zyba3y4rn3kXM9F=QdRDgq<>aQyHXJgKn!h9tziZa@*aN7SrgQJ|KDl1er& zLdF1910<0IhL8{n3BN}T^3->D?$r^zy*u3e1N~LJ`+OORxpOJUZmf140708syJ;JS zA&r13KpERhG!o1R65@{H+po`H3z26`%@98Q5!kwo1ePYkyr2=rK@HYQ8-@;q0=$ck zfWW=!?EEYlsNtI*f>NxD(EC`>Gf=bO8=R ztZ4`CUdaGSM1Bbf$}><2*92M=paMg9DRg}?<|DnL9Z%d2r0W76T?6#=fx-`6(=(v} z<+per&e3kR=88q z_-+Z0prsn%q1Ezq_-4}*V6yJ3rrwJIT@GdqX%MnB2;fAen%6)`Vj0EqqRQoUu%=gB zLSt|aXv=J*6$c1H08R{$0#_uA0AHA{YA%2=CYU3DB)@_JG~i9&wnb9`)k>x47P1{t ze!UTVMS=;9pqxUbG*oLUU_6(9@r$<(y%3AX&5cO?!;;WwJ;+t=d%yXkXU5;0^-A`C Z#$Rq#3pK@&%5(q#002ovPDHLkV1gZn3Dp1q literal 0 HcmV?d00001 diff --git a/src/qt/res/icons/lock_open.png b/src/qt/res/icons/lock_open.png new file mode 100644 index 0000000000000000000000000000000000000000..c98ca8663bf94b299530410074a7607c59d9c41c GIT binary patch literal 1644 zcmV-y29x=TP)QsV-Fw189^)Jjx+s%VAOhdxw& zLY3MF=v$?#m8z;d@KOOq&?v2xQZ5O?5Rw2vNg$4$IG6P;_Iht~Ip^!xv+Bxgr@Kgz z`j>t>J7+a>{@?$bGc!s=fSL{+`Y~(E5(EKJ6n0u`p6KXk-ybuelyc_hZ=9c*nR+V> z{ns*?^c8C(Kv+wM4pFyCFgP`J{mG+8 zkN))Ik3aZzJol2;G^6GXR4V?{!^6A&bnxJ#*+L;=cD8`;&*36uI0r&Yu0OI6pr#Dq>7~ z``3nc?b?0Y_U+p^aNyejzj^i5mp@IX)Bk8-qHzMo7^kzd{l&d|_qAQVJjbO=V|?_{ zd+!zs3(tv|bH-Sk%U$iAoE&@Mp@+WnL@Kq5k&#E-lP6ESFg|{MG?nshfN(QuR!OZO zHt^Ws;J`QY`GBdZ94Ag3|G@VvkEc@UQ;y@7UDx$J&%01AFCIE_=~ov?Nr}jU*81Z3_!oc6<#M#Nv~tHCTX%zOR)9qj;xxVoz8;KX ztgs;*V+!FA%AU;F{hLzxLdnO`uABlE zp{7;uf9_ZOW8k^Aj*M%K1=Pyzsgh$^F`tY|fmQ}9f;ECt3P&qMJ5-7lPQP>J zr60XK@y!2BV8iCF9}FLSz$M!SCIAUzqLrhKKwCgS0b2avs&D@xp zKiIGZT4BWxP;I@SOJE9M%Q3~80TqFnhT=Hb3Z&O1$rLn{Jy>nO=m067O zlgdp6qy+fO^9v_NdFuHRqd8E(U*8USD?LfykOq?mq~1VM2&&0#X#AK$l_E$1Y_%1^ z6#qJw=kpxgNy5}3yz#byQa(8+s%NQ~GJ>LU0;pO7HmF8lZGj4we|M)f8!@b_)?|PU z86YYr_lMLc5GL)E)+Q6M0YpjlHA=~xqu9N-jUV0z8NdUc?1uxpRgzp-gs4Y z*Re!EG3mRMYuFenIK8dx>xcC~D=^##Ew=-X1!dNN7~7-)0ki@FkR^P;uN|wHtBZ`D zgm$0{IDG~rr@%`?CdR8Hqrr7Rq=`rIe{EHOaA~ZeeF)1eoGvkW0XhK%%;sR?l(6M) z7d#DCSf!NP{3lsrAV^R?*lGe!%=IFYi+Fk;IBsGfG>|O`%*Jd}-fCX6q zpw@y4m;hQ89pCL_IKxU+fNVAD`n8m*wxAgUqLT&9B@hn~&@o~G4V@Y2QmiS<+VLwL zlL9NvBp^w@(hiuadzNr$D1Ebe4b}l=nn?g~G-Nz54!1;FL*#-)jSVQJ9F=vT&AEjJ z0AHiEavB;amr8kmuA|%2JCKN5BIO8Cv5ivUY^9-r>D=ru-}wE>Uu0TZ)`_*2HKh=m qmr_cH!9;lN%JlC5R(+EFKlLAsuOH%9yfi)l00007I*iP@AtiR z>)e{^nXZ1GnXc-Yny#*yukY04u`$Rn006*NRFL`bZ^Zjg&`|#M)E6%%0D!<@BQ5>T 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 J6;j4Q{{zW&Wn};W literal 0 HcmV?d00001 diff --git a/src/qt/res/icons/mining_active.png b/src/qt/res/icons/mining_active.png new file mode 100644 index 0000000000000000000000000000000000000000..e8fbccf8324b59eafba6d5ede64ce5549fff2113 GIT binary patch literal 10027 zcmb7qWl)?=u7I*iP@AtiR z>)e{^nXZ1GnXc-Yny#*yukY04u`$Rn006*NRFL`bZ^Zjg&`|#M)E6%%0D!<@BQ5>T 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 J6;j4Q{{zW&Wn};W literal 0 HcmV?d00001 diff --git a/src/qt/res/icons/mining_inactive.png b/src/qt/res/icons/mining_inactive.png new file mode 100644 index 0000000000000000000000000000000000000000..a7afe66ff38f84fe6a1b1f50f393be21447f0272 GIT binary patch literal 665 zcmV;K0%rY*P)z>&J!wNjP*7-ZbZ>KLZ*U+{L=&7z9SURYx{kZJB-{O_mG`h>jmecB4@T2*N<|i_a$n zz~hQtb}Iahj2~$Oya9!-ihU3{;CN^v1L6v>bhFh4aSK?z#2*05OZ*kE^p0Bs@deEE zCfu8FqmB$fDU3$C-`g{?u%6$Lb~p5t+#bb74Psdf{7^@s?iketl1~6E#%|S-wMwa& z-zpYY3u}3~RPP6>qorGQWJ8C${e88}zte2BWn%9x0uXce;}%}R<_AojjhlB4H>WWF zJZ`xQm_32(JO4l*{!9x2d;^-bQosDY+=~DJ03c&XQcVB=dL;k=fP(-4`Tqa_faw4L zbuj<{>RI+y?e7jI9=9K!$r0M@VxK|v5j&-0nG1c?Ew5Ci)V>kuOb z1`*hj0#w}2CH0oviN z)T;6;z=U7_z(=}f0HDW-%4~74A=)w;p@XhY~egAs=~82frH5RB!Qog;=EMi zE1HUUO~e*rv$$4YO-F09WN;}wb_Tks*8ADK={>^lHgOh%H+>huIfHZtI|Xy~T83QQ zor@eP|wVaf9yE`ZR2au6&7ZP00000NkvXXu0mjfp6C`S literal 0 HcmV?d00001 diff --git a/src/qt/res/icons/notsynced.png b/src/qt/res/icons/notsynced.png new file mode 100644 index 0000000000000000000000000000000000000000..c9e71184c5c0641bc14763cc14ae899c98363eb6 GIT binary patch literal 1013 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 JR;^-<{y(0T(|P~^ literal 0 HcmV?d00001 diff --git a/src/qt/res/icons/qrcode.png b/src/qt/res/icons/qrcode.png new file mode 100644 index 0000000000000000000000000000000000000000..a8d97174b39197ce4f457640f948212edf109451 GIT binary patch literal 237 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0P3?wHke>@jRF%}28J29*~C-V}>VGHmHasB`Q zKad%E=yDxMI?3DJg`tC0)&t1lEbxddW?Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2ipf2 z5ds4xdmmE(00;9)L_t(o!=0CVY*Y6Y$3H(i_H}HW*ugjtoMN0fkkAGaN=wt1TgIT} zQJ__&YSq+Dl_qVp>bhx@)=B#Vgt}>(s!}v2S8QXoJmX#xpx zLdc6GcKr6ezy0AGW>Pz&J<`$D)jhx8_j}IoJbo8uk<*Vqbtk|viwoKr3VqmLTGnV?(RBXwJu5$62fQzCAN(Bwm1e1w)>n5LEaFl`P1|1jHUxeI zjgw|e`}|ECrL%Eq;C(p0LBi47AaO)MsYK~b5VCnZ^Bjxnox`dKje~8=?GRW4jWKBV zZF)jlH7PvL{t$ab`NM|<$5%`EXciJj1=u7?1VRg*d)`&)^@}ABJ|vvWnjKLHje%|H zj5W7x=YvKkwEuF;GxEvh_lUHb!JuiFD$4ofcfTe%JQQ3b2^(~!5`~cev5hXjzg{Gg36SC@O0m_(b4T8jZ(lq=0aPzG7Dq3s z@hky5G(GBAc>39mkIA)}v`EFGw|FN3Ba&i|hqk@DnYu9+T(1$>tA96vl7>)2V71F% z?h&zM@*Bq^0jt%@%U_<7r#d?)P7(JyAuIrXcJG=)Yd1Zy_VETEV{iN!H8MH#bo7Lg z*yg(UqU{)CHztBlNdoOAEN9d7HQv+W@)z4hB$djd51Sg|LQ!s zLjY`^Uw>c!@U>m4%hB{*472{=3}%#wwqt ziOEzdFL9*AfFv>3EnCi<6n?Y4wQNr5whxB7&)u~4K+6cc;d3~fjyEi2vZFmqB2Oqy z0?K@KWPbiKiNi;v^5H=-o=#^O=CenVa#zWfJzXM`PVFy-9iwpe8&yyQEqB09f2p(i zEzbf*zdDPG$mbIlvqDwi`^3(l;rd{I!O|>}5?L`{K0P`jrqZd_KG+7FdjR+(U%VDV zOF8VUu-Th;Ih=G4^pP&GxebT|T7mBhU@e;`Uk*=*SSH;%1l#+dJ=exKbCDH7C2+x# zPBne5sg>*9m0XWZk_0k9TGtfWVovALl)kaW>5{L8Cj@GyH3r+hf^!}qJR5-s;DwL{ zE|}A)rpr=RKIn3DBN8SJsJd#ps(Dla<~Ut)cX&bwHPaf0?I++IGr;o_00;rK5VFE~ zdn(zinoX4}YZeh7zD`6>EUkb#0cV+;GYt=Af!Yl4lEYhv z<4>EOY8z(-YMU)VV7-ACEB@2?u`zfjU5e8^LjaX?=W#6+rzbKM+zNr$ffsYj@SuGTM^h!GW`%^5YYx72}g&y5jY{ocA`&42$#gW;W4 zF>tN_rniH@ny8G>(pl)KmnE?!BUWZv&il4YK#z z6%mUjT2;ZeCXI8N1=>^GR|LCk4o8!>)WvX5H}RY%mC}2J&Eq99K13`Q??}7c­ zZW90>+H58nk8Vh5{I$BgysS7D7g{8YSr5M*m{V6T2d?#sSUkQzBiVkJmhJ5TXAId< zZW6ps{r`4bQ=&|Mp`Zx@n!#9r_^fw zGFn?FJLgzsn}G`-L*T#+@LOKiNzxMD6Y!J7$j}XS>rdsB+aa{Hx?hDIewFs_qQV4f zHKc&g1iYX|Cr^(#?Zg)@KqliI0=5Fd&4uqT|C2T_T~WlAkqu9b4>c~?*H@JFyr<~) z{tdf}AY|sgkyVeL9=iYjj;{>_PUOGY6_#ETrokl*8wP8* p%`*09m8&4S`0mmPT>L*a{{;|vTY-!e0lxqM002ovPDHLkV1kdY`8xmr literal 0 HcmV?d00001 diff --git a/src/qt/res/icons/receive.png b/src/qt/res/icons/receive.png new file mode 100644 index 0000000000000000000000000000000000000000..53ad1d1565e74c0f4895b7fbf525dbd58bb663d2 GIT binary patch literal 1437 zcmV;O1!DS%P)h#JsQc@Ozh*@G;=JEp}Bos3GVxeZGX-HzRW}%^EYN8p9 zghenj0~bj8M`^8<&hJf0O*1vWXmd_ByUYmkbj-_~6Z*&BJr9TXa^ClO?(_S- z@A+M(wZ{J$2I0Pd|23>z2kenAktGI0V-vU>1i&Exn!vKGX&J3B*mMB3xJ~H&vpNXq zI?`h7z@oh2%innn!GK9Rv?l=CySxDy11!_PvZ}_s`n?w?Az;>a$ARo2G>e99Oeq~m z1PnJrcZ4P|3)S0BqMj=azll!4*j)%<&`N1sOFGC8+Sqko<4RJ45up?koM1s=WFgQu z&j*JqcTVSuW8HP2^L$05n~xhfa*4rG9NbYzCI!NVz>vu{VoYbB4D?I@aYHEu8w{qF zFiC(`4lFHT5|lRFdSK95$a^3_-?+QBbI7y=h+H^=Kx0!t3!4OygwEtW79eiyIYk75 zOCoh>;F5bVC6w+^H!?eUb^*DNYAB?(Zu!wkII@ID-5e+d5|GJ##(v@6d75BLNGaVE z386r9iU}hC1UtB48OH%MXAz()Bfb1D+5qXedC~}>PJ^X%g%|7iT{7x<7&d1=WF1<=$ku;r)I61K4_ zy8wgz=A`86x0lsb?D*QOpKilHKkQwW*J0S$(mQ4Rk^-%Uj^&c&3 zzCDIuZVskAoQpZ*qqr7NyFz$|{7MopKh+m=Cl?_~wI2H68V63rcJ)uDh z_{{n5uGo!@+s`5r4dK->Q7o7ob93KLJ7UJf{wSX|0I`A)4xPD**B9?Z(h*Bx8Jq7- zN8~fAMOyZrRZ;gT|8TVN!uVp8jV-`{-j-XGrNbiV+b4uQf3{)9qTkWdnp#U$zXTe% zHv%-lZ>~wCq;K|;ou6DyJc?H)4Zt%aE$_ItOzdcA!R)2G(cBcTq`WVHrq3M&(^_}x zin9hIaP=GPx#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2ipe_ z3ndRC4ewL{00c-$L_t(o!?l;oZyZGshrjCXnb{p@AHhOFh(km`+z5&kaX{q6Kaf9z z1Ls7DBNECXaNz{v0A~bek}DyJ0up&3L=r_750Tge<7e#c?kWzmUXQUMHp;d%>fTaM z*H^#luIUvsW52EXtN;xa5xGAfdX%y)wLB?-df-Hnqj{ai%$cmkDcbs@iUaJ zL@|_1B9llYNn|pY=Dud|?hH%stUXx(1WwGJpd%fUB@&IpL?T%tOEW(D)KL!7_6=Zw znljSS*twF3lRnuPN7Hlw1jw36+C<-0Ad*mW)2mJg0BZoY705fJ-?C-P(*h8(W}?Pj zdq72r#0Ee!V$(>0f@&t_xWoCRA1je_8Yk?D0|+T^E1;5zTS~|_M7G@Q*r_OxGck`^ z(T`8SmPN*=-~a&fVcC7D>h(T)_SEaIq6*r)Z8jdOVwO-<35WWIY6XDWWRBVPJTn{J zxpeJEFS?<46cAAq-#8ps-Yl}dD7+cexpS|5@cya8FTQ}PVlkm9VWw!xSk92rq$fp4 zU5)0a&^AEq`6PiUSYdu30+-f;j0U*UBA&p*>co|a4j3soRpBwEXRoDv@7bJs*E9YtU$_aK3HJ!@;5A9 zzk!c&N961QktOc1DGAN;#mw^UJ1ktj%KF{gI1JyCSN{Wo zNjh2zBp`2YHaq`cqPCoPwD6F{pKf#i%2h^xJj4MWPauQXjvR+^DN6rX?X+)>ytb$MW3Itj^7`^2@KpwYA-!ClRo{A-4K9L=-4m5DJ7W!Ve#R z!rjlmAapud&aBVRKem8q<82p&dkjRL*osC069qh*i;HY>u(lUO7WT}4+GB5Mvj_ae zW!0Apkskl6wd<}cfLIE611C-8bCPg?LkJ>>87od!qHs~njJNxP6ZeKJ6pM;FkK(FXg7d2hqWg|bD z(v_^$dS#!%7+_cp8B_yi!VKM_W+g387oc<{y`o3I>@%na+e(yu>Y~Pv{B!}jp{6cs zW{Q~xqy^C{d*qEgU4Txg==$yiM(UtPY-|y4u=;{aAEQkzJZx3YUY>c545Bl_6%<2LF0000>3pDMXV*lVvtf2(-?_T5=q)L+C+oIfS}RVMdK^tBQ-WO zji^|W67W$=Ynl>UTWYimVz3mo7`ruFNz^E&m6!O~?sf0Z%sJ=RDSKf9{IQE};~(uw zzB%9d=9f92%=w+1j1m#P%%Oq*Z2)_8puV=YVSs@ExqyP90$T9$2sJmB#NLa@t9T$t zA;1fVpZ!oq7|bNQafDw$fJhx%k%x}9mgI^#7oI-PySAM(jS7a|>_4`4?Sj4prx3a|>G4xkXk!=7Fbg;_j* z3Y-6MDKloBbQvGjpCibW&vgobuaNq0;DVqK00Q6yL>&EYvMWW12ucN>ctbOx3YSlH zoO5hJJ79 zO9!*&<`_`%hyf76<(_(fPGmLCgAGCyz%;xIP#QWM(C`BEWtz*U1!kQD0PENH0PeNp z_yU4PXflCB2ckmeKeO^!r3z^*j^GrzQV4)R5J*$Fbed+tR0Fom?>4^6Q|ouuu<@Fa z0SNTgjVV;jL{_t6)2F=t&x{rYbtm8g3uZI>#MW*9 zV9C|b1KfpH+eQGOOcHCxwU#NDB9hpkm4ZS_L9y^bpQesH^TdRMebS3iF2^iAznSlz z8&j^9d1c35=FfkY5BJtqQ;Js-gkb^1P+Refzqf99p+fG4no0!)L2y~1trBy~k`9_< z7)WzI{#QoFX+?H%mD!U^2N&P?{4N$P`XdMS_Wy*YZ+~VcVCDLo^aK^q;XmYFcVLT_ET<)#;T^0A(eDA{W%+YQL@ z*YU`Q07w&n4?-yP^)s6o+g@SE-#(`Ewr#w=efM7(6E8yO#tSeS00EAESqMV4*@B5! zxo#)RSL|@T2L^slYqE^MzDE5Q1W?jX-|pHoRO4GwyoaYTMgu^A0Xa60^xOM;)0bDT>luSp p_fbuLiIbcle4g?DpVKcL;NROra-e_cBVYgk002ovPDHLkV1h7LxF-Mr literal 0 HcmV?d00001 diff --git a/src/qt/res/icons/staking_off.png b/src/qt/res/icons/staking_off.png new file mode 100644 index 0000000000000000000000000000000000000000..91e570e1a7f54e22f1eaf86fbd82245b1d95b5ae GIT binary patch literal 978 zcmV;@11Al{zp+N*54QB?bhllt_ihBmOG^v7t^*JbM-;!mCK?C?zV7Mi{@myDMWvLy zeS7ssCX;!3eSP(KXJ_Zn^Ye@H%*+gni;D=}6^%yyJv}`S2L?X+ZgB7(Znq1E!-13% zAq2%@k&TTFlF8qGSY2KFF`vKqdvbCT`EITq9v=Q_WMt%mV96I)wbS27xnDzVtz@9*FL?5kj~0Yy=`zP?7+vkVLjVB0pw z$635yFNz}Y`FzyX)!orFO--dz>oODyMTdune~v`LNGZ9zykviWp9c>nh(y9PHa3#a z=Q%hy!0!)W+cqAL2g5Kw1Xg8NSJ%VQ(a}$Y5aja(c6L%sPk&2O)BD)AjSzxxI6^j? zWp{U%+S*zy%R)-Ud3JX8T4`@@AD2>cetypO_BK;f(=;_TVVXB6io~)i6pOcvkAFc! zLj&vUFE9*)>gsAVO^YiYkEhe+a*@qu85)rvOwc7E4P@9334I3^rmICIB}# zMQpo*Vi?Bnsw#;@B6z)CQmGW7P>9>xTL4O>GQnUYCnq^JH#h0;??+0BWm(uZN%ipX z@R!@$Qn%kXCNE!B{xgQEs)WPg|54etO`%YrQmOo^luD&1$z&3TL&NQM z<8-=kx!ly(*HbQ+Fin%HswzAl51OVSgg^*EE|3`U4^13fZ*cdg1x=HCo3x}^U^fUN}*7AC4{(JUtfR6=X(#Q z(@7xUr@OnGj*br8ZZ`myRUwzlkxr*q=I7@h0he-WYKlZ6ag$D`pKF>XP4lMP;cz(J zZWlr*R4O*bVv%h2m~=Y*Pdc4`JU2J@2*~yJ_99waTNxS}VsUX1z!{In2b!Ck;~tME z4h-71ZCjT0s#q+p>AL z*jV2DDl@Tng#sCK$VLFrN-TUfcJ1{0gQKr~c!Byv43+Wl)-`5M5U~7ob#`*$^;f~i zD_hRq^QG+Z6lk?G5>TPtI0-6 zNw^`*ekyrtXXWW1LUj5s*S%f;vfXMSlPBg_E&%G#-Xw(BIt0&h{?TOS9-^ zO$mo|AsaZ%WLAaQ>Hj)%wIxHI<` zl}4AmF0wbbk7L>C}fsaQ1j#1-_5V0dP zwl@=RY{1q*^pPUHe#rXd3WfWbU&!b&7AsjH&fDn6(s8}=?ahO2kvd2X6w~>DE-7?g zQ9LZLwX(_lgEWdP)_DXvzP7PgXv^ODb>s4cdYyIpAM9Y9}y@HADW zD5GbxT0sR? zpi|?~%Na;V^B#X0NkA9pAf~}9oo=bGsm{0eOl1|^4hJsuzrvlnGo7lzTJXc?nBvQv znvWPqj#bx4s*`VcI{LB6<8?M3ulJ|cc#09@VYEMgiLP5S_n=z`p_)-s(qSoa2-O60 z`EtI@%}3XzWoyOtzH*{vMic8w3T1CnF6PY{bPo@qyK{DsERqIUrnAhFAX^F)!v-au z0Ol(42rD8Ri)3McQNEk_(l>$$h6O8xM{h^a)$uhb=EyEZB|+I-7EKLW+yQMV3ATs} zETv!zWK)}ngtISpm9Qv62z+{no{s3OF)8h)nlUUG$0|fXtc3E_P)%21<4T-N zCH4dY3z#P37!18fZ-*Yy#}W=Oh5-HmWtNJSXk5Mi`Gx(%v$1JB?qqs&$kogkdhr)n zM&4FX!9WR#(j_f@cFa*48+D!nGcO6n1ZM_>WB{utkY5(8xz67KP^}>|X1vnl00000 LNkvXXu0mjf9!^u| literal 0 HcmV?d00001 diff --git a/src/qt/res/icons/transaction0.png b/src/qt/res/icons/transaction0.png new file mode 100644 index 0000000000000000000000000000000000000000..4578666ee4640bb6c1473a52196faf336c2ee637 GIT binary patch literal 569 zcmV-90>=G`P)6TKe5D=lb*hwL) z(Ba*RA{D_+>{eX+XB5OiaFBxFVCfog$RHH8EulkO92{)@%;^v<#=bG+z}cSXckg-b zxk^N^Dy5VLJOK6p0e%C2WXqto0ZJ(a7_nIFWhfMS<@I`xCX>mm-|v5{)oO2m?;>)! z3*gD;^Pf_w)Kh@bXe1twM*%dO&0pnm`D6vTGK$Ex1`dnG;^%ZaeHI7=62NgZ8hu-- zR4&`?wj`6ucfkHXy#>Gq90G3O9-x3n*=+Wr)oO`pnk_(I>+Rd&t>znUjAR22g2A9M zpU)W#1|NXwrs2k3o&GqN%Uv`Y4asCOec8f%*N46tqMY?fPeRr@}l?^HzSbUN+XZ1!dI{nxb%pd1c|zE~_+E|))m z|IA>qNE_+f!{Km3*Y(73IDFsjcF#m)ahDs|-EQ}Dzu*7D>2#jlq}>I$Zy3gDJRX1I za=8+Kc2~fBJRX1R^?H-(bov!oT8VaLpa30s2#m1!$^d@>M~5aO#PL7+00000NkvXX Hu0mjfRpJ7b literal 0 HcmV?d00001 diff --git a/src/qt/res/icons/transaction2.png b/src/qt/res/icons/transaction2.png new file mode 100644 index 0000000000000000000000000000000000000000..01bb558a100e37e6985d700585a60bb38669ffc1 GIT binary patch literal 413 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|*pj^6T^Rm@ z;DWu&Cj&(|3p^r=85p>QL70(Y)*K0-AbW|YuPgg)Ha<~v<98h?X+R;_%#er@=ltB< z)VvZPmw~~#C^fMpHASI3vm`^o-P1Q9MK6^dDE`IM#WBR<^xn(1UM_|rZ4ce&Itg&U zW$|X_3g1x7+NE8 z`3rwieebz%j_^P0Q+bB*^Z9uh{1W9)&*)aXd#FHdPebvVkTYTRYo{`vU)0>`Rdqai zTI;6ho<~fz_x&S!6-$fqH^eqqM|3I1rrRdn)Kx3&|LAqANAa!M_pMSFl-vs1zDm_J z?|sjg6%}!qO-`!Hy6wxv$q8$umS;!tv)f1Jemf{CCwPx#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2i^h> z1}rpU_YegD00CM_L_t(I%axO{YQj(yhCiFcv}uisN(TpL2c>ioiXhgd(k@OuflI+h za4q-(E)I2b5?{c@#TO7dskC$o2&I&?$xYIBu|+Tm`cHTG&v!o#oCv{*0vezIKfovO zwR!(15;R>dmnjyDq|<3E%VN1)G8&E8EA4h0;J8w$JT#llr&6hO4@5hi&d$e2egI9= zXti3FuIm?#MkAk0CU1wsp{Uhr)a!KsH5Ab8cIo%~sHz%sT^G;ujOlcW>$;>;DK>iv z2K>dg?GIU&ktFFnm&@Te4y)A)z}^e6ZBQr_7>~!yW-|bBu)$<9VK5l%boMsr^?C>) z4g$os4TKP9ex)!#WZMAv_A5yt08ddAV?Lk18HVw=Uaw#MAYle_B9XYtX0zA2u3rXq z!vH6lOy;gyt>)wL_|4|H4gxr)X}&BL3(L0cXTbAaRM--M7;p-_`<*htFWw%A5tOHp QdH?_b07*qoM6N<$g1DN%wg3PC literal 0 HcmV?d00001 diff --git a/src/qt/res/icons/triangles-128.png b/src/qt/res/icons/triangles-128.png new file mode 100644 index 0000000000000000000000000000000000000000..b76083e60011d88ff17d35b17b6b9f2401f26a8e GIT binary patch literal 14457 zcmb8Wbx>Ws7XbKhic4`V?(Xg`EfjZ$qD3G6aEe2L;_mJ)4|jKWcXwF6-~P9|v$H#Q zlAFmnH_4G4xtaX=t|X0&fR6wG0FY&6Bvd}%p#KUy>}TC0WHbT*Krma0i+{H=u>}Bt z%Ly@^@{mS^A(;!XPP8H9`1tFhMOkE&dHwuY=!Cn!zH?uAv46XWdRX`2ffcpZF^PPG zspsJ0f)?fAyn}=O!NH}QH5oT?dx=ES;q{Hv_FuXj9by33vhjG(yp(aKGH)o(2x97L zXV8x07$AyE^L}|30RU=Ok0=EV4L-(lf%(55mMp@>LMcTln2P8^CE7JClb!=g|2>i$ zy8r2fNL>FdPuk&^yq@G~VmDh2K@&9f{lU{y3VZ&BVEQ~bBW|TXJ84sIW=z5aiROfw zi>=?aPpyz1o#F=3XuT?rB56_8S|(n+iM$n?oUSYvr<3BbpH zPgZ;3-_M>e4l-I!0D!L4e+A-eytpU;Km_aYQ`1?+$c@y&(caw3#*Eb2-NB5MM@&}n zKc1I+$wo1>M(wStU;P7TY&-Tc#foH?#JrHqf^*xs&pj)B3Sc15sj6qtX;s+5f$t{o z53dWp^PTS(zHgat6Ca!to$q&*zA&W%UV#*OqB2`MVvnsSf1{ZJ;G18>Z<1gQ*`rNU zqaCu7-m@dCjbpkD-FTYvbHxuY}Id8&idc=@AYpx8Rf)jXk(qBKohGt@y>08RTsGzvo1m8J;PZ>1I z+y&vn*z988yln4e-{iX3?#OhuVa4X_$@JCw``bH|BQQ^4O!s{W0QhM`W9SdR3#VaS86~xc2%&wb*e@nxY<~B5aKxuN{A^R*)g`ZHM2H(56^jyJVFlL zI5H4FF~Eyw7(ILKg#-Ye=m%~fFWj!9IYSFOjUn<5ZeTCp-n|98nV-fwEZ>Lf{T^OR zY&yoZ#fy3HmU;Mb`I47$J-zfOudKKr<*eP6`v&8G_84b%gk00bQja0c+_)C(a5 zUg^*FP(DJ^@1;8*xhDbVp8k0TLLafAnb2<%50PE{bI0U*9rPTz1M_qJy-$^;940tE z_Aes0?HE-aJ_^2<2NBQn%AMwia2?-rZpD4xPPr}U5lvJrIO%CWioRVj2j^u**r#8J zz12#K?JA2qIZ^9qgy1Yi|1>|T#Q$cKVZcqF^IUv_xTWJu(9*IPmb#q8hu4xMbZ-VL zKwQ4fILd?{tE4b*Xu7aep)GyvKv~t?q%b zvbecu-86tn&Q1sq%YHI|Cou6;wLBi!i*-oMC1bo>8UJ{dd$*WE4J6W`?(|p3-tV*x zd`Pu_lX_zsR8$y4((C;Bx@CU6dp*%xD%ct43q7Q~Ju|4gI6pjpREj8^$%od7?6(V- z80}7=lN$YU`A@vVc68}By29;jjPpa{#if{$T<71v%6F)(Ba#=WrGv`BPKy4@{MCW5 zu^0KH2g-lmijySlkCcCWPU9};8*853u`B^3nU%eNE?U30X+T^80O$8hME=v{-x$hD zvnc5AWn}(9dd0U>N)LDUV;|0$zVXoj&mOK0H z6j;RKcO(Dx)xmpoS=+aqDJxk!3i2(t?gc0L{(@P;B;>)iABv=v${bVmpivTgVr8;y zRqxf?`s&A7F0NKbqp%2xWD8Hbp_luY3{=>U<#*OhV}rxYiR~|az03QIm6QC7C{*)Q z7iV|#K2fQq#qCT%2B%X9qJnvbqY9XOfRv z@`-=LIx=y;bRMF{KUuuol<%M-y*EtyJYucz0li=uyTk{Q{6Vn+0jPe2s&4eEI5@vx z#7*SIsWBmqbgbdTQx}LAdT*bS&Xqs1+)xX+GtEtQ4NY>*bGAt6Mh`YD-bijvC*-61 zb00hz7*9@$wr$fa)kvn^-LT&zEIl_Guc zy^ey9cHn)-`r_~3zc=OOPtMPkOpJah+-#L}>RDn;_$v2)OqO{QZR3b?T!_D}g~RXa zAW#Dz_&rDZqf0TnPTB?+<3Z1r8V8wbLLa&Z2Bohb-G_x%a9JvB-lGZ|(O`uyx3<4M z)5SXao|81&GM_Lt7hmxcCN_fhQc%It^gnF>>v#A4fu-hEV`vOvnH+Mg+hm zyB-X{AL$FA4C`W#OSo!Od@n1DmV1doKHDP1zvu z;@nW@#g#BUb&v*f9e@Ua3*bQoumaK-p3pD>{D6aS)vqE3>kQ$HQ@3m_Ab z5Z3F@@GwEX=cS|d5Kbr+<{U8S^|inkfGXPQxLQfmJ#@#K^1;}e%XGp0o4IR5Ho;U z#QiU>2n_hAOqvjy!szZqx?!f`5SNN8GU19&ZXOnB7LS~LyPYq43e2qCmo2lTDD zp1t5w$OWd=0EZoLJ5=LWJDgQB85tQe859{w8N@*-R8zu1=s~`ifEa@BGT)uE1GDS0 zbhF1r^g`%B#~|(C;9#l%Y+%-%SgS~;Uk8L9(i&7d94uZitQ2HFbUzLi1{HF_7jsx_ z$i!PetiUT5#cyTmwU#8LXMr8VAdIrIRy@TC@{ixSQyYz$kgSj+@G`lnyG_F6Ca#p2^MYTjE z#mq$2#P0&||D?QSp=3ei#%9ZAX=SHN%8OZxuY^ZMGKJcO`9Qv*cwj#B5i1Blq7thL z9Bem-7h+AUFT|0D8T~;Ijg6X$#DQkkYYPLeUG;A=_VM2t<`_B}^J(DzPh3A`udLj^TpYL%A<*BSk2tE75itvl%Dz7Z|%r zaU_o*Ivg^KV#Q;{d&Gywo6NWLyT-YOcNaKFN$l9U%RSV3C^EB^zaw*ik&cbPf*|xY z@$1xAWM{v_n(2CR?l`+M@h=iXQdXjPic2yua($v^;x2zm((%KzW0oVIsqRRT@gu*E zWrt9un+GQbsx#Y?+VY;EK+y+a^mT30ty(imHKaD;HjFm5KM3fS_M4y;a^Vr-4dn6S zt>NK%thsX8O1-^I-^<&t+im;jgo4BSk9Gm8!pM%yPW(K46-oeF09F782n+l|qA$KK z-zNTPIH({Op!;EHq0bQ3G1AbD(Ht@4u(WaZ=}#GTFGB(0q2X!tD&%1lC3N^2b@MA+*VIdLQuwA1obR;Ku0+rRv#HLQoy6@uH>k_z)el{C;LyQ zpW$jJN$ROw%?%`HVbXAwQ3*;7Ol1|>b~O-1el1d1!(c1-sibd&hxJ0JO0;vDp3qYO!S9ZVmK9;Z?V45N67tcAzj z1?~xBoEXN7dAq#GwtL5$sSf77mDtjd_?umZAAhdRL=^6%tqYpC7VI;uEF}S|0I8q` zk#(@AKUyYfr)W>tbeGjP=x+zXWr4@R>VegPeZf7*Zpb8|%xbI!rPX=5rNuQjMXF&wGsrG9uPIySBwL!?!2;>f}xTbu$I%xwZ-Kn_?be^2a4o={|7a=Pg?(|_>2KG3$Y}rKJaf0-%UG_1+$d>x&@AqKu&r0uN{tD? z(8b)R!WZ~sD;p;(Iph_0krz`Skxy2bkqVo%AKMUPN9|1-EtS!a)Ql&otUumXoXnBD zPzzs6R{NuNVjn!l8&{ip!tGWM&NeKWY;$Omd7wRJm{(m@$#ORVmdfRkdFHHT`SJ`i8@SW7l@~*QnLDEu9VaXVMl6 z)TYxh(9y93m*FDfrKW*5d-D3fUAj z3`rfC7S#oX0984PC)y^G7%zYrkzl~P-+t66VphqA%Z>6xrZp>)N`Fp zo!{ghWt~zlY(ED^l`YGV&eKz~|Q|pNE6YgAl2};K0COKPix(sK}>N6?OlB z4Y)4e_Y-@4uzBptS%U;f@Kl;4A%Z~?0Fh7-I26>nW?#tV)(9Q*aF!$kk=a-qy|K|| z3=knj`_AIPgXZvUW4&;O+3O;@uY*Vg{j##`@fcIYkQ9ydy8{bP7Wn%p2!M)4#sdEh zgS;p!=Nnt>jwlsNJUIN1ST9A9T#(c#gHi~7P?u~b>0VHmq=|)koxE(wkc7XQf{MM$H=9jC> zlOtvKmq)%1v>a~G9-=x5?C^6p8hTO;`j=gp0CMzes9|Rov^}B_vHX4*bBtWkLUGaV z;iCR=hVVSY3sTVEY9UEQW)7y@)X54BUfQ zRf0hwDkq9T@$KOu7$1(GBMO8=p+A9S#%73vfqBS>g-)xsoG~*d3zny)^U-U zeaY?3zp0LucDY=iuD6$93^7}4O-{?IUF=Sir-d}WkxJ}p77N9O=8JkrJxmj5jsrj7 z7tZhPn}mda5Sv@{!$_x;AT+i_c$Z;#0+^d^qGwbR7K)P&q$CVmYe}Cq)2wBwjv*D@ z`I%o@lpl$gesAQgG`rzsVX0T&KeIQ6+?<+WVQM%gf)P)`EReYF_Z#eM`cVSgh2MF> z*B)aIbWc~`BGwRM1+mgSor}Yb-VhqEgK@T)z>?~PD=t)Ax6b_HL!l!=OiRtp7}n`2 zwC5&-tpLXUGj8>U24^Ocgx};$$gD7~^9 zf)$N|Lfl+})JFVN$*FH_nYU?5RKgj}r|17>#ukcPy8@UrLU2it(hhF%mK>t;om|JQ zZq8iSt$Ws%?WhVC3GghIq-zjltYx|N#_vySS5q+ZLTFibXOpM?G`e*oSI}*+msv3; z{GlEl4V8abm83}9_L^6+Q9g*;s3YwIt4c>9hXJ~_=Cv|bDqP+w!VNm5ku@z?tn8oI z3mV-BbJ_UaV(cDJ4v%f8SPkmiaSk?*(G$#U_I12)|M4=OoYrpcv+!4N618f#y3?ml z%~vt~1rcgQ^N(+NC2gOkX=1InY54Dc;kA9f{t~tjqPwwHAPkJmu?V4>_aL61$-0ZU zp#@Zxa^~gfww_toXE!fGE05A!9z|GieT9M>WC~%vi|X?>A8Tw9w;b%s-Z^Ymvr9ZW zcK1q~;NlM&qI*78YN^z(Jj;@I&G@6^C0S0eAi3CTo9YH}{y0bU9SQRwN^l28z{555 z^_tk=xHuawa>ZTE(PD$NdHN25APKoxI-}K0D0Z)SZ$w)lWQ9@vYN(Z{+>^3G^(^?& z`&;a0SJNC{#ra61ZLKG@ojK2t=x-PUKlka02A9hecf87+uCjfY2B8p(^UZWU(8_U( z=g&1LYeaX@KRUMz!==TkQ`%}mVISrT$j7x*4JPXl*I(KjG$s5nntQY%%UVhr{KDD- zUD_Hdo`f5MM^L$Iw(mo^b)ygQ3OP^Snho{g-Yv#V<3D+NQ&=x;2#<*_j-&MAhf`Y} zuGgEFyOS1>oHG}zj=t^$o-+Qa{Wok=)F?Y)W1@2bIXEOIUBbtSh4q&>B!Mw;MQXNvx&!`?1zhRMkUo+LtU8$$4b~wvr*sdG0 zE%*J80kF$eh+O5!*|N2M%*ozpT|s1I$4?HUD6Lw2r1AE9!Ngg$K=Ll&P+Y6N83=i0 zx8ILB-a50e;)1hjn6om3P_Pc}@v~ULh*JLLnI)+C4PDmgj1Y>#e10>5c=i;&@R{Bp)wsBBiX}KHMq^m^f*i$MrLwV zFs%j^HsR8cE0*1z=ZeM~@w#VZnbXBklVi(0UaJ{@!g4d_dRm)ezq5NZ+?tJ2n+vTj zxrk%3>_~x~ab?=6qi@v+H;RGq3P*L1miGMx7 zre|?6q^{ZQG}Go%<60qIRar*vzM+8?Q}}RXeRRS*)q$x{Qgr-)LHab$O&kSt?bFz?s5{ZL#@l}Gd8l;Oy({Rsuwt($p^AqOYcIE6v_E6zpU8CB zzVuY)P`ju7G8&~?evN%URNI&DW^`q~q$ep@F38a~-3stdXIh974j7m*yqH_vTtRfZ zRiDKufH~bquEBwflNHuTo``m#J{z-zv0sB}qCE31$W69~{l#q1FnVp~Vsn1buu|r^ zkL{9j0g+x*b~0+IrIr}ch<{tvL?X1l*;VgHkq{CPH}4N zJi)fw^aN;>T-ql2s~GS5L}E97xBW^a|E^AODRr@C!yR_33tzxS1Xq%@xaR)sCAQP9xqWXN z7bkaKu3V_XDxjx}MS;GG@Zfn?>&`NBfOGlA-2R0K(fSHYpvYZTTm|xmVd6RBqKP@g zYAt7`LiWM+*Gf+!5On7N!SVgOkr`M7rw^m}-9s?H zTB?`P9P@^nRf?w<%1vIvF0wD$qES=f^ZdNEdFAmB1-Y5oHtw$erpcOD!j2--p99r$ z!}*QdtbfV(!DuluG@k8q+U@z*!I^of9=|zXQr4>lxDvfBTGQ2*V;|h*N3%UW=i;hw zTv^9CXH5#|y&8;wh&&#(ZZQUXzlKdy%zH4Yk6n^j`UP;Muzo773|jB~b8CF7cWtED zSNm7Y{!ct2XLWK10%f56XX9V)`I_lzODjZPo>^y|zsiy2{x5>90P-Q7B9$r5MATH5 z117*DH0PO~z5J-B-p;;RryAF0%{ljWgp+PtDvb9F}cqAPN+7% z3^x(!?SDT$RM9J=4!F@Rw4{Rh`sNT(rMTQC%&vEi`7IYlmdiiI4_PO;QsPuiYmeJ{ zERktz6#ol_PLp3ZB%He4tIe#HbA`Nty~|DN**(NXRt3mZ(SK)MO8tgmp2k?T*Bn6T zCSt$0w_e-pbg#ZMD^xlBtx<+L2@ZUnWWGB04!~{JMk4$CPgHTDc zyxZ@OW?4Y?yLPkisE76$CwT|rrF89j1f=18rFq|%jgs{Pli5}iUtyjP7l&AW^Ofl3 z7lB8n+&k2as=~V4AgQvF3l+9=b^7GS({<_}wKKD+_DLCzm%UcdTTSN?b0`95WeLH; z;!Q7r)BDB`C{crqx}yVwna)Ng5GiPA#rMPg1r80hz1_j~U~bDEdfZ@HNMGPX3myV| zqa29V_U<8r2Rgf{UcdPO^adMHdu)gA001xv|Bol4nu_25I}klfSB%=>K?-`{lOz(| z&LuwEX=1RN1RI)9J{XL4%Ti;lJQZ_Ha*#q7A)x))rH+eBYm|8`eOL8;PZEBAd9r`G z`pmCMNMu!w!4c*Gl2rbgqXihWqa0CXG-UPOK0aLNe+Y|d$d+R2Nq9!pN>M8TPlh3ZzkS3U@Rfpw z$`lO~n(Atwvgo(=x(QcyTvAOD9W$s4baZQkzGe997y4fgD|2&ml`%lE4Hbu#3@)qj zD^|2fUSMD7*MP{f0tGG^BTo1Vljca7ge8$AhdN7qo|^_hUu+FA4uo-$CTa3 zh)r^Duv@|;(R?_Tf;FUX;%sw;)4eThYw2x&iZ0mVfdD&PyYAGMcPm*iBuH}kZ8eC# zl4Z_D*WcSE7tx|JxQt8NG%+z~32eR;XgF`98`oYRok{nys-s?RDE{Q? z_EEcYX%nS$5#Bu5K_-B(fA;=r56&A4+;Jo^-u6N@6n?+N2TQ#cvUI=kWXOQQQ-=79 z3O1`5H7&!SrD-KmJLRp>tLY=`WCf(rgJWs*C+!bE_sTlWwbl9ZbmNcI#0{4E(9g|KVK%7qK~I(vKhQ$v4p(rx%f3j#WJ%$ zY9Wzia7Di(NYKSe;5qLP4v(6WT?y=!R;xZ$ko>y$683aMJkf3@ZWCx`iawp5M?L$e zWmGAo@BJn#zM|&yz0QJbvnNZ?Erk&J%mug85;43mbe-k)Qr(lHZa~eIv`#~(pL5ys z?E=yEMyE43ryTR9kldqZGMA43>#{ZD4&hn)`$I4`wLN;f(czZUN9^Re#!}a$z7^hs z<;I0?h~7xpHZq8fA`-7kB4RUM1=bUw!Nl-b0 zI%XjvFZv@qk}pJW7cjP}*SvJg`o<`K?sXH0pwIXjcd*ai-X8+y`xGiI^+s>QJ{yJq zx5j@U=l?+eUvd6_A^(4w^#5f*0p+#V?2gfvR|*3b9UoKXS5&(5UE+5HD+>Ssvqn}z z^yh!3c*$OG!KL4KWBp)#B)JWrajAwuUWr39F$5S^$U~gdg-7&P?zne+bF^Uw$%QaF z4vp0N*d+5A?lIre4-#fNOENZxW;(()7+aEn!dr%b10_yom(u-S-+S@Ep^EZvJWzTa z6)o$}ZnH(DpqFR)h0dfjiTCZ)0Bq3m8{iBak1f;?W`MqlRqHCOJ+ig(1}N{}-QFaR z$rnc4jOmSDc>^&9TR%Y69YG<2H_^-+^EbBH65$4=MCQ-oEGY{p9G!rYaL}6^4)y=^ zqK6#0)-#%n8bFR4Zfy2emmB+=C;lU3&&^$^(CZ4W@K+{W{qBZ6HV}Ib=H^!fi9=n< zfL&OB9LJ4fC+yGPpQ<$V)2(fNyTK(L|>ea_ppcL+1?*<%~hQ#^i1*nWJ{ACFj zt{b@;QYP4x4IZ6~_eu^wBGjn_$<8$^ty(Dhx!Nyn$c|Dx&ncfHvJ8 zi5xr^RNLc@9wZ`+s~}KGVwGaMQlSzjO(wSkNKMW_IADYjj>=W=JQDQ+=^&|(uLDs0 zyTo0d!m13tNK?+);Z<&pm-2ro=M+Mb4o?$hf(s3pl?lY9gTLD0CgP*-Bi$p1@=K?W z;qv_6SL;!eT!feI%0LFm{z*?X>Nb&JkAmHag+N!faTLP-PzINE1-LXTX0VVndxt+R z>KeldC54Hb+UK|l<6X+{@v*R=nUAtjD=8DK^6odaB*L~UK#xiU!80A^}@1Kf^mfH-=$fx?I^ z%UnQZ>4DHxe6NjmbvhK?_L7##z?iN zsvV3V7C;pvuIP)!pRF~tNafE|ctJPz(EwuLWE?dVH{yYSkkUJuq@nDfCg>AYgjG#7 zWhPveUFxg=J?JDjZ0Q5mfG*3(;SR9Mxld!cb!0{Uf(mbu@UVFKF!{|v#dsZw*?l^~ z+YR*ZSJdMp*G0%$cLF$!#ZW`>`JESW#*ZGh@59dD7uz(hPh2pb`Y;(wL_|`>4tswL zHjPKn#9<<7XZV=xOlRyNIl78B0FF8>Ro?d@txG*%wX6}_FGCZeAkWc(ow_eGv+lR|IaBj=b9^lhGdVeSLq&ZOr=!2d>W*T@LCUmGf zUkx-Ee5(9{Uep}V&O(Zx$;o4k=0na)4a|enH(2oXr~T3>u=3#5vv|D^vDX+`;dSYm zi^EQ|by?-SQ`H^u<7WG(`l}90*hs;-lm;BwwE8xLY{kOCnj-`4^1Gf^!Q4~_qNqrn z1R|W|Xr!Aouu$~tRB5-YJ&g z*R+M#^OOGZd5T{JG6<4QHM9VoT0eyq_|i19$C(sTw2@EU z$@XSe_ZT^j@{78dEFvnhEO#W$C@vPWl7{Bbf36#sZd!o&5gUbvH;5*F+-M6!)VV#% zl#&DVKi0&R{KBW9&A$ag9{T*TrD`iy5L)N}iKKRwxJqfstWDlOuM`7vrt+2ya`J*& zOD-GwY_>+sxk9xZj%%h0!yO_1@|1ml0DS(kzFGx(%wiI6?0dT)FLlUEQkWt70_VG% z!Dd*68~D%CD%gDbE0XU1=UNb^O_DAXfe0=WZ#zmW^e56U>Rw3GLr$wb)p6MPzNQW^ zlP-`u74RTg3C^{Lm+j4mKB?W~HMKpr=#eqqtkF^}8q~ng4fuk|xElB8AY9s^B77W@ zhy?JrDLzB-;mtkp4L36yeAV(=C12R3-UCu_$f+2Gn0jpLDu>M;RCK68^v~LX5@E~X zg}!EEyPB?Jbp*<6^>6J@btHVpjwQy$XpEp!AXpD)=hV6qI7SHZixPq^u*r-m%kuUh z?I!U=Ct2BllbBDF&#V^#kC&{vjcX4^dT05vKgNPDU{;p4;JTyqAygVBl0cXIJ^#$~ z-J*E!k@F}NTj6|}y7%hi1Cm%{fV4@$xwNkqIE3*0t}ryHKOi>%1Ya{pBb6gxZc06u zVe?0_>8+%l9C#WloR~97~6( zLjtAt;?zYGIfw?{RPkbNC#uq|S78SHgJHd*0>8n!1n6IgDi z1eqiQrwXx@x^xFv{2S~cs1xF-RwmM&f{Ithz?o7GB+JLnT52g5m+c>3ELq!z)-Vre zwdP>-X|7B5p*A@FNeCU$6%Ej}3`JIA+v}&dTN)!r2no)US9_>KM6r};G8b7DD$z_) zY%_L&u3nQZ!?4wZD4_7MWBC#9E(!DnRib@Wr)zlu{)iQ`Vhrmp(*X6%rCs*6?lf#KUv|>rh?CL(;gN7B5`1<>XrP-11NC{{BpQ_U71O`~Pp+wHxYXnUJ%PVbqGm+ovS)?&|yMz|eRI=Q;aI*%1g&0|qb%^6|B zE!=##?59LRcpa{*w$KlgA`X`(li8&Xzx`A`XF55lszO+|Xx?G6>0qrrtXh`5$vE;K zs;GXdJjO=HhG+x515P`&CP6KQ+by}HrO7m7RC3nO5JwszdG?5GfBURc)2J=acXjNJ ztF$OoLq3Cv74;*+PpZCqpxKSbZ5L++8Pv}n&}bl*9i?Ie{$jW-8)+`r%r!YGt3Bxv z{Z9!{yZNQ^y*c-gO{A$Z7{{op_7UV#YG4HXd-xw=Ivs`0c zY9Y#L^JHY(XL7nXb!}E6`Ot3dnubIa*uW@iL9DvZ3eNOz-hD1v#jW z+Teee8S4LMDeEF7C|E1sX31kA$wayQtpFt*0iyQmZvNKEyxyudhI=TFn`})j!N+0z(;<$h%#`9iQ*#d480%?(oGZ&~My>fP zt(KM*k274e@`COd?)d2h;5$`l@>8}&o9rN}@|-k^&)r?;n`{gepNRDS<5;5hOsCaU z%6s$m+Wv_RS2YvFclF0*W8r*)e+@R}u0_S-g=96GqMF(>zSEnGuw6LBfhTH04NMTE z*b7w3Di5Q$bBz%+g!+;r^FoQa9H~4U6l(%GEViclX%&`NdX)?K4nsR^ls{-~bY<%< zJ`bgh2hpSF(ox@3KP0o`lS#_?h2zSOqG5K7!ldSZr`y3Vm>G{V+An$h>W@o**4A#g zuO`fg+p5r3kxQs!NkUH1a?s9P@Q{V5njK;OTf{5Ki^J=sCDmjvRx$C!jEunn+2*Zl zCmqB>!29#JN6jQ!S@_i~B@Ea&h`YIqDZ)a|W#Un?!RE{ao$PlfE9wAMT58C2ijRh9 zJ#(|&VGfj`3SIc?h|R{QslIuK2-0EBHnS!fxx%-8o@C*&*nX-p(ds*m!|jrc{P6@u z$*UrGU^@lu{_(hb*VIxtMz`x9V!6>clikmaCNnON@4 zApIFxF=@~6Q!Alj&ENiW9H`m<&G&_-e&iP2X8zW1wW-r)Y5C++gxR;G0$f|KMdZ8v zZ|nts(Q}|K-ukd&D|i74WODh%Jz^uDwNqn{I;7?mVm`ti-z**g3DDB5SHYSt#Fs$fIiMFFuR-`SI}GU0IwzvCc9 z9Z(pg-^^QuvlGrcMCF}Z?718?o$~&OVeMgvO3SsXJpomU0;2tc216RXr8+WyC9Y_< zv^?O*P+uUNBmhs{2F#A%c;qxk)ZjG#E7>SDEBYQ{GyFOUfxfQVEt_9 z1>J-Q|3mxlQf~>Q2w32|-(#3^0ZREN-Txb_({?K0aRL^g3hwI<%7ie+b-N_sY$x>qYV}S6*_xgel%RkwtVDZ#{VM2`i}qP{lgCC zA!0;NOHGJiN$0m$wxRWUdAH-f|7Ru)1s9;r;=*ItKVx>0k0%rh020)^%&hQt&Ikr7${5%!qsFPm7nNCJS+2(?2yJS_`7D>dpz;cz$BJ#c*P| zCx6!e)~P*nL4amY|DpkJ9fCO_O(V=qRCmYKpW#5!fgsPh6O`n0td zRMyXHo~9q^@*9}I+MAhf#BxA>i$&>Xv({#phsFPBkwfja#R3|3H+QGJy9e-5XahS| zvdth^XpJP3HL}m2=mEVy52sjY|V?)Ci(_q|VIeM&iMMFafh z$?Icd4j`X;EQ>|Ksqbhhq(}4X>JF%?D)2?%F^nPSB}~(0yTI|G#>+<)%|7SlG?}#{ zRBx(KerbW-+nYr0nT|D86h7@6Nk$r~I;^79@e3fEv$iWP?rC-0SzDW~sgGXhk>P|2 z;(RmZ5VR~f{3^(hqR61|tFkC&R%(*-rizylG;-DpD?O7MR};s6o~^hOt+JbH{8~d9!@?J z6vnB?K+T^Iw^jxZxt}{)Uvp-_RMB^l6ne-EkifBM;X^WHNAiP*g~pdD5B?ZV^kK(F zhB$BmncnLo4LO2GX$WYL#e)RB^TsRCw1i2ro~Do%;+bW&qdhs2IR`2+bgaGk;KbZ6 zyV6G;Kziq6pNSdD;0`Du{}|E8)hRF2VT6yns}pz6&73-|RVo!42vYfg{Ru)>PD?I4 z?nQJm-^AI#ax*38M-$kqYC#=^?M z$HL9W%0c_N$HvAVIJ5nUNb?_}lfAjKn~|d#K-ARU*o^eMrM7I*iP@AtiR z>)e{^nXZ1GnXc-Yny#*yukY04u`$Rn006*NRFL`bZ^Zjg&`|#M)E6%%0D!<@BQ5>T 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 J6;j4Q{{zW&Wn};W literal 0 HcmV?d00001 diff --git a/src/qt/res/icons/triangles.icns b/src/qt/res/icons/triangles.icns new file mode 100644 index 0000000000000000000000000000000000000000..6422dfa522867bf7d216d0a89ba78d3fd2ae1305 GIT binary patch literal 79804 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 P+8RKR+PY5D=-U4WneUVM literal 0 HcmV?d00001 diff --git a/src/qt/res/icons/triangles.png b/src/qt/res/icons/triangles.png new file mode 100644 index 0000000000000000000000000000000000000000..4ff9c76320944c593d0beb253667984f78378129 GIT binary patch literal 21016 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 NVxViHQ*+Y^^S@{3;OhVY literal 0 HcmV?d00001 diff --git a/src/qt/res/icons/tx_inout.png b/src/qt/res/icons/tx_inout.png new file mode 100644 index 0000000000000000000000000000000000000000..5f092f97aa3db749e5e7f490158a489e16cbf4cd GIT binary patch literal 2442 zcmV;533c{~P)FdS2i4#krI z$;jMwh4UvwP?AF(?cI$?5W=j&A7~uy_o{IiB$|jyL)+bs4M7M5A}AXh=TM`YGGv62 zT{%z2?XLYkAOC23>$=|cdu_MQY_FubZ@;zsBku5%- z@9C8*SH9l>zg6)hz~JEEg|6#fFCy0gmmc+?L=FN^TWg0@bto7NzIoKjnn3_bCX?41 zV{QjJk5&L4*$xa@Yc~ah!L2~UCNM_`uw}~@|K#N4jjGxYe7I2sH3|`VTU8$i9t;Em zf2!ACc_%0n6BEP01@$^US`_-6uLG9=AFtQnVXwhdD)kAD7D@zA)yrpL_m-+|7LmuZ+3fGTySv}>VpJIJzFqiiFHIX78ag|d z%Uumz4O|6$z+)^QnMK@3P!vFbPkPAzzP0w#!C-JZ4IGRBY}>Z&t^ND=|7~Dk;2}WL z>GTc2FRR&=HrsGGe7~xu9LIUdYql}arJ7I?_NBNz<6LW3VZ6bjADWHOtLF~9BU z>1iqW-{i$sRSiIYfB$(vzlc2D+uOU+YuN@sM3#8Wzs;*-udH3W_AFz}3*@W*BER4N zd4ND5FbeFhW-lTJz;)fb$=B#pR5cw6g}&yc{GtG-dyMxLkNG^&*Vnf+m&?7Rs--_b zf64XMYCcr;KcP_QeBj2C+ddI_C=?3aUCrJASZh5AAR-N`0k_?D+X`##^W@(IrDZJZ z>+9E92B!#|EhBGWGXc&-5=a&Z3q`G2jJ&kLbYsK*$y z2{^S3E(`<$14Y9^ z&wukY#a@@mWFD&|f~YF#bozI|HC1BY83+Wtc9s9ur>c+%(d1=g=$Kkm5?AV0C06_H3}&dA8fBOG534{(j^x`X}w{cR?ZNcezL zs#%E0c(pv`jEsz2DI&+~6#FXIb-PS=cehKS?ahR$dKoGohT}L-8e^`f^6ROoh{)}+ zSnM~&CUC?cq5?Io|3C1+18G&g1{kfy{%D}8;b=7aBRDh;s49S}o>6Ooj^jLUt-XT$ zqDUq7sOlBg+C{lsZsFwQLEO1@-bXD!h<#G$H zwTp}~=c?+9(>;cWe9Lhhr+8yd;o&kOGUG#tNC)|8b4@eBfq{WPuUWHZxzFc&0$5y@ ze2$206p%;6AN zo(D)I674_|IEO>Od>e2v&;_go{NZr;qpJFIj;tN7h};;BMyFj_noSeHTHA=7U;x&w zTbFYj=VsssWl3+gx3@nB(9+U!3vljCezMuDx~{vQBX_xSz?Y-Z=p!@P7u%ZGYTb|; zP()QV7K`1Xs(l>lTpuZ(74Wk4J~1(&@pycXi2R}Cc2-2b7>mUot!7_r0=v8f+^8l{ zj^jAd!X`&nM1D0DoG~5MY}?w}EP%DPXg3LTN2Aflyp(MKvf1owUNWm{wFy(rIF9pc zYwhxAG&&5BNF?T~>Q&Y3#>dAMVD8+x3E(|d4aQ=zjb6*0+8$4*)BAv`iUa>p)ugIE z77PYo_F7Oio_+S&Ihjo6V}+9^oxtTxvtm@r=;&zMO*h?i5Ma%kH5bI=@xRZe+$jN4 zsnjzf^4VF&{cj*?j7d&ROuSsa6EqXGK5!`_a+gj_1MGV0=(9Mqw@<2 zpNoq_YgMK6y1~3ruY;)}r|Y^q>vh%yo~qZulmNyUPj7eNh=f$N zeD2;Xo)MAgjvYH5Z{)GsY9~b{olajVBCAz(CHYy|u|k2Zs=5(Ku3o*mA=`50%<8Q0 z#*G`70G}&}aTyIbY+c3}@Pdd8ipZu_t5!|7gw`--eOS6kB9WNu_xl&SuDb+SQaEF< z7-$Dhqw?M#s9H4=%$seZqIUN)PZ2Vkuo zJ#gT_XmQ+ryl~V6_?Tr~#;{X5v07*qo IM6N<$f*YKb@Bjb+ literal 0 HcmV?d00001 diff --git a/src/qt/res/icons/tx_input.png b/src/qt/res/icons/tx_input.png new file mode 100644 index 0000000000000000000000000000000000000000..0f5fea3a8456c73a27c2f0f3d01b3bc96aee389d GIT binary patch literal 2152 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 Hu0mjf+T;As literal 0 HcmV?d00001 diff --git a/src/qt/res/images/about.png b/src/qt/res/images/about.png new file mode 100644 index 0000000000000000000000000000000000000000..4ff9c76320944c593d0beb253667984f78378129 GIT binary patch literal 21016 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 NVxViHQ*+Y^^S@{3;OhVY literal 0 HcmV?d00001 diff --git a/src/qt/res/images/splash.png b/src/qt/res/images/splash.png new file mode 100644 index 0000000000000000000000000000000000000000..4ff9c76320944c593d0beb253667984f78378129 GIT binary patch literal 21016 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 NVxViHQ*+Y^^S@{3;OhVY literal 0 HcmV?d00001 diff --git a/src/qt/res/images/wallet.png b/src/qt/res/images/wallet.png new file mode 100644 index 0000000000000000000000000000000000000000..4ff9c76320944c593d0beb253667984f78378129 GIT binary patch literal 21016 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 NVxViHQ*+Y^^S@{3;OhVY literal 0 HcmV?d00001 diff --git a/src/qt/res/movies/update_spinner.mng b/src/qt/res/movies/update_spinner.mng new file mode 100644 index 0000000000000000000000000000000000000000..7df3baac6f9045553ebc88e3eb6aaf9fafa37e29 GIT binary patch literal 27817 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 X_3U)dpy>Z91dJB^2GVJs?Y{p4I{`$4 literal 0 HcmV?d00001 diff --git a/src/qt/res/src/bitcoin.svg b/src/qt/res/src/bitcoin.svg new file mode 100644 index 0000000..96f1017 --- /dev/null +++ b/src/qt/res/src/bitcoin.svg @@ -0,0 +1,115 @@ + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/qt/res/src/clock1.svg b/src/qt/res/src/clock1.svg new file mode 100644 index 0000000..793dc7f --- /dev/null +++ b/src/qt/res/src/clock1.svg @@ -0,0 +1,261 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/qt/res/src/clock2.svg b/src/qt/res/src/clock2.svg new file mode 100644 index 0000000..6a78adf --- /dev/null +++ b/src/qt/res/src/clock2.svg @@ -0,0 +1,262 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/qt/res/src/clock3.svg b/src/qt/res/src/clock3.svg new file mode 100644 index 0000000..09ccc25 --- /dev/null +++ b/src/qt/res/src/clock3.svg @@ -0,0 +1,261 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/qt/res/src/clock4.svg b/src/qt/res/src/clock4.svg new file mode 100644 index 0000000..7d9dc37 --- /dev/null +++ b/src/qt/res/src/clock4.svg @@ -0,0 +1,261 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/qt/res/src/clock5.svg b/src/qt/res/src/clock5.svg new file mode 100644 index 0000000..9fd58d9 --- /dev/null +++ b/src/qt/res/src/clock5.svg @@ -0,0 +1,262 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/qt/res/src/clock_green.svg b/src/qt/res/src/clock_green.svg new file mode 100644 index 0000000..e31f0e7 --- /dev/null +++ b/src/qt/res/src/clock_green.svg @@ -0,0 +1,262 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/qt/res/src/inout.svg b/src/qt/res/src/inout.svg new file mode 100644 index 0000000..bfab8ef --- /dev/null +++ b/src/qt/res/src/inout.svg @@ -0,0 +1,122 @@ + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + diff --git a/src/qt/res/src/questionmark.svg b/src/qt/res/src/questionmark.svg new file mode 100644 index 0000000..c03c159 --- /dev/null +++ b/src/qt/res/src/questionmark.svg @@ -0,0 +1,159 @@ + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + ? + ? + + + ? + + diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp new file mode 100644 index 0000000..d4e3e4a --- /dev/null +++ b/src/qt/rpcconsole.cpp @@ -0,0 +1,437 @@ +#include "rpcconsole.h" +#include "ui_rpcconsole.h" + +#include "clientmodel.h" +#include "bitcoinrpc.h" +#include "guiutil.h" + +#include +#include +#include +#include +#include +#include +#include + +#include + +// TODO: make it possible to filter out categories (esp debug messages when implemented) +// TODO: receive errors and debug messages through ClientModel + +const int CONSOLE_SCROLLBACK = 50; +const int CONSOLE_HISTORY = 50; + +const QSize ICON_SIZE(24, 24); + +const struct { + const char *url; + const char *source; +} ICON_MAPPING[] = { + {"cmd-request", ":/icons/tx_input"}, + {"cmd-reply", ":/icons/tx_output"}, + {"cmd-error", ":/icons/tx_output"}, + {"misc", ":/icons/tx_inout"}, + {NULL, NULL} +}; + +/* Object for executing console RPC commands in a separate thread. +*/ +class RPCExecutor: public QObject +{ + Q_OBJECT +public slots: + void start(); + void request(const QString &command); +signals: + void reply(int category, const QString &command); +}; + +#include "rpcconsole.moc" + +void RPCExecutor::start() +{ + // Nothing to do +} + +/** + * Split shell command line into a list of arguments. Aims to emulate \c bash and friends. + * + * - Arguments are delimited with whitespace + * - Extra whitespace at the beginning and end and between arguments will be ignored + * - Text can be "double" or 'single' quoted + * - The backslash \c \ is used as escape character + * - Outside quotes, any character can be escaped + * - Within double quotes, only escape \c " and backslashes before a \c " or another backslash + * - Within single quotes, no escaping is possible and no special interpretation takes place + * + * @param[out] args Parsed arguments will be appended to this list + * @param[in] strCommand Command line to split + */ +bool parseCommandLine(std::vector &args, const std::string &strCommand) +{ + enum CmdParseState + { + STATE_EATING_SPACES, + STATE_ARGUMENT, + STATE_SINGLEQUOTED, + STATE_DOUBLEQUOTED, + STATE_ESCAPE_OUTER, + STATE_ESCAPE_DOUBLEQUOTED + } state = STATE_EATING_SPACES; + std::string curarg; + foreach(char ch, strCommand) + { + switch(state) + { + case STATE_ARGUMENT: // In or after argument + case STATE_EATING_SPACES: // Handle runs of whitespace + switch(ch) + { + case '"': state = STATE_DOUBLEQUOTED; break; + case '\'': state = STATE_SINGLEQUOTED; break; + case '\\': state = STATE_ESCAPE_OUTER; break; + case ' ': case '\n': case '\t': + if(state == STATE_ARGUMENT) // Space ends argument + { + args.push_back(curarg); + curarg.clear(); + } + state = STATE_EATING_SPACES; + break; + default: curarg += ch; state = STATE_ARGUMENT; + } + break; + case STATE_SINGLEQUOTED: // Single-quoted string + switch(ch) + { + case '\'': state = STATE_ARGUMENT; break; + default: curarg += ch; + } + break; + case STATE_DOUBLEQUOTED: // Double-quoted string + switch(ch) + { + case '"': state = STATE_ARGUMENT; break; + case '\\': state = STATE_ESCAPE_DOUBLEQUOTED; break; + default: curarg += ch; + } + break; + case STATE_ESCAPE_OUTER: // '\' outside quotes + curarg += ch; state = STATE_ARGUMENT; + break; + case STATE_ESCAPE_DOUBLEQUOTED: // '\' in double-quoted text + if(ch != '"' && ch != '\\') curarg += '\\'; // keep '\' for everything but the quote and '\' itself + curarg += ch; state = STATE_DOUBLEQUOTED; + break; + } + } + switch(state) // final state + { + case STATE_EATING_SPACES: + return true; + case STATE_ARGUMENT: + args.push_back(curarg); + return true; + default: // ERROR to end in one of the other states + return false; + } +} + +void RPCExecutor::request(const QString &command) +{ + std::vector args; + if(!parseCommandLine(args, command.toStdString())) + { + emit reply(RPCConsole::CMD_ERROR, QString("Parse error: unbalanced ' or \"")); + return; + } + if(args.empty()) + return; // Nothing to do + try + { + std::string strPrint; + // Convert argument list to JSON objects in method-dependent way, + // and pass it along with the method name to the dispatcher. + json_spirit::Value result = tableRPC.execute( + args[0], + RPCConvertValues(args[0], std::vector(args.begin() + 1, args.end()))); + + // Format result reply + if (result.type() == json_spirit::null_type) + strPrint = ""; + else if (result.type() == json_spirit::str_type) + strPrint = result.get_str(); + else + strPrint = write_string(result, true); + + emit reply(RPCConsole::CMD_REPLY, QString::fromStdString(strPrint)); + } + catch (json_spirit::Object& objError) + { + try // Nice formatting for standard-format error + { + int code = find_value(objError, "code").get_int(); + std::string message = find_value(objError, "message").get_str(); + emit reply(RPCConsole::CMD_ERROR, QString::fromStdString(message) + " (code " + QString::number(code) + ")"); + } + catch(std::runtime_error &) // raised when converting to invalid type, i.e. missing code or message + { // Show raw JSON object + emit reply(RPCConsole::CMD_ERROR, QString::fromStdString(write_string(json_spirit::Value(objError), false))); + } + } + catch (std::exception& e) + { + emit reply(RPCConsole::CMD_ERROR, QString("Error: ") + QString::fromStdString(e.what())); + } +} + +RPCConsole::RPCConsole(QWidget *parent) : + QDialog(parent), + ui(new Ui::RPCConsole), + historyPtr(0) +{ + ui->setupUi(this); + +#ifndef Q_OS_MAC + ui->openDebugLogfileButton->setIcon(QIcon(":/icons/export")); + ui->showCLOptionsButton->setIcon(QIcon(":/icons/options")); +#endif + + // Install event filter for up and down arrow + ui->lineEdit->installEventFilter(this); + ui->messagesWidget->installEventFilter(this); + + connect(ui->clearButton, SIGNAL(clicked()), this, SLOT(clear())); + + // set OpenSSL version label + ui->openSSLVersion->setText(SSLeay_version(SSLEAY_VERSION)); + + startExecutor(); + + clear(); +} + +RPCConsole::~RPCConsole() +{ + emit stopExecutor(); + delete ui; +} + +bool RPCConsole::eventFilter(QObject* obj, QEvent *event) +{ + if(event->type() == QEvent::KeyPress) // Special key handling + { + QKeyEvent *keyevt = static_cast(event); + int key = keyevt->key(); + Qt::KeyboardModifiers mod = keyevt->modifiers(); + switch(key) + { + case Qt::Key_Up: if(obj == ui->lineEdit) { browseHistory(-1); return true; } break; + case Qt::Key_Down: if(obj == ui->lineEdit) { browseHistory(1); return true; } break; + case Qt::Key_PageUp: /* pass paging keys to messages widget */ + case Qt::Key_PageDown: + if(obj == ui->lineEdit) + { + QApplication::postEvent(ui->messagesWidget, new QKeyEvent(*keyevt)); + return true; + } + break; + default: + // Typing in messages widget brings focus to line edit, and redirects key there + // Exclude most combinations and keys that emit no text, except paste shortcuts + if(obj == ui->messagesWidget && ( + (!mod && !keyevt->text().isEmpty() && key != Qt::Key_Tab) || + ((mod & Qt::ControlModifier) && key == Qt::Key_V) || + ((mod & Qt::ShiftModifier) && key == Qt::Key_Insert))) + { + ui->lineEdit->setFocus(); + QApplication::postEvent(ui->lineEdit, new QKeyEvent(*keyevt)); + return true; + } + } + } + return QDialog::eventFilter(obj, event); +} + +void RPCConsole::setClientModel(ClientModel *model) +{ + this->clientModel = model; + if(model) + { + // Subscribe to information, replies, messages, errors + connect(model, SIGNAL(numConnectionsChanged(int)), this, SLOT(setNumConnections(int))); + connect(model, SIGNAL(numBlocksChanged(int,int)), this, SLOT(setNumBlocks(int,int))); + + // Provide initial values + ui->clientVersion->setText(model->formatFullVersion()); + ui->clientName->setText(model->clientName()); + ui->buildDate->setText(model->formatBuildDate()); + ui->startupTime->setText(model->formatClientStartupTime()); + + setNumConnections(model->getNumConnections()); + ui->isTestNet->setChecked(model->isTestNet()); + + setNumBlocks(model->getNumBlocks(), model->getNumBlocksOfPeers()); + } +} + +static QString categoryClass(int category) +{ + switch(category) + { + case RPCConsole::CMD_REQUEST: return "cmd-request"; break; + case RPCConsole::CMD_REPLY: return "cmd-reply"; break; + case RPCConsole::CMD_ERROR: return "cmd-error"; break; + default: return "misc"; + } +} + +void RPCConsole::clear() +{ + ui->messagesWidget->clear(); + ui->lineEdit->clear(); + ui->lineEdit->setFocus(); + + // Add smoothly scaled icon images. + // (when using width/height on an img, Qt uses nearest instead of linear interpolation) + for(int i=0; ICON_MAPPING[i].url; ++i) + { + ui->messagesWidget->document()->addResource( + QTextDocument::ImageResource, + QUrl(ICON_MAPPING[i].url), + QImage(ICON_MAPPING[i].source).scaled(ICON_SIZE, Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); + } + + // Set default style sheet + ui->messagesWidget->document()->setDefaultStyleSheet( + "table { }" + "td.time { color: #808080; padding-top: 3px; } " + "td.message { font-family: Monospace; font-size: 12px; } " + "td.cmd-request { color: #006060; } " + "td.cmd-error { color: red; } " + "b { color: #006060; } " + ); + + message(CMD_REPLY, (tr("Welcome to the triangles RPC console.") + "
" + + tr("Use up and down arrows to navigate history, and Ctrl-L to clear screen.") + "
" + + tr("Type help for an overview of available commands.")), true); +} + +void RPCConsole::message(int category, const QString &message, bool html) +{ + QTime time = QTime::currentTime(); + QString timeString = time.toString(); + QString out; + out += ""; + out += ""; + out += "
" + timeString + ""; + if(html) + out += message; + else + out += GUIUtil::HtmlEscape(message, true); + out += "
"; + ui->messagesWidget->append(out); +} + +void RPCConsole::setNumConnections(int count) +{ + ui->numberOfConnections->setText(QString::number(count)); +} + +void RPCConsole::setNumBlocks(int count, int countOfPeers) +{ + ui->numberOfBlocks->setText(QString::number(count)); + ui->totalBlocks->setText(QString::number(countOfPeers)); + if(clientModel) + { + // If there is no current number available display N/A instead of 0, which can't ever be true + ui->totalBlocks->setText(clientModel->getNumBlocksOfPeers() == 0 ? tr("N/A") : QString::number(clientModel->getNumBlocksOfPeers())); + ui->lastBlockTime->setText(clientModel->getLastBlockDate().toString()); + } +} + +void RPCConsole::on_lineEdit_returnPressed() +{ + QString cmd = ui->lineEdit->text(); + ui->lineEdit->clear(); + + if(!cmd.isEmpty()) + { + message(CMD_REQUEST, cmd); + emit cmdRequest(cmd); + // Truncate history from current position + history.erase(history.begin() + historyPtr, history.end()); + // Append command to history + history.append(cmd); + // Enforce maximum history size + while(history.size() > CONSOLE_HISTORY) + history.removeFirst(); + // Set pointer to end of history + historyPtr = history.size(); + // Scroll console view to end + scrollToEnd(); + } +} + +void RPCConsole::browseHistory(int offset) +{ + historyPtr += offset; + if(historyPtr < 0) + historyPtr = 0; + if(historyPtr > history.size()) + historyPtr = history.size(); + QString cmd; + if(historyPtr < history.size()) + cmd = history.at(historyPtr); + ui->lineEdit->setText(cmd); +} + +void RPCConsole::startExecutor() +{ + QThread* thread = new QThread; + RPCExecutor *executor = new RPCExecutor(); + executor->moveToThread(thread); + + // Notify executor when thread started (in executor thread) + connect(thread, SIGNAL(started()), executor, SLOT(start())); + // Replies from executor object must go to this object + connect(executor, SIGNAL(reply(int,QString)), this, SLOT(message(int,QString))); + // Requests from this object must go to executor + connect(this, SIGNAL(cmdRequest(QString)), executor, SLOT(request(QString))); + // On stopExecutor signal + // - queue executor for deletion (in execution thread) + // - quit the Qt event loop in the execution thread + connect(this, SIGNAL(stopExecutor()), executor, SLOT(deleteLater())); + connect(this, SIGNAL(stopExecutor()), thread, SLOT(quit())); + // Queue the thread for deletion (in this thread) when it is finished + connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); + + // Default implementation of QThread::run() simply spins up an event loop in the thread, + // which is what we want. + thread->start(); +} + +void RPCConsole::on_tabWidget_currentChanged(int index) +{ + if(ui->tabWidget->widget(index) == ui->tab_console) + { + ui->lineEdit->setFocus(); + } +} + +void RPCConsole::on_openDebugLogfileButton_clicked() +{ + GUIUtil::openDebugLogfile(); +} + +void RPCConsole::scrollToEnd() +{ + QScrollBar *scrollbar = ui->messagesWidget->verticalScrollBar(); + scrollbar->setValue(scrollbar->maximum()); +} + +void RPCConsole::on_showCLOptionsButton_clicked() +{ + GUIUtil::HelpMessageBox help; + help.exec(); +} diff --git a/src/qt/rpcconsole.h b/src/qt/rpcconsole.h new file mode 100644 index 0000000..3c38b4b --- /dev/null +++ b/src/qt/rpcconsole.h @@ -0,0 +1,66 @@ +#ifndef RPCCONSOLE_H +#define RPCCONSOLE_H + +#include + +namespace Ui { + class RPCConsole; +} +class ClientModel; + +/** Local Bitcoin RPC console. */ +class RPCConsole: public QDialog +{ + Q_OBJECT + +public: + explicit RPCConsole(QWidget *parent = 0); + ~RPCConsole(); + + void setClientModel(ClientModel *model); + + enum MessageClass { + MC_ERROR, + MC_DEBUG, + CMD_REQUEST, + CMD_REPLY, + CMD_ERROR + }; + +protected: + virtual bool eventFilter(QObject* obj, QEvent *event); + +private slots: + void on_lineEdit_returnPressed(); + void on_tabWidget_currentChanged(int index); + /** open the debug.log from the current datadir */ + void on_openDebugLogfileButton_clicked(); + /** display messagebox with program parameters (same as bitcoin-qt --help) */ + void on_showCLOptionsButton_clicked(); + +public slots: + void clear(); + void message(int category, const QString &message, bool html = false); + /** Set number of connections shown in the UI */ + void setNumConnections(int count); + /** Set number of blocks shown in the UI */ + void setNumBlocks(int count, int countOfPeers); + /** Go forward or back in history */ + void browseHistory(int offset); + /** Scroll console view to end */ + void scrollToEnd(); +signals: + // For RPC command executor + void stopExecutor(); + void cmdRequest(const QString &command); + +private: + Ui::RPCConsole *ui; + ClientModel *clientModel; + QStringList history; + int historyPtr; + + void startExecutor(); +}; + +#endif // RPCCONSOLE_H diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp new file mode 100644 index 0000000..bdcc388 --- /dev/null +++ b/src/qt/sendcoinsdialog.cpp @@ -0,0 +1,516 @@ +#include "sendcoinsdialog.h" +#include "ui_sendcoinsdialog.h" +#include "init.h" +#include "walletmodel.h" +#include "addresstablemodel.h" +#include "addressbookpage.h" +#include "bitcoinunits.h" +#include "addressbookpage.h" +#include "optionsmodel.h" +#include "sendcoinsentry.h" +#include "guiutil.h" +#include "askpassphrasedialog.h" +#include "coincontrol.h" +#include "coincontroldialog.h" + +#include +#include +#include +#include +#include + +SendCoinsDialog::SendCoinsDialog(QWidget *parent) : + QDialog(parent), + ui(new Ui::SendCoinsDialog), + model(0) +{ + ui->setupUi(this); + +#ifdef Q_OS_MAC // Icons on push buttons are very uncommon on Mac + ui->addButton->setIcon(QIcon()); + ui->clearButton->setIcon(QIcon()); + ui->sendButton->setIcon(QIcon()); +#endif + +#if QT_VERSION >= 0x040700 + /* Do not move this to the XML file, Qt before 4.7 will choke on it */ + ui->lineEditCoinControlChange->setPlaceholderText(tr("Enter a Triangles address (e.g. TrXW1RKLDe8VMNwTwLwSiKuATN5M74EL85)")); +#endif + + addEntry(); + + connect(ui->addButton, SIGNAL(clicked()), this, SLOT(addEntry())); + connect(ui->clearButton, SIGNAL(clicked()), this, SLOT(clear())); + + // Coin Control + ui->lineEditCoinControlChange->setFont(GUIUtil::bitcoinAddressFont()); + connect(ui->pushButtonCoinControl, SIGNAL(clicked()), this, SLOT(coinControlButtonClicked())); + connect(ui->checkBoxCoinControlChange, SIGNAL(stateChanged(int)), this, SLOT(coinControlChangeChecked(int))); + connect(ui->lineEditCoinControlChange, SIGNAL(textEdited(const QString &)), this, SLOT(coinControlChangeEdited(const QString &))); + + // Coin Control: clipboard actions + QAction *clipboardQuantityAction = new QAction(tr("Copy quantity"), this); + QAction *clipboardAmountAction = new QAction(tr("Copy amount"), this); + QAction *clipboardFeeAction = new QAction(tr("Copy fee"), this); + QAction *clipboardAfterFeeAction = new QAction(tr("Copy after fee"), this); + QAction *clipboardBytesAction = new QAction(tr("Copy bytes"), this); + QAction *clipboardPriorityAction = new QAction(tr("Copy priority"), this); + QAction *clipboardLowOutputAction = new QAction(tr("Copy low output"), this); + QAction *clipboardChangeAction = new QAction(tr("Copy change"), this); + connect(clipboardQuantityAction, SIGNAL(triggered()), this, SLOT(coinControlClipboardQuantity())); + connect(clipboardAmountAction, SIGNAL(triggered()), this, SLOT(coinControlClipboardAmount())); + connect(clipboardFeeAction, SIGNAL(triggered()), this, SLOT(coinControlClipboardFee())); + connect(clipboardAfterFeeAction, SIGNAL(triggered()), this, SLOT(coinControlClipboardAfterFee())); + connect(clipboardBytesAction, SIGNAL(triggered()), this, SLOT(coinControlClipboardBytes())); + connect(clipboardPriorityAction, SIGNAL(triggered()), this, SLOT(coinControlClipboardPriority())); + connect(clipboardLowOutputAction, SIGNAL(triggered()), this, SLOT(coinControlClipboardLowOutput())); + connect(clipboardChangeAction, SIGNAL(triggered()), this, SLOT(coinControlClipboardChange())); + ui->labelCoinControlQuantity->addAction(clipboardQuantityAction); + ui->labelCoinControlAmount->addAction(clipboardAmountAction); + ui->labelCoinControlFee->addAction(clipboardFeeAction); + ui->labelCoinControlAfterFee->addAction(clipboardAfterFeeAction); + ui->labelCoinControlBytes->addAction(clipboardBytesAction); + ui->labelCoinControlPriority->addAction(clipboardPriorityAction); + ui->labelCoinControlLowOutput->addAction(clipboardLowOutputAction); + ui->labelCoinControlChange->addAction(clipboardChangeAction); + + fNewRecipientAllowed = true; +} + +void SendCoinsDialog::setModel(WalletModel *model) +{ + this->model = model; + + for(int i = 0; i < ui->entries->count(); ++i) + { + SendCoinsEntry *entry = qobject_cast(ui->entries->itemAt(i)->widget()); + if(entry) + { + entry->setModel(model); + } + } + if(model && model->getOptionsModel()) + { + setBalance(model->getBalance(), model->getStake(), model->getUnconfirmedBalance(), model->getImmatureBalance()); + connect(model, SIGNAL(balanceChanged(qint64, qint64, qint64, qint64)), this, SLOT(setBalance(qint64, qint64, qint64, qint64))); + connect(model->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit())); + + // Coin Control + connect(model->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(coinControlUpdateLabels())); + connect(model->getOptionsModel(), SIGNAL(coinControlFeaturesChanged(bool)), this, SLOT(coinControlFeatureChanged(bool))); + connect(model->getOptionsModel(), SIGNAL(transactionFeeChanged(qint64)), this, SLOT(coinControlUpdateLabels())); + ui->frameCoinControl->setVisible(model->getOptionsModel()->getCoinControlFeatures()); + coinControlUpdateLabels(); + } +} + +SendCoinsDialog::~SendCoinsDialog() +{ + delete ui; +} + +void SendCoinsDialog::on_sendButton_clicked() +{ + QList recipients; + bool valid = true; + + if(!model) + return; + + for(int i = 0; i < ui->entries->count(); ++i) + { + SendCoinsEntry *entry = qobject_cast(ui->entries->itemAt(i)->widget()); + if(entry) + { + if(entry->validate()) + { + recipients.append(entry->getValue()); + } + else + { + valid = false; + } + } + } + + if(!valid || recipients.isEmpty()) + { + return; + } + + // Format confirmation message + QStringList formatted; + foreach(const SendCoinsRecipient &rcp, recipients) + { + formatted.append(tr("%1 to %2 (%3)").arg(BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, rcp.amount), Qt::escape(rcp.label), rcp.address)); + } + + fNewRecipientAllowed = false; + + QMessageBox::StandardButton retval = QMessageBox::question(this, tr("Confirm send coins"), + tr("Are you sure you want to send %1?").arg(formatted.join(tr(" and "))), + QMessageBox::Yes|QMessageBox::Cancel, + QMessageBox::Cancel); + + if(retval != QMessageBox::Yes) + { + fNewRecipientAllowed = true; + return; + } + + WalletModel::UnlockContext ctx(model->requestUnlock()); + if(!ctx.isValid()) + { + // Unlock wallet was cancelled + fNewRecipientAllowed = true; + return; + } + + WalletModel::SendCoinsReturn sendstatus; + + if (!model->getOptionsModel() || !model->getOptionsModel()->getCoinControlFeatures()) + sendstatus = model->sendCoins(recipients); + else + sendstatus = model->sendCoins(recipients, CoinControlDialog::coinControl); + + switch(sendstatus.status) + { + case WalletModel::InvalidAddress: + QMessageBox::warning(this, tr("Send Coins"), + tr("The recipient address is not valid, please recheck."), + QMessageBox::Ok, QMessageBox::Ok); + break; + case WalletModel::InvalidAmount: + QMessageBox::warning(this, tr("Send Coins"), + tr("The amount to pay must be larger than 0."), + QMessageBox::Ok, QMessageBox::Ok); + break; + case WalletModel::AmountExceedsBalance: + QMessageBox::warning(this, tr("Send Coins"), + tr("The amount exceeds your balance."), + QMessageBox::Ok, QMessageBox::Ok); + break; + case WalletModel::AmountWithFeeExceedsBalance: + QMessageBox::warning(this, tr("Send Coins"), + tr("The total exceeds your balance when the %1 transaction fee is included."). + arg(BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, sendstatus.fee)), + QMessageBox::Ok, QMessageBox::Ok); + break; + case WalletModel::DuplicateAddress: + QMessageBox::warning(this, tr("Send Coins"), + tr("Duplicate address found, can only send to each address once per send operation."), + QMessageBox::Ok, QMessageBox::Ok); + break; + case WalletModel::TransactionCreationFailed: + QMessageBox::warning(this, tr("Send Coins"), + tr("Error: Transaction creation failed."), + QMessageBox::Ok, QMessageBox::Ok); + break; + case WalletModel::TransactionCommitFailed: + QMessageBox::warning(this, tr("Send Coins"), + tr("Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here."), + QMessageBox::Ok, QMessageBox::Ok); + break; + case WalletModel::Aborted: // User aborted, nothing to do + break; + case WalletModel::OK: + accept(); + CoinControlDialog::coinControl->UnSelectAll(); + coinControlUpdateLabels(); + break; + } + fNewRecipientAllowed = true; +} + +void SendCoinsDialog::clear() +{ + // Remove entries until only one left + while(ui->entries->count()) + { + delete ui->entries->takeAt(0)->widget(); + } + addEntry(); + + updateRemoveEnabled(); + + ui->sendButton->setDefault(true); +} + +void SendCoinsDialog::reject() +{ + clear(); +} + +void SendCoinsDialog::accept() +{ + clear(); +} + +SendCoinsEntry *SendCoinsDialog::addEntry() +{ + SendCoinsEntry *entry = new SendCoinsEntry(this); + entry->setModel(model); + ui->entries->addWidget(entry); + connect(entry, SIGNAL(removeEntry(SendCoinsEntry*)), this, SLOT(removeEntry(SendCoinsEntry*))); + connect(entry, SIGNAL(payAmountChanged()), this, SLOT(coinControlUpdateLabels())); + + updateRemoveEnabled(); + + // Focus the field, so that entry can start immediately + entry->clear(); + entry->setFocus(); + ui->scrollAreaWidgetContents->resize(ui->scrollAreaWidgetContents->sizeHint()); + QCoreApplication::instance()->processEvents(); + QScrollBar* bar = ui->scrollArea->verticalScrollBar(); + if(bar) + bar->setSliderPosition(bar->maximum()); + return entry; +} + +void SendCoinsDialog::updateRemoveEnabled() +{ + // Remove buttons are enabled as soon as there is more than one send-entry + bool enabled = (ui->entries->count() > 1); + for(int i = 0; i < ui->entries->count(); ++i) + { + SendCoinsEntry *entry = qobject_cast(ui->entries->itemAt(i)->widget()); + if(entry) + { + entry->setRemoveEnabled(enabled); + } + } + setupTabChain(0); + coinControlUpdateLabels(); +} + +void SendCoinsDialog::removeEntry(SendCoinsEntry* entry) +{ + delete entry; + updateRemoveEnabled(); +} + +QWidget *SendCoinsDialog::setupTabChain(QWidget *prev) +{ + for(int i = 0; i < ui->entries->count(); ++i) + { + SendCoinsEntry *entry = qobject_cast(ui->entries->itemAt(i)->widget()); + if(entry) + { + prev = entry->setupTabChain(prev); + } + } + QWidget::setTabOrder(prev, ui->addButton); + QWidget::setTabOrder(ui->addButton, ui->sendButton); + return ui->sendButton; +} + +void SendCoinsDialog::pasteEntry(const SendCoinsRecipient &rv) +{ + if(!fNewRecipientAllowed) + return; + + SendCoinsEntry *entry = 0; + // Replace the first entry if it is still unused + if(ui->entries->count() == 1) + { + SendCoinsEntry *first = qobject_cast(ui->entries->itemAt(0)->widget()); + if(first->isClear()) + { + entry = first; + } + } + if(!entry) + { + entry = addEntry(); + } + + entry->setValue(rv); +} + +bool SendCoinsDialog::handleURI(const QString &uri) +{ + SendCoinsRecipient rv; + // URI has to be valid + if (GUIUtil::parseBitcoinURI(uri, &rv)) + { + CBitcoinAddress address(rv.address.toStdString()); + if (!address.IsValid()) + return false; + pasteEntry(rv); + return true; + } + + return false; +} + +void SendCoinsDialog::setBalance(qint64 balance, qint64 stake, qint64 unconfirmedBalance, qint64 immatureBalance) +{ + Q_UNUSED(stake); + Q_UNUSED(unconfirmedBalance); + Q_UNUSED(immatureBalance); + if(!model || !model->getOptionsModel()) + return; + + int unit = model->getOptionsModel()->getDisplayUnit(); + ui->labelBalance->setText(BitcoinUnits::formatWithUnit(unit, balance)); +} + +void SendCoinsDialog::updateDisplayUnit() +{ + if(model && model->getOptionsModel()) + { + // Update labelBalance with the current balance and the current unit + ui->labelBalance->setText(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), model->getBalance())); + } +} + + // Coin Control: copy label "Quantity" to clipboard + void SendCoinsDialog::coinControlClipboardQuantity() + { + QApplication::clipboard()->setText(ui->labelCoinControlQuantity->text()); + } + + // Coin Control: copy label "Amount" to clipboard + void SendCoinsDialog::coinControlClipboardAmount() + { + QApplication::clipboard()->setText(ui->labelCoinControlAmount->text().left(ui->labelCoinControlAmount->text().indexOf(" "))); + } + + // Coin Control: copy label "Fee" to clipboard + void SendCoinsDialog::coinControlClipboardFee() + { + QApplication::clipboard()->setText(ui->labelCoinControlFee->text().left(ui->labelCoinControlFee->text().indexOf(" "))); + } + + // Coin Control: copy label "After fee" to clipboard + void SendCoinsDialog::coinControlClipboardAfterFee() + { + QApplication::clipboard()->setText(ui->labelCoinControlAfterFee->text().left(ui->labelCoinControlAfterFee->text().indexOf(" "))); + } + + // Coin Control: copy label "Bytes" to clipboard + void SendCoinsDialog::coinControlClipboardBytes() + { + QApplication::clipboard()->setText(ui->labelCoinControlBytes->text()); + } + + // Coin Control: copy label "Priority" to clipboard + void SendCoinsDialog::coinControlClipboardPriority() + { + QApplication::clipboard()->setText(ui->labelCoinControlPriority->text()); + } + + // Coin Control: copy label "Low output" to clipboard + void SendCoinsDialog::coinControlClipboardLowOutput() + { + QApplication::clipboard()->setText(ui->labelCoinControlLowOutput->text()); + } + + // Coin Control: copy label "Change" to clipboard + void SendCoinsDialog::coinControlClipboardChange() + { + QApplication::clipboard()->setText(ui->labelCoinControlChange->text().left(ui->labelCoinControlChange->text().indexOf(" "))); + } + + // Coin Control: settings menu - coin control enabled/disabled by user + void SendCoinsDialog::coinControlFeatureChanged(bool checked) + { + ui->frameCoinControl->setVisible(checked); + + if (!checked && model) // coin control features disabled + CoinControlDialog::coinControl->SetNull(); + } + + // Coin Control: button inputs -> show actual coin control dialog + void SendCoinsDialog::coinControlButtonClicked() + { + CoinControlDialog dlg; + dlg.setModel(model); + dlg.exec(); + coinControlUpdateLabels(); + } + + // Coin Control: checkbox custom change address + void SendCoinsDialog::coinControlChangeChecked(int state) + { + if (model) + { + if (state == Qt::Checked) + CoinControlDialog::coinControl->destChange = CBitcoinAddress(ui->lineEditCoinControlChange->text().toStdString()).Get(); + else + CoinControlDialog::coinControl->destChange = CNoDestination(); + } + + ui->lineEditCoinControlChange->setEnabled((state == Qt::Checked)); + ui->labelCoinControlChangeLabel->setEnabled((state == Qt::Checked)); + } + + // Coin Control: custom change address changed + void SendCoinsDialog::coinControlChangeEdited(const QString & text) + { + if (model) + { + CoinControlDialog::coinControl->destChange = CBitcoinAddress(text.toStdString()).Get(); + + // label for the change address + ui->labelCoinControlChangeLabel->setStyleSheet("QLabel{color:black;}"); + if (text.isEmpty()) + ui->labelCoinControlChangeLabel->setText(""); + else if (!CBitcoinAddress(text.toStdString()).IsValid()) + { + ui->labelCoinControlChangeLabel->setStyleSheet("QLabel{color:red;}"); + ui->labelCoinControlChangeLabel->setText(tr("WARNING: Invalid Triangle address")); + } + else + { + QString associatedLabel = model->getAddressTableModel()->labelForAddress(text); + if (!associatedLabel.isEmpty()) + ui->labelCoinControlChangeLabel->setText(associatedLabel); + else + { + CPubKey pubkey; + CKeyID keyid; + CBitcoinAddress(text.toStdString()).GetKeyID(keyid); + if (model->getPubKey(keyid, pubkey)) + ui->labelCoinControlChangeLabel->setText(tr("(no label)")); + else + { + ui->labelCoinControlChangeLabel->setStyleSheet("QLabel{color:red;}"); + ui->labelCoinControlChangeLabel->setText(tr("WARNING: unknown change address")); + } + } + } + } + } + + // Coin Control: update labels + void SendCoinsDialog::coinControlUpdateLabels() + { + if (!model || !model->getOptionsModel() || !model->getOptionsModel()->getCoinControlFeatures()) + return; + // set pay amounts + CoinControlDialog::payAmounts.clear(); + for(int i = 0; i < ui->entries->count(); ++i) + { + SendCoinsEntry *entry = qobject_cast(ui->entries->itemAt(i)->widget()); + if(entry) + CoinControlDialog::payAmounts.append(entry->getValue().amount); + } + if (CoinControlDialog::coinControl->HasSelected()) + { + // actual coin control calculation + CoinControlDialog::updateLabels(model, this); + // show coin control stats + ui->labelCoinControlAutomaticallySelected->hide(); + ui->widgetCoinControl->show(); + } + else + { + // hide coin control stats + ui->labelCoinControlAutomaticallySelected->show(); + ui->widgetCoinControl->hide(); + ui->labelCoinControlInsuffFunds->hide(); + } +} + + diff --git a/src/qt/sendcoinsdialog.h b/src/qt/sendcoinsdialog.h new file mode 100644 index 0000000..68424bb --- /dev/null +++ b/src/qt/sendcoinsdialog.h @@ -0,0 +1,68 @@ +#ifndef SENDCOINSDIALOG_H +#define SENDCOINSDIALOG_H + +#include +#include + +namespace Ui { + class SendCoinsDialog; +} +class WalletModel; +class SendCoinsEntry; +class SendCoinsRecipient; + +QT_BEGIN_NAMESPACE +class QUrl; +QT_END_NAMESPACE + +/** Dialog for sending bitcoins */ +class SendCoinsDialog : public QDialog +{ + Q_OBJECT + +public: + explicit SendCoinsDialog(QWidget *parent = 0); + ~SendCoinsDialog(); + + void setModel(WalletModel *model); + + /** Set up the tab chain manually, as Qt messes up the tab chain by default in some cases (issue https://bugreports.qt-project.org/browse/QTBUG-10907). + */ + QWidget *setupTabChain(QWidget *prev); + + void pasteEntry(const SendCoinsRecipient &rv); + bool handleURI(const QString &uri); + +public slots: + void clear(); + void reject(); + void accept(); + SendCoinsEntry *addEntry(); + void updateRemoveEnabled(); + void setBalance(qint64 balance, qint64 stake, qint64 unconfirmedBalance, qint64 immatureBalance); + +private: + Ui::SendCoinsDialog *ui; + WalletModel *model; + bool fNewRecipientAllowed; + +private slots: + void on_sendButton_clicked(); + void removeEntry(SendCoinsEntry* entry); + void updateDisplayUnit(); + void coinControlFeatureChanged(bool); + void coinControlButtonClicked(); + void coinControlChangeChecked(int); + void coinControlChangeEdited(const QString &); + void coinControlUpdateLabels(); + void coinControlClipboardQuantity(); + void coinControlClipboardAmount(); + void coinControlClipboardFee(); + void coinControlClipboardAfterFee(); + void coinControlClipboardBytes(); + void coinControlClipboardPriority(); + void coinControlClipboardLowOutput(); + void coinControlClipboardChange(); +}; + +#endif // SENDCOINSDIALOG_H diff --git a/src/qt/sendcoinsentry.cpp b/src/qt/sendcoinsentry.cpp new file mode 100644 index 0000000..fa3d2d9 --- /dev/null +++ b/src/qt/sendcoinsentry.cpp @@ -0,0 +1,175 @@ +#include "sendcoinsentry.h" +#include "ui_sendcoinsentry.h" +#include "guiutil.h" +#include "bitcoinunits.h" +#include "addressbookpage.h" +#include "walletmodel.h" +#include "optionsmodel.h" +#include "addresstablemodel.h" + +#include +#include + +SendCoinsEntry::SendCoinsEntry(QWidget *parent) : + QFrame(parent), + ui(new Ui::SendCoinsEntry), + model(0) +{ + ui->setupUi(this); + +#ifdef Q_OS_MAC + ui->payToLayout->setSpacing(4); +#endif +#if QT_VERSION >= 0x040700 + /* Do not move this to the XML file, Qt before 4.7 will choke on it */ + ui->addAsLabel->setPlaceholderText(tr("Enter a label for this address to add it to your address book")); + ui->payTo->setPlaceholderText(tr("Enter a valid Triangles address")); +#endif + setFocusPolicy(Qt::TabFocus); + setFocusProxy(ui->payTo); + + GUIUtil::setupAddressWidget(ui->payTo, this); +} + +SendCoinsEntry::~SendCoinsEntry() +{ + delete ui; +} + +void SendCoinsEntry::on_pasteButton_clicked() +{ + // Paste text from clipboard into recipient field + ui->payTo->setText(QApplication::clipboard()->text()); +} + +void SendCoinsEntry::on_addressBookButton_clicked() +{ + if(!model) + return; + AddressBookPage dlg(AddressBookPage::ForSending, AddressBookPage::SendingTab, this); + dlg.setModel(model->getAddressTableModel()); + if(dlg.exec()) + { + ui->payTo->setText(dlg.getReturnValue()); + ui->payAmount->setFocus(); + } +} + +void SendCoinsEntry::on_payTo_textChanged(const QString &address) +{ + if(!model) + return; + // Fill in label from address book, if address has an associated label + QString associatedLabel = model->getAddressTableModel()->labelForAddress(address); + if(!associatedLabel.isEmpty()) + ui->addAsLabel->setText(associatedLabel); +} + +void SendCoinsEntry::setModel(WalletModel *model) +{ + this->model = model; + + if(model && model->getOptionsModel()) + connect(model->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit())); + + connect(ui->payAmount, SIGNAL(textChanged()), this, SIGNAL(payAmountChanged())); + + clear(); +} + +void SendCoinsEntry::setRemoveEnabled(bool enabled) +{ + ui->deleteButton->setEnabled(enabled); +} + +void SendCoinsEntry::clear() +{ + ui->payTo->clear(); + ui->addAsLabel->clear(); + ui->payAmount->clear(); + ui->payTo->setFocus(); + // update the display unit, to not use the default ("BTC") + updateDisplayUnit(); +} + +void SendCoinsEntry::on_deleteButton_clicked() +{ + emit removeEntry(this); +} + +bool SendCoinsEntry::validate() +{ + // Check input validity + bool retval = true; + + if(!ui->payAmount->validate()) + { + retval = false; + } + else + { + if(ui->payAmount->value() <= 0) + { + // Cannot send 0 coins or less + ui->payAmount->setValid(false); + retval = false; + } + } + + if(!ui->payTo->hasAcceptableInput() || + (model && !model->validateAddress(ui->payTo->text()))) + { + ui->payTo->setValid(false); + retval = false; + } + + return retval; +} + +SendCoinsRecipient SendCoinsEntry::getValue() +{ + SendCoinsRecipient rv; + + rv.address = ui->payTo->text(); + rv.label = ui->addAsLabel->text(); + rv.amount = ui->payAmount->value(); + + return rv; +} + +QWidget *SendCoinsEntry::setupTabChain(QWidget *prev) +{ + QWidget::setTabOrder(prev, ui->payTo); + QWidget::setTabOrder(ui->payTo, ui->addressBookButton); + QWidget::setTabOrder(ui->addressBookButton, ui->pasteButton); + QWidget::setTabOrder(ui->pasteButton, ui->deleteButton); + QWidget::setTabOrder(ui->deleteButton, ui->addAsLabel); + + return ui->payAmount->setupTabChain(ui->addAsLabel); +} + +void SendCoinsEntry::setValue(const SendCoinsRecipient &value) +{ + ui->payTo->setText(value.address); + ui->addAsLabel->setText(value.label); + ui->payAmount->setValue(value.amount); +} + +bool SendCoinsEntry::isClear() +{ + return ui->payTo->text().isEmpty(); +} + +void SendCoinsEntry::setFocus() +{ + ui->payTo->setFocus(); +} + +void SendCoinsEntry::updateDisplayUnit() +{ + if(model && model->getOptionsModel()) + { + // Update payAmount with the current unit + ui->payAmount->setDisplayUnit(model->getOptionsModel()->getDisplayUnit()); + } +} diff --git a/src/qt/sendcoinsentry.h b/src/qt/sendcoinsentry.h new file mode 100644 index 0000000..4148128 --- /dev/null +++ b/src/qt/sendcoinsentry.h @@ -0,0 +1,56 @@ +#ifndef SENDCOINSENTRY_H +#define SENDCOINSENTRY_H + +#include + +namespace Ui { + class SendCoinsEntry; +} +class WalletModel; +class SendCoinsRecipient; + +/** A single entry in the dialog for sending bitcoins. */ +class SendCoinsEntry : public QFrame +{ + Q_OBJECT + +public: + explicit SendCoinsEntry(QWidget *parent = 0); + ~SendCoinsEntry(); + + void setModel(WalletModel *model); + bool validate(); + SendCoinsRecipient getValue(); + + /** Return whether the entry is still empty and unedited */ + bool isClear(); + + void setValue(const SendCoinsRecipient &value); + + /** Set up the tab chain manually, as Qt messes up the tab chain by default in some cases (issue https://bugreports.qt-project.org/browse/QTBUG-10907). + */ + QWidget *setupTabChain(QWidget *prev); + + void setFocus(); + +public slots: + void setRemoveEnabled(bool enabled); + void clear(); + +signals: + void removeEntry(SendCoinsEntry *entry); + void payAmountChanged(); + +private slots: + void on_deleteButton_clicked(); + void on_payTo_textChanged(const QString &address); + void on_addressBookButton_clicked(); + void on_pasteButton_clicked(); + void updateDisplayUnit(); + +private: + Ui::SendCoinsEntry *ui; + WalletModel *model; +}; + +#endif // SENDCOINSENTRY_H diff --git a/src/qt/signverifymessagedialog.cpp b/src/qt/signverifymessagedialog.cpp new file mode 100644 index 0000000..6e130f6 --- /dev/null +++ b/src/qt/signverifymessagedialog.cpp @@ -0,0 +1,274 @@ +#include "signverifymessagedialog.h" +#include "ui_signverifymessagedialog.h" + +#include "addressbookpage.h" +#include "base58.h" +#include "guiutil.h" +#include "init.h" +#include "main.h" +#include "optionsmodel.h" +#include "walletmodel.h" +#include "wallet.h" + +#include +#include + +#include + +SignVerifyMessageDialog::SignVerifyMessageDialog(QWidget *parent) : + QDialog(parent), + ui(new Ui::SignVerifyMessageDialog), + model(0) +{ + ui->setupUi(this); + +#if (QT_VERSION >= 0x040700) + /* Do not move this to the XML file, Qt before 4.7 will choke on it */ + ui->addressIn_SM->setPlaceholderText(tr("Enter a valid Triangles address")); + ui->signatureOut_SM->setPlaceholderText(tr("Click \"Sign Message\" to generate signature")); + + ui->addressIn_VM->setPlaceholderText(tr("Enter a valid Triangles address")); + ui->signatureIn_VM->setPlaceholderText(tr("Enter Triangles signature")); +#endif + + GUIUtil::setupAddressWidget(ui->addressIn_SM, this); + GUIUtil::setupAddressWidget(ui->addressIn_VM, this); + + ui->addressIn_SM->installEventFilter(this); + ui->messageIn_SM->installEventFilter(this); + ui->signatureOut_SM->installEventFilter(this); + ui->addressIn_VM->installEventFilter(this); + ui->messageIn_VM->installEventFilter(this); + ui->signatureIn_VM->installEventFilter(this); + + ui->signatureOut_SM->setFont(GUIUtil::bitcoinAddressFont()); + ui->signatureIn_VM->setFont(GUIUtil::bitcoinAddressFont()); +} + +SignVerifyMessageDialog::~SignVerifyMessageDialog() +{ + delete ui; +} + +void SignVerifyMessageDialog::setModel(WalletModel *model) +{ + this->model = model; +} + +void SignVerifyMessageDialog::setAddress_SM(QString address) +{ + ui->addressIn_SM->setText(address); + ui->messageIn_SM->setFocus(); +} + +void SignVerifyMessageDialog::setAddress_VM(QString address) +{ + ui->addressIn_VM->setText(address); + ui->messageIn_VM->setFocus(); +} + +void SignVerifyMessageDialog::showTab_SM(bool fShow) +{ + ui->tabWidget->setCurrentIndex(0); + + if (fShow) + this->show(); +} + +void SignVerifyMessageDialog::showTab_VM(bool fShow) +{ + ui->tabWidget->setCurrentIndex(1); + if (fShow) + this->show(); +} + +void SignVerifyMessageDialog::on_addressBookButton_SM_clicked() +{ + if (model && model->getAddressTableModel()) + { + AddressBookPage dlg(AddressBookPage::ForSending, AddressBookPage::ReceivingTab, this); + dlg.setModel(model->getAddressTableModel()); + if (dlg.exec()) + { + setAddress_SM(dlg.getReturnValue()); + } + } +} + +void SignVerifyMessageDialog::on_pasteButton_SM_clicked() +{ + setAddress_SM(QApplication::clipboard()->text()); +} + +void SignVerifyMessageDialog::on_signMessageButton_SM_clicked() +{ + /* Clear old signature to ensure users don't get confused on error with an old signature displayed */ + ui->signatureOut_SM->clear(); + + CBitcoinAddress addr(ui->addressIn_SM->text().toStdString()); + if (!addr.IsValid()) + { + ui->addressIn_SM->setValid(false); + ui->statusLabel_SM->setStyleSheet("QLabel { color: red; }"); + ui->statusLabel_SM->setText(tr("The entered address is invalid.") + QString(" ") + tr("Please check the address and try again.")); + return; + } + CKeyID keyID; + if (!addr.GetKeyID(keyID)) + { + ui->addressIn_SM->setValid(false); + ui->statusLabel_SM->setStyleSheet("QLabel { color: red; }"); + ui->statusLabel_SM->setText(tr("The entered address does not refer to a key.") + QString(" ") + tr("Please check the address and try again.")); + return; + } + + WalletModel::UnlockContext ctx(model->requestUnlock()); + if (!ctx.isValid()) + { + ui->statusLabel_SM->setStyleSheet("QLabel { color: red; }"); + ui->statusLabel_SM->setText(tr("Wallet unlock was cancelled.")); + return; + } + + CKey key; + if (!pwalletMain->GetKey(keyID, key)) + { + ui->statusLabel_SM->setStyleSheet("QLabel { color: red; }"); + ui->statusLabel_SM->setText(tr("Private key for the entered address is not available.")); + return; + } + + CDataStream ss(SER_GETHASH, 0); + ss << strMessageMagic; + ss << ui->messageIn_SM->document()->toPlainText().toStdString(); + + std::vector vchSig; + if (!key.SignCompact(Hash(ss.begin(), ss.end()), vchSig)) + { + ui->statusLabel_SM->setStyleSheet("QLabel { color: red; }"); + ui->statusLabel_SM->setText(QString("") + tr("Message signing failed.") + QString("")); + return; + } + + ui->statusLabel_SM->setStyleSheet("QLabel { color: green; }"); + ui->statusLabel_SM->setText(QString("") + tr("Message signed.") + QString("")); + + ui->signatureOut_SM->setText(QString::fromStdString(EncodeBase64(&vchSig[0], vchSig.size()))); +} + +void SignVerifyMessageDialog::on_copySignatureButton_SM_clicked() +{ + QApplication::clipboard()->setText(ui->signatureOut_SM->text()); +} + +void SignVerifyMessageDialog::on_clearButton_SM_clicked() +{ + ui->addressIn_SM->clear(); + ui->messageIn_SM->clear(); + ui->signatureOut_SM->clear(); + ui->statusLabel_SM->clear(); + + ui->addressIn_SM->setFocus(); +} + +void SignVerifyMessageDialog::on_addressBookButton_VM_clicked() +{ + if (model && model->getAddressTableModel()) + { + AddressBookPage dlg(AddressBookPage::ForSending, AddressBookPage::SendingTab, this); + dlg.setModel(model->getAddressTableModel()); + if (dlg.exec()) + { + setAddress_VM(dlg.getReturnValue()); + } + } +} + +void SignVerifyMessageDialog::on_verifyMessageButton_VM_clicked() +{ + CBitcoinAddress addr(ui->addressIn_VM->text().toStdString()); + if (!addr.IsValid()) + { + ui->addressIn_VM->setValid(false); + ui->statusLabel_VM->setStyleSheet("QLabel { color: red; }"); + ui->statusLabel_VM->setText(tr("The entered address is invalid.") + QString(" ") + tr("Please check the address and try again.")); + return; + } + CKeyID keyID; + if (!addr.GetKeyID(keyID)) + { + ui->addressIn_VM->setValid(false); + ui->statusLabel_VM->setStyleSheet("QLabel { color: red; }"); + ui->statusLabel_VM->setText(tr("The entered address does not refer to a key.") + QString(" ") + tr("Please check the address and try again.")); + return; + } + + bool fInvalid = false; + std::vector vchSig = DecodeBase64(ui->signatureIn_VM->text().toStdString().c_str(), &fInvalid); + + if (fInvalid) + { + ui->signatureIn_VM->setValid(false); + ui->statusLabel_VM->setStyleSheet("QLabel { color: red; }"); + ui->statusLabel_VM->setText(tr("The signature could not be decoded.") + QString(" ") + tr("Please check the signature and try again.")); + return; + } + + CDataStream ss(SER_GETHASH, 0); + ss << strMessageMagic; + ss << ui->messageIn_VM->document()->toPlainText().toStdString(); + + CKey key; + if (!key.SetCompactSignature(Hash(ss.begin(), ss.end()), vchSig)) + { + ui->signatureIn_VM->setValid(false); + ui->statusLabel_VM->setStyleSheet("QLabel { color: red; }"); + ui->statusLabel_VM->setText(tr("The signature did not match the message digest.") + QString(" ") + tr("Please check the signature and try again.")); + return; + } + + if (!(CBitcoinAddress(key.GetPubKey().GetID()) == addr)) + { + ui->statusLabel_VM->setStyleSheet("QLabel { color: red; }"); + ui->statusLabel_VM->setText(QString("") + tr("Message verification failed.") + QString("")); + return; + } + + ui->statusLabel_VM->setStyleSheet("QLabel { color: green; }"); + ui->statusLabel_VM->setText(QString("") + tr("Message verified.") + QString("")); +} + +void SignVerifyMessageDialog::on_clearButton_VM_clicked() +{ + ui->addressIn_VM->clear(); + ui->signatureIn_VM->clear(); + ui->messageIn_VM->clear(); + ui->statusLabel_VM->clear(); + + ui->addressIn_VM->setFocus(); +} + +bool SignVerifyMessageDialog::eventFilter(QObject *object, QEvent *event) +{ + if (event->type() == QEvent::MouseButtonPress || event->type() == QEvent::FocusIn) + { + if (ui->tabWidget->currentIndex() == 0) + { + /* Clear status message on focus change */ + ui->statusLabel_SM->clear(); + + /* Select generated signature */ + if (object == ui->signatureOut_SM) + { + ui->signatureOut_SM->selectAll(); + return true; + } + } + else if (ui->tabWidget->currentIndex() == 1) + { + /* Clear status message on focus change */ + ui->statusLabel_VM->clear(); + } + } + return QDialog::eventFilter(object, event); +} diff --git a/src/qt/signverifymessagedialog.h b/src/qt/signverifymessagedialog.h new file mode 100644 index 0000000..5569c8b --- /dev/null +++ b/src/qt/signverifymessagedialog.h @@ -0,0 +1,49 @@ +#ifndef SIGNVERIFYMESSAGEDIALOG_H +#define SIGNVERIFYMESSAGEDIALOG_H + +#include + +namespace Ui { + class SignVerifyMessageDialog; +} +class WalletModel; + +QT_BEGIN_NAMESPACE +QT_END_NAMESPACE + +class SignVerifyMessageDialog : public QDialog +{ + Q_OBJECT + +public: + explicit SignVerifyMessageDialog(QWidget *parent = 0); + ~SignVerifyMessageDialog(); + + void setModel(WalletModel *model); + void setAddress_SM(QString address); + void setAddress_VM(QString address); + + void showTab_SM(bool fShow); + void showTab_VM(bool fShow); + +protected: + bool eventFilter(QObject *object, QEvent *event); + +private: + Ui::SignVerifyMessageDialog *ui; + WalletModel *model; + +private slots: + /* sign message */ + void on_addressBookButton_SM_clicked(); + void on_pasteButton_SM_clicked(); + void on_signMessageButton_SM_clicked(); + void on_copySignatureButton_SM_clicked(); + void on_clearButton_SM_clicked(); + /* verify message */ + void on_addressBookButton_VM_clicked(); + void on_verifyMessageButton_VM_clicked(); + void on_clearButton_VM_clicked(); +}; + +#endif // SIGNVERIFYMESSAGEDIALOG_H diff --git a/src/qt/test/test_main.cpp b/src/qt/test/test_main.cpp new file mode 100644 index 0000000..3c7794b --- /dev/null +++ b/src/qt/test/test_main.cpp @@ -0,0 +1,16 @@ +#include +#include + +#include "uritests.h" + +// This is all you need to run all the tests +int main(int argc, char *argv[]) +{ + bool fInvalid = false; + + URITests test1; + if (QTest::qExec(&test1) != 0) + fInvalid = true; + + return fInvalid; +} diff --git a/src/qt/test/uritests.cpp b/src/qt/test/uritests.cpp new file mode 100644 index 0000000..4662f5e --- /dev/null +++ b/src/qt/test/uritests.cpp @@ -0,0 +1,71 @@ +#include "uritests.h" +#include "../guiutil.h" +#include "../walletmodel.h" + +#include + +/* +struct SendCoinsRecipient +{ + QString address; + QString label; + qint64 amount; +}; +*/ + +void URITests::uriTests() +{ + SendCoinsRecipient rv; + QUrl uri; + uri.setUrl(QString("bitcoin:175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W?req-dontexist=")); + QVERIFY(!GUIUtil::parseBitcoinURI(uri, &rv)); + + uri.setUrl(QString("bitcoin:175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W?dontexist=")); + QVERIFY(GUIUtil::parseBitcoinURI(uri, &rv)); + QVERIFY(rv.address == QString("175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W")); + QVERIFY(rv.label == QString()); + QVERIFY(rv.amount == 0); + + uri.setUrl(QString("bitcoin:175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W?label=Wikipedia Example Address")); + QVERIFY(GUIUtil::parseBitcoinURI(uri, &rv)); + QVERIFY(rv.address == QString("175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W")); + QVERIFY(rv.label == QString("Wikipedia Example Address")); + QVERIFY(rv.amount == 0); + + uri.setUrl(QString("bitcoin:175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W?amount=0.001")); + QVERIFY(GUIUtil::parseBitcoinURI(uri, &rv)); + QVERIFY(rv.address == QString("175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W")); + QVERIFY(rv.label == QString()); + QVERIFY(rv.amount == 100000); + + uri.setUrl(QString("bitcoin:175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W?amount=1.001")); + QVERIFY(GUIUtil::parseBitcoinURI(uri, &rv)); + QVERIFY(rv.address == QString("175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W")); + QVERIFY(rv.label == QString()); + QVERIFY(rv.amount == 100100000); + + uri.setUrl(QString("bitcoin:175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W?amount=100&label=Wikipedia Example")); + QVERIFY(GUIUtil::parseBitcoinURI(uri, &rv)); + QVERIFY(rv.address == QString("175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W")); + QVERIFY(rv.amount == 10000000000LL); + QVERIFY(rv.label == QString("Wikipedia Example")); + + uri.setUrl(QString("bitcoin:175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W?message=Wikipedia Example Address")); + QVERIFY(GUIUtil::parseBitcoinURI(uri, &rv)); + QVERIFY(rv.address == QString("175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W")); + QVERIFY(rv.label == QString()); + + QVERIFY(GUIUtil::parseBitcoinURI("bitcoin://175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W?message=Wikipedia Example Address", &rv)); + QVERIFY(rv.address == QString("175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W")); + QVERIFY(rv.label == QString()); + + // We currently don't implement the message parameter (ok, yea, we break spec...) + uri.setUrl(QString("bitcoin:175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W?req-message=Wikipedia Example Address")); + QVERIFY(!GUIUtil::parseBitcoinURI(uri, &rv)); + + uri.setUrl(QString("bitcoin:175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W?amount=1,000&label=Wikipedia Example")); + QVERIFY(!GUIUtil::parseBitcoinURI(uri, &rv)); + + uri.setUrl(QString("bitcoin:175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W?amount=1,000.0&label=Wikipedia Example")); + QVERIFY(!GUIUtil::parseBitcoinURI(uri, &rv)); +} diff --git a/src/qt/test/uritests.h b/src/qt/test/uritests.h new file mode 100644 index 0000000..1237516 --- /dev/null +++ b/src/qt/test/uritests.h @@ -0,0 +1,15 @@ +#ifndef URITESTS_H +#define URITESTS_H + +#include +#include + +class URITests : public QObject +{ + Q_OBJECT + +private slots: + void uriTests(); +}; + +#endif // URITESTS_H diff --git a/src/qt/transactiondesc.cpp b/src/qt/transactiondesc.cpp new file mode 100644 index 0000000..a82e3e2 --- /dev/null +++ b/src/qt/transactiondesc.cpp @@ -0,0 +1,278 @@ +#include "transactiondesc.h" + +#include "guiutil.h" +#include "bitcoinunits.h" + +#include "main.h" +#include "wallet.h" +#include "db.h" +#include "ui_interface.h" +#include "base58.h" + +QString TransactionDesc::FormatTxStatus(const CWalletTx& wtx) +{ + if (!wtx.IsFinal()) + { + if (wtx.nLockTime < LOCKTIME_THRESHOLD) + return tr("Open for %n block(s)", "", nBestHeight - wtx.nLockTime); + else + return tr("Open until %1").arg(GUIUtil::dateTimeStr(wtx.nLockTime)); + } + else + { + int nDepth = wtx.GetDepthInMainChain(); + if (GetAdjustedTime() - wtx.nTimeReceived > 2 * 60 && wtx.GetRequestCount() == 0) + return tr("%1/offline").arg(nDepth); + else if (nDepth < 6) + return tr("%1/unconfirmed").arg(nDepth); + else + return tr("%1 confirmations").arg(nDepth); + } +} + +QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx) +{ + QString strHTML; + + { + LOCK(wallet->cs_wallet); + strHTML.reserve(4000); + strHTML += ""; + + int64 nTime = wtx.GetTxTime(); + int64 nCredit = wtx.GetCredit(); + int64 nDebit = wtx.GetDebit(); + int64 nNet = nCredit - nDebit; + + strHTML += "" + tr("Status") + ": " + FormatTxStatus(wtx); + int nRequests = wtx.GetRequestCount(); + if (nRequests != -1) + { + if (nRequests == 0) + strHTML += tr(", has not been successfully broadcast yet"); + else if (nRequests > 0) + strHTML += tr(", broadcast through %n node(s)", "", nRequests); + } + strHTML += "
"; + + strHTML += "" + tr("Date") + ": " + (nTime ? GUIUtil::dateTimeStr(nTime) : "") + "
"; + + // + // From + // + if (wtx.IsCoinBase()) + { + strHTML += "" + tr("Source") + ": " + tr("Generated") + "
"; + } + else if (wtx.mapValue.count("from") && !wtx.mapValue["from"].empty()) + { + // Online transaction + strHTML += "" + tr("From") + ": " + GUIUtil::HtmlEscape(wtx.mapValue["from"]) + "
"; + } + else + { + // Offline transaction + if (nNet > 0) + { + // Credit + BOOST_FOREACH(const CTxOut& txout, wtx.vout) + { + if (wallet->IsMine(txout)) + { + CTxDestination address; + if (ExtractDestination(txout.scriptPubKey, address) && IsMine(*wallet, address)) + { + if (wallet->mapAddressBook.count(address)) + { + strHTML += "" + tr("From") + ": " + tr("unknown") + "
"; + strHTML += "" + tr("To") + ": "; + strHTML += GUIUtil::HtmlEscape(CBitcoinAddress(address).ToString()); + if (!wallet->mapAddressBook[address].empty()) + strHTML += " (" + tr("own address") + ", " + tr("label") + ": " + GUIUtil::HtmlEscape(wallet->mapAddressBook[address]) + ")"; + else + strHTML += " (" + tr("own address") + ")"; + strHTML += "
"; + } + } + break; + } + } + } + } + + // + // To + // + if (wtx.mapValue.count("to") && !wtx.mapValue["to"].empty()) + { + // Online transaction + std::string strAddress = wtx.mapValue["to"]; + strHTML += "" + tr("To") + ": "; + CTxDestination dest = CBitcoinAddress(strAddress).Get(); + if (wallet->mapAddressBook.count(dest) && !wallet->mapAddressBook[dest].empty()) + strHTML += GUIUtil::HtmlEscape(wallet->mapAddressBook[dest]) + " "; + strHTML += GUIUtil::HtmlEscape(strAddress) + "
"; + } + + // + // Amount + // + if (wtx.IsCoinBase() && nCredit == 0) + { + // + // Coinbase + // + int64 nUnmatured = 0; + BOOST_FOREACH(const CTxOut& txout, wtx.vout) + nUnmatured += wallet->GetCredit(txout); + strHTML += "" + tr("Credit") + ": "; + if (wtx.IsInMainChain()) + strHTML += BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, nUnmatured)+ " (" + tr("matures in %n more block(s)", "", wtx.GetBlocksToMaturity()) + ")"; + else + strHTML += "(" + tr("not accepted") + ")"; + strHTML += "
"; + } + else if (nNet > 0) + { + // + // Credit + // + strHTML += "" + tr("Credit") + ": " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, nNet) + "
"; + } + else + { + bool fAllFromMe = true; + BOOST_FOREACH(const CTxIn& txin, wtx.vin) + fAllFromMe = fAllFromMe && wallet->IsMine(txin); + + bool fAllToMe = true; + BOOST_FOREACH(const CTxOut& txout, wtx.vout) + fAllToMe = fAllToMe && wallet->IsMine(txout); + + if (fAllFromMe) + { + // + // Debit + // + BOOST_FOREACH(const CTxOut& txout, wtx.vout) + { + if (wallet->IsMine(txout)) + continue; + + if (!wtx.mapValue.count("to") || wtx.mapValue["to"].empty()) + { + // Offline transaction + CTxDestination address; + if (ExtractDestination(txout.scriptPubKey, address)) + { + strHTML += "" + tr("To") + ": "; + if (wallet->mapAddressBook.count(address) && !wallet->mapAddressBook[address].empty()) + strHTML += GUIUtil::HtmlEscape(wallet->mapAddressBook[address]) + " "; + strHTML += GUIUtil::HtmlEscape(CBitcoinAddress(address).ToString()); + strHTML += "
"; + } + } + + strHTML += "" + tr("Debit") + ": " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, -txout.nValue) + "
"; + } + + if (fAllToMe) + { + // Payment to self + int64 nChange = wtx.GetChange(); + int64 nValue = nCredit - nChange; + strHTML += "" + tr("Debit") + ": " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, -nValue) + "
"; + strHTML += "" + tr("Credit") + ": " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, nValue) + "
"; + } + + int64 nTxFee = nDebit - wtx.GetValueOut(); + if (nTxFee > 0) + strHTML += "" + tr("Transaction fee") + ": " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, -nTxFee) + "
"; + } + else + { + // + // Mixed debit transaction + // + BOOST_FOREACH(const CTxIn& txin, wtx.vin) + if (wallet->IsMine(txin)) + strHTML += "" + tr("Debit") + ": " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, -wallet->GetDebit(txin)) + "
"; + BOOST_FOREACH(const CTxOut& txout, wtx.vout) + if (wallet->IsMine(txout)) + strHTML += "" + tr("Credit") + ": " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, wallet->GetCredit(txout)) + "
"; + } + } + + strHTML += "" + tr("Net amount") + ": " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, nNet, true) + "
"; + + // + // Message + // + if (!wtx.mapValue["message"].empty()) + strHTML += "
" + tr("Message") + ":
" + GUIUtil::HtmlEscape(wtx.mapValue["message"], true) + "
"; + + if (!wtx.mapValue["comment"].empty()) + strHTML += "
" + tr("Comment") + ":
" + GUIUtil::HtmlEscape(wtx.mapValue["comment"], true) + "
"; + + strHTML += "" + tr("Transaction ID") + ": " + wtx.GetHash().ToString().c_str() + "
"; + + + + if (wtx.IsCoinBase() || wtx.IsCoinStake()) + strHTML += "
" + tr("Generated coins must mature 50 blocks before they can be spent. When you generated this block, it was broadcast to the network to be added to the block chain. If it fails to get into the chain, its state will change to \"not accepted\" and it won't be spendable. This may occasionally happen if another node generates a block within a few seconds of yours.") + "
"; + + // + // Debug view + // + if (fDebug) + { + strHTML += "



" + tr("Debug information") + "

"; + BOOST_FOREACH(const CTxIn& txin, wtx.vin) + if(wallet->IsMine(txin)) + strHTML += "" + tr("Debit") + ": " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, -wallet->GetDebit(txin)) + "
"; + BOOST_FOREACH(const CTxOut& txout, wtx.vout) + if(wallet->IsMine(txout)) + strHTML += "" + tr("Credit") + ": " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, wallet->GetCredit(txout)) + "
"; + + strHTML += "
" + tr("Transaction") + ":
"; + strHTML += GUIUtil::HtmlEscape(wtx.ToString(), true); + + CTxDB txdb("r"); // To fetch source txouts + + strHTML += "
" + tr("Inputs") + ":"; + strHTML += "
    "; + + { + LOCK(wallet->cs_wallet); + BOOST_FOREACH(const CTxIn& txin, wtx.vin) + { + COutPoint prevout = txin.prevout; + + CTransaction prev; + if(txdb.ReadDiskTx(prevout.hash, prev)) + { + if (prevout.n < prev.vout.size()) + { + strHTML += "
  • "; + const CTxOut &vout = prev.vout[prevout.n]; + CTxDestination address; + if (ExtractDestination(vout.scriptPubKey, address)) + { + if (wallet->mapAddressBook.count(address) && !wallet->mapAddressBook[address].empty()) + strHTML += GUIUtil::HtmlEscape(wallet->mapAddressBook[address]) + " "; + strHTML += QString::fromStdString(CBitcoinAddress(address).ToString()); + } + strHTML = strHTML + " " + tr("Amount") + "=" + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, vout.nValue); + strHTML = strHTML + " IsMine=" + (wallet->IsMine(vout) ? tr("true") : tr("false")) + "
  • "; + } + } + } + } + + strHTML += "
"; + } + + strHTML += "
"; + } + return strHTML; +} diff --git a/src/qt/transactiondesc.h b/src/qt/transactiondesc.h new file mode 100644 index 0000000..2523f9a --- /dev/null +++ b/src/qt/transactiondesc.h @@ -0,0 +1,24 @@ +#ifndef TRANSACTIONDESC_H +#define TRANSACTIONDESC_H + +#include +#include +#include + +class CWallet; +class CWalletTx; + +/** Provide a human-readable extended HTML description of a transaction. + */ +class TransactionDesc: public QObject +{ + Q_OBJECT +public: + static QString toHTML(CWallet *wallet, CWalletTx &wtx); +private: + TransactionDesc() {} + + static QString FormatTxStatus(const CWalletTx& wtx); +}; + +#endif // TRANSACTIONDESC_H diff --git a/src/qt/transactiondescdialog.cpp b/src/qt/transactiondescdialog.cpp new file mode 100644 index 0000000..3bd4808 --- /dev/null +++ b/src/qt/transactiondescdialog.cpp @@ -0,0 +1,20 @@ +#include "transactiondescdialog.h" +#include "ui_transactiondescdialog.h" + +#include "transactiontablemodel.h" + +#include + +TransactionDescDialog::TransactionDescDialog(const QModelIndex &idx, QWidget *parent) : + QDialog(parent), + ui(new Ui::TransactionDescDialog) +{ + ui->setupUi(this); + QString desc = idx.data(TransactionTableModel::LongDescriptionRole).toString(); + ui->detailText->setHtml(desc); +} + +TransactionDescDialog::~TransactionDescDialog() +{ + delete ui; +} diff --git a/src/qt/transactiondescdialog.h b/src/qt/transactiondescdialog.h new file mode 100644 index 0000000..e86fb58 --- /dev/null +++ b/src/qt/transactiondescdialog.h @@ -0,0 +1,26 @@ +#ifndef TRANSACTIONDESCDIALOG_H +#define TRANSACTIONDESCDIALOG_H + +#include + +namespace Ui { + class TransactionDescDialog; +} +QT_BEGIN_NAMESPACE +class QModelIndex; +QT_END_NAMESPACE + +/** Dialog showing transaction details. */ +class TransactionDescDialog : public QDialog +{ + Q_OBJECT + +public: + explicit TransactionDescDialog(const QModelIndex &idx, QWidget *parent = 0); + ~TransactionDescDialog(); + +private: + Ui::TransactionDescDialog *ui; +}; + +#endif // TRANSACTIONDESCDIALOG_H diff --git a/src/qt/transactionfilterproxy.cpp b/src/qt/transactionfilterproxy.cpp new file mode 100644 index 0000000..16fb4da --- /dev/null +++ b/src/qt/transactionfilterproxy.cpp @@ -0,0 +1,86 @@ +#include "transactionfilterproxy.h" +#include "transactiontablemodel.h" + +#include + +#include + +// Earliest date that can be represented (far in the past) +const QDateTime TransactionFilterProxy::MIN_DATE = QDateTime::fromTime_t(0); +// Last date that can be represented (far in the future) +const QDateTime TransactionFilterProxy::MAX_DATE = QDateTime::fromTime_t(0xFFFFFFFF); + +TransactionFilterProxy::TransactionFilterProxy(QObject *parent) : + QSortFilterProxyModel(parent), + dateFrom(MIN_DATE), + dateTo(MAX_DATE), + addrPrefix(), + typeFilter(ALL_TYPES), + minAmount(0), + limitRows(-1) +{ +} + +bool TransactionFilterProxy::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const +{ + QModelIndex index = sourceModel()->index(sourceRow, 0, sourceParent); + + int type = index.data(TransactionTableModel::TypeRole).toInt(); + QDateTime datetime = index.data(TransactionTableModel::DateRole).toDateTime(); + QString address = index.data(TransactionTableModel::AddressRole).toString(); + QString label = index.data(TransactionTableModel::LabelRole).toString(); + qint64 amount = llabs(index.data(TransactionTableModel::AmountRole).toLongLong()); + + if(!(TYPE(type) & typeFilter)) + return false; + if(datetime < dateFrom || datetime > dateTo) + return false; + if (!address.contains(addrPrefix, Qt::CaseInsensitive) && !label.contains(addrPrefix, Qt::CaseInsensitive)) + return false; + if(amount < minAmount) + return false; + + return true; +} + +void TransactionFilterProxy::setDateRange(const QDateTime &from, const QDateTime &to) +{ + this->dateFrom = from; + this->dateTo = to; + invalidateFilter(); +} + +void TransactionFilterProxy::setAddressPrefix(const QString &addrPrefix) +{ + this->addrPrefix = addrPrefix; + invalidateFilter(); +} + +void TransactionFilterProxy::setTypeFilter(quint32 modes) +{ + this->typeFilter = modes; + invalidateFilter(); +} + +void TransactionFilterProxy::setMinAmount(qint64 minimum) +{ + this->minAmount = minimum; + invalidateFilter(); +} + +void TransactionFilterProxy::setLimit(int limit) +{ + this->limitRows = limit; +} + +int TransactionFilterProxy::rowCount(const QModelIndex &parent) const +{ + if(limitRows != -1) + { + return std::min(QSortFilterProxyModel::rowCount(parent), limitRows); + } + else + { + return QSortFilterProxyModel::rowCount(parent); + } +} diff --git a/src/qt/transactionfilterproxy.h b/src/qt/transactionfilterproxy.h new file mode 100644 index 0000000..30b9858 --- /dev/null +++ b/src/qt/transactionfilterproxy.h @@ -0,0 +1,52 @@ +#ifndef TRANSACTIONFILTERPROXY_H +#define TRANSACTIONFILTERPROXY_H + +#include +#include + +/** Filter the transaction list according to pre-specified rules. */ +class TransactionFilterProxy : public QSortFilterProxyModel +{ + Q_OBJECT +public: + explicit TransactionFilterProxy(QObject *parent = 0); + + /** Earliest date that can be represented (far in the past) */ + static const QDateTime MIN_DATE; + /** Last date that can be represented (far in the future) */ + static const QDateTime MAX_DATE; + /** Type filter bit field (all types) */ + static const quint32 ALL_TYPES = 0xFFFFFFFF; + + static quint32 TYPE(int type) { return 1< TransactionRecord::decomposeTransaction(const CWallet *wallet, const CWalletTx &wtx) +{ + QList parts; + int64 nTime = wtx.GetTxTime(); + int64 nCredit = wtx.GetCredit(true); + int64 nDebit = wtx.GetDebit(); + int64 nNet = nCredit - nDebit; + uint256 hash = wtx.GetHash(); + std::map mapValue = wtx.mapValue; + + if (wtx.IsCoinStake()) + { + // Stake generation + parts.append(TransactionRecord(hash, nTime, TransactionRecord::StakeMint, "", -nDebit, wtx.GetValueOut())); + } + else if (nNet > 0 || wtx.IsCoinBase()) + { + // + // Credit + // + BOOST_FOREACH(const CTxOut& txout, wtx.vout) + { + if(wallet->IsMine(txout)) + { + TransactionRecord sub(hash, nTime); + CTxDestination address; + sub.idx = parts.size(); // sequence number + sub.credit = txout.nValue; + if (ExtractDestination(txout.scriptPubKey, address) && IsMine(*wallet, address)) + { + // Received by Bitcoin Address + sub.type = TransactionRecord::RecvWithAddress; + sub.address = CBitcoinAddress(address).ToString(); + } + else + { + // Received by IP connection (deprecated features), or a multisignature or other non-simple transaction + sub.type = TransactionRecord::RecvFromOther; + sub.address = mapValue["from"]; + } + if (wtx.IsCoinBase()) + { + // Generated + sub.type = TransactionRecord::Generated; + } + + parts.append(sub); + } + } + } + else + { + bool fAllFromMe = true; + BOOST_FOREACH(const CTxIn& txin, wtx.vin) + fAllFromMe = fAllFromMe && wallet->IsMine(txin); + + bool fAllToMe = true; + BOOST_FOREACH(const CTxOut& txout, wtx.vout) + fAllToMe = fAllToMe && wallet->IsMine(txout); + + if (fAllFromMe && fAllToMe) + { + // Payment to self + int64 nChange = wtx.GetChange(); + + parts.append(TransactionRecord(hash, nTime, TransactionRecord::SendToSelf, "", + -(nDebit - nChange), nCredit - nChange)); + } + else if (fAllFromMe) + { + // + // Debit + // + int64 nTxFee = nDebit - wtx.GetValueOut(); + + for (unsigned int nOut = 0; nOut < wtx.vout.size(); nOut++) + { + const CTxOut& txout = wtx.vout[nOut]; + TransactionRecord sub(hash, nTime); + sub.idx = parts.size(); + + if(wallet->IsMine(txout)) + { + // Ignore parts sent to self, as this is usually the change + // from a transaction sent back to our own address. + continue; + } + + CTxDestination address; + if (ExtractDestination(txout.scriptPubKey, address)) + { + // Sent to Bitcoin Address + sub.type = TransactionRecord::SendToAddress; + sub.address = CBitcoinAddress(address).ToString(); + } + else + { + // Sent to IP, or other non-address transaction like OP_EVAL + sub.type = TransactionRecord::SendToOther; + sub.address = mapValue["to"]; + } + + int64 nValue = txout.nValue; + /* Add fee to first output */ + if (nTxFee > 0) + { + nValue += nTxFee; + nTxFee = 0; + } + sub.debit = -nValue; + + parts.append(sub); + } + } + else + { + // + // Mixed debit transaction, can't break down payees + // + parts.append(TransactionRecord(hash, nTime, TransactionRecord::Other, "", nNet, 0)); + } + } + + return parts; +} + +void TransactionRecord::updateStatus(const CWalletTx &wtx) +{ + // Determine transaction status + + // Find the block the tx is in + CBlockIndex* pindex = NULL; + std::map::iterator mi = mapBlockIndex.find(wtx.hashBlock); + if (mi != mapBlockIndex.end()) + pindex = (*mi).second; + + // Sort order, unrecorded transactions sort to the top + status.sortKey = strprintf("%010d-%01d-%010u-%03d", + (pindex ? pindex->nHeight : std::numeric_limits::max()), + (wtx.IsCoinBase() ? 1 : 0), + wtx.nTimeReceived, + idx); + status.confirmed = wtx.IsConfirmed(); + status.depth = wtx.GetDepthInMainChain(); + status.cur_num_blocks = nBestHeight; + + if (!wtx.IsFinal()) + { + if (wtx.nLockTime < LOCKTIME_THRESHOLD) + { + status.status = TransactionStatus::OpenUntilBlock; + status.open_for = nBestHeight - wtx.nLockTime; + } + else + { + status.status = TransactionStatus::OpenUntilDate; + status.open_for = wtx.nLockTime; + } + } + else + { + if (GetAdjustedTime() - wtx.nTimeReceived > 2 * 60 && wtx.GetRequestCount() == 0) + { + status.status = TransactionStatus::Offline; + } + else if (status.depth < NumConfirmations) + { + status.status = TransactionStatus::Unconfirmed; + } + else + { + status.status = TransactionStatus::HaveConfirmations; + } + } + + // For generated transactions, determine maturity + if(type == TransactionRecord::Generated || type == TransactionRecord::StakeMint) + { + int64 nCredit = wtx.GetCredit(true); + if (nCredit == 0) + { + status.maturity = TransactionStatus::Immature; + + if (wtx.IsInMainChain()) + { + status.matures_in = wtx.GetBlocksToMaturity(); + + // Check if the block was requested by anyone + if (GetAdjustedTime() - wtx.nTimeReceived > 2 * 60 && wtx.GetRequestCount() == 0) + status.maturity = TransactionStatus::MaturesWarning; + } + else + { + status.maturity = TransactionStatus::NotAccepted; + } + } + else + { + status.maturity = TransactionStatus::Mature; + } + } +} + +bool TransactionRecord::statusUpdateNeeded() +{ + return status.cur_num_blocks != nBestHeight; +} + +std::string TransactionRecord::getTxID() +{ + return hash.ToString() + strprintf("-%03d", idx); +} + diff --git a/src/qt/transactionrecord.h b/src/qt/transactionrecord.h new file mode 100644 index 0000000..3e36fff --- /dev/null +++ b/src/qt/transactionrecord.h @@ -0,0 +1,130 @@ +#ifndef TRANSACTIONRECORD_H +#define TRANSACTIONRECORD_H + +#include "uint256.h" + +#include + +class CWallet; +class CWalletTx; + +/** UI model for transaction status. The transaction status is the part of a transaction that will change over time. + */ +class TransactionStatus +{ +public: + TransactionStatus(): + confirmed(false), sortKey(""), maturity(Mature), + matures_in(0), status(Offline), depth(0), open_for(0), cur_num_blocks(-1) + { } + + enum Maturity + { + Immature, + Mature, + MaturesWarning, /**< Transaction will likely not mature because no nodes have confirmed */ + NotAccepted + }; + + enum Status { + OpenUntilDate, + OpenUntilBlock, + Offline, + Unconfirmed, + HaveConfirmations + }; + + bool confirmed; + std::string sortKey; + + /** @name Generated (mined) transactions + @{*/ + Maturity maturity; + int matures_in; + /**@}*/ + + /** @name Reported status + @{*/ + Status status; + int64 depth; + int64 open_for; /**< Timestamp if status==OpenUntilDate, otherwise number of blocks */ + /**@}*/ + + /** Current number of blocks (to know whether cached status is still valid) */ + int cur_num_blocks; +}; + +/** UI model for a transaction. A core transaction can be represented by multiple UI transactions if it has + multiple outputs. + */ +class TransactionRecord +{ +public: + enum Type + { + Other, + Generated, + SendToAddress, + SendToOther, + RecvWithAddress, + RecvFromOther, + SendToSelf, + StakeMint + }; + + /** Number of confirmation needed for transaction */ + static const int NumConfirmations = 4; + + TransactionRecord(): + hash(), time(0), type(Other), address(""), debit(0), credit(0), idx(0) + { + } + + TransactionRecord(uint256 hash, int64 time): + hash(hash), time(time), type(Other), address(""), debit(0), + credit(0), idx(0) + { + } + + TransactionRecord(uint256 hash, int64 time, + Type type, const std::string &address, + int64 debit, int64 credit): + hash(hash), time(time), type(type), address(address), debit(debit), credit(credit), + idx(0) + { + } + + /** Decompose CWallet transaction to model transaction records. + */ + static bool showTransaction(const CWalletTx &wtx); + static QList decomposeTransaction(const CWallet *wallet, const CWalletTx &wtx); + + /** @name Immutable transaction attributes + @{*/ + uint256 hash; + int64 time; + Type type; + std::string address; + int64 debit; + int64 credit; + /**@}*/ + + /** Subtransaction index, for sort key */ + int idx; + + /** Status: can change with block chain update */ + TransactionStatus status; + + /** Return the unique identifier for this transaction (part) */ + std::string getTxID(); + + /** Update status from core wallet tx. + */ + void updateStatus(const CWalletTx &wtx); + + /** Return whether a status update is needed. + */ + bool statusUpdateNeeded(); +}; + +#endif // TRANSACTIONRECORD_H diff --git a/src/qt/transactiontablemodel.cpp b/src/qt/transactiontablemodel.cpp new file mode 100644 index 0000000..2e9cc46 --- /dev/null +++ b/src/qt/transactiontablemodel.cpp @@ -0,0 +1,639 @@ +#include "transactiontablemodel.h" +#include "guiutil.h" +#include "transactionrecord.h" +#include "guiconstants.h" +#include "transactiondesc.h" +#include "walletmodel.h" +#include "optionsmodel.h" +#include "addresstablemodel.h" +#include "bitcoinunits.h" + +#include "wallet.h" +#include "ui_interface.h" + +#include +#include +#include +#include +#include +#include +#include + +// Amount column is right-aligned it contains numbers +static int column_alignments[] = { + Qt::AlignLeft|Qt::AlignVCenter, + Qt::AlignLeft|Qt::AlignVCenter, + Qt::AlignLeft|Qt::AlignVCenter, + Qt::AlignLeft|Qt::AlignVCenter, + Qt::AlignRight|Qt::AlignVCenter + }; + +// Comparison operator for sort/binary search of model tx list +struct TxLessThan +{ + bool operator()(const TransactionRecord &a, const TransactionRecord &b) const + { + return a.hash < b.hash; + } + bool operator()(const TransactionRecord &a, const uint256 &b) const + { + return a.hash < b; + } + bool operator()(const uint256 &a, const TransactionRecord &b) const + { + return a < b.hash; + } +}; + +// Private implementation +class TransactionTablePriv +{ +public: + TransactionTablePriv(CWallet *wallet, TransactionTableModel *parent): + wallet(wallet), + parent(parent) + { + } + CWallet *wallet; + TransactionTableModel *parent; + + /* Local cache of wallet. + * As it is in the same order as the CWallet, by definition + * this is sorted by sha256. + */ + QList cachedWallet; + + /* Query entire wallet anew from core. + */ + void refreshWallet() + { + OutputDebugStringF("refreshWallet\n"); + cachedWallet.clear(); + { + LOCK(wallet->cs_wallet); + for(std::map::iterator it = wallet->mapWallet.begin(); it != wallet->mapWallet.end(); ++it) + { + if(TransactionRecord::showTransaction(it->second)) + cachedWallet.append(TransactionRecord::decomposeTransaction(wallet, it->second)); + } + } + } + + /* Update our model of the wallet incrementally, to synchronize our model of the wallet + with that of the core. + + Call with transaction that was added, removed or changed. + */ + void updateWallet(const uint256 &hash, int status) + { + OutputDebugStringF("updateWallet %s %i\n", hash.ToString().c_str(), status); + { + LOCK(wallet->cs_wallet); + + // Find transaction in wallet + std::map::iterator mi = wallet->mapWallet.find(hash); + bool inWallet = mi != wallet->mapWallet.end(); + + // Find bounds of this transaction in model + QList::iterator lower = qLowerBound( + cachedWallet.begin(), cachedWallet.end(), hash, TxLessThan()); + QList::iterator upper = qUpperBound( + cachedWallet.begin(), cachedWallet.end(), hash, TxLessThan()); + int lowerIndex = (lower - cachedWallet.begin()); + int upperIndex = (upper - cachedWallet.begin()); + bool inModel = (lower != upper); + + // Determine whether to show transaction or not + bool showTransaction = (inWallet && TransactionRecord::showTransaction(mi->second)); + + if(status == CT_UPDATED) + { + if(showTransaction && !inModel) + status = CT_NEW; /* Not in model, but want to show, treat as new */ + if(!showTransaction && inModel) + status = CT_DELETED; /* In model, but want to hide, treat as deleted */ + } + + OutputDebugStringF(" inWallet=%i inModel=%i Index=%i-%i showTransaction=%i derivedStatus=%i\n", + inWallet, inModel, lowerIndex, upperIndex, showTransaction, status); + + switch(status) + { + case CT_NEW: + if(inModel) + { + OutputDebugStringF("Warning: updateWallet: Got CT_NEW, but transaction is already in model\n"); + break; + } + if(!inWallet) + { + OutputDebugStringF("Warning: updateWallet: Got CT_NEW, but transaction is not in wallet\n"); + break; + } + if(showTransaction) + { + // Added -- insert at the right position + QList toInsert = + TransactionRecord::decomposeTransaction(wallet, mi->second); + if(!toInsert.isEmpty()) /* only if something to insert */ + { + parent->beginInsertRows(QModelIndex(), lowerIndex, lowerIndex+toInsert.size()-1); + int insert_idx = lowerIndex; + foreach(const TransactionRecord &rec, toInsert) + { + cachedWallet.insert(insert_idx, rec); + insert_idx += 1; + } + parent->endInsertRows(); + } + } + break; + case CT_DELETED: + if(!inModel) + { + OutputDebugStringF("Warning: updateWallet: Got CT_DELETED, but transaction is not in model\n"); + break; + } + // Removed -- remove entire transaction from table + parent->beginRemoveRows(QModelIndex(), lowerIndex, upperIndex-1); + cachedWallet.erase(lower, upper); + parent->endRemoveRows(); + break; + case CT_UPDATED: + // Miscellaneous updates -- nothing to do, status update will take care of this, and is only computed for + // visible transactions. + break; + } + } + } + + int size() + { + return cachedWallet.size(); + } + + TransactionRecord *index(int idx) + { + if(idx >= 0 && idx < cachedWallet.size()) + { + TransactionRecord *rec = &cachedWallet[idx]; + + // If a status update is needed (blocks came in since last check), + // update the status of this transaction from the wallet. Otherwise, + // simply re-use the cached status. + if(rec->statusUpdateNeeded()) + { + { + LOCK(wallet->cs_wallet); + std::map::iterator mi = wallet->mapWallet.find(rec->hash); + + if(mi != wallet->mapWallet.end()) + { + rec->updateStatus(mi->second); + } + } + } + return rec; + } + else + { + return 0; + } + } + + QString describe(TransactionRecord *rec) + { + { + LOCK(wallet->cs_wallet); + std::map::iterator mi = wallet->mapWallet.find(rec->hash); + if(mi != wallet->mapWallet.end()) + { + return TransactionDesc::toHTML(wallet, mi->second); + } + } + return QString(""); + } + +}; + +TransactionTableModel::TransactionTableModel(CWallet* wallet, WalletModel *parent): + QAbstractTableModel(parent), + wallet(wallet), + walletModel(parent), + priv(new TransactionTablePriv(wallet, this)), + cachedNumBlocks(0) +{ + columns << QString() << tr("Date") << tr("Type") << tr("Address") << tr("Amount"); + + priv->refreshWallet(); + + QTimer *timer = new QTimer(this); + connect(timer, SIGNAL(timeout()), this, SLOT(updateConfirmations())); + timer->start(MODEL_UPDATE_DELAY); + + connect(walletModel->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit())); +} + +TransactionTableModel::~TransactionTableModel() +{ + delete priv; +} + +void TransactionTableModel::updateTransaction(const QString &hash, int status) +{ + uint256 updated; + updated.SetHex(hash.toStdString()); + + priv->updateWallet(updated, status); +} + +void TransactionTableModel::updateConfirmations() +{ + if(nBestHeight != cachedNumBlocks) + { + cachedNumBlocks = nBestHeight; + // Blocks came in since last poll. + // Invalidate status (number of confirmations) and (possibly) description + // for all rows. Qt is smart enough to only actually request the data for the + // visible rows. + emit dataChanged(index(0, Status), index(priv->size()-1, Status)); + emit dataChanged(index(0, ToAddress), index(priv->size()-1, ToAddress)); + } +} + +int TransactionTableModel::rowCount(const QModelIndex &parent) const +{ + Q_UNUSED(parent); + return priv->size(); +} + +int TransactionTableModel::columnCount(const QModelIndex &parent) const +{ + Q_UNUSED(parent); + return columns.length(); +} + +QString TransactionTableModel::formatTxStatus(const TransactionRecord *wtx) const +{ + QString status; + + switch(wtx->status.status) + { + case TransactionStatus::OpenUntilBlock: + status = tr("Open for %n block(s)","",wtx->status.open_for); + break; + case TransactionStatus::OpenUntilDate: + status = tr("Open until %1").arg(GUIUtil::dateTimeStr(wtx->status.open_for)); + break; + case TransactionStatus::Offline: + status = tr("Offline (%1 confirmations)").arg(wtx->status.depth); + break; + case TransactionStatus::Unconfirmed: + status = tr("Unconfirmed (%1 of %2 confirmations)").arg(wtx->status.depth).arg(TransactionRecord::NumConfirmations); + break; + case TransactionStatus::HaveConfirmations: + status = tr("Confirmed (%1 confirmations)").arg(wtx->status.depth); + break; + } + if(wtx->type == TransactionRecord::Generated || wtx->type == TransactionRecord::StakeMint) + { + switch(wtx->status.maturity) + { + case TransactionStatus::Immature: + status += "\n" + tr("Mined balance will be available when it matures in %n more block(s)", "", wtx->status.matures_in); + break; + case TransactionStatus::Mature: + break; + case TransactionStatus::MaturesWarning: + status += "\n" + tr("This block was not received by any other nodes and will probably not be accepted!"); + break; + case TransactionStatus::NotAccepted: + status += "\n" + tr("Generated but not accepted"); + break; + } + } + + return status; +} + +QString TransactionTableModel::formatTxDate(const TransactionRecord *wtx) const +{ + if(wtx->time) + { + return GUIUtil::dateTimeStr(wtx->time); + } + else + { + return QString(); + } +} + +/* Look up address in address book, if found return label (address) + otherwise just return (address) + */ +QString TransactionTableModel::lookupAddress(const std::string &address, bool tooltip) const +{ + QString label = walletModel->getAddressTableModel()->labelForAddress(QString::fromStdString(address)); + QString description; + if(!label.isEmpty()) + { + description += label + QString(" "); + } + if(label.isEmpty() || walletModel->getOptionsModel()->getDisplayAddresses() || tooltip) + { + description += QString("(") + QString::fromStdString(address) + QString(")"); + } + return description; +} + +QString TransactionTableModel::formatTxType(const TransactionRecord *wtx) const +{ + switch(wtx->type) + { + case TransactionRecord::RecvWithAddress: + return tr("Received with"); + case TransactionRecord::RecvFromOther: + return tr("Received from"); + case TransactionRecord::SendToAddress: + case TransactionRecord::SendToOther: + return tr("Sent to"); + case TransactionRecord::SendToSelf: + return tr("Payment to yourself"); + case TransactionRecord::StakeMint: + case TransactionRecord::Generated: + return tr("Mined"); + default: + return QString(); + } +} + +QVariant TransactionTableModel::txAddressDecoration(const TransactionRecord *wtx) const +{ + switch(wtx->type) + { + case TransactionRecord::Generated: + case TransactionRecord::StakeMint: + { + QString str = BitcoinUnits::format(walletModel->getOptionsModel()->getDisplayUnit(), wtx->credit + wtx->debit); + float dd = str.toFloat(); + return QIcon(":/icons/tx_mined"); + } + case TransactionRecord::RecvWithAddress: + case TransactionRecord::RecvFromOther: + return QIcon(":/icons/tx_input"); + case TransactionRecord::SendToAddress: + case TransactionRecord::SendToOther: + return QIcon(":/icons/tx_output"); + default: + return QIcon(":/icons/tx_inout"); + } + return QVariant(); +} + +QString TransactionTableModel::formatTxToAddress(const TransactionRecord *wtx, bool tooltip) const +{ + switch(wtx->type) + { + case TransactionRecord::RecvFromOther: + return QString::fromStdString(wtx->address); + case TransactionRecord::RecvWithAddress: + case TransactionRecord::SendToAddress: + case TransactionRecord::Generated: + return lookupAddress(wtx->address, tooltip); + case TransactionRecord::SendToOther: + return QString::fromStdString(wtx->address); + case TransactionRecord::SendToSelf: + default: + return tr("(n/a)"); + } +} + +QVariant TransactionTableModel::addressColor(const TransactionRecord *wtx) const +{ + // Show addresses without label in a less visible color + switch(wtx->type) + { + case TransactionRecord::RecvWithAddress: + case TransactionRecord::SendToAddress: + case TransactionRecord::Generated: + { + QString label = walletModel->getAddressTableModel()->labelForAddress(QString::fromStdString(wtx->address)); + if(label.isEmpty()) + return COLOR_BAREADDRESS; + } break; + case TransactionRecord::SendToSelf: + return COLOR_BAREADDRESS; + default: + break; + } + return QVariant(); +} + +QString TransactionTableModel::formatTxAmount(const TransactionRecord *wtx, bool showUnconfirmed) const +{ + QString str = BitcoinUnits::format(walletModel->getOptionsModel()->getDisplayUnit(), wtx->credit + wtx->debit); + if(showUnconfirmed) + { + if(!wtx->status.confirmed || wtx->status.maturity != TransactionStatus::Mature) + { + str = QString("[") + str + QString("]"); + } + } + return QString(str); +} + +QVariant TransactionTableModel::txStatusDecoration(const TransactionRecord *wtx) const +{ + if(wtx->type == TransactionRecord::Generated || wtx->type == TransactionRecord::StakeMint) + { + switch(wtx->status.maturity) + { + case TransactionStatus::Immature: { + int total = wtx->status.depth + wtx->status.matures_in; + int part = (wtx->status.depth * 4 / total) + 1; + return QIcon(QString(":/icons/transaction_%1").arg(part)); + } + case TransactionStatus::Mature: + return QIcon(":/icons/transaction_confirmed"); + case TransactionStatus::MaturesWarning: + case TransactionStatus::NotAccepted: + return QIcon(":/icons/transaction_0"); + } + } + else + { + switch(wtx->status.status) + { + case TransactionStatus::OpenUntilBlock: + case TransactionStatus::OpenUntilDate: + return QColor(64,64,255); + break; + case TransactionStatus::Offline: + return QColor(192,192,192); + case TransactionStatus::Unconfirmed: + switch(wtx->status.depth) + { + case 0: return QIcon(":/icons/transaction_0"); + case 1: return QIcon(":/icons/transaction_1"); + case 2: return QIcon(":/icons/transaction_2"); + case 3: return QIcon(":/icons/transaction_3"); + case 4: return QIcon(":/icons/transaction_4"); + default: return QIcon(":/icons/transaction_5"); + }; + case TransactionStatus::HaveConfirmations: + return QIcon(":/icons/transaction_confirmed"); + } + } + return QColor(0,0,0); +} + +QString TransactionTableModel::formatTooltip(const TransactionRecord *rec) const +{ + QString tooltip = formatTxStatus(rec) + QString("\n") + formatTxType(rec); + if(rec->type==TransactionRecord::RecvFromOther || rec->type==TransactionRecord::SendToOther || + rec->type==TransactionRecord::SendToAddress || rec->type==TransactionRecord::RecvWithAddress) + { + tooltip += QString(" ") + formatTxToAddress(rec, true); + } + return tooltip; +} + +QVariant TransactionTableModel::data(const QModelIndex &index, int role) const +{ + if(!index.isValid()) + return QVariant(); + TransactionRecord *rec = static_cast(index.internalPointer()); + + switch(role) + { + case Qt::DecorationRole: + switch(index.column()) + { + case Status: + return txStatusDecoration(rec); + case ToAddress: + return txAddressDecoration(rec); + } + break; + case Qt::DisplayRole: + switch(index.column()) + { + case Date: + return formatTxDate(rec); + case Type: + return formatTxType(rec); + case ToAddress: + return formatTxToAddress(rec, false); + case Amount: + return formatTxAmount(rec); + } + break; + case Qt::EditRole: + // Edit role is used for sorting, so return the unformatted values + switch(index.column()) + { + case Status: + return QString::fromStdString(rec->status.sortKey); + case Date: + return rec->time; + case Type: + return formatTxType(rec); + case ToAddress: + return formatTxToAddress(rec, true); + case Amount: + return rec->credit + rec->debit; + } + break; + case Qt::ToolTipRole: + return formatTooltip(rec); + case Qt::TextAlignmentRole: + return column_alignments[index.column()]; + case Qt::ForegroundRole: + // Non-confirmed transactions are grey + if(!rec->status.confirmed) + { + return COLOR_UNCONFIRMED; + } + if(index.column() == Amount && (rec->credit+rec->debit) < 0) + { + return COLOR_NEGATIVE; + } + if(index.column() == ToAddress) + { + return addressColor(rec); + } + break; + case TypeRole: + return rec->type; + case DateRole: + return QDateTime::fromTime_t(static_cast(rec->time)); + case LongDescriptionRole: + return priv->describe(rec); + case AddressRole: + return QString::fromStdString(rec->address); + case LabelRole: + return walletModel->getAddressTableModel()->labelForAddress(QString::fromStdString(rec->address)); + case AmountRole: + return rec->credit + rec->debit; + case TxIDRole: + return QString::fromStdString(rec->getTxID()); + case ConfirmedRole: + // Return True if transaction counts for balance + return rec->status.confirmed && !((rec->type == TransactionRecord::Generated || rec->type == TransactionRecord::StakeMint) && + rec->status.maturity != TransactionStatus::Mature); + case FormattedAmountRole: + return formatTxAmount(rec, false); + } + return QVariant(); +} + +QVariant TransactionTableModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + if(orientation == Qt::Horizontal) + { + if(role == Qt::DisplayRole) + { + return columns[section]; + } + else if (role == Qt::TextAlignmentRole) + { + return column_alignments[section]; + } else if (role == Qt::ToolTipRole) + { + switch(section) + { + case Status: + return tr("Transaction status. Hover over this field to show number of confirmations."); + case Date: + return tr("Date and time that the transaction was received."); + case Type: + return tr("Type of transaction."); + case ToAddress: + return tr("Destination address of transaction."); + case Amount: + return tr("Amount removed from or added to balance."); + } + } + } + return QVariant(); +} + +QModelIndex TransactionTableModel::index(int row, int column, const QModelIndex &parent) const +{ + Q_UNUSED(parent); + TransactionRecord *data = priv->index(row); + if(data) + { + return createIndex(row, column, priv->index(row)); + } + else + { + return QModelIndex(); + } +} + +void TransactionTableModel::updateDisplayUnit() +{ + // emit dataChanged to update Amount column with the current unit + emit dataChanged(index(0, Amount), index(priv->size()-1, Amount)); +} diff --git a/src/qt/transactiontablemodel.h b/src/qt/transactiontablemodel.h new file mode 100644 index 0000000..fd321ce --- /dev/null +++ b/src/qt/transactiontablemodel.h @@ -0,0 +1,85 @@ +#ifndef TRANSACTIONTABLEMODEL_H +#define TRANSACTIONTABLEMODEL_H + +#include +#include + +class CWallet; +class TransactionTablePriv; +class TransactionRecord; +class WalletModel; + +/** UI model for the transaction table of a wallet. + */ +class TransactionTableModel : public QAbstractTableModel +{ + Q_OBJECT +public: + explicit TransactionTableModel(CWallet* wallet, WalletModel *parent = 0); + ~TransactionTableModel(); + + enum ColumnIndex { + Status = 0, + Date = 1, + Type = 2, + ToAddress = 3, + Amount = 4 + }; + + /** Roles to get specific information from a transaction row. + These are independent of column. + */ + enum RoleIndex { + /** Type of transaction */ + TypeRole = Qt::UserRole, + /** Date and time this transaction was created */ + DateRole, + /** Long description (HTML format) */ + LongDescriptionRole, + /** Address of transaction */ + AddressRole, + /** Label of address related to transaction */ + LabelRole, + /** Net amount of transaction */ + AmountRole, + /** Unique identifier */ + TxIDRole, + /** Is transaction confirmed? */ + ConfirmedRole, + /** Formatted amount, without brackets when unconfirmed */ + FormattedAmountRole + }; + + int rowCount(const QModelIndex &parent) const; + int columnCount(const QModelIndex &parent) const; + QVariant data(const QModelIndex &index, int role) const; + QVariant headerData(int section, Qt::Orientation orientation, int role) const; + QModelIndex index(int row, int column, const QModelIndex & parent = QModelIndex()) const; +private: + CWallet* wallet; + WalletModel *walletModel; + QStringList columns; + TransactionTablePriv *priv; + int cachedNumBlocks; + + QString lookupAddress(const std::string &address, bool tooltip) const; + QVariant addressColor(const TransactionRecord *wtx) const; + QString formatTxStatus(const TransactionRecord *wtx) const; + QString formatTxDate(const TransactionRecord *wtx) const; + QString formatTxType(const TransactionRecord *wtx) const; + QString formatTxToAddress(const TransactionRecord *wtx, bool tooltip) const; + QString formatTxAmount(const TransactionRecord *wtx, bool showUnconfirmed=true) const; + QString formatTooltip(const TransactionRecord *rec) const; + QVariant txStatusDecoration(const TransactionRecord *wtx) const; + QVariant txAddressDecoration(const TransactionRecord *wtx) const; + +public slots: + void updateTransaction(const QString &hash, int status); + void updateConfirmations(); + void updateDisplayUnit(); + + friend class TransactionTablePriv; +}; + +#endif + diff --git a/src/qt/transactionview.cpp b/src/qt/transactionview.cpp new file mode 100644 index 0000000..6a32f26 --- /dev/null +++ b/src/qt/transactionview.cpp @@ -0,0 +1,432 @@ +#include "transactionview.h" + +#include "transactionfilterproxy.h" +#include "transactionrecord.h" +#include "walletmodel.h" +#include "addresstablemodel.h" +#include "transactiontablemodel.h" +#include "bitcoinunits.h" +#include "csvmodelwriter.h" +#include "transactiondescdialog.h" +#include "editaddressdialog.h" +#include "optionsmodel.h" +#include "guiutil.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +TransactionView::TransactionView(QWidget *parent) : + QWidget(parent), model(0), transactionProxyModel(0), + transactionView(0) +{ + // Build filter row + setContentsMargins(0,0,0,0); + + QHBoxLayout *hlayout = new QHBoxLayout(); + hlayout->setContentsMargins(0,0,0,0); +#ifdef Q_OS_MAC + hlayout->setSpacing(5); + hlayout->addSpacing(26); +#else + hlayout->setSpacing(0); + hlayout->addSpacing(23); +#endif + + dateWidget = new QComboBox(this); +#ifdef Q_OS_MAC + dateWidget->setFixedWidth(121); +#else + dateWidget->setFixedWidth(120); +#endif + dateWidget->addItem(tr("All"), All); + dateWidget->addItem(tr("Today"), Today); + dateWidget->addItem(tr("This week"), ThisWeek); + dateWidget->addItem(tr("This month"), ThisMonth); + dateWidget->addItem(tr("Last month"), LastMonth); + dateWidget->addItem(tr("This year"), ThisYear); + dateWidget->addItem(tr("Range..."), Range); + hlayout->addWidget(dateWidget); + + typeWidget = new QComboBox(this); +#ifdef Q_OS_MAC + typeWidget->setFixedWidth(121); +#else + typeWidget->setFixedWidth(120); +#endif + + typeWidget->addItem(tr("All"), TransactionFilterProxy::ALL_TYPES); + typeWidget->addItem(tr("Received with"), TransactionFilterProxy::TYPE(TransactionRecord::RecvWithAddress) | + TransactionFilterProxy::TYPE(TransactionRecord::RecvFromOther)); + typeWidget->addItem(tr("Sent to"), TransactionFilterProxy::TYPE(TransactionRecord::SendToAddress) | + TransactionFilterProxy::TYPE(TransactionRecord::SendToOther)); + typeWidget->addItem(tr("To yourself"), TransactionFilterProxy::TYPE(TransactionRecord::SendToSelf)); + typeWidget->addItem(tr("Minted"), TransactionFilterProxy::TYPE(TransactionRecord::StakeMint)); + typeWidget->addItem(tr("Mined"), TransactionFilterProxy::TYPE(TransactionRecord::Generated)); + typeWidget->addItem(tr("Other"), TransactionFilterProxy::TYPE(TransactionRecord::Other)); + + hlayout->addWidget(typeWidget); + + addressWidget = new QLineEdit(this); +#if QT_VERSION >= 0x040700 + /* Do not move this to the XML file, Qt before 4.7 will choke on it */ + addressWidget->setPlaceholderText(tr("Enter address or label to search")); +#endif + hlayout->addWidget(addressWidget); + + amountWidget = new QLineEdit(this); +#if QT_VERSION >= 0x040700 + /* Do not move this to the XML file, Qt before 4.7 will choke on it */ + amountWidget->setPlaceholderText(tr("Min amount")); +#endif +#ifdef Q_OS_MAC + amountWidget->setFixedWidth(97); +#else + amountWidget->setFixedWidth(100); +#endif + amountWidget->setValidator(new QDoubleValidator(0, 1e20, 8, this)); + hlayout->addWidget(amountWidget); + + QVBoxLayout *vlayout = new QVBoxLayout(this); + vlayout->setContentsMargins(0,0,0,0); + vlayout->setSpacing(0); + + QTableView *view = new QTableView(this); + vlayout->addLayout(hlayout); + vlayout->addWidget(createDateRangeWidget()); + vlayout->addWidget(view); + vlayout->setSpacing(0); + int width = view->verticalScrollBar()->sizeHint().width(); + // Cover scroll bar width with spacing +#ifdef Q_OS_MAC + hlayout->addSpacing(width+2); +#else + hlayout->addSpacing(width); +#endif + // Always show scroll bar + view->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); + view->setTabKeyNavigation(false); + view->setContextMenuPolicy(Qt::CustomContextMenu); + + transactionView = view; + + // Actions + QAction *copyAddressAction = new QAction(tr("Copy address"), this); + QAction *copyLabelAction = new QAction(tr("Copy label"), this); + QAction *copyAmountAction = new QAction(tr("Copy amount"), this); + QAction *editLabelAction = new QAction(tr("Edit label"), this); + QAction *showDetailsAction = new QAction(tr("Show transaction details"), this); + + contextMenu = new QMenu(); + contextMenu->addAction(copyAddressAction); + contextMenu->addAction(copyLabelAction); + contextMenu->addAction(copyAmountAction); + contextMenu->addAction(editLabelAction); + contextMenu->addAction(showDetailsAction); + + // Connect actions + connect(dateWidget, SIGNAL(activated(int)), this, SLOT(chooseDate(int))); + connect(typeWidget, SIGNAL(activated(int)), this, SLOT(chooseType(int))); + connect(addressWidget, SIGNAL(textChanged(QString)), this, SLOT(changedPrefix(QString))); + connect(amountWidget, SIGNAL(textChanged(QString)), this, SLOT(changedAmount(QString))); + + connect(view, SIGNAL(doubleClicked(QModelIndex)), this, SIGNAL(doubleClicked(QModelIndex))); + connect(view, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(contextualMenu(QPoint))); + + connect(copyAddressAction, SIGNAL(triggered()), this, SLOT(copyAddress())); + connect(copyLabelAction, SIGNAL(triggered()), this, SLOT(copyLabel())); + connect(copyAmountAction, SIGNAL(triggered()), this, SLOT(copyAmount())); + connect(editLabelAction, SIGNAL(triggered()), this, SLOT(editLabel())); + connect(showDetailsAction, SIGNAL(triggered()), this, SLOT(showDetails())); +} + +void TransactionView::setModel(WalletModel *model) +{ + this->model = model; + if(model) + { + transactionProxyModel = new TransactionFilterProxy(this); + transactionProxyModel->setSourceModel(model->getTransactionTableModel()); + transactionProxyModel->setDynamicSortFilter(true); + transactionProxyModel->setSortCaseSensitivity(Qt::CaseInsensitive); + transactionProxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive); + + transactionProxyModel->setSortRole(Qt::EditRole); + + transactionView->setModel(transactionProxyModel); + transactionView->setAlternatingRowColors(true); + transactionView->setSelectionBehavior(QAbstractItemView::SelectRows); + transactionView->setSelectionMode(QAbstractItemView::ExtendedSelection); + transactionView->setSortingEnabled(true); + transactionView->sortByColumn(TransactionTableModel::Date, Qt::DescendingOrder); + transactionView->verticalHeader()->hide(); + + transactionView->horizontalHeader()->resizeSection( + TransactionTableModel::Status, 23); + transactionView->horizontalHeader()->resizeSection( + TransactionTableModel::Date, 120); + transactionView->horizontalHeader()->resizeSection( + TransactionTableModel::Type, 120); + transactionView->horizontalHeader()->setResizeMode( + TransactionTableModel::ToAddress, QHeaderView::Stretch); + transactionView->horizontalHeader()->resizeSection( + TransactionTableModel::Amount, 100); + } +} + +void TransactionView::chooseDate(int idx) +{ + if(!transactionProxyModel) + return; + QDate current = QDate::currentDate(); + dateRangeWidget->setVisible(false); + switch(dateWidget->itemData(idx).toInt()) + { + case All: + transactionProxyModel->setDateRange( + TransactionFilterProxy::MIN_DATE, + TransactionFilterProxy::MAX_DATE); + break; + case Today: + transactionProxyModel->setDateRange( + QDateTime(current), + TransactionFilterProxy::MAX_DATE); + break; + case ThisWeek: { + // Find last Monday + QDate startOfWeek = current.addDays(-(current.dayOfWeek()-1)); + transactionProxyModel->setDateRange( + QDateTime(startOfWeek), + TransactionFilterProxy::MAX_DATE); + + } break; + case ThisMonth: + transactionProxyModel->setDateRange( + QDateTime(QDate(current.year(), current.month(), 1)), + TransactionFilterProxy::MAX_DATE); + break; + case LastMonth: + transactionProxyModel->setDateRange( + QDateTime(QDate(current.year(), current.month()-1, 1)), + QDateTime(QDate(current.year(), current.month(), 1))); + break; + case ThisYear: + transactionProxyModel->setDateRange( + QDateTime(QDate(current.year(), 1, 1)), + TransactionFilterProxy::MAX_DATE); + break; + case Range: + dateRangeWidget->setVisible(true); + dateRangeChanged(); + break; + } +} + +void TransactionView::chooseType(int idx) +{ + if(!transactionProxyModel) + return; + transactionProxyModel->setTypeFilter( + typeWidget->itemData(idx).toInt()); +} + +void TransactionView::changedPrefix(const QString &prefix) +{ + if(!transactionProxyModel) + return; + transactionProxyModel->setAddressPrefix(prefix); +} + +void TransactionView::changedAmount(const QString &amount) +{ + if(!transactionProxyModel) + return; + qint64 amount_parsed = 0; + if(BitcoinUnits::parse(model->getOptionsModel()->getDisplayUnit(), amount, &amount_parsed)) + { + transactionProxyModel->setMinAmount(amount_parsed); + } + else + { + transactionProxyModel->setMinAmount(0); + } +} + +void TransactionView::exportClicked() +{ + // CSV is currently the only supported format + QString filename = GUIUtil::getSaveFileName( + this, + tr("Export Transaction Data"), QString(), + tr("Comma separated file (*.csv)")); + + if (filename.isNull()) return; + + CSVModelWriter writer(filename); + + // name, column, role + writer.setModel(transactionProxyModel); + writer.addColumn(tr("Confirmed"), 0, TransactionTableModel::ConfirmedRole); + writer.addColumn(tr("Date"), 0, TransactionTableModel::DateRole); + writer.addColumn(tr("Type"), TransactionTableModel::Type, Qt::EditRole); + writer.addColumn(tr("Label"), 0, TransactionTableModel::LabelRole); + writer.addColumn(tr("Address"), 0, TransactionTableModel::AddressRole); + writer.addColumn(tr("Amount"), 0, TransactionTableModel::FormattedAmountRole); + writer.addColumn(tr("ID"), 0, TransactionTableModel::TxIDRole); + + if(!writer.write()) + { + QMessageBox::critical(this, tr("Error exporting"), tr("Could not write to file %1.").arg(filename), + QMessageBox::Abort, QMessageBox::Abort); + } +} + +void TransactionView::contextualMenu(const QPoint &point) +{ + QModelIndex index = transactionView->indexAt(point); + if(index.isValid()) + { + contextMenu->exec(QCursor::pos()); + } +} + +void TransactionView::copyAddress() +{ + GUIUtil::copyEntryData(transactionView, 0, TransactionTableModel::AddressRole); +} + +void TransactionView::copyLabel() +{ + GUIUtil::copyEntryData(transactionView, 0, TransactionTableModel::LabelRole); +} + +void TransactionView::copyAmount() +{ + GUIUtil::copyEntryData(transactionView, 0, TransactionTableModel::FormattedAmountRole); +} + +void TransactionView::editLabel() +{ + if(!transactionView->selectionModel() ||!model) + return; + QModelIndexList selection = transactionView->selectionModel()->selectedRows(); + if(!selection.isEmpty()) + { + AddressTableModel *addressBook = model->getAddressTableModel(); + if(!addressBook) + return; + QString address = selection.at(0).data(TransactionTableModel::AddressRole).toString(); + if(address.isEmpty()) + { + // If this transaction has no associated address, exit + return; + } + // Is address in address book? Address book can miss address when a transaction is + // sent from outside the UI. + int idx = addressBook->lookupAddress(address); + if(idx != -1) + { + // Edit sending / receiving address + QModelIndex modelIdx = addressBook->index(idx, 0, QModelIndex()); + // Determine type of address, launch appropriate editor dialog type + QString type = modelIdx.data(AddressTableModel::TypeRole).toString(); + + EditAddressDialog dlg(type==AddressTableModel::Receive + ? EditAddressDialog::EditReceivingAddress + : EditAddressDialog::EditSendingAddress, + this); + dlg.setModel(addressBook); + dlg.loadRow(idx); + dlg.exec(); + } + else + { + // Add sending address + EditAddressDialog dlg(EditAddressDialog::NewSendingAddress, + this); + dlg.setModel(addressBook); + dlg.setAddress(address); + dlg.exec(); + } + } +} + +void TransactionView::showDetails() +{ + if(!transactionView->selectionModel()) + return; + QModelIndexList selection = transactionView->selectionModel()->selectedRows(); + if(!selection.isEmpty()) + { + TransactionDescDialog dlg(selection.at(0)); + dlg.exec(); + } +} + +QWidget *TransactionView::createDateRangeWidget() +{ + dateRangeWidget = new QFrame(); + dateRangeWidget->setFrameStyle(QFrame::Panel | QFrame::Raised); + dateRangeWidget->setContentsMargins(1,1,1,1); + QHBoxLayout *layout = new QHBoxLayout(dateRangeWidget); + layout->setContentsMargins(0,0,0,0); + layout->addSpacing(23); + layout->addWidget(new QLabel(tr("Range:"))); + + dateFrom = new QDateTimeEdit(this); + dateFrom->setDisplayFormat("dd/MM/yy"); + dateFrom->setCalendarPopup(true); + dateFrom->setMinimumWidth(100); + dateFrom->setDate(QDate::currentDate().addDays(-7)); + layout->addWidget(dateFrom); + layout->addWidget(new QLabel(tr("to"))); + + dateTo = new QDateTimeEdit(this); + dateTo->setDisplayFormat("dd/MM/yy"); + dateTo->setCalendarPopup(true); + dateTo->setMinimumWidth(100); + dateTo->setDate(QDate::currentDate()); + layout->addWidget(dateTo); + layout->addStretch(); + + // Hide by default + dateRangeWidget->setVisible(false); + + // Notify on change + connect(dateFrom, SIGNAL(dateChanged(QDate)), this, SLOT(dateRangeChanged())); + connect(dateTo, SIGNAL(dateChanged(QDate)), this, SLOT(dateRangeChanged())); + + return dateRangeWidget; +} + +void TransactionView::dateRangeChanged() +{ + if(!transactionProxyModel) + return; + transactionProxyModel->setDateRange( + QDateTime(dateFrom->date()), + QDateTime(dateTo->date()).addDays(1)); +} + +void TransactionView::focusTransaction(const QModelIndex &idx) +{ + if(!transactionProxyModel) + return; + QModelIndex targetIdx = transactionProxyModel->mapFromSource(idx); + transactionView->scrollTo(targetIdx); + transactionView->setCurrentIndex(targetIdx); + transactionView->setFocus(); +} diff --git a/src/qt/transactionview.h b/src/qt/transactionview.h new file mode 100644 index 0000000..4ade3ec --- /dev/null +++ b/src/qt/transactionview.h @@ -0,0 +1,82 @@ +#ifndef TRANSACTIONVIEW_H +#define TRANSACTIONVIEW_H + +#include + +class WalletModel; +class TransactionFilterProxy; + +QT_BEGIN_NAMESPACE +class QTableView; +class QComboBox; +class QLineEdit; +class QModelIndex; +class QMenu; +class QFrame; +class QDateTimeEdit; +QT_END_NAMESPACE + +/** Widget showing the transaction list for a wallet, including a filter row. + Using the filter row, the user can view or export a subset of the transactions. + */ +class TransactionView : public QWidget +{ + Q_OBJECT +public: + explicit TransactionView(QWidget *parent = 0); + + void setModel(WalletModel *model); + + // Date ranges for filter + enum DateEnum + { + All, + Today, + ThisWeek, + ThisMonth, + LastMonth, + ThisYear, + Range + }; + +private: + WalletModel *model; + TransactionFilterProxy *transactionProxyModel; + QTableView *transactionView; + + QComboBox *dateWidget; + QComboBox *typeWidget; + QLineEdit *addressWidget; + QLineEdit *amountWidget; + + QMenu *contextMenu; + + QFrame *dateRangeWidget; + QDateTimeEdit *dateFrom; + QDateTimeEdit *dateTo; + + QWidget *createDateRangeWidget(); + +private slots: + void contextualMenu(const QPoint &); + void dateRangeChanged(); + void showDetails(); + void copyAddress(); + void editLabel(); + void copyLabel(); + void copyAmount(); + +signals: + void doubleClicked(const QModelIndex&); + +public slots: + void chooseDate(int idx); + void chooseType(int idx); + void changedPrefix(const QString &prefix); + void changedAmount(const QString &amount); + void exportClicked(); + void focusTransaction(const QModelIndex&); + +}; + +#endif // TRANSACTIONVIEW_H diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp new file mode 100644 index 0000000..59bf104 --- /dev/null +++ b/src/qt/walletmodel.cpp @@ -0,0 +1,456 @@ +#include "walletmodel.h" +#include "guiconstants.h" +#include "optionsmodel.h" +#include "addresstablemodel.h" +#include "transactiontablemodel.h" + +#include "ui_interface.h" +#include "wallet.h" +#include "walletdb.h" // for BackupWallet +#include "base58.h" + +#include +#include + +WalletModel::WalletModel(CWallet *wallet, OptionsModel *optionsModel, QObject *parent) : + QObject(parent), wallet(wallet), optionsModel(optionsModel), addressTableModel(0), + transactionTableModel(0), + cachedBalance(0), cachedStake(0), cachedUnconfirmedBalance(0), cachedImmatureBalance(0), + cachedNumTransactions(0), + cachedEncryptionStatus(Unencrypted), + cachedNumBlocks(0) +{ + addressTableModel = new AddressTableModel(wallet, this); + transactionTableModel = new TransactionTableModel(wallet, this); + + // This timer will be fired repeatedly to update the balance + pollTimer = new QTimer(this); + connect(pollTimer, SIGNAL(timeout()), this, SLOT(pollBalanceChanged())); + pollTimer->start(MODEL_UPDATE_DELAY); + + subscribeToCoreSignals(); +} + +WalletModel::~WalletModel() +{ + unsubscribeFromCoreSignals(); +} + +qint64 WalletModel::getBalance() const +{ + return wallet->GetBalance(); +} + +qint64 WalletModel::getUnconfirmedBalance() const +{ + return wallet->GetUnconfirmedBalance(); +} + +qint64 WalletModel::getStake() const +{ + return wallet->GetStake(); +} + +qint64 WalletModel::getImmatureBalance() const +{ + return wallet->GetImmatureBalance(); +} + +int WalletModel::getNumTransactions() const +{ + int numTransactions = 0; + { + LOCK(wallet->cs_wallet); + numTransactions = wallet->mapWallet.size(); + } + return numTransactions; +} + +void WalletModel::updateStatus() +{ + EncryptionStatus newEncryptionStatus = getEncryptionStatus(); + + if(cachedEncryptionStatus != newEncryptionStatus) + emit encryptionStatusChanged(newEncryptionStatus); +} + +void WalletModel::pollBalanceChanged() +{ + if(nBestHeight != cachedNumBlocks) + { + // Balance and number of transactions might have changed + cachedNumBlocks = nBestHeight; + checkBalanceChanged(); + } +} + +void WalletModel::checkBalanceChanged() +{ + qint64 newBalance = getBalance(); + qint64 newStake = getStake(); + qint64 newUnconfirmedBalance = getUnconfirmedBalance(); + qint64 newImmatureBalance = getImmatureBalance(); + + if(cachedBalance != newBalance || cachedStake != newStake || cachedUnconfirmedBalance != newUnconfirmedBalance || cachedImmatureBalance != newImmatureBalance) + { + cachedBalance = newBalance; + cachedStake = newStake; + cachedUnconfirmedBalance = newUnconfirmedBalance; + cachedImmatureBalance = newImmatureBalance; + emit balanceChanged(newBalance, newStake, newUnconfirmedBalance, newImmatureBalance); + } +} + +void WalletModel::updateTransaction(const QString &hash, int status) +{ + if(transactionTableModel) + transactionTableModel->updateTransaction(hash, status); + + // Balance and number of transactions might have changed + checkBalanceChanged(); + + int newNumTransactions = getNumTransactions(); + if(cachedNumTransactions != newNumTransactions) + { + cachedNumTransactions = newNumTransactions; + emit numTransactionsChanged(newNumTransactions); + } +} + +void WalletModel::updateAddressBook(const QString &address, const QString &label, bool isMine, int status) +{ + if(addressTableModel) + addressTableModel->updateEntry(address, label, isMine, status); +} + +bool WalletModel::validateAddress(const QString &address) +{ + CBitcoinAddress addressParsed(address.toStdString()); + return addressParsed.IsValid(); +} + +WalletModel::SendCoinsReturn WalletModel::sendCoins(const QList &recipients, const CCoinControl *coinControl) +{ + qint64 total = 0; + QSet setAddress; + QString hex; + + if(recipients.empty()) + { + return OK; + } + + // Pre-check input data for validity + foreach(const SendCoinsRecipient &rcp, recipients) + { + if(!validateAddress(rcp.address)) + { + return InvalidAddress; + } + setAddress.insert(rcp.address); + + if(rcp.amount <= 0) + { + return InvalidAmount; + } + total += rcp.amount; + } + + if(recipients.size() > setAddress.size()) + { + return DuplicateAddress; + } + + int64 nBalance = 0; + std::vector vCoins; + wallet->AvailableCoins(vCoins, true, coinControl); + + BOOST_FOREACH(const COutput& out, vCoins) + nBalance += out.tx->vout[out.i].nValue; + if(total > nBalance) + { + return AmountExceedsBalance; + } + + if((total + nTransactionFee) > nBalance) + { + return SendCoinsReturn(AmountWithFeeExceedsBalance, nTransactionFee); + } + + { + LOCK2(cs_main, wallet->cs_wallet); + + // Sendmany + std::vector > vecSend; + foreach(const SendCoinsRecipient &rcp, recipients) + { + CScript scriptPubKey; + scriptPubKey.SetDestination(CBitcoinAddress(rcp.address.toStdString()).Get()); + vecSend.push_back(make_pair(scriptPubKey, rcp.amount)); + } + + CWalletTx wtx; + CReserveKey keyChange(wallet); + int64 nFeeRequired = 0; + bool fCreated = wallet->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired, coinControl); + + if(!fCreated) + { + if((total + nFeeRequired) > nBalance) // FIXME: could cause collisions in the future + { + return SendCoinsReturn(AmountWithFeeExceedsBalance, nFeeRequired); + } + return TransactionCreationFailed; + } + if(!uiInterface.ThreadSafeAskFee(nFeeRequired, tr("Sending...").toStdString())) + { + return Aborted; + } + if(!wallet->CommitTransaction(wtx, keyChange)) + { + return TransactionCommitFailed; + } + hex = QString::fromStdString(wtx.GetHash().GetHex()); + } + + // Add addresses / update labels that we've sent to to the address book + foreach(const SendCoinsRecipient &rcp, recipients) + { + std::string strAddress = rcp.address.toStdString(); + CTxDestination dest = CBitcoinAddress(strAddress).Get(); + std::string strLabel = rcp.label.toStdString(); + { + LOCK(wallet->cs_wallet); + + std::map::iterator mi = wallet->mapAddressBook.find(dest); + + // Check if we have a new address or an updated label + if (mi == wallet->mapAddressBook.end() || mi->second != strLabel) + { + wallet->SetAddressBookName(dest, strLabel); + } + } + } + + return SendCoinsReturn(OK, 0, hex); +} + +OptionsModel *WalletModel::getOptionsModel() +{ + return optionsModel; +} + +AddressTableModel *WalletModel::getAddressTableModel() +{ + return addressTableModel; +} + +TransactionTableModel *WalletModel::getTransactionTableModel() +{ + return transactionTableModel; +} + +WalletModel::EncryptionStatus WalletModel::getEncryptionStatus() const +{ + if(!wallet->IsCrypted()) + { + return Unencrypted; + } + else if(wallet->IsLocked()) + { + return Locked; + } + else + { + return Unlocked; + } +} + +bool WalletModel::setWalletEncrypted(bool encrypted, const SecureString &passphrase) +{ + if(encrypted) + { + // Encrypt + return wallet->EncryptWallet(passphrase); + } + else + { + // Decrypt -- TODO; not supported yet + return false; + } +} + +bool WalletModel::setWalletLocked(bool locked, const SecureString &passPhrase) +{ + if(locked) + { + // Lock + return wallet->Lock(); + } + else + { + // Unlock + return wallet->Unlock(passPhrase); + } +} + +bool WalletModel::changePassphrase(const SecureString &oldPass, const SecureString &newPass) +{ + bool retval; + { + LOCK(wallet->cs_wallet); + wallet->Lock(); // Make sure wallet is locked before attempting pass change + retval = wallet->ChangeWalletPassphrase(oldPass, newPass); + } + return retval; +} + +bool WalletModel::backupWallet(const QString &filename) +{ + return BackupWallet(*wallet, filename.toLocal8Bit().data()); +} + +// Handlers for core signals +static void NotifyKeyStoreStatusChanged(WalletModel *walletmodel, CCryptoKeyStore *wallet) +{ + OutputDebugStringF("NotifyKeyStoreStatusChanged\n"); + QMetaObject::invokeMethod(walletmodel, "updateStatus", Qt::QueuedConnection); +} + +static void NotifyAddressBookChanged(WalletModel *walletmodel, CWallet *wallet, const CTxDestination &address, const std::string &label, bool isMine, ChangeType status) +{ + OutputDebugStringF("NotifyAddressBookChanged %s %s isMine=%i status=%i\n", CBitcoinAddress(address).ToString().c_str(), label.c_str(), isMine, status); + QMetaObject::invokeMethod(walletmodel, "updateAddressBook", Qt::QueuedConnection, + Q_ARG(QString, QString::fromStdString(CBitcoinAddress(address).ToString())), + Q_ARG(QString, QString::fromStdString(label)), + Q_ARG(bool, isMine), + Q_ARG(int, status)); +} + +static void NotifyTransactionChanged(WalletModel *walletmodel, CWallet *wallet, const uint256 &hash, ChangeType status) +{ + OutputDebugStringF("NotifyTransactionChanged %s status=%i\n", hash.GetHex().c_str(), status); + QMetaObject::invokeMethod(walletmodel, "updateTransaction", Qt::QueuedConnection, + Q_ARG(QString, QString::fromStdString(hash.GetHex())), + Q_ARG(int, status)); +} + +void WalletModel::subscribeToCoreSignals() +{ + // Connect signals to wallet + wallet->NotifyStatusChanged.connect(boost::bind(&NotifyKeyStoreStatusChanged, this, _1)); + wallet->NotifyAddressBookChanged.connect(boost::bind(NotifyAddressBookChanged, this, _1, _2, _3, _4, _5)); + wallet->NotifyTransactionChanged.connect(boost::bind(NotifyTransactionChanged, this, _1, _2, _3)); +} + +void WalletModel::unsubscribeFromCoreSignals() +{ + // Disconnect signals from wallet + wallet->NotifyStatusChanged.disconnect(boost::bind(&NotifyKeyStoreStatusChanged, this, _1)); + wallet->NotifyAddressBookChanged.disconnect(boost::bind(NotifyAddressBookChanged, this, _1, _2, _3, _4, _5)); + wallet->NotifyTransactionChanged.disconnect(boost::bind(NotifyTransactionChanged, this, _1, _2, _3)); +} + +// WalletModel::UnlockContext implementation +WalletModel::UnlockContext WalletModel::requestUnlock() +{ + bool was_locked = getEncryptionStatus() == Locked; + if(was_locked) + { + // Request UI to unlock wallet + emit requireUnlock(); + } + // If wallet is still locked, unlock was failed or cancelled, mark context as invalid + bool valid = getEncryptionStatus() != Locked; + + return UnlockContext(this, valid, was_locked); +} + +WalletModel::UnlockContext::UnlockContext(WalletModel *wallet, bool valid, bool relock): + wallet(wallet), + valid(valid), + relock(relock) +{ +} + +WalletModel::UnlockContext::~UnlockContext() +{ + if(valid && relock) + { + wallet->setWalletLocked(true); + } +} + +void WalletModel::UnlockContext::CopyFrom(const UnlockContext& rhs) +{ + // Transfer context; old object no longer relocks wallet + *this = rhs; + rhs.relock = false; +} + + bool WalletModel::getPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const + { + return wallet->GetPubKey(address, vchPubKeyOut); + } + + // returns a list of COutputs from COutPoints + void WalletModel::getOutputs(const std::vector& vOutpoints, std::vector& vOutputs) + { + BOOST_FOREACH(const COutPoint& outpoint, vOutpoints) + { + if (!wallet->mapWallet.count(outpoint.hash)) continue; + COutput out(&wallet->mapWallet[outpoint.hash], outpoint.n, wallet->mapWallet[outpoint.hash].GetDepthInMainChain()); + vOutputs.push_back(out); + } + } + + // AvailableCoins + LockedCoins grouped by wallet address (put change in one group with wallet address) + void WalletModel::listCoins(std::map >& mapCoins) const + { + std::vector vCoins; + wallet->AvailableCoins(vCoins); + std::vector vLockedCoins; + + // add locked coins + BOOST_FOREACH(const COutPoint& outpoint, vLockedCoins) + { + if (!wallet->mapWallet.count(outpoint.hash)) continue; + COutput out(&wallet->mapWallet[outpoint.hash], outpoint.n, wallet->mapWallet[outpoint.hash].GetDepthInMainChain()); + vCoins.push_back(out); + } + + BOOST_FOREACH(const COutput& out, vCoins) + { + COutput cout = out; + + while (wallet->IsChange(cout.tx->vout[cout.i]) && cout.tx->vin.size() > 0 && wallet->IsMine(cout.tx->vin[0])) + { + if (!wallet->mapWallet.count(cout.tx->vin[0].prevout.hash)) break; + cout = COutput(&wallet->mapWallet[cout.tx->vin[0].prevout.hash], cout.tx->vin[0].prevout.n, 0); + } + + CTxDestination address; + if(!ExtractDestination(cout.tx->vout[cout.i].scriptPubKey, address)) continue; + mapCoins[CBitcoinAddress(address).ToString().c_str()].push_back(out); + } + } + + bool WalletModel::isLockedCoin(uint256 hash, unsigned int n) const + { + return false; + } + + void WalletModel::lockCoin(COutPoint& output) + { + return; + } + + void WalletModel::unlockCoin(COutPoint& output) + { + return; + } + + void WalletModel::listLockedCoins(std::vector& vOutpts) + { + return; + } diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h new file mode 100644 index 0000000..0a1ffd5 --- /dev/null +++ b/src/qt/walletmodel.h @@ -0,0 +1,185 @@ +#ifndef WALLETMODEL_H +#define WALLETMODEL_H + +#include +#include +#include + +#include "allocators.h" /* for SecureString */ + +class OptionsModel; +class AddressTableModel; +class TransactionTableModel; +class CWallet; +class CKeyID; +class CPubKey; +class COutput; +class COutPoint; +class uint256; +class CCoinControl; + +QT_BEGIN_NAMESPACE +class QTimer; +QT_END_NAMESPACE + +class SendCoinsRecipient +{ +public: + QString address; + QString label; + qint64 amount; +}; + +/** Interface to Bitcoin wallet from Qt view code. */ +class WalletModel : public QObject +{ + Q_OBJECT + +public: + explicit WalletModel(CWallet *wallet, OptionsModel *optionsModel, QObject *parent = 0); + ~WalletModel(); + + enum StatusCode // Returned by sendCoins + { + OK, + InvalidAmount, + InvalidAddress, + AmountExceedsBalance, + AmountWithFeeExceedsBalance, + DuplicateAddress, + TransactionCreationFailed, // Error returned when wallet is still locked + TransactionCommitFailed, + Aborted + }; + + enum EncryptionStatus + { + Unencrypted, // !wallet->IsCrypted() + Locked, // wallet->IsCrypted() && wallet->IsLocked() + Unlocked // wallet->IsCrypted() && !wallet->IsLocked() + }; + + OptionsModel *getOptionsModel(); + AddressTableModel *getAddressTableModel(); + TransactionTableModel *getTransactionTableModel(); + + qint64 getBalance() const; + qint64 getStake() const; + qint64 getUnconfirmedBalance() const; + qint64 getImmatureBalance() const; + int getNumTransactions() const; + EncryptionStatus getEncryptionStatus() const; + + // Check address for validity + bool validateAddress(const QString &address); + + // Return status record for SendCoins, contains error id + information + struct SendCoinsReturn + { + SendCoinsReturn(StatusCode status=Aborted, + qint64 fee=0, + QString hex=QString()): + status(status), fee(fee), hex(hex) {} + StatusCode status; + qint64 fee; // is used in case status is "AmountWithFeeExceedsBalance" + QString hex; // is filled with the transaction hash if status is "OK" + }; + + // Send coins to a list of recipients + SendCoinsReturn sendCoins(const QList &recipients, const CCoinControl *coinControl=NULL); + + // Wallet encryption + bool setWalletEncrypted(bool encrypted, const SecureString &passphrase); + // Passphrase only needed when unlocking + bool setWalletLocked(bool locked, const SecureString &passPhrase=SecureString()); + bool changePassphrase(const SecureString &oldPass, const SecureString &newPass); + // Wallet backup + bool backupWallet(const QString &filename); + + // RAI object for unlocking wallet, returned by requestUnlock() + class UnlockContext + { + public: + UnlockContext(WalletModel *wallet, bool valid, bool relock); + ~UnlockContext(); + + bool isValid() const { return valid; } + + // Copy operator and constructor transfer the context + UnlockContext(const UnlockContext& obj) { CopyFrom(obj); } + UnlockContext& operator=(const UnlockContext& rhs) { CopyFrom(rhs); return *this; } + private: + WalletModel *wallet; + bool valid; + mutable bool relock; // mutable, as it can be set to false by copying + + void CopyFrom(const UnlockContext& rhs); + }; + + UnlockContext requestUnlock(); + + bool getPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const; + void getOutputs(const std::vector& vOutpoints, std::vector& vOutputs); + void listCoins(std::map >& mapCoins) const; + bool isLockedCoin(uint256 hash, unsigned int n) const; + void lockCoin(COutPoint& output); + void unlockCoin(COutPoint& output); + void listLockedCoins(std::vector& vOutpts); + +private: + CWallet *wallet; + + // Wallet has an options model for wallet-specific options + // (transaction fee, for example) + OptionsModel *optionsModel; + + AddressTableModel *addressTableModel; + TransactionTableModel *transactionTableModel; + + // Cache some values to be able to detect changes + qint64 cachedBalance; + qint64 cachedStake; + qint64 cachedUnconfirmedBalance; + qint64 cachedImmatureBalance; + qint64 cachedNumTransactions; + EncryptionStatus cachedEncryptionStatus; + int cachedNumBlocks; + + QTimer *pollTimer; + + void subscribeToCoreSignals(); + void unsubscribeFromCoreSignals(); + void checkBalanceChanged(); + + +public slots: + /* Wallet status might have changed */ + void updateStatus(); + /* New transaction, or transaction changed status */ + void updateTransaction(const QString &hash, int status); + /* New, updated or removed address book entry */ + void updateAddressBook(const QString &address, const QString &label, bool isMine, int status); + /* Current, immature or unconfirmed balance might have changed - emit 'balanceChanged' if so */ + void pollBalanceChanged(); + +signals: + // Signal that balance in wallet changed + void balanceChanged(qint64 balance, qint64 stake, qint64 unconfirmedBalance, qint64 immatureBalance); + + // Number of transactions in wallet changed + void numTransactionsChanged(int count); + + // Encryption status of wallet changed + void encryptionStatusChanged(int status); + + // Signal emitted when wallet needs to be unlocked + // It is valid behaviour for listeners to keep the wallet locked after this signal; + // this means that the unlocking failed or was cancelled. + void requireUnlock(); + + // Asynchronous error notification + void error(const QString &title, const QString &message, bool modal); +}; + + +#endif // WALLETMODEL_H diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp new file mode 100644 index 0000000..e1f74da --- /dev/null +++ b/src/rpcblockchain.cpp @@ -0,0 +1,256 @@ +// Copyright (c) 2010 Satoshi Nakamoto +// Copyright (c) 2009-2012 The Bitcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "main.h" +#include "bitcoinrpc.h" + +using namespace json_spirit; +using namespace std; + +extern void TxToJSON(const CTransaction& tx, const uint256 hashBlock, json_spirit::Object& entry); + +double GetDifficulty(const CBlockIndex* blockindex) +{ + // Floating point number that is a multiple of the minimum difficulty, + // minimum difficulty = 1.0. + if (blockindex == NULL) + { + if (pindexBest == NULL) + return 1.0; + else + blockindex = GetLastBlockIndex(pindexBest, false); + } + + int nShift = (blockindex->nBits >> 24) & 0xff; + + double dDiff = + (double)0x0000ffff / (double)(blockindex->nBits & 0x00ffffff); + + while (nShift < 29) + { + dDiff *= 256.0; + nShift++; + } + while (nShift > 29) + { + dDiff /= 256.0; + nShift--; + } + + return dDiff; +} + +double GetPoSKernelPS() +{ + int nPoSInterval = 72; + double dStakeKernelsTriedAvg = 0; + int nStakesHandled = 0, nStakesTime = 0; + + CBlockIndex* pindex = pindexBest;; + CBlockIndex* pindexPrevStake = NULL; + + while (pindex && nStakesHandled < nPoSInterval) + { + if (pindex->IsProofOfStake()) + { + dStakeKernelsTriedAvg += GetDifficulty(pindex) * 4294967296.0; + nStakesTime += pindexPrevStake ? (pindexPrevStake->nTime - pindex->nTime) : 0; + pindexPrevStake = pindex; + nStakesHandled++; + } + + pindex = pindex->pprev; + } + + return nStakesTime ? dStakeKernelsTriedAvg / nStakesTime : 0; +} + +Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool fPrintTransactionDetail) +{ + Object result; + result.push_back(Pair("hash", block.GetHash().GetHex())); + CMerkleTx txGen(block.vtx[0]); + txGen.SetMerkleBranch(&block); + result.push_back(Pair("confirmations", (int)txGen.GetDepthInMainChain())); + result.push_back(Pair("size", (int)::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION))); + result.push_back(Pair("height", blockindex->nHeight)); + result.push_back(Pair("version", block.nVersion)); + result.push_back(Pair("merkleroot", block.hashMerkleRoot.GetHex())); + result.push_back(Pair("mint", ValueFromAmount(blockindex->nMint))); + result.push_back(Pair("time", (boost::int64_t)block.GetBlockTime())); + result.push_back(Pair("nonce", (boost::uint64_t)block.nNonce)); + result.push_back(Pair("bits", HexBits(block.nBits))); + result.push_back(Pair("difficulty", GetDifficulty(blockindex))); + + if (blockindex->pprev) + result.push_back(Pair("previousblockhash", blockindex->pprev->GetBlockHash().GetHex())); + if (blockindex->pnext) + result.push_back(Pair("nextblockhash", blockindex->pnext->GetBlockHash().GetHex())); + + result.push_back(Pair("flags", strprintf("%s%s", blockindex->IsProofOfStake()? "proof-of-stake" : "proof-of-work", blockindex->GeneratedStakeModifier()? " stake-modifier": ""))); + result.push_back(Pair("proofhash", blockindex->IsProofOfStake()? blockindex->hashProofOfStake.GetHex() : blockindex->GetBlockHash().GetHex())); + result.push_back(Pair("entropybit", (int)blockindex->GetStakeEntropyBit())); + result.push_back(Pair("modifier", strprintf("%016"PRI64x, blockindex->nStakeModifier))); + result.push_back(Pair("modifierchecksum", strprintf("%08x", blockindex->nStakeModifierChecksum))); + Array txinfo; + BOOST_FOREACH (const CTransaction& tx, block.vtx) + { + if (fPrintTransactionDetail) + { + Object entry; + + entry.push_back(Pair("txid", tx.GetHash().GetHex())); + TxToJSON(tx, 0, entry); + + txinfo.push_back(entry); + } + else + txinfo.push_back(tx.GetHash().GetHex()); + } + + result.push_back(Pair("tx", txinfo)); + result.push_back(Pair("signature", HexStr(block.vchBlockSig.begin(), block.vchBlockSig.end()))); + + return result; +} + + +Value getblockcount(const Array& params, bool fHelp) +{ + if (fHelp || params.size() != 0) + throw runtime_error( + "getblockcount\n" + "Returns the number of blocks in the longest block chain."); + + return nBestHeight; +} + + +Value getdifficulty(const Array& params, bool fHelp) +{ + if (fHelp || params.size() != 0) + throw runtime_error( + "getdifficulty\n" + "Returns the difficulty as a multiple of the minimum difficulty."); + + Object obj; + obj.push_back(Pair("proof-of-work", GetDifficulty())); + obj.push_back(Pair("proof-of-stake", GetDifficulty(GetLastBlockIndex(pindexBest, true)))); + obj.push_back(Pair("search-interval", (int)nLastCoinStakeSearchInterval)); + return obj; +} + + +Value settxfee(const Array& params, bool fHelp) +{ + if (fHelp || params.size() < 1 || params.size() > 1 || AmountFromValue(params[0]) < MIN_TX_FEE) + throw runtime_error( + "settxfee \n" + " is a real and is rounded to the nearest 0.01"); + + nTransactionFee = AmountFromValue(params[0]); + nTransactionFee = (nTransactionFee / CENT) * CENT; // round to cent + + return true; +} + +Value getrawmempool(const Array& params, bool fHelp) +{ + if (fHelp || params.size() != 0) + throw runtime_error( + "getrawmempool\n" + "Returns all transaction ids in memory pool."); + + vector vtxid; + mempool.queryHashes(vtxid); + + Array a; + BOOST_FOREACH(const uint256& hash, vtxid) + a.push_back(hash.ToString()); + + return a; +} + +Value getblockhash(const Array& params, bool fHelp) +{ + if (fHelp || params.size() != 1) + throw runtime_error( + "getblockhash \n" + "Returns hash of block in best-block-chain at ."); + + int nHeight = params[0].get_int(); + if (nHeight < 0 || nHeight > nBestHeight) + throw runtime_error("Block number out of range."); + + CBlockIndex* pblockindex = FindBlockByHeight(nHeight); + return pblockindex->phashBlock->GetHex(); +} + +Value getblock(const Array& params, bool fHelp) +{ + if (fHelp || params.size() < 1 || params.size() > 2) + throw runtime_error( + "getblock [txinfo]\n" + "txinfo optional to print more detailed tx info\n" + "Returns details of a block with given block-hash."); + + std::string strHash = params[0].get_str(); + uint256 hash(strHash); + + if (mapBlockIndex.count(hash) == 0) + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found"); + + CBlock block; + CBlockIndex* pblockindex = mapBlockIndex[hash]; + block.ReadFromDisk(pblockindex, true); + + return blockToJSON(block, pblockindex, params.size() > 1 ? params[1].get_bool() : false); +} + +Value getblockbynumber(const Array& params, bool fHelp) +{ + if (fHelp || params.size() < 1 || params.size() > 2) + throw runtime_error( + "getblock [txinfo]\n" + "txinfo optional to print more detailed tx info\n" + "Returns details of a block with given block-number."); + + int nHeight = params[0].get_int(); + if (nHeight < 0 || nHeight > nBestHeight) + throw runtime_error("Block number out of range."); + + CBlock block; + CBlockIndex* pblockindex = mapBlockIndex[hashBestChain]; + while (pblockindex->nHeight > nHeight) + pblockindex = pblockindex->pprev; + + uint256 hash = *pblockindex->phashBlock; + + pblockindex = mapBlockIndex[hash]; + block.ReadFromDisk(pblockindex, true); + + return blockToJSON(block, pblockindex, params.size() > 1 ? params[1].get_bool() : false); +} + +// triangles: get information of sync-checkpoint +Value getcheckpoint(const Array& params, bool fHelp) +{ + if (fHelp || params.size() != 0) + throw runtime_error( + "getcheckpoint\n" + "Show info of synchronized checkpoint.\n"); + + Object result; + CBlockIndex* pindexCheckpoint; + + result.push_back(Pair("synccheckpoint", Checkpoints::hashSyncCheckpoint.ToString().c_str())); + pindexCheckpoint = mapBlockIndex[Checkpoints::hashSyncCheckpoint]; + result.push_back(Pair("height", pindexCheckpoint->nHeight)); + result.push_back(Pair("timestamp", DateTimeStrFormat(pindexCheckpoint->GetBlockTime()).c_str())); + if (mapArgs.count("-checkpointkey")) + result.push_back(Pair("checkpointmaster", true)); + + return result; +} diff --git a/src/rpcdump.cpp b/src/rpcdump.cpp new file mode 100644 index 0000000..1bbc73f --- /dev/null +++ b/src/rpcdump.cpp @@ -0,0 +1,95 @@ +// Copyright (c) 2009-2012 Bitcoin Developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "init.h" // for pwalletMain +#include "bitcoinrpc.h" +#include "ui_interface.h" +#include "base58.h" + +#include + +#define printf OutputDebugStringF + +using namespace json_spirit; +using namespace std; + +class CTxDump +{ +public: + CBlockIndex *pindex; + int64 nValue; + bool fSpent; + CWalletTx* ptx; + int nOut; + CTxDump(CWalletTx* ptx = NULL, int nOut = -1) + { + pindex = NULL; + nValue = 0; + fSpent = false; + this->ptx = ptx; + this->nOut = nOut; + } +}; + +Value importprivkey(const Array& params, bool fHelp) +{ + if (fHelp || params.size() < 1 || params.size() > 2) + throw runtime_error( + "importprivkey [label]\n" + "Adds a private key (as returned by dumpprivkey) to your wallet."); + + string strSecret = params[0].get_str(); + string strLabel = ""; + if (params.size() > 1) + strLabel = params[1].get_str(); + CBitcoinSecret vchSecret; + bool fGood = vchSecret.SetString(strSecret); + + if (!fGood) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key"); + if (fWalletUnlockMintOnly) // triangles: no importprivkey in mint-only mode + throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Wallet is unlocked for minting only."); + + CKey key; + bool fCompressed; + CSecret secret = vchSecret.GetSecret(fCompressed); + key.SetSecret(secret, fCompressed); + CKeyID vchAddress = key.GetPubKey().GetID(); + { + LOCK2(cs_main, pwalletMain->cs_wallet); + + pwalletMain->MarkDirty(); + pwalletMain->SetAddressBookName(vchAddress, strLabel); + + if (!pwalletMain->AddKey(key)) + throw JSONRPCError(RPC_WALLET_ERROR, "Error adding key to wallet"); + + pwalletMain->ScanForWalletTransactions(pindexGenesisBlock, true); + pwalletMain->ReacceptWalletTransactions(); + } + + return Value::null; +} + +Value dumpprivkey(const Array& params, bool fHelp) +{ + if (fHelp || params.size() != 1) + throw runtime_error( + "dumpprivkey \n" + "Reveals the private key corresponding to ."); + + string strAddress = params[0].get_str(); + CBitcoinAddress address; + if (!address.SetString(strAddress)) + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid triangles address"); + if (fWalletUnlockMintOnly) // triangles: no dumpprivkey in mint-only mode + throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Wallet is unlocked for minting only."); + CKeyID keyID; + if (!address.GetKeyID(keyID)) + throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to a key"); + CSecret vchSecret; + bool fCompressed; + if (!pwalletMain->GetSecret(keyID, vchSecret, fCompressed)) + throw JSONRPCError(RPC_WALLET_ERROR, "Private key for address " + strAddress + " is not known"); + return CBitcoinSecret(vchSecret, fCompressed).ToString(); +} diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp new file mode 100644 index 0000000..f1729fa --- /dev/null +++ b/src/rpcmining.cpp @@ -0,0 +1,552 @@ +// Copyright (c) 2010 Satoshi Nakamoto +// Copyright (c) 2009-2012 The Bitcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "main.h" +#include "db.h" +#include "init.h" +#include "bitcoinrpc.h" + +using namespace json_spirit; +using namespace std; + +Value getgenerate(const Array& params, bool fHelp) +{ + if (fHelp || params.size() != 0) + throw runtime_error( + "getgenerate\n" + "Returns true or false."); + + return GetBoolArg("-gen"); +} + + +Value setgenerate(const Array& params, bool fHelp) +{ + if (fHelp || params.size() < 1 || params.size() > 2) + throw runtime_error( + "setgenerate [genproclimit]\n" + " is true or false to turn generation on or off.\n" + "Generation is limited to [genproclimit] processors, -1 is unlimited."); + + bool fGenerate = true; + if (params.size() > 0) + fGenerate = params[0].get_bool(); + + if (params.size() > 1) + { + int nGenProcLimit = params[1].get_int(); + mapArgs["-genproclimit"] = itostr(nGenProcLimit); + if (nGenProcLimit == 0) + fGenerate = false; + } + mapArgs["-gen"] = (fGenerate ? "1" : "0"); + + GenerateBitcoins(fGenerate, pwalletMain); + return Value::null; +} + + +Value gethashespersec(const Array& params, bool fHelp) +{ + if (fHelp || params.size() != 0) + throw runtime_error( + "gethashespersec\n" + "Returns a recent hashes per second performance measurement while generating."); + + if (GetTimeMillis() - nHPSTimerStart > 8000) + return (boost::int64_t)0; + return (boost::int64_t)dHashesPerSec; +} + + +Value getmininginfo(const Array& params, bool fHelp) +{ + if (fHelp || params.size() != 0) + throw runtime_error( + "getmininginfo\n" + "Returns an object containing mining-related information."); + + Object obj; + obj.push_back(Pair("blocks", (int)nBestHeight)); + obj.push_back(Pair("currentblocksize",(uint64_t)nLastBlockSize)); + obj.push_back(Pair("currentblocktx",(uint64_t)nLastBlockTx)); + obj.push_back(Pair("difficulty", (double)GetDifficulty())); + obj.push_back(Pair("errors", GetWarnings("statusbar"))); + obj.push_back(Pair("generate", GetBoolArg("-gen"))); + obj.push_back(Pair("genproclimit", (int)GetArg("-genproclimit", -1))); + obj.push_back(Pair("hashespersec", gethashespersec(params, false))); + obj.push_back(Pair("networkhashps", getnetworkhashps(params, false))); + obj.push_back(Pair("pooledtx", (uint64_t)mempool.size())); + obj.push_back(Pair("testnet", fTestNet)); + return obj; +} + +// Litecoin: Return average network hashes per second based on last number of blocks. +Value GetNetworkHashPS(int lookup) { + if (pindexBest == NULL) + return 0; + + // If lookup is -1, then use blocks since last difficulty change. + if (lookup <= 0) + lookup = pindexBest->nHeight % 2016 + 1; + + // If lookup is larger than chain, then set it to chain length. + if (lookup > pindexBest->nHeight) + lookup = pindexBest->nHeight; + + CBlockIndex* pindexPrev = pindexBest; + for (int i = 0; i < lookup; i++) + pindexPrev = pindexPrev->pprev; + + double timeDiff = pindexBest->GetBlockTime() - pindexPrev->GetBlockTime(); + double timePerBlock = timeDiff / lookup; + + return (boost::int64_t)(((double)GetDifficulty() * pow(2.0, 32)) / timePerBlock); +} + +Value getnetworkhashps(const Array& params, bool fHelp) +{ + if (fHelp || params.size() > 1) + throw runtime_error( + "getnetworkhashps [blocks]\n" + "Returns the estimated network hashes per second based on the last 120 blocks.\n" + "Pass in [blocks] to override # of blocks, -1 specifies since last difficulty change."); + + return GetNetworkHashPS(params.size() > 0 ? params[0].get_int() : 120); +} + + +Value getworkex(const Array& params, bool fHelp) +{ + if (fHelp || params.size() > 2) + throw runtime_error( + "getworkex [data, coinbase]\n" + "If [data, coinbase] is not specified, returns extended work data.\n" + ); + + if (vNodes.empty()) + throw JSONRPCError(-9, "triangles is not connected!"); + + if (IsInitialBlockDownload()) + throw JSONRPCError(-10, "triangles is downloading blocks..."); + + typedef map > mapNewBlock_t; + static mapNewBlock_t mapNewBlock; + static vector vNewBlock; + static CReserveKey reservekey(pwalletMain); + + if (params.size() == 0) + { + // Update block + static unsigned int nTransactionsUpdatedLast; + static CBlockIndex* pindexPrev; + static int64 nStart; + static CBlock* pblock; + if (pindexPrev != pindexBest || + (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 60)) + { + if (pindexPrev != pindexBest) + { + // Deallocate old blocks since they're obsolete now + mapNewBlock.clear(); + BOOST_FOREACH(CBlock* pblock, vNewBlock) + delete pblock; + vNewBlock.clear(); + } + nTransactionsUpdatedLast = nTransactionsUpdated; + pindexPrev = pindexBest; + nStart = GetTime(); + + // Create new block + pblock = CreateNewBlock(pwalletMain); + if (!pblock) + throw JSONRPCError(-7, "Out of memory"); + vNewBlock.push_back(pblock); + } + + // Update nTime + pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime()); + pblock->nNonce = 0; + + // Update nExtraNonce + static unsigned int nExtraNonce = 0; + IncrementExtraNonce(pblock, pindexPrev, nExtraNonce); + + // Save + mapNewBlock[pblock->hashMerkleRoot] = make_pair(pblock, pblock->vtx[0].vin[0].scriptSig); + + // Prebuild hash buffers + char pmidstate[32]; + char pdata[128]; + char phash1[64]; + FormatHashBuffers(pblock, pmidstate, pdata, phash1); + + uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256(); + + CTransaction coinbaseTx = pblock->vtx[0]; + std::vector merkle = pblock->GetMerkleBranch(0); + + Object result; + result.push_back(Pair("data", HexStr(BEGIN(pdata), END(pdata)))); + result.push_back(Pair("target", HexStr(BEGIN(hashTarget), END(hashTarget)))); + + CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION); + ssTx << coinbaseTx; + result.push_back(Pair("coinbase", HexStr(ssTx.begin(), ssTx.end()))); + + Array merkle_arr; + + BOOST_FOREACH(uint256 merkleh, merkle) { + merkle_arr.push_back(HexStr(BEGIN(merkleh), END(merkleh))); + } + + result.push_back(Pair("merkle", merkle_arr)); + + + return result; + } + else + { + // Parse parameters + vector vchData = ParseHex(params[0].get_str()); + vector coinbase; + + if(params.size() == 2) + coinbase = ParseHex(params[1].get_str()); + + if (vchData.size() != 128) + throw JSONRPCError(-8, "Invalid parameter"); + + CBlock* pdata = (CBlock*)&vchData[0]; + + // Byte reverse + for (int i = 0; i < 128/4; i++) + ((unsigned int*)pdata)[i] = ByteReverse(((unsigned int*)pdata)[i]); + + // Get saved block + if (!mapNewBlock.count(pdata->hashMerkleRoot)) + return false; + CBlock* pblock = mapNewBlock[pdata->hashMerkleRoot].first; + + pblock->nTime = pdata->nTime; + pblock->nNonce = pdata->nNonce; + + if(coinbase.size() == 0) + pblock->vtx[0].vin[0].scriptSig = mapNewBlock[pdata->hashMerkleRoot].second; + else + CDataStream(coinbase, SER_NETWORK, PROTOCOL_VERSION) >> pblock->vtx[0]; // FIXME - HACK! + + pblock->hashMerkleRoot = pblock->BuildMerkleTree(); + + if (!pblock->SignBlock(*pwalletMain)) + throw JSONRPCError(-100, "Unable to sign block, wallet locked?"); + + return CheckWork(pblock, *pwalletMain, reservekey); + } +} + + +Value getwork(const Array& params, bool fHelp) +{ + if (fHelp || params.size() > 1) + throw runtime_error( + "getwork [data]\n" + "If [data] is not specified, returns formatted hash data to work on:\n" + " \"midstate\" : precomputed hash state after hashing the first half of the data (DEPRECATED)\n" // deprecated + " \"data\" : block data\n" + " \"hash1\" : formatted hash buffer for second hash (DEPRECATED)\n" // deprecated + " \"target\" : little endian hash target\n" + "If [data] is specified, tries to solve the block and returns true if it was successful."); + + if (vNodes.empty()) + throw JSONRPCError(RPC_CLIENT_NOT_CONNECTED, "triangles is not connected!"); + + if (IsInitialBlockDownload()) + throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, "triangles is downloading blocks..."); + + typedef map > mapNewBlock_t; + static mapNewBlock_t mapNewBlock; // FIXME: thread safety + static vector vNewBlock; + static CReserveKey reservekey(pwalletMain); + + if (params.size() == 0) + { + // Update block + static unsigned int nTransactionsUpdatedLast; + static CBlockIndex* pindexPrev; + static int64 nStart; + static CBlock* pblock; + if (pindexPrev != pindexBest || + (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 60)) + { + if (pindexPrev != pindexBest) + { + // Deallocate old blocks since they're obsolete now + mapNewBlock.clear(); + BOOST_FOREACH(CBlock* pblock, vNewBlock) + delete pblock; + vNewBlock.clear(); + } + + // Clear pindexPrev so future getworks make a new block, despite any failures from here on + pindexPrev = NULL; + + // Store the pindexBest used before CreateNewBlock, to avoid races + nTransactionsUpdatedLast = nTransactionsUpdated; + CBlockIndex* pindexPrevNew = pindexBest; + nStart = GetTime(); + + // Create new block + pblock = CreateNewBlock(pwalletMain); + if (!pblock) + throw JSONRPCError(RPC_OUT_OF_MEMORY, "Out of memory"); + vNewBlock.push_back(pblock); + + // Need to update only after we know CreateNewBlock succeeded + pindexPrev = pindexPrevNew; + } + + // Update nTime + pblock->UpdateTime(pindexPrev); + pblock->nNonce = 0; + + // Update nExtraNonce + static unsigned int nExtraNonce = 0; + IncrementExtraNonce(pblock, pindexPrev, nExtraNonce); + + // Save + mapNewBlock[pblock->hashMerkleRoot] = make_pair(pblock, pblock->vtx[0].vin[0].scriptSig); + + // Pre-build hash buffers + char pmidstate[32]; + char pdata[128]; + char phash1[64]; + FormatHashBuffers(pblock, pmidstate, pdata, phash1); + + uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256(); + + Object result; + result.push_back(Pair("midstate", HexStr(BEGIN(pmidstate), END(pmidstate)))); // deprecated + result.push_back(Pair("data", HexStr(BEGIN(pdata), END(pdata)))); + result.push_back(Pair("hash1", HexStr(BEGIN(phash1), END(phash1)))); // deprecated + result.push_back(Pair("target", HexStr(BEGIN(hashTarget), END(hashTarget)))); + return result; + } + else + { + // Parse parameters + vector vchData = ParseHex(params[0].get_str()); + if (vchData.size() != 128) + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter"); + CBlock* pdata = (CBlock*)&vchData[0]; + + // Byte reverse + for (int i = 0; i < 128/4; i++) + ((unsigned int*)pdata)[i] = ByteReverse(((unsigned int*)pdata)[i]); + + // Get saved block + if (!mapNewBlock.count(pdata->hashMerkleRoot)) + return false; + CBlock* pblock = mapNewBlock[pdata->hashMerkleRoot].first; + + pblock->nTime = pdata->nTime; + pblock->nNonce = pdata->nNonce; + pblock->vtx[0].vin[0].scriptSig = mapNewBlock[pdata->hashMerkleRoot].second; + pblock->hashMerkleRoot = pblock->BuildMerkleTree(); + + if (!pblock->SignBlock(*pwalletMain)) + throw JSONRPCError(-100, "Unable to sign block, wallet locked?"); + + return CheckWork(pblock, *pwalletMain, reservekey); + } +} + + +Value getblocktemplate(const Array& params, bool fHelp) +{ + if (fHelp || params.size() > 1) + throw runtime_error( + "getblocktemplate [params]\n" + "Returns data needed to construct a block to work on:\n" + " \"version\" : block version\n" + " \"previousblockhash\" : hash of current highest block\n" + " \"transactions\" : contents of non-coinbase transactions that should be included in the next block\n" + " \"coinbaseaux\" : data that should be included in coinbase\n" + " \"coinbasevalue\" : maximum allowable input to coinbase transaction, including the generation award and transaction fees\n" + " \"target\" : hash target\n" + " \"mintime\" : minimum timestamp appropriate for next block\n" + " \"curtime\" : current timestamp\n" + " \"mutable\" : list of ways the block template may be changed\n" + " \"noncerange\" : range of valid nonces\n" + " \"sigoplimit\" : limit of sigops in blocks\n" + " \"sizelimit\" : limit of block size\n" + " \"bits\" : compressed target of next block\n" + " \"height\" : height of the next block\n" + "See https://en.bitcoin.it/wiki/BIP_0022 for full specification."); + + std::string strMode = "template"; + if (params.size() > 0) + { + const Object& oparam = params[0].get_obj(); + const Value& modeval = find_value(oparam, "mode"); + if (modeval.type() == str_type) + strMode = modeval.get_str(); + else if (modeval.type() == null_type) + { + /* Do nothing */ + } + else + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid mode"); + } + + if (strMode != "template") + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid mode"); + + if (vNodes.empty()) + throw JSONRPCError(RPC_CLIENT_NOT_CONNECTED, "triangles is not connected!"); + + if (IsInitialBlockDownload()) + throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, "triangles is downloading blocks..."); + + static CReserveKey reservekey(pwalletMain); + + // Update block + static unsigned int nTransactionsUpdatedLast; + static CBlockIndex* pindexPrev; + static int64 nStart; + static CBlock* pblock; + if (pindexPrev != pindexBest || + (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 5)) + { + // Clear pindexPrev so future calls make a new block, despite any failures from here on + pindexPrev = NULL; + + // Store the pindexBest used before CreateNewBlock, to avoid races + nTransactionsUpdatedLast = nTransactionsUpdated; + CBlockIndex* pindexPrevNew = pindexBest; + nStart = GetTime(); + + // Create new block + if(pblock) + { + delete pblock; + pblock = NULL; + } + pblock = CreateNewBlock(pwalletMain); + if (!pblock) + throw JSONRPCError(RPC_OUT_OF_MEMORY, "Out of memory"); + + // Need to update only after we know CreateNewBlock succeeded + pindexPrev = pindexPrevNew; + } + + // Update nTime + pblock->UpdateTime(pindexPrev); + pblock->nNonce = 0; + + Array transactions; + map setTxIndex; + int i = 0; + CTxDB txdb("r"); + BOOST_FOREACH (CTransaction& tx, pblock->vtx) + { + uint256 txHash = tx.GetHash(); + setTxIndex[txHash] = i++; + + if (tx.IsCoinBase() || tx.IsCoinStake()) + continue; + + Object entry; + + CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION); + ssTx << tx; + entry.push_back(Pair("data", HexStr(ssTx.begin(), ssTx.end()))); + + entry.push_back(Pair("hash", txHash.GetHex())); + + MapPrevTx mapInputs; + map mapUnused; + bool fInvalid = false; + if (tx.FetchInputs(txdb, mapUnused, false, false, mapInputs, fInvalid)) + { + entry.push_back(Pair("fee", (int64_t)(tx.GetValueIn(mapInputs) - tx.GetValueOut()))); + + Array deps; + BOOST_FOREACH (MapPrevTx::value_type& inp, mapInputs) + { + if (setTxIndex.count(inp.first)) + deps.push_back(setTxIndex[inp.first]); + } + entry.push_back(Pair("depends", deps)); + + int64_t nSigOps = tx.GetLegacySigOpCount(); + nSigOps += tx.GetP2SHSigOpCount(mapInputs); + entry.push_back(Pair("sigops", nSigOps)); + } + + transactions.push_back(entry); + } + + Object aux; + aux.push_back(Pair("flags", HexStr(COINBASE_FLAGS.begin(), COINBASE_FLAGS.end()))); + + uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256(); + + static Array aMutable; + if (aMutable.empty()) + { + aMutable.push_back("time"); + aMutable.push_back("transactions"); + aMutable.push_back("prevblock"); + } + + Object result; + result.push_back(Pair("version", pblock->nVersion)); + result.push_back(Pair("previousblockhash", pblock->hashPrevBlock.GetHex())); + result.push_back(Pair("transactions", transactions)); + result.push_back(Pair("coinbaseaux", aux)); + result.push_back(Pair("coinbasevalue", (int64_t)pblock->vtx[0].vout[0].nValue)); + result.push_back(Pair("target", hashTarget.GetHex())); + result.push_back(Pair("mintime", (int64_t)pindexPrev->GetMedianTimePast()+1)); + result.push_back(Pair("mutable", aMutable)); + result.push_back(Pair("noncerange", "00000000ffffffff")); + result.push_back(Pair("sigoplimit", (int64_t)MAX_BLOCK_SIGOPS)); + result.push_back(Pair("sizelimit", (int64_t)MAX_BLOCK_SIZE)); + result.push_back(Pair("curtime", (int64_t)pblock->nTime)); + result.push_back(Pair("bits", HexBits(pblock->nBits))); + result.push_back(Pair("height", (int64_t)(pindexPrev->nHeight+1))); + + return result; +} + +Value submitblock(const Array& params, bool fHelp) +{ + if (fHelp || params.size() < 1 || params.size() > 2) + throw runtime_error( + "submitblock [optional-params-obj]\n" + "[optional-params-obj] parameter is currently ignored.\n" + "Attempts to submit new block to network.\n" + "See https://en.bitcoin.it/wiki/BIP_0022 for full specification."); + + vector blockData(ParseHex(params[0].get_str())); + CDataStream ssBlock(blockData, SER_NETWORK, PROTOCOL_VERSION); + CBlock block; + try { + ssBlock >> block; + } + catch (std::exception &e) { + throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Block decode failed"); + } + + if (!block.SignBlock(*pwalletMain)) + throw JSONRPCError(-100, "Unable to sign block, wallet locked?"); + + bool fAccepted = ProcessBlock(NULL, &block); + if (!fAccepted) + return "rejected"; + + return Value::null; +} + diff --git a/src/rpcnet.cpp b/src/rpcnet.cpp new file mode 100644 index 0000000..3b5ba41 --- /dev/null +++ b/src/rpcnet.cpp @@ -0,0 +1,136 @@ +// Copyright (c) 2009-2012 Bitcoin Developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "net.h" +#include "bitcoinrpc.h" +#include "alert.h" +#include "wallet.h" +#include "db.h" +#include "walletdb.h" + +using namespace json_spirit; +using namespace std; + +Value getconnectioncount(const Array& params, bool fHelp) +{ + if (fHelp || params.size() != 0) + throw runtime_error( + "getconnectioncount\n" + "Returns the number of connections to other nodes."); + + LOCK(cs_vNodes); + return (int)vNodes.size(); +} + +static void CopyNodeStats(std::vector& vstats) +{ + vstats.clear(); + + LOCK(cs_vNodes); + vstats.reserve(vNodes.size()); + BOOST_FOREACH(CNode* pnode, vNodes) { + CNodeStats stats; + pnode->copyStats(stats); + vstats.push_back(stats); + } +} + +Value getpeerinfo(const Array& params, bool fHelp) +{ + if (fHelp || params.size() != 0) + throw runtime_error( + "getpeerinfo\n" + "Returns data about each connected network node."); + + vector vstats; + CopyNodeStats(vstats); + + Array ret; + + BOOST_FOREACH(const CNodeStats& stats, vstats) { + Object obj; + + obj.push_back(Pair("addr", stats.addrName)); + obj.push_back(Pair("services", strprintf("%08"PRI64x, stats.nServices))); + obj.push_back(Pair("lastsend", (boost::int64_t)stats.nLastSend)); + obj.push_back(Pair("lastrecv", (boost::int64_t)stats.nLastRecv)); + obj.push_back(Pair("conntime", (boost::int64_t)stats.nTimeConnected)); + obj.push_back(Pair("version", stats.nVersion)); + obj.push_back(Pair("subver", stats.cleanSubVer)); + obj.push_back(Pair("inbound", stats.fInbound)); + obj.push_back(Pair("releasetime", (boost::int64_t)stats.nReleaseTime)); + obj.push_back(Pair("startingheight", stats.nStartingHeight)); + obj.push_back(Pair("banscore", stats.nMisbehavior)); + + ret.push_back(obj); + } + + return ret; +} + +extern CCriticalSection cs_mapAlerts; +extern map mapAlerts; + +// triangles: send alert. +// There is a known deadlock situation with ThreadMessageHandler +// ThreadMessageHandler: holds cs_vSend and acquiring cs_main in SendMessages() +// ThreadRPCServer: holds cs_main and acquiring cs_vSend in alert.RelayTo()/PushMessage()/BeginMessage() +Value sendalert(const Array& params, bool fHelp) +{ + if (fHelp || params.size() < 6) + throw runtime_error( + "sendalert [cancelupto]\n" + " is the alert text message\n" + " is hex string of alert master private key\n" + " is the minimum applicable internal client version\n" + " is the maximum applicable internal client version\n" + " is integer priority number\n" + " is the alert id\n" + "[cancelupto] cancels all alert id's up to this number\n" + "Returns true or false."); + + CAlert alert; + CKey key; + + alert.strStatusBar = params[0].get_str(); + alert.nMinVer = params[2].get_int(); + alert.nMaxVer = params[3].get_int(); + alert.nPriority = params[4].get_int(); + alert.nID = params[5].get_int(); + if (params.size() > 6) + alert.nCancel = params[6].get_int(); + alert.nVersion = PROTOCOL_VERSION; + alert.nRelayUntil = GetAdjustedTime() + 365*24*60*60; + alert.nExpiration = GetAdjustedTime() + 365*24*60*60; + + CDataStream sMsg(SER_NETWORK, PROTOCOL_VERSION); + sMsg << (CUnsignedAlert)alert; + alert.vchMsg = vector(sMsg.begin(), sMsg.end()); + + vector vchPrivKey = ParseHex(params[1].get_str()); + key.SetPrivKey(CPrivKey(vchPrivKey.begin(), vchPrivKey.end())); // if key is not correct openssl may crash + if (!key.Sign(Hash(alert.vchMsg.begin(), alert.vchMsg.end()), alert.vchSig)) + throw runtime_error( + "Unable to sign alert, check private key?\n"); + if(!alert.ProcessAlert()) + throw runtime_error( + "Failed to process alert.\n"); + // Relay alert + { + LOCK(cs_vNodes); + BOOST_FOREACH(CNode* pnode, vNodes) + alert.RelayTo(pnode); + } + + Object result; + result.push_back(Pair("strStatusBar", alert.strStatusBar)); + result.push_back(Pair("nVersion", alert.nVersion)); + result.push_back(Pair("nMinVer", alert.nMinVer)); + result.push_back(Pair("nMaxVer", alert.nMaxVer)); + result.push_back(Pair("nPriority", alert.nPriority)); + result.push_back(Pair("nID", alert.nID)); + if (alert.nCancel > 0) + result.push_back(Pair("nCancel", alert.nCancel)); + return result; +} diff --git a/src/rpcrawtransaction.cpp b/src/rpcrawtransaction.cpp new file mode 100644 index 0000000..085cf41 --- /dev/null +++ b/src/rpcrawtransaction.cpp @@ -0,0 +1,532 @@ +// Copyright (c) 2010 Satoshi Nakamoto +// Copyright (c) 2009-2012 The Bitcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include + +#include "base58.h" +#include "bitcoinrpc.h" +#include "db.h" +#include "init.h" +#include "main.h" +#include "net.h" +#include "wallet.h" + +using namespace std; +using namespace boost; +using namespace boost::assign; +using namespace json_spirit; + +void ScriptPubKeyToJSON(const CScript& scriptPubKey, Object& out) +{ + txnouttype type; + vector addresses; + int nRequired; + + out.push_back(Pair("asm", scriptPubKey.ToString())); + out.push_back(Pair("hex", HexStr(scriptPubKey.begin(), scriptPubKey.end()))); + + if (!ExtractDestinations(scriptPubKey, type, addresses, nRequired)) + { + out.push_back(Pair("type", GetTxnOutputType(TX_NONSTANDARD))); + return; + } + + out.push_back(Pair("reqSigs", nRequired)); + out.push_back(Pair("type", GetTxnOutputType(type))); + + Array a; + BOOST_FOREACH(const CTxDestination& addr, addresses) + a.push_back(CBitcoinAddress(addr).ToString()); + out.push_back(Pair("addresses", a)); +} + +void TxToJSON(const CTransaction& tx, const uint256 hashBlock, Object& entry) +{ + entry.push_back(Pair("txid", tx.GetHash().GetHex())); + entry.push_back(Pair("version", tx.nVersion)); + entry.push_back(Pair("time", (boost::int64_t)tx.nTime)); + entry.push_back(Pair("locktime", (boost::int64_t)tx.nLockTime)); + Array vin; + BOOST_FOREACH(const CTxIn& txin, tx.vin) + { + Object in; + if (tx.IsCoinBase()) + in.push_back(Pair("coinbase", HexStr(txin.scriptSig.begin(), txin.scriptSig.end()))); + else + { + in.push_back(Pair("txid", txin.prevout.hash.GetHex())); + in.push_back(Pair("vout", (boost::int64_t)txin.prevout.n)); + Object o; + o.push_back(Pair("asm", txin.scriptSig.ToString())); + o.push_back(Pair("hex", HexStr(txin.scriptSig.begin(), txin.scriptSig.end()))); + in.push_back(Pair("scriptSig", o)); + } + in.push_back(Pair("sequence", (boost::int64_t)txin.nSequence)); + vin.push_back(in); + } + entry.push_back(Pair("vin", vin)); + Array vout; + for (unsigned int i = 0; i < tx.vout.size(); i++) + { + const CTxOut& txout = tx.vout[i]; + Object out; + out.push_back(Pair("value", ValueFromAmount(txout.nValue))); + out.push_back(Pair("n", (boost::int64_t)i)); + Object o; + ScriptPubKeyToJSON(txout.scriptPubKey, o); + out.push_back(Pair("scriptPubKey", o)); + vout.push_back(out); + } + entry.push_back(Pair("vout", vout)); + + if (hashBlock != 0) + { + entry.push_back(Pair("blockhash", hashBlock.GetHex())); + map::iterator mi = mapBlockIndex.find(hashBlock); + if (mi != mapBlockIndex.end() && (*mi).second) + { + CBlockIndex* pindex = (*mi).second; + if (pindex->IsInMainChain()) + { + entry.push_back(Pair("confirmations", 1 + nBestHeight - pindex->nHeight)); + entry.push_back(Pair("time", (boost::int64_t)pindex->nTime)); + entry.push_back(Pair("blocktime", (boost::int64_t)pindex->nTime)); + } + else + entry.push_back(Pair("confirmations", 0)); + } + } +} + +Value getrawtransaction(const Array& params, bool fHelp) +{ + if (fHelp || params.size() < 1 || params.size() > 2) + throw runtime_error( + "getrawtransaction [verbose=0]\n" + "If verbose=0, returns a string that is\n" + "serialized, hex-encoded data for .\n" + "If verbose is non-zero, returns an Object\n" + "with information about ."); + + uint256 hash; + hash.SetHex(params[0].get_str()); + + bool fVerbose = false; + if (params.size() > 1) + fVerbose = (params[1].get_int() != 0); + + CTransaction tx; + uint256 hashBlock = 0; + if (!GetTransaction(hash, tx, hashBlock)) + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available about transaction"); + + CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION); + ssTx << tx; + string strHex = HexStr(ssTx.begin(), ssTx.end()); + + if (!fVerbose) + return strHex; + + Object result; + result.push_back(Pair("hex", strHex)); + TxToJSON(tx, hashBlock, result); + return result; +} + +Value listunspent(const Array& params, bool fHelp) +{ + if (fHelp || params.size() > 3) + throw runtime_error( + "listunspent [minconf=1] [maxconf=9999999] [\"address\",...]\n" + "Returns array of unspent transaction outputs\n" + "with between minconf and maxconf (inclusive) confirmations.\n" + "Optionally filtered to only include txouts paid to specified addresses.\n" + "Results are an array of Objects, each of which has:\n" + "{txid, vout, scriptPubKey, amount, confirmations}"); + + RPCTypeCheck(params, list_of(int_type)(int_type)(array_type)); + + int nMinDepth = 1; + if (params.size() > 0) + nMinDepth = params[0].get_int(); + + int nMaxDepth = 9999999; + if (params.size() > 1) + nMaxDepth = params[1].get_int(); + + set setAddress; + if (params.size() > 2) + { + Array inputs = params[2].get_array(); + BOOST_FOREACH(Value& input, inputs) + { + CBitcoinAddress address(input.get_str()); + if (!address.IsValid()) + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid triangles address: ")+input.get_str()); + if (setAddress.count(address)) + throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+input.get_str()); + setAddress.insert(address); + } + } + + Array results; + vector vecOutputs; + pwalletMain->AvailableCoins(vecOutputs, false); + BOOST_FOREACH(const COutput& out, vecOutputs) + { + if (out.nDepth < nMinDepth || out.nDepth > nMaxDepth) + continue; + + if(setAddress.size()) + { + CTxDestination address; + if(!ExtractDestination(out.tx->vout[out.i].scriptPubKey, address)) + continue; + + if (!setAddress.count(address)) + continue; + } + + int64 nValue = out.tx->vout[out.i].nValue; + const CScript& pk = out.tx->vout[out.i].scriptPubKey; + Object entry; + entry.push_back(Pair("txid", out.tx->GetHash().GetHex())); + entry.push_back(Pair("vout", out.i)); + entry.push_back(Pair("scriptPubKey", HexStr(pk.begin(), pk.end()))); + entry.push_back(Pair("amount",ValueFromAmount(nValue))); + entry.push_back(Pair("confirmations",out.nDepth)); + results.push_back(entry); + } + + return results; +} + +Value createrawtransaction(const Array& params, bool fHelp) +{ + if (fHelp || params.size() != 2) + throw runtime_error( + "createrawtransaction [{\"txid\":txid,\"vout\":n},...] {address:amount,...}\n" + "Create a transaction spending given inputs\n" + "(array of objects containing transaction id and output number),\n" + "sending to given address(es).\n" + "Returns hex-encoded raw transaction.\n" + "Note that the transaction's inputs are not signed, and\n" + "it is not stored in the wallet or transmitted to the network."); + + RPCTypeCheck(params, list_of(array_type)(obj_type)); + + Array inputs = params[0].get_array(); + Object sendTo = params[1].get_obj(); + + CTransaction rawTx; + + BOOST_FOREACH(Value& input, inputs) + { + const Object& o = input.get_obj(); + + const Value& txid_v = find_value(o, "txid"); + if (txid_v.type() != str_type) + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, missing txid key"); + string txid = txid_v.get_str(); + if (!IsHex(txid)) + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected hex txid"); + + const Value& vout_v = find_value(o, "vout"); + if (vout_v.type() != int_type) + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, missing vout key"); + int nOutput = vout_v.get_int(); + if (nOutput < 0) + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout must be positive"); + + CTxIn in(COutPoint(uint256(txid), nOutput)); + rawTx.vin.push_back(in); + } + + set setAddress; + BOOST_FOREACH(const Pair& s, sendTo) + { + CBitcoinAddress address(s.name_); + if (!address.IsValid()) + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid triangles address: ")+s.name_); + + if (setAddress.count(address)) + throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+s.name_); + setAddress.insert(address); + + CScript scriptPubKey; + scriptPubKey.SetDestination(address.Get()); + int64 nAmount = AmountFromValue(s.value_); + + CTxOut out(nAmount, scriptPubKey); + rawTx.vout.push_back(out); + } + + CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); + ss << rawTx; + return HexStr(ss.begin(), ss.end()); +} + +Value decoderawtransaction(const Array& params, bool fHelp) +{ + if (fHelp || params.size() != 1) + throw runtime_error( + "decoderawtransaction \n" + "Return a JSON object representing the serialized, hex-encoded transaction."); + + RPCTypeCheck(params, list_of(str_type)); + + vector txData(ParseHex(params[0].get_str())); + CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION); + CTransaction tx; + try { + ssData >> tx; + } + catch (std::exception &e) { + throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed"); + } + + Object result; + TxToJSON(tx, 0, result); + + return result; +} + +Value signrawtransaction(const Array& params, bool fHelp) +{ + if (fHelp || params.size() < 1 || params.size() > 4) + throw runtime_error( + "signrawtransaction [{\"txid\":txid,\"vout\":n,\"scriptPubKey\":hex},...] [,...] [sighashtype=\"ALL\"]\n" + "Sign inputs for raw transaction (serialized, hex-encoded).\n" + "Second optional argument (may be null) is an array of previous transaction outputs that\n" + "this transaction depends on but may not yet be in the blockchain.\n" + "Third optional argument (may be null) is an array of base58-encoded private\n" + "keys that, if given, will be the only keys used to sign the transaction.\n" + "Fourth optional argument is a string that is one of six values; ALL, NONE, SINGLE or\n" + "ALL|ANYONECANPAY, NONE|ANYONECANPAY, SINGLE|ANYONECANPAY.\n" + "Returns json object with keys:\n" + " hex : raw transaction with signature(s) (hex-encoded string)\n" + " complete : 1 if transaction has a complete set of signature (0 if not)" + + HelpRequiringPassphrase()); + + RPCTypeCheck(params, list_of(str_type)(array_type)(array_type)(str_type), true); + + vector txData(ParseHex(params[0].get_str())); + CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION); + vector txVariants; + while (!ssData.empty()) + { + try { + CTransaction tx; + ssData >> tx; + txVariants.push_back(tx); + } + catch (std::exception &e) { + throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed"); + } + } + + if (txVariants.empty()) + throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Missing transaction"); + + // mergedTx will end up with all the signatures; it + // starts as a clone of the rawtx: + CTransaction mergedTx(txVariants[0]); + bool fComplete = true; + + // Fetch previous transactions (inputs): + map mapPrevOut; + for (unsigned int i = 0; i < mergedTx.vin.size(); i++) + { + CTransaction tempTx; + MapPrevTx mapPrevTx; + CTxDB txdb("r"); + map unused; + bool fInvalid; + + // FetchInputs aborts on failure, so we go one at a time. + tempTx.vin.push_back(mergedTx.vin[i]); + tempTx.FetchInputs(txdb, unused, false, false, mapPrevTx, fInvalid); + + // Copy results into mapPrevOut: + BOOST_FOREACH(const CTxIn& txin, tempTx.vin) + { + const uint256& prevHash = txin.prevout.hash; + if (mapPrevTx.count(prevHash) && mapPrevTx[prevHash].second.vout.size()>txin.prevout.n) + mapPrevOut[txin.prevout] = mapPrevTx[prevHash].second.vout[txin.prevout.n].scriptPubKey; + } + } + + // Add previous txouts given in the RPC call: + if (params.size() > 1 && params[1].type() != null_type) + { + Array prevTxs = params[1].get_array(); + BOOST_FOREACH(Value& p, prevTxs) + { + if (p.type() != obj_type) + throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "expected object with {\"txid'\",\"vout\",\"scriptPubKey\"}"); + + Object prevOut = p.get_obj(); + + RPCTypeCheck(prevOut, map_list_of("txid", str_type)("vout", int_type)("scriptPubKey", str_type)); + + string txidHex = find_value(prevOut, "txid").get_str(); + if (!IsHex(txidHex)) + throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "txid must be hexadecimal"); + uint256 txid; + txid.SetHex(txidHex); + + int nOut = find_value(prevOut, "vout").get_int(); + if (nOut < 0) + throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "vout must be positive"); + + string pkHex = find_value(prevOut, "scriptPubKey").get_str(); + if (!IsHex(pkHex)) + throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "scriptPubKey must be hexadecimal"); + vector pkData(ParseHex(pkHex)); + CScript scriptPubKey(pkData.begin(), pkData.end()); + + COutPoint outpoint(txid, nOut); + if (mapPrevOut.count(outpoint)) + { + // Complain if scriptPubKey doesn't match + if (mapPrevOut[outpoint] != scriptPubKey) + { + string err("Previous output scriptPubKey mismatch:\n"); + err = err + mapPrevOut[outpoint].ToString() + "\nvs:\n"+ + scriptPubKey.ToString(); + throw JSONRPCError(RPC_DESERIALIZATION_ERROR, err); + } + } + else + mapPrevOut[outpoint] = scriptPubKey; + } + } + + bool fGivenKeys = false; + CBasicKeyStore tempKeystore; + if (params.size() > 2 && params[2].type() != null_type) + { + fGivenKeys = true; + Array keys = params[2].get_array(); + BOOST_FOREACH(Value k, keys) + { + CBitcoinSecret vchSecret; + bool fGood = vchSecret.SetString(k.get_str()); + if (!fGood) + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY,"Invalid private key"); + CKey key; + bool fCompressed; + CSecret secret = vchSecret.GetSecret(fCompressed); + key.SetSecret(secret, fCompressed); + tempKeystore.AddKey(key); + } + } + else + EnsureWalletIsUnlocked(); + + const CKeyStore& keystore = (fGivenKeys ? tempKeystore : *pwalletMain); + + int nHashType = SIGHASH_ALL; + if (params.size() > 3 && params[3].type() != null_type) + { + static map mapSigHashValues = + boost::assign::map_list_of + (string("ALL"), int(SIGHASH_ALL)) + (string("ALL|ANYONECANPAY"), int(SIGHASH_ALL|SIGHASH_ANYONECANPAY)) + (string("NONE"), int(SIGHASH_NONE)) + (string("NONE|ANYONECANPAY"), int(SIGHASH_NONE|SIGHASH_ANYONECANPAY)) + (string("SINGLE"), int(SIGHASH_SINGLE)) + (string("SINGLE|ANYONECANPAY"), int(SIGHASH_SINGLE|SIGHASH_ANYONECANPAY)) + ; + string strHashType = params[3].get_str(); + if (mapSigHashValues.count(strHashType)) + nHashType = mapSigHashValues[strHashType]; + else + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid sighash param"); + } + + bool fHashSingle = ((nHashType & ~SIGHASH_ANYONECANPAY) == SIGHASH_SINGLE); + + // Sign what we can: + for (unsigned int i = 0; i < mergedTx.vin.size(); i++) + { + CTxIn& txin = mergedTx.vin[i]; + if (mapPrevOut.count(txin.prevout) == 0) + { + fComplete = false; + continue; + } + const CScript& prevPubKey = mapPrevOut[txin.prevout]; + + txin.scriptSig.clear(); + // Only sign SIGHASH_SINGLE if there's a corresponding output: + if (!fHashSingle || (i < mergedTx.vout.size())) + SignSignature(keystore, prevPubKey, mergedTx, i, nHashType); + + // ... and merge in other signatures: + BOOST_FOREACH(const CTransaction& txv, txVariants) + { + txin.scriptSig = CombineSignatures(prevPubKey, mergedTx, i, txin.scriptSig, txv.vin[i].scriptSig); + } + if (!VerifyScript(txin.scriptSig, prevPubKey, mergedTx, i, true, 0)) + fComplete = false; + } + + Object result; + CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION); + ssTx << mergedTx; + result.push_back(Pair("hex", HexStr(ssTx.begin(), ssTx.end()))); + result.push_back(Pair("complete", fComplete)); + + return result; +} + +Value sendrawtransaction(const Array& params, bool fHelp) +{ + if (fHelp || params.size() < 1 || params.size() > 1) + throw runtime_error( + "sendrawtransaction \n" + "Submits raw transaction (serialized, hex-encoded) to local node and network."); + + RPCTypeCheck(params, list_of(str_type)); + + // parse hex string from parameter + vector txData(ParseHex(params[0].get_str())); + CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION); + CTransaction tx; + + // deserialize binary data stream + try { + ssData >> tx; + } + catch (std::exception &e) { + throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed"); + } + uint256 hashTx = tx.GetHash(); + + // See if the transaction is already in a block + // or in the memory pool: + CTransaction existingTx; + uint256 hashBlock = 0; + if (GetTransaction(hashTx, existingTx, hashBlock)) + { + if (hashBlock != 0) + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("transaction already in block ")+hashBlock.GetHex()); + // Not in block, but already in the memory pool; will drop + // through to re-relay it. + } + else + { + // push to local node + CTxDB txdb("r"); + if (!tx.AcceptToMemoryPool(txdb)) + throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX rejected"); + + SyncWithWallets(tx, NULL, true); + } + RelayMessage(CInv(MSG_TX, hashTx), tx); + + return hashTx.GetHex(); +} diff --git a/src/rpcwallet.cpp b/src/rpcwallet.cpp new file mode 100644 index 0000000..f58a05f --- /dev/null +++ b/src/rpcwallet.cpp @@ -0,0 +1,1763 @@ +// Copyright (c) 2010 Satoshi Nakamoto +// Copyright (c) 2009-2012 The Bitcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "wallet.h" +#include "walletdb.h" +#include "bitcoinrpc.h" +#include "init.h" +#include "base58.h" + +using namespace json_spirit; +using namespace std; + +int64 nWalletUnlockTime; +static CCriticalSection cs_nWalletUnlockTime; + +extern void TxToJSON(const CTransaction& tx, const uint256 hashBlock, json_spirit::Object& entry); + +std::string HelpRequiringPassphrase() +{ + return pwalletMain->IsCrypted() + ? "\nrequires wallet passphrase to be set with walletpassphrase first" + : ""; +} + +void EnsureWalletIsUnlocked() +{ + if (pwalletMain->IsLocked()) + throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first."); + if (fWalletUnlockMintOnly) + throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Wallet unlocked for block minting only."); +} + +void WalletTxToJSON(const CWalletTx& wtx, Object& entry) +{ + int confirms = wtx.GetDepthInMainChain(); + entry.push_back(Pair("confirmations", confirms)); + if (wtx.IsCoinBase() || wtx.IsCoinStake()) + entry.push_back(Pair("generated", true)); + if (confirms) + { + entry.push_back(Pair("blockhash", wtx.hashBlock.GetHex())); + entry.push_back(Pair("blockindex", wtx.nIndex)); + entry.push_back(Pair("blocktime", (boost::int64_t)(mapBlockIndex[wtx.hashBlock]->nTime))); + } + entry.push_back(Pair("txid", wtx.GetHash().GetHex())); + entry.push_back(Pair("time", (boost::int64_t)wtx.GetTxTime())); + entry.push_back(Pair("timereceived", (boost::int64_t)wtx.nTimeReceived)); + BOOST_FOREACH(const PAIRTYPE(string,string)& item, wtx.mapValue) + entry.push_back(Pair(item.first, item.second)); +} + +string AccountFromValue(const Value& value) +{ + string strAccount = value.get_str(); + if (strAccount == "*") + throw JSONRPCError(RPC_WALLET_INVALID_ACCOUNT_NAME, "Invalid account name"); + return strAccount; +} + +Value getinfo(const Array& params, bool fHelp) +{ + if (fHelp || params.size() != 0) + throw runtime_error( + "getinfo\n" + "Returns an object containing various state info."); + + proxyType proxy; + GetProxy(NET_IPV4, proxy); + + Object obj; + obj.push_back(Pair("version", FormatFullVersion())); + obj.push_back(Pair("protocolversion",(int)PROTOCOL_VERSION)); + obj.push_back(Pair("walletversion", pwalletMain->GetVersion())); + obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance()))); + obj.push_back(Pair("newmint", ValueFromAmount(pwalletMain->GetNewMint()))); + obj.push_back(Pair("stake", ValueFromAmount(pwalletMain->GetStake()))); + obj.push_back(Pair("blocks", (int)nBestHeight)); + obj.push_back(Pair("moneysupply", ValueFromAmount(pindexBest->nMoneySupply))); + obj.push_back(Pair("connections", (int)vNodes.size())); + obj.push_back(Pair("proxy", (proxy.first.IsValid() ? proxy.first.ToStringIPPort() : string()))); + obj.push_back(Pair("ip", addrSeenByPeer.ToStringIP())); + obj.push_back(Pair("difficulty", (double)GetDifficulty())); + obj.push_back(Pair("testnet", fTestNet)); + obj.push_back(Pair("keypoololdest", (boost::int64_t)pwalletMain->GetOldestKeyPoolTime())); + obj.push_back(Pair("keypoolsize", pwalletMain->GetKeyPoolSize())); + obj.push_back(Pair("paytxfee", ValueFromAmount(nTransactionFee))); + if (pwalletMain->IsCrypted()) + obj.push_back(Pair("unlocked_until", (boost::int64_t)nWalletUnlockTime / 1000)); + obj.push_back(Pair("errors", GetWarnings("statusbar"))); + return obj; +} + + +Value getnewpubkey(const Array& params, bool fHelp) +{ + if (fHelp || params.size() > 1) + throw runtime_error( + "getnewpubkey [account]\n" + "Returns new public key for coinbase generation."); + + // Parse the account first so we don't generate a key if there's an error + string strAccount; + if (params.size() > 0) + strAccount = AccountFromValue(params[0]); + + if (!pwalletMain->IsLocked()) + pwalletMain->TopUpKeyPool(); + + // Generate a new key that is added to wallet + CPubKey newKey; + if (!pwalletMain->GetKeyFromPool(newKey, false)) + throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first"); + CKeyID keyID = newKey.GetID(); + + pwalletMain->SetAddressBookName(keyID, strAccount); + vector vchPubKey = newKey.Raw(); + + return HexStr(vchPubKey.begin(), vchPubKey.end()); +} + + +Value getnewaddress(const Array& params, bool fHelp) +{ + if (fHelp || params.size() > 1) + throw runtime_error( + "getnewaddress [account]\n" + "Returns a new triangles address for receiving payments. " + "If [account] is specified (recommended), it is added to the address book " + "so payments received with the address will be credited to [account]."); + + // Parse the account first so we don't generate a key if there's an error + string strAccount; + if (params.size() > 0) + strAccount = AccountFromValue(params[0]); + + if (!pwalletMain->IsLocked()) + pwalletMain->TopUpKeyPool(); + + // Generate a new key that is added to wallet + CPubKey newKey; + if (!pwalletMain->GetKeyFromPool(newKey, false)) + throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first"); + CKeyID keyID = newKey.GetID(); + + pwalletMain->SetAddressBookName(keyID, strAccount); + + return CBitcoinAddress(keyID).ToString(); +} + + +CBitcoinAddress GetAccountAddress(string strAccount, bool bForceNew=false) +{ + CWalletDB walletdb(pwalletMain->strWalletFile); + + CAccount account; + walletdb.ReadAccount(strAccount, account); + + bool bKeyUsed = false; + + // Check if the current key has been used + if (account.vchPubKey.IsValid()) + { + CScript scriptPubKey; + scriptPubKey.SetDestination(account.vchPubKey.GetID()); + for (map::iterator it = pwalletMain->mapWallet.begin(); + it != pwalletMain->mapWallet.end() && account.vchPubKey.IsValid(); + ++it) + { + const CWalletTx& wtx = (*it).second; + BOOST_FOREACH(const CTxOut& txout, wtx.vout) + if (txout.scriptPubKey == scriptPubKey) + bKeyUsed = true; + } + } + + // Generate a new key + if (!account.vchPubKey.IsValid() || bForceNew || bKeyUsed) + { + if (!pwalletMain->GetKeyFromPool(account.vchPubKey, false)) + throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first"); + + pwalletMain->SetAddressBookName(account.vchPubKey.GetID(), strAccount); + walletdb.WriteAccount(strAccount, account); + } + + return CBitcoinAddress(account.vchPubKey.GetID()); +} + +Value getaccountaddress(const Array& params, bool fHelp) +{ + if (fHelp || params.size() != 1) + throw runtime_error( + "getaccountaddress \n" + "Returns the current triangles address for receiving payments to this account."); + + // Parse the account first so we don't generate a key if there's an error + string strAccount = AccountFromValue(params[0]); + + Value ret; + + ret = GetAccountAddress(strAccount).ToString(); + + return ret; +} + + + +Value setaccount(const Array& params, bool fHelp) +{ + if (fHelp || params.size() < 1 || params.size() > 2) + throw runtime_error( + "setaccount \n" + "Sets the account associated with the given address."); + + CBitcoinAddress address(params[0].get_str()); + if (!address.IsValid()) + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid triangles address"); + + + string strAccount; + if (params.size() > 1) + strAccount = AccountFromValue(params[1]); + + // Detect when changing the account of an address that is the 'unused current key' of another account: + if (pwalletMain->mapAddressBook.count(address.Get())) + { + string strOldAccount = pwalletMain->mapAddressBook[address.Get()]; + if (address == GetAccountAddress(strOldAccount)) + GetAccountAddress(strOldAccount, true); + } + + pwalletMain->SetAddressBookName(address.Get(), strAccount); + + return Value::null; +} + + +Value getaccount(const Array& params, bool fHelp) +{ + if (fHelp || params.size() != 1) + throw runtime_error( + "getaccount \n" + "Returns the account associated with the given address."); + + CBitcoinAddress address(params[0].get_str()); + if (!address.IsValid()) + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid triangles address"); + + string strAccount; + map::iterator mi = pwalletMain->mapAddressBook.find(address.Get()); + if (mi != pwalletMain->mapAddressBook.end() && !(*mi).second.empty()) + strAccount = (*mi).second; + return strAccount; +} + + +Value getaddressesbyaccount(const Array& params, bool fHelp) +{ + if (fHelp || params.size() != 1) + throw runtime_error( + "getaddressesbyaccount \n" + "Returns the list of addresses for the given account."); + + string strAccount = AccountFromValue(params[0]); + + // Find all addresses that have the given account + Array ret; + BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook) + { + const CBitcoinAddress& address = item.first; + const string& strName = item.second; + if (strName == strAccount) + ret.push_back(address.ToString()); + } + return ret; +} + +Value sendtoaddress(const Array& params, bool fHelp) +{ + if (fHelp || params.size() < 2 || params.size() > 4) + throw runtime_error( + "sendtoaddress [comment] [comment-to]\n" + " is a real and is rounded to the nearest 0.000001" + + HelpRequiringPassphrase()); + + CBitcoinAddress address(params[0].get_str()); + if (!address.IsValid()) + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid triangles address"); + + // Amount + int64 nAmount = AmountFromValue(params[1]); + + if (nAmount < MIN_TXOUT_AMOUNT) + throw JSONRPCError(-101, "Send amount too small"); + + // Wallet comments + CWalletTx wtx; + if (params.size() > 2 && params[2].type() != null_type && !params[2].get_str().empty()) + wtx.mapValue["comment"] = params[2].get_str(); + if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty()) + wtx.mapValue["to"] = params[3].get_str(); + + if (pwalletMain->IsLocked()) + throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first."); + + string strError = pwalletMain->SendMoneyToDestination(address.Get(), nAmount, wtx); + if (strError != "") + throw JSONRPCError(RPC_WALLET_ERROR, strError); + + return wtx.GetHash().GetHex(); +} + +Value listaddressgroupings(const Array& params, bool fHelp) +{ + if (fHelp) + throw runtime_error( + "listaddressgroupings\n" + "Lists groups of addresses which have had their common ownership\n" + "made public by common use as inputs or as the resulting change\n" + "in past transactions"); + + Array jsonGroupings; + map balances = pwalletMain->GetAddressBalances(); + BOOST_FOREACH(set grouping, pwalletMain->GetAddressGroupings()) + { + Array jsonGrouping; + BOOST_FOREACH(CTxDestination address, grouping) + { + Array addressInfo; + addressInfo.push_back(CBitcoinAddress(address).ToString()); + addressInfo.push_back(ValueFromAmount(balances[address])); + { + LOCK(pwalletMain->cs_wallet); + if (pwalletMain->mapAddressBook.find(CBitcoinAddress(address).Get()) != pwalletMain->mapAddressBook.end()) + addressInfo.push_back(pwalletMain->mapAddressBook.find(CBitcoinAddress(address).Get())->second); + } + jsonGrouping.push_back(addressInfo); + } + jsonGroupings.push_back(jsonGrouping); + } + return jsonGroupings; +} + +Value signmessage(const Array& params, bool fHelp) +{ + if (fHelp || params.size() != 2) + throw runtime_error( + "signmessage \n" + "Sign a message with the private key of an address"); + + EnsureWalletIsUnlocked(); + + string strAddress = params[0].get_str(); + string strMessage = params[1].get_str(); + + CBitcoinAddress addr(strAddress); + if (!addr.IsValid()) + throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address"); + + CKeyID keyID; + if (!addr.GetKeyID(keyID)) + throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key"); + + CKey key; + if (!pwalletMain->GetKey(keyID, key)) + throw JSONRPCError(RPC_WALLET_ERROR, "Private key not available"); + + CDataStream ss(SER_GETHASH, 0); + ss << strMessageMagic; + ss << strMessage; + + vector vchSig; + if (!key.SignCompact(Hash(ss.begin(), ss.end()), vchSig)) + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Sign failed"); + + return EncodeBase64(&vchSig[0], vchSig.size()); +} + +Value verifymessage(const Array& params, bool fHelp) +{ + if (fHelp || params.size() != 3) + throw runtime_error( + "verifymessage \n" + "Verify a signed message"); + + string strAddress = params[0].get_str(); + string strSign = params[1].get_str(); + string strMessage = params[2].get_str(); + + CBitcoinAddress addr(strAddress); + if (!addr.IsValid()) + throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address"); + + CKeyID keyID; + if (!addr.GetKeyID(keyID)) + throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key"); + + bool fInvalid = false; + vector vchSig = DecodeBase64(strSign.c_str(), &fInvalid); + + if (fInvalid) + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Malformed base64 encoding"); + + CDataStream ss(SER_GETHASH, 0); + ss << strMessageMagic; + ss << strMessage; + + CKey key; + if (!key.SetCompactSignature(Hash(ss.begin(), ss.end()), vchSig)) + return false; + + return (key.GetPubKey().GetID() == keyID); +} + + +Value getreceivedbyaddress(const Array& params, bool fHelp) +{ + if (fHelp || params.size() < 1 || params.size() > 2) + throw runtime_error( + "getreceivedbyaddress [minconf=1]\n" + "Returns the total amount received by in transactions with at least [minconf] confirmations."); + + // Bitcoin address + CBitcoinAddress address = CBitcoinAddress(params[0].get_str()); + CScript scriptPubKey; + if (!address.IsValid()) + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid triangles address"); + scriptPubKey.SetDestination(address.Get()); + if (!IsMine(*pwalletMain,scriptPubKey)) + return (double)0.0; + + // Minimum confirmations + int nMinDepth = 1; + if (params.size() > 1) + nMinDepth = params[1].get_int(); + + // Tally + int64 nAmount = 0; + for (map::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) + { + const CWalletTx& wtx = (*it).second; + if (wtx.IsCoinBase() || wtx.IsCoinStake() || !wtx.IsFinal()) + continue; + + BOOST_FOREACH(const CTxOut& txout, wtx.vout) + if (txout.scriptPubKey == scriptPubKey) + if (wtx.GetDepthInMainChain() >= nMinDepth) + nAmount += txout.nValue; + } + + return ValueFromAmount(nAmount); +} + + +void GetAccountAddresses(string strAccount, set& setAddress) +{ + BOOST_FOREACH(const PAIRTYPE(CTxDestination, string)& item, pwalletMain->mapAddressBook) + { + const CTxDestination& address = item.first; + const string& strName = item.second; + if (strName == strAccount) + setAddress.insert(address); + } +} + +Value getreceivedbyaccount(const Array& params, bool fHelp) +{ + if (fHelp || params.size() < 1 || params.size() > 2) + throw runtime_error( + "getreceivedbyaccount [minconf=1]\n" + "Returns the total amount received by addresses with in transactions with at least [minconf] confirmations."); + + // Minimum confirmations + int nMinDepth = 1; + if (params.size() > 1) + nMinDepth = params[1].get_int(); + + // Get the set of pub keys assigned to account + string strAccount = AccountFromValue(params[0]); + set setAddress; + GetAccountAddresses(strAccount, setAddress); + + // Tally + int64 nAmount = 0; + for (map::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) + { + const CWalletTx& wtx = (*it).second; + if (wtx.IsCoinBase() || wtx.IsCoinStake() || !wtx.IsFinal()) + continue; + + BOOST_FOREACH(const CTxOut& txout, wtx.vout) + { + CTxDestination address; + if (ExtractDestination(txout.scriptPubKey, address) && IsMine(*pwalletMain, address) && setAddress.count(address)) + if (wtx.GetDepthInMainChain() >= nMinDepth) + nAmount += txout.nValue; + } + } + + return (double)nAmount / (double)COIN; +} + + +int64 GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth) +{ + int64 nBalance = 0; + + // Tally wallet transactions + for (map::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) + { + const CWalletTx& wtx = (*it).second; + if (!wtx.IsFinal()) + continue; + + int64 nGeneratedImmature, nGeneratedMature, nReceived, nSent, nFee; + wtx.GetAccountAmounts(strAccount, nGeneratedImmature, nGeneratedMature, nReceived, nSent, nFee); + + if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth) + nBalance += nReceived; + + if((wtx.IsCoinBaseOrStake() && wtx.GetDepthInMainChain() >= nMinDepth && wtx.GetBlocksToMaturity() == 0) + || !wtx.IsCoinBaseOrStake()) + { + nBalance += nGeneratedMature - nSent - nFee; + } + } + + // Tally internal accounting entries + nBalance += walletdb.GetAccountCreditDebit(strAccount); + + return nBalance; +} + +int64 GetAccountBalance(const string& strAccount, int nMinDepth) +{ + CWalletDB walletdb(pwalletMain->strWalletFile); + return GetAccountBalance(walletdb, strAccount, nMinDepth); +} + + +Value getbalance(const Array& params, bool fHelp) +{ + if (fHelp || params.size() > 2) + throw runtime_error( + "getbalance [account] [minconf=1]\n" + "If [account] is not specified, returns the server's total available balance.\n" + "If [account] is specified, returns the balance in the account."); + + if (params.size() == 0) + return ValueFromAmount(pwalletMain->GetBalance()); + + int nMinDepth = 1; + if (params.size() > 1) + nMinDepth = params[1].get_int(); + + if (params[0].get_str() == "*") { + // Calculate total balance a different way from GetBalance() + // (GetBalance() sums up all unspent TxOuts) + // getbalance and getbalance '*' should always return the same number. + int64 nBalance = 0; + for (map::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) + { + const CWalletTx& wtx = (*it).second; + if (!wtx.IsFinal()) + continue; + + int64 allGeneratedImmature, allGeneratedMature, allFee; + allGeneratedImmature = allGeneratedMature = allFee = 0; + + string strSentAccount; + list > listReceived; + list > listSent; + wtx.GetAmounts(allGeneratedImmature, allGeneratedMature, listReceived, listSent, allFee, strSentAccount); + if (wtx.GetDepthInMainChain() >= nMinDepth) + { + BOOST_FOREACH(const PAIRTYPE(CTxDestination,int64)& r, listReceived) + nBalance += r.second; + } + + if((wtx.IsCoinBaseOrStake() && wtx.GetDepthInMainChain() >= nMinDepth && wtx.GetBlocksToMaturity() == 0) + || !wtx.IsCoinBaseOrStake()) + { + BOOST_FOREACH(const PAIRTYPE(CTxDestination,int64)& r, listSent) + nBalance -= r.second; + nBalance -= allFee; + nBalance += allGeneratedMature; + } + } + return ValueFromAmount(nBalance); + } + + string strAccount = AccountFromValue(params[0]); + + int64 nBalance = GetAccountBalance(strAccount, nMinDepth); + + return ValueFromAmount(nBalance); +} + + +Value movecmd(const Array& params, bool fHelp) +{ + if (fHelp || params.size() < 3 || params.size() > 5) + throw runtime_error( + "move [minconf=1] [comment]\n" + "Move from one account in your wallet to another."); + + string strFrom = AccountFromValue(params[0]); + string strTo = AccountFromValue(params[1]); + int64 nAmount = AmountFromValue(params[2]); + + if (nAmount < MIN_TXOUT_AMOUNT) + throw JSONRPCError(-101, "Send amount too small"); + + if (params.size() > 3) + // unused parameter, used to be nMinDepth, keep type-checking it though + (void)params[3].get_int(); + string strComment; + if (params.size() > 4) + strComment = params[4].get_str(); + + CWalletDB walletdb(pwalletMain->strWalletFile); + if (!walletdb.TxnBegin()) + throw JSONRPCError(RPC_DATABASE_ERROR, "database error"); + + int64 nNow = GetAdjustedTime(); + + // Debit + CAccountingEntry debit; + debit.nOrderPos = pwalletMain->IncOrderPosNext(&walletdb); + debit.strAccount = strFrom; + debit.nCreditDebit = -nAmount; + debit.nTime = nNow; + debit.strOtherAccount = strTo; + debit.strComment = strComment; + walletdb.WriteAccountingEntry(debit); + + // Credit + CAccountingEntry credit; + credit.nOrderPos = pwalletMain->IncOrderPosNext(&walletdb); + credit.strAccount = strTo; + credit.nCreditDebit = nAmount; + credit.nTime = nNow; + credit.strOtherAccount = strFrom; + credit.strComment = strComment; + walletdb.WriteAccountingEntry(credit); + + if (!walletdb.TxnCommit()) + throw JSONRPCError(RPC_DATABASE_ERROR, "database error"); + + return true; +} + + +Value sendfrom(const Array& params, bool fHelp) +{ + if (fHelp || params.size() < 3 || params.size() > 6) + throw runtime_error( + "sendfrom [minconf=1] [comment] [comment-to]\n" + " is a real and is rounded to the nearest 0.000001" + + HelpRequiringPassphrase()); + + string strAccount = AccountFromValue(params[0]); + CBitcoinAddress address(params[1].get_str()); + if (!address.IsValid()) + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid triangles address"); + int64 nAmount = AmountFromValue(params[2]); + + if (nAmount < MIN_TXOUT_AMOUNT) + throw JSONRPCError(-101, "Send amount too small"); + + int nMinDepth = 1; + if (params.size() > 3) + nMinDepth = params[3].get_int(); + + CWalletTx wtx; + wtx.strFromAccount = strAccount; + if (params.size() > 4 && params[4].type() != null_type && !params[4].get_str().empty()) + wtx.mapValue["comment"] = params[4].get_str(); + if (params.size() > 5 && params[5].type() != null_type && !params[5].get_str().empty()) + wtx.mapValue["to"] = params[5].get_str(); + + EnsureWalletIsUnlocked(); + + // Check funds + int64 nBalance = GetAccountBalance(strAccount, nMinDepth); + if (nAmount > nBalance) + throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds"); + + // Send + string strError = pwalletMain->SendMoneyToDestination(address.Get(), nAmount, wtx); + if (strError != "") + throw JSONRPCError(RPC_WALLET_ERROR, strError); + + return wtx.GetHash().GetHex(); +} + + +Value sendmany(const Array& params, bool fHelp) +{ + if (fHelp || params.size() < 2 || params.size() > 4) + throw runtime_error( + "sendmany {address:amount,...} [minconf=1] [comment]\n" + "amounts are double-precision floating point numbers" + + HelpRequiringPassphrase()); + + string strAccount = AccountFromValue(params[0]); + Object sendTo = params[1].get_obj(); + int nMinDepth = 1; + if (params.size() > 2) + nMinDepth = params[2].get_int(); + + CWalletTx wtx; + + wtx.strFromAccount = strAccount; + if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty()) + wtx.mapValue["comment"] = params[3].get_str(); + + set setAddress; + vector > vecSend; + + int64 totalAmount = 0; + BOOST_FOREACH(const Pair& s, sendTo) + { + CBitcoinAddress address(s.name_); + if (!address.IsValid()) + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid triangles address: ")+s.name_); + + if (setAddress.count(address)) + throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+s.name_); + setAddress.insert(address); + + CScript scriptPubKey; + scriptPubKey.SetDestination(address.Get()); + int64 nAmount = AmountFromValue(s.value_); + + if (nAmount < MIN_TXOUT_AMOUNT) + throw JSONRPCError(-101, "Send amount too small"); + + totalAmount += nAmount; + + vecSend.push_back(make_pair(scriptPubKey, nAmount)); + } + + EnsureWalletIsUnlocked(); + + // Check funds + int64 nBalance = GetAccountBalance(strAccount, nMinDepth); + if (totalAmount > nBalance) + throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds"); + + // Send + CReserveKey keyChange(pwalletMain); + int64 nFeeRequired = 0; + bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired); + if (!fCreated) + { + if (totalAmount + nFeeRequired > pwalletMain->GetBalance()) + throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Insufficient funds"); + throw JSONRPCError(RPC_WALLET_ERROR, "Transaction creation failed"); + } + if (!pwalletMain->CommitTransaction(wtx, keyChange)) + throw JSONRPCError(RPC_WALLET_ERROR, "Transaction commit failed"); + + return wtx.GetHash().GetHex(); +} + +Value addmultisigaddress(const Array& params, bool fHelp) +{ + if (fHelp || params.size() < 2 || params.size() > 3) + { + string msg = "addmultisigaddress <'[\"key\",\"key\"]'> [account]\n" + "Add a nrequired-to-sign multisignature address to the wallet\"\n" + "each key is a triangles address or hex-encoded public key\n" + "If [account] is specified, assign address to [account]."; + throw runtime_error(msg); + } + + int nRequired = params[0].get_int(); + const Array& keys = params[1].get_array(); + string strAccount; + if (params.size() > 2) + strAccount = AccountFromValue(params[2]); + + // Gather public keys + if (nRequired < 1) + throw runtime_error("a multisignature address must require at least one key to redeem"); + if ((int)keys.size() < nRequired) + throw runtime_error( + strprintf("not enough keys supplied " + "(got %"PRIszu" keys, but need at least %d to redeem)", keys.size(), nRequired)); + std::vector pubkeys; + pubkeys.resize(keys.size()); + for (unsigned int i = 0; i < keys.size(); i++) + { + const std::string& ks = keys[i].get_str(); + + // Case 1: Bitcoin address and we have full public key: + CBitcoinAddress address(ks); + if (address.IsValid()) + { + CKeyID keyID; + if (!address.GetKeyID(keyID)) + throw runtime_error( + strprintf("%s does not refer to a key",ks.c_str())); + CPubKey vchPubKey; + if (!pwalletMain->GetPubKey(keyID, vchPubKey)) + throw runtime_error( + strprintf("no full public key for address %s",ks.c_str())); + if (!vchPubKey.IsValid() || !pubkeys[i].SetPubKey(vchPubKey)) + throw runtime_error(" Invalid public key: "+ks); + } + + // Case 2: hex public key + else if (IsHex(ks)) + { + CPubKey vchPubKey(ParseHex(ks)); + if (!vchPubKey.IsValid() || !pubkeys[i].SetPubKey(vchPubKey)) + throw runtime_error(" Invalid public key: "+ks); + } + else + { + throw runtime_error(" Invalid public key: "+ks); + } + } + + // Construct using pay-to-script-hash: + CScript inner; + inner.SetMultisig(nRequired, pubkeys); + CScriptID innerID = inner.GetID(); + pwalletMain->AddCScript(inner); + + pwalletMain->SetAddressBookName(innerID, strAccount); + return CBitcoinAddress(innerID).ToString(); +} + + +struct tallyitem +{ + int64 nAmount; + int nConf; + tallyitem() + { + nAmount = 0; + nConf = std::numeric_limits::max(); + } +}; + +Value ListReceived(const Array& params, bool fByAccounts) +{ + // Minimum confirmations + int nMinDepth = 1; + if (params.size() > 0) + nMinDepth = params[0].get_int(); + + // Whether to include empty accounts + bool fIncludeEmpty = false; + if (params.size() > 1) + fIncludeEmpty = params[1].get_bool(); + + // Tally + map mapTally; + for (map::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) + { + const CWalletTx& wtx = (*it).second; + + if (wtx.IsCoinBase() || wtx.IsCoinStake() || !wtx.IsFinal()) + continue; + + int nDepth = wtx.GetDepthInMainChain(); + if (nDepth < nMinDepth) + continue; + + BOOST_FOREACH(const CTxOut& txout, wtx.vout) + { + CTxDestination address; + if (!ExtractDestination(txout.scriptPubKey, address) || !IsMine(*pwalletMain, address)) + continue; + + tallyitem& item = mapTally[address]; + item.nAmount += txout.nValue; + item.nConf = min(item.nConf, nDepth); + } + } + + // Reply + Array ret; + map mapAccountTally; + BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook) + { + const CBitcoinAddress& address = item.first; + const string& strAccount = item.second; + map::iterator it = mapTally.find(address); + if (it == mapTally.end() && !fIncludeEmpty) + continue; + + int64 nAmount = 0; + int nConf = std::numeric_limits::max(); + if (it != mapTally.end()) + { + nAmount = (*it).second.nAmount; + nConf = (*it).second.nConf; + } + + if (fByAccounts) + { + tallyitem& item = mapAccountTally[strAccount]; + item.nAmount += nAmount; + item.nConf = min(item.nConf, nConf); + } + else + { + Object obj; + obj.push_back(Pair("address", address.ToString())); + obj.push_back(Pair("account", strAccount)); + obj.push_back(Pair("amount", ValueFromAmount(nAmount))); + obj.push_back(Pair("confirmations", (nConf == std::numeric_limits::max() ? 0 : nConf))); + ret.push_back(obj); + } + } + + if (fByAccounts) + { + for (map::iterator it = mapAccountTally.begin(); it != mapAccountTally.end(); ++it) + { + int64 nAmount = (*it).second.nAmount; + int nConf = (*it).second.nConf; + Object obj; + obj.push_back(Pair("account", (*it).first)); + obj.push_back(Pair("amount", ValueFromAmount(nAmount))); + obj.push_back(Pair("confirmations", (nConf == std::numeric_limits::max() ? 0 : nConf))); + ret.push_back(obj); + } + } + + return ret; +} + +Value listreceivedbyaddress(const Array& params, bool fHelp) +{ + if (fHelp || params.size() > 2) + throw runtime_error( + "listreceivedbyaddress [minconf=1] [includeempty=false]\n" + "[minconf] is the minimum number of confirmations before payments are included.\n" + "[includeempty] whether to include addresses that haven't received any payments.\n" + "Returns an array of objects containing:\n" + " \"address\" : receiving address\n" + " \"account\" : the account of the receiving address\n" + " \"amount\" : total amount received by the address\n" + " \"confirmations\" : number of confirmations of the most recent transaction included"); + + return ListReceived(params, false); +} + +Value listreceivedbyaccount(const Array& params, bool fHelp) +{ + if (fHelp || params.size() > 2) + throw runtime_error( + "listreceivedbyaccount [minconf=1] [includeempty=false]\n" + "[minconf] is the minimum number of confirmations before payments are included.\n" + "[includeempty] whether to include accounts that haven't received any payments.\n" + "Returns an array of objects containing:\n" + " \"account\" : the account of the receiving addresses\n" + " \"amount\" : total amount received by addresses with this account\n" + " \"confirmations\" : number of confirmations of the most recent transaction included"); + + return ListReceived(params, true); +} + +void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, Array& ret) +{ + int64 nGeneratedImmature, nGeneratedMature, nFee; + string strSentAccount; + list > listReceived; + list > listSent; + + wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount); + + bool fAllAccounts = (strAccount == string("*")); + + // Generated blocks assigned to account "" + if ((nGeneratedMature+nGeneratedImmature) != 0 && (fAllAccounts || strAccount == "")) + { + Object entry; + entry.push_back(Pair("account", string(""))); + if (nGeneratedImmature) + { + entry.push_back(Pair("category", wtx.GetDepthInMainChain() ? "immature" : "orphan")); + entry.push_back(Pair("amount", ValueFromAmount(nGeneratedImmature))); + } + else + { + entry.push_back(Pair("category", "generate")); + entry.push_back(Pair("amount", ValueFromAmount(nGeneratedMature))); + } + if (fLong) + WalletTxToJSON(wtx, entry); + ret.push_back(entry); + } + + // Sent + if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount)) + { + BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64)& s, listSent) + { + Object entry; + entry.push_back(Pair("account", strSentAccount)); + entry.push_back(Pair("address", CBitcoinAddress(s.first).ToString())); + entry.push_back(Pair("category", "send")); + entry.push_back(Pair("amount", ValueFromAmount(-s.second))); + entry.push_back(Pair("fee", ValueFromAmount(-nFee))); + if (fLong) + WalletTxToJSON(wtx, entry); + ret.push_back(entry); + } + } + + // Received + if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth) + { + BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64)& r, listReceived) + { + string account; + if (pwalletMain->mapAddressBook.count(r.first)) + account = pwalletMain->mapAddressBook[r.first]; + if (fAllAccounts || (account == strAccount)) + { + Object entry; + entry.push_back(Pair("account", account)); + entry.push_back(Pair("address", CBitcoinAddress(r.first).ToString())); + if (wtx.IsCoinBase()) + { + if (wtx.GetDepthInMainChain() < 1) + entry.push_back(Pair("category", "orphan")); + else if (wtx.GetBlocksToMaturity() > 0) + entry.push_back(Pair("category", "immature")); + else + entry.push_back(Pair("category", "generate")); + } + else + entry.push_back(Pair("category", "receive")); + entry.push_back(Pair("amount", ValueFromAmount(r.second))); + if (fLong) + WalletTxToJSON(wtx, entry); + ret.push_back(entry); + } + } + } +} + +void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Array& ret) +{ + bool fAllAccounts = (strAccount == string("*")); + + if (fAllAccounts || acentry.strAccount == strAccount) + { + Object entry; + entry.push_back(Pair("account", acentry.strAccount)); + entry.push_back(Pair("category", "move")); + entry.push_back(Pair("time", (boost::int64_t)acentry.nTime)); + entry.push_back(Pair("amount", ValueFromAmount(acentry.nCreditDebit))); + entry.push_back(Pair("otheraccount", acentry.strOtherAccount)); + entry.push_back(Pair("comment", acentry.strComment)); + ret.push_back(entry); + } +} + +Value listtransactions(const Array& params, bool fHelp) +{ + if (fHelp || params.size() > 3) + throw runtime_error( + "listtransactions [account] [count=10] [from=0]\n" + "Returns up to [count] most recent transactions skipping the first [from] transactions for account [account]."); + + string strAccount = "*"; + if (params.size() > 0) + strAccount = params[0].get_str(); + int nCount = 10; + if (params.size() > 1) + nCount = params[1].get_int(); + int nFrom = 0; + if (params.size() > 2) + nFrom = params[2].get_int(); + + if (nCount < 0) + throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative count"); + if (nFrom < 0) + throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative from"); + + Array ret; + + std::list acentries; + CWallet::TxItems txOrdered = pwalletMain->OrderedTxItems(acentries, strAccount); + + // iterate backwards until we have nCount items to return: + for (CWallet::TxItems::reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it) + { + CWalletTx *const pwtx = (*it).second.first; + if (pwtx != 0) + ListTransactions(*pwtx, strAccount, 0, true, ret); + CAccountingEntry *const pacentry = (*it).second.second; + if (pacentry != 0) + AcentryToJSON(*pacentry, strAccount, ret); + + if ((int)ret.size() >= (nCount+nFrom)) break; + } + // ret is newest to oldest + + if (nFrom > (int)ret.size()) + nFrom = ret.size(); + if ((nFrom + nCount) > (int)ret.size()) + nCount = ret.size() - nFrom; + Array::iterator first = ret.begin(); + std::advance(first, nFrom); + Array::iterator last = ret.begin(); + std::advance(last, nFrom+nCount); + + if (last != ret.end()) ret.erase(last, ret.end()); + if (first != ret.begin()) ret.erase(ret.begin(), first); + + std::reverse(ret.begin(), ret.end()); // Return oldest to newest + + return ret; +} + +Value listaccounts(const Array& params, bool fHelp) +{ + if (fHelp || params.size() > 1) + throw runtime_error( + "listaccounts [minconf=1]\n" + "Returns Object that has account names as keys, account balances as values."); + + int nMinDepth = 1; + if (params.size() > 0) + nMinDepth = params[0].get_int(); + + map mapAccountBalances; + BOOST_FOREACH(const PAIRTYPE(CTxDestination, string)& entry, pwalletMain->mapAddressBook) { + if (IsMine(*pwalletMain, entry.first)) // This address belongs to me + mapAccountBalances[entry.second] = 0; + } + + for (map::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) + { + const CWalletTx& wtx = (*it).second; + + if(!wtx.IsFinal()) + continue; + + int64 nGeneratedImmature, nGeneratedMature, nFee; + string strSentAccount; + list > listReceived; + list > listSent; + wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount); + if (wtx.GetDepthInMainChain() >= nMinDepth) + { + BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64)& r, listReceived) + if (pwalletMain->mapAddressBook.count(r.first)) + mapAccountBalances[pwalletMain->mapAddressBook[r.first]] += r.second; + else + mapAccountBalances[""] += r.second; + } + + if((wtx.IsCoinBaseOrStake() && wtx.GetDepthInMainChain() >= nMinDepth && wtx.GetBlocksToMaturity() == 0) + || !wtx.IsCoinBaseOrStake()) + { + mapAccountBalances[strSentAccount] -= nFee; + mapAccountBalances[""] += nGeneratedMature; + + BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64)& s, listSent) + mapAccountBalances[strSentAccount] -= s.second; + + } + } + + list acentries; + CWalletDB(pwalletMain->strWalletFile).ListAccountCreditDebit("*", acentries); + BOOST_FOREACH(const CAccountingEntry& entry, acentries) + mapAccountBalances[entry.strAccount] += entry.nCreditDebit; + + Object ret; + BOOST_FOREACH(const PAIRTYPE(string, int64)& accountBalance, mapAccountBalances) { + ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second))); + } + return ret; +} + +Value listsinceblock(const Array& params, bool fHelp) +{ + if (fHelp) + throw runtime_error( + "listsinceblock [blockhash] [target-confirmations]\n" + "Get all transactions in blocks since block [blockhash], or all transactions if omitted"); + + CBlockIndex *pindex = NULL; + int target_confirms = 1; + + if (params.size() > 0) + { + uint256 blockId = 0; + + blockId.SetHex(params[0].get_str()); + pindex = CBlockLocator(blockId).GetBlockIndex(); + } + + if (params.size() > 1) + { + target_confirms = params[1].get_int(); + + if (target_confirms < 1) + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter"); + } + + int depth = pindex ? (1 + nBestHeight - pindex->nHeight) : -1; + + Array transactions; + + for (map::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); it++) + { + CWalletTx tx = (*it).second; + + if (depth == -1 || tx.GetDepthInMainChain() < depth) + ListTransactions(tx, "*", 0, true, transactions); + } + + uint256 lastblock; + + if (target_confirms == 1) + { + lastblock = hashBestChain; + } + else + { + int target_height = pindexBest->nHeight + 1 - target_confirms; + + CBlockIndex *block; + for (block = pindexBest; + block && block->nHeight > target_height; + block = block->pprev) { } + + lastblock = block ? block->GetBlockHash() : 0; + } + + Object ret; + ret.push_back(Pair("transactions", transactions)); + ret.push_back(Pair("lastblock", lastblock.GetHex())); + + return ret; +} + +Value gettransaction(const Array& params, bool fHelp) +{ + if (fHelp || params.size() != 1) + throw runtime_error( + "gettransaction \n" + "Get detailed information about "); + + uint256 hash; + hash.SetHex(params[0].get_str()); + + Object entry; + + if (pwalletMain->mapWallet.count(hash)) + { + const CWalletTx& wtx = pwalletMain->mapWallet[hash]; + + TxToJSON(wtx, 0, entry); + + int64 nCredit = wtx.GetCredit(); + int64 nDebit = wtx.GetDebit(); + int64 nNet = nCredit - nDebit; + int64 nFee = (wtx.IsFromMe() ? wtx.GetValueOut() - nDebit : 0); + + entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee))); + if (wtx.IsFromMe()) + entry.push_back(Pair("fee", ValueFromAmount(nFee))); + + WalletTxToJSON(wtx, entry); + + Array details; + ListTransactions(pwalletMain->mapWallet[hash], "*", 0, false, details); + entry.push_back(Pair("details", details)); + } + else + { + CTransaction tx; + uint256 hashBlock = 0; + if (GetTransaction(hash, tx, hashBlock)) + { + entry.push_back(Pair("txid", hash.GetHex())); + TxToJSON(tx, 0, entry); + if (hashBlock == 0) + entry.push_back(Pair("confirmations", 0)); + else + { + entry.push_back(Pair("blockhash", hashBlock.GetHex())); + map::iterator mi = mapBlockIndex.find(hashBlock); + if (mi != mapBlockIndex.end() && (*mi).second) + { + CBlockIndex* pindex = (*mi).second; + if (pindex->IsInMainChain()) + { + entry.push_back(Pair("confirmations", 1 + nBestHeight - pindex->nHeight)); + entry.push_back(Pair("txntime", (boost::int64_t)tx.nTime)); + entry.push_back(Pair("time", (boost::int64_t)pindex->nTime)); + } + else + entry.push_back(Pair("confirmations", 0)); + } + } + } + else + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available about transaction"); + } + + return entry; +} + + +Value backupwallet(const Array& params, bool fHelp) +{ + if (fHelp || params.size() != 1) + throw runtime_error( + "backupwallet \n" + "Safely copies wallet.dat to destination, which can be a directory or a path with filename."); + + string strDest = params[0].get_str(); + if (!BackupWallet(*pwalletMain, strDest)) + throw JSONRPCError(RPC_WALLET_ERROR, "Error: Wallet backup failed!"); + + return Value::null; +} + + +Value keypoolrefill(const Array& params, bool fHelp) +{ + if (fHelp || params.size() > 0) + throw runtime_error( + "keypoolrefill\n" + "Fills the keypool." + + HelpRequiringPassphrase()); + + EnsureWalletIsUnlocked(); + + pwalletMain->TopUpKeyPool(); + + if (pwalletMain->GetKeyPoolSize() < GetArg("-keypool", 100)) + throw JSONRPCError(RPC_WALLET_ERROR, "Error refreshing keypool."); + + return Value::null; +} + + +void ThreadTopUpKeyPool(void* parg) +{ + // Make this thread recognisable as the key-topping-up thread + RenameThread("bitcoin-key-top"); + + pwalletMain->TopUpKeyPool(); +} + +void ThreadCleanWalletPassphrase(void* parg) +{ + // Make this thread recognisable as the wallet relocking thread + RenameThread("bitcoin-lock-wa"); + + int64 nMyWakeTime = GetTimeMillis() + *((int64*)parg) * 1000; + + ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime); + + if (nWalletUnlockTime == 0) + { + nWalletUnlockTime = nMyWakeTime; + + do + { + if (nWalletUnlockTime==0) + break; + int64 nToSleep = nWalletUnlockTime - GetTimeMillis(); + if (nToSleep <= 0) + break; + + LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime); + Sleep(nToSleep); + ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime); + + } while(1); + + if (nWalletUnlockTime) + { + nWalletUnlockTime = 0; + pwalletMain->Lock(); + } + } + else + { + if (nWalletUnlockTime < nMyWakeTime) + nWalletUnlockTime = nMyWakeTime; + } + + LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime); + + delete (int64*)parg; +} + +Value walletpassphrase(const Array& params, bool fHelp) +{ + if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 3)) + throw runtime_error( + "walletpassphrase [mintonly]\n" + "Stores the wallet decryption key in memory for seconds.\n" + "mintonly is optional true/false allowing only block minting."); + if (fHelp) + return true; + if (!pwalletMain->IsCrypted()) + throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrase was called."); + + if (!pwalletMain->IsLocked()) + throw JSONRPCError(RPC_WALLET_ALREADY_UNLOCKED, "Error: Wallet is already unlocked, use walletlock first if need to change unlock settings."); + // Note that the walletpassphrase is stored in params[0] which is not mlock()ed + SecureString strWalletPass; + strWalletPass.reserve(100); + // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string) + // Alternately, find a way to make params[0] mlock()'d to begin with. + strWalletPass = params[0].get_str().c_str(); + + if (strWalletPass.length() > 0) + { + if (!pwalletMain->Unlock(strWalletPass)) + throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect."); + } + else + throw runtime_error( + "walletpassphrase \n" + "Stores the wallet decryption key in memory for seconds."); + + NewThread(ThreadTopUpKeyPool, NULL); + int64* pnSleepTime = new int64(params[1].get_int64()); + NewThread(ThreadCleanWalletPassphrase, pnSleepTime); + + // triangles: if user OS account compromised prevent trivial sendmoney commands + if (params.size() > 2) + fWalletUnlockMintOnly = params[2].get_bool(); + else + fWalletUnlockMintOnly = false; + + return Value::null; +} + + +Value walletpassphrasechange(const Array& params, bool fHelp) +{ + if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2)) + throw runtime_error( + "walletpassphrasechange \n" + "Changes the wallet passphrase from to ."); + if (fHelp) + return true; + if (!pwalletMain->IsCrypted()) + throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrasechange was called."); + + // TODO: get rid of these .c_str() calls by implementing SecureString::operator=(std::string) + // Alternately, find a way to make params[0] mlock()'d to begin with. + SecureString strOldWalletPass; + strOldWalletPass.reserve(100); + strOldWalletPass = params[0].get_str().c_str(); + + SecureString strNewWalletPass; + strNewWalletPass.reserve(100); + strNewWalletPass = params[1].get_str().c_str(); + + if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1) + throw runtime_error( + "walletpassphrasechange \n" + "Changes the wallet passphrase from to ."); + + if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass)) + throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect."); + + return Value::null; +} + + +Value walletlock(const Array& params, bool fHelp) +{ + if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0)) + throw runtime_error( + "walletlock\n" + "Removes the wallet encryption key from memory, locking the wallet.\n" + "After calling this method, you will need to call walletpassphrase again\n" + "before being able to call any methods which require the wallet to be unlocked."); + if (fHelp) + return true; + if (!pwalletMain->IsCrypted()) + throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletlock was called."); + + { + LOCK(cs_nWalletUnlockTime); + pwalletMain->Lock(); + nWalletUnlockTime = 0; + } + + return Value::null; +} + + +Value encryptwallet(const Array& params, bool fHelp) +{ + if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1)) + throw runtime_error( + "encryptwallet \n" + "Encrypts the wallet with ."); + if (fHelp) + return true; + if (pwalletMain->IsCrypted()) + throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an encrypted wallet, but encryptwallet was called."); + + // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string) + // Alternately, find a way to make params[0] mlock()'d to begin with. + SecureString strWalletPass; + strWalletPass.reserve(100); + strWalletPass = params[0].get_str().c_str(); + + if (strWalletPass.length() < 1) + throw runtime_error( + "encryptwallet \n" + "Encrypts the wallet with ."); + + if (!pwalletMain->EncryptWallet(strWalletPass)) + throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, "Error: Failed to encrypt the wallet."); + + // BDB seems to have a bad habit of writing old data into + // slack space in .dat files; that is bad if the old data is + // unencrypted private keys. So: + StartShutdown(); + return "wallet encrypted; triangles server stopping, restart to run with encrypted wallet. The keypool has been flushed, you need to make a new backup."; +} + +class DescribeAddressVisitor : public boost::static_visitor +{ +public: + Object operator()(const CNoDestination &dest) const { return Object(); } + + Object operator()(const CKeyID &keyID) const { + Object obj; + CPubKey vchPubKey; + pwalletMain->GetPubKey(keyID, vchPubKey); + obj.push_back(Pair("isscript", false)); + obj.push_back(Pair("pubkey", HexStr(vchPubKey.Raw()))); + obj.push_back(Pair("iscompressed", vchPubKey.IsCompressed())); + return obj; + } + + Object operator()(const CScriptID &scriptID) const { + Object obj; + obj.push_back(Pair("isscript", true)); + CScript subscript; + pwalletMain->GetCScript(scriptID, subscript); + std::vector addresses; + txnouttype whichType; + int nRequired; + ExtractDestinations(subscript, whichType, addresses, nRequired); + obj.push_back(Pair("script", GetTxnOutputType(whichType))); + Array a; + BOOST_FOREACH(const CTxDestination& addr, addresses) + a.push_back(CBitcoinAddress(addr).ToString()); + obj.push_back(Pair("addresses", a)); + if (whichType == TX_MULTISIG) + obj.push_back(Pair("sigsrequired", nRequired)); + return obj; + } +}; + +Value validateaddress(const Array& params, bool fHelp) +{ + if (fHelp || params.size() != 1) + throw runtime_error( + "validateaddress \n" + "Return information about ."); + + CBitcoinAddress address(params[0].get_str()); + bool isValid = address.IsValid(); + + Object ret; + ret.push_back(Pair("isvalid", isValid)); + if (isValid) + { + CTxDestination dest = address.Get(); + string currentAddress = address.ToString(); + ret.push_back(Pair("address", currentAddress)); + bool fMine = IsMine(*pwalletMain, dest); + ret.push_back(Pair("ismine", fMine)); + if (fMine) { + Object detail = boost::apply_visitor(DescribeAddressVisitor(), dest); + ret.insert(ret.end(), detail.begin(), detail.end()); + } + if (pwalletMain->mapAddressBook.count(dest)) + ret.push_back(Pair("account", pwalletMain->mapAddressBook[dest])); + } + return ret; +} + +Value validatepubkey(const Array& params, bool fHelp) +{ + if (fHelp || !params.size() || params.size() > 2) + throw runtime_error( + "validatepubkey \n" + "Return information about ."); + + std::vector vchPubKey = ParseHex(params[0].get_str()); + CPubKey pubKey(vchPubKey); + + bool isValid = pubKey.IsValid(); + bool isCompressed = pubKey.IsCompressed(); + CKeyID keyID = pubKey.GetID(); + + CBitcoinAddress address; + address.Set(keyID); + + Object ret; + ret.push_back(Pair("isvalid", isValid)); + if (isValid) + { + CTxDestination dest = address.Get(); + string currentAddress = address.ToString(); + ret.push_back(Pair("address", currentAddress)); + bool fMine = IsMine(*pwalletMain, dest); + ret.push_back(Pair("ismine", fMine)); + ret.push_back(Pair("iscompressed", isCompressed)); + if (fMine) { + Object detail = boost::apply_visitor(DescribeAddressVisitor(), dest); + ret.insert(ret.end(), detail.begin(), detail.end()); + } + if (pwalletMain->mapAddressBook.count(dest)) + ret.push_back(Pair("account", pwalletMain->mapAddressBook[dest])); + } + return ret; +} + +// triangles: reserve balance from being staked for network protection +Value reservebalance(const Array& params, bool fHelp) +{ + if (fHelp || params.size() > 2) + throw runtime_error( + "reservebalance [ [amount]]\n" + " is true or false to turn balance reserve on or off.\n" + " is a real and rounded to cent.\n" + "Set reserve amount not participating in network protection.\n" + "If no parameters provided current setting is printed.\n"); + + if (params.size() > 0) + { + bool fReserve = params[0].get_bool(); + if (fReserve) + { + if (params.size() == 1) + throw runtime_error("must provide amount to reserve balance.\n"); + int64 nAmount = AmountFromValue(params[1]); + nAmount = (nAmount / CENT) * CENT; // round to cent + if (nAmount < 0) + throw runtime_error("amount cannot be negative.\n"); + mapArgs["-reservebalance"] = FormatMoney(nAmount).c_str(); + } + else + { + if (params.size() > 1) + throw runtime_error("cannot specify amount to turn off reserve.\n"); + mapArgs["-reservebalance"] = "0"; + } + } + + Object result; + int64 nReserveBalance = 0; + if (mapArgs.count("-reservebalance") && !ParseMoney(mapArgs["-reservebalance"], nReserveBalance)) + throw runtime_error("invalid reserve balance amount\n"); + result.push_back(Pair("reserve", (nReserveBalance > 0))); + result.push_back(Pair("amount", ValueFromAmount(nReserveBalance))); + return result; +} + + +// triangles: check wallet integrity +Value checkwallet(const Array& params, bool fHelp) +{ + if (fHelp || params.size() > 0) + throw runtime_error( + "checkwallet\n" + "Check wallet for integrity.\n"); + + int nMismatchSpent; + int64 nBalanceInQuestion; + pwalletMain->FixSpentCoins(nMismatchSpent, nBalanceInQuestion, true); + Object result; + if (nMismatchSpent == 0) + result.push_back(Pair("wallet check passed", true)); + else + { + result.push_back(Pair("mismatched spent coins", nMismatchSpent)); + result.push_back(Pair("amount in question", ValueFromAmount(nBalanceInQuestion))); + } + return result; +} + + +// triangles: repair wallet +Value repairwallet(const Array& params, bool fHelp) +{ + if (fHelp || params.size() > 0) + throw runtime_error( + "repairwallet\n" + "Repair wallet if checkwallet reports any problem.\n"); + + int nMismatchSpent; + int64 nBalanceInQuestion; + pwalletMain->FixSpentCoins(nMismatchSpent, nBalanceInQuestion); + Object result; + if (nMismatchSpent == 0) + result.push_back(Pair("wallet check passed", true)); + else + { + result.push_back(Pair("mismatched spent coins", nMismatchSpent)); + result.push_back(Pair("amount affected by repair", ValueFromAmount(nBalanceInQuestion))); + } + return result; +} + +// triangles: resend unconfirmed wallet transactions +Value resendtx(const Array& params, bool fHelp) +{ + if (fHelp || params.size() > 1) + throw runtime_error( + "resendtx\n" + "Re-send unconfirmed transactions.\n" + ); + + ResendWalletTransactions(); + + return Value::null; +} + +// triangles: make a public-private key pair +Value makekeypair(const Array& params, bool fHelp) +{ + if (fHelp || params.size() > 1) + throw runtime_error( + "makekeypair [prefix]\n" + "Make a public/private key pair.\n" + "[prefix] is optional preferred prefix for the public key.\n"); + + string strPrefix = ""; + if (params.size() > 0) + strPrefix = params[0].get_str(); + + CKey key; + key.MakeNewKey(false); + + CPrivKey vchPrivKey = key.GetPrivKey(); + Object result; + result.push_back(Pair("PrivateKey", HexStr(vchPrivKey.begin(), vchPrivKey.end()))); + result.push_back(Pair("PublicKey", HexStr(key.GetPubKey().Raw()))); + return result; +} diff --git a/src/script.cpp b/src/script.cpp new file mode 100644 index 0000000..e8c5de1 --- /dev/null +++ b/src/script.cpp @@ -0,0 +1,1883 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2012 The Bitcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include +#include + +using namespace std; +using namespace boost; + +#include "script.h" +#include "keystore.h" +#include "bignum.h" +#include "key.h" +#include "main.h" +#include "sync.h" +#include "util.h" + +bool CheckSig(vector vchSig, vector vchPubKey, CScript scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType); + +static const valtype vchFalse(0); +static const valtype vchZero(0); +static const valtype vchTrue(1, 1); +static const CBigNum bnZero(0); +static const CBigNum bnOne(1); +static const CBigNum bnFalse(0); +static const CBigNum bnTrue(1); +static const size_t nMaxNumSize = 4; + + +CBigNum CastToBigNum(const valtype& vch) +{ + if (vch.size() > nMaxNumSize) + throw runtime_error("CastToBigNum() : overflow"); + // Get rid of extra leading zeros + return CBigNum(CBigNum(vch).getvch()); +} + +bool CastToBool(const valtype& vch) +{ + for (unsigned int i = 0; i < vch.size(); i++) + { + if (vch[i] != 0) + { + // Can be negative zero + if (i == vch.size()-1 && vch[i] == 0x80) + return false; + return true; + } + } + return false; +} + +// WARNING: This does not work as expected for signed integers; the sign-bit +// is left in place as the integer is zero-extended. The correct behavior +// would be to move the most significant bit of the last byte during the +// resize process. MakeSameSize() is currently only used by the disabled +// opcodes OP_AND, OP_OR, and OP_XOR. +void MakeSameSize(valtype& vch1, valtype& vch2) +{ + // Lengthen the shorter one + if (vch1.size() < vch2.size()) + // PATCH: + // +unsigned char msb = vch1[vch1.size()-1]; + // +vch1[vch1.size()-1] &= 0x7f; + // vch1.resize(vch2.size(), 0); + // +vch1[vch1.size()-1] = msb; + vch1.resize(vch2.size(), 0); + if (vch2.size() < vch1.size()) + // PATCH: + // +unsigned char msb = vch2[vch2.size()-1]; + // +vch2[vch2.size()-1] &= 0x7f; + // vch2.resize(vch1.size(), 0); + // +vch2[vch2.size()-1] = msb; + vch2.resize(vch1.size(), 0); +} + + + +// +// Script is a stack machine (like Forth) that evaluates a predicate +// returning a bool indicating valid or not. There are no loops. +// +#define stacktop(i) (stack.at(stack.size()+(i))) +#define altstacktop(i) (altstack.at(altstack.size()+(i))) +static inline void popstack(vector& stack) +{ + if (stack.empty()) + throw runtime_error("popstack() : stack empty"); + stack.pop_back(); +} + + +const char* GetTxnOutputType(txnouttype t) +{ + switch (t) + { + case TX_NONSTANDARD: return "nonstandard"; + case TX_PUBKEY: return "pubkey"; + case TX_PUBKEYHASH: return "pubkeyhash"; + case TX_SCRIPTHASH: return "scripthash"; + case TX_MULTISIG: return "multisig"; + } + return NULL; +} + + +const char* GetOpName(opcodetype opcode) +{ + switch (opcode) + { + // push value + case OP_0 : return "0"; + case OP_PUSHDATA1 : return "OP_PUSHDATA1"; + case OP_PUSHDATA2 : return "OP_PUSHDATA2"; + case OP_PUSHDATA4 : return "OP_PUSHDATA4"; + case OP_1NEGATE : return "-1"; + case OP_RESERVED : return "OP_RESERVED"; + case OP_1 : return "1"; + case OP_2 : return "2"; + case OP_3 : return "3"; + case OP_4 : return "4"; + case OP_5 : return "5"; + case OP_6 : return "6"; + case OP_7 : return "7"; + case OP_8 : return "8"; + case OP_9 : return "9"; + case OP_10 : return "10"; + case OP_11 : return "11"; + case OP_12 : return "12"; + case OP_13 : return "13"; + case OP_14 : return "14"; + case OP_15 : return "15"; + case OP_16 : return "16"; + + // control + case OP_NOP : return "OP_NOP"; + case OP_VER : return "OP_VER"; + case OP_IF : return "OP_IF"; + case OP_NOTIF : return "OP_NOTIF"; + case OP_VERIF : return "OP_VERIF"; + case OP_VERNOTIF : return "OP_VERNOTIF"; + case OP_ELSE : return "OP_ELSE"; + case OP_ENDIF : return "OP_ENDIF"; + case OP_VERIFY : return "OP_VERIFY"; + case OP_RETURN : return "OP_RETURN"; + + // stack ops + case OP_TOALTSTACK : return "OP_TOALTSTACK"; + case OP_FROMALTSTACK : return "OP_FROMALTSTACK"; + case OP_2DROP : return "OP_2DROP"; + case OP_2DUP : return "OP_2DUP"; + case OP_3DUP : return "OP_3DUP"; + case OP_2OVER : return "OP_2OVER"; + case OP_2ROT : return "OP_2ROT"; + case OP_2SWAP : return "OP_2SWAP"; + case OP_IFDUP : return "OP_IFDUP"; + case OP_DEPTH : return "OP_DEPTH"; + case OP_DROP : return "OP_DROP"; + case OP_DUP : return "OP_DUP"; + case OP_NIP : return "OP_NIP"; + case OP_OVER : return "OP_OVER"; + case OP_PICK : return "OP_PICK"; + case OP_ROLL : return "OP_ROLL"; + case OP_ROT : return "OP_ROT"; + case OP_SWAP : return "OP_SWAP"; + case OP_TUCK : return "OP_TUCK"; + + // splice ops + case OP_CAT : return "OP_CAT"; + case OP_SUBSTR : return "OP_SUBSTR"; + case OP_LEFT : return "OP_LEFT"; + case OP_RIGHT : return "OP_RIGHT"; + case OP_SIZE : return "OP_SIZE"; + + // bit logic + case OP_INVERT : return "OP_INVERT"; + case OP_AND : return "OP_AND"; + case OP_OR : return "OP_OR"; + case OP_XOR : return "OP_XOR"; + case OP_EQUAL : return "OP_EQUAL"; + case OP_EQUALVERIFY : return "OP_EQUALVERIFY"; + case OP_RESERVED1 : return "OP_RESERVED1"; + case OP_RESERVED2 : return "OP_RESERVED2"; + + // numeric + case OP_1ADD : return "OP_1ADD"; + case OP_1SUB : return "OP_1SUB"; + case OP_2MUL : return "OP_2MUL"; + case OP_2DIV : return "OP_2DIV"; + case OP_NEGATE : return "OP_NEGATE"; + case OP_ABS : return "OP_ABS"; + case OP_NOT : return "OP_NOT"; + case OP_0NOTEQUAL : return "OP_0NOTEQUAL"; + case OP_ADD : return "OP_ADD"; + case OP_SUB : return "OP_SUB"; + case OP_MUL : return "OP_MUL"; + case OP_DIV : return "OP_DIV"; + case OP_MOD : return "OP_MOD"; + case OP_LSHIFT : return "OP_LSHIFT"; + case OP_RSHIFT : return "OP_RSHIFT"; + case OP_BOOLAND : return "OP_BOOLAND"; + case OP_BOOLOR : return "OP_BOOLOR"; + case OP_NUMEQUAL : return "OP_NUMEQUAL"; + case OP_NUMEQUALVERIFY : return "OP_NUMEQUALVERIFY"; + case OP_NUMNOTEQUAL : return "OP_NUMNOTEQUAL"; + case OP_LESSTHAN : return "OP_LESSTHAN"; + case OP_GREATERTHAN : return "OP_GREATERTHAN"; + case OP_LESSTHANOREQUAL : return "OP_LESSTHANOREQUAL"; + case OP_GREATERTHANOREQUAL : return "OP_GREATERTHANOREQUAL"; + case OP_MIN : return "OP_MIN"; + case OP_MAX : return "OP_MAX"; + case OP_WITHIN : return "OP_WITHIN"; + + // crypto + case OP_RIPEMD160 : return "OP_RIPEMD160"; + case OP_SHA1 : return "OP_SHA1"; + case OP_SHA256 : return "OP_SHA256"; + case OP_HASH160 : return "OP_HASH160"; + case OP_HASH256 : return "OP_HASH256"; + case OP_CODESEPARATOR : return "OP_CODESEPARATOR"; + case OP_CHECKSIG : return "OP_CHECKSIG"; + case OP_CHECKSIGVERIFY : return "OP_CHECKSIGVERIFY"; + case OP_CHECKMULTISIG : return "OP_CHECKMULTISIG"; + case OP_CHECKMULTISIGVERIFY : return "OP_CHECKMULTISIGVERIFY"; + + // expanson + case OP_NOP1 : return "OP_NOP1"; + case OP_NOP2 : return "OP_NOP2"; + case OP_NOP3 : return "OP_NOP3"; + case OP_NOP4 : return "OP_NOP4"; + case OP_NOP5 : return "OP_NOP5"; + case OP_NOP6 : return "OP_NOP6"; + case OP_NOP7 : return "OP_NOP7"; + case OP_NOP8 : return "OP_NOP8"; + case OP_NOP9 : return "OP_NOP9"; + case OP_NOP10 : return "OP_NOP10"; + + + + // template matching params + case OP_PUBKEYHASH : return "OP_PUBKEYHASH"; + case OP_PUBKEY : return "OP_PUBKEY"; + + case OP_INVALIDOPCODE : return "OP_INVALIDOPCODE"; + default: + return "OP_UNKNOWN"; + } +} + +bool EvalScript(vector >& stack, const CScript& script, const CTransaction& txTo, unsigned int nIn, int nHashType) +{ + CAutoBN_CTX pctx; + CScript::const_iterator pc = script.begin(); + CScript::const_iterator pend = script.end(); + CScript::const_iterator pbegincodehash = script.begin(); + opcodetype opcode; + valtype vchPushValue; + vector vfExec; + vector altstack; + if (script.size() > 10000) + return false; + int nOpCount = 0; + + + try + { + while (pc < pend) + { + bool fExec = !count(vfExec.begin(), vfExec.end(), false); + + // + // Read instruction + // + if (!script.GetOp(pc, opcode, vchPushValue)) + return false; + if (vchPushValue.size() > 520) + return false; + if (opcode > OP_16 && ++nOpCount > 201) + return false; + + if (opcode == OP_CAT || + opcode == OP_SUBSTR || + opcode == OP_LEFT || + opcode == OP_RIGHT || + opcode == OP_INVERT || + opcode == OP_AND || + opcode == OP_OR || + opcode == OP_XOR || + opcode == OP_2MUL || + opcode == OP_2DIV || + opcode == OP_MUL || + opcode == OP_DIV || + opcode == OP_MOD || + opcode == OP_LSHIFT || + opcode == OP_RSHIFT) + return false; + + if (fExec && 0 <= opcode && opcode <= OP_PUSHDATA4) + stack.push_back(vchPushValue); + else if (fExec || (OP_IF <= opcode && opcode <= OP_ENDIF)) + switch (opcode) + { + // + // Push value + // + case OP_1NEGATE: + case OP_1: + case OP_2: + case OP_3: + case OP_4: + case OP_5: + case OP_6: + case OP_7: + case OP_8: + case OP_9: + case OP_10: + case OP_11: + case OP_12: + case OP_13: + case OP_14: + case OP_15: + case OP_16: + { + // ( -- value) + CBigNum bn((int)opcode - (int)(OP_1 - 1)); + stack.push_back(bn.getvch()); + } + break; + + + // + // Control + // + case OP_NOP: + case OP_NOP1: case OP_NOP2: case OP_NOP3: case OP_NOP4: case OP_NOP5: + case OP_NOP6: case OP_NOP7: case OP_NOP8: case OP_NOP9: case OP_NOP10: + break; + + case OP_IF: + case OP_NOTIF: + { + // if [statements] [else [statements]] endif + bool fValue = false; + if (fExec) + { + if (stack.size() < 1) + return false; + valtype& vch = stacktop(-1); + fValue = CastToBool(vch); + if (opcode == OP_NOTIF) + fValue = !fValue; + popstack(stack); + } + vfExec.push_back(fValue); + } + break; + + case OP_ELSE: + { + if (vfExec.empty()) + return false; + vfExec.back() = !vfExec.back(); + } + break; + + case OP_ENDIF: + { + if (vfExec.empty()) + return false; + vfExec.pop_back(); + } + break; + + case OP_VERIFY: + { + // (true -- ) or + // (false -- false) and return + if (stack.size() < 1) + return false; + bool fValue = CastToBool(stacktop(-1)); + if (fValue) + popstack(stack); + else + return false; + } + break; + + case OP_RETURN: + { + return false; + } + break; + + + // + // Stack ops + // + case OP_TOALTSTACK: + { + if (stack.size() < 1) + return false; + altstack.push_back(stacktop(-1)); + popstack(stack); + } + break; + + case OP_FROMALTSTACK: + { + if (altstack.size() < 1) + return false; + stack.push_back(altstacktop(-1)); + popstack(altstack); + } + break; + + case OP_2DROP: + { + // (x1 x2 -- ) + if (stack.size() < 2) + return false; + popstack(stack); + popstack(stack); + } + break; + + case OP_2DUP: + { + // (x1 x2 -- x1 x2 x1 x2) + if (stack.size() < 2) + return false; + valtype vch1 = stacktop(-2); + valtype vch2 = stacktop(-1); + stack.push_back(vch1); + stack.push_back(vch2); + } + break; + + case OP_3DUP: + { + // (x1 x2 x3 -- x1 x2 x3 x1 x2 x3) + if (stack.size() < 3) + return false; + valtype vch1 = stacktop(-3); + valtype vch2 = stacktop(-2); + valtype vch3 = stacktop(-1); + stack.push_back(vch1); + stack.push_back(vch2); + stack.push_back(vch3); + } + break; + + case OP_2OVER: + { + // (x1 x2 x3 x4 -- x1 x2 x3 x4 x1 x2) + if (stack.size() < 4) + return false; + valtype vch1 = stacktop(-4); + valtype vch2 = stacktop(-3); + stack.push_back(vch1); + stack.push_back(vch2); + } + break; + + case OP_2ROT: + { + // (x1 x2 x3 x4 x5 x6 -- x3 x4 x5 x6 x1 x2) + if (stack.size() < 6) + return false; + valtype vch1 = stacktop(-6); + valtype vch2 = stacktop(-5); + stack.erase(stack.end()-6, stack.end()-4); + stack.push_back(vch1); + stack.push_back(vch2); + } + break; + + case OP_2SWAP: + { + // (x1 x2 x3 x4 -- x3 x4 x1 x2) + if (stack.size() < 4) + return false; + swap(stacktop(-4), stacktop(-2)); + swap(stacktop(-3), stacktop(-1)); + } + break; + + case OP_IFDUP: + { + // (x - 0 | x x) + if (stack.size() < 1) + return false; + valtype vch = stacktop(-1); + if (CastToBool(vch)) + stack.push_back(vch); + } + break; + + case OP_DEPTH: + { + // -- stacksize + CBigNum bn(stack.size()); + stack.push_back(bn.getvch()); + } + break; + + case OP_DROP: + { + // (x -- ) + if (stack.size() < 1) + return false; + popstack(stack); + } + break; + + case OP_DUP: + { + // (x -- x x) + if (stack.size() < 1) + return false; + valtype vch = stacktop(-1); + stack.push_back(vch); + } + break; + + case OP_NIP: + { + // (x1 x2 -- x2) + if (stack.size() < 2) + return false; + stack.erase(stack.end() - 2); + } + break; + + case OP_OVER: + { + // (x1 x2 -- x1 x2 x1) + if (stack.size() < 2) + return false; + valtype vch = stacktop(-2); + stack.push_back(vch); + } + break; + + case OP_PICK: + case OP_ROLL: + { + // (xn ... x2 x1 x0 n - xn ... x2 x1 x0 xn) + // (xn ... x2 x1 x0 n - ... x2 x1 x0 xn) + if (stack.size() < 2) + return false; + int n = CastToBigNum(stacktop(-1)).getint(); + popstack(stack); + if (n < 0 || n >= (int)stack.size()) + return false; + valtype vch = stacktop(-n-1); + if (opcode == OP_ROLL) + stack.erase(stack.end()-n-1); + stack.push_back(vch); + } + break; + + case OP_ROT: + { + // (x1 x2 x3 -- x2 x3 x1) + // x2 x1 x3 after first swap + // x2 x3 x1 after second swap + if (stack.size() < 3) + return false; + swap(stacktop(-3), stacktop(-2)); + swap(stacktop(-2), stacktop(-1)); + } + break; + + case OP_SWAP: + { + // (x1 x2 -- x2 x1) + if (stack.size() < 2) + return false; + swap(stacktop(-2), stacktop(-1)); + } + break; + + case OP_TUCK: + { + // (x1 x2 -- x2 x1 x2) + if (stack.size() < 2) + return false; + valtype vch = stacktop(-1); + stack.insert(stack.end()-2, vch); + } + break; + + + // + // Splice ops + // + case OP_CAT: + { + // (x1 x2 -- out) + if (stack.size() < 2) + return false; + valtype& vch1 = stacktop(-2); + valtype& vch2 = stacktop(-1); + vch1.insert(vch1.end(), vch2.begin(), vch2.end()); + popstack(stack); + if (stacktop(-1).size() > 520) + return false; + } + break; + + case OP_SUBSTR: + { + // (in begin size -- out) + if (stack.size() < 3) + return false; + valtype& vch = stacktop(-3); + int nBegin = CastToBigNum(stacktop(-2)).getint(); + int nEnd = nBegin + CastToBigNum(stacktop(-1)).getint(); + if (nBegin < 0 || nEnd < nBegin) + return false; + if (nBegin > (int)vch.size()) + nBegin = vch.size(); + if (nEnd > (int)vch.size()) + nEnd = vch.size(); + vch.erase(vch.begin() + nEnd, vch.end()); + vch.erase(vch.begin(), vch.begin() + nBegin); + popstack(stack); + popstack(stack); + } + break; + + case OP_LEFT: + case OP_RIGHT: + { + // (in size -- out) + if (stack.size() < 2) + return false; + valtype& vch = stacktop(-2); + int nSize = CastToBigNum(stacktop(-1)).getint(); + if (nSize < 0) + return false; + if (nSize > (int)vch.size()) + nSize = vch.size(); + if (opcode == OP_LEFT) + vch.erase(vch.begin() + nSize, vch.end()); + else + vch.erase(vch.begin(), vch.end() - nSize); + popstack(stack); + } + break; + + case OP_SIZE: + { + // (in -- in size) + if (stack.size() < 1) + return false; + CBigNum bn(stacktop(-1).size()); + stack.push_back(bn.getvch()); + } + break; + + + // + // Bitwise logic + // + case OP_INVERT: + { + // (in - out) + if (stack.size() < 1) + return false; + valtype& vch = stacktop(-1); + for (unsigned int i = 0; i < vch.size(); i++) + vch[i] = ~vch[i]; + } + break; + + // + // WARNING: These disabled opcodes exhibit unexpected behavior + // when used on signed integers due to a bug in MakeSameSize() + // [see definition of MakeSameSize() above]. + // + case OP_AND: + case OP_OR: + case OP_XOR: + { + // (x1 x2 - out) + if (stack.size() < 2) + return false; + valtype& vch1 = stacktop(-2); + valtype& vch2 = stacktop(-1); + MakeSameSize(vch1, vch2); // <-- NOT SAFE FOR SIGNED VALUES + if (opcode == OP_AND) + { + for (unsigned int i = 0; i < vch1.size(); i++) + vch1[i] &= vch2[i]; + } + else if (opcode == OP_OR) + { + for (unsigned int i = 0; i < vch1.size(); i++) + vch1[i] |= vch2[i]; + } + else if (opcode == OP_XOR) + { + for (unsigned int i = 0; i < vch1.size(); i++) + vch1[i] ^= vch2[i]; + } + popstack(stack); + } + break; + + case OP_EQUAL: + case OP_EQUALVERIFY: + //case OP_NOTEQUAL: // use OP_NUMNOTEQUAL + { + // (x1 x2 - bool) + if (stack.size() < 2) + return false; + valtype& vch1 = stacktop(-2); + valtype& vch2 = stacktop(-1); + bool fEqual = (vch1 == vch2); + // OP_NOTEQUAL is disabled because it would be too easy to say + // something like n != 1 and have some wiseguy pass in 1 with extra + // zero bytes after it (numerically, 0x01 == 0x0001 == 0x000001) + //if (opcode == OP_NOTEQUAL) + // fEqual = !fEqual; + popstack(stack); + popstack(stack); + stack.push_back(fEqual ? vchTrue : vchFalse); + if (opcode == OP_EQUALVERIFY) + { + if (fEqual) + popstack(stack); + else + return false; + } + } + break; + + + // + // Numeric + // + case OP_1ADD: + case OP_1SUB: + case OP_2MUL: + case OP_2DIV: + case OP_NEGATE: + case OP_ABS: + case OP_NOT: + case OP_0NOTEQUAL: + { + // (in -- out) + if (stack.size() < 1) + return false; + CBigNum bn = CastToBigNum(stacktop(-1)); + switch (opcode) + { + case OP_1ADD: bn += bnOne; break; + case OP_1SUB: bn -= bnOne; break; + case OP_2MUL: bn <<= 1; break; + case OP_2DIV: bn >>= 1; break; + case OP_NEGATE: bn = -bn; break; + case OP_ABS: if (bn < bnZero) bn = -bn; break; + case OP_NOT: bn = (bn == bnZero); break; + case OP_0NOTEQUAL: bn = (bn != bnZero); break; + default: assert(!"invalid opcode"); break; + } + popstack(stack); + stack.push_back(bn.getvch()); + } + break; + + case OP_ADD: + case OP_SUB: + case OP_MUL: + case OP_DIV: + case OP_MOD: + case OP_LSHIFT: + case OP_RSHIFT: + case OP_BOOLAND: + case OP_BOOLOR: + case OP_NUMEQUAL: + case OP_NUMEQUALVERIFY: + case OP_NUMNOTEQUAL: + case OP_LESSTHAN: + case OP_GREATERTHAN: + case OP_LESSTHANOREQUAL: + case OP_GREATERTHANOREQUAL: + case OP_MIN: + case OP_MAX: + { + // (x1 x2 -- out) + if (stack.size() < 2) + return false; + CBigNum bn1 = CastToBigNum(stacktop(-2)); + CBigNum bn2 = CastToBigNum(stacktop(-1)); + CBigNum bn; + switch (opcode) + { + case OP_ADD: + bn = bn1 + bn2; + break; + + case OP_SUB: + bn = bn1 - bn2; + break; + + case OP_MUL: + if (!BN_mul(&bn, &bn1, &bn2, pctx)) + return false; + break; + + case OP_DIV: + if (!BN_div(&bn, NULL, &bn1, &bn2, pctx)) + return false; + break; + + case OP_MOD: + if (!BN_mod(&bn, &bn1, &bn2, pctx)) + return false; + break; + + case OP_LSHIFT: + if (bn2 < bnZero || bn2 > CBigNum(2048)) + return false; + bn = bn1 << bn2.getulong(); + break; + + case OP_RSHIFT: + if (bn2 < bnZero || bn2 > CBigNum(2048)) + return false; + bn = bn1 >> bn2.getulong(); + break; + + case OP_BOOLAND: bn = (bn1 != bnZero && bn2 != bnZero); break; + case OP_BOOLOR: bn = (bn1 != bnZero || bn2 != bnZero); break; + case OP_NUMEQUAL: bn = (bn1 == bn2); break; + case OP_NUMEQUALVERIFY: bn = (bn1 == bn2); break; + case OP_NUMNOTEQUAL: bn = (bn1 != bn2); break; + case OP_LESSTHAN: bn = (bn1 < bn2); break; + case OP_GREATERTHAN: bn = (bn1 > bn2); break; + case OP_LESSTHANOREQUAL: bn = (bn1 <= bn2); break; + case OP_GREATERTHANOREQUAL: bn = (bn1 >= bn2); break; + case OP_MIN: bn = (bn1 < bn2 ? bn1 : bn2); break; + case OP_MAX: bn = (bn1 > bn2 ? bn1 : bn2); break; + default: assert(!"invalid opcode"); break; + } + popstack(stack); + popstack(stack); + stack.push_back(bn.getvch()); + + if (opcode == OP_NUMEQUALVERIFY) + { + if (CastToBool(stacktop(-1))) + popstack(stack); + else + return false; + } + } + break; + + case OP_WITHIN: + { + // (x min max -- out) + if (stack.size() < 3) + return false; + CBigNum bn1 = CastToBigNum(stacktop(-3)); + CBigNum bn2 = CastToBigNum(stacktop(-2)); + CBigNum bn3 = CastToBigNum(stacktop(-1)); + bool fValue = (bn2 <= bn1 && bn1 < bn3); + popstack(stack); + popstack(stack); + popstack(stack); + stack.push_back(fValue ? vchTrue : vchFalse); + } + break; + + + // + // Crypto + // + case OP_RIPEMD160: + case OP_SHA1: + case OP_SHA256: + case OP_HASH160: + case OP_HASH256: + { + // (in -- hash) + if (stack.size() < 1) + return false; + valtype& vch = stacktop(-1); + valtype vchHash((opcode == OP_RIPEMD160 || opcode == OP_SHA1 || opcode == OP_HASH160) ? 20 : 32); + if (opcode == OP_RIPEMD160) + RIPEMD160(&vch[0], vch.size(), &vchHash[0]); + else if (opcode == OP_SHA1) + SHA1(&vch[0], vch.size(), &vchHash[0]); + else if (opcode == OP_SHA256) + SHA256(&vch[0], vch.size(), &vchHash[0]); + else if (opcode == OP_HASH160) + { + uint160 hash160 = Hash160(vch); + memcpy(&vchHash[0], &hash160, sizeof(hash160)); + } + else if (opcode == OP_HASH256) + { + uint256 hash = Hash(vch.begin(), vch.end()); + memcpy(&vchHash[0], &hash, sizeof(hash)); + } + popstack(stack); + stack.push_back(vchHash); + } + break; + + case OP_CODESEPARATOR: + { + // Hash starts after the code separator + pbegincodehash = pc; + } + break; + + case OP_CHECKSIG: + case OP_CHECKSIGVERIFY: + { + // (sig pubkey -- bool) + if (stack.size() < 2) + return false; + + valtype& vchSig = stacktop(-2); + valtype& vchPubKey = stacktop(-1); + + ////// debug print + //PrintHex(vchSig.begin(), vchSig.end(), "sig: %s\n"); + //PrintHex(vchPubKey.begin(), vchPubKey.end(), "pubkey: %s\n"); + + // Subset of script starting at the most recent codeseparator + CScript scriptCode(pbegincodehash, pend); + + // Drop the signature, since there's no way for a signature to sign itself + scriptCode.FindAndDelete(CScript(vchSig)); + + bool fSuccess = CheckSig(vchSig, vchPubKey, scriptCode, txTo, nIn, nHashType); + + popstack(stack); + popstack(stack); + stack.push_back(fSuccess ? vchTrue : vchFalse); + if (opcode == OP_CHECKSIGVERIFY) + { + if (fSuccess) + popstack(stack); + else + return false; + } + } + break; + + case OP_CHECKMULTISIG: + case OP_CHECKMULTISIGVERIFY: + { + // ([sig ...] num_of_signatures [pubkey ...] num_of_pubkeys -- bool) + + int i = 1; + if ((int)stack.size() < i) + return false; + + int nKeysCount = CastToBigNum(stacktop(-i)).getint(); + if (nKeysCount < 0 || nKeysCount > 20) + return false; + nOpCount += nKeysCount; + if (nOpCount > 201) + return false; + int ikey = ++i; + i += nKeysCount; + if ((int)stack.size() < i) + return false; + + int nSigsCount = CastToBigNum(stacktop(-i)).getint(); + if (nSigsCount < 0 || nSigsCount > nKeysCount) + return false; + int isig = ++i; + i += nSigsCount; + if ((int)stack.size() < i) + return false; + + // Subset of script starting at the most recent codeseparator + CScript scriptCode(pbegincodehash, pend); + + // Drop the signatures, since there's no way for a signature to sign itself + for (int k = 0; k < nSigsCount; k++) + { + valtype& vchSig = stacktop(-isig-k); + scriptCode.FindAndDelete(CScript(vchSig)); + } + + bool fSuccess = true; + while (fSuccess && nSigsCount > 0) + { + valtype& vchSig = stacktop(-isig); + valtype& vchPubKey = stacktop(-ikey); + + // Check signature + if (CheckSig(vchSig, vchPubKey, scriptCode, txTo, nIn, nHashType)) + { + isig++; + nSigsCount--; + } + ikey++; + nKeysCount--; + + // If there are more signatures left than keys left, + // then too many signatures have failed + if (nSigsCount > nKeysCount) + fSuccess = false; + } + + while (i-- > 0) + popstack(stack); + stack.push_back(fSuccess ? vchTrue : vchFalse); + + if (opcode == OP_CHECKMULTISIGVERIFY) + { + if (fSuccess) + popstack(stack); + else + return false; + } + } + break; + + default: + return false; + } + + // Size limits + if (stack.size() + altstack.size() > 1000) + return false; + } + } + catch (...) + { + return false; + } + + + if (!vfExec.empty()) + return false; + + return true; +} + + + + + + + + + +uint256 SignatureHash(CScript scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType) +{ + if (nIn >= txTo.vin.size()) + { + printf("ERROR: SignatureHash() : nIn=%d out of range\n", nIn); + return 1; + } + CTransaction txTmp(txTo); + + // In case concatenating two scripts ends up with two codeseparators, + // or an extra one at the end, this prevents all those possible incompatibilities. + scriptCode.FindAndDelete(CScript(OP_CODESEPARATOR)); + + // Blank out other inputs' signatures + for (unsigned int i = 0; i < txTmp.vin.size(); i++) + txTmp.vin[i].scriptSig = CScript(); + txTmp.vin[nIn].scriptSig = scriptCode; + + // Blank out some of the outputs + if ((nHashType & 0x1f) == SIGHASH_NONE) + { + // Wildcard payee + txTmp.vout.clear(); + + // Let the others update at will + for (unsigned int i = 0; i < txTmp.vin.size(); i++) + if (i != nIn) + txTmp.vin[i].nSequence = 0; + } + else if ((nHashType & 0x1f) == SIGHASH_SINGLE) + { + // Only lock-in the txout payee at same index as txin + unsigned int nOut = nIn; + if (nOut >= txTmp.vout.size()) + { + printf("ERROR: SignatureHash() : nOut=%d out of range\n", nOut); + return 1; + } + txTmp.vout.resize(nOut+1); + for (unsigned int i = 0; i < nOut; i++) + txTmp.vout[i].SetNull(); + + // Let the others update at will + for (unsigned int i = 0; i < txTmp.vin.size(); i++) + if (i != nIn) + txTmp.vin[i].nSequence = 0; + } + + // Blank out other inputs completely, not recommended for open transactions + if (nHashType & SIGHASH_ANYONECANPAY) + { + txTmp.vin[0] = txTmp.vin[nIn]; + txTmp.vin.resize(1); + } + + // Serialize and hash + CDataStream ss(SER_GETHASH, 0); + ss.reserve(10000); + ss << txTmp << nHashType; + return Hash(ss.begin(), ss.end()); +} + + +// Valid signature cache, to avoid doing expensive ECDSA signature checking +// twice for every transaction (once when accepted into memory pool, and +// again when accepted into the block chain) + +class CSignatureCache +{ +private: + // sigdata_type is (signature hash, signature, public key): + typedef boost::tuple, std::vector > sigdata_type; + std::set< sigdata_type> setValid; + CCriticalSection cs_sigcache; + +public: + bool + Get(uint256 hash, const std::vector& vchSig, const std::vector& pubKey) + { + LOCK(cs_sigcache); + + sigdata_type k(hash, vchSig, pubKey); + std::set::iterator mi = setValid.find(k); + if (mi != setValid.end()) + return true; + return false; + } + + void Set(uint256 hash, const std::vector& vchSig, const std::vector& pubKey) + { + // DoS prevention: limit cache size to less than 10MB + // (~200 bytes per cache entry times 50,000 entries) + // Since there are a maximum of 20,000 signature operations per block + // 50,000 is a reasonable default. + int64 nMaxCacheSize = GetArg("-maxsigcachesize", 50000); + if (nMaxCacheSize <= 0) return; + + LOCK(cs_sigcache); + + while (static_cast(setValid.size()) > nMaxCacheSize) + { + // Evict a random entry. Random because that helps + // foil would-be DoS attackers who might try to pre-generate + // and re-use a set of valid signatures just-slightly-greater + // than our cache size. + uint256 randomHash = GetRandHash(); + std::vector unused; + std::set::iterator it = + setValid.lower_bound(sigdata_type(randomHash, unused, unused)); + if (it == setValid.end()) + it = setValid.begin(); + setValid.erase(*it); + } + + sigdata_type k(hash, vchSig, pubKey); + setValid.insert(k); + } +}; + +bool CheckSig(vector vchSig, vector vchPubKey, CScript scriptCode, + const CTransaction& txTo, unsigned int nIn, int nHashType) +{ + static CSignatureCache signatureCache; + + // Hash type is one byte tacked on to the end of the signature + if (vchSig.empty()) + return false; + if (nHashType == 0) + nHashType = vchSig.back(); + else if (nHashType != vchSig.back()) + return false; + vchSig.pop_back(); + + uint256 sighash = SignatureHash(scriptCode, txTo, nIn, nHashType); + + if (signatureCache.Get(sighash, vchSig, vchPubKey)) + return true; + + CKey key; + if (!key.SetPubKey(vchPubKey)) + return false; + + if (!key.Verify(sighash, vchSig)) + return false; + + signatureCache.Set(sighash, vchSig, vchPubKey); + return true; +} + + + + + + + + + +// +// Return public keys or hashes from scriptPubKey, for 'standard' transaction types. +// +bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector >& vSolutionsRet) +{ + // Templates + static map mTemplates; + if (mTemplates.empty()) + { + // Standard tx, sender provides pubkey, receiver adds signature + mTemplates.insert(make_pair(TX_PUBKEY, CScript() << OP_PUBKEY << OP_CHECKSIG)); + + // Bitcoin address tx, sender provides hash of pubkey, receiver provides signature and pubkey + mTemplates.insert(make_pair(TX_PUBKEYHASH, CScript() << OP_DUP << OP_HASH160 << OP_PUBKEYHASH << OP_EQUALVERIFY << OP_CHECKSIG)); + + // Sender provides N pubkeys, receivers provides M signatures + mTemplates.insert(make_pair(TX_MULTISIG, CScript() << OP_SMALLINTEGER << OP_PUBKEYS << OP_SMALLINTEGER << OP_CHECKMULTISIG)); + } + + // Shortcut for pay-to-script-hash, which are more constrained than the other types: + // it is always OP_HASH160 20 [20 byte hash] OP_EQUAL + if (scriptPubKey.IsPayToScriptHash()) + { + typeRet = TX_SCRIPTHASH; + vector hashBytes(scriptPubKey.begin()+2, scriptPubKey.begin()+22); + vSolutionsRet.push_back(hashBytes); + return true; + } + + // Scan templates + const CScript& script1 = scriptPubKey; + BOOST_FOREACH(const PAIRTYPE(txnouttype, CScript)& tplate, mTemplates) + { + const CScript& script2 = tplate.second; + vSolutionsRet.clear(); + + opcodetype opcode1, opcode2; + vector vch1, vch2; + + // Compare + CScript::const_iterator pc1 = script1.begin(); + CScript::const_iterator pc2 = script2.begin(); + loop + { + if (pc1 == script1.end() && pc2 == script2.end()) + { + // Found a match + typeRet = tplate.first; + if (typeRet == TX_MULTISIG) + { + // Additional checks for TX_MULTISIG: + unsigned char m = vSolutionsRet.front()[0]; + unsigned char n = vSolutionsRet.back()[0]; + if (m < 1 || n < 1 || m > n || vSolutionsRet.size()-2 != n) + return false; + } + return true; + } + if (!script1.GetOp(pc1, opcode1, vch1)) + break; + if (!script2.GetOp(pc2, opcode2, vch2)) + break; + + // Template matching opcodes: + if (opcode2 == OP_PUBKEYS) + { + while (vch1.size() >= 33 && vch1.size() <= 120) + { + vSolutionsRet.push_back(vch1); + if (!script1.GetOp(pc1, opcode1, vch1)) + break; + } + if (!script2.GetOp(pc2, opcode2, vch2)) + break; + // Normal situation is to fall through + // to other if/else statements + } + + if (opcode2 == OP_PUBKEY) + { + if (vch1.size() < 33 || vch1.size() > 120) + break; + vSolutionsRet.push_back(vch1); + } + else if (opcode2 == OP_PUBKEYHASH) + { + if (vch1.size() != sizeof(uint160)) + break; + vSolutionsRet.push_back(vch1); + } + else if (opcode2 == OP_SMALLINTEGER) + { // Single-byte small integer pushed onto vSolutions + if (opcode1 == OP_0 || + (opcode1 >= OP_1 && opcode1 <= OP_16)) + { + char n = (char)CScript::DecodeOP_N(opcode1); + vSolutionsRet.push_back(valtype(1, n)); + } + else + break; + } + else if (opcode1 != opcode2 || vch1 != vch2) + { + // Others must match exactly + break; + } + } + } + + vSolutionsRet.clear(); + typeRet = TX_NONSTANDARD; + return false; +} + + +bool Sign1(const CKeyID& address, const CKeyStore& keystore, uint256 hash, int nHashType, CScript& scriptSigRet) +{ + CKey key; + if (!keystore.GetKey(address, key)) + return false; + + vector vchSig; + if (!key.Sign(hash, vchSig)) + return false; + vchSig.push_back((unsigned char)nHashType); + scriptSigRet << vchSig; + + return true; +} + +bool SignN(const vector& multisigdata, const CKeyStore& keystore, uint256 hash, int nHashType, CScript& scriptSigRet) +{ + int nSigned = 0; + int nRequired = multisigdata.front()[0]; + for (unsigned int i = 1; i < multisigdata.size()-1 && nSigned < nRequired; i++) + { + const valtype& pubkey = multisigdata[i]; + CKeyID keyID = CPubKey(pubkey).GetID(); + if (Sign1(keyID, keystore, hash, nHashType, scriptSigRet)) + ++nSigned; + } + return nSigned==nRequired; +} + +// +// Sign scriptPubKey with private keys stored in keystore, given transaction hash and hash type. +// Signatures are returned in scriptSigRet (or returns false if scriptPubKey can't be signed), +// unless whichTypeRet is TX_SCRIPTHASH, in which case scriptSigRet is the redemption script. +// Returns false if scriptPubKey could not be completely satisfied. +// +bool Solver(const CKeyStore& keystore, const CScript& scriptPubKey, uint256 hash, int nHashType, + CScript& scriptSigRet, txnouttype& whichTypeRet) +{ + scriptSigRet.clear(); + + vector vSolutions; + if (!Solver(scriptPubKey, whichTypeRet, vSolutions)) + return false; + + CKeyID keyID; + switch (whichTypeRet) + { + case TX_NONSTANDARD: + return false; + case TX_PUBKEY: + keyID = CPubKey(vSolutions[0]).GetID(); + return Sign1(keyID, keystore, hash, nHashType, scriptSigRet); + case TX_PUBKEYHASH: + keyID = CKeyID(uint160(vSolutions[0])); + if (!Sign1(keyID, keystore, hash, nHashType, scriptSigRet)) + return false; + else + { + CPubKey vch; + keystore.GetPubKey(keyID, vch); + scriptSigRet << vch; + } + return true; + case TX_SCRIPTHASH: + return keystore.GetCScript(uint160(vSolutions[0]), scriptSigRet); + + case TX_MULTISIG: + scriptSigRet << OP_0; // workaround CHECKMULTISIG bug + return (SignN(vSolutions, keystore, hash, nHashType, scriptSigRet)); + } + return false; +} + +int ScriptSigArgsExpected(txnouttype t, const std::vector >& vSolutions) +{ + switch (t) + { + case TX_NONSTANDARD: + return -1; + case TX_PUBKEY: + return 1; + case TX_PUBKEYHASH: + return 2; + case TX_MULTISIG: + if (vSolutions.size() < 1 || vSolutions[0].size() < 1) + return -1; + return vSolutions[0][0] + 1; + case TX_SCRIPTHASH: + return 1; // doesn't include args needed by the script + } + return -1; +} + +bool IsStandard(const CScript& scriptPubKey) +{ + vector vSolutions; + txnouttype whichType; + if (!Solver(scriptPubKey, whichType, vSolutions)) + return false; + + if (whichType == TX_MULTISIG) + { + unsigned char m = vSolutions.front()[0]; + unsigned char n = vSolutions.back()[0]; + // Support up to x-of-3 multisig txns as standard + if (n < 1 || n > 3) + return false; + if (m < 1 || m > n) + return false; + } + + return whichType != TX_NONSTANDARD; +} + + +unsigned int HaveKeys(const vector& pubkeys, const CKeyStore& keystore) +{ + unsigned int nResult = 0; + BOOST_FOREACH(const valtype& pubkey, pubkeys) + { + CKeyID keyID = CPubKey(pubkey).GetID(); + if (keystore.HaveKey(keyID)) + ++nResult; + } + return nResult; +} + + +class CKeyStoreIsMineVisitor : public boost::static_visitor +{ +private: + const CKeyStore *keystore; +public: + CKeyStoreIsMineVisitor(const CKeyStore *keystoreIn) : keystore(keystoreIn) { } + bool operator()(const CNoDestination &dest) const { return false; } + bool operator()(const CKeyID &keyID) const { return keystore->HaveKey(keyID); } + bool operator()(const CScriptID &scriptID) const { return keystore->HaveCScript(scriptID); } +}; + +bool IsMine(const CKeyStore &keystore, const CTxDestination &dest) +{ + return boost::apply_visitor(CKeyStoreIsMineVisitor(&keystore), dest); +} + +bool IsMine(const CKeyStore &keystore, const CScript& scriptPubKey) +{ + vector vSolutions; + txnouttype whichType; + if (!Solver(scriptPubKey, whichType, vSolutions)) + return false; + + CKeyID keyID; + switch (whichType) + { + case TX_NONSTANDARD: + return false; + case TX_PUBKEY: + keyID = CPubKey(vSolutions[0]).GetID(); + return keystore.HaveKey(keyID); + case TX_PUBKEYHASH: + keyID = CKeyID(uint160(vSolutions[0])); + return keystore.HaveKey(keyID); + case TX_SCRIPTHASH: + { + CScript subscript; + if (!keystore.GetCScript(CScriptID(uint160(vSolutions[0])), subscript)) + return false; + return IsMine(keystore, subscript); + } + case TX_MULTISIG: + { + // Only consider transactions "mine" if we own ALL the + // keys involved. multi-signature transactions that are + // partially owned (somebody else has a key that can spend + // them) enable spend-out-from-under-you attacks, especially + // in shared-wallet situations. + vector keys(vSolutions.begin()+1, vSolutions.begin()+vSolutions.size()-1); + return HaveKeys(keys, keystore) == keys.size(); + } + } + return false; +} + +bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet) +{ + vector vSolutions; + txnouttype whichType; + if (!Solver(scriptPubKey, whichType, vSolutions)) + return false; + + if (whichType == TX_PUBKEY) + { + addressRet = CPubKey(vSolutions[0]).GetID(); + return true; + } + else if (whichType == TX_PUBKEYHASH) + { + addressRet = CKeyID(uint160(vSolutions[0])); + return true; + } + else if (whichType == TX_SCRIPTHASH) + { + addressRet = CScriptID(uint160(vSolutions[0])); + return true; + } + // Multisig txns have more than one address... + return false; +} + +bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, vector& addressRet, int& nRequiredRet) +{ + addressRet.clear(); + typeRet = TX_NONSTANDARD; + vector vSolutions; + if (!Solver(scriptPubKey, typeRet, vSolutions)) + return false; + + if (typeRet == TX_MULTISIG) + { + nRequiredRet = vSolutions.front()[0]; + for (unsigned int i = 1; i < vSolutions.size()-1; i++) + { + CTxDestination address = CPubKey(vSolutions[i]).GetID(); + addressRet.push_back(address); + } + } + else + { + nRequiredRet = 1; + CTxDestination address; + if (!ExtractDestination(scriptPubKey, address)) + return false; + addressRet.push_back(address); + } + + return true; +} + +bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn, + bool fValidatePayToScriptHash, int nHashType) +{ + vector > stack, stackCopy; + if (!EvalScript(stack, scriptSig, txTo, nIn, nHashType)) + return false; + if (fValidatePayToScriptHash) + stackCopy = stack; + if (!EvalScript(stack, scriptPubKey, txTo, nIn, nHashType)) + return false; + if (stack.empty()) + return false; + + if (CastToBool(stack.back()) == false) + return false; + + // Additional validation for spend-to-script-hash transactions: + if (fValidatePayToScriptHash && scriptPubKey.IsPayToScriptHash()) + { + if (!scriptSig.IsPushOnly()) // scriptSig must be literals-only + return false; // or validation fails + + const valtype& pubKeySerialized = stackCopy.back(); + CScript pubKey2(pubKeySerialized.begin(), pubKeySerialized.end()); + popstack(stackCopy); + + if (!EvalScript(stackCopy, pubKey2, txTo, nIn, nHashType)) + return false; + if (stackCopy.empty()) + return false; + return CastToBool(stackCopy.back()); + } + + return true; +} + + +bool SignSignature(const CKeyStore &keystore, const CScript& fromPubKey, CTransaction& txTo, unsigned int nIn, int nHashType) +{ + assert(nIn < txTo.vin.size()); + CTxIn& txin = txTo.vin[nIn]; + + // Leave out the signature from the hash, since a signature can't sign itself. + // The checksig op will also drop the signatures from its hash. + uint256 hash = SignatureHash(fromPubKey, txTo, nIn, nHashType); + + txnouttype whichType; + if (!Solver(keystore, fromPubKey, hash, nHashType, txin.scriptSig, whichType)) + return false; + + if (whichType == TX_SCRIPTHASH) + { + // Solver returns the subscript that need to be evaluated; + // the final scriptSig is the signatures from that + // and then the serialized subscript: + CScript subscript = txin.scriptSig; + + // Recompute txn hash using subscript in place of scriptPubKey: + uint256 hash2 = SignatureHash(subscript, txTo, nIn, nHashType); + + txnouttype subType; + bool fSolved = + Solver(keystore, subscript, hash2, nHashType, txin.scriptSig, subType) && subType != TX_SCRIPTHASH; + // Append serialized subscript whether or not it is completely signed: + txin.scriptSig << static_cast(subscript); + if (!fSolved) return false; + } + + // Test solution + return VerifyScript(txin.scriptSig, fromPubKey, txTo, nIn, true, 0); +} + +bool SignSignature(const CKeyStore &keystore, const CTransaction& txFrom, CTransaction& txTo, unsigned int nIn, int nHashType) +{ + assert(nIn < txTo.vin.size()); + CTxIn& txin = txTo.vin[nIn]; + assert(txin.prevout.n < txFrom.vout.size()); + assert(txin.prevout.hash == txFrom.GetHash()); + const CTxOut& txout = txFrom.vout[txin.prevout.n]; + + return SignSignature(keystore, txout.scriptPubKey, txTo, nIn, nHashType); +} + +bool VerifySignature(const CTransaction& txFrom, const CTransaction& txTo, unsigned int nIn, bool fValidatePayToScriptHash, int nHashType) +{ + assert(nIn < txTo.vin.size()); + const CTxIn& txin = txTo.vin[nIn]; + if (txin.prevout.n >= txFrom.vout.size()) + return false; + const CTxOut& txout = txFrom.vout[txin.prevout.n]; + + if (txin.prevout.hash != txFrom.GetHash()) + return false; + + return VerifyScript(txin.scriptSig, txout.scriptPubKey, txTo, nIn, fValidatePayToScriptHash, nHashType); +} + +static CScript PushAll(const vector& values) +{ + CScript result; + BOOST_FOREACH(const valtype& v, values) + result << v; + return result; +} + +static CScript CombineMultisig(CScript scriptPubKey, const CTransaction& txTo, unsigned int nIn, + const vector& vSolutions, + vector& sigs1, vector& sigs2) +{ + // Combine all the signatures we've got: + set allsigs; + BOOST_FOREACH(const valtype& v, sigs1) + { + if (!v.empty()) + allsigs.insert(v); + } + BOOST_FOREACH(const valtype& v, sigs2) + { + if (!v.empty()) + allsigs.insert(v); + } + + // Build a map of pubkey -> signature by matching sigs to pubkeys: + assert(vSolutions.size() > 1); + unsigned int nSigsRequired = vSolutions.front()[0]; + unsigned int nPubKeys = vSolutions.size()-2; + map sigs; + BOOST_FOREACH(const valtype& sig, allsigs) + { + for (unsigned int i = 0; i < nPubKeys; i++) + { + const valtype& pubkey = vSolutions[i+1]; + if (sigs.count(pubkey)) + continue; // Already got a sig for this pubkey + + if (CheckSig(sig, pubkey, scriptPubKey, txTo, nIn, 0)) + { + sigs[pubkey] = sig; + break; + } + } + } + // Now build a merged CScript: + unsigned int nSigsHave = 0; + CScript result; result << OP_0; // pop-one-too-many workaround + for (unsigned int i = 0; i < nPubKeys && nSigsHave < nSigsRequired; i++) + { + if (sigs.count(vSolutions[i+1])) + { + result << sigs[vSolutions[i+1]]; + ++nSigsHave; + } + } + // Fill any missing with OP_0: + for (unsigned int i = nSigsHave; i < nSigsRequired; i++) + result << OP_0; + + return result; +} + +static CScript CombineSignatures(CScript scriptPubKey, const CTransaction& txTo, unsigned int nIn, + const txnouttype txType, const vector& vSolutions, + vector& sigs1, vector& sigs2) +{ + switch (txType) + { + case TX_NONSTANDARD: + // Don't know anything about this, assume bigger one is correct: + if (sigs1.size() >= sigs2.size()) + return PushAll(sigs1); + return PushAll(sigs2); + case TX_PUBKEY: + case TX_PUBKEYHASH: + // Signatures are bigger than placeholders or empty scripts: + if (sigs1.empty() || sigs1[0].empty()) + return PushAll(sigs2); + return PushAll(sigs1); + case TX_SCRIPTHASH: + if (sigs1.empty() || sigs1.back().empty()) + return PushAll(sigs2); + else if (sigs2.empty() || sigs2.back().empty()) + return PushAll(sigs1); + else + { + // Recur to combine: + valtype spk = sigs1.back(); + CScript pubKey2(spk.begin(), spk.end()); + + txnouttype txType2; + vector > vSolutions2; + Solver(pubKey2, txType2, vSolutions2); + sigs1.pop_back(); + sigs2.pop_back(); + CScript result = CombineSignatures(pubKey2, txTo, nIn, txType2, vSolutions2, sigs1, sigs2); + result << spk; + return result; + } + case TX_MULTISIG: + return CombineMultisig(scriptPubKey, txTo, nIn, vSolutions, sigs1, sigs2); + } + + return CScript(); +} + +CScript CombineSignatures(CScript scriptPubKey, const CTransaction& txTo, unsigned int nIn, + const CScript& scriptSig1, const CScript& scriptSig2) +{ + txnouttype txType; + vector > vSolutions; + Solver(scriptPubKey, txType, vSolutions); + + vector stack1; + EvalScript(stack1, scriptSig1, CTransaction(), 0, 0); + vector stack2; + EvalScript(stack2, scriptSig2, CTransaction(), 0, 0); + + return CombineSignatures(scriptPubKey, txTo, nIn, txType, vSolutions, stack1, stack2); +} + +unsigned int CScript::GetSigOpCount(bool fAccurate) const +{ + unsigned int n = 0; + const_iterator pc = begin(); + opcodetype lastOpcode = OP_INVALIDOPCODE; + while (pc < end()) + { + opcodetype opcode; + if (!GetOp(pc, opcode)) + break; + if (opcode == OP_CHECKSIG || opcode == OP_CHECKSIGVERIFY) + n++; + else if (opcode == OP_CHECKMULTISIG || opcode == OP_CHECKMULTISIGVERIFY) + { + if (fAccurate && lastOpcode >= OP_1 && lastOpcode <= OP_16) + n += DecodeOP_N(lastOpcode); + else + n += 20; + } + lastOpcode = opcode; + } + return n; +} + +unsigned int CScript::GetSigOpCount(const CScript& scriptSig) const +{ + if (!IsPayToScriptHash()) + return GetSigOpCount(true); + + // This is a pay-to-script-hash scriptPubKey; + // get the last item that the scriptSig + // pushes onto the stack: + const_iterator pc = scriptSig.begin(); + vector data; + while (pc < scriptSig.end()) + { + opcodetype opcode; + if (!scriptSig.GetOp(pc, opcode, data)) + return 0; + if (opcode > OP_16) + return 0; + } + + /// ... and return its opcount: + CScript subscript(data.begin(), data.end()); + return subscript.GetSigOpCount(true); +} + +bool CScript::IsPayToScriptHash() const +{ + // Extra-fast test for pay-to-script-hash CScripts: + return (this->size() == 23 && + this->at(0) == OP_HASH160 && + this->at(1) == 0x14 && + this->at(22) == OP_EQUAL); +} + +class CScriptVisitor : public boost::static_visitor +{ +private: + CScript *script; +public: + CScriptVisitor(CScript *scriptin) { script = scriptin; } + + bool operator()(const CNoDestination &dest) const { + script->clear(); + return false; + } + + bool operator()(const CKeyID &keyID) const { + script->clear(); + *script << OP_DUP << OP_HASH160 << keyID << OP_EQUALVERIFY << OP_CHECKSIG; + return true; + } + + bool operator()(const CScriptID &scriptID) const { + script->clear(); + *script << OP_HASH160 << scriptID << OP_EQUAL; + return true; + } +}; + +void CScript::SetDestination(const CTxDestination& dest) +{ + boost::apply_visitor(CScriptVisitor(this), dest); +} + +void CScript::SetMultisig(int nRequired, const std::vector& keys) +{ + this->clear(); + + *this << EncodeOP_N(nRequired); + BOOST_FOREACH(const CKey& key, keys) + *this << key.GetPubKey(); + *this << EncodeOP_N(keys.size()) << OP_CHECKMULTISIG; +} diff --git a/src/script.h b/src/script.h new file mode 100644 index 0000000..99465cb --- /dev/null +++ b/src/script.h @@ -0,0 +1,606 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2012 The Bitcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. +#ifndef H_BITCOIN_SCRIPT +#define H_BITCOIN_SCRIPT + +#include +#include + +#include +#include + +#include "keystore.h" +#include "bignum.h" + +typedef std::vector valtype; + +class CTransaction; + +/** Signature hash types/flags */ +enum +{ + SIGHASH_ALL = 1, + SIGHASH_NONE = 2, + SIGHASH_SINGLE = 3, + SIGHASH_ANYONECANPAY = 0x80, +}; + + +enum txnouttype +{ + TX_NONSTANDARD, + // 'standard' transaction types: + TX_PUBKEY, + TX_PUBKEYHASH, + TX_SCRIPTHASH, + TX_MULTISIG, +}; + +class CNoDestination { +public: + friend bool operator==(const CNoDestination &a, const CNoDestination &b) { return true; } + friend bool operator<(const CNoDestination &a, const CNoDestination &b) { return true; } +}; + +/** A txout script template with a specific destination. It is either: + * * CNoDestination: no destination set + * * CKeyID: TX_PUBKEYHASH destination + * * CScriptID: TX_SCRIPTHASH destination + * A CTxDestination is the internal data type encoded in a CBitcoinAddress + */ +typedef boost::variant CTxDestination; + +const char* GetTxnOutputType(txnouttype t); + +/** Script opcodes */ +enum opcodetype +{ + // push value + OP_0 = 0x00, + OP_FALSE = OP_0, + OP_PUSHDATA1 = 0x4c, + OP_PUSHDATA2 = 0x4d, + OP_PUSHDATA4 = 0x4e, + OP_1NEGATE = 0x4f, + OP_RESERVED = 0x50, + OP_1 = 0x51, + OP_TRUE=OP_1, + OP_2 = 0x52, + OP_3 = 0x53, + OP_4 = 0x54, + OP_5 = 0x55, + OP_6 = 0x56, + OP_7 = 0x57, + OP_8 = 0x58, + OP_9 = 0x59, + OP_10 = 0x5a, + OP_11 = 0x5b, + OP_12 = 0x5c, + OP_13 = 0x5d, + OP_14 = 0x5e, + OP_15 = 0x5f, + OP_16 = 0x60, + + // control + OP_NOP = 0x61, + OP_VER = 0x62, + OP_IF = 0x63, + OP_NOTIF = 0x64, + OP_VERIF = 0x65, + OP_VERNOTIF = 0x66, + OP_ELSE = 0x67, + OP_ENDIF = 0x68, + OP_VERIFY = 0x69, + OP_RETURN = 0x6a, + + // stack ops + OP_TOALTSTACK = 0x6b, + OP_FROMALTSTACK = 0x6c, + OP_2DROP = 0x6d, + OP_2DUP = 0x6e, + OP_3DUP = 0x6f, + OP_2OVER = 0x70, + OP_2ROT = 0x71, + OP_2SWAP = 0x72, + OP_IFDUP = 0x73, + OP_DEPTH = 0x74, + OP_DROP = 0x75, + OP_DUP = 0x76, + OP_NIP = 0x77, + OP_OVER = 0x78, + OP_PICK = 0x79, + OP_ROLL = 0x7a, + OP_ROT = 0x7b, + OP_SWAP = 0x7c, + OP_TUCK = 0x7d, + + // splice ops + OP_CAT = 0x7e, + OP_SUBSTR = 0x7f, + OP_LEFT = 0x80, + OP_RIGHT = 0x81, + OP_SIZE = 0x82, + + // bit logic + OP_INVERT = 0x83, + OP_AND = 0x84, + OP_OR = 0x85, + OP_XOR = 0x86, + OP_EQUAL = 0x87, + OP_EQUALVERIFY = 0x88, + OP_RESERVED1 = 0x89, + OP_RESERVED2 = 0x8a, + + // numeric + OP_1ADD = 0x8b, + OP_1SUB = 0x8c, + OP_2MUL = 0x8d, + OP_2DIV = 0x8e, + OP_NEGATE = 0x8f, + OP_ABS = 0x90, + OP_NOT = 0x91, + OP_0NOTEQUAL = 0x92, + + OP_ADD = 0x93, + OP_SUB = 0x94, + OP_MUL = 0x95, + OP_DIV = 0x96, + OP_MOD = 0x97, + OP_LSHIFT = 0x98, + OP_RSHIFT = 0x99, + + OP_BOOLAND = 0x9a, + OP_BOOLOR = 0x9b, + OP_NUMEQUAL = 0x9c, + OP_NUMEQUALVERIFY = 0x9d, + OP_NUMNOTEQUAL = 0x9e, + OP_LESSTHAN = 0x9f, + OP_GREATERTHAN = 0xa0, + OP_LESSTHANOREQUAL = 0xa1, + OP_GREATERTHANOREQUAL = 0xa2, + OP_MIN = 0xa3, + OP_MAX = 0xa4, + + OP_WITHIN = 0xa5, + + // crypto + OP_RIPEMD160 = 0xa6, + OP_SHA1 = 0xa7, + OP_SHA256 = 0xa8, + OP_HASH160 = 0xa9, + OP_HASH256 = 0xaa, + OP_CODESEPARATOR = 0xab, + OP_CHECKSIG = 0xac, + OP_CHECKSIGVERIFY = 0xad, + OP_CHECKMULTISIG = 0xae, + OP_CHECKMULTISIGVERIFY = 0xaf, + + // expansion + OP_NOP1 = 0xb0, + OP_NOP2 = 0xb1, + OP_NOP3 = 0xb2, + OP_NOP4 = 0xb3, + OP_NOP5 = 0xb4, + OP_NOP6 = 0xb5, + OP_NOP7 = 0xb6, + OP_NOP8 = 0xb7, + OP_NOP9 = 0xb8, + OP_NOP10 = 0xb9, + + + + // template matching params + OP_SMALLINTEGER = 0xfa, + OP_PUBKEYS = 0xfb, + OP_PUBKEYHASH = 0xfd, + OP_PUBKEY = 0xfe, + + OP_INVALIDOPCODE = 0xff, +}; + +const char* GetOpName(opcodetype opcode); + + + +inline std::string ValueString(const std::vector& vch) +{ + if (vch.size() <= 4) + return strprintf("%d", CBigNum(vch).getint()); + else + return HexStr(vch); +} + +inline std::string StackString(const std::vector >& vStack) +{ + std::string str; + BOOST_FOREACH(const std::vector& vch, vStack) + { + if (!str.empty()) + str += " "; + str += ValueString(vch); + } + return str; +} + + + + + + + + +/** Serialized script, used inside transaction inputs and outputs */ +class CScript : public std::vector +{ +protected: + CScript& push_int64(int64 n) + { + if (n == -1 || (n >= 1 && n <= 16)) + { + push_back(n + (OP_1 - 1)); + } + else + { + CBigNum bn(n); + *this << bn.getvch(); + } + return *this; + } + + CScript& push_uint64(uint64 n) + { + if (n >= 1 && n <= 16) + { + push_back(n + (OP_1 - 1)); + } + else + { + CBigNum bn(n); + *this << bn.getvch(); + } + return *this; + } + +public: + CScript() { } + CScript(const CScript& b) : std::vector(b.begin(), b.end()) { } + CScript(const_iterator pbegin, const_iterator pend) : std::vector(pbegin, pend) { } +#ifndef _MSC_VER + CScript(const unsigned char* pbegin, const unsigned char* pend) : std::vector(pbegin, pend) { } +#endif + + CScript& operator+=(const CScript& b) + { + insert(end(), b.begin(), b.end()); + return *this; + } + + friend CScript operator+(const CScript& a, const CScript& b) + { + CScript ret = a; + ret += b; + return ret; + } + + + //explicit CScript(char b) is not portable. Use 'signed char' or 'unsigned char'. + explicit CScript(signed char b) { operator<<(b); } + explicit CScript(short b) { operator<<(b); } + explicit CScript(int b) { operator<<(b); } + explicit CScript(long b) { operator<<(b); } + explicit CScript(int64 b) { operator<<(b); } + explicit CScript(unsigned char b) { operator<<(b); } + explicit CScript(unsigned int b) { operator<<(b); } + explicit CScript(unsigned short b) { operator<<(b); } + explicit CScript(unsigned long b) { operator<<(b); } + explicit CScript(uint64 b) { operator<<(b); } + + explicit CScript(opcodetype b) { operator<<(b); } + explicit CScript(const uint256& b) { operator<<(b); } + explicit CScript(const CBigNum& b) { operator<<(b); } + explicit CScript(const std::vector& b) { operator<<(b); } + + + //CScript& operator<<(char b) is not portable. Use 'signed char' or 'unsigned char'. + CScript& operator<<(signed char b) { return push_int64(b); } + CScript& operator<<(short b) { return push_int64(b); } + CScript& operator<<(int b) { return push_int64(b); } + CScript& operator<<(long b) { return push_int64(b); } + CScript& operator<<(int64 b) { return push_int64(b); } + CScript& operator<<(unsigned char b) { return push_uint64(b); } + CScript& operator<<(unsigned int b) { return push_uint64(b); } + CScript& operator<<(unsigned short b) { return push_uint64(b); } + CScript& operator<<(unsigned long b) { return push_uint64(b); } + CScript& operator<<(uint64 b) { return push_uint64(b); } + + CScript& operator<<(opcodetype opcode) + { + if (opcode < 0 || opcode > 0xff) + throw std::runtime_error("CScript::operator<<() : invalid opcode"); + insert(end(), (unsigned char)opcode); + return *this; + } + + CScript& operator<<(const uint160& b) + { + insert(end(), sizeof(b)); + insert(end(), (unsigned char*)&b, (unsigned char*)&b + sizeof(b)); + return *this; + } + + CScript& operator<<(const uint256& b) + { + insert(end(), sizeof(b)); + insert(end(), (unsigned char*)&b, (unsigned char*)&b + sizeof(b)); + return *this; + } + + CScript& operator<<(const CPubKey& key) + { + std::vector vchKey = key.Raw(); + return (*this) << vchKey; + } + + CScript& operator<<(const CBigNum& b) + { + *this << b.getvch(); + return *this; + } + + CScript& operator<<(const std::vector& b) + { + if (b.size() < OP_PUSHDATA1) + { + insert(end(), (unsigned char)b.size()); + } + else if (b.size() <= 0xff) + { + insert(end(), OP_PUSHDATA1); + insert(end(), (unsigned char)b.size()); + } + else if (b.size() <= 0xffff) + { + insert(end(), OP_PUSHDATA2); + unsigned short nSize = b.size(); + insert(end(), (unsigned char*)&nSize, (unsigned char*)&nSize + sizeof(nSize)); + } + else + { + insert(end(), OP_PUSHDATA4); + unsigned int nSize = b.size(); + insert(end(), (unsigned char*)&nSize, (unsigned char*)&nSize + sizeof(nSize)); + } + insert(end(), b.begin(), b.end()); + return *this; + } + + CScript& operator<<(const CScript& b) + { + // I'm not sure if this should push the script or concatenate scripts. + // If there's ever a use for pushing a script onto a script, delete this member fn + assert(!"Warning: Pushing a CScript onto a CScript with << is probably not intended, use + to concatenate!"); + return *this; + } + + + bool GetOp(iterator& pc, opcodetype& opcodeRet, std::vector& vchRet) + { + // Wrapper so it can be called with either iterator or const_iterator + const_iterator pc2 = pc; + bool fRet = GetOp2(pc2, opcodeRet, &vchRet); + pc = begin() + (pc2 - begin()); + return fRet; + } + + bool GetOp(iterator& pc, opcodetype& opcodeRet) + { + const_iterator pc2 = pc; + bool fRet = GetOp2(pc2, opcodeRet, NULL); + pc = begin() + (pc2 - begin()); + return fRet; + } + + bool GetOp(const_iterator& pc, opcodetype& opcodeRet, std::vector& vchRet) const + { + return GetOp2(pc, opcodeRet, &vchRet); + } + + bool GetOp(const_iterator& pc, opcodetype& opcodeRet) const + { + return GetOp2(pc, opcodeRet, NULL); + } + + bool GetOp2(const_iterator& pc, opcodetype& opcodeRet, std::vector* pvchRet) const + { + opcodeRet = OP_INVALIDOPCODE; + if (pvchRet) + pvchRet->clear(); + if (pc >= end()) + return false; + + // Read instruction + if (end() - pc < 1) + return false; + unsigned int opcode = *pc++; + + // Immediate operand + if (opcode <= OP_PUSHDATA4) + { + unsigned int nSize; + if (opcode < OP_PUSHDATA1) + { + nSize = opcode; + } + else if (opcode == OP_PUSHDATA1) + { + if (end() - pc < 1) + return false; + nSize = *pc++; + } + else if (opcode == OP_PUSHDATA2) + { + if (end() - pc < 2) + return false; + nSize = 0; + memcpy(&nSize, &pc[0], 2); + pc += 2; + } + else if (opcode == OP_PUSHDATA4) + { + if (end() - pc < 4) + return false; + memcpy(&nSize, &pc[0], 4); + pc += 4; + } + if (end() - pc < 0 || (unsigned int)(end() - pc) < nSize) + return false; + if (pvchRet) + pvchRet->assign(pc, pc + nSize); + pc += nSize; + } + + opcodeRet = (opcodetype)opcode; + return true; + } + + // Encode/decode small integers: + static int DecodeOP_N(opcodetype opcode) + { + if (opcode == OP_0) + return 0; + assert(opcode >= OP_1 && opcode <= OP_16); + return (int)opcode - (int)(OP_1 - 1); + } + static opcodetype EncodeOP_N(int n) + { + assert(n >= 0 && n <= 16); + if (n == 0) + return OP_0; + return (opcodetype)(OP_1+n-1); + } + + int FindAndDelete(const CScript& b) + { + int nFound = 0; + if (b.empty()) + return nFound; + iterator pc = begin(); + opcodetype opcode; + do + { + while (end() - pc >= (long)b.size() && memcmp(&pc[0], &b[0], b.size()) == 0) + { + erase(pc, pc + b.size()); + ++nFound; + } + } + while (GetOp(pc, opcode)); + return nFound; + } + int Find(opcodetype op) const + { + int nFound = 0; + opcodetype opcode; + for (const_iterator pc = begin(); pc != end() && GetOp(pc, opcode);) + if (opcode == op) + ++nFound; + return nFound; + } + + // Pre-version-0.6, Bitcoin always counted CHECKMULTISIGs + // as 20 sigops. With pay-to-script-hash, that changed: + // CHECKMULTISIGs serialized in scriptSigs are + // counted more accurately, assuming they are of the form + // ... OP_N CHECKMULTISIG ... + unsigned int GetSigOpCount(bool fAccurate) const; + + // Accurately count sigOps, including sigOps in + // pay-to-script-hash transactions: + unsigned int GetSigOpCount(const CScript& scriptSig) const; + + bool IsPayToScriptHash() const; + + // Called by CTransaction::IsStandard + bool IsPushOnly() const + { + const_iterator pc = begin(); + while (pc < end()) + { + opcodetype opcode; + if (!GetOp(pc, opcode)) + return false; + if (opcode > OP_16) + return false; + } + return true; + } + + + void SetDestination(const CTxDestination& address); + void SetMultisig(int nRequired, const std::vector& keys); + + + void PrintHex() const + { + printf("CScript(%s)\n", HexStr(begin(), end(), true).c_str()); + } + + std::string ToString(bool fShort=false) const + { + std::string str; + opcodetype opcode; + std::vector vch; + const_iterator pc = begin(); + while (pc < end()) + { + if (!str.empty()) + str += " "; + if (!GetOp(pc, opcode, vch)) + { + str += "[error]"; + return str; + } + if (0 <= opcode && opcode <= OP_PUSHDATA4) + str += fShort? ValueString(vch).substr(0, 10) : ValueString(vch); + else + str += GetOpName(opcode); + } + return str; + } + + void print() const + { + printf("%s\n", ToString().c_str()); + } + + CScriptID GetID() const + { + return CScriptID(Hash160(*this)); + } +}; + + + + + +bool EvalScript(std::vector >& stack, const CScript& script, const CTransaction& txTo, unsigned int nIn, int nHashType); +bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, std::vector >& vSolutionsRet); +int ScriptSigArgsExpected(txnouttype t, const std::vector >& vSolutions); +bool IsStandard(const CScript& scriptPubKey); +bool IsMine(const CKeyStore& keystore, const CScript& scriptPubKey); +bool IsMine(const CKeyStore& keystore, const CTxDestination &dest); +bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet); +bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, std::vector& addressRet, int& nRequiredRet); +bool SignSignature(const CKeyStore& keystore, const CScript& fromPubKey, CTransaction& txTo, unsigned int nIn, int nHashType=SIGHASH_ALL); +bool SignSignature(const CKeyStore& keystore, const CTransaction& txFrom, CTransaction& txTo, unsigned int nIn, int nHashType=SIGHASH_ALL); +bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn, + bool fValidatePayToScriptHash, int nHashType); +bool VerifySignature(const CTransaction& txFrom, const CTransaction& txTo, unsigned int nIn, bool fValidatePayToScriptHash, int nHashType); + +// Given two sets of signatures for scriptPubKey, possibly with OP_0 placeholders, +// combine them intelligently and return the result. +CScript CombineSignatures(CScript scriptPubKey, const CTransaction& txTo, unsigned int nIn, const CScript& scriptSig1, const CScript& scriptSig2); + +#endif diff --git a/src/scrypt-x86.S b/src/scrypt-x86.S new file mode 100644 index 0000000..6a4465c --- /dev/null +++ b/src/scrypt-x86.S @@ -0,0 +1,908 @@ +# Copyright 2011 pooler@litecoinpool.org +# 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. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + +#if defined(__i386__) + +#define gen_salsa8_core_quadround() \ + movl 52(%esp), %ecx; \ + movl 4(%esp), %edx; \ + movl 20(%esp), %ebx; \ + movl 8(%esp), %esi; \ + leal (%ecx, %edx), %edi; \ + roll $7, %edi; \ + xorl %edi, %ebx; \ + movl %ebx, 4(%esp); \ + movl 36(%esp), %edi; \ + leal (%edx, %ebx), %ebp; \ + roll $9, %ebp; \ + xorl %ebp, %edi; \ + movl 24(%esp), %ebp; \ + movl %edi, 8(%esp); \ + addl %edi, %ebx; \ + roll $13, %ebx; \ + xorl %ebx, %ecx; \ + movl 40(%esp), %ebx; \ + movl %ecx, 20(%esp); \ + addl %edi, %ecx; \ + roll $18, %ecx; \ + leal (%esi, %ebp), %edi; \ + roll $7, %edi; \ + xorl %edi, %ebx; \ + movl %ebx, 24(%esp); \ + movl 56(%esp), %edi; \ + xorl %ecx, %edx; \ + leal (%ebp, %ebx), %ecx; \ + roll $9, %ecx; \ + xorl %ecx, %edi; \ + movl %edi, 36(%esp); \ + movl 28(%esp), %ecx; \ + movl %edx, 28(%esp); \ + movl 44(%esp), %edx; \ + addl %edi, %ebx; \ + roll $13, %ebx; \ + xorl %ebx, %esi; \ + movl 60(%esp), %ebx; \ + movl %esi, 40(%esp); \ + addl %edi, %esi; \ + roll $18, %esi; \ + leal (%ecx, %edx), %edi; \ + roll $7, %edi; \ + xorl %edi, %ebx; \ + movl %ebx, 44(%esp); \ + movl 12(%esp), %edi; \ + xorl %esi, %ebp; \ + leal (%edx, %ebx), %esi; \ + roll $9, %esi; \ + xorl %esi, %edi; \ + movl %edi, 12(%esp); \ + movl 48(%esp), %esi; \ + movl %ebp, 48(%esp); \ + movl 64(%esp), %ebp; \ + addl %edi, %ebx; \ + roll $13, %ebx; \ + xorl %ebx, %ecx; \ + movl 16(%esp), %ebx; \ + movl %ecx, 16(%esp); \ + addl %edi, %ecx; \ + roll $18, %ecx; \ + leal (%esi, %ebp), %edi; \ + roll $7, %edi; \ + xorl %edi, %ebx; \ + movl 32(%esp), %edi; \ + xorl %ecx, %edx; \ + leal (%ebp, %ebx), %ecx; \ + roll $9, %ecx; \ + xorl %ecx, %edi; \ + movl %edi, 32(%esp); \ + movl %ebx, %ecx; \ + movl %edx, 52(%esp); \ + movl 28(%esp), %edx; \ + addl %edi, %ebx; \ + roll $13, %ebx; \ + xorl %ebx, %esi; \ + movl 40(%esp), %ebx; \ + movl %esi, 28(%esp); \ + addl %edi, %esi; \ + roll $18, %esi; \ + leal (%ecx, %edx), %edi; \ + roll $7, %edi; \ + xorl %edi, %ebx; \ + movl %ebx, 40(%esp); \ + movl 12(%esp), %edi; \ + xorl %esi, %ebp; \ + leal (%edx, %ebx), %esi; \ + roll $9, %esi; \ + xorl %esi, %edi; \ + movl %edi, 12(%esp); \ + movl 4(%esp), %esi; \ + movl %ebp, 4(%esp); \ + movl 48(%esp), %ebp; \ + addl %edi, %ebx; \ + roll $13, %ebx; \ + xorl %ebx, %ecx; \ + movl 16(%esp), %ebx; \ + movl %ecx, 16(%esp); \ + addl %edi, %ecx; \ + roll $18, %ecx; \ + leal (%esi, %ebp), %edi; \ + roll $7, %edi; \ + xorl %edi, %ebx; \ + movl %ebx, 48(%esp); \ + movl 32(%esp), %edi; \ + xorl %ecx, %edx; \ + leal (%ebp, %ebx), %ecx; \ + roll $9, %ecx; \ + xorl %ecx, %edi; \ + movl %edi, 32(%esp); \ + movl 24(%esp), %ecx; \ + movl %edx, 24(%esp); \ + movl 52(%esp), %edx; \ + addl %edi, %ebx; \ + roll $13, %ebx; \ + xorl %ebx, %esi; \ + movl 28(%esp), %ebx; \ + movl %esi, 28(%esp); \ + addl %edi, %esi; \ + roll $18, %esi; \ + leal (%ecx, %edx), %edi; \ + roll $7, %edi; \ + xorl %edi, %ebx; \ + movl %ebx, 52(%esp); \ + movl 8(%esp), %edi; \ + xorl %esi, %ebp; \ + leal (%edx, %ebx), %esi; \ + roll $9, %esi; \ + xorl %esi, %edi; \ + movl %edi, 8(%esp); \ + movl 44(%esp), %esi; \ + movl %ebp, 44(%esp); \ + movl 4(%esp), %ebp; \ + addl %edi, %ebx; \ + roll $13, %ebx; \ + xorl %ebx, %ecx; \ + movl 20(%esp), %ebx; \ + movl %ecx, 4(%esp); \ + addl %edi, %ecx; \ + roll $18, %ecx; \ + leal (%esi, %ebp), %edi; \ + roll $7, %edi; \ + xorl %edi, %ebx; \ + movl 36(%esp), %edi; \ + xorl %ecx, %edx; \ + leal (%ebp, %ebx), %ecx; \ + roll $9, %ecx; \ + xorl %ecx, %edi; \ + movl %edi, 20(%esp); \ + movl %ebx, %ecx; \ + movl %edx, 36(%esp); \ + movl 24(%esp), %edx; \ + addl %edi, %ebx; \ + roll $13, %ebx; \ + xorl %ebx, %esi; \ + movl 28(%esp), %ebx; \ + movl %esi, 24(%esp); \ + addl %edi, %esi; \ + roll $18, %esi; \ + leal (%ecx, %edx), %edi; \ + roll $7, %edi; \ + xorl %edi, %ebx; \ + movl %ebx, 28(%esp); \ + xorl %esi, %ebp; \ + movl 8(%esp), %esi; \ + leal (%edx, %ebx), %edi; \ + roll $9, %edi; \ + xorl %edi, %esi; \ + movl 40(%esp), %edi; \ + movl %ebp, 8(%esp); \ + movl 44(%esp), %ebp; \ + movl %esi, 40(%esp); \ + addl %esi, %ebx; \ + roll $13, %ebx; \ + xorl %ebx, %ecx; \ + movl 4(%esp), %ebx; \ + movl %ecx, 44(%esp); \ + addl %esi, %ecx; \ + roll $18, %ecx; \ + leal (%edi, %ebp), %esi; \ + roll $7, %esi; \ + xorl %esi, %ebx; \ + movl %ebx, 4(%esp); \ + movl 20(%esp), %esi; \ + xorl %ecx, %edx; \ + leal (%ebp, %ebx), %ecx; \ + roll $9, %ecx; \ + xorl %ecx, %esi; \ + movl %esi, 56(%esp); \ + movl 48(%esp), %ecx; \ + movl %edx, 20(%esp); \ + movl 36(%esp), %edx; \ + addl %esi, %ebx; \ + roll $13, %ebx; \ + xorl %ebx, %edi; \ + movl 24(%esp), %ebx; \ + movl %edi, 24(%esp); \ + addl %esi, %edi; \ + roll $18, %edi; \ + leal (%ecx, %edx), %esi; \ + roll $7, %esi; \ + xorl %esi, %ebx; \ + movl %ebx, 60(%esp); \ + movl 12(%esp), %esi; \ + xorl %edi, %ebp; \ + leal (%edx, %ebx), %edi; \ + roll $9, %edi; \ + xorl %edi, %esi; \ + movl %esi, 12(%esp); \ + movl 52(%esp), %edi; \ + movl %ebp, 36(%esp); \ + movl 8(%esp), %ebp; \ + addl %esi, %ebx; \ + roll $13, %ebx; \ + xorl %ebx, %ecx; \ + movl 16(%esp), %ebx; \ + movl %ecx, 16(%esp); \ + addl %esi, %ecx; \ + roll $18, %ecx; \ + leal (%edi, %ebp), %esi; \ + roll $7, %esi; \ + xorl %esi, %ebx; \ + movl 32(%esp), %esi; \ + xorl %ecx, %edx; \ + leal (%ebp, %ebx), %ecx; \ + roll $9, %ecx; \ + xorl %ecx, %esi; \ + movl %esi, 32(%esp); \ + movl %ebx, %ecx; \ + movl %edx, 48(%esp); \ + movl 20(%esp), %edx; \ + addl %esi, %ebx; \ + roll $13, %ebx; \ + xorl %ebx, %edi; \ + movl 24(%esp), %ebx; \ + movl %edi, 20(%esp); \ + addl %esi, %edi; \ + roll $18, %edi; \ + leal (%ecx, %edx), %esi; \ + roll $7, %esi; \ + xorl %esi, %ebx; \ + movl %ebx, 8(%esp); \ + movl 12(%esp), %esi; \ + xorl %edi, %ebp; \ + leal (%edx, %ebx), %edi; \ + roll $9, %edi; \ + xorl %edi, %esi; \ + movl %esi, 12(%esp); \ + movl 28(%esp), %edi; \ + movl %ebp, 52(%esp); \ + movl 36(%esp), %ebp; \ + addl %esi, %ebx; \ + roll $13, %ebx; \ + xorl %ebx, %ecx; \ + movl 16(%esp), %ebx; \ + movl %ecx, 16(%esp); \ + addl %esi, %ecx; \ + roll $18, %ecx; \ + leal (%edi, %ebp), %esi; \ + roll $7, %esi; \ + xorl %esi, %ebx; \ + movl %ebx, 28(%esp); \ + movl 32(%esp), %esi; \ + xorl %ecx, %edx; \ + leal (%ebp, %ebx), %ecx; \ + roll $9, %ecx; \ + xorl %ecx, %esi; \ + movl %esi, 32(%esp); \ + movl 4(%esp), %ecx; \ + movl %edx, 4(%esp); \ + movl 48(%esp), %edx; \ + addl %esi, %ebx; \ + roll $13, %ebx; \ + xorl %ebx, %edi; \ + movl 20(%esp), %ebx; \ + movl %edi, 20(%esp); \ + addl %esi, %edi; \ + roll $18, %edi; \ + leal (%ecx, %edx), %esi; \ + roll $7, %esi; \ + xorl %esi, %ebx; \ + movl %ebx, 48(%esp); \ + movl 40(%esp), %esi; \ + xorl %edi, %ebp; \ + leal (%edx, %ebx), %edi; \ + roll $9, %edi; \ + xorl %edi, %esi; \ + movl %esi, 36(%esp); \ + movl 60(%esp), %edi; \ + movl %ebp, 24(%esp); \ + movl 52(%esp), %ebp; \ + addl %esi, %ebx; \ + roll $13, %ebx; \ + xorl %ebx, %ecx; \ + movl 44(%esp), %ebx; \ + movl %ecx, 40(%esp); \ + addl %esi, %ecx; \ + roll $18, %ecx; \ + leal (%edi, %ebp), %esi; \ + roll $7, %esi; \ + xorl %esi, %ebx; \ + movl %ebx, 52(%esp); \ + movl 56(%esp), %esi; \ + xorl %ecx, %edx; \ + leal (%ebp, %ebx), %ecx; \ + roll $9, %ecx; \ + xorl %ecx, %esi; \ + movl %esi, 56(%esp); \ + addl %esi, %ebx; \ + movl %edx, 44(%esp); \ + roll $13, %ebx; \ + xorl %ebx, %edi; \ + movl %edi, 60(%esp); \ + addl %esi, %edi; \ + roll $18, %edi; \ + xorl %edi, %ebp; \ + movl %ebp, 64(%esp); \ + + + .text + .align 16 +gen_salsa8_core: + gen_salsa8_core_quadround() + gen_salsa8_core_quadround() + ret + + + .text + .align 16 + .globl scrypt_core + .globl _scrypt_core +scrypt_core: +_scrypt_core: + pushl %ebx + pushl %ebp + pushl %edi + pushl %esi + + # Check for SSE2 availability + movl $1, %eax + cpuid + andl $0x04000000, %edx + jnz xmm_scrypt_core + +gen_scrypt_core: + movl 20(%esp), %edi + movl 24(%esp), %esi + subl $72, %esp + +#define scrypt_core_macro1a(p, q) \ + movl p(%edi), %eax; \ + movl q(%edi), %edx; \ + movl %eax, p(%esi); \ + movl %edx, q(%esi); \ + xorl %edx, %eax; \ + movl %eax, p(%edi); \ + movl %eax, p(%esp); \ + + +#define scrypt_core_macro1b(p, q) \ + movl p(%edi), %eax; \ + xorl p(%esi, %edx), %eax; \ + movl q(%edi), %ebx; \ + xorl q(%esi, %edx), %ebx; \ + movl %ebx, q(%edi); \ + xorl %ebx, %eax; \ + movl %eax, p(%edi); \ + movl %eax, p(%esp); \ + + +#define scrypt_core_macro2(p, q) \ + movl p(%esp), %eax; \ + addl p(%edi), %eax; \ + movl %eax, p(%edi); \ + xorl q(%edi), %eax; \ + movl %eax, q(%edi); \ + movl %eax, p(%esp); \ + + +#define scrypt_core_macro3(p, q) \ + movl p(%esp), %eax; \ + addl q(%edi), %eax; \ + movl %eax, q(%edi); \ + + + leal 131072(%esi), %ecx +gen_scrypt_core_loop1: + movl %esi, 64(%esp) + movl %ecx, 68(%esp) + + scrypt_core_macro1a(0, 64) + scrypt_core_macro1a(4, 68) + scrypt_core_macro1a(8, 72) + scrypt_core_macro1a(12, 76) + scrypt_core_macro1a(16, 80) + scrypt_core_macro1a(20, 84) + scrypt_core_macro1a(24, 88) + scrypt_core_macro1a(28, 92) + scrypt_core_macro1a(32, 96) + scrypt_core_macro1a(36, 100) + scrypt_core_macro1a(40, 104) + scrypt_core_macro1a(44, 108) + scrypt_core_macro1a(48, 112) + scrypt_core_macro1a(52, 116) + scrypt_core_macro1a(56, 120) + scrypt_core_macro1a(60, 124) + + call gen_salsa8_core + + movl 92(%esp), %edi + scrypt_core_macro2(0, 64) + scrypt_core_macro2(4, 68) + scrypt_core_macro2(8, 72) + scrypt_core_macro2(12, 76) + scrypt_core_macro2(16, 80) + scrypt_core_macro2(20, 84) + scrypt_core_macro2(24, 88) + scrypt_core_macro2(28, 92) + scrypt_core_macro2(32, 96) + scrypt_core_macro2(36, 100) + scrypt_core_macro2(40, 104) + scrypt_core_macro2(44, 108) + scrypt_core_macro2(48, 112) + scrypt_core_macro2(52, 116) + scrypt_core_macro2(56, 120) + scrypt_core_macro2(60, 124) + + call gen_salsa8_core + + movl 92(%esp), %edi + scrypt_core_macro3(0, 64) + scrypt_core_macro3(4, 68) + scrypt_core_macro3(8, 72) + scrypt_core_macro3(12, 76) + scrypt_core_macro3(16, 80) + scrypt_core_macro3(20, 84) + scrypt_core_macro3(24, 88) + scrypt_core_macro3(28, 92) + scrypt_core_macro3(32, 96) + scrypt_core_macro3(36, 100) + scrypt_core_macro3(40, 104) + scrypt_core_macro3(44, 108) + scrypt_core_macro3(48, 112) + scrypt_core_macro3(52, 116) + scrypt_core_macro3(56, 120) + scrypt_core_macro3(60, 124) + + movl 64(%esp), %esi + movl 68(%esp), %ecx + addl $128, %esi + cmpl %ecx, %esi + jne gen_scrypt_core_loop1 + + movl 96(%esp), %esi + movl $1024, %ecx +gen_scrypt_core_loop2: + movl %ecx, 68(%esp) + + movl 64(%edi), %edx + andl $1023, %edx + shll $7, %edx + + scrypt_core_macro1b(0, 64) + scrypt_core_macro1b(4, 68) + scrypt_core_macro1b(8, 72) + scrypt_core_macro1b(12, 76) + scrypt_core_macro1b(16, 80) + scrypt_core_macro1b(20, 84) + scrypt_core_macro1b(24, 88) + scrypt_core_macro1b(28, 92) + scrypt_core_macro1b(32, 96) + scrypt_core_macro1b(36, 100) + scrypt_core_macro1b(40, 104) + scrypt_core_macro1b(44, 108) + scrypt_core_macro1b(48, 112) + scrypt_core_macro1b(52, 116) + scrypt_core_macro1b(56, 120) + scrypt_core_macro1b(60, 124) + + call gen_salsa8_core + + movl 92(%esp), %edi + scrypt_core_macro2(0, 64) + scrypt_core_macro2(4, 68) + scrypt_core_macro2(8, 72) + scrypt_core_macro2(12, 76) + scrypt_core_macro2(16, 80) + scrypt_core_macro2(20, 84) + scrypt_core_macro2(24, 88) + scrypt_core_macro2(28, 92) + scrypt_core_macro2(32, 96) + scrypt_core_macro2(36, 100) + scrypt_core_macro2(40, 104) + scrypt_core_macro2(44, 108) + scrypt_core_macro2(48, 112) + scrypt_core_macro2(52, 116) + scrypt_core_macro2(56, 120) + scrypt_core_macro2(60, 124) + + call gen_salsa8_core + + movl 92(%esp), %edi + movl 96(%esp), %esi + scrypt_core_macro3(0, 64) + scrypt_core_macro3(4, 68) + scrypt_core_macro3(8, 72) + scrypt_core_macro3(12, 76) + scrypt_core_macro3(16, 80) + scrypt_core_macro3(20, 84) + scrypt_core_macro3(24, 88) + scrypt_core_macro3(28, 92) + scrypt_core_macro3(32, 96) + scrypt_core_macro3(36, 100) + scrypt_core_macro3(40, 104) + scrypt_core_macro3(44, 108) + scrypt_core_macro3(48, 112) + scrypt_core_macro3(52, 116) + scrypt_core_macro3(56, 120) + scrypt_core_macro3(60, 124) + + movl 68(%esp), %ecx + subl $1, %ecx + ja gen_scrypt_core_loop2 + + addl $72, %esp + popl %esi + popl %edi + popl %ebp + popl %ebx + ret + + +#define xmm_salsa8_core_doubleround() \ + movdqa %xmm1, %xmm4; \ + paddd %xmm0, %xmm4; \ + movdqa %xmm4, %xmm5; \ + pslld $7, %xmm4; \ + psrld $25, %xmm5; \ + pxor %xmm4, %xmm3; \ + pxor %xmm5, %xmm3; \ + movdqa %xmm0, %xmm4; \ + paddd %xmm3, %xmm4; \ + movdqa %xmm4, %xmm5; \ + pslld $9, %xmm4; \ + psrld $23, %xmm5; \ + pxor %xmm4, %xmm2; \ + movdqa %xmm3, %xmm4; \ + pshufd $0x93, %xmm3, %xmm3; \ + pxor %xmm5, %xmm2; \ + paddd %xmm2, %xmm4; \ + movdqa %xmm4, %xmm5; \ + pslld $13, %xmm4; \ + psrld $19, %xmm5; \ + pxor %xmm4, %xmm1; \ + movdqa %xmm2, %xmm4; \ + pshufd $0x4e, %xmm2, %xmm2; \ + pxor %xmm5, %xmm1; \ + paddd %xmm1, %xmm4; \ + movdqa %xmm4, %xmm5; \ + pslld $18, %xmm4; \ + psrld $14, %xmm5; \ + pxor %xmm4, %xmm0; \ + pshufd $0x39, %xmm1, %xmm1; \ + pxor %xmm5, %xmm0; \ + movdqa %xmm3, %xmm4; \ + paddd %xmm0, %xmm4; \ + movdqa %xmm4, %xmm5; \ + pslld $7, %xmm4; \ + psrld $25, %xmm5; \ + pxor %xmm4, %xmm1; \ + pxor %xmm5, %xmm1; \ + movdqa %xmm0, %xmm4; \ + paddd %xmm1, %xmm4; \ + movdqa %xmm4, %xmm5; \ + pslld $9, %xmm4; \ + psrld $23, %xmm5; \ + pxor %xmm4, %xmm2; \ + movdqa %xmm1, %xmm4; \ + pshufd $0x93, %xmm1, %xmm1; \ + pxor %xmm5, %xmm2; \ + paddd %xmm2, %xmm4; \ + movdqa %xmm4, %xmm5; \ + pslld $13, %xmm4; \ + psrld $19, %xmm5; \ + pxor %xmm4, %xmm3; \ + movdqa %xmm2, %xmm4; \ + pshufd $0x4e, %xmm2, %xmm2; \ + pxor %xmm5, %xmm3; \ + paddd %xmm3, %xmm4; \ + movdqa %xmm4, %xmm5; \ + pslld $18, %xmm4; \ + psrld $14, %xmm5; \ + pxor %xmm4, %xmm0; \ + pshufd $0x39, %xmm3, %xmm3; \ + pxor %xmm5, %xmm0; \ + + +#define xmm_salsa8_core() \ + xmm_salsa8_core_doubleround(); \ + xmm_salsa8_core_doubleround(); \ + xmm_salsa8_core_doubleround(); \ + xmm_salsa8_core_doubleround(); \ + + + .align 16 +xmm_scrypt_core: + movl 20(%esp), %edi + movl 24(%esp), %esi + movl %esp, %ebp + subl $128, %esp + andl $-16, %esp + + # shuffle 1st block to (%esp) + movl 60(%edi), %edx + movl 44(%edi), %ecx + movl 28(%edi), %ebx + movl 12(%edi), %eax + movl %edx, 12(%esp) + movl %ecx, 28(%esp) + movl %ebx, 44(%esp) + movl %eax, 60(%esp) + movl 40(%edi), %ecx + movl 24(%edi), %ebx + movl 8(%edi), %eax + movl 56(%edi), %edx + movl %ecx, 8(%esp) + movl %ebx, 24(%esp) + movl %eax, 40(%esp) + movl %edx, 56(%esp) + movl 20(%edi), %ebx + movl 4(%edi), %eax + movl 52(%edi), %edx + movl 36(%edi), %ecx + movl %ebx, 4(%esp) + movl %eax, 20(%esp) + movl %edx, 36(%esp) + movl %ecx, 52(%esp) + movl 0(%edi), %eax + movl 48(%edi), %edx + movl 32(%edi), %ecx + movl 16(%edi), %ebx + movl %eax, 0(%esp) + movl %edx, 16(%esp) + movl %ecx, 32(%esp) + movl %ebx, 48(%esp) + + # shuffle 2nd block to 64(%esp) + movl 124(%edi), %edx + movl 108(%edi), %ecx + movl 92(%edi), %ebx + movl 76(%edi), %eax + movl %edx, 76(%esp) + movl %ecx, 92(%esp) + movl %ebx, 108(%esp) + movl %eax, 124(%esp) + movl 104(%edi), %ecx + movl 88(%edi), %ebx + movl 72(%edi), %eax + movl 120(%edi), %edx + movl %ecx, 72(%esp) + movl %ebx, 88(%esp) + movl %eax, 104(%esp) + movl %edx, 120(%esp) + movl 84(%edi), %ebx + movl 68(%edi), %eax + movl 116(%edi), %edx + movl 100(%edi), %ecx + movl %ebx, 68(%esp) + movl %eax, 84(%esp) + movl %edx, 100(%esp) + movl %ecx, 116(%esp) + movl 64(%edi), %eax + movl 112(%edi), %edx + movl 96(%edi), %ecx + movl 80(%edi), %ebx + movl %eax, 64(%esp) + movl %edx, 80(%esp) + movl %ecx, 96(%esp) + movl %ebx, 112(%esp) + + movl %esi, %edx + leal 131072(%esi), %ecx +xmm_scrypt_core_loop1: + movdqa 0(%esp), %xmm0 + movdqa 16(%esp), %xmm1 + movdqa 32(%esp), %xmm2 + movdqa 48(%esp), %xmm3 + movdqa 64(%esp), %xmm4 + movdqa 80(%esp), %xmm5 + movdqa 96(%esp), %xmm6 + movdqa 112(%esp), %xmm7 + movdqa %xmm0, 0(%edx) + movdqa %xmm1, 16(%edx) + movdqa %xmm2, 32(%edx) + movdqa %xmm3, 48(%edx) + movdqa %xmm4, 64(%edx) + movdqa %xmm5, 80(%edx) + movdqa %xmm6, 96(%edx) + movdqa %xmm7, 112(%edx) + + pxor %xmm4, %xmm0 + pxor %xmm5, %xmm1 + pxor %xmm6, %xmm2 + pxor %xmm7, %xmm3 + movdqa %xmm0, 0(%esp) + movdqa %xmm1, 16(%esp) + movdqa %xmm2, 32(%esp) + movdqa %xmm3, 48(%esp) + xmm_salsa8_core() + paddd 0(%esp), %xmm0 + paddd 16(%esp), %xmm1 + paddd 32(%esp), %xmm2 + paddd 48(%esp), %xmm3 + movdqa %xmm0, 0(%esp) + movdqa %xmm1, 16(%esp) + movdqa %xmm2, 32(%esp) + movdqa %xmm3, 48(%esp) + + pxor 64(%esp), %xmm0 + pxor 80(%esp), %xmm1 + pxor 96(%esp), %xmm2 + pxor 112(%esp), %xmm3 + movdqa %xmm0, 64(%esp) + movdqa %xmm1, 80(%esp) + movdqa %xmm2, 96(%esp) + movdqa %xmm3, 112(%esp) + xmm_salsa8_core() + paddd 64(%esp), %xmm0 + paddd 80(%esp), %xmm1 + paddd 96(%esp), %xmm2 + paddd 112(%esp), %xmm3 + movdqa %xmm0, 64(%esp) + movdqa %xmm1, 80(%esp) + movdqa %xmm2, 96(%esp) + movdqa %xmm3, 112(%esp) + + addl $128, %edx + cmpl %ecx, %edx + jne xmm_scrypt_core_loop1 + + movl $1024, %ecx +xmm_scrypt_core_loop2: + movdqa 0(%esp), %xmm0 + movdqa 16(%esp), %xmm1 + movdqa 32(%esp), %xmm2 + movdqa 48(%esp), %xmm3 + movdqa 64(%esp), %xmm4 + movdqa 80(%esp), %xmm5 + movdqa 96(%esp), %xmm6 + movdqa 112(%esp), %xmm7 + movd %xmm4, %edx + andl $1023, %edx + shll $7, %edx + pxor 0(%esi, %edx), %xmm0 + pxor 16(%esi, %edx), %xmm1 + pxor 32(%esi, %edx), %xmm2 + pxor 48(%esi, %edx), %xmm3 + pxor 64(%esi, %edx), %xmm4 + pxor 80(%esi, %edx), %xmm5 + pxor 96(%esi, %edx), %xmm6 + pxor 112(%esi, %edx), %xmm7 + movdqa %xmm4, 64(%esp) + movdqa %xmm5, 80(%esp) + movdqa %xmm6, 96(%esp) + movdqa %xmm7, 112(%esp) + + pxor %xmm4, %xmm0 + pxor %xmm5, %xmm1 + pxor %xmm6, %xmm2 + pxor %xmm7, %xmm3 + movdqa %xmm0, 0(%esp) + movdqa %xmm1, 16(%esp) + movdqa %xmm2, 32(%esp) + movdqa %xmm3, 48(%esp) + xmm_salsa8_core() + paddd 0(%esp), %xmm0 + paddd 16(%esp), %xmm1 + paddd 32(%esp), %xmm2 + paddd 48(%esp), %xmm3 + movdqa %xmm0, 0(%esp) + movdqa %xmm1, 16(%esp) + movdqa %xmm2, 32(%esp) + movdqa %xmm3, 48(%esp) + + pxor 64(%esp), %xmm0 + pxor 80(%esp), %xmm1 + pxor 96(%esp), %xmm2 + pxor 112(%esp), %xmm3 + movdqa %xmm0, 64(%esp) + movdqa %xmm1, 80(%esp) + movdqa %xmm2, 96(%esp) + movdqa %xmm3, 112(%esp) + xmm_salsa8_core() + paddd 64(%esp), %xmm0 + paddd 80(%esp), %xmm1 + paddd 96(%esp), %xmm2 + paddd 112(%esp), %xmm3 + movdqa %xmm0, 64(%esp) + movdqa %xmm1, 80(%esp) + movdqa %xmm2, 96(%esp) + movdqa %xmm3, 112(%esp) + + subl $1, %ecx + ja xmm_scrypt_core_loop2 + + # re-shuffle 1st block back + movl 60(%esp), %edx + movl 44(%esp), %ecx + movl 28(%esp), %ebx + movl 12(%esp), %eax + movl %edx, 12(%edi) + movl %ecx, 28(%edi) + movl %ebx, 44(%edi) + movl %eax, 60(%edi) + movl 40(%esp), %ecx + movl 24(%esp), %ebx + movl 8(%esp), %eax + movl 56(%esp), %edx + movl %ecx, 8(%edi) + movl %ebx, 24(%edi) + movl %eax, 40(%edi) + movl %edx, 56(%edi) + movl 20(%esp), %ebx + movl 4(%esp), %eax + movl 52(%esp), %edx + movl 36(%esp), %ecx + movl %ebx, 4(%edi) + movl %eax, 20(%edi) + movl %edx, 36(%edi) + movl %ecx, 52(%edi) + movl 0(%esp), %eax + movl 48(%esp), %edx + movl 32(%esp), %ecx + movl 16(%esp), %ebx + movl %eax, 0(%edi) + movl %edx, 16(%edi) + movl %ecx, 32(%edi) + movl %ebx, 48(%edi) + + # re-shuffle 2nd block back + movl 124(%esp), %edx + movl 108(%esp), %ecx + movl 92(%esp), %ebx + movl 76(%esp), %eax + movl %edx, 76(%edi) + movl %ecx, 92(%edi) + movl %ebx, 108(%edi) + movl %eax, 124(%edi) + movl 104(%esp), %ecx + movl 88(%esp), %ebx + movl 72(%esp), %eax + movl 120(%esp), %edx + movl %ecx, 72(%edi) + movl %ebx, 88(%edi) + movl %eax, 104(%edi) + movl %edx, 120(%edi) + movl 84(%esp), %ebx + movl 68(%esp), %eax + movl 116(%esp), %edx + movl 100(%esp), %ecx + movl %ebx, 68(%edi) + movl %eax, 84(%edi) + movl %edx, 100(%edi) + movl %ecx, 116(%edi) + movl 64(%esp), %eax + movl 112(%esp), %edx + movl 96(%esp), %ecx + movl 80(%esp), %ebx + movl %eax, 64(%edi) + movl %edx, 80(%edi) + movl %ecx, 96(%edi) + movl %ebx, 112(%edi) + + movl %ebp, %esp + popl %esi + popl %edi + popl %ebp + popl %ebx + ret + +#endif diff --git a/src/scrypt-x86_64.S b/src/scrypt-x86_64.S new file mode 100644 index 0000000..3ed3483 --- /dev/null +++ b/src/scrypt-x86_64.S @@ -0,0 +1,1831 @@ +# Copyright 2011-2012 pooler@litecoinpool.org +# 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. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + +#if defined(__linux__) && defined(__ELF__) + .section .note.GNU-stack,"",%progbits +#endif + +#if defined(__x86_64__) + +#define scrypt_shuffle(src, so, dest, do) \ + movl so+60(src), %r8d; \ + movl so+44(src), %r9d; \ + movl so+28(src), %r10d; \ + movl so+12(src), %r11d; \ + movl %r8d, do+12(dest); \ + movl %r9d, do+28(dest); \ + movl %r10d, do+44(dest); \ + movl %r11d, do+60(dest); \ + movl so+40(src), %r8d; \ + movl so+8(src), %r9d; \ + movl so+48(src), %r10d; \ + movl so+16(src), %r11d; \ + movl %r8d, do+8(dest); \ + movl %r9d, do+40(dest); \ + movl %r10d, do+16(dest); \ + movl %r11d, do+48(dest); \ + movl so+20(src), %r8d; \ + movl so+4(src), %r9d; \ + movl so+52(src), %r10d; \ + movl so+36(src), %r11d; \ + movl %r8d, do+4(dest); \ + movl %r9d, do+20(dest); \ + movl %r10d, do+36(dest); \ + movl %r11d, do+52(dest); \ + movl so+0(src), %r8d; \ + movl so+24(src), %r9d; \ + movl so+32(src), %r10d; \ + movl so+56(src), %r11d; \ + movl %r8d, do+0(dest); \ + movl %r9d, do+24(dest); \ + movl %r10d, do+32(dest); \ + movl %r11d, do+56(dest); \ + + +#define gen_salsa8_core_doubleround() \ + movq 72(%rsp), %r15; \ + leaq (%r14, %rdx), %rbp; \ + roll $7, %ebp; \ + xorq %rbp, %r9; \ + leaq (%rdi, %r15), %rbp; \ + roll $7, %ebp; \ + xorq %rbp, %r10; \ + leaq (%rdx, %r9), %rbp; \ + roll $9, %ebp; \ + xorq %rbp, %r11; \ + leaq (%r15, %r10), %rbp; \ + roll $9, %ebp; \ + xorq %rbp, %r13; \ + leaq (%r9, %r11), %rbp; \ + roll $13, %ebp; \ + xorq %rbp, %r14; \ + leaq (%r10, %r13), %rbp; \ + roll $13, %ebp; \ + xorq %rbp, %rdi; \ + leaq (%r11, %r14), %rbp; \ + roll $18, %ebp; \ + xorq %rbp, %rdx; \ + leaq (%r13, %rdi), %rbp; \ + roll $18, %ebp; \ + xorq %rbp, %r15; \ + movq 48(%rsp), %rbp; \ + movq %r15, 72(%rsp); \ + leaq (%rax, %rbp), %r15; \ + roll $7, %r15d; \ + xorq %r15, %rbx; \ + leaq (%rbp, %rbx), %r15; \ + roll $9, %r15d; \ + xorq %r15, %rcx; \ + leaq (%rbx, %rcx), %r15; \ + roll $13, %r15d; \ + xorq %r15, %rax; \ + leaq (%rcx, %rax), %r15; \ + roll $18, %r15d; \ + xorq %r15, %rbp; \ + movq 88(%rsp), %r15; \ + movq %rbp, 48(%rsp); \ + leaq (%r12, %r15), %rbp; \ + roll $7, %ebp; \ + xorq %rbp, %rsi; \ + leaq (%r15, %rsi), %rbp; \ + roll $9, %ebp; \ + xorq %rbp, %r8; \ + leaq (%rsi, %r8), %rbp; \ + roll $13, %ebp; \ + xorq %rbp, %r12; \ + leaq (%r8, %r12), %rbp; \ + roll $18, %ebp; \ + xorq %rbp, %r15; \ + movq %r15, 88(%rsp); \ + movq 72(%rsp), %r15; \ + leaq (%rsi, %rdx), %rbp; \ + roll $7, %ebp; \ + xorq %rbp, %rdi; \ + leaq (%r9, %r15), %rbp; \ + roll $7, %ebp; \ + xorq %rbp, %rax; \ + leaq (%rdx, %rdi), %rbp; \ + roll $9, %ebp; \ + xorq %rbp, %rcx; \ + leaq (%r15, %rax), %rbp; \ + roll $9, %ebp; \ + xorq %rbp, %r8; \ + leaq (%rdi, %rcx), %rbp; \ + roll $13, %ebp; \ + xorq %rbp, %rsi; \ + leaq (%rax, %r8), %rbp; \ + roll $13, %ebp; \ + xorq %rbp, %r9; \ + leaq (%rcx, %rsi), %rbp; \ + roll $18, %ebp; \ + xorq %rbp, %rdx; \ + leaq (%r8, %r9), %rbp; \ + roll $18, %ebp; \ + xorq %rbp, %r15; \ + movq 48(%rsp), %rbp; \ + movq %r15, 72(%rsp); \ + leaq (%r10, %rbp), %r15; \ + roll $7, %r15d; \ + xorq %r15, %r12; \ + leaq (%rbp, %r12), %r15; \ + roll $9, %r15d; \ + xorq %r15, %r11; \ + leaq (%r12, %r11), %r15; \ + roll $13, %r15d; \ + xorq %r15, %r10; \ + leaq (%r11, %r10), %r15; \ + roll $18, %r15d; \ + xorq %r15, %rbp; \ + movq 88(%rsp), %r15; \ + movq %rbp, 48(%rsp); \ + leaq (%rbx, %r15), %rbp; \ + roll $7, %ebp; \ + xorq %rbp, %r14; \ + leaq (%r15, %r14), %rbp; \ + roll $9, %ebp; \ + xorq %rbp, %r13; \ + leaq (%r14, %r13), %rbp; \ + roll $13, %ebp; \ + xorq %rbp, %rbx; \ + leaq (%r13, %rbx), %rbp; \ + roll $18, %ebp; \ + xorq %rbp, %r15; \ + movq %r15, 88(%rsp); \ + + + .text + .align 16 +gen_salsa8_core: + # 0: %rdx, %rdi, %rcx, %rsi + movq 8(%rsp), %rdi + movq %rdi, %rdx + shrq $32, %rdi + movq 16(%rsp), %rsi + movq %rsi, %rcx + shrq $32, %rsi + # 1: %r9, 72(%rsp), %rax, %r8 + movq 24(%rsp), %r8 + movq %r8, %r9 + shrq $32, %r8 + movq %r8, 72(%rsp) + movq 32(%rsp), %r8 + movq %r8, %rax + shrq $32, %r8 + # 2: %r11, %r10, 48(%rsp), %r12 + movq 40(%rsp), %r10 + movq %r10, %r11 + shrq $32, %r10 + movq 48(%rsp), %r12 + #movq %r12, %r13 + #movq %r13, 48(%rsp) + shrq $32, %r12 + # 3: %r14, %r13, %rbx, 88(%rsp) + movq 56(%rsp), %r13 + movq %r13, %r14 + shrq $32, %r13 + movq 64(%rsp), %r15 + movq %r15, %rbx + shrq $32, %r15 + movq %r15, 88(%rsp) + + gen_salsa8_core_doubleround() + gen_salsa8_core_doubleround() + gen_salsa8_core_doubleround() + gen_salsa8_core_doubleround() + + movl %edx, %edx + shlq $32, %rdi + addq %rdi, %rdx + movd %rdx, %xmm0 + + movl %ecx, %ecx + shlq $32, %rsi + addq %rsi, %rcx + movd %rcx, %xmm4 + + movq 72(%rsp), %rdi + movl %r9d, %r9d + shlq $32, %rdi + addq %rdi, %r9 + movd %r9, %xmm1 + + movl %eax, %eax + shlq $32, %r8 + addq %r8, %rax + movd %rax, %xmm5 + + movl %r11d, %r11d + shlq $32, %r10 + addq %r10, %r11 + movd %r11, %xmm2 + + movl 48(%rsp), %r8d + shlq $32, %r12 + addq %r12, %r8 + movd %r8, %xmm6 + + movl %r14d, %r14d + shlq $32, %r13 + addq %r13, %r14 + movd %r14, %xmm3 + + movq 88(%rsp), %rdi + movl %ebx, %ebx + shlq $32, %rdi + addq %rdi, %rbx + movd %rbx, %xmm7 + + punpcklqdq %xmm4, %xmm0 + punpcklqdq %xmm5, %xmm1 + punpcklqdq %xmm6, %xmm2 + punpcklqdq %xmm7, %xmm3 + + #movq %rdx, 8(%rsp) + #movq %rcx, 16(%rsp) + #movq %r9, 24(%rsp) + #movq %rax, 32(%rsp) + #movq %r11, 40(%rsp) + #movq %r8, 48(%rsp) + #movq %r14, 56(%rsp) + #movq %rbx, 64(%rsp) + + ret + + + .text + .align 16 + .globl scrypt_core + .globl _scrypt_core +scrypt_core: +_scrypt_core: + pushq %rbx + pushq %rbp + pushq %r12 + pushq %r13 + pushq %r14 + pushq %r15 +#if defined(WIN64) + subq $176, %rsp + movdqa %xmm6, 8(%rsp) + movdqa %xmm7, 24(%rsp) + movdqa %xmm8, 40(%rsp) + movdqa %xmm9, 56(%rsp) + movdqa %xmm10, 72(%rsp) + movdqa %xmm11, 88(%rsp) + movdqa %xmm12, 104(%rsp) + movdqa %xmm13, 120(%rsp) + movdqa %xmm14, 136(%rsp) + movdqa %xmm15, 152(%rsp) + pushq %rdi + pushq %rsi + movq %rcx, %rdi + movq %rdx, %rsi +#endif + +#define scrypt_core_cleanup() \ + popq %r15; \ + popq %r14; \ + popq %r13; \ + popq %r12; \ + popq %rbp; \ + popq %rbx; \ + + + # GenuineIntel processors have fast SIMD + xorl %eax, %eax + cpuid + cmpl $0x6c65746e, %ecx + jne gen_scrypt_core + cmpl $0x49656e69, %edx + jne gen_scrypt_core + cmpl $0x756e6547, %ebx + je xmm_scrypt_core + +gen_scrypt_core: + subq $136, %rsp + movdqa 0(%rdi), %xmm8 + movdqa 16(%rdi), %xmm9 + movdqa 32(%rdi), %xmm10 + movdqa 48(%rdi), %xmm11 + movdqa 64(%rdi), %xmm12 + movdqa 80(%rdi), %xmm13 + movdqa 96(%rdi), %xmm14 + movdqa 112(%rdi), %xmm15 + + leaq 131072(%rsi), %rcx + movq %rdi, 104(%rsp) + movq %rsi, 112(%rsp) + movq %rcx, 120(%rsp) +gen_scrypt_core_loop1: + movdqa %xmm8, 0(%rsi) + movdqa %xmm9, 16(%rsi) + movdqa %xmm10, 32(%rsi) + movdqa %xmm11, 48(%rsi) + movdqa %xmm12, 64(%rsi) + movdqa %xmm13, 80(%rsi) + movdqa %xmm14, 96(%rsi) + movdqa %xmm15, 112(%rsi) + + pxor %xmm12, %xmm8 + pxor %xmm13, %xmm9 + pxor %xmm14, %xmm10 + pxor %xmm15, %xmm11 + movdqa %xmm8, 0(%rsp) + movdqa %xmm9, 16(%rsp) + movdqa %xmm10, 32(%rsp) + movdqa %xmm11, 48(%rsp) + movq %rsi, 128(%rsp) + call gen_salsa8_core + paddd %xmm0, %xmm8 + paddd %xmm1, %xmm9 + paddd %xmm2, %xmm10 + paddd %xmm3, %xmm11 + + pxor %xmm8, %xmm12 + pxor %xmm9, %xmm13 + pxor %xmm10, %xmm14 + pxor %xmm11, %xmm15 + movdqa %xmm12, 0(%rsp) + movdqa %xmm13, 16(%rsp) + movdqa %xmm14, 32(%rsp) + movdqa %xmm15, 48(%rsp) + call gen_salsa8_core + movq 128(%rsp), %rsi + paddd %xmm0, %xmm12 + paddd %xmm1, %xmm13 + paddd %xmm2, %xmm14 + paddd %xmm3, %xmm15 + + addq $128, %rsi + movq 120(%rsp), %rcx + cmpq %rcx, %rsi + jne gen_scrypt_core_loop1 + + movq $1024, %rcx +gen_scrypt_core_loop2: + movq 112(%rsp), %rsi + movd %xmm12, %edx + andl $1023, %edx + shll $7, %edx + movdqa 0(%rsi, %rdx), %xmm0 + movdqa 16(%rsi, %rdx), %xmm1 + movdqa 32(%rsi, %rdx), %xmm2 + movdqa 48(%rsi, %rdx), %xmm3 + movdqa 64(%rsi, %rdx), %xmm4 + movdqa 80(%rsi, %rdx), %xmm5 + movdqa 96(%rsi, %rdx), %xmm6 + movdqa 112(%rsi, %rdx), %xmm7 + pxor %xmm0, %xmm8 + pxor %xmm1, %xmm9 + pxor %xmm2, %xmm10 + pxor %xmm3, %xmm11 + pxor %xmm4, %xmm12 + pxor %xmm5, %xmm13 + pxor %xmm6, %xmm14 + pxor %xmm7, %xmm15 + + pxor %xmm12, %xmm8 + pxor %xmm13, %xmm9 + pxor %xmm14, %xmm10 + pxor %xmm15, %xmm11 + movdqa %xmm8, 0(%rsp) + movdqa %xmm9, 16(%rsp) + movdqa %xmm10, 32(%rsp) + movdqa %xmm11, 48(%rsp) + movq %rcx, 128(%rsp) + call gen_salsa8_core + paddd %xmm0, %xmm8 + paddd %xmm1, %xmm9 + paddd %xmm2, %xmm10 + paddd %xmm3, %xmm11 + + pxor %xmm8, %xmm12 + pxor %xmm9, %xmm13 + pxor %xmm10, %xmm14 + pxor %xmm11, %xmm15 + movdqa %xmm12, 0(%rsp) + movdqa %xmm13, 16(%rsp) + movdqa %xmm14, 32(%rsp) + movdqa %xmm15, 48(%rsp) + call gen_salsa8_core + movq 128(%rsp), %rcx + paddd %xmm0, %xmm12 + paddd %xmm1, %xmm13 + paddd %xmm2, %xmm14 + paddd %xmm3, %xmm15 + + subq $1, %rcx + ja gen_scrypt_core_loop2 + + movq 104(%rsp), %rdi + movdqa %xmm8, 0(%rdi) + movdqa %xmm9, 16(%rdi) + movdqa %xmm10, 32(%rdi) + movdqa %xmm11, 48(%rdi) + movdqa %xmm12, 64(%rdi) + movdqa %xmm13, 80(%rdi) + movdqa %xmm14, 96(%rdi) + movdqa %xmm15, 112(%rdi) + + addq $136, %rsp + scrypt_core_cleanup() + ret + + +#define xmm_salsa8_core_doubleround() \ + movdqa %xmm1, %xmm4; \ + paddd %xmm0, %xmm4; \ + movdqa %xmm4, %xmm5; \ + pslld $7, %xmm4; \ + psrld $25, %xmm5; \ + pxor %xmm4, %xmm3; \ + pxor %xmm5, %xmm3; \ + movdqa %xmm0, %xmm4; \ + paddd %xmm3, %xmm4; \ + movdqa %xmm4, %xmm5; \ + pslld $9, %xmm4; \ + psrld $23, %xmm5; \ + pxor %xmm4, %xmm2; \ + movdqa %xmm3, %xmm4; \ + pshufd $0x93, %xmm3, %xmm3; \ + pxor %xmm5, %xmm2; \ + paddd %xmm2, %xmm4; \ + movdqa %xmm4, %xmm5; \ + pslld $13, %xmm4; \ + psrld $19, %xmm5; \ + pxor %xmm4, %xmm1; \ + movdqa %xmm2, %xmm4; \ + pshufd $0x4e, %xmm2, %xmm2; \ + pxor %xmm5, %xmm1; \ + paddd %xmm1, %xmm4; \ + movdqa %xmm4, %xmm5; \ + pslld $18, %xmm4; \ + psrld $14, %xmm5; \ + pxor %xmm4, %xmm0; \ + pshufd $0x39, %xmm1, %xmm1; \ + pxor %xmm5, %xmm0; \ + movdqa %xmm3, %xmm4; \ + paddd %xmm0, %xmm4; \ + movdqa %xmm4, %xmm5; \ + pslld $7, %xmm4; \ + psrld $25, %xmm5; \ + pxor %xmm4, %xmm1; \ + pxor %xmm5, %xmm1; \ + movdqa %xmm0, %xmm4; \ + paddd %xmm1, %xmm4; \ + movdqa %xmm4, %xmm5; \ + pslld $9, %xmm4; \ + psrld $23, %xmm5; \ + pxor %xmm4, %xmm2; \ + movdqa %xmm1, %xmm4; \ + pshufd $0x93, %xmm1, %xmm1; \ + pxor %xmm5, %xmm2; \ + paddd %xmm2, %xmm4; \ + movdqa %xmm4, %xmm5; \ + pslld $13, %xmm4; \ + psrld $19, %xmm5; \ + pxor %xmm4, %xmm3; \ + movdqa %xmm2, %xmm4; \ + pshufd $0x4e, %xmm2, %xmm2; \ + pxor %xmm5, %xmm3; \ + paddd %xmm3, %xmm4; \ + movdqa %xmm4, %xmm5; \ + pslld $18, %xmm4; \ + psrld $14, %xmm5; \ + pxor %xmm4, %xmm0; \ + pshufd $0x39, %xmm3, %xmm3; \ + pxor %xmm5, %xmm0; \ + + +#define xmm_salsa8_core() \ + xmm_salsa8_core_doubleround(); \ + xmm_salsa8_core_doubleround(); \ + xmm_salsa8_core_doubleround(); \ + xmm_salsa8_core_doubleround(); \ + + + .align 16 +xmm_scrypt_core: + # shuffle 1st block into %xmm8-%xmm11 + movl 60(%rdi), %edx + movl 44(%rdi), %ecx + movl 28(%rdi), %ebx + movl 12(%rdi), %eax + movd %edx, %xmm0 + movd %ecx, %xmm1 + movd %ebx, %xmm2 + movd %eax, %xmm3 + movl 40(%rdi), %ecx + movl 24(%rdi), %ebx + movl 8(%rdi), %eax + movl 56(%rdi), %edx + pshufd $0x93, %xmm0, %xmm0 + pshufd $0x93, %xmm1, %xmm1 + pshufd $0x93, %xmm2, %xmm2 + pshufd $0x93, %xmm3, %xmm3 + movd %ecx, %xmm4 + movd %ebx, %xmm5 + movd %eax, %xmm6 + movd %edx, %xmm7 + paddd %xmm4, %xmm0 + paddd %xmm5, %xmm1 + paddd %xmm6, %xmm2 + paddd %xmm7, %xmm3 + movl 20(%rdi), %ebx + movl 4(%rdi), %eax + movl 52(%rdi), %edx + movl 36(%rdi), %ecx + pshufd $0x93, %xmm0, %xmm0 + pshufd $0x93, %xmm1, %xmm1 + pshufd $0x93, %xmm2, %xmm2 + pshufd $0x93, %xmm3, %xmm3 + movd %ebx, %xmm4 + movd %eax, %xmm5 + movd %edx, %xmm6 + movd %ecx, %xmm7 + paddd %xmm4, %xmm0 + paddd %xmm5, %xmm1 + paddd %xmm6, %xmm2 + paddd %xmm7, %xmm3 + movl 0(%rdi), %eax + movl 48(%rdi), %edx + movl 32(%rdi), %ecx + movl 16(%rdi), %ebx + pshufd $0x93, %xmm0, %xmm0 + pshufd $0x93, %xmm1, %xmm1 + pshufd $0x93, %xmm2, %xmm2 + pshufd $0x93, %xmm3, %xmm3 + movd %eax, %xmm8 + movd %edx, %xmm9 + movd %ecx, %xmm10 + movd %ebx, %xmm11 + paddd %xmm0, %xmm8 + paddd %xmm1, %xmm9 + paddd %xmm2, %xmm10 + paddd %xmm3, %xmm11 + + # shuffle 2nd block into %xmm12-%xmm15 + movl 124(%rdi), %edx + movl 108(%rdi), %ecx + movl 92(%rdi), %ebx + movl 76(%rdi), %eax + movd %edx, %xmm0 + movd %ecx, %xmm1 + movd %ebx, %xmm2 + movd %eax, %xmm3 + movl 104(%rdi), %ecx + movl 88(%rdi), %ebx + movl 72(%rdi), %eax + movl 120(%rdi), %edx + pshufd $0x93, %xmm0, %xmm0 + pshufd $0x93, %xmm1, %xmm1 + pshufd $0x93, %xmm2, %xmm2 + pshufd $0x93, %xmm3, %xmm3 + movd %ecx, %xmm4 + movd %ebx, %xmm5 + movd %eax, %xmm6 + movd %edx, %xmm7 + paddd %xmm4, %xmm0 + paddd %xmm5, %xmm1 + paddd %xmm6, %xmm2 + paddd %xmm7, %xmm3 + movl 84(%rdi), %ebx + movl 68(%rdi), %eax + movl 116(%rdi), %edx + movl 100(%rdi), %ecx + pshufd $0x93, %xmm0, %xmm0 + pshufd $0x93, %xmm1, %xmm1 + pshufd $0x93, %xmm2, %xmm2 + pshufd $0x93, %xmm3, %xmm3 + movd %ebx, %xmm4 + movd %eax, %xmm5 + movd %edx, %xmm6 + movd %ecx, %xmm7 + paddd %xmm4, %xmm0 + paddd %xmm5, %xmm1 + paddd %xmm6, %xmm2 + paddd %xmm7, %xmm3 + movl 64(%rdi), %eax + movl 112(%rdi), %edx + movl 96(%rdi), %ecx + movl 80(%rdi), %ebx + pshufd $0x93, %xmm0, %xmm0 + pshufd $0x93, %xmm1, %xmm1 + pshufd $0x93, %xmm2, %xmm2 + pshufd $0x93, %xmm3, %xmm3 + movd %eax, %xmm12 + movd %edx, %xmm13 + movd %ecx, %xmm14 + movd %ebx, %xmm15 + paddd %xmm0, %xmm12 + paddd %xmm1, %xmm13 + paddd %xmm2, %xmm14 + paddd %xmm3, %xmm15 + + movq %rsi, %rdx + leaq 131072(%rsi), %rcx +xmm_scrypt_core_loop1: + movdqa %xmm8, 0(%rdx) + movdqa %xmm9, 16(%rdx) + movdqa %xmm10, 32(%rdx) + movdqa %xmm11, 48(%rdx) + movdqa %xmm12, 64(%rdx) + movdqa %xmm13, 80(%rdx) + movdqa %xmm14, 96(%rdx) + movdqa %xmm15, 112(%rdx) + + pxor %xmm12, %xmm8 + pxor %xmm13, %xmm9 + pxor %xmm14, %xmm10 + pxor %xmm15, %xmm11 + movdqa %xmm8, %xmm0 + movdqa %xmm9, %xmm1 + movdqa %xmm10, %xmm2 + movdqa %xmm11, %xmm3 + xmm_salsa8_core() + paddd %xmm0, %xmm8 + paddd %xmm1, %xmm9 + paddd %xmm2, %xmm10 + paddd %xmm3, %xmm11 + + pxor %xmm8, %xmm12 + pxor %xmm9, %xmm13 + pxor %xmm10, %xmm14 + pxor %xmm11, %xmm15 + movdqa %xmm12, %xmm0 + movdqa %xmm13, %xmm1 + movdqa %xmm14, %xmm2 + movdqa %xmm15, %xmm3 + xmm_salsa8_core() + paddd %xmm0, %xmm12 + paddd %xmm1, %xmm13 + paddd %xmm2, %xmm14 + paddd %xmm3, %xmm15 + + addq $128, %rdx + cmpq %rcx, %rdx + jne xmm_scrypt_core_loop1 + + movq $1024, %rcx +xmm_scrypt_core_loop2: + movd %xmm12, %edx + andl $1023, %edx + shll $7, %edx + movdqa 0(%rsi, %rdx), %xmm0 + movdqa 16(%rsi, %rdx), %xmm1 + movdqa 32(%rsi, %rdx), %xmm2 + movdqa 48(%rsi, %rdx), %xmm3 + movdqa 64(%rsi, %rdx), %xmm4 + movdqa 80(%rsi, %rdx), %xmm5 + movdqa 96(%rsi, %rdx), %xmm6 + movdqa 112(%rsi, %rdx), %xmm7 + pxor %xmm0, %xmm8 + pxor %xmm1, %xmm9 + pxor %xmm2, %xmm10 + pxor %xmm3, %xmm11 + pxor %xmm4, %xmm12 + pxor %xmm5, %xmm13 + pxor %xmm6, %xmm14 + pxor %xmm7, %xmm15 + + pxor %xmm12, %xmm8 + pxor %xmm13, %xmm9 + pxor %xmm14, %xmm10 + pxor %xmm15, %xmm11 + movdqa %xmm8, %xmm0 + movdqa %xmm9, %xmm1 + movdqa %xmm10, %xmm2 + movdqa %xmm11, %xmm3 + xmm_salsa8_core() + paddd %xmm0, %xmm8 + paddd %xmm1, %xmm9 + paddd %xmm2, %xmm10 + paddd %xmm3, %xmm11 + + pxor %xmm8, %xmm12 + pxor %xmm9, %xmm13 + pxor %xmm10, %xmm14 + pxor %xmm11, %xmm15 + movdqa %xmm12, %xmm0 + movdqa %xmm13, %xmm1 + movdqa %xmm14, %xmm2 + movdqa %xmm15, %xmm3 + xmm_salsa8_core() + paddd %xmm0, %xmm12 + paddd %xmm1, %xmm13 + paddd %xmm2, %xmm14 + paddd %xmm3, %xmm15 + + subq $1, %rcx + ja xmm_scrypt_core_loop2 + + # re-shuffle 1st block back + movd %xmm8, %eax + movd %xmm9, %edx + movd %xmm10, %ecx + movd %xmm11, %ebx + pshufd $0x39, %xmm8, %xmm8 + pshufd $0x39, %xmm9, %xmm9 + pshufd $0x39, %xmm10, %xmm10 + pshufd $0x39, %xmm11, %xmm11 + movl %eax, 0(%rdi) + movl %edx, 48(%rdi) + movl %ecx, 32(%rdi) + movl %ebx, 16(%rdi) + movd %xmm8, %ebx + movd %xmm9, %eax + movd %xmm10, %edx + movd %xmm11, %ecx + pshufd $0x39, %xmm8, %xmm8 + pshufd $0x39, %xmm9, %xmm9 + pshufd $0x39, %xmm10, %xmm10 + pshufd $0x39, %xmm11, %xmm11 + movl %ebx, 20(%rdi) + movl %eax, 4(%rdi) + movl %edx, 52(%rdi) + movl %ecx, 36(%rdi) + movd %xmm8, %ecx + movd %xmm9, %ebx + movd %xmm10, %eax + movd %xmm11, %edx + pshufd $0x39, %xmm8, %xmm8 + pshufd $0x39, %xmm9, %xmm9 + pshufd $0x39, %xmm10, %xmm10 + pshufd $0x39, %xmm11, %xmm11 + movl %ecx, 40(%rdi) + movl %ebx, 24(%rdi) + movl %eax, 8(%rdi) + movl %edx, 56(%rdi) + movd %xmm8, %edx + movd %xmm9, %ecx + movd %xmm10, %ebx + movd %xmm11, %eax + movl %edx, 60(%rdi) + movl %ecx, 44(%rdi) + movl %ebx, 28(%rdi) + movl %eax, 12(%rdi) + + # re-shuffle 2nd block back + movd %xmm12, %eax + movd %xmm13, %edx + movd %xmm14, %ecx + movd %xmm15, %ebx + pshufd $0x39, %xmm12, %xmm12 + pshufd $0x39, %xmm13, %xmm13 + pshufd $0x39, %xmm14, %xmm14 + pshufd $0x39, %xmm15, %xmm15 + movl %eax, 64(%rdi) + movl %edx, 112(%rdi) + movl %ecx, 96(%rdi) + movl %ebx, 80(%rdi) + movd %xmm12, %ebx + movd %xmm13, %eax + movd %xmm14, %edx + movd %xmm15, %ecx + pshufd $0x39, %xmm12, %xmm12 + pshufd $0x39, %xmm13, %xmm13 + pshufd $0x39, %xmm14, %xmm14 + pshufd $0x39, %xmm15, %xmm15 + movl %ebx, 84(%rdi) + movl %eax, 68(%rdi) + movl %edx, 116(%rdi) + movl %ecx, 100(%rdi) + movd %xmm12, %ecx + movd %xmm13, %ebx + movd %xmm14, %eax + movd %xmm15, %edx + pshufd $0x39, %xmm12, %xmm12 + pshufd $0x39, %xmm13, %xmm13 + pshufd $0x39, %xmm14, %xmm14 + pshufd $0x39, %xmm15, %xmm15 + movl %ecx, 104(%rdi) + movl %ebx, 88(%rdi) + movl %eax, 72(%rdi) + movl %edx, 120(%rdi) + movd %xmm12, %edx + movd %xmm13, %ecx + movd %xmm14, %ebx + movd %xmm15, %eax + movl %edx, 124(%rdi) + movl %ecx, 108(%rdi) + movl %ebx, 92(%rdi) + movl %eax, 76(%rdi) + + scrypt_core_cleanup() + ret + + + .text + .align 16 + .globl scrypt_best_throughput + .globl _scrypt_best_throughput +scrypt_best_throughput: +_scrypt_best_throughput: + pushq %rbx + xorq %rax, %rax + cpuid + movl $3, %eax + cmpl $0x444d4163, %ecx + jne scrypt_best_throughput_exit + cmpl $0x69746e65, %edx + jne scrypt_best_throughput_exit + cmpl $0x68747541, %ebx + jne scrypt_best_throughput_exit + movl $1, %eax + cpuid + andl $0x0ff00000, %eax + movl $3, %eax + jnz scrypt_best_throughput_exit + movl $1, %eax +scrypt_best_throughput_exit: + popq %rbx + ret + + +#define xmm_salsa8_core_2way_doubleround() \ + movdqa %xmm1, %xmm4; \ + movdqa %xmm9, %xmm6; \ + paddd %xmm0, %xmm4; \ + paddd %xmm8, %xmm6; \ + movdqa %xmm4, %xmm5; \ + movdqa %xmm6, %xmm7; \ + pslld $7, %xmm4; \ + pslld $7, %xmm6; \ + psrld $25, %xmm5; \ + psrld $25, %xmm7; \ + pxor %xmm4, %xmm3; \ + pxor %xmm6, %xmm11; \ + pxor %xmm5, %xmm3; \ + pxor %xmm7, %xmm11; \ + movdqa %xmm0, %xmm4; \ + movdqa %xmm8, %xmm6; \ + paddd %xmm3, %xmm4; \ + paddd %xmm11, %xmm6; \ + movdqa %xmm4, %xmm5; \ + movdqa %xmm6, %xmm7; \ + pslld $9, %xmm4; \ + pslld $9, %xmm6; \ + psrld $23, %xmm5; \ + psrld $23, %xmm7; \ + pxor %xmm4, %xmm2; \ + pxor %xmm6, %xmm10; \ + movdqa %xmm3, %xmm4; \ + movdqa %xmm11, %xmm6; \ + pshufd $0x93, %xmm3, %xmm3; \ + pshufd $0x93, %xmm11, %xmm11; \ + pxor %xmm5, %xmm2; \ + pxor %xmm7, %xmm10; \ + paddd %xmm2, %xmm4; \ + paddd %xmm10, %xmm6; \ + movdqa %xmm4, %xmm5; \ + movdqa %xmm6, %xmm7; \ + pslld $13, %xmm4; \ + pslld $13, %xmm6; \ + psrld $19, %xmm5; \ + psrld $19, %xmm7; \ + pxor %xmm4, %xmm1; \ + pxor %xmm6, %xmm9; \ + movdqa %xmm2, %xmm4; \ + movdqa %xmm10, %xmm6; \ + pshufd $0x4e, %xmm2, %xmm2; \ + pshufd $0x4e, %xmm10, %xmm10; \ + pxor %xmm5, %xmm1; \ + pxor %xmm7, %xmm9; \ + paddd %xmm1, %xmm4; \ + paddd %xmm9, %xmm6; \ + movdqa %xmm4, %xmm5; \ + movdqa %xmm6, %xmm7; \ + pslld $18, %xmm4; \ + pslld $18, %xmm6; \ + psrld $14, %xmm5; \ + psrld $14, %xmm7; \ + pxor %xmm4, %xmm0; \ + pxor %xmm6, %xmm8; \ + pshufd $0x39, %xmm1, %xmm1; \ + pshufd $0x39, %xmm9, %xmm9; \ + pxor %xmm5, %xmm0; \ + pxor %xmm7, %xmm8; \ + movdqa %xmm3, %xmm4; \ + movdqa %xmm11, %xmm6; \ + paddd %xmm0, %xmm4; \ + paddd %xmm8, %xmm6; \ + movdqa %xmm4, %xmm5; \ + movdqa %xmm6, %xmm7; \ + pslld $7, %xmm4; \ + pslld $7, %xmm6; \ + psrld $25, %xmm5; \ + psrld $25, %xmm7; \ + pxor %xmm4, %xmm1; \ + pxor %xmm6, %xmm9; \ + pxor %xmm5, %xmm1; \ + pxor %xmm7, %xmm9; \ + movdqa %xmm0, %xmm4; \ + movdqa %xmm8, %xmm6; \ + paddd %xmm1, %xmm4; \ + paddd %xmm9, %xmm6; \ + movdqa %xmm4, %xmm5; \ + movdqa %xmm6, %xmm7; \ + pslld $9, %xmm4; \ + pslld $9, %xmm6; \ + psrld $23, %xmm5; \ + psrld $23, %xmm7; \ + pxor %xmm4, %xmm2; \ + pxor %xmm6, %xmm10; \ + movdqa %xmm1, %xmm4; \ + movdqa %xmm9, %xmm6; \ + pshufd $0x93, %xmm1, %xmm1; \ + pshufd $0x93, %xmm9, %xmm9; \ + pxor %xmm5, %xmm2; \ + pxor %xmm7, %xmm10; \ + paddd %xmm2, %xmm4; \ + paddd %xmm10, %xmm6; \ + movdqa %xmm4, %xmm5; \ + movdqa %xmm6, %xmm7; \ + pslld $13, %xmm4; \ + pslld $13, %xmm6; \ + psrld $19, %xmm5; \ + psrld $19, %xmm7; \ + pxor %xmm4, %xmm3; \ + pxor %xmm6, %xmm11; \ + movdqa %xmm2, %xmm4; \ + movdqa %xmm10, %xmm6; \ + pshufd $0x4e, %xmm2, %xmm2; \ + pshufd $0x4e, %xmm10, %xmm10; \ + pxor %xmm5, %xmm3; \ + pxor %xmm7, %xmm11; \ + paddd %xmm3, %xmm4; \ + paddd %xmm11, %xmm6; \ + movdqa %xmm4, %xmm5; \ + movdqa %xmm6, %xmm7; \ + pslld $18, %xmm4; \ + pslld $18, %xmm6; \ + psrld $14, %xmm5; \ + psrld $14, %xmm7; \ + pxor %xmm4, %xmm0; \ + pxor %xmm6, %xmm8; \ + pshufd $0x39, %xmm3, %xmm3; \ + pshufd $0x39, %xmm11, %xmm11; \ + pxor %xmm5, %xmm0; \ + pxor %xmm7, %xmm8; \ + + +#define xmm_salsa8_core_2way() \ + xmm_salsa8_core_2way_doubleround(); \ + xmm_salsa8_core_2way_doubleround(); \ + xmm_salsa8_core_2way_doubleround(); \ + xmm_salsa8_core_2way_doubleround(); \ + + + + .text + .align 16 + .globl scrypt_core_2way + .globl _scrypt_core_2way +scrypt_core_2way: +_scrypt_core_2way: + pushq %rbx + pushq %rbp +#if defined(WIN64) + subq $176, %rsp + movdqa %xmm6, 8(%rsp) + movdqa %xmm7, 24(%rsp) + movdqa %xmm8, 40(%rsp) + movdqa %xmm9, 56(%rsp) + movdqa %xmm10, 72(%rsp) + movdqa %xmm11, 88(%rsp) + movdqa %xmm12, 104(%rsp) + movdqa %xmm13, 120(%rsp) + movdqa %xmm14, 136(%rsp) + movdqa %xmm15, 152(%rsp) + pushq %rdi + pushq %rsi + movq %rcx, %rdi + movq %rdx, %rsi + movq %r8, %rdx +#endif + subq $264, %rsp + + scrypt_shuffle(%rdi, 0, %rsp, 0) + scrypt_shuffle(%rdi, 64, %rsp, 64) + scrypt_shuffle(%rsi, 0, %rsp, 128) + scrypt_shuffle(%rsi, 64, %rsp, 192) + + movdqa 192(%rsp), %xmm12 + movdqa 208(%rsp), %xmm13 + movdqa 224(%rsp), %xmm14 + movdqa 240(%rsp), %xmm15 + + movq %rdx, %rbp + leaq 262144(%rdx), %rcx +scrypt_core_2way_loop1: + movdqa 0(%rsp), %xmm0 + movdqa 16(%rsp), %xmm1 + movdqa 32(%rsp), %xmm2 + movdqa 48(%rsp), %xmm3 + movdqa 64(%rsp), %xmm4 + movdqa 80(%rsp), %xmm5 + movdqa 96(%rsp), %xmm6 + movdqa 112(%rsp), %xmm7 + movdqa 128(%rsp), %xmm8 + movdqa 144(%rsp), %xmm9 + movdqa 160(%rsp), %xmm10 + movdqa 176(%rsp), %xmm11 + pxor %xmm4, %xmm0 + pxor %xmm5, %xmm1 + pxor %xmm6, %xmm2 + pxor %xmm7, %xmm3 + movdqa %xmm0, 0(%rbp) + movdqa %xmm1, 16(%rbp) + movdqa %xmm2, 32(%rbp) + movdqa %xmm3, 48(%rbp) + movdqa %xmm4, 64(%rbp) + movdqa %xmm5, 80(%rbp) + movdqa %xmm6, 96(%rbp) + movdqa %xmm7, 112(%rbp) + pxor %xmm12, %xmm8 + pxor %xmm13, %xmm9 + pxor %xmm14, %xmm10 + pxor %xmm15, %xmm11 + movdqa %xmm8, 128(%rbp) + movdqa %xmm9, 144(%rbp) + movdqa %xmm10, 160(%rbp) + movdqa %xmm11, 176(%rbp) + movdqa %xmm12, 192(%rbp) + movdqa %xmm13, 208(%rbp) + movdqa %xmm14, 224(%rbp) + movdqa %xmm15, 240(%rbp) + + xmm_salsa8_core_2way() + paddd 0(%rbp), %xmm0 + paddd 16(%rbp), %xmm1 + paddd 32(%rbp), %xmm2 + paddd 48(%rbp), %xmm3 + paddd 128(%rbp), %xmm8 + paddd 144(%rbp), %xmm9 + paddd 160(%rbp), %xmm10 + paddd 176(%rbp), %xmm11 + movdqa %xmm0, 0(%rsp) + movdqa %xmm1, 16(%rsp) + movdqa %xmm2, 32(%rsp) + movdqa %xmm3, 48(%rsp) + movdqa %xmm8, 128(%rsp) + movdqa %xmm9, 144(%rsp) + movdqa %xmm10, 160(%rsp) + movdqa %xmm11, 176(%rsp) + + pxor 64(%rsp), %xmm0 + pxor 80(%rsp), %xmm1 + pxor 96(%rsp), %xmm2 + pxor 112(%rsp), %xmm3 + pxor %xmm12, %xmm8 + pxor %xmm13, %xmm9 + pxor %xmm14, %xmm10 + pxor %xmm15, %xmm11 + movdqa %xmm0, 64(%rsp) + movdqa %xmm1, 80(%rsp) + movdqa %xmm2, 96(%rsp) + movdqa %xmm3, 112(%rsp) + movdqa %xmm8, %xmm12 + movdqa %xmm9, %xmm13 + movdqa %xmm10, %xmm14 + movdqa %xmm11, %xmm15 + xmm_salsa8_core_2way() + paddd 64(%rsp), %xmm0 + paddd 80(%rsp), %xmm1 + paddd 96(%rsp), %xmm2 + paddd 112(%rsp), %xmm3 + paddd %xmm8, %xmm12 + paddd %xmm9, %xmm13 + paddd %xmm10, %xmm14 + paddd %xmm11, %xmm15 + movdqa %xmm0, 64(%rsp) + movdqa %xmm1, 80(%rsp) + movdqa %xmm2, 96(%rsp) + movdqa %xmm3, 112(%rsp) + + addq $256, %rbp + cmpq %rcx, %rbp + jne scrypt_core_2way_loop1 + + movq $1024, %rcx +scrypt_core_2way_loop2: + movdqa 0(%rsp), %xmm0 + movdqa 16(%rsp), %xmm1 + movdqa 32(%rsp), %xmm2 + movdqa 48(%rsp), %xmm3 + movdqa 64(%rsp), %xmm4 + movdqa 80(%rsp), %xmm5 + movdqa 96(%rsp), %xmm6 + movdqa 112(%rsp), %xmm7 + movdqa 128(%rsp), %xmm8 + movdqa 144(%rsp), %xmm9 + movdqa 160(%rsp), %xmm10 + movdqa 176(%rsp), %xmm11 + movd %xmm4, %ebp + andl $1023, %ebp + shll $8, %ebp + pxor 0(%rdx, %rbp), %xmm0 + pxor 16(%rdx, %rbp), %xmm1 + pxor 32(%rdx, %rbp), %xmm2 + pxor 48(%rdx, %rbp), %xmm3 + movd %xmm12, %ebx + andl $1023, %ebx + shll $8, %ebx + addl $128, %ebx + pxor 0(%rdx, %rbx), %xmm8 + pxor 16(%rdx, %rbx), %xmm9 + pxor 32(%rdx, %rbx), %xmm10 + pxor 48(%rdx, %rbx), %xmm11 + + pxor %xmm4, %xmm0 + pxor %xmm5, %xmm1 + pxor %xmm6, %xmm2 + pxor %xmm7, %xmm3 + pxor %xmm12, %xmm8 + pxor %xmm13, %xmm9 + pxor %xmm14, %xmm10 + pxor %xmm15, %xmm11 + movdqa %xmm0, 0(%rsp) + movdqa %xmm1, 16(%rsp) + movdqa %xmm2, 32(%rsp) + movdqa %xmm3, 48(%rsp) + movdqa %xmm8, 128(%rsp) + movdqa %xmm9, 144(%rsp) + movdqa %xmm10, 160(%rsp) + movdqa %xmm11, 176(%rsp) + xmm_salsa8_core_2way() + paddd 0(%rsp), %xmm0 + paddd 16(%rsp), %xmm1 + paddd 32(%rsp), %xmm2 + paddd 48(%rsp), %xmm3 + paddd 128(%rsp), %xmm8 + paddd 144(%rsp), %xmm9 + paddd 160(%rsp), %xmm10 + paddd 176(%rsp), %xmm11 + movdqa %xmm0, 0(%rsp) + movdqa %xmm1, 16(%rsp) + movdqa %xmm2, 32(%rsp) + movdqa %xmm3, 48(%rsp) + movdqa %xmm8, 128(%rsp) + movdqa %xmm9, 144(%rsp) + movdqa %xmm10, 160(%rsp) + movdqa %xmm11, 176(%rsp) + + pxor 64(%rdx, %rbp), %xmm0 + pxor 80(%rdx, %rbp), %xmm1 + pxor 96(%rdx, %rbp), %xmm2 + pxor 112(%rdx, %rbp), %xmm3 + pxor 64(%rdx, %rbx), %xmm8 + pxor 80(%rdx, %rbx), %xmm9 + pxor 96(%rdx, %rbx), %xmm10 + pxor 112(%rdx, %rbx), %xmm11 + pxor 64(%rsp), %xmm0 + pxor 80(%rsp), %xmm1 + pxor 96(%rsp), %xmm2 + pxor 112(%rsp), %xmm3 + pxor %xmm12, %xmm8 + pxor %xmm13, %xmm9 + pxor %xmm14, %xmm10 + pxor %xmm15, %xmm11 + movdqa %xmm0, 64(%rsp) + movdqa %xmm1, 80(%rsp) + movdqa %xmm2, 96(%rsp) + movdqa %xmm3, 112(%rsp) + movdqa %xmm8, %xmm12 + movdqa %xmm9, %xmm13 + movdqa %xmm10, %xmm14 + movdqa %xmm11, %xmm15 + xmm_salsa8_core_2way() + paddd 64(%rsp), %xmm0 + paddd 80(%rsp), %xmm1 + paddd 96(%rsp), %xmm2 + paddd 112(%rsp), %xmm3 + paddd %xmm8, %xmm12 + paddd %xmm9, %xmm13 + paddd %xmm10, %xmm14 + paddd %xmm11, %xmm15 + movdqa %xmm0, 64(%rsp) + movdqa %xmm1, 80(%rsp) + movdqa %xmm2, 96(%rsp) + movdqa %xmm3, 112(%rsp) + + subq $1, %rcx + ja scrypt_core_2way_loop2 + + movdqa %xmm12, 192(%rsp) + movdqa %xmm13, 208(%rsp) + movdqa %xmm14, 224(%rsp) + movdqa %xmm15, 240(%rsp) + + scrypt_shuffle(%rsp, 0, %rdi, 0) + scrypt_shuffle(%rsp, 64, %rdi, 64) + scrypt_shuffle(%rsp, 128, %rsi, 0) + scrypt_shuffle(%rsp, 192, %rsi, 64) + + addq $264, %rsp +#if defined(WIN64) + popq %rsi + popq %rdi + movdqa 8(%rsp), %xmm6 + movdqa 24(%rsp), %xmm7 + movdqa 40(%rsp), %xmm8 + movdqa 56(%rsp), %xmm9 + movdqa 72(%rsp), %xmm10 + movdqa 88(%rsp), %xmm11 + movdqa 104(%rsp), %xmm12 + movdqa 120(%rsp), %xmm13 + movdqa 136(%rsp), %xmm14 + movdqa 152(%rsp), %xmm15 + addq $176, %rsp +#endif + popq %rbp + popq %rbx + ret + + +#define xmm_salsa8_core_3way_doubleround() \ + movdqa %xmm1, %xmm4; \ + movdqa %xmm9, %xmm6; \ + movdqa %xmm13, %xmm7; \ + paddd %xmm0, %xmm4; \ + paddd %xmm8, %xmm6; \ + paddd %xmm12, %xmm7; \ + movdqa %xmm4, %xmm5; \ + pslld $7, %xmm4; \ + psrld $25, %xmm5; \ + pxor %xmm4, %xmm3; \ + pxor %xmm5, %xmm3; \ + movdqa %xmm0, %xmm4; \ + movdqa %xmm6, %xmm5; \ + pslld $7, %xmm6; \ + psrld $25, %xmm5; \ + pxor %xmm6, %xmm11; \ + pxor %xmm5, %xmm11; \ + movdqa %xmm8, %xmm6; \ + movdqa %xmm7, %xmm5; \ + pslld $7, %xmm7; \ + psrld $25, %xmm5; \ + pxor %xmm7, %xmm15; \ + pxor %xmm5, %xmm15; \ + movdqa %xmm12, %xmm7; \ + paddd %xmm3, %xmm4; \ + paddd %xmm11, %xmm6; \ + paddd %xmm15, %xmm7; \ + movdqa %xmm4, %xmm5; \ + pslld $9, %xmm4; \ + psrld $23, %xmm5; \ + pxor %xmm4, %xmm2; \ + movdqa %xmm3, %xmm4; \ + pshufd $0x93, %xmm3, %xmm3; \ + pxor %xmm5, %xmm2; \ + movdqa %xmm6, %xmm5; \ + pslld $9, %xmm6; \ + psrld $23, %xmm5; \ + pxor %xmm6, %xmm10; \ + movdqa %xmm11, %xmm6; \ + pshufd $0x93, %xmm11, %xmm11; \ + pxor %xmm5, %xmm10; \ + movdqa %xmm7, %xmm5; \ + pslld $9, %xmm7; \ + psrld $23, %xmm5; \ + pxor %xmm7, %xmm14; \ + movdqa %xmm15, %xmm7; \ + pshufd $0x93, %xmm15, %xmm15; \ + pxor %xmm5, %xmm14; \ + paddd %xmm2, %xmm4; \ + paddd %xmm10, %xmm6; \ + paddd %xmm14, %xmm7; \ + movdqa %xmm4, %xmm5; \ + pslld $13, %xmm4; \ + psrld $19, %xmm5; \ + pxor %xmm4, %xmm1; \ + movdqa %xmm2, %xmm4; \ + pshufd $0x4e, %xmm2, %xmm2; \ + pxor %xmm5, %xmm1; \ + movdqa %xmm6, %xmm5; \ + pslld $13, %xmm6; \ + psrld $19, %xmm5; \ + pxor %xmm6, %xmm9; \ + movdqa %xmm10, %xmm6; \ + pshufd $0x4e, %xmm10, %xmm10; \ + pxor %xmm5, %xmm9; \ + movdqa %xmm7, %xmm5; \ + pslld $13, %xmm7; \ + psrld $19, %xmm5; \ + pxor %xmm7, %xmm13; \ + movdqa %xmm14, %xmm7; \ + pshufd $0x4e, %xmm14, %xmm14; \ + pxor %xmm5, %xmm13; \ + paddd %xmm1, %xmm4; \ + paddd %xmm9, %xmm6; \ + paddd %xmm13, %xmm7; \ + movdqa %xmm4, %xmm5; \ + pslld $18, %xmm4; \ + psrld $14, %xmm5; \ + pxor %xmm4, %xmm0; \ + pshufd $0x39, %xmm1, %xmm1; \ + pxor %xmm5, %xmm0; \ + movdqa %xmm3, %xmm4; \ + movdqa %xmm6, %xmm5; \ + pslld $18, %xmm6; \ + psrld $14, %xmm5; \ + pxor %xmm6, %xmm8; \ + pshufd $0x39, %xmm9, %xmm9; \ + pxor %xmm5, %xmm8; \ + movdqa %xmm11, %xmm6; \ + movdqa %xmm7, %xmm5; \ + pslld $18, %xmm7; \ + psrld $14, %xmm5; \ + pxor %xmm7, %xmm12; \ + pshufd $0x39, %xmm13, %xmm13; \ + pxor %xmm5, %xmm12; \ + movdqa %xmm15, %xmm7; \ + paddd %xmm0, %xmm4; \ + paddd %xmm8, %xmm6; \ + paddd %xmm12, %xmm7; \ + movdqa %xmm4, %xmm5; \ + pslld $7, %xmm4; \ + psrld $25, %xmm5; \ + pxor %xmm4, %xmm1; \ + pxor %xmm5, %xmm1; \ + movdqa %xmm0, %xmm4; \ + movdqa %xmm6, %xmm5; \ + pslld $7, %xmm6; \ + psrld $25, %xmm5; \ + pxor %xmm6, %xmm9; \ + pxor %xmm5, %xmm9; \ + movdqa %xmm8, %xmm6; \ + movdqa %xmm7, %xmm5; \ + pslld $7, %xmm7; \ + psrld $25, %xmm5; \ + pxor %xmm7, %xmm13; \ + pxor %xmm5, %xmm13; \ + movdqa %xmm12, %xmm7; \ + paddd %xmm1, %xmm4; \ + paddd %xmm9, %xmm6; \ + paddd %xmm13, %xmm7; \ + movdqa %xmm4, %xmm5; \ + pslld $9, %xmm4; \ + psrld $23, %xmm5; \ + pxor %xmm4, %xmm2; \ + movdqa %xmm1, %xmm4; \ + pshufd $0x93, %xmm1, %xmm1; \ + pxor %xmm5, %xmm2; \ + movdqa %xmm6, %xmm5; \ + pslld $9, %xmm6; \ + psrld $23, %xmm5; \ + pxor %xmm6, %xmm10; \ + movdqa %xmm9, %xmm6; \ + pshufd $0x93, %xmm9, %xmm9; \ + pxor %xmm5, %xmm10; \ + movdqa %xmm7, %xmm5; \ + pslld $9, %xmm7; \ + psrld $23, %xmm5; \ + pxor %xmm7, %xmm14; \ + movdqa %xmm13, %xmm7; \ + pshufd $0x93, %xmm13, %xmm13; \ + pxor %xmm5, %xmm14; \ + paddd %xmm2, %xmm4; \ + paddd %xmm10, %xmm6; \ + paddd %xmm14, %xmm7; \ + movdqa %xmm4, %xmm5; \ + pslld $13, %xmm4; \ + psrld $19, %xmm5; \ + pxor %xmm4, %xmm3; \ + movdqa %xmm2, %xmm4; \ + pshufd $0x4e, %xmm2, %xmm2; \ + pxor %xmm5, %xmm3; \ + movdqa %xmm6, %xmm5; \ + pslld $13, %xmm6; \ + psrld $19, %xmm5; \ + pxor %xmm6, %xmm11; \ + movdqa %xmm10, %xmm6; \ + pshufd $0x4e, %xmm10, %xmm10; \ + pxor %xmm5, %xmm11; \ + movdqa %xmm7, %xmm5; \ + pslld $13, %xmm7; \ + psrld $19, %xmm5; \ + pxor %xmm7, %xmm15; \ + movdqa %xmm14, %xmm7; \ + pshufd $0x4e, %xmm14, %xmm14; \ + pxor %xmm5, %xmm15; \ + paddd %xmm3, %xmm4; \ + paddd %xmm11, %xmm6; \ + paddd %xmm15, %xmm7; \ + movdqa %xmm4, %xmm5; \ + pslld $18, %xmm4; \ + psrld $14, %xmm5; \ + pxor %xmm4, %xmm0; \ + pshufd $0x39, %xmm3, %xmm3; \ + pxor %xmm5, %xmm0; \ + movdqa %xmm6, %xmm5; \ + pslld $18, %xmm6; \ + psrld $14, %xmm5; \ + pxor %xmm6, %xmm8; \ + pshufd $0x39, %xmm11, %xmm11; \ + pxor %xmm5, %xmm8; \ + movdqa %xmm7, %xmm5; \ + pslld $18, %xmm7; \ + psrld $14, %xmm5; \ + pxor %xmm7, %xmm12; \ + pshufd $0x39, %xmm15, %xmm15; \ + pxor %xmm5, %xmm12; \ + + +#define xmm_salsa8_core_3way() \ + xmm_salsa8_core_3way_doubleround(); \ + xmm_salsa8_core_3way_doubleround(); \ + xmm_salsa8_core_3way_doubleround(); \ + xmm_salsa8_core_3way_doubleround(); \ + + + .text + .align 16 + .globl scrypt_core_3way + .globl _scrypt_core_3way +scrypt_core_3way: +_scrypt_core_3way: + pushq %rbx + pushq %rbp +#if defined(WIN64) + subq $176, %rsp + movdqa %xmm6, 8(%rsp) + movdqa %xmm7, 24(%rsp) + movdqa %xmm8, 40(%rsp) + movdqa %xmm9, 56(%rsp) + movdqa %xmm10, 72(%rsp) + movdqa %xmm11, 88(%rsp) + movdqa %xmm12, 104(%rsp) + movdqa %xmm13, 120(%rsp) + movdqa %xmm14, 136(%rsp) + movdqa %xmm15, 152(%rsp) + pushq %rdi + pushq %rsi + movq %rcx, %rdi + movq %rdx, %rsi + movq %r8, %rdx + movq %r9, %rcx +#endif + subq $392, %rsp + + scrypt_shuffle(%rdi, 0, %rsp, 0) + scrypt_shuffle(%rdi, 64, %rsp, 64) + scrypt_shuffle(%rsi, 0, %rsp, 128) + scrypt_shuffle(%rsi, 64, %rsp, 192) + scrypt_shuffle(%rdx, 0, %rsp, 256) + scrypt_shuffle(%rdx, 64, %rsp, 320) + + movdqa 128+64(%rsp), %xmm8 + movdqa 128+80(%rsp), %xmm9 + movdqa 128+96(%rsp), %xmm10 + movdqa 128+112(%rsp), %xmm11 + + movq %rcx, %rbp + leaq 3*131072(%rcx), %rax +scrypt_core_3way_loop1: + movdqa %xmm8, %xmm12 + movdqa %xmm9, %xmm13 + movdqa %xmm10, %xmm14 + movdqa %xmm11, %xmm15 + movdqa 0(%rsp), %xmm0 + movdqa 16(%rsp), %xmm1 + movdqa 32(%rsp), %xmm2 + movdqa 48(%rsp), %xmm3 + movdqa 64(%rsp), %xmm4 + movdqa 80(%rsp), %xmm5 + movdqa 96(%rsp), %xmm6 + movdqa 112(%rsp), %xmm7 + movdqa 128+0(%rsp), %xmm8 + movdqa 128+16(%rsp), %xmm9 + movdqa 128+32(%rsp), %xmm10 + movdqa 128+48(%rsp), %xmm11 + pxor %xmm4, %xmm0 + pxor %xmm5, %xmm1 + pxor %xmm6, %xmm2 + pxor %xmm7, %xmm3 + movdqa %xmm0, 0(%rbp) + movdqa %xmm1, 16(%rbp) + movdqa %xmm2, 32(%rbp) + movdqa %xmm3, 48(%rbp) + movdqa %xmm4, 64(%rbp) + movdqa %xmm5, 80(%rbp) + movdqa %xmm6, 96(%rbp) + movdqa %xmm7, 112(%rbp) + pxor %xmm12, %xmm8 + pxor %xmm13, %xmm9 + pxor %xmm14, %xmm10 + pxor %xmm15, %xmm11 + movdqa %xmm8, 128+0(%rbp) + movdqa %xmm9, 128+16(%rbp) + movdqa %xmm10, 128+32(%rbp) + movdqa %xmm11, 128+48(%rbp) + movdqa %xmm12, 128+64(%rbp) + movdqa %xmm13, 128+80(%rbp) + movdqa %xmm14, 128+96(%rbp) + movdqa %xmm15, 128+112(%rbp) + movdqa 256+0(%rsp), %xmm12 + movdqa 256+16(%rsp), %xmm13 + movdqa 256+32(%rsp), %xmm14 + movdqa 256+48(%rsp), %xmm15 + movdqa 256+64(%rsp), %xmm4 + movdqa 256+80(%rsp), %xmm5 + movdqa 256+96(%rsp), %xmm6 + movdqa 256+112(%rsp), %xmm7 + pxor %xmm4, %xmm12 + pxor %xmm5, %xmm13 + pxor %xmm6, %xmm14 + pxor %xmm7, %xmm15 + movdqa %xmm12, 256+0(%rbp) + movdqa %xmm13, 256+16(%rbp) + movdqa %xmm14, 256+32(%rbp) + movdqa %xmm15, 256+48(%rbp) + movdqa %xmm4, 256+64(%rbp) + movdqa %xmm5, 256+80(%rbp) + movdqa %xmm6, 256+96(%rbp) + movdqa %xmm7, 256+112(%rbp) + + xmm_salsa8_core_3way() + paddd 0(%rbp), %xmm0 + paddd 16(%rbp), %xmm1 + paddd 32(%rbp), %xmm2 + paddd 48(%rbp), %xmm3 + paddd 128+0(%rbp), %xmm8 + paddd 128+16(%rbp), %xmm9 + paddd 128+32(%rbp), %xmm10 + paddd 128+48(%rbp), %xmm11 + paddd 256+0(%rbp), %xmm12 + paddd 256+16(%rbp), %xmm13 + paddd 256+32(%rbp), %xmm14 + paddd 256+48(%rbp), %xmm15 + movdqa %xmm0, 0(%rsp) + movdqa %xmm1, 16(%rsp) + movdqa %xmm2, 32(%rsp) + movdqa %xmm3, 48(%rsp) + movdqa %xmm8, 128+0(%rsp) + movdqa %xmm9, 128+16(%rsp) + movdqa %xmm10, 128+32(%rsp) + movdqa %xmm11, 128+48(%rsp) + movdqa %xmm12, 256+0(%rsp) + movdqa %xmm13, 256+16(%rsp) + movdqa %xmm14, 256+32(%rsp) + movdqa %xmm15, 256+48(%rsp) + + pxor 64(%rsp), %xmm0 + pxor 80(%rsp), %xmm1 + pxor 96(%rsp), %xmm2 + pxor 112(%rsp), %xmm3 + pxor 128+64(%rsp), %xmm8 + pxor 128+80(%rsp), %xmm9 + pxor 128+96(%rsp), %xmm10 + pxor 128+112(%rsp), %xmm11 + pxor 256+64(%rsp), %xmm12 + pxor 256+80(%rsp), %xmm13 + pxor 256+96(%rsp), %xmm14 + pxor 256+112(%rsp), %xmm15 + movdqa %xmm0, 64(%rsp) + movdqa %xmm1, 80(%rsp) + movdqa %xmm2, 96(%rsp) + movdqa %xmm3, 112(%rsp) + movdqa %xmm8, 128+64(%rsp) + movdqa %xmm9, 128+80(%rsp) + movdqa %xmm10, 128+96(%rsp) + movdqa %xmm11, 128+112(%rsp) + movdqa %xmm12, 256+64(%rsp) + movdqa %xmm13, 256+80(%rsp) + movdqa %xmm14, 256+96(%rsp) + movdqa %xmm15, 256+112(%rsp) + xmm_salsa8_core_3way() + paddd 64(%rsp), %xmm0 + paddd 80(%rsp), %xmm1 + paddd 96(%rsp), %xmm2 + paddd 112(%rsp), %xmm3 + paddd 128+64(%rsp), %xmm8 + paddd 128+80(%rsp), %xmm9 + paddd 128+96(%rsp), %xmm10 + paddd 128+112(%rsp), %xmm11 + paddd 256+64(%rsp), %xmm12 + paddd 256+80(%rsp), %xmm13 + paddd 256+96(%rsp), %xmm14 + paddd 256+112(%rsp), %xmm15 + movdqa %xmm0, 64(%rsp) + movdqa %xmm1, 80(%rsp) + movdqa %xmm2, 96(%rsp) + movdqa %xmm3, 112(%rsp) + movdqa %xmm8, 128+64(%rsp) + movdqa %xmm9, 128+80(%rsp) + movdqa %xmm10, 128+96(%rsp) + movdqa %xmm11, 128+112(%rsp) + movdqa %xmm12, 256+64(%rsp) + movdqa %xmm13, 256+80(%rsp) + movdqa %xmm14, 256+96(%rsp) + movdqa %xmm15, 256+112(%rsp) + + addq $3*128, %rbp + cmpq %rax, %rbp + jne scrypt_core_3way_loop1 + + movq $1024, %rax +scrypt_core_3way_loop2: + movl 64(%rsp), %ebp + andl $1023, %ebp + leal (%ebp, %ebp, 2), %ebp + shll $7, %ebp + movl 128+64(%rsp), %ebx + andl $1023, %ebx + leal (%ebx, %ebx, 2), %ebx + shll $7, %ebx + addl $128, %ebx + movl 256+64(%rsp), %r8d + andl $1023, %r8d + leal (%r8d, %r8d, 2), %r8d + shll $7, %r8d + addl $256, %r8d + movdqa 0(%rsp), %xmm0 + movdqa 16(%rsp), %xmm1 + movdqa 32(%rsp), %xmm2 + movdqa 48(%rsp), %xmm3 + movdqa 128+0(%rsp), %xmm8 + movdqa 128+16(%rsp), %xmm9 + movdqa 128+32(%rsp), %xmm10 + movdqa 128+48(%rsp), %xmm11 + movdqa 256+0(%rsp), %xmm12 + movdqa 256+16(%rsp), %xmm13 + movdqa 256+32(%rsp), %xmm14 + movdqa 256+48(%rsp), %xmm15 + pxor 0(%rcx, %rbp), %xmm0 + pxor 16(%rcx, %rbp), %xmm1 + pxor 32(%rcx, %rbp), %xmm2 + pxor 48(%rcx, %rbp), %xmm3 + pxor 0(%rcx, %rbx), %xmm8 + pxor 16(%rcx, %rbx), %xmm9 + pxor 32(%rcx, %rbx), %xmm10 + pxor 48(%rcx, %rbx), %xmm11 + pxor 0(%rcx, %r8), %xmm12 + pxor 16(%rcx, %r8), %xmm13 + pxor 32(%rcx, %r8), %xmm14 + pxor 48(%rcx, %r8), %xmm15 + + pxor 64(%rsp), %xmm0 + pxor 80(%rsp), %xmm1 + pxor 96(%rsp), %xmm2 + pxor 112(%rsp), %xmm3 + pxor 128+64(%rsp), %xmm8 + pxor 128+80(%rsp), %xmm9 + pxor 128+96(%rsp), %xmm10 + pxor 128+112(%rsp), %xmm11 + pxor 256+64(%rsp), %xmm12 + pxor 256+80(%rsp), %xmm13 + pxor 256+96(%rsp), %xmm14 + pxor 256+112(%rsp), %xmm15 + movdqa %xmm0, 0(%rsp) + movdqa %xmm1, 16(%rsp) + movdqa %xmm2, 32(%rsp) + movdqa %xmm3, 48(%rsp) + movdqa %xmm8, 128+0(%rsp) + movdqa %xmm9, 128+16(%rsp) + movdqa %xmm10, 128+32(%rsp) + movdqa %xmm11, 128+48(%rsp) + movdqa %xmm12, 256+0(%rsp) + movdqa %xmm13, 256+16(%rsp) + movdqa %xmm14, 256+32(%rsp) + movdqa %xmm15, 256+48(%rsp) + xmm_salsa8_core_3way() + paddd 0(%rsp), %xmm0 + paddd 16(%rsp), %xmm1 + paddd 32(%rsp), %xmm2 + paddd 48(%rsp), %xmm3 + paddd 128+0(%rsp), %xmm8 + paddd 128+16(%rsp), %xmm9 + paddd 128+32(%rsp), %xmm10 + paddd 128+48(%rsp), %xmm11 + paddd 256+0(%rsp), %xmm12 + paddd 256+16(%rsp), %xmm13 + paddd 256+32(%rsp), %xmm14 + paddd 256+48(%rsp), %xmm15 + movdqa %xmm0, 0(%rsp) + movdqa %xmm1, 16(%rsp) + movdqa %xmm2, 32(%rsp) + movdqa %xmm3, 48(%rsp) + movdqa %xmm8, 128+0(%rsp) + movdqa %xmm9, 128+16(%rsp) + movdqa %xmm10, 128+32(%rsp) + movdqa %xmm11, 128+48(%rsp) + movdqa %xmm12, 256+0(%rsp) + movdqa %xmm13, 256+16(%rsp) + movdqa %xmm14, 256+32(%rsp) + movdqa %xmm15, 256+48(%rsp) + + pxor 64(%rcx, %rbp), %xmm0 + pxor 80(%rcx, %rbp), %xmm1 + pxor 96(%rcx, %rbp), %xmm2 + pxor 112(%rcx, %rbp), %xmm3 + pxor 64(%rcx, %rbx), %xmm8 + pxor 80(%rcx, %rbx), %xmm9 + pxor 96(%rcx, %rbx), %xmm10 + pxor 112(%rcx, %rbx), %xmm11 + pxor 64(%rcx, %r8), %xmm12 + pxor 80(%rcx, %r8), %xmm13 + pxor 96(%rcx, %r8), %xmm14 + pxor 112(%rcx, %r8), %xmm15 + pxor 64(%rsp), %xmm0 + pxor 80(%rsp), %xmm1 + pxor 96(%rsp), %xmm2 + pxor 112(%rsp), %xmm3 + pxor 128+64(%rsp), %xmm8 + pxor 128+80(%rsp), %xmm9 + pxor 128+96(%rsp), %xmm10 + pxor 128+112(%rsp), %xmm11 + pxor 256+64(%rsp), %xmm12 + pxor 256+80(%rsp), %xmm13 + pxor 256+96(%rsp), %xmm14 + pxor 256+112(%rsp), %xmm15 + movdqa %xmm0, 64(%rsp) + movdqa %xmm1, 80(%rsp) + movdqa %xmm2, 96(%rsp) + movdqa %xmm3, 112(%rsp) + movdqa %xmm8, 128+64(%rsp) + movdqa %xmm9, 128+80(%rsp) + movdqa %xmm10, 128+96(%rsp) + movdqa %xmm11, 128+112(%rsp) + movdqa %xmm12, 256+64(%rsp) + movdqa %xmm13, 256+80(%rsp) + movdqa %xmm14, 256+96(%rsp) + movdqa %xmm15, 256+112(%rsp) + xmm_salsa8_core_3way() + paddd 64(%rsp), %xmm0 + paddd 80(%rsp), %xmm1 + paddd 96(%rsp), %xmm2 + paddd 112(%rsp), %xmm3 + paddd 128+64(%rsp), %xmm8 + paddd 128+80(%rsp), %xmm9 + paddd 128+96(%rsp), %xmm10 + paddd 128+112(%rsp), %xmm11 + paddd 256+64(%rsp), %xmm12 + paddd 256+80(%rsp), %xmm13 + paddd 256+96(%rsp), %xmm14 + paddd 256+112(%rsp), %xmm15 + movdqa %xmm0, 64(%rsp) + movdqa %xmm1, 80(%rsp) + movdqa %xmm2, 96(%rsp) + movdqa %xmm3, 112(%rsp) + movdqa %xmm8, 128+64(%rsp) + movdqa %xmm9, 128+80(%rsp) + movdqa %xmm10, 128+96(%rsp) + movdqa %xmm11, 128+112(%rsp) + movdqa %xmm12, 256+64(%rsp) + movdqa %xmm13, 256+80(%rsp) + movdqa %xmm14, 256+96(%rsp) + movdqa %xmm15, 256+112(%rsp) + + subq $1, %rax + ja scrypt_core_3way_loop2 + + scrypt_shuffle(%rsp, 0, %rdi, 0) + scrypt_shuffle(%rsp, 64, %rdi, 64) + scrypt_shuffle(%rsp, 128, %rsi, 0) + scrypt_shuffle(%rsp, 192, %rsi, 64) + scrypt_shuffle(%rsp, 256, %rdx, 0) + scrypt_shuffle(%rsp, 320, %rdx, 64) + + addq $392, %rsp +#if defined(WIN64) + popq %rsi + popq %rdi + movdqa 8(%rsp), %xmm6 + movdqa 24(%rsp), %xmm7 + movdqa 40(%rsp), %xmm8 + movdqa 56(%rsp), %xmm9 + movdqa 72(%rsp), %xmm10 + movdqa 88(%rsp), %xmm11 + movdqa 104(%rsp), %xmm12 + movdqa 120(%rsp), %xmm13 + movdqa 136(%rsp), %xmm14 + movdqa 152(%rsp), %xmm15 + addq $176, %rsp +#endif + popq %rbp + popq %rbx + ret + +#endif diff --git a/src/scrypt.cpp b/src/scrypt.cpp new file mode 100644 index 0000000..06ef53c --- /dev/null +++ b/src/scrypt.cpp @@ -0,0 +1,198 @@ +/*- + * Copyright 2009 Colin Percival, 2011 ArtForz, 2011 pooler, 2013 Balthazar + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + * + * This file was originally written by Colin Percival as part of the Tarsnap + * online backup system. + */ + +#include +#include + +#include "scrypt.h" +#include "pbkdf2.h" + +#include "util.h" +#include "net.h" + +#define SCRYPT_BUFFER_SIZE (131072 + 63) + +#if defined (OPTIMIZED_SALSA) && ( defined (__x86_64__) || defined (__i386__) || defined(__arm__) ) +extern "C" void scrypt_core(unsigned int *X, unsigned int *V); +#else +// Generic scrypt_core implementation + +static inline void xor_salsa8(unsigned int B[16], const unsigned int Bx[16]) +{ + unsigned int x00,x01,x02,x03,x04,x05,x06,x07,x08,x09,x10,x11,x12,x13,x14,x15; + int i; + + x00 = (B[0] ^= Bx[0]); + x01 = (B[1] ^= Bx[1]); + x02 = (B[2] ^= Bx[2]); + x03 = (B[3] ^= Bx[3]); + x04 = (B[4] ^= Bx[4]); + x05 = (B[5] ^= Bx[5]); + x06 = (B[6] ^= Bx[6]); + x07 = (B[7] ^= Bx[7]); + x08 = (B[8] ^= Bx[8]); + x09 = (B[9] ^= Bx[9]); + x10 = (B[10] ^= Bx[10]); + x11 = (B[11] ^= Bx[11]); + x12 = (B[12] ^= Bx[12]); + x13 = (B[13] ^= Bx[13]); + x14 = (B[14] ^= Bx[14]); + x15 = (B[15] ^= Bx[15]); + for (i = 0; i < 8; i += 2) { +#define R(a, b) (((a) << (b)) | ((a) >> (32 - (b)))) + /* Operate on columns. */ + x04 ^= R(x00+x12, 7); x09 ^= R(x05+x01, 7); + x14 ^= R(x10+x06, 7); x03 ^= R(x15+x11, 7); + + x08 ^= R(x04+x00, 9); x13 ^= R(x09+x05, 9); + x02 ^= R(x14+x10, 9); x07 ^= R(x03+x15, 9); + + x12 ^= R(x08+x04,13); x01 ^= R(x13+x09,13); + x06 ^= R(x02+x14,13); x11 ^= R(x07+x03,13); + + x00 ^= R(x12+x08,18); x05 ^= R(x01+x13,18); + x10 ^= R(x06+x02,18); x15 ^= R(x11+x07,18); + + /* Operate on rows. */ + x01 ^= R(x00+x03, 7); x06 ^= R(x05+x04, 7); + x11 ^= R(x10+x09, 7); x12 ^= R(x15+x14, 7); + + x02 ^= R(x01+x00, 9); x07 ^= R(x06+x05, 9); + x08 ^= R(x11+x10, 9); x13 ^= R(x12+x15, 9); + + x03 ^= R(x02+x01,13); x04 ^= R(x07+x06,13); + x09 ^= R(x08+x11,13); x14 ^= R(x13+x12,13); + + x00 ^= R(x03+x02,18); x05 ^= R(x04+x07,18); + x10 ^= R(x09+x08,18); x15 ^= R(x14+x13,18); +#undef R + } + B[0] += x00; + B[1] += x01; + B[2] += x02; + B[3] += x03; + B[4] += x04; + B[5] += x05; + B[6] += x06; + B[7] += x07; + B[8] += x08; + B[9] += x09; + B[10] += x10; + B[11] += x11; + B[12] += x12; + B[13] += x13; + B[14] += x14; + B[15] += x15; +} + +static inline void scrypt_core(unsigned int *X, unsigned int *V) +{ + unsigned int i, j, k; + + for (i = 0; i < 1024; i++) { + memcpy(&V[i * 32], X, 128); + xor_salsa8(&X[0], &X[16]); + xor_salsa8(&X[16], &X[0]); + } + for (i = 0; i < 1024; i++) { + j = 32 * (X[16] & 1023); + for (k = 0; k < 32; k++) + X[k] ^= V[j + k]; + xor_salsa8(&X[0], &X[16]); + xor_salsa8(&X[16], &X[0]); + } +} + +#endif + +/* cpu and memory intensive function to transform a 80 byte buffer into a 32 byte output + scratchpad size needs to be at least 63 + (128 * r * p) + (256 * r + 64) + (128 * r * N) bytes + r = 1, p = 1, N = 1024 + */ + +uint256 scrypt_nosalt(const void* input, size_t inputlen, void *scratchpad) +{ + unsigned int *V; + unsigned int X[32]; + uint256 result = 0; + V = (unsigned int *)(((uintptr_t)(scratchpad) + 63) & ~ (uintptr_t)(63)); + + PBKDF2_SHA256((const uint8_t*)input, inputlen, (const uint8_t*)input, inputlen, 1, (uint8_t *)X, 128); + scrypt_core(X, V); + PBKDF2_SHA256((const uint8_t*)input, inputlen, (uint8_t *)X, 128, 1, (uint8_t*)&result, 32); + + return result; +} + +uint256 scrypt(const void* data, size_t datalen, const void* salt, size_t saltlen, void *scratchpad) +{ + unsigned int *V; + unsigned int X[32]; + uint256 result = 0; + V = (unsigned int *)(((uintptr_t)(scratchpad) + 63) & ~ (uintptr_t)(63)); + + PBKDF2_SHA256((const uint8_t*)data, datalen, (const uint8_t*)salt, saltlen, 1, (uint8_t *)X, 128); + scrypt_core(X, V); + PBKDF2_SHA256((const uint8_t*)data, datalen, (uint8_t *)X, 128, 1, (uint8_t*)&result, 32); + + return result; +} + +uint256 scrypt_hash(const void* input, size_t inputlen) +{ + unsigned char scratchpad[SCRYPT_BUFFER_SIZE]; + return scrypt_nosalt(input, inputlen, scratchpad); +} + +uint256 scrypt_salted_hash(const void* input, size_t inputlen, const void* salt, size_t saltlen) +{ + unsigned char scratchpad[SCRYPT_BUFFER_SIZE]; + return scrypt(input, inputlen, salt, saltlen, scratchpad); +} + +uint256 scrypt_salted_multiround_hash(const void* input, size_t inputlen, const void* salt, size_t saltlen, const unsigned int nRounds) +{ + uint256 resultHash = scrypt_salted_hash(input, inputlen, salt, saltlen); + uint256 transitionalHash = resultHash; + + for(unsigned int i = 1; i < nRounds; i++) + { + resultHash = scrypt_salted_hash(input, inputlen, (const void*)&transitionalHash, 32); + transitionalHash = resultHash; + } + + return resultHash; +} + +uint256 scrypt_blockhash(const void* input) +{ + unsigned char scratchpad[SCRYPT_BUFFER_SIZE]; + return scrypt_nosalt(input, 80, scratchpad); +} + diff --git a/src/scrypt.h b/src/scrypt.h new file mode 100644 index 0000000..17afd85 --- /dev/null +++ b/src/scrypt.h @@ -0,0 +1,15 @@ +#ifndef SCRYPT_MINE_H +#define SCRYPT_MINE_H + +#include +#include + +#include "util.h" +#include "net.h" + +uint256 scrypt_salted_multiround_hash(const void* input, size_t inputlen, const void* salt, size_t saltlen, const unsigned int nRounds); +uint256 scrypt_salted_hash(const void* input, size_t inputlen, const void* salt, size_t saltlen); +uint256 scrypt_hash(const void* input, size_t inputlen); +uint256 scrypt_blockhash(const void* input); + +#endif // SCRYPT_MINE_H diff --git a/src/scrypt_mine.cpp b/src/scrypt_mine.cpp new file mode 100644 index 0000000..afca59d --- /dev/null +++ b/src/scrypt_mine.cpp @@ -0,0 +1,208 @@ +/*- + * Copyright 2009 Colin Percival, 2011 ArtForz, 2011 pooler, 2013 Balthazar + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + * + * This file was originally written by Colin Percival as part of the Tarsnap + * online backup system. + */ + +#include +#include +#include + +#include "scrypt_mine.h" +#include "pbkdf2.h" + +#include "util.h" +#include "net.h" + +extern bool fShutdown; +extern bool fGenerateBitcoins; + +extern CBlockIndex* pindexBest; +extern uint32_t nTransactionsUpdated; + + +#if defined(__x86_64__) + +#define SCRYPT_3WAY +#define SCRYPT_BUFFER_SIZE (3 * 131072 + 63) + +extern "C" int scrypt_best_throughput(); +extern "C" void scrypt_core(uint32_t *X, uint32_t *V); +extern "C" void scrypt_core_2way(uint32_t *X, uint32_t *Y, uint32_t *V); +extern "C" void scrypt_core_3way(uint32_t *X, uint32_t *Y, uint32_t *Z, uint32_t *V); + +#elif defined(__i386__) + +#define SCRYPT_BUFFER_SIZE (131072 + 63) + +extern "C" void scrypt_core(uint32_t *X, uint32_t *V); + +#endif + +void *scrypt_buffer_alloc() { + return malloc(SCRYPT_BUFFER_SIZE); +} + +void scrypt_buffer_free(void *scratchpad) +{ + free(scratchpad); +} + +/* cpu and memory intensive function to transform a 80 byte buffer into a 32 byte output + scratchpad size needs to be at least 63 + (128 * r * p) + (256 * r + 64) + (128 * r * N) bytes + r = 1, p = 1, N = 1024 + */ + +static void scrypt(const void* input, size_t inputlen, uint32_t *res, void *scratchpad) +{ + uint32_t *V; + uint32_t X[32]; + V = (uint32_t *)(((uintptr_t)(scratchpad) + 63) & ~ (uintptr_t)(63)); + + PBKDF2_SHA256((const uint8_t*)input, inputlen, (const uint8_t*)input, sizeof(block_header), 1, (uint8_t *)X, 128); + + scrypt_core(X, V); + + PBKDF2_SHA256((const uint8_t*)input, inputlen, (uint8_t *)X, 128, 1, (uint8_t*)res, 32); +} + +void scrypt_hash(const void* input, size_t inputlen, uint32_t *res, void *scratchpad) +{ + return scrypt(input, inputlen, res, scratchpad); +} + +#ifdef SCRYPT_3WAY +static void scrypt_2way(const void *input1, const void *input2, size_t input1len, size_t input2len, uint32_t *res1, uint32_t *res2, void *scratchpad) +{ + uint32_t *V; + uint32_t X[32], Y[32]; + V = (uint32_t *)(((uintptr_t)(scratchpad) + 63) & ~ (uintptr_t)(63)); + + PBKDF2_SHA256((const uint8_t*)input1, input1len, (const uint8_t*)input1, input1len, 1, (uint8_t *)X, 128); + PBKDF2_SHA256((const uint8_t*)input2, input2len, (const uint8_t*)input2, input2len, 1, (uint8_t *)Y, 128); + + scrypt_core_2way(X, Y, V); + + PBKDF2_SHA256((const uint8_t*)input1, input1len, (uint8_t *)X, 128, 1, (uint8_t*)res1, 32); + PBKDF2_SHA256((const uint8_t*)input2, input2len, (uint8_t *)Y, 128, 1, (uint8_t*)res2, 32); +} + +static void scrypt_3way(const void *input1, const void *input2, const void *input3, + size_t input1len, size_t input2len, size_t input3len, uint32_t *res1, uint32_t *res2, uint32_t *res3, + void *scratchpad) +{ + uint32_t *V; + uint32_t X[32], Y[32], Z[32]; + V = (uint32_t *)(((uintptr_t)(scratchpad) + 63) & ~ (uintptr_t)(63)); + + PBKDF2_SHA256((const uint8_t*)input1, input1len, (const uint8_t*)input1, input1len, 1, (uint8_t *)X, 128); + PBKDF2_SHA256((const uint8_t*)input2, input2len, (const uint8_t*)input2, input2len, 1, (uint8_t *)Y, 128); + PBKDF2_SHA256((const uint8_t*)input3, input3len, (const uint8_t*)input3, input3len, 1, (uint8_t *)Z, 128); + + scrypt_core_3way(X, Y, Z, V); + + PBKDF2_SHA256((const uint8_t*)input1, input1len, (uint8_t *)X, 128, 1, (uint8_t*)res1, 32); + PBKDF2_SHA256((const uint8_t*)input2, input2len, (uint8_t *)Y, 128, 1, (uint8_t*)res2, 32); + PBKDF2_SHA256((const uint8_t*)input3, input3len, (uint8_t *)Z, 128, 1, (uint8_t*)res3, 32); +} +#endif + +unsigned int scanhash_scrypt(block_header *pdata, void *scratchbuf, + uint32_t max_nonce, uint32_t &hash_count, + void *result, block_header *res_header) +{ + hash_count = 0; + block_header data = *pdata; + uint32_t hash[8]; + unsigned char *hashc = (unsigned char *) &hash; + +#ifdef SCRYPT_3WAY + block_header data2 = *pdata; + uint32_t hash2[8]; + unsigned char *hashc2 = (unsigned char *) &hash2; + + block_header data3 = *pdata; + uint32_t hash3[8]; + unsigned char *hashc3 = (unsigned char *) &hash3; + + int throughput = scrypt_best_throughput(); +#endif + + uint32_t n = 0; + + while (true) { + + data.nonce = n++; + +#ifdef SCRYPT_3WAY + if (throughput >= 2 && n < max_nonce) { + data2.nonce = n++; + if(throughput >= 3) + { + data3.nonce = n++; + scrypt_3way(&data, &data2, &data3, 80, 80, 80, hash, hash2, hash3, scratchbuf); + hash_count += 3; + + if (hashc3[31] == 0 && hashc3[30] == 0) { + memcpy(result, hash3, 32); + *res_header = data3; + + return data3.nonce; + } + } + else + { + scrypt_2way(&data, &data2, 80, 80, hash, hash2, scratchbuf); + hash_count += 2; + } + + if (hashc2[31] == 0 && hashc2[30] == 0) { + memcpy(result, hash2, 32); + + return data2.nonce; + } + } else { + scrypt(&data, 80, hash, scratchbuf); + hash_count += 1; + } +#else + scrypt(&data, 80, hash, scratchbuf); + hash_count += 1; +#endif + if (hashc[31] == 0 && hashc[30] == 0) { + memcpy(result, hash, 32); + + return data.nonce; + } + + if (n >= max_nonce) { + hash_count = 0xffff + 1; + break; + } + } + + return (unsigned int) -1; +} diff --git a/src/scrypt_mine.h b/src/scrypt_mine.h new file mode 100644 index 0000000..e316e28 --- /dev/null +++ b/src/scrypt_mine.h @@ -0,0 +1,30 @@ +#ifndef SCRYPT_MINE_H +#define SCRYPT_MINE_H + +#include +#include + +#include "util.h" +#include "net.h" + +typedef struct +{ + unsigned int version; + uint256 prev_block; + uint256 merkle_root; + unsigned int timestamp; + unsigned int bits; + unsigned int nonce; + +} block_header; + +void *scrypt_buffer_alloc(); +void scrypt_buffer_free(void *scratchpad); + +unsigned int scanhash_scrypt(block_header *pdata, void *scratchbuf, + uint32_t max_nonce, uint32_t &hash_count, + void *result, block_header *res_header); + +void scrypt_hash(const void* input, size_t inputlen, uint32_t *res, void *scratchpad); + +#endif // SCRYPT_MINE_H diff --git a/src/serialize.h b/src/serialize.h new file mode 100644 index 0000000..012918d --- /dev/null +++ b/src/serialize.h @@ -0,0 +1,1133 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2012 The Bitcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. +#ifndef BITCOIN_SERIALIZE_H +#define BITCOIN_SERIALIZE_H + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "allocators.h" +#include "version.h" + +typedef long long int64; +typedef unsigned long long uint64; + +class CScript; +class CDataStream; +class CAutoFile; +static const unsigned int MAX_SIZE = 0x02000000; + +// Used to bypass the rule against non-const reference to temporary +// where it makes sense with wrappers such as CFlatData or CTxDB +template +inline T& REF(const T& val) +{ + return const_cast(val); +} + +///////////////////////////////////////////////////////////////// +// +// Templates for serializing to anything that looks like a stream, +// i.e. anything that supports .read(char*, int) and .write(char*, int) +// + +enum +{ + // primary actions + SER_NETWORK = (1 << 0), + SER_DISK = (1 << 1), + SER_GETHASH = (1 << 2), + + // modifiers + SER_SKIPSIG = (1 << 16), + SER_BLOCKHEADERONLY = (1 << 17), +}; + +#define IMPLEMENT_SERIALIZE(statements) \ + unsigned int GetSerializeSize(int nType, int nVersion) const \ + { \ + CSerActionGetSerializeSize ser_action; \ + const bool fGetSize = true; \ + const bool fWrite = false; \ + const bool fRead = false; \ + unsigned int nSerSize = 0; \ + ser_streamplaceholder s; \ + assert(fGetSize||fWrite||fRead); /* suppress warning */ \ + s.nType = nType; \ + s.nVersion = nVersion; \ + {statements} \ + return nSerSize; \ + } \ + template \ + void Serialize(Stream& s, int nType, int nVersion) const \ + { \ + CSerActionSerialize ser_action; \ + const bool fGetSize = false; \ + const bool fWrite = true; \ + const bool fRead = false; \ + unsigned int nSerSize = 0; \ + assert(fGetSize||fWrite||fRead); /* suppress warning */ \ + {statements} \ + } \ + template \ + void Unserialize(Stream& s, int nType, int nVersion) \ + { \ + CSerActionUnserialize ser_action; \ + const bool fGetSize = false; \ + const bool fWrite = false; \ + const bool fRead = true; \ + unsigned int nSerSize = 0; \ + assert(fGetSize||fWrite||fRead); /* suppress warning */ \ + {statements} \ + } + +#define READWRITE(obj) (nSerSize += ::SerReadWrite(s, (obj), nType, nVersion, ser_action)) + + + + + + +// +// Basic types +// +#define WRITEDATA(s, obj) s.write((char*)&(obj), sizeof(obj)) +#define READDATA(s, obj) s.read((char*)&(obj), sizeof(obj)) + +inline unsigned int GetSerializeSize(char a, int, int=0) { return sizeof(a); } +inline unsigned int GetSerializeSize(signed char a, int, int=0) { return sizeof(a); } +inline unsigned int GetSerializeSize(unsigned char a, int, int=0) { return sizeof(a); } +inline unsigned int GetSerializeSize(signed short a, int, int=0) { return sizeof(a); } +inline unsigned int GetSerializeSize(unsigned short a, int, int=0) { return sizeof(a); } +inline unsigned int GetSerializeSize(signed int a, int, int=0) { return sizeof(a); } +inline unsigned int GetSerializeSize(unsigned int a, int, int=0) { return sizeof(a); } +inline unsigned int GetSerializeSize(signed long a, int, int=0) { return sizeof(a); } +inline unsigned int GetSerializeSize(unsigned long a, int, int=0) { return sizeof(a); } +inline unsigned int GetSerializeSize(int64 a, int, int=0) { return sizeof(a); } +inline unsigned int GetSerializeSize(uint64 a, int, int=0) { return sizeof(a); } +inline unsigned int GetSerializeSize(float a, int, int=0) { return sizeof(a); } +inline unsigned int GetSerializeSize(double a, int, int=0) { return sizeof(a); } + +template inline void Serialize(Stream& s, char a, int, int=0) { WRITEDATA(s, a); } +template inline void Serialize(Stream& s, signed char a, int, int=0) { WRITEDATA(s, a); } +template inline void Serialize(Stream& s, unsigned char a, int, int=0) { WRITEDATA(s, a); } +template inline void Serialize(Stream& s, signed short a, int, int=0) { WRITEDATA(s, a); } +template inline void Serialize(Stream& s, unsigned short a, int, int=0) { WRITEDATA(s, a); } +template inline void Serialize(Stream& s, signed int a, int, int=0) { WRITEDATA(s, a); } +template inline void Serialize(Stream& s, unsigned int a, int, int=0) { WRITEDATA(s, a); } +template inline void Serialize(Stream& s, signed long a, int, int=0) { WRITEDATA(s, a); } +template inline void Serialize(Stream& s, unsigned long a, int, int=0) { WRITEDATA(s, a); } +template inline void Serialize(Stream& s, int64 a, int, int=0) { WRITEDATA(s, a); } +template inline void Serialize(Stream& s, uint64 a, int, int=0) { WRITEDATA(s, a); } +template inline void Serialize(Stream& s, float a, int, int=0) { WRITEDATA(s, a); } +template inline void Serialize(Stream& s, double a, int, int=0) { WRITEDATA(s, a); } + +template inline void Unserialize(Stream& s, char& a, int, int=0) { READDATA(s, a); } +template inline void Unserialize(Stream& s, signed char& a, int, int=0) { READDATA(s, a); } +template inline void Unserialize(Stream& s, unsigned char& a, int, int=0) { READDATA(s, a); } +template inline void Unserialize(Stream& s, signed short& a, int, int=0) { READDATA(s, a); } +template inline void Unserialize(Stream& s, unsigned short& a, int, int=0) { READDATA(s, a); } +template inline void Unserialize(Stream& s, signed int& a, int, int=0) { READDATA(s, a); } +template inline void Unserialize(Stream& s, unsigned int& a, int, int=0) { READDATA(s, a); } +template inline void Unserialize(Stream& s, signed long& a, int, int=0) { READDATA(s, a); } +template inline void Unserialize(Stream& s, unsigned long& a, int, int=0) { READDATA(s, a); } +template inline void Unserialize(Stream& s, int64& a, int, int=0) { READDATA(s, a); } +template inline void Unserialize(Stream& s, uint64& a, int, int=0) { READDATA(s, a); } +template inline void Unserialize(Stream& s, float& a, int, int=0) { READDATA(s, a); } +template inline void Unserialize(Stream& s, double& a, int, int=0) { READDATA(s, a); } + +inline unsigned int GetSerializeSize(bool a, int, int=0) { return sizeof(char); } +template inline void Serialize(Stream& s, bool a, int, int=0) { char f=a; WRITEDATA(s, f); } +template inline void Unserialize(Stream& s, bool& a, int, int=0) { char f; READDATA(s, f); a=f; } + + +#ifndef THROW_WITH_STACKTRACE +#define THROW_WITH_STACKTRACE(exception) \ +{ \ + LogStackTrace(); \ + throw (exception); \ +} +void LogStackTrace(); +#endif + +// +// Compact size +// size < 253 -- 1 byte +// size <= USHRT_MAX -- 3 bytes (253 + 2 bytes) +// size <= UINT_MAX -- 5 bytes (254 + 4 bytes) +// size > UINT_MAX -- 9 bytes (255 + 8 bytes) +// +inline unsigned int GetSizeOfCompactSize(uint64 nSize) +{ + if (nSize < 253) return sizeof(unsigned char); + else if (nSize <= std::numeric_limits::max()) return sizeof(unsigned char) + sizeof(unsigned short); + else if (nSize <= std::numeric_limits::max()) return sizeof(unsigned char) + sizeof(unsigned int); + else return sizeof(unsigned char) + sizeof(uint64); +} + +template +void WriteCompactSize(Stream& os, uint64 nSize) +{ + if (nSize < 253) + { + unsigned char chSize = nSize; + WRITEDATA(os, chSize); + } + else if (nSize <= std::numeric_limits::max()) + { + unsigned char chSize = 253; + unsigned short xSize = nSize; + WRITEDATA(os, chSize); + WRITEDATA(os, xSize); + } + else if (nSize <= std::numeric_limits::max()) + { + unsigned char chSize = 254; + unsigned int xSize = nSize; + WRITEDATA(os, chSize); + WRITEDATA(os, xSize); + } + else + { + unsigned char chSize = 255; + uint64 xSize = nSize; + WRITEDATA(os, chSize); + WRITEDATA(os, xSize); + } + return; +} + +template +uint64 ReadCompactSize(Stream& is) +{ + unsigned char chSize; + READDATA(is, chSize); + uint64 nSizeRet = 0; + if (chSize < 253) + { + nSizeRet = chSize; + } + else if (chSize == 253) + { + unsigned short xSize; + READDATA(is, xSize); + nSizeRet = xSize; + } + else if (chSize == 254) + { + unsigned int xSize; + READDATA(is, xSize); + nSizeRet = xSize; + } + else + { + uint64 xSize; + READDATA(is, xSize); + nSizeRet = xSize; + } + if (nSizeRet > (uint64)MAX_SIZE) + THROW_WITH_STACKTRACE(std::ios_base::failure("ReadCompactSize() : size too large")); + return nSizeRet; +} + + + +#define FLATDATA(obj) REF(CFlatData((char*)&(obj), (char*)&(obj) + sizeof(obj))) + +/** Wrapper for serializing arrays and POD. + */ +class CFlatData +{ +protected: + char* pbegin; + char* pend; +public: + CFlatData(void* pbeginIn, void* pendIn) : pbegin((char*)pbeginIn), pend((char*)pendIn) { } + char* begin() { return pbegin; } + const char* begin() const { return pbegin; } + char* end() { return pend; } + const char* end() const { return pend; } + + unsigned int GetSerializeSize(int, int=0) const + { + return pend - pbegin; + } + + template + void Serialize(Stream& s, int, int=0) const + { + s.write(pbegin, pend - pbegin); + } + + template + void Unserialize(Stream& s, int, int=0) + { + s.read(pbegin, pend - pbegin); + } +}; + +// +// Forward declarations +// + +// string +template unsigned int GetSerializeSize(const std::basic_string& str, int, int=0); +template void Serialize(Stream& os, const std::basic_string& str, int, int=0); +template void Unserialize(Stream& is, std::basic_string& str, int, int=0); + +// vector +template unsigned int GetSerializeSize_impl(const std::vector& v, int nType, int nVersion, const boost::true_type&); +template unsigned int GetSerializeSize_impl(const std::vector& v, int nType, int nVersion, const boost::false_type&); +template inline unsigned int GetSerializeSize(const std::vector& v, int nType, int nVersion); +template void Serialize_impl(Stream& os, const std::vector& v, int nType, int nVersion, const boost::true_type&); +template void Serialize_impl(Stream& os, const std::vector& v, int nType, int nVersion, const boost::false_type&); +template inline void Serialize(Stream& os, const std::vector& v, int nType, int nVersion); +template void Unserialize_impl(Stream& is, std::vector& v, int nType, int nVersion, const boost::true_type&); +template void Unserialize_impl(Stream& is, std::vector& v, int nType, int nVersion, const boost::false_type&); +template inline void Unserialize(Stream& is, std::vector& v, int nType, int nVersion); + +// others derived from vector +extern inline unsigned int GetSerializeSize(const CScript& v, int nType, int nVersion); +template void Serialize(Stream& os, const CScript& v, int nType, int nVersion); +template void Unserialize(Stream& is, CScript& v, int nType, int nVersion); + +// pair +template unsigned int GetSerializeSize(const std::pair& item, int nType, int nVersion); +template void Serialize(Stream& os, const std::pair& item, int nType, int nVersion); +template void Unserialize(Stream& is, std::pair& item, int nType, int nVersion); + +// 3 tuple +template unsigned int GetSerializeSize(const boost::tuple& item, int nType, int nVersion); +template void Serialize(Stream& os, const boost::tuple& item, int nType, int nVersion); +template void Unserialize(Stream& is, boost::tuple& item, int nType, int nVersion); + +// 4 tuple +template unsigned int GetSerializeSize(const boost::tuple& item, int nType, int nVersion); +template void Serialize(Stream& os, const boost::tuple& item, int nType, int nVersion); +template void Unserialize(Stream& is, boost::tuple& item, int nType, int nVersion); + +// map +template unsigned int GetSerializeSize(const std::map& m, int nType, int nVersion); +template void Serialize(Stream& os, const std::map& m, int nType, int nVersion); +template void Unserialize(Stream& is, std::map& m, int nType, int nVersion); + +// set +template unsigned int GetSerializeSize(const std::set& m, int nType, int nVersion); +template void Serialize(Stream& os, const std::set& m, int nType, int nVersion); +template void Unserialize(Stream& is, std::set& m, int nType, int nVersion); + + + + + +// +// If none of the specialized versions above matched, default to calling member function. +// "int nType" is changed to "long nType" to keep from getting an ambiguous overload error. +// The compiler will only cast int to long if none of the other templates matched. +// Thanks to Boost serialization for this idea. +// +template +inline unsigned int GetSerializeSize(const T& a, long nType, int nVersion) +{ + return a.GetSerializeSize((int)nType, nVersion); +} + +template +inline void Serialize(Stream& os, const T& a, long nType, int nVersion) +{ + a.Serialize(os, (int)nType, nVersion); +} + +template +inline void Unserialize(Stream& is, T& a, long nType, int nVersion) +{ + a.Unserialize(is, (int)nType, nVersion); +} + + + + + +// +// string +// +template +unsigned int GetSerializeSize(const std::basic_string& str, int, int) +{ + return GetSizeOfCompactSize(str.size()) + str.size() * sizeof(str[0]); +} + +template +void Serialize(Stream& os, const std::basic_string& str, int, int) +{ + WriteCompactSize(os, str.size()); + if (!str.empty()) + os.write((char*)&str[0], str.size() * sizeof(str[0])); +} + +template +void Unserialize(Stream& is, std::basic_string& str, int, int) +{ + unsigned int nSize = ReadCompactSize(is); + str.resize(nSize); + if (nSize != 0) + is.read((char*)&str[0], nSize * sizeof(str[0])); +} + + + +// +// vector +// +template +unsigned int GetSerializeSize_impl(const std::vector& v, int nType, int nVersion, const boost::true_type&) +{ + return (GetSizeOfCompactSize(v.size()) + v.size() * sizeof(T)); +} + +template +unsigned int GetSerializeSize_impl(const std::vector& v, int nType, int nVersion, const boost::false_type&) +{ + unsigned int nSize = GetSizeOfCompactSize(v.size()); + for (typename std::vector::const_iterator vi = v.begin(); vi != v.end(); ++vi) + nSize += GetSerializeSize((*vi), nType, nVersion); + return nSize; +} + +template +inline unsigned int GetSerializeSize(const std::vector& v, int nType, int nVersion) +{ + return GetSerializeSize_impl(v, nType, nVersion, boost::is_fundamental()); +} + + +template +void Serialize_impl(Stream& os, const std::vector& v, int nType, int nVersion, const boost::true_type&) +{ + WriteCompactSize(os, v.size()); + if (!v.empty()) + os.write((char*)&v[0], v.size() * sizeof(T)); +} + +template +void Serialize_impl(Stream& os, const std::vector& v, int nType, int nVersion, const boost::false_type&) +{ + WriteCompactSize(os, v.size()); + for (typename std::vector::const_iterator vi = v.begin(); vi != v.end(); ++vi) + ::Serialize(os, (*vi), nType, nVersion); +} + +template +inline void Serialize(Stream& os, const std::vector& v, int nType, int nVersion) +{ + Serialize_impl(os, v, nType, nVersion, boost::is_fundamental()); +} + + +template +void Unserialize_impl(Stream& is, std::vector& v, int nType, int nVersion, const boost::true_type&) +{ + // Limit size per read so bogus size value won't cause out of memory + v.clear(); + unsigned int nSize = ReadCompactSize(is); + unsigned int i = 0; + while (i < nSize) + { + unsigned int blk = std::min(nSize - i, (unsigned int)(1 + 4999999 / sizeof(T))); + v.resize(i + blk); + is.read((char*)&v[i], blk * sizeof(T)); + i += blk; + } +} + +template +void Unserialize_impl(Stream& is, std::vector& v, int nType, int nVersion, const boost::false_type&) +{ + v.clear(); + unsigned int nSize = ReadCompactSize(is); + unsigned int i = 0; + unsigned int nMid = 0; + while (nMid < nSize) + { + nMid += 5000000 / sizeof(T); + if (nMid > nSize) + nMid = nSize; + v.resize(nMid); + for (; i < nMid; i++) + Unserialize(is, v[i], nType, nVersion); + } +} + +template +inline void Unserialize(Stream& is, std::vector& v, int nType, int nVersion) +{ + Unserialize_impl(is, v, nType, nVersion, boost::is_fundamental()); +} + + + +// +// others derived from vector +// +inline unsigned int GetSerializeSize(const CScript& v, int nType, int nVersion) +{ + return GetSerializeSize((const std::vector&)v, nType, nVersion); +} + +template +void Serialize(Stream& os, const CScript& v, int nType, int nVersion) +{ + Serialize(os, (const std::vector&)v, nType, nVersion); +} + +template +void Unserialize(Stream& is, CScript& v, int nType, int nVersion) +{ + Unserialize(is, (std::vector&)v, nType, nVersion); +} + + + +// +// pair +// +template +unsigned int GetSerializeSize(const std::pair& item, int nType, int nVersion) +{ + return GetSerializeSize(item.first, nType, nVersion) + GetSerializeSize(item.second, nType, nVersion); +} + +template +void Serialize(Stream& os, const std::pair& item, int nType, int nVersion) +{ + Serialize(os, item.first, nType, nVersion); + Serialize(os, item.second, nType, nVersion); +} + +template +void Unserialize(Stream& is, std::pair& item, int nType, int nVersion) +{ + Unserialize(is, item.first, nType, nVersion); + Unserialize(is, item.second, nType, nVersion); +} + + + +// +// 3 tuple +// +template +unsigned int GetSerializeSize(const boost::tuple& item, int nType, int nVersion) +{ + unsigned int nSize = 0; + nSize += GetSerializeSize(boost::get<0>(item), nType, nVersion); + nSize += GetSerializeSize(boost::get<1>(item), nType, nVersion); + nSize += GetSerializeSize(boost::get<2>(item), nType, nVersion); + return nSize; +} + +template +void Serialize(Stream& os, const boost::tuple& item, int nType, int nVersion) +{ + Serialize(os, boost::get<0>(item), nType, nVersion); + Serialize(os, boost::get<1>(item), nType, nVersion); + Serialize(os, boost::get<2>(item), nType, nVersion); +} + +template +void Unserialize(Stream& is, boost::tuple& item, int nType, int nVersion) +{ + Unserialize(is, boost::get<0>(item), nType, nVersion); + Unserialize(is, boost::get<1>(item), nType, nVersion); + Unserialize(is, boost::get<2>(item), nType, nVersion); +} + + + +// +// 4 tuple +// +template +unsigned int GetSerializeSize(const boost::tuple& item, int nType, int nVersion) +{ + unsigned int nSize = 0; + nSize += GetSerializeSize(boost::get<0>(item), nType, nVersion); + nSize += GetSerializeSize(boost::get<1>(item), nType, nVersion); + nSize += GetSerializeSize(boost::get<2>(item), nType, nVersion); + nSize += GetSerializeSize(boost::get<3>(item), nType, nVersion); + return nSize; +} + +template +void Serialize(Stream& os, const boost::tuple& item, int nType, int nVersion) +{ + Serialize(os, boost::get<0>(item), nType, nVersion); + Serialize(os, boost::get<1>(item), nType, nVersion); + Serialize(os, boost::get<2>(item), nType, nVersion); + Serialize(os, boost::get<3>(item), nType, nVersion); +} + +template +void Unserialize(Stream& is, boost::tuple& item, int nType, int nVersion) +{ + Unserialize(is, boost::get<0>(item), nType, nVersion); + Unserialize(is, boost::get<1>(item), nType, nVersion); + Unserialize(is, boost::get<2>(item), nType, nVersion); + Unserialize(is, boost::get<3>(item), nType, nVersion); +} + + + +// +// map +// +template +unsigned int GetSerializeSize(const std::map& m, int nType, int nVersion) +{ + unsigned int nSize = GetSizeOfCompactSize(m.size()); + for (typename std::map::const_iterator mi = m.begin(); mi != m.end(); ++mi) + nSize += GetSerializeSize((*mi), nType, nVersion); + return nSize; +} + +template +void Serialize(Stream& os, const std::map& m, int nType, int nVersion) +{ + WriteCompactSize(os, m.size()); + for (typename std::map::const_iterator mi = m.begin(); mi != m.end(); ++mi) + Serialize(os, (*mi), nType, nVersion); +} + +template +void Unserialize(Stream& is, std::map& m, int nType, int nVersion) +{ + m.clear(); + unsigned int nSize = ReadCompactSize(is); + typename std::map::iterator mi = m.begin(); + for (unsigned int i = 0; i < nSize; i++) + { + std::pair item; + Unserialize(is, item, nType, nVersion); + mi = m.insert(mi, item); + } +} + + + +// +// set +// +template +unsigned int GetSerializeSize(const std::set& m, int nType, int nVersion) +{ + unsigned int nSize = GetSizeOfCompactSize(m.size()); + for (typename std::set::const_iterator it = m.begin(); it != m.end(); ++it) + nSize += GetSerializeSize((*it), nType, nVersion); + return nSize; +} + +template +void Serialize(Stream& os, const std::set& m, int nType, int nVersion) +{ + WriteCompactSize(os, m.size()); + for (typename std::set::const_iterator it = m.begin(); it != m.end(); ++it) + Serialize(os, (*it), nType, nVersion); +} + +template +void Unserialize(Stream& is, std::set& m, int nType, int nVersion) +{ + m.clear(); + unsigned int nSize = ReadCompactSize(is); + typename std::set::iterator it = m.begin(); + for (unsigned int i = 0; i < nSize; i++) + { + K key; + Unserialize(is, key, nType, nVersion); + it = m.insert(it, key); + } +} + + + +// +// Support for IMPLEMENT_SERIALIZE and READWRITE macro +// +class CSerActionGetSerializeSize { }; +class CSerActionSerialize { }; +class CSerActionUnserialize { }; + +template +inline unsigned int SerReadWrite(Stream& s, const T& obj, int nType, int nVersion, CSerActionGetSerializeSize ser_action) +{ + return ::GetSerializeSize(obj, nType, nVersion); +} + +template +inline unsigned int SerReadWrite(Stream& s, const T& obj, int nType, int nVersion, CSerActionSerialize ser_action) +{ + ::Serialize(s, obj, nType, nVersion); + return 0; +} + +template +inline unsigned int SerReadWrite(Stream& s, T& obj, int nType, int nVersion, CSerActionUnserialize ser_action) +{ + ::Unserialize(s, obj, nType, nVersion); + return 0; +} + +struct ser_streamplaceholder +{ + int nType; + int nVersion; +}; + + +/** Double ended buffer combining vector and stream-like interfaces. + * + * >> and << read and write unformatted data using the above serialization templates. + * Fills with data in linear time; some stringstream implementations take N^2 time. + */ +class CDataStream +{ +protected: + typedef std::vector > vector_type; + vector_type vch; + unsigned int nReadPos; + short state; + short exceptmask; +public: + int nType; + int nVersion; + + typedef vector_type::allocator_type allocator_type; + typedef vector_type::size_type size_type; + typedef vector_type::difference_type difference_type; + typedef vector_type::reference reference; + typedef vector_type::const_reference const_reference; + typedef vector_type::value_type value_type; + typedef vector_type::iterator iterator; + typedef vector_type::const_iterator const_iterator; + typedef vector_type::reverse_iterator reverse_iterator; + + explicit CDataStream(int nTypeIn, int nVersionIn) + { + Init(nTypeIn, nVersionIn); + } + + CDataStream(const_iterator pbegin, const_iterator pend, int nTypeIn, int nVersionIn) : vch(pbegin, pend) + { + Init(nTypeIn, nVersionIn); + } + +#if !defined(_MSC_VER) || _MSC_VER >= 1300 + CDataStream(const char* pbegin, const char* pend, int nTypeIn, int nVersionIn) : vch(pbegin, pend) + { + Init(nTypeIn, nVersionIn); + } +#endif + + CDataStream(const vector_type& vchIn, int nTypeIn, int nVersionIn) : vch(vchIn.begin(), vchIn.end()) + { + Init(nTypeIn, nVersionIn); + } + + CDataStream(const std::vector& vchIn, int nTypeIn, int nVersionIn) : vch(vchIn.begin(), vchIn.end()) + { + Init(nTypeIn, nVersionIn); + } + + CDataStream(const std::vector& vchIn, int nTypeIn, int nVersionIn) : vch((char*)&vchIn.begin()[0], (char*)&vchIn.end()[0]) + { + Init(nTypeIn, nVersionIn); + } + + void Init(int nTypeIn, int nVersionIn) + { + nReadPos = 0; + nType = nTypeIn; + nVersion = nVersionIn; + state = 0; + exceptmask = std::ios::badbit | std::ios::failbit; + } + + CDataStream& operator+=(const CDataStream& b) + { + vch.insert(vch.end(), b.begin(), b.end()); + return *this; + } + + friend CDataStream operator+(const CDataStream& a, const CDataStream& b) + { + CDataStream ret = a; + ret += b; + return (ret); + } + + std::string str() const + { + return (std::string(begin(), end())); + } + + + // + // Vector subset + // + const_iterator begin() const { return vch.begin() + nReadPos; } + iterator begin() { return vch.begin() + nReadPos; } + const_iterator end() const { return vch.end(); } + iterator end() { return vch.end(); } + size_type size() const { return vch.size() - nReadPos; } + bool empty() const { return vch.size() == nReadPos; } + void resize(size_type n, value_type c=0) { vch.resize(n + nReadPos, c); } + void reserve(size_type n) { vch.reserve(n + nReadPos); } + const_reference operator[](size_type pos) const { return vch[pos + nReadPos]; } + reference operator[](size_type pos) { return vch[pos + nReadPos]; } + void clear() { vch.clear(); nReadPos = 0; } + iterator insert(iterator it, const char& x=char()) { return vch.insert(it, x); } + void insert(iterator it, size_type n, const char& x) { vch.insert(it, n, x); } + + void insert(iterator it, const_iterator first, const_iterator last) + { + assert(last - first >= 0); + if (it == vch.begin() + nReadPos && (unsigned int)(last - first) <= nReadPos) + { + // special case for inserting at the front when there's room + nReadPos -= (last - first); + memcpy(&vch[nReadPos], &first[0], last - first); + } + else + vch.insert(it, first, last); + } + +#if !defined(MAC_OSX) + void insert(iterator it, std::vector::const_iterator first, std::vector::const_iterator last) + { + assert(last - first >= 0); + if (it == vch.begin() + nReadPos && (unsigned int)(last - first) <= nReadPos) + { + // special case for inserting at the front when there's room + nReadPos -= (last - first); + memcpy(&vch[nReadPos], &first[0], last - first); + } + else + vch.insert(it, first, last); + } +#endif + +#if !defined(_MSC_VER) || _MSC_VER >= 1300 + void insert(iterator it, const char* first, const char* last) + { + assert(last - first >= 0); + if (it == vch.begin() + nReadPos && (unsigned int)(last - first) <= nReadPos) + { + // special case for inserting at the front when there's room + nReadPos -= (last - first); + memcpy(&vch[nReadPos], &first[0], last - first); + } + else + vch.insert(it, first, last); + } +#endif + + iterator erase(iterator it) + { + if (it == vch.begin() + nReadPos) + { + // special case for erasing from the front + if (++nReadPos >= vch.size()) + { + // whenever we reach the end, we take the opportunity to clear the buffer + nReadPos = 0; + return vch.erase(vch.begin(), vch.end()); + } + return vch.begin() + nReadPos; + } + else + return vch.erase(it); + } + + iterator erase(iterator first, iterator last) + { + if (first == vch.begin() + nReadPos) + { + // special case for erasing from the front + if (last == vch.end()) + { + nReadPos = 0; + return vch.erase(vch.begin(), vch.end()); + } + else + { + nReadPos = (last - vch.begin()); + return last; + } + } + else + return vch.erase(first, last); + } + + inline void Compact() + { + vch.erase(vch.begin(), vch.begin() + nReadPos); + nReadPos = 0; + } + + bool Rewind(size_type n) + { + // Rewind by n characters if the buffer hasn't been compacted yet + if (n > nReadPos) + return false; + nReadPos -= n; + return true; + } + + + // + // Stream subset + // + void setstate(short bits, const char* psz) + { + state |= bits; + if (state & exceptmask) + THROW_WITH_STACKTRACE(std::ios_base::failure(psz)); + } + + bool eof() const { return size() == 0; } + bool fail() const { return state & (std::ios::badbit | std::ios::failbit); } + bool good() const { return !eof() && (state == 0); } + void clear(short n) { state = n; } // name conflict with vector clear() + short exceptions() { return exceptmask; } + short exceptions(short mask) { short prev = exceptmask; exceptmask = mask; setstate(0, "CDataStream"); return prev; } + CDataStream* rdbuf() { return this; } + int in_avail() { return size(); } + + void SetType(int n) { nType = n; } + int GetType() { return nType; } + void SetVersion(int n) { nVersion = n; } + int GetVersion() { return nVersion; } + void ReadVersion() { *this >> nVersion; } + void WriteVersion() { *this << nVersion; } + + CDataStream& read(char* pch, int nSize) + { + // Read from the beginning of the buffer + assert(nSize >= 0); + unsigned int nReadPosNext = nReadPos + nSize; + if (nReadPosNext >= vch.size()) + { + if (nReadPosNext > vch.size()) + { + setstate(std::ios::failbit, "CDataStream::read() : end of data"); + memset(pch, 0, nSize); + nSize = vch.size() - nReadPos; + } + memcpy(pch, &vch[nReadPos], nSize); + nReadPos = 0; + vch.clear(); + return (*this); + } + memcpy(pch, &vch[nReadPos], nSize); + nReadPos = nReadPosNext; + return (*this); + } + + CDataStream& ignore(int nSize) + { + // Ignore from the beginning of the buffer + assert(nSize >= 0); + unsigned int nReadPosNext = nReadPos + nSize; + if (nReadPosNext >= vch.size()) + { + if (nReadPosNext > vch.size()) + { + setstate(std::ios::failbit, "CDataStream::ignore() : end of data"); + nSize = vch.size() - nReadPos; + } + nReadPos = 0; + vch.clear(); + return (*this); + } + nReadPos = nReadPosNext; + return (*this); + } + + CDataStream& write(const char* pch, int nSize) + { + // Write to the end of the buffer + assert(nSize >= 0); + vch.insert(vch.end(), pch, pch + nSize); + return (*this); + } + + template + void Serialize(Stream& s, int nType, int nVersion) const + { + // Special case: stream << stream concatenates like stream += stream + if (!vch.empty()) + s.write((char*)&vch[0], vch.size() * sizeof(vch[0])); + } + + template + unsigned int GetSerializeSize(const T& obj) + { + // Tells the size of the object if serialized to this stream + return ::GetSerializeSize(obj, nType, nVersion); + } + + template + CDataStream& operator<<(const T& obj) + { + // Serialize to this stream + ::Serialize(*this, obj, nType, nVersion); + return (*this); + } + + template + CDataStream& operator>>(T& obj) + { + // Unserialize from this stream + ::Unserialize(*this, obj, nType, nVersion); + return (*this); + } +}; + + + + + + + + + + +/** RAII wrapper for FILE*. + * + * Will automatically close the file when it goes out of scope if not null. + * If you're returning the file pointer, return file.release(). + * If you need to close the file early, use file.fclose() instead of fclose(file). + */ +class CAutoFile +{ +protected: + FILE* file; + short state; + short exceptmask; +public: + int nType; + int nVersion; + + CAutoFile(FILE* filenew, int nTypeIn, int nVersionIn) + { + file = filenew; + nType = nTypeIn; + nVersion = nVersionIn; + state = 0; + exceptmask = std::ios::badbit | std::ios::failbit; + } + + ~CAutoFile() + { + fclose(); + } + + void fclose() + { + if (file != NULL && file != stdin && file != stdout && file != stderr) + ::fclose(file); + file = NULL; + } + + FILE* release() { FILE* ret = file; file = NULL; return ret; } + operator FILE*() { return file; } + FILE* operator->() { return file; } + FILE& operator*() { return *file; } + FILE** operator&() { return &file; } + FILE* operator=(FILE* pnew) { return file = pnew; } + bool operator!() { return (file == NULL); } + + + // + // Stream subset + // + void setstate(short bits, const char* psz) + { + state |= bits; + if (state & exceptmask) + THROW_WITH_STACKTRACE(std::ios_base::failure(psz)); + } + + bool fail() const { return state & (std::ios::badbit | std::ios::failbit); } + bool good() const { return state == 0; } + void clear(short n = 0) { state = n; } + short exceptions() { return exceptmask; } + short exceptions(short mask) { short prev = exceptmask; exceptmask = mask; setstate(0, "CAutoFile"); return prev; } + + void SetType(int n) { nType = n; } + int GetType() { return nType; } + void SetVersion(int n) { nVersion = n; } + int GetVersion() { return nVersion; } + void ReadVersion() { *this >> nVersion; } + void WriteVersion() { *this << nVersion; } + + CAutoFile& read(char* pch, size_t nSize) + { + if (!file) + throw std::ios_base::failure("CAutoFile::read : file handle is NULL"); + if (fread(pch, 1, nSize, file) != nSize) + setstate(std::ios::failbit, feof(file) ? "CAutoFile::read : end of file" : "CAutoFile::read : fread failed"); + return (*this); + } + + CAutoFile& write(const char* pch, size_t nSize) + { + if (!file) + throw std::ios_base::failure("CAutoFile::write : file handle is NULL"); + if (fwrite(pch, 1, nSize, file) != nSize) + setstate(std::ios::failbit, "CAutoFile::write : write failed"); + return (*this); + } + + template + unsigned int GetSerializeSize(const T& obj) + { + // Tells the size of the object if serialized to this stream + return ::GetSerializeSize(obj, nType, nVersion); + } + + template + CAutoFile& operator<<(const T& obj) + { + // Serialize to this stream + if (!file) + throw std::ios_base::failure("CAutoFile::operator<< : file handle is NULL"); + ::Serialize(*this, obj, nType, nVersion); + return (*this); + } + + template + CAutoFile& operator>>(T& obj) + { + // Unserialize from this stream + if (!file) + throw std::ios_base::failure("CAutoFile::operator>> : file handle is NULL"); + ::Unserialize(*this, obj, nType, nVersion); + return (*this); + } +}; + +#endif diff --git a/src/shavite.c b/src/shavite.c new file mode 100644 index 0000000..7a9b041 --- /dev/null +++ b/src/shavite.c @@ -0,0 +1,1764 @@ +/* $Id: shavite.c 227 2010-06-16 17:28:38Z tp $ */ +/* + * SHAvite-3 implementation. + * + * ==========================(LICENSE BEGIN)============================ + * + * Copyright (c) 2007-2010 Projet RNRT SAPHIR + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * ===========================(LICENSE END)============================= + * + * @author Thomas Pornin + */ + +#include +#include + +#include "sph_shavite.h" + +#ifdef __cplusplus +extern "C"{ +#endif + +#if SPH_SMALL_FOOTPRINT && !defined SPH_SMALL_FOOTPRINT_SHAVITE +#define SPH_SMALL_FOOTPRINT_SHAVITE 1 +#endif + +#ifdef _MSC_VER +#pragma warning (disable: 4146) +#endif + +#define C32 SPH_C32 + +/* + * As of round 2 of the SHA-3 competition, the published reference + * implementation and test vectors are wrong, because they use + * big-endian AES tables while the internal decoding uses little-endian. + * The code below follows the specification. To turn it into a code + * which follows the reference implementation (the one called "BugFix" + * on the SHAvite-3 web site, published on Nov 23rd, 2009), comment out + * the code below (from the '#define AES_BIG_ENDIAN...' to the definition + * of the AES_ROUND_NOKEY macro) and replace it with the version which + * is commented out afterwards. + */ + +#define AES_BIG_ENDIAN 0 +#include "aes_helper.c" + +static const sph_u32 IV224[] = { + C32(0x6774F31C), C32(0x990AE210), C32(0xC87D4274), C32(0xC9546371), + C32(0x62B2AEA8), C32(0x4B5801D8), C32(0x1B702860), C32(0x842F3017) +}; + +static const sph_u32 IV256[] = { + C32(0x49BB3E47), C32(0x2674860D), C32(0xA8B392AC), C32(0x021AC4E6), + C32(0x409283CF), C32(0x620E5D86), C32(0x6D929DCB), C32(0x96CC2A8B) +}; + +static const sph_u32 IV384[] = { + C32(0x83DF1545), C32(0xF9AAEC13), C32(0xF4803CB0), C32(0x11FE1F47), + C32(0xDA6CD269), C32(0x4F53FCD7), C32(0x950529A2), C32(0x97908147), + C32(0xB0A4D7AF), C32(0x2B9132BF), C32(0x226E607D), C32(0x3C0F8D7C), + C32(0x487B3F0F), C32(0x04363E22), C32(0x0155C99C), C32(0xEC2E20D3) +}; + +static const sph_u32 IV512[] = { + C32(0x72FCCDD8), C32(0x79CA4727), C32(0x128A077B), C32(0x40D55AEC), + C32(0xD1901A06), C32(0x430AE307), C32(0xB29F5CD1), C32(0xDF07FBFC), + C32(0x8E45D73D), C32(0x681AB538), C32(0xBDE86578), C32(0xDD577E47), + C32(0xE275EADE), C32(0x502D9FCD), C32(0xB9357178), C32(0x022A4B9A) +}; + +#define AES_ROUND_NOKEY(x0, x1, x2, x3) do { \ + sph_u32 t0 = (x0); \ + sph_u32 t1 = (x1); \ + sph_u32 t2 = (x2); \ + sph_u32 t3 = (x3); \ + AES_ROUND_NOKEY_LE(t0, t1, t2, t3, x0, x1, x2, x3); \ + } while (0) + +/* + * This is the code needed to match the "reference implementation" as + * published on Nov 23rd, 2009, instead of the published specification. + * + +#define AES_BIG_ENDIAN 1 +#include "aes_helper.c" + +static const sph_u32 IV224[] = { + C32(0xC4C67795), C32(0xC0B1817F), C32(0xEAD88924), C32(0x1ABB1BB0), + C32(0xE0C29152), C32(0xBDE046BA), C32(0xAEEECF99), C32(0x58D509D8) +}; + +static const sph_u32 IV256[] = { + C32(0x3EECF551), C32(0xBF10819B), C32(0xE6DC8559), C32(0xF3E23FD5), + C32(0x431AEC73), C32(0x79E3F731), C32(0x98325F05), C32(0xA92A31F1) +}; + +static const sph_u32 IV384[] = { + C32(0x71F48510), C32(0xA903A8AC), C32(0xFE3216DD), C32(0x0B2D2AD4), + C32(0x6672900A), C32(0x41032819), C32(0x15A7D780), C32(0xB3CAB8D9), + C32(0x34EF4711), C32(0xDE019FE8), C32(0x4D674DC4), C32(0xE056D96B), + C32(0xA35C016B), C32(0xDD903BA7), C32(0x8C1B09B4), C32(0x2C3E9F25) +}; + +static const sph_u32 IV512[] = { + C32(0xD5652B63), C32(0x25F1E6EA), C32(0xB18F48FA), C32(0xA1EE3A47), + C32(0xC8B67B07), C32(0xBDCE48D3), C32(0xE3937B78), C32(0x05DB5186), + C32(0x613BE326), C32(0xA11FA303), C32(0x90C833D4), C32(0x79CEE316), + C32(0x1E1AF00F), C32(0x2829B165), C32(0x23B25F80), C32(0x21E11499) +}; + +#define AES_ROUND_NOKEY(x0, x1, x2, x3) do { \ + sph_u32 t0 = (x0); \ + sph_u32 t1 = (x1); \ + sph_u32 t2 = (x2); \ + sph_u32 t3 = (x3); \ + AES_ROUND_NOKEY_BE(t0, t1, t2, t3, x0, x1, x2, x3); \ + } while (0) + + */ + +#define KEY_EXPAND_ELT(k0, k1, k2, k3) do { \ + sph_u32 kt; \ + AES_ROUND_NOKEY(k1, k2, k3, k0); \ + kt = (k0); \ + (k0) = (k1); \ + (k1) = (k2); \ + (k2) = (k3); \ + (k3) = kt; \ + } while (0) + +#if SPH_SMALL_FOOTPRINT_SHAVITE + +/* + * This function assumes that "msg" is aligned for 32-bit access. + */ +static void +c256(sph_shavite_small_context *sc, const void *msg) +{ + sph_u32 p0, p1, p2, p3, p4, p5, p6, p7; + sph_u32 rk[144]; + size_t u; + int r, s; + +#if SPH_LITTLE_ENDIAN + memcpy(rk, msg, 64); +#else + for (u = 0; u < 16; u += 4) { + rk[u + 0] = sph_dec32le_aligned( + (const unsigned char *)msg + (u << 2) + 0); + rk[u + 1] = sph_dec32le_aligned( + (const unsigned char *)msg + (u << 2) + 4); + rk[u + 2] = sph_dec32le_aligned( + (const unsigned char *)msg + (u << 2) + 8); + rk[u + 3] = sph_dec32le_aligned( + (const unsigned char *)msg + (u << 2) + 12); + } +#endif + u = 16; + for (r = 0; r < 4; r ++) { + for (s = 0; s < 2; s ++) { + sph_u32 x0, x1, x2, x3; + + x0 = rk[u - 15]; + x1 = rk[u - 14]; + x2 = rk[u - 13]; + x3 = rk[u - 16]; + AES_ROUND_NOKEY(x0, x1, x2, x3); + rk[u + 0] = x0 ^ rk[u - 4]; + rk[u + 1] = x1 ^ rk[u - 3]; + rk[u + 2] = x2 ^ rk[u - 2]; + rk[u + 3] = x3 ^ rk[u - 1]; + if (u == 16) { + rk[ 16] ^= sc->count0; + rk[ 17] ^= SPH_T32(~sc->count1); + } else if (u == 56) { + rk[ 57] ^= sc->count1; + rk[ 58] ^= SPH_T32(~sc->count0); + } + u += 4; + + x0 = rk[u - 15]; + x1 = rk[u - 14]; + x2 = rk[u - 13]; + x3 = rk[u - 16]; + AES_ROUND_NOKEY(x0, x1, x2, x3); + rk[u + 0] = x0 ^ rk[u - 4]; + rk[u + 1] = x1 ^ rk[u - 3]; + rk[u + 2] = x2 ^ rk[u - 2]; + rk[u + 3] = x3 ^ rk[u - 1]; + if (u == 84) { + rk[ 86] ^= sc->count1; + rk[ 87] ^= SPH_T32(~sc->count0); + } else if (u == 124) { + rk[124] ^= sc->count0; + rk[127] ^= SPH_T32(~sc->count1); + } + u += 4; + } + for (s = 0; s < 4; s ++) { + rk[u + 0] = rk[u - 16] ^ rk[u - 3]; + rk[u + 1] = rk[u - 15] ^ rk[u - 2]; + rk[u + 2] = rk[u - 14] ^ rk[u - 1]; + rk[u + 3] = rk[u - 13] ^ rk[u - 0]; + u += 4; + } + } + + p0 = sc->h[0x0]; + p1 = sc->h[0x1]; + p2 = sc->h[0x2]; + p3 = sc->h[0x3]; + p4 = sc->h[0x4]; + p5 = sc->h[0x5]; + p6 = sc->h[0x6]; + p7 = sc->h[0x7]; + u = 0; + for (r = 0; r < 6; r ++) { + sph_u32 x0, x1, x2, x3; + + x0 = p4 ^ rk[u ++]; + x1 = p5 ^ rk[u ++]; + x2 = p6 ^ rk[u ++]; + x3 = p7 ^ rk[u ++]; + AES_ROUND_NOKEY(x0, x1, x2, x3); + x0 ^= rk[u ++]; + x1 ^= rk[u ++]; + x2 ^= rk[u ++]; + x3 ^= rk[u ++]; + AES_ROUND_NOKEY(x0, x1, x2, x3); + x0 ^= rk[u ++]; + x1 ^= rk[u ++]; + x2 ^= rk[u ++]; + x3 ^= rk[u ++]; + AES_ROUND_NOKEY(x0, x1, x2, x3); + p0 ^= x0; + p1 ^= x1; + p2 ^= x2; + p3 ^= x3; + + x0 = p0 ^ rk[u ++]; + x1 = p1 ^ rk[u ++]; + x2 = p2 ^ rk[u ++]; + x3 = p3 ^ rk[u ++]; + AES_ROUND_NOKEY(x0, x1, x2, x3); + x0 ^= rk[u ++]; + x1 ^= rk[u ++]; + x2 ^= rk[u ++]; + x3 ^= rk[u ++]; + AES_ROUND_NOKEY(x0, x1, x2, x3); + x0 ^= rk[u ++]; + x1 ^= rk[u ++]; + x2 ^= rk[u ++]; + x3 ^= rk[u ++]; + AES_ROUND_NOKEY(x0, x1, x2, x3); + p4 ^= x0; + p5 ^= x1; + p6 ^= x2; + p7 ^= x3; + } + sc->h[0x0] ^= p0; + sc->h[0x1] ^= p1; + sc->h[0x2] ^= p2; + sc->h[0x3] ^= p3; + sc->h[0x4] ^= p4; + sc->h[0x5] ^= p5; + sc->h[0x6] ^= p6; + sc->h[0x7] ^= p7; +} + +#else + +/* + * This function assumes that "msg" is aligned for 32-bit access. + */ +static void +c256(sph_shavite_small_context *sc, const void *msg) +{ + sph_u32 p0, p1, p2, p3, p4, p5, p6, p7; + sph_u32 x0, x1, x2, x3; + sph_u32 rk0, rk1, rk2, rk3, rk4, rk5, rk6, rk7; + sph_u32 rk8, rk9, rkA, rkB, rkC, rkD, rkE, rkF; + + p0 = sc->h[0x0]; + p1 = sc->h[0x1]; + p2 = sc->h[0x2]; + p3 = sc->h[0x3]; + p4 = sc->h[0x4]; + p5 = sc->h[0x5]; + p6 = sc->h[0x6]; + p7 = sc->h[0x7]; + /* round 0 */ + rk0 = sph_dec32le_aligned((const unsigned char *)msg + 0); + x0 = p4 ^ rk0; + rk1 = sph_dec32le_aligned((const unsigned char *)msg + 4); + x1 = p5 ^ rk1; + rk2 = sph_dec32le_aligned((const unsigned char *)msg + 8); + x2 = p6 ^ rk2; + rk3 = sph_dec32le_aligned((const unsigned char *)msg + 12); + x3 = p7 ^ rk3; + AES_ROUND_NOKEY(x0, x1, x2, x3); + rk4 = sph_dec32le_aligned((const unsigned char *)msg + 16); + x0 ^= rk4; + rk5 = sph_dec32le_aligned((const unsigned char *)msg + 20); + x1 ^= rk5; + rk6 = sph_dec32le_aligned((const unsigned char *)msg + 24); + x2 ^= rk6; + rk7 = sph_dec32le_aligned((const unsigned char *)msg + 28); + x3 ^= rk7; + AES_ROUND_NOKEY(x0, x1, x2, x3); + rk8 = sph_dec32le_aligned((const unsigned char *)msg + 32); + x0 ^= rk8; + rk9 = sph_dec32le_aligned((const unsigned char *)msg + 36); + x1 ^= rk9; + rkA = sph_dec32le_aligned((const unsigned char *)msg + 40); + x2 ^= rkA; + rkB = sph_dec32le_aligned((const unsigned char *)msg + 44); + x3 ^= rkB; + AES_ROUND_NOKEY(x0, x1, x2, x3); + p0 ^= x0; + p1 ^= x1; + p2 ^= x2; + p3 ^= x3; + /* round 1 */ + rkC = sph_dec32le_aligned((const unsigned char *)msg + 48); + x0 = p0 ^ rkC; + rkD = sph_dec32le_aligned((const unsigned char *)msg + 52); + x1 = p1 ^ rkD; + rkE = sph_dec32le_aligned((const unsigned char *)msg + 56); + x2 = p2 ^ rkE; + rkF = sph_dec32le_aligned((const unsigned char *)msg + 60); + x3 = p3 ^ rkF; + AES_ROUND_NOKEY(x0, x1, x2, x3); + KEY_EXPAND_ELT(rk0, rk1, rk2, rk3); + rk0 ^= rkC ^ sc->count0; + rk1 ^= rkD ^ SPH_T32(~sc->count1); + rk2 ^= rkE; + rk3 ^= rkF; + x0 ^= rk0; + x1 ^= rk1; + x2 ^= rk2; + x3 ^= rk3; + AES_ROUND_NOKEY(x0, x1, x2, x3); + KEY_EXPAND_ELT(rk4, rk5, rk6, rk7); + rk4 ^= rk0; + rk5 ^= rk1; + rk6 ^= rk2; + rk7 ^= rk3; + x0 ^= rk4; + x1 ^= rk5; + x2 ^= rk6; + x3 ^= rk7; + AES_ROUND_NOKEY(x0, x1, x2, x3); + p4 ^= x0; + p5 ^= x1; + p6 ^= x2; + p7 ^= x3; + /* round 2 */ + KEY_EXPAND_ELT(rk8, rk9, rkA, rkB); + rk8 ^= rk4; + rk9 ^= rk5; + rkA ^= rk6; + rkB ^= rk7; + x0 = p4 ^ rk8; + x1 = p5 ^ rk9; + x2 = p6 ^ rkA; + x3 = p7 ^ rkB; + AES_ROUND_NOKEY(x0, x1, x2, x3); + KEY_EXPAND_ELT(rkC, rkD, rkE, rkF); + rkC ^= rk8; + rkD ^= rk9; + rkE ^= rkA; + rkF ^= rkB; + x0 ^= rkC; + x1 ^= rkD; + x2 ^= rkE; + x3 ^= rkF; + AES_ROUND_NOKEY(x0, x1, x2, x3); + rk0 ^= rkD; + x0 ^= rk0; + rk1 ^= rkE; + x1 ^= rk1; + rk2 ^= rkF; + x2 ^= rk2; + rk3 ^= rk0; + x3 ^= rk3; + AES_ROUND_NOKEY(x0, x1, x2, x3); + p0 ^= x0; + p1 ^= x1; + p2 ^= x2; + p3 ^= x3; + /* round 3 */ + rk4 ^= rk1; + x0 = p0 ^ rk4; + rk5 ^= rk2; + x1 = p1 ^ rk5; + rk6 ^= rk3; + x2 = p2 ^ rk6; + rk7 ^= rk4; + x3 = p3 ^ rk7; + AES_ROUND_NOKEY(x0, x1, x2, x3); + rk8 ^= rk5; + x0 ^= rk8; + rk9 ^= rk6; + x1 ^= rk9; + rkA ^= rk7; + x2 ^= rkA; + rkB ^= rk8; + x3 ^= rkB; + AES_ROUND_NOKEY(x0, x1, x2, x3); + rkC ^= rk9; + x0 ^= rkC; + rkD ^= rkA; + x1 ^= rkD; + rkE ^= rkB; + x2 ^= rkE; + rkF ^= rkC; + x3 ^= rkF; + AES_ROUND_NOKEY(x0, x1, x2, x3); + p4 ^= x0; + p5 ^= x1; + p6 ^= x2; + p7 ^= x3; + /* round 4 */ + KEY_EXPAND_ELT(rk0, rk1, rk2, rk3); + rk0 ^= rkC; + rk1 ^= rkD; + rk2 ^= rkE; + rk3 ^= rkF; + x0 = p4 ^ rk0; + x1 = p5 ^ rk1; + x2 = p6 ^ rk2; + x3 = p7 ^ rk3; + AES_ROUND_NOKEY(x0, x1, x2, x3); + KEY_EXPAND_ELT(rk4, rk5, rk6, rk7); + rk4 ^= rk0; + rk5 ^= rk1; + rk6 ^= rk2; + rk7 ^= rk3; + x0 ^= rk4; + x1 ^= rk5; + x2 ^= rk6; + x3 ^= rk7; + AES_ROUND_NOKEY(x0, x1, x2, x3); + KEY_EXPAND_ELT(rk8, rk9, rkA, rkB); + rk8 ^= rk4; + rk9 ^= rk5 ^ sc->count1; + rkA ^= rk6 ^ SPH_T32(~sc->count0); + rkB ^= rk7; + x0 ^= rk8; + x1 ^= rk9; + x2 ^= rkA; + x3 ^= rkB; + AES_ROUND_NOKEY(x0, x1, x2, x3); + p0 ^= x0; + p1 ^= x1; + p2 ^= x2; + p3 ^= x3; + /* round 5 */ + KEY_EXPAND_ELT(rkC, rkD, rkE, rkF); + rkC ^= rk8; + rkD ^= rk9; + rkE ^= rkA; + rkF ^= rkB; + x0 = p0 ^ rkC; + x1 = p1 ^ rkD; + x2 = p2 ^ rkE; + x3 = p3 ^ rkF; + AES_ROUND_NOKEY(x0, x1, x2, x3); + rk0 ^= rkD; + x0 ^= rk0; + rk1 ^= rkE; + x1 ^= rk1; + rk2 ^= rkF; + x2 ^= rk2; + rk3 ^= rk0; + x3 ^= rk3; + AES_ROUND_NOKEY(x0, x1, x2, x3); + rk4 ^= rk1; + x0 ^= rk4; + rk5 ^= rk2; + x1 ^= rk5; + rk6 ^= rk3; + x2 ^= rk6; + rk7 ^= rk4; + x3 ^= rk7; + AES_ROUND_NOKEY(x0, x1, x2, x3); + p4 ^= x0; + p5 ^= x1; + p6 ^= x2; + p7 ^= x3; + /* round 6 */ + rk8 ^= rk5; + x0 = p4 ^ rk8; + rk9 ^= rk6; + x1 = p5 ^ rk9; + rkA ^= rk7; + x2 = p6 ^ rkA; + rkB ^= rk8; + x3 = p7 ^ rkB; + AES_ROUND_NOKEY(x0, x1, x2, x3); + rkC ^= rk9; + x0 ^= rkC; + rkD ^= rkA; + x1 ^= rkD; + rkE ^= rkB; + x2 ^= rkE; + rkF ^= rkC; + x3 ^= rkF; + AES_ROUND_NOKEY(x0, x1, x2, x3); + KEY_EXPAND_ELT(rk0, rk1, rk2, rk3); + rk0 ^= rkC; + rk1 ^= rkD; + rk2 ^= rkE; + rk3 ^= rkF; + x0 ^= rk0; + x1 ^= rk1; + x2 ^= rk2; + x3 ^= rk3; + AES_ROUND_NOKEY(x0, x1, x2, x3); + p0 ^= x0; + p1 ^= x1; + p2 ^= x2; + p3 ^= x3; + /* round 7 */ + KEY_EXPAND_ELT(rk4, rk5, rk6, rk7); + rk4 ^= rk0; + rk5 ^= rk1; + rk6 ^= rk2 ^ sc->count1; + rk7 ^= rk3 ^ SPH_T32(~sc->count0); + x0 = p0 ^ rk4; + x1 = p1 ^ rk5; + x2 = p2 ^ rk6; + x3 = p3 ^ rk7; + AES_ROUND_NOKEY(x0, x1, x2, x3); + KEY_EXPAND_ELT(rk8, rk9, rkA, rkB); + rk8 ^= rk4; + rk9 ^= rk5; + rkA ^= rk6; + rkB ^= rk7; + x0 ^= rk8; + x1 ^= rk9; + x2 ^= rkA; + x3 ^= rkB; + AES_ROUND_NOKEY(x0, x1, x2, x3); + KEY_EXPAND_ELT(rkC, rkD, rkE, rkF); + rkC ^= rk8; + rkD ^= rk9; + rkE ^= rkA; + rkF ^= rkB; + x0 ^= rkC; + x1 ^= rkD; + x2 ^= rkE; + x3 ^= rkF; + AES_ROUND_NOKEY(x0, x1, x2, x3); + p4 ^= x0; + p5 ^= x1; + p6 ^= x2; + p7 ^= x3; + /* round 8 */ + rk0 ^= rkD; + x0 = p4 ^ rk0; + rk1 ^= rkE; + x1 = p5 ^ rk1; + rk2 ^= rkF; + x2 = p6 ^ rk2; + rk3 ^= rk0; + x3 = p7 ^ rk3; + AES_ROUND_NOKEY(x0, x1, x2, x3); + rk4 ^= rk1; + x0 ^= rk4; + rk5 ^= rk2; + x1 ^= rk5; + rk6 ^= rk3; + x2 ^= rk6; + rk7 ^= rk4; + x3 ^= rk7; + AES_ROUND_NOKEY(x0, x1, x2, x3); + rk8 ^= rk5; + x0 ^= rk8; + rk9 ^= rk6; + x1 ^= rk9; + rkA ^= rk7; + x2 ^= rkA; + rkB ^= rk8; + x3 ^= rkB; + AES_ROUND_NOKEY(x0, x1, x2, x3); + p0 ^= x0; + p1 ^= x1; + p2 ^= x2; + p3 ^= x3; + /* round 9 */ + rkC ^= rk9; + x0 = p0 ^ rkC; + rkD ^= rkA; + x1 = p1 ^ rkD; + rkE ^= rkB; + x2 = p2 ^ rkE; + rkF ^= rkC; + x3 = p3 ^ rkF; + AES_ROUND_NOKEY(x0, x1, x2, x3); + KEY_EXPAND_ELT(rk0, rk1, rk2, rk3); + rk0 ^= rkC; + rk1 ^= rkD; + rk2 ^= rkE; + rk3 ^= rkF; + x0 ^= rk0; + x1 ^= rk1; + x2 ^= rk2; + x3 ^= rk3; + AES_ROUND_NOKEY(x0, x1, x2, x3); + KEY_EXPAND_ELT(rk4, rk5, rk6, rk7); + rk4 ^= rk0; + rk5 ^= rk1; + rk6 ^= rk2; + rk7 ^= rk3; + x0 ^= rk4; + x1 ^= rk5; + x2 ^= rk6; + x3 ^= rk7; + AES_ROUND_NOKEY(x0, x1, x2, x3); + p4 ^= x0; + p5 ^= x1; + p6 ^= x2; + p7 ^= x3; + /* round 10 */ + KEY_EXPAND_ELT(rk8, rk9, rkA, rkB); + rk8 ^= rk4; + rk9 ^= rk5; + rkA ^= rk6; + rkB ^= rk7; + x0 = p4 ^ rk8; + x1 = p5 ^ rk9; + x2 = p6 ^ rkA; + x3 = p7 ^ rkB; + AES_ROUND_NOKEY(x0, x1, x2, x3); + KEY_EXPAND_ELT(rkC, rkD, rkE, rkF); + rkC ^= rk8 ^ sc->count0; + rkD ^= rk9; + rkE ^= rkA; + rkF ^= rkB ^ SPH_T32(~sc->count1); + x0 ^= rkC; + x1 ^= rkD; + x2 ^= rkE; + x3 ^= rkF; + AES_ROUND_NOKEY(x0, x1, x2, x3); + rk0 ^= rkD; + x0 ^= rk0; + rk1 ^= rkE; + x1 ^= rk1; + rk2 ^= rkF; + x2 ^= rk2; + rk3 ^= rk0; + x3 ^= rk3; + AES_ROUND_NOKEY(x0, x1, x2, x3); + p0 ^= x0; + p1 ^= x1; + p2 ^= x2; + p3 ^= x3; + /* round 11 */ + rk4 ^= rk1; + x0 = p0 ^ rk4; + rk5 ^= rk2; + x1 = p1 ^ rk5; + rk6 ^= rk3; + x2 = p2 ^ rk6; + rk7 ^= rk4; + x3 = p3 ^ rk7; + AES_ROUND_NOKEY(x0, x1, x2, x3); + rk8 ^= rk5; + x0 ^= rk8; + rk9 ^= rk6; + x1 ^= rk9; + rkA ^= rk7; + x2 ^= rkA; + rkB ^= rk8; + x3 ^= rkB; + AES_ROUND_NOKEY(x0, x1, x2, x3); + rkC ^= rk9; + x0 ^= rkC; + rkD ^= rkA; + x1 ^= rkD; + rkE ^= rkB; + x2 ^= rkE; + rkF ^= rkC; + x3 ^= rkF; + AES_ROUND_NOKEY(x0, x1, x2, x3); + p4 ^= x0; + p5 ^= x1; + p6 ^= x2; + p7 ^= x3; + sc->h[0x0] ^= p0; + sc->h[0x1] ^= p1; + sc->h[0x2] ^= p2; + sc->h[0x3] ^= p3; + sc->h[0x4] ^= p4; + sc->h[0x5] ^= p5; + sc->h[0x6] ^= p6; + sc->h[0x7] ^= p7; +} + +#endif + +#if SPH_SMALL_FOOTPRINT_SHAVITE + +/* + * This function assumes that "msg" is aligned for 32-bit access. + */ +static void +c512(sph_shavite_big_context *sc, const void *msg) +{ + sph_u32 p0, p1, p2, p3, p4, p5, p6, p7; + sph_u32 p8, p9, pA, pB, pC, pD, pE, pF; + sph_u32 rk[448]; + size_t u; + int r, s; + +#if SPH_LITTLE_ENDIAN + memcpy(rk, msg, 128); +#else + for (u = 0; u < 32; u += 4) { + rk[u + 0] = sph_dec32le_aligned( + (const unsigned char *)msg + (u << 2) + 0); + rk[u + 1] = sph_dec32le_aligned( + (const unsigned char *)msg + (u << 2) + 4); + rk[u + 2] = sph_dec32le_aligned( + (const unsigned char *)msg + (u << 2) + 8); + rk[u + 3] = sph_dec32le_aligned( + (const unsigned char *)msg + (u << 2) + 12); + } +#endif + u = 32; + for (;;) { + for (s = 0; s < 4; s ++) { + sph_u32 x0, x1, x2, x3; + + x0 = rk[u - 31]; + x1 = rk[u - 30]; + x2 = rk[u - 29]; + x3 = rk[u - 32]; + AES_ROUND_NOKEY(x0, x1, x2, x3); + rk[u + 0] = x0 ^ rk[u - 4]; + rk[u + 1] = x1 ^ rk[u - 3]; + rk[u + 2] = x2 ^ rk[u - 2]; + rk[u + 3] = x3 ^ rk[u - 1]; + if (u == 32) { + rk[ 32] ^= sc->count0; + rk[ 33] ^= sc->count1; + rk[ 34] ^= sc->count2; + rk[ 35] ^= SPH_T32(~sc->count3); + } else if (u == 440) { + rk[440] ^= sc->count1; + rk[441] ^= sc->count0; + rk[442] ^= sc->count3; + rk[443] ^= SPH_T32(~sc->count2); + } + u += 4; + + x0 = rk[u - 31]; + x1 = rk[u - 30]; + x2 = rk[u - 29]; + x3 = rk[u - 32]; + AES_ROUND_NOKEY(x0, x1, x2, x3); + rk[u + 0] = x0 ^ rk[u - 4]; + rk[u + 1] = x1 ^ rk[u - 3]; + rk[u + 2] = x2 ^ rk[u - 2]; + rk[u + 3] = x3 ^ rk[u - 1]; + if (u == 164) { + rk[164] ^= sc->count3; + rk[165] ^= sc->count2; + rk[166] ^= sc->count1; + rk[167] ^= SPH_T32(~sc->count0); + } else if (u == 316) { + rk[316] ^= sc->count2; + rk[317] ^= sc->count3; + rk[318] ^= sc->count0; + rk[319] ^= SPH_T32(~sc->count1); + } + u += 4; + } + if (u == 448) + break; + for (s = 0; s < 8; s ++) { + rk[u + 0] = rk[u - 32] ^ rk[u - 7]; + rk[u + 1] = rk[u - 31] ^ rk[u - 6]; + rk[u + 2] = rk[u - 30] ^ rk[u - 5]; + rk[u + 3] = rk[u - 29] ^ rk[u - 4]; + u += 4; + } + } + + p0 = sc->h[0x0]; + p1 = sc->h[0x1]; + p2 = sc->h[0x2]; + p3 = sc->h[0x3]; + p4 = sc->h[0x4]; + p5 = sc->h[0x5]; + p6 = sc->h[0x6]; + p7 = sc->h[0x7]; + p8 = sc->h[0x8]; + p9 = sc->h[0x9]; + pA = sc->h[0xA]; + pB = sc->h[0xB]; + pC = sc->h[0xC]; + pD = sc->h[0xD]; + pE = sc->h[0xE]; + pF = sc->h[0xF]; + u = 0; + for (r = 0; r < 14; r ++) { +#define C512_ELT(l0, l1, l2, l3, r0, r1, r2, r3) do { \ + sph_u32 x0, x1, x2, x3; \ + x0 = r0 ^ rk[u ++]; \ + x1 = r1 ^ rk[u ++]; \ + x2 = r2 ^ rk[u ++]; \ + x3 = r3 ^ rk[u ++]; \ + AES_ROUND_NOKEY(x0, x1, x2, x3); \ + x0 ^= rk[u ++]; \ + x1 ^= rk[u ++]; \ + x2 ^= rk[u ++]; \ + x3 ^= rk[u ++]; \ + AES_ROUND_NOKEY(x0, x1, x2, x3); \ + x0 ^= rk[u ++]; \ + x1 ^= rk[u ++]; \ + x2 ^= rk[u ++]; \ + x3 ^= rk[u ++]; \ + AES_ROUND_NOKEY(x0, x1, x2, x3); \ + x0 ^= rk[u ++]; \ + x1 ^= rk[u ++]; \ + x2 ^= rk[u ++]; \ + x3 ^= rk[u ++]; \ + AES_ROUND_NOKEY(x0, x1, x2, x3); \ + l0 ^= x0; \ + l1 ^= x1; \ + l2 ^= x2; \ + l3 ^= x3; \ + } while (0) + +#define WROT(a, b, c, d) do { \ + sph_u32 t = d; \ + d = c; \ + c = b; \ + b = a; \ + a = t; \ + } while (0) + + C512_ELT(p0, p1, p2, p3, p4, p5, p6, p7); + C512_ELT(p8, p9, pA, pB, pC, pD, pE, pF); + + WROT(p0, p4, p8, pC); + WROT(p1, p5, p9, pD); + WROT(p2, p6, pA, pE); + WROT(p3, p7, pB, pF); + +#undef C512_ELT +#undef WROT + } + sc->h[0x0] ^= p0; + sc->h[0x1] ^= p1; + sc->h[0x2] ^= p2; + sc->h[0x3] ^= p3; + sc->h[0x4] ^= p4; + sc->h[0x5] ^= p5; + sc->h[0x6] ^= p6; + sc->h[0x7] ^= p7; + sc->h[0x8] ^= p8; + sc->h[0x9] ^= p9; + sc->h[0xA] ^= pA; + sc->h[0xB] ^= pB; + sc->h[0xC] ^= pC; + sc->h[0xD] ^= pD; + sc->h[0xE] ^= pE; + sc->h[0xF] ^= pF; +} + +#else + +/* + * This function assumes that "msg" is aligned for 32-bit access. + */ +static void +c512(sph_shavite_big_context *sc, const void *msg) +{ + sph_u32 p0, p1, p2, p3, p4, p5, p6, p7; + sph_u32 p8, p9, pA, pB, pC, pD, pE, pF; + sph_u32 x0, x1, x2, x3; + sph_u32 rk00, rk01, rk02, rk03, rk04, rk05, rk06, rk07; + sph_u32 rk08, rk09, rk0A, rk0B, rk0C, rk0D, rk0E, rk0F; + sph_u32 rk10, rk11, rk12, rk13, rk14, rk15, rk16, rk17; + sph_u32 rk18, rk19, rk1A, rk1B, rk1C, rk1D, rk1E, rk1F; + int r; + + p0 = sc->h[0x0]; + p1 = sc->h[0x1]; + p2 = sc->h[0x2]; + p3 = sc->h[0x3]; + p4 = sc->h[0x4]; + p5 = sc->h[0x5]; + p6 = sc->h[0x6]; + p7 = sc->h[0x7]; + p8 = sc->h[0x8]; + p9 = sc->h[0x9]; + pA = sc->h[0xA]; + pB = sc->h[0xB]; + pC = sc->h[0xC]; + pD = sc->h[0xD]; + pE = sc->h[0xE]; + pF = sc->h[0xF]; + /* round 0 */ + rk00 = sph_dec32le_aligned((const unsigned char *)msg + 0); + x0 = p4 ^ rk00; + rk01 = sph_dec32le_aligned((const unsigned char *)msg + 4); + x1 = p5 ^ rk01; + rk02 = sph_dec32le_aligned((const unsigned char *)msg + 8); + x2 = p6 ^ rk02; + rk03 = sph_dec32le_aligned((const unsigned char *)msg + 12); + x3 = p7 ^ rk03; + AES_ROUND_NOKEY(x0, x1, x2, x3); + rk04 = sph_dec32le_aligned((const unsigned char *)msg + 16); + x0 ^= rk04; + rk05 = sph_dec32le_aligned((const unsigned char *)msg + 20); + x1 ^= rk05; + rk06 = sph_dec32le_aligned((const unsigned char *)msg + 24); + x2 ^= rk06; + rk07 = sph_dec32le_aligned((const unsigned char *)msg + 28); + x3 ^= rk07; + AES_ROUND_NOKEY(x0, x1, x2, x3); + rk08 = sph_dec32le_aligned((const unsigned char *)msg + 32); + x0 ^= rk08; + rk09 = sph_dec32le_aligned((const unsigned char *)msg + 36); + x1 ^= rk09; + rk0A = sph_dec32le_aligned((const unsigned char *)msg + 40); + x2 ^= rk0A; + rk0B = sph_dec32le_aligned((const unsigned char *)msg + 44); + x3 ^= rk0B; + AES_ROUND_NOKEY(x0, x1, x2, x3); + rk0C = sph_dec32le_aligned((const unsigned char *)msg + 48); + x0 ^= rk0C; + rk0D = sph_dec32le_aligned((const unsigned char *)msg + 52); + x1 ^= rk0D; + rk0E = sph_dec32le_aligned((const unsigned char *)msg + 56); + x2 ^= rk0E; + rk0F = sph_dec32le_aligned((const unsigned char *)msg + 60); + x3 ^= rk0F; + AES_ROUND_NOKEY(x0, x1, x2, x3); + p0 ^= x0; + p1 ^= x1; + p2 ^= x2; + p3 ^= x3; + rk10 = sph_dec32le_aligned((const unsigned char *)msg + 64); + x0 = pC ^ rk10; + rk11 = sph_dec32le_aligned((const unsigned char *)msg + 68); + x1 = pD ^ rk11; + rk12 = sph_dec32le_aligned((const unsigned char *)msg + 72); + x2 = pE ^ rk12; + rk13 = sph_dec32le_aligned((const unsigned char *)msg + 76); + x3 = pF ^ rk13; + AES_ROUND_NOKEY(x0, x1, x2, x3); + rk14 = sph_dec32le_aligned((const unsigned char *)msg + 80); + x0 ^= rk14; + rk15 = sph_dec32le_aligned((const unsigned char *)msg + 84); + x1 ^= rk15; + rk16 = sph_dec32le_aligned((const unsigned char *)msg + 88); + x2 ^= rk16; + rk17 = sph_dec32le_aligned((const unsigned char *)msg + 92); + x3 ^= rk17; + AES_ROUND_NOKEY(x0, x1, x2, x3); + rk18 = sph_dec32le_aligned((const unsigned char *)msg + 96); + x0 ^= rk18; + rk19 = sph_dec32le_aligned((const unsigned char *)msg + 100); + x1 ^= rk19; + rk1A = sph_dec32le_aligned((const unsigned char *)msg + 104); + x2 ^= rk1A; + rk1B = sph_dec32le_aligned((const unsigned char *)msg + 108); + x3 ^= rk1B; + AES_ROUND_NOKEY(x0, x1, x2, x3); + rk1C = sph_dec32le_aligned((const unsigned char *)msg + 112); + x0 ^= rk1C; + rk1D = sph_dec32le_aligned((const unsigned char *)msg + 116); + x1 ^= rk1D; + rk1E = sph_dec32le_aligned((const unsigned char *)msg + 120); + x2 ^= rk1E; + rk1F = sph_dec32le_aligned((const unsigned char *)msg + 124); + x3 ^= rk1F; + AES_ROUND_NOKEY(x0, x1, x2, x3); + p8 ^= x0; + p9 ^= x1; + pA ^= x2; + pB ^= x3; + + for (r = 0; r < 3; r ++) { + /* round 1, 5, 9 */ + KEY_EXPAND_ELT(rk00, rk01, rk02, rk03); + rk00 ^= rk1C; + rk01 ^= rk1D; + rk02 ^= rk1E; + rk03 ^= rk1F; + if (r == 0) { + rk00 ^= sc->count0; + rk01 ^= sc->count1; + rk02 ^= sc->count2; + rk03 ^= SPH_T32(~sc->count3); + } + x0 = p0 ^ rk00; + x1 = p1 ^ rk01; + x2 = p2 ^ rk02; + x3 = p3 ^ rk03; + AES_ROUND_NOKEY(x0, x1, x2, x3); + KEY_EXPAND_ELT(rk04, rk05, rk06, rk07); + rk04 ^= rk00; + rk05 ^= rk01; + rk06 ^= rk02; + rk07 ^= rk03; + if (r == 1) { + rk04 ^= sc->count3; + rk05 ^= sc->count2; + rk06 ^= sc->count1; + rk07 ^= SPH_T32(~sc->count0); + } + x0 ^= rk04; + x1 ^= rk05; + x2 ^= rk06; + x3 ^= rk07; + AES_ROUND_NOKEY(x0, x1, x2, x3); + KEY_EXPAND_ELT(rk08, rk09, rk0A, rk0B); + rk08 ^= rk04; + rk09 ^= rk05; + rk0A ^= rk06; + rk0B ^= rk07; + x0 ^= rk08; + x1 ^= rk09; + x2 ^= rk0A; + x3 ^= rk0B; + AES_ROUND_NOKEY(x0, x1, x2, x3); + KEY_EXPAND_ELT(rk0C, rk0D, rk0E, rk0F); + rk0C ^= rk08; + rk0D ^= rk09; + rk0E ^= rk0A; + rk0F ^= rk0B; + x0 ^= rk0C; + x1 ^= rk0D; + x2 ^= rk0E; + x3 ^= rk0F; + AES_ROUND_NOKEY(x0, x1, x2, x3); + pC ^= x0; + pD ^= x1; + pE ^= x2; + pF ^= x3; + KEY_EXPAND_ELT(rk10, rk11, rk12, rk13); + rk10 ^= rk0C; + rk11 ^= rk0D; + rk12 ^= rk0E; + rk13 ^= rk0F; + x0 = p8 ^ rk10; + x1 = p9 ^ rk11; + x2 = pA ^ rk12; + x3 = pB ^ rk13; + AES_ROUND_NOKEY(x0, x1, x2, x3); + KEY_EXPAND_ELT(rk14, rk15, rk16, rk17); + rk14 ^= rk10; + rk15 ^= rk11; + rk16 ^= rk12; + rk17 ^= rk13; + x0 ^= rk14; + x1 ^= rk15; + x2 ^= rk16; + x3 ^= rk17; + AES_ROUND_NOKEY(x0, x1, x2, x3); + KEY_EXPAND_ELT(rk18, rk19, rk1A, rk1B); + rk18 ^= rk14; + rk19 ^= rk15; + rk1A ^= rk16; + rk1B ^= rk17; + x0 ^= rk18; + x1 ^= rk19; + x2 ^= rk1A; + x3 ^= rk1B; + AES_ROUND_NOKEY(x0, x1, x2, x3); + KEY_EXPAND_ELT(rk1C, rk1D, rk1E, rk1F); + rk1C ^= rk18; + rk1D ^= rk19; + rk1E ^= rk1A; + rk1F ^= rk1B; + if (r == 2) { + rk1C ^= sc->count2; + rk1D ^= sc->count3; + rk1E ^= sc->count0; + rk1F ^= SPH_T32(~sc->count1); + } + x0 ^= rk1C; + x1 ^= rk1D; + x2 ^= rk1E; + x3 ^= rk1F; + AES_ROUND_NOKEY(x0, x1, x2, x3); + p4 ^= x0; + p5 ^= x1; + p6 ^= x2; + p7 ^= x3; + /* round 2, 6, 10 */ + rk00 ^= rk19; + x0 = pC ^ rk00; + rk01 ^= rk1A; + x1 = pD ^ rk01; + rk02 ^= rk1B; + x2 = pE ^ rk02; + rk03 ^= rk1C; + x3 = pF ^ rk03; + AES_ROUND_NOKEY(x0, x1, x2, x3); + rk04 ^= rk1D; + x0 ^= rk04; + rk05 ^= rk1E; + x1 ^= rk05; + rk06 ^= rk1F; + x2 ^= rk06; + rk07 ^= rk00; + x3 ^= rk07; + AES_ROUND_NOKEY(x0, x1, x2, x3); + rk08 ^= rk01; + x0 ^= rk08; + rk09 ^= rk02; + x1 ^= rk09; + rk0A ^= rk03; + x2 ^= rk0A; + rk0B ^= rk04; + x3 ^= rk0B; + AES_ROUND_NOKEY(x0, x1, x2, x3); + rk0C ^= rk05; + x0 ^= rk0C; + rk0D ^= rk06; + x1 ^= rk0D; + rk0E ^= rk07; + x2 ^= rk0E; + rk0F ^= rk08; + x3 ^= rk0F; + AES_ROUND_NOKEY(x0, x1, x2, x3); + p8 ^= x0; + p9 ^= x1; + pA ^= x2; + pB ^= x3; + rk10 ^= rk09; + x0 = p4 ^ rk10; + rk11 ^= rk0A; + x1 = p5 ^ rk11; + rk12 ^= rk0B; + x2 = p6 ^ rk12; + rk13 ^= rk0C; + x3 = p7 ^ rk13; + AES_ROUND_NOKEY(x0, x1, x2, x3); + rk14 ^= rk0D; + x0 ^= rk14; + rk15 ^= rk0E; + x1 ^= rk15; + rk16 ^= rk0F; + x2 ^= rk16; + rk17 ^= rk10; + x3 ^= rk17; + AES_ROUND_NOKEY(x0, x1, x2, x3); + rk18 ^= rk11; + x0 ^= rk18; + rk19 ^= rk12; + x1 ^= rk19; + rk1A ^= rk13; + x2 ^= rk1A; + rk1B ^= rk14; + x3 ^= rk1B; + AES_ROUND_NOKEY(x0, x1, x2, x3); + rk1C ^= rk15; + x0 ^= rk1C; + rk1D ^= rk16; + x1 ^= rk1D; + rk1E ^= rk17; + x2 ^= rk1E; + rk1F ^= rk18; + x3 ^= rk1F; + AES_ROUND_NOKEY(x0, x1, x2, x3); + p0 ^= x0; + p1 ^= x1; + p2 ^= x2; + p3 ^= x3; + /* round 3, 7, 11 */ + KEY_EXPAND_ELT(rk00, rk01, rk02, rk03); + rk00 ^= rk1C; + rk01 ^= rk1D; + rk02 ^= rk1E; + rk03 ^= rk1F; + x0 = p8 ^ rk00; + x1 = p9 ^ rk01; + x2 = pA ^ rk02; + x3 = pB ^ rk03; + AES_ROUND_NOKEY(x0, x1, x2, x3); + KEY_EXPAND_ELT(rk04, rk05, rk06, rk07); + rk04 ^= rk00; + rk05 ^= rk01; + rk06 ^= rk02; + rk07 ^= rk03; + x0 ^= rk04; + x1 ^= rk05; + x2 ^= rk06; + x3 ^= rk07; + AES_ROUND_NOKEY(x0, x1, x2, x3); + KEY_EXPAND_ELT(rk08, rk09, rk0A, rk0B); + rk08 ^= rk04; + rk09 ^= rk05; + rk0A ^= rk06; + rk0B ^= rk07; + x0 ^= rk08; + x1 ^= rk09; + x2 ^= rk0A; + x3 ^= rk0B; + AES_ROUND_NOKEY(x0, x1, x2, x3); + KEY_EXPAND_ELT(rk0C, rk0D, rk0E, rk0F); + rk0C ^= rk08; + rk0D ^= rk09; + rk0E ^= rk0A; + rk0F ^= rk0B; + x0 ^= rk0C; + x1 ^= rk0D; + x2 ^= rk0E; + x3 ^= rk0F; + AES_ROUND_NOKEY(x0, x1, x2, x3); + p4 ^= x0; + p5 ^= x1; + p6 ^= x2; + p7 ^= x3; + KEY_EXPAND_ELT(rk10, rk11, rk12, rk13); + rk10 ^= rk0C; + rk11 ^= rk0D; + rk12 ^= rk0E; + rk13 ^= rk0F; + x0 = p0 ^ rk10; + x1 = p1 ^ rk11; + x2 = p2 ^ rk12; + x3 = p3 ^ rk13; + AES_ROUND_NOKEY(x0, x1, x2, x3); + KEY_EXPAND_ELT(rk14, rk15, rk16, rk17); + rk14 ^= rk10; + rk15 ^= rk11; + rk16 ^= rk12; + rk17 ^= rk13; + x0 ^= rk14; + x1 ^= rk15; + x2 ^= rk16; + x3 ^= rk17; + AES_ROUND_NOKEY(x0, x1, x2, x3); + KEY_EXPAND_ELT(rk18, rk19, rk1A, rk1B); + rk18 ^= rk14; + rk19 ^= rk15; + rk1A ^= rk16; + rk1B ^= rk17; + x0 ^= rk18; + x1 ^= rk19; + x2 ^= rk1A; + x3 ^= rk1B; + AES_ROUND_NOKEY(x0, x1, x2, x3); + KEY_EXPAND_ELT(rk1C, rk1D, rk1E, rk1F); + rk1C ^= rk18; + rk1D ^= rk19; + rk1E ^= rk1A; + rk1F ^= rk1B; + x0 ^= rk1C; + x1 ^= rk1D; + x2 ^= rk1E; + x3 ^= rk1F; + AES_ROUND_NOKEY(x0, x1, x2, x3); + pC ^= x0; + pD ^= x1; + pE ^= x2; + pF ^= x3; + /* round 4, 8, 12 */ + rk00 ^= rk19; + x0 = p4 ^ rk00; + rk01 ^= rk1A; + x1 = p5 ^ rk01; + rk02 ^= rk1B; + x2 = p6 ^ rk02; + rk03 ^= rk1C; + x3 = p7 ^ rk03; + AES_ROUND_NOKEY(x0, x1, x2, x3); + rk04 ^= rk1D; + x0 ^= rk04; + rk05 ^= rk1E; + x1 ^= rk05; + rk06 ^= rk1F; + x2 ^= rk06; + rk07 ^= rk00; + x3 ^= rk07; + AES_ROUND_NOKEY(x0, x1, x2, x3); + rk08 ^= rk01; + x0 ^= rk08; + rk09 ^= rk02; + x1 ^= rk09; + rk0A ^= rk03; + x2 ^= rk0A; + rk0B ^= rk04; + x3 ^= rk0B; + AES_ROUND_NOKEY(x0, x1, x2, x3); + rk0C ^= rk05; + x0 ^= rk0C; + rk0D ^= rk06; + x1 ^= rk0D; + rk0E ^= rk07; + x2 ^= rk0E; + rk0F ^= rk08; + x3 ^= rk0F; + AES_ROUND_NOKEY(x0, x1, x2, x3); + p0 ^= x0; + p1 ^= x1; + p2 ^= x2; + p3 ^= x3; + rk10 ^= rk09; + x0 = pC ^ rk10; + rk11 ^= rk0A; + x1 = pD ^ rk11; + rk12 ^= rk0B; + x2 = pE ^ rk12; + rk13 ^= rk0C; + x3 = pF ^ rk13; + AES_ROUND_NOKEY(x0, x1, x2, x3); + rk14 ^= rk0D; + x0 ^= rk14; + rk15 ^= rk0E; + x1 ^= rk15; + rk16 ^= rk0F; + x2 ^= rk16; + rk17 ^= rk10; + x3 ^= rk17; + AES_ROUND_NOKEY(x0, x1, x2, x3); + rk18 ^= rk11; + x0 ^= rk18; + rk19 ^= rk12; + x1 ^= rk19; + rk1A ^= rk13; + x2 ^= rk1A; + rk1B ^= rk14; + x3 ^= rk1B; + AES_ROUND_NOKEY(x0, x1, x2, x3); + rk1C ^= rk15; + x0 ^= rk1C; + rk1D ^= rk16; + x1 ^= rk1D; + rk1E ^= rk17; + x2 ^= rk1E; + rk1F ^= rk18; + x3 ^= rk1F; + AES_ROUND_NOKEY(x0, x1, x2, x3); + p8 ^= x0; + p9 ^= x1; + pA ^= x2; + pB ^= x3; + } + /* round 13 */ + KEY_EXPAND_ELT(rk00, rk01, rk02, rk03); + rk00 ^= rk1C; + rk01 ^= rk1D; + rk02 ^= rk1E; + rk03 ^= rk1F; + x0 = p0 ^ rk00; + x1 = p1 ^ rk01; + x2 = p2 ^ rk02; + x3 = p3 ^ rk03; + AES_ROUND_NOKEY(x0, x1, x2, x3); + KEY_EXPAND_ELT(rk04, rk05, rk06, rk07); + rk04 ^= rk00; + rk05 ^= rk01; + rk06 ^= rk02; + rk07 ^= rk03; + x0 ^= rk04; + x1 ^= rk05; + x2 ^= rk06; + x3 ^= rk07; + AES_ROUND_NOKEY(x0, x1, x2, x3); + KEY_EXPAND_ELT(rk08, rk09, rk0A, rk0B); + rk08 ^= rk04; + rk09 ^= rk05; + rk0A ^= rk06; + rk0B ^= rk07; + x0 ^= rk08; + x1 ^= rk09; + x2 ^= rk0A; + x3 ^= rk0B; + AES_ROUND_NOKEY(x0, x1, x2, x3); + KEY_EXPAND_ELT(rk0C, rk0D, rk0E, rk0F); + rk0C ^= rk08; + rk0D ^= rk09; + rk0E ^= rk0A; + rk0F ^= rk0B; + x0 ^= rk0C; + x1 ^= rk0D; + x2 ^= rk0E; + x3 ^= rk0F; + AES_ROUND_NOKEY(x0, x1, x2, x3); + pC ^= x0; + pD ^= x1; + pE ^= x2; + pF ^= x3; + KEY_EXPAND_ELT(rk10, rk11, rk12, rk13); + rk10 ^= rk0C; + rk11 ^= rk0D; + rk12 ^= rk0E; + rk13 ^= rk0F; + x0 = p8 ^ rk10; + x1 = p9 ^ rk11; + x2 = pA ^ rk12; + x3 = pB ^ rk13; + AES_ROUND_NOKEY(x0, x1, x2, x3); + KEY_EXPAND_ELT(rk14, rk15, rk16, rk17); + rk14 ^= rk10; + rk15 ^= rk11; + rk16 ^= rk12; + rk17 ^= rk13; + x0 ^= rk14; + x1 ^= rk15; + x2 ^= rk16; + x3 ^= rk17; + AES_ROUND_NOKEY(x0, x1, x2, x3); + KEY_EXPAND_ELT(rk18, rk19, rk1A, rk1B); + rk18 ^= rk14 ^ sc->count1; + rk19 ^= rk15 ^ sc->count0; + rk1A ^= rk16 ^ sc->count3; + rk1B ^= rk17 ^ SPH_T32(~sc->count2); + x0 ^= rk18; + x1 ^= rk19; + x2 ^= rk1A; + x3 ^= rk1B; + AES_ROUND_NOKEY(x0, x1, x2, x3); + KEY_EXPAND_ELT(rk1C, rk1D, rk1E, rk1F); + rk1C ^= rk18; + rk1D ^= rk19; + rk1E ^= rk1A; + rk1F ^= rk1B; + x0 ^= rk1C; + x1 ^= rk1D; + x2 ^= rk1E; + x3 ^= rk1F; + AES_ROUND_NOKEY(x0, x1, x2, x3); + p4 ^= x0; + p5 ^= x1; + p6 ^= x2; + p7 ^= x3; + sc->h[0x0] ^= p8; + sc->h[0x1] ^= p9; + sc->h[0x2] ^= pA; + sc->h[0x3] ^= pB; + sc->h[0x4] ^= pC; + sc->h[0x5] ^= pD; + sc->h[0x6] ^= pE; + sc->h[0x7] ^= pF; + sc->h[0x8] ^= p0; + sc->h[0x9] ^= p1; + sc->h[0xA] ^= p2; + sc->h[0xB] ^= p3; + sc->h[0xC] ^= p4; + sc->h[0xD] ^= p5; + sc->h[0xE] ^= p6; + sc->h[0xF] ^= p7; +} + +#endif + +static void +shavite_small_init(sph_shavite_small_context *sc, const sph_u32 *iv) +{ + memcpy(sc->h, iv, sizeof sc->h); + sc->ptr = 0; + sc->count0 = 0; + sc->count1 = 0; +} + +static void +shavite_small_core(sph_shavite_small_context *sc, const void *data, size_t len) +{ + unsigned char *buf; + size_t ptr; + + buf = sc->buf; + ptr = sc->ptr; + while (len > 0) { + size_t clen; + + clen = (sizeof sc->buf) - ptr; + if (clen > len) + clen = len; + memcpy(buf + ptr, data, clen); + data = (const unsigned char *)data + clen; + ptr += clen; + len -= clen; + if (ptr == sizeof sc->buf) { + if ((sc->count0 = SPH_T32(sc->count0 + 512)) == 0) + sc->count1 = SPH_T32(sc->count1 + 1); + c256(sc, buf); + ptr = 0; + } + } + sc->ptr = ptr; +} + +static void +shavite_small_close(sph_shavite_small_context *sc, + unsigned ub, unsigned n, void *dst, size_t out_size_w32) +{ + unsigned char *buf; + size_t ptr, u; + unsigned z; + sph_u32 count0, count1; + + buf = sc->buf; + ptr = sc->ptr; + count0 = (sc->count0 += (ptr << 3) + n); + count1 = sc->count1; + z = 0x80 >> n; + z = ((ub & -z) | z) & 0xFF; + if (ptr == 0 && n == 0) { + buf[0] = 0x80; + memset(buf + 1, 0, 53); + sc->count0 = sc->count1 = 0; + } else if (ptr < 54) { + buf[ptr ++] = z; + memset(buf + ptr, 0, 54 - ptr); + } else { + buf[ptr ++] = z; + memset(buf + ptr, 0, 64 - ptr); + c256(sc, buf); + memset(buf, 0, 54); + sc->count0 = sc->count1 = 0; + } + sph_enc32le(buf + 54, count0); + sph_enc32le(buf + 58, count1); + buf[62] = out_size_w32 << 5; + buf[63] = out_size_w32 >> 3; + c256(sc, buf); + for (u = 0; u < out_size_w32; u ++) + sph_enc32le((unsigned char *)dst + (u << 2), sc->h[u]); +} + +static void +shavite_big_init(sph_shavite_big_context *sc, const sph_u32 *iv) +{ + memcpy(sc->h, iv, sizeof sc->h); + sc->ptr = 0; + sc->count0 = 0; + sc->count1 = 0; + sc->count2 = 0; + sc->count3 = 0; +} + +static void +shavite_big_core(sph_shavite_big_context *sc, const void *data, size_t len) +{ + unsigned char *buf; + size_t ptr; + + buf = sc->buf; + ptr = sc->ptr; + while (len > 0) { + size_t clen; + + clen = (sizeof sc->buf) - ptr; + if (clen > len) + clen = len; + memcpy(buf + ptr, data, clen); + data = (const unsigned char *)data + clen; + ptr += clen; + len -= clen; + if (ptr == sizeof sc->buf) { + if ((sc->count0 = SPH_T32(sc->count0 + 1024)) == 0) { + sc->count1 = SPH_T32(sc->count1 + 1); + if (sc->count1 == 0) { + sc->count2 = SPH_T32(sc->count2 + 1); + if (sc->count2 == 0) { + sc->count3 = SPH_T32( + sc->count3 + 1); + } + } + } + c512(sc, buf); + ptr = 0; + } + } + sc->ptr = ptr; +} + +static void +shavite_big_close(sph_shavite_big_context *sc, + unsigned ub, unsigned n, void *dst, size_t out_size_w32) +{ + unsigned char *buf; + size_t ptr, u; + unsigned z; + sph_u32 count0, count1, count2, count3; + + buf = sc->buf; + ptr = sc->ptr; + count0 = (sc->count0 += (ptr << 3) + n); + count1 = sc->count1; + count2 = sc->count2; + count3 = sc->count3; + z = 0x80 >> n; + z = ((ub & -z) | z) & 0xFF; + if (ptr == 0 && n == 0) { + buf[0] = 0x80; + memset(buf + 1, 0, 109); + sc->count0 = sc->count1 = sc->count2 = sc->count3 = 0; + } else if (ptr < 110) { + buf[ptr ++] = z; + memset(buf + ptr, 0, 110 - ptr); + } else { + buf[ptr ++] = z; + memset(buf + ptr, 0, 128 - ptr); + c512(sc, buf); + memset(buf, 0, 110); + sc->count0 = sc->count1 = sc->count2 = sc->count3 = 0; + } + sph_enc32le(buf + 110, count0); + sph_enc32le(buf + 114, count1); + sph_enc32le(buf + 118, count2); + sph_enc32le(buf + 122, count3); + buf[126] = out_size_w32 << 5; + buf[127] = out_size_w32 >> 3; + c512(sc, buf); + for (u = 0; u < out_size_w32; u ++) + sph_enc32le((unsigned char *)dst + (u << 2), sc->h[u]); +} + +/* see sph_shavite.h */ +void +sph_shavite224_init(void *cc) +{ + shavite_small_init(cc, IV224); +} + +/* see sph_shavite.h */ +void +sph_shavite224(void *cc, const void *data, size_t len) +{ + shavite_small_core(cc, data, len); +} + +/* see sph_shavite.h */ +void +sph_shavite224_close(void *cc, void *dst) +{ + shavite_small_close(cc, 0, 0, dst, 7); + shavite_small_init(cc, IV224); +} + +/* see sph_shavite.h */ +void +sph_shavite224_addbits_and_close(void *cc, unsigned ub, unsigned n, void *dst) +{ + shavite_small_close(cc, ub, n, dst, 7); + shavite_small_init(cc, IV224); +} + +/* see sph_shavite.h */ +void +sph_shavite256_init(void *cc) +{ + shavite_small_init(cc, IV256); +} + +/* see sph_shavite.h */ +void +sph_shavite256(void *cc, const void *data, size_t len) +{ + shavite_small_core(cc, data, len); +} + +/* see sph_shavite.h */ +void +sph_shavite256_close(void *cc, void *dst) +{ + shavite_small_close(cc, 0, 0, dst, 8); + shavite_small_init(cc, IV256); +} + +/* see sph_shavite.h */ +void +sph_shavite256_addbits_and_close(void *cc, unsigned ub, unsigned n, void *dst) +{ + shavite_small_close(cc, ub, n, dst, 8); + shavite_small_init(cc, IV256); +} + +/* see sph_shavite.h */ +void +sph_shavite384_init(void *cc) +{ + shavite_big_init(cc, IV384); +} + +/* see sph_shavite.h */ +void +sph_shavite384(void *cc, const void *data, size_t len) +{ + shavite_big_core(cc, data, len); +} + +/* see sph_shavite.h */ +void +sph_shavite384_close(void *cc, void *dst) +{ + shavite_big_close(cc, 0, 0, dst, 12); + shavite_big_init(cc, IV384); +} + +/* see sph_shavite.h */ +void +sph_shavite384_addbits_and_close(void *cc, unsigned ub, unsigned n, void *dst) +{ + shavite_big_close(cc, ub, n, dst, 12); + shavite_big_init(cc, IV384); +} + +/* see sph_shavite.h */ +void +sph_shavite512_init(void *cc) +{ + shavite_big_init(cc, IV512); +} + +/* see sph_shavite.h */ +void +sph_shavite512(void *cc, const void *data, size_t len) +{ + shavite_big_core(cc, data, len); +} + +/* see sph_shavite.h */ +void +sph_shavite512_close(void *cc, void *dst) +{ + shavite_big_close(cc, 0, 0, dst, 16); + shavite_big_init(cc, IV512); +} + +/* see sph_shavite.h */ +void +sph_shavite512_addbits_and_close(void *cc, unsigned ub, unsigned n, void *dst) +{ + shavite_big_close(cc, ub, n, dst, 16); + shavite_big_init(cc, IV512); +} + +#ifdef __cplusplus +} +#endif diff --git a/src/simd.c b/src/simd.c new file mode 100644 index 0000000..1e94d92 --- /dev/null +++ b/src/simd.c @@ -0,0 +1,1799 @@ +/* $Id: simd.c 227 2010-06-16 17:28:38Z tp $ */ +/* + * SIMD implementation. + * + * ==========================(LICENSE BEGIN)============================ + * + * Copyright (c) 2007-2010 Projet RNRT SAPHIR + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * ===========================(LICENSE END)============================= + * + * @author Thomas Pornin + */ + +#include +#include +#include + +#include "sph_simd.h" + +#ifdef __cplusplus +extern "C"{ +#endif + +#if SPH_SMALL_FOOTPRINT && !defined SPH_SMALL_FOOTPRINT_SIMD +#define SPH_SMALL_FOOTPRINT_SIMD 1 +#endif + +#ifdef _MSC_VER +#pragma warning (disable: 4146) +#endif + +typedef sph_u32 u32; +typedef sph_s32 s32; +#define C32 SPH_C32 +#define T32 SPH_T32 +#define ROL32 SPH_ROTL32 + +#define XCAT(x, y) XCAT_(x, y) +#define XCAT_(x, y) x ## y + +/* + * The powers of 41 modulo 257. We use exponents from 0 to 255, inclusive. + */ +static const s32 alpha_tab[] = { + 1, 41, 139, 45, 46, 87, 226, 14, 60, 147, 116, 130, + 190, 80, 196, 69, 2, 82, 21, 90, 92, 174, 195, 28, + 120, 37, 232, 3, 123, 160, 135, 138, 4, 164, 42, 180, + 184, 91, 133, 56, 240, 74, 207, 6, 246, 63, 13, 19, + 8, 71, 84, 103, 111, 182, 9, 112, 223, 148, 157, 12, + 235, 126, 26, 38, 16, 142, 168, 206, 222, 107, 18, 224, + 189, 39, 57, 24, 213, 252, 52, 76, 32, 27, 79, 155, + 187, 214, 36, 191, 121, 78, 114, 48, 169, 247, 104, 152, + 64, 54, 158, 53, 117, 171, 72, 125, 242, 156, 228, 96, + 81, 237, 208, 47, 128, 108, 59, 106, 234, 85, 144, 250, + 227, 55, 199, 192, 162, 217, 159, 94, 256, 216, 118, 212, + 211, 170, 31, 243, 197, 110, 141, 127, 67, 177, 61, 188, + 255, 175, 236, 167, 165, 83, 62, 229, 137, 220, 25, 254, + 134, 97, 122, 119, 253, 93, 215, 77, 73, 166, 124, 201, + 17, 183, 50, 251, 11, 194, 244, 238, 249, 186, 173, 154, + 146, 75, 248, 145, 34, 109, 100, 245, 22, 131, 231, 219, + 241, 115, 89, 51, 35, 150, 239, 33, 68, 218, 200, 233, + 44, 5, 205, 181, 225, 230, 178, 102, 70, 43, 221, 66, + 136, 179, 143, 209, 88, 10, 153, 105, 193, 203, 99, 204, + 140, 86, 185, 132, 15, 101, 29, 161, 176, 20, 49, 210, + 129, 149, 198, 151, 23, 172, 113, 7, 30, 202, 58, 65, + 95, 40, 98, 163 +}; + +/* + * Ranges: + * REDS1: from -32768..98302 to -383..383 + * REDS2: from -2^31..2^31-1 to -32768..98302 + */ +#define REDS1(x) (((x) & 0xFF) - ((x) >> 8)) +#define REDS2(x) (((x) & 0xFFFF) + ((x) >> 16)) + +/* + * If, upon entry, the values of q[] are all in the -N..N range (where + * N >= 98302) then the new values of q[] are in the -2N..2N range. + * + * Since alpha_tab[v] <= 256, maximum allowed range is for N = 8388608. + */ +#define FFT_LOOP(rb, hk, as, id) do { \ + size_t u, v; \ + s32 m = q[(rb)]; \ + s32 n = q[(rb) + (hk)]; \ + q[(rb)] = m + n; \ + q[(rb) + (hk)] = m - n; \ + u = v = 0; \ + goto id; \ + for (; u < (hk); u += 4, v += 4 * (as)) { \ + s32 t; \ + m = q[(rb) + u + 0]; \ + n = q[(rb) + u + 0 + (hk)]; \ + t = REDS2(n * alpha_tab[v + 0 * (as)]); \ + q[(rb) + u + 0] = m + t; \ + q[(rb) + u + 0 + (hk)] = m - t; \ + id: \ + m = q[(rb) + u + 1]; \ + n = q[(rb) + u + 1 + (hk)]; \ + t = REDS2(n * alpha_tab[v + 1 * (as)]); \ + q[(rb) + u + 1] = m + t; \ + q[(rb) + u + 1 + (hk)] = m - t; \ + m = q[(rb) + u + 2]; \ + n = q[(rb) + u + 2 + (hk)]; \ + t = REDS2(n * alpha_tab[v + 2 * (as)]); \ + q[(rb) + u + 2] = m + t; \ + q[(rb) + u + 2 + (hk)] = m - t; \ + m = q[(rb) + u + 3]; \ + n = q[(rb) + u + 3 + (hk)]; \ + t = REDS2(n * alpha_tab[v + 3 * (as)]); \ + q[(rb) + u + 3] = m + t; \ + q[(rb) + u + 3 + (hk)] = m - t; \ + } \ + } while (0) + +/* + * Output ranges: + * d0: min= 0 max= 1020 + * d1: min= -67 max= 4587 + * d2: min=-4335 max= 4335 + * d3: min=-4147 max= 507 + * d4: min= -510 max= 510 + * d5: min= -252 max= 4402 + * d6: min=-4335 max= 4335 + * d7: min=-4332 max= 322 + */ +#define FFT8(xb, xs, d) do { \ + s32 x0 = x[(xb)]; \ + s32 x1 = x[(xb) + (xs)]; \ + s32 x2 = x[(xb) + 2 * (xs)]; \ + s32 x3 = x[(xb) + 3 * (xs)]; \ + s32 a0 = x0 + x2; \ + s32 a1 = x0 + (x2 << 4); \ + s32 a2 = x0 - x2; \ + s32 a3 = x0 - (x2 << 4); \ + s32 b0 = x1 + x3; \ + s32 b1 = REDS1((x1 << 2) + (x3 << 6)); \ + s32 b2 = (x1 << 4) - (x3 << 4); \ + s32 b3 = REDS1((x1 << 6) + (x3 << 2)); \ + d ## 0 = a0 + b0; \ + d ## 1 = a1 + b1; \ + d ## 2 = a2 + b2; \ + d ## 3 = a3 + b3; \ + d ## 4 = a0 - b0; \ + d ## 5 = a1 - b1; \ + d ## 6 = a2 - b2; \ + d ## 7 = a3 - b3; \ + } while (0) + +/* + * When k=16, we have alpha=2. Multiplication by alpha^i is then reduced + * to some shifting. + * + * Output: within -591471..591723 + */ +#define FFT16(xb, xs, rb) do { \ + s32 d1_0, d1_1, d1_2, d1_3, d1_4, d1_5, d1_6, d1_7; \ + s32 d2_0, d2_1, d2_2, d2_3, d2_4, d2_5, d2_6, d2_7; \ + FFT8(xb, (xs) << 1, d1_); \ + FFT8((xb) + (xs), (xs) << 1, d2_); \ + q[(rb) + 0] = d1_0 + d2_0; \ + q[(rb) + 1] = d1_1 + (d2_1 << 1); \ + q[(rb) + 2] = d1_2 + (d2_2 << 2); \ + q[(rb) + 3] = d1_3 + (d2_3 << 3); \ + q[(rb) + 4] = d1_4 + (d2_4 << 4); \ + q[(rb) + 5] = d1_5 + (d2_5 << 5); \ + q[(rb) + 6] = d1_6 + (d2_6 << 6); \ + q[(rb) + 7] = d1_7 + (d2_7 << 7); \ + q[(rb) + 8] = d1_0 - d2_0; \ + q[(rb) + 9] = d1_1 - (d2_1 << 1); \ + q[(rb) + 10] = d1_2 - (d2_2 << 2); \ + q[(rb) + 11] = d1_3 - (d2_3 << 3); \ + q[(rb) + 12] = d1_4 - (d2_4 << 4); \ + q[(rb) + 13] = d1_5 - (d2_5 << 5); \ + q[(rb) + 14] = d1_6 - (d2_6 << 6); \ + q[(rb) + 15] = d1_7 - (d2_7 << 7); \ + } while (0) + +/* + * Output range: |q| <= 1183446 + */ +#define FFT32(xb, xs, rb, id) do { \ + FFT16(xb, (xs) << 1, rb); \ + FFT16((xb) + (xs), (xs) << 1, (rb) + 16); \ + FFT_LOOP(rb, 16, 8, id); \ + } while (0) + +/* + * Output range: |q| <= 2366892 + */ +#define FFT64(xb, xs, rb, id) do { \ + FFT32(xb, (xs) << 1, rb, XCAT(id, a)); \ + FFT32((xb) + (xs), (xs) << 1, (rb) + 32, XCAT(id, b)); \ + FFT_LOOP(rb, 32, 4, id); \ + } while (0) + +#if SPH_SMALL_FOOTPRINT_SIMD + +static void +fft32(unsigned char *x, size_t xs, s32 *q) +{ + size_t xd; + + xd = xs << 1; + FFT16(0, xd, 0); + FFT16(xs, xd, 16); + FFT_LOOP(0, 16, 8, label_); +} + +#define FFT128(xb, xs, rb, id) do { \ + fft32(x + (xb) + ((xs) * 0), (xs) << 2, &q[(rb) + 0]); \ + fft32(x + (xb) + ((xs) * 2), (xs) << 2, &q[(rb) + 32]); \ + FFT_LOOP(rb, 32, 4, XCAT(id, aa)); \ + fft32(x + (xb) + ((xs) * 1), (xs) << 2, &q[(rb) + 64]); \ + fft32(x + (xb) + ((xs) * 3), (xs) << 2, &q[(rb) + 96]); \ + FFT_LOOP((rb) + 64, 32, 4, XCAT(id, ab)); \ + FFT_LOOP(rb, 64, 2, XCAT(id, a)); \ + } while (0) + +#else + +/* + * Output range: |q| <= 4733784 + */ +#define FFT128(xb, xs, rb, id) do { \ + FFT64(xb, (xs) << 1, rb, XCAT(id, a)); \ + FFT64((xb) + (xs), (xs) << 1, (rb) + 64, XCAT(id, b)); \ + FFT_LOOP(rb, 64, 2, id); \ + } while (0) + +#endif + +/* + * For SIMD-384 / SIMD-512, the fully unrolled FFT yields a compression + * function which does not fit in the 32 kB L1 cache of a typical x86 + * Intel. We therefore add a function call layer at the FFT64 level. + */ + +static void +fft64(unsigned char *x, size_t xs, s32 *q) +{ + size_t xd; + + xd = xs << 1; + FFT32(0, xd, 0, label_a); + FFT32(xs, xd, 32, label_b); + FFT_LOOP(0, 32, 4, label_); +} + +/* + * Output range: |q| <= 9467568 + */ +#define FFT256(xb, xs, rb, id) do { \ + fft64(x + (xb) + ((xs) * 0), (xs) << 2, &q[(rb) + 0]); \ + fft64(x + (xb) + ((xs) * 2), (xs) << 2, &q[(rb) + 64]); \ + FFT_LOOP(rb, 64, 2, XCAT(id, aa)); \ + fft64(x + (xb) + ((xs) * 1), (xs) << 2, &q[(rb) + 128]); \ + fft64(x + (xb) + ((xs) * 3), (xs) << 2, &q[(rb) + 192]); \ + FFT_LOOP((rb) + 128, 64, 2, XCAT(id, ab)); \ + FFT_LOOP(rb, 128, 1, XCAT(id, a)); \ + } while (0) + +/* + * alpha^(127*i) mod 257 + */ +static const unsigned short yoff_s_n[] = { + 1, 98, 95, 58, 30, 113, 23, 198, 129, 49, 176, 29, + 15, 185, 140, 99, 193, 153, 88, 143, 136, 221, 70, 178, + 225, 205, 44, 200, 68, 239, 35, 89, 241, 231, 22, 100, + 34, 248, 146, 173, 249, 244, 11, 50, 17, 124, 73, 215, + 253, 122, 134, 25, 137, 62, 165, 236, 255, 61, 67, 141, + 197, 31, 211, 118, 256, 159, 162, 199, 227, 144, 234, 59, + 128, 208, 81, 228, 242, 72, 117, 158, 64, 104, 169, 114, + 121, 36, 187, 79, 32, 52, 213, 57, 189, 18, 222, 168, + 16, 26, 235, 157, 223, 9, 111, 84, 8, 13, 246, 207, + 240, 133, 184, 42, 4, 135, 123, 232, 120, 195, 92, 21, + 2, 196, 190, 116, 60, 226, 46, 139 +}; + +/* + * alpha^(127*i) + alpha^(125*i) mod 257 + */ +static const unsigned short yoff_s_f[] = { + 2, 156, 118, 107, 45, 212, 111, 162, 97, 249, 211, 3, + 49, 101, 151, 223, 189, 178, 253, 204, 76, 82, 232, 65, + 96, 176, 161, 47, 189, 61, 248, 107, 0, 131, 133, 113, + 17, 33, 12, 111, 251, 103, 57, 148, 47, 65, 249, 143, + 189, 8, 204, 230, 205, 151, 187, 227, 247, 111, 140, 6, + 77, 10, 21, 149, 255, 101, 139, 150, 212, 45, 146, 95, + 160, 8, 46, 254, 208, 156, 106, 34, 68, 79, 4, 53, + 181, 175, 25, 192, 161, 81, 96, 210, 68, 196, 9, 150, + 0, 126, 124, 144, 240, 224, 245, 146, 6, 154, 200, 109, + 210, 192, 8, 114, 68, 249, 53, 27, 52, 106, 70, 30, + 10, 146, 117, 251, 180, 247, 236, 108 +}; + +/* + * beta^(255*i) mod 257 + */ +static const unsigned short yoff_b_n[] = { + 1, 163, 98, 40, 95, 65, 58, 202, 30, 7, 113, 172, + 23, 151, 198, 149, 129, 210, 49, 20, 176, 161, 29, 101, + 15, 132, 185, 86, 140, 204, 99, 203, 193, 105, 153, 10, + 88, 209, 143, 179, 136, 66, 221, 43, 70, 102, 178, 230, + 225, 181, 205, 5, 44, 233, 200, 218, 68, 33, 239, 150, + 35, 51, 89, 115, 241, 219, 231, 131, 22, 245, 100, 109, + 34, 145, 248, 75, 146, 154, 173, 186, 249, 238, 244, 194, + 11, 251, 50, 183, 17, 201, 124, 166, 73, 77, 215, 93, + 253, 119, 122, 97, 134, 254, 25, 220, 137, 229, 62, 83, + 165, 167, 236, 175, 255, 188, 61, 177, 67, 127, 141, 110, + 197, 243, 31, 170, 211, 212, 118, 216, 256, 94, 159, 217, + 162, 192, 199, 55, 227, 250, 144, 85, 234, 106, 59, 108, + 128, 47, 208, 237, 81, 96, 228, 156, 242, 125, 72, 171, + 117, 53, 158, 54, 64, 152, 104, 247, 169, 48, 114, 78, + 121, 191, 36, 214, 187, 155, 79, 27, 32, 76, 52, 252, + 213, 24, 57, 39, 189, 224, 18, 107, 222, 206, 168, 142, + 16, 38, 26, 126, 235, 12, 157, 148, 223, 112, 9, 182, + 111, 103, 84, 71, 8, 19, 13, 63, 246, 6, 207, 74, + 240, 56, 133, 91, 184, 180, 42, 164, 4, 138, 135, 160, + 123, 3, 232, 37, 120, 28, 195, 174, 92, 90, 21, 82, + 2, 69, 196, 80, 190, 130, 116, 147, 60, 14, 226, 87, + 46, 45, 139, 41 +}; + +/* + * beta^(255*i) + beta^(253*i) mod 257 + */ +static const unsigned short yoff_b_f[] = { + 2, 203, 156, 47, 118, 214, 107, 106, 45, 93, 212, 20, + 111, 73, 162, 251, 97, 215, 249, 53, 211, 19, 3, 89, + 49, 207, 101, 67, 151, 130, 223, 23, 189, 202, 178, 239, + 253, 127, 204, 49, 76, 236, 82, 137, 232, 157, 65, 79, + 96, 161, 176, 130, 161, 30, 47, 9, 189, 247, 61, 226, + 248, 90, 107, 64, 0, 88, 131, 243, 133, 59, 113, 115, + 17, 236, 33, 213, 12, 191, 111, 19, 251, 61, 103, 208, + 57, 35, 148, 248, 47, 116, 65, 119, 249, 178, 143, 40, + 189, 129, 8, 163, 204, 227, 230, 196, 205, 122, 151, 45, + 187, 19, 227, 72, 247, 125, 111, 121, 140, 220, 6, 107, + 77, 69, 10, 101, 21, 65, 149, 171, 255, 54, 101, 210, + 139, 43, 150, 151, 212, 164, 45, 237, 146, 184, 95, 6, + 160, 42, 8, 204, 46, 238, 254, 168, 208, 50, 156, 190, + 106, 127, 34, 234, 68, 55, 79, 18, 4, 130, 53, 208, + 181, 21, 175, 120, 25, 100, 192, 178, 161, 96, 81, 127, + 96, 227, 210, 248, 68, 10, 196, 31, 9, 167, 150, 193, + 0, 169, 126, 14, 124, 198, 144, 142, 240, 21, 224, 44, + 245, 66, 146, 238, 6, 196, 154, 49, 200, 222, 109, 9, + 210, 141, 192, 138, 8, 79, 114, 217, 68, 128, 249, 94, + 53, 30, 27, 61, 52, 135, 106, 212, 70, 238, 30, 185, + 10, 132, 146, 136, 117, 37, 251, 150, 180, 188, 247, 156, + 236, 192, 108, 86 +}; + +#define INNER(l, h, mm) (((u32)((l) * (mm)) & 0xFFFFU) \ + + ((u32)((h) * (mm)) << 16)) + +#define W_SMALL(sb, o1, o2, mm) \ + (INNER(q[8 * (sb) + 2 * 0 + o1], q[8 * (sb) + 2 * 0 + o2], mm), \ + INNER(q[8 * (sb) + 2 * 1 + o1], q[8 * (sb) + 2 * 1 + o2], mm), \ + INNER(q[8 * (sb) + 2 * 2 + o1], q[8 * (sb) + 2 * 2 + o2], mm), \ + INNER(q[8 * (sb) + 2 * 3 + o1], q[8 * (sb) + 2 * 3 + o2], mm) + +#define WS_0_0 W_SMALL( 4, 0, 1, 185) +#define WS_0_1 W_SMALL( 6, 0, 1, 185) +#define WS_0_2 W_SMALL( 0, 0, 1, 185) +#define WS_0_3 W_SMALL( 2, 0, 1, 185) +#define WS_0_4 W_SMALL( 7, 0, 1, 185) +#define WS_0_5 W_SMALL( 5, 0, 1, 185) +#define WS_0_6 W_SMALL( 3, 0, 1, 185) +#define WS_0_7 W_SMALL( 1, 0, 1, 185) +#define WS_1_0 W_SMALL(15, 0, 1, 185) +#define WS_1_1 W_SMALL(11, 0, 1, 185) +#define WS_1_2 W_SMALL(12, 0, 1, 185) +#define WS_1_3 W_SMALL( 8, 0, 1, 185) +#define WS_1_4 W_SMALL( 9, 0, 1, 185) +#define WS_1_5 W_SMALL(13, 0, 1, 185) +#define WS_1_6 W_SMALL(10, 0, 1, 185) +#define WS_1_7 W_SMALL(14, 0, 1, 185) +#define WS_2_0 W_SMALL(17, -128, -64, 233) +#define WS_2_1 W_SMALL(18, -128, -64, 233) +#define WS_2_2 W_SMALL(23, -128, -64, 233) +#define WS_2_3 W_SMALL(20, -128, -64, 233) +#define WS_2_4 W_SMALL(22, -128, -64, 233) +#define WS_2_5 W_SMALL(21, -128, -64, 233) +#define WS_2_6 W_SMALL(16, -128, -64, 233) +#define WS_2_7 W_SMALL(19, -128, -64, 233) +#define WS_3_0 W_SMALL(30, -191, -127, 233) +#define WS_3_1 W_SMALL(24, -191, -127, 233) +#define WS_3_2 W_SMALL(25, -191, -127, 233) +#define WS_3_3 W_SMALL(31, -191, -127, 233) +#define WS_3_4 W_SMALL(27, -191, -127, 233) +#define WS_3_5 W_SMALL(29, -191, -127, 233) +#define WS_3_6 W_SMALL(28, -191, -127, 233) +#define WS_3_7 W_SMALL(26, -191, -127, 233) + +#define W_BIG(sb, o1, o2, mm) \ + (INNER(q[16 * (sb) + 2 * 0 + o1], q[16 * (sb) + 2 * 0 + o2], mm), \ + INNER(q[16 * (sb) + 2 * 1 + o1], q[16 * (sb) + 2 * 1 + o2], mm), \ + INNER(q[16 * (sb) + 2 * 2 + o1], q[16 * (sb) + 2 * 2 + o2], mm), \ + INNER(q[16 * (sb) + 2 * 3 + o1], q[16 * (sb) + 2 * 3 + o2], mm), \ + INNER(q[16 * (sb) + 2 * 4 + o1], q[16 * (sb) + 2 * 4 + o2], mm), \ + INNER(q[16 * (sb) + 2 * 5 + o1], q[16 * (sb) + 2 * 5 + o2], mm), \ + INNER(q[16 * (sb) + 2 * 6 + o1], q[16 * (sb) + 2 * 6 + o2], mm), \ + INNER(q[16 * (sb) + 2 * 7 + o1], q[16 * (sb) + 2 * 7 + o2], mm) + +#define WB_0_0 W_BIG( 4, 0, 1, 185) +#define WB_0_1 W_BIG( 6, 0, 1, 185) +#define WB_0_2 W_BIG( 0, 0, 1, 185) +#define WB_0_3 W_BIG( 2, 0, 1, 185) +#define WB_0_4 W_BIG( 7, 0, 1, 185) +#define WB_0_5 W_BIG( 5, 0, 1, 185) +#define WB_0_6 W_BIG( 3, 0, 1, 185) +#define WB_0_7 W_BIG( 1, 0, 1, 185) +#define WB_1_0 W_BIG(15, 0, 1, 185) +#define WB_1_1 W_BIG(11, 0, 1, 185) +#define WB_1_2 W_BIG(12, 0, 1, 185) +#define WB_1_3 W_BIG( 8, 0, 1, 185) +#define WB_1_4 W_BIG( 9, 0, 1, 185) +#define WB_1_5 W_BIG(13, 0, 1, 185) +#define WB_1_6 W_BIG(10, 0, 1, 185) +#define WB_1_7 W_BIG(14, 0, 1, 185) +#define WB_2_0 W_BIG(17, -256, -128, 233) +#define WB_2_1 W_BIG(18, -256, -128, 233) +#define WB_2_2 W_BIG(23, -256, -128, 233) +#define WB_2_3 W_BIG(20, -256, -128, 233) +#define WB_2_4 W_BIG(22, -256, -128, 233) +#define WB_2_5 W_BIG(21, -256, -128, 233) +#define WB_2_6 W_BIG(16, -256, -128, 233) +#define WB_2_7 W_BIG(19, -256, -128, 233) +#define WB_3_0 W_BIG(30, -383, -255, 233) +#define WB_3_1 W_BIG(24, -383, -255, 233) +#define WB_3_2 W_BIG(25, -383, -255, 233) +#define WB_3_3 W_BIG(31, -383, -255, 233) +#define WB_3_4 W_BIG(27, -383, -255, 233) +#define WB_3_5 W_BIG(29, -383, -255, 233) +#define WB_3_6 W_BIG(28, -383, -255, 233) +#define WB_3_7 W_BIG(26, -383, -255, 233) + +#define IF(x, y, z) ((((y) ^ (z)) & (x)) ^ (z)) +#define MAJ(x, y, z) (((x) & (y)) | (((x) | (y)) & (z))) + +#define PP4_0_0 1 +#define PP4_0_1 0 +#define PP4_0_2 3 +#define PP4_0_3 2 +#define PP4_1_0 2 +#define PP4_1_1 3 +#define PP4_1_2 0 +#define PP4_1_3 1 +#define PP4_2_0 3 +#define PP4_2_1 2 +#define PP4_2_2 1 +#define PP4_2_3 0 + +#define PP8_0_0 1 +#define PP8_0_1 0 +#define PP8_0_2 3 +#define PP8_0_3 2 +#define PP8_0_4 5 +#define PP8_0_5 4 +#define PP8_0_6 7 +#define PP8_0_7 6 + +#define PP8_1_0 6 +#define PP8_1_1 7 +#define PP8_1_2 4 +#define PP8_1_3 5 +#define PP8_1_4 2 +#define PP8_1_5 3 +#define PP8_1_6 0 +#define PP8_1_7 1 + +#define PP8_2_0 2 +#define PP8_2_1 3 +#define PP8_2_2 0 +#define PP8_2_3 1 +#define PP8_2_4 6 +#define PP8_2_5 7 +#define PP8_2_6 4 +#define PP8_2_7 5 + +#define PP8_3_0 3 +#define PP8_3_1 2 +#define PP8_3_2 1 +#define PP8_3_3 0 +#define PP8_3_4 7 +#define PP8_3_5 6 +#define PP8_3_6 5 +#define PP8_3_7 4 + +#define PP8_4_0 5 +#define PP8_4_1 4 +#define PP8_4_2 7 +#define PP8_4_3 6 +#define PP8_4_4 1 +#define PP8_4_5 0 +#define PP8_4_6 3 +#define PP8_4_7 2 + +#define PP8_5_0 7 +#define PP8_5_1 6 +#define PP8_5_2 5 +#define PP8_5_3 4 +#define PP8_5_4 3 +#define PP8_5_5 2 +#define PP8_5_6 1 +#define PP8_5_7 0 + +#define PP8_6_0 4 +#define PP8_6_1 5 +#define PP8_6_2 6 +#define PP8_6_3 7 +#define PP8_6_4 0 +#define PP8_6_5 1 +#define PP8_6_6 2 +#define PP8_6_7 3 + +#if SPH_SIMD_NOCOPY + +#define DECL_STATE_SMALL +#define READ_STATE_SMALL(sc) +#define WRITE_STATE_SMALL(sc) +#define DECL_STATE_BIG +#define READ_STATE_BIG(sc) +#define WRITE_STATE_BIG(sc) + +#else + +#define DECL_STATE_SMALL \ + u32 A0, A1, A2, A3, B0, B1, B2, B3, C0, C1, C2, C3, D0, D1, D2, D3; + +#define READ_STATE_SMALL(sc) do { \ + A0 = (sc)->state[ 0]; \ + A1 = (sc)->state[ 1]; \ + A2 = (sc)->state[ 2]; \ + A3 = (sc)->state[ 3]; \ + B0 = (sc)->state[ 4]; \ + B1 = (sc)->state[ 5]; \ + B2 = (sc)->state[ 6]; \ + B3 = (sc)->state[ 7]; \ + C0 = (sc)->state[ 8]; \ + C1 = (sc)->state[ 9]; \ + C2 = (sc)->state[10]; \ + C3 = (sc)->state[11]; \ + D0 = (sc)->state[12]; \ + D1 = (sc)->state[13]; \ + D2 = (sc)->state[14]; \ + D3 = (sc)->state[15]; \ + } while (0) + +#define WRITE_STATE_SMALL(sc) do { \ + (sc)->state[ 0] = A0; \ + (sc)->state[ 1] = A1; \ + (sc)->state[ 2] = A2; \ + (sc)->state[ 3] = A3; \ + (sc)->state[ 4] = B0; \ + (sc)->state[ 5] = B1; \ + (sc)->state[ 6] = B2; \ + (sc)->state[ 7] = B3; \ + (sc)->state[ 8] = C0; \ + (sc)->state[ 9] = C1; \ + (sc)->state[10] = C2; \ + (sc)->state[11] = C3; \ + (sc)->state[12] = D0; \ + (sc)->state[13] = D1; \ + (sc)->state[14] = D2; \ + (sc)->state[15] = D3; \ + } while (0) + +#define DECL_STATE_BIG \ + u32 A0, A1, A2, A3, A4, A5, A6, A7; \ + u32 B0, B1, B2, B3, B4, B5, B6, B7; \ + u32 C0, C1, C2, C3, C4, C5, C6, C7; \ + u32 D0, D1, D2, D3, D4, D5, D6, D7; + +#define READ_STATE_BIG(sc) do { \ + A0 = (sc)->state[ 0]; \ + A1 = (sc)->state[ 1]; \ + A2 = (sc)->state[ 2]; \ + A3 = (sc)->state[ 3]; \ + A4 = (sc)->state[ 4]; \ + A5 = (sc)->state[ 5]; \ + A6 = (sc)->state[ 6]; \ + A7 = (sc)->state[ 7]; \ + B0 = (sc)->state[ 8]; \ + B1 = (sc)->state[ 9]; \ + B2 = (sc)->state[10]; \ + B3 = (sc)->state[11]; \ + B4 = (sc)->state[12]; \ + B5 = (sc)->state[13]; \ + B6 = (sc)->state[14]; \ + B7 = (sc)->state[15]; \ + C0 = (sc)->state[16]; \ + C1 = (sc)->state[17]; \ + C2 = (sc)->state[18]; \ + C3 = (sc)->state[19]; \ + C4 = (sc)->state[20]; \ + C5 = (sc)->state[21]; \ + C6 = (sc)->state[22]; \ + C7 = (sc)->state[23]; \ + D0 = (sc)->state[24]; \ + D1 = (sc)->state[25]; \ + D2 = (sc)->state[26]; \ + D3 = (sc)->state[27]; \ + D4 = (sc)->state[28]; \ + D5 = (sc)->state[29]; \ + D6 = (sc)->state[30]; \ + D7 = (sc)->state[31]; \ + } while (0) + +#define WRITE_STATE_BIG(sc) do { \ + (sc)->state[ 0] = A0; \ + (sc)->state[ 1] = A1; \ + (sc)->state[ 2] = A2; \ + (sc)->state[ 3] = A3; \ + (sc)->state[ 4] = A4; \ + (sc)->state[ 5] = A5; \ + (sc)->state[ 6] = A6; \ + (sc)->state[ 7] = A7; \ + (sc)->state[ 8] = B0; \ + (sc)->state[ 9] = B1; \ + (sc)->state[10] = B2; \ + (sc)->state[11] = B3; \ + (sc)->state[12] = B4; \ + (sc)->state[13] = B5; \ + (sc)->state[14] = B6; \ + (sc)->state[15] = B7; \ + (sc)->state[16] = C0; \ + (sc)->state[17] = C1; \ + (sc)->state[18] = C2; \ + (sc)->state[19] = C3; \ + (sc)->state[20] = C4; \ + (sc)->state[21] = C5; \ + (sc)->state[22] = C6; \ + (sc)->state[23] = C7; \ + (sc)->state[24] = D0; \ + (sc)->state[25] = D1; \ + (sc)->state[26] = D2; \ + (sc)->state[27] = D3; \ + (sc)->state[28] = D4; \ + (sc)->state[29] = D5; \ + (sc)->state[30] = D6; \ + (sc)->state[31] = D7; \ + } while (0) + +#endif + +#define STEP_ELT(n, w, fun, s, ppb) do { \ + u32 tt = T32(D ## n + (w) + fun(A ## n, B ## n, C ## n)); \ + A ## n = T32(ROL32(tt, s) + XCAT(tA, XCAT(ppb, n))); \ + D ## n = C ## n; \ + C ## n = B ## n; \ + B ## n = tA ## n; \ + } while (0) + +#define STEP_SMALL(w0, w1, w2, w3, fun, r, s, pp4b) do { \ + u32 tA0 = ROL32(A0, r); \ + u32 tA1 = ROL32(A1, r); \ + u32 tA2 = ROL32(A2, r); \ + u32 tA3 = ROL32(A3, r); \ + STEP_ELT(0, w0, fun, s, pp4b); \ + STEP_ELT(1, w1, fun, s, pp4b); \ + STEP_ELT(2, w2, fun, s, pp4b); \ + STEP_ELT(3, w3, fun, s, pp4b); \ + } while (0) + +#define STEP_BIG(w0, w1, w2, w3, w4, w5, w6, w7, fun, r, s, pp8b) do { \ + u32 tA0 = ROL32(A0, r); \ + u32 tA1 = ROL32(A1, r); \ + u32 tA2 = ROL32(A2, r); \ + u32 tA3 = ROL32(A3, r); \ + u32 tA4 = ROL32(A4, r); \ + u32 tA5 = ROL32(A5, r); \ + u32 tA6 = ROL32(A6, r); \ + u32 tA7 = ROL32(A7, r); \ + STEP_ELT(0, w0, fun, s, pp8b); \ + STEP_ELT(1, w1, fun, s, pp8b); \ + STEP_ELT(2, w2, fun, s, pp8b); \ + STEP_ELT(3, w3, fun, s, pp8b); \ + STEP_ELT(4, w4, fun, s, pp8b); \ + STEP_ELT(5, w5, fun, s, pp8b); \ + STEP_ELT(6, w6, fun, s, pp8b); \ + STEP_ELT(7, w7, fun, s, pp8b); \ + } while (0) + +#define M3_0_0 0_ +#define M3_1_0 1_ +#define M3_2_0 2_ +#define M3_3_0 0_ +#define M3_4_0 1_ +#define M3_5_0 2_ +#define M3_6_0 0_ +#define M3_7_0 1_ + +#define M3_0_1 1_ +#define M3_1_1 2_ +#define M3_2_1 0_ +#define M3_3_1 1_ +#define M3_4_1 2_ +#define M3_5_1 0_ +#define M3_6_1 1_ +#define M3_7_1 2_ + +#define M3_0_2 2_ +#define M3_1_2 0_ +#define M3_2_2 1_ +#define M3_3_2 2_ +#define M3_4_2 0_ +#define M3_5_2 1_ +#define M3_6_2 2_ +#define M3_7_2 0_ + +#define STEP_SMALL_(w, fun, r, s, pp4b) STEP_SMALL w, fun, r, s, pp4b) + +#define ONE_ROUND_SMALL(ri, isp, p0, p1, p2, p3) do { \ + STEP_SMALL_(WS_ ## ri ## 0, \ + IF, p0, p1, XCAT(PP4_, M3_0_ ## isp)); \ + STEP_SMALL_(WS_ ## ri ## 1, \ + IF, p1, p2, XCAT(PP4_, M3_1_ ## isp)); \ + STEP_SMALL_(WS_ ## ri ## 2, \ + IF, p2, p3, XCAT(PP4_, M3_2_ ## isp)); \ + STEP_SMALL_(WS_ ## ri ## 3, \ + IF, p3, p0, XCAT(PP4_, M3_3_ ## isp)); \ + STEP_SMALL_(WS_ ## ri ## 4, \ + MAJ, p0, p1, XCAT(PP4_, M3_4_ ## isp)); \ + STEP_SMALL_(WS_ ## ri ## 5, \ + MAJ, p1, p2, XCAT(PP4_, M3_5_ ## isp)); \ + STEP_SMALL_(WS_ ## ri ## 6, \ + MAJ, p2, p3, XCAT(PP4_, M3_6_ ## isp)); \ + STEP_SMALL_(WS_ ## ri ## 7, \ + MAJ, p3, p0, XCAT(PP4_, M3_7_ ## isp)); \ + } while (0) + +#define M7_0_0 0_ +#define M7_1_0 1_ +#define M7_2_0 2_ +#define M7_3_0 3_ +#define M7_4_0 4_ +#define M7_5_0 5_ +#define M7_6_0 6_ +#define M7_7_0 0_ + +#define M7_0_1 1_ +#define M7_1_1 2_ +#define M7_2_1 3_ +#define M7_3_1 4_ +#define M7_4_1 5_ +#define M7_5_1 6_ +#define M7_6_1 0_ +#define M7_7_1 1_ + +#define M7_0_2 2_ +#define M7_1_2 3_ +#define M7_2_2 4_ +#define M7_3_2 5_ +#define M7_4_2 6_ +#define M7_5_2 0_ +#define M7_6_2 1_ +#define M7_7_2 2_ + +#define M7_0_3 3_ +#define M7_1_3 4_ +#define M7_2_3 5_ +#define M7_3_3 6_ +#define M7_4_3 0_ +#define M7_5_3 1_ +#define M7_6_3 2_ +#define M7_7_3 3_ + +#define STEP_BIG_(w, fun, r, s, pp8b) STEP_BIG w, fun, r, s, pp8b) + +#define ONE_ROUND_BIG(ri, isp, p0, p1, p2, p3) do { \ + STEP_BIG_(WB_ ## ri ## 0, \ + IF, p0, p1, XCAT(PP8_, M7_0_ ## isp)); \ + STEP_BIG_(WB_ ## ri ## 1, \ + IF, p1, p2, XCAT(PP8_, M7_1_ ## isp)); \ + STEP_BIG_(WB_ ## ri ## 2, \ + IF, p2, p3, XCAT(PP8_, M7_2_ ## isp)); \ + STEP_BIG_(WB_ ## ri ## 3, \ + IF, p3, p0, XCAT(PP8_, M7_3_ ## isp)); \ + STEP_BIG_(WB_ ## ri ## 4, \ + MAJ, p0, p1, XCAT(PP8_, M7_4_ ## isp)); \ + STEP_BIG_(WB_ ## ri ## 5, \ + MAJ, p1, p2, XCAT(PP8_, M7_5_ ## isp)); \ + STEP_BIG_(WB_ ## ri ## 6, \ + MAJ, p2, p3, XCAT(PP8_, M7_6_ ## isp)); \ + STEP_BIG_(WB_ ## ri ## 7, \ + MAJ, p3, p0, XCAT(PP8_, M7_7_ ## isp)); \ + } while (0) + +#if SPH_SMALL_FOOTPRINT_SIMD + +#define A0 state[ 0] +#define A1 state[ 1] +#define A2 state[ 2] +#define A3 state[ 3] +#define B0 state[ 4] +#define B1 state[ 5] +#define B2 state[ 6] +#define B3 state[ 7] +#define C0 state[ 8] +#define C1 state[ 9] +#define C2 state[10] +#define C3 state[11] +#define D0 state[12] +#define D1 state[13] +#define D2 state[14] +#define D3 state[15] + +#define STEP2_ELT(n, w, fun, s, ppb) do { \ + u32 tt = T32(D ## n + (w) + fun(A ## n, B ## n, C ## n)); \ + A ## n = T32(ROL32(tt, s) + tA[(ppb) ^ n]); \ + D ## n = C ## n; \ + C ## n = B ## n; \ + B ## n = tA[n]; \ + } while (0) + +#define STEP2_SMALL(w0, w1, w2, w3, fun, r, s, pp4b) do { \ + u32 tA[4]; \ + tA[0] = ROL32(A0, r); \ + tA[1] = ROL32(A1, r); \ + tA[2] = ROL32(A2, r); \ + tA[3] = ROL32(A3, r); \ + STEP2_ELT(0, w0, fun, s, pp4b); \ + STEP2_ELT(1, w1, fun, s, pp4b); \ + STEP2_ELT(2, w2, fun, s, pp4b); \ + STEP2_ELT(3, w3, fun, s, pp4b); \ + } while (0) + +static void +one_round_small(u32 *state, u32 *w, int isp, int p0, int p1, int p2, int p3) +{ + static const int pp4k[] = { 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2 }; + + STEP2_SMALL(w[ 0], w[ 1], w[ 2], w[ 3], IF, p0, p1, pp4k[isp + 0]); + STEP2_SMALL(w[ 4], w[ 5], w[ 6], w[ 7], IF, p1, p2, pp4k[isp + 1]); + STEP2_SMALL(w[ 8], w[ 9], w[10], w[11], IF, p2, p3, pp4k[isp + 2]); + STEP2_SMALL(w[12], w[13], w[14], w[15], IF, p3, p0, pp4k[isp + 3]); + STEP2_SMALL(w[16], w[17], w[18], w[19], MAJ, p0, p1, pp4k[isp + 4]); + STEP2_SMALL(w[20], w[21], w[22], w[23], MAJ, p1, p2, pp4k[isp + 5]); + STEP2_SMALL(w[24], w[25], w[26], w[27], MAJ, p2, p3, pp4k[isp + 6]); + STEP2_SMALL(w[28], w[29], w[30], w[31], MAJ, p3, p0, pp4k[isp + 7]); +} + +static void +compress_small(sph_simd_small_context *sc, int last) +{ + unsigned char *x; + s32 q[128]; + int i; + u32 w[32]; + u32 state[16]; + size_t u; + + static const size_t wsp[32] = { + 4 << 3, 6 << 3, 0 << 3, 2 << 3, + 7 << 3, 5 << 3, 3 << 3, 1 << 3, + 15 << 3, 11 << 3, 12 << 3, 8 << 3, + 9 << 3, 13 << 3, 10 << 3, 14 << 3, + 17 << 3, 18 << 3, 23 << 3, 20 << 3, + 22 << 3, 21 << 3, 16 << 3, 19 << 3, + 30 << 3, 24 << 3, 25 << 3, 31 << 3, + 27 << 3, 29 << 3, 28 << 3, 26 << 3 + }; + + x = sc->buf; + FFT128(0, 1, 0, ll); + if (last) { + for (i = 0; i < 128; i ++) { + s32 tq; + + tq = q[i] + yoff_s_f[i]; + tq = REDS2(tq); + tq = REDS1(tq); + tq = REDS1(tq); + q[i] = (tq <= 128 ? tq : tq - 257); + } + } else { + for (i = 0; i < 128; i ++) { + s32 tq; + + tq = q[i] + yoff_s_n[i]; + tq = REDS2(tq); + tq = REDS1(tq); + tq = REDS1(tq); + q[i] = (tq <= 128 ? tq : tq - 257); + } + } + + for (i = 0; i < 16; i += 4) { + state[i + 0] = sc->state[i + 0] + ^ sph_dec32le_aligned(x + 4 * (i + 0)); + state[i + 1] = sc->state[i + 1] + ^ sph_dec32le_aligned(x + 4 * (i + 1)); + state[i + 2] = sc->state[i + 2] + ^ sph_dec32le_aligned(x + 4 * (i + 2)); + state[i + 3] = sc->state[i + 3] + ^ sph_dec32le_aligned(x + 4 * (i + 3)); + } + +#define WSREAD(sb, o1, o2, mm) do { \ + for (u = 0; u < 32; u += 4) { \ + size_t v = wsp[(u >> 2) + (sb)]; \ + w[u + 0] = INNER(q[v + 2 * 0 + (o1)], \ + q[v + 2 * 0 + (o2)], mm); \ + w[u + 1] = INNER(q[v + 2 * 1 + (o1)], \ + q[v + 2 * 1 + (o2)], mm); \ + w[u + 2] = INNER(q[v + 2 * 2 + (o1)], \ + q[v + 2 * 2 + (o2)], mm); \ + w[u + 3] = INNER(q[v + 2 * 3 + (o1)], \ + q[v + 2 * 3 + (o2)], mm); \ + } \ + } while (0) + + WSREAD( 0, 0, 1, 185); + one_round_small(state, w, 0, 3, 23, 17, 27); + WSREAD( 8, 0, 1, 185); + one_round_small(state, w, 2, 28, 19, 22, 7); + WSREAD(16, -128, -64, 233); + one_round_small(state, w, 1, 29, 9, 15, 5); + WSREAD(24, -191, -127, 233); + one_round_small(state, w, 0, 4, 13, 10, 25); + +#undef WSREAD + + STEP_SMALL(sc->state[ 0], sc->state[ 1], sc->state[ 2], sc->state[ 3], + IF, 4, 13, PP4_2_); + STEP_SMALL(sc->state[ 4], sc->state[ 5], sc->state[ 6], sc->state[ 7], + IF, 13, 10, PP4_0_); + STEP_SMALL(sc->state[ 8], sc->state[ 9], sc->state[10], sc->state[11], + IF, 10, 25, PP4_1_); + STEP_SMALL(sc->state[12], sc->state[13], sc->state[14], sc->state[15], + IF, 25, 4, PP4_2_); + + memcpy(sc->state, state, sizeof state); +} + +#undef A0 +#undef A1 +#undef A2 +#undef A3 +#undef B0 +#undef B1 +#undef B2 +#undef B3 +#undef C0 +#undef C1 +#undef C2 +#undef C3 +#undef D0 +#undef D1 +#undef D2 +#undef D3 + +#else + +#if SPH_SIMD_NOCOPY +#define A0 (sc->state[ 0]) +#define A1 (sc->state[ 1]) +#define A2 (sc->state[ 2]) +#define A3 (sc->state[ 3]) +#define B0 (sc->state[ 4]) +#define B1 (sc->state[ 5]) +#define B2 (sc->state[ 6]) +#define B3 (sc->state[ 7]) +#define C0 (sc->state[ 8]) +#define C1 (sc->state[ 9]) +#define C2 (sc->state[10]) +#define C3 (sc->state[11]) +#define D0 (sc->state[12]) +#define D1 (sc->state[13]) +#define D2 (sc->state[14]) +#define D3 (sc->state[15]) +#endif + +static void +compress_small(sph_simd_small_context *sc, int last) +{ + unsigned char *x; + s32 q[128]; + int i; + DECL_STATE_SMALL +#if SPH_SIMD_NOCOPY + sph_u32 saved[16]; +#endif + +#if SPH_SIMD_NOCOPY + memcpy(saved, sc->state, sizeof saved); +#endif + x = sc->buf; + FFT128(0, 1, 0, ll); + if (last) { + for (i = 0; i < 128; i ++) { + s32 tq; + + tq = q[i] + yoff_s_f[i]; + tq = REDS2(tq); + tq = REDS1(tq); + tq = REDS1(tq); + q[i] = (tq <= 128 ? tq : tq - 257); + } + } else { + for (i = 0; i < 128; i ++) { + s32 tq; + + tq = q[i] + yoff_s_n[i]; + tq = REDS2(tq); + tq = REDS1(tq); + tq = REDS1(tq); + q[i] = (tq <= 128 ? tq : tq - 257); + } + } + READ_STATE_SMALL(sc); + A0 ^= sph_dec32le_aligned(x + 0); + A1 ^= sph_dec32le_aligned(x + 4); + A2 ^= sph_dec32le_aligned(x + 8); + A3 ^= sph_dec32le_aligned(x + 12); + B0 ^= sph_dec32le_aligned(x + 16); + B1 ^= sph_dec32le_aligned(x + 20); + B2 ^= sph_dec32le_aligned(x + 24); + B3 ^= sph_dec32le_aligned(x + 28); + C0 ^= sph_dec32le_aligned(x + 32); + C1 ^= sph_dec32le_aligned(x + 36); + C2 ^= sph_dec32le_aligned(x + 40); + C3 ^= sph_dec32le_aligned(x + 44); + D0 ^= sph_dec32le_aligned(x + 48); + D1 ^= sph_dec32le_aligned(x + 52); + D2 ^= sph_dec32le_aligned(x + 56); + D3 ^= sph_dec32le_aligned(x + 60); + ONE_ROUND_SMALL(0_, 0, 3, 23, 17, 27); + ONE_ROUND_SMALL(1_, 2, 28, 19, 22, 7); + ONE_ROUND_SMALL(2_, 1, 29, 9, 15, 5); + ONE_ROUND_SMALL(3_, 0, 4, 13, 10, 25); +#if SPH_SIMD_NOCOPY + STEP_SMALL(saved[ 0], saved[ 1], saved[ 2], saved[ 3], + IF, 4, 13, PP4_2_); + STEP_SMALL(saved[ 4], saved[ 5], saved[ 6], saved[ 7], + IF, 13, 10, PP4_0_); + STEP_SMALL(saved[ 8], saved[ 9], saved[10], saved[11], + IF, 10, 25, PP4_1_); + STEP_SMALL(saved[12], saved[13], saved[14], saved[15], + IF, 25, 4, PP4_2_); +#else + STEP_SMALL(sc->state[ 0], sc->state[ 1], sc->state[ 2], sc->state[ 3], + IF, 4, 13, PP4_2_); + STEP_SMALL(sc->state[ 4], sc->state[ 5], sc->state[ 6], sc->state[ 7], + IF, 13, 10, PP4_0_); + STEP_SMALL(sc->state[ 8], sc->state[ 9], sc->state[10], sc->state[11], + IF, 10, 25, PP4_1_); + STEP_SMALL(sc->state[12], sc->state[13], sc->state[14], sc->state[15], + IF, 25, 4, PP4_2_); + WRITE_STATE_SMALL(sc); +#endif +} + +#if SPH_SIMD_NOCOPY +#undef A0 +#undef A1 +#undef A2 +#undef A3 +#undef B0 +#undef B1 +#undef B2 +#undef B3 +#undef C0 +#undef C1 +#undef C2 +#undef C3 +#undef D0 +#undef D1 +#undef D2 +#undef D3 +#endif + +#endif + +#if SPH_SMALL_FOOTPRINT_SIMD + +#define A0 state[ 0] +#define A1 state[ 1] +#define A2 state[ 2] +#define A3 state[ 3] +#define A4 state[ 4] +#define A5 state[ 5] +#define A6 state[ 6] +#define A7 state[ 7] +#define B0 state[ 8] +#define B1 state[ 9] +#define B2 state[10] +#define B3 state[11] +#define B4 state[12] +#define B5 state[13] +#define B6 state[14] +#define B7 state[15] +#define C0 state[16] +#define C1 state[17] +#define C2 state[18] +#define C3 state[19] +#define C4 state[20] +#define C5 state[21] +#define C6 state[22] +#define C7 state[23] +#define D0 state[24] +#define D1 state[25] +#define D2 state[26] +#define D3 state[27] +#define D4 state[28] +#define D5 state[29] +#define D6 state[30] +#define D7 state[31] + +/* + * Not needed -- already defined for SIMD-224 / SIMD-256 + * +#define STEP2_ELT(n, w, fun, s, ppb) do { \ + u32 tt = T32(D ## n + (w) + fun(A ## n, B ## n, C ## n)); \ + A ## n = T32(ROL32(tt, s) + tA[(ppb) ^ n]); \ + D ## n = C ## n; \ + C ## n = B ## n; \ + B ## n = tA[n]; \ + } while (0) + */ + +#define STEP2_BIG(w0, w1, w2, w3, w4, w5, w6, w7, fun, r, s, pp8b) do { \ + u32 tA[8]; \ + tA[0] = ROL32(A0, r); \ + tA[1] = ROL32(A1, r); \ + tA[2] = ROL32(A2, r); \ + tA[3] = ROL32(A3, r); \ + tA[4] = ROL32(A4, r); \ + tA[5] = ROL32(A5, r); \ + tA[6] = ROL32(A6, r); \ + tA[7] = ROL32(A7, r); \ + STEP2_ELT(0, w0, fun, s, pp8b); \ + STEP2_ELT(1, w1, fun, s, pp8b); \ + STEP2_ELT(2, w2, fun, s, pp8b); \ + STEP2_ELT(3, w3, fun, s, pp8b); \ + STEP2_ELT(4, w4, fun, s, pp8b); \ + STEP2_ELT(5, w5, fun, s, pp8b); \ + STEP2_ELT(6, w6, fun, s, pp8b); \ + STEP2_ELT(7, w7, fun, s, pp8b); \ + } while (0) + +static void +one_round_big(u32 *state, u32 *w, int isp, int p0, int p1, int p2, int p3) +{ + static const int pp8k[] = { 1, 6, 2, 3, 5, 7, 4, 1, 6, 2, 3 }; + + STEP2_BIG(w[ 0], w[ 1], w[ 2], w[ 3], w[ 4], w[ 5], w[ 6], w[ 7], + IF, p0, p1, pp8k[isp + 0]); + STEP2_BIG(w[ 8], w[ 9], w[10], w[11], w[12], w[13], w[14], w[15], + IF, p1, p2, pp8k[isp + 1]); + STEP2_BIG(w[16], w[17], w[18], w[19], w[20], w[21], w[22], w[23], + IF, p2, p3, pp8k[isp + 2]); + STEP2_BIG(w[24], w[25], w[26], w[27], w[28], w[29], w[30], w[31], + IF, p3, p0, pp8k[isp + 3]); + STEP2_BIG(w[32], w[33], w[34], w[35], w[36], w[37], w[38], w[39], + MAJ, p0, p1, pp8k[isp + 4]); + STEP2_BIG(w[40], w[41], w[42], w[43], w[44], w[45], w[46], w[47], + MAJ, p1, p2, pp8k[isp + 5]); + STEP2_BIG(w[48], w[49], w[50], w[51], w[52], w[53], w[54], w[55], + MAJ, p2, p3, pp8k[isp + 6]); + STEP2_BIG(w[56], w[57], w[58], w[59], w[60], w[61], w[62], w[63], + MAJ, p3, p0, pp8k[isp + 7]); +} + +static void +compress_big(sph_simd_big_context *sc, int last) +{ + unsigned char *x; + s32 q[256]; + int i; + u32 w[64]; + u32 state[32]; + size_t u; + + static const size_t wbp[32] = { + 4 << 4, 6 << 4, 0 << 4, 2 << 4, + 7 << 4, 5 << 4, 3 << 4, 1 << 4, + 15 << 4, 11 << 4, 12 << 4, 8 << 4, + 9 << 4, 13 << 4, 10 << 4, 14 << 4, + 17 << 4, 18 << 4, 23 << 4, 20 << 4, + 22 << 4, 21 << 4, 16 << 4, 19 << 4, + 30 << 4, 24 << 4, 25 << 4, 31 << 4, + 27 << 4, 29 << 4, 28 << 4, 26 << 4 + }; + + x = sc->buf; + FFT256(0, 1, 0, ll); + if (last) { + for (i = 0; i < 256; i ++) { + s32 tq; + + tq = q[i] + yoff_b_f[i]; + tq = REDS2(tq); + tq = REDS1(tq); + tq = REDS1(tq); + q[i] = (tq <= 128 ? tq : tq - 257); + } + } else { + for (i = 0; i < 256; i ++) { + s32 tq; + + tq = q[i] + yoff_b_n[i]; + tq = REDS2(tq); + tq = REDS1(tq); + tq = REDS1(tq); + q[i] = (tq <= 128 ? tq : tq - 257); + } + } + + for (i = 0; i < 32; i += 8) { + state[i + 0] = sc->state[i + 0] + ^ sph_dec32le_aligned(x + 4 * (i + 0)); + state[i + 1] = sc->state[i + 1] + ^ sph_dec32le_aligned(x + 4 * (i + 1)); + state[i + 2] = sc->state[i + 2] + ^ sph_dec32le_aligned(x + 4 * (i + 2)); + state[i + 3] = sc->state[i + 3] + ^ sph_dec32le_aligned(x + 4 * (i + 3)); + state[i + 4] = sc->state[i + 4] + ^ sph_dec32le_aligned(x + 4 * (i + 4)); + state[i + 5] = sc->state[i + 5] + ^ sph_dec32le_aligned(x + 4 * (i + 5)); + state[i + 6] = sc->state[i + 6] + ^ sph_dec32le_aligned(x + 4 * (i + 6)); + state[i + 7] = sc->state[i + 7] + ^ sph_dec32le_aligned(x + 4 * (i + 7)); + } + +#define WBREAD(sb, o1, o2, mm) do { \ + for (u = 0; u < 64; u += 8) { \ + size_t v = wbp[(u >> 3) + (sb)]; \ + w[u + 0] = INNER(q[v + 2 * 0 + (o1)], \ + q[v + 2 * 0 + (o2)], mm); \ + w[u + 1] = INNER(q[v + 2 * 1 + (o1)], \ + q[v + 2 * 1 + (o2)], mm); \ + w[u + 2] = INNER(q[v + 2 * 2 + (o1)], \ + q[v + 2 * 2 + (o2)], mm); \ + w[u + 3] = INNER(q[v + 2 * 3 + (o1)], \ + q[v + 2 * 3 + (o2)], mm); \ + w[u + 4] = INNER(q[v + 2 * 4 + (o1)], \ + q[v + 2 * 4 + (o2)], mm); \ + w[u + 5] = INNER(q[v + 2 * 5 + (o1)], \ + q[v + 2 * 5 + (o2)], mm); \ + w[u + 6] = INNER(q[v + 2 * 6 + (o1)], \ + q[v + 2 * 6 + (o2)], mm); \ + w[u + 7] = INNER(q[v + 2 * 7 + (o1)], \ + q[v + 2 * 7 + (o2)], mm); \ + } \ + } while (0) + + WBREAD( 0, 0, 1, 185); + one_round_big(state, w, 0, 3, 23, 17, 27); + WBREAD( 8, 0, 1, 185); + one_round_big(state, w, 1, 28, 19, 22, 7); + WBREAD(16, -256, -128, 233); + one_round_big(state, w, 2, 29, 9, 15, 5); + WBREAD(24, -383, -255, 233); + one_round_big(state, w, 3, 4, 13, 10, 25); + +#undef WBREAD + + STEP_BIG( + sc->state[ 0], sc->state[ 1], sc->state[ 2], sc->state[ 3], + sc->state[ 4], sc->state[ 5], sc->state[ 6], sc->state[ 7], + IF, 4, 13, PP8_4_); + STEP_BIG( + sc->state[ 8], sc->state[ 9], sc->state[10], sc->state[11], + sc->state[12], sc->state[13], sc->state[14], sc->state[15], + IF, 13, 10, PP8_5_); + STEP_BIG( + sc->state[16], sc->state[17], sc->state[18], sc->state[19], + sc->state[20], sc->state[21], sc->state[22], sc->state[23], + IF, 10, 25, PP8_6_); + STEP_BIG( + sc->state[24], sc->state[25], sc->state[26], sc->state[27], + sc->state[28], sc->state[29], sc->state[30], sc->state[31], + IF, 25, 4, PP8_0_); + + memcpy(sc->state, state, sizeof state); +} + +#undef A0 +#undef A1 +#undef A2 +#undef A3 +#undef A4 +#undef A5 +#undef A6 +#undef A7 +#undef B0 +#undef B1 +#undef B2 +#undef B3 +#undef B4 +#undef B5 +#undef B6 +#undef B7 +#undef C0 +#undef C1 +#undef C2 +#undef C3 +#undef C4 +#undef C5 +#undef C6 +#undef C7 +#undef D0 +#undef D1 +#undef D2 +#undef D3 +#undef D4 +#undef D5 +#undef D6 +#undef D7 + +#else + +#if SPH_SIMD_NOCOPY +#define A0 (sc->state[ 0]) +#define A1 (sc->state[ 1]) +#define A2 (sc->state[ 2]) +#define A3 (sc->state[ 3]) +#define A4 (sc->state[ 4]) +#define A5 (sc->state[ 5]) +#define A6 (sc->state[ 6]) +#define A7 (sc->state[ 7]) +#define B0 (sc->state[ 8]) +#define B1 (sc->state[ 9]) +#define B2 (sc->state[10]) +#define B3 (sc->state[11]) +#define B4 (sc->state[12]) +#define B5 (sc->state[13]) +#define B6 (sc->state[14]) +#define B7 (sc->state[15]) +#define C0 (sc->state[16]) +#define C1 (sc->state[17]) +#define C2 (sc->state[18]) +#define C3 (sc->state[19]) +#define C4 (sc->state[20]) +#define C5 (sc->state[21]) +#define C6 (sc->state[22]) +#define C7 (sc->state[23]) +#define D0 (sc->state[24]) +#define D1 (sc->state[25]) +#define D2 (sc->state[26]) +#define D3 (sc->state[27]) +#define D4 (sc->state[28]) +#define D5 (sc->state[29]) +#define D6 (sc->state[30]) +#define D7 (sc->state[31]) +#endif + +static void +compress_big(sph_simd_big_context *sc, int last) +{ + unsigned char *x; + s32 q[256]; + int i; + DECL_STATE_BIG +#if SPH_SIMD_NOCOPY + sph_u32 saved[32]; +#endif + +#if SPH_SIMD_NOCOPY + memcpy(saved, sc->state, sizeof saved); +#endif + + x = sc->buf; + FFT256(0, 1, 0, ll); + if (last) { + for (i = 0; i < 256; i ++) { + s32 tq; + + tq = q[i] + yoff_b_f[i]; + tq = REDS2(tq); + tq = REDS1(tq); + tq = REDS1(tq); + q[i] = (tq <= 128 ? tq : tq - 257); + } + } else { + for (i = 0; i < 256; i ++) { + s32 tq; + + tq = q[i] + yoff_b_n[i]; + tq = REDS2(tq); + tq = REDS1(tq); + tq = REDS1(tq); + q[i] = (tq <= 128 ? tq : tq - 257); + } + } + READ_STATE_BIG(sc); + A0 ^= sph_dec32le_aligned(x + 0); + A1 ^= sph_dec32le_aligned(x + 4); + A2 ^= sph_dec32le_aligned(x + 8); + A3 ^= sph_dec32le_aligned(x + 12); + A4 ^= sph_dec32le_aligned(x + 16); + A5 ^= sph_dec32le_aligned(x + 20); + A6 ^= sph_dec32le_aligned(x + 24); + A7 ^= sph_dec32le_aligned(x + 28); + B0 ^= sph_dec32le_aligned(x + 32); + B1 ^= sph_dec32le_aligned(x + 36); + B2 ^= sph_dec32le_aligned(x + 40); + B3 ^= sph_dec32le_aligned(x + 44); + B4 ^= sph_dec32le_aligned(x + 48); + B5 ^= sph_dec32le_aligned(x + 52); + B6 ^= sph_dec32le_aligned(x + 56); + B7 ^= sph_dec32le_aligned(x + 60); + C0 ^= sph_dec32le_aligned(x + 64); + C1 ^= sph_dec32le_aligned(x + 68); + C2 ^= sph_dec32le_aligned(x + 72); + C3 ^= sph_dec32le_aligned(x + 76); + C4 ^= sph_dec32le_aligned(x + 80); + C5 ^= sph_dec32le_aligned(x + 84); + C6 ^= sph_dec32le_aligned(x + 88); + C7 ^= sph_dec32le_aligned(x + 92); + D0 ^= sph_dec32le_aligned(x + 96); + D1 ^= sph_dec32le_aligned(x + 100); + D2 ^= sph_dec32le_aligned(x + 104); + D3 ^= sph_dec32le_aligned(x + 108); + D4 ^= sph_dec32le_aligned(x + 112); + D5 ^= sph_dec32le_aligned(x + 116); + D6 ^= sph_dec32le_aligned(x + 120); + D7 ^= sph_dec32le_aligned(x + 124); + + ONE_ROUND_BIG(0_, 0, 3, 23, 17, 27); + ONE_ROUND_BIG(1_, 1, 28, 19, 22, 7); + ONE_ROUND_BIG(2_, 2, 29, 9, 15, 5); + ONE_ROUND_BIG(3_, 3, 4, 13, 10, 25); +#if SPH_SIMD_NOCOPY + STEP_BIG( + saved[ 0], saved[ 1], saved[ 2], saved[ 3], + saved[ 4], saved[ 5], saved[ 6], saved[ 7], + IF, 4, 13, PP8_4_); + STEP_BIG( + saved[ 8], saved[ 9], saved[10], saved[11], + saved[12], saved[13], saved[14], saved[15], + IF, 13, 10, PP8_5_); + STEP_BIG( + saved[16], saved[17], saved[18], saved[19], + saved[20], saved[21], saved[22], saved[23], + IF, 10, 25, PP8_6_); + STEP_BIG( + saved[24], saved[25], saved[26], saved[27], + saved[28], saved[29], saved[30], saved[31], + IF, 25, 4, PP8_0_); +#else + STEP_BIG( + sc->state[ 0], sc->state[ 1], sc->state[ 2], sc->state[ 3], + sc->state[ 4], sc->state[ 5], sc->state[ 6], sc->state[ 7], + IF, 4, 13, PP8_4_); + STEP_BIG( + sc->state[ 8], sc->state[ 9], sc->state[10], sc->state[11], + sc->state[12], sc->state[13], sc->state[14], sc->state[15], + IF, 13, 10, PP8_5_); + STEP_BIG( + sc->state[16], sc->state[17], sc->state[18], sc->state[19], + sc->state[20], sc->state[21], sc->state[22], sc->state[23], + IF, 10, 25, PP8_6_); + STEP_BIG( + sc->state[24], sc->state[25], sc->state[26], sc->state[27], + sc->state[28], sc->state[29], sc->state[30], sc->state[31], + IF, 25, 4, PP8_0_); + WRITE_STATE_BIG(sc); +#endif +} + +#if SPH_SIMD_NOCOPY +#undef A0 +#undef A1 +#undef A2 +#undef A3 +#undef A4 +#undef A5 +#undef A6 +#undef A7 +#undef B0 +#undef B1 +#undef B2 +#undef B3 +#undef B4 +#undef B5 +#undef B6 +#undef B7 +#undef C0 +#undef C1 +#undef C2 +#undef C3 +#undef C4 +#undef C5 +#undef C6 +#undef C7 +#undef D0 +#undef D1 +#undef D2 +#undef D3 +#undef D4 +#undef D5 +#undef D6 +#undef D7 +#endif + +#endif + +static const u32 IV224[] = { + C32(0x33586E9F), C32(0x12FFF033), C32(0xB2D9F64D), C32(0x6F8FEA53), + C32(0xDE943106), C32(0x2742E439), C32(0x4FBAB5AC), C32(0x62B9FF96), + C32(0x22E7B0AF), C32(0xC862B3A8), C32(0x33E00CDC), C32(0x236B86A6), + C32(0xF64AE77C), C32(0xFA373B76), C32(0x7DC1EE5B), C32(0x7FB29CE8) +}; + +static const u32 IV256[] = { + C32(0x4D567983), C32(0x07190BA9), C32(0x8474577B), C32(0x39D726E9), + C32(0xAAF3D925), C32(0x3EE20B03), C32(0xAFD5E751), C32(0xC96006D3), + C32(0xC2C2BA14), C32(0x49B3BCB4), C32(0xF67CAF46), C32(0x668626C9), + C32(0xE2EAA8D2), C32(0x1FF47833), C32(0xD0C661A5), C32(0x55693DE1) +}; + +static const u32 IV384[] = { + C32(0x8A36EEBC), C32(0x94A3BD90), C32(0xD1537B83), C32(0xB25B070B), + C32(0xF463F1B5), C32(0xB6F81E20), C32(0x0055C339), C32(0xB4D144D1), + C32(0x7360CA61), C32(0x18361A03), C32(0x17DCB4B9), C32(0x3414C45A), + C32(0xA699A9D2), C32(0xE39E9664), C32(0x468BFE77), C32(0x51D062F8), + C32(0xB9E3BFE8), C32(0x63BECE2A), C32(0x8FE506B9), C32(0xF8CC4AC2), + C32(0x7AE11542), C32(0xB1AADDA1), C32(0x64B06794), C32(0x28D2F462), + C32(0xE64071EC), C32(0x1DEB91A8), C32(0x8AC8DB23), C32(0x3F782AB5), + C32(0x039B5CB8), C32(0x71DDD962), C32(0xFADE2CEA), C32(0x1416DF71) +}; + +static const u32 IV512[] = { + C32(0x0BA16B95), C32(0x72F999AD), C32(0x9FECC2AE), C32(0xBA3264FC), + C32(0x5E894929), C32(0x8E9F30E5), C32(0x2F1DAA37), C32(0xF0F2C558), + C32(0xAC506643), C32(0xA90635A5), C32(0xE25B878B), C32(0xAAB7878F), + C32(0x88817F7A), C32(0x0A02892B), C32(0x559A7550), C32(0x598F657E), + C32(0x7EEF60A1), C32(0x6B70E3E8), C32(0x9C1714D1), C32(0xB958E2A8), + C32(0xAB02675E), C32(0xED1C014F), C32(0xCD8D65BB), C32(0xFDB7A257), + C32(0x09254899), C32(0xD699C7BC), C32(0x9019B6DC), C32(0x2B9022E4), + C32(0x8FA14956), C32(0x21BF9BD3), C32(0xB94D0943), C32(0x6FFDDC22) +}; + +static void +init_small(void *cc, const u32 *iv) +{ + sph_simd_small_context *sc; + + sc = cc; + memcpy(sc->state, iv, sizeof sc->state); + sc->count_low = sc->count_high = 0; + sc->ptr = 0; +} + +static void +init_big(void *cc, const u32 *iv) +{ + sph_simd_big_context *sc; + + sc = cc; + memcpy(sc->state, iv, sizeof sc->state); + sc->count_low = sc->count_high = 0; + sc->ptr = 0; +} + +static void +update_small(void *cc, const void *data, size_t len) +{ + sph_simd_small_context *sc; + + sc = cc; + while (len > 0) { + size_t clen; + + clen = (sizeof sc->buf) - sc->ptr; + if (clen > len) + clen = len; + memcpy(sc->buf + sc->ptr, data, clen); + data = (const unsigned char *)data + clen; + len -= clen; + if ((sc->ptr += clen) == sizeof sc->buf) { + compress_small(sc, 0); + sc->ptr = 0; + sc->count_low = T32(sc->count_low + 1); + if (sc->count_low == 0) + sc->count_high ++; + } + } +} + +static void +update_big(void *cc, const void *data, size_t len) +{ + sph_simd_big_context *sc; + + sc = cc; + while (len > 0) { + size_t clen; + + clen = (sizeof sc->buf) - sc->ptr; + if (clen > len) + clen = len; + memcpy(sc->buf + sc->ptr, data, clen); + data = (const unsigned char *)data + clen; + len -= clen; + if ((sc->ptr += clen) == sizeof sc->buf) { + compress_big(sc, 0); + sc->ptr = 0; + sc->count_low = T32(sc->count_low + 1); + if (sc->count_low == 0) + sc->count_high ++; + } + } +} + +static void +encode_count_small(unsigned char *dst, + u32 low, u32 high, size_t ptr, unsigned n) +{ + low = T32(low << 9); + high = T32(high << 9) + (low >> 23); + low += (ptr << 3) + n; + sph_enc32le(dst, low); + sph_enc32le(dst + 4, high); +} + +static void +encode_count_big(unsigned char *dst, + u32 low, u32 high, size_t ptr, unsigned n) +{ + low = T32(low << 10); + high = T32(high << 10) + (low >> 22); + low += (ptr << 3) + n; + sph_enc32le(dst, low); + sph_enc32le(dst + 4, high); +} + +static void +finalize_small(void *cc, unsigned ub, unsigned n, void *dst, size_t dst_len) +{ + sph_simd_small_context *sc; + unsigned char *d; + size_t u; + + sc = cc; + if (sc->ptr > 0 || n > 0) { + memset(sc->buf + sc->ptr, 0, + (sizeof sc->buf) - sc->ptr); + sc->buf[sc->ptr] = ub & (0xFF << (8 - n)); + compress_small(sc, 0); + } + memset(sc->buf, 0, sizeof sc->buf); + encode_count_small(sc->buf, sc->count_low, sc->count_high, sc->ptr, n); + compress_small(sc, 1); + d = dst; + for (d = dst, u = 0; u < dst_len; u ++) + sph_enc32le(d + (u << 2), sc->state[u]); +} + +static void +finalize_big(void *cc, unsigned ub, unsigned n, void *dst, size_t dst_len) +{ + sph_simd_big_context *sc; + unsigned char *d; + size_t u; + + sc = cc; + if (sc->ptr > 0 || n > 0) { + memset(sc->buf + sc->ptr, 0, + (sizeof sc->buf) - sc->ptr); + sc->buf[sc->ptr] = ub & (0xFF << (8 - n)); + compress_big(sc, 0); + } + memset(sc->buf, 0, sizeof sc->buf); + encode_count_big(sc->buf, sc->count_low, sc->count_high, sc->ptr, n); + compress_big(sc, 1); + d = dst; + for (d = dst, u = 0; u < dst_len; u ++) + sph_enc32le(d + (u << 2), sc->state[u]); +} + +void +sph_simd224_init(void *cc) +{ + init_small(cc, IV224); +} + +void +sph_simd224(void *cc, const void *data, size_t len) +{ + update_small(cc, data, len); +} + +void +sph_simd224_close(void *cc, void *dst) +{ + sph_simd224_addbits_and_close(cc, 0, 0, dst); +} + +void +sph_simd224_addbits_and_close(void *cc, unsigned ub, unsigned n, void *dst) +{ + finalize_small(cc, ub, n, dst, 7); + sph_simd224_init(cc); +} + +void +sph_simd256_init(void *cc) +{ + init_small(cc, IV256); +} + +void +sph_simd256(void *cc, const void *data, size_t len) +{ + update_small(cc, data, len); +} + +void +sph_simd256_close(void *cc, void *dst) +{ + sph_simd256_addbits_and_close(cc, 0, 0, dst); +} + +void +sph_simd256_addbits_and_close(void *cc, unsigned ub, unsigned n, void *dst) +{ + finalize_small(cc, ub, n, dst, 8); + sph_simd256_init(cc); +} + +void +sph_simd384_init(void *cc) +{ + init_big(cc, IV384); +} + +void +sph_simd384(void *cc, const void *data, size_t len) +{ + update_big(cc, data, len); +} + +void +sph_simd384_close(void *cc, void *dst) +{ + sph_simd384_addbits_and_close(cc, 0, 0, dst); +} + +void +sph_simd384_addbits_and_close(void *cc, unsigned ub, unsigned n, void *dst) +{ + finalize_big(cc, ub, n, dst, 12); + sph_simd384_init(cc); +} + +void +sph_simd512_init(void *cc) +{ + init_big(cc, IV512); +} + +void +sph_simd512(void *cc, const void *data, size_t len) +{ + update_big(cc, data, len); +} + +void +sph_simd512_close(void *cc, void *dst) +{ + sph_simd512_addbits_and_close(cc, 0, 0, dst); +} + +void +sph_simd512_addbits_and_close(void *cc, unsigned ub, unsigned n, void *dst) +{ + finalize_big(cc, ub, n, dst, 16); + sph_simd512_init(cc); +} +#ifdef __cplusplus +} +#endif diff --git a/src/skein.c b/src/skein.c new file mode 100644 index 0000000..7e47e35 --- /dev/null +++ b/src/skein.c @@ -0,0 +1,1254 @@ +/* $Id: skein.c 254 2011-06-07 19:38:58Z tp $ */ +/* + * Skein implementation. + * + * ==========================(LICENSE BEGIN)============================ + * + * Copyright (c) 2007-2010 Projet RNRT SAPHIR + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * ===========================(LICENSE END)============================= + * + * @author Thomas Pornin + */ + +#include +#include + +#include "sph_skein.h" + +#ifdef __cplusplus +extern "C"{ +#endif + + +#if SPH_SMALL_FOOTPRINT && !defined SPH_SMALL_FOOTPRINT_SKEIN +#define SPH_SMALL_FOOTPRINT_SKEIN 1 +#endif + +#ifdef _MSC_VER +#pragma warning (disable: 4146) +#endif + +#if SPH_64 + +#if 0 +/* obsolete */ +/* + * M5_ ## s ## _ ## i evaluates to s+i mod 5 (0 <= s <= 18, 0 <= i <= 3). + */ + +#define M5_0_0 0 +#define M5_0_1 1 +#define M5_0_2 2 +#define M5_0_3 3 + +#define M5_1_0 1 +#define M5_1_1 2 +#define M5_1_2 3 +#define M5_1_3 4 + +#define M5_2_0 2 +#define M5_2_1 3 +#define M5_2_2 4 +#define M5_2_3 0 + +#define M5_3_0 3 +#define M5_3_1 4 +#define M5_3_2 0 +#define M5_3_3 1 + +#define M5_4_0 4 +#define M5_4_1 0 +#define M5_4_2 1 +#define M5_4_3 2 + +#define M5_5_0 0 +#define M5_5_1 1 +#define M5_5_2 2 +#define M5_5_3 3 + +#define M5_6_0 1 +#define M5_6_1 2 +#define M5_6_2 3 +#define M5_6_3 4 + +#define M5_7_0 2 +#define M5_7_1 3 +#define M5_7_2 4 +#define M5_7_3 0 + +#define M5_8_0 3 +#define M5_8_1 4 +#define M5_8_2 0 +#define M5_8_3 1 + +#define M5_9_0 4 +#define M5_9_1 0 +#define M5_9_2 1 +#define M5_9_3 2 + +#define M5_10_0 0 +#define M5_10_1 1 +#define M5_10_2 2 +#define M5_10_3 3 + +#define M5_11_0 1 +#define M5_11_1 2 +#define M5_11_2 3 +#define M5_11_3 4 + +#define M5_12_0 2 +#define M5_12_1 3 +#define M5_12_2 4 +#define M5_12_3 0 + +#define M5_13_0 3 +#define M5_13_1 4 +#define M5_13_2 0 +#define M5_13_3 1 + +#define M5_14_0 4 +#define M5_14_1 0 +#define M5_14_2 1 +#define M5_14_3 2 + +#define M5_15_0 0 +#define M5_15_1 1 +#define M5_15_2 2 +#define M5_15_3 3 + +#define M5_16_0 1 +#define M5_16_1 2 +#define M5_16_2 3 +#define M5_16_3 4 + +#define M5_17_0 2 +#define M5_17_1 3 +#define M5_17_2 4 +#define M5_17_3 0 + +#define M5_18_0 3 +#define M5_18_1 4 +#define M5_18_2 0 +#define M5_18_3 1 +#endif + +/* + * M9_ ## s ## _ ## i evaluates to s+i mod 9 (0 <= s <= 18, 0 <= i <= 7). + */ + +#define M9_0_0 0 +#define M9_0_1 1 +#define M9_0_2 2 +#define M9_0_3 3 +#define M9_0_4 4 +#define M9_0_5 5 +#define M9_0_6 6 +#define M9_0_7 7 + +#define M9_1_0 1 +#define M9_1_1 2 +#define M9_1_2 3 +#define M9_1_3 4 +#define M9_1_4 5 +#define M9_1_5 6 +#define M9_1_6 7 +#define M9_1_7 8 + +#define M9_2_0 2 +#define M9_2_1 3 +#define M9_2_2 4 +#define M9_2_3 5 +#define M9_2_4 6 +#define M9_2_5 7 +#define M9_2_6 8 +#define M9_2_7 0 + +#define M9_3_0 3 +#define M9_3_1 4 +#define M9_3_2 5 +#define M9_3_3 6 +#define M9_3_4 7 +#define M9_3_5 8 +#define M9_3_6 0 +#define M9_3_7 1 + +#define M9_4_0 4 +#define M9_4_1 5 +#define M9_4_2 6 +#define M9_4_3 7 +#define M9_4_4 8 +#define M9_4_5 0 +#define M9_4_6 1 +#define M9_4_7 2 + +#define M9_5_0 5 +#define M9_5_1 6 +#define M9_5_2 7 +#define M9_5_3 8 +#define M9_5_4 0 +#define M9_5_5 1 +#define M9_5_6 2 +#define M9_5_7 3 + +#define M9_6_0 6 +#define M9_6_1 7 +#define M9_6_2 8 +#define M9_6_3 0 +#define M9_6_4 1 +#define M9_6_5 2 +#define M9_6_6 3 +#define M9_6_7 4 + +#define M9_7_0 7 +#define M9_7_1 8 +#define M9_7_2 0 +#define M9_7_3 1 +#define M9_7_4 2 +#define M9_7_5 3 +#define M9_7_6 4 +#define M9_7_7 5 + +#define M9_8_0 8 +#define M9_8_1 0 +#define M9_8_2 1 +#define M9_8_3 2 +#define M9_8_4 3 +#define M9_8_5 4 +#define M9_8_6 5 +#define M9_8_7 6 + +#define M9_9_0 0 +#define M9_9_1 1 +#define M9_9_2 2 +#define M9_9_3 3 +#define M9_9_4 4 +#define M9_9_5 5 +#define M9_9_6 6 +#define M9_9_7 7 + +#define M9_10_0 1 +#define M9_10_1 2 +#define M9_10_2 3 +#define M9_10_3 4 +#define M9_10_4 5 +#define M9_10_5 6 +#define M9_10_6 7 +#define M9_10_7 8 + +#define M9_11_0 2 +#define M9_11_1 3 +#define M9_11_2 4 +#define M9_11_3 5 +#define M9_11_4 6 +#define M9_11_5 7 +#define M9_11_6 8 +#define M9_11_7 0 + +#define M9_12_0 3 +#define M9_12_1 4 +#define M9_12_2 5 +#define M9_12_3 6 +#define M9_12_4 7 +#define M9_12_5 8 +#define M9_12_6 0 +#define M9_12_7 1 + +#define M9_13_0 4 +#define M9_13_1 5 +#define M9_13_2 6 +#define M9_13_3 7 +#define M9_13_4 8 +#define M9_13_5 0 +#define M9_13_6 1 +#define M9_13_7 2 + +#define M9_14_0 5 +#define M9_14_1 6 +#define M9_14_2 7 +#define M9_14_3 8 +#define M9_14_4 0 +#define M9_14_5 1 +#define M9_14_6 2 +#define M9_14_7 3 + +#define M9_15_0 6 +#define M9_15_1 7 +#define M9_15_2 8 +#define M9_15_3 0 +#define M9_15_4 1 +#define M9_15_5 2 +#define M9_15_6 3 +#define M9_15_7 4 + +#define M9_16_0 7 +#define M9_16_1 8 +#define M9_16_2 0 +#define M9_16_3 1 +#define M9_16_4 2 +#define M9_16_5 3 +#define M9_16_6 4 +#define M9_16_7 5 + +#define M9_17_0 8 +#define M9_17_1 0 +#define M9_17_2 1 +#define M9_17_3 2 +#define M9_17_4 3 +#define M9_17_5 4 +#define M9_17_6 5 +#define M9_17_7 6 + +#define M9_18_0 0 +#define M9_18_1 1 +#define M9_18_2 2 +#define M9_18_3 3 +#define M9_18_4 4 +#define M9_18_5 5 +#define M9_18_6 6 +#define M9_18_7 7 + +/* + * M3_ ## s ## _ ## i evaluates to s+i mod 3 (0 <= s <= 18, 0 <= i <= 1). + */ + +#define M3_0_0 0 +#define M3_0_1 1 +#define M3_1_0 1 +#define M3_1_1 2 +#define M3_2_0 2 +#define M3_2_1 0 +#define M3_3_0 0 +#define M3_3_1 1 +#define M3_4_0 1 +#define M3_4_1 2 +#define M3_5_0 2 +#define M3_5_1 0 +#define M3_6_0 0 +#define M3_6_1 1 +#define M3_7_0 1 +#define M3_7_1 2 +#define M3_8_0 2 +#define M3_8_1 0 +#define M3_9_0 0 +#define M3_9_1 1 +#define M3_10_0 1 +#define M3_10_1 2 +#define M3_11_0 2 +#define M3_11_1 0 +#define M3_12_0 0 +#define M3_12_1 1 +#define M3_13_0 1 +#define M3_13_1 2 +#define M3_14_0 2 +#define M3_14_1 0 +#define M3_15_0 0 +#define M3_15_1 1 +#define M3_16_0 1 +#define M3_16_1 2 +#define M3_17_0 2 +#define M3_17_1 0 +#define M3_18_0 0 +#define M3_18_1 1 + +#define XCAT(x, y) XCAT_(x, y) +#define XCAT_(x, y) x ## y + +#if 0 +/* obsolete */ +#define SKSI(k, s, i) XCAT(k, XCAT(XCAT(XCAT(M5_, s), _), i)) +#define SKST(t, s, v) XCAT(t, XCAT(XCAT(XCAT(M3_, s), _), v)) +#endif + +#define SKBI(k, s, i) XCAT(k, XCAT(XCAT(XCAT(M9_, s), _), i)) +#define SKBT(t, s, v) XCAT(t, XCAT(XCAT(XCAT(M3_, s), _), v)) + +#if 0 +/* obsolete */ +#define TFSMALL_KINIT(k0, k1, k2, k3, k4, t0, t1, t2) do { \ + k4 = (k0 ^ k1) ^ (k2 ^ k3) ^ SPH_C64(0x1BD11BDAA9FC1A22); \ + t2 = t0 ^ t1; \ + } while (0) +#endif + +#define TFBIG_KINIT(k0, k1, k2, k3, k4, k5, k6, k7, k8, t0, t1, t2) do { \ + k8 = ((k0 ^ k1) ^ (k2 ^ k3)) ^ ((k4 ^ k5) ^ (k6 ^ k7)) \ + ^ SPH_C64(0x1BD11BDAA9FC1A22); \ + t2 = t0 ^ t1; \ + } while (0) + +#if 0 +/* obsolete */ +#define TFSMALL_ADDKEY(w0, w1, w2, w3, k, t, s) do { \ + w0 = SPH_T64(w0 + SKSI(k, s, 0)); \ + w1 = SPH_T64(w1 + SKSI(k, s, 1) + SKST(t, s, 0)); \ + w2 = SPH_T64(w2 + SKSI(k, s, 2) + SKST(t, s, 1)); \ + w3 = SPH_T64(w3 + SKSI(k, s, 3) + (sph_u64)s); \ + } while (0) +#endif + +#if SPH_SMALL_FOOTPRINT_SKEIN + +#define TFBIG_ADDKEY(s, tt0, tt1) do { \ + p0 = SPH_T64(p0 + h[s + 0]); \ + p1 = SPH_T64(p1 + h[s + 1]); \ + p2 = SPH_T64(p2 + h[s + 2]); \ + p3 = SPH_T64(p3 + h[s + 3]); \ + p4 = SPH_T64(p4 + h[s + 4]); \ + p5 = SPH_T64(p5 + h[s + 5] + tt0); \ + p6 = SPH_T64(p6 + h[s + 6] + tt1); \ + p7 = SPH_T64(p7 + h[s + 7] + (sph_u64)s); \ + } while (0) + +#else + +#define TFBIG_ADDKEY(w0, w1, w2, w3, w4, w5, w6, w7, k, t, s) do { \ + w0 = SPH_T64(w0 + SKBI(k, s, 0)); \ + w1 = SPH_T64(w1 + SKBI(k, s, 1)); \ + w2 = SPH_T64(w2 + SKBI(k, s, 2)); \ + w3 = SPH_T64(w3 + SKBI(k, s, 3)); \ + w4 = SPH_T64(w4 + SKBI(k, s, 4)); \ + w5 = SPH_T64(w5 + SKBI(k, s, 5) + SKBT(t, s, 0)); \ + w6 = SPH_T64(w6 + SKBI(k, s, 6) + SKBT(t, s, 1)); \ + w7 = SPH_T64(w7 + SKBI(k, s, 7) + (sph_u64)s); \ + } while (0) + +#endif + +#if 0 +/* obsolete */ +#define TFSMALL_MIX(x0, x1, rc) do { \ + x0 = SPH_T64(x0 + x1); \ + x1 = SPH_ROTL64(x1, rc) ^ x0; \ + } while (0) +#endif + +#define TFBIG_MIX(x0, x1, rc) do { \ + x0 = SPH_T64(x0 + x1); \ + x1 = SPH_ROTL64(x1, rc) ^ x0; \ + } while (0) + +#if 0 +/* obsolete */ +#define TFSMALL_MIX4(w0, w1, w2, w3, rc0, rc1) do { \ + TFSMALL_MIX(w0, w1, rc0); \ + TFSMALL_MIX(w2, w3, rc1); \ + } while (0) +#endif + +#define TFBIG_MIX8(w0, w1, w2, w3, w4, w5, w6, w7, rc0, rc1, rc2, rc3) do { \ + TFBIG_MIX(w0, w1, rc0); \ + TFBIG_MIX(w2, w3, rc1); \ + TFBIG_MIX(w4, w5, rc2); \ + TFBIG_MIX(w6, w7, rc3); \ + } while (0) + +#if 0 +/* obsolete */ +#define TFSMALL_4e(s) do { \ + TFSMALL_ADDKEY(p0, p1, p2, p3, h, t, s); \ + TFSMALL_MIX4(p0, p1, p2, p3, 14, 16); \ + TFSMALL_MIX4(p0, p3, p2, p1, 52, 57); \ + TFSMALL_MIX4(p0, p1, p2, p3, 23, 40); \ + TFSMALL_MIX4(p0, p3, p2, p1, 5, 37); \ + } while (0) + +#define TFSMALL_4o(s) do { \ + TFSMALL_ADDKEY(p0, p1, p2, p3, h, t, s); \ + TFSMALL_MIX4(p0, p1, p2, p3, 25, 33); \ + TFSMALL_MIX4(p0, p3, p2, p1, 46, 12); \ + TFSMALL_MIX4(p0, p1, p2, p3, 58, 22); \ + TFSMALL_MIX4(p0, p3, p2, p1, 32, 32); \ + } while (0) +#endif + +#if SPH_SMALL_FOOTPRINT_SKEIN + +#define TFBIG_4e(s) do { \ + TFBIG_ADDKEY(s, t0, t1); \ + TFBIG_MIX8(p0, p1, p2, p3, p4, p5, p6, p7, 46, 36, 19, 37); \ + TFBIG_MIX8(p2, p1, p4, p7, p6, p5, p0, p3, 33, 27, 14, 42); \ + TFBIG_MIX8(p4, p1, p6, p3, p0, p5, p2, p7, 17, 49, 36, 39); \ + TFBIG_MIX8(p6, p1, p0, p7, p2, p5, p4, p3, 44, 9, 54, 56); \ + } while (0) + +#define TFBIG_4o(s) do { \ + TFBIG_ADDKEY(s, t1, t2); \ + TFBIG_MIX8(p0, p1, p2, p3, p4, p5, p6, p7, 39, 30, 34, 24); \ + TFBIG_MIX8(p2, p1, p4, p7, p6, p5, p0, p3, 13, 50, 10, 17); \ + TFBIG_MIX8(p4, p1, p6, p3, p0, p5, p2, p7, 25, 29, 39, 43); \ + TFBIG_MIX8(p6, p1, p0, p7, p2, p5, p4, p3, 8, 35, 56, 22); \ + } while (0) + +#else + +#define TFBIG_4e(s) do { \ + TFBIG_ADDKEY(p0, p1, p2, p3, p4, p5, p6, p7, h, t, s); \ + TFBIG_MIX8(p0, p1, p2, p3, p4, p5, p6, p7, 46, 36, 19, 37); \ + TFBIG_MIX8(p2, p1, p4, p7, p6, p5, p0, p3, 33, 27, 14, 42); \ + TFBIG_MIX8(p4, p1, p6, p3, p0, p5, p2, p7, 17, 49, 36, 39); \ + TFBIG_MIX8(p6, p1, p0, p7, p2, p5, p4, p3, 44, 9, 54, 56); \ + } while (0) + +#define TFBIG_4o(s) do { \ + TFBIG_ADDKEY(p0, p1, p2, p3, p4, p5, p6, p7, h, t, s); \ + TFBIG_MIX8(p0, p1, p2, p3, p4, p5, p6, p7, 39, 30, 34, 24); \ + TFBIG_MIX8(p2, p1, p4, p7, p6, p5, p0, p3, 13, 50, 10, 17); \ + TFBIG_MIX8(p4, p1, p6, p3, p0, p5, p2, p7, 25, 29, 39, 43); \ + TFBIG_MIX8(p6, p1, p0, p7, p2, p5, p4, p3, 8, 35, 56, 22); \ + } while (0) + +#endif + +#if 0 +/* obsolete */ +#define UBI_SMALL(etype, extra) do { \ + sph_u64 h4, t0, t1, t2; \ + sph_u64 m0 = sph_dec64le(buf + 0); \ + sph_u64 m1 = sph_dec64le(buf + 8); \ + sph_u64 m2 = sph_dec64le(buf + 16); \ + sph_u64 m3 = sph_dec64le(buf + 24); \ + sph_u64 p0 = m0; \ + sph_u64 p1 = m1; \ + sph_u64 p2 = m2; \ + sph_u64 p3 = m3; \ + t0 = SPH_T64(bcount << 5) + (sph_u64)(extra); \ + t1 = (bcount >> 59) + ((sph_u64)(etype) << 55); \ + TFSMALL_KINIT(h0, h1, h2, h3, h4, t0, t1, t2); \ + TFSMALL_4e(0); \ + TFSMALL_4o(1); \ + TFSMALL_4e(2); \ + TFSMALL_4o(3); \ + TFSMALL_4e(4); \ + TFSMALL_4o(5); \ + TFSMALL_4e(6); \ + TFSMALL_4o(7); \ + TFSMALL_4e(8); \ + TFSMALL_4o(9); \ + TFSMALL_4e(10); \ + TFSMALL_4o(11); \ + TFSMALL_4e(12); \ + TFSMALL_4o(13); \ + TFSMALL_4e(14); \ + TFSMALL_4o(15); \ + TFSMALL_4e(16); \ + TFSMALL_4o(17); \ + TFSMALL_ADDKEY(p0, p1, p2, p3, h, t, 18); \ + h0 = m0 ^ p0; \ + h1 = m1 ^ p1; \ + h2 = m2 ^ p2; \ + h3 = m3 ^ p3; \ + } while (0) +#endif + +#if SPH_SMALL_FOOTPRINT_SKEIN + +#define UBI_BIG(etype, extra) do { \ + sph_u64 t0, t1, t2; \ + unsigned u; \ + sph_u64 m0 = sph_dec64le_aligned(buf + 0); \ + sph_u64 m1 = sph_dec64le_aligned(buf + 8); \ + sph_u64 m2 = sph_dec64le_aligned(buf + 16); \ + sph_u64 m3 = sph_dec64le_aligned(buf + 24); \ + sph_u64 m4 = sph_dec64le_aligned(buf + 32); \ + sph_u64 m5 = sph_dec64le_aligned(buf + 40); \ + sph_u64 m6 = sph_dec64le_aligned(buf + 48); \ + sph_u64 m7 = sph_dec64le_aligned(buf + 56); \ + sph_u64 p0 = m0; \ + sph_u64 p1 = m1; \ + sph_u64 p2 = m2; \ + sph_u64 p3 = m3; \ + sph_u64 p4 = m4; \ + sph_u64 p5 = m5; \ + sph_u64 p6 = m6; \ + sph_u64 p7 = m7; \ + t0 = SPH_T64(bcount << 6) + (sph_u64)(extra); \ + t1 = (bcount >> 58) + ((sph_u64)(etype) << 55); \ + TFBIG_KINIT(h[0], h[1], h[2], h[3], h[4], h[5], \ + h[6], h[7], h[8], t0, t1, t2); \ + for (u = 0; u <= 15; u += 3) { \ + h[u + 9] = h[u + 0]; \ + h[u + 10] = h[u + 1]; \ + h[u + 11] = h[u + 2]; \ + } \ + for (u = 0; u < 9; u ++) { \ + sph_u64 s = u << 1; \ + sph_u64 tmp; \ + TFBIG_4e(s); \ + TFBIG_4o(s + 1); \ + tmp = t2; \ + t2 = t1; \ + t1 = t0; \ + t0 = tmp; \ + } \ + TFBIG_ADDKEY(18, t0, t1); \ + h[0] = m0 ^ p0; \ + h[1] = m1 ^ p1; \ + h[2] = m2 ^ p2; \ + h[3] = m3 ^ p3; \ + h[4] = m4 ^ p4; \ + h[5] = m5 ^ p5; \ + h[6] = m6 ^ p6; \ + h[7] = m7 ^ p7; \ + } while (0) + +#else + +#define UBI_BIG(etype, extra) do { \ + sph_u64 h8, t0, t1, t2; \ + sph_u64 m0 = sph_dec64le_aligned(buf + 0); \ + sph_u64 m1 = sph_dec64le_aligned(buf + 8); \ + sph_u64 m2 = sph_dec64le_aligned(buf + 16); \ + sph_u64 m3 = sph_dec64le_aligned(buf + 24); \ + sph_u64 m4 = sph_dec64le_aligned(buf + 32); \ + sph_u64 m5 = sph_dec64le_aligned(buf + 40); \ + sph_u64 m6 = sph_dec64le_aligned(buf + 48); \ + sph_u64 m7 = sph_dec64le_aligned(buf + 56); \ + sph_u64 p0 = m0; \ + sph_u64 p1 = m1; \ + sph_u64 p2 = m2; \ + sph_u64 p3 = m3; \ + sph_u64 p4 = m4; \ + sph_u64 p5 = m5; \ + sph_u64 p6 = m6; \ + sph_u64 p7 = m7; \ + t0 = SPH_T64(bcount << 6) + (sph_u64)(extra); \ + t1 = (bcount >> 58) + ((sph_u64)(etype) << 55); \ + TFBIG_KINIT(h0, h1, h2, h3, h4, h5, h6, h7, h8, t0, t1, t2); \ + TFBIG_4e(0); \ + TFBIG_4o(1); \ + TFBIG_4e(2); \ + TFBIG_4o(3); \ + TFBIG_4e(4); \ + TFBIG_4o(5); \ + TFBIG_4e(6); \ + TFBIG_4o(7); \ + TFBIG_4e(8); \ + TFBIG_4o(9); \ + TFBIG_4e(10); \ + TFBIG_4o(11); \ + TFBIG_4e(12); \ + TFBIG_4o(13); \ + TFBIG_4e(14); \ + TFBIG_4o(15); \ + TFBIG_4e(16); \ + TFBIG_4o(17); \ + TFBIG_ADDKEY(p0, p1, p2, p3, p4, p5, p6, p7, h, t, 18); \ + h0 = m0 ^ p0; \ + h1 = m1 ^ p1; \ + h2 = m2 ^ p2; \ + h3 = m3 ^ p3; \ + h4 = m4 ^ p4; \ + h5 = m5 ^ p5; \ + h6 = m6 ^ p6; \ + h7 = m7 ^ p7; \ + } while (0) + +#endif + +#if 0 +/* obsolete */ +#define DECL_STATE_SMALL \ + sph_u64 h0, h1, h2, h3; \ + sph_u64 bcount; + +#define READ_STATE_SMALL(sc) do { \ + h0 = (sc)->h0; \ + h1 = (sc)->h1; \ + h2 = (sc)->h2; \ + h3 = (sc)->h3; \ + bcount = sc->bcount; \ + } while (0) + +#define WRITE_STATE_SMALL(sc) do { \ + (sc)->h0 = h0; \ + (sc)->h1 = h1; \ + (sc)->h2 = h2; \ + (sc)->h3 = h3; \ + sc->bcount = bcount; \ + } while (0) +#endif + +#if SPH_SMALL_FOOTPRINT_SKEIN + +#define DECL_STATE_BIG \ + sph_u64 h[27]; \ + sph_u64 bcount; + +#define READ_STATE_BIG(sc) do { \ + h[0] = (sc)->h0; \ + h[1] = (sc)->h1; \ + h[2] = (sc)->h2; \ + h[3] = (sc)->h3; \ + h[4] = (sc)->h4; \ + h[5] = (sc)->h5; \ + h[6] = (sc)->h6; \ + h[7] = (sc)->h7; \ + bcount = sc->bcount; \ + } while (0) + +#define WRITE_STATE_BIG(sc) do { \ + (sc)->h0 = h[0]; \ + (sc)->h1 = h[1]; \ + (sc)->h2 = h[2]; \ + (sc)->h3 = h[3]; \ + (sc)->h4 = h[4]; \ + (sc)->h5 = h[5]; \ + (sc)->h6 = h[6]; \ + (sc)->h7 = h[7]; \ + sc->bcount = bcount; \ + } while (0) + +#else + +#define DECL_STATE_BIG \ + sph_u64 h0, h1, h2, h3, h4, h5, h6, h7; \ + sph_u64 bcount; + +#define READ_STATE_BIG(sc) do { \ + h0 = (sc)->h0; \ + h1 = (sc)->h1; \ + h2 = (sc)->h2; \ + h3 = (sc)->h3; \ + h4 = (sc)->h4; \ + h5 = (sc)->h5; \ + h6 = (sc)->h6; \ + h7 = (sc)->h7; \ + bcount = sc->bcount; \ + } while (0) + +#define WRITE_STATE_BIG(sc) do { \ + (sc)->h0 = h0; \ + (sc)->h1 = h1; \ + (sc)->h2 = h2; \ + (sc)->h3 = h3; \ + (sc)->h4 = h4; \ + (sc)->h5 = h5; \ + (sc)->h6 = h6; \ + (sc)->h7 = h7; \ + sc->bcount = bcount; \ + } while (0) + +#endif + +#if 0 +/* obsolete */ +static void +skein_small_init(sph_skein_small_context *sc, const sph_u64 *iv) +{ + sc->h0 = iv[0]; + sc->h1 = iv[1]; + sc->h2 = iv[2]; + sc->h3 = iv[3]; + sc->bcount = 0; + sc->ptr = 0; +} +#endif + +static void +skein_big_init(sph_skein_big_context *sc, const sph_u64 *iv) +{ + sc->h0 = iv[0]; + sc->h1 = iv[1]; + sc->h2 = iv[2]; + sc->h3 = iv[3]; + sc->h4 = iv[4]; + sc->h5 = iv[5]; + sc->h6 = iv[6]; + sc->h7 = iv[7]; + sc->bcount = 0; + sc->ptr = 0; +} + +#if 0 +/* obsolete */ +static void +skein_small_core(sph_skein_small_context *sc, const void *data, size_t len) +{ + unsigned char *buf; + size_t ptr, clen; + unsigned first; + DECL_STATE_SMALL + + buf = sc->buf; + ptr = sc->ptr; + clen = (sizeof sc->buf) - ptr; + if (len <= clen) { + memcpy(buf + ptr, data, len); + sc->ptr = ptr + len; + return; + } + if (clen != 0) { + memcpy(buf + ptr, data, clen); + data = (const unsigned char *)data + clen; + len -= clen; + } + +#if SPH_SMALL_FOOTPRINT_SKEIN + + READ_STATE_SMALL(sc); + first = (bcount == 0) << 7; + for (;;) { + bcount ++; + UBI_SMALL(96 + first, 0); + if (len <= sizeof sc->buf) + break; + first = 0; + memcpy(buf, data, sizeof sc->buf); + data = (const unsigned char *)data + sizeof sc->buf; + len -= sizeof sc->buf; + } + WRITE_STATE_SMALL(sc); + sc->ptr = len; + memcpy(buf, data, len); + +#else + + /* + * Unrolling the loop yields a slight performance boost, while + * keeping the code size aorund 24 kB on 32-bit x86. + */ + READ_STATE_SMALL(sc); + first = (bcount == 0) << 7; + for (;;) { + bcount ++; + UBI_SMALL(96 + first, 0); + if (len <= sizeof sc->buf) + break; + buf = (unsigned char *)data; + bcount ++; + UBI_SMALL(96, 0); + if (len <= 2 * sizeof sc->buf) { + data = buf + sizeof sc->buf; + len -= sizeof sc->buf; + break; + } + buf += sizeof sc->buf; + data = buf + sizeof sc->buf; + first = 0; + len -= 2 * sizeof sc->buf; + } + WRITE_STATE_SMALL(sc); + sc->ptr = len; + memcpy(sc->buf, data, len); + +#endif +} +#endif + +static void +skein_big_core(sph_skein_big_context *sc, const void *data, size_t len) +{ + /* + * The Skein "final bit" in the tweak is troublesome here, + * because if the input has a length which is a multiple of the + * block size (512 bits) then that bit must be set for the + * final block, which is full of message bits (padding in + * Skein can be reduced to no extra bit at all). However, this + * function cannot know whether it processes the last chunks of + * the message or not. Hence we may keep a full block of buffered + * data (64 bytes). + */ + unsigned char *buf; + size_t ptr; + unsigned first; + DECL_STATE_BIG + + buf = sc->buf; + ptr = sc->ptr; + if (len <= (sizeof sc->buf) - ptr) { + memcpy(buf + ptr, data, len); + ptr += len; + sc->ptr = ptr; + return; + } + + READ_STATE_BIG(sc); + first = (bcount == 0) << 7; + do { + size_t clen; + + if (ptr == sizeof sc->buf) { + bcount ++; + UBI_BIG(96 + first, 0); + first = 0; + ptr = 0; + } + clen = (sizeof sc->buf) - ptr; + if (clen > len) + clen = len; + memcpy(buf + ptr, data, clen); + ptr += clen; + data = (const unsigned char *)data + clen; + len -= clen; + } while (len > 0); + WRITE_STATE_BIG(sc); + sc->ptr = ptr; +} + +#if 0 +/* obsolete */ +static void +skein_small_close(sph_skein_small_context *sc, unsigned ub, unsigned n, + void *dst, size_t out_len) +{ + unsigned char *buf; + size_t ptr; + unsigned et; + int i; + DECL_STATE_SMALL + + if (n != 0) { + unsigned z; + unsigned char x; + + z = 0x80 >> n; + x = ((ub & -z) | z) & 0xFF; + skein_small_core(sc, &x, 1); + } + + buf = sc->buf; + ptr = sc->ptr; + READ_STATE_SMALL(sc); + memset(buf + ptr, 0, (sizeof sc->buf) - ptr); + et = 352 + ((bcount == 0) << 7) + (n != 0); + for (i = 0; i < 2; i ++) { + UBI_SMALL(et, ptr); + if (i == 0) { + memset(buf, 0, sizeof sc->buf); + bcount = 0; + et = 510; + ptr = 8; + } + } + + sph_enc64le_aligned(buf + 0, h0); + sph_enc64le_aligned(buf + 8, h1); + sph_enc64le_aligned(buf + 16, h2); + sph_enc64le_aligned(buf + 24, h3); + memcpy(dst, buf, out_len); +} +#endif + +static void +skein_big_close(sph_skein_big_context *sc, unsigned ub, unsigned n, + void *dst, size_t out_len) +{ + unsigned char *buf; + size_t ptr; + unsigned et; + int i; +#if SPH_SMALL_FOOTPRINT_SKEIN + size_t u; +#endif + DECL_STATE_BIG + + /* + * Add bit padding if necessary. + */ + if (n != 0) { + unsigned z; + unsigned char x; + + z = 0x80 >> n; + x = ((ub & -z) | z) & 0xFF; + skein_big_core(sc, &x, 1); + } + + buf = sc->buf; + ptr = sc->ptr; + + /* + * At that point, if ptr == 0, then the message was empty; + * otherwise, there is between 1 and 64 bytes (inclusive) which + * are yet to be processed. Either way, we complete the buffer + * to a full block with zeros (the Skein specification mandates + * that an empty message is padded so that there is at least + * one block to process). + * + * Once this block has been processed, we do it again, with + * a block full of zeros, for the output (that block contains + * the encoding of "0", over 8 bytes, then padded with zeros). + */ + READ_STATE_BIG(sc); + memset(buf + ptr, 0, (sizeof sc->buf) - ptr); + et = 352 + ((bcount == 0) << 7) + (n != 0); + for (i = 0; i < 2; i ++) { + UBI_BIG(et, ptr); + if (i == 0) { + memset(buf, 0, sizeof sc->buf); + bcount = 0; + et = 510; + ptr = 8; + } + } + +#if SPH_SMALL_FOOTPRINT_SKEIN + + /* + * We use a temporary buffer because we must support the case + * where output size is not a multiple of 64 (namely, a 224-bit + * output). + */ + for (u = 0; u < out_len; u += 8) + sph_enc64le_aligned(buf + u, h[u >> 3]); + memcpy(dst, buf, out_len); + +#else + + sph_enc64le_aligned(buf + 0, h0); + sph_enc64le_aligned(buf + 8, h1); + sph_enc64le_aligned(buf + 16, h2); + sph_enc64le_aligned(buf + 24, h3); + sph_enc64le_aligned(buf + 32, h4); + sph_enc64le_aligned(buf + 40, h5); + sph_enc64le_aligned(buf + 48, h6); + sph_enc64le_aligned(buf + 56, h7); + memcpy(dst, buf, out_len); + +#endif +} + +#if 0 +/* obsolete */ +static const sph_u64 IV224[] = { + SPH_C64(0xC6098A8C9AE5EA0B), SPH_C64(0x876D568608C5191C), + SPH_C64(0x99CB88D7D7F53884), SPH_C64(0x384BDDB1AEDDB5DE) +}; + +static const sph_u64 IV256[] = { + SPH_C64(0xFC9DA860D048B449), SPH_C64(0x2FCA66479FA7D833), + SPH_C64(0xB33BC3896656840F), SPH_C64(0x6A54E920FDE8DA69) +}; +#endif + +static const sph_u64 IV224[] = { + SPH_C64(0xCCD0616248677224), SPH_C64(0xCBA65CF3A92339EF), + SPH_C64(0x8CCD69D652FF4B64), SPH_C64(0x398AED7B3AB890B4), + SPH_C64(0x0F59D1B1457D2BD0), SPH_C64(0x6776FE6575D4EB3D), + SPH_C64(0x99FBC70E997413E9), SPH_C64(0x9E2CFCCFE1C41EF7) +}; + +static const sph_u64 IV256[] = { + SPH_C64(0xCCD044A12FDB3E13), SPH_C64(0xE83590301A79A9EB), + SPH_C64(0x55AEA0614F816E6F), SPH_C64(0x2A2767A4AE9B94DB), + SPH_C64(0xEC06025E74DD7683), SPH_C64(0xE7A436CDC4746251), + SPH_C64(0xC36FBAF9393AD185), SPH_C64(0x3EEDBA1833EDFC13) +}; + +static const sph_u64 IV384[] = { + SPH_C64(0xA3F6C6BF3A75EF5F), SPH_C64(0xB0FEF9CCFD84FAA4), + SPH_C64(0x9D77DD663D770CFE), SPH_C64(0xD798CBF3B468FDDA), + SPH_C64(0x1BC4A6668A0E4465), SPH_C64(0x7ED7D434E5807407), + SPH_C64(0x548FC1ACD4EC44D6), SPH_C64(0x266E17546AA18FF8) +}; + +static const sph_u64 IV512[] = { + SPH_C64(0x4903ADFF749C51CE), SPH_C64(0x0D95DE399746DF03), + SPH_C64(0x8FD1934127C79BCE), SPH_C64(0x9A255629FF352CB1), + SPH_C64(0x5DB62599DF6CA7B0), SPH_C64(0xEABE394CA9D5C3F4), + SPH_C64(0x991112C71A75B523), SPH_C64(0xAE18A40B660FCC33) +}; + +#if 0 +/* obsolete */ +/* see sph_skein.h */ +void +sph_skein224_init(void *cc) +{ + skein_small_init(cc, IV224); +} + +/* see sph_skein.h */ +void +sph_skein224(void *cc, const void *data, size_t len) +{ + skein_small_core(cc, data, len); +} + +/* see sph_skein.h */ +void +sph_skein224_close(void *cc, void *dst) +{ + sph_skein224_addbits_and_close(cc, 0, 0, dst); +} + +/* see sph_skein.h */ +void +sph_skein224_addbits_and_close(void *cc, unsigned ub, unsigned n, void *dst) +{ + skein_small_close(cc, ub, n, dst, 28); + sph_skein224_init(cc); +} + +/* see sph_skein.h */ +void +sph_skein256_init(void *cc) +{ + skein_small_init(cc, IV256); +} + +/* see sph_skein.h */ +void +sph_skein256(void *cc, const void *data, size_t len) +{ + skein_small_core(cc, data, len); +} + +/* see sph_skein.h */ +void +sph_skein256_close(void *cc, void *dst) +{ + sph_skein256_addbits_and_close(cc, 0, 0, dst); +} + +/* see sph_skein.h */ +void +sph_skein256_addbits_and_close(void *cc, unsigned ub, unsigned n, void *dst) +{ + skein_small_close(cc, ub, n, dst, 32); + sph_skein256_init(cc); +} +#endif + +/* see sph_skein.h */ +void +sph_skein224_init(void *cc) +{ + skein_big_init(cc, IV224); +} + +/* see sph_skein.h */ +void +sph_skein224(void *cc, const void *data, size_t len) +{ + skein_big_core(cc, data, len); +} + +/* see sph_skein.h */ +void +sph_skein224_close(void *cc, void *dst) +{ + sph_skein224_addbits_and_close(cc, 0, 0, dst); +} + +/* see sph_skein.h */ +void +sph_skein224_addbits_and_close(void *cc, unsigned ub, unsigned n, void *dst) +{ + skein_big_close(cc, ub, n, dst, 28); + sph_skein224_init(cc); +} + +/* see sph_skein.h */ +void +sph_skein256_init(void *cc) +{ + skein_big_init(cc, IV256); +} + +/* see sph_skein.h */ +void +sph_skein256(void *cc, const void *data, size_t len) +{ + skein_big_core(cc, data, len); +} + +/* see sph_skein.h */ +void +sph_skein256_close(void *cc, void *dst) +{ + sph_skein256_addbits_and_close(cc, 0, 0, dst); +} + +/* see sph_skein.h */ +void +sph_skein256_addbits_and_close(void *cc, unsigned ub, unsigned n, void *dst) +{ + skein_big_close(cc, ub, n, dst, 32); + sph_skein256_init(cc); +} + +/* see sph_skein.h */ +void +sph_skein384_init(void *cc) +{ + skein_big_init(cc, IV384); +} + +/* see sph_skein.h */ +void +sph_skein384(void *cc, const void *data, size_t len) +{ + skein_big_core(cc, data, len); +} + +/* see sph_skein.h */ +void +sph_skein384_close(void *cc, void *dst) +{ + sph_skein384_addbits_and_close(cc, 0, 0, dst); +} + +/* see sph_skein.h */ +void +sph_skein384_addbits_and_close(void *cc, unsigned ub, unsigned n, void *dst) +{ + skein_big_close(cc, ub, n, dst, 48); + sph_skein384_init(cc); +} + +/* see sph_skein.h */ +void +sph_skein512_init(void *cc) +{ + skein_big_init(cc, IV512); +} + +/* see sph_skein.h */ +void +sph_skein512(void *cc, const void *data, size_t len) +{ + skein_big_core(cc, data, len); +} + +/* see sph_skein.h */ +void +sph_skein512_close(void *cc, void *dst) +{ + sph_skein512_addbits_and_close(cc, 0, 0, dst); +} + +/* see sph_skein.h */ +void +sph_skein512_addbits_and_close(void *cc, unsigned ub, unsigned n, void *dst) +{ + skein_big_close(cc, ub, n, dst, 64); + sph_skein512_init(cc); +} + +#endif + + +#ifdef __cplusplus +} +#endif diff --git a/src/sph_blake.h b/src/sph_blake.h new file mode 100644 index 0000000..d8d7943 --- /dev/null +++ b/src/sph_blake.h @@ -0,0 +1,327 @@ +/* $Id: sph_blake.h 252 2011-06-07 17:55:14Z tp $ */ +/** + * BLAKE interface. BLAKE is a family of functions which differ by their + * output size; this implementation defines BLAKE for output sizes 224, + * 256, 384 and 512 bits. This implementation conforms to the "third + * round" specification. + * + * ==========================(LICENSE BEGIN)============================ + * + * Copyright (c) 2007-2010 Projet RNRT SAPHIR + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * ===========================(LICENSE END)============================= + * + * @file sph_blake.h + * @author Thomas Pornin + */ + +#ifndef SPH_BLAKE_H__ +#define SPH_BLAKE_H__ + +#ifdef __cplusplus +extern "C"{ +#endif + +#include +#include "sph_types.h" + +/** + * Output size (in bits) for BLAKE-224. + */ +#define SPH_SIZE_blake224 224 + +/** + * Output size (in bits) for BLAKE-256. + */ +#define SPH_SIZE_blake256 256 + +#if SPH_64 + +/** + * Output size (in bits) for BLAKE-384. + */ +#define SPH_SIZE_blake384 384 + +/** + * Output size (in bits) for BLAKE-512. + */ +#define SPH_SIZE_blake512 512 + +#endif + +/** + * This structure is a context for BLAKE-224 and BLAKE-256 computations: + * it contains the intermediate values and some data from the last + * entered block. Once a BLAKE computation has been performed, the + * context can be reused for another computation. + * + * The contents of this structure are private. A running BLAKE + * computation can be cloned by copying the context (e.g. with a simple + * memcpy()). + */ +typedef struct { +#ifndef DOXYGEN_IGNORE + unsigned char buf[64]; /* first field, for alignment */ + size_t ptr; + sph_u32 H[8]; + sph_u32 S[4]; + sph_u32 T0, T1; +#endif +} sph_blake_small_context; + +/** + * This structure is a context for BLAKE-224 computations. It is + * identical to the common sph_blake_small_context. + */ +typedef sph_blake_small_context sph_blake224_context; + +/** + * This structure is a context for BLAKE-256 computations. It is + * identical to the common sph_blake_small_context. + */ +typedef sph_blake_small_context sph_blake256_context; + +#if SPH_64 + +/** + * This structure is a context for BLAKE-384 and BLAKE-512 computations: + * it contains the intermediate values and some data from the last + * entered block. Once a BLAKE computation has been performed, the + * context can be reused for another computation. + * + * The contents of this structure are private. A running BLAKE + * computation can be cloned by copying the context (e.g. with a simple + * memcpy()). + */ +typedef struct { +#ifndef DOXYGEN_IGNORE + unsigned char buf[128]; /* first field, for alignment */ + size_t ptr; + sph_u64 H[8]; + sph_u64 S[4]; + sph_u64 T0, T1; +#endif +} sph_blake_big_context; + +/** + * This structure is a context for BLAKE-384 computations. It is + * identical to the common sph_blake_small_context. + */ +typedef sph_blake_big_context sph_blake384_context; + +/** + * This structure is a context for BLAKE-512 computations. It is + * identical to the common sph_blake_small_context. + */ +typedef sph_blake_big_context sph_blake512_context; + +#endif + +/** + * Initialize a BLAKE-224 context. This process performs no memory allocation. + * + * @param cc the BLAKE-224 context (pointer to a + * sph_blake224_context) + */ +void sph_blake224_init(void *cc); + +/** + * Process some data bytes. It is acceptable that len is zero + * (in which case this function does nothing). + * + * @param cc the BLAKE-224 context + * @param data the input data + * @param len the input data length (in bytes) + */ +void sph_blake224(void *cc, const void *data, size_t len); + +/** + * Terminate the current BLAKE-224 computation and output the result into + * the provided buffer. The destination buffer must be wide enough to + * accomodate the result (28 bytes). The context is automatically + * reinitialized. + * + * @param cc the BLAKE-224 context + * @param dst the destination buffer + */ +void sph_blake224_close(void *cc, void *dst); + +/** + * Add a few additional bits (0 to 7) to the current computation, then + * terminate it and output the result in the provided buffer, which must + * be wide enough to accomodate the result (28 bytes). If bit number i + * in ub has value 2^i, then the extra bits are those + * numbered 7 downto 8-n (this is the big-endian convention at the byte + * level). The context is automatically reinitialized. + * + * @param cc the BLAKE-224 context + * @param ub the extra bits + * @param n the number of extra bits (0 to 7) + * @param dst the destination buffer + */ +void sph_blake224_addbits_and_close( + void *cc, unsigned ub, unsigned n, void *dst); + +/** + * Initialize a BLAKE-256 context. This process performs no memory allocation. + * + * @param cc the BLAKE-256 context (pointer to a + * sph_blake256_context) + */ +void sph_blake256_init(void *cc); + +/** + * Process some data bytes. It is acceptable that len is zero + * (in which case this function does nothing). + * + * @param cc the BLAKE-256 context + * @param data the input data + * @param len the input data length (in bytes) + */ +void sph_blake256(void *cc, const void *data, size_t len); + +/** + * Terminate the current BLAKE-256 computation and output the result into + * the provided buffer. The destination buffer must be wide enough to + * accomodate the result (32 bytes). The context is automatically + * reinitialized. + * + * @param cc the BLAKE-256 context + * @param dst the destination buffer + */ +void sph_blake256_close(void *cc, void *dst); + +/** + * Add a few additional bits (0 to 7) to the current computation, then + * terminate it and output the result in the provided buffer, which must + * be wide enough to accomodate the result (32 bytes). If bit number i + * in ub has value 2^i, then the extra bits are those + * numbered 7 downto 8-n (this is the big-endian convention at the byte + * level). The context is automatically reinitialized. + * + * @param cc the BLAKE-256 context + * @param ub the extra bits + * @param n the number of extra bits (0 to 7) + * @param dst the destination buffer + */ +void sph_blake256_addbits_and_close( + void *cc, unsigned ub, unsigned n, void *dst); + +#if SPH_64 + +/** + * Initialize a BLAKE-384 context. This process performs no memory allocation. + * + * @param cc the BLAKE-384 context (pointer to a + * sph_blake384_context) + */ +void sph_blake384_init(void *cc); + +/** + * Process some data bytes. It is acceptable that len is zero + * (in which case this function does nothing). + * + * @param cc the BLAKE-384 context + * @param data the input data + * @param len the input data length (in bytes) + */ +void sph_blake384(void *cc, const void *data, size_t len); + +/** + * Terminate the current BLAKE-384 computation and output the result into + * the provided buffer. The destination buffer must be wide enough to + * accomodate the result (48 bytes). The context is automatically + * reinitialized. + * + * @param cc the BLAKE-384 context + * @param dst the destination buffer + */ +void sph_blake384_close(void *cc, void *dst); + +/** + * Add a few additional bits (0 to 7) to the current computation, then + * terminate it and output the result in the provided buffer, which must + * be wide enough to accomodate the result (48 bytes). If bit number i + * in ub has value 2^i, then the extra bits are those + * numbered 7 downto 8-n (this is the big-endian convention at the byte + * level). The context is automatically reinitialized. + * + * @param cc the BLAKE-384 context + * @param ub the extra bits + * @param n the number of extra bits (0 to 7) + * @param dst the destination buffer + */ +void sph_blake384_addbits_and_close( + void *cc, unsigned ub, unsigned n, void *dst); + +/** + * Initialize a BLAKE-512 context. This process performs no memory allocation. + * + * @param cc the BLAKE-512 context (pointer to a + * sph_blake512_context) + */ +void sph_blake512_init(void *cc); + +/** + * Process some data bytes. It is acceptable that len is zero + * (in which case this function does nothing). + * + * @param cc the BLAKE-512 context + * @param data the input data + * @param len the input data length (in bytes) + */ +void sph_blake512(void *cc, const void *data, size_t len); + +/** + * Terminate the current BLAKE-512 computation and output the result into + * the provided buffer. The destination buffer must be wide enough to + * accomodate the result (64 bytes). The context is automatically + * reinitialized. + * + * @param cc the BLAKE-512 context + * @param dst the destination buffer + */ +void sph_blake512_close(void *cc, void *dst); + +/** + * Add a few additional bits (0 to 7) to the current computation, then + * terminate it and output the result in the provided buffer, which must + * be wide enough to accomodate the result (64 bytes). If bit number i + * in ub has value 2^i, then the extra bits are those + * numbered 7 downto 8-n (this is the big-endian convention at the byte + * level). The context is automatically reinitialized. + * + * @param cc the BLAKE-512 context + * @param ub the extra bits + * @param n the number of extra bits (0 to 7) + * @param dst the destination buffer + */ +void sph_blake512_addbits_and_close( + void *cc, unsigned ub, unsigned n, void *dst); + +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/sph_bmw.h b/src/sph_bmw.h new file mode 100644 index 0000000..d386b0c --- /dev/null +++ b/src/sph_bmw.h @@ -0,0 +1,328 @@ +/* $Id: sph_bmw.h 216 2010-06-08 09:46:57Z tp $ */ +/** + * BMW interface. BMW (aka "Blue Midnight Wish") is a family of + * functions which differ by their output size; this implementation + * defines BMW for output sizes 224, 256, 384 and 512 bits. + * + * ==========================(LICENSE BEGIN)============================ + * + * Copyright (c) 2007-2010 Projet RNRT SAPHIR + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * ===========================(LICENSE END)============================= + * + * @file sph_bmw.h + * @author Thomas Pornin + */ + +#ifndef SPH_BMW_H__ +#define SPH_BMW_H__ + +#ifdef __cplusplus +extern "C"{ +#endif + +#include +#include "sph_types.h" + +/** + * Output size (in bits) for BMW-224. + */ +#define SPH_SIZE_bmw224 224 + +/** + * Output size (in bits) for BMW-256. + */ +#define SPH_SIZE_bmw256 256 + +#if SPH_64 + +/** + * Output size (in bits) for BMW-384. + */ +#define SPH_SIZE_bmw384 384 + +/** + * Output size (in bits) for BMW-512. + */ +#define SPH_SIZE_bmw512 512 + +#endif + +/** + * This structure is a context for BMW-224 and BMW-256 computations: + * it contains the intermediate values and some data from the last + * entered block. Once a BMW computation has been performed, the + * context can be reused for another computation. + * + * The contents of this structure are private. A running BMW + * computation can be cloned by copying the context (e.g. with a simple + * memcpy()). + */ +typedef struct { +#ifndef DOXYGEN_IGNORE + unsigned char buf[64]; /* first field, for alignment */ + size_t ptr; + sph_u32 H[16]; +#if SPH_64 + sph_u64 bit_count; +#else + sph_u32 bit_count_high, bit_count_low; +#endif +#endif +} sph_bmw_small_context; + +/** + * This structure is a context for BMW-224 computations. It is + * identical to the common sph_bmw_small_context. + */ +typedef sph_bmw_small_context sph_bmw224_context; + +/** + * This structure is a context for BMW-256 computations. It is + * identical to the common sph_bmw_small_context. + */ +typedef sph_bmw_small_context sph_bmw256_context; + +#if SPH_64 + +/** + * This structure is a context for BMW-384 and BMW-512 computations: + * it contains the intermediate values and some data from the last + * entered block. Once a BMW computation has been performed, the + * context can be reused for another computation. + * + * The contents of this structure are private. A running BMW + * computation can be cloned by copying the context (e.g. with a simple + * memcpy()). + */ +typedef struct { +#ifndef DOXYGEN_IGNORE + unsigned char buf[128]; /* first field, for alignment */ + size_t ptr; + sph_u64 H[16]; + sph_u64 bit_count; +#endif +} sph_bmw_big_context; + +/** + * This structure is a context for BMW-384 computations. It is + * identical to the common sph_bmw_small_context. + */ +typedef sph_bmw_big_context sph_bmw384_context; + +/** + * This structure is a context for BMW-512 computations. It is + * identical to the common sph_bmw_small_context. + */ +typedef sph_bmw_big_context sph_bmw512_context; + +#endif + +/** + * Initialize a BMW-224 context. This process performs no memory allocation. + * + * @param cc the BMW-224 context (pointer to a + * sph_bmw224_context) + */ +void sph_bmw224_init(void *cc); + +/** + * Process some data bytes. It is acceptable that len is zero + * (in which case this function does nothing). + * + * @param cc the BMW-224 context + * @param data the input data + * @param len the input data length (in bytes) + */ +void sph_bmw224(void *cc, const void *data, size_t len); + +/** + * Terminate the current BMW-224 computation and output the result into + * the provided buffer. The destination buffer must be wide enough to + * accomodate the result (28 bytes). The context is automatically + * reinitialized. + * + * @param cc the BMW-224 context + * @param dst the destination buffer + */ +void sph_bmw224_close(void *cc, void *dst); + +/** + * Add a few additional bits (0 to 7) to the current computation, then + * terminate it and output the result in the provided buffer, which must + * be wide enough to accomodate the result (28 bytes). If bit number i + * in ub has value 2^i, then the extra bits are those + * numbered 7 downto 8-n (this is the big-endian convention at the byte + * level). The context is automatically reinitialized. + * + * @param cc the BMW-224 context + * @param ub the extra bits + * @param n the number of extra bits (0 to 7) + * @param dst the destination buffer + */ +void sph_bmw224_addbits_and_close( + void *cc, unsigned ub, unsigned n, void *dst); + +/** + * Initialize a BMW-256 context. This process performs no memory allocation. + * + * @param cc the BMW-256 context (pointer to a + * sph_bmw256_context) + */ +void sph_bmw256_init(void *cc); + +/** + * Process some data bytes. It is acceptable that len is zero + * (in which case this function does nothing). + * + * @param cc the BMW-256 context + * @param data the input data + * @param len the input data length (in bytes) + */ +void sph_bmw256(void *cc, const void *data, size_t len); + +/** + * Terminate the current BMW-256 computation and output the result into + * the provided buffer. The destination buffer must be wide enough to + * accomodate the result (32 bytes). The context is automatically + * reinitialized. + * + * @param cc the BMW-256 context + * @param dst the destination buffer + */ +void sph_bmw256_close(void *cc, void *dst); + +/** + * Add a few additional bits (0 to 7) to the current computation, then + * terminate it and output the result in the provided buffer, which must + * be wide enough to accomodate the result (32 bytes). If bit number i + * in ub has value 2^i, then the extra bits are those + * numbered 7 downto 8-n (this is the big-endian convention at the byte + * level). The context is automatically reinitialized. + * + * @param cc the BMW-256 context + * @param ub the extra bits + * @param n the number of extra bits (0 to 7) + * @param dst the destination buffer + */ +void sph_bmw256_addbits_and_close( + void *cc, unsigned ub, unsigned n, void *dst); + +#if SPH_64 + +/** + * Initialize a BMW-384 context. This process performs no memory allocation. + * + * @param cc the BMW-384 context (pointer to a + * sph_bmw384_context) + */ +void sph_bmw384_init(void *cc); + +/** + * Process some data bytes. It is acceptable that len is zero + * (in which case this function does nothing). + * + * @param cc the BMW-384 context + * @param data the input data + * @param len the input data length (in bytes) + */ +void sph_bmw384(void *cc, const void *data, size_t len); + +/** + * Terminate the current BMW-384 computation and output the result into + * the provided buffer. The destination buffer must be wide enough to + * accomodate the result (48 bytes). The context is automatically + * reinitialized. + * + * @param cc the BMW-384 context + * @param dst the destination buffer + */ +void sph_bmw384_close(void *cc, void *dst); + +/** + * Add a few additional bits (0 to 7) to the current computation, then + * terminate it and output the result in the provided buffer, which must + * be wide enough to accomodate the result (48 bytes). If bit number i + * in ub has value 2^i, then the extra bits are those + * numbered 7 downto 8-n (this is the big-endian convention at the byte + * level). The context is automatically reinitialized. + * + * @param cc the BMW-384 context + * @param ub the extra bits + * @param n the number of extra bits (0 to 7) + * @param dst the destination buffer + */ +void sph_bmw384_addbits_and_close( + void *cc, unsigned ub, unsigned n, void *dst); + +/** + * Initialize a BMW-512 context. This process performs no memory allocation. + * + * @param cc the BMW-512 context (pointer to a + * sph_bmw512_context) + */ +void sph_bmw512_init(void *cc); + +/** + * Process some data bytes. It is acceptable that len is zero + * (in which case this function does nothing). + * + * @param cc the BMW-512 context + * @param data the input data + * @param len the input data length (in bytes) + */ +void sph_bmw512(void *cc, const void *data, size_t len); + +/** + * Terminate the current BMW-512 computation and output the result into + * the provided buffer. The destination buffer must be wide enough to + * accomodate the result (64 bytes). The context is automatically + * reinitialized. + * + * @param cc the BMW-512 context + * @param dst the destination buffer + */ +void sph_bmw512_close(void *cc, void *dst); + +/** + * Add a few additional bits (0 to 7) to the current computation, then + * terminate it and output the result in the provided buffer, which must + * be wide enough to accomodate the result (64 bytes). If bit number i + * in ub has value 2^i, then the extra bits are those + * numbered 7 downto 8-n (this is the big-endian convention at the byte + * level). The context is automatically reinitialized. + * + * @param cc the BMW-512 context + * @param ub the extra bits + * @param n the number of extra bits (0 to 7) + * @param dst the destination buffer + */ +void sph_bmw512_addbits_and_close( + void *cc, unsigned ub, unsigned n, void *dst); + +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/sph_cubehash.h b/src/sph_cubehash.h new file mode 100644 index 0000000..487a194 --- /dev/null +++ b/src/sph_cubehash.h @@ -0,0 +1,292 @@ +/* $Id: sph_cubehash.h 180 2010-05-08 02:29:25Z tp $ */ +/** + * CubeHash interface. CubeHash is a family of functions which differ by + * their output size; this implementation defines CubeHash for output + * sizes 224, 256, 384 and 512 bits, with the "standard parameters" + * (CubeHash16/32 with the CubeHash specification notations). + * + * ==========================(LICENSE BEGIN)============================ + * + * Copyright (c) 2007-2010 Projet RNRT SAPHIR + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * ===========================(LICENSE END)============================= + * + * @file sph_cubehash.h + * @author Thomas Pornin + */ + +#ifndef SPH_CUBEHASH_H__ +#define SPH_CUBEHASH_H__ + +#ifdef __cplusplus +extern "C"{ +#endif + +#include +#include "sph_types.h" + +/** + * Output size (in bits) for CubeHash-224. + */ +#define SPH_SIZE_cubehash224 224 + +/** + * Output size (in bits) for CubeHash-256. + */ +#define SPH_SIZE_cubehash256 256 + +/** + * Output size (in bits) for CubeHash-384. + */ +#define SPH_SIZE_cubehash384 384 + +/** + * Output size (in bits) for CubeHash-512. + */ +#define SPH_SIZE_cubehash512 512 + +/** + * This structure is a context for CubeHash computations: it contains the + * intermediate values and some data from the last entered block. Once + * a CubeHash computation has been performed, the context can be reused for + * another computation. + * + * The contents of this structure are private. A running CubeHash computation + * can be cloned by copying the context (e.g. with a simple + * memcpy()). + */ +typedef struct { +#ifndef DOXYGEN_IGNORE + unsigned char buf[32]; /* first field, for alignment */ + size_t ptr; + sph_u32 state[32]; +#endif +} sph_cubehash_context; + +/** + * Type for a CubeHash-224 context (identical to the common context). + */ +typedef sph_cubehash_context sph_cubehash224_context; + +/** + * Type for a CubeHash-256 context (identical to the common context). + */ +typedef sph_cubehash_context sph_cubehash256_context; + +/** + * Type for a CubeHash-384 context (identical to the common context). + */ +typedef sph_cubehash_context sph_cubehash384_context; + +/** + * Type for a CubeHash-512 context (identical to the common context). + */ +typedef sph_cubehash_context sph_cubehash512_context; + +/** + * Initialize a CubeHash-224 context. This process performs no memory + * allocation. + * + * @param cc the CubeHash-224 context (pointer to a + * sph_cubehash224_context) + */ +void sph_cubehash224_init(void *cc); + +/** + * Process some data bytes. It is acceptable that len is zero + * (in which case this function does nothing). + * + * @param cc the CubeHash-224 context + * @param data the input data + * @param len the input data length (in bytes) + */ +void sph_cubehash224(void *cc, const void *data, size_t len); + +/** + * Terminate the current CubeHash-224 computation and output the result into + * the provided buffer. The destination buffer must be wide enough to + * accomodate the result (28 bytes). The context is automatically + * reinitialized. + * + * @param cc the CubeHash-224 context + * @param dst the destination buffer + */ +void sph_cubehash224_close(void *cc, void *dst); + +/** + * Add a few additional bits (0 to 7) to the current computation, then + * terminate it and output the result in the provided buffer, which must + * be wide enough to accomodate the result (28 bytes). If bit number i + * in ub has value 2^i, then the extra bits are those + * numbered 7 downto 8-n (this is the big-endian convention at the byte + * level). The context is automatically reinitialized. + * + * @param cc the CubeHash-224 context + * @param ub the extra bits + * @param n the number of extra bits (0 to 7) + * @param dst the destination buffer + */ +void sph_cubehash224_addbits_and_close( + void *cc, unsigned ub, unsigned n, void *dst); + +/** + * Initialize a CubeHash-256 context. This process performs no memory + * allocation. + * + * @param cc the CubeHash-256 context (pointer to a + * sph_cubehash256_context) + */ +void sph_cubehash256_init(void *cc); + +/** + * Process some data bytes. It is acceptable that len is zero + * (in which case this function does nothing). + * + * @param cc the CubeHash-256 context + * @param data the input data + * @param len the input data length (in bytes) + */ +void sph_cubehash256(void *cc, const void *data, size_t len); + +/** + * Terminate the current CubeHash-256 computation and output the result into + * the provided buffer. The destination buffer must be wide enough to + * accomodate the result (32 bytes). The context is automatically + * reinitialized. + * + * @param cc the CubeHash-256 context + * @param dst the destination buffer + */ +void sph_cubehash256_close(void *cc, void *dst); + +/** + * Add a few additional bits (0 to 7) to the current computation, then + * terminate it and output the result in the provided buffer, which must + * be wide enough to accomodate the result (32 bytes). If bit number i + * in ub has value 2^i, then the extra bits are those + * numbered 7 downto 8-n (this is the big-endian convention at the byte + * level). The context is automatically reinitialized. + * + * @param cc the CubeHash-256 context + * @param ub the extra bits + * @param n the number of extra bits (0 to 7) + * @param dst the destination buffer + */ +void sph_cubehash256_addbits_and_close( + void *cc, unsigned ub, unsigned n, void *dst); + +/** + * Initialize a CubeHash-384 context. This process performs no memory + * allocation. + * + * @param cc the CubeHash-384 context (pointer to a + * sph_cubehash384_context) + */ +void sph_cubehash384_init(void *cc); + +/** + * Process some data bytes. It is acceptable that len is zero + * (in which case this function does nothing). + * + * @param cc the CubeHash-384 context + * @param data the input data + * @param len the input data length (in bytes) + */ +void sph_cubehash384(void *cc, const void *data, size_t len); + +/** + * Terminate the current CubeHash-384 computation and output the result into + * the provided buffer. The destination buffer must be wide enough to + * accomodate the result (48 bytes). The context is automatically + * reinitialized. + * + * @param cc the CubeHash-384 context + * @param dst the destination buffer + */ +void sph_cubehash384_close(void *cc, void *dst); + +/** + * Add a few additional bits (0 to 7) to the current computation, then + * terminate it and output the result in the provided buffer, which must + * be wide enough to accomodate the result (48 bytes). If bit number i + * in ub has value 2^i, then the extra bits are those + * numbered 7 downto 8-n (this is the big-endian convention at the byte + * level). The context is automatically reinitialized. + * + * @param cc the CubeHash-384 context + * @param ub the extra bits + * @param n the number of extra bits (0 to 7) + * @param dst the destination buffer + */ +void sph_cubehash384_addbits_and_close( + void *cc, unsigned ub, unsigned n, void *dst); + +/** + * Initialize a CubeHash-512 context. This process performs no memory + * allocation. + * + * @param cc the CubeHash-512 context (pointer to a + * sph_cubehash512_context) + */ +void sph_cubehash512_init(void *cc); + +/** + * Process some data bytes. It is acceptable that len is zero + * (in which case this function does nothing). + * + * @param cc the CubeHash-512 context + * @param data the input data + * @param len the input data length (in bytes) + */ +void sph_cubehash512(void *cc, const void *data, size_t len); + +/** + * Terminate the current CubeHash-512 computation and output the result into + * the provided buffer. The destination buffer must be wide enough to + * accomodate the result (64 bytes). The context is automatically + * reinitialized. + * + * @param cc the CubeHash-512 context + * @param dst the destination buffer + */ +void sph_cubehash512_close(void *cc, void *dst); + +/** + * Add a few additional bits (0 to 7) to the current computation, then + * terminate it and output the result in the provided buffer, which must + * be wide enough to accomodate the result (64 bytes). If bit number i + * in ub has value 2^i, then the extra bits are those + * numbered 7 downto 8-n (this is the big-endian convention at the byte + * level). The context is automatically reinitialized. + * + * @param cc the CubeHash-512 context + * @param ub the extra bits + * @param n the number of extra bits (0 to 7) + * @param dst the destination buffer + */ +void sph_cubehash512_addbits_and_close( + void *cc, unsigned ub, unsigned n, void *dst); +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/sph_echo.h b/src/sph_echo.h new file mode 100644 index 0000000..1ae1e3d --- /dev/null +++ b/src/sph_echo.h @@ -0,0 +1,320 @@ +/* $Id: sph_echo.h 216 2010-06-08 09:46:57Z tp $ */ +/** + * ECHO interface. ECHO is a family of functions which differ by + * their output size; this implementation defines ECHO for output + * sizes 224, 256, 384 and 512 bits. + * + * ==========================(LICENSE BEGIN)============================ + * + * Copyright (c) 2007-2010 Projet RNRT SAPHIR + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * ===========================(LICENSE END)============================= + * + * @file sph_echo.h + * @author Thomas Pornin + */ + +#ifndef SPH_ECHO_H__ +#define SPH_ECHO_H__ + +#ifdef __cplusplus +extern "C"{ +#endif + +#include +#include "sph_types.h" + +/** + * Output size (in bits) for ECHO-224. + */ +#define SPH_SIZE_echo224 224 + +/** + * Output size (in bits) for ECHO-256. + */ +#define SPH_SIZE_echo256 256 + +/** + * Output size (in bits) for ECHO-384. + */ +#define SPH_SIZE_echo384 384 + +/** + * Output size (in bits) for ECHO-512. + */ +#define SPH_SIZE_echo512 512 + +/** + * This structure is a context for ECHO computations: it contains the + * intermediate values and some data from the last entered block. Once + * an ECHO computation has been performed, the context can be reused for + * another computation. This specific structure is used for ECHO-224 + * and ECHO-256. + * + * The contents of this structure are private. A running ECHO computation + * can be cloned by copying the context (e.g. with a simple + * memcpy()). + */ +typedef struct { +#ifndef DOXYGEN_IGNORE + unsigned char buf[192]; /* first field, for alignment */ + size_t ptr; + union { + sph_u32 Vs[4][4]; +#if SPH_64 + sph_u64 Vb[4][2]; +#endif + } u; + sph_u32 C0, C1, C2, C3; +#endif +} sph_echo_small_context; + +/** + * This structure is a context for ECHO computations: it contains the + * intermediate values and some data from the last entered block. Once + * an ECHO computation has been performed, the context can be reused for + * another computation. This specific structure is used for ECHO-384 + * and ECHO-512. + * + * The contents of this structure are private. A running ECHO computation + * can be cloned by copying the context (e.g. with a simple + * memcpy()). + */ +typedef struct { +#ifndef DOXYGEN_IGNORE + unsigned char buf[128]; /* first field, for alignment */ + size_t ptr; + union { + sph_u32 Vs[8][4]; +#if SPH_64 + sph_u64 Vb[8][2]; +#endif + } u; + sph_u32 C0, C1, C2, C3; +#endif +} sph_echo_big_context; + +/** + * Type for a ECHO-224 context (identical to the common "small" context). + */ +typedef sph_echo_small_context sph_echo224_context; + +/** + * Type for a ECHO-256 context (identical to the common "small" context). + */ +typedef sph_echo_small_context sph_echo256_context; + +/** + * Type for a ECHO-384 context (identical to the common "big" context). + */ +typedef sph_echo_big_context sph_echo384_context; + +/** + * Type for a ECHO-512 context (identical to the common "big" context). + */ +typedef sph_echo_big_context sph_echo512_context; + +/** + * Initialize an ECHO-224 context. This process performs no memory allocation. + * + * @param cc the ECHO-224 context (pointer to a + * sph_echo224_context) + */ +void sph_echo224_init(void *cc); + +/** + * Process some data bytes. It is acceptable that len is zero + * (in which case this function does nothing). + * + * @param cc the ECHO-224 context + * @param data the input data + * @param len the input data length (in bytes) + */ +void sph_echo224(void *cc, const void *data, size_t len); + +/** + * Terminate the current ECHO-224 computation and output the result into + * the provided buffer. The destination buffer must be wide enough to + * accomodate the result (28 bytes). The context is automatically + * reinitialized. + * + * @param cc the ECHO-224 context + * @param dst the destination buffer + */ +void sph_echo224_close(void *cc, void *dst); + +/** + * Add a few additional bits (0 to 7) to the current computation, then + * terminate it and output the result in the provided buffer, which must + * be wide enough to accomodate the result (28 bytes). If bit number i + * in ub has value 2^i, then the extra bits are those + * numbered 7 downto 8-n (this is the big-endian convention at the byte + * level). The context is automatically reinitialized. + * + * @param cc the ECHO-224 context + * @param ub the extra bits + * @param n the number of extra bits (0 to 7) + * @param dst the destination buffer + */ +void sph_echo224_addbits_and_close( + void *cc, unsigned ub, unsigned n, void *dst); + +/** + * Initialize an ECHO-256 context. This process performs no memory allocation. + * + * @param cc the ECHO-256 context (pointer to a + * sph_echo256_context) + */ +void sph_echo256_init(void *cc); + +/** + * Process some data bytes. It is acceptable that len is zero + * (in which case this function does nothing). + * + * @param cc the ECHO-256 context + * @param data the input data + * @param len the input data length (in bytes) + */ +void sph_echo256(void *cc, const void *data, size_t len); + +/** + * Terminate the current ECHO-256 computation and output the result into + * the provided buffer. The destination buffer must be wide enough to + * accomodate the result (32 bytes). The context is automatically + * reinitialized. + * + * @param cc the ECHO-256 context + * @param dst the destination buffer + */ +void sph_echo256_close(void *cc, void *dst); + +/** + * Add a few additional bits (0 to 7) to the current computation, then + * terminate it and output the result in the provided buffer, which must + * be wide enough to accomodate the result (32 bytes). If bit number i + * in ub has value 2^i, then the extra bits are those + * numbered 7 downto 8-n (this is the big-endian convention at the byte + * level). The context is automatically reinitialized. + * + * @param cc the ECHO-256 context + * @param ub the extra bits + * @param n the number of extra bits (0 to 7) + * @param dst the destination buffer + */ +void sph_echo256_addbits_and_close( + void *cc, unsigned ub, unsigned n, void *dst); + +/** + * Initialize an ECHO-384 context. This process performs no memory allocation. + * + * @param cc the ECHO-384 context (pointer to a + * sph_echo384_context) + */ +void sph_echo384_init(void *cc); + +/** + * Process some data bytes. It is acceptable that len is zero + * (in which case this function does nothing). + * + * @param cc the ECHO-384 context + * @param data the input data + * @param len the input data length (in bytes) + */ +void sph_echo384(void *cc, const void *data, size_t len); + +/** + * Terminate the current ECHO-384 computation and output the result into + * the provided buffer. The destination buffer must be wide enough to + * accomodate the result (48 bytes). The context is automatically + * reinitialized. + * + * @param cc the ECHO-384 context + * @param dst the destination buffer + */ +void sph_echo384_close(void *cc, void *dst); + +/** + * Add a few additional bits (0 to 7) to the current computation, then + * terminate it and output the result in the provided buffer, which must + * be wide enough to accomodate the result (48 bytes). If bit number i + * in ub has value 2^i, then the extra bits are those + * numbered 7 downto 8-n (this is the big-endian convention at the byte + * level). The context is automatically reinitialized. + * + * @param cc the ECHO-384 context + * @param ub the extra bits + * @param n the number of extra bits (0 to 7) + * @param dst the destination buffer + */ +void sph_echo384_addbits_and_close( + void *cc, unsigned ub, unsigned n, void *dst); + +/** + * Initialize an ECHO-512 context. This process performs no memory allocation. + * + * @param cc the ECHO-512 context (pointer to a + * sph_echo512_context) + */ +void sph_echo512_init(void *cc); + +/** + * Process some data bytes. It is acceptable that len is zero + * (in which case this function does nothing). + * + * @param cc the ECHO-512 context + * @param data the input data + * @param len the input data length (in bytes) + */ +void sph_echo512(void *cc, const void *data, size_t len); + +/** + * Terminate the current ECHO-512 computation and output the result into + * the provided buffer. The destination buffer must be wide enough to + * accomodate the result (64 bytes). The context is automatically + * reinitialized. + * + * @param cc the ECHO-512 context + * @param dst the destination buffer + */ +void sph_echo512_close(void *cc, void *dst); + +/** + * Add a few additional bits (0 to 7) to the current computation, then + * terminate it and output the result in the provided buffer, which must + * be wide enough to accomodate the result (64 bytes). If bit number i + * in ub has value 2^i, then the extra bits are those + * numbered 7 downto 8-n (this is the big-endian convention at the byte + * level). The context is automatically reinitialized. + * + * @param cc the ECHO-512 context + * @param ub the extra bits + * @param n the number of extra bits (0 to 7) + * @param dst the destination buffer + */ +void sph_echo512_addbits_and_close( + void *cc, unsigned ub, unsigned n, void *dst); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/sph_fugue.h b/src/sph_fugue.h new file mode 100644 index 0000000..c8ff395 --- /dev/null +++ b/src/sph_fugue.h @@ -0,0 +1,81 @@ +#ifndef SPH_FUGUE_H__ +#define SPH_FUGUE_H__ + +#include +#include "sph_types.h" + +#ifdef __cplusplus +extern "C"{ +#endif + +#define SPH_SIZE_fugue224 224 + +#define SPH_SIZE_fugue256 256 + +#define SPH_SIZE_fugue384 384 + +#define SPH_SIZE_fugue512 512 + +typedef struct { +#ifndef DOXYGEN_IGNORE + sph_u32 partial; + unsigned partial_len; + unsigned round_shift; + sph_u32 S[36]; +#if SPH_64 + sph_u64 bit_count; +#else + sph_u32 bit_count_high, bit_count_low; +#endif +#endif +} sph_fugue_context; + +typedef sph_fugue_context sph_fugue224_context; + +typedef sph_fugue_context sph_fugue256_context; + +typedef sph_fugue_context sph_fugue384_context; + +typedef sph_fugue_context sph_fugue512_context; + +void sph_fugue224_init(void *cc); + +void sph_fugue224(void *cc, const void *data, size_t len); + +void sph_fugue224_close(void *cc, void *dst); + +void sph_fugue224_addbits_and_close( + void *cc, unsigned ub, unsigned n, void *dst); + +void sph_fugue256_init(void *cc); + +void sph_fugue256(void *cc, const void *data, size_t len); + +void sph_fugue256_close(void *cc, void *dst); + +void sph_fugue256_addbits_and_close( + void *cc, unsigned ub, unsigned n, void *dst); + +void sph_fugue384_init(void *cc); + +void sph_fugue384(void *cc, const void *data, size_t len); + +void sph_fugue384_close(void *cc, void *dst); + +void sph_fugue384_addbits_and_close( + void *cc, unsigned ub, unsigned n, void *dst); + +void sph_fugue512_init(void *cc); + +void sph_fugue512(void *cc, const void *data, size_t len); + +void sph_fugue512_close(void *cc, void *dst); + +void sph_fugue512_addbits_and_close( + void *cc, unsigned ub, unsigned n, void *dst); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/sph_groestl.h b/src/sph_groestl.h new file mode 100644 index 0000000..495f05e --- /dev/null +++ b/src/sph_groestl.h @@ -0,0 +1,329 @@ +/* $Id: sph_groestl.h 216 2010-06-08 09:46:57Z tp $ */ +/** + * Groestl interface. This code implements Groestl with the recommended + * parameters for SHA-3, with outputs of 224, 256, 384 and 512 bits. + * + * ==========================(LICENSE BEGIN)============================ + * + * Copyright (c) 2007-2010 Projet RNRT SAPHIR + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * ===========================(LICENSE END)============================= + * + * @file sph_groestl.h + * @author Thomas Pornin + */ + +#ifndef SPH_GROESTL_H__ +#define SPH_GROESTL_H__ + +#ifdef __cplusplus +extern "C"{ +#endif + +#include +#include "sph_types.h" + +/** + * Output size (in bits) for Groestl-224. + */ +#define SPH_SIZE_groestl224 224 + +/** + * Output size (in bits) for Groestl-256. + */ +#define SPH_SIZE_groestl256 256 + +/** + * Output size (in bits) for Groestl-384. + */ +#define SPH_SIZE_groestl384 384 + +/** + * Output size (in bits) for Groestl-512. + */ +#define SPH_SIZE_groestl512 512 + +/** + * This structure is a context for Groestl-224 and Groestl-256 computations: + * it contains the intermediate values and some data from the last + * entered block. Once a Groestl computation has been performed, the + * context can be reused for another computation. + * + * The contents of this structure are private. A running Groestl + * computation can be cloned by copying the context (e.g. with a simple + * memcpy()). + */ +typedef struct { +#ifndef DOXYGEN_IGNORE + unsigned char buf[64]; /* first field, for alignment */ + size_t ptr; + union { +#if SPH_64 + sph_u64 wide[8]; +#endif + sph_u32 narrow[16]; + } state; +#if SPH_64 + sph_u64 count; +#else + sph_u32 count_high, count_low; +#endif +#endif +} sph_groestl_small_context; + +/** + * This structure is a context for Groestl-224 computations. It is + * identical to the common sph_groestl_small_context. + */ +typedef sph_groestl_small_context sph_groestl224_context; + +/** + * This structure is a context for Groestl-256 computations. It is + * identical to the common sph_groestl_small_context. + */ +typedef sph_groestl_small_context sph_groestl256_context; + +/** + * This structure is a context for Groestl-384 and Groestl-512 computations: + * it contains the intermediate values and some data from the last + * entered block. Once a Groestl computation has been performed, the + * context can be reused for another computation. + * + * The contents of this structure are private. A running Groestl + * computation can be cloned by copying the context (e.g. with a simple + * memcpy()). + */ +typedef struct { +#ifndef DOXYGEN_IGNORE + unsigned char buf[128]; /* first field, for alignment */ + size_t ptr; + union { +#if SPH_64 + sph_u64 wide[16]; +#endif + sph_u32 narrow[32]; + } state; +#if SPH_64 + sph_u64 count; +#else + sph_u32 count_high, count_low; +#endif +#endif +} sph_groestl_big_context; + +/** + * This structure is a context for Groestl-384 computations. It is + * identical to the common sph_groestl_small_context. + */ +typedef sph_groestl_big_context sph_groestl384_context; + +/** + * This structure is a context for Groestl-512 computations. It is + * identical to the common sph_groestl_small_context. + */ +typedef sph_groestl_big_context sph_groestl512_context; + +/** + * Initialize a Groestl-224 context. This process performs no memory allocation. + * + * @param cc the Groestl-224 context (pointer to a + * sph_groestl224_context) + */ +void sph_groestl224_init(void *cc); + +/** + * Process some data bytes. It is acceptable that len is zero + * (in which case this function does nothing). + * + * @param cc the Groestl-224 context + * @param data the input data + * @param len the input data length (in bytes) + */ +void sph_groestl224(void *cc, const void *data, size_t len); + +/** + * Terminate the current Groestl-224 computation and output the result into + * the provided buffer. The destination buffer must be wide enough to + * accomodate the result (28 bytes). The context is automatically + * reinitialized. + * + * @param cc the Groestl-224 context + * @param dst the destination buffer + */ +void sph_groestl224_close(void *cc, void *dst); + +/** + * Add a few additional bits (0 to 7) to the current computation, then + * terminate it and output the result in the provided buffer, which must + * be wide enough to accomodate the result (28 bytes). If bit number i + * in ub has value 2^i, then the extra bits are those + * numbered 7 downto 8-n (this is the big-endian convention at the byte + * level). The context is automatically reinitialized. + * + * @param cc the Groestl-224 context + * @param ub the extra bits + * @param n the number of extra bits (0 to 7) + * @param dst the destination buffer + */ +void sph_groestl224_addbits_and_close( + void *cc, unsigned ub, unsigned n, void *dst); + +/** + * Initialize a Groestl-256 context. This process performs no memory allocation. + * + * @param cc the Groestl-256 context (pointer to a + * sph_groestl256_context) + */ +void sph_groestl256_init(void *cc); + +/** + * Process some data bytes. It is acceptable that len is zero + * (in which case this function does nothing). + * + * @param cc the Groestl-256 context + * @param data the input data + * @param len the input data length (in bytes) + */ +void sph_groestl256(void *cc, const void *data, size_t len); + +/** + * Terminate the current Groestl-256 computation and output the result into + * the provided buffer. The destination buffer must be wide enough to + * accomodate the result (32 bytes). The context is automatically + * reinitialized. + * + * @param cc the Groestl-256 context + * @param dst the destination buffer + */ +void sph_groestl256_close(void *cc, void *dst); + +/** + * Add a few additional bits (0 to 7) to the current computation, then + * terminate it and output the result in the provided buffer, which must + * be wide enough to accomodate the result (32 bytes). If bit number i + * in ub has value 2^i, then the extra bits are those + * numbered 7 downto 8-n (this is the big-endian convention at the byte + * level). The context is automatically reinitialized. + * + * @param cc the Groestl-256 context + * @param ub the extra bits + * @param n the number of extra bits (0 to 7) + * @param dst the destination buffer + */ +void sph_groestl256_addbits_and_close( + void *cc, unsigned ub, unsigned n, void *dst); + +/** + * Initialize a Groestl-384 context. This process performs no memory allocation. + * + * @param cc the Groestl-384 context (pointer to a + * sph_groestl384_context) + */ +void sph_groestl384_init(void *cc); + +/** + * Process some data bytes. It is acceptable that len is zero + * (in which case this function does nothing). + * + * @param cc the Groestl-384 context + * @param data the input data + * @param len the input data length (in bytes) + */ +void sph_groestl384(void *cc, const void *data, size_t len); + +/** + * Terminate the current Groestl-384 computation and output the result into + * the provided buffer. The destination buffer must be wide enough to + * accomodate the result (48 bytes). The context is automatically + * reinitialized. + * + * @param cc the Groestl-384 context + * @param dst the destination buffer + */ +void sph_groestl384_close(void *cc, void *dst); + +/** + * Add a few additional bits (0 to 7) to the current computation, then + * terminate it and output the result in the provided buffer, which must + * be wide enough to accomodate the result (48 bytes). If bit number i + * in ub has value 2^i, then the extra bits are those + * numbered 7 downto 8-n (this is the big-endian convention at the byte + * level). The context is automatically reinitialized. + * + * @param cc the Groestl-384 context + * @param ub the extra bits + * @param n the number of extra bits (0 to 7) + * @param dst the destination buffer + */ +void sph_groestl384_addbits_and_close( + void *cc, unsigned ub, unsigned n, void *dst); + +/** + * Initialize a Groestl-512 context. This process performs no memory allocation. + * + * @param cc the Groestl-512 context (pointer to a + * sph_groestl512_context) + */ +void sph_groestl512_init(void *cc); + +/** + * Process some data bytes. It is acceptable that len is zero + * (in which case this function does nothing). + * + * @param cc the Groestl-512 context + * @param data the input data + * @param len the input data length (in bytes) + */ +void sph_groestl512(void *cc, const void *data, size_t len); + +/** + * Terminate the current Groestl-512 computation and output the result into + * the provided buffer. The destination buffer must be wide enough to + * accomodate the result (64 bytes). The context is automatically + * reinitialized. + * + * @param cc the Groestl-512 context + * @param dst the destination buffer + */ +void sph_groestl512_close(void *cc, void *dst); + +/** + * Add a few additional bits (0 to 7) to the current computation, then + * terminate it and output the result in the provided buffer, which must + * be wide enough to accomodate the result (64 bytes). If bit number i + * in ub has value 2^i, then the extra bits are those + * numbered 7 downto 8-n (this is the big-endian convention at the byte + * level). The context is automatically reinitialized. + * + * @param cc the Groestl-512 context + * @param ub the extra bits + * @param n the number of extra bits (0 to 7) + * @param dst the destination buffer + */ +void sph_groestl512_addbits_and_close( + void *cc, unsigned ub, unsigned n, void *dst); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/sph_hamsi.h b/src/sph_hamsi.h new file mode 100644 index 0000000..f44d2d4 --- /dev/null +++ b/src/sph_hamsi.h @@ -0,0 +1,321 @@ +/* $Id: sph_hamsi.h 216 2010-06-08 09:46:57Z tp $ */ +/** + * Hamsi interface. This code implements Hamsi with the recommended + * parameters for SHA-3, with outputs of 224, 256, 384 and 512 bits. + * + * ==========================(LICENSE BEGIN)============================ + * + * Copyright (c) 2007-2010 Projet RNRT SAPHIR + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * ===========================(LICENSE END)============================= + * + * @file sph_hamsi.h + * @author Thomas Pornin + */ + +#ifndef SPH_HAMSI_H__ +#define SPH_HAMSI_H__ + +#include +#include "sph_types.h" + +#ifdef __cplusplus +extern "C"{ +#endif + +/** + * Output size (in bits) for Hamsi-224. + */ +#define SPH_SIZE_hamsi224 224 + +/** + * Output size (in bits) for Hamsi-256. + */ +#define SPH_SIZE_hamsi256 256 + +/** + * Output size (in bits) for Hamsi-384. + */ +#define SPH_SIZE_hamsi384 384 + +/** + * Output size (in bits) for Hamsi-512. + */ +#define SPH_SIZE_hamsi512 512 + +/** + * This structure is a context for Hamsi-224 and Hamsi-256 computations: + * it contains the intermediate values and some data from the last + * entered block. Once a Hamsi computation has been performed, the + * context can be reused for another computation. + * + * The contents of this structure are private. A running Hamsi + * computation can be cloned by copying the context (e.g. with a simple + * memcpy()). + */ +typedef struct { +#ifndef DOXYGEN_IGNORE + unsigned char partial[4]; + size_t partial_len; + sph_u32 h[8]; +#if SPH_64 + sph_u64 count; +#else + sph_u32 count_high, count_low; +#endif +#endif +} sph_hamsi_small_context; + +/** + * This structure is a context for Hamsi-224 computations. It is + * identical to the common sph_hamsi_small_context. + */ +typedef sph_hamsi_small_context sph_hamsi224_context; + +/** + * This structure is a context for Hamsi-256 computations. It is + * identical to the common sph_hamsi_small_context. + */ +typedef sph_hamsi_small_context sph_hamsi256_context; + +/** + * This structure is a context for Hamsi-384 and Hamsi-512 computations: + * it contains the intermediate values and some data from the last + * entered block. Once a Hamsi computation has been performed, the + * context can be reused for another computation. + * + * The contents of this structure are private. A running Hamsi + * computation can be cloned by copying the context (e.g. with a simple + * memcpy()). + */ +typedef struct { +#ifndef DOXYGEN_IGNORE + unsigned char partial[8]; + size_t partial_len; + sph_u32 h[16]; +#if SPH_64 + sph_u64 count; +#else + sph_u32 count_high, count_low; +#endif +#endif +} sph_hamsi_big_context; + +/** + * This structure is a context for Hamsi-384 computations. It is + * identical to the common sph_hamsi_small_context. + */ +typedef sph_hamsi_big_context sph_hamsi384_context; + +/** + * This structure is a context for Hamsi-512 computations. It is + * identical to the common sph_hamsi_small_context. + */ +typedef sph_hamsi_big_context sph_hamsi512_context; + +/** + * Initialize a Hamsi-224 context. This process performs no memory allocation. + * + * @param cc the Hamsi-224 context (pointer to a + * sph_hamsi224_context) + */ +void sph_hamsi224_init(void *cc); + +/** + * Process some data bytes. It is acceptable that len is zero + * (in which case this function does nothing). + * + * @param cc the Hamsi-224 context + * @param data the input data + * @param len the input data length (in bytes) + */ +void sph_hamsi224(void *cc, const void *data, size_t len); + +/** + * Terminate the current Hamsi-224 computation and output the result into + * the provided buffer. The destination buffer must be wide enough to + * accomodate the result (28 bytes). The context is automatically + * reinitialized. + * + * @param cc the Hamsi-224 context + * @param dst the destination buffer + */ +void sph_hamsi224_close(void *cc, void *dst); + +/** + * Add a few additional bits (0 to 7) to the current computation, then + * terminate it and output the result in the provided buffer, which must + * be wide enough to accomodate the result (28 bytes). If bit number i + * in ub has value 2^i, then the extra bits are those + * numbered 7 downto 8-n (this is the big-endian convention at the byte + * level). The context is automatically reinitialized. + * + * @param cc the Hamsi-224 context + * @param ub the extra bits + * @param n the number of extra bits (0 to 7) + * @param dst the destination buffer + */ +void sph_hamsi224_addbits_and_close( + void *cc, unsigned ub, unsigned n, void *dst); + +/** + * Initialize a Hamsi-256 context. This process performs no memory allocation. + * + * @param cc the Hamsi-256 context (pointer to a + * sph_hamsi256_context) + */ +void sph_hamsi256_init(void *cc); + +/** + * Process some data bytes. It is acceptable that len is zero + * (in which case this function does nothing). + * + * @param cc the Hamsi-256 context + * @param data the input data + * @param len the input data length (in bytes) + */ +void sph_hamsi256(void *cc, const void *data, size_t len); + +/** + * Terminate the current Hamsi-256 computation and output the result into + * the provided buffer. The destination buffer must be wide enough to + * accomodate the result (32 bytes). The context is automatically + * reinitialized. + * + * @param cc the Hamsi-256 context + * @param dst the destination buffer + */ +void sph_hamsi256_close(void *cc, void *dst); + +/** + * Add a few additional bits (0 to 7) to the current computation, then + * terminate it and output the result in the provided buffer, which must + * be wide enough to accomodate the result (32 bytes). If bit number i + * in ub has value 2^i, then the extra bits are those + * numbered 7 downto 8-n (this is the big-endian convention at the byte + * level). The context is automatically reinitialized. + * + * @param cc the Hamsi-256 context + * @param ub the extra bits + * @param n the number of extra bits (0 to 7) + * @param dst the destination buffer + */ +void sph_hamsi256_addbits_and_close( + void *cc, unsigned ub, unsigned n, void *dst); + +/** + * Initialize a Hamsi-384 context. This process performs no memory allocation. + * + * @param cc the Hamsi-384 context (pointer to a + * sph_hamsi384_context) + */ +void sph_hamsi384_init(void *cc); + +/** + * Process some data bytes. It is acceptable that len is zero + * (in which case this function does nothing). + * + * @param cc the Hamsi-384 context + * @param data the input data + * @param len the input data length (in bytes) + */ +void sph_hamsi384(void *cc, const void *data, size_t len); + +/** + * Terminate the current Hamsi-384 computation and output the result into + * the provided buffer. The destination buffer must be wide enough to + * accomodate the result (48 bytes). The context is automatically + * reinitialized. + * + * @param cc the Hamsi-384 context + * @param dst the destination buffer + */ +void sph_hamsi384_close(void *cc, void *dst); + +/** + * Add a few additional bits (0 to 7) to the current computation, then + * terminate it and output the result in the provided buffer, which must + * be wide enough to accomodate the result (48 bytes). If bit number i + * in ub has value 2^i, then the extra bits are those + * numbered 7 downto 8-n (this is the big-endian convention at the byte + * level). The context is automatically reinitialized. + * + * @param cc the Hamsi-384 context + * @param ub the extra bits + * @param n the number of extra bits (0 to 7) + * @param dst the destination buffer + */ +void sph_hamsi384_addbits_and_close( + void *cc, unsigned ub, unsigned n, void *dst); + +/** + * Initialize a Hamsi-512 context. This process performs no memory allocation. + * + * @param cc the Hamsi-512 context (pointer to a + * sph_hamsi512_context) + */ +void sph_hamsi512_init(void *cc); + +/** + * Process some data bytes. It is acceptable that len is zero + * (in which case this function does nothing). + * + * @param cc the Hamsi-512 context + * @param data the input data + * @param len the input data length (in bytes) + */ +void sph_hamsi512(void *cc, const void *data, size_t len); + +/** + * Terminate the current Hamsi-512 computation and output the result into + * the provided buffer. The destination buffer must be wide enough to + * accomodate the result (64 bytes). The context is automatically + * reinitialized. + * + * @param cc the Hamsi-512 context + * @param dst the destination buffer + */ +void sph_hamsi512_close(void *cc, void *dst); + +/** + * Add a few additional bits (0 to 7) to the current computation, then + * terminate it and output the result in the provided buffer, which must + * be wide enough to accomodate the result (64 bytes). If bit number i + * in ub has value 2^i, then the extra bits are those + * numbered 7 downto 8-n (this is the big-endian convention at the byte + * level). The context is automatically reinitialized. + * + * @param cc the Hamsi-512 context + * @param ub the extra bits + * @param n the number of extra bits (0 to 7) + * @param dst the destination buffer + */ +void sph_hamsi512_addbits_and_close( + void *cc, unsigned ub, unsigned n, void *dst); + + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/sph_jh.h b/src/sph_jh.h new file mode 100644 index 0000000..82fae58 --- /dev/null +++ b/src/sph_jh.h @@ -0,0 +1,298 @@ +/* $Id: sph_jh.h 216 2010-06-08 09:46:57Z tp $ */ +/** + * JH interface. JH is a family of functions which differ by + * their output size; this implementation defines JH for output + * sizes 224, 256, 384 and 512 bits. + * + * ==========================(LICENSE BEGIN)============================ + * + * Copyright (c) 2007-2010 Projet RNRT SAPHIR + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * ===========================(LICENSE END)============================= + * + * @file sph_jh.h + * @author Thomas Pornin + */ + +#ifndef SPH_JH_H__ +#define SPH_JH_H__ + +#ifdef __cplusplus +extern "C"{ +#endif + +#include +#include "sph_types.h" + +/** + * Output size (in bits) for JH-224. + */ +#define SPH_SIZE_jh224 224 + +/** + * Output size (in bits) for JH-256. + */ +#define SPH_SIZE_jh256 256 + +/** + * Output size (in bits) for JH-384. + */ +#define SPH_SIZE_jh384 384 + +/** + * Output size (in bits) for JH-512. + */ +#define SPH_SIZE_jh512 512 + +/** + * This structure is a context for JH computations: it contains the + * intermediate values and some data from the last entered block. Once + * a JH computation has been performed, the context can be reused for + * another computation. + * + * The contents of this structure are private. A running JH computation + * can be cloned by copying the context (e.g. with a simple + * memcpy()). + */ +typedef struct { +#ifndef DOXYGEN_IGNORE + unsigned char buf[64]; /* first field, for alignment */ + size_t ptr; + union { +#if SPH_64 + sph_u64 wide[16]; +#endif + sph_u32 narrow[32]; + } H; +#if SPH_64 + sph_u64 block_count; +#else + sph_u32 block_count_high, block_count_low; +#endif +#endif +} sph_jh_context; + +/** + * Type for a JH-224 context (identical to the common context). + */ +typedef sph_jh_context sph_jh224_context; + +/** + * Type for a JH-256 context (identical to the common context). + */ +typedef sph_jh_context sph_jh256_context; + +/** + * Type for a JH-384 context (identical to the common context). + */ +typedef sph_jh_context sph_jh384_context; + +/** + * Type for a JH-512 context (identical to the common context). + */ +typedef sph_jh_context sph_jh512_context; + +/** + * Initialize a JH-224 context. This process performs no memory allocation. + * + * @param cc the JH-224 context (pointer to a + * sph_jh224_context) + */ +void sph_jh224_init(void *cc); + +/** + * Process some data bytes. It is acceptable that len is zero + * (in which case this function does nothing). + * + * @param cc the JH-224 context + * @param data the input data + * @param len the input data length (in bytes) + */ +void sph_jh224(void *cc, const void *data, size_t len); + +/** + * Terminate the current JH-224 computation and output the result into + * the provided buffer. The destination buffer must be wide enough to + * accomodate the result (28 bytes). The context is automatically + * reinitialized. + * + * @param cc the JH-224 context + * @param dst the destination buffer + */ +void sph_jh224_close(void *cc, void *dst); + +/** + * Add a few additional bits (0 to 7) to the current computation, then + * terminate it and output the result in the provided buffer, which must + * be wide enough to accomodate the result (28 bytes). If bit number i + * in ub has value 2^i, then the extra bits are those + * numbered 7 downto 8-n (this is the big-endian convention at the byte + * level). The context is automatically reinitialized. + * + * @param cc the JH-224 context + * @param ub the extra bits + * @param n the number of extra bits (0 to 7) + * @param dst the destination buffer + */ +void sph_jh224_addbits_and_close( + void *cc, unsigned ub, unsigned n, void *dst); + +/** + * Initialize a JH-256 context. This process performs no memory allocation. + * + * @param cc the JH-256 context (pointer to a + * sph_jh256_context) + */ +void sph_jh256_init(void *cc); + +/** + * Process some data bytes. It is acceptable that len is zero + * (in which case this function does nothing). + * + * @param cc the JH-256 context + * @param data the input data + * @param len the input data length (in bytes) + */ +void sph_jh256(void *cc, const void *data, size_t len); + +/** + * Terminate the current JH-256 computation and output the result into + * the provided buffer. The destination buffer must be wide enough to + * accomodate the result (32 bytes). The context is automatically + * reinitialized. + * + * @param cc the JH-256 context + * @param dst the destination buffer + */ +void sph_jh256_close(void *cc, void *dst); + +/** + * Add a few additional bits (0 to 7) to the current computation, then + * terminate it and output the result in the provided buffer, which must + * be wide enough to accomodate the result (32 bytes). If bit number i + * in ub has value 2^i, then the extra bits are those + * numbered 7 downto 8-n (this is the big-endian convention at the byte + * level). The context is automatically reinitialized. + * + * @param cc the JH-256 context + * @param ub the extra bits + * @param n the number of extra bits (0 to 7) + * @param dst the destination buffer + */ +void sph_jh256_addbits_and_close( + void *cc, unsigned ub, unsigned n, void *dst); + +/** + * Initialize a JH-384 context. This process performs no memory allocation. + * + * @param cc the JH-384 context (pointer to a + * sph_jh384_context) + */ +void sph_jh384_init(void *cc); + +/** + * Process some data bytes. It is acceptable that len is zero + * (in which case this function does nothing). + * + * @param cc the JH-384 context + * @param data the input data + * @param len the input data length (in bytes) + */ +void sph_jh384(void *cc, const void *data, size_t len); + +/** + * Terminate the current JH-384 computation and output the result into + * the provided buffer. The destination buffer must be wide enough to + * accomodate the result (48 bytes). The context is automatically + * reinitialized. + * + * @param cc the JH-384 context + * @param dst the destination buffer + */ +void sph_jh384_close(void *cc, void *dst); + +/** + * Add a few additional bits (0 to 7) to the current computation, then + * terminate it and output the result in the provided buffer, which must + * be wide enough to accomodate the result (48 bytes). If bit number i + * in ub has value 2^i, then the extra bits are those + * numbered 7 downto 8-n (this is the big-endian convention at the byte + * level). The context is automatically reinitialized. + * + * @param cc the JH-384 context + * @param ub the extra bits + * @param n the number of extra bits (0 to 7) + * @param dst the destination buffer + */ +void sph_jh384_addbits_and_close( + void *cc, unsigned ub, unsigned n, void *dst); + +/** + * Initialize a JH-512 context. This process performs no memory allocation. + * + * @param cc the JH-512 context (pointer to a + * sph_jh512_context) + */ +void sph_jh512_init(void *cc); + +/** + * Process some data bytes. It is acceptable that len is zero + * (in which case this function does nothing). + * + * @param cc the JH-512 context + * @param data the input data + * @param len the input data length (in bytes) + */ +void sph_jh512(void *cc, const void *data, size_t len); + +/** + * Terminate the current JH-512 computation and output the result into + * the provided buffer. The destination buffer must be wide enough to + * accomodate the result (64 bytes). The context is automatically + * reinitialized. + * + * @param cc the JH-512 context + * @param dst the destination buffer + */ +void sph_jh512_close(void *cc, void *dst); + +/** + * Add a few additional bits (0 to 7) to the current computation, then + * terminate it and output the result in the provided buffer, which must + * be wide enough to accomodate the result (64 bytes). If bit number i + * in ub has value 2^i, then the extra bits are those + * numbered 7 downto 8-n (this is the big-endian convention at the byte + * level). The context is automatically reinitialized. + * + * @param cc the JH-512 context + * @param ub the extra bits + * @param n the number of extra bits (0 to 7) + * @param dst the destination buffer + */ +void sph_jh512_addbits_and_close( + void *cc, unsigned ub, unsigned n, void *dst); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/sph_keccak.h b/src/sph_keccak.h new file mode 100644 index 0000000..bdafdb8 --- /dev/null +++ b/src/sph_keccak.h @@ -0,0 +1,293 @@ +/* $Id: sph_keccak.h 216 2010-06-08 09:46:57Z tp $ */ +/** + * Keccak interface. This is the interface for Keccak with the + * recommended parameters for SHA-3, with output lengths 224, 256, + * 384 and 512 bits. + * + * ==========================(LICENSE BEGIN)============================ + * + * Copyright (c) 2007-2010 Projet RNRT SAPHIR + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * ===========================(LICENSE END)============================= + * + * @file sph_keccak.h + * @author Thomas Pornin + */ + +#ifndef SPH_KECCAK_H__ +#define SPH_KECCAK_H__ + +#ifdef __cplusplus +extern "C"{ +#endif + +#include +#include "sph_types.h" + +/** + * Output size (in bits) for Keccak-224. + */ +#define SPH_SIZE_keccak224 224 + +/** + * Output size (in bits) for Keccak-256. + */ +#define SPH_SIZE_keccak256 256 + +/** + * Output size (in bits) for Keccak-384. + */ +#define SPH_SIZE_keccak384 384 + +/** + * Output size (in bits) for Keccak-512. + */ +#define SPH_SIZE_keccak512 512 + +/** + * This structure is a context for Keccak computations: it contains the + * intermediate values and some data from the last entered block. Once a + * Keccak computation has been performed, the context can be reused for + * another computation. + * + * The contents of this structure are private. A running Keccak computation + * can be cloned by copying the context (e.g. with a simple + * memcpy()). + */ +typedef struct { +#ifndef DOXYGEN_IGNORE + unsigned char buf[144]; /* first field, for alignment */ + size_t ptr, lim; + union { +#if SPH_64 + sph_u64 wide[25]; +#endif + sph_u32 narrow[50]; + } u; +#endif +} sph_keccak_context; + +/** + * Type for a Keccak-224 context (identical to the common context). + */ +typedef sph_keccak_context sph_keccak224_context; + +/** + * Type for a Keccak-256 context (identical to the common context). + */ +typedef sph_keccak_context sph_keccak256_context; + +/** + * Type for a Keccak-384 context (identical to the common context). + */ +typedef sph_keccak_context sph_keccak384_context; + +/** + * Type for a Keccak-512 context (identical to the common context). + */ +typedef sph_keccak_context sph_keccak512_context; + +/** + * Initialize a Keccak-224 context. This process performs no memory allocation. + * + * @param cc the Keccak-224 context (pointer to a + * sph_keccak224_context) + */ +void sph_keccak224_init(void *cc); + +/** + * Process some data bytes. It is acceptable that len is zero + * (in which case this function does nothing). + * + * @param cc the Keccak-224 context + * @param data the input data + * @param len the input data length (in bytes) + */ +void sph_keccak224(void *cc, const void *data, size_t len); + +/** + * Terminate the current Keccak-224 computation and output the result into + * the provided buffer. The destination buffer must be wide enough to + * accomodate the result (28 bytes). The context is automatically + * reinitialized. + * + * @param cc the Keccak-224 context + * @param dst the destination buffer + */ +void sph_keccak224_close(void *cc, void *dst); + +/** + * Add a few additional bits (0 to 7) to the current computation, then + * terminate it and output the result in the provided buffer, which must + * be wide enough to accomodate the result (28 bytes). If bit number i + * in ub has value 2^i, then the extra bits are those + * numbered 7 downto 8-n (this is the big-endian convention at the byte + * level). The context is automatically reinitialized. + * + * @param cc the Keccak-224 context + * @param ub the extra bits + * @param n the number of extra bits (0 to 7) + * @param dst the destination buffer + */ +void sph_keccak224_addbits_and_close( + void *cc, unsigned ub, unsigned n, void *dst); + +/** + * Initialize a Keccak-256 context. This process performs no memory allocation. + * + * @param cc the Keccak-256 context (pointer to a + * sph_keccak256_context) + */ +void sph_keccak256_init(void *cc); + +/** + * Process some data bytes. It is acceptable that len is zero + * (in which case this function does nothing). + * + * @param cc the Keccak-256 context + * @param data the input data + * @param len the input data length (in bytes) + */ +void sph_keccak256(void *cc, const void *data, size_t len); + +/** + * Terminate the current Keccak-256 computation and output the result into + * the provided buffer. The destination buffer must be wide enough to + * accomodate the result (32 bytes). The context is automatically + * reinitialized. + * + * @param cc the Keccak-256 context + * @param dst the destination buffer + */ +void sph_keccak256_close(void *cc, void *dst); + +/** + * Add a few additional bits (0 to 7) to the current computation, then + * terminate it and output the result in the provided buffer, which must + * be wide enough to accomodate the result (32 bytes). If bit number i + * in ub has value 2^i, then the extra bits are those + * numbered 7 downto 8-n (this is the big-endian convention at the byte + * level). The context is automatically reinitialized. + * + * @param cc the Keccak-256 context + * @param ub the extra bits + * @param n the number of extra bits (0 to 7) + * @param dst the destination buffer + */ +void sph_keccak256_addbits_and_close( + void *cc, unsigned ub, unsigned n, void *dst); + +/** + * Initialize a Keccak-384 context. This process performs no memory allocation. + * + * @param cc the Keccak-384 context (pointer to a + * sph_keccak384_context) + */ +void sph_keccak384_init(void *cc); + +/** + * Process some data bytes. It is acceptable that len is zero + * (in which case this function does nothing). + * + * @param cc the Keccak-384 context + * @param data the input data + * @param len the input data length (in bytes) + */ +void sph_keccak384(void *cc, const void *data, size_t len); + +/** + * Terminate the current Keccak-384 computation and output the result into + * the provided buffer. The destination buffer must be wide enough to + * accomodate the result (48 bytes). The context is automatically + * reinitialized. + * + * @param cc the Keccak-384 context + * @param dst the destination buffer + */ +void sph_keccak384_close(void *cc, void *dst); + +/** + * Add a few additional bits (0 to 7) to the current computation, then + * terminate it and output the result in the provided buffer, which must + * be wide enough to accomodate the result (48 bytes). If bit number i + * in ub has value 2^i, then the extra bits are those + * numbered 7 downto 8-n (this is the big-endian convention at the byte + * level). The context is automatically reinitialized. + * + * @param cc the Keccak-384 context + * @param ub the extra bits + * @param n the number of extra bits (0 to 7) + * @param dst the destination buffer + */ +void sph_keccak384_addbits_and_close( + void *cc, unsigned ub, unsigned n, void *dst); + +/** + * Initialize a Keccak-512 context. This process performs no memory allocation. + * + * @param cc the Keccak-512 context (pointer to a + * sph_keccak512_context) + */ +void sph_keccak512_init(void *cc); + +/** + * Process some data bytes. It is acceptable that len is zero + * (in which case this function does nothing). + * + * @param cc the Keccak-512 context + * @param data the input data + * @param len the input data length (in bytes) + */ +void sph_keccak512(void *cc, const void *data, size_t len); + +/** + * Terminate the current Keccak-512 computation and output the result into + * the provided buffer. The destination buffer must be wide enough to + * accomodate the result (64 bytes). The context is automatically + * reinitialized. + * + * @param cc the Keccak-512 context + * @param dst the destination buffer + */ +void sph_keccak512_close(void *cc, void *dst); + +/** + * Add a few additional bits (0 to 7) to the current computation, then + * terminate it and output the result in the provided buffer, which must + * be wide enough to accomodate the result (64 bytes). If bit number i + * in ub has value 2^i, then the extra bits are those + * numbered 7 downto 8-n (this is the big-endian convention at the byte + * level). The context is automatically reinitialized. + * + * @param cc the Keccak-512 context + * @param ub the extra bits + * @param n the number of extra bits (0 to 7) + * @param dst the destination buffer + */ +void sph_keccak512_addbits_and_close( + void *cc, unsigned ub, unsigned n, void *dst); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/sph_luffa.h b/src/sph_luffa.h new file mode 100644 index 0000000..a32fd7b --- /dev/null +++ b/src/sph_luffa.h @@ -0,0 +1,296 @@ +/* $Id: sph_luffa.h 154 2010-04-26 17:00:24Z tp $ */ +/** + * Luffa interface. Luffa is a family of functions which differ by + * their output size; this implementation defines Luffa for output + * sizes 224, 256, 384 and 512 bits. + * + * ==========================(LICENSE BEGIN)============================ + * + * Copyright (c) 2007-2010 Projet RNRT SAPHIR + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * ===========================(LICENSE END)============================= + * + * @file sph_luffa.h + * @author Thomas Pornin + */ + +#ifndef SPH_LUFFA_H__ +#define SPH_LUFFA_H__ + +#ifdef __cplusplus +extern "C"{ +#endif + +#include +#include "sph_types.h" + +/** + * Output size (in bits) for Luffa-224. + */ +#define SPH_SIZE_luffa224 224 + +/** + * Output size (in bits) for Luffa-256. + */ +#define SPH_SIZE_luffa256 256 + +/** + * Output size (in bits) for Luffa-384. + */ +#define SPH_SIZE_luffa384 384 + +/** + * Output size (in bits) for Luffa-512. + */ +#define SPH_SIZE_luffa512 512 + +/** + * This structure is a context for Luffa-224 computations: it contains + * the intermediate values and some data from the last entered block. + * Once a Luffa computation has been performed, the context can be + * reused for another computation. + * + * The contents of this structure are private. A running Luffa + * computation can be cloned by copying the context (e.g. with a simple + * memcpy()). + */ +typedef struct { +#ifndef DOXYGEN_IGNORE + unsigned char buf[32]; /* first field, for alignment */ + size_t ptr; + sph_u32 V[3][8]; +#endif +} sph_luffa224_context; + +/** + * This structure is a context for Luffa-256 computations. It is + * identical to sph_luffa224_context. + */ +typedef sph_luffa224_context sph_luffa256_context; + +/** + * This structure is a context for Luffa-384 computations. + */ +typedef struct { +#ifndef DOXYGEN_IGNORE + unsigned char buf[32]; /* first field, for alignment */ + size_t ptr; + sph_u32 V[4][8]; +#endif +} sph_luffa384_context; + +/** + * This structure is a context for Luffa-512 computations. + */ +typedef struct { +#ifndef DOXYGEN_IGNORE + unsigned char buf[32]; /* first field, for alignment */ + size_t ptr; + sph_u32 V[5][8]; +#endif +} sph_luffa512_context; + +/** + * Initialize a Luffa-224 context. This process performs no memory allocation. + * + * @param cc the Luffa-224 context (pointer to a + * sph_luffa224_context) + */ +void sph_luffa224_init(void *cc); + +/** + * Process some data bytes. It is acceptable that len is zero + * (in which case this function does nothing). + * + * @param cc the Luffa-224 context + * @param data the input data + * @param len the input data length (in bytes) + */ +void sph_luffa224(void *cc, const void *data, size_t len); + +/** + * Terminate the current Luffa-224 computation and output the result into + * the provided buffer. The destination buffer must be wide enough to + * accomodate the result (28 bytes). The context is automatically + * reinitialized. + * + * @param cc the Luffa-224 context + * @param dst the destination buffer + */ +void sph_luffa224_close(void *cc, void *dst); + +/** + * Add a few additional bits (0 to 7) to the current computation, then + * terminate it and output the result in the provided buffer, which must + * be wide enough to accomodate the result (28 bytes). If bit number i + * in ub has value 2^i, then the extra bits are those + * numbered 7 downto 8-n (this is the big-endian convention at the byte + * level). The context is automatically reinitialized. + * + * @param cc the Luffa-224 context + * @param ub the extra bits + * @param n the number of extra bits (0 to 7) + * @param dst the destination buffer + */ +void sph_luffa224_addbits_and_close( + void *cc, unsigned ub, unsigned n, void *dst); + +/** + * Initialize a Luffa-256 context. This process performs no memory allocation. + * + * @param cc the Luffa-256 context (pointer to a + * sph_luffa256_context) + */ +void sph_luffa256_init(void *cc); + +/** + * Process some data bytes. It is acceptable that len is zero + * (in which case this function does nothing). + * + * @param cc the Luffa-256 context + * @param data the input data + * @param len the input data length (in bytes) + */ +void sph_luffa256(void *cc, const void *data, size_t len); + +/** + * Terminate the current Luffa-256 computation and output the result into + * the provided buffer. The destination buffer must be wide enough to + * accomodate the result (32 bytes). The context is automatically + * reinitialized. + * + * @param cc the Luffa-256 context + * @param dst the destination buffer + */ +void sph_luffa256_close(void *cc, void *dst); + +/** + * Add a few additional bits (0 to 7) to the current computation, then + * terminate it and output the result in the provided buffer, which must + * be wide enough to accomodate the result (32 bytes). If bit number i + * in ub has value 2^i, then the extra bits are those + * numbered 7 downto 8-n (this is the big-endian convention at the byte + * level). The context is automatically reinitialized. + * + * @param cc the Luffa-256 context + * @param ub the extra bits + * @param n the number of extra bits (0 to 7) + * @param dst the destination buffer + */ +void sph_luffa256_addbits_and_close( + void *cc, unsigned ub, unsigned n, void *dst); + +/** + * Initialize a Luffa-384 context. This process performs no memory allocation. + * + * @param cc the Luffa-384 context (pointer to a + * sph_luffa384_context) + */ +void sph_luffa384_init(void *cc); + +/** + * Process some data bytes. It is acceptable that len is zero + * (in which case this function does nothing). + * + * @param cc the Luffa-384 context + * @param data the input data + * @param len the input data length (in bytes) + */ +void sph_luffa384(void *cc, const void *data, size_t len); + +/** + * Terminate the current Luffa-384 computation and output the result into + * the provided buffer. The destination buffer must be wide enough to + * accomodate the result (48 bytes). The context is automatically + * reinitialized. + * + * @param cc the Luffa-384 context + * @param dst the destination buffer + */ +void sph_luffa384_close(void *cc, void *dst); + +/** + * Add a few additional bits (0 to 7) to the current computation, then + * terminate it and output the result in the provided buffer, which must + * be wide enough to accomodate the result (48 bytes). If bit number i + * in ub has value 2^i, then the extra bits are those + * numbered 7 downto 8-n (this is the big-endian convention at the byte + * level). The context is automatically reinitialized. + * + * @param cc the Luffa-384 context + * @param ub the extra bits + * @param n the number of extra bits (0 to 7) + * @param dst the destination buffer + */ +void sph_luffa384_addbits_and_close( + void *cc, unsigned ub, unsigned n, void *dst); + +/** + * Initialize a Luffa-512 context. This process performs no memory allocation. + * + * @param cc the Luffa-512 context (pointer to a + * sph_luffa512_context) + */ +void sph_luffa512_init(void *cc); + +/** + * Process some data bytes. It is acceptable that len is zero + * (in which case this function does nothing). + * + * @param cc the Luffa-512 context + * @param data the input data + * @param len the input data length (in bytes) + */ +void sph_luffa512(void *cc, const void *data, size_t len); + +/** + * Terminate the current Luffa-512 computation and output the result into + * the provided buffer. The destination buffer must be wide enough to + * accomodate the result (64 bytes). The context is automatically + * reinitialized. + * + * @param cc the Luffa-512 context + * @param dst the destination buffer + */ +void sph_luffa512_close(void *cc, void *dst); + +/** + * Add a few additional bits (0 to 7) to the current computation, then + * terminate it and output the result in the provided buffer, which must + * be wide enough to accomodate the result (64 bytes). If bit number i + * in ub has value 2^i, then the extra bits are those + * numbered 7 downto 8-n (this is the big-endian convention at the byte + * level). The context is automatically reinitialized. + * + * @param cc the Luffa-512 context + * @param ub the extra bits + * @param n the number of extra bits (0 to 7) + * @param dst the destination buffer + */ +void sph_luffa512_addbits_and_close( + void *cc, unsigned ub, unsigned n, void *dst); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/sph_shavite.h b/src/sph_shavite.h new file mode 100644 index 0000000..0957e42 --- /dev/null +++ b/src/sph_shavite.h @@ -0,0 +1,314 @@ +/* $Id: sph_shavite.h 208 2010-06-02 20:33:00Z tp $ */ +/** + * SHAvite-3 interface. This code implements SHAvite-3 with the + * recommended parameters for SHA-3, with outputs of 224, 256, 384 and + * 512 bits. In the following, we call the function "SHAvite" (without + * the "-3" suffix), thus "SHAvite-224" is "SHAvite-3 with a 224-bit + * output". + * + * ==========================(LICENSE BEGIN)============================ + * + * Copyright (c) 2007-2010 Projet RNRT SAPHIR + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * ===========================(LICENSE END)============================= + * + * @file sph_shavite.h + * @author Thomas Pornin + */ + +#ifndef SPH_SHAVITE_H__ +#define SPH_SHAVITE_H__ + +#include +#include "sph_types.h" + +#ifdef __cplusplus +extern "C"{ +#endif + +/** + * Output size (in bits) for SHAvite-224. + */ +#define SPH_SIZE_shavite224 224 + +/** + * Output size (in bits) for SHAvite-256. + */ +#define SPH_SIZE_shavite256 256 + +/** + * Output size (in bits) for SHAvite-384. + */ +#define SPH_SIZE_shavite384 384 + +/** + * Output size (in bits) for SHAvite-512. + */ +#define SPH_SIZE_shavite512 512 + +/** + * This structure is a context for SHAvite-224 and SHAvite-256 computations: + * it contains the intermediate values and some data from the last + * entered block. Once a SHAvite computation has been performed, the + * context can be reused for another computation. + * + * The contents of this structure are private. A running SHAvite + * computation can be cloned by copying the context (e.g. with a simple + * memcpy()). + */ +typedef struct { +#ifndef DOXYGEN_IGNORE + unsigned char buf[64]; /* first field, for alignment */ + size_t ptr; + sph_u32 h[8]; + sph_u32 count0, count1; +#endif +} sph_shavite_small_context; + +/** + * This structure is a context for SHAvite-224 computations. It is + * identical to the common sph_shavite_small_context. + */ +typedef sph_shavite_small_context sph_shavite224_context; + +/** + * This structure is a context for SHAvite-256 computations. It is + * identical to the common sph_shavite_small_context. + */ +typedef sph_shavite_small_context sph_shavite256_context; + +/** + * This structure is a context for SHAvite-384 and SHAvite-512 computations: + * it contains the intermediate values and some data from the last + * entered block. Once a SHAvite computation has been performed, the + * context can be reused for another computation. + * + * The contents of this structure are private. A running SHAvite + * computation can be cloned by copying the context (e.g. with a simple + * memcpy()). + */ +typedef struct { +#ifndef DOXYGEN_IGNORE + unsigned char buf[128]; /* first field, for alignment */ + size_t ptr; + sph_u32 h[16]; + sph_u32 count0, count1, count2, count3; +#endif +} sph_shavite_big_context; + +/** + * This structure is a context for SHAvite-384 computations. It is + * identical to the common sph_shavite_small_context. + */ +typedef sph_shavite_big_context sph_shavite384_context; + +/** + * This structure is a context for SHAvite-512 computations. It is + * identical to the common sph_shavite_small_context. + */ +typedef sph_shavite_big_context sph_shavite512_context; + +/** + * Initialize a SHAvite-224 context. This process performs no memory allocation. + * + * @param cc the SHAvite-224 context (pointer to a + * sph_shavite224_context) + */ +void sph_shavite224_init(void *cc); + +/** + * Process some data bytes. It is acceptable that len is zero + * (in which case this function does nothing). + * + * @param cc the SHAvite-224 context + * @param data the input data + * @param len the input data length (in bytes) + */ +void sph_shavite224(void *cc, const void *data, size_t len); + +/** + * Terminate the current SHAvite-224 computation and output the result into + * the provided buffer. The destination buffer must be wide enough to + * accomodate the result (28 bytes). The context is automatically + * reinitialized. + * + * @param cc the SHAvite-224 context + * @param dst the destination buffer + */ +void sph_shavite224_close(void *cc, void *dst); + +/** + * Add a few additional bits (0 to 7) to the current computation, then + * terminate it and output the result in the provided buffer, which must + * be wide enough to accomodate the result (28 bytes). If bit number i + * in ub has value 2^i, then the extra bits are those + * numbered 7 downto 8-n (this is the big-endian convention at the byte + * level). The context is automatically reinitialized. + * + * @param cc the SHAvite-224 context + * @param ub the extra bits + * @param n the number of extra bits (0 to 7) + * @param dst the destination buffer + */ +void sph_shavite224_addbits_and_close( + void *cc, unsigned ub, unsigned n, void *dst); + +/** + * Initialize a SHAvite-256 context. This process performs no memory allocation. + * + * @param cc the SHAvite-256 context (pointer to a + * sph_shavite256_context) + */ +void sph_shavite256_init(void *cc); + +/** + * Process some data bytes. It is acceptable that len is zero + * (in which case this function does nothing). + * + * @param cc the SHAvite-256 context + * @param data the input data + * @param len the input data length (in bytes) + */ +void sph_shavite256(void *cc, const void *data, size_t len); + +/** + * Terminate the current SHAvite-256 computation and output the result into + * the provided buffer. The destination buffer must be wide enough to + * accomodate the result (32 bytes). The context is automatically + * reinitialized. + * + * @param cc the SHAvite-256 context + * @param dst the destination buffer + */ +void sph_shavite256_close(void *cc, void *dst); + +/** + * Add a few additional bits (0 to 7) to the current computation, then + * terminate it and output the result in the provided buffer, which must + * be wide enough to accomodate the result (32 bytes). If bit number i + * in ub has value 2^i, then the extra bits are those + * numbered 7 downto 8-n (this is the big-endian convention at the byte + * level). The context is automatically reinitialized. + * + * @param cc the SHAvite-256 context + * @param ub the extra bits + * @param n the number of extra bits (0 to 7) + * @param dst the destination buffer + */ +void sph_shavite256_addbits_and_close( + void *cc, unsigned ub, unsigned n, void *dst); + +/** + * Initialize a SHAvite-384 context. This process performs no memory allocation. + * + * @param cc the SHAvite-384 context (pointer to a + * sph_shavite384_context) + */ +void sph_shavite384_init(void *cc); + +/** + * Process some data bytes. It is acceptable that len is zero + * (in which case this function does nothing). + * + * @param cc the SHAvite-384 context + * @param data the input data + * @param len the input data length (in bytes) + */ +void sph_shavite384(void *cc, const void *data, size_t len); + +/** + * Terminate the current SHAvite-384 computation and output the result into + * the provided buffer. The destination buffer must be wide enough to + * accomodate the result (48 bytes). The context is automatically + * reinitialized. + * + * @param cc the SHAvite-384 context + * @param dst the destination buffer + */ +void sph_shavite384_close(void *cc, void *dst); + +/** + * Add a few additional bits (0 to 7) to the current computation, then + * terminate it and output the result in the provided buffer, which must + * be wide enough to accomodate the result (48 bytes). If bit number i + * in ub has value 2^i, then the extra bits are those + * numbered 7 downto 8-n (this is the big-endian convention at the byte + * level). The context is automatically reinitialized. + * + * @param cc the SHAvite-384 context + * @param ub the extra bits + * @param n the number of extra bits (0 to 7) + * @param dst the destination buffer + */ +void sph_shavite384_addbits_and_close( + void *cc, unsigned ub, unsigned n, void *dst); + +/** + * Initialize a SHAvite-512 context. This process performs no memory allocation. + * + * @param cc the SHAvite-512 context (pointer to a + * sph_shavite512_context) + */ +void sph_shavite512_init(void *cc); + +/** + * Process some data bytes. It is acceptable that len is zero + * (in which case this function does nothing). + * + * @param cc the SHAvite-512 context + * @param data the input data + * @param len the input data length (in bytes) + */ +void sph_shavite512(void *cc, const void *data, size_t len); + +/** + * Terminate the current SHAvite-512 computation and output the result into + * the provided buffer. The destination buffer must be wide enough to + * accomodate the result (64 bytes). The context is automatically + * reinitialized. + * + * @param cc the SHAvite-512 context + * @param dst the destination buffer + */ +void sph_shavite512_close(void *cc, void *dst); + +/** + * Add a few additional bits (0 to 7) to the current computation, then + * terminate it and output the result in the provided buffer, which must + * be wide enough to accomodate the result (64 bytes). If bit number i + * in ub has value 2^i, then the extra bits are those + * numbered 7 downto 8-n (this is the big-endian convention at the byte + * level). The context is automatically reinitialized. + * + * @param cc the SHAvite-512 context + * @param ub the extra bits + * @param n the number of extra bits (0 to 7) + * @param dst the destination buffer + */ +void sph_shavite512_addbits_and_close( + void *cc, unsigned ub, unsigned n, void *dst); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/sph_simd.h b/src/sph_simd.h new file mode 100644 index 0000000..92ee1e7 --- /dev/null +++ b/src/sph_simd.h @@ -0,0 +1,309 @@ +/* $Id: sph_simd.h 154 2010-04-26 17:00:24Z tp $ */ +/** + * SIMD interface. SIMD is a family of functions which differ by + * their output size; this implementation defines SIMD for output + * sizes 224, 256, 384 and 512 bits. + * + * ==========================(LICENSE BEGIN)============================ + * + * Copyright (c) 2007-2010 Projet RNRT SAPHIR + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * ===========================(LICENSE END)============================= + * + * @file sph_simd.h + * @author Thomas Pornin + */ + +#ifndef SPH_SIMD_H__ +#define SPH_SIMD_H__ + +#ifdef __cplusplus +extern "C"{ +#endif + +#include +#include "sph_types.h" + +/** + * Output size (in bits) for SIMD-224. + */ +#define SPH_SIZE_simd224 224 + +/** + * Output size (in bits) for SIMD-256. + */ +#define SPH_SIZE_simd256 256 + +/** + * Output size (in bits) for SIMD-384. + */ +#define SPH_SIZE_simd384 384 + +/** + * Output size (in bits) for SIMD-512. + */ +#define SPH_SIZE_simd512 512 + +/** + * This structure is a context for SIMD computations: it contains the + * intermediate values and some data from the last entered block. Once + * an SIMD computation has been performed, the context can be reused for + * another computation. This specific structure is used for SIMD-224 + * and SIMD-256. + * + * The contents of this structure are private. A running SIMD computation + * can be cloned by copying the context (e.g. with a simple + * memcpy()). + */ +typedef struct { +#ifndef DOXYGEN_IGNORE + unsigned char buf[64]; /* first field, for alignment */ + size_t ptr; + sph_u32 state[16]; + sph_u32 count_low, count_high; +#endif +} sph_simd_small_context; + +/** + * This structure is a context for SIMD computations: it contains the + * intermediate values and some data from the last entered block. Once + * an SIMD computation has been performed, the context can be reused for + * another computation. This specific structure is used for SIMD-384 + * and SIMD-512. + * + * The contents of this structure are private. A running SIMD computation + * can be cloned by copying the context (e.g. with a simple + * memcpy()). + */ +typedef struct { +#ifndef DOXYGEN_IGNORE + unsigned char buf[128]; /* first field, for alignment */ + size_t ptr; + sph_u32 state[32]; + sph_u32 count_low, count_high; +#endif +} sph_simd_big_context; + +/** + * Type for a SIMD-224 context (identical to the common "small" context). + */ +typedef sph_simd_small_context sph_simd224_context; + +/** + * Type for a SIMD-256 context (identical to the common "small" context). + */ +typedef sph_simd_small_context sph_simd256_context; + +/** + * Type for a SIMD-384 context (identical to the common "big" context). + */ +typedef sph_simd_big_context sph_simd384_context; + +/** + * Type for a SIMD-512 context (identical to the common "big" context). + */ +typedef sph_simd_big_context sph_simd512_context; + +/** + * Initialize an SIMD-224 context. This process performs no memory allocation. + * + * @param cc the SIMD-224 context (pointer to a + * sph_simd224_context) + */ +void sph_simd224_init(void *cc); + +/** + * Process some data bytes. It is acceptable that len is zero + * (in which case this function does nothing). + * + * @param cc the SIMD-224 context + * @param data the input data + * @param len the input data length (in bytes) + */ +void sph_simd224(void *cc, const void *data, size_t len); + +/** + * Terminate the current SIMD-224 computation and output the result into + * the provided buffer. The destination buffer must be wide enough to + * accomodate the result (28 bytes). The context is automatically + * reinitialized. + * + * @param cc the SIMD-224 context + * @param dst the destination buffer + */ +void sph_simd224_close(void *cc, void *dst); + +/** + * Add a few additional bits (0 to 7) to the current computation, then + * terminate it and output the result in the provided buffer, which must + * be wide enough to accomodate the result (28 bytes). If bit number i + * in ub has value 2^i, then the extra bits are those + * numbered 7 downto 8-n (this is the big-endian convention at the byte + * level). The context is automatically reinitialized. + * + * @param cc the SIMD-224 context + * @param ub the extra bits + * @param n the number of extra bits (0 to 7) + * @param dst the destination buffer + */ +void sph_simd224_addbits_and_close( + void *cc, unsigned ub, unsigned n, void *dst); + +/** + * Initialize an SIMD-256 context. This process performs no memory allocation. + * + * @param cc the SIMD-256 context (pointer to a + * sph_simd256_context) + */ +void sph_simd256_init(void *cc); + +/** + * Process some data bytes. It is acceptable that len is zero + * (in which case this function does nothing). + * + * @param cc the SIMD-256 context + * @param data the input data + * @param len the input data length (in bytes) + */ +void sph_simd256(void *cc, const void *data, size_t len); + +/** + * Terminate the current SIMD-256 computation and output the result into + * the provided buffer. The destination buffer must be wide enough to + * accomodate the result (32 bytes). The context is automatically + * reinitialized. + * + * @param cc the SIMD-256 context + * @param dst the destination buffer + */ +void sph_simd256_close(void *cc, void *dst); + +/** + * Add a few additional bits (0 to 7) to the current computation, then + * terminate it and output the result in the provided buffer, which must + * be wide enough to accomodate the result (32 bytes). If bit number i + * in ub has value 2^i, then the extra bits are those + * numbered 7 downto 8-n (this is the big-endian convention at the byte + * level). The context is automatically reinitialized. + * + * @param cc the SIMD-256 context + * @param ub the extra bits + * @param n the number of extra bits (0 to 7) + * @param dst the destination buffer + */ +void sph_simd256_addbits_and_close( + void *cc, unsigned ub, unsigned n, void *dst); + +/** + * Initialize an SIMD-384 context. This process performs no memory allocation. + * + * @param cc the SIMD-384 context (pointer to a + * sph_simd384_context) + */ +void sph_simd384_init(void *cc); + +/** + * Process some data bytes. It is acceptable that len is zero + * (in which case this function does nothing). + * + * @param cc the SIMD-384 context + * @param data the input data + * @param len the input data length (in bytes) + */ +void sph_simd384(void *cc, const void *data, size_t len); + +/** + * Terminate the current SIMD-384 computation and output the result into + * the provided buffer. The destination buffer must be wide enough to + * accomodate the result (48 bytes). The context is automatically + * reinitialized. + * + * @param cc the SIMD-384 context + * @param dst the destination buffer + */ +void sph_simd384_close(void *cc, void *dst); + +/** + * Add a few additional bits (0 to 7) to the current computation, then + * terminate it and output the result in the provided buffer, which must + * be wide enough to accomodate the result (48 bytes). If bit number i + * in ub has value 2^i, then the extra bits are those + * numbered 7 downto 8-n (this is the big-endian convention at the byte + * level). The context is automatically reinitialized. + * + * @param cc the SIMD-384 context + * @param ub the extra bits + * @param n the number of extra bits (0 to 7) + * @param dst the destination buffer + */ +void sph_simd384_addbits_and_close( + void *cc, unsigned ub, unsigned n, void *dst); + +/** + * Initialize an SIMD-512 context. This process performs no memory allocation. + * + * @param cc the SIMD-512 context (pointer to a + * sph_simd512_context) + */ +void sph_simd512_init(void *cc); + +/** + * Process some data bytes. It is acceptable that len is zero + * (in which case this function does nothing). + * + * @param cc the SIMD-512 context + * @param data the input data + * @param len the input data length (in bytes) + */ +void sph_simd512(void *cc, const void *data, size_t len); + +/** + * Terminate the current SIMD-512 computation and output the result into + * the provided buffer. The destination buffer must be wide enough to + * accomodate the result (64 bytes). The context is automatically + * reinitialized. + * + * @param cc the SIMD-512 context + * @param dst the destination buffer + */ +void sph_simd512_close(void *cc, void *dst); + +/** + * Add a few additional bits (0 to 7) to the current computation, then + * terminate it and output the result in the provided buffer, which must + * be wide enough to accomodate the result (64 bytes). If bit number i + * in ub has value 2^i, then the extra bits are those + * numbered 7 downto 8-n (this is the big-endian convention at the byte + * level). The context is automatically reinitialized. + * + * @param cc the SIMD-512 context + * @param ub the extra bits + * @param n the number of extra bits (0 to 7) + * @param dst the destination buffer + */ +void sph_simd512_addbits_and_close( + void *cc, unsigned ub, unsigned n, void *dst); +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/sph_skein.h b/src/sph_skein.h new file mode 100644 index 0000000..bddbc86 --- /dev/null +++ b/src/sph_skein.h @@ -0,0 +1,298 @@ +/* $Id: sph_skein.h 253 2011-06-07 18:33:10Z tp $ */ +/** + * Skein interface. The Skein specification defines three main + * functions, called Skein-256, Skein-512 and Skein-1024, which can be + * further parameterized with an output length. For the SHA-3 + * competition, Skein-512 is used for output sizes of 224, 256, 384 and + * 512 bits; this is what this code implements. Thus, we hereafter call + * Skein-224, Skein-256, Skein-384 and Skein-512 what the Skein + * specification defines as Skein-512-224, Skein-512-256, Skein-512-384 + * and Skein-512-512, respectively. + * + * ==========================(LICENSE BEGIN)============================ + * + * Copyright (c) 2007-2010 Projet RNRT SAPHIR + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * ===========================(LICENSE END)============================= + * + * @file sph_skein.h + * @author Thomas Pornin + */ + +#ifndef SPH_SKEIN_H__ +#define SPH_SKEIN_H__ + +#ifdef __cplusplus +extern "C"{ +#endif + +#include +#include "sph_types.h" + +#if SPH_64 + +/** + * Output size (in bits) for Skein-224. + */ +#define SPH_SIZE_skein224 224 + +/** + * Output size (in bits) for Skein-256. + */ +#define SPH_SIZE_skein256 256 + +/** + * Output size (in bits) for Skein-384. + */ +#define SPH_SIZE_skein384 384 + +/** + * Output size (in bits) for Skein-512. + */ +#define SPH_SIZE_skein512 512 + +/** + * This structure is a context for Skein computations (with a 384- or + * 512-bit output): it contains the intermediate values and some data + * from the last entered block. Once a Skein computation has been + * performed, the context can be reused for another computation. + * + * The contents of this structure are private. A running Skein computation + * can be cloned by copying the context (e.g. with a simple + * memcpy()). + */ +typedef struct { +#ifndef DOXYGEN_IGNORE + unsigned char buf[64]; /* first field, for alignment */ + size_t ptr; + sph_u64 h0, h1, h2, h3, h4, h5, h6, h7; + sph_u64 bcount; +#endif +} sph_skein_big_context; + +/** + * Type for a Skein-224 context (identical to the common "big" context). + */ +typedef sph_skein_big_context sph_skein224_context; + +/** + * Type for a Skein-256 context (identical to the common "big" context). + */ +typedef sph_skein_big_context sph_skein256_context; + +/** + * Type for a Skein-384 context (identical to the common "big" context). + */ +typedef sph_skein_big_context sph_skein384_context; + +/** + * Type for a Skein-512 context (identical to the common "big" context). + */ +typedef sph_skein_big_context sph_skein512_context; + +/** + * Initialize a Skein-224 context. This process performs no memory allocation. + * + * @param cc the Skein-224 context (pointer to a + * sph_skein224_context) + */ +void sph_skein224_init(void *cc); + +/** + * Process some data bytes. It is acceptable that len is zero + * (in which case this function does nothing). + * + * @param cc the Skein-224 context + * @param data the input data + * @param len the input data length (in bytes) + */ +void sph_skein224(void *cc, const void *data, size_t len); + +/** + * Terminate the current Skein-224 computation and output the result into + * the provided buffer. The destination buffer must be wide enough to + * accomodate the result (28 bytes). The context is automatically + * reinitialized. + * + * @param cc the Skein-224 context + * @param dst the destination buffer + */ +void sph_skein224_close(void *cc, void *dst); + +/** + * Add a few additional bits (0 to 7) to the current computation, then + * terminate it and output the result in the provided buffer, which must + * be wide enough to accomodate the result (28 bytes). If bit number i + * in ub has value 2^i, then the extra bits are those + * numbered 7 downto 8-n (this is the big-endian convention at the byte + * level). The context is automatically reinitialized. + * + * @param cc the Skein-224 context + * @param ub the extra bits + * @param n the number of extra bits (0 to 7) + * @param dst the destination buffer + */ +void sph_skein224_addbits_and_close( + void *cc, unsigned ub, unsigned n, void *dst); + +/** + * Initialize a Skein-256 context. This process performs no memory allocation. + * + * @param cc the Skein-256 context (pointer to a + * sph_skein256_context) + */ +void sph_skein256_init(void *cc); + +/** + * Process some data bytes. It is acceptable that len is zero + * (in which case this function does nothing). + * + * @param cc the Skein-256 context + * @param data the input data + * @param len the input data length (in bytes) + */ +void sph_skein256(void *cc, const void *data, size_t len); + +/** + * Terminate the current Skein-256 computation and output the result into + * the provided buffer. The destination buffer must be wide enough to + * accomodate the result (32 bytes). The context is automatically + * reinitialized. + * + * @param cc the Skein-256 context + * @param dst the destination buffer + */ +void sph_skein256_close(void *cc, void *dst); + +/** + * Add a few additional bits (0 to 7) to the current computation, then + * terminate it and output the result in the provided buffer, which must + * be wide enough to accomodate the result (32 bytes). If bit number i + * in ub has value 2^i, then the extra bits are those + * numbered 7 downto 8-n (this is the big-endian convention at the byte + * level). The context is automatically reinitialized. + * + * @param cc the Skein-256 context + * @param ub the extra bits + * @param n the number of extra bits (0 to 7) + * @param dst the destination buffer + */ +void sph_skein256_addbits_and_close( + void *cc, unsigned ub, unsigned n, void *dst); + +/** + * Initialize a Skein-384 context. This process performs no memory allocation. + * + * @param cc the Skein-384 context (pointer to a + * sph_skein384_context) + */ +void sph_skein384_init(void *cc); + +/** + * Process some data bytes. It is acceptable that len is zero + * (in which case this function does nothing). + * + * @param cc the Skein-384 context + * @param data the input data + * @param len the input data length (in bytes) + */ +void sph_skein384(void *cc, const void *data, size_t len); + +/** + * Terminate the current Skein-384 computation and output the result into + * the provided buffer. The destination buffer must be wide enough to + * accomodate the result (48 bytes). The context is automatically + * reinitialized. + * + * @param cc the Skein-384 context + * @param dst the destination buffer + */ +void sph_skein384_close(void *cc, void *dst); + +/** + * Add a few additional bits (0 to 7) to the current computation, then + * terminate it and output the result in the provided buffer, which must + * be wide enough to accomodate the result (48 bytes). If bit number i + * in ub has value 2^i, then the extra bits are those + * numbered 7 downto 8-n (this is the big-endian convention at the byte + * level). The context is automatically reinitialized. + * + * @param cc the Skein-384 context + * @param ub the extra bits + * @param n the number of extra bits (0 to 7) + * @param dst the destination buffer + */ +void sph_skein384_addbits_and_close( + void *cc, unsigned ub, unsigned n, void *dst); + +/** + * Initialize a Skein-512 context. This process performs no memory allocation. + * + * @param cc the Skein-512 context (pointer to a + * sph_skein512_context) + */ +void sph_skein512_init(void *cc); + +/** + * Process some data bytes. It is acceptable that len is zero + * (in which case this function does nothing). + * + * @param cc the Skein-512 context + * @param data the input data + * @param len the input data length (in bytes) + */ +void sph_skein512(void *cc, const void *data, size_t len); + +/** + * Terminate the current Skein-512 computation and output the result into + * the provided buffer. The destination buffer must be wide enough to + * accomodate the result (64 bytes). The context is automatically + * reinitialized. + * + * @param cc the Skein-512 context + * @param dst the destination buffer + */ +void sph_skein512_close(void *cc, void *dst); + +/** + * Add a few additional bits (0 to 7) to the current computation, then + * terminate it and output the result in the provided buffer, which must + * be wide enough to accomodate the result (64 bytes). If bit number i + * in ub has value 2^i, then the extra bits are those + * numbered 7 downto 8-n (this is the big-endian convention at the byte + * level). The context is automatically reinitialized. + * + * @param cc the Skein-512 context + * @param ub the extra bits + * @param n the number of extra bits (0 to 7) + * @param dst the destination buffer + */ +void sph_skein512_addbits_and_close( + void *cc, unsigned ub, unsigned n, void *dst); + +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/sph_types.h b/src/sph_types.h new file mode 100644 index 0000000..7295b0b --- /dev/null +++ b/src/sph_types.h @@ -0,0 +1,1976 @@ +/* $Id: sph_types.h 260 2011-07-21 01:02:38Z tp $ */ +/** + * Basic type definitions. + * + * This header file defines the generic integer types that will be used + * for the implementation of hash functions; it also contains helper + * functions which encode and decode multi-byte integer values, using + * either little-endian or big-endian conventions. + * + * This file contains a compile-time test on the size of a byte + * (the unsigned char C type). If bytes are not octets, + * i.e. if they do not have a size of exactly 8 bits, then compilation + * is aborted. Architectures where bytes are not octets are relatively + * rare, even in the embedded devices market. We forbid non-octet bytes + * because there is no clear convention on how octet streams are encoded + * on such systems. + * + * ==========================(LICENSE BEGIN)============================ + * + * Copyright (c) 2007-2010 Projet RNRT SAPHIR + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * ===========================(LICENSE END)============================= + * + * @file sph_types.h + * @author Thomas Pornin + */ + +#ifndef SPH_TYPES_H__ +#define SPH_TYPES_H__ + +#include + +/* + * All our I/O functions are defined over octet streams. We do not know + * how to handle input data if bytes are not octets. + */ +#if CHAR_BIT != 8 +#error This code requires 8-bit bytes +#endif + +/* ============= BEGIN documentation block for Doxygen ============ */ + +#ifdef DOXYGEN_IGNORE + +/** @mainpage sphlib C code documentation + * + * @section overview Overview + * + * sphlib is a library which contains implementations of + * various cryptographic hash functions. These pages have been generated + * with doxygen and + * document the API for the C implementations. + * + * The API is described in appropriate header files, which are available + * in the "Files" section. Each hash function family has its own header, + * whose name begins with "sph_" and contains the family + * name. For instance, the API for the RIPEMD hash functions is available + * in the header file sph_ripemd.h. + * + * @section principles API structure and conventions + * + * @subsection io Input/output conventions + * + * In all generality, hash functions operate over strings of bits. + * Individual bits are rarely encountered in C programming or actual + * communication protocols; most protocols converge on the ubiquitous + * "octet" which is a group of eight bits. Data is thus expressed as a + * stream of octets. The C programming language contains the notion of a + * "byte", which is a data unit managed under the type "unsigned + * char". The C standard prescribes that a byte should hold at + * least eight bits, but possibly more. Most modern architectures, even + * in the embedded world, feature eight-bit bytes, i.e. map bytes to + * octets. + * + * Nevertheless, for some of the implemented hash functions, an extra + * API has been added, which allows the input of arbitrary sequences of + * bits: when the computation is about to be closed, 1 to 7 extra bits + * can be added. The functions for which this API is implemented include + * the SHA-2 functions and all SHA-3 candidates. + * + * sphlib defines hash function which may hash octet streams, + * i.e. streams of bits where the number of bits is a multiple of eight. + * The data input functions in the sphlib API expect data + * as anonymous pointers ("const void *") with a length + * (of type "size_t") which gives the input data chunk length + * in bytes. A byte is assumed to be an octet; the sph_types.h + * header contains a compile-time test which prevents compilation on + * architectures where this property is not met. + * + * The hash function output is also converted into bytes. All currently + * implemented hash functions have an output width which is a multiple of + * eight, and this is likely to remain true for new designs. + * + * Most hash functions internally convert input data into 32-bit of 64-bit + * words, using either little-endian or big-endian conversion. The hash + * output also often consists of such words, which are encoded into output + * bytes with a similar endianness convention. Some hash functions have + * been only loosely specified on that subject; when necessary, + * sphlib has been tested against published "reference" + * implementations in order to use the same conventions. + * + * @subsection shortname Function short name + * + * Each implemented hash function has a "short name" which is used + * internally to derive the identifiers for the functions and context + * structures which the function uses. For instance, MD5 has the short + * name "md5". Short names are listed in the next section, + * for the implemented hash functions. In subsequent sections, the + * short name will be assumed to be "XXX": replace with the + * actual hash function name to get the C identifier. + * + * Note: some functions within the same family share the same core + * elements, such as update function or context structure. Correspondingly, + * some of the defined types or functions may actually be macros which + * transparently evaluate to another type or function name. + * + * @subsection context Context structure + * + * Each implemented hash fonction has its own context structure, available + * under the type name "sph_XXX_context" for the hash function + * with short name "XXX". This structure holds all needed + * state for a running hash computation. + * + * The contents of these structures are meant to be opaque, and private + * to the implementation. However, these contents are specified in the + * header files so that application code which uses sphlib + * may access the size of those structures. + * + * The caller is responsible for allocating the context structure, + * whether by dynamic allocation (malloc() or equivalent), + * static allocation (a global permanent variable), as an automatic + * variable ("on the stack"), or by any other mean which ensures proper + * structure alignment. sphlib code performs no dynamic + * allocation by itself. + * + * The context must be initialized before use, using the + * sph_XXX_init() function. This function sets the context + * state to proper initial values for hashing. + * + * Since all state data is contained within the context structure, + * sphlib is thread-safe and reentrant: several hash + * computations may be performed in parallel, provided that they do not + * operate on the same context. Moreover, a running computation can be + * cloned by copying the context (with a simple memcpy()): + * the context and its clone are then independant and may be updated + * with new data and/or closed without interfering with each other. + * Similarly, a context structure can be moved in memory at will: + * context structures contain no pointer, in particular no pointer to + * themselves. + * + * @subsection dataio Data input + * + * Hashed data is input with the sph_XXX() fonction, which + * takes as parameters a pointer to the context, a pointer to the data + * to hash, and the number of data bytes to hash. The context is updated + * with the new data. + * + * Data can be input in one or several calls, with arbitrary input lengths. + * However, it is best, performance wise, to input data by relatively big + * chunks (say a few kilobytes), because this allows sphlib to + * optimize things and avoid internal copying. + * + * When all data has been input, the context can be closed with + * sph_XXX_close(). The hash output is computed and written + * into the provided buffer. The caller must take care to provide a + * buffer of appropriate length; e.g., when using SHA-1, the output is + * a 20-byte word, therefore the output buffer must be at least 20-byte + * long. + * + * For some hash functions, the sph_XXX_addbits_and_close() + * function can be used instead of sph_XXX_close(). This + * function can take a few extra bits to be added at + * the end of the input message. This allows hashing messages with a + * bit length which is not a multiple of 8. The extra bits are provided + * as an unsigned integer value, and a bit count. The bit count must be + * between 0 and 7, inclusive. The extra bits are provided as bits 7 to + * 0 (bits of numerical value 128, 64, 32... downto 0), in that order. + * For instance, to add three bits of value 1, 1 and 0, the unsigned + * integer will have value 192 (1*128 + 1*64 + 0*32) and the bit count + * will be 3. + * + * The SPH_SIZE_XXX macro is defined for each hash function; + * it evaluates to the function output size, expressed in bits. For instance, + * SPH_SIZE_sha1 evaluates to 160. + * + * When closed, the context is automatically reinitialized and can be + * immediately used for another computation. It is not necessary to call + * sph_XXX_init() after a close. Note that + * sph_XXX_init() can still be called to "reset" a context, + * i.e. forget previously input data, and get back to the initial state. + * + * @subsection alignment Data alignment + * + * "Alignment" is a property of data, which is said to be "properly + * aligned" when its emplacement in memory is such that the data can + * be optimally read by full words. This depends on the type of access; + * basically, some hash functions will read data by 32-bit or 64-bit + * words. sphlib does not mandate such alignment for input + * data, but using aligned data can substantially improve performance. + * + * As a rule, it is best to input data by chunks whose length (in bytes) + * is a multiple of eight, and which begins at "generally aligned" + * addresses, such as the base address returned by a call to + * malloc(). + * + * @section functions Implemented functions + * + * We give here the list of implemented functions. They are grouped by + * family; to each family corresponds a specific header file. Each + * individual function has its associated "short name". Please refer to + * the documentation for that header file to get details on the hash + * function denomination and provenance. + * + * Note: the functions marked with a '(64)' in the list below are + * available only if the C compiler provides an integer type of length + * 64 bits or more. Such a type is mandatory in the latest C standard + * (ISO 9899:1999, aka "C99") and is present in several older compilers + * as well, so chances are that such a type is available. + * + * - HAVAL family: file sph_haval.h + * - HAVAL-128/3 (128-bit, 3 passes): short name: haval128_3 + * - HAVAL-128/4 (128-bit, 4 passes): short name: haval128_4 + * - HAVAL-128/5 (128-bit, 5 passes): short name: haval128_5 + * - HAVAL-160/3 (160-bit, 3 passes): short name: haval160_3 + * - HAVAL-160/4 (160-bit, 4 passes): short name: haval160_4 + * - HAVAL-160/5 (160-bit, 5 passes): short name: haval160_5 + * - HAVAL-192/3 (192-bit, 3 passes): short name: haval192_3 + * - HAVAL-192/4 (192-bit, 4 passes): short name: haval192_4 + * - HAVAL-192/5 (192-bit, 5 passes): short name: haval192_5 + * - HAVAL-224/3 (224-bit, 3 passes): short name: haval224_3 + * - HAVAL-224/4 (224-bit, 4 passes): short name: haval224_4 + * - HAVAL-224/5 (224-bit, 5 passes): short name: haval224_5 + * - HAVAL-256/3 (256-bit, 3 passes): short name: haval256_3 + * - HAVAL-256/4 (256-bit, 4 passes): short name: haval256_4 + * - HAVAL-256/5 (256-bit, 5 passes): short name: haval256_5 + * - MD2: file sph_md2.h, short name: md2 + * - MD4: file sph_md4.h, short name: md4 + * - MD5: file sph_md5.h, short name: md5 + * - PANAMA: file sph_panama.h, short name: panama + * - RadioGatun family: file sph_radiogatun.h + * - RadioGatun[32]: short name: radiogatun32 + * - RadioGatun[64]: short name: radiogatun64 (64) + * - RIPEMD family: file sph_ripemd.h + * - RIPEMD: short name: ripemd + * - RIPEMD-128: short name: ripemd128 + * - RIPEMD-160: short name: ripemd160 + * - SHA-0: file sph_sha0.h, short name: sha0 + * - SHA-1: file sph_sha1.h, short name: sha1 + * - SHA-2 family, 32-bit hashes: file sph_sha2.h + * - SHA-224: short name: sha224 + * - SHA-256: short name: sha256 + * - SHA-384: short name: sha384 (64) + * - SHA-512: short name: sha512 (64) + * - Tiger family: file sph_tiger.h + * - Tiger: short name: tiger (64) + * - Tiger2: short name: tiger2 (64) + * - WHIRLPOOL family: file sph_whirlpool.h + * - WHIRLPOOL-0: short name: whirlpool0 (64) + * - WHIRLPOOL-1: short name: whirlpool1 (64) + * - WHIRLPOOL: short name: whirlpool (64) + * + * The fourteen second-round SHA-3 candidates are also implemented; + * when applicable, the implementations follow the "final" specifications + * as published for the third round of the SHA-3 competition (BLAKE, + * Groestl, JH, Keccak and Skein have been tweaked for third round). + * + * - BLAKE family: file sph_blake.h + * - BLAKE-224: short name: blake224 + * - BLAKE-256: short name: blake256 + * - BLAKE-384: short name: blake384 + * - BLAKE-512: short name: blake512 + * - BMW (Blue Midnight Wish) family: file sph_bmw.h + * - BMW-224: short name: bmw224 + * - BMW-256: short name: bmw256 + * - BMW-384: short name: bmw384 (64) + * - BMW-512: short name: bmw512 (64) + * - CubeHash family: file sph_cubehash.h (specified as + * CubeHash16/32 in the CubeHash specification) + * - CubeHash-224: short name: cubehash224 + * - CubeHash-256: short name: cubehash256 + * - CubeHash-384: short name: cubehash384 + * - CubeHash-512: short name: cubehash512 + * - ECHO family: file sph_echo.h + * - ECHO-224: short name: echo224 + * - ECHO-256: short name: echo256 + * - ECHO-384: short name: echo384 + * - ECHO-512: short name: echo512 + * - Fugue family: file sph_fugue.h + * - Fugue-224: short name: fugue224 + * - Fugue-256: short name: fugue256 + * - Fugue-384: short name: fugue384 + * - Fugue-512: short name: fugue512 + * - Groestl family: file sph_groestl.h + * - Groestl-224: short name: groestl224 + * - Groestl-256: short name: groestl256 + * - Groestl-384: short name: groestl384 + * - Groestl-512: short name: groestl512 + * - Hamsi family: file sph_hamsi.h + * - Hamsi-224: short name: hamsi224 + * - Hamsi-256: short name: hamsi256 + * - Hamsi-384: short name: hamsi384 + * - Hamsi-512: short name: hamsi512 + * - JH family: file sph_jh.h + * - JH-224: short name: jh224 + * - JH-256: short name: jh256 + * - JH-384: short name: jh384 + * - JH-512: short name: jh512 + * - Keccak family: file sph_keccak.h + * - Keccak-224: short name: keccak224 + * - Keccak-256: short name: keccak256 + * - Keccak-384: short name: keccak384 + * - Keccak-512: short name: keccak512 + * - Luffa family: file sph_luffa.h + * - Luffa-224: short name: luffa224 + * - Luffa-256: short name: luffa256 + * - Luffa-384: short name: luffa384 + * - Luffa-512: short name: luffa512 + * - Shabal family: file sph_shabal.h + * - Shabal-192: short name: shabal192 + * - Shabal-224: short name: shabal224 + * - Shabal-256: short name: shabal256 + * - Shabal-384: short name: shabal384 + * - Shabal-512: short name: shabal512 + * - SHAvite-3 family: file sph_shavite.h + * - SHAvite-224 (nominally "SHAvite-3 with 224-bit output"): + * short name: shabal224 + * - SHAvite-256 (nominally "SHAvite-3 with 256-bit output"): + * short name: shabal256 + * - SHAvite-384 (nominally "SHAvite-3 with 384-bit output"): + * short name: shabal384 + * - SHAvite-512 (nominally "SHAvite-3 with 512-bit output"): + * short name: shabal512 + * - SIMD family: file sph_simd.h + * - SIMD-224: short name: simd224 + * - SIMD-256: short name: simd256 + * - SIMD-384: short name: simd384 + * - SIMD-512: short name: simd512 + * - Skein family: file sph_skein.h + * - Skein-224 (nominally specified as Skein-512-224): short name: + * skein224 (64) + * - Skein-256 (nominally specified as Skein-512-256): short name: + * skein256 (64) + * - Skein-384 (nominally specified as Skein-512-384): short name: + * skein384 (64) + * - Skein-512 (nominally specified as Skein-512-512): short name: + * skein512 (64) + * + * For the second-round SHA-3 candidates, the functions are as specified + * for round 2, i.e. with the "tweaks" that some candidates added + * between round 1 and round 2. Also, some of the submitted packages for + * round 2 contained errors, in the specification, reference code, or + * both. sphlib implements the corrected versions. + */ + +/** @hideinitializer + * Unsigned integer type whose length is at least 32 bits; on most + * architectures, it will have a width of exactly 32 bits. Unsigned C + * types implement arithmetics modulo a power of 2; use the + * SPH_T32() macro to ensure that the value is truncated + * to exactly 32 bits. Unless otherwise specified, all macros and + * functions which accept sph_u32 values assume that these + * values fit on 32 bits, i.e. do not exceed 2^32-1, even on architectures + * where sph_u32 is larger than that. + */ +typedef __arch_dependant__ sph_u32; + +/** @hideinitializer + * Signed integer type corresponding to sph_u32; it has + * width 32 bits or more. + */ +typedef __arch_dependant__ sph_s32; + +/** @hideinitializer + * Unsigned integer type whose length is at least 64 bits; on most + * architectures which feature such a type, it will have a width of + * exactly 64 bits. C99-compliant platform will have this type; it + * is also defined when the GNU compiler (gcc) is used, and on + * platforms where unsigned long is large enough. If this + * type is not available, then some hash functions which depends on + * a 64-bit type will not be available (most notably SHA-384, SHA-512, + * Tiger and WHIRLPOOL). + */ +typedef __arch_dependant__ sph_u64; + +/** @hideinitializer + * Signed integer type corresponding to sph_u64; it has + * width 64 bits or more. + */ +typedef __arch_dependant__ sph_s64; + +/** + * This macro expands the token x into a suitable + * constant expression of type sph_u32. Depending on + * how this type is defined, a suffix such as UL may + * be appended to the argument. + * + * @param x the token to expand into a suitable constant expression + */ +#define SPH_C32(x) + +/** + * Truncate a 32-bit value to exactly 32 bits. On most systems, this is + * a no-op, recognized as such by the compiler. + * + * @param x the value to truncate (of type sph_u32) + */ +#define SPH_T32(x) + +/** + * Rotate a 32-bit value by a number of bits to the left. The rotate + * count must reside between 1 and 31. This macro assumes that its + * first argument fits in 32 bits (no extra bit allowed on machines where + * sph_u32 is wider); both arguments may be evaluated + * several times. + * + * @param x the value to rotate (of type sph_u32) + * @param n the rotation count (between 1 and 31, inclusive) + */ +#define SPH_ROTL32(x, n) + +/** + * Rotate a 32-bit value by a number of bits to the left. The rotate + * count must reside between 1 and 31. This macro assumes that its + * first argument fits in 32 bits (no extra bit allowed on machines where + * sph_u32 is wider); both arguments may be evaluated + * several times. + * + * @param x the value to rotate (of type sph_u32) + * @param n the rotation count (between 1 and 31, inclusive) + */ +#define SPH_ROTR32(x, n) + +/** + * This macro is defined on systems for which a 64-bit type has been + * detected, and is used for sph_u64. + */ +#define SPH_64 + +/** + * This macro is defined on systems for the "native" integer size is + * 64 bits (64-bit values fit in one register). + */ +#define SPH_64_TRUE + +/** + * This macro expands the token x into a suitable + * constant expression of type sph_u64. Depending on + * how this type is defined, a suffix such as ULL may + * be appended to the argument. This macro is defined only if a + * 64-bit type was detected and used for sph_u64. + * + * @param x the token to expand into a suitable constant expression + */ +#define SPH_C64(x) + +/** + * Truncate a 64-bit value to exactly 64 bits. On most systems, this is + * a no-op, recognized as such by the compiler. This macro is defined only + * if a 64-bit type was detected and used for sph_u64. + * + * @param x the value to truncate (of type sph_u64) + */ +#define SPH_T64(x) + +/** + * Rotate a 64-bit value by a number of bits to the left. The rotate + * count must reside between 1 and 63. This macro assumes that its + * first argument fits in 64 bits (no extra bit allowed on machines where + * sph_u64 is wider); both arguments may be evaluated + * several times. This macro is defined only if a 64-bit type was detected + * and used for sph_u64. + * + * @param x the value to rotate (of type sph_u64) + * @param n the rotation count (between 1 and 63, inclusive) + */ +#define SPH_ROTL64(x, n) + +/** + * Rotate a 64-bit value by a number of bits to the left. The rotate + * count must reside between 1 and 63. This macro assumes that its + * first argument fits in 64 bits (no extra bit allowed on machines where + * sph_u64 is wider); both arguments may be evaluated + * several times. This macro is defined only if a 64-bit type was detected + * and used for sph_u64. + * + * @param x the value to rotate (of type sph_u64) + * @param n the rotation count (between 1 and 63, inclusive) + */ +#define SPH_ROTR64(x, n) + +/** + * This macro evaluates to inline or an equivalent construction, + * if available on the compilation platform, or to nothing otherwise. This + * is used to declare inline functions, for which the compiler should + * endeavour to include the code directly in the caller. Inline functions + * are typically defined in header files as replacement for macros. + */ +#define SPH_INLINE + +/** + * This macro is defined if the platform has been detected as using + * little-endian convention. This implies that the sph_u32 + * type (and the sph_u64 type also, if it is defined) has + * an exact width (i.e. exactly 32-bit, respectively 64-bit). + */ +#define SPH_LITTLE_ENDIAN + +/** + * This macro is defined if the platform has been detected as using + * big-endian convention. This implies that the sph_u32 + * type (and the sph_u64 type also, if it is defined) has + * an exact width (i.e. exactly 32-bit, respectively 64-bit). + */ +#define SPH_BIG_ENDIAN + +/** + * This macro is defined if 32-bit words (and 64-bit words, if defined) + * can be read from and written to memory efficiently in little-endian + * convention. This is the case for little-endian platforms, and also + * for the big-endian platforms which have special little-endian access + * opcodes (e.g. Ultrasparc). + */ +#define SPH_LITTLE_FAST + +/** + * This macro is defined if 32-bit words (and 64-bit words, if defined) + * can be read from and written to memory efficiently in big-endian + * convention. This is the case for little-endian platforms, and also + * for the little-endian platforms which have special big-endian access + * opcodes. + */ +#define SPH_BIG_FAST + +/** + * On some platforms, this macro is defined to an unsigned integer type + * into which pointer values may be cast. The resulting value can then + * be tested for being a multiple of 2, 4 or 8, indicating an aligned + * pointer for, respectively, 16-bit, 32-bit or 64-bit memory accesses. + */ +#define SPH_UPTR + +/** + * When defined, this macro indicates that unaligned memory accesses + * are possible with only a minor penalty, and thus should be prefered + * over strategies which first copy data to an aligned buffer. + */ +#define SPH_UNALIGNED + +/** + * Byte-swap a 32-bit word (i.e. 0x12345678 becomes + * 0x78563412). This is an inline function which resorts + * to inline assembly on some platforms, for better performance. + * + * @param x the 32-bit value to byte-swap + * @return the byte-swapped value + */ +static inline sph_u32 sph_bswap32(sph_u32 x); + +/** + * Byte-swap a 64-bit word. This is an inline function which resorts + * to inline assembly on some platforms, for better performance. This + * function is defined only if a suitable 64-bit type was found for + * sph_u64 + * + * @param x the 64-bit value to byte-swap + * @return the byte-swapped value + */ +static inline sph_u64 sph_bswap64(sph_u64 x); + +/** + * Decode a 16-bit unsigned value from memory, in little-endian convention + * (least significant byte comes first). + * + * @param src the source address + * @return the decoded value + */ +static inline unsigned sph_dec16le(const void *src); + +/** + * Encode a 16-bit unsigned value into memory, in little-endian convention + * (least significant byte comes first). + * + * @param dst the destination buffer + * @param val the value to encode + */ +static inline void sph_enc16le(void *dst, unsigned val); + +/** + * Decode a 16-bit unsigned value from memory, in big-endian convention + * (most significant byte comes first). + * + * @param src the source address + * @return the decoded value + */ +static inline unsigned sph_dec16be(const void *src); + +/** + * Encode a 16-bit unsigned value into memory, in big-endian convention + * (most significant byte comes first). + * + * @param dst the destination buffer + * @param val the value to encode + */ +static inline void sph_enc16be(void *dst, unsigned val); + +/** + * Decode a 32-bit unsigned value from memory, in little-endian convention + * (least significant byte comes first). + * + * @param src the source address + * @return the decoded value + */ +static inline sph_u32 sph_dec32le(const void *src); + +/** + * Decode a 32-bit unsigned value from memory, in little-endian convention + * (least significant byte comes first). This function assumes that the + * source address is suitably aligned for a direct access, if the platform + * supports such things; it can thus be marginally faster than the generic + * sph_dec32le() function. + * + * @param src the source address + * @return the decoded value + */ +static inline sph_u32 sph_dec32le_aligned(const void *src); + +/** + * Encode a 32-bit unsigned value into memory, in little-endian convention + * (least significant byte comes first). + * + * @param dst the destination buffer + * @param val the value to encode + */ +static inline void sph_enc32le(void *dst, sph_u32 val); + +/** + * Encode a 32-bit unsigned value into memory, in little-endian convention + * (least significant byte comes first). This function assumes that the + * destination address is suitably aligned for a direct access, if the + * platform supports such things; it can thus be marginally faster than + * the generic sph_enc32le() function. + * + * @param dst the destination buffer + * @param val the value to encode + */ +static inline void sph_enc32le_aligned(void *dst, sph_u32 val); + +/** + * Decode a 32-bit unsigned value from memory, in big-endian convention + * (most significant byte comes first). + * + * @param src the source address + * @return the decoded value + */ +static inline sph_u32 sph_dec32be(const void *src); + +/** + * Decode a 32-bit unsigned value from memory, in big-endian convention + * (most significant byte comes first). This function assumes that the + * source address is suitably aligned for a direct access, if the platform + * supports such things; it can thus be marginally faster than the generic + * sph_dec32be() function. + * + * @param src the source address + * @return the decoded value + */ +static inline sph_u32 sph_dec32be_aligned(const void *src); + +/** + * Encode a 32-bit unsigned value into memory, in big-endian convention + * (most significant byte comes first). + * + * @param dst the destination buffer + * @param val the value to encode + */ +static inline void sph_enc32be(void *dst, sph_u32 val); + +/** + * Encode a 32-bit unsigned value into memory, in big-endian convention + * (most significant byte comes first). This function assumes that the + * destination address is suitably aligned for a direct access, if the + * platform supports such things; it can thus be marginally faster than + * the generic sph_enc32be() function. + * + * @param dst the destination buffer + * @param val the value to encode + */ +static inline void sph_enc32be_aligned(void *dst, sph_u32 val); + +/** + * Decode a 64-bit unsigned value from memory, in little-endian convention + * (least significant byte comes first). This function is defined only + * if a suitable 64-bit type was detected and used for sph_u64. + * + * @param src the source address + * @return the decoded value + */ +static inline sph_u64 sph_dec64le(const void *src); + +/** + * Decode a 64-bit unsigned value from memory, in little-endian convention + * (least significant byte comes first). This function assumes that the + * source address is suitably aligned for a direct access, if the platform + * supports such things; it can thus be marginally faster than the generic + * sph_dec64le() function. This function is defined only + * if a suitable 64-bit type was detected and used for sph_u64. + * + * @param src the source address + * @return the decoded value + */ +static inline sph_u64 sph_dec64le_aligned(const void *src); + +/** + * Encode a 64-bit unsigned value into memory, in little-endian convention + * (least significant byte comes first). This function is defined only + * if a suitable 64-bit type was detected and used for sph_u64. + * + * @param dst the destination buffer + * @param val the value to encode + */ +static inline void sph_enc64le(void *dst, sph_u64 val); + +/** + * Encode a 64-bit unsigned value into memory, in little-endian convention + * (least significant byte comes first). This function assumes that the + * destination address is suitably aligned for a direct access, if the + * platform supports such things; it can thus be marginally faster than + * the generic sph_enc64le() function. This function is defined + * only if a suitable 64-bit type was detected and used for + * sph_u64. + * + * @param dst the destination buffer + * @param val the value to encode + */ +static inline void sph_enc64le_aligned(void *dst, sph_u64 val); + +/** + * Decode a 64-bit unsigned value from memory, in big-endian convention + * (most significant byte comes first). This function is defined only + * if a suitable 64-bit type was detected and used for sph_u64. + * + * @param src the source address + * @return the decoded value + */ +static inline sph_u64 sph_dec64be(const void *src); + +/** + * Decode a 64-bit unsigned value from memory, in big-endian convention + * (most significant byte comes first). This function assumes that the + * source address is suitably aligned for a direct access, if the platform + * supports such things; it can thus be marginally faster than the generic + * sph_dec64be() function. This function is defined only + * if a suitable 64-bit type was detected and used for sph_u64. + * + * @param src the source address + * @return the decoded value + */ +static inline sph_u64 sph_dec64be_aligned(const void *src); + +/** + * Encode a 64-bit unsigned value into memory, in big-endian convention + * (most significant byte comes first). This function is defined only + * if a suitable 64-bit type was detected and used for sph_u64. + * + * @param dst the destination buffer + * @param val the value to encode + */ +static inline void sph_enc64be(void *dst, sph_u64 val); + +/** + * Encode a 64-bit unsigned value into memory, in big-endian convention + * (most significant byte comes first). This function assumes that the + * destination address is suitably aligned for a direct access, if the + * platform supports such things; it can thus be marginally faster than + * the generic sph_enc64be() function. This function is defined + * only if a suitable 64-bit type was detected and used for + * sph_u64. + * + * @param dst the destination buffer + * @param val the value to encode + */ +static inline void sph_enc64be_aligned(void *dst, sph_u64 val); + +#endif + +/* ============== END documentation block for Doxygen ============= */ + +#ifndef DOXYGEN_IGNORE + +/* + * We want to define the types "sph_u32" and "sph_u64" which hold + * unsigned values of at least, respectively, 32 and 64 bits. These + * tests should select appropriate types for most platforms. The + * macro "SPH_64" is defined if the 64-bit is supported. + */ + +#undef SPH_64 +#undef SPH_64_TRUE + +#if defined __STDC__ && __STDC_VERSION__ >= 199901L + +/* + * On C99 implementations, we can use to get an exact 64-bit + * type, if any, or otherwise use a wider type (which must exist, for + * C99 conformance). + */ + +#include + +#ifdef UINT32_MAX +typedef uint32_t sph_u32; +typedef int32_t sph_s32; +#else +typedef uint_fast32_t sph_u32; +typedef int_fast32_t sph_s32; +#endif +#if !SPH_NO_64 +#ifdef UINT64_MAX +typedef uint64_t sph_u64; +typedef int64_t sph_s64; +#else +typedef uint_fast64_t sph_u64; +typedef int_fast64_t sph_s64; +#endif +#endif + +#define SPH_C32(x) ((sph_u32)(x)) +#if !SPH_NO_64 +#define SPH_C64(x) ((sph_u64)(x)) +#define SPH_64 1 +#endif + +#else + +/* + * On non-C99 systems, we use "unsigned int" if it is wide enough, + * "unsigned long" otherwise. This supports all "reasonable" architectures. + * We have to be cautious: pre-C99 preprocessors handle constants + * differently in '#if' expressions. Hence the shifts to test UINT_MAX. + */ + +#if ((UINT_MAX >> 11) >> 11) >= 0x3FF + +typedef unsigned int sph_u32; +typedef int sph_s32; + +#define SPH_C32(x) ((sph_u32)(x ## U)) + +#else + +typedef unsigned long sph_u32; +typedef long sph_s32; + +#define SPH_C32(x) ((sph_u32)(x ## UL)) + +#endif + +#if !SPH_NO_64 + +/* + * We want a 64-bit type. We use "unsigned long" if it is wide enough (as + * is common on 64-bit architectures such as AMD64, Alpha or Sparcv9), + * "unsigned long long" otherwise, if available. We use ULLONG_MAX to + * test whether "unsigned long long" is available; we also know that + * gcc features this type, even if the libc header do not know it. + */ + +#if ((ULONG_MAX >> 31) >> 31) >= 3 + +typedef unsigned long sph_u64; +typedef long sph_s64; + +#define SPH_C64(x) ((sph_u64)(x ## UL)) + +#define SPH_64 1 + +#elif ((ULLONG_MAX >> 31) >> 31) >= 3 || defined __GNUC__ + +typedef unsigned long long sph_u64; +typedef long long sph_s64; + +#define SPH_C64(x) ((sph_u64)(x ## ULL)) + +#define SPH_64 1 + +#else + +/* + * No 64-bit type... + */ + +#endif + +#endif + +#endif + +/* + * If the "unsigned long" type has length 64 bits or more, then this is + * a "true" 64-bit architectures. This is also true with Visual C on + * amd64, even though the "long" type is limited to 32 bits. + */ +#if SPH_64 && (((ULONG_MAX >> 31) >> 31) >= 3 || defined _M_X64) +#define SPH_64_TRUE 1 +#endif + +/* + * Implementation note: some processors have specific opcodes to perform + * a rotation. Recent versions of gcc recognize the expression above and + * use the relevant opcodes, when appropriate. + */ + +#define SPH_T32(x) ((x) & SPH_C32(0xFFFFFFFF)) +#define SPH_ROTL32(x, n) SPH_T32(((x) << (n)) | ((x) >> (32 - (n)))) +#define SPH_ROTR32(x, n) SPH_ROTL32(x, (32 - (n))) + +#if SPH_64 + +#define SPH_T64(x) ((x) & SPH_C64(0xFFFFFFFFFFFFFFFF)) +#define SPH_ROTL64(x, n) SPH_T64(((x) << (n)) | ((x) >> (64 - (n)))) +#define SPH_ROTR64(x, n) SPH_ROTL64(x, (64 - (n))) + +#endif + +#ifndef DOXYGEN_IGNORE +/* + * Define SPH_INLINE to be an "inline" qualifier, if available. We define + * some small macro-like functions which benefit greatly from being inlined. + */ +#if (defined __STDC__ && __STDC_VERSION__ >= 199901L) || defined __GNUC__ +#define SPH_INLINE inline +#elif defined _MSC_VER +#define SPH_INLINE __inline +#else +#define SPH_INLINE +#endif +#endif + +/* + * We define some macros which qualify the architecture. These macros + * may be explicit set externally (e.g. as compiler parameters). The + * code below sets those macros if they are not already defined. + * + * Most macros are boolean, thus evaluate to either zero or non-zero. + * The SPH_UPTR macro is special, in that it evaluates to a C type, + * or is not defined. + * + * SPH_UPTR if defined: unsigned type to cast pointers into + * + * SPH_UNALIGNED non-zero if unaligned accesses are efficient + * SPH_LITTLE_ENDIAN non-zero if architecture is known to be little-endian + * SPH_BIG_ENDIAN non-zero if architecture is known to be big-endian + * SPH_LITTLE_FAST non-zero if little-endian decoding is fast + * SPH_BIG_FAST non-zero if big-endian decoding is fast + * + * If SPH_UPTR is defined, then encoding and decoding of 32-bit and 64-bit + * values will try to be "smart". Either SPH_LITTLE_ENDIAN or SPH_BIG_ENDIAN + * _must_ be non-zero in those situations. The 32-bit and 64-bit types + * _must_ also have an exact width. + * + * SPH_SPARCV9_GCC_32 UltraSPARC-compatible with gcc, 32-bit mode + * SPH_SPARCV9_GCC_64 UltraSPARC-compatible with gcc, 64-bit mode + * SPH_SPARCV9_GCC UltraSPARC-compatible with gcc + * SPH_I386_GCC x86-compatible (32-bit) with gcc + * SPH_I386_MSVC x86-compatible (32-bit) with Microsoft Visual C + * SPH_AMD64_GCC x86-compatible (64-bit) with gcc + * SPH_AMD64_MSVC x86-compatible (64-bit) with Microsoft Visual C + * SPH_PPC32_GCC PowerPC, 32-bit, with gcc + * SPH_PPC64_GCC PowerPC, 64-bit, with gcc + * + * TODO: enhance automatic detection, for more architectures and compilers. + * Endianness is the most important. SPH_UNALIGNED and SPH_UPTR help with + * some very fast functions (e.g. MD4) when using unaligned input data. + * The CPU-specific-with-GCC macros are useful only for inline assembly, + * normally restrained to this header file. + */ + +/* + * 32-bit x86, aka "i386 compatible". + */ +#if defined __i386__ || defined _M_IX86 + +#define SPH_DETECT_UNALIGNED 1 +#define SPH_DETECT_LITTLE_ENDIAN 1 +#define SPH_DETECT_UPTR sph_u32 +#ifdef __GNUC__ +#define SPH_DETECT_I386_GCC 1 +#endif +#ifdef _MSC_VER +#define SPH_DETECT_I386_MSVC 1 +#endif + +/* + * 64-bit x86, hereafter known as "amd64". + */ +#elif defined __x86_64 || defined _M_X64 + +#define SPH_DETECT_UNALIGNED 1 +#define SPH_DETECT_LITTLE_ENDIAN 1 +#define SPH_DETECT_UPTR sph_u64 +#ifdef __GNUC__ +#define SPH_DETECT_AMD64_GCC 1 +#endif +#ifdef _MSC_VER +#define SPH_DETECT_AMD64_MSVC 1 +#endif + +/* + * 64-bit Sparc architecture (implies v9). + */ +#elif ((defined __sparc__ || defined __sparc) && defined __arch64__) \ + || defined __sparcv9 + +#define SPH_DETECT_BIG_ENDIAN 1 +#define SPH_DETECT_UPTR sph_u64 +#ifdef __GNUC__ +#define SPH_DETECT_SPARCV9_GCC_64 1 +#define SPH_DETECT_LITTLE_FAST 1 +#endif + +/* + * 32-bit Sparc. + */ +#elif (defined __sparc__ || defined __sparc) \ + && !(defined __sparcv9 || defined __arch64__) + +#define SPH_DETECT_BIG_ENDIAN 1 +#define SPH_DETECT_UPTR sph_u32 +#if defined __GNUC__ && defined __sparc_v9__ +#define SPH_DETECT_SPARCV9_GCC_32 1 +#define SPH_DETECT_LITTLE_FAST 1 +#endif + +/* + * ARM, little-endian. + */ +#elif defined __arm__ && __ARMEL__ + +#define SPH_DETECT_LITTLE_ENDIAN 1 + +/* + * MIPS, little-endian. + */ +#elif MIPSEL || _MIPSEL || __MIPSEL || __MIPSEL__ + +#define SPH_DETECT_LITTLE_ENDIAN 1 + +/* + * MIPS, big-endian. + */ +#elif MIPSEB || _MIPSEB || __MIPSEB || __MIPSEB__ + +#define SPH_DETECT_BIG_ENDIAN 1 + +/* + * PowerPC. + */ +#elif defined __powerpc__ || defined __POWERPC__ || defined __ppc__ \ + || defined _ARCH_PPC + +/* + * Note: we do not declare cross-endian access to be "fast": even if + * using inline assembly, implementation should still assume that + * keeping the decoded word in a temporary is faster than decoding + * it again. + */ +#if defined __GNUC__ +#if SPH_64_TRUE +#define SPH_DETECT_PPC64_GCC 1 +#else +#define SPH_DETECT_PPC32_GCC 1 +#endif +#endif + +#if defined __BIG_ENDIAN__ || defined _BIG_ENDIAN +#define SPH_DETECT_BIG_ENDIAN 1 +#elif defined __LITTLE_ENDIAN__ || defined _LITTLE_ENDIAN +#define SPH_DETECT_LITTLE_ENDIAN 1 +#endif + +/* + * Itanium, 64-bit. + */ +#elif defined __ia64 || defined __ia64__ \ + || defined __itanium__ || defined _M_IA64 + +#if defined __BIG_ENDIAN__ || defined _BIG_ENDIAN +#define SPH_DETECT_BIG_ENDIAN 1 +#else +#define SPH_DETECT_LITTLE_ENDIAN 1 +#endif +#if defined __LP64__ || defined _LP64 +#define SPH_DETECT_UPTR sph_u64 +#else +#define SPH_DETECT_UPTR sph_u32 +#endif + +#endif + +#if defined SPH_DETECT_SPARCV9_GCC_32 || defined SPH_DETECT_SPARCV9_GCC_64 +#define SPH_DETECT_SPARCV9_GCC 1 +#endif + +#if defined SPH_DETECT_UNALIGNED && !defined SPH_UNALIGNED +#define SPH_UNALIGNED SPH_DETECT_UNALIGNED +#endif +#if defined SPH_DETECT_UPTR && !defined SPH_UPTR +#define SPH_UPTR SPH_DETECT_UPTR +#endif +#if defined SPH_DETECT_LITTLE_ENDIAN && !defined SPH_LITTLE_ENDIAN +#define SPH_LITTLE_ENDIAN SPH_DETECT_LITTLE_ENDIAN +#endif +#if defined SPH_DETECT_BIG_ENDIAN && !defined SPH_BIG_ENDIAN +#define SPH_BIG_ENDIAN SPH_DETECT_BIG_ENDIAN +#endif +#if defined SPH_DETECT_LITTLE_FAST && !defined SPH_LITTLE_FAST +#define SPH_LITTLE_FAST SPH_DETECT_LITTLE_FAST +#endif +#if defined SPH_DETECT_BIG_FAST && !defined SPH_BIG_FAST +#define SPH_BIG_FAST SPH_DETECT_BIG_FAST +#endif +#if defined SPH_DETECT_SPARCV9_GCC_32 && !defined SPH_SPARCV9_GCC_32 +#define SPH_SPARCV9_GCC_32 SPH_DETECT_SPARCV9_GCC_32 +#endif +#if defined SPH_DETECT_SPARCV9_GCC_64 && !defined SPH_SPARCV9_GCC_64 +#define SPH_SPARCV9_GCC_64 SPH_DETECT_SPARCV9_GCC_64 +#endif +#if defined SPH_DETECT_SPARCV9_GCC && !defined SPH_SPARCV9_GCC +#define SPH_SPARCV9_GCC SPH_DETECT_SPARCV9_GCC +#endif +#if defined SPH_DETECT_I386_GCC && !defined SPH_I386_GCC +#define SPH_I386_GCC SPH_DETECT_I386_GCC +#endif +#if defined SPH_DETECT_I386_MSVC && !defined SPH_I386_MSVC +#define SPH_I386_MSVC SPH_DETECT_I386_MSVC +#endif +#if defined SPH_DETECT_AMD64_GCC && !defined SPH_AMD64_GCC +#define SPH_AMD64_GCC SPH_DETECT_AMD64_GCC +#endif +#if defined SPH_DETECT_AMD64_MSVC && !defined SPH_AMD64_MSVC +#define SPH_AMD64_MSVC SPH_DETECT_AMD64_MSVC +#endif +#if defined SPH_DETECT_PPC32_GCC && !defined SPH_PPC32_GCC +#define SPH_PPC32_GCC SPH_DETECT_PPC32_GCC +#endif +#if defined SPH_DETECT_PPC64_GCC && !defined SPH_PPC64_GCC +#define SPH_PPC64_GCC SPH_DETECT_PPC64_GCC +#endif + +#if SPH_LITTLE_ENDIAN && !defined SPH_LITTLE_FAST +#define SPH_LITTLE_FAST 1 +#endif +#if SPH_BIG_ENDIAN && !defined SPH_BIG_FAST +#define SPH_BIG_FAST 1 +#endif + +#if defined SPH_UPTR && !(SPH_LITTLE_ENDIAN || SPH_BIG_ENDIAN) +#error SPH_UPTR defined, but endianness is not known. +#endif + +#if SPH_I386_GCC && !SPH_NO_ASM + +/* + * On x86 32-bit, with gcc, we use the bswapl opcode to byte-swap 32-bit + * values. + */ + +static SPH_INLINE sph_u32 +sph_bswap32(sph_u32 x) +{ + __asm__ __volatile__ ("bswapl %0" : "=r" (x) : "0" (x)); + return x; +} + +#if SPH_64 + +static SPH_INLINE sph_u64 +sph_bswap64(sph_u64 x) +{ + return ((sph_u64)sph_bswap32((sph_u32)x) << 32) + | (sph_u64)sph_bswap32((sph_u32)(x >> 32)); +} + +#endif + +#elif SPH_AMD64_GCC && !SPH_NO_ASM + +/* + * On x86 64-bit, with gcc, we use the bswapl opcode to byte-swap 32-bit + * and 64-bit values. + */ + +static SPH_INLINE sph_u32 +sph_bswap32(sph_u32 x) +{ + __asm__ __volatile__ ("bswapl %0" : "=r" (x) : "0" (x)); + return x; +} + +#if SPH_64 + +static SPH_INLINE sph_u64 +sph_bswap64(sph_u64 x) +{ + __asm__ __volatile__ ("bswapq %0" : "=r" (x) : "0" (x)); + return x; +} + +#endif + +/* + * Disabled code. Apparently, Microsoft Visual C 2005 is smart enough + * to generate proper opcodes for endianness swapping with the pure C + * implementation below. + * + +#elif SPH_I386_MSVC && !SPH_NO_ASM + +static __inline sph_u32 __declspec(naked) __fastcall +sph_bswap32(sph_u32 x) +{ + __asm { + bswap ecx + mov eax,ecx + ret + } +} + +#if SPH_64 + +static SPH_INLINE sph_u64 +sph_bswap64(sph_u64 x) +{ + return ((sph_u64)sph_bswap32((sph_u32)x) << 32) + | (sph_u64)sph_bswap32((sph_u32)(x >> 32)); +} + +#endif + + * + * [end of disabled code] + */ + +#else + +static SPH_INLINE sph_u32 +sph_bswap32(sph_u32 x) +{ + x = SPH_T32((x << 16) | (x >> 16)); + x = ((x & SPH_C32(0xFF00FF00)) >> 8) + | ((x & SPH_C32(0x00FF00FF)) << 8); + return x; +} + +#if SPH_64 + +/** + * Byte-swap a 64-bit value. + * + * @param x the input value + * @return the byte-swapped value + */ +static SPH_INLINE sph_u64 +sph_bswap64(sph_u64 x) +{ + x = SPH_T64((x << 32) | (x >> 32)); + x = ((x & SPH_C64(0xFFFF0000FFFF0000)) >> 16) + | ((x & SPH_C64(0x0000FFFF0000FFFF)) << 16); + x = ((x & SPH_C64(0xFF00FF00FF00FF00)) >> 8) + | ((x & SPH_C64(0x00FF00FF00FF00FF)) << 8); + return x; +} + +#endif + +#endif + +#if SPH_SPARCV9_GCC && !SPH_NO_ASM + +/* + * On UltraSPARC systems, native ordering is big-endian, but it is + * possible to perform little-endian read accesses by specifying the + * address space 0x88 (ASI_PRIMARY_LITTLE). Basically, either we use + * the opcode "lda [%reg]0x88,%dst", where %reg is the register which + * contains the source address and %dst is the destination register, + * or we use "lda [%reg+imm]%asi,%dst", which uses the %asi register + * to get the address space name. The latter format is better since it + * combines an addition and the actual access in a single opcode; but + * it requires the setting (and subsequent resetting) of %asi, which is + * slow. Some operations (i.e. MD5 compression function) combine many + * successive little-endian read accesses, which may share the same + * %asi setting. The macros below contain the appropriate inline + * assembly. + */ + +#define SPH_SPARCV9_SET_ASI \ + sph_u32 sph_sparcv9_asi; \ + __asm__ __volatile__ ( \ + "rd %%asi,%0\n\twr %%g0,0x88,%%asi" : "=r" (sph_sparcv9_asi)); + +#define SPH_SPARCV9_RESET_ASI \ + __asm__ __volatile__ ("wr %%g0,%0,%%asi" : : "r" (sph_sparcv9_asi)); + +#define SPH_SPARCV9_DEC32LE(base, idx) ({ \ + sph_u32 sph_sparcv9_tmp; \ + __asm__ __volatile__ ("lda [%1+" #idx "*4]%%asi,%0" \ + : "=r" (sph_sparcv9_tmp) : "r" (base)); \ + sph_sparcv9_tmp; \ + }) + +#endif + +static SPH_INLINE void +sph_enc16be(void *dst, unsigned val) +{ + ((unsigned char *)dst)[0] = (val >> 8); + ((unsigned char *)dst)[1] = val; +} + +static SPH_INLINE unsigned +sph_dec16be(const void *src) +{ + return ((unsigned)(((const unsigned char *)src)[0]) << 8) + | (unsigned)(((const unsigned char *)src)[1]); +} + +static SPH_INLINE void +sph_enc16le(void *dst, unsigned val) +{ + ((unsigned char *)dst)[0] = val; + ((unsigned char *)dst)[1] = val >> 8; +} + +static SPH_INLINE unsigned +sph_dec16le(const void *src) +{ + return (unsigned)(((const unsigned char *)src)[0]) + | ((unsigned)(((const unsigned char *)src)[1]) << 8); +} + +/** + * Encode a 32-bit value into the provided buffer (big endian convention). + * + * @param dst the destination buffer + * @param val the 32-bit value to encode + */ +static SPH_INLINE void +sph_enc32be(void *dst, sph_u32 val) +{ +#if defined SPH_UPTR +#if SPH_UNALIGNED +#if SPH_LITTLE_ENDIAN + val = sph_bswap32(val); +#endif + *(sph_u32 *)dst = val; +#else + if (((SPH_UPTR)dst & 3) == 0) { +#if SPH_LITTLE_ENDIAN + val = sph_bswap32(val); +#endif + *(sph_u32 *)dst = val; + } else { + ((unsigned char *)dst)[0] = (val >> 24); + ((unsigned char *)dst)[1] = (val >> 16); + ((unsigned char *)dst)[2] = (val >> 8); + ((unsigned char *)dst)[3] = val; + } +#endif +#else + ((unsigned char *)dst)[0] = (val >> 24); + ((unsigned char *)dst)[1] = (val >> 16); + ((unsigned char *)dst)[2] = (val >> 8); + ((unsigned char *)dst)[3] = val; +#endif +} + +/** + * Encode a 32-bit value into the provided buffer (big endian convention). + * The destination buffer must be properly aligned. + * + * @param dst the destination buffer (32-bit aligned) + * @param val the value to encode + */ +static SPH_INLINE void +sph_enc32be_aligned(void *dst, sph_u32 val) +{ +#if SPH_LITTLE_ENDIAN + *(sph_u32 *)dst = sph_bswap32(val); +#elif SPH_BIG_ENDIAN + *(sph_u32 *)dst = val; +#else + ((unsigned char *)dst)[0] = (val >> 24); + ((unsigned char *)dst)[1] = (val >> 16); + ((unsigned char *)dst)[2] = (val >> 8); + ((unsigned char *)dst)[3] = val; +#endif +} + +/** + * Decode a 32-bit value from the provided buffer (big endian convention). + * + * @param src the source buffer + * @return the decoded value + */ +static SPH_INLINE sph_u32 +sph_dec32be(const void *src) +{ +#if defined SPH_UPTR +#if SPH_UNALIGNED +#if SPH_LITTLE_ENDIAN + return sph_bswap32(*(const sph_u32 *)src); +#else + return *(const sph_u32 *)src; +#endif +#else + if (((SPH_UPTR)src & 3) == 0) { +#if SPH_LITTLE_ENDIAN + return sph_bswap32(*(const sph_u32 *)src); +#else + return *(const sph_u32 *)src; +#endif + } else { + return ((sph_u32)(((const unsigned char *)src)[0]) << 24) + | ((sph_u32)(((const unsigned char *)src)[1]) << 16) + | ((sph_u32)(((const unsigned char *)src)[2]) << 8) + | (sph_u32)(((const unsigned char *)src)[3]); + } +#endif +#else + return ((sph_u32)(((const unsigned char *)src)[0]) << 24) + | ((sph_u32)(((const unsigned char *)src)[1]) << 16) + | ((sph_u32)(((const unsigned char *)src)[2]) << 8) + | (sph_u32)(((const unsigned char *)src)[3]); +#endif +} + +/** + * Decode a 32-bit value from the provided buffer (big endian convention). + * The source buffer must be properly aligned. + * + * @param src the source buffer (32-bit aligned) + * @return the decoded value + */ +static SPH_INLINE sph_u32 +sph_dec32be_aligned(const void *src) +{ +#if SPH_LITTLE_ENDIAN + return sph_bswap32(*(const sph_u32 *)src); +#elif SPH_BIG_ENDIAN + return *(const sph_u32 *)src; +#else + return ((sph_u32)(((const unsigned char *)src)[0]) << 24) + | ((sph_u32)(((const unsigned char *)src)[1]) << 16) + | ((sph_u32)(((const unsigned char *)src)[2]) << 8) + | (sph_u32)(((const unsigned char *)src)[3]); +#endif +} + +/** + * Encode a 32-bit value into the provided buffer (little endian convention). + * + * @param dst the destination buffer + * @param val the 32-bit value to encode + */ +static SPH_INLINE void +sph_enc32le(void *dst, sph_u32 val) +{ +#if defined SPH_UPTR +#if SPH_UNALIGNED +#if SPH_BIG_ENDIAN + val = sph_bswap32(val); +#endif + *(sph_u32 *)dst = val; +#else + if (((SPH_UPTR)dst & 3) == 0) { +#if SPH_BIG_ENDIAN + val = sph_bswap32(val); +#endif + *(sph_u32 *)dst = val; + } else { + ((unsigned char *)dst)[0] = val; + ((unsigned char *)dst)[1] = (val >> 8); + ((unsigned char *)dst)[2] = (val >> 16); + ((unsigned char *)dst)[3] = (val >> 24); + } +#endif +#else + ((unsigned char *)dst)[0] = val; + ((unsigned char *)dst)[1] = (val >> 8); + ((unsigned char *)dst)[2] = (val >> 16); + ((unsigned char *)dst)[3] = (val >> 24); +#endif +} + +/** + * Encode a 32-bit value into the provided buffer (little endian convention). + * The destination buffer must be properly aligned. + * + * @param dst the destination buffer (32-bit aligned) + * @param val the value to encode + */ +static SPH_INLINE void +sph_enc32le_aligned(void *dst, sph_u32 val) +{ +#if SPH_LITTLE_ENDIAN + *(sph_u32 *)dst = val; +#elif SPH_BIG_ENDIAN + *(sph_u32 *)dst = sph_bswap32(val); +#else + ((unsigned char *)dst)[0] = val; + ((unsigned char *)dst)[1] = (val >> 8); + ((unsigned char *)dst)[2] = (val >> 16); + ((unsigned char *)dst)[3] = (val >> 24); +#endif +} + +/** + * Decode a 32-bit value from the provided buffer (little endian convention). + * + * @param src the source buffer + * @return the decoded value + */ +static SPH_INLINE sph_u32 +sph_dec32le(const void *src) +{ +#if defined SPH_UPTR +#if SPH_UNALIGNED +#if SPH_BIG_ENDIAN + return sph_bswap32(*(const sph_u32 *)src); +#else + return *(const sph_u32 *)src; +#endif +#else + if (((SPH_UPTR)src & 3) == 0) { +#if SPH_BIG_ENDIAN +#if SPH_SPARCV9_GCC && !SPH_NO_ASM + sph_u32 tmp; + + /* + * "__volatile__" is needed here because without it, + * gcc-3.4.3 miscompiles the code and performs the + * access before the test on the address, thus triggering + * a bus error... + */ + __asm__ __volatile__ ( + "lda [%1]0x88,%0" : "=r" (tmp) : "r" (src)); + return tmp; +/* + * On PowerPC, this turns out not to be worth the effort: the inline + * assembly makes GCC optimizer uncomfortable, which tends to nullify + * the decoding gains. + * + * For most hash functions, using this inline assembly trick changes + * hashing speed by less than 5% and often _reduces_ it. The biggest + * gains are for MD4 (+11%) and CubeHash (+30%). For all others, it is + * less then 10%. The speed gain on CubeHash is probably due to the + * chronic shortage of registers that CubeHash endures; for the other + * functions, the generic code appears to be efficient enough already. + * +#elif (SPH_PPC32_GCC || SPH_PPC64_GCC) && !SPH_NO_ASM + sph_u32 tmp; + + __asm__ __volatile__ ( + "lwbrx %0,0,%1" : "=r" (tmp) : "r" (src)); + return tmp; + */ +#else + return sph_bswap32(*(const sph_u32 *)src); +#endif +#else + return *(const sph_u32 *)src; +#endif + } else { + return (sph_u32)(((const unsigned char *)src)[0]) + | ((sph_u32)(((const unsigned char *)src)[1]) << 8) + | ((sph_u32)(((const unsigned char *)src)[2]) << 16) + | ((sph_u32)(((const unsigned char *)src)[3]) << 24); + } +#endif +#else + return (sph_u32)(((const unsigned char *)src)[0]) + | ((sph_u32)(((const unsigned char *)src)[1]) << 8) + | ((sph_u32)(((const unsigned char *)src)[2]) << 16) + | ((sph_u32)(((const unsigned char *)src)[3]) << 24); +#endif +} + +/** + * Decode a 32-bit value from the provided buffer (little endian convention). + * The source buffer must be properly aligned. + * + * @param src the source buffer (32-bit aligned) + * @return the decoded value + */ +static SPH_INLINE sph_u32 +sph_dec32le_aligned(const void *src) +{ +#if SPH_LITTLE_ENDIAN + return *(const sph_u32 *)src; +#elif SPH_BIG_ENDIAN +#if SPH_SPARCV9_GCC && !SPH_NO_ASM + sph_u32 tmp; + + __asm__ __volatile__ ("lda [%1]0x88,%0" : "=r" (tmp) : "r" (src)); + return tmp; +/* + * Not worth it generally. + * +#elif (SPH_PPC32_GCC || SPH_PPC64_GCC) && !SPH_NO_ASM + sph_u32 tmp; + + __asm__ __volatile__ ("lwbrx %0,0,%1" : "=r" (tmp) : "r" (src)); + return tmp; + */ +#else + return sph_bswap32(*(const sph_u32 *)src); +#endif +#else + return (sph_u32)(((const unsigned char *)src)[0]) + | ((sph_u32)(((const unsigned char *)src)[1]) << 8) + | ((sph_u32)(((const unsigned char *)src)[2]) << 16) + | ((sph_u32)(((const unsigned char *)src)[3]) << 24); +#endif +} + +#if SPH_64 + +/** + * Encode a 64-bit value into the provided buffer (big endian convention). + * + * @param dst the destination buffer + * @param val the 64-bit value to encode + */ +static SPH_INLINE void +sph_enc64be(void *dst, sph_u64 val) +{ +#if defined SPH_UPTR +#if SPH_UNALIGNED +#if SPH_LITTLE_ENDIAN + val = sph_bswap64(val); +#endif + *(sph_u64 *)dst = val; +#else + if (((SPH_UPTR)dst & 7) == 0) { +#if SPH_LITTLE_ENDIAN + val = sph_bswap64(val); +#endif + *(sph_u64 *)dst = val; + } else { + ((unsigned char *)dst)[0] = (val >> 56); + ((unsigned char *)dst)[1] = (val >> 48); + ((unsigned char *)dst)[2] = (val >> 40); + ((unsigned char *)dst)[3] = (val >> 32); + ((unsigned char *)dst)[4] = (val >> 24); + ((unsigned char *)dst)[5] = (val >> 16); + ((unsigned char *)dst)[6] = (val >> 8); + ((unsigned char *)dst)[7] = val; + } +#endif +#else + ((unsigned char *)dst)[0] = (val >> 56); + ((unsigned char *)dst)[1] = (val >> 48); + ((unsigned char *)dst)[2] = (val >> 40); + ((unsigned char *)dst)[3] = (val >> 32); + ((unsigned char *)dst)[4] = (val >> 24); + ((unsigned char *)dst)[5] = (val >> 16); + ((unsigned char *)dst)[6] = (val >> 8); + ((unsigned char *)dst)[7] = val; +#endif +} + +/** + * Encode a 64-bit value into the provided buffer (big endian convention). + * The destination buffer must be properly aligned. + * + * @param dst the destination buffer (64-bit aligned) + * @param val the value to encode + */ +static SPH_INLINE void +sph_enc64be_aligned(void *dst, sph_u64 val) +{ +#if SPH_LITTLE_ENDIAN + *(sph_u64 *)dst = sph_bswap64(val); +#elif SPH_BIG_ENDIAN + *(sph_u64 *)dst = val; +#else + ((unsigned char *)dst)[0] = (val >> 56); + ((unsigned char *)dst)[1] = (val >> 48); + ((unsigned char *)dst)[2] = (val >> 40); + ((unsigned char *)dst)[3] = (val >> 32); + ((unsigned char *)dst)[4] = (val >> 24); + ((unsigned char *)dst)[5] = (val >> 16); + ((unsigned char *)dst)[6] = (val >> 8); + ((unsigned char *)dst)[7] = val; +#endif +} + +/** + * Decode a 64-bit value from the provided buffer (big endian convention). + * + * @param src the source buffer + * @return the decoded value + */ +static SPH_INLINE sph_u64 +sph_dec64be(const void *src) +{ +#if defined SPH_UPTR +#if SPH_UNALIGNED +#if SPH_LITTLE_ENDIAN + return sph_bswap64(*(const sph_u64 *)src); +#else + return *(const sph_u64 *)src; +#endif +#else + if (((SPH_UPTR)src & 7) == 0) { +#if SPH_LITTLE_ENDIAN + return sph_bswap64(*(const sph_u64 *)src); +#else + return *(const sph_u64 *)src; +#endif + } else { + return ((sph_u64)(((const unsigned char *)src)[0]) << 56) + | ((sph_u64)(((const unsigned char *)src)[1]) << 48) + | ((sph_u64)(((const unsigned char *)src)[2]) << 40) + | ((sph_u64)(((const unsigned char *)src)[3]) << 32) + | ((sph_u64)(((const unsigned char *)src)[4]) << 24) + | ((sph_u64)(((const unsigned char *)src)[5]) << 16) + | ((sph_u64)(((const unsigned char *)src)[6]) << 8) + | (sph_u64)(((const unsigned char *)src)[7]); + } +#endif +#else + return ((sph_u64)(((const unsigned char *)src)[0]) << 56) + | ((sph_u64)(((const unsigned char *)src)[1]) << 48) + | ((sph_u64)(((const unsigned char *)src)[2]) << 40) + | ((sph_u64)(((const unsigned char *)src)[3]) << 32) + | ((sph_u64)(((const unsigned char *)src)[4]) << 24) + | ((sph_u64)(((const unsigned char *)src)[5]) << 16) + | ((sph_u64)(((const unsigned char *)src)[6]) << 8) + | (sph_u64)(((const unsigned char *)src)[7]); +#endif +} + +/** + * Decode a 64-bit value from the provided buffer (big endian convention). + * The source buffer must be properly aligned. + * + * @param src the source buffer (64-bit aligned) + * @return the decoded value + */ +static SPH_INLINE sph_u64 +sph_dec64be_aligned(const void *src) +{ +#if SPH_LITTLE_ENDIAN + return sph_bswap64(*(const sph_u64 *)src); +#elif SPH_BIG_ENDIAN + return *(const sph_u64 *)src; +#else + return ((sph_u64)(((const unsigned char *)src)[0]) << 56) + | ((sph_u64)(((const unsigned char *)src)[1]) << 48) + | ((sph_u64)(((const unsigned char *)src)[2]) << 40) + | ((sph_u64)(((const unsigned char *)src)[3]) << 32) + | ((sph_u64)(((const unsigned char *)src)[4]) << 24) + | ((sph_u64)(((const unsigned char *)src)[5]) << 16) + | ((sph_u64)(((const unsigned char *)src)[6]) << 8) + | (sph_u64)(((const unsigned char *)src)[7]); +#endif +} + +/** + * Encode a 64-bit value into the provided buffer (little endian convention). + * + * @param dst the destination buffer + * @param val the 64-bit value to encode + */ +static SPH_INLINE void +sph_enc64le(void *dst, sph_u64 val) +{ +#if defined SPH_UPTR +#if SPH_UNALIGNED +#if SPH_BIG_ENDIAN + val = sph_bswap64(val); +#endif + *(sph_u64 *)dst = val; +#else + if (((SPH_UPTR)dst & 7) == 0) { +#if SPH_BIG_ENDIAN + val = sph_bswap64(val); +#endif + *(sph_u64 *)dst = val; + } else { + ((unsigned char *)dst)[0] = val; + ((unsigned char *)dst)[1] = (val >> 8); + ((unsigned char *)dst)[2] = (val >> 16); + ((unsigned char *)dst)[3] = (val >> 24); + ((unsigned char *)dst)[4] = (val >> 32); + ((unsigned char *)dst)[5] = (val >> 40); + ((unsigned char *)dst)[6] = (val >> 48); + ((unsigned char *)dst)[7] = (val >> 56); + } +#endif +#else + ((unsigned char *)dst)[0] = val; + ((unsigned char *)dst)[1] = (val >> 8); + ((unsigned char *)dst)[2] = (val >> 16); + ((unsigned char *)dst)[3] = (val >> 24); + ((unsigned char *)dst)[4] = (val >> 32); + ((unsigned char *)dst)[5] = (val >> 40); + ((unsigned char *)dst)[6] = (val >> 48); + ((unsigned char *)dst)[7] = (val >> 56); +#endif +} + +/** + * Encode a 64-bit value into the provided buffer (little endian convention). + * The destination buffer must be properly aligned. + * + * @param dst the destination buffer (64-bit aligned) + * @param val the value to encode + */ +static SPH_INLINE void +sph_enc64le_aligned(void *dst, sph_u64 val) +{ +#if SPH_LITTLE_ENDIAN + *(sph_u64 *)dst = val; +#elif SPH_BIG_ENDIAN + *(sph_u64 *)dst = sph_bswap64(val); +#else + ((unsigned char *)dst)[0] = val; + ((unsigned char *)dst)[1] = (val >> 8); + ((unsigned char *)dst)[2] = (val >> 16); + ((unsigned char *)dst)[3] = (val >> 24); + ((unsigned char *)dst)[4] = (val >> 32); + ((unsigned char *)dst)[5] = (val >> 40); + ((unsigned char *)dst)[6] = (val >> 48); + ((unsigned char *)dst)[7] = (val >> 56); +#endif +} + +/** + * Decode a 64-bit value from the provided buffer (little endian convention). + * + * @param src the source buffer + * @return the decoded value + */ +static SPH_INLINE sph_u64 +sph_dec64le(const void *src) +{ +#if defined SPH_UPTR +#if SPH_UNALIGNED +#if SPH_BIG_ENDIAN + return sph_bswap64(*(const sph_u64 *)src); +#else + return *(const sph_u64 *)src; +#endif +#else + if (((SPH_UPTR)src & 7) == 0) { +#if SPH_BIG_ENDIAN +#if SPH_SPARCV9_GCC_64 && !SPH_NO_ASM + sph_u64 tmp; + + __asm__ __volatile__ ( + "ldxa [%1]0x88,%0" : "=r" (tmp) : "r" (src)); + return tmp; +/* + * Not worth it generally. + * +#elif SPH_PPC32_GCC && !SPH_NO_ASM + return (sph_u64)sph_dec32le_aligned(src) + | ((sph_u64)sph_dec32le_aligned( + (const char *)src + 4) << 32); +#elif SPH_PPC64_GCC && !SPH_NO_ASM + sph_u64 tmp; + + __asm__ __volatile__ ( + "ldbrx %0,0,%1" : "=r" (tmp) : "r" (src)); + return tmp; + */ +#else + return sph_bswap64(*(const sph_u64 *)src); +#endif +#else + return *(const sph_u64 *)src; +#endif + } else { + return (sph_u64)(((const unsigned char *)src)[0]) + | ((sph_u64)(((const unsigned char *)src)[1]) << 8) + | ((sph_u64)(((const unsigned char *)src)[2]) << 16) + | ((sph_u64)(((const unsigned char *)src)[3]) << 24) + | ((sph_u64)(((const unsigned char *)src)[4]) << 32) + | ((sph_u64)(((const unsigned char *)src)[5]) << 40) + | ((sph_u64)(((const unsigned char *)src)[6]) << 48) + | ((sph_u64)(((const unsigned char *)src)[7]) << 56); + } +#endif +#else + return (sph_u64)(((const unsigned char *)src)[0]) + | ((sph_u64)(((const unsigned char *)src)[1]) << 8) + | ((sph_u64)(((const unsigned char *)src)[2]) << 16) + | ((sph_u64)(((const unsigned char *)src)[3]) << 24) + | ((sph_u64)(((const unsigned char *)src)[4]) << 32) + | ((sph_u64)(((const unsigned char *)src)[5]) << 40) + | ((sph_u64)(((const unsigned char *)src)[6]) << 48) + | ((sph_u64)(((const unsigned char *)src)[7]) << 56); +#endif +} + +/** + * Decode a 64-bit value from the provided buffer (little endian convention). + * The source buffer must be properly aligned. + * + * @param src the source buffer (64-bit aligned) + * @return the decoded value + */ +static SPH_INLINE sph_u64 +sph_dec64le_aligned(const void *src) +{ +#if SPH_LITTLE_ENDIAN + return *(const sph_u64 *)src; +#elif SPH_BIG_ENDIAN +#if SPH_SPARCV9_GCC_64 && !SPH_NO_ASM + sph_u64 tmp; + + __asm__ __volatile__ ("ldxa [%1]0x88,%0" : "=r" (tmp) : "r" (src)); + return tmp; +/* + * Not worth it generally. + * +#elif SPH_PPC32_GCC && !SPH_NO_ASM + return (sph_u64)sph_dec32le_aligned(src) + | ((sph_u64)sph_dec32le_aligned((const char *)src + 4) << 32); +#elif SPH_PPC64_GCC && !SPH_NO_ASM + sph_u64 tmp; + + __asm__ __volatile__ ("ldbrx %0,0,%1" : "=r" (tmp) : "r" (src)); + return tmp; + */ +#else + return sph_bswap64(*(const sph_u64 *)src); +#endif +#else + return (sph_u64)(((const unsigned char *)src)[0]) + | ((sph_u64)(((const unsigned char *)src)[1]) << 8) + | ((sph_u64)(((const unsigned char *)src)[2]) << 16) + | ((sph_u64)(((const unsigned char *)src)[3]) << 24) + | ((sph_u64)(((const unsigned char *)src)[4]) << 32) + | ((sph_u64)(((const unsigned char *)src)[5]) << 40) + | ((sph_u64)(((const unsigned char *)src)[6]) << 48) + | ((sph_u64)(((const unsigned char *)src)[7]) << 56); +#endif +} + +#endif + +#endif /* Doxygen excluded block */ + +#endif diff --git a/src/strlcpy.h b/src/strlcpy.h new file mode 100644 index 0000000..2cc786e --- /dev/null +++ b/src/strlcpy.h @@ -0,0 +1,90 @@ +/* + * Copyright (c) 1998 Todd C. Miller + * + * Permission to use, copy, modify, and 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. + */ +#ifndef BITCOIN_STRLCPY_H +#define BITCOIN_STRLCPY_H + +#include +#include + +/* + * Copy src to string dst of size siz. At most siz-1 characters + * will be copied. Always NUL terminates (unless siz == 0). + * Returns strlen(src); if retval >= siz, truncation occurred. + */ +inline size_t strlcpy(char *dst, const char *src, size_t siz) +{ + char *d = dst; + const char *s = src; + size_t n = siz; + + /* Copy as many bytes as will fit */ + if (n != 0) + { + while (--n != 0) + { + if ((*d++ = *s++) == '\0') + break; + } + } + + /* Not enough room in dst, add NUL and traverse rest of src */ + if (n == 0) + { + if (siz != 0) + *d = '\0'; /* NUL-terminate dst */ + while (*s++) + ; + } + + return(s - src - 1); /* count does not include NUL */ +} + +/* + * Appends src to string dst of size siz (unlike strncat, siz is the + * full size of dst, not space left). At most siz-1 characters + * will be copied. Always NUL terminates (unless siz <= strlen(dst)). + * Returns strlen(src) + MIN(siz, strlen(initial dst)). + * If retval >= siz, truncation occurred. + */ +inline size_t strlcat(char *dst, const char *src, size_t siz) +{ + char *d = dst; + const char *s = src; + size_t n = siz; + size_t dlen; + + /* Find the end of dst and adjust bytes left but don't go past end */ + while (n-- != 0 && *d != '\0') + d++; + dlen = d - dst; + n = siz - dlen; + + if (n == 0) + return(dlen + strlen(s)); + while (*s != '\0') + { + if (n != 1) + { + *d++ = *s; + n--; + } + s++; + } + *d = '\0'; + + return(dlen + (s - src)); /* count does not include NUL */ +} +#endif diff --git a/src/sync.cpp b/src/sync.cpp new file mode 100644 index 0000000..1ac4403 --- /dev/null +++ b/src/sync.cpp @@ -0,0 +1,128 @@ +// Copyright (c) 2011-2012 The Bitcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "sync.h" +#include "util.h" + +#include + +#ifdef DEBUG_LOCKCONTENTION +void PrintLockContention(const char* pszName, const char* pszFile, int nLine) +{ + printf("LOCKCONTENTION: %s\n", pszName); + printf("Locker: %s:%d\n", pszFile, nLine); +} +#endif /* DEBUG_LOCKCONTENTION */ + +#ifdef DEBUG_LOCKORDER +// +// Early deadlock detection. +// Problem being solved: +// Thread 1 locks A, then B, then C +// Thread 2 locks D, then C, then A +// --> may result in deadlock between the two threads, depending on when they run. +// Solution implemented here: +// Keep track of pairs of locks: (A before B), (A before C), etc. +// Complain if any thread tries to lock in a different order. +// + +struct CLockLocation +{ + CLockLocation(const char* pszName, const char* pszFile, int nLine) + { + mutexName = pszName; + sourceFile = pszFile; + sourceLine = nLine; + } + + std::string ToString() const + { + return mutexName+" "+sourceFile+":"+itostr(sourceLine); + } + +private: + std::string mutexName; + std::string sourceFile; + int sourceLine; +}; + +typedef std::vector< std::pair > LockStack; + +static boost::mutex dd_mutex; +static std::map, LockStack> lockorders; +static boost::thread_specific_ptr lockstack; + + +static void potential_deadlock_detected(const std::pair& mismatch, const LockStack& s1, const LockStack& s2) +{ + printf("POTENTIAL DEADLOCK DETECTED\n"); + printf("Previous lock order was:\n"); + BOOST_FOREACH(const PAIRTYPE(void*, CLockLocation)& i, s2) + { + if (i.first == mismatch.first) printf(" (1)"); + if (i.first == mismatch.second) printf(" (2)"); + printf(" %s\n", i.second.ToString().c_str()); + } + printf("Current lock order is:\n"); + BOOST_FOREACH(const PAIRTYPE(void*, CLockLocation)& i, s1) + { + if (i.first == mismatch.first) printf(" (1)"); + if (i.first == mismatch.second) printf(" (2)"); + printf(" %s\n", i.second.ToString().c_str()); + } +} + +static void push_lock(void* c, const CLockLocation& locklocation, bool fTry) +{ + if (lockstack.get() == NULL) + lockstack.reset(new LockStack); + + if (fDebug) printf("Locking: %s\n", locklocation.ToString().c_str()); + dd_mutex.lock(); + + (*lockstack).push_back(std::make_pair(c, locklocation)); + + if (!fTry) { + BOOST_FOREACH(const PAIRTYPE(void*, CLockLocation)& i, (*lockstack)) { + if (i.first == c) break; + + std::pair p1 = std::make_pair(i.first, c); + if (lockorders.count(p1)) + continue; + lockorders[p1] = (*lockstack); + + std::pair p2 = std::make_pair(c, i.first); + if (lockorders.count(p2)) + { + potential_deadlock_detected(p1, lockorders[p2], lockorders[p1]); + break; + } + } + } + dd_mutex.unlock(); +} + +static void pop_lock() +{ + if (fDebug) + { + const CLockLocation& locklocation = (*lockstack).rbegin()->second; + printf("Unlocked: %s\n", locklocation.ToString().c_str()); + } + dd_mutex.lock(); + (*lockstack).pop_back(); + dd_mutex.unlock(); +} + +void EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry) +{ + push_lock(cs, CLockLocation(pszName, pszFile, nLine), fTry); +} + +void LeaveCritical() +{ + pop_lock(); +} + +#endif /* DEBUG_LOCKORDER */ diff --git a/src/sync.h b/src/sync.h new file mode 100644 index 0000000..e80efbe --- /dev/null +++ b/src/sync.h @@ -0,0 +1,212 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2012 The Bitcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. +#ifndef BITCOIN_SYNC_H +#define BITCOIN_SYNC_H + +#include +#include +#include +#include + + + + +/** Wrapped boost mutex: supports recursive locking, but no waiting */ +typedef boost::recursive_mutex CCriticalSection; + +/** Wrapped boost mutex: supports waiting but not recursive locking */ +typedef boost::mutex CWaitableCriticalSection; + +#ifdef DEBUG_LOCKORDER +void EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry = false); +void LeaveCritical(); +#else +void static inline EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry = false) {} +void static inline LeaveCritical() {} +#endif + +#ifdef DEBUG_LOCKCONTENTION +void PrintLockContention(const char* pszName, const char* pszFile, int nLine); +#endif + +/** Wrapper around boost::unique_lock */ +template +class CMutexLock +{ +private: + boost::unique_lock lock; +public: + + void Enter(const char* pszName, const char* pszFile, int nLine) + { + if (!lock.owns_lock()) + { + EnterCritical(pszName, pszFile, nLine, (void*)(lock.mutex())); +#ifdef DEBUG_LOCKCONTENTION + if (!lock.try_lock()) + { + PrintLockContention(pszName, pszFile, nLine); +#endif + lock.lock(); +#ifdef DEBUG_LOCKCONTENTION + } +#endif + } + } + + void Leave() + { + if (lock.owns_lock()) + { + lock.unlock(); + LeaveCritical(); + } + } + + bool TryEnter(const char* pszName, const char* pszFile, int nLine) + { + if (!lock.owns_lock()) + { + EnterCritical(pszName, pszFile, nLine, (void*)(lock.mutex()), true); + lock.try_lock(); + if (!lock.owns_lock()) + LeaveCritical(); + } + return lock.owns_lock(); + } + + CMutexLock(Mutex& mutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) : lock(mutexIn, boost::defer_lock) + { + if (fTry) + TryEnter(pszName, pszFile, nLine); + else + Enter(pszName, pszFile, nLine); + } + + ~CMutexLock() + { + if (lock.owns_lock()) + LeaveCritical(); + } + + operator bool() + { + return lock.owns_lock(); + } + + boost::unique_lock &GetLock() + { + return lock; + } +}; + +typedef CMutexLock CCriticalBlock; + +#define LOCK(cs) CCriticalBlock criticalblock(cs, #cs, __FILE__, __LINE__) +#define LOCK2(cs1,cs2) CCriticalBlock criticalblock1(cs1, #cs1, __FILE__, __LINE__),criticalblock2(cs2, #cs2, __FILE__, __LINE__) +#define TRY_LOCK(cs,name) CCriticalBlock name(cs, #cs, __FILE__, __LINE__, true) + +#define ENTER_CRITICAL_SECTION(cs) \ + { \ + EnterCritical(#cs, __FILE__, __LINE__, (void*)(&cs)); \ + (cs).lock(); \ + } + +#define LEAVE_CRITICAL_SECTION(cs) \ + { \ + (cs).unlock(); \ + LeaveCritical(); \ + } + +class CSemaphore +{ +private: + boost::condition_variable condition; + boost::mutex mutex; + int value; + +public: + CSemaphore(int init) : value(init) {} + + void wait() { + boost::unique_lock lock(mutex); + while (value < 1) { + condition.wait(lock); + } + value--; + } + + bool try_wait() { + boost::unique_lock lock(mutex); + if (value < 1) + return false; + value--; + return true; + } + + void post() { + { + boost::unique_lock lock(mutex); + value++; + } + condition.notify_one(); + } +}; + +/** RAII-style semaphore lock */ +class CSemaphoreGrant +{ +private: + CSemaphore *sem; + bool fHaveGrant; + +public: + void Acquire() { + if (fHaveGrant) + return; + sem->wait(); + fHaveGrant = true; + } + + void Release() { + if (!fHaveGrant) + return; + sem->post(); + fHaveGrant = false; + } + + bool TryAcquire() { + if (!fHaveGrant && sem->try_wait()) + fHaveGrant = true; + return fHaveGrant; + } + + void MoveTo(CSemaphoreGrant &grant) { + grant.Release(); + grant.sem = sem; + grant.fHaveGrant = fHaveGrant; + sem = NULL; + fHaveGrant = false; + } + + CSemaphoreGrant() : sem(NULL), fHaveGrant(false) {} + + CSemaphoreGrant(CSemaphore &sema, bool fTry = false) : sem(&sema), fHaveGrant(false) { + if (fTry) + TryAcquire(); + else + Acquire(); + } + + ~CSemaphoreGrant() { + Release(); + } + + operator bool() { + return fHaveGrant; + } +}; +#endif + diff --git a/src/test/Checkpoints_tests.cpp b/src/test/Checkpoints_tests.cpp new file mode 100644 index 0000000..b14e9f7 --- /dev/null +++ b/src/test/Checkpoints_tests.cpp @@ -0,0 +1,34 @@ +// +// Unit tests for block-chain checkpoints +// +#include // for 'map_list_of()' +#include +#include + +#include "../checkpoints.h" +#include "../util.h" + +using namespace std; + +BOOST_AUTO_TEST_SUITE(Checkpoints_tests) + +BOOST_AUTO_TEST_CASE(sanity) +{ + uint256 p11111 = uint256("0x0000000069e244f73d78e8fd29ba2fd2ed618bd6fa2ee92559f542fdb26e7c1d"); + uint256 p134444 = uint256("0x00000000000005b12ffd4cd315cd34ffd4a594f430ac814c91184a0d42d2b0fe"); + BOOST_CHECK(Checkpoints::CheckBlock(11111, p11111)); + BOOST_CHECK(Checkpoints::CheckBlock(134444, p134444)); + + + // Wrong hashes at checkpoints should fail: + BOOST_CHECK(!Checkpoints::CheckBlock(11111, p134444)); + BOOST_CHECK(!Checkpoints::CheckBlock(134444, p11111)); + + // ... but any hash not at a checkpoint should succeed: + BOOST_CHECK(Checkpoints::CheckBlock(11111+1, p134444)); + BOOST_CHECK(Checkpoints::CheckBlock(134444+1, p11111)); + + BOOST_CHECK(Checkpoints::GetTotalBlocksEstimate() >= 134444); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/DoS_tests.cpp b/src/test/DoS_tests.cpp new file mode 100644 index 0000000..7f08dd5 --- /dev/null +++ b/src/test/DoS_tests.cpp @@ -0,0 +1,314 @@ +// +// Unit tests for denial-of-service detection/prevention code +// +#include + +#include // for 'map_list_of()' +#include +#include +#include + +#include "main.h" +#include "wallet.h" +#include "net.h" +#include "util.h" + +#include + +// Tests this internal-to-main.cpp method: +extern bool AddOrphanTx(const CDataStream& vMsg); +extern unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans); +extern std::map mapOrphanTransactions; +extern std::map > mapOrphanTransactionsByPrev; + +CService ip(uint32_t i) +{ + struct in_addr s; + s.s_addr = i; + return CService(CNetAddr(s), GetDefaultPort()); +} + +BOOST_AUTO_TEST_SUITE(DoS_tests) + +BOOST_AUTO_TEST_CASE(DoS_banning) +{ + CNode::ClearBanned(); + CAddress addr1(ip(0xa0b0c001)); + CNode dummyNode1(INVALID_SOCKET, addr1, "", true); + dummyNode1.Misbehaving(100); // Should get banned + BOOST_CHECK(CNode::IsBanned(addr1)); + BOOST_CHECK(!CNode::IsBanned(ip(0xa0b0c001|0x0000ff00))); // Different IP, not banned + + CAddress addr2(ip(0xa0b0c002)); + CNode dummyNode2(INVALID_SOCKET, addr2, "", true); + dummyNode2.Misbehaving(50); + BOOST_CHECK(!CNode::IsBanned(addr2)); // 2 not banned yet... + BOOST_CHECK(CNode::IsBanned(addr1)); // ... but 1 still should be + dummyNode2.Misbehaving(50); + BOOST_CHECK(CNode::IsBanned(addr2)); +} + +BOOST_AUTO_TEST_CASE(DoS_banscore) +{ + CNode::ClearBanned(); + mapArgs["-banscore"] = "111"; // because 11 is my favorite number + CAddress addr1(ip(0xa0b0c001)); + CNode dummyNode1(INVALID_SOCKET, addr1, "", true); + dummyNode1.Misbehaving(100); + BOOST_CHECK(!CNode::IsBanned(addr1)); + dummyNode1.Misbehaving(10); + BOOST_CHECK(!CNode::IsBanned(addr1)); + dummyNode1.Misbehaving(1); + BOOST_CHECK(CNode::IsBanned(addr1)); + mapArgs.erase("-banscore"); +} + +BOOST_AUTO_TEST_CASE(DoS_bantime) +{ + CNode::ClearBanned(); + int64 nStartTime = GetTime(); + SetMockTime(nStartTime); // Overrides future calls to GetTime() + + CAddress addr(ip(0xa0b0c001)); + CNode dummyNode(INVALID_SOCKET, addr, "", true); + + dummyNode.Misbehaving(100); + BOOST_CHECK(CNode::IsBanned(addr)); + + SetMockTime(nStartTime+60*60); + BOOST_CHECK(CNode::IsBanned(addr)); + + SetMockTime(nStartTime+60*60*24+1); + BOOST_CHECK(!CNode::IsBanned(addr)); +} + +static bool CheckNBits(unsigned int nbits1, int64 time1, unsigned int nbits2, int64 time2)\ +{ + if (time1 > time2) + return CheckNBits(nbits2, time2, nbits1, time1); + int64 deltaTime = time2-time1; + + CBigNum required; + required.SetCompact(ComputeMinWork(nbits1, deltaTime)); + CBigNum have; + have.SetCompact(nbits2); + return (have <= required); +} + +BOOST_AUTO_TEST_CASE(DoS_checknbits) +{ + using namespace boost::assign; // for 'map_list_of()' + + // Timestamps,nBits from the bitcoin blockchain. + // These are the block-chain checkpoint blocks + typedef std::map BlockData; + BlockData chainData = + map_list_of(1239852051,486604799)(1262749024,486594666) + (1279305360,469854461)(1280200847,469830746)(1281678674,469809688) + (1296207707,453179945)(1302624061,453036989)(1309640330,437004818) + (1313172719,436789733); + + // Make sure CheckNBits considers every combination of block-chain-lock-in-points + // "sane": + BOOST_FOREACH(const BlockData::value_type& i, chainData) + { + BOOST_FOREACH(const BlockData::value_type& j, chainData) + { + BOOST_CHECK(CheckNBits(i.second, i.first, j.second, j.first)); + } + } + + // Test a couple of insane combinations: + BlockData::value_type firstcheck = *(chainData.begin()); + BlockData::value_type lastcheck = *(chainData.rbegin()); + + // First checkpoint difficulty at or a while after the last checkpoint time should fail when + // compared to last checkpoint + BOOST_CHECK(!CheckNBits(firstcheck.second, lastcheck.first+60*10, lastcheck.second, lastcheck.first)); + BOOST_CHECK(!CheckNBits(firstcheck.second, lastcheck.first+60*60*24*14, lastcheck.second, lastcheck.first)); + + // ... but OK if enough time passed for difficulty to adjust downward: + BOOST_CHECK(CheckNBits(firstcheck.second, lastcheck.first+60*60*24*365*4, lastcheck.second, lastcheck.first)); + +} + +CTransaction RandomOrphan() +{ + std::map::iterator it; + it = mapOrphanTransactions.lower_bound(GetRandHash()); + if (it == mapOrphanTransactions.end()) + it = mapOrphanTransactions.begin(); + const CDataStream* pvMsg = it->second; + CTransaction tx; + CDataStream(*pvMsg) >> tx; + return tx; +} + +BOOST_AUTO_TEST_CASE(DoS_mapOrphans) +{ + CKey key; + key.MakeNewKey(true); + CBasicKeyStore keystore; + keystore.AddKey(key); + + // 50 orphan transactions: + for (int i = 0; i < 50; i++) + { + CTransaction tx; + tx.vin.resize(1); + tx.vin[0].prevout.n = 0; + tx.vin[0].prevout.hash = GetRandHash(); + tx.vin[0].scriptSig << OP_1; + tx.vout.resize(1); + tx.vout[0].nValue = 1*CENT; + tx.vout[0].scriptPubKey.SetDestination(key.GetPubKey().GetID()); + + CDataStream ds(SER_DISK, CLIENT_VERSION); + ds << tx; + AddOrphanTx(ds); + } + + // ... and 50 that depend on other orphans: + for (int i = 0; i < 50; i++) + { + CTransaction txPrev = RandomOrphan(); + + CTransaction tx; + tx.vin.resize(1); + tx.vin[0].prevout.n = 0; + tx.vin[0].prevout.hash = txPrev.GetHash(); + tx.vout.resize(1); + tx.vout[0].nValue = 1*CENT; + tx.vout[0].scriptPubKey.SetDestination(key.GetPubKey().GetID()); + SignSignature(keystore, txPrev, tx, 0); + + CDataStream ds(SER_DISK, CLIENT_VERSION); + ds << tx; + AddOrphanTx(ds); + } + + // This really-big orphan should be ignored: + for (int i = 0; i < 10; i++) + { + CTransaction txPrev = RandomOrphan(); + + CTransaction tx; + tx.vout.resize(1); + tx.vout[0].nValue = 1*CENT; + tx.vout[0].scriptPubKey.SetDestination(key.GetPubKey().GetID()); + tx.vin.resize(500); + for (unsigned int j = 0; j < tx.vin.size(); j++) + { + tx.vin[j].prevout.n = j; + tx.vin[j].prevout.hash = txPrev.GetHash(); + } + SignSignature(keystore, txPrev, tx, 0); + // Re-use same signature for other inputs + // (they don't have to be valid for this test) + for (unsigned int j = 1; j < tx.vin.size(); j++) + tx.vin[j].scriptSig = tx.vin[0].scriptSig; + + CDataStream ds(SER_DISK, CLIENT_VERSION); + ds << tx; + BOOST_CHECK(!AddOrphanTx(ds)); + } + + // Test LimitOrphanTxSize() function: + LimitOrphanTxSize(40); + BOOST_CHECK(mapOrphanTransactions.size() <= 40); + LimitOrphanTxSize(10); + BOOST_CHECK(mapOrphanTransactions.size() <= 10); + LimitOrphanTxSize(0); + BOOST_CHECK(mapOrphanTransactions.empty()); + BOOST_CHECK(mapOrphanTransactionsByPrev.empty()); +} + +BOOST_AUTO_TEST_CASE(DoS_checkSig) +{ + // Test signature caching code (see key.cpp Verify() methods) + + CKey key; + key.MakeNewKey(true); + CBasicKeyStore keystore; + keystore.AddKey(key); + + // 100 orphan transactions: + static const int NPREV=100; + CTransaction orphans[NPREV]; + for (int i = 0; i < NPREV; i++) + { + CTransaction& tx = orphans[i]; + tx.vin.resize(1); + tx.vin[0].prevout.n = 0; + tx.vin[0].prevout.hash = GetRandHash(); + tx.vin[0].scriptSig << OP_1; + tx.vout.resize(1); + tx.vout[0].nValue = 1*CENT; + tx.vout[0].scriptPubKey.SetDestination(key.GetPubKey().GetID()); + + CDataStream ds(SER_DISK, CLIENT_VERSION); + ds << tx; + AddOrphanTx(ds); + } + + // Create a transaction that depends on orphans: + CTransaction tx; + tx.vout.resize(1); + tx.vout[0].nValue = 1*CENT; + tx.vout[0].scriptPubKey.SetDestination(key.GetPubKey().GetID()); + tx.vin.resize(NPREV); + for (unsigned int j = 0; j < tx.vin.size(); j++) + { + tx.vin[j].prevout.n = 0; + tx.vin[j].prevout.hash = orphans[j].GetHash(); + } + // Creating signatures primes the cache: + boost::posix_time::ptime mst1 = boost::posix_time::microsec_clock::local_time(); + for (unsigned int j = 0; j < tx.vin.size(); j++) + BOOST_CHECK(SignSignature(keystore, orphans[j], tx, j)); + boost::posix_time::ptime mst2 = boost::posix_time::microsec_clock::local_time(); + boost::posix_time::time_duration msdiff = mst2 - mst1; + long nOneValidate = msdiff.total_milliseconds(); + if (fDebug) printf("DoS_Checksig sign: %ld\n", nOneValidate); + + // ... now validating repeatedly should be quick: + // 2.8GHz machine, -g build: Sign takes ~760ms, + // uncached Verify takes ~250ms, cached Verify takes ~50ms + // (for 100 single-signature inputs) + mst1 = boost::posix_time::microsec_clock::local_time(); + for (unsigned int i = 0; i < 5; i++) + for (unsigned int j = 0; j < tx.vin.size(); j++) + BOOST_CHECK(VerifySignature(orphans[j], tx, j, true, SIGHASH_ALL)); + mst2 = boost::posix_time::microsec_clock::local_time(); + msdiff = mst2 - mst1; + long nManyValidate = msdiff.total_milliseconds(); + if (fDebug) printf("DoS_Checksig five: %ld\n", nManyValidate); + + BOOST_CHECK_MESSAGE(nManyValidate < nOneValidate, "Signature cache timing failed"); + + // Empty a signature, validation should fail: + CScript save = tx.vin[0].scriptSig; + tx.vin[0].scriptSig = CScript(); + BOOST_CHECK(!VerifySignature(orphans[0], tx, 0, true, SIGHASH_ALL)); + tx.vin[0].scriptSig = save; + + // Swap signatures, validation should fail: + std::swap(tx.vin[0].scriptSig, tx.vin[1].scriptSig); + BOOST_CHECK(!VerifySignature(orphans[0], tx, 0, true, SIGHASH_ALL)); + BOOST_CHECK(!VerifySignature(orphans[1], tx, 1, true, SIGHASH_ALL)); + std::swap(tx.vin[0].scriptSig, tx.vin[1].scriptSig); + + // Exercise -maxsigcachesize code: + mapArgs["-maxsigcachesize"] = "10"; + // Generate a new, different signature for vin[0] to trigger cache clear: + CScript oldSig = tx.vin[0].scriptSig; + BOOST_CHECK(SignSignature(keystore, orphans[0], tx, 0)); + BOOST_CHECK(tx.vin[0].scriptSig != oldSig); + for (unsigned int j = 0; j < tx.vin.size(); j++) + BOOST_CHECK(VerifySignature(orphans[j], tx, j, true, SIGHASH_ALL)); + mapArgs.erase("-maxsigcachesize"); + + LimitOrphanTxSize(0); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/README b/src/test/README new file mode 100644 index 0000000..77f7faa --- /dev/null +++ b/src/test/README @@ -0,0 +1,21 @@ +The sources in this directory are unit test cases. Boost includes a +unit testing framework, and since bitcoin already uses boost, it makes +sense to simply use this framework rather than require developers to +configure some other framework (we want as few impediments to creating +unit tests as possible). + +The build system is setup to compile an executable called "test_bitcoin" +that runs all of the unit tests. The main source file is called +test_bitcoin.cpp, which simply includes other files that contain the +actual unit tests (outside of a couple required preprocessor +directives). The pattern is to create one test file for each class or +source file for which you want to create unit tests. The file naming +convention is "_tests.cpp" and such files should wrap +their tests in a test suite called "_tests". For an +examples of this pattern, examine uint160_tests.cpp and +uint256_tests.cpp. + +For further reading, I found the following website to be helpful in +explaining how the boost unit test framework works: + +http://www.alittlemadness.com/2009/03/31/c-unit-testing-with-boosttest/ diff --git a/src/test/accounting_tests.cpp b/src/test/accounting_tests.cpp new file mode 100644 index 0000000..8ac6572 --- /dev/null +++ b/src/test/accounting_tests.cpp @@ -0,0 +1,123 @@ +#include + +#include + +#include "init.h" +#include "wallet.h" +#include "walletdb.h" + +BOOST_AUTO_TEST_SUITE(accounting_tests) + +static void +GetResults(CWalletDB& walletdb, std::map& results) +{ + std::list aes; + + results.clear(); + BOOST_CHECK(walletdb.ReorderTransactions(pwalletMain) == DB_LOAD_OK); + walletdb.ListAccountCreditDebit("", aes); + BOOST_FOREACH(CAccountingEntry& ae, aes) + { + results[ae.nOrderPos] = ae; + } +} + +BOOST_AUTO_TEST_CASE(acc_orderupgrade) +{ + CWalletDB walletdb(pwalletMain->strWalletFile); + std::vector vpwtx; + CWalletTx wtx; + CAccountingEntry ae; + std::map results; + + ae.strAccount = ""; + ae.nCreditDebit = 1; + ae.nTime = 1333333333; + ae.strOtherAccount = "b"; + ae.strComment = ""; + walletdb.WriteAccountingEntry(ae); + + wtx.mapValue["comment"] = "z"; + pwalletMain->AddToWallet(wtx); + vpwtx.push_back(&pwalletMain->mapWallet[wtx.GetHash()]); + vpwtx[0]->nTimeReceived = (unsigned int)1333333335; + vpwtx[0]->nOrderPos = -1; + + ae.nTime = 1333333336; + ae.strOtherAccount = "c"; + walletdb.WriteAccountingEntry(ae); + + GetResults(walletdb, results); + + BOOST_CHECK(pwalletMain->nOrderPosNext == 3); + BOOST_CHECK(2 == results.size()); + BOOST_CHECK(results[0].nTime == 1333333333); + BOOST_CHECK(results[0].strComment.empty()); + BOOST_CHECK(1 == vpwtx[0]->nOrderPos); + BOOST_CHECK(results[2].nTime == 1333333336); + BOOST_CHECK(results[2].strOtherAccount == "c"); + + + ae.nTime = 1333333330; + ae.strOtherAccount = "d"; + ae.nOrderPos = pwalletMain->IncOrderPosNext(); + walletdb.WriteAccountingEntry(ae); + + GetResults(walletdb, results); + + BOOST_CHECK(results.size() == 3); + BOOST_CHECK(pwalletMain->nOrderPosNext == 4); + BOOST_CHECK(results[0].nTime == 1333333333); + BOOST_CHECK(1 == vpwtx[0]->nOrderPos); + BOOST_CHECK(results[2].nTime == 1333333336); + BOOST_CHECK(results[3].nTime == 1333333330); + BOOST_CHECK(results[3].strComment.empty()); + + + wtx.mapValue["comment"] = "y"; + --wtx.nLockTime; // Just to change the hash :) + pwalletMain->AddToWallet(wtx); + vpwtx.push_back(&pwalletMain->mapWallet[wtx.GetHash()]); + vpwtx[1]->nTimeReceived = (unsigned int)1333333336; + + wtx.mapValue["comment"] = "x"; + --wtx.nLockTime; // Just to change the hash :) + pwalletMain->AddToWallet(wtx); + vpwtx.push_back(&pwalletMain->mapWallet[wtx.GetHash()]); + vpwtx[2]->nTimeReceived = (unsigned int)1333333329; + vpwtx[2]->nOrderPos = -1; + + GetResults(walletdb, results); + + BOOST_CHECK(results.size() == 3); + BOOST_CHECK(pwalletMain->nOrderPosNext == 6); + BOOST_CHECK(0 == vpwtx[2]->nOrderPos); + BOOST_CHECK(results[1].nTime == 1333333333); + BOOST_CHECK(2 == vpwtx[0]->nOrderPos); + BOOST_CHECK(results[3].nTime == 1333333336); + BOOST_CHECK(results[4].nTime == 1333333330); + BOOST_CHECK(results[4].strComment.empty()); + BOOST_CHECK(5 == vpwtx[1]->nOrderPos); + + + ae.nTime = 1333333334; + ae.strOtherAccount = "e"; + ae.nOrderPos = -1; + walletdb.WriteAccountingEntry(ae); + + GetResults(walletdb, results); + + BOOST_CHECK(results.size() == 4); + BOOST_CHECK(pwalletMain->nOrderPosNext == 7); + BOOST_CHECK(0 == vpwtx[2]->nOrderPos); + BOOST_CHECK(results[1].nTime == 1333333333); + BOOST_CHECK(2 == vpwtx[0]->nOrderPos); + BOOST_CHECK(results[3].nTime == 1333333336); + BOOST_CHECK(results[3].strComment.empty()); + BOOST_CHECK(results[4].nTime == 1333333330); + BOOST_CHECK(results[4].strComment.empty()); + BOOST_CHECK(results[5].nTime == 1333333334); + BOOST_CHECK(6 == vpwtx[1]->nOrderPos); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/allocator_tests.cpp b/src/test/allocator_tests.cpp new file mode 100644 index 0000000..d5cb8e8 --- /dev/null +++ b/src/test/allocator_tests.cpp @@ -0,0 +1,115 @@ +#include + +#include "init.h" +#include "main.h" +#include "util.h" + +BOOST_AUTO_TEST_SUITE(allocator_tests) + +// Dummy memory page locker for platform independent tests +static const void *last_lock_addr, *last_unlock_addr; +static size_t last_lock_len, last_unlock_len; +class TestLocker +{ +public: + bool Lock(const void *addr, size_t len) + { + last_lock_addr = addr; + last_lock_len = len; + return true; + } + bool Unlock(const void *addr, size_t len) + { + last_unlock_addr = addr; + last_unlock_len = len; + return true; + } +}; + +BOOST_AUTO_TEST_CASE(test_LockedPageManagerBase) +{ + const size_t test_page_size = 4096; + LockedPageManagerBase lpm(test_page_size); + size_t addr; + last_lock_addr = last_unlock_addr = 0; + last_lock_len = last_unlock_len = 0; + + /* Try large number of small objects */ + addr = 0; + for(int i=0; i<1000; ++i) + { + lpm.LockRange(reinterpret_cast(addr), 33); + addr += 33; + } + /* Try small number of page-sized objects, straddling two pages */ + addr = test_page_size*100 + 53; + for(int i=0; i<100; ++i) + { + lpm.LockRange(reinterpret_cast(addr), test_page_size); + addr += test_page_size; + } + /* Try small number of page-sized objects aligned to exactly one page */ + addr = test_page_size*300; + for(int i=0; i<100; ++i) + { + lpm.LockRange(reinterpret_cast(addr), test_page_size); + addr += test_page_size; + } + /* one very large object, straddling pages */ + lpm.LockRange(reinterpret_cast(test_page_size*600+1), test_page_size*500); + BOOST_CHECK(last_lock_addr == reinterpret_cast(test_page_size*(600+500))); + /* one very large object, page aligned */ + lpm.LockRange(reinterpret_cast(test_page_size*1200), test_page_size*500-1); + BOOST_CHECK(last_lock_addr == reinterpret_cast(test_page_size*(1200+500-1))); + + BOOST_CHECK(lpm.GetLockedPageCount() == ( + (1000*33+test_page_size-1)/test_page_size + // small objects + 101 + 100 + // page-sized objects + 501 + 500)); // large objects + BOOST_CHECK((last_lock_len & (test_page_size-1)) == 0); // always lock entire pages + BOOST_CHECK(last_unlock_len == 0); // nothing unlocked yet + + /* And unlock again */ + addr = 0; + for(int i=0; i<1000; ++i) + { + lpm.UnlockRange(reinterpret_cast(addr), 33); + addr += 33; + } + addr = test_page_size*100 + 53; + for(int i=0; i<100; ++i) + { + lpm.UnlockRange(reinterpret_cast(addr), test_page_size); + addr += test_page_size; + } + addr = test_page_size*300; + for(int i=0; i<100; ++i) + { + lpm.UnlockRange(reinterpret_cast(addr), test_page_size); + addr += test_page_size; + } + lpm.UnlockRange(reinterpret_cast(test_page_size*600+1), test_page_size*500); + lpm.UnlockRange(reinterpret_cast(test_page_size*1200), test_page_size*500-1); + + /* Check that everything is released */ + BOOST_CHECK(lpm.GetLockedPageCount() == 0); + + /* A few and unlocks of size zero (should have no effect) */ + addr = 0; + for(int i=0; i<1000; ++i) + { + lpm.LockRange(reinterpret_cast(addr), 0); + addr += 1; + } + BOOST_CHECK(lpm.GetLockedPageCount() == 0); + addr = 0; + for(int i=0; i<1000; ++i) + { + lpm.UnlockRange(reinterpret_cast(addr), 0); + addr += 1; + } + BOOST_CHECK(lpm.GetLockedPageCount() == 0); + BOOST_CHECK((last_unlock_len & (test_page_size-1)) == 0); // always unlock entire pages +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/base32_tests.cpp b/src/test/base32_tests.cpp new file mode 100644 index 0000000..fdf3285 --- /dev/null +++ b/src/test/base32_tests.cpp @@ -0,0 +1,20 @@ +#include + +#include "util.h" + +BOOST_AUTO_TEST_SUITE(base32_tests) + +BOOST_AUTO_TEST_CASE(base32_testvectors) +{ + static const std::string vstrIn[] = {"","f","fo","foo","foob","fooba","foobar"}; + static const std::string vstrOut[] = {"","my======","mzxq====","mzxw6===","mzxw6yq=","mzxw6ytb","mzxw6ytboi======"}; + for (unsigned int i=0; i +#include "json/json_spirit_reader_template.h" +#include "json/json_spirit_writer_template.h" +#include "json/json_spirit_utils.h" + +#include "base58.h" +#include "util.h" + +using namespace json_spirit; +extern Array read_json(const std::string& filename); + +BOOST_AUTO_TEST_SUITE(base58_tests) + +// Goal: test low-level base58 encoding functionality +BOOST_AUTO_TEST_CASE(base58_EncodeBase58) +{ + Array tests = read_json("base58_encode_decode.json"); + + BOOST_FOREACH(Value& tv, tests) + { + Array test = tv.get_array(); + std::string strTest = write_string(tv, false); + if (test.size() < 2) // Allow for extra stuff (useful for comments) + { + BOOST_ERROR("Bad test: " << strTest); + continue; + } + std::vector sourcedata = ParseHex(test[0].get_str()); + std::string base58string = test[1].get_str(); + BOOST_CHECK_MESSAGE( + EncodeBase58(&sourcedata[0], &sourcedata[sourcedata.size()]) == base58string, + strTest); + } +} + +// Goal: test low-level base58 decoding functionality +BOOST_AUTO_TEST_CASE(base58_DecodeBase58) +{ + Array tests = read_json("base58_encode_decode.json"); + std::vector result; + + BOOST_FOREACH(Value& tv, tests) + { + Array test = tv.get_array(); + std::string strTest = write_string(tv, false); + if (test.size() < 2) // Allow for extra stuff (useful for comments) + { + BOOST_ERROR("Bad test: " << strTest); + continue; + } + std::vector expected = ParseHex(test[0].get_str()); + std::string base58string = test[1].get_str(); + BOOST_CHECK_MESSAGE(DecodeBase58(base58string, result), strTest); + BOOST_CHECK_MESSAGE(result.size() == expected.size() && std::equal(result.begin(), result.end(), expected.begin()), strTest); + } + + BOOST_CHECK(!DecodeBase58("invalid", result)); +} + +// Visitor to check address type +class TestAddrTypeVisitor : public boost::static_visitor +{ +private: + std::string exp_addrType; +public: + TestAddrTypeVisitor(const std::string &exp_addrType) : exp_addrType(exp_addrType) { } + bool operator()(const CKeyID &id) const + { + return (exp_addrType == "pubkey"); + } + bool operator()(const CScriptID &id) const + { + return (exp_addrType == "script"); + } + bool operator()(const CNoDestination &no) const + { + return (exp_addrType == "none"); + } +}; + +// Visitor to check address payload +class TestPayloadVisitor : public boost::static_visitor +{ +private: + std::vector exp_payload; +public: + TestPayloadVisitor(std::vector &exp_payload) : exp_payload(exp_payload) { } + bool operator()(const CKeyID &id) const + { + uint160 exp_key(exp_payload); + return exp_key == id; + } + bool operator()(const CScriptID &id) const + { + uint160 exp_key(exp_payload); + return exp_key == id; + } + bool operator()(const CNoDestination &no) const + { + return exp_payload.size() == 0; + } +}; + +// Goal: check that parsed keys match test payload +BOOST_AUTO_TEST_CASE(base58_keys_valid_parse) +{ + Array tests = read_json("base58_keys_valid.json"); + std::vector result; + CBitcoinSecret secret; + CBitcoinAddress addr; + // Save global state + bool fTestNet_stored = fTestNet; + + BOOST_FOREACH(Value& tv, tests) + { + Array test = tv.get_array(); + std::string strTest = write_string(tv, false); + if (test.size() < 3) // Allow for extra stuff (useful for comments) + { + BOOST_ERROR("Bad test: " << strTest); + continue; + } + std::string exp_base58string = test[0].get_str(); + std::vector exp_payload = ParseHex(test[1].get_str()); + const Object &metadata = test[2].get_obj(); + bool isPrivkey = find_value(metadata, "isPrivkey").get_bool(); + bool isTestnet = find_value(metadata, "isTestnet").get_bool(); + fTestNet = isTestnet; // Override testnet flag + if(isPrivkey) + { + bool isCompressed = find_value(metadata, "isCompressed").get_bool(); + // Must be valid private key + // Note: CBitcoinSecret::SetString tests isValid, whereas CBitcoinAddress does not! + BOOST_CHECK_MESSAGE(secret.SetString(exp_base58string), "!SetString:"+ strTest); + BOOST_CHECK_MESSAGE(secret.IsValid(), "!IsValid:" + strTest); + bool fCompressedOut = false; + CSecret privkey = secret.GetSecret(fCompressedOut); + BOOST_CHECK_MESSAGE(fCompressedOut == isCompressed, "compressed mismatch:" + strTest); + BOOST_CHECK_MESSAGE(privkey.size() == exp_payload.size() && std::equal(privkey.begin(), privkey.end(), exp_payload.begin()), "key mismatch:" + strTest); + + // Private key must be invalid public key + addr.SetString(exp_base58string); + BOOST_CHECK_MESSAGE(!addr.IsValid(), "IsValid privkey as pubkey:" + strTest); + } + else + { + std::string exp_addrType = find_value(metadata, "addrType").get_str(); // "script" or "pubkey" + // Must be valid public key + BOOST_CHECK_MESSAGE(addr.SetString(exp_base58string), "SetString:" + strTest); + BOOST_CHECK_MESSAGE(addr.IsValid(), "!IsValid:" + strTest); + BOOST_CHECK_MESSAGE(addr.IsScript() == (exp_addrType == "script"), "isScript mismatch" + strTest); + CTxDestination dest = addr.Get(); + BOOST_CHECK_MESSAGE(boost::apply_visitor(TestAddrTypeVisitor(exp_addrType), dest), "addrType mismatch" + strTest); + + // Public key must be invalid private key + secret.SetString(exp_base58string); + BOOST_CHECK_MESSAGE(!secret.IsValid(), "IsValid pubkey as privkey:" + strTest); + } + } + // Restore global state + fTestNet = fTestNet_stored; +} + +// Goal: check that generated keys match test vectors +BOOST_AUTO_TEST_CASE(base58_keys_valid_gen) +{ + Array tests = read_json("base58_keys_valid.json"); + std::vector result; + // Save global state + bool fTestNet_stored = fTestNet; + + BOOST_FOREACH(Value& tv, tests) + { + Array test = tv.get_array(); + std::string strTest = write_string(tv, false); + if (test.size() < 3) // Allow for extra stuff (useful for comments) + { + BOOST_ERROR("Bad test: " << strTest); + continue; + } + std::string exp_base58string = test[0].get_str(); + std::vector exp_payload = ParseHex(test[1].get_str()); + const Object &metadata = test[2].get_obj(); + bool isPrivkey = find_value(metadata, "isPrivkey").get_bool(); + bool isTestnet = find_value(metadata, "isTestnet").get_bool(); + fTestNet = isTestnet; // Override testnet flag + if(isPrivkey) + { + bool isCompressed = find_value(metadata, "isCompressed").get_bool(); + CBitcoinSecret secret; + secret.SetSecret(CSecret(exp_payload.begin(), exp_payload.end()), isCompressed); + BOOST_CHECK_MESSAGE(secret.ToString() == exp_base58string, "result mismatch: " + strTest); + } + else + { + std::string exp_addrType = find_value(metadata, "addrType").get_str(); + CTxDestination dest; + if(exp_addrType == "pubkey") + { + dest = CKeyID(uint160(exp_payload)); + } + else if(exp_addrType == "script") + { + dest = CScriptID(uint160(exp_payload)); + } + else if(exp_addrType == "none") + { + dest = CNoDestination(); + } + else + { + BOOST_ERROR("Bad addrtype: " << strTest); + continue; + } + CBitcoinAddress addrOut; + BOOST_CHECK_MESSAGE(boost::apply_visitor(CBitcoinAddressVisitor(&addrOut), dest), "encode dest: " + strTest); + BOOST_CHECK_MESSAGE(addrOut.ToString() == exp_base58string, "mismatch: " + strTest); + } + } + + // Visiting a CNoDestination must fail + CBitcoinAddress dummyAddr; + CTxDestination nodest = CNoDestination(); + BOOST_CHECK(!boost::apply_visitor(CBitcoinAddressVisitor(&dummyAddr), nodest)); + + // Restore global state + fTestNet = fTestNet_stored; +} + +// Goal: check that base58 parsing code is robust against a variety of corrupted data +BOOST_AUTO_TEST_CASE(base58_keys_invalid) +{ + Array tests = read_json("base58_keys_invalid.json"); // Negative testcases + std::vector result; + CBitcoinSecret secret; + CBitcoinAddress addr; + + BOOST_FOREACH(Value& tv, tests) + { + Array test = tv.get_array(); + std::string strTest = write_string(tv, false); + if (test.size() < 1) // Allow for extra stuff (useful for comments) + { + BOOST_ERROR("Bad test: " << strTest); + continue; + } + std::string exp_base58string = test[0].get_str(); + + // must be invalid as public and as private key + addr.SetString(exp_base58string); + BOOST_CHECK_MESSAGE(!addr.IsValid(), "IsValid pubkey:" + strTest); + secret.SetString(exp_base58string); + BOOST_CHECK_MESSAGE(!secret.IsValid(), "IsValid privkey:" + strTest); + } +} + + +BOOST_AUTO_TEST_SUITE_END() + diff --git a/src/test/base64_tests.cpp b/src/test/base64_tests.cpp new file mode 100644 index 0000000..c5a053e --- /dev/null +++ b/src/test/base64_tests.cpp @@ -0,0 +1,22 @@ +#include + +#include "main.h" +#include "wallet.h" +#include "util.h" + +BOOST_AUTO_TEST_SUITE(base64_tests) + +BOOST_AUTO_TEST_CASE(base64_testvectors) +{ + static const std::string vstrIn[] = {"","f","fo","foo","foob","fooba","foobar"}; + static const std::string vstrOut[] = {"","Zg==","Zm8=","Zm9v","Zm9vYg==","Zm9vYmE=","Zm9vYmFy"}; + for (unsigned int i=0; i +#include + +#include "bignum.h" +#include "util.h" + +BOOST_AUTO_TEST_SUITE(bignum_tests) + +// Unfortunately there's no standard way of preventing a function from being +// inlined, so we define a macro for it. +// +// You should use it like this: +// NOINLINE void function() {...} +#if defined(__GNUC__) +// This also works and will be defined for any compiler implementing GCC +// extensions, such as Clang and ICC. +#define NOINLINE __attribute__((noinline)) +#elif defined(_MSC_VER) +#define NOINLINE __declspec(noinline) +#else +// We give out a warning because it impacts the correctness of one bignum test. +#warning You should define NOINLINE for your compiler. +#define NOINLINE +#endif + +// For the following test case, it is useful to use additional tools. +// +// The simplest one to use is the compiler flag -ftrapv, which detects integer +// overflows and similar errors. However, due to optimizations and compilers +// taking advantage of undefined behavior sometimes it may not actually detect +// anything. +// +// You can also use compiler-based stack protection to possibly detect possible +// stack buffer overruns. +// +// For more accurate diagnostics, you can use an undefined arithmetic operation +// detector such as the clang-based tool: +// +// "IOC: An Integer Overflow Checker for C/C++" +// +// Available at: http://embed.cs.utah.edu/ioc/ +// +// It might also be useful to use Google's AddressSanitizer to detect +// stack buffer overruns, which valgrind can't currently detect. + +// Let's force this code not to be inlined, in order to actually +// test a generic version of the function. This increases the chance +// that -ftrapv will detect overflows. +NOINLINE void mysetint64(CBigNum& num, int64 n) +{ + num.setint64(n); +} + +// For each number, we do 2 tests: one with inline code, then we reset the +// value to 0, then the second one with a non-inlined function. +BOOST_AUTO_TEST_CASE(bignum_setint64) +{ + int64 n; + + { + n = 0; + CBigNum num(n); + BOOST_CHECK(num.ToString() == "0"); + num.setulong(0); + BOOST_CHECK(num.ToString() == "0"); + mysetint64(num, n); + BOOST_CHECK(num.ToString() == "0"); + } + { + n = 1; + CBigNum num(n); + BOOST_CHECK(num.ToString() == "1"); + num.setulong(0); + BOOST_CHECK(num.ToString() == "0"); + mysetint64(num, n); + BOOST_CHECK(num.ToString() == "1"); + } + { + n = -1; + CBigNum num(n); + BOOST_CHECK(num.ToString() == "-1"); + num.setulong(0); + BOOST_CHECK(num.ToString() == "0"); + mysetint64(num, n); + BOOST_CHECK(num.ToString() == "-1"); + } + { + n = 5; + CBigNum num(n); + BOOST_CHECK(num.ToString() == "5"); + num.setulong(0); + BOOST_CHECK(num.ToString() == "0"); + mysetint64(num, n); + BOOST_CHECK(num.ToString() == "5"); + } + { + n = -5; + CBigNum num(n); + BOOST_CHECK(num.ToString() == "-5"); + num.setulong(0); + BOOST_CHECK(num.ToString() == "0"); + mysetint64(num, n); + BOOST_CHECK(num.ToString() == "-5"); + } + { + n = std::numeric_limits::min(); + CBigNum num(n); + BOOST_CHECK(num.ToString() == "-9223372036854775808"); + num.setulong(0); + BOOST_CHECK(num.ToString() == "0"); + mysetint64(num, n); + BOOST_CHECK(num.ToString() == "-9223372036854775808"); + } + { + n = std::numeric_limits::max(); + CBigNum num(n); + BOOST_CHECK(num.ToString() == "9223372036854775807"); + num.setulong(0); + BOOST_CHECK(num.ToString() == "0"); + mysetint64(num, n); + BOOST_CHECK(num.ToString() == "9223372036854775807"); + } +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/data/base58_encode_decode.json b/src/test/data/base58_encode_decode.json new file mode 100644 index 0000000..9448f25 --- /dev/null +++ b/src/test/data/base58_encode_decode.json @@ -0,0 +1,14 @@ +[ +["", ""], +["61", "2g"], +["626262", "a3gV"], +["636363", "aPEr"], +["73696d706c792061206c6f6e6720737472696e67", "2cFupjhnEsSn59qHXstmK2ffpLv2"], +["00eb15231dfceb60925886b67d065299925915aeb172c06647", "1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L"], +["516b6fcd0f", "ABnLTmg"], +["bf4f89001e670274dd", "3SEo3LWLoPntC"], +["572e4794", "3EFU7m"], +["ecac89cad93923c02321", "EJDM8drfXA6uyA"], +["10c8511e", "Rt5zm"], +["00000000000000000000", "1111111111"] +] diff --git a/src/test/data/base58_keys_invalid.json b/src/test/data/base58_keys_invalid.json new file mode 100644 index 0000000..a088620 --- /dev/null +++ b/src/test/data/base58_keys_invalid.json @@ -0,0 +1,152 @@ +[ + [ + "" + ], + [ + "x" + ], + [ + "37qgekLpCCHrQuSjvX3fs496FWTGsHFHizjJAs6NPcR47aefnnCWECAhHV6E3g4YN7u7Yuwod5Y" + ], + [ + "dzb7VV1Ui55BARxv7ATxAtCUeJsANKovDGWFVgpTbhq9gvPqP3yv" + ], + [ + "MuNu7ZAEDFiHthiunm7dPjwKqrVNCM3mAz6rP9zFveQu14YA8CxExSJTHcVP9DErn6u84E6Ej7S" + ], + [ + "rPpQpYknyNQ5AEHuY6H8ijJJrYc2nDKKk9jjmKEXsWzyAQcFGpDLU2Zvsmoi8JLR7hAwoy3RQWf" + ], + [ + "4Uc3FmN6NQ6zLBK5QQBXRBUREaaHwCZYsGCueHauuDmJpZKn6jkEskMB2Zi2CNgtb5r6epWEFfUJq" + ], + [ + "7aQgR5DFQ25vyXmqZAWmnVCjL3PkBcdVkBUpjrjMTcghHx3E8wb" + ], + [ + "17QpPprjeg69fW1DV8DcYYCKvWjYhXvWkov6MJ1iTTvMFj6weAqW7wybZeH57WTNxXVCRH4veVs" + ], + [ + "KxuACDviz8Xvpn1xAh9MfopySZNuyajYMZWz16Dv2mHHryznWUp3" + ], + [ + "7nK3GSmqdXJQtdohvGfJ7KsSmn3TmGqExug49583bDAL91pVSGq5xS9SHoAYL3Wv3ijKTit65th" + ], + [ + "cTivdBmq7bay3RFGEBBuNfMh2P1pDCgRYN2Wbxmgwr4ki3jNUL2va" + ], + [ + "gjMV4vjNjyMrna4fsAr8bWxAbwtmMUBXJS3zL4NJt5qjozpbQLmAfK1uA3CquSqsZQMpoD1g2nk" + ], + [ + "emXm1naBMoVzPjbk7xpeTVMFy4oDEe25UmoyGgKEB1gGWsK8kRGs" + ], + [ + "7VThQnNRj1o3Zyvc7XHPRrjDf8j2oivPTeDXnRPYWeYGE4pXeRJDZgf28ppti5hsHWXS2GSobdqyo" + ], + [ + "1G9u6oCVCPh2o8m3t55ACiYvG1y5BHewUkDSdiQarDcYXXhFHYdzMdYfUAhfxn5vNZBwpgUNpso" + ], + [ + "31QQ7ZMLkScDiB4VyZjuptr7AEc9j1SjstF7pRoLhHTGkW4Q2y9XELobQmhhWxeRvqcukGd1XCq" + ], + [ + "DHqKSnpxa8ZdQyH8keAhvLTrfkyBMQxqngcQA5N8LQ9KVt25kmGN" + ], + [ + "2LUHcJPbwLCy9GLH1qXmfmAwvadWw4bp4PCpDfduLqV17s6iDcy1imUwhQJhAoNoN1XNmweiJP4i" + ], + [ + "7USRzBXAnmck8fX9HmW7RAb4qt92VFX6soCnts9s74wxm4gguVhtG5of8fZGbNPJA83irHVY6bCos" + ], + [ + "1DGezo7BfVebZxAbNT3XGujdeHyNNBF3vnficYoTSp4PfK2QaML9bHzAMxke3wdKdHYWmsMTJVu" + ], + [ + "2D12DqDZKwCxxkzs1ZATJWvgJGhQ4cFi3WrizQ5zLAyhN5HxuAJ1yMYaJp8GuYsTLLxTAz6otCfb" + ], + [ + "8AFJzuTujXjw1Z6M3fWhQ1ujDW7zsV4ePeVjVo7D1egERqSW9nZ" + ], + [ + "163Q17qLbTCue8YY3AvjpUhotuaodLm2uqMhpYirsKjVqnxJRWTEoywMVY3NbBAHuhAJ2cF9GAZ" + ], + [ + "2MnmgiRH4eGLyLc9eAqStzk7dFgBjFtUCtu" + ], + [ + "461QQ2sYWxU7H2PV4oBwJGNch8XVTYYbZxU" + ], + [ + "2UCtv53VttmQYkVU4VMtXB31REvQg4ABzs41AEKZ8UcB7DAfVzdkV9JDErwGwyj5AUHLkmgZeobs" + ], + [ + "cSNjAsnhgtiFMi6MtfvgscMB2Cbhn2v1FUYfviJ1CdjfidvmeW6mn" + ], + [ + "gmsow2Y6EWAFDFE1CE4Hd3Tpu2BvfmBfG1SXsuRARbnt1WjkZnFh1qGTiptWWbjsq2Q6qvpgJVj" + ], + [ + "nksUKSkzS76v8EsSgozXGMoQFiCoCHzCVajFKAXqzK5on9ZJYVHMD5CKwgmX3S3c7M1U3xabUny" + ], + [ + "L3favK1UzFGgdzYBF2oBT5tbayCo4vtVBLJhg2iYuMeePxWG8SQc" + ], + [ + "7VxLxGGtYT6N99GdEfi6xz56xdQ8nP2dG1CavuXx7Rf2PrvNMTBNevjkfgs9JmkcGm6EXpj8ipyPZ" + ], + [ + "2mbZwFXF6cxShaCo2czTRB62WTx9LxhTtpP" + ], + [ + "dB7cwYdcPSgiyAwKWL3JwCVwSk6epU2txw" + ], + [ + "HPhFUhUAh8ZQQisH8QQWafAxtQYju3SFTX" + ], + [ + "4ctAH6AkHzq5ioiM1m9T3E2hiYEev5mTsB" + ], + [ + "Hn1uFi4dNexWrqARpjMqgT6cX1UsNPuV3cHdGg9ExyXw8HTKadbktRDtdeVmY3M1BxJStiL4vjJ" + ], + [ + "Sq3fDbvutABmnAHHExJDgPLQn44KnNC7UsXuT7KZecpaYDMU9Txs" + ], + [ + "6TqWyrqdgUEYDQU1aChMuFMMEimHX44qHFzCUgGfqxGgZNMUVWJ" + ], + [ + "giqJo7oWqFxNKWyrgcBxAVHXnjJ1t6cGoEffce5Y1y7u649Noj5wJ4mmiUAKEVVrYAGg2KPB3Y4" + ], + [ + "cNzHY5e8vcmM3QVJUcjCyiKMYfeYvyueq5qCMV3kqcySoLyGLYUK" + ], + [ + "37uTe568EYc9WLoHEd9jXEvUiWbq5LFLscNyqvAzLU5vBArUJA6eydkLmnMwJDjkL5kXc2VK7ig" + ], + [ + "EsYbG4tWWWY45G31nox838qNdzksbPySWc" + ], + [ + "nbuzhfwMoNzA3PaFnyLcRxE9bTJPDkjZ6Rf6Y6o2ckXZfzZzXBT" + ], + [ + "cQN9PoxZeCWK1x56xnz6QYAsvR11XAce3Ehp3gMUdfSQ53Y2mPzx" + ], + [ + "1Gm3N3rkef6iMbx4voBzaxtXcmmiMTqZPhcuAepRzYUJQW4qRpEnHvMojzof42hjFRf8PE2jPde" + ], + [ + "2TAq2tuN6x6m233bpT7yqdYQPELdTDJn1eU" + ], + [ + "ntEtnnGhqPii4joABvBtSEJG6BxjT2tUZqE8PcVYgk3RHpgxgHDCQxNbLJf7ardf1dDk2oCQ7Cf" + ], + [ + "Ky1YjoZNgQ196HJV3HpdkecfhRBmRZdMJk89Hi5KGfpfPwS2bUbfd" + ], + [ + "2A1q1YsMZowabbvta7kTy2Fd6qN4r5ZCeG3qLpvZBMzCixMUdkN2Y4dHB1wPsZAeVXUGD83MfRED" + ] +] diff --git a/src/test/data/base58_keys_valid.json b/src/test/data/base58_keys_valid.json new file mode 100644 index 0000000..e1e252e --- /dev/null +++ b/src/test/data/base58_keys_valid.json @@ -0,0 +1,452 @@ +[ + [ + "1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i", + "65a16059864a2fdbc7c99a4723a8395bc6f188eb", + { + "addrType": "pubkey", + "isPrivkey": false, + "isTestnet": false + } + ], + [ + "3CMNFxN1oHBc4R1EpboAL5yzHGgE611Xou", + "74f209f6ea907e2ea48f74fae05782ae8a665257", + { + "addrType": "script", + "isPrivkey": false, + "isTestnet": false + } + ], + [ + "mo9ncXisMeAoXwqcV5EWuyncbmCcQN4rVs", + "53c0307d6851aa0ce7825ba883c6bd9ad242b486", + { + "addrType": "pubkey", + "isPrivkey": false, + "isTestnet": true + } + ], + [ + "2N2JD6wb56AfK4tfmM6PwdVmoYk2dCKf4Br", + "6349a418fc4578d10a372b54b45c280cc8c4382f", + { + "addrType": "script", + "isPrivkey": false, + "isTestnet": true + } + ], + [ + "5Kd3NBUAdUnhyzenEwVLy9pBKxSwXvE9FMPyR4UKZvpe6E3AgLr", + "eddbdc1168f1daeadbd3e44c1e3f8f5a284c2029f78ad26af98583a499de5b19", + { + "isCompressed": false, + "isPrivkey": true, + "isTestnet": false + } + ], + [ + "Kz6UJmQACJmLtaQj5A3JAge4kVTNQ8gbvXuwbmCj7bsaabudb3RD", + "55c9bccb9ed68446d1b75273bbce89d7fe013a8acd1625514420fb2aca1a21c4", + { + "isCompressed": true, + "isPrivkey": true, + "isTestnet": false + } + ], + [ + "9213qJab2HNEpMpYNBa7wHGFKKbkDn24jpANDs2huN3yi4J11ko", + "36cb93b9ab1bdabf7fb9f2c04f1b9cc879933530ae7842398eef5a63a56800c2", + { + "isCompressed": false, + "isPrivkey": true, + "isTestnet": true + } + ], + [ + "cTpB4YiyKiBcPxnefsDpbnDxFDffjqJob8wGCEDXxgQ7zQoMXJdH", + "b9f4892c9e8282028fea1d2667c4dc5213564d41fc5783896a0d843fc15089f3", + { + "isCompressed": true, + "isPrivkey": true, + "isTestnet": true + } + ], + [ + "1Ax4gZtb7gAit2TivwejZHYtNNLT18PUXJ", + "6d23156cbbdcc82a5a47eee4c2c7c583c18b6bf4", + { + "addrType": "pubkey", + "isPrivkey": false, + "isTestnet": false + } + ], + [ + "3QjYXhTkvuj8qPaXHTTWb5wjXhdsLAAWVy", + "fcc5460dd6e2487c7d75b1963625da0e8f4c5975", + { + "addrType": "script", + "isPrivkey": false, + "isTestnet": false + } + ], + [ + "n3ZddxzLvAY9o7184TB4c6FJasAybsw4HZ", + "f1d470f9b02370fdec2e6b708b08ac431bf7a5f7", + { + "addrType": "pubkey", + "isPrivkey": false, + "isTestnet": true + } + ], + [ + "2NBFNJTktNa7GZusGbDbGKRZTxdK9VVez3n", + "c579342c2c4c9220205e2cdc285617040c924a0a", + { + "addrType": "script", + "isPrivkey": false, + "isTestnet": true + } + ], + [ + "5K494XZwps2bGyeL71pWid4noiSNA2cfCibrvRWqcHSptoFn7rc", + "a326b95ebae30164217d7a7f57d72ab2b54e3be64928a19da0210b9568d4015e", + { + "isCompressed": false, + "isPrivkey": true, + "isTestnet": false + } + ], + [ + "L1RrrnXkcKut5DEMwtDthjwRcTTwED36thyL1DebVrKuwvohjMNi", + "7d998b45c219a1e38e99e7cbd312ef67f77a455a9b50c730c27f02c6f730dfb4", + { + "isCompressed": true, + "isPrivkey": true, + "isTestnet": false + } + ], + [ + "93DVKyFYwSN6wEo3E2fCrFPUp17FtrtNi2Lf7n4G3garFb16CRj", + "d6bca256b5abc5602ec2e1c121a08b0da2556587430bcf7e1898af2224885203", + { + "isCompressed": false, + "isPrivkey": true, + "isTestnet": true + } + ], + [ + "cTDVKtMGVYWTHCb1AFjmVbEbWjvKpKqKgMaR3QJxToMSQAhmCeTN", + "a81ca4e8f90181ec4b61b6a7eb998af17b2cb04de8a03b504b9e34c4c61db7d9", + { + "isCompressed": true, + "isPrivkey": true, + "isTestnet": true + } + ], + [ + "1C5bSj1iEGUgSTbziymG7Cn18ENQuT36vv", + "7987ccaa53d02c8873487ef919677cd3db7a6912", + { + "addrType": "pubkey", + "isPrivkey": false, + "isTestnet": false + } + ], + [ + "3AnNxabYGoTxYiTEZwFEnerUoeFXK2Zoks", + "63bcc565f9e68ee0189dd5cc67f1b0e5f02f45cb", + { + "addrType": "script", + "isPrivkey": false, + "isTestnet": false + } + ], + [ + "n3LnJXCqbPjghuVs8ph9CYsAe4Sh4j97wk", + "ef66444b5b17f14e8fae6e7e19b045a78c54fd79", + { + "addrType": "pubkey", + "isPrivkey": false, + "isTestnet": true + } + ], + [ + "2NB72XtkjpnATMggui83aEtPawyyKvnbX2o", + "c3e55fceceaa4391ed2a9677f4a4d34eacd021a0", + { + "addrType": "script", + "isPrivkey": false, + "isTestnet": true + } + ], + [ + "5KaBW9vNtWNhc3ZEDyNCiXLPdVPHCikRxSBWwV9NrpLLa4LsXi9", + "e75d936d56377f432f404aabb406601f892fd49da90eb6ac558a733c93b47252", + { + "isCompressed": false, + "isPrivkey": true, + "isTestnet": false + } + ], + [ + "L1axzbSyynNYA8mCAhzxkipKkfHtAXYF4YQnhSKcLV8YXA874fgT", + "8248bd0375f2f75d7e274ae544fb920f51784480866b102384190b1addfbaa5c", + { + "isCompressed": true, + "isPrivkey": true, + "isTestnet": false + } + ], + [ + "927CnUkUbasYtDwYwVn2j8GdTuACNnKkjZ1rpZd2yBB1CLcnXpo", + "44c4f6a096eac5238291a94cc24c01e3b19b8d8cef72874a079e00a242237a52", + { + "isCompressed": false, + "isPrivkey": true, + "isTestnet": true + } + ], + [ + "cUcfCMRjiQf85YMzzQEk9d1s5A4K7xL5SmBCLrezqXFuTVefyhY7", + "d1de707020a9059d6d3abaf85e17967c6555151143db13dbb06db78df0f15c69", + { + "isCompressed": true, + "isPrivkey": true, + "isTestnet": true + } + ], + [ + "1Gqk4Tv79P91Cc1STQtU3s1W6277M2CVWu", + "adc1cc2081a27206fae25792f28bbc55b831549d", + { + "addrType": "pubkey", + "isPrivkey": false, + "isTestnet": false + } + ], + [ + "33vt8ViH5jsr115AGkW6cEmEz9MpvJSwDk", + "188f91a931947eddd7432d6e614387e32b244709", + { + "addrType": "script", + "isPrivkey": false, + "isTestnet": false + } + ], + [ + "mhaMcBxNh5cqXm4aTQ6EcVbKtfL6LGyK2H", + "1694f5bc1a7295b600f40018a618a6ea48eeb498", + { + "addrType": "pubkey", + "isPrivkey": false, + "isTestnet": true + } + ], + [ + "2MxgPqX1iThW3oZVk9KoFcE5M4JpiETssVN", + "3b9b3fd7a50d4f08d1a5b0f62f644fa7115ae2f3", + { + "addrType": "script", + "isPrivkey": false, + "isTestnet": true + } + ], + [ + "5HtH6GdcwCJA4ggWEL1B3jzBBUB8HPiBi9SBc5h9i4Wk4PSeApR", + "091035445ef105fa1bb125eccfb1882f3fe69592265956ade751fd095033d8d0", + { + "isCompressed": false, + "isPrivkey": true, + "isTestnet": false + } + ], + [ + "L2xSYmMeVo3Zek3ZTsv9xUrXVAmrWxJ8Ua4cw8pkfbQhcEFhkXT8", + "ab2b4bcdfc91d34dee0ae2a8c6b6668dadaeb3a88b9859743156f462325187af", + { + "isCompressed": true, + "isPrivkey": true, + "isTestnet": false + } + ], + [ + "92xFEve1Z9N8Z641KQQS7ByCSb8kGjsDzw6fAmjHN1LZGKQXyMq", + "b4204389cef18bbe2b353623cbf93e8678fbc92a475b664ae98ed594e6cf0856", + { + "isCompressed": false, + "isPrivkey": true, + "isTestnet": true + } + ], + [ + "cVM65tdYu1YK37tNoAyGoJTR13VBYFva1vg9FLuPAsJijGvG6NEA", + "e7b230133f1b5489843260236b06edca25f66adb1be455fbd38d4010d48faeef", + { + "isCompressed": true, + "isPrivkey": true, + "isTestnet": true + } + ], + [ + "1JwMWBVLtiqtscbaRHai4pqHokhFCbtoB4", + "c4c1b72491ede1eedaca00618407ee0b772cad0d", + { + "addrType": "pubkey", + "isPrivkey": false, + "isTestnet": false + } + ], + [ + "3QCzvfL4ZRvmJFiWWBVwxfdaNBT8EtxB5y", + "f6fe69bcb548a829cce4c57bf6fff8af3a5981f9", + { + "addrType": "script", + "isPrivkey": false, + "isTestnet": false + } + ], + [ + "mizXiucXRCsEriQCHUkCqef9ph9qtPbZZ6", + "261f83568a098a8638844bd7aeca039d5f2352c0", + { + "addrType": "pubkey", + "isPrivkey": false, + "isTestnet": true + } + ], + [ + "2NEWDzHWwY5ZZp8CQWbB7ouNMLqCia6YRda", + "e930e1834a4d234702773951d627cce82fbb5d2e", + { + "addrType": "script", + "isPrivkey": false, + "isTestnet": true + } + ], + [ + "5KQmDryMNDcisTzRp3zEq9e4awRmJrEVU1j5vFRTKpRNYPqYrMg", + "d1fab7ab7385ad26872237f1eb9789aa25cc986bacc695e07ac571d6cdac8bc0", + { + "isCompressed": false, + "isPrivkey": true, + "isTestnet": false + } + ], + [ + "L39Fy7AC2Hhj95gh3Yb2AU5YHh1mQSAHgpNixvm27poizcJyLtUi", + "b0bbede33ef254e8376aceb1510253fc3550efd0fcf84dcd0c9998b288f166b3", + { + "isCompressed": true, + "isPrivkey": true, + "isTestnet": false + } + ], + [ + "91cTVUcgydqyZLgaANpf1fvL55FH53QMm4BsnCADVNYuWuqdVys", + "037f4192c630f399d9271e26c575269b1d15be553ea1a7217f0cb8513cef41cb", + { + "isCompressed": false, + "isPrivkey": true, + "isTestnet": true + } + ], + [ + "cQspfSzsgLeiJGB2u8vrAiWpCU4MxUT6JseWo2SjXy4Qbzn2fwDw", + "6251e205e8ad508bab5596bee086ef16cd4b239e0cc0c5d7c4e6035441e7d5de", + { + "isCompressed": true, + "isPrivkey": true, + "isTestnet": true + } + ], + [ + "19dcawoKcZdQz365WpXWMhX6QCUpR9SY4r", + "5eadaf9bb7121f0f192561a5a62f5e5f54210292", + { + "addrType": "pubkey", + "isPrivkey": false, + "isTestnet": false + } + ], + [ + "37Sp6Rv3y4kVd1nQ1JV5pfqXccHNyZm1x3", + "3f210e7277c899c3a155cc1c90f4106cbddeec6e", + { + "addrType": "script", + "isPrivkey": false, + "isTestnet": false + } + ], + [ + "myoqcgYiehufrsnnkqdqbp69dddVDMopJu", + "c8a3c2a09a298592c3e180f02487cd91ba3400b5", + { + "addrType": "pubkey", + "isPrivkey": false, + "isTestnet": true + } + ], + [ + "2N7FuwuUuoTBrDFdrAZ9KxBmtqMLxce9i1C", + "99b31df7c9068d1481b596578ddbb4d3bd90baeb", + { + "addrType": "script", + "isPrivkey": false, + "isTestnet": true + } + ], + [ + "5KL6zEaMtPRXZKo1bbMq7JDjjo1bJuQcsgL33je3oY8uSJCR5b4", + "c7666842503db6dc6ea061f092cfb9c388448629a6fe868d068c42a488b478ae", + { + "isCompressed": false, + "isPrivkey": true, + "isTestnet": false + } + ], + [ + "KwV9KAfwbwt51veZWNscRTeZs9CKpojyu1MsPnaKTF5kz69H1UN2", + "07f0803fc5399e773555ab1e8939907e9badacc17ca129e67a2f5f2ff84351dd", + { + "isCompressed": true, + "isPrivkey": true, + "isTestnet": false + } + ], + [ + "93N87D6uxSBzwXvpokpzg8FFmfQPmvX4xHoWQe3pLdYpbiwT5YV", + "ea577acfb5d1d14d3b7b195c321566f12f87d2b77ea3a53f68df7ebf8604a801", + { + "isCompressed": false, + "isPrivkey": true, + "isTestnet": true + } + ], + [ + "cMxXusSihaX58wpJ3tNuuUcZEQGt6DKJ1wEpxys88FFaQCYjku9h", + "0b3b34f0958d8a268193a9814da92c3e8b58b4a4378a542863e34ac289cd830c", + { + "isCompressed": true, + "isPrivkey": true, + "isTestnet": true + } + ], + [ + "13p1ijLwsnrcuyqcTvJXkq2ASdXqcnEBLE", + "1ed467017f043e91ed4c44b4e8dd674db211c4e6", + { + "addrType": "pubkey", + "isPrivkey": false, + "isTestnet": false + } + ], + [ + "3ALJH9Y951VCGcVZYAdpA3KchoP9McEj1G", + "5ece0cadddc415b1980f001785947120acdb36fc", + { + "addrType": "script", + "isPrivkey": false, + "isTestnet": false + } + ] +] diff --git a/src/test/data/script_invalid.json b/src/test/data/script_invalid.json new file mode 100644 index 0000000..d413eae --- /dev/null +++ b/src/test/data/script_invalid.json @@ -0,0 +1,245 @@ +[ +["", ""], +["", "NOP"], +["NOP", ""], +["NOP","NOP"], + +["0x4c01","0x01 NOP", "PUSHDATA1 with not enough bytes"], +["0x4d0200ff","0x01 NOP", "PUSHDATA2 with not enough bytes"], +["0x4e03000000ffff","0x01 NOP", "PUSHDATA4 with not enough bytes"], + +["1", "IF 0x50 ENDIF 1", "0x50 is reserved"], +["0x52", "0x5f ADD 0x60 EQUAL", "0x51 through 0x60 push 1 through 16 onto stack"], +["0","NOP"], +["1", "IF VER ELSE 1 ENDIF", "VER non-functional"], +["0", "IF VERIF ELSE 1 ENDIF", "VERIF illegal everywhere"], +["0", "IF VERNOTIF ELSE 1 ENDIF", "VERNOT illegal everywhere"], + +["1 IF", "1 ENDIF", "IF/ENDIF can't span scriptSig/scriptPubKey"], +["1 IF 0 ENDIF", "1 ENDIF"], +["1 ELSE 0 ENDIF", "1"], +["0 NOTIF", "123"], + +["0", "DUP IF ENDIF"], +["0", "IF 1 ENDIF"], +["0", "DUP IF ELSE ENDIF"], +["0", "IF 1 ELSE ENDIF"], +["0", "NOTIF ELSE 1 ENDIF"], + +["0 1", "IF IF 1 ELSE 0 ENDIF ENDIF"], +["0 0", "IF IF 1 ELSE 0 ENDIF ENDIF"], +["1 0", "IF IF 1 ELSE 0 ENDIF ELSE IF 0 ELSE 1 ENDIF ENDIF"], +["0 1", "IF IF 1 ELSE 0 ENDIF ELSE IF 0 ELSE 1 ENDIF ENDIF"], + +["0 0", "NOTIF IF 1 ELSE 0 ENDIF ENDIF"], +["0 1", "NOTIF IF 1 ELSE 0 ENDIF ENDIF"], +["1 1", "NOTIF IF 1 ELSE 0 ENDIF ELSE IF 0 ELSE 1 ENDIF ENDIF"], +["0 0", "NOTIF IF 1 ELSE 0 ENDIF ELSE IF 0 ELSE 1 ENDIF ENDIF"], + +["1", "RETURN"], +["1", "DUP IF RETURN ENDIF"], + +["0", "VERIFY 1"], +["1", "VERIFY"], +["1", "VERIFY 0"], + +["1 TOALTSTACK", "FROMALTSTACK 1", "alt stack not shared between sig/pubkey"], + +["IFDUP", "DEPTH 0 EQUAL"], +["DROP", "DEPTH 0 EQUAL"], +["DUP", "DEPTH 0 EQUAL"], +["1", "DUP 1 ADD 2 EQUALVERIFY 0 EQUAL"], +["NOP", "NIP"], +["NOP", "1 NIP"], +["NOP", "1 0 NIP"], +["NOP", "OVER 1"], +["1", "OVER"], +["0 1", "OVER DEPTH 3 EQUALVERIFY"], +["19 20 21", "PICK 19 EQUALVERIFY DEPTH 2 EQUAL"], +["NOP", "0 PICK"], +["1", "-1 PICK"], +["19 20 21", "0 PICK 20 EQUALVERIFY DEPTH 3 EQUAL"], +["19 20 21", "1 PICK 21 EQUALVERIFY DEPTH 3 EQUAL"], +["19 20 21", "2 PICK 22 EQUALVERIFY DEPTH 3 EQUAL"], +["NOP", "0 ROLL"], +["1", "-1 ROLL"], +["19 20 21", "0 ROLL 20 EQUALVERIFY DEPTH 2 EQUAL"], +["19 20 21", "1 ROLL 21 EQUALVERIFY DEPTH 2 EQUAL"], +["19 20 21", "2 ROLL 22 EQUALVERIFY DEPTH 2 EQUAL"], +["NOP", "ROT 1"], +["NOP", "1 ROT 1"], +["NOP", "1 2 ROT 1"], +["NOP", "0 1 2 ROT"], +["NOP", "SWAP 1"], +["1", "SWAP 1"], +["0 1", "SWAP 1 EQUALVERIFY"], +["NOP", "TUCK 1"], +["1", "TUCK 1"], +["1 0", "TUCK DEPTH 3 EQUALVERIFY SWAP 2DROP"], +["NOP", "2DUP 1"], +["1", "2DUP 1"], +["NOP", "3DUP 1"], +["1", "3DUP 1"], +["1 2", "3DUP 1"], +["NOP", "2OVER 1"], +["1", "2 3 2OVER 1"], +["NOP", "2SWAP 1"], +["1", "2 3 2SWAP 1"], + +["'a' 'b'", "CAT", "CAT disabled"], +["'a' 'b' 0", "IF CAT ELSE 1 ENDIF", "CAT disabled"], +["'abc' 1 1", "SUBSTR", "SUBSTR disabled"], +["'abc' 1 1 0", "IF SUBSTR ELSE 1 ENDIF", "SUBSTR disabled"], +["'abc' 2 0", "IF LEFT ELSE 1 ENDIF", "LEFT disabled"], +["'abc' 2 0", "IF RIGHT ELSE 1 ENDIF", "RIGHT disabled"], + +["NOP", "SIZE 1"], + +["'abc'", "IF INVERT ELSE 1 ENDIF", "INVERT disabled"], +["1 2 0 IF AND ELSE 1 ENDIF", "NOP", "AND disabled"], +["1 2 0 IF OR ELSE 1 ENDIF", "NOP", "OR disabled"], +["1 2 0 IF XOR ELSE 1 ENDIF", "NOP", "XOR disabled"], +["2 0 IF 2MUL ELSE 1 ENDIF", "NOP", "2MUL disabled"], +["2 0 IF 2DIV ELSE 1 ENDIF", "NOP", "2DIV disabled"], +["2 2 0 IF MUL ELSE 1 ENDIF", "NOP", "MUL disabled"], +["2 2 0 IF DIV ELSE 1 ENDIF", "NOP", "DIV disabled"], +["2 2 0 IF MOD ELSE 1 ENDIF", "NOP", "MOD disabled"], +["2 2 0 IF LSHIFT ELSE 1 ENDIF", "NOP", "LSHIFT disabled"], +["2 2 0 IF RSHIFT ELSE 1 ENDIF", "NOP", "RSHIFT disabled"], + +["0 1","EQUAL"], +["1 1 ADD", "0 EQUAL"], +["11 1 ADD 12 SUB", "11 EQUAL"], + +["2147483648 0 ADD", "NOP", "arithmetic operands must be in range [-2^31...2^31] "], +["-2147483648 0 ADD", "NOP", "arithmetic operands must be in range [-2^31...2^31] "], +["2147483647 DUP ADD", "4294967294 NUMEQUAL", "NUMEQUAL must be in numeric range"], +["'abcdef' NOT", "0 EQUAL", "NOT is an arithmetic operand"], + +["2 DUP MUL", "4 EQUAL", "disabled"], +["2 DUP DIV", "1 EQUAL", "disabled"], +["2 2MUL", "4 EQUAL", "disabled"], +["2 2DIV", "1 EQUAL", "disabled"], +["7 3 MOD", "1 EQUAL", "disabled"], +["2 2 LSHIFT", "8 EQUAL", "disabled"], +["2 1 RSHIFT", "1 EQUAL", "disabled"], + +["1","NOP1 NOP2 NOP3 NOP4 NOP5 NOP6 NOP7 NOP8 NOP9 NOP10 2 EQUAL"], +["'NOP_1_to_10' NOP1 NOP2 NOP3 NOP4 NOP5 NOP6 NOP7 NOP8 NOP9 NOP10","'NOP_1_to_11' EQUAL"], + +["0x50","1", "opcode 0x50 is reserved"], +["1", "IF 0xba ELSE 1 ENDIF", "opcodes above NOP10 invalid"], +["1", "IF 0xc0 ELSE 1 ENDIF"], +["1", "IF 0xd1 ELSE 1 ENDIF"], +["1", "IF 0xee ELSE 1 ENDIF"], +["1", "IF 0xfd ELSE 1 ENDIF"], +["1", "IF 0xff ELSE 1 ENDIF"], + +["NOP", "RIPEMD160"], +["NOP", "SHA1"], +["NOP", "SHA256"], +["NOP", "HASH160"], +["NOP", "HASH256"], + +["NOP", +"'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb'", +">520 byte push"], +["0", +"IF 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' ENDIF 1", +">520 byte push in non-executed IF branch"], +["1", +"0x61616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161", +">201 opcodes executed. 0x61 is NOP"], +["0", +"IF 0x6161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161 ENDIF 1", +">201 opcodes including non-executed IF branch. 0x61 is NOP"], +["1 2 3 4 5 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f", +"1 2 3 4 5 6 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f", +">1,000 stack size (0x6f is 3DUP)"], +["1 2 3 4 5 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f", +"1 TOALTSTACK 2 TOALTSTACK 3 4 5 6 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f", +">1,000 stack+altstack size"], +["NOP", +"0 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f 2DUP 0x616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161", +"10,001-byte scriptPubKey"], + +["NOP1","NOP10"], + +["1","VER", "OP_VER is reserved"], +["1","VERIF", "OP_VERIF is reserved"], +["1","VERNOTIF", "OP_VERNOTIF is reserved"], +["1","RESERVED1", "OP_RESERVED1 is reserved"], +["1","RESERVED2", "OP_RESERVED2 is reserved"], +["1","0xba", "0xba == OP_NOP10 + 1"], + +["2147483648", "1ADD 1", "We cannot do math on 5-byte integers"], +["-2147483648", "1ADD 1", "Because we use a sign bit, -2147483648 is also 5 bytes"], + +["1", "1 ENDIF", "ENDIF without IF"], +["1", "IF 1", "IF without ENDIF"], +["1 IF 1", "ENDIF", "IFs don't carry over"], + +["NOP", "IF 1 ENDIF", "The following tests check the if(stack.size() < N) tests in each opcode"], +["NOP", "NOTIF 1 ENDIF", "They are here to catch copy-and-paste errors"], +["NOP", "VERIFY 1", "Most of them are duplicated elsewhere,"], + +["NOP", "TOALTSTACK 1", "but, hey, more is always better, right?"], +["1", "FROMALTSTACK"], +["1", "2DROP 1"], +["1", "2DUP"], +["1 1", "3DUP"], +["1 1 1", "2OVER"], +["1 1 1 1 1", "2ROT"], +["1 1 1", "2SWAP"], +["NOP", "IFDUP 1"], +["NOP", "DROP 1"], +["NOP", "DUP 1"], +["1", "NIP"], +["1", "OVER"], +["1 1 1 3", "PICK"], +["0", "PICK 1"], +["1 1 1 3", "ROLL"], +["0", "ROLL 1"], +["1 1", "ROT"], +["1", "SWAP"], +["1", "TUCK"], + +["NOP", "SIZE 1"], + +["1", "EQUAL 1"], +["1", "EQUALVERIFY 1"], + +["NOP", "1ADD 1"], +["NOP", "1SUB 1"], +["NOP", "NEGATE 1"], +["NOP", "ABS 1"], +["NOP", "NOT 1"], +["NOP", "0NOTEQUAL 1"], + +["1", "ADD"], +["1", "SUB"], +["1", "BOOLAND"], +["1", "BOOLOR"], +["1", "NUMEQUAL"], +["1", "NUMEQUALVERIFY 1"], +["1", "NUMNOTEQUAL"], +["1", "LESSTHAN"], +["1", "GREATERTHAN"], +["1", "LESSTHANOREQUAL"], +["1", "GREATERTHANOREQUAL"], +["1", "MIN"], +["1", "MAX"], +["1 1", "WITHIN"], + +["NOP", "RIPEMD160 1"], +["NOP", "SHA1 1"], +["NOP", "SHA256 1"], +["NOP", "HASH160 1"], +["NOP", "HASH256 1"], + +["NOP 0x01 1", "HASH160 0x14 0xda1745e9b549bd0bfa1a569971c77eba30cd5a4b EQUAL", "Tests for Script.IsPushOnly()"], +["NOP1 0x01 1", "HASH160 0x14 0xda1745e9b549bd0bfa1a569971c77eba30cd5a4b EQUAL"], + +["0 0x01 0x50", "HASH160 0x14 0xece424a6bb6ddf4db592c0faed60685047a361b1 EQUAL", "OP_RESERVED in P2SH should fail"], +["0 0x01 VER", "HASH160 0x14 0x0f4d7845db968f2a81b530b6f3c1d6246d4c7e01 EQUAL", "OP_VER in P2SH should fail"] +] diff --git a/src/test/data/script_valid.json b/src/test/data/script_valid.json new file mode 100644 index 0000000..c33a3c7 --- /dev/null +++ b/src/test/data/script_valid.json @@ -0,0 +1,313 @@ +[ +["0x01 0x0b", "11 EQUAL", "push 1 byte"], +["0x02 0x417a", "'Az' EQUAL"], +["0x4b 0x417a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a", + "'Azzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz' EQUAL", "push 75 bytes"], + +["0x4c 0x01 0x07","7 EQUAL", "0x4c is OP_PUSHDATA1"], +["0x4d 0x0100 0x08","8 EQUAL", "0x4d is OP_PUSHDATA2"], +["0x4e 0x01000000 0x09","9 EQUAL", "0x4e is OP_PUSHDATA4"], + +["0x4c 0x00","0 EQUAL"], +["0x4d 0x0000","0 EQUAL"], +["0x4e 0x00000000","0 EQUAL"], +["0x4f 1000 ADD","999 EQUAL"], +["0", "IF 0x50 ENDIF 1", "0x50 is reserved (ok if not executed)"], +["0x51", "0x5f ADD 0x60 EQUAL", "0x51 through 0x60 push 1 through 16 onto stack"], +["1","NOP"], +["0", "IF VER ELSE 1 ENDIF", "VER non-functional (ok if not executed)"], +["0", "IF RESERVED1 RESERVED2 ELSE 1 ENDIF", "RESERVED ok in un-executed IF"], + +["1", "DUP IF ENDIF"], +["1", "IF 1 ENDIF"], +["1", "DUP IF ELSE ENDIF"], +["1", "IF 1 ELSE ENDIF"], +["0", "IF ELSE 1 ENDIF"], + +["1 1", "IF IF 1 ELSE 0 ENDIF ENDIF"], +["1 0", "IF IF 1 ELSE 0 ENDIF ENDIF"], +["1 1", "IF IF 1 ELSE 0 ENDIF ELSE IF 0 ELSE 1 ENDIF ENDIF"], +["0 0", "IF IF 1 ELSE 0 ENDIF ELSE IF 0 ELSE 1 ENDIF ENDIF"], + +["1 0", "NOTIF IF 1 ELSE 0 ENDIF ENDIF"], +["1 1", "NOTIF IF 1 ELSE 0 ENDIF ENDIF"], +["1 0", "NOTIF IF 1 ELSE 0 ENDIF ELSE IF 0 ELSE 1 ENDIF ENDIF"], +["0 1", "NOTIF IF 1 ELSE 0 ENDIF ELSE IF 0 ELSE 1 ENDIF ENDIF"], + +["1 1", "VERIFY"], + +["10 0 11 TOALTSTACK DROP FROMALTSTACK", "ADD 21 EQUAL"], +["'gavin_was_here' TOALTSTACK 11 FROMALTSTACK", "'gavin_was_here' EQUALVERIFY 11 EQUAL"], + +["0 IFDUP", "DEPTH 1 EQUALVERIFY 0 EQUAL"], +["1 IFDUP", "DEPTH 2 EQUALVERIFY 1 EQUALVERIFY 1 EQUAL"], +["0 DROP", "DEPTH 0 EQUAL"], +["0", "DUP 1 ADD 1 EQUALVERIFY 0 EQUAL"], +["0 1", "NIP"], +["1 0", "OVER DEPTH 3 EQUALVERIFY"], +["22 21 20", "0 PICK 20 EQUALVERIFY DEPTH 3 EQUAL"], +["22 21 20", "1 PICK 21 EQUALVERIFY DEPTH 3 EQUAL"], +["22 21 20", "2 PICK 22 EQUALVERIFY DEPTH 3 EQUAL"], +["22 21 20", "0 ROLL 20 EQUALVERIFY DEPTH 2 EQUAL"], +["22 21 20", "1 ROLL 21 EQUALVERIFY DEPTH 2 EQUAL"], +["22 21 20", "2 ROLL 22 EQUALVERIFY DEPTH 2 EQUAL"], +["22 21 20", "ROT 22 EQUAL"], +["22 21 20", "ROT DROP 20 EQUAL"], +["22 21 20", "ROT DROP DROP 21 EQUAL"], +["22 21 20", "ROT ROT 21 EQUAL"], +["22 21 20", "ROT ROT ROT 20 EQUAL"], +["25 24 23 22 21 20", "2ROT 24 EQUAL"], +["25 24 23 22 21 20", "2ROT DROP 25 EQUAL"], +["25 24 23 22 21 20", "2ROT 2DROP 20 EQUAL"], +["25 24 23 22 21 20", "2ROT 2DROP DROP 21 EQUAL"], +["25 24 23 22 21 20", "2ROT 2DROP 2DROP 22 EQUAL"], +["25 24 23 22 21 20", "2ROT 2DROP 2DROP DROP 23 EQUAL"], +["25 24 23 22 21 20", "2ROT 2ROT 22 EQUAL"], +["25 24 23 22 21 20", "2ROT 2ROT 2ROT 20 EQUAL"], +["1 0", "SWAP 1 EQUALVERIFY 0 EQUAL"], +["0 1", "TUCK DEPTH 3 EQUALVERIFY SWAP 2DROP"], +["13 14", "2DUP ROT EQUALVERIFY EQUAL"], +["-1 0 1 2", "3DUP DEPTH 7 EQUALVERIFY ADD ADD 3 EQUALVERIFY 2DROP 0 EQUALVERIFY"], +["1 2 3 5", "2OVER ADD ADD 8 EQUALVERIFY ADD ADD 6 EQUAL"], +["1 3 5 7", "2SWAP ADD 4 EQUALVERIFY ADD 12 EQUAL"], +["0", "SIZE 0 EQUAL"], +["1", "SIZE 1 EQUAL"], +["127", "SIZE 1 EQUAL"], +["128", "SIZE 2 EQUAL"], +["32767", "SIZE 2 EQUAL"], +["32768", "SIZE 3 EQUAL"], +["8388607", "SIZE 3 EQUAL"], +["8388608", "SIZE 4 EQUAL"], +["2147483647", "SIZE 4 EQUAL"], +["2147483648", "SIZE 5 EQUAL"], +["-1", "SIZE 1 EQUAL"], +["-127", "SIZE 1 EQUAL"], +["-128", "SIZE 2 EQUAL"], +["-32767", "SIZE 2 EQUAL"], +["-32768", "SIZE 3 EQUAL"], +["-8388607", "SIZE 3 EQUAL"], +["-8388608", "SIZE 4 EQUAL"], +["-2147483647", "SIZE 4 EQUAL"], +["-2147483648", "SIZE 5 EQUAL"], +["'abcdefghijklmnopqrstuvwxyz'", "SIZE 26 EQUAL"], + + +["2 -2 ADD", "0 EQUAL"], +["2147483647 -2147483647 ADD", "0 EQUAL"], +["-1 -1 ADD", "-2 EQUAL"], + +["0 0","EQUAL"], +["1 1 ADD", "2 EQUAL"], +["1 1ADD", "2 EQUAL"], +["111 1SUB", "110 EQUAL"], +["111 1 ADD 12 SUB", "100 EQUAL"], +["0 ABS", "0 EQUAL"], +["16 ABS", "16 EQUAL"], +["-16 ABS", "-16 NEGATE EQUAL"], +["0 NOT", "NOP"], +["1 NOT", "0 EQUAL"], +["11 NOT", "0 EQUAL"], +["0 0NOTEQUAL", "0 EQUAL"], +["1 0NOTEQUAL", "1 EQUAL"], +["111 0NOTEQUAL", "1 EQUAL"], +["-111 0NOTEQUAL", "1 EQUAL"], +["1 1 BOOLAND", "NOP"], +["1 0 BOOLAND", "NOT"], +["0 1 BOOLAND", "NOT"], +["0 0 BOOLAND", "NOT"], +["16 17 BOOLAND", "NOP"], +["1 1 BOOLOR", "NOP"], +["1 0 BOOLOR", "NOP"], +["0 1 BOOLOR", "NOP"], +["0 0 BOOLOR", "NOT"], +["16 17 BOOLOR", "NOP"], +["11 10 1 ADD", "NUMEQUAL"], +["11 10 1 ADD", "NUMEQUALVERIFY 1"], +["11 10 1 ADD", "NUMNOTEQUAL NOT"], +["111 10 1 ADD", "NUMNOTEQUAL"], +["11 10", "LESSTHAN NOT"], +["4 4", "LESSTHAN NOT"], +["10 11", "LESSTHAN"], +["-11 11", "LESSTHAN"], +["-11 -10", "LESSTHAN"], +["11 10", "GREATERTHAN"], +["4 4", "GREATERTHAN NOT"], +["10 11", "GREATERTHAN NOT"], +["-11 11", "GREATERTHAN NOT"], +["-11 -10", "GREATERTHAN NOT"], +["11 10", "LESSTHANOREQUAL NOT"], +["4 4", "LESSTHANOREQUAL"], +["10 11", "LESSTHANOREQUAL"], +["-11 11", "LESSTHANOREQUAL"], +["-11 -10", "LESSTHANOREQUAL"], +["11 10", "GREATERTHANOREQUAL"], +["4 4", "GREATERTHANOREQUAL"], +["10 11", "GREATERTHANOREQUAL NOT"], +["-11 11", "GREATERTHANOREQUAL NOT"], +["-11 -10", "GREATERTHANOREQUAL NOT"], +["1 0 MIN", "0 NUMEQUAL"], +["0 1 MIN", "0 NUMEQUAL"], +["-1 0 MIN", "-1 NUMEQUAL"], +["0 -2147483647 MIN", "-2147483647 NUMEQUAL"], +["2147483647 0 MAX", "2147483647 NUMEQUAL"], +["0 100 MAX", "100 NUMEQUAL"], +["-100 0 MAX", "0 NUMEQUAL"], +["0 -2147483647 MAX", "0 NUMEQUAL"], +["0 0 1", "WITHIN"], +["1 0 1", "WITHIN NOT"], +["0 -2147483647 2147483647", "WITHIN"], +["-1 -100 100", "WITHIN"], +["11 -100 100", "WITHIN"], +["-2147483647 -100 100", "WITHIN NOT"], +["2147483647 -100 100", "WITHIN NOT"], + +["2147483647 2147483647 SUB", "0 EQUAL"], +["2147483647 DUP ADD", "4294967294 EQUAL", ">32 bit EQUAL is valid"], +["2147483647 NEGATE DUP ADD", "-4294967294 EQUAL"], + +["''", "RIPEMD160 0x14 0x9c1185a5c5e9fc54612808977ee8f548b2258d31 EQUAL"], +["'a'", "RIPEMD160 0x14 0x0bdc9d2d256b3ee9daae347be6f4dc835a467ffe EQUAL"], +["'abcdefghijklmnopqrstuvwxyz'", "RIPEMD160 0x14 0xf71c27109c692c1b56bbdceb5b9d2865b3708dbc EQUAL"], +["''", "SHA1 0x14 0xda39a3ee5e6b4b0d3255bfef95601890afd80709 EQUAL"], +["'a'", "SHA1 0x14 0x86f7e437faa5a7fce15d1ddcb9eaeaea377667b8 EQUAL"], +["'abcdefghijklmnopqrstuvwxyz'", "SHA1 0x14 0x32d10c7b8cf96570ca04ce37f2a19d84240d3a89 EQUAL"], +["''", "SHA256 0x20 0xe3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 EQUAL"], +["'a'", "SHA256 0x20 0xca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb EQUAL"], +["'abcdefghijklmnopqrstuvwxyz'", "SHA256 0x20 0x71c480df93d6ae2f1efad1447c66c9525e316218cf51fc8d9ed832f2daf18b73 EQUAL"], +["''", "DUP HASH160 SWAP SHA256 RIPEMD160 EQUAL"], +["''", "DUP HASH256 SWAP SHA256 SHA256 EQUAL"], +["''", "NOP HASH160 0x14 0xb472a266d0bd89c13706a4132ccfb16f7c3b9fcb EQUAL"], +["'a'", "HASH160 NOP 0x14 0x994355199e516ff76c4fa4aab39337b9d84cf12b EQUAL"], +["'abcdefghijklmnopqrstuvwxyz'", "HASH160 0x4c 0x14 0xc286a1af0947f58d1ad787385b1c2c4a976f9e71 EQUAL"], +["''", "HASH256 0x20 0x5df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c9456 EQUAL"], +["'a'", "HASH256 0x20 0xbf5d3affb73efd2ec6c36ad3112dd933efed63c4e1cbffcfa88e2759c144f2d8 EQUAL"], +["'abcdefghijklmnopqrstuvwxyz'", "HASH256 0x4c 0x20 0xca139bc10c2f660da42666f72e89a225936fc60f193c161124a672050c434671 EQUAL"], + + +["1","NOP1 NOP2 NOP3 NOP4 NOP5 NOP6 NOP7 NOP8 NOP9 NOP10 1 EQUAL"], +["'NOP_1_to_10' NOP1 NOP2 NOP3 NOP4 NOP5 NOP6 NOP7 NOP8 NOP9 NOP10","'NOP_1_to_10' EQUAL"], + +["0", "IF 0xba ELSE 1 ENDIF", "opcodes above NOP10 invalid if executed"], +["0", "IF 0xc0 ELSE 1 ENDIF"], +["0", "IF 0xd1 ELSE 1 ENDIF"], +["0", "IF 0xee ELSE 1 ENDIF"], +["0", "IF 0xfd ELSE 1 ENDIF"], +["0", "IF 0xff ELSE 1 ENDIF"], + +["NOP", +"'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb'", +"520 byte push"], +["1", +"0x616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161", +"201 opcodes executed. 0x61 is NOP"], +["1 2 3 4 5 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f", +"1 2 3 4 5 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f", +"1,000 stack size (0x6f is 3DUP)"], +["1 TOALTSTACK 2 TOALTSTACK 3 4 5 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f", +"1 2 3 4 5 6 7 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f", +"1,000 stack size (altstack cleared between scriptSig/scriptPubKey)"], +["'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f", +"'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f 2DUP 0x616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161", +"Max-size (10,000-byte), max-push(520 bytes), max-opcodes(201), max stack size(1,000 items). 0x6f is 3DUP, 0x61 is NOP"], + +["NOP","1"], + +["1", "0x01 0x01 EQUAL", "The following is useful for checking implementations of BN_bn2mpi"], +["127", "0x01 0x7F EQUAL"], +["128", "0x02 0x8000 EQUAL", "Leave room for the sign bit"], +["32767", "0x02 0xFF7F EQUAL"], +["32768", "0x03 0x008000 EQUAL"], +["8388607", "0x03 0xFFFF7F EQUAL"], +["8388608", "0x04 0x00008000 EQUAL"], +["2147483647", "0x04 0xFFFFFF7F EQUAL"], +["2147483648", "0x05 0x0000008000 EQUAL"], +["-1", "0x01 0x81 EQUAL", "Numbers are little-endian with the MSB being a sign bit"], +["-127", "0x01 0xFF EQUAL"], +["-128", "0x02 0x8080 EQUAL"], +["-32767", "0x02 0xFFFF EQUAL"], +["-32768", "0x03 0x008080 EQUAL"], +["-8388607", "0x03 0xFFFFFF EQUAL"], +["-8388608", "0x04 0x00008080 EQUAL"], +["-2147483647", "0x04 0xFFFFFFFF EQUAL"], +["-2147483648", "0x05 0x0000008080 EQUAL"], + +["2147483647", "1ADD 2147483648 EQUAL", "We can do math on 4-byte integers, and compare 5-byte ones"], +["2147483647", "1ADD 1"], +["-2147483647", "1ADD 1"], + + +["NOP", "NOP 1", "The following tests check the if(stack.size() < N) tests in each opcode"], +["1", "IF 1 ENDIF", "They are here to catch copy-and-paste errors"], +["0", "NOTIF 1 ENDIF", "Most of them are duplicated elsewhere,"], +["1", "VERIFY 1", "but, hey, more is always better, right?"], + +["0", "TOALTSTACK 1"], +["1", "TOALTSTACK FROMALTSTACK"], +["0 0", "2DROP 1"], +["0 1", "2DUP"], +["0 0 1", "3DUP"], +["0 1 0 0", "2OVER"], +["0 1 0 0 0 0", "2ROT"], +["0 1 0 0", "2SWAP"], +["1", "IFDUP"], +["NOP", "DEPTH 1"], +["0", "DROP 1"], +["1", "DUP"], +["0 1", "NIP"], +["1 0", "OVER"], +["1 0 0 0 3", "PICK"], +["1 0", "PICK"], +["1 0 0 0 3", "ROLL"], +["1 0", "ROLL"], +["1 0 0", "ROT"], +["1 0", "SWAP"], +["0 1", "TUCK"], + +["1", "SIZE"], + +["0 0", "EQUAL"], +["0 0", "EQUALVERIFY 1"], + +["0", "1ADD"], +["2", "1SUB"], +["-1", "NEGATE"], +["-1", "ABS"], +["0", "NOT"], +["-1", "0NOTEQUAL"], + +["1 0", "ADD"], +["1 0", "SUB"], +["-1 -1", "BOOLAND"], +["-1 0", "BOOLOR"], +["0 0", "NUMEQUAL"], +["0 0", "NUMEQUALVERIFY 1"], +["-1 0", "NUMNOTEQUAL"], +["-1 0", "LESSTHAN"], +["1 0", "GREATERTHAN"], +["0 0", "LESSTHANOREQUAL"], +["0 0", "GREATERTHANOREQUAL"], +["-1 0", "MIN"], +["1 0", "MAX"], +["-1 -1 0", "WITHIN"], + +["0", "RIPEMD160"], +["0", "SHA1"], +["0", "SHA256"], +["0", "HASH160"], +["0", "HASH256"], +["NOP", "CODESEPARATOR 1"], + +["NOP", "NOP1 1"], +["NOP", "NOP2 1"], +["NOP", "NOP3 1"], +["NOP", "NOP4 1"], +["NOP", "NOP5 1"], +["NOP", "NOP6 1"], +["NOP", "NOP7 1"], +["NOP", "NOP8 1"], +["NOP", "NOP9 1"], +["NOP", "NOP10 1"], + +["0 0x01 1", "HASH160 0x14 0xda1745e9b549bd0bfa1a569971c77eba30cd5a4b EQUAL", "Very basic P2SH"], +["0x4c 0 0x01 1", "HASH160 0x14 0xda1745e9b549bd0bfa1a569971c77eba30cd5a4b EQUAL"] +] diff --git a/src/test/data/tx_invalid.json b/src/test/data/tx_invalid.json new file mode 100644 index 0000000..f01ee06 --- /dev/null +++ b/src/test/data/tx_invalid.json @@ -0,0 +1,64 @@ +[ +["The following are deserialized transactions which are invalid."], +["They are in the form"], +["[[[prevout hash, prevout index, prevout scriptPubKey], [input 2], ...],"], +["serializedTransaction, enforceP2SH]"], +["Objects that are only a single string (like this one) are ignored"], + +["0e1b5688cf179cd9f7cbda1fac0090f6e684bbf8cd946660120197c3f3681809 but with extra junk appended to the end of the scriptPubKey"], +[[["6ca7ec7b1847f6bdbd737176050e6a08d66ccd55bb94ad24f4018024107a5827", 0, "0x41 0x043b640e983c9690a14c039a2037ecc3467b27a0dcd58f19d76c7bc118d09fec45adc5370a1c5bf8067ca9f5557a4cf885fdb0fe0dcc9c3a7137226106fbc779a5 CHECKSIG VERIFY 1"]], +"010000000127587a10248001f424ad94bb55cd6cd6086a0e05767173bdbdf647187beca76c000000004948304502201b822ad10d6adc1a341ae8835be3f70a25201bbff31f59cbb9c5353a5f0eca18022100ea7b2f7074e9aa9cf70aa8d0ffee13e6b45dddabf1ab961bda378bcdb778fa4701ffffffff0100f2052a010000001976a914fc50c5907d86fed474ba5ce8b12a66e0a4c139d888ac00000000", true], + +["This is the nearly-standard transaction with CHECKSIGVERIFY 1 instead of CHECKSIG from tx_valid.json"], +["but with the signature duplicated in the scriptPubKey with a non-standard pushdata prefix"], +["See FindAndDelete, which will only remove if it uses the same pushdata prefix as is standard"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "DUP HASH160 0x14 0x5b6462475454710f3c22f5fdf0b40704c92f25c3 EQUALVERIFY CHECKSIGVERIFY 1 0x4c 0x47 0x3044022067288ea50aa799543a536ff9306f8e1cba05b9c6b10951175b924f96732555ed022026d7b5265f38d21541519e4a1e55044d5b9e17e15cdbaf29ae3792e99e883e7a01"]], +"01000000010001000000000000000000000000000000000000000000000000000000000000000000006a473044022067288ea50aa799543a536ff9306f8e1cba05b9c6b10951175b924f96732555ed022026d7b5265f38d21541519e4a1e55044d5b9e17e15cdbaf29ae3792e99e883e7a012103ba8c8b86dea131c22ab967e6dd99bdae8eff7a1f75a2c35f1f944109e3fe5e22ffffffff010000000000000000015100000000", true], + +["Same as above, but with the sig in the scriptSig also pushed with the same non-standard OP_PUSHDATA"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "DUP HASH160 0x14 0x5b6462475454710f3c22f5fdf0b40704c92f25c3 EQUALVERIFY CHECKSIGVERIFY 1 0x4c 0x47 0x3044022067288ea50aa799543a536ff9306f8e1cba05b9c6b10951175b924f96732555ed022026d7b5265f38d21541519e4a1e55044d5b9e17e15cdbaf29ae3792e99e883e7a01"]], +"01000000010001000000000000000000000000000000000000000000000000000000000000000000006b4c473044022067288ea50aa799543a536ff9306f8e1cba05b9c6b10951175b924f96732555ed022026d7b5265f38d21541519e4a1e55044d5b9e17e15cdbaf29ae3792e99e883e7a012103ba8c8b86dea131c22ab967e6dd99bdae8eff7a1f75a2c35f1f944109e3fe5e22ffffffff010000000000000000015100000000", true], + +["An invalid P2SH Transaction"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x7a052c840ba73af26755de42cf01cc9e0a49fef0 EQUAL"]], +"010000000100010000000000000000000000000000000000000000000000000000000000000000000009085768617420697320ffffffff010000000000000000015100000000", true], + +["Tests for CTransaction::CheckTransaction()"], +["No inputs"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x7a052c840ba73af26755de42cf01cc9e0a49fef0 EQUAL"]], +"0100000000010000000000000000015100000000", true], + +["No outputs"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x05ab9e14d983742513f0f451e105ffb4198d1dd4 EQUAL"]], +"01000000010001000000000000000000000000000000000000000000000000000000000000000000006d483045022100f16703104aab4e4088317c862daec83440242411b039d14280e03dd33b487ab802201318a7be236672c5c56083eb7a5a195bc57a40af7923ff8545016cd3b571e2a601232103c40e5d339df3f30bf753e7e04450ae4ef76c9e45587d1d993bdc4cd06f0651c7acffffffff0000000000", true], + +["Negative output"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0xae609aca8061d77c5e111f6bb62501a6bbe2bfdb EQUAL"]], +"01000000010001000000000000000000000000000000000000000000000000000000000000000000006d4830450220063222cbb128731fc09de0d7323746539166544d6c1df84d867ccea84bcc8903022100bf568e8552844de664cd41648a031554327aa8844af34b4f27397c65b92c04de0123210243ec37dee0e2e053a9c976f43147e79bc7d9dc606ea51010af1ac80db6b069e1acffffffff01ffffffffffffffff015100000000", true], + +["MAX_MONEY + 1 output"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x32afac281462b822adbec5094b8d4d337dd5bd6a EQUAL"]], +"01000000010001000000000000000000000000000000000000000000000000000000000000000000006e493046022100e1eadba00d9296c743cb6ecc703fd9ddc9b3cd12906176a226ae4c18d6b00796022100a71aef7d2874deff681ba6080f1b278bac7bb99c61b08a85f4311970ffe7f63f012321030c0588dc44d92bdcbf8e72093466766fdc265ead8db64517b0c542275b70fffbacffffffff010140075af0750700015100000000", true], + +["MAX_MONEY output + 1 output"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0xb558cbf4930954aa6a344363a15668d7477ae716 EQUAL"]], +"01000000010001000000000000000000000000000000000000000000000000000000000000000000006d483045022027deccc14aa6668e78a8c9da3484fbcd4f9dcc9bb7d1b85146314b21b9ae4d86022100d0b43dece8cfb07348de0ca8bc5b86276fa88f7f2138381128b7c36ab2e42264012321029bb13463ddd5d2cc05da6e84e37536cb9525703cfd8f43afdb414988987a92f6acffffffff020040075af075070001510001000000000000015100000000", true], + +["Duplicate inputs"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x236d0639db62b0773fd8ac34dc85ae19e9aba80a EQUAL"]], +"01000000020001000000000000000000000000000000000000000000000000000000000000000000006c47304402204bb1197053d0d7799bf1b30cd503c44b58d6240cccbdc85b6fe76d087980208f02204beeed78200178ffc6c74237bb74b3f276bbb4098b5605d814304fe128bf1431012321039e8815e15952a7c3fada1905f8cf55419837133bd7756c0ef14fc8dfe50c0deaacffffffff0001000000000000000000000000000000000000000000000000000000000000000000006c47304402202306489afef52a6f62e90bf750bbcdf40c06f5c6b138286e6b6b86176bb9341802200dba98486ea68380f47ebb19a7df173b99e6bc9c681d6ccf3bde31465d1f16b3012321039e8815e15952a7c3fada1905f8cf55419837133bd7756c0ef14fc8dfe50c0deaacffffffff010000000000000000015100000000", true], + +["Coinbase of size 1"], +["Note the input is just required to make the tester happy"], +[[["0000000000000000000000000000000000000000000000000000000000000000", -1, "1"]], +"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0151ffffffff010000000000000000015100000000", true], + +["Coinbase of size 101"], +["Note the input is just required to make the tester happy"], +[[["0000000000000000000000000000000000000000000000000000000000000000", -1, "1"]], +"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff655151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151ffffffff010000000000000000015100000000", true], + +["Null txin"], +[[["0000000000000000000000000000000000000000000000000000000000000000", -1, "HASH160 0x14 0x02dae7dbbda56097959cba59b1989dd3e47937bf EQUAL"]], +"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff6e49304602210086f39e028e46dafa8e1e3be63906465f4cf038fbe5ed6403dc3e74ae876e6431022100c4625c675cfc5c7e3a0e0d7eaec92ac24da20c73a88eb40d09253e51ac6def5201232103a183ddc41e84753aca47723c965d1b5c8b0e2b537963518355e6dd6cf8415e50acffffffff010000000000000000015100000000", true] +] diff --git a/src/test/data/tx_valid.json b/src/test/data/tx_valid.json new file mode 100644 index 0000000..5528ae7 --- /dev/null +++ b/src/test/data/tx_valid.json @@ -0,0 +1,71 @@ +[ +["The following are deserialized transactions which are valid."], +["They are in the form"], +["[[[prevout hash, prevout index, prevout scriptPubKey], [input 2], ...],"], +["serializedTransaction, enforceP2SH]"], +["Objects that are only a single string (like this one) are ignored"], + +["The following is 23b397edccd3740a74adb603c9756370fafcde9bcc4483eb271ecad09a94dd63"], +["It is of particular interest because it contains an invalidly-encoded signature which OpenSSL accepts"], +["See http://r6.ca/blog/20111119T211504Z.html"], +["It is also the first OP_CHECKMULTISIG transaction in standard form"], +[[["60a20bd93aa49ab4b28d514ec10b06e1829ce6818ec06cd3aabd013ebcdc4bb1", 0, "1 0x41 0x04cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaff7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4 0x41 0x0461cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d76519aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b25c15342af 2 OP_CHECKMULTISIG"]], +"0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba26000000000490047304402203f16c6f40162ab686621ef3000b04e75418a0c0cb2d8aebeac894ae360ac1e780220ddc15ecdfc3507ac48e1681a33eb60996631bf6bf5bc0a0682c4db743ce7ca2b01ffffffff0140420f00000000001976a914660d4ef3a743e3e696ad990364e555c271ad504b88ac00000000", true], + +["The following is a tweaked form of 23b397edccd3740a74adb603c9756370fafcde9bcc4483eb271ecad09a94dd63"], +["It has an arbitrary extra byte stuffed into the signature at pos length - 2"], +[[["60a20bd93aa49ab4b28d514ec10b06e1829ce6818ec06cd3aabd013ebcdc4bb1", 0, "1 0x41 0x04cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaff7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4 0x41 0x0461cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d76519aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b25c15342af 2 OP_CHECKMULTISIG"]], +"0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba260000000004A0048304402203f16c6f40162ab686621ef3000b04e75418a0c0cb2d8aebeac894ae360ac1e780220ddc15ecdfc3507ac48e1681a33eb60996631bf6bf5bc0a0682c4db743ce7ca2bab01ffffffff0140420f00000000001976a914660d4ef3a743e3e696ad990364e555c271ad504b88ac00000000", true], + +["The following is c99c49da4c38af669dea436d3e73780dfdb6c1ecf9958baa52960e8baee30e73"], +["It is of interest because it contains a 0-sequence as well as a signature of SIGHASH type 0 (which is not a real type)"], +[[["406b2b06bcd34d3c8733e6b79f7a394c8a431fbf4ff5ac705c93f4076bb77602", 0, "DUP HASH160 0x14 0xdc44b1164188067c3a32d4780f5996fa14a4f2d9 EQUALVERIFY CHECKSIG"]], +"01000000010276b76b07f4935c70acf54fbf1f438a4c397a9fb7e633873c4dd3bc062b6b40000000008c493046022100d23459d03ed7e9511a47d13292d3430a04627de6235b6e51a40f9cd386f2abe3022100e7d25b080f0bb8d8d5f878bba7d54ad2fda650ea8d158a33ee3cbd11768191fd004104b0e2c879e4daf7b9ab68350228c159766676a14f5815084ba166432aab46198d4cca98fa3e9981d0a90b2effc514b76279476550ba3663fdcaff94c38420e9d5000000000100093d00000000001976a9149a7b0f3b80c6baaeedce0a0842553800f832ba1f88ac00000000", true], + +["A nearly-standard transaction with CHECKSIGVERIFY 1 instead of CHECKSIG"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "DUP HASH160 0x14 0x5b6462475454710f3c22f5fdf0b40704c92f25c3 EQUALVERIFY CHECKSIGVERIFY 1"]], +"01000000010001000000000000000000000000000000000000000000000000000000000000000000006a473044022067288ea50aa799543a536ff9306f8e1cba05b9c6b10951175b924f96732555ed022026d7b5265f38d21541519e4a1e55044d5b9e17e15cdbaf29ae3792e99e883e7a012103ba8c8b86dea131c22ab967e6dd99bdae8eff7a1f75a2c35f1f944109e3fe5e22ffffffff010000000000000000015100000000", true], + +["Same as above, but with the signature duplicated in the scriptPubKey with the proper pushdata prefix"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "DUP HASH160 0x14 0x5b6462475454710f3c22f5fdf0b40704c92f25c3 EQUALVERIFY CHECKSIGVERIFY 1 0x47 0x3044022067288ea50aa799543a536ff9306f8e1cba05b9c6b10951175b924f96732555ed022026d7b5265f38d21541519e4a1e55044d5b9e17e15cdbaf29ae3792e99e883e7a01"]], +"01000000010001000000000000000000000000000000000000000000000000000000000000000000006a473044022067288ea50aa799543a536ff9306f8e1cba05b9c6b10951175b924f96732555ed022026d7b5265f38d21541519e4a1e55044d5b9e17e15cdbaf29ae3792e99e883e7a012103ba8c8b86dea131c22ab967e6dd99bdae8eff7a1f75a2c35f1f944109e3fe5e22ffffffff010000000000000000015100000000", true], + +["The following is f7fdd091fa6d8f5e7a8c2458f5c38faffff2d3f1406b6e4fe2c99dcc0d2d1cbb"], +["It caught a bug in the workaround for 23b397edccd3740a74adb603c9756370fafcde9bcc4483eb271ecad09a94dd63 in an overly simple implementation"], +[[["b464e85df2a238416f8bdae11d120add610380ea07f4ef19c5f9dfd472f96c3d", 0, "DUP HASH160 0x14 0xbef80ecf3a44500fda1bc92176e442891662aed2 EQUALVERIFY CHECKSIG"], +["b7978cc96e59a8b13e0865d3f95657561a7f725be952438637475920bac9eb21", 1, "DUP HASH160 0x14 0xbef80ecf3a44500fda1bc92176e442891662aed2 EQUALVERIFY CHECKSIG"]], +"01000000023d6cf972d4dff9c519eff407ea800361dd0a121de1da8b6f4138a2f25de864b4000000008a4730440220ffda47bfc776bcd269da4832626ac332adfca6dd835e8ecd83cd1ebe7d709b0e022049cffa1cdc102a0b56e0e04913606c70af702a1149dc3b305ab9439288fee090014104266abb36d66eb4218a6dd31f09bb92cf3cfa803c7ea72c1fc80a50f919273e613f895b855fb7465ccbc8919ad1bd4a306c783f22cd3227327694c4fa4c1c439affffffff21ebc9ba20594737864352e95b727f1a565756f9d365083eb1a8596ec98c97b7010000008a4730440220503ff10e9f1e0de731407a4a245531c9ff17676eda461f8ceeb8c06049fa2c810220c008ac34694510298fa60b3f000df01caa244f165b727d4896eb84f81e46bcc4014104266abb36d66eb4218a6dd31f09bb92cf3cfa803c7ea72c1fc80a50f919273e613f895b855fb7465ccbc8919ad1bd4a306c783f22cd3227327694c4fa4c1c439affffffff01f0da5200000000001976a914857ccd42dded6df32949d4646dfa10a92458cfaa88ac00000000", true], + +["The following tests for the presence of a bug in the handling of SIGHASH_SINGLE"], +["It results in signing the constant 1, instead of something generated based on the transaction,"], +["when the input doing the signing has an index greater than the maximum output index"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "DUP HASH160 0x14 0xe52b482f2faa8ecbf0db344f93c84ac908557f33 EQUALVERIFY CHECKSIG"], ["0000000000000000000000000000000000000000000000000000000000000200", 0, "1"]], +"01000000020002000000000000000000000000000000000000000000000000000000000000000000000151ffffffff0001000000000000000000000000000000000000000000000000000000000000000000006b483045022100c9cdd08798a28af9d1baf44a6c77bcc7e279f47dc487c8c899911bc48feaffcc0220503c5c50ae3998a733263c5c0f7061b483e2b56c4c41b456e7d2f5a78a74c077032102d5c25adb51b61339d2b05315791e21bbe80ea470a49db0135720983c905aace0ffffffff010000000000000000015100000000", true], + +["An invalid P2SH Transaction"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x7a052c840ba73af26755de42cf01cc9e0a49fef0 EQUAL"]], +"010000000100010000000000000000000000000000000000000000000000000000000000000000000009085768617420697320ffffffff010000000000000000015100000000", false], + +["A valid P2SH Transaction using the standard transaction type put forth in BIP 16"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x8febbed40483661de6958d957412f82deed8e2f7 EQUAL"]], +"01000000010001000000000000000000000000000000000000000000000000000000000000000000006e493046022100c66c9cdf4c43609586d15424c54707156e316d88b0a1534c9e6b0d4f311406310221009c0fe51dbc9c4ab7cc25d3fdbeccf6679fe6827f08edf2b4a9f16ee3eb0e438a0123210338e8034509af564c62644c07691942e0c056752008a173c89f60ab2a88ac2ebfacffffffff010000000000000000015100000000", true], + +["Tests for CTransaction::CheckTransaction()"], +["MAX_MONEY output"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x32afac281462b822adbec5094b8d4d337dd5bd6a EQUAL"]], +"01000000010001000000000000000000000000000000000000000000000000000000000000000000006e493046022100e1eadba00d9296c743cb6ecc703fd9ddc9b3cd12906176a226ae4c18d6b00796022100a71aef7d2874deff681ba6080f1b278bac7bb99c61b08a85f4311970ffe7f63f012321030c0588dc44d92bdcbf8e72093466766fdc265ead8db64517b0c542275b70fffbacffffffff010040075af0750700015100000000", true], + +["MAX_MONEY output + 0 output"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0xb558cbf4930954aa6a344363a15668d7477ae716 EQUAL"]], +"01000000010001000000000000000000000000000000000000000000000000000000000000000000006d483045022027deccc14aa6668e78a8c9da3484fbcd4f9dcc9bb7d1b85146314b21b9ae4d86022100d0b43dece8cfb07348de0ca8bc5b86276fa88f7f2138381128b7c36ab2e42264012321029bb13463ddd5d2cc05da6e84e37536cb9525703cfd8f43afdb414988987a92f6acffffffff020040075af075070001510000000000000000015100000000", true], + +["Coinbase of size 2"], +["Note the input is just required to make the tester happy"], +[[["0000000000000000000000000000000000000000000000000000000000000000", -1, "1"]], +"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff025151ffffffff010000000000000000015100000000", true], + +["Coinbase of size 100"], +["Note the input is just required to make the tester happy"], +[[["0000000000000000000000000000000000000000000000000000000000000000", -1, "1"]], +"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff6451515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151ffffffff010000000000000000015100000000", true] +] diff --git a/src/test/getarg_tests.cpp b/src/test/getarg_tests.cpp new file mode 100644 index 0000000..78953d2 --- /dev/null +++ b/src/test/getarg_tests.cpp @@ -0,0 +1,167 @@ +#include +#include +#include + +#include "util.h" + +BOOST_AUTO_TEST_SUITE(getarg_tests) + +static void +ResetArgs(const std::string& strArg) +{ + std::vector vecArg; + boost::split(vecArg, strArg, boost::is_space(), boost::token_compress_on); + + // Insert dummy executable name: + vecArg.insert(vecArg.begin(), "testbitcoin"); + + // Convert to char*: + std::vector vecChar; + BOOST_FOREACH(std::string& s, vecArg) + vecChar.push_back(s.c_str()); + + ParseParameters(vecChar.size(), &vecChar[0]); +} + +BOOST_AUTO_TEST_CASE(boolarg) +{ + ResetArgs("-foo"); + BOOST_CHECK(GetBoolArg("-foo")); + BOOST_CHECK(GetBoolArg("-foo", false)); + BOOST_CHECK(GetBoolArg("-foo", true)); + + BOOST_CHECK(!GetBoolArg("-fo")); + BOOST_CHECK(!GetBoolArg("-fo", false)); + BOOST_CHECK(GetBoolArg("-fo", true)); + + BOOST_CHECK(!GetBoolArg("-fooo")); + BOOST_CHECK(!GetBoolArg("-fooo", false)); + BOOST_CHECK(GetBoolArg("-fooo", true)); + + ResetArgs("-foo=0"); + BOOST_CHECK(!GetBoolArg("-foo")); + BOOST_CHECK(!GetBoolArg("-foo", false)); + BOOST_CHECK(!GetBoolArg("-foo", true)); + + ResetArgs("-foo=1"); + BOOST_CHECK(GetBoolArg("-foo")); + BOOST_CHECK(GetBoolArg("-foo", false)); + BOOST_CHECK(GetBoolArg("-foo", true)); + + // New 0.6 feature: auto-map -nosomething to !-something: + ResetArgs("-nofoo"); + BOOST_CHECK(!GetBoolArg("-foo")); + BOOST_CHECK(!GetBoolArg("-foo", false)); + BOOST_CHECK(!GetBoolArg("-foo", true)); + + ResetArgs("-nofoo=1"); + BOOST_CHECK(!GetBoolArg("-foo")); + BOOST_CHECK(!GetBoolArg("-foo", false)); + BOOST_CHECK(!GetBoolArg("-foo", true)); + + ResetArgs("-foo -nofoo"); // -foo should win + BOOST_CHECK(GetBoolArg("-foo")); + BOOST_CHECK(GetBoolArg("-foo", false)); + BOOST_CHECK(GetBoolArg("-foo", true)); + + ResetArgs("-foo=1 -nofoo=1"); // -foo should win + BOOST_CHECK(GetBoolArg("-foo")); + BOOST_CHECK(GetBoolArg("-foo", false)); + BOOST_CHECK(GetBoolArg("-foo", true)); + + ResetArgs("-foo=0 -nofoo=0"); // -foo should win + BOOST_CHECK(!GetBoolArg("-foo")); + BOOST_CHECK(!GetBoolArg("-foo", false)); + BOOST_CHECK(!GetBoolArg("-foo", true)); + + // New 0.6 feature: treat -- same as -: + ResetArgs("--foo=1"); + BOOST_CHECK(GetBoolArg("-foo")); + BOOST_CHECK(GetBoolArg("-foo", false)); + BOOST_CHECK(GetBoolArg("-foo", true)); + + ResetArgs("--nofoo=1"); + BOOST_CHECK(!GetBoolArg("-foo")); + BOOST_CHECK(!GetBoolArg("-foo", false)); + BOOST_CHECK(!GetBoolArg("-foo", true)); + +} + +BOOST_AUTO_TEST_CASE(stringarg) +{ + ResetArgs(""); + BOOST_CHECK_EQUAL(GetArg("-foo", ""), ""); + BOOST_CHECK_EQUAL(GetArg("-foo", "eleven"), "eleven"); + + ResetArgs("-foo -bar"); + BOOST_CHECK_EQUAL(GetArg("-foo", ""), ""); + BOOST_CHECK_EQUAL(GetArg("-foo", "eleven"), ""); + + ResetArgs("-foo="); + BOOST_CHECK_EQUAL(GetArg("-foo", ""), ""); + BOOST_CHECK_EQUAL(GetArg("-foo", "eleven"), ""); + + ResetArgs("-foo=11"); + BOOST_CHECK_EQUAL(GetArg("-foo", ""), "11"); + BOOST_CHECK_EQUAL(GetArg("-foo", "eleven"), "11"); + + ResetArgs("-foo=eleven"); + BOOST_CHECK_EQUAL(GetArg("-foo", ""), "eleven"); + BOOST_CHECK_EQUAL(GetArg("-foo", "eleven"), "eleven"); + +} + +BOOST_AUTO_TEST_CASE(intarg) +{ + ResetArgs(""); + BOOST_CHECK_EQUAL(GetArg("-foo", 11), 11); + BOOST_CHECK_EQUAL(GetArg("-foo", 0), 0); + + ResetArgs("-foo -bar"); + BOOST_CHECK_EQUAL(GetArg("-foo", 11), 0); + BOOST_CHECK_EQUAL(GetArg("-bar", 11), 0); + + ResetArgs("-foo=11 -bar=12"); + BOOST_CHECK_EQUAL(GetArg("-foo", 0), 11); + BOOST_CHECK_EQUAL(GetArg("-bar", 11), 12); + + ResetArgs("-foo=NaN -bar=NotANumber"); + BOOST_CHECK_EQUAL(GetArg("-foo", 1), 0); + BOOST_CHECK_EQUAL(GetArg("-bar", 11), 0); +} + +BOOST_AUTO_TEST_CASE(doubledash) +{ + ResetArgs("--foo"); + BOOST_CHECK_EQUAL(GetBoolArg("-foo"), true); + + ResetArgs("--foo=verbose --bar=1"); + BOOST_CHECK_EQUAL(GetArg("-foo", ""), "verbose"); + BOOST_CHECK_EQUAL(GetArg("-bar", 0), 1); +} + +BOOST_AUTO_TEST_CASE(boolargno) +{ + ResetArgs("-nofoo"); + BOOST_CHECK(!GetBoolArg("-foo")); + BOOST_CHECK(!GetBoolArg("-foo", true)); + BOOST_CHECK(!GetBoolArg("-foo", false)); + + ResetArgs("-nofoo=1"); + BOOST_CHECK(!GetBoolArg("-foo")); + BOOST_CHECK(!GetBoolArg("-foo", true)); + BOOST_CHECK(!GetBoolArg("-foo", false)); + + ResetArgs("-nofoo=0"); + BOOST_CHECK(GetBoolArg("-foo")); + BOOST_CHECK(GetBoolArg("-foo", true)); + BOOST_CHECK(GetBoolArg("-foo", false)); + + ResetArgs("-foo --nofoo"); + BOOST_CHECK(GetBoolArg("-foo")); + + ResetArgs("-nofoo -foo"); // foo always wins: + BOOST_CHECK(GetBoolArg("-foo")); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/key_tests.cpp b/src/test/key_tests.cpp new file mode 100644 index 0000000..0a6df88 --- /dev/null +++ b/src/test/key_tests.cpp @@ -0,0 +1,147 @@ +#include + +#include +#include + +#include "key.h" +#include "base58.h" +#include "uint256.h" +#include "util.h" + +using namespace std; + +static const string strSecret1 ("5HxWvvfubhXpYYpS3tJkw6fq9jE9j18THftkZjHHfmFiWtmAbrj"); +static const string strSecret2 ("5KC4ejrDjv152FGwP386VD1i2NYc5KkfSMyv1nGy1VGDxGHqVY3"); +static const string strSecret1C ("Kwr371tjA9u2rFSMZjTNun2PXXP3WPZu2afRHTcta6KxEUdm1vEw"); +static const string strSecret2C ("L3Hq7a8FEQwJkW1M2GNKDW28546Vp5miewcCzSqUD9kCAXrJdS3g"); +static const CBitcoinAddress addr1 ("1QFqqMUD55ZV3PJEJZtaKCsQmjLT6JkjvJ"); +static const CBitcoinAddress addr2 ("1F5y5E5FMc5YzdJtB9hLaUe43GDxEKXENJ"); +static const CBitcoinAddress addr1C("1NoJrossxPBKfCHuJXT4HadJrXRE9Fxiqs"); +static const CBitcoinAddress addr2C("1CRj2HyM1CXWzHAXLQtiGLyggNT9WQqsDs"); + + +static const string strAddressBad("1HV9Lc3sNHZxwj4Zk6fB38tEmBryq2cBiF"); + + +#ifdef KEY_TESTS_DUMPINFO +void dumpKeyInfo(uint256 privkey) +{ + CSecret secret; + secret.resize(32); + memcpy(&secret[0], &privkey, 32); + vector sec; + sec.resize(32); + memcpy(&sec[0], &secret[0], 32); + printf(" * secret (hex): %s\n", HexStr(sec).c_str()); + + for (int nCompressed=0; nCompressed<2; nCompressed++) + { + bool fCompressed = nCompressed == 1; + printf(" * %s:\n", fCompressed ? "compressed" : "uncompressed"); + CBitcoinSecret bsecret; + bsecret.SetSecret(secret, fCompressed); + printf(" * secret (base58): %s\n", bsecret.ToString().c_str()); + CKey key; + key.SetSecret(secret, fCompressed); + vector vchPubKey = key.GetPubKey(); + printf(" * pubkey (hex): %s\n", HexStr(vchPubKey).c_str()); + printf(" * address (base58): %s\n", CBitcoinAddress(vchPubKey).ToString().c_str()); + } +} +#endif + + +BOOST_AUTO_TEST_SUITE(key_tests) + +BOOST_AUTO_TEST_CASE(key_test1) +{ + CBitcoinSecret bsecret1, bsecret2, bsecret1C, bsecret2C, baddress1; + BOOST_CHECK( bsecret1.SetString (strSecret1)); + BOOST_CHECK( bsecret2.SetString (strSecret2)); + BOOST_CHECK( bsecret1C.SetString(strSecret1C)); + BOOST_CHECK( bsecret2C.SetString(strSecret2C)); + BOOST_CHECK(!baddress1.SetString(strAddressBad)); + + bool fCompressed; + CSecret secret1 = bsecret1.GetSecret (fCompressed); + BOOST_CHECK(fCompressed == false); + CSecret secret2 = bsecret2.GetSecret (fCompressed); + BOOST_CHECK(fCompressed == false); + CSecret secret1C = bsecret1C.GetSecret(fCompressed); + BOOST_CHECK(fCompressed == true); + CSecret secret2C = bsecret2C.GetSecret(fCompressed); + BOOST_CHECK(fCompressed == true); + + BOOST_CHECK(secret1 == secret1C); + BOOST_CHECK(secret2 == secret2C); + + CKey key1, key2, key1C, key2C; + key1.SetSecret(secret1, false); + key2.SetSecret(secret2, false); + key1C.SetSecret(secret1, true); + key2C.SetSecret(secret2, true); + + BOOST_CHECK(addr1.Get() == CTxDestination(key1.GetPubKey().GetID())); + BOOST_CHECK(addr2.Get() == CTxDestination(key2.GetPubKey().GetID())); + BOOST_CHECK(addr1C.Get() == CTxDestination(key1C.GetPubKey().GetID())); + BOOST_CHECK(addr2C.Get() == CTxDestination(key2C.GetPubKey().GetID())); + + for (int n=0; n<16; n++) + { + string strMsg = strprintf("Very secret message %i: 11", n); + uint256 hashMsg = Hash(strMsg.begin(), strMsg.end()); + + // normal signatures + + vector sign1, sign2, sign1C, sign2C; + + BOOST_CHECK(key1.Sign (hashMsg, sign1)); + BOOST_CHECK(key2.Sign (hashMsg, sign2)); + BOOST_CHECK(key1C.Sign(hashMsg, sign1C)); + BOOST_CHECK(key2C.Sign(hashMsg, sign2C)); + + BOOST_CHECK( key1.Verify(hashMsg, sign1)); + BOOST_CHECK(!key1.Verify(hashMsg, sign2)); + BOOST_CHECK( key1.Verify(hashMsg, sign1C)); + BOOST_CHECK(!key1.Verify(hashMsg, sign2C)); + + BOOST_CHECK(!key2.Verify(hashMsg, sign1)); + BOOST_CHECK( key2.Verify(hashMsg, sign2)); + BOOST_CHECK(!key2.Verify(hashMsg, sign1C)); + BOOST_CHECK( key2.Verify(hashMsg, sign2C)); + + BOOST_CHECK( key1C.Verify(hashMsg, sign1)); + BOOST_CHECK(!key1C.Verify(hashMsg, sign2)); + BOOST_CHECK( key1C.Verify(hashMsg, sign1C)); + BOOST_CHECK(!key1C.Verify(hashMsg, sign2C)); + + BOOST_CHECK(!key2C.Verify(hashMsg, sign1)); + BOOST_CHECK( key2C.Verify(hashMsg, sign2)); + BOOST_CHECK(!key2C.Verify(hashMsg, sign1C)); + BOOST_CHECK( key2C.Verify(hashMsg, sign2C)); + + // compact signatures (with key recovery) + + vector csign1, csign2, csign1C, csign2C; + + BOOST_CHECK(key1.SignCompact (hashMsg, csign1)); + BOOST_CHECK(key2.SignCompact (hashMsg, csign2)); + BOOST_CHECK(key1C.SignCompact(hashMsg, csign1C)); + BOOST_CHECK(key2C.SignCompact(hashMsg, csign2C)); + + CKey rkey1, rkey2, rkey1C, rkey2C; + + BOOST_CHECK(rkey1.SetCompactSignature (hashMsg, csign1)); + BOOST_CHECK(rkey2.SetCompactSignature (hashMsg, csign2)); + BOOST_CHECK(rkey1C.SetCompactSignature(hashMsg, csign1C)); + BOOST_CHECK(rkey2C.SetCompactSignature(hashMsg, csign2C)); + + + BOOST_CHECK(rkey1.GetPubKey() == key1.GetPubKey()); + BOOST_CHECK(rkey2.GetPubKey() == key2.GetPubKey()); + BOOST_CHECK(rkey1C.GetPubKey() == key1C.GetPubKey()); + BOOST_CHECK(rkey2C.GetPubKey() == key2C.GetPubKey()); + } +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp new file mode 100644 index 0000000..4558a76 --- /dev/null +++ b/src/test/miner_tests.cpp @@ -0,0 +1,227 @@ +#include + +#include "init.h" +#include "main.h" +#include "uint256.h" +#include "util.h" +#include "wallet.h" + +extern void SHA256Transform(void* pstate, void* pinput, const void* pinit); + +BOOST_AUTO_TEST_SUITE(miner_tests) + +static +struct { + unsigned char extranonce; + unsigned int nonce; +} blockinfo[] = { + {4, 0xa4a3e223}, {2, 0x15c32f9e}, {1, 0x0375b547}, {1, 0x7004a8a5}, + {2, 0xce440296}, {2, 0x52cfe198}, {1, 0x77a72cd0}, {2, 0xbb5d6f84}, + {2, 0x83f30c2c}, {1, 0x48a73d5b}, {1, 0xef7dcd01}, {2, 0x6809c6c4}, + {2, 0x0883ab3c}, {1, 0x087bbbe2}, {2, 0x2104a814}, {2, 0xdffb6daa}, + {1, 0xee8a0a08}, {2, 0xba4237c1}, {1, 0xa70349dc}, {1, 0x344722bb}, + {3, 0xd6294733}, {2, 0xec9f5c94}, {2, 0xca2fbc28}, {1, 0x6ba4f406}, + {2, 0x015d4532}, {1, 0x6e119b7c}, {2, 0x43e8f314}, {2, 0x27962f38}, + {2, 0xb571b51b}, {2, 0xb36bee23}, {2, 0xd17924a8}, {2, 0x6bc212d9}, + {1, 0x630d4948}, {2, 0x9a4c4ebb}, {2, 0x554be537}, {1, 0xd63ddfc7}, + {2, 0xa10acc11}, {1, 0x759a8363}, {2, 0xfb73090d}, {1, 0xe82c6a34}, + {1, 0xe33e92d7}, {3, 0x658ef5cb}, {2, 0xba32ff22}, {5, 0x0227a10c}, + {1, 0xa9a70155}, {5, 0xd096d809}, {1, 0x37176174}, {1, 0x830b8d0f}, + {1, 0xc6e3910e}, {2, 0x823f3ca8}, {1, 0x99850849}, {1, 0x7521fb81}, + {1, 0xaacaabab}, {1, 0xd645a2eb}, {5, 0x7aea1781}, {5, 0x9d6e4b78}, + {1, 0x4ce90fd8}, {1, 0xabdc832d}, {6, 0x4a34f32a}, {2, 0xf2524c1c}, + {2, 0x1bbeb08a}, {1, 0xad47f480}, {1, 0x9f026aeb}, {1, 0x15a95049}, + {2, 0xd1cb95b2}, {2, 0xf84bbda5}, {1, 0x0fa62cd1}, {1, 0xe05f9169}, + {1, 0x78d194a9}, {5, 0x3e38147b}, {5, 0x737ba0d4}, {1, 0x63378e10}, + {1, 0x6d5f91cf}, {2, 0x88612eb8}, {2, 0xe9639484}, {1, 0xb7fabc9d}, + {2, 0x19b01592}, {1, 0x5a90dd31}, {2, 0x5bd7e028}, {2, 0x94d00323}, + {1, 0xa9b9c01a}, {1, 0x3a40de61}, {1, 0x56e7eec7}, {5, 0x859f7ef6}, + {1, 0xfd8e5630}, {1, 0x2b0c9f7f}, {1, 0xba700e26}, {1, 0x7170a408}, + {1, 0x70de86a8}, {1, 0x74d64cd5}, {1, 0x49e738a1}, {2, 0x6910b602}, + {0, 0x643c565f}, {1, 0x54264b3f}, {2, 0x97ea6396}, {2, 0x55174459}, + {2, 0x03e8779a}, {1, 0x98f34d8f}, {1, 0xc07b2b07}, {1, 0xdfe29668}, + {1, 0x3141c7c1}, {1, 0xb3b595f4}, {1, 0x735abf08}, {5, 0x623bfbce}, + {2, 0xd351e722}, {1, 0xf4ca48c9}, {1, 0x5b19c670}, {1, 0xa164bf0e}, + {2, 0xbbbeb305}, {2, 0xfe1c810a}, +}; + +// NOTE: These tests rely on CreateNewBlock doing its own self-validation! +BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) +{ + CReserveKey reservekey(pwalletMain); + CBlock *pblock; + CTransaction tx; + CScript script; + uint256 hash; + + // Simple block creation, nothing special yet: + BOOST_CHECK(pblock = CreateNewBlock(reservekey)); + + // We can't make transactions until we have inputs + // Therefore, load 100 blocks :) + std::vectortxFirst; + for (unsigned int i = 0; i < sizeof(blockinfo)/sizeof(*blockinfo); ++i) + { + pblock->nVersion = 1; + pblock->nTime = pindexBest->GetMedianTimePast()+1; + pblock->vtx[0].vin[0].scriptSig = CScript(); + pblock->vtx[0].vin[0].scriptSig.push_back(blockinfo[i].extranonce); + pblock->vtx[0].vin[0].scriptSig.push_back(pindexBest->nHeight); + pblock->vtx[0].vout[0].scriptPubKey = CScript(); + if (txFirst.size() < 2) + txFirst.push_back(new CTransaction(pblock->vtx[0])); + pblock->hashMerkleRoot = pblock->BuildMerkleTree(); + pblock->nNonce = blockinfo[i].nonce; + assert(ProcessBlock(NULL, pblock)); + pblock->hashPrevBlock = pblock->GetHash(); + } + delete pblock; + + // Just to make sure we can still make simple blocks + BOOST_CHECK(pblock = CreateNewBlock(reservekey)); + + // block sigops > limit: 1000 CHECKMULTISIG + 1 + tx.vin.resize(1); + // NOTE: OP_NOP is used to force 20 SigOps for the CHECKMULTISIG + tx.vin[0].scriptSig = CScript() << OP_0 << OP_0 << OP_0 << OP_NOP << OP_CHECKMULTISIG << OP_1; + tx.vin[0].prevout.hash = txFirst[0]->GetHash(); + tx.vin[0].prevout.n = 0; + tx.vout.resize(1); + tx.vout[0].nValue = 5000000000LL; + for (unsigned int i = 0; i < 1001; ++i) + { + tx.vout[0].nValue -= 1000000; + hash = tx.GetHash(); + mempool.addUnchecked(hash, tx); + tx.vin[0].prevout.hash = hash; + } + BOOST_CHECK(pblock = CreateNewBlock(reservekey)); + delete pblock; + mempool.clear(); + + // block size > limit + tx.vin[0].scriptSig = CScript(); + // 18 * (520char + DROP) + OP_1 = 9433 bytes + std::vector vchData(520); + for (unsigned int i = 0; i < 18; ++i) + tx.vin[0].scriptSig << vchData << OP_DROP; + tx.vin[0].scriptSig << OP_1; + tx.vin[0].prevout.hash = txFirst[0]->GetHash(); + tx.vout[0].nValue = 5000000000LL; + for (unsigned int i = 0; i < 128; ++i) + { + tx.vout[0].nValue -= 10000000; + hash = tx.GetHash(); + mempool.addUnchecked(hash, tx); + tx.vin[0].prevout.hash = hash; + } + BOOST_CHECK(pblock = CreateNewBlock(reservekey)); + delete pblock; + mempool.clear(); + + // orphan in mempool + hash = tx.GetHash(); + mempool.addUnchecked(hash, tx); + BOOST_CHECK(pblock = CreateNewBlock(reservekey)); + delete pblock; + mempool.clear(); + + // child with higher priority than parent + tx.vin[0].scriptSig = CScript() << OP_1; + tx.vin[0].prevout.hash = txFirst[1]->GetHash(); + tx.vout[0].nValue = 4900000000LL; + hash = tx.GetHash(); + mempool.addUnchecked(hash, tx); + tx.vin[0].prevout.hash = hash; + tx.vin.resize(2); + tx.vin[1].scriptSig = CScript() << OP_1; + tx.vin[1].prevout.hash = txFirst[0]->GetHash(); + tx.vin[1].prevout.n = 0; + tx.vout[0].nValue = 5900000000LL; + hash = tx.GetHash(); + mempool.addUnchecked(hash, tx); + BOOST_CHECK(pblock = CreateNewBlock(reservekey)); + delete pblock; + mempool.clear(); + + // coinbase in mempool + tx.vin.resize(1); + tx.vin[0].prevout.SetNull(); + tx.vin[0].scriptSig = CScript() << OP_0 << OP_1; + tx.vout[0].nValue = 0; + hash = tx.GetHash(); + mempool.addUnchecked(hash, tx); + BOOST_CHECK(pblock = CreateNewBlock(reservekey)); + delete pblock; + mempool.clear(); + + // invalid (pre-p2sh) txn in mempool + tx.vin[0].prevout.hash = txFirst[0]->GetHash(); + tx.vin[0].prevout.n = 0; + tx.vin[0].scriptSig = CScript() << OP_1; + tx.vout[0].nValue = 4900000000LL; + script = CScript() << OP_0; + tx.vout[0].scriptPubKey.SetDestination(script.GetID()); + hash = tx.GetHash(); + mempool.addUnchecked(hash, tx); + tx.vin[0].prevout.hash = hash; + tx.vin[0].scriptSig = CScript() << (std::vector)script; + tx.vout[0].nValue -= 1000000; + hash = tx.GetHash(); + mempool.addUnchecked(hash,tx); + BOOST_CHECK(pblock = CreateNewBlock(reservekey)); + delete pblock; + mempool.clear(); + + // double spend txn pair in mempool + tx.vin[0].prevout.hash = txFirst[0]->GetHash(); + tx.vin[0].scriptSig = CScript() << OP_1; + tx.vout[0].nValue = 4900000000LL; + tx.vout[0].scriptPubKey = CScript() << OP_1; + hash = tx.GetHash(); + mempool.addUnchecked(hash, tx); + tx.vout[0].scriptPubKey = CScript() << OP_2; + hash = tx.GetHash(); + mempool.addUnchecked(hash, tx); + BOOST_CHECK(pblock = CreateNewBlock(reservekey)); + delete pblock; + mempool.clear(); + + // subsidy changing + int nHeight = pindexBest->nHeight; + pindexBest->nHeight = 209999; + BOOST_CHECK(pblock = CreateNewBlock(reservekey)); + delete pblock; + pindexBest->nHeight = 210000; + BOOST_CHECK(pblock = CreateNewBlock(reservekey)); + delete pblock; + pindexBest->nHeight = nHeight; +} + +BOOST_AUTO_TEST_CASE(sha256transform_equality) +{ + unsigned int pSHA256InitState[8] = {0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19}; + + + // unsigned char pstate[32]; + unsigned char pinput[64]; + + int i; + + for (i = 0; i < 32; i++) { + pinput[i] = i; + pinput[i+32] = 0; + } + + uint256 hash; + + SHA256Transform(&hash, pinput, pSHA256InitState); + + BOOST_TEST_MESSAGE(hash.GetHex()); + + uint256 hash_reference("0x2df5e1c65ef9f8cde240d23cae2ec036d31a15ec64bc68f64be242b1da6631f3"); + + BOOST_CHECK(hash == hash_reference); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/mruset_tests.cpp b/src/test/mruset_tests.cpp new file mode 100644 index 0000000..64a6678 --- /dev/null +++ b/src/test/mruset_tests.cpp @@ -0,0 +1,90 @@ +#include + +using namespace std; + +#include "mruset.h" +#include "util.h" + +#define NUM_TESTS 16 +#define MAX_SIZE 100 + +class mrutester +{ +private: + mruset mru; + std::set set; + +public: + mrutester() { mru.max_size(MAX_SIZE); } + int size() const { return set.size(); } + + void insert(int n) + { + mru.insert(n); + set.insert(n); + BOOST_CHECK(mru == set); + } +}; + +BOOST_AUTO_TEST_SUITE(mruset_tests) + +// Test that an mruset behaves like a set, as long as no more than MAX_SIZE elements are in it +BOOST_AUTO_TEST_CASE(mruset_like_set) +{ + + for (int nTest=0; nTest mru(MAX_SIZE); + for (int nAction=0; nAction<3*MAX_SIZE; nAction++) + { + int n = GetRandInt(2 * MAX_SIZE); + mru.insert(n); + BOOST_CHECK(mru.size() <= MAX_SIZE); + } + } +} + +// 16-bit permutation function +int static permute(int n) +{ + // hexadecimals of pi; verified to be linearly independent + static const int table[16] = {0x243F, 0x6A88, 0x85A3, 0x08D3, 0x1319, 0x8A2E, 0x0370, 0x7344, + 0xA409, 0x3822, 0x299F, 0x31D0, 0x082E, 0xFA98, 0xEC4E, 0x6C89}; + + int ret = 0; + for (int bit=0; bit<16; bit++) + if (n & (1< mru(MAX_SIZE); + for (int n=0; n<10*MAX_SIZE; n++) + { + mru.insert(permute(n)); + + set tester; + for (int m=max(0,n-MAX_SIZE+1); m<=n; m++) + tester.insert(permute(m)); + + BOOST_CHECK(mru == tester); + } +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/multisig_tests.cpp b/src/test/multisig_tests.cpp new file mode 100644 index 0000000..6bc5e3b --- /dev/null +++ b/src/test/multisig_tests.cpp @@ -0,0 +1,296 @@ +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "keystore.h" +#include "main.h" +#include "script.h" +#include "wallet.h" + +using namespace std; +using namespace boost::assign; + +typedef vector valtype; + +extern uint256 SignatureHash(CScript scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType); +extern bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn, + bool fValidatePayToScriptHash, int nHashType); + +BOOST_AUTO_TEST_SUITE(multisig_tests) + +CScript +sign_multisig(CScript scriptPubKey, vector keys, CTransaction transaction, int whichIn) +{ + uint256 hash = SignatureHash(scriptPubKey, transaction, whichIn, SIGHASH_ALL); + + CScript result; + result << OP_0; // CHECKMULTISIG bug workaround + BOOST_FOREACH(CKey key, keys) + { + vector vchSig; + BOOST_CHECK(key.Sign(hash, vchSig)); + vchSig.push_back((unsigned char)SIGHASH_ALL); + result << vchSig; + } + return result; +} + +BOOST_AUTO_TEST_CASE(multisig_verify) +{ + CKey key[4]; + for (int i = 0; i < 4; i++) + key[i].MakeNewKey(true); + + CScript a_and_b; + a_and_b << OP_2 << key[0].GetPubKey() << key[1].GetPubKey() << OP_2 << OP_CHECKMULTISIG; + + CScript a_or_b; + a_or_b << OP_1 << key[0].GetPubKey() << key[1].GetPubKey() << OP_2 << OP_CHECKMULTISIG; + + CScript escrow; + escrow << OP_2 << key[0].GetPubKey() << key[1].GetPubKey() << key[2].GetPubKey() << OP_3 << OP_CHECKMULTISIG; + + CTransaction txFrom; // Funding transaction + txFrom.vout.resize(3); + txFrom.vout[0].scriptPubKey = a_and_b; + txFrom.vout[1].scriptPubKey = a_or_b; + txFrom.vout[2].scriptPubKey = escrow; + + CTransaction txTo[3]; // Spending transaction + for (int i = 0; i < 3; i++) + { + txTo[i].vin.resize(1); + txTo[i].vout.resize(1); + txTo[i].vin[0].prevout.n = i; + txTo[i].vin[0].prevout.hash = txFrom.GetHash(); + txTo[i].vout[0].nValue = 1; + } + + vector keys; + CScript s; + + // Test a AND b: + keys.clear(); + keys += key[0],key[1]; // magic operator+= from boost.assign + s = sign_multisig(a_and_b, keys, txTo[0], 0); + BOOST_CHECK(VerifyScript(s, a_and_b, txTo[0], 0, true, 0)); + + for (int i = 0; i < 4; i++) + { + keys.clear(); + keys += key[i]; + s = sign_multisig(a_and_b, keys, txTo[0], 0); + BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, txTo[0], 0, true, 0), strprintf("a&b 1: %d", i)); + + keys.clear(); + keys += key[1],key[i]; + s = sign_multisig(a_and_b, keys, txTo[0], 0); + BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, txTo[0], 0, true, 0), strprintf("a&b 2: %d", i)); + } + + // Test a OR b: + for (int i = 0; i < 4; i++) + { + keys.clear(); + keys += key[i]; + s = sign_multisig(a_or_b, keys, txTo[1], 0); + if (i == 0 || i == 1) + BOOST_CHECK_MESSAGE(VerifyScript(s, a_or_b, txTo[1], 0, true, 0), strprintf("a|b: %d", i)); + else + BOOST_CHECK_MESSAGE(!VerifyScript(s, a_or_b, txTo[1], 0, true, 0), strprintf("a|b: %d", i)); + } + s.clear(); + s << OP_0 << OP_0; + BOOST_CHECK(!VerifyScript(s, a_or_b, txTo[1], 0, true, 0)); + s.clear(); + s << OP_0 << OP_1; + BOOST_CHECK(!VerifyScript(s, a_or_b, txTo[1], 0, true, 0)); + + + for (int i = 0; i < 4; i++) + for (int j = 0; j < 4; j++) + { + keys.clear(); + keys += key[i],key[j]; + s = sign_multisig(escrow, keys, txTo[2], 0); + if (i < j && i < 3 && j < 3) + BOOST_CHECK_MESSAGE(VerifyScript(s, escrow, txTo[2], 0, true, 0), strprintf("escrow 1: %d %d", i, j)); + else + BOOST_CHECK_MESSAGE(!VerifyScript(s, escrow, txTo[2], 0, true, 0), strprintf("escrow 2: %d %d", i, j)); + } +} + +BOOST_AUTO_TEST_CASE(multisig_IsStandard) +{ + CKey key[4]; + for (int i = 0; i < 4; i++) + key[i].MakeNewKey(true); + + CScript a_and_b; + a_and_b << OP_2 << key[0].GetPubKey() << key[1].GetPubKey() << OP_2 << OP_CHECKMULTISIG; + BOOST_CHECK(::IsStandard(a_and_b)); + + CScript a_or_b; + a_or_b << OP_1 << key[0].GetPubKey() << key[1].GetPubKey() << OP_2 << OP_CHECKMULTISIG; + BOOST_CHECK(::IsStandard(a_or_b)); + + CScript escrow; + escrow << OP_2 << key[0].GetPubKey() << key[1].GetPubKey() << key[2].GetPubKey() << OP_3 << OP_CHECKMULTISIG; + BOOST_CHECK(::IsStandard(escrow)); + + CScript one_of_four; + one_of_four << OP_1 << key[0].GetPubKey() << key[1].GetPubKey() << key[2].GetPubKey() << key[3].GetPubKey() << OP_4 << OP_CHECKMULTISIG; + BOOST_CHECK(!::IsStandard(one_of_four)); + + CScript malformed[6]; + malformed[0] << OP_3 << key[0].GetPubKey() << key[1].GetPubKey() << OP_2 << OP_CHECKMULTISIG; + malformed[1] << OP_2 << key[0].GetPubKey() << key[1].GetPubKey() << OP_3 << OP_CHECKMULTISIG; + malformed[2] << OP_0 << key[0].GetPubKey() << key[1].GetPubKey() << OP_2 << OP_CHECKMULTISIG; + malformed[3] << OP_1 << key[0].GetPubKey() << key[1].GetPubKey() << OP_0 << OP_CHECKMULTISIG; + malformed[4] << OP_1 << key[0].GetPubKey() << key[1].GetPubKey() << OP_CHECKMULTISIG; + malformed[5] << OP_1 << key[0].GetPubKey() << key[1].GetPubKey(); + + for (int i = 0; i < 6; i++) + BOOST_CHECK(!::IsStandard(malformed[i])); +} + +BOOST_AUTO_TEST_CASE(multisig_Solver1) +{ + // Tests Solver() that returns lists of keys that are + // required to satisfy a ScriptPubKey + // + // Also tests IsMine() and ExtractAddress() + // + // Note: ExtractAddress for the multisignature transactions + // always returns false for this release, even if you have + // one key that would satisfy an (a|b) or 2-of-3 keys needed + // to spend an escrow transaction. + // + CBasicKeyStore keystore, emptykeystore, partialkeystore; + CKey key[3]; + CTxDestination keyaddr[3]; + for (int i = 0; i < 3; i++) + { + key[i].MakeNewKey(true); + keystore.AddKey(key[i]); + keyaddr[i] = key[i].GetPubKey().GetID(); + } + partialkeystore.AddKey(key[0]); + + { + vector solutions; + txnouttype whichType; + CScript s; + s << key[0].GetPubKey() << OP_CHECKSIG; + BOOST_CHECK(Solver(s, whichType, solutions)); + BOOST_CHECK(solutions.size() == 1); + CTxDestination addr; + BOOST_CHECK(ExtractDestination(s, addr)); + BOOST_CHECK(addr == keyaddr[0]); + BOOST_CHECK(IsMine(keystore, s)); + BOOST_CHECK(!IsMine(emptykeystore, s)); + } + { + vector solutions; + txnouttype whichType; + CScript s; + s << OP_DUP << OP_HASH160 << key[0].GetPubKey().GetID() << OP_EQUALVERIFY << OP_CHECKSIG; + BOOST_CHECK(Solver(s, whichType, solutions)); + BOOST_CHECK(solutions.size() == 1); + CTxDestination addr; + BOOST_CHECK(ExtractDestination(s, addr)); + BOOST_CHECK(addr == keyaddr[0]); + BOOST_CHECK(IsMine(keystore, s)); + BOOST_CHECK(!IsMine(emptykeystore, s)); + } + { + vector solutions; + txnouttype whichType; + CScript s; + s << OP_2 << key[0].GetPubKey() << key[1].GetPubKey() << OP_2 << OP_CHECKMULTISIG; + BOOST_CHECK(Solver(s, whichType, solutions)); + BOOST_CHECK_EQUAL(solutions.size(), 4); + CTxDestination addr; + BOOST_CHECK(!ExtractDestination(s, addr)); + BOOST_CHECK(IsMine(keystore, s)); + BOOST_CHECK(!IsMine(emptykeystore, s)); + BOOST_CHECK(!IsMine(partialkeystore, s)); + } + { + vector solutions; + txnouttype whichType; + CScript s; + s << OP_1 << key[0].GetPubKey() << key[1].GetPubKey() << OP_2 << OP_CHECKMULTISIG; + BOOST_CHECK(Solver(s, whichType, solutions)); + BOOST_CHECK_EQUAL(solutions.size(), 4); + vector addrs; + int nRequired; + BOOST_CHECK(ExtractDestinations(s, whichType, addrs, nRequired)); + BOOST_CHECK(addrs[0] == keyaddr[0]); + BOOST_CHECK(addrs[1] == keyaddr[1]); + BOOST_CHECK(nRequired == 1); + BOOST_CHECK(IsMine(keystore, s)); + BOOST_CHECK(!IsMine(emptykeystore, s)); + BOOST_CHECK(!IsMine(partialkeystore, s)); + } + { + vector solutions; + txnouttype whichType; + CScript s; + s << OP_2 << key[0].GetPubKey() << key[1].GetPubKey() << key[2].GetPubKey() << OP_3 << OP_CHECKMULTISIG; + BOOST_CHECK(Solver(s, whichType, solutions)); + BOOST_CHECK(solutions.size() == 5); + } +} + +BOOST_AUTO_TEST_CASE(multisig_Sign) +{ + // Test SignSignature() (and therefore the version of Solver() that signs transactions) + CBasicKeyStore keystore; + CKey key[4]; + for (int i = 0; i < 4; i++) + { + key[i].MakeNewKey(true); + keystore.AddKey(key[i]); + } + + CScript a_and_b; + a_and_b << OP_2 << key[0].GetPubKey() << key[1].GetPubKey() << OP_2 << OP_CHECKMULTISIG; + + CScript a_or_b; + a_or_b << OP_1 << key[0].GetPubKey() << key[1].GetPubKey() << OP_2 << OP_CHECKMULTISIG; + + CScript escrow; + escrow << OP_2 << key[0].GetPubKey() << key[1].GetPubKey() << key[2].GetPubKey() << OP_3 << OP_CHECKMULTISIG; + + CTransaction txFrom; // Funding transaction + txFrom.vout.resize(3); + txFrom.vout[0].scriptPubKey = a_and_b; + txFrom.vout[1].scriptPubKey = a_or_b; + txFrom.vout[2].scriptPubKey = escrow; + + CTransaction txTo[3]; // Spending transaction + for (int i = 0; i < 3; i++) + { + txTo[i].vin.resize(1); + txTo[i].vout.resize(1); + txTo[i].vin[0].prevout.n = i; + txTo[i].vin[0].prevout.hash = txFrom.GetHash(); + txTo[i].vout[0].nValue = 1; + } + + for (int i = 0; i < 3; i++) + { + BOOST_CHECK_MESSAGE(SignSignature(keystore, txFrom, txTo[i], 0), strprintf("SignSignature %d", i)); + } +} + + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/netbase_tests.cpp b/src/test/netbase_tests.cpp new file mode 100644 index 0000000..e5a7562 --- /dev/null +++ b/src/test/netbase_tests.cpp @@ -0,0 +1,102 @@ +#include + +#include +#include + +#include "netbase.h" + +using namespace std; + +BOOST_AUTO_TEST_SUITE(netbase_tests) + +BOOST_AUTO_TEST_CASE(netbase_networks) +{ + BOOST_CHECK(CNetAddr("127.0.0.1").GetNetwork() == NET_UNROUTABLE); + BOOST_CHECK(CNetAddr("::1").GetNetwork() == NET_UNROUTABLE); + BOOST_CHECK(CNetAddr("8.8.8.8").GetNetwork() == NET_IPV4); + BOOST_CHECK(CNetAddr("2001::8888").GetNetwork() == NET_IPV6); + BOOST_CHECK(CNetAddr("FD87:D87E:EB43:edb1:8e4:3588:e546:35ca").GetNetwork() == NET_TOR); +} + +BOOST_AUTO_TEST_CASE(netbase_properties) +{ + BOOST_CHECK(CNetAddr("127.0.0.1").IsIPv4()); + BOOST_CHECK(CNetAddr("::FFFF:192.168.1.1").IsIPv4()); + BOOST_CHECK(CNetAddr("::1").IsIPv6()); + BOOST_CHECK(CNetAddr("10.0.0.1").IsRFC1918()); + BOOST_CHECK(CNetAddr("192.168.1.1").IsRFC1918()); + BOOST_CHECK(CNetAddr("172.31.255.255").IsRFC1918()); + BOOST_CHECK(CNetAddr("2001:0DB8::").IsRFC3849()); + BOOST_CHECK(CNetAddr("169.254.1.1").IsRFC3927()); + BOOST_CHECK(CNetAddr("2002::1").IsRFC3964()); + BOOST_CHECK(CNetAddr("FC00::").IsRFC4193()); + BOOST_CHECK(CNetAddr("2001::2").IsRFC4380()); + BOOST_CHECK(CNetAddr("2001:10::").IsRFC4843()); + BOOST_CHECK(CNetAddr("FE80::").IsRFC4862()); + BOOST_CHECK(CNetAddr("64:FF9B::").IsRFC6052()); + BOOST_CHECK(CNetAddr("FD87:D87E:EB43:edb1:8e4:3588:e546:35ca").IsTor()); + BOOST_CHECK(CNetAddr("127.0.0.1").IsLocal()); + BOOST_CHECK(CNetAddr("::1").IsLocal()); + BOOST_CHECK(CNetAddr("8.8.8.8").IsRoutable()); + BOOST_CHECK(CNetAddr("2001::1").IsRoutable()); + BOOST_CHECK(CNetAddr("127.0.0.1").IsValid()); +} + +bool static TestSplitHost(string test, string host, int port) +{ + string hostOut; + int portOut = -1; + SplitHostPort(test, portOut, hostOut); + return hostOut == host && port == portOut; +} + +BOOST_AUTO_TEST_CASE(netbase_splithost) +{ + BOOST_CHECK(TestSplitHost("www.bitcoin.org", "www.bitcoin.org", -1)); + BOOST_CHECK(TestSplitHost("[www.bitcoin.org]", "www.bitcoin.org", -1)); + BOOST_CHECK(TestSplitHost("www.bitcoin.org:80", "www.bitcoin.org", 80)); + BOOST_CHECK(TestSplitHost("[www.bitcoin.org]:80", "www.bitcoin.org", 80)); + BOOST_CHECK(TestSplitHost("127.0.0.1", "127.0.0.1", -1)); + BOOST_CHECK(TestSplitHost("127.0.0.1:8333", "127.0.0.1", 8333)); + BOOST_CHECK(TestSplitHost("[127.0.0.1]", "127.0.0.1", -1)); + BOOST_CHECK(TestSplitHost("[127.0.0.1]:8333", "127.0.0.1", 8333)); + BOOST_CHECK(TestSplitHost("::ffff:127.0.0.1", "::ffff:127.0.0.1", -1)); + BOOST_CHECK(TestSplitHost("[::ffff:127.0.0.1]:8333", "::ffff:127.0.0.1", 8333)); + BOOST_CHECK(TestSplitHost("[::]:8333", "::", 8333)); + BOOST_CHECK(TestSplitHost("::8333", "::8333", -1)); + BOOST_CHECK(TestSplitHost(":8333", "", 8333)); + BOOST_CHECK(TestSplitHost("[]:8333", "", 8333)); + BOOST_CHECK(TestSplitHost("", "", -1)); +} + +bool static TestParse(string src, string canon) +{ + CService addr; + if (!LookupNumeric(src.c_str(), addr, 65535)) + return canon == ""; + return canon == addr.ToString(); +} + +BOOST_AUTO_TEST_CASE(netbase_lookupnumeric) +{ + BOOST_CHECK(TestParse("127.0.0.1", "127.0.0.1:65535")); + BOOST_CHECK(TestParse("127.0.0.1:8333", "127.0.0.1:8333")); + BOOST_CHECK(TestParse("::ffff:127.0.0.1", "127.0.0.1:65535")); + BOOST_CHECK(TestParse("::", "[::]:65535")); + BOOST_CHECK(TestParse("[::]:8333", "[::]:8333")); + BOOST_CHECK(TestParse("[127.0.0.1]", "127.0.0.1:65535")); + BOOST_CHECK(TestParse(":::", "")); +} + +BOOST_AUTO_TEST_CASE(onioncat_test) +{ + // values from http://www.cypherpunk.at/onioncat/wiki/OnionCat + CNetAddr addr1("5wyqrzbvrdsumnok.onion"); + CNetAddr addr2("FD87:D87E:EB43:edb1:8e4:3588:e546:35ca"); + BOOST_CHECK(addr1 == addr2); + BOOST_CHECK(addr1.IsTor()); + BOOST_CHECK(addr1.ToStringIP() == "5wyqrzbvrdsumnok.onion"); + BOOST_CHECK(addr1.IsRoutable()); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/rpc_tests.cpp b/src/test/rpc_tests.cpp new file mode 100644 index 0000000..505ec8f --- /dev/null +++ b/src/test/rpc_tests.cpp @@ -0,0 +1,62 @@ +#include +#include + +#include "base58.h" +#include "util.h" +#include "bitcoinrpc.h" + +using namespace std; +using namespace json_spirit; + +BOOST_AUTO_TEST_SUITE(rpc_tests) + +static Array +createArgs(int nRequired, const char* address1=NULL, const char* address2=NULL) +{ + Array result; + result.push_back(nRequired); + Array addresses; + if (address1) addresses.push_back(address1); + if (address2) addresses.push_back(address2); + result.push_back(addresses); + return result; +} + +BOOST_AUTO_TEST_CASE(rpc_addmultisig) +{ + rpcfn_type addmultisig = tableRPC["addmultisigaddress"]->actor; + + // old, 65-byte-long: + const char address1Hex[] = "0434e3e09f49ea168c5bbf53f877ff4206923858aab7c7e1df25bc263978107c95e35065a27ef6f1b27222db0ec97e0e895eaca603d3ee0d4c060ce3d8a00286c8"; + // new, compressed: + const char address2Hex[] = "0388c2037017c62240b6b72ac1a2a5f94da790596ebd06177c8572752922165cb4"; + + Value v; + CBitcoinAddress address; + BOOST_CHECK_NO_THROW(v = addmultisig(createArgs(1, address1Hex), false)); + address.SetString(v.get_str()); + BOOST_CHECK(address.IsValid() && address.IsScript()); + + BOOST_CHECK_NO_THROW(v = addmultisig(createArgs(1, address1Hex, address2Hex), false)); + address.SetString(v.get_str()); + BOOST_CHECK(address.IsValid() && address.IsScript()); + + BOOST_CHECK_NO_THROW(v = addmultisig(createArgs(2, address1Hex, address2Hex), false)); + address.SetString(v.get_str()); + BOOST_CHECK(address.IsValid() && address.IsScript()); + + BOOST_CHECK_THROW(addmultisig(createArgs(0), false), runtime_error); + BOOST_CHECK_THROW(addmultisig(createArgs(1), false), runtime_error); + BOOST_CHECK_THROW(addmultisig(createArgs(2, address1Hex), false), runtime_error); + + BOOST_CHECK_THROW(addmultisig(createArgs(1, ""), false), runtime_error); + BOOST_CHECK_THROW(addmultisig(createArgs(1, "NotAValidPubkey"), false), runtime_error); + + string short1(address1Hex, address1Hex+sizeof(address1Hex)-2); // last byte missing + BOOST_CHECK_THROW(addmultisig(createArgs(2, short1.c_str()), false), runtime_error); + + string short2(address1Hex+1, address1Hex+sizeof(address1Hex)); // first byte missing + BOOST_CHECK_THROW(addmultisig(createArgs(2, short2.c_str()), false), runtime_error); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/script_P2SH_tests.cpp b/src/test/script_P2SH_tests.cpp new file mode 100644 index 0000000..eabfcd0 --- /dev/null +++ b/src/test/script_P2SH_tests.cpp @@ -0,0 +1,330 @@ +#include +#include +#include +#include +#include +#include + +#include "../main.h" +#include "../script.h" +#include "../wallet.h" + +using namespace std; + +// Test routines internal to script.cpp: +extern uint256 SignatureHash(CScript scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType); +extern bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn, + bool fValidatePayToScriptHash, int nHashType); + +// Helpers: +static std::vector +Serialize(const CScript& s) +{ + std::vector sSerialized(s); + return sSerialized; +} + +static bool +Verify(const CScript& scriptSig, const CScript& scriptPubKey, bool fStrict) +{ + // Create dummy to/from transactions: + CTransaction txFrom; + txFrom.vout.resize(1); + txFrom.vout[0].scriptPubKey = scriptPubKey; + + CTransaction txTo; + txTo.vin.resize(1); + txTo.vout.resize(1); + txTo.vin[0].prevout.n = 0; + txTo.vin[0].prevout.hash = txFrom.GetHash(); + txTo.vin[0].scriptSig = scriptSig; + txTo.vout[0].nValue = 1; + + return VerifyScript(scriptSig, scriptPubKey, txTo, 0, fStrict, 0); +} + + +BOOST_AUTO_TEST_SUITE(script_P2SH_tests) + +BOOST_AUTO_TEST_CASE(sign) +{ + // Pay-to-script-hash looks like this: + // scriptSig: + // scriptPubKey: HASH160 EQUAL + + // Test SignSignature() (and therefore the version of Solver() that signs transactions) + CBasicKeyStore keystore; + CKey key[4]; + for (int i = 0; i < 4; i++) + { + key[i].MakeNewKey(true); + keystore.AddKey(key[i]); + } + + // 8 Scripts: checking all combinations of + // different keys, straight/P2SH, pubkey/pubkeyhash + CScript standardScripts[4]; + standardScripts[0] << key[0].GetPubKey() << OP_CHECKSIG; + standardScripts[1].SetDestination(key[1].GetPubKey().GetID()); + standardScripts[2] << key[1].GetPubKey() << OP_CHECKSIG; + standardScripts[3].SetDestination(key[2].GetPubKey().GetID()); + CScript evalScripts[4]; + for (int i = 0; i < 4; i++) + { + keystore.AddCScript(standardScripts[i]); + evalScripts[i].SetDestination(standardScripts[i].GetID()); + } + + CTransaction txFrom; // Funding transaction: + txFrom.vout.resize(8); + for (int i = 0; i < 4; i++) + { + txFrom.vout[i].scriptPubKey = evalScripts[i]; + txFrom.vout[i+4].scriptPubKey = standardScripts[i]; + } + BOOST_CHECK(txFrom.IsStandard()); + + CTransaction txTo[8]; // Spending transactions + for (int i = 0; i < 8; i++) + { + txTo[i].vin.resize(1); + txTo[i].vout.resize(1); + txTo[i].vin[0].prevout.n = i; + txTo[i].vin[0].prevout.hash = txFrom.GetHash(); + txTo[i].vout[0].nValue = 1; + BOOST_CHECK_MESSAGE(IsMine(keystore, txFrom.vout[i].scriptPubKey), strprintf("IsMine %d", i)); + } + for (int i = 0; i < 8; i++) + { + BOOST_CHECK_MESSAGE(SignSignature(keystore, txFrom, txTo[i], 0), strprintf("SignSignature %d", i)); + } + // All of the above should be OK, and the txTos have valid signatures + // Check to make sure signature verification fails if we use the wrong ScriptSig: + for (int i = 0; i < 8; i++) + for (int j = 0; j < 8; j++) + { + CScript sigSave = txTo[i].vin[0].scriptSig; + txTo[i].vin[0].scriptSig = txTo[j].vin[0].scriptSig; + bool sigOK = VerifySignature(txFrom, txTo[i], 0, true, 0); + if (i == j) + BOOST_CHECK_MESSAGE(sigOK, strprintf("VerifySignature %d %d", i, j)); + else + BOOST_CHECK_MESSAGE(!sigOK, strprintf("VerifySignature %d %d", i, j)); + txTo[i].vin[0].scriptSig = sigSave; + } +} + +BOOST_AUTO_TEST_CASE(norecurse) +{ + // Make sure only the outer pay-to-script-hash does the + // extra-validation thing: + CScript invalidAsScript; + invalidAsScript << OP_INVALIDOPCODE << OP_INVALIDOPCODE; + + CScript p2sh; + p2sh.SetDestination(invalidAsScript.GetID()); + + CScript scriptSig; + scriptSig << Serialize(invalidAsScript); + + // Should not verify, because it will try to execute OP_INVALIDOPCODE + BOOST_CHECK(!Verify(scriptSig, p2sh, true)); + + // Try to recur, and verification should succeed because + // the inner HASH160 <> EQUAL should only check the hash: + CScript p2sh2; + p2sh2.SetDestination(p2sh.GetID()); + CScript scriptSig2; + scriptSig2 << Serialize(invalidAsScript) << Serialize(p2sh); + + BOOST_CHECK(Verify(scriptSig2, p2sh2, true)); +} + +BOOST_AUTO_TEST_CASE(set) +{ + // Test the CScript::Set* methods + CBasicKeyStore keystore; + CKey key[4]; + std::vector keys; + for (int i = 0; i < 4; i++) + { + key[i].MakeNewKey(true); + keystore.AddKey(key[i]); + keys.push_back(key[i]); + } + + CScript inner[4]; + inner[0].SetDestination(key[0].GetPubKey().GetID()); + inner[1].SetMultisig(2, std::vector(keys.begin(), keys.begin()+2)); + inner[2].SetMultisig(1, std::vector(keys.begin(), keys.begin()+2)); + inner[3].SetMultisig(2, std::vector(keys.begin(), keys.begin()+3)); + + CScript outer[4]; + for (int i = 0; i < 4; i++) + { + outer[i].SetDestination(inner[i].GetID()); + keystore.AddCScript(inner[i]); + } + + CTransaction txFrom; // Funding transaction: + txFrom.vout.resize(4); + for (int i = 0; i < 4; i++) + { + txFrom.vout[i].scriptPubKey = outer[i]; + } + BOOST_CHECK(txFrom.IsStandard()); + + CTransaction txTo[4]; // Spending transactions + for (int i = 0; i < 4; i++) + { + txTo[i].vin.resize(1); + txTo[i].vout.resize(1); + txTo[i].vin[0].prevout.n = i; + txTo[i].vin[0].prevout.hash = txFrom.GetHash(); + txTo[i].vout[0].nValue = 1; + txTo[i].vout[0].scriptPubKey = inner[i]; + BOOST_CHECK_MESSAGE(IsMine(keystore, txFrom.vout[i].scriptPubKey), strprintf("IsMine %d", i)); + } + for (int i = 0; i < 4; i++) + { + BOOST_CHECK_MESSAGE(SignSignature(keystore, txFrom, txTo[i], 0), strprintf("SignSignature %d", i)); + BOOST_CHECK_MESSAGE(txTo[i].IsStandard(), strprintf("txTo[%d].IsStandard", i)); + } +} + +BOOST_AUTO_TEST_CASE(is) +{ + // Test CScript::IsPayToScriptHash() + uint160 dummy; + CScript p2sh; + p2sh << OP_HASH160 << dummy << OP_EQUAL; + BOOST_CHECK(p2sh.IsPayToScriptHash()); + + // Not considered pay-to-script-hash if using one of the OP_PUSHDATA opcodes: + static const unsigned char direct[] = { OP_HASH160, 20, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, OP_EQUAL }; + BOOST_CHECK(CScript(direct, direct+sizeof(direct)).IsPayToScriptHash()); + static const unsigned char pushdata1[] = { OP_HASH160, OP_PUSHDATA1, 20, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, OP_EQUAL }; + BOOST_CHECK(!CScript(pushdata1, pushdata1+sizeof(pushdata1)).IsPayToScriptHash()); + static const unsigned char pushdata2[] = { OP_HASH160, OP_PUSHDATA2, 20,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, OP_EQUAL }; + BOOST_CHECK(!CScript(pushdata2, pushdata2+sizeof(pushdata2)).IsPayToScriptHash()); + static const unsigned char pushdata4[] = { OP_HASH160, OP_PUSHDATA4, 20,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, OP_EQUAL }; + BOOST_CHECK(!CScript(pushdata4, pushdata4+sizeof(pushdata4)).IsPayToScriptHash()); + + CScript not_p2sh; + BOOST_CHECK(!not_p2sh.IsPayToScriptHash()); + + not_p2sh.clear(); not_p2sh << OP_HASH160 << dummy << dummy << OP_EQUAL; + BOOST_CHECK(!not_p2sh.IsPayToScriptHash()); + + not_p2sh.clear(); not_p2sh << OP_NOP << dummy << OP_EQUAL; + BOOST_CHECK(!not_p2sh.IsPayToScriptHash()); + + not_p2sh.clear(); not_p2sh << OP_HASH160 << dummy << OP_CHECKSIG; + BOOST_CHECK(!not_p2sh.IsPayToScriptHash()); +} + +BOOST_AUTO_TEST_CASE(switchover) +{ + // Test switch over code + CScript notValid; + notValid << OP_11 << OP_12 << OP_EQUALVERIFY; + CScript scriptSig; + scriptSig << Serialize(notValid); + + CScript fund; + fund.SetDestination(notValid.GetID()); + + + // Validation should succeed under old rules (hash is correct): + BOOST_CHECK(Verify(scriptSig, fund, false)); + // Fail under new: + BOOST_CHECK(!Verify(scriptSig, fund, true)); +} + +BOOST_AUTO_TEST_CASE(AreInputsStandard) +{ + std::map > mapInputs; + CBasicKeyStore keystore; + CKey key[3]; + vector keys; + for (int i = 0; i < 3; i++) + { + key[i].MakeNewKey(true); + keystore.AddKey(key[i]); + keys.push_back(key[i]); + } + + CTransaction txFrom; + txFrom.vout.resize(6); + + // First three are standard: + CScript pay1; pay1.SetDestination(key[0].GetPubKey().GetID()); + keystore.AddCScript(pay1); + CScript payScriptHash1; payScriptHash1.SetDestination(pay1.GetID()); + CScript pay1of3; pay1of3.SetMultisig(1, keys); + + txFrom.vout[0].scriptPubKey = payScriptHash1; + txFrom.vout[1].scriptPubKey = pay1; + txFrom.vout[2].scriptPubKey = pay1of3; + + // Last three non-standard: + CScript empty; + keystore.AddCScript(empty); + txFrom.vout[3].scriptPubKey = empty; + // Can't use SetPayToScriptHash, it checks for the empty Script. So: + txFrom.vout[4].scriptPubKey << OP_HASH160 << Hash160(empty) << OP_EQUAL; + CScript oneOfEleven; + oneOfEleven << OP_1; + for (int i = 0; i < 11; i++) + oneOfEleven << key[0].GetPubKey(); + oneOfEleven << OP_11 << OP_CHECKMULTISIG; + txFrom.vout[5].scriptPubKey.SetDestination(oneOfEleven.GetID()); + + mapInputs[txFrom.GetHash()] = make_pair(CTxIndex(), txFrom); + + CTransaction txTo; + txTo.vout.resize(1); + txTo.vout[0].scriptPubKey.SetDestination(key[1].GetPubKey().GetID()); + + txTo.vin.resize(3); + txTo.vin[0].prevout.n = 0; + txTo.vin[0].prevout.hash = txFrom.GetHash(); + BOOST_CHECK(SignSignature(keystore, txFrom, txTo, 0)); + txTo.vin[1].prevout.n = 1; + txTo.vin[1].prevout.hash = txFrom.GetHash(); + BOOST_CHECK(SignSignature(keystore, txFrom, txTo, 1)); + txTo.vin[2].prevout.n = 2; + txTo.vin[2].prevout.hash = txFrom.GetHash(); + BOOST_CHECK(SignSignature(keystore, txFrom, txTo, 2)); + + BOOST_CHECK(txTo.AreInputsStandard(mapInputs)); + BOOST_CHECK_EQUAL(txTo.GetP2SHSigOpCount(mapInputs), 1); + + // Make sure adding crap to the scriptSigs makes them non-standard: + for (int i = 0; i < 3; i++) + { + CScript t = txTo.vin[i].scriptSig; + txTo.vin[i].scriptSig = (CScript() << 11) + t; + BOOST_CHECK(!txTo.AreInputsStandard(mapInputs)); + txTo.vin[i].scriptSig = t; + } + + CTransaction txToNonStd; + txToNonStd.vout.resize(1); + txToNonStd.vout[0].scriptPubKey.SetDestination(key[1].GetPubKey().GetID()); + txToNonStd.vin.resize(2); + txToNonStd.vin[0].prevout.n = 4; + txToNonStd.vin[0].prevout.hash = txFrom.GetHash(); + txToNonStd.vin[0].scriptSig << Serialize(empty); + txToNonStd.vin[1].prevout.n = 5; + txToNonStd.vin[1].prevout.hash = txFrom.GetHash(); + txToNonStd.vin[1].scriptSig << OP_0 << Serialize(oneOfEleven); + + BOOST_CHECK(!txToNonStd.AreInputsStandard(mapInputs)); + BOOST_CHECK_EQUAL(txToNonStd.GetP2SHSigOpCount(mapInputs), 11); + + txToNonStd.vin[0].scriptSig.clear(); + BOOST_CHECK(!txToNonStd.AreInputsStandard(mapInputs)); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp new file mode 100644 index 0000000..61d9a64 --- /dev/null +++ b/src/test/script_tests.cpp @@ -0,0 +1,445 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "json/json_spirit_reader_template.h" +#include "json/json_spirit_writer_template.h" +#include "json/json_spirit_utils.h" + +#include "main.h" +#include "wallet.h" + +using namespace std; +using namespace json_spirit; +using namespace boost::algorithm; + +extern uint256 SignatureHash(CScript scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType); +extern bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn, + bool fValidatePayToScriptHash, int nHashType); + +CScript +ParseScript(string s) +{ + CScript result; + + static map mapOpNames; + + if (mapOpNames.size() == 0) + { + for (int op = OP_NOP; op <= OP_NOP10; op++) + { + const char* name = GetOpName((opcodetype)op); + if (strcmp(name, "OP_UNKNOWN") == 0) + continue; + string strName(name); + mapOpNames[strName] = (opcodetype)op; + // Convenience: OP_ADD and just ADD are both recognized: + replace_first(strName, "OP_", ""); + mapOpNames[strName] = (opcodetype)op; + } + } + + vector words; + split(words, s, is_any_of(" \t\n"), token_compress_on); + + BOOST_FOREACH(string w, words) + { + if (all(w, is_digit()) || + (starts_with(w, "-") && all(string(w.begin()+1, w.end()), is_digit()))) + { + // Number + int64 n = atoi64(w); + result << n; + } + else if (starts_with(w, "0x") && IsHex(string(w.begin()+2, w.end()))) + { + // Raw hex data, inserted NOT pushed onto stack: + std::vector raw = ParseHex(string(w.begin()+2, w.end())); + result.insert(result.end(), raw.begin(), raw.end()); + } + else if (w.size() >= 2 && starts_with(w, "'") && ends_with(w, "'")) + { + // Single-quoted string, pushed as data. NOTE: this is poor-man's + // parsing, spaces/tabs/newlines in single-quoted strings won't work. + std::vector value(w.begin()+1, w.end()-1); + result << value; + } + else if (mapOpNames.count(w)) + { + // opcode, e.g. OP_ADD or OP_1: + result << mapOpNames[w]; + } + else + { + BOOST_ERROR("Parse error: " << s); + return CScript(); + } + } + + return result; +} + +Array +read_json(const std::string& filename) +{ + namespace fs = boost::filesystem; + fs::path testFile = fs::current_path() / "test" / "data" / filename; + +#ifdef TEST_DATA_DIR + if (!fs::exists(testFile)) + { + testFile = fs::path(BOOST_PP_STRINGIZE(TEST_DATA_DIR)) / filename; + } +#endif + + ifstream ifs(testFile.string().c_str(), ifstream::in); + Value v; + if (!read_stream(ifs, v)) + { + if (ifs.fail()) + BOOST_ERROR("Cound not find/open " << filename); + else + BOOST_ERROR("JSON syntax error in " << filename); + return Array(); + } + if (v.type() != array_type) + { + BOOST_ERROR(filename << " does not contain a json array"); + return Array(); + } + + return v.get_array(); +} + +BOOST_AUTO_TEST_SUITE(script_tests) + +BOOST_AUTO_TEST_CASE(script_valid) +{ + // Read tests from test/data/script_valid.json + // Format is an array of arrays + // Inner arrays are [ "scriptSig", "scriptPubKey" ] + // ... where scriptSig and scriptPubKey are stringified + // scripts. + Array tests = read_json("script_valid.json"); + + BOOST_FOREACH(Value& tv, tests) + { + Array test = tv.get_array(); + string strTest = write_string(tv, false); + if (test.size() < 2) // Allow size > 2; extra stuff ignored (useful for comments) + { + BOOST_ERROR("Bad test: " << strTest); + continue; + } + string scriptSigString = test[0].get_str(); + CScript scriptSig = ParseScript(scriptSigString); + string scriptPubKeyString = test[1].get_str(); + CScript scriptPubKey = ParseScript(scriptPubKeyString); + + CTransaction tx; + BOOST_CHECK_MESSAGE(VerifyScript(scriptSig, scriptPubKey, tx, 0, true, SIGHASH_NONE), strTest); + } +} + +BOOST_AUTO_TEST_CASE(script_invalid) +{ + // Scripts that should evaluate as invalid + Array tests = read_json("script_invalid.json"); + + BOOST_FOREACH(Value& tv, tests) + { + Array test = tv.get_array(); + string strTest = write_string(tv, false); + if (test.size() < 2) // Allow size > 2; extra stuff ignored (useful for comments) + { + BOOST_ERROR("Bad test: " << strTest); + continue; + } + string scriptSigString = test[0].get_str(); + CScript scriptSig = ParseScript(scriptSigString); + string scriptPubKeyString = test[1].get_str(); + CScript scriptPubKey = ParseScript(scriptPubKeyString); + + CTransaction tx; + BOOST_CHECK_MESSAGE(!VerifyScript(scriptSig, scriptPubKey, tx, 0, true, SIGHASH_NONE), strTest); + } +} + +BOOST_AUTO_TEST_CASE(script_PushData) +{ + // Check that PUSHDATA1, PUSHDATA2, and PUSHDATA4 create the same value on + // the stack as the 1-75 opcodes do. + static const unsigned char direct[] = { 1, 0x5a }; + static const unsigned char pushdata1[] = { OP_PUSHDATA1, 1, 0x5a }; + static const unsigned char pushdata2[] = { OP_PUSHDATA2, 1, 0, 0x5a }; + static const unsigned char pushdata4[] = { OP_PUSHDATA4, 1, 0, 0, 0, 0x5a }; + + vector > directStack; + BOOST_CHECK(EvalScript(directStack, CScript(&direct[0], &direct[sizeof(direct)]), CTransaction(), 0, 0)); + + vector > pushdata1Stack; + BOOST_CHECK(EvalScript(pushdata1Stack, CScript(&pushdata1[0], &pushdata1[sizeof(pushdata1)]), CTransaction(), 0, 0)); + BOOST_CHECK(pushdata1Stack == directStack); + + vector > pushdata2Stack; + BOOST_CHECK(EvalScript(pushdata2Stack, CScript(&pushdata2[0], &pushdata2[sizeof(pushdata2)]), CTransaction(), 0, 0)); + BOOST_CHECK(pushdata2Stack == directStack); + + vector > pushdata4Stack; + BOOST_CHECK(EvalScript(pushdata4Stack, CScript(&pushdata4[0], &pushdata4[sizeof(pushdata4)]), CTransaction(), 0, 0)); + BOOST_CHECK(pushdata4Stack == directStack); +} + +CScript +sign_multisig(CScript scriptPubKey, std::vector keys, CTransaction transaction) +{ + uint256 hash = SignatureHash(scriptPubKey, transaction, 0, SIGHASH_ALL); + + CScript result; + // + // NOTE: CHECKMULTISIG has an unfortunate bug; it requires + // one extra item on the stack, before the signatures. + // Putting OP_0 on the stack is the workaround; + // fixing the bug would mean splitting the blockchain (old + // clients would not accept new CHECKMULTISIG transactions, + // and vice-versa) + // + result << OP_0; + BOOST_FOREACH(CKey key, keys) + { + vector vchSig; + BOOST_CHECK(key.Sign(hash, vchSig)); + vchSig.push_back((unsigned char)SIGHASH_ALL); + result << vchSig; + } + return result; +} +CScript +sign_multisig(CScript scriptPubKey, CKey key, CTransaction transaction) +{ + std::vector keys; + keys.push_back(key); + return sign_multisig(scriptPubKey, keys, transaction); +} + +BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG12) +{ + CKey key1, key2, key3; + key1.MakeNewKey(true); + key2.MakeNewKey(false); + key3.MakeNewKey(true); + + CScript scriptPubKey12; + scriptPubKey12 << OP_1 << key1.GetPubKey() << key2.GetPubKey() << OP_2 << OP_CHECKMULTISIG; + + CTransaction txFrom12; + txFrom12.vout.resize(1); + txFrom12.vout[0].scriptPubKey = scriptPubKey12; + + CTransaction txTo12; + txTo12.vin.resize(1); + txTo12.vout.resize(1); + txTo12.vin[0].prevout.n = 0; + txTo12.vin[0].prevout.hash = txFrom12.GetHash(); + txTo12.vout[0].nValue = 1; + + CScript goodsig1 = sign_multisig(scriptPubKey12, key1, txTo12); + BOOST_CHECK(VerifyScript(goodsig1, scriptPubKey12, txTo12, 0, true, 0)); + txTo12.vout[0].nValue = 2; + BOOST_CHECK(!VerifyScript(goodsig1, scriptPubKey12, txTo12, 0, true, 0)); + + CScript goodsig2 = sign_multisig(scriptPubKey12, key2, txTo12); + BOOST_CHECK(VerifyScript(goodsig2, scriptPubKey12, txTo12, 0, true, 0)); + + CScript badsig1 = sign_multisig(scriptPubKey12, key3, txTo12); + BOOST_CHECK(!VerifyScript(badsig1, scriptPubKey12, txTo12, 0, true, 0)); +} + +BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG23) +{ + CKey key1, key2, key3, key4; + key1.MakeNewKey(true); + key2.MakeNewKey(false); + key3.MakeNewKey(true); + key4.MakeNewKey(false); + + CScript scriptPubKey23; + scriptPubKey23 << OP_2 << key1.GetPubKey() << key2.GetPubKey() << key3.GetPubKey() << OP_3 << OP_CHECKMULTISIG; + + CTransaction txFrom23; + txFrom23.vout.resize(1); + txFrom23.vout[0].scriptPubKey = scriptPubKey23; + + CTransaction txTo23; + txTo23.vin.resize(1); + txTo23.vout.resize(1); + txTo23.vin[0].prevout.n = 0; + txTo23.vin[0].prevout.hash = txFrom23.GetHash(); + txTo23.vout[0].nValue = 1; + + std::vector keys; + keys.push_back(key1); keys.push_back(key2); + CScript goodsig1 = sign_multisig(scriptPubKey23, keys, txTo23); + BOOST_CHECK(VerifyScript(goodsig1, scriptPubKey23, txTo23, 0, true, 0)); + + keys.clear(); + keys.push_back(key1); keys.push_back(key3); + CScript goodsig2 = sign_multisig(scriptPubKey23, keys, txTo23); + BOOST_CHECK(VerifyScript(goodsig2, scriptPubKey23, txTo23, 0, true, 0)); + + keys.clear(); + keys.push_back(key2); keys.push_back(key3); + CScript goodsig3 = sign_multisig(scriptPubKey23, keys, txTo23); + BOOST_CHECK(VerifyScript(goodsig3, scriptPubKey23, txTo23, 0, true, 0)); + + keys.clear(); + keys.push_back(key2); keys.push_back(key2); // Can't re-use sig + CScript badsig1 = sign_multisig(scriptPubKey23, keys, txTo23); + BOOST_CHECK(!VerifyScript(badsig1, scriptPubKey23, txTo23, 0, true, 0)); + + keys.clear(); + keys.push_back(key2); keys.push_back(key1); // sigs must be in correct order + CScript badsig2 = sign_multisig(scriptPubKey23, keys, txTo23); + BOOST_CHECK(!VerifyScript(badsig2, scriptPubKey23, txTo23, 0, true, 0)); + + keys.clear(); + keys.push_back(key3); keys.push_back(key2); // sigs must be in correct order + CScript badsig3 = sign_multisig(scriptPubKey23, keys, txTo23); + BOOST_CHECK(!VerifyScript(badsig3, scriptPubKey23, txTo23, 0, true, 0)); + + keys.clear(); + keys.push_back(key4); keys.push_back(key2); // sigs must match pubkeys + CScript badsig4 = sign_multisig(scriptPubKey23, keys, txTo23); + BOOST_CHECK(!VerifyScript(badsig4, scriptPubKey23, txTo23, 0, true, 0)); + + keys.clear(); + keys.push_back(key1); keys.push_back(key4); // sigs must match pubkeys + CScript badsig5 = sign_multisig(scriptPubKey23, keys, txTo23); + BOOST_CHECK(!VerifyScript(badsig5, scriptPubKey23, txTo23, 0, true, 0)); + + keys.clear(); // Must have signatures + CScript badsig6 = sign_multisig(scriptPubKey23, keys, txTo23); + BOOST_CHECK(!VerifyScript(badsig6, scriptPubKey23, txTo23, 0, true, 0)); +} + +BOOST_AUTO_TEST_CASE(script_combineSigs) +{ + // Test the CombineSignatures function + CBasicKeyStore keystore; + vector keys; + for (int i = 0; i < 3; i++) + { + CKey key; + key.MakeNewKey(i%2 == 1); + keys.push_back(key); + keystore.AddKey(key); + } + + CTransaction txFrom; + txFrom.vout.resize(1); + txFrom.vout[0].scriptPubKey.SetDestination(keys[0].GetPubKey().GetID()); + CScript& scriptPubKey = txFrom.vout[0].scriptPubKey; + CTransaction txTo; + txTo.vin.resize(1); + txTo.vout.resize(1); + txTo.vin[0].prevout.n = 0; + txTo.vin[0].prevout.hash = txFrom.GetHash(); + CScript& scriptSig = txTo.vin[0].scriptSig; + txTo.vout[0].nValue = 1; + + CScript empty; + CScript combined = CombineSignatures(scriptPubKey, txTo, 0, empty, empty); + BOOST_CHECK(combined.empty()); + + // Single signature case: + SignSignature(keystore, txFrom, txTo, 0); // changes scriptSig + combined = CombineSignatures(scriptPubKey, txTo, 0, scriptSig, empty); + BOOST_CHECK(combined == scriptSig); + combined = CombineSignatures(scriptPubKey, txTo, 0, empty, scriptSig); + BOOST_CHECK(combined == scriptSig); + CScript scriptSigCopy = scriptSig; + // Signing again will give a different, valid signature: + SignSignature(keystore, txFrom, txTo, 0); + combined = CombineSignatures(scriptPubKey, txTo, 0, scriptSigCopy, scriptSig); + BOOST_CHECK(combined == scriptSigCopy || combined == scriptSig); + + // P2SH, single-signature case: + CScript pkSingle; pkSingle << keys[0].GetPubKey() << OP_CHECKSIG; + keystore.AddCScript(pkSingle); + scriptPubKey.SetDestination(pkSingle.GetID()); + SignSignature(keystore, txFrom, txTo, 0); + combined = CombineSignatures(scriptPubKey, txTo, 0, scriptSig, empty); + BOOST_CHECK(combined == scriptSig); + combined = CombineSignatures(scriptPubKey, txTo, 0, empty, scriptSig); + BOOST_CHECK(combined == scriptSig); + scriptSigCopy = scriptSig; + SignSignature(keystore, txFrom, txTo, 0); + combined = CombineSignatures(scriptPubKey, txTo, 0, scriptSigCopy, scriptSig); + BOOST_CHECK(combined == scriptSigCopy || combined == scriptSig); + // dummy scriptSigCopy with placeholder, should always choose non-placeholder: + scriptSigCopy = CScript() << OP_0 << static_cast >(pkSingle); + combined = CombineSignatures(scriptPubKey, txTo, 0, scriptSigCopy, scriptSig); + BOOST_CHECK(combined == scriptSig); + combined = CombineSignatures(scriptPubKey, txTo, 0, scriptSig, scriptSigCopy); + BOOST_CHECK(combined == scriptSig); + + // Hardest case: Multisig 2-of-3 + scriptPubKey.SetMultisig(2, keys); + keystore.AddCScript(scriptPubKey); + SignSignature(keystore, txFrom, txTo, 0); + combined = CombineSignatures(scriptPubKey, txTo, 0, scriptSig, empty); + BOOST_CHECK(combined == scriptSig); + combined = CombineSignatures(scriptPubKey, txTo, 0, empty, scriptSig); + BOOST_CHECK(combined == scriptSig); + + // A couple of partially-signed versions: + vector sig1; + uint256 hash1 = SignatureHash(scriptPubKey, txTo, 0, SIGHASH_ALL); + BOOST_CHECK(keys[0].Sign(hash1, sig1)); + sig1.push_back(SIGHASH_ALL); + vector sig2; + uint256 hash2 = SignatureHash(scriptPubKey, txTo, 0, SIGHASH_NONE); + BOOST_CHECK(keys[1].Sign(hash2, sig2)); + sig2.push_back(SIGHASH_NONE); + vector sig3; + uint256 hash3 = SignatureHash(scriptPubKey, txTo, 0, SIGHASH_SINGLE); + BOOST_CHECK(keys[2].Sign(hash3, sig3)); + sig3.push_back(SIGHASH_SINGLE); + + // Not fussy about order (or even existence) of placeholders or signatures: + CScript partial1a = CScript() << OP_0 << sig1 << OP_0; + CScript partial1b = CScript() << OP_0 << OP_0 << sig1; + CScript partial2a = CScript() << OP_0 << sig2; + CScript partial2b = CScript() << sig2 << OP_0; + CScript partial3a = CScript() << sig3; + CScript partial3b = CScript() << OP_0 << OP_0 << sig3; + CScript partial3c = CScript() << OP_0 << sig3 << OP_0; + CScript complete12 = CScript() << OP_0 << sig1 << sig2; + CScript complete13 = CScript() << OP_0 << sig1 << sig3; + CScript complete23 = CScript() << OP_0 << sig2 << sig3; + + combined = CombineSignatures(scriptPubKey, txTo, 0, partial1a, partial1b); + BOOST_CHECK(combined == partial1a); + combined = CombineSignatures(scriptPubKey, txTo, 0, partial1a, partial2a); + BOOST_CHECK(combined == complete12); + combined = CombineSignatures(scriptPubKey, txTo, 0, partial2a, partial1a); + BOOST_CHECK(combined == complete12); + combined = CombineSignatures(scriptPubKey, txTo, 0, partial1b, partial2b); + BOOST_CHECK(combined == complete12); + combined = CombineSignatures(scriptPubKey, txTo, 0, partial3b, partial1b); + BOOST_CHECK(combined == complete13); + combined = CombineSignatures(scriptPubKey, txTo, 0, partial2a, partial3a); + BOOST_CHECK(combined == complete23); + combined = CombineSignatures(scriptPubKey, txTo, 0, partial3b, partial2b); + BOOST_CHECK(combined == complete23); + combined = CombineSignatures(scriptPubKey, txTo, 0, partial3b, partial3a); + BOOST_CHECK(combined == partial3c); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/sigopcount_tests.cpp b/src/test/sigopcount_tests.cpp new file mode 100644 index 0000000..59673f9 --- /dev/null +++ b/src/test/sigopcount_tests.cpp @@ -0,0 +1,60 @@ +#include +#include +#include + +#include "script.h" +#include "key.h" + +using namespace std; + +// Helpers: +static std::vector +Serialize(const CScript& s) +{ + std::vector sSerialized(s); + return sSerialized; +} + +BOOST_AUTO_TEST_SUITE(sigopcount_tests) + +BOOST_AUTO_TEST_CASE(GetSigOpCount) +{ + // Test CScript::GetSigOpCount() + CScript s1; + BOOST_CHECK_EQUAL(s1.GetSigOpCount(false), 0); + BOOST_CHECK_EQUAL(s1.GetSigOpCount(true), 0); + + uint160 dummy; + s1 << OP_1 << dummy << dummy << OP_2 << OP_CHECKMULTISIG; + BOOST_CHECK_EQUAL(s1.GetSigOpCount(true), 2); + s1 << OP_IF << OP_CHECKSIG << OP_ENDIF; + BOOST_CHECK_EQUAL(s1.GetSigOpCount(true), 3); + BOOST_CHECK_EQUAL(s1.GetSigOpCount(false), 21); + + CScript p2sh; + p2sh.SetDestination(s1.GetID()); + CScript scriptSig; + scriptSig << OP_0 << Serialize(s1); + BOOST_CHECK_EQUAL(p2sh.GetSigOpCount(scriptSig), 3); + + std::vector keys; + for (int i = 0; i < 3; i++) + { + CKey k; + k.MakeNewKey(true); + keys.push_back(k); + } + CScript s2; + s2.SetMultisig(1, keys); + BOOST_CHECK_EQUAL(s2.GetSigOpCount(true), 3); + BOOST_CHECK_EQUAL(s2.GetSigOpCount(false), 20); + + p2sh.SetDestination(s2.GetID()); + BOOST_CHECK_EQUAL(p2sh.GetSigOpCount(true), 0); + BOOST_CHECK_EQUAL(p2sh.GetSigOpCount(false), 0); + CScript scriptSig2; + scriptSig2 << OP_1 << dummy << dummy << Serialize(s2); + BOOST_CHECK_EQUAL(p2sh.GetSigOpCount(scriptSig2), 3); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp new file mode 100644 index 0000000..bcf0907 --- /dev/null +++ b/src/test/test_bitcoin.cpp @@ -0,0 +1,44 @@ +#define BOOST_TEST_MODULE Bitcoin Test Suite +#include + +#include "db.h" +#include "main.h" +#include "wallet.h" + +CWallet* pwalletMain; +CClientUIInterface uiInterface; + +extern bool fPrintToConsole; +extern void noui_connect(); + +struct TestingSetup { + TestingSetup() { + fPrintToDebugger = true; // don't want to write to debug.log file + noui_connect(); + bitdb.MakeMock(); + LoadBlockIndex(true); + bool fFirstRun; + pwalletMain = new CWallet("wallet.dat"); + pwalletMain->LoadWallet(fFirstRun); + RegisterWallet(pwalletMain); + } + ~TestingSetup() + { + delete pwalletMain; + pwalletMain = NULL; + bitdb.Flush(true); + } +}; + +BOOST_GLOBAL_FIXTURE(TestingSetup); + +void Shutdown(void* parg) +{ + exit(0); +} + +void StartShutdown() +{ + exit(0); +} + diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp new file mode 100644 index 0000000..c230458 --- /dev/null +++ b/src/test/transaction_tests.cpp @@ -0,0 +1,264 @@ +#include +#include +#include +#include "json/json_spirit_writer_template.h" + +#include "main.h" +#include "wallet.h" + +using namespace std; +using namespace json_spirit; + +// In script_tests.cpp +extern Array read_json(const std::string& filename); +extern CScript ParseScript(string s); + +BOOST_AUTO_TEST_SUITE(transaction_tests) + +BOOST_AUTO_TEST_CASE(tx_valid) +{ + // Read tests from test/data/tx_valid.json + // Format is an array of arrays + // Inner arrays are either [ "comment" ] + // or [[[prevout hash, prevout index, prevout scriptPubKey], [input 2], ...],"], serializedTransaction, enforceP2SH + // ... where all scripts are stringified scripts. + Array tests = read_json("tx_valid.json"); + + BOOST_FOREACH(Value& tv, tests) + { + Array test = tv.get_array(); + string strTest = write_string(tv, false); + if (test[0].type() == array_type) + { + if (test.size() != 3 || test[1].type() != str_type || test[2].type() != bool_type) + { + BOOST_ERROR("Bad test: " << strTest); + continue; + } + + map mapprevOutScriptPubKeys; + Array inputs = test[0].get_array(); + bool fValid = true; + BOOST_FOREACH(Value& input, inputs) + { + if (input.type() != array_type) + { + fValid = false; + break; + } + Array vinput = input.get_array(); + if (vinput.size() != 3) + { + fValid = false; + break; + } + + mapprevOutScriptPubKeys[COutPoint(uint256(vinput[0].get_str()), vinput[1].get_int())] = ParseScript(vinput[2].get_str()); + } + if (!fValid) + { + BOOST_ERROR("Bad test: " << strTest); + continue; + } + + string transaction = test[1].get_str(); + CDataStream stream(ParseHex(transaction), SER_NETWORK, PROTOCOL_VERSION); + CTransaction tx; + stream >> tx; + + BOOST_CHECK_MESSAGE(tx.CheckTransaction(), strTest); + + for (unsigned int i = 0; i < tx.vin.size(); i++) + { + if (!mapprevOutScriptPubKeys.count(tx.vin[i].prevout)) + { + BOOST_ERROR("Bad test: " << strTest); + break; + } + + BOOST_CHECK_MESSAGE(VerifyScript(tx.vin[i].scriptSig, mapprevOutScriptPubKeys[tx.vin[i].prevout], tx, i, test[2].get_bool(), 0), strTest); + } + } + } +} + +BOOST_AUTO_TEST_CASE(tx_invalid) +{ + // Read tests from test/data/tx_invalid.json + // Format is an array of arrays + // Inner arrays are either [ "comment" ] + // or [[[prevout hash, prevout index, prevout scriptPubKey], [input 2], ...],"], serializedTransaction, enforceP2SH + // ... where all scripts are stringified scripts. + Array tests = read_json("tx_invalid.json"); + + BOOST_FOREACH(Value& tv, tests) + { + Array test = tv.get_array(); + string strTest = write_string(tv, false); + if (test[0].type() == array_type) + { + if (test.size() != 3 || test[1].type() != str_type || test[2].type() != bool_type) + { + BOOST_ERROR("Bad test: " << strTest); + continue; + } + + map mapprevOutScriptPubKeys; + Array inputs = test[0].get_array(); + bool fValid = true; + BOOST_FOREACH(Value& input, inputs) + { + if (input.type() != array_type) + { + fValid = false; + break; + } + Array vinput = input.get_array(); + if (vinput.size() != 3) + { + fValid = false; + break; + } + + mapprevOutScriptPubKeys[COutPoint(uint256(vinput[0].get_str()), vinput[1].get_int())] = ParseScript(vinput[2].get_str()); + } + if (!fValid) + { + BOOST_ERROR("Bad test: " << strTest); + continue; + } + + string transaction = test[1].get_str(); + CDataStream stream(ParseHex(transaction), SER_NETWORK, PROTOCOL_VERSION); + CTransaction tx; + stream >> tx; + + fValid = tx.CheckTransaction(); + + for (unsigned int i = 0; i < tx.vin.size() && fValid; i++) + { + if (!mapprevOutScriptPubKeys.count(tx.vin[i].prevout)) + { + BOOST_ERROR("Bad test: " << strTest); + break; + } + + fValid = VerifyScript(tx.vin[i].scriptSig, mapprevOutScriptPubKeys[tx.vin[i].prevout], tx, i, test[2].get_bool(), 0); + } + + BOOST_CHECK_MESSAGE(!fValid, strTest); + } + } +} + +BOOST_AUTO_TEST_CASE(basic_transaction_tests) +{ + // Random real transaction (e2769b09e784f32f62ef849763d4f45b98e07ba658647343b915ff832b110436) + unsigned char ch[] = {0x01, 0x00, 0x00, 0x00, 0x01, 0x6b, 0xff, 0x7f, 0xcd, 0x4f, 0x85, 0x65, 0xef, 0x40, 0x6d, 0xd5, 0xd6, 0x3d, 0x4f, 0xf9, 0x4f, 0x31, 0x8f, 0xe8, 0x20, 0x27, 0xfd, 0x4d, 0xc4, 0x51, 0xb0, 0x44, 0x74, 0x01, 0x9f, 0x74, 0xb4, 0x00, 0x00, 0x00, 0x00, 0x8c, 0x49, 0x30, 0x46, 0x02, 0x21, 0x00, 0xda, 0x0d, 0xc6, 0xae, 0xce, 0xfe, 0x1e, 0x06, 0xef, 0xdf, 0x05, 0x77, 0x37, 0x57, 0xde, 0xb1, 0x68, 0x82, 0x09, 0x30, 0xe3, 0xb0, 0xd0, 0x3f, 0x46, 0xf5, 0xfc, 0xf1, 0x50, 0xbf, 0x99, 0x0c, 0x02, 0x21, 0x00, 0xd2, 0x5b, 0x5c, 0x87, 0x04, 0x00, 0x76, 0xe4, 0xf2, 0x53, 0xf8, 0x26, 0x2e, 0x76, 0x3e, 0x2d, 0xd5, 0x1e, 0x7f, 0xf0, 0xbe, 0x15, 0x77, 0x27, 0xc4, 0xbc, 0x42, 0x80, 0x7f, 0x17, 0xbd, 0x39, 0x01, 0x41, 0x04, 0xe6, 0xc2, 0x6e, 0xf6, 0x7d, 0xc6, 0x10, 0xd2, 0xcd, 0x19, 0x24, 0x84, 0x78, 0x9a, 0x6c, 0xf9, 0xae, 0xa9, 0x93, 0x0b, 0x94, 0x4b, 0x7e, 0x2d, 0xb5, 0x34, 0x2b, 0x9d, 0x9e, 0x5b, 0x9f, 0xf7, 0x9a, 0xff, 0x9a, 0x2e, 0xe1, 0x97, 0x8d, 0xd7, 0xfd, 0x01, 0xdf, 0xc5, 0x22, 0xee, 0x02, 0x28, 0x3d, 0x3b, 0x06, 0xa9, 0xd0, 0x3a, 0xcf, 0x80, 0x96, 0x96, 0x8d, 0x7d, 0xbb, 0x0f, 0x91, 0x78, 0xff, 0xff, 0xff, 0xff, 0x02, 0x8b, 0xa7, 0x94, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x19, 0x76, 0xa9, 0x14, 0xba, 0xde, 0xec, 0xfd, 0xef, 0x05, 0x07, 0x24, 0x7f, 0xc8, 0xf7, 0x42, 0x41, 0xd7, 0x3b, 0xc0, 0x39, 0x97, 0x2d, 0x7b, 0x88, 0xac, 0x40, 0x94, 0xa8, 0x02, 0x00, 0x00, 0x00, 0x00, 0x19, 0x76, 0xa9, 0x14, 0xc1, 0x09, 0x32, 0x48, 0x3f, 0xec, 0x93, 0xed, 0x51, 0xf5, 0xfe, 0x95, 0xe7, 0x25, 0x59, 0xf2, 0xcc, 0x70, 0x43, 0xf9, 0x88, 0xac, 0x00, 0x00, 0x00, 0x00, 0x00}; + vector vch(ch, ch + sizeof(ch) -1); + CDataStream stream(vch, SER_DISK, CLIENT_VERSION); + CTransaction tx; + stream >> tx; + BOOST_CHECK_MESSAGE(tx.CheckTransaction(), "Simple deserialized transaction should be valid."); + + // Check that duplicate txins fail + tx.vin.push_back(tx.vin[0]); + BOOST_CHECK_MESSAGE(!tx.CheckTransaction(), "Transaction with duplicate txins should be invalid."); +} + +// +// Helper: create two dummy transactions, each with +// two outputs. The first has 11 and 50 CENT outputs +// paid to a TX_PUBKEY, the second 21 and 22 CENT outputs +// paid to a TX_PUBKEYHASH. +// +static std::vector +SetupDummyInputs(CBasicKeyStore& keystoreRet, MapPrevTx& inputsRet) +{ + std::vector dummyTransactions; + dummyTransactions.resize(2); + + // Add some keys to the keystore: + CKey key[4]; + for (int i = 0; i < 4; i++) + { + key[i].MakeNewKey(i % 2); + keystoreRet.AddKey(key[i]); + } + + // Create some dummy input transactions + dummyTransactions[0].vout.resize(2); + dummyTransactions[0].vout[0].nValue = 11*CENT; + dummyTransactions[0].vout[0].scriptPubKey << key[0].GetPubKey() << OP_CHECKSIG; + dummyTransactions[0].vout[1].nValue = 50*CENT; + dummyTransactions[0].vout[1].scriptPubKey << key[1].GetPubKey() << OP_CHECKSIG; + inputsRet[dummyTransactions[0].GetHash()] = make_pair(CTxIndex(), dummyTransactions[0]); + + dummyTransactions[1].vout.resize(2); + dummyTransactions[1].vout[0].nValue = 21*CENT; + dummyTransactions[1].vout[0].scriptPubKey.SetDestination(key[2].GetPubKey().GetID()); + dummyTransactions[1].vout[1].nValue = 22*CENT; + dummyTransactions[1].vout[1].scriptPubKey.SetDestination(key[3].GetPubKey().GetID()); + inputsRet[dummyTransactions[1].GetHash()] = make_pair(CTxIndex(), dummyTransactions[1]); + + return dummyTransactions; +} + +BOOST_AUTO_TEST_CASE(test_Get) +{ + CBasicKeyStore keystore; + MapPrevTx dummyInputs; + std::vector dummyTransactions = SetupDummyInputs(keystore, dummyInputs); + + CTransaction t1; + t1.vin.resize(3); + t1.vin[0].prevout.hash = dummyTransactions[0].GetHash(); + t1.vin[0].prevout.n = 1; + t1.vin[0].scriptSig << std::vector(65, 0); + t1.vin[1].prevout.hash = dummyTransactions[1].GetHash(); + t1.vin[1].prevout.n = 0; + t1.vin[1].scriptSig << std::vector(65, 0) << std::vector(33, 4); + t1.vin[2].prevout.hash = dummyTransactions[1].GetHash(); + t1.vin[2].prevout.n = 1; + t1.vin[2].scriptSig << std::vector(65, 0) << std::vector(33, 4); + t1.vout.resize(2); + t1.vout[0].nValue = 90*CENT; + t1.vout[0].scriptPubKey << OP_1; + + BOOST_CHECK(t1.AreInputsStandard(dummyInputs)); + BOOST_CHECK_EQUAL(t1.GetValueIn(dummyInputs), (50+21+22)*CENT); + + // Adding extra junk to the scriptSig should make it non-standard: + t1.vin[0].scriptSig << OP_11; + BOOST_CHECK(!t1.AreInputsStandard(dummyInputs)); + + // ... as should not having enough: + t1.vin[0].scriptSig = CScript(); + BOOST_CHECK(!t1.AreInputsStandard(dummyInputs)); +} + +BOOST_AUTO_TEST_CASE(test_GetThrow) +{ + CBasicKeyStore keystore; + MapPrevTx dummyInputs; + std::vector dummyTransactions = SetupDummyInputs(keystore, dummyInputs); + + MapPrevTx missingInputs; + + CTransaction t1; + t1.vin.resize(3); + t1.vin[0].prevout.hash = dummyTransactions[0].GetHash(); + t1.vin[0].prevout.n = 0; + t1.vin[1].prevout.hash = dummyTransactions[1].GetHash();; + t1.vin[1].prevout.n = 0; + t1.vin[2].prevout.hash = dummyTransactions[1].GetHash();; + t1.vin[2].prevout.n = 1; + t1.vout.resize(2); + t1.vout[0].nValue = 90*CENT; + t1.vout[0].scriptPubKey << OP_1; + + BOOST_CHECK_THROW(t1.AreInputsStandard(missingInputs), runtime_error); + BOOST_CHECK_THROW(t1.GetValueIn(missingInputs), runtime_error); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/uint160_tests.cpp b/src/test/uint160_tests.cpp new file mode 100644 index 0000000..35cb35b --- /dev/null +++ b/src/test/uint160_tests.cpp @@ -0,0 +1,18 @@ +#include + +#include "uint256.h" + +BOOST_AUTO_TEST_SUITE(uint160_tests) + +BOOST_AUTO_TEST_CASE(uint160_equality) +{ + uint160 num1 = 10; + uint160 num2 = 11; + BOOST_CHECK(num1+1 == num2); + + uint64 num3 = 10; + BOOST_CHECK(num1 == num3); + BOOST_CHECK(num1+num2 == num3+num2); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/uint256_tests.cpp b/src/test/uint256_tests.cpp new file mode 100644 index 0000000..efdc8a6 --- /dev/null +++ b/src/test/uint256_tests.cpp @@ -0,0 +1,18 @@ +#include + +#include "uint256.h" + +BOOST_AUTO_TEST_SUITE(uint256_tests) + +BOOST_AUTO_TEST_CASE(uint256_equality) +{ + uint256 num1 = 10; + uint256 num2 = 11; + BOOST_CHECK(num1+1 == num2); + + uint64 num3 = 10; + BOOST_CHECK(num1 == num3); + BOOST_CHECK(num1+num2 == num3+num2); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp new file mode 100644 index 0000000..3a4c035 --- /dev/null +++ b/src/test/util_tests.cpp @@ -0,0 +1,264 @@ +#include +#include +#include + +#include "main.h" +#include "wallet.h" +#include "util.h" + +using namespace std; + +BOOST_AUTO_TEST_SUITE(util_tests) + +BOOST_AUTO_TEST_CASE(util_criticalsection) +{ + CCriticalSection cs; + + do { + LOCK(cs); + break; + + BOOST_ERROR("break was swallowed!"); + } while(0); + + do { + TRY_LOCK(cs, lockTest); + if (lockTest) + break; + + BOOST_ERROR("break was swallowed!"); + } while(0); +} + +BOOST_AUTO_TEST_CASE(util_MedianFilter) +{ + CMedianFilter filter(5, 15); + + BOOST_CHECK_EQUAL(filter.median(), 15); + + filter.input(20); // [15 20] + BOOST_CHECK_EQUAL(filter.median(), 17); + + filter.input(30); // [15 20 30] + BOOST_CHECK_EQUAL(filter.median(), 20); + + filter.input(3); // [3 15 20 30] + BOOST_CHECK_EQUAL(filter.median(), 17); + + filter.input(7); // [3 7 15 20 30] + BOOST_CHECK_EQUAL(filter.median(), 15); + + filter.input(18); // [3 7 18 20 30] + BOOST_CHECK_EQUAL(filter.median(), 18); + + filter.input(0); // [0 3 7 18 30] + BOOST_CHECK_EQUAL(filter.median(), 7); +} + +static const unsigned char ParseHex_expected[65] = { + 0x04, 0x67, 0x8a, 0xfd, 0xb0, 0xfe, 0x55, 0x48, 0x27, 0x19, 0x67, 0xf1, 0xa6, 0x71, 0x30, 0xb7, + 0x10, 0x5c, 0xd6, 0xa8, 0x28, 0xe0, 0x39, 0x09, 0xa6, 0x79, 0x62, 0xe0, 0xea, 0x1f, 0x61, 0xde, + 0xb6, 0x49, 0xf6, 0xbc, 0x3f, 0x4c, 0xef, 0x38, 0xc4, 0xf3, 0x55, 0x04, 0xe5, 0x1e, 0xc1, 0x12, + 0xde, 0x5c, 0x38, 0x4d, 0xf7, 0xba, 0x0b, 0x8d, 0x57, 0x8a, 0x4c, 0x70, 0x2b, 0x6b, 0xf1, 0x1d, + 0x5f +}; +BOOST_AUTO_TEST_CASE(util_ParseHex) +{ + std::vector result; + std::vector expected(ParseHex_expected, ParseHex_expected + sizeof(ParseHex_expected)); + // Basic test vector + result = ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f"); + BOOST_CHECK_EQUAL_COLLECTIONS(result.begin(), result.end(), expected.begin(), expected.end()); + + // Spaces between bytes must be supported + result = ParseHex("12 34 56 78"); + BOOST_CHECK(result.size() == 4 && result[0] == 0x12 && result[1] == 0x34 && result[2] == 0x56 && result[3] == 0x78); + + // Stop parsing at invalid value + result = ParseHex("1234 invalid 1234"); + BOOST_CHECK(result.size() == 2 && result[0] == 0x12 && result[1] == 0x34); +} + +BOOST_AUTO_TEST_CASE(util_HexStr) +{ + BOOST_CHECK_EQUAL( + HexStr(ParseHex_expected, ParseHex_expected + sizeof(ParseHex_expected)), + "04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f"); + + BOOST_CHECK_EQUAL( + HexStr(ParseHex_expected, ParseHex_expected + 5, true), + "04 67 8a fd b0"); + + BOOST_CHECK_EQUAL( + HexStr(ParseHex_expected, ParseHex_expected, true), + ""); + + std::vector ParseHex_vec(ParseHex_expected, ParseHex_expected + 5); + + BOOST_CHECK_EQUAL( + HexStr(ParseHex_vec, true), + "04 67 8a fd b0"); +} + + +BOOST_AUTO_TEST_CASE(util_DateTimeStrFormat) +{ +/*These are platform-dependant and thus removed to avoid useless test failures + BOOST_CHECK_EQUAL(DateTimeStrFormat("%x %H:%M:%S", 0), "01/01/70 00:00:00"); + BOOST_CHECK_EQUAL(DateTimeStrFormat("%x %H:%M:%S", 0x7FFFFFFF), "01/19/38 03:14:07"); + // Formats used within Bitcoin + BOOST_CHECK_EQUAL(DateTimeStrFormat("%x %H:%M:%S", 1317425777), "09/30/11 23:36:17"); + BOOST_CHECK_EQUAL(DateTimeStrFormat("%x %H:%M", 1317425777), "09/30/11 23:36"); +*/ +} + +BOOST_AUTO_TEST_CASE(util_ParseParameters) +{ + const char *argv_test[] = {"-ignored", "-a", "-b", "-ccc=argument", "-ccc=multiple", "f", "-d=e"}; + + ParseParameters(0, (char**)argv_test); + BOOST_CHECK(mapArgs.empty() && mapMultiArgs.empty()); + + ParseParameters(1, (char**)argv_test); + BOOST_CHECK(mapArgs.empty() && mapMultiArgs.empty()); + + ParseParameters(5, (char**)argv_test); + // expectation: -ignored is ignored (program name argument), + // -a, -b and -ccc end up in map, -d ignored because it is after + // a non-option argument (non-GNU option parsing) + BOOST_CHECK(mapArgs.size() == 3 && mapMultiArgs.size() == 3); + BOOST_CHECK(mapArgs.count("-a") && mapArgs.count("-b") && mapArgs.count("-ccc") + && !mapArgs.count("f") && !mapArgs.count("-d")); + BOOST_CHECK(mapMultiArgs.count("-a") && mapMultiArgs.count("-b") && mapMultiArgs.count("-ccc") + && !mapMultiArgs.count("f") && !mapMultiArgs.count("-d")); + + BOOST_CHECK(mapArgs["-a"] == "" && mapArgs["-ccc"] == "multiple"); + BOOST_CHECK(mapMultiArgs["-ccc"].size() == 2); +} + +BOOST_AUTO_TEST_CASE(util_GetArg) +{ + mapArgs.clear(); + mapArgs["strtest1"] = "string..."; + // strtest2 undefined on purpose + mapArgs["inttest1"] = "12345"; + mapArgs["inttest2"] = "81985529216486895"; + // inttest3 undefined on purpose + mapArgs["booltest1"] = ""; + // booltest2 undefined on purpose + mapArgs["booltest3"] = "0"; + mapArgs["booltest4"] = "1"; + + BOOST_CHECK_EQUAL(GetArg("strtest1", "default"), "string..."); + BOOST_CHECK_EQUAL(GetArg("strtest2", "default"), "default"); + BOOST_CHECK_EQUAL(GetArg("inttest1", -1), 12345); + BOOST_CHECK_EQUAL(GetArg("inttest2", -1), 81985529216486895LL); + BOOST_CHECK_EQUAL(GetArg("inttest3", -1), -1); + BOOST_CHECK_EQUAL(GetBoolArg("booltest1"), true); + BOOST_CHECK_EQUAL(GetBoolArg("booltest2"), false); + BOOST_CHECK_EQUAL(GetBoolArg("booltest3"), false); + BOOST_CHECK_EQUAL(GetBoolArg("booltest4"), true); +} + +BOOST_AUTO_TEST_CASE(util_WildcardMatch) +{ + BOOST_CHECK(WildcardMatch("127.0.0.1", "*")); + BOOST_CHECK(WildcardMatch("127.0.0.1", "127.*")); + BOOST_CHECK(WildcardMatch("abcdef", "a?cde?")); + BOOST_CHECK(!WildcardMatch("abcdef", "a?cde??")); + BOOST_CHECK(WildcardMatch("abcdef", "a*f")); + BOOST_CHECK(!WildcardMatch("abcdef", "a*x")); + BOOST_CHECK(WildcardMatch("", "*")); +} + +BOOST_AUTO_TEST_CASE(util_FormatMoney) +{ + BOOST_CHECK_EQUAL(FormatMoney(0, false), "0.00"); + BOOST_CHECK_EQUAL(FormatMoney((COIN/10000)*123456789, false), "12345.6789"); + BOOST_CHECK_EQUAL(FormatMoney(COIN, true), "+1.00"); + BOOST_CHECK_EQUAL(FormatMoney(-COIN, false), "-1.00"); + BOOST_CHECK_EQUAL(FormatMoney(-COIN, true), "-1.00"); + + BOOST_CHECK_EQUAL(FormatMoney(COIN*100000000, false), "100000000.00"); + BOOST_CHECK_EQUAL(FormatMoney(COIN*10000000, false), "10000000.00"); + BOOST_CHECK_EQUAL(FormatMoney(COIN*1000000, false), "1000000.00"); + BOOST_CHECK_EQUAL(FormatMoney(COIN*100000, false), "100000.00"); + BOOST_CHECK_EQUAL(FormatMoney(COIN*10000, false), "10000.00"); + BOOST_CHECK_EQUAL(FormatMoney(COIN*1000, false), "1000.00"); + BOOST_CHECK_EQUAL(FormatMoney(COIN*100, false), "100.00"); + BOOST_CHECK_EQUAL(FormatMoney(COIN*10, false), "10.00"); + BOOST_CHECK_EQUAL(FormatMoney(COIN, false), "1.00"); + BOOST_CHECK_EQUAL(FormatMoney(COIN/10, false), "0.10"); + BOOST_CHECK_EQUAL(FormatMoney(COIN/100, false), "0.01"); + BOOST_CHECK_EQUAL(FormatMoney(COIN/1000, false), "0.001"); + BOOST_CHECK_EQUAL(FormatMoney(COIN/10000, false), "0.0001"); + BOOST_CHECK_EQUAL(FormatMoney(COIN/100000, false), "0.00001"); + BOOST_CHECK_EQUAL(FormatMoney(COIN/1000000, false), "0.000001"); + BOOST_CHECK_EQUAL(FormatMoney(COIN/10000000, false), "0.0000001"); + BOOST_CHECK_EQUAL(FormatMoney(COIN/100000000, false), "0.00000001"); +} + +BOOST_AUTO_TEST_CASE(util_ParseMoney) +{ + int64 ret = 0; + BOOST_CHECK(ParseMoney("0.0", ret)); + BOOST_CHECK_EQUAL(ret, 0); + + BOOST_CHECK(ParseMoney("12345.6789", ret)); + BOOST_CHECK_EQUAL(ret, (COIN/10000)*123456789); + + BOOST_CHECK(ParseMoney("100000000.00", ret)); + BOOST_CHECK_EQUAL(ret, COIN*100000000); + BOOST_CHECK(ParseMoney("10000000.00", ret)); + BOOST_CHECK_EQUAL(ret, COIN*10000000); + BOOST_CHECK(ParseMoney("1000000.00", ret)); + BOOST_CHECK_EQUAL(ret, COIN*1000000); + BOOST_CHECK(ParseMoney("100000.00", ret)); + BOOST_CHECK_EQUAL(ret, COIN*100000); + BOOST_CHECK(ParseMoney("10000.00", ret)); + BOOST_CHECK_EQUAL(ret, COIN*10000); + BOOST_CHECK(ParseMoney("1000.00", ret)); + BOOST_CHECK_EQUAL(ret, COIN*1000); + BOOST_CHECK(ParseMoney("100.00", ret)); + BOOST_CHECK_EQUAL(ret, COIN*100); + BOOST_CHECK(ParseMoney("10.00", ret)); + BOOST_CHECK_EQUAL(ret, COIN*10); + BOOST_CHECK(ParseMoney("1.00", ret)); + BOOST_CHECK_EQUAL(ret, COIN); + BOOST_CHECK(ParseMoney("0.1", ret)); + BOOST_CHECK_EQUAL(ret, COIN/10); + BOOST_CHECK(ParseMoney("0.01", ret)); + BOOST_CHECK_EQUAL(ret, COIN/100); + BOOST_CHECK(ParseMoney("0.001", ret)); + BOOST_CHECK_EQUAL(ret, COIN/1000); + BOOST_CHECK(ParseMoney("0.0001", ret)); + BOOST_CHECK_EQUAL(ret, COIN/10000); + BOOST_CHECK(ParseMoney("0.00001", ret)); + BOOST_CHECK_EQUAL(ret, COIN/100000); + BOOST_CHECK(ParseMoney("0.000001", ret)); + BOOST_CHECK_EQUAL(ret, COIN/1000000); + BOOST_CHECK(ParseMoney("0.0000001", ret)); + BOOST_CHECK_EQUAL(ret, COIN/10000000); + BOOST_CHECK(ParseMoney("0.00000001", ret)); + BOOST_CHECK_EQUAL(ret, COIN/100000000); + + // Attempted 63 bit overflow should fail + BOOST_CHECK(!ParseMoney("92233720368.54775808", ret)); +} + +BOOST_AUTO_TEST_CASE(util_IsHex) +{ + BOOST_CHECK(IsHex("00")); + BOOST_CHECK(IsHex("00112233445566778899aabbccddeeffAABBCCDDEEFF")); + BOOST_CHECK(IsHex("ff")); + BOOST_CHECK(IsHex("FF")); + + BOOST_CHECK(!IsHex("")); + BOOST_CHECK(!IsHex("0")); + BOOST_CHECK(!IsHex("a")); + BOOST_CHECK(!IsHex("eleven")); + BOOST_CHECK(!IsHex("00xx00")); + BOOST_CHECK(!IsHex("0x0000")); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/wallet_tests.cpp b/src/test/wallet_tests.cpp new file mode 100644 index 0000000..b0b3c47 --- /dev/null +++ b/src/test/wallet_tests.cpp @@ -0,0 +1,295 @@ +#include + +#include "main.h" +#include "wallet.h" + +// how many times to run all the tests to have a chance to catch errors that only show up with particular random shuffles +#define RUN_TESTS 100 + +// some tests fail 1% of the time due to bad luck. +// we repeat those tests this many times and only complain if all iterations of the test fail +#define RANDOM_REPEATS 5 + +using namespace std; + +typedef set > CoinSet; + +BOOST_AUTO_TEST_SUITE(wallet_tests) + +static CWallet wallet; +static vector vCoins; + +static void add_coin(int64 nValue, int nAge = 6*24, bool fIsFromMe = false, int nInput=0) +{ + static int i; + CTransaction* tx = new CTransaction; + tx->nLockTime = i++; // so all transactions get different hashes + tx->vout.resize(nInput+1); + tx->vout[nInput].nValue = nValue; + CWalletTx* wtx = new CWalletTx(&wallet, *tx); + delete tx; + if (fIsFromMe) + { + // IsFromMe() returns (GetDebit() > 0), and GetDebit() is 0 if vin.empty(), + // so stop vin being empty, and cache a non-zero Debit to fake out IsFromMe() + wtx->vin.resize(1); + wtx->fDebitCached = true; + wtx->nDebitCached = 1; + } + COutput output(wtx, nInput, nAge); + vCoins.push_back(output); +} + +static void empty_wallet(void) +{ + BOOST_FOREACH(COutput output, vCoins) + delete output.tx; + vCoins.clear(); +} + +static bool equal_sets(CoinSet a, CoinSet b) +{ + pair ret = mismatch(a.begin(), a.end(), b.begin()); + return ret.first == a.end() && ret.second == b.end(); +} + +BOOST_AUTO_TEST_CASE(coin_selection_tests) +{ + static CoinSet setCoinsRet, setCoinsRet2; + static int64 nValueRet; + + // test multiple times to allow for differences in the shuffle order + for (int i = 0; i < RUN_TESTS; i++) + { + empty_wallet(); + + // with an empty wallet we can't even pay one cent + BOOST_CHECK(!wallet.SelectCoinsMinConf( 1 * CENT, 1, 6, vCoins, setCoinsRet, nValueRet)); + + add_coin(1*CENT, 4); // add a new 1 cent coin + + // with a new 1 cent coin, we still can't find a mature 1 cent + BOOST_CHECK(!wallet.SelectCoinsMinConf( 1 * CENT, 1, 6, vCoins, setCoinsRet, nValueRet)); + + // but we can find a new 1 cent + BOOST_CHECK( wallet.SelectCoinsMinConf( 1 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet)); + BOOST_CHECK_EQUAL(nValueRet, 1 * CENT); + + add_coin(2*CENT); // add a mature 2 cent coin + + // we can't make 3 cents of mature coins + BOOST_CHECK(!wallet.SelectCoinsMinConf( 3 * CENT, 1, 6, vCoins, setCoinsRet, nValueRet)); + + // we can make 3 cents of new coins + BOOST_CHECK( wallet.SelectCoinsMinConf( 3 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet)); + BOOST_CHECK_EQUAL(nValueRet, 3 * CENT); + + add_coin(5*CENT); // add a mature 5 cent coin, + add_coin(10*CENT, 3, true); // a new 10 cent coin sent from one of our own addresses + add_coin(20*CENT); // and a mature 20 cent coin + + // now we have new: 1+10=11 (of which 10 was self-sent), and mature: 2+5+20=27. total = 38 + + // we can't make 38 cents only if we disallow new coins: + BOOST_CHECK(!wallet.SelectCoinsMinConf(38 * CENT, 1, 6, vCoins, setCoinsRet, nValueRet)); + // we can't even make 37 cents if we don't allow new coins even if they're from us + BOOST_CHECK(!wallet.SelectCoinsMinConf(38 * CENT, 6, 6, vCoins, setCoinsRet, nValueRet)); + // but we can make 37 cents if we accept new coins from ourself + BOOST_CHECK( wallet.SelectCoinsMinConf(37 * CENT, 1, 6, vCoins, setCoinsRet, nValueRet)); + BOOST_CHECK_EQUAL(nValueRet, 37 * CENT); + // and we can make 38 cents if we accept all new coins + BOOST_CHECK( wallet.SelectCoinsMinConf(38 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet)); + BOOST_CHECK_EQUAL(nValueRet, 38 * CENT); + + // try making 34 cents from 1,2,5,10,20 - we can't do it exactly + BOOST_CHECK( wallet.SelectCoinsMinConf(34 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet)); + BOOST_CHECK_GT(nValueRet, 34 * CENT); // but should get more than 34 cents + BOOST_CHECK_EQUAL(setCoinsRet.size(), 3); // the best should be 20+10+5. it's incredibly unlikely the 1 or 2 got included (but possible) + + // when we try making 7 cents, the smaller coins (1,2,5) are enough. We should see just 2+5 + BOOST_CHECK( wallet.SelectCoinsMinConf( 7 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet)); + BOOST_CHECK_EQUAL(nValueRet, 7 * CENT); + BOOST_CHECK_EQUAL(setCoinsRet.size(), 2); + + // when we try making 8 cents, the smaller coins (1,2,5) are exactly enough. + BOOST_CHECK( wallet.SelectCoinsMinConf( 8 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet)); + BOOST_CHECK(nValueRet == 8 * CENT); + BOOST_CHECK_EQUAL(setCoinsRet.size(), 3); + + // when we try making 9 cents, no subset of smaller coins is enough, and we get the next bigger coin (10) + BOOST_CHECK( wallet.SelectCoinsMinConf( 9 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet)); + BOOST_CHECK_EQUAL(nValueRet, 10 * CENT); + BOOST_CHECK_EQUAL(setCoinsRet.size(), 1); + + // now clear out the wallet and start again to test choosing between subsets of smaller coins and the next biggest coin + empty_wallet(); + + add_coin( 6*CENT); + add_coin( 7*CENT); + add_coin( 8*CENT); + add_coin(20*CENT); + add_coin(30*CENT); // now we have 6+7+8+20+30 = 71 cents total + + // check that we have 71 and not 72 + BOOST_CHECK( wallet.SelectCoinsMinConf(71 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet)); + BOOST_CHECK(!wallet.SelectCoinsMinConf(72 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet)); + + // now try making 16 cents. the best smaller coins can do is 6+7+8 = 21; not as good at the next biggest coin, 20 + BOOST_CHECK( wallet.SelectCoinsMinConf(16 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet)); + BOOST_CHECK_EQUAL(nValueRet, 20 * CENT); // we should get 20 in one coin + BOOST_CHECK_EQUAL(setCoinsRet.size(), 1); + + add_coin( 5*CENT); // now we have 5+6+7+8+20+30 = 75 cents total + + // now if we try making 16 cents again, the smaller coins can make 5+6+7 = 18 cents, better than the next biggest coin, 20 + BOOST_CHECK( wallet.SelectCoinsMinConf(16 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet)); + BOOST_CHECK_EQUAL(nValueRet, 18 * CENT); // we should get 18 in 3 coins + BOOST_CHECK_EQUAL(setCoinsRet.size(), 3); + + add_coin( 18*CENT); // now we have 5+6+7+8+18+20+30 + + // and now if we try making 16 cents again, the smaller coins can make 5+6+7 = 18 cents, the same as the next biggest coin, 18 + BOOST_CHECK( wallet.SelectCoinsMinConf(16 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet)); + BOOST_CHECK_EQUAL(nValueRet, 18 * CENT); // we should get 18 in 1 coin + BOOST_CHECK_EQUAL(setCoinsRet.size(), 1); // because in the event of a tie, the biggest coin wins + + // now try making 11 cents. we should get 5+6 + BOOST_CHECK( wallet.SelectCoinsMinConf(11 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet)); + BOOST_CHECK_EQUAL(nValueRet, 11 * CENT); + BOOST_CHECK_EQUAL(setCoinsRet.size(), 2); + + // check that the smallest bigger coin is used + add_coin( 1*COIN); + add_coin( 2*COIN); + add_coin( 3*COIN); + add_coin( 4*COIN); // now we have 5+6+7+8+18+20+30+100+200+300+400 = 1094 cents + BOOST_CHECK( wallet.SelectCoinsMinConf(95 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet)); + BOOST_CHECK_EQUAL(nValueRet, 1 * COIN); // we should get 1 BTC in 1 coin + BOOST_CHECK_EQUAL(setCoinsRet.size(), 1); + + BOOST_CHECK( wallet.SelectCoinsMinConf(195 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet)); + BOOST_CHECK_EQUAL(nValueRet, 2 * COIN); // we should get 2 BTC in 1 coin + BOOST_CHECK_EQUAL(setCoinsRet.size(), 1); + + // empty the wallet and start again, now with fractions of a cent, to test sub-cent change avoidance + empty_wallet(); + add_coin(0.1*CENT); + add_coin(0.2*CENT); + add_coin(0.3*CENT); + add_coin(0.4*CENT); + add_coin(0.5*CENT); + + // try making 1 cent from 0.1 + 0.2 + 0.3 + 0.4 + 0.5 = 1.5 cents + // we'll get sub-cent change whatever happens, so can expect 1.0 exactly + BOOST_CHECK( wallet.SelectCoinsMinConf(1 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet)); + BOOST_CHECK_EQUAL(nValueRet, 1 * CENT); + + // but if we add a bigger coin, making it possible to avoid sub-cent change, things change: + add_coin(1111*CENT); + + // try making 1 cent from 0.1 + 0.2 + 0.3 + 0.4 + 0.5 + 1111 = 1112.5 cents + BOOST_CHECK( wallet.SelectCoinsMinConf(1 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet)); + BOOST_CHECK_EQUAL(nValueRet, 1 * CENT); // we should get the exact amount + + // if we add more sub-cent coins: + add_coin(0.6*CENT); + add_coin(0.7*CENT); + + // and try again to make 1.0 cents, we can still make 1.0 cents + BOOST_CHECK( wallet.SelectCoinsMinConf(1 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet)); + BOOST_CHECK_EQUAL(nValueRet, 1 * CENT); // we should get the exact amount + + // run the 'mtgox' test (see http://blockexplorer.com/tx/29a3efd3ef04f9153d47a990bd7b048a4b2d213daaa5fb8ed670fb85f13bdbcf) + // they tried to consolidate 10 50k coins into one 500k coin, and ended up with 50k in change + empty_wallet(); + for (int i = 0; i < 20; i++) + add_coin(50000 * COIN); + + BOOST_CHECK( wallet.SelectCoinsMinConf(500000 * COIN, 1, 1, vCoins, setCoinsRet, nValueRet)); + BOOST_CHECK_EQUAL(nValueRet, 500000 * COIN); // we should get the exact amount + BOOST_CHECK_EQUAL(setCoinsRet.size(), 10); // in ten coins + + // if there's not enough in the smaller coins to make at least 1 cent change (0.5+0.6+0.7 < 1.0+1.0), + // we need to try finding an exact subset anyway + + // sometimes it will fail, and so we use the next biggest coin: + empty_wallet(); + add_coin(0.5 * CENT); + add_coin(0.6 * CENT); + add_coin(0.7 * CENT); + add_coin(1111 * CENT); + BOOST_CHECK( wallet.SelectCoinsMinConf(1 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet)); + BOOST_CHECK_EQUAL(nValueRet, 1111 * CENT); // we get the bigger coin + BOOST_CHECK_EQUAL(setCoinsRet.size(), 1); + + // but sometimes it's possible, and we use an exact subset (0.4 + 0.6 = 1.0) + empty_wallet(); + add_coin(0.4 * CENT); + add_coin(0.6 * CENT); + add_coin(0.8 * CENT); + add_coin(1111 * CENT); + BOOST_CHECK( wallet.SelectCoinsMinConf(1 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet)); + BOOST_CHECK_EQUAL(nValueRet, 1 * CENT); // we should get the exact amount + BOOST_CHECK_EQUAL(setCoinsRet.size(), 2); // in two coins 0.4+0.6 + + // test avoiding sub-cent change + empty_wallet(); + add_coin(0.0005 * COIN); + add_coin(0.01 * COIN); + add_coin(1 * COIN); + + // trying to make 1.0001 from these three coins + BOOST_CHECK( wallet.SelectCoinsMinConf(1.0001 * COIN, 1, 1, vCoins, setCoinsRet, nValueRet)); + BOOST_CHECK_EQUAL(nValueRet, 1.0105 * COIN); // we should get all coins + BOOST_CHECK_EQUAL(setCoinsRet.size(), 3); + + // but if we try to make 0.999, we should take the bigger of the two small coins to avoid sub-cent change + BOOST_CHECK( wallet.SelectCoinsMinConf(0.999 * COIN, 1, 1, vCoins, setCoinsRet, nValueRet)); + BOOST_CHECK_EQUAL(nValueRet, 1.01 * COIN); // we should get 1 + 0.01 + BOOST_CHECK_EQUAL(setCoinsRet.size(), 2); + + // test randomness + { + empty_wallet(); + for (int i2 = 0; i2 < 100; i2++) + add_coin(COIN); + + // picking 50 from 100 coins doesn't depend on the shuffle, + // but does depend on randomness in the stochastic approximation code + BOOST_CHECK(wallet.SelectCoinsMinConf(50 * COIN, 1, 6, vCoins, setCoinsRet , nValueRet)); + BOOST_CHECK(wallet.SelectCoinsMinConf(50 * COIN, 1, 6, vCoins, setCoinsRet2, nValueRet)); + BOOST_CHECK(!equal_sets(setCoinsRet, setCoinsRet2)); + + int fails = 0; + for (int i = 0; i < RANDOM_REPEATS; i++) + { + // selecting 1 from 100 identical coins depends on the shuffle; this test will fail 1% of the time + // run the test RANDOM_REPEATS times and only complain if all of them fail + BOOST_CHECK(wallet.SelectCoinsMinConf(COIN, 1, 6, vCoins, setCoinsRet , nValueRet)); + BOOST_CHECK(wallet.SelectCoinsMinConf(COIN, 1, 6, vCoins, setCoinsRet2, nValueRet)); + if (equal_sets(setCoinsRet, setCoinsRet2)) + fails++; + } + BOOST_CHECK_NE(fails, RANDOM_REPEATS); + + // add 75 cents in small change. not enough to make 90 cents, + // then try making 90 cents. there are multiple competing "smallest bigger" coins, + // one of which should be picked at random + add_coin( 5*CENT); add_coin(10*CENT); add_coin(15*CENT); add_coin(20*CENT); add_coin(25*CENT); + + fails = 0; + for (int i = 0; i < RANDOM_REPEATS; i++) + { + // selecting 1 from 100 identical coins depends on the shuffle; this test will fail 1% of the time + // run the test RANDOM_REPEATS times and only complain if all of them fail + BOOST_CHECK(wallet.SelectCoinsMinConf(90*CENT, 1, 6, vCoins, setCoinsRet , nValueRet)); + BOOST_CHECK(wallet.SelectCoinsMinConf(90*CENT, 1, 6, vCoins, setCoinsRet2, nValueRet)); + if (equal_sets(setCoinsRet, setCoinsRet2)) + fails++; + } + BOOST_CHECK_NE(fails, RANDOM_REPEATS); + } + } +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/tor/LICENSE b/src/tor/LICENSE new file mode 100644 index 0000000..8a6fcca --- /dev/null +++ b/src/tor/LICENSE @@ -0,0 +1,174 @@ + This file contains the license for Tor, + a free software project to provide anonymity on the Internet. + + It also lists the licenses for other components used by Tor. + + For more information about Tor, see https://www.torproject.org/. + + If you got this file as a part of a larger bundle, + there may be other license terms that you should be aware of. + +=============================================================================== +Tor is distributed under this license: + +Copyright (c) 2001-2004, Roger Dingledine +Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson +Copyright (c) 2007-2013, The Tor Project, Inc. + +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. + + * Neither the names of the copyright owners 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 +OWNER 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. +=============================================================================== +src/ext/strlcat.c and src/ext/strlcpy.c by Todd C. Miller are licensed +under the following license: + + * Copyright (c) 1998 Todd C. Miller + * 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. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE AUTHOR 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. +=============================================================================== +src/ext/tor_queue.h is licensed under the following license: + + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + +=============================================================================== +src/config/geoip is licensed under the following license: + +OPEN DATA LICENSE (GeoLite Country and GeoLite City databases) + +Copyright (c) 2008 MaxMind, Inc. All Rights Reserved. + +All advertising materials and documentation mentioning features or use of +this database must display the following acknowledgment: +"This product includes GeoLite data created by MaxMind, available from +http://maxmind.com/" + +Redistribution and use with or without modification, are permitted provided +that the following conditions are met: +1. Redistributions must retain the above copyright notice, this list of +conditions and the following disclaimer in the documentation and/or other +materials provided with the distribution. +2. All advertising materials and documentation mentioning features or use of +this database must display the following acknowledgement: +"This product includes GeoLite data created by MaxMind, available from +http://maxmind.com/" +3. "MaxMind" may not be used to endorse or promote products derived from this +database without specific prior written permission. + +THIS DATABASE IS PROVIDED BY MAXMIND, INC ``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 MAXMIND 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 +DATABASE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +=============================================================================== +m4/pc_from_ucontext.m4 is available under the following license. Note that +it is *not* built into the Tor license. + +Copyright (c) 2005, Google Inc. +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. + * Neither the name of Google Inc. 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 +OWNER 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. + +=============================================================================== +If you got Tor as a static binary with OpenSSL included, then you should know: + "This product includes software developed by the OpenSSL Project + for use in the OpenSSL Toolkit (http://www.openssl.org/)" +=============================================================================== diff --git a/src/tor/address.c b/src/tor/address.c new file mode 100644 index 0000000..c30d2ab --- /dev/null +++ b/src/tor/address.c @@ -0,0 +1,1692 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file address.c + * \brief Functions to use and manipulate the tor_addr_t structure. + **/ + +#include "orconfig.h" +#include "tor_compat.h" +#include "tor_util.h" +#include "address.h" +#include "torlog.h" +#include "container.h" +#include "sandbox.h" + +#ifdef _WIN32 +#include +#include +#include +/* For access to structs needed by GetAdaptersAddresses */ +#undef _WIN32_WINNT +#define _WIN32_WINNT 0x0501 +#include +#endif + +#ifdef HAVE_SYS_TIME_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif +#ifdef HAVE_ERRNO_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_ARPA_INET_H +#include +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_NETDB_H +#include +#endif +#ifdef HAVE_SYS_PARAM_H +#include /* FreeBSD needs this to know what version it is */ +#endif +#ifdef HAVE_SYS_UN_H +#include +#endif +#ifdef HAVE_IFADDRS_H +#include +#endif +#ifdef HAVE_SYS_IOCTL_H +#include +#endif +#ifdef HAVE_NET_IF_H +#include +#endif +#include +#include +#include +#include +#include + +/* tor_addr_is_null() and maybe other functions rely on AF_UNSPEC being 0 to + * work correctly. Bail out here if we've found a platform where AF_UNSPEC + * isn't 0. */ +#if AF_UNSPEC != 0 +#error We rely on AF_UNSPEC being 0. Let us know about your platform, please! +#endif + +/** Convert the tor_addr_t in a, with port in port, into a + * sockaddr object in *sa_out of object size len. If not enough + * room is available in sa_out, or on error, return 0. On success, return + * the length of the sockaddr. + * + * Interface note: ordinarily, we return -1 for error. We can't do that here, + * since socklen_t is unsigned on some platforms. + **/ +socklen_t +tor_addr_to_sockaddr(const tor_addr_t *a, + uint16_t port, + struct sockaddr *sa_out, + socklen_t len) +{ + sa_family_t family = tor_addr_family(a); + if (family == AF_INET) { + struct sockaddr_in *sin; + if (len < (int)sizeof(struct sockaddr_in)) + return 0; + sin = (struct sockaddr_in *)sa_out; + memset(sin, 0, sizeof(struct sockaddr_in)); +#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN + sin->sin_len = sizeof(struct sockaddr_in); +#endif + sin->sin_family = AF_INET; + sin->sin_port = htons(port); + sin->sin_addr.s_addr = tor_addr_to_ipv4n(a); + return sizeof(struct sockaddr_in); + } else if (family == AF_INET6) { + struct sockaddr_in6 *sin6; + if (len < (int)sizeof(struct sockaddr_in6)) + return 0; + sin6 = (struct sockaddr_in6 *)sa_out; + memset(sin6, 0, sizeof(struct sockaddr_in6)); +#ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_LEN + sin6->sin6_len = sizeof(struct sockaddr_in6); +#endif + sin6->sin6_family = AF_INET6; + sin6->sin6_port = htons(port); + memcpy(&sin6->sin6_addr, tor_addr_to_in6(a), sizeof(struct in6_addr)); + return sizeof(struct sockaddr_in6); + } else { + return 0; + } +} + +/** Set the tor_addr_t in a to contain the socket address contained in + * sa. */ +int +tor_addr_from_sockaddr(tor_addr_t *a, const struct sockaddr *sa, + uint16_t *port_out) +{ + tor_assert(a); + tor_assert(sa); + if (sa->sa_family == AF_INET) { + struct sockaddr_in *sin = (struct sockaddr_in *) sa; + tor_addr_from_ipv4n(a, sin->sin_addr.s_addr); + if (port_out) + *port_out = ntohs(sin->sin_port); + } else if (sa->sa_family == AF_INET6) { + struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) sa; + tor_addr_from_in6(a, &sin6->sin6_addr); + if (port_out) + *port_out = ntohs(sin6->sin6_port); + } else { + tor_addr_make_unspec(a); + return -1; + } + return 0; +} + +/** Return a newly allocated string holding the address described in + * sa. AF_UNIX, AF_UNSPEC, AF_INET, and AF_INET6 are supported. */ +char * +tor_sockaddr_to_str(const struct sockaddr *sa) +{ + char address[TOR_ADDR_BUF_LEN]; + char *result; + tor_addr_t addr; + uint16_t port; +#ifdef HAVE_SYS_UN_H + if (sa->sa_family == AF_UNIX) { + struct sockaddr_un *s_un = (struct sockaddr_un *)sa; + tor_asprintf(&result, "unix:%s", s_un->sun_path); + return result; + } +#endif + if (sa->sa_family == AF_UNSPEC) + return tor_strdup("unspec"); + + if (tor_addr_from_sockaddr(&addr, sa, &port) < 0) + return NULL; + if (! tor_addr_to_str(address, &addr, sizeof(address), 1)) + return NULL; + tor_asprintf(&result, "%s:%d", address, (int)port); + return result; +} + +/** Set address a to the unspecified address. This address belongs to + * no family. */ +void +tor_addr_make_unspec(tor_addr_t *a) +{ + memset(a, 0, sizeof(*a)); + a->family = AF_UNSPEC; +} + +/** Set address a to the null address in address family family. + * The null address for AF_INET is 0.0.0.0. The null address for AF_INET6 is + * [::]. AF_UNSPEC is all null. */ +void +tor_addr_make_null(tor_addr_t *a, sa_family_t family) +{ + memset(a, 0, sizeof(*a)); + a->family = family; +} + +/** Similar behavior to Unix gethostbyname: resolve name, and set + * *addr to the proper IP address and family. The family + * argument (which must be AF_INET, AF_INET6, or AF_UNSPEC) declares a + * preferred family, though another one may be returned if only one + * family is implemented for this address. + * + * Return 0 on success, -1 on failure; 1 on transient failure. + */ +int +tor_addr_lookup(const char *name, uint16_t family, tor_addr_t *addr) +{ + /* Perhaps eventually this should be replaced by a tor_getaddrinfo or + * something. + */ + struct in_addr iaddr; + struct in6_addr iaddr6; + tor_assert(name); + tor_assert(addr); + tor_assert(family == AF_INET || family == AF_INET6 || family == AF_UNSPEC); + if (!*name) { + /* Empty address is an error. */ + return -1; + } else if (tor_inet_pton(AF_INET, name, &iaddr)) { + /* It's an IPv4 IP. */ + if (family == AF_INET6) + return -1; + tor_addr_from_in(addr, &iaddr); + return 0; + } else if (tor_inet_pton(AF_INET6, name, &iaddr6)) { + if (family == AF_INET) + return -1; + tor_addr_from_in6(addr, &iaddr6); + return 0; + } else { +#ifdef HAVE_GETADDRINFO + int err; + struct addrinfo *res=NULL, *res_p; + struct addrinfo *best=NULL; + struct addrinfo hints; + int result = -1; + memset(&hints, 0, sizeof(hints)); + hints.ai_family = family; + hints.ai_socktype = SOCK_STREAM; + err = sandbox_getaddrinfo(name, NULL, &hints, &res); + if (!err) { + best = NULL; + for (res_p = res; res_p; res_p = res_p->ai_next) { + if (family == AF_UNSPEC) { + if (res_p->ai_family == AF_INET) { + best = res_p; + break; + } else if (res_p->ai_family == AF_INET6 && !best) { + best = res_p; + } + } else if (family == res_p->ai_family) { + best = res_p; + break; + } + } + if (!best) + best = res; + if (best->ai_family == AF_INET) { + tor_addr_from_in(addr, + &((struct sockaddr_in*)best->ai_addr)->sin_addr); + result = 0; + } else if (best->ai_family == AF_INET6) { + tor_addr_from_in6(addr, + &((struct sockaddr_in6*)best->ai_addr)->sin6_addr); + result = 0; + } + freeaddrinfo(res); + return result; + } + return (err == EAI_AGAIN) ? 1 : -1; +#else + struct hostent *ent; + int err; +#ifdef HAVE_GETHOSTBYNAME_R_6_ARG + char buf[2048]; + struct hostent hostent; + int r; + r = gethostbyname_r(name, &hostent, buf, sizeof(buf), &ent, &err); +#elif defined(HAVE_GETHOSTBYNAME_R_5_ARG) + char buf[2048]; + struct hostent hostent; + ent = gethostbyname_r(name, &hostent, buf, sizeof(buf), &err); +#elif defined(HAVE_GETHOSTBYNAME_R_3_ARG) + struct hostent_data data; + struct hostent hent; + memset(&data, 0, sizeof(data)); + err = gethostbyname_r(name, &hent, &data); + ent = err ? NULL : &hent; +#else + ent = gethostbyname(name); +#ifdef _WIN32 + err = WSAGetLastError(); +#else + err = h_errno; +#endif +#endif /* endif HAVE_GETHOSTBYNAME_R_6_ARG. */ + if (ent) { + if (ent->h_addrtype == AF_INET) { + tor_addr_from_in(addr, (struct in_addr*) ent->h_addr); + } else if (ent->h_addrtype == AF_INET6) { + tor_addr_from_in6(addr, (struct in6_addr*) ent->h_addr); + } else { + tor_assert(0); /* gethostbyname() returned a bizarre addrtype */ + } + return 0; + } +#ifdef _WIN32 + return (err == WSATRY_AGAIN) ? 1 : -1; +#else + return (err == TRY_AGAIN) ? 1 : -1; +#endif +#endif + } +} + +/** Return true iff ip is an IP reserved to localhost or local networks + * in RFC1918 or RFC4193 or RFC4291. (fec0::/10, deprecated by RFC3879, is + * also treated as internal for now.) + */ +int +tor_addr_is_internal_(const tor_addr_t *addr, int for_listening, + const char *filename, int lineno) +{ + uint32_t iph4 = 0; + uint32_t iph6[4]; + sa_family_t v_family; + v_family = tor_addr_family(addr); + + if (v_family == AF_INET) { + iph4 = tor_addr_to_ipv4h(addr); + } else if (v_family == AF_INET6) { + if (tor_addr_is_v4(addr)) { /* v4-mapped */ + v_family = AF_INET; + iph4 = ntohl(tor_addr_to_in6_addr32(addr)[3]); + } + } + + if (v_family == AF_INET6) { + const uint32_t *a32 = tor_addr_to_in6_addr32(addr); + iph6[0] = ntohl(a32[0]); + iph6[1] = ntohl(a32[1]); + iph6[2] = ntohl(a32[2]); + iph6[3] = ntohl(a32[3]); + if (for_listening && !iph6[0] && !iph6[1] && !iph6[2] && !iph6[3]) /* :: */ + return 0; + + if (((iph6[0] & 0xfe000000) == 0xfc000000) || /* fc00/7 - RFC4193 */ + ((iph6[0] & 0xffc00000) == 0xfe800000) || /* fe80/10 - RFC4291 */ + ((iph6[0] & 0xffc00000) == 0xfec00000)) /* fec0/10 D- RFC3879 */ + return 1; + + if (!iph6[0] && !iph6[1] && !iph6[2] && + ((iph6[3] & 0xfffffffe) == 0x00000000)) /* ::/127 */ + return 1; + + return 0; + } else if (v_family == AF_INET) { + if (for_listening && !iph4) /* special case for binding to 0.0.0.0 */ + return 0; + if (((iph4 & 0xff000000) == 0x0a000000) || /* 10/8 */ + ((iph4 & 0xff000000) == 0x00000000) || /* 0/8 */ + ((iph4 & 0xff000000) == 0x7f000000) || /* 127/8 */ + ((iph4 & 0xffff0000) == 0xa9fe0000) || /* 169.254/16 */ + ((iph4 & 0xfff00000) == 0xac100000) || /* 172.16/12 */ + ((iph4 & 0xffff0000) == 0xc0a80000)) /* 192.168/16 */ + return 1; + return 0; + } + + /* unknown address family... assume it's not safe for external use */ + /* rather than tor_assert(0) */ + log_warn(LD_BUG, "tor_addr_is_internal() called from %s:%d with a " + "non-IP address of type %d", filename, lineno, (int)v_family); + tor_fragile_assert(); + return 1; +} + +/** Convert a tor_addr_t addr into a string, and store it in + * dest of size len. Returns a pointer to dest on success, + * or NULL on failure. If decorate, surround IPv6 addresses with + * brackets. + */ +const char * +tor_addr_to_str(char *dest, const tor_addr_t *addr, size_t len, int decorate) +{ + const char *ptr; + tor_assert(addr && dest); + + switch (tor_addr_family(addr)) { + case AF_INET: + /* Shortest addr x.x.x.x + \0 */ + if (len < 8) + return NULL; + ptr = tor_inet_ntop(AF_INET, &addr->addr.in_addr, dest, len); + break; + case AF_INET6: + /* Shortest addr [ :: ] + \0 */ + if (len < (3 + (decorate ? 2 : 0))) + return NULL; + + if (decorate) + ptr = tor_inet_ntop(AF_INET6, &addr->addr.in6_addr, dest+1, len-2); + else + ptr = tor_inet_ntop(AF_INET6, &addr->addr.in6_addr, dest, len); + + if (ptr && decorate) { + *dest = '['; + memcpy(dest+strlen(dest), "]", 2); + tor_assert(ptr == dest+1); + ptr = dest; + } + break; + default: + return NULL; + } + return ptr; +} + +/** Parse an .in-addr.arpa or .ip6.arpa address from address. Return 0 + * if this is not an .in-addr.arpa address or an .ip6.arpa address. Return -1 + * if this is an ill-formed .in-addr.arpa address or an .ip6.arpa address. + * Also return -1 if family is not AF_UNSPEC, and the parsed address + * family does not match family. On success, return 1, and store the + * result, if any, into result, if provided. + * + * If accept_regular is set and the address is in neither recognized + * reverse lookup hostname format, try parsing the address as a regular + * IPv4 or IPv6 address too. + */ +int +tor_addr_parse_PTR_name(tor_addr_t *result, const char *address, + int family, int accept_regular) +{ + if (!strcasecmpend(address, ".in-addr.arpa")) { + /* We have an in-addr.arpa address. */ + char buf[INET_NTOA_BUF_LEN]; + size_t len; + struct in_addr inaddr; + if (family == AF_INET6) + return -1; + + len = strlen(address) - strlen(".in-addr.arpa"); + if (len >= INET_NTOA_BUF_LEN) + return -1; /* Too long. */ + + memcpy(buf, address, len); + buf[len] = '\0'; + if (tor_inet_aton(buf, &inaddr) == 0) + return -1; /* malformed. */ + + /* reverse the bytes */ + inaddr.s_addr = (uint32_t) + (((inaddr.s_addr & 0x000000ff) << 24) + |((inaddr.s_addr & 0x0000ff00) << 8) + |((inaddr.s_addr & 0x00ff0000) >> 8) + |((inaddr.s_addr & 0xff000000) >> 24)); + + if (result) { + tor_addr_from_in(result, &inaddr); + } + return 1; + } + + if (!strcasecmpend(address, ".ip6.arpa")) { + const char *cp; + int i; + int n0, n1; + struct in6_addr in6; + + if (family == AF_INET) + return -1; + + cp = address; + for (i = 0; i < 16; ++i) { + n0 = hex_decode_digit(*cp++); /* The low-order nybble appears first. */ + if (*cp++ != '.') return -1; /* Then a dot. */ + n1 = hex_decode_digit(*cp++); /* The high-order nybble appears first. */ + if (*cp++ != '.') return -1; /* Then another dot. */ + if (n0<0 || n1 < 0) /* Both nybbles must be hex. */ + return -1; + + /* We don't check the length of the string in here. But that's okay, + * since we already know that the string ends with ".ip6.arpa", and + * there is no way to frameshift .ip6.arpa so it fits into the pattern + * of hexdigit, period, hexdigit, period that we enforce above. + */ + + /* Assign from low-byte to high-byte. */ + in6.s6_addr[15-i] = n0 | (n1 << 4); + } + if (strcasecmp(cp, "ip6.arpa")) + return -1; + + if (result) { + tor_addr_from_in6(result, &in6); + } + return 1; + } + + if (accept_regular) { + tor_addr_t tmp; + int r = tor_addr_parse(&tmp, address); + if (r < 0) + return 0; + if (r != family && family != AF_UNSPEC) + return -1; + + if (result) + memcpy(result, &tmp, sizeof(tor_addr_t)); + + return 1; + } + + return 0; +} + +/** Convert addr to an in-addr.arpa name or a .ip6.arpa name, + * and store the result in the outlen-byte buffer at + * out. Return the number of chars written to out, not + * including the trailing \0, on success. Returns -1 on failure. */ +int +tor_addr_to_PTR_name(char *out, size_t outlen, + const tor_addr_t *addr) +{ + tor_assert(out); + tor_assert(addr); + + if (addr->family == AF_INET) { + uint32_t a = tor_addr_to_ipv4h(addr); + + return tor_snprintf(out, outlen, "%d.%d.%d.%d.in-addr.arpa", + (int)(uint8_t)((a )&0xff), + (int)(uint8_t)((a>>8 )&0xff), + (int)(uint8_t)((a>>16)&0xff), + (int)(uint8_t)((a>>24)&0xff)); + } else if (addr->family == AF_INET6) { + int i; + char *cp = out; + const uint8_t *bytes = tor_addr_to_in6_addr8(addr); + if (outlen < REVERSE_LOOKUP_NAME_BUF_LEN) + return -1; + for (i = 15; i >= 0; --i) { + uint8_t byte = bytes[i]; + *cp++ = "0123456789abcdef"[byte & 0x0f]; + *cp++ = '.'; + *cp++ = "0123456789abcdef"[byte >> 4]; + *cp++ = '.'; + } + memcpy(cp, "ip6.arpa", 9); /* 8 characters plus NUL */ + return 32 * 2 + 8; + } + return -1; +} + +/** Parse a string s containing an IPv4/IPv6 address, and possibly + * a mask and port or port range. Store the parsed address in + * addr_out, a mask (if any) in mask_out, and port(s) (if any) + * in port_min_out and port_max_out. + * + * The syntax is: + * Address OptMask OptPortRange + * Address ::= IPv4Address / "[" IPv6Address "]" / "*" + * OptMask ::= "/" Integer / + * OptPortRange ::= ":*" / ":" Integer / ":" Integer "-" Integer / + * + * - If mask, minport, or maxport are NULL, we do not want these + * options to be set; treat them as an error if present. + * - If the string has no mask, the mask is set to /32 (IPv4) or /128 (IPv6). + * - If the string has one port, it is placed in both min and max port + * variables. + * - If the string has no port(s), port_(min|max)_out are set to 1 and 65535. + * + * Return an address family on success, or -1 if an invalid address string is + * provided. + * + * If 'flags & TAPMP_EXTENDED_STAR' is false, then the wildcard address '*' + * yield an IPv4 wildcard. + * + * If 'flags & TAPMP_EXTENDED_STAR' is true, then the wildcard address '*' + * yields an AF_UNSPEC wildcard address, and the following change is made + * in the grammar above: + * Address ::= IPv4Address / "[" IPv6Address "]" / "*" / "*4" / "*6" + * with the new "*4" and "*6" productions creating a wildcard to match + * IPv4 or IPv6 addresses. + * + */ +int +tor_addr_parse_mask_ports(const char *s, + unsigned flags, + tor_addr_t *addr_out, + maskbits_t *maskbits_out, + uint16_t *port_min_out, uint16_t *port_max_out) +{ + char *base = NULL, *address, *mask = NULL, *port = NULL, *rbracket = NULL; + char *endptr; + int any_flag=0, v4map=0; + sa_family_t family; + struct in6_addr in6_tmp; + struct in_addr in_tmp; + + tor_assert(s); + tor_assert(addr_out); + + /** Longest possible length for an address, mask, and port-range combination. + * Includes IP, [], /mask, :, ports */ +#define MAX_ADDRESS_LENGTH (TOR_ADDR_BUF_LEN+2+(1+INET_NTOA_BUF_LEN)+12+1) + + if (strlen(s) > MAX_ADDRESS_LENGTH) { + log_warn(LD_GENERAL, "Impossibly long IP %s; rejecting", escaped(s)); + goto err; + } + base = tor_strdup(s); + + /* Break 'base' into separate strings. */ + address = base; + if (*address == '[') { /* Probably IPv6 */ + address++; + rbracket = strchr(address, ']'); + if (!rbracket) { + log_warn(LD_GENERAL, + "No closing IPv6 bracket in address pattern; rejecting."); + goto err; + } + } + mask = strchr((rbracket?rbracket:address),'/'); + port = strchr((mask?mask:(rbracket?rbracket:address)), ':'); + if (port) + *port++ = '\0'; + if (mask) + *mask++ = '\0'; + if (rbracket) + *rbracket = '\0'; + if (port && mask) + tor_assert(port > mask); + if (mask && rbracket) + tor_assert(mask > rbracket); + + /* Now "address" is the a.b.c.d|'*'|abcd::1 part... + * "mask" is the Mask|Maskbits part... + * and "port" is the *|port|min-max part. + */ + + /* Process the address portion */ + memset(addr_out, 0, sizeof(tor_addr_t)); + + if (!strcmp(address, "*")) { + if (flags & TAPMP_EXTENDED_STAR) { + family = AF_UNSPEC; + tor_addr_make_unspec(addr_out); + } else { + family = AF_INET; + tor_addr_from_ipv4h(addr_out, 0); + } + any_flag = 1; + } else if (!strcmp(address, "*4") && (flags & TAPMP_EXTENDED_STAR)) { + family = AF_INET; + tor_addr_from_ipv4h(addr_out, 0); + any_flag = 1; + } else if (!strcmp(address, "*6") && (flags & TAPMP_EXTENDED_STAR)) { + static char nil_bytes[16] = { 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 }; + family = AF_INET6; + tor_addr_from_ipv6_bytes(addr_out, nil_bytes); + any_flag = 1; + } else if (tor_inet_pton(AF_INET6, address, &in6_tmp) > 0) { + family = AF_INET6; + tor_addr_from_in6(addr_out, &in6_tmp); + } else if (tor_inet_pton(AF_INET, address, &in_tmp) > 0) { + family = AF_INET; + tor_addr_from_in(addr_out, &in_tmp); + } else { + log_warn(LD_GENERAL, "Malformed IP %s in address pattern; rejecting.", + escaped(address)); + goto err; + } + + v4map = tor_addr_is_v4(addr_out); + + /* Parse mask */ + if (maskbits_out) { + int bits = 0; + struct in_addr v4mask; + + if (mask) { /* the caller (tried to) specify a mask */ + bits = (int) strtol(mask, &endptr, 10); + if (!*endptr) { /* strtol converted everything, so it was an integer */ + if ((bits<0 || bits>128) || + (family == AF_INET && bits > 32)) { + log_warn(LD_GENERAL, + "Bad number of mask bits (%d) on address range; rejecting.", + bits); + goto err; + } + } else { /* mask might still be an address-style mask */ + if (tor_inet_pton(AF_INET, mask, &v4mask) > 0) { + bits = addr_mask_get_bits(ntohl(v4mask.s_addr)); + if (bits < 0) { + log_warn(LD_GENERAL, + "IPv4-style mask %s is not a prefix address; rejecting.", + escaped(mask)); + goto err; + } + } else { /* Not IPv4; we don't do address-style IPv6 masks. */ + log_warn(LD_GENERAL, + "Malformed mask on address range %s; rejecting.", + escaped(s)); + goto err; + } + } + if (family == AF_INET6 && v4map) { + if (bits > 32 && bits < 96) { /* Crazy */ + log_warn(LD_GENERAL, + "Bad mask bits %d for V4-mapped V6 address; rejecting.", + bits); + goto err; + } + /* XXXX_IP6 is this really what we want? */ + bits = 96 + bits%32; /* map v4-mapped masks onto 96-128 bits */ + } + } else { /* pick an appropriate mask, as none was given */ + if (any_flag) + bits = 0; /* This is okay whether it's V6 or V4 (FIX V4-mapped V6!) */ + else if (tor_addr_family(addr_out) == AF_INET) + bits = 32; + else if (tor_addr_family(addr_out) == AF_INET6) + bits = 128; + } + *maskbits_out = (maskbits_t) bits; + } else { + if (mask) { + log_warn(LD_GENERAL, + "Unexpected mask in address %s; rejecting", escaped(s)); + goto err; + } + } + + /* Parse port(s) */ + if (port_min_out) { + uint16_t port2; + if (!port_max_out) /* caller specified one port; fake the second one */ + port_max_out = &port2; + + if (parse_port_range(port, port_min_out, port_max_out) < 0) { + goto err; + } else if ((*port_min_out != *port_max_out) && port_max_out == &port2) { + log_warn(LD_GENERAL, + "Wanted one port from address range, but there are two."); + + port_max_out = NULL; /* caller specified one port, so set this back */ + goto err; + } + } else { + if (port) { + log_warn(LD_GENERAL, + "Unexpected ports in address %s; rejecting", escaped(s)); + goto err; + } + } + + tor_free(base); + return tor_addr_family(addr_out); + err: + tor_free(base); + return -1; +} + +/** Determine whether an address is IPv4, either native or IPv4-mapped IPv6. + * Note that this is about representation only, as any decent stack will + * reject IPv4-mapped addresses received on the wire (and won't use them + * on the wire either). + */ +int +tor_addr_is_v4(const tor_addr_t *addr) +{ + tor_assert(addr); + + if (tor_addr_family(addr) == AF_INET) + return 1; + + if (tor_addr_family(addr) == AF_INET6) { + /* First two don't need to be ordered */ + uint32_t *a32 = tor_addr_to_in6_addr32(addr); + if (a32[0] == 0 && a32[1] == 0 && ntohl(a32[2]) == 0x0000ffffu) + return 1; + } + + return 0; /* Not IPv4 - unknown family or a full-blood IPv6 address */ +} + +/** Determine whether an address addr is null, either all zeroes or + * belonging to family AF_UNSPEC. + */ +int +tor_addr_is_null(const tor_addr_t *addr) +{ + tor_assert(addr); + + switch (tor_addr_family(addr)) { + case AF_INET6: { + uint32_t *a32 = tor_addr_to_in6_addr32(addr); + return (a32[0] == 0) && (a32[1] == 0) && (a32[2] == 0) && (a32[3] == 0); + } + case AF_INET: + return (tor_addr_to_ipv4n(addr) == 0); + case AF_UNSPEC: + return 1; + default: + log_warn(LD_BUG, "Called with unknown address family %d", + (int)tor_addr_family(addr)); + return 0; + } + //return 1; +} + +/** Return true iff addr is a loopback address */ +int +tor_addr_is_loopback(const tor_addr_t *addr) +{ + tor_assert(addr); + switch (tor_addr_family(addr)) { + case AF_INET6: { + /* ::1 */ + uint32_t *a32 = tor_addr_to_in6_addr32(addr); + return (a32[0] == 0) && (a32[1] == 0) && (a32[2] == 0) && + (ntohl(a32[3]) == 1); + } + case AF_INET: + /* 127.0.0.1 */ + return (tor_addr_to_ipv4h(addr) & 0xff000000) == 0x7f000000; + case AF_UNSPEC: + return 0; + default: + tor_fragile_assert(); + return 0; + } +} + +/** Set dest to equal the IPv4 address in v4addr (given in + * network order). */ +void +tor_addr_from_ipv4n(tor_addr_t *dest, uint32_t v4addr) +{ + tor_assert(dest); + memset(dest, 0, sizeof(tor_addr_t)); + dest->family = AF_INET; + dest->addr.in_addr.s_addr = v4addr; +} + +/** Set dest to equal the IPv6 address in the 16 bytes at + * ipv6_bytes. */ +void +tor_addr_from_ipv6_bytes(tor_addr_t *dest, const char *ipv6_bytes) +{ + tor_assert(dest); + tor_assert(ipv6_bytes); + memset(dest, 0, sizeof(tor_addr_t)); + dest->family = AF_INET6; + memcpy(dest->addr.in6_addr.s6_addr, ipv6_bytes, 16); +} + +/** Set dest equal to the IPv6 address in the in6_addr in6. */ +void +tor_addr_from_in6(tor_addr_t *dest, const struct in6_addr *in6) +{ + tor_addr_from_ipv6_bytes(dest, (const char*)in6->s6_addr); +} + +/** Copy a tor_addr_t from src to dest. + */ +void +tor_addr_copy(tor_addr_t *dest, const tor_addr_t *src) +{ + if (src == dest) + return; + tor_assert(src); + tor_assert(dest); + memcpy(dest, src, sizeof(tor_addr_t)); +} + +/** Given two addresses addr1 and addr2, return 0 if the two + * addresses are equivalent under the mask mbits, less than 0 if addr1 + * precedes addr2, and greater than 0 otherwise. + * + * Different address families (IPv4 vs IPv6) are always considered unequal if + * how is CMP_EXACT; otherwise, IPv6-mapped IPv4 addresses are + * considered equivalent to their IPv4 equivalents. + */ +int +tor_addr_compare(const tor_addr_t *addr1, const tor_addr_t *addr2, + tor_addr_comparison_t how) +{ + return tor_addr_compare_masked(addr1, addr2, 128, how); +} + +/** As tor_addr_compare(), but only looks at the first mask bits of + * the address. + * + * Reduce over-specific masks (>128 for ipv6, >32 for ipv4) to 128 or 32. + * + * The mask is interpreted relative to addr1, so that if a is + * \::ffff:1.2.3.4, and b is 3.4.5.6, + * tor_addr_compare_masked(a,b,100,CMP_SEMANTIC) is the same as + * -tor_addr_compare_masked(b,a,4,CMP_SEMANTIC). + * + * We guarantee that the ordering from tor_addr_compare_masked is a total + * order on addresses, but not that it is any particular order, or that it + * will be the same from one version to the next. + */ +int +tor_addr_compare_masked(const tor_addr_t *addr1, const tor_addr_t *addr2, + maskbits_t mbits, tor_addr_comparison_t how) +{ + /** Helper: Evaluates to -1 if a is less than b, 0 if a equals b, or 1 if a + * is greater than b. May evaluate a and b more than once. */ +#define TRISTATE(a,b) (((a)<(b))?-1: (((a)==(b))?0:1)) + sa_family_t family1, family2, v_family1, v_family2; + + tor_assert(addr1 && addr2); + + v_family1 = family1 = tor_addr_family(addr1); + v_family2 = family2 = tor_addr_family(addr2); + + if (family1==family2) { + /* When the families are the same, there's only one way to do the + * comparison: exactly. */ + int r; + switch (family1) { + case AF_UNSPEC: + return 0; /* All unspecified addresses are equal */ + case AF_INET: { + uint32_t a1 = tor_addr_to_ipv4h(addr1); + uint32_t a2 = tor_addr_to_ipv4h(addr2); + if (mbits <= 0) + return 0; + if (mbits > 32) + mbits = 32; + a1 >>= (32-mbits); + a2 >>= (32-mbits); + r = TRISTATE(a1, a2); + return r; + } + case AF_INET6: { + const uint8_t *a1 = tor_addr_to_in6_addr8(addr1); + const uint8_t *a2 = tor_addr_to_in6_addr8(addr2); + const int bytes = mbits >> 3; + const int leftover_bits = mbits & 7; + if (bytes && (r = tor_memcmp(a1, a2, bytes))) { + return r; + } else if (leftover_bits) { + uint8_t b1 = a1[bytes] >> (8-leftover_bits); + uint8_t b2 = a2[bytes] >> (8-leftover_bits); + return TRISTATE(b1, b2); + } else { + return 0; + } + } + default: + tor_fragile_assert(); + return 0; + } + } else if (how == CMP_EXACT) { + /* Unequal families and an exact comparison? Stop now! */ + return TRISTATE(family1, family2); + } + + if (mbits == 0) + return 0; + + if (family1 == AF_INET6 && tor_addr_is_v4(addr1)) + v_family1 = AF_INET; + if (family2 == AF_INET6 && tor_addr_is_v4(addr2)) + v_family2 = AF_INET; + if (v_family1 == v_family2) { + /* One or both addresses are a mapped ipv4 address. */ + uint32_t a1, a2; + if (family1 == AF_INET6) { + a1 = tor_addr_to_mapped_ipv4h(addr1); + if (mbits <= 96) + return 0; + mbits -= 96; /* We just decided that the first 96 bits of a1 "match". */ + } else { + a1 = tor_addr_to_ipv4h(addr1); + } + if (family2 == AF_INET6) { + a2 = tor_addr_to_mapped_ipv4h(addr2); + } else { + a2 = tor_addr_to_ipv4h(addr2); + } + if (mbits <= 0) return 0; + if (mbits > 32) mbits = 32; + a1 >>= (32-mbits); + a2 >>= (32-mbits); + return TRISTATE(a1, a2); + } else { + /* Unequal families, and semantic comparison, and no semantic family + * matches. */ + return TRISTATE(family1, family2); + } +} + +/** Return a hash code based on the address addr */ +unsigned int +tor_addr_hash(const tor_addr_t *addr) +{ + switch (tor_addr_family(addr)) { + case AF_INET: + return tor_addr_to_ipv4h(addr); + case AF_UNSPEC: + return 0x4e4d5342; + case AF_INET6: { + const uint32_t *u = tor_addr_to_in6_addr32(addr); + return u[0] + u[1] + u[2] + u[3]; + } + default: + tor_fragile_assert(); + return 0; + } +} + +/** Return a newly allocated string with a representation of addr. */ +char * +tor_dup_addr(const tor_addr_t *addr) +{ + char buf[TOR_ADDR_BUF_LEN]; + if (tor_addr_to_str(buf, addr, sizeof(buf), 0)) { + return tor_strdup(buf); + } else { + return tor_strdup(""); + } +} + +/** Return a string representing the address addr. This string + * is statically allocated, and must not be freed. Each call to + * fmt_addr_impl invalidates the last result of the function. + * This function is not thread-safe. If decorate is set, add + * brackets to IPv6 addresses. + * + * It's better to use the wrapper macros of this function: + * fmt_addr() and fmt_and_decorate_addr(). + */ +const char * +fmt_addr_impl(const tor_addr_t *addr, int decorate) +{ + static char buf[TOR_ADDR_BUF_LEN]; + if (!addr) return ""; + if (tor_addr_to_str(buf, addr, sizeof(buf), decorate)) + return buf; + else + return "???"; +} + +/** Return a string representing the pair addr and port. + * This calls fmt_and_decorate_addr internally, so IPv6 addresses will + * have brackets, and the caveats of fmt_addr_impl apply. + */ +const char * +fmt_addrport(const tor_addr_t *addr, uint16_t port) +{ + /* Add space for a colon and up to 5 digits. */ + static char buf[TOR_ADDR_BUF_LEN + 6]; + tor_snprintf(buf, sizeof(buf), "%s:%u", fmt_and_decorate_addr(addr), port); + return buf; +} + +/** Like fmt_addr(), but takes addr as a host-order IPv4 + * addresses. Also not thread-safe, also clobbers its return buffer on + * repeated calls. */ +const char * +fmt_addr32(uint32_t addr) +{ + static char buf[INET_NTOA_BUF_LEN]; + struct in_addr in; + in.s_addr = htonl(addr); + tor_inet_ntoa(&in, buf, sizeof(buf)); + return buf; +} + +/** Convert the string in src to a tor_addr_t addr. The string + * may be an IPv4 address, an IPv6 address, or an IPv6 address surrounded by + * square brackets. + * + * Return an address family on success, or -1 if an invalid address string is + * provided. */ +int +tor_addr_parse(tor_addr_t *addr, const char *src) +{ + char *tmp = NULL; /* Holds substring if we got a dotted quad. */ + int result; + struct in_addr in_tmp; + struct in6_addr in6_tmp; + tor_assert(addr && src); + if (src[0] == '[' && src[1]) + src = tmp = tor_strndup(src+1, strlen(src)-2); + + if (tor_inet_pton(AF_INET6, src, &in6_tmp) > 0) { + result = AF_INET6; + tor_addr_from_in6(addr, &in6_tmp); + } else if (tor_inet_pton(AF_INET, src, &in_tmp) > 0) { + result = AF_INET; + tor_addr_from_in(addr, &in_tmp); + } else { + result = -1; + } + + tor_free(tmp); + return result; +} + +/** Parse an address or address-port combination from s, resolve the + * address as needed, and put the result in addr_out and (optionally) + * port_out. Return 0 on success, negative on failure. */ +int +tor_addr_port_lookup(const char *s, tor_addr_t *addr_out, uint16_t *port_out) +{ + const char *port; + tor_addr_t addr; + uint16_t portval; + char *tmp = NULL; + + tor_assert(s); + tor_assert(addr_out); + + s = eat_whitespace(s); + + if (*s == '[') { + port = strstr(s, "]"); + if (!port) + goto err; + tmp = tor_strndup(s+1, port-(s+1)); + port = port+1; + if (*port == ':') + port++; + else + port = NULL; + } else { + port = strchr(s, ':'); + if (port) + tmp = tor_strndup(s, port-s); + else + tmp = tor_strdup(s); + if (port) + ++port; + } + + if (tor_addr_lookup(tmp, AF_UNSPEC, &addr) != 0) + goto err; + tor_free(tmp); + + if (port) { + portval = (int) tor_parse_long(port, 10, 1, 65535, NULL, NULL); + if (!portval) + goto err; + } else { + portval = 0; + } + + if (port_out) + *port_out = portval; + tor_addr_copy(addr_out, &addr); + + return 0; + err: + tor_free(tmp); + return -1; +} + +#ifdef _WIN32 +typedef ULONG (WINAPI *GetAdaptersAddresses_fn_t)( + ULONG, ULONG, PVOID, PIP_ADAPTER_ADDRESSES, PULONG); +#endif + +/** Try to ask our network interfaces what addresses they are bound to. + * Return a new smartlist of tor_addr_t on success, and NULL on failure. + * (An empty smartlist indicates that we successfully learned that we have no + * addresses.) Log failure messages at severity. */ +static smartlist_t * +get_interface_addresses_raw(int severity) +{ +#if defined(HAVE_GETIFADDRS) + /* Most free Unixy systems provide getifaddrs, which gives us a linked list + * of struct ifaddrs. */ + struct ifaddrs *ifa = NULL; + const struct ifaddrs *i; + smartlist_t *result; + if (getifaddrs(&ifa) < 0) { + log_fn(severity, LD_NET, "Unable to call getifaddrs(): %s", + strerror(errno)); + return NULL; + } + + result = smartlist_new(); + for (i = ifa; i; i = i->ifa_next) { + tor_addr_t tmp; + if ((i->ifa_flags & (IFF_UP | IFF_RUNNING)) != (IFF_UP | IFF_RUNNING)) + continue; + if (!i->ifa_addr) + continue; + if (i->ifa_addr->sa_family != AF_INET && + i->ifa_addr->sa_family != AF_INET6) + continue; + if (tor_addr_from_sockaddr(&tmp, i->ifa_addr, NULL) < 0) + continue; + smartlist_add(result, tor_memdup(&tmp, sizeof(tmp))); + } + + freeifaddrs(ifa); + return result; +#elif defined(_WIN32) + /* Windows XP began to provide GetAdaptersAddresses. Windows 2000 had a + "GetAdaptersInfo", but that's deprecated; let's just try + GetAdaptersAddresses and fall back to connect+getsockname. + */ + HANDLE lib = load_windows_system_library(TEXT("iphlpapi.dll")); + smartlist_t *result = NULL; + GetAdaptersAddresses_fn_t fn; + ULONG size, res; + IP_ADAPTER_ADDRESSES *addresses = NULL, *address; + + (void) severity; + +#define FLAGS (GAA_FLAG_SKIP_ANYCAST | \ + GAA_FLAG_SKIP_MULTICAST | \ + GAA_FLAG_SKIP_DNS_SERVER) + + if (!lib) { + log_fn(severity, LD_NET, "Unable to load iphlpapi.dll"); + goto done; + } + + if (!(fn = (GetAdaptersAddresses_fn_t) + GetProcAddress(lib, "GetAdaptersAddresses"))) { + log_fn(severity, LD_NET, "Unable to obtain pointer to " + "GetAdaptersAddresses"); + goto done; + } + + /* Guess how much space we need. */ + size = 15*1024; + addresses = tor_malloc(size); + res = fn(AF_UNSPEC, FLAGS, NULL, addresses, &size); + if (res == ERROR_BUFFER_OVERFLOW) { + /* we didn't guess that we needed enough space; try again */ + tor_free(addresses); + addresses = tor_malloc(size); + res = fn(AF_UNSPEC, FLAGS, NULL, addresses, &size); + } + if (res != NO_ERROR) { + log_fn(severity, LD_NET, "GetAdaptersAddresses failed (result: %lu)", res); + goto done; + } + + result = smartlist_new(); + for (address = addresses; address; address = address->Next) { + IP_ADAPTER_UNICAST_ADDRESS *a; + for (a = address->FirstUnicastAddress; a; a = a->Next) { + /* Yes, it's a linked list inside a linked list */ + struct sockaddr *sa = a->Address.lpSockaddr; + tor_addr_t tmp; + if (sa->sa_family != AF_INET && sa->sa_family != AF_INET6) + continue; + if (tor_addr_from_sockaddr(&tmp, sa, NULL) < 0) + continue; + smartlist_add(result, tor_memdup(&tmp, sizeof(tmp))); + } + } + + done: + if (lib) + FreeLibrary(lib); + tor_free(addresses); + return result; +#elif defined(SIOCGIFCONF) && defined(HAVE_IOCTL) + /* Some older unixy systems make us use ioctl(SIOCGIFCONF) */ + struct ifconf ifc; + int fd, i, sz, n; + smartlist_t *result = NULL; + /* This interface, AFAICT, only supports AF_INET addresses */ + fd = socket(AF_INET, SOCK_DGRAM, 0); + if (fd < 0) { + tor_log(severity, LD_NET, "socket failed: %s", strerror(errno)); + goto done; + } + /* Guess how much space we need. */ + ifc.ifc_len = sz = 15*1024; + ifc.ifc_ifcu.ifcu_req = tor_malloc(sz); + if (ioctl(fd, SIOCGIFCONF, &ifc) < 0) { + tor_log(severity, LD_NET, "ioctl failed: %s", strerror(errno)); + close(fd); + goto done; + } + close(fd); + result = smartlist_new(); + if (ifc.ifc_len < sz) + sz = ifc.ifc_len; + n = sz / sizeof(struct ifreq); + for (i = 0; i < n ; ++i) { + struct ifreq *r = &ifc.ifc_ifcu.ifcu_req[i]; + struct sockaddr *sa = &r->ifr_addr; + tor_addr_t tmp; + if (sa->sa_family != AF_INET && sa->sa_family != AF_INET6) + continue; /* should be impossible */ + if (tor_addr_from_sockaddr(&tmp, sa, NULL) < 0) + continue; + smartlist_add(result, tor_memdup(&tmp, sizeof(tmp))); + } + done: + tor_free(ifc.ifc_ifcu.ifcu_req); + return result; +#else + (void) severity; + return NULL; +#endif +} + +/** Return true iff a is a multicast address. */ +static int +tor_addr_is_multicast(const tor_addr_t *a) +{ + sa_family_t family = tor_addr_family(a); + if (family == AF_INET) { + uint32_t ipv4h = tor_addr_to_ipv4h(a); + if ((ipv4h >> 24) == 0xe0) + return 1; /* Multicast */ + } else if (family == AF_INET6) { + const uint8_t *a32 = tor_addr_to_in6_addr8(a); + if (a32[0] == 0xff) + return 1; + } + return 0; +} + +/** Set *addr to the IP address (if any) of whatever interface + * connects to the Internet. This address should only be used in checking + * whether our address has changed. Return 0 on success, -1 on failure. + */ +int +get_interface_address6(int severity, sa_family_t family, tor_addr_t *addr) +{ + /* XXX really, this function should yield a smartlist of addresses. */ + smartlist_t *addrs; + int sock=-1, r=-1; + struct sockaddr_storage my_addr, target_addr; + socklen_t addr_len; + tor_assert(addr); + + /* Try to do this the smart way if possible. */ + if ((addrs = get_interface_addresses_raw(severity))) { + int rv = -1; + SMARTLIST_FOREACH_BEGIN(addrs, tor_addr_t *, a) { + if (family != AF_UNSPEC && family != tor_addr_family(a)) + continue; + if (tor_addr_is_loopback(a) || + tor_addr_is_multicast(a)) + continue; + + tor_addr_copy(addr, a); + rv = 0; + + /* If we found a non-internal address, declare success. Otherwise, + * keep looking. */ + if (!tor_addr_is_internal(a, 0)) + break; + } SMARTLIST_FOREACH_END(a); + + SMARTLIST_FOREACH(addrs, tor_addr_t *, a, tor_free(a)); + smartlist_free(addrs); + return rv; + } + + /* Okay, the smart way is out. */ + memset(addr, 0, sizeof(tor_addr_t)); + memset(&target_addr, 0, sizeof(target_addr)); + /* Don't worry: no packets are sent. We just need to use a real address + * on the actual Internet. */ + if (family == AF_INET6) { + struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)&target_addr; + /* Use the "discard" service port */ + sin6->sin6_port = htons(9); + sock = tor_open_socket(PF_INET6,SOCK_DGRAM,IPPROTO_UDP); + addr_len = (socklen_t)sizeof(struct sockaddr_in6); + sin6->sin6_family = AF_INET6; + S6_ADDR16(sin6->sin6_addr)[0] = htons(0x2002); /* 2002:: */ + } else if (family == AF_INET) { + struct sockaddr_in *sin = (struct sockaddr_in*)&target_addr; + /* Use the "discard" service port */ + sin->sin_port = htons(9); + sock = tor_open_socket(PF_INET,SOCK_DGRAM,IPPROTO_UDP); + addr_len = (socklen_t)sizeof(struct sockaddr_in); + sin->sin_family = AF_INET; + sin->sin_addr.s_addr = htonl(0x12000001); /* 18.0.0.1 */ + } else { + return -1; + } + if (sock < 0) { + int e = tor_socket_errno(-1); + log_fn(severity, LD_NET, "unable to create socket: %s", + tor_socket_strerror(e)); + goto err; + } + + if (connect(sock,(struct sockaddr *)&target_addr, addr_len) < 0) { + int e = tor_socket_errno(sock); + log_fn(severity, LD_NET, "connect() failed: %s", tor_socket_strerror(e)); + goto err; + } + + if (getsockname(sock,(struct sockaddr*)&my_addr, &addr_len)) { + int e = tor_socket_errno(sock); + log_fn(severity, LD_NET, "getsockname() to determine interface failed: %s", + tor_socket_strerror(e)); + goto err; + } + + tor_addr_from_sockaddr(addr, (struct sockaddr*)&my_addr, NULL); + r=0; + err: + if (sock >= 0) + tor_close_socket(sock); + return r; +} + +/* ====== + * IPv4 helpers + * XXXX024 IPv6 deprecate some of these. + */ + +/** Return true iff ip (in host order) is an IP reserved to localhost, + * or reserved for local networks by RFC 1918. + */ +int +is_internal_IP(uint32_t ip, int for_listening) +{ + tor_addr_t myaddr; + myaddr.family = AF_INET; + myaddr.addr.in_addr.s_addr = htonl(ip); + + return tor_addr_is_internal(&myaddr, for_listening); +} + +/** Given an address of the form "ip:port", try to divide it into its + * ip and port portions, setting *address_out to a newly + * allocated string holding the address portion and *port_out + * to the port. + * + * Don't do DNS lookups and don't allow domain names in the field. + * Don't accept addrport of the form "" or ":0". + * + * Return 0 on success, -1 on failure. */ +int +tor_addr_port_parse(int severity, const char *addrport, + tor_addr_t *address_out, uint16_t *port_out) +{ + int retval = -1; + int r; + char *addr_tmp = NULL; + + tor_assert(addrport); + tor_assert(address_out); + tor_assert(port_out); + + r = tor_addr_port_split(severity, addrport, &addr_tmp, port_out); + if (r < 0) + goto done; + + if (!*port_out) + goto done; + + /* make sure that address_out is an IP address */ + if (tor_addr_parse(address_out, addr_tmp) < 0) + goto done; + + retval = 0; + + done: + tor_free(addr_tmp); + return retval; +} + +/** Given an address of the form "host[:port]", try to divide it into its host + * ane port portions, setting *address_out to a newly allocated string + * holding the address portion and *port_out to the port (or 0 if no + * port is given). Return 0 on success, -1 on failure. */ +int +tor_addr_port_split(int severity, const char *addrport, + char **address_out, uint16_t *port_out) +{ + tor_assert(addrport); + tor_assert(address_out); + tor_assert(port_out); + return addr_port_lookup(severity, addrport, address_out, NULL, port_out); +} + +/** Parse a string of the form "host[:port]" from addrport. If + * address is provided, set *address to a copy of the + * host portion of the string. If addr is provided, try to + * resolve the host portion of the string and store it into + * *addr (in host byte order). If port_out is provided, + * store the port number into *port_out, or 0 if no port is given. + * If port_out is NULL, then there must be no port number in + * addrport. + * Return 0 on success, -1 on failure. + */ +int +addr_port_lookup(int severity, const char *addrport, char **address, + uint32_t *addr, uint16_t *port_out) +{ + const char *colon; + char *address_ = NULL; + int port_; + int ok = 1; + + tor_assert(addrport); + + colon = strrchr(addrport, ':'); + if (colon) { + address_ = tor_strndup(addrport, colon-addrport); + port_ = (int) tor_parse_long(colon+1,10,1,65535,NULL,NULL); + if (!port_) { + log_fn(severity, LD_GENERAL, "Port %s out of range", escaped(colon+1)); + ok = 0; + } + if (!port_out) { + char *esc_addrport = esc_for_log(addrport); + log_fn(severity, LD_GENERAL, + "Port %s given on %s when not required", + escaped(colon+1), esc_addrport); + tor_free(esc_addrport); + ok = 0; + } + } else { + address_ = tor_strdup(addrport); + port_ = 0; + } + + if (addr) { + /* There's an addr pointer, so we need to resolve the hostname. */ + if (tor_lookup_hostname(address_,addr)) { + log_fn(severity, LD_NET, "Couldn't look up %s", escaped(address_)); + ok = 0; + *addr = 0; + } + } + + if (address && ok) { + *address = address_; + } else { + if (address) + *address = NULL; + tor_free(address_); + } + if (port_out) + *port_out = ok ? ((uint16_t) port_) : 0; + + return ok ? 0 : -1; +} + +/** If mask is an address mask for a bit-prefix, return the number of + * bits. Otherwise, return -1. */ +int +addr_mask_get_bits(uint32_t mask) +{ + int i; + if (mask == 0) + return 0; + if (mask == 0xFFFFFFFFu) + return 32; + for (i=0; i<=32; ++i) { + if (mask == (uint32_t) ~((1u<<(32-i))-1)) { + return i; + } + } + return -1; +} + +/** Parse a string s in the format of (*|port(-maxport)?)?, setting the + * various *out pointers as appropriate. Return 0 on success, -1 on failure. + */ +int +parse_port_range(const char *port, uint16_t *port_min_out, + uint16_t *port_max_out) +{ + int port_min, port_max, ok; + tor_assert(port_min_out); + tor_assert(port_max_out); + + if (!port || *port == '\0' || strcmp(port, "*") == 0) { + port_min = 1; + port_max = 65535; + } else { + char *endptr = NULL; + port_min = (int)tor_parse_long(port, 10, 0, 65535, &ok, &endptr); + if (!ok) { + log_warn(LD_GENERAL, + "Malformed port %s on address range; rejecting.", + escaped(port)); + return -1; + } else if (endptr && *endptr == '-') { + port = endptr+1; + endptr = NULL; + port_max = (int)tor_parse_long(port, 10, 1, 65535, &ok, &endptr); + if (!ok) { + log_warn(LD_GENERAL, + "Malformed port %s on address range; rejecting.", + escaped(port)); + return -1; + } + } else { + port_max = port_min; + } + if (port_min > port_max) { + log_warn(LD_GENERAL, "Insane port range on address policy; rejecting."); + return -1; + } + } + + if (port_min < 1) + port_min = 1; + if (port_max > 65535) + port_max = 65535; + + *port_min_out = (uint16_t) port_min; + *port_max_out = (uint16_t) port_max; + + return 0; +} + +/** Given an IPv4 in_addr struct *in (in network order, as usual), + * write it as a string into the buf_len-byte buffer in + * buf. + */ +int +tor_inet_ntoa(const struct in_addr *in, char *buf, size_t buf_len) +{ + uint32_t a = ntohl(in->s_addr); + return tor_snprintf(buf, buf_len, "%d.%d.%d.%d", + (int)(uint8_t)((a>>24)&0xff), + (int)(uint8_t)((a>>16)&0xff), + (int)(uint8_t)((a>>8 )&0xff), + (int)(uint8_t)((a )&0xff)); +} + +/** Given a host-order addr, call tor_inet_ntop() on it + * and return a strdup of the resulting address. + */ +char * +tor_dup_ip(uint32_t addr) +{ + char buf[TOR_ADDR_BUF_LEN]; + struct in_addr in; + + in.s_addr = htonl(addr); + tor_inet_ntop(AF_INET, &in, buf, sizeof(buf)); + return tor_strdup(buf); +} + +/** + * Set *addr to the host-order IPv4 address (if any) of whatever + * interface connects to the Internet. This address should only be used in + * checking whether our address has changed. Return 0 on success, -1 on + * failure. + */ +int +get_interface_address(int severity, uint32_t *addr) +{ + tor_addr_t local_addr; + int r; + + r = get_interface_address6(severity, AF_INET, &local_addr); + if (r>=0) + *addr = tor_addr_to_ipv4h(&local_addr); + return r; +} + +/** Return true if we can tell that name is a canonical name for the + * loopback address. */ +int +tor_addr_hostname_is_local(const char *name) +{ + return !strcasecmp(name, "localhost") || + !strcasecmp(name, "local") || + !strcasecmpend(name, ".local"); +} + +/** Return a newly allocated tor_addr_port_t with addr and + port filled in. */ +tor_addr_port_t * +tor_addr_port_new(const tor_addr_t *addr, uint16_t port) +{ + tor_addr_port_t *ap = tor_malloc_zero(sizeof(tor_addr_port_t)); + if (addr) + tor_addr_copy(&ap->addr, addr); + ap->port = port; + return ap; +} + diff --git a/src/tor/address.h b/src/tor/address.h new file mode 100644 index 0000000..87909a3 --- /dev/null +++ b/src/tor/address.h @@ -0,0 +1,232 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file address.h + * \brief Headers for address.h + **/ + +#ifndef TOR_ADDRESS_H +#define TOR_ADDRESS_H + +#include "orconfig.h" +#include "torint.h" +#include "tor_compat.h" + +/** The number of bits from an address to consider while doing a masked + * comparison. */ +typedef uint8_t maskbits_t; + +struct in_addr; +/** Holds an IPv4 or IPv6 address. (Uses less memory than struct + * sockaddr_storage.) */ +typedef struct tor_addr_t +{ + sa_family_t family; + union { + uint32_t dummy_; /* This field is here so we have something to initialize + * with a reliable cross-platform type. */ + struct in_addr in_addr; + struct in6_addr in6_addr; + } addr; +} tor_addr_t; + +/** Holds an IP address and a TCP/UDP port. */ +typedef struct tor_addr_port_t +{ + tor_addr_t addr; + uint16_t port; +} tor_addr_port_t; + +#define TOR_ADDR_NULL {AF_UNSPEC, {0}} + +static INLINE const struct in6_addr *tor_addr_to_in6(const tor_addr_t *a); +static INLINE uint32_t tor_addr_to_ipv4n(const tor_addr_t *a); +static INLINE uint32_t tor_addr_to_ipv4h(const tor_addr_t *a); +static INLINE uint32_t tor_addr_to_mapped_ipv4h(const tor_addr_t *a); +static INLINE sa_family_t tor_addr_family(const tor_addr_t *a); +static INLINE const struct in_addr *tor_addr_to_in(const tor_addr_t *a); +static INLINE int tor_addr_eq_ipv4h(const tor_addr_t *a, uint32_t u); + +socklen_t tor_addr_to_sockaddr(const tor_addr_t *a, uint16_t port, + struct sockaddr *sa_out, socklen_t len); +int tor_addr_from_sockaddr(tor_addr_t *a, const struct sockaddr *sa, + uint16_t *port_out); +void tor_addr_make_unspec(tor_addr_t *a); +void tor_addr_make_null(tor_addr_t *a, sa_family_t family); +char *tor_sockaddr_to_str(const struct sockaddr *sa); + +/** Return an in6_addr* equivalent to a, or NULL if a is not + * an IPv6 address. */ +static INLINE const struct in6_addr * +tor_addr_to_in6(const tor_addr_t *a) +{ + return a->family == AF_INET6 ? &a->addr.in6_addr : NULL; +} + +/** Given an IPv6 address x, yield it as an array of uint8_t. + * + * Requires that x is actually an IPv6 address. + */ +#define tor_addr_to_in6_addr8(x) tor_addr_to_in6(x)->s6_addr +/** Given an IPv6 address x, yield it as an array of uint16_t. + * + * Requires that x is actually an IPv6 address. + */ +#define tor_addr_to_in6_addr16(x) S6_ADDR16(*tor_addr_to_in6(x)) +/** Given an IPv6 address x, yield it as an array of uint32_t. + * + * Requires that x is actually an IPv6 address. + */ +#define tor_addr_to_in6_addr32(x) S6_ADDR32(*tor_addr_to_in6(x)) + +/** Return an IPv4 address in network order for a, or 0 if + * a is not an IPv4 address. */ +static INLINE uint32_t +tor_addr_to_ipv4n(const tor_addr_t *a) +{ + return a->family == AF_INET ? a->addr.in_addr.s_addr : 0; +} +/** Return an IPv4 address in host order for a, or 0 if + * a is not an IPv4 address. */ +static INLINE uint32_t +tor_addr_to_ipv4h(const tor_addr_t *a) +{ + return ntohl(tor_addr_to_ipv4n(a)); +} +/** Given an IPv6 address, return its mapped IPv4 address in host order, or + * 0 if a is not an IPv6 address. + * + * (Does not check whether the address is really a mapped address */ +static INLINE uint32_t +tor_addr_to_mapped_ipv4h(const tor_addr_t *a) +{ + return a->family == AF_INET6 ? ntohl(tor_addr_to_in6_addr32(a)[3]) : 0; +} +/** Return the address family of a. Possible values are: + * AF_INET6, AF_INET, AF_UNSPEC. */ +static INLINE sa_family_t +tor_addr_family(const tor_addr_t *a) +{ + return a->family; +} +/** Return an in_addr* equivalent to a, or NULL if a is not + * an IPv4 address. */ +static INLINE const struct in_addr * +tor_addr_to_in(const tor_addr_t *a) +{ + return a->family == AF_INET ? &a->addr.in_addr : NULL; +} +/** Return true iff a is an IPv4 address equal to the host-ordered + * address in u. */ +static INLINE int +tor_addr_eq_ipv4h(const tor_addr_t *a, uint32_t u) +{ + return a->family == AF_INET ? (tor_addr_to_ipv4h(a) == u) : 0; +} + +/** Length of a buffer that you need to allocate to be sure you can encode + * any tor_addr_t. + * + * This allows enough space for + * "[ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255]", + * plus a terminating NUL. + */ +#define TOR_ADDR_BUF_LEN 48 + +int tor_addr_lookup(const char *name, uint16_t family, tor_addr_t *addr_out); +char *tor_dup_addr(const tor_addr_t *addr) ATTR_MALLOC; + +/** Wrapper function of fmt_addr_impl(). It does not decorate IPv6 + * addresses. */ +#define fmt_addr(a) fmt_addr_impl((a), 0) +/** Wrapper function of fmt_addr_impl(). It decorates IPv6 + * addresses. */ +#define fmt_and_decorate_addr(a) fmt_addr_impl((a), 1) +const char *fmt_addr_impl(const tor_addr_t *addr, int decorate); +const char *fmt_addrport(const tor_addr_t *addr, uint16_t port); +const char * fmt_addr32(uint32_t addr); +int get_interface_address6(int severity, sa_family_t family, tor_addr_t *addr); + +/** Flag to specify how to do a comparison between addresses. In an "exact" + * comparison, addresses are equivalent only if they are in the same family + * with the same value. In a "semantic" comparison, IPv4 addresses match all + * IPv6 encodings of those addresses. */ +typedef enum { + CMP_EXACT, + CMP_SEMANTIC, +} tor_addr_comparison_t; + +int tor_addr_compare(const tor_addr_t *addr1, const tor_addr_t *addr2, + tor_addr_comparison_t how); +int tor_addr_compare_masked(const tor_addr_t *addr1, const tor_addr_t *addr2, + maskbits_t mask, tor_addr_comparison_t how); +/** Return true iff a and b are the same address. The comparison is done + * "exactly". */ +#define tor_addr_eq(a,b) (0==tor_addr_compare((a),(b),CMP_EXACT)) + +unsigned int tor_addr_hash(const tor_addr_t *addr); +int tor_addr_is_v4(const tor_addr_t *addr); +int tor_addr_is_internal_(const tor_addr_t *ip, int for_listening, + const char *filename, int lineno); +#define tor_addr_is_internal(addr, for_listening) \ + tor_addr_is_internal_((addr), (for_listening), SHORT_FILE__, __LINE__) + +/** Longest length that can be required for a reverse lookup name. */ +/* 32 nybbles, 32 dots, 8 characters of "ip6.arpa", 1 NUL: 73 characters. */ +#define REVERSE_LOOKUP_NAME_BUF_LEN 73 +int tor_addr_to_PTR_name(char *out, size_t outlen, + const tor_addr_t *addr); +int tor_addr_parse_PTR_name(tor_addr_t *result, const char *address, + int family, int accept_regular); + +int tor_addr_port_lookup(const char *s, tor_addr_t *addr_out, + uint16_t *port_out); +#define TAPMP_EXTENDED_STAR 1 +int tor_addr_parse_mask_ports(const char *s, unsigned flags, + tor_addr_t *addr_out, maskbits_t *mask_out, + uint16_t *port_min_out, uint16_t *port_max_out); +const char * tor_addr_to_str(char *dest, const tor_addr_t *addr, size_t len, + int decorate); +int tor_addr_parse(tor_addr_t *addr, const char *src); +void tor_addr_copy(tor_addr_t *dest, const tor_addr_t *src); +void tor_addr_from_ipv4n(tor_addr_t *dest, uint32_t v4addr); +/** Set dest to the IPv4 address encoded in v4addr in host + * order. */ +#define tor_addr_from_ipv4h(dest, v4addr) \ + tor_addr_from_ipv4n((dest), htonl(v4addr)) +void tor_addr_from_ipv6_bytes(tor_addr_t *dest, const char *bytes); +/** Set dest to the IPv4 address incoded in in. */ +#define tor_addr_from_in(dest, in) \ + tor_addr_from_ipv4n((dest), (in)->s_addr); +void tor_addr_from_in6(tor_addr_t *dest, const struct in6_addr *in6); +int tor_addr_is_null(const tor_addr_t *addr); +int tor_addr_is_loopback(const tor_addr_t *addr); + +int tor_addr_port_split(int severity, const char *addrport, + char **address_out, uint16_t *port_out); + +int tor_addr_port_parse(int severity, const char *addrport, + tor_addr_t *address_out, uint16_t *port_out); + +int tor_addr_hostname_is_local(const char *name); + +/* IPv4 helpers */ +int is_internal_IP(uint32_t ip, int for_listening); +int addr_port_lookup(int severity, const char *addrport, char **address, + uint32_t *addr, uint16_t *port_out); +int parse_port_range(const char *port, uint16_t *port_min_out, + uint16_t *port_max_out); +int addr_mask_get_bits(uint32_t mask); +/** Length of a buffer to allocate to hold the results of tor_inet_ntoa.*/ +#define INET_NTOA_BUF_LEN 16 +int tor_inet_ntoa(const struct in_addr *in, char *buf, size_t buf_len); +char *tor_dup_ip(uint32_t addr) ATTR_MALLOC; +int get_interface_address(int severity, uint32_t *addr); + +tor_addr_port_t *tor_addr_port_new(const tor_addr_t *addr, uint16_t port); + +#endif + diff --git a/src/tor/addressmap.c b/src/tor/addressmap.c new file mode 100644 index 0000000..9bc79bd --- /dev/null +++ b/src/tor/addressmap.c @@ -0,0 +1,1078 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#define ADDRESSMAP_PRIVATE + +#include "or.h" +#include "addressmap.h" +#include "circuituse.h" +#include "config.h" +#include "connection_edge.h" +#include "control.h" +#include "dns.h" +#include "routerset.h" +#include "nodelist.h" + +/** A client-side struct to remember requests to rewrite addresses + * to new addresses. These structs are stored in the hash table + * "addressmap" below. + * + * There are 5 ways to set an address mapping: + * - A MapAddress command from the controller [permanent] + * - An AddressMap directive in the torrc [permanent] + * - When a TrackHostExits torrc directive is triggered [temporary] + * - When a DNS resolve succeeds [temporary] + * - When a DNS resolve fails [temporary] + * + * When an addressmap request is made but one is already registered, + * the new one is replaced only if the currently registered one has + * no "new_address" (that is, it's in the process of DNS resolve), + * or if the new one is permanent (expires==0 or 1). + * + * (We overload the 'expires' field, using "0" for mappings set via + * the configuration file, "1" for mappings set from the control + * interface, and other values for DNS and TrackHostExit mappings that can + * expire.) + * + * A mapping may be 'wildcarded'. If "src_wildcard" is true, then + * any address that ends with a . followed by the key for this entry will + * get remapped by it. If "dst_wildcard" is also true, then only the + * matching suffix of such addresses will get replaced by new_address. + */ +typedef struct { + char *new_address; + time_t expires; + ENUM_BF(addressmap_entry_source_t) source:3; + unsigned src_wildcard:1; + unsigned dst_wildcard:1; + short num_resolve_failures; +} addressmap_entry_t; + +/** Entry for mapping addresses to which virtual address we mapped them to. */ +typedef struct { + char *ipv4_address; + char *ipv6_address; + char *hostname_address; +} virtaddress_entry_t; + +/** A hash table to store client-side address rewrite instructions. */ +static strmap_t *addressmap=NULL; + +/** + * Table mapping addresses to which virtual address, if any, we + * assigned them to. + * + * We maintain the following invariant: if [A,B] is in + * virtaddress_reversemap, then B must be a virtual address, and [A,B] + * must be in addressmap. We do not require that the converse hold: + * if it fails, then we could end up mapping two virtual addresses to + * the same address, which is no disaster. + **/ +static strmap_t *virtaddress_reversemap=NULL; + +/** Initialize addressmap. */ +void +addressmap_init(void) +{ + addressmap = strmap_new(); + virtaddress_reversemap = strmap_new(); +} + +/** Free the memory associated with the addressmap entry _ent. */ +static void +addressmap_ent_free(void *_ent) +{ + addressmap_entry_t *ent; + if (!_ent) + return; + + ent = _ent; + tor_free(ent->new_address); + tor_free(ent); +} + +/** Free storage held by a virtaddress_entry_t* entry in ent. */ +static void +addressmap_virtaddress_ent_free(void *_ent) +{ + virtaddress_entry_t *ent; + if (!_ent) + return; + + ent = _ent; + tor_free(ent->ipv4_address); + tor_free(ent->hostname_address); + tor_free(ent); +} + +/** Free storage held by a virtaddress_entry_t* entry in ent. */ +static void +addressmap_virtaddress_remove(const char *address, addressmap_entry_t *ent) +{ + if (ent && ent->new_address && + address_is_in_virtual_range(ent->new_address)) { + virtaddress_entry_t *ve = + strmap_get(virtaddress_reversemap, ent->new_address); + /*log_fn(LOG_NOTICE,"remove reverse mapping for %s",ent->new_address);*/ + if (ve) { + if (!strcmp(address, ve->ipv4_address)) + tor_free(ve->ipv4_address); + if (!strcmp(address, ve->hostname_address)) + tor_free(ve->hostname_address); + if (!ve->ipv4_address && !ve->hostname_address) { + tor_free(ve); + strmap_remove(virtaddress_reversemap, ent->new_address); + } + } + } +} + +/** Remove ent (which must be mapped to by address) from the + * client address maps. */ +static void +addressmap_ent_remove(const char *address, addressmap_entry_t *ent) +{ + addressmap_virtaddress_remove(address, ent); + addressmap_ent_free(ent); +} + +/** Unregister all TrackHostExits mappings from any address to + * *.exitname.exit. */ +void +clear_trackexithost_mappings(const char *exitname) +{ + char *suffix = NULL; + if (!addressmap || !exitname) + return; + tor_asprintf(&suffix, ".%s.exit", exitname); + tor_strlower(suffix); + + STRMAP_FOREACH_MODIFY(addressmap, address, addressmap_entry_t *, ent) { + if (ent->source == ADDRMAPSRC_TRACKEXIT && + !strcmpend(ent->new_address, suffix)) { + addressmap_ent_remove(address, ent); + MAP_DEL_CURRENT(address); + } + } STRMAP_FOREACH_END; + + tor_free(suffix); +} + +/** Remove all TRACKEXIT mappings from the addressmap for which the target + * host is unknown or no longer allowed, or for which the source address + * is no longer in trackexithosts. */ +void +addressmap_clear_excluded_trackexithosts(const or_options_t *options) +{ + const routerset_t *allow_nodes = options->ExitNodes; + const routerset_t *exclude_nodes = options->ExcludeExitNodesUnion_; + + if (!addressmap) + return; + if (routerset_is_empty(allow_nodes)) + allow_nodes = NULL; + if (allow_nodes == NULL && routerset_is_empty(exclude_nodes)) + return; + + STRMAP_FOREACH_MODIFY(addressmap, address, addressmap_entry_t *, ent) { + size_t len; + const char *target = ent->new_address, *dot; + char *nodename; + const node_t *node; + + if (!target) { + /* DNS resolving in progress */ + continue; + } else if (strcmpend(target, ".exit")) { + /* Not a .exit mapping */ + continue; + } else if (ent->source != ADDRMAPSRC_TRACKEXIT) { + /* Not a trackexit mapping. */ + continue; + } + len = strlen(target); + if (len < 6) + continue; /* malformed. */ + dot = target + len - 6; /* dot now points to just before .exit */ + while (dot > target && *dot != '.') + dot--; + if (*dot == '.') dot++; + nodename = tor_strndup(dot, len-5-(dot-target));; + node = node_get_by_nickname(nodename, 0); + tor_free(nodename); + if (!node || + (allow_nodes && !routerset_contains_node(allow_nodes, node)) || + routerset_contains_node(exclude_nodes, node) || + !hostname_in_track_host_exits(options, address)) { + /* We don't know this one, or we want to be rid of it. */ + addressmap_ent_remove(address, ent); + MAP_DEL_CURRENT(address); + } + } STRMAP_FOREACH_END; +} + +/** Return true iff address is one that we are configured to + * automap on resolve according to options. */ +int +addressmap_address_should_automap(const char *address, + const or_options_t *options) +{ + const smartlist_t *suffix_list = options->AutomapHostsSuffixes; + + if (!suffix_list) + return 0; + + SMARTLIST_FOREACH_BEGIN(suffix_list, const char *, suffix) { + if (!strcasecmpend(address, suffix)) + return 1; + } SMARTLIST_FOREACH_END(suffix); + return 0; +} + +/** Remove all AUTOMAP mappings from the addressmap for which the + * source address no longer matches AutomapHostsSuffixes, which is + * no longer allowed by AutomapHostsOnResolve, or for which the + * target address is no longer in the virtual network. */ +void +addressmap_clear_invalid_automaps(const or_options_t *options) +{ + int clear_all = !options->AutomapHostsOnResolve; + const smartlist_t *suffixes = options->AutomapHostsSuffixes; + + if (!addressmap) + return; + + if (!suffixes) + clear_all = 1; /* This should be impossible, but let's be sure. */ + + STRMAP_FOREACH_MODIFY(addressmap, src_address, addressmap_entry_t *, ent) { + int remove = clear_all; + if (ent->source != ADDRMAPSRC_AUTOMAP) + continue; /* not an automap mapping. */ + + if (!remove) { + remove = ! addressmap_address_should_automap(src_address, options); + } + + if (!remove && ! address_is_in_virtual_range(ent->new_address)) + remove = 1; + + if (remove) { + addressmap_ent_remove(src_address, ent); + MAP_DEL_CURRENT(src_address); + } + } STRMAP_FOREACH_END; +} + +/** Remove all entries from the addressmap that were set via the + * configuration file or the command line. */ +void +addressmap_clear_configured(void) +{ + addressmap_get_mappings(NULL, 0, 0, 0); +} + +/** Remove all entries from the addressmap that are set to expire, ever. */ +void +addressmap_clear_transient(void) +{ + addressmap_get_mappings(NULL, 2, TIME_MAX, 0); +} + +/** Clean out entries from the addressmap cache that were + * added long enough ago that they are no longer valid. + */ +void +addressmap_clean(time_t now) +{ + addressmap_get_mappings(NULL, 2, now, 0); +} + +/** Free all the elements in the addressmap, and free the addressmap + * itself. */ +void +addressmap_free_all(void) +{ + strmap_free(addressmap, addressmap_ent_free); + addressmap = NULL; + + strmap_free(virtaddress_reversemap, addressmap_virtaddress_ent_free); + virtaddress_reversemap = NULL; +} + +/** Try to find a match for AddressMap expressions that use + * wildcard notation such as '*.c.d *.e.f' (so 'a.c.d' will map to 'a.e.f') or + * '*.c.d a.b.c' (so 'a.c.d' will map to a.b.c). + * Return the matching entry in AddressMap or NULL if no match is found. + * For expressions such as '*.c.d *.e.f', truncate address 'a.c.d' + * to 'a' before we return the matching AddressMap entry. + * + * This function does not handle the case where a pattern of the form "*.c.d" + * matches the address c.d -- that's done by the main addressmap_rewrite + * function. + */ +static addressmap_entry_t * +addressmap_match_superdomains(char *address) +{ + addressmap_entry_t *val; + char *cp; + + cp = address; + while ((cp = strchr(cp, '.'))) { + /* cp now points to a suffix of address that begins with a . */ + val = strmap_get_lc(addressmap, cp+1); + if (val && val->src_wildcard) { + if (val->dst_wildcard) + *cp = '\0'; + return val; + } + ++cp; + } + return NULL; +} + +/** Look at address, and rewrite it until it doesn't want any + * more rewrites; but don't get into an infinite loop. + * Don't write more than maxlen chars into address. Return true if the + * address changed; false otherwise. Set *expires_out to the + * expiry time of the result, or to time_max if the result does + * not expire. + * + * If exit_source_out is non-null, we set it as follows. If we the + * address starts out as a non-exit address, and we remap it to an .exit + * address at any point, then set *exit_source_out to the + * address_entry_source_t of the first such rule. Set *exit_source_out + * to ADDRMAPSRC_NONE if there is no such rewrite, or if the original address + * was a .exit. + */ +int +addressmap_rewrite(char *address, size_t maxlen, + unsigned flags, + time_t *expires_out, + addressmap_entry_source_t *exit_source_out) +{ + addressmap_entry_t *ent; + int rewrites; + time_t expires = TIME_MAX; + addressmap_entry_source_t exit_source = ADDRMAPSRC_NONE; + char *addr_orig = tor_strdup(address); + char *log_addr_orig = NULL; + + for (rewrites = 0; rewrites < 16; rewrites++) { + int exact_match = 0; + log_addr_orig = tor_strdup(escaped_safe_str_client(address)); + + ent = strmap_get(addressmap, address); + + if (!ent || !ent->new_address) { + ent = addressmap_match_superdomains(address); + } else { + if (ent->src_wildcard && !ent->dst_wildcard && + !strcasecmp(address, ent->new_address)) { + /* This is a rule like *.example.com example.com, and we just got + * "example.com" */ + goto done; + } + + exact_match = 1; + } + + if (!ent || !ent->new_address) { + goto done; + } + + if (ent && ent->source == ADDRMAPSRC_DNS) { + sa_family_t f; + tor_addr_t tmp; + f = tor_addr_parse(&tmp, ent->new_address); + if (f == AF_INET && !(flags & AMR_FLAG_USE_IPV4_DNS)) + goto done; + else if (f == AF_INET6 && !(flags & AMR_FLAG_USE_IPV6_DNS)) + goto done; + } + + if (ent->dst_wildcard && !exact_match) { + strlcat(address, ".", maxlen); + strlcat(address, ent->new_address, maxlen); + } else { + strlcpy(address, ent->new_address, maxlen); + } + + if (!strcmpend(address, ".exit") && + strcmpend(addr_orig, ".exit") && + exit_source == ADDRMAPSRC_NONE) { + exit_source = ent->source; + } + + log_info(LD_APP, "Addressmap: rewriting %s to %s", + log_addr_orig, escaped_safe_str_client(address)); + if (ent->expires > 1 && ent->expires < expires) + expires = ent->expires; + + tor_free(log_addr_orig); + } + log_warn(LD_CONFIG, + "Loop detected: we've rewritten %s 16 times! Using it as-is.", + escaped_safe_str_client(address)); + /* it's fine to rewrite a rewrite, but don't loop forever */ + + done: + tor_free(addr_orig); + tor_free(log_addr_orig); + if (exit_source_out) + *exit_source_out = exit_source; + if (expires_out) + *expires_out = TIME_MAX; + return (rewrites > 0); +} + +/** If we have a cached reverse DNS entry for the address stored in the + * maxlen-byte buffer address (typically, a dotted quad) then + * rewrite to the cached value and return 1. Otherwise return 0. Set + * *expires_out to the expiry time of the result, or to time_max + * if the result does not expire. */ +int +addressmap_rewrite_reverse(char *address, size_t maxlen, unsigned flags, + time_t *expires_out) +{ + char *s, *cp; + addressmap_entry_t *ent; + int r = 0; + { + sa_family_t f; + tor_addr_t tmp; + f = tor_addr_parse(&tmp, address); + if (f == AF_INET && !(flags & AMR_FLAG_USE_IPV4_DNS)) + return 0; + else if (f == AF_INET6 && !(flags & AMR_FLAG_USE_IPV6_DNS)) + return 0; + } + + tor_asprintf(&s, "REVERSE[%s]", address); + ent = strmap_get(addressmap, s); + if (ent) { + cp = tor_strdup(escaped_safe_str_client(ent->new_address)); + log_info(LD_APP, "Rewrote reverse lookup %s -> %s", + escaped_safe_str_client(s), cp); + tor_free(cp); + strlcpy(address, ent->new_address, maxlen); + r = 1; + } + + if (expires_out) + *expires_out = (ent && ent->expires > 1) ? ent->expires : TIME_MAX; + + tor_free(s); + return r; +} + +/** Return 1 if address is already registered, else return 0. If address + * is already registered, and update_expires is non-zero, then update + * the expiry time on the mapping with update_expires if it is a + * mapping created by TrackHostExits. */ +int +addressmap_have_mapping(const char *address, int update_expiry) +{ + addressmap_entry_t *ent; + if (!(ent=strmap_get_lc(addressmap, address))) + return 0; + if (update_expiry && ent->source==ADDRMAPSRC_TRACKEXIT) + ent->expires=time(NULL) + update_expiry; + return 1; +} + +/** Register a request to map address to new_address, + * which will expire on expires (or 0 if never expires from + * config file, 1 if never expires from controller, 2 if never expires + * (virtual address mapping) from the controller.) + * + * new_address should be a newly dup'ed string, which we'll use or + * free as appropriate. We will leave address alone. + * + * If wildcard_addr is true, then the mapping will match any address + * equal to address, or any address ending with a period followed by + * address. If wildcard_addr and wildcard_new_addr are + * both true, the mapping will rewrite addresses that end with + * ".address" into ones that end with ".new_address." + * + * If new_address is NULL, or new_address is equal to + * address and wildcard_addr is equal to + * wildcard_new_addr, remove any mappings that exist from + * address. + * + * + * It is an error to set wildcard_new_addr if wildcard_addr is + * not set. */ +void +addressmap_register(const char *address, char *new_address, time_t expires, + addressmap_entry_source_t source, + const int wildcard_addr, + const int wildcard_new_addr) +{ + addressmap_entry_t *ent; + + if (wildcard_new_addr) + tor_assert(wildcard_addr); + + ent = strmap_get(addressmap, address); + if (!new_address || (!strcasecmp(address,new_address) && + wildcard_addr == wildcard_new_addr)) { + /* Remove the mapping, if any. */ + tor_free(new_address); + if (ent) { + addressmap_ent_remove(address,ent); + strmap_remove(addressmap, address); + } + return; + } + if (!ent) { /* make a new one and register it */ + ent = tor_malloc_zero(sizeof(addressmap_entry_t)); + strmap_set(addressmap, address, ent); + } else if (ent->new_address) { /* we need to clean up the old mapping. */ + if (expires > 1) { + log_info(LD_APP,"Temporary addressmap ('%s' to '%s') not performed, " + "since it's already mapped to '%s'", + safe_str_client(address), + safe_str_client(new_address), + safe_str_client(ent->new_address)); + tor_free(new_address); + return; + } + if (address_is_in_virtual_range(ent->new_address) && + expires != 2) { + /* XXX This isn't the perfect test; we want to avoid removing + * mappings set from the control interface _as virtual mapping */ + addressmap_virtaddress_remove(address, ent); + } + tor_free(ent->new_address); + } /* else { we have an in-progress resolve with no mapping. } */ + + ent->new_address = new_address; + ent->expires = expires==2 ? 1 : expires; + ent->num_resolve_failures = 0; + ent->source = source; + ent->src_wildcard = wildcard_addr ? 1 : 0; + ent->dst_wildcard = wildcard_new_addr ? 1 : 0; + + log_info(LD_CONFIG, "Addressmap: (re)mapped '%s' to '%s'", + safe_str_client(address), + safe_str_client(ent->new_address)); + control_event_address_mapped(address, ent->new_address, expires, NULL, 1); +} + +/** An attempt to resolve address failed at some OR. + * Increment the number of resolve failures we have on record + * for it, and then return that number. + */ +int +client_dns_incr_failures(const char *address) +{ + addressmap_entry_t *ent = strmap_get(addressmap, address); + if (!ent) { + ent = tor_malloc_zero(sizeof(addressmap_entry_t)); + ent->expires = time(NULL) + MAX_DNS_ENTRY_AGE; + strmap_set(addressmap,address,ent); + } + if (ent->num_resolve_failures < SHORT_MAX) + ++ent->num_resolve_failures; /* don't overflow */ + log_info(LD_APP, "Address %s now has %d resolve failures.", + safe_str_client(address), + ent->num_resolve_failures); + return ent->num_resolve_failures; +} + +/** If address is in the client DNS addressmap, reset + * the number of resolve failures we have on record for it. + * This is used when we fail a stream because it won't resolve: + * otherwise future attempts on that address will only try once. + */ +void +client_dns_clear_failures(const char *address) +{ + addressmap_entry_t *ent = strmap_get(addressmap, address); + if (ent) + ent->num_resolve_failures = 0; +} + +/** Record the fact that address resolved to name. + * We can now use this in subsequent streams via addressmap_rewrite() + * so we can more correctly choose an exit that will allow address. + * + * If exitname is defined, then append the addresses with + * ".exitname.exit" before registering the mapping. + * + * If ttl is nonnegative, the mapping will be valid for + * ttlseconds; otherwise, we use the default. + */ +static void +client_dns_set_addressmap_impl(entry_connection_t *for_conn, + const char *address, const char *name, + const char *exitname, + int ttl) +{ + char *extendedaddress=NULL, *extendedval=NULL; + (void)for_conn; + + tor_assert(address); + tor_assert(name); + + if (ttl<0) + ttl = DEFAULT_DNS_TTL; + else + ttl = dns_clip_ttl(ttl); + + if (exitname) { + /* XXXX fails to ever get attempts to get an exit address of + * google.com.digest[=~]nickname.exit; we need a syntax for this that + * won't make strict RFC952-compliant applications (like us) barf. */ + tor_asprintf(&extendedaddress, + "%s.%s.exit", address, exitname); + tor_asprintf(&extendedval, + "%s.%s.exit", name, exitname); + } else { + tor_asprintf(&extendedaddress, + "%s", address); + tor_asprintf(&extendedval, + "%s", name); + } + addressmap_register(extendedaddress, extendedval, + time(NULL) + ttl, ADDRMAPSRC_DNS, 0, 0); + tor_free(extendedaddress); +} + +/** Record the fact that address resolved to val. + * We can now use this in subsequent streams via addressmap_rewrite() + * so we can more correctly choose an exit that will allow address. + * + * If exitname is defined, then append the addresses with + * ".exitname.exit" before registering the mapping. + * + * If ttl is nonnegative, the mapping will be valid for + * ttlseconds; otherwise, we use the default. + */ +void +client_dns_set_addressmap(entry_connection_t *for_conn, + const char *address, + const tor_addr_t *val, + const char *exitname, + int ttl) +{ + tor_addr_t addr_tmp; + char valbuf[TOR_ADDR_BUF_LEN]; + + tor_assert(address); + tor_assert(val); + + if (tor_addr_parse(&addr_tmp, address) >= 0) + return; /* If address was an IP address already, don't add a mapping. */ + + if (tor_addr_family(val) == AF_INET) { + if (! for_conn->cache_ipv4_answers) + return; + } else if (tor_addr_family(val) == AF_INET6) { + if (! for_conn->cache_ipv6_answers) + return; + } + + if (! tor_addr_to_str(valbuf, val, sizeof(valbuf), 1)) + return; + + client_dns_set_addressmap_impl(for_conn, address, valbuf, exitname, ttl); +} + +/** Add a cache entry noting that address (ordinarily a dotted quad) + * resolved via a RESOLVE_PTR request to the hostname v. + * + * If exitname is defined, then append the addresses with + * ".exitname.exit" before registering the mapping. + * + * If ttl is nonnegative, the mapping will be valid for + * ttlseconds; otherwise, we use the default. + */ +void +client_dns_set_reverse_addressmap(entry_connection_t *for_conn, + const char *address, const char *v, + const char *exitname, + int ttl) +{ + char *s = NULL; + { + tor_addr_t tmp_addr; + sa_family_t f = tor_addr_parse(&tmp_addr, address); + if ((f == AF_INET && ! for_conn->cache_ipv4_answers) || + (f == AF_INET6 && ! for_conn->cache_ipv6_answers)) + return; + } + tor_asprintf(&s, "REVERSE[%s]", address); + client_dns_set_addressmap_impl(for_conn, s, v, exitname, ttl); + tor_free(s); +} + +/* By default, we hand out 127.192.0.1 through 127.254.254.254. + * These addresses should map to localhost, so even if the + * application accidentally tried to connect to them directly (not + * via Tor), it wouldn't get too far astray. + * + * These options are configured by parse_virtual_addr_network(). + */ + +static virtual_addr_conf_t virtaddr_conf_ipv4; +static virtual_addr_conf_t virtaddr_conf_ipv6; + +/** Read a netmask of the form 127.192.0.0/10 from "val", and check whether + * it's a valid set of virtual addresses to hand out in response to MAPADDRESS + * requests. Return 0 on success; set *msg (if provided) to a newly allocated + * string and return -1 on failure. If validate_only is false, sets the + * actual virtual address range to the parsed value. */ +int +parse_virtual_addr_network(const char *val, sa_family_t family, + int validate_only, + char **msg) +{ + const int ipv6 = (family == AF_INET6); + tor_addr_t addr; + maskbits_t bits; + const int max_bits = ipv6 ? 40 : 16; + virtual_addr_conf_t *conf = ipv6 ? &virtaddr_conf_ipv6 : &virtaddr_conf_ipv4; + + if (tor_addr_parse_mask_ports(val, 0, &addr, &bits, NULL, NULL) < 0) { + if (msg) + tor_asprintf(msg, "Error parsing VirtualAddressNetwork%s %s", + ipv6?"IPv6":"", val); + return -1; + } + if (tor_addr_family(&addr) != family) { + if (msg) + tor_asprintf(msg, "Incorrect address type for VirtualAddressNetwork%s", + ipv6?"IPv6":""); + return -1; + } +#if 0 + if (port_min != 1 || port_max != 65535) { + if (msg) + tor_asprintf(msg, "Can't specify ports on VirtualAddressNetwork%s", + ipv6?"IPv6":""); + return -1; + } +#endif + + if (bits > max_bits) { + if (msg) + tor_asprintf(msg, "VirtualAddressNetwork%s expects a /%d " + "network or larger",ipv6?"IPv6":"", max_bits); + return -1; + } + + if (validate_only) + return 0; + + tor_addr_copy(&conf->addr, &addr); + conf->bits = bits; + + return 0; +} + +/** + * Return true iff addr is likely to have been returned by + * client_dns_get_unused_address. + **/ +int +address_is_in_virtual_range(const char *address) +{ + tor_addr_t addr; + tor_assert(address); + if (!strcasecmpend(address, ".virtual")) { + return 1; + } else if (tor_addr_parse(&addr, address) >= 0) { + const virtual_addr_conf_t *conf = (tor_addr_family(&addr) == AF_INET6) ? + &virtaddr_conf_ipv6 : &virtaddr_conf_ipv4; + if (tor_addr_compare_masked(&addr, &conf->addr, conf->bits, CMP_EXACT)==0) + return 1; + } + return 0; +} + +/** Return a random address conforming to the virtual address configuration + * in conf. + */ +STATIC void +get_random_virtual_addr(const virtual_addr_conf_t *conf, tor_addr_t *addr_out) +{ + uint8_t tmp[4]; + const uint8_t *addr_bytes; + uint8_t bytes[16]; + const int ipv6 = tor_addr_family(&conf->addr) == AF_INET6; + const int total_bytes = ipv6 ? 16 : 4; + + tor_assert(conf->bits <= total_bytes * 8); + + /* Set addr_bytes to the bytes of the virtual network, in host order */ + if (ipv6) { + addr_bytes = tor_addr_to_in6_addr8(&conf->addr); + } else { + set_uint32(tmp, tor_addr_to_ipv4n(&conf->addr)); + addr_bytes = tmp; + } + + /* Get an appropriate number of random bytes. */ + crypto_rand((char*)bytes, total_bytes); + + /* Now replace the first "conf->bits" bits of 'bytes' with addr_bytes*/ + if (conf->bits >= 8) + memcpy(bytes, addr_bytes, conf->bits / 8); + if (conf->bits & 7) { + uint8_t mask = 0xff >> (conf->bits & 7); + bytes[conf->bits/8] &= mask; + bytes[conf->bits/8] |= addr_bytes[conf->bits/8] & ~mask; + } + + if (ipv6) + tor_addr_from_ipv6_bytes(addr_out, (char*) bytes); + else + tor_addr_from_ipv4n(addr_out, get_uint32(bytes)); + + tor_assert(tor_addr_compare_masked(addr_out, &conf->addr, + conf->bits, CMP_EXACT)==0); +} + +/** Return a newly allocated string holding an address of type + * (one of RESOLVED_TYPE_{IPV4|HOSTNAME}) that has not yet been mapped, + * and that is very unlikely to be the address of any real host. + * + * May return NULL if we have run out of virtual addresses. + */ +static char * +addressmap_get_virtual_address(int type) +{ + char buf[64]; + tor_assert(addressmap); + + if (type == RESOLVED_TYPE_HOSTNAME) { + char rand[10]; + do { + crypto_rand(rand, sizeof(rand)); + base32_encode(buf,sizeof(buf),rand,sizeof(rand)); + strlcat(buf, ".virtual", sizeof(buf)); + } while (strmap_get(addressmap, buf)); + return tor_strdup(buf); + } else if (type == RESOLVED_TYPE_IPV4 || type == RESOLVED_TYPE_IPV6) { + const int ipv6 = (type == RESOLVED_TYPE_IPV6); + const virtual_addr_conf_t *conf = ipv6 ? + &virtaddr_conf_ipv6 : &virtaddr_conf_ipv4; + + /* Don't try more than 1000 times. This gives us P < 1e-9 for + * failing to get a good address so long as the address space is + * less than ~97.95% full. That's always going to be true under + * sensible circumstances for an IPv6 /10, and it's going to be + * true for an IPv4 /10 as long as we've handed out less than + * 4.08 million addresses. */ + uint32_t attempts = 1000; + + tor_addr_t addr; + + while (attempts--) { + get_random_virtual_addr(conf, &addr); + + if (!ipv6) { + /* Don't hand out any .0 or .255 address. */ + const uint32_t a = tor_addr_to_ipv4h(&addr); + if ((a & 0xff) == 0 || (a & 0xff) == 0xff) + continue; + } + + tor_addr_to_str(buf, &addr, sizeof(buf), 1); + if (!strmap_get(addressmap, buf)) { + /* XXXX This code is to make sure I didn't add an undecorated version + * by mistake. I hope it's needless. */ + char tmp[TOR_ADDR_BUF_LEN]; + tor_addr_to_str(buf, &addr, sizeof(tmp), 0); + if (strmap_get(addressmap, tmp)) { + log_warn(LD_BUG, "%s wasn't in the addressmap, but %s was.", + buf, tmp); + continue; + } + + return tor_strdup(buf); + } + } + log_warn(LD_CONFIG, "Ran out of virtual addresses!"); + return NULL; + } else { + log_warn(LD_BUG, "Called with unsupported address type (%d)", type); + return NULL; + } +} + +/** A controller has requested that we map some address of type + * type to the address new_address. Choose an address + * that is unlikely to be used, and map it, and return it in a newly + * allocated string. If another address of the same type is already + * mapped to new_address, try to return a copy of that address. + * + * The string in new_address may be freed or inserted into a map + * as appropriate. May return NULL if are out of virtual addresses. + **/ +const char * +addressmap_register_virtual_address(int type, char *new_address) +{ + char **addrp; + virtaddress_entry_t *vent; + int vent_needs_to_be_added = 0; + + tor_assert(new_address); + tor_assert(addressmap); + tor_assert(virtaddress_reversemap); + + vent = strmap_get(virtaddress_reversemap, new_address); + if (!vent) { + vent = tor_malloc_zero(sizeof(virtaddress_entry_t)); + vent_needs_to_be_added = 1; + } + + if (type == RESOLVED_TYPE_IPV4) + addrp = &vent->ipv4_address; + else if (type == RESOLVED_TYPE_IPV6) + addrp = &vent->ipv6_address; + else + addrp = &vent->hostname_address; + + if (*addrp) { + addressmap_entry_t *ent = strmap_get(addressmap, *addrp); + if (ent && ent->new_address && + !strcasecmp(new_address, ent->new_address)) { + tor_free(new_address); + tor_assert(!vent_needs_to_be_added); + return tor_strdup(*addrp); + } else { + log_warn(LD_BUG, + "Internal confusion: I thought that '%s' was mapped to by " + "'%s', but '%s' really maps to '%s'. This is a harmless bug.", + safe_str_client(new_address), + safe_str_client(*addrp), + safe_str_client(*addrp), + ent?safe_str_client(ent->new_address):"(nothing)"); + } + } + + tor_free(*addrp); + *addrp = addressmap_get_virtual_address(type); + if (!*addrp) { + tor_free(vent); + tor_free(new_address); + return NULL; + } + log_info(LD_APP, "Registering map from %s to %s", *addrp, new_address); + if (vent_needs_to_be_added) + strmap_set(virtaddress_reversemap, new_address, vent); + addressmap_register(*addrp, new_address, 2, ADDRMAPSRC_AUTOMAP, 0, 0); + +#if 0 + { + /* Try to catch possible bugs */ + addressmap_entry_t *ent; + ent = strmap_get(addressmap, *addrp); + tor_assert(ent); + tor_assert(!strcasecmp(ent->new_address,new_address)); + vent = strmap_get(virtaddress_reversemap, new_address); + tor_assert(vent); + tor_assert(!strcasecmp(*addrp, + (type == RESOLVED_TYPE_IPV4) ? + vent->ipv4_address : vent->hostname_address)); + log_info(LD_APP, "Map from %s to %s okay.", + safe_str_client(*addrp), + safe_str_client(new_address)); + } +#endif + + return *addrp; +} + +/** Return 1 if address has funny characters in it like colons. Return + * 0 if it's fine, or if we're configured to allow it anyway. client + * should be true if we're using this address as a client; false if we're + * using it as a server. + */ +int +address_is_invalid_destination(const char *address, int client) +{ + if (client) { + if (get_options()->AllowNonRFC953Hostnames) + return 0; + } else { + if (get_options()->ServerDNSAllowNonRFC953Hostnames) + return 0; + } + + /* It might be an IPv6 address! */ + { + tor_addr_t a; + if (tor_addr_parse(&a, address) >= 0) + return 0; + } + + while (*address) { + if (TOR_ISALNUM(*address) || + *address == '-' || + *address == '.' || + *address == '_') /* Underscore is not allowed, but Windows does it + * sometimes, just to thumb its nose at the IETF. */ + ++address; + else + return 1; + } + return 0; +} + +/** Iterate over all address mappings which have expiry times between + * min_expires and max_expires, inclusive. If sl is provided, add an + * "old-addr new-addr expiry" string to sl for each mapping, omitting + * the expiry time if want_expiry is false. If sl is NULL, remove the + * mappings. + */ +void +addressmap_get_mappings(smartlist_t *sl, time_t min_expires, + time_t max_expires, int want_expiry) +{ + strmap_iter_t *iter; + const char *key; + void *val_; + addressmap_entry_t *val; + + if (!addressmap) + addressmap_init(); + + for (iter = strmap_iter_init(addressmap); !strmap_iter_done(iter); ) { + strmap_iter_get(iter, &key, &val_); + val = val_; + if (val->expires >= min_expires && val->expires <= max_expires) { + if (!sl) { + iter = strmap_iter_next_rmv(addressmap,iter); + addressmap_ent_remove(key, val); + continue; + } else if (val->new_address) { + const char *src_wc = val->src_wildcard ? "*." : ""; + const char *dst_wc = val->dst_wildcard ? "*." : ""; + if (want_expiry) { + if (val->expires < 3 || val->expires == TIME_MAX) + smartlist_add_asprintf(sl, "%s%s %s%s NEVER", + src_wc, key, dst_wc, val->new_address); + else { + char time[ISO_TIME_LEN+1]; + format_iso_time(time, val->expires); + smartlist_add_asprintf(sl, "%s%s %s%s \"%s\"", + src_wc, key, dst_wc, val->new_address, + time); + } + } else { + smartlist_add_asprintf(sl, "%s%s %s%s", + src_wc, key, dst_wc, val->new_address); + } + } + } + iter = strmap_iter_next(addressmap,iter); + } +} + diff --git a/src/tor/addressmap.h b/src/tor/addressmap.h new file mode 100644 index 0000000..417832b --- /dev/null +++ b/src/tor/addressmap.h @@ -0,0 +1,62 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_ADDRESSMAP_H +#define TOR_ADDRESSMAP_H + +#include "testsupport.h" + +void addressmap_init(void); +void addressmap_clear_excluded_trackexithosts(const or_options_t *options); +void addressmap_clear_invalid_automaps(const or_options_t *options); +void addressmap_clean(time_t now); +void addressmap_clear_configured(void); +void addressmap_clear_transient(void); +void addressmap_free_all(void); +#define AMR_FLAG_USE_IPV4_DNS (1u<<0) +#define AMR_FLAG_USE_IPV6_DNS (1u<<1) +int addressmap_rewrite(char *address, size_t maxlen, unsigned flags, + time_t *expires_out, + addressmap_entry_source_t *exit_source_out); +int addressmap_rewrite_reverse(char *address, size_t maxlen, unsigned flags, + time_t *expires_out); +int addressmap_have_mapping(const char *address, int update_timeout); + +void addressmap_register(const char *address, char *new_address, + time_t expires, addressmap_entry_source_t source, + const int address_wildcard, + const int new_address_wildcard); +int parse_virtual_addr_network(const char *val, + sa_family_t family, int validate_only, + char **msg); +int client_dns_incr_failures(const char *address); +void client_dns_clear_failures(const char *address); +void client_dns_set_addressmap(entry_connection_t *for_conn, + const char *address, const tor_addr_t *val, + const char *exitname, int ttl); +const char *addressmap_register_virtual_address(int type, char *new_address); +void addressmap_get_mappings(smartlist_t *sl, time_t min_expires, + time_t max_expires, int want_expiry); +int address_is_in_virtual_range(const char *addr); +void clear_trackexithost_mappings(const char *exitname); +void client_dns_set_reverse_addressmap(entry_connection_t *for_conn, + const char *address, const char *v, + const char *exitname, int ttl); +int addressmap_address_should_automap(const char *address, + const or_options_t *options); + +#ifdef ADDRESSMAP_PRIVATE +typedef struct virtual_addr_conf_t { + tor_addr_t addr; + maskbits_t bits; +} virtual_addr_conf_t; + +STATIC void get_random_virtual_addr(const virtual_addr_conf_t *conf, + tor_addr_t *addr_out); +#endif + +#endif + diff --git a/src/tor/aes.c b/src/tor/aes.c new file mode 100644 index 0000000..e4cfe91 --- /dev/null +++ b/src/tor/aes.c @@ -0,0 +1,522 @@ +/* Copyright (c) 2001, Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file aes.c + * \brief Implements a counter-mode stream cipher on top of AES. + **/ + +#include "orconfig.h" + +#ifdef _WIN32 /*wrkard for dtls1.h >= 0.9.8m of "#include "*/ + #ifndef _WIN32_WINNT + #define _WIN32_WINNT 0x0501 + #endif + #define WIN32_LEAN_AND_MEAN + #if defined(_MSC_VER) && (_MSC_VER < 1300) + #include + #else + #include + #include + #endif +#endif + +#include +#include +#include +#include +#include +#include +#include +#include "crypto.h" +#if OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,0,0) +/* See comments about which counter mode implementation to use below. */ +#include +#define CAN_USE_OPENSSL_CTR +#endif +#include "tor_compat.h" +#include "aes.h" +#include "tor_util.h" +#include "torlog.h" +#include "di_ops.h" + +#ifdef ANDROID +/* Android's OpenSSL seems to have removed all of its Engine support. */ +#define DISABLE_ENGINES +#endif + +/* We have five strategies for implementing AES counter mode. + * + * Best with x86 and x86_64: Use EVP_aes_ctr128() and EVP_EncryptUpdate(). + * This is possible with OpenSSL 1.0.1, where the counter-mode implementation + * can use bit-sliced or vectorized AES or AESNI as appropriate. + * + * Otherwise: Pick the best possible AES block implementation that OpenSSL + * gives us, and the best possible counter-mode implementation, and combine + * them. + */ +#if OPENSSL_VERSION_NUMBER >= OPENSSL_V_NOPATCH(1,0,1) && \ + (defined(__i386) || defined(__i386__) || defined(_M_IX86) || \ + defined(__x86_64) || defined(__x86_64__) || \ + defined(_M_AMD64) || defined(_M_X64) || defined(__INTEL__)) \ + +#define USE_EVP_AES_CTR + +#endif + +/* We have 2 strategies for getting the AES block cipher: Via OpenSSL's + * AES_encrypt function, or via OpenSSL's EVP_EncryptUpdate function. + * + * If there's any hardware acceleration in play, we want to be using EVP_* so + * we can get it. Otherwise, we'll want AES_*, which seems to be about 5% + * faster than indirecting through the EVP layer. + */ + +/* We have 2 strategies for getting a plug-in counter mode: use our own, or + * use OpenSSL's. + * + * Here we have a counter mode that's faster than the one shipping with + * OpenSSL pre-1.0 (by about 10%!). But OpenSSL 1.0.0 added a counter mode + * implementation faster than the one here (by about 7%). So we pick which + * one to used based on the Openssl version above. (OpenSSL 1.0.0a fixed a + * critical bug in that counter mode implementation, so we need to test to + * make sure that we have a fixed version.) + */ + +#ifdef USE_EVP_AES_CTR + +struct aes_cnt_cipher { + EVP_CIPHER_CTX evp; +}; + +aes_cnt_cipher_t * +aes_new_cipher(const char *key, const char *iv) +{ + aes_cnt_cipher_t *cipher; + cipher = tor_malloc_zero(sizeof(aes_cnt_cipher_t)); + EVP_EncryptInit(&cipher->evp, EVP_aes_128_ctr(), + (const unsigned char*)key, (const unsigned char *)iv); + return cipher; +} +void +aes_cipher_free(aes_cnt_cipher_t *cipher) +{ + if (!cipher) + return; + EVP_CIPHER_CTX_cleanup(&cipher->evp); + memwipe(cipher, 0, sizeof(aes_cnt_cipher_t)); + tor_free(cipher); +} +void +aes_crypt(aes_cnt_cipher_t *cipher, const char *input, size_t len, + char *output) +{ + int outl; + + tor_assert(len < INT_MAX); + + EVP_EncryptUpdate(&cipher->evp, (unsigned char*)output, + &outl, (const unsigned char *)input, (int)len); +} +void +aes_crypt_inplace(aes_cnt_cipher_t *cipher, char *data, size_t len) +{ + int outl; + + tor_assert(len < INT_MAX); + + EVP_EncryptUpdate(&cipher->evp, (unsigned char*)data, + &outl, (unsigned char*)data, (int)len); +} +int +evaluate_evp_for_aes(int force_val) +{ + (void) force_val; + log_info(LD_CRYPTO, "This version of OpenSSL has a known-good EVP " + "counter-mode implementation. Using it."); + return 0; +} +int +evaluate_ctr_for_aes(void) +{ + return 0; +} +#else + +/*======================================================================*/ +/* Interface to AES code, and counter implementation */ + +/** Implements an AES counter-mode cipher. */ +struct aes_cnt_cipher { +/** This next element (however it's defined) is the AES key. */ + union { + EVP_CIPHER_CTX evp; + AES_KEY aes; + } key; + +#if !defined(WORDS_BIGENDIAN) +#define USING_COUNTER_VARS + /** These four values, together, implement a 128-bit counter, with + * counter0 as the low-order word and counter3 as the high-order word. */ + uint32_t counter3; + uint32_t counter2; + uint32_t counter1; + uint32_t counter0; +#endif + + union { + /** The counter, in big-endian order, as bytes. */ + uint8_t buf[16]; + /** The counter, in big-endian order, as big-endian words. Note that + * on big-endian platforms, this is redundant with counter3...0, + * so we just use these values instead. */ + uint32_t buf32[4]; + } ctr_buf; + + /** The encrypted value of ctr_buf. */ + uint8_t buf[16]; + /** Our current stream position within buf. */ + unsigned int pos; + + /** True iff we're using the evp implementation of this cipher. */ + uint8_t using_evp; +}; + +/** True iff we should prefer the EVP implementation for AES, either because + * we're testing it or because we have hardware acceleration configured */ +static int should_use_EVP = 0; + +#ifdef CAN_USE_OPENSSL_CTR +/** True iff we have tested the counter-mode implementation and found that it + * doesn't have the counter-mode bug from OpenSSL 1.0.0. */ +static int should_use_openssl_CTR = 0; +#endif + +/** Check whether we should use the EVP interface for AES. If force_val + * is nonnegative, we use use EVP iff it is true. Otherwise, we use EVP + * if there is an engine enabled for aes-ecb. */ +int +evaluate_evp_for_aes(int force_val) +{ + ENGINE *e; + + if (force_val >= 0) { + should_use_EVP = force_val; + return 0; + } +#ifdef DISABLE_ENGINES + should_use_EVP = 0; +#else + e = ENGINE_get_cipher_engine(NID_aes_128_ecb); + + if (e) { + log_info(LD_CRYPTO, "AES engine \"%s\" found; using EVP_* functions.", + ENGINE_get_name(e)); + should_use_EVP = 1; + } else { + log_info(LD_CRYPTO, "No AES engine found; using AES_* functions."); + should_use_EVP = 0; + } +#endif + + return 0; +} + +/** Test the OpenSSL counter mode implementation to see whether it has the + * counter-mode bug from OpenSSL 1.0.0. If the implementation works, then + * we will use it for future encryption/decryption operations. + * + * We can't just look at the OpenSSL version, since some distributions update + * their OpenSSL packages without changing the version number. + **/ +int +evaluate_ctr_for_aes(void) +{ +#ifdef CAN_USE_OPENSSL_CTR + /* Result of encrypting an all-zero block with an all-zero 128-bit AES key. + * This should be the same as encrypting an all-zero block with an all-zero + * 128-bit AES key in counter mode, starting at position 0 of the stream. + */ + static const unsigned char encrypt_zero[] = + "\x66\xe9\x4b\xd4\xef\x8a\x2c\x3b\x88\x4c\xfa\x59\xca\x34\x2b\x2e"; + unsigned char zero[16]; + unsigned char output[16]; + unsigned char ivec[16]; + unsigned char ivec_tmp[16]; + unsigned int pos, i; + AES_KEY key; + memset(zero, 0, sizeof(zero)); + memset(ivec, 0, sizeof(ivec)); + AES_set_encrypt_key(zero, 128, &key); + + pos = 0; + /* Encrypting a block one byte at a time should make the error manifest + * itself for known bogus openssl versions. */ + for (i=0; i<16; ++i) + AES_ctr128_encrypt(&zero[i], &output[i], 1, &key, ivec, ivec_tmp, &pos); + + if (fast_memneq(output, encrypt_zero, 16)) { + /* Counter mode is buggy */ + log_notice(LD_CRYPTO, "This OpenSSL has a buggy version of counter mode; " + "not using it."); + } else { + /* Counter mode is okay */ + log_info(LD_CRYPTO, "This OpenSSL has a good implementation of counter " + "mode; using it."); + should_use_openssl_CTR = 1; + } +#else + log_info(LD_CRYPTO, "This version of OpenSSL has a slow implementation of " + "counter mode; not using it."); +#endif + return 0; +} + +#if !defined(USING_COUNTER_VARS) +#define COUNTER(c, n) ((c)->ctr_buf.buf32[3-(n)]) +#else +#define COUNTER(c, n) ((c)->counter ## n) +#endif + +/** + * Helper function: set cipher's internal buffer to the encrypted + * value of the current counter. + */ +static INLINE void +aes_fill_buf_(aes_cnt_cipher_t *cipher) +{ + /* We don't currently use OpenSSL's counter mode implementation because: + * 1) some versions have known bugs + * 2) its attitude towards IVs is not our own + * 3) changing the counter position was not trivial, last time I looked. + * None of these issues are insurmountable in principle. + */ + + if (cipher->using_evp) { + int outl=16, inl=16; + EVP_EncryptUpdate(&cipher->key.evp, cipher->buf, &outl, + cipher->ctr_buf.buf, inl); + } else { + AES_encrypt(cipher->ctr_buf.buf, cipher->buf, &cipher->key.aes); + } +} + +static void aes_set_key(aes_cnt_cipher_t *cipher, const char *key, + int key_bits); +static void aes_set_iv(aes_cnt_cipher_t *cipher, const char *iv); + +/** + * Return a newly allocated counter-mode AES128 cipher implementation, + * using the 128-bit key key and the 128-bit IV iv. + */ +aes_cnt_cipher_t* +aes_new_cipher(const char *key, const char *iv) +{ + aes_cnt_cipher_t* result = tor_malloc_zero(sizeof(aes_cnt_cipher_t)); + + aes_set_key(result, key, 128); + aes_set_iv(result, iv); + + return result; +} + +/** Set the key of cipher to key, which is + * key_bits bits long (must be 128, 192, or 256). Also resets + * the counter to 0. + */ +static void +aes_set_key(aes_cnt_cipher_t *cipher, const char *key, int key_bits) +{ + if (should_use_EVP) { + const EVP_CIPHER *c; + switch (key_bits) { + case 128: c = EVP_aes_128_ecb(); break; + case 192: c = EVP_aes_192_ecb(); break; + case 256: c = EVP_aes_256_ecb(); break; + default: tor_assert(0); + } + EVP_EncryptInit(&cipher->key.evp, c, (const unsigned char*)key, NULL); + cipher->using_evp = 1; + } else { + AES_set_encrypt_key((const unsigned char *)key, key_bits,&cipher->key.aes); + cipher->using_evp = 0; + } + +#ifdef USING_COUNTER_VARS + cipher->counter0 = 0; + cipher->counter1 = 0; + cipher->counter2 = 0; + cipher->counter3 = 0; +#endif + + memset(cipher->ctr_buf.buf, 0, sizeof(cipher->ctr_buf.buf)); + + cipher->pos = 0; + +#ifdef CAN_USE_OPENSSL_CTR + if (should_use_openssl_CTR) + memset(cipher->buf, 0, sizeof(cipher->buf)); + else +#endif + aes_fill_buf_(cipher); +} + +/** Release storage held by cipher + */ +void +aes_cipher_free(aes_cnt_cipher_t *cipher) +{ + if (!cipher) + return; + if (cipher->using_evp) { + EVP_CIPHER_CTX_cleanup(&cipher->key.evp); + } + memwipe(cipher, 0, sizeof(aes_cnt_cipher_t)); + tor_free(cipher); +} + +#if defined(USING_COUNTER_VARS) +#define UPDATE_CTR_BUF(c, n) STMT_BEGIN \ + (c)->ctr_buf.buf32[3-(n)] = htonl((c)->counter ## n); \ + STMT_END +#else +#define UPDATE_CTR_BUF(c, n) +#endif + +#ifdef CAN_USE_OPENSSL_CTR +/* Helper function to use EVP with openssl's counter-mode wrapper. */ +static void +evp_block128_fn(const uint8_t in[16], + uint8_t out[16], + const void *key) +{ + EVP_CIPHER_CTX *ctx = (void*)key; + int inl=16, outl=16; + EVP_EncryptUpdate(ctx, out, &outl, in, inl); +} +#endif + +/** Encrypt len bytes from input, storing the result in + * output. Uses the key in cipher, and advances the counter + * by len bytes as it encrypts. + */ +void +aes_crypt(aes_cnt_cipher_t *cipher, const char *input, size_t len, + char *output) +{ +#ifdef CAN_USE_OPENSSL_CTR + if (should_use_openssl_CTR) { + if (cipher->using_evp) { + /* In openssl 1.0.0, there's an if'd out EVP_aes_128_ctr in evp.h. If + * it weren't disabled, it might be better just to use that. + */ + CRYPTO_ctr128_encrypt((const unsigned char *)input, + (unsigned char *)output, + len, + &cipher->key.evp, + cipher->ctr_buf.buf, + cipher->buf, + &cipher->pos, + evp_block128_fn); + } else { + AES_ctr128_encrypt((const unsigned char *)input, + (unsigned char *)output, + len, + &cipher->key.aes, + cipher->ctr_buf.buf, + cipher->buf, + &cipher->pos); + } + return; + } else +#endif + { + int c = cipher->pos; + if (PREDICT_UNLIKELY(!len)) return; + + while (1) { + do { + if (len-- == 0) { cipher->pos = c; return; } + *(output++) = *(input++) ^ cipher->buf[c]; + } while (++c != 16); + cipher->pos = c = 0; + if (PREDICT_UNLIKELY(! ++COUNTER(cipher, 0))) { + if (PREDICT_UNLIKELY(! ++COUNTER(cipher, 1))) { + if (PREDICT_UNLIKELY(! ++COUNTER(cipher, 2))) { + ++COUNTER(cipher, 3); + UPDATE_CTR_BUF(cipher, 3); + } + UPDATE_CTR_BUF(cipher, 2); + } + UPDATE_CTR_BUF(cipher, 1); + } + UPDATE_CTR_BUF(cipher, 0); + aes_fill_buf_(cipher); + } + } +} + +/** Encrypt len bytes from input, storing the results in place. + * Uses the key in cipher, and advances the counter by len bytes + * as it encrypts. + */ +void +aes_crypt_inplace(aes_cnt_cipher_t *cipher, char *data, size_t len) +{ +#ifdef CAN_USE_OPENSSL_CTR + if (should_use_openssl_CTR) { + aes_crypt(cipher, data, len, data); + return; + } else +#endif + { + int c = cipher->pos; + if (PREDICT_UNLIKELY(!len)) return; + + while (1) { + do { + if (len-- == 0) { cipher->pos = c; return; } + *(data++) ^= cipher->buf[c]; + } while (++c != 16); + cipher->pos = c = 0; + if (PREDICT_UNLIKELY(! ++COUNTER(cipher, 0))) { + if (PREDICT_UNLIKELY(! ++COUNTER(cipher, 1))) { + if (PREDICT_UNLIKELY(! ++COUNTER(cipher, 2))) { + ++COUNTER(cipher, 3); + UPDATE_CTR_BUF(cipher, 3); + } + UPDATE_CTR_BUF(cipher, 2); + } + UPDATE_CTR_BUF(cipher, 1); + } + UPDATE_CTR_BUF(cipher, 0); + aes_fill_buf_(cipher); + } + } +} + +/** Reset the 128-bit counter of cipher to the 16-bit big-endian value + * in iv. */ +static void +aes_set_iv(aes_cnt_cipher_t *cipher, const char *iv) +{ +#ifdef USING_COUNTER_VARS + cipher->counter3 = ntohl(get_uint32(iv)); + cipher->counter2 = ntohl(get_uint32(iv+4)); + cipher->counter1 = ntohl(get_uint32(iv+8)); + cipher->counter0 = ntohl(get_uint32(iv+12)); +#endif + cipher->pos = 0; + memcpy(cipher->ctr_buf.buf, iv, 16); + +#ifdef CAN_USE_OPENSSL_CTR + if (!should_use_openssl_CTR) +#endif + aes_fill_buf_(cipher); +} + +#endif + diff --git a/src/tor/aes.h b/src/tor/aes.h new file mode 100644 index 0000000..8ff28a7 --- /dev/null +++ b/src/tor/aes.h @@ -0,0 +1,29 @@ +/* Copyright (c) 2003, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/* Implements a minimal interface to counter-mode AES. */ + +#ifndef TOR_AES_H +#define TOR_AES_H + +/** + * \file aes.h + * \brief Headers for aes.c + */ + +struct aes_cnt_cipher; +typedef struct aes_cnt_cipher aes_cnt_cipher_t; + +aes_cnt_cipher_t* aes_new_cipher(const char *key, const char *iv); +void aes_cipher_free(aes_cnt_cipher_t *cipher); +void aes_crypt(aes_cnt_cipher_t *cipher, const char *input, size_t len, + char *output); +void aes_crypt_inplace(aes_cnt_cipher_t *cipher, char *data, size_t len); + +int evaluate_evp_for_aes(int force_value); +int evaluate_ctr_for_aes(void); + +#endif + diff --git a/src/tor/anonymize.P b/src/tor/anonymize.P new file mode 100644 index 0000000..ae97293 --- /dev/null +++ b/src/tor/anonymize.P @@ -0,0 +1,1072 @@ +tor/anonymize.o: tor/anonymize.cpp \ + /path/to/triangles/src/tor/anonymize.h \ + /path/to/triangles/src/util.h \ + /path/to/triangles/src/uint256.h \ + /opt/local/include/boost/thread.hpp \ + /opt/local/include/boost/thread/thread.hpp \ + /opt/local/include/boost/thread/thread_only.hpp \ + /opt/local/include/boost/thread/detail/platform.hpp \ + /opt/local/include/boost/config.hpp \ + /opt/local/include/boost/config/user.hpp \ + /opt/local/include/boost/config/select_compiler_config.hpp \ + /opt/local/include/boost/config/compiler/clang.hpp \ + /opt/local/include/boost/config/select_stdlib_config.hpp \ + /opt/local/include/boost/config/no_tr1/utility.hpp \ + /opt/local/include/boost/config/stdlib/libstdcpp3.hpp \ + /opt/local/include/boost/config/select_platform_config.hpp \ + /opt/local/include/boost/config/platform/macos.hpp \ + /opt/local/include/boost/config/posix_features.hpp \ + /opt/local/include/boost/config/suffix.hpp \ + /opt/local/include/boost/config/requires_threads.hpp \ + /opt/local/include/boost/thread/pthread/thread_data.hpp \ + /opt/local/include/boost/thread/detail/config.hpp \ + /opt/local/include/boost/detail/workaround.hpp \ + /opt/local/include/boost/config/auto_link.hpp \ + /opt/local/include/boost/thread/exceptions.hpp \ + /opt/local/include/boost/system/system_error.hpp \ + /opt/local/include/boost/system/error_code.hpp \ + /opt/local/include/boost/system/config.hpp \ + /opt/local/include/boost/system/api_config.hpp \ + /opt/local/include/boost/cstdint.hpp \ + /opt/local/include/boost/assert.hpp \ + /opt/local/include/boost/current_function.hpp \ + /opt/local/include/boost/operators.hpp \ + /opt/local/include/boost/iterator.hpp \ + /opt/local/include/boost/noncopyable.hpp \ + /opt/local/include/boost/utility/enable_if.hpp \ + /opt/local/include/boost/cerrno.hpp \ + /opt/local/include/boost/config/abi_prefix.hpp \ + /opt/local/include/boost/config/abi_suffix.hpp \ + /opt/local/include/boost/thread/lock_guard.hpp \ + /opt/local/include/boost/thread/detail/delete.hpp \ + /opt/local/include/boost/thread/detail/move.hpp \ + /opt/local/include/boost/type_traits/is_convertible.hpp \ + /opt/local/include/boost/type_traits/intrinsics.hpp \ + /opt/local/include/boost/type_traits/config.hpp \ + /opt/local/include/boost/type_traits/is_same.hpp \ + /opt/local/include/boost/type_traits/detail/bool_trait_def.hpp \ + /opt/local/include/boost/type_traits/detail/template_arity_spec.hpp \ + /opt/local/include/boost/mpl/int.hpp \ + /opt/local/include/boost/mpl/int_fwd.hpp \ + /opt/local/include/boost/mpl/aux_/adl_barrier.hpp \ + /opt/local/include/boost/mpl/aux_/config/adl.hpp \ + /opt/local/include/boost/mpl/aux_/config/msvc.hpp \ + /opt/local/include/boost/mpl/aux_/config/intel.hpp \ + /opt/local/include/boost/mpl/aux_/config/gcc.hpp \ + /opt/local/include/boost/mpl/aux_/config/workaround.hpp \ + /opt/local/include/boost/mpl/aux_/nttp_decl.hpp \ + /opt/local/include/boost/mpl/aux_/config/nttp.hpp \ + /opt/local/include/boost/mpl/aux_/integral_wrapper.hpp \ + /opt/local/include/boost/mpl/integral_c_tag.hpp \ + /opt/local/include/boost/mpl/aux_/config/static_constant.hpp \ + /opt/local/include/boost/mpl/aux_/static_cast.hpp \ + /opt/local/include/boost/preprocessor/cat.hpp \ + /opt/local/include/boost/preprocessor/config/config.hpp \ + /opt/local/include/boost/mpl/aux_/template_arity_fwd.hpp \ + /opt/local/include/boost/mpl/aux_/preprocessor/params.hpp \ + /opt/local/include/boost/mpl/aux_/config/preprocessor.hpp \ + /opt/local/include/boost/preprocessor/comma_if.hpp \ + /opt/local/include/boost/preprocessor/punctuation/comma_if.hpp \ + /opt/local/include/boost/preprocessor/control/if.hpp \ + /opt/local/include/boost/preprocessor/control/iif.hpp \ + /opt/local/include/boost/preprocessor/logical/bool.hpp \ + /opt/local/include/boost/preprocessor/facilities/empty.hpp \ + /opt/local/include/boost/preprocessor/punctuation/comma.hpp \ + /opt/local/include/boost/preprocessor/repeat.hpp \ + /opt/local/include/boost/preprocessor/repetition/repeat.hpp \ + /opt/local/include/boost/preprocessor/debug/error.hpp \ + /opt/local/include/boost/preprocessor/detail/auto_rec.hpp \ + /opt/local/include/boost/preprocessor/tuple/eat.hpp \ + /opt/local/include/boost/preprocessor/inc.hpp \ + /opt/local/include/boost/preprocessor/arithmetic/inc.hpp \ + /opt/local/include/boost/mpl/aux_/config/lambda.hpp \ + /opt/local/include/boost/mpl/aux_/config/ttp.hpp \ + /opt/local/include/boost/mpl/aux_/config/ctps.hpp \ + /opt/local/include/boost/mpl/aux_/config/overload_resolution.hpp \ + /opt/local/include/boost/type_traits/integral_constant.hpp \ + /opt/local/include/boost/mpl/bool.hpp \ + /opt/local/include/boost/mpl/bool_fwd.hpp \ + /opt/local/include/boost/mpl/integral_c.hpp \ + /opt/local/include/boost/mpl/integral_c_fwd.hpp \ + /opt/local/include/boost/mpl/aux_/lambda_support.hpp \ + /opt/local/include/boost/type_traits/detail/bool_trait_undef.hpp \ + /opt/local/include/boost/type_traits/is_reference.hpp \ + /opt/local/include/boost/type_traits/is_lvalue_reference.hpp \ + /opt/local/include/boost/type_traits/is_rvalue_reference.hpp \ + /opt/local/include/boost/type_traits/ice.hpp \ + /opt/local/include/boost/type_traits/detail/yes_no_type.hpp \ + /opt/local/include/boost/type_traits/detail/ice_or.hpp \ + /opt/local/include/boost/type_traits/detail/ice_and.hpp \ + /opt/local/include/boost/type_traits/detail/ice_not.hpp \ + /opt/local/include/boost/type_traits/detail/ice_eq.hpp \ + /opt/local/include/boost/type_traits/is_volatile.hpp \ + /opt/local/include/boost/type_traits/detail/cv_traits_impl.hpp \ + /opt/local/include/boost/type_traits/is_abstract.hpp \ + /opt/local/include/boost/type_traits/remove_reference.hpp \ + /opt/local/include/boost/type_traits/broken_compiler_spec.hpp \ + /opt/local/include/boost/type_traits/detail/type_trait_def.hpp \ + /opt/local/include/boost/type_traits/detail/type_trait_undef.hpp \ + /opt/local/include/boost/type_traits/remove_cv.hpp \ + /opt/local/include/boost/type_traits/decay.hpp \ + /opt/local/include/boost/type_traits/is_array.hpp \ + /opt/local/include/boost/type_traits/is_function.hpp \ + /opt/local/include/boost/type_traits/detail/false_result.hpp \ + /opt/local/include/boost/type_traits/detail/is_function_ptr_helper.hpp \ + /opt/local/include/boost/type_traits/remove_bounds.hpp \ + /opt/local/include/boost/type_traits/add_pointer.hpp \ + /opt/local/include/boost/mpl/eval_if.hpp \ + /opt/local/include/boost/mpl/if.hpp \ + /opt/local/include/boost/mpl/aux_/value_wknd.hpp \ + /opt/local/include/boost/mpl/aux_/config/integral.hpp \ + /opt/local/include/boost/mpl/aux_/config/eti.hpp \ + /opt/local/include/boost/mpl/aux_/na_spec.hpp \ + /opt/local/include/boost/mpl/lambda_fwd.hpp \ + /opt/local/include/boost/mpl/void_fwd.hpp \ + /opt/local/include/boost/mpl/aux_/na.hpp \ + /opt/local/include/boost/mpl/aux_/na_fwd.hpp \ + /opt/local/include/boost/mpl/aux_/lambda_arity_param.hpp \ + /opt/local/include/boost/mpl/aux_/arity.hpp \ + /opt/local/include/boost/mpl/aux_/config/dtp.hpp \ + /opt/local/include/boost/mpl/aux_/preprocessor/enum.hpp \ + /opt/local/include/boost/mpl/aux_/preprocessor/def_params_tail.hpp \ + /opt/local/include/boost/mpl/limits/arity.hpp \ + /opt/local/include/boost/preprocessor/logical/and.hpp \ + /opt/local/include/boost/preprocessor/logical/bitand.hpp \ + /opt/local/include/boost/preprocessor/identity.hpp \ + /opt/local/include/boost/preprocessor/facilities/identity.hpp \ + /opt/local/include/boost/preprocessor/empty.hpp \ + /opt/local/include/boost/preprocessor/arithmetic/add.hpp \ + /opt/local/include/boost/preprocessor/arithmetic/dec.hpp \ + /opt/local/include/boost/preprocessor/control/while.hpp \ + /opt/local/include/boost/preprocessor/list/fold_left.hpp \ + /opt/local/include/boost/preprocessor/list/detail/fold_left.hpp \ + /opt/local/include/boost/preprocessor/control/expr_iif.hpp \ + /opt/local/include/boost/preprocessor/list/adt.hpp \ + /opt/local/include/boost/preprocessor/detail/is_binary.hpp \ + /opt/local/include/boost/preprocessor/detail/check.hpp \ + /opt/local/include/boost/preprocessor/logical/compl.hpp \ + /opt/local/include/boost/preprocessor/list/fold_right.hpp \ + /opt/local/include/boost/preprocessor/list/detail/fold_right.hpp \ + /opt/local/include/boost/preprocessor/list/reverse.hpp \ + /opt/local/include/boost/preprocessor/control/detail/while.hpp \ + /opt/local/include/boost/preprocessor/tuple/elem.hpp \ + /opt/local/include/boost/preprocessor/facilities/overload.hpp \ + /opt/local/include/boost/preprocessor/variadic/size.hpp \ + /opt/local/include/boost/preprocessor/tuple/rem.hpp \ + /opt/local/include/boost/preprocessor/variadic/elem.hpp \ + /opt/local/include/boost/preprocessor/arithmetic/sub.hpp \ + /opt/local/include/boost/mpl/identity.hpp \ + /opt/local/include/boost/move/utility.hpp \ + /opt/local/include/boost/move/detail/config_begin.hpp \ + /opt/local/include/boost/move/core.hpp \ + /opt/local/include/boost/move/detail/meta_utils.hpp \ + /opt/local/include/boost/move/detail/config_end.hpp \ + /opt/local/include/boost/move/traits.hpp \ + /opt/local/include/boost/type_traits/has_trivial_destructor.hpp \ + /opt/local/include/boost/type_traits/is_pod.hpp \ + /opt/local/include/boost/type_traits/is_void.hpp \ + /opt/local/include/boost/type_traits/is_scalar.hpp \ + /opt/local/include/boost/type_traits/is_arithmetic.hpp \ + /opt/local/include/boost/type_traits/is_integral.hpp \ + /opt/local/include/boost/type_traits/is_float.hpp \ + /opt/local/include/boost/type_traits/is_enum.hpp \ + /opt/local/include/boost/type_traits/is_pointer.hpp \ + /opt/local/include/boost/type_traits/is_member_pointer.hpp \ + /opt/local/include/boost/type_traits/is_member_function_pointer.hpp \ + /opt/local/include/boost/type_traits/detail/is_mem_fun_pointer_impl.hpp \ + /opt/local/include/boost/type_traits/is_nothrow_move_constructible.hpp \ + /opt/local/include/boost/type_traits/has_trivial_move_constructor.hpp \ + /opt/local/include/boost/type_traits/has_nothrow_copy.hpp \ + /opt/local/include/boost/type_traits/has_trivial_copy.hpp \ + /opt/local/include/boost/utility/declval.hpp \ + /opt/local/include/boost/type_traits/add_rvalue_reference.hpp \ + /opt/local/include/boost/type_traits/is_nothrow_move_assignable.hpp \ + /opt/local/include/boost/type_traits/has_trivial_move_assign.hpp \ + /opt/local/include/boost/type_traits/is_const.hpp \ + /opt/local/include/boost/type_traits/has_nothrow_assign.hpp \ + /opt/local/include/boost/type_traits/has_trivial_assign.hpp \ + /opt/local/include/boost/thread/detail/lockable_wrapper.hpp \ + /opt/local/include/boost/thread/lock_options.hpp \ + /opt/local/include/boost/thread/lock_types.hpp \ + /opt/local/include/boost/thread/lockable_traits.hpp \ + /opt/local/include/boost/type_traits/is_class.hpp \ + /opt/local/include/boost/thread/thread_time.hpp \ + /opt/local/include/boost/date_time/time_clock.hpp \ + /opt/local/include/boost/date_time/c_time.hpp \ + /opt/local/include/boost/throw_exception.hpp \ + /opt/local/include/boost/date_time/compiler_config.hpp \ + /opt/local/include/boost/date_time/locale_config.hpp \ + /opt/local/include/boost/shared_ptr.hpp \ + /opt/local/include/boost/smart_ptr/shared_ptr.hpp \ + /opt/local/include/boost/config/no_tr1/memory.hpp \ + /opt/local/include/boost/checked_delete.hpp \ + /opt/local/include/boost/smart_ptr/detail/shared_count.hpp \ + /opt/local/include/boost/smart_ptr/bad_weak_ptr.hpp \ + /opt/local/include/boost/smart_ptr/detail/sp_counted_base.hpp \ + /opt/local/include/boost/smart_ptr/detail/sp_has_sync.hpp \ + /opt/local/include/boost/smart_ptr/detail/sp_counted_base_gcc_x86.hpp \ + /opt/local/include/boost/detail/sp_typeinfo.hpp \ + /opt/local/include/boost/smart_ptr/detail/sp_counted_impl.hpp \ + /opt/local/include/boost/smart_ptr/detail/sp_convertible.hpp \ + /opt/local/include/boost/smart_ptr/detail/sp_nullptr_t.hpp \ + /opt/local/include/boost/smart_ptr/detail/spinlock_pool.hpp \ + /opt/local/include/boost/smart_ptr/detail/spinlock.hpp \ + /opt/local/include/boost/smart_ptr/detail/spinlock_sync.hpp \ + /opt/local/include/boost/smart_ptr/detail/yield_k.hpp \ + /opt/local/include/boost/memory_order.hpp \ + /opt/local/include/boost/smart_ptr/detail/operator_bool.hpp \ + /opt/local/include/boost/date_time/microsec_time_clock.hpp \ + /opt/local/include/boost/date_time/filetime_functions.hpp \ + /opt/local/include/boost/date_time/posix_time/posix_time_types.hpp \ + /opt/local/include/boost/date_time/posix_time/ptime.hpp \ + /opt/local/include/boost/date_time/posix_time/posix_time_system.hpp \ + /opt/local/include/boost/date_time/posix_time/posix_time_config.hpp \ + /opt/local/include/boost/limits.hpp \ + /opt/local/include/boost/config/no_tr1/cmath.hpp \ + /opt/local/include/boost/date_time/time_duration.hpp \ + /opt/local/include/boost/static_assert.hpp \ + /opt/local/include/boost/date_time/time_defs.hpp \ + /opt/local/include/boost/date_time/special_defs.hpp \ + /opt/local/include/boost/date_time/time_resolution_traits.hpp \ + /opt/local/include/boost/date_time/int_adapter.hpp \ + /opt/local/include/boost/date_time/gregorian/gregorian_types.hpp \ + /opt/local/include/boost/date_time/date.hpp \ + /opt/local/include/boost/date_time/year_month_day.hpp \ + /opt/local/include/boost/date_time/period.hpp \ + /opt/local/include/boost/date_time/gregorian/greg_calendar.hpp \ + /opt/local/include/boost/date_time/gregorian/greg_weekday.hpp \ + /opt/local/include/boost/date_time/constrained_value.hpp \ + /opt/local/include/boost/type_traits/is_base_of.hpp \ + /opt/local/include/boost/type_traits/is_base_and_derived.hpp \ + /opt/local/include/boost/date_time/date_defs.hpp \ + /opt/local/include/boost/date_time/gregorian/greg_day_of_year.hpp \ + /opt/local/include/boost/date_time/gregorian_calendar.hpp \ + /opt/local/include/boost/date_time/gregorian_calendar.ipp \ + /opt/local/include/boost/date_time/gregorian/greg_ymd.hpp \ + /opt/local/include/boost/date_time/gregorian/greg_day.hpp \ + /opt/local/include/boost/date_time/gregorian/greg_year.hpp \ + /opt/local/include/boost/date_time/gregorian/greg_month.hpp \ + /opt/local/include/boost/date_time/gregorian/greg_duration.hpp \ + /opt/local/include/boost/date_time/date_duration.hpp \ + /opt/local/include/boost/date_time/date_duration_types.hpp \ + /opt/local/include/boost/date_time/gregorian/greg_duration_types.hpp \ + /opt/local/include/boost/date_time/gregorian/greg_date.hpp \ + /opt/local/include/boost/date_time/adjust_functors.hpp \ + /opt/local/include/boost/date_time/wrapping_int.hpp \ + /opt/local/include/boost/date_time/date_generators.hpp \ + /opt/local/include/boost/date_time/date_clock_device.hpp \ + /opt/local/include/boost/date_time/date_iterator.hpp \ + /opt/local/include/boost/date_time/time_system_split.hpp \ + /opt/local/include/boost/date_time/time_system_counted.hpp \ + /opt/local/include/boost/date_time/time.hpp \ + /opt/local/include/boost/date_time/posix_time/date_duration_operators.hpp \ + /opt/local/include/boost/date_time/posix_time/posix_time_duration.hpp \ + /opt/local/include/boost/date_time/posix_time/time_period.hpp \ + /opt/local/include/boost/date_time/time_iterator.hpp \ + /opt/local/include/boost/date_time/dst_rules.hpp \ + /opt/local/include/boost/chrono/time_point.hpp \ + /opt/local/include/boost/chrono/duration.hpp \ + /opt/local/include/boost/chrono/config.hpp \ + /opt/local/include/boost/chrono/detail/static_assert.hpp \ + /opt/local/include/boost/mpl/logical.hpp \ + /opt/local/include/boost/mpl/or.hpp \ + /opt/local/include/boost/mpl/aux_/config/use_preprocessed.hpp \ + /opt/local/include/boost/mpl/aux_/nested_type_wknd.hpp \ + /opt/local/include/boost/mpl/aux_/include_preprocessed.hpp \ + /opt/local/include/boost/mpl/aux_/config/compiler.hpp \ + /opt/local/include/boost/preprocessor/stringize.hpp \ + /opt/local/include/boost/mpl/aux_/preprocessed/gcc/or.hpp \ + /opt/local/include/boost/mpl/and.hpp \ + /opt/local/include/boost/mpl/aux_/preprocessed/gcc/and.hpp \ + /opt/local/include/boost/mpl/not.hpp \ + /opt/local/include/boost/ratio/ratio.hpp \ + /opt/local/include/boost/ratio/config.hpp \ + /opt/local/include/boost/ratio/detail/mpl/abs.hpp \ + /opt/local/include/boost/ratio/detail/mpl/sign.hpp \ + /opt/local/include/boost/ratio/detail/mpl/gcd.hpp \ + /opt/local/include/boost/mpl/aux_/largest_int.hpp \ + /opt/local/include/boost/mpl/aux_/config/dependent_nttp.hpp \ + /opt/local/include/boost/ratio/detail/mpl/lcm.hpp \ + /opt/local/include/boost/integer_traits.hpp \ + /opt/local/include/boost/ratio/ratio_fwd.hpp \ + /opt/local/include/boost/ratio/detail/overflow_helpers.hpp \ + /opt/local/include/boost/type_traits/common_type.hpp \ + /opt/local/include/boost/typeof/typeof.hpp \ + /opt/local/include/boost/typeof/message.hpp \ + /opt/local/include/boost/typeof/native.hpp \ + /opt/local/include/boost/type_traits/is_floating_point.hpp \ + /opt/local/include/boost/type_traits/is_unsigned.hpp \ + /opt/local/include/boost/chrono/detail/is_evenly_divisible_by.hpp \ + /opt/local/include/boost/thread/mutex.hpp \ + /opt/local/include/boost/thread/pthread/mutex.hpp \ + /opt/local/include/boost/thread/xtime.hpp \ + /opt/local/include/boost/date_time/posix_time/conversion.hpp \ + /opt/local/include/boost/date_time/gregorian/conversion.hpp \ + /opt/local/include/boost/thread/pthread/timespec.hpp \ + /opt/local/include/boost/thread/pthread/pthread_mutex_scoped_lock.hpp \ + /opt/local/include/boost/chrono/system_clocks.hpp \ + /opt/local/include/boost/chrono/detail/system.hpp \ + /opt/local/include/boost/version.hpp \ + /opt/local/include/boost/chrono/clock_string.hpp \ + /opt/local/include/boost/chrono/ceil.hpp \ + /opt/local/include/boost/thread/pthread/condition_variable_fwd.hpp \ + /opt/local/include/boost/thread/cv_status.hpp \ + /opt/local/include/boost/detail/scoped_enum_emulation.hpp \ + /opt/local/include/boost/enable_shared_from_this.hpp \ + /opt/local/include/boost/smart_ptr/enable_shared_from_this.hpp \ + /opt/local/include/boost/smart_ptr/weak_ptr.hpp \ + /opt/local/include/boost/optional.hpp \ + /opt/local/include/boost/optional/optional.hpp \ + /opt/local/include/boost/type.hpp \ + /opt/local/include/boost/type_traits/alignment_of.hpp \ + /opt/local/include/boost/type_traits/detail/size_t_trait_def.hpp \ + /opt/local/include/boost/mpl/size_t.hpp \ + /opt/local/include/boost/mpl/size_t_fwd.hpp \ + /opt/local/include/boost/type_traits/detail/size_t_trait_undef.hpp \ + /opt/local/include/boost/type_traits/has_nothrow_constructor.hpp \ + /opt/local/include/boost/type_traits/has_trivial_constructor.hpp \ + /opt/local/include/boost/type_traits/type_with_alignment.hpp \ + /opt/local/include/boost/preprocessor/list/for_each_i.hpp \ + /opt/local/include/boost/preprocessor/repetition/for.hpp \ + /opt/local/include/boost/preprocessor/repetition/detail/for.hpp \ + /opt/local/include/boost/preprocessor/tuple/to_list.hpp \ + /opt/local/include/boost/preprocessor/list/transform.hpp \ + /opt/local/include/boost/preprocessor/list/append.hpp \ + /opt/local/include/boost/detail/reference_content.hpp \ + /opt/local/include/boost/mpl/void.hpp \ + /opt/local/include/boost/none.hpp /opt/local/include/boost/none_t.hpp \ + /opt/local/include/boost/utility/swap.hpp \ + /opt/local/include/boost/utility/addressof.hpp \ + /opt/local/include/boost/utility/compare_pointees.hpp \ + /opt/local/include/boost/utility/in_place_factory.hpp \ + /opt/local/include/boost/utility/detail/in_place_factory_prefix.hpp \ + /opt/local/include/boost/preprocessor/punctuation/paren.hpp \ + /opt/local/include/boost/preprocessor/iteration/iterate.hpp \ + /opt/local/include/boost/preprocessor/array/elem.hpp \ + /opt/local/include/boost/preprocessor/array/data.hpp \ + /opt/local/include/boost/preprocessor/array/size.hpp \ + /opt/local/include/boost/preprocessor/slot/slot.hpp \ + /opt/local/include/boost/preprocessor/slot/detail/def.hpp \ + /opt/local/include/boost/preprocessor/repetition/enum.hpp \ + /opt/local/include/boost/preprocessor/repetition/enum_params.hpp \ + /opt/local/include/boost/preprocessor/repetition/enum_binary_params.hpp \ + /opt/local/include/boost/preprocessor/repetition/enum_trailing_params.hpp \ + /opt/local/include/boost/preprocessor/iteration/detail/iter/forward1.hpp \ + /opt/local/include/boost/preprocessor/iteration/detail/bounds/lower1.hpp \ + /opt/local/include/boost/preprocessor/slot/detail/shared.hpp \ + /opt/local/include/boost/preprocessor/iteration/detail/bounds/upper1.hpp \ + /opt/local/include/boost/utility/detail/in_place_factory_suffix.hpp \ + /opt/local/include/boost/optional/optional_fwd.hpp \ + /opt/local/include/boost/thread/detail/thread.hpp \ + /opt/local/include/boost/thread/detail/thread_heap_alloc.hpp \ + /opt/local/include/boost/thread/pthread/thread_heap_alloc.hpp \ + /opt/local/include/boost/thread/detail/make_tuple_indices.hpp \ + /opt/local/include/boost/thread/detail/invoke.hpp \ + /opt/local/include/boost/thread/detail/is_convertible.hpp \ + /opt/local/include/boost/ref.hpp /opt/local/include/boost/bind.hpp \ + /opt/local/include/boost/bind/bind.hpp \ + /opt/local/include/boost/mem_fn.hpp \ + /opt/local/include/boost/bind/mem_fn.hpp \ + /opt/local/include/boost/get_pointer.hpp \ + /opt/local/include/boost/bind/mem_fn_template.hpp \ + /opt/local/include/boost/bind/mem_fn_cc.hpp \ + /opt/local/include/boost/is_placeholder.hpp \ + /opt/local/include/boost/bind/arg.hpp \ + /opt/local/include/boost/visit_each.hpp \ + /opt/local/include/boost/bind/storage.hpp \ + /opt/local/include/boost/bind/bind_template.hpp \ + /opt/local/include/boost/bind/bind_cc.hpp \ + /opt/local/include/boost/bind/bind_mf_cc.hpp \ + /opt/local/include/boost/bind/bind_mf2_cc.hpp \ + /opt/local/include/boost/bind/placeholders.hpp \ + /opt/local/include/boost/io/ios_state.hpp \ + /opt/local/include/boost/io_fwd.hpp \ + /opt/local/include/boost/functional/hash.hpp \ + /opt/local/include/boost/functional/hash/hash.hpp \ + /opt/local/include/boost/functional/hash/hash_fwd.hpp \ + /opt/local/include/boost/functional/hash/detail/hash_float.hpp \ + /opt/local/include/boost/functional/hash/detail/float_functions.hpp \ + /opt/local/include/boost/functional/hash/detail/limits.hpp \ + /opt/local/include/boost/integer/static_log2.hpp \ + /opt/local/include/boost/integer_fwd.hpp \ + /opt/local/include/boost/functional/hash/extensions.hpp \ + /opt/local/include/boost/detail/container_fwd.hpp \ + /opt/local/include/boost/preprocessor/repetition/repeat_from_to.hpp \ + /opt/local/include/boost/thread/detail/thread_interruption.hpp \ + /opt/local/include/boost/thread/v2/thread.hpp \ + /opt/local/include/boost/thread/condition_variable.hpp \ + /opt/local/include/boost/thread/pthread/condition_variable.hpp \ + /opt/local/include/boost/thread/detail/thread_group.hpp \ + /opt/local/include/boost/thread/shared_mutex.hpp \ + /opt/local/include/boost/thread/pthread/shared_mutex.hpp \ + /opt/local/include/boost/thread/once.hpp \ + /opt/local/include/boost/thread/pthread/once_atomic.hpp \ + /opt/local/include/boost/detail/no_exceptions_support.hpp \ + /opt/local/include/boost/atomic.hpp \ + /opt/local/include/boost/atomic/atomic.hpp \ + /opt/local/include/boost/atomic/detail/config.hpp \ + /opt/local/include/boost/atomic/detail/platform.hpp \ + /opt/local/include/boost/atomic/detail/gcc-atomic.hpp \ + /opt/local/include/boost/atomic/detail/base.hpp \ + /opt/local/include/boost/atomic/detail/lockpool.hpp \ + /opt/local/include/boost/atomic/detail/link.hpp \ + /opt/local/include/boost/atomic/detail/type-classification.hpp \ + /opt/local/include/boost/type_traits/is_signed.hpp \ + /opt/local/include/boost/thread/recursive_mutex.hpp \ + /opt/local/include/boost/thread/pthread/recursive_mutex.hpp \ + /opt/local/include/boost/thread/tss.hpp \ + /opt/local/include/boost/thread/locks.hpp \ + /opt/local/include/boost/thread/lock_algorithms.hpp \ + /opt/local/include/boost/thread/barrier.hpp \ + /opt/local/include/boost/function.hpp \ + /opt/local/include/boost/preprocessor/iterate.hpp \ + /opt/local/include/boost/function/detail/prologue.hpp \ + /opt/local/include/boost/config/no_tr1/functional.hpp \ + /opt/local/include/boost/function/function_base.hpp \ + /opt/local/include/boost/integer.hpp \ + /opt/local/include/boost/type_traits/composite_traits.hpp \ + /opt/local/include/boost/type_traits/is_union.hpp \ + /opt/local/include/boost/function_equal.hpp \ + /opt/local/include/boost/function/function_fwd.hpp \ + /opt/local/include/boost/preprocessor/enum.hpp \ + /opt/local/include/boost/preprocessor/enum_params.hpp \ + /opt/local/include/boost/function/detail/function_iterate.hpp \ + /opt/local/include/boost/function/detail/maybe_include.hpp \ + /opt/local/include/boost/function/function_template.hpp \ + /opt/local/include/boost/utility/result_of.hpp \ + /opt/local/include/boost/preprocessor/repetition/enum_shifted_params.hpp \ + /opt/local/include/boost/preprocessor/facilities/intercept.hpp \ + /opt/local/include/boost/mpl/has_xxx.hpp \ + /opt/local/include/boost/mpl/aux_/type_wrapper.hpp \ + /opt/local/include/boost/mpl/aux_/yes_no.hpp \ + /opt/local/include/boost/mpl/aux_/config/arrays.hpp \ + /opt/local/include/boost/mpl/aux_/config/has_xxx.hpp \ + /opt/local/include/boost/mpl/aux_/config/msvc_typename.hpp \ + /opt/local/include/boost/utility/detail/result_of_iterate.hpp \ + /opt/local/include/boost/thread/future.hpp \ + /opt/local/include/boost/thread/detail/async_func.hpp \ + /opt/local/include/boost/tuple/tuple.hpp \ + /opt/local/include/boost/tuple/detail/tuple_basic.hpp \ + /opt/local/include/boost/type_traits/cv_traits.hpp \ + /opt/local/include/boost/type_traits/add_const.hpp \ + /opt/local/include/boost/type_traits/add_volatile.hpp \ + /opt/local/include/boost/type_traits/add_cv.hpp \ + /opt/local/include/boost/type_traits/remove_const.hpp \ + /opt/local/include/boost/type_traits/remove_volatile.hpp \ + /opt/local/include/boost/type_traits/function_traits.hpp \ + /opt/local/include/boost/exception_ptr.hpp \ + /opt/local/include/boost/exception/detail/exception_ptr.hpp \ + /opt/local/include/boost/scoped_ptr.hpp \ + /opt/local/include/boost/smart_ptr/scoped_ptr.hpp \ + /opt/local/include/boost/type_traits/is_fundamental.hpp \ + /opt/local/include/boost/scoped_array.hpp \ + /opt/local/include/boost/smart_ptr/scoped_array.hpp \ + /opt/local/include/boost/next_prior.hpp \ + /opt/local/include/boost/thread/future_error_code.hpp \ + /opt/local/include/boost/detail/atomic_undef_macros.hpp \ + /opt/local/include/boost/detail/atomic_redef_macros.hpp \ + /opt/local/include/boost/filesystem.hpp \ + /opt/local/include/boost/filesystem/config.hpp \ + /opt/local/include/boost/filesystem/path.hpp \ + /opt/local/include/boost/filesystem/path_traits.hpp \ + /opt/local/include/boost/iterator/iterator_facade.hpp \ + /opt/local/include/boost/iterator/interoperable.hpp \ + /opt/local/include/boost/iterator/detail/config_def.hpp \ + /opt/local/include/boost/iterator/detail/config_undef.hpp \ + /opt/local/include/boost/iterator/iterator_traits.hpp \ + /opt/local/include/boost/detail/iterator.hpp \ + /opt/local/include/boost/iterator/detail/facade_iterator_category.hpp \ + /opt/local/include/boost/iterator/iterator_categories.hpp \ + /opt/local/include/boost/mpl/placeholders.hpp \ + /opt/local/include/boost/mpl/arg.hpp \ + /opt/local/include/boost/mpl/arg_fwd.hpp \ + /opt/local/include/boost/mpl/aux_/na_assert.hpp \ + /opt/local/include/boost/mpl/assert.hpp \ + /opt/local/include/boost/mpl/aux_/config/pp_counter.hpp \ + /opt/local/include/boost/mpl/aux_/arity_spec.hpp \ + /opt/local/include/boost/mpl/aux_/arg_typedef.hpp \ + /opt/local/include/boost/mpl/aux_/preprocessed/gcc/arg.hpp \ + /opt/local/include/boost/mpl/aux_/preprocessed/gcc/placeholders.hpp \ + /opt/local/include/boost/detail/indirect_traits.hpp \ + /opt/local/include/boost/type_traits/remove_pointer.hpp \ + /opt/local/include/boost/iterator/detail/enable_if.hpp \ + /opt/local/include/boost/mpl/always.hpp \ + /opt/local/include/boost/mpl/apply.hpp \ + /opt/local/include/boost/mpl/apply_fwd.hpp \ + /opt/local/include/boost/mpl/aux_/preprocessed/gcc/apply_fwd.hpp \ + /opt/local/include/boost/mpl/apply_wrap.hpp \ + /opt/local/include/boost/mpl/aux_/has_apply.hpp \ + /opt/local/include/boost/mpl/aux_/config/has_apply.hpp \ + /opt/local/include/boost/mpl/aux_/msvc_never_true.hpp \ + /opt/local/include/boost/mpl/aux_/preprocessed/gcc/apply_wrap.hpp \ + /opt/local/include/boost/mpl/lambda.hpp \ + /opt/local/include/boost/mpl/bind.hpp \ + /opt/local/include/boost/mpl/bind_fwd.hpp \ + /opt/local/include/boost/mpl/aux_/config/bind.hpp \ + /opt/local/include/boost/mpl/aux_/preprocessed/gcc/bind_fwd.hpp \ + /opt/local/include/boost/mpl/next.hpp \ + /opt/local/include/boost/mpl/next_prior.hpp \ + /opt/local/include/boost/mpl/aux_/common_name_wknd.hpp \ + /opt/local/include/boost/mpl/protect.hpp \ + /opt/local/include/boost/mpl/aux_/preprocessed/gcc/bind.hpp \ + /opt/local/include/boost/mpl/aux_/full_lambda.hpp \ + /opt/local/include/boost/mpl/quote.hpp \ + /opt/local/include/boost/mpl/aux_/has_type.hpp \ + /opt/local/include/boost/mpl/aux_/config/bcc.hpp \ + /opt/local/include/boost/mpl/aux_/preprocessed/gcc/quote.hpp \ + /opt/local/include/boost/mpl/aux_/template_arity.hpp \ + /opt/local/include/boost/mpl/aux_/preprocessed/gcc/template_arity.hpp \ + /opt/local/include/boost/mpl/aux_/preprocessed/gcc/full_lambda.hpp \ + /opt/local/include/boost/mpl/aux_/preprocessed/gcc/apply.hpp \ + /opt/local/include/boost/io/detail/quoted_manip.hpp \ + /opt/local/include/boost/functional/hash_fwd.hpp \ + /opt/local/include/boost/filesystem/operations.hpp \ + /opt/local/include/boost/detail/bitmask.hpp \ + /opt/local/include/boost/filesystem/convenience.hpp \ + /opt/local/include/openssl/sha.h /opt/local/include/openssl/e_os2.h \ + /opt/local/include/openssl/opensslconf.h \ + /opt/local/include/openssl/ripemd.h \ + /path/to/triangles/src/netbase.h \ + /path/to/triangles/src/serialize.h \ + /opt/local/include/boost/tuple/tuple_comparison.hpp \ + /opt/local/include/boost/tuple/tuple_io.hpp \ + /path/to/triangles/src/allocators.h \ + /path/to/triangles/src/version.h \ + /path/to/triangles/src/clientversion.h \ + /path/to/triangles/src/compat.h +tor/anonymize.cpp : + /path/to/triangles/src/tor/anonymize.h : + /path/to/triangles/src/util.h : + /path/to/triangles/src/uint256.h : + /opt/local/include/boost/thread.hpp : + /opt/local/include/boost/thread/thread.hpp : + /opt/local/include/boost/thread/thread_only.hpp : + /opt/local/include/boost/thread/detail/platform.hpp : + /opt/local/include/boost/config.hpp : + /opt/local/include/boost/config/user.hpp : + /opt/local/include/boost/config/select_compiler_config.hpp : + /opt/local/include/boost/config/compiler/clang.hpp : + /opt/local/include/boost/config/select_stdlib_config.hpp : + /opt/local/include/boost/config/no_tr1/utility.hpp : + /opt/local/include/boost/config/stdlib/libstdcpp3.hpp : + /opt/local/include/boost/config/select_platform_config.hpp : + /opt/local/include/boost/config/platform/macos.hpp : + /opt/local/include/boost/config/posix_features.hpp : + /opt/local/include/boost/config/suffix.hpp : + /opt/local/include/boost/config/requires_threads.hpp : + /opt/local/include/boost/thread/pthread/thread_data.hpp : + /opt/local/include/boost/thread/detail/config.hpp : + /opt/local/include/boost/detail/workaround.hpp : + /opt/local/include/boost/config/auto_link.hpp : + /opt/local/include/boost/thread/exceptions.hpp : + /opt/local/include/boost/system/system_error.hpp : + /opt/local/include/boost/system/error_code.hpp : + /opt/local/include/boost/system/config.hpp : + /opt/local/include/boost/system/api_config.hpp : + /opt/local/include/boost/cstdint.hpp : + /opt/local/include/boost/assert.hpp : + /opt/local/include/boost/current_function.hpp : + /opt/local/include/boost/operators.hpp : + /opt/local/include/boost/iterator.hpp : + /opt/local/include/boost/noncopyable.hpp : + /opt/local/include/boost/utility/enable_if.hpp : + /opt/local/include/boost/cerrno.hpp : + /opt/local/include/boost/config/abi_prefix.hpp : + /opt/local/include/boost/config/abi_suffix.hpp : + /opt/local/include/boost/thread/lock_guard.hpp : + /opt/local/include/boost/thread/detail/delete.hpp : + /opt/local/include/boost/thread/detail/move.hpp : + /opt/local/include/boost/type_traits/is_convertible.hpp : + /opt/local/include/boost/type_traits/intrinsics.hpp : + /opt/local/include/boost/type_traits/config.hpp : + /opt/local/include/boost/type_traits/is_same.hpp : + /opt/local/include/boost/type_traits/detail/bool_trait_def.hpp : + /opt/local/include/boost/type_traits/detail/template_arity_spec.hpp : + /opt/local/include/boost/mpl/int.hpp : + /opt/local/include/boost/mpl/int_fwd.hpp : + /opt/local/include/boost/mpl/aux_/adl_barrier.hpp : + /opt/local/include/boost/mpl/aux_/config/adl.hpp : + /opt/local/include/boost/mpl/aux_/config/msvc.hpp : + /opt/local/include/boost/mpl/aux_/config/intel.hpp : + /opt/local/include/boost/mpl/aux_/config/gcc.hpp : + /opt/local/include/boost/mpl/aux_/config/workaround.hpp : + /opt/local/include/boost/mpl/aux_/nttp_decl.hpp : + /opt/local/include/boost/mpl/aux_/config/nttp.hpp : + /opt/local/include/boost/mpl/aux_/integral_wrapper.hpp : + /opt/local/include/boost/mpl/integral_c_tag.hpp : + /opt/local/include/boost/mpl/aux_/config/static_constant.hpp : + /opt/local/include/boost/mpl/aux_/static_cast.hpp : + /opt/local/include/boost/preprocessor/cat.hpp : + /opt/local/include/boost/preprocessor/config/config.hpp : + /opt/local/include/boost/mpl/aux_/template_arity_fwd.hpp : + /opt/local/include/boost/mpl/aux_/preprocessor/params.hpp : + /opt/local/include/boost/mpl/aux_/config/preprocessor.hpp : + /opt/local/include/boost/preprocessor/comma_if.hpp : + /opt/local/include/boost/preprocessor/punctuation/comma_if.hpp : + /opt/local/include/boost/preprocessor/control/if.hpp : + /opt/local/include/boost/preprocessor/control/iif.hpp : + /opt/local/include/boost/preprocessor/logical/bool.hpp : + /opt/local/include/boost/preprocessor/facilities/empty.hpp : + /opt/local/include/boost/preprocessor/punctuation/comma.hpp : + /opt/local/include/boost/preprocessor/repeat.hpp : + /opt/local/include/boost/preprocessor/repetition/repeat.hpp : + /opt/local/include/boost/preprocessor/debug/error.hpp : + /opt/local/include/boost/preprocessor/detail/auto_rec.hpp : + /opt/local/include/boost/preprocessor/tuple/eat.hpp : + /opt/local/include/boost/preprocessor/inc.hpp : + /opt/local/include/boost/preprocessor/arithmetic/inc.hpp : + /opt/local/include/boost/mpl/aux_/config/lambda.hpp : + /opt/local/include/boost/mpl/aux_/config/ttp.hpp : + /opt/local/include/boost/mpl/aux_/config/ctps.hpp : + /opt/local/include/boost/mpl/aux_/config/overload_resolution.hpp : + /opt/local/include/boost/type_traits/integral_constant.hpp : + /opt/local/include/boost/mpl/bool.hpp : + /opt/local/include/boost/mpl/bool_fwd.hpp : + /opt/local/include/boost/mpl/integral_c.hpp : + /opt/local/include/boost/mpl/integral_c_fwd.hpp : + /opt/local/include/boost/mpl/aux_/lambda_support.hpp : + /opt/local/include/boost/type_traits/detail/bool_trait_undef.hpp : + /opt/local/include/boost/type_traits/is_reference.hpp : + /opt/local/include/boost/type_traits/is_lvalue_reference.hpp : + /opt/local/include/boost/type_traits/is_rvalue_reference.hpp : + /opt/local/include/boost/type_traits/ice.hpp : + /opt/local/include/boost/type_traits/detail/yes_no_type.hpp : + /opt/local/include/boost/type_traits/detail/ice_or.hpp : + /opt/local/include/boost/type_traits/detail/ice_and.hpp : + /opt/local/include/boost/type_traits/detail/ice_not.hpp : + /opt/local/include/boost/type_traits/detail/ice_eq.hpp : + /opt/local/include/boost/type_traits/is_volatile.hpp : + /opt/local/include/boost/type_traits/detail/cv_traits_impl.hpp : + /opt/local/include/boost/type_traits/is_abstract.hpp : + /opt/local/include/boost/type_traits/remove_reference.hpp : + /opt/local/include/boost/type_traits/broken_compiler_spec.hpp : + /opt/local/include/boost/type_traits/detail/type_trait_def.hpp : + /opt/local/include/boost/type_traits/detail/type_trait_undef.hpp : + /opt/local/include/boost/type_traits/remove_cv.hpp : + /opt/local/include/boost/type_traits/decay.hpp : + /opt/local/include/boost/type_traits/is_array.hpp : + /opt/local/include/boost/type_traits/is_function.hpp : + /opt/local/include/boost/type_traits/detail/false_result.hpp : + /opt/local/include/boost/type_traits/detail/is_function_ptr_helper.hpp : + /opt/local/include/boost/type_traits/remove_bounds.hpp : + /opt/local/include/boost/type_traits/add_pointer.hpp : + /opt/local/include/boost/mpl/eval_if.hpp : + /opt/local/include/boost/mpl/if.hpp : + /opt/local/include/boost/mpl/aux_/value_wknd.hpp : + /opt/local/include/boost/mpl/aux_/config/integral.hpp : + /opt/local/include/boost/mpl/aux_/config/eti.hpp : + /opt/local/include/boost/mpl/aux_/na_spec.hpp : + /opt/local/include/boost/mpl/lambda_fwd.hpp : + /opt/local/include/boost/mpl/void_fwd.hpp : + /opt/local/include/boost/mpl/aux_/na.hpp : + /opt/local/include/boost/mpl/aux_/na_fwd.hpp : + /opt/local/include/boost/mpl/aux_/lambda_arity_param.hpp : + /opt/local/include/boost/mpl/aux_/arity.hpp : + /opt/local/include/boost/mpl/aux_/config/dtp.hpp : + /opt/local/include/boost/mpl/aux_/preprocessor/enum.hpp : + /opt/local/include/boost/mpl/aux_/preprocessor/def_params_tail.hpp : + /opt/local/include/boost/mpl/limits/arity.hpp : + /opt/local/include/boost/preprocessor/logical/and.hpp : + /opt/local/include/boost/preprocessor/logical/bitand.hpp : + /opt/local/include/boost/preprocessor/identity.hpp : + /opt/local/include/boost/preprocessor/facilities/identity.hpp : + /opt/local/include/boost/preprocessor/empty.hpp : + /opt/local/include/boost/preprocessor/arithmetic/add.hpp : + /opt/local/include/boost/preprocessor/arithmetic/dec.hpp : + /opt/local/include/boost/preprocessor/control/while.hpp : + /opt/local/include/boost/preprocessor/list/fold_left.hpp : + /opt/local/include/boost/preprocessor/list/detail/fold_left.hpp : + /opt/local/include/boost/preprocessor/control/expr_iif.hpp : + /opt/local/include/boost/preprocessor/list/adt.hpp : + /opt/local/include/boost/preprocessor/detail/is_binary.hpp : + /opt/local/include/boost/preprocessor/detail/check.hpp : + /opt/local/include/boost/preprocessor/logical/compl.hpp : + /opt/local/include/boost/preprocessor/list/fold_right.hpp : + /opt/local/include/boost/preprocessor/list/detail/fold_right.hpp : + /opt/local/include/boost/preprocessor/list/reverse.hpp : + /opt/local/include/boost/preprocessor/control/detail/while.hpp : + /opt/local/include/boost/preprocessor/tuple/elem.hpp : + /opt/local/include/boost/preprocessor/facilities/overload.hpp : + /opt/local/include/boost/preprocessor/variadic/size.hpp : + /opt/local/include/boost/preprocessor/tuple/rem.hpp : + /opt/local/include/boost/preprocessor/variadic/elem.hpp : + /opt/local/include/boost/preprocessor/arithmetic/sub.hpp : + /opt/local/include/boost/mpl/identity.hpp : + /opt/local/include/boost/move/utility.hpp : + /opt/local/include/boost/move/detail/config_begin.hpp : + /opt/local/include/boost/move/core.hpp : + /opt/local/include/boost/move/detail/meta_utils.hpp : + /opt/local/include/boost/move/detail/config_end.hpp : + /opt/local/include/boost/move/traits.hpp : + /opt/local/include/boost/type_traits/has_trivial_destructor.hpp : + /opt/local/include/boost/type_traits/is_pod.hpp : + /opt/local/include/boost/type_traits/is_void.hpp : + /opt/local/include/boost/type_traits/is_scalar.hpp : + /opt/local/include/boost/type_traits/is_arithmetic.hpp : + /opt/local/include/boost/type_traits/is_integral.hpp : + /opt/local/include/boost/type_traits/is_float.hpp : + /opt/local/include/boost/type_traits/is_enum.hpp : + /opt/local/include/boost/type_traits/is_pointer.hpp : + /opt/local/include/boost/type_traits/is_member_pointer.hpp : + /opt/local/include/boost/type_traits/is_member_function_pointer.hpp : + /opt/local/include/boost/type_traits/detail/is_mem_fun_pointer_impl.hpp : + /opt/local/include/boost/type_traits/is_nothrow_move_constructible.hpp : + /opt/local/include/boost/type_traits/has_trivial_move_constructor.hpp : + /opt/local/include/boost/type_traits/has_nothrow_copy.hpp : + /opt/local/include/boost/type_traits/has_trivial_copy.hpp : + /opt/local/include/boost/utility/declval.hpp : + /opt/local/include/boost/type_traits/add_rvalue_reference.hpp : + /opt/local/include/boost/type_traits/is_nothrow_move_assignable.hpp : + /opt/local/include/boost/type_traits/has_trivial_move_assign.hpp : + /opt/local/include/boost/type_traits/is_const.hpp : + /opt/local/include/boost/type_traits/has_nothrow_assign.hpp : + /opt/local/include/boost/type_traits/has_trivial_assign.hpp : + /opt/local/include/boost/thread/detail/lockable_wrapper.hpp : + /opt/local/include/boost/thread/lock_options.hpp : + /opt/local/include/boost/thread/lock_types.hpp : + /opt/local/include/boost/thread/lockable_traits.hpp : + /opt/local/include/boost/type_traits/is_class.hpp : + /opt/local/include/boost/thread/thread_time.hpp : + /opt/local/include/boost/date_time/time_clock.hpp : + /opt/local/include/boost/date_time/c_time.hpp : + /opt/local/include/boost/throw_exception.hpp : + /opt/local/include/boost/date_time/compiler_config.hpp : + /opt/local/include/boost/date_time/locale_config.hpp : + /opt/local/include/boost/shared_ptr.hpp : + /opt/local/include/boost/smart_ptr/shared_ptr.hpp : + /opt/local/include/boost/config/no_tr1/memory.hpp : + /opt/local/include/boost/checked_delete.hpp : + /opt/local/include/boost/smart_ptr/detail/shared_count.hpp : + /opt/local/include/boost/smart_ptr/bad_weak_ptr.hpp : + /opt/local/include/boost/smart_ptr/detail/sp_counted_base.hpp : + /opt/local/include/boost/smart_ptr/detail/sp_has_sync.hpp : + /opt/local/include/boost/smart_ptr/detail/sp_counted_base_gcc_x86.hpp : + /opt/local/include/boost/detail/sp_typeinfo.hpp : + /opt/local/include/boost/smart_ptr/detail/sp_counted_impl.hpp : + /opt/local/include/boost/smart_ptr/detail/sp_convertible.hpp : + /opt/local/include/boost/smart_ptr/detail/sp_nullptr_t.hpp : + /opt/local/include/boost/smart_ptr/detail/spinlock_pool.hpp : + /opt/local/include/boost/smart_ptr/detail/spinlock.hpp : + /opt/local/include/boost/smart_ptr/detail/spinlock_sync.hpp : + /opt/local/include/boost/smart_ptr/detail/yield_k.hpp : + /opt/local/include/boost/memory_order.hpp : + /opt/local/include/boost/smart_ptr/detail/operator_bool.hpp : + /opt/local/include/boost/date_time/microsec_time_clock.hpp : + /opt/local/include/boost/date_time/filetime_functions.hpp : + /opt/local/include/boost/date_time/posix_time/posix_time_types.hpp : + /opt/local/include/boost/date_time/posix_time/ptime.hpp : + /opt/local/include/boost/date_time/posix_time/posix_time_system.hpp : + /opt/local/include/boost/date_time/posix_time/posix_time_config.hpp : + /opt/local/include/boost/limits.hpp : + /opt/local/include/boost/config/no_tr1/cmath.hpp : + /opt/local/include/boost/date_time/time_duration.hpp : + /opt/local/include/boost/static_assert.hpp : + /opt/local/include/boost/date_time/time_defs.hpp : + /opt/local/include/boost/date_time/special_defs.hpp : + /opt/local/include/boost/date_time/time_resolution_traits.hpp : + /opt/local/include/boost/date_time/int_adapter.hpp : + /opt/local/include/boost/date_time/gregorian/gregorian_types.hpp : + /opt/local/include/boost/date_time/date.hpp : + /opt/local/include/boost/date_time/year_month_day.hpp : + /opt/local/include/boost/date_time/period.hpp : + /opt/local/include/boost/date_time/gregorian/greg_calendar.hpp : + /opt/local/include/boost/date_time/gregorian/greg_weekday.hpp : + /opt/local/include/boost/date_time/constrained_value.hpp : + /opt/local/include/boost/type_traits/is_base_of.hpp : + /opt/local/include/boost/type_traits/is_base_and_derived.hpp : + /opt/local/include/boost/date_time/date_defs.hpp : + /opt/local/include/boost/date_time/gregorian/greg_day_of_year.hpp : + /opt/local/include/boost/date_time/gregorian_calendar.hpp : + /opt/local/include/boost/date_time/gregorian_calendar.ipp : + /opt/local/include/boost/date_time/gregorian/greg_ymd.hpp : + /opt/local/include/boost/date_time/gregorian/greg_day.hpp : + /opt/local/include/boost/date_time/gregorian/greg_year.hpp : + /opt/local/include/boost/date_time/gregorian/greg_month.hpp : + /opt/local/include/boost/date_time/gregorian/greg_duration.hpp : + /opt/local/include/boost/date_time/date_duration.hpp : + /opt/local/include/boost/date_time/date_duration_types.hpp : + /opt/local/include/boost/date_time/gregorian/greg_duration_types.hpp : + /opt/local/include/boost/date_time/gregorian/greg_date.hpp : + /opt/local/include/boost/date_time/adjust_functors.hpp : + /opt/local/include/boost/date_time/wrapping_int.hpp : + /opt/local/include/boost/date_time/date_generators.hpp : + /opt/local/include/boost/date_time/date_clock_device.hpp : + /opt/local/include/boost/date_time/date_iterator.hpp : + /opt/local/include/boost/date_time/time_system_split.hpp : + /opt/local/include/boost/date_time/time_system_counted.hpp : + /opt/local/include/boost/date_time/time.hpp : + /opt/local/include/boost/date_time/posix_time/date_duration_operators.hpp : + /opt/local/include/boost/date_time/posix_time/posix_time_duration.hpp : + /opt/local/include/boost/date_time/posix_time/time_period.hpp : + /opt/local/include/boost/date_time/time_iterator.hpp : + /opt/local/include/boost/date_time/dst_rules.hpp : + /opt/local/include/boost/chrono/time_point.hpp : + /opt/local/include/boost/chrono/duration.hpp : + /opt/local/include/boost/chrono/config.hpp : + /opt/local/include/boost/chrono/detail/static_assert.hpp : + /opt/local/include/boost/mpl/logical.hpp : + /opt/local/include/boost/mpl/or.hpp : + /opt/local/include/boost/mpl/aux_/config/use_preprocessed.hpp : + /opt/local/include/boost/mpl/aux_/nested_type_wknd.hpp : + /opt/local/include/boost/mpl/aux_/include_preprocessed.hpp : + /opt/local/include/boost/mpl/aux_/config/compiler.hpp : + /opt/local/include/boost/preprocessor/stringize.hpp : + /opt/local/include/boost/mpl/aux_/preprocessed/gcc/or.hpp : + /opt/local/include/boost/mpl/and.hpp : + /opt/local/include/boost/mpl/aux_/preprocessed/gcc/and.hpp : + /opt/local/include/boost/mpl/not.hpp : + /opt/local/include/boost/ratio/ratio.hpp : + /opt/local/include/boost/ratio/config.hpp : + /opt/local/include/boost/ratio/detail/mpl/abs.hpp : + /opt/local/include/boost/ratio/detail/mpl/sign.hpp : + /opt/local/include/boost/ratio/detail/mpl/gcd.hpp : + /opt/local/include/boost/mpl/aux_/largest_int.hpp : + /opt/local/include/boost/mpl/aux_/config/dependent_nttp.hpp : + /opt/local/include/boost/ratio/detail/mpl/lcm.hpp : + /opt/local/include/boost/integer_traits.hpp : + /opt/local/include/boost/ratio/ratio_fwd.hpp : + /opt/local/include/boost/ratio/detail/overflow_helpers.hpp : + /opt/local/include/boost/type_traits/common_type.hpp : + /opt/local/include/boost/typeof/typeof.hpp : + /opt/local/include/boost/typeof/message.hpp : + /opt/local/include/boost/typeof/native.hpp : + /opt/local/include/boost/type_traits/is_floating_point.hpp : + /opt/local/include/boost/type_traits/is_unsigned.hpp : + /opt/local/include/boost/chrono/detail/is_evenly_divisible_by.hpp : + /opt/local/include/boost/thread/mutex.hpp : + /opt/local/include/boost/thread/pthread/mutex.hpp : + /opt/local/include/boost/thread/xtime.hpp : + /opt/local/include/boost/date_time/posix_time/conversion.hpp : + /opt/local/include/boost/date_time/gregorian/conversion.hpp : + /opt/local/include/boost/thread/pthread/timespec.hpp : + /opt/local/include/boost/thread/pthread/pthread_mutex_scoped_lock.hpp : + /opt/local/include/boost/chrono/system_clocks.hpp : + /opt/local/include/boost/chrono/detail/system.hpp : + /opt/local/include/boost/version.hpp : + /opt/local/include/boost/chrono/clock_string.hpp : + /opt/local/include/boost/chrono/ceil.hpp : + /opt/local/include/boost/thread/pthread/condition_variable_fwd.hpp : + /opt/local/include/boost/thread/cv_status.hpp : + /opt/local/include/boost/detail/scoped_enum_emulation.hpp : + /opt/local/include/boost/enable_shared_from_this.hpp : + /opt/local/include/boost/smart_ptr/enable_shared_from_this.hpp : + /opt/local/include/boost/smart_ptr/weak_ptr.hpp : + /opt/local/include/boost/optional.hpp : + /opt/local/include/boost/optional/optional.hpp : + /opt/local/include/boost/type.hpp : + /opt/local/include/boost/type_traits/alignment_of.hpp : + /opt/local/include/boost/type_traits/detail/size_t_trait_def.hpp : + /opt/local/include/boost/mpl/size_t.hpp : + /opt/local/include/boost/mpl/size_t_fwd.hpp : + /opt/local/include/boost/type_traits/detail/size_t_trait_undef.hpp : + /opt/local/include/boost/type_traits/has_nothrow_constructor.hpp : + /opt/local/include/boost/type_traits/has_trivial_constructor.hpp : + /opt/local/include/boost/type_traits/type_with_alignment.hpp : + /opt/local/include/boost/preprocessor/list/for_each_i.hpp : + /opt/local/include/boost/preprocessor/repetition/for.hpp : + /opt/local/include/boost/preprocessor/repetition/detail/for.hpp : + /opt/local/include/boost/preprocessor/tuple/to_list.hpp : + /opt/local/include/boost/preprocessor/list/transform.hpp : + /opt/local/include/boost/preprocessor/list/append.hpp : + /opt/local/include/boost/detail/reference_content.hpp : + /opt/local/include/boost/mpl/void.hpp : + /opt/local/include/boost/none.hpp /opt/local/include/boost/none_t.hpp : + /opt/local/include/boost/utility/swap.hpp : + /opt/local/include/boost/utility/addressof.hpp : + /opt/local/include/boost/utility/compare_pointees.hpp : + /opt/local/include/boost/utility/in_place_factory.hpp : + /opt/local/include/boost/utility/detail/in_place_factory_prefix.hpp : + /opt/local/include/boost/preprocessor/punctuation/paren.hpp : + /opt/local/include/boost/preprocessor/iteration/iterate.hpp : + /opt/local/include/boost/preprocessor/array/elem.hpp : + /opt/local/include/boost/preprocessor/array/data.hpp : + /opt/local/include/boost/preprocessor/array/size.hpp : + /opt/local/include/boost/preprocessor/slot/slot.hpp : + /opt/local/include/boost/preprocessor/slot/detail/def.hpp : + /opt/local/include/boost/preprocessor/repetition/enum.hpp : + /opt/local/include/boost/preprocessor/repetition/enum_params.hpp : + /opt/local/include/boost/preprocessor/repetition/enum_binary_params.hpp : + /opt/local/include/boost/preprocessor/repetition/enum_trailing_params.hpp : + /opt/local/include/boost/preprocessor/iteration/detail/iter/forward1.hpp : + /opt/local/include/boost/preprocessor/iteration/detail/bounds/lower1.hpp : + /opt/local/include/boost/preprocessor/slot/detail/shared.hpp : + /opt/local/include/boost/preprocessor/iteration/detail/bounds/upper1.hpp : + /opt/local/include/boost/utility/detail/in_place_factory_suffix.hpp : + /opt/local/include/boost/optional/optional_fwd.hpp : + /opt/local/include/boost/thread/detail/thread.hpp : + /opt/local/include/boost/thread/detail/thread_heap_alloc.hpp : + /opt/local/include/boost/thread/pthread/thread_heap_alloc.hpp : + /opt/local/include/boost/thread/detail/make_tuple_indices.hpp : + /opt/local/include/boost/thread/detail/invoke.hpp : + /opt/local/include/boost/thread/detail/is_convertible.hpp : + /opt/local/include/boost/ref.hpp /opt/local/include/boost/bind.hpp : + /opt/local/include/boost/bind/bind.hpp : + /opt/local/include/boost/mem_fn.hpp : + /opt/local/include/boost/bind/mem_fn.hpp : + /opt/local/include/boost/get_pointer.hpp : + /opt/local/include/boost/bind/mem_fn_template.hpp : + /opt/local/include/boost/bind/mem_fn_cc.hpp : + /opt/local/include/boost/is_placeholder.hpp : + /opt/local/include/boost/bind/arg.hpp : + /opt/local/include/boost/visit_each.hpp : + /opt/local/include/boost/bind/storage.hpp : + /opt/local/include/boost/bind/bind_template.hpp : + /opt/local/include/boost/bind/bind_cc.hpp : + /opt/local/include/boost/bind/bind_mf_cc.hpp : + /opt/local/include/boost/bind/bind_mf2_cc.hpp : + /opt/local/include/boost/bind/placeholders.hpp : + /opt/local/include/boost/io/ios_state.hpp : + /opt/local/include/boost/io_fwd.hpp : + /opt/local/include/boost/functional/hash.hpp : + /opt/local/include/boost/functional/hash/hash.hpp : + /opt/local/include/boost/functional/hash/hash_fwd.hpp : + /opt/local/include/boost/functional/hash/detail/hash_float.hpp : + /opt/local/include/boost/functional/hash/detail/float_functions.hpp : + /opt/local/include/boost/functional/hash/detail/limits.hpp : + /opt/local/include/boost/integer/static_log2.hpp : + /opt/local/include/boost/integer_fwd.hpp : + /opt/local/include/boost/functional/hash/extensions.hpp : + /opt/local/include/boost/detail/container_fwd.hpp : + /opt/local/include/boost/preprocessor/repetition/repeat_from_to.hpp : + /opt/local/include/boost/thread/detail/thread_interruption.hpp : + /opt/local/include/boost/thread/v2/thread.hpp : + /opt/local/include/boost/thread/condition_variable.hpp : + /opt/local/include/boost/thread/pthread/condition_variable.hpp : + /opt/local/include/boost/thread/detail/thread_group.hpp : + /opt/local/include/boost/thread/shared_mutex.hpp : + /opt/local/include/boost/thread/pthread/shared_mutex.hpp : + /opt/local/include/boost/thread/once.hpp : + /opt/local/include/boost/thread/pthread/once_atomic.hpp : + /opt/local/include/boost/detail/no_exceptions_support.hpp : + /opt/local/include/boost/atomic.hpp : + /opt/local/include/boost/atomic/atomic.hpp : + /opt/local/include/boost/atomic/detail/config.hpp : + /opt/local/include/boost/atomic/detail/platform.hpp : + /opt/local/include/boost/atomic/detail/gcc-atomic.hpp : + /opt/local/include/boost/atomic/detail/base.hpp : + /opt/local/include/boost/atomic/detail/lockpool.hpp : + /opt/local/include/boost/atomic/detail/link.hpp : + /opt/local/include/boost/atomic/detail/type-classification.hpp : + /opt/local/include/boost/type_traits/is_signed.hpp : + /opt/local/include/boost/thread/recursive_mutex.hpp : + /opt/local/include/boost/thread/pthread/recursive_mutex.hpp : + /opt/local/include/boost/thread/tss.hpp : + /opt/local/include/boost/thread/locks.hpp : + /opt/local/include/boost/thread/lock_algorithms.hpp : + /opt/local/include/boost/thread/barrier.hpp : + /opt/local/include/boost/function.hpp : + /opt/local/include/boost/preprocessor/iterate.hpp : + /opt/local/include/boost/function/detail/prologue.hpp : + /opt/local/include/boost/config/no_tr1/functional.hpp : + /opt/local/include/boost/function/function_base.hpp : + /opt/local/include/boost/integer.hpp : + /opt/local/include/boost/type_traits/composite_traits.hpp : + /opt/local/include/boost/type_traits/is_union.hpp : + /opt/local/include/boost/function_equal.hpp : + /opt/local/include/boost/function/function_fwd.hpp : + /opt/local/include/boost/preprocessor/enum.hpp : + /opt/local/include/boost/preprocessor/enum_params.hpp : + /opt/local/include/boost/function/detail/function_iterate.hpp : + /opt/local/include/boost/function/detail/maybe_include.hpp : + /opt/local/include/boost/function/function_template.hpp : + /opt/local/include/boost/utility/result_of.hpp : + /opt/local/include/boost/preprocessor/repetition/enum_shifted_params.hpp : + /opt/local/include/boost/preprocessor/facilities/intercept.hpp : + /opt/local/include/boost/mpl/has_xxx.hpp : + /opt/local/include/boost/mpl/aux_/type_wrapper.hpp : + /opt/local/include/boost/mpl/aux_/yes_no.hpp : + /opt/local/include/boost/mpl/aux_/config/arrays.hpp : + /opt/local/include/boost/mpl/aux_/config/has_xxx.hpp : + /opt/local/include/boost/mpl/aux_/config/msvc_typename.hpp : + /opt/local/include/boost/utility/detail/result_of_iterate.hpp : + /opt/local/include/boost/thread/future.hpp : + /opt/local/include/boost/thread/detail/async_func.hpp : + /opt/local/include/boost/tuple/tuple.hpp : + /opt/local/include/boost/tuple/detail/tuple_basic.hpp : + /opt/local/include/boost/type_traits/cv_traits.hpp : + /opt/local/include/boost/type_traits/add_const.hpp : + /opt/local/include/boost/type_traits/add_volatile.hpp : + /opt/local/include/boost/type_traits/add_cv.hpp : + /opt/local/include/boost/type_traits/remove_const.hpp : + /opt/local/include/boost/type_traits/remove_volatile.hpp : + /opt/local/include/boost/type_traits/function_traits.hpp : + /opt/local/include/boost/exception_ptr.hpp : + /opt/local/include/boost/exception/detail/exception_ptr.hpp : + /opt/local/include/boost/scoped_ptr.hpp : + /opt/local/include/boost/smart_ptr/scoped_ptr.hpp : + /opt/local/include/boost/type_traits/is_fundamental.hpp : + /opt/local/include/boost/scoped_array.hpp : + /opt/local/include/boost/smart_ptr/scoped_array.hpp : + /opt/local/include/boost/next_prior.hpp : + /opt/local/include/boost/thread/future_error_code.hpp : + /opt/local/include/boost/detail/atomic_undef_macros.hpp : + /opt/local/include/boost/detail/atomic_redef_macros.hpp : + /opt/local/include/boost/filesystem.hpp : + /opt/local/include/boost/filesystem/config.hpp : + /opt/local/include/boost/filesystem/path.hpp : + /opt/local/include/boost/filesystem/path_traits.hpp : + /opt/local/include/boost/iterator/iterator_facade.hpp : + /opt/local/include/boost/iterator/interoperable.hpp : + /opt/local/include/boost/iterator/detail/config_def.hpp : + /opt/local/include/boost/iterator/detail/config_undef.hpp : + /opt/local/include/boost/iterator/iterator_traits.hpp : + /opt/local/include/boost/detail/iterator.hpp : + /opt/local/include/boost/iterator/detail/facade_iterator_category.hpp : + /opt/local/include/boost/iterator/iterator_categories.hpp : + /opt/local/include/boost/mpl/placeholders.hpp : + /opt/local/include/boost/mpl/arg.hpp : + /opt/local/include/boost/mpl/arg_fwd.hpp : + /opt/local/include/boost/mpl/aux_/na_assert.hpp : + /opt/local/include/boost/mpl/assert.hpp : + /opt/local/include/boost/mpl/aux_/config/pp_counter.hpp : + /opt/local/include/boost/mpl/aux_/arity_spec.hpp : + /opt/local/include/boost/mpl/aux_/arg_typedef.hpp : + /opt/local/include/boost/mpl/aux_/preprocessed/gcc/arg.hpp : + /opt/local/include/boost/mpl/aux_/preprocessed/gcc/placeholders.hpp : + /opt/local/include/boost/detail/indirect_traits.hpp : + /opt/local/include/boost/type_traits/remove_pointer.hpp : + /opt/local/include/boost/iterator/detail/enable_if.hpp : + /opt/local/include/boost/mpl/always.hpp : + /opt/local/include/boost/mpl/apply.hpp : + /opt/local/include/boost/mpl/apply_fwd.hpp : + /opt/local/include/boost/mpl/aux_/preprocessed/gcc/apply_fwd.hpp : + /opt/local/include/boost/mpl/apply_wrap.hpp : + /opt/local/include/boost/mpl/aux_/has_apply.hpp : + /opt/local/include/boost/mpl/aux_/config/has_apply.hpp : + /opt/local/include/boost/mpl/aux_/msvc_never_true.hpp : + /opt/local/include/boost/mpl/aux_/preprocessed/gcc/apply_wrap.hpp : + /opt/local/include/boost/mpl/lambda.hpp : + /opt/local/include/boost/mpl/bind.hpp : + /opt/local/include/boost/mpl/bind_fwd.hpp : + /opt/local/include/boost/mpl/aux_/config/bind.hpp : + /opt/local/include/boost/mpl/aux_/preprocessed/gcc/bind_fwd.hpp : + /opt/local/include/boost/mpl/next.hpp : + /opt/local/include/boost/mpl/next_prior.hpp : + /opt/local/include/boost/mpl/aux_/common_name_wknd.hpp : + /opt/local/include/boost/mpl/protect.hpp : + /opt/local/include/boost/mpl/aux_/preprocessed/gcc/bind.hpp : + /opt/local/include/boost/mpl/aux_/full_lambda.hpp : + /opt/local/include/boost/mpl/quote.hpp : + /opt/local/include/boost/mpl/aux_/has_type.hpp : + /opt/local/include/boost/mpl/aux_/config/bcc.hpp : + /opt/local/include/boost/mpl/aux_/preprocessed/gcc/quote.hpp : + /opt/local/include/boost/mpl/aux_/template_arity.hpp : + /opt/local/include/boost/mpl/aux_/preprocessed/gcc/template_arity.hpp : + /opt/local/include/boost/mpl/aux_/preprocessed/gcc/full_lambda.hpp : + /opt/local/include/boost/mpl/aux_/preprocessed/gcc/apply.hpp : + /opt/local/include/boost/io/detail/quoted_manip.hpp : + /opt/local/include/boost/functional/hash_fwd.hpp : + /opt/local/include/boost/filesystem/operations.hpp : + /opt/local/include/boost/detail/bitmask.hpp : + /opt/local/include/boost/filesystem/convenience.hpp : + /opt/local/include/openssl/sha.h /opt/local/include/openssl/e_os2.h : + /opt/local/include/openssl/opensslconf.h : + /opt/local/include/openssl/ripemd.h : + /path/to/triangles/src/netbase.h : + /path/to/triangles/src/serialize.h : + /opt/local/include/boost/tuple/tuple_comparison.hpp : + /opt/local/include/boost/tuple/tuple_io.hpp : + /path/to/triangles/src/allocators.h : + /path/to/triangles/src/version.h : + /path/to/triangles/src/clientversion.h : + /path/to/triangles/src/compat.h : diff --git a/src/tor/anonymize.cpp b/src/tor/anonymize.cpp new file mode 100644 index 0000000..1f50ba0 --- /dev/null +++ b/src/tor/anonymize.cpp @@ -0,0 +1,60 @@ +/* Copyright (c) 2009-2010 Satoshi Nakamoto + Copyright (c) 2009-2012 The Bitcoin developers + Copyright (c) 2013-2014 The StealthCoin/StealthSend Developers */ +/* Copyright (c) 2014, triangles Developers */ +/* See LICENSE for licensing information */ + +#include "anonymize.h" +#include "util.h" + +#include +#include +#include +#include +#include + +char const* anonymize_tor_data_directory( +) { + static std::string const retrieved = ( + GetDataDir( + ) / "tor" + ).string( + ); + return retrieved.c_str( + ); +} + +char const* anonymize_service_directory( +) { + static std::string const retrieved = ( + GetDataDir( + ) / "onion" + ).string( + ); + return retrieved.c_str( + ); +} + +int check_interrupted( +) { + return boost::this_thread::interruption_requested( + ) ? 1 : 0; +} + +static boost::mutex initializing; + +static std::auto_ptr > uninitialized( + new boost::unique_lock( + initializing + ) +); + +void set_initialized( +) { + uninitialized.reset(); +} + +void wait_initialized( +) { + boost::unique_lock checking(initializing); +} diff --git a/src/tor/anonymize.h b/src/tor/anonymize.h new file mode 100644 index 0000000..bda29a7 --- /dev/null +++ b/src/tor/anonymize.h @@ -0,0 +1,37 @@ +/* Copyright (c) 2014, StealthCoin/StealthSend Developers */ +/* Copyright (c) 2014, triangles Developers */ +/* See LICENSE for licensing information */ + +/** + * \file anonymize.h + * \brief Headers for anonymize.cpp + **/ + +#ifndef TOR_RAZOR_H +#define TOR_RAZOR_H + +#ifdef __cplusplus +extern "C" { +#endif + + char const* anonymize_tor_data_directory( + ); + + char const* anonymize_service_directory( + ); + + int check_interrupted( + ); + + void set_initialized( + ); + + void wait_initialized( + ); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/src/tor/backtrace.c b/src/tor/backtrace.c new file mode 100644 index 0000000..e1452b0 --- /dev/null +++ b/src/tor/backtrace.c @@ -0,0 +1,205 @@ +/* Copyright (c) 2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#define __USE_GNU +#define _GNU_SOURCE 1 + +#include "orconfig.h" +#include "backtrace.h" +#include "tor_compat.h" +#include "tor_util.h" +#include "torlog.h" + +#ifdef HAVE_EXECINFO_H +#include +#endif +#ifdef HAVE_FCNTL_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif +#ifdef HAVE_SIGNAL_H +#include +#endif + +#ifdef HAVE_CYGWIN_SIGNAL_H +#include +#elif defined(HAVE_SYS_UCONTEXT_H) +#include +#elif defined(HAVE_UCONTEXT_H) +#include +#endif + +#if defined(HAVE_EXECINFO_H) && defined(HAVE_BACKTRACE) && \ + defined(HAVE_BACKTRACE_SYMBOLS_FD) && defined(HAVE_SIGACTION) +#define USE_BACKTRACE +#endif + +#if !defined(USE_BACKTRACE) +#define NO_BACKTRACE_IMPL +#endif + +/** Version of Tor to report in backtrace messages. */ +static char *bt_version = NULL; + +#ifdef USE_BACKTRACE +/** Largest stack depth to try to dump. */ +#define MAX_DEPTH 256 +/** Static allocation of stack to dump. This is static so we avoid stack + * pressure. */ +static void *cb_buf[MAX_DEPTH]; + +/** Change a stacktrace in stack of depth depth so that it will + * log the correct function from which a signal was received with context + * ctx. (When we get a signal, the current function will not have + * called any other function, and will therefore have not pushed its address + * onto the stack. Fortunately, we usually have the program counter in the + * ucontext_t structure. + */ +static void +clean_backtrace(void **stack, int depth, const ucontext_t *ctx) +{ +#ifdef PC_FROM_UCONTEXT +#if defined(__linux__) + const int n = 1; +#elif defined(__darwin__) || defined(__APPLE__) || defined(__OpenBSD__) \ + || defined(__FreeBSD__) + const int n = 2; +#else + const int n = 1; +#endif + if (depth <= n) + return; + + stack[n] = (void*) ctx->PC_FROM_UCONTEXT; +#else + (void) depth; + (void) ctx; +#endif +} + +/** Log a message msg at severity in domain, and follow + * that with a backtrace log. */ +void +log_backtrace(int severity, int domain, const char *msg) +{ + int depth = backtrace(cb_buf, MAX_DEPTH); + char **symbols = backtrace_symbols(cb_buf, depth); + int i; + tor_log(severity, domain, "%s. Stack trace:", msg); + if (!symbols) { + tor_log(severity, domain, " Unable to generate backtrace."); + return; + } + for (i=0; i < depth; ++i) { + tor_log(severity, domain, " %s", symbols[i]); + } + free(symbols); +} + +static void crash_handler(int sig, siginfo_t *si, void *ctx_) + __attribute__((noreturn)); + +/** Signal handler: write a crash message with a stack trace, and die. */ +static void +crash_handler(int sig, siginfo_t *si, void *ctx_) +{ + char buf[40]; + int depth; + ucontext_t *ctx = (ucontext_t *) ctx_; + int n_fds, i; + const int *fds = NULL; + + (void) si; + + depth = backtrace(cb_buf, MAX_DEPTH); + /* Clean up the top stack frame so we get the real function + * name for the most recently failing function. */ + clean_backtrace(cb_buf, depth, ctx); + + format_dec_number_sigsafe((unsigned)sig, buf, sizeof(buf)); + + tor_log_err_sigsafe(bt_version, " died: Caught signal ", buf, "\n", + NULL); + + n_fds = tor_log_get_sigsafe_err_fds(&fds); + for (i=0; i < n_fds; ++i) + backtrace_symbols_fd(cb_buf, depth, fds[i]); + + abort(); +} + +/** Install signal handlers as needed so that when we crash, we produce a + * useful stack trace. Return 0 on success, -1 on failure. */ +static int +install_bt_handler(void) +{ + int trap_signals[] = { SIGSEGV, SIGILL, SIGFPE, SIGBUS, SIGSYS, + SIGIO, -1 }; + int i, rv=0; + + struct sigaction sa; + memset(&sa, 0, sizeof(sa)); + sa.sa_sigaction = crash_handler; + sa.sa_flags = SA_SIGINFO; + sigfillset(&sa.sa_mask); + + for (i = 0; trap_signals[i] >= 0; ++i) { + if (sigaction(trap_signals[i], &sa, NULL) == -1) { + log_warn(LD_BUG, "Sigaction failed: %s", strerror(errno)); + rv = -1; + } + } + return rv; +} + +/** Uninstall crash handlers. */ +static void +remove_bt_handler(void) +{ + /* We don't need to actually free anything at exit here. */ +} +#endif + +#ifdef NO_BACKTRACE_IMPL +void +log_backtrace(int severity, int domain, const char *msg) +{ + tor_log(severity, domain, "%s. (Stack trace not available)", msg); +} + +static int +install_bt_handler(void) +{ + return 0; +} + +static void +remove_bt_handler(void) +{ +} +#endif + +/** Set up code to handle generating error messages on crashes. */ +int +configure_backtrace_handler(const char *tor_version) +{ + tor_free(bt_version); + if (!tor_version) + tor_version = ""; + tor_asprintf(&bt_version, "Tor %s", tor_version); + + return install_bt_handler(); +} + +/** Perform end-of-process cleanup for code that generates error messages on + * crashes. */ +void +clean_up_backtrace_handler(void) +{ + remove_bt_handler(); + + tor_free(bt_version); +} + diff --git a/src/tor/backtrace.h b/src/tor/backtrace.h new file mode 100644 index 0000000..765436f --- /dev/null +++ b/src/tor/backtrace.h @@ -0,0 +1,12 @@ +/* Copyright (c) 2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_BACKTRACE_H +#define TOR_BACKTRACE_H + +void log_backtrace(int severity, int domain, const char *msg); +int configure_backtrace_handler(const char *tor_version); +void clean_up_backtrace_handler(void); + +#endif + diff --git a/src/tor/buffers.c b/src/tor/buffers.c new file mode 100644 index 0000000..40083e7 --- /dev/null +++ b/src/tor/buffers.c @@ -0,0 +1,2584 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file buffers.c + * \brief Implements a generic interface buffer. Buffers are + * fairly opaque string holders that can read to or flush from: + * memory, file descriptors, or TLS connections. + **/ +#define BUFFERS_PRIVATE +#include "or.h" +#include "addressmap.h" +#include "buffers.h" +#include "config.h" +#include "connection_edge.h" +#include "connection_or.h" +#include "control.h" +#include "reasons.h" +#include "ext_orport.h" +#include "tor_util.h" +#include "torlog.h" +#ifdef HAVE_UNISTD_H +#include +#endif + +//#define PARANOIA + +#ifdef PARANOIA +/** Helper: If PARANOIA is defined, assert that the buffer in local variable + * buf is well-formed. */ +#define check() STMT_BEGIN assert_buf_ok(buf); STMT_END +#else +#define check() STMT_NIL +#endif + +/* Implementation notes: + * + * After flirting with memmove, and dallying with ring-buffers, we're finally + * getting up to speed with the 1970s and implementing buffers as a linked + * list of small chunks. Each buffer has such a list; data is removed from + * the head of the list, and added at the tail. The list is singly linked, + * and the buffer keeps a pointer to the head and the tail. + * + * Every chunk, except the tail, contains at least one byte of data. Data in + * each chunk is contiguous. + * + * When you need to treat the first N characters on a buffer as a contiguous + * string, use the buf_pullup function to make them so. Don't do this more + * than necessary. + * + * The major free Unix kernels have handled buffers like this since, like, + * forever. + */ + +static int parse_socks(const char *data, size_t datalen, socks_request_t *req, + int log_sockstype, int safe_socks, ssize_t *drain_out, + size_t *want_length_out); +static int parse_socks_client(const uint8_t *data, size_t datalen, + int state, char **reason, + ssize_t *drain_out); + +/* Chunk manipulation functions */ + +/** A single chunk on a buffer or in a freelist. */ +typedef struct chunk_t { + struct chunk_t *next; /**< The next chunk on the buffer or freelist. */ + size_t datalen; /**< The number of bytes stored in this chunk */ + size_t memlen; /**< The number of usable bytes of storage in mem. */ + char *data; /**< A pointer to the first byte of data stored in mem. */ + char mem[FLEXIBLE_ARRAY_MEMBER]; /**< The actual memory used for storage in + * this chunk. */ +} chunk_t; + +#define CHUNK_HEADER_LEN STRUCT_OFFSET(chunk_t, mem[0]) + +/** Return the number of bytes needed to allocate a chunk to hold + * memlen bytes. */ +#define CHUNK_ALLOC_SIZE(memlen) (CHUNK_HEADER_LEN + (memlen)) +/** Return the number of usable bytes in a chunk allocated with + * malloc(memlen). */ +#define CHUNK_SIZE_WITH_ALLOC(memlen) ((memlen) - CHUNK_HEADER_LEN) + +/** Return the next character in chunk onto which data can be appended. + * If the chunk is full, this might be off the end of chunk->mem. */ +static INLINE char * +CHUNK_WRITE_PTR(chunk_t *chunk) +{ + return chunk->data + chunk->datalen; +} + +/** Return the number of bytes that can be written onto chunk without + * running out of space. */ +static INLINE size_t +CHUNK_REMAINING_CAPACITY(const chunk_t *chunk) +{ + return (chunk->mem + chunk->memlen) - (chunk->data + chunk->datalen); +} + +/** Move all bytes stored in chunk to the front of chunk->mem, + * to free up space at the end. */ +static INLINE void +chunk_repack(chunk_t *chunk) +{ + if (chunk->datalen && chunk->data != &chunk->mem[0]) { + memmove(chunk->mem, chunk->data, chunk->datalen); + } + chunk->data = &chunk->mem[0]; +} + +#if defined(ENABLE_BUF_FREELISTS) || defined(RUNNING_DOXYGEN) +/** A freelist of chunks. */ +typedef struct chunk_freelist_t { + size_t alloc_size; /**< What size chunks does this freelist hold? */ + int max_length; /**< Never allow more than this number of chunks in the + * freelist. */ + int slack; /**< When trimming the freelist, leave this number of extra + * chunks beyond lowest_length.*/ + int cur_length; /**< How many chunks on the freelist now? */ + int lowest_length; /**< What's the smallest value of cur_length since the + * last time we cleaned this freelist? */ + uint64_t n_alloc; + uint64_t n_free; + uint64_t n_hit; + chunk_t *head; /**< First chunk on the freelist. */ +} chunk_freelist_t; + +/** Macro to help define freelists. */ +#define FL(a,m,s) { a, m, s, 0, 0, 0, 0, 0, NULL } + +/** Static array of freelists, sorted by alloc_len, terminated by an entry + * with alloc_size of 0. */ +static chunk_freelist_t freelists[] = { + FL(4096, 256, 8), FL(8192, 128, 4), FL(16384, 64, 4), FL(32768, 32, 2), + FL(0, 0, 0) +}; +#undef FL +/** How many times have we looked for a chunk of a size that no freelist + * could help with? */ +static uint64_t n_freelist_miss = 0; + +static void assert_freelist_ok(chunk_freelist_t *fl); + +/** Return the freelist to hold chunks of size alloc, or NULL if + * no freelist exists for that size. */ +static INLINE chunk_freelist_t * +get_freelist(size_t alloc) +{ + int i; + for (i=0; (freelists[i].alloc_size <= alloc && + freelists[i].alloc_size); ++i ) { + if (freelists[i].alloc_size == alloc) { + return &freelists[i]; + } + } + return NULL; +} + +/** Deallocate a chunk or put it on a freelist */ +static void +chunk_free_unchecked(chunk_t *chunk) +{ + size_t alloc; + chunk_freelist_t *freelist; + + alloc = CHUNK_ALLOC_SIZE(chunk->memlen); + freelist = get_freelist(alloc); + if (freelist && freelist->cur_length < freelist->max_length) { + chunk->next = freelist->head; + freelist->head = chunk; + ++freelist->cur_length; + } else { + if (freelist) + ++freelist->n_free; + tor_free(chunk); + } +} + +/** Allocate a new chunk with a given allocation size, or get one from the + * freelist. Note that a chunk with allocation size A can actually hold only + * CHUNK_SIZE_WITH_ALLOC(A) bytes in its mem field. */ +static INLINE chunk_t * +chunk_new_with_alloc_size(size_t alloc) +{ + chunk_t *ch; + chunk_freelist_t *freelist; + tor_assert(alloc >= sizeof(chunk_t)); + freelist = get_freelist(alloc); + if (freelist && freelist->head) { + ch = freelist->head; + freelist->head = ch->next; + if (--freelist->cur_length < freelist->lowest_length) + freelist->lowest_length = freelist->cur_length; + ++freelist->n_hit; + } else { + if (freelist) + ++freelist->n_alloc; + else + ++n_freelist_miss; + ch = tor_malloc(alloc); + } + ch->next = NULL; + ch->datalen = 0; + ch->memlen = CHUNK_SIZE_WITH_ALLOC(alloc); + ch->data = &ch->mem[0]; + return ch; +} +#else +static void +chunk_free_unchecked(chunk_t *chunk) +{ + tor_free(chunk); +} +static INLINE chunk_t * +chunk_new_with_alloc_size(size_t alloc) +{ + chunk_t *ch; + ch = tor_malloc(alloc); + ch->next = NULL; + ch->datalen = 0; + ch->memlen = CHUNK_SIZE_WITH_ALLOC(alloc); + ch->data = &ch->mem[0]; + return ch; +} +#endif + +/** Expand chunk until it can hold sz bytes, and return a + * new pointer to chunk. Old pointers are no longer valid. */ +static INLINE chunk_t * +chunk_grow(chunk_t *chunk, size_t sz) +{ + off_t offset; + tor_assert(sz > chunk->memlen); + offset = chunk->data - chunk->mem; + chunk = tor_realloc(chunk, CHUNK_ALLOC_SIZE(sz)); + chunk->memlen = sz; + chunk->data = chunk->mem + offset; + return chunk; +} + +/** If a read onto the end of a chunk would be smaller than this number, then + * just start a new chunk. */ +#define MIN_READ_LEN 8 +/** Every chunk should take up at least this many bytes. */ +#define MIN_CHUNK_ALLOC 256 +/** No chunk should take up more than this many bytes. */ +#define MAX_CHUNK_ALLOC 65536 + +/** Return the allocation size we'd like to use to hold target + * bytes. */ +static INLINE size_t +preferred_chunk_size(size_t target) +{ + size_t sz = MIN_CHUNK_ALLOC; + while (CHUNK_SIZE_WITH_ALLOC(sz) < target) { + sz <<= 1; + } + return sz; +} + +/** Remove from the freelists most chunks that have not been used since the + * last call to buf_shrink_freelists(). */ +void +buf_shrink_freelists(int free_all) +{ +#ifdef ENABLE_BUF_FREELISTS + int i; + disable_control_logging(); + for (i = 0; freelists[i].alloc_size; ++i) { + int slack = freelists[i].slack; + assert_freelist_ok(&freelists[i]); + if (free_all || freelists[i].lowest_length > slack) { + int n_to_free = free_all ? freelists[i].cur_length : + (freelists[i].lowest_length - slack); + int n_to_skip = freelists[i].cur_length - n_to_free; + int orig_length = freelists[i].cur_length; + int orig_n_to_free = n_to_free, n_freed=0; + int orig_n_to_skip = n_to_skip; + int new_length = n_to_skip; + chunk_t **chp = &freelists[i].head; + chunk_t *chunk; + while (n_to_skip) { + if (! (*chp)->next) { + log_warn(LD_BUG, "I wanted to skip %d chunks in the freelist for " + "%d-byte chunks, but only found %d. (Length %d)", + orig_n_to_skip, (int)freelists[i].alloc_size, + orig_n_to_skip-n_to_skip, freelists[i].cur_length); + assert_freelist_ok(&freelists[i]); + goto done; + } + // tor_assert((*chp)->next); + chp = &(*chp)->next; + --n_to_skip; + } + chunk = *chp; + *chp = NULL; + while (chunk) { + chunk_t *next = chunk->next; + tor_free(chunk); + chunk = next; + --n_to_free; + ++n_freed; + ++freelists[i].n_free; + } + if (n_to_free) { + log_warn(LD_BUG, "Freelist length for %d-byte chunks may have been " + "messed up somehow.", (int)freelists[i].alloc_size); + log_warn(LD_BUG, "There were %d chunks at the start. I decided to " + "keep %d. I wanted to free %d. I freed %d. I somehow think " + "I have %d left to free.", + freelists[i].cur_length, n_to_skip, orig_n_to_free, + n_freed, n_to_free); + } + // tor_assert(!n_to_free); + freelists[i].cur_length = new_length; + log_info(LD_MM, "Cleaned freelist for %d-byte chunks: original " + "length %d, kept %d, dropped %d.", + (int)freelists[i].alloc_size, orig_length, + orig_n_to_skip, orig_n_to_free); + } + freelists[i].lowest_length = freelists[i].cur_length; + assert_freelist_ok(&freelists[i]); + } + done: + enable_control_logging(); +#else + (void) free_all; +#endif +} + +/** Describe the current status of the freelists at log level severity. + */ +void +buf_dump_freelist_sizes(int severity) +{ +#ifdef ENABLE_BUF_FREELISTS + int i; + tor_log(severity, LD_MM, "====== Buffer freelists:"); + for (i = 0; freelists[i].alloc_size; ++i) { + uint64_t total = ((uint64_t)freelists[i].cur_length) * + freelists[i].alloc_size; + tor_log(severity, LD_MM, + U64_FORMAT" bytes in %d %d-byte chunks ["U64_FORMAT + " misses; "U64_FORMAT" frees; "U64_FORMAT" hits]", + U64_PRINTF_ARG(total), + freelists[i].cur_length, (int)freelists[i].alloc_size, + U64_PRINTF_ARG(freelists[i].n_alloc), + U64_PRINTF_ARG(freelists[i].n_free), + U64_PRINTF_ARG(freelists[i].n_hit)); + } + tor_log(severity, LD_MM, U64_FORMAT" allocations in non-freelist sizes", + U64_PRINTF_ARG(n_freelist_miss)); +#else + (void)severity; +#endif +} + +/** Magic value for buf_t.magic, to catch pointer errors. */ +#define BUFFER_MAGIC 0xB0FFF312u +/** A resizeable buffer, optimized for reading and writing. */ +struct buf_t { + uint32_t magic; /**< Magic cookie for debugging: Must be set to + * BUFFER_MAGIC. */ + size_t datalen; /**< How many bytes is this buffer holding right now? */ + size_t default_chunk_size; /**< Don't allocate any chunks smaller than + * this for this buffer. */ + chunk_t *head; /**< First chunk in the list, or NULL for none. */ + chunk_t *tail; /**< Last chunk in the list, or NULL for none. */ +}; + +/** Collapse data from the first N chunks from buf into buf->head, + * growing it as necessary, until buf->head has the first bytes bytes + * of data from the buffer, or until buf->head has all the data in buf. + * + * If nulterminate is true, ensure that there is a 0 byte in + * buf->head->mem right after all the data. */ +static void +buf_pullup(buf_t *buf, size_t bytes, int nulterminate) +{ + chunk_t *dest, *src; + size_t capacity; + if (!buf->head) + return; + + check(); + if (buf->datalen < bytes) + bytes = buf->datalen; + + if (nulterminate) { + capacity = bytes + 1; + if (buf->head->datalen >= bytes && CHUNK_REMAINING_CAPACITY(buf->head)) { + *CHUNK_WRITE_PTR(buf->head) = '\0'; + return; + } + } else { + capacity = bytes; + if (buf->head->datalen >= bytes) + return; + } + + if (buf->head->memlen >= capacity) { + /* We don't need to grow the first chunk, but we might need to repack it.*/ + size_t needed = capacity - buf->head->datalen; + if (CHUNK_REMAINING_CAPACITY(buf->head) < needed) + chunk_repack(buf->head); + tor_assert(CHUNK_REMAINING_CAPACITY(buf->head) >= needed); + } else { + chunk_t *newhead; + size_t newsize; + /* We need to grow the chunk. */ + chunk_repack(buf->head); + newsize = CHUNK_SIZE_WITH_ALLOC(preferred_chunk_size(capacity)); + newhead = chunk_grow(buf->head, newsize); + tor_assert(newhead->memlen >= capacity); + if (newhead != buf->head) { + if (buf->tail == buf->head) + buf->tail = newhead; + buf->head = newhead; + } + } + + dest = buf->head; + while (dest->datalen < bytes) { + size_t n = bytes - dest->datalen; + src = dest->next; + tor_assert(src); + if (n > src->datalen) { + memcpy(CHUNK_WRITE_PTR(dest), src->data, src->datalen); + dest->datalen += src->datalen; + dest->next = src->next; + if (buf->tail == src) + buf->tail = dest; + chunk_free_unchecked(src); + } else { + memcpy(CHUNK_WRITE_PTR(dest), src->data, n); + dest->datalen += n; + src->data += n; + src->datalen -= n; + tor_assert(dest->datalen == bytes); + } + } + + if (nulterminate) { + tor_assert(CHUNK_REMAINING_CAPACITY(buf->head)); + *CHUNK_WRITE_PTR(buf->head) = '\0'; + } + + check(); +} + +/** Resize buf so it won't hold extra memory that we haven't been + * using lately. + */ +void +buf_shrink(buf_t *buf) +{ + (void)buf; +} + +/** Remove the first n bytes from buf. */ +static INLINE void +buf_remove_from_front(buf_t *buf, size_t n) +{ + tor_assert(buf->datalen >= n); + while (n) { + tor_assert(buf->head); + if (buf->head->datalen > n) { + buf->head->datalen -= n; + buf->head->data += n; + buf->datalen -= n; + return; + } else { + chunk_t *victim = buf->head; + n -= victim->datalen; + buf->datalen -= victim->datalen; + buf->head = victim->next; + if (buf->tail == victim) + buf->tail = NULL; + chunk_free_unchecked(victim); + } + } + check(); +} + +/** Create and return a new buf with default chunk capacity size. + */ +buf_t * +buf_new_with_capacity(size_t size) +{ + buf_t *b = buf_new(); + b->default_chunk_size = preferred_chunk_size(size); + return b; +} + +/** Allocate and return a new buffer with default capacity. */ +buf_t * +buf_new(void) +{ + buf_t *buf = tor_malloc_zero(sizeof(buf_t)); + buf->magic = BUFFER_MAGIC; + buf->default_chunk_size = 4096; + return buf; +} + +/** Remove all data from buf. */ +void +buf_clear(buf_t *buf) +{ + chunk_t *chunk, *next; + buf->datalen = 0; + for (chunk = buf->head; chunk; chunk = next) { + next = chunk->next; + chunk_free_unchecked(chunk); + } + buf->head = buf->tail = NULL; +} + +/** Return the number of bytes stored in buf */ +size_t +buf_datalen(const buf_t *buf) +{ + return buf->datalen; +} + +/** Return the total length of all chunks used in buf. */ +size_t +buf_allocation(const buf_t *buf) +{ + size_t total = 0; + const chunk_t *chunk; + for (chunk = buf->head; chunk; chunk = chunk->next) { + total += chunk->memlen; + } + return total; +} + +/** Return the number of bytes that can be added to buf without + * performing any additional allocation. */ +size_t +buf_slack(const buf_t *buf) +{ + if (!buf->tail) + return 0; + else + return CHUNK_REMAINING_CAPACITY(buf->tail); +} + +/** Release storage held by buf. */ +void +buf_free(buf_t *buf) +{ + if (!buf) + return; + + buf_clear(buf); + buf->magic = 0xdeadbeef; + tor_free(buf); +} + +/** Return a new copy of in_chunk */ +static chunk_t * +chunk_copy(const chunk_t *in_chunk) +{ + chunk_t *newch = tor_memdup(in_chunk, CHUNK_ALLOC_SIZE(in_chunk->memlen)); + newch->next = NULL; + if (in_chunk->data) { + off_t offset = in_chunk->data - in_chunk->mem; + newch->data = newch->mem + offset; + } + return newch; +} + +/** Return a new copy of buf */ +buf_t * +buf_copy(const buf_t *buf) +{ + chunk_t *ch; + buf_t *out = buf_new(); + out->default_chunk_size = buf->default_chunk_size; + for (ch = buf->head; ch; ch = ch->next) { + chunk_t *newch = chunk_copy(ch); + if (out->tail) { + out->tail->next = newch; + out->tail = newch; + } else { + out->head = out->tail = newch; + } + } + out->datalen = buf->datalen; + return out; +} + +/** Append a new chunk with enough capacity to hold capacity bytes to + * the tail of buf. If capped, don't allocate a chunk bigger + * than MAX_CHUNK_ALLOC. */ +static chunk_t * +buf_add_chunk_with_capacity(buf_t *buf, size_t capacity, int capped) +{ + chunk_t *chunk; + if (CHUNK_ALLOC_SIZE(capacity) < buf->default_chunk_size) { + chunk = chunk_new_with_alloc_size(buf->default_chunk_size); + } else if (capped && CHUNK_ALLOC_SIZE(capacity) > MAX_CHUNK_ALLOC) { + chunk = chunk_new_with_alloc_size(MAX_CHUNK_ALLOC); + } else { + chunk = chunk_new_with_alloc_size(preferred_chunk_size(capacity)); + } + if (buf->tail) { + tor_assert(buf->head); + buf->tail->next = chunk; + buf->tail = chunk; + } else { + tor_assert(!buf->head); + buf->head = buf->tail = chunk; + } + check(); + return chunk; +} + +/** Read up to at_most bytes from the socket fd into + * chunk (which must be on buf). If we get an EOF, set + * *reached_eof to 1. Return -1 on error, 0 on eof or blocking, + * and the number of bytes read otherwise. */ +static INLINE int +read_to_chunk(buf_t *buf, chunk_t *chunk, tor_socket_t fd, size_t at_most, + int *reached_eof, int *socket_error) +{ + ssize_t read_result; + if (at_most > CHUNK_REMAINING_CAPACITY(chunk)) + at_most = CHUNK_REMAINING_CAPACITY(chunk); + read_result = tor_socket_recv(fd, CHUNK_WRITE_PTR(chunk), at_most, 0); + + if (read_result < 0) { + int e = tor_socket_errno(fd); + if (!ERRNO_IS_EAGAIN(e)) { /* it's a real error */ +#ifdef _WIN32 + if (e == WSAENOBUFS) + log_warn(LD_NET,"recv() failed: WSAENOBUFS. Not enough ram?"); +#endif + *socket_error = e; + return -1; + } + return 0; /* would block. */ + } else if (read_result == 0) { + log_debug(LD_NET,"Encountered eof on fd %d", (int)fd); + *reached_eof = 1; + return 0; + } else { /* actually got bytes. */ + buf->datalen += read_result; + chunk->datalen += read_result; + log_debug(LD_NET,"Read %ld bytes. %d on inbuf.", (long)read_result, + (int)buf->datalen); + tor_assert(read_result < INT_MAX); + return (int)read_result; + } +} + +/** As read_to_chunk(), but return (negative) error code on error, blocking, + * or TLS, and the number of bytes read otherwise. */ +static INLINE int +read_to_chunk_tls(buf_t *buf, chunk_t *chunk, tor_tls_t *tls, + size_t at_most) +{ + int read_result; + + tor_assert(CHUNK_REMAINING_CAPACITY(chunk) >= at_most); + read_result = tor_tls_read(tls, CHUNK_WRITE_PTR(chunk), at_most); + if (read_result < 0) + return read_result; + buf->datalen += read_result; + chunk->datalen += read_result; + return read_result; +} + +/** Read from socket s, writing onto end of buf. Read at most + * at_most bytes, growing the buffer as necessary. If recv() returns 0 + * (because of EOF), set *reached_eof to 1 and return 0. Return -1 on + * error; else return the number of bytes read. + */ +/* XXXX024 indicate "read blocked" somehow? */ +int +read_to_buf(tor_socket_t s, size_t at_most, buf_t *buf, int *reached_eof, + int *socket_error) +{ + /* XXXX024 It's stupid to overload the return values for these functions: + * "error status" and "number of bytes read" are not mutually exclusive. + */ + int r = 0; + size_t total_read = 0; + + check(); + tor_assert(reached_eof); + tor_assert(SOCKET_OK(s)); + + while (at_most > total_read) { + size_t readlen = at_most - total_read; + chunk_t *chunk; + if (!buf->tail || CHUNK_REMAINING_CAPACITY(buf->tail) < MIN_READ_LEN) { + chunk = buf_add_chunk_with_capacity(buf, at_most, 1); + if (readlen > chunk->memlen) + readlen = chunk->memlen; + } else { + size_t cap = CHUNK_REMAINING_CAPACITY(buf->tail); + chunk = buf->tail; + if (cap < readlen) + readlen = cap; + } + + r = read_to_chunk(buf, chunk, s, readlen, reached_eof, socket_error); + check(); + if (r < 0) + return r; /* Error */ + tor_assert(total_read+r < INT_MAX); + total_read += r; + if ((size_t)r < readlen) { /* eof, block, or no more to read. */ + break; + } + } + return (int)total_read; +} + +/** As read_to_buf, but reads from a TLS connection, and returns a TLS + * status value rather than the number of bytes read. + * + * Using TLS on OR connections complicates matters in two ways. + * + * First, a TLS stream has its own read buffer independent of the + * connection's read buffer. (TLS needs to read an entire frame from + * the network before it can decrypt any data. Thus, trying to read 1 + * byte from TLS can require that several KB be read from the network + * and decrypted. The extra data is stored in TLS's decrypt buffer.) + * Because the data hasn't been read by Tor (it's still inside the TLS), + * this means that sometimes a connection "has stuff to read" even when + * poll() didn't return POLLIN. The tor_tls_get_pending_bytes function is + * used in connection.c to detect TLS objects with non-empty internal + * buffers and read from them again. + * + * Second, the TLS stream's events do not correspond directly to network + * events: sometimes, before a TLS stream can read, the network must be + * ready to write -- or vice versa. + */ +int +read_to_buf_tls(tor_tls_t *tls, size_t at_most, buf_t *buf) +{ + int r = 0; + size_t total_read = 0; + + check_no_tls_errors(); + + check(); + + while (at_most > total_read) { + size_t readlen = at_most - total_read; + chunk_t *chunk; + if (!buf->tail || CHUNK_REMAINING_CAPACITY(buf->tail) < MIN_READ_LEN) { + chunk = buf_add_chunk_with_capacity(buf, at_most, 1); + if (readlen > chunk->memlen) + readlen = chunk->memlen; + } else { + size_t cap = CHUNK_REMAINING_CAPACITY(buf->tail); + chunk = buf->tail; + if (cap < readlen) + readlen = cap; + } + + r = read_to_chunk_tls(buf, chunk, tls, readlen); + check(); + if (r < 0) + return r; /* Error */ + tor_assert(total_read+r < INT_MAX); + total_read += r; + if ((size_t)r < readlen) /* eof, block, or no more to read. */ + break; + } + return (int)total_read; +} + +/** Helper for flush_buf(): try to write sz bytes from chunk + * chunk of buffer buf onto socket s. On success, deduct + * the bytes written from *buf_flushlen. Return the number of bytes + * written on success, 0 on blocking, -1 on failure. + */ +static INLINE int +flush_chunk(tor_socket_t s, buf_t *buf, chunk_t *chunk, size_t sz, + size_t *buf_flushlen) +{ + ssize_t write_result; + + if (sz > chunk->datalen) + sz = chunk->datalen; + write_result = tor_socket_send(s, chunk->data, sz, 0); + + if (write_result < 0) { + int e = tor_socket_errno(s); + if (!ERRNO_IS_EAGAIN(e)) { /* it's a real error */ +#ifdef _WIN32 + if (e == WSAENOBUFS) + log_warn(LD_NET,"write() failed: WSAENOBUFS. Not enough ram?"); +#endif + return -1; + } + log_debug(LD_NET,"write() would block, returning."); + return 0; + } else { + *buf_flushlen -= write_result; + buf_remove_from_front(buf, write_result); + tor_assert(write_result < INT_MAX); + return (int)write_result; + } +} + +/** Helper for flush_buf_tls(): try to write sz bytes from chunk + * chunk of buffer buf onto socket s. (Tries to write + * more if there is a forced pending write size.) On success, deduct the + * bytes written from *buf_flushlen. Return the number of bytes + * written on success, and a TOR_TLS error code on failure or blocking. + */ +static INLINE int +flush_chunk_tls(tor_tls_t *tls, buf_t *buf, chunk_t *chunk, + size_t sz, size_t *buf_flushlen) +{ + int r; + size_t forced; + char *data; + + forced = tor_tls_get_forced_write_size(tls); + if (forced > sz) + sz = forced; + if (chunk) { + data = chunk->data; + tor_assert(sz <= chunk->datalen); + } else { + data = NULL; + tor_assert(sz == 0); + } + r = tor_tls_write(tls, data, sz); + if (r < 0) + return r; + if (*buf_flushlen > (size_t)r) + *buf_flushlen -= r; + else + *buf_flushlen = 0; + buf_remove_from_front(buf, r); + log_debug(LD_NET,"flushed %d bytes, %d ready to flush, %d remain.", + r,(int)*buf_flushlen,(int)buf->datalen); + return r; +} + +/** Write data from buf to the socket s. Write at most + * sz bytes, decrement *buf_flushlen by + * the number of bytes actually written, and remove the written bytes + * from the buffer. Return the number of bytes written on success, + * -1 on failure. Return 0 if write() would block. + */ +int +flush_buf(tor_socket_t s, buf_t *buf, size_t sz, size_t *buf_flushlen) +{ + /* XXXX024 It's stupid to overload the return values for these functions: + * "error status" and "number of bytes flushed" are not mutually exclusive. + */ + int r; + size_t flushed = 0; + tor_assert(buf_flushlen); + tor_assert(SOCKET_OK(s)); + tor_assert(*buf_flushlen <= buf->datalen); + tor_assert(sz <= *buf_flushlen); + + check(); + while (sz) { + size_t flushlen0; + tor_assert(buf->head); + if (buf->head->datalen >= sz) + flushlen0 = sz; + else + flushlen0 = buf->head->datalen; + + r = flush_chunk(s, buf, buf->head, flushlen0, buf_flushlen); + check(); + if (r < 0) + return r; + flushed += r; + sz -= r; + if (r == 0 || (size_t)r < flushlen0) /* can't flush any more now. */ + break; + } + tor_assert(flushed < INT_MAX); + return (int)flushed; +} + +/** As flush_buf(), but writes data to a TLS connection. Can write more than + * flushlen bytes. + */ +int +flush_buf_tls(tor_tls_t *tls, buf_t *buf, size_t flushlen, + size_t *buf_flushlen) +{ + int r; + size_t flushed = 0; + ssize_t sz; + tor_assert(buf_flushlen); + tor_assert(*buf_flushlen <= buf->datalen); + tor_assert(flushlen <= *buf_flushlen); + sz = (ssize_t) flushlen; + + /* we want to let tls write even if flushlen is zero, because it might + * have a partial record pending */ + check_no_tls_errors(); + + check(); + do { + size_t flushlen0; + if (buf->head) { + if ((ssize_t)buf->head->datalen >= sz) + flushlen0 = sz; + else + flushlen0 = buf->head->datalen; + } else { + flushlen0 = 0; + } + + r = flush_chunk_tls(tls, buf, buf->head, flushlen0, buf_flushlen); + check(); + if (r < 0) + return r; + flushed += r; + sz -= r; + if (r == 0) /* Can't flush any more now. */ + break; + } while (sz > 0); + tor_assert(flushed < INT_MAX); + return (int)flushed; +} + +/** Append string_len bytes from string to the end of + * buf. + * + * Return the new length of the buffer on success, -1 on failure. + */ +int +write_to_buf(const char *string, size_t string_len, buf_t *buf) +{ + if (!string_len) + return (int)buf->datalen; + check(); + + while (string_len) { + size_t copy; + if (!buf->tail || !CHUNK_REMAINING_CAPACITY(buf->tail)) + buf_add_chunk_with_capacity(buf, string_len, 1); + + copy = CHUNK_REMAINING_CAPACITY(buf->tail); + if (copy > string_len) + copy = string_len; + memcpy(CHUNK_WRITE_PTR(buf->tail), string, copy); + string_len -= copy; + string += copy; + buf->datalen += copy; + buf->tail->datalen += copy; + } + + check(); + tor_assert(buf->datalen < INT_MAX); + return (int)buf->datalen; +} + +/** Helper: copy the first string_len bytes from buf + * onto string. + */ +static INLINE void +peek_from_buf(char *string, size_t string_len, const buf_t *buf) +{ + chunk_t *chunk; + + tor_assert(string); + /* make sure we don't ask for too much */ + tor_assert(string_len <= buf->datalen); + /* assert_buf_ok(buf); */ + + chunk = buf->head; + while (string_len) { + size_t copy = string_len; + tor_assert(chunk); + if (chunk->datalen < copy) + copy = chunk->datalen; + memcpy(string, chunk->data, copy); + string_len -= copy; + string += copy; + chunk = chunk->next; + } +} + +/** Remove string_len bytes from the front of buf, and store + * them into string. Return the new buffer size. string_len + * must be \<= the number of bytes on the buffer. + */ +int +fetch_from_buf(char *string, size_t string_len, buf_t *buf) +{ + /* There must be string_len bytes in buf; write them onto string, + * then memmove buf back (that is, remove them from buf). + * + * Return the number of bytes still on the buffer. */ + + check(); + peek_from_buf(string, string_len, buf); + buf_remove_from_front(buf, string_len); + check(); + tor_assert(buf->datalen < INT_MAX); + return (int)buf->datalen; +} + +/** True iff the cell command command is one that implies a + * variable-length cell in Tor link protocol linkproto. */ +static INLINE int +cell_command_is_var_length(uint8_t command, int linkproto) +{ + /* If linkproto is v2 (2), CELL_VERSIONS is the only variable-length cells + * work as implemented here. If it's 1, there are no variable-length cells. + * Tor does not support other versions right now, and so can't negotiate + * them. + */ + switch (linkproto) { + case 1: + /* Link protocol version 1 has no variable-length cells. */ + return 0; + case 2: + /* In link protocol version 2, VERSIONS is the only variable-length cell */ + return command == CELL_VERSIONS; + case 0: + case 3: + default: + /* In link protocol version 3 and later, and in version "unknown", + * commands 128 and higher indicate variable-length. VERSIONS is + * grandfathered in. */ + return command == CELL_VERSIONS || command >= 128; + } +} + +/** Check buf for a variable-length cell according to the rules of link + * protocol version linkproto. If one is found, pull it off the buffer + * and assign a newly allocated var_cell_t to *out, and return 1. + * Return 0 if whatever is on the start of buf_t is not a variable-length + * cell. Return 1 and set *out to NULL if there seems to be the start + * of a variable-length cell on buf, but the whole thing isn't there + * yet. */ +int +fetch_var_cell_from_buf(buf_t *buf, var_cell_t **out, int linkproto) +{ + char hdr[VAR_CELL_MAX_HEADER_SIZE]; + var_cell_t *result; + uint8_t command; + uint16_t length; + const int wide_circ_ids = linkproto >= MIN_LINK_PROTO_FOR_WIDE_CIRC_IDS; + const int circ_id_len = get_circ_id_size(wide_circ_ids); + const unsigned header_len = get_var_cell_header_size(wide_circ_ids); + check(); + *out = NULL; + if (buf->datalen < header_len) + return 0; + peek_from_buf(hdr, header_len, buf); + + command = get_uint8(hdr + circ_id_len); + if (!(cell_command_is_var_length(command, linkproto))) + return 0; + + length = ntohs(get_uint16(hdr + circ_id_len + 1)); + if (buf->datalen < (size_t)(header_len+length)) + return 1; + result = var_cell_new(length); + result->command = command; + if (wide_circ_ids) + result->circ_id = ntohl(get_uint32(hdr)); + else + result->circ_id = ntohs(get_uint16(hdr)); + + buf_remove_from_front(buf, header_len); + peek_from_buf((char*) result->payload, length, buf); + buf_remove_from_front(buf, length); + check(); + + *out = result; + return 1; +} + +#ifdef USE_BUFFEREVENTS +/** Try to read n bytes from buf at pos (which may be + * NULL for the start of the buffer), copying the data only if necessary. Set + * *data_out to a pointer to the desired bytes. Set free_out + * to 1 if we needed to malloc *data because the original bytes were + * noncontiguous; 0 otherwise. Return the number of bytes actually available + * at *data_out. + */ +static ssize_t +inspect_evbuffer(struct evbuffer *buf, char **data_out, size_t n, + int *free_out, struct evbuffer_ptr *pos) +{ + int n_vecs, i; + + if (evbuffer_get_length(buf) < n) + n = evbuffer_get_length(buf); + if (n == 0) + return 0; + n_vecs = evbuffer_peek(buf, n, pos, NULL, 0); + tor_assert(n_vecs > 0); + if (n_vecs == 1) { + struct evbuffer_iovec v; + i = evbuffer_peek(buf, n, pos, &v, 1); + tor_assert(i == 1); + *data_out = v.iov_base; + *free_out = 0; + return v.iov_len; + } else { + ev_ssize_t copied; + *data_out = tor_malloc(n); + *free_out = 1; + copied = evbuffer_copyout(buf, *data_out, n); + tor_assert(copied >= 0 && (size_t)copied == n); + return copied; + } +} + +/** As fetch_var_cell_from_buf, buf works on an evbuffer. */ +int +fetch_var_cell_from_evbuffer(struct evbuffer *buf, var_cell_t **out, + int linkproto) +{ + char *hdr = NULL; + int free_hdr = 0; + size_t n; + size_t buf_len; + uint8_t command; + uint16_t cell_length; + var_cell_t *cell; + int result = 0; + const int wide_circ_ids = linkproto >= MIN_LINK_PROTO_FOR_WIDE_CIRC_IDS; + const int circ_id_len = get_circ_id_size(wide_circ_ids); + const unsigned header_len = get_var_cell_header_size(wide_circ_ids); + + *out = NULL; + buf_len = evbuffer_get_length(buf); + if (buf_len < header_len) + return 0; + + n = inspect_evbuffer(buf, &hdr, header_len, &free_hdr, NULL); + tor_assert(n >= header_len); + + command = get_uint8(hdr + circ_id_len); + if (!(cell_command_is_var_length(command, linkproto))) { + goto done; + } + + cell_length = ntohs(get_uint16(hdr + circ_id_len + 1)); + if (buf_len < (size_t)(header_len+cell_length)) { + result = 1; /* Not all here yet. */ + goto done; + } + + cell = var_cell_new(cell_length); + cell->command = command; + if (wide_circ_ids) + cell->circ_id = ntohl(get_uint32(hdr)); + else + cell->circ_id = ntohs(get_uint16(hdr)); + evbuffer_drain(buf, header_len); + evbuffer_remove(buf, cell->payload, cell_length); + *out = cell; + result = 1; + + done: + if (free_hdr && hdr) + tor_free(hdr); + return result; +} +#endif + +/** Move up to *buf_flushlen bytes from buf_in to + * buf_out, and modify *buf_flushlen appropriately. + * Return the number of bytes actually copied. + */ +int +move_buf_to_buf(buf_t *buf_out, buf_t *buf_in, size_t *buf_flushlen) +{ + /* We can do way better here, but this doesn't turn up in any profiles. */ + char b[4096]; + size_t cp, len; + len = *buf_flushlen; + if (len > buf_in->datalen) + len = buf_in->datalen; + + cp = len; /* Remember the number of bytes we intend to copy. */ + tor_assert(cp < INT_MAX); + while (len) { + /* This isn't the most efficient implementation one could imagine, since + * it does two copies instead of 1, but I kinda doubt that this will be + * critical path. */ + size_t n = len > sizeof(b) ? sizeof(b) : len; + fetch_from_buf(b, n, buf_in); + write_to_buf(b, n, buf_out); + len -= n; + } + *buf_flushlen -= cp; + return (int)cp; +} + +/** Internal structure: represents a position in a buffer. */ +typedef struct buf_pos_t { + const chunk_t *chunk; /**< Which chunk are we pointing to? */ + int pos;/**< Which character inside the chunk's data are we pointing to? */ + size_t chunk_pos; /**< Total length of all previous chunks. */ +} buf_pos_t; + +/** Initialize out to point to the first character of buf.*/ +static void +buf_pos_init(const buf_t *buf, buf_pos_t *out) +{ + out->chunk = buf->head; + out->pos = 0; + out->chunk_pos = 0; +} + +/** Advance out to the first appearance of ch at the current + * position of out, or later. Return -1 if no instances are found; + * otherwise returns the absolute position of the character. */ +static off_t +buf_find_pos_of_char(char ch, buf_pos_t *out) +{ + const chunk_t *chunk; + int pos; + tor_assert(out); + if (out->chunk) { + if (out->chunk->datalen) { + tor_assert(out->pos < (off_t)out->chunk->datalen); + } else { + tor_assert(out->pos == 0); + } + } + pos = out->pos; + for (chunk = out->chunk; chunk; chunk = chunk->next) { + char *cp = memchr(chunk->data+pos, ch, chunk->datalen - pos); + if (cp) { + out->chunk = chunk; + tor_assert(cp - chunk->data < INT_MAX); + out->pos = (int)(cp - chunk->data); + return out->chunk_pos + out->pos; + } else { + out->chunk_pos += chunk->datalen; + pos = 0; + } + } + return -1; +} + +/** Advance pos by a single character, if there are any more characters + * in the buffer. Returns 0 on success, -1 on failure. */ +static INLINE int +buf_pos_inc(buf_pos_t *pos) +{ + ++pos->pos; + if (pos->pos == (off_t)pos->chunk->datalen) { + if (!pos->chunk->next) + return -1; + pos->chunk_pos += pos->chunk->datalen; + pos->chunk = pos->chunk->next; + pos->pos = 0; + } + return 0; +} + +/** Return true iff the n-character string in s appears + * (verbatim) at pos. */ +static int +buf_matches_at_pos(const buf_pos_t *pos, const char *s, size_t n) +{ + buf_pos_t p; + if (!n) + return 1; + + memcpy(&p, pos, sizeof(p)); + + while (1) { + char ch = p.chunk->data[p.pos]; + if (ch != *s) + return 0; + ++s; + /* If we're out of characters that don't match, we match. Check this + * _before_ we test incrementing pos, in case we're at the end of the + * string. */ + if (--n == 0) + return 1; + if (buf_pos_inc(&p)<0) + return 0; + } +} + +/** Return the first position in buf at which the n-character + * string s occurs, or -1 if it does not occur. */ +STATIC int +buf_find_string_offset(const buf_t *buf, const char *s, size_t n) +{ + buf_pos_t pos; + buf_pos_init(buf, &pos); + while (buf_find_pos_of_char(*s, &pos) >= 0) { + if (buf_matches_at_pos(&pos, s, n)) { + tor_assert(pos.chunk_pos + pos.pos < INT_MAX); + return (int)(pos.chunk_pos + pos.pos); + } else { + if (buf_pos_inc(&pos)<0) + return -1; + } + } + return -1; +} + +/** There is a (possibly incomplete) http statement on buf, of the + * form "\%s\\r\\n\\r\\n\%s", headers, body. (body may contain NULs.) + * If a) the headers include a Content-Length field and all bytes in + * the body are present, or b) there's no Content-Length field and + * all headers are present, then: + * + * - strdup headers into *headers_out, and NUL-terminate it. + * - memdup body into *body_out, and NUL-terminate it. + * - Then remove them from buf, and return 1. + * + * - If headers or body is NULL, discard that part of the buf. + * - If a headers or body doesn't fit in the arg, return -1. + * (We ensure that the headers or body don't exceed max len, + * _even if_ we're planning to discard them.) + * - If force_complete is true, then succeed even if not all of the + * content has arrived. + * + * Else, change nothing and return 0. + */ +int +fetch_from_buf_http(buf_t *buf, + char **headers_out, size_t max_headerlen, + char **body_out, size_t *body_used, size_t max_bodylen, + int force_complete) +{ + char *headers, *p; + size_t headerlen, bodylen, contentlen; + int crlf_offset; + + check(); + if (!buf->head) + return 0; + + crlf_offset = buf_find_string_offset(buf, "\r\n\r\n", 4); + if (crlf_offset > (int)max_headerlen || + (crlf_offset < 0 && buf->datalen > max_headerlen)) { + log_debug(LD_HTTP,"headers too long."); + return -1; + } else if (crlf_offset < 0) { + log_debug(LD_HTTP,"headers not all here yet."); + return 0; + } + /* Okay, we have a full header. Make sure it all appears in the first + * chunk. */ + if ((int)buf->head->datalen < crlf_offset + 4) + buf_pullup(buf, crlf_offset+4, 0); + headerlen = crlf_offset + 4; + + headers = buf->head->data; + bodylen = buf->datalen - headerlen; + log_debug(LD_HTTP,"headerlen %d, bodylen %d.", (int)headerlen, (int)bodylen); + + if (max_headerlen <= headerlen) { + log_warn(LD_HTTP,"headerlen %d larger than %d. Failing.", + (int)headerlen, (int)max_headerlen-1); + return -1; + } + if (max_bodylen <= bodylen) { + log_warn(LD_HTTP,"bodylen %d larger than %d. Failing.", + (int)bodylen, (int)max_bodylen-1); + return -1; + } + +#define CONTENT_LENGTH "\r\nContent-Length: " + p = (char*) tor_memstr(headers, headerlen, CONTENT_LENGTH); + if (p) { + int i; + i = atoi(p+strlen(CONTENT_LENGTH)); + if (i < 0) { + log_warn(LD_PROTOCOL, "Content-Length is less than zero; it looks like " + "someone is trying to crash us."); + return -1; + } + contentlen = i; + /* if content-length is malformed, then our body length is 0. fine. */ + log_debug(LD_HTTP,"Got a contentlen of %d.",(int)contentlen); + if (bodylen < contentlen) { + if (!force_complete) { + log_debug(LD_HTTP,"body not all here yet."); + return 0; /* not all there yet */ + } + } + if (bodylen > contentlen) { + bodylen = contentlen; + log_debug(LD_HTTP,"bodylen reduced to %d.",(int)bodylen); + } + } + /* all happy. copy into the appropriate places, and return 1 */ + if (headers_out) { + *headers_out = tor_malloc(headerlen+1); + fetch_from_buf(*headers_out, headerlen, buf); + (*headers_out)[headerlen] = 0; /* NUL terminate it */ + } + if (body_out) { + tor_assert(body_used); + *body_used = bodylen; + *body_out = tor_malloc(bodylen+1); + fetch_from_buf(*body_out, bodylen, buf); + (*body_out)[bodylen] = 0; /* NUL terminate it */ + } + check(); + return 1; +} + +#ifdef USE_BUFFEREVENTS +/** As fetch_from_buf_http, buf works on an evbuffer. */ +int +fetch_from_evbuffer_http(struct evbuffer *buf, + char **headers_out, size_t max_headerlen, + char **body_out, size_t *body_used, size_t max_bodylen, + int force_complete) +{ + struct evbuffer_ptr crlf, content_length; + size_t headerlen, bodylen, contentlen; + + /* Find the first \r\n\r\n in the buffer */ + crlf = evbuffer_search(buf, "\r\n\r\n", 4, NULL); + if (crlf.pos < 0) { + /* We didn't find one. */ + if (evbuffer_get_length(buf) > max_headerlen) + return -1; /* Headers too long. */ + return 0; /* Headers not here yet. */ + } else if (crlf.pos > (int)max_headerlen) { + return -1; /* Headers too long. */ + } + + headerlen = crlf.pos + 4; /* Skip over the \r\n\r\n */ + bodylen = evbuffer_get_length(buf) - headerlen; + if (bodylen > max_bodylen) + return -1; /* body too long */ + + /* Look for the first occurrence of CONTENT_LENGTH insize buf before the + * crlfcrlf */ + content_length = evbuffer_search_range(buf, CONTENT_LENGTH, + strlen(CONTENT_LENGTH), NULL, &crlf); + + if (content_length.pos >= 0) { + /* We found a content_length: parse it and figure out if the body is here + * yet. */ + struct evbuffer_ptr eol; + char *data = NULL; + int free_data = 0; + int n, i; + n = evbuffer_ptr_set(buf, &content_length, strlen(CONTENT_LENGTH), + EVBUFFER_PTR_ADD); + tor_assert(n == 0); + eol = evbuffer_search_eol(buf, &content_length, NULL, EVBUFFER_EOL_CRLF); + tor_assert(eol.pos > content_length.pos); + tor_assert(eol.pos <= crlf.pos); + inspect_evbuffer(buf, &data, eol.pos - content_length.pos, &free_data, + &content_length); + + i = atoi(data); + if (free_data) + tor_free(data); + if (i < 0) { + log_warn(LD_PROTOCOL, "Content-Length is less than zero; it looks like " + "someone is trying to crash us."); + return -1; + } + contentlen = i; + /* if content-length is malformed, then our body length is 0. fine. */ + log_debug(LD_HTTP,"Got a contentlen of %d.",(int)contentlen); + if (bodylen < contentlen) { + if (!force_complete) { + log_debug(LD_HTTP,"body not all here yet."); + return 0; /* not all there yet */ + } + } + if (bodylen > contentlen) { + bodylen = contentlen; + log_debug(LD_HTTP,"bodylen reduced to %d.",(int)bodylen); + } + } + + if (headers_out) { + *headers_out = tor_malloc(headerlen+1); + evbuffer_remove(buf, *headers_out, headerlen); + (*headers_out)[headerlen] = '\0'; + } + if (body_out) { + tor_assert(headers_out); + tor_assert(body_used); + *body_used = bodylen; + *body_out = tor_malloc(bodylen+1); + evbuffer_remove(buf, *body_out, bodylen); + (*body_out)[bodylen] = '\0'; + } + return 1; +} +#endif + +/** + * Wait this many seconds before warning the user about using SOCKS unsafely + * again (requires that WarnUnsafeSocks is turned on). */ +#define SOCKS_WARN_INTERVAL 5 + +/** Warn that the user application has made an unsafe socks request using + * protocol socks_protocol on port port. Don't warn more than + * once per SOCKS_WARN_INTERVAL, unless safe_socks is set. */ +static void +log_unsafe_socks_warning(int socks_protocol, const char *address, + uint16_t port, int safe_socks) +{ + static ratelim_t socks_ratelim = RATELIM_INIT(SOCKS_WARN_INTERVAL); + + const or_options_t *options = get_options(); + if (! options->WarnUnsafeSocks) + return; + if (safe_socks) { + log_fn_ratelim(&socks_ratelim, LOG_WARN, LD_APP, + "Your application (using socks%d to port %d) is giving " + "Tor only an IP address. Applications that do DNS resolves " + "themselves may leak information. Consider using Socks4A " + "(e.g. via privoxy or socat) instead. For more information, " + "please see https://wiki.torproject.org/TheOnionRouter/" + "TorFAQ#SOCKSAndDNS.%s", + socks_protocol, + (int)port, + safe_socks ? " Rejecting." : ""); + } + control_event_client_status(LOG_WARN, + "DANGEROUS_SOCKS PROTOCOL=SOCKS%d ADDRESS=%s:%d", + socks_protocol, address, (int)port); +} + +/** Do not attempt to parse socks messages longer than this. This value is + * actually significantly higher than the longest possible socks message. */ +#define MAX_SOCKS_MESSAGE_LEN 512 + +/** Return a new socks_request_t. */ +socks_request_t * +socks_request_new(void) +{ + return tor_malloc_zero(sizeof(socks_request_t)); +} + +/** Free all storage held in the socks_request_t req. */ +void +socks_request_free(socks_request_t *req) +{ + if (!req) + return; + if (req->username) { + memwipe(req->username, 0x10, req->usernamelen); + tor_free(req->username); + } + if (req->password) { + memwipe(req->password, 0x04, req->passwordlen); + tor_free(req->password); + } + memwipe(req, 0xCC, sizeof(socks_request_t)); + tor_free(req); +} + +/** There is a (possibly incomplete) socks handshake on buf, of one + * of the forms + * - socks4: "socksheader username\\0" + * - socks4a: "socksheader username\\0 destaddr\\0" + * - socks5 phase one: "version #methods methods" + * - socks5 phase two: "version command 0 addresstype..." + * If it's a complete and valid handshake, and destaddr fits in + * MAX_SOCKS_ADDR_LEN bytes, then pull the handshake off the buf, + * assign to req, and return 1. + * + * If it's invalid or too big, return -1. + * + * Else it's not all there yet, leave buf alone and return 0. + * + * If you want to specify the socks reply, write it into req->reply + * and set req->replylen, else leave req->replylen alone. + * + * If log_sockstype is non-zero, then do a notice-level log of whether + * the connection is possibly leaking DNS requests locally or not. + * + * If safe_socks is true, then reject unsafe socks protocols. + * + * If returning 0 or -1, req->address and req->port are + * undefined. + */ +int +fetch_from_buf_socks(buf_t *buf, socks_request_t *req, + int log_sockstype, int safe_socks) +{ + int res; + ssize_t n_drain; + size_t want_length = 128; + + if (buf->datalen < 2) /* version and another byte */ + return 0; + + do { + n_drain = 0; + buf_pullup(buf, want_length, 0); + tor_assert(buf->head && buf->head->datalen >= 2); + want_length = 0; + + res = parse_socks(buf->head->data, buf->head->datalen, req, log_sockstype, + safe_socks, &n_drain, &want_length); + + if (n_drain < 0) + buf_clear(buf); + else if (n_drain > 0) + buf_remove_from_front(buf, n_drain); + + } while (res == 0 && buf->head && want_length < buf->datalen && + buf->datalen >= 2); + + return res; +} + +#ifdef USE_BUFFEREVENTS +/* As fetch_from_buf_socks(), but targets an evbuffer instead. */ +int +fetch_from_evbuffer_socks(struct evbuffer *buf, socks_request_t *req, + int log_sockstype, int safe_socks) +{ + char *data; + ssize_t n_drain; + size_t datalen, buflen, want_length; + int res; + + buflen = evbuffer_get_length(buf); + if (buflen < 2) + return 0; + + { + /* See if we can find the socks request in the first chunk of the buffer. + */ + struct evbuffer_iovec v; + int i; + n_drain = 0; + i = evbuffer_peek(buf, -1, NULL, &v, 1); + tor_assert(i == 1); + data = v.iov_base; + datalen = v.iov_len; + want_length = 0; + + res = parse_socks(data, datalen, req, log_sockstype, + safe_socks, &n_drain, &want_length); + + if (n_drain < 0) + evbuffer_drain(buf, evbuffer_get_length(buf)); + else if (n_drain > 0) + evbuffer_drain(buf, n_drain); + + if (res) + return res; + } + + /* Okay, the first chunk of the buffer didn't have a complete socks request. + * That means that either we don't have a whole socks request at all, or + * it's gotten split up. We're going to try passing parse_socks() bigger + * and bigger chunks until either it says "Okay, I got it", or it says it + * will need more data than we currently have. */ + + /* Loop while we have more data that we haven't given parse_socks() yet. */ + do { + int free_data = 0; + const size_t last_wanted = want_length; + n_drain = 0; + data = NULL; + datalen = inspect_evbuffer(buf, &data, want_length, &free_data, NULL); + + want_length = 0; + res = parse_socks(data, datalen, req, log_sockstype, + safe_socks, &n_drain, &want_length); + + if (free_data) + tor_free(data); + + if (n_drain < 0) + evbuffer_drain(buf, evbuffer_get_length(buf)); + else if (n_drain > 0) + evbuffer_drain(buf, n_drain); + + if (res == 0 && n_drain == 0 && want_length <= last_wanted) { + /* If we drained nothing, and we didn't ask for more than last time, + * then we probably wanted more data than the buffer actually had, + * and we're finding out that we're not satisified with it. It's + * time to break until we have more data. */ + break; + } + + buflen = evbuffer_get_length(buf); + } while (res == 0 && want_length <= buflen && buflen >= 2); + + return res; +} +#endif + +/** The size of the header of an Extended ORPort message: 2 bytes for + * COMMAND, 2 bytes for BODYLEN */ +#define EXT_OR_CMD_HEADER_SIZE 4 + +/** Read buf, which should contain an Extended ORPort message + * from a transport proxy. If well-formed, create and populate + * out with the Extended ORport message. Return 0 if the + * buffer was incomplete, 1 if it was well-formed and -1 if we + * encountered an error while parsing it. */ +int +fetch_ext_or_command_from_buf(buf_t *buf, ext_or_cmd_t **out) +{ + char hdr[EXT_OR_CMD_HEADER_SIZE]; + uint16_t len; + + check(); + if (buf->datalen < EXT_OR_CMD_HEADER_SIZE) + return 0; + peek_from_buf(hdr, sizeof(hdr), buf); + len = ntohs(get_uint16(hdr+2)); + if (buf->datalen < (unsigned)len + EXT_OR_CMD_HEADER_SIZE) + return 0; + *out = ext_or_cmd_new(len); + (*out)->cmd = ntohs(get_uint16(hdr)); + (*out)->len = len; + buf_remove_from_front(buf, EXT_OR_CMD_HEADER_SIZE); + fetch_from_buf((*out)->body, len, buf); + return 1; +} + +#ifdef USE_BUFFEREVENTS +/** Read buf, which should contain an Extended ORPort message + * from a transport proxy. If well-formed, create and populate + * out with the Extended ORport message. Return 0 if the + * buffer was incomplete, 1 if it was well-formed and -1 if we + * encountered an error while parsing it. */ +int +fetch_ext_or_command_from_evbuffer(struct evbuffer *buf, ext_or_cmd_t **out) +{ + char hdr[EXT_OR_CMD_HEADER_SIZE]; + uint16_t len; + size_t buf_len = evbuffer_get_length(buf); + + if (buf_len < EXT_OR_CMD_HEADER_SIZE) + return 0; + evbuffer_copyout(buf, hdr, EXT_OR_CMD_HEADER_SIZE); + len = ntohs(get_uint16(hdr+2)); + if (buf_len < (unsigned)len + EXT_OR_CMD_HEADER_SIZE) + return 0; + *out = ext_or_cmd_new(len); + (*out)->cmd = ntohs(get_uint16(hdr)); + (*out)->len = len; + evbuffer_drain(buf, EXT_OR_CMD_HEADER_SIZE); + evbuffer_remove(buf, (*out)->body, len); + return 1; +} +#endif + +/** Implementation helper to implement fetch_from_*_socks. Instead of looking + * at a buffer's contents, we look at the datalen bytes of data in + * data. Instead of removing data from the buffer, we set + * drain_out to the amount of data that should be removed (or -1 if the + * buffer should be cleared). Instead of pulling more data into the first + * chunk of the buffer, we set *want_length_out to the number of bytes + * we'd like to see in the input buffer, if they're available. */ +static int +parse_socks(const char *data, size_t datalen, socks_request_t *req, + int log_sockstype, int safe_socks, ssize_t *drain_out, + size_t *want_length_out) +{ + unsigned int len; + char tmpbuf[TOR_ADDR_BUF_LEN+1]; + tor_addr_t destaddr; + uint32_t destip; + uint8_t socksver; + char *next, *startaddr; + unsigned char usernamelen, passlen; + struct in_addr in; + + if (datalen < 2) { + /* We always need at least 2 bytes. */ + *want_length_out = 2; + return 0; + } + + if (req->socks_version == 5 && !req->got_auth) { + /* See if we have received authentication. Strictly speaking, we should + also check whether we actually negotiated username/password + authentication. But some broken clients will send us authentication + even if we negotiated SOCKS_NO_AUTH. */ + if (*data == 1) { /* username/pass version 1 */ + /* Format is: authversion [1 byte] == 1 + usernamelen [1 byte] + username [usernamelen bytes] + passlen [1 byte] + password [passlen bytes] */ + usernamelen = (unsigned char)*(data + 1); + if (datalen < 2u + usernamelen + 1u) { + *want_length_out = 2u + usernamelen + 1u; + return 0; + } + passlen = (unsigned char)*(data + 2u + usernamelen); + if (datalen < 2u + usernamelen + 1u + passlen) { + *want_length_out = 2u + usernamelen + 1u + passlen; + return 0; + } + req->replylen = 2; /* 2 bytes of response */ + req->reply[0] = 1; /* authversion == 1 */ + req->reply[1] = 0; /* authentication successful */ + log_debug(LD_APP, + "socks5: Accepted username/password without checking."); + if (usernamelen) { + req->username = tor_memdup(data+2u, usernamelen); + req->usernamelen = usernamelen; + } + if (passlen) { + req->password = tor_memdup(data+3u+usernamelen, passlen); + req->passwordlen = passlen; + } + *drain_out = 2u + usernamelen + 1u + passlen; + req->got_auth = 1; + *want_length_out = 7; /* Minimal socks5 sommand. */ + return 0; + } else if (req->auth_type == SOCKS_USER_PASS) { + /* unknown version byte */ + log_warn(LD_APP, "Socks5 username/password version %d not recognized; " + "rejecting.", (int)*data); + return -1; + } + } + + socksver = *data; + + switch (socksver) { /* which version of socks? */ + case 5: /* socks5 */ + + if (req->socks_version != 5) { /* we need to negotiate a method */ + unsigned char nummethods = (unsigned char)*(data+1); + int have_user_pass, have_no_auth; + int r=0; + tor_assert(!req->socks_version); + if (datalen < 2u+nummethods) { + *want_length_out = 2u+nummethods; + return 0; + } + if (!nummethods) + return -1; + req->replylen = 2; /* 2 bytes of response */ + req->reply[0] = 5; /* socks5 reply */ + have_user_pass = (memchr(data+2, SOCKS_USER_PASS, nummethods) !=NULL); + have_no_auth = (memchr(data+2, SOCKS_NO_AUTH, nummethods) !=NULL); + if (have_user_pass && !(have_no_auth && req->socks_prefer_no_auth)) { + req->auth_type = SOCKS_USER_PASS; + req->reply[1] = SOCKS_USER_PASS; /* tell client to use "user/pass" + auth method */ + req->socks_version = 5; /* remember we've already negotiated auth */ + log_debug(LD_APP,"socks5: accepted method 2 (username/password)"); + r=0; + } else if (have_no_auth) { + req->reply[1] = SOCKS_NO_AUTH; /* tell client to use "none" auth + method */ + req->socks_version = 5; /* remember we've already negotiated auth */ + log_debug(LD_APP,"socks5: accepted method 0 (no authentication)"); + r=0; + } else { + log_warn(LD_APP, + "socks5: offered methods don't include 'no auth' or " + "username/password. Rejecting."); + req->reply[1] = '\xFF'; /* reject all methods */ + r=-1; + } + /* Remove packet from buf. Some SOCKS clients will have sent extra + * junk at this point; let's hope it's an authentication message. */ + *drain_out = 2u + nummethods; + + return r; + } + if (req->auth_type != SOCKS_NO_AUTH && !req->got_auth) { + log_warn(LD_APP, + "socks5: negotiated authentication, but none provided"); + return -1; + } + /* we know the method; read in the request */ + log_debug(LD_APP,"socks5: checking request"); + if (datalen < 7) {/* basic info plus >=1 for addr plus 2 for port */ + *want_length_out = 7; + return 0; /* not yet */ + } + req->command = (unsigned char) *(data+1); + if (req->command != SOCKS_COMMAND_CONNECT && + req->command != SOCKS_COMMAND_RESOLVE && + req->command != SOCKS_COMMAND_RESOLVE_PTR) { + /* not a connect or resolve or a resolve_ptr? we don't support it. */ + log_warn(LD_APP,"socks5: command %d not recognized. Rejecting.", + req->command); + return -1; + } + switch (*(data+3)) { /* address type */ + case 1: /* IPv4 address */ + case 4: /* IPv6 address */ { + const int is_v6 = *(data+3) == 4; + const unsigned addrlen = is_v6 ? 16 : 4; + log_debug(LD_APP,"socks5: ipv4 address type"); + if (datalen < 6+addrlen) {/* ip/port there? */ + *want_length_out = 6+addrlen; + return 0; /* not yet */ + } + + if (is_v6) + tor_addr_from_ipv6_bytes(&destaddr, data+4); + else + tor_addr_from_ipv4n(&destaddr, get_uint32(data+4)); + + tor_addr_to_str(tmpbuf, &destaddr, sizeof(tmpbuf), 1); + + if (strlen(tmpbuf)+1 > MAX_SOCKS_ADDR_LEN) { + log_warn(LD_APP, + "socks5 IP takes %d bytes, which doesn't fit in %d. " + "Rejecting.", + (int)strlen(tmpbuf)+1,(int)MAX_SOCKS_ADDR_LEN); + return -1; + } + strlcpy(req->address,tmpbuf,sizeof(req->address)); + req->port = ntohs(get_uint16(data+4+addrlen)); + *drain_out = 6+addrlen; + if (req->command != SOCKS_COMMAND_RESOLVE_PTR && + !addressmap_have_mapping(req->address,0)) { + log_unsafe_socks_warning(5, req->address, req->port, safe_socks); + if (safe_socks) + return -1; + } + return 1; + } + case 3: /* fqdn */ + log_debug(LD_APP,"socks5: fqdn address type"); + if (req->command == SOCKS_COMMAND_RESOLVE_PTR) { + log_warn(LD_APP, "socks5 received RESOLVE_PTR command with " + "hostname type. Rejecting."); + return -1; + } + len = (unsigned char)*(data+4); + if (datalen < 7+len) { /* addr/port there? */ + *want_length_out = 7+len; + return 0; /* not yet */ + } + if (len+1 > MAX_SOCKS_ADDR_LEN) { + log_warn(LD_APP, + "socks5 hostname is %d bytes, which doesn't fit in " + "%d. Rejecting.", len+1,MAX_SOCKS_ADDR_LEN); + return -1; + } + memcpy(req->address,data+5,len); + req->address[len] = 0; + req->port = ntohs(get_uint16(data+5+len)); + *drain_out = 5+len+2; + if (!tor_strisprint(req->address) || strchr(req->address,'\"')) { + log_warn(LD_PROTOCOL, + "Your application (using socks5 to port %d) gave Tor " + "a malformed hostname: %s. Rejecting the connection.", + req->port, escaped(req->address)); + return -1; + } + if (log_sockstype) + log_notice(LD_APP, + "Your application (using socks5 to port %d) instructed " + "Tor to take care of the DNS resolution itself if " + "necessary. This is good.", req->port); + return 1; + default: /* unsupported */ + log_warn(LD_APP,"socks5: unsupported address type %d. Rejecting.", + (int) *(data+3)); + return -1; + } + tor_assert(0); + case 4: { /* socks4 */ + enum {socks4, socks4a} socks4_prot = socks4a; + const char *authstart, *authend; + /* http://ss5.sourceforge.net/socks4.protocol.txt */ + /* http://ss5.sourceforge.net/socks4A.protocol.txt */ + + req->socks_version = 4; + if (datalen < SOCKS4_NETWORK_LEN) {/* basic info available? */ + *want_length_out = SOCKS4_NETWORK_LEN; + return 0; /* not yet */ + } + // buf_pullup(buf, 1280, 0); + req->command = (unsigned char) *(data+1); + if (req->command != SOCKS_COMMAND_CONNECT && + req->command != SOCKS_COMMAND_RESOLVE) { + /* not a connect or resolve? we don't support it. (No resolve_ptr with + * socks4.) */ + log_warn(LD_APP,"socks4: command %d not recognized. Rejecting.", + req->command); + return -1; + } + + req->port = ntohs(get_uint16(data+2)); + destip = ntohl(get_uint32(data+4)); + if ((!req->port && req->command!=SOCKS_COMMAND_RESOLVE) || !destip) { + log_warn(LD_APP,"socks4: Port or DestIP is zero. Rejecting."); + return -1; + } + if (destip >> 8) { + log_debug(LD_APP,"socks4: destip not in form 0.0.0.x."); + in.s_addr = htonl(destip); + tor_inet_ntoa(&in,tmpbuf,sizeof(tmpbuf)); + if (strlen(tmpbuf)+1 > MAX_SOCKS_ADDR_LEN) { + log_debug(LD_APP,"socks4 addr (%d bytes) too long. Rejecting.", + (int)strlen(tmpbuf)); + return -1; + } + log_debug(LD_APP, + "socks4: successfully read destip (%s)", + safe_str_client(tmpbuf)); + socks4_prot = socks4; + } + + authstart = data + SOCKS4_NETWORK_LEN; + next = memchr(authstart, 0, + datalen-SOCKS4_NETWORK_LEN); + if (!next) { + if (datalen >= 1024) { + log_debug(LD_APP, "Socks4 user name too long; rejecting."); + return -1; + } + log_debug(LD_APP,"socks4: Username not here yet."); + *want_length_out = datalen+1024; /* More than we need, but safe */ + return 0; + } + authend = next; + tor_assert(next < data+datalen); + + startaddr = NULL; + if (socks4_prot != socks4a && + !addressmap_have_mapping(tmpbuf,0)) { + log_unsafe_socks_warning(4, tmpbuf, req->port, safe_socks); + + if (safe_socks) + return -1; + } + if (socks4_prot == socks4a) { + if (next+1 == data+datalen) { + log_debug(LD_APP,"socks4: No part of destaddr here yet."); + *want_length_out = datalen + 1024; /* More than we need, but safe */ + return 0; + } + startaddr = next+1; + next = memchr(startaddr, 0, data + datalen - startaddr); + if (!next) { + if (datalen >= 1024) { + log_debug(LD_APP,"socks4: Destaddr too long."); + return -1; + } + log_debug(LD_APP,"socks4: Destaddr not all here yet."); + *want_length_out = datalen + 1024; /* More than we need, but safe */ + return 0; + } + if (MAX_SOCKS_ADDR_LEN <= next-startaddr) { + log_warn(LD_APP,"socks4: Destaddr too long. Rejecting."); + return -1; + } + // tor_assert(next < buf->cur+buf->datalen); + + if (log_sockstype) + log_notice(LD_APP, + "Your application (using socks4a to port %d) instructed " + "Tor to take care of the DNS resolution itself if " + "necessary. This is good.", req->port); + } + log_debug(LD_APP,"socks4: Everything is here. Success."); + strlcpy(req->address, startaddr ? startaddr : tmpbuf, + sizeof(req->address)); + if (!tor_strisprint(req->address) || strchr(req->address,'\"')) { + log_warn(LD_PROTOCOL, + "Your application (using socks4 to port %d) gave Tor " + "a malformed hostname: %s. Rejecting the connection.", + req->port, escaped(req->address)); + return -1; + } + if (authend != authstart) { + req->got_auth = 1; + req->usernamelen = authend - authstart; + req->username = tor_memdup(authstart, authend - authstart); + } + /* next points to the final \0 on inbuf */ + *drain_out = next - data + 1; + return 1; + } + case 'G': /* get */ + case 'H': /* head */ + case 'P': /* put/post */ + case 'C': /* connect */ + strlcpy((char*)req->reply, +"HTTP/1.0 501 Tor is not an HTTP Proxy\r\n" +"Content-Type: text/html; charset=iso-8859-1\r\n\r\n" +"\n" +"\n" +"Tor is not an HTTP Proxy\n" +"\n" +"\n" +"

Tor is not an HTTP Proxy

\n" +"

\n" +"It appears you have configured your web browser to use Tor as an HTTP proxy." +"\n" +"This is not correct: Tor is a SOCKS proxy, not an HTTP proxy.\n" +"Please configure your client accordingly.\n" +"

\n" +"

\n" +"See " + "https://www.torproject.org/documentation.html for more " + "information.\n" +"\n" +"

\n" +"\n" +"\n" + , MAX_SOCKS_REPLY_LEN); + req->replylen = strlen((char*)req->reply)+1; + /* fall through */ + default: /* version is not socks4 or socks5 */ + log_warn(LD_APP, + "Socks version %d not recognized. (Tor is not an http proxy.)", + *(data)); + { + /* Tell the controller the first 8 bytes. */ + char *tmp = tor_strndup(data, datalen < 8 ? datalen : 8); + control_event_client_status(LOG_WARN, + "SOCKS_UNKNOWN_PROTOCOL DATA=\"%s\"", + escaped(tmp)); + tor_free(tmp); + } + return -1; + } +} + +/** Inspect a reply from SOCKS server stored in buf according + * to state, removing the protocol data upon success. Return 0 on + * incomplete response, 1 on success and -1 on error, in which case + * reason is set to a descriptive message (free() when finished + * with it). + * + * As a special case, 2 is returned when user/pass is required + * during SOCKS5 handshake and user/pass is configured. + */ +int +fetch_from_buf_socks_client(buf_t *buf, int state, char **reason) +{ + ssize_t drain = 0; + int r; + if (buf->datalen < 2) + return 0; + + buf_pullup(buf, MAX_SOCKS_MESSAGE_LEN, 0); + tor_assert(buf->head && buf->head->datalen >= 2); + + r = parse_socks_client((uint8_t*)buf->head->data, buf->head->datalen, + state, reason, &drain); + if (drain > 0) + buf_remove_from_front(buf, drain); + else if (drain < 0) + buf_clear(buf); + + return r; +} + +#ifdef USE_BUFFEREVENTS +/** As fetch_from_buf_socks_client, buf works on an evbuffer */ +int +fetch_from_evbuffer_socks_client(struct evbuffer *buf, int state, + char **reason) +{ + ssize_t drain = 0; + uint8_t *data; + size_t datalen; + int r; + + /* Linearize the SOCKS response in the buffer, up to 128 bytes. + * (parse_socks_client shouldn't need to see anything beyond that.) */ + datalen = evbuffer_get_length(buf); + if (datalen > MAX_SOCKS_MESSAGE_LEN) + datalen = MAX_SOCKS_MESSAGE_LEN; + data = evbuffer_pullup(buf, datalen); + + r = parse_socks_client(data, datalen, state, reason, &drain); + if (drain > 0) + evbuffer_drain(buf, drain); + else if (drain < 0) + evbuffer_drain(buf, evbuffer_get_length(buf)); + + return r; +} +#endif + +/** Implementation logic for fetch_from_*_socks_client. */ +static int +parse_socks_client(const uint8_t *data, size_t datalen, + int state, char **reason, + ssize_t *drain_out) +{ + unsigned int addrlen; + *drain_out = 0; + if (datalen < 2) + return 0; + + switch (state) { + case PROXY_SOCKS4_WANT_CONNECT_OK: + /* Wait for the complete response */ + if (datalen < 8) + return 0; + + if (data[1] != 0x5a) { + *reason = tor_strdup(socks4_response_code_to_string(data[1])); + return -1; + } + + /* Success */ + *drain_out = 8; + return 1; + + case PROXY_SOCKS5_WANT_AUTH_METHOD_NONE: + /* we don't have any credentials */ + if (data[1] != 0x00) { + *reason = tor_strdup("server doesn't support any of our " + "available authentication methods"); + return -1; + } + + log_info(LD_NET, "SOCKS 5 client: continuing without authentication"); + *drain_out = -1; + return 1; + + case PROXY_SOCKS5_WANT_AUTH_METHOD_RFC1929: + /* we have a username and password. return 1 if we can proceed without + * providing authentication, or 2 otherwise. */ + switch (data[1]) { + case 0x00: + log_info(LD_NET, "SOCKS 5 client: we have auth details but server " + "doesn't require authentication."); + *drain_out = -1; + return 1; + case 0x02: + log_info(LD_NET, "SOCKS 5 client: need authentication."); + *drain_out = -1; + return 2; + /* fall through */ + } + + *reason = tor_strdup("server doesn't support any of our available " + "authentication methods"); + return -1; + + case PROXY_SOCKS5_WANT_AUTH_RFC1929_OK: + /* handle server reply to rfc1929 authentication */ + if (data[1] != 0x00) { + *reason = tor_strdup("authentication failed"); + return -1; + } + + log_info(LD_NET, "SOCKS 5 client: authentication successful."); + *drain_out = -1; + return 1; + + case PROXY_SOCKS5_WANT_CONNECT_OK: + /* response is variable length. BND.ADDR, etc, isn't needed + * (don't bother with buf_pullup()), but make sure to eat all + * the data used */ + + /* wait for address type field to arrive */ + if (datalen < 4) + return 0; + + switch (data[3]) { + case 0x01: /* ip4 */ + addrlen = 4; + break; + case 0x04: /* ip6 */ + addrlen = 16; + break; + case 0x03: /* fqdn (can this happen here?) */ + if (datalen < 5) + return 0; + addrlen = 1 + data[4]; + break; + default: + *reason = tor_strdup("invalid response to connect request"); + return -1; + } + + /* wait for address and port */ + if (datalen < 6 + addrlen) + return 0; + + if (data[1] != 0x00) { + *reason = tor_strdup(socks5_response_code_to_string(data[1])); + return -1; + } + + *drain_out = 6 + addrlen; + return 1; + } + + /* shouldn't get here... */ + tor_assert(0); + + return -1; +} + +/** Return 1 iff buf looks more like it has an (obsolete) v0 controller + * command on it than any valid v1 controller command. */ +int +peek_buf_has_control0_command(buf_t *buf) +{ + if (buf->datalen >= 4) { + char header[4]; + uint16_t cmd; + peek_from_buf(header, sizeof(header), buf); + cmd = ntohs(get_uint16(header+2)); + if (cmd <= 0x14) + return 1; /* This is definitely not a v1 control command. */ + } + return 0; +} + +#ifdef USE_BUFFEREVENTS +int +peek_evbuffer_has_control0_command(struct evbuffer *buf) +{ + int result = 0; + if (evbuffer_get_length(buf) >= 4) { + int free_out = 0; + char *data = NULL; + size_t n = inspect_evbuffer(buf, &data, 4, &free_out, NULL); + uint16_t cmd; + tor_assert(n >= 4); + cmd = ntohs(get_uint16(data+2)); + if (cmd <= 0x14) + result = 1; + if (free_out) + tor_free(data); + } + return result; +} +#endif + +/** Return the index within buf at which ch first appears, + * or -1 if ch does not appear on buf. */ +static off_t +buf_find_offset_of_char(buf_t *buf, char ch) +{ + chunk_t *chunk; + off_t offset = 0; + for (chunk = buf->head; chunk; chunk = chunk->next) { + char *cp = memchr(chunk->data, ch, chunk->datalen); + if (cp) + return offset + (cp - chunk->data); + else + offset += chunk->datalen; + } + return -1; +} + +/** Try to read a single LF-terminated line from buf, and write it + * (including the LF), NUL-terminated, into the *data_len byte buffer + * at data_out. Set *data_len to the number of bytes in the + * line, not counting the terminating NUL. Return 1 if we read a whole line, + * return 0 if we don't have a whole line yet, and return -1 if the line + * length exceeds *data_len. + */ +int +fetch_from_buf_line(buf_t *buf, char *data_out, size_t *data_len) +{ + size_t sz; + off_t offset; + + if (!buf->head) + return 0; + + offset = buf_find_offset_of_char(buf, '\n'); + if (offset < 0) + return 0; + sz = (size_t) offset; + if (sz+2 > *data_len) { + *data_len = sz + 2; + return -1; + } + fetch_from_buf(data_out, sz+1, buf); + data_out[sz+1] = '\0'; + *data_len = sz+1; + return 1; +} + +/** Compress on uncompress the data_len bytes in data using the + * zlib state state, appending the result to buf. If + * done is true, flush the data in the state and finish the + * compression/uncompression. Return -1 on failure, 0 on success. */ +int +write_to_buf_zlib(buf_t *buf, tor_zlib_state_t *state, + const char *data, size_t data_len, + int done) +{ + char *next; + size_t old_avail, avail; + int over = 0; + do { + int need_new_chunk = 0; + if (!buf->tail || ! CHUNK_REMAINING_CAPACITY(buf->tail)) { + size_t cap = data_len / 4; + buf_add_chunk_with_capacity(buf, cap, 1); + } + next = CHUNK_WRITE_PTR(buf->tail); + avail = old_avail = CHUNK_REMAINING_CAPACITY(buf->tail); + switch (tor_zlib_process(state, &next, &avail, &data, &data_len, done)) { + case TOR_ZLIB_DONE: + over = 1; + break; + case TOR_ZLIB_ERR: + return -1; + case TOR_ZLIB_OK: + if (data_len == 0) + over = 1; + break; + case TOR_ZLIB_BUF_FULL: + if (avail) { + /* Zlib says we need more room (ZLIB_BUF_FULL). Start a new chunk + * automatically, whether were going to or not. */ + need_new_chunk = 1; + } + break; + } + buf->datalen += old_avail - avail; + buf->tail->datalen += old_avail - avail; + if (need_new_chunk) { + buf_add_chunk_with_capacity(buf, data_len/4, 1); + } + + } while (!over); + check(); + return 0; +} + +#ifdef USE_BUFFEREVENTS +int +write_to_evbuffer_zlib(struct evbuffer *buf, tor_zlib_state_t *state, + const char *data, size_t data_len, + int done) +{ + char *next; + size_t old_avail, avail; + int over = 0, n; + struct evbuffer_iovec vec[1]; + do { + { + size_t cap = data_len / 4; + if (cap < 128) + cap = 128; + /* XXXX NM this strategy is fragmentation-prone. We should really have + * two iovecs, and write first into the one, and then into the + * second if the first gets full. */ + n = evbuffer_reserve_space(buf, cap, vec, 1); + tor_assert(n == 1); + } + + next = vec[0].iov_base; + avail = old_avail = vec[0].iov_len; + + switch (tor_zlib_process(state, &next, &avail, &data, &data_len, done)) { + case TOR_ZLIB_DONE: + over = 1; + break; + case TOR_ZLIB_ERR: + return -1; + case TOR_ZLIB_OK: + if (data_len == 0) + over = 1; + break; + case TOR_ZLIB_BUF_FULL: + if (avail) { + /* Zlib says we need more room (ZLIB_BUF_FULL). Start a new chunk + * automatically, whether were going to or not. */ + } + break; + } + + /* XXXX possible infinite loop on BUF_FULL. */ + vec[0].iov_len = old_avail - avail; + evbuffer_commit_space(buf, vec, 1); + + } while (!over); + check(); + return 0; +} +#endif + +/** Set *output to contain a copy of the data in *input */ +int +generic_buffer_set_to_copy(generic_buffer_t **output, + const generic_buffer_t *input) +{ +#ifdef USE_BUFFEREVENTS + struct evbuffer_ptr ptr; + size_t remaining = evbuffer_get_length(input); + if (*output) { + evbuffer_drain(*output, evbuffer_get_length(*output)); + } else { + if (!(*output = evbuffer_new())) + return -1; + } + evbuffer_ptr_set((struct evbuffer*)input, &ptr, 0, EVBUFFER_PTR_SET); + while (remaining) { + struct evbuffer_iovec v[4]; + int n_used, i; + n_used = evbuffer_peek((struct evbuffer*)input, -1, &ptr, v, 4); + if (n_used < 0) + return -1; + for (i=0;ibuf is corrupted. + */ +void +assert_buf_ok(buf_t *buf) +{ + tor_assert(buf); + tor_assert(buf->magic == BUFFER_MAGIC); + + if (! buf->head) { + tor_assert(!buf->tail); + tor_assert(buf->datalen == 0); + } else { + chunk_t *ch; + size_t total = 0; + tor_assert(buf->tail); + for (ch = buf->head; ch; ch = ch->next) { + total += ch->datalen; + tor_assert(ch->datalen <= ch->memlen); + tor_assert(ch->data >= &ch->mem[0]); + tor_assert(ch->data < &ch->mem[0]+ch->memlen); + tor_assert(ch->data+ch->datalen <= &ch->mem[0] + ch->memlen); + if (!ch->next) + tor_assert(ch == buf->tail); + } + tor_assert(buf->datalen == total); + } +} + +#ifdef ENABLE_BUF_FREELISTS +/** Log an error and exit if fl is corrupted. + */ +static void +assert_freelist_ok(chunk_freelist_t *fl) +{ + chunk_t *ch; + int n; + tor_assert(fl->alloc_size > 0); + n = 0; + for (ch = fl->head; ch; ch = ch->next) { + tor_assert(CHUNK_ALLOC_SIZE(ch->memlen) == fl->alloc_size); + ++n; + } + tor_assert(n == fl->cur_length); + tor_assert(n >= fl->lowest_length); + tor_assert(n <= fl->max_length); +} +#endif + diff --git a/src/tor/buffers.h b/src/tor/buffers.h new file mode 100644 index 0000000..48b1185 --- /dev/null +++ b/src/tor/buffers.h @@ -0,0 +1,106 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file buffers.h + * \brief Header file for buffers.c. + **/ + +#ifndef TOR_BUFFERS_H +#define TOR_BUFFERS_H + +#include "testsupport.h" + +buf_t *buf_new(void); +buf_t *buf_new_with_capacity(size_t size); +void buf_free(buf_t *buf); +void buf_clear(buf_t *buf); +buf_t *buf_copy(const buf_t *buf); +void buf_shrink(buf_t *buf); +void buf_shrink_freelists(int free_all); +void buf_dump_freelist_sizes(int severity); + +size_t buf_datalen(const buf_t *buf); +size_t buf_allocation(const buf_t *buf); +size_t buf_slack(const buf_t *buf); + +int read_to_buf(tor_socket_t s, size_t at_most, buf_t *buf, int *reached_eof, + int *socket_error); +int read_to_buf_tls(tor_tls_t *tls, size_t at_most, buf_t *buf); + +int flush_buf(tor_socket_t s, buf_t *buf, size_t sz, size_t *buf_flushlen); +int flush_buf_tls(tor_tls_t *tls, buf_t *buf, size_t sz, size_t *buf_flushlen); + +int write_to_buf(const char *string, size_t string_len, buf_t *buf); +int write_to_buf_zlib(buf_t *buf, tor_zlib_state_t *state, + const char *data, size_t data_len, int done); +int move_buf_to_buf(buf_t *buf_out, buf_t *buf_in, size_t *buf_flushlen); +int fetch_from_buf(char *string, size_t string_len, buf_t *buf); +int fetch_var_cell_from_buf(buf_t *buf, var_cell_t **out, int linkproto); +int fetch_from_buf_http(buf_t *buf, + char **headers_out, size_t max_headerlen, + char **body_out, size_t *body_used, size_t max_bodylen, + int force_complete); +socks_request_t *socks_request_new(void); +void socks_request_free(socks_request_t *req); +int fetch_from_buf_socks(buf_t *buf, socks_request_t *req, + int log_sockstype, int safe_socks); +int fetch_from_buf_socks_client(buf_t *buf, int state, char **reason); +int fetch_from_buf_line(buf_t *buf, char *data_out, size_t *data_len); + +int peek_buf_has_control0_command(buf_t *buf); + +int fetch_ext_or_command_from_buf(buf_t *buf, ext_or_cmd_t **out); + +#ifdef USE_BUFFEREVENTS +int fetch_var_cell_from_evbuffer(struct evbuffer *buf, var_cell_t **out, + int linkproto); +int fetch_from_evbuffer_socks(struct evbuffer *buf, socks_request_t *req, + int log_sockstype, int safe_socks); +int fetch_from_evbuffer_socks_client(struct evbuffer *buf, int state, + char **reason); +int fetch_from_evbuffer_http(struct evbuffer *buf, + char **headers_out, size_t max_headerlen, + char **body_out, size_t *body_used, size_t max_bodylen, + int force_complete); +int peek_evbuffer_has_control0_command(struct evbuffer *buf); +int write_to_evbuffer_zlib(struct evbuffer *buf, tor_zlib_state_t *state, + const char *data, size_t data_len, + int done); +int fetch_ext_or_command_from_evbuffer(struct evbuffer *buf, + ext_or_cmd_t **out); +#endif + +#ifdef USE_BUFFEREVENTS +#define generic_buffer_new() evbuffer_new() +#define generic_buffer_len(b) evbuffer_get_length((b)) +#define generic_buffer_add(b,dat,len) evbuffer_add((b),(dat),(len)) +#define generic_buffer_get(b,buf,buflen) evbuffer_remove((b),(buf),(buflen)) +#define generic_buffer_clear(b) evbuffer_drain((b), evbuffer_get_length((b))) +#define generic_buffer_free(b) evbuffer_free((b)) +#define generic_buffer_fetch_ext_or_cmd(b, out) \ + fetch_ext_or_command_from_evbuffer((b), (out)) +#else +#define generic_buffer_new() buf_new() +#define generic_buffer_len(b) buf_datalen((b)) +#define generic_buffer_add(b,dat,len) write_to_buf((dat),(len),(b)) +#define generic_buffer_get(b,buf,buflen) fetch_from_buf((buf),(buflen),(b)) +#define generic_buffer_clear(b) buf_clear((b)) +#define generic_buffer_free(b) buf_free((b)) +#define generic_buffer_fetch_ext_or_cmd(b, out) \ + fetch_ext_or_command_from_buf((b), (out)) +#endif +int generic_buffer_set_to_copy(generic_buffer_t **output, + const generic_buffer_t *input); + +void assert_buf_ok(buf_t *buf); + +#ifdef BUFFERS_PRIVATE +STATIC int buf_find_string_offset(const buf_t *buf, const char *s, size_t n); +#endif + +#endif + diff --git a/src/tor/channel.c b/src/tor/channel.c new file mode 100644 index 0000000..62796d9 --- /dev/null +++ b/src/tor/channel.c @@ -0,0 +1,4191 @@ +/* * Copyright (c) 2012-2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file channel.c + * \brief OR-to-OR channel abstraction layer + **/ + +/* + * Define this so channel.h gives us things only channel_t subclasses + * should touch. + */ + +#define TOR_CHANNEL_INTERNAL_ + +#include "or.h" +#include "channel.h" +#include "channeltls.h" +#include "circuitbuild.h" +#include "circuitlist.h" +#include "circuitstats.h" +#include "connection_or.h" /* For var_cell_free() */ +#include "circuitmux.h" +#include "entrynodes.h" +#include "geoip.h" +#include "nodelist.h" +#include "relay.h" +#include "rephist.h" +#include "router.h" +#include "routerlist.h" + +/* Cell queue structure */ + +typedef struct cell_queue_entry_s cell_queue_entry_t; +struct cell_queue_entry_s { + TOR_SIMPLEQ_ENTRY(cell_queue_entry_s) next; + enum { + CELL_QUEUE_FIXED, + CELL_QUEUE_VAR, + CELL_QUEUE_PACKED + } type; + union { + struct { + cell_t *cell; + } fixed; + struct { + var_cell_t *var_cell; + } var; + struct { + packed_cell_t *packed_cell; + } packed; + } u; +}; + +/* Global lists of channels */ + +/* All channel_t instances */ +static smartlist_t *all_channels = NULL; + +/* All channel_t instances not in ERROR or CLOSED states */ +static smartlist_t *active_channels = NULL; + +/* All channel_t instances in ERROR or CLOSED states */ +static smartlist_t *finished_channels = NULL; + +/* All channel_listener_t instances */ +static smartlist_t *all_listeners = NULL; + +/* All channel_listener_t instances in LISTENING state */ +static smartlist_t *active_listeners = NULL; + +/* All channel_listener_t instances in LISTENING state */ +static smartlist_t *finished_listeners = NULL; + +/* Counter for ID numbers */ +static uint64_t n_channels_allocated = 0; + +/* Digest->channel map + * + * Similar to the one used in connection_or.c, this maps from the identity + * digest of a remote endpoint to a channel_t to that endpoint. Channels + * should be placed here when registered and removed when they close or error. + * If more than one channel exists, follow the next_with_same_id pointer + * as a linked list. + */ +HT_HEAD(channel_idmap, channel_idmap_entry_s) channel_identity_map = + HT_INITIALIZER(); + +typedef struct channel_idmap_entry_s { + HT_ENTRY(channel_idmap_entry_s) node; + uint8_t digest[DIGEST_LEN]; + TOR_LIST_HEAD(channel_list_s, channel_s) channel_list; +} channel_idmap_entry_t; + +static INLINE unsigned +channel_idmap_hash(const channel_idmap_entry_t *ent) +{ + const unsigned *a = (const unsigned *)ent->digest; +#if SIZEOF_INT == 4 + return a[0] ^ a[1] ^ a[2] ^ a[3] ^ a[4]; +#elif SIZEOF_INT == 8 + return a[0] ^ a[1]; +#endif +} + +static INLINE int +channel_idmap_eq(const channel_idmap_entry_t *a, + const channel_idmap_entry_t *b) +{ + return tor_memeq(a->digest, b->digest, DIGEST_LEN); +} + +HT_PROTOTYPE(channel_idmap, channel_idmap_entry_s, node, channel_idmap_hash, + channel_idmap_eq); +HT_GENERATE(channel_idmap, channel_idmap_entry_s, node, channel_idmap_hash, + channel_idmap_eq, 0.5, tor_malloc, tor_realloc, tor_free_); + +static cell_queue_entry_t * cell_queue_entry_dup(cell_queue_entry_t *q); +static void cell_queue_entry_free(cell_queue_entry_t *q, int handed_off); +static int cell_queue_entry_is_padding(cell_queue_entry_t *q); +static cell_queue_entry_t * +cell_queue_entry_new_fixed(cell_t *cell); +static cell_queue_entry_t * +cell_queue_entry_new_var(var_cell_t *var_cell); +static int is_destroy_cell(channel_t *chan, + const cell_queue_entry_t *q, circid_t *circid_out); + +/* Functions to maintain the digest map */ +static void channel_add_to_digest_map(channel_t *chan); +static void channel_remove_from_digest_map(channel_t *chan); + +/* + * Flush cells from just the outgoing queue without trying to get them + * from circuits; used internall by channel_flush_some_cells(). + */ +static ssize_t +channel_flush_some_cells_from_outgoing_queue(channel_t *chan, + ssize_t num_cells); +static void channel_force_free(channel_t *chan); +static void +channel_free_list(smartlist_t *channels, int mark_for_close); +static void +channel_listener_free_list(smartlist_t *channels, int mark_for_close); +static void channel_listener_force_free(channel_listener_t *chan_l); +static void +channel_write_cell_queue_entry(channel_t *chan, cell_queue_entry_t *q); + +/*********************************** + * Channel state utility functions * + **********************************/ + +/** + * Indicate whether a given channel state is valid + */ + +int +channel_state_is_valid(channel_state_t state) +{ + int is_valid; + + switch (state) { + case CHANNEL_STATE_CLOSED: + case CHANNEL_STATE_CLOSING: + case CHANNEL_STATE_ERROR: + case CHANNEL_STATE_MAINT: + case CHANNEL_STATE_OPENING: + case CHANNEL_STATE_OPEN: + is_valid = 1; + break; + case CHANNEL_STATE_LAST: + default: + is_valid = 0; + } + + return is_valid; +} + +/** + * Indicate whether a given channel listener state is valid + */ + +int +channel_listener_state_is_valid(channel_listener_state_t state) +{ + int is_valid; + + switch (state) { + case CHANNEL_LISTENER_STATE_CLOSED: + case CHANNEL_LISTENER_STATE_LISTENING: + case CHANNEL_LISTENER_STATE_CLOSING: + case CHANNEL_LISTENER_STATE_ERROR: + is_valid = 1; + break; + case CHANNEL_LISTENER_STATE_LAST: + default: + is_valid = 0; + } + + return is_valid; +} + +/** + * Indicate whether a channel state transition is valid + * + * This function takes two channel states and indicates whether a + * transition between them is permitted (see the state definitions and + * transition table in or.h at the channel_state_t typedef). + */ + +int +channel_state_can_transition(channel_state_t from, channel_state_t to) +{ + int is_valid; + + switch (from) { + case CHANNEL_STATE_CLOSED: + is_valid = (to == CHANNEL_STATE_OPENING); + break; + case CHANNEL_STATE_CLOSING: + is_valid = (to == CHANNEL_STATE_CLOSED || + to == CHANNEL_STATE_ERROR); + break; + case CHANNEL_STATE_ERROR: + is_valid = 0; + break; + case CHANNEL_STATE_MAINT: + is_valid = (to == CHANNEL_STATE_CLOSING || + to == CHANNEL_STATE_ERROR || + to == CHANNEL_STATE_OPEN); + break; + case CHANNEL_STATE_OPENING: + is_valid = (to == CHANNEL_STATE_CLOSING || + to == CHANNEL_STATE_ERROR || + to == CHANNEL_STATE_OPEN); + break; + case CHANNEL_STATE_OPEN: + is_valid = (to == CHANNEL_STATE_CLOSING || + to == CHANNEL_STATE_ERROR || + to == CHANNEL_STATE_MAINT); + break; + case CHANNEL_STATE_LAST: + default: + is_valid = 0; + } + + return is_valid; +} + +/** + * Indicate whether a channel listener state transition is valid + * + * This function takes two channel listener states and indicates whether a + * transition between them is permitted (see the state definitions and + * transition table in or.h at the channel_listener_state_t typedef). + */ + +int +channel_listener_state_can_transition(channel_listener_state_t from, + channel_listener_state_t to) +{ + int is_valid; + + switch (from) { + case CHANNEL_LISTENER_STATE_CLOSED: + is_valid = (to == CHANNEL_LISTENER_STATE_LISTENING); + break; + case CHANNEL_LISTENER_STATE_CLOSING: + is_valid = (to == CHANNEL_LISTENER_STATE_CLOSED || + to == CHANNEL_LISTENER_STATE_ERROR); + break; + case CHANNEL_LISTENER_STATE_ERROR: + is_valid = 0; + break; + case CHANNEL_LISTENER_STATE_LISTENING: + is_valid = (to == CHANNEL_LISTENER_STATE_CLOSING || + to == CHANNEL_LISTENER_STATE_ERROR); + break; + case CHANNEL_LISTENER_STATE_LAST: + default: + is_valid = 0; + } + + return is_valid; +} + +/** + * Return a human-readable description for a channel state + */ + +const char * +channel_state_to_string(channel_state_t state) +{ + const char *descr; + + switch (state) { + case CHANNEL_STATE_CLOSED: + descr = "closed"; + break; + case CHANNEL_STATE_CLOSING: + descr = "closing"; + break; + case CHANNEL_STATE_ERROR: + descr = "channel error"; + break; + case CHANNEL_STATE_MAINT: + descr = "temporarily suspended for maintenance"; + break; + case CHANNEL_STATE_OPENING: + descr = "opening"; + break; + case CHANNEL_STATE_OPEN: + descr = "open"; + break; + case CHANNEL_STATE_LAST: + default: + descr = "unknown or invalid channel state"; + } + + return descr; +} + +/** + * Return a human-readable description for a channel listenier state + */ + +const char * +channel_listener_state_to_string(channel_listener_state_t state) +{ + const char *descr; + + switch (state) { + case CHANNEL_LISTENER_STATE_CLOSED: + descr = "closed"; + break; + case CHANNEL_LISTENER_STATE_CLOSING: + descr = "closing"; + break; + case CHANNEL_LISTENER_STATE_ERROR: + descr = "channel listener error"; + break; + case CHANNEL_LISTENER_STATE_LISTENING: + descr = "listening"; + break; + case CHANNEL_LISTENER_STATE_LAST: + default: + descr = "unknown or invalid channel listener state"; + } + + return descr; +} + +/*************************************** + * Channel registration/unregistration * + ***************************************/ + +/** + * Register a channel + * + * This function registers a newly created channel in the global lists/maps + * of active channels. + */ + +void +channel_register(channel_t *chan) +{ + tor_assert(chan); + + /* No-op if already registered */ + if (chan->registered) return; + + log_debug(LD_CHANNEL, + "Registering channel %p (ID " U64_FORMAT ") " + "in state %s (%d) with digest %s", + chan, U64_PRINTF_ARG(chan->global_identifier), + channel_state_to_string(chan->state), chan->state, + hex_str(chan->identity_digest, DIGEST_LEN)); + + /* Make sure we have all_channels, then add it */ + if (!all_channels) all_channels = smartlist_new(); + smartlist_add(all_channels, chan); + + /* Is it finished? */ + if (chan->state == CHANNEL_STATE_CLOSED || + chan->state == CHANNEL_STATE_ERROR) { + /* Put it in the finished list, creating it if necessary */ + if (!finished_channels) finished_channels = smartlist_new(); + smartlist_add(finished_channels, chan); + } else { + /* Put it in the active list, creating it if necessary */ + if (!active_channels) active_channels = smartlist_new(); + smartlist_add(active_channels, chan); + + if (chan->state != CHANNEL_STATE_CLOSING) { + /* It should have a digest set */ + if (!tor_digest_is_zero(chan->identity_digest)) { + /* Yeah, we're good, add it to the map */ + channel_add_to_digest_map(chan); + } else { + log_info(LD_CHANNEL, + "Channel %p (global ID " U64_FORMAT ") " + "in state %s (%d) registered with no identity digest", + chan, U64_PRINTF_ARG(chan->global_identifier), + channel_state_to_string(chan->state), chan->state); + } + } + } + + /* Mark it as registered */ + chan->registered = 1; +} + +/** + * Unregister a channel + * + * This function removes a channel from the global lists and maps and is used + * when freeing a closed/errored channel. + */ + +void +channel_unregister(channel_t *chan) +{ + tor_assert(chan); + + /* No-op if not registered */ + if (!(chan->registered)) return; + + /* Is it finished? */ + if (chan->state == CHANNEL_STATE_CLOSED || + chan->state == CHANNEL_STATE_ERROR) { + /* Get it out of the finished list */ + if (finished_channels) smartlist_remove(finished_channels, chan); + } else { + /* Get it out of the active list */ + if (active_channels) smartlist_remove(active_channels, chan); + } + + /* Get it out of all_channels */ + if (all_channels) smartlist_remove(all_channels, chan); + + /* Mark it as unregistered */ + chan->registered = 0; + + /* Should it be in the digest map? */ + if (!tor_digest_is_zero(chan->identity_digest) && + !(chan->state == CHANNEL_STATE_CLOSING || + chan->state == CHANNEL_STATE_CLOSED || + chan->state == CHANNEL_STATE_ERROR)) { + /* Remove it */ + channel_remove_from_digest_map(chan); + } +} + +/** + * Register a channel listener + * + * This function registers a newly created channel listner in the global + * lists/maps of active channel listeners. + */ + +void +channel_listener_register(channel_listener_t *chan_l) +{ + tor_assert(chan_l); + + /* No-op if already registered */ + if (chan_l->registered) return; + + log_debug(LD_CHANNEL, + "Registering channel listener %p (ID " U64_FORMAT ") " + "in state %s (%d)", + chan_l, U64_PRINTF_ARG(chan_l->global_identifier), + channel_listener_state_to_string(chan_l->state), + chan_l->state); + + /* Make sure we have all_channels, then add it */ + if (!all_listeners) all_listeners = smartlist_new(); + smartlist_add(all_listeners, chan_l); + + /* Is it finished? */ + if (chan_l->state == CHANNEL_LISTENER_STATE_CLOSED || + chan_l->state == CHANNEL_LISTENER_STATE_ERROR) { + /* Put it in the finished list, creating it if necessary */ + if (!finished_listeners) finished_listeners = smartlist_new(); + smartlist_add(finished_listeners, chan_l); + } else { + /* Put it in the active list, creating it if necessary */ + if (!active_listeners) active_listeners = smartlist_new(); + smartlist_add(active_listeners, chan_l); + } + + /* Mark it as registered */ + chan_l->registered = 1; +} + +/** + * Unregister a channel listener + * + * This function removes a channel listener from the global lists and maps + * and is used when freeing a closed/errored channel listener. + */ + +void +channel_listener_unregister(channel_listener_t *chan_l) +{ + tor_assert(chan_l); + + /* No-op if not registered */ + if (!(chan_l->registered)) return; + + /* Is it finished? */ + if (chan_l->state == CHANNEL_LISTENER_STATE_CLOSED || + chan_l->state == CHANNEL_LISTENER_STATE_ERROR) { + /* Get it out of the finished list */ + if (finished_listeners) smartlist_remove(finished_listeners, chan_l); + } else { + /* Get it out of the active list */ + if (active_listeners) smartlist_remove(active_listeners, chan_l); + } + + /* Get it out of all_channels */ + if (all_listeners) smartlist_remove(all_listeners, chan_l); + + /* Mark it as unregistered */ + chan_l->registered = 0; +} + +/********************************* + * Channel digest map maintenance + *********************************/ + +/** + * Add a channel to the digest map + * + * This function adds a channel to the digest map and inserts it into the + * correct linked list if channels with that remote endpoint identity digest + * already exist. + */ + +static void +channel_add_to_digest_map(channel_t *chan) +{ + channel_idmap_entry_t *ent, search; + + tor_assert(chan); + + /* Assert that the state makes sense */ + tor_assert(!(chan->state == CHANNEL_STATE_CLOSING || + chan->state == CHANNEL_STATE_CLOSED || + chan->state == CHANNEL_STATE_ERROR)); + + /* Assert that there is a digest */ + tor_assert(!tor_digest_is_zero(chan->identity_digest)); + + memcpy(search.digest, chan->identity_digest, DIGEST_LEN); + ent = HT_FIND(channel_idmap, &channel_identity_map, &search); + if (! ent) { + ent = tor_malloc(sizeof(channel_idmap_entry_t)); + memcpy(ent->digest, chan->identity_digest, DIGEST_LEN); + TOR_LIST_INIT(&ent->channel_list); + HT_INSERT(channel_idmap, &channel_identity_map, ent); + } + TOR_LIST_INSERT_HEAD(&ent->channel_list, chan, next_with_same_id); + + log_debug(LD_CHANNEL, + "Added channel %p (global ID " U64_FORMAT ") " + "to identity map in state %s (%d) with digest %s", + chan, U64_PRINTF_ARG(chan->global_identifier), + channel_state_to_string(chan->state), chan->state, + hex_str(chan->identity_digest, DIGEST_LEN)); +} + +/** + * Remove a channel from the digest map + * + * This function removes a channel from the digest map and the linked list of + * channels for that digest if more than one exists. + */ + +static void +channel_remove_from_digest_map(channel_t *chan) +{ + channel_idmap_entry_t *ent, search; + + tor_assert(chan); + + /* Assert that there is a digest */ + tor_assert(!tor_digest_is_zero(chan->identity_digest)); + +#if 0 + /* Make sure we have a map */ + if (!channel_identity_map) { + /* + * No identity map, so we can't find it by definition. This + * case is similar to digestmap_get() failing below. + */ + log_warn(LD_BUG, + "Trying to remove channel %p (global ID " U64_FORMAT ") " + "with digest %s from identity map, but didn't have any identity " + "map", + chan, U64_PRINTF_ARG(chan->global_identifier), + hex_str(chan->identity_digest, DIGEST_LEN)); + /* Clear out its next/prev pointers */ + if (chan->next_with_same_id) { + chan->next_with_same_id->prev_with_same_id = chan->prev_with_same_id; + } + if (chan->prev_with_same_id) { + chan->prev_with_same_id->next_with_same_id = chan->next_with_same_id; + } + chan->next_with_same_id = NULL; + chan->prev_with_same_id = NULL; + + return; + } +#endif + + /* Pull it out of its list, wherever that list is */ + TOR_LIST_REMOVE(chan, next_with_same_id); + + memcpy(search.digest, chan->identity_digest, DIGEST_LEN); + ent = HT_FIND(channel_idmap, &channel_identity_map, &search); + + /* Look for it in the map */ + if (ent) { + /* Okay, it's here */ + + if (TOR_LIST_EMPTY(&ent->channel_list)) { + HT_REMOVE(channel_idmap, &channel_identity_map, ent); + tor_free(ent); + } + + log_debug(LD_CHANNEL, + "Removed channel %p (global ID " U64_FORMAT ") from " + "identity map in state %s (%d) with digest %s", + chan, U64_PRINTF_ARG(chan->global_identifier), + channel_state_to_string(chan->state), chan->state, + hex_str(chan->identity_digest, DIGEST_LEN)); + } else { + /* Shouldn't happen */ + log_warn(LD_BUG, + "Trying to remove channel %p (global ID " U64_FORMAT ") with " + "digest %s from identity map, but couldn't find any with " + "that digest", + chan, U64_PRINTF_ARG(chan->global_identifier), + hex_str(chan->identity_digest, DIGEST_LEN)); + } +} + +/**************************** + * Channel lookup functions * + ***************************/ + +/** + * Find channel by global ID + * + * This function searches for a channel by the global_identifier assigned + * at initialization time. This identifier is unique for the lifetime of the + * Tor process. + */ + +channel_t * +channel_find_by_global_id(uint64_t global_identifier) +{ + channel_t *rv = NULL; + + if (all_channels && smartlist_len(all_channels) > 0) { + SMARTLIST_FOREACH_BEGIN(all_channels, channel_t *, curr) { + if (curr->global_identifier == global_identifier) { + rv = curr; + break; + } + } SMARTLIST_FOREACH_END(curr); + } + + return rv; +} + +/** + * Find channel by digest of the remote endpoint + * + * This function looks up a channel by the digest of its remote endpoint in + * the channel digest map. It's possible that more than one channel to a + * given endpoint exists. Use channel_next_with_digest() to walk the list. + */ + +channel_t * +channel_find_by_remote_digest(const char *identity_digest) +{ + channel_t *rv = NULL; + channel_idmap_entry_t *ent, search; + + tor_assert(identity_digest); + + memcpy(search.digest, identity_digest, DIGEST_LEN); + ent = HT_FIND(channel_idmap, &channel_identity_map, &search); + if (ent) { + rv = TOR_LIST_FIRST(&ent->channel_list); + } + + return rv; +} + +/** + * Get next channel with digest + * + * This function takes a channel and finds the next channel in the list + * with the same digest. + */ + +channel_t * +channel_next_with_digest(channel_t *chan) +{ + tor_assert(chan); + + return TOR_LIST_NEXT(chan, next_with_same_id); +} + +/** + * Initialize a channel + * + * This function should be called by subclasses to set up some per-channel + * variables. I.e., this is the superclass constructor. Before this, the + * channel should be allocated with tor_malloc_zero(). + */ + +void +channel_init(channel_t *chan) +{ + tor_assert(chan); + + /* Assign an ID and bump the counter */ + chan->global_identifier = n_channels_allocated++; + + /* Init timestamp */ + chan->timestamp_last_added_nonpadding = time(NULL); + + /* Init next_circ_id */ + chan->next_circ_id = crypto_rand_int(1 << 15); + + /* Initialize queues. */ + TOR_SIMPLEQ_INIT(&chan->incoming_queue); + TOR_SIMPLEQ_INIT(&chan->outgoing_queue); + + /* Initialize list entries. */ + memset(&chan->next_with_same_id, 0, sizeof(chan->next_with_same_id)); + + /* Timestamp it */ + channel_timestamp_created(chan); + + /* It hasn't been open yet. */ + chan->has_been_open = 0; +} + +/** + * Initialize a channel listener + * + * This function should be called by subclasses to set up some per-channel + * variables. I.e., this is the superclass constructor. Before this, the + * channel listener should be allocated with tor_malloc_zero(). + */ + +void +channel_init_listener(channel_listener_t *chan_l) +{ + tor_assert(chan_l); + + /* Assign an ID and bump the counter */ + chan_l->global_identifier = n_channels_allocated++; + + /* Timestamp it */ + channel_listener_timestamp_created(chan_l); +} + +/** + * Free a channel; nothing outside of channel.c and subclasses should call + * this - it frees channels after they have closed and been unregistered. + */ + +void +channel_free(channel_t *chan) +{ + if (!chan) return; + + /* It must be closed or errored */ + tor_assert(chan->state == CHANNEL_STATE_CLOSED || + chan->state == CHANNEL_STATE_ERROR); + /* It must be deregistered */ + tor_assert(!(chan->registered)); + + log_debug(LD_CHANNEL, + "Freeing channel " U64_FORMAT " at %p", + U64_PRINTF_ARG(chan->global_identifier), chan); + + /* + * Get rid of cmux policy before we do anything, so cmux policies don't + * see channels in weird half-freed states. + */ + if (chan->cmux) { + circuitmux_set_policy(chan->cmux, NULL); + } + + /* Call a free method if there is one */ + if (chan->free) chan->free(chan); + + channel_clear_remote_end(chan); + + /* Get rid of cmux */ + if (chan->cmux) { + circuitmux_detach_all_circuits(chan->cmux); + circuitmux_mark_destroyed_circids_usable(chan->cmux, chan); + circuitmux_free(chan->cmux); + chan->cmux = NULL; + } + + /* We're in CLOSED or ERROR, so the cell queue is already empty */ + + tor_free(chan); +} + +/** + * Free a channel listener; nothing outside of channel.c and subclasses + * should call this - it frees channel listeners after they have closed and + * been unregistered. + */ + +void +channel_listener_free(channel_listener_t *chan_l) +{ + if (!chan_l) return; + + log_debug(LD_CHANNEL, + "Freeing channel_listener_t " U64_FORMAT " at %p", + U64_PRINTF_ARG(chan_l->global_identifier), + chan_l); + + /* It must be closed or errored */ + tor_assert(chan_l->state == CHANNEL_LISTENER_STATE_CLOSED || + chan_l->state == CHANNEL_LISTENER_STATE_ERROR); + /* It must be deregistered */ + tor_assert(!(chan_l->registered)); + + /* Call a free method if there is one */ + if (chan_l->free) chan_l->free(chan_l); + + /* + * We're in CLOSED or ERROR, so the incoming channel queue is already + * empty. + */ + + tor_free(chan_l); +} + +/** + * Free a channel and skip the state/registration asserts; this internal- + * use-only function should be called only from channel_free_all() when + * shutting down the Tor process. + */ + +static void +channel_force_free(channel_t *chan) +{ + cell_queue_entry_t *cell, *cell_tmp; + tor_assert(chan); + + log_debug(LD_CHANNEL, + "Force-freeing channel " U64_FORMAT " at %p", + U64_PRINTF_ARG(chan->global_identifier), chan); + + /* + * Get rid of cmux policy before we do anything, so cmux policies don't + * see channels in weird half-freed states. + */ + if (chan->cmux) { + circuitmux_set_policy(chan->cmux, NULL); + } + + /* Call a free method if there is one */ + if (chan->free) chan->free(chan); + + channel_clear_remote_end(chan); + + /* Get rid of cmux */ + if (chan->cmux) { + circuitmux_free(chan->cmux); + chan->cmux = NULL; + } + + /* We might still have a cell queue; kill it */ + TOR_SIMPLEQ_FOREACH_SAFE(cell, &chan->incoming_queue, next, cell_tmp) { + cell_queue_entry_free(cell, 0); + } + TOR_SIMPLEQ_INIT(&chan->incoming_queue); + + /* Outgoing cell queue is similar, but we can have to free packed cells */ + TOR_SIMPLEQ_FOREACH_SAFE(cell, &chan->outgoing_queue, next, cell_tmp) { + cell_queue_entry_free(cell, 0); + } + TOR_SIMPLEQ_INIT(&chan->outgoing_queue); + + tor_free(chan); +} + +/** + * Free a channel listener and skip the state/reigstration asserts; this + * internal-use-only function should be called only from channel_free_all() + * when shutting down the Tor process. + */ + +static void +channel_listener_force_free(channel_listener_t *chan_l) +{ + tor_assert(chan_l); + + log_debug(LD_CHANNEL, + "Force-freeing channel_listener_t " U64_FORMAT " at %p", + U64_PRINTF_ARG(chan_l->global_identifier), + chan_l); + + /* Call a free method if there is one */ + if (chan_l->free) chan_l->free(chan_l); + + /* + * The incoming list just gets emptied and freed; we request close on + * any channels we find there, but since we got called while shutting + * down they will get deregistered and freed elsewhere anyway. + */ + if (chan_l->incoming_list) { + SMARTLIST_FOREACH_BEGIN(chan_l->incoming_list, + channel_t *, qchan) { + channel_mark_for_close(qchan); + } SMARTLIST_FOREACH_END(qchan); + + smartlist_free(chan_l->incoming_list); + chan_l->incoming_list = NULL; + } + + tor_free(chan_l); +} + +/** + * Return the current registered listener for a channel listener + * + * This function returns a function pointer to the current registered + * handler for new incoming channels on a channel listener. + */ + +channel_listener_fn_ptr +channel_listener_get_listener_fn(channel_listener_t *chan_l) +{ + tor_assert(chan_l); + + if (chan_l->state == CHANNEL_LISTENER_STATE_LISTENING) + return chan_l->listener; + + return NULL; +} + +/** + * Set the listener for a channel listener + * + * This function sets the handler for new incoming channels on a channel + * listener. + */ + +void +channel_listener_set_listener_fn(channel_listener_t *chan_l, + channel_listener_fn_ptr listener) +{ + tor_assert(chan_l); + tor_assert(chan_l->state == CHANNEL_LISTENER_STATE_LISTENING); + + log_debug(LD_CHANNEL, + "Setting listener callback for channel listener %p " + "(global ID " U64_FORMAT ") to %p", + chan_l, U64_PRINTF_ARG(chan_l->global_identifier), + listener); + + chan_l->listener = listener; + if (chan_l->listener) channel_listener_process_incoming(chan_l); +} + +/** + * Return the fixed-length cell handler for a channel + * + * This function gets the handler for incoming fixed-length cells installed + * on a channel. + */ + +channel_cell_handler_fn_ptr +channel_get_cell_handler(channel_t *chan) +{ + tor_assert(chan); + + if (chan->state == CHANNEL_STATE_OPENING || + chan->state == CHANNEL_STATE_OPEN || + chan->state == CHANNEL_STATE_MAINT) + return chan->cell_handler; + + return NULL; +} + +/** + * Return the variable-length cell handler for a channel + * + * This function gets the handler for incoming variable-length cells + * installed on a channel. + */ + +channel_var_cell_handler_fn_ptr +channel_get_var_cell_handler(channel_t *chan) +{ + tor_assert(chan); + + if (chan->state == CHANNEL_STATE_OPENING || + chan->state == CHANNEL_STATE_OPEN || + chan->state == CHANNEL_STATE_MAINT) + return chan->var_cell_handler; + + return NULL; +} + +/** + * Set both cell handlers for a channel + * + * This function sets both the fixed-length and variable length cell handlers + * for a channel and processes any incoming cells that had been blocked in the + * queue because none were available. + */ + +void +channel_set_cell_handlers(channel_t *chan, + channel_cell_handler_fn_ptr cell_handler, + channel_var_cell_handler_fn_ptr + var_cell_handler) +{ + int try_again = 0; + + tor_assert(chan); + tor_assert(chan->state == CHANNEL_STATE_OPENING || + chan->state == CHANNEL_STATE_OPEN || + chan->state == CHANNEL_STATE_MAINT); + + log_debug(LD_CHANNEL, + "Setting cell_handler callback for channel %p to %p", + chan, cell_handler); + log_debug(LD_CHANNEL, + "Setting var_cell_handler callback for channel %p to %p", + chan, var_cell_handler); + + /* Should we try the queue? */ + if (cell_handler && + cell_handler != chan->cell_handler) try_again = 1; + if (var_cell_handler && + var_cell_handler != chan->var_cell_handler) try_again = 1; + + /* Change them */ + chan->cell_handler = cell_handler; + chan->var_cell_handler = var_cell_handler; + + /* Re-run the queue if we have one and there's any reason to */ + if (! TOR_SIMPLEQ_EMPTY(&chan->incoming_queue) && + try_again && + (chan->cell_handler || + chan->var_cell_handler)) channel_process_cells(chan); +} + +/* + * On closing channels + * + * There are three functions that close channels, for use in + * different circumstances: + * + * - Use channel_mark_for_close() for most cases + * - Use channel_close_from_lower_layer() if you are connection_or.c + * and the other end closes the underlying connection. + * - Use channel_close_for_error() if you are connection_or.c and + * some sort of error has occurred. + */ + +/** + * Mark a channel for closure + * + * This function tries to close a channel_t; it will go into the CLOSING + * state, and eventually the lower layer should put it into the CLOSED or + * ERROR state. Then, channel_run_cleanup() will eventually free it. + */ + +void +channel_mark_for_close(channel_t *chan) +{ + tor_assert(chan != NULL); + tor_assert(chan->close != NULL); + + /* If it's already in CLOSING, CLOSED or ERROR, this is a no-op */ + if (chan->state == CHANNEL_STATE_CLOSING || + chan->state == CHANNEL_STATE_CLOSED || + chan->state == CHANNEL_STATE_ERROR) return; + + log_debug(LD_CHANNEL, + "Closing channel %p (global ID " U64_FORMAT ") " + "by request", + chan, U64_PRINTF_ARG(chan->global_identifier)); + + /* Note closing by request from above */ + chan->reason_for_closing = CHANNEL_CLOSE_REQUESTED; + + /* Change state to CLOSING */ + channel_change_state(chan, CHANNEL_STATE_CLOSING); + + /* Tell the lower layer */ + chan->close(chan); + + /* + * It's up to the lower layer to change state to CLOSED or ERROR when we're + * ready; we'll try to free channels that are in the finished list from + * channel_run_cleanup(). The lower layer should do this by calling + * channel_closed(). + */ +} + +/** + * Mark a channel listener for closure + * + * This function tries to close a channel_listener_t; it will go into the + * CLOSING state, and eventually the lower layer should put it into the CLOSED + * or ERROR state. Then, channel_run_cleanup() will eventually free it. + */ + +void +channel_listener_mark_for_close(channel_listener_t *chan_l) +{ + tor_assert(chan_l != NULL); + tor_assert(chan_l->close != NULL); + + /* If it's already in CLOSING, CLOSED or ERROR, this is a no-op */ + if (chan_l->state == CHANNEL_LISTENER_STATE_CLOSING || + chan_l->state == CHANNEL_LISTENER_STATE_CLOSED || + chan_l->state == CHANNEL_LISTENER_STATE_ERROR) return; + + log_debug(LD_CHANNEL, + "Closing channel listener %p (global ID " U64_FORMAT ") " + "by request", + chan_l, U64_PRINTF_ARG(chan_l->global_identifier)); + + /* Note closing by request from above */ + chan_l->reason_for_closing = CHANNEL_LISTENER_CLOSE_REQUESTED; + + /* Change state to CLOSING */ + channel_listener_change_state(chan_l, CHANNEL_LISTENER_STATE_CLOSING); + + /* Tell the lower layer */ + chan_l->close(chan_l); + + /* + * It's up to the lower layer to change state to CLOSED or ERROR when we're + * ready; we'll try to free channels that are in the finished list from + * channel_run_cleanup(). The lower layer should do this by calling + * channel_listener_closed(). + */ +} + +/** + * Close a channel from the lower layer + * + * Notify the channel code that the channel is being closed due to a non-error + * condition in the lower layer. This does not call the close() method, since + * the lower layer already knows. + */ + +void +channel_close_from_lower_layer(channel_t *chan) +{ + tor_assert(chan != NULL); + + /* If it's already in CLOSING, CLOSED or ERROR, this is a no-op */ + if (chan->state == CHANNEL_STATE_CLOSING || + chan->state == CHANNEL_STATE_CLOSED || + chan->state == CHANNEL_STATE_ERROR) return; + + log_debug(LD_CHANNEL, + "Closing channel %p (global ID " U64_FORMAT ") " + "due to lower-layer event", + chan, U64_PRINTF_ARG(chan->global_identifier)); + + /* Note closing by event from below */ + chan->reason_for_closing = CHANNEL_CLOSE_FROM_BELOW; + + /* Change state to CLOSING */ + channel_change_state(chan, CHANNEL_STATE_CLOSING); +} + +/** + * Close a channel listener from the lower layer + * + * Notify the channel code that the channel listener is being closed due to a + * non-error condition in the lower layer. This does not call the close() + * method, since the lower layer already knows. + */ + +void +channel_listener_close_from_lower_layer(channel_listener_t *chan_l) +{ + tor_assert(chan_l != NULL); + + /* If it's already in CLOSING, CLOSED or ERROR, this is a no-op */ + if (chan_l->state == CHANNEL_LISTENER_STATE_CLOSING || + chan_l->state == CHANNEL_LISTENER_STATE_CLOSED || + chan_l->state == CHANNEL_LISTENER_STATE_ERROR) return; + + log_debug(LD_CHANNEL, + "Closing channel listener %p (global ID " U64_FORMAT ") " + "due to lower-layer event", + chan_l, U64_PRINTF_ARG(chan_l->global_identifier)); + + /* Note closing by event from below */ + chan_l->reason_for_closing = CHANNEL_LISTENER_CLOSE_FROM_BELOW; + + /* Change state to CLOSING */ + channel_listener_change_state(chan_l, CHANNEL_LISTENER_STATE_CLOSING); +} + +/** + * Notify that the channel is being closed due to an error condition + * + * This function is called by the lower layer implementing the transport + * when a channel must be closed due to an error condition. This does not + * call the channel's close method, since the lower layer already knows. + */ + +void +channel_close_for_error(channel_t *chan) +{ + tor_assert(chan != NULL); + + /* If it's already in CLOSING, CLOSED or ERROR, this is a no-op */ + if (chan->state == CHANNEL_STATE_CLOSING || + chan->state == CHANNEL_STATE_CLOSED || + chan->state == CHANNEL_STATE_ERROR) return; + + log_debug(LD_CHANNEL, + "Closing channel %p due to lower-layer error", + chan); + + /* Note closing by event from below */ + chan->reason_for_closing = CHANNEL_CLOSE_FOR_ERROR; + + /* Change state to CLOSING */ + channel_change_state(chan, CHANNEL_STATE_CLOSING); +} + +/** + * Notify that the channel listener is being closed due to an error condition + * + * This function is called by the lower layer implementing the transport + * when a channel listener must be closed due to an error condition. This + * does not call the channel listener's close method, since the lower layer + * already knows. + */ + +void +channel_listener_close_for_error(channel_listener_t *chan_l) +{ + tor_assert(chan_l != NULL); + + /* If it's already in CLOSING, CLOSED or ERROR, this is a no-op */ + if (chan_l->state == CHANNEL_LISTENER_STATE_CLOSING || + chan_l->state == CHANNEL_LISTENER_STATE_CLOSED || + chan_l->state == CHANNEL_LISTENER_STATE_ERROR) return; + + log_debug(LD_CHANNEL, + "Closing channel listener %p (global ID " U64_FORMAT ") " + "due to lower-layer error", + chan_l, U64_PRINTF_ARG(chan_l->global_identifier)); + + /* Note closing by event from below */ + chan_l->reason_for_closing = CHANNEL_LISTENER_CLOSE_FOR_ERROR; + + /* Change state to CLOSING */ + channel_listener_change_state(chan_l, CHANNEL_LISTENER_STATE_CLOSING); +} + +/** + * Notify that the lower layer is finished closing the channel + * + * This function should be called by the lower layer when a channel + * is finished closing and it should be regarded as inactive and + * freed by the channel code. + */ + +void +channel_closed(channel_t *chan) +{ + tor_assert(chan); + tor_assert(chan->state == CHANNEL_STATE_CLOSING || + chan->state == CHANNEL_STATE_CLOSED || + chan->state == CHANNEL_STATE_ERROR); + + /* No-op if already inactive */ + if (chan->state == CHANNEL_STATE_CLOSED || + chan->state == CHANNEL_STATE_ERROR) return; + + /* Inform any pending (not attached) circs that they should + * give up. */ + if (! chan->has_been_open) + circuit_n_chan_done(chan, 0); + + /* Now close all the attached circuits on it. */ + circuit_unlink_all_from_channel(chan, END_CIRC_REASON_CHANNEL_CLOSED); + + if (chan->reason_for_closing != CHANNEL_CLOSE_FOR_ERROR) { + channel_change_state(chan, CHANNEL_STATE_CLOSED); + } else { + channel_change_state(chan, CHANNEL_STATE_ERROR); + } +} + +/** + * Notify that the lower layer is finished closing the channel listener + * + * This function should be called by the lower layer when a channel listener + * is finished closing and it should be regarded as inactive and + * freed by the channel code. + */ + +void +channel_listener_closed(channel_listener_t *chan_l) +{ + tor_assert(chan_l); + tor_assert(chan_l->state == CHANNEL_LISTENER_STATE_CLOSING || + chan_l->state == CHANNEL_LISTENER_STATE_CLOSED || + chan_l->state == CHANNEL_LISTENER_STATE_ERROR); + + /* No-op if already inactive */ + if (chan_l->state == CHANNEL_LISTENER_STATE_CLOSED || + chan_l->state == CHANNEL_LISTENER_STATE_ERROR) return; + + if (chan_l->reason_for_closing != CHANNEL_LISTENER_CLOSE_FOR_ERROR) { + channel_listener_change_state(chan_l, CHANNEL_LISTENER_STATE_CLOSED); + } else { + channel_listener_change_state(chan_l, CHANNEL_LISTENER_STATE_ERROR); + } +} + +/** + * Clear the identity_digest of a channel + * + * This function clears the identity digest of the remote endpoint for a + * channel; this is intended for use by the lower layer. + */ + +void +channel_clear_identity_digest(channel_t *chan) +{ + int state_not_in_map; + + tor_assert(chan); + + log_debug(LD_CHANNEL, + "Clearing remote endpoint digest on channel %p with " + "global ID " U64_FORMAT, + chan, U64_PRINTF_ARG(chan->global_identifier)); + + state_not_in_map = + (chan->state == CHANNEL_STATE_CLOSING || + chan->state == CHANNEL_STATE_CLOSED || + chan->state == CHANNEL_STATE_ERROR); + + if (!state_not_in_map && chan->registered && + !tor_digest_is_zero(chan->identity_digest)) + /* if it's registered get it out of the digest map */ + channel_remove_from_digest_map(chan); + + memset(chan->identity_digest, 0, + sizeof(chan->identity_digest)); +} + +/** + * Set the identity_digest of a channel + * + * This function sets the identity digest of the remote endpoint for a + * channel; this is intended for use by the lower layer. + */ + +void +channel_set_identity_digest(channel_t *chan, + const char *identity_digest) +{ + int was_in_digest_map, should_be_in_digest_map, state_not_in_map; + + tor_assert(chan); + + log_debug(LD_CHANNEL, + "Setting remote endpoint digest on channel %p with " + "global ID " U64_FORMAT " to digest %s", + chan, U64_PRINTF_ARG(chan->global_identifier), + identity_digest ? + hex_str(identity_digest, DIGEST_LEN) : "(null)"); + + state_not_in_map = + (chan->state == CHANNEL_STATE_CLOSING || + chan->state == CHANNEL_STATE_CLOSED || + chan->state == CHANNEL_STATE_ERROR); + was_in_digest_map = + !state_not_in_map && + chan->registered && + !tor_digest_is_zero(chan->identity_digest); + should_be_in_digest_map = + !state_not_in_map && + chan->registered && + (identity_digest && + !tor_digest_is_zero(identity_digest)); + + if (was_in_digest_map) + /* We should always remove it; we'll add it back if we're writing + * in a new digest. + */ + channel_remove_from_digest_map(chan); + + if (identity_digest) { + memcpy(chan->identity_digest, + identity_digest, + sizeof(chan->identity_digest)); + } else { + memset(chan->identity_digest, 0, + sizeof(chan->identity_digest)); + } + + /* Put it in the digest map if we should */ + if (should_be_in_digest_map) + channel_add_to_digest_map(chan); +} + +/** + * Clear the remote end metadata (identity_digest/nickname) of a channel + * + * This function clears all the remote end info from a channel; this is + * intended for use by the lower layer. + */ + +void +channel_clear_remote_end(channel_t *chan) +{ + int state_not_in_map; + + tor_assert(chan); + + log_debug(LD_CHANNEL, + "Clearing remote endpoint identity on channel %p with " + "global ID " U64_FORMAT, + chan, U64_PRINTF_ARG(chan->global_identifier)); + + state_not_in_map = + (chan->state == CHANNEL_STATE_CLOSING || + chan->state == CHANNEL_STATE_CLOSED || + chan->state == CHANNEL_STATE_ERROR); + + if (!state_not_in_map && chan->registered && + !tor_digest_is_zero(chan->identity_digest)) + /* if it's registered get it out of the digest map */ + channel_remove_from_digest_map(chan); + + memset(chan->identity_digest, 0, + sizeof(chan->identity_digest)); + tor_free(chan->nickname); +} + +/** + * Set the remote end metadata (identity_digest/nickname) of a channel + * + * This function sets new remote end info on a channel; this is intended + * for use by the lower layer. + */ + +void +channel_set_remote_end(channel_t *chan, + const char *identity_digest, + const char *nickname) +{ + int was_in_digest_map, should_be_in_digest_map, state_not_in_map; + + tor_assert(chan); + + log_debug(LD_CHANNEL, + "Setting remote endpoint identity on channel %p with " + "global ID " U64_FORMAT " to nickname %s, digest %s", + chan, U64_PRINTF_ARG(chan->global_identifier), + nickname ? nickname : "(null)", + identity_digest ? + hex_str(identity_digest, DIGEST_LEN) : "(null)"); + + state_not_in_map = + (chan->state == CHANNEL_STATE_CLOSING || + chan->state == CHANNEL_STATE_CLOSED || + chan->state == CHANNEL_STATE_ERROR); + was_in_digest_map = + !state_not_in_map && + chan->registered && + !tor_digest_is_zero(chan->identity_digest); + should_be_in_digest_map = + !state_not_in_map && + chan->registered && + (identity_digest && + !tor_digest_is_zero(identity_digest)); + + if (was_in_digest_map) + /* We should always remove it; we'll add it back if we're writing + * in a new digest. + */ + channel_remove_from_digest_map(chan); + + if (identity_digest) { + memcpy(chan->identity_digest, + identity_digest, + sizeof(chan->identity_digest)); + + } else { + memset(chan->identity_digest, 0, + sizeof(chan->identity_digest)); + } + + tor_free(chan->nickname); + if (nickname) + chan->nickname = tor_strdup(nickname); + + /* Put it in the digest map if we should */ + if (should_be_in_digest_map) + channel_add_to_digest_map(chan); +} + +/** + * Duplicate a cell queue entry; this is a shallow copy intended for use + * in channel_write_cell_queue_entry(). + */ + +static cell_queue_entry_t * +cell_queue_entry_dup(cell_queue_entry_t *q) +{ + cell_queue_entry_t *rv = NULL; + + tor_assert(q); + + rv = tor_malloc(sizeof(*rv)); + memcpy(rv, q, sizeof(*rv)); + + return rv; +} + +/** + * Free a cell_queue_entry_t; the handed_off parameter indicates whether + * the contents were passed to the lower layer (it is responsible for + * them) or not (we should free). + */ + +static void +cell_queue_entry_free(cell_queue_entry_t *q, int handed_off) +{ + if (!q) return; + + if (!handed_off) { + /* + * If we handed it off, the recipient becomes responsible (or + * with packed cells the channel_t subclass calls packed_cell + * free after writing out its contents; see, e.g., + * channel_tls_write_packed_cell_method(). Otherwise, we have + * to take care of it here if possible. + */ + switch (q->type) { + case CELL_QUEUE_FIXED: + if (q->u.fixed.cell) { + /* + * There doesn't seem to be a cell_free() function anywhere in the + * pre-channel code; just use tor_free() + */ + tor_free(q->u.fixed.cell); + } + break; + case CELL_QUEUE_PACKED: + if (q->u.packed.packed_cell) { + packed_cell_free(q->u.packed.packed_cell); + } + break; + case CELL_QUEUE_VAR: + if (q->u.var.var_cell) { + /* + * This one's in connection_or.c; it'd be nice to figure out the + * whole flow of cells from one end to the other and factor the + * cell memory management functions like this out of the specific + * TLS lower layer. + */ + var_cell_free(q->u.var.var_cell); + } + break; + default: + /* + * Nothing we can do if we don't know the type; this will + * have been warned about elsewhere. + */ + break; + } + } + tor_free(q); +} + +/** + * Check whether a cell queue entry is padding; this is a helper function + * for channel_write_cell_queue_entry() + */ + +static int +cell_queue_entry_is_padding(cell_queue_entry_t *q) +{ + tor_assert(q); + + if (q->type == CELL_QUEUE_FIXED) { + if (q->u.fixed.cell) { + if (q->u.fixed.cell->command == CELL_PADDING || + q->u.fixed.cell->command == CELL_VPADDING) { + return 1; + } + } + } else if (q->type == CELL_QUEUE_VAR) { + if (q->u.var.var_cell) { + if (q->u.var.var_cell->command == CELL_PADDING || + q->u.var.var_cell->command == CELL_VPADDING) { + return 1; + } + } + } + + return 0; +} + +/** + * Allocate a new cell queue entry for a fixed-size cell + */ + +static cell_queue_entry_t * +cell_queue_entry_new_fixed(cell_t *cell) +{ + cell_queue_entry_t *q = NULL; + + tor_assert(cell); + + q = tor_malloc(sizeof(*q)); + q->type = CELL_QUEUE_FIXED; + q->u.fixed.cell = cell; + + return q; +} + +/** + * Allocate a new cell queue entry for a variable-size cell + */ + +static cell_queue_entry_t * +cell_queue_entry_new_var(var_cell_t *var_cell) +{ + cell_queue_entry_t *q = NULL; + + tor_assert(var_cell); + + q = tor_malloc(sizeof(*q)); + q->type = CELL_QUEUE_VAR; + q->u.var.var_cell = var_cell; + + return q; +} + +/** + * Write to a channel based on a cell_queue_entry_t + * + * Given a cell_queue_entry_t filled out by the caller, try to send the cell + * and queue it if we can't. + */ + +static void +channel_write_cell_queue_entry(channel_t *chan, cell_queue_entry_t *q) +{ + int result = 0, sent = 0; + cell_queue_entry_t *tmp = NULL; + + tor_assert(chan); + tor_assert(q); + + /* Assert that the state makes sense for a cell write */ + tor_assert(chan->state == CHANNEL_STATE_OPENING || + chan->state == CHANNEL_STATE_OPEN || + chan->state == CHANNEL_STATE_MAINT); + + /* Increment the timestamp unless it's padding */ + if (!cell_queue_entry_is_padding(q)) { + chan->timestamp_last_added_nonpadding = approx_time(); + } + + { + circid_t circ_id; + if (is_destroy_cell(chan, q, &circ_id)) { + channel_note_destroy_not_pending(chan, circ_id); + } + } + + /* Can we send it right out? If so, try */ + if (TOR_SIMPLEQ_EMPTY(&chan->outgoing_queue) && + chan->state == CHANNEL_STATE_OPEN) { + /* Pick the right write function for this cell type and save the result */ + switch (q->type) { + case CELL_QUEUE_FIXED: + tor_assert(chan->write_cell); + tor_assert(q->u.fixed.cell); + result = chan->write_cell(chan, q->u.fixed.cell); + break; + case CELL_QUEUE_PACKED: + tor_assert(chan->write_packed_cell); + tor_assert(q->u.packed.packed_cell); + result = chan->write_packed_cell(chan, q->u.packed.packed_cell); + break; + case CELL_QUEUE_VAR: + tor_assert(chan->write_var_cell); + tor_assert(q->u.var.var_cell); + result = chan->write_var_cell(chan, q->u.var.var_cell); + break; + default: + tor_assert(1); + } + + /* Check if we got it out */ + if (result > 0) { + sent = 1; + /* Timestamp for transmission */ + channel_timestamp_xmit(chan); + /* If we're here the queue is empty, so it's drained too */ + channel_timestamp_drained(chan); + /* Update the counter */ + ++(chan->n_cells_xmitted); + } + } + + if (!sent) { + /* Not sent, queue it */ + /* + * We have to copy the queue entry passed in, since the caller probably + * used the stack. + */ + tmp = cell_queue_entry_dup(q); + TOR_SIMPLEQ_INSERT_TAIL(&chan->outgoing_queue, tmp, next); + /* Try to process the queue? */ + if (chan->state == CHANNEL_STATE_OPEN) channel_flush_cells(chan); + } +} + +/** + * Write a cell to a channel + * + * Write a fixed-length cell to a channel using the write_cell() method. + * This is equivalent to the pre-channels connection_or_write_cell_to_buf(); + * it is called by the transport-independent code to deliver a cell to a + * channel for transmission. + */ + +void +channel_write_cell(channel_t *chan, cell_t *cell) +{ + cell_queue_entry_t q; + + tor_assert(chan); + tor_assert(cell); + + if (chan->state == CHANNEL_STATE_CLOSING) { + log_debug(LD_CHANNEL, "Discarding cell_t %p on closing channel %p with " + "global ID "U64_FORMAT, cell, chan, + U64_PRINTF_ARG(chan->global_identifier)); + tor_free(cell); + return; + } + + log_debug(LD_CHANNEL, + "Writing cell_t %p to channel %p with global ID " + U64_FORMAT, + cell, chan, U64_PRINTF_ARG(chan->global_identifier)); + + q.type = CELL_QUEUE_FIXED; + q.u.fixed.cell = cell; + channel_write_cell_queue_entry(chan, &q); +} + +/** + * Write a packed cell to a channel + * + * Write a packed cell to a channel using the write_cell() method. This is + * called by the transport-independent code to deliver a packed cell to a + * channel for transmission. + */ + +void +channel_write_packed_cell(channel_t *chan, packed_cell_t *packed_cell) +{ + cell_queue_entry_t q; + + tor_assert(chan); + tor_assert(packed_cell); + + if (chan->state == CHANNEL_STATE_CLOSING) { + log_debug(LD_CHANNEL, "Discarding packed_cell_t %p on closing channel %p " + "with global ID "U64_FORMAT, packed_cell, chan, + U64_PRINTF_ARG(chan->global_identifier)); + packed_cell_free(packed_cell); + return; + } + + log_debug(LD_CHANNEL, + "Writing packed_cell_t %p to channel %p with global ID " + U64_FORMAT, + packed_cell, chan, + U64_PRINTF_ARG(chan->global_identifier)); + + q.type = CELL_QUEUE_PACKED; + q.u.packed.packed_cell = packed_cell; + channel_write_cell_queue_entry(chan, &q); +} + +/** + * Write a variable-length cell to a channel + * + * Write a variable-length cell to a channel using the write_cell() method. + * This is equivalent to the pre-channels + * connection_or_write_var_cell_to_buf(); it's called by the transport- + * independent code to deliver a var_cell to a channel for transmission. + */ + +void +channel_write_var_cell(channel_t *chan, var_cell_t *var_cell) +{ + cell_queue_entry_t q; + + tor_assert(chan); + tor_assert(var_cell); + + if (chan->state == CHANNEL_STATE_CLOSING) { + log_debug(LD_CHANNEL, "Discarding var_cell_t %p on closing channel %p " + "with global ID "U64_FORMAT, var_cell, chan, + U64_PRINTF_ARG(chan->global_identifier)); + var_cell_free(var_cell); + return; + } + + log_debug(LD_CHANNEL, + "Writing var_cell_t %p to channel %p with global ID " + U64_FORMAT, + var_cell, chan, + U64_PRINTF_ARG(chan->global_identifier)); + + q.type = CELL_QUEUE_VAR; + q.u.var.var_cell = var_cell; + channel_write_cell_queue_entry(chan, &q); +} + +/** + * Change channel state + * + * This internal and subclass use only function is used to change channel + * state, performing all transition validity checks and whatever actions + * are appropriate to the state transition in question. + */ + +void +channel_change_state(channel_t *chan, channel_state_t to_state) +{ + channel_state_t from_state; + unsigned char was_active, is_active; + unsigned char was_in_id_map, is_in_id_map; + + tor_assert(chan); + from_state = chan->state; + + tor_assert(channel_state_is_valid(from_state)); + tor_assert(channel_state_is_valid(to_state)); + tor_assert(channel_state_can_transition(chan->state, to_state)); + + /* Check for no-op transitions */ + if (from_state == to_state) { + log_debug(LD_CHANNEL, + "Got no-op transition from \"%s\" to itself on channel %p" + "(global ID " U64_FORMAT ")", + channel_state_to_string(to_state), + chan, U64_PRINTF_ARG(chan->global_identifier)); + return; + } + + /* If we're going to a closing or closed state, we must have a reason set */ + if (to_state == CHANNEL_STATE_CLOSING || + to_state == CHANNEL_STATE_CLOSED || + to_state == CHANNEL_STATE_ERROR) { + tor_assert(chan->reason_for_closing != CHANNEL_NOT_CLOSING); + } + + /* + * We need to maintain the queues here for some transitions: + * when we enter CHANNEL_STATE_OPEN (especially from CHANNEL_STATE_MAINT) + * we may have a backlog of cells to transmit, so drain the queues in + * that case, and when going to CHANNEL_STATE_CLOSED the subclass + * should have made sure to finish sending things (or gone to + * CHANNEL_STATE_ERROR if not possible), so we assert for that here. + */ + + log_debug(LD_CHANNEL, + "Changing state of channel %p (global ID " U64_FORMAT + ") from \"%s\" to \"%s\"", + chan, + U64_PRINTF_ARG(chan->global_identifier), + channel_state_to_string(chan->state), + channel_state_to_string(to_state)); + + chan->state = to_state; + + /* Need to add to the right lists if the channel is registered */ + if (chan->registered) { + was_active = !(from_state == CHANNEL_STATE_CLOSED || + from_state == CHANNEL_STATE_ERROR); + is_active = !(to_state == CHANNEL_STATE_CLOSED || + to_state == CHANNEL_STATE_ERROR); + + /* Need to take off active list and put on finished list? */ + if (was_active && !is_active) { + if (active_channels) smartlist_remove(active_channels, chan); + if (!finished_channels) finished_channels = smartlist_new(); + smartlist_add(finished_channels, chan); + } + /* Need to put on active list? */ + else if (!was_active && is_active) { + if (finished_channels) smartlist_remove(finished_channels, chan); + if (!active_channels) active_channels = smartlist_new(); + smartlist_add(active_channels, chan); + } + + if (!tor_digest_is_zero(chan->identity_digest)) { + /* Now we need to handle the identity map */ + was_in_id_map = !(from_state == CHANNEL_STATE_CLOSING || + from_state == CHANNEL_STATE_CLOSED || + from_state == CHANNEL_STATE_ERROR); + is_in_id_map = !(to_state == CHANNEL_STATE_CLOSING || + to_state == CHANNEL_STATE_CLOSED || + to_state == CHANNEL_STATE_ERROR); + + if (!was_in_id_map && is_in_id_map) channel_add_to_digest_map(chan); + else if (was_in_id_map && !is_in_id_map) + channel_remove_from_digest_map(chan); + } + } + + /* Tell circuits if we opened and stuff */ + if (to_state == CHANNEL_STATE_OPEN) { + channel_do_open_actions(chan); + chan->has_been_open = 1; + + /* Check for queued cells to process */ + if (! TOR_SIMPLEQ_EMPTY(&chan->incoming_queue)) + channel_process_cells(chan); + if (! TOR_SIMPLEQ_EMPTY(&chan->outgoing_queue)) + channel_flush_cells(chan); + } else if (to_state == CHANNEL_STATE_CLOSED || + to_state == CHANNEL_STATE_ERROR) { + /* Assert that all queues are empty */ + tor_assert(TOR_SIMPLEQ_EMPTY(&chan->incoming_queue)); + tor_assert(TOR_SIMPLEQ_EMPTY(&chan->outgoing_queue)); + } +} + +/** + * Change channel listener state + * + * This internal and subclass use only function is used to change channel + * listener state, performing all transition validity checks and whatever + * actions are appropriate to the state transition in question. + */ + +void +channel_listener_change_state(channel_listener_t *chan_l, + channel_listener_state_t to_state) +{ + channel_listener_state_t from_state; + unsigned char was_active, is_active; + + tor_assert(chan_l); + from_state = chan_l->state; + + tor_assert(channel_listener_state_is_valid(from_state)); + tor_assert(channel_listener_state_is_valid(to_state)); + tor_assert(channel_listener_state_can_transition(chan_l->state, to_state)); + + /* Check for no-op transitions */ + if (from_state == to_state) { + log_debug(LD_CHANNEL, + "Got no-op transition from \"%s\" to itself on channel " + "listener %p (global ID " U64_FORMAT ")", + channel_listener_state_to_string(to_state), + chan_l, U64_PRINTF_ARG(chan_l->global_identifier)); + return; + } + + /* If we're going to a closing or closed state, we must have a reason set */ + if (to_state == CHANNEL_LISTENER_STATE_CLOSING || + to_state == CHANNEL_LISTENER_STATE_CLOSED || + to_state == CHANNEL_LISTENER_STATE_ERROR) { + tor_assert(chan_l->reason_for_closing != CHANNEL_LISTENER_NOT_CLOSING); + } + + /* + * We need to maintain the queues here for some transitions: + * when we enter CHANNEL_STATE_OPEN (especially from CHANNEL_STATE_MAINT) + * we may have a backlog of cells to transmit, so drain the queues in + * that case, and when going to CHANNEL_STATE_CLOSED the subclass + * should have made sure to finish sending things (or gone to + * CHANNEL_STATE_ERROR if not possible), so we assert for that here. + */ + + log_debug(LD_CHANNEL, + "Changing state of channel listener %p (global ID " U64_FORMAT + "from \"%s\" to \"%s\"", + chan_l, U64_PRINTF_ARG(chan_l->global_identifier), + channel_listener_state_to_string(chan_l->state), + channel_listener_state_to_string(to_state)); + + chan_l->state = to_state; + + /* Need to add to the right lists if the channel listener is registered */ + if (chan_l->registered) { + was_active = !(from_state == CHANNEL_LISTENER_STATE_CLOSED || + from_state == CHANNEL_LISTENER_STATE_ERROR); + is_active = !(to_state == CHANNEL_LISTENER_STATE_CLOSED || + to_state == CHANNEL_LISTENER_STATE_ERROR); + + /* Need to take off active list and put on finished list? */ + if (was_active && !is_active) { + if (active_listeners) smartlist_remove(active_listeners, chan_l); + if (!finished_listeners) finished_listeners = smartlist_new(); + smartlist_add(finished_listeners, chan_l); + } + /* Need to put on active list? */ + else if (!was_active && is_active) { + if (finished_listeners) smartlist_remove(finished_listeners, chan_l); + if (!active_listeners) active_listeners = smartlist_new(); + smartlist_add(active_listeners, chan_l); + } + } + + if (to_state == CHANNEL_LISTENER_STATE_CLOSED || + to_state == CHANNEL_LISTENER_STATE_ERROR) { + /* Assert that the queue is empty */ + tor_assert(!(chan_l->incoming_list) || + smartlist_len(chan_l->incoming_list) == 0); + } +} + +/** + * Try to flush cells to the lower layer + * + * this is called by the lower layer to indicate that it wants more cells; + * it will try to write up to num_cells cells from the channel's cell queue or + * from circuits active on that channel, or as many as it has available if + * num_cells == -1. + */ + +#define MAX_CELLS_TO_GET_FROM_CIRCUITS_FOR_UNLIMITED 256 + +ssize_t +channel_flush_some_cells(channel_t *chan, ssize_t num_cells) +{ + unsigned int unlimited = 0; + ssize_t flushed = 0; + int num_cells_from_circs, clamped_num_cells; + + tor_assert(chan); + + if (num_cells < 0) unlimited = 1; + if (!unlimited && num_cells <= flushed) goto done; + + /* If we aren't in CHANNEL_STATE_OPEN, nothing goes through */ + if (chan->state == CHANNEL_STATE_OPEN) { + /* Try to flush as much as we can that's already queued */ + flushed += channel_flush_some_cells_from_outgoing_queue(chan, + (unlimited ? -1 : num_cells - flushed)); + if (!unlimited && num_cells <= flushed) goto done; + + if (circuitmux_num_cells(chan->cmux) > 0) { + /* Calculate number of cells, including clamp */ + if (unlimited) { + clamped_num_cells = MAX_CELLS_TO_GET_FROM_CIRCUITS_FOR_UNLIMITED; + } else { + if (num_cells - flushed > + MAX_CELLS_TO_GET_FROM_CIRCUITS_FOR_UNLIMITED) { + clamped_num_cells = MAX_CELLS_TO_GET_FROM_CIRCUITS_FOR_UNLIMITED; + } else { + clamped_num_cells = (int)(num_cells - flushed); + } + } + /* Try to get more cells from any active circuits */ + num_cells_from_circs = channel_flush_from_first_active_circuit( + chan, clamped_num_cells); + + /* If it claims we got some, process the queue again */ + if (num_cells_from_circs > 0) { + flushed += channel_flush_some_cells_from_outgoing_queue(chan, + (unlimited ? -1 : num_cells - flushed)); + } + } + } + + done: + return flushed; +} + +/** + * Flush cells from just the channel's outgoing cell queue + * + * This gets called from channel_flush_some_cells() above to flush cells + * just from the queue without trying for active_circuits. + */ + +static ssize_t +channel_flush_some_cells_from_outgoing_queue(channel_t *chan, + ssize_t num_cells) +{ + unsigned int unlimited = 0; + ssize_t flushed = 0; + cell_queue_entry_t *q = NULL; + + tor_assert(chan); + tor_assert(chan->write_cell); + tor_assert(chan->write_packed_cell); + tor_assert(chan->write_var_cell); + + if (num_cells < 0) unlimited = 1; + if (!unlimited && num_cells <= flushed) return 0; + + /* If we aren't in CHANNEL_STATE_OPEN, nothing goes through */ + if (chan->state == CHANNEL_STATE_OPEN) { + while ((unlimited || num_cells > flushed) && + NULL != (q = TOR_SIMPLEQ_FIRST(&chan->outgoing_queue))) { + + if (1) { + /* + * Okay, we have a good queue entry, try to give it to the lower + * layer. + */ + switch (q->type) { + case CELL_QUEUE_FIXED: + if (q->u.fixed.cell) { + if (chan->write_cell(chan, + q->u.fixed.cell)) { + ++flushed; + channel_timestamp_xmit(chan); + ++(chan->n_cells_xmitted); + cell_queue_entry_free(q, 1); + q = NULL; + } + /* Else couldn't write it; leave it on the queue */ + } else { + /* This shouldn't happen */ + log_info(LD_CHANNEL, + "Saw broken cell queue entry of type CELL_QUEUE_FIXED " + "with no cell on channel %p " + "(global ID " U64_FORMAT ").", + chan, U64_PRINTF_ARG(chan->global_identifier)); + /* Throw it away */ + cell_queue_entry_free(q, 0); + q = NULL; + } + break; + case CELL_QUEUE_PACKED: + if (q->u.packed.packed_cell) { + if (chan->write_packed_cell(chan, + q->u.packed.packed_cell)) { + ++flushed; + channel_timestamp_xmit(chan); + ++(chan->n_cells_xmitted); + cell_queue_entry_free(q, 1); + q = NULL; + } + /* Else couldn't write it; leave it on the queue */ + } else { + /* This shouldn't happen */ + log_info(LD_CHANNEL, + "Saw broken cell queue entry of type CELL_QUEUE_PACKED " + "with no cell on channel %p " + "(global ID " U64_FORMAT ").", + chan, U64_PRINTF_ARG(chan->global_identifier)); + /* Throw it away */ + cell_queue_entry_free(q, 0); + q = NULL; + } + break; + case CELL_QUEUE_VAR: + if (q->u.var.var_cell) { + if (chan->write_var_cell(chan, + q->u.var.var_cell)) { + ++flushed; + channel_timestamp_xmit(chan); + ++(chan->n_cells_xmitted); + cell_queue_entry_free(q, 1); + q = NULL; + } + /* Else couldn't write it; leave it on the queue */ + } else { + /* This shouldn't happen */ + log_info(LD_CHANNEL, + "Saw broken cell queue entry of type CELL_QUEUE_VAR " + "with no cell on channel %p " + "(global ID " U64_FORMAT ").", + chan, U64_PRINTF_ARG(chan->global_identifier)); + /* Throw it away */ + cell_queue_entry_free(q, 0); + q = NULL; + } + break; + default: + /* Unknown type, log and free it */ + log_info(LD_CHANNEL, + "Saw an unknown cell queue entry type %d on channel %p " + "(global ID " U64_FORMAT "; ignoring it." + " Someone should fix this.", + q->type, chan, U64_PRINTF_ARG(chan->global_identifier)); + cell_queue_entry_free(q, 0); + q = NULL; + } + + /* if q got NULLed out, we used it and should remove the queue entry */ + if (!q) TOR_SIMPLEQ_REMOVE_HEAD(&chan->outgoing_queue, next); + /* No cell removed from list, so we can't go on any further */ + else break; + } + } + } + + /* Did we drain the queue? */ + if (TOR_SIMPLEQ_EMPTY(&chan->outgoing_queue)) { + channel_timestamp_drained(chan); + } + + return flushed; +} + +/** + * Flush as many cells as we possibly can from the queue + * + * This tries to flush as many cells from the queue as the lower layer + * will take. It just calls channel_flush_some_cells_from_outgoing_queue() + * in unlimited mode. + */ + +void +channel_flush_cells(channel_t *chan) +{ + channel_flush_some_cells_from_outgoing_queue(chan, -1); +} + +/** + * Check if any cells are available + * + * This gets used from the lower layer to check if any more cells are + * available. + */ + +int +channel_more_to_flush(channel_t *chan) +{ + tor_assert(chan); + + /* Check if we have any queued */ + if (! TOR_SIMPLEQ_EMPTY(&chan->incoming_queue)) + return 1; + + /* Check if any circuits would like to queue some */ + if (circuitmux_num_cells(chan->cmux) > 0) return 1; + + /* Else no */ + return 0; +} + +/** + * Notify the channel we're done flushing the output in the lower layer + * + * Connection.c will call this when we've flushed the output; there's some + * dirreq-related maintenance to do. + */ + +void +channel_notify_flushed(channel_t *chan) +{ + tor_assert(chan); + + if (chan->dirreq_id != 0) + geoip_change_dirreq_state(chan->dirreq_id, + DIRREQ_TUNNELED, + DIRREQ_CHANNEL_BUFFER_FLUSHED); +} + +/** + * Process the queue of incoming channels on a listener + * + * Use a listener's registered callback to process as many entries in the + * queue of incoming channels as possible. + */ + +void +channel_listener_process_incoming(channel_listener_t *listener) +{ + tor_assert(listener); + + /* + * CHANNEL_LISTENER_STATE_CLOSING permitted because we drain the queue + * while closing a listener. + */ + tor_assert(listener->state == CHANNEL_LISTENER_STATE_LISTENING || + listener->state == CHANNEL_LISTENER_STATE_CLOSING); + tor_assert(listener->listener); + + log_debug(LD_CHANNEL, + "Processing queue of incoming connections for channel " + "listener %p (global ID " U64_FORMAT ")", + listener, U64_PRINTF_ARG(listener->global_identifier)); + + if (!(listener->incoming_list)) return; + + SMARTLIST_FOREACH_BEGIN(listener->incoming_list, + channel_t *, chan) { + tor_assert(chan); + + log_debug(LD_CHANNEL, + "Handling incoming channel %p (" U64_FORMAT ") " + "for listener %p (" U64_FORMAT ")", + chan, + U64_PRINTF_ARG(chan->global_identifier), + listener, + U64_PRINTF_ARG(listener->global_identifier)); + /* Make sure this is set correctly */ + channel_mark_incoming(chan); + listener->listener(listener, chan); + } SMARTLIST_FOREACH_END(chan); + + smartlist_free(listener->incoming_list); + listener->incoming_list = NULL; +} + +/** + * Take actions required when a channel becomes open + * + * Handle actions we should do when we know a channel is open; a lot of + * this comes from the old connection_or_set_state_open() of connection_or.c. + * + * Because of this mechanism, future channel_t subclasses should take care + * not to change a channel to from CHANNEL_STATE_OPENING to CHANNEL_STATE_OPEN + * until there is positive confirmation that the network is operational. + * In particular, anything UDP-based should not make this transition until a + * packet is received from the other side. + */ + +void +channel_do_open_actions(channel_t *chan) +{ + tor_addr_t remote_addr; + int started_here, not_using = 0; + time_t now = time(NULL); + + tor_assert(chan); + + started_here = channel_is_outgoing(chan); + + if (started_here) { + circuit_build_times_network_is_live(get_circuit_build_times_mutable()); + rep_hist_note_connect_succeeded(chan->identity_digest, now); + if (entry_guard_register_connect_status( + chan->identity_digest, 1, 0, now) < 0) { + /* Close any circuits pending on this channel. We leave it in state + * 'open' though, because it didn't actually *fail* -- we just + * chose not to use it. */ + log_debug(LD_OR, + "New entry guard was reachable, but closing this " + "connection so we can retry the earlier entry guards."); + circuit_n_chan_done(chan, 0); + not_using = 1; + } + router_set_status(chan->identity_digest, 1); + } else { + /* only report it to the geoip module if it's not a known router */ + if (!router_get_by_id_digest(chan->identity_digest)) { + if (channel_get_addr_if_possible(chan, &remote_addr)) { + char *transport_name = NULL; + if (chan->get_transport_name(chan, &transport_name) < 0) + transport_name = NULL; + + geoip_note_client_seen(GEOIP_CLIENT_CONNECT, + &remote_addr, transport_name, + now); + tor_free(transport_name); + } + /* Otherwise the underlying transport can't tell us this, so skip it */ + } + } + + if (!not_using) circuit_n_chan_done(chan, 1); +} + +/** + * Queue an incoming channel on a listener + * + * Internal and subclass use only function to queue an incoming channel from + * a listener. A subclass of channel_listener_t should call this when a new + * incoming channel is created. + */ + +void +channel_listener_queue_incoming(channel_listener_t *listener, + channel_t *incoming) +{ + int need_to_queue = 0; + + tor_assert(listener); + tor_assert(listener->state == CHANNEL_LISTENER_STATE_LISTENING); + tor_assert(incoming); + + log_debug(LD_CHANNEL, + "Queueing incoming channel %p (global ID " U64_FORMAT ") on " + "channel listener %p (global ID " U64_FORMAT ")", + incoming, U64_PRINTF_ARG(incoming->global_identifier), + listener, U64_PRINTF_ARG(listener->global_identifier)); + + /* Do we need to queue it, or can we just call the listener right away? */ + if (!(listener->listener)) need_to_queue = 1; + if (listener->incoming_list && + (smartlist_len(listener->incoming_list) > 0)) + need_to_queue = 1; + + /* If we need to queue and have no queue, create one */ + if (need_to_queue && !(listener->incoming_list)) { + listener->incoming_list = smartlist_new(); + } + + /* Bump the counter and timestamp it */ + channel_listener_timestamp_active(listener); + channel_listener_timestamp_accepted(listener); + ++(listener->n_accepted); + + /* If we don't need to queue, process it right away */ + if (!need_to_queue) { + tor_assert(listener->listener); + listener->listener(listener, incoming); + } + /* + * Otherwise, we need to queue; queue and then process the queue if + * we can. + */ + else { + tor_assert(listener->incoming_list); + smartlist_add(listener->incoming_list, incoming); + if (listener->listener) channel_listener_process_incoming(listener); + } +} + +/** + * Process queued incoming cells + * + * Process as many queued cells as we can from the incoming + * cell queue. + */ + +void +channel_process_cells(channel_t *chan) +{ + cell_queue_entry_t *q; + tor_assert(chan); + tor_assert(chan->state == CHANNEL_STATE_CLOSING || + chan->state == CHANNEL_STATE_MAINT || + chan->state == CHANNEL_STATE_OPEN); + + log_debug(LD_CHANNEL, + "Processing as many incoming cells as we can for channel %p", + chan); + + /* Nothing we can do if we have no registered cell handlers */ + if (!(chan->cell_handler || + chan->var_cell_handler)) return; + /* Nothing we can do if we have no cells */ + if (TOR_SIMPLEQ_EMPTY(&chan->incoming_queue)) return; + + /* + * Process cells until we're done or find one we have no current handler + * for. + */ + while (NULL != (q = TOR_SIMPLEQ_FIRST(&chan->incoming_queue))) { + tor_assert(q); + tor_assert(q->type == CELL_QUEUE_FIXED || + q->type == CELL_QUEUE_VAR); + + if (q->type == CELL_QUEUE_FIXED && + chan->cell_handler) { + /* Handle a fixed-length cell */ + TOR_SIMPLEQ_REMOVE_HEAD(&chan->incoming_queue, next); + tor_assert(q->u.fixed.cell); + log_debug(LD_CHANNEL, + "Processing incoming cell_t %p for channel %p (global ID " + U64_FORMAT ")", + q->u.fixed.cell, chan, + U64_PRINTF_ARG(chan->global_identifier)); + chan->cell_handler(chan, q->u.fixed.cell); + tor_free(q); + } else if (q->type == CELL_QUEUE_VAR && + chan->var_cell_handler) { + /* Handle a variable-length cell */ + TOR_SIMPLEQ_REMOVE_HEAD(&chan->incoming_queue, next); + tor_assert(q->u.var.var_cell); + log_debug(LD_CHANNEL, + "Processing incoming var_cell_t %p for channel %p (global ID " + U64_FORMAT ")", + q->u.var.var_cell, chan, + U64_PRINTF_ARG(chan->global_identifier)); + chan->var_cell_handler(chan, q->u.var.var_cell); + tor_free(q); + } else { + /* Can't handle this one */ + break; + } + } +} + +/** + * Queue incoming cell + * + * This should be called by a channel_t subclass to queue an incoming fixed- + * length cell for processing, and process it if possible. + */ + +void +channel_queue_cell(channel_t *chan, cell_t *cell) +{ + int need_to_queue = 0; + cell_queue_entry_t *q; + + tor_assert(chan); + tor_assert(cell); + tor_assert(chan->state == CHANNEL_STATE_OPEN); + + /* Do we need to queue it, or can we just call the handler right away? */ + if (!(chan->cell_handler)) need_to_queue = 1; + if (! TOR_SIMPLEQ_EMPTY(&chan->incoming_queue)) + need_to_queue = 1; + + /* Timestamp for receiving */ + channel_timestamp_recv(chan); + + /* Update the counter */ + ++(chan->n_cells_recved); + + /* If we don't need to queue we can just call cell_handler */ + if (!need_to_queue) { + tor_assert(chan->cell_handler); + log_debug(LD_CHANNEL, + "Directly handling incoming cell_t %p for channel %p " + "(global ID " U64_FORMAT ")", + cell, chan, + U64_PRINTF_ARG(chan->global_identifier)); + chan->cell_handler(chan, cell); + } else { + /* Otherwise queue it and then process the queue if possible. */ + q = cell_queue_entry_new_fixed(cell); + log_debug(LD_CHANNEL, + "Queueing incoming cell_t %p for channel %p " + "(global ID " U64_FORMAT ")", + cell, chan, + U64_PRINTF_ARG(chan->global_identifier)); + TOR_SIMPLEQ_INSERT_TAIL(&chan->incoming_queue, q, next); + if (chan->cell_handler || + chan->var_cell_handler) { + channel_process_cells(chan); + } + } +} + +/** + * Queue incoming variable-length cell + * + * This should be called by a channel_t subclass to queue an incoming + * variable-length cell for processing, and process it if possible. + */ + +void +channel_queue_var_cell(channel_t *chan, var_cell_t *var_cell) +{ + int need_to_queue = 0; + cell_queue_entry_t *q; + + tor_assert(chan); + tor_assert(var_cell); + tor_assert(chan->state == CHANNEL_STATE_OPEN); + + /* Do we need to queue it, or can we just call the handler right away? */ + if (!(chan->var_cell_handler)) need_to_queue = 1; + if (! TOR_SIMPLEQ_EMPTY(&chan->incoming_queue)) + need_to_queue = 1; + + /* Timestamp for receiving */ + channel_timestamp_recv(chan); + + /* Update the counter */ + ++(chan->n_cells_recved); + + /* If we don't need to queue we can just call cell_handler */ + if (!need_to_queue) { + tor_assert(chan->var_cell_handler); + log_debug(LD_CHANNEL, + "Directly handling incoming var_cell_t %p for channel %p " + "(global ID " U64_FORMAT ")", + var_cell, chan, + U64_PRINTF_ARG(chan->global_identifier)); + chan->var_cell_handler(chan, var_cell); + } else { + /* Otherwise queue it and then process the queue if possible. */ + q = cell_queue_entry_new_var(var_cell); + log_debug(LD_CHANNEL, + "Queueing incoming var_cell_t %p for channel %p " + "(global ID " U64_FORMAT ")", + var_cell, chan, + U64_PRINTF_ARG(chan->global_identifier)); + TOR_SIMPLEQ_INSERT_TAIL(&chan->incoming_queue, q, next); + if (chan->cell_handler || + chan->var_cell_handler) { + channel_process_cells(chan); + } + } +} + +/** If packed_cell on chan is a destroy cell, then set + * *circid_out to its circuit ID, and return true. Otherwise, return + * false. */ +/* XXXX Move this function. */ +int +packed_cell_is_destroy(channel_t *chan, + const packed_cell_t *packed_cell, + circid_t *circid_out) +{ + if (chan->wide_circ_ids) { + if (packed_cell->body[4] == CELL_DESTROY) { + *circid_out = ntohl(get_uint32(packed_cell->body)); + return 1; + } + } else { + if (packed_cell->body[2] == CELL_DESTROY) { + *circid_out = ntohs(get_uint16(packed_cell->body)); + return 1; + } + } + return 0; +} + +/** DOCDOC */ +static int +is_destroy_cell(channel_t *chan, + const cell_queue_entry_t *q, circid_t *circid_out) +{ + *circid_out = 0; + switch (q->type) { + case CELL_QUEUE_FIXED: + if (q->u.fixed.cell->command == CELL_DESTROY) { + *circid_out = q->u.fixed.cell->circ_id; + return 1; + } + break; + case CELL_QUEUE_VAR: + if (q->u.var.var_cell->command == CELL_DESTROY) { + *circid_out = q->u.var.var_cell->circ_id; + return 1; + } + break; + case CELL_QUEUE_PACKED: + return packed_cell_is_destroy(chan, q->u.packed.packed_cell, circid_out); + } + return 0; +} + +/** + * Send destroy cell on a channel + * + * Write a destroy cell with circ ID circ_id and reason reason + * onto channel chan. Don't perform range-checking on reason: + * we may want to propagate reasons from other cells. + */ + +int +channel_send_destroy(circid_t circ_id, channel_t *chan, int reason) +{ + tor_assert(chan); + + /* Check to make sure we can send on this channel first */ + if (!(chan->state == CHANNEL_STATE_CLOSING || + chan->state == CHANNEL_STATE_CLOSED || + chan->state == CHANNEL_STATE_ERROR) && + chan->cmux) { + channel_note_destroy_pending(chan, circ_id); + circuitmux_append_destroy_cell(chan, chan->cmux, circ_id, reason); + log_debug(LD_OR, + "Sending destroy (circID %u) on channel %p " + "(global ID " U64_FORMAT ")", + (unsigned)circ_id, chan, + U64_PRINTF_ARG(chan->global_identifier)); + } else { + log_warn(LD_BUG, + "Someone called channel_send_destroy() for circID %u " + "on a channel " U64_FORMAT " at %p in state %s (%d)", + (unsigned)circ_id, U64_PRINTF_ARG(chan->global_identifier), + chan, channel_state_to_string(chan->state), + chan->state); + } + + return 0; +} + +/** + * Dump channel statistics to the log + * + * This is called from dumpstats() in onion_main.c and spams the log with + * statistics on channels. + */ + +void +channel_dumpstats(int severity) +{ + if (all_channels && smartlist_len(all_channels) > 0) { + tor_log(severity, LD_GENERAL, + "Dumping statistics about %d channels:", + smartlist_len(all_channels)); + tor_log(severity, LD_GENERAL, + "%d are active, and %d are done and waiting for cleanup", + (active_channels != NULL) ? + smartlist_len(active_channels) : 0, + (finished_channels != NULL) ? + smartlist_len(finished_channels) : 0); + + SMARTLIST_FOREACH(all_channels, channel_t *, chan, + channel_dump_statistics(chan, severity)); + + tor_log(severity, LD_GENERAL, + "Done spamming about channels now"); + } else { + tor_log(severity, LD_GENERAL, + "No channels to dump"); + } +} + +/** + * Dump channel listener statistics to the log + * + * This is called from dumpstats() in onion_main.c and spams the log with + * statistics on channel listeners. + */ + +void +channel_listener_dumpstats(int severity) +{ + if (all_listeners && smartlist_len(all_listeners) > 0) { + tor_log(severity, LD_GENERAL, + "Dumping statistics about %d channel listeners:", + smartlist_len(all_listeners)); + tor_log(severity, LD_GENERAL, + "%d are active and %d are done and waiting for cleanup", + (active_listeners != NULL) ? + smartlist_len(active_listeners) : 0, + (finished_listeners != NULL) ? + smartlist_len(finished_listeners) : 0); + + SMARTLIST_FOREACH(all_listeners, channel_listener_t *, chan_l, + channel_listener_dump_statistics(chan_l, severity)); + + tor_log(severity, LD_GENERAL, + "Done spamming about channel listeners now"); + } else { + tor_log(severity, LD_GENERAL, + "No channel listeners to dump"); + } +} + +/** + * Set the cmux policy on all active channels + */ + +void +channel_set_cmux_policy_everywhere(circuitmux_policy_t *pol) +{ + if (!active_channels) return; + + SMARTLIST_FOREACH_BEGIN(active_channels, channel_t *, curr) { + if (curr->cmux) { + circuitmux_set_policy(curr->cmux, pol); + } + } SMARTLIST_FOREACH_END(curr); +} + +/** + * Clean up channels + * + * This gets called periodically from run_scheduled_events() in onion_main.c; + * it cleans up after closed channels. + */ + +void +channel_run_cleanup(void) +{ + channel_t *tmp = NULL; + + /* Check if we need to do anything */ + if (!finished_channels || smartlist_len(finished_channels) == 0) return; + + /* Iterate through finished_channels and get rid of them */ + SMARTLIST_FOREACH_BEGIN(finished_channels, channel_t *, curr) { + tmp = curr; + /* Remove it from the list */ + SMARTLIST_DEL_CURRENT(finished_channels, curr); + /* Also unregister it */ + channel_unregister(tmp); + /* ... and free it */ + channel_free(tmp); + } SMARTLIST_FOREACH_END(curr); +} + +/** + * Clean up channel listeners + * + * This gets called periodically from run_scheduled_events() in onion_main.c; + * it cleans up after closed channel listeners. + */ + +void +channel_listener_run_cleanup(void) +{ + channel_listener_t *tmp = NULL; + + /* Check if we need to do anything */ + if (!finished_listeners || smartlist_len(finished_listeners) == 0) return; + + /* Iterate through finished_channels and get rid of them */ + SMARTLIST_FOREACH_BEGIN(finished_listeners, channel_listener_t *, curr) { + tmp = curr; + /* Remove it from the list */ + SMARTLIST_DEL_CURRENT(finished_listeners, curr); + /* Also unregister it */ + channel_listener_unregister(tmp); + /* ... and free it */ + channel_listener_free(tmp); + } SMARTLIST_FOREACH_END(curr); +} + +/** + * Free a list of channels for channel_free_all() + */ + +static void +channel_free_list(smartlist_t *channels, int mark_for_close) +{ + if (!channels) return; + + SMARTLIST_FOREACH_BEGIN(channels, channel_t *, curr) { + /* Deregister and free it */ + tor_assert(curr); + log_debug(LD_CHANNEL, + "Cleaning up channel %p (global ID " U64_FORMAT ") " + "in state %s (%d)", + curr, U64_PRINTF_ARG(curr->global_identifier), + channel_state_to_string(curr->state), curr->state); + /* Detach circuits early so they can find the channel */ + if (curr->cmux) { + circuitmux_detach_all_circuits(curr->cmux); + } + channel_unregister(curr); + if (mark_for_close) { + if (!(curr->state == CHANNEL_STATE_CLOSING || + curr->state == CHANNEL_STATE_CLOSED || + curr->state == CHANNEL_STATE_ERROR)) { + channel_mark_for_close(curr); + } + channel_force_free(curr); + } else channel_free(curr); + } SMARTLIST_FOREACH_END(curr); +} + +/** + * Free a list of channel listeners for channel_free_all() + */ + +static void +channel_listener_free_list(smartlist_t *listeners, int mark_for_close) +{ + if (!listeners) return; + + SMARTLIST_FOREACH_BEGIN(listeners, channel_listener_t *, curr) { + /* Deregister and free it */ + tor_assert(curr); + log_debug(LD_CHANNEL, + "Cleaning up channel listener %p (global ID " U64_FORMAT ") " + "in state %s (%d)", + curr, U64_PRINTF_ARG(curr->global_identifier), + channel_listener_state_to_string(curr->state), curr->state); + channel_listener_unregister(curr); + if (mark_for_close) { + if (!(curr->state == CHANNEL_LISTENER_STATE_CLOSING || + curr->state == CHANNEL_LISTENER_STATE_CLOSED || + curr->state == CHANNEL_LISTENER_STATE_ERROR)) { + channel_listener_mark_for_close(curr); + } + channel_listener_force_free(curr); + } else channel_listener_free(curr); + } SMARTLIST_FOREACH_END(curr); +} + +/** + * Close all channels and free everything + * + * This gets called from tor_free_all() in onion_main.c to clean up on exit. + * It will close all registered channels and free associated storage, + * then free the all_channels, active_channels, listening_channels and + * finished_channels lists and also channel_identity_map. + */ + +void +channel_free_all(void) +{ + log_debug(LD_CHANNEL, + "Shutting down channels..."); + + /* First, let's go for finished channels */ + if (finished_channels) { + channel_free_list(finished_channels, 0); + smartlist_free(finished_channels); + finished_channels = NULL; + } + + /* Now the finished listeners */ + if (finished_listeners) { + channel_listener_free_list(finished_listeners, 0); + smartlist_free(finished_listeners); + finished_listeners = NULL; + } + + /* Now all active channels */ + if (active_channels) { + channel_free_list(active_channels, 1); + smartlist_free(active_channels); + active_channels = NULL; + } + + /* Now all active listeners */ + if (active_listeners) { + channel_listener_free_list(active_listeners, 1); + smartlist_free(active_listeners); + active_listeners = NULL; + } + + /* Now all channels, in case any are left over */ + if (all_channels) { + channel_free_list(all_channels, 1); + smartlist_free(all_channels); + all_channels = NULL; + } + + /* Now all listeners, in case any are left over */ + if (all_listeners) { + channel_listener_free_list(all_listeners, 1); + smartlist_free(all_listeners); + all_listeners = NULL; + } + + /* Now free channel_identity_map */ + log_debug(LD_CHANNEL, + "Freeing channel_identity_map"); + /* Geez, anything still left over just won't die ... let it leak then */ + HT_CLEAR(channel_idmap, &channel_identity_map); + + log_debug(LD_CHANNEL, + "Done cleaning up after channels"); +} + +/** + * Connect to a given addr/port/digest + * + * This sets up a new outgoing channel; in the future if multiple + * channel_t subclasses are available, this is where the selection policy + * should go. It may also be desirable to fold port into tor_addr_t + * or make a new type including a tor_addr_t and port, so we have a + * single abstract object encapsulating all the protocol details of + * how to contact an OR. + */ + +channel_t * +channel_connect(const tor_addr_t *addr, uint16_t port, + const char *id_digest) +{ + return channel_tls_connect(addr, port, id_digest); +} + +/** + * Decide which of two channels to prefer for extending a circuit + * + * This function is called while extending a circuit and returns true iff + * a is 'better' than b. The most important criterion here is that a + * canonical channel is always better than a non-canonical one, but the + * number of circuits and the age are used as tie-breakers. + * + * This is based on the former connection_or_is_better() of connection_or.c + */ + +int +channel_is_better(time_t now, channel_t *a, channel_t *b, + int forgive_new_connections) +{ + int a_grace, b_grace; + int a_is_canonical, b_is_canonical; + int a_has_circs, b_has_circs; + + /* + * Do not definitively deprecate a new channel with no circuits on it + * until this much time has passed. + */ +#define NEW_CHAN_GRACE_PERIOD (15*60) + + tor_assert(a); + tor_assert(b); + + /* Check if one is canonical and the other isn't first */ + a_is_canonical = channel_is_canonical(a); + b_is_canonical = channel_is_canonical(b); + + if (a_is_canonical && !b_is_canonical) return 1; + if (!a_is_canonical && b_is_canonical) return 0; + + /* + * Okay, if we're here they tied on canonicity. Next we check if + * they have any circuits, and if one does and the other doesn't, + * we prefer the one that does, unless we are forgiving and the + * one that has no circuits is in its grace period. + */ + + a_has_circs = (channel_num_circuits(a) > 0); + b_has_circs = (channel_num_circuits(b) > 0); + a_grace = (forgive_new_connections && + (now < channel_when_created(a) + NEW_CHAN_GRACE_PERIOD)); + b_grace = (forgive_new_connections && + (now < channel_when_created(b) + NEW_CHAN_GRACE_PERIOD)); + + if (a_has_circs && !b_has_circs && !b_grace) return 1; + if (!a_has_circs && b_has_circs && !a_grace) return 0; + + /* They tied on circuits too; just prefer whichever is newer */ + + if (channel_when_created(a) > channel_when_created(b)) return 1; + else return 0; +} + +/** + * Get a channel to extend a circuit + * + * Pick a suitable channel to extend a circuit to given the desired digest + * the address we believe is correct for that digest; this tries to see + * if we already have one for the requested endpoint, but if there is no good + * channel, set *msg_out to a message describing the channel's state + * and our next action, and set *launch_out to a boolean indicated whether + * the caller should try to launch a new channel with channel_connect(). + */ + +channel_t * +channel_get_for_extend(const char *digest, + const tor_addr_t *target_addr, + const char **msg_out, + int *launch_out) +{ + channel_t *chan, *best = NULL; + int n_inprogress_goodaddr = 0, n_old = 0; + int n_noncanonical = 0, n_possible = 0; + time_t now = approx_time(); + + tor_assert(msg_out); + tor_assert(launch_out); + + chan = channel_find_by_remote_digest(digest); + + /* Walk the list, unrefing the old one and refing the new at each + * iteration. + */ + for (; chan; chan = channel_next_with_digest(chan)) { + tor_assert(tor_memeq(chan->identity_digest, + digest, DIGEST_LEN)); + + if (chan->state == CHANNEL_STATE_CLOSING || + chan->state == CHANNEL_STATE_CLOSED || + chan->state == CHANNEL_STATE_ERROR) + continue; + + /* Never return a channel on which the other end appears to be + * a client. */ + if (channel_is_client(chan)) { + continue; + } + + /* Never return a non-open connection. */ + if (chan->state != CHANNEL_STATE_OPEN) { + /* If the address matches, don't launch a new connection for this + * circuit. */ + if (channel_matches_target_addr_for_extend(chan, target_addr)) + ++n_inprogress_goodaddr; + continue; + } + + /* Never return a connection that shouldn't be used for circs. */ + if (channel_is_bad_for_new_circs(chan)) { + ++n_old; + continue; + } + + /* Never return a non-canonical connection using a recent link protocol + * if the address is not what we wanted. + * + * The channel_is_canonical_is_reliable() function asks the lower layer + * if we should trust channel_is_canonical(). The below is from the + * comments of the old circuit_or_get_for_extend() and applies when + * the lower-layer transport is channel_tls_t. + * + * (For old link protocols, we can't rely on is_canonical getting + * set properly if we're talking to the right address, since we might + * have an out-of-date descriptor, and we will get no NETINFO cell to + * tell us about the right address.) + */ + if (!channel_is_canonical(chan) && + channel_is_canonical_is_reliable(chan) && + !channel_matches_target_addr_for_extend(chan, target_addr)) { + ++n_noncanonical; + continue; + } + + ++n_possible; + + if (!best) { + best = chan; /* If we have no 'best' so far, this one is good enough. */ + continue; + } + + if (channel_is_better(now, chan, best, 0)) + best = chan; + } + + if (best) { + *msg_out = "Connection is fine; using it."; + *launch_out = 0; + return best; + } else if (n_inprogress_goodaddr) { + *msg_out = "Connection in progress; waiting."; + *launch_out = 0; + return NULL; + } else if (n_old || n_noncanonical) { + *msg_out = "Connections all too old, or too non-canonical. " + " Launching a new one."; + *launch_out = 1; + return NULL; + } else { + *msg_out = "Not connected. Connecting."; + *launch_out = 1; + return NULL; + } +} + +/** + * Describe the transport subclass for a channel + * + * Invoke a method to get a string description of the lower-layer + * transport for this channel. + */ + +const char * +channel_describe_transport(channel_t *chan) +{ + tor_assert(chan); + tor_assert(chan->describe_transport); + + return chan->describe_transport(chan); +} + +/** + * Describe the transport subclass for a channel listener + * + * Invoke a method to get a string description of the lower-layer + * transport for this channel listener. + */ + +const char * +channel_listener_describe_transport(channel_listener_t *chan_l) +{ + tor_assert(chan_l); + tor_assert(chan_l->describe_transport); + + return chan_l->describe_transport(chan_l); +} + +/** + * Return the number of entries in queue + */ +static int +chan_cell_queue_len(const chan_cell_queue_t *queue) +{ + int r = 0; + cell_queue_entry_t *cell; + TOR_SIMPLEQ_FOREACH(cell, queue, next) + ++r; + return r; +} + +/** + * Dump channel statistics + * + * Dump statistics for one channel to the log + */ + +void +channel_dump_statistics(channel_t *chan, int severity) +{ + double avg, interval, age; + time_t now = time(NULL); + tor_addr_t remote_addr; + int have_remote_addr; + char *remote_addr_str; + + tor_assert(chan); + + age = (double)(now - chan->timestamp_created); + + tor_log(severity, LD_GENERAL, + "Channel " U64_FORMAT " (at %p) with transport %s is in state " + "%s (%d)", + U64_PRINTF_ARG(chan->global_identifier), chan, + channel_describe_transport(chan), + channel_state_to_string(chan->state), chan->state); + tor_log(severity, LD_GENERAL, + " * Channel " U64_FORMAT " was created at " U64_FORMAT + " (" U64_FORMAT " seconds ago) " + "and last active at " U64_FORMAT " (" U64_FORMAT " seconds ago)", + U64_PRINTF_ARG(chan->global_identifier), + U64_PRINTF_ARG(chan->timestamp_created), + U64_PRINTF_ARG(now - chan->timestamp_created), + U64_PRINTF_ARG(chan->timestamp_active), + U64_PRINTF_ARG(now - chan->timestamp_active)); + + /* Handle digest and nickname */ + if (!tor_digest_is_zero(chan->identity_digest)) { + if (chan->nickname) { + tor_log(severity, LD_GENERAL, + " * Channel " U64_FORMAT " says it is connected " + "to an OR with digest %s and nickname %s", + U64_PRINTF_ARG(chan->global_identifier), + hex_str(chan->identity_digest, DIGEST_LEN), + chan->nickname); + } else { + tor_log(severity, LD_GENERAL, + " * Channel " U64_FORMAT " says it is connected " + "to an OR with digest %s and no known nickname", + U64_PRINTF_ARG(chan->global_identifier), + hex_str(chan->identity_digest, DIGEST_LEN)); + } + } else { + if (chan->nickname) { + tor_log(severity, LD_GENERAL, + " * Channel " U64_FORMAT " does not know the digest" + " of the OR it is connected to, but reports its nickname is %s", + U64_PRINTF_ARG(chan->global_identifier), + chan->nickname); + } else { + tor_log(severity, LD_GENERAL, + " * Channel " U64_FORMAT " does not know the digest" + " or the nickname of the OR it is connected to", + U64_PRINTF_ARG(chan->global_identifier)); + } + } + + /* Handle remote address and descriptions */ + have_remote_addr = channel_get_addr_if_possible(chan, &remote_addr); + if (have_remote_addr) { + char *actual = tor_strdup(channel_get_actual_remote_descr(chan)); + remote_addr_str = tor_dup_addr(&remote_addr); + tor_log(severity, LD_GENERAL, + " * Channel " U64_FORMAT " says its remote address" + " is %s, and gives a canonical description of \"%s\" and an " + "actual description of \"%s\"", + U64_PRINTF_ARG(chan->global_identifier), + remote_addr_str, + channel_get_canonical_remote_descr(chan), + actual); + tor_free(remote_addr_str); + tor_free(actual); + } else { + char *actual = tor_strdup(channel_get_actual_remote_descr(chan)); + tor_log(severity, LD_GENERAL, + " * Channel " U64_FORMAT " does not know its remote " + "address, but gives a canonical description of \"%s\" and an " + "actual description of \"%s\"", + U64_PRINTF_ARG(chan->global_identifier), + channel_get_canonical_remote_descr(chan), + actual); + tor_free(actual); + } + + /* Handle marks */ + tor_log(severity, LD_GENERAL, + " * Channel " U64_FORMAT " has these marks: %s %s %s " + "%s %s %s", + U64_PRINTF_ARG(chan->global_identifier), + channel_is_bad_for_new_circs(chan) ? + "bad_for_new_circs" : "!bad_for_new_circs", + channel_is_canonical(chan) ? + "canonical" : "!canonical", + channel_is_canonical_is_reliable(chan) ? + "is_canonical_is_reliable" : + "!is_canonical_is_reliable", + channel_is_client(chan) ? + "client" : "!client", + channel_is_local(chan) ? + "local" : "!local", + channel_is_incoming(chan) ? + "incoming" : "outgoing"); + + /* Describe queues */ + tor_log(severity, LD_GENERAL, + " * Channel " U64_FORMAT " has %d queued incoming cells" + " and %d queued outgoing cells", + U64_PRINTF_ARG(chan->global_identifier), + chan_cell_queue_len(&chan->incoming_queue), + chan_cell_queue_len(&chan->outgoing_queue)); + + /* Describe circuits */ + tor_log(severity, LD_GENERAL, + " * Channel " U64_FORMAT " has %d active circuits out of" + " %d in total", + U64_PRINTF_ARG(chan->global_identifier), + (chan->cmux != NULL) ? + circuitmux_num_active_circuits(chan->cmux) : 0, + (chan->cmux != NULL) ? + circuitmux_num_circuits(chan->cmux) : 0); + + /* Describe timestamps */ + tor_log(severity, LD_GENERAL, + " * Channel " U64_FORMAT " was last used by a " + "client at " U64_FORMAT " (" U64_FORMAT " seconds ago)", + U64_PRINTF_ARG(chan->global_identifier), + U64_PRINTF_ARG(chan->timestamp_client), + U64_PRINTF_ARG(now - chan->timestamp_client)); + tor_log(severity, LD_GENERAL, + " * Channel " U64_FORMAT " was last drained at " + U64_FORMAT " (" U64_FORMAT " seconds ago)", + U64_PRINTF_ARG(chan->global_identifier), + U64_PRINTF_ARG(chan->timestamp_drained), + U64_PRINTF_ARG(now - chan->timestamp_drained)); + tor_log(severity, LD_GENERAL, + " * Channel " U64_FORMAT " last received a cell " + "at " U64_FORMAT " (" U64_FORMAT " seconds ago)", + U64_PRINTF_ARG(chan->global_identifier), + U64_PRINTF_ARG(chan->timestamp_recv), + U64_PRINTF_ARG(now - chan->timestamp_recv)); + tor_log(severity, LD_GENERAL, + " * Channel " U64_FORMAT " last trasmitted a cell " + "at " U64_FORMAT " (" U64_FORMAT " seconds ago)", + U64_PRINTF_ARG(chan->global_identifier), + U64_PRINTF_ARG(chan->timestamp_xmit), + U64_PRINTF_ARG(now - chan->timestamp_xmit)); + + /* Describe counters and rates */ + tor_log(severity, LD_GENERAL, + " * Channel " U64_FORMAT " has received " + U64_FORMAT " cells and transmitted " U64_FORMAT, + U64_PRINTF_ARG(chan->global_identifier), + U64_PRINTF_ARG(chan->n_cells_recved), + U64_PRINTF_ARG(chan->n_cells_xmitted)); + if (now > chan->timestamp_created && + chan->timestamp_created > 0) { + if (chan->n_cells_recved > 0) { + avg = (double)(chan->n_cells_recved) / age; + if (avg >= 1.0) { + tor_log(severity, LD_GENERAL, + " * Channel " U64_FORMAT " has averaged %f " + "cells received per second", + U64_PRINTF_ARG(chan->global_identifier), avg); + } else if (avg >= 0.0) { + interval = 1.0 / avg; + tor_log(severity, LD_GENERAL, + " * Channel " U64_FORMAT " has averaged %f " + "seconds between received cells", + U64_PRINTF_ARG(chan->global_identifier), interval); + } + } + if (chan->n_cells_xmitted > 0) { + avg = (double)(chan->n_cells_xmitted) / age; + if (avg >= 1.0) { + tor_log(severity, LD_GENERAL, + " * Channel " U64_FORMAT " has averaged %f " + "cells transmitted per second", + U64_PRINTF_ARG(chan->global_identifier), avg); + } else if (avg >= 0.0) { + interval = 1.0 / avg; + tor_log(severity, LD_GENERAL, + " * Channel " U64_FORMAT " has averaged %f " + "seconds between transmitted cells", + U64_PRINTF_ARG(chan->global_identifier), interval); + } + } + } + + /* Dump anything the lower layer has to say */ + channel_dump_transport_statistics(chan, severity); +} + +/** + * Dump channel listener statistics + * + * Dump statistics for one channel listener to the log + */ + +void +channel_listener_dump_statistics(channel_listener_t *chan_l, int severity) +{ + double avg, interval, age; + time_t now = time(NULL); + + tor_assert(chan_l); + + age = (double)(now - chan_l->timestamp_created); + + tor_log(severity, LD_GENERAL, + "Channel listener " U64_FORMAT " (at %p) with transport %s is in " + "state %s (%d)", + U64_PRINTF_ARG(chan_l->global_identifier), chan_l, + channel_listener_describe_transport(chan_l), + channel_listener_state_to_string(chan_l->state), chan_l->state); + tor_log(severity, LD_GENERAL, + " * Channel listener " U64_FORMAT " was created at " U64_FORMAT + " (" U64_FORMAT " seconds ago) " + "and last active at " U64_FORMAT " (" U64_FORMAT " seconds ago)", + U64_PRINTF_ARG(chan_l->global_identifier), + U64_PRINTF_ARG(chan_l->timestamp_created), + U64_PRINTF_ARG(now - chan_l->timestamp_created), + U64_PRINTF_ARG(chan_l->timestamp_active), + U64_PRINTF_ARG(now - chan_l->timestamp_active)); + + tor_log(severity, LD_GENERAL, + " * Channel listener " U64_FORMAT " last accepted an incoming " + "channel at " U64_FORMAT " (" U64_FORMAT " seconds ago) " + "and has accepted " U64_FORMAT " channels in total", + U64_PRINTF_ARG(chan_l->global_identifier), + U64_PRINTF_ARG(chan_l->timestamp_accepted), + U64_PRINTF_ARG(now - chan_l->timestamp_accepted), + U64_PRINTF_ARG(chan_l->n_accepted)); + + /* + * If it's sensible to do so, get the rate of incoming channels on this + * listener + */ + if (now > chan_l->timestamp_created && + chan_l->timestamp_created > 0 && + chan_l->n_accepted > 0) { + avg = (double)(chan_l->n_accepted) / age; + if (avg >= 1.0) { + tor_log(severity, LD_GENERAL, + " * Channel listener " U64_FORMAT " has averaged %f incoming " + "channels per second", + U64_PRINTF_ARG(chan_l->global_identifier), avg); + } else if (avg >= 0.0) { + interval = 1.0 / avg; + tor_log(severity, LD_GENERAL, + " * Channel listener " U64_FORMAT " has averaged %f seconds " + "between incoming channels", + U64_PRINTF_ARG(chan_l->global_identifier), interval); + } + } + + /* Dump anything the lower layer has to say */ + channel_listener_dump_transport_statistics(chan_l, severity); +} + +/** + * Invoke transport-specific stats dump for channel + * + * If there is a lower-layer statistics dump method, invoke it + */ + +void +channel_dump_transport_statistics(channel_t *chan, int severity) +{ + tor_assert(chan); + + if (chan->dumpstats) chan->dumpstats(chan, severity); +} + +/** + * Invoke transport-specific stats dump for channel listener + * + * If there is a lower-layer statistics dump method, invoke it + */ + +void +channel_listener_dump_transport_statistics(channel_listener_t *chan_l, + int severity) +{ + tor_assert(chan_l); + + if (chan_l->dumpstats) chan_l->dumpstats(chan_l, severity); +} + +/** + * Return text description of the remote endpoint + * + * This function return a test provided by the lower layer of the remote + * endpoint for this channel; it should specify the actual address connected + * to/from. + * + * Subsequent calls to channel_get_{actual,canonical}_remote_{address,descr} + * may invalidate the return value from this function. + */ +const char * +channel_get_actual_remote_descr(channel_t *chan) +{ + tor_assert(chan); + tor_assert(chan->get_remote_descr); + + /* Param 1 indicates the actual description */ + return chan->get_remote_descr(chan, GRD_FLAG_ORIGINAL); +} + +/** + * Return the text address of the remote endpoint. + * + * Subsequent calls to channel_get_{actual,canonical}_remote_{address,descr} + * may invalidate the return value from this function. + */ +const char * +channel_get_actual_remote_address(channel_t *chan) +{ + /* Param 1 indicates the actual description */ + return chan->get_remote_descr(chan, GRD_FLAG_ORIGINAL|GRD_FLAG_ADDR_ONLY); +} + +/** + * Return text description of the remote endpoint canonical address + * + * This function return a test provided by the lower layer of the remote + * endpoint for this channel; it should use the known canonical address for + * this OR's identity digest if possible. + * + * Subsequent calls to channel_get_{actual,canonical}_remote_{address,descr} + * may invalidate the return value from this function. + */ +const char * +channel_get_canonical_remote_descr(channel_t *chan) +{ + tor_assert(chan); + tor_assert(chan->get_remote_descr); + + /* Param 0 indicates the canonicalized description */ + return chan->get_remote_descr(chan, 0); +} + +/** + * Get remote address if possible. + * + * Write the remote address out to a tor_addr_t if the underlying transport + * supports this operation, and return 1. Return 0 if the underlying transport + * doesn't let us do this. + */ +int +channel_get_addr_if_possible(channel_t *chan, tor_addr_t *addr_out) +{ + tor_assert(chan); + tor_assert(addr_out); + + if (chan->get_remote_addr) + return chan->get_remote_addr(chan, addr_out); + /* Else no support, method not implemented */ + else return 0; +} + +/** + * Check if there are outgoing queue writes on this channel + * + * Indicate if either we have queued cells, or if not, whether the underlying + * lower-layer transport thinks it has an output queue. + */ + +int +channel_has_queued_writes(channel_t *chan) +{ + int has_writes = 0; + + tor_assert(chan); + tor_assert(chan->has_queued_writes); + + if (! TOR_SIMPLEQ_EMPTY(&chan->outgoing_queue)) { + has_writes = 1; + } else { + /* Check with the lower layer */ + has_writes = chan->has_queued_writes(chan); + } + + return has_writes; +} + +/** + * Check the is_bad_for_new_circs flag + * + * This function returns the is_bad_for_new_circs flag of the specified + * channel. + */ + +int +channel_is_bad_for_new_circs(channel_t *chan) +{ + tor_assert(chan); + + return chan->is_bad_for_new_circs; +} + +/** + * Mark a channel as bad for new circuits + * + * Set the is_bad_for_new_circs_flag on chan. + */ + +void +channel_mark_bad_for_new_circs(channel_t *chan) +{ + tor_assert(chan); + + chan->is_bad_for_new_circs = 1; +} + +/** + * Get the client flag + * + * This returns the client flag of a channel, which will be set if + * command_process_create_cell() in command.c thinks this is a connection + * from a client. + */ + +int +channel_is_client(channel_t *chan) +{ + tor_assert(chan); + + return chan->is_client; +} + +/** + * Set the client flag + * + * Mark a channel as being from a client + */ + +void +channel_mark_client(channel_t *chan) +{ + tor_assert(chan); + + chan->is_client = 1; +} + +/** + * Get the canonical flag for a channel + * + * This returns the is_canonical for a channel; this flag is determined by + * the lower layer and can't be set in a transport-independent way. + */ + +int +channel_is_canonical(channel_t *chan) +{ + tor_assert(chan); + tor_assert(chan->is_canonical); + + return chan->is_canonical(chan, 0); +} + +/** + * Test if the canonical flag is reliable + * + * This function asks if the lower layer thinks it's safe to trust the + * result of channel_is_canonical() + */ + +int +channel_is_canonical_is_reliable(channel_t *chan) +{ + tor_assert(chan); + tor_assert(chan->is_canonical); + + return chan->is_canonical(chan, 1); +} + +/** + * Test incoming flag + * + * This function gets the incoming flag; this is set when a listener spawns + * a channel. If this returns true the channel was remotely initiated. + */ + +int +channel_is_incoming(channel_t *chan) +{ + tor_assert(chan); + + return chan->is_incoming; +} + +/** + * Set the incoming flag + * + * This function is called when a channel arrives on a listening channel + * to mark it as incoming. + */ + +void +channel_mark_incoming(channel_t *chan) +{ + tor_assert(chan); + + chan->is_incoming = 1; +} + +/** + * Test local flag + * + * This function gets the local flag; the lower layer should set this when + * setting up the channel if is_local_addr() is true for all of the + * destinations it will communicate with on behalf of this channel. It's + * used to decide whether to declare the network reachable when seeing incoming + * traffic on the channel. + */ + +int +channel_is_local(channel_t *chan) +{ + tor_assert(chan); + + return chan->is_local; +} + +/** + * Set the local flag + * + * This internal-only function should be called by the lower layer if the + * channel is to a local address. See channel_is_local() above or the + * description of the is_local bit in channel.h + */ + +void +channel_mark_local(channel_t *chan) +{ + tor_assert(chan); + + chan->is_local = 1; +} + +/** + * Test outgoing flag + * + * This function gets the outgoing flag; this is the inverse of the incoming + * bit set when a listener spawns a channel. If this returns true the channel + * was locally initiated. + */ + +int +channel_is_outgoing(channel_t *chan) +{ + tor_assert(chan); + + return !(chan->is_incoming); +} + +/** + * Mark a channel as outgoing + * + * This function clears the incoming flag and thus marks a channel as + * outgoing. + */ + +void +channel_mark_outgoing(channel_t *chan) +{ + tor_assert(chan); + + chan->is_incoming = 0; +} + +/********************* + * Timestamp updates * + ********************/ + +/** + * Update the created timestamp for a channel + * + * This updates the channel's created timestamp and should only be called + * from channel_init(). + */ + +void +channel_timestamp_created(channel_t *chan) +{ + time_t now = time(NULL); + + tor_assert(chan); + + chan->timestamp_created = now; +} + +/** + * Update the created timestamp for a channel listener + * + * This updates the channel listener's created timestamp and should only be + * called from channel_init_listener(). + */ + +void +channel_listener_timestamp_created(channel_listener_t *chan_l) +{ + time_t now = time(NULL); + + tor_assert(chan_l); + + chan_l->timestamp_created = now; +} + +/** + * Update the last active timestamp for a channel + * + * This function updates the channel's last active timestamp; it should be + * called by the lower layer whenever there is activity on the channel which + * does not lead to a cell being transmitted or received; the active timestamp + * is also updated from channel_timestamp_recv() and channel_timestamp_xmit(), + * but it should be updated for things like the v3 handshake and stuff that + * produce activity only visible to the lower layer. + */ + +void +channel_timestamp_active(channel_t *chan) +{ + time_t now = time(NULL); + + tor_assert(chan); + + chan->timestamp_active = now; +} + +/** + * Update the last active timestamp for a channel listener + */ + +void +channel_listener_timestamp_active(channel_listener_t *chan_l) +{ + time_t now = time(NULL); + + tor_assert(chan_l); + + chan_l->timestamp_active = now; +} + +/** + * Update the last accepted timestamp. + * + * This function updates the channel listener's last accepted timestamp; it + * should be called whenever a new incoming channel is accepted on a + * listener. + */ + +void +channel_listener_timestamp_accepted(channel_listener_t *chan_l) +{ + time_t now = time(NULL); + + tor_assert(chan_l); + + chan_l->timestamp_active = now; + chan_l->timestamp_accepted = now; +} + +/** + * Update client timestamp + * + * This function is called by relay.c to timestamp a channel that appears to + * be used as a client. + */ + +void +channel_timestamp_client(channel_t *chan) +{ + time_t now = time(NULL); + + tor_assert(chan); + + chan->timestamp_client = now; +} + +/** + * Update the last drained timestamp + * + * This is called whenever we transmit a cell which leaves the outgoing cell + * queue completely empty. It also updates the xmit time and the active time. + */ + +void +channel_timestamp_drained(channel_t *chan) +{ + time_t now = time(NULL); + + tor_assert(chan); + + chan->timestamp_active = now; + chan->timestamp_drained = now; + chan->timestamp_xmit = now; +} + +/** + * Update the recv timestamp + * + * This is called whenever we get an incoming cell from the lower layer. + * This also updates the active timestamp. + */ + +void +channel_timestamp_recv(channel_t *chan) +{ + time_t now = time(NULL); + + tor_assert(chan); + + chan->timestamp_active = now; + chan->timestamp_recv = now; +} + +/** + * Update the xmit timestamp + * This is called whenever we pass an outgoing cell to the lower layer. This + * also updates the active timestamp. + */ + +void +channel_timestamp_xmit(channel_t *chan) +{ + time_t now = time(NULL); + + tor_assert(chan); + + chan->timestamp_active = now; + chan->timestamp_xmit = now; +} + +/*************************************************************** + * Timestamp queries - see above for definitions of timestamps * + **************************************************************/ + +/** + * Query created timestamp for a channel + */ + +time_t +channel_when_created(channel_t *chan) +{ + tor_assert(chan); + + return chan->timestamp_created; +} + +/** + * Query created timestamp for a channel listener + */ + +time_t +channel_listener_when_created(channel_listener_t *chan_l) +{ + tor_assert(chan_l); + + return chan_l->timestamp_created; +} + +/** + * Query last active timestamp for a channel + */ + +time_t +channel_when_last_active(channel_t *chan) +{ + tor_assert(chan); + + return chan->timestamp_active; +} + +/** + * Query last active timestamp for a channel listener + */ + +time_t +channel_listener_when_last_active(channel_listener_t *chan_l) +{ + tor_assert(chan_l); + + return chan_l->timestamp_active; +} + +/** + * Query last accepted timestamp for a channel listener + */ + +time_t +channel_listener_when_last_accepted(channel_listener_t *chan_l) +{ + tor_assert(chan_l); + + return chan_l->timestamp_accepted; +} + +/** + * Query client timestamp + */ + +time_t +channel_when_last_client(channel_t *chan) +{ + tor_assert(chan); + + return chan->timestamp_client; +} + +/** + * Query drained timestamp + */ + +time_t +channel_when_last_drained(channel_t *chan) +{ + tor_assert(chan); + + return chan->timestamp_drained; +} + +/** + * Query recv timestamp + */ + +time_t +channel_when_last_recv(channel_t *chan) +{ + tor_assert(chan); + + return chan->timestamp_recv; +} + +/** + * Query xmit timestamp + */ + +time_t +channel_when_last_xmit(channel_t *chan) +{ + tor_assert(chan); + + return chan->timestamp_xmit; +} + +/** + * Query accepted counter + */ + +uint64_t +channel_listener_count_accepted(channel_listener_t *chan_l) +{ + tor_assert(chan_l); + + return chan_l->n_accepted; +} + +/** + * Query received cell counter + */ + +uint64_t +channel_count_recved(channel_t *chan) +{ + tor_assert(chan); + + return chan->n_cells_recved; +} + +/** + * Query transmitted cell counter + */ + +uint64_t +channel_count_xmitted(channel_t *chan) +{ + tor_assert(chan); + + return chan->n_cells_xmitted; +} + +/** + * Check if a channel matches an extend_info_t + * + * This function calls the lower layer and asks if this channel matches a + * given extend_info_t. + */ + +int +channel_matches_extend_info(channel_t *chan, extend_info_t *extend_info) +{ + tor_assert(chan); + tor_assert(chan->matches_extend_info); + tor_assert(extend_info); + + return chan->matches_extend_info(chan, extend_info); +} + +/** + * Check if a channel matches a given target address; return true iff we do. + * + * This function calls into the lower layer and asks if this channel thinks + * it matches a given target address for circuit extension purposes. + */ + +int +channel_matches_target_addr_for_extend(channel_t *chan, + const tor_addr_t *target) +{ + tor_assert(chan); + tor_assert(chan->matches_target); + tor_assert(target); + + return chan->matches_target(chan, target); +} + +/** + * Return the total number of circuits used by a channel + * + * @param chan Channel to query + * @return Number of circuits using this as n_chan or p_chan + */ + +unsigned int +channel_num_circuits(channel_t *chan) +{ + tor_assert(chan); + + return chan->num_n_circuits + + chan->num_p_circuits; +} + +/** + * Set up circuit ID generation + * + * This is called when setting up a channel and replaces the old + * connection_or_set_circid_type() + */ +void +channel_set_circid_type(channel_t *chan, + crypto_pk_t *identity_rcvd, + int consider_identity) +{ + int started_here; + crypto_pk_t *our_identity; + + tor_assert(chan); + + started_here = channel_is_outgoing(chan); + + if (! consider_identity) { + if (started_here) + chan->circ_id_type = CIRC_ID_TYPE_HIGHER; + else + chan->circ_id_type = CIRC_ID_TYPE_LOWER; + return; + } + + our_identity = started_here ? + get_tlsclient_identity_key() : get_server_identity_key(); + + if (identity_rcvd) { + if (crypto_pk_cmp_keys(our_identity, identity_rcvd) < 0) { + chan->circ_id_type = CIRC_ID_TYPE_LOWER; + } else { + chan->circ_id_type = CIRC_ID_TYPE_HIGHER; + } + } else { + chan->circ_id_type = CIRC_ID_TYPE_NEITHER; + } +} + diff --git a/src/tor/channel.h b/src/tor/channel.h new file mode 100644 index 0000000..a9ade3f --- /dev/null +++ b/src/tor/channel.h @@ -0,0 +1,489 @@ +/* * Copyright (c) 2012-2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file channel.h + * \brief Header file for channel.c + **/ + +#ifndef TOR_CHANNEL_H +#define TOR_CHANNEL_H + +#include "or.h" +#include "circuitmux.h" + +/* Channel handler function pointer typedefs */ +typedef void (*channel_listener_fn_ptr)(channel_listener_t *, channel_t *); +typedef void (*channel_cell_handler_fn_ptr)(channel_t *, cell_t *); +typedef void (*channel_var_cell_handler_fn_ptr)(channel_t *, var_cell_t *); + +struct cell_queue_entry_s; +TOR_SIMPLEQ_HEAD(chan_cell_queue, cell_queue_entry_s) incoming_queue; +typedef struct chan_cell_queue chan_cell_queue_t; + +/* + * Channel struct; see the channel_t typedef in or.h. A channel is an + * abstract interface for the OR-to-OR connection, similar to connection_or_t, + * but without the strong coupling to the underlying TLS implementation. They + * are constructed by calling a protocol-specific function to open a channel + * to a particular node, and once constructed support the abstract operations + * defined below. + */ + +struct channel_s { + /* Magic number for type-checking cast macros */ + uint32_t magic; + + /* Current channel state */ + channel_state_t state; + + /* Globally unique ID number for a channel over the lifetime of a Tor + * process. + */ + uint64_t global_identifier; + + /* Should we expect to see this channel in the channel lists? */ + unsigned char registered:1; + + /** has this channel ever been open? */ + unsigned int has_been_open:1; + + /** Why did we close? + */ + enum { + CHANNEL_NOT_CLOSING = 0, + CHANNEL_CLOSE_REQUESTED, + CHANNEL_CLOSE_FROM_BELOW, + CHANNEL_CLOSE_FOR_ERROR + } reason_for_closing; + + /* Timestamps for both cell channels and listeners */ + time_t timestamp_created; /* Channel created */ + time_t timestamp_active; /* Any activity */ + + /* Methods implemented by the lower layer */ + + /* Free a channel */ + void (*free)(channel_t *); + /* Close an open channel */ + void (*close)(channel_t *); + /* Describe the transport subclass for this channel */ + const char * (*describe_transport)(channel_t *); + /* Optional method to dump transport-specific statistics on the channel */ + void (*dumpstats)(channel_t *, int); + + /* Registered handlers for incoming cells */ + channel_cell_handler_fn_ptr cell_handler; + channel_var_cell_handler_fn_ptr var_cell_handler; + + /* Methods implemented by the lower layer */ + + /* + * Ask the underlying transport what the remote endpoint address is, in + * a tor_addr_t. This is optional and subclasses may leave this NULL. + * If they implement it, they should write the address out to the + * provided tor_addr_t *, and return 1 if successful or 0 if no address + * available. + */ + int (*get_remote_addr)(channel_t *, tor_addr_t *); + int (*get_transport_name)(channel_t *chan, char **transport_out); + +#define GRD_FLAG_ORIGINAL 1 +#define GRD_FLAG_ADDR_ONLY 2 + /* + * Get a text description of the remote endpoint; canonicalized if the flag + * GRD_FLAG_ORIGINAL is not set, or the one we originally connected + * to/received from if it is. If GRD_FLAG_ADDR_ONLY is set, we return only + * the original address. + */ + const char * (*get_remote_descr)(channel_t *, int); + /* Check if the lower layer has queued writes */ + int (*has_queued_writes)(channel_t *); + /* + * If the second param is zero, ask the lower layer if this is + * 'canonical', for a transport-specific definition of canonical; if + * it is 1, ask if the answer to the preceding query is safe to rely + * on. + */ + int (*is_canonical)(channel_t *, int); + /* Check if this channel matches a specified extend_info_t */ + int (*matches_extend_info)(channel_t *, extend_info_t *); + /* Check if this channel matches a target address when extending */ + int (*matches_target)(channel_t *, const tor_addr_t *); + /* Write a cell to an open channel */ + int (*write_cell)(channel_t *, cell_t *); + /* Write a packed cell to an open channel */ + int (*write_packed_cell)(channel_t *, packed_cell_t *); + /* Write a variable-length cell to an open channel */ + int (*write_var_cell)(channel_t *, var_cell_t *); + + /* + * Hash of the public RSA key for the other side's identity key, or + * zeroes if the other side hasn't shown us a valid identity key. + */ + char identity_digest[DIGEST_LEN]; + /* Nickname of the OR on the other side, or NULL if none. */ + char *nickname; + + /* + * Linked list of channels with the same identity digest, for the + * digest->channel map + */ + TOR_LIST_ENTRY(channel_s) next_with_same_id; + + /* List of incoming cells to handle */ + chan_cell_queue_t incoming_queue; + + /* List of queued outgoing cells */ + chan_cell_queue_t outgoing_queue; + + /* Circuit mux for circuits sending on this channel */ + circuitmux_t *cmux; + + /* Circuit ID generation stuff for use by circuitbuild.c */ + + /* + * When we send CREATE cells along this connection, which half of the + * space should we use? + */ + ENUM_BF(circ_id_type_t) circ_id_type:2; + /** DOCDOC*/ + unsigned wide_circ_ids:1; + /* + * Which circ_id do we try to use next on this connection? This is + * always in the range 0..1<<15-1. + */ + circid_t next_circ_id; + + /* For how many circuits are we n_chan? What about p_chan? */ + unsigned int num_n_circuits, num_p_circuits; + + /* + * True iff this channel shouldn't get any new circs attached to it, + * because the connection is too old, or because there's a better one. + * More generally, this flag is used to note an unhealthy connection; + * for example, if a bad connection fails we shouldn't assume that the + * router itself has a problem. + */ + unsigned int is_bad_for_new_circs:1; + + /** True iff we have decided that the other end of this connection + * is a client. Channels with this flag set should never be used + * to satisfy an EXTEND request. */ + unsigned int is_client:1; + + /** Set if the channel was initiated remotely (came from a listener) */ + unsigned int is_incoming:1; + + /** Set by lower layer if this is local; i.e., everything it communicates + * with for this channel returns true for is_local_addr(). This is used + * to decide whether to declare reachability when we receive something on + * this channel in circuitbuild.c + */ + unsigned int is_local:1; + + /** Channel timestamps for cell channels */ + time_t timestamp_client; /* Client used this, according to relay.c */ + time_t timestamp_drained; /* Output queue empty */ + time_t timestamp_recv; /* Cell received from lower layer */ + time_t timestamp_xmit; /* Cell sent to lower layer */ + + /* Timestamp for relay.c */ + time_t timestamp_last_added_nonpadding; + + /** Unique ID for measuring direct network status requests;vtunneled ones + * come over a circuit_t, which has a dirreq_id field as well, but is a + * distinct namespace. */ + uint64_t dirreq_id; + + /** Channel counters for cell channels */ + uint64_t n_cells_recved; + uint64_t n_cells_xmitted; +}; + +struct channel_listener_s { + /* Current channel listener state */ + channel_listener_state_t state; + + /* Globally unique ID number for a channel over the lifetime of a Tor + * process. + */ + uint64_t global_identifier; + + /* Should we expect to see this channel in the channel lists? */ + unsigned char registered:1; + + /** Why did we close? + */ + enum { + CHANNEL_LISTENER_NOT_CLOSING = 0, + CHANNEL_LISTENER_CLOSE_REQUESTED, + CHANNEL_LISTENER_CLOSE_FROM_BELOW, + CHANNEL_LISTENER_CLOSE_FOR_ERROR + } reason_for_closing; + + /* Timestamps for both cell channels and listeners */ + time_t timestamp_created; /* Channel created */ + time_t timestamp_active; /* Any activity */ + + /* Methods implemented by the lower layer */ + + /* Free a channel */ + void (*free)(channel_listener_t *); + /* Close an open channel */ + void (*close)(channel_listener_t *); + /* Describe the transport subclass for this channel */ + const char * (*describe_transport)(channel_listener_t *); + /* Optional method to dump transport-specific statistics on the channel */ + void (*dumpstats)(channel_listener_t *, int); + + /* Registered listen handler to call on incoming connection */ + channel_listener_fn_ptr listener; + + /* List of pending incoming connections */ + smartlist_t *incoming_list; + + /* Timestamps for listeners */ + time_t timestamp_accepted; + + /* Counters for listeners */ + uint64_t n_accepted; +}; + +/* Channel state manipulations */ + +int channel_state_is_valid(channel_state_t state); +int channel_listener_state_is_valid(channel_listener_state_t state); + +int channel_state_can_transition(channel_state_t from, channel_state_t to); +int channel_listener_state_can_transition(channel_listener_state_t from, + channel_listener_state_t to); + +const char * channel_state_to_string(channel_state_t state); +const char * +channel_listener_state_to_string(channel_listener_state_t state); + +/* Abstract channel operations */ + +void channel_mark_for_close(channel_t *chan); +void channel_write_cell(channel_t *chan, cell_t *cell); +void channel_write_packed_cell(channel_t *chan, packed_cell_t *cell); +void channel_write_var_cell(channel_t *chan, var_cell_t *cell); + +void channel_listener_mark_for_close(channel_listener_t *chan_l); + +/* Channel callback registrations */ + +/* Listener callback */ +channel_listener_fn_ptr +channel_listener_get_listener_fn(channel_listener_t *chan); + +void channel_listener_set_listener_fn(channel_listener_t *chan, + channel_listener_fn_ptr listener); + +/* Incoming cell callbacks */ +channel_cell_handler_fn_ptr channel_get_cell_handler(channel_t *chan); + +channel_var_cell_handler_fn_ptr +channel_get_var_cell_handler(channel_t *chan); + +void channel_set_cell_handlers(channel_t *chan, + channel_cell_handler_fn_ptr cell_handler, + channel_var_cell_handler_fn_ptr + var_cell_handler); + +/* Clean up closed channels and channel listeners periodically; these are + * called from run_scheduled_events() in onion_main.c. + */ +void channel_run_cleanup(void); +void channel_listener_run_cleanup(void); + +/* Close all channels and deallocate everything */ +void channel_free_all(void); + +/* Dump some statistics in the log */ +void channel_dumpstats(int severity); +void channel_listener_dumpstats(int severity); + +/* Set the cmux policy on all active channels */ +void channel_set_cmux_policy_everywhere(circuitmux_policy_t *pol); + +#ifdef TOR_CHANNEL_INTERNAL_ + +/* Channel operations for subclasses and internal use only */ + +/* Initialize a newly allocated channel - do this first in subclass + * constructors. + */ + +void channel_init(channel_t *chan); +void channel_init_listener(channel_listener_t *chan); + +/* Channel registration/unregistration */ +void channel_register(channel_t *chan); +void channel_unregister(channel_t *chan); + +/* Channel listener registration/unregistration */ +void channel_listener_register(channel_listener_t *chan_l); +void channel_listener_unregister(channel_listener_t *chan_l); + +/* Close from below */ +void channel_close_from_lower_layer(channel_t *chan); +void channel_close_for_error(channel_t *chan); +void channel_closed(channel_t *chan); + +void channel_listener_close_from_lower_layer(channel_listener_t *chan_l); +void channel_listener_close_for_error(channel_listener_t *chan_l); +void channel_listener_closed(channel_listener_t *chan_l); + +/* Free a channel */ +void channel_free(channel_t *chan); +void channel_listener_free(channel_listener_t *chan_l); + +/* State/metadata setters */ + +void channel_change_state(channel_t *chan, channel_state_t to_state); +void channel_clear_identity_digest(channel_t *chan); +void channel_clear_remote_end(channel_t *chan); +void channel_mark_local(channel_t *chan); +void channel_mark_incoming(channel_t *chan); +void channel_mark_outgoing(channel_t *chan); +void channel_set_identity_digest(channel_t *chan, + const char *identity_digest); +void channel_set_remote_end(channel_t *chan, + const char *identity_digest, + const char *nickname); + +void channel_listener_change_state(channel_listener_t *chan_l, + channel_listener_state_t to_state); + +/* Timestamp updates */ +void channel_timestamp_created(channel_t *chan); +void channel_timestamp_active(channel_t *chan); +void channel_timestamp_drained(channel_t *chan); +void channel_timestamp_recv(channel_t *chan); +void channel_timestamp_xmit(channel_t *chan); + +void channel_listener_timestamp_created(channel_listener_t *chan_l); +void channel_listener_timestamp_active(channel_listener_t *chan_l); +void channel_listener_timestamp_accepted(channel_listener_t *chan_l); + +/* Incoming channel handling */ +void channel_listener_process_incoming(channel_listener_t *listener); +void channel_listener_queue_incoming(channel_listener_t *listener, + channel_t *incoming); + +/* Incoming cell handling */ +void channel_process_cells(channel_t *chan); +void channel_queue_cell(channel_t *chan, cell_t *cell); +void channel_queue_var_cell(channel_t *chan, var_cell_t *var_cell); + +/* Outgoing cell handling */ +void channel_flush_cells(channel_t *chan); + +/* Request from lower layer for more cells if available */ +ssize_t channel_flush_some_cells(channel_t *chan, ssize_t num_cells); + +/* Query if data available on this channel */ +int channel_more_to_flush(channel_t *chan); + +/* Notify flushed outgoing for dirreq handling */ +void channel_notify_flushed(channel_t *chan); + +/* Handle stuff we need to do on open like notifying circuits */ +void channel_do_open_actions(channel_t *chan); + +#endif + +/* Helper functions to perform operations on channels */ + +int channel_send_destroy(circid_t circ_id, channel_t *chan, + int reason); + +/* + * Outside abstract interfaces that should eventually get turned into + * something transport/address format independent. + */ + +channel_t * channel_connect(const tor_addr_t *addr, uint16_t port, + const char *id_digest); + +channel_t * channel_get_for_extend(const char *digest, + const tor_addr_t *target_addr, + const char **msg_out, + int *launch_out); + +/* Ask which of two channels is better for circuit-extension purposes */ +int channel_is_better(time_t now, + channel_t *a, channel_t *b, + int forgive_new_connections); + +/** Channel lookups + */ + +channel_t * channel_find_by_global_id(uint64_t global_identifier); +channel_t * channel_find_by_remote_digest(const char *identity_digest); + +/** For things returned by channel_find_by_remote_digest(), walk the list. + */ +channel_t * channel_next_with_digest(channel_t *chan); + +/* + * Metadata queries/updates + */ + +const char * channel_describe_transport(channel_t *chan); +void channel_dump_statistics(channel_t *chan, int severity); +void channel_dump_transport_statistics(channel_t *chan, int severity); +const char * channel_get_actual_remote_descr(channel_t *chan); +const char * channel_get_actual_remote_address(channel_t *chan); +int channel_get_addr_if_possible(channel_t *chan, tor_addr_t *addr_out); +const char * channel_get_canonical_remote_descr(channel_t *chan); +int channel_has_queued_writes(channel_t *chan); +int channel_is_bad_for_new_circs(channel_t *chan); +void channel_mark_bad_for_new_circs(channel_t *chan); +int channel_is_canonical(channel_t *chan); +int channel_is_canonical_is_reliable(channel_t *chan); +int channel_is_client(channel_t *chan); +int channel_is_local(channel_t *chan); +int channel_is_incoming(channel_t *chan); +int channel_is_outgoing(channel_t *chan); +void channel_mark_client(channel_t *chan); +int channel_matches_extend_info(channel_t *chan, extend_info_t *extend_info); +int channel_matches_target_addr_for_extend(channel_t *chan, + const tor_addr_t *target); +unsigned int channel_num_circuits(channel_t *chan); +void channel_set_circid_type(channel_t *chan, crypto_pk_t *identity_rcvd, + int consider_identity); +void channel_timestamp_client(channel_t *chan); + +const char * channel_listener_describe_transport(channel_listener_t *chan_l); +void channel_listener_dump_statistics(channel_listener_t *chan_l, + int severity); +void channel_listener_dump_transport_statistics(channel_listener_t *chan_l, + int severity); + +/* Timestamp queries */ +time_t channel_when_created(channel_t *chan); +time_t channel_when_last_active(channel_t *chan); +time_t channel_when_last_client(channel_t *chan); +time_t channel_when_last_drained(channel_t *chan); +time_t channel_when_last_recv(channel_t *chan); +time_t channel_when_last_xmit(channel_t *chan); + +time_t channel_listener_when_created(channel_listener_t *chan_l); +time_t channel_listener_when_last_active(channel_listener_t *chan_l); +time_t channel_listener_when_last_accepted(channel_listener_t *chan_l); + +/* Counter queries */ +uint64_t channel_count_recved(channel_t *chan); +uint64_t channel_count_xmitted(channel_t *chan); + +uint64_t channel_listener_count_accepted(channel_listener_t *chan_l); + +int packed_cell_is_destroy(channel_t *chan, + const packed_cell_t *packed_cell, + circid_t *circid_out); + +#endif + diff --git a/src/tor/channeltls.c b/src/tor/channeltls.c new file mode 100644 index 0000000..959ec47 --- /dev/null +++ b/src/tor/channeltls.c @@ -0,0 +1,2074 @@ +/* * Copyright (c) 2012-2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file channeltls.c + * \brief channel_t concrete subclass using or_connection_t + **/ + +/* + * Define this so channel.h gives us things only channel_t subclasses + * should touch. + */ + +#define TOR_CHANNEL_INTERNAL_ + +#include "or.h" +#include "channel.h" +#include "channeltls.h" +#include "circuitmux.h" +#include "circuitmux_ewma.h" +#include "config.h" +#include "connection.h" +#include "connection_or.h" +#include "control.h" +#include "relay.h" +#include "router.h" +#include "routerlist.h" + +/** How many CELL_PADDING cells have we received, ever? */ +uint64_t stats_n_padding_cells_processed = 0; +/** How many CELL_VERSIONS cells have we received, ever? */ +uint64_t stats_n_versions_cells_processed = 0; +/** How many CELL_NETINFO cells have we received, ever? */ +uint64_t stats_n_netinfo_cells_processed = 0; +/** How many CELL_VPADDING cells have we received, ever? */ +uint64_t stats_n_vpadding_cells_processed = 0; +/** How many CELL_CERTS cells have we received, ever? */ +uint64_t stats_n_certs_cells_processed = 0; +/** How many CELL_AUTH_CHALLENGE cells have we received, ever? */ +uint64_t stats_n_auth_challenge_cells_processed = 0; +/** How many CELL_AUTHENTICATE cells have we received, ever? */ +uint64_t stats_n_authenticate_cells_processed = 0; +/** How many CELL_AUTHORIZE cells have we received, ever? */ +uint64_t stats_n_authorize_cells_processed = 0; + +/** Active listener, if any */ +channel_listener_t *channel_tls_listener = NULL; + +/* Utility function declarations */ +static void channel_tls_common_init(channel_tls_t *tlschan); + +/* channel_tls_t method declarations */ + +static void channel_tls_close_method(channel_t *chan); +static const char * channel_tls_describe_transport_method(channel_t *chan); +static void channel_tls_free_method(channel_t *chan); +static int +channel_tls_get_remote_addr_method(channel_t *chan, tor_addr_t *addr_out); +static int +channel_tls_get_transport_name_method(channel_t *chan, char **transport_out); +static const char * +channel_tls_get_remote_descr_method(channel_t *chan, int flags); +static int channel_tls_has_queued_writes_method(channel_t *chan); +static int channel_tls_is_canonical_method(channel_t *chan, int req); +static int +channel_tls_matches_extend_info_method(channel_t *chan, + extend_info_t *extend_info); +static int channel_tls_matches_target_method(channel_t *chan, + const tor_addr_t *target); +static int channel_tls_write_cell_method(channel_t *chan, + cell_t *cell); +static int channel_tls_write_packed_cell_method(channel_t *chan, + packed_cell_t *packed_cell); +static int channel_tls_write_var_cell_method(channel_t *chan, + var_cell_t *var_cell); + +/* channel_listener_tls_t method declarations */ + +static void channel_tls_listener_close_method(channel_listener_t *chan_l); +static const char * +channel_tls_listener_describe_transport_method(channel_listener_t *chan_l); + +/** Handle incoming cells for the handshake stuff here rather than + * passing them on up. */ + +static void channel_tls_process_versions_cell(var_cell_t *cell, + channel_tls_t *tlschan); +static void channel_tls_process_netinfo_cell(cell_t *cell, + channel_tls_t *tlschan); +static void channel_tls_process_certs_cell(var_cell_t *cell, + channel_tls_t *tlschan); +static void channel_tls_process_auth_challenge_cell(var_cell_t *cell, + channel_tls_t *tlschan); +static void channel_tls_process_authenticate_cell(var_cell_t *cell, + channel_tls_t *tlschan); +static int command_allowed_before_handshake(uint8_t command); +static int enter_v3_handshake_with_cell(var_cell_t *cell, + channel_tls_t *tlschan); + +/** + * Do parts of channel_tls_t initialization common to channel_tls_connect() + * and channel_tls_handle_incoming(). + */ + +static void +channel_tls_common_init(channel_tls_t *tlschan) +{ + channel_t *chan; + + tor_assert(tlschan); + + chan = &(tlschan->base_); + channel_init(chan); + chan->magic = TLS_CHAN_MAGIC; + chan->state = CHANNEL_STATE_OPENING; + chan->close = channel_tls_close_method; + chan->describe_transport = channel_tls_describe_transport_method; + chan->free = channel_tls_free_method; + chan->get_remote_addr = channel_tls_get_remote_addr_method; + chan->get_remote_descr = channel_tls_get_remote_descr_method; + chan->get_transport_name = channel_tls_get_transport_name_method; + chan->has_queued_writes = channel_tls_has_queued_writes_method; + chan->is_canonical = channel_tls_is_canonical_method; + chan->matches_extend_info = channel_tls_matches_extend_info_method; + chan->matches_target = channel_tls_matches_target_method; + chan->write_cell = channel_tls_write_cell_method; + chan->write_packed_cell = channel_tls_write_packed_cell_method; + chan->write_var_cell = channel_tls_write_var_cell_method; + + chan->cmux = circuitmux_alloc(); + if (cell_ewma_enabled()) { + circuitmux_set_policy(chan->cmux, &ewma_policy); + } +} + +/** + * Start a new TLS channel + * + * Launch a new OR connection to addr:port and expect to + * handshake with an OR with identity digest id_digest, and wrap + * it in a channel_tls_t. + */ + +channel_t * +channel_tls_connect(const tor_addr_t *addr, uint16_t port, + const char *id_digest) +{ + channel_tls_t *tlschan = tor_malloc_zero(sizeof(*tlschan)); + channel_t *chan = &(tlschan->base_); + + channel_tls_common_init(tlschan); + + log_debug(LD_CHANNEL, + "In channel_tls_connect() for channel %p " + "(global id " U64_FORMAT ")", + tlschan, + U64_PRINTF_ARG(chan->global_identifier)); + + if (is_local_addr(addr)) channel_mark_local(chan); + channel_mark_outgoing(chan); + + /* Set up or_connection stuff */ + tlschan->conn = connection_or_connect(addr, port, id_digest, tlschan); + /* connection_or_connect() will fill in tlschan->conn */ + if (!(tlschan->conn)) { + chan->reason_for_closing = CHANNEL_CLOSE_FOR_ERROR; + channel_change_state(chan, CHANNEL_STATE_ERROR); + goto err; + } + + log_debug(LD_CHANNEL, + "Got orconn %p for channel with global id " U64_FORMAT, + tlschan->conn, U64_PRINTF_ARG(chan->global_identifier)); + + goto done; + + err: + circuitmux_free(chan->cmux); + tor_free(tlschan); + chan = NULL; + + done: + /* If we got one, we should register it */ + if (chan) channel_register(chan); + + return chan; +} + +/** + * Return the current channel_tls_t listener + * + * Returns the current channel listener for incoming TLS connections, or + * NULL if none has been established + */ + +channel_listener_t * +channel_tls_get_listener(void) +{ + return channel_tls_listener; +} + +/** + * Start a channel_tls_t listener if necessary + * + * Return the current channel_tls_t listener, or start one if we haven't yet, + * and return that. + */ + +channel_listener_t * +channel_tls_start_listener(void) +{ + channel_listener_t *listener; + + if (!channel_tls_listener) { + listener = tor_malloc_zero(sizeof(*listener)); + channel_init_listener(listener); + listener->state = CHANNEL_LISTENER_STATE_LISTENING; + listener->close = channel_tls_listener_close_method; + listener->describe_transport = + channel_tls_listener_describe_transport_method; + + channel_tls_listener = listener; + + log_debug(LD_CHANNEL, + "Starting TLS channel listener %p with global id " U64_FORMAT, + listener, U64_PRINTF_ARG(listener->global_identifier)); + + channel_listener_register(listener); + } else listener = channel_tls_listener; + + return listener; +} + +/** + * Free everything on shutdown + * + * Not much to do here, since channel_free_all() takes care of a lot, but let's + * get rid of the listener. + */ + +void +channel_tls_free_all(void) +{ + channel_listener_t *old_listener = NULL; + + log_debug(LD_CHANNEL, + "Shutting down TLS channels..."); + + if (channel_tls_listener) { + /* + * When we close it, channel_tls_listener will get nulled out, so save + * a pointer so we can free it. + */ + old_listener = channel_tls_listener; + log_debug(LD_CHANNEL, + "Closing channel_tls_listener with ID " U64_FORMAT + " at %p.", + U64_PRINTF_ARG(old_listener->global_identifier), + old_listener); + channel_listener_unregister(old_listener); + channel_listener_mark_for_close(old_listener); + channel_listener_free(old_listener); + tor_assert(channel_tls_listener == NULL); + } + + log_debug(LD_CHANNEL, + "Done shutting down TLS channels"); +} + +/** + * Create a new channel around an incoming or_connection_t + */ + +channel_t * +channel_tls_handle_incoming(or_connection_t *orconn) +{ + channel_tls_t *tlschan = tor_malloc_zero(sizeof(*tlschan)); + channel_t *chan = &(tlschan->base_); + + tor_assert(orconn); + tor_assert(!(orconn->chan)); + + channel_tls_common_init(tlschan); + + /* Link the channel and orconn to each other */ + tlschan->conn = orconn; + orconn->chan = tlschan; + + if (is_local_addr(&(TO_CONN(orconn)->addr))) channel_mark_local(chan); + channel_mark_incoming(chan); + + /* Register it */ + channel_register(chan); + + return chan; +} + +/********* + * Casts * + ********/ + +/** + * Cast a channel_tls_t to a channel_t. + */ + +channel_t * +channel_tls_to_base(channel_tls_t *tlschan) +{ + if (!tlschan) return NULL; + + return &(tlschan->base_); +} + +/** + * Cast a channel_t to a channel_tls_t, with appropriate type-checking + * asserts. + */ + +channel_tls_t * +channel_tls_from_base(channel_t *chan) +{ + if (!chan) return NULL; + + tor_assert(chan->magic == TLS_CHAN_MAGIC); + + return (channel_tls_t *)(chan); +} + +/******************************************** + * Method implementations for channel_tls_t * + *******************************************/ + +/** + * Close a channel_tls_t + * + * This implements the close method for channel_tls_t + */ + +static void +channel_tls_close_method(channel_t *chan) +{ + channel_tls_t *tlschan = BASE_CHAN_TO_TLS(chan); + + tor_assert(tlschan); + + if (tlschan->conn) connection_or_close_normally(tlschan->conn, 1); + else { + /* Weird - we'll have to change the state ourselves, I guess */ + log_info(LD_CHANNEL, + "Tried to close channel_tls_t %p with NULL conn", + tlschan); + channel_change_state(chan, CHANNEL_STATE_ERROR); + } +} + +/** + * Describe the transport for a channel_tls_t + * + * This returns the string "TLS channel on connection " to the upper + * layer. + */ + +static const char * +channel_tls_describe_transport_method(channel_t *chan) +{ + static char *buf = NULL; + uint64_t id; + channel_tls_t *tlschan; + const char *rv = NULL; + + tor_assert(chan); + + tlschan = BASE_CHAN_TO_TLS(chan); + + if (tlschan->conn) { + id = TO_CONN(tlschan->conn)->global_identifier; + + if (buf) tor_free(buf); + tor_asprintf(&buf, + "TLS channel (connection " U64_FORMAT ")", + U64_PRINTF_ARG(id)); + + rv = buf; + } else { + rv = "TLS channel (no connection)"; + } + + return rv; +} + +/** + * Free a channel_tls_t + * + * This is called by the generic channel layer when freeing a channel_tls_t; + * this happens either on a channel which has already reached + * CHANNEL_STATE_CLOSED or CHANNEL_STATE_ERROR from channel_run_cleanup() or + * on shutdown from channel_free_all(). In the latter case we might still + * have an orconn active (which connection_free_all() will get to later), + * so we should null out its channel pointer now. + */ + +static void +channel_tls_free_method(channel_t *chan) +{ + channel_tls_t *tlschan = BASE_CHAN_TO_TLS(chan); + + tor_assert(tlschan); + + if (tlschan->conn) { + tlschan->conn->chan = NULL; + tlschan->conn = NULL; + } +} + +/** + * Get the remote address of a channel_tls_t + * + * This implements the get_remote_addr method for channel_tls_t; copy the + * remote endpoint of the channel to addr_out and return 1 (always + * succeeds for this transport). + */ + +static int +channel_tls_get_remote_addr_method(channel_t *chan, tor_addr_t *addr_out) +{ + int rv = 0; + channel_tls_t *tlschan = BASE_CHAN_TO_TLS(chan); + + tor_assert(tlschan); + tor_assert(addr_out); + + if (tlschan->conn) { + tor_addr_copy(addr_out, &(TO_CONN(tlschan->conn)->addr)); + rv = 1; + } else tor_addr_make_unspec(addr_out); + + return rv; +} + +/** + * Get the name of the pluggable transport used by a channel_tls_t. + * + * This implements the get_transport_name for channel_tls_t. If the + * channel uses a pluggable transport, copy its name to + * transport_out and return 0. If the channel did not use a + * pluggable transport, return -1. */ + +static int +channel_tls_get_transport_name_method(channel_t *chan, char **transport_out) +{ + channel_tls_t *tlschan = BASE_CHAN_TO_TLS(chan); + + tor_assert(tlschan); + tor_assert(transport_out); + tor_assert(tlschan->conn); + + if (!tlschan->conn->ext_or_transport) + return -1; + + *transport_out = tor_strdup(tlschan->conn->ext_or_transport); + return 0; +} + +/** + * Get endpoint description of a channel_tls_t + * + * This implements the get_remote_descr method for channel_tls_t; it returns + * a text description of the remote endpoint of the channel suitable for use + * in log messages. The req parameter is 0 for the canonical address or 1 for + * the actual address seen. + */ + +static const char * +channel_tls_get_remote_descr_method(channel_t *chan, int flags) +{ +#define MAX_DESCR_LEN 32 + + static char buf[MAX_DESCR_LEN + 1]; + channel_tls_t *tlschan = BASE_CHAN_TO_TLS(chan); + connection_t *conn; + const char *answer = NULL; + char *addr_str; + + tor_assert(tlschan); + + if (tlschan->conn) { + conn = TO_CONN(tlschan->conn); + switch (flags) { + case 0: + /* Canonical address with port*/ + tor_snprintf(buf, MAX_DESCR_LEN + 1, + "%s:%u", conn->address, conn->port); + answer = buf; + break; + case GRD_FLAG_ORIGINAL: + /* Actual address with port */ + addr_str = tor_dup_addr(&(tlschan->conn->real_addr)); + tor_snprintf(buf, MAX_DESCR_LEN + 1, + "%s:%u", addr_str, conn->port); + tor_free(addr_str); + answer = buf; + break; + case GRD_FLAG_ADDR_ONLY: + /* Canonical address, no port */ + strlcpy(buf, conn->address, sizeof(buf)); + answer = buf; + break; + case GRD_FLAG_ORIGINAL|GRD_FLAG_ADDR_ONLY: + /* Actual address, no port */ + addr_str = tor_dup_addr(&(tlschan->conn->real_addr)); + strlcpy(buf, addr_str, sizeof(buf)); + tor_free(addr_str); + answer = buf; + break; + default: + /* Something's broken in channel.c */ + tor_assert(1); + } + } else { + strlcpy(buf, "(No connection)", sizeof(buf)); + answer = buf; + } + + return answer; +} + +/** + * Tell the upper layer if we have queued writes + * + * This implements the has_queued_writes method for channel_tls t_; it returns + * 1 iff we have queued writes on the outbuf of the underlying or_connection_t. + */ + +static int +channel_tls_has_queued_writes_method(channel_t *chan) +{ + size_t outbuf_len; + channel_tls_t *tlschan = BASE_CHAN_TO_TLS(chan); + + tor_assert(tlschan); + if (!(tlschan->conn)) { + log_info(LD_CHANNEL, + "something called has_queued_writes on a tlschan " + "(%p with ID " U64_FORMAT " but no conn", + chan, U64_PRINTF_ARG(chan->global_identifier)); + } + + outbuf_len = (tlschan->conn != NULL) ? + connection_get_outbuf_len(TO_CONN(tlschan->conn)) : + 0; + + return (outbuf_len > 0); +} + +/** + * Tell the upper layer if we're canonical + * + * This implements the is_canonical method for channel_tls_t; if req is zero, + * it returns whether this is a canonical channel, and if it is one it returns + * whether that can be relied upon. + */ + +static int +channel_tls_is_canonical_method(channel_t *chan, int req) +{ + int answer = 0; + channel_tls_t *tlschan = BASE_CHAN_TO_TLS(chan); + + tor_assert(tlschan); + + if (tlschan->conn) { + switch (req) { + case 0: + answer = tlschan->conn->is_canonical; + break; + case 1: + /* + * Is the is_canonical bit reliable? In protocols version 2 and up + * we get the canonical address from a NETINFO cell, but in older + * versions it might be based on an obsolete descriptor. + */ + answer = (tlschan->conn->link_proto >= 2); + break; + default: + /* This shouldn't happen; channel.c is broken if it does */ + tor_assert(1); + } + } + /* else return 0 for tlschan->conn == NULL */ + + return answer; +} + +/** + * Check if we match an extend_info_t + * + * This implements the matches_extend_info method for channel_tls_t; the upper + * layer wants to know if this channel matches an extend_info_t. + */ + +static int +channel_tls_matches_extend_info_method(channel_t *chan, + extend_info_t *extend_info) +{ + channel_tls_t *tlschan = BASE_CHAN_TO_TLS(chan); + + tor_assert(tlschan); + tor_assert(extend_info); + + /* Never match if we have no conn */ + if (!(tlschan->conn)) { + log_info(LD_CHANNEL, + "something called matches_extend_info on a tlschan " + "(%p with ID " U64_FORMAT " but no conn", + chan, U64_PRINTF_ARG(chan->global_identifier)); + return 0; + } + + return (tor_addr_eq(&(extend_info->addr), + &(TO_CONN(tlschan->conn)->addr)) && + (extend_info->port == TO_CONN(tlschan->conn)->port)); +} + +/** + * Check if we match a target address; return true iff we do. + * + * This implements the matches_target method for channel_tls t_; the upper + * layer wants to know if this channel matches a target address when extending + * a circuit. + */ + +static int +channel_tls_matches_target_method(channel_t *chan, + const tor_addr_t *target) +{ + channel_tls_t *tlschan = BASE_CHAN_TO_TLS(chan); + + tor_assert(tlschan); + tor_assert(target); + + /* Never match if we have no conn */ + if (!(tlschan->conn)) { + log_info(LD_CHANNEL, + "something called matches_target on a tlschan " + "(%p with ID " U64_FORMAT " but no conn", + chan, U64_PRINTF_ARG(chan->global_identifier)); + return 0; + } + + return tor_addr_eq(&(tlschan->conn->real_addr), target); +} + +/** + * Write a cell to a channel_tls_t + * + * This implements the write_cell method for channel_tls_t; given a + * channel_tls_t and a cell_t, transmit the cell_t. + */ + +static int +channel_tls_write_cell_method(channel_t *chan, cell_t *cell) +{ + channel_tls_t *tlschan = BASE_CHAN_TO_TLS(chan); + int written = 0; + + tor_assert(tlschan); + tor_assert(cell); + + if (tlschan->conn) { + connection_or_write_cell_to_buf(cell, tlschan->conn); + ++written; + } else { + log_info(LD_CHANNEL, + "something called write_cell on a tlschan " + "(%p with ID " U64_FORMAT " but no conn", + chan, U64_PRINTF_ARG(chan->global_identifier)); + } + + return written; +} + +/** + * Write a packed cell to a channel_tls_t + * + * This implements the write_packed_cell method for channel_tls_t; given a + * channel_tls_t and a packed_cell_t, transmit the packed_cell_t. + */ + +static int +channel_tls_write_packed_cell_method(channel_t *chan, + packed_cell_t *packed_cell) +{ + channel_tls_t *tlschan = BASE_CHAN_TO_TLS(chan); + size_t cell_network_size = get_cell_network_size(chan->wide_circ_ids); + int written = 0; + + tor_assert(tlschan); + tor_assert(packed_cell); + + if (tlschan->conn) { + connection_write_to_buf(packed_cell->body, cell_network_size, + TO_CONN(tlschan->conn)); + + /* This is where the cell is finished; used to be done from relay.c */ + packed_cell_free(packed_cell); + ++written; + } else { + log_info(LD_CHANNEL, + "something called write_packed_cell on a tlschan " + "(%p with ID " U64_FORMAT " but no conn", + chan, U64_PRINTF_ARG(chan->global_identifier)); + } + + return written; +} + +/** + * Write a variable-length cell to a channel_tls_t + * + * This implements the write_var_cell method for channel_tls_t; given a + * channel_tls_t and a var_cell_t, transmit the var_cell_t. + */ + +static int +channel_tls_write_var_cell_method(channel_t *chan, var_cell_t *var_cell) +{ + channel_tls_t *tlschan = BASE_CHAN_TO_TLS(chan); + int written = 0; + + tor_assert(tlschan); + tor_assert(var_cell); + + if (tlschan->conn) { + connection_or_write_var_cell_to_buf(var_cell, tlschan->conn); + ++written; + } else { + log_info(LD_CHANNEL, + "something called write_var_cell on a tlschan " + "(%p with ID " U64_FORMAT " but no conn", + chan, U64_PRINTF_ARG(chan->global_identifier)); + } + + return written; +} + +/************************************************* + * Method implementations for channel_listener_t * + ************************************************/ + +/** + * Close a channel_listener_t + * + * This implements the close method for channel_listener_t + */ + +static void +channel_tls_listener_close_method(channel_listener_t *chan_l) +{ + tor_assert(chan_l); + + /* + * Listeners we just go ahead and change state through to CLOSED, but + * make sure to check if they're channel_tls_listener to NULL it out. + */ + if (chan_l == channel_tls_listener) + channel_tls_listener = NULL; + + if (!(chan_l->state == CHANNEL_LISTENER_STATE_CLOSING || + chan_l->state == CHANNEL_LISTENER_STATE_CLOSED || + chan_l->state == CHANNEL_LISTENER_STATE_ERROR)) { + channel_listener_change_state(chan_l, CHANNEL_LISTENER_STATE_CLOSING); + } + + if (chan_l->incoming_list) { + SMARTLIST_FOREACH_BEGIN(chan_l->incoming_list, + channel_t *, ichan) { + channel_mark_for_close(ichan); + } SMARTLIST_FOREACH_END(ichan); + + smartlist_free(chan_l->incoming_list); + chan_l->incoming_list = NULL; + } + + if (!(chan_l->state == CHANNEL_LISTENER_STATE_CLOSED || + chan_l->state == CHANNEL_LISTENER_STATE_ERROR)) { + channel_listener_change_state(chan_l, CHANNEL_LISTENER_STATE_CLOSED); + } +} + +/** + * Describe the transport for a channel_listener_t + * + * This returns the string "TLS channel (listening)" to the upper + * layer. + */ + +static const char * +channel_tls_listener_describe_transport_method(channel_listener_t *chan_l) +{ + tor_assert(chan_l); + + return "TLS channel (listening)"; +} + +/******************************************************* + * Functions for handling events on an or_connection_t * + ******************************************************/ + +/** + * Handle an orconn state change + * + * This function will be called by connection_or.c when the or_connection_t + * associated with this channel_tls_t changes state. + */ + +void +channel_tls_handle_state_change_on_orconn(channel_tls_t *chan, + or_connection_t *conn, + uint8_t old_state, + uint8_t state) +{ + channel_t *base_chan; + + tor_assert(chan); + tor_assert(conn); + tor_assert(conn->chan == chan); + tor_assert(chan->conn == conn); + /* -Werror appeasement */ + tor_assert(old_state == old_state); + + base_chan = TLS_CHAN_TO_BASE(chan); + + /* Make sure the base connection state makes sense - shouldn't be error, + * closed or listening. */ + + tor_assert(base_chan->state == CHANNEL_STATE_OPENING || + base_chan->state == CHANNEL_STATE_OPEN || + base_chan->state == CHANNEL_STATE_MAINT || + base_chan->state == CHANNEL_STATE_CLOSING); + + /* Did we just go to state open? */ + if (state == OR_CONN_STATE_OPEN) { + /* + * We can go to CHANNEL_STATE_OPEN from CHANNEL_STATE_OPENING or + * CHANNEL_STATE_MAINT on this. + */ + channel_change_state(base_chan, CHANNEL_STATE_OPEN); + } else { + /* + * Not open, so from CHANNEL_STATE_OPEN we go to CHANNEL_STATE_MAINT, + * otherwise no change. + */ + if (base_chan->state == CHANNEL_STATE_OPEN) { + channel_change_state(base_chan, CHANNEL_STATE_MAINT); + } + } +} + +/** + * Flush cells from a channel_tls_t + * + * Try to flush up to about num_cells cells, and return how many we flushed. + */ + +ssize_t +channel_tls_flush_some_cells(channel_tls_t *chan, ssize_t num_cells) +{ + ssize_t flushed = 0; + + tor_assert(chan); + + if (flushed >= num_cells) goto done; + + /* + * If channel_tls_t ever buffers anything below the channel_t layer, flush + * that first here. + */ + + flushed += channel_flush_some_cells(TLS_CHAN_TO_BASE(chan), + num_cells - flushed); + + /* + * If channel_tls_t ever buffers anything below the channel_t layer, check + * how much we actually got and push it on down here. + */ + + done: + return flushed; +} + +/** + * Check if a channel_tls_t has anything to flush + * + * Return true if there is any more to flush on this channel (cells in queue + * or active circuits). + */ + +int +channel_tls_more_to_flush(channel_tls_t *chan) +{ + tor_assert(chan); + + /* + * If channel_tls_t ever buffers anything below channel_t, the + * check for that should go here first. + */ + + return channel_more_to_flush(TLS_CHAN_TO_BASE(chan)); +} + +#ifdef KEEP_TIMING_STATS + +/** + * Timing states wrapper + * + * This is a wrapper function around the actual function that processes the + * cell that just arrived on chan. Increment *time + * by the number of microseconds used by the call to *func(cell, chan). + */ + +static void +channel_tls_time_process_cell(cell_t *cell, channel_tls_t *chan, int *time, + void (*func)(cell_t *, channel_tls_t *)) +{ + struct timeval start, end; + long time_passed; + + tor_gettimeofday(&start); + + (*func)(cell, chan); + + tor_gettimeofday(&end); + time_passed = tv_udiff(&start, &end) ; + + if (time_passed > 10000) { /* more than 10ms */ + log_debug(LD_OR,"That call just took %ld ms.",time_passed/1000); + } + + if (time_passed < 0) { + log_info(LD_GENERAL,"That call took us back in time!"); + time_passed = 0; + } + + *time += time_passed; +} +#endif + +/** + * Handle an incoming cell on a channel_tls_t + * + * This is called from connection_or.c to handle an arriving cell; it checks + * for cell types specific to the handshake for this transport protocol and + * handles them, and queues all other cells to the channel_t layer, which + * eventually will hand them off to command.c. + */ + +void +channel_tls_handle_cell(cell_t *cell, or_connection_t *conn) +{ + channel_tls_t *chan; + int handshaking; + +#ifdef KEEP_TIMING_STATS +#define PROCESS_CELL(tp, cl, cn) STMT_BEGIN { \ + ++num ## tp; \ + channel_tls_time_process_cell(cl, cn, & tp ## time , \ + channel_tls_process_ ## tp ## _cell); \ + } STMT_END +#else +#define PROCESS_CELL(tp, cl, cn) channel_tls_process_ ## tp ## _cell(cl, cn) +#endif + + tor_assert(cell); + tor_assert(conn); + + chan = conn->chan; + + if (!chan) { + log_warn(LD_CHANNEL, + "Got a cell_t on an OR connection with no channel"); + return; + } + + handshaking = (TO_CONN(conn)->state != OR_CONN_STATE_OPEN); + + if (conn->base_.marked_for_close) + return; + + /* Reject all but VERSIONS and NETINFO when handshaking. */ + /* (VERSIONS should actually be impossible; it's variable-length.) */ + if (handshaking && cell->command != CELL_VERSIONS && + cell->command != CELL_NETINFO) { + log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, + "Received unexpected cell command %d in chan state %s / " + "conn state %s; closing the connection.", + (int)cell->command, + channel_state_to_string(TLS_CHAN_TO_BASE(chan)->state), + conn_state_to_string(CONN_TYPE_OR, TO_CONN(conn)->state)); + connection_or_close_for_error(conn, 0); + return; + } + + if (conn->base_.state == OR_CONN_STATE_OR_HANDSHAKING_V3) + or_handshake_state_record_cell(conn, conn->handshake_state, cell, 1); + + switch (cell->command) { + case CELL_PADDING: + ++stats_n_padding_cells_processed; + /* do nothing */ + break; + case CELL_VERSIONS: + tor_fragile_assert(); + break; + case CELL_NETINFO: + ++stats_n_netinfo_cells_processed; + PROCESS_CELL(netinfo, cell, chan); + break; + case CELL_CREATE: + case CELL_CREATE_FAST: + case CELL_CREATED: + case CELL_CREATED_FAST: + case CELL_RELAY: + case CELL_RELAY_EARLY: + case CELL_DESTROY: + case CELL_CREATE2: + case CELL_CREATED2: + /* + * These are all transport independent and we pass them up through the + * channel_t mechanism. They are ultimately handled in command.c. + */ + channel_queue_cell(TLS_CHAN_TO_BASE(chan), cell); + break; + default: + log_fn(LOG_INFO, LD_PROTOCOL, + "Cell of unknown type (%d) received in channeltls.c. " + "Dropping.", + cell->command); + break; + } +} + +/** + * Handle an incoming variable-length cell on a channel_tls_t + * + * Process a var_cell that was just received on conn. Keep + * internal statistics about how many of each cell we've processed so far + * this second, and the total number of microseconds it took to + * process each type of cell. All the var_cell commands are handshake- + * related and live below the channel_t layer, so no variable-length + * cells ever get delivered in the current implementation, but I've left + * the mechanism in place for future use. + */ + +void +channel_tls_handle_var_cell(var_cell_t *var_cell, or_connection_t *conn) +{ + channel_tls_t *chan; + +#ifdef KEEP_TIMING_STATS + /* how many of each cell have we seen so far this second? needs better + * name. */ + static int num_versions = 0, num_certs = 0; + static time_t current_second = 0; /* from previous calls to time */ + time_t now = time(NULL); + + if (current_second == 0) current_second = now; + if (now > current_second) { /* the second has rolled over */ + /* print stats */ + log_info(LD_OR, + "At end of second: %d versions (%d ms), %d certs (%d ms)", + num_versions, versions_time / ((now - current_second) * 1000), + num_certs, certs_time / ((now - current_second) * 1000)); + + num_versions = num_certs = 0; + versions_time = certs_time = 0; + + /* remember which second it is, for next time */ + current_second = now; + } +#endif + + tor_assert(var_cell); + tor_assert(conn); + + chan = conn->chan; + + if (!chan) { + log_warn(LD_CHANNEL, + "Got a var_cell_t on an OR connection with no channel"); + return; + } + + if (TO_CONN(conn)->marked_for_close) + return; + + switch (TO_CONN(conn)->state) { + case OR_CONN_STATE_OR_HANDSHAKING_V2: + if (var_cell->command != CELL_VERSIONS) { + log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, + "Received a cell with command %d in unexpected " + "orconn state \"%s\" [%d], channel state \"%s\" [%d]; " + "closing the connection.", + (int)(var_cell->command), + conn_state_to_string(CONN_TYPE_OR, TO_CONN(conn)->state), + TO_CONN(conn)->state, + channel_state_to_string(TLS_CHAN_TO_BASE(chan)->state), + (int)(TLS_CHAN_TO_BASE(chan)->state)); + /* + * The code in connection_or.c will tell channel_t to close for + * error; it will go to CHANNEL_STATE_CLOSING, and then to + * CHANNEL_STATE_ERROR when conn is closed. + */ + connection_or_close_for_error(conn, 0); + return; + } + break; + case OR_CONN_STATE_TLS_HANDSHAKING: + /* If we're using bufferevents, it's entirely possible for us to + * notice "hey, data arrived!" before we notice "hey, the handshake + * finished!" And we need to be accepting both at once to handle both + * the v2 and v3 handshakes. */ + + /* fall through */ + case OR_CONN_STATE_TLS_SERVER_RENEGOTIATING: + if (!(command_allowed_before_handshake(var_cell->command))) { + log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, + "Received a cell with command %d in unexpected " + "orconn state \"%s\" [%d], channel state \"%s\" [%d]; " + "closing the connection.", + (int)(var_cell->command), + conn_state_to_string(CONN_TYPE_OR, TO_CONN(conn)->state), + (int)(TO_CONN(conn)->state), + channel_state_to_string(TLS_CHAN_TO_BASE(chan)->state), + (int)(TLS_CHAN_TO_BASE(chan)->state)); + /* see above comment about CHANNEL_STATE_ERROR */ + connection_or_close_for_error(conn, 0); + return; + } else { + if (enter_v3_handshake_with_cell(var_cell, chan) < 0) + return; + } + break; + case OR_CONN_STATE_OR_HANDSHAKING_V3: + if (var_cell->command != CELL_AUTHENTICATE) + or_handshake_state_record_var_cell(conn, conn->handshake_state, + var_cell, 1); + break; /* Everything is allowed */ + case OR_CONN_STATE_OPEN: + if (conn->link_proto < 3) { + log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, + "Received a variable-length cell with command %d in orconn " + "state %s [%d], channel state %s [%d] with link protocol %d; " + "ignoring it.", + (int)(var_cell->command), + conn_state_to_string(CONN_TYPE_OR, TO_CONN(conn)->state), + (int)(TO_CONN(conn)->state), + channel_state_to_string(TLS_CHAN_TO_BASE(chan)->state), + (int)(TLS_CHAN_TO_BASE(chan)->state), + (int)(conn->link_proto)); + return; + } + break; + default: + log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, + "Received var-length cell with command %d in unexpected " + "orconn state \"%s\" [%d], channel state \"%s\" [%d]; " + "ignoring it.", + (int)(var_cell->command), + conn_state_to_string(CONN_TYPE_OR, TO_CONN(conn)->state), + (int)(TO_CONN(conn)->state), + channel_state_to_string(TLS_CHAN_TO_BASE(chan)->state), + (int)(TLS_CHAN_TO_BASE(chan)->state)); + return; + } + + /* Now handle the cell */ + + switch (var_cell->command) { + case CELL_VERSIONS: + ++stats_n_versions_cells_processed; + PROCESS_CELL(versions, var_cell, chan); + break; + case CELL_VPADDING: + ++stats_n_vpadding_cells_processed; + /* Do nothing */ + break; + case CELL_CERTS: + ++stats_n_certs_cells_processed; + PROCESS_CELL(certs, var_cell, chan); + break; + case CELL_AUTH_CHALLENGE: + ++stats_n_auth_challenge_cells_processed; + PROCESS_CELL(auth_challenge, var_cell, chan); + break; + case CELL_AUTHENTICATE: + ++stats_n_authenticate_cells_processed; + PROCESS_CELL(authenticate, var_cell, chan); + break; + case CELL_AUTHORIZE: + ++stats_n_authorize_cells_processed; + /* Ignored so far. */ + break; + default: + log_fn(LOG_INFO, LD_PROTOCOL, + "Variable-length cell of unknown type (%d) received.", + (int)(var_cell->command)); + break; + } +} + +/** + * Check if this cell type is allowed before the handshake is finished + * + * Return true if command is a cell command that's allowed to start a + * V3 handshake. + */ + +static int +command_allowed_before_handshake(uint8_t command) +{ + switch (command) { + case CELL_VERSIONS: + case CELL_VPADDING: + case CELL_AUTHORIZE: + return 1; + default: + return 0; + } +} + +/** + * Start a V3 handshake on an incoming connection + * + * Called when we as a server receive an appropriate cell while waiting + * either for a cell or a TLS handshake. Set the connection's state to + * "handshaking_v3', initializes the or_handshake_state field as needed, + * and add the cell to the hash of incoming cells.) + */ + +static int +enter_v3_handshake_with_cell(var_cell_t *cell, channel_tls_t *chan) +{ + int started_here = 0; + + tor_assert(cell); + tor_assert(chan); + tor_assert(chan->conn); + + started_here = connection_or_nonopen_was_started_here(chan->conn); + + tor_assert(TO_CONN(chan->conn)->state == OR_CONN_STATE_TLS_HANDSHAKING || + TO_CONN(chan->conn)->state == + OR_CONN_STATE_TLS_SERVER_RENEGOTIATING); + + if (started_here) { + log_fn(LOG_PROTOCOL_WARN, LD_OR, + "Received a cell while TLS-handshaking, not in " + "OR_HANDSHAKING_V3, on a connection we originated."); + } + connection_or_block_renegotiation(chan->conn); + chan->conn->base_.state = OR_CONN_STATE_OR_HANDSHAKING_V3; + if (connection_init_or_handshake_state(chan->conn, started_here) < 0) { + connection_or_close_for_error(chan->conn, 0); + return -1; + } + or_handshake_state_record_var_cell(chan->conn, + chan->conn->handshake_state, cell, 1); + return 0; +} + +/** + * Process a 'versions' cell. + * + * This function is called to handle an incoming VERSIONS cell; the current + * link protocol version must be 0 to indicate that no version has yet been + * negotiated. We compare the versions in the cell to the list of versions + * we support, pick the highest version we have in common, and continue the + * negotiation from there. + */ + +static void +channel_tls_process_versions_cell(var_cell_t *cell, channel_tls_t *chan) +{ + int highest_supported_version = 0; + const uint8_t *cp, *end; + int started_here = 0; + + tor_assert(cell); + tor_assert(chan); + tor_assert(chan->conn); + + if ((cell->payload_len % 2) == 1) { + log_fn(LOG_PROTOCOL_WARN, LD_OR, + "Received a VERSION cell with odd payload length %d; " + "closing connection.",cell->payload_len); + connection_or_close_for_error(chan->conn, 0); + return; + } + + started_here = connection_or_nonopen_was_started_here(chan->conn); + + if (chan->conn->link_proto != 0 || + (chan->conn->handshake_state && + chan->conn->handshake_state->received_versions)) { + log_fn(LOG_PROTOCOL_WARN, LD_OR, + "Received a VERSIONS cell on a connection with its version " + "already set to %d; dropping", + (int)(chan->conn->link_proto)); + return; + } + switch (chan->conn->base_.state) + { + case OR_CONN_STATE_OR_HANDSHAKING_V2: + case OR_CONN_STATE_OR_HANDSHAKING_V3: + break; + case OR_CONN_STATE_TLS_HANDSHAKING: + case OR_CONN_STATE_TLS_SERVER_RENEGOTIATING: + default: + log_fn(LOG_PROTOCOL_WARN, LD_OR, + "VERSIONS cell while in unexpected state"); + return; + } + + tor_assert(chan->conn->handshake_state); + end = cell->payload + cell->payload_len; + for (cp = cell->payload; cp+1 < end; cp += 2) { + uint16_t v = ntohs(get_uint16(cp)); + if (is_or_protocol_version_known(v) && v > highest_supported_version) + highest_supported_version = v; + } + if (!highest_supported_version) { + log_fn(LOG_PROTOCOL_WARN, LD_OR, + "Couldn't find a version in common between my version list and the " + "list in the VERSIONS cell; closing connection."); + connection_or_close_for_error(chan->conn, 0); + return; + } else if (highest_supported_version == 1) { + /* Negotiating version 1 makes no sense, since version 1 has no VERSIONS + * cells. */ + log_fn(LOG_PROTOCOL_WARN, LD_OR, + "Used version negotiation protocol to negotiate a v1 connection. " + "That's crazily non-compliant. Closing connection."); + connection_or_close_for_error(chan->conn, 0); + return; + } else if (highest_supported_version < 3 && + chan->conn->base_.state == OR_CONN_STATE_OR_HANDSHAKING_V3) { + log_fn(LOG_PROTOCOL_WARN, LD_OR, + "Negotiated link protocol 2 or lower after doing a v3 TLS " + "handshake. Closing connection."); + connection_or_close_for_error(chan->conn, 0); + return; + } else if (highest_supported_version != 2 && + chan->conn->base_.state == OR_CONN_STATE_OR_HANDSHAKING_V2) { + /* XXXX This should eventually be a log_protocol_warn */ + log_fn(LOG_WARN, LD_OR, + "Negotiated link with non-2 protocol after doing a v2 TLS " + "handshake with %s. Closing connection.", + fmt_addr(&chan->conn->base_.addr)); + connection_or_close_for_error(chan->conn, 0); + return; + } + + chan->conn->link_proto = highest_supported_version; + chan->conn->handshake_state->received_versions = 1; + + if (chan->conn->link_proto == 2) { + log_info(LD_OR, + "Negotiated version %d with %s:%d; sending NETINFO.", + highest_supported_version, + safe_str_client(chan->conn->base_.address), + chan->conn->base_.port); + + if (connection_or_send_netinfo(chan->conn) < 0) { + connection_or_close_for_error(chan->conn, 0); + return; + } + } else { + const int send_versions = !started_here; + /* If we want to authenticate, send a CERTS cell */ + const int send_certs = !started_here || public_server_mode(get_options()); + /* If we're a host that got a connection, ask for authentication. */ + const int send_chall = !started_here; + /* If our certs cell will authenticate us, we can send a netinfo cell + * right now. */ + const int send_netinfo = !started_here; + const int send_any = + send_versions || send_certs || send_chall || send_netinfo; + tor_assert(chan->conn->link_proto >= 3); + + log_info(LD_OR, + "Negotiated version %d with %s:%d; %s%s%s%s%s", + highest_supported_version, + safe_str_client(chan->conn->base_.address), + chan->conn->base_.port, + send_any ? "Sending cells:" : "Waiting for CERTS cell", + send_versions ? " VERSIONS" : "", + send_certs ? " CERTS" : "", + send_chall ? " AUTH_CHALLENGE" : "", + send_netinfo ? " NETINFO" : ""); + +#ifdef DISABLE_V3_LINKPROTO_SERVERSIDE + if (1) { + connection_or_close_normally(chan->conn, 1); + return; + } +#endif + + if (send_versions) { + if (connection_or_send_versions(chan->conn, 1) < 0) { + log_warn(LD_OR, "Couldn't send versions cell"); + connection_or_close_for_error(chan->conn, 0); + return; + } + } + + /* We set this after sending the verions cell. */ + /*XXXXX symbolic const.*/ + chan->base_.wide_circ_ids = + chan->conn->link_proto >= MIN_LINK_PROTO_FOR_WIDE_CIRC_IDS; + chan->conn->wide_circ_ids = chan->base_.wide_circ_ids; + + if (send_certs) { + if (connection_or_send_certs_cell(chan->conn) < 0) { + log_warn(LD_OR, "Couldn't send certs cell"); + connection_or_close_for_error(chan->conn, 0); + return; + } + } + if (send_chall) { + if (connection_or_send_auth_challenge_cell(chan->conn) < 0) { + log_warn(LD_OR, "Couldn't send auth_challenge cell"); + connection_or_close_for_error(chan->conn, 0); + return; + } + } + if (send_netinfo) { + if (connection_or_send_netinfo(chan->conn) < 0) { + log_warn(LD_OR, "Couldn't send netinfo cell"); + connection_or_close_for_error(chan->conn, 0); + return; + } + } + } +} + +/** + * Process a 'netinfo' cell + * + * This function is called to handle an incoming NETINFO cell; read and act + * on its contents, and set the connection state to "open". + */ + +static void +channel_tls_process_netinfo_cell(cell_t *cell, channel_tls_t *chan) +{ + time_t timestamp; + uint8_t my_addr_type; + uint8_t my_addr_len; + const uint8_t *my_addr_ptr; + const uint8_t *cp, *end; + uint8_t n_other_addrs; + time_t now = time(NULL); + + long apparent_skew = 0; + tor_addr_t my_apparent_addr = TOR_ADDR_NULL; + + tor_assert(cell); + tor_assert(chan); + tor_assert(chan->conn); + + if (chan->conn->link_proto < 2) { + log_fn(LOG_PROTOCOL_WARN, LD_OR, + "Received a NETINFO cell on %s connection; dropping.", + chan->conn->link_proto == 0 ? "non-versioned" : "a v1"); + return; + } + if (chan->conn->base_.state != OR_CONN_STATE_OR_HANDSHAKING_V2 && + chan->conn->base_.state != OR_CONN_STATE_OR_HANDSHAKING_V3) { + log_fn(LOG_PROTOCOL_WARN, LD_OR, + "Received a NETINFO cell on non-handshaking connection; dropping."); + return; + } + tor_assert(chan->conn->handshake_state && + chan->conn->handshake_state->received_versions); + + if (chan->conn->base_.state == OR_CONN_STATE_OR_HANDSHAKING_V3) { + tor_assert(chan->conn->link_proto >= 3); + if (chan->conn->handshake_state->started_here) { + if (!(chan->conn->handshake_state->authenticated)) { + log_fn(LOG_PROTOCOL_WARN, LD_OR, + "Got a NETINFO cell from server, " + "but no authentication. Closing the connection."); + connection_or_close_for_error(chan->conn, 0); + return; + } + } else { + /* we're the server. If the client never authenticated, we have + some housekeeping to do.*/ + if (!(chan->conn->handshake_state->authenticated)) { + tor_assert(tor_digest_is_zero( + (const char*)(chan->conn->handshake_state-> + authenticated_peer_id))); + channel_set_circid_type(TLS_CHAN_TO_BASE(chan), NULL, + chan->conn->link_proto < MIN_LINK_PROTO_FOR_WIDE_CIRC_IDS); + + connection_or_init_conn_from_address(chan->conn, + &(chan->conn->base_.addr), + chan->conn->base_.port, + (const char*)(chan->conn->handshake_state-> + authenticated_peer_id), + 0); + } + } + } + + /* Decode the cell. */ + timestamp = ntohl(get_uint32(cell->payload)); + if (labs(now - chan->conn->handshake_state->sent_versions_at) < 180) { + apparent_skew = now - timestamp; + } + + my_addr_type = (uint8_t) cell->payload[4]; + my_addr_len = (uint8_t) cell->payload[5]; + my_addr_ptr = (uint8_t*) cell->payload + 6; + end = cell->payload + CELL_PAYLOAD_SIZE; + cp = cell->payload + 6 + my_addr_len; + + /* We used to check: + * if (my_addr_len >= CELL_PAYLOAD_SIZE - 6) { + * + * This is actually never going to happen, since my_addr_len is at most 255, + * and CELL_PAYLOAD_LEN - 6 is 503. So we know that cp is < end. */ + + if (my_addr_type == RESOLVED_TYPE_IPV4 && my_addr_len == 4) { + tor_addr_from_ipv4n(&my_apparent_addr, get_uint32(my_addr_ptr)); + } else if (my_addr_type == RESOLVED_TYPE_IPV6 && my_addr_len == 16) { + tor_addr_from_ipv6_bytes(&my_apparent_addr, (const char *) my_addr_ptr); + } + + n_other_addrs = (uint8_t) *cp++; + while (n_other_addrs && cp < end-2) { + /* Consider all the other addresses; if any matches, this connection is + * "canonical." */ + tor_addr_t addr; + const uint8_t *next = + decode_address_from_payload(&addr, cp, (int)(end-cp)); + if (next == NULL) { + log_fn(LOG_PROTOCOL_WARN, LD_OR, + "Bad address in netinfo cell; closing connection."); + connection_or_close_for_error(chan->conn, 0); + return; + } + if (tor_addr_eq(&addr, &(chan->conn->real_addr))) { + chan->conn->is_canonical = 1; + break; + } + cp = next; + --n_other_addrs; + } + + /* Act on apparent skew. */ + /** Warn when we get a netinfo skew with at least this value. */ +#define NETINFO_NOTICE_SKEW 3600 + if (labs(apparent_skew) > NETINFO_NOTICE_SKEW && + router_get_by_id_digest(chan->conn->identity_digest)) { + char dbuf[64]; + int severity; + /*XXXX be smarter about when everybody says we are skewed. */ + if (router_digest_is_trusted_dir(chan->conn->identity_digest)) + severity = LOG_WARN; + else + severity = LOG_INFO; + format_time_interval(dbuf, sizeof(dbuf), apparent_skew); + log_fn(severity, LD_GENERAL, + "Received NETINFO cell with skewed time from " + "server at %s:%d. It seems that our clock is %s by %s, or " + "that theirs is %s. Tor requires an accurate clock to work: " + "please check your time and date settings.", + chan->conn->base_.address, + (int)(chan->conn->base_.port), + apparent_skew > 0 ? "ahead" : "behind", + dbuf, + apparent_skew > 0 ? "behind" : "ahead"); + if (severity == LOG_WARN) /* only tell the controller if an authority */ + control_event_general_status(LOG_WARN, + "CLOCK_SKEW SKEW=%ld SOURCE=OR:%s:%d", + apparent_skew, + chan->conn->base_.address, + chan->conn->base_.port); + } + + /* XXX maybe act on my_apparent_addr, if the source is sufficiently + * trustworthy. */ + + if (! chan->conn->handshake_state->sent_netinfo) { + /* If we were prepared to authenticate, but we never got an AUTH_CHALLENGE + * cell, then we would not previously have sent a NETINFO cell. Do so + * now. */ + if (connection_or_send_netinfo(chan->conn) < 0) { + connection_or_close_for_error(chan->conn, 0); + return; + } + } + + if (connection_or_set_state_open(chan->conn) < 0) { + log_fn(LOG_PROTOCOL_WARN, LD_OR, + "Got good NETINFO cell from %s:%d; but " + "was unable to make the OR connection become open.", + safe_str_client(chan->conn->base_.address), + chan->conn->base_.port); + connection_or_close_for_error(chan->conn, 0); + } else { + log_info(LD_OR, + "Got good NETINFO cell from %s:%d; OR connection is now " + "open, using protocol version %d. Its ID digest is %s. " + "Our address is apparently %s.", + safe_str_client(chan->conn->base_.address), + chan->conn->base_.port, + (int)(chan->conn->link_proto), + hex_str(TLS_CHAN_TO_BASE(chan)->identity_digest, + DIGEST_LEN), + tor_addr_is_null(&my_apparent_addr) ? + "" : fmt_and_decorate_addr(&my_apparent_addr)); + } + assert_connection_ok(TO_CONN(chan->conn),time(NULL)); +} + +/** + * Process a CERTS cell from a channel. + * + * This function is called to process an incoming CERTS cell on a + * channel_tls_t: + * + * If the other side should not have sent us a CERTS cell, or the cell is + * malformed, or it is supposed to authenticate the TLS key but it doesn't, + * then mark the connection. + * + * If the cell has a good cert chain and we're doing a v3 handshake, then + * store the certificates in or_handshake_state. If this is the client side + * of the connection, we then authenticate the server or mark the connection. + * If it's the server side, wait for an AUTHENTICATE cell. + */ + +static void +channel_tls_process_certs_cell(var_cell_t *cell, channel_tls_t *chan) +{ + tor_cert_t *link_cert = NULL; + tor_cert_t *id_cert = NULL; + tor_cert_t *auth_cert = NULL; + uint8_t *ptr; + int n_certs, i; + int send_netinfo = 0; + + tor_assert(cell); + tor_assert(chan); + tor_assert(chan->conn); + +#define ERR(s) \ + do { \ + log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, \ + "Received a bad CERTS cell from %s:%d: %s", \ + safe_str(chan->conn->base_.address), \ + chan->conn->base_.port, (s)); \ + connection_or_close_for_error(chan->conn, 0); \ + goto err; \ + } while (0) + + if (chan->conn->base_.state != OR_CONN_STATE_OR_HANDSHAKING_V3) + ERR("We're not doing a v3 handshake!"); + if (chan->conn->link_proto < 3) + ERR("We're not using link protocol >= 3"); + if (chan->conn->handshake_state->received_certs_cell) + ERR("We already got one"); + if (chan->conn->handshake_state->authenticated) { + /* Should be unreachable, but let's make sure. */ + ERR("We're already authenticated!"); + } + if (cell->payload_len < 1) + ERR("It had no body"); + if (cell->circ_id) + ERR("It had a nonzero circuit ID"); + + n_certs = cell->payload[0]; + ptr = cell->payload + 1; + for (i = 0; i < n_certs; ++i) { + uint8_t cert_type; + uint16_t cert_len; + if (ptr + 3 > cell->payload + cell->payload_len) { + goto truncated; + } + cert_type = *ptr; + cert_len = ntohs(get_uint16(ptr+1)); + if (ptr + 3 + cert_len > cell->payload + cell->payload_len) { + goto truncated; + } + if (cert_type == OR_CERT_TYPE_TLS_LINK || + cert_type == OR_CERT_TYPE_ID_1024 || + cert_type == OR_CERT_TYPE_AUTH_1024) { + tor_cert_t *cert = tor_cert_decode(ptr + 3, cert_len); + if (!cert) { + log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, + "Received undecodable certificate in CERTS cell from %s:%d", + safe_str(chan->conn->base_.address), + chan->conn->base_.port); + } else { + if (cert_type == OR_CERT_TYPE_TLS_LINK) { + if (link_cert) { + tor_cert_free(cert); + ERR("Too many TLS_LINK certificates"); + } + link_cert = cert; + } else if (cert_type == OR_CERT_TYPE_ID_1024) { + if (id_cert) { + tor_cert_free(cert); + ERR("Too many ID_1024 certificates"); + } + id_cert = cert; + } else if (cert_type == OR_CERT_TYPE_AUTH_1024) { + if (auth_cert) { + tor_cert_free(cert); + ERR("Too many AUTH_1024 certificates"); + } + auth_cert = cert; + } else { + tor_cert_free(cert); + } + } + } + ptr += 3 + cert_len; + continue; + + truncated: + ERR("It ends in the middle of a certificate"); + } + + if (chan->conn->handshake_state->started_here) { + int severity; + if (! (id_cert && link_cert)) + ERR("The certs we wanted were missing"); + /* Okay. We should be able to check the certificates now. */ + if (! tor_tls_cert_matches_key(chan->conn->tls, link_cert)) { + ERR("The link certificate didn't match the TLS public key"); + } + /* Note that this warns more loudly about time and validity if we were + * _trying_ to connect to an authority, not necessarily if we _did_ connect + * to one. */ + if (router_digest_is_trusted_dir( + TLS_CHAN_TO_BASE(chan)->identity_digest)) + severity = LOG_WARN; + else + severity = LOG_PROTOCOL_WARN; + + if (! tor_tls_cert_is_valid(severity, link_cert, id_cert, 0)) + ERR("The link certificate was not valid"); + if (! tor_tls_cert_is_valid(severity, id_cert, id_cert, 1)) + ERR("The ID certificate was not valid"); + + chan->conn->handshake_state->authenticated = 1; + { + const digests_t *id_digests = tor_cert_get_id_digests(id_cert); + crypto_pk_t *identity_rcvd; + if (!id_digests) + ERR("Couldn't compute digests for key in ID cert"); + + identity_rcvd = tor_tls_cert_get_key(id_cert); + if (!identity_rcvd) + ERR("Internal error: Couldn't get RSA key from ID cert."); + memcpy(chan->conn->handshake_state->authenticated_peer_id, + id_digests->d[DIGEST_SHA1], DIGEST_LEN); + channel_set_circid_type(TLS_CHAN_TO_BASE(chan), identity_rcvd, + chan->conn->link_proto < MIN_LINK_PROTO_FOR_WIDE_CIRC_IDS); + crypto_pk_free(identity_rcvd); + } + + if (connection_or_client_learned_peer_id(chan->conn, + chan->conn->handshake_state->authenticated_peer_id) < 0) + ERR("Problem setting or checking peer id"); + + log_info(LD_OR, + "Got some good certificates from %s:%d: Authenticated it.", + safe_str(chan->conn->base_.address), chan->conn->base_.port); + + chan->conn->handshake_state->id_cert = id_cert; + id_cert = NULL; + + if (!public_server_mode(get_options())) { + /* If we initiated the connection and we are not a public server, we + * aren't planning to authenticate at all. At this point we know who we + * are talking to, so we can just send a netinfo now. */ + send_netinfo = 1; + } + } else { + if (! (id_cert && auth_cert)) + ERR("The certs we wanted were missing"); + + /* Remember these certificates so we can check an AUTHENTICATE cell */ + if (! tor_tls_cert_is_valid(LOG_PROTOCOL_WARN, auth_cert, id_cert, 1)) + ERR("The authentication certificate was not valid"); + if (! tor_tls_cert_is_valid(LOG_PROTOCOL_WARN, id_cert, id_cert, 1)) + ERR("The ID certificate was not valid"); + + log_info(LD_OR, + "Got some good certificates from %s:%d: " + "Waiting for AUTHENTICATE.", + safe_str(chan->conn->base_.address), + chan->conn->base_.port); + /* XXXX check more stuff? */ + + chan->conn->handshake_state->id_cert = id_cert; + chan->conn->handshake_state->auth_cert = auth_cert; + id_cert = auth_cert = NULL; + } + + chan->conn->handshake_state->received_certs_cell = 1; + + if (send_netinfo) { + if (connection_or_send_netinfo(chan->conn) < 0) { + log_warn(LD_OR, "Couldn't send netinfo cell"); + connection_or_close_for_error(chan->conn, 0); + goto err; + } + } + + err: + tor_cert_free(id_cert); + tor_cert_free(link_cert); + tor_cert_free(auth_cert); +#undef ERR +} + +/** + * Process an AUTH_CHALLENGE cell from a channel_tls_t + * + * This function is called to handle an incoming AUTH_CHALLENGE cell on a + * channel_tls_t; if we weren't supposed to get one (for example, because we're + * not the originator of the channel), or it's ill-formed, or we aren't doing + * a v3 handshake, mark the channel. If the cell is well-formed but we don't + * want to authenticate, just drop it. If the cell is well-formed *and* we + * want to authenticate, send an AUTHENTICATE cell and then a NETINFO cell. + */ + +static void +channel_tls_process_auth_challenge_cell(var_cell_t *cell, channel_tls_t *chan) +{ + int n_types, i, use_type = -1; + uint8_t *cp; + + tor_assert(cell); + tor_assert(chan); + tor_assert(chan->conn); + +#define ERR(s) \ + do { \ + log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, \ + "Received a bad AUTH_CHALLENGE cell from %s:%d: %s", \ + safe_str(chan->conn->base_.address), \ + chan->conn->base_.port, (s)); \ + connection_or_close_for_error(chan->conn, 0); \ + return; \ + } while (0) + + if (chan->conn->base_.state != OR_CONN_STATE_OR_HANDSHAKING_V3) + ERR("We're not currently doing a v3 handshake"); + if (chan->conn->link_proto < 3) + ERR("We're not using link protocol >= 3"); + if (!(chan->conn->handshake_state->started_here)) + ERR("We didn't originate this connection"); + if (chan->conn->handshake_state->received_auth_challenge) + ERR("We already received one"); + if (!(chan->conn->handshake_state->received_certs_cell)) + ERR("We haven't gotten a CERTS cell yet"); + if (cell->payload_len < OR_AUTH_CHALLENGE_LEN + 2) + ERR("It was too short"); + if (cell->circ_id) + ERR("It had a nonzero circuit ID"); + + n_types = ntohs(get_uint16(cell->payload + OR_AUTH_CHALLENGE_LEN)); + if (cell->payload_len < OR_AUTH_CHALLENGE_LEN + 2 + 2*n_types) + ERR("It looks truncated"); + + /* Now see if there is an authentication type we can use */ + cp = cell->payload+OR_AUTH_CHALLENGE_LEN + 2; + for (i = 0; i < n_types; ++i, cp += 2) { + uint16_t authtype = ntohs(get_uint16(cp)); + if (authtype == AUTHTYPE_RSA_SHA256_TLSSECRET) + use_type = authtype; + } + + chan->conn->handshake_state->received_auth_challenge = 1; + + if (! public_server_mode(get_options())) { + /* If we're not a public server then we don't want to authenticate on a + connection we originated, and we already sent a NETINFO cell when we + got the CERTS cell. We have nothing more to do. */ + return; + } + + if (use_type >= 0) { + log_info(LD_OR, + "Got an AUTH_CHALLENGE cell from %s:%d: Sending " + "authentication", + safe_str(chan->conn->base_.address), + chan->conn->base_.port); + + if (connection_or_send_authenticate_cell(chan->conn, use_type) < 0) { + log_warn(LD_OR, + "Couldn't send authenticate cell"); + connection_or_close_for_error(chan->conn, 0); + return; + } + } else { + log_info(LD_OR, + "Got an AUTH_CHALLENGE cell from %s:%d, but we don't " + "know any of its authentication types. Not authenticating.", + safe_str(chan->conn->base_.address), + chan->conn->base_.port); + } + + if (connection_or_send_netinfo(chan->conn) < 0) { + log_warn(LD_OR, "Couldn't send netinfo cell"); + connection_or_close_for_error(chan->conn, 0); + return; + } + +#undef ERR +} + +/** + * Process an AUTHENTICATE cell from a channel_tls_t + * + * If it's ill-formed or we weren't supposed to get one or we're not doing a + * v3 handshake, then mark the connection. If it does not authenticate the + * other side of the connection successfully (because it isn't signed right, + * we didn't get a CERTS cell, etc) mark the connection. Otherwise, accept + * the identity of the router on the other side of the connection. + */ + +static void +channel_tls_process_authenticate_cell(var_cell_t *cell, channel_tls_t *chan) +{ + uint8_t expected[V3_AUTH_FIXED_PART_LEN]; + const uint8_t *auth; + int authlen; + + tor_assert(cell); + tor_assert(chan); + tor_assert(chan->conn); + +#define ERR(s) \ + do { \ + log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, \ + "Received a bad AUTHENTICATE cell from %s:%d: %s", \ + safe_str(chan->conn->base_.address), \ + chan->conn->base_.port, (s)); \ + connection_or_close_for_error(chan->conn, 0); \ + return; \ + } while (0) + + if (chan->conn->base_.state != OR_CONN_STATE_OR_HANDSHAKING_V3) + ERR("We're not doing a v3 handshake"); + if (chan->conn->link_proto < 3) + ERR("We're not using link protocol >= 3"); + if (chan->conn->handshake_state->started_here) + ERR("We originated this connection"); + if (chan->conn->handshake_state->received_authenticate) + ERR("We already got one!"); + if (chan->conn->handshake_state->authenticated) { + /* Should be impossible given other checks */ + ERR("The peer is already authenticated"); + } + if (!(chan->conn->handshake_state->received_certs_cell)) + ERR("We never got a certs cell"); + if (chan->conn->handshake_state->auth_cert == NULL) + ERR("We never got an authentication certificate"); + if (chan->conn->handshake_state->id_cert == NULL) + ERR("We never got an identity certificate"); + if (cell->payload_len < 4) + ERR("Cell was way too short"); + + auth = cell->payload; + { + uint16_t type = ntohs(get_uint16(auth)); + uint16_t len = ntohs(get_uint16(auth+2)); + if (4 + len > cell->payload_len) + ERR("Authenticator was truncated"); + + if (type != AUTHTYPE_RSA_SHA256_TLSSECRET) + ERR("Authenticator type was not recognized"); + + auth += 4; + authlen = len; + } + + if (authlen < V3_AUTH_BODY_LEN + 1) + ERR("Authenticator was too short"); + + if (connection_or_compute_authenticate_cell_body( + chan->conn, expected, sizeof(expected), NULL, 1) < 0) + ERR("Couldn't compute expected AUTHENTICATE cell body"); + + if (tor_memneq(expected, auth, sizeof(expected))) + ERR("Some field in the AUTHENTICATE cell body was not as expected"); + + { + crypto_pk_t *pk = tor_tls_cert_get_key( + chan->conn->handshake_state->auth_cert); + char d[DIGEST256_LEN]; + char *signed_data; + size_t keysize; + int signed_len; + + if (!pk) + ERR("Internal error: couldn't get RSA key from AUTH cert."); + crypto_digest256(d, (char*)auth, V3_AUTH_BODY_LEN, DIGEST_SHA256); + + keysize = crypto_pk_keysize(pk); + signed_data = tor_malloc(keysize); + signed_len = crypto_pk_public_checksig(pk, signed_data, keysize, + (char*)auth + V3_AUTH_BODY_LEN, + authlen - V3_AUTH_BODY_LEN); + crypto_pk_free(pk); + if (signed_len < 0) { + tor_free(signed_data); + ERR("Signature wasn't valid"); + } + if (signed_len < DIGEST256_LEN) { + tor_free(signed_data); + ERR("Not enough data was signed"); + } + /* Note that we deliberately allow *more* than DIGEST256_LEN bytes here, + * in case they're later used to hold a SHA3 digest or something. */ + if (tor_memneq(signed_data, d, DIGEST256_LEN)) { + tor_free(signed_data); + ERR("Signature did not match data to be signed."); + } + tor_free(signed_data); + } + + /* Okay, we are authenticated. */ + chan->conn->handshake_state->received_authenticate = 1; + chan->conn->handshake_state->authenticated = 1; + chan->conn->handshake_state->digest_received_data = 0; + { + crypto_pk_t *identity_rcvd = + tor_tls_cert_get_key(chan->conn->handshake_state->id_cert); + const digests_t *id_digests = + tor_cert_get_id_digests(chan->conn->handshake_state->id_cert); + + /* This must exist; we checked key type when reading the cert. */ + tor_assert(id_digests); + + memcpy(chan->conn->handshake_state->authenticated_peer_id, + id_digests->d[DIGEST_SHA1], DIGEST_LEN); + + channel_set_circid_type(TLS_CHAN_TO_BASE(chan), identity_rcvd, + chan->conn->link_proto < MIN_LINK_PROTO_FOR_WIDE_CIRC_IDS); + crypto_pk_free(identity_rcvd); + + connection_or_init_conn_from_address(chan->conn, + &(chan->conn->base_.addr), + chan->conn->base_.port, + (const char*)(chan->conn->handshake_state-> + authenticated_peer_id), + 0); + + log_info(LD_OR, + "Got an AUTHENTICATE cell from %s:%d: Looks good.", + safe_str(chan->conn->base_.address), + chan->conn->base_.port); + } + +#undef ERR +} + diff --git a/src/tor/channeltls.h b/src/tor/channeltls.h new file mode 100644 index 0000000..b4a7e2b --- /dev/null +++ b/src/tor/channeltls.h @@ -0,0 +1,57 @@ +/* * Copyright (c) 2012-2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file channeltls.h + * \brief Header file for channeltls.c + **/ + +#ifndef TOR_CHANNELTLS_H +#define TOR_CHANNELTLS_H + +#include "or.h" +#include "channel.h" + +#define BASE_CHAN_TO_TLS(c) (channel_tls_from_base((c))) +#define TLS_CHAN_TO_BASE(c) (channel_tls_to_base((c))) + +#define TLS_CHAN_MAGIC 0x8a192427U + +#ifdef TOR_CHANNEL_INTERNAL_ + +struct channel_tls_s { + /* Base channel_t struct */ + channel_t base_; + /* or_connection_t pointer */ + or_connection_t *conn; +}; + +#endif /* TOR_CHANNEL_INTERNAL_ */ + +channel_t * channel_tls_connect(const tor_addr_t *addr, uint16_t port, + const char *id_digest); +channel_listener_t * channel_tls_get_listener(void); +channel_listener_t * channel_tls_start_listener(void); +channel_t * channel_tls_handle_incoming(or_connection_t *orconn); + +/* Casts */ + +channel_t * channel_tls_to_base(channel_tls_t *tlschan); +channel_tls_t * channel_tls_from_base(channel_t *chan); + +/* Things for connection_or.c to call back into */ +ssize_t channel_tls_flush_some_cells(channel_tls_t *chan, ssize_t num_cells); +int channel_tls_more_to_flush(channel_tls_t *chan); +void channel_tls_handle_cell(cell_t *cell, or_connection_t *conn); +void channel_tls_handle_state_change_on_orconn(channel_tls_t *chan, + or_connection_t *conn, + uint8_t old_state, + uint8_t state); +void channel_tls_handle_var_cell(var_cell_t *var_cell, + or_connection_t *conn); + +/* Cleanup at shutdown */ +void channel_tls_free_all(void); + +#endif + diff --git a/src/tor/ciphers.inc b/src/tor/ciphers.inc new file mode 100644 index 0000000..137d78b --- /dev/null +++ b/src/tor/ciphers.inc @@ -0,0 +1,182 @@ +/* This is an include file used to define the list of ciphers clients should + * advertise. Before including it, you should define the CIPHER and XCIPHER + * macros. + * + * This file was automatically generated by get_mozilla_ciphers.py. + */ +#ifdef TLS1_TXT_ECDHE_ECDSA_WITH_AES_256_CBC_SHA + CIPHER(0xc00a, TLS1_TXT_ECDHE_ECDSA_WITH_AES_256_CBC_SHA) +#else + XCIPHER(0xc00a, TLS1_TXT_ECDHE_ECDSA_WITH_AES_256_CBC_SHA) +#endif +#ifdef TLS1_TXT_ECDHE_RSA_WITH_AES_256_CBC_SHA + CIPHER(0xc014, TLS1_TXT_ECDHE_RSA_WITH_AES_256_CBC_SHA) +#else + XCIPHER(0xc014, TLS1_TXT_ECDHE_RSA_WITH_AES_256_CBC_SHA) +#endif +#ifdef TLS1_TXT_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA + CIPHER(0x0088, TLS1_TXT_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA) +#else + XCIPHER(0x0088, TLS1_TXT_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA) +#endif +#ifdef TLS1_TXT_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA + CIPHER(0x0087, TLS1_TXT_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA) +#else + XCIPHER(0x0087, TLS1_TXT_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA) +#endif +#ifdef TLS1_TXT_DHE_RSA_WITH_AES_256_SHA + CIPHER(0x0039, TLS1_TXT_DHE_RSA_WITH_AES_256_SHA) +#else + XCIPHER(0x0039, TLS1_TXT_DHE_RSA_WITH_AES_256_SHA) +#endif +#ifdef TLS1_TXT_DHE_DSS_WITH_AES_256_SHA + CIPHER(0x0038, TLS1_TXT_DHE_DSS_WITH_AES_256_SHA) +#else + XCIPHER(0x0038, TLS1_TXT_DHE_DSS_WITH_AES_256_SHA) +#endif +#ifdef TLS1_TXT_ECDH_RSA_WITH_AES_256_CBC_SHA + CIPHER(0xc00f, TLS1_TXT_ECDH_RSA_WITH_AES_256_CBC_SHA) +#else + XCIPHER(0xc00f, TLS1_TXT_ECDH_RSA_WITH_AES_256_CBC_SHA) +#endif +#ifdef TLS1_TXT_ECDH_ECDSA_WITH_AES_256_CBC_SHA + CIPHER(0xc005, TLS1_TXT_ECDH_ECDSA_WITH_AES_256_CBC_SHA) +#else + XCIPHER(0xc005, TLS1_TXT_ECDH_ECDSA_WITH_AES_256_CBC_SHA) +#endif +#ifdef TLS1_TXT_RSA_WITH_CAMELLIA_256_CBC_SHA + CIPHER(0x0084, TLS1_TXT_RSA_WITH_CAMELLIA_256_CBC_SHA) +#else + XCIPHER(0x0084, TLS1_TXT_RSA_WITH_CAMELLIA_256_CBC_SHA) +#endif +#ifdef TLS1_TXT_RSA_WITH_AES_256_SHA + CIPHER(0x0035, TLS1_TXT_RSA_WITH_AES_256_SHA) +#else + XCIPHER(0x0035, TLS1_TXT_RSA_WITH_AES_256_SHA) +#endif +#ifdef TLS1_TXT_ECDHE_ECDSA_WITH_RC4_128_SHA + CIPHER(0xc007, TLS1_TXT_ECDHE_ECDSA_WITH_RC4_128_SHA) +#else + XCIPHER(0xc007, TLS1_TXT_ECDHE_ECDSA_WITH_RC4_128_SHA) +#endif +#ifdef TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_CBC_SHA + CIPHER(0xc009, TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_CBC_SHA) +#else + XCIPHER(0xc009, TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_CBC_SHA) +#endif +#ifdef TLS1_TXT_ECDHE_RSA_WITH_RC4_128_SHA + CIPHER(0xc011, TLS1_TXT_ECDHE_RSA_WITH_RC4_128_SHA) +#else + XCIPHER(0xc011, TLS1_TXT_ECDHE_RSA_WITH_RC4_128_SHA) +#endif +#ifdef TLS1_TXT_ECDHE_RSA_WITH_AES_128_CBC_SHA + CIPHER(0xc013, TLS1_TXT_ECDHE_RSA_WITH_AES_128_CBC_SHA) +#else + XCIPHER(0xc013, TLS1_TXT_ECDHE_RSA_WITH_AES_128_CBC_SHA) +#endif +#ifdef TLS1_TXT_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA + CIPHER(0x0045, TLS1_TXT_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA) +#else + XCIPHER(0x0045, TLS1_TXT_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA) +#endif +#ifdef TLS1_TXT_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA + CIPHER(0x0044, TLS1_TXT_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA) +#else + XCIPHER(0x0044, TLS1_TXT_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA) +#endif +#ifdef TLS1_TXT_DHE_RSA_WITH_AES_128_SHA + CIPHER(0x0033, TLS1_TXT_DHE_RSA_WITH_AES_128_SHA) +#else + XCIPHER(0x0033, TLS1_TXT_DHE_RSA_WITH_AES_128_SHA) +#endif +#ifdef TLS1_TXT_DHE_DSS_WITH_AES_128_SHA + CIPHER(0x0032, TLS1_TXT_DHE_DSS_WITH_AES_128_SHA) +#else + XCIPHER(0x0032, TLS1_TXT_DHE_DSS_WITH_AES_128_SHA) +#endif +#ifdef TLS1_TXT_ECDH_RSA_WITH_RC4_128_SHA + CIPHER(0xc00c, TLS1_TXT_ECDH_RSA_WITH_RC4_128_SHA) +#else + XCIPHER(0xc00c, TLS1_TXT_ECDH_RSA_WITH_RC4_128_SHA) +#endif +#ifdef TLS1_TXT_ECDH_RSA_WITH_AES_128_CBC_SHA + CIPHER(0xc00e, TLS1_TXT_ECDH_RSA_WITH_AES_128_CBC_SHA) +#else + XCIPHER(0xc00e, TLS1_TXT_ECDH_RSA_WITH_AES_128_CBC_SHA) +#endif +#ifdef TLS1_TXT_ECDH_ECDSA_WITH_RC4_128_SHA + CIPHER(0xc002, TLS1_TXT_ECDH_ECDSA_WITH_RC4_128_SHA) +#else + XCIPHER(0xc002, TLS1_TXT_ECDH_ECDSA_WITH_RC4_128_SHA) +#endif +#ifdef TLS1_TXT_ECDH_ECDSA_WITH_AES_128_CBC_SHA + CIPHER(0xc004, TLS1_TXT_ECDH_ECDSA_WITH_AES_128_CBC_SHA) +#else + XCIPHER(0xc004, TLS1_TXT_ECDH_ECDSA_WITH_AES_128_CBC_SHA) +#endif +#ifdef TLS1_TXT_RSA_WITH_SEED_SHA + CIPHER(0x0096, TLS1_TXT_RSA_WITH_SEED_SHA) +#else + XCIPHER(0x0096, TLS1_TXT_RSA_WITH_SEED_SHA) +#endif +#ifdef TLS1_TXT_RSA_WITH_CAMELLIA_128_CBC_SHA + CIPHER(0x0041, TLS1_TXT_RSA_WITH_CAMELLIA_128_CBC_SHA) +#else + XCIPHER(0x0041, TLS1_TXT_RSA_WITH_CAMELLIA_128_CBC_SHA) +#endif +#ifdef SSL3_TXT_RSA_RC4_128_MD5 + CIPHER(0x0004, SSL3_TXT_RSA_RC4_128_MD5) +#else + XCIPHER(0x0004, SSL3_TXT_RSA_RC4_128_MD5) +#endif +#ifdef SSL3_TXT_RSA_RC4_128_SHA + CIPHER(0x0005, SSL3_TXT_RSA_RC4_128_SHA) +#else + XCIPHER(0x0005, SSL3_TXT_RSA_RC4_128_SHA) +#endif +#ifdef TLS1_TXT_RSA_WITH_AES_128_SHA + CIPHER(0x002f, TLS1_TXT_RSA_WITH_AES_128_SHA) +#else + XCIPHER(0x002f, TLS1_TXT_RSA_WITH_AES_128_SHA) +#endif +#ifdef TLS1_TXT_ECDHE_ECDSA_WITH_DES_192_CBC3_SHA + CIPHER(0xc008, TLS1_TXT_ECDHE_ECDSA_WITH_DES_192_CBC3_SHA) +#else + XCIPHER(0xc008, TLS1_TXT_ECDHE_ECDSA_WITH_DES_192_CBC3_SHA) +#endif +#ifdef TLS1_TXT_ECDHE_RSA_WITH_DES_192_CBC3_SHA + CIPHER(0xc012, TLS1_TXT_ECDHE_RSA_WITH_DES_192_CBC3_SHA) +#else + XCIPHER(0xc012, TLS1_TXT_ECDHE_RSA_WITH_DES_192_CBC3_SHA) +#endif +#ifdef SSL3_TXT_EDH_RSA_DES_192_CBC3_SHA + CIPHER(0x0016, SSL3_TXT_EDH_RSA_DES_192_CBC3_SHA) +#else + XCIPHER(0x0016, SSL3_TXT_EDH_RSA_DES_192_CBC3_SHA) +#endif +#ifdef SSL3_TXT_EDH_DSS_DES_192_CBC3_SHA + CIPHER(0x0013, SSL3_TXT_EDH_DSS_DES_192_CBC3_SHA) +#else + XCIPHER(0x0013, SSL3_TXT_EDH_DSS_DES_192_CBC3_SHA) +#endif +#ifdef TLS1_TXT_ECDH_RSA_WITH_DES_192_CBC3_SHA + CIPHER(0xc00d, TLS1_TXT_ECDH_RSA_WITH_DES_192_CBC3_SHA) +#else + XCIPHER(0xc00d, TLS1_TXT_ECDH_RSA_WITH_DES_192_CBC3_SHA) +#endif +#ifdef TLS1_TXT_ECDH_ECDSA_WITH_DES_192_CBC3_SHA + CIPHER(0xc003, TLS1_TXT_ECDH_ECDSA_WITH_DES_192_CBC3_SHA) +#else + XCIPHER(0xc003, TLS1_TXT_ECDH_ECDSA_WITH_DES_192_CBC3_SHA) +#endif +/* No openssl macro found for 0xfeff */ +#ifdef SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA + CIPHER(0xfeff, SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA) +#else + XCIPHER(0xfeff, SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA) +#endif +#ifdef SSL3_TXT_RSA_DES_192_CBC3_SHA + CIPHER(0x000a, SSL3_TXT_RSA_DES_192_CBC3_SHA) +#else + XCIPHER(0x000a, SSL3_TXT_RSA_DES_192_CBC3_SHA) +#endif diff --git a/src/tor/circpathbias.c b/src/tor/circpathbias.c new file mode 100644 index 0000000..51a75cf --- /dev/null +++ b/src/tor/circpathbias.c @@ -0,0 +1,1538 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#include "or.h" +#include "channel.h" +#include "circpathbias.h" +#include "circuitbuild.h" +#include "circuitlist.h" +#include "circuituse.h" +#include "circuitstats.h" +#include "connection_edge.h" +#include "config.h" +#include "entrynodes.h" +#include "networkstatus.h" +#include "relay.h" + +static void pathbias_count_successful_close(origin_circuit_t *circ); +static void pathbias_count_collapse(origin_circuit_t *circ); +static void pathbias_count_use_failed(origin_circuit_t *circ); +static void pathbias_measure_use_rate(entry_guard_t *guard); +static void pathbias_measure_close_rate(entry_guard_t *guard); +static void pathbias_scale_use_rates(entry_guard_t *guard); +static void pathbias_scale_close_rates(entry_guard_t *guard); +static int entry_guard_inc_circ_attempt_count(entry_guard_t *guard); + +/** Increment the number of times we successfully extended a circuit to + * guard, first checking if the failure rate is high enough that + * we should eliminate the guard. Return -1 if the guard looks no good; + * return 0 if the guard looks fine. + */ +static int +entry_guard_inc_circ_attempt_count(entry_guard_t *guard) +{ + entry_guards_changed(); + + pathbias_measure_close_rate(guard); + + if (guard->path_bias_disabled) + return -1; + + pathbias_scale_close_rates(guard); + guard->circ_attempts++; + + log_info(LD_CIRC, "Got success count %f/%f for guard %s ($%s)", + guard->circ_successes, guard->circ_attempts, guard->nickname, + hex_str(guard->identity, DIGEST_LEN)); + return 0; +} + +/** The minimum number of circuit attempts before we start + * thinking about warning about path bias and dropping guards */ +static int +pathbias_get_min_circs(const or_options_t *options) +{ +#define DFLT_PATH_BIAS_MIN_CIRC 150 + if (options->PathBiasCircThreshold >= 5) + return options->PathBiasCircThreshold; + else + return networkstatus_get_param(NULL, "pb_mincircs", + DFLT_PATH_BIAS_MIN_CIRC, + 5, INT32_MAX); +} + +/** The circuit success rate below which we issue a notice */ +static double +pathbias_get_notice_rate(const or_options_t *options) +{ +#define DFLT_PATH_BIAS_NOTICE_PCT 70 + if (options->PathBiasNoticeRate >= 0.0) + return options->PathBiasNoticeRate; + else + return networkstatus_get_param(NULL, "pb_noticepct", + DFLT_PATH_BIAS_NOTICE_PCT, 0, 100)/100.0; +} + +/* XXXX024 I'd like to have this be static again, but entrynodes.c needs it. */ +/** The circuit success rate below which we issue a warn */ +static double +pathbias_get_warn_rate(const or_options_t *options) +{ +#define DFLT_PATH_BIAS_WARN_PCT 50 + if (options->PathBiasWarnRate >= 0.0) + return options->PathBiasWarnRate; + else + return networkstatus_get_param(NULL, "pb_warnpct", + DFLT_PATH_BIAS_WARN_PCT, 0, 100)/100.0; +} + +/* XXXX024 I'd like to have this be static again, but entrynodes.c needs it. */ +/** + * The extreme rate is the rate at which we would drop the guard, + * if pb_dropguard is also set. Otherwise we just warn. + */ +double +pathbias_get_extreme_rate(const or_options_t *options) +{ +#define DFLT_PATH_BIAS_EXTREME_PCT 30 + if (options->PathBiasExtremeRate >= 0.0) + return options->PathBiasExtremeRate; + else + return networkstatus_get_param(NULL, "pb_extremepct", + DFLT_PATH_BIAS_EXTREME_PCT, 0, 100)/100.0; +} + +/* XXXX024 I'd like to have this be static again, but entrynodes.c needs it. */ +/** + * If 1, we actually disable use of guards that fall below + * the extreme_pct. + */ +int +pathbias_get_dropguards(const or_options_t *options) +{ +#define DFLT_PATH_BIAS_DROP_GUARDS 0 + if (options->PathBiasDropGuards >= 0) + return options->PathBiasDropGuards; + else + return networkstatus_get_param(NULL, "pb_dropguards", + DFLT_PATH_BIAS_DROP_GUARDS, 0, 1); +} + +/** + * This is the number of circuits at which we scale our + * counts by mult_factor/scale_factor. Note, this count is + * not exact, as we only perform the scaling in the event + * of no integer truncation. + */ +static int +pathbias_get_scale_threshold(const or_options_t *options) +{ +#define DFLT_PATH_BIAS_SCALE_THRESHOLD 300 + if (options->PathBiasScaleThreshold >= 10) + return options->PathBiasScaleThreshold; + else + return networkstatus_get_param(NULL, "pb_scalecircs", + DFLT_PATH_BIAS_SCALE_THRESHOLD, 10, + INT32_MAX); +} + +/** + * Compute the path bias scaling ratio from the consensus + * parameters pb_multfactor/pb_scalefactor. + * + * Returns a value in (0, 1.0] which we multiply our pathbias + * counts with to scale them down. + */ +static double +pathbias_get_scale_ratio(const or_options_t *options) +{ + /* + * The scale factor is the denominator for our scaling + * of circuit counts for our path bias window. + * + * Note that our use of doubles for the path bias state + * file means that powers of 2 work best here. + */ + int denominator = networkstatus_get_param(NULL, "pb_scalefactor", + 2, 2, INT32_MAX); + (void) options; + /** + * The mult factor is the numerator for our scaling + * of circuit counts for our path bias window. It + * allows us to scale by fractions. + */ + return networkstatus_get_param(NULL, "pb_multfactor", + 1, 1, denominator)/((double)denominator); +} + +/** The minimum number of circuit usage attempts before we start + * thinking about warning about path use bias and dropping guards */ +static int +pathbias_get_min_use(const or_options_t *options) +{ +#define DFLT_PATH_BIAS_MIN_USE 20 + if (options->PathBiasUseThreshold >= 3) + return options->PathBiasUseThreshold; + else + return networkstatus_get_param(NULL, "pb_minuse", + DFLT_PATH_BIAS_MIN_USE, + 3, INT32_MAX); +} + +/** The circuit use success rate below which we issue a notice */ +static double +pathbias_get_notice_use_rate(const or_options_t *options) +{ +#define DFLT_PATH_BIAS_NOTICE_USE_PCT 80 + if (options->PathBiasNoticeUseRate >= 0.0) + return options->PathBiasNoticeUseRate; + else + return networkstatus_get_param(NULL, "pb_noticeusepct", + DFLT_PATH_BIAS_NOTICE_USE_PCT, + 0, 100)/100.0; +} + +/** + * The extreme use rate is the rate at which we would drop the guard, + * if pb_dropguard is also set. Otherwise we just warn. + */ +double +pathbias_get_extreme_use_rate(const or_options_t *options) +{ +#define DFLT_PATH_BIAS_EXTREME_USE_PCT 60 + if (options->PathBiasExtremeUseRate >= 0.0) + return options->PathBiasExtremeUseRate; + else + return networkstatus_get_param(NULL, "pb_extremeusepct", + DFLT_PATH_BIAS_EXTREME_USE_PCT, + 0, 100)/100.0; +} + +/** + * This is the number of circuits at which we scale our + * use counts by mult_factor/scale_factor. Note, this count is + * not exact, as we only perform the scaling in the event + * of no integer truncation. + */ +static int +pathbias_get_scale_use_threshold(const or_options_t *options) +{ +#define DFLT_PATH_BIAS_SCALE_USE_THRESHOLD 100 + if (options->PathBiasScaleUseThreshold >= 10) + return options->PathBiasScaleUseThreshold; + else + return networkstatus_get_param(NULL, "pb_scaleuse", + DFLT_PATH_BIAS_SCALE_USE_THRESHOLD, + 10, INT32_MAX); +} + +/** + * Convert a Guard's path state to string. + */ +const char * +pathbias_state_to_string(path_state_t state) +{ + switch (state) { + case PATH_STATE_NEW_CIRC: + return "new"; + case PATH_STATE_BUILD_ATTEMPTED: + return "build attempted"; + case PATH_STATE_BUILD_SUCCEEDED: + return "build succeeded"; + case PATH_STATE_USE_ATTEMPTED: + return "use attempted"; + case PATH_STATE_USE_SUCCEEDED: + return "use succeeded"; + case PATH_STATE_USE_FAILED: + return "use failed"; + case PATH_STATE_ALREADY_COUNTED: + return "already counted"; + } + + return "unknown"; +} + +/** + * This function decides if a circuit has progressed far enough to count + * as a circuit "attempt". As long as end-to-end tagging is possible, + * we assume the adversary will use it over hop-to-hop failure. Therefore, + * we only need to account bias for the last hop. This should make us + * much more resilient to ambient circuit failure, and also make that + * failure easier to measure (we only need to measure Exit failure rates). + */ +static int +pathbias_is_new_circ_attempt(origin_circuit_t *circ) +{ +#define N2N_TAGGING_IS_POSSIBLE +#ifdef N2N_TAGGING_IS_POSSIBLE + /* cpath is a circular list. We want circs with more than one hop, + * and the second hop must be waiting for keys still (it's just + * about to get them). */ + return circ->cpath && + circ->cpath->next != circ->cpath && + circ->cpath->next->state == CPATH_STATE_AWAITING_KEYS; +#else + /* If tagging attacks are no longer possible, we probably want to + * count bias from the first hop. However, one could argue that + * timing-based tagging is still more useful than per-hop failure. + * In which case, we'd never want to use this. + */ + return circ->cpath && + circ->cpath->state == CPATH_STATE_AWAITING_KEYS; +#endif +} + +/** + * Decide if the path bias code should count a circuit. + * + * @returns 1 if we should count it, 0 otherwise. + */ +static int +pathbias_should_count(origin_circuit_t *circ) +{ +#define PATHBIAS_COUNT_INTERVAL (600) + static ratelim_t count_limit = + RATELIM_INIT(PATHBIAS_COUNT_INTERVAL); + char *rate_msg = NULL; + + /* We can't do path bias accounting without entry guards. + * Testing and controller circuits also have no guards. + * + * We also don't count server-side rends, because their + * endpoint could be chosen maliciously. + * Similarly, we can't count client-side intro attempts, + * because clients can be manipulated into connecting to + * malicious intro points. */ + if (get_options()->UseEntryGuards == 0 || + circ->base_.purpose == CIRCUIT_PURPOSE_TESTING || + circ->base_.purpose == CIRCUIT_PURPOSE_CONTROLLER || + circ->base_.purpose == CIRCUIT_PURPOSE_S_CONNECT_REND || + circ->base_.purpose == CIRCUIT_PURPOSE_S_REND_JOINED || + (circ->base_.purpose >= CIRCUIT_PURPOSE_C_INTRODUCING && + circ->base_.purpose <= CIRCUIT_PURPOSE_C_INTRODUCE_ACKED)) { + + /* Check to see if the shouldcount result has changed due to a + * unexpected purpose change that would affect our results. + * + * The reason we check the path state too here is because for the + * cannibalized versions of these purposes, we count them as successful + * before their purpose change. + */ + if (circ->pathbias_shouldcount == PATHBIAS_SHOULDCOUNT_COUNTED + && circ->path_state != PATH_STATE_ALREADY_COUNTED) { + log_info(LD_BUG, + "Circuit %d is now being ignored despite being counted " + "in the past. Purpose is %s, path state is %s", + circ->global_identifier, + circuit_purpose_to_string(circ->base_.purpose), + pathbias_state_to_string(circ->path_state)); + } + circ->pathbias_shouldcount = PATHBIAS_SHOULDCOUNT_IGNORED; + return 0; + } + + /* Completely ignore one hop circuits */ + if (circ->build_state->onehop_tunnel || + circ->build_state->desired_path_len == 1) { + /* Check for inconsistency */ + if (circ->build_state->desired_path_len != 1 || + !circ->build_state->onehop_tunnel) { + if ((rate_msg = rate_limit_log(&count_limit, approx_time()))) { + log_info(LD_BUG, + "One-hop circuit has length %d. Path state is %s. " + "Circuit is a %s currently %s.%s", + circ->build_state->desired_path_len, + pathbias_state_to_string(circ->path_state), + circuit_purpose_to_string(circ->base_.purpose), + circuit_state_to_string(circ->base_.state), + rate_msg); + tor_free(rate_msg); + } + tor_fragile_assert(); + } + + /* Check to see if the shouldcount result has changed due to a + * unexpected change that would affect our results */ + if (circ->pathbias_shouldcount == PATHBIAS_SHOULDCOUNT_COUNTED) { + log_info(LD_BUG, + "One-hop circuit %d is now being ignored despite being counted " + "in the past. Purpose is %s, path state is %s", + circ->global_identifier, + circuit_purpose_to_string(circ->base_.purpose), + pathbias_state_to_string(circ->path_state)); + } + circ->pathbias_shouldcount = PATHBIAS_SHOULDCOUNT_IGNORED; + return 0; + } + + /* Check to see if the shouldcount result has changed due to a + * unexpected purpose change that would affect our results */ + if (circ->pathbias_shouldcount == PATHBIAS_SHOULDCOUNT_IGNORED) { + log_info(LD_BUG, + "Circuit %d is now being counted despite being ignored " + "in the past. Purpose is %s, path state is %s", + circ->global_identifier, + circuit_purpose_to_string(circ->base_.purpose), + pathbias_state_to_string(circ->path_state)); + } + circ->pathbias_shouldcount = PATHBIAS_SHOULDCOUNT_COUNTED; + + return 1; +} + +/** + * Check our circuit state to see if this is a successful circuit attempt. + * If so, record it in the current guard's path bias circ_attempt count. + * + * Also check for several potential error cases for bug #6475. + */ +int +pathbias_count_build_attempt(origin_circuit_t *circ) +{ +#define CIRC_ATTEMPT_NOTICE_INTERVAL (600) + static ratelim_t circ_attempt_notice_limit = + RATELIM_INIT(CIRC_ATTEMPT_NOTICE_INTERVAL); + char *rate_msg = NULL; + + if (!pathbias_should_count(circ)) { + return 0; + } + + if (pathbias_is_new_circ_attempt(circ)) { + /* Help track down the real cause of bug #6475: */ + if (circ->has_opened && circ->path_state != PATH_STATE_BUILD_ATTEMPTED) { + if ((rate_msg = rate_limit_log(&circ_attempt_notice_limit, + approx_time()))) { + log_info(LD_BUG, + "Opened circuit is in strange path state %s. " + "Circuit is a %s currently %s.%s", + pathbias_state_to_string(circ->path_state), + circuit_purpose_to_string(circ->base_.purpose), + circuit_state_to_string(circ->base_.state), + rate_msg); + tor_free(rate_msg); + } + } + + /* Don't re-count cannibalized circs.. */ + if (!circ->has_opened) { + entry_guard_t *guard = NULL; + + if (circ->cpath && circ->cpath->extend_info) { + guard = entry_guard_get_by_id_digest( + circ->cpath->extend_info->identity_digest); + } else if (circ->base_.n_chan) { + guard = + entry_guard_get_by_id_digest(circ->base_.n_chan->identity_digest); + } + + if (guard) { + if (circ->path_state == PATH_STATE_NEW_CIRC) { + circ->path_state = PATH_STATE_BUILD_ATTEMPTED; + + if (entry_guard_inc_circ_attempt_count(guard) < 0) { + /* Bogus guard; we already warned. */ + return -END_CIRC_REASON_TORPROTOCOL; + } + } else { + if ((rate_msg = rate_limit_log(&circ_attempt_notice_limit, + approx_time()))) { + log_info(LD_BUG, + "Unopened circuit has strange path state %s. " + "Circuit is a %s currently %s.%s", + pathbias_state_to_string(circ->path_state), + circuit_purpose_to_string(circ->base_.purpose), + circuit_state_to_string(circ->base_.state), + rate_msg); + tor_free(rate_msg); + } + } + } else { + if ((rate_msg = rate_limit_log(&circ_attempt_notice_limit, + approx_time()))) { + log_info(LD_CIRC, + "Unopened circuit has no known guard. " + "Circuit is a %s currently %s.%s", + circuit_purpose_to_string(circ->base_.purpose), + circuit_state_to_string(circ->base_.state), + rate_msg); + tor_free(rate_msg); + } + } + } + } + + return 0; +} + +/** + * Check our circuit state to see if this is a successful circuit + * completion. If so, record it in the current guard's path bias + * success count. + * + * Also check for several potential error cases for bug #6475. + */ +void +pathbias_count_build_success(origin_circuit_t *circ) +{ +#define SUCCESS_NOTICE_INTERVAL (600) + static ratelim_t success_notice_limit = + RATELIM_INIT(SUCCESS_NOTICE_INTERVAL); + char *rate_msg = NULL; + entry_guard_t *guard = NULL; + + if (!pathbias_should_count(circ)) { + return; + } + + /* Don't count cannibalized/reused circs for path bias + * "build" success, since they get counted under "use" success. */ + if (!circ->has_opened) { + if (circ->cpath && circ->cpath->extend_info) { + guard = entry_guard_get_by_id_digest( + circ->cpath->extend_info->identity_digest); + } + + if (guard) { + if (circ->path_state == PATH_STATE_BUILD_ATTEMPTED) { + circ->path_state = PATH_STATE_BUILD_SUCCEEDED; + guard->circ_successes++; + entry_guards_changed(); + + log_info(LD_CIRC, "Got success count %f/%f for guard %s ($%s)", + guard->circ_successes, guard->circ_attempts, + guard->nickname, hex_str(guard->identity, DIGEST_LEN)); + } else { + if ((rate_msg = rate_limit_log(&success_notice_limit, + approx_time()))) { + log_info(LD_BUG, + "Succeeded circuit is in strange path state %s. " + "Circuit is a %s currently %s.%s", + pathbias_state_to_string(circ->path_state), + circuit_purpose_to_string(circ->base_.purpose), + circuit_state_to_string(circ->base_.state), + rate_msg); + tor_free(rate_msg); + } + } + + if (guard->circ_attempts < guard->circ_successes) { + log_notice(LD_BUG, "Unexpectedly high successes counts (%f/%f) " + "for guard %s ($%s)", + guard->circ_successes, guard->circ_attempts, + guard->nickname, hex_str(guard->identity, DIGEST_LEN)); + } + /* In rare cases, CIRCUIT_PURPOSE_TESTING can get converted to + * CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT and have no guards here. + * No need to log that case. */ + } else if (circ->base_.purpose != CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT) { + if ((rate_msg = rate_limit_log(&success_notice_limit, + approx_time()))) { + log_info(LD_CIRC, + "Completed circuit has no known guard. " + "Circuit is a %s currently %s.%s", + circuit_purpose_to_string(circ->base_.purpose), + circuit_state_to_string(circ->base_.state), + rate_msg); + tor_free(rate_msg); + } + } + } else { + if (circ->path_state < PATH_STATE_BUILD_SUCCEEDED) { + if ((rate_msg = rate_limit_log(&success_notice_limit, + approx_time()))) { + log_info(LD_BUG, + "Opened circuit is in strange path state %s. " + "Circuit is a %s currently %s.%s", + pathbias_state_to_string(circ->path_state), + circuit_purpose_to_string(circ->base_.purpose), + circuit_state_to_string(circ->base_.state), + rate_msg); + tor_free(rate_msg); + } + } + } +} + +/** + * Record an attempt to use a circuit. Changes the circuit's + * path state and update its guard's usage counter. + * + * Used for path bias usage accounting. + */ +void +pathbias_count_use_attempt(origin_circuit_t *circ) +{ + entry_guard_t *guard; + + if (!pathbias_should_count(circ)) { + return; + } + + if (circ->path_state < PATH_STATE_BUILD_SUCCEEDED) { + log_notice(LD_BUG, + "Used circuit is in strange path state %s. " + "Circuit is a %s currently %s.", + pathbias_state_to_string(circ->path_state), + circuit_purpose_to_string(circ->base_.purpose), + circuit_state_to_string(circ->base_.state)); + } else if (circ->path_state < PATH_STATE_USE_ATTEMPTED) { + guard = entry_guard_get_by_id_digest( + circ->cpath->extend_info->identity_digest); + if (guard) { + pathbias_measure_use_rate(guard); + pathbias_scale_use_rates(guard); + guard->use_attempts++; + entry_guards_changed(); + + log_debug(LD_CIRC, + "Marked circuit %d (%f/%f) as used for guard %s ($%s).", + circ->global_identifier, + guard->use_successes, guard->use_attempts, + guard->nickname, hex_str(guard->identity, DIGEST_LEN)); + } + + circ->path_state = PATH_STATE_USE_ATTEMPTED; + } else { + /* Harmless but educational log message */ + log_info(LD_CIRC, + "Used circuit %d is already in path state %s. " + "Circuit is a %s currently %s.", + circ->global_identifier, + pathbias_state_to_string(circ->path_state), + circuit_purpose_to_string(circ->base_.purpose), + circuit_state_to_string(circ->base_.state)); + } + + return; +} + +/** + * Check the circuit's path state is appropriate and mark it as + * successfully used. Used for path bias usage accounting. + * + * We don't actually increment the guard's counters until + * pathbias_check_close(), because the circuit can still transition + * back to PATH_STATE_USE_ATTEMPTED if a stream fails later (this + * is done so we can probe the circuit for liveness at close). + */ +void +pathbias_mark_use_success(origin_circuit_t *circ) +{ + if (!pathbias_should_count(circ)) { + return; + } + + if (circ->path_state < PATH_STATE_USE_ATTEMPTED) { + log_notice(LD_BUG, + "Used circuit %d is in strange path state %s. " + "Circuit is a %s currently %s.", + circ->global_identifier, + pathbias_state_to_string(circ->path_state), + circuit_purpose_to_string(circ->base_.purpose), + circuit_state_to_string(circ->base_.state)); + + pathbias_count_use_attempt(circ); + } + + /* We don't do any accounting at the guard until actual circuit close */ + circ->path_state = PATH_STATE_USE_SUCCEEDED; + + return; +} + +/** + * If a stream ever detatches from a circuit in a retriable way, + * we need to mark this circuit as still needing either another + * successful stream, or in need of a probe. + * + * An adversary could let the first stream request succeed (ie the + * resolve), but then tag and timeout the remainder (via cell + * dropping), forcing them on new circuits. + * + * Rolling back the state will cause us to probe such circuits, which + * should lead to probe failures in the event of such tagging due to + * either unrecognized cells coming in while we wait for the probe, + * or the cipher state getting out of sync in the case of dropped cells. + */ +void +pathbias_mark_use_rollback(origin_circuit_t *circ) +{ + if (circ->path_state == PATH_STATE_USE_SUCCEEDED) { + log_info(LD_CIRC, + "Rolling back pathbias use state to 'attempted' for detached " + "circuit %d", circ->global_identifier); + circ->path_state = PATH_STATE_USE_ATTEMPTED; + } +} + +/** + * Actually count a circuit success towards a guard's usage counters + * if the path state is appropriate. + */ +static void +pathbias_count_use_success(origin_circuit_t *circ) +{ + entry_guard_t *guard; + + if (!pathbias_should_count(circ)) { + return; + } + + if (circ->path_state != PATH_STATE_USE_SUCCEEDED) { + log_notice(LD_BUG, + "Successfully used circuit %d is in strange path state %s. " + "Circuit is a %s currently %s.", + circ->global_identifier, + pathbias_state_to_string(circ->path_state), + circuit_purpose_to_string(circ->base_.purpose), + circuit_state_to_string(circ->base_.state)); + } else { + guard = entry_guard_get_by_id_digest( + circ->cpath->extend_info->identity_digest); + if (guard) { + guard->use_successes++; + entry_guards_changed(); + + if (guard->use_attempts < guard->use_successes) { + log_notice(LD_BUG, "Unexpectedly high use successes counts (%f/%f) " + "for guard %s=%s", + guard->use_successes, guard->use_attempts, + guard->nickname, hex_str(guard->identity, DIGEST_LEN)); + } + + log_debug(LD_CIRC, + "Marked circuit %d (%f/%f) as used successfully for guard " + "%s ($%s).", + circ->global_identifier, guard->use_successes, + guard->use_attempts, guard->nickname, + hex_str(guard->identity, DIGEST_LEN)); + } + } + + return; +} + +/** + * Send a probe down a circuit that the client attempted to use, + * but for which the stream timed out/failed. The probe is a + * RELAY_BEGIN cell with a 0.a.b.c destination address, which + * the exit will reject and reply back, echoing that address. + * + * The reason for such probes is because it is possible to bias + * a user's paths simply by causing timeouts, and these timeouts + * are not possible to differentiate from unresponsive servers. + * + * The probe is sent at the end of the circuit lifetime for two + * reasons: to prevent cryptographic taggers from being able to + * drop cells to cause timeouts, and to prevent easy recognition + * of probes before any real client traffic happens. + * + * Returns -1 if we couldn't probe, 0 otherwise. + */ +static int +pathbias_send_usable_probe(circuit_t *circ) +{ + /* Based on connection_ap_handshake_send_begin() */ + char payload[CELL_PAYLOAD_SIZE]; + int payload_len; + origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ); + crypt_path_t *cpath_layer = NULL; + char *probe_nonce = NULL; + + tor_assert(ocirc); + + cpath_layer = ocirc->cpath->prev; + + if (cpath_layer->state != CPATH_STATE_OPEN) { + /* This can happen for cannibalized circuits. Their + * last hop isn't yet open */ + log_info(LD_CIRC, + "Got pathbias probe request for unopened circuit %d. " + "Opened %d, len %d", ocirc->global_identifier, + ocirc->has_opened, ocirc->build_state->desired_path_len); + return -1; + } + + /* We already went down this road. */ + if (circ->purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING && + ocirc->pathbias_probe_id) { + log_info(LD_CIRC, + "Got pathbias probe request for circuit %d with " + "outstanding probe", ocirc->global_identifier); + return -1; + } + + /* Can't probe if the channel isn't open */ + if (circ->n_chan == NULL || + (circ->n_chan->state != CHANNEL_STATE_OPEN + && circ->n_chan->state != CHANNEL_STATE_MAINT)) { + log_info(LD_CIRC, + "Skipping pathbias probe for circuit %d: Channel is not open.", + ocirc->global_identifier); + return -1; + } + + circuit_change_purpose(circ, CIRCUIT_PURPOSE_PATH_BIAS_TESTING); + + /* Update timestamp for when circuit_expire_building() should kill us */ + tor_gettimeofday(&circ->timestamp_began); + + /* Generate a random address for the nonce */ + crypto_rand((char*)ô->pathbias_probe_nonce, + sizeof(ocirc->pathbias_probe_nonce)); + ocirc->pathbias_probe_nonce &= 0x00ffffff; + probe_nonce = tor_dup_ip(ocirc->pathbias_probe_nonce); + + tor_snprintf(payload,RELAY_PAYLOAD_SIZE, "%s:25", probe_nonce); + payload_len = (int)strlen(payload)+1; + + // XXX: need this? Can we assume ipv4 will always be supported? + // If not, how do we tell? + //if (payload_len <= RELAY_PAYLOAD_SIZE - 4 && edge_conn->begincell_flags) { + // set_uint32(payload + payload_len, htonl(edge_conn->begincell_flags)); + // payload_len += 4; + //} + + /* Generate+Store stream id, make sure it's non-zero */ + ocirc->pathbias_probe_id = get_unique_stream_id_by_circ(ocirc); + + if (ocirc->pathbias_probe_id==0) { + log_warn(LD_CIRC, + "Ran out of stream IDs on circuit %u during " + "pathbias probe attempt.", ocirc->global_identifier); + tor_free(probe_nonce); + return -1; + } + + log_info(LD_CIRC, + "Sending pathbias testing cell to %s:25 on stream %d for circ %d.", + probe_nonce, ocirc->pathbias_probe_id, ocirc->global_identifier); + tor_free(probe_nonce); + + /* Send a test relay cell */ + if (relay_send_command_from_edge(ocirc->pathbias_probe_id, circ, + RELAY_COMMAND_BEGIN, payload, + payload_len, cpath_layer) < 0) { + log_notice(LD_CIRC, + "Failed to send pathbias probe cell on circuit %d.", + ocirc->global_identifier); + return -1; + } + + /* Mark it freshly dirty so it doesn't get expired in the meantime */ + circ->timestamp_dirty = time(NULL); + + return 0; +} + +/** + * Check the response to a pathbias probe, to ensure the + * cell is recognized and the nonce and other probe + * characteristics are as expected. + * + * If the response is valid, return 0. Otherwise return < 0. + */ +int +pathbias_check_probe_response(circuit_t *circ, const cell_t *cell) +{ + /* Based on connection_edge_process_relay_cell() */ + relay_header_t rh; + int reason; + uint32_t ipv4_host; + origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ); + + tor_assert(cell); + tor_assert(ocirc); + tor_assert(circ->purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING); + + relay_header_unpack(&rh, cell->payload); + + reason = rh.length > 0 ? + get_uint8(cell->payload+RELAY_HEADER_SIZE) : END_STREAM_REASON_MISC; + + if (rh.command == RELAY_COMMAND_END && + reason == END_STREAM_REASON_EXITPOLICY && + ocirc->pathbias_probe_id == rh.stream_id) { + + /* Check length+extract host: It is in network order after the reason code. + * See connection_edge_end(). */ + if (rh.length < 9) { /* reason+ipv4+dns_ttl */ + log_notice(LD_PROTOCOL, + "Short path bias probe response length field (%d).", rh.length); + return - END_CIRC_REASON_TORPROTOCOL; + } + + ipv4_host = ntohl(get_uint32(cell->payload+RELAY_HEADER_SIZE+1)); + + /* Check nonce */ + if (ipv4_host == ocirc->pathbias_probe_nonce) { + pathbias_mark_use_success(ocirc); + circuit_mark_for_close(circ, END_CIRC_REASON_FINISHED); + log_info(LD_CIRC, + "Got valid path bias probe back for circ %d, stream %d.", + ocirc->global_identifier, ocirc->pathbias_probe_id); + return 0; + } else { + log_notice(LD_CIRC, + "Got strange probe value 0x%x vs 0x%x back for circ %d, " + "stream %d.", ipv4_host, ocirc->pathbias_probe_nonce, + ocirc->global_identifier, ocirc->pathbias_probe_id); + return -1; + } + } + log_info(LD_CIRC, + "Got another cell back back on pathbias probe circuit %d: " + "Command: %d, Reason: %d, Stream-id: %d", + ocirc->global_identifier, rh.command, reason, rh.stream_id); + return -1; +} + +/** + * Check if a circuit was used and/or closed successfully. + * + * If we attempted to use the circuit to carry a stream but failed + * for whatever reason, or if the circuit mysteriously died before + * we could attach any streams, record these two cases. + * + * If we *have* successfully used the circuit, or it appears to + * have been closed by us locally, count it as a success. + * + * Returns 0 if we're done making decisions with the circ, + * or -1 if we want to probe it first. + */ +int +pathbias_check_close(origin_circuit_t *ocirc, int reason) +{ + circuit_t *circ = ô->base_; + + if (!pathbias_should_count(ocirc)) { + return 0; + } + + switch (ocirc->path_state) { + /* If the circuit was closed after building, but before use, we need + * to ensure we were the ones who tried to close it (and not a remote + * actor). */ + case PATH_STATE_BUILD_SUCCEEDED: + if (reason & END_CIRC_REASON_FLAG_REMOTE) { + /* Remote circ close reasons on an unused circuit all could be bias */ + log_info(LD_CIRC, + "Circuit %d remote-closed without successful use for reason %d. " + "Circuit purpose %d currently %d,%s. Len %d.", + ocirc->global_identifier, + reason, circ->purpose, ocirc->has_opened, + circuit_state_to_string(circ->state), + ocirc->build_state->desired_path_len); + pathbias_count_collapse(ocirc); + } else if ((reason & ~END_CIRC_REASON_FLAG_REMOTE) + == END_CIRC_REASON_CHANNEL_CLOSED && + circ->n_chan && + circ->n_chan->reason_for_closing + != CHANNEL_CLOSE_REQUESTED) { + /* If we didn't close the channel ourselves, it could be bias */ + /* XXX: Only count bias if the network is live? + * What about clock jumps/suspends? */ + log_info(LD_CIRC, + "Circuit %d's channel closed without successful use for reason " + "%d, channel reason %d. Circuit purpose %d currently %d,%s. Len " + "%d.", ocirc->global_identifier, + reason, circ->n_chan->reason_for_closing, + circ->purpose, ocirc->has_opened, + circuit_state_to_string(circ->state), + ocirc->build_state->desired_path_len); + pathbias_count_collapse(ocirc); + } else { + pathbias_count_successful_close(ocirc); + } + break; + + /* If we tried to use a circuit but failed, we should probe it to ensure + * it has not been tampered with. */ + case PATH_STATE_USE_ATTEMPTED: + /* XXX: Only probe and/or count failure if the network is live? + * What about clock jumps/suspends? */ + if (pathbias_send_usable_probe(circ) == 0) + return -1; + else + pathbias_count_use_failed(ocirc); + + /* Any circuit where there were attempted streams but no successful + * streams could be bias */ + log_info(LD_CIRC, + "Circuit %d closed without successful use for reason %d. " + "Circuit purpose %d currently %d,%s. Len %d.", + ocirc->global_identifier, + reason, circ->purpose, ocirc->has_opened, + circuit_state_to_string(circ->state), + ocirc->build_state->desired_path_len); + break; + + case PATH_STATE_USE_SUCCEEDED: + pathbias_count_successful_close(ocirc); + pathbias_count_use_success(ocirc); + break; + + case PATH_STATE_USE_FAILED: + pathbias_count_use_failed(ocirc); + break; + + case PATH_STATE_NEW_CIRC: + case PATH_STATE_BUILD_ATTEMPTED: + case PATH_STATE_ALREADY_COUNTED: + default: + // Other states are uninteresting. No stats to count. + break; + } + + ocirc->path_state = PATH_STATE_ALREADY_COUNTED; + + return 0; +} + +/** + * Count a successfully closed circuit. + */ +static void +pathbias_count_successful_close(origin_circuit_t *circ) +{ + entry_guard_t *guard = NULL; + if (!pathbias_should_count(circ)) { + return; + } + + if (circ->cpath && circ->cpath->extend_info) { + guard = entry_guard_get_by_id_digest( + circ->cpath->extend_info->identity_digest); + } + + if (guard) { + /* In the long run: circuit_success ~= successful_circuit_close + + * circ_failure + stream_failure */ + guard->successful_circuits_closed++; + entry_guards_changed(); + } else if (circ->base_.purpose != CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT) { + /* In rare cases, CIRCUIT_PURPOSE_TESTING can get converted to + * CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT and have no guards here. + * No need to log that case. */ + log_info(LD_CIRC, + "Successfully closed circuit has no known guard. " + "Circuit is a %s currently %s", + circuit_purpose_to_string(circ->base_.purpose), + circuit_state_to_string(circ->base_.state)); + } +} + +/** + * Count a circuit that fails after it is built, but before it can + * carry any traffic. + * + * This is needed because there are ways to destroy a + * circuit after it has successfully completed. Right now, this is + * used for purely informational/debugging purposes. + */ +static void +pathbias_count_collapse(origin_circuit_t *circ) +{ + entry_guard_t *guard = NULL; + + if (!pathbias_should_count(circ)) { + return; + } + + if (circ->cpath && circ->cpath->extend_info) { + guard = entry_guard_get_by_id_digest( + circ->cpath->extend_info->identity_digest); + } + + if (guard) { + guard->collapsed_circuits++; + entry_guards_changed(); + } else if (circ->base_.purpose != CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT) { + /* In rare cases, CIRCUIT_PURPOSE_TESTING can get converted to + * CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT and have no guards here. + * No need to log that case. */ + log_info(LD_CIRC, + "Destroyed circuit has no known guard. " + "Circuit is a %s currently %s", + circuit_purpose_to_string(circ->base_.purpose), + circuit_state_to_string(circ->base_.state)); + } +} + +/** + * Count a known failed circuit (because we could not probe it). + * + * This counter is informational. + */ +static void +pathbias_count_use_failed(origin_circuit_t *circ) +{ + entry_guard_t *guard = NULL; + if (!pathbias_should_count(circ)) { + return; + } + + if (circ->cpath && circ->cpath->extend_info) { + guard = entry_guard_get_by_id_digest( + circ->cpath->extend_info->identity_digest); + } + + if (guard) { + guard->unusable_circuits++; + entry_guards_changed(); + } else if (circ->base_.purpose != CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT) { + /* In rare cases, CIRCUIT_PURPOSE_TESTING can get converted to + * CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT and have no guards here. + * No need to log that case. */ + /* XXX note cut-and-paste code in this function compared to nearby + * functions. Would be nice to refactor. -RD */ + log_info(LD_CIRC, + "Stream-failing circuit has no known guard. " + "Circuit is a %s currently %s", + circuit_purpose_to_string(circ->base_.purpose), + circuit_state_to_string(circ->base_.state)); + } +} + +/** + * Count timeouts for path bias log messages. + * + * These counts are purely informational. + */ +void +pathbias_count_timeout(origin_circuit_t *circ) +{ + entry_guard_t *guard = NULL; + + if (!pathbias_should_count(circ)) { + return; + } + + /* For hidden service circs, they can actually be used + * successfully and then time out later (because + * the other side declines to use them). */ + if (circ->path_state == PATH_STATE_USE_SUCCEEDED) { + return; + } + + if (circ->cpath && circ->cpath->extend_info) { + guard = entry_guard_get_by_id_digest( + circ->cpath->extend_info->identity_digest); + } + + if (guard) { + guard->timeouts++; + entry_guards_changed(); + } +} + +/** + * Helper function to count all of the currently opened circuits + * for a guard that are in a given path state range. The state + * range is inclusive on both ends. + */ +static int +pathbias_count_circs_in_states(entry_guard_t *guard, + path_state_t from, + path_state_t to) +{ + circuit_t *circ; + int open_circuits = 0; + + /* Count currently open circuits. Give them the benefit of the doubt. */ + TOR_LIST_FOREACH(circ, circuit_get_global_list(), head) { + origin_circuit_t *ocirc = NULL; + if (!CIRCUIT_IS_ORIGIN(circ) || /* didn't originate here */ + circ->marked_for_close) /* already counted */ + continue; + + ocirc = TO_ORIGIN_CIRCUIT(circ); + + if (!ocirc->cpath || !ocirc->cpath->extend_info) + continue; + + if (ocirc->path_state >= from && + ocirc->path_state <= to && + pathbias_should_count(ocirc) && + fast_memeq(guard->identity, + ocirc->cpath->extend_info->identity_digest, + DIGEST_LEN)) { + log_debug(LD_CIRC, "Found opened circuit %d in path_state %s", + ocirc->global_identifier, + pathbias_state_to_string(ocirc->path_state)); + open_circuits++; + } + } + + return open_circuits; +} + +/** + * Return the number of circuits counted as successfully closed for + * this guard. + * + * Also add in the currently open circuits to give them the benefit + * of the doubt. + */ +double +pathbias_get_close_success_count(entry_guard_t *guard) +{ + return guard->successful_circuits_closed + + pathbias_count_circs_in_states(guard, + PATH_STATE_BUILD_SUCCEEDED, + PATH_STATE_USE_SUCCEEDED); +} + +/** + * Return the number of circuits counted as successfully used + * this guard. + * + * Also add in the currently open circuits that we are attempting + * to use to give them the benefit of the doubt. + */ +double +pathbias_get_use_success_count(entry_guard_t *guard) +{ + return guard->use_successes + + pathbias_count_circs_in_states(guard, + PATH_STATE_USE_ATTEMPTED, + PATH_STATE_USE_SUCCEEDED); +} + +/** + * Check the path bias use rate against our consensus parameter limits. + * + * Emits a log message if the use success rates are too low. + * + * If pathbias_get_dropguards() is set, we also disable the use of + * very failure prone guards. + */ +static void +pathbias_measure_use_rate(entry_guard_t *guard) +{ + const or_options_t *options = get_options(); + + if (guard->use_attempts > pathbias_get_min_use(options)) { + /* Note: We rely on the < comparison here to allow us to set a 0 + * rate and disable the feature entirely. If refactoring, don't + * change to <= */ + if (pathbias_get_use_success_count(guard)/guard->use_attempts + < pathbias_get_extreme_use_rate(options)) { + /* Dropping is currently disabled by default. */ + if (pathbias_get_dropguards(options)) { + if (!guard->path_bias_disabled) { + log_warn(LD_CIRC, + "Your Guard %s ($%s) is failing to carry an extremely large " + "amount of stream on its circuits. " + "To avoid potential route manipulation attacks, Tor has " + "disabled use of this guard. " + "Use counts are %ld/%ld. Success counts are %ld/%ld. " + "%ld circuits completed, %ld were unusable, %ld collapsed, " + "and %ld timed out. " + "For reference, your timeout cutoff is %ld seconds.", + guard->nickname, hex_str(guard->identity, DIGEST_LEN), + tor_lround(pathbias_get_use_success_count(guard)), + tor_lround(guard->use_attempts), + tor_lround(pathbias_get_close_success_count(guard)), + tor_lround(guard->circ_attempts), + tor_lround(guard->circ_successes), + tor_lround(guard->unusable_circuits), + tor_lround(guard->collapsed_circuits), + tor_lround(guard->timeouts), + tor_lround(get_circuit_build_close_time_ms()/1000)); + guard->path_bias_disabled = 1; + guard->bad_since = approx_time(); + entry_guards_changed(); + return; + } + } else if (!guard->path_bias_use_extreme) { + guard->path_bias_use_extreme = 1; + log_warn(LD_CIRC, + "Your Guard %s ($%s) is failing to carry an extremely large " + "amount of streams on its circuits. " + "This could indicate a route manipulation attack, network " + "overload, bad local network connectivity, or a bug. " + "Use counts are %ld/%ld. Success counts are %ld/%ld. " + "%ld circuits completed, %ld were unusable, %ld collapsed, " + "and %ld timed out. " + "For reference, your timeout cutoff is %ld seconds.", + guard->nickname, hex_str(guard->identity, DIGEST_LEN), + tor_lround(pathbias_get_use_success_count(guard)), + tor_lround(guard->use_attempts), + tor_lround(pathbias_get_close_success_count(guard)), + tor_lround(guard->circ_attempts), + tor_lround(guard->circ_successes), + tor_lround(guard->unusable_circuits), + tor_lround(guard->collapsed_circuits), + tor_lround(guard->timeouts), + tor_lround(get_circuit_build_close_time_ms()/1000)); + } + } else if (pathbias_get_use_success_count(guard)/guard->use_attempts + < pathbias_get_notice_use_rate(options)) { + if (!guard->path_bias_use_noticed) { + guard->path_bias_use_noticed = 1; + log_notice(LD_CIRC, + "Your Guard %s ($%s) is failing to carry more streams on its " + "circuits than usual. " + "Most likely this means the Tor network is overloaded " + "or your network connection is poor. " + "Use counts are %ld/%ld. Success counts are %ld/%ld. " + "%ld circuits completed, %ld were unusable, %ld collapsed, " + "and %ld timed out. " + "For reference, your timeout cutoff is %ld seconds.", + guard->nickname, hex_str(guard->identity, DIGEST_LEN), + tor_lround(pathbias_get_use_success_count(guard)), + tor_lround(guard->use_attempts), + tor_lround(pathbias_get_close_success_count(guard)), + tor_lround(guard->circ_attempts), + tor_lround(guard->circ_successes), + tor_lround(guard->unusable_circuits), + tor_lround(guard->collapsed_circuits), + tor_lround(guard->timeouts), + tor_lround(get_circuit_build_close_time_ms()/1000)); + } + } + } +} + +/** + * Check the path bias circuit close status rates against our consensus + * parameter limits. + * + * Emits a log message if the use success rates are too low. + * + * If pathbias_get_dropguards() is set, we also disable the use of + * very failure prone guards. + * + * XXX: This function shares similar log messages and checks to + * pathbias_measure_use_rate(). It may be possible to combine them + * eventually, especially if we can ever remove the need for 3 + * levels of closure warns (if the overall circuit failure rate + * goes down with ntor). One way to do so would be to multiply + * the build rate with the use rate to get an idea of the total + * fraction of the total network paths the user is able to use. + * See ticket #8159. + */ +static void +pathbias_measure_close_rate(entry_guard_t *guard) +{ + const or_options_t *options = get_options(); + + if (guard->circ_attempts > pathbias_get_min_circs(options)) { + /* Note: We rely on the < comparison here to allow us to set a 0 + * rate and disable the feature entirely. If refactoring, don't + * change to <= */ + if (pathbias_get_close_success_count(guard)/guard->circ_attempts + < pathbias_get_extreme_rate(options)) { + /* Dropping is currently disabled by default. */ + if (pathbias_get_dropguards(options)) { + if (!guard->path_bias_disabled) { + log_warn(LD_CIRC, + "Your Guard %s ($%s) is failing an extremely large " + "amount of circuits. " + "To avoid potential route manipulation attacks, Tor has " + "disabled use of this guard. " + "Success counts are %ld/%ld. Use counts are %ld/%ld. " + "%ld circuits completed, %ld were unusable, %ld collapsed, " + "and %ld timed out. " + "For reference, your timeout cutoff is %ld seconds.", + guard->nickname, hex_str(guard->identity, DIGEST_LEN), + tor_lround(pathbias_get_close_success_count(guard)), + tor_lround(guard->circ_attempts), + tor_lround(pathbias_get_use_success_count(guard)), + tor_lround(guard->use_attempts), + tor_lround(guard->circ_successes), + tor_lround(guard->unusable_circuits), + tor_lround(guard->collapsed_circuits), + tor_lround(guard->timeouts), + tor_lround(get_circuit_build_close_time_ms()/1000)); + guard->path_bias_disabled = 1; + guard->bad_since = approx_time(); + entry_guards_changed(); + return; + } + } else if (!guard->path_bias_extreme) { + guard->path_bias_extreme = 1; + log_warn(LD_CIRC, + "Your Guard %s ($%s) is failing an extremely large " + "amount of circuits. " + "This could indicate a route manipulation attack, " + "extreme network overload, or a bug. " + "Success counts are %ld/%ld. Use counts are %ld/%ld. " + "%ld circuits completed, %ld were unusable, %ld collapsed, " + "and %ld timed out. " + "For reference, your timeout cutoff is %ld seconds.", + guard->nickname, hex_str(guard->identity, DIGEST_LEN), + tor_lround(pathbias_get_close_success_count(guard)), + tor_lround(guard->circ_attempts), + tor_lround(pathbias_get_use_success_count(guard)), + tor_lround(guard->use_attempts), + tor_lround(guard->circ_successes), + tor_lround(guard->unusable_circuits), + tor_lround(guard->collapsed_circuits), + tor_lround(guard->timeouts), + tor_lround(get_circuit_build_close_time_ms()/1000)); + } + } else if (pathbias_get_close_success_count(guard)/guard->circ_attempts + < pathbias_get_warn_rate(options)) { + if (!guard->path_bias_warned) { + guard->path_bias_warned = 1; + log_warn(LD_CIRC, + "Your Guard %s ($%s) is failing a very large " + "amount of circuits. " + "Most likely this means the Tor network is " + "overloaded, but it could also mean an attack against " + "you or potentially the guard itself. " + "Success counts are %ld/%ld. Use counts are %ld/%ld. " + "%ld circuits completed, %ld were unusable, %ld collapsed, " + "and %ld timed out. " + "For reference, your timeout cutoff is %ld seconds.", + guard->nickname, hex_str(guard->identity, DIGEST_LEN), + tor_lround(pathbias_get_close_success_count(guard)), + tor_lround(guard->circ_attempts), + tor_lround(pathbias_get_use_success_count(guard)), + tor_lround(guard->use_attempts), + tor_lround(guard->circ_successes), + tor_lround(guard->unusable_circuits), + tor_lround(guard->collapsed_circuits), + tor_lround(guard->timeouts), + tor_lround(get_circuit_build_close_time_ms()/1000)); + } + } else if (pathbias_get_close_success_count(guard)/guard->circ_attempts + < pathbias_get_notice_rate(options)) { + if (!guard->path_bias_noticed) { + guard->path_bias_noticed = 1; + log_notice(LD_CIRC, + "Your Guard %s ($%s) is failing more circuits than " + "usual. " + "Most likely this means the Tor network is overloaded. " + "Success counts are %ld/%ld. Use counts are %ld/%ld. " + "%ld circuits completed, %ld were unusable, %ld collapsed, " + "and %ld timed out. " + "For reference, your timeout cutoff is %ld seconds.", + guard->nickname, hex_str(guard->identity, DIGEST_LEN), + tor_lround(pathbias_get_close_success_count(guard)), + tor_lround(guard->circ_attempts), + tor_lround(pathbias_get_use_success_count(guard)), + tor_lround(guard->use_attempts), + tor_lround(guard->circ_successes), + tor_lround(guard->unusable_circuits), + tor_lround(guard->collapsed_circuits), + tor_lround(guard->timeouts), + tor_lround(get_circuit_build_close_time_ms()/1000)); + } + } + } +} + +/** + * This function scales the path bias use rates if we have + * more data than the scaling threshold. This allows us to + * be more sensitive to recent measurements. + * + * XXX: The attempt count transfer stuff here might be done + * better by keeping separate pending counters that get + * transfered at circuit close. See ticket #8160. + */ +static void +pathbias_scale_close_rates(entry_guard_t *guard) +{ + const or_options_t *options = get_options(); + + /* If we get a ton of circuits, just scale everything down */ + if (guard->circ_attempts > pathbias_get_scale_threshold(options)) { + double scale_ratio = pathbias_get_scale_ratio(options); + int opened_attempts = pathbias_count_circs_in_states(guard, + PATH_STATE_BUILD_ATTEMPTED, PATH_STATE_BUILD_ATTEMPTED); + int opened_built = pathbias_count_circs_in_states(guard, + PATH_STATE_BUILD_SUCCEEDED, + PATH_STATE_USE_FAILED); + /* Verify that the counts are sane before and after scaling */ + int counts_are_sane = (guard->circ_attempts >= guard->circ_successes); + + guard->circ_attempts -= (opened_attempts+opened_built); + guard->circ_successes -= opened_built; + + guard->circ_attempts *= scale_ratio; + guard->circ_successes *= scale_ratio; + guard->timeouts *= scale_ratio; + guard->successful_circuits_closed *= scale_ratio; + guard->collapsed_circuits *= scale_ratio; + guard->unusable_circuits *= scale_ratio; + + guard->circ_attempts += (opened_attempts+opened_built); + guard->circ_successes += opened_built; + + entry_guards_changed(); + + log_info(LD_CIRC, + "Scaled pathbias counts to (%f,%f)/%f (%d/%d open) for guard " + "%s ($%s)", + guard->circ_successes, guard->successful_circuits_closed, + guard->circ_attempts, opened_built, opened_attempts, + guard->nickname, hex_str(guard->identity, DIGEST_LEN)); + + /* Have the counts just become invalid by this scaling attempt? */ + if (counts_are_sane && guard->circ_attempts < guard->circ_successes) { + log_notice(LD_BUG, + "Scaling has mangled pathbias counts to %f/%f (%d/%d open) " + "for guard %s ($%s)", + guard->circ_successes, guard->circ_attempts, opened_built, + opened_attempts, guard->nickname, + hex_str(guard->identity, DIGEST_LEN)); + } + } +} + +/** + * This function scales the path bias circuit close rates if we have + * more data than the scaling threshold. This allows us to be more + * sensitive to recent measurements. + * + * XXX: The attempt count transfer stuff here might be done + * better by keeping separate pending counters that get + * transfered at circuit close. See ticket #8160. + */ +void +pathbias_scale_use_rates(entry_guard_t *guard) +{ + const or_options_t *options = get_options(); + + /* If we get a ton of circuits, just scale everything down */ + if (guard->use_attempts > pathbias_get_scale_use_threshold(options)) { + double scale_ratio = pathbias_get_scale_ratio(options); + int opened_attempts = pathbias_count_circs_in_states(guard, + PATH_STATE_USE_ATTEMPTED, PATH_STATE_USE_SUCCEEDED); + /* Verify that the counts are sane before and after scaling */ + int counts_are_sane = (guard->use_attempts >= guard->use_successes); + + guard->use_attempts -= opened_attempts; + + guard->use_attempts *= scale_ratio; + guard->use_successes *= scale_ratio; + + guard->use_attempts += opened_attempts; + + log_info(LD_CIRC, + "Scaled pathbias use counts to %f/%f (%d open) for guard %s ($%s)", + guard->use_successes, guard->use_attempts, opened_attempts, + guard->nickname, hex_str(guard->identity, DIGEST_LEN)); + + /* Have the counts just become invalid by this scaling attempt? */ + if (counts_are_sane && guard->use_attempts < guard->use_successes) { + log_notice(LD_BUG, + "Scaling has mangled pathbias usage counts to %f/%f " + "(%d open) for guard %s ($%s)", + guard->circ_successes, guard->circ_attempts, + opened_attempts, guard->nickname, + hex_str(guard->identity, DIGEST_LEN)); + } + + entry_guards_changed(); + } +} + diff --git a/src/tor/circpathbias.h b/src/tor/circpathbias.h new file mode 100644 index 0000000..c95d801 --- /dev/null +++ b/src/tor/circpathbias.h @@ -0,0 +1,29 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file circuitbuild.h + * \brief Header file for circuitbuild.c. + **/ + +#ifndef TOR_CIRCPATHBIAS_H +#define TOR_CIRCPATHBIAS_H + +double pathbias_get_extreme_rate(const or_options_t *options); +double pathbias_get_extreme_use_rate(const or_options_t *options); +int pathbias_get_dropguards(const or_options_t *options); +void pathbias_count_timeout(origin_circuit_t *circ); +void pathbias_count_build_success(origin_circuit_t *circ); +int pathbias_count_build_attempt(origin_circuit_t *circ); +int pathbias_check_close(origin_circuit_t *circ, int reason); +int pathbias_check_probe_response(circuit_t *circ, const cell_t *cell); +void pathbias_count_use_attempt(origin_circuit_t *circ); +void pathbias_mark_use_success(origin_circuit_t *circ); +void pathbias_mark_use_rollback(origin_circuit_t *circ); +const char *pathbias_state_to_string(path_state_t state); + +#endif + diff --git a/src/tor/circuitbuild.c b/src/tor/circuitbuild.c new file mode 100644 index 0000000..aeeea47 --- /dev/null +++ b/src/tor/circuitbuild.c @@ -0,0 +1,2200 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file circuitbuild.c + * \brief The actual details of building circuits. + **/ + +#include "or.h" +#include "channel.h" +#include "circpathbias.h" +#include "circuitbuild.h" +#include "circuitlist.h" +#include "circuitstats.h" +#include "circuituse.h" +#include "command.h" +#include "config.h" +#include "confparse.h" +#include "connection.h" +#include "connection_edge.h" +#include "connection_or.h" +#include "control.h" +#include "directory.h" +#include "entrynodes.h" +#include "onion_main.h" +#include "microdesc.h" +#include "networkstatus.h" +#include "nodelist.h" +#include "onion.h" +#include "onion_tap.h" +#include "onion_fast.h" +#include "policies.h" +#include "transports.h" +#include "relay.h" +#include "rephist.h" +#include "router.h" +#include "routerlist.h" +#include "routerparse.h" +#include "routerset.h" +#include "crypto.h" + +#ifndef MIN +#define MIN(a,b) ((a)<(b)?(a):(b)) +#endif + +static channel_t * channel_connect_for_circuit(const tor_addr_t *addr, + uint16_t port, + const char *id_digest); +static int circuit_deliver_create_cell(circuit_t *circ, + const create_cell_t *create_cell, + int relayed); +static int onion_pick_cpath_exit(origin_circuit_t *circ, extend_info_t *exit); +static crypt_path_t *onion_next_hop_in_cpath(crypt_path_t *cpath); +static int onion_extend_cpath(origin_circuit_t *circ); +static int count_acceptable_nodes(smartlist_t *routers); +static int onion_append_hop(crypt_path_t **head_ptr, extend_info_t *choice); +#ifdef CURVE25519_ENABLED +static int circuits_can_use_ntor(void); +#endif + +/** This function tries to get a channel to the specified endpoint, + * and then calls command_setup_channel() to give it the right + * callbacks. + */ +static channel_t * +channel_connect_for_circuit(const tor_addr_t *addr, uint16_t port, + const char *id_digest) +{ + channel_t *chan; + + chan = channel_connect(addr, port, id_digest); + if (chan) command_setup_channel(chan); + + return chan; +} + +/** Iterate over values of circ_id, starting from conn-\>next_circ_id, + * and with the high bit specified by conn-\>circ_id_type, until we get + * a circ_id that is not in use by any other circuit on that conn. + * + * Return it, or 0 if can't get a unique circ_id. + */ +static circid_t +get_unique_circ_id_by_chan(channel_t *chan) +{ + circid_t test_circ_id; + circid_t attempts=0; + circid_t high_bit, max_range; + + tor_assert(chan); + + if (chan->circ_id_type == CIRC_ID_TYPE_NEITHER) { + log_warn(LD_BUG, + "Trying to pick a circuit ID for a connection from " + "a client with no identity."); + return 0; + } + max_range = (chan->wide_circ_ids) ? (1u<<31) : (1u<<15); + high_bit = (chan->circ_id_type == CIRC_ID_TYPE_HIGHER) ? max_range : 0; + do { + /* Sequentially iterate over test_circ_id=1...max_range until we find a + * circID such that (high_bit|test_circ_id) is not already used. */ + test_circ_id = chan->next_circ_id++; + if (test_circ_id == 0 || test_circ_id >= max_range) { + test_circ_id = 1; + chan->next_circ_id = 2; + } + if (++attempts > max_range) { + /* Make sure we don't loop forever if all circ_id's are used. This + * matters because it's an external DoS opportunity. + */ + log_warn(LD_CIRC,"No unused circ IDs. Failing."); + return 0; + } + test_circ_id |= high_bit; + } while (circuit_id_in_use_on_channel(test_circ_id, chan)); + return test_circ_id; +} + +/** If verbose is false, allocate and return a comma-separated list of + * the currently built elements of circ. If verbose is true, also + * list information about link status in a more verbose format using spaces. + * If verbose_names is false, give nicknames for Named routers and hex + * digests for others; if verbose_names is true, use $DIGEST=Name style + * names. + */ +static char * +circuit_list_path_impl(origin_circuit_t *circ, int verbose, int verbose_names) +{ + crypt_path_t *hop; + smartlist_t *elements; + const char *states[] = {"closed", "waiting for keys", "open"}; + char *s; + + elements = smartlist_new(); + + if (verbose) { + const char *nickname = build_state_get_exit_nickname(circ->build_state); + smartlist_add_asprintf(elements, "%s%s circ (length %d%s%s):", + circ->build_state->is_internal ? "internal" : "exit", + circ->build_state->need_uptime ? " (high-uptime)" : "", + circ->build_state->desired_path_len, + circ->base_.state == CIRCUIT_STATE_OPEN ? "" : ", last hop ", + circ->base_.state == CIRCUIT_STATE_OPEN ? "" : + (nickname?nickname:"*unnamed*")); + } + + hop = circ->cpath; + do { + char *elt; + const char *id; + const node_t *node; + if (!hop) + break; + if (!verbose && hop->state != CPATH_STATE_OPEN) + break; + if (!hop->extend_info) + break; + id = hop->extend_info->identity_digest; + if (verbose_names) { + elt = tor_malloc(MAX_VERBOSE_NICKNAME_LEN+1); + if ((node = node_get_by_id(id))) { + node_get_verbose_nickname(node, elt); + } else if (is_legal_nickname(hop->extend_info->nickname)) { + elt[0] = '$'; + base16_encode(elt+1, HEX_DIGEST_LEN+1, id, DIGEST_LEN); + elt[HEX_DIGEST_LEN+1]= '~'; + strlcpy(elt+HEX_DIGEST_LEN+2, + hop->extend_info->nickname, MAX_NICKNAME_LEN+1); + } else { + elt[0] = '$'; + base16_encode(elt+1, HEX_DIGEST_LEN+1, id, DIGEST_LEN); + } + } else { /* ! verbose_names */ + node = node_get_by_id(id); + if (node && node_is_named(node)) { + elt = tor_strdup(node_get_nickname(node)); + } else { + elt = tor_malloc(HEX_DIGEST_LEN+2); + elt[0] = '$'; + base16_encode(elt+1, HEX_DIGEST_LEN+1, id, DIGEST_LEN); + } + } + tor_assert(elt); + if (verbose) { + tor_assert(hop->state <= 2); + smartlist_add_asprintf(elements,"%s(%s)",elt,states[hop->state]); + tor_free(elt); + } else { + smartlist_add(elements, elt); + } + hop = hop->next; + } while (hop != circ->cpath); + + s = smartlist_join_strings(elements, verbose?" ":",", 0, NULL); + SMARTLIST_FOREACH(elements, char*, cp, tor_free(cp)); + smartlist_free(elements); + return s; +} + +/** If verbose is false, allocate and return a comma-separated + * list of the currently built elements of circ. If + * verbose is true, also list information about link status in + * a more verbose format using spaces. + */ +char * +circuit_list_path(origin_circuit_t *circ, int verbose) +{ + return circuit_list_path_impl(circ, verbose, 0); +} + +/** Allocate and return a comma-separated list of the currently built elements + * of circ, giving each as a verbose nickname. + */ +char * +circuit_list_path_for_controller(origin_circuit_t *circ) +{ + return circuit_list_path_impl(circ, 0, 1); +} + +/** Log, at severity severity, the nicknames of each router in + * circ's cpath. Also log the length of the cpath, and the intended + * exit point. + */ +void +circuit_log_path(int severity, unsigned int domain, origin_circuit_t *circ) +{ + char *s = circuit_list_path(circ,1); + tor_log(severity,domain,"%s",s); + tor_free(s); +} + +/** Tell the rep(utation)hist(ory) module about the status of the links + * in circ. Hops that have become OPEN are marked as successfully + * extended; the _first_ hop that isn't open (if any) is marked as + * unable to extend. + */ +/* XXXX Someday we should learn from OR circuits too. */ +void +circuit_rep_hist_note_result(origin_circuit_t *circ) +{ + crypt_path_t *hop; + const char *prev_digest = NULL; + hop = circ->cpath; + if (!hop) /* circuit hasn't started building yet. */ + return; + if (server_mode(get_options())) { + const routerinfo_t *me = router_get_my_routerinfo(); + if (!me) + return; + prev_digest = me->cache_info.identity_digest; + } + do { + const node_t *node = node_get_by_id(hop->extend_info->identity_digest); + if (node) { /* Why do we check this? We know the identity. -NM XXXX */ + if (prev_digest) { + if (hop->state == CPATH_STATE_OPEN) + rep_hist_note_extend_succeeded(prev_digest, node->identity); + else { + rep_hist_note_extend_failed(prev_digest, node->identity); + break; + } + } + prev_digest = node->identity; + } else { + prev_digest = NULL; + } + hop=hop->next; + } while (hop!=circ->cpath); +} + +#ifdef CURVE25519_ENABLED +/** Return 1 iff at least one node in circ's cpath supports ntor. */ +static int +circuit_cpath_supports_ntor(const origin_circuit_t *circ) +{ + crypt_path_t *head = circ->cpath, *cpath = circ->cpath; + + cpath = head; + do { + if (cpath->extend_info && + !tor_mem_is_zero( + (const char*)cpath->extend_info->curve25519_onion_key.public_key, + CURVE25519_PUBKEY_LEN)) + return 1; + + cpath = cpath->next; + } while (cpath != head); + + return 0; +} +#else +#define circuit_cpath_supports_ntor(circ) 0 +#endif + +/** Pick all the entries in our cpath. Stop and return 0 when we're + * happy, or return -1 if an error occurs. */ +static int +onion_populate_cpath(origin_circuit_t *circ) +{ + int n_tries = 0; +#ifdef CURVE25519_ENABLED + const int using_ntor = circuits_can_use_ntor(); +#else + const int using_ntor = 0; +#endif + +#define MAX_POPULATE_ATTEMPTS 32 + + while (1) { + int r = onion_extend_cpath(circ); + if (r < 0) { + log_info(LD_CIRC,"Generating cpath hop failed."); + return -1; + } + if (r == 1) { + /* This circuit doesn't need/shouldn't be forced to have an ntor hop */ + if (circ->build_state->desired_path_len <= 1 || ! using_ntor) + return 0; + + /* This circuit has an ntor hop. great! */ + if (circuit_cpath_supports_ntor(circ)) + return 0; + + /* No node in the circuit supports ntor. Have we already tried too many + * times? */ + if (++n_tries >= MAX_POPULATE_ATTEMPTS) + break; + + /* Clear the path and retry */ + circuit_clear_cpath(circ); + } + } + log_warn(LD_CIRC, "I tried for %d times, but I couldn't build a %d-hop " + "circuit with at least one node that supports ntor.", + MAX_POPULATE_ATTEMPTS, + circ->build_state->desired_path_len); + + return -1; +} + +/** Create and return a new origin circuit. Initialize its purpose and + * build-state based on our arguments. The flags argument is a + * bitfield of CIRCLAUNCH_* flags. */ +origin_circuit_t * +origin_circuit_init(uint8_t purpose, int flags) +{ + /* sets circ->p_circ_id and circ->p_chan */ + origin_circuit_t *circ = origin_circuit_new(); + circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_CHAN_WAIT); + circ->build_state = tor_malloc_zero(sizeof(cpath_build_state_t)); + circ->build_state->onehop_tunnel = + ((flags & CIRCLAUNCH_ONEHOP_TUNNEL) ? 1 : 0); + circ->build_state->need_uptime = + ((flags & CIRCLAUNCH_NEED_UPTIME) ? 1 : 0); + circ->build_state->need_capacity = + ((flags & CIRCLAUNCH_NEED_CAPACITY) ? 1 : 0); + circ->build_state->is_internal = + ((flags & CIRCLAUNCH_IS_INTERNAL) ? 1 : 0); + circ->base_.purpose = purpose; + return circ; +} + +/** Build a new circuit for purpose. If exit + * is defined, then use that as your exit router, else choose a suitable + * exit node. + * + * Also launch a connection to the first OR in the chosen path, if + * it's not open already. + */ +origin_circuit_t * +circuit_establish_circuit(uint8_t purpose, extend_info_t *exit, int flags) +{ + origin_circuit_t *circ; + int err_reason = 0; + + circ = origin_circuit_init(purpose, flags); + + if (onion_pick_cpath_exit(circ, exit) < 0 || + onion_populate_cpath(circ) < 0) { + circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_NOPATH); + return NULL; + } + + control_event_circuit_status(circ, CIRC_EVENT_LAUNCHED, 0); + + if ((err_reason = circuit_handle_first_hop(circ)) < 0) { + circuit_mark_for_close(TO_CIRCUIT(circ), -err_reason); + return NULL; + } + return circ; +} + +/** Start establishing the first hop of our circuit. Figure out what + * OR we should connect to, and if necessary start the connection to + * it. If we're already connected, then send the 'create' cell. + * Return 0 for ok, -reason if circ should be marked-for-close. */ +int +circuit_handle_first_hop(origin_circuit_t *circ) +{ + crypt_path_t *firsthop; + channel_t *n_chan; + int err_reason = 0; + const char *msg = NULL; + int should_launch = 0; + + firsthop = onion_next_hop_in_cpath(circ->cpath); + tor_assert(firsthop); + tor_assert(firsthop->extend_info); + + /* now see if we're already connected to the first OR in 'route' */ + log_debug(LD_CIRC,"Looking for firsthop '%s'", + fmt_addrport(&firsthop->extend_info->addr, + firsthop->extend_info->port)); + + n_chan = channel_get_for_extend(firsthop->extend_info->identity_digest, + &firsthop->extend_info->addr, + &msg, + &should_launch); + + if (!n_chan) { + /* not currently connected in a useful way. */ + log_info(LD_CIRC, "Next router is %s: %s", + safe_str_client(extend_info_describe(firsthop->extend_info)), + msg?msg:"???"); + circ->base_.n_hop = extend_info_dup(firsthop->extend_info); + + if (should_launch) { + if (circ->build_state->onehop_tunnel) + control_event_bootstrap(BOOTSTRAP_STATUS_CONN_DIR, 0); + n_chan = channel_connect_for_circuit( + &firsthop->extend_info->addr, + firsthop->extend_info->port, + firsthop->extend_info->identity_digest); + if (!n_chan) { /* connect failed, forget the whole thing */ + log_info(LD_CIRC,"connect to firsthop failed. Closing."); + return -END_CIRC_REASON_CONNECTFAILED; + } + } + + log_debug(LD_CIRC,"connecting in progress (or finished). Good."); + /* return success. The onion/circuit/etc will be taken care of + * automatically (may already have been) whenever n_chan reaches + * OR_CONN_STATE_OPEN. + */ + return 0; + } else { /* it's already open. use it. */ + tor_assert(!circ->base_.n_hop); + circ->base_.n_chan = n_chan; + log_debug(LD_CIRC,"Conn open. Delivering first onion skin."); + if ((err_reason = circuit_send_next_onion_skin(circ)) < 0) { + log_info(LD_CIRC,"circuit_send_next_onion_skin failed."); + return err_reason; + } + } + return 0; +} + +/** Find any circuits that are waiting on or_conn to become + * open and get them to send their create cells forward. + * + * Status is 1 if connect succeeded, or 0 if connect failed. + */ +void +circuit_n_chan_done(channel_t *chan, int status) +{ + smartlist_t *pending_circs; + int err_reason = 0; + + tor_assert(chan); + + log_debug(LD_CIRC,"chan to %s/%s, status=%d", + chan->nickname ? chan->nickname : "NULL", + channel_get_canonical_remote_descr(chan), status); + + pending_circs = smartlist_new(); + circuit_get_all_pending_on_channel(pending_circs, chan); + + SMARTLIST_FOREACH_BEGIN(pending_circs, circuit_t *, circ) + { + /* These checks are redundant wrt get_all_pending_on_or_conn, but I'm + * leaving them in in case it's possible for the status of a circuit to + * change as we're going down the list. */ + if (circ->marked_for_close || circ->n_chan || !circ->n_hop || + circ->state != CIRCUIT_STATE_CHAN_WAIT) + continue; + + if (tor_digest_is_zero(circ->n_hop->identity_digest)) { + /* Look at addr/port. This is an unkeyed connection. */ + if (!channel_matches_extend_info(chan, circ->n_hop)) + continue; + } else { + /* We expected a key. See if it's the right one. */ + if (tor_memneq(chan->identity_digest, + circ->n_hop->identity_digest, DIGEST_LEN)) + continue; + } + if (!status) { /* chan failed; close circ */ + log_info(LD_CIRC,"Channel failed; closing circ."); + circuit_mark_for_close(circ, END_CIRC_REASON_CHANNEL_CLOSED); + continue; + } + log_debug(LD_CIRC, "Found circ, sending create cell."); + /* circuit_deliver_create_cell will set n_circ_id and add us to + * chan_circuid_circuit_map, so we don't need to call + * set_circid_chan here. */ + circ->n_chan = chan; + extend_info_free(circ->n_hop); + circ->n_hop = NULL; + + if (CIRCUIT_IS_ORIGIN(circ)) { + if ((err_reason = + circuit_send_next_onion_skin(TO_ORIGIN_CIRCUIT(circ))) < 0) { + log_info(LD_CIRC, + "send_next_onion_skin failed; circuit marked for closing."); + circuit_mark_for_close(circ, -err_reason); + continue; + /* XXX could this be bad, eg if next_onion_skin failed because conn + * died? */ + } + } else { + /* pull the create cell out of circ->n_chan_create_cell, and send it */ + tor_assert(circ->n_chan_create_cell); + if (circuit_deliver_create_cell(circ, circ->n_chan_create_cell, 1)<0) { + circuit_mark_for_close(circ, END_CIRC_REASON_RESOURCELIMIT); + continue; + } + tor_free(circ->n_chan_create_cell); + circuit_set_state(circ, CIRCUIT_STATE_OPEN); + } + } + SMARTLIST_FOREACH_END(circ); + + smartlist_free(pending_circs); +} + +/** Find a new circid that isn't currently in use on the circ->n_chan + * for the outgoing + * circuit circ, and deliver the cell create_cell to this + * circuit. If relayed is true, this is a create cell somebody + * gave us via an EXTEND cell, so we shouldn't worry if we don't understand + * it. Return -1 if we failed to find a suitable circid, else return 0. + */ +static int +circuit_deliver_create_cell(circuit_t *circ, const create_cell_t *create_cell, + int relayed) +{ + cell_t cell; + circid_t id; + int r; + + tor_assert(circ); + tor_assert(circ->n_chan); + tor_assert(create_cell); + tor_assert(create_cell->cell_type == CELL_CREATE || + create_cell->cell_type == CELL_CREATE_FAST || + create_cell->cell_type == CELL_CREATE2); + + id = get_unique_circ_id_by_chan(circ->n_chan); + if (!id) { + log_warn(LD_CIRC,"failed to get unique circID."); + return -1; + } + log_debug(LD_CIRC,"Chosen circID %u.", (unsigned)id); + circuit_set_n_circid_chan(circ, id, circ->n_chan); + + memset(&cell, 0, sizeof(cell_t)); + r = relayed ? create_cell_format_relayed(&cell, create_cell) + : create_cell_format(&cell, create_cell); + if (r < 0) { + log_warn(LD_CIRC,"Couldn't format create cell"); + return -1; + } + cell.circ_id = circ->n_circ_id; + + append_cell_to_circuit_queue(circ, circ->n_chan, &cell, + CELL_DIRECTION_OUT, 0); + + if (CIRCUIT_IS_ORIGIN(circ)) { + /* Update began timestamp for circuits starting their first hop */ + if (TO_ORIGIN_CIRCUIT(circ)->cpath->state == CPATH_STATE_CLOSED) { + if (circ->n_chan->state != CHANNEL_STATE_OPEN) { + log_warn(LD_CIRC, + "Got first hop for a circuit without an opened channel. " + "State: %s.", channel_state_to_string(circ->n_chan->state)); + tor_fragile_assert(); + } + + tor_gettimeofday(&circ->timestamp_began); + } + + /* mark it so it gets better rate limiting treatment. */ + channel_timestamp_client(circ->n_chan); + } + + return 0; +} + +/** We've decided to start our reachability testing. If all + * is set, log this to the user. Return 1 if we did, or 0 if + * we chose not to log anything. */ +int +inform_testing_reachability(void) +{ + char dirbuf[128]; + const routerinfo_t *me = router_get_my_routerinfo(); + if (!me) + return 0; + control_event_server_status(LOG_NOTICE, + "CHECKING_REACHABILITY ORADDRESS=%s:%d", + me->address, me->or_port); + if (me->dir_port) { + tor_snprintf(dirbuf, sizeof(dirbuf), " and DirPort %s:%d", + me->address, me->dir_port); + control_event_server_status(LOG_NOTICE, + "CHECKING_REACHABILITY DIRADDRESS=%s:%d", + me->address, me->dir_port); + } + log_notice(LD_OR, "Now checking whether ORPort %s:%d%s %s reachable... " + "(this may take up to %d minutes -- look for log " + "messages indicating success)", + me->address, me->or_port, + me->dir_port ? dirbuf : "", + me->dir_port ? "are" : "is", + TIMEOUT_UNTIL_UNREACHABILITY_COMPLAINT/60); + + return 1; +} + +/** Return true iff we should send a create_fast cell to start building a given + * circuit */ +static INLINE int +should_use_create_fast_for_circuit(origin_circuit_t *circ) +{ + const or_options_t *options = get_options(); + tor_assert(circ->cpath); + tor_assert(circ->cpath->extend_info); + + if (!circ->cpath->extend_info->onion_key) + return 1; /* our hand is forced: only a create_fast will work. */ + if (public_server_mode(options)) { + /* We're a server, and we know an onion key. We can choose. + * Prefer to blend our circuit into the other circuits we are + * creating on behalf of others. */ + return 0; + } + if (options->FastFirstHopPK == -1) { + /* option is "auto", so look at the consensus. */ + return networkstatus_get_param(NULL, "usecreatefast", 1, 0, 1); + } + + return options->FastFirstHopPK; +} + +/** Return true if circ is the type of circuit we want to count + * timeouts from. In particular, we want it to have not completed yet + * (already completing indicates we cannibalized it), and we want it to + * have exactly three hops. + */ +int +circuit_timeout_want_to_count_circ(origin_circuit_t *circ) +{ + return !circ->has_opened + && circ->build_state->desired_path_len == DEFAULT_ROUTE_LEN; +} + +#ifdef CURVE25519_ENABLED +/** Return true if the ntor handshake is enabled in the configuration, or if + * it's been set to "auto" in the configuration and it's enabled in the + * consensus. */ +static int +circuits_can_use_ntor(void) +{ + const or_options_t *options = get_options(); + if (options->UseNTorHandshake != -1) + return options->UseNTorHandshake; + return networkstatus_get_param(NULL, "UseNTorHandshake", 0, 0, 1); +} +#endif + +/** Decide whether to use a TAP or ntor handshake for connecting to ei + * directly, and set *cell_type_out and *handshake_type_out + * accordingly. */ +static void +circuit_pick_create_handshake(uint8_t *cell_type_out, + uint16_t *handshake_type_out, + const extend_info_t *ei) +{ +#ifdef CURVE25519_ENABLED + if (!tor_mem_is_zero((const char*)ei->curve25519_onion_key.public_key, + CURVE25519_PUBKEY_LEN) && + circuits_can_use_ntor()) { + *cell_type_out = CELL_CREATE2; + *handshake_type_out = ONION_HANDSHAKE_TYPE_NTOR; + return; + } +#else + (void) ei; +#endif + + *cell_type_out = CELL_CREATE; + *handshake_type_out = ONION_HANDSHAKE_TYPE_TAP; +} + +/** Decide whether to use a TAP or ntor handshake for connecting to ei + * directly, and set *handshake_type_out accordingly. Decide whether, + * in extending through node to do so, we should use an EXTEND2 or an + * EXTEND cell to do so, and set *cell_type_out and + * *create_cell_type_out accordingly. */ +static void +circuit_pick_extend_handshake(uint8_t *cell_type_out, + uint8_t *create_cell_type_out, + uint16_t *handshake_type_out, + const node_t *node_prev, + const extend_info_t *ei) +{ + uint8_t t; + circuit_pick_create_handshake(&t, handshake_type_out, ei); + /* XXXX024 The check for whether the node has a curve25519 key is a bad + * proxy for whether it can do extend2 cells; once a version that + * handles extend2 cells is out, remove it. */ + if (node_prev && + *handshake_type_out != ONION_HANDSHAKE_TYPE_TAP && + (node_has_curve25519_onion_key(node_prev) || + (node_prev->rs && node_prev->rs->version_supports_extend2_cells))) { + *cell_type_out = RELAY_COMMAND_EXTEND2; + *create_cell_type_out = CELL_CREATE2; + } else { + *cell_type_out = RELAY_COMMAND_EXTEND; + *create_cell_type_out = CELL_CREATE; + } +} + +/** This is the backbone function for building circuits. + * + * If circ's first hop is closed, then we need to build a create + * cell and send it forward. + * + * Otherwise, we need to build a relay extend cell and send it + * forward. + * + * Return -reason if we want to tear down circ, else return 0. + */ +int +circuit_send_next_onion_skin(origin_circuit_t *circ) +{ + crypt_path_t *hop; + const node_t *node; + + tor_assert(circ); + + if (circ->cpath->state == CPATH_STATE_CLOSED) { + /* This is the first hop. */ + create_cell_t cc; + int fast; + int len; + log_debug(LD_CIRC,"First skin; sending create cell."); + memset(&cc, 0, sizeof(cc)); + if (circ->build_state->onehop_tunnel) + control_event_bootstrap(BOOTSTRAP_STATUS_ONEHOP_CREATE, 0); + else + control_event_bootstrap(BOOTSTRAP_STATUS_CIRCUIT_CREATE, 0); + + node = node_get_by_id(circ->base_.n_chan->identity_digest); + fast = should_use_create_fast_for_circuit(circ); + if (!fast) { + /* We are an OR and we know the right onion key: we should + * send a create cell. + */ + circuit_pick_create_handshake(&cc.cell_type, &cc.handshake_type, + circ->cpath->extend_info); + note_request("cell: create", 1); + } else { + /* We are not an OR, and we're building the first hop of a circuit to a + * new OR: we can be speedy and use CREATE_FAST to save an RSA operation + * and a DH operation. */ + cc.cell_type = CELL_CREATE_FAST; + cc.handshake_type = ONION_HANDSHAKE_TYPE_FAST; + note_request("cell: create fast", 1); + } + + len = onion_skin_create(cc.handshake_type, + circ->cpath->extend_info, + &circ->cpath->handshake_state, + cc.onionskin); + if (len < 0) { + log_warn(LD_CIRC,"onion_skin_create (first hop) failed."); + return - END_CIRC_REASON_INTERNAL; + } + cc.handshake_len = len; + + if (circuit_deliver_create_cell(TO_CIRCUIT(circ), &cc, 0) < 0) + return - END_CIRC_REASON_RESOURCELIMIT; + + circ->cpath->state = CPATH_STATE_AWAITING_KEYS; + circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_BUILDING); + log_info(LD_CIRC,"First hop: finished sending %s cell to '%s'", + fast ? "CREATE_FAST" : "CREATE", + node ? node_describe(node) : ""); + } else { + extend_cell_t ec; + int len; + tor_assert(circ->cpath->state == CPATH_STATE_OPEN); + tor_assert(circ->base_.state == CIRCUIT_STATE_BUILDING); + log_debug(LD_CIRC,"starting to send subsequent skin."); + hop = onion_next_hop_in_cpath(circ->cpath); + memset(&ec, 0, sizeof(ec)); + if (!hop) { + /* done building the circuit. whew. */ + circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_OPEN); + if (circuit_timeout_want_to_count_circ(circ)) { + struct timeval end; + long timediff; + tor_gettimeofday(&end); + timediff = tv_mdiff(&circ->base_.timestamp_began, &end); + + /* + * If the circuit build time is much greater than we would have cut + * it off at, we probably had a suspend event along this codepath, + * and we should discard the value. + */ + if (timediff < 0 || + timediff > 2*get_circuit_build_close_time_ms()+1000) { + log_notice(LD_CIRC, "Strange value for circuit build time: %ldmsec. " + "Assuming clock jump. Purpose %d (%s)", timediff, + circ->base_.purpose, + circuit_purpose_to_string(circ->base_.purpose)); + } else if (!circuit_build_times_disabled()) { + /* Only count circuit times if the network is live */ + if (circuit_build_times_network_check_live( + get_circuit_build_times())) { + circuit_build_times_add_time(get_circuit_build_times_mutable(), + (build_time_t)timediff); + circuit_build_times_set_timeout(get_circuit_build_times_mutable()); + } + + if (circ->base_.purpose != CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT) { + circuit_build_times_network_circ_success( + get_circuit_build_times_mutable()); + } + } + } + log_info(LD_CIRC,"circuit built!"); + circuit_reset_failure_count(0); + + if (circ->build_state->onehop_tunnel || circ->has_opened) { + control_event_bootstrap(BOOTSTRAP_STATUS_REQUESTING_STATUS, 0); + } + + pathbias_count_build_success(circ); + circuit_rep_hist_note_result(circ); + circuit_has_opened(circ); /* do other actions as necessary */ + + if (!can_complete_circuit && !circ->build_state->onehop_tunnel) { + const or_options_t *options = get_options(); + can_complete_circuit=1; + /* FFFF Log a count of known routers here */ + log_notice(LD_GENERAL, + "Tor has successfully opened a circuit. " + "Looks like client functionality is working."); + control_event_bootstrap(BOOTSTRAP_STATUS_DONE, 0); + control_event_client_status(LOG_NOTICE, "CIRCUIT_ESTABLISHED"); + clear_broken_connection_map(1); + if (server_mode(options) && !check_whether_orport_reachable()) { + inform_testing_reachability(); + consider_testing_reachability(1, 1); + } + } + + /* We're done with measurement circuits here. Just close them */ + if (circ->base_.purpose == CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT) { + circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_FINISHED); + } + return 0; + } + + if (tor_addr_family(&hop->extend_info->addr) != AF_INET) { + log_warn(LD_BUG, "Trying to extend to a non-IPv4 address."); + return - END_CIRC_REASON_INTERNAL; + } + + { + const node_t *prev_node; + prev_node = node_get_by_id(hop->prev->extend_info->identity_digest); + circuit_pick_extend_handshake(&ec.cell_type, + &ec.create_cell.cell_type, + &ec.create_cell.handshake_type, + prev_node, + hop->extend_info); + } + + tor_addr_copy(&ec.orport_ipv4.addr, &hop->extend_info->addr); + ec.orport_ipv4.port = hop->extend_info->port; + tor_addr_make_unspec(&ec.orport_ipv6.addr); + memcpy(ec.node_id, hop->extend_info->identity_digest, DIGEST_LEN); + + len = onion_skin_create(ec.create_cell.handshake_type, + hop->extend_info, + &hop->handshake_state, + ec.create_cell.onionskin); + if (len < 0) { + log_warn(LD_CIRC,"onion_skin_create failed."); + return - END_CIRC_REASON_INTERNAL; + } + ec.create_cell.handshake_len = len; + + log_info(LD_CIRC,"Sending extend relay cell."); + note_request("cell: extend", 1); + { + uint8_t command = 0; + uint16_t payload_len=0; + uint8_t payload[RELAY_PAYLOAD_SIZE]; + if (extend_cell_format(&command, &payload_len, payload, &ec)<0) { + log_warn(LD_CIRC,"Couldn't format extend cell"); + return -END_CIRC_REASON_INTERNAL; + } + + /* send it to hop->prev, because it will transfer + * it to a create cell and then send to hop */ + if (relay_send_command_from_edge(0, TO_CIRCUIT(circ), + command, + (char*)payload, payload_len, + hop->prev) < 0) + return 0; /* circuit is closed */ + } + hop->state = CPATH_STATE_AWAITING_KEYS; + } + return 0; +} + +/** Our clock just jumped by seconds_elapsed. Assume + * something has also gone wrong with our network: notify the user, + * and abandon all not-yet-used circuits. */ +void +circuit_note_clock_jumped(int seconds_elapsed) +{ + int severity = server_mode(get_options()) ? LOG_WARN : LOG_NOTICE; + tor_log(severity, LD_GENERAL, "Your system clock just jumped %d seconds %s; " + "assuming established circuits no longer work.", + seconds_elapsed >=0 ? seconds_elapsed : -seconds_elapsed, + seconds_elapsed >=0 ? "forward" : "backward"); + control_event_general_status(LOG_WARN, "CLOCK_JUMPED TIME=%d", + seconds_elapsed); + can_complete_circuit=0; /* so it'll log when it works again */ + control_event_client_status(severity, "CIRCUIT_NOT_ESTABLISHED REASON=%s", + "CLOCK_JUMPED"); + circuit_mark_all_unused_circs(); + circuit_mark_all_dirty_circs_as_unusable(); +} + +/** Take the 'extend' cell, pull out addr/port plus the onion + * skin and identity digest for the next hop. If we're already connected, + * pass the onion skin to the next hop using a create cell; otherwise + * launch a new OR connection, and circ will notice when the + * connection succeeds or fails. + * + * Return -1 if we want to warn and tear down the circuit, else return 0. + */ +int +circuit_extend(cell_t *cell, circuit_t *circ) +{ + channel_t *n_chan; + relay_header_t rh; + extend_cell_t ec; + const char *msg = NULL; + int should_launch = 0; + + if (circ->n_chan) { + log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, + "n_chan already set. Bug/attack. Closing."); + return -1; + } + if (circ->n_hop) { + log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, + "conn to next hop already launched. Bug/attack. Closing."); + return -1; + } + + if (!server_mode(get_options())) { + log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, + "Got an extend cell, but running as a client. Closing."); + return -1; + } + + relay_header_unpack(&rh, cell->payload); + + if (extend_cell_parse(&ec, rh.command, + cell->payload+RELAY_HEADER_SIZE, + rh.length) < 0) { + log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, + "Can't parse extend cell. Closing circuit."); + return -1; + } + + if (!ec.orport_ipv4.port || tor_addr_is_null(&ec.orport_ipv4.addr)) { + log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, + "Client asked me to extend to zero destination port or addr."); + return -1; + } + + if (tor_addr_is_internal(&ec.orport_ipv4.addr, 0) && + !get_options()->ExtendAllowPrivateAddresses) { + log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, + "Client asked me to extend to a private address"); + return -1; + } + + /* Check if they asked us for 0000..0000. We support using + * an empty fingerprint for the first hop (e.g. for a bridge relay), + * but we don't want to let people send us extend cells for empty + * fingerprints -- a) because it opens the user up to a mitm attack, + * and b) because it lets an attacker force the relay to hold open a + * new TLS connection for each extend request. */ + if (tor_digest_is_zero((const char*)ec.node_id)) { + log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, + "Client asked me to extend without specifying an id_digest."); + return -1; + } + + /* Next, check if we're being asked to connect to the hop that the + * extend cell came from. There isn't any reason for that, and it can + * assist circular-path attacks. */ + if (tor_memeq(ec.node_id, + TO_OR_CIRCUIT(circ)->p_chan->identity_digest, + DIGEST_LEN)) { + log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, + "Client asked me to extend back to the previous hop."); + return -1; + } + + n_chan = channel_get_for_extend((const char*)ec.node_id, + &ec.orport_ipv4.addr, + &msg, + &should_launch); + + if (!n_chan) { + log_debug(LD_CIRC|LD_OR,"Next router (%s): %s", + fmt_addrport(&ec.orport_ipv4.addr,ec.orport_ipv4.port), + msg?msg:"????"); + + circ->n_hop = extend_info_new(NULL /*nickname*/, + (const char*)ec.node_id, + NULL /*onion_key*/, + NULL /*curve25519_key*/, + &ec.orport_ipv4.addr, + ec.orport_ipv4.port); + + circ->n_chan_create_cell = tor_memdup(&ec.create_cell, + sizeof(ec.create_cell)); + + circuit_set_state(circ, CIRCUIT_STATE_CHAN_WAIT); + + if (should_launch) { + /* we should try to open a connection */ + n_chan = channel_connect_for_circuit(&ec.orport_ipv4.addr, + ec.orport_ipv4.port, + (const char*)ec.node_id); + if (!n_chan) { + log_info(LD_CIRC,"Launching n_chan failed. Closing circuit."); + circuit_mark_for_close(circ, END_CIRC_REASON_CONNECTFAILED); + return 0; + } + log_debug(LD_CIRC,"connecting in progress (or finished). Good."); + } + /* return success. The onion/circuit/etc will be taken care of + * automatically (may already have been) whenever n_chan reaches + * OR_CONN_STATE_OPEN. + */ + return 0; + } + + tor_assert(!circ->n_hop); /* Connection is already established. */ + circ->n_chan = n_chan; + log_debug(LD_CIRC, + "n_chan is %s", + channel_get_canonical_remote_descr(n_chan)); + + if (circuit_deliver_create_cell(circ, &ec.create_cell, 1) < 0) + return -1; + + return 0; +} + +/** Initialize cpath-\>{f|b}_{crypto|digest} from the key material in + * key_data. key_data must contain CPATH_KEY_MATERIAL bytes, which are + * used as follows: + * - 20 to initialize f_digest + * - 20 to initialize b_digest + * - 16 to key f_crypto + * - 16 to key b_crypto + * + * (If 'reverse' is true, then f_XX and b_XX are swapped.) + */ +int +circuit_init_cpath_crypto(crypt_path_t *cpath, const char *key_data, + int reverse) +{ + crypto_digest_t *tmp_digest; + crypto_cipher_t *tmp_crypto; + + tor_assert(cpath); + tor_assert(key_data); + tor_assert(!(cpath->f_crypto || cpath->b_crypto || + cpath->f_digest || cpath->b_digest)); + + cpath->f_digest = crypto_digest_new(); + crypto_digest_add_bytes(cpath->f_digest, key_data, DIGEST_LEN); + cpath->b_digest = crypto_digest_new(); + crypto_digest_add_bytes(cpath->b_digest, key_data+DIGEST_LEN, DIGEST_LEN); + + if (!(cpath->f_crypto = + crypto_cipher_new(key_data+(2*DIGEST_LEN)))) { + log_warn(LD_BUG,"Forward cipher initialization failed."); + return -1; + } + if (!(cpath->b_crypto = + crypto_cipher_new(key_data+(2*DIGEST_LEN)+CIPHER_KEY_LEN))) { + log_warn(LD_BUG,"Backward cipher initialization failed."); + return -1; + } + + if (reverse) { + tmp_digest = cpath->f_digest; + cpath->f_digest = cpath->b_digest; + cpath->b_digest = tmp_digest; + tmp_crypto = cpath->f_crypto; + cpath->f_crypto = cpath->b_crypto; + cpath->b_crypto = tmp_crypto; + } + + return 0; +} + +/** A "created" cell reply came back to us on circuit circ. + * (The body of reply varies depending on what sort of handshake + * this is.) + * + * Calculate the appropriate keys and digests, make sure KH is + * correct, and initialize this hop of the cpath. + * + * Return - reason if we want to mark circ for close, else return 0. + */ +int +circuit_finish_handshake(origin_circuit_t *circ, + const created_cell_t *reply) +{ + char keys[CPATH_KEY_MATERIAL_LEN]; + crypt_path_t *hop; + int rv; + + if ((rv = pathbias_count_build_attempt(circ)) < 0) + return rv; + + if (circ->cpath->state == CPATH_STATE_AWAITING_KEYS) { + hop = circ->cpath; + } else { + hop = onion_next_hop_in_cpath(circ->cpath); + if (!hop) { /* got an extended when we're all done? */ + log_warn(LD_PROTOCOL,"got extended when circ already built? Closing."); + return - END_CIRC_REASON_TORPROTOCOL; + } + } + tor_assert(hop->state == CPATH_STATE_AWAITING_KEYS); + + { + if (onion_skin_client_handshake(hop->handshake_state.tag, + &hop->handshake_state, + reply->reply, reply->handshake_len, + (uint8_t*)keys, sizeof(keys), + (uint8_t*)hop->rend_circ_nonce) < 0) { + log_warn(LD_CIRC,"onion_skin_client_handshake failed."); + return -END_CIRC_REASON_TORPROTOCOL; + } + } + + onion_handshake_state_release(&hop->handshake_state); + + if (circuit_init_cpath_crypto(hop, keys, 0)<0) { + return -END_CIRC_REASON_TORPROTOCOL; + } + + hop->state = CPATH_STATE_OPEN; + log_info(LD_CIRC,"Finished building circuit hop:"); + circuit_log_path(LOG_INFO,LD_CIRC,circ); + control_event_circuit_status(circ, CIRC_EVENT_EXTENDED, 0); + + return 0; +} + +/** We received a relay truncated cell on circ. + * + * Since we don't send truncates currently, getting a truncated + * means that a connection broke or an extend failed. For now, + * just give up: force circ to close, and return 0. + */ +int +circuit_truncated(origin_circuit_t *circ, crypt_path_t *layer, int reason) +{ +// crypt_path_t *victim; +// connection_t *stream; + + tor_assert(circ); + tor_assert(layer); + + /* XXX Since we don't send truncates currently, getting a truncated + * means that a connection broke or an extend failed. For now, + * just give up. + */ + circuit_mark_for_close(TO_CIRCUIT(circ), + END_CIRC_REASON_FLAG_REMOTE|reason); + return 0; + +#if 0 + while (layer->next != circ->cpath) { + /* we need to clear out layer->next */ + victim = layer->next; + log_debug(LD_CIRC, "Killing a layer of the cpath."); + + for (stream = circ->p_streams; stream; stream=stream->next_stream) { + if (stream->cpath_layer == victim) { + log_info(LD_APP, "Marking stream %d for close because of truncate.", + stream->stream_id); + /* no need to send 'end' relay cells, + * because the other side's already dead + */ + connection_mark_unattached_ap(stream, END_STREAM_REASON_DESTROY); + } + } + + layer->next = victim->next; + circuit_free_cpath_node(victim); + } + + log_info(LD_CIRC, "finished"); + return 0; +#endif +} + +/** Given a response payload and keys, initialize, then send a created + * cell back. + */ +int +onionskin_answer(or_circuit_t *circ, + const created_cell_t *created_cell, + const char *keys, + const uint8_t *rend_circ_nonce) +{ + cell_t cell; + crypt_path_t *tmp_cpath; + + if (created_cell_format(&cell, created_cell) < 0) { + log_warn(LD_BUG,"couldn't format created cell (type=%d, len=%d)", + (int)created_cell->cell_type, (int)created_cell->handshake_len); + return -1; + } + cell.circ_id = circ->p_circ_id; + + tmp_cpath = tor_malloc_zero(sizeof(crypt_path_t)); + tmp_cpath->magic = CRYPT_PATH_MAGIC; + + circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_OPEN); + + log_debug(LD_CIRC,"init digest forward 0x%.8x, backward 0x%.8x.", + (unsigned int)get_uint32(keys), + (unsigned int)get_uint32(keys+20)); + if (circuit_init_cpath_crypto(tmp_cpath, keys, 0)<0) { + log_warn(LD_BUG,"Circuit initialization failed"); + tor_free(tmp_cpath); + return -1; + } + circ->n_digest = tmp_cpath->f_digest; + circ->n_crypto = tmp_cpath->f_crypto; + circ->p_digest = tmp_cpath->b_digest; + circ->p_crypto = tmp_cpath->b_crypto; + tmp_cpath->magic = 0; + tor_free(tmp_cpath); + + memcpy(circ->rend_circ_nonce, rend_circ_nonce, DIGEST_LEN); + + circ->is_first_hop = (created_cell->cell_type == CELL_CREATED_FAST); + + append_cell_to_circuit_queue(TO_CIRCUIT(circ), + circ->p_chan, &cell, CELL_DIRECTION_IN, 0); + log_debug(LD_CIRC,"Finished sending '%s' cell.", + circ->is_first_hop ? "created_fast" : "created"); + + if (!channel_is_local(circ->p_chan) && + !channel_is_outgoing(circ->p_chan)) { + /* record that we could process create cells from a non-local conn + * that we didn't initiate; presumably this means that create cells + * can reach us too. */ + router_orport_found_reachable(); + } + + return 0; +} + +/** Choose a length for a circuit of purpose purpose: three + the + * number of endpoints that would give something away about our destination. + * + * If the routerlist nodes doesn't have enough routers + * to handle the desired path length, return -1. + */ +static int +new_route_len(uint8_t purpose, extend_info_t *exit, smartlist_t *nodes) +{ + int num_acceptable_routers; + int routelen; + + tor_assert(nodes); + + routelen = DEFAULT_ROUTE_LEN; + if (exit && + purpose != CIRCUIT_PURPOSE_TESTING && + purpose != CIRCUIT_PURPOSE_S_ESTABLISH_INTRO) + routelen++; + + num_acceptable_routers = count_acceptable_nodes(nodes); + + log_debug(LD_CIRC,"Chosen route length %d (%d/%d routers suitable).", + routelen, num_acceptable_routers, smartlist_len(nodes)); + + if (num_acceptable_routers < routelen) { + log_info(LD_CIRC, + "Not enough acceptable routers (%d/%d). Discarding this circuit.", + num_acceptable_routers, routelen); + return -1; + } + + return routelen; +} + +/** Return a newly allocated list of uint16_t * for each predicted port not + * handled by a current circuit. */ +static smartlist_t * +circuit_get_unhandled_ports(time_t now) +{ + smartlist_t *dest = rep_hist_get_predicted_ports(now); + circuit_remove_handled_ports(dest); + return dest; +} + +/** Return 1 if we already have circuits present or on the way for + * all anticipated ports. Return 0 if we should make more. + * + * If we're returning 0, set need_uptime and need_capacity to + * indicate any requirements that the unhandled ports have. + */ +int +circuit_all_predicted_ports_handled(time_t now, int *need_uptime, + int *need_capacity) +{ + int i, enough; + uint16_t *port; + smartlist_t *sl = circuit_get_unhandled_ports(now); + smartlist_t *LongLivedServices = get_options()->LongLivedPorts; + tor_assert(need_uptime); + tor_assert(need_capacity); + // Always predict need_capacity + *need_capacity = 1; + enough = (smartlist_len(sl) == 0); + for (i = 0; i < smartlist_len(sl); ++i) { + port = smartlist_get(sl, i); + if (smartlist_contains_int_as_string(LongLivedServices, *port)) + *need_uptime = 1; + tor_free(port); + } + smartlist_free(sl); + return enough; +} + +/** Return 1 if node can handle one or more of the ports in + * needed_ports, else return 0. + */ +static int +node_handles_some_port(const node_t *node, smartlist_t *needed_ports) +{ /* XXXX MOVE */ + int i; + uint16_t port; + + for (i = 0; i < smartlist_len(needed_ports); ++i) { + addr_policy_result_t r; + /* alignment issues aren't a worry for this dereference, since + needed_ports is explicitly a smartlist of uint16_t's */ + port = *(uint16_t *)smartlist_get(needed_ports, i); + tor_assert(port); + if (node) + r = compare_tor_addr_to_node_policy(NULL, port, node); + else + continue; + if (r != ADDR_POLICY_REJECTED && r != ADDR_POLICY_PROBABLY_REJECTED) + return 1; + } + return 0; +} + +/** Return true iff conn needs another general circuit to be + * built. */ +static int +ap_stream_wants_exit_attention(connection_t *conn) +{ + entry_connection_t *entry; + if (conn->type != CONN_TYPE_AP) + return 0; + entry = TO_ENTRY_CONN(conn); + + if (conn->state == AP_CONN_STATE_CIRCUIT_WAIT && + !conn->marked_for_close && + !(entry->want_onehop) && /* ignore one-hop streams */ + !(entry->use_begindir) && /* ignore targeted dir fetches */ + !(entry->chosen_exit_name) && /* ignore defined streams */ + !connection_edge_is_rendezvous_stream(TO_EDGE_CONN(conn)) && + !circuit_stream_is_being_handled(TO_ENTRY_CONN(conn), 0, + MIN_CIRCUITS_HANDLING_STREAM)) + return 1; + return 0; +} + +/** Return a pointer to a suitable router to be the exit node for the + * general-purpose circuit we're about to build. + * + * Look through the connection array, and choose a router that maximizes + * the number of pending streams that can exit from this router. + * + * Return NULL if we can't find any suitable routers. + */ +static const node_t * +choose_good_exit_server_general(int need_uptime, int need_capacity) +{ + int *n_supported; + int n_pending_connections = 0; + smartlist_t *connections; + int best_support = -1; + int n_best_support=0; + const or_options_t *options = get_options(); + const smartlist_t *the_nodes; + const node_t *node=NULL; + + connections = get_connection_array(); + + /* Count how many connections are waiting for a circuit to be built. + * We use this for log messages now, but in the future we may depend on it. + */ + SMARTLIST_FOREACH(connections, connection_t *, conn, + { + if (ap_stream_wants_exit_attention(conn)) + ++n_pending_connections; + }); +// log_fn(LOG_DEBUG, "Choosing exit node; %d connections are pending", +// n_pending_connections); + /* Now we count, for each of the routers in the directory, how many + * of the pending connections could possibly exit from that + * router (n_supported[i]). (We can't be sure about cases where we + * don't know the IP address of the pending connection.) + * + * -1 means "Don't use this router at all." + */ + the_nodes = nodelist_get_list(); + n_supported = tor_malloc(sizeof(int)*smartlist_len(the_nodes)); + SMARTLIST_FOREACH_BEGIN(the_nodes, const node_t *, node) { + const int i = node_sl_idx; + if (router_digest_is_me(node->identity)) { + n_supported[i] = -1; +// log_fn(LOG_DEBUG,"Skipping node %s -- it's me.", router->nickname); + /* XXX there's probably a reverse predecessor attack here, but + * it's slow. should we take this out? -RD + */ + continue; + } + if (!node_has_descriptor(node)) { + n_supported[i] = -1; + continue; + } + if (!node->is_running || node->is_bad_exit) { + n_supported[i] = -1; + continue; /* skip routers that are known to be down or bad exits */ + } + if (node_get_purpose(node) != ROUTER_PURPOSE_GENERAL) { + /* never pick a non-general node as a random exit. */ + n_supported[i] = -1; + continue; + } + if (routerset_contains_node(options->ExcludeExitNodesUnion_, node)) { + n_supported[i] = -1; + continue; /* user asked us not to use it, no matter what */ + } + if (options->ExitNodes && + !routerset_contains_node(options->ExitNodes, node)) { + n_supported[i] = -1; + continue; /* not one of our chosen exit nodes */ + } + + if (node_is_unreliable(node, need_uptime, need_capacity, 0)) { + n_supported[i] = -1; + continue; /* skip routers that are not suitable. Don't worry if + * this makes us reject all the possible routers: if so, + * we'll retry later in this function with need_update and + * need_capacity set to 0. */ + } + if (!(node->is_valid || options->AllowInvalid_ & ALLOW_INVALID_EXIT)) { + /* if it's invalid and we don't want it */ + n_supported[i] = -1; +// log_fn(LOG_DEBUG,"Skipping node %s (index %d) -- invalid router.", +// router->nickname, i); + continue; /* skip invalid routers */ + } + if (options->ExcludeSingleHopRelays && + node_allows_single_hop_exits(node)) { + n_supported[i] = -1; + continue; + } + if (node_exit_policy_rejects_all(node)) { + n_supported[i] = -1; +// log_fn(LOG_DEBUG,"Skipping node %s (index %d) -- it rejects all.", +// router->nickname, i); + continue; /* skip routers that reject all */ + } + n_supported[i] = 0; + /* iterate over connections */ + SMARTLIST_FOREACH_BEGIN(connections, connection_t *, conn) { + if (!ap_stream_wants_exit_attention(conn)) + continue; /* Skip everything but APs in CIRCUIT_WAIT */ + if (connection_ap_can_use_exit(TO_ENTRY_CONN(conn), node)) { + ++n_supported[i]; +// log_fn(LOG_DEBUG,"%s is supported. n_supported[%d] now %d.", +// router->nickname, i, n_supported[i]); + } else { +// log_fn(LOG_DEBUG,"%s (index %d) would reject this stream.", +// router->nickname, i); + } + } SMARTLIST_FOREACH_END(conn); + if (n_pending_connections > 0 && n_supported[i] == 0) { + /* Leave best_support at -1 if that's where it is, so we can + * distinguish it later. */ + continue; + } + if (n_supported[i] > best_support) { + /* If this router is better than previous ones, remember its index + * and goodness, and start counting how many routers are this good. */ + best_support = n_supported[i]; n_best_support=1; +// log_fn(LOG_DEBUG,"%s is new best supported option so far.", +// router->nickname); + } else if (n_supported[i] == best_support) { + /* If this router is _as good_ as the best one, just increment the + * count of equally good routers.*/ + ++n_best_support; + } + } SMARTLIST_FOREACH_END(node); + log_info(LD_CIRC, + "Found %d servers that might support %d/%d pending connections.", + n_best_support, best_support >= 0 ? best_support : 0, + n_pending_connections); + + /* If any routers definitely support any pending connections, choose one + * at random. */ + if (best_support > 0) { + smartlist_t *supporting = smartlist_new(); + + SMARTLIST_FOREACH(the_nodes, const node_t *, node, { + if (n_supported[node_sl_idx] == best_support) + smartlist_add(supporting, (void*)node); + }); + + node = node_sl_choose_by_bandwidth(supporting, WEIGHT_FOR_EXIT); + smartlist_free(supporting); + } else { + /* Either there are no pending connections, or no routers even seem to + * possibly support any of them. Choose a router at random that satisfies + * at least one predicted exit port. */ + + int attempt; + smartlist_t *needed_ports, *supporting; + + if (best_support == -1) { + if (need_uptime || need_capacity) { + log_info(LD_CIRC, + "We couldn't find any live%s%s routers; falling back " + "to list of all routers.", + need_capacity?", fast":"", + need_uptime?", stable":""); + tor_free(n_supported); + return choose_good_exit_server_general(0, 0); + } + log_notice(LD_CIRC, "All routers are down or won't exit%s -- " + "choosing a doomed exit at random.", + options->ExcludeExitNodesUnion_ ? " or are Excluded" : ""); + } + supporting = smartlist_new(); + needed_ports = circuit_get_unhandled_ports(time(NULL)); + for (attempt = 0; attempt < 2; attempt++) { + /* try once to pick only from routers that satisfy a needed port, + * then if there are none, pick from any that support exiting. */ + SMARTLIST_FOREACH_BEGIN(the_nodes, const node_t *, node) { + if (n_supported[node_sl_idx] != -1 && + (attempt || node_handles_some_port(node, needed_ports))) { +// log_fn(LOG_DEBUG,"Try %d: '%s' is a possibility.", +// try, router->nickname); + smartlist_add(supporting, (void*)node); + } + } SMARTLIST_FOREACH_END(node); + + node = node_sl_choose_by_bandwidth(supporting, WEIGHT_FOR_EXIT); + if (node) + break; + smartlist_clear(supporting); + /* If we reach this point, we can't actually support any unhandled + * predicted ports, so clear all the remaining ones. */ + if (smartlist_len(needed_ports)) + rep_hist_remove_predicted_ports(needed_ports); + } + SMARTLIST_FOREACH(needed_ports, uint16_t *, cp, tor_free(cp)); + smartlist_free(needed_ports); + smartlist_free(supporting); + } + + tor_free(n_supported); + if (node) { + log_info(LD_CIRC, "Chose exit server '%s'", node_describe(node)); + return node; + } + if (options->ExitNodes) { + log_warn(LD_CIRC, + "No specified %sexit routers seem to be running: " + "can't choose an exit.", + options->ExcludeExitNodesUnion_ ? "non-excluded " : ""); + } + return NULL; +} + +/** Return a pointer to a suitable router to be the exit node for the + * circuit of purpose purpose that we're about to build (or NULL + * if no router is suitable). + * + * For general-purpose circuits, pass it off to + * choose_good_exit_server_general() + * + * For client-side rendezvous circuits, choose a random node, weighted + * toward the preferences in 'options'. + */ +static const node_t * +choose_good_exit_server(uint8_t purpose, + int need_uptime, int need_capacity, int is_internal) +{ + const or_options_t *options = get_options(); + router_crn_flags_t flags = CRN_NEED_DESC; + if (need_uptime) + flags |= CRN_NEED_UPTIME; + if (need_capacity) + flags |= CRN_NEED_CAPACITY; + + switch (purpose) { + case CIRCUIT_PURPOSE_C_GENERAL: + if (options->AllowInvalid_ & ALLOW_INVALID_MIDDLE) + flags |= CRN_ALLOW_INVALID; + if (is_internal) /* pick it like a middle hop */ + return router_choose_random_node(NULL, options->ExcludeNodes, flags); + else + return choose_good_exit_server_general(need_uptime,need_capacity); + case CIRCUIT_PURPOSE_C_ESTABLISH_REND: + if (options->AllowInvalid_ & ALLOW_INVALID_RENDEZVOUS) + flags |= CRN_ALLOW_INVALID; + return router_choose_random_node(NULL, options->ExcludeNodes, flags); + } + log_warn(LD_BUG,"Unhandled purpose %d", purpose); + tor_fragile_assert(); + return NULL; +} + +/** Log a warning if the user specified an exit for the circuit that + * has been excluded from use by ExcludeNodes or ExcludeExitNodes. */ +static void +warn_if_last_router_excluded(origin_circuit_t *circ, const extend_info_t *exit) +{ + const or_options_t *options = get_options(); + routerset_t *rs = options->ExcludeNodes; + const char *description; + uint8_t purpose = circ->base_.purpose; + + if (circ->build_state->onehop_tunnel) + return; + + switch (purpose) + { + default: + case CIRCUIT_PURPOSE_OR: + case CIRCUIT_PURPOSE_INTRO_POINT: + case CIRCUIT_PURPOSE_REND_POINT_WAITING: + case CIRCUIT_PURPOSE_REND_ESTABLISHED: + log_warn(LD_BUG, "Called on non-origin circuit (purpose %d, %s)", + (int)purpose, + circuit_purpose_to_string(purpose)); + return; + case CIRCUIT_PURPOSE_C_GENERAL: + if (circ->build_state->is_internal) + return; + description = "requested exit node"; + rs = options->ExcludeExitNodesUnion_; + break; + case CIRCUIT_PURPOSE_C_INTRODUCING: + case CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT: + case CIRCUIT_PURPOSE_C_INTRODUCE_ACKED: + case CIRCUIT_PURPOSE_S_ESTABLISH_INTRO: + case CIRCUIT_PURPOSE_S_CONNECT_REND: + case CIRCUIT_PURPOSE_S_REND_JOINED: + case CIRCUIT_PURPOSE_TESTING: + return; + case CIRCUIT_PURPOSE_C_ESTABLISH_REND: + case CIRCUIT_PURPOSE_C_REND_READY: + case CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED: + case CIRCUIT_PURPOSE_C_REND_JOINED: + description = "chosen rendezvous point"; + break; + case CIRCUIT_PURPOSE_CONTROLLER: + rs = options->ExcludeExitNodesUnion_; + description = "controller-selected circuit target"; + break; + } + + if (routerset_contains_extendinfo(rs, exit)) { + /* We should never get here if StrictNodes is set to 1. */ + if (options->StrictNodes) { + log_warn(LD_BUG, "Using %s '%s' which is listed in ExcludeNodes%s, " + "even though StrictNodes is set. Please report. " + "(Circuit purpose: %s)", + description, extend_info_describe(exit), + rs==options->ExcludeNodes?"":" or ExcludeExitNodes", + circuit_purpose_to_string(purpose)); + } else { + log_warn(LD_CIRC, "Using %s '%s' which is listed in " + "ExcludeNodes%s, because no better options were available. To " + "prevent this (and possibly break your Tor functionality), " + "set the StrictNodes configuration option. " + "(Circuit purpose: %s)", + description, extend_info_describe(exit), + rs==options->ExcludeNodes?"":" or ExcludeExitNodes", + circuit_purpose_to_string(purpose)); + } + circuit_log_path(LOG_WARN, LD_CIRC, circ); + } + + return; +} + +/** Decide a suitable length for circ's cpath, and pick an exit + * router (or use exit if provided). Store these in the + * cpath. Return 0 if ok, -1 if circuit should be closed. */ +static int +onion_pick_cpath_exit(origin_circuit_t *circ, extend_info_t *exit) +{ + cpath_build_state_t *state = circ->build_state; + + if (state->onehop_tunnel) { + log_debug(LD_CIRC, "Launching a one-hop circuit for dir tunnel."); + state->desired_path_len = 1; + } else { + int r = new_route_len(circ->base_.purpose, exit, nodelist_get_list()); + if (r < 1) /* must be at least 1 */ + return -1; + state->desired_path_len = r; + } + + if (exit) { /* the circuit-builder pre-requested one */ + warn_if_last_router_excluded(circ, exit); + log_info(LD_CIRC,"Using requested exit node '%s'", + extend_info_describe(exit)); + exit = extend_info_dup(exit); + } else { /* we have to decide one */ + const node_t *node = + choose_good_exit_server(circ->base_.purpose, state->need_uptime, + state->need_capacity, state->is_internal); + if (!node) { + log_warn(LD_CIRC,"failed to choose an exit server"); + return -1; + } + exit = extend_info_from_node(node, 0); + tor_assert(exit); + } + state->chosen_exit = exit; + return 0; +} + +/** Give circ a new exit destination to exit, and add a + * hop to the cpath reflecting this. Don't send the next extend cell -- + * the caller will do this if it wants to. + */ +int +circuit_append_new_exit(origin_circuit_t *circ, extend_info_t *exit) +{ + cpath_build_state_t *state; + tor_assert(exit); + tor_assert(circ); + + state = circ->build_state; + tor_assert(state); + extend_info_free(state->chosen_exit); + state->chosen_exit = extend_info_dup(exit); + + ++circ->build_state->desired_path_len; + onion_append_hop(&circ->cpath, exit); + return 0; +} + +/** Take an open circ, and add a new hop at the end, based on + * info. Set its state back to CIRCUIT_STATE_BUILDING, and then + * send the next extend cell to begin connecting to that hop. + */ +int +circuit_extend_to_new_exit(origin_circuit_t *circ, extend_info_t *exit) +{ + int err_reason = 0; + warn_if_last_router_excluded(circ, exit); + + tor_gettimeofday(&circ->base_.timestamp_began); + + circuit_append_new_exit(circ, exit); + circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_BUILDING); + if ((err_reason = circuit_send_next_onion_skin(circ))<0) { + log_warn(LD_CIRC, "Couldn't extend circuit to new point %s.", + extend_info_describe(exit)); + circuit_mark_for_close(TO_CIRCUIT(circ), -err_reason); + return -1; + } + + // XXX: Should cannibalized circuits be dirty or not? Not easy to say.. + + return 0; +} + +/** Return the number of routers in routers that are currently up + * and available for building circuits through. + */ +static int +count_acceptable_nodes(smartlist_t *nodes) +{ + int num=0; + + SMARTLIST_FOREACH_BEGIN(nodes, const node_t *, node) { + // log_debug(LD_CIRC, +// "Contemplating whether router %d (%s) is a new option.", +// i, r->nickname); + if (! node->is_running) +// log_debug(LD_CIRC,"Nope, the directory says %d is not running.",i); + continue; + if (! node->is_valid) +// log_debug(LD_CIRC,"Nope, the directory says %d is not valid.",i); + continue; + if (! node_has_descriptor(node)) + continue; + /* XXX This clause makes us count incorrectly: if AllowInvalidRouters + * allows this node in some places, then we're getting an inaccurate + * count. For now, be conservative and don't count it. But later we + * should try to be smarter. */ + ++num; + } SMARTLIST_FOREACH_END(node); + +// log_debug(LD_CIRC,"I like %d. num_acceptable_routers now %d.",i, num); + + return num; +} + +/** Add new_hop to the end of the doubly-linked-list head_ptr. + * This function is used to extend cpath by another hop. + */ +void +onion_append_to_cpath(crypt_path_t **head_ptr, crypt_path_t *new_hop) +{ + if (*head_ptr) { + new_hop->next = (*head_ptr); + new_hop->prev = (*head_ptr)->prev; + (*head_ptr)->prev->next = new_hop; + (*head_ptr)->prev = new_hop; + } else { + *head_ptr = new_hop; + new_hop->prev = new_hop->next = new_hop; + } +} + +/** A helper function used by onion_extend_cpath(). Use purpose + * and state and the cpath head (currently populated only + * to length cur_len to decide a suitable middle hop for a + * circuit. In particular, make sure we don't pick the exit node or its + * family, and make sure we don't duplicate any previous nodes or their + * families. */ +static const node_t * +choose_good_middle_server(uint8_t purpose, + cpath_build_state_t *state, + crypt_path_t *head, + int cur_len) +{ + int i; + const node_t *r, *choice; + crypt_path_t *cpath; + smartlist_t *excluded; + const or_options_t *options = get_options(); + router_crn_flags_t flags = CRN_NEED_DESC; + tor_assert(CIRCUIT_PURPOSE_MIN_ <= purpose && + purpose <= CIRCUIT_PURPOSE_MAX_); + + log_debug(LD_CIRC, "Contemplating intermediate hop: random choice."); + excluded = smartlist_new(); + if ((r = build_state_get_exit_node(state))) { + nodelist_add_node_and_family(excluded, r); + } + for (i = 0, cpath = head; i < cur_len; ++i, cpath=cpath->next) { + if ((r = node_get_by_id(cpath->extend_info->identity_digest))) { + nodelist_add_node_and_family(excluded, r); + } + } + + if (state->need_uptime) + flags |= CRN_NEED_UPTIME; + if (state->need_capacity) + flags |= CRN_NEED_CAPACITY; + if (options->AllowInvalid_ & ALLOW_INVALID_MIDDLE) + flags |= CRN_ALLOW_INVALID; + choice = router_choose_random_node(excluded, options->ExcludeNodes, flags); + smartlist_free(excluded); + return choice; +} + +/** Pick a good entry server for the circuit to be built according to + * state. Don't reuse a chosen exit (if any), don't use this + * router (if we're an OR), and respect firewall settings; if we're + * configured to use entry guards, return one. + * + * If state is NULL, we're choosing a router to serve as an entry + * guard, not for any particular circuit. + */ +/* XXXX024 I'd like to have this be static again, but entrynodes.c needs it. */ +const node_t * +choose_good_entry_server(uint8_t purpose, cpath_build_state_t *state) +{ + const node_t *choice; + smartlist_t *excluded; + const or_options_t *options = get_options(); + router_crn_flags_t flags = CRN_NEED_GUARD|CRN_NEED_DESC; + const node_t *node; + + if (state && options->UseEntryGuards && + (purpose != CIRCUIT_PURPOSE_TESTING || options->BridgeRelay)) { + /* This request is for an entry server to use for a regular circuit, + * and we use entry guard nodes. Just return one of the guard nodes. */ + return choose_random_entry(state); + } + + excluded = smartlist_new(); + + if (state && (node = build_state_get_exit_node(state))) { + /* Exclude the exit node from the state, if we have one. Also exclude its + * family. */ + nodelist_add_node_and_family(excluded, node); + } + if (firewall_is_fascist_or()) { + /* Exclude all ORs that we can't reach through our firewall */ + smartlist_t *nodes = nodelist_get_list(); + SMARTLIST_FOREACH(nodes, const node_t *, node, { + if (!fascist_firewall_allows_node(node)) + smartlist_add(excluded, (void*)node); + }); + } + /* and exclude current entry guards and their families, if applicable */ + /*XXXX025 use the using_as_guard flag to accomplish this.*/ + if (options->UseEntryGuards) { + SMARTLIST_FOREACH(get_entry_guards(), const entry_guard_t *, entry, + { + if ((node = node_get_by_id(entry->identity))) { + nodelist_add_node_and_family(excluded, node); + } + }); + } + + if (state) { + if (state->need_uptime) + flags |= CRN_NEED_UPTIME; + if (state->need_capacity) + flags |= CRN_NEED_CAPACITY; + } + if (options->AllowInvalid_ & ALLOW_INVALID_ENTRY) + flags |= CRN_ALLOW_INVALID; + + choice = router_choose_random_node(excluded, options->ExcludeNodes, flags); + smartlist_free(excluded); + return choice; +} + +/** Return the first non-open hop in cpath, or return NULL if all + * hops are open. */ +static crypt_path_t * +onion_next_hop_in_cpath(crypt_path_t *cpath) +{ + crypt_path_t *hop = cpath; + do { + if (hop->state != CPATH_STATE_OPEN) + return hop; + hop = hop->next; + } while (hop != cpath); + return NULL; +} + +/** Choose a suitable next hop in the cpath head_ptr, + * based on state. Append the hop info to head_ptr. + * + * Return 1 if the path is complete, 0 if we successfully added a hop, + * and -1 on error. + */ +static int +onion_extend_cpath(origin_circuit_t *circ) +{ + uint8_t purpose = circ->base_.purpose; + cpath_build_state_t *state = circ->build_state; + int cur_len = circuit_get_cpath_len(circ); + extend_info_t *info = NULL; + + if (cur_len >= state->desired_path_len) { + log_debug(LD_CIRC, "Path is complete: %d steps long", + state->desired_path_len); + return 1; + } + + log_debug(LD_CIRC, "Path is %d long; we want %d", cur_len, + state->desired_path_len); + + if (cur_len == state->desired_path_len - 1) { /* Picking last node */ + info = extend_info_dup(state->chosen_exit); + } else if (cur_len == 0) { /* picking first node */ + const node_t *r = choose_good_entry_server(purpose, state); + if (r) { + /* If we're a client, use the preferred address rather than the + primary address, for potentially connecting to an IPv6 OR + port. */ + info = extend_info_from_node(r, server_mode(get_options()) == 0); + tor_assert(info); + } + } else { + const node_t *r = + choose_good_middle_server(purpose, state, circ->cpath, cur_len); + if (r) { + info = extend_info_from_node(r, 0); + tor_assert(info); + } + } + + if (!info) { + log_warn(LD_CIRC,"Failed to find node for hop %d of our path. Discarding " + "this circuit.", cur_len); + return -1; + } + + log_debug(LD_CIRC,"Chose router %s for hop %d (exit is %s)", + extend_info_describe(info), + cur_len+1, build_state_get_exit_nickname(state)); + + onion_append_hop(&circ->cpath, info); + extend_info_free(info); + return 0; +} + +/** Create a new hop, annotate it with information about its + * corresponding router choice, and append it to the + * end of the cpath head_ptr. */ +static int +onion_append_hop(crypt_path_t **head_ptr, extend_info_t *choice) +{ + crypt_path_t *hop = tor_malloc_zero(sizeof(crypt_path_t)); + + /* link hop into the cpath, at the end. */ + onion_append_to_cpath(head_ptr, hop); + + hop->magic = CRYPT_PATH_MAGIC; + hop->state = CPATH_STATE_CLOSED; + + hop->extend_info = extend_info_dup(choice); + + hop->package_window = circuit_initial_package_window(); + hop->deliver_window = CIRCWINDOW_START; + + return 0; +} + +/** Allocate a new extend_info object based on the various arguments. */ +extend_info_t * +extend_info_new(const char *nickname, const char *digest, + crypto_pk_t *onion_key, + const curve25519_public_key_t *curve25519_key, + const tor_addr_t *addr, uint16_t port) +{ + extend_info_t *info = tor_malloc_zero(sizeof(extend_info_t)); + memcpy(info->identity_digest, digest, DIGEST_LEN); + if (nickname) + strlcpy(info->nickname, nickname, sizeof(info->nickname)); + if (onion_key) + info->onion_key = crypto_pk_dup_key(onion_key); +#ifdef CURVE25519_ENABLED + if (curve25519_key) + memcpy(&info->curve25519_onion_key, curve25519_key, + sizeof(curve25519_public_key_t)); +#else + (void)curve25519_key; +#endif + tor_addr_copy(&info->addr, addr); + info->port = port; + return info; +} + +/** Allocate and return a new extend_info that can be used to build a + * circuit to or through the node node. Use the primary address + * of the node (i.e. its IPv4 address) unless + * for_direct_connect is true, in which case the preferred + * address is used instead. May return NULL if there is not enough + * info about node to extend to it--for example, if there is no + * routerinfo_t or microdesc_t. + **/ +extend_info_t * +extend_info_from_node(const node_t *node, int for_direct_connect) +{ + tor_addr_port_t ap; + + if (node->ri == NULL && (node->rs == NULL || node->md == NULL)) + return NULL; + + if (for_direct_connect) + node_get_pref_orport(node, &ap); + else + node_get_prim_orport(node, &ap); + + log_debug(LD_CIRC, "using %s for %s", + fmt_addrport(&ap.addr, ap.port), + node->ri ? node->ri->nickname : node->rs->nickname); + + if (node->ri) + return extend_info_new(node->ri->nickname, + node->identity, + node->ri->onion_pkey, + node->ri->onion_curve25519_pkey, + &ap.addr, + ap.port); + else if (node->rs && node->md) + return extend_info_new(node->rs->nickname, + node->identity, + node->md->onion_pkey, + node->md->onion_curve25519_pkey, + &ap.addr, + ap.port); + else + return NULL; +} + +/** Release storage held by an extend_info_t struct. */ +void +extend_info_free(extend_info_t *info) +{ + if (!info) + return; + crypto_pk_free(info->onion_key); + tor_free(info); +} + +/** Allocate and return a new extend_info_t with the same contents as + * info. */ +extend_info_t * +extend_info_dup(extend_info_t *info) +{ + extend_info_t *newinfo; + tor_assert(info); + newinfo = tor_malloc(sizeof(extend_info_t)); + memcpy(newinfo, info, sizeof(extend_info_t)); + if (info->onion_key) + newinfo->onion_key = crypto_pk_dup_key(info->onion_key); + else + newinfo->onion_key = NULL; + return newinfo; +} + +/** Return the routerinfo_t for the chosen exit router in state. + * If there is no chosen exit, or if we don't know the routerinfo_t for + * the chosen exit, return NULL. + */ +const node_t * +build_state_get_exit_node(cpath_build_state_t *state) +{ + if (!state || !state->chosen_exit) + return NULL; + return node_get_by_id(state->chosen_exit->identity_digest); +} + +/** Return the nickname for the chosen exit router in state. If + * there is no chosen exit, or if we don't know the routerinfo_t for the + * chosen exit, return NULL. + */ +const char * +build_state_get_exit_nickname(cpath_build_state_t *state) +{ + if (!state || !state->chosen_exit) + return NULL; + return state->chosen_exit->nickname; +} + diff --git a/src/tor/circuitbuild.h b/src/tor/circuitbuild.h new file mode 100644 index 0000000..ebcb22c --- /dev/null +++ b/src/tor/circuitbuild.h @@ -0,0 +1,62 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file circuitbuild.h + * \brief Header file for circuitbuild.c. + **/ + +#ifndef TOR_CIRCUITBUILD_H +#define TOR_CIRCUITBUILD_H + +char *circuit_list_path(origin_circuit_t *circ, int verbose); +char *circuit_list_path_for_controller(origin_circuit_t *circ); +void circuit_log_path(int severity, unsigned int domain, + origin_circuit_t *circ); +void circuit_rep_hist_note_result(origin_circuit_t *circ); +origin_circuit_t *origin_circuit_init(uint8_t purpose, int flags); +origin_circuit_t *circuit_establish_circuit(uint8_t purpose, + extend_info_t *exit, + int flags); +int circuit_handle_first_hop(origin_circuit_t *circ); +void circuit_n_chan_done(channel_t *chan, int status); +int inform_testing_reachability(void); +int circuit_timeout_want_to_count_circ(origin_circuit_t *circ); +int circuit_send_next_onion_skin(origin_circuit_t *circ); +void circuit_note_clock_jumped(int seconds_elapsed); +int circuit_extend(cell_t *cell, circuit_t *circ); +int circuit_init_cpath_crypto(crypt_path_t *cpath, const char *key_data, + int reverse); +struct created_cell_t; +int circuit_finish_handshake(origin_circuit_t *circ, + const struct created_cell_t *created_cell); +int circuit_truncated(origin_circuit_t *circ, crypt_path_t *layer, + int reason); +int onionskin_answer(or_circuit_t *circ, + const struct created_cell_t *created_cell, + const char *keys, + const uint8_t *rend_circ_nonce); +int circuit_all_predicted_ports_handled(time_t now, int *need_uptime, + int *need_capacity); + +int circuit_append_new_exit(origin_circuit_t *circ, extend_info_t *info); +int circuit_extend_to_new_exit(origin_circuit_t *circ, extend_info_t *info); +void onion_append_to_cpath(crypt_path_t **head_ptr, crypt_path_t *new_hop); +extend_info_t *extend_info_new(const char *nickname, const char *digest, + crypto_pk_t *onion_key, + const curve25519_public_key_t *curve25519_key, + const tor_addr_t *addr, uint16_t port); +extend_info_t *extend_info_from_node(const node_t *r, int for_direct_connect); +extend_info_t *extend_info_dup(extend_info_t *info); +void extend_info_free(extend_info_t *info); +const node_t *build_state_get_exit_node(cpath_build_state_t *state); +const char *build_state_get_exit_nickname(cpath_build_state_t *state); + +const node_t *choose_good_entry_server(uint8_t purpose, + cpath_build_state_t *state); + +#endif + diff --git a/src/tor/circuitlist.c b/src/tor/circuitlist.c new file mode 100644 index 0000000..9474896 --- /dev/null +++ b/src/tor/circuitlist.c @@ -0,0 +1,1878 @@ +/* Copyright 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file circuitlist.c + * \brief Manage the global circuit list. + **/ +#define CIRCUITLIST_PRIVATE +#include "or.h" +#include "channel.h" +#include "circpathbias.h" +#include "circuitbuild.h" +#include "circuitlist.h" +#include "circuituse.h" +#include "circuitstats.h" +#include "connection.h" +#include "config.h" +#include "connection_edge.h" +#include "connection_or.h" +#include "control.h" +#include "networkstatus.h" +#include "nodelist.h" +#include "onion.h" +#include "onion_fast.h" +#include "policies.h" +#include "relay.h" +#include "rendclient.h" +#include "rendcommon.h" +#include "rephist.h" +#include "routerlist.h" +#include "routerset.h" +#include "ht.h" + +/********* START VARIABLES **********/ + +/** A global list of all circuits at this hop. */ +struct global_circuitlist_s global_circuitlist = + TOR_LIST_HEAD_INITIALIZER(global_circuitlist); + +/** A list of all the circuits in CIRCUIT_STATE_CHAN_WAIT. */ +static smartlist_t *circuits_pending_chans = NULL; + +static void circuit_free_cpath_node(crypt_path_t *victim); +static void cpath_ref_decref(crypt_path_reference_t *cpath_ref); + +/********* END VARIABLES ************/ + +/** A map from channel and circuit ID to circuit. (Lookup performance is + * very important here, since we need to do it every time a cell arrives.) */ +typedef struct chan_circid_circuit_map_t { + HT_ENTRY(chan_circid_circuit_map_t) node; + channel_t *chan; + circid_t circ_id; + circuit_t *circuit; +} chan_circid_circuit_map_t; + +/** Helper for hash tables: compare the channel and circuit ID for a and + * b, and return less than, equal to, or greater than zero appropriately. + */ +static INLINE int +chan_circid_entries_eq_(chan_circid_circuit_map_t *a, + chan_circid_circuit_map_t *b) +{ + return a->chan == b->chan && a->circ_id == b->circ_id; +} + +/** Helper: return a hash based on circuit ID and the pointer value of + * chan in a. */ +static INLINE unsigned int +chan_circid_entry_hash_(chan_circid_circuit_map_t *a) +{ + return ((unsigned)a->circ_id) ^ (unsigned)(uintptr_t)(a->chan); +} + +/** Map from [chan,circid] to circuit. */ +static HT_HEAD(chan_circid_map, chan_circid_circuit_map_t) + chan_circid_map = HT_INITIALIZER(); +HT_PROTOTYPE(chan_circid_map, chan_circid_circuit_map_t, node, + chan_circid_entry_hash_, chan_circid_entries_eq_) +HT_GENERATE(chan_circid_map, chan_circid_circuit_map_t, node, + chan_circid_entry_hash_, chan_circid_entries_eq_, 0.6, + malloc, realloc, free) + +/** The most recently returned entry from circuit_get_by_circid_chan; + * used to improve performance when many cells arrive in a row from the + * same circuit. + */ +chan_circid_circuit_map_t *_last_circid_chan_ent = NULL; + +/** Implementation helper for circuit_set_{p,n}_circid_channel: A circuit ID + * and/or channel for circ has just changed from old_chan, old_id + * to chan, id. Adjust the chan,circid map as appropriate, removing + * the old entry (if any) and adding a new one. */ +static void +circuit_set_circid_chan_helper(circuit_t *circ, int direction, + circid_t id, + channel_t *chan) +{ + chan_circid_circuit_map_t search; + chan_circid_circuit_map_t *found; + channel_t *old_chan, **chan_ptr; + circid_t old_id, *circid_ptr; + int make_active, attached = 0; + + if (direction == CELL_DIRECTION_OUT) { + chan_ptr = &circ->n_chan; + circid_ptr = &circ->n_circ_id; + make_active = circ->n_chan_cells.n > 0; + } else { + or_circuit_t *c = TO_OR_CIRCUIT(circ); + chan_ptr = &c->p_chan; + circid_ptr = &c->p_circ_id; + make_active = c->p_chan_cells.n > 0; + } + old_chan = *chan_ptr; + old_id = *circid_ptr; + + if (id == old_id && chan == old_chan) + return; + + if (_last_circid_chan_ent && + ((old_id == _last_circid_chan_ent->circ_id && + old_chan == _last_circid_chan_ent->chan) || + (id == _last_circid_chan_ent->circ_id && + chan == _last_circid_chan_ent->chan))) { + _last_circid_chan_ent = NULL; + } + + if (old_chan) { + /* + * If we're changing channels or ID and had an old channel and a non + * zero old ID and weren't marked for close (i.e., we should have been + * attached), detach the circuit. ID changes require this because + * circuitmux hashes on (channel_id, circuit_id). + */ + if (old_id != 0 && (old_chan != chan || old_id != id) && + !(circ->marked_for_close)) { + tor_assert(old_chan->cmux); + circuitmux_detach_circuit(old_chan->cmux, circ); + } + + /* we may need to remove it from the conn-circid map */ + search.circ_id = old_id; + search.chan = old_chan; + found = HT_REMOVE(chan_circid_map, &chan_circid_map, &search); + if (found) { + tor_free(found); + if (direction == CELL_DIRECTION_OUT) { + /* One fewer circuits use old_chan as n_chan */ + --(old_chan->num_n_circuits); + } else { + /* One fewer circuits use old_chan as p_chan */ + --(old_chan->num_p_circuits); + } + } + } + + /* Change the values only after we have possibly made the circuit inactive + * on the previous chan. */ + *chan_ptr = chan; + *circid_ptr = id; + + if (chan == NULL) + return; + + /* now add the new one to the conn-circid map */ + search.circ_id = id; + search.chan = chan; + found = HT_FIND(chan_circid_map, &chan_circid_map, &search); + if (found) { + found->circuit = circ; + } else { + found = tor_malloc_zero(sizeof(chan_circid_circuit_map_t)); + found->circ_id = id; + found->chan = chan; + found->circuit = circ; + HT_INSERT(chan_circid_map, &chan_circid_map, found); + } + + /* + * Attach to the circuitmux if we're changing channels or IDs and + * have a new channel and ID to use and the circuit is not marked for + * close. + */ + if (chan && id != 0 && (old_chan != chan || old_id != id) && + !(circ->marked_for_close)) { + tor_assert(chan->cmux); + circuitmux_attach_circuit(chan->cmux, circ, direction); + attached = 1; + } + + /* + * This is a no-op if we have no cells, but if we do it marks us active to + * the circuitmux + */ + if (make_active && attached) + update_circuit_on_cmux(circ, direction); + + /* Adjust circuit counts on new channel */ + if (direction == CELL_DIRECTION_OUT) { + ++chan->num_n_circuits; + } else { + ++chan->num_p_circuits; + } +} + +/** Mark that circuit id id shouldn't be used on channel chan, + * even if there is no circuit on the channel. We use this to keep the + * circuit id from getting re-used while we have queued but not yet sent + * a destroy cell. */ +void +channel_mark_circid_unusable(channel_t *chan, circid_t id) +{ + chan_circid_circuit_map_t search; + chan_circid_circuit_map_t *ent; + + /* See if there's an entry there. That wouldn't be good. */ + memset(&search, 0, sizeof(search)); + search.chan = chan; + search.circ_id = id; + ent = HT_FIND(chan_circid_map, &chan_circid_map, &search); + + if (ent && ent->circuit) { + /* we have a problem. */ + log_warn(LD_BUG, "Tried to mark %u unusable on %p, but there was already " + "a circuit there.", (unsigned)id, chan); + } else if (ent) { + /* It's already marked. */ + } else { + ent = tor_malloc_zero(sizeof(chan_circid_circuit_map_t)); + ent->chan = chan; + ent->circ_id = id; + /* leave circuit at NULL */ + HT_INSERT(chan_circid_map, &chan_circid_map, ent); + } +} + +/** Mark that a circuit id id can be used again on chan. + * We use this to re-enable the circuit ID after we've sent a destroy cell. + */ +void +channel_mark_circid_usable(channel_t *chan, circid_t id) +{ + chan_circid_circuit_map_t search; + chan_circid_circuit_map_t *ent; + + /* See if there's an entry there. That wouldn't be good. */ + memset(&search, 0, sizeof(search)); + search.chan = chan; + search.circ_id = id; + ent = HT_REMOVE(chan_circid_map, &chan_circid_map, &search); + if (ent && ent->circuit) { + log_warn(LD_BUG, "Tried to mark %u usable on %p, but there was already " + "a circuit there.", (unsigned)id, chan); + return; + } + if (_last_circid_chan_ent == ent) + _last_circid_chan_ent = NULL; + tor_free(ent); +} + +/** Called to indicate that a DESTROY is pending on chan with + * circuit ID id, but hasn't been sent yet. */ +void +channel_note_destroy_pending(channel_t *chan, circid_t id) +{ + circuit_t *circ = circuit_get_by_circid_channel_even_if_marked(id,chan); + if (circ) { + if (circ->n_chan == chan && circ->n_circ_id == id) { + circ->n_delete_pending = 1; + } else { + or_circuit_t *orcirc = TO_OR_CIRCUIT(circ); + if (orcirc->p_chan == chan && orcirc->p_circ_id == id) { + circ->p_delete_pending = 1; + } + } + return; + } + channel_mark_circid_unusable(chan, id); +} + +/** Called to indicate that a DESTROY is no longer pending on chan with + * circuit ID id -- typically, because it has been sent. */ +void +channel_note_destroy_not_pending(channel_t *chan, circid_t id) +{ + circuit_t *circ = circuit_get_by_circid_channel_even_if_marked(id,chan); + if (circ) { + if (circ->n_chan == chan && circ->n_circ_id == id) { + circ->n_delete_pending = 0; + } else { + or_circuit_t *orcirc = TO_OR_CIRCUIT(circ); + if (orcirc->p_chan == chan && orcirc->p_circ_id == id) { + circ->p_delete_pending = 0; + } + } + /* XXXX this shouldn't happen; log a bug here. */ + return; + } + channel_mark_circid_usable(chan, id); +} + +/** Set the p_conn field of a circuit circ, along + * with the corresponding circuit ID, and add the circuit as appropriate + * to the (chan,id)-\>circuit map. */ +void +circuit_set_p_circid_chan(or_circuit_t *or_circ, circid_t id, + channel_t *chan) +{ + circuit_t *circ = TO_CIRCUIT(or_circ); + channel_t *old_chan = or_circ->p_chan; + circid_t old_id = or_circ->p_circ_id; + + circuit_set_circid_chan_helper(circ, CELL_DIRECTION_IN, id, chan); + + if (chan) + tor_assert(bool_eq(or_circ->p_chan_cells.n, + or_circ->next_active_on_p_chan)); + + if (circ->p_delete_pending && old_chan) { + channel_mark_circid_unusable(old_chan, old_id); + circ->p_delete_pending = 0; + } +} + +/** Set the n_conn field of a circuit circ, along + * with the corresponding circuit ID, and add the circuit as appropriate + * to the (chan,id)-\>circuit map. */ +void +circuit_set_n_circid_chan(circuit_t *circ, circid_t id, + channel_t *chan) +{ + channel_t *old_chan = circ->n_chan; + circid_t old_id = circ->n_circ_id; + + circuit_set_circid_chan_helper(circ, CELL_DIRECTION_OUT, id, chan); + + if (chan) + tor_assert(bool_eq(circ->n_chan_cells.n, circ->next_active_on_n_chan)); + + if (circ->n_delete_pending && old_chan) { + channel_mark_circid_unusable(old_chan, old_id); + circ->n_delete_pending = 0; + } +} + +/** Change the state of circ to state, adding it to or removing + * it from lists as appropriate. */ +void +circuit_set_state(circuit_t *circ, uint8_t state) +{ + tor_assert(circ); + if (state == circ->state) + return; + if (!circuits_pending_chans) + circuits_pending_chans = smartlist_new(); + if (circ->state == CIRCUIT_STATE_CHAN_WAIT) { + /* remove from waiting-circuit list. */ + smartlist_remove(circuits_pending_chans, circ); + } + if (state == CIRCUIT_STATE_CHAN_WAIT) { + /* add to waiting-circuit list. */ + smartlist_add(circuits_pending_chans, circ); + } + if (state == CIRCUIT_STATE_OPEN) + tor_assert(!circ->n_chan_create_cell); + circ->state = state; +} + +/** Append to out all circuits in state CHAN_WAIT waiting for + * the given connection. */ +void +circuit_get_all_pending_on_channel(smartlist_t *out, channel_t *chan) +{ + tor_assert(out); + tor_assert(chan); + + if (!circuits_pending_chans) + return; + + SMARTLIST_FOREACH_BEGIN(circuits_pending_chans, circuit_t *, circ) { + if (circ->marked_for_close) + continue; + if (!circ->n_hop) + continue; + tor_assert(circ->state == CIRCUIT_STATE_CHAN_WAIT); + if (tor_digest_is_zero(circ->n_hop->identity_digest)) { + /* Look at addr/port. This is an unkeyed connection. */ + if (!channel_matches_extend_info(chan, circ->n_hop)) + continue; + } else { + /* We expected a key. See if it's the right one. */ + if (tor_memneq(chan->identity_digest, + circ->n_hop->identity_digest, DIGEST_LEN)) + continue; + } + smartlist_add(out, circ); + } SMARTLIST_FOREACH_END(circ); +} + +/** Return the number of circuits in state CHAN_WAIT, waiting for the given + * channel. */ +int +circuit_count_pending_on_channel(channel_t *chan) +{ + int cnt; + smartlist_t *sl = smartlist_new(); + + tor_assert(chan); + + circuit_get_all_pending_on_channel(sl, chan); + cnt = smartlist_len(sl); + smartlist_free(sl); + log_debug(LD_CIRC,"or_conn to %s at %s, %d pending circs", + chan->nickname ? chan->nickname : "NULL", + channel_get_canonical_remote_descr(chan), + cnt); + return cnt; +} + +/** Detach from the global circuit list, and deallocate, all + * circuits that have been marked for close. + */ +void +circuit_close_all_marked(void) +{ + circuit_t *circ, *tmp; + TOR_LIST_FOREACH_SAFE(circ, &global_circuitlist, head, tmp) + if (circ->marked_for_close) + circuit_free(circ); +} + +/** Return the head of the global linked list of circuits. */ +struct global_circuitlist_s * +circuit_get_global_list(void) +{ + return &global_circuitlist; +} + +/** Function to make circ-\>state human-readable */ +const char * +circuit_state_to_string(int state) +{ + static char buf[64]; + switch (state) { + case CIRCUIT_STATE_BUILDING: return "doing handshakes"; + case CIRCUIT_STATE_ONIONSKIN_PENDING: return "processing the onion"; + case CIRCUIT_STATE_CHAN_WAIT: return "connecting to server"; + case CIRCUIT_STATE_OPEN: return "open"; + default: + log_warn(LD_BUG, "Unknown circuit state %d", state); + tor_snprintf(buf, sizeof(buf), "unknown state [%d]", state); + return buf; + } +} + +/** Map a circuit purpose to a string suitable to be displayed to a + * controller. */ +const char * +circuit_purpose_to_controller_string(uint8_t purpose) +{ + static char buf[32]; + switch (purpose) { + case CIRCUIT_PURPOSE_OR: + case CIRCUIT_PURPOSE_INTRO_POINT: + case CIRCUIT_PURPOSE_REND_POINT_WAITING: + case CIRCUIT_PURPOSE_REND_ESTABLISHED: + return "SERVER"; /* A controller should never see these, actually. */ + + case CIRCUIT_PURPOSE_C_GENERAL: + return "GENERAL"; + case CIRCUIT_PURPOSE_C_INTRODUCING: + case CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT: + case CIRCUIT_PURPOSE_C_INTRODUCE_ACKED: + return "HS_CLIENT_INTRO"; + + case CIRCUIT_PURPOSE_C_ESTABLISH_REND: + case CIRCUIT_PURPOSE_C_REND_READY: + case CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED: + case CIRCUIT_PURPOSE_C_REND_JOINED: + return "HS_CLIENT_REND"; + + case CIRCUIT_PURPOSE_S_ESTABLISH_INTRO: + case CIRCUIT_PURPOSE_S_INTRO: + return "HS_SERVICE_INTRO"; + + case CIRCUIT_PURPOSE_S_CONNECT_REND: + case CIRCUIT_PURPOSE_S_REND_JOINED: + return "HS_SERVICE_REND"; + + case CIRCUIT_PURPOSE_TESTING: + return "TESTING"; + case CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT: + return "MEASURE_TIMEOUT"; + case CIRCUIT_PURPOSE_CONTROLLER: + return "CONTROLLER"; + case CIRCUIT_PURPOSE_PATH_BIAS_TESTING: + return "PATH_BIAS_TESTING"; + + default: + tor_snprintf(buf, sizeof(buf), "UNKNOWN_%d", (int)purpose); + return buf; + } +} + +/** Return a string specifying the state of the hidden-service circuit + * purpose purpose, or NULL if purpose is not a + * hidden-service-related circuit purpose. */ +const char * +circuit_purpose_to_controller_hs_state_string(uint8_t purpose) +{ + switch (purpose) + { + default: + log_fn(LOG_WARN, LD_BUG, + "Unrecognized circuit purpose: %d", + (int)purpose); + tor_fragile_assert(); + /* fall through */ + + case CIRCUIT_PURPOSE_OR: + case CIRCUIT_PURPOSE_C_GENERAL: + case CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT: + case CIRCUIT_PURPOSE_TESTING: + case CIRCUIT_PURPOSE_CONTROLLER: + case CIRCUIT_PURPOSE_PATH_BIAS_TESTING: + return NULL; + + case CIRCUIT_PURPOSE_INTRO_POINT: + return "OR_HSSI_ESTABLISHED"; + case CIRCUIT_PURPOSE_REND_POINT_WAITING: + return "OR_HSCR_ESTABLISHED"; + case CIRCUIT_PURPOSE_REND_ESTABLISHED: + return "OR_HS_R_JOINED"; + + case CIRCUIT_PURPOSE_C_INTRODUCING: + return "HSCI_CONNECTING"; + case CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT: + return "HSCI_INTRO_SENT"; + case CIRCUIT_PURPOSE_C_INTRODUCE_ACKED: + return "HSCI_DONE"; + + case CIRCUIT_PURPOSE_C_ESTABLISH_REND: + return "HSCR_CONNECTING"; + case CIRCUIT_PURPOSE_C_REND_READY: + return "HSCR_ESTABLISHED_IDLE"; + case CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED: + return "HSCR_ESTABLISHED_WAITING"; + case CIRCUIT_PURPOSE_C_REND_JOINED: + return "HSCR_JOINED"; + + case CIRCUIT_PURPOSE_S_ESTABLISH_INTRO: + return "HSSI_CONNECTING"; + case CIRCUIT_PURPOSE_S_INTRO: + return "HSSI_ESTABLISHED"; + + case CIRCUIT_PURPOSE_S_CONNECT_REND: + return "HSSR_CONNECTING"; + case CIRCUIT_PURPOSE_S_REND_JOINED: + return "HSSR_JOINED"; + } +} + +/** Return a human-readable string for the circuit purpose purpose. */ +const char * +circuit_purpose_to_string(uint8_t purpose) +{ + static char buf[32]; + + switch (purpose) + { + case CIRCUIT_PURPOSE_OR: + return "Circuit at relay"; + case CIRCUIT_PURPOSE_INTRO_POINT: + return "Acting as intro point"; + case CIRCUIT_PURPOSE_REND_POINT_WAITING: + return "Acting as rendevous (pending)"; + case CIRCUIT_PURPOSE_REND_ESTABLISHED: + return "Acting as rendevous (established)"; + case CIRCUIT_PURPOSE_C_GENERAL: + return "General-purpose client"; + case CIRCUIT_PURPOSE_C_INTRODUCING: + return "Hidden service client: Connecting to intro point"; + case CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT: + return "Hidden service client: Waiting for ack from intro point"; + case CIRCUIT_PURPOSE_C_INTRODUCE_ACKED: + return "Hidden service client: Received ack from intro point"; + case CIRCUIT_PURPOSE_C_ESTABLISH_REND: + return "Hidden service client: Establishing rendezvous point"; + case CIRCUIT_PURPOSE_C_REND_READY: + return "Hidden service client: Pending rendezvous point"; + case CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED: + return "Hidden service client: Pending rendezvous point (ack received)"; + case CIRCUIT_PURPOSE_C_REND_JOINED: + return "Hidden service client: Active rendezvous point"; + case CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT: + return "Measuring circuit timeout"; + + case CIRCUIT_PURPOSE_S_ESTABLISH_INTRO: + return "Hidden service: Establishing introduction point"; + case CIRCUIT_PURPOSE_S_INTRO: + return "Hidden service: Introduction point"; + case CIRCUIT_PURPOSE_S_CONNECT_REND: + return "Hidden service: Connecting to rendezvous point"; + case CIRCUIT_PURPOSE_S_REND_JOINED: + return "Hidden service: Active rendezvous point"; + + case CIRCUIT_PURPOSE_TESTING: + return "Testing circuit"; + + case CIRCUIT_PURPOSE_CONTROLLER: + return "Circuit made by controller"; + + case CIRCUIT_PURPOSE_PATH_BIAS_TESTING: + return "Path-bias testing circuit"; + + default: + tor_snprintf(buf, sizeof(buf), "UNKNOWN_%d", (int)purpose); + return buf; + } +} + +/** Pick a reasonable package_window to start out for our circuits. + * Originally this was hard-coded at 1000, but now the consensus votes + * on the answer. See proposal 168. */ +int32_t +circuit_initial_package_window(void) +{ + int32_t num = networkstatus_get_param(NULL, "circwindow", CIRCWINDOW_START, + CIRCWINDOW_START_MIN, + CIRCWINDOW_START_MAX); + /* If the consensus tells us a negative number, we'd assert. */ + if (num < 0) + num = CIRCWINDOW_START; + return num; +} + +/** Initialize the common elements in a circuit_t, and add it to the global + * list. */ +static void +init_circuit_base(circuit_t *circ) +{ + tor_gettimeofday(&circ->timestamp_created); + + // Gets reset when we send CREATE_FAST. + // circuit_expire_building() expects these to be equal + // until the orconn is built. + circ->timestamp_began = circ->timestamp_created; + + circ->package_window = circuit_initial_package_window(); + circ->deliver_window = CIRCWINDOW_START; + cell_queue_init(&circ->n_chan_cells); + + TOR_LIST_INSERT_HEAD(&global_circuitlist, circ, head); +} + +/** Allocate space for a new circuit, initializing with p_circ_id + * and p_conn. Add it to the global circuit list. + */ +origin_circuit_t * +origin_circuit_new(void) +{ + origin_circuit_t *circ; + /* never zero, since a global ID of 0 is treated specially by the + * controller */ + static uint32_t n_circuits_allocated = 1; + + circ = tor_malloc_zero(sizeof(origin_circuit_t)); + circ->base_.magic = ORIGIN_CIRCUIT_MAGIC; + + circ->next_stream_id = crypto_rand_int(1<<16); + circ->global_identifier = n_circuits_allocated++; + circ->remaining_relay_early_cells = MAX_RELAY_EARLY_CELLS_PER_CIRCUIT; + circ->remaining_relay_early_cells -= crypto_rand_int(2); + + init_circuit_base(TO_CIRCUIT(circ)); + + circuit_build_times_update_last_circ(get_circuit_build_times_mutable()); + + return circ; +} + +/** Allocate a new or_circuit_t, connected to p_conn as + * p_circ_id. If p_conn is NULL, the circuit is unattached. */ +or_circuit_t * +or_circuit_new(circid_t p_circ_id, channel_t *p_chan) +{ + /* CircIDs */ + or_circuit_t *circ; + + circ = tor_malloc_zero(sizeof(or_circuit_t)); + circ->base_.magic = OR_CIRCUIT_MAGIC; + + if (p_chan) + circuit_set_p_circid_chan(circ, p_circ_id, p_chan); + + circ->remaining_relay_early_cells = MAX_RELAY_EARLY_CELLS_PER_CIRCUIT; + cell_queue_init(&circ->p_chan_cells); + + init_circuit_base(TO_CIRCUIT(circ)); + + return circ; +} + +/** Deallocate space associated with circ. + */ +STATIC void +circuit_free(circuit_t *circ) +{ + void *mem; + size_t memlen; + if (!circ) + return; + + if (CIRCUIT_IS_ORIGIN(circ)) { + origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ); + mem = ocirc; + memlen = sizeof(origin_circuit_t); + tor_assert(circ->magic == ORIGIN_CIRCUIT_MAGIC); + if (ocirc->build_state) { + extend_info_free(ocirc->build_state->chosen_exit); + circuit_free_cpath_node(ocirc->build_state->pending_final_cpath); + cpath_ref_decref(ocirc->build_state->service_pending_final_cpath_ref); + } + tor_free(ocirc->build_state); + + circuit_clear_cpath(ocirc); + + crypto_pk_free(ocirc->intro_key); + rend_data_free(ocirc->rend_data); + + tor_free(ocirc->dest_address); + if (ocirc->socks_username) { + memwipe(ocirc->socks_username, 0x12, ocirc->socks_username_len); + tor_free(ocirc->socks_username); + } + if (ocirc->socks_password) { + memwipe(ocirc->socks_password, 0x06, ocirc->socks_password_len); + tor_free(ocirc->socks_password); + } + addr_policy_list_free(ocirc->prepend_policy); + } else { + or_circuit_t *ocirc = TO_OR_CIRCUIT(circ); + /* Remember cell statistics for this circuit before deallocating. */ + if (get_options()->CellStatistics) + rep_hist_buffer_stats_add_circ(circ, time(NULL)); + mem = ocirc; + memlen = sizeof(or_circuit_t); + tor_assert(circ->magic == OR_CIRCUIT_MAGIC); + + crypto_cipher_free(ocirc->p_crypto); + crypto_digest_free(ocirc->p_digest); + crypto_cipher_free(ocirc->n_crypto); + crypto_digest_free(ocirc->n_digest); + + if (ocirc->rend_splice) { + or_circuit_t *other = ocirc->rend_splice; + tor_assert(other->base_.magic == OR_CIRCUIT_MAGIC); + other->rend_splice = NULL; + } + + /* remove from map. */ + circuit_set_p_circid_chan(ocirc, 0, NULL); + + /* Clear cell queue _after_ removing it from the map. Otherwise our + * "active" checks will be violated. */ + cell_queue_clear(ô->p_chan_cells); + } + + extend_info_free(circ->n_hop); + tor_free(circ->n_chan_create_cell); + + TOR_LIST_REMOVE(circ, head); + + /* Remove from map. */ + circuit_set_n_circid_chan(circ, 0, NULL); + + /* Clear cell queue _after_ removing it from the map. Otherwise our + * "active" checks will be violated. */ + cell_queue_clear(&circ->n_chan_cells); + + memwipe(mem, 0xAA, memlen); /* poison memory */ + tor_free(mem); +} + +/** Deallocate the linked list circ->cpath, and remove the cpath from + * circ. */ +void +circuit_clear_cpath(origin_circuit_t *circ) +{ + crypt_path_t *victim, *head, *cpath; + + head = cpath = circ->cpath; + + if (!cpath) + return; + + /* it's a circular list, so we have to notice when we've + * gone through it once. */ + while (cpath->next && cpath->next != head) { + victim = cpath; + cpath = victim->next; + circuit_free_cpath_node(victim); + } + + circuit_free_cpath_node(cpath); + + circ->cpath = NULL; +} + +/** Release all storage held by circuits. */ +void +circuit_free_all(void) +{ + circuit_t *tmp, *tmp2; + + TOR_LIST_FOREACH_SAFE(tmp, &global_circuitlist, head, tmp2) { + if (! CIRCUIT_IS_ORIGIN(tmp)) { + or_circuit_t *or_circ = TO_OR_CIRCUIT(tmp); + while (or_circ->resolving_streams) { + edge_connection_t *next_conn; + next_conn = or_circ->resolving_streams->next_stream; + connection_free(TO_CONN(or_circ->resolving_streams)); + or_circ->resolving_streams = next_conn; + } + } + circuit_free(tmp); + } + + smartlist_free(circuits_pending_chans); + circuits_pending_chans = NULL; + + HT_CLEAR(chan_circid_map, &chan_circid_map); +} + +/** Deallocate space associated with the cpath node victim. */ +static void +circuit_free_cpath_node(crypt_path_t *victim) +{ + if (!victim) + return; + + crypto_cipher_free(victim->f_crypto); + crypto_cipher_free(victim->b_crypto); + crypto_digest_free(victim->f_digest); + crypto_digest_free(victim->b_digest); + onion_handshake_state_release(&victim->handshake_state); + crypto_dh_free(victim->rend_dh_handshake_state); + extend_info_free(victim->extend_info); + + memwipe(victim, 0xBB, sizeof(crypt_path_t)); /* poison memory */ + tor_free(victim); +} + +/** Release a crypt_path_reference_t*, which may be NULL. */ +static void +cpath_ref_decref(crypt_path_reference_t *cpath_ref) +{ + if (cpath_ref != NULL) { + if (--(cpath_ref->refcount) == 0) { + circuit_free_cpath_node(cpath_ref->cpath); + tor_free(cpath_ref); + } + } +} + +/** A helper function for circuit_dump_by_conn() below. Log a bunch + * of information about circuit circ. + */ +static void +circuit_dump_conn_details(int severity, + circuit_t *circ, + int conn_array_index, + const char *type, + circid_t this_circid, + circid_t other_circid) +{ + tor_log(severity, LD_CIRC, "Conn %d has %s circuit: circID %u " + "(other side %u), state %d (%s), born %ld:", + conn_array_index, type, (unsigned)this_circid, (unsigned)other_circid, + circ->state, circuit_state_to_string(circ->state), + (long)circ->timestamp_began.tv_sec); + if (CIRCUIT_IS_ORIGIN(circ)) { /* circ starts at this node */ + circuit_log_path(severity, LD_CIRC, TO_ORIGIN_CIRCUIT(circ)); + } +} + +/** Log, at severity severity, information about each circuit + * that is connected to conn. + */ +void +circuit_dump_by_conn(connection_t *conn, int severity) +{ + circuit_t *circ; + edge_connection_t *tmpconn; + + TOR_LIST_FOREACH(circ, &global_circuitlist, head) { + circid_t n_circ_id = circ->n_circ_id, p_circ_id = 0; + + if (circ->marked_for_close) { + continue; + } + + if (!CIRCUIT_IS_ORIGIN(circ)) { + p_circ_id = TO_OR_CIRCUIT(circ)->p_circ_id; + } + + if (CIRCUIT_IS_ORIGIN(circ)) { + for (tmpconn=TO_ORIGIN_CIRCUIT(circ)->p_streams; tmpconn; + tmpconn=tmpconn->next_stream) { + if (TO_CONN(tmpconn) == conn) { + circuit_dump_conn_details(severity, circ, conn->conn_array_index, + "App-ward", p_circ_id, n_circ_id); + } + } + } + + if (! CIRCUIT_IS_ORIGIN(circ)) { + for (tmpconn=TO_OR_CIRCUIT(circ)->n_streams; tmpconn; + tmpconn=tmpconn->next_stream) { + if (TO_CONN(tmpconn) == conn) { + circuit_dump_conn_details(severity, circ, conn->conn_array_index, + "Exit-ward", n_circ_id, p_circ_id); + } + } + } + } +} + +/** A helper function for circuit_dump_by_chan() below. Log a bunch + * of information about circuit circ. + */ +static void +circuit_dump_chan_details(int severity, + circuit_t *circ, + channel_t *chan, + const char *type, + circid_t this_circid, + circid_t other_circid) +{ + tor_log(severity, LD_CIRC, "Conn %p has %s circuit: circID %u " + "(other side %u), state %d (%s), born %ld:", + chan, type, (unsigned)this_circid, (unsigned)other_circid, circ->state, + circuit_state_to_string(circ->state), + (long)circ->timestamp_began.tv_sec); + if (CIRCUIT_IS_ORIGIN(circ)) { /* circ starts at this node */ + circuit_log_path(severity, LD_CIRC, TO_ORIGIN_CIRCUIT(circ)); + } +} + +/** Log, at severity severity, information about each circuit + * that is connected to chan. + */ +void +circuit_dump_by_chan(channel_t *chan, int severity) +{ + circuit_t *circ; + + tor_assert(chan); + + TOR_LIST_FOREACH(circ, &global_circuitlist, head) { + circid_t n_circ_id = circ->n_circ_id, p_circ_id = 0; + + if (circ->marked_for_close) { + continue; + } + + if (!CIRCUIT_IS_ORIGIN(circ)) { + p_circ_id = TO_OR_CIRCUIT(circ)->p_circ_id; + } + + if (! CIRCUIT_IS_ORIGIN(circ) && TO_OR_CIRCUIT(circ)->p_chan && + TO_OR_CIRCUIT(circ)->p_chan == chan) { + circuit_dump_chan_details(severity, circ, chan, "App-ward", + p_circ_id, n_circ_id); + } + + if (circ->n_chan && circ->n_chan == chan) { + circuit_dump_chan_details(severity, circ, chan, "Exit-ward", + n_circ_id, p_circ_id); + } + + if (!circ->n_chan && circ->n_hop && + channel_matches_extend_info(chan, circ->n_hop) && + tor_memeq(chan->identity_digest, + circ->n_hop->identity_digest, DIGEST_LEN)) { + circuit_dump_chan_details(severity, circ, chan, + (circ->state == CIRCUIT_STATE_OPEN && + !CIRCUIT_IS_ORIGIN(circ)) ? + "Endpoint" : "Pending", + n_circ_id, p_circ_id); + } + } +} + +/** Return the circuit whose global ID is id, or NULL if no + * such circuit exists. */ +origin_circuit_t * +circuit_get_by_global_id(uint32_t id) +{ + circuit_t *circ; + TOR_LIST_FOREACH(circ, &global_circuitlist, head) { + if (CIRCUIT_IS_ORIGIN(circ) && + TO_ORIGIN_CIRCUIT(circ)->global_identifier == id) { + if (circ->marked_for_close) + return NULL; + else + return TO_ORIGIN_CIRCUIT(circ); + } + } + return NULL; +} + +/** Return a circ such that: + * - circ-\>n_circ_id or circ-\>p_circ_id is equal to circ_id, and + * - circ is attached to chan, either as p_chan or n_chan. + * Return NULL if no such circuit exists. + * + * If found_entry_out is provided, set it to true if we have a + * placeholder entry for circid/chan, and leave it unset otherwise. + */ +static INLINE circuit_t * +circuit_get_by_circid_channel_impl(circid_t circ_id, channel_t *chan, + int *found_entry_out) +{ + chan_circid_circuit_map_t search; + chan_circid_circuit_map_t *found; + + if (_last_circid_chan_ent && + circ_id == _last_circid_chan_ent->circ_id && + chan == _last_circid_chan_ent->chan) { + found = _last_circid_chan_ent; + } else { + search.circ_id = circ_id; + search.chan = chan; + found = HT_FIND(chan_circid_map, &chan_circid_map, &search); + _last_circid_chan_ent = found; + } + if (found && found->circuit) { + log_debug(LD_CIRC, + "circuit_get_by_circid_channel_impl() returning circuit %p for" + " circ_id %u, channel ID " U64_FORMAT " (%p)", + found->circuit, (unsigned)circ_id, + U64_PRINTF_ARG(chan->global_identifier), chan); + if (found_entry_out) + *found_entry_out = 1; + return found->circuit; + } + + log_debug(LD_CIRC, + "circuit_get_by_circid_channel_impl() found %s for" + " circ_id %u, channel ID " U64_FORMAT " (%p)", + found ? "placeholder" : "nothing", + (unsigned)circ_id, + U64_PRINTF_ARG(chan->global_identifier), chan); + + if (found_entry_out) + *found_entry_out = found ? 1 : 0; + + return NULL; + /* The rest of this checks for bugs. Disabled by default. */ + /* We comment it out because coverity complains otherwise. + { + circuit_t *circ; + TOR_LIST_FOREACH(circ, &global_circuitlist, head) { + if (! CIRCUIT_IS_ORIGIN(circ)) { + or_circuit_t *or_circ = TO_OR_CIRCUIT(circ); + if (or_circ->p_chan == chan && or_circ->p_circ_id == circ_id) { + log_warn(LD_BUG, + "circuit matches p_chan, but not in hash table (Bug!)"); + return circ; + } + } + if (circ->n_chan == chan && circ->n_circ_id == circ_id) { + log_warn(LD_BUG, + "circuit matches n_chan, but not in hash table (Bug!)"); + return circ; + } + } + return NULL; + } */ +} + +/** Return a circ such that: + * - circ-\>n_circ_id or circ-\>p_circ_id is equal to circ_id, and + * - circ is attached to chan, either as p_chan or n_chan. + * - circ is not marked for close. + * Return NULL if no such circuit exists. + */ +circuit_t * +circuit_get_by_circid_channel(circid_t circ_id, channel_t *chan) +{ + circuit_t *circ = circuit_get_by_circid_channel_impl(circ_id, chan, NULL); + if (!circ || circ->marked_for_close) + return NULL; + else + return circ; +} + +/** Return a circ such that: + * - circ-\>n_circ_id or circ-\>p_circ_id is equal to circ_id, and + * - circ is attached to chan, either as p_chan or n_chan. + * Return NULL if no such circuit exists. + */ +circuit_t * +circuit_get_by_circid_channel_even_if_marked(circid_t circ_id, + channel_t *chan) +{ + return circuit_get_by_circid_channel_impl(circ_id, chan, NULL); +} + +/** Return true iff the circuit ID circ_id is currently used by a + * circuit, marked or not, on chan. */ +int +circuit_id_in_use_on_channel(circid_t circ_id, channel_t *chan) +{ + int found = 0; + return circuit_get_by_circid_channel_impl(circ_id, chan, &found) != NULL + || found; +} + +/** Return the circuit that a given edge connection is using. */ +circuit_t * +circuit_get_by_edge_conn(edge_connection_t *conn) +{ + circuit_t *circ; + + circ = conn->on_circuit; + tor_assert(!circ || + (CIRCUIT_IS_ORIGIN(circ) ? circ->magic == ORIGIN_CIRCUIT_MAGIC + : circ->magic == OR_CIRCUIT_MAGIC)); + + return circ; +} + +/** For each circuit that has chan as n_chan or p_chan, unlink the + * circuit from the chan,circid map, and mark it for close if it hasn't + * been marked already. + */ +void +circuit_unlink_all_from_channel(channel_t *chan, int reason) +{ + circuit_t *circ; + + channel_unlink_all_circuits(chan); + + TOR_LIST_FOREACH(circ, &global_circuitlist, head) { + int mark = 0; + if (circ->n_chan == chan) { + circuit_set_n_circid_chan(circ, 0, NULL); + mark = 1; + + /* If we didn't request this closure, pass the remote + * bit to mark_for_close. */ + if (chan->reason_for_closing != CHANNEL_CLOSE_REQUESTED) + reason |= END_CIRC_REASON_FLAG_REMOTE; + } + if (! CIRCUIT_IS_ORIGIN(circ)) { + or_circuit_t *or_circ = TO_OR_CIRCUIT(circ); + if (or_circ->p_chan == chan) { + circuit_set_p_circid_chan(or_circ, 0, NULL); + mark = 1; + } + } + if (mark && !circ->marked_for_close) + circuit_mark_for_close(circ, reason); + } +} + +/** Return a circ such that + * - circ-\>rend_data-\>onion_address is equal to + * rend_data-\>onion_address, + * - circ-\>rend_data-\>rend_cookie is equal to + * rend_data-\>rend_cookie, and + * - circ-\>purpose is equal to CIRCUIT_PURPOSE_C_REND_READY. + * + * Return NULL if no such circuit exists. + */ +origin_circuit_t * +circuit_get_ready_rend_circ_by_rend_data(const rend_data_t *rend_data) +{ + circuit_t *circ; + TOR_LIST_FOREACH(circ, &global_circuitlist, head) { + if (!circ->marked_for_close && + circ->purpose == CIRCUIT_PURPOSE_C_REND_READY) { + origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ); + if (ocirc->rend_data && + !rend_cmp_service_ids(rend_data->onion_address, + ocirc->rend_data->onion_address) && + tor_memeq(ocirc->rend_data->rend_cookie, + rend_data->rend_cookie, + REND_COOKIE_LEN)) + return ocirc; + } + } + return NULL; +} + +/** Return the first circuit originating here in global_circuitlist after + * start whose purpose is purpose, and where + * digest (if set) matches the rend_pk_digest field. Return NULL if no + * circuit is found. If start is NULL, begin at the start of the list. + */ +origin_circuit_t * +circuit_get_next_by_pk_and_purpose(origin_circuit_t *start, + const char *digest, uint8_t purpose) +{ + circuit_t *circ; + tor_assert(CIRCUIT_PURPOSE_IS_ORIGIN(purpose)); + if (start == NULL) + circ = TOR_LIST_FIRST(&global_circuitlist); + else + circ = TOR_LIST_NEXT(TO_CIRCUIT(start), head); + + for ( ; circ; circ = TOR_LIST_NEXT(circ, head)) { + if (circ->marked_for_close) + continue; + if (circ->purpose != purpose) + continue; + if (!digest) + return TO_ORIGIN_CIRCUIT(circ); + else if (TO_ORIGIN_CIRCUIT(circ)->rend_data && + tor_memeq(TO_ORIGIN_CIRCUIT(circ)->rend_data->rend_pk_digest, + digest, DIGEST_LEN)) + return TO_ORIGIN_CIRCUIT(circ); + } + return NULL; +} + +/** Return the first OR circuit in the global list whose purpose is + * purpose, and whose rend_token is the len-byte + * token. */ +static or_circuit_t * +circuit_get_by_rend_token_and_purpose(uint8_t purpose, const char *token, + size_t len) +{ + circuit_t *circ; + TOR_LIST_FOREACH(circ, &global_circuitlist, head) { + if (! circ->marked_for_close && + circ->purpose == purpose && + tor_memeq(TO_OR_CIRCUIT(circ)->rend_token, token, len)) + return TO_OR_CIRCUIT(circ); + } + return NULL; +} + +/** Return the circuit waiting for a rendezvous with the provided cookie. + * Return NULL if no such circuit is found. + */ +or_circuit_t * +circuit_get_rendezvous(const char *cookie) +{ + return circuit_get_by_rend_token_and_purpose( + CIRCUIT_PURPOSE_REND_POINT_WAITING, + cookie, REND_COOKIE_LEN); +} + +/** Return the circuit waiting for intro cells of the given digest. + * Return NULL if no such circuit is found. + */ +or_circuit_t * +circuit_get_intro_point(const char *digest) +{ + return circuit_get_by_rend_token_and_purpose( + CIRCUIT_PURPOSE_INTRO_POINT, digest, + DIGEST_LEN); +} + +/** Return a circuit that is open, is CIRCUIT_PURPOSE_C_GENERAL, + * has a timestamp_dirty value of 0, has flags matching the CIRCLAUNCH_* + * flags in flags, and if info is defined, does not already use info + * as any of its hops; or NULL if no circuit fits this description. + * + * The purpose argument (currently ignored) refers to the purpose of + * the circuit we want to create, not the purpose of the circuit we want to + * cannibalize. + * + * If !CIRCLAUNCH_NEED_UPTIME, prefer returning non-uptime circuits. + */ +origin_circuit_t * +circuit_find_to_cannibalize(uint8_t purpose, extend_info_t *info, + int flags) +{ + circuit_t *circ_; + origin_circuit_t *best=NULL; + int need_uptime = (flags & CIRCLAUNCH_NEED_UPTIME) != 0; + int need_capacity = (flags & CIRCLAUNCH_NEED_CAPACITY) != 0; + int internal = (flags & CIRCLAUNCH_IS_INTERNAL) != 0; + const or_options_t *options = get_options(); + + /* Make sure we're not trying to create a onehop circ by + * cannibalization. */ + tor_assert(!(flags & CIRCLAUNCH_ONEHOP_TUNNEL)); + + log_debug(LD_CIRC, + "Hunting for a circ to cannibalize: purpose %d, uptime %d, " + "capacity %d, internal %d", + purpose, need_uptime, need_capacity, internal); + + TOR_LIST_FOREACH(circ_, &global_circuitlist, head) { + if (CIRCUIT_IS_ORIGIN(circ_) && + circ_->state == CIRCUIT_STATE_OPEN && + !circ_->marked_for_close && + circ_->purpose == CIRCUIT_PURPOSE_C_GENERAL && + !circ_->timestamp_dirty) { + origin_circuit_t *circ = TO_ORIGIN_CIRCUIT(circ_); + if ((!need_uptime || circ->build_state->need_uptime) && + (!need_capacity || circ->build_state->need_capacity) && + (internal == circ->build_state->is_internal) && + !circ->unusable_for_new_conns && + circ->remaining_relay_early_cells && + circ->build_state->desired_path_len == DEFAULT_ROUTE_LEN && + !circ->build_state->onehop_tunnel && + !circ->isolation_values_set) { + if (info) { + /* need to make sure we don't duplicate hops */ + crypt_path_t *hop = circ->cpath; + const node_t *ri1 = node_get_by_id(info->identity_digest); + do { + const node_t *ri2; + if (tor_memeq(hop->extend_info->identity_digest, + info->identity_digest, DIGEST_LEN)) + goto next; + if (ri1 && + (ri2 = node_get_by_id(hop->extend_info->identity_digest)) + && nodes_in_same_family(ri1, ri2)) + goto next; + hop=hop->next; + } while (hop!=circ->cpath); + } + if (options->ExcludeNodes) { + /* Make sure no existing nodes in the circuit are excluded for + * general use. (This may be possible if StrictNodes is 0, and we + * thought we needed to use an otherwise excluded node for, say, a + * directory operation.) */ + crypt_path_t *hop = circ->cpath; + do { + if (routerset_contains_extendinfo(options->ExcludeNodes, + hop->extend_info)) + goto next; + hop = hop->next; + } while (hop != circ->cpath); + } + if (!best || (best->build_state->need_uptime && !need_uptime)) + best = circ; + next: ; + } + } + } + return best; +} + +/** Return the number of hops in circuit's path. */ +int +circuit_get_cpath_len(origin_circuit_t *circ) +{ + int n = 0; + if (circ && circ->cpath) { + crypt_path_t *cpath, *cpath_next = NULL; + for (cpath = circ->cpath; cpath_next != circ->cpath; cpath = cpath_next) { + cpath_next = cpath->next; + ++n; + } + } + return n; +} + +/** Return the hopnumth hop in circ->cpath, or NULL if there + * aren't that many hops in the list. */ +crypt_path_t * +circuit_get_cpath_hop(origin_circuit_t *circ, int hopnum) +{ + if (circ && circ->cpath && hopnum > 0) { + crypt_path_t *cpath, *cpath_next = NULL; + for (cpath = circ->cpath; cpath_next != circ->cpath; cpath = cpath_next) { + cpath_next = cpath->next; + if (--hopnum <= 0) + return cpath; + } + } + return NULL; +} + +/** Go through the circuitlist; mark-for-close each circuit that starts + * at us but has not yet been used. */ +void +circuit_mark_all_unused_circs(void) +{ + circuit_t *circ; + TOR_LIST_FOREACH(circ, &global_circuitlist, head) { + if (CIRCUIT_IS_ORIGIN(circ) && + !circ->marked_for_close && + !circ->timestamp_dirty) + circuit_mark_for_close(circ, END_CIRC_REASON_FINISHED); + } +} + +/** Go through the circuitlist; for each circuit that starts at us + * and is dirty, frob its timestamp_dirty so we won't use it for any + * new streams. + * + * This is useful for letting the user change pseudonyms, so new + * streams will not be linkable to old streams. + */ +void +circuit_mark_all_dirty_circs_as_unusable(void) +{ + circuit_t *circ; + TOR_LIST_FOREACH(circ, &global_circuitlist, head) { + if (CIRCUIT_IS_ORIGIN(circ) && + !circ->marked_for_close && + circ->timestamp_dirty) { + mark_circuit_unusable_for_new_conns(TO_ORIGIN_CIRCUIT(circ)); + } + } +} + +/** Mark circ to be closed next time we call + * circuit_close_all_marked(). Do any cleanup needed: + * - If state is onionskin_pending, remove circ from the onion_pending + * list. + * - If circ isn't open yet: call circuit_build_failed() if we're + * the origin, and in either case call circuit_rep_hist_note_result() + * to note stats. + * - If purpose is C_INTRODUCE_ACK_WAIT, report the intro point + * failure we just had to the hidden service client module. + * - If purpose is C_INTRODUCING and reason isn't TIMEOUT, + * report to the hidden service client module that the intro point + * we just tried may be unreachable. + * - Send appropriate destroys and edge_destroys for conns and + * streams attached to circ. + * - If circ->rend_splice is set (we are the midpoint of a joined + * rendezvous stream), then mark the other circuit to close as well. + */ +void +circuit_mark_for_close_(circuit_t *circ, int reason, int line, + const char *file) +{ + int orig_reason = reason; /* Passed to the controller */ + assert_circuit_ok(circ); + tor_assert(line); + tor_assert(file); + + if (circ->marked_for_close) { + log_warn(LD_BUG, + "Duplicate call to circuit_mark_for_close at %s:%d" + " (first at %s:%d)", file, line, + circ->marked_for_close_file, circ->marked_for_close); + return; + } + if (reason == END_CIRC_AT_ORIGIN) { + if (!CIRCUIT_IS_ORIGIN(circ)) { + log_warn(LD_BUG, "Specified 'at-origin' non-reason for ending circuit, " + "but circuit was not at origin. (called %s:%d, purpose=%d)", + file, line, circ->purpose); + } + reason = END_CIRC_REASON_NONE; + } + + if (CIRCUIT_IS_ORIGIN(circ)) { + if (pathbias_check_close(TO_ORIGIN_CIRCUIT(circ), reason) == -1) { + /* Don't close it yet, we need to test it first */ + return; + } + + /* We don't send reasons when closing circuits at the origin. */ + reason = END_CIRC_REASON_NONE; + } + + if (reason & END_CIRC_REASON_FLAG_REMOTE) + reason &= ~END_CIRC_REASON_FLAG_REMOTE; + + if (reason < END_CIRC_REASON_MIN_ || reason > END_CIRC_REASON_MAX_) { + if (!(orig_reason & END_CIRC_REASON_FLAG_REMOTE)) + log_warn(LD_BUG, "Reason %d out of range at %s:%d", reason, file, line); + reason = END_CIRC_REASON_NONE; + } + + if (circ->state == CIRCUIT_STATE_ONIONSKIN_PENDING) { + onion_pending_remove(TO_OR_CIRCUIT(circ)); + } + /* If the circuit ever became OPEN, we sent it to the reputation history + * module then. If it isn't OPEN, we send it there now to remember which + * links worked and which didn't. + */ + if (circ->state != CIRCUIT_STATE_OPEN) { + if (CIRCUIT_IS_ORIGIN(circ)) { + origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ); + circuit_build_failed(ocirc); /* take actions if necessary */ + circuit_rep_hist_note_result(ocirc); + } + } + if (circ->state == CIRCUIT_STATE_CHAN_WAIT) { + if (circuits_pending_chans) + smartlist_remove(circuits_pending_chans, circ); + } + if (CIRCUIT_IS_ORIGIN(circ)) { + control_event_circuit_status(TO_ORIGIN_CIRCUIT(circ), + (circ->state == CIRCUIT_STATE_OPEN)?CIRC_EVENT_CLOSED:CIRC_EVENT_FAILED, + orig_reason); + } + if (circ->purpose == CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT) { + origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ); + int timed_out = (reason == END_CIRC_REASON_TIMEOUT); + tor_assert(circ->state == CIRCUIT_STATE_OPEN); + tor_assert(ocirc->build_state->chosen_exit); + tor_assert(ocirc->rend_data); + /* treat this like getting a nack from it */ + log_info(LD_REND, "Failed intro circ %s to %s (awaiting ack). %s", + safe_str_client(ocirc->rend_data->onion_address), + safe_str_client(build_state_get_exit_nickname(ocirc->build_state)), + timed_out ? "Recording timeout." : "Removing from descriptor."); + rend_client_report_intro_point_failure(ocirc->build_state->chosen_exit, + ocirc->rend_data, + timed_out ? + INTRO_POINT_FAILURE_TIMEOUT : + INTRO_POINT_FAILURE_GENERIC); + } else if (circ->purpose == CIRCUIT_PURPOSE_C_INTRODUCING && + reason != END_CIRC_REASON_TIMEOUT) { + origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ); + if (ocirc->build_state->chosen_exit && ocirc->rend_data) { + log_info(LD_REND, "Failed intro circ %s to %s " + "(building circuit to intro point). " + "Marking intro point as possibly unreachable.", + safe_str_client(ocirc->rend_data->onion_address), + safe_str_client(build_state_get_exit_nickname(ocirc->build_state))); + rend_client_report_intro_point_failure(ocirc->build_state->chosen_exit, + ocirc->rend_data, + INTRO_POINT_FAILURE_UNREACHABLE); + } + } + if (circ->n_chan) { + circuit_clear_cell_queue(circ, circ->n_chan); + /* Only send destroy if the channel isn't closing anyway */ + if (!(circ->n_chan->state == CHANNEL_STATE_CLOSING || + circ->n_chan->state == CHANNEL_STATE_CLOSED || + circ->n_chan->state == CHANNEL_STATE_ERROR)) { + channel_send_destroy(circ->n_circ_id, circ->n_chan, reason); + } + circuitmux_detach_circuit(circ->n_chan->cmux, circ); + } + + if (! CIRCUIT_IS_ORIGIN(circ)) { + or_circuit_t *or_circ = TO_OR_CIRCUIT(circ); + edge_connection_t *conn; + for (conn=or_circ->n_streams; conn; conn=conn->next_stream) + connection_edge_destroy(or_circ->p_circ_id, conn); + or_circ->n_streams = NULL; + + while (or_circ->resolving_streams) { + conn = or_circ->resolving_streams; + or_circ->resolving_streams = conn->next_stream; + if (!conn->base_.marked_for_close) { + /* The client will see a DESTROY, and infer that the connections + * are closing because the circuit is getting torn down. No need + * to send an end cell. */ + conn->edge_has_sent_end = 1; + conn->end_reason = END_STREAM_REASON_DESTROY; + conn->end_reason |= END_STREAM_REASON_FLAG_ALREADY_SENT_CLOSED; + connection_mark_for_close(TO_CONN(conn)); + } + conn->on_circuit = NULL; + } + + if (or_circ->p_chan) { + circuit_clear_cell_queue(circ, or_circ->p_chan); + /* Only send destroy if the channel isn't closing anyway */ + if (!(or_circ->p_chan->state == CHANNEL_STATE_CLOSING || + or_circ->p_chan->state == CHANNEL_STATE_CLOSED || + or_circ->p_chan->state == CHANNEL_STATE_ERROR)) { + channel_send_destroy(or_circ->p_circ_id, or_circ->p_chan, reason); + } + circuitmux_detach_circuit(or_circ->p_chan->cmux, circ); + } + } else { + origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ); + edge_connection_t *conn; + for (conn=ocirc->p_streams; conn; conn=conn->next_stream) + connection_edge_destroy(circ->n_circ_id, conn); + ocirc->p_streams = NULL; + } + + circ->marked_for_close = line; + circ->marked_for_close_file = file; + + if (!CIRCUIT_IS_ORIGIN(circ)) { + or_circuit_t *or_circ = TO_OR_CIRCUIT(circ); + if (or_circ->rend_splice) { + if (!or_circ->rend_splice->base_.marked_for_close) { + /* do this after marking this circuit, to avoid infinite recursion. */ + circuit_mark_for_close(TO_CIRCUIT(or_circ->rend_splice), reason); + } + or_circ->rend_splice = NULL; + } + } +} + +/** Given a marked circuit circ, aggressively free its cell queues to + * recover memory. */ +static void +marked_circuit_free_cells(circuit_t *circ) +{ + if (!circ->marked_for_close) { + log_warn(LD_BUG, "Called on non-marked circuit"); + return; + } + cell_queue_clear(&circ->n_chan_cells); + if (! CIRCUIT_IS_ORIGIN(circ)) + cell_queue_clear(& TO_OR_CIRCUIT(circ)->p_chan_cells); +} + +/** Return the number of cells used by the circuit c's cell queues. */ +STATIC size_t +n_cells_in_circ_queues(const circuit_t *c) +{ + size_t n = c->n_chan_cells.n; + if (! CIRCUIT_IS_ORIGIN(c)) { + circuit_t *cc = (circuit_t *) c; + n += TO_OR_CIRCUIT(cc)->p_chan_cells.n; + } + return n; +} + +/** + * Return the age of the oldest cell queued on c, in milliseconds. + * Return 0 if there are no cells queued on c. Requires that now be + * the current time in milliseconds since the epoch, truncated. + * + * This function will return incorrect results if the oldest cell queued on + * the circuit is older than 2**32 msec (about 49 days) old. + */ +static uint32_t +circuit_max_queued_cell_age(const circuit_t *c, uint32_t now) +{ + uint32_t age = 0; + packed_cell_t *cell; + + if (NULL != (cell = TOR_SIMPLEQ_FIRST(&c->n_chan_cells.head))) + age = now - cell->inserted_time; + + if (! CIRCUIT_IS_ORIGIN(c)) { + const or_circuit_t *orcirc = TO_OR_CIRCUIT((circuit_t*)c); + if (NULL != (cell = TOR_SIMPLEQ_FIRST(&orcirc->p_chan_cells.head))) { + uint32_t age2 = now - cell->inserted_time; + if (age2 > age) + return age2; + } + } + return age; +} + +/** Temporary variable for circuits_compare_by_oldest_queued_cell_ This is a + * kludge to work around the fact that qsort doesn't provide a way for + * comparison functions to take an extra argument. */ +static uint32_t circcomp_now_tmp; + +/** Helper to sort a list of circuit_t by age of oldest cell, in descending + * order. Requires that circcomp_now_tmp is set correctly. */ +static int +circuits_compare_by_oldest_queued_cell_(const void **a_, const void **b_) +{ + const circuit_t *a = *a_; + const circuit_t *b = *b_; + uint32_t age_a = circuit_max_queued_cell_age(a, circcomp_now_tmp); + uint32_t age_b = circuit_max_queued_cell_age(b, circcomp_now_tmp); + + if (age_a < age_b) + return 1; + else if (age_a == age_b) + return 0; + else + return -1; +} + +#define FRACTION_OF_CELLS_TO_RETAIN_ON_OOM 0.90 + +/** We're out of memory for cells, having allocated current_allocation + * bytes' worth. Kill the 'worst' circuits until we're under + * FRACTION_OF_CIRCS_TO_RETAIN_ON_OOM of our maximum usage. */ +void +circuits_handle_oom(size_t current_allocation) +{ + /* Let's hope there's enough slack space for this allocation here... */ + smartlist_t *circlist = smartlist_new(); + circuit_t *circ; + size_t n_cells_removed=0, n_cells_to_remove; + int n_circuits_killed=0; + struct timeval now; + log_notice(LD_GENERAL, "We're low on memory. Killing circuits with " + "over-long queues. (This behavior is controlled by " + "MaxMemInCellQueues.)"); + + { + size_t mem_target = (size_t)(get_options()->MaxMemInCellQueues * + FRACTION_OF_CELLS_TO_RETAIN_ON_OOM); + size_t mem_to_recover; + if (current_allocation <= mem_target) + return; + mem_to_recover = current_allocation - mem_target; + n_cells_to_remove = CEIL_DIV(mem_to_recover, packed_cell_mem_cost()); + } + + /* This algorithm itself assumes that you've got enough memory slack + * to actually run it. */ + TOR_LIST_FOREACH(circ, &global_circuitlist, head) + smartlist_add(circlist, circ); + + /* Set circcomp_now_tmp so that the sort can work. */ + tor_gettimeofday_cached(&now); + circcomp_now_tmp = (uint32_t)tv_to_msec(&now); + + /* This is O(n log n); there are faster algorithms we could use instead. + * Let's hope this doesn't happen enough to be in the critical path. */ + smartlist_sort(circlist, circuits_compare_by_oldest_queued_cell_); + + /* Okay, now the worst circuits are at the front of the list. Let's mark + * them, and reclaim their storage aggressively. */ + SMARTLIST_FOREACH_BEGIN(circlist, circuit_t *, circ) { + size_t n = n_cells_in_circ_queues(circ); + if (! circ->marked_for_close) { + circuit_mark_for_close(circ, END_CIRC_REASON_RESOURCELIMIT); + } + marked_circuit_free_cells(circ); + + ++n_circuits_killed; + n_cells_removed += n; + if (n_cells_removed >= n_cells_to_remove) + break; + } SMARTLIST_FOREACH_END(circ); + + clean_cell_pool(); /* In case this helps. */ + + log_notice(LD_GENERAL, "Removed "U64_FORMAT" bytes by killing %d circuits.", + U64_PRINTF_ARG(n_cells_removed * packed_cell_mem_cost()), + n_circuits_killed); + + smartlist_free(circlist); +} + +/** Verify that cpath layer cp has all of its invariants + * correct. Trigger an assert if anything is invalid. + */ +void +assert_cpath_layer_ok(const crypt_path_t *cp) +{ +// tor_assert(cp->addr); /* these are zero for rendezvous extra-hops */ +// tor_assert(cp->port); + tor_assert(cp); + tor_assert(cp->magic == CRYPT_PATH_MAGIC); + switch (cp->state) + { + case CPATH_STATE_OPEN: + tor_assert(cp->f_crypto); + tor_assert(cp->b_crypto); + /* fall through */ + case CPATH_STATE_CLOSED: + /*XXXX Assert that there's no handshake_state either. */ + tor_assert(!cp->rend_dh_handshake_state); + break; + case CPATH_STATE_AWAITING_KEYS: + /* tor_assert(cp->dh_handshake_state); */ + break; + default: + log_fn(LOG_ERR, LD_BUG, "Unexpected state %d", cp->state); + tor_assert(0); + } + tor_assert(cp->package_window >= 0); + tor_assert(cp->deliver_window >= 0); +} + +/** Verify that cpath cp has all of its invariants + * correct. Trigger an assert if anything is invalid. + */ +static void +assert_cpath_ok(const crypt_path_t *cp) +{ + const crypt_path_t *start = cp; + + do { + assert_cpath_layer_ok(cp); + /* layers must be in sequence of: "open* awaiting? closed*" */ + if (cp != start) { + if (cp->state == CPATH_STATE_AWAITING_KEYS) { + tor_assert(cp->prev->state == CPATH_STATE_OPEN); + } else if (cp->state == CPATH_STATE_OPEN) { + tor_assert(cp->prev->state == CPATH_STATE_OPEN); + } + } + cp = cp->next; + tor_assert(cp); + } while (cp != start); +} + +/** Verify that circuit c has all of its invariants + * correct. Trigger an assert if anything is invalid. + */ +void +assert_circuit_ok(const circuit_t *c) +{ + edge_connection_t *conn; + const or_circuit_t *or_circ = NULL; + const origin_circuit_t *origin_circ = NULL; + + tor_assert(c); + tor_assert(c->magic == ORIGIN_CIRCUIT_MAGIC || c->magic == OR_CIRCUIT_MAGIC); + tor_assert(c->purpose >= CIRCUIT_PURPOSE_MIN_ && + c->purpose <= CIRCUIT_PURPOSE_MAX_); + + { + /* Having a separate variable for this pleases GCC 4.2 in ways I hope I + * never understand. -NM. */ + circuit_t *nonconst_circ = (circuit_t*) c; + if (CIRCUIT_IS_ORIGIN(c)) + origin_circ = TO_ORIGIN_CIRCUIT(nonconst_circ); + else + or_circ = TO_OR_CIRCUIT(nonconst_circ); + } + + if (c->n_chan) { + tor_assert(!c->n_hop); + + if (c->n_circ_id) { + /* We use the _impl variant here to make sure we don't fail on marked + * circuits, which would not be returned by the regular function. */ + circuit_t *c2 = circuit_get_by_circid_channel_impl(c->n_circ_id, + c->n_chan, NULL); + tor_assert(c == c2); + } + } + if (or_circ && or_circ->p_chan) { + if (or_circ->p_circ_id) { + /* ibid */ + circuit_t *c2 = + circuit_get_by_circid_channel_impl(or_circ->p_circ_id, + or_circ->p_chan, NULL); + tor_assert(c == c2); + } + } + if (or_circ) + for (conn = or_circ->n_streams; conn; conn = conn->next_stream) + tor_assert(conn->base_.type == CONN_TYPE_EXIT); + + tor_assert(c->deliver_window >= 0); + tor_assert(c->package_window >= 0); + if (c->state == CIRCUIT_STATE_OPEN) { + tor_assert(!c->n_chan_create_cell); + if (or_circ) { + tor_assert(or_circ->n_crypto); + tor_assert(or_circ->p_crypto); + tor_assert(or_circ->n_digest); + tor_assert(or_circ->p_digest); + } + } + if (c->state == CIRCUIT_STATE_CHAN_WAIT && !c->marked_for_close) { + tor_assert(circuits_pending_chans && + smartlist_contains(circuits_pending_chans, c)); + } else { + tor_assert(!circuits_pending_chans || + !smartlist_contains(circuits_pending_chans, c)); + } + if (origin_circ && origin_circ->cpath) { + assert_cpath_ok(origin_circ->cpath); + } + if (c->purpose == CIRCUIT_PURPOSE_REND_ESTABLISHED) { + tor_assert(or_circ); + if (!c->marked_for_close) { + tor_assert(or_circ->rend_splice); + tor_assert(or_circ->rend_splice->rend_splice == or_circ); + } + tor_assert(or_circ->rend_splice != or_circ); + } else { + tor_assert(!or_circ || !or_circ->rend_splice); + } +} + diff --git a/src/tor/circuitlist.h b/src/tor/circuitlist.h new file mode 100644 index 0000000..1c8cf7d --- /dev/null +++ b/src/tor/circuitlist.h @@ -0,0 +1,82 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file circuitlist.h + * \brief Header file for circuitlist.c. + **/ + +#ifndef TOR_CIRCUITLIST_H +#define TOR_CIRCUITLIST_H + +#include "testsupport.h" + +TOR_LIST_HEAD(global_circuitlist_s, circuit_t); + +struct global_circuitlist_s* circuit_get_global_list(void); +const char *circuit_state_to_string(int state); +const char *circuit_purpose_to_controller_string(uint8_t purpose); +const char *circuit_purpose_to_controller_hs_state_string(uint8_t purpose); +const char *circuit_purpose_to_string(uint8_t purpose); +void circuit_dump_by_conn(connection_t *conn, int severity); +void circuit_dump_by_chan(channel_t *chan, int severity); +void circuit_set_p_circid_chan(or_circuit_t *circ, circid_t id, + channel_t *chan); +void circuit_set_n_circid_chan(circuit_t *circ, circid_t id, + channel_t *chan); +void channel_mark_circid_unusable(channel_t *chan, circid_t id); +void channel_mark_circid_usable(channel_t *chan, circid_t id); +void circuit_set_state(circuit_t *circ, uint8_t state); +void circuit_close_all_marked(void); +int32_t circuit_initial_package_window(void); +origin_circuit_t *origin_circuit_new(void); +or_circuit_t *or_circuit_new(circid_t p_circ_id, channel_t *p_chan); +circuit_t *circuit_get_by_circid_channel(circid_t circ_id, + channel_t *chan); +circuit_t * +circuit_get_by_circid_channel_even_if_marked(circid_t circ_id, + channel_t *chan); +int circuit_id_in_use_on_channel(circid_t circ_id, channel_t *chan); +circuit_t *circuit_get_by_edge_conn(edge_connection_t *conn); +void circuit_unlink_all_from_channel(channel_t *chan, int reason); +origin_circuit_t *circuit_get_by_global_id(uint32_t id); +origin_circuit_t *circuit_get_ready_rend_circ_by_rend_data( + const rend_data_t *rend_data); +origin_circuit_t *circuit_get_next_by_pk_and_purpose(origin_circuit_t *start, + const char *digest, uint8_t purpose); +or_circuit_t *circuit_get_rendezvous(const char *cookie); +or_circuit_t *circuit_get_intro_point(const char *digest); +origin_circuit_t *circuit_find_to_cannibalize(uint8_t purpose, + extend_info_t *info, int flags); +void circuit_mark_all_unused_circs(void); +void circuit_mark_all_dirty_circs_as_unusable(void); +void circuit_mark_for_close_(circuit_t *circ, int reason, + int line, const char *file); +int circuit_get_cpath_len(origin_circuit_t *circ); +void circuit_clear_cpath(origin_circuit_t *circ); +crypt_path_t *circuit_get_cpath_hop(origin_circuit_t *circ, int hopnum); +void circuit_get_all_pending_on_channel(smartlist_t *out, + channel_t *chan); +int circuit_count_pending_on_channel(channel_t *chan); + +#define circuit_mark_for_close(c, reason) \ + circuit_mark_for_close_((c), (reason), __LINE__, SHORT_FILE__) + +void assert_cpath_layer_ok(const crypt_path_t *cp); +void assert_circuit_ok(const circuit_t *c); +void circuit_free_all(void); +void circuits_handle_oom(size_t current_allocation); + +void channel_note_destroy_pending(channel_t *chan, circid_t id); +void channel_note_destroy_not_pending(channel_t *chan, circid_t id); + +#ifdef CIRCUITLIST_PRIVATE +STATIC void circuit_free(circuit_t *circ); +STATIC size_t n_cells_in_circ_queues(const circuit_t *c); +#endif + +#endif + diff --git a/src/tor/circuitmux.c b/src/tor/circuitmux.c new file mode 100644 index 0000000..f2af943 --- /dev/null +++ b/src/tor/circuitmux.c @@ -0,0 +1,1898 @@ +/* * Copyright (c) 2012-2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file circuitmux.c + * \brief Circuit mux/cell selection abstraction + **/ + +#include "or.h" +#include "channel.h" +#include "circuitlist.h" +#include "circuitmux.h" +#include "relay.h" + +/* + * Private typedefs for circuitmux.c + */ + +/* + * Map of muxinfos for circuitmux_t to use; struct is defined below (name + * of struct must match HT_HEAD line). + */ +typedef struct chanid_circid_muxinfo_map chanid_circid_muxinfo_map_t; + +/* + * Hash table entry (yeah, calling it chanid_circid_muxinfo_s seems to + * break the hash table code). + */ +typedef struct chanid_circid_muxinfo_t chanid_circid_muxinfo_t; + +/* + * Anything the mux wants to store per-circuit in the map; right now just + * a count of queued cells. + */ + +typedef struct circuit_muxinfo_s circuit_muxinfo_t; + +/* + * Structures for circuitmux.c + */ + +/* + * A circuitmux is a collection of circuits; it tracks which subset + * of the attached circuits are 'active' (i.e., have cells available + * to transmit) and how many cells on each. It expoes three distinct + * interfaces to other components: + * + * To channels, which each have a circuitmux_t, the supported operations + * are: + * + * circuitmux_get_first_active_circuit(): + * + * Pick one of the circuitmux's active circuits to send cells from. + * + * circuitmux_notify_xmit_cells(): + * + * Notify the circuitmux that cells have been sent on a circuit. + * + * To circuits, the exposed operations are: + * + * circuitmux_attach_circuit(): + * + * Attach a circuit to the circuitmux; this will allocate any policy- + * specific data wanted for this circuit and add it to the active + * circuits list if it has queued cells. + * + * circuitmux_detach_circuit(): + * + * Detach a circuit from the circuitmux, freeing associated structures. + * + * circuitmux_clear_num_cells(): + * + * Clear the circuitmux's cell counter for this circuit. + * + * circuitmux_set_num_cells(): + * + * Set the circuitmux's cell counter for this circuit. + * + * See circuitmux.h for the circuitmux_policy_t data structure, which contains + * a table of function pointers implementing a circuit selection policy, and + * circuitmux_ewma.c for an example of a circuitmux policy. Circuitmux + * policies can be manipulated with: + * + * circuitmux_get_policy(): + * + * Return the current policy for a circuitmux_t, if any. + * + * circuitmux_clear_policy(): + * + * Remove a policy installed on a circuitmux_t, freeing all associated + * data. The circuitmux will revert to the built-in round-robin behavior. + * + * circuitmux_set_policy(): + * + * Install a policy on a circuitmux_t; the appropriate callbacks will be + * made to attach all existing circuits to the new policy. + * + */ + +struct circuitmux_s { + /* Keep count of attached, active circuits */ + unsigned int n_circuits, n_active_circuits; + + /* Total number of queued cells on all circuits */ + unsigned int n_cells; + + /* + * Map from (channel ID, circuit ID) pairs to circuit_muxinfo_t + */ + chanid_circid_muxinfo_map_t *chanid_circid_map; + + /* + * Double-linked ring of circuits with queued cells waiting for room to + * free up on this connection's outbuf. Every time we pull cells from + * a circuit, we advance this pointer to the next circuit in the ring. + */ + struct circuit_t *active_circuits_head, *active_circuits_tail; + + /** List of queued destroy cells */ + cell_queue_t destroy_cell_queue; + /** Boolean: True iff the last cell to circuitmux_get_first_active_circuit + * returned the destroy queue. Used to force alternation between + * destroy/non-destroy cells. + * + * XXXX There is no reason to think that alternating is a particularly good + * approach -- it's just designed to prevent destroys from starving other + * cells completely. + */ + unsigned int last_cell_was_destroy : 1; + /** Destroy counter: increment this when a destroy gets queued, decrement + * when we unqueue it, so we can test to make sure they don't starve. + */ + int64_t destroy_ctr; + + /* + * Circuitmux policy; if this is non-NULL, it can override the built- + * in round-robin active circuits behavior. This is how EWMA works in + * the new circuitmux_t world. + */ + const circuitmux_policy_t *policy; + + /* Policy-specific data */ + circuitmux_policy_data_t *policy_data; +}; + +/* + * This struct holds whatever we want to store per attached circuit on a + * circuitmux_t; right now, just the count of queued cells and the direction. + */ + +struct circuit_muxinfo_s { + /* Count of cells on this circuit at last update */ + unsigned int cell_count; + /* Direction of flow */ + cell_direction_t direction; + /* Policy-specific data */ + circuitmux_policy_circ_data_t *policy_data; + /* Mark bit for consistency checker */ + unsigned int mark:1; +}; + +/* + * A map from channel ID and circuit ID to a circuit_muxinfo_t for that + * circuit. + */ + +struct chanid_circid_muxinfo_t { + HT_ENTRY(chanid_circid_muxinfo_t) node; + uint64_t chan_id; + circid_t circ_id; + circuit_muxinfo_t muxinfo; +}; + +/* + * Internal-use #defines + */ + +#ifdef CMUX_PARANOIA +#define circuitmux_assert_okay_paranoid(cmux) \ + circuitmux_assert_okay(cmux) +#else +#define circuitmux_assert_okay_paranoid(cmux) +#endif + +/* + * Static function declarations + */ + +static INLINE int +chanid_circid_entries_eq(chanid_circid_muxinfo_t *a, + chanid_circid_muxinfo_t *b); +static INLINE unsigned int +chanid_circid_entry_hash(chanid_circid_muxinfo_t *a); +static chanid_circid_muxinfo_t * +circuitmux_find_map_entry(circuitmux_t *cmux, circuit_t *circ); +static void +circuitmux_make_circuit_active(circuitmux_t *cmux, circuit_t *circ, + cell_direction_t direction); +static void +circuitmux_make_circuit_inactive(circuitmux_t *cmux, circuit_t *circ, + cell_direction_t direction); +static INLINE void +circuitmux_move_active_circ_to_tail(circuitmux_t *cmux, circuit_t *circ, + cell_direction_t direction); +static INLINE circuit_t ** +circuitmux_next_active_circ_p(circuitmux_t *cmux, circuit_t *circ); +static INLINE circuit_t ** +circuitmux_prev_active_circ_p(circuitmux_t *cmux, circuit_t *circ); +static void circuitmux_assert_okay_pass_one(circuitmux_t *cmux); +static void circuitmux_assert_okay_pass_two(circuitmux_t *cmux); +static void circuitmux_assert_okay_pass_three(circuitmux_t *cmux); + +/* Static global variables */ + +/** Count the destroy balance to debug destroy queue logic */ +static int64_t global_destroy_ctr = 0; + +/* Function definitions */ + +/** + * Linked list helpers + */ + +/** + * Move an active circuit to the tail of the cmux's active circuits list; + * used by circuitmux_notify_xmit_cells(). + */ + +static INLINE void +circuitmux_move_active_circ_to_tail(circuitmux_t *cmux, circuit_t *circ, + cell_direction_t direction) +{ + circuit_t **next_p = NULL, **prev_p = NULL; + circuit_t **next_prev = NULL, **prev_next = NULL; + circuit_t **tail_next = NULL; + or_circuit_t *or_circ = NULL; + + tor_assert(cmux); + tor_assert(circ); + + circuitmux_assert_okay_paranoid(cmux); + + /* Figure out our next_p and prev_p for this cmux/direction */ + if (direction) { + if (direction == CELL_DIRECTION_OUT) { + tor_assert(circ->n_mux == cmux); + next_p = &(circ->next_active_on_n_chan); + prev_p = &(circ->prev_active_on_n_chan); + } else { + or_circ = TO_OR_CIRCUIT(circ); + tor_assert(or_circ->p_mux == cmux); + next_p = &(or_circ->next_active_on_p_chan); + prev_p = &(or_circ->prev_active_on_p_chan); + } + } else { + if (circ->n_mux == cmux) { + next_p = &(circ->next_active_on_n_chan); + prev_p = &(circ->prev_active_on_n_chan); + direction = CELL_DIRECTION_OUT; + } else { + or_circ = TO_OR_CIRCUIT(circ); + tor_assert(or_circ->p_mux == cmux); + next_p = &(or_circ->next_active_on_p_chan); + prev_p = &(or_circ->prev_active_on_p_chan); + direction = CELL_DIRECTION_IN; + } + } + tor_assert(next_p); + tor_assert(prev_p); + + /* Check if this really is an active circuit */ + if ((*next_p == NULL && *prev_p == NULL) && + !(circ == cmux->active_circuits_head || + circ == cmux->active_circuits_tail)) { + /* Not active, no-op */ + return; + } + + /* Check if this is already the tail */ + if (circ == cmux->active_circuits_tail) return; + + /* Okay, we have to move it; figure out next_prev and prev_next */ + if (*next_p) next_prev = circuitmux_prev_active_circ_p(cmux, *next_p); + if (*prev_p) prev_next = circuitmux_next_active_circ_p(cmux, *prev_p); + /* Adjust the previous node's next pointer, if any */ + if (prev_next) *prev_next = *next_p; + /* Otherwise, we were the head */ + else cmux->active_circuits_head = *next_p; + /* Adjust the next node's previous pointer, if any */ + if (next_prev) *next_prev = *prev_p; + /* We're out of the list; now re-attach at the tail */ + /* Adjust our next and prev pointers */ + *next_p = NULL; + *prev_p = cmux->active_circuits_tail; + /* Set the next pointer of the tail, or the head if none */ + if (cmux->active_circuits_tail) { + tail_next = circuitmux_next_active_circ_p(cmux, + cmux->active_circuits_tail); + *tail_next = circ; + } else { + cmux->active_circuits_head = circ; + } + /* Set the tail to this circuit */ + cmux->active_circuits_tail = circ; + + circuitmux_assert_okay_paranoid(cmux); +} + +static INLINE circuit_t ** +circuitmux_next_active_circ_p(circuitmux_t *cmux, circuit_t *circ) +{ + tor_assert(cmux); + tor_assert(circ); + + if (circ->n_mux == cmux) return &(circ->next_active_on_n_chan); + else { + tor_assert(TO_OR_CIRCUIT(circ)->p_mux == cmux); + return &(TO_OR_CIRCUIT(circ)->next_active_on_p_chan); + } +} + +static INLINE circuit_t ** +circuitmux_prev_active_circ_p(circuitmux_t *cmux, circuit_t *circ) +{ + tor_assert(cmux); + tor_assert(circ); + + if (circ->n_mux == cmux) return &(circ->prev_active_on_n_chan); + else { + tor_assert(TO_OR_CIRCUIT(circ)->p_mux == cmux); + return &(TO_OR_CIRCUIT(circ)->prev_active_on_p_chan); + } +} + +/** + * Helper for chanid_circid_cell_count_map_t hash table: compare the channel + * ID and circuit ID for a and b, and return less than, equal to, or greater + * than zero appropriately. + */ + +static INLINE int +chanid_circid_entries_eq(chanid_circid_muxinfo_t *a, + chanid_circid_muxinfo_t *b) +{ + return a->chan_id == b->chan_id && a->circ_id == b->circ_id; +} + +/** + * Helper: return a hash based on circuit ID and channel ID in a. + */ + +static INLINE unsigned int +chanid_circid_entry_hash(chanid_circid_muxinfo_t *a) +{ + return (((unsigned int)(a->circ_id) << 8) ^ + ((unsigned int)((a->chan_id >> 32) & 0xffffffff)) ^ + ((unsigned int)(a->chan_id & 0xffffffff))); +} + +/* Declare the struct chanid_circid_muxinfo_map type */ +HT_HEAD(chanid_circid_muxinfo_map, chanid_circid_muxinfo_t); + +/* Emit a bunch of hash table stuff */ +HT_PROTOTYPE(chanid_circid_muxinfo_map, chanid_circid_muxinfo_t, node, + chanid_circid_entry_hash, chanid_circid_entries_eq); +HT_GENERATE(chanid_circid_muxinfo_map, chanid_circid_muxinfo_t, node, + chanid_circid_entry_hash, chanid_circid_entries_eq, 0.6, + malloc, realloc, free); + +/* + * Circuitmux alloc/free functions + */ + +/** + * Allocate a new circuitmux_t + */ + +circuitmux_t * +circuitmux_alloc(void) +{ + circuitmux_t *rv = NULL; + + rv = tor_malloc_zero(sizeof(*rv)); + rv->chanid_circid_map = tor_malloc_zero(sizeof(*( rv->chanid_circid_map))); + HT_INIT(chanid_circid_muxinfo_map, rv->chanid_circid_map); + cell_queue_init(&rv->destroy_cell_queue); + + return rv; +} + +/** + * Detach all circuits from a circuitmux (use before circuitmux_free()) + */ + +void +circuitmux_detach_all_circuits(circuitmux_t *cmux) +{ + chanid_circid_muxinfo_t **i = NULL, *to_remove; + channel_t *chan = NULL; + circuit_t *circ = NULL; + + tor_assert(cmux); + /* + * Don't circuitmux_assert_okay_paranoid() here; this gets called when + * channels are being freed and have already been unregistered, so + * the channel ID lookups it does will fail. + */ + + i = HT_START(chanid_circid_muxinfo_map, cmux->chanid_circid_map); + while (i) { + to_remove = *i; + if (to_remove) { + /* Find a channel and circuit */ + chan = channel_find_by_global_id(to_remove->chan_id); + if (chan) { + circ = + circuit_get_by_circid_channel_even_if_marked(to_remove->circ_id, + chan); + if (circ) { + /* Clear the circuit's mux for this direction */ + if (to_remove->muxinfo.direction == CELL_DIRECTION_OUT) { + /* + * Update active_circuits et al.; this does policy notifies, so + * comes before freeing policy data + */ + + if (to_remove->muxinfo.cell_count > 0) { + circuitmux_make_circuit_inactive(cmux, circ, CELL_DIRECTION_OUT); + } + + /* Clear n_mux */ + circ->n_mux = NULL; + } else if (circ->magic == OR_CIRCUIT_MAGIC) { + /* + * Update active_circuits et al.; this does policy notifies, so + * comes before freeing policy data + */ + + if (to_remove->muxinfo.cell_count > 0) { + circuitmux_make_circuit_inactive(cmux, circ, CELL_DIRECTION_IN); + } + + /* + * It has a sensible p_chan and direction == CELL_DIRECTION_IN, + * so clear p_mux. + */ + TO_OR_CIRCUIT(circ)->p_mux = NULL; + } else { + /* Complain and move on */ + log_warn(LD_CIRC, + "Circuit %u/channel " U64_FORMAT " had direction == " + "CELL_DIRECTION_IN, but isn't an or_circuit_t", + (unsigned)to_remove->circ_id, + U64_PRINTF_ARG(to_remove->chan_id)); + } + + /* Free policy-specific data if we have it */ + if (to_remove->muxinfo.policy_data) { + /* + * If we have policy data, assert that we have the means to + * free it + */ + tor_assert(cmux->policy); + tor_assert(cmux->policy->free_circ_data); + /* Call free_circ_data() */ + cmux->policy->free_circ_data(cmux, + cmux->policy_data, + circ, + to_remove->muxinfo.policy_data); + to_remove->muxinfo.policy_data = NULL; + } + } else { + /* Complain and move on */ + log_warn(LD_CIRC, + "Couldn't find circuit %u (for channel " U64_FORMAT ")", + (unsigned)to_remove->circ_id, + U64_PRINTF_ARG(to_remove->chan_id)); + } + } else { + /* Complain and move on */ + log_warn(LD_CIRC, + "Couldn't find channel " U64_FORMAT " (for circuit id %u)", + U64_PRINTF_ARG(to_remove->chan_id), + (unsigned)to_remove->circ_id); + } + + /* Assert that we don't have un-freed policy data for this circuit */ + tor_assert(to_remove->muxinfo.policy_data == NULL); + } + + i = HT_NEXT_RMV(chanid_circid_muxinfo_map, cmux->chanid_circid_map, i); + + /* Free it */ + tor_free(to_remove); + } + + cmux->n_circuits = 0; + cmux->n_active_circuits = 0; + cmux->n_cells = 0; +} + +/** Reclaim all circuit IDs currently marked as unusable on chan because + * of pending destroy cells in cmux. + * + * This function must be called AFTER circuits are unlinked from the (channel, + * circuid-id) map with circuit_unlink_all_from_channel(), but before calling + * circuitmux_free(). + */ +void +circuitmux_mark_destroyed_circids_usable(circuitmux_t *cmux, channel_t *chan) +{ + packed_cell_t *cell; + int n_bad = 0; + TOR_SIMPLEQ_FOREACH(cell, &cmux->destroy_cell_queue.head, next) { + circid_t circid = 0; + if (packed_cell_is_destroy(chan, cell, &circid)) { + channel_mark_circid_usable(chan, circid); + } else { + ++n_bad; + } + } + if (n_bad) + log_warn(LD_BUG, "%d cell(s) on destroy queue did not look like a " + "DESTROY cell.", n_bad); +} + +/** + * Free a circuitmux_t; the circuits must be detached first with + * circuitmux_detach_all_circuits(). + */ + +void +circuitmux_free(circuitmux_t *cmux) +{ + if (!cmux) return; + + tor_assert(cmux->n_circuits == 0); + tor_assert(cmux->n_active_circuits == 0); + + /* + * Free policy-specific data if we have any; we don't + * need to do circuitmux_set_policy(cmux, NULL) to cover + * the circuits because they would have been handled in + * circuitmux_detach_all_circuits() before this was + * called. + */ + if (cmux->policy && cmux->policy->free_cmux_data) { + if (cmux->policy_data) { + cmux->policy->free_cmux_data(cmux, cmux->policy_data); + cmux->policy_data = NULL; + } + } else tor_assert(cmux->policy_data == NULL); + + if (cmux->chanid_circid_map) { + HT_CLEAR(chanid_circid_muxinfo_map, cmux->chanid_circid_map); + tor_free(cmux->chanid_circid_map); + } + + /* + * We're throwing away some destroys; log the counter and + * adjust the global counter by the queue size. + */ + if (cmux->destroy_cell_queue.n > 0) { + cmux->destroy_ctr -= cmux->destroy_cell_queue.n; + global_destroy_ctr -= cmux->destroy_cell_queue.n; + log_debug(LD_CIRC, + "Freeing cmux at %p with %u queued destroys; the last cmux " + "destroy balance was "I64_FORMAT", global is "I64_FORMAT, + cmux, cmux->destroy_cell_queue.n, + I64_PRINTF_ARG(cmux->destroy_ctr), + I64_PRINTF_ARG(global_destroy_ctr)); + } else { + log_debug(LD_CIRC, + "Freeing cmux at %p with no queued destroys, the cmux destroy " + "balance was "I64_FORMAT", global is "I64_FORMAT, + cmux, + I64_PRINTF_ARG(cmux->destroy_ctr), + I64_PRINTF_ARG(global_destroy_ctr)); + } + + cell_queue_clear(&cmux->destroy_cell_queue); + + tor_free(cmux); +} + +/* + * Circuitmux policy control functions + */ + +/** + * Remove any policy installed on cmux; all policy data will be freed and + * cmux behavior will revert to the built-in round-robin active_circuits + * mechanism. + */ + +void +circuitmux_clear_policy(circuitmux_t *cmux) +{ + tor_assert(cmux); + + /* Internally, this is just setting policy to NULL */ + if (cmux->policy) { + circuitmux_set_policy(cmux, NULL); + } +} + +/** + * Return the policy currently installed on a circuitmux_t + */ + +const circuitmux_policy_t * +circuitmux_get_policy(circuitmux_t *cmux) +{ + tor_assert(cmux); + + return cmux->policy; +} + +/** + * Set policy; allocate for new policy, detach all circuits from old policy + * if any, attach them to new policy, and free old policy data. + */ + +void +circuitmux_set_policy(circuitmux_t *cmux, + const circuitmux_policy_t *pol) +{ + const circuitmux_policy_t *old_pol = NULL, *new_pol = NULL; + circuitmux_policy_data_t *old_pol_data = NULL, *new_pol_data = NULL; + chanid_circid_muxinfo_t **i = NULL; + channel_t *chan = NULL; + uint64_t last_chan_id_searched = 0; + circuit_t *circ = NULL; + + tor_assert(cmux); + + /* Set up variables */ + old_pol = cmux->policy; + old_pol_data = cmux->policy_data; + new_pol = pol; + + /* Check if this is the trivial case */ + if (old_pol == new_pol) return; + + /* Allocate data for new policy, if any */ + if (new_pol && new_pol->alloc_cmux_data) { + /* + * If alloc_cmux_data is not null, then we expect to get some policy + * data. Assert that we also have free_cmux_data so we can free it + * when the time comes, and allocate it. + */ + tor_assert(new_pol->free_cmux_data); + new_pol_data = new_pol->alloc_cmux_data(cmux); + tor_assert(new_pol_data); + } + + /* Install new policy and new policy data on cmux */ + cmux->policy = new_pol; + cmux->policy_data = new_pol_data; + + /* Iterate over all circuits, attaching/detaching each one */ + i = HT_START(chanid_circid_muxinfo_map, cmux->chanid_circid_map); + while (i) { + /* Assert that this entry isn't NULL */ + tor_assert(*i); + + /* + * Get the channel; since normal case is all circuits on the mux share a + * channel, we cache last_chan_id_searched + */ + if (!chan || last_chan_id_searched != (*i)->chan_id) { + chan = channel_find_by_global_id((*i)->chan_id); + last_chan_id_searched = (*i)->chan_id; + } + tor_assert(chan); + + /* Get the circuit */ + circ = circuit_get_by_circid_channel_even_if_marked((*i)->circ_id, chan); + tor_assert(circ); + + /* Need to tell old policy it becomes inactive (i.e., it is active) ? */ + if (old_pol && old_pol->notify_circ_inactive && + (*i)->muxinfo.cell_count > 0) { + old_pol->notify_circ_inactive(cmux, old_pol_data, circ, + (*i)->muxinfo.policy_data); + } + + /* Need to free old policy data? */ + if ((*i)->muxinfo.policy_data) { + /* Assert that we have the means to free it if we have policy data */ + tor_assert(old_pol); + tor_assert(old_pol->free_circ_data); + /* Free it */ + old_pol->free_circ_data(cmux, old_pol_data, circ, + (*i)->muxinfo.policy_data); + (*i)->muxinfo.policy_data = NULL; + } + + /* Need to allocate new policy data? */ + if (new_pol && new_pol->alloc_circ_data) { + /* + * If alloc_circ_data is not null, we expect to get some per-circuit + * policy data. Assert that we also have free_circ_data so we can + * free it when the time comes, and allocate it. + */ + tor_assert(new_pol->free_circ_data); + (*i)->muxinfo.policy_data = + new_pol->alloc_circ_data(cmux, new_pol_data, circ, + (*i)->muxinfo.direction, + (*i)->muxinfo.cell_count); + } + + /* Need to make active on new policy? */ + if (new_pol && new_pol->notify_circ_active && + (*i)->muxinfo.cell_count > 0) { + new_pol->notify_circ_active(cmux, new_pol_data, circ, + (*i)->muxinfo.policy_data); + } + + /* Advance to next circuit map entry */ + i = HT_NEXT(chanid_circid_muxinfo_map, cmux->chanid_circid_map, i); + } + + /* Free data for old policy, if any */ + if (old_pol_data) { + /* + * If we had old policy data, we should have an old policy and a free + * function for it. + */ + tor_assert(old_pol); + tor_assert(old_pol->free_cmux_data); + old_pol->free_cmux_data(cmux, old_pol_data); + old_pol_data = NULL; + } +} + +/* + * Circuitmux/circuit attachment status inquiry functions + */ + +/** + * Query the direction of an attached circuit + */ + +cell_direction_t +circuitmux_attached_circuit_direction(circuitmux_t *cmux, circuit_t *circ) +{ + chanid_circid_muxinfo_t *hashent = NULL; + + /* Try to find a map entry */ + hashent = circuitmux_find_map_entry(cmux, circ); + + /* + * This function should only be called on attached circuits; assert that + * we had a map entry. + */ + tor_assert(hashent); + + /* Return the direction from the map entry */ + return hashent->muxinfo.direction; +} + +/** + * Find an entry in the cmux's map for this circuit or return NULL if there + * is none. + */ + +static chanid_circid_muxinfo_t * +circuitmux_find_map_entry(circuitmux_t *cmux, circuit_t *circ) +{ + chanid_circid_muxinfo_t search, *hashent = NULL; + + /* Sanity-check parameters */ + tor_assert(cmux); + tor_assert(cmux->chanid_circid_map); + tor_assert(circ); + + /* Check if we have n_chan */ + if (circ->n_chan) { + /* Okay, let's see if it's attached for n_chan/n_circ_id */ + search.chan_id = circ->n_chan->global_identifier; + search.circ_id = circ->n_circ_id; + + /* Query */ + hashent = HT_FIND(chanid_circid_muxinfo_map, cmux->chanid_circid_map, + &search); + } + + /* Found something? */ + if (hashent) { + /* + * Assert that the direction makes sense for a hashent we found by + * n_chan/n_circ_id before we return it. + */ + tor_assert(hashent->muxinfo.direction == CELL_DIRECTION_OUT); + } else { + /* Not there, have we got a p_chan/p_circ_id to try? */ + if (circ->magic == OR_CIRCUIT_MAGIC) { + search.circ_id = TO_OR_CIRCUIT(circ)->p_circ_id; + /* Check for p_chan */ + if (TO_OR_CIRCUIT(circ)->p_chan) { + search.chan_id = TO_OR_CIRCUIT(circ)->p_chan->global_identifier; + /* Okay, search for that */ + hashent = HT_FIND(chanid_circid_muxinfo_map, cmux->chanid_circid_map, + &search); + /* Find anything? */ + if (hashent) { + /* Assert that the direction makes sense before we return it */ + tor_assert(hashent->muxinfo.direction == CELL_DIRECTION_IN); + } + } + } + } + + /* Okay, hashent is it if it was there */ + return hashent; +} + +/** + * Query whether a circuit is attached to a circuitmux + */ + +int +circuitmux_is_circuit_attached(circuitmux_t *cmux, circuit_t *circ) +{ + chanid_circid_muxinfo_t *hashent = NULL; + + /* Look if it's in the circuit map */ + hashent = circuitmux_find_map_entry(cmux, circ); + + return (hashent != NULL); +} + +/** + * Query whether a circuit is active on a circuitmux + */ + +int +circuitmux_is_circuit_active(circuitmux_t *cmux, circuit_t *circ) +{ + chanid_circid_muxinfo_t *hashent = NULL; + int is_active = 0; + + tor_assert(cmux); + tor_assert(circ); + + /* Look if it's in the circuit map */ + hashent = circuitmux_find_map_entry(cmux, circ); + if (hashent) { + /* Check the number of cells on this circuit */ + is_active = (hashent->muxinfo.cell_count > 0); + } + /* else not attached, so not active */ + + return is_active; +} + +/** + * Query number of available cells for a circuit on a circuitmux + */ + +unsigned int +circuitmux_num_cells_for_circuit(circuitmux_t *cmux, circuit_t *circ) +{ + chanid_circid_muxinfo_t *hashent = NULL; + unsigned int n_cells = 0; + + tor_assert(cmux); + tor_assert(circ); + + /* Look if it's in the circuit map */ + hashent = circuitmux_find_map_entry(cmux, circ); + if (hashent) { + /* Just get the cell count for this circuit */ + n_cells = hashent->muxinfo.cell_count; + } + /* else not attached, so 0 cells */ + + return n_cells; +} + +/** + * Query total number of available cells on a circuitmux + */ + +unsigned int +circuitmux_num_cells(circuitmux_t *cmux) +{ + tor_assert(cmux); + + return cmux->n_cells + cmux->destroy_cell_queue.n; +} + +/** + * Query total number of circuits active on a circuitmux + */ + +unsigned int +circuitmux_num_active_circuits(circuitmux_t *cmux) +{ + tor_assert(cmux); + + return cmux->n_active_circuits; +} + +/** + * Query total number of circuits attached to a circuitmux + */ + +unsigned int +circuitmux_num_circuits(circuitmux_t *cmux) +{ + tor_assert(cmux); + + return cmux->n_circuits; +} + +/* + * Functions for circuit code to call to update circuit status + */ + +/** + * Attach a circuit to a circuitmux, for the specified direction. + */ + +MOCK_IMPL(void, +circuitmux_attach_circuit,(circuitmux_t *cmux, circuit_t *circ, + cell_direction_t direction)) +{ + channel_t *chan = NULL; + uint64_t channel_id; + circid_t circ_id; + chanid_circid_muxinfo_t search, *hashent = NULL; + unsigned int cell_count; + + tor_assert(cmux); + tor_assert(circ); + tor_assert(direction == CELL_DIRECTION_IN || + direction == CELL_DIRECTION_OUT); + circuitmux_assert_okay_paranoid(cmux); + + /* + * Figure out which channel we're using, and get the circuit's current + * cell count and circuit ID; assert that the circuit is not already + * attached to another mux. + */ + if (direction == CELL_DIRECTION_OUT) { + /* It's n_chan */ + chan = circ->n_chan; + cell_count = circ->n_chan_cells.n; + circ_id = circ->n_circ_id; + } else { + /* We want p_chan */ + chan = TO_OR_CIRCUIT(circ)->p_chan; + cell_count = TO_OR_CIRCUIT(circ)->p_chan_cells.n; + circ_id = TO_OR_CIRCUIT(circ)->p_circ_id; + } + /* Assert that we did get a channel */ + tor_assert(chan); + /* Assert that the circuit ID is sensible */ + tor_assert(circ_id != 0); + + /* Get the channel ID */ + channel_id = chan->global_identifier; + + /* See if we already have this one */ + search.chan_id = channel_id; + search.circ_id = circ_id; + hashent = HT_FIND(chanid_circid_muxinfo_map, cmux->chanid_circid_map, + &search); + + if (hashent) { + /* + * This circuit was already attached to this cmux; make sure the + * directions match and update the cell count and active circuit count. + */ + log_info(LD_CIRC, + "Circuit %u on channel " U64_FORMAT " was already attached to " + "cmux %p (trying to attach to %p)", + (unsigned)circ_id, U64_PRINTF_ARG(channel_id), + ((direction == CELL_DIRECTION_OUT) ? + circ->n_mux : TO_OR_CIRCUIT(circ)->p_mux), + cmux); + + /* + * The mux pointer on this circuit and the direction in result should + * match; otherwise assert. + */ + if (direction == CELL_DIRECTION_OUT) tor_assert(circ->n_mux == cmux); + else tor_assert(TO_OR_CIRCUIT(circ)->p_mux == cmux); + tor_assert(hashent->muxinfo.direction == direction); + + /* + * Looks okay; just update the cell count and active circuits if we must + */ + if (hashent->muxinfo.cell_count > 0 && cell_count == 0) { + --(cmux->n_active_circuits); + circuitmux_make_circuit_inactive(cmux, circ, direction); + } else if (hashent->muxinfo.cell_count == 0 && cell_count > 0) { + ++(cmux->n_active_circuits); + circuitmux_make_circuit_active(cmux, circ, direction); + } + cmux->n_cells -= hashent->muxinfo.cell_count; + cmux->n_cells += cell_count; + hashent->muxinfo.cell_count = cell_count; + } else { + /* + * New circuit; add an entry and update the circuit/active circuit + * counts. + */ + log_debug(LD_CIRC, + "Attaching circuit %u on channel " U64_FORMAT " to cmux %p", + (unsigned)circ_id, U64_PRINTF_ARG(channel_id), cmux); + + /* + * Assert that the circuit doesn't already have a mux for this + * direction. + */ + if (direction == CELL_DIRECTION_OUT) tor_assert(circ->n_mux == NULL); + else tor_assert(TO_OR_CIRCUIT(circ)->p_mux == NULL); + + /* Insert it in the map */ + hashent = tor_malloc_zero(sizeof(*hashent)); + hashent->chan_id = channel_id; + hashent->circ_id = circ_id; + hashent->muxinfo.cell_count = cell_count; + hashent->muxinfo.direction = direction; + /* Allocate policy specific circuit data if we need it */ + if (cmux->policy && cmux->policy->alloc_circ_data) { + /* Assert that we have the means to free policy-specific data */ + tor_assert(cmux->policy->free_circ_data); + /* Allocate it */ + hashent->muxinfo.policy_data = + cmux->policy->alloc_circ_data(cmux, + cmux->policy_data, + circ, + direction, + cell_count); + /* If we wanted policy data, it's an error not to get any */ + tor_assert(hashent->muxinfo.policy_data); + } + HT_INSERT(chanid_circid_muxinfo_map, cmux->chanid_circid_map, + hashent); + + /* Set the circuit's mux for this direction */ + if (direction == CELL_DIRECTION_OUT) circ->n_mux = cmux; + else TO_OR_CIRCUIT(circ)->p_mux = cmux; + + /* Make sure the next/prev pointers are NULL */ + if (direction == CELL_DIRECTION_OUT) { + circ->next_active_on_n_chan = NULL; + circ->prev_active_on_n_chan = NULL; + } else { + TO_OR_CIRCUIT(circ)->next_active_on_p_chan = NULL; + TO_OR_CIRCUIT(circ)->prev_active_on_p_chan = NULL; + } + + /* Update counters */ + ++(cmux->n_circuits); + if (cell_count > 0) { + ++(cmux->n_active_circuits); + circuitmux_make_circuit_active(cmux, circ, direction); + } + cmux->n_cells += cell_count; + } + + circuitmux_assert_okay_paranoid(cmux); +} + +/** + * Detach a circuit from a circuitmux and update all counters as needed; + * no-op if not attached. + */ + +MOCK_IMPL(void, +circuitmux_detach_circuit,(circuitmux_t *cmux, circuit_t *circ)) +{ + chanid_circid_muxinfo_t search, *hashent = NULL; + /* + * Use this to keep track of whether we found it for n_chan or + * p_chan for consistency checking. + */ + cell_direction_t last_searched_direction; + + tor_assert(cmux); + tor_assert(cmux->chanid_circid_map); + tor_assert(circ); + circuitmux_assert_okay_paranoid(cmux); + + /* See if we have it for n_chan/n_circ_id */ + if (circ->n_chan) { + search.chan_id = circ->n_chan->global_identifier; + search.circ_id = circ->n_circ_id; + hashent = HT_FIND(chanid_circid_muxinfo_map, cmux->chanid_circid_map, + &search); + last_searched_direction = CELL_DIRECTION_OUT; + } + + /* Got one? If not, see if it's an or_circuit_t and try p_chan/p_circ_id */ + if (!hashent) { + if (circ->magic == OR_CIRCUIT_MAGIC) { + search.circ_id = TO_OR_CIRCUIT(circ)->p_circ_id; + if (TO_OR_CIRCUIT(circ)->p_chan) { + search.chan_id = TO_OR_CIRCUIT(circ)->p_chan->global_identifier; + hashent = HT_FIND(chanid_circid_muxinfo_map, + cmux->chanid_circid_map, + &search); + last_searched_direction = CELL_DIRECTION_IN; + } + } + } + + /* + * If hashent isn't NULL, we have a circuit to detach; don't remove it from + * the map until later of circuitmux_make_circuit_inactive() breaks. + */ + if (hashent) { + /* Update counters */ + --(cmux->n_circuits); + if (hashent->muxinfo.cell_count > 0) { + --(cmux->n_active_circuits); + /* This does policy notifies, so comes before freeing policy data */ + circuitmux_make_circuit_inactive(cmux, circ, last_searched_direction); + } + cmux->n_cells -= hashent->muxinfo.cell_count; + + /* Free policy-specific data if we have it */ + if (hashent->muxinfo.policy_data) { + /* If we have policy data, assert that we have the means to free it */ + tor_assert(cmux->policy); + tor_assert(cmux->policy->free_circ_data); + /* Call free_circ_data() */ + cmux->policy->free_circ_data(cmux, + cmux->policy_data, + circ, + hashent->muxinfo.policy_data); + hashent->muxinfo.policy_data = NULL; + } + + /* Consistency check: the direction must match the direction searched */ + tor_assert(last_searched_direction == hashent->muxinfo.direction); + /* Clear the circuit's mux for this direction */ + if (last_searched_direction == CELL_DIRECTION_OUT) circ->n_mux = NULL; + else TO_OR_CIRCUIT(circ)->p_mux = NULL; + + /* Now remove it from the map */ + HT_REMOVE(chanid_circid_muxinfo_map, cmux->chanid_circid_map, hashent); + + /* Free the hash entry */ + tor_free(hashent); + } + + circuitmux_assert_okay_paranoid(cmux); +} + +/** + * Make a circuit active; update active list and policy-specific info, but + * we don't mess with the counters or hash table here. + */ + +static void +circuitmux_make_circuit_active(circuitmux_t *cmux, circuit_t *circ, + cell_direction_t direction) +{ + circuit_t **next_active = NULL, **prev_active = NULL, **next_prev = NULL; + circuitmux_t *circuit_cmux = NULL; + chanid_circid_muxinfo_t *hashent = NULL; + channel_t *chan = NULL; + circid_t circ_id; + int already_active; + + tor_assert(cmux); + tor_assert(circ); + tor_assert(direction == CELL_DIRECTION_OUT || + direction == CELL_DIRECTION_IN); + /* + * Don't circuitmux_assert_okay_paranoid(cmux) here because the cell count + * already got changed and we have to update the list for it to be consistent + * again. + */ + + /* Get the right set of active list links for this direction */ + if (direction == CELL_DIRECTION_OUT) { + next_active = &(circ->next_active_on_n_chan); + prev_active = &(circ->prev_active_on_n_chan); + circuit_cmux = circ->n_mux; + chan = circ->n_chan; + circ_id = circ->n_circ_id; + } else { + next_active = &(TO_OR_CIRCUIT(circ)->next_active_on_p_chan); + prev_active = &(TO_OR_CIRCUIT(circ)->prev_active_on_p_chan); + circuit_cmux = TO_OR_CIRCUIT(circ)->p_mux; + chan = TO_OR_CIRCUIT(circ)->p_chan; + circ_id = TO_OR_CIRCUIT(circ)->p_circ_id; + } + + /* Assert that it is attached to this mux and a channel */ + tor_assert(cmux == circuit_cmux); + tor_assert(chan != NULL); + + /* + * Check if the circuit really was inactive; if it's active, at least one + * of the next_active and prev_active pointers will not be NULL, or this + * circuit will be either the head or tail of the list for this cmux. + */ + already_active = (*prev_active != NULL || *next_active != NULL || + cmux->active_circuits_head == circ || + cmux->active_circuits_tail == circ); + + /* If we're already active, log a warning and finish */ + if (already_active) { + log_warn(LD_CIRC, + "Circuit %u on channel " U64_FORMAT " was already active", + (unsigned)circ_id, U64_PRINTF_ARG(chan->global_identifier)); + return; + } + + /* + * This is going at the head of the list; if the old head is not NULL, + * then its prev pointer should point to this. + */ + *next_active = cmux->active_circuits_head; /* Next is old head */ + *prev_active = NULL; /* Prev is NULL (this will be the head) */ + if (cmux->active_circuits_head) { + /* The list had an old head; update its prev pointer */ + next_prev = + circuitmux_prev_active_circ_p(cmux, cmux->active_circuits_head); + tor_assert(next_prev); + *next_prev = circ; + } else { + /* The list was empty; this becomes the tail as well */ + cmux->active_circuits_tail = circ; + } + /* This becomes the new head of the list */ + cmux->active_circuits_head = circ; + + /* Policy-specific notification */ + if (cmux->policy && + cmux->policy->notify_circ_active) { + /* Okay, we need to check the circuit for policy data now */ + hashent = circuitmux_find_map_entry(cmux, circ); + /* We should have found something */ + tor_assert(hashent); + /* Notify */ + cmux->policy->notify_circ_active(cmux, cmux->policy_data, + circ, hashent->muxinfo.policy_data); + } + + circuitmux_assert_okay_paranoid(cmux); +} + +/** + * Make a circuit inactive; update active list and policy-specific info, but + * we don't mess with the counters or hash table here. + */ + +static void +circuitmux_make_circuit_inactive(circuitmux_t *cmux, circuit_t *circ, + cell_direction_t direction) +{ + circuit_t **next_active = NULL, **prev_active = NULL; + circuit_t **next_prev = NULL, **prev_next = NULL; + circuitmux_t *circuit_cmux = NULL; + chanid_circid_muxinfo_t *hashent = NULL; + channel_t *chan = NULL; + circid_t circ_id; + int already_inactive; + + tor_assert(cmux); + tor_assert(circ); + tor_assert(direction == CELL_DIRECTION_OUT || + direction == CELL_DIRECTION_IN); + /* + * Don't circuitmux_assert_okay_paranoid(cmux) here because the cell count + * already got changed and we have to update the list for it to be consistent + * again. + */ + + /* Get the right set of active list links for this direction */ + if (direction == CELL_DIRECTION_OUT) { + next_active = &(circ->next_active_on_n_chan); + prev_active = &(circ->prev_active_on_n_chan); + circuit_cmux = circ->n_mux; + chan = circ->n_chan; + circ_id = circ->n_circ_id; + } else { + next_active = &(TO_OR_CIRCUIT(circ)->next_active_on_p_chan); + prev_active = &(TO_OR_CIRCUIT(circ)->prev_active_on_p_chan); + circuit_cmux = TO_OR_CIRCUIT(circ)->p_mux; + chan = TO_OR_CIRCUIT(circ)->p_chan; + circ_id = TO_OR_CIRCUIT(circ)->p_circ_id; + } + + /* Assert that it is attached to this mux and a channel */ + tor_assert(cmux == circuit_cmux); + tor_assert(chan != NULL); + + /* + * Check if the circuit really was active; if it's inactive, the + * next_active and prev_active pointers will be NULL and this circuit + * will not be the head or tail of the list for this cmux. + */ + already_inactive = (*prev_active == NULL && *next_active == NULL && + cmux->active_circuits_head != circ && + cmux->active_circuits_tail != circ); + + /* If we're already inactive, log a warning and finish */ + if (already_inactive) { + log_warn(LD_CIRC, + "Circuit %d on channel " U64_FORMAT " was already inactive", + (unsigned)circ_id, U64_PRINTF_ARG(chan->global_identifier)); + return; + } + + /* Remove from the list; first get next_prev and prev_next */ + if (*next_active) { + /* + * If there's a next circuit, its previous circuit becomes this + * circuit's previous circuit. + */ + next_prev = circuitmux_prev_active_circ_p(cmux, *next_active); + } else { + /* Else, the tail becomes this circuit's previous circuit */ + next_prev = &(cmux->active_circuits_tail); + } + + /* Got next_prev, now prev_next */ + if (*prev_active) { + /* + * If there's a previous circuit, its next circuit becomes this circuit's + * next circuit. + */ + prev_next = circuitmux_next_active_circ_p(cmux, *prev_active); + } else { + /* Else, the head becomes this circuit's next circuit */ + prev_next = &(cmux->active_circuits_head); + } + + /* Assert that we got sensible values for the next/prev pointers */ + tor_assert(next_prev != NULL); + tor_assert(prev_next != NULL); + + /* Update the next/prev pointers - this removes circ from the list */ + *next_prev = *prev_active; + *prev_next = *next_active; + + /* Now null out prev_active/next_active */ + *prev_active = NULL; + *next_active = NULL; + + /* Policy-specific notification */ + if (cmux->policy && + cmux->policy->notify_circ_inactive) { + /* Okay, we need to check the circuit for policy data now */ + hashent = circuitmux_find_map_entry(cmux, circ); + /* We should have found something */ + tor_assert(hashent); + /* Notify */ + cmux->policy->notify_circ_inactive(cmux, cmux->policy_data, + circ, hashent->muxinfo.policy_data); + } + + circuitmux_assert_okay_paranoid(cmux); +} + +/** + * Clear the cell counter for a circuit on a circuitmux + */ + +void +circuitmux_clear_num_cells(circuitmux_t *cmux, circuit_t *circ) +{ + /* This is the same as setting the cell count to zero */ + circuitmux_set_num_cells(cmux, circ, 0); +} + +/** + * Set the cell counter for a circuit on a circuitmux + */ + +void +circuitmux_set_num_cells(circuitmux_t *cmux, circuit_t *circ, + unsigned int n_cells) +{ + chanid_circid_muxinfo_t *hashent = NULL; + + tor_assert(cmux); + tor_assert(circ); + + circuitmux_assert_okay_paranoid(cmux); + + /* Search for this circuit's entry */ + hashent = circuitmux_find_map_entry(cmux, circ); + /* Assert that we found one */ + tor_assert(hashent); + + /* Update cmux cell counter */ + cmux->n_cells -= hashent->muxinfo.cell_count; + cmux->n_cells += n_cells; + + /* Do we need to notify a cmux policy? */ + if (cmux->policy && cmux->policy->notify_set_n_cells) { + /* Call notify_set_n_cells */ + cmux->policy->notify_set_n_cells(cmux, + cmux->policy_data, + circ, + hashent->muxinfo.policy_data, + n_cells); + } + + /* + * Update cmux active circuit counter: is the old cell count > 0 and the + * new cell count == 0 ? + */ + if (hashent->muxinfo.cell_count > 0 && n_cells == 0) { + --(cmux->n_active_circuits); + hashent->muxinfo.cell_count = n_cells; + circuitmux_make_circuit_inactive(cmux, circ, hashent->muxinfo.direction); + /* Is the old cell count == 0 and the new cell count > 0 ? */ + } else if (hashent->muxinfo.cell_count == 0 && n_cells > 0) { + ++(cmux->n_active_circuits); + hashent->muxinfo.cell_count = n_cells; + circuitmux_make_circuit_active(cmux, circ, hashent->muxinfo.direction); + } else { + /* + * Update the entry cell count like this so we can put a + * circuitmux_assert_okay_paranoid inside make_circuit_(in)active() too. + */ + hashent->muxinfo.cell_count = n_cells; + } + + circuitmux_assert_okay_paranoid(cmux); +} + +/* + * Functions for channel code to call to get a circuit to transmit from or + * notify that cells have been transmitted. + */ + +/** + * Pick a circuit to send from, using the active circuits list or a + * circuitmux policy if one is available. This is called from channel.c. + * + * If we would rather send a destroy cell, return NULL and set + * *destroy_queue_out to the destroy queue. + * + * If we have nothing to send, set *destroy_queue_out to NULL and + * return NULL. + */ + +circuit_t * +circuitmux_get_first_active_circuit(circuitmux_t *cmux, + cell_queue_t **destroy_queue_out) +{ + circuit_t *circ = NULL; + + tor_assert(cmux); + tor_assert(destroy_queue_out); + + *destroy_queue_out = NULL; + + if (cmux->destroy_cell_queue.n && + (!cmux->last_cell_was_destroy || cmux->n_active_circuits == 0)) { + /* We have destroy cells to send, and either we just sent a relay cell, + * or we have no relay cells to send. */ + + /* XXXX We should let the cmux policy have some say in this eventually. */ + /* XXXX Alternating is not a terribly brilliant approach here. */ + *destroy_queue_out = &cmux->destroy_cell_queue; + + cmux->last_cell_was_destroy = 1; + } else if (cmux->n_active_circuits > 0) { + /* We also must have a cell available for this to be the case */ + tor_assert(cmux->n_cells > 0); + /* Do we have a policy-provided circuit selector? */ + if (cmux->policy && cmux->policy->pick_active_circuit) { + circ = cmux->policy->pick_active_circuit(cmux, cmux->policy_data); + } + /* Fall back on the head of the active circuits list */ + if (!circ) { + tor_assert(cmux->active_circuits_head); + circ = cmux->active_circuits_head; + } + cmux->last_cell_was_destroy = 0; + } else { + tor_assert(cmux->n_cells == 0); + tor_assert(cmux->destroy_cell_queue.n == 0); + } + + return circ; +} + +/** + * Notify the circuitmux that cells have been sent on a circuit; this + * is called from channel.c. + */ + +void +circuitmux_notify_xmit_cells(circuitmux_t *cmux, circuit_t *circ, + unsigned int n_cells) +{ + chanid_circid_muxinfo_t *hashent = NULL; + int becomes_inactive = 0; + + tor_assert(cmux); + tor_assert(circ); + circuitmux_assert_okay_paranoid(cmux); + + if (n_cells == 0) return; + + /* + * To handle this, we have to: + * + * 1.) Adjust the circuit's cell counter in the cmux hash table + * 2.) Move the circuit to the tail of the active_circuits linked list + * for this cmux, or make the circuit inactive if the cell count + * went to zero. + * 3.) Call cmux->policy->notify_xmit_cells(), if any + */ + + /* Find the hash entry */ + hashent = circuitmux_find_map_entry(cmux, circ); + /* Assert that we found one */ + tor_assert(hashent); + + /* Adjust the cell counter and assert that we had that many cells to send */ + tor_assert(n_cells <= hashent->muxinfo.cell_count); + hashent->muxinfo.cell_count -= n_cells; + /* Do we need to make the circuit inactive? */ + if (hashent->muxinfo.cell_count == 0) becomes_inactive = 1; + /* Adjust the mux cell counter */ + cmux->n_cells -= n_cells; + + /* If we aren't making it inactive later, move it to the tail of the list */ + if (!becomes_inactive) { + circuitmux_move_active_circ_to_tail(cmux, circ, + hashent->muxinfo.direction); + } + + /* + * We call notify_xmit_cells() before making the circuit inactive if needed, + * so the policy can always count on this coming in on an active circuit. + */ + if (cmux->policy && cmux->policy->notify_xmit_cells) { + cmux->policy->notify_xmit_cells(cmux, cmux->policy_data, circ, + hashent->muxinfo.policy_data, + n_cells); + } + + /* + * Now make the circuit inactive if needed; this will call the policy's + * notify_circ_inactive() if present. + */ + if (becomes_inactive) { + --(cmux->n_active_circuits); + circuitmux_make_circuit_inactive(cmux, circ, hashent->muxinfo.direction); + } + + circuitmux_assert_okay_paranoid(cmux); +} + +/** + * Notify the circuitmux that a destroy was sent, so we can update + * the counter. + */ + +void +circuitmux_notify_xmit_destroy(circuitmux_t *cmux) +{ + tor_assert(cmux); + + --(cmux->destroy_ctr); + --(global_destroy_ctr); + log_debug(LD_CIRC, + "Cmux at %p sent a destroy, cmux counter is now "I64_FORMAT", " + "global counter is now "I64_FORMAT, + cmux, + I64_PRINTF_ARG(cmux->destroy_ctr), + I64_PRINTF_ARG(global_destroy_ctr)); +} + +/* + * Circuitmux consistency checking assertions + */ + +/** + * Check that circuitmux data structures are consistent and fail with an + * assert if not. + */ + +void +circuitmux_assert_okay(circuitmux_t *cmux) +{ + tor_assert(cmux); + + /* + * Pass 1: iterate the hash table; for each entry: + * a) Check that the circuit has this cmux for n_mux or p_mux + * b) If the cell_count is > 0, set the mark bit; otherwise clear it + * c) Also check activeness (cell_count > 0 should be active) + * d) Count the number of circuits, active circuits and queued cells + * and at the end check that they match the counters in the cmux. + * + * Pass 2: iterate the active circuits list; for each entry, + * make sure the circuit is attached to this mux and appears + * in the hash table. Make sure the mark bit is 1, and clear + * it in the hash table entry. Consistency-check the linked + * list pointers. + * + * Pass 3: iterate the hash table again; assert if any active circuits + * (mark bit set to 1) are discovered that weren't cleared in pass 2 + * (don't appear in the linked list). + */ + + circuitmux_assert_okay_pass_one(cmux); + circuitmux_assert_okay_pass_two(cmux); + circuitmux_assert_okay_pass_three(cmux); +} + +/** + * Do the first pass of circuitmux_assert_okay(); see the comment in that + * function. + */ + +static void +circuitmux_assert_okay_pass_one(circuitmux_t *cmux) +{ + chanid_circid_muxinfo_t **i = NULL; + uint64_t chan_id; + channel_t *chan; + circid_t circ_id; + circuit_t *circ; + or_circuit_t *or_circ; + unsigned int circ_is_active; + circuit_t **next_p, **prev_p; + unsigned int n_circuits, n_active_circuits, n_cells; + + tor_assert(cmux); + tor_assert(cmux->chanid_circid_map); + + /* Reset the counters */ + n_circuits = n_active_circuits = n_cells = 0; + /* Start iterating the hash table */ + i = HT_START(chanid_circid_muxinfo_map, cmux->chanid_circid_map); + while (i) { + /* Assert that the hash table entry isn't null */ + tor_assert(*i); + + /* Get the channel and circuit id */ + chan_id = (*i)->chan_id; + circ_id = (*i)->circ_id; + + /* Find the channel and circuit, assert that they exist */ + chan = channel_find_by_global_id(chan_id); + tor_assert(chan); + circ = circuit_get_by_circid_channel_even_if_marked(circ_id, chan); + tor_assert(circ); + /* Clear the circ_is_active bit to start */ + circ_is_active = 0; + + /* Assert that we know which direction this is going */ + tor_assert((*i)->muxinfo.direction == CELL_DIRECTION_OUT || + (*i)->muxinfo.direction == CELL_DIRECTION_IN); + + if ((*i)->muxinfo.direction == CELL_DIRECTION_OUT) { + /* We should be n_mux on this circuit */ + tor_assert(cmux == circ->n_mux); + tor_assert(chan == circ->n_chan); + /* Get next and prev for next test */ + next_p = &(circ->next_active_on_n_chan); + prev_p = &(circ->prev_active_on_n_chan); + } else { + /* This should be an or_circuit_t and we should be p_mux */ + or_circ = TO_OR_CIRCUIT(circ); + tor_assert(cmux == or_circ->p_mux); + tor_assert(chan == or_circ->p_chan); + /* Get next and prev for next test */ + next_p = &(or_circ->next_active_on_p_chan); + prev_p = &(or_circ->prev_active_on_p_chan); + } + + /* + * Should this circuit be active? I.e., does the mux know about > 0 + * cells on it? + */ + circ_is_active = ((*i)->muxinfo.cell_count > 0); + + /* It should be in the linked list iff it's active */ + if (circ_is_active) { + /* Either we have a next link or we are the tail */ + tor_assert(*next_p || (circ == cmux->active_circuits_tail)); + /* Either we have a prev link or we are the head */ + tor_assert(*prev_p || (circ == cmux->active_circuits_head)); + /* Increment the active circuits counter */ + ++n_active_circuits; + } else { + /* Shouldn't be in list, so no next or prev link */ + tor_assert(!(*next_p)); + tor_assert(!(*prev_p)); + /* And can't be head or tail */ + tor_assert(circ != cmux->active_circuits_head); + tor_assert(circ != cmux->active_circuits_tail); + } + + /* Increment the circuits counter */ + ++n_circuits; + /* Adjust the cell counter */ + n_cells += (*i)->muxinfo.cell_count; + + /* Set the mark bit to circ_is_active */ + (*i)->muxinfo.mark = circ_is_active; + + /* Advance to the next entry */ + i = HT_NEXT(chanid_circid_muxinfo_map, cmux->chanid_circid_map, i); + } + + /* Now check the counters */ + tor_assert(n_cells == cmux->n_cells); + tor_assert(n_circuits == cmux->n_circuits); + tor_assert(n_active_circuits == cmux->n_active_circuits); +} + +/** + * Do the second pass of circuitmux_assert_okay(); see the comment in that + * function. + */ + +static void +circuitmux_assert_okay_pass_two(circuitmux_t *cmux) +{ + circuit_t *curr_circ, *prev_circ = NULL, *next_circ; + or_circuit_t *curr_or_circ; + uint64_t curr_chan_id; + circid_t curr_circ_id; + circuit_t **next_p, **prev_p; + channel_t *chan; + unsigned int n_active_circuits = 0; + cell_direction_t direction; + chanid_circid_muxinfo_t search, *hashent = NULL; + + tor_assert(cmux); + tor_assert(cmux->chanid_circid_map); + + /* + * Walk the linked list of active circuits in cmux; keep track of the + * previous circuit seen for consistency checking purposes. Count them + * to make sure the number in the linked list matches + * cmux->n_active_circuits. + */ + curr_circ = cmux->active_circuits_head; + while (curr_circ) { + /* Reset some things */ + chan = NULL; + curr_or_circ = NULL; + next_circ = NULL; + next_p = prev_p = NULL; + direction = 0; + + /* Figure out if this is n_mux or p_mux */ + if (cmux == curr_circ->n_mux) { + /* Get next_p and prev_p */ + next_p = &(curr_circ->next_active_on_n_chan); + prev_p = &(curr_circ->prev_active_on_n_chan); + /* Get the channel */ + chan = curr_circ->n_chan; + /* Get the circuit id */ + curr_circ_id = curr_circ->n_circ_id; + /* Remember the direction */ + direction = CELL_DIRECTION_OUT; + } else { + /* We must be p_mux and this must be an or_circuit_t */ + curr_or_circ = TO_OR_CIRCUIT(curr_circ); + tor_assert(cmux == curr_or_circ->p_mux); + /* Get next_p and prev_p */ + next_p = &(curr_or_circ->next_active_on_p_chan); + prev_p = &(curr_or_circ->prev_active_on_p_chan); + /* Get the channel */ + chan = curr_or_circ->p_chan; + /* Get the circuit id */ + curr_circ_id = curr_or_circ->p_circ_id; + /* Remember the direction */ + direction = CELL_DIRECTION_IN; + } + + /* Assert that we got a channel and get the channel ID */ + tor_assert(chan); + curr_chan_id = chan->global_identifier; + + /* Assert that prev_p points to last circuit we saw */ + tor_assert(*prev_p == prev_circ); + /* If that's NULL, assert that we are the head */ + if (!(*prev_p)) tor_assert(curr_circ == cmux->active_circuits_head); + + /* Get the next circuit */ + next_circ = *next_p; + /* If it's NULL, assert that we are the tail */ + if (!(*next_p)) tor_assert(curr_circ == cmux->active_circuits_tail); + + /* Now find the hash table entry for this circuit */ + search.chan_id = curr_chan_id; + search.circ_id = curr_circ_id; + hashent = HT_FIND(chanid_circid_muxinfo_map, cmux->chanid_circid_map, + &search); + + /* Assert that we have one */ + tor_assert(hashent); + + /* Assert that the direction matches */ + tor_assert(direction == hashent->muxinfo.direction); + + /* Assert that the hash entry got marked in pass one */ + tor_assert(hashent->muxinfo.mark); + + /* Clear the mark */ + hashent->muxinfo.mark = 0; + + /* Increment the counter */ + ++n_active_circuits; + + /* Advance to the next active circuit and update prev_circ */ + prev_circ = curr_circ; + curr_circ = next_circ; + } + + /* Assert that the counter matches the cmux */ + tor_assert(n_active_circuits == cmux->n_active_circuits); +} + +/** + * Do the third pass of circuitmux_assert_okay(); see the comment in that + * function. + */ + +static void +circuitmux_assert_okay_pass_three(circuitmux_t *cmux) +{ + chanid_circid_muxinfo_t **i = NULL; + + tor_assert(cmux); + tor_assert(cmux->chanid_circid_map); + + /* Start iterating the hash table */ + i = HT_START(chanid_circid_muxinfo_map, cmux->chanid_circid_map); + + /* Advance through each entry */ + while (i) { + /* Assert that it isn't null */ + tor_assert(*i); + + /* + * Assert that this entry is not marked - i.e., that either we didn't + * think it should be active in pass one or we saw it in the active + * circuits linked list. + */ + tor_assert(!((*i)->muxinfo.mark)); + + /* Advance to the next entry */ + i = HT_NEXT(chanid_circid_muxinfo_map, cmux->chanid_circid_map, i); + } +} + +/*DOCDOC */ +void +circuitmux_append_destroy_cell(channel_t *chan, + circuitmux_t *cmux, + circid_t circ_id, + uint8_t reason) +{ + cell_t cell; + memset(&cell, 0, sizeof(cell_t)); + cell.circ_id = circ_id; + cell.command = CELL_DESTROY; + cell.payload[0] = (uint8_t) reason; + + cell_queue_append_packed_copy(NULL, &cmux->destroy_cell_queue, 0, &cell, + chan->wide_circ_ids, 0); + + /* Destroy entering the queue, update counters */ + ++(cmux->destroy_ctr); + ++global_destroy_ctr; + log_debug(LD_CIRC, + "Cmux at %p queued a destroy for circ %u, cmux counter is now " + I64_FORMAT", global counter is now "I64_FORMAT, + cmux, circ_id, + I64_PRINTF_ARG(cmux->destroy_ctr), + I64_PRINTF_ARG(global_destroy_ctr)); + + /* XXXX Duplicate code from append_cell_to_circuit_queue */ + if (!channel_has_queued_writes(chan)) { + /* There is no data at all waiting to be sent on the outbuf. Add a + * cell, so that we can notice when it gets flushed, flushed_some can + * get called, and we can start putting more data onto the buffer then. + */ + log_debug(LD_GENERAL, "Primed a buffer."); + channel_flush_from_first_active_circuit(chan, 1); + } +} + diff --git a/src/tor/circuitmux.h b/src/tor/circuitmux.h new file mode 100644 index 0000000..ee2f5d1 --- /dev/null +++ b/src/tor/circuitmux.h @@ -0,0 +1,147 @@ +/* * Copyright (c) 2012-2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file circuitmux.h + * \brief Header file for circuitmux.c + **/ + +#ifndef TOR_CIRCUITMUX_H +#define TOR_CIRCUITMUX_H + +#include "or.h" +#include "testsupport.h" + +typedef struct circuitmux_policy_s circuitmux_policy_t; +typedef struct circuitmux_policy_data_s circuitmux_policy_data_t; +typedef struct circuitmux_policy_circ_data_s circuitmux_policy_circ_data_t; + +struct circuitmux_policy_s { + /* Allocate cmux-wide policy-specific data */ + circuitmux_policy_data_t * (*alloc_cmux_data)(circuitmux_t *cmux); + /* Free cmux-wide policy-specific data */ + void (*free_cmux_data)(circuitmux_t *cmux, + circuitmux_policy_data_t *pol_data); + /* Allocate circuit policy-specific data for a newly attached circuit */ + circuitmux_policy_circ_data_t * + (*alloc_circ_data)(circuitmux_t *cmux, + circuitmux_policy_data_t *pol_data, + circuit_t *circ, + cell_direction_t direction, + unsigned int cell_count); + /* Free circuit policy-specific data */ + void (*free_circ_data)(circuitmux_t *cmux, + circuitmux_policy_data_t *pol_data, + circuit_t *circ, + circuitmux_policy_circ_data_t *pol_circ_data); + /* Notify that a circuit has become active/inactive */ + void (*notify_circ_active)(circuitmux_t *cmux, + circuitmux_policy_data_t *pol_data, + circuit_t *circ, + circuitmux_policy_circ_data_t *pol_circ_data); + void (*notify_circ_inactive)(circuitmux_t *cmux, + circuitmux_policy_data_t *pol_data, + circuit_t *circ, + circuitmux_policy_circ_data_t *pol_circ_data); + /* Notify of arriving/transmitted cells on a circuit */ + void (*notify_set_n_cells)(circuitmux_t *cmux, + circuitmux_policy_data_t *pol_data, + circuit_t *circ, + circuitmux_policy_circ_data_t *pol_circ_data, + unsigned int n_cells); + void (*notify_xmit_cells)(circuitmux_t *cmux, + circuitmux_policy_data_t *pol_data, + circuit_t *circ, + circuitmux_policy_circ_data_t *pol_circ_data, + unsigned int n_cells); + /* Choose a circuit */ + circuit_t * (*pick_active_circuit)(circuitmux_t *cmux, + circuitmux_policy_data_t *pol_data); +}; + +/* + * Circuitmux policy implementations can subclass this to store circuitmux- + * wide data; it just has the magic number in the base struct. + */ + +struct circuitmux_policy_data_s { + uint32_t magic; +}; + +/* + * Circuitmux policy implementations can subclass this to store circuit- + * specific data; it just has the magic number in the base struct. + */ + +struct circuitmux_policy_circ_data_s { + uint32_t magic; +}; + +/* + * Upcast #defines for the above types + */ + +/** + * Convert a circuitmux_policy_data_t subtype to a circuitmux_policy_data_t. + */ + +#define TO_CMUX_POL_DATA(x) (&((x)->base_)) + +/** + * Convert a circuitmux_policy_circ_data_t subtype to a + * circuitmux_policy_circ_data_t. + */ + +#define TO_CMUX_POL_CIRC_DATA(x) (&((x)->base_)) + +/* Consistency check */ +void circuitmux_assert_okay(circuitmux_t *cmux); + +/* Create/destroy */ +circuitmux_t * circuitmux_alloc(void); +void circuitmux_detach_all_circuits(circuitmux_t *cmux); +void circuitmux_free(circuitmux_t *cmux); + +/* Policy control */ +void circuitmux_clear_policy(circuitmux_t *cmux); +const circuitmux_policy_t * circuitmux_get_policy(circuitmux_t *cmux); +void circuitmux_set_policy(circuitmux_t *cmux, + const circuitmux_policy_t *pol); + +/* Status inquiries */ +cell_direction_t circuitmux_attached_circuit_direction( + circuitmux_t *cmux, + circuit_t *circ); +int circuitmux_is_circuit_attached(circuitmux_t *cmux, circuit_t *circ); +int circuitmux_is_circuit_active(circuitmux_t *cmux, circuit_t *circ); +unsigned int circuitmux_num_cells_for_circuit(circuitmux_t *cmux, + circuit_t *circ); +unsigned int circuitmux_num_cells(circuitmux_t *cmux); +unsigned int circuitmux_num_circuits(circuitmux_t *cmux); +unsigned int circuitmux_num_active_circuits(circuitmux_t *cmux); + +/* Channel interface */ +circuit_t * circuitmux_get_first_active_circuit(circuitmux_t *cmux, + cell_queue_t **destroy_queue_out); +void circuitmux_notify_xmit_cells(circuitmux_t *cmux, circuit_t *circ, + unsigned int n_cells); +void circuitmux_notify_xmit_destroy(circuitmux_t *cmux); + +/* Circuit interface */ +MOCK_DECL(void, circuitmux_attach_circuit, (circuitmux_t *cmux, + circuit_t *circ, + cell_direction_t direction)); +MOCK_DECL(void, circuitmux_detach_circuit, + (circuitmux_t *cmux, circuit_t *circ)); +void circuitmux_clear_num_cells(circuitmux_t *cmux, circuit_t *circ); +void circuitmux_set_num_cells(circuitmux_t *cmux, circuit_t *circ, + unsigned int n_cells); + +void circuitmux_append_destroy_cell(channel_t *chan, + circuitmux_t *cmux, circid_t circ_id, + uint8_t reason); +void circuitmux_mark_destroyed_circids_usable(circuitmux_t *cmux, + channel_t *chan); + +#endif /* TOR_CIRCUITMUX_H */ + diff --git a/src/tor/circuitmux_ewma.c b/src/tor/circuitmux_ewma.c new file mode 100644 index 0000000..3f37d7b --- /dev/null +++ b/src/tor/circuitmux_ewma.c @@ -0,0 +1,684 @@ +/* * Copyright (c) 2012-2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file circuitmux_ewma.c + * \brief EWMA circuit selection as a circuitmux_t policy + **/ + +#define TOR_CIRCUITMUX_EWMA_C_ + +#include + +#include "or.h" +#include "circuitmux.h" +#include "circuitmux_ewma.h" +#include "networkstatus.h" + +/*** EWMA parameter #defines ***/ + +/** How long does a tick last (seconds)? */ +#define EWMA_TICK_LEN 10 + +/** The default per-tick scale factor, if it hasn't been overridden by a + * consensus or a configuration setting. zero means "disabled". */ +#define EWMA_DEFAULT_HALFLIFE 0.0 + +/*** Some useful constant #defines ***/ + +/*DOCDOC*/ +#define EPSILON 0.00001 +/*DOCDOC*/ +#define LOG_ONEHALF -0.69314718055994529 + +/*** EWMA structures ***/ + +typedef struct cell_ewma_s cell_ewma_t; +typedef struct ewma_policy_data_s ewma_policy_data_t; +typedef struct ewma_policy_circ_data_s ewma_policy_circ_data_t; + +/** + * The cell_ewma_t structure keeps track of how many cells a circuit has + * transferred recently. It keeps an EWMA (exponentially weighted moving + * average) of the number of cells flushed from the circuit queue onto a + * connection in channel_flush_from_first_active_circuit(). + */ + +struct cell_ewma_s { + /** The last 'tick' at which we recalibrated cell_count. + * + * A cell sent at exactly the start of this tick has weight 1.0. Cells sent + * since the start of this tick have weight greater than 1.0; ones sent + * earlier have less weight. */ + unsigned int last_adjusted_tick; + /** The EWMA of the cell count. */ + double cell_count; + /** True iff this is the cell count for a circuit's previous + * channel. */ + unsigned int is_for_p_chan : 1; + /** The position of the circuit within the OR connection's priority + * queue. */ + int heap_index; +}; + +struct ewma_policy_data_s { + circuitmux_policy_data_t base_; + + /** + * Priority queue of cell_ewma_t for circuits with queued cells waiting + * for room to free up on the channel that owns this circuitmux. Kept + * in heap order according to EWMA. This was formerly in channel_t, and + * in or_connection_t before that. + */ + smartlist_t *active_circuit_pqueue; + + /** + * The tick on which the cell_ewma_ts in active_circuit_pqueue last had + * their ewma values rescaled. This was formerly in channel_t, and in + * or_connection_t before that. + */ + unsigned int active_circuit_pqueue_last_recalibrated; +}; + +struct ewma_policy_circ_data_s { + circuitmux_policy_circ_data_t base_; + + /** + * The EWMA count for the number of cells flushed from this circuit + * onto this circuitmux. Used to determine which circuit to flush + * from next. This was formerly in circuit_t and or_circuit_t. + */ + cell_ewma_t cell_ewma; + + /** + * Pointer back to the circuit_t this is for; since we're separating + * out circuit selection policy like this, we can't attach cell_ewma_t + * to the circuit_t any more, so we can't use SUBTYPE_P directly to a + * circuit_t like before; instead get it here. + */ + circuit_t *circ; +}; + +#define EWMA_POL_DATA_MAGIC 0x2fd8b16aU +#define EWMA_POL_CIRC_DATA_MAGIC 0x761e7747U + +/*** Downcasts for the above types ***/ + +static ewma_policy_data_t * +TO_EWMA_POL_DATA(circuitmux_policy_data_t *); + +static ewma_policy_circ_data_t * +TO_EWMA_POL_CIRC_DATA(circuitmux_policy_circ_data_t *); + +/** + * Downcast a circuitmux_policy_data_t to an ewma_policy_data_t and assert + * if the cast is impossible. + */ + +static INLINE ewma_policy_data_t * +TO_EWMA_POL_DATA(circuitmux_policy_data_t *pol) +{ + if (!pol) return NULL; + else { + tor_assert(pol->magic == EWMA_POL_DATA_MAGIC); + return DOWNCAST(ewma_policy_data_t, pol); + } +} + +/** + * Downcast a circuitmux_policy_circ_data_t to an ewma_policy_circ_data_t + * and assert if the cast is impossible. + */ + +static INLINE ewma_policy_circ_data_t * +TO_EWMA_POL_CIRC_DATA(circuitmux_policy_circ_data_t *pol) +{ + if (!pol) return NULL; + else { + tor_assert(pol->magic == EWMA_POL_CIRC_DATA_MAGIC); + return DOWNCAST(ewma_policy_circ_data_t, pol); + } +} + +/*** Static declarations for circuitmux_ewma.c ***/ + +static void add_cell_ewma(ewma_policy_data_t *pol, cell_ewma_t *ewma); +static int compare_cell_ewma_counts(const void *p1, const void *p2); +static unsigned cell_ewma_tick_from_timeval(const struct timeval *now, + double *remainder_out); +static circuit_t * cell_ewma_to_circuit(cell_ewma_t *ewma); +static INLINE double get_scale_factor(unsigned from_tick, unsigned to_tick); +static cell_ewma_t * pop_first_cell_ewma(ewma_policy_data_t *pol); +static void remove_cell_ewma(ewma_policy_data_t *pol, cell_ewma_t *ewma); +static void scale_single_cell_ewma(cell_ewma_t *ewma, unsigned cur_tick); +static void scale_active_circuits(ewma_policy_data_t *pol, + unsigned cur_tick); + +/*** Circuitmux policy methods ***/ + +static circuitmux_policy_data_t * ewma_alloc_cmux_data(circuitmux_t *cmux); +static void ewma_free_cmux_data(circuitmux_t *cmux, + circuitmux_policy_data_t *pol_data); +static circuitmux_policy_circ_data_t * +ewma_alloc_circ_data(circuitmux_t *cmux, circuitmux_policy_data_t *pol_data, + circuit_t *circ, cell_direction_t direction, + unsigned int cell_count); +static void +ewma_free_circ_data(circuitmux_t *cmux, + circuitmux_policy_data_t *pol_data, + circuit_t *circ, + circuitmux_policy_circ_data_t *pol_circ_data); +static void +ewma_notify_circ_active(circuitmux_t *cmux, + circuitmux_policy_data_t *pol_data, + circuit_t *circ, + circuitmux_policy_circ_data_t *pol_circ_data); +static void +ewma_notify_circ_inactive(circuitmux_t *cmux, + circuitmux_policy_data_t *pol_data, + circuit_t *circ, + circuitmux_policy_circ_data_t *pol_circ_data); +static void +ewma_notify_xmit_cells(circuitmux_t *cmux, + circuitmux_policy_data_t *pol_data, + circuit_t *circ, + circuitmux_policy_circ_data_t *pol_circ_data, + unsigned int n_cells); +static circuit_t * +ewma_pick_active_circuit(circuitmux_t *cmux, + circuitmux_policy_data_t *pol_data); + +/*** EWMA global variables ***/ + +/** The per-tick scale factor to be used when computing cell-count EWMA + * values. (A cell sent N ticks before the start of the current tick + * has value ewma_scale_factor ** N.) + */ +static double ewma_scale_factor = 0.1; +/* DOCDOC ewma_enabled */ +static int ewma_enabled = 0; + +/*** EWMA circuitmux_policy_t method table ***/ + +circuitmux_policy_t ewma_policy = { + /*.alloc_cmux_data =*/ ewma_alloc_cmux_data, + /*.free_cmux_data =*/ ewma_free_cmux_data, + /*.alloc_circ_data =*/ ewma_alloc_circ_data, + /*.free_circ_data =*/ ewma_free_circ_data, + /*.notify_circ_active =*/ ewma_notify_circ_active, + /*.notify_circ_inactive =*/ ewma_notify_circ_inactive, + /*.notify_set_n_cells =*/ NULL, /* EWMA doesn't need this */ + /*.notify_xmit_cells =*/ ewma_notify_xmit_cells, + /*.pick_active_circuit =*/ ewma_pick_active_circuit +}; + +/*** EWMA method implementations using the below EWMA helper functions ***/ + +/** + * Allocate an ewma_policy_data_t and upcast it to a circuitmux_policy_data_t; + * this is called when setting the policy on a circuitmux_t to ewma_policy. + */ + +static circuitmux_policy_data_t * +ewma_alloc_cmux_data(circuitmux_t *cmux) +{ + ewma_policy_data_t *pol = NULL; + + tor_assert(cmux); + + pol = tor_malloc_zero(sizeof(*pol)); + pol->base_.magic = EWMA_POL_DATA_MAGIC; + pol->active_circuit_pqueue = smartlist_new(); + pol->active_circuit_pqueue_last_recalibrated = cell_ewma_get_tick(); + + return TO_CMUX_POL_DATA(pol); +} + +/** + * Free an ewma_policy_data_t allocated with ewma_alloc_cmux_data() + */ + +static void +ewma_free_cmux_data(circuitmux_t *cmux, + circuitmux_policy_data_t *pol_data) +{ + ewma_policy_data_t *pol = NULL; + + tor_assert(cmux); + if (!pol_data) return; + + pol = TO_EWMA_POL_DATA(pol_data); + + smartlist_free(pol->active_circuit_pqueue); + tor_free(pol); +} + +/** + * Allocate an ewma_policy_circ_data_t and upcast it to a + * circuitmux_policy_data_t; this is called when attaching a circuit to a + * circuitmux_t with ewma_policy. + */ + +static circuitmux_policy_circ_data_t * +ewma_alloc_circ_data(circuitmux_t *cmux, + circuitmux_policy_data_t *pol_data, + circuit_t *circ, + cell_direction_t direction, + unsigned int cell_count) +{ + ewma_policy_circ_data_t *cdata = NULL; + + tor_assert(cmux); + tor_assert(pol_data); + tor_assert(circ); + tor_assert(direction == CELL_DIRECTION_OUT || + direction == CELL_DIRECTION_IN); + /* Shut the compiler up */ + tor_assert(cell_count == cell_count); + + cdata = tor_malloc_zero(sizeof(*cdata)); + cdata->base_.magic = EWMA_POL_CIRC_DATA_MAGIC; + cdata->circ = circ; + + /* + * Initialize the cell_ewma_t structure (formerly in + * init_circuit_base()) + */ + cdata->cell_ewma.last_adjusted_tick = cell_ewma_get_tick(); + cdata->cell_ewma.cell_count = 0.0; + cdata->cell_ewma.heap_index = -1; + if (direction == CELL_DIRECTION_IN) { + cdata->cell_ewma.is_for_p_chan = 1; + } else { + cdata->cell_ewma.is_for_p_chan = 0; + } + + return TO_CMUX_POL_CIRC_DATA(cdata); +} + +/** + * Free an ewma_policy_circ_data_t allocated with ewma_alloc_circ_data() + */ + +static void +ewma_free_circ_data(circuitmux_t *cmux, + circuitmux_policy_data_t *pol_data, + circuit_t *circ, + circuitmux_policy_circ_data_t *pol_circ_data) + +{ + ewma_policy_circ_data_t *cdata = NULL; + + tor_assert(cmux); + tor_assert(circ); + tor_assert(pol_data); + + if (!pol_circ_data) return; + + cdata = TO_EWMA_POL_CIRC_DATA(pol_circ_data); + + tor_free(cdata); +} + +/** + * Handle circuit activation; this inserts the circuit's cell_ewma into + * the active_circuits_pqueue. + */ + +static void +ewma_notify_circ_active(circuitmux_t *cmux, + circuitmux_policy_data_t *pol_data, + circuit_t *circ, + circuitmux_policy_circ_data_t *pol_circ_data) +{ + ewma_policy_data_t *pol = NULL; + ewma_policy_circ_data_t *cdata = NULL; + + tor_assert(cmux); + tor_assert(pol_data); + tor_assert(circ); + tor_assert(pol_circ_data); + + pol = TO_EWMA_POL_DATA(pol_data); + cdata = TO_EWMA_POL_CIRC_DATA(pol_circ_data); + + add_cell_ewma(pol, &(cdata->cell_ewma)); +} + +/** + * Handle circuit deactivation; this removes the circuit's cell_ewma from + * the active_circuits_pqueue. + */ + +static void +ewma_notify_circ_inactive(circuitmux_t *cmux, + circuitmux_policy_data_t *pol_data, + circuit_t *circ, + circuitmux_policy_circ_data_t *pol_circ_data) +{ + ewma_policy_data_t *pol = NULL; + ewma_policy_circ_data_t *cdata = NULL; + + tor_assert(cmux); + tor_assert(pol_data); + tor_assert(circ); + tor_assert(pol_circ_data); + + pol = TO_EWMA_POL_DATA(pol_data); + cdata = TO_EWMA_POL_CIRC_DATA(pol_circ_data); + + remove_cell_ewma(pol, &(cdata->cell_ewma)); +} + +/** + * Update cell_ewma for this circuit after we've sent some cells, and + * remove/reinsert it in the queue. This used to be done (brokenly, + * see bug 6816) in channel_flush_from_first_active_circuit(). + */ + +static void +ewma_notify_xmit_cells(circuitmux_t *cmux, + circuitmux_policy_data_t *pol_data, + circuit_t *circ, + circuitmux_policy_circ_data_t *pol_circ_data, + unsigned int n_cells) +{ + ewma_policy_data_t *pol = NULL; + ewma_policy_circ_data_t *cdata = NULL; + unsigned int tick; + double fractional_tick, ewma_increment; + /* The current (hi-res) time */ + struct timeval now_hires; + cell_ewma_t *cell_ewma, *tmp; + + tor_assert(cmux); + tor_assert(pol_data); + tor_assert(circ); + tor_assert(pol_circ_data); + tor_assert(n_cells > 0); + + pol = TO_EWMA_POL_DATA(pol_data); + cdata = TO_EWMA_POL_CIRC_DATA(pol_circ_data); + + /* Rescale the EWMAs if needed */ + tor_gettimeofday_cached(&now_hires); + tick = cell_ewma_tick_from_timeval(&now_hires, &fractional_tick); + + if (tick != pol->active_circuit_pqueue_last_recalibrated) { + scale_active_circuits(pol, tick); + } + + /* How much do we adjust the cell count in cell_ewma by? */ + ewma_increment = + ((double)(n_cells)) * pow(ewma_scale_factor, -fractional_tick); + + /* Do the adjustment */ + cell_ewma = &(cdata->cell_ewma); + cell_ewma->cell_count += ewma_increment; + + /* + * Since we just sent on this circuit, it should be at the head of + * the queue. Pop the head, assert that it matches, then re-add. + */ + tmp = pop_first_cell_ewma(pol); + tor_assert(tmp == cell_ewma); + add_cell_ewma(pol, cell_ewma); +} + +/** + * Pick the preferred circuit to send from; this will be the one with + * the lowest EWMA value in the priority queue. This used to be done + * in channel_flush_from_first_active_circuit(). + */ + +static circuit_t * +ewma_pick_active_circuit(circuitmux_t *cmux, + circuitmux_policy_data_t *pol_data) +{ + ewma_policy_data_t *pol = NULL; + circuit_t *circ = NULL; + cell_ewma_t *cell_ewma = NULL; + + tor_assert(cmux); + tor_assert(pol_data); + + pol = TO_EWMA_POL_DATA(pol_data); + + if (smartlist_len(pol->active_circuit_pqueue) > 0) { + /* Get the head of the queue */ + cell_ewma = smartlist_get(pol->active_circuit_pqueue, 0); + circ = cell_ewma_to_circuit(cell_ewma); + } + + return circ; +} + +/** Helper for sorting cell_ewma_t values in their priority queue. */ +static int +compare_cell_ewma_counts(const void *p1, const void *p2) +{ + const cell_ewma_t *e1 = p1, *e2 = p2; + + if (e1->cell_count < e2->cell_count) + return -1; + else if (e1->cell_count > e2->cell_count) + return 1; + else + return 0; +} + +/** Given a cell_ewma_t, return a pointer to the circuit containing it. */ +static circuit_t * +cell_ewma_to_circuit(cell_ewma_t *ewma) +{ + ewma_policy_circ_data_t *cdata = NULL; + + tor_assert(ewma); + cdata = SUBTYPE_P(ewma, ewma_policy_circ_data_t, cell_ewma); + tor_assert(cdata); + + return cdata->circ; +} + +/* ==== Functions for scaling cell_ewma_t ==== + + When choosing which cells to relay first, we favor circuits that have been + quiet recently. This gives better latency on connections that aren't + pushing lots of data, and makes the network feel more interactive. + + Conceptually, we take an exponentially weighted mean average of the number + of cells a circuit has sent, and allow active circuits (those with cells to + relay) to send cells in reverse order of their exponentially-weighted mean + average (EWMA) cell count. [That is, a cell sent N seconds ago 'counts' + F^N times as much as a cell sent now, for 0now, compute the cell_ewma tick in which it occurs + * and the fraction of the tick that has elapsed between the start of the tick + * and now. Return the former and store the latter in + * *remainder_out. + * + * These tick values are not meant to be shared between Tor instances, or used + * for other purposes. */ + +static unsigned +cell_ewma_tick_from_timeval(const struct timeval *now, + double *remainder_out) +{ + unsigned res = (unsigned) (now->tv_sec / EWMA_TICK_LEN); + /* rem */ + double rem = (now->tv_sec % EWMA_TICK_LEN) + + ((double)(now->tv_usec)) / 1.0e6; + *remainder_out = rem / EWMA_TICK_LEN; + return res; +} + +/** Tell the caller whether ewma_enabled is set */ +int +cell_ewma_enabled(void) +{ + return ewma_enabled; +} + +/** Compute and return the current cell_ewma tick. */ +unsigned int +cell_ewma_get_tick(void) +{ + return ((unsigned)approx_time() / EWMA_TICK_LEN); +} + +/** Adjust the global cell scale factor based on options */ +void +cell_ewma_set_scale_factor(const or_options_t *options, + const networkstatus_t *consensus) +{ + int32_t halflife_ms; + double halflife; + const char *source; + if (options && options->CircuitPriorityHalflife >= -EPSILON) { + halflife = options->CircuitPriorityHalflife; + source = "CircuitPriorityHalflife in configuration"; + } else if (consensus && (halflife_ms = networkstatus_get_param( + consensus, "CircuitPriorityHalflifeMsec", + -1, -1, INT32_MAX)) >= 0) { + halflife = ((double)halflife_ms)/1000.0; + source = "CircuitPriorityHalflifeMsec in consensus"; + } else { + halflife = EWMA_DEFAULT_HALFLIFE; + source = "Default value"; + } + + if (halflife <= EPSILON) { + /* The cell EWMA algorithm is disabled. */ + ewma_scale_factor = 0.1; + ewma_enabled = 0; + log_info(LD_OR, + "Disabled cell_ewma algorithm because of value in %s", + source); + } else { + /* convert halflife into halflife-per-tick. */ + halflife /= EWMA_TICK_LEN; + /* compute per-tick scale factor. */ + ewma_scale_factor = exp( LOG_ONEHALF / halflife ); + ewma_enabled = 1; + log_info(LD_OR, + "Enabled cell_ewma algorithm because of value in %s; " + "scale factor is %f per %d seconds", + source, ewma_scale_factor, EWMA_TICK_LEN); + } +} + +/** Return the multiplier necessary to convert the value of a cell sent in + * 'from_tick' to one sent in 'to_tick'. */ +static INLINE double +get_scale_factor(unsigned from_tick, unsigned to_tick) +{ + /* This math can wrap around, but that's okay: unsigned overflow is + well-defined */ + int diff = (int)(to_tick - from_tick); + return pow(ewma_scale_factor, diff); +} + +/** Adjust the cell count of ewma so that it is scaled with respect to + * cur_tick */ +static void +scale_single_cell_ewma(cell_ewma_t *ewma, unsigned cur_tick) +{ + double factor = get_scale_factor(ewma->last_adjusted_tick, cur_tick); + ewma->cell_count *= factor; + ewma->last_adjusted_tick = cur_tick; +} + +/** Adjust the cell count of every active circuit on chan so + * that they are scaled with respect to cur_tick */ +static void +scale_active_circuits(ewma_policy_data_t *pol, unsigned cur_tick) +{ + double factor; + + tor_assert(pol); + tor_assert(pol->active_circuit_pqueue); + + factor = + get_scale_factor( + pol->active_circuit_pqueue_last_recalibrated, + cur_tick); + /** Ordinarily it isn't okay to change the value of an element in a heap, + * but it's okay here, since we are preserving the order. */ + SMARTLIST_FOREACH_BEGIN( + pol->active_circuit_pqueue, + cell_ewma_t *, e) { + tor_assert(e->last_adjusted_tick == + pol->active_circuit_pqueue_last_recalibrated); + e->cell_count *= factor; + e->last_adjusted_tick = cur_tick; + } SMARTLIST_FOREACH_END(e); + pol->active_circuit_pqueue_last_recalibrated = cur_tick; +} + +/** Rescale ewma to the same scale as pol, and add it to + * pol's priority queue of active circuits */ +static void +add_cell_ewma(ewma_policy_data_t *pol, cell_ewma_t *ewma) +{ + tor_assert(pol); + tor_assert(pol->active_circuit_pqueue); + tor_assert(ewma); + tor_assert(ewma->heap_index == -1); + + scale_single_cell_ewma( + ewma, + pol->active_circuit_pqueue_last_recalibrated); + + smartlist_pqueue_add(pol->active_circuit_pqueue, + compare_cell_ewma_counts, + STRUCT_OFFSET(cell_ewma_t, heap_index), + ewma); +} + +/** Remove ewma from pol's priority queue of active circuits */ +static void +remove_cell_ewma(ewma_policy_data_t *pol, cell_ewma_t *ewma) +{ + tor_assert(pol); + tor_assert(pol->active_circuit_pqueue); + tor_assert(ewma); + tor_assert(ewma->heap_index != -1); + + smartlist_pqueue_remove(pol->active_circuit_pqueue, + compare_cell_ewma_counts, + STRUCT_OFFSET(cell_ewma_t, heap_index), + ewma); +} + +/** Remove and return the first cell_ewma_t from pol's priority queue of + * active circuits. Requires that the priority queue is nonempty. */ +static cell_ewma_t * +pop_first_cell_ewma(ewma_policy_data_t *pol) +{ + tor_assert(pol); + tor_assert(pol->active_circuit_pqueue); + + return smartlist_pqueue_pop(pol->active_circuit_pqueue, + compare_cell_ewma_counts, + STRUCT_OFFSET(cell_ewma_t, heap_index)); +} + diff --git a/src/tor/circuitmux_ewma.h b/src/tor/circuitmux_ewma.h new file mode 100644 index 0000000..a512745 --- /dev/null +++ b/src/tor/circuitmux_ewma.h @@ -0,0 +1,29 @@ +/* * Copyright (c) 2012-2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file circuitmux_ewma.h + * \brief Header file for circuitmux_ewma.c + **/ + +#ifndef TOR_CIRCUITMUX_EWMA_H +#define TOR_CIRCUITMUX_EWMA_H + +#include "or.h" +#include "circuitmux.h" + +/* Everything but circuitmux_ewma.c should see this extern */ +#ifndef TOR_CIRCUITMUX_EWMA_C_ + +extern circuitmux_policy_t ewma_policy; + +#endif /* !(TOR_CIRCUITMUX_EWMA_C_) */ + +/* Externally visible EWMA functions */ +int cell_ewma_enabled(void); +unsigned int cell_ewma_get_tick(void); +void cell_ewma_set_scale_factor(const or_options_t *options, + const networkstatus_t *consensus); + +#endif /* TOR_CIRCUITMUX_EWMA_H */ + diff --git a/src/tor/circuitstats.c b/src/tor/circuitstats.c new file mode 100644 index 0000000..eaefc9e --- /dev/null +++ b/src/tor/circuitstats.c @@ -0,0 +1,1644 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#define CIRCUITSTATS_PRIVATE + +#include "or.h" +#include "circuitbuild.h" +#include "circuitstats.h" +#include "config.h" +#include "confparse.h" +#include "control.h" +#include "networkstatus.h" +#include "statefile.h" + +#undef log +#include + +static void cbt_control_event_buildtimeout_set( + const circuit_build_times_t *cbt, + buildtimeout_set_event_t type); + +#define CBT_BIN_TO_MS(bin) ((bin)*CBT_BIN_WIDTH + (CBT_BIN_WIDTH/2)) + +/** Global list of circuit build times */ +// XXXX: Add this as a member for entry_guard_t instead of global? +// Then we could do per-guard statistics, as guards are likely to +// vary in their own latency. The downside of this is that guards +// can change frequently, so we'd be building a lot more circuits +// most likely. +static circuit_build_times_t circ_times; + +#ifdef TOR_UNIT_TESTS +/** If set, we're running the unit tests: we should avoid clobbering + * our state file or accessing get_options() or get_or_state() */ +static int unit_tests = 0; +#else +#define unit_tests 0 +#endif + +/** Return a pointer to the data structure describing our current circuit + * build time history and computations. */ +const circuit_build_times_t * +get_circuit_build_times(void) +{ + return &circ_times; +} + +/** As get_circuit_build_times, but return a mutable pointer. */ +circuit_build_times_t * +get_circuit_build_times_mutable(void) +{ + return &circ_times; +} + +/** Return the time to wait before actually closing an under-construction, in + * milliseconds. */ +double +get_circuit_build_close_time_ms(void) +{ + return circ_times.close_ms; +} + +/** Return the time to wait before giving up on an under-construction circuit, + * in milliseconds. */ +double +get_circuit_build_timeout_ms(void) +{ + return circ_times.timeout_ms; +} + +/** + * This function decides if CBT learning should be disabled. It returns + * true if one or more of the following four conditions are met: + * + * 1. If the cbtdisabled consensus parameter is set. + * 2. If the torrc option LearnCircuitBuildTimeout is false. + * 3. If we are a directory authority + * 4. If we fail to write circuit build time history to our state file. + */ +int +circuit_build_times_disabled(void) +{ + if (unit_tests) { + return 0; + } else { + int consensus_disabled = networkstatus_get_param(NULL, "cbtdisabled", + 0, 0, 1); + int config_disabled = !get_options()->LearnCircuitBuildTimeout; + int dirauth_disabled = get_options()->AuthoritativeDir; + int state_disabled = did_last_state_file_write_fail() ? 1 : 0; + + if (consensus_disabled || config_disabled || dirauth_disabled || + state_disabled) { + log_debug(LD_CIRC, + "CircuitBuildTime learning is disabled. " + "Consensus=%d, Config=%d, AuthDir=%d, StateFile=%d", + consensus_disabled, config_disabled, dirauth_disabled, + state_disabled); + return 1; + } else { + log_debug(LD_CIRC, + "CircuitBuildTime learning is not disabled. " + "Consensus=%d, Config=%d, AuthDir=%d, StateFile=%d", + consensus_disabled, config_disabled, dirauth_disabled, + state_disabled); + return 0; + } + } +} + +/** + * Retrieve and bounds-check the cbtmaxtimeouts consensus paramter. + * + * Effect: When this many timeouts happen in the last 'cbtrecentcount' + * circuit attempts, the client should discard all of its history and + * begin learning a fresh timeout value. + */ +static int32_t +circuit_build_times_max_timeouts(void) +{ + int32_t cbt_maxtimeouts; + + cbt_maxtimeouts = networkstatus_get_param(NULL, "cbtmaxtimeouts", + CBT_DEFAULT_MAX_RECENT_TIMEOUT_COUNT, + CBT_MIN_MAX_RECENT_TIMEOUT_COUNT, + CBT_MAX_MAX_RECENT_TIMEOUT_COUNT); + + if (!(get_options()->LearnCircuitBuildTimeout)) { + log_debug(LD_BUG, + "circuit_build_times_max_timeouts() called, cbtmaxtimeouts is" + " %d", + cbt_maxtimeouts); + } + + return cbt_maxtimeouts; +} + +/** + * Retrieve and bounds-check the cbtnummodes consensus paramter. + * + * Effect: This value governs how many modes to use in the weighted + * average calculation of Pareto parameter Xm. A value of 3 introduces + * some bias (2-5% of CDF) under ideal conditions, but allows for better + * performance in the event that a client chooses guard nodes of radically + * different performance characteristics. + */ +static int32_t +circuit_build_times_default_num_xm_modes(void) +{ + int32_t num = networkstatus_get_param(NULL, "cbtnummodes", + CBT_DEFAULT_NUM_XM_MODES, + CBT_MIN_NUM_XM_MODES, + CBT_MAX_NUM_XM_MODES); + + if (!(get_options()->LearnCircuitBuildTimeout)) { + log_debug(LD_BUG, + "circuit_build_times_default_num_xm_modes() called, cbtnummodes" + " is %d", + num); + } + + return num; +} + +/** + * Retrieve and bounds-check the cbtmincircs consensus paramter. + * + * Effect: This is the minimum number of circuits to build before + * computing a timeout. + */ +static int32_t +circuit_build_times_min_circs_to_observe(void) +{ + int32_t num = networkstatus_get_param(NULL, "cbtmincircs", + CBT_DEFAULT_MIN_CIRCUITS_TO_OBSERVE, + CBT_MIN_MIN_CIRCUITS_TO_OBSERVE, + CBT_MAX_MIN_CIRCUITS_TO_OBSERVE); + + if (!(get_options()->LearnCircuitBuildTimeout)) { + log_debug(LD_BUG, + "circuit_build_times_min_circs_to_observe() called, cbtmincircs" + " is %d", + num); + } + + return num; +} + +/** Return true iff cbt has recorded enough build times that we + * want to start acting on the timeout it implies. */ +int +circuit_build_times_enough_to_compute(const circuit_build_times_t *cbt) +{ + return cbt->total_build_times >= circuit_build_times_min_circs_to_observe(); +} + +/** + * Retrieve and bounds-check the cbtquantile consensus paramter. + * + * Effect: This is the position on the quantile curve to use to set the + * timeout value. It is a percent (10-99). + */ +double +circuit_build_times_quantile_cutoff(void) +{ + int32_t num = networkstatus_get_param(NULL, "cbtquantile", + CBT_DEFAULT_QUANTILE_CUTOFF, + CBT_MIN_QUANTILE_CUTOFF, + CBT_MAX_QUANTILE_CUTOFF); + + if (!(get_options()->LearnCircuitBuildTimeout)) { + log_debug(LD_BUG, + "circuit_build_times_quantile_cutoff() called, cbtquantile" + " is %d", + num); + } + + return num/100.0; +} + +/** + * Retrieve and bounds-check the cbtclosequantile consensus paramter. + * + * Effect: This is the position on the quantile curve to use to set the + * timeout value to use to actually close circuits. It is a percent + * (0-99). + */ +static double +circuit_build_times_close_quantile(void) +{ + int32_t param; + /* Cast is safe - circuit_build_times_quantile_cutoff() is capped */ + int32_t min = (int)tor_lround(100*circuit_build_times_quantile_cutoff()); + param = networkstatus_get_param(NULL, "cbtclosequantile", + CBT_DEFAULT_CLOSE_QUANTILE, + CBT_MIN_CLOSE_QUANTILE, + CBT_MAX_CLOSE_QUANTILE); + + if (!(get_options()->LearnCircuitBuildTimeout)) { + log_debug(LD_BUG, + "circuit_build_times_close_quantile() called, cbtclosequantile" + " is %d", param); + } + + if (param < min) { + log_warn(LD_DIR, "Consensus parameter cbtclosequantile is " + "too small, raising to %d", min); + param = min; + } + return param / 100.0; +} + +/** + * Retrieve and bounds-check the cbttestfreq consensus paramter. + * + * Effect: Describes how often in seconds to build a test circuit to + * gather timeout values. Only applies if less than 'cbtmincircs' + * have been recorded. + */ +static int32_t +circuit_build_times_test_frequency(void) +{ + int32_t num = networkstatus_get_param(NULL, "cbttestfreq", + CBT_DEFAULT_TEST_FREQUENCY, + CBT_MIN_TEST_FREQUENCY, + CBT_MAX_TEST_FREQUENCY); + + if (!(get_options()->LearnCircuitBuildTimeout)) { + log_debug(LD_BUG, + "circuit_build_times_test_frequency() called, cbttestfreq is %d", + num); + } + + return num; +} + +/** + * Retrieve and bounds-check the cbtmintimeout consensus parameter. + * + * Effect: This is the minimum allowed timeout value in milliseconds. + * The minimum is to prevent rounding to 0 (we only check once + * per second). + */ +static int32_t +circuit_build_times_min_timeout(void) +{ + int32_t num = networkstatus_get_param(NULL, "cbtmintimeout", + CBT_DEFAULT_TIMEOUT_MIN_VALUE, + CBT_MIN_TIMEOUT_MIN_VALUE, + CBT_MAX_TIMEOUT_MIN_VALUE); + + if (!(get_options()->LearnCircuitBuildTimeout)) { + log_debug(LD_BUG, + "circuit_build_times_min_timeout() called, cbtmintimeout is %d", + num); + } + + return num; +} + +/** + * Retrieve and bounds-check the cbtinitialtimeout consensus paramter. + * + * Effect: This is the timeout value to use before computing a timeout, + * in milliseconds. + */ +int32_t +circuit_build_times_initial_timeout(void) +{ + int32_t min = circuit_build_times_min_timeout(); + int32_t param = networkstatus_get_param(NULL, "cbtinitialtimeout", + CBT_DEFAULT_TIMEOUT_INITIAL_VALUE, + CBT_MIN_TIMEOUT_INITIAL_VALUE, + CBT_MAX_TIMEOUT_INITIAL_VALUE); + + if (!(get_options()->LearnCircuitBuildTimeout)) { + log_debug(LD_BUG, + "circuit_build_times_initial_timeout() called, " + "cbtinitialtimeout is %d", + param); + } + + if (param < min) { + log_warn(LD_DIR, "Consensus parameter cbtinitialtimeout is too small, " + "raising to %d", min); + param = min; + } + return param; +} + +/** + * Retrieve and bounds-check the cbtrecentcount consensus paramter. + * + * Effect: This is the number of circuit build times to keep track of + * for deciding if we hit cbtmaxtimeouts and need to reset our state + * and learn a new timeout. + */ +static int32_t +circuit_build_times_recent_circuit_count(networkstatus_t *ns) +{ + int32_t num; + num = networkstatus_get_param(ns, "cbtrecentcount", + CBT_DEFAULT_RECENT_CIRCUITS, + CBT_MIN_RECENT_CIRCUITS, + CBT_MAX_RECENT_CIRCUITS); + + if (!(get_options()->LearnCircuitBuildTimeout)) { + log_debug(LD_BUG, + "circuit_build_times_recent_circuit_count() called, " + "cbtrecentcount is %d", + num); + } + + return num; +} + +/** + * This function is called when we get a consensus update. + * + * It checks to see if we have changed any consensus parameters + * that require reallocation or discard of previous stats. + */ +void +circuit_build_times_new_consensus_params(circuit_build_times_t *cbt, + networkstatus_t *ns) +{ + int32_t num; + + /* + * First check if we're doing adaptive timeouts at all; nothing to + * update if we aren't. + */ + + if (!circuit_build_times_disabled()) { + num = circuit_build_times_recent_circuit_count(ns); + + if (num > 0) { + if (num != cbt->liveness.num_recent_circs) { + int8_t *recent_circs; + log_notice(LD_CIRC, "The Tor Directory Consensus has changed how many " + "circuits we must track to detect network failures from %d " + "to %d.", cbt->liveness.num_recent_circs, num); + + tor_assert(cbt->liveness.timeouts_after_firsthop || + cbt->liveness.num_recent_circs == 0); + + /* + * Technically this is a circular array that we are reallocating + * and memcopying. However, since it only consists of either 1s + * or 0s, and is only used in a statistical test to determine when + * we should discard our history after a sufficient number of 1's + * have been reached, it is fine if order is not preserved or + * elements are lost. + * + * cbtrecentcount should only be changing in cases of severe network + * distress anyway, so memory correctness here is paramount over + * doing acrobatics to preserve the array. + */ + recent_circs = tor_malloc_zero(sizeof(int8_t)*num); + if (cbt->liveness.timeouts_after_firsthop && + cbt->liveness.num_recent_circs > 0) { + memcpy(recent_circs, cbt->liveness.timeouts_after_firsthop, + sizeof(int8_t)*MIN(num, cbt->liveness.num_recent_circs)); + } + + // Adjust the index if it needs it. + if (num < cbt->liveness.num_recent_circs) { + cbt->liveness.after_firsthop_idx = MIN(num-1, + cbt->liveness.after_firsthop_idx); + } + + tor_free(cbt->liveness.timeouts_after_firsthop); + cbt->liveness.timeouts_after_firsthop = recent_circs; + cbt->liveness.num_recent_circs = num; + } + /* else no change, nothing to do */ + } else { /* num == 0 */ + /* + * Weird. This probably shouldn't happen, so log a warning, but try + * to do something sensible anyway. + */ + + log_warn(LD_CIRC, + "The cbtrecentcircs consensus parameter came back zero! " + "This disables adaptive timeouts since we can't keep track of " + "any recent circuits."); + + circuit_build_times_free_timeouts(cbt); + } + } else { + /* + * Adaptive timeouts are disabled; this might be because of the + * LearnCircuitBuildTimes config parameter, and hence permanent, or + * the cbtdisabled consensus parameter, so it may be a new condition. + * Treat it like getting num == 0 above and free the circuit history + * if we have any. + */ + + circuit_build_times_free_timeouts(cbt); + } +} + +/** + * Return the initial default or configured timeout in milliseconds + */ +static double +circuit_build_times_get_initial_timeout(void) +{ + double timeout; + + /* + * Check if we have LearnCircuitBuildTimeout, and if we don't, + * always use CircuitBuildTimeout, no questions asked. + */ + if (!unit_tests && get_options()->CircuitBuildTimeout) { + timeout = get_options()->CircuitBuildTimeout*1000; + if (get_options()->LearnCircuitBuildTimeout && + timeout < circuit_build_times_min_timeout()) { + log_warn(LD_CIRC, "Config CircuitBuildTimeout too low. Setting to %ds", + circuit_build_times_min_timeout()/1000); + timeout = circuit_build_times_min_timeout(); + } + } else { + timeout = circuit_build_times_initial_timeout(); + } + + return timeout; +} + +/** + * Reset the build time state. + * + * Leave estimated parameters, timeout and network liveness intact + * for future use. + */ +STATIC void +circuit_build_times_reset(circuit_build_times_t *cbt) +{ + memset(cbt->circuit_build_times, 0, sizeof(cbt->circuit_build_times)); + cbt->total_build_times = 0; + cbt->build_times_idx = 0; + cbt->have_computed_timeout = 0; +} + +/** + * Initialize the buildtimes structure for first use. + * + * Sets the initial timeout values based on either the config setting, + * the consensus param, or the default (CBT_DEFAULT_TIMEOUT_INITIAL_VALUE). + */ +void +circuit_build_times_init(circuit_build_times_t *cbt) +{ + memset(cbt, 0, sizeof(*cbt)); + /* + * Check if we really are using adaptive timeouts, and don't keep + * track of this stuff if not. + */ + if (!circuit_build_times_disabled()) { + cbt->liveness.num_recent_circs = + circuit_build_times_recent_circuit_count(NULL); + cbt->liveness.timeouts_after_firsthop = + tor_malloc_zero(sizeof(int8_t)*cbt->liveness.num_recent_circs); + } else { + cbt->liveness.num_recent_circs = 0; + cbt->liveness.timeouts_after_firsthop = NULL; + } + cbt->close_ms = cbt->timeout_ms = circuit_build_times_get_initial_timeout(); + cbt_control_event_buildtimeout_set(cbt, BUILDTIMEOUT_SET_EVENT_RESET); +} + +/** + * Free the saved timeouts, if the cbtdisabled consensus parameter got turned + * on or something. + */ + +void +circuit_build_times_free_timeouts(circuit_build_times_t *cbt) +{ + if (!cbt) return; + + if (cbt->liveness.timeouts_after_firsthop) { + tor_free(cbt->liveness.timeouts_after_firsthop); + } + + cbt->liveness.num_recent_circs = 0; +} + +#if 0 +/** + * Rewind our build time history by n positions. + */ +static void +circuit_build_times_rewind_history(circuit_build_times_t *cbt, int n) +{ + int i = 0; + + cbt->build_times_idx -= n; + cbt->build_times_idx %= CBT_NCIRCUITS_TO_OBSERVE; + + for (i = 0; i < n; i++) { + cbt->circuit_build_times[(i+cbt->build_times_idx) + %CBT_NCIRCUITS_TO_OBSERVE]=0; + } + + if (cbt->total_build_times > n) { + cbt->total_build_times -= n; + } else { + cbt->total_build_times = 0; + } + + log_info(LD_CIRC, + "Rewound history by %d places. Current index: %d. " + "Total: %d", n, cbt->build_times_idx, cbt->total_build_times); +} +#endif + +/** + * Add a new build time value time to the set of build times. Time + * units are milliseconds. + * + * circuit_build_times cbt is a circular array, so loop around when + * array is full. + */ +int +circuit_build_times_add_time(circuit_build_times_t *cbt, build_time_t time) +{ + if (time <= 0 || time > CBT_BUILD_TIME_MAX) { + log_warn(LD_BUG, "Circuit build time is too large (%u)." + "This is probably a bug.", time); + tor_fragile_assert(); + return -1; + } + + log_debug(LD_CIRC, "Adding circuit build time %u", time); + + cbt->circuit_build_times[cbt->build_times_idx] = time; + cbt->build_times_idx = (cbt->build_times_idx + 1) % CBT_NCIRCUITS_TO_OBSERVE; + if (cbt->total_build_times < CBT_NCIRCUITS_TO_OBSERVE) + cbt->total_build_times++; + + if ((cbt->total_build_times % CBT_SAVE_STATE_EVERY) == 0) { + /* Save state every n circuit builds */ + if (!unit_tests && !get_options()->AvoidDiskWrites) + or_state_mark_dirty(get_or_state(), 0); + } + + return 0; +} + +/** + * Return maximum circuit build time + */ +static build_time_t +circuit_build_times_max(const circuit_build_times_t *cbt) +{ + int i = 0; + build_time_t max_build_time = 0; + for (i = 0; i < CBT_NCIRCUITS_TO_OBSERVE; i++) { + if (cbt->circuit_build_times[i] > max_build_time + && cbt->circuit_build_times[i] != CBT_BUILD_ABANDONED) + max_build_time = cbt->circuit_build_times[i]; + } + return max_build_time; +} + +#if 0 +/** Return minimum circuit build time */ +build_time_t +circuit_build_times_min(circuit_build_times_t *cbt) +{ + int i = 0; + build_time_t min_build_time = CBT_BUILD_TIME_MAX; + for (i = 0; i < CBT_NCIRCUITS_TO_OBSERVE; i++) { + if (cbt->circuit_build_times[i] && /* 0 <-> uninitialized */ + cbt->circuit_build_times[i] < min_build_time) + min_build_time = cbt->circuit_build_times[i]; + } + if (min_build_time == CBT_BUILD_TIME_MAX) { + log_warn(LD_CIRC, "No build times less than CBT_BUILD_TIME_MAX!"); + } + return min_build_time; +} +#endif + +/** + * Calculate and return a histogram for the set of build times. + * + * Returns an allocated array of histrogram bins representing + * the frequency of index*CBT_BIN_WIDTH millisecond + * build times. Also outputs the number of bins in nbins. + * + * The return value must be freed by the caller. + */ +static uint32_t * +circuit_build_times_create_histogram(const circuit_build_times_t *cbt, + build_time_t *nbins) +{ + uint32_t *histogram; + build_time_t max_build_time = circuit_build_times_max(cbt); + int i, c; + + *nbins = 1 + (max_build_time / CBT_BIN_WIDTH); + histogram = tor_malloc_zero(*nbins * sizeof(build_time_t)); + + // calculate histogram + for (i = 0; i < CBT_NCIRCUITS_TO_OBSERVE; i++) { + if (cbt->circuit_build_times[i] == 0 + || cbt->circuit_build_times[i] == CBT_BUILD_ABANDONED) + continue; /* 0 <-> uninitialized */ + + c = (cbt->circuit_build_times[i] / CBT_BIN_WIDTH); + histogram[c]++; + } + + return histogram; +} + +/** + * Return the Pareto start-of-curve parameter Xm. + * + * Because we are not a true Pareto curve, we compute this as the + * weighted average of the N most frequent build time bins. N is either + * 1 if we don't have enough circuit build time data collected, or + * determined by the consensus parameter cbtnummodes (default 3). + */ +static build_time_t +circuit_build_times_get_xm(circuit_build_times_t *cbt) +{ + build_time_t i, nbins; + build_time_t *nth_max_bin; + int32_t bin_counts=0; + build_time_t ret = 0; + uint32_t *histogram = circuit_build_times_create_histogram(cbt, &nbins); + int n=0; + int num_modes = circuit_build_times_default_num_xm_modes(); + + tor_assert(nbins > 0); + tor_assert(num_modes > 0); + + // Only use one mode if < 1000 buildtimes. Not enough data + // for multiple. + if (cbt->total_build_times < CBT_NCIRCUITS_TO_OBSERVE) + num_modes = 1; + + nth_max_bin = (build_time_t*)tor_malloc_zero(num_modes*sizeof(build_time_t)); + + /* Determine the N most common build times */ + for (i = 0; i < nbins; i++) { + if (histogram[i] >= histogram[nth_max_bin[0]]) { + nth_max_bin[0] = i; + } + + for (n = 1; n < num_modes; n++) { + if (histogram[i] >= histogram[nth_max_bin[n]] && + (!histogram[nth_max_bin[n-1]] + || histogram[i] < histogram[nth_max_bin[n-1]])) { + nth_max_bin[n] = i; + } + } + } + + for (n = 0; n < num_modes; n++) { + bin_counts += histogram[nth_max_bin[n]]; + ret += CBT_BIN_TO_MS(nth_max_bin[n])*histogram[nth_max_bin[n]]; + log_info(LD_CIRC, "Xm mode #%d: %u %u", n, CBT_BIN_TO_MS(nth_max_bin[n]), + histogram[nth_max_bin[n]]); + } + + /* The following assert is safe, because we don't get called when we + * haven't observed at least CBT_MIN_MIN_CIRCUITS_TO_OBSERVE circuits. */ + tor_assert(bin_counts > 0); + + ret /= bin_counts; + tor_free(histogram); + tor_free(nth_max_bin); + + return ret; +} + +/** + * Output a histogram of current circuit build times to + * the or_state_t state structure. + */ +void +circuit_build_times_update_state(const circuit_build_times_t *cbt, + or_state_t *state) +{ + uint32_t *histogram; + build_time_t i = 0; + build_time_t nbins = 0; + config_line_t **next, *line; + + histogram = circuit_build_times_create_histogram(cbt, &nbins); + // write to state + config_free_lines(state->BuildtimeHistogram); + next = &state->BuildtimeHistogram; + *next = NULL; + + state->TotalBuildTimes = cbt->total_build_times; + state->CircuitBuildAbandonedCount = 0; + + for (i = 0; i < CBT_NCIRCUITS_TO_OBSERVE; i++) { + if (cbt->circuit_build_times[i] == CBT_BUILD_ABANDONED) + state->CircuitBuildAbandonedCount++; + } + + for (i = 0; i < nbins; i++) { + // compress the histogram by skipping the blanks + if (histogram[i] == 0) continue; + *next = line = tor_malloc_zero(sizeof(config_line_t)); + line->key = tor_strdup("CircuitBuildTimeBin"); + tor_asprintf(&line->value, "%d %d", + CBT_BIN_TO_MS(i), histogram[i]); + next = &(line->next); + } + + if (!unit_tests) { + if (!get_options()->AvoidDiskWrites) + or_state_mark_dirty(get_or_state(), 0); + } + + tor_free(histogram); +} + +/** + * Shuffle the build times array. + * + * Adapted from http://en.wikipedia.org/wiki/Fisher-Yates_shuffle + */ +static void +circuit_build_times_shuffle_and_store_array(circuit_build_times_t *cbt, + build_time_t *raw_times, + uint32_t num_times) +{ + uint32_t n = num_times; + if (num_times > CBT_NCIRCUITS_TO_OBSERVE) { + log_notice(LD_CIRC, "The number of circuit times that this Tor version " + "uses to calculate build times is less than the number stored " + "in your state file. Decreasing the circuit time history from " + "%lu to %d.", (unsigned long)num_times, + CBT_NCIRCUITS_TO_OBSERVE); + } + + if (n > INT_MAX-1) { + log_warn(LD_CIRC, "For some insane reasons, you had %lu circuit build " + "observations in your state file. That's far too many; probably " + "there's a bug here.", (unsigned long)n); + n = INT_MAX-1; + } + + /* This code can only be run on a compact array */ + while (n-- > 1) { + int k = crypto_rand_int(n + 1); /* 0 <= k <= n. */ + build_time_t tmp = raw_times[k]; + raw_times[k] = raw_times[n]; + raw_times[n] = tmp; + } + + /* Since the times are now shuffled, take a random CBT_NCIRCUITS_TO_OBSERVE + * subset (ie the first CBT_NCIRCUITS_TO_OBSERVE values) */ + for (n = 0; n < MIN(num_times, CBT_NCIRCUITS_TO_OBSERVE); n++) { + circuit_build_times_add_time(cbt, raw_times[n]); + } +} + +/** + * Filter old synthetic timeouts that were created before the + * new right-censored Pareto calculation was deployed. + * + * Once all clients before 0.2.1.13-alpha are gone, this code + * will be unused. + */ +static int +circuit_build_times_filter_timeouts(circuit_build_times_t *cbt) +{ + int num_filtered=0, i=0; + double timeout_rate = 0; + build_time_t max_timeout = 0; + + timeout_rate = circuit_build_times_timeout_rate(cbt); + max_timeout = (build_time_t)cbt->close_ms; + + for (i = 0; i < CBT_NCIRCUITS_TO_OBSERVE; i++) { + if (cbt->circuit_build_times[i] > max_timeout) { + build_time_t replaced = cbt->circuit_build_times[i]; + num_filtered++; + cbt->circuit_build_times[i] = CBT_BUILD_ABANDONED; + + log_debug(LD_CIRC, "Replaced timeout %d with %d", replaced, + cbt->circuit_build_times[i]); + } + } + + log_info(LD_CIRC, + "We had %d timeouts out of %d build times, " + "and filtered %d above the max of %u", + (int)(cbt->total_build_times*timeout_rate), + cbt->total_build_times, num_filtered, max_timeout); + + return num_filtered; +} + +/** + * Load histogram from state, shuffling the resulting array + * after we do so. Use this result to estimate parameters and + * calculate the timeout. + * + * Return -1 on error. + */ +int +circuit_build_times_parse_state(circuit_build_times_t *cbt, + or_state_t *state) +{ + int tot_values = 0; + uint32_t loaded_cnt = 0, N = 0; + config_line_t *line; + unsigned int i; + build_time_t *loaded_times; + int err = 0; + circuit_build_times_init(cbt); + + if (circuit_build_times_disabled()) { + return 0; + } + + /* build_time_t 0 means uninitialized */ + loaded_times = tor_malloc_zero(sizeof(build_time_t)*state->TotalBuildTimes); + + for (line = state->BuildtimeHistogram; line; line = line->next) { + smartlist_t *args = smartlist_new(); + smartlist_split_string(args, line->value, " ", + SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); + if (smartlist_len(args) < 2) { + log_warn(LD_GENERAL, "Unable to parse circuit build times: " + "Too few arguments to CircuitBuildTime"); + err = 1; + SMARTLIST_FOREACH(args, char*, cp, tor_free(cp)); + smartlist_free(args); + break; + } else { + const char *ms_str = smartlist_get(args,0); + const char *count_str = smartlist_get(args,1); + uint32_t count, k; + build_time_t ms; + int ok; + ms = (build_time_t)tor_parse_ulong(ms_str, 0, 0, + CBT_BUILD_TIME_MAX, &ok, NULL); + if (!ok) { + log_warn(LD_GENERAL, "Unable to parse circuit build times: " + "Unparsable bin number"); + err = 1; + SMARTLIST_FOREACH(args, char*, cp, tor_free(cp)); + smartlist_free(args); + break; + } + count = (uint32_t)tor_parse_ulong(count_str, 0, 0, + UINT32_MAX, &ok, NULL); + if (!ok) { + log_warn(LD_GENERAL, "Unable to parse circuit build times: " + "Unparsable bin count"); + err = 1; + SMARTLIST_FOREACH(args, char*, cp, tor_free(cp)); + smartlist_free(args); + break; + } + + if (loaded_cnt+count+state->CircuitBuildAbandonedCount + > state->TotalBuildTimes) { + log_warn(LD_CIRC, + "Too many build times in state file. " + "Stopping short before %d", + loaded_cnt+count); + SMARTLIST_FOREACH(args, char*, cp, tor_free(cp)); + smartlist_free(args); + break; + } + + for (k = 0; k < count; k++) { + loaded_times[loaded_cnt++] = ms; + } + N++; + SMARTLIST_FOREACH(args, char*, cp, tor_free(cp)); + smartlist_free(args); + } + } + + log_info(LD_CIRC, + "Adding %d timeouts.", state->CircuitBuildAbandonedCount); + for (i=0; i < state->CircuitBuildAbandonedCount; i++) { + loaded_times[loaded_cnt++] = CBT_BUILD_ABANDONED; + } + + if (loaded_cnt != state->TotalBuildTimes) { + log_warn(LD_CIRC, + "Corrupt state file? Build times count mismatch. " + "Read %d times, but file says %d", loaded_cnt, + state->TotalBuildTimes); + err = 1; + circuit_build_times_reset(cbt); + goto done; + } + + circuit_build_times_shuffle_and_store_array(cbt, loaded_times, loaded_cnt); + + /* Verify that we didn't overwrite any indexes */ + for (i=0; i < CBT_NCIRCUITS_TO_OBSERVE; i++) { + if (!cbt->circuit_build_times[i]) + break; + tot_values++; + } + log_info(LD_CIRC, + "Loaded %d/%d values from %d lines in circuit time histogram", + tot_values, cbt->total_build_times, N); + + if (cbt->total_build_times != tot_values + || cbt->total_build_times > CBT_NCIRCUITS_TO_OBSERVE) { + log_warn(LD_CIRC, + "Corrupt state file? Shuffled build times mismatch. " + "Read %d times, but file says %d", tot_values, + state->TotalBuildTimes); + err = 1; + circuit_build_times_reset(cbt); + goto done; + } + + circuit_build_times_set_timeout(cbt); + + if (!state->CircuitBuildAbandonedCount && cbt->total_build_times) { + circuit_build_times_filter_timeouts(cbt); + } + + done: + tor_free(loaded_times); + return err ? -1 : 0; +} + +/** + * Estimates the Xm and Alpha parameters using + * http://en.wikipedia.org/wiki/Pareto_distribution#Parameter_estimation + * + * The notable difference is that we use mode instead of min to estimate Xm. + * This is because our distribution is frechet-like. We claim this is + * an acceptable approximation because we are only concerned with the + * accuracy of the CDF of the tail. + */ +STATIC int +circuit_build_times_update_alpha(circuit_build_times_t *cbt) +{ + build_time_t *x=cbt->circuit_build_times; + double a = 0; + int n=0,i=0,abandoned_count=0; + build_time_t max_time=0; + + /* http://en.wikipedia.org/wiki/Pareto_distribution#Parameter_estimation */ + /* We sort of cheat here and make our samples slightly more pareto-like + * and less frechet-like. */ + cbt->Xm = circuit_build_times_get_xm(cbt); + + tor_assert(cbt->Xm > 0); + + for (i=0; i< CBT_NCIRCUITS_TO_OBSERVE; i++) { + if (!x[i]) { + continue; + } + + if (x[i] < cbt->Xm) { + a += tor_mathlog(cbt->Xm); + } else if (x[i] == CBT_BUILD_ABANDONED) { + abandoned_count++; + } else { + a += tor_mathlog(x[i]); + if (x[i] > max_time) + max_time = x[i]; + } + n++; + } + + /* + * We are erring and asserting here because this can only happen + * in codepaths other than startup. The startup state parsing code + * performs this same check, and resets state if it hits it. If we + * hit it at runtime, something serious has gone wrong. + */ + if (n!=cbt->total_build_times) { + log_err(LD_CIRC, "Discrepancy in build times count: %d vs %d", n, + cbt->total_build_times); + } + tor_assert(n==cbt->total_build_times); + + if (max_time <= 0) { + /* This can happen if Xm is actually the *maximum* value in the set. + * It can also happen if we've abandoned every single circuit somehow. + * In either case, tell the caller not to compute a new build timeout. */ + log_warn(LD_BUG, + "Could not determine largest build time (%d). " + "Xm is %dms and we've abandoned %d out of %d circuits.", max_time, + cbt->Xm, abandoned_count, n); + return 0; + } + + a += abandoned_count*tor_mathlog(max_time); + + a -= n*tor_mathlog(cbt->Xm); + // Estimator comes from Eq #4 in: + // "Bayesian estimation based on trimmed samples from Pareto populations" + // by Arturo J. Fernández. We are right-censored only. + a = (n-abandoned_count)/a; + + cbt->alpha = a; + + return 1; +} + +/** + * This is the Pareto Quantile Function. It calculates the point x + * in the distribution such that F(x) = quantile (ie quantile*100% + * of the mass of the density function is below x on the curve). + * + * We use it to calculate the timeout and also to generate synthetic + * values of time for circuits that timeout before completion. + * + * See http://en.wikipedia.org/wiki/Quantile_function, + * http://en.wikipedia.org/wiki/Inverse_transform_sampling and + * http://en.wikipedia.org/wiki/Pareto_distribution#Generating_a_ + * random_sample_from_Pareto_distribution + * That's right. I'll cite wikipedia all day long. + * + * Return value is in milliseconds. + */ +STATIC double +circuit_build_times_calculate_timeout(circuit_build_times_t *cbt, + double quantile) +{ + double ret; + tor_assert(quantile >= 0); + tor_assert(1.0-quantile > 0); + tor_assert(cbt->Xm > 0); + + ret = cbt->Xm/pow(1.0-quantile,1.0/cbt->alpha); + if (ret > INT32_MAX) { + ret = INT32_MAX; + } + tor_assert(ret > 0); + return ret; +} + +#ifdef TOR_UNIT_TESTS +/** Pareto CDF */ +double +circuit_build_times_cdf(circuit_build_times_t *cbt, double x) +{ + double ret; + tor_assert(cbt->Xm > 0); + ret = 1.0-pow(cbt->Xm/x,cbt->alpha); + tor_assert(0 <= ret && ret <= 1.0); + return ret; +} +#endif + +#ifdef TOR_UNIT_TESTS +/** + * Generate a synthetic time using our distribution parameters. + * + * The return value will be within the [q_lo, q_hi) quantile points + * on the CDF. + */ +build_time_t +circuit_build_times_generate_sample(circuit_build_times_t *cbt, + double q_lo, double q_hi) +{ + double randval = crypto_rand_double(); + build_time_t ret; + double u; + + /* Generate between [q_lo, q_hi) */ + /*XXXX This is what nextafter is supposed to be for; we should use it on the + * platforms that support it. */ + q_hi -= 1.0/(INT32_MAX); + + tor_assert(q_lo >= 0); + tor_assert(q_hi < 1); + tor_assert(q_lo < q_hi); + + u = q_lo + (q_hi-q_lo)*randval; + + tor_assert(0 <= u && u < 1.0); + /* circuit_build_times_calculate_timeout returns <= INT32_MAX */ + ret = (build_time_t) + tor_lround(circuit_build_times_calculate_timeout(cbt, u)); + tor_assert(ret > 0); + return ret; +} +#endif + +#ifdef TOR_UNIT_TESTS +/** + * Estimate an initial alpha parameter by solving the quantile + * function with a quantile point and a specific timeout value. + */ +void +circuit_build_times_initial_alpha(circuit_build_times_t *cbt, + double quantile, double timeout_ms) +{ + // Q(u) = Xm/((1-u)^(1/a)) + // Q(0.8) = Xm/((1-0.8))^(1/a)) = CircBuildTimeout + // CircBuildTimeout = Xm/((1-0.8))^(1/a)) + // CircBuildTimeout = Xm*((1-0.8))^(-1/a)) + // ln(CircBuildTimeout) = ln(Xm)+ln(((1-0.8)))*(-1/a) + // -ln(1-0.8)/(ln(CircBuildTimeout)-ln(Xm))=a + tor_assert(quantile >= 0); + tor_assert(cbt->Xm > 0); + cbt->alpha = tor_mathlog(1.0-quantile)/ + (tor_mathlog(cbt->Xm)-tor_mathlog(timeout_ms)); + tor_assert(cbt->alpha > 0); +} +#endif + +/** + * Returns true if we need circuits to be built + */ +int +circuit_build_times_needs_circuits(const circuit_build_times_t *cbt) +{ + /* Return true if < MIN_CIRCUITS_TO_OBSERVE */ + return !circuit_build_times_enough_to_compute(cbt); +} + +/** + * Returns true if we should build a timeout test circuit + * right now. + */ +int +circuit_build_times_needs_circuits_now(const circuit_build_times_t *cbt) +{ + return circuit_build_times_needs_circuits(cbt) && + approx_time()-cbt->last_circ_at > circuit_build_times_test_frequency(); +} + +/** + * Called to indicate that the network showed some signs of liveness, + * i.e. we received a cell. + * + * This is used by circuit_build_times_network_check_live() to decide + * if we should record the circuit build timeout or not. + * + * This function is called every time we receive a cell. Avoid + * syscalls, events, and other high-intensity work. + */ +void +circuit_build_times_network_is_live(circuit_build_times_t *cbt) +{ + time_t now = approx_time(); + if (cbt->liveness.nonlive_timeouts > 0) { + log_notice(LD_CIRC, + "Tor now sees network activity. Restoring circuit build " + "timeout recording. Network was down for %d seconds " + "during %d circuit attempts.", + (int)(now - cbt->liveness.network_last_live), + cbt->liveness.nonlive_timeouts); + } + cbt->liveness.network_last_live = now; + cbt->liveness.nonlive_timeouts = 0; +} + +/** + * Called to indicate that we completed a circuit. Because this circuit + * succeeded, it doesn't count as a timeout-after-the-first-hop. + * + * This is used by circuit_build_times_network_check_changed() to determine + * if we had too many recent timeouts and need to reset our learned timeout + * to something higher. + */ +void +circuit_build_times_network_circ_success(circuit_build_times_t *cbt) +{ + /* Check for NULLness because we might not be using adaptive timeouts */ + if (cbt->liveness.timeouts_after_firsthop && + cbt->liveness.num_recent_circs > 0) { + cbt->liveness.timeouts_after_firsthop[cbt->liveness.after_firsthop_idx] + = 0; + cbt->liveness.after_firsthop_idx++; + cbt->liveness.after_firsthop_idx %= cbt->liveness.num_recent_circs; + } +} + +/** + * A circuit just timed out. If it failed after the first hop, record it + * in our history for later deciding if the network speed has changed. + * + * This is used by circuit_build_times_network_check_changed() to determine + * if we had too many recent timeouts and need to reset our learned timeout + * to something higher. + */ +static void +circuit_build_times_network_timeout(circuit_build_times_t *cbt, + int did_onehop) +{ + /* Check for NULLness because we might not be using adaptive timeouts */ + if (cbt->liveness.timeouts_after_firsthop && + cbt->liveness.num_recent_circs > 0) { + if (did_onehop) { + cbt->liveness.timeouts_after_firsthop[cbt->liveness.after_firsthop_idx] + = 1; + cbt->liveness.after_firsthop_idx++; + cbt->liveness.after_firsthop_idx %= cbt->liveness.num_recent_circs; + } + } +} + +/** + * A circuit was just forcibly closed. If there has been no recent network + * activity at all, but this circuit was launched back when we thought the + * network was live, increment the number of "nonlive" circuit timeouts. + * + * This is used by circuit_build_times_network_check_live() to decide + * if we should record the circuit build timeout or not. + */ +static void +circuit_build_times_network_close(circuit_build_times_t *cbt, + int did_onehop, time_t start_time) +{ + time_t now = time(NULL); + /* + * Check if this is a timeout that was for a circuit that spent its + * entire existence during a time where we have had no network activity. + */ + if (cbt->liveness.network_last_live < start_time) { + if (did_onehop) { + char last_live_buf[ISO_TIME_LEN+1]; + char start_time_buf[ISO_TIME_LEN+1]; + char now_buf[ISO_TIME_LEN+1]; + format_local_iso_time(last_live_buf, cbt->liveness.network_last_live); + format_local_iso_time(start_time_buf, start_time); + format_local_iso_time(now_buf, now); + log_notice(LD_CIRC, + "A circuit somehow completed a hop while the network was " + "not live. The network was last live at %s, but the circuit " + "launched at %s. It's now %s. This could mean your clock " + "changed.", last_live_buf, start_time_buf, now_buf); + } + cbt->liveness.nonlive_timeouts++; + if (cbt->liveness.nonlive_timeouts == 1) { + log_notice(LD_CIRC, + "Tor has not observed any network activity for the past %d " + "seconds. Disabling circuit build timeout recording.", + (int)(now - cbt->liveness.network_last_live)); + } else { + log_info(LD_CIRC, + "Got non-live timeout. Current count is: %d", + cbt->liveness.nonlive_timeouts); + } + } +} + +/** + * When the network is not live, we do not record circuit build times. + * + * The network is considered not live if there has been at least one + * circuit build that began and ended (had its close_ms measurement + * period expire) since we last received a cell. + * + * Also has the side effect of rewinding the circuit time history + * in the case of recent liveness changes. + */ +int +circuit_build_times_network_check_live(const circuit_build_times_t *cbt) +{ + if (cbt->liveness.nonlive_timeouts > 0) { + return 0; + } + + return 1; +} + +/** + * Returns true if we have seen more than MAX_RECENT_TIMEOUT_COUNT of + * the past RECENT_CIRCUITS time out after the first hop. Used to detect + * if the network connection has changed significantly, and if so, + * resets our circuit build timeout to the default. + * + * Also resets the entire timeout history in this case and causes us + * to restart the process of building test circuits and estimating a + * new timeout. + */ +STATIC int +circuit_build_times_network_check_changed(circuit_build_times_t *cbt) +{ + int total_build_times = cbt->total_build_times; + int timeout_count=0; + int i; + + if (cbt->liveness.timeouts_after_firsthop && + cbt->liveness.num_recent_circs > 0) { + /* how many of our recent circuits made it to the first hop but then + * timed out? */ + for (i = 0; i < cbt->liveness.num_recent_circs; i++) { + timeout_count += cbt->liveness.timeouts_after_firsthop[i]; + } + } + + /* If 80% of our recent circuits are timing out after the first hop, + * we need to re-estimate a new initial alpha and timeout. */ + if (timeout_count < circuit_build_times_max_timeouts()) { + return 0; + } + + circuit_build_times_reset(cbt); + if (cbt->liveness.timeouts_after_firsthop && + cbt->liveness.num_recent_circs > 0) { + memset(cbt->liveness.timeouts_after_firsthop, 0, + sizeof(*cbt->liveness.timeouts_after_firsthop)* + cbt->liveness.num_recent_circs); + } + cbt->liveness.after_firsthop_idx = 0; + + /* Check to see if this has happened before. If so, double the timeout + * to give people on abysmally bad network connections a shot at access */ + if (cbt->timeout_ms >= circuit_build_times_get_initial_timeout()) { + if (cbt->timeout_ms > INT32_MAX/2 || cbt->close_ms > INT32_MAX/2) { + log_warn(LD_CIRC, "Insanely large circuit build timeout value. " + "(timeout = %fmsec, close = %fmsec)", + cbt->timeout_ms, cbt->close_ms); + } else { + cbt->timeout_ms *= 2; + cbt->close_ms *= 2; + } + } else { + cbt->close_ms = cbt->timeout_ms + = circuit_build_times_get_initial_timeout(); + } + + cbt_control_event_buildtimeout_set(cbt, BUILDTIMEOUT_SET_EVENT_RESET); + + log_notice(LD_CIRC, + "Your network connection speed appears to have changed. Resetting " + "timeout to %lds after %d timeouts and %d buildtimes.", + tor_lround(cbt->timeout_ms/1000), timeout_count, + total_build_times); + + return 1; +} + +/** + * Count the number of timeouts in a set of cbt data. + */ +double +circuit_build_times_timeout_rate(const circuit_build_times_t *cbt) +{ + int i=0,timeouts=0; + for (i = 0; i < CBT_NCIRCUITS_TO_OBSERVE; i++) { + if (cbt->circuit_build_times[i] >= cbt->timeout_ms) { + timeouts++; + } + } + + if (!cbt->total_build_times) + return 0; + + return ((double)timeouts)/cbt->total_build_times; +} + +/** + * Count the number of closed circuits in a set of cbt data. + */ +double +circuit_build_times_close_rate(const circuit_build_times_t *cbt) +{ + int i=0,closed=0; + for (i = 0; i < CBT_NCIRCUITS_TO_OBSERVE; i++) { + if (cbt->circuit_build_times[i] == CBT_BUILD_ABANDONED) { + closed++; + } + } + + if (!cbt->total_build_times) + return 0; + + return ((double)closed)/cbt->total_build_times; +} + +/** + * Store a timeout as a synthetic value. + * + * Returns true if the store was successful and we should possibly + * update our timeout estimate. + */ +int +circuit_build_times_count_close(circuit_build_times_t *cbt, + int did_onehop, + time_t start_time) +{ + if (circuit_build_times_disabled()) { + cbt->close_ms = cbt->timeout_ms + = circuit_build_times_get_initial_timeout(); + return 0; + } + + /* Record this force-close to help determine if the network is dead */ + circuit_build_times_network_close(cbt, did_onehop, start_time); + + /* Only count timeouts if network is live.. */ + if (!circuit_build_times_network_check_live(cbt)) { + return 0; + } + + circuit_build_times_add_time(cbt, CBT_BUILD_ABANDONED); + return 1; +} + +/** + * Update timeout counts to determine if we need to expire + * our build time history due to excessive timeouts. + * + * We do not record any actual time values at this stage; + * we are only interested in recording the fact that a timeout + * happened. We record the time values via + * circuit_build_times_count_close() and circuit_build_times_add_time(). + */ +void +circuit_build_times_count_timeout(circuit_build_times_t *cbt, + int did_onehop) +{ + if (circuit_build_times_disabled()) { + cbt->close_ms = cbt->timeout_ms + = circuit_build_times_get_initial_timeout(); + return; + } + + /* Register the fact that a timeout just occurred. */ + circuit_build_times_network_timeout(cbt, did_onehop); + + /* If there are a ton of timeouts, we should reset + * the circuit build timeout. */ + circuit_build_times_network_check_changed(cbt); +} + +/** + * Estimate a new timeout based on history and set our timeout + * variable accordingly. + */ +static int +circuit_build_times_set_timeout_worker(circuit_build_times_t *cbt) +{ + build_time_t max_time; + if (!circuit_build_times_enough_to_compute(cbt)) + return 0; + + if (!circuit_build_times_update_alpha(cbt)) + return 0; + + cbt->timeout_ms = circuit_build_times_calculate_timeout(cbt, + circuit_build_times_quantile_cutoff()); + + cbt->close_ms = circuit_build_times_calculate_timeout(cbt, + circuit_build_times_close_quantile()); + + max_time = circuit_build_times_max(cbt); + + if (cbt->timeout_ms > max_time) { + log_info(LD_CIRC, + "Circuit build timeout of %dms is beyond the maximum build " + "time we have ever observed. Capping it to %dms.", + (int)cbt->timeout_ms, max_time); + cbt->timeout_ms = max_time; + } + + if (max_time < INT32_MAX/2 && cbt->close_ms > 2*max_time) { + log_info(LD_CIRC, + "Circuit build measurement period of %dms is more than twice " + "the maximum build time we have ever observed. Capping it to " + "%dms.", (int)cbt->close_ms, 2*max_time); + cbt->close_ms = 2*max_time; + } + + /* Sometimes really fast guard nodes give us such a steep curve + * that this ends up being not that much greater than timeout_ms. + * Make it be at least 1 min to handle this case. */ + cbt->close_ms = MAX(cbt->close_ms, circuit_build_times_initial_timeout()); + + cbt->have_computed_timeout = 1; + return 1; +} + +/** + * Exposed function to compute a new timeout. Dispatches events and + * also filters out extremely high timeout values. + */ +void +circuit_build_times_set_timeout(circuit_build_times_t *cbt) +{ + long prev_timeout = tor_lround(cbt->timeout_ms/1000); + double timeout_rate; + + /* + * Just return if we aren't using adaptive timeouts + */ + if (circuit_build_times_disabled()) + return; + + if (!circuit_build_times_set_timeout_worker(cbt)) + return; + + if (cbt->timeout_ms < circuit_build_times_min_timeout()) { + log_info(LD_CIRC, "Set buildtimeout to low value %fms. Setting to %dms", + cbt->timeout_ms, circuit_build_times_min_timeout()); + cbt->timeout_ms = circuit_build_times_min_timeout(); + if (cbt->close_ms < cbt->timeout_ms) { + /* This shouldn't happen because of MAX() in timeout_worker above, + * but doing it just in case */ + cbt->close_ms = circuit_build_times_initial_timeout(); + } + } + + cbt_control_event_buildtimeout_set(cbt, BUILDTIMEOUT_SET_EVENT_COMPUTED); + + timeout_rate = circuit_build_times_timeout_rate(cbt); + + if (prev_timeout > tor_lround(cbt->timeout_ms/1000)) { + log_info(LD_CIRC, + "Based on %d circuit times, it looks like we don't need to " + "wait so long for circuits to finish. We will now assume a " + "circuit is too slow to use after waiting %ld seconds.", + cbt->total_build_times, + tor_lround(cbt->timeout_ms/1000)); + log_info(LD_CIRC, + "Circuit timeout data: %fms, %fms, Xm: %d, a: %f, r: %f", + cbt->timeout_ms, cbt->close_ms, cbt->Xm, cbt->alpha, + timeout_rate); + } else if (prev_timeout < tor_lround(cbt->timeout_ms/1000)) { + log_info(LD_CIRC, + "Based on %d circuit times, it looks like we need to wait " + "longer for circuits to finish. We will now assume a " + "circuit is too slow to use after waiting %ld seconds.", + cbt->total_build_times, + tor_lround(cbt->timeout_ms/1000)); + log_info(LD_CIRC, + "Circuit timeout data: %fms, %fms, Xm: %d, a: %f, r: %f", + cbt->timeout_ms, cbt->close_ms, cbt->Xm, cbt->alpha, + timeout_rate); + } else { + log_info(LD_CIRC, + "Set circuit build timeout to %lds (%fms, %fms, Xm: %d, a: %f," + " r: %f) based on %d circuit times", + tor_lround(cbt->timeout_ms/1000), + cbt->timeout_ms, cbt->close_ms, cbt->Xm, cbt->alpha, timeout_rate, + cbt->total_build_times); + } +} + +#ifdef TOR_UNIT_TESTS +/** Make a note that we're running unit tests (rather than running Tor + * itself), so we avoid clobbering our state file. */ +void +circuitbuild_running_unit_tests(void) +{ + unit_tests = 1; +} +#endif + +void +circuit_build_times_update_last_circ(circuit_build_times_t *cbt) +{ + cbt->last_circ_at = approx_time(); +} + +static void +cbt_control_event_buildtimeout_set(const circuit_build_times_t *cbt, + buildtimeout_set_event_t type) +{ + char *args = NULL; + double qnt; + + switch (type) { + case BUILDTIMEOUT_SET_EVENT_RESET: + case BUILDTIMEOUT_SET_EVENT_SUSPENDED: + case BUILDTIMEOUT_SET_EVENT_DISCARD: + qnt = 1.0; + break; + case BUILDTIMEOUT_SET_EVENT_COMPUTED: + case BUILDTIMEOUT_SET_EVENT_RESUME: + default: + qnt = circuit_build_times_quantile_cutoff(); + break; + } + + tor_asprintf(&args, "TOTAL_TIMES=%lu " + "TIMEOUT_MS=%lu XM=%lu ALPHA=%f CUTOFF_QUANTILE=%f " + "TIMEOUT_RATE=%f CLOSE_MS=%lu CLOSE_RATE=%f", + (unsigned long)cbt->total_build_times, + (unsigned long)cbt->timeout_ms, + (unsigned long)cbt->Xm, cbt->alpha, qnt, + circuit_build_times_timeout_rate(cbt), + (unsigned long)cbt->close_ms, + circuit_build_times_close_rate(cbt)); + + control_event_buildtimeout_set(type, args); + + tor_free(args); +} + diff --git a/src/tor/circuitstats.h b/src/tor/circuitstats.h new file mode 100644 index 0000000..3343310 --- /dev/null +++ b/src/tor/circuitstats.h @@ -0,0 +1,98 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file circuitstats.h + * \brief Header file for circuitstats.c + **/ + +#ifndef TOR_CIRCUITSTATS_H +#define TOR_CIRCUITSTATS_H + +const circuit_build_times_t *get_circuit_build_times(void); +circuit_build_times_t *get_circuit_build_times_mutable(void); +double get_circuit_build_close_time_ms(void); +double get_circuit_build_timeout_ms(void); + +int circuit_build_times_disabled(void); +int circuit_build_times_enough_to_compute(const circuit_build_times_t *cbt); +void circuit_build_times_update_state(const circuit_build_times_t *cbt, + or_state_t *state); +int circuit_build_times_parse_state(circuit_build_times_t *cbt, + or_state_t *state); +void circuit_build_times_count_timeout(circuit_build_times_t *cbt, + int did_onehop); +int circuit_build_times_count_close(circuit_build_times_t *cbt, + int did_onehop, time_t start_time); +void circuit_build_times_set_timeout(circuit_build_times_t *cbt); +int circuit_build_times_add_time(circuit_build_times_t *cbt, + build_time_t time); +int circuit_build_times_needs_circuits(const circuit_build_times_t *cbt); + +int circuit_build_times_needs_circuits_now(const circuit_build_times_t *cbt); +void circuit_build_times_init(circuit_build_times_t *cbt); +void circuit_build_times_free_timeouts(circuit_build_times_t *cbt); +void circuit_build_times_new_consensus_params(circuit_build_times_t *cbt, + networkstatus_t *ns); +double circuit_build_times_timeout_rate(const circuit_build_times_t *cbt); +double circuit_build_times_close_rate(const circuit_build_times_t *cbt); + +void circuit_build_times_update_last_circ(circuit_build_times_t *cbt); + +#ifdef CIRCUITSTATS_PRIVATE +STATIC double circuit_build_times_calculate_timeout(circuit_build_times_t *cbt, + double quantile); +STATIC int circuit_build_times_update_alpha(circuit_build_times_t *cbt); +STATIC void circuit_build_times_reset(circuit_build_times_t *cbt); + +/* Network liveness functions */ +STATIC int circuit_build_times_network_check_changed( + circuit_build_times_t *cbt); +#endif + +#ifdef TOR_UNIT_TESTS +build_time_t circuit_build_times_generate_sample(circuit_build_times_t *cbt, + double q_lo, double q_hi); +double circuit_build_times_cdf(circuit_build_times_t *cbt, double x); +void circuit_build_times_initial_alpha(circuit_build_times_t *cbt, + double quantile, double time_ms); +void circuitbuild_running_unit_tests(void); +#endif + +/* Network liveness functions */ +void circuit_build_times_network_is_live(circuit_build_times_t *cbt); +int circuit_build_times_network_check_live(const circuit_build_times_t *cbt); +void circuit_build_times_network_circ_success(circuit_build_times_t *cbt); + +#ifdef CIRCUITSTATS_PRIVATE +/** Structure for circuit build times history */ +struct circuit_build_times_s { + /** The circular array of recorded build times in milliseconds */ + build_time_t circuit_build_times[CBT_NCIRCUITS_TO_OBSERVE]; + /** Current index in the circuit_build_times circular array */ + int build_times_idx; + /** Total number of build times accumulated. Max CBT_NCIRCUITS_TO_OBSERVE */ + int total_build_times; + /** Information about the state of our local network connection */ + network_liveness_t liveness; + /** Last time we built a circuit. Used to decide to build new test circs */ + time_t last_circ_at; + /** "Minimum" value of our pareto distribution (actually mode) */ + build_time_t Xm; + /** alpha exponent for pareto dist. */ + double alpha; + /** Have we computed a timeout? */ + int have_computed_timeout; + /** The exact value for that timeout in milliseconds. Stored as a double + * to maintain precision from calculations to and from quantile value. */ + double timeout_ms; + /** How long we wait before actually closing the circuit. */ + double close_ms; +}; +#endif + +#endif + diff --git a/src/tor/circuituse.c b/src/tor/circuituse.c new file mode 100644 index 0000000..8b82de0 --- /dev/null +++ b/src/tor/circuituse.c @@ -0,0 +1,2326 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file circuituse.c + * \brief Launch the right sort of circuits and attach streams to them. + **/ + +#include "or.h" +#include "addressmap.h" +#include "channel.h" +#include "circpathbias.h" +#include "circuitbuild.h" +#include "circuitlist.h" +#include "circuitstats.h" +#include "circuituse.h" +#include "config.h" +#include "connection.h" +#include "connection_edge.h" +#include "control.h" +#include "entrynodes.h" +#include "nodelist.h" +#include "networkstatus.h" +#include "policies.h" +#include "rendclient.h" +#include "rendcommon.h" +#include "rendservice.h" +#include "rephist.h" +#include "router.h" +#include "routerlist.h" + +static void circuit_expire_old_circuits_clientside(void); +static void circuit_increment_failure_count(void); + +/** Return 1 if circ could be returned by circuit_get_best(). + * Else return 0. + */ +static int +circuit_is_acceptable(const origin_circuit_t *origin_circ, + const entry_connection_t *conn, + int must_be_open, uint8_t purpose, + int need_uptime, int need_internal, + time_t now) +{ + const circuit_t *circ = TO_CIRCUIT(origin_circ); + const node_t *exitnode; + cpath_build_state_t *build_state; + tor_assert(circ); + tor_assert(conn); + tor_assert(conn->socks_request); + + if (must_be_open && (circ->state != CIRCUIT_STATE_OPEN || !circ->n_chan)) + return 0; /* ignore non-open circs */ + if (circ->marked_for_close) + return 0; + + /* if this circ isn't our purpose, skip. */ + if (purpose == CIRCUIT_PURPOSE_C_REND_JOINED && !must_be_open) { + if (circ->purpose != CIRCUIT_PURPOSE_C_ESTABLISH_REND && + circ->purpose != CIRCUIT_PURPOSE_C_REND_READY && + circ->purpose != CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED && + circ->purpose != CIRCUIT_PURPOSE_C_REND_JOINED) + return 0; + } else if (purpose == CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT && + !must_be_open) { + if (circ->purpose != CIRCUIT_PURPOSE_C_INTRODUCING && + circ->purpose != CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT) + return 0; + } else { + if (purpose != circ->purpose) + return 0; + } + + /* If this is a timed-out hidden service circuit, skip it. */ + if (origin_circ->hs_circ_has_timed_out) { + return 0; + } + + if (purpose == CIRCUIT_PURPOSE_C_GENERAL || + purpose == CIRCUIT_PURPOSE_C_REND_JOINED) { + if (circ->timestamp_dirty && + circ->timestamp_dirty+get_options()->MaxCircuitDirtiness <= now) + return 0; + } + + if (origin_circ->unusable_for_new_conns) + return 0; + + /* decide if this circ is suitable for this conn */ + + /* for rend circs, circ->cpath->prev is not the last router in the + * circuit, it's the magical extra bob hop. so just check the nickname + * of the one we meant to finish at. + */ + build_state = origin_circ->build_state; + exitnode = build_state_get_exit_node(build_state); + + if (need_uptime && !build_state->need_uptime) + return 0; + if (need_internal != build_state->is_internal) + return 0; + + if (purpose == CIRCUIT_PURPOSE_C_GENERAL) { + tor_addr_t addr; + const int family = tor_addr_parse(&addr, conn->socks_request->address); + if (!exitnode && !build_state->onehop_tunnel) { + log_debug(LD_CIRC,"Not considering circuit with unknown router."); + return 0; /* this circuit is screwed and doesn't know it yet, + * or is a rendezvous circuit. */ + } + if (build_state->onehop_tunnel) { + if (!conn->want_onehop) { + log_debug(LD_CIRC,"Skipping one-hop circuit."); + return 0; + } + tor_assert(conn->chosen_exit_name); + if (build_state->chosen_exit) { + char digest[DIGEST_LEN]; + if (hexdigest_to_digest(conn->chosen_exit_name, digest) < 0) + return 0; /* broken digest, we don't want it */ + if (tor_memneq(digest, build_state->chosen_exit->identity_digest, + DIGEST_LEN)) + return 0; /* this is a circuit to somewhere else */ + if (tor_digest_is_zero(digest)) { + /* we don't know the digest; have to compare addr:port */ + if (family < 0 || + !tor_addr_eq(&build_state->chosen_exit->addr, &addr) || + build_state->chosen_exit->port != conn->socks_request->port) + return 0; + } + } + } else { + if (conn->want_onehop) { + /* don't use three-hop circuits -- that could hurt our anonymity. */ + return 0; + } + } + if (origin_circ->prepend_policy && family != -1) { + int r = compare_tor_addr_to_addr_policy(&addr, + conn->socks_request->port, + origin_circ->prepend_policy); + if (r == ADDR_POLICY_REJECTED) + return 0; + } + if (exitnode && !connection_ap_can_use_exit(conn, exitnode)) { + /* can't exit from this router */ + return 0; + } + } else { /* not general */ + const edge_connection_t *edge_conn = ENTRY_TO_EDGE_CONN(conn); + if ((edge_conn->rend_data && !origin_circ->rend_data) || + (!edge_conn->rend_data && origin_circ->rend_data) || + (edge_conn->rend_data && origin_circ->rend_data && + rend_cmp_service_ids(edge_conn->rend_data->onion_address, + origin_circ->rend_data->onion_address))) { + /* this circ is not for this conn */ + return 0; + } + } + + if (!connection_edge_compatible_with_circuit(conn, origin_circ)) { + /* conn needs to be isolated from other conns that have already used + * origin_circ */ + return 0; + } + + return 1; +} + +/** Return 1 if circuit a is better than circuit b for + * conn, and return 0 otherwise. Used by circuit_get_best. + */ +static int +circuit_is_better(const origin_circuit_t *oa, const origin_circuit_t *ob, + const entry_connection_t *conn) +{ + const circuit_t *a = TO_CIRCUIT(oa); + const circuit_t *b = TO_CIRCUIT(ob); + const uint8_t purpose = ENTRY_TO_CONN(conn)->purpose; + int a_bits, b_bits; + + /* If one of the circuits was allowed to live due to relaxing its timeout, + * it is definitely worse (it's probably a much slower path). */ + if (oa->relaxed_timeout && !ob->relaxed_timeout) + return 0; /* ob is better. It's not relaxed. */ + if (!oa->relaxed_timeout && ob->relaxed_timeout) + return 1; /* oa is better. It's not relaxed. */ + + switch (purpose) { + case CIRCUIT_PURPOSE_C_GENERAL: + /* if it's used but less dirty it's best; + * else if it's more recently created it's best + */ + if (b->timestamp_dirty) { + if (a->timestamp_dirty && + a->timestamp_dirty > b->timestamp_dirty) + return 1; + } else { + if (a->timestamp_dirty || + timercmp(&a->timestamp_began, &b->timestamp_began, >)) + return 1; + if (ob->build_state->is_internal) + /* XXX023 what the heck is this internal thing doing here. I + * think we can get rid of it. circuit_is_acceptable() already + * makes sure that is_internal is exactly what we need it to + * be. -RD */ + return 1; + } + break; + case CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT: + /* the closer it is to ack_wait the better it is */ + if (a->purpose > b->purpose) + return 1; + break; + case CIRCUIT_PURPOSE_C_REND_JOINED: + /* the closer it is to rend_joined the better it is */ + if (a->purpose > b->purpose) + return 1; + break; + } + + /* XXXX023 Maybe this check should get a higher priority to avoid + * using up circuits too rapidly. */ + + a_bits = connection_edge_update_circuit_isolation(conn, + (origin_circuit_t*)oa, 1); + b_bits = connection_edge_update_circuit_isolation(conn, + (origin_circuit_t*)ob, 1); + /* if x_bits < 0, then we have not used x for anything; better not to dirty + * a connection if we can help it. */ + if (a_bits < 0) { + return 0; + } else if (b_bits < 0) { + return 1; + } + a_bits &= ~ oa->isolation_flags_mixed; + a_bits &= ~ ob->isolation_flags_mixed; + if (n_bits_set_u8(a_bits) < n_bits_set_u8(b_bits)) { + /* The fewer new restrictions we need to make on a circuit for stream + * isolation, the better. */ + return 1; + } + + return 0; +} + +/** Find the best circ that conn can use, preferably one which is + * dirty. Circ must not be too old. + * + * Conn must be defined. + * + * If must_be_open, ignore circs not in CIRCUIT_STATE_OPEN. + * + * circ_purpose specifies what sort of circuit we must have. + * It can be C_GENERAL, C_INTRODUCE_ACK_WAIT, or C_REND_JOINED. + * + * If it's REND_JOINED and must_be_open==0, then return the closest + * rendezvous-purposed circuit that you can find. + * + * If it's INTRODUCE_ACK_WAIT and must_be_open==0, then return the + * closest introduce-purposed circuit that you can find. + */ +static origin_circuit_t * +circuit_get_best(const entry_connection_t *conn, + int must_be_open, uint8_t purpose, + int need_uptime, int need_internal) +{ + circuit_t *circ; + origin_circuit_t *best=NULL; + struct timeval now; + int intro_going_on_but_too_old = 0; + + tor_assert(conn); + + tor_assert(purpose == CIRCUIT_PURPOSE_C_GENERAL || + purpose == CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT || + purpose == CIRCUIT_PURPOSE_C_REND_JOINED); + + tor_gettimeofday(&now); + + TOR_LIST_FOREACH(circ, circuit_get_global_list(), head) { + origin_circuit_t *origin_circ; + if (!CIRCUIT_IS_ORIGIN(circ)) + continue; + origin_circ = TO_ORIGIN_CIRCUIT(circ); + + /* Log an info message if we're going to launch a new intro circ in + * parallel */ + if (purpose == CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT && + !must_be_open && origin_circ->hs_circ_has_timed_out) { + intro_going_on_but_too_old = 1; + continue; + } + + if (!circuit_is_acceptable(origin_circ,conn,must_be_open,purpose, + need_uptime,need_internal,now.tv_sec)) + continue; + + /* now this is an acceptable circ to hand back. but that doesn't + * mean it's the *best* circ to hand back. try to decide. + */ + if (!best || circuit_is_better(origin_circ,best,conn)) + best = origin_circ; + } + + if (!best && intro_going_on_but_too_old) + log_info(LD_REND|LD_CIRC, "There is an intro circuit being created " + "right now, but it has already taken quite a while. Starting " + "one in parallel."); + + return best; +} + +/** Return the number of not-yet-open general-purpose origin circuits. */ +static int +count_pending_general_client_circuits(void) +{ + const circuit_t *circ; + + int count = 0; + + TOR_LIST_FOREACH(circ, circuit_get_global_list(), head) { + if (circ->marked_for_close || + circ->state == CIRCUIT_STATE_OPEN || + circ->purpose != CIRCUIT_PURPOSE_C_GENERAL || + !CIRCUIT_IS_ORIGIN(circ)) + continue; + + ++count; + } + + return count; +} + +#if 0 +/** Check whether, according to the policies in options, the + * circuit circ makes sense. */ +/* XXXX currently only checks Exclude{Exit}Nodes; it should check more. + * Also, it doesn't have the right definition of an exit circuit. Also, + * it's never called. */ +int +circuit_conforms_to_options(const origin_circuit_t *circ, + const or_options_t *options) +{ + const crypt_path_t *cpath, *cpath_next = NULL; + + /* first check if it includes any excluded nodes */ + for (cpath = circ->cpath; cpath_next != circ->cpath; cpath = cpath_next) { + cpath_next = cpath->next; + if (routerset_contains_extendinfo(options->ExcludeNodes, + cpath->extend_info)) + return 0; + } + + /* then consider the final hop */ + if (routerset_contains_extendinfo(options->ExcludeExitNodes, + circ->cpath->prev->extend_info)) + return 0; + + return 1; +} +#endif + +/** Close all circuits that start at us, aren't open, and were born + * at least CircuitBuildTimeout seconds ago. + */ +void +circuit_expire_building(void) +{ + circuit_t *victim, *next_circ; + /* circ_times.timeout_ms and circ_times.close_ms are from + * circuit_build_times_get_initial_timeout() if we haven't computed + * custom timeouts yet */ + struct timeval general_cutoff, begindir_cutoff, fourhop_cutoff, + close_cutoff, extremely_old_cutoff, hs_extremely_old_cutoff, + cannibalized_cutoff, c_intro_cutoff, s_intro_cutoff, stream_cutoff; + const or_options_t *options = get_options(); + struct timeval now; + cpath_build_state_t *build_state; + int any_opened_circs = 0; + + tor_gettimeofday(&now); + + /* Check to see if we have any opened circuits. If we don't, + * we want to be more lenient with timeouts, in case the + * user has relocated and/or changed network connections. + * See bug #3443. */ + TOR_LIST_FOREACH(next_circ, circuit_get_global_list(), head) { + if (!CIRCUIT_IS_ORIGIN(next_circ) || /* didn't originate here */ + next_circ->marked_for_close) { /* don't mess with marked circs */ + continue; + } + + if (TO_ORIGIN_CIRCUIT(next_circ)->has_opened && + next_circ->state == CIRCUIT_STATE_OPEN && + TO_ORIGIN_CIRCUIT(next_circ)->build_state && + TO_ORIGIN_CIRCUIT(next_circ)->build_state->desired_path_len + == DEFAULT_ROUTE_LEN) { + any_opened_circs = 1; + break; + } + } + +#define SET_CUTOFF(target, msec) do { \ + long ms = tor_lround(msec); \ + struct timeval diff; \ + diff.tv_sec = ms / 1000; \ + diff.tv_usec = (int)((ms % 1000) * 1000); \ + timersub(&now, &diff, &target); \ + } while (0) + + /** + * Because circuit build timeout is calculated only based on 3 hop + * general purpose circuit construction, we need to scale the timeout + * to make it properly apply to longer circuits, and circuits of + * certain usage types. The following diagram illustrates how we + * derive the scaling below. In short, we calculate the number + * of times our telescoping-based circuit construction causes cells + * to traverse each link for the circuit purpose types in question, + * and then assume each link is equivalent. + * + * OP --a--> A --b--> B --c--> C + * OP --a--> A --b--> B --c--> C --d--> D + * + * Let h = a = b = c = d + * + * Three hops (general_cutoff) + * RTTs = 3a + 2b + c + * RTTs = 6h + * Cannibalized: + * RTTs = a+b+c+d + * RTTs = 4h + * Four hops: + * RTTs = 4a + 3b + 2c + d + * RTTs = 10h + * Client INTRODUCE1+ACK: // XXX: correct? + * RTTs = 5a + 4b + 3c + 2d + * RTTs = 14h + * Server intro: + * RTTs = 4a + 3b + 2c + * RTTs = 9h + */ + SET_CUTOFF(general_cutoff, get_circuit_build_timeout_ms()); + SET_CUTOFF(begindir_cutoff, get_circuit_build_timeout_ms()); + + /* > 3hop circs seem to have a 1.0 second delay on their cannibalized + * 4th hop. */ + SET_CUTOFF(fourhop_cutoff, get_circuit_build_timeout_ms() * (10/6.0) + 1000); + + /* CIRCUIT_PURPOSE_C_ESTABLISH_REND behaves more like a RELAY cell. + * Use the stream cutoff (more or less). */ + SET_CUTOFF(stream_cutoff, MAX(options->CircuitStreamTimeout,15)*1000 + 1000); + + /* Be lenient with cannibalized circs. They already survived the official + * CBT, and they're usually not performance-critical. */ + SET_CUTOFF(cannibalized_cutoff, + MAX(get_circuit_build_close_time_ms()*(4/6.0), + options->CircuitStreamTimeout * 1000) + 1000); + + /* Intro circs have an extra round trip (and are also 4 hops long) */ + SET_CUTOFF(c_intro_cutoff, get_circuit_build_timeout_ms() * (14/6.0) + 1000); + + /* Server intro circs have an extra round trip */ + SET_CUTOFF(s_intro_cutoff, get_circuit_build_timeout_ms() * (9/6.0) + 1000); + + SET_CUTOFF(close_cutoff, get_circuit_build_close_time_ms()); + SET_CUTOFF(extremely_old_cutoff, get_circuit_build_close_time_ms()*2 + 1000); + + SET_CUTOFF(hs_extremely_old_cutoff, + MAX(get_circuit_build_close_time_ms()*2 + 1000, + options->SocksTimeout * 1000)); + + TOR_LIST_FOREACH(next_circ, circuit_get_global_list(), head) { + struct timeval cutoff; + victim = next_circ; + if (!CIRCUIT_IS_ORIGIN(victim) || /* didn't originate here */ + victim->marked_for_close) /* don't mess with marked circs */ + continue; + + /* If we haven't yet started the first hop, it means we don't have + * any orconns available, and thus have not started counting time yet + * for this circuit. See circuit_deliver_create_cell() and uses of + * timestamp_began. + * + * Continue to wait in this case. The ORConn should timeout + * independently and kill us then. + */ + if (TO_ORIGIN_CIRCUIT(victim)->cpath->state == CPATH_STATE_CLOSED) { + continue; + } + + build_state = TO_ORIGIN_CIRCUIT(victim)->build_state; + if (build_state && build_state->onehop_tunnel) + cutoff = begindir_cutoff; + else if (victim->purpose == CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT) + cutoff = close_cutoff; + else if (victim->purpose == CIRCUIT_PURPOSE_C_INTRODUCING || + victim->purpose == CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT) + cutoff = c_intro_cutoff; + else if (victim->purpose == CIRCUIT_PURPOSE_S_ESTABLISH_INTRO) + cutoff = s_intro_cutoff; + else if (victim->purpose == CIRCUIT_PURPOSE_C_ESTABLISH_REND) + cutoff = stream_cutoff; + else if (victim->purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING) + cutoff = close_cutoff; + else if (TO_ORIGIN_CIRCUIT(victim)->has_opened && + victim->state != CIRCUIT_STATE_OPEN) + cutoff = cannibalized_cutoff; + else if (build_state && build_state->desired_path_len >= 4) + cutoff = fourhop_cutoff; + else + cutoff = general_cutoff; + + if (TO_ORIGIN_CIRCUIT(victim)->hs_circ_has_timed_out) + cutoff = hs_extremely_old_cutoff; + + if (timercmp(&victim->timestamp_began, &cutoff, >)) + continue; /* it's still young, leave it alone */ + + /* We need to double-check the opened state here because + * we don't want to consider opened 1-hop dircon circuits for + * deciding when to relax the timeout, but we *do* want to relax + * those circuits too if nothing else is opened *and* they still + * aren't either. */ + if (!any_opened_circs && victim->state != CIRCUIT_STATE_OPEN) { + /* It's still young enough that we wouldn't close it, right? */ + if (timercmp(&victim->timestamp_began, &close_cutoff, >)) { + if (!TO_ORIGIN_CIRCUIT(victim)->relaxed_timeout) { + int first_hop_succeeded = TO_ORIGIN_CIRCUIT(victim)->cpath->state + == CPATH_STATE_OPEN; + log_info(LD_CIRC, + "No circuits are opened. Relaxing timeout for circuit %d " + "(a %s %d-hop circuit in state %s with channel state %s). " + "%d guards are live.", + TO_ORIGIN_CIRCUIT(victim)->global_identifier, + circuit_purpose_to_string(victim->purpose), + TO_ORIGIN_CIRCUIT(victim)->build_state->desired_path_len, + circuit_state_to_string(victim->state), + channel_state_to_string(victim->n_chan->state), + num_live_entry_guards(0)); + + /* We count the timeout here for CBT, because technically this + * was a timeout, and the timeout value needs to reset if we + * see enough of them. Note this means we also need to avoid + * double-counting below, too. */ + circuit_build_times_count_timeout(get_circuit_build_times_mutable(), + first_hop_succeeded); + TO_ORIGIN_CIRCUIT(victim)->relaxed_timeout = 1; + } + continue; + } else { + static ratelim_t relax_timeout_limit = RATELIM_INIT(3600); + const double build_close_ms = get_circuit_build_close_time_ms(); + log_fn_ratelim(&relax_timeout_limit, LOG_NOTICE, LD_CIRC, + "No circuits are opened. Relaxed timeout for circuit %d " + "(a %s %d-hop circuit in state %s with channel state %s) to " + "%ldms. However, it appears the circuit has timed out " + "anyway. %d guards are live.", + TO_ORIGIN_CIRCUIT(victim)->global_identifier, + circuit_purpose_to_string(victim->purpose), + TO_ORIGIN_CIRCUIT(victim)->build_state->desired_path_len, + circuit_state_to_string(victim->state), + channel_state_to_string(victim->n_chan->state), + (long)build_close_ms, + num_live_entry_guards(0)); + } + } + +#if 0 + /* some debug logs, to help track bugs */ + if (victim->purpose >= CIRCUIT_PURPOSE_C_INTRODUCING && + victim->purpose <= CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED) { + if (!victim->timestamp_dirty) + log_fn(LOG_DEBUG,"Considering %sopen purpose %d to %s (circid %d)." + "(clean).", + victim->state == CIRCUIT_STATE_OPEN ? "" : "non", + victim->purpose, victim->build_state->chosen_exit_name, + victim->n_circ_id); + else + log_fn(LOG_DEBUG,"Considering %sopen purpose %d to %s (circid %d). " + "%d secs since dirty.", + victim->state == CIRCUIT_STATE_OPEN ? "" : "non", + victim->purpose, victim->build_state->chosen_exit_name, + victim->n_circ_id, + (int)(now - victim->timestamp_dirty)); + } +#endif + + /* if circ is !open, or if it's open but purpose is a non-finished + * intro or rend, then mark it for close */ + if (victim->state == CIRCUIT_STATE_OPEN) { + switch (victim->purpose) { + default: /* most open circuits can be left alone. */ + continue; /* yes, continue inside a switch refers to the nearest + * enclosing loop. C is smart. */ + case CIRCUIT_PURPOSE_S_ESTABLISH_INTRO: + break; /* too old, need to die */ + case CIRCUIT_PURPOSE_C_REND_READY: + /* it's a rend_ready circ -- has it already picked a query? */ + /* c_rend_ready circs measure age since timestamp_dirty, + * because that's set when they switch purposes + */ + if (TO_ORIGIN_CIRCUIT(victim)->rend_data || + victim->timestamp_dirty > cutoff.tv_sec) + continue; + break; + case CIRCUIT_PURPOSE_PATH_BIAS_TESTING: + /* Open path bias testing circuits are given a long + * time to complete the test, but not forever */ + TO_ORIGIN_CIRCUIT(victim)->path_state = PATH_STATE_USE_FAILED; + break; + case CIRCUIT_PURPOSE_C_INTRODUCING: + /* We keep old introducing circuits around for + * a while in parallel, and they can end up "opened". + * We decide below if we're going to mark them timed + * out and eventually close them. + */ + break; + case CIRCUIT_PURPOSE_C_ESTABLISH_REND: + case CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED: + case CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT: + /* rend and intro circs become dirty each time they + * make an introduction attempt. so timestamp_dirty + * will reflect the time since the last attempt. + */ + if (victim->timestamp_dirty > cutoff.tv_sec) + continue; + break; + } + } else { /* circuit not open, consider recording failure as timeout */ + int first_hop_succeeded = TO_ORIGIN_CIRCUIT(victim)->cpath && + TO_ORIGIN_CIRCUIT(victim)->cpath->state == CPATH_STATE_OPEN; + + if (TO_ORIGIN_CIRCUIT(victim)->p_streams != NULL) { + log_warn(LD_BUG, "Circuit %d (purpose %d, %s) has timed out, " + "yet has attached streams!", + TO_ORIGIN_CIRCUIT(victim)->global_identifier, + victim->purpose, + circuit_purpose_to_string(victim->purpose)); + tor_fragile_assert(); + continue; + } + + if (circuit_timeout_want_to_count_circ(TO_ORIGIN_CIRCUIT(victim)) && + circuit_build_times_enough_to_compute(get_circuit_build_times())) { + /* Circuits are allowed to last longer for measurement. + * Switch their purpose and wait. */ + if (victim->purpose != CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT) { + control_event_circuit_status(TO_ORIGIN_CIRCUIT(victim), + CIRC_EVENT_FAILED, + END_CIRC_REASON_TIMEOUT); + circuit_change_purpose(victim, CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT); + /* Record this failure to check for too many timeouts + * in a row. This function does not record a time value yet + * (we do that later); it only counts the fact that we did + * have a timeout. We also want to avoid double-counting + * already "relaxed" circuits, which are counted above. */ + if (!TO_ORIGIN_CIRCUIT(victim)->relaxed_timeout) { + circuit_build_times_count_timeout( + get_circuit_build_times_mutable(), + first_hop_succeeded); + } + continue; + } + + /* + * If the circuit build time is much greater than we would have cut + * it off at, we probably had a suspend event along this codepath, + * and we should discard the value. + */ + if (timercmp(&victim->timestamp_began, &extremely_old_cutoff, <)) { + log_notice(LD_CIRC, + "Extremely large value for circuit build timeout: %lds. " + "Assuming clock jump. Purpose %d (%s)", + (long)(now.tv_sec - victim->timestamp_began.tv_sec), + victim->purpose, + circuit_purpose_to_string(victim->purpose)); + } else if (circuit_build_times_count_close( + get_circuit_build_times_mutable(), + first_hop_succeeded, + victim->timestamp_created.tv_sec)) { + circuit_build_times_set_timeout(get_circuit_build_times_mutable()); + } + } + } + + /* If this is a hidden service client circuit which is far enough + * along in connecting to its destination, and we haven't already + * flagged it as 'timed out', and the user has not told us to + * close such circs immediately on timeout, flag it as 'timed out' + * so we'll launch another intro or rend circ, but don't mark it + * for close yet. + * + * (Circs flagged as 'timed out' are given a much longer timeout + * period above, so we won't close them in the next call to + * circuit_expire_building.) */ + if (!(options->CloseHSClientCircuitsImmediatelyOnTimeout) && + !(TO_ORIGIN_CIRCUIT(victim)->hs_circ_has_timed_out)) { + switch (victim->purpose) { + case CIRCUIT_PURPOSE_C_REND_READY: + /* We only want to spare a rend circ if it has been specified in + * an INTRODUCE1 cell sent to a hidden service. A circ's + * pending_final_cpath field is non-NULL iff it is a rend circ + * and we have tried to send an INTRODUCE1 cell specifying it. + * Thus, if the pending_final_cpath field *is* NULL, then we + * want to not spare it. */ + if (TO_ORIGIN_CIRCUIT(victim)->build_state->pending_final_cpath == + NULL) + break; + /* fallthrough! */ + case CIRCUIT_PURPOSE_C_INTRODUCING: + /* connection_ap_handshake_attach_circuit() will relaunch for us */ + case CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT: + case CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED: + /* If we have reached this line, we want to spare the circ for now. */ + log_info(LD_CIRC,"Marking circ %u (state %d:%s, purpose %d) " + "as timed-out HS circ", + (unsigned)victim->n_circ_id, + victim->state, circuit_state_to_string(victim->state), + victim->purpose); + TO_ORIGIN_CIRCUIT(victim)->hs_circ_has_timed_out = 1; + continue; + default: + break; + } + } + + /* If this is a service-side rendezvous circuit which is far + * enough along in connecting to its destination, consider sparing + * it. */ + if (!(options->CloseHSServiceRendCircuitsImmediatelyOnTimeout) && + !(TO_ORIGIN_CIRCUIT(victim)->hs_circ_has_timed_out) && + victim->purpose == CIRCUIT_PURPOSE_S_CONNECT_REND) { + log_info(LD_CIRC,"Marking circ %u (state %d:%s, purpose %d) " + "as timed-out HS circ; relaunching rendezvous attempt.", + (unsigned)victim->n_circ_id, + victim->state, circuit_state_to_string(victim->state), + victim->purpose); + TO_ORIGIN_CIRCUIT(victim)->hs_circ_has_timed_out = 1; + rend_service_relaunch_rendezvous(TO_ORIGIN_CIRCUIT(victim)); + continue; + } + + if (victim->n_chan) + log_info(LD_CIRC, + "Abandoning circ %u %s:%u (state %d,%d:%s, purpose %d, " + "len %d)", TO_ORIGIN_CIRCUIT(victim)->global_identifier, + channel_get_canonical_remote_descr(victim->n_chan), + (unsigned)victim->n_circ_id, + TO_ORIGIN_CIRCUIT(victim)->has_opened, + victim->state, circuit_state_to_string(victim->state), + victim->purpose, + TO_ORIGIN_CIRCUIT(victim)->build_state->desired_path_len); + else + log_info(LD_CIRC, + "Abandoning circ %u %u (state %d,%d:%s, purpose %d, len %d)", + TO_ORIGIN_CIRCUIT(victim)->global_identifier, + (unsigned)victim->n_circ_id, + TO_ORIGIN_CIRCUIT(victim)->has_opened, + victim->state, + circuit_state_to_string(victim->state), victim->purpose, + TO_ORIGIN_CIRCUIT(victim)->build_state->desired_path_len); + + circuit_log_path(LOG_INFO,LD_CIRC,TO_ORIGIN_CIRCUIT(victim)); + if (victim->purpose == CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT) + circuit_mark_for_close(victim, END_CIRC_REASON_MEASUREMENT_EXPIRED); + else + circuit_mark_for_close(victim, END_CIRC_REASON_TIMEOUT); + + pathbias_count_timeout(TO_ORIGIN_CIRCUIT(victim)); + } +} + +/** Remove any elements in needed_ports that are handled by an + * open or in-progress circuit. + */ +void +circuit_remove_handled_ports(smartlist_t *needed_ports) +{ + int i; + uint16_t *port; + + for (i = 0; i < smartlist_len(needed_ports); ++i) { + port = smartlist_get(needed_ports, i); + tor_assert(*port); + if (circuit_stream_is_being_handled(NULL, *port, + MIN_CIRCUITS_HANDLING_STREAM)) { +// log_debug(LD_CIRC,"Port %d is already being handled; removing.", port); + smartlist_del(needed_ports, i--); + tor_free(port); + } else { + log_debug(LD_CIRC,"Port %d is not handled.", *port); + } + } +} + +/** Return 1 if at least min general-purpose non-internal circuits + * will have an acceptable exit node for exit stream conn if it + * is defined, else for "*:port". + * Else return 0. + */ +int +circuit_stream_is_being_handled(entry_connection_t *conn, + uint16_t port, int min) +{ + circuit_t *circ; + const node_t *exitnode; + int num=0; + time_t now = time(NULL); + int need_uptime = smartlist_contains_int_as_string( + get_options()->LongLivedPorts, + conn ? conn->socks_request->port : port); + + TOR_LIST_FOREACH(circ, circuit_get_global_list(), head) { + if (CIRCUIT_IS_ORIGIN(circ) && + !circ->marked_for_close && + circ->purpose == CIRCUIT_PURPOSE_C_GENERAL && + (!circ->timestamp_dirty || + circ->timestamp_dirty + get_options()->MaxCircuitDirtiness > now)) { + origin_circuit_t *origin_circ = TO_ORIGIN_CIRCUIT(circ); + cpath_build_state_t *build_state = origin_circ->build_state; + if (build_state->is_internal || build_state->onehop_tunnel) + continue; + if (origin_circ->unusable_for_new_conns) + continue; + + exitnode = build_state_get_exit_node(build_state); + if (exitnode && (!need_uptime || build_state->need_uptime)) { + int ok; + if (conn) { + ok = connection_ap_can_use_exit(conn, exitnode); + } else { + addr_policy_result_t r; + r = compare_tor_addr_to_node_policy(NULL, port, exitnode); + ok = r != ADDR_POLICY_REJECTED && r != ADDR_POLICY_PROBABLY_REJECTED; + } + if (ok) { + if (++num >= min) + return 1; + } + } + } + } + return 0; +} + +/** Don't keep more than this many unused open circuits around. */ +#define MAX_UNUSED_OPEN_CIRCUITS 14 + +/** Figure out how many circuits we have open that are clean. Make + * sure it's enough for all the upcoming behaviors we predict we'll have. + * But put an upper bound on the total number of circuits. + */ +static void +circuit_predict_and_launch_new(void) +{ + circuit_t *circ; + int num=0, num_internal=0, num_uptime_internal=0; + int hidserv_needs_uptime=0, hidserv_needs_capacity=1; + int port_needs_uptime=0, port_needs_capacity=1; + time_t now = time(NULL); + int flags = 0; + + /* First, count how many of each type of circuit we have already. */ + TOR_LIST_FOREACH(circ, circuit_get_global_list(), head) { + cpath_build_state_t *build_state; + origin_circuit_t *origin_circ; + if (!CIRCUIT_IS_ORIGIN(circ)) + continue; + if (circ->marked_for_close) + continue; /* don't mess with marked circs */ + if (circ->timestamp_dirty) + continue; /* only count clean circs */ + if (circ->purpose != CIRCUIT_PURPOSE_C_GENERAL) + continue; /* only pay attention to general-purpose circs */ + origin_circ = TO_ORIGIN_CIRCUIT(circ); + if (origin_circ->unusable_for_new_conns) + continue; + build_state = origin_circ->build_state; + if (build_state->onehop_tunnel) + continue; + num++; + if (build_state->is_internal) + num_internal++; + if (build_state->need_uptime && build_state->is_internal) + num_uptime_internal++; + } + + /* If that's enough, then stop now. */ + if (num >= MAX_UNUSED_OPEN_CIRCUITS) + return; /* we already have many, making more probably will hurt */ + + /* Second, see if we need any more exit circuits. */ + /* check if we know of a port that's been requested recently + * and no circuit is currently available that can handle it. */ + if (!circuit_all_predicted_ports_handled(now, &port_needs_uptime, + &port_needs_capacity)) { + if (port_needs_uptime) + flags |= CIRCLAUNCH_NEED_UPTIME; + if (port_needs_capacity) + flags |= CIRCLAUNCH_NEED_CAPACITY; + log_info(LD_CIRC, + "Have %d clean circs (%d internal), need another exit circ.", + num, num_internal); + circuit_launch(CIRCUIT_PURPOSE_C_GENERAL, flags); + return; + } + + /* Third, see if we need any more hidden service (server) circuits. */ + if (num_rend_services() && num_uptime_internal < 3) { + flags = (CIRCLAUNCH_NEED_CAPACITY | CIRCLAUNCH_NEED_UPTIME | + CIRCLAUNCH_IS_INTERNAL); + log_info(LD_CIRC, + "Have %d clean circs (%d internal), need another internal " + "circ for my hidden service.", + num, num_internal); + circuit_launch(CIRCUIT_PURPOSE_C_GENERAL, flags); + return; + } + + /* Fourth, see if we need any more hidden service (client) circuits. */ + if (rep_hist_get_predicted_internal(now, &hidserv_needs_uptime, + &hidserv_needs_capacity) && + ((num_uptime_internal<2 && hidserv_needs_uptime) || + num_internal<2)) { + if (hidserv_needs_uptime) + flags |= CIRCLAUNCH_NEED_UPTIME; + if (hidserv_needs_capacity) + flags |= CIRCLAUNCH_NEED_CAPACITY; + flags |= CIRCLAUNCH_IS_INTERNAL; + log_info(LD_CIRC, + "Have %d clean circs (%d uptime-internal, %d internal), need" + " another hidden service circ.", + num, num_uptime_internal, num_internal); + circuit_launch(CIRCUIT_PURPOSE_C_GENERAL, flags); + return; + } + + /* Finally, check to see if we still need more circuits to learn + * a good build timeout. But if we're close to our max number we + * want, don't do another -- we want to leave a few slots open so + * we can still build circuits preemptively as needed. */ + if (num < MAX_UNUSED_OPEN_CIRCUITS-2 && + ! circuit_build_times_disabled() && + circuit_build_times_needs_circuits_now(get_circuit_build_times())) { + flags = CIRCLAUNCH_NEED_CAPACITY; + log_info(LD_CIRC, + "Have %d clean circs need another buildtime test circ.", num); + circuit_launch(CIRCUIT_PURPOSE_C_GENERAL, flags); + return; + } +} + +/** Build a new test circuit every 5 minutes */ +#define TESTING_CIRCUIT_INTERVAL 300 + +/** This function is called once a second, if router_have_min_dir_info() is + * true. Its job is to make sure all services we offer have enough circuits + * available. Some services just want enough circuits for current tasks, + * whereas others want a minimum set of idle circuits hanging around. + */ +void +circuit_build_needed_circs(time_t now) +{ + static time_t time_to_new_circuit = 0; + const or_options_t *options = get_options(); + + /* launch a new circ for any pending streams that need one */ + connection_ap_attach_pending(); + + /* make sure any hidden services have enough intro points */ + rend_services_introduce(); + + if (time_to_new_circuit < now) { + circuit_reset_failure_count(1); + time_to_new_circuit = now + options->NewCircuitPeriod; + if (proxy_mode(get_options())) + addressmap_clean(now); + circuit_expire_old_circuits_clientside(); + +#if 0 /* disable for now, until predict-and-launch-new can cull leftovers */ + circ = circuit_get_youngest_clean_open(CIRCUIT_PURPOSE_C_GENERAL); + if (get_options()->RunTesting && + circ && + circ->timestamp_began.tv_sec + TESTING_CIRCUIT_INTERVAL < now) { + log_fn(LOG_INFO,"Creating a new testing circuit."); + circuit_launch(CIRCUIT_PURPOSE_C_GENERAL, 0); + } +#endif + } + if (!options->DisablePredictedCircuits) + circuit_predict_and_launch_new(); +} + +/** If the stream conn is a member of any of the linked + * lists of circ, then remove it from the list. + */ +void +circuit_detach_stream(circuit_t *circ, edge_connection_t *conn) +{ + edge_connection_t *prevconn; + + tor_assert(circ); + tor_assert(conn); + + if (conn->base_.type == CONN_TYPE_AP) { + entry_connection_t *entry_conn = EDGE_TO_ENTRY_CONN(conn); + entry_conn->may_use_optimistic_data = 0; + } + conn->cpath_layer = NULL; /* don't keep a stale pointer */ + conn->on_circuit = NULL; + + if (CIRCUIT_IS_ORIGIN(circ)) { + origin_circuit_t *origin_circ = TO_ORIGIN_CIRCUIT(circ); + if (conn == origin_circ->p_streams) { + origin_circ->p_streams = conn->next_stream; + return; + } + + for (prevconn = origin_circ->p_streams; + prevconn && prevconn->next_stream && prevconn->next_stream != conn; + prevconn = prevconn->next_stream) + ; + if (prevconn && prevconn->next_stream) { + prevconn->next_stream = conn->next_stream; + return; + } + } else { + or_circuit_t *or_circ = TO_OR_CIRCUIT(circ); + if (conn == or_circ->n_streams) { + or_circ->n_streams = conn->next_stream; + return; + } + if (conn == or_circ->resolving_streams) { + or_circ->resolving_streams = conn->next_stream; + return; + } + + for (prevconn = or_circ->n_streams; + prevconn && prevconn->next_stream && prevconn->next_stream != conn; + prevconn = prevconn->next_stream) + ; + if (prevconn && prevconn->next_stream) { + prevconn->next_stream = conn->next_stream; + return; + } + + for (prevconn = or_circ->resolving_streams; + prevconn && prevconn->next_stream && prevconn->next_stream != conn; + prevconn = prevconn->next_stream) + ; + if (prevconn && prevconn->next_stream) { + prevconn->next_stream = conn->next_stream; + return; + } + } + + log_warn(LD_BUG,"Edge connection not in circuit's list."); + /* Don't give an error here; it's harmless. */ + tor_fragile_assert(); +} + +/** If we haven't yet decided on a good timeout value for circuit + * building, we close idles circuits aggressively so we can get more + * data points. */ +#define IDLE_TIMEOUT_WHILE_LEARNING (10*60) + +/** Find each circuit that has been unused for too long, or dirty + * for too long and has no streams on it: mark it for close. + */ +static void +circuit_expire_old_circuits_clientside(void) +{ + circuit_t *circ; + struct timeval cutoff, now; + + tor_gettimeofday(&now); + cutoff = now; + + if (! circuit_build_times_disabled() && + circuit_build_times_needs_circuits(get_circuit_build_times())) { + /* Circuits should be shorter lived if we need more of them + * for learning a good build timeout */ + cutoff.tv_sec -= IDLE_TIMEOUT_WHILE_LEARNING; + } else { + cutoff.tv_sec -= get_options()->CircuitIdleTimeout; + } + + TOR_LIST_FOREACH(circ, circuit_get_global_list(), head) { + if (circ->marked_for_close || !CIRCUIT_IS_ORIGIN(circ)) + continue; + /* If the circuit has been dirty for too long, and there are no streams + * on it, mark it for close. + */ + if (circ->timestamp_dirty && + circ->timestamp_dirty + get_options()->MaxCircuitDirtiness < + now.tv_sec && + !TO_ORIGIN_CIRCUIT(circ)->p_streams /* nothing attached */ ) { + log_debug(LD_CIRC, "Closing n_circ_id %u (dirty %ld sec ago, " + "purpose %d)", + (unsigned)circ->n_circ_id, + (long)(now.tv_sec - circ->timestamp_dirty), + circ->purpose); + /* Don't do this magic for testing circuits. Their death is governed + * by circuit_expire_building */ + if (circ->purpose != CIRCUIT_PURPOSE_PATH_BIAS_TESTING) + circuit_mark_for_close(circ, END_CIRC_REASON_FINISHED); + } else if (!circ->timestamp_dirty && circ->state == CIRCUIT_STATE_OPEN) { + if (timercmp(&circ->timestamp_began, &cutoff, <)) { + if (circ->purpose == CIRCUIT_PURPOSE_C_GENERAL || + circ->purpose == CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT || + circ->purpose == CIRCUIT_PURPOSE_S_ESTABLISH_INTRO || + circ->purpose == CIRCUIT_PURPOSE_TESTING || + (circ->purpose >= CIRCUIT_PURPOSE_C_INTRODUCING && + circ->purpose <= CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED) || + circ->purpose == CIRCUIT_PURPOSE_S_CONNECT_REND) { + log_debug(LD_CIRC, + "Closing circuit that has been unused for %ld msec.", + tv_mdiff(&circ->timestamp_began, &now)); + circuit_mark_for_close(circ, END_CIRC_REASON_FINISHED); + } else if (!TO_ORIGIN_CIRCUIT(circ)->is_ancient) { + /* Server-side rend joined circuits can end up really old, because + * they are reused by clients for longer than normal. The client + * controls their lifespan. (They never become dirty, because + * connection_exit_begin_conn() never marks anything as dirty.) + * Similarly, server-side intro circuits last a long time. */ + if (circ->purpose != CIRCUIT_PURPOSE_S_REND_JOINED && + circ->purpose != CIRCUIT_PURPOSE_S_INTRO) { + log_notice(LD_CIRC, + "Ancient non-dirty circuit %d is still around after " + "%ld milliseconds. Purpose: %d (%s)", + TO_ORIGIN_CIRCUIT(circ)->global_identifier, + tv_mdiff(&circ->timestamp_began, &now), + circ->purpose, + circuit_purpose_to_string(circ->purpose)); + TO_ORIGIN_CIRCUIT(circ)->is_ancient = 1; + } + } + } + } + } +} + +/** How long do we wait before killing circuits with the properties + * described below? + * + * Probably we could choose a number here as low as 5 to 10 seconds, + * since these circs are used for begindir, and a) generally you either + * ask another begindir question right after or you don't for a long time, + * b) clients at least through 0.2.1.x choose from the whole set of + * directory mirrors at each choice, and c) re-establishing a one-hop + * circuit via create-fast is a light operation assuming the TLS conn is + * still there. + * + * I expect "b" to go away one day when we move to using directory + * guards, but I think "a" and "c" are good enough reasons that a low + * number is safe even then. + */ +#define IDLE_ONE_HOP_CIRC_TIMEOUT 60 + +/** Find each non-origin circuit that has been unused for too long, + * has no streams on it, used a create_fast, and ends here: mark it + * for close. + */ +void +circuit_expire_old_circuits_serverside(time_t now) +{ + circuit_t *circ; + or_circuit_t *or_circ; + time_t cutoff = now - IDLE_ONE_HOP_CIRC_TIMEOUT; + + TOR_LIST_FOREACH(circ, circuit_get_global_list(), head) { + if (circ->marked_for_close || CIRCUIT_IS_ORIGIN(circ)) + continue; + or_circ = TO_OR_CIRCUIT(circ); + /* If the circuit has been idle for too long, and there are no streams + * on it, and it ends here, and it used a create_fast, mark it for close. + */ + if (or_circ->is_first_hop && !circ->n_chan && + !or_circ->n_streams && !or_circ->resolving_streams && + or_circ->p_chan && + channel_when_last_xmit(or_circ->p_chan) <= cutoff) { + log_info(LD_CIRC, "Closing circ_id %u (empty %d secs ago)", + (unsigned)or_circ->p_circ_id, + (int)(now - channel_when_last_xmit(or_circ->p_chan))); + circuit_mark_for_close(circ, END_CIRC_REASON_FINISHED); + } + } +} + +/** Number of testing circuits we want open before testing our bandwidth. */ +#define NUM_PARALLEL_TESTING_CIRCS 4 + +/** True iff we've ever had enough testing circuits open to test our + * bandwidth. */ +static int have_performed_bandwidth_test = 0; + +/** Reset have_performed_bandwidth_test, so we'll start building + * testing circuits again so we can exercise our bandwidth. */ +void +reset_bandwidth_test(void) +{ + have_performed_bandwidth_test = 0; +} + +/** Return 1 if we've already exercised our bandwidth, or if we + * have fewer than NUM_PARALLEL_TESTING_CIRCS testing circuits + * established or on the way. Else return 0. + */ +int +circuit_enough_testing_circs(void) +{ + circuit_t *circ; + int num = 0; + + if (have_performed_bandwidth_test) + return 1; + + TOR_LIST_FOREACH(circ, circuit_get_global_list(), head) { + if (!circ->marked_for_close && CIRCUIT_IS_ORIGIN(circ) && + circ->purpose == CIRCUIT_PURPOSE_TESTING && + circ->state == CIRCUIT_STATE_OPEN) + num++; + } + return num >= NUM_PARALLEL_TESTING_CIRCS; +} + +/** A testing circuit has completed. Take whatever stats we want. + * Noticing reachability is taken care of in onionskin_answer(), + * so there's no need to record anything here. But if we still want + * to do the bandwidth test, and we now have enough testing circuits + * open, do it. + */ +static void +circuit_testing_opened(origin_circuit_t *circ) +{ + if (have_performed_bandwidth_test || + !check_whether_orport_reachable()) { + /* either we've already done everything we want with testing circuits, + * or this testing circuit became open due to a fluke, e.g. we picked + * a last hop where we already had the connection open due to an + * outgoing local circuit. */ + circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_AT_ORIGIN); + } else if (circuit_enough_testing_circs()) { + router_perform_bandwidth_test(NUM_PARALLEL_TESTING_CIRCS, time(NULL)); + have_performed_bandwidth_test = 1; + } else + consider_testing_reachability(1, 0); +} + +/** A testing circuit has failed to build. Take whatever stats we want. */ +static void +circuit_testing_failed(origin_circuit_t *circ, int at_last_hop) +{ + if (server_mode(get_options()) && check_whether_orport_reachable()) + return; + + log_info(LD_GENERAL, + "Our testing circuit (to see if your ORPort is reachable) " + "has failed. I'll try again later."); + + /* These aren't used yet. */ + (void)circ; + (void)at_last_hop; +} + +/** The circuit circ has just become open. Take the next + * step: for rendezvous circuits, we pass circ to the appropriate + * function in rendclient or rendservice. For general circuits, we + * call connection_ap_attach_pending, which looks for pending streams + * that could use circ. + */ +void +circuit_has_opened(origin_circuit_t *circ) +{ + control_event_circuit_status(circ, CIRC_EVENT_BUILT, 0); + + /* Remember that this circuit has finished building. Now if we start + * it building again later (e.g. by extending it), we will know not + * to consider its build time. */ + circ->has_opened = 1; + + switch (TO_CIRCUIT(circ)->purpose) { + case CIRCUIT_PURPOSE_C_ESTABLISH_REND: + rend_client_rendcirc_has_opened(circ); + /* Start building an intro circ if we don't have one yet. */ + connection_ap_attach_pending(); + /* This isn't a call to circuit_try_attaching_streams because a + * circuit in _C_ESTABLISH_REND state isn't connected to its + * hidden service yet, thus we can't attach streams to it yet, + * thus circuit_try_attaching_streams would always clear the + * circuit's isolation state. circuit_try_attaching_streams is + * called later, when the rend circ enters _C_REND_JOINED + * state. */ + break; + case CIRCUIT_PURPOSE_C_INTRODUCING: + rend_client_introcirc_has_opened(circ); + break; + case CIRCUIT_PURPOSE_C_GENERAL: + /* Tell any AP connections that have been waiting for a new + * circuit that one is ready. */ + circuit_try_attaching_streams(circ); + break; + case CIRCUIT_PURPOSE_S_ESTABLISH_INTRO: + /* at Bob, waiting for introductions */ + rend_service_intro_has_opened(circ); + break; + case CIRCUIT_PURPOSE_S_CONNECT_REND: + /* at Bob, connecting to rend point */ + rend_service_rendezvous_has_opened(circ); + break; + case CIRCUIT_PURPOSE_TESTING: + circuit_testing_opened(circ); + break; + /* default: + * This won't happen in normal operation, but might happen if the + * controller did it. Just let it slide. */ + } +} + +/** If the stream-isolation state of circ can be cleared, clear + * it. Return non-zero iff circ's isolation state was cleared. */ +static int +circuit_try_clearing_isolation_state(origin_circuit_t *circ) +{ + if (/* The circuit may have become non-open if it was cannibalized.*/ + circ->base_.state == CIRCUIT_STATE_OPEN && + /* If !isolation_values_set, there is nothing to clear. */ + circ->isolation_values_set && + /* It's not legal to clear a circuit's isolation info if it's ever had + * streams attached */ + !circ->isolation_any_streams_attached) { + /* If we have any isolation information set on this circuit, and + * we didn't manage to attach any streams to it, then we can + * and should clear it and try again. */ + circuit_clear_isolation(circ); + return 1; + } else { + return 0; + } +} + +/** Called when a circuit becomes ready for streams to be attached to + * it. */ +void +circuit_try_attaching_streams(origin_circuit_t *circ) +{ + /* Attach streams to this circuit if we can. */ + connection_ap_attach_pending(); + + /* The call to circuit_try_clearing_isolation_state here will do + * nothing and return 0 if we didn't attach any streams to circ + * above. */ + if (circuit_try_clearing_isolation_state(circ)) { + /* Maybe *now* we can attach some streams to this circuit. */ + connection_ap_attach_pending(); + } +} + +/** Called whenever a circuit could not be successfully built. + */ +void +circuit_build_failed(origin_circuit_t *circ) +{ + channel_t *n_chan = NULL; + /* we should examine circ and see if it failed because of + * the last hop or an earlier hop. then use this info below. + */ + int failed_at_last_hop = 0; + /* If the last hop isn't open, and the second-to-last is, we failed + * at the last hop. */ + if (circ->cpath && + circ->cpath->prev->state != CPATH_STATE_OPEN && + circ->cpath->prev->prev->state == CPATH_STATE_OPEN) { + failed_at_last_hop = 1; + } + if (circ->cpath && + circ->cpath->state != CPATH_STATE_OPEN && + ! circ->base_.received_destroy) { + /* We failed at the first hop for some reason other than a DESTROY cell. + * If there's an OR connection to blame, blame it. Also, avoid this relay + * for a while, and fail any one-hop directory fetches destined for it. */ + const char *n_chan_id = circ->cpath->extend_info->identity_digest; + int already_marked = 0; + if (circ->base_.n_chan) { + n_chan = circ->base_.n_chan; + + if (n_chan->is_bad_for_new_circs) { + /* We only want to blame this router when a fresh healthy + * connection fails. So don't mark this router as newly failed, + * since maybe this was just an old circuit attempt that's + * finally timing out now. Also, there's no need to blow away + * circuits/streams/etc, since the failure of an unhealthy conn + * doesn't tell us much about whether a healthy conn would + * succeed. */ + already_marked = 1; + } + log_info(LD_OR, + "Our circuit failed to get a response from the first hop " + "(%s). I'm going to try to rotate to a better connection.", + channel_get_canonical_remote_descr(n_chan)); + n_chan->is_bad_for_new_circs = 1; + } else { + log_info(LD_OR, + "Our circuit died before the first hop with no connection"); + } + if (n_chan_id && !already_marked) { + entry_guard_register_connect_status(n_chan_id, 0, 1, time(NULL)); + /* if there are any one-hop streams waiting on this circuit, fail + * them now so they can retry elsewhere. */ + connection_ap_fail_onehop(n_chan_id, circ->build_state); + } + } + + switch (circ->base_.purpose) { + case CIRCUIT_PURPOSE_C_GENERAL: + /* If we never built the circuit, note it as a failure. */ + circuit_increment_failure_count(); + if (failed_at_last_hop) { + /* Make sure any streams that demand our last hop as their exit + * know that it's unlikely to happen. */ + circuit_discard_optional_exit_enclaves(circ->cpath->prev->extend_info); + } + break; + case CIRCUIT_PURPOSE_TESTING: + circuit_testing_failed(circ, failed_at_last_hop); + break; + case CIRCUIT_PURPOSE_S_ESTABLISH_INTRO: + /* at Bob, waiting for introductions */ + if (circ->base_.state != CIRCUIT_STATE_OPEN) { + circuit_increment_failure_count(); + } + /* no need to care here, because bob will rebuild intro + * points periodically. */ + break; + case CIRCUIT_PURPOSE_C_INTRODUCING: + /* at Alice, connecting to intro point */ + /* Don't increment failure count, since Bob may have picked + * the introduction point maliciously */ + /* Alice will pick a new intro point when this one dies, if + * the stream in question still cares. No need to act here. */ + break; + case CIRCUIT_PURPOSE_C_ESTABLISH_REND: + /* at Alice, waiting for Bob */ + circuit_increment_failure_count(); + /* Alice will pick a new rend point when this one dies, if + * the stream in question still cares. No need to act here. */ + break; + case CIRCUIT_PURPOSE_S_CONNECT_REND: + /* at Bob, connecting to rend point */ + /* Don't increment failure count, since Alice may have picked + * the rendezvous point maliciously */ + log_info(LD_REND, + "Couldn't connect to Alice's chosen rend point %s " + "(%s hop failed).", + escaped(build_state_get_exit_nickname(circ->build_state)), + failed_at_last_hop?"last":"non-last"); + rend_service_relaunch_rendezvous(circ); + break; + /* default: + * This won't happen in normal operation, but might happen if the + * controller did it. Just let it slide. */ + } +} + +/** Number of consecutive failures so far; should only be touched by + * circuit_launch_new and circuit_*_failure_count. + */ +static int n_circuit_failures = 0; +/** Before the last time we called circuit_reset_failure_count(), were + * there a lot of failures? */ +static int did_circs_fail_last_period = 0; + +/** Don't retry launching a new circuit if we try this many times with no + * success. */ +#define MAX_CIRCUIT_FAILURES 5 + +/** Launch a new circuit; see circuit_launch_by_extend_info() for + * details on arguments. */ +origin_circuit_t * +circuit_launch(uint8_t purpose, int flags) +{ + return circuit_launch_by_extend_info(purpose, NULL, flags); +} + +/** Launch a new circuit with purpose purpose and exit node + * extend_info (or NULL to select a random exit node). If flags + * contains CIRCLAUNCH_NEED_UPTIME, choose among routers with high uptime. If + * CIRCLAUNCH_NEED_CAPACITY is set, choose among routers with high bandwidth. + * If CIRCLAUNCH_IS_INTERNAL is true, the last hop need not be an exit node. + * If CIRCLAUNCH_ONEHOP_TUNNEL is set, the circuit will have only one hop. + * Return the newly allocated circuit on success, or NULL on failure. */ +origin_circuit_t * +circuit_launch_by_extend_info(uint8_t purpose, + extend_info_t *extend_info, + int flags) +{ + origin_circuit_t *circ; + int onehop_tunnel = (flags & CIRCLAUNCH_ONEHOP_TUNNEL) != 0; + + if (!onehop_tunnel && !router_have_minimum_dir_info()) { + log_debug(LD_CIRC,"Haven't fetched enough directory info yet; canceling " + "circuit launch."); + return NULL; + } + + if ((extend_info || purpose != CIRCUIT_PURPOSE_C_GENERAL) && + purpose != CIRCUIT_PURPOSE_TESTING && !onehop_tunnel) { + /* see if there are appropriate circs available to cannibalize. */ + /* XXX if we're planning to add a hop, perhaps we want to look for + * internal circs rather than exit circs? -RD */ + circ = circuit_find_to_cannibalize(purpose, extend_info, flags); + if (circ) { + uint8_t old_purpose = circ->base_.purpose; + struct timeval old_timestamp_began; + + log_info(LD_CIRC,"Cannibalizing circ '%s' for purpose %d (%s)", + build_state_get_exit_nickname(circ->build_state), purpose, + circuit_purpose_to_string(purpose)); + + if ((purpose == CIRCUIT_PURPOSE_S_CONNECT_REND || + purpose == CIRCUIT_PURPOSE_C_INTRODUCING) && + circ->path_state == PATH_STATE_BUILD_SUCCEEDED) { + /* Path bias: Cannibalized rends pre-emptively count as a + * successfully built but unused closed circuit. We don't + * wait until the extend (or the close) because the rend + * point could be malicious. + * + * Same deal goes for client side introductions. Clients + * can be manipulated to connect repeatedly to them + * (especially web clients). + * + * If we decide to probe the initial portion of these circs, + * (up to the adversary's final hop), we need to remove this, + * or somehow mark the circuit with a special path state. + */ + + /* This must be called before the purpose change */ + pathbias_check_close(circ, END_CIRC_REASON_FINISHED); + } + + circuit_change_purpose(TO_CIRCUIT(circ), purpose); + /* Reset the start date of this circ, else expire_building + * will see it and think it's been trying to build since it + * began. + * + * Technically, the code should reset this when the + * create cell is finally sent, but we're close enough + * here. */ + tor_gettimeofday(&circ->base_.timestamp_began); + + control_event_circuit_cannibalized(circ, old_purpose, + &old_timestamp_began); + + switch (purpose) { + case CIRCUIT_PURPOSE_C_ESTABLISH_REND: + case CIRCUIT_PURPOSE_S_ESTABLISH_INTRO: + /* it's ready right now */ + break; + case CIRCUIT_PURPOSE_C_INTRODUCING: + case CIRCUIT_PURPOSE_S_CONNECT_REND: + case CIRCUIT_PURPOSE_C_GENERAL: + /* need to add a new hop */ + tor_assert(extend_info); + if (circuit_extend_to_new_exit(circ, extend_info) < 0) + return NULL; + break; + default: + log_warn(LD_BUG, + "unexpected purpose %d when cannibalizing a circ.", + purpose); + tor_fragile_assert(); + return NULL; + } + return circ; + } + } + + if (did_circs_fail_last_period && + n_circuit_failures > MAX_CIRCUIT_FAILURES) { + /* too many failed circs in a row. don't try. */ +// log_fn(LOG_INFO,"%d failures so far, not trying.",n_circuit_failures); + return NULL; + } + + /* try a circ. if it fails, circuit_mark_for_close will increment + * n_circuit_failures */ + return circuit_establish_circuit(purpose, extend_info, flags); +} + +/** Record another failure at opening a general circuit. When we have + * too many, we'll stop trying for the remainder of this minute. + */ +static void +circuit_increment_failure_count(void) +{ + ++n_circuit_failures; + log_debug(LD_CIRC,"n_circuit_failures now %d.",n_circuit_failures); +} + +/** Reset the failure count for opening general circuits. This means + * we will try MAX_CIRCUIT_FAILURES times more (if necessary) before + * stopping again. + */ +void +circuit_reset_failure_count(int timeout) +{ + if (timeout && n_circuit_failures > MAX_CIRCUIT_FAILURES) + did_circs_fail_last_period = 1; + else + did_circs_fail_last_period = 0; + n_circuit_failures = 0; +} + +/** Find an open circ that we're happy to use for conn and return 1. If + * there isn't one, and there isn't one on the way, launch one and return + * 0. If it will never work, return -1. + * + * Write the found or in-progress or launched circ into *circp. + */ +static int +circuit_get_open_circ_or_launch(entry_connection_t *conn, + uint8_t desired_circuit_purpose, + origin_circuit_t **circp) +{ + origin_circuit_t *circ; + int check_exit_policy; + int need_uptime, need_internal; + int want_onehop; + const or_options_t *options = get_options(); + + tor_assert(conn); + tor_assert(circp); + tor_assert(ENTRY_TO_CONN(conn)->state == AP_CONN_STATE_CIRCUIT_WAIT); + check_exit_policy = + conn->socks_request->command == SOCKS_COMMAND_CONNECT && + !conn->use_begindir && + !connection_edge_is_rendezvous_stream(ENTRY_TO_EDGE_CONN(conn)); + want_onehop = conn->want_onehop; + + need_uptime = !conn->want_onehop && !conn->use_begindir && + smartlist_contains_int_as_string(options->LongLivedPorts, + conn->socks_request->port); + + if (desired_circuit_purpose != CIRCUIT_PURPOSE_C_GENERAL) + need_internal = 1; + else if (conn->use_begindir || conn->want_onehop) + need_internal = 1; + else + need_internal = 0; + + circ = circuit_get_best(conn, 1, desired_circuit_purpose, + need_uptime, need_internal); + + if (circ) { + *circp = circ; + return 1; /* we're happy */ + } + + if (!want_onehop && !router_have_minimum_dir_info()) { + if (!connection_get_by_type(CONN_TYPE_DIR)) { + int severity = LOG_NOTICE; + /* FFFF if this is a tunneled directory fetch, don't yell + * as loudly. the user doesn't even know it's happening. */ + if (entry_list_is_constrained(options) && + entries_known_but_down(options)) { + log_fn(severity, LD_APP|LD_DIR, + "Application request when we haven't used client functionality " + "lately. Optimistically trying known %s again.", + options->UseBridges ? "bridges" : "entrynodes"); + entries_retry_all(options); + } else if (!options->UseBridges || any_bridge_descriptors_known()) { + log_fn(severity, LD_APP|LD_DIR, + "Application request when we haven't used client functionality " + "lately. Optimistically trying directory fetches again."); + routerlist_retry_directory_downloads(time(NULL)); + } + } + /* the stream will be dealt with when router_have_minimum_dir_info becomes + * 1, or when all directory attempts fail and directory_all_unreachable() + * kills it. + */ + return 0; + } + + /* Do we need to check exit policy? */ + if (check_exit_policy) { + if (!conn->chosen_exit_name) { + struct in_addr in; + tor_addr_t addr, *addrp=NULL; + if (tor_inet_aton(conn->socks_request->address, &in)) { + tor_addr_from_in(&addr, &in); + addrp = &addr; + } + if (router_exit_policy_all_nodes_reject(addrp, + conn->socks_request->port, + need_uptime)) { + log_notice(LD_APP, + "No Tor server allows exit to %s:%d. Rejecting.", + safe_str_client(conn->socks_request->address), + conn->socks_request->port); + return -1; + } + } else { + /* XXXX024 Duplicates checks in connection_ap_handshake_attach_circuit: + * refactor into a single function? */ + const node_t *node = node_get_by_nickname(conn->chosen_exit_name, 1); + int opt = conn->chosen_exit_optional; + if (node && !connection_ap_can_use_exit(conn, node)) { + log_fn(opt ? LOG_INFO : LOG_WARN, LD_APP, + "Requested exit point '%s' is excluded or " + "would refuse request. %s.", + conn->chosen_exit_name, opt ? "Trying others" : "Closing"); + if (opt) { + conn->chosen_exit_optional = 0; + tor_free(conn->chosen_exit_name); + /* Try again. */ + return circuit_get_open_circ_or_launch(conn, + desired_circuit_purpose, + circp); + } + return -1; + } + } + } + + /* is one already on the way? */ + circ = circuit_get_best(conn, 0, desired_circuit_purpose, + need_uptime, need_internal); + if (circ) + log_debug(LD_CIRC, "one on the way!"); + if (!circ) { + extend_info_t *extend_info=NULL; + uint8_t new_circ_purpose; + const int n_pending = count_pending_general_client_circuits(); + + if (n_pending >= options->MaxClientCircuitsPending) { + static ratelim_t delay_limit = RATELIM_INIT(10*60); + char *m; + if ((m = rate_limit_log(&delay_limit, approx_time()))) { + log_notice(LD_APP, "We'd like to launch a circuit to handle a " + "connection, but we already have %d general-purpose client " + "circuits pending. Waiting until some finish.%s", + n_pending, m); + tor_free(m); + } + return 0; + } + + if (desired_circuit_purpose == CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT) { + /* need to pick an intro point */ + rend_data_t *rend_data = ENTRY_TO_EDGE_CONN(conn)->rend_data; + tor_assert(rend_data); + extend_info = rend_client_get_random_intro(rend_data); + if (!extend_info) { + log_info(LD_REND, + "No intro points for '%s': re-fetching service descriptor.", + safe_str_client(rend_data->onion_address)); + rend_client_refetch_v2_renddesc(rend_data); + ENTRY_TO_CONN(conn)->state = AP_CONN_STATE_RENDDESC_WAIT; + return 0; + } + log_info(LD_REND,"Chose %s as intro point for '%s'.", + extend_info_describe(extend_info), + safe_str_client(rend_data->onion_address)); + } + + /* If we have specified a particular exit node for our + * connection, then be sure to open a circuit to that exit node. + */ + if (desired_circuit_purpose == CIRCUIT_PURPOSE_C_GENERAL) { + if (conn->chosen_exit_name) { + const node_t *r; + int opt = conn->chosen_exit_optional; + r = node_get_by_nickname(conn->chosen_exit_name, 1); + if (r && node_has_descriptor(r)) { + /* We might want to connect to an IPv6 bridge for loading + descriptors so we use the preferred address rather than + the primary. */ + extend_info = extend_info_from_node(r, conn->want_onehop ? 1 : 0); + } else { + log_debug(LD_DIR, "considering %d, %s", + want_onehop, conn->chosen_exit_name); + if (want_onehop && conn->chosen_exit_name[0] == '$') { + /* We're asking for a one-hop circuit to a router that + * we don't have a routerinfo about. Make up an extend_info. */ + char digest[DIGEST_LEN]; + char *hexdigest = conn->chosen_exit_name+1; + tor_addr_t addr; + if (strlen(hexdigest) < HEX_DIGEST_LEN || + base16_decode(digest,DIGEST_LEN,hexdigest,HEX_DIGEST_LEN)<0) { + log_info(LD_DIR, "Broken exit digest on tunnel conn. Closing."); + return -1; + } + if (tor_addr_parse(&addr, conn->socks_request->address) < 0) { + log_info(LD_DIR, "Broken address %s on tunnel conn. Closing.", + escaped_safe_str_client(conn->socks_request->address)); + return -1; + } + extend_info = extend_info_new(conn->chosen_exit_name+1, + digest, NULL, NULL, &addr, + conn->socks_request->port); + } else { + /* We will need an onion key for the router, and we + * don't have one. Refuse or relax requirements. */ + log_fn(opt ? LOG_INFO : LOG_WARN, LD_APP, + "Requested exit point '%s' is not known. %s.", + conn->chosen_exit_name, opt ? "Trying others" : "Closing"); + if (opt) { + conn->chosen_exit_optional = 0; + tor_free(conn->chosen_exit_name); + /* Try again with no requested exit */ + return circuit_get_open_circ_or_launch(conn, + desired_circuit_purpose, + circp); + } + return -1; + } + } + } + } + + if (desired_circuit_purpose == CIRCUIT_PURPOSE_C_REND_JOINED) + new_circ_purpose = CIRCUIT_PURPOSE_C_ESTABLISH_REND; + else if (desired_circuit_purpose == CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT) + new_circ_purpose = CIRCUIT_PURPOSE_C_INTRODUCING; + else + new_circ_purpose = desired_circuit_purpose; + + if (options->Tor2webMode && + (new_circ_purpose == CIRCUIT_PURPOSE_C_ESTABLISH_REND || + new_circ_purpose == CIRCUIT_PURPOSE_C_INTRODUCING)) { + want_onehop = 1; + } + + { + int flags = CIRCLAUNCH_NEED_CAPACITY; + if (want_onehop) flags |= CIRCLAUNCH_ONEHOP_TUNNEL; + if (need_uptime) flags |= CIRCLAUNCH_NEED_UPTIME; + if (need_internal) flags |= CIRCLAUNCH_IS_INTERNAL; + circ = circuit_launch_by_extend_info(new_circ_purpose, extend_info, + flags); + } + + extend_info_free(extend_info); + + if (desired_circuit_purpose == CIRCUIT_PURPOSE_C_GENERAL) { + /* We just caused a circuit to get built because of this stream. + * If this stream has caused a _lot_ of circuits to be built, that's + * a bad sign: we should tell the user. */ + if (conn->num_circuits_launched < NUM_CIRCUITS_LAUNCHED_THRESHOLD && + ++conn->num_circuits_launched == NUM_CIRCUITS_LAUNCHED_THRESHOLD) + log_info(LD_CIRC, "The application request to %s:%d has launched " + "%d circuits without finding one it likes.", + escaped_safe_str_client(conn->socks_request->address), + conn->socks_request->port, + conn->num_circuits_launched); + } else { + /* help predict this next time */ + rep_hist_note_used_internal(time(NULL), need_uptime, 1); + if (circ) { + /* write the service_id into circ */ + circ->rend_data = rend_data_dup(ENTRY_TO_EDGE_CONN(conn)->rend_data); + if (circ->base_.purpose == CIRCUIT_PURPOSE_C_ESTABLISH_REND && + circ->base_.state == CIRCUIT_STATE_OPEN) + rend_client_rendcirc_has_opened(circ); + } + } + } /* endif (!circ) */ + if (circ) { + /* Mark the circuit with the isolation fields for this connection. + * When the circuit arrives, we'll clear these flags: this is + * just some internal bookkeeping to make sure that we have + * launched enough circuits. + */ + connection_edge_update_circuit_isolation(conn, circ, 0); + } else { + log_info(LD_APP, + "No safe circuit (purpose %d) ready for edge " + "connection; delaying.", + desired_circuit_purpose); + } + *circp = circ; + return 0; +} + +/** Return true iff crypt_path is one of the crypt_paths for + * circ. */ +static int +cpath_is_on_circuit(origin_circuit_t *circ, crypt_path_t *crypt_path) +{ + crypt_path_t *cpath, *cpath_next = NULL; + for (cpath = circ->cpath; cpath_next != circ->cpath; cpath = cpath_next) { + cpath_next = cpath->next; + if (crypt_path == cpath) + return 1; + } + return 0; +} + +/** Return true iff client-side optimistic data is supported. */ +static int +optimistic_data_enabled(void) +{ + const or_options_t *options = get_options(); + if (options->OptimisticData < 0) { + /* XXX023 consider having auto default to 1 rather than 0 before + * the 0.2.3 branch goes stable. See bug 3617. -RD */ + const int32_t enabled = + networkstatus_get_param(NULL, "UseOptimisticData", 0, 0, 1); + return (int)enabled; + } + return options->OptimisticData; +} + +/** Attach the AP stream apconn to circ's linked list of + * p_streams. Also set apconn's cpath_layer to cpath, or to the last + * hop in circ's cpath if cpath is NULL. + */ +static void +link_apconn_to_circ(entry_connection_t *apconn, origin_circuit_t *circ, + crypt_path_t *cpath) +{ + const node_t *exitnode; + + /* add it into the linked list of streams on this circuit */ + log_debug(LD_APP|LD_CIRC, "attaching new conn to circ. n_circ_id %u.", + (unsigned)circ->base_.n_circ_id); + /* reset it, so we can measure circ timeouts */ + ENTRY_TO_CONN(apconn)->timestamp_lastread = time(NULL); + ENTRY_TO_EDGE_CONN(apconn)->next_stream = circ->p_streams; + ENTRY_TO_EDGE_CONN(apconn)->on_circuit = TO_CIRCUIT(circ); + /* assert_connection_ok(conn, time(NULL)); */ + circ->p_streams = ENTRY_TO_EDGE_CONN(apconn); + + if (connection_edge_is_rendezvous_stream(ENTRY_TO_EDGE_CONN(apconn))) { + /* We are attaching a stream to a rendezvous circuit. That means + * that an attempt to connect to a hidden service just + * succeeded. Tell rendclient.c. */ + rend_client_note_connection_attempt_ended( + ENTRY_TO_EDGE_CONN(apconn)->rend_data->onion_address); + } + + if (cpath) { /* we were given one; use it */ + tor_assert(cpath_is_on_circuit(circ, cpath)); + } else { + /* use the last hop in the circuit */ + tor_assert(circ->cpath); + tor_assert(circ->cpath->prev); + tor_assert(circ->cpath->prev->state == CPATH_STATE_OPEN); + cpath = circ->cpath->prev; + } + ENTRY_TO_EDGE_CONN(apconn)->cpath_layer = cpath; + + circ->isolation_any_streams_attached = 1; + connection_edge_update_circuit_isolation(apconn, circ, 0); + + /* See if we can use optimistic data on this circuit */ + if (cpath->extend_info && + (exitnode = node_get_by_id(cpath->extend_info->identity_digest)) && + exitnode->rs) { + /* Okay; we know what exit node this is. */ + if (optimistic_data_enabled() && + circ->base_.purpose == CIRCUIT_PURPOSE_C_GENERAL && + exitnode->rs->version_supports_optimistic_data) + apconn->may_use_optimistic_data = 1; + else + apconn->may_use_optimistic_data = 0; + log_info(LD_APP, "Looks like completed circuit to %s %s allow " + "optimistic data for connection to %s", + safe_str_client(node_describe(exitnode)), + apconn->may_use_optimistic_data ? "does" : "doesn't", + safe_str_client(apconn->socks_request->address)); + } +} + +/** Return true iff address is matched by one of the entries in + * TrackHostExits. */ +int +hostname_in_track_host_exits(const or_options_t *options, const char *address) +{ + if (!options->TrackHostExits) + return 0; + SMARTLIST_FOREACH_BEGIN(options->TrackHostExits, const char *, cp) { + if (cp[0] == '.') { /* match end */ + if (cp[1] == '\0' || + !strcasecmpend(address, cp) || + !strcasecmp(address, &cp[1])) + return 1; + } else if (strcasecmp(cp, address) == 0) { + return 1; + } + } SMARTLIST_FOREACH_END(cp); + return 0; +} + +/** If an exit wasn't explicitly specified for conn, consider saving + * the exit that we *did* choose for use by future connections to + * conn's destination. + */ +static void +consider_recording_trackhost(const entry_connection_t *conn, + const origin_circuit_t *circ) +{ + const or_options_t *options = get_options(); + char *new_address = NULL; + char fp[HEX_DIGEST_LEN+1]; + + /* Search the addressmap for this conn's destination. */ + /* If he's not in the address map.. */ + if (!options->TrackHostExits || + addressmap_have_mapping(conn->socks_request->address, + options->TrackHostExitsExpire)) + return; /* nothing to track, or already mapped */ + + if (!hostname_in_track_host_exits(options, conn->socks_request->address) || + !circ->build_state->chosen_exit) + return; + + /* write down the fingerprint of the chosen exit, not the nickname, + * because the chosen exit might not be named. */ + base16_encode(fp, sizeof(fp), + circ->build_state->chosen_exit->identity_digest, DIGEST_LEN); + + /* Add this exit/hostname pair to the addressmap. */ + tor_asprintf(&new_address, "%s.%s.exit", + conn->socks_request->address, fp); + + addressmap_register(conn->socks_request->address, new_address, + time(NULL) + options->TrackHostExitsExpire, + ADDRMAPSRC_TRACKEXIT, 0, 0); +} + +/** Attempt to attach the connection conn to circ, and send a + * begin or resolve cell as appropriate. Return values are as for + * connection_ap_handshake_attach_circuit. The stream will exit from the hop + * indicated by cpath, or from the last hop in circ's cpath if + * cpath is NULL. */ +int +connection_ap_handshake_attach_chosen_circuit(entry_connection_t *conn, + origin_circuit_t *circ, + crypt_path_t *cpath) +{ + connection_t *base_conn = ENTRY_TO_CONN(conn); + tor_assert(conn); + tor_assert(base_conn->state == AP_CONN_STATE_CIRCUIT_WAIT || + base_conn->state == AP_CONN_STATE_CONTROLLER_WAIT); + tor_assert(conn->socks_request); + tor_assert(circ); + tor_assert(circ->base_.state == CIRCUIT_STATE_OPEN); + + base_conn->state = AP_CONN_STATE_CIRCUIT_WAIT; + + if (!circ->base_.timestamp_dirty) + circ->base_.timestamp_dirty = time(NULL); + + pathbias_count_use_attempt(circ); + + link_apconn_to_circ(conn, circ, cpath); + tor_assert(conn->socks_request); + if (conn->socks_request->command == SOCKS_COMMAND_CONNECT) { + if (!conn->use_begindir) + consider_recording_trackhost(conn, circ); + if (connection_ap_handshake_send_begin(conn) < 0) + return -1; + } else { + if (connection_ap_handshake_send_resolve(conn) < 0) + return -1; + } + + return 1; +} + +/** Try to find a safe live circuit for CONN_TYPE_AP connection conn. If + * we don't find one: if conn cannot be handled by any known nodes, + * warn and return -1 (conn needs to die, and is maybe already marked); + * else launch new circuit (if necessary) and return 0. + * Otherwise, associate conn with a safe live circuit, do the + * right next step, and return 1. + */ +/* XXXX this function should mark for close whenever it returns -1; + * its callers shouldn't have to worry about that. */ +int +connection_ap_handshake_attach_circuit(entry_connection_t *conn) +{ + connection_t *base_conn = ENTRY_TO_CONN(conn); + int retval; + int conn_age; + int want_onehop; + + tor_assert(conn); + tor_assert(base_conn->state == AP_CONN_STATE_CIRCUIT_WAIT); + tor_assert(conn->socks_request); + want_onehop = conn->want_onehop; + + conn_age = (int)(time(NULL) - base_conn->timestamp_created); + + if (conn_age >= get_options()->SocksTimeout) { + int severity = (tor_addr_is_null(&base_conn->addr) && !base_conn->port) ? + LOG_INFO : LOG_NOTICE; + log_fn(severity, LD_APP, + "Tried for %d seconds to get a connection to %s:%d. Giving up.", + conn_age, safe_str_client(conn->socks_request->address), + conn->socks_request->port); + return -1; + } + + if (!connection_edge_is_rendezvous_stream(ENTRY_TO_EDGE_CONN(conn))) { + /* we're a general conn */ + origin_circuit_t *circ=NULL; + + if (conn->chosen_exit_name) { + const node_t *node = node_get_by_nickname(conn->chosen_exit_name, 1); + int opt = conn->chosen_exit_optional; + if (!node && !want_onehop) { + /* We ran into this warning when trying to extend a circuit to a + * hidden service directory for which we didn't have a router + * descriptor. See flyspray task 767 for more details. We should + * keep this in mind when deciding to use BEGIN_DIR cells for other + * directory requests as well. -KL*/ + log_fn(opt ? LOG_INFO : LOG_WARN, LD_APP, + "Requested exit point '%s' is not known. %s.", + conn->chosen_exit_name, opt ? "Trying others" : "Closing"); + if (opt) { + conn->chosen_exit_optional = 0; + tor_free(conn->chosen_exit_name); + return 0; + } + return -1; + } + if (node && !connection_ap_can_use_exit(conn, node)) { + log_fn(opt ? LOG_INFO : LOG_WARN, LD_APP, + "Requested exit point '%s' is excluded or " + "would refuse request. %s.", + conn->chosen_exit_name, opt ? "Trying others" : "Closing"); + if (opt) { + conn->chosen_exit_optional = 0; + tor_free(conn->chosen_exit_name); + return 0; + } + return -1; + } + } + + /* find the circuit that we should use, if there is one. */ + retval = circuit_get_open_circ_or_launch( + conn, CIRCUIT_PURPOSE_C_GENERAL, &circ); + if (retval < 1) // XXX023 if we totally fail, this still returns 0 -RD + return retval; + + log_debug(LD_APP|LD_CIRC, + "Attaching apconn to circ %u (stream %d sec old).", + (unsigned)circ->base_.n_circ_id, conn_age); + /* print the circ's path, so people can figure out which circs are + * sucking. */ + circuit_log_path(LOG_INFO,LD_APP|LD_CIRC,circ); + + /* We have found a suitable circuit for our conn. Hurray. */ + return connection_ap_handshake_attach_chosen_circuit(conn, circ, NULL); + + } else { /* we're a rendezvous conn */ + origin_circuit_t *rendcirc=NULL, *introcirc=NULL; + + tor_assert(!ENTRY_TO_EDGE_CONN(conn)->cpath_layer); + + /* start by finding a rendezvous circuit for us */ + + retval = circuit_get_open_circ_or_launch( + conn, CIRCUIT_PURPOSE_C_REND_JOINED, &rendcirc); + if (retval < 0) return -1; /* failed */ + + if (retval > 0) { + tor_assert(rendcirc); + /* one is already established, attach */ + log_info(LD_REND, + "rend joined circ %d already here. attaching. " + "(stream %d sec old)", + (unsigned)rendcirc->base_.n_circ_id, conn_age); + /* Mark rendezvous circuits as 'newly dirty' every time you use + * them, since the process of rebuilding a rendezvous circ is so + * expensive. There is a tradeoff between linkability and + * feasibility, at this point. + */ + rendcirc->base_.timestamp_dirty = time(NULL); + + /* We've also attempted to use them. If they fail, we need to + * probe them for path bias */ + pathbias_count_use_attempt(rendcirc); + + link_apconn_to_circ(conn, rendcirc, NULL); + if (connection_ap_handshake_send_begin(conn) < 0) + return 0; /* already marked, let them fade away */ + return 1; + } + + if (rendcirc && (rendcirc->base_.purpose == + CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED)) { + log_info(LD_REND, + "pending-join circ %u already here, with intro ack. " + "Stalling. (stream %d sec old)", + (unsigned)rendcirc->base_.n_circ_id, conn_age); + return 0; + } + + /* it's on its way. find an intro circ. */ + retval = circuit_get_open_circ_or_launch( + conn, CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT, &introcirc); + if (retval < 0) return -1; /* failed */ + + if (retval > 0) { + /* one has already sent the intro. keep waiting. */ + tor_assert(introcirc); + log_info(LD_REND, "Intro circ %u present and awaiting ack (rend %u). " + "Stalling. (stream %d sec old)", + (unsigned)introcirc->base_.n_circ_id, + rendcirc ? (unsigned)rendcirc->base_.n_circ_id : 0, + conn_age); + return 0; + } + + /* now rendcirc and introcirc are each either undefined or not finished */ + + if (rendcirc && introcirc && + rendcirc->base_.purpose == CIRCUIT_PURPOSE_C_REND_READY) { + log_info(LD_REND, + "ready rend circ %u already here (no intro-ack yet on " + "intro %u). (stream %d sec old)", + (unsigned)rendcirc->base_.n_circ_id, + (unsigned)introcirc->base_.n_circ_id, conn_age); + + tor_assert(introcirc->base_.purpose == CIRCUIT_PURPOSE_C_INTRODUCING); + if (introcirc->base_.state == CIRCUIT_STATE_OPEN) { + log_info(LD_REND,"found open intro circ %u (rend %u); sending " + "introduction. (stream %d sec old)", + (unsigned)introcirc->base_.n_circ_id, + (unsigned)rendcirc->base_.n_circ_id, + conn_age); + switch (rend_client_send_introduction(introcirc, rendcirc)) { + case 0: /* success */ + rendcirc->base_.timestamp_dirty = time(NULL); + introcirc->base_.timestamp_dirty = time(NULL); + + pathbias_count_use_attempt(introcirc); + pathbias_count_use_attempt(rendcirc); + + assert_circuit_ok(TO_CIRCUIT(rendcirc)); + assert_circuit_ok(TO_CIRCUIT(introcirc)); + return 0; + case -1: /* transient error */ + return 0; + case -2: /* permanent error */ + return -1; + default: /* oops */ + tor_fragile_assert(); + return -1; + } + } + } + + log_info(LD_REND, "Intro (%u) and rend (%u) circs are not both ready. " + "Stalling conn. (%d sec old)", + introcirc ? (unsigned)introcirc->base_.n_circ_id : 0, + rendcirc ? (unsigned)rendcirc->base_.n_circ_id : 0, conn_age); + return 0; + } +} + +/** Change circ's purpose to new_purpose. */ +void +circuit_change_purpose(circuit_t *circ, uint8_t new_purpose) +{ + uint8_t old_purpose; + /* Don't allow an OR circ to become an origin circ or vice versa. */ + tor_assert(!!(CIRCUIT_IS_ORIGIN(circ)) == + !!(CIRCUIT_PURPOSE_IS_ORIGIN(new_purpose))); + + if (circ->purpose == new_purpose) return; + + if (CIRCUIT_IS_ORIGIN(circ)) { + char old_purpose_desc[80] = ""; + + strncpy(old_purpose_desc, circuit_purpose_to_string(circ->purpose), 80-1); + old_purpose_desc[80-1] = '\0'; + + log_debug(LD_CIRC, + "changing purpose of origin circ %d " + "from \"%s\" (%d) to \"%s\" (%d)", + TO_ORIGIN_CIRCUIT(circ)->global_identifier, + old_purpose_desc, + circ->purpose, + circuit_purpose_to_string(new_purpose), + new_purpose); + } + + old_purpose = circ->purpose; + circ->purpose = new_purpose; + + if (CIRCUIT_IS_ORIGIN(circ)) { + control_event_circuit_purpose_changed(TO_ORIGIN_CIRCUIT(circ), + old_purpose); + } +} + +/** Mark circ so that no more connections can be attached to it. */ +void +mark_circuit_unusable_for_new_conns(origin_circuit_t *circ) +{ + const or_options_t *options = get_options(); + tor_assert(circ); + + /* XXXX025 This is a kludge; we're only keeping it around in case there's + * something that doesn't check unusable_for_new_conns, and to avoid + * deeper refactoring of our expiration logic. */ + if (! circ->base_.timestamp_dirty) + circ->base_.timestamp_dirty = approx_time(); + if (options->MaxCircuitDirtiness >= circ->base_.timestamp_dirty) + circ->base_.timestamp_dirty = 1; /* prevent underflow */ + else + circ->base_.timestamp_dirty -= options->MaxCircuitDirtiness; + + circ->unusable_for_new_conns = 1; +} + diff --git a/src/tor/circuituse.h b/src/tor/circuituse.h new file mode 100644 index 0000000..11e5a64 --- /dev/null +++ b/src/tor/circuituse.h @@ -0,0 +1,61 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file circuituse.h + * \brief Header file for circuituse.c. + **/ + +#ifndef TOR_CIRCUITUSE_H +#define TOR_CIRCUITUSE_H + +void circuit_expire_building(void); +void circuit_remove_handled_ports(smartlist_t *needed_ports); +int circuit_stream_is_being_handled(entry_connection_t *conn, uint16_t port, + int min); +#if 0 +int circuit_conforms_to_options(const origin_circuit_t *circ, + const or_options_t *options); +#endif +void circuit_build_needed_circs(time_t now); +void circuit_detach_stream(circuit_t *circ, edge_connection_t *conn); + +void circuit_expire_old_circuits_serverside(time_t now); + +void reset_bandwidth_test(void); +int circuit_enough_testing_circs(void); + +void circuit_has_opened(origin_circuit_t *circ); +void circuit_try_attaching_streams(origin_circuit_t *circ); +void circuit_build_failed(origin_circuit_t *circ); + +/** Flag to set when a circuit should have only a single hop. */ +#define CIRCLAUNCH_ONEHOP_TUNNEL (1<<0) +/** Flag to set when a circuit needs to be built of high-uptime nodes */ +#define CIRCLAUNCH_NEED_UPTIME (1<<1) +/** Flag to set when a circuit needs to be built of high-capacity nodes */ +#define CIRCLAUNCH_NEED_CAPACITY (1<<2) +/** Flag to set when the last hop of a circuit doesn't need to be an + * exit node. */ +#define CIRCLAUNCH_IS_INTERNAL (1<<3) +origin_circuit_t *circuit_launch_by_extend_info(uint8_t purpose, + extend_info_t *info, + int flags); +origin_circuit_t *circuit_launch(uint8_t purpose, int flags); +void circuit_reset_failure_count(int timeout); +int connection_ap_handshake_attach_chosen_circuit(entry_connection_t *conn, + origin_circuit_t *circ, + crypt_path_t *cpath); +int connection_ap_handshake_attach_circuit(entry_connection_t *conn); + +void circuit_change_purpose(circuit_t *circ, uint8_t new_purpose); + +int hostname_in_track_host_exits(const or_options_t *options, + const char *address); +void mark_circuit_unusable_for_new_conns(origin_circuit_t *circ); + +#endif + diff --git a/src/tor/command.c b/src/tor/command.c new file mode 100644 index 0000000..9b3ff16 --- /dev/null +++ b/src/tor/command.c @@ -0,0 +1,589 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file command.c + * \brief Functions for processing incoming cells. + **/ + +/* In-points to command.c: + * + * - command_process_cell(), called from + * incoming cell handlers of channel_t instances; + * callbacks registered in command_setup_channel(), + * called when channels are created in circuitbuild.c + */ +#include "or.h" +#include "channel.h" +#include "circuitbuild.h" +#include "circuitlist.h" +#include "command.h" +#include "connection.h" +#include "connection_or.h" +#include "config.h" +#include "control.h" +#include "cpuworker.h" +#include "hibernate.h" +#include "nodelist.h" +#include "onion.h" +#include "rephist.h" +#include "relay.h" +#include "router.h" +#include "routerlist.h" + +/** How many CELL_CREATE cells have we received, ever? */ +uint64_t stats_n_create_cells_processed = 0; +/** How many CELL_CREATED cells have we received, ever? */ +uint64_t stats_n_created_cells_processed = 0; +/** How many CELL_RELAY cells have we received, ever? */ +uint64_t stats_n_relay_cells_processed = 0; +/** How many CELL_DESTROY cells have we received, ever? */ +uint64_t stats_n_destroy_cells_processed = 0; + +/* Handle an incoming channel */ +static void command_handle_incoming_channel(channel_listener_t *listener, + channel_t *chan); + +/* These are the main functions for processing cells */ +static void command_process_create_cell(cell_t *cell, channel_t *chan); +static void command_process_created_cell(cell_t *cell, channel_t *chan); +static void command_process_relay_cell(cell_t *cell, channel_t *chan); +static void command_process_destroy_cell(cell_t *cell, channel_t *chan); + +/** Convert the cell command into a lower-case, human-readable + * string. */ +const char * +cell_command_to_string(uint8_t command) +{ + switch (command) { + case CELL_PADDING: return "padding"; + case CELL_CREATE: return "create"; + case CELL_CREATED: return "created"; + case CELL_RELAY: return "relay"; + case CELL_DESTROY: return "destroy"; + case CELL_CREATE_FAST: return "create_fast"; + case CELL_CREATED_FAST: return "created_fast"; + case CELL_VERSIONS: return "versions"; + case CELL_NETINFO: return "netinfo"; + case CELL_RELAY_EARLY: return "relay_early"; + case CELL_CREATE2: return "create2"; + case CELL_CREATED2: return "created2"; + case CELL_VPADDING: return "vpadding"; + case CELL_CERTS: return "certs"; + case CELL_AUTH_CHALLENGE: return "auth_challenge"; + case CELL_AUTHENTICATE: return "authenticate"; + case CELL_AUTHORIZE: return "authorize"; + default: return "unrecognized"; + } +} + +#ifdef KEEP_TIMING_STATS +/** This is a wrapper function around the actual function that processes the + * cell that just arrived on conn. Increment *time + * by the number of microseconds used by the call to *func(cell, conn). + */ +static void +command_time_process_cell(cell_t *cell, channel_t *chan, int *time, + void (*func)(cell_t *, channel_t *)) +{ + struct timeval start, end; + long time_passed; + + tor_gettimeofday(&start); + + (*func)(cell, chan); + + tor_gettimeofday(&end); + time_passed = tv_udiff(&start, &end) ; + + if (time_passed > 10000) { /* more than 10ms */ + log_debug(LD_OR,"That call just took %ld ms.",time_passed/1000); + } + if (time_passed < 0) { + log_info(LD_GENERAL,"That call took us back in time!"); + time_passed = 0; + } + *time += time_passed; +} +#endif + +/** Process a cell that was just received on chan. Keep internal + * statistics about how many of each cell we've processed so far + * this second, and the total number of microseconds it took to + * process each type of cell. + */ +void +command_process_cell(channel_t *chan, cell_t *cell) +{ +#ifdef KEEP_TIMING_STATS + /* how many of each cell have we seen so far this second? needs better + * name. */ + static int num_create=0, num_created=0, num_relay=0, num_destroy=0; + /* how long has it taken to process each type of cell? */ + static int create_time=0, created_time=0, relay_time=0, destroy_time=0; + static time_t current_second = 0; /* from previous calls to time */ + + time_t now = time(NULL); + + if (now > current_second) { /* the second has rolled over */ + /* print stats */ + log_info(LD_OR, + "At end of second: %d creates (%d ms), %d createds (%d ms), " + "%d relays (%d ms), %d destroys (%d ms)", + num_create, create_time/1000, + num_created, created_time/1000, + num_relay, relay_time/1000, + num_destroy, destroy_time/1000); + + /* zero out stats */ + num_create = num_created = num_relay = num_destroy = 0; + create_time = created_time = relay_time = destroy_time = 0; + + /* remember which second it is, for next time */ + current_second = now; + } +#endif + +#ifdef KEEP_TIMING_STATS +#define PROCESS_CELL(tp, cl, cn) STMT_BEGIN { \ + ++num ## tp; \ + command_time_process_cell(cl, cn, & tp ## time , \ + command_process_ ## tp ## _cell); \ + } STMT_END +#else +#define PROCESS_CELL(tp, cl, cn) command_process_ ## tp ## _cell(cl, cn) +#endif + + switch (cell->command) { + case CELL_CREATE: + case CELL_CREATE_FAST: + case CELL_CREATE2: + ++stats_n_create_cells_processed; + PROCESS_CELL(create, cell, chan); + break; + case CELL_CREATED: + case CELL_CREATED_FAST: + case CELL_CREATED2: + ++stats_n_created_cells_processed; + PROCESS_CELL(created, cell, chan); + break; + case CELL_RELAY: + case CELL_RELAY_EARLY: + ++stats_n_relay_cells_processed; + PROCESS_CELL(relay, cell, chan); + break; + case CELL_DESTROY: + ++stats_n_destroy_cells_processed; + PROCESS_CELL(destroy, cell, chan); + break; + default: + log_fn(LOG_INFO, LD_PROTOCOL, + "Cell of unknown or unexpected type (%d) received. " + "Dropping.", + cell->command); + break; + } +} + +/** Process an incoming var_cell from a channel; in the current protocol all + * the var_cells are handshake-related and handled below the channel layer, + * so this just logs a warning and drops the cell. + */ + +void +command_process_var_cell(channel_t *chan, var_cell_t *var_cell) +{ + tor_assert(chan); + tor_assert(var_cell); + + log_info(LD_PROTOCOL, + "Received unexpected var_cell above the channel layer of type %d" + "; dropping it.", + var_cell->command); +} + +/** Process a 'create' cell that just arrived from chan. Make a + * new circuit with the p_circ_id specified in cell. Put the circuit in state + * onionskin_pending, and pass the onionskin to the cpuworker. Circ will get + * picked up again when the cpuworker finishes decrypting it. + */ +static void +command_process_create_cell(cell_t *cell, channel_t *chan) +{ + or_circuit_t *circ; + const or_options_t *options = get_options(); + int id_is_high; + create_cell_t *create_cell; + + tor_assert(cell); + tor_assert(chan); + + log_debug(LD_OR, + "Got a CREATE cell for circ_id %u on channel " U64_FORMAT + " (%p)", + (unsigned)cell->circ_id, + U64_PRINTF_ARG(chan->global_identifier), chan); + + if (we_are_hibernating()) { + log_info(LD_OR, + "Received create cell but we're shutting down. Sending back " + "destroy."); + channel_send_destroy(cell->circ_id, chan, + END_CIRC_REASON_HIBERNATING); + return; + } + + if (!server_mode(options) || + (!public_server_mode(options) && channel_is_outgoing(chan))) { + log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, + "Received create cell (type %d) from %s, but we're connected " + "to it as a client. " + "Sending back a destroy.", + (int)cell->command, channel_get_canonical_remote_descr(chan)); + channel_send_destroy(cell->circ_id, chan, + END_CIRC_REASON_TORPROTOCOL); + return; + } + + if (cell->circ_id == 0) { + log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, + "Received a create cell (type %d) from %s with zero circID; " + " ignoring.", (int)cell->command, + channel_get_actual_remote_descr(chan)); + return; + } + + /* If the high bit of the circuit ID is not as expected, close the + * circ. */ + if (chan->wide_circ_ids) + id_is_high = cell->circ_id & (1u<<31); + else + id_is_high = cell->circ_id & (1u<<15); + if ((id_is_high && + chan->circ_id_type == CIRC_ID_TYPE_HIGHER) || + (!id_is_high && + chan->circ_id_type == CIRC_ID_TYPE_LOWER)) { + log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, + "Received create cell with unexpected circ_id %u. Closing.", + (unsigned)cell->circ_id); + channel_send_destroy(cell->circ_id, chan, + END_CIRC_REASON_TORPROTOCOL); + return; + } + + if (circuit_id_in_use_on_channel(cell->circ_id, chan)) { + const node_t *node = node_get_by_id(chan->identity_digest); + log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, + "Received CREATE cell (circID %u) for known circ. " + "Dropping (age %d).", + (unsigned)cell->circ_id, + (int)(time(NULL) - channel_when_created(chan))); + if (node) { + char *p = esc_for_log(node_get_platform(node)); + log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, + "Details: router %s, platform %s.", + node_describe(node), p); + tor_free(p); + } + return; + } + + circ = or_circuit_new(cell->circ_id, chan); + circ->base_.purpose = CIRCUIT_PURPOSE_OR; + circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_ONIONSKIN_PENDING); + create_cell = tor_malloc_zero(sizeof(create_cell_t)); + if (create_cell_parse(create_cell, cell) < 0) { + tor_free(create_cell); + log_fn(LOG_PROTOCOL_WARN, LD_OR, + "Bogus/unrecognized create cell; closing."); + circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_TORPROTOCOL); + return; + } + + if (create_cell->handshake_type != ONION_HANDSHAKE_TYPE_FAST) { + /* hand it off to the cpuworkers, and then return. */ + if (connection_or_digest_is_known_relay(chan->identity_digest)) + rep_hist_note_circuit_handshake_requested(create_cell->handshake_type); + if (assign_onionskin_to_cpuworker(NULL, circ, create_cell) < 0) { + log_debug(LD_GENERAL,"Failed to hand off onionskin. Closing."); + circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_RESOURCELIMIT); + return; + } + log_debug(LD_OR,"success: handed off onionskin."); + } else { + /* This is a CREATE_FAST cell; we can handle it immediately without using + * a CPU worker. */ + uint8_t keys[CPATH_KEY_MATERIAL_LEN]; + uint8_t rend_circ_nonce[DIGEST_LEN]; + int len; + created_cell_t created_cell; + + /* Make sure we never try to use the OR connection on which we + * received this cell to satisfy an EXTEND request, */ + channel_mark_client(chan); + + memset(&created_cell, 0, sizeof(created_cell)); + len = onion_skin_server_handshake(ONION_HANDSHAKE_TYPE_FAST, + create_cell->onionskin, + create_cell->handshake_len, + NULL, + created_cell.reply, + keys, CPATH_KEY_MATERIAL_LEN, + rend_circ_nonce); + tor_free(create_cell); + if (len < 0) { + log_warn(LD_OR,"Failed to generate key material. Closing."); + circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_INTERNAL); + tor_free(create_cell); + return; + } + created_cell.cell_type = CELL_CREATED_FAST; + created_cell.handshake_len = len; + + if (onionskin_answer(circ, &created_cell, + (const char *)keys, rend_circ_nonce)<0) { + log_warn(LD_OR,"Failed to reply to CREATE_FAST cell. Closing."); + circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_INTERNAL); + return; + } + memwipe(keys, 0, sizeof(keys)); + } +} + +/** Process a 'created' cell that just arrived from chan. + * Find the circuit + * that it's intended for. If we're not the origin of the circuit, package + * the 'created' cell in an 'extended' relay cell and pass it back. If we + * are the origin of the circuit, send it to circuit_finish_handshake() to + * finish processing keys, and then call circuit_send_next_onion_skin() to + * extend to the next hop in the circuit if necessary. + */ +static void +command_process_created_cell(cell_t *cell, channel_t *chan) +{ + circuit_t *circ; + extended_cell_t extended_cell; + + circ = circuit_get_by_circid_channel(cell->circ_id, chan); + + if (!circ) { + log_info(LD_OR, + "(circID %u) unknown circ (probably got a destroy earlier). " + "Dropping.", (unsigned)cell->circ_id); + return; + } + + if (circ->n_circ_id != cell->circ_id) { + log_fn(LOG_PROTOCOL_WARN,LD_PROTOCOL, + "got created cell from Tor client? Closing."); + circuit_mark_for_close(circ, END_CIRC_REASON_TORPROTOCOL); + return; + } + + if (created_cell_parse(&extended_cell.created_cell, cell) < 0) { + log_fn(LOG_PROTOCOL_WARN, LD_OR, "Unparseable created cell."); + circuit_mark_for_close(circ, END_CIRC_REASON_TORPROTOCOL); + return; + } + + if (CIRCUIT_IS_ORIGIN(circ)) { /* we're the OP. Handshake this. */ + origin_circuit_t *origin_circ = TO_ORIGIN_CIRCUIT(circ); + int err_reason = 0; + log_debug(LD_OR,"at OP. Finishing handshake."); + if ((err_reason = circuit_finish_handshake(origin_circ, + &extended_cell.created_cell)) < 0) { + log_warn(LD_OR,"circuit_finish_handshake failed."); + circuit_mark_for_close(circ, -err_reason); + return; + } + log_debug(LD_OR,"Moving to next skin."); + if ((err_reason = circuit_send_next_onion_skin(origin_circ)) < 0) { + log_info(LD_OR,"circuit_send_next_onion_skin failed."); + /* XXX push this circuit_close lower */ + circuit_mark_for_close(circ, -err_reason); + return; + } + } else { /* pack it into an extended relay cell, and send it. */ + uint8_t command=0; + uint16_t len=0; + uint8_t payload[RELAY_PAYLOAD_SIZE]; + log_debug(LD_OR, + "Converting created cell to extended relay cell, sending."); + memset(payload, 0, sizeof(payload)); + if (extended_cell.created_cell.cell_type == CELL_CREATED2) + extended_cell.cell_type = RELAY_COMMAND_EXTENDED2; + else + extended_cell.cell_type = RELAY_COMMAND_EXTENDED; + if (extended_cell_format(&command, &len, payload, &extended_cell) < 0) { + log_fn(LOG_PROTOCOL_WARN, LD_OR, "Can't format extended cell."); + circuit_mark_for_close(circ, END_CIRC_REASON_TORPROTOCOL); + return; + } + + relay_send_command_from_edge(0, circ, command, + (const char*)payload, len, NULL); + } +} + +/** Process a 'relay' or 'relay_early' cell that just arrived from + * conn. Make sure it came in with a recognized circ_id. Pass it on to + * circuit_receive_relay_cell() for actual processing. + */ +static void +command_process_relay_cell(cell_t *cell, channel_t *chan) +{ + circuit_t *circ; + int reason, direction; + + circ = circuit_get_by_circid_channel(cell->circ_id, chan); + + if (!circ) { + log_debug(LD_OR, + "unknown circuit %u on connection from %s. Dropping.", + (unsigned)cell->circ_id, + channel_get_canonical_remote_descr(chan)); + return; + } + + if (circ->state == CIRCUIT_STATE_ONIONSKIN_PENDING) { + log_fn(LOG_PROTOCOL_WARN,LD_PROTOCOL,"circuit in create_wait. Closing."); + circuit_mark_for_close(circ, END_CIRC_REASON_TORPROTOCOL); + return; + } + + if (CIRCUIT_IS_ORIGIN(circ)) { + /* if we're a relay and treating connections with recent local + * traffic better, then this is one of them. */ + channel_timestamp_client(chan); + } + + if (!CIRCUIT_IS_ORIGIN(circ) && + cell->circ_id == TO_OR_CIRCUIT(circ)->p_circ_id) + direction = CELL_DIRECTION_OUT; + else + direction = CELL_DIRECTION_IN; + + /* If we have a relay_early cell, make sure that it's outbound, and we've + * gotten no more than MAX_RELAY_EARLY_CELLS_PER_CIRCUIT of them. */ + if (cell->command == CELL_RELAY_EARLY) { + if (direction == CELL_DIRECTION_IN) { + /* Allow an unlimited number of inbound relay_early cells, + * for hidden service compatibility. There isn't any way to make + * a long circuit through inbound relay_early cells anyway. See + * bug 1038. -RD */ + } else { + or_circuit_t *or_circ = TO_OR_CIRCUIT(circ); + if (or_circ->remaining_relay_early_cells == 0) { + log_fn(LOG_PROTOCOL_WARN, LD_OR, + "Received too many RELAY_EARLY cells on circ %u from %s." + " Closing circuit.", + (unsigned)cell->circ_id, + safe_str(channel_get_canonical_remote_descr(chan))); + circuit_mark_for_close(circ, END_CIRC_REASON_TORPROTOCOL); + return; + } + --or_circ->remaining_relay_early_cells; + } + } + + if ((reason = circuit_receive_relay_cell(cell, circ, direction)) < 0) { + log_fn(LOG_PROTOCOL_WARN,LD_PROTOCOL,"circuit_receive_relay_cell " + "(%s) failed. Closing.", + direction==CELL_DIRECTION_OUT?"forward":"backward"); + circuit_mark_for_close(circ, -reason); + } +} + +/** Process a 'destroy' cell that just arrived from + * chan. Find the circ that it refers to (if any). + * + * If the circ is in state + * onionskin_pending, then call onion_pending_remove() to remove it + * from the pending onion list (note that if it's already being + * processed by the cpuworker, it won't be in the list anymore; but + * when the cpuworker returns it, the circuit will be gone, and the + * cpuworker response will be dropped). + * + * Then mark the circuit for close (which marks all edges for close, + * and passes the destroy cell onward if necessary). + */ +static void +command_process_destroy_cell(cell_t *cell, channel_t *chan) +{ + circuit_t *circ; + int reason; + + circ = circuit_get_by_circid_channel(cell->circ_id, chan); + if (!circ) { + log_info(LD_OR,"unknown circuit %u on connection from %s. Dropping.", + (unsigned)cell->circ_id, + channel_get_canonical_remote_descr(chan)); + return; + } + log_debug(LD_OR,"Received for circID %u.",(unsigned)cell->circ_id); + + reason = (uint8_t)cell->payload[0]; + circ->received_destroy = 1; + + if (!CIRCUIT_IS_ORIGIN(circ) && + cell->circ_id == TO_OR_CIRCUIT(circ)->p_circ_id) { + /* the destroy came from behind */ + circuit_set_p_circid_chan(TO_OR_CIRCUIT(circ), 0, NULL); + circuit_mark_for_close(circ, reason|END_CIRC_REASON_FLAG_REMOTE); + } else { /* the destroy came from ahead */ + circuit_set_n_circid_chan(circ, 0, NULL); + if (CIRCUIT_IS_ORIGIN(circ)) { + circuit_mark_for_close(circ, reason|END_CIRC_REASON_FLAG_REMOTE); + } else { + char payload[1]; + log_debug(LD_OR, "Delivering 'truncated' back."); + payload[0] = (char)reason; + relay_send_command_from_edge(0, circ, RELAY_COMMAND_TRUNCATED, + payload, sizeof(payload), NULL); + } + } +} + +/** Callback to handle a new channel; call command_setup_channel() to give + * it the right cell handlers. + */ + +static void +command_handle_incoming_channel(channel_listener_t *listener, channel_t *chan) +{ + tor_assert(listener); + tor_assert(chan); + + command_setup_channel(chan); +} + +/** Given a channel, install the right handlers to process incoming + * cells on it. + */ + +void +command_setup_channel(channel_t *chan) +{ + tor_assert(chan); + + channel_set_cell_handlers(chan, + command_process_cell, + command_process_var_cell); +} + +/** Given a listener, install the right handler to process incoming + * channels on it. + */ + +void +command_setup_listener(channel_listener_t *listener) +{ + tor_assert(listener); + tor_assert(listener->state == CHANNEL_LISTENER_STATE_LISTENING); + + channel_listener_set_listener_fn(listener, command_handle_incoming_channel); +} + diff --git a/src/tor/command.h b/src/tor/command.h new file mode 100644 index 0000000..adea6ad --- /dev/null +++ b/src/tor/command.h @@ -0,0 +1,31 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file command.h + * \brief Header file for command.c. + **/ + +#ifndef TOR_COMMAND_H +#define TOR_COMMAND_H + +#include "channel.h" + +void command_process_cell(channel_t *chan, cell_t *cell); +void command_process_var_cell(channel_t *chan, var_cell_t *cell); +void command_setup_channel(channel_t *chan); +void command_setup_listener(channel_listener_t *chan_l); + +const char *cell_command_to_string(uint8_t command); + +extern uint64_t stats_n_padding_cells_processed; +extern uint64_t stats_n_create_cells_processed; +extern uint64_t stats_n_created_cells_processed; +extern uint64_t stats_n_relay_cells_processed; +extern uint64_t stats_n_destroy_cells_processed; + +#endif + diff --git a/src/tor/common_sha1.i b/src/tor/common_sha1.i new file mode 100644 index 0000000..80ea224 --- /dev/null +++ b/src/tor/common_sha1.i @@ -0,0 +1,26 @@ +"10e0ec8ee3318e6a5ebbedc35d45ad4ec2fe5bb2 src/common/aes.c\n" +"7fdacbf7fc104d4e118ce06cf823b2f3cb145291 src/common/crypto.c\n" +"401d6c1243b8d99ad8f64dba232e234e60a59eb7 src/common/crypto_format.c\n" +"64a20b8425300b0bf2373a4fe4eb74b47c4baf50 src/common/torgzip.c\n" +"f0e8fd88f7198ad4adbd5c28e4af909b2d553b5a src/common/tortls.c\n" +"05dc726d9d47888cc75a1c3bd31c8214dc2cb581 src/common/crypto_curve25519.c\n" +"d233965a57506745525c7a78ff2911d59f5e3743 src/common/address.h\n" +"ac6a50ceb318ed6907b5804034b98172ffc5ff83 src/common/backtrace.h\n" +"947ef902f15f556f176b1115f09d9966e377347d src/common/aes.h\n" +"6fb51902eea04b5c33a99a754845958fec43d912 src/common/ciphers.inc\n" +"4618a9860688c2cb12d37d8172317324c10f0a92 src/common/tor_compat.h\n" +"e427c754391f1282a98cbbb387bae2ae403cbde7 src/common/compat_libevent.h\n" +"faaa0bcfcc0cbc61f6d092b9b36e56cb89b090b7 src/common/container.h\n" +"7196fde86ec70bd579e8fcd546817d285d936b18 src/common/crypto.h\n" +"1260154e3b65f2586a54986deffec6963a4c7204 src/common/crypto_curve25519.h\n" +"9ed1bb165e8d0532cae5bfd17e27d037d2a05bf4 src/common/di_ops.h\n" +"697be45dc2e1ae6537b34dc72abf6394952a1b87 src/common/memarea.h\n" +"0b594bada47b6e23358fa924cffbf24e01180d60 src/common/mempool.h\n" +"2cd7af59a82d4e1ca2873d2801c44176605a545a src/common/procmon.h\n" +"ed8b5d4225ceaf11e29fe635a091e2b2f3fe3ae8 src/common/sandbox.h\n" +"ddfdca2f5d52acc27214a3c91c0ca73c81b526eb src/common/testsupport.h\n" +"13108dc9184a7ece65685e0724e7e8770acd576f src/common/torgzip.h\n" +"8d71f0488728c324a5aabfd92d209350973b490a src/common/torint.h\n" +"b86f76bfdfdc3bd841233c662761e857cb830c88 src/common/torlog.h\n" +"27209a8a0e9b8c61bbbb2d50241a2a4b4595ce19 src/common/tortls.h\n" +"e5cb074466d9f59f1988e8964fed1476c238ff14 src/common/tor_util.h\n" diff --git a/src/tor/compat.c b/src/tor/compat.c new file mode 100644 index 0000000..541f8d2 --- /dev/null +++ b/src/tor/compat.c @@ -0,0 +1,3254 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file compat.c + * \brief Wrappers to make calls more portable. This code defines + * functions such as tor_malloc, tor_snprintf, get/set various data types, + * renaming, setting socket options, switching user IDs. It is basically + * where the non-portable items are conditionally included depending on + * the platform. + **/ + +/* This is required on rh7 to make strptime not complain. + * We also need it to make memmem get defined (where available) + */ +/* XXXX024 We should just use AC_USE_SYSTEM_EXTENSIONS in our autoconf, + * and get this (and other important stuff!) automatically. Once we do that, + * make sure to also change the extern char **environ detection in + * configure.ac, because whether that is declared or not depends on whether + * we have _GNU_SOURCE defined! Maybe that means that once we take this out, + * we can also take out the configure check. */ +#define _GNU_SOURCE + +#define COMPAT_PRIVATE +#include "tor_compat.h" + +#ifdef _WIN32 +#include +#include +#include +#endif + +#ifdef HAVE_UNAME +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif +#ifdef HAVE_SYS_FCNTL_H +#include +#endif +#ifdef HAVE_PWD_H +#include +#endif +#ifdef HAVE_GRP_H +#include +#endif +#ifdef HAVE_FCNTL_H +#include +#endif +#ifdef HAVE_ERRNO_H +#include +#endif +#ifdef HAVE_ARPA_INET_H +#include +#endif +#ifdef HAVE_CRT_EXTERNS_H +#include +#endif + +#ifndef HAVE_GETTIMEOFDAY +#ifdef HAVE_FTIME +#include +#endif +#endif + +/* Includes for the process attaching prevention */ +#if defined(HAVE_SYS_PRCTL_H) && defined(__linux__) +#include +#elif defined(__APPLE__) +#include +#include +#endif + +#ifdef HAVE_NETDB_H +#include +#endif +#ifdef HAVE_SYS_PARAM_H +#include /* FreeBSD needs this to know what version it is */ +#endif +#include +#include +#include +#ifdef HAVE_SIGNAL_H +#include +#endif +#ifdef HAVE_UTIME_H +#include +#endif +#ifdef HAVE_SYS_UTIME_H +#include +#endif +#ifdef HAVE_SYS_MMAN_H +#include +#endif +#ifdef HAVE_SYS_SYSLIMITS_H +#include +#endif +#ifdef HAVE_SYS_FILE_H +#include +#endif +#if defined(HAVE_SYS_PRCTL_H) && defined(__linux__) +/* Only use the linux prctl; the IRIX prctl is totally different */ +#include +#endif + +#include "torlog.h" +#include "tor_util.h" +#include "container.h" +#include "address.h" +#include "sandbox.h" + +/* Inline the strl functions if the platform doesn't have them. */ +#ifndef HAVE_STRLCPY +#include "strlcpy.c" +#endif +#ifndef HAVE_STRLCAT +#include "strlcat.c" +#endif + +/** As open(path, flags, mode), but return an fd with the close-on-exec mode + * set. */ +int +tor_open_cloexec(const char *path, int flags, unsigned mode) +{ + int fd; +#ifdef O_CLOEXEC + path = sandbox_intern_string(path); + fd = open(path, flags|O_CLOEXEC, mode); + if (fd >= 0) + return fd; + /* If we got an error, see if it is EINVAL. EINVAL might indicate that, + * even though we were built on a system with O_CLOEXEC support, we + * are running on one without. */ + if (errno != EINVAL) + return -1; +#endif + + fd = open(path, flags, mode); +#ifdef FD_CLOEXEC + if (fd >= 0) { + if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) { + log_warn(LD_FS,"Couldn't set FD_CLOEXEC: %s", strerror(errno)); + close(fd); + return -1; + } + } +#endif + return fd; +} + +/** As fopen(path,mode), but ensures that the O_CLOEXEC bit is set on the + * underlying file handle. */ +FILE * +tor_fopen_cloexec(const char *path, const char *mode) +{ + FILE *result = fopen(path, mode); +#ifdef FD_CLOEXEC + if (result != NULL) { + if (fcntl(fileno(result), F_SETFD, FD_CLOEXEC) == -1) { + log_warn(LD_FS,"Couldn't set FD_CLOEXEC: %s", strerror(errno)); + fclose(result); + return NULL; + } + } +#endif + return result; +} + +#if defined(HAVE_SYS_MMAN_H) || defined(RUNNING_DOXYGEN) +/** Try to create a memory mapping for filename and return it. On + * failure, return NULL. Sets errno properly, using ERANGE to mean + * "empty file". */ +tor_mmap_t * +tor_mmap_file(const char *filename) +{ + int fd; /* router file */ + char *string; + int page_size; + tor_mmap_t *res; + size_t size, filesize; + + tor_assert(filename); + + fd = tor_open_cloexec(filename, O_RDONLY, 0); + if (fd<0) { + int save_errno = errno; + int severity = (errno == ENOENT) ? LOG_INFO : LOG_WARN; + log_fn(severity, LD_FS,"Could not open \"%s\" for mmap(): %s",filename, + strerror(errno)); + errno = save_errno; + return NULL; + } + + /* XXXX why not just do fstat here? */ + size = filesize = (size_t) lseek(fd, 0, SEEK_END); + lseek(fd, 0, SEEK_SET); + /* ensure page alignment */ + page_size = getpagesize(); + size += (size%page_size) ? page_size-(size%page_size) : 0; + + if (!size) { + /* Zero-length file. If we call mmap on it, it will succeed but + * return NULL, and bad things will happen. So just fail. */ + log_info(LD_FS,"File \"%s\" is empty. Ignoring.",filename); + errno = ERANGE; + close(fd); + return NULL; + } + + string = mmap(0, size, PROT_READ, MAP_PRIVATE, fd, 0); + close(fd); + if (string == MAP_FAILED) { + int save_errno = errno; + log_warn(LD_FS,"Could not mmap file \"%s\": %s", filename, + strerror(errno)); + errno = save_errno; + return NULL; + } + + res = tor_malloc_zero(sizeof(tor_mmap_t)); + res->data = string; + res->size = filesize; + res->mapping_size = size; + + return res; +} +/** Release storage held for a memory mapping. */ +void +tor_munmap_file(tor_mmap_t *handle) +{ + munmap((char*)handle->data, handle->mapping_size); + tor_free(handle); +} +#elif defined(_WIN32) +tor_mmap_t * +tor_mmap_file(const char *filename) +{ + TCHAR tfilename[MAX_PATH]= {0}; + tor_mmap_t *res = tor_malloc_zero(sizeof(tor_mmap_t)); + int empty = 0; + HANDLE file_handle = INVALID_HANDLE_VALUE; + DWORD size_low, size_high; + uint64_t real_size; + res->mmap_handle = NULL; +#ifdef UNICODE + mbstowcs(tfilename,filename,MAX_PATH); +#else + strlcpy(tfilename,filename,MAX_PATH); +#endif + file_handle = CreateFile(tfilename, + GENERIC_READ, FILE_SHARE_READ, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + 0); + + if (file_handle == INVALID_HANDLE_VALUE) + goto win_err; + + size_low = GetFileSize(file_handle, &size_high); + + if (size_low == INVALID_FILE_SIZE && GetLastError() != NO_ERROR) { + log_warn(LD_FS,"Error getting size of \"%s\".",filename); + goto win_err; + } + if (size_low == 0 && size_high == 0) { + log_info(LD_FS,"File \"%s\" is empty. Ignoring.",filename); + empty = 1; + goto err; + } + real_size = (((uint64_t)size_high)<<32) | size_low; + if (real_size > SIZE_MAX) { + log_warn(LD_FS,"File \"%s\" is too big to map; not trying.",filename); + goto err; + } + res->size = real_size; + + res->mmap_handle = CreateFileMapping(file_handle, + NULL, + PAGE_READONLY, + size_high, + size_low, + NULL); + if (res->mmap_handle == NULL) + goto win_err; + res->data = (char*) MapViewOfFile(res->mmap_handle, + FILE_MAP_READ, + 0, 0, 0); + if (!res->data) + goto win_err; + + CloseHandle(file_handle); + return res; + win_err: { + DWORD e = GetLastError(); + int severity = (e == ERROR_FILE_NOT_FOUND || e == ERROR_PATH_NOT_FOUND) ? + LOG_INFO : LOG_WARN; + char *msg = format_win32_error(e); + log_fn(severity, LD_FS, "Couldn't mmap file \"%s\": %s", filename, msg); + tor_free(msg); + if (e == ERROR_FILE_NOT_FOUND || e == ERROR_PATH_NOT_FOUND) + errno = ENOENT; + else + errno = EINVAL; + } + err: + if (empty) + errno = ERANGE; + if (file_handle != INVALID_HANDLE_VALUE) + CloseHandle(file_handle); + tor_munmap_file(res); + return NULL; +} +void +tor_munmap_file(tor_mmap_t *handle) +{ + if (handle->data) + /* This is an ugly cast, but without it, "data" in struct tor_mmap_t would + have to be redefined as non-const. */ + UnmapViewOfFile( (LPVOID) handle->data); + + if (handle->mmap_handle != NULL) + CloseHandle(handle->mmap_handle); + tor_free(handle); +} +#else +tor_mmap_t * +tor_mmap_file(const char *filename) +{ + struct stat st; + char *res = read_file_to_str(filename, RFTS_BIN|RFTS_IGNORE_MISSING, &st); + tor_mmap_t *handle; + if (! res) + return NULL; + handle = tor_malloc_zero(sizeof(tor_mmap_t)); + handle->data = res; + handle->size = st.st_size; + return handle; +} +void +tor_munmap_file(tor_mmap_t *handle) +{ + char *d = (char*)handle->data; + tor_free(d); + memwipe(handle, 0, sizeof(tor_mmap_t)); + tor_free(handle); +} +#endif + +/** Replacement for snprintf. Differs from platform snprintf in two + * ways: First, always NUL-terminates its output. Second, always + * returns -1 if the result is truncated. (Note that this return + * behavior does not conform to C99; it just happens to be + * easier to emulate "return -1" with conformant implementations than + * it is to emulate "return number that would be written" with + * non-conformant implementations.) */ +int +tor_snprintf(char *str, size_t size, const char *format, ...) +{ + va_list ap; + int r; + va_start(ap,format); + r = tor_vsnprintf(str,size,format,ap); + va_end(ap); + return r; +} + +/** Replacement for vsnprintf; behavior differs as tor_snprintf differs from + * snprintf. + */ +int +tor_vsnprintf(char *str, size_t size, const char *format, va_list args) +{ + int r; + if (size == 0) + return -1; /* no place for the NUL */ + if (size > SIZE_T_CEILING) + return -1; +#ifdef _WIN32 + r = _vsnprintf(str, size, format, args); +#else + r = vsnprintf(str, size, format, args); +#endif + str[size-1] = '\0'; + if (r < 0 || r >= (ssize_t)size) + return -1; + return r; +} + +/** + * Portable asprintf implementation. Does a printf() into a newly malloc'd + * string. Sets *strp to this string, and returns its length (not + * including the terminating NUL character). + * + * You can treat this function as if its implementation were something like +
+     char buf[_INFINITY_];
+     tor_snprintf(buf, sizeof(buf), fmt, args);
+     *strp = tor_strdup(buf);
+     return strlen(*strp):
+   
+ * Where _INFINITY_ is an imaginary constant so big that any string can fit + * into it. + */ +int +tor_asprintf(char **strp, const char *fmt, ...) +{ + int r; + va_list args; + va_start(args, fmt); + r = tor_vasprintf(strp, fmt, args); + va_end(args); + if (!*strp || r < 0) { + log_err(LD_BUG, "Internal error in asprintf"); + tor_assert(0); + } + return r; +} + +/** + * Portable vasprintf implementation. Does a printf() into a newly malloc'd + * string. Differs from regular vasprintf in the same ways that + * tor_asprintf() differs from regular asprintf. + */ +int +tor_vasprintf(char **strp, const char *fmt, va_list args) +{ + /* use a temporary variable in case *strp is in args. */ + char *strp_tmp=NULL; +#ifdef HAVE_VASPRINTF + /* If the platform gives us one, use it. */ + int r = vasprintf(&strp_tmp, fmt, args); + if (r < 0) + *strp = NULL; + else + *strp = strp_tmp; + return r; +#elif defined(HAVE__VSCPRINTF) + /* On Windows, _vsnprintf won't tell us the length of the string if it + * overflows, so we need to use _vcsprintf to tell how much to allocate */ + int len, r; + len = _vscprintf(fmt, args); + if (len < 0) { + *strp = NULL; + return -1; + } + strp_tmp = tor_malloc(len + 1); + r = _vsnprintf(strp_tmp, len+1, fmt, args); + if (r != len) { + tor_free(strp_tmp); + *strp = NULL; + return -1; + } + *strp = strp_tmp; + return len; +#else + /* Everywhere else, we have a decent vsnprintf that tells us how many + * characters we need. We give it a try on a short buffer first, since + * it might be nice to avoid the second vsnprintf call. + */ + char buf[128]; + int len, r; + va_list tmp_args; + va_copy(tmp_args, args); + len = vsnprintf(buf, sizeof(buf), fmt, tmp_args); + va_end(tmp_args); + if (len < (int)sizeof(buf)) { + *strp = tor_strdup(buf); + return len; + } + strp_tmp = tor_malloc(len+1); + r = vsnprintf(strp_tmp, len+1, fmt, args); + if (r != len) { + tor_free(strp_tmp); + *strp = NULL; + return -1; + } + *strp = strp_tmp; + return len; +#endif +} + +/** Given hlen bytes at haystack and nlen bytes at + * needle, return a pointer to the first occurrence of the needle + * within the haystack, or NULL if there is no such occurrence. + * + * This function is not timing-safe. + * + * Requires that nlen be greater than zero. + */ +const void * +tor_memmem(const void *_haystack, size_t hlen, + const void *_needle, size_t nlen) +{ +#if defined(HAVE_MEMMEM) && (!defined(__GNUC__) || __GNUC__ >= 2) && !defined(__APPLE__) + tor_assert(nlen); + return memmem(_haystack, hlen, _needle, nlen); +#else + /* This isn't as fast as the GLIBC implementation, but it doesn't need to + * be. */ + const char *p, *end; + const char *haystack = (const char*)_haystack; + const char *needle = (const char*)_needle; + char first; + tor_assert(nlen); + + p = haystack; + end = haystack + hlen; + first = *(const char*)needle; + while ((p = memchr(p, first, end-p))) { + if (p+nlen > end) + return NULL; + if (fast_memeq(p, needle, nlen)) + return p; + ++p; + } + return NULL; +#endif +} + +/** + * Tables to implement ctypes-replacement TOR_IS*() functions. Each table + * has 256 bits to look up whether a character is in some set or not. This + * fails on non-ASCII platforms, but it is hard to find a platform whose + * character set is not a superset of ASCII nowadays. */ + +/**@{*/ +const uint32_t TOR_ISALPHA_TABLE[8] = + { 0, 0, 0x7fffffe, 0x7fffffe, 0, 0, 0, 0 }; +const uint32_t TOR_ISALNUM_TABLE[8] = + { 0, 0x3ff0000, 0x7fffffe, 0x7fffffe, 0, 0, 0, 0 }; +const uint32_t TOR_ISSPACE_TABLE[8] = { 0x3e00, 0x1, 0, 0, 0, 0, 0, 0 }; +const uint32_t TOR_ISXDIGIT_TABLE[8] = + { 0, 0x3ff0000, 0x7e, 0x7e, 0, 0, 0, 0 }; +const uint32_t TOR_ISDIGIT_TABLE[8] = { 0, 0x3ff0000, 0, 0, 0, 0, 0, 0 }; +const uint32_t TOR_ISPRINT_TABLE[8] = + { 0, 0xffffffff, 0xffffffff, 0x7fffffff, 0, 0, 0, 0x0 }; +const uint32_t TOR_ISUPPER_TABLE[8] = { 0, 0, 0x7fffffe, 0, 0, 0, 0, 0 }; +const uint32_t TOR_ISLOWER_TABLE[8] = { 0, 0, 0, 0x7fffffe, 0, 0, 0, 0 }; + +/** Upper-casing and lowercasing tables to map characters to upper/lowercase + * equivalents. Used by tor_toupper() and tor_tolower(). */ +/**@{*/ +const char TOR_TOUPPER_TABLE[256] = { + 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, + 16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31, + 32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47, + 48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63, + 64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79, + 80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95, + 96,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79, + 80,81,82,83,84,85,86,87,88,89,90,123,124,125,126,127, + 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, + 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159, + 160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175, + 176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191, + 192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207, + 208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223, + 224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239, + 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255, +}; +const char TOR_TOLOWER_TABLE[256] = { + 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, + 16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31, + 32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47, + 48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63, + 64,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111, + 112,113,114,115,116,117,118,119,120,121,122,91,92,93,94,95, + 96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111, + 112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127, + 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, + 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159, + 160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175, + 176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191, + 192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207, + 208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223, + 224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239, + 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255, +}; +/**@}*/ + +/** Helper for tor_strtok_r_impl: Advances cp past all characters in + * sep, and returns its new value. */ +static char * +strtok_helper(char *cp, const char *sep) +{ + if (sep[1]) { + while (*cp && strchr(sep, *cp)) + ++cp; + } else { + while (*cp && *cp == *sep) + ++cp; + } + return cp; +} + +/** Implementation of strtok_r for platforms whose coders haven't figured out + * how to write one. Hey guys! You can use this code here for free! */ +char * +tor_strtok_r_impl(char *str, const char *sep, char **lasts) +{ + char *cp, *start; + tor_assert(*sep); + if (str) { + str = strtok_helper(str, sep); + if (!*str) + return NULL; + start = cp = *lasts = str; + } else if (!*lasts || !**lasts) { + return NULL; + } else { + start = cp = *lasts; + } + + if (sep[1]) { + while (*cp && !strchr(sep, *cp)) + ++cp; + } else { + cp = strchr(cp, *sep); + } + + if (!cp || !*cp) { + *lasts = NULL; + } else { + *cp++ = '\0'; + *lasts = strtok_helper(cp, sep); + } + return start; +} + +#ifdef _WIN32 +/** Take a filename and return a pointer to its final element. This + * function is called on __FILE__ to fix a MSVC nit where __FILE__ + * contains the full path to the file. This is bad, because it + * confuses users to find the home directory of the person who + * compiled the binary in their warning messages. + */ +const char * +tor_fix_source_file(const char *fname) +{ + const char *cp1, *cp2, *r; + cp1 = strrchr(fname, '/'); + cp2 = strrchr(fname, '\\'); + if (cp1 && cp2) { + r = (cp1cp. Equivalent to + * *(uint16_t*)(cp), but will not cause segfaults on platforms that forbid + * unaligned memory access. + */ +uint16_t +get_uint16(const void *cp) +{ + uint16_t v; + memcpy(&v,cp,2); + return v; +} +/** + * Read a 32-bit value beginning at cp. Equivalent to + * *(uint32_t*)(cp), but will not cause segfaults on platforms that forbid + * unaligned memory access. + */ +uint32_t +get_uint32(const void *cp) +{ + uint32_t v; + memcpy(&v,cp,4); + return v; +} +/** + * Read a 64-bit value beginning at cp. Equivalent to + * *(uint64_t*)(cp), but will not cause segfaults on platforms that forbid + * unaligned memory access. + */ +uint64_t +get_uint64(const void *cp) +{ + uint64_t v; + memcpy(&v,cp,8); + return v; +} + +/** + * Set a 16-bit value beginning at cp to v. Equivalent to + * *(uint16_t*)(cp) = v, but will not cause segfaults on platforms that forbid + * unaligned memory access. */ +void +set_uint16(void *cp, uint16_t v) +{ + memcpy(cp,&v,2); +} +/** + * Set a 32-bit value beginning at cp to v. Equivalent to + * *(uint32_t*)(cp) = v, but will not cause segfaults on platforms that forbid + * unaligned memory access. */ +void +set_uint32(void *cp, uint32_t v) +{ + memcpy(cp,&v,4); +} +/** + * Set a 64-bit value beginning at cp to v. Equivalent to + * *(uint64_t*)(cp) = v, but will not cause segfaults on platforms that forbid + * unaligned memory access. */ +void +set_uint64(void *cp, uint64_t v) +{ + memcpy(cp,&v,8); +} + +/** + * Rename the file from to the file to. On Unix, this is + * the same as rename(2). On windows, this removes to first if + * it already exists. + * Returns 0 on success. Returns -1 and sets errno on failure. + */ +int +replace_file(const char *from, const char *to) +{ +#ifndef _WIN32 + return rename(from,to); +#else + switch (file_status(to)) + { + case FN_NOENT: + break; + case FN_FILE: + if (unlink(to)) return -1; + break; + case FN_ERROR: + return -1; + case FN_DIR: + errno = EISDIR; + return -1; + } + return rename(from,to); +#endif +} + +/** Change fname's modification time to now. */ +int +touch_file(const char *fname) +{ + if (utime(fname, NULL)!=0) + return -1; + return 0; +} + +/** Represents a lockfile on which we hold the lock. */ +struct tor_lockfile_t { + /** Name of the file */ + char *filename; + /** File descriptor used to hold the file open */ + int fd; +}; + +/** Try to get a lock on the lockfile filename, creating it as + * necessary. If someone else has the lock and blocking is true, + * wait until the lock is available. Otherwise return immediately whether + * we succeeded or not. + * + * Set *locked_out to true if somebody else had the lock, and to false + * otherwise. + * + * Return a tor_lockfile_t on success, NULL on failure. + * + * (Implementation note: because we need to fall back to fcntl on some + * platforms, these locks are per-process, not per-thread. If you want + * to do in-process locking, use tor_mutex_t like a normal person. + * On Windows, when blocking is true, the maximum time that + * is actually waited is 10 seconds, after which NULL is returned + * and locked_out is set to 1.) + */ +tor_lockfile_t * +tor_lockfile_lock(const char *filename, int blocking, int *locked_out) +{ + tor_lockfile_t *result; + int fd; + *locked_out = 0; + + log_info(LD_FS, "Locking \"%s\"", filename); + fd = tor_open_cloexec(filename, O_RDWR|O_CREAT|O_TRUNC, 0600); + if (fd < 0) { + log_warn(LD_FS,"Couldn't open \"%s\" for locking: %s", filename, + strerror(errno)); + return NULL; + } + +#ifdef _WIN32 + _lseek(fd, 0, SEEK_SET); + if (_locking(fd, blocking ? _LK_LOCK : _LK_NBLCK, 1) < 0) { + if (errno != EACCES && errno != EDEADLOCK) + log_warn(LD_FS,"Couldn't lock \"%s\": %s", filename, strerror(errno)); + else + *locked_out = 1; + close(fd); + return NULL; + } +#elif defined(HAVE_FLOCK) + if (flock(fd, LOCK_EX|(blocking ? 0 : LOCK_NB)) < 0) { + if (errno != EWOULDBLOCK) + log_warn(LD_FS,"Couldn't lock \"%s\": %s", filename, strerror(errno)); + else + *locked_out = 1; + close(fd); + return NULL; + } +#else + { + struct flock lock; + memset(&lock, 0, sizeof(lock)); + lock.l_type = F_WRLCK; + lock.l_whence = SEEK_SET; + if (fcntl(fd, blocking ? F_SETLKW : F_SETLK, &lock) < 0) { + if (errno != EACCES && errno != EAGAIN) + log_warn(LD_FS, "Couldn't lock \"%s\": %s", filename, strerror(errno)); + else + *locked_out = 1; + close(fd); + return NULL; + } + } +#endif + + result = tor_malloc(sizeof(tor_lockfile_t)); + result->filename = tor_strdup(filename); + result->fd = fd; + return result; +} + +/** Release the lock held as lockfile. */ +void +tor_lockfile_unlock(tor_lockfile_t *lockfile) +{ + tor_assert(lockfile); + + log_info(LD_FS, "Unlocking \"%s\"", lockfile->filename); +#ifdef _WIN32 + _lseek(lockfile->fd, 0, SEEK_SET); + if (_locking(lockfile->fd, _LK_UNLCK, 1) < 0) { + log_warn(LD_FS,"Error unlocking \"%s\": %s", lockfile->filename, + strerror(errno)); + } +#elif defined(HAVE_FLOCK) + if (flock(lockfile->fd, LOCK_UN) < 0) { + log_warn(LD_FS, "Error unlocking \"%s\": %s", lockfile->filename, + strerror(errno)); + } +#else + /* Closing the lockfile is sufficient. */ +#endif + + close(lockfile->fd); + lockfile->fd = -1; + tor_free(lockfile->filename); + tor_free(lockfile); +} + +/** @{ */ +/** Some old versions of Unix didn't define constants for these values, + * and instead expect you to say 0, 1, or 2. */ +#ifndef SEEK_SET +#define SEEK_SET 0 +#endif +#ifndef SEEK_CUR +#define SEEK_CUR 1 +#endif +#ifndef SEEK_END +#define SEEK_END 2 +#endif +/** @} */ + +/** Return the position of fd with respect to the start of the file. */ +off_t +tor_fd_getpos(int fd) +{ +#ifdef _WIN32 + return (off_t) _lseek(fd, 0, SEEK_CUR); +#else + return (off_t) lseek(fd, 0, SEEK_CUR); +#endif +} + +/** Move fd to the end of the file. Return -1 on error, 0 on success. */ +int +tor_fd_seekend(int fd) +{ +#ifdef _WIN32 + return _lseek(fd, 0, SEEK_END) < 0 ? -1 : 0; +#else + return lseek(fd, 0, SEEK_END) < 0 ? -1 : 0; +#endif +} + +/** Move fd to position pos in the file. Return -1 on error, 0 + * on success. */ +int +tor_fd_setpos(int fd, off_t pos) +{ +#ifdef _WIN32 + return _lseek(fd, pos, SEEK_SET) < 0 ? -1 : 0; +#else + return lseek(fd, pos, SEEK_SET) < 0 ? -1 : 0; +#endif +} + +#undef DEBUG_SOCKET_COUNTING +#ifdef DEBUG_SOCKET_COUNTING +/** A bitarray of all fds that should be passed to tor_socket_close(). Only + * used if DEBUG_SOCKET_COUNTING is defined. */ +static bitarray_t *open_sockets = NULL; +/** The size of open_sockets, in bits. */ +static int max_socket = -1; +#endif + +/** Count of number of sockets currently open. (Undercounts sockets opened by + * eventdns and libevent.) */ +static int n_sockets_open = 0; + +/** Mutex to protect open_sockets, max_socket, and n_sockets_open. */ +static tor_mutex_t *socket_accounting_mutex = NULL; + +/** Helper: acquire the socket accounting lock. */ +static INLINE void +socket_accounting_lock(void) +{ + if (PREDICT_UNLIKELY(!socket_accounting_mutex)) + socket_accounting_mutex = tor_mutex_new(); + tor_mutex_acquire(socket_accounting_mutex); +} + +/** Helper: release the socket accounting lock. */ +static INLINE void +socket_accounting_unlock(void) +{ + tor_mutex_release(socket_accounting_mutex); +} + +/** As close(), but guaranteed to work for sockets across platforms (including + * Windows, where close()ing a socket doesn't work. Returns 0 on success and + * the socket error code on failure. */ +int +tor_close_socket_simple(tor_socket_t s) +{ + int r = 0; + + /* On Windows, you have to call close() on fds returned by open(), + * and closesocket() on fds returned by socket(). On Unix, everything + * gets close()'d. We abstract this difference by always using + * tor_close_socket to close sockets, and always using close() on + * files. + */ + #if defined(_WIN32) + r = closesocket(s); + #else + r = close(s); + #endif + + if (r != 0) { + int err = tor_socket_errno(-1); + log_info(LD_NET, "Close returned an error: %s", tor_socket_strerror(err)); + return err; + } + + return r; +} + +/** As tor_close_socket_simple(), but keeps track of the number + * of open sockets. Returns 0 on success, -1 on failure. */ +int +tor_close_socket(tor_socket_t s) +{ + int r = tor_close_socket_simple(s); + + socket_accounting_lock(); +#ifdef DEBUG_SOCKET_COUNTING + if (s > max_socket || ! bitarray_is_set(open_sockets, s)) { + log_warn(LD_BUG, "Closing a socket (%d) that wasn't returned by tor_open_" + "socket(), or that was already closed or something.", s); + } else { + tor_assert(open_sockets && s <= max_socket); + bitarray_clear(open_sockets, s); + } +#endif + if (r == 0) { + --n_sockets_open; + } else { +#ifdef _WIN32 + if (r != WSAENOTSOCK) + --n_sockets_open; +#else + if (r != EBADF) + --n_sockets_open; +#endif + r = -1; + } + + if (n_sockets_open < 0) + log_warn(LD_BUG, "Our socket count is below zero: %d. Please submit a " + "bug report.", n_sockets_open); + socket_accounting_unlock(); + return r; +} + +/** @{ */ +#ifdef DEBUG_SOCKET_COUNTING +/** Helper: if DEBUG_SOCKET_COUNTING is enabled, remember that s is + * now an open socket. */ +static INLINE void +mark_socket_open(tor_socket_t s) +{ + /* XXXX This bitarray business will NOT work on windows: sockets aren't + small ints there. */ + if (s > max_socket) { + if (max_socket == -1) { + open_sockets = bitarray_init_zero(s+128); + max_socket = s+128; + } else { + open_sockets = bitarray_expand(open_sockets, max_socket, s+128); + max_socket = s+128; + } + } + if (bitarray_is_set(open_sockets, s)) { + log_warn(LD_BUG, "I thought that %d was already open, but socket() just " + "gave it to me!", s); + } + bitarray_set(open_sockets, s); +} +#else +#define mark_socket_open(s) STMT_NIL +#endif +/** @} */ + +/** As socket(), but counts the number of open sockets. */ +tor_socket_t +tor_open_socket(int domain, int type, int protocol) +{ + return tor_open_socket_with_extensions(domain, type, protocol, 1, 0); +} + +/** As socket(), but creates a nonblocking socket and + * counts the number of open sockets. */ +tor_socket_t +tor_open_socket_nonblocking(int domain, int type, int protocol) +{ + return tor_open_socket_with_extensions(domain, type, protocol, 1, 1); +} + +/** As socket(), but counts the number of open sockets and handles + * socket creation with either of SOCK_CLOEXEC and SOCK_NONBLOCK specified. + * cloexec and nonblock should be either 0 or 1 to indicate + * if the corresponding extension should be used.*/ +tor_socket_t +tor_open_socket_with_extensions(int domain, int type, int protocol, + int cloexec, int nonblock) +{ + tor_socket_t s; +#if defined(SOCK_CLOEXEC) && defined(SOCK_NONBLOCK) + int ext_flags = (cloexec ? SOCK_CLOEXEC : 0) | + (nonblock ? SOCK_NONBLOCK : 0); + s = socket(domain, type|ext_flags, protocol); + if (SOCKET_OK(s)) + goto socket_ok; + /* If we got an error, see if it is EINVAL. EINVAL might indicate that, + * even though we were built on a system with SOCK_CLOEXEC and SOCK_NONBLOCK + * support, we are running on one without. */ + if (errno != EINVAL) + return s; +#endif /* SOCK_CLOEXEC && SOCK_NONBLOCK */ + + s = socket(domain, type, protocol); + if (! SOCKET_OK(s)) + return s; + +#if defined(FD_CLOEXEC) + if (cloexec) { + if (fcntl(s, F_SETFD, FD_CLOEXEC) == -1) { + log_warn(LD_FS,"Couldn't set FD_CLOEXEC: %s", strerror(errno)); + tor_close_socket_simple(s); + return TOR_INVALID_SOCKET; + } + } +#else + (void)cloexec; +#endif + + if (nonblock) { + if (set_socket_nonblocking(s) == -1) { + tor_close_socket_simple(s); + return TOR_INVALID_SOCKET; + } + } + + goto socket_ok; /* So that socket_ok will not be unused. */ + + socket_ok: + socket_accounting_lock(); + ++n_sockets_open; + mark_socket_open(s); + socket_accounting_unlock(); + return s; +} + +/** As accept(), but counts the number of open sockets. */ +tor_socket_t +tor_accept_socket(tor_socket_t sockfd, struct sockaddr *addr, socklen_t *len) +{ + return tor_accept_socket_with_extensions(sockfd, addr, len, 1, 0); +} + +/** As accept(), but returns a nonblocking socket and + * counts the number of open sockets. */ +tor_socket_t +tor_accept_socket_nonblocking(tor_socket_t sockfd, struct sockaddr *addr, + socklen_t *len) +{ + return tor_accept_socket_with_extensions(sockfd, addr, len, 1, 1); +} + +/** As accept(), but counts the number of open sockets and handles + * socket creation with either of SOCK_CLOEXEC and SOCK_NONBLOCK specified. + * cloexec and nonblock should be either 0 or 1 to indicate + * if the corresponding extension should be used.*/ +tor_socket_t +tor_accept_socket_with_extensions(tor_socket_t sockfd, struct sockaddr *addr, + socklen_t *len, int cloexec, int nonblock) +{ + tor_socket_t s; +#if defined(HAVE_ACCEPT4) && defined(SOCK_CLOEXEC) && defined(SOCK_NONBLOCK) + int ext_flags = (cloexec ? SOCK_CLOEXEC : 0) | + (nonblock ? SOCK_NONBLOCK : 0); + s = accept4(sockfd, addr, len, ext_flags); + if (SOCKET_OK(s)) + goto socket_ok; + /* If we got an error, see if it is ENOSYS. ENOSYS indicates that, + * even though we were built on a system with accept4 support, we + * are running on one without. Also, check for EINVAL, which indicates that + * we are missing SOCK_CLOEXEC/SOCK_NONBLOCK support. */ + if (errno != EINVAL && errno != ENOSYS) + return s; +#endif + + s = accept(sockfd, addr, len); + if (!SOCKET_OK(s)) + return s; + +#if defined(FD_CLOEXEC) + if (cloexec) { + if (fcntl(s, F_SETFD, FD_CLOEXEC) == -1) { + log_warn(LD_NET, "Couldn't set FD_CLOEXEC: %s", strerror(errno)); + tor_close_socket_simple(s); + return TOR_INVALID_SOCKET; + } + } +#else + (void)cloexec; +#endif + + if (nonblock) { + if (set_socket_nonblocking(s) == -1) { + tor_close_socket_simple(s); + return TOR_INVALID_SOCKET; + } + } + + goto socket_ok; /* So that socket_ok will not be unused. */ + + socket_ok: + socket_accounting_lock(); + ++n_sockets_open; + mark_socket_open(s); + socket_accounting_unlock(); + return s; +} + +/** Return the number of sockets we currently have opened. */ +int +get_n_open_sockets(void) +{ + int n; + socket_accounting_lock(); + n = n_sockets_open; + socket_accounting_unlock(); + return n; +} + +/** Turn socket into a nonblocking socket. Return 0 on success, -1 + * on failure. + */ +int +set_socket_nonblocking(tor_socket_t socket) +{ +#if defined(_WIN32) + unsigned long nonblocking = 1; + ioctlsocket(socket, FIONBIO, (unsigned long*) &nonblocking); +#else + int flags; + + flags = fcntl(socket, F_GETFL, 0); + if (flags == -1) { + log_warn(LD_NET, "Couldn't get file status flags: %s", strerror(errno)); + return -1; + } + flags |= O_NONBLOCK; + if (fcntl(socket, F_SETFL, flags) == -1) { + log_warn(LD_NET, "Couldn't set file status flags: %s", strerror(errno)); + return -1; + } +#endif + + return 0; +} + +/** + * Allocate a pair of connected sockets. (Like socketpair(family, + * type,protocol,fd), but works on systems that don't have + * socketpair.) + * + * Currently, only (AF_UNIX, SOCK_STREAM, 0) sockets are supported. + * + * Note that on systems without socketpair, this call will fail if + * localhost is inaccessible (for example, if the networking + * stack is down). And even if it succeeds, the socket pair will not + * be able to read while localhost is down later (the socket pair may + * even close, depending on OS-specific timeouts). + * + * Returns 0 on success and -errno on failure; do not rely on the value + * of errno or WSAGetLastError(). + **/ +/* It would be nicer just to set errno, but that won't work for windows. */ +int +tor_socketpair(int family, int type, int protocol, tor_socket_t fd[2]) +{ +//don't use win32 socketpairs (they are always bad) +#if defined(HAVE_SOCKETPAIR) && !defined(_WIN32) + int r; + +#ifdef SOCK_CLOEXEC + r = socketpair(family, type|SOCK_CLOEXEC, protocol, fd); + if (r == 0) + goto sockets_ok; + /* If we got an error, see if it is EINVAL. EINVAL might indicate that, + * even though we were built on a system with SOCK_CLOEXEC support, we + * are running on one without. */ + if (errno != EINVAL) + return -errno; +#endif + + r = socketpair(family, type, protocol, fd); + if (r < 0) + return -errno; + +#if defined(FD_CLOEXEC) + if (SOCKET_OK(fd[0])) { + r = fcntl(fd[0], F_SETFD, FD_CLOEXEC); + if (r == -1) { + close(fd[0]); + close(fd[1]); + return -errno; + } + } + if (SOCKET_OK(fd[1])) { + r = fcntl(fd[1], F_SETFD, FD_CLOEXEC); + if (r == -1) { + close(fd[0]); + close(fd[1]); + return -errno; + } + } +#endif + goto sockets_ok; /* So that sockets_ok will not be unused. */ + + sockets_ok: + socket_accounting_lock(); + if (SOCKET_OK(fd[0])) { + ++n_sockets_open; + mark_socket_open(fd[0]); + } + if (SOCKET_OK(fd[1])) { + ++n_sockets_open; + mark_socket_open(fd[1]); + } + socket_accounting_unlock(); + + return 0; +#else + return tor_ersatz_socketpair(family, type, protocol, fd); +#endif +} + +#ifdef NEED_ERSATZ_SOCKETPAIR +/** + * Helper used to implement socketpair on systems that lack it, by + * making a direct connection to localhost. + */ +STATIC int +tor_ersatz_socketpair(int family, int type, int protocol, tor_socket_t fd[2]) +{ + /* This socketpair does not work when localhost is down. So + * it's really not the same thing at all. But it's close enough + * for now, and really, when localhost is down sometimes, we + * have other problems too. + */ + tor_socket_t listener = TOR_INVALID_SOCKET; + tor_socket_t connector = TOR_INVALID_SOCKET; + tor_socket_t acceptor = TOR_INVALID_SOCKET; + struct sockaddr_in listen_addr; + struct sockaddr_in connect_addr; + socklen_t size; + int saved_errno = -1; + + if (protocol +#ifdef AF_UNIX + || family != AF_UNIX +#endif + ) { +#ifdef _WIN32 + return -WSAEAFNOSUPPORT; +#else + return -EAFNOSUPPORT; +#endif + } + if (!fd) { + return -EINVAL; + } + + listener = tor_open_socket(AF_INET, type, 0); + if (!SOCKET_OK(listener)) + return -tor_socket_errno(-1); + memset(&listen_addr, 0, sizeof(listen_addr)); + listen_addr.sin_family = AF_INET; + listen_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + listen_addr.sin_port = 0; /* kernel chooses port. */ + if (bind(listener, (struct sockaddr *) &listen_addr, sizeof (listen_addr)) + == -1) + goto tidy_up_and_fail; + if (listen(listener, 1) == -1) + goto tidy_up_and_fail; + + connector = tor_open_socket(AF_INET, type, 0); + if (!SOCKET_OK(connector)) + goto tidy_up_and_fail; + /* We want to find out the port number to connect to. */ + size = sizeof(connect_addr); + if (getsockname(listener, (struct sockaddr *) &connect_addr, &size) == -1) + goto tidy_up_and_fail; + if (size != sizeof (connect_addr)) + goto abort_tidy_up_and_fail; + if (connect(connector, (struct sockaddr *) &connect_addr, + sizeof(connect_addr)) == -1) + goto tidy_up_and_fail; + + size = sizeof(listen_addr); + acceptor = tor_accept_socket(listener, + (struct sockaddr *) &listen_addr, &size); + if (!SOCKET_OK(acceptor)) + goto tidy_up_and_fail; + if (size != sizeof(listen_addr)) + goto abort_tidy_up_and_fail; + /* Now check we are talking to ourself by matching port and host on the + two sockets. */ + if (getsockname(connector, (struct sockaddr *) &connect_addr, &size) == -1) + goto tidy_up_and_fail; + if (size != sizeof (connect_addr) + || listen_addr.sin_family != connect_addr.sin_family + || listen_addr.sin_addr.s_addr != connect_addr.sin_addr.s_addr + || listen_addr.sin_port != connect_addr.sin_port) { + goto abort_tidy_up_and_fail; + } + tor_close_socket(listener); + fd[0] = connector; + fd[1] = acceptor; + + return 0; + + abort_tidy_up_and_fail: +#ifdef _WIN32 + saved_errno = WSAECONNABORTED; +#else + saved_errno = ECONNABORTED; /* I hope this is portable and appropriate. */ +#endif + tidy_up_and_fail: + if (saved_errno < 0) + saved_errno = errno; + if (SOCKET_OK(listener)) + tor_close_socket(listener); + if (SOCKET_OK(connector)) + tor_close_socket(connector); + if (SOCKET_OK(acceptor)) + tor_close_socket(acceptor); + return -saved_errno; +} +#endif + +/** Number of extra file descriptors to keep in reserve beyond those that we + * tell Tor it's allowed to use. */ +#define ULIMIT_BUFFER 32 /* keep 32 extra fd's beyond ConnLimit_ */ + +/** Learn the maximum allowed number of file descriptors, and tell the system + * we want to use up to that number. (Some systems have a low soft limit, and + * let us set it higher.) + * + * We compute this by finding the largest number that we can use. + * If we can't find a number greater than or equal to limit, + * then we fail: return -1. + * + * If limit is 0, then do not adjust the current maximum. + * + * Otherwise, return 0 and store the maximum we found inside max_out.*/ +int +set_max_file_descriptors(rlim_t limit, int *max_out) +{ + /* Define some maximum connections values for systems where we cannot + * automatically determine a limit. Re Cygwin, see + * http://archives.seul.org/or/talk/Aug-2006/msg00210.html + * For an iPhone, 9999 should work. For Windows and all other unknown + * systems we use 15000 as the default. */ +#ifndef HAVE_GETRLIMIT +#if defined(CYGWIN) || defined(__CYGWIN__) + const char *platform = "Cygwin"; + const unsigned long MAX_CONNECTIONS = 3200; +#elif defined(_WIN32) + const char *platform = "Windows"; + const unsigned long MAX_CONNECTIONS = 15000; +#else + const char *platform = "unknown platforms with no getrlimit()"; + const unsigned long MAX_CONNECTIONS = 15000; +#endif + log_fn(LOG_INFO, LD_NET, + "This platform is missing getrlimit(). Proceeding."); + if (limit > MAX_CONNECTIONS) { + log_warn(LD_CONFIG, + "We do not support more than %lu file descriptors " + "on %s. Tried to raise to %lu.", + (unsigned long)MAX_CONNECTIONS, platform, (unsigned long)limit); + return -1; + } + limit = MAX_CONNECTIONS; +#else /* HAVE_GETRLIMIT */ + struct rlimit rlim; + + if (getrlimit(RLIMIT_NOFILE, &rlim) != 0) { + log_warn(LD_NET, "Could not get maximum number of file descriptors: %s", + strerror(errno)); + return -1; + } + if (limit == 0) { + /* If limit == 0, return the maximum value without setting it. */ + limit = rlim.rlim_max; + if (limit > INT_MAX) + limit = INT_MAX; + *max_out = (int)limit - ULIMIT_BUFFER; + return 0; + } + if (rlim.rlim_max < limit) { + log_warn(LD_CONFIG,"We need %lu file descriptors available, and we're " + "limited to %lu. Please change your ulimit -n.", + (unsigned long)limit, (unsigned long)rlim.rlim_max); + return -1; + } + + if (rlim.rlim_max > rlim.rlim_cur) { + log_info(LD_NET,"Raising max file descriptors from %lu to %lu.", + (unsigned long)rlim.rlim_cur, (unsigned long)rlim.rlim_max); + } + rlim.rlim_cur = rlim.rlim_max; + + if (setrlimit(RLIMIT_NOFILE, &rlim) != 0) { + int bad = 1; +#ifdef OPEN_MAX + if (errno == EINVAL && OPEN_MAX < rlim.rlim_cur) { + /* On some platforms, OPEN_MAX is the real limit, and getrlimit() is + * full of nasty lies. I'm looking at you, OSX 10.5.... */ + rlim.rlim_cur = OPEN_MAX; + if (setrlimit(RLIMIT_NOFILE, &rlim) == 0) { + if (rlim.rlim_cur < (rlim_t)limit) { + log_warn(LD_CONFIG, "We are limited to %lu file descriptors by " + "OPEN_MAX, and ConnLimit is %lu. Changing ConnLimit; sorry.", + (unsigned long)OPEN_MAX, (unsigned long)limit); + } else { + log_info(LD_CONFIG, "Dropped connection limit to OPEN_MAX (%lu); " + "Apparently, %lu was too high and rlimit lied to us.", + (unsigned long)OPEN_MAX, (unsigned long)rlim.rlim_max); + } + bad = 0; + } + } +#endif /* OPEN_MAX */ + if (bad) { + log_warn(LD_CONFIG,"Couldn't set maximum number of file descriptors: %s", + strerror(errno)); + return -1; + } + } + /* leave some overhead for logs, etc, */ + limit = rlim.rlim_cur; +#endif /* HAVE_GETRLIMIT */ + + if (limit < ULIMIT_BUFFER) { + log_warn(LD_CONFIG, + "ConnLimit must be at least %d. Failing.", ULIMIT_BUFFER); + return -1; + } + if (limit > INT_MAX) + limit = INT_MAX; + tor_assert(max_out); + *max_out = (int)limit - ULIMIT_BUFFER; + return 0; +} + +#ifndef _WIN32 +/** Log details of current user and group credentials. Return 0 on + * success. Logs and return -1 on failure. + */ +static int +log_credential_status(void) +{ +/** Log level to use when describing non-error UID/GID status. */ +#define CREDENTIAL_LOG_LEVEL LOG_INFO + /* Real, effective and saved UIDs */ + uid_t ruid, euid, suid; + /* Read, effective and saved GIDs */ + gid_t rgid, egid, sgid; + /* Supplementary groups */ + gid_t *sup_gids = NULL; + int sup_gids_size; + /* Number of supplementary groups */ + int ngids; + + /* log UIDs */ +#ifdef HAVE_GETRESUID + if (getresuid(&ruid, &euid, &suid) != 0 ) { + log_warn(LD_GENERAL, "Error getting changed UIDs: %s", strerror(errno)); + return -1; + } else { + log_fn(CREDENTIAL_LOG_LEVEL, LD_GENERAL, + "UID is %u (real), %u (effective), %u (saved)", + (unsigned)ruid, (unsigned)euid, (unsigned)suid); + } +#else + /* getresuid is not present on MacOS X, so we can't get the saved (E)UID */ + ruid = getuid(); + euid = geteuid(); + (void)suid; + + log_fn(CREDENTIAL_LOG_LEVEL, LD_GENERAL, + "UID is %u (real), %u (effective), unknown (saved)", + (unsigned)ruid, (unsigned)euid); +#endif + + /* log GIDs */ +#ifdef HAVE_GETRESGID + if (getresgid(&rgid, &egid, &sgid) != 0 ) { + log_warn(LD_GENERAL, "Error getting changed GIDs: %s", strerror(errno)); + return -1; + } else { + log_fn(CREDENTIAL_LOG_LEVEL, LD_GENERAL, + "GID is %u (real), %u (effective), %u (saved)", + (unsigned)rgid, (unsigned)egid, (unsigned)sgid); + } +#else + /* getresgid is not present on MacOS X, so we can't get the saved (E)GID */ + rgid = getgid(); + egid = getegid(); + (void)sgid; + log_fn(CREDENTIAL_LOG_LEVEL, LD_GENERAL, + "GID is %u (real), %u (effective), unknown (saved)", + (unsigned)rgid, (unsigned)egid); +#endif + + /* log supplementary groups */ + sup_gids_size = 64; + sup_gids = tor_malloc(sizeof(gid_t) * 64); + while ((ngids = getgroups(sup_gids_size, sup_gids)) < 0 && + errno == EINVAL && + sup_gids_size < NGROUPS_MAX) { + sup_gids_size *= 2; + sup_gids = tor_realloc(sup_gids, sizeof(gid_t) * sup_gids_size); + } + + if (ngids < 0) { + log_warn(LD_GENERAL, "Error getting supplementary GIDs: %s", + strerror(errno)); + tor_free(sup_gids); + return -1; + } else { + int i, retval = 0; + char *s = NULL; + smartlist_t *elts = smartlist_new(); + + for (i = 0; iuser and switch to their + * primary group. Return 0 on success. On failure, log and return -1. + */ +int +switch_id(const char *user) +{ +#ifndef _WIN32 + struct passwd *pw = NULL; + uid_t old_uid; + gid_t old_gid; + static int have_already_switched_id = 0; + + tor_assert(user); + + if (have_already_switched_id) + return 0; + + /* Log the initial credential state */ + if (log_credential_status()) + return -1; + + log_fn(CREDENTIAL_LOG_LEVEL, LD_GENERAL, "Changing user and groups"); + + /* Get old UID/GID to check if we changed correctly */ + old_uid = getuid(); + old_gid = getgid(); + + /* Lookup the user and group information, if we have a problem, bail out. */ + pw = getpwnam(user); + if (pw == NULL) { + log_warn(LD_CONFIG, "Error setting configured user: %s not found", user); + return -1; + } + + /* Properly switch egid,gid,euid,uid here or bail out */ + if (setgroups(1, &pw->pw_gid)) { + log_warn(LD_GENERAL, "Error setting groups to gid %d: \"%s\".", + (int)pw->pw_gid, strerror(errno)); + if (old_uid == pw->pw_uid) { + log_warn(LD_GENERAL, "Tor is already running as %s. You do not need " + "the \"User\" option if you are already running as the user " + "you want to be. (If you did not set the User option in your " + "torrc, check whether it was specified on the command line " + "by a startup script.)", user); + } else { + log_warn(LD_GENERAL, "If you set the \"User\" option, you must start Tor" + " as root."); + } + return -1; + } + + if (setegid(pw->pw_gid)) { + log_warn(LD_GENERAL, "Error setting egid to %d: %s", + (int)pw->pw_gid, strerror(errno)); + return -1; + } + + if (setgid(pw->pw_gid)) { + log_warn(LD_GENERAL, "Error setting gid to %d: %s", + (int)pw->pw_gid, strerror(errno)); + return -1; + } + + if (setuid(pw->pw_uid)) { + log_warn(LD_GENERAL, "Error setting configured uid to %s (%d): %s", + user, (int)pw->pw_uid, strerror(errno)); + return -1; + } + + if (seteuid(pw->pw_uid)) { + log_warn(LD_GENERAL, "Error setting configured euid to %s (%d): %s", + user, (int)pw->pw_uid, strerror(errno)); + return -1; + } + + /* This is how OpenBSD rolls: + if (setgroups(1, &pw->pw_gid) || setegid(pw->pw_gid) || + setgid(pw->pw_gid) || setuid(pw->pw_uid) || seteuid(pw->pw_uid)) { + setgid(pw->pw_gid) || seteuid(pw->pw_uid) || setuid(pw->pw_uid)) { + log_warn(LD_GENERAL, "Error setting configured UID/GID: %s", + strerror(errno)); + return -1; + } + */ + + /* We've properly switched egid, gid, euid, uid, and supplementary groups if + * we're here. */ + +#if !defined(CYGWIN) && !defined(__CYGWIN__) + /* If we tried to drop privilege to a group/user other than root, attempt to + * restore root (E)(U|G)ID, and abort if the operation succeeds */ + + /* Only check for privilege dropping if we were asked to be non-root */ + if (pw->pw_uid) { + /* Try changing GID/EGID */ + if (pw->pw_gid != old_gid && + (setgid(old_gid) != -1 || setegid(old_gid) != -1)) { + log_warn(LD_GENERAL, "Was able to restore group credentials even after " + "switching GID: this means that the setgid code didn't work."); + return -1; + } + + /* Try changing UID/EUID */ + if (pw->pw_uid != old_uid && + (setuid(old_uid) != -1 || seteuid(old_uid) != -1)) { + log_warn(LD_GENERAL, "Was able to restore user credentials even after " + "switching UID: this means that the setuid code didn't work."); + return -1; + } + } +#endif + + /* Check what really happened */ + if (log_credential_status()) { + return -1; + } + + have_already_switched_id = 1; /* mark success so we never try again */ + +#if defined(__linux__) && defined(HAVE_SYS_PRCTL_H) && defined(HAVE_PRCTL) +#ifdef PR_SET_DUMPABLE + if (pw->pw_uid) { + /* Re-enable core dumps if we're not running as root. */ + log_info(LD_CONFIG, "Re-enabling coredumps"); + if (prctl(PR_SET_DUMPABLE, 1)) { + log_warn(LD_CONFIG, "Unable to re-enable coredumps: %s",strerror(errno)); + } + } +#endif +#endif + return 0; + +#else + (void)user; + + log_warn(LD_CONFIG, + "User specified but switching users is unsupported on your OS."); + return -1; +#endif +} + +/* We only use the linux prctl for now. There is no Win32 support; this may + * also work on various BSD systems and Mac OS X - send testing feedback! + * + * On recent Gnu/Linux kernels it is possible to create a system-wide policy + * that will prevent non-root processes from attaching to other processes + * unless they are the parent process; thus gdb can attach to programs that + * they execute but they cannot attach to other processes running as the same + * user. The system wide policy may be set with the sysctl + * kernel.yama.ptrace_scope or by inspecting + * /proc/sys/kernel/yama/ptrace_scope and it is 1 by default on Ubuntu 11.04. + * + * This ptrace scope will be ignored on Gnu/Linux for users with + * CAP_SYS_PTRACE and so it is very likely that root will still be able to + * attach to the Tor process. + */ +/** Attempt to disable debugger attachment: return 1 on success, -1 on + * failure, and 0 if we don't know how to try on this platform. */ +int +tor_disable_debugger_attach(void) +{ + int r, attempted; + r = -1; + attempted = 0; + log_debug(LD_CONFIG, + "Attemping to disable debugger attachment to Tor for " + "unprivileged users."); +#if defined(__linux__) && defined(HAVE_SYS_PRCTL_H) && defined(HAVE_PRCTL) +#ifdef PR_SET_DUMPABLE + attempted = 1; + r = prctl(PR_SET_DUMPABLE, 0); +#endif +#endif +#if defined(__APPLE__) && defined(PT_DENY_ATTACH) + if (r < 0) { + attempted = 1; + r = ptrace(PT_DENY_ATTACH, 0, 0, 0); + } +#endif + + // XXX: TODO - Mac OS X has dtrace and this may be disabled. + // XXX: TODO - Windows probably has something similar + if (r == 0 && attempted) { + log_debug(LD_CONFIG,"Debugger attachment disabled for " + "unprivileged users."); + return 1; + } else if (attempted) { + log_warn(LD_CONFIG, "Unable to disable debugger attaching: %s", + strerror(errno)); + } + return r; +} + +#ifdef HAVE_PWD_H +/** Allocate and return a string containing the home directory for the + * user username. Only works on posix-like systems. */ +char * +get_user_homedir(const char *username) +{ + struct passwd *pw; + tor_assert(username); + + if (!(pw = getpwnam(username))) { + log_err(LD_CONFIG,"User \"%s\" not found.", username); + return NULL; + } + return tor_strdup(pw->pw_dir); +} +#endif + +/** Modify fname to contain the name of its parent directory. Doesn't + * actually examine the filesystem; does a purely syntactic modification. + * + * The parent of the root director is considered to be iteself. + * + * Path separators are the forward slash (/) everywhere and additionally + * the backslash (\) on Win32. + * + * Cuts off any number of trailing path separators but otherwise ignores + * them for purposes of finding the parent directory. + * + * Returns 0 if a parent directory was successfully found, -1 otherwise (fname + * did not have any path separators or only had them at the end). + * */ +int +get_parent_directory(char *fname) +{ + char *cp; + int at_end = 1; + tor_assert(fname); +#ifdef _WIN32 + /* If we start with, say, c:, then don't consider that the start of the path + */ + if (fname[0] && fname[1] == ':') { + fname += 2; + } +#endif + /* Now we want to remove all path-separators at the end of the string, + * and to remove the end of the string starting with the path separator + * before the last non-path-separator. In perl, this would be + * s#[/]*$##; s#/[^/]*$##; + * on a unixy platform. + */ + cp = fname + strlen(fname); + at_end = 1; + while (--cp >= fname) { + int is_sep = (*cp == '/' +#ifdef _WIN32 + || *cp == '\\' +#endif + ); + if (is_sep) { + if (cp == fname) { + /* This is the first separator in the file name; don't remove it! */ + cp[1] = '\0'; + return 0; + } + *cp = '\0'; + if (! at_end) + return 0; + } else { + at_end = 0; + } + } + return -1; +} + +#ifndef _WIN32 +/** Return a newly allocated string containing the output of getcwd(). Return + * NULL on failure. (We can't just use getcwd() into a PATH_MAX buffer, since + * Hurd hasn't got a PATH_MAX.) + */ +static char * +alloc_getcwd(void) +{ + int saved_errno = errno; +/* We use this as a starting path length. Not too large seems sane. */ +#define START_PATH_LENGTH 128 +/* Nobody has a maxpath longer than this, as far as I know. And if they + * do, they shouldn't. */ +#define MAX_SANE_PATH_LENGTH 4096 + size_t path_length = START_PATH_LENGTH; + char *path = tor_malloc(path_length); + + errno = 0; + while (getcwd(path, path_length) == NULL) { + if (errno == ERANGE && path_length < MAX_SANE_PATH_LENGTH) { + path_length*=2; + path = tor_realloc(path, path_length); + } else { + tor_free(path); + path = NULL; + break; + } + } + errno = saved_errno; + return path; +} +#endif + +/** Expand possibly relative path fname to an absolute path. + * Return a newly allocated string, possibly equal to fname. */ +char * +make_path_absolute(char *fname) +{ +#ifdef _WIN32 + char *absfname_malloced = _fullpath(NULL, fname, 1); + + /* We don't want to assume that tor_free can free a string allocated + * with malloc. On failure, return fname (it's better than nothing). */ + char *absfname = tor_strdup(absfname_malloced ? absfname_malloced : fname); + if (absfname_malloced) free(absfname_malloced); + + return absfname; +#else + char *absfname = NULL, *path = NULL; + + tor_assert(fname); + + if (fname[0] == '/') { + absfname = tor_strdup(fname); + } else { + path = alloc_getcwd(); + if (path) { + tor_asprintf(&absfname, "%s/%s", path, fname); + tor_free(path); + } else { + /* If getcwd failed, the best we can do here is keep using the + * relative path. (Perhaps / isn't readable by this UID/GID.) */ + log_warn(LD_GENERAL, "Unable to find current working directory: %s", + strerror(errno)); + absfname = tor_strdup(fname); + } + } + return absfname; +#endif +} + +#ifndef HAVE__NSGETENVIRON +#ifndef HAVE_EXTERN_ENVIRON_DECLARED +/* Some platforms declare environ under some circumstances, others don't. */ +#ifndef RUNNING_DOXYGEN +extern char **environ; +#endif +#endif +#endif + +/** Return the current environment. This is a portable replacement for + * 'environ'. */ +char ** +get_environment(void) +{ +#ifdef HAVE__NSGETENVIRON + /* This is for compatibility between OSX versions. Otherwise (for example) + * when we do a mostly-static build on OSX 10.7, the resulting binary won't + * work on OSX 10.6. */ + return *_NSGetEnviron(); +#else + return environ; +#endif +} + +/** Set *addr to the IP address (in dotted-quad notation) stored in c. + * Return 1 on success, 0 if c is badly formatted. (Like inet_aton(c,addr), + * but works on Windows and Solaris.) + */ +int +tor_inet_aton(const char *str, struct in_addr* addr) +{ + unsigned a,b,c,d; + char more; + if (tor_sscanf(str, "%3u.%3u.%3u.%3u%c", &a,&b,&c,&d,&more) != 4) + return 0; + if (a > 255) return 0; + if (b > 255) return 0; + if (c > 255) return 0; + if (d > 255) return 0; + addr->s_addr = htonl((a<<24) | (b<<16) | (c<<8) | d); + return 1; +} + +/** Given af==AF_INET and src a struct in_addr, or + * af==AF_INET6 and src a struct in6_addr, try to format the + * address and store it in the len-byte buffer dst. Returns + * dst on success, NULL on failure. + * + * (Like inet_ntop(af,src,dst,len), but works on platforms that don't have it: + * Tor sometimes needs to format ipv6 addresses even on platforms without ipv6 + * support.) */ +const char * +tor_inet_ntop(int af, const void *src, char *dst, size_t len) +{ + if (af == AF_INET) { + if (tor_inet_ntoa(src, dst, len) < 0) + return NULL; + else + return dst; + } else if (af == AF_INET6) { + const struct in6_addr *addr = src; + char buf[64], *cp; + int longestGapLen = 0, longestGapPos = -1, i, + curGapPos = -1, curGapLen = 0; + uint16_t words[8]; + for (i = 0; i < 8; ++i) { + words[i] = (((uint16_t)addr->s6_addr[2*i])<<8) + addr->s6_addr[2*i+1]; + } + if (words[0] == 0 && words[1] == 0 && words[2] == 0 && words[3] == 0 && + words[4] == 0 && ((words[5] == 0 && words[6] && words[7]) || + (words[5] == 0xffff))) { + /* This is an IPv4 address. */ + if (words[5] == 0) { + tor_snprintf(buf, sizeof(buf), "::%d.%d.%d.%d", + addr->s6_addr[12], addr->s6_addr[13], + addr->s6_addr[14], addr->s6_addr[15]); + } else { + tor_snprintf(buf, sizeof(buf), "::%x:%d.%d.%d.%d", words[5], + addr->s6_addr[12], addr->s6_addr[13], + addr->s6_addr[14], addr->s6_addr[15]); + } + if ((strlen(buf) + 1) > len) /* +1 for \0 */ + return NULL; + strlcpy(dst, buf, len); + return dst; + } + i = 0; + while (i < 8) { + if (words[i] == 0) { + curGapPos = i++; + curGapLen = 1; + while (i<8 && words[i] == 0) { + ++i; ++curGapLen; + } + if (curGapLen > longestGapLen) { + longestGapPos = curGapPos; + longestGapLen = curGapLen; + } + } else { + ++i; + } + } + if (longestGapLen<=1) + longestGapPos = -1; + + cp = buf; + for (i = 0; i < 8; ++i) { + if (words[i] == 0 && longestGapPos == i) { + if (i == 0) + *cp++ = ':'; + *cp++ = ':'; + while (i < 8 && words[i] == 0) + ++i; + --i; /* to compensate for loop increment. */ + } else { + tor_snprintf(cp, sizeof(buf)-(cp-buf), "%x", (unsigned)words[i]); + cp += strlen(cp); + if (i != 7) + *cp++ = ':'; + } + } + *cp = '\0'; + if ((strlen(buf) + 1) > len) /* +1 for \0 */ + return NULL; + strlcpy(dst, buf, len); + return dst; + } else { + return NULL; + } +} + +/** Given af==AF_INET or af==AF_INET6, and a string src + * encoding an IPv4 address or IPv6 address correspondingly, try to parse the + * address and store the result in dst (which must have space for a + * struct in_addr or a struct in6_addr, as appropriate). Return 1 on success, + * 0 on a bad parse, and -1 on a bad af. + * + * (Like inet_pton(af,src,dst) but works on platforms that don't have it: Tor + * sometimes needs to format ipv6 addresses even on platforms without ipv6 + * support.) */ +int +tor_inet_pton(int af, const char *src, void *dst) +{ + if (af == AF_INET) { + return tor_inet_aton(src, dst); + } else if (af == AF_INET6) { + struct in6_addr *out = dst; + uint16_t words[8]; + int gapPos = -1, i, setWords=0; + const char *dot = strchr(src, '.'); + const char *eow; /* end of words. */ + if (dot == src) + return 0; + else if (!dot) + eow = src+strlen(src); + else { + unsigned byte1,byte2,byte3,byte4; + char more; + for (eow = dot-1; eow >= src && TOR_ISDIGIT(*eow); --eow) + ; + ++eow; + + /* We use "scanf" because some platform inet_aton()s are too lax + * about IPv4 addresses of the form "1.2.3" */ + if (tor_sscanf(eow, "%3u.%3u.%3u.%3u%c", + &byte1,&byte2,&byte3,&byte4,&more) != 4) + return 0; + + if (byte1 > 255 || byte2 > 255 || byte3 > 255 || byte4 > 255) + return 0; + + words[6] = (byte1<<8) | byte2; + words[7] = (byte3<<8) | byte4; + setWords += 2; + } + + i = 0; + while (src < eow) { + if (i > 7) + return 0; + if (TOR_ISXDIGIT(*src)) { + char *next; + ssize_t len; + long r = strtol(src, &next, 16); + tor_assert(next != NULL); + tor_assert(next != src); + + len = *next == '\0' ? eow - src : next - src; + if (len > 4) + return 0; + if (len > 1 && !TOR_ISXDIGIT(src[1])) + return 0; /* 0x is not valid */ + + tor_assert(r >= 0); + tor_assert(r < 65536); + words[i++] = (uint16_t)r; + setWords++; + src = next; + if (*src != ':' && src != eow) + return 0; + ++src; + } else if (*src == ':' && i > 0 && gapPos == -1) { + gapPos = i; + ++src; + } else if (*src == ':' && i == 0 && src+1 < eow && src[1] == ':' && + gapPos == -1) { + gapPos = i; + src += 2; + } else { + return 0; + } + } + + if (setWords > 8 || + (setWords == 8 && gapPos != -1) || + (setWords < 8 && gapPos == -1)) + return 0; + + if (gapPos >= 0) { + int nToMove = setWords - (dot ? 2 : 0) - gapPos; + int gapLen = 8 - setWords; + tor_assert(nToMove >= 0); + memmove(&words[gapPos+gapLen], &words[gapPos], + sizeof(uint16_t)*nToMove); + memset(&words[gapPos], 0, sizeof(uint16_t)*gapLen); + } + for (i = 0; i < 8; ++i) { + out->s6_addr[2*i ] = words[i] >> 8; + out->s6_addr[2*i+1] = words[i] & 0xff; + } + + return 1; + } else { + return -1; + } +} + +/** Similar behavior to Unix gethostbyname: resolve name, and set + * *addr to the proper IP address, in host byte order. Returns 0 + * on success, -1 on failure; 1 on transient failure. + * + * (This function exists because standard windows gethostbyname + * doesn't treat raw IP addresses properly.) + */ +int +tor_lookup_hostname(const char *name, uint32_t *addr) +{ + tor_addr_t myaddr; + int ret; + + if ((ret = tor_addr_lookup(name, AF_INET, &myaddr))) + return ret; + + if (tor_addr_family(&myaddr) == AF_INET) { + *addr = tor_addr_to_ipv4h(&myaddr); + return ret; + } + + return -1; +} + +/** Hold the result of our call to uname. */ +static char uname_result[256]; +/** True iff uname_result is set. */ +static int uname_result_is_set = 0; + +/** Return a pointer to a description of our platform. + */ +const char * +get_uname(void) +{ +#ifdef HAVE_UNAME + struct utsname u; +#endif + if (!uname_result_is_set) { +#ifdef HAVE_UNAME + if (uname(&u) != -1) { + /* (Linux says 0 is success, Solaris says 1 is success) */ + strlcpy(uname_result, u.sysname, sizeof(uname_result)); + } else +#endif + { +#ifdef _WIN32 + OSVERSIONINFOEX info; + int i; + const char *plat = NULL; + static struct { + unsigned major; unsigned minor; const char *version; + } win_version_table[] = { + { 6, 2, "Windows 8" }, + { 6, 1, "Windows 7" }, + { 6, 0, "Windows Vista" }, + { 5, 2, "Windows Server 2003" }, + { 5, 1, "Windows XP" }, + { 5, 0, "Windows 2000" }, + /* { 4, 0, "Windows NT 4.0" }, */ + { 4, 90, "Windows Me" }, + { 4, 10, "Windows 98" }, + /* { 4, 0, "Windows 95" } */ + { 3, 51, "Windows NT 3.51" }, + { 0, 0, NULL } + }; + memset(&info, 0, sizeof(info)); + info.dwOSVersionInfoSize = sizeof(info); + if (! GetVersionEx((LPOSVERSIONINFO)&info)) { + strlcpy(uname_result, "Bizarre version of Windows where GetVersionEx" + " doesn't work.", sizeof(uname_result)); + uname_result_is_set = 1; + return uname_result; + } + if (info.dwMajorVersion == 4 && info.dwMinorVersion == 0) { + if (info.dwPlatformId == VER_PLATFORM_WIN32_NT) + plat = "Windows NT 4.0"; + else + plat = "Windows 95"; + } else { + for (i=0; win_version_table[i].major>0; ++i) { + if (win_version_table[i].major == info.dwMajorVersion && + win_version_table[i].minor == info.dwMinorVersion) { + plat = win_version_table[i].version; + break; + } + } + } + if (plat) { + strlcpy(uname_result, plat, sizeof(uname_result)); + } else { + if (info.dwMajorVersion > 6 || + (info.dwMajorVersion==6 && info.dwMinorVersion>2)) + tor_snprintf(uname_result, sizeof(uname_result), + "Very recent version of Windows [major=%d,minor=%d]", + (int)info.dwMajorVersion,(int)info.dwMinorVersion); + else + tor_snprintf(uname_result, sizeof(uname_result), + "Unrecognized version of Windows [major=%d,minor=%d]", + (int)info.dwMajorVersion,(int)info.dwMinorVersion); + } +#if !defined (WINCE) +#ifdef VER_NT_SERVER + if (info.wProductType == VER_NT_SERVER || + info.wProductType == VER_NT_DOMAIN_CONTROLLER) { + strlcat(uname_result, " [server]", sizeof(uname_result)); + } +#endif +#endif +#else + strlcpy(uname_result, "Unknown platform", sizeof(uname_result)); +#endif + } + uname_result_is_set = 1; + } + return uname_result; +} + +/* + * Process control + */ + +#if defined(USE_PTHREADS) +/** Wraps a void (*)(void*) function and its argument so we can + * invoke them in a way pthreads would expect. + */ +typedef struct tor_pthread_data_t { + void (*func)(void *); + void *data; +} tor_pthread_data_t; +/** Given a tor_pthread_data_t _data, call _data->func(d->data) + * and free _data. Used to make sure we can call functions the way pthread + * expects. */ +static void * +tor_pthread_helper_fn(void *_data) +{ + tor_pthread_data_t *data = _data; + void (*func)(void*); + void *arg; + /* mask signals to worker threads to avoid SIGPIPE, etc */ + sigset_t sigs; + /* We're in a subthread; don't handle any signals here. */ + sigfillset(&sigs); + pthread_sigmask(SIG_SETMASK, &sigs, NULL); + + func = data->func; + arg = data->data; + tor_free(_data); + func(arg); + return NULL; +} +#endif + +/** Minimalist interface to run a void function in the background. On + * Unix calls fork, on win32 calls beginthread. Returns -1 on failure. + * func should not return, but rather should call spawn_exit. + * + * NOTE: if data is used, it should not be allocated on the stack, + * since in a multithreaded environment, there is no way to be sure that + * the caller's stack will still be around when the called function is + * running. + */ +int +spawn_func(void (*func)(void *), void *data) +{ +#if defined(USE_WIN32_THREADS) + int rv; + rv = (int)_beginthread(func, 0, data); + if (rv == (int)-1) + return -1; + return 0; +#elif defined(USE_PTHREADS) + pthread_t thread; + tor_pthread_data_t *d; + d = tor_malloc(sizeof(tor_pthread_data_t)); + d->data = data; + d->func = func; + if (pthread_create(&thread,NULL,tor_pthread_helper_fn,d)) + return -1; + if (pthread_detach(thread)) + return -1; + return 0; +#else + pid_t pid; + pid = fork(); + if (pid<0) + return -1; + if (pid==0) { + /* Child */ + func(data); + tor_assert(0); /* Should never reach here. */ + return 0; /* suppress "control-reaches-end-of-non-void" warning. */ + } else { + /* Parent */ + return 0; + } +#endif +} + +/** End the current thread/process. + */ +void +spawn_exit(void) +{ +#if defined(USE_WIN32_THREADS) + _endthread(); + //we should never get here. my compiler thinks that _endthread returns, this + //is an attempt to fool it. + tor_assert(0); + _exit(0); +#elif defined(USE_PTHREADS) + pthread_exit(NULL); +#else + /* http://www.erlenstar.demon.co.uk/unix/faq_2.html says we should + * call _exit, not exit, from child processes. */ + _exit(0); +#endif +} + +/** Implementation logic for compute_num_cpus(). */ +static int +compute_num_cpus_impl(void) +{ +#ifdef _WIN32 + SYSTEM_INFO info; + memset(&info, 0, sizeof(info)); + GetSystemInfo(&info); + if (info.dwNumberOfProcessors >= 1 && info.dwNumberOfProcessors < INT_MAX) + return (int)info.dwNumberOfProcessors; + else + return -1; +#elif defined(HAVE_SYSCONF) +#ifdef _SC_NPROCESSORS_CONF + long cpus_conf = sysconf(_SC_NPROCESSORS_CONF); +#else + long cpus_conf = -1; +#endif +#ifdef _SC_NPROCESSORS_ONLN + long cpus_onln = sysconf(_SC_NPROCESSORS_ONLN); +#else + long cpus_onln = -1; +#endif + long cpus = -1; + + if (cpus_conf > 0 && cpus_onln < 0) { + cpus = cpus_conf; + } else if (cpus_onln > 0 && cpus_conf < 0) { + cpus = cpus_onln; + } else if (cpus_onln > 0 && cpus_conf > 0) { + if (cpus_onln < cpus_conf) { + log_notice(LD_GENERAL, "I think we have %ld CPUS, but only %ld of them " + "are available. Telling Tor to only use %ld. You can over" + "ride this with the NumCPUs option", + cpus_conf, cpus_onln, cpus_onln); + } + cpus = cpus_onln; + } + + if (cpus >= 1 && cpus < INT_MAX) + return (int)cpus; + else + return -1; +#else + return -1; +#endif +} + +#define MAX_DETECTABLE_CPUS 16 + +/** Return how many CPUs we are running with. We assume that nobody is + * using hot-swappable CPUs, so we don't recompute this after the first + * time. Return -1 if we don't know how to tell the number of CPUs on this + * system. + */ +int +compute_num_cpus(void) +{ + static int num_cpus = -2; + if (num_cpus == -2) { + num_cpus = compute_num_cpus_impl(); + tor_assert(num_cpus != -2); + if (num_cpus > MAX_DETECTABLE_CPUS) + log_notice(LD_GENERAL, "Wow! I detected that you have %d CPUs. I " + "will not autodetect any more than %d, though. If you " + "want to configure more, set NumCPUs in your torrc", + num_cpus, MAX_DETECTABLE_CPUS); + } + return num_cpus; +} + +/** Set *timeval to the current time of day. On error, log and terminate. + * (Same as gettimeofday(timeval,NULL), but never returns -1.) + */ +void +tor_gettimeofday(struct timeval *timeval) +{ +#ifdef _WIN32 + /* Epoch bias copied from perl: number of units between windows epoch and + * Unix epoch. */ +#define EPOCH_BIAS U64_LITERAL(116444736000000000) +#define UNITS_PER_SEC U64_LITERAL(10000000) +#define USEC_PER_SEC U64_LITERAL(1000000) +#define UNITS_PER_USEC U64_LITERAL(10) + union { + uint64_t ft_64; + FILETIME ft_ft; + } ft; +#if defined (WINCE) + /* wince do not have GetSystemTimeAsFileTime */ + SYSTEMTIME stime; + GetSystemTime(&stime); + SystemTimeToFileTime(&stime,&ft.ft_ft); +#else + /* number of 100-nsec units since Jan 1, 1601 */ + GetSystemTimeAsFileTime(&ft.ft_ft); +#endif + if (ft.ft_64 < EPOCH_BIAS) { + log_err(LD_GENERAL,"System time is before 1970; failing."); + exit(1); + } + ft.ft_64 -= EPOCH_BIAS; + timeval->tv_sec = (unsigned) (ft.ft_64 / UNITS_PER_SEC); + timeval->tv_usec = (unsigned) ((ft.ft_64 / UNITS_PER_USEC) % USEC_PER_SEC); +#elif defined(HAVE_GETTIMEOFDAY) + if (gettimeofday(timeval, NULL)) { + log_err(LD_GENERAL,"gettimeofday failed."); + /* If gettimeofday dies, we have either given a bad timezone (we didn't), + or segfaulted.*/ + exit(1); + } +#elif defined(HAVE_FTIME) + struct timeb tb; + ftime(&tb); + timeval->tv_sec = tb.time; + timeval->tv_usec = tb.millitm * 1000; +#else +#error "No way to get time." +#endif + return; +} + +#if defined(TOR_IS_MULTITHREADED) && !defined(_WIN32) +/** Defined iff we need to add locks when defining fake versions of reentrant + * versions of time-related functions. */ +#define TIME_FNS_NEED_LOCKS +#endif + +/** Helper: Deal with confused or out-of-bounds values from localtime_r and + * friends. (On some platforms, they can give out-of-bounds values or can + * return NULL.) If islocal, this is a localtime result; otherwise + * it's from gmtime. The function returned r, when given timep + * as its input. If we need to store new results, store them in + * resultbuf. */ +static struct tm * +correct_tm(int islocal, const time_t *timep, struct tm *resultbuf, + struct tm *r) +{ + const char *outcome; + + if (PREDICT_LIKELY(r)) { + if (r->tm_year > 8099) { /* We can't strftime dates after 9999 CE. */ + r->tm_year = 8099; + r->tm_mon = 11; + r->tm_mday = 31; + r->tm_yday = 365; + r->tm_hour = 23; + r->tm_min = 59; + r->tm_sec = 59; + } + return r; + } + + /* If we get here, gmtime or localtime returned NULL. It might have done + * this because of overrun or underrun, or it might have done it because of + * some other weird issue. */ + if (timep) { + if (*timep < 0) { + r = resultbuf; + r->tm_year = 70; /* 1970 CE */ + r->tm_mon = 0; + r->tm_mday = 1; + r->tm_yday = 1; + r->tm_hour = 0; + r->tm_min = 0 ; + r->tm_sec = 0; + outcome = "Rounding up to 1970"; + goto done; + } else if (*timep >= INT32_MAX) { + /* Rounding down to INT32_MAX isn't so great, but keep in mind that we + * only do it if gmtime/localtime tells us NULL. */ + r = resultbuf; + r->tm_year = 137; /* 2037 CE */ + r->tm_mon = 11; + r->tm_mday = 31; + r->tm_yday = 365; + r->tm_hour = 23; + r->tm_min = 59; + r->tm_sec = 59; + outcome = "Rounding down to 2037"; + goto done; + } + } + + /* If we get here, then gmtime/localtime failed without getting an extreme + * value for *timep */ + + tor_fragile_assert(); + r = resultbuf; + memset(resultbuf, 0, sizeof(struct tm)); + outcome="can't recover"; + done: + log_warn(LD_BUG, "%s("I64_FORMAT") failed with error %s: %s", + islocal?"localtime":"gmtime", + timep?I64_PRINTF_ARG(*timep):0, + strerror(errno), + outcome); + return r; +} + +/** @{ */ +/** As localtime_r, but defined for platforms that don't have it: + * + * Convert *timep to a struct tm in local time, and store the value in + * *result. Return the result on success, or NULL on failure. + */ +#ifdef HAVE_LOCALTIME_R +struct tm * +tor_localtime_r(const time_t *timep, struct tm *result) +{ + struct tm *r; + r = localtime_r(timep, result); + return correct_tm(1, timep, result, r); +} +#elif defined(TIME_FNS_NEED_LOCKS) +struct tm * +tor_localtime_r(const time_t *timep, struct tm *result) +{ + struct tm *r; + static tor_mutex_t *m=NULL; + if (!m) { m=tor_mutex_new(); } + tor_assert(result); + tor_mutex_acquire(m); + r = localtime(timep); + if (r) + memcpy(result, r, sizeof(struct tm)); + tor_mutex_release(m); + return correct_tm(1, timep, result, r); +} +#else +struct tm * +tor_localtime_r(const time_t *timep, struct tm *result) +{ + struct tm *r; + tor_assert(result); + r = localtime(timep); + if (r) + memcpy(result, r, sizeof(struct tm)); + return correct_tm(1, timep, result, r); +} +#endif +/** @} */ + +/** @{ */ +/** As gmtimee_r, but defined for platforms that don't have it: + * + * Convert *timep to a struct tm in UTC, and store the value in + * *result. Return the result on success, or NULL on failure. + */ +#ifdef HAVE_GMTIME_R +struct tm * +tor_gmtime_r(const time_t *timep, struct tm *result) +{ + struct tm *r; + r = gmtime_r(timep, result); + return correct_tm(0, timep, result, r); +} +#elif defined(TIME_FNS_NEED_LOCKS) +struct tm * +tor_gmtime_r(const time_t *timep, struct tm *result) +{ + struct tm *r; + static tor_mutex_t *m=NULL; + if (!m) { m=tor_mutex_new(); } + tor_assert(result); + tor_mutex_acquire(m); + r = gmtime(timep); + if (r) + memcpy(result, r, sizeof(struct tm)); + tor_mutex_release(m); + return correct_tm(0, timep, result, r); +} +#else +struct tm * +tor_gmtime_r(const time_t *timep, struct tm *result) +{ + struct tm *r; + tor_assert(result); + r = gmtime(timep); + if (r) + memcpy(result, r, sizeof(struct tm)); + return correct_tm(0, timep, result, r); +} +#endif + +#if defined(USE_WIN32_THREADS) +void +tor_mutex_init(tor_mutex_t *m) +{ + InitializeCriticalSection(&m->mutex); +} +void +tor_mutex_uninit(tor_mutex_t *m) +{ + DeleteCriticalSection(&m->mutex); +} +void +tor_mutex_acquire(tor_mutex_t *m) +{ + tor_assert(m); + EnterCriticalSection(&m->mutex); +} +void +tor_mutex_release(tor_mutex_t *m) +{ + LeaveCriticalSection(&m->mutex); +} +unsigned long +tor_get_thread_id(void) +{ + return (unsigned long)GetCurrentThreadId(); +} +#elif defined(USE_PTHREADS) +/** A mutex attribute that we're going to use to tell pthreads that we want + * "reentrant" mutexes (i.e., once we can re-lock if we're already holding + * them.) */ +static pthread_mutexattr_t attr_reentrant; +/** True iff we've called tor_threads_init() */ +static int threads_initialized = 0; +/** Initialize mutex so it can be locked. Every mutex must be set + * up with tor_mutex_init() or tor_mutex_new(); not both. */ +void +tor_mutex_init(tor_mutex_t *mutex) +{ + int err; + if (PREDICT_UNLIKELY(!threads_initialized)) + tor_threads_init(); + err = pthread_mutex_init(&mutex->mutex, &attr_reentrant); + if (PREDICT_UNLIKELY(err)) { + log_err(LD_GENERAL, "Error %d creating a mutex.", err); + tor_fragile_assert(); + } +} +/** Wait until m is free, then acquire it. */ +void +tor_mutex_acquire(tor_mutex_t *m) +{ + int err; + tor_assert(m); + err = pthread_mutex_lock(&m->mutex); + if (PREDICT_UNLIKELY(err)) { + log_err(LD_GENERAL, "Error %d locking a mutex.", err); + tor_fragile_assert(); + } +} +/** Release the lock m so another thread can have it. */ +void +tor_mutex_release(tor_mutex_t *m) +{ + int err; + tor_assert(m); + err = pthread_mutex_unlock(&m->mutex); + if (PREDICT_UNLIKELY(err)) { + log_err(LD_GENERAL, "Error %d unlocking a mutex.", err); + tor_fragile_assert(); + } +} +/** Clean up the mutex m so that it no longer uses any system + * resources. Does not free m. This function must only be called on + * mutexes from tor_mutex_init(). */ +void +tor_mutex_uninit(tor_mutex_t *m) +{ + int err; + tor_assert(m); + err = pthread_mutex_destroy(&m->mutex); + if (PREDICT_UNLIKELY(err)) { + log_err(LD_GENERAL, "Error %d destroying a mutex.", err); + tor_fragile_assert(); + } +} +/** Return an integer representing this thread. */ +unsigned long +tor_get_thread_id(void) +{ + union { + pthread_t thr; + unsigned long id; + } r; + r.thr = pthread_self(); + return r.id; +} +#endif + +#ifdef TOR_IS_MULTITHREADED +/** Return a newly allocated, ready-for-use mutex. */ +tor_mutex_t * +tor_mutex_new(void) +{ + tor_mutex_t *m = tor_malloc_zero(sizeof(tor_mutex_t)); + tor_mutex_init(m); + return m; +} +/** Release all storage and system resources held by m. */ +void +tor_mutex_free(tor_mutex_t *m) +{ + if (!m) + return; + tor_mutex_uninit(m); + tor_free(m); +} +#endif + +/* Conditions. */ +#ifdef USE_PTHREADS +#if 0 +/** Cross-platform condition implementation. */ +struct tor_cond_t { + pthread_cond_t cond; +}; +/** Return a newly allocated condition, with nobody waiting on it. */ +tor_cond_t * +tor_cond_new(void) +{ + tor_cond_t *cond = tor_malloc_zero(sizeof(tor_cond_t)); + if (pthread_cond_init(&cond->cond, NULL)) { + tor_free(cond); + return NULL; + } + return cond; +} +/** Release all resources held by cond. */ +void +tor_cond_free(tor_cond_t *cond) +{ + if (!cond) + return; + if (pthread_cond_destroy(&cond->cond)) { + log_warn(LD_GENERAL,"Error freeing condition: %s", strerror(errno)); + return; + } + tor_free(cond); +} +/** Wait until one of the tor_cond_signal functions is called on cond. + * All waiters on the condition must wait holding the same mutex. + * Returns 0 on success, negative on failure. */ +int +tor_cond_wait(tor_cond_t *cond, tor_mutex_t *mutex) +{ + return pthread_cond_wait(&cond->cond, &mutex->mutex) ? -1 : 0; +} +/** Wake up one of the waiters on cond. */ +void +tor_cond_signal_one(tor_cond_t *cond) +{ + pthread_cond_signal(&cond->cond); +} +/** Wake up all of the waiters on cond. */ +void +tor_cond_signal_all(tor_cond_t *cond) +{ + pthread_cond_broadcast(&cond->cond); +} +#endif +/** Set up common structures for use by threading. */ +void +tor_threads_init(void) +{ + if (!threads_initialized) { + pthread_mutexattr_init(&attr_reentrant); + pthread_mutexattr_settype(&attr_reentrant, PTHREAD_MUTEX_RECURSIVE); + threads_initialized = 1; + set_main_thread(); + } +} +#elif defined(USE_WIN32_THREADS) +#if 0 +static DWORD cond_event_tls_index; +struct tor_cond_t { + CRITICAL_SECTION mutex; + smartlist_t *events; +}; +tor_cond_t * +tor_cond_new(void) +{ + tor_cond_t *cond = tor_malloc_zero(sizeof(tor_cond_t)); + InitializeCriticalSection(&cond->mutex); + cond->events = smartlist_new(); + return cond; +} +void +tor_cond_free(tor_cond_t *cond) +{ + if (!cond) + return; + DeleteCriticalSection(&cond->mutex); + /* XXXX notify? */ + smartlist_free(cond->events); + tor_free(cond); +} +int +tor_cond_wait(tor_cond_t *cond, tor_mutex_t *mutex) +{ + HANDLE event; + int r; + tor_assert(cond); + tor_assert(mutex); + event = TlsGetValue(cond_event_tls_index); + if (!event) { + event = CreateEvent(0, FALSE, FALSE, NULL); + TlsSetValue(cond_event_tls_index, event); + } + EnterCriticalSection(&cond->mutex); + + tor_assert(WaitForSingleObject(event, 0) == WAIT_TIMEOUT); + tor_assert(!smartlist_contains(cond->events, event)); + smartlist_add(cond->events, event); + + LeaveCriticalSection(&cond->mutex); + + tor_mutex_release(mutex); + r = WaitForSingleObject(event, INFINITE); + tor_mutex_acquire(mutex); + + switch (r) { + case WAIT_OBJECT_0: /* we got the mutex normally. */ + break; + case WAIT_ABANDONED: /* holding thread exited. */ + case WAIT_TIMEOUT: /* Should never happen. */ + tor_assert(0); + break; + case WAIT_FAILED: + log_warn(LD_GENERAL, "Failed to acquire mutex: %d",(int) GetLastError()); + } + return 0; +} +void +tor_cond_signal_one(tor_cond_t *cond) +{ + HANDLE event; + tor_assert(cond); + + EnterCriticalSection(&cond->mutex); + + if ((event = smartlist_pop_last(cond->events))) + SetEvent(event); + + LeaveCriticalSection(&cond->mutex); +} +void +tor_cond_signal_all(tor_cond_t *cond) +{ + tor_assert(cond); + + EnterCriticalSection(&cond->mutex); + SMARTLIST_FOREACH(cond->events, HANDLE, event, SetEvent(event)); + smartlist_clear(cond->events); + LeaveCriticalSection(&cond->mutex); +} +#endif +void +tor_threads_init(void) +{ +#if 0 + cond_event_tls_index = TlsAlloc(); +#endif + set_main_thread(); +} +#endif + +#if defined(HAVE_MLOCKALL) && HAVE_DECL_MLOCKALL && defined(RLIMIT_MEMLOCK) +/** Attempt to raise the current and max rlimit to infinity for our process. + * This only needs to be done once and can probably only be done when we have + * not already dropped privileges. + */ +static int +tor_set_max_memlock(void) +{ + /* Future consideration for Windows is probably SetProcessWorkingSetSize + * This is similar to setting the memory rlimit of RLIMIT_MEMLOCK + * http://msdn.microsoft.com/en-us/library/ms686234(VS.85).aspx + */ + + struct rlimit limit; + + /* RLIM_INFINITY is -1 on some platforms. */ + limit.rlim_cur = RLIM_INFINITY; + limit.rlim_max = RLIM_INFINITY; + + if (setrlimit(RLIMIT_MEMLOCK, &limit) == -1) { + if (errno == EPERM) { + log_warn(LD_GENERAL, "You appear to lack permissions to change memory " + "limits. Are you root?"); + } + log_warn(LD_GENERAL, "Unable to raise RLIMIT_MEMLOCK: %s", + strerror(errno)); + return -1; + } + + return 0; +} +#endif + +/** Attempt to lock all current and all future memory pages. + * This should only be called once and while we're privileged. + * Like mlockall() we return 0 when we're successful and -1 when we're not. + * Unlike mlockall() we return 1 if we've already attempted to lock memory. + */ +int +tor_mlockall(void) +{ + static int memory_lock_attempted = 0; + + if (memory_lock_attempted) { + return 1; + } + + memory_lock_attempted = 1; + + /* + * Future consideration for Windows may be VirtualLock + * VirtualLock appears to implement mlock() but not mlockall() + * + * http://msdn.microsoft.com/en-us/library/aa366895(VS.85).aspx + */ + +#if defined(HAVE_MLOCKALL) && HAVE_DECL_MLOCKALL && defined(RLIMIT_MEMLOCK) + if (tor_set_max_memlock() == 0) { + log_debug(LD_GENERAL, "RLIMIT_MEMLOCK is now set to RLIM_INFINITY."); + } + + if (mlockall(MCL_CURRENT|MCL_FUTURE) == 0) { + log_info(LD_GENERAL, "Insecure OS paging is effectively disabled."); + return 0; + } else { + if (errno == ENOSYS) { + /* Apple - it's 2009! I'm looking at you. Grrr. */ + log_notice(LD_GENERAL, "It appears that mlockall() is not available on " + "your platform."); + } else if (errno == EPERM) { + log_notice(LD_GENERAL, "It appears that you lack the permissions to " + "lock memory. Are you root?"); + } + log_notice(LD_GENERAL, "Unable to lock all current and future memory " + "pages: %s", strerror(errno)); + return -1; + } +#else + log_warn(LD_GENERAL, "Unable to lock memory pages. mlockall() unsupported?"); + return -1; +#endif +} + +/** Identity of the "main" thread */ +static unsigned long main_thread_id = -1; + +/** Start considering the current thread to be the 'main thread'. This has + * no effect on anything besides in_main_thread(). */ +void +set_main_thread(void) +{ + main_thread_id = tor_get_thread_id(); +} +/** Return true iff called from the main thread. */ +int +in_main_thread(void) +{ + return main_thread_id == tor_get_thread_id(); +} + +/** + * On Windows, WSAEWOULDBLOCK is not always correct: when you see it, + * you need to ask the socket for its actual errno. Also, you need to + * get your errors from WSAGetLastError, not errno. (If you supply a + * socket of -1, we check WSAGetLastError, but don't correct + * WSAEWOULDBLOCKs.) + * + * The upshot of all of this is that when a socket call fails, you + * should call tor_socket_errno at most once on the failing + * socket to get the error. + */ +#if defined(_WIN32) +int +tor_socket_errno(tor_socket_t sock) +{ + int optval, optvallen=sizeof(optval); + int err = WSAGetLastError(); + if (err == WSAEWOULDBLOCK && SOCKET_OK(sock)) { + if (getsockopt(sock, SOL_SOCKET, SO_ERROR, (void*)&optval, &optvallen)) + return err; + if (optval) + return optval; + } + return err; +} +#endif + +#if defined(_WIN32) +#define E(code, s) { code, (s " [" #code " ]") } +struct { int code; const char *msg; } windows_socket_errors[] = { + E(WSAEINTR, "Interrupted function call"), + E(WSAEACCES, "Permission denied"), + E(WSAEFAULT, "Bad address"), + E(WSAEINVAL, "Invalid argument"), + E(WSAEMFILE, "Too many open files"), + E(WSAEWOULDBLOCK, "Resource temporarily unavailable"), + E(WSAEINPROGRESS, "Operation now in progress"), + E(WSAEALREADY, "Operation already in progress"), + E(WSAENOTSOCK, "Socket operation on nonsocket"), + E(WSAEDESTADDRREQ, "Destination address required"), + E(WSAEMSGSIZE, "Message too long"), + E(WSAEPROTOTYPE, "Protocol wrong for socket"), + E(WSAENOPROTOOPT, "Bad protocol option"), + E(WSAEPROTONOSUPPORT, "Protocol not supported"), + E(WSAESOCKTNOSUPPORT, "Socket type not supported"), + /* What's the difference between NOTSUPP and NOSUPPORT? :) */ + E(WSAEOPNOTSUPP, "Operation not supported"), + E(WSAEPFNOSUPPORT, "Protocol family not supported"), + E(WSAEAFNOSUPPORT, "Address family not supported by protocol family"), + E(WSAEADDRINUSE, "Address already in use"), + E(WSAEADDRNOTAVAIL, "Cannot assign requested address"), + E(WSAENETDOWN, "Network is down"), + E(WSAENETUNREACH, "Network is unreachable"), + E(WSAENETRESET, "Network dropped connection on reset"), + E(WSAECONNABORTED, "Software caused connection abort"), + E(WSAECONNRESET, "Connection reset by peer"), + E(WSAENOBUFS, "No buffer space available"), + E(WSAEISCONN, "Socket is already connected"), + E(WSAENOTCONN, "Socket is not connected"), + E(WSAESHUTDOWN, "Cannot send after socket shutdown"), + E(WSAETIMEDOUT, "Connection timed out"), + E(WSAECONNREFUSED, "Connection refused"), + E(WSAEHOSTDOWN, "Host is down"), + E(WSAEHOSTUNREACH, "No route to host"), + E(WSAEPROCLIM, "Too many processes"), + /* Yes, some of these start with WSA, not WSAE. No, I don't know why. */ + E(WSASYSNOTREADY, "Network subsystem is unavailable"), + E(WSAVERNOTSUPPORTED, "Winsock.dll out of range"), + E(WSANOTINITIALISED, "Successful WSAStartup not yet performed"), + E(WSAEDISCON, "Graceful shutdown now in progress"), +#ifdef WSATYPE_NOT_FOUND + E(WSATYPE_NOT_FOUND, "Class type not found"), +#endif + E(WSAHOST_NOT_FOUND, "Host not found"), + E(WSATRY_AGAIN, "Nonauthoritative host not found"), + E(WSANO_RECOVERY, "This is a nonrecoverable error"), + E(WSANO_DATA, "Valid name, no data record of requested type)"), + + /* There are some more error codes whose numeric values are marked + * OS dependent. They start with WSA_, apparently for the same + * reason that practitioners of some craft traditions deliberately + * introduce imperfections into their baskets and rugs "to allow the + * evil spirits to escape." If we catch them, then our binaries + * might not report consistent results across versions of Windows. + * Thus, I'm going to let them all fall through. + */ + { -1, NULL }, +}; +/** There does not seem to be a strerror equivalent for Winsock errors. + * Naturally, we have to roll our own. + */ +const char * +tor_socket_strerror(int e) +{ + int i; + for (i=0; windows_socket_errors[i].code >= 0; ++i) { + if (e == windows_socket_errors[i].code) + return windows_socket_errors[i].msg; + } + return strerror(e); +} +#endif + +/** Called before we make any calls to network-related functions. + * (Some operating systems require their network libraries to be + * initialized.) */ +int +network_init(void) +{ +#ifdef _WIN32 + /* This silly exercise is necessary before windows will allow + * gethostbyname to work. */ + WSADATA WSAData; + int r; + r = WSAStartup(0x101,&WSAData); + if (r) { + log_warn(LD_NET,"Error initializing windows network layer: code was %d",r); + return -1; + } + if (sizeof(SOCKET) != sizeof(tor_socket_t)) { + log_warn(LD_BUG,"The tor_socket_t type does not match SOCKET in size; Tor " + "might not work. (Sizes are %d and %d respectively.)", + (int)sizeof(tor_socket_t), (int)sizeof(SOCKET)); + } + /* WSAData.iMaxSockets might show the max sockets we're allowed to use. + * We might use it to complain if we're trying to be a server but have + * too few sockets available. */ +#endif + return 0; +} + +#ifdef _WIN32 +/** Return a newly allocated string describing the windows system error code + * err. Note that error codes are different from errno. Error codes + * come from GetLastError() when a winapi call fails. errno is set only when + * ANSI functions fail. Whee. */ +char * +format_win32_error(DWORD err) +{ + TCHAR *str = NULL; + char *result; + DWORD n; + + /* Somebody once decided that this interface was better than strerror(). */ + n = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, err, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPVOID)&str, + 0, NULL); + + if (str && n) { +#ifdef UNICODE + size_t len; + if (n > 128*1024) + len = (128 * 1024) * 2 + 1; /* This shouldn't be possible, but let's + * make sure. */ + else + len = n * 2 + 1; + result = tor_malloc(len); + wcstombs(result,str,len); + result[len-1] = '\0'; +#else + result = tor_strdup(str); +#endif + } else { + result = tor_strdup(""); + } + if (str) { + LocalFree(str); /* LocalFree != free() */ + } + return result; +} +#endif + diff --git a/src/tor/compat_libevent.c b/src/tor/compat_libevent.c new file mode 100644 index 0000000..58ec08c --- /dev/null +++ b/src/tor/compat_libevent.c @@ -0,0 +1,663 @@ +/* Copyright (c) 2009-2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file compat_libevent.c + * \brief Wrappers to handle porting between different versions of libevent. + * + * In an ideal world, we'd just use Libevent 2.0 from now on. But as of June + * 2012, Libevent 1.4 is still all over, and some poor souls are stuck on + * Libevent 1.3e. */ + +#include "orconfig.h" +#include "tor_compat.h" +#include "compat_libevent.h" + +#include "tor_util.h" +#include "torlog.h" + +#ifdef HAVE_EVENT2_EVENT_H +#include +#include +#ifdef USE_BUFFEREVENTS +#include +#endif +#else +#include +#endif + +/** A number representing a version of Libevent. + + This is a 4-byte number, with the first three bytes representing the + major, minor, and patchlevel respectively of the library. The fourth + byte is unused. + + This is equivalent to the format of LIBEVENT_VERSION_NUMBER on Libevent + 2.0.1 or later. For versions of Libevent before 1.4.0, which followed the + format of "1.0, 1.0a, 1.0b", we define 1.0 to be equivalent to 1.0.0, 1.0a + to be equivalent to 1.0.1, and so on. +*/ +typedef uint32_t le_version_t; + +/** @{ */ +/** Macros: returns the number of a libevent version as a le_version_t */ +#define V(major, minor, patch) \ + (((major) << 24) | ((minor) << 16) | ((patch) << 8)) +#define V_OLD(major, minor, patch) \ + V((major), (minor), (patch)-'a'+1) +/** @} */ + +/** Represetns a version of libevent so old we can't figure out what version + * it is. */ +#define LE_OLD V(0,0,0) +/** Represents a version of libevent so weird we can't figure out what version + * it is. */ +#define LE_OTHER V(0,0,99) + +#if 0 +static le_version_t tor_get_libevent_version(const char **v_out); +#endif + +#if defined(HAVE_EVENT_SET_LOG_CALLBACK) || defined(RUNNING_DOXYGEN) +/** A string which, if it appears in a libevent log, should be ignored. */ +static const char *suppress_msg = NULL; +/** Callback function passed to event_set_log() so we can intercept + * log messages from libevent. */ +static void +libevent_logging_callback(int severity, const char *msg) +{ + char buf[1024]; + size_t n; + if (suppress_msg && strstr(msg, suppress_msg)) + return; + n = strlcpy(buf, msg, sizeof(buf)); + if (n && n < sizeof(buf) && buf[n-1] == '\n') { + buf[n-1] = '\0'; + } + switch (severity) { + case _EVENT_LOG_DEBUG: + log_debug(LD_NOCB|LD_NET, "Message from libevent: %s", buf); + break; + case _EVENT_LOG_MSG: + log_info(LD_NOCB|LD_NET, "Message from libevent: %s", buf); + break; + case _EVENT_LOG_WARN: + log_warn(LD_NOCB|LD_GENERAL, "Warning from libevent: %s", buf); + break; + case _EVENT_LOG_ERR: + log_err(LD_NOCB|LD_GENERAL, "Error from libevent: %s", buf); + break; + default: + log_warn(LD_NOCB|LD_GENERAL, "Message [%d] from libevent: %s", + severity, buf); + break; + } +} +/** Set hook to intercept log messages from libevent. */ +void +configure_libevent_logging(void) +{ + event_set_log_callback(libevent_logging_callback); +} +/** Ignore any libevent log message that contains msg. */ +void +suppress_libevent_log_msg(const char *msg) +{ + suppress_msg = msg; +} +#else +void +configure_libevent_logging(void) +{ +} +void +suppress_libevent_log_msg(const char *msg) +{ + (void)msg; +} +#endif + +#ifndef HAVE_EVENT2_EVENT_H +/** Work-alike replacement for event_new() on pre-Libevent-2.0 systems. */ +struct event * +tor_event_new(struct event_base *base, int sock, short what, + void (*cb)(int, short, void *), void *arg) +{ + struct event *e = tor_malloc_zero(sizeof(struct event)); + event_set(e, sock, what, cb, arg); + if (! base) + base = tor_libevent_get_base(); + event_base_set(base, e); + return e; +} +/** Work-alike replacement for evtimer_new() on pre-Libevent-2.0 systems. */ +struct event * +tor_evtimer_new(struct event_base *base, + void (*cb)(int, short, void *), void *arg) +{ + return tor_event_new(base, -1, 0, cb, arg); +} +/** Work-alike replacement for evsignal_new() on pre-Libevent-2.0 systems. */ +struct event * +tor_evsignal_new(struct event_base * base, int sig, + void (*cb)(int, short, void *), void *arg) +{ + return tor_event_new(base, sig, EV_SIGNAL|EV_PERSIST, cb, arg); +} +/** Work-alike replacement for event_free() on pre-Libevent-2.0 systems. */ +void +tor_event_free(struct event *ev) +{ + event_del(ev); + tor_free(ev); +} +#endif + +/** Global event base for use by the main thread. */ +struct event_base *the_event_base = NULL; + +/* This is what passes for version detection on OSX. We set + * MACOSX_KQUEUE_IS_BROKEN to true iff we're on a version of OSX before + * 10.4.0 (aka 1040). */ +#ifdef __APPLE__ +#ifdef __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ +#define MACOSX_KQUEUE_IS_BROKEN \ + (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 1040) +#else +#define MACOSX_KQUEUE_IS_BROKEN 0 +#endif +#endif + +#ifdef USE_BUFFEREVENTS +static int using_iocp_bufferevents = 0; +static void tor_libevent_set_tick_timeout(int msec_per_tick); + +int +tor_libevent_using_iocp_bufferevents(void) +{ + return using_iocp_bufferevents; +} +#endif + +/** Initialize the Libevent library and set up the event base. */ +void +tor_libevent_initialize(tor_libevent_cfg *torcfg) +{ + tor_assert(the_event_base == NULL); + /* some paths below don't use torcfg, so avoid unused variable warnings */ + (void)torcfg; + +#ifdef HAVE_EVENT2_EVENT_H + { + int attempts = 0; + int using_threads; + struct event_config *cfg; + + retry: + ++attempts; + using_threads = 0; + cfg = event_config_new(); + tor_assert(cfg); + +#if defined(_WIN32) && defined(USE_BUFFEREVENTS) + if (! torcfg->disable_iocp) { + evthread_use_windows_threads(); + event_config_set_flag(cfg, EVENT_BASE_FLAG_STARTUP_IOCP); + using_iocp_bufferevents = 1; + using_threads = 1; + } else { + using_iocp_bufferevents = 0; + } +#endif + + if (!using_threads) { + /* Telling Libevent not to try to turn locking on can avoid a needless + * socketpair() attempt. */ + event_config_set_flag(cfg, EVENT_BASE_FLAG_NOLOCK); + } + +#if defined(LIBEVENT_VERSION_NUMBER) && LIBEVENT_VERSION_NUMBER >= V(2,0,7) + if (torcfg->num_cpus > 0) + event_config_set_num_cpus_hint(cfg, torcfg->num_cpus); +#endif + +#if LIBEVENT_VERSION_NUMBER >= V(2,0,9) + /* We can enable changelist support with epoll, since we don't give + * Libevent any dup'd fds. This lets us avoid some syscalls. */ + event_config_set_flag(cfg, EVENT_BASE_FLAG_EPOLL_USE_CHANGELIST); +#endif + + the_event_base = event_base_new_with_config(cfg); + + event_config_free(cfg); + + if (using_threads && the_event_base == NULL && attempts < 2) { + /* This could be a socketpair() failure, which can happen sometimes on + * windows boxes with obnoxious firewall rules. Downgrade and try + * again. */ +#if defined(_WIN32) && defined(USE_BUFFEREVENTS) + if (torcfg->disable_iocp == 0) { + log_warn(LD_GENERAL, "Unable to initialize Libevent. Trying again " + "with IOCP disabled."); + } else +#endif + { + log_warn(LD_GENERAL, "Unable to initialize Libevent. Trying again."); + } + + torcfg->disable_iocp = 1; + goto retry; + } + } +#else + the_event_base = event_init(); +#endif + + if (!the_event_base) { + log_err(LD_GENERAL, "Unable to initialize Libevent: cannot continue."); + exit(1); + } + +#if defined(HAVE_EVENT_GET_VERSION) && defined(HAVE_EVENT_GET_METHOD) + /* Making this a NOTICE for now so we can link bugs to a libevent versions + * or methods better. */ + log_info(LD_GENERAL, + "Initialized libevent version %s using method %s. Good.", + event_get_version(), tor_libevent_get_method()); +#else + log_notice(LD_GENERAL, + "Initialized old libevent (version 1.0b or earlier)."); + log_warn(LD_GENERAL, + "You have a *VERY* old version of libevent. It is likely to be buggy; " + "please build Tor with a more recent version."); +#endif + +#ifdef USE_BUFFEREVENTS + tor_libevent_set_tick_timeout(torcfg->msec_per_tick); +#endif +} + +/** Return the current Libevent event base that we're set up to use. */ +struct event_base * +tor_libevent_get_base(void) +{ + return the_event_base; +} + +#ifndef HAVE_EVENT_BASE_LOOPEXIT +/** Replacement for event_base_loopexit on some very old versions of Libevent + * that we are not yet brave enough to deprecate. */ +int +tor_event_base_loopexit(struct event_base *base, struct timeval *tv) +{ + tor_assert(base == the_event_base); + return event_loopexit(tv); +} +#endif + +/** Return the name of the Libevent backend we're using. */ +const char * +tor_libevent_get_method(void) +{ +#ifdef HAVE_EVENT2_EVENT_H + return event_base_get_method(the_event_base); +#elif defined(HAVE_EVENT_GET_METHOD) + return event_get_method(); +#else + return ""; +#endif +} + +/** Return the le_version_t for the version of libevent specified in the + * string v. If the version is very new or uses an unrecognized + * version, format, return LE_OTHER. */ +static le_version_t +tor_decode_libevent_version(const char *v) +{ + unsigned major, minor, patchlevel; + char c, e, extra; + int fields; + + /* Try the new preferred "1.4.11-stable" format. + * Also accept "1.4.14b-stable". */ + fields = tor_sscanf(v, "%u.%u.%u%c%c", &major, &minor, &patchlevel, &c, &e); + if (fields == 3 || + ((fields == 4 || fields == 5 ) && (c == '-' || c == '_')) || + (fields == 5 && TOR_ISALPHA(c) && (e == '-' || e == '_'))) { + return V(major,minor,patchlevel); + } + + /* Try the old "1.3e" format. */ + fields = tor_sscanf(v, "%u.%u%c%c", &major, &minor, &c, &extra); + if (fields == 3 && TOR_ISALPHA(c)) { + return V_OLD(major, minor, c); + } else if (fields == 2) { + return V(major, minor, 0); + } + + return LE_OTHER; +} + +/** Return an integer representing the binary interface of a Libevent library. + * Two different versions with different numbers are sure not to be binary + * compatible. Two different versions with the same numbers have a decent + * chance of binary compatibility.*/ +static int +le_versions_compatibility(le_version_t v) +{ + if (v == LE_OTHER) + return 0; + if (v < V_OLD(1,0,'c')) + return 1; + else if (v < V(1,4,0)) + return 2; + else if (v < V(1,4,99)) + return 3; + else if (v < V(2,0,1)) + return 4; + else /* Everything 2.0 and later should be compatible. */ + return 5; +} + +#if 0 +/** Return the version number of the currently running version of Libevent. + * See le_version_t for info on the format. + */ +static le_version_t +tor_get_libevent_version(const char **v_out) +{ + const char *v; + le_version_t r; +#if defined(HAVE_EVENT_GET_VERSION_NUMBER) + v = event_get_version(); + r = event_get_version_number(); +#elif defined (HAVE_EVENT_GET_VERSION) + v = event_get_version(); + r = tor_decode_libevent_version(v); +#else + v = "pre-1.0c"; + r = LE_OLD; +#endif + if (v_out) + *v_out = v; + return r; +} +#endif + +/** Return a string representation of the version of the currently running + * version of Libevent. */ +const char * +tor_libevent_get_version_str(void) +{ +#ifdef HAVE_EVENT_GET_VERSION + return event_get_version(); +#else + return "pre-1.0c"; +#endif +} + +/** + * Compare the current Libevent method and version to a list of versions + * which are known not to work. Warn the user as appropriate. + */ +void +tor_check_libevent_version(const char *m, int server, + const char **badness_out) +{ + (void) m; + (void) server; + *badness_out = NULL; +} + +#if defined(LIBEVENT_VERSION) +#define HEADER_VERSION LIBEVENT_VERSION +#elif defined(_EVENT_VERSION) +#define HEADER_VERSION _EVENT_VERSION +#endif + +/** Return a string representation of the version of Libevent that was used +* at compilation time. */ +const char * +tor_libevent_get_header_version_str(void) +{ + return HEADER_VERSION; +} + +/** See whether the headers we were built against differ from the library we + * linked against so much that we're likely to crash. If so, warn the + * user. */ +void +tor_check_libevent_header_compatibility(void) +{ + (void) le_versions_compatibility; + (void) tor_decode_libevent_version; + + /* In libevent versions before 2.0, it's hard to keep binary compatibility + * between upgrades, and unpleasant to detect when the version we compiled + * against is unlike the version we have linked against. Here's how. */ +#if defined(HEADER_VERSION) && defined(HAVE_EVENT_GET_VERSION) + /* We have a header-file version and a function-call version. Easy. */ + if (strcmp(HEADER_VERSION, event_get_version())) { + le_version_t v1, v2; + int compat1 = -1, compat2 = -1; + int verybad; + v1 = tor_decode_libevent_version(HEADER_VERSION); + v2 = tor_decode_libevent_version(event_get_version()); + compat1 = le_versions_compatibility(v1); + compat2 = le_versions_compatibility(v2); + + verybad = compat1 != compat2; + + tor_log(verybad ? LOG_WARN : LOG_NOTICE, + LD_GENERAL, "We were compiled with headers from version %s " + "of Libevent, but we're using a Libevent library that says it's " + "version %s.", HEADER_VERSION, event_get_version()); + if (verybad) + log_warn(LD_GENERAL, "This will almost certainly make Tor crash."); + else + log_info(LD_GENERAL, "I think these versions are binary-compatible."); + } +#elif defined(HAVE_EVENT_GET_VERSION) + /* event_get_version but no _EVENT_VERSION. We might be in 1.4.0-beta or + earlier, where that's normal. To see whether we were compiled with an + earlier version, let's see whether the struct event defines MIN_HEAP_IDX. + */ +#ifdef HAVE_STRUCT_EVENT_MIN_HEAP_IDX + /* The header files are 1.4.0-beta or later. If the version is not + * 1.4.0-beta, we are incompatible. */ + { + if (strcmp(event_get_version(), "1.4.0-beta")) { + log_warn(LD_GENERAL, "It's a little hard to tell, but you seem to have " + "Libevent 1.4.0-beta header files, whereas you have linked " + "against Libevent %s. This will probably make Tor crash.", + event_get_version()); + } + } +#else + /* Our headers are 1.3e or earlier. If the library version is not 1.4.x or + later, we're probably fine. */ + { + const char *v = event_get_version(); + if ((v[0] == '1' && v[2] == '.' && v[3] > '3') || v[0] > '1') { + log_warn(LD_GENERAL, "It's a little hard to tell, but you seem to have " + "Libevent header file from 1.3e or earlier, whereas you have " + "linked against Libevent %s. This will probably make Tor " + "crash.", event_get_version()); + } + } +#endif + +#elif defined(HEADER_VERSION) +#warn "_EVENT_VERSION is defined but not get_event_version(): Libevent is odd." +#else + /* Your libevent is ancient. */ +#endif +} + +/* + If possible, we're going to try to use Libevent's periodic timer support, + since it does a pretty good job of making sure that periodic events get + called exactly M seconds apart, rather than starting each one exactly M + seconds after the time that the last one was run. + */ +#ifdef HAVE_EVENT2_EVENT_H +#define HAVE_PERIODIC +#define PERIODIC_FLAGS EV_PERSIST +#else +#define PERIODIC_FLAGS 0 +#endif + +/** Represents a timer that's run every N microseconds by Libevent. */ +struct periodic_timer_t { + /** Underlying event used to implement this periodic event. */ + struct event *ev; + /** The callback we'll be invoking whenever the event triggers */ + void (*cb)(struct periodic_timer_t *, void *); + /** User-supplied data for the callback */ + void *data; +#ifndef HAVE_PERIODIC + /** If Libevent doesn't know how to invoke events every N microseconds, + * we'll need to remember the timeout interval here. */ + struct timeval tv; +#endif +}; + +/** Libevent callback to implement a periodic event. */ +static void +periodic_timer_cb(evutil_socket_t fd, short what, void *arg) +{ + periodic_timer_t *timer = arg; + (void) what; + (void) fd; +#ifndef HAVE_PERIODIC + /** reschedule the event as needed. */ + event_add(timer->ev, &timer->tv); +#endif + timer->cb(timer, timer->data); +} + +/** Create and schedule a new timer that will run every tv in + * the event loop of base. When the timer fires, it will + * run the timer in cb with the user-supplied data in data. */ +periodic_timer_t * +periodic_timer_new(struct event_base *base, + const struct timeval *tv, + void (*cb)(periodic_timer_t *timer, void *data), + void *data) +{ + periodic_timer_t *timer; + tor_assert(base); + tor_assert(tv); + tor_assert(cb); + timer = tor_malloc_zero(sizeof(periodic_timer_t)); + if (!(timer->ev = tor_event_new(base, -1, PERIODIC_FLAGS, + periodic_timer_cb, timer))) { + tor_free(timer); + return NULL; + } + timer->cb = cb; + timer->data = data; +#ifndef HAVE_PERIODIC + memcpy(&timer->tv, tv, sizeof(struct timeval)); +#endif + event_add(timer->ev, (struct timeval *)tv); /*drop const for old libevent*/ + return timer; +} + +/** Stop and free a periodic timer */ +void +periodic_timer_free(periodic_timer_t *timer) +{ + if (!timer) + return; + tor_event_free(timer->ev); + tor_free(timer); +} + +#ifdef USE_BUFFEREVENTS +static const struct timeval *one_tick = NULL; +/** + * Return a special timeout to be passed whenever libevent's O(1) timeout + * implementation should be used. Only use this when the timer is supposed + * to fire after msec_per_tick ticks have elapsed. +*/ +const struct timeval * +tor_libevent_get_one_tick_timeout(void) +{ + tor_assert(one_tick); + return one_tick; +} + +/** Initialize the common timeout that we'll use to refill the buckets every + * time a tick elapses. */ +static void +tor_libevent_set_tick_timeout(int msec_per_tick) +{ + struct event_base *base = tor_libevent_get_base(); + struct timeval tv; + + tor_assert(! one_tick); + tv.tv_sec = msec_per_tick / 1000; + tv.tv_usec = (msec_per_tick % 1000) * 1000; + one_tick = event_base_init_common_timeout(base, &tv); +} + +static struct bufferevent * +tor_get_root_bufferevent(struct bufferevent *bev) +{ + struct bufferevent *u; + while ((u = bufferevent_get_underlying(bev)) != NULL) + bev = u; + return bev; +} + +int +tor_set_bufferevent_rate_limit(struct bufferevent *bev, + struct ev_token_bucket_cfg *cfg) +{ + return bufferevent_set_rate_limit(tor_get_root_bufferevent(bev), cfg); +} + +int +tor_add_bufferevent_to_rate_limit_group(struct bufferevent *bev, + struct bufferevent_rate_limit_group *g) +{ + return bufferevent_add_to_rate_limit_group(tor_get_root_bufferevent(bev), g); +} +#endif + +#if defined(LIBEVENT_VERSION_NUMBER) && LIBEVENT_VERSION_NUMBER >= V(2,1,1) +void +tor_gettimeofday_cached(struct timeval *tv) +{ + event_base_gettimeofday_cached(the_event_base, tv); +} +void +tor_gettimeofday_cache_clear(void) +{ + event_base_update_cache_time(the_event_base); +} +#else +/** Cache the current hi-res time; the cache gets reset when libevent + * calls us. */ +static struct timeval cached_time_hires = {0, 0}; + +/** Return a fairly recent view of the current time. */ +void +tor_gettimeofday_cached(struct timeval *tv) +{ + if (cached_time_hires.tv_sec == 0) { + tor_gettimeofday(&cached_time_hires); + } + *tv = cached_time_hires; +} + +/** Reset the cached view of the current time, so that the next time we try + * to learn it, we will get an up-to-date value. */ +void +tor_gettimeofday_cache_clear(void) +{ + cached_time_hires.tv_sec = 0; +} +#endif + diff --git a/src/tor/compat_libevent.h b/src/tor/compat_libevent.h new file mode 100644 index 0000000..fda8733 --- /dev/null +++ b/src/tor/compat_libevent.h @@ -0,0 +1,96 @@ +/* Copyright (c) 2009-2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_COMPAT_LIBEVENT_H +#define TOR_COMPAT_LIBEVENT_H + +#include "orconfig.h" + +struct event; +struct event_base; +#ifdef USE_BUFFEREVENTS +struct bufferevent; +struct ev_token_bucket_cfg; +struct bufferevent_rate_limit_group; +#endif + +#ifdef HAVE_EVENT2_EVENT_H +#include +#elif !defined(EVUTIL_SOCKET_DEFINED) +#define EVUTIL_SOCKET_DEFINED +#define evutil_socket_t int +#endif + +void configure_libevent_logging(void); +void suppress_libevent_log_msg(const char *msg); + +#ifdef HAVE_EVENT2_EVENT_H +#define tor_event_new event_new +#define tor_evtimer_new evtimer_new +#define tor_evsignal_new evsignal_new +#define tor_event_free event_free +#define tor_evdns_add_server_port(sock, tcp, cb, data) \ + evdns_add_server_port_with_base(tor_libevent_get_base(), \ + (sock),(tcp),(cb),(data)); + +#else +struct event *tor_event_new(struct event_base * base, evutil_socket_t sock, + short what, void (*cb)(evutil_socket_t, short, void *), void *arg); +struct event *tor_evtimer_new(struct event_base * base, + void (*cb)(evutil_socket_t, short, void *), void *arg); +struct event *tor_evsignal_new(struct event_base * base, int sig, + void (*cb)(evutil_socket_t, short, void *), void *arg); +void tor_event_free(struct event *ev); +#define tor_evdns_add_server_port evdns_add_server_port +#endif + +typedef struct periodic_timer_t periodic_timer_t; + +periodic_timer_t *periodic_timer_new(struct event_base *base, + const struct timeval *tv, + void (*cb)(periodic_timer_t *timer, void *data), + void *data); +void periodic_timer_free(periodic_timer_t *); + +#ifdef HAVE_EVENT_BASE_LOOPEXIT +#define tor_event_base_loopexit event_base_loopexit +#else +struct timeval; +int tor_event_base_loopexit(struct event_base *base, struct timeval *tv); +#endif + +/** Defines a configuration for using libevent with Tor: passed as an argument + * to tor_libevent_initialize() to describe how we want to set up. */ +typedef struct tor_libevent_cfg { + /** Flag: if true, disable IOCP (assuming that it could be enabled). */ + int disable_iocp; + /** How many CPUs should we use (relevant only with IOCP). */ + int num_cpus; + /** How many milliseconds should we allow between updating bandwidth limits? + * (relevant only with bufferevents). */ + int msec_per_tick; +} tor_libevent_cfg; + +void tor_libevent_initialize(tor_libevent_cfg *cfg); +struct event_base *tor_libevent_get_base(void); +const char *tor_libevent_get_method(void); +void tor_check_libevent_version(const char *m, int server, + const char **badness_out); +void tor_check_libevent_header_compatibility(void); +const char *tor_libevent_get_version_str(void); +const char *tor_libevent_get_header_version_str(void); + +#ifdef USE_BUFFEREVENTS +const struct timeval *tor_libevent_get_one_tick_timeout(void); +int tor_libevent_using_iocp_bufferevents(void); +int tor_set_bufferevent_rate_limit(struct bufferevent *bev, + struct ev_token_bucket_cfg *cfg); +int tor_add_bufferevent_to_rate_limit_group(struct bufferevent *bev, + struct bufferevent_rate_limit_group *g); +#endif + +void tor_gettimeofday_cached(struct timeval *tv); +void tor_gettimeofday_cache_clear(void); + +#endif + diff --git a/src/tor/config.c b/src/tor/config.c new file mode 100644 index 0000000..d44971d --- /dev/null +++ b/src/tor/config.c @@ -0,0 +1,6704 @@ + /* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file config.c + * \brief Code to parse and interpret configuration files. + **/ + +#define CONFIG_PRIVATE +#include "or.h" +#include "addressmap.h" +#include "channel.h" +#include "circuitbuild.h" +#include "circuitlist.h" +#include "circuitmux.h" +#include "circuitmux_ewma.h" +#include "config.h" +#include "connection.h" +#include "connection_edge.h" +#include "connection_or.h" +#include "control.h" +#include "confparse.h" +#include "cpuworker.h" +#include "dirserv.h" +#include "dirvote.h" +#include "dns.h" +#include "entrynodes.h" +#include "geoip.h" +#include "hibernate.h" +#include "onion_main.h" +#include "networkstatus.h" +#include "nodelist.h" +#include "policies.h" +#include "relay.h" +#include "rendclient.h" +#include "rendservice.h" +#include "rephist.h" +#include "router.h" +#include "sandbox.h" +#include "tor_util.h" +#include "routerlist.h" +#include "routerset.h" +#include "statefile.h" +#include "transports.h" +#include "ext_orport.h" +#include "torgzip.h" +#include "anonymize.h" +#ifdef _WIN32 +#include +#endif + +#include "procmon.h" + +/* From onion_main.c */ +extern int quiet_level; + +/** A list of abbreviations and aliases to map command-line options, obsolete + * option names, or alternative option names, to their current values. */ +static config_abbrev_t option_abbrevs_[] = { + PLURAL(AuthDirBadDirCC), + PLURAL(AuthDirBadExitCC), + PLURAL(AuthDirInvalidCC), + PLURAL(AuthDirRejectCC), + PLURAL(ExitNode), + PLURAL(EntryNode), + PLURAL(ExcludeNode), + PLURAL(FirewallPort), + PLURAL(LongLivedPort), + PLURAL(HiddenServiceNode), + PLURAL(HiddenServiceExcludeNode), + PLURAL(NumCPU), + PLURAL(RendNode), + PLURAL(RendExcludeNode), + PLURAL(StrictEntryNode), + PLURAL(StrictExitNode), + PLURAL(StrictNode), + { "l", "Log", 1, 0}, + { "AllowUnverifiedNodes", "AllowInvalidNodes", 0, 0}, + { "AutomapHostSuffixes", "AutomapHostsSuffixes", 0, 0}, + { "AutomapHostOnResolve", "AutomapHostsOnResolve", 0, 0}, + { "BandwidthRateBytes", "BandwidthRate", 0, 0}, + { "BandwidthBurstBytes", "BandwidthBurst", 0, 0}, + { "DirFetchPostPeriod", "StatusFetchPeriod", 0, 0}, + { "DirServer", "DirAuthority", 0, 0}, /* XXXX024 later, make this warn? */ + { "MaxConn", "ConnLimit", 0, 1}, + { "ORBindAddress", "ORListenAddress", 0, 0}, + { "DirBindAddress", "DirListenAddress", 0, 0}, + { "SocksBindAddress", "SocksListenAddress", 0, 0}, + { "UseHelperNodes", "UseEntryGuards", 0, 0}, + { "NumHelperNodes", "NumEntryGuards", 0, 0}, + { "UseEntryNodes", "UseEntryGuards", 0, 0}, + { "NumEntryNodes", "NumEntryGuards", 0, 0}, + { "ResolvConf", "ServerDNSResolvConfFile", 0, 1}, + { "SearchDomains", "ServerDNSSearchDomains", 0, 1}, + { "ServerDNSAllowBrokenResolvConf", "ServerDNSAllowBrokenConfig", 0, 0}, + { "PreferTunnelledDirConns", "PreferTunneledDirConns", 0, 0}, + { "BridgeAuthoritativeDirectory", "BridgeAuthoritativeDir", 0, 0}, + { "HashedControlPassword", "__HashedControlSessionPassword", 1, 0}, + { "StrictEntryNodes", "StrictNodes", 0, 1}, + { "StrictExitNodes", "StrictNodes", 0, 1}, + { "VirtualAddrNetwork", "VirtualAddrNetworkIPv4", 0, 0}, + { "_UseFilteringSSLBufferevents", "UseFilteringSSLBufferevents", 0, 1}, + { NULL, NULL, 0, 0}, +}; + +/** An entry for config_vars: "The option name has type + * CONFIG_TYPE_conftype, and corresponds to + * or_options_t.member" + */ +#define VAR(name,conftype,member,initvalue) \ + { name, CONFIG_TYPE_ ## conftype, STRUCT_OFFSET(or_options_t, member), \ + initvalue } +/** As VAR, but the option name and member name are the same. */ +#define V(member,conftype,initvalue) \ + VAR(#member, conftype, member, initvalue) +/** An entry for config_vars: "The option name is obsolete." */ +#define OBSOLETE(name) { name, CONFIG_TYPE_OBSOLETE, 0, NULL } + +#define VPORT(member,conftype,initvalue) \ + VAR(#member, conftype, member ## _lines, initvalue) + +/** Array of configuration options. Until we disallow nonstandard + * abbreviations, order is significant, since the first matching option will + * be chosen first. + */ +static config_var_t option_vars_[] = { + OBSOLETE("AccountingMaxKB"), + V(AccountingMax, MEMUNIT, "0 bytes"), + V(AccountingStart, STRING, NULL), + V(Address, STRING, NULL), + V(AllowDotExit, BOOL, "0"), + V(AllowInvalidNodes, CSV, "middle,rendezvous"), + V(AllowNonRFC953Hostnames, BOOL, "0"), + V(AllowSingleHopCircuits, BOOL, "0"), + V(AllowSingleHopExits, BOOL, "0"), + V(AlternateBridgeAuthority, LINELIST, NULL), + V(AlternateDirAuthority, LINELIST, NULL), + V(AlternateHSAuthority, LINELIST, NULL), + V(AssumeReachable, BOOL, "0"), + V(AuthDirBadDir, LINELIST, NULL), + V(AuthDirBadDirCCs, CSV, ""), + V(AuthDirBadExit, LINELIST, NULL), + V(AuthDirBadExitCCs, CSV, ""), + V(AuthDirInvalid, LINELIST, NULL), + V(AuthDirInvalidCCs, CSV, ""), + V(AuthDirFastGuarantee, MEMUNIT, "100 KB"), + V(AuthDirGuardBWGuarantee, MEMUNIT, "250 KB"), + V(AuthDirReject, LINELIST, NULL), + V(AuthDirRejectCCs, CSV, ""), + V(AuthDirRejectUnlisted, BOOL, "0"), + V(AuthDirListBadDirs, BOOL, "0"), + V(AuthDirListBadExits, BOOL, "0"), + V(AuthDirMaxServersPerAddr, UINT, "2"), + V(AuthDirMaxServersPerAuthAddr,UINT, "5"), + V(AuthDirHasIPv6Connectivity, BOOL, "0"), + VAR("AuthoritativeDirectory", BOOL, AuthoritativeDir, "0"), + V(AutomapHostsOnResolve, BOOL, "0"), + V(AutomapHostsSuffixes, CSV, ".onion,.exit"), + V(AvoidDiskWrites, BOOL, "0"), + V(BandwidthBurst, MEMUNIT, "1 GB"), + V(BandwidthRate, MEMUNIT, "1 GB"), + V(BridgeAuthoritativeDir, BOOL, "0"), + VAR("Bridge", LINELIST, Bridges, NULL), + V(BridgePassword, STRING, NULL), + V(BridgeRecordUsageByCountry, BOOL, "1"), + V(BridgeRelay, BOOL, "0"), + V(CellStatistics, BOOL, "0"), + V(LearnCircuitBuildTimeout, BOOL, "1"), + V(CircuitBuildTimeout, INTERVAL, "0"), + V(CircuitIdleTimeout, INTERVAL, "1 hour"), + V(CircuitStreamTimeout, INTERVAL, "0"), + V(CircuitPriorityHalflife, DOUBLE, "-100.0"), /*negative:'Use default'*/ + V(ClientDNSRejectInternalAddresses, BOOL,"1"), + V(ClientOnly, BOOL, "0"), + V(ClientPreferIPv6ORPort, BOOL, "0"), + V(ClientRejectInternalAddresses, BOOL, "1"), + V(ClientTransportPlugin, LINELIST, NULL), + V(ClientUseIPv6, BOOL, "0"), + V(ConsensusParams, STRING, NULL), + V(ConnLimit, UINT, "1000"), + V(ConnDirectionStatistics, BOOL, "0"), + V(ConstrainedSockets, BOOL, "0"), + V(ConstrainedSockSize, MEMUNIT, "8192"), + V(ContactInfo, STRING, NULL), + V(ControlListenAddress, LINELIST, NULL), + VPORT(ControlPort, LINELIST, NULL), + V(ControlPortFileGroupReadable,BOOL, "0"), + V(ControlPortWriteToFile, FILENAME, NULL), + V(ControlSocket, LINELIST, NULL), + V(ControlSocketsGroupWritable, BOOL, "0"), + V(CookieAuthentication, BOOL, "0"), + V(CookieAuthFileGroupReadable, BOOL, "0"), + V(CookieAuthFile, STRING, NULL), + V(CountPrivateBandwidth, BOOL, "0"), + V(DataDirectory, FILENAME, NULL), + OBSOLETE("DebugLogFile"), + V(DisableNetwork, BOOL, "0"), + V(DirAllowPrivateAddresses, BOOL, "0"), + V(TestingAuthDirTimeToLearnReachability, INTERVAL, "30 minutes"), + V(DirListenAddress, LINELIST, NULL), + OBSOLETE("DirFetchPeriod"), + V(DirPolicy, LINELIST, NULL), + VPORT(DirPort, LINELIST, NULL), + V(DirPortFrontPage, FILENAME, NULL), + OBSOLETE("DirPostPeriod"), + OBSOLETE("DirRecordUsageByCountry"), + OBSOLETE("DirRecordUsageGranularity"), + OBSOLETE("DirRecordUsageRetainIPs"), + OBSOLETE("DirRecordUsageSaveInterval"), + V(DirReqStatistics, BOOL, "1"), + VAR("DirAuthority", LINELIST, DirAuthorities, NULL), + V(DirAuthorityFallbackRate, DOUBLE, "1.0"), + V(DisableAllSwap, BOOL, "0"), + V(DisableDebuggerAttachment, BOOL, "1"), + V(DisableIOCP, BOOL, "1"), + OBSOLETE("DisableV2DirectoryInfo_"), + V(DynamicDHGroups, BOOL, "0"), + VPORT(DNSPort, LINELIST, NULL), + V(DNSListenAddress, LINELIST, NULL), + V(DownloadExtraInfo, BOOL, "0"), + V(TestingEnableConnBwEvent, BOOL, "0"), + V(TestingEnableCellStatsEvent, BOOL, "0"), + V(TestingEnableTbEmptyEvent, BOOL, "0"), + V(EnforceDistinctSubnets, BOOL, "1"), + V(EntryNodes, ROUTERSET, NULL), + V(EntryStatistics, BOOL, "0"), + V(TestingEstimatedDescriptorPropagationTime, INTERVAL, "10 minutes"), + V(ExcludeNodes, ROUTERSET, NULL), + V(ExcludeExitNodes, ROUTERSET, NULL), + V(ExcludeSingleHopRelays, BOOL, "1"), + V(ExitNodes, ROUTERSET, NULL), + V(ExitPolicy, LINELIST, NULL), + V(ExitPolicyRejectPrivate, BOOL, "1"), + V(ExitPortStatistics, BOOL, "0"), + V(ExtendAllowPrivateAddresses, BOOL, "0"), + VPORT(ExtORPort, LINELIST, NULL), + V(ExtraInfoStatistics, BOOL, "1"), + V(FallbackDir, LINELIST, NULL), + + OBSOLETE("FallbackNetworkstatusFile"), + V(FascistFirewall, BOOL, "0"), + V(FirewallPorts, CSV, ""), + V(FastFirstHopPK, AUTOBOOL, "auto"), + V(FetchDirInfoEarly, BOOL, "0"), + V(FetchDirInfoExtraEarly, BOOL, "0"), + V(FetchServerDescriptors, BOOL, "1"), + V(FetchHidServDescriptors, BOOL, "1"), + V(FetchUselessDescriptors, BOOL, "0"), + OBSOLETE("FetchV2Networkstatus"), + V(GeoIPExcludeUnknown, AUTOBOOL, "auto"), +#ifdef _WIN32 + V(GeoIPFile, FILENAME, ""), + V(GeoIPv6File, FILENAME, ""), +#else + V(GeoIPFile, FILENAME, + "/usr/share" PATH_SEPARATOR "tor" PATH_SEPARATOR "geoip"), + V(GeoIPv6File, FILENAME, + "/usr/share" PATH_SEPARATOR "tor" PATH_SEPARATOR "geoip6"), +#endif + OBSOLETE("GiveGuardFlagTo_CVE_2011_2768_VulnerableRelays"), + OBSOLETE("Group"), + V(GuardLifetime, INTERVAL, "0 minutes"), + V(HardwareAccel, BOOL, "0"), + V(HeartbeatPeriod, INTERVAL, "6 hours"), + V(AccelName, STRING, NULL), + V(AccelDir, FILENAME, NULL), + V(HashedControlPassword, LINELIST, NULL), + V(HidServDirectoryV2, BOOL, "1"), + VAR("HiddenServiceDir", LINELIST_S, RendConfigLines, NULL), + OBSOLETE("HiddenServiceExcludeNodes"), + OBSOLETE("HiddenServiceNodes"), + VAR("HiddenServiceOptions",LINELIST_V, RendConfigLines, NULL), + VAR("HiddenServicePort", LINELIST_S, RendConfigLines, NULL), + VAR("HiddenServiceVersion",LINELIST_S, RendConfigLines, NULL), + VAR("HiddenServiceAuthorizeClient",LINELIST_S,RendConfigLines, NULL), + V(HidServAuth, LINELIST, NULL), + V(HSAuthoritativeDir, BOOL, "0"), + OBSOLETE("HSAuthorityRecordStats"), + V(CloseHSClientCircuitsImmediatelyOnTimeout, BOOL, "0"), + V(CloseHSServiceRendCircuitsImmediatelyOnTimeout, BOOL, "0"), + V(HTTPProxy, STRING, NULL), + V(HTTPProxyAuthenticator, STRING, NULL), + V(HTTPSProxy, STRING, NULL), + V(HTTPSProxyAuthenticator, STRING, NULL), + V(IPv6Exit, BOOL, "0"), + VAR("ServerTransportPlugin", LINELIST, ServerTransportPlugin, NULL), + V(ServerTransportListenAddr, LINELIST, NULL), + V(ServerTransportOptions, LINELIST, NULL), + V(Socks4Proxy, STRING, NULL), + V(Socks5Proxy, STRING, NULL), + V(Socks5ProxyUsername, STRING, NULL), + V(Socks5ProxyPassword, STRING, NULL), + OBSOLETE("IgnoreVersion"), + V(KeepalivePeriod, INTERVAL, "5 minutes"), + VAR("Log", LINELIST, Logs, NULL), + V(LogMessageDomains, BOOL, "0"), + OBSOLETE("LinkPadding"), + OBSOLETE("LogLevel"), + OBSOLETE("LogFile"), + V(LogTimeGranularity, MSEC_INTERVAL, "1 second"), + V(LongLivedPorts, CSV, + "21,22,706,1863,5050,5190,5222,5223,6523,6667,6697,8300"), + VAR("MapAddress", LINELIST, AddressMap, NULL), + V(MaxAdvertisedBandwidth, MEMUNIT, "1 GB"), + V(MaxCircuitDirtiness, INTERVAL, "10 minutes"), + V(MaxClientCircuitsPending, UINT, "32"), + V(MaxMemInCellQueues, MEMUNIT, "8 GB"), + OBSOLETE("MaxOnionsPending"), + V(MaxOnionQueueDelay, MSEC_INTERVAL, "1750 msec"), + V(MinMeasuredBWsForAuthToIgnoreAdvertised, INT, "500"), + OBSOLETE("MonthlyAccountingStart"), + V(MyFamily, STRING, NULL), + V(NewCircuitPeriod, INTERVAL, "30 seconds"), + VAR("NamingAuthoritativeDirectory",BOOL, NamingAuthoritativeDir, "0"), + V(NATDListenAddress, LINELIST, NULL), + VPORT(NATDPort, LINELIST, NULL), + V(Nickname, STRING, NULL), + V(WarnUnsafeSocks, BOOL, "1"), + OBSOLETE("NoPublish"), + VAR("NodeFamily", LINELIST, NodeFamilies, NULL), + V(NumCPUs, UINT, "0"), + V(NumDirectoryGuards, UINT, "0"), + V(NumEntryGuards, UINT, "3"), + V(ORListenAddress, LINELIST, NULL), + VPORT(ORPort, LINELIST, NULL), + V(OutboundBindAddress, LINELIST, NULL), + + OBSOLETE("PathBiasDisableRate"), + V(PathBiasCircThreshold, INT, "-1"), + V(PathBiasNoticeRate, DOUBLE, "-1"), + V(PathBiasWarnRate, DOUBLE, "-1"), + V(PathBiasExtremeRate, DOUBLE, "-1"), + V(PathBiasScaleThreshold, INT, "-1"), + OBSOLETE("PathBiasScaleFactor"), + OBSOLETE("PathBiasMultFactor"), + V(PathBiasDropGuards, AUTOBOOL, "0"), + OBSOLETE("PathBiasUseCloseCounts"), + + V(PathBiasUseThreshold, INT, "-1"), + V(PathBiasNoticeUseRate, DOUBLE, "-1"), + V(PathBiasExtremeUseRate, DOUBLE, "-1"), + V(PathBiasScaleUseThreshold, INT, "-1"), + + V(PathsNeededToBuildCircuits, DOUBLE, "-1"), + OBSOLETE("PathlenCoinWeight"), + V(PerConnBWBurst, MEMUNIT, "0"), + V(PerConnBWRate, MEMUNIT, "0"), + V(PidFile, STRING, NULL), + V(TestingTorNetwork, BOOL, "0"), + V(TestingMinExitFlagThreshold, MEMUNIT, "0"), + V(TestingMinFastFlagThreshold, MEMUNIT, "0"), + V(OptimisticData, AUTOBOOL, "auto"), + V(PortForwarding, BOOL, "0"), + V(PortForwardingHelper, FILENAME, "tor-fw-helper"), + V(PreferTunneledDirConns, BOOL, "1"), + V(ProtocolWarnings, BOOL, "0"), + V(PublishServerDescriptor, CSV, "1"), + V(PublishHidServDescriptors, BOOL, "1"), + V(ReachableAddresses, LINELIST, NULL), + V(ReachableDirAddresses, LINELIST, NULL), + V(ReachableORAddresses, LINELIST, NULL), + V(RecommendedVersions, LINELIST, NULL), + V(RecommendedClientVersions, LINELIST, NULL), + V(RecommendedServerVersions, LINELIST, NULL), + OBSOLETE("RedirectExit"), + V(RefuseUnknownExits, AUTOBOOL, "auto"), + V(RejectPlaintextPorts, CSV, ""), + V(RelayBandwidthBurst, MEMUNIT, "0"), + V(RelayBandwidthRate, MEMUNIT, "0"), + OBSOLETE("RendExcludeNodes"), + OBSOLETE("RendNodes"), + V(RendPostPeriod, INTERVAL, "1 hour"), + V(RephistTrackTime, INTERVAL, "24 hours"), + OBSOLETE("RouterFile"), + V(RunAsDaemon, BOOL, "0"), +// V(RunTesting, BOOL, "0"), + OBSOLETE("RunTesting"), // currently unused + V(Sandbox, BOOL, "0"), + V(SafeLogging, STRING, "1"), + V(SafeSocks, BOOL, "0"), + V(ServerDNSAllowBrokenConfig, BOOL, "1"), + V(ServerDNSAllowNonRFC953Hostnames, BOOL,"0"), + V(ServerDNSDetectHijacking, BOOL, "1"), + V(ServerDNSRandomizeCase, BOOL, "1"), + V(ServerDNSResolvConfFile, STRING, NULL), + V(ServerDNSSearchDomains, BOOL, "0"), + V(ServerDNSTestAddresses, CSV, + "www.google.com,www.mit.edu,www.yahoo.com,www.slashdot.org"), + V(ShutdownWaitLength, INTERVAL, "30 seconds"), + V(SocksListenAddress, LINELIST, NULL), + V(SocksPolicy, LINELIST, NULL), + VPORT(SocksPort, LINELIST, NULL), + V(SocksTimeout, INTERVAL, "2 minutes"), + V(SSLKeyLifetime, INTERVAL, "0"), + OBSOLETE("StatusFetchPeriod"), + V(StrictNodes, BOOL, "0"), + V(Support022HiddenServices, AUTOBOOL, "auto"), + OBSOLETE("SysLog"), + V(TestSocks, BOOL, "0"), + OBSOLETE("TestVia"), + V(TokenBucketRefillInterval, MSEC_INTERVAL, "100 msec"), + V(Tor2webMode, BOOL, "0"), + V(TLSECGroup, STRING, NULL), + V(TrackHostExits, CSV, NULL), + V(TrackHostExitsExpire, INTERVAL, "30 minutes"), + OBSOLETE("TrafficShaping"), + V(TransListenAddress, LINELIST, NULL), + VPORT(TransPort, LINELIST, NULL), + V(TransProxyType, STRING, "default"), + V(TunnelDirConns, BOOL, "1"), + V(UpdateBridgesFromAuthority, BOOL, "0"), + V(UseBridges, BOOL, "0"), + V(UseEntryGuards, BOOL, "1"), + V(UseEntryGuardsAsDirGuards, BOOL, "1"), + V(UseMicrodescriptors, AUTOBOOL, "auto"), + V(UseNTorHandshake, AUTOBOOL, "1"), + V(User, STRING, NULL), + V(UserspaceIOCPBuffers, BOOL, "0"), + VAR("V1AuthoritativeDirectory",BOOL, V1AuthoritativeDir, "0"), + OBSOLETE("V2AuthoritativeDirectory"), + VAR("V3AuthoritativeDirectory",BOOL, V3AuthoritativeDir, "0"), + V(TestingV3AuthInitialVotingInterval, INTERVAL, "30 minutes"), + V(TestingV3AuthInitialVoteDelay, INTERVAL, "5 minutes"), + V(TestingV3AuthInitialDistDelay, INTERVAL, "5 minutes"), + V(TestingV3AuthVotingStartOffset, INTERVAL, "0"), + V(V3AuthVotingInterval, INTERVAL, "1 hour"), + V(V3AuthVoteDelay, INTERVAL, "5 minutes"), + V(V3AuthDistDelay, INTERVAL, "5 minutes"), + V(V3AuthNIntervalsValid, UINT, "3"), + V(V3AuthUseLegacyKey, BOOL, "0"), + V(V3BandwidthsFile, FILENAME, NULL), + VAR("VersioningAuthoritativeDirectory",BOOL,VersioningAuthoritativeDir, "0"), + V(VirtualAddrNetworkIPv4, STRING, "127.192.0.0/10"), + V(VirtualAddrNetworkIPv6, STRING, "[FE80::]/10"), + V(WarnPlaintextPorts, CSV, "23,109,110,143"), + V(UseFilteringSSLBufferevents, BOOL, "0"), + VAR("__ReloadTorrcOnSIGHUP", BOOL, ReloadTorrcOnSIGHUP, "1"), + VAR("__AllDirActionsPrivate", BOOL, AllDirActionsPrivate, "0"), + VAR("__DisablePredictedCircuits",BOOL,DisablePredictedCircuits, "0"), + VAR("__LeaveStreamsUnattached",BOOL, LeaveStreamsUnattached, "0"), + VAR("__HashedControlSessionPassword", LINELIST, HashedControlSessionPassword, + NULL), + VAR("__OwningControllerProcess",STRING,OwningControllerProcess, NULL), + V(MinUptimeHidServDirectoryV2, INTERVAL, "25 hours"), + V(VoteOnHidServDirectoriesV2, BOOL, "1"), + V(TestingServerDownloadSchedule, CSV_INTERVAL, "0, 0, 0, 60, 60, 120, " + "300, 900, 2147483647"), + V(TestingClientDownloadSchedule, CSV_INTERVAL, "0, 0, 60, 300, 600, " + "2147483647"), + V(TestingServerConsensusDownloadSchedule, CSV_INTERVAL, "0, 0, 60, " + "300, 600, 1800, 1800, 1800, 1800, " + "1800, 3600, 7200"), + V(TestingClientConsensusDownloadSchedule, CSV_INTERVAL, "0, 0, 60, " + "300, 600, 1800, 3600, 3600, 3600, " + "10800, 21600, 43200"), + V(TestingBridgeDownloadSchedule, CSV_INTERVAL, "3600, 900, 900, 3600"), + V(TestingClientMaxIntervalWithoutRequest, INTERVAL, "10 minutes"), + V(TestingDirConnectionMaxStall, INTERVAL, "5 minutes"), + V(TestingConsensusMaxDownloadTries, UINT, "8"), + V(TestingDescriptorMaxDownloadTries, UINT, "8"), + V(TestingMicrodescMaxDownloadTries, UINT, "8"), + V(TestingCertMaxDownloadTries, UINT, "8"), + V(TestingDirAuthVoteGuard, ROUTERSET, NULL), + VAR("___UsingTestNetworkDefaults", BOOL, UsingTestNetworkDefaults_, "0"), + + { NULL, CONFIG_TYPE_OBSOLETE, 0, NULL } +}; + +/** Override default values with these if the user sets the TestingTorNetwork + * option. */ +static const config_var_t testing_tor_network_defaults[] = { + V(ServerDNSAllowBrokenConfig, BOOL, "1"), + V(DirAllowPrivateAddresses, BOOL, "1"), + V(EnforceDistinctSubnets, BOOL, "0"), + V(AssumeReachable, BOOL, "1"), + V(AuthDirMaxServersPerAddr, UINT, "0"), + V(AuthDirMaxServersPerAuthAddr,UINT, "0"), + V(ClientDNSRejectInternalAddresses, BOOL,"0"), + V(ClientRejectInternalAddresses, BOOL, "0"), + V(CountPrivateBandwidth, BOOL, "1"), + V(ExitPolicyRejectPrivate, BOOL, "0"), + V(ExtendAllowPrivateAddresses, BOOL, "1"), + V(V3AuthVotingInterval, INTERVAL, "5 minutes"), + V(V3AuthVoteDelay, INTERVAL, "20 seconds"), + V(V3AuthDistDelay, INTERVAL, "20 seconds"), + V(TestingV3AuthInitialVotingInterval, INTERVAL, "5 minutes"), + V(TestingV3AuthInitialVoteDelay, INTERVAL, "20 seconds"), + V(TestingV3AuthInitialDistDelay, INTERVAL, "20 seconds"), + V(TestingV3AuthVotingStartOffset, INTERVAL, "0"), + V(TestingAuthDirTimeToLearnReachability, INTERVAL, "0 minutes"), + V(TestingEstimatedDescriptorPropagationTime, INTERVAL, "0 minutes"), + V(MinUptimeHidServDirectoryV2, INTERVAL, "0 minutes"), + V(TestingServerDownloadSchedule, CSV_INTERVAL, "0, 0, 0, 5, 10, 15, " + "20, 30, 60"), + V(TestingClientDownloadSchedule, CSV_INTERVAL, "0, 0, 5, 10, 15, 20, " + "30, 60"), + V(TestingServerConsensusDownloadSchedule, CSV_INTERVAL, "0, 0, 5, 10, " + "15, 20, 30, 60"), + V(TestingClientConsensusDownloadSchedule, CSV_INTERVAL, "0, 0, 5, 10, " + "15, 20, 30, 60"), + V(TestingBridgeDownloadSchedule, CSV_INTERVAL, "60, 30, 30, 60"), + V(TestingClientMaxIntervalWithoutRequest, INTERVAL, "5 seconds"), + V(TestingDirConnectionMaxStall, INTERVAL, "30 seconds"), + V(TestingConsensusMaxDownloadTries, UINT, "80"), + V(TestingDescriptorMaxDownloadTries, UINT, "80"), + V(TestingMicrodescMaxDownloadTries, UINT, "80"), + V(TestingCertMaxDownloadTries, UINT, "80"), + V(TestingEnableConnBwEvent, BOOL, "1"), + V(TestingEnableCellStatsEvent, BOOL, "1"), + V(TestingEnableTbEmptyEvent, BOOL, "1"), + VAR("___UsingTestNetworkDefaults", BOOL, UsingTestNetworkDefaults_, "1"), + + { NULL, CONFIG_TYPE_OBSOLETE, 0, NULL } +}; + +#undef VAR +#undef V +#undef OBSOLETE + +#ifdef _WIN32 +static char *get_windows_conf_root(void); +#endif +static int options_act_reversible(const or_options_t *old_options, char **msg); +static int options_act(const or_options_t *old_options); +static int options_transition_allowed(const or_options_t *old, + const or_options_t *new, + char **msg); +static int options_transition_affects_workers( + const or_options_t *old_options, const or_options_t *new_options); +static int options_transition_affects_descriptor( + const or_options_t *old_options, const or_options_t *new_options); +static int check_nickname_list(char **lst, const char *name, char **msg); + +static int parse_client_transport_line(const char *line, int validate_only); + +static int parse_server_transport_line(const char *line, int validate_only); +static char *get_bindaddr_from_transport_listen_line(const char *line, + const char *transport); +static int parse_dir_authority_line(const char *line, + dirinfo_type_t required_type, + int validate_only); +static int parse_dir_fallback_line(const char *line, + int validate_only); +static void port_cfg_free(port_cfg_t *port); +static int parse_ports(or_options_t *options, int validate_only, + char **msg_out, int *n_ports_out); +static int check_server_ports(const smartlist_t *ports, + const or_options_t *options); + +static int validate_data_directory(or_options_t *options); +static int write_configuration_file(const char *fname, + const or_options_t *options); +static int options_init_logs(or_options_t *options, int validate_only); + +static void init_libevent(const or_options_t *options); +static int opt_streq(const char *s1, const char *s2); +static int parse_outbound_addresses(or_options_t *options, int validate_only, + char **msg); +static void config_maybe_load_geoip_files_(const or_options_t *options, + const or_options_t *old_options); +static int options_validate_cb(void *old_options, void *options, + void *default_options, + int from_setconf, char **msg); + +/** Magic value for or_options_t. */ +#define OR_OPTIONS_MAGIC 9090909 + +/** Configuration format for or_options_t. */ +STATIC config_format_t options_format = { + sizeof(or_options_t), + OR_OPTIONS_MAGIC, + STRUCT_OFFSET(or_options_t, magic_), + option_abbrevs_, + option_vars_, + options_validate_cb, + NULL +}; + +/* + * Functions to read and write the global options pointer. + */ + +/** Command-line and config-file options. */ +static or_options_t *global_options = NULL; +/** The fallback options_t object; this is where we look for options not + * in torrc before we fall back to Tor's defaults. */ +static or_options_t *global_default_options = NULL; +/** Name of most recently read torrc file. */ +static char *torrc_fname = NULL; +/** Name of the most recently read torrc-defaults file.*/ +static char *torrc_defaults_fname; +/** Configuration options set by command line. */ +static config_line_t *global_cmdline_options = NULL; +/** Non-configuration options set by the command line */ +static config_line_t *global_cmdline_only_options = NULL; +/** Boolean: Have we parsed the command line? */ +static int have_parsed_cmdline = 0; +/** Contents of most recently read DirPortFrontPage file. */ +static char *global_dirfrontpagecontents = NULL; +/** List of port_cfg_t for all configured ports. */ +static smartlist_t *configured_ports = NULL; + +/** Return the contents of our frontpage string, or NULL if not configured. */ +const char * +get_dirportfrontpage(void) +{ + return global_dirfrontpagecontents; +} + +/** Return the currently configured options. */ +or_options_t * +get_options_mutable(void) +{ + tor_assert(global_options); + return global_options; +} + +/** Returns the currently configured options */ +const or_options_t * +get_options(void) +{ + return get_options_mutable(); +} + +/** Change the current global options to contain new_val instead of + * their current value; take action based on the new value; free the old value + * as necessary. Returns 0 on success, -1 on failure. + */ +int +set_options(or_options_t *new_val, char **msg) +{ + int i; + smartlist_t *elements; + config_line_t *line; + or_options_t *old_options = global_options; + global_options = new_val; + /* Note that we pass the *old* options below, for comparison. It + * pulls the new options directly out of global_options. */ + if (options_act_reversible(old_options, msg)<0) { + tor_assert(*msg); + global_options = old_options; + return -1; + } + if (options_act(old_options) < 0) { /* acting on the options failed. die. */ + log_err(LD_BUG, + "Acting on config options left us in a broken state. Dying."); + exit(1); + } + /* Issues a CONF_CHANGED event to notify controller of the change. If Tor is + * just starting up then the old_options will be undefined. */ + if (old_options && old_options != global_options) { + elements = smartlist_new(); + for (i=0; options_format.vars[i].name; ++i) { + const config_var_t *var = &options_format.vars[i]; + const char *var_name = var->name; + if (var->type == CONFIG_TYPE_LINELIST_S || + var->type == CONFIG_TYPE_OBSOLETE) { + continue; + } + if (!config_is_same(&options_format, new_val, old_options, var_name)) { + line = config_get_assigned_option(&options_format, new_val, + var_name, 1); + + if (line) { + config_line_t *next; + for (; line; line = next) { + next = line->next; + smartlist_add(elements, line->key); + smartlist_add(elements, line->value); + tor_free(line); + } + } else { + smartlist_add(elements, tor_strdup(options_format.vars[i].name)); + smartlist_add(elements, NULL); + } + } + } + control_event_conf_changed(elements); + SMARTLIST_FOREACH(elements, char *, cp, tor_free(cp)); + smartlist_free(elements); + } + + if (old_options != global_options) + config_free(&options_format, old_options); + + return 0; +} + +extern const char tor_git_revision[]; /* from tor_main.c */ + +/** The version of this Tor process, as parsed. */ +static char *the_tor_version = NULL; +/** A shorter version of this Tor process's version, for export in our router + * descriptor. (Does not include the git version, if any.) */ +static char *the_short_tor_version = NULL; + +/** Return the current Tor version. */ +const char * +get_version(void) +{ + if (the_tor_version == NULL) { + if (strlen(tor_git_revision)) { + tor_asprintf(&the_tor_version, "%s (git-%s)", get_short_version(), + tor_git_revision); + } else { + the_tor_version = tor_strdup(get_short_version()); + } + } + return the_tor_version; +} + +/** Return the current Tor version, without any git tag. */ +const char * +get_short_version(void) +{ + + if (the_short_tor_version == NULL) { +#ifdef TOR_BUILD_TAG + tor_asprintf(&the_short_tor_version, "%s (%s)", VERSION, TOR_BUILD_TAG); +#else + the_short_tor_version = tor_strdup(VERSION); +#endif + } + return the_short_tor_version; +} + +/** Release additional memory allocated in options + */ +STATIC void +or_options_free(or_options_t *options) +{ + if (!options) + return; + + routerset_free(options->ExcludeExitNodesUnion_); + if (options->NodeFamilySets) { + SMARTLIST_FOREACH(options->NodeFamilySets, routerset_t *, + rs, routerset_free(rs)); + smartlist_free(options->NodeFamilySets); + } + tor_free(options->BridgePassword_AuthDigest_); + tor_free(options->command_arg); + config_free(&options_format, options); +} + +/** Release all memory and resources held by global configuration structures. + */ +void +config_free_all(void) +{ + or_options_free(global_options); + global_options = NULL; + or_options_free(global_default_options); + global_default_options = NULL; + + config_free_lines(global_cmdline_options); + global_cmdline_options = NULL; + + config_free_lines(global_cmdline_only_options); + global_cmdline_only_options = NULL; + + if (configured_ports) { + SMARTLIST_FOREACH(configured_ports, + port_cfg_t *, p, port_cfg_free(p)); + smartlist_free(configured_ports); + configured_ports = NULL; + } + + tor_free(torrc_fname); + tor_free(torrc_defaults_fname); + tor_free(the_tor_version); + tor_free(global_dirfrontpagecontents); + + tor_free(the_short_tor_version); + tor_free(the_tor_version); +} + +/** Make address -- a piece of information related to our operation as + * a client -- safe to log according to the settings in options->SafeLogging, + * and return it. + * + * (We return "[scrubbed]" if SafeLogging is "1", and address otherwise.) + */ +const char * +safe_str_client(const char *address) +{ + tor_assert(address); + if (get_options()->SafeLogging_ == SAFELOG_SCRUB_ALL) + return "[scrubbed]"; + else + return address; +} + +/** Make address -- a piece of information of unspecified sensitivity + * -- safe to log according to the settings in options->SafeLogging, and + * return it. + * + * (We return "[scrubbed]" if SafeLogging is anything besides "0", and address + * otherwise.) + */ +const char * +safe_str(const char *address) +{ + tor_assert(address); + if (get_options()->SafeLogging_ != SAFELOG_SCRUB_NONE) + return "[scrubbed]"; + else + return address; +} + +/** Equivalent to escaped(safe_str_client(address)). See reentrancy note on + * escaped(): don't use this outside the main thread, or twice in the same + * log statement. */ +const char * +escaped_safe_str_client(const char *address) +{ + if (get_options()->SafeLogging_ == SAFELOG_SCRUB_ALL) + return "[scrubbed]"; + else + return escaped(address); +} + +/** Equivalent to escaped(safe_str(address)). See reentrancy note on + * escaped(): don't use this outside the main thread, or twice in the same + * log statement. */ +const char * +escaped_safe_str(const char *address) +{ + if (get_options()->SafeLogging_ != SAFELOG_SCRUB_NONE) + return "[scrubbed]"; + else + return escaped(address); +} + +/** Add the default directory authorities directly into the trusted dir list, + * but only add them insofar as they share bits with type. */ +static void +add_default_trusted_dir_authorities(dirinfo_type_t type) +{ + int i; + const char *authorities[] = { + "moria1 orport=9101 " + "v3ident=D586D18309DED4CD6D57C18FDB97EFA96D330566 " + "128.31.0.39:9131 9695 DFC3 5FFE B861 329B 9F1A B04C 4639 7020 CE31", + "tor26 v1 orport=443 v3ident=14C131DFC5C6F93646BE72FA1401C02A8DF2E8B4 " + "86.59.21.38:80 847B 1F85 0344 D787 6491 A548 92F9 0493 4E4E B85D", + "dizum orport=443 v3ident=E8A9C45EDE6D711294FADF8E7951F4DE6CA56B58 " + "194.109.206.212:80 7EA6 EAD6 FD83 083C 538F 4403 8BBF A077 587D D755", + "Tonga orport=443 bridge 82.94.251.203:80 " + "4A0C CD2D DC79 9508 3D73 F5D6 6710 0C8A 5831 F16D", + "turtles orport=9090 " + "v3ident=27B6B5996C426270A5C95488AA5BCEB6BCC86956 " + "76.73.17.194:9030 F397 038A DC51 3361 35E7 B80B D99C A384 4360 292B", + "gabelmoo orport=443 " + "v3ident=ED03BB616EB2F60BEC80151114BB25CEF515B226 " + "212.112.245.170:80 F204 4413 DAC2 E02E 3D6B CF47 35A1 9BCA 1DE9 7281", + "dannenberg orport=443 " + "v3ident=585769C78764D58426B8B52B6651A5A71137189A " + "193.23.244.244:80 7BE6 83E6 5D48 1413 21C5 ED92 F075 C553 64AC 7123", + "urras orport=80 v3ident=80550987E1D626E3EBA5E5E75A458DE0626D088C " + "208.83.223.34:443 0AD3 FA88 4D18 F89E EA2D 89C0 1937 9E0E 7FD9 4417", + "maatuska orport=80 " + "v3ident=49015F787433103580E3B66A1707A00E60F2D15B " + "171.25.193.9:443 BD6A 8292 55CB 08E6 6FBE 7D37 4836 3586 E46B 3810", + "Faravahar orport=443 " + "v3ident=EFCBE720AB3A82B99F9E953CD5BF50F7EEFC7B97 " + "154.35.32.5:80 CF6D 0AAF B385 BE71 B8E1 11FC 5CFF 4B47 9237 33BC", + NULL + }; + for (i=0; authorities[i]; i++) { + if (parse_dir_authority_line(authorities[i], type, 0)<0) { + log_err(LD_BUG, "Couldn't parse internal DirAuthority line %s", + authorities[i]); + } + } +} + +/** Add the default fallback directory servers into the fallback directory + * server list. */ +static void +add_default_fallback_dir_servers(void) +{ + int i; + const char *fallback[] = { + NULL + }; + for (i=0; fallback[i]; i++) { + if (parse_dir_fallback_line(fallback[i], 0)<0) { + log_err(LD_BUG, "Couldn't parse internal FallbackDir line %s", + fallback[i]); + } + } +} + +/** Look at all the config options for using alternate directory + * authorities, and make sure none of them are broken. Also, warn the + * user if we changed any dangerous ones. + */ +static int +validate_dir_servers(or_options_t *options, or_options_t *old_options) +{ + config_line_t *cl; + + if (options->DirAuthorities && + (options->AlternateDirAuthority || options->AlternateBridgeAuthority || + options->AlternateHSAuthority)) { + log_warn(LD_CONFIG, + "You cannot set both DirAuthority and Alternate*Authority."); + return -1; + } + + /* do we want to complain to the user about being partitionable? */ + if ((options->DirAuthorities && + (!old_options || + !config_lines_eq(options->DirAuthorities, + old_options->DirAuthorities))) || + (options->AlternateDirAuthority && + (!old_options || + !config_lines_eq(options->AlternateDirAuthority, + old_options->AlternateDirAuthority)))) { + log_warn(LD_CONFIG, + "You have used DirAuthority or AlternateDirAuthority to " + "specify alternate directory authorities in " + "your configuration. This is potentially dangerous: it can " + "make you look different from all other Tor users, and hurt " + "your anonymity. Even if you've specified the same " + "authorities as Tor uses by default, the defaults could " + "change in the future. Be sure you know what you're doing."); + } + + /* Now go through the four ways you can configure an alternate + * set of directory authorities, and make sure none are broken. */ + for (cl = options->DirAuthorities; cl; cl = cl->next) + if (parse_dir_authority_line(cl->value, NO_DIRINFO, 1)<0) + return -1; + for (cl = options->AlternateBridgeAuthority; cl; cl = cl->next) + if (parse_dir_authority_line(cl->value, NO_DIRINFO, 1)<0) + return -1; + for (cl = options->AlternateDirAuthority; cl; cl = cl->next) + if (parse_dir_authority_line(cl->value, NO_DIRINFO, 1)<0) + return -1; + for (cl = options->AlternateHSAuthority; cl; cl = cl->next) + if (parse_dir_authority_line(cl->value, NO_DIRINFO, 1)<0) + return -1; + for (cl = options->FallbackDir; cl; cl = cl->next) + if (parse_dir_fallback_line(cl->value, 1)<0) + return -1; + return 0; +} + +/** Look at all the config options and assign new dir authorities + * as appropriate. + */ +static int +consider_adding_dir_servers(const or_options_t *options, + const or_options_t *old_options) +{ + config_line_t *cl; + int need_to_update = + !smartlist_len(router_get_trusted_dir_servers()) || + !smartlist_len(router_get_fallback_dir_servers()) || !old_options || + !config_lines_eq(options->DirAuthorities, old_options->DirAuthorities) || + !config_lines_eq(options->FallbackDir, old_options->FallbackDir) || + !config_lines_eq(options->AlternateBridgeAuthority, + old_options->AlternateBridgeAuthority) || + !config_lines_eq(options->AlternateDirAuthority, + old_options->AlternateDirAuthority) || + !config_lines_eq(options->AlternateHSAuthority, + old_options->AlternateHSAuthority); + + if (!need_to_update) + return 0; /* all done */ + + /* Start from a clean slate. */ + clear_dir_servers(); + + if (!options->DirAuthorities) { + /* then we may want some of the defaults */ + dirinfo_type_t type = NO_DIRINFO; + if (!options->AlternateBridgeAuthority) + type |= BRIDGE_DIRINFO; + if (!options->AlternateDirAuthority) + type |= V1_DIRINFO | V3_DIRINFO | EXTRAINFO_DIRINFO | + MICRODESC_DIRINFO; + if (!options->AlternateHSAuthority) + type |= HIDSERV_DIRINFO; + add_default_trusted_dir_authorities(type); + } + if (!options->FallbackDir) + add_default_fallback_dir_servers(); + + for (cl = options->DirAuthorities; cl; cl = cl->next) + if (parse_dir_authority_line(cl->value, NO_DIRINFO, 0)<0) + return -1; + for (cl = options->AlternateBridgeAuthority; cl; cl = cl->next) + if (parse_dir_authority_line(cl->value, NO_DIRINFO, 0)<0) + return -1; + for (cl = options->AlternateDirAuthority; cl; cl = cl->next) + if (parse_dir_authority_line(cl->value, NO_DIRINFO, 0)<0) + return -1; + for (cl = options->AlternateHSAuthority; cl; cl = cl->next) + if (parse_dir_authority_line(cl->value, NO_DIRINFO, 0)<0) + return -1; + for (cl = options->FallbackDir; cl; cl = cl->next) + if (parse_dir_fallback_line(cl->value, 0)<0) + return -1; + return 0; +} + +/** Fetch the active option list, and take actions based on it. All of the + * things we do should survive being done repeatedly. If present, + * old_options contains the previous value of the options. + * + * Return 0 if all goes well, return -1 if things went badly. + */ +static int +options_act_reversible(const or_options_t *old_options, char **msg) +{ + smartlist_t *new_listeners = smartlist_new(); + smartlist_t *replaced_listeners = smartlist_new(); + static int libevent_initialized = 0; + or_options_t *options = get_options_mutable(); + int running_tor = options->command == CMD_RUN_TOR; + int set_conn_limit = 0; + int r = -1; + int logs_marked = 0; + int old_min_log_level = get_min_log_level(); + + /* Daemonize _first_, since we only want to open most of this stuff in + * the subprocess. Libevent bases can't be reliably inherited across + * processes. */ + if (running_tor && options->RunAsDaemon) { + /* No need to roll back, since you can't change the value. */ + start_daemon(); + } + +#ifndef HAVE_SYS_UN_H + if (options->ControlSocket || options->ControlSocketsGroupWritable) { + *msg = tor_strdup("Unix domain sockets (ControlSocket) not supported " + "on this OS/with this build."); + goto rollback; + } +#else + if (options->ControlSocketsGroupWritable && !options->ControlSocket) { + *msg = tor_strdup("Setting ControlSocketGroupWritable without setting" + "a ControlSocket makes no sense."); + goto rollback; + } +#endif + + if (running_tor) { + int n_ports=0; + /* We need to set the connection limit before we can open the listeners. */ + if (set_max_file_descriptors((unsigned)options->ConnLimit, + &options->ConnLimit_) < 0) { + *msg = tor_strdup("Problem with ConnLimit value. See logs for details."); + goto rollback; + } + set_conn_limit = 1; + + /* Set up libevent. (We need to do this before we can register the + * listeners as listeners.) */ + if (running_tor && !libevent_initialized) { + init_libevent(options); + libevent_initialized = 1; + } + + /* Adjust the port configuration so we can launch listeners. */ + if (parse_ports(options, 0, msg, &n_ports)) { + if (!*msg) + *msg = tor_strdup("Unexpected problem parsing port config"); + goto rollback; + } + + /* Set the hibernation state appropriately.*/ + consider_hibernation(time(NULL)); + + /* Launch the listeners. (We do this before we setuid, so we can bind to + * ports under 1024.) We don't want to rebind if we're hibernating. If + * networking is disabled, this will close all but the control listeners, + * but disable those. */ + if (!we_are_hibernating()) { + if (retry_all_listeners(replaced_listeners, new_listeners, + options->DisableNetwork) < 0) { + *msg = tor_strdup("Failed to bind one of the listener ports."); + goto rollback; + } + } + if (options->DisableNetwork) { + /* Aggressively close non-controller stuff, NOW */ + log_notice(LD_NET, "DisableNetwork is set. Tor will not make or accept " + "non-control network connections. Shutting down all existing " + "connections."); + connection_mark_all_noncontrol_connections(); + } + } + +#if defined(HAVE_NET_IF_H) && defined(HAVE_NET_PFVAR_H) + /* Open /dev/pf before dropping privileges. */ + if (options->TransPort_set) { + if (get_pf_socket() < 0) { + *msg = tor_strdup("Unable to open /dev/pf for transparent proxy."); + goto rollback; + } + } +#endif + + /* Attempt to lock all current and future memory with mlockall() only once */ + if (options->DisableAllSwap) { + if (tor_mlockall() == -1) { + *msg = tor_strdup("DisableAllSwap failure. Do you have proper " + "permissions?"); + goto done; + } + } + + /* Setuid/setgid as appropriate */ + if (options->User) { + if (switch_id(options->User) != 0) { + /* No need to roll back, since you can't change the value. */ + *msg = tor_strdup("Problem with User value. See logs for details."); + goto done; + } + } + + /* Ensure data directory is private; create if possible. */ + if (check_private_dir(options->DataDirectory, + running_tor ? CPD_CREATE : CPD_CHECK, + options->User)<0) { + tor_asprintf(msg, + "Couldn't access/create private data directory \"%s\"", + options->DataDirectory); + goto done; + /* No need to roll back, since you can't change the value. */ + } + + /* Bail out at this point if we're not going to be a client or server: + * we don't run Tor itself. */ + if (!running_tor) + goto commit; + + mark_logs_temp(); /* Close current logs once new logs are open. */ + logs_marked = 1; + if (options_init_logs(options, 0)<0) { /* Configure the tor_log(s) */ + *msg = tor_strdup("Failed to init Log options. See logs for details."); + goto rollback; + } + + commit: + r = 0; + if (logs_marked) { + log_severity_list_t *severity = + tor_malloc_zero(sizeof(log_severity_list_t)); + close_temp_logs(); + add_callback_log(severity, control_event_logmsg); + control_adjust_event_log_severity(); + tor_free(severity); + tor_log_update_sigsafe_err_fds(); + } + if (get_min_log_level() >= LOG_INFO && + get_min_log_level() != old_min_log_level) { + log_warn(LD_GENERAL, "Your log may contain sensitive information: you're " + "logging more than \"notice\". Please log safely. Don't log " + "unless it serves an important reason, and overwrite the log " + "afterwards."); + } + + SMARTLIST_FOREACH(replaced_listeners, connection_t *, conn, + { + log_notice(LD_NET, "Closing old %s on %s:%d", + conn_type_to_string(conn->type), conn->address, conn->port); + connection_close_immediate(conn); + connection_mark_for_close(conn); + }); + goto done; + + rollback: + r = -1; + tor_assert(*msg); + + if (logs_marked) { + rollback_log_changes(); + control_adjust_event_log_severity(); + } + + if (set_conn_limit && old_options) + set_max_file_descriptors((unsigned)old_options->ConnLimit, + &options->ConnLimit_); + + SMARTLIST_FOREACH(new_listeners, connection_t *, conn, + { + log_notice(LD_NET, "Closing partially-constructed %s on %s:%d", + conn_type_to_string(conn->type), conn->address, conn->port); + connection_close_immediate(conn); + connection_mark_for_close(conn); + }); + + done: + smartlist_free(new_listeners); + smartlist_free(replaced_listeners); + return r; +} + +/** If we need to have a GEOIP ip-to-country map to run with our configured + * options, return 1 and set *reason_out to a description of why. */ +int +options_need_geoip_info(const or_options_t *options, const char **reason_out) +{ + int bridge_usage = + options->BridgeRelay && options->BridgeRecordUsageByCountry; + int routerset_usage = + routerset_needs_geoip(options->EntryNodes) || + routerset_needs_geoip(options->ExitNodes) || + routerset_needs_geoip(options->ExcludeExitNodes) || + routerset_needs_geoip(options->ExcludeNodes); + + if (routerset_usage && reason_out) { + *reason_out = "We've been configured to use (or avoid) nodes in certain " + "countries, and we need GEOIP information to figure out which ones they " + "are."; + } else if (bridge_usage && reason_out) { + *reason_out = "We've been configured to see which countries can access " + "us as a bridge, and we need GEOIP information to tell which countries " + "clients are in."; + } + return bridge_usage || routerset_usage; +} + +/** Return the bandwidthrate that we are going to report to the authorities + * based on the config options. */ +uint32_t +get_effective_bwrate(const or_options_t *options) +{ + uint64_t bw = options->BandwidthRate; + if (bw > options->MaxAdvertisedBandwidth) + bw = options->MaxAdvertisedBandwidth; + if (options->RelayBandwidthRate > 0 && bw > options->RelayBandwidthRate) + bw = options->RelayBandwidthRate; + /* ensure_bandwidth_cap() makes sure that this cast can't overflow. */ + return (uint32_t)bw; +} + +/** Return the bandwidthburst that we are going to report to the authorities + * based on the config options. */ +uint32_t +get_effective_bwburst(const or_options_t *options) +{ + uint64_t bw = options->BandwidthBurst; + if (options->RelayBandwidthBurst > 0 && bw > options->RelayBandwidthBurst) + bw = options->RelayBandwidthBurst; + /* ensure_bandwidth_cap() makes sure that this cast can't overflow. */ + return (uint32_t)bw; +} + +/** Return True if any changes from old_options to + * new_options needs us to refresh our TLS context. */ +static int +options_transition_requires_fresh_tls_context(const or_options_t *old_options, + const or_options_t *new_options) +{ + tor_assert(new_options); + + if (!old_options) + return 0; + + if ((old_options->DynamicDHGroups != new_options->DynamicDHGroups)) { + return 1; + } + + if (!opt_streq(old_options->TLSECGroup, new_options->TLSECGroup)) + return 1; + + return 0; +} + +/** Fetch the active option list, and take actions based on it. All of the + * things we do should survive being done repeatedly. If present, + * old_options contains the previous value of the options. + * + * Return 0 if all goes well, return -1 if it's time to die. + * + * Note: We haven't moved all the "act on new configuration" logic + * here yet. Some is still in do_hup() and other places. + */ +static int +options_act(const or_options_t *old_options) +{ + config_line_t *cl; + or_options_t *options = get_options_mutable(); + int running_tor = options->command == CMD_RUN_TOR; + char *msg=NULL; + const int transition_affects_workers = + old_options && options_transition_affects_workers(old_options, options); + int old_ewma_enabled; + + /* disable ptrace and later, other basic debugging techniques */ + { + /* Remember if we already disabled debugger attachment */ + static int disabled_debugger_attach = 0; + /* Remember if we already warned about being configured not to disable + * debugger attachment */ + static int warned_debugger_attach = 0; + /* Don't disable debugger attachment when we're running the unit tests. */ + if (options->DisableDebuggerAttachment && !disabled_debugger_attach && + running_tor) { + int ok = tor_disable_debugger_attach(); + if (warned_debugger_attach && ok == 1) { + log_notice(LD_CONFIG, "Disabled attaching debuggers for unprivileged " + "users."); + } + disabled_debugger_attach = (ok == 1); + } else if (!options->DisableDebuggerAttachment && + !warned_debugger_attach) { + log_notice(LD_CONFIG, "Not disabling debugger attaching for " + "unprivileged users."); + warned_debugger_attach = 1; + } + } + + /* Write control ports to disk as appropriate */ + control_ports_write_to_file(); + + if (running_tor && !have_lockfile()) { + if (try_locking(options, 1) < 0) + return -1; + } + + if (consider_adding_dir_servers(options, old_options) < 0) + return -1; + +#ifdef NON_ANONYMOUS_MODE_ENABLED + log_warn(LD_GENERAL, "This copy of Tor was compiled to run in a " + "non-anonymous mode. It will provide NO ANONYMITY."); +#endif + +#ifdef ENABLE_TOR2WEB_MODE + if (!options->Tor2webMode) { + log_err(LD_CONFIG, "This copy of Tor was compiled to run in " + "'tor2web mode'. It can only be run with the Tor2webMode torrc " + "option enabled."); + return -1; + } +#else + if (options->Tor2webMode) { + log_err(LD_CONFIG, "This copy of Tor was not compiled to run in " + "'tor2web mode'. It cannot be run with the Tor2webMode torrc " + "option enabled. To enable Tor2webMode recompile with the " + "--enable-tor2webmode option."); + return -1; + } +#endif + + if (options->SafeLogging_ != SAFELOG_SCRUB_ALL && + (!old_options || old_options->SafeLogging_ != options->SafeLogging_)) { + log_warn(LD_GENERAL, "Your log may contain sensitive information - you " + "disabled SafeLogging. Please log safely. Don't log unless it " + "serves an important reason. Overwrite the log afterwards."); + } + + if (options->Bridges) { + mark_bridge_list(); + for (cl = options->Bridges; cl; cl = cl->next) { + bridge_line_t *bridge_line = parse_bridge_line(cl->value); + if (!bridge_line) { + log_warn(LD_BUG, + "Previously validated Bridge line could not be added!"); + return -1; + } + bridge_add_from_config(bridge_line); + } + sweep_bridge_list(); + } + + if (running_tor && rend_config_services(options, 0)<0) { + log_warn(LD_BUG, + "Previously validated hidden services line could not be added!"); + return -1; + } + + if (running_tor && rend_parse_service_authorization(options, 0) < 0) { + log_warn(LD_BUG, "Previously validated client authorization for " + "hidden services could not be added!"); + return -1; + } + + /* Load state */ + if (! or_state_loaded() && running_tor) { + if (or_state_load()) + return -1; + rep_hist_load_mtbf_data(time(NULL)); + } + + mark_transport_list(); + pt_prepare_proxy_list_for_config_read(); + if (options->ClientTransportPlugin) { + for (cl = options->ClientTransportPlugin; cl; cl = cl->next) { + if (parse_client_transport_line(cl->value, 0)<0) { + log_warn(LD_BUG, + "Previously validated ClientTransportPlugin line " + "could not be added!"); + return -1; + } + } + } + + if (options->ServerTransportPlugin && server_mode(options)) { + for (cl = options->ServerTransportPlugin; cl; cl = cl->next) { + if (parse_server_transport_line(cl->value, 0)<0) { + log_warn(LD_BUG, + "Previously validated ServerTransportPlugin line " + "could not be added!"); + return -1; + } + } + } + sweep_transport_list(); + sweep_proxy_list(); + + /* Bail out at this point if we're not going to be a client or server: + * we want to not fork, and to log stuff to stderr. */ + if (!running_tor) + return 0; + + /* Finish backgrounding the process */ + if (options->RunAsDaemon) { + /* We may be calling this for the n'th time (on SIGHUP), but it's safe. */ + finish_daemon(options->DataDirectory); + } + + /* If needed, generate a new TLS DH prime according to the current torrc. */ + if (server_mode(options) && options->DynamicDHGroups) { + char *keydir = get_datadir_fname("keys"); + if (check_private_dir(keydir, CPD_CREATE, options->User)) { + tor_free(keydir); + return -1; + } + tor_free(keydir); + + if (!old_options || !old_options->DynamicDHGroups) { + char *fname = get_datadir_fname2("keys", "dynamic_dh_params"); + crypto_set_tls_dh_prime(fname); + tor_free(fname); + } + } else { /* clients don't need a dynamic DH prime. */ + crypto_set_tls_dh_prime(NULL); + } + + /* We want to reinit keys as needed before we do much of anything else: + keys are important, and other things can depend on them. */ + if (transition_affects_workers || + (options->V3AuthoritativeDir && (!old_options || + !old_options->V3AuthoritativeDir))) { + if (init_keys() < 0) { + log_warn(LD_BUG,"Error initializing keys; exiting"); + return -1; + } + } else if (old_options && + options_transition_requires_fresh_tls_context(old_options, + options)) { + if (router_initialize_tls_context() < 0) { + log_warn(LD_BUG,"Error initializing TLS context."); + return -1; + } + } + + /* Write our PID to the PID file. If we do not have write permissions we + * will log a warning */ + if (options->PidFile) + write_pidfile(options->PidFile); + + /* Register addressmap directives */ + config_register_addressmaps(options); + parse_virtual_addr_network(options->VirtualAddrNetworkIPv4, AF_INET,0,NULL); + parse_virtual_addr_network(options->VirtualAddrNetworkIPv6, AF_INET6,0,NULL); + + /* Update address policies. */ + if (policies_parse_from_options(options) < 0) { + /* This should be impossible, but let's be sure. */ + log_warn(LD_BUG,"Error parsing already-validated policy options."); + return -1; + } + + if (init_control_cookie_authentication(options->CookieAuthentication) < 0) { + log_warn(LD_CONFIG,"Error creating control cookie authentication file."); + return -1; + } + + /* If we have an ExtORPort, initialize its auth cookie. */ + if (init_ext_or_cookie_authentication(!!options->ExtORPort_lines) < 0) { + log_warn(LD_CONFIG,"Error creating Extended ORPort cookie file."); + return -1; + } + + monitor_owning_controller_process(options->OwningControllerProcess); + + /* reload keys as needed for rendezvous services. */ + if (rend_service_load_all_keys()<0) { + log_warn(LD_GENERAL,"Error loading rendezvous service keys"); + return -1; + } + + /* Set up accounting */ + if (accounting_parse_options(options, 0)<0) { + log_warn(LD_CONFIG,"Error in accounting options"); + return -1; + } + if (accounting_is_enabled(options)) + configure_accounting(time(NULL)); + +#ifdef USE_BUFFEREVENTS + /* If we're using the bufferevents implementation and our rate limits + * changed, we need to tell the rate-limiting system about it. */ + if (!old_options || + old_options->BandwidthRate != options->BandwidthRate || + old_options->BandwidthBurst != options->BandwidthBurst || + old_options->RelayBandwidthRate != options->RelayBandwidthRate || + old_options->RelayBandwidthBurst != options->RelayBandwidthBurst) + connection_bucket_init(); +#endif + + old_ewma_enabled = cell_ewma_enabled(); + /* Change the cell EWMA settings */ + cell_ewma_set_scale_factor(options, networkstatus_get_latest_consensus()); + /* If we just enabled ewma, set the cmux policy on all active channels */ + if (cell_ewma_enabled() && !old_ewma_enabled) { + channel_set_cmux_policy_everywhere(&ewma_policy); + } else if (!cell_ewma_enabled() && old_ewma_enabled) { + /* Turn it off everywhere */ + channel_set_cmux_policy_everywhere(NULL); + } + + /* Update the BridgePassword's hashed version as needed. We store this as a + * digest so that we can do side-channel-proof comparisons on it. + */ + if (options->BridgePassword) { + char *http_authenticator; + http_authenticator = alloc_http_authenticator(options->BridgePassword); + if (!http_authenticator) { + log_warn(LD_BUG, "Unable to allocate HTTP authenticator. Not setting " + "BridgePassword."); + return -1; + } + options->BridgePassword_AuthDigest_ = tor_malloc(DIGEST256_LEN); + crypto_digest256(options->BridgePassword_AuthDigest_, + http_authenticator, strlen(http_authenticator), + DIGEST_SHA256); + tor_free(http_authenticator); + } + + if (parse_outbound_addresses(options, 0, &msg) < 0) { + log_warn(LD_BUG, "Failed parsing oubound bind addresses: %s", msg); + tor_free(msg); + return -1; + } + + /* Check for transitions that need action. */ + if (old_options) { + int revise_trackexithosts = 0; + int revise_automap_entries = 0; + if ((options->UseEntryGuards && !old_options->UseEntryGuards) || + options->UseBridges != old_options->UseBridges || + (options->UseBridges && + !config_lines_eq(options->Bridges, old_options->Bridges)) || + !routerset_equal(old_options->ExcludeNodes,options->ExcludeNodes) || + !routerset_equal(old_options->ExcludeExitNodes, + options->ExcludeExitNodes) || + !routerset_equal(old_options->EntryNodes, options->EntryNodes) || + !routerset_equal(old_options->ExitNodes, options->ExitNodes) || + options->StrictNodes != old_options->StrictNodes) { + log_info(LD_CIRC, + "Changed to using entry guards or bridges, or changed " + "preferred or excluded node lists. " + "Abandoning previous circuits."); + circuit_mark_all_unused_circs(); + circuit_mark_all_dirty_circs_as_unusable(); + revise_trackexithosts = 1; + } + + if (!smartlist_strings_eq(old_options->TrackHostExits, + options->TrackHostExits)) + revise_trackexithosts = 1; + + if (revise_trackexithosts) + addressmap_clear_excluded_trackexithosts(options); + + if (!options->AutomapHostsOnResolve) { + if (old_options->AutomapHostsOnResolve) + revise_automap_entries = 1; + } else { + if (!smartlist_strings_eq(old_options->AutomapHostsSuffixes, + options->AutomapHostsSuffixes)) + revise_automap_entries = 1; + else if (!opt_streq(old_options->VirtualAddrNetworkIPv4, + options->VirtualAddrNetworkIPv4) || + !opt_streq(old_options->VirtualAddrNetworkIPv6, + options->VirtualAddrNetworkIPv6)) + revise_automap_entries = 1; + } + + if (revise_automap_entries) + addressmap_clear_invalid_automaps(options); + +/* How long should we delay counting bridge stats after becoming a bridge? + * We use this so we don't count people who used our bridge thinking it is + * a relay. If you change this, don't forget to change the log message + * below. It's 4 hours (the time it takes to stop being used by clients) + * plus some extra time for clock skew. */ +#define RELAY_BRIDGE_STATS_DELAY (6 * 60 * 60) + + if (! bool_eq(options->BridgeRelay, old_options->BridgeRelay)) { + int was_relay = 0; + if (options->BridgeRelay) { + time_t int_start = time(NULL); + if (config_lines_eq(old_options->ORPort_lines,options->ORPort_lines)) { + int_start += RELAY_BRIDGE_STATS_DELAY; + was_relay = 1; + } + geoip_bridge_stats_init(int_start); + log_info(LD_CONFIG, "We are acting as a bridge now. Starting new " + "GeoIP stats interval%s.", was_relay ? " in 6 " + "hours from now" : ""); + } else { + geoip_bridge_stats_term(); + log_info(LD_GENERAL, "We are no longer acting as a bridge. " + "Forgetting GeoIP stats."); + } + } + + if (transition_affects_workers) { + log_info(LD_GENERAL, + "Worker-related options changed. Rotating workers."); + + if (server_mode(options) && !server_mode(old_options)) { + ip_address_changed(0); + if (can_complete_circuit || !any_predicted_circuits(time(NULL))) + inform_testing_reachability(); + } + cpuworkers_rotate(); + if (dns_reset()) + return -1; + } else { + if (dns_reset()) + return -1; + } + + if (options->PerConnBWRate != old_options->PerConnBWRate || + options->PerConnBWBurst != old_options->PerConnBWBurst) + connection_or_update_token_buckets(get_connection_array(), options); + } + + config_maybe_load_geoip_files_(options, old_options); + + if (geoip_is_loaded(AF_INET) && options->GeoIPExcludeUnknown) { + /* ExcludeUnknown is true or "auto" */ + const int is_auto = options->GeoIPExcludeUnknown == -1; + int changed; + + changed = routerset_add_unknown_ccs(&options->ExcludeNodes, is_auto); + changed += routerset_add_unknown_ccs(&options->ExcludeExitNodes, is_auto); + + if (changed) + routerset_add_unknown_ccs(&options->ExcludeExitNodesUnion_, is_auto); + } + + if (options->CellStatistics || options->DirReqStatistics || + options->EntryStatistics || options->ExitPortStatistics || + options->ConnDirectionStatistics || + options->BridgeAuthoritativeDir) { + time_t now = time(NULL); + int print_notice = 0; + + /* If we aren't acting as a server, we can't collect stats anyway. */ + if (!server_mode(options)) { + options->CellStatistics = 0; + options->DirReqStatistics = 0; + options->EntryStatistics = 0; + options->ExitPortStatistics = 0; + } + + if ((!old_options || !old_options->CellStatistics) && + options->CellStatistics) { + rep_hist_buffer_stats_init(now); + print_notice = 1; + } + if ((!old_options || !old_options->DirReqStatistics) && + options->DirReqStatistics) { + if (geoip_is_loaded(AF_INET)) { + geoip_dirreq_stats_init(now); + print_notice = 1; + } else { + options->DirReqStatistics = 0; + /* Don't warn Tor clients, they don't use statistics */ + if (options->ORPort_set) + log_notice(LD_CONFIG, "Configured to measure directory request " + "statistics, but no GeoIP database found. " + "Please specify a GeoIP database using the " + "GeoIPFile option."); + } + } + if ((!old_options || !old_options->EntryStatistics) && + options->EntryStatistics && !should_record_bridge_info(options)) { + if (geoip_is_loaded(AF_INET) || geoip_is_loaded(AF_INET6)) { + geoip_entry_stats_init(now); + print_notice = 1; + } else { + options->EntryStatistics = 0; + log_notice(LD_CONFIG, "Configured to measure entry node " + "statistics, but no GeoIP database found. " + "Please specify a GeoIP database using the " + "GeoIPFile option."); + } + } + if ((!old_options || !old_options->ExitPortStatistics) && + options->ExitPortStatistics) { + rep_hist_exit_stats_init(now); + print_notice = 1; + } + if ((!old_options || !old_options->ConnDirectionStatistics) && + options->ConnDirectionStatistics) { + rep_hist_conn_stats_init(now); + } + if ((!old_options || !old_options->BridgeAuthoritativeDir) && + options->BridgeAuthoritativeDir) { + rep_hist_desc_stats_init(now); + print_notice = 1; + } + if (print_notice) + log_notice(LD_CONFIG, "Configured to measure statistics. Look for " + "the *-stats files that will first be written to the " + "data directory in 24 hours from now."); + } + + if (old_options && old_options->CellStatistics && + !options->CellStatistics) + rep_hist_buffer_stats_term(); + if (old_options && old_options->DirReqStatistics && + !options->DirReqStatistics) + geoip_dirreq_stats_term(); + if (old_options && old_options->EntryStatistics && + !options->EntryStatistics) + geoip_entry_stats_term(); + if (old_options && old_options->ExitPortStatistics && + !options->ExitPortStatistics) + rep_hist_exit_stats_term(); + if (old_options && old_options->ConnDirectionStatistics && + !options->ConnDirectionStatistics) + rep_hist_conn_stats_term(); + if (old_options && old_options->BridgeAuthoritativeDir && + !options->BridgeAuthoritativeDir) + rep_hist_desc_stats_term(); + + /* Check if we need to parse and add the EntryNodes config option. */ + if (options->EntryNodes && + (!old_options || + !routerset_equal(old_options->EntryNodes,options->EntryNodes) || + !routerset_equal(old_options->ExcludeNodes,options->ExcludeNodes))) + entry_nodes_should_be_added(); + + /* Since our options changed, we might need to regenerate and upload our + * server descriptor. + */ + if (!old_options || + options_transition_affects_descriptor(old_options, options)) + mark_my_descriptor_dirty("config change"); + + /* We may need to reschedule some directory stuff if our status changed. */ + if (old_options) { + if (authdir_mode_v3(options) && !authdir_mode_v3(old_options)) + dirvote_recalculate_timing(options, time(NULL)); + if (!bool_eq(directory_fetches_dir_info_early(options), + directory_fetches_dir_info_early(old_options)) || + !bool_eq(directory_fetches_dir_info_later(options), + directory_fetches_dir_info_later(old_options))) { + /* Make sure update_router_have_min_dir_info gets called. */ + router_dir_info_changed(); + /* We might need to download a new consensus status later or sooner than + * we had expected. */ + update_consensus_networkstatus_fetch_time(time(NULL)); + } + } + + /* Load the webpage we're going to serve every time someone asks for '/' on + our DirPort. */ + tor_free(global_dirfrontpagecontents); + if (options->DirPortFrontPage) { + global_dirfrontpagecontents = + read_file_to_str(options->DirPortFrontPage, 0, NULL); + if (!global_dirfrontpagecontents) { + log_warn(LD_CONFIG, + "DirPortFrontPage file '%s' not found. Continuing anyway.", + options->DirPortFrontPage); + } + } + + return 0; +} + +static const struct { + const char *name; + int takes_argument; +} CMDLINE_ONLY_OPTIONS[] = { + { "-f", 1 }, + { "--allow-missing-torrc", 0 }, + { "--defaults-torrc", 1 }, + { "--hash-password", 1 }, + { "--dump-config", 1 }, + { "--list-fingerprint", 0 }, + { "--verify-config", 0 }, + { "--ignore-missing-torrc", 0 }, + { "--quiet", 0 }, + { "--hush", 0 }, + { "--version", 0 }, + { "--library-versions", 0 }, + { "-h", 0 }, + { "--help", 0 }, + { "--list-torrc-options", 0 }, + { "--digests", 0 }, + { "--nt-service", 0 }, + { "-nt-service", 0 }, + { NULL, 0 }, +}; + +/** Helper: Read a list of configuration options from the command line. If + * successful, or if ignore_errors is set, put them in *result, put the + * commandline-only options in *cmdline_result, and return 0; + * otherwise, return -1 and leave *result and cmdline_result + * alone. */ +int +config_parse_commandline(int argc, char **argv, int ignore_errors, + config_line_t **result, + config_line_t **cmdline_result) +{ + config_line_t *param = NULL; + + config_line_t *front = NULL; + config_line_t **new = &front; + + config_line_t *front_cmdline = NULL; + config_line_t **new_cmdline = &front_cmdline; + + char *s, *arg; + int i = 1; + + while (i < argc) { + unsigned command = CONFIG_LINE_NORMAL; + int want_arg = 1; + int is_cmdline = 0; + int j; + + for (j = 0; CMDLINE_ONLY_OPTIONS[j].name != NULL; ++j) { + if (!strcmp(argv[i], CMDLINE_ONLY_OPTIONS[j].name)) { + is_cmdline = 1; + want_arg = CMDLINE_ONLY_OPTIONS[j].takes_argument; + break; + } + } + + s = argv[i]; + + /* Each keyword may be prefixed with one or two dashes. */ + if (*s == '-') + s++; + if (*s == '-') + s++; + /* Figure out the command, if any. */ + if (*s == '+') { + s++; + command = CONFIG_LINE_APPEND; + } else if (*s == '/') { + s++; + command = CONFIG_LINE_CLEAR; + /* A 'clear' command has no argument. */ + want_arg = 0; + } + + if (want_arg && i == argc-1) { + if (ignore_errors) { + arg = strdup(""); + } else { + log_warn(LD_CONFIG,"Command-line option '%s' with no value. Failing.", + argv[i]); + config_free_lines(front); + config_free_lines(front_cmdline); + return -1; + } + } else { + arg = want_arg ? tor_strdup(argv[i+1]) : strdup(""); + } + + param = tor_malloc_zero(sizeof(config_line_t)); + param->key = is_cmdline ? tor_strdup(argv[i]) : tor_strdup(s); + param->value = arg; + param->command = command; + param->next = NULL; + log_debug(LD_CONFIG, "command line: parsed keyword '%s', value '%s'", + param->key, param->value); + + if (is_cmdline) { + *new_cmdline = param; + new_cmdline = &((*new_cmdline)->next); + } else { + *new = param; + new = &((*new)->next); + } + + i += want_arg ? 2 : 1; + } + *cmdline_result = front_cmdline; + *result = front; + return 0; +} + +/** Return true iff key is a valid configuration option. */ +int +option_is_recognized(const char *key) +{ + const config_var_t *var = config_find_option(&options_format, key); + return (var != NULL); +} + +/** Return the canonical name of a configuration option, or NULL + * if no such option exists. */ +const char * +option_get_canonical_name(const char *key) +{ + const config_var_t *var = config_find_option(&options_format, key); + return var ? var->name : NULL; +} + +/** Return a canonical list of the options assigned for key. + */ +config_line_t * +option_get_assignment(const or_options_t *options, const char *key) +{ + return config_get_assigned_option(&options_format, options, key, 1); +} + +/** Try assigning list to the global options. You do this by duping + * options, assigning list to the new one, then validating it. If it's + * ok, then throw out the old one and stick with the new one. Else, + * revert to old and return failure. Return SETOPT_OK on success, or + * a setopt_err_t on failure. + * + * If not success, point *msg to a newly allocated string describing + * what went wrong. + */ +setopt_err_t +options_trial_assign(config_line_t *list, int use_defaults, + int clear_first, char **msg) +{ + int r; + or_options_t *trial_options = config_dup(&options_format, get_options()); + + if ((r=config_assign(&options_format, trial_options, + list, use_defaults, clear_first, msg)) < 0) { + config_free(&options_format, trial_options); + return r; + } + + if (options_validate(get_options_mutable(), trial_options, + global_default_options, 1, msg) < 0) { + config_free(&options_format, trial_options); + return SETOPT_ERR_PARSE; /*XXX make this a separate return value. */ + } + + if (options_transition_allowed(get_options(), trial_options, msg) < 0) { + config_free(&options_format, trial_options); + return SETOPT_ERR_TRANSITION; + } + + if (set_options(trial_options, msg)<0) { + config_free(&options_format, trial_options); + return SETOPT_ERR_SETTING; + } + + /* we liked it. put it in place. */ + return SETOPT_OK; +} + +/** Print a usage message for tor. */ +static void +print_usage(void) +{ + printf( +"Copyright (c) 2001-2004, Roger Dingledine\n" +"Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson\n" +"Copyright (c) 2007-2013, The Tor Project, Inc.\n\n" +"tor -f [args]\n" +"See man page for options, or https://www.torproject.org/ for " +"documentation.\n"); +} + +/** Print all non-obsolete torrc options. */ +static void +list_torrc_options(void) +{ + int i; + smartlist_t *lines = smartlist_new(); + for (i = 0; option_vars_[i].name; ++i) { + const config_var_t *var = &option_vars_[i]; + if (var->type == CONFIG_TYPE_OBSOLETE || + var->type == CONFIG_TYPE_LINELIST_V) + continue; + printf("%s\n", var->name); + } + smartlist_free(lines); +} + +/** Last value actually set by resolve_my_address. */ +static uint32_t last_resolved_addr = 0; + +/** Accessor for last_resolved_addr from outside this file. */ +uint32_t +get_last_resolved_addr(void) +{ + return last_resolved_addr; +} + +/** + * Use options-\>Address to guess our public IP address. + * + * Return 0 if all is well, or -1 if we can't find a suitable + * public IP address. + * + * If we are returning 0: + * - Put our public IP address (in host order) into *addr_out. + * - If method_out is non-NULL, set *method_out to a static + * string describing how we arrived at our answer. + * - If hostname_out is non-NULL, and we resolved a hostname to + * get our address, set *hostname_out to a newly allocated string + * holding that hostname. (If we didn't get our address by resolving a + * hostname, set *hostname_out to NULL.) + * + * XXXX ipv6 + */ +int +resolve_my_address(int warn_severity, const or_options_t *options, + uint32_t *addr_out, + const char **method_out, char **hostname_out) +{ + struct in_addr in; + uint32_t addr; /* host order */ + char hostname[256]; + const char *method_used; + const char *hostname_used; + int explicit_ip=1; + int explicit_hostname=1; + int from_interface=0; + char *addr_string = NULL; + const char *address = options->Address; + int notice_severity = warn_severity <= LOG_NOTICE ? + LOG_NOTICE : warn_severity; + + tor_assert(addr_out); + + /* + * Step one: Fill in 'hostname' to be our best guess. + */ + + if (address && *address) { + strlcpy(hostname, address, sizeof(hostname)); + } else { /* then we need to guess our address */ + explicit_ip = 0; /* it's implicit */ + explicit_hostname = 0; /* it's implicit */ + + if (gethostname(hostname, sizeof(hostname)) < 0) { + log_fn(warn_severity, LD_NET,"Error obtaining local hostname"); + return -1; + } + log_debug(LD_CONFIG, "Guessed local host name as '%s'", hostname); + } + + /* + * Step two: Now that we know 'hostname', parse it or resolve it. If + * it doesn't parse or resolve, look at the interface address. Set 'addr' + * to be our (host-order) 32-bit answer. + */ + + if (tor_inet_aton(hostname, &in) == 0) { + /* then we have to resolve it */ + explicit_ip = 0; + if (tor_lookup_hostname(hostname, &addr)) { /* failed to resolve */ + uint32_t interface_ip; /* host order */ + + if (explicit_hostname) { + log_fn(warn_severity, LD_CONFIG, + "Could not resolve local Address '%s'. Failing.", hostname); + return -1; + } + log_fn(notice_severity, LD_CONFIG, + "Could not resolve guessed local hostname '%s'. " + "Trying something else.", hostname); + if (get_interface_address(warn_severity, &interface_ip)) { + log_fn(warn_severity, LD_CONFIG, + "Could not get local interface IP address. Failing."); + return -1; + } + from_interface = 1; + addr = interface_ip; + log_fn(notice_severity, LD_CONFIG, "Learned IP address '%s' for " + "local interface. Using that.", fmt_addr32(addr)); + strlcpy(hostname, "", sizeof(hostname)); + } else { /* resolved hostname into addr */ + if (!explicit_hostname && + is_internal_IP(addr, 0)) { + uint32_t interface_ip; + + log_fn(notice_severity, LD_CONFIG, "Guessed local hostname '%s' " + "resolves to a private IP address (%s). Trying something " + "else.", hostname, fmt_addr32(addr)); + + if (get_interface_address(warn_severity, &interface_ip)) { + log_fn(warn_severity, LD_CONFIG, + "Could not get local interface IP address. Too bad."); + } else if (is_internal_IP(interface_ip, 0)) { + log_fn(notice_severity, LD_CONFIG, + "Interface IP address '%s' is a private address too. " + "Ignoring.", fmt_addr32(interface_ip)); + } else { + from_interface = 1; + addr = interface_ip; + log_fn(notice_severity, LD_CONFIG, + "Learned IP address '%s' for local interface." + " Using that.", fmt_addr32(addr)); + strlcpy(hostname, "", sizeof(hostname)); + } + } + } + } else { + addr = ntohl(in.s_addr); /* set addr so that addr_string is not + * illformed */ + } + + /* + * Step three: Check whether 'addr' is an internal IP address, and error + * out if it is and we don't want that. + */ + + addr_string = tor_dup_ip(addr); + if (is_internal_IP(addr, 0)) { + /* make sure we're ok with publishing an internal IP */ + if (!options->DirAuthorities && !options->AlternateDirAuthority) { + /* if they are using the default authorities, disallow internal IPs + * always. */ + log_fn(warn_severity, LD_CONFIG, + "Address '%s' resolves to private IP address '%s'. " + "Tor servers that use the default DirAuthorities must have " + "public IP addresses.", hostname, addr_string); + tor_free(addr_string); + return -1; + } + if (!explicit_ip) { + /* even if they've set their own authorities, require an explicit IP if + * they're using an internal address. */ + log_fn(warn_severity, LD_CONFIG, "Address '%s' resolves to private " + "IP address '%s'. Please set the Address config option to be " + "the IP address you want to use.", hostname, addr_string); + tor_free(addr_string); + return -1; + } + } + + /* + * Step four: We have a winner! 'addr' is our answer for sure, and + * 'addr_string' is its string form. Fill out the various fields to + * say how we decided it. + */ + + log_debug(LD_CONFIG, "Resolved Address to '%s'.", addr_string); + + if (explicit_ip) { + method_used = "CONFIGURED"; + hostname_used = NULL; + } else if (explicit_hostname) { + method_used = "RESOLVED"; + hostname_used = hostname; + } else if (from_interface) { + method_used = "INTERFACE"; + hostname_used = NULL; + } else { + method_used = "GETHOSTNAME"; + hostname_used = hostname; + } + + *addr_out = addr; + if (method_out) + *method_out = method_used; + if (hostname_out) + *hostname_out = hostname_used ? tor_strdup(hostname_used) : NULL; + + /* + * Step five: Check if the answer has changed since last time (or if + * there was no last time), and if so call various functions to keep + * us up-to-date. + */ + + if (last_resolved_addr && last_resolved_addr != *addr_out) { + /* Leave this as a notice, regardless of the requested severity, + * at least until dynamic IP address support becomes bulletproof. */ + log_notice(LD_NET, + "Your IP address seems to have changed to %s " + "(METHOD=%s%s%s). Updating.", + addr_string, method_used, + hostname_used ? " HOSTNAME=" : "", + hostname_used ? hostname_used : ""); + ip_address_changed(0); + } + + if (last_resolved_addr != *addr_out) { + control_event_server_status(LOG_NOTICE, + "EXTERNAL_ADDRESS ADDRESS=%s METHOD=%s%s%s", + addr_string, method_used, + hostname_used ? " HOSTNAME=" : "", + hostname_used ? hostname_used : ""); + } + last_resolved_addr = *addr_out; + + /* + * And finally, clean up and return success. + */ + + tor_free(addr_string); + return 0; +} + +/** Return true iff addr is judged to be on the same network as us, or + * on a private network. + */ +int +is_local_addr(const tor_addr_t *addr) +{ + if (tor_addr_is_internal(addr, 0)) + return 1; + /* Check whether ip is on the same /24 as we are. */ + if (get_options()->EnforceDistinctSubnets == 0) + return 0; + if (tor_addr_family(addr) == AF_INET) { + /*XXXX023 IP6 what corresponds to an /24? */ + uint32_t ip = tor_addr_to_ipv4h(addr); + + /* It's possible that this next check will hit before the first time + * resolve_my_address actually succeeds. (For clients, it is likely that + * resolve_my_address will never be called at all). In those cases, + * last_resolved_addr will be 0, and so checking to see whether ip is on + * the same /24 as last_resolved_addr will be the same as checking whether + * it was on net 0, which is already done by is_internal_IP. + */ + if ((last_resolved_addr & (uint32_t)0xffffff00ul) + == (ip & (uint32_t)0xffffff00ul)) + return 1; + } + return 0; +} + +/** Return a new empty or_options_t. Used for testing. */ +or_options_t * +options_new(void) +{ + return config_new(&options_format); +} + +/** Set options to hold reasonable defaults for most options. + * Each option defaults to zero. */ +void +options_init(or_options_t *options) +{ + config_init(&options_format, options); +} + +/** Return a string containing a possible configuration file that would give + * the configuration in options. If minimal is true, do not + * include options that are the same as Tor's defaults. + */ +char * +options_dump(const or_options_t *options, int how_to_dump) +{ + const or_options_t *use_defaults; + int minimal; + switch (how_to_dump) { + case OPTIONS_DUMP_MINIMAL: + use_defaults = global_default_options; + minimal = 1; + break; + case OPTIONS_DUMP_DEFAULTS: + use_defaults = NULL; + minimal = 1; + break; + case OPTIONS_DUMP_ALL: + use_defaults = NULL; + minimal = 0; + break; + default: + log_warn(LD_BUG, "Bogus value for how_to_dump==%d", how_to_dump); + return NULL; + } + + return config_dump(&options_format, use_defaults, options, minimal, 0); +} + +/** Return 0 if every element of sl is a string holding a decimal + * representation of a port number, or if sl is NULL. + * Otherwise set *msg and return -1. */ +static int +validate_ports_csv(smartlist_t *sl, const char *name, char **msg) +{ + int i; + tor_assert(name); + + if (!sl) + return 0; + + SMARTLIST_FOREACH(sl, const char *, cp, + { + i = atoi(cp); + if (i < 1 || i > 65535) { + tor_asprintf(msg, "Port '%s' out of range in %s", cp, name); + return -1; + } + }); + return 0; +} + +/** If value exceeds ROUTER_MAX_DECLARED_BANDWIDTH, write + * a complaint into *msg using string desc, and return -1. + * Else return 0. + */ +static int +ensure_bandwidth_cap(uint64_t *value, const char *desc, char **msg) +{ + if (*value > ROUTER_MAX_DECLARED_BANDWIDTH) { + /* This handles an understandable special case where somebody says "2gb" + * whereas our actual maximum is 2gb-1 (INT_MAX) */ + --*value; + } + if (*value > ROUTER_MAX_DECLARED_BANDWIDTH) { + tor_asprintf(msg, "%s ("U64_FORMAT") must be at most %d", + desc, U64_PRINTF_ARG(*value), + ROUTER_MAX_DECLARED_BANDWIDTH); + return -1; + } + return 0; +} + +/** Parse an authority type from options-\>PublishServerDescriptor + * and write it to options-\>PublishServerDescriptor_. Treat "1" + * as "v3" unless BridgeRelay is 1, in which case treat it as "bridge". + * Treat "0" as "". + * Return 0 on success or -1 if not a recognized authority type (in which + * case the value of PublishServerDescriptor_ is undefined). */ +static int +compute_publishserverdescriptor(or_options_t *options) +{ + smartlist_t *list = options->PublishServerDescriptor; + dirinfo_type_t *auth = &options->PublishServerDescriptor_; + *auth = NO_DIRINFO; + if (!list) /* empty list, answer is none */ + return 0; + SMARTLIST_FOREACH_BEGIN(list, const char *, string) { + if (!strcasecmp(string, "v1")) + *auth |= V1_DIRINFO; + else if (!strcmp(string, "1")) + if (options->BridgeRelay) + *auth |= BRIDGE_DIRINFO; + else + *auth |= V3_DIRINFO; + else if (!strcasecmp(string, "v2")) + /* obsolete */; + else if (!strcasecmp(string, "v3")) + *auth |= V3_DIRINFO; + else if (!strcasecmp(string, "bridge")) + *auth |= BRIDGE_DIRINFO; + else if (!strcasecmp(string, "hidserv")) + log_warn(LD_CONFIG, + "PublishServerDescriptor hidserv is invalid. See " + "PublishHidServDescriptors."); + else if (!strcasecmp(string, "") || !strcmp(string, "0")) + /* no authority */; + else + return -1; + } SMARTLIST_FOREACH_END(string); + return 0; +} + +/** Lowest allowable value for RendPostPeriod; if this is too low, hidden + * services can overload the directory system. */ +#define MIN_REND_POST_PERIOD (10*60) + +/** Highest allowable value for RendPostPeriod. */ +#define MAX_DIR_PERIOD (MIN_ONION_KEY_LIFETIME/2) + +/** Lowest allowable value for MaxCircuitDirtiness; if this is too low, Tor + * will generate too many circuits and potentially overload the network. */ +#define MIN_MAX_CIRCUIT_DIRTINESS 10 + +/** Highest allowable value for MaxCircuitDirtiness: prevents time_t + * overflows. */ +#define MAX_MAX_CIRCUIT_DIRTINESS (30*24*60*60) + +/** Lowest allowable value for CircuitStreamTimeout; if this is too low, Tor + * will generate too many circuits and potentially overload the network. */ +#define MIN_CIRCUIT_STREAM_TIMEOUT 10 + +/** Lowest allowable value for HeartbeatPeriod; if this is too low, we might + * expose more information than we're comfortable with. */ +#define MIN_HEARTBEAT_PERIOD (30*60) + +/** Lowest recommended value for CircuitBuildTimeout; if it is set too low + * and LearnCircuitBuildTimeout is off, the failure rate for circuit + * construction may be very high. In that case, if it is set below this + * threshold emit a warning. + * */ +#define RECOMMENDED_MIN_CIRCUIT_BUILD_TIMEOUT (10) + +static int +options_validate_cb(void *old_options, void *options, void *default_options, + int from_setconf, char **msg) +{ + return options_validate(old_options, options, default_options, + from_setconf, msg); +} + +/** Return 0 if every setting in options is reasonable, is a + * permissible transition from old_options, and none of the + * testing-only settings differ from default_options unless in + * testing mode. Else return -1. Should have no side effects, except for + * normalizing the contents of options. + * + * On error, tor_strdup an error explanation into *msg. + * + * XXX + * If from_setconf, we were called by the controller, and our + * Log line should stay empty. If it's 0, then give us a default log + * if there are no logs defined. + */ +STATIC int +options_validate(or_options_t *old_options, or_options_t *options, + or_options_t *default_options, int from_setconf, char **msg) +{ + int i; + config_line_t *cl; + const char *uname = get_uname(); + int n_ports=0; +#define REJECT(arg) \ + STMT_BEGIN *msg = tor_strdup(arg); return -1; STMT_END +#define COMPLAIN(arg) STMT_BEGIN log_warn(LD_CONFIG, arg); STMT_END + + tor_assert(msg); + *msg = NULL; + + if (server_mode(options) && + (!strcmpstart(uname, "Windows 95") || + !strcmpstart(uname, "Windows 98") || + !strcmpstart(uname, "Windows Me"))) { + log_warn(LD_CONFIG, "Tor is running as a server, but you are " + "running %s; this probably won't work. See " + "https://wiki.torproject.org/TheOnionRouter/TorFAQ#ServerOS " + "for details.", uname); + } + + if (parse_ports(options, 1, msg, &n_ports) < 0) + return -1; + + if (parse_outbound_addresses(options, 1, msg) < 0) + return -1; + + if (validate_data_directory(options)<0) + REJECT("Invalid DataDirectory"); + + if (options->Nickname == NULL) { + if (server_mode(options)) { + options->Nickname = tor_strdup(UNNAMED_ROUTER_NICKNAME); + } + } else { + if (!is_legal_nickname(options->Nickname)) { + tor_asprintf(msg, + "Nickname '%s' is wrong length or contains illegal characters.", + options->Nickname); + return -1; + } + } + + if (server_mode(options) && !options->ContactInfo) + log_notice(LD_CONFIG, "Your ContactInfo config option is not set. " + "Please consider setting it, so we can contact you if your server is " + "misconfigured or something else goes wrong."); + + /* Special case on first boot if no Log options are given. */ + if (!options->Logs && !options->RunAsDaemon && !from_setconf) { + if (quiet_level == 0) + config_line_append(&options->Logs, "Log", "notice stdout"); + else if (quiet_level == 1) + config_line_append(&options->Logs, "Log", "warn stdout"); + } + + if (options_init_logs(options, 1)<0) /* Validate the tor_log(s) */ + REJECT("Failed to validate Log options. See logs for details."); + + if (authdir_mode(options)) { + /* confirm that our address isn't broken, so we can complain now */ + uint32_t tmp; + if (resolve_my_address(LOG_WARN, options, &tmp, NULL, NULL) < 0) + REJECT("Failed to resolve/guess local address. See logs for details."); + } + +#ifndef _WIN32 + if (options->RunAsDaemon && torrc_fname && path_is_relative(torrc_fname)) + REJECT("Can't use a relative path to torrc when RunAsDaemon is set."); +#endif + + /* XXXX require that the only port not be DirPort? */ + /* XXXX require that at least one port be listened-upon. */ + if (n_ports == 0 && !options->RendConfigLines) + log_warn(LD_CONFIG, + "SocksPort, TransPort, NATDPort, DNSPort, and ORPort are all " + "undefined, and there aren't any hidden services configured. " + "Tor will still run, but probably won't do anything."); + + options->TransProxyType_parsed = TPT_DEFAULT; +#ifdef USE_TRANSPARENT + if (options->TransProxyType) { + if (!strcasecmp(options->TransProxyType, "default")) { + options->TransProxyType_parsed = TPT_DEFAULT; + } else if (!strcasecmp(options->TransProxyType, "tproxy")) { +#ifndef __linux__ + REJECT("TPROXY is a Linux-specific feature."); +#else + options->TransProxyType_parsed = TPT_TPROXY; +#endif + } else { + REJECT("Unrecognized value for TransProxyType"); + } + + if (strcasecmp(options->TransProxyType, "default") && + !options->TransPort_set) { + REJECT("Cannot use TransProxyType without any valid TransPort or " + "TransListenAddress."); + } + } +#else + if (options->TransPort_set) + REJECT("TransPort and TransListenAddress are disabled " + "in this build."); +#endif + + if (options->TokenBucketRefillInterval <= 0 + || options->TokenBucketRefillInterval > 1000) { + REJECT("TokenBucketRefillInterval must be between 1 and 1000 inclusive."); + } + + if (options->ExcludeExitNodes || options->ExcludeNodes) { + options->ExcludeExitNodesUnion_ = routerset_new(); + routerset_union(options->ExcludeExitNodesUnion_,options->ExcludeExitNodes); + routerset_union(options->ExcludeExitNodesUnion_,options->ExcludeNodes); + } + + if (options->NodeFamilies) { + options->NodeFamilySets = smartlist_new(); + for (cl = options->NodeFamilies; cl; cl = cl->next) { + routerset_t *rs = routerset_new(); + if (routerset_parse(rs, cl->value, cl->key) == 0) { + smartlist_add(options->NodeFamilySets, rs); + } else { + routerset_free(rs); + } + } + } + + if (options->TLSECGroup && (strcasecmp(options->TLSECGroup, "P256") && + strcasecmp(options->TLSECGroup, "P224"))) { + COMPLAIN("Unrecognized TLSECGroup: Falling back to the default."); + tor_free(options->TLSECGroup); + } + + if (options->ExcludeNodes && options->StrictNodes) { + COMPLAIN("You have asked to exclude certain relays from all positions " + "in your circuits. Expect hidden services and other Tor " + "features to be broken in unpredictable ways."); + } + + if (options->AuthoritativeDir) { + if (!options->ContactInfo && !options->TestingTorNetwork) + REJECT("Authoritative directory servers must set ContactInfo"); + if (options->V1AuthoritativeDir && !options->RecommendedVersions) + REJECT("V1 authoritative dir servers must set RecommendedVersions."); + if (!options->RecommendedClientVersions) + options->RecommendedClientVersions = + config_lines_dup(options->RecommendedVersions); + if (!options->RecommendedServerVersions) + options->RecommendedServerVersions = + config_lines_dup(options->RecommendedVersions); + if (options->VersioningAuthoritativeDir && + (!options->RecommendedClientVersions || + !options->RecommendedServerVersions)) + REJECT("Versioning authoritative dir servers must set " + "Recommended*Versions."); + if (options->UseEntryGuards) { + log_info(LD_CONFIG, "Authoritative directory servers can't set " + "UseEntryGuards. Disabling."); + options->UseEntryGuards = 0; + } + if (!options->DownloadExtraInfo && authdir_mode_any_main(options)) { + log_info(LD_CONFIG, "Authoritative directories always try to download " + "extra-info documents. Setting DownloadExtraInfo."); + options->DownloadExtraInfo = 1; + } + if (!(options->BridgeAuthoritativeDir || options->HSAuthoritativeDir || + options->V1AuthoritativeDir || + options->V3AuthoritativeDir)) + REJECT("AuthoritativeDir is set, but none of " + "(Bridge/HS/V1/V3)AuthoritativeDir is set."); + /* If we have a v3bandwidthsfile and it's broken, complain on startup */ + if (options->V3BandwidthsFile && !old_options) { + dirserv_read_measured_bandwidths(options->V3BandwidthsFile, NULL); + } + } + + if (options->AuthoritativeDir && !options->DirPort_set) + REJECT("Running as authoritative directory, but no DirPort set."); + + if (options->AuthoritativeDir && !options->ORPort_set) + REJECT("Running as authoritative directory, but no ORPort set."); + + if (options->AuthoritativeDir && options->ClientOnly) + REJECT("Running as authoritative directory, but ClientOnly also set."); + + if (options->FetchDirInfoExtraEarly && !options->FetchDirInfoEarly) + REJECT("FetchDirInfoExtraEarly requires that you also set " + "FetchDirInfoEarly"); + + if (options->HSAuthoritativeDir && proxy_mode(options)) + REJECT("Running as authoritative v0 HS directory, but also configured " + "as a client."); + + if (options->ConnLimit <= 0) { + tor_asprintf(msg, + "ConnLimit must be greater than 0, but was set to %d", + options->ConnLimit); + return -1; + } + + if (options->PathsNeededToBuildCircuits >= 0.0) { + if (options->PathsNeededToBuildCircuits < 0.25) { + log_warn(LD_CONFIG, "PathsNeededToBuildCircuits is too low. Increasing " + "to 0.25"); + options->PathsNeededToBuildCircuits = 0.25; + } else if (options->PathsNeededToBuildCircuits > 0.95) { + log_warn(LD_CONFIG, "PathsNeededToBuildCircuits is too high. Decreasing " + "to 0.95"); + options->PathsNeededToBuildCircuits = 0.95; + } + } + + if (options->MaxClientCircuitsPending <= 0 || + options->MaxClientCircuitsPending > MAX_MAX_CLIENT_CIRCUITS_PENDING) { + tor_asprintf(msg, + "MaxClientCircuitsPending must be between 1 and %d, but " + "was set to %d", MAX_MAX_CLIENT_CIRCUITS_PENDING, + options->MaxClientCircuitsPending); + return -1; + } + + if (validate_ports_csv(options->FirewallPorts, "FirewallPorts", msg) < 0) + return -1; + + if (validate_ports_csv(options->LongLivedPorts, "LongLivedPorts", msg) < 0) + return -1; + + if (validate_ports_csv(options->RejectPlaintextPorts, + "RejectPlaintextPorts", msg) < 0) + return -1; + + if (validate_ports_csv(options->WarnPlaintextPorts, + "WarnPlaintextPorts", msg) < 0) + return -1; + + if (options->FascistFirewall && !options->ReachableAddresses) { + if (options->FirewallPorts && smartlist_len(options->FirewallPorts)) { + /* We already have firewall ports set, so migrate them to + * ReachableAddresses, which will set ReachableORAddresses and + * ReachableDirAddresses if they aren't set explicitly. */ + smartlist_t *instead = smartlist_new(); + config_line_t *new_line = tor_malloc_zero(sizeof(config_line_t)); + new_line->key = tor_strdup("ReachableAddresses"); + /* If we're configured with the old format, we need to prepend some + * open ports. */ + SMARTLIST_FOREACH(options->FirewallPorts, const char *, portno, + { + int p = atoi(portno); + if (p<0) continue; + smartlist_add_asprintf(instead, "*:%d", p); + }); + new_line->value = smartlist_join_strings(instead,",",0,NULL); + /* These have been deprecated since 0.1.1.5-alpha-cvs */ + log_notice(LD_CONFIG, + "Converting FascistFirewall and FirewallPorts " + "config options to new format: \"ReachableAddresses %s\"", + new_line->value); + options->ReachableAddresses = new_line; + SMARTLIST_FOREACH(instead, char *, cp, tor_free(cp)); + smartlist_free(instead); + } else { + /* We do not have FirewallPorts set, so add 80 to + * ReachableDirAddresses, and 443 to ReachableORAddresses. */ + if (!options->ReachableDirAddresses) { + config_line_t *new_line = tor_malloc_zero(sizeof(config_line_t)); + new_line->key = tor_strdup("ReachableDirAddresses"); + new_line->value = tor_strdup("*:80"); + options->ReachableDirAddresses = new_line; + log_notice(LD_CONFIG, "Converting FascistFirewall config option " + "to new format: \"ReachableDirAddresses *:80\""); + } + if (!options->ReachableORAddresses) { + config_line_t *new_line = tor_malloc_zero(sizeof(config_line_t)); + new_line->key = tor_strdup("ReachableORAddresses"); + new_line->value = tor_strdup("*:443"); + options->ReachableORAddresses = new_line; + log_notice(LD_CONFIG, "Converting FascistFirewall config option " + "to new format: \"ReachableORAddresses *:443\""); + } + } + } + + for (i=0; i<3; i++) { + config_line_t **linep = + (i==0) ? &options->ReachableAddresses : + (i==1) ? &options->ReachableORAddresses : + &options->ReachableDirAddresses; + if (!*linep) + continue; + /* We need to end with a reject *:*, not an implicit accept *:* */ + for (;;) { + if (!strcmp((*linep)->value, "reject *:*")) /* already there */ + break; + linep = &((*linep)->next); + if (!*linep) { + *linep = tor_malloc_zero(sizeof(config_line_t)); + (*linep)->key = tor_strdup( + (i==0) ? "ReachableAddresses" : + (i==1) ? "ReachableORAddresses" : + "ReachableDirAddresses"); + (*linep)->value = tor_strdup("reject *:*"); + break; + } + } + } + + if ((options->ReachableAddresses || + options->ReachableORAddresses || + options->ReachableDirAddresses) && + server_mode(options)) + REJECT("Servers must be able to freely connect to the rest " + "of the Internet, so they must not set Reachable*Addresses " + "or FascistFirewall."); + + if (options->UseBridges && + server_mode(options)) + REJECT("Servers must be able to freely connect to the rest " + "of the Internet, so they must not set UseBridges."); + + /* If both of these are set, we'll end up with funny behavior where we + * demand enough entrynodes be up and running else we won't build + * circuits, yet we never actually use them. */ + if (options->UseBridges && options->EntryNodes) + REJECT("You cannot set both UseBridges and EntryNodes."); + + if (options->EntryNodes && !options->UseEntryGuards) { + REJECT("If EntryNodes is set, UseEntryGuards must be enabled."); + } + + if (options->MaxMemInCellQueues < (500 << 20)) { + log_warn(LD_CONFIG, "MaxMemInCellQueues must be at least 500 MB for now. " + "Ideally, have it as large as you can afford."); + options->MaxMemInCellQueues = (500 << 20); + } + + options->AllowInvalid_ = 0; + + if (options->AllowInvalidNodes) { + SMARTLIST_FOREACH_BEGIN(options->AllowInvalidNodes, const char *, cp) { + if (!strcasecmp(cp, "entry")) + options->AllowInvalid_ |= ALLOW_INVALID_ENTRY; + else if (!strcasecmp(cp, "exit")) + options->AllowInvalid_ |= ALLOW_INVALID_EXIT; + else if (!strcasecmp(cp, "middle")) + options->AllowInvalid_ |= ALLOW_INVALID_MIDDLE; + else if (!strcasecmp(cp, "introduction")) + options->AllowInvalid_ |= ALLOW_INVALID_INTRODUCTION; + else if (!strcasecmp(cp, "rendezvous")) + options->AllowInvalid_ |= ALLOW_INVALID_RENDEZVOUS; + else { + tor_asprintf(msg, + "Unrecognized value '%s' in AllowInvalidNodes", cp); + return -1; + } + } SMARTLIST_FOREACH_END(cp); + } + + if (!options->SafeLogging || + !strcasecmp(options->SafeLogging, "0")) { + options->SafeLogging_ = SAFELOG_SCRUB_NONE; + } else if (!strcasecmp(options->SafeLogging, "relay")) { + options->SafeLogging_ = SAFELOG_SCRUB_RELAY; + } else if (!strcasecmp(options->SafeLogging, "1")) { + options->SafeLogging_ = SAFELOG_SCRUB_ALL; + } else { + tor_asprintf(msg, + "Unrecognized value '%s' in SafeLogging", + escaped(options->SafeLogging)); + return -1; + } + + if (compute_publishserverdescriptor(options) < 0) { + tor_asprintf(msg, "Unrecognized value in PublishServerDescriptor"); + return -1; + } + + if ((options->BridgeRelay + || options->PublishServerDescriptor_ & BRIDGE_DIRINFO) + && (options->PublishServerDescriptor_ + & (V1_DIRINFO|V3_DIRINFO))) { + REJECT("Bridges are not supposed to publish router descriptors to the " + "directory authorities. Please correct your " + "PublishServerDescriptor line."); + } + + if (options->BridgeRelay && options->DirPort_set) { + log_warn(LD_CONFIG, "Can't set a DirPort on a bridge relay; disabling " + "DirPort"); + config_free_lines(options->DirPort_lines); + options->DirPort_lines = NULL; + options->DirPort_set = 0; + } + + if (options->MinUptimeHidServDirectoryV2 < 0) { + log_warn(LD_CONFIG, "MinUptimeHidServDirectoryV2 option must be at " + "least 0 seconds. Changing to 0."); + options->MinUptimeHidServDirectoryV2 = 0; + } + + if (options->RendPostPeriod < MIN_REND_POST_PERIOD) { + log_warn(LD_CONFIG, "RendPostPeriod option is too short; " + "raising to %d seconds.", MIN_REND_POST_PERIOD); + options->RendPostPeriod = MIN_REND_POST_PERIOD; + } + + if (options->RendPostPeriod > MAX_DIR_PERIOD) { + log_warn(LD_CONFIG, "RendPostPeriod is too large; clipping to %ds.", + MAX_DIR_PERIOD); + options->RendPostPeriod = MAX_DIR_PERIOD; + } + + if (options->Tor2webMode && options->LearnCircuitBuildTimeout) { + /* LearnCircuitBuildTimeout and Tor2webMode are incompatible in + * two ways: + * + * - LearnCircuitBuildTimeout results in a low CBT, which + * Tor2webMode's use of one-hop rendezvous circuits lowers + * much further, producing *far* too many timeouts. + * + * - The adaptive CBT code does not update its timeout estimate + * using build times for single-hop circuits. + * + * If we fix both of these issues someday, we should test + * Tor2webMode with LearnCircuitBuildTimeout on again. */ + log_notice(LD_CONFIG,"Tor2webMode is enabled; turning " + "LearnCircuitBuildTimeout off."); + options->LearnCircuitBuildTimeout = 0; + } + + if (options->Tor2webMode && options->UseEntryGuards) { + /* tor2web mode clients do not (and should not) use entry guards + * in any meaningful way. Further, tor2web mode causes the hidden + * service client code to do things which break the path bias + * detector, and it's far easier to turn off entry guards (and + * thus the path bias detector with it) than to figure out how to + * make a piece of code which cannot possibly help tor2web mode + * users compatible with tor2web mode. + */ + log_notice(LD_CONFIG, + "Tor2WebMode is enabled; disabling UseEntryGuards."); + options->UseEntryGuards = 0; + } + + if (!(options->UseEntryGuards) && + (options->RendConfigLines != NULL)) { + log_warn(LD_CONFIG, + "UseEntryGuards is disabled, but you have configured one or more " + "hidden services on this Tor instance. Your hidden services " + "will be very easy to locate using a well-known attack -- see " + "http://freehaven.net/anonbib/#hs-attack06 for details."); + } + + if (!options->LearnCircuitBuildTimeout && options->CircuitBuildTimeout && + options->CircuitBuildTimeout < RECOMMENDED_MIN_CIRCUIT_BUILD_TIMEOUT) { + log_warn(LD_CONFIG, + "CircuitBuildTimeout is shorter (%d seconds) than the recommended " + "minimum (%d seconds), and LearnCircuitBuildTimeout is disabled. " + "If tor isn't working, raise this value or enable " + "LearnCircuitBuildTimeout.", + options->CircuitBuildTimeout, + RECOMMENDED_MIN_CIRCUIT_BUILD_TIMEOUT ); + } else if (!options->LearnCircuitBuildTimeout && + !options->CircuitBuildTimeout) { + log_notice(LD_CONFIG, "You disabled LearnCircuitBuildTimeout, but didn't " + "a CircuitBuildTimeout. I'll pick a plausible default."); + } + + if (options->PathBiasNoticeRate > 1.0) { + tor_asprintf(msg, + "PathBiasNoticeRate is too high. " + "It must be between 0 and 1.0"); + return -1; + } + if (options->PathBiasWarnRate > 1.0) { + tor_asprintf(msg, + "PathBiasWarnRate is too high. " + "It must be between 0 and 1.0"); + return -1; + } + if (options->PathBiasExtremeRate > 1.0) { + tor_asprintf(msg, + "PathBiasExtremeRate is too high. " + "It must be between 0 and 1.0"); + return -1; + } + if (options->PathBiasNoticeUseRate > 1.0) { + tor_asprintf(msg, + "PathBiasNoticeUseRate is too high. " + "It must be between 0 and 1.0"); + return -1; + } + if (options->PathBiasExtremeUseRate > 1.0) { + tor_asprintf(msg, + "PathBiasExtremeUseRate is too high. " + "It must be between 0 and 1.0"); + return -1; + } + + if (options->MaxCircuitDirtiness < MIN_MAX_CIRCUIT_DIRTINESS) { + log_warn(LD_CONFIG, "MaxCircuitDirtiness option is too short; " + "raising to %d seconds.", MIN_MAX_CIRCUIT_DIRTINESS); + options->MaxCircuitDirtiness = MIN_MAX_CIRCUIT_DIRTINESS; + } + + if (options->MaxCircuitDirtiness > MAX_MAX_CIRCUIT_DIRTINESS) { + log_warn(LD_CONFIG, "MaxCircuitDirtiness option is too high; " + "setting to %d days.", MAX_MAX_CIRCUIT_DIRTINESS/86400); + options->MaxCircuitDirtiness = MAX_MAX_CIRCUIT_DIRTINESS; + } + + if (options->CircuitStreamTimeout && + options->CircuitStreamTimeout < MIN_CIRCUIT_STREAM_TIMEOUT) { + log_warn(LD_CONFIG, "CircuitStreamTimeout option is too short; " + "raising to %d seconds.", MIN_CIRCUIT_STREAM_TIMEOUT); + options->CircuitStreamTimeout = MIN_CIRCUIT_STREAM_TIMEOUT; + } + + if (options->HeartbeatPeriod && + options->HeartbeatPeriod < MIN_HEARTBEAT_PERIOD) { + log_warn(LD_CONFIG, "HeartbeatPeriod option is too short; " + "raising to %d seconds.", MIN_HEARTBEAT_PERIOD); + options->HeartbeatPeriod = MIN_HEARTBEAT_PERIOD; + } + + if (options->KeepalivePeriod < 1) + REJECT("KeepalivePeriod option must be positive."); + + if (ensure_bandwidth_cap(&options->BandwidthRate, + "BandwidthRate", msg) < 0) + return -1; + if (ensure_bandwidth_cap(&options->BandwidthBurst, + "BandwidthBurst", msg) < 0) + return -1; + if (ensure_bandwidth_cap(&options->MaxAdvertisedBandwidth, + "MaxAdvertisedBandwidth", msg) < 0) + return -1; + if (ensure_bandwidth_cap(&options->RelayBandwidthRate, + "RelayBandwidthRate", msg) < 0) + return -1; + if (ensure_bandwidth_cap(&options->RelayBandwidthBurst, + "RelayBandwidthBurst", msg) < 0) + return -1; + if (ensure_bandwidth_cap(&options->PerConnBWRate, + "PerConnBWRate", msg) < 0) + return -1; + if (ensure_bandwidth_cap(&options->PerConnBWBurst, + "PerConnBWBurst", msg) < 0) + return -1; + if (ensure_bandwidth_cap(&options->AuthDirFastGuarantee, + "AuthDirFastGuarantee", msg) < 0) + return -1; + if (ensure_bandwidth_cap(&options->AuthDirGuardBWGuarantee, + "AuthDirGuardBWGuarantee", msg) < 0) + return -1; + + if (options->RelayBandwidthRate && !options->RelayBandwidthBurst) + options->RelayBandwidthBurst = options->RelayBandwidthRate; + if (options->RelayBandwidthBurst && !options->RelayBandwidthRate) + options->RelayBandwidthRate = options->RelayBandwidthBurst; + + if (server_mode(options)) { + if (options->BandwidthRate < ROUTER_REQUIRED_MIN_BANDWIDTH) { + tor_asprintf(msg, + "BandwidthRate is set to %d bytes/second. " + "For servers, it must be at least %d.", + (int)options->BandwidthRate, + ROUTER_REQUIRED_MIN_BANDWIDTH); + return -1; + } else if (options->MaxAdvertisedBandwidth < + ROUTER_REQUIRED_MIN_BANDWIDTH/2) { + tor_asprintf(msg, + "MaxAdvertisedBandwidth is set to %d bytes/second. " + "For servers, it must be at least %d.", + (int)options->MaxAdvertisedBandwidth, + ROUTER_REQUIRED_MIN_BANDWIDTH/2); + return -1; + } + if (options->RelayBandwidthRate && + options->RelayBandwidthRate < ROUTER_REQUIRED_MIN_BANDWIDTH) { + tor_asprintf(msg, + "RelayBandwidthRate is set to %d bytes/second. " + "For servers, it must be at least %d.", + (int)options->RelayBandwidthRate, + ROUTER_REQUIRED_MIN_BANDWIDTH); + return -1; + } + } + + if (options->RelayBandwidthRate > options->RelayBandwidthBurst) + REJECT("RelayBandwidthBurst must be at least equal " + "to RelayBandwidthRate."); + + if (options->BandwidthRate > options->BandwidthBurst) + REJECT("BandwidthBurst must be at least equal to BandwidthRate."); + + /* if they set relaybandwidth* really high but left bandwidth* + * at the default, raise the defaults. */ + if (options->RelayBandwidthRate > options->BandwidthRate) + options->BandwidthRate = options->RelayBandwidthRate; + if (options->RelayBandwidthBurst > options->BandwidthBurst) + options->BandwidthBurst = options->RelayBandwidthBurst; + + if (accounting_parse_options(options, 1)<0) + REJECT("Failed to parse accounting options. See logs for details."); + + if (options->AccountingMax) { + if (options->RendConfigLines && server_mode(options)) { + log_warn(LD_CONFIG, "Using accounting with a hidden service and an " + "ORPort is risky: your hidden service(s) and your public " + "address will all turn off at the same time, which may alert " + "observers that they are being run by the same party."); + } else if (config_count_key(options->RendConfigLines, + "HiddenServiceDir") > 1) { + log_warn(LD_CONFIG, "Using accounting with multiple hidden services is " + "risky: they will all turn off at the same time, which may " + "alert observers that they are being run by the same party."); + } + } + + if (options->HTTPProxy) { /* parse it now */ + if (tor_addr_port_lookup(options->HTTPProxy, + &options->HTTPProxyAddr, &options->HTTPProxyPort) < 0) + REJECT("HTTPProxy failed to parse or resolve. Please fix."); + if (options->HTTPProxyPort == 0) { /* give it a default */ + options->HTTPProxyPort = 80; + } + } + + if (options->HTTPProxyAuthenticator) { + if (strlen(options->HTTPProxyAuthenticator) >= 512) + REJECT("HTTPProxyAuthenticator is too long (>= 512 chars)."); + } + + if (options->HTTPSProxy) { /* parse it now */ + if (tor_addr_port_lookup(options->HTTPSProxy, + &options->HTTPSProxyAddr, &options->HTTPSProxyPort) <0) + REJECT("HTTPSProxy failed to parse or resolve. Please fix."); + if (options->HTTPSProxyPort == 0) { /* give it a default */ + options->HTTPSProxyPort = 443; + } + } + + if (options->HTTPSProxyAuthenticator) { + if (strlen(options->HTTPSProxyAuthenticator) >= 512) + REJECT("HTTPSProxyAuthenticator is too long (>= 512 chars)."); + } + + if (options->Socks4Proxy) { /* parse it now */ + if (tor_addr_port_lookup(options->Socks4Proxy, + &options->Socks4ProxyAddr, + &options->Socks4ProxyPort) <0) + REJECT("Socks4Proxy failed to parse or resolve. Please fix."); + if (options->Socks4ProxyPort == 0) { /* give it a default */ + options->Socks4ProxyPort = 1080; + } + } + + if (options->Socks5Proxy) { /* parse it now */ + if (tor_addr_port_lookup(options->Socks5Proxy, + &options->Socks5ProxyAddr, + &options->Socks5ProxyPort) <0) + REJECT("Socks5Proxy failed to parse or resolve. Please fix."); + if (options->Socks5ProxyPort == 0) { /* give it a default */ + options->Socks5ProxyPort = 1080; + } + } + + /* Check if more than one proxy type has been enabled. */ + if (!!options->Socks4Proxy + !!options->Socks5Proxy + + !!options->HTTPSProxy + !!options->ClientTransportPlugin > 1) + REJECT("You have configured more than one proxy type. " + "(Socks4Proxy|Socks5Proxy|HTTPSProxy|ClientTransportPlugin)"); + + /* Check if the proxies will give surprising behavior. */ + if (options->HTTPProxy && !(options->Socks4Proxy || + options->Socks5Proxy || + options->HTTPSProxy)) { + log_warn(LD_CONFIG, "HTTPProxy configured, but no SOCKS proxy or " + "HTTPS proxy configured. Watch out: this configuration will " + "proxy unencrypted directory connections only."); + } + + if (options->Socks5ProxyUsername) { + size_t len; + + len = strlen(options->Socks5ProxyUsername); + if (len < 1 || len > MAX_SOCKS5_AUTH_FIELD_SIZE) + REJECT("Socks5ProxyUsername must be between 1 and 255 characters."); + + if (!options->Socks5ProxyPassword) + REJECT("Socks5ProxyPassword must be included with Socks5ProxyUsername."); + + len = strlen(options->Socks5ProxyPassword); + if (len < 1 || len > MAX_SOCKS5_AUTH_FIELD_SIZE) + REJECT("Socks5ProxyPassword must be between 1 and 255 characters."); + } else if (options->Socks5ProxyPassword) + REJECT("Socks5ProxyPassword must be included with Socks5ProxyUsername."); + + if (options->HashedControlPassword) { + smartlist_t *sl = decode_hashed_passwords(options->HashedControlPassword); + if (!sl) { + REJECT("Bad HashedControlPassword: wrong length or bad encoding"); + } else { + SMARTLIST_FOREACH(sl, char*, cp, tor_free(cp)); + smartlist_free(sl); + } + } + + if (options->HashedControlSessionPassword) { + smartlist_t *sl = decode_hashed_passwords( + options->HashedControlSessionPassword); + if (!sl) { + REJECT("Bad HashedControlSessionPassword: wrong length or bad encoding"); + } else { + SMARTLIST_FOREACH(sl, char*, cp, tor_free(cp)); + smartlist_free(sl); + } + } + + if (options->OwningControllerProcess) { + const char *validate_pspec_msg = NULL; + if (tor_validate_process_specifier(options->OwningControllerProcess, + &validate_pspec_msg)) { + tor_asprintf(msg, "Bad OwningControllerProcess: %s", + validate_pspec_msg); + return -1; + } + } + + if (options->ControlPort_set && !options->HashedControlPassword && + !options->HashedControlSessionPassword && + !options->CookieAuthentication) { + log_warn(LD_CONFIG, "ControlPort is open, but no authentication method " + "has been configured. This means that any program on your " + "computer can reconfigure your Tor. That's bad! You should " + "upgrade your Tor controller as soon as possible."); + } + + if (options->CookieAuthFileGroupReadable && !options->CookieAuthFile) { + log_warn(LD_CONFIG, "CookieAuthFileGroupReadable is set, but will have " + "no effect: you must specify an explicit CookieAuthFile to " + "have it group-readable."); + } + + if (options->UseEntryGuards && ! options->NumEntryGuards) + REJECT("Cannot enable UseEntryGuards with NumEntryGuards set to 0"); + + if (options->MyFamily && options->BridgeRelay) { + log_warn(LD_CONFIG, "Listing a family for a bridge relay is not " + "supported: it can reveal bridge fingerprints to censors. " + "You should also make sure you aren't listing this bridge's " + "fingerprint in any other MyFamily."); + } + if (check_nickname_list(&options->MyFamily, "MyFamily", msg)) + return -1; + for (cl = options->NodeFamilies; cl; cl = cl->next) { + routerset_t *rs = routerset_new(); + if (routerset_parse(rs, cl->value, cl->key)) { + routerset_free(rs); + return -1; + } + routerset_free(rs); + } + + if (validate_addr_policies(options, msg) < 0) + return -1; + + if (validate_dir_servers(options, old_options) < 0) + REJECT("Directory authority/fallback line did not parse. See logs " + "for details."); + + if (options->UseBridges && !options->Bridges) + REJECT("If you set UseBridges, you must specify at least one bridge."); + if (options->UseBridges && !options->TunnelDirConns) + REJECT("If you set UseBridges, you must set TunnelDirConns."); + + for (cl = options->Bridges; cl; cl = cl->next) { + bridge_line_t *bridge_line = parse_bridge_line(cl->value); + if (!bridge_line) + REJECT("Bridge line did not parse. See logs for details."); + bridge_line_free(bridge_line); + } + + for (cl = options->ClientTransportPlugin; cl; cl = cl->next) { + if (parse_client_transport_line(cl->value, 1)<0) + REJECT("Transport line did not parse. See logs for details."); + } + + for (cl = options->ServerTransportPlugin; cl; cl = cl->next) { + if (parse_server_transport_line(cl->value, 1)<0) + REJECT("Server transport line did not parse. See logs for details."); + } + + if (options->ServerTransportPlugin && !server_mode(options)) { + log_notice(LD_GENERAL, "Tor is not configured as a relay but you specified" + " a ServerTransportPlugin line (%s). The ServerTransportPlugin " + "line will be ignored.", + escaped(options->ServerTransportPlugin->value)); + } + + for (cl = options->ServerTransportListenAddr; cl; cl = cl->next) { + /** If get_bindaddr_from_transport_listen_line() fails with + 'transport' being NULL, it means that something went wrong + while parsing the ServerTransportListenAddr line. */ + char *bindaddr = get_bindaddr_from_transport_listen_line(cl->value, NULL); + if (!bindaddr) + REJECT("ServerTransportListenAddr did not parse. See logs for details."); + tor_free(bindaddr); + } + + if (options->ServerTransportListenAddr && !options->ServerTransportPlugin) { + log_notice(LD_GENERAL, "You need at least a single managed-proxy to " + "specify a transport listen address. The " + "ServerTransportListenAddr line will be ignored."); + } + + for (cl = options->ServerTransportOptions; cl; cl = cl->next) { + /** If get_options_from_transport_options_line() fails with + 'transport' being NULL, it means that something went wrong + while parsing the ServerTransportOptions line. */ + smartlist_t *options_sl = + get_options_from_transport_options_line(cl->value, NULL); + if (!options_sl) + REJECT("ServerTransportOptions did not parse. See logs for details."); + + SMARTLIST_FOREACH(options_sl, char *, cp, tor_free(cp)); + smartlist_free(options_sl); + } + + /* If we are a bridge with a pluggable transport proxy but no + Extended ORPort, inform the user that she is missing out. */ + if (server_mode(options) && options->ServerTransportPlugin && + !options->ExtORPort_lines) { + log_notice(LD_CONFIG, "We are a bridge with a pluggable transport " + "proxy but the Extended ORPort is disabled. The " + "Extended ORPort helps Tor communicate with the pluggable " + "transport proxy. Please enable it using the ExtORPort " + "torrc option."); + } + + if (options->ConstrainedSockets) { + /* If the user wants to constrain socket buffer use, make sure the desired + * limit is between MIN|MAX_TCPSOCK_BUFFER in k increments. */ + if (options->ConstrainedSockSize < MIN_CONSTRAINED_TCP_BUFFER || + options->ConstrainedSockSize > MAX_CONSTRAINED_TCP_BUFFER || + options->ConstrainedSockSize % 1024) { + tor_asprintf(msg, + "ConstrainedSockSize is invalid. Must be a value between %d and %d " + "in 1024 byte increments.", + MIN_CONSTRAINED_TCP_BUFFER, MAX_CONSTRAINED_TCP_BUFFER); + return -1; + } + if (options->DirPort_set) { + /* Providing cached directory entries while system TCP buffers are scarce + * will exacerbate the socket errors. Suggest that this be disabled. */ + COMPLAIN("You have requested constrained socket buffers while also " + "serving directory entries via DirPort. It is strongly " + "suggested that you disable serving directory requests when " + "system TCP buffer resources are scarce."); + } + } + + if (options->V3AuthVoteDelay + options->V3AuthDistDelay >= + options->V3AuthVotingInterval/2) { + REJECT("V3AuthVoteDelay plus V3AuthDistDelay must be less than half " + "V3AuthVotingInterval"); + } + if (options->V3AuthVoteDelay < MIN_VOTE_SECONDS) + REJECT("V3AuthVoteDelay is way too low."); + if (options->V3AuthDistDelay < MIN_DIST_SECONDS) + REJECT("V3AuthDistDelay is way too low."); + + if (options->V3AuthNIntervalsValid < 2) + REJECT("V3AuthNIntervalsValid must be at least 2."); + + if (options->V3AuthVotingInterval < MIN_VOTE_INTERVAL) { + REJECT("V3AuthVotingInterval is insanely low."); + } else if (options->V3AuthVotingInterval > 24*60*60) { + REJECT("V3AuthVotingInterval is insanely high."); + } else if (((24*60*60) % options->V3AuthVotingInterval) != 0) { + COMPLAIN("V3AuthVotingInterval does not divide evenly into 24 hours."); + } + + if (rend_config_services(options, 1) < 0) + REJECT("Failed to configure rendezvous options. See logs for details."); + + /* Parse client-side authorization for hidden services. */ + if (rend_parse_service_authorization(options, 1) < 0) + REJECT("Failed to configure client authorization for hidden services. " + "See logs for details."); + + if (parse_virtual_addr_network(options->VirtualAddrNetworkIPv4, + AF_INET, 1, msg)<0) + return -1; + if (parse_virtual_addr_network(options->VirtualAddrNetworkIPv6, + AF_INET6, 1, msg)<0) + return -1; + + if (options->PreferTunneledDirConns && !options->TunnelDirConns) + REJECT("Must set TunnelDirConns if PreferTunneledDirConns is set."); + + if ((options->Socks4Proxy || options->Socks5Proxy) && + !options->HTTPProxy && !options->PreferTunneledDirConns) + REJECT("When Socks4Proxy or Socks5Proxy is configured, " + "PreferTunneledDirConns and TunnelDirConns must both be " + "set to 1, or HTTPProxy must be configured."); + + if (options->AutomapHostsSuffixes) { + SMARTLIST_FOREACH(options->AutomapHostsSuffixes, char *, suf, + { + size_t len = strlen(suf); + if (len && suf[len-1] == '.') + suf[len-1] = '\0'; + }); + } + + if (options->TestingTorNetwork && + !(options->DirAuthorities || + (options->AlternateDirAuthority && + options->AlternateBridgeAuthority))) { + REJECT("TestingTorNetwork may only be configured in combination with " + "a non-default set of DirAuthority or both of " + "AlternateDirAuthority and AlternateBridgeAuthority configured."); + } + + if (options->AllowSingleHopExits && !options->DirAuthorities) { + COMPLAIN("You have set AllowSingleHopExits; now your relay will allow " + "others to make one-hop exits. However, since by default most " + "clients avoid relays that set this option, most clients will " + "ignore you."); + } + +#define CHECK_DEFAULT(arg) \ + STMT_BEGIN \ + if (!options->TestingTorNetwork && \ + !options->UsingTestNetworkDefaults_ && \ + !config_is_same(&options_format,options, \ + default_options,#arg)) { \ + REJECT(#arg " may only be changed in testing Tor " \ + "networks!"); \ + } STMT_END + CHECK_DEFAULT(TestingV3AuthInitialVotingInterval); + CHECK_DEFAULT(TestingV3AuthInitialVoteDelay); + CHECK_DEFAULT(TestingV3AuthInitialDistDelay); + CHECK_DEFAULT(TestingV3AuthVotingStartOffset); + CHECK_DEFAULT(TestingAuthDirTimeToLearnReachability); + CHECK_DEFAULT(TestingEstimatedDescriptorPropagationTime); + CHECK_DEFAULT(TestingServerDownloadSchedule); + CHECK_DEFAULT(TestingClientDownloadSchedule); + CHECK_DEFAULT(TestingServerConsensusDownloadSchedule); + CHECK_DEFAULT(TestingClientConsensusDownloadSchedule); + CHECK_DEFAULT(TestingBridgeDownloadSchedule); + CHECK_DEFAULT(TestingClientMaxIntervalWithoutRequest); + CHECK_DEFAULT(TestingDirConnectionMaxStall); + CHECK_DEFAULT(TestingConsensusMaxDownloadTries); + CHECK_DEFAULT(TestingDescriptorMaxDownloadTries); + CHECK_DEFAULT(TestingMicrodescMaxDownloadTries); + CHECK_DEFAULT(TestingCertMaxDownloadTries); +#undef CHECK_DEFAULT + + if (options->TestingV3AuthInitialVotingInterval < MIN_VOTE_INTERVAL) { + REJECT("TestingV3AuthInitialVotingInterval is insanely low."); + } else if (((30*60) % options->TestingV3AuthInitialVotingInterval) != 0) { + REJECT("TestingV3AuthInitialVotingInterval does not divide evenly into " + "30 minutes."); + } + + if (options->TestingV3AuthInitialVoteDelay < MIN_VOTE_SECONDS) { + REJECT("TestingV3AuthInitialVoteDelay is way too low."); + } + + if (options->TestingV3AuthInitialDistDelay < MIN_DIST_SECONDS) { + REJECT("TestingV3AuthInitialDistDelay is way too low."); + } + + if (options->TestingV3AuthInitialVoteDelay + + options->TestingV3AuthInitialDistDelay >= + options->TestingV3AuthInitialVotingInterval/2) { + REJECT("TestingV3AuthInitialVoteDelay plus TestingV3AuthInitialDistDelay " + "must be less than half TestingV3AuthInitialVotingInterval"); + } + + if (options->TestingV3AuthVotingStartOffset > + MIN(options->TestingV3AuthInitialVotingInterval, + options->V3AuthVotingInterval)) { + REJECT("TestingV3AuthVotingStartOffset is higher than the voting " + "interval."); + } + + if (options->TestingAuthDirTimeToLearnReachability < 0) { + REJECT("TestingAuthDirTimeToLearnReachability must be non-negative."); + } else if (options->TestingAuthDirTimeToLearnReachability > 2*60*60) { + COMPLAIN("TestingAuthDirTimeToLearnReachability is insanely high."); + } + + if (options->TestingEstimatedDescriptorPropagationTime < 0) { + REJECT("TestingEstimatedDescriptorPropagationTime must be non-negative."); + } else if (options->TestingEstimatedDescriptorPropagationTime > 60*60) { + COMPLAIN("TestingEstimatedDescriptorPropagationTime is insanely high."); + } + + if (options->TestingClientMaxIntervalWithoutRequest < 1) { + REJECT("TestingClientMaxIntervalWithoutRequest is way too low."); + } else if (options->TestingClientMaxIntervalWithoutRequest > 3600) { + COMPLAIN("TestingClientMaxIntervalWithoutRequest is insanely high."); + } + + if (options->TestingDirConnectionMaxStall < 5) { + REJECT("TestingDirConnectionMaxStall is way too low."); + } else if (options->TestingDirConnectionMaxStall > 3600) { + COMPLAIN("TestingDirConnectionMaxStall is insanely high."); + } + + if (options->TestingConsensusMaxDownloadTries < 2) { + REJECT("TestingConsensusMaxDownloadTries must be greater than 1."); + } else if (options->TestingConsensusMaxDownloadTries > 800) { + COMPLAIN("TestingConsensusMaxDownloadTries is insanely high."); + } + + if (options->TestingDescriptorMaxDownloadTries < 2) { + REJECT("TestingDescriptorMaxDownloadTries must be greater than 1."); + } else if (options->TestingDescriptorMaxDownloadTries > 800) { + COMPLAIN("TestingDescriptorMaxDownloadTries is insanely high."); + } + + if (options->TestingMicrodescMaxDownloadTries < 2) { + REJECT("TestingMicrodescMaxDownloadTries must be greater than 1."); + } else if (options->TestingMicrodescMaxDownloadTries > 800) { + COMPLAIN("TestingMicrodescMaxDownloadTries is insanely high."); + } + + if (options->TestingCertMaxDownloadTries < 2) { + REJECT("TestingCertMaxDownloadTries must be greater than 1."); + } else if (options->TestingCertMaxDownloadTries > 800) { + COMPLAIN("TestingCertMaxDownloadTries is insanely high."); + } + + if (options->TestingEnableConnBwEvent && + !options->TestingTorNetwork && !options->UsingTestNetworkDefaults_) { + REJECT("TestingEnableConnBwEvent may only be changed in testing " + "Tor networks!"); + } + + if (options->TestingEnableCellStatsEvent && + !options->TestingTorNetwork && !options->UsingTestNetworkDefaults_) { + REJECT("TestingEnableCellStatsEvent may only be changed in testing " + "Tor networks!"); + } + + if (options->TestingEnableTbEmptyEvent && + !options->TestingTorNetwork && !options->UsingTestNetworkDefaults_) { + REJECT("TestingEnableTbEmptyEvent may only be changed in testing " + "Tor networks!"); + } + + if (options->TestingTorNetwork) { + log_warn(LD_CONFIG, "TestingTorNetwork is set. This will make your node " + "almost unusable in the public Tor network, and is " + "therefore only advised if you are building a " + "testing Tor network!"); + } + + if (options->AccelName && !options->HardwareAccel) + options->HardwareAccel = 1; + if (options->AccelDir && !options->AccelName) + REJECT("Can't use hardware crypto accelerator dir without engine name."); + + if (options->PublishServerDescriptor) + SMARTLIST_FOREACH(options->PublishServerDescriptor, const char *, pubdes, { + if (!strcmp(pubdes, "1") || !strcmp(pubdes, "0")) + if (smartlist_len(options->PublishServerDescriptor) > 1) { + COMPLAIN("You have passed a list of multiple arguments to the " + "PublishServerDescriptor option that includes 0 or 1. " + "0 or 1 should only be used as the sole argument. " + "This configuration will be rejected in a future release."); + break; + } + }); + + if (options->BridgeRelay == 1 && ! options->ORPort_set) + REJECT("BridgeRelay is 1, ORPort is not set. This is an invalid " + "combination."); + + return 0; +#undef REJECT +#undef COMPLAIN +} + +/** Helper: return true iff s1 and s2 are both NULL, or both non-NULL + * equal strings. */ +static int +opt_streq(const char *s1, const char *s2) +{ + return 0 == strcmp_opt(s1, s2); +} + +/** Check if any of the previous options have changed but aren't allowed to. */ +static int +options_transition_allowed(const or_options_t *old, + const or_options_t *new_val, + char **msg) +{ + if (!old) + return 0; + + if (!opt_streq(old->PidFile, new_val->PidFile)) { + *msg = tor_strdup("PidFile is not allowed to change."); + return -1; + } + + if (old->RunAsDaemon != new_val->RunAsDaemon) { + *msg = tor_strdup("While Tor is running, changing RunAsDaemon " + "is not allowed."); + return -1; + } + + if (strcmp(old->DataDirectory,new_val->DataDirectory)!=0) { + tor_asprintf(msg, + "While Tor is running, changing DataDirectory " + "(\"%s\"->\"%s\") is not allowed.", + old->DataDirectory, new_val->DataDirectory); + return -1; + } + + if (!opt_streq(old->User, new_val->User)) { + *msg = tor_strdup("While Tor is running, changing User is not allowed."); + return -1; + } + + if ((old->HardwareAccel != new_val->HardwareAccel) + || !opt_streq(old->AccelName, new_val->AccelName) + || !opt_streq(old->AccelDir, new_val->AccelDir)) { + *msg = tor_strdup("While Tor is running, changing OpenSSL hardware " + "acceleration engine is not allowed."); + return -1; + } + + if (old->TestingTorNetwork != new_val->TestingTorNetwork) { + *msg = tor_strdup("While Tor is running, changing TestingTorNetwork " + "is not allowed."); + return -1; + } + + if (old->DisableAllSwap != new_val->DisableAllSwap) { + *msg = tor_strdup("While Tor is running, changing DisableAllSwap " + "is not allowed."); + return -1; + } + + if (old->TokenBucketRefillInterval != new_val->TokenBucketRefillInterval) { + *msg = tor_strdup("While Tor is running, changing TokenBucketRefill" + "Interval is not allowed"); + return -1; + } + + if (old->DisableIOCP != new_val->DisableIOCP) { + *msg = tor_strdup("While Tor is running, changing DisableIOCP " + "is not allowed."); + return -1; + } + + if (old->DisableDebuggerAttachment && + !new_val->DisableDebuggerAttachment) { + *msg = tor_strdup("While Tor is running, disabling " + "DisableDebuggerAttachment is not allowed."); + return -1; + } + + return 0; +} + +/** Return 1 if any change from old_options to new_options + * will require us to rotate the CPU and DNS workers; else return 0. */ +static int +options_transition_affects_workers(const or_options_t *old_options, + const or_options_t *new_options) +{ + if (!opt_streq(old_options->DataDirectory, new_options->DataDirectory) || + old_options->NumCPUs != new_options->NumCPUs || + !config_lines_eq(old_options->ORPort_lines, new_options->ORPort_lines) || + old_options->ServerDNSSearchDomains != + new_options->ServerDNSSearchDomains || + old_options->SafeLogging_ != new_options->SafeLogging_ || + old_options->ClientOnly != new_options->ClientOnly || + public_server_mode(old_options) != public_server_mode(new_options) || + !config_lines_eq(old_options->Logs, new_options->Logs) || + old_options->LogMessageDomains != new_options->LogMessageDomains) + return 1; + + /* Check whether log options match. */ + + /* Nothing that changed matters. */ + return 0; +} + +/** Return 1 if any change from old_options to new_options + * will require us to generate a new descriptor; else return 0. */ +static int +options_transition_affects_descriptor(const or_options_t *old_options, + const or_options_t *new_options) +{ + /* XXX We can be smarter here. If your DirPort isn't being + * published and you just turned it off, no need to republish. Etc. */ + if (!opt_streq(old_options->DataDirectory, new_options->DataDirectory) || + !opt_streq(old_options->Nickname,new_options->Nickname) || + !opt_streq(old_options->Address,new_options->Address) || + !config_lines_eq(old_options->ExitPolicy,new_options->ExitPolicy) || + old_options->ExitPolicyRejectPrivate != + new_options->ExitPolicyRejectPrivate || + old_options->IPv6Exit != new_options->IPv6Exit || + !config_lines_eq(old_options->ORPort_lines, + new_options->ORPort_lines) || + !config_lines_eq(old_options->DirPort_lines, + new_options->DirPort_lines) || + old_options->ClientOnly != new_options->ClientOnly || + old_options->DisableNetwork != new_options->DisableNetwork || + old_options->PublishServerDescriptor_ != + new_options->PublishServerDescriptor_ || + get_effective_bwrate(old_options) != get_effective_bwrate(new_options) || + get_effective_bwburst(old_options) != + get_effective_bwburst(new_options) || + !opt_streq(old_options->ContactInfo, new_options->ContactInfo) || + !opt_streq(old_options->MyFamily, new_options->MyFamily) || + !opt_streq(old_options->AccountingStart, new_options->AccountingStart) || + old_options->AccountingMax != new_options->AccountingMax || + public_server_mode(old_options) != public_server_mode(new_options)) + return 1; + + return 0; +} + +#ifdef _WIN32 +/** Return the directory on windows where we expect to find our application + * data. */ +static char * +get_windows_conf_root(void) +{ + static int is_set = 0; + static char path[MAX_PATH*2+1]; + TCHAR tpath[MAX_PATH] = {0}; + + LPITEMIDLIST idl; + IMalloc *m; + HRESULT result; + + if (is_set) + return path; + + /* Find X:\documents and settings\username\application data\ . + * We would use SHGetSpecialFolder path, but that wasn't added until IE4. + */ +#ifdef ENABLE_LOCAL_APPDATA +#define APPDATA_PATH CSIDL_LOCAL_APPDATA +#else +#define APPDATA_PATH CSIDL_APPDATA +#endif + if (!SUCCEEDED(SHGetSpecialFolderLocation(NULL, APPDATA_PATH, &idl))) { + getcwd(path,MAX_PATH); + is_set = 1; + log_warn(LD_CONFIG, + "I couldn't find your application data folder: are you " + "running an ancient version of Windows 95? Defaulting to \"%s\"", + path); + return path; + } + /* Convert the path from an "ID List" (whatever that is!) to a path. */ + result = SHGetPathFromIDList(idl, tpath); +#ifdef UNICODE + wcstombs(path,tpath,sizeof(path)); + path[sizeof(path)-1] = '\0'; +#else + strlcpy(path,tpath,sizeof(path)); +#endif + + /* Now we need to free the memory that the path-idl was stored in. In + * typical Windows fashion, we can't just call 'free()' on it. */ + SHGetMalloc(&m); + if (m) { + m->lpVtbl->Free(m, idl); + m->lpVtbl->Release(m); + } + if (!SUCCEEDED(result)) { + return NULL; + } + strlcat(path,"\\tor",MAX_PATH); + is_set = 1; + return path; +} +#endif + +/** Return the default location for our torrc file (if defaults_file is + * false), or for the torrc-defaults file (if defaults_file is true). */ +static const char * +get_default_conf_file(int defaults_file) +{ +#ifdef _WIN32 + if (defaults_file) { + static char defaults_path[MAX_PATH+1]; + tor_snprintf(defaults_path, MAX_PATH, "%s\\torrc-defaults", + get_windows_conf_root()); + return defaults_path; + } else { + static char path[MAX_PATH+1]; + tor_snprintf(path, MAX_PATH, "%s\\torrc", + get_windows_conf_root()); + return path; + } +#else + return defaults_file ? CONFDIR "/torrc-defaults" : CONFDIR "/torrc"; +#endif +} + +/** Verify whether lst is a string containing valid-looking comma-separated + * nicknames, or NULL. Will normalise lst to prefix '$' to any nickname + * or fingerprint that needs it. Return 0 on success. + * Warn and return -1 on failure. + */ +static int +check_nickname_list(char **lst, const char *name, char **msg) +{ + int r = 0; + smartlist_t *sl; + int changes = 0; + + if (!*lst) + return 0; + sl = smartlist_new(); + + smartlist_split_string(sl, *lst, ",", + SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK|SPLIT_STRIP_SPACE, 0); + + SMARTLIST_FOREACH_BEGIN(sl, char *, s) + { + if (!is_legal_nickname_or_hexdigest(s)) { + // check if first char is dollar + if (s[0] != '$') { + // Try again but with a dollar symbol prepended + char *prepended; + tor_asprintf(&prepended, "$%s", s); + + if (is_legal_nickname_or_hexdigest(prepended)) { + // The nickname is valid when it's prepended, swap the current + // version with a prepended one + tor_free(s); + SMARTLIST_REPLACE_CURRENT(sl, s, prepended); + changes = 1; + continue; + } + + // Still not valid, free and fallback to error message + tor_free(prepended); + } + + tor_asprintf(msg, "Invalid nickname '%s' in %s line", s, name); + r = -1; + break; + } + } + SMARTLIST_FOREACH_END(s); + + // Replace the caller's nickname list with a fixed one + if (changes && r == 0) { + char *newNicknames = smartlist_join_strings(sl, ", ", 0, NULL); + tor_free(*lst); + *lst = newNicknames; + } + + SMARTLIST_FOREACH(sl, char *, s, tor_free(s)); + smartlist_free(sl); + + return r; +} + +/** Learn config file name from command line arguments, or use the default. + * + * If defaults_file is true, we're looking for torrc-defaults; + * otherwise, we're looking for the regular torrc_file. + * + * Set *using_default_fname to true if we're using the default + * configuration file name; or false if we've set it from the command line. + * + * Set *ignore_missing_torrc to true if we should ignore the resulting + * filename if it doesn't exist. + */ +static char * +find_torrc_filename(config_line_t *cmd_arg, + int defaults_file, + int *using_default_fname, int *ignore_missing_torrc) +{ + char *fname=NULL; + config_line_t *p_index; + const char *fname_opt = defaults_file ? "--defaults-torrc" : "-f"; + const char *ignore_opt = defaults_file ? NULL : "--ignore-missing-torrc"; + + if (defaults_file) + *ignore_missing_torrc = 1; + + for (p_index = cmd_arg; p_index; p_index = p_index->next) { + if (!strcmp(p_index->key, fname_opt)) { + if (fname) { + log_warn(LD_CONFIG, "Duplicate %s options on command line.", + fname_opt); + tor_free(fname); + } + fname = expand_filename(p_index->value); + + { + char *absfname; + absfname = make_path_absolute(fname); + tor_free(fname); + fname = absfname; + } + + *using_default_fname = 0; + } else if (ignore_opt && !strcmp(p_index->key,ignore_opt)) { + *ignore_missing_torrc = 1; + } + } + + if (*using_default_fname) { + /* didn't find one, try CONFDIR */ + const char *dflt = get_default_conf_file(defaults_file); + if (dflt && file_status(dflt) == FN_FILE) { + fname = tor_strdup(dflt); + } else { +#ifndef _WIN32 + char *fn = NULL; + if (!defaults_file) + fn = expand_filename("~/.torrc"); + if (fn && file_status(fn) == FN_FILE) { + fname = fn; + } else { + tor_free(fn); + fname = tor_strdup(dflt); + } +#else + fname = tor_strdup(dflt); +#endif + } + } + return fname; +} + +/** Load a configuration file from disk, setting torrc_fname or + * torrc_defaults_fname if successful. + * + * If defaults_file is true, load torrc-defaults; otherwise load torrc. + * + * Return the contents of the file on success, and NULL on failure. + */ +static char * +load_torrc_from_disk(config_line_t *cmd_arg, int defaults_file) +{ + char *fname=NULL; + char *cf = NULL; + int using_default_torrc = 1; + int ignore_missing_torrc = 0; + char **fname_var = defaults_file ? &torrc_defaults_fname : &torrc_fname; + + fname = find_torrc_filename(cmd_arg, defaults_file, + &using_default_torrc, &ignore_missing_torrc); + tor_assert(fname); + log_debug(LD_CONFIG, "Opening config file \"%s\"", fname); + + tor_free(*fname_var); + *fname_var = fname; + + /* Open config file */ + if (file_status(fname) != FN_FILE || + !(cf = read_file_to_str(fname,0,NULL))) { + if (using_default_torrc == 1 || ignore_missing_torrc) { + if (!defaults_file) + log_notice(LD_CONFIG, "Configuration file \"%s\" not present, " + "using reasonable defaults.", fname); + tor_free(fname); /* sets fname to NULL */ + *fname_var = NULL; + cf = tor_strdup(""); + } else { + log_warn(LD_CONFIG, + "Unable to open configuration file \"%s\".", fname); + goto err; + } + } else { + log_notice(LD_CONFIG, "Read configuration file \"%s\".", fname); + } + + return cf; + err: + tor_free(fname); + *fname_var = NULL; + return NULL; +} + +/** Read a configuration file into options, finding the configuration + * file location based on the command line. After loading the file + * call options_init_from_string() to load the config. + * Return 0 if success, -1 if failure. */ +int +options_init_from_torrc(int argc, char **argv) +{ + char *cf=NULL, *cf_defaults=NULL; + int command; + int retval = -1; + char *command_arg = NULL; + char *errmsg=NULL; + config_line_t *p_index = NULL; + config_line_t *cmdline_only_options = NULL; + + /* Go through command-line variables */ + if (! have_parsed_cmdline) { + /* Or we could redo the list every time we pass this place. + * It does not really matter */ + if (config_parse_commandline(argc, argv, 0, &global_cmdline_options, + &global_cmdline_only_options) < 0) { + goto err; + } + have_parsed_cmdline = 1; + } + cmdline_only_options = global_cmdline_only_options; + + if (config_line_find(cmdline_only_options, "-h") || + config_line_find(cmdline_only_options, "--help")) { + print_usage(); + exit(0); + } + if (config_line_find(cmdline_only_options, "--list-torrc-options")) { + /* For documenting validating whether we've documented everything. */ + list_torrc_options(); + exit(0); + } + + if (config_line_find(cmdline_only_options, "--version")) { + printf("Tor version %s.\n",get_version()); + exit(0); + } + + if (config_line_find(cmdline_only_options, "--digests")) { + printf("Tor version %s.\n",get_version()); + printf("%s", libor_get_digests()); + printf("%s", tor_get_digests()); + exit(0); + } + + if (config_line_find(cmdline_only_options, "--library-versions")) { + printf("Tor version %s. \n", get_version()); + printf("Library versions\tCompiled\t\tRuntime\n"); + printf("Libevent\t\t%-15s\t\t%s\n", + tor_libevent_get_header_version_str(), + tor_libevent_get_version_str()); + printf("OpenSSL \t\t%-15s\t\t%s\n", + crypto_openssl_get_header_version_str(), + crypto_openssl_get_version_str()); + printf("Zlib \t\t%-15s\t\t%s\n", + tor_zlib_get_header_version_str(), + tor_zlib_get_version_str()); + //TODO: Hex versions? + exit(0); + } + + command = CMD_RUN_TOR; + for (p_index = cmdline_only_options; p_index; p_index = p_index->next) { + if (!strcmp(p_index->key,"--list-fingerprint")) { + command = CMD_LIST_FINGERPRINT; + } else if (!strcmp(p_index->key, "--hash-password")) { + command = CMD_HASH_PASSWORD; + command_arg = p_index->value; + } else if (!strcmp(p_index->key, "--dump-config")) { + command = CMD_DUMP_CONFIG; + command_arg = p_index->value; + } else if (!strcmp(p_index->key, "--verify-config")) { + command = CMD_VERIFY_CONFIG; + } + } + + if (command == CMD_HASH_PASSWORD) { + cf_defaults = tor_strdup(""); + cf = tor_strdup(""); + } else { + cf_defaults = load_torrc_from_disk(cmdline_only_options, 1); + cf = load_torrc_from_disk(cmdline_only_options, 0); + if (!cf) { + if (config_line_find(cmdline_only_options, "--allow-missing-torrc")) { + cf = tor_strdup(""); + } else { + goto err; + } + } + } + + retval = options_init_from_string(cf_defaults, cf, command, command_arg, + &errmsg); + + err: + + tor_free(cf); + tor_free(cf_defaults); + if (errmsg) { + log_warn(LD_CONFIG,"%s", errmsg); + tor_free(errmsg); + } + return retval < 0 ? -1 : 0; +} + +/** Load the options from the configuration in cf, validate + * them for consistency and take actions based on them. + * + * Return 0 if success, negative on error: + * * -1 for general errors. + * * -2 for failure to parse/validate, + * * -3 for transition not allowed + * * -4 for error while setting the new options + */ +setopt_err_t +options_init_from_string(const char *cf_defaults, const char *cf, + int command, const char *command_arg, + char **msg) +{ + or_options_t *oldoptions, *newoptions, *newdefaultoptions=NULL; + config_line_t *cl; + int retval, i; + setopt_err_t err = SETOPT_ERR_MISC; + tor_assert(msg); + + oldoptions = global_options; /* get_options unfortunately asserts if + this is the first time we run*/ + + newoptions = tor_malloc_zero(sizeof(or_options_t)); + newoptions->magic_ = OR_OPTIONS_MAGIC; + options_init(newoptions); + newoptions->command = command; + newoptions->command_arg = command_arg ? tor_strdup(command_arg) : NULL; + + for (i = 0; i < 2; ++i) { + const char *body = i==0 ? cf_defaults : cf; + if (!body) + continue; + /* get config lines, assign them */ + retval = config_get_lines(body, &cl, 1); + if (retval < 0) { + err = SETOPT_ERR_PARSE; + goto err; + } + retval = config_assign(&options_format, newoptions, cl, 0, 0, msg); + config_free_lines(cl); + if (retval < 0) { + err = SETOPT_ERR_PARSE; + goto err; + } + if (i==0) + newdefaultoptions = config_dup(&options_format, newoptions); + } + + if (newdefaultoptions == NULL) { + newdefaultoptions = config_dup(&options_format, global_default_options); + } + + /* Go through command-line variables too */ + retval = config_assign(&options_format, newoptions, + global_cmdline_options, 0, 0, msg); + if (retval < 0) { + err = SETOPT_ERR_PARSE; + goto err; + } + + /* If this is a testing network configuration, change defaults + * for a list of dependent config options, re-initialize newoptions + * with the new defaults, and assign all options to it second time. */ + if (newoptions->TestingTorNetwork) { + /* XXXX this is a bit of a kludge. perhaps there's a better way to do + * this? We could, for example, make the parsing algorithm do two passes + * over the configuration. If it finds any "suite" options like + * TestingTorNetwork, it could change the defaults before its second pass. + * Not urgent so long as this seems to work, but at any sign of trouble, + * let's clean it up. -NM */ + + /* Change defaults. */ + int i; + for (i = 0; testing_tor_network_defaults[i].name; ++i) { + const config_var_t *new_var = &testing_tor_network_defaults[i]; + config_var_t *old_var = + config_find_option_mutable(&options_format, new_var->name); + tor_assert(new_var); + tor_assert(old_var); + old_var->initvalue = new_var->initvalue; + } + + /* Clear newoptions and re-initialize them with new defaults. */ + config_free(&options_format, newoptions); + config_free(&options_format, newdefaultoptions); + newdefaultoptions = NULL; + newoptions = tor_malloc_zero(sizeof(or_options_t)); + newoptions->magic_ = OR_OPTIONS_MAGIC; + options_init(newoptions); + newoptions->command = command; + newoptions->command_arg = command_arg ? tor_strdup(command_arg) : NULL; + + /* Assign all options a second time. */ + for (i = 0; i < 2; ++i) { + const char *body = i==0 ? cf_defaults : cf; + if (!body) + continue; + /* get config lines, assign them */ + retval = config_get_lines(body, &cl, 1); + if (retval < 0) { + err = SETOPT_ERR_PARSE; + goto err; + } + retval = config_assign(&options_format, newoptions, cl, 0, 0, msg); + config_free_lines(cl); + if (retval < 0) { + err = SETOPT_ERR_PARSE; + goto err; + } + if (i==0) + newdefaultoptions = config_dup(&options_format, newoptions); + } + /* Assign command-line variables a second time too */ + retval = config_assign(&options_format, newoptions, + global_cmdline_options, 0, 0, msg); + if (retval < 0) { + err = SETOPT_ERR_PARSE; + goto err; + } + } + + /* Validate newoptions */ + if (options_validate(oldoptions, newoptions, newdefaultoptions, + 0, msg) < 0) { + err = SETOPT_ERR_PARSE; /*XXX make this a separate return value.*/ + goto err; + } + + if (options_transition_allowed(oldoptions, newoptions, msg) < 0) { + err = SETOPT_ERR_TRANSITION; + goto err; + } + + if (set_options(newoptions, msg)) { + err = SETOPT_ERR_SETTING; + goto err; /* frees and replaces old options */ + } + config_free(&options_format, global_default_options); + global_default_options = newdefaultoptions; + + return SETOPT_OK; + + err: + config_free(&options_format, newoptions); + config_free(&options_format, newdefaultoptions); + if (*msg) { + char *old_msg = *msg; + tor_asprintf(msg, "Failed to parse/validate config: %s", old_msg); + tor_free(old_msg); + } + return err; +} + +/** Return the location for our configuration file. + */ +const char * +get_torrc_fname(int defaults_fname) +{ + const char *fname = defaults_fname ? torrc_defaults_fname : torrc_fname; + + if (fname) + return fname; + else + return get_default_conf_file(defaults_fname); +} + +/** Adjust the address map based on the MapAddress elements in the + * configuration options + */ +void +config_register_addressmaps(const or_options_t *options) +{ + smartlist_t *elts; + config_line_t *opt; + const char *from, *to, *msg; + + addressmap_clear_configured(); + elts = smartlist_new(); + for (opt = options->AddressMap; opt; opt = opt->next) { + smartlist_split_string(elts, opt->value, NULL, + SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 2); + if (smartlist_len(elts) < 2) { + log_warn(LD_CONFIG,"MapAddress '%s' has too few arguments. Ignoring.", + opt->value); + goto cleanup; + } + + from = smartlist_get(elts,0); + to = smartlist_get(elts,1); + + if (to[0] == '.' || from[0] == '.') { + log_warn(LD_CONFIG,"MapAddress '%s' is ambiguous - address starts with a" + "'.'. Ignoring.",opt->value); + goto cleanup; + } + + if (addressmap_register_auto(from, to, 0, ADDRMAPSRC_TORRC, &msg) < 0) { + log_warn(LD_CONFIG,"MapAddress '%s' failed: %s. Ignoring.", opt->value, + msg); + goto cleanup; + } + + if (smartlist_len(elts) > 2) + log_warn(LD_CONFIG,"Ignoring extra arguments to MapAddress."); + + cleanup: + SMARTLIST_FOREACH(elts, char*, cp, tor_free(cp)); + smartlist_clear(elts); + } + smartlist_free(elts); +} + +/** As addressmap_register(), but detect the wildcarded status of "from" and + * "to", and do not steal a reference to to. */ +/* XXXX024 move to connection_edge.c */ +int +addressmap_register_auto(const char *from, const char *to, + time_t expires, + addressmap_entry_source_t addrmap_source, + const char **msg) +{ + int from_wildcard = 0, to_wildcard = 0; + + *msg = "whoops, forgot the error message"; + if (1) { + if (!strcmp(to, "*") || !strcmp(from, "*")) { + *msg = "can't remap from or to *"; + return -1; + } + /* Detect asterisks in expressions of type: '*.example.com' */ + if (!strncmp(from,"*.",2)) { + from += 2; + from_wildcard = 1; + } + if (!strncmp(to,"*.",2)) { + to += 2; + to_wildcard = 1; + } + + if (to_wildcard && !from_wildcard) { + *msg = "can only use wildcard (i.e. '*.') if 'from' address " + "uses wildcard also"; + return -1; + } + + if (address_is_invalid_destination(to, 1)) { + *msg = "destination is invalid"; + return -1; + } + + addressmap_register(from, tor_strdup(to), expires, addrmap_source, + from_wildcard, to_wildcard); + } + return 0; +} + +/** + * Initialize the logs based on the configuration file. + */ +static int +options_init_logs(or_options_t *options, int validate_only) +{ + config_line_t *opt; + int ok; + smartlist_t *elts; + int daemon = +#ifdef _WIN32 + 0; +#else + options->RunAsDaemon; +#endif + + if (options->LogTimeGranularity <= 0) { + log_warn(LD_CONFIG, "Log time granularity '%d' has to be positive.", + options->LogTimeGranularity); + return -1; + } else if (1000 % options->LogTimeGranularity != 0 && + options->LogTimeGranularity % 1000 != 0) { + int granularity = options->LogTimeGranularity; + if (granularity < 40) { + do granularity++; + while (1000 % granularity != 0); + } else if (granularity < 1000) { + granularity = 1000 / granularity; + while (1000 % granularity != 0) + granularity--; + granularity = 1000 / granularity; + } else { + granularity = 1000 * ((granularity / 1000) + 1); + } + log_warn(LD_CONFIG, "Log time granularity '%d' has to be either a " + "divisor or a multiple of 1 second. Changing to " + "'%d'.", + options->LogTimeGranularity, granularity); + if (!validate_only) + set_log_time_granularity(granularity); + } else { + if (!validate_only) + set_log_time_granularity(options->LogTimeGranularity); + } + + ok = 1; + elts = smartlist_new(); + + for (opt = options->Logs; opt; opt = opt->next) { + log_severity_list_t *severity; + const char *cfg = opt->value; + severity = tor_malloc_zero(sizeof(log_severity_list_t)); + if (parse_log_severity_config(&cfg, severity) < 0) { + log_warn(LD_CONFIG, "Couldn't parse log levels in Log option 'Log %s'", + opt->value); + ok = 0; goto cleanup; + } + + smartlist_split_string(elts, cfg, NULL, + SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 2); + + if (smartlist_len(elts) == 0) + smartlist_add(elts, tor_strdup("stdout")); + + if (smartlist_len(elts) == 1 && + (!strcasecmp(smartlist_get(elts,0), "stdout") || + !strcasecmp(smartlist_get(elts,0), "stderr"))) { + int err = smartlist_len(elts) && + !strcasecmp(smartlist_get(elts,0), "stderr"); + if (!validate_only) { + if (daemon) { + log_warn(LD_CONFIG, + "Can't log to %s with RunAsDaemon set; skipping stdout", + err?"stderr":"stdout"); + } else { + add_stream_log(severity, err?"":"", + fileno(err?stderr:stdout)); + } + } + goto cleanup; + } + if (smartlist_len(elts) == 1 && + !strcasecmp(smartlist_get(elts,0), "syslog")) { +#ifdef HAVE_SYSLOG_H + if (!validate_only) { + add_syslog_log(severity); + } +#else + log_warn(LD_CONFIG, "Syslog is not supported on this system. Sorry."); +#endif + goto cleanup; + } + + if (smartlist_len(elts) == 2 && + !strcasecmp(smartlist_get(elts,0), "file")) { + if (!validate_only) { + char *fname = expand_filename(smartlist_get(elts, 1)); + if (add_file_log(severity, fname) < 0) { + log_warn(LD_CONFIG, "Couldn't open file for 'Log %s': %s", + opt->value, strerror(errno)); + ok = 0; + } + tor_free(fname); + } + goto cleanup; + } + + log_warn(LD_CONFIG, "Bad syntax on file Log option 'Log %s'", + opt->value); + ok = 0; goto cleanup; + + cleanup: + SMARTLIST_FOREACH(elts, char*, cp, tor_free(cp)); + smartlist_clear(elts); + tor_free(severity); + } + smartlist_free(elts); + + if (ok && !validate_only) + logs_set_domain_logging(options->LogMessageDomains); + + return ok?0:-1; +} + +/** Given a smartlist of SOCKS arguments to be passed to a transport + * proxy in args, validate them and return -1 if they are + * corrupted. Return 0 if they seem OK. */ +static int +validate_transport_socks_arguments(const smartlist_t *args) +{ + char *socks_string = NULL; + size_t socks_string_len; + + tor_assert(args); + tor_assert(smartlist_len(args) > 0); + + SMARTLIST_FOREACH_BEGIN(args, const char *, s) { + if (!string_is_key_value(LOG_WARN, s)) { /* items should be k=v items */ + log_warn(LD_CONFIG, "'%s' is not a k=v item.", s); + return -1; + } + } SMARTLIST_FOREACH_END(s); + + socks_string = pt_stringify_socks_args(args); + if (!socks_string) + return -1; + + socks_string_len = strlen(socks_string); + tor_free(socks_string); + + if (socks_string_len > MAX_SOCKS5_AUTH_SIZE_TOTAL) { + log_warn(LD_CONFIG, "SOCKS arguments can't be more than %u bytes (%lu).", + MAX_SOCKS5_AUTH_SIZE_TOTAL, + (unsigned long) socks_string_len); + return -1; + } + + return 0; +} + +/** Deallocate a bridge_line_t structure. */ +/* private */ void +bridge_line_free(bridge_line_t *bridge_line) +{ + if (!bridge_line) + return; + + if (bridge_line->socks_args) { + SMARTLIST_FOREACH(bridge_line->socks_args, char*, s, tor_free(s)); + smartlist_free(bridge_line->socks_args); + } + tor_free(bridge_line->transport_name); + tor_free(bridge_line); +} + +/** Read the contents of a Bridge line from line. Return 0 + * if the line is well-formed, and -1 if it isn't. If + * validate_only is 0, and the line is well-formed, then add + * the bridge described in the line to our internal bridge list. + * + * Bridge line format: + * Bridge [transport] IP:PORT [id-fingerprint] [k=v] [k=v] ... + */ +/* private */ bridge_line_t * +parse_bridge_line(const char *line) +{ + smartlist_t *items = NULL; + char *addrport=NULL, *fingerprint=NULL; + char *field=NULL; + bridge_line_t *bridge_line = tor_malloc_zero(sizeof(bridge_line_t)); + + items = smartlist_new(); + smartlist_split_string(items, line, NULL, + SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, -1); + if (smartlist_len(items) < 1) { + log_warn(LD_CONFIG, "Too few arguments to Bridge line."); + goto err; + } + + /* first field is either a transport name or addrport */ + field = smartlist_get(items, 0); + smartlist_del_keeporder(items, 0); + + if (string_is_C_identifier(field)) { + /* It's a transport name. */ + bridge_line->transport_name = field; + if (smartlist_len(items) < 1) { + log_warn(LD_CONFIG, "Too few items to Bridge line."); + goto err; + } + addrport = smartlist_get(items, 0); /* Next field is addrport then. */ + smartlist_del_keeporder(items, 0); + } else { + addrport = field; + } + + /* Parse addrport. */ + if (tor_addr_port_lookup(addrport, + &bridge_line->addr, &bridge_line->port)<0) { + log_warn(LD_CONFIG, "Error parsing Bridge address '%s'", addrport); + goto err; + } + if (!bridge_line->port) { + log_info(LD_CONFIG, + "Bridge address '%s' has no port; using default port 443.", + addrport); + bridge_line->port = 443; + } + + /* If transports are enabled, next field could be a fingerprint or a + socks argument. If transports are disabled, next field must be + a fingerprint. */ + if (smartlist_len(items)) { + if (bridge_line->transport_name) { /* transports enabled: */ + field = smartlist_get(items, 0); + smartlist_del_keeporder(items, 0); + + /* If it's a key=value pair, then it's a SOCKS argument for the + transport proxy... */ + if (string_is_key_value(LOG_DEBUG, field)) { + bridge_line->socks_args = smartlist_new(); + smartlist_add(bridge_line->socks_args, field); + } else { /* ...otherwise, it's the bridge fingerprint. */ + fingerprint = field; + } + + } else { /* transports disabled: */ + fingerprint = smartlist_join_strings(items, "", 0, NULL); + } + } + + /* Handle fingerprint, if it was provided. */ + if (fingerprint) { + if (strlen(fingerprint) != HEX_DIGEST_LEN) { + log_warn(LD_CONFIG, "Key digest for Bridge is wrong length."); + goto err; + } + if (base16_decode(bridge_line->digest, DIGEST_LEN, + fingerprint, HEX_DIGEST_LEN)<0) { + log_warn(LD_CONFIG, "Unable to decode Bridge key digest."); + goto err; + } + } + + /* If we are using transports, any remaining items in the smartlist + should be k=v values. */ + if (bridge_line->transport_name && smartlist_len(items)) { + if (!bridge_line->socks_args) + bridge_line->socks_args = smartlist_new(); + + /* append remaining items of 'items' to 'socks_args' */ + smartlist_add_all(bridge_line->socks_args, items); + smartlist_clear(items); + + tor_assert(smartlist_len(bridge_line->socks_args) > 0); + } + + if (bridge_line->socks_args) { + if (validate_transport_socks_arguments(bridge_line->socks_args) < 0) + goto err; + } + + goto done; + + err: + bridge_line_free(bridge_line); + bridge_line = NULL; + + done: + SMARTLIST_FOREACH(items, char*, s, tor_free(s)); + smartlist_free(items); + tor_free(addrport); + tor_free(fingerprint); + + return bridge_line; +} + +/** Read the contents of a ClientTransportPlugin line from + * line. Return 0 if the line is well-formed, and -1 if it + * isn't. + * + * If validate_only is 0, the line is well-formed, and the + * transport is needed by some bridge: + * - If it's an external proxy line, add the transport described in the line to + * our internal transport list. + * - If it's a managed proxy line, launch the managed proxy. */ +static int +parse_client_transport_line(const char *line, int validate_only) +{ + smartlist_t *items = NULL; + int r; + char *field2=NULL; + + const char *transports=NULL; + smartlist_t *transport_list=NULL; + char *addrport=NULL; + tor_addr_t addr; + uint16_t port = 0; + int socks_ver=PROXY_NONE; + + /* managed proxy options */ + int is_managed=0; + char **proxy_argv=NULL; + char **tmp=NULL; + int proxy_argc, i; + int is_useless_proxy=1; + + int line_length; + + items = smartlist_new(); + smartlist_split_string(items, line, NULL, + SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, -1); + + line_length = smartlist_len(items); + if (line_length < 3) { + log_warn(LD_CONFIG, "Too few arguments on ClientTransportPlugin line."); + goto err; + } + + /* Get the first line element, split it to commas into + transport_list (in case it's multiple transports) and validate + the transport names. */ + transports = smartlist_get(items, 0); + transport_list = smartlist_new(); + smartlist_split_string(transport_list, transports, ",", + SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); + SMARTLIST_FOREACH_BEGIN(transport_list, const char *, transport_name) { + /* validate transport names */ + if (!string_is_C_identifier(transport_name)) { + log_warn(LD_CONFIG, "Transport name is not a C identifier (%s).", + transport_name); + goto err; + } + + /* see if we actually need the transports provided by this proxy */ + if (!validate_only && transport_is_needed(transport_name)) + is_useless_proxy = 0; + } SMARTLIST_FOREACH_END(transport_name); + + /* field2 is either a SOCKS version or "exec" */ + field2 = smartlist_get(items, 1); + + if (!strcmp(field2,"socks4")) { + socks_ver = PROXY_SOCKS4; + } else if (!strcmp(field2,"socks5")) { + socks_ver = PROXY_SOCKS5; + } else if (!strcmp(field2,"exec")) { + is_managed=1; + } else { + log_warn(LD_CONFIG, "Strange ClientTransportPlugin field '%s'.", + field2); + goto err; + } + + if (is_managed) { /* managed */ + if (!validate_only && is_useless_proxy) { + log_warn(LD_GENERAL, "Pluggable transport proxy (%s) does not provide " + "any needed transports and will not be launched.", line); + } + + /* If we are not just validating, use the rest of the line as the + argv of the proxy to be launched. Also, make sure that we are + only launching proxies that contribute useful transports. */ + if (!validate_only && !is_useless_proxy) { + proxy_argc = line_length-2; + tor_assert(proxy_argc > 0); + proxy_argv = tor_malloc_zero(sizeof(char*)*(proxy_argc+1)); + tmp = proxy_argv; + for (i=0;iline, return its + * string. Return NULL if the line was not + * well-formed. + * + * If transport is set, return NULL if the line is not + * referring to transport. + * + * The returned string is allocated on the heap and it's the + * responsibility of the caller to free it. */ +static char * +get_bindaddr_from_transport_listen_line(const char *line,const char *transport) +{ + smartlist_t *items = NULL; + const char *parsed_transport = NULL; + char *addrport = NULL; + tor_addr_t addr; + uint16_t port = 0; + + items = smartlist_new(); + smartlist_split_string(items, line, NULL, + SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, -1); + + if (smartlist_len(items) < 2) { + log_warn(LD_CONFIG,"Too few arguments on ServerTransportListenAddr line."); + goto err; + } + + parsed_transport = smartlist_get(items, 0); + addrport = tor_strdup(smartlist_get(items, 1)); + + /* If 'transport' is given, check if it matches the one on the line */ + if (transport && strcmp(transport, parsed_transport)) + goto err; + + /* Validate addrport */ + if (tor_addr_port_parse(LOG_WARN, addrport, &addr, &port)<0) { + log_warn(LD_CONFIG, "Error parsing ServerTransportListenAddr " + "address '%s'", addrport); + goto err; + } + + goto done; + + err: + tor_free(addrport); + addrport = NULL; + + done: + SMARTLIST_FOREACH(items, char*, s, tor_free(s)); + smartlist_free(items); + + return addrport; +} + +/** Given a ServerTransportOptions line, return a smartlist + * with the options. Return NULL if the line was not well-formed. + * + * If transport is set, return NULL if the line is not + * referring to transport. + * + * The returned smartlist and its strings are allocated on the heap + * and it's the responsibility of the caller to free it. */ +smartlist_t * +get_options_from_transport_options_line(const char *line,const char *transport) +{ + smartlist_t *items = smartlist_new(); + smartlist_t *options = smartlist_new(); + const char *parsed_transport = NULL; + + smartlist_split_string(items, line, NULL, + SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, -1); + + if (smartlist_len(items) < 2) { + log_warn(LD_CONFIG,"Too few arguments on ServerTransportOptions line."); + goto err; + } + + parsed_transport = smartlist_get(items, 0); + /* If 'transport' is given, check if it matches the one on the line */ + if (transport && strcmp(transport, parsed_transport)) + goto err; + + SMARTLIST_FOREACH_BEGIN(items, const char *, option) { + if (option_sl_idx == 0) /* skip the transport field (first field)*/ + continue; + + /* validate that it's a k=v value */ + if (!string_is_key_value(LOG_WARN, option)) { + log_warn(LD_CONFIG, "%s is not a k=v value.", escaped(option)); + goto err; + } + + /* add it to the options smartlist */ + smartlist_add(options, tor_strdup(option)); + log_debug(LD_CONFIG, "Added %s to the list of options", escaped(option)); + } SMARTLIST_FOREACH_END(option); + + goto done; + + err: + SMARTLIST_FOREACH(options, char*, s, tor_free(s)); + smartlist_free(options); + options = NULL; + + done: + SMARTLIST_FOREACH(items, char*, s, tor_free(s)); + smartlist_free(items); + + return options; +} + +/** Given the name of a pluggable transport in transport, check + * the configuration file to see if the user has explicitly asked for + * it to listen on a specific port. Return a string if + * so, otherwise NULL. */ +char * +get_transport_bindaddr_from_config(const char *transport) +{ + config_line_t *cl; + const or_options_t *options = get_options(); + + for (cl = options->ServerTransportListenAddr; cl; cl = cl->next) { + char *bindaddr = + get_bindaddr_from_transport_listen_line(cl->value, transport); + if (bindaddr) + return bindaddr; + } + + return NULL; +} + +/** Given the name of a pluggable transport in transport, check + * the configuration file to see if the user has asked us to pass any + * parameters to the pluggable transport. Return a smartlist + * containing the parameters, otherwise NULL. */ +smartlist_t * +get_options_for_server_transport(const char *transport) +{ + config_line_t *cl; + const or_options_t *options = get_options(); + + for (cl = options->ServerTransportOptions; cl; cl = cl->next) { + smartlist_t *options_sl = + get_options_from_transport_options_line(cl->value, transport); + if (options_sl) + return options_sl; + } + + return NULL; +} + +/** Read the contents of a ServerTransportPlugin line from + * line. Return 0 if the line is well-formed, and -1 if it + * isn't. + * If validate_only is 0, the line is well-formed, and it's a + * managed proxy line, launch the managed proxy. */ +static int +parse_server_transport_line(const char *line, int validate_only) +{ + smartlist_t *items = NULL; + int r; + const char *transports=NULL; + smartlist_t *transport_list=NULL; + char *type=NULL; + char *addrport=NULL; + tor_addr_t addr; + uint16_t port = 0; + + /* managed proxy options */ + int is_managed=0; + char **proxy_argv=NULL; + char **tmp=NULL; + int proxy_argc,i; + + int line_length; + + items = smartlist_new(); + smartlist_split_string(items, line, NULL, + SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, -1); + + line_length = smartlist_len(items); + if (line_length < 3) { + log_warn(LD_CONFIG, "Too few arguments on ServerTransportPlugin line."); + goto err; + } + + /* Get the first line element, split it to commas into + transport_list (in case it's multiple transports) and validate + the transport names. */ + transports = smartlist_get(items, 0); + transport_list = smartlist_new(); + smartlist_split_string(transport_list, transports, ",", + SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); + SMARTLIST_FOREACH_BEGIN(transport_list, const char *, transport_name) { + if (!string_is_C_identifier(transport_name)) { + log_warn(LD_CONFIG, "Transport name is not a C identifier (%s).", + transport_name); + goto err; + } + } SMARTLIST_FOREACH_END(transport_name); + + type = smartlist_get(items, 1); + + if (!strcmp(type, "exec")) { + is_managed=1; + } else if (!strcmp(type, "proxy")) { + is_managed=0; + } else { + log_warn(LD_CONFIG, "Strange ServerTransportPlugin type '%s'", type); + goto err; + } + + if (is_managed) { /* managed */ + if (!validate_only) { + proxy_argc = line_length-2; + tor_assert(proxy_argc > 0); + proxy_argv = tor_malloc_zero(sizeof(char*)*(proxy_argc+1)); + tmp = proxy_argv; + + for (i=0;iline. If + * validate_only is 0, and the line is well-formed, and it + * shares any bits with required_type or required_type + * is 0, then add the dirserver described in the line (minus whatever + * bits it's missing) as a valid authority. Return 0 on success, + * or -1 if the line isn't well-formed or if we can't add it. */ +static int +parse_dir_authority_line(const char *line, dirinfo_type_t required_type, + int validate_only) +{ + smartlist_t *items = NULL; + int r; + char *addrport=NULL, *address=NULL, *nickname=NULL, *fingerprint=NULL; + uint16_t dir_port = 0, or_port = 0; + char digest[DIGEST_LEN]; + char v3_digest[DIGEST_LEN]; + dirinfo_type_t type = 0; + int is_not_hidserv_authority = 0; + double weight = 1.0; + + items = smartlist_new(); + smartlist_split_string(items, line, NULL, + SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, -1); + if (smartlist_len(items) < 1) { + log_warn(LD_CONFIG, "No arguments on DirAuthority line."); + goto err; + } + + if (is_legal_nickname(smartlist_get(items, 0))) { + nickname = smartlist_get(items, 0); + smartlist_del_keeporder(items, 0); + } + + while (smartlist_len(items)) { + char *flag = smartlist_get(items, 0); + if (TOR_ISDIGIT(flag[0])) + break; + if (!strcasecmp(flag, "v1")) { + type |= (V1_DIRINFO | HIDSERV_DIRINFO); + } else if (!strcasecmp(flag, "hs")) { + type |= HIDSERV_DIRINFO; + } else if (!strcasecmp(flag, "no-hs")) { + is_not_hidserv_authority = 1; + } else if (!strcasecmp(flag, "bridge")) { + type |= BRIDGE_DIRINFO; + } else if (!strcasecmp(flag, "no-v2")) { + /* obsolete, but may still be contained in DirAuthority lines generated + by various tools */; + } else if (!strcasecmpstart(flag, "orport=")) { + int ok; + char *portstring = flag + strlen("orport="); + or_port = (uint16_t) tor_parse_long(portstring, 10, 1, 65535, &ok, NULL); + if (!ok) + log_warn(LD_CONFIG, "Invalid orport '%s' on DirAuthority line.", + portstring); + } else if (!strcmpstart(flag, "weight=")) { + int ok; + const char *wstring = flag + strlen("weight="); + weight = tor_parse_double(wstring, 0, UINT64_MAX, &ok, NULL); + if (!ok) { + log_warn(LD_CONFIG, "Invalid weight '%s' on DirAuthority line.",flag); + weight=1.0; + } + } else if (!strcasecmpstart(flag, "v3ident=")) { + char *idstr = flag + strlen("v3ident="); + if (strlen(idstr) != HEX_DIGEST_LEN || + base16_decode(v3_digest, DIGEST_LEN, idstr, HEX_DIGEST_LEN)<0) { + log_warn(LD_CONFIG, "Bad v3 identity digest '%s' on DirAuthority line", + flag); + } else { + type |= V3_DIRINFO|EXTRAINFO_DIRINFO|MICRODESC_DIRINFO; + } + } else { + log_warn(LD_CONFIG, "Unrecognized flag '%s' on DirAuthority line", + flag); + } + tor_free(flag); + smartlist_del_keeporder(items, 0); + } + if (is_not_hidserv_authority) + type &= ~HIDSERV_DIRINFO; + + if (smartlist_len(items) < 2) { + log_warn(LD_CONFIG, "Too few arguments to DirAuthority line."); + goto err; + } + addrport = smartlist_get(items, 0); + smartlist_del_keeporder(items, 0); + if (addr_port_lookup(LOG_WARN, addrport, &address, NULL, &dir_port)<0) { + log_warn(LD_CONFIG, "Error parsing DirAuthority address '%s'", addrport); + goto err; + } + if (!dir_port) { + log_warn(LD_CONFIG, "Missing port in DirAuthority address '%s'",addrport); + goto err; + } + + fingerprint = smartlist_join_strings(items, "", 0, NULL); + if (strlen(fingerprint) != HEX_DIGEST_LEN) { + log_warn(LD_CONFIG, "Key digest '%s' for DirAuthority is wrong length %d.", + fingerprint, (int)strlen(fingerprint)); + goto err; + } + if (!strcmp(fingerprint, "E623F7625FBE0C87820F11EC5F6D5377ED816294")) { + /* a known bad fingerprint. refuse to use it. We can remove this + * clause once Tor 0.1.2.17 is obsolete. */ + log_warn(LD_CONFIG, "Dangerous dirserver line. To correct, erase your " + "torrc file (%s), or reinstall Tor and use the default torrc.", + get_torrc_fname(0)); + goto err; + } + if (base16_decode(digest, DIGEST_LEN, fingerprint, HEX_DIGEST_LEN)<0) { + log_warn(LD_CONFIG, "Unable to decode DirAuthority key digest."); + goto err; + } + + if (!validate_only && (!required_type || required_type & type)) { + dir_server_t *ds; + if (required_type) + type &= required_type; /* pare down what we think of them as an + * authority for. */ + log_debug(LD_DIR, "Trusted %d dirserver at %s:%d (%s)", (int)type, + address, (int)dir_port, (char*)smartlist_get(items,0)); + if (!(ds = trusted_dir_server_new(nickname, address, dir_port, or_port, + digest, v3_digest, type, weight))) + goto err; + dir_server_add(ds); + } + + r = 0; + goto done; + + err: + r = -1; + + done: + SMARTLIST_FOREACH(items, char*, s, tor_free(s)); + smartlist_free(items); + tor_free(addrport); + tor_free(address); + tor_free(nickname); + tor_free(fingerprint); + return r; +} + +/** Read the contents of a FallbackDir line from line. If + * validate_only is 0, and the line is well-formed, then add the + * dirserver described in the line as a fallback directory. Return 0 on + * success, or -1 if the line isn't well-formed or if we can't add it. */ +static int +parse_dir_fallback_line(const char *line, + int validate_only) +{ + int r = -1; + smartlist_t *items = smartlist_new(), *positional = smartlist_new(); + int orport = -1; + uint16_t dirport; + tor_addr_t addr; + int ok; + char id[DIGEST_LEN]; + char *address=NULL; + double weight=1.0; + + memset(id, 0, sizeof(id)); + smartlist_split_string(items, line, NULL, + SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, -1); + SMARTLIST_FOREACH_BEGIN(items, const char *, cp) { + const char *eq = strchr(cp, '='); + ok = 1; + if (! eq) { + smartlist_add(positional, (char*)cp); + continue; + } + if (!strcmpstart(cp, "orport=")) { + orport = (int)tor_parse_long(cp+strlen("orport="), 10, + 1, 65535, &ok, NULL); + } else if (!strcmpstart(cp, "id=")) { + ok = !base16_decode(id, DIGEST_LEN, + cp+strlen("id="), strlen(cp)-strlen("id=")); + } else if (!strcmpstart(cp, "weight=")) { + int ok; + const char *wstring = cp + strlen("weight="); + weight = tor_parse_double(wstring, 0, UINT64_MAX, &ok, NULL); + if (!ok) { + log_warn(LD_CONFIG, "Invalid weight '%s' on FallbackDir line.", cp); + weight=1.0; + } + } + + if (!ok) { + log_warn(LD_CONFIG, "Bad FallbackDir option %s", escaped(cp)); + goto end; + } + } SMARTLIST_FOREACH_END(cp); + + if (smartlist_len(positional) != 1) { + log_warn(LD_CONFIG, "Couldn't parse FallbackDir line %s", escaped(line)); + goto end; + } + + if (tor_digest_is_zero(id)) { + log_warn(LD_CONFIG, "Missing identity on FallbackDir line"); + goto end; + } + + if (orport <= 0) { + log_warn(LD_CONFIG, "Missing orport on FallbackDir line"); + goto end; + } + + if (tor_addr_port_split(LOG_INFO, smartlist_get(positional, 0), + &address, &dirport) < 0 || + tor_addr_parse(&addr, address)<0) { + log_warn(LD_CONFIG, "Couldn't parse address:port %s on FallbackDir line", + (const char*)smartlist_get(positional, 0)); + goto end; + } + + if (!validate_only) { + dir_server_t *ds; + ds = fallback_dir_server_new(&addr, dirport, orport, id, weight); + if (!ds) { + log_warn(LD_CONFIG, "Couldn't create FallbackDir %s", escaped(line)); + goto end; + } + dir_server_add(ds); + } + + r = 0; + + end: + SMARTLIST_FOREACH(items, char *, cp, tor_free(cp)); + smartlist_free(items); + smartlist_free(positional); + tor_free(address); + return r; +} + +/** Allocate and return a new port_cfg_t with reasonable defaults. */ +static port_cfg_t * +port_cfg_new(void) +{ + port_cfg_t *cfg = tor_malloc_zero(sizeof(port_cfg_t)); + cfg->ipv4_traffic = 1; + cfg->cache_ipv4_answers = 1; + cfg->prefer_ipv6_virtaddr = 1; + return cfg; +} + +/** Free all storage held in port */ +static void +port_cfg_free(port_cfg_t *port) +{ + tor_free(port); +} + +/** Warn for every port in ports of type listener_type that is + * on a publicly routable address. */ +static void +warn_nonlocal_client_ports(const smartlist_t *ports, const char *portname, + int listener_type) +{ + SMARTLIST_FOREACH_BEGIN(ports, const port_cfg_t *, port) { + if (port->type != listener_type) + continue; + if (port->is_unix_addr) { + /* Unix sockets aren't accessible over a network. */ + } else if (!tor_addr_is_internal(&port->addr, 1)) { + log_warn(LD_CONFIG, "You specified a public address '%s' for %sPort. " + "Other people on the Internet might find your computer and " + "use it as an open proxy. Please don't allow this unless you " + "have a good reason.", + fmt_addrport(&port->addr, port->port), portname); + } else if (!tor_addr_is_loopback(&port->addr)) { + log_notice(LD_CONFIG, "You configured a non-loopback address '%s' " + "for %sPort. This allows everybody on your local network to " + "use your machine as a proxy. Make sure this is what you " + "wanted.", + fmt_addrport(&port->addr, port->port), portname); + } + } SMARTLIST_FOREACH_END(port); +} + +/** Warn for every Extended ORPort port in ports that is on a + * publicly routable address. */ +static void +warn_nonlocal_ext_orports(const smartlist_t *ports, const char *portname) +{ + SMARTLIST_FOREACH_BEGIN(ports, const port_cfg_t *, port) { + if (port->type != CONN_TYPE_EXT_OR_LISTENER) + continue; + if (port->is_unix_addr) + continue; + /* XXX maybe warn even if address is RFC1918? */ + if (!tor_addr_is_internal(&port->addr, 1)) { + log_warn(LD_CONFIG, "You specified a public address '%s' for %sPort. " + "This is not advised; this address is supposed to only be " + "exposed on localhost so that your pluggable transport " + "proxies can connect to it.", + fmt_addrport(&port->addr, port->port), portname); + } + } SMARTLIST_FOREACH_END(port); +} + +/** Given a list of port_cfg_t in ports, warn any controller port there + * is listening on any non-loopback address. If forbid is true, + * then emit a stronger warning and remove the port from the list. + */ +static void +warn_nonlocal_controller_ports(smartlist_t *ports, unsigned forbid) +{ + int warned = 0; + SMARTLIST_FOREACH_BEGIN(ports, port_cfg_t *, port) { + if (port->type != CONN_TYPE_CONTROL_LISTENER) + continue; + if (port->is_unix_addr) + continue; + if (!tor_addr_is_loopback(&port->addr)) { + if (forbid) { + if (!warned) + log_warn(LD_CONFIG, + "You have a ControlPort set to accept " + "unauthenticated connections from a non-local address. " + "This means that programs not running on your computer " + "can reconfigure your Tor, without even having to guess a " + "password. That's so bad that I'm closing your ControlPort " + "for you. If you need to control your Tor remotely, try " + "enabling authentication and using a tool like stunnel or " + "ssh to encrypt remote access."); + warned = 1; + port_cfg_free(port); + SMARTLIST_DEL_CURRENT(ports, port); + } else { + log_warn(LD_CONFIG, "You have a ControlPort set to accept " + "connections from a non-local address. This means that " + "programs not running on your computer can reconfigure your " + "Tor. That's pretty bad, since the controller " + "protocol isn't encrypted! Maybe you should just listen on " + "127.0.0.1 and use a tool like stunnel or ssh to encrypt " + "remote connections to your control port."); + return; /* No point in checking the rest */ + } + } + } SMARTLIST_FOREACH_END(port); +} + +#define CL_PORT_NO_OPTIONS (1u<<0) +#define CL_PORT_WARN_NONLOCAL (1u<<1) +#define CL_PORT_ALLOW_EXTRA_LISTENADDR (1u<<2) +#define CL_PORT_SERVER_OPTIONS (1u<<3) +#define CL_PORT_FORBID_NONLOCAL (1u<<4) +#define CL_PORT_TAKES_HOSTNAMES (1u<<5) + +/** + * Parse port configuration for a single port type. + * + * Read entries of the "FooPort" type from the list ports, and + * entries of the "FooListenAddress" type from the list + * listenaddrs. Two syntaxes are supported: a legacy syntax + * where FooPort is at most a single entry containing a port number and + * where FooListenAddress has any number of address:port combinations; + * and a new syntax where there are no FooListenAddress entries and + * where FooPort can have any number of entries of the format + * "[Address:][Port] IsolationOptions". + * + * In log messages, describe the port type as portname. + * + * If no address is specified, default to defaultaddr. If no + * FooPort is given, default to defaultport (if 0, there is no default). + * + * If CL_PORT_NO_OPTIONS is set in flags, do not allow stream + * isolation options in the FooPort entries. + * + * If CL_PORT_WARN_NONLOCAL is set in flags, warn if any of the + * ports are not on a local address. If CL_PORT_FORBID_NONLOCAL is set, + * this is a contrl port with no password set: don't even allow it. + * + * Unless CL_PORT_ALLOW_EXTRA_LISTENADDR is set in flags, warn + * if FooListenAddress is set but FooPort is 0. + * + * If CL_PORT_SERVER_OPTIONS is set in flags, do not allow stream + * isolation options in the FooPort entries; instead allow the + * server-port option set. + * + * If CL_PORT_TAKES_HOSTNAMES is set in flags, allow the options + * {No,}IPv{4,6}Traffic. + * + * On success, if out is given, add a new port_cfg_t entry to + * out for every port that the client should listen on. Return 0 + * on success, -1 on failure. + */ +static int +parse_port_config(smartlist_t *out, + const config_line_t *ports, + const config_line_t *listenaddrs, + const char *portname, + int listener_type, + const char *defaultaddr, + int defaultport, + unsigned flags) +{ + smartlist_t *elts; + int retval = -1; + const unsigned is_control = (listener_type == CONN_TYPE_CONTROL_LISTENER); + const unsigned is_ext_orport = (listener_type == CONN_TYPE_EXT_OR_LISTENER); + const unsigned allow_no_options = flags & CL_PORT_NO_OPTIONS; + const unsigned use_server_options = flags & CL_PORT_SERVER_OPTIONS; + const unsigned warn_nonlocal = flags & CL_PORT_WARN_NONLOCAL; + const unsigned forbid_nonlocal = flags & CL_PORT_FORBID_NONLOCAL; + const unsigned allow_spurious_listenaddr = + flags & CL_PORT_ALLOW_EXTRA_LISTENADDR; + const unsigned takes_hostnames = flags & CL_PORT_TAKES_HOSTNAMES; + int got_zero_port=0, got_nonzero_port=0; + + /* FooListenAddress is deprecated; let's make it work like it used to work, + * though. */ + if (listenaddrs) { + int mainport = defaultport; + + if (ports && ports->next) { + log_warn(LD_CONFIG, "%sListenAddress can't be used when there are " + "multiple %sPort lines", portname, portname); + return -1; + } else if (ports) { + if (!strcmp(ports->value, "auto")) { + mainport = CFG_AUTO_PORT; + } else { + int ok; + mainport = (int)tor_parse_long(ports->value, 10, 0, 65535, &ok, NULL); + if (!ok) { + log_warn(LD_CONFIG, "%sListenAddress can only be used with a single " + "%sPort with value \"auto\" or 1-65535 and no options set.", + portname, portname); + return -1; + } + } + } + + if (mainport == 0) { + if (allow_spurious_listenaddr) + return 1; /*DOCDOC*/ + log_warn(LD_CONFIG, "%sPort must be defined if %sListenAddress is used", + portname, portname); + return -1; + } + + if (use_server_options && out) { + /* Add a no_listen port. */ + port_cfg_t *cfg = port_cfg_new(); + cfg->type = listener_type; + cfg->port = mainport; + tor_addr_make_unspec(&cfg->addr); /* Server ports default to 0.0.0.0 */ + cfg->no_listen = 1; + cfg->bind_ipv4_only = 1; + cfg->ipv4_traffic = 1; + cfg->prefer_ipv6_virtaddr = 1; + smartlist_add(out, cfg); + } + + for (; listenaddrs; listenaddrs = listenaddrs->next) { + tor_addr_t addr; + uint16_t port = 0; + if (tor_addr_port_lookup(listenaddrs->value, &addr, &port) < 0) { + log_warn(LD_CONFIG, "Unable to parse %sListenAddress '%s'", + portname, listenaddrs->value); + return -1; + } + if (out) { + port_cfg_t *cfg = port_cfg_new(); + cfg->type = listener_type; + cfg->port = port ? port : mainport; + tor_addr_copy(&cfg->addr, &addr); + cfg->session_group = SESSION_GROUP_UNSET; + cfg->isolation_flags = ISO_DEFAULT; + cfg->no_advertise = 1; + smartlist_add(out, cfg); + } + } + + if (warn_nonlocal && out) { + if (is_control) + warn_nonlocal_controller_ports(out, forbid_nonlocal); + else if (is_ext_orport) + warn_nonlocal_ext_orports(out, portname); + else + warn_nonlocal_client_ports(out, portname, listener_type); + } + return 0; + } /* end if (listenaddrs) */ + + /* No ListenAddress lines. If there's no FooPort, then maybe make a default + * one. */ + if (! ports) { + if (defaultport && out) { + port_cfg_t *cfg = port_cfg_new(); + cfg->type = listener_type; + cfg->port = defaultport; + tor_addr_parse(&cfg->addr, defaultaddr); + cfg->session_group = SESSION_GROUP_UNSET; + cfg->isolation_flags = ISO_DEFAULT; + smartlist_add(out, cfg); + } + return 0; + } + + /* At last we can actually parse the FooPort lines. The syntax is: + * [Addr:](Port|auto) [Options].*/ + elts = smartlist_new(); + + for (; ports; ports = ports->next) { + tor_addr_t addr; + int port; + int sessiongroup = SESSION_GROUP_UNSET; + unsigned isolation = ISO_DEFAULT; + int prefer_no_auth = 0; + + char *addrport; + uint16_t ptmp=0; + int ok; + int no_listen = 0, no_advertise = 0, all_addrs = 0, + bind_ipv4_only = 0, bind_ipv6_only = 0, + ipv4_traffic = 1, ipv6_traffic = 0, prefer_ipv6 = 0, + cache_ipv4 = 1, use_cached_ipv4 = 0, + cache_ipv6 = 0, use_cached_ipv6 = 0, + prefer_ipv6_automap = 1; + + smartlist_split_string(elts, ports->value, NULL, + SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); + if (smartlist_len(elts) == 0) { + log_warn(LD_CONFIG, "Invalid %sPort line with no value", portname); + goto err; + } + + if (allow_no_options && smartlist_len(elts) > 1) { + log_warn(LD_CONFIG, "Too many options on %sPort line", portname); + goto err; + } + + /* Now parse the addr/port value */ + addrport = smartlist_get(elts, 0); + if (!strcmp(addrport, "auto")) { + port = CFG_AUTO_PORT; + tor_addr_parse(&addr, defaultaddr); + } else if (!strcasecmpend(addrport, ":auto")) { + char *addrtmp = tor_strndup(addrport, strlen(addrport)-5); + port = CFG_AUTO_PORT; + if (tor_addr_port_lookup(addrtmp, &addr, &ptmp)<0 || ptmp) { + log_warn(LD_CONFIG, "Invalid address '%s' for %sPort", + escaped(addrport), portname); + tor_free(addrtmp); + goto err; + } + } else { + /* Try parsing integer port before address, because, who knows? + "19099" might be a valid address. */ + port = (int) tor_parse_long(addrport, 10, 0, 65535, &ok, NULL); + if (ok) { + tor_addr_parse(&addr, defaultaddr); + } else if (tor_addr_port_lookup(addrport, &addr, &ptmp) == 0) { + if (ptmp == 0) { + log_warn(LD_CONFIG, "%sPort line has address but no port", portname); + goto err; + } + port = ptmp; + } else { + log_warn(LD_CONFIG, "Couldn't parse address '%s' for %sPort", + escaped(addrport), portname); + goto err; + } + } + + /* Now parse the rest of the options, if any. */ + if (use_server_options) { + /* This is a server port; parse advertising options */ + SMARTLIST_FOREACH_BEGIN(elts, char *, elt) { + if (elt_sl_idx == 0) + continue; /* Skip addr:port */ + + if (!strcasecmp(elt, "NoAdvertise")) { + no_advertise = 1; + } else if (!strcasecmp(elt, "NoListen")) { + no_listen = 1; +#if 0 + /* not implemented yet. */ + } else if (!strcasecmp(elt, "AllAddrs")) { + + all_addrs = 1; +#endif + } else if (!strcasecmp(elt, "IPv4Only")) { + bind_ipv4_only = 1; + } else if (!strcasecmp(elt, "IPv6Only")) { + bind_ipv6_only = 1; + } else { + log_warn(LD_CONFIG, "Unrecognized %sPort option '%s'", + portname, escaped(elt)); + } + } SMARTLIST_FOREACH_END(elt); + + if (no_advertise && no_listen) { + log_warn(LD_CONFIG, "Tried to set both NoListen and NoAdvertise " + "on %sPort line '%s'", + portname, escaped(ports->value)); + goto err; + } + if (bind_ipv4_only && bind_ipv6_only) { + log_warn(LD_CONFIG, "Tried to set both IPv4Only and IPv6Only " + "on %sPort line '%s'", + portname, escaped(ports->value)); + goto err; + } + if (bind_ipv4_only && tor_addr_family(&addr) == AF_INET6) { + log_warn(LD_CONFIG, "Could not interpret %sPort address as IPv6", + portname); + goto err; + } + if (bind_ipv6_only && tor_addr_family(&addr) == AF_INET) { + log_warn(LD_CONFIG, "Could not interpret %sPort address as IPv4", + portname); + goto err; + } + } else { + /* This is a client port; parse isolation options */ + SMARTLIST_FOREACH_BEGIN(elts, char *, elt) { + int no = 0, isoflag = 0; + const char *elt_orig = elt; + if (elt_sl_idx == 0) + continue; /* Skip addr:port */ + if (!strcasecmpstart(elt, "SessionGroup=")) { + int group = (int)tor_parse_long(elt+strlen("SessionGroup="), + 10, 0, INT_MAX, &ok, NULL); + if (!ok) { + log_warn(LD_CONFIG, "Invalid %sPort option '%s'", + portname, escaped(elt)); + goto err; + } + if (sessiongroup >= 0) { + log_warn(LD_CONFIG, "Multiple SessionGroup options on %sPort", + portname); + goto err; + } + sessiongroup = group; + continue; + } + + if (!strcasecmpstart(elt, "No")) { + no = 1; + elt += 2; + } + + if (takes_hostnames) { + if (!strcasecmp(elt, "IPv4Traffic")) { + ipv4_traffic = ! no; + continue; + } else if (!strcasecmp(elt, "IPv6Traffic")) { + ipv6_traffic = ! no; + continue; + } else if (!strcasecmp(elt, "PreferIPv6")) { + prefer_ipv6 = ! no; + continue; + } + } + if (!strcasecmp(elt, "CacheIPv4DNS")) { + cache_ipv4 = ! no; + continue; + } else if (!strcasecmp(elt, "CacheIPv6DNS")) { + cache_ipv6 = ! no; + continue; + } else if (!strcasecmp(elt, "CacheDNS")) { + cache_ipv4 = cache_ipv6 = ! no; + continue; + } else if (!strcasecmp(elt, "UseIPv4Cache")) { + use_cached_ipv4 = ! no; + continue; + } else if (!strcasecmp(elt, "UseIPv6Cache")) { + use_cached_ipv6 = ! no; + continue; + } else if (!strcasecmp(elt, "UseDNSCache")) { + use_cached_ipv4 = use_cached_ipv6 = ! no; + continue; + } else if (!strcasecmp(elt, "PreferIPv6Automap")) { + prefer_ipv6_automap = ! no; + continue; + } else if (!strcasecmp(elt, "PreferSOCKSNoAuth")) { + prefer_no_auth = ! no; + continue; + } + + if (!strcasecmpend(elt, "s")) + elt[strlen(elt)-1] = '\0'; /* kill plurals. */ + + if (!strcasecmp(elt, "IsolateDestPort")) { + isoflag = ISO_DESTPORT; + } else if (!strcasecmp(elt, "IsolateDestAddr")) { + isoflag = ISO_DESTADDR; + } else if (!strcasecmp(elt, "IsolateSOCKSAuth")) { + isoflag = ISO_SOCKSAUTH; + } else if (!strcasecmp(elt, "IsolateClientProtocol")) { + isoflag = ISO_CLIENTPROTO; + } else if (!strcasecmp(elt, "IsolateClientAddr")) { + isoflag = ISO_CLIENTADDR; + } else { + log_warn(LD_CONFIG, "Unrecognized %sPort option '%s'", + portname, escaped(elt_orig)); + } + + if (no) { + isolation &= ~isoflag; + } else { + isolation |= isoflag; + } + } SMARTLIST_FOREACH_END(elt); + } + + if (port) + got_nonzero_port = 1; + else + got_zero_port = 1; + + if (ipv4_traffic == 0 && ipv6_traffic == 0) { + log_warn(LD_CONFIG, "You have a %sPort entry with both IPv4 and " + "IPv6 disabled; that won't work.", portname); + goto err; + } + + if (out && port) { + port_cfg_t *cfg = port_cfg_new(); + tor_addr_copy(&cfg->addr, &addr); + cfg->port = port; + cfg->type = listener_type; + cfg->isolation_flags = isolation; + cfg->session_group = sessiongroup; + cfg->no_advertise = no_advertise; + cfg->no_listen = no_listen; + cfg->all_addrs = all_addrs; + cfg->bind_ipv4_only = bind_ipv4_only; + cfg->bind_ipv6_only = bind_ipv6_only; + cfg->ipv4_traffic = ipv4_traffic; + cfg->ipv6_traffic = ipv6_traffic; + cfg->prefer_ipv6 = prefer_ipv6; + cfg->cache_ipv4_answers = cache_ipv4; + cfg->cache_ipv6_answers = cache_ipv6; + cfg->use_cached_ipv4_answers = use_cached_ipv4; + cfg->use_cached_ipv6_answers = use_cached_ipv6; + cfg->prefer_ipv6_virtaddr = prefer_ipv6_automap; + cfg->socks_prefer_no_auth = prefer_no_auth; + if (! (isolation & ISO_SOCKSAUTH)) + cfg->socks_prefer_no_auth = 1; + + smartlist_add(out, cfg); + } + SMARTLIST_FOREACH(elts, char *, cp, tor_free(cp)); + smartlist_clear(elts); + } + + if (warn_nonlocal && out) { + if (is_control) + warn_nonlocal_controller_ports(out, forbid_nonlocal); + else if (is_ext_orport) + warn_nonlocal_ext_orports(out, portname); + else + warn_nonlocal_client_ports(out, portname, listener_type); + } + + if (got_zero_port && got_nonzero_port) { + log_warn(LD_CONFIG, "You specified a nonzero %sPort along with '%sPort 0' " + "in the same configuration. Did you mean to disable %sPort or " + "not?", portname, portname, portname); + goto err; + } + + retval = 0; + err: + SMARTLIST_FOREACH(elts, char *, cp, tor_free(cp)); + smartlist_free(elts); + return retval; +} + +/** Parse a list of config_line_t for an AF_UNIX unix socket listener option + * from cfg and add them to out. No fancy options are + * supported: the line contains nothing but the path to the AF_UNIX socket. */ +static int +parse_unix_socket_config(smartlist_t *out, const config_line_t *cfg, + int listener_type) +{ + + if (!out) + return 0; + + for ( ; cfg; cfg = cfg->next) { + size_t len = strlen(cfg->value); + port_cfg_t *port = tor_malloc_zero(sizeof(port_cfg_t) + len + 1); + port->is_unix_addr = 1; + memcpy(port->unix_addr, cfg->value, len+1); + port->type = listener_type; + smartlist_add(out, port); + } + + return 0; +} + +/** Return the number of ports which are actually going to listen with type + * listenertype. Do not count no_listen ports. Do not count unix + * sockets. */ +static int +count_real_listeners(const smartlist_t *ports, int listenertype) +{ + int n = 0; + SMARTLIST_FOREACH_BEGIN(ports, port_cfg_t *, port) { + if (port->no_listen || port->is_unix_addr) + continue; + if (port->type != listenertype) + continue; + ++n; + } SMARTLIST_FOREACH_END(port); + return n; +} + +/** Parse all client port types (Socks, DNS, Trans, NATD) from + * options. On success, set *n_ports_out to the number + * of ports that are listed, update the *Port_set values in + * options, and return 0. On failure, set *msg to a + * description of the problem and return -1. + * + * If validate_only is false, set configured_client_ports to the + * new list of ports parsed from options. + **/ +static int +parse_ports(or_options_t *options, int validate_only, + char **msg, int *n_ports_out) +{ + smartlist_t *ports; + int retval = -1; + + ports = smartlist_new(); + + *n_ports_out = 0; + + if (parse_port_config(ports, + options->SocksPort_lines, options->SocksListenAddress, + "Socks", CONN_TYPE_AP_LISTENER, + "127.0.0.1", 19099, + CL_PORT_WARN_NONLOCAL|CL_PORT_ALLOW_EXTRA_LISTENADDR| + CL_PORT_TAKES_HOSTNAMES) < 0) { + *msg = tor_strdup("Invalid SocksPort/SocksListenAddress configuration"); + goto err; + } + if (parse_port_config(ports, + options->DNSPort_lines, options->DNSListenAddress, + "DNS", CONN_TYPE_AP_DNS_LISTENER, + "127.0.0.1", 0, + CL_PORT_WARN_NONLOCAL|CL_PORT_TAKES_HOSTNAMES) < 0) { + *msg = tor_strdup("Invalid DNSPort/DNSListenAddress configuration"); + goto err; + } + if (parse_port_config(ports, + options->TransPort_lines, options->TransListenAddress, + "Trans", CONN_TYPE_AP_TRANS_LISTENER, + "127.0.0.1", 0, + CL_PORT_WARN_NONLOCAL) < 0) { + *msg = tor_strdup("Invalid TransPort/TransListenAddress configuration"); + goto err; + } + if (parse_port_config(ports, + options->NATDPort_lines, options->NATDListenAddress, + "NATD", CONN_TYPE_AP_NATD_LISTENER, + "127.0.0.1", 0, + CL_PORT_WARN_NONLOCAL) < 0) { + *msg = tor_strdup("Invalid NatdPort/NatdListenAddress configuration"); + goto err; + } + { + unsigned control_port_flags = CL_PORT_NO_OPTIONS | CL_PORT_WARN_NONLOCAL; + const int any_passwords = (options->HashedControlPassword || + options->HashedControlSessionPassword || + options->CookieAuthentication); + if (! any_passwords) + control_port_flags |= CL_PORT_FORBID_NONLOCAL; + + if (parse_port_config(ports, + options->ControlPort_lines, + options->ControlListenAddress, + "Control", CONN_TYPE_CONTROL_LISTENER, + "127.0.0.1", 0, + control_port_flags) < 0) { + *msg = tor_strdup("Invalid ControlPort/ControlListenAddress " + "configuration"); + goto err; + } + if (parse_unix_socket_config(ports, + options->ControlSocket, + CONN_TYPE_CONTROL_LISTENER) < 0) { + *msg = tor_strdup("Invalid ControlSocket configuration"); + goto err; + } + } + if (! options->ClientOnly) { + if (parse_port_config(ports, + options->ORPort_lines, options->ORListenAddress, + "OR", CONN_TYPE_OR_LISTENER, + "0.0.0.0", 0, + CL_PORT_SERVER_OPTIONS) < 0) { + *msg = tor_strdup("Invalid ORPort/ORListenAddress configuration"); + goto err; + } + if (parse_port_config(ports, + options->ExtORPort_lines, NULL, + "ExtOR", CONN_TYPE_EXT_OR_LISTENER, + "127.0.0.1", 0, + CL_PORT_SERVER_OPTIONS|CL_PORT_WARN_NONLOCAL) < 0) { + *msg = tor_strdup("Invalid ExtORPort configuration"); + goto err; + } + if (parse_port_config(ports, + options->DirPort_lines, options->DirListenAddress, + "Dir", CONN_TYPE_DIR_LISTENER, + "0.0.0.0", 0, + CL_PORT_SERVER_OPTIONS) < 0) { + *msg = tor_strdup("Invalid DirPort/DirListenAddress configuration"); + goto err; + } + } + + if (check_server_ports(ports, options) < 0) { + *msg = tor_strdup("Misconfigured server ports"); + goto err; + } + + *n_ports_out = smartlist_len(ports); + + retval = 0; + + /* Update the *Port_set options. The !! here is to force a boolean out of + an integer. */ + options->ORPort_set = + !! count_real_listeners(ports, CONN_TYPE_OR_LISTENER); + options->SocksPort_set = + !! count_real_listeners(ports, CONN_TYPE_AP_LISTENER); + options->TransPort_set = + !! count_real_listeners(ports, CONN_TYPE_AP_TRANS_LISTENER); + options->NATDPort_set = + !! count_real_listeners(ports, CONN_TYPE_AP_NATD_LISTENER); + options->ControlPort_set = + !! count_real_listeners(ports, CONN_TYPE_CONTROL_LISTENER); + options->DirPort_set = + !! count_real_listeners(ports, CONN_TYPE_DIR_LISTENER); + options->DNSPort_set = + !! count_real_listeners(ports, CONN_TYPE_AP_DNS_LISTENER); + options->ExtORPort_set = + !! count_real_listeners(ports, CONN_TYPE_EXT_OR_LISTENER); + + if (!validate_only) { + if (configured_ports) { + SMARTLIST_FOREACH(configured_ports, + port_cfg_t *, p, port_cfg_free(p)); + smartlist_free(configured_ports); + } + configured_ports = ports; + ports = NULL; /* prevent free below. */ + } + + err: + if (ports) { + SMARTLIST_FOREACH(ports, port_cfg_t *, p, port_cfg_free(p)); + smartlist_free(ports); + } + return retval; +} + +/** Given a list of port_cfg_t in ports, check them for internal + * consistency and warn as appropriate. */ +static int +check_server_ports(const smartlist_t *ports, + const or_options_t *options) +{ + int n_orport_advertised = 0; + int n_orport_advertised_ipv4 = 0; + int n_orport_listeners = 0; + int n_dirport_advertised = 0; + int n_dirport_listeners = 0; + int n_low_port = 0; + int r = 0; + + SMARTLIST_FOREACH_BEGIN(ports, const port_cfg_t *, port) { + if (port->type == CONN_TYPE_DIR_LISTENER) { + if (! port->no_advertise) + ++n_dirport_advertised; + if (! port->no_listen) + ++n_dirport_listeners; + } else if (port->type == CONN_TYPE_OR_LISTENER) { + if (! port->no_advertise) { + ++n_orport_advertised; + if (tor_addr_family(&port->addr) == AF_INET || + (tor_addr_family(&port->addr) == AF_UNSPEC && + !port->bind_ipv6_only)) + ++n_orport_advertised_ipv4; + } + if (! port->no_listen) + ++n_orport_listeners; + } else { + continue; + } +#ifndef _WIN32 + if (!port->no_listen && port->port < 1024) + ++n_low_port; +#endif + } SMARTLIST_FOREACH_END(port); + + if (n_orport_advertised && !n_orport_listeners) { + log_warn(LD_CONFIG, "We are advertising an ORPort, but not actually " + "listening on one."); + r = -1; + } + if (n_orport_listeners && !n_orport_advertised) { + log_warn(LD_CONFIG, "We are listening on an ORPort, but not advertising " + "any ORPorts. This will keep us from building a %s " + "descriptor, and make us impossible to use.", + options->BridgeRelay ? "bridge" : "router"); + r = -1; + } + if (n_dirport_advertised && !n_dirport_listeners) { + log_warn(LD_CONFIG, "We are advertising a DirPort, but not actually " + "listening on one."); + r = -1; + } + if (n_dirport_advertised > 1) { + log_warn(LD_CONFIG, "Can't advertise more than one DirPort."); + r = -1; + } + if (n_orport_advertised && !n_orport_advertised_ipv4 && + !options->BridgeRelay) { + log_warn(LD_CONFIG, "Configured non-bridge only to listen on an IPv6 " + "address."); + r = -1; + } + + if (n_low_port && options->AccountingMax) { + log_warn(LD_CONFIG, + "You have set AccountingMax to use hibernation. You have also " + "chosen a low DirPort or OrPort. This combination can make Tor stop " + "working when it tries to re-attach the port after a period of " + "hibernation. Please choose a different port or turn off " + "hibernation unless you know this combination will work on your " + "platform."); + } + + return r; +} + +/** Return a list of port_cfg_t for client ports parsed from the + * options. */ +const smartlist_t * +get_configured_ports(void) +{ + if (!configured_ports) + configured_ports = smartlist_new(); + return configured_ports; +} + +/** Return an address:port string representation of the address + * where the first listener_type listener waits for + * connections. Return NULL if we couldn't find a listener. The + * string is allocated on the heap and it's the responsibility of the + * caller to free it after use. + * + * This function is meant to be used by the pluggable transport proxy + * spawning code, please make sure that it fits your purposes before + * using it. */ +char * +get_first_listener_addrport_string(int listener_type) +{ + static const char *ipv4_localhost = "127.0.0.1"; + static const char *ipv6_localhost = "[::1]"; + const char *address; + uint16_t port; + char *string = NULL; + + if (!configured_ports) + return NULL; + + SMARTLIST_FOREACH_BEGIN(configured_ports, const port_cfg_t *, cfg) { + if (cfg->no_listen) + continue; + + if (cfg->type == listener_type && + tor_addr_family(&cfg->addr) != AF_UNSPEC) { + + /* We found the first listener of the type we are interested in! */ + + /* If a listener is listening on INADDR_ANY, assume that it's + also listening on 127.0.0.1, and point the transport proxy + there: */ + if (tor_addr_is_null(&cfg->addr)) + address = tor_addr_is_v4(&cfg->addr) ? ipv4_localhost : ipv6_localhost; + else + address = fmt_and_decorate_addr(&cfg->addr); + + /* If a listener is configured with port 'auto', we are forced + to iterate all listener connections and find out in which + port it ended up listening: */ + if (cfg->port == CFG_AUTO_PORT) { + port = router_get_active_listener_port_by_type_af(listener_type, + tor_addr_family(&cfg->addr)); + if (!port) + return NULL; + } else { + port = cfg->port; + } + + tor_asprintf(&string, "%s:%u", address, port); + + return string; + } + + } SMARTLIST_FOREACH_END(cfg); + + return NULL; +} + +/** Return the first advertised port of type listener_type in + address_family. */ +int +get_first_advertised_port_by_type_af(int listener_type, int address_family) +{ + if (!configured_ports) + return 0; + SMARTLIST_FOREACH_BEGIN(configured_ports, const port_cfg_t *, cfg) { + if (cfg->type == listener_type && + !cfg->no_advertise && + (tor_addr_family(&cfg->addr) == address_family || + tor_addr_family(&cfg->addr) == AF_UNSPEC)) { + if (tor_addr_family(&cfg->addr) != AF_UNSPEC || + (address_family == AF_INET && !cfg->bind_ipv6_only) || + (address_family == AF_INET6 && !cfg->bind_ipv4_only)) { + return cfg->port; + } + } + } SMARTLIST_FOREACH_END(cfg); + return 0; +} + +/** Adjust the value of options->DataDirectory, or fill it in if it's + * absent. Return 0 on success, -1 on failure. */ +static int +normalize_data_directory(or_options_t *options) +{ + char *p; + if (options->DataDirectory) + return 0; /* all set */ +#ifdef _WIN32 + p = tor_malloc(MAX_PATH); + strlcpy(p,anonymize_tor_data_directory(),MAX_PATH); +#else + p = tor_malloc(PATH_MAX); + strlcpy(p,anonymize_tor_data_directory(),PATH_MAX); +#endif + options->DataDirectory = p; + return 0; +} + +/** Check and normalize the value of options->DataDirectory; return 0 if it + * is sane, -1 otherwise. */ +static int +validate_data_directory(or_options_t *options) +{ + if (normalize_data_directory(options) < 0) + return -1; + tor_assert(options->DataDirectory); + if (strlen(options->DataDirectory) > (512-128)) { + log_warn(LD_CONFIG, "DataDirectory is too long."); + return -1; + } + return 0; +} + +/** This string must remain the same forevermore. It is how we + * recognize that the torrc file doesn't need to be backed up. */ +#define GENERATED_FILE_PREFIX "# This file was generated by Tor; " \ + "if you edit it, comments will not be preserved" +/** This string can change; it tries to give the reader an idea + * that editing this file by hand is not a good plan. */ +#define GENERATED_FILE_COMMENT "# The old torrc file was renamed " \ + "to torrc.orig.1 or similar, and Tor will ignore it" + +/** Save a configuration file for the configuration in options + * into the file fname. If the file already exists, and + * doesn't begin with GENERATED_FILE_PREFIX, rename it. Otherwise + * replace it. Return 0 on success, -1 on failure. */ +static int +write_configuration_file(const char *fname, const or_options_t *options) +{ + char *old_val=NULL, *new_val=NULL, *new_conf=NULL; + int rename_old = 0, r; + + tor_assert(fname); + + switch (file_status(fname)) { + case FN_FILE: + old_val = read_file_to_str(fname, 0, NULL); + if (!old_val || strcmpstart(old_val, GENERATED_FILE_PREFIX)) { + rename_old = 1; + } + tor_free(old_val); + break; + case FN_NOENT: + break; + case FN_ERROR: + case FN_DIR: + default: + log_warn(LD_CONFIG, + "Config file \"%s\" is not a file? Failing.", fname); + return -1; + } + + if (!(new_conf = options_dump(options, OPTIONS_DUMP_MINIMAL))) { + log_warn(LD_BUG, "Couldn't get configuration string"); + goto err; + } + + tor_asprintf(&new_val, "%s\n%s\n\n%s", + GENERATED_FILE_PREFIX, GENERATED_FILE_COMMENT, new_conf); + + if (rename_old) { + int i = 1; + char *fn_tmp = NULL; + while (1) { + tor_asprintf(&fn_tmp, "%s.orig.%d", fname, i); + if (file_status(fn_tmp) == FN_NOENT) + break; + tor_free(fn_tmp); + ++i; + } + log_notice(LD_CONFIG, "Renaming old configuration file to \"%s\"", fn_tmp); + if (rename(fname, fn_tmp) < 0) { + log_warn(LD_FS, + "Couldn't rename configuration file \"%s\" to \"%s\": %s", + fname, fn_tmp, strerror(errno)); + tor_free(fn_tmp); + goto err; + } + tor_free(fn_tmp); + } + + if (write_str_to_file(fname, new_val, 0) < 0) + goto err; + + r = 0; + goto done; + err: + r = -1; + done: + tor_free(new_val); + tor_free(new_conf); + return r; +} + +/** + * Save the current configuration file value to disk. Return 0 on + * success, -1 on failure. + **/ +int +options_save_current(void) +{ + /* This fails if we can't write to our configuration file. + * + * If we try falling back to datadirectory or something, we have a better + * chance of saving the configuration, but a better chance of doing + * something the user never expected. */ + return write_configuration_file(get_torrc_fname(0), get_options()); +} + +/** Return the number of cpus configured in options. If we are + * told to auto-detect the number of cpus, return the auto-detected number. */ +int +get_num_cpus(const or_options_t *options) +{ + if (options->NumCPUs == 0) { + int n = compute_num_cpus(); + return (n >= 1) ? n : 1; + } else { + return options->NumCPUs; + } +} + +/** + * Initialize the libevent library. + */ +static void +init_libevent(const or_options_t *options) +{ + const char *badness=NULL; + tor_libevent_cfg cfg; + + tor_assert(options); + + configure_libevent_logging(); + /* If the kernel complains that some method (say, epoll) doesn't + * exist, we don't care about it, since libevent will cope. + */ + suppress_libevent_log_msg("Function not implemented"); + + tor_check_libevent_header_compatibility(); + + memset(&cfg, 0, sizeof(cfg)); + cfg.disable_iocp = options->DisableIOCP; + cfg.num_cpus = get_num_cpus(options); + cfg.msec_per_tick = options->TokenBucketRefillInterval; + + tor_libevent_initialize(&cfg); + + suppress_libevent_log_msg(NULL); + + tor_check_libevent_version(tor_libevent_get_method(), + server_mode(get_options()), + &badness); + if (badness) { + const char *v = tor_libevent_get_version_str(); + const char *m = tor_libevent_get_method(); + control_event_general_status(LOG_WARN, + "BAD_LIBEVENT VERSION=%s METHOD=%s BADNESS=%s RECOVERED=NO", + v, m, badness); + } +} + +/** Return a newly allocated string holding a filename relative to the data + * directory. If sub1 is present, it is the first path component after + * the data directory. If sub2 is also present, it is the second path + * component after the data directory. If suffix is present, it + * is appended to the filename. + * + * Examples: + * get_datadir_fname2_suffix("a", NULL, NULL) -> $DATADIR/a + * get_datadir_fname2_suffix("a", NULL, ".tmp") -> $DATADIR/a.tmp + * get_datadir_fname2_suffix("a", "b", ".tmp") -> $DATADIR/a/b/.tmp + * get_datadir_fname2_suffix("a", "b", NULL) -> $DATADIR/a/b + * + * Note: Consider using the get_datadir_fname* macros in or.h. + */ +char * +options_get_datadir_fname2_suffix(const or_options_t *options, + const char *sub1, const char *sub2, + const char *suffix) +{ + char *fname = NULL; + size_t len; + tor_assert(options); + tor_assert(options->DataDirectory); + tor_assert(sub1 || !sub2); /* If sub2 is present, sub1 must be present. */ + len = strlen(options->DataDirectory); + if (sub1) { + len += strlen(sub1)+1; + if (sub2) + len += strlen(sub2)+1; + } + if (suffix) + len += strlen(suffix); + len++; + fname = tor_malloc(len); + if (sub1) { + if (sub2) { + tor_snprintf(fname, len, "%s"PATH_SEPARATOR"%s"PATH_SEPARATOR"%s", + options->DataDirectory, sub1, sub2); + } else { + tor_snprintf(fname, len, "%s"PATH_SEPARATOR"%s", + options->DataDirectory, sub1); + } + } else { + strlcpy(fname, options->DataDirectory, len); + } + if (suffix) + strlcat(fname, suffix, len); + return fname; +} + +/** Check wether the data directory has a private subdirectory + * subdir. If not, try to create it. Return 0 on success, + * -1 otherwise. */ +int +check_or_create_data_subdir(const char *subdir) +{ + char *statsdir = get_datadir_fname(subdir); + int return_val = 0; + + if (check_private_dir(statsdir, CPD_CREATE, get_options()->User) < 0) { + log_warn(LD_HIST, "Unable to create %s/ directory!", subdir); + return_val = -1; + } + tor_free(statsdir); + return return_val; +} + +/** Create a file named fname with contents str in the + * subdirectory subdir of the data directory. descr + * should be a short description of the file's content and will be + * used for the warning message, if it's present and the write process + * fails. Return 0 on success, -1 otherwise.*/ +int +write_to_data_subdir(const char* subdir, const char* fname, + const char* str, const char* descr) +{ + char *filename = get_datadir_fname2(subdir, fname); + int return_val = 0; + + if (write_str_to_file(filename, str, 0) < 0) { + log_warn(LD_HIST, "Unable to write %s to disk!", descr ? descr : fname); + return_val = -1; + } + tor_free(filename); + return return_val; +} + +/** Given a file name check to see whether the file exists but has not been + * modified for a very long time. If so, remove it. */ +void +remove_file_if_very_old(const char *fname, time_t now) +{ +#define VERY_OLD_FILE_AGE (28*24*60*60) + struct stat st; + + if (stat(sandbox_intern_string(fname), &st)==0 && + st.st_mtime < now-VERY_OLD_FILE_AGE) { + char buf[ISO_TIME_LEN+1]; + format_local_iso_time(buf, st.st_mtime); + log_notice(LD_GENERAL, "Obsolete file %s hasn't been modified since %s. " + "Removing it.", fname, buf); + unlink(fname); + } +} + +/** Return a smartlist of ports that must be forwarded by + * tor-fw-helper. The smartlist contains the ports in a string format + * that is understandable by tor-fw-helper. */ +smartlist_t * +get_list_of_ports_to_forward(void) +{ + smartlist_t *ports_to_forward = smartlist_new(); + int port = 0; + + /** XXX TODO tor-fw-helper does not support forwarding ports to + other hosts than the local one. If the user is binding to a + different IP address, tor-fw-helper won't work. */ + port = router_get_advertised_or_port(get_options()); /* Get ORPort */ + if (port) + smartlist_add_asprintf(ports_to_forward, "%d:%d", port, port); + + port = router_get_advertised_dir_port(get_options(), 0); /* Get DirPort */ + if (port) + smartlist_add_asprintf(ports_to_forward, "%d:%d", port, port); + + /* Get ports of transport proxies */ + { + smartlist_t *transport_ports = get_transport_proxy_ports(); + if (transport_ports) { + smartlist_add_all(ports_to_forward, transport_ports); + smartlist_free(transport_ports); + } + } + + if (!smartlist_len(ports_to_forward)) { + smartlist_free(ports_to_forward); + ports_to_forward = NULL; + } + + return ports_to_forward; +} + +/** Helper to implement GETINFO functions about configuration variables (not + * their values). Given a "config/names" question, set *answer to a + * new string describing the supported configuration variables and their + * types. */ +int +getinfo_helper_config(control_connection_t *conn, + const char *question, char **answer, + const char **errmsg) +{ + (void) conn; + (void) errmsg; + if (!strcmp(question, "config/names")) { + smartlist_t *sl = smartlist_new(); + int i; + for (i = 0; option_vars_[i].name; ++i) { + const config_var_t *var = &option_vars_[i]; + const char *type; + /* don't tell controller about triple-underscore options */ + if (!strncmp(option_vars_[i].name, "___", 3)) + continue; + switch (var->type) { + case CONFIG_TYPE_STRING: type = "String"; break; + case CONFIG_TYPE_FILENAME: type = "Filename"; break; + case CONFIG_TYPE_UINT: type = "Integer"; break; + case CONFIG_TYPE_INT: type = "SignedInteger"; break; + case CONFIG_TYPE_PORT: type = "Port"; break; + case CONFIG_TYPE_INTERVAL: type = "TimeInterval"; break; + case CONFIG_TYPE_MSEC_INTERVAL: type = "TimeMsecInterval"; break; + case CONFIG_TYPE_MEMUNIT: type = "DataSize"; break; + case CONFIG_TYPE_DOUBLE: type = "Float"; break; + case CONFIG_TYPE_BOOL: type = "Boolean"; break; + case CONFIG_TYPE_AUTOBOOL: type = "Boolean+Auto"; break; + case CONFIG_TYPE_ISOTIME: type = "Time"; break; + case CONFIG_TYPE_ROUTERSET: type = "RouterList"; break; + case CONFIG_TYPE_CSV: type = "CommaList"; break; + case CONFIG_TYPE_CSV_INTERVAL: type = "TimeIntervalCommaList"; break; + case CONFIG_TYPE_LINELIST: type = "LineList"; break; + case CONFIG_TYPE_LINELIST_S: type = "Dependant"; break; + case CONFIG_TYPE_LINELIST_V: type = "Virtual"; break; + default: + case CONFIG_TYPE_OBSOLETE: + type = NULL; break; + } + if (!type) + continue; + smartlist_add_asprintf(sl, "%s %s\n",var->name,type); + } + *answer = smartlist_join_strings(sl, "", 0, NULL); + SMARTLIST_FOREACH(sl, char *, c, tor_free(c)); + smartlist_free(sl); + } else if (!strcmp(question, "config/defaults")) { + smartlist_t *sl = smartlist_new(); + int i; + for (i = 0; option_vars_[i].name; ++i) { + const config_var_t *var = &option_vars_[i]; + if (var->initvalue != NULL) { + char *val = esc_for_log(var->initvalue); + smartlist_add_asprintf(sl, "%s %s\n",var->name,val); + tor_free(val); + } + } + *answer = smartlist_join_strings(sl, "", 0, NULL); + SMARTLIST_FOREACH(sl, char *, c, tor_free(c)); + smartlist_free(sl); + } + return 0; +} + +/** Parse outbound bind address option lines. If validate_only + * is not 0 update OutboundBindAddressIPv4_ and + * OutboundBindAddressIPv6_ in options. On failure, set + * msg (if provided) to a newly allocated string containing a + * description of the problem and return -1. */ +static int +parse_outbound_addresses(or_options_t *options, int validate_only, char **msg) +{ + const config_line_t *lines = options->OutboundBindAddress; + int found_v4 = 0, found_v6 = 0; + + if (!validate_only) { + memset(&options->OutboundBindAddressIPv4_, 0, + sizeof(options->OutboundBindAddressIPv4_)); + memset(&options->OutboundBindAddressIPv6_, 0, + sizeof(options->OutboundBindAddressIPv6_)); + } + while (lines) { + tor_addr_t addr, *dst_addr = NULL; + int af = tor_addr_parse(&addr, lines->value); + switch (af) { + case AF_INET: + if (found_v4) { + if (msg) + tor_asprintf(msg, "Multiple IPv4 outbound bind addresses " + "configured: %s", lines->value); + return -1; + } + found_v4 = 1; + dst_addr = &options->OutboundBindAddressIPv4_; + break; + case AF_INET6: + if (found_v6) { + if (msg) + tor_asprintf(msg, "Multiple IPv6 outbound bind addresses " + "configured: %s", lines->value); + return -1; + } + found_v6 = 1; + dst_addr = &options->OutboundBindAddressIPv6_; + break; + default: + if (msg) + tor_asprintf(msg, "Outbound bind address '%s' didn't parse.", + lines->value); + return -1; + } + if (!validate_only) + tor_addr_copy(dst_addr, &addr); + lines = lines->next; + } + return 0; +} + +/** Load one of the geoip files, family determining which + * one. default_fname is used if on Windows and + * fname equals "". */ +static void +config_load_geoip_file_(sa_family_t family, + const char *fname, + const char *default_fname) +{ +#ifdef _WIN32 + char *free_fname = NULL; /* Used to hold any temporary-allocated value */ + /* XXXX Don't use this "" junk; make our filename options + * understand prefixes somehow. -NM */ + if (!strcmp(fname, "")) { + const char *conf_root = get_windows_conf_root(); + tor_asprintf(&free_fname, "%s\\%s", conf_root, default_fname); + fname = free_fname; + } + geoip_load_file(family, fname); + tor_free(free_fname); +#else + (void)default_fname; + geoip_load_file(family, fname); +#endif +} + +/** Load geoip files for IPv4 and IPv6 if options and + * old_options indicate we should. */ +static void +config_maybe_load_geoip_files_(const or_options_t *options, + const or_options_t *old_options) +{ + /* XXXX024 Reload GeoIPFile on SIGHUP. -NM */ + + if (options->GeoIPFile && + ((!old_options || !opt_streq(old_options->GeoIPFile, + options->GeoIPFile)) + || !geoip_is_loaded(AF_INET))) + config_load_geoip_file_(AF_INET, options->GeoIPFile, "geoip"); + if (options->GeoIPv6File && + ((!old_options || !opt_streq(old_options->GeoIPv6File, + options->GeoIPv6File)) + || !geoip_is_loaded(AF_INET6))) + config_load_geoip_file_(AF_INET6, options->GeoIPv6File, "geoip6"); +} + +/** Initialize cookie authentication (used so far by the ControlPort + * and Extended ORPort). + * + * Allocate memory and create a cookie (of length cookie_len) + * in cookie_out. + * Then write it down to fname and prepend it with header. + * + * If the whole procedure was successful, set + * cookie_is_set_out to True. */ +int +init_cookie_authentication(const char *fname, const char *header, + int cookie_len, + uint8_t **cookie_out, int *cookie_is_set_out) +{ + char cookie_file_str_len = strlen(header) + cookie_len; + char *cookie_file_str = tor_malloc(cookie_file_str_len); + int retval = -1; + + /* We don't want to generate a new cookie every time we call + * options_act(). One should be enough. */ + if (*cookie_is_set_out) { + retval = 0; /* we are all set */ + goto done; + } + + /* If we've already set the cookie, free it before re-setting + it. This can happen if we previously generated a cookie, but + couldn't write it to a disk. */ + if (*cookie_out) + tor_free(*cookie_out); + + /* Generate the cookie */ + *cookie_out = tor_malloc(cookie_len); + if (crypto_rand((char *)*cookie_out, cookie_len) < 0) + goto done; + + /* Create the string that should be written on the file. */ + memcpy(cookie_file_str, header, strlen(header)); + memcpy(cookie_file_str+strlen(header), *cookie_out, cookie_len); + if (write_bytes_to_file(fname, cookie_file_str, cookie_file_str_len, 1)) { + log_warn(LD_FS,"Error writing auth cookie to %s.", escaped(fname)); + goto done; + } + + /* Success! */ + log_info(LD_GENERAL, "Generated auth cookie file in '%s'.", escaped(fname)); + *cookie_is_set_out = 1; + retval = 0; + + done: + memwipe(cookie_file_str, 0, cookie_file_str_len); + tor_free(cookie_file_str); + return retval; +} + diff --git a/src/tor/config.h b/src/tor/config.h new file mode 100644 index 0000000..8ee2a45 --- /dev/null +++ b/src/tor/config.h @@ -0,0 +1,144 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file config.h + * \brief Header file for config.c. + **/ + +#ifndef TOR_CONFIG_H +#define TOR_CONFIG_H + +const char *get_dirportfrontpage(void); +const or_options_t *get_options(void); +or_options_t *get_options_mutable(void); +int set_options(or_options_t *new_val, char **msg); +void config_free_all(void); +const char *safe_str_client(const char *address); +const char *safe_str(const char *address); +const char *escaped_safe_str_client(const char *address); +const char *escaped_safe_str(const char *address); +const char *get_version(void); +const char *get_short_version(void); +setopt_err_t options_trial_assign(config_line_t *list, int use_defaults, + int clear_first, char **msg); + +uint32_t get_last_resolved_addr(void); +int resolve_my_address(int warn_severity, const or_options_t *options, + uint32_t *addr_out, + const char **method_out, char **hostname_out); +int is_local_addr(const tor_addr_t *addr); +void options_init(or_options_t *options); + +#define OPTIONS_DUMP_MINIMAL 1 +#define OPTIONS_DUMP_DEFAULTS 2 +#define OPTIONS_DUMP_ALL 3 +char *options_dump(const or_options_t *options, int how_to_dump); +int options_init_from_torrc(int argc, char **argv); +setopt_err_t options_init_from_string(const char *cf_defaults, const char *cf, + int command, const char *command_arg, char **msg); +int option_is_recognized(const char *key); +const char *option_get_canonical_name(const char *key); +config_line_t *option_get_assignment(const or_options_t *options, + const char *key); +int options_save_current(void); +const char *get_torrc_fname(int defaults_fname); +char *options_get_datadir_fname2_suffix(const or_options_t *options, + const char *sub1, const char *sub2, + const char *suffix); +#define get_datadir_fname2_suffix(sub1, sub2, suffix) \ + options_get_datadir_fname2_suffix(get_options(), (sub1), (sub2), (suffix)) +/** Return a newly allocated string containing datadir/sub1. See + * get_datadir_fname2_suffix. */ +#define get_datadir_fname(sub1) get_datadir_fname2_suffix((sub1), NULL, NULL) +/** Return a newly allocated string containing datadir/sub1/sub2. See + * get_datadir_fname2_suffix. */ +#define get_datadir_fname2(sub1,sub2) \ + get_datadir_fname2_suffix((sub1), (sub2), NULL) +/** Return a newly allocated string containing datadir/sub1suffix. See + * get_datadir_fname2_suffix. */ +#define get_datadir_fname_suffix(sub1, suffix) \ + get_datadir_fname2_suffix((sub1), NULL, (suffix)) + +int check_or_create_data_subdir(const char *subdir); +int write_to_data_subdir(const char* subdir, const char* fname, + const char* str, const char* descr); + +int get_num_cpus(const or_options_t *options); + +const smartlist_t *get_configured_ports(void); +int get_first_advertised_port_by_type_af(int listener_type, + int address_family); +#define get_primary_or_port() \ + (get_first_advertised_port_by_type_af(CONN_TYPE_OR_LISTENER, AF_INET)) +#define get_primary_dir_port() \ + (get_first_advertised_port_by_type_af(CONN_TYPE_DIR_LISTENER, AF_INET)) + +char *get_first_listener_addrport_string(int listener_type); + +int options_need_geoip_info(const or_options_t *options, + const char **reason_out); + +smartlist_t *get_list_of_ports_to_forward(void); + +int getinfo_helper_config(control_connection_t *conn, + const char *question, char **answer, + const char **errmsg); + +const char *tor_get_digests(void); +uint32_t get_effective_bwrate(const or_options_t *options); +uint32_t get_effective_bwburst(const or_options_t *options); + +char *get_transport_bindaddr_from_config(const char *transport); + +int init_cookie_authentication(const char *fname, const char *header, + int cookie_len, + uint8_t **cookie_out, int *cookie_is_set_out); + +or_options_t *options_new(void); + +int config_parse_commandline(int argc, char **argv, int ignore_errors, + config_line_t **result, + config_line_t **cmdline_result); + +void config_register_addressmaps(const or_options_t *options); +/* XXXX024 move to connection_edge.h */ +int addressmap_register_auto(const char *from, const char *to, + time_t expires, + addressmap_entry_source_t addrmap_source, + const char **msg); + +/** Represents the information stored in a torrc Bridge line. */ +typedef struct bridge_line_t { + tor_addr_t addr; /* The IP address of the bridge. */ + uint16_t port; /* The TCP port of the bridge. */ + char *transport_name; /* The name of the pluggable transport that + should be used to connect to the bridge. */ + char digest[DIGEST_LEN]; /* The bridge's identity key digest. */ + smartlist_t *socks_args; /* SOCKS arguments for the pluggable + transport proxy. */ +} bridge_line_t; + +void bridge_line_free(bridge_line_t *bridge_line); +bridge_line_t *parse_bridge_line(const char *line); +smartlist_t *get_options_from_transport_options_line(const char *line, + const char *transport); +smartlist_t *get_options_for_server_transport(const char *transport); + +#ifdef CONFIG_PRIVATE +#ifdef TOR_UNIT_TESTS +extern struct config_format_t options_format; +#endif + +STATIC void or_options_free(or_options_t *options); +STATIC int options_validate(or_options_t *old_options, + or_options_t *options, + or_options_t *default_options, + int from_setconf, char **msg); +#endif + +#endif + diff --git a/src/tor/config_codedigest.c b/src/tor/config_codedigest.c new file mode 100644 index 0000000..86d14ba --- /dev/null +++ b/src/tor/config_codedigest.c @@ -0,0 +1,13 @@ + +const char *tor_get_digests(void); + +/** Return a string describing the digest of the source files in src/or/ + */ +const char * +tor_get_digests(void) +{ + return "" +#include "or_sha1.i" + ; +} + diff --git a/src/tor/confparse.c b/src/tor/confparse.c new file mode 100644 index 0000000..c5400a6 --- /dev/null +++ b/src/tor/confparse.c @@ -0,0 +1,1316 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#include "or.h" +#include "confparse.h" +#include "routerset.h" + +static uint64_t config_parse_memunit(const char *s, int *ok); +static int config_parse_msec_interval(const char *s, int *ok); +static int config_parse_interval(const char *s, int *ok); +static void config_reset(const config_format_t *fmt, void *options, + const config_var_t *var, int use_defaults); + +/** Allocate an empty configuration object of a given format type. */ +void * +config_new(const config_format_t *fmt) +{ + void *opts = tor_malloc_zero(fmt->size); + *(uint32_t*)STRUCT_VAR_P(opts, fmt->magic_offset) = fmt->magic; + CONFIG_CHECK(fmt, opts); + return opts; +} + +/* + * Functions to parse config options + */ + +/** If option is an official abbreviation for a longer option, + * return the longer option. Otherwise return option. + * If command_line is set, apply all abbreviations. Otherwise, only + * apply abbreviations that work for the config file and the command line. + * If warn_obsolete is set, warn about deprecated names. */ +const char * +config_expand_abbrev(const config_format_t *fmt, const char *option, + int command_line, int warn_obsolete) +{ + int i; + if (! fmt->abbrevs) + return option; + for (i=0; fmt->abbrevs[i].abbreviated; ++i) { + /* Abbreviations are case insensitive. */ + if (!strcasecmp(option,fmt->abbrevs[i].abbreviated) && + (command_line || !fmt->abbrevs[i].commandline_only)) { + if (warn_obsolete && fmt->abbrevs[i].warn) { + log_warn(LD_CONFIG, + "The configuration option '%s' is deprecated; " + "use '%s' instead.", + fmt->abbrevs[i].abbreviated, + fmt->abbrevs[i].full); + } + /* Keep going through the list in case we want to rewrite it more. + * (We could imagine recursing here, but I don't want to get the + * user into an infinite loop if we craft our list wrong.) */ + option = fmt->abbrevs[i].full; + } + } + return option; +} + +/** Helper: allocate a new configuration option mapping 'key' to 'val', + * append it to *lst. */ +void +config_line_append(config_line_t **lst, + const char *key, + const char *val) +{ + config_line_t *newline; + + newline = tor_malloc_zero(sizeof(config_line_t)); + newline->key = tor_strdup(key); + newline->value = tor_strdup(val); + newline->next = NULL; + while (*lst) + lst = &((*lst)->next); + + (*lst) = newline; +} + +/** Return the line in lines whose key is exactly key, or NULL + * if no such key exists. For handling commandline-only options only; other + * options should be looked up in the appropriate data structure. */ +const config_line_t * +config_line_find(const config_line_t *lines, + const char *key) +{ + const config_line_t *cl; + for (cl = lines; cl; cl = cl->next) { + if (!strcmp(cl->key, key)) + return cl; + } + return NULL; +} + +/** Helper: parse the config string and strdup into key/value + * strings. Set *result to the list, or NULL if parsing the string + * failed. Return 0 on success, -1 on failure. Warn and ignore any + * misformatted lines. + * + * If extended is set, then treat keys beginning with / and with + as + * indicating "clear" and "append" respectively. */ +int +config_get_lines(const char *string, config_line_t **result, int extended) +{ + config_line_t *list = NULL, **next; + char *k, *v; + const char *parse_err; + + next = &list; + do { + k = v = NULL; + string = parse_config_line_from_str_verbose(string, &k, &v, &parse_err); + if (!string) { + log_warn(LD_CONFIG, "Error while parsing configuration: %s", + parse_err?parse_err:""); + config_free_lines(list); + tor_free(k); + tor_free(v); + return -1; + } + if (k && v) { + unsigned command = CONFIG_LINE_NORMAL; + if (extended) { + if (k[0] == '+') { + char *k_new = tor_strdup(k+1); + tor_free(k); + k = k_new; + command = CONFIG_LINE_APPEND; + } else if (k[0] == '/') { + char *k_new = tor_strdup(k+1); + tor_free(k); + k = k_new; + tor_free(v); + v = tor_strdup(""); + command = CONFIG_LINE_CLEAR; + } + } + /* This list can get long, so we keep a pointer to the end of it + * rather than using config_line_append over and over and getting + * n^2 performance. */ + *next = tor_malloc_zero(sizeof(config_line_t)); + (*next)->key = k; + (*next)->value = v; + (*next)->next = NULL; + (*next)->command = command; + next = &((*next)->next); + } else { + tor_free(k); + tor_free(v); + } + } while (*string); + + *result = list; + return 0; +} + +/** + * Free all the configuration lines on the linked list front. + */ +void +config_free_lines(config_line_t *front) +{ + config_line_t *tmp; + + while (front) { + tmp = front; + front = tmp->next; + + tor_free(tmp->key); + tor_free(tmp->value); + tor_free(tmp); + } +} + +/** As config_find_option, but return a non-const pointer. */ +config_var_t * +config_find_option_mutable(config_format_t *fmt, const char *key) +{ + int i; + size_t keylen = strlen(key); + if (!keylen) + return NULL; /* if they say "--" on the command line, it's not an option */ + /* First, check for an exact (case-insensitive) match */ + for (i=0; fmt->vars[i].name; ++i) { + if (!strcasecmp(key, fmt->vars[i].name)) { + return &fmt->vars[i]; + } + } + /* If none, check for an abbreviated match */ + for (i=0; fmt->vars[i].name; ++i) { + if (!strncasecmp(key, fmt->vars[i].name, keylen)) { + log_warn(LD_CONFIG, "The abbreviation '%s' is deprecated. " + "Please use '%s' instead", + key, fmt->vars[i].name); + return &fmt->vars[i]; + } + } + /* Okay, unrecognized option */ + return NULL; +} + +/** If key is a configuration option, return the corresponding const + * config_var_t. Otherwise, if key is a non-standard abbreviation, + * warn, and return the corresponding const config_var_t. Otherwise return + * NULL. + */ +const config_var_t * +config_find_option(const config_format_t *fmt, const char *key) +{ + return config_find_option_mutable((config_format_t*)fmt, key); +} + +/** Return the number of option entries in fmt. */ +static int +config_count_options(const config_format_t *fmt) +{ + int i; + for (i=0; fmt->vars[i].name; ++i) + ; + return i; +} + +/* + * Functions to assign config options. + */ + +/** c-\>key is known to be a real key. Update options + * with c-\>value and return 0, or return -1 if bad value. + * + * Called from config_assign_line() and option_reset(). + */ +static int +config_assign_value(const config_format_t *fmt, void *options, + config_line_t *c, char **msg) +{ + int i, ok; + const config_var_t *var; + void *lvalue; + int *csv_int; + smartlist_t *csv_str; + + CONFIG_CHECK(fmt, options); + + var = config_find_option(fmt, c->key); + tor_assert(var); + + lvalue = STRUCT_VAR_P(options, var->var_offset); + + switch (var->type) { + + case CONFIG_TYPE_PORT: + if (!strcasecmp(c->value, "auto")) { + *(int *)lvalue = CFG_AUTO_PORT; + break; + } + /* fall through */ + case CONFIG_TYPE_INT: + case CONFIG_TYPE_UINT: + i = (int)tor_parse_long(c->value, 10, + var->type==CONFIG_TYPE_INT ? INT_MIN : 0, + var->type==CONFIG_TYPE_PORT ? 65535 : INT_MAX, + &ok, NULL); + if (!ok) { + tor_asprintf(msg, + "Int keyword '%s %s' is malformed or out of bounds.", + c->key, c->value); + return -1; + } + *(int *)lvalue = i; + break; + + case CONFIG_TYPE_INTERVAL: { + i = config_parse_interval(c->value, &ok); + if (!ok) { + tor_asprintf(msg, + "Interval '%s %s' is malformed or out of bounds.", + c->key, c->value); + return -1; + } + *(int *)lvalue = i; + break; + } + + case CONFIG_TYPE_MSEC_INTERVAL: { + i = config_parse_msec_interval(c->value, &ok); + if (!ok) { + tor_asprintf(msg, + "Msec interval '%s %s' is malformed or out of bounds.", + c->key, c->value); + return -1; + } + *(int *)lvalue = i; + break; + } + + case CONFIG_TYPE_MEMUNIT: { + uint64_t u64 = config_parse_memunit(c->value, &ok); + if (!ok) { + tor_asprintf(msg, + "Value '%s %s' is malformed or out of bounds.", + c->key, c->value); + return -1; + } + *(uint64_t *)lvalue = u64; + break; + } + + case CONFIG_TYPE_BOOL: + i = (int)tor_parse_long(c->value, 10, 0, 1, &ok, NULL); + if (!ok) { + tor_asprintf(msg, + "Boolean '%s %s' expects 0 or 1.", + c->key, c->value); + return -1; + } + *(int *)lvalue = i; + break; + + case CONFIG_TYPE_AUTOBOOL: + if (!strcmp(c->value, "auto")) + *(int *)lvalue = -1; + else if (!strcmp(c->value, "0")) + *(int *)lvalue = 0; + else if (!strcmp(c->value, "1")) + *(int *)lvalue = 1; + else { + tor_asprintf(msg, "Boolean '%s %s' expects 0, 1, or 'auto'.", + c->key, c->value); + return -1; + } + break; + + case CONFIG_TYPE_STRING: + case CONFIG_TYPE_FILENAME: + tor_free(*(char **)lvalue); + *(char **)lvalue = tor_strdup(c->value); + break; + + case CONFIG_TYPE_DOUBLE: + *(double *)lvalue = atof(c->value); + break; + + case CONFIG_TYPE_ISOTIME: + if (parse_iso_time(c->value, (time_t *)lvalue)) { + tor_asprintf(msg, + "Invalid time '%s' for keyword '%s'", c->value, c->key); + return -1; + } + break; + + case CONFIG_TYPE_ROUTERSET: + if (*(routerset_t**)lvalue) { + routerset_free(*(routerset_t**)lvalue); + } + *(routerset_t**)lvalue = routerset_new(); + if (routerset_parse(*(routerset_t**)lvalue, c->value, c->key)<0) { + tor_asprintf(msg, "Invalid exit list '%s' for option '%s'", + c->value, c->key); + return -1; + } + break; + + case CONFIG_TYPE_CSV: + if (*(smartlist_t**)lvalue) { + SMARTLIST_FOREACH(*(smartlist_t**)lvalue, char *, cp, tor_free(cp)); + smartlist_clear(*(smartlist_t**)lvalue); + } else { + *(smartlist_t**)lvalue = smartlist_new(); + } + + smartlist_split_string(*(smartlist_t**)lvalue, c->value, ",", + SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); + break; + + case CONFIG_TYPE_CSV_INTERVAL: + if (*(smartlist_t**)lvalue) { + SMARTLIST_FOREACH(*(smartlist_t**)lvalue, int *, cp, tor_free(cp)); + smartlist_clear(*(smartlist_t**)lvalue); + } else { + *(smartlist_t**)lvalue = smartlist_new(); + } + csv_str = smartlist_new(); + smartlist_split_string(csv_str, c->value, ",", + SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); + SMARTLIST_FOREACH_BEGIN(csv_str, char *, str) + { + i = config_parse_interval(str, &ok); + if (!ok) { + tor_asprintf(msg, + "Interval in '%s %s' is malformed or out of bounds.", + c->key, c->value); + SMARTLIST_FOREACH(csv_str, char *, cp, tor_free(cp)); + smartlist_free(csv_str); + return -1; + } + csv_int = tor_malloc_zero(sizeof(int)); + *csv_int = i; + smartlist_add(*(smartlist_t**)lvalue, csv_int); + } + SMARTLIST_FOREACH_END(str); + SMARTLIST_FOREACH(csv_str, char *, cp, tor_free(cp)); + smartlist_free(csv_str); + break; + + case CONFIG_TYPE_LINELIST: + case CONFIG_TYPE_LINELIST_S: + { + config_line_t *lastval = *(config_line_t**)lvalue; + if (lastval && lastval->fragile) { + if (c->command != CONFIG_LINE_APPEND) { + config_free_lines(lastval); + *(config_line_t**)lvalue = NULL; + } else { + lastval->fragile = 0; + } + } + + config_line_append((config_line_t**)lvalue, c->key, c->value); + } + break; + case CONFIG_TYPE_OBSOLETE: + log_warn(LD_CONFIG, "Skipping obsolete configuration option '%s'", c->key); + break; + case CONFIG_TYPE_LINELIST_V: + tor_asprintf(msg, + "You may not provide a value for virtual option '%s'", c->key); + return -1; + default: + tor_assert(0); + break; + } + return 0; +} + +/** Mark every linelist in options "fragile", so that fresh assignments + * to it will replace old ones. */ +static void +config_mark_lists_fragile(const config_format_t *fmt, void *options) +{ + int i; + tor_assert(fmt); + tor_assert(options); + + for (i = 0; fmt->vars[i].name; ++i) { + const config_var_t *var = &fmt->vars[i]; + config_line_t *list; + if (var->type != CONFIG_TYPE_LINELIST && + var->type != CONFIG_TYPE_LINELIST_V) + continue; + + list = *(config_line_t **)STRUCT_VAR_P(options, var->var_offset); + if (list) + list->fragile = 1; + } +} + +/** If c is a syntactically valid configuration line, update + * options with its value and return 0. Otherwise return -1 for bad + * key, -2 for bad value. + * + * If clear_first is set, clear the value first. Then if + * use_defaults is set, set the value to the default. + * + * Called from config_assign(). + */ +static int +config_assign_line(const config_format_t *fmt, void *options, + config_line_t *c, int use_defaults, + int clear_first, bitarray_t *options_seen, char **msg) +{ + const config_var_t *var; + + CONFIG_CHECK(fmt, options); + + var = config_find_option(fmt, c->key); + if (!var) { + if (fmt->extra) { + void *lvalue = STRUCT_VAR_P(options, fmt->extra->var_offset); + log_info(LD_CONFIG, + "Found unrecognized option '%s'; saving it.", c->key); + config_line_append((config_line_t**)lvalue, c->key, c->value); + return 0; + } else { + tor_asprintf(msg, + "Unknown option '%s'. Failing.", c->key); + return -1; + } + } + + /* Put keyword into canonical case. */ + if (strcmp(var->name, c->key)) { + tor_free(c->key); + c->key = tor_strdup(var->name); + } + + if (!strlen(c->value)) { + /* reset or clear it, then return */ + if (!clear_first) { + if ((var->type == CONFIG_TYPE_LINELIST || + var->type == CONFIG_TYPE_LINELIST_S) && + c->command != CONFIG_LINE_CLEAR) { + /* We got an empty linelist from the torrc or command line. + As a special case, call this an error. Warn and ignore. */ + log_warn(LD_CONFIG, + "Linelist option '%s' has no value. Skipping.", c->key); + } else { /* not already cleared */ + config_reset(fmt, options, var, use_defaults); + } + } + return 0; + } else if (c->command == CONFIG_LINE_CLEAR && !clear_first) { + config_reset(fmt, options, var, use_defaults); + } + + if (options_seen && (var->type != CONFIG_TYPE_LINELIST && + var->type != CONFIG_TYPE_LINELIST_S)) { + /* We're tracking which options we've seen, and this option is not + * supposed to occur more than once. */ + int var_index = (int)(var - fmt->vars); + if (bitarray_is_set(options_seen, var_index)) { + log_warn(LD_CONFIG, "Option '%s' used more than once; all but the last " + "value will be ignored.", var->name); + } + bitarray_set(options_seen, var_index); + } + + if (config_assign_value(fmt, options, c, msg) < 0) + return -2; + return 0; +} + +/** Restore the option named key in options to its default value. + * Called from config_assign(). */ +static void +config_reset_line(const config_format_t *fmt, void *options, + const char *key, int use_defaults) +{ + const config_var_t *var; + + CONFIG_CHECK(fmt, options); + + var = config_find_option(fmt, key); + if (!var) + return; /* give error on next pass. */ + + config_reset(fmt, options, var, use_defaults); +} + +/** Return true iff value needs to be quoted and escaped to be used in + * a configuration file. */ +static int +config_value_needs_escape(const char *value) +{ + if (*value == '\"') + return 1; + while (*value) { + switch (*value) + { + case '\r': + case '\n': + case '#': + /* Note: quotes and backspaces need special handling when we are using + * quotes, not otherwise, so they don't trigger escaping on their + * own. */ + return 1; + default: + if (!TOR_ISPRINT(*value)) + return 1; + } + ++value; + } + return 0; +} + +/** Return a newly allocated deep copy of the lines in inp. */ +config_line_t * +config_lines_dup(const config_line_t *inp) +{ + config_line_t *result = NULL; + config_line_t **next_out = &result; + while (inp) { + *next_out = tor_malloc_zero(sizeof(config_line_t)); + (*next_out)->key = tor_strdup(inp->key); + (*next_out)->value = tor_strdup(inp->value); + inp = inp->next; + next_out = &((*next_out)->next); + } + (*next_out) = NULL; + return result; +} + +/** Return newly allocated line or lines corresponding to key in the + * configuration options. If escape_val is true and a + * value needs to be quoted before it's put in a config file, quote and + * escape that value. Return NULL if no such key exists. */ +config_line_t * +config_get_assigned_option(const config_format_t *fmt, const void *options, + const char *key, int escape_val) +{ + const config_var_t *var; + const void *value; + config_line_t *result; + smartlist_t *csv_str; + tor_assert(options && key); + + CONFIG_CHECK(fmt, options); + + var = config_find_option(fmt, key); + if (!var) { + log_warn(LD_CONFIG, "Unknown option '%s'. Failing.", key); + return NULL; + } + value = STRUCT_VAR_P(options, var->var_offset); + + result = tor_malloc_zero(sizeof(config_line_t)); + result->key = tor_strdup(var->name); + switch (var->type) + { + case CONFIG_TYPE_STRING: + case CONFIG_TYPE_FILENAME: + if (*(char**)value) { + result->value = tor_strdup(*(char**)value); + } else { + tor_free(result->key); + tor_free(result); + return NULL; + } + break; + case CONFIG_TYPE_ISOTIME: + if (*(time_t*)value) { + result->value = tor_malloc(ISO_TIME_LEN+1); + format_iso_time(result->value, *(time_t*)value); + } else { + tor_free(result->key); + tor_free(result); + } + escape_val = 0; /* Can't need escape. */ + break; + case CONFIG_TYPE_PORT: + if (*(int*)value == CFG_AUTO_PORT) { + result->value = tor_strdup("auto"); + escape_val = 0; + break; + } + /* fall through */ + case CONFIG_TYPE_INTERVAL: + case CONFIG_TYPE_MSEC_INTERVAL: + case CONFIG_TYPE_UINT: + case CONFIG_TYPE_INT: + /* This means every or_options_t uint or bool element + * needs to be an int. Not, say, a uint16_t or char. */ + tor_asprintf(&result->value, "%d", *(int*)value); + escape_val = 0; /* Can't need escape. */ + break; + case CONFIG_TYPE_MEMUNIT: + tor_asprintf(&result->value, U64_FORMAT, + U64_PRINTF_ARG(*(uint64_t*)value)); + escape_val = 0; /* Can't need escape. */ + break; + case CONFIG_TYPE_DOUBLE: + tor_asprintf(&result->value, "%f", *(double*)value); + escape_val = 0; /* Can't need escape. */ + break; + + case CONFIG_TYPE_AUTOBOOL: + if (*(int*)value == -1) { + result->value = tor_strdup("auto"); + escape_val = 0; + break; + } + /* fall through */ + case CONFIG_TYPE_BOOL: + result->value = tor_strdup(*(int*)value ? "1" : "0"); + escape_val = 0; /* Can't need escape. */ + break; + case CONFIG_TYPE_ROUTERSET: + result->value = routerset_to_string(*(routerset_t**)value); + break; + case CONFIG_TYPE_CSV: + if (*(smartlist_t**)value) + result->value = + smartlist_join_strings(*(smartlist_t**)value, ",", 0, NULL); + else + result->value = tor_strdup(""); + break; + case CONFIG_TYPE_CSV_INTERVAL: + if (*(smartlist_t**)value) { + csv_str = smartlist_new(); + SMARTLIST_FOREACH_BEGIN(*(smartlist_t**)value, int *, i) + { + smartlist_add_asprintf(csv_str, "%d", *i); + } + SMARTLIST_FOREACH_END(i); + result->value = smartlist_join_strings(csv_str, ",", 0, NULL); + SMARTLIST_FOREACH(csv_str, char *, cp, tor_free(cp)); + smartlist_free(csv_str); + } else + result->value = tor_strdup(""); + break; + case CONFIG_TYPE_OBSOLETE: + log_fn(LOG_INFO, LD_CONFIG, + "You asked me for the value of an obsolete config option '%s'.", + key); + tor_free(result->key); + tor_free(result); + return NULL; + case CONFIG_TYPE_LINELIST_S: + log_warn(LD_CONFIG, + "Can't return context-sensitive '%s' on its own", key); + tor_free(result->key); + tor_free(result); + return NULL; + case CONFIG_TYPE_LINELIST: + case CONFIG_TYPE_LINELIST_V: + tor_free(result->key); + tor_free(result); + result = config_lines_dup(*(const config_line_t**)value); + break; + default: + tor_free(result->key); + tor_free(result); + log_warn(LD_BUG,"Unknown type %d for known key '%s'", + var->type, key); + return NULL; + } + + if (escape_val) { + config_line_t *line; + for (line = result; line; line = line->next) { + if (line->value && config_value_needs_escape(line->value)) { + char *newval = esc_for_log(line->value); + tor_free(line->value); + line->value = newval; + } + } + } + + return result; +} +/** Iterate through the linked list of requested options list. + * For each item, convert as appropriate and assign to options. + * If an item is unrecognized, set *msg and return -1 immediately, + * else return 0 for success. + * + * If clear_first, interpret config options as replacing (not + * extending) their previous values. If clear_first is set, + * then use_defaults to decide if you set to defaults after + * clearing, or make the value 0 or NULL. + * + * Here are the use cases: + * 1. A non-empty AllowInvalid line in your torrc. Appends to current + * if linelist, replaces current if csv. + * 2. An empty AllowInvalid line in your torrc. Should clear it. + * 3. "RESETCONF AllowInvalid" sets it to default. + * 4. "SETCONF AllowInvalid" makes it NULL. + * 5. "SETCONF AllowInvalid=foo" clears it and sets it to "foo". + * + * Use_defaults Clear_first + * 0 0 "append" + * 1 0 undefined, don't use + * 0 1 "set to null first" + * 1 1 "set to defaults first" + * Return 0 on success, -1 on bad key, -2 on bad value. + * + * As an additional special case, if a LINELIST config option has + * no value and clear_first is 0, then warn and ignore it. + */ + +/* +There are three call cases for config_assign() currently. + +Case one: Torrc entry +options_init_from_torrc() calls config_assign(0, 0) + calls config_assign_line(0, 0). + if value is empty, calls config_reset(0) and returns. + calls config_assign_value(), appends. + +Case two: setconf +options_trial_assign() calls config_assign(0, 1) + calls config_reset_line(0) + calls config_reset(0) + calls option_clear(). + calls config_assign_line(0, 1). + if value is empty, returns. + calls config_assign_value(), appends. + +Case three: resetconf +options_trial_assign() calls config_assign(1, 1) + calls config_reset_line(1) + calls config_reset(1) + calls option_clear(). + calls config_assign_value(default) + calls config_assign_line(1, 1). + returns. +*/ +int +config_assign(const config_format_t *fmt, void *options, config_line_t *list, + int use_defaults, int clear_first, char **msg) +{ + config_line_t *p; + bitarray_t *options_seen; + const int n_options = config_count_options(fmt); + + CONFIG_CHECK(fmt, options); + + /* pass 1: normalize keys */ + for (p = list; p; p = p->next) { + const char *full = config_expand_abbrev(fmt, p->key, 0, 1); + if (strcmp(full,p->key)) { + tor_free(p->key); + p->key = tor_strdup(full); + } + } + + /* pass 2: if we're reading from a resetting source, clear all + * mentioned config options, and maybe set to their defaults. */ + if (clear_first) { + for (p = list; p; p = p->next) + config_reset_line(fmt, options, p->key, use_defaults); + } + + options_seen = bitarray_init_zero(n_options); + /* pass 3: assign. */ + while (list) { + int r; + if ((r=config_assign_line(fmt, options, list, use_defaults, + clear_first, options_seen, msg))) { + bitarray_free(options_seen); + return r; + } + list = list->next; + } + bitarray_free(options_seen); + + /** Now we're done assigning a group of options to the configuration. + * Subsequent group assignments should _replace_ linelists, not extend + * them. */ + config_mark_lists_fragile(fmt, options); + + return 0; +} + +/** Reset config option var to 0, 0.0, NULL, or the equivalent. + * Called from config_reset() and config_free(). */ +static void +config_clear(const config_format_t *fmt, void *options, + const config_var_t *var) +{ + void *lvalue = STRUCT_VAR_P(options, var->var_offset); + (void)fmt; /* unused */ + switch (var->type) { + case CONFIG_TYPE_STRING: + case CONFIG_TYPE_FILENAME: + tor_free(*(char**)lvalue); + break; + case CONFIG_TYPE_DOUBLE: + *(double*)lvalue = 0.0; + break; + case CONFIG_TYPE_ISOTIME: + *(time_t*)lvalue = 0; + break; + case CONFIG_TYPE_INTERVAL: + case CONFIG_TYPE_MSEC_INTERVAL: + case CONFIG_TYPE_UINT: + case CONFIG_TYPE_INT: + case CONFIG_TYPE_PORT: + case CONFIG_TYPE_BOOL: + *(int*)lvalue = 0; + break; + case CONFIG_TYPE_AUTOBOOL: + *(int*)lvalue = -1; + break; + case CONFIG_TYPE_MEMUNIT: + *(uint64_t*)lvalue = 0; + break; + case CONFIG_TYPE_ROUTERSET: + if (*(routerset_t**)lvalue) { + routerset_free(*(routerset_t**)lvalue); + *(routerset_t**)lvalue = NULL; + } + break; + case CONFIG_TYPE_CSV: + if (*(smartlist_t**)lvalue) { + SMARTLIST_FOREACH(*(smartlist_t **)lvalue, char *, cp, tor_free(cp)); + smartlist_free(*(smartlist_t **)lvalue); + *(smartlist_t **)lvalue = NULL; + } + break; + case CONFIG_TYPE_CSV_INTERVAL: + if (*(smartlist_t**)lvalue) { + SMARTLIST_FOREACH(*(smartlist_t **)lvalue, int *, cp, tor_free(cp)); + smartlist_free(*(smartlist_t **)lvalue); + *(smartlist_t **)lvalue = NULL; + } + break; + case CONFIG_TYPE_LINELIST: + case CONFIG_TYPE_LINELIST_S: + config_free_lines(*(config_line_t **)lvalue); + *(config_line_t **)lvalue = NULL; + break; + case CONFIG_TYPE_LINELIST_V: + /* handled by linelist_s. */ + break; + case CONFIG_TYPE_OBSOLETE: + break; + } +} + +/** Clear the option indexed by var in options. Then if + * use_defaults, set it to its default value. + * Called by config_init() and option_reset_line() and option_assign_line(). */ +static void +config_reset(const config_format_t *fmt, void *options, + const config_var_t *var, int use_defaults) +{ + config_line_t *c; + char *msg = NULL; + CONFIG_CHECK(fmt, options); + config_clear(fmt, options, var); /* clear it first */ + if (!use_defaults) + return; /* all done */ + if (var->initvalue) { + c = tor_malloc_zero(sizeof(config_line_t)); + c->key = tor_strdup(var->name); + c->value = tor_strdup(var->initvalue); + if (config_assign_value(fmt, options, c, &msg) < 0) { + log_warn(LD_BUG, "Failed to assign default: %s", msg); + tor_free(msg); /* if this happens it's a bug */ + } + config_free_lines(c); + } +} + +/** Release storage held by options. */ +void +config_free(const config_format_t *fmt, void *options) +{ + int i; + + if (!options) + return; + + tor_assert(fmt); + + for (i=0; fmt->vars[i].name; ++i) + config_clear(fmt, options, &(fmt->vars[i])); + if (fmt->extra) { + config_line_t **linep = STRUCT_VAR_P(options, fmt->extra->var_offset); + config_free_lines(*linep); + *linep = NULL; + } + tor_free(options); +} + +/** Return true iff a and b contain identical keys and values in identical + * order. */ +int +config_lines_eq(config_line_t *a, config_line_t *b) +{ + while (a && b) { + if (strcasecmp(a->key, b->key) || strcmp(a->value, b->value)) + return 0; + a = a->next; + b = b->next; + } + if (a || b) + return 0; + return 1; +} + +/** Return the number of lines in a whose key is key. */ +int +config_count_key(const config_line_t *a, const char *key) +{ + int n = 0; + while (a) { + if (!strcasecmp(a->key, key)) { + ++n; + } + a = a->next; + } + return n; +} + +/** Return true iff the option name has the same value in o1 + * and o2. Must not be called for LINELIST_S or OBSOLETE options. + */ +int +config_is_same(const config_format_t *fmt, + const void *o1, const void *o2, + const char *name) +{ + config_line_t *c1, *c2; + int r = 1; + CONFIG_CHECK(fmt, o1); + CONFIG_CHECK(fmt, o2); + + c1 = config_get_assigned_option(fmt, o1, name, 0); + c2 = config_get_assigned_option(fmt, o2, name, 0); + r = config_lines_eq(c1, c2); + config_free_lines(c1); + config_free_lines(c2); + return r; +} + +/** Copy storage held by old into a new or_options_t and return it. */ +void * +config_dup(const config_format_t *fmt, const void *old) +{ + void *newopts; + int i; + config_line_t *line; + + newopts = config_new(fmt); + for (i=0; fmt->vars[i].name; ++i) { + if (fmt->vars[i].type == CONFIG_TYPE_LINELIST_S) + continue; + if (fmt->vars[i].type == CONFIG_TYPE_OBSOLETE) + continue; + line = config_get_assigned_option(fmt, old, fmt->vars[i].name, 0); + if (line) { + char *msg = NULL; + if (config_assign(fmt, newopts, line, 0, 0, &msg) < 0) { + log_err(LD_BUG, "config_get_assigned_option() generated " + "something we couldn't config_assign(): %s", msg); + tor_free(msg); + tor_assert(0); + } + } + config_free_lines(line); + } + return newopts; +} +/** Set all vars in the configuration object options to their default + * values. */ +void +config_init(const config_format_t *fmt, void *options) +{ + int i; + const config_var_t *var; + CONFIG_CHECK(fmt, options); + + for (i=0; fmt->vars[i].name; ++i) { + var = &fmt->vars[i]; + if (!var->initvalue) + continue; /* defaults to NULL or 0 */ + config_reset(fmt, options, var, 1); + } +} + +/** Allocate and return a new string holding the written-out values of the vars + * in 'options'. If 'minimal', do not write out any default-valued vars. + * Else, if comment_defaults, write default values as comments. + */ +char * +config_dump(const config_format_t *fmt, const void *default_options, + const void *options, int minimal, + int comment_defaults) +{ + smartlist_t *elements; + const void *defaults = default_options; + void *defaults_tmp = NULL; + config_line_t *line, *assigned; + char *result; + int i; + char *msg = NULL; + + if (defaults == NULL) { + defaults = defaults_tmp = config_new(fmt); + config_init(fmt, defaults_tmp); + } + + /* XXX use a 1 here so we don't add a new log line while dumping */ + if (default_options == NULL) { + if (fmt->validate_fn(NULL, defaults_tmp, defaults_tmp, 1, &msg) < 0) { + log_err(LD_BUG, "Failed to validate default config: %s", msg); + tor_free(msg); + tor_assert(0); + } + } + + elements = smartlist_new(); + for (i=0; fmt->vars[i].name; ++i) { + int comment_option = 0; + if (fmt->vars[i].type == CONFIG_TYPE_OBSOLETE || + fmt->vars[i].type == CONFIG_TYPE_LINELIST_S) + continue; + /* Don't save 'hidden' control variables. */ + if (!strcmpstart(fmt->vars[i].name, "__")) + continue; + if (minimal && config_is_same(fmt, options, defaults, fmt->vars[i].name)) + continue; + else if (comment_defaults && + config_is_same(fmt, options, defaults, fmt->vars[i].name)) + comment_option = 1; + + line = assigned = + config_get_assigned_option(fmt, options, fmt->vars[i].name, 1); + + for (; line; line = line->next) { + smartlist_add_asprintf(elements, "%s%s %s\n", + comment_option ? "# " : "", + line->key, line->value); + } + config_free_lines(assigned); + } + + if (fmt->extra) { + line = *(config_line_t**)STRUCT_VAR_P(options, fmt->extra->var_offset); + for (; line; line = line->next) { + smartlist_add_asprintf(elements, "%s %s\n", line->key, line->value); + } + } + + result = smartlist_join_strings(elements, "", 0, NULL); + SMARTLIST_FOREACH(elements, char *, cp, tor_free(cp)); + smartlist_free(elements); + if (defaults_tmp) + config_free(fmt, defaults_tmp); + return result; +} + +/** Mapping from a unit name to a multiplier for converting that unit into a + * base unit. Used by config_parse_unit. */ +struct unit_table_t { + const char *unit; /**< The name of the unit */ + uint64_t multiplier; /**< How many of the base unit appear in this unit */ +}; + +/** Table to map the names of memory units to the number of bytes they + * contain. */ +static struct unit_table_t memory_units[] = { + { "", 1 }, + { "b", 1<< 0 }, + { "byte", 1<< 0 }, + { "bytes", 1<< 0 }, + { "kb", 1<<10 }, + { "kbyte", 1<<10 }, + { "kbytes", 1<<10 }, + { "kilobyte", 1<<10 }, + { "kilobytes", 1<<10 }, + { "kilobits", 1<<7 }, + { "kilobit", 1<<7 }, + { "kbits", 1<<7 }, + { "kbit", 1<<7 }, + { "m", 1<<20 }, + { "mb", 1<<20 }, + { "mbyte", 1<<20 }, + { "mbytes", 1<<20 }, + { "megabyte", 1<<20 }, + { "megabytes", 1<<20 }, + { "megabits", 1<<17 }, + { "megabit", 1<<17 }, + { "mbits", 1<<17 }, + { "mbit", 1<<17 }, + { "gb", 1<<30 }, + { "gbyte", 1<<30 }, + { "gbytes", 1<<30 }, + { "gigabyte", 1<<30 }, + { "gigabytes", 1<<30 }, + { "gigabits", 1<<27 }, + { "gigabit", 1<<27 }, + { "gbits", 1<<27 }, + { "gbit", 1<<27 }, + { "tb", U64_LITERAL(1)<<40 }, + { "terabyte", U64_LITERAL(1)<<40 }, + { "terabytes", U64_LITERAL(1)<<40 }, + { "terabits", U64_LITERAL(1)<<37 }, + { "terabit", U64_LITERAL(1)<<37 }, + { "tbits", U64_LITERAL(1)<<37 }, + { "tbit", U64_LITERAL(1)<<37 }, + { NULL, 0 }, +}; + +/** Table to map the names of time units to the number of seconds they + * contain. */ +static struct unit_table_t time_units[] = { + { "", 1 }, + { "second", 1 }, + { "seconds", 1 }, + { "minute", 60 }, + { "minutes", 60 }, + { "hour", 60*60 }, + { "hours", 60*60 }, + { "day", 24*60*60 }, + { "days", 24*60*60 }, + { "week", 7*24*60*60 }, + { "weeks", 7*24*60*60 }, + { "month", 2629728, }, /* about 30.437 days */ + { "months", 2629728, }, + { NULL, 0 }, +}; + +/** Table to map the names of time units to the number of milliseconds + * they contain. */ +static struct unit_table_t time_msec_units[] = { + { "", 1 }, + { "msec", 1 }, + { "millisecond", 1 }, + { "milliseconds", 1 }, + { "second", 1000 }, + { "seconds", 1000 }, + { "minute", 60*1000 }, + { "minutes", 60*1000 }, + { "hour", 60*60*1000 }, + { "hours", 60*60*1000 }, + { "day", 24*60*60*1000 }, + { "days", 24*60*60*1000 }, + { "week", 7*24*60*60*1000 }, + { "weeks", 7*24*60*60*1000 }, + { NULL, 0 }, +}; + +/** Parse a string val containing a number, zero or more + * spaces, and an optional unit string. If the unit appears in the + * table u, then multiply the number by the unit multiplier. + * On success, set *ok to 1 and return this product. + * Otherwise, set *ok to 0. + */ +static uint64_t +config_parse_units(const char *val, struct unit_table_t *u, int *ok) +{ + uint64_t v = 0; + double d = 0; + int use_float = 0; + char *cp; + + tor_assert(ok); + + v = tor_parse_uint64(val, 10, 0, UINT64_MAX, ok, &cp); + if (!*ok || (cp && *cp == '.')) { + d = tor_parse_double(val, 0, UINT64_MAX, ok, &cp); + if (!*ok) + goto done; + use_float = 1; + } + + if (!cp) { + *ok = 1; + v = use_float ? DBL_TO_U64(d) : v; + goto done; + } + + cp = (char*) eat_whitespace(cp); + + for ( ;u->unit;++u) { + if (!strcasecmp(u->unit, cp)) { + if (use_float) + v = u->multiplier * d; + else + v *= u->multiplier; + *ok = 1; + goto done; + } + } + log_warn(LD_CONFIG, "Unknown unit '%s'.", cp); + *ok = 0; + done: + + if (*ok) + return v; + else + return 0; +} + +/** Parse a string in the format "number unit", where unit is a unit of + * information (byte, KB, M, etc). On success, set *ok to true + * and return the number of bytes specified. Otherwise, set + * *ok to false and return 0. */ +static uint64_t +config_parse_memunit(const char *s, int *ok) +{ + uint64_t u = config_parse_units(s, memory_units, ok); + return u; +} + +/** Parse a string in the format "number unit", where unit is a unit of + * time in milliseconds. On success, set *ok to true and return + * the number of milliseconds in the provided interval. Otherwise, set + * *ok to 0 and return -1. */ +static int +config_parse_msec_interval(const char *s, int *ok) +{ + uint64_t r; + r = config_parse_units(s, time_msec_units, ok); + if (!ok) + return -1; + if (r > INT_MAX) { + log_warn(LD_CONFIG, "Msec interval '%s' is too long", s); + *ok = 0; + return -1; + } + return (int)r; +} + +/** Parse a string in the format "number unit", where unit is a unit of time. + * On success, set *ok to true and return the number of seconds in + * the provided interval. Otherwise, set *ok to 0 and return -1. + */ +static int +config_parse_interval(const char *s, int *ok) +{ + uint64_t r; + r = config_parse_units(s, time_units, ok); + if (!ok) + return -1; + if (r > INT_MAX) { + log_warn(LD_CONFIG, "Interval '%s' is too long", s); + *ok = 0; + return -1; + } + return (int)r; +} + diff --git a/src/tor/confparse.h b/src/tor/confparse.h new file mode 100644 index 0000000..2cd6c49 --- /dev/null +++ b/src/tor/confparse.h @@ -0,0 +1,137 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_CONFPARSE_H +#define TOR_CONFPARSE_H + +/** Enumeration of types which option values can take */ +typedef enum config_type_t { + CONFIG_TYPE_STRING = 0, /**< An arbitrary string. */ + CONFIG_TYPE_FILENAME, /**< A filename: some prefixes get expanded. */ + CONFIG_TYPE_UINT, /**< A non-negative integer less than MAX_INT */ + CONFIG_TYPE_INT, /**< Any integer. */ + CONFIG_TYPE_PORT, /**< A port from 1...65535, 0 for "not set", or + * "auto". */ + CONFIG_TYPE_INTERVAL, /**< A number of seconds, with optional units*/ + CONFIG_TYPE_MSEC_INTERVAL,/**< A number of milliseconds, with optional + * units */ + CONFIG_TYPE_MEMUNIT, /**< A number of bytes, with optional units*/ + CONFIG_TYPE_DOUBLE, /**< A floating-point value */ + CONFIG_TYPE_BOOL, /**< A boolean value, expressed as 0 or 1. */ + CONFIG_TYPE_AUTOBOOL, /**< A boolean+auto value, expressed 0 for false, + * 1 for true, and -1 for auto */ + CONFIG_TYPE_ISOTIME, /**< An ISO-formatted time relative to UTC. */ + CONFIG_TYPE_CSV, /**< A list of strings, separated by commas and + * optional whitespace. */ + CONFIG_TYPE_CSV_INTERVAL, /**< A list of strings, separated by commas and + * optional whitespace, representing intervals in + * seconds, with optional units */ + CONFIG_TYPE_LINELIST, /**< Uninterpreted config lines */ + CONFIG_TYPE_LINELIST_S, /**< Uninterpreted, context-sensitive config lines, + * mixed with other keywords. */ + CONFIG_TYPE_LINELIST_V, /**< Catch-all "virtual" option to summarize + * context-sensitive config lines when fetching. + */ + CONFIG_TYPE_ROUTERSET, /**< A list of router names, addrs, and fps, + * parsed into a routerset_t. */ + CONFIG_TYPE_OBSOLETE, /**< Obsolete (ignored) option. */ +} config_type_t; + +/** An abbreviation for a configuration option allowed on the command line. */ +typedef struct config_abbrev_t { + const char *abbreviated; + const char *full; + int commandline_only; + int warn; +} config_abbrev_t; + +/* Handy macro for declaring "In the config file or on the command line, + * you can abbreviate toks as tok". */ +#define PLURAL(tok) { #tok, #tok "s", 0, 0 } + +/** A variable allowed in the configuration file or on the command line. */ +typedef struct config_var_t { + const char *name; /**< The full keyword (case insensitive). */ + config_type_t type; /**< How to interpret the type and turn it into a + * value. */ + off_t var_offset; /**< Offset of the corresponding member of or_options_t. */ + const char *initvalue; /**< String (or null) describing initial value. */ +} config_var_t; + +/** Represents an English description of a configuration variable; used when + * generating configuration file comments. */ +typedef struct config_var_description_t { + const char *name; + const char *description; +} config_var_description_t; + +/** Type of a callback to validate whether a given configuration is + * well-formed and consistent. See options_trial_assign() for documentation + * of arguments. */ +typedef int (*validate_fn_t)(void*,void*,void*,int,char**); + +/** Information on the keys, value types, key-to-struct-member mappings, + * variable descriptions, validation functions, and abbreviations for a + * configuration or storage format. */ +typedef struct config_format_t { + size_t size; /**< Size of the struct that everything gets parsed into. */ + uint32_t magic; /**< Required 'magic value' to make sure we have a struct + * of the right type. */ + off_t magic_offset; /**< Offset of the magic value within the struct. */ + config_abbrev_t *abbrevs; /**< List of abbreviations that we expand when + * parsing this format. */ + config_var_t *vars; /**< List of variables we recognize, their default + * values, and where we stick them in the structure. */ + validate_fn_t validate_fn; /**< Function to validate config. */ + /** If present, extra is a LINELIST variable for unrecognized + * lines. Otherwise, unrecognized lines are an error. */ + config_var_t *extra; +} config_format_t; + +/** Macro: assert that cfg has the right magic field for format + * fmt. */ +#define CONFIG_CHECK(fmt, cfg) STMT_BEGIN \ + tor_assert(fmt && cfg); \ + tor_assert((fmt)->magic == \ + *(uint32_t*)STRUCT_VAR_P(cfg,fmt->magic_offset)); \ + STMT_END + +void *config_new(const config_format_t *fmt); +void config_line_append(config_line_t **lst, + const char *key, const char *val); +config_line_t *config_lines_dup(const config_line_t *inp); +const config_line_t *config_line_find(const config_line_t *lines, + const char *key); +void config_free(const config_format_t *fmt, void *options); +int config_lines_eq(config_line_t *a, config_line_t *b); +int config_count_key(const config_line_t *a, const char *key); +config_line_t *config_get_assigned_option(const config_format_t *fmt, + const void *options, const char *key, + int escape_val); +int config_is_same(const config_format_t *fmt, + const void *o1, const void *o2, + const char *name); +void config_init(const config_format_t *fmt, void *options); +void *config_dup(const config_format_t *fmt, const void *old); +char *config_dump(const config_format_t *fmt, const void *default_options, + const void *options, int minimal, + int comment_defaults); +int config_assign(const config_format_t *fmt, void *options, + config_line_t *list, + int use_defaults, int clear_first, char **msg); +config_var_t *config_find_option_mutable(config_format_t *fmt, + const char *key); +const config_var_t *config_find_option(const config_format_t *fmt, + const char *key); + +int config_get_lines(const char *string, config_line_t **result, int extended); +void config_free_lines(config_line_t *front); +const char *config_expand_abbrev(const config_format_t *fmt, + const char *option, + int command_line, int warn_obsolete); + +#endif + diff --git a/src/tor/connection.c b/src/tor/connection.c new file mode 100644 index 0000000..ebf679e --- /dev/null +++ b/src/tor/connection.c @@ -0,0 +1,4850 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file connection.c + * \brief General high-level functions to handle reading and writing + * on connections. + **/ + +#define CONNECTION_PRIVATE +#include "or.h" +#include "buffers.h" +/* + * Define this so we get channel internal functions, since we're implementing + * part of a subclass (channel_tls_t). + */ +#define TOR_CHANNEL_INTERNAL_ +#define CONNECTION_PRIVATE +#include "channel.h" +#include "channeltls.h" +#include "circuitbuild.h" +#include "circuitlist.h" +#include "circuituse.h" +#include "config.h" +#include "connection.h" +#include "connection_edge.h" +#include "connection_or.h" +#include "control.h" +#include "cpuworker.h" +#include "directory.h" +#include "dirserv.h" +#include "dns.h" +#include "dnsserv.h" +#include "entrynodes.h" +#include "ext_orport.h" +#include "geoip.h" +#include "onion_main.h" +#include "policies.h" +#include "reasons.h" +#include "relay.h" +#include "rendclient.h" +#include "rendcommon.h" +#include "rephist.h" +#include "router.h" +#include "transports.h" +#include "routerparse.h" +#include "transports.h" + +#ifdef USE_BUFFEREVENTS +#include +#endif + +#ifdef HAVE_PWD_H +#include +#endif + +static connection_t *connection_listener_new( + const struct sockaddr *listensockaddr, + socklen_t listensocklen, int type, + const char *address, + const port_cfg_t *portcfg); +static void connection_init(time_t now, connection_t *conn, int type, + int socket_family); +static int connection_init_accepted_conn(connection_t *conn, + const listener_connection_t *listener); +static int connection_handle_listener_read(connection_t *conn, int new_type); +#ifndef USE_BUFFEREVENTS +static int connection_bucket_should_increase(int bucket, + or_connection_t *conn); +#endif +static int connection_finished_flushing(connection_t *conn); +static int connection_flushed_some(connection_t *conn); +static int connection_finished_connecting(connection_t *conn); +static int connection_reached_eof(connection_t *conn); +static int connection_read_to_buf(connection_t *conn, ssize_t *max_to_read, + int *socket_error); +static int connection_process_inbuf(connection_t *conn, int package_partial); +static void client_check_address_changed(tor_socket_t sock); +static void set_constrained_socket_buffers(tor_socket_t sock, int size); + +static const char *connection_proxy_state_to_string(int state); +static int connection_read_https_proxy_response(connection_t *conn); +static void connection_send_socks5_connect(connection_t *conn); +static const char *proxy_type_to_string(int proxy_type); +static int get_proxy_type(void); + +/** The last addresses that our network interface seemed to have been + * binding to. We use this as one way to detect when our IP changes. + * + * XXX024 We should really use the entire list of interfaces here. + **/ +static tor_addr_t *last_interface_ipv4 = NULL; +/* DOCDOC last_interface_ipv6 */ +static tor_addr_t *last_interface_ipv6 = NULL; +/** A list of tor_addr_t for addresses we've used in outgoing connections. + * Used to detect IP address changes. */ +static smartlist_t *outgoing_addrs = NULL; + +#define CASE_ANY_LISTENER_TYPE \ + case CONN_TYPE_OR_LISTENER: \ + case CONN_TYPE_EXT_OR_LISTENER: \ + case CONN_TYPE_AP_LISTENER: \ + case CONN_TYPE_DIR_LISTENER: \ + case CONN_TYPE_CONTROL_LISTENER: \ + case CONN_TYPE_AP_TRANS_LISTENER: \ + case CONN_TYPE_AP_NATD_LISTENER: \ + case CONN_TYPE_AP_DNS_LISTENER + +/**************************************************************/ + +/** + * Return the human-readable name for the connection type type + */ +const char * +conn_type_to_string(int type) +{ + static char buf[64]; + switch (type) { + case CONN_TYPE_OR_LISTENER: return "OR listener"; + case CONN_TYPE_OR: return "OR"; + case CONN_TYPE_EXIT: return "Exit"; + case CONN_TYPE_AP_LISTENER: return "Socks listener"; + case CONN_TYPE_AP_TRANS_LISTENER: + return "Transparent pf/netfilter listener"; + case CONN_TYPE_AP_NATD_LISTENER: return "Transparent natd listener"; + case CONN_TYPE_AP_DNS_LISTENER: return "DNS listener"; + case CONN_TYPE_AP: return "Socks"; + case CONN_TYPE_DIR_LISTENER: return "Directory listener"; + case CONN_TYPE_DIR: return "Directory"; + case CONN_TYPE_CPUWORKER: return "CPU worker"; + case CONN_TYPE_CONTROL_LISTENER: return "Control listener"; + case CONN_TYPE_CONTROL: return "Control"; + case CONN_TYPE_EXT_OR: return "Extended OR"; + case CONN_TYPE_EXT_OR_LISTENER: return "Extended OR listener"; + default: + log_warn(LD_BUG, "unknown connection type %d", type); + tor_snprintf(buf, sizeof(buf), "unknown [%d]", type); + return buf; + } +} + +/** + * Return the human-readable name for the connection state state + * for the connection type type + */ +const char * +conn_state_to_string(int type, int state) +{ + static char buf[96]; + switch (type) { + CASE_ANY_LISTENER_TYPE: + if (state == LISTENER_STATE_READY) + return "ready"; + break; + case CONN_TYPE_OR: + switch (state) { + case OR_CONN_STATE_CONNECTING: return "connect()ing"; + case OR_CONN_STATE_PROXY_HANDSHAKING: return "handshaking (proxy)"; + case OR_CONN_STATE_TLS_HANDSHAKING: return "handshaking (TLS)"; + case OR_CONN_STATE_TLS_CLIENT_RENEGOTIATING: + return "renegotiating (TLS, v2 handshake)"; + case OR_CONN_STATE_TLS_SERVER_RENEGOTIATING: + return "waiting for renegotiation or V3 handshake"; + case OR_CONN_STATE_OR_HANDSHAKING_V2: + return "handshaking (Tor, v2 handshake)"; + case OR_CONN_STATE_OR_HANDSHAKING_V3: + return "handshaking (Tor, v3 handshake)"; + case OR_CONN_STATE_OPEN: return "open"; + } + break; + case CONN_TYPE_EXT_OR: + switch (state) { + case EXT_OR_CONN_STATE_AUTH_WAIT_AUTH_TYPE: + return "waiting for authentication type"; + case EXT_OR_CONN_STATE_AUTH_WAIT_CLIENT_NONCE: + return "waiting for client nonce"; + case EXT_OR_CONN_STATE_AUTH_WAIT_CLIENT_HASH: + return "waiting for client hash"; + case EXT_OR_CONN_STATE_OPEN: return "open"; + case EXT_OR_CONN_STATE_FLUSHING: return "flushing final OKAY"; + } + break; + case CONN_TYPE_EXIT: + switch (state) { + case EXIT_CONN_STATE_RESOLVING: return "waiting for dest info"; + case EXIT_CONN_STATE_CONNECTING: return "connecting"; + case EXIT_CONN_STATE_OPEN: return "open"; + case EXIT_CONN_STATE_RESOLVEFAILED: return "resolve failed"; + } + break; + case CONN_TYPE_AP: + switch (state) { + case AP_CONN_STATE_SOCKS_WAIT: return "waiting for socks info"; + case AP_CONN_STATE_NATD_WAIT: return "waiting for natd dest info"; + case AP_CONN_STATE_RENDDESC_WAIT: return "waiting for rendezvous desc"; + case AP_CONN_STATE_CONTROLLER_WAIT: return "waiting for controller"; + case AP_CONN_STATE_CIRCUIT_WAIT: return "waiting for circuit"; + case AP_CONN_STATE_CONNECT_WAIT: return "waiting for connect response"; + case AP_CONN_STATE_RESOLVE_WAIT: return "waiting for resolve response"; + case AP_CONN_STATE_OPEN: return "open"; + } + break; + case CONN_TYPE_DIR: + switch (state) { + case DIR_CONN_STATE_CONNECTING: return "connecting"; + case DIR_CONN_STATE_CLIENT_SENDING: return "client sending"; + case DIR_CONN_STATE_CLIENT_READING: return "client reading"; + case DIR_CONN_STATE_CLIENT_FINISHED: return "client finished"; + case DIR_CONN_STATE_SERVER_COMMAND_WAIT: return "waiting for command"; + case DIR_CONN_STATE_SERVER_WRITING: return "writing"; + } + break; + case CONN_TYPE_CPUWORKER: + switch (state) { + case CPUWORKER_STATE_IDLE: return "idle"; + case CPUWORKER_STATE_BUSY_ONION: return "busy with onion"; + } + break; + case CONN_TYPE_CONTROL: + switch (state) { + case CONTROL_CONN_STATE_OPEN: return "open (protocol v1)"; + case CONTROL_CONN_STATE_NEEDAUTH: + return "waiting for authentication (protocol v1)"; + } + break; + } + + log_warn(LD_BUG, "unknown connection state %d (type %d)", state, type); + tor_snprintf(buf, sizeof(buf), + "unknown state [%d] on unknown [%s] connection", + state, conn_type_to_string(type)); + return buf; +} + +#ifdef USE_BUFFEREVENTS +/** Return true iff the connection's type is one that can use a + bufferevent-based implementation. */ +int +connection_type_uses_bufferevent(connection_t *conn) +{ + switch (conn->type) { + case CONN_TYPE_AP: + case CONN_TYPE_EXIT: + case CONN_TYPE_DIR: + case CONN_TYPE_CONTROL: + case CONN_TYPE_OR: + case CONN_TYPE_EXT_OR: + case CONN_TYPE_CPUWORKER: + return 1; + default: + return 0; + } +} +#endif + +/** Allocate and return a new dir_connection_t, initialized as by + * connection_init(). */ +dir_connection_t * +dir_connection_new(int socket_family) +{ + dir_connection_t *dir_conn = tor_malloc_zero(sizeof(dir_connection_t)); + connection_init(time(NULL), TO_CONN(dir_conn), CONN_TYPE_DIR, socket_family); + return dir_conn; +} + +/** Allocate and return a new or_connection_t, initialized as by + * connection_init(). + * + * Set timestamp_last_added_nonpadding to now. + * + * Assign a pseudorandom next_circ_id between 0 and 2**15. + * + * Initialize active_circuit_pqueue. + * + * Set active_circuit_pqueue_last_recalibrated to current cell_ewma tick. + */ +or_connection_t * +or_connection_new(int type, int socket_family) +{ + or_connection_t *or_conn = tor_malloc_zero(sizeof(or_connection_t)); + time_t now = time(NULL); + tor_assert(type == CONN_TYPE_OR || type == CONN_TYPE_EXT_OR); + connection_init(now, TO_CONN(or_conn), type, socket_family); + + or_conn->timestamp_last_added_nonpadding = time(NULL); + + if (type == CONN_TYPE_EXT_OR) + connection_or_set_ext_or_identifier(or_conn); + + return or_conn; +} + +/** Allocate and return a new entry_connection_t, initialized as by + * connection_init(). + * + * Allocate space to store the socks_request. + */ +entry_connection_t * +entry_connection_new(int type, int socket_family) +{ + entry_connection_t *entry_conn = tor_malloc_zero(sizeof(entry_connection_t)); + tor_assert(type == CONN_TYPE_AP); + connection_init(time(NULL), ENTRY_TO_CONN(entry_conn), type, socket_family); + entry_conn->socks_request = socks_request_new(); + /* If this is coming from a listener, we'll set it up based on the listener + * in a little while. Otherwise, we're doing this as a linked connection + * of some kind, and we should set it up here based on the socket family */ + if (socket_family == AF_INET) + entry_conn->ipv4_traffic_ok = 1; + else if (socket_family == AF_INET6) + entry_conn->ipv6_traffic_ok = 1; + return entry_conn; +} + +/** Allocate and return a new edge_connection_t, initialized as by + * connection_init(). */ +edge_connection_t * +edge_connection_new(int type, int socket_family) +{ + edge_connection_t *edge_conn = tor_malloc_zero(sizeof(edge_connection_t)); + tor_assert(type == CONN_TYPE_EXIT); + connection_init(time(NULL), TO_CONN(edge_conn), type, socket_family); + return edge_conn; +} + +/** Allocate and return a new control_connection_t, initialized as by + * connection_init(). */ +control_connection_t * +control_connection_new(int socket_family) +{ + control_connection_t *control_conn = + tor_malloc_zero(sizeof(control_connection_t)); + connection_init(time(NULL), + TO_CONN(control_conn), CONN_TYPE_CONTROL, socket_family); + return control_conn; +} + +/** Allocate and return a new listener_connection_t, initialized as by + * connection_init(). */ +listener_connection_t * +listener_connection_new(int type, int socket_family) +{ + listener_connection_t *listener_conn = + tor_malloc_zero(sizeof(listener_connection_t)); + connection_init(time(NULL), TO_CONN(listener_conn), type, socket_family); + return listener_conn; +} + +/** Allocate, initialize, and return a new connection_t subtype of type + * to make or receive connections of address family socket_family. The + * type should be one of the CONN_TYPE_* constants. */ +connection_t * +connection_new(int type, int socket_family) +{ + switch (type) { + case CONN_TYPE_OR: + case CONN_TYPE_EXT_OR: + return TO_CONN(or_connection_new(type, socket_family)); + + case CONN_TYPE_EXIT: + return TO_CONN(edge_connection_new(type, socket_family)); + + case CONN_TYPE_AP: + return ENTRY_TO_CONN(entry_connection_new(type, socket_family)); + + case CONN_TYPE_DIR: + return TO_CONN(dir_connection_new(socket_family)); + + case CONN_TYPE_CONTROL: + return TO_CONN(control_connection_new(socket_family)); + + CASE_ANY_LISTENER_TYPE: + return TO_CONN(listener_connection_new(type, socket_family)); + + default: { + connection_t *conn = tor_malloc_zero(sizeof(connection_t)); + connection_init(time(NULL), conn, type, socket_family); + return conn; + } + } +} + +/** Initializes conn. (you must call connection_add() to link it into the main + * array). + * + * Set conn-\>magic to the correct value. + * + * Set conn-\>type to type. Set conn-\>s and conn-\>conn_array_index to + * -1 to signify they are not yet assigned. + * + * Initialize conn's timestamps to now. + */ +static void +connection_init(time_t now, connection_t *conn, int type, int socket_family) +{ + static uint64_t n_connections_allocated = 1; + + switch (type) { + case CONN_TYPE_OR: + case CONN_TYPE_EXT_OR: + conn->magic = OR_CONNECTION_MAGIC; + break; + case CONN_TYPE_EXIT: + conn->magic = EDGE_CONNECTION_MAGIC; + break; + case CONN_TYPE_AP: + conn->magic = ENTRY_CONNECTION_MAGIC; + break; + case CONN_TYPE_DIR: + conn->magic = DIR_CONNECTION_MAGIC; + break; + case CONN_TYPE_CONTROL: + conn->magic = CONTROL_CONNECTION_MAGIC; + break; + CASE_ANY_LISTENER_TYPE: + conn->magic = LISTENER_CONNECTION_MAGIC; + break; + default: + conn->magic = BASE_CONNECTION_MAGIC; + break; + } + + conn->s = TOR_INVALID_SOCKET; /* give it a default of 'not used' */ + conn->conn_array_index = -1; /* also default to 'not used' */ + conn->global_identifier = n_connections_allocated++; + + conn->type = type; + conn->socket_family = socket_family; +#ifndef USE_BUFFEREVENTS + if (!connection_is_listener(conn)) { + /* listeners never use their buf */ + conn->inbuf = buf_new(); + conn->outbuf = buf_new(); + } +#endif + + conn->timestamp_created = now; + conn->timestamp_lastread = now; + conn->timestamp_lastwritten = now; +} + +/** Create a link between conn_a and conn_b. */ +void +connection_link_connections(connection_t *conn_a, connection_t *conn_b) +{ + tor_assert(! SOCKET_OK(conn_a->s)); + tor_assert(! SOCKET_OK(conn_b->s)); + + conn_a->linked = 1; + conn_b->linked = 1; + conn_a->linked_conn = conn_b; + conn_b->linked_conn = conn_a; +} + +/** Deallocate memory used by conn. Deallocate its buffers if + * necessary, close its socket if necessary, and mark the directory as dirty + * if conn is an OR or OP connection. + */ +STATIC void +connection_free_(connection_t *conn) +{ + void *mem; + size_t memlen; + if (!conn) + return; + + switch (conn->type) { + case CONN_TYPE_OR: + case CONN_TYPE_EXT_OR: + tor_assert(conn->magic == OR_CONNECTION_MAGIC); + mem = TO_OR_CONN(conn); + memlen = sizeof(or_connection_t); + break; + case CONN_TYPE_AP: + tor_assert(conn->magic == ENTRY_CONNECTION_MAGIC); + mem = TO_ENTRY_CONN(conn); + memlen = sizeof(entry_connection_t); + break; + case CONN_TYPE_EXIT: + tor_assert(conn->magic == EDGE_CONNECTION_MAGIC); + mem = TO_EDGE_CONN(conn); + memlen = sizeof(edge_connection_t); + break; + case CONN_TYPE_DIR: + tor_assert(conn->magic == DIR_CONNECTION_MAGIC); + mem = TO_DIR_CONN(conn); + memlen = sizeof(dir_connection_t); + break; + case CONN_TYPE_CONTROL: + tor_assert(conn->magic == CONTROL_CONNECTION_MAGIC); + mem = TO_CONTROL_CONN(conn); + memlen = sizeof(control_connection_t); + break; + CASE_ANY_LISTENER_TYPE: + tor_assert(conn->magic == LISTENER_CONNECTION_MAGIC); + mem = TO_LISTENER_CONN(conn); + memlen = sizeof(listener_connection_t); + break; + default: + tor_assert(conn->magic == BASE_CONNECTION_MAGIC); + mem = conn; + memlen = sizeof(connection_t); + break; + } + + if (conn->linked) { + log_info(LD_GENERAL, "Freeing linked %s connection [%s] with %d " + "bytes on inbuf, %d on outbuf.", + conn_type_to_string(conn->type), + conn_state_to_string(conn->type, conn->state), + (int)connection_get_inbuf_len(conn), + (int)connection_get_outbuf_len(conn)); + } + + if (!connection_is_listener(conn)) { + buf_free(conn->inbuf); + buf_free(conn->outbuf); + } else { + if (conn->socket_family == AF_UNIX) { + /* For now only control ports can be Unix domain sockets + * and listeners at the same time */ + tor_assert(conn->type == CONN_TYPE_CONTROL_LISTENER); + + if (unlink(conn->address) < 0 && errno != ENOENT) { + log_warn(LD_NET, "Could not unlink %s: %s", conn->address, + strerror(errno)); + } + } + } + + tor_free(conn->address); + + if (connection_speaks_cells(conn)) { + or_connection_t *or_conn = TO_OR_CONN(conn); + tor_tls_free(or_conn->tls); + or_conn->tls = NULL; + or_handshake_state_free(or_conn->handshake_state); + or_conn->handshake_state = NULL; + tor_free(or_conn->nickname); + if (or_conn->chan) { + /* Owww, this shouldn't happen, but... */ + log_info(LD_CHANNEL, + "Freeing orconn at %p, saw channel %p with ID " + U64_FORMAT " left un-NULLed", + or_conn, TLS_CHAN_TO_BASE(or_conn->chan), + U64_PRINTF_ARG( + TLS_CHAN_TO_BASE(or_conn->chan)->global_identifier)); + if (!(TLS_CHAN_TO_BASE(or_conn->chan)->state == CHANNEL_STATE_CLOSED || + TLS_CHAN_TO_BASE(or_conn->chan)->state == CHANNEL_STATE_ERROR)) { + channel_close_for_error(TLS_CHAN_TO_BASE(or_conn->chan)); + } + + or_conn->chan->conn = NULL; + or_conn->chan = NULL; + } + } + if (conn->type == CONN_TYPE_AP) { + entry_connection_t *entry_conn = TO_ENTRY_CONN(conn); + tor_free(entry_conn->chosen_exit_name); + tor_free(entry_conn->original_dest_address); + if (entry_conn->socks_request) + socks_request_free(entry_conn->socks_request); + if (entry_conn->pending_optimistic_data) { + generic_buffer_free(entry_conn->pending_optimistic_data); + } + if (entry_conn->sending_optimistic_data) { + generic_buffer_free(entry_conn->sending_optimistic_data); + } + } + if (CONN_IS_EDGE(conn)) { + rend_data_free(TO_EDGE_CONN(conn)->rend_data); + } + if (conn->type == CONN_TYPE_CONTROL) { + control_connection_t *control_conn = TO_CONTROL_CONN(conn); + tor_free(control_conn->safecookie_client_hash); + tor_free(control_conn->incoming_cmd); + } + + tor_free(conn->read_event); /* Probably already freed by connection_free. */ + tor_free(conn->write_event); /* Probably already freed by connection_free. */ + IF_HAS_BUFFEREVENT(conn, { + /* This was a workaround to handle bugs in some old versions of libevent + * where callbacks can occur after calling bufferevent_free(). Setting + * the callbacks to NULL prevented this. It shouldn't be necessary any + * more, but let's not tempt fate for now. */ + bufferevent_setcb(conn->bufev, NULL, NULL, NULL, NULL); + bufferevent_free(conn->bufev); + conn->bufev = NULL; + }); + + if (conn->type == CONN_TYPE_DIR) { + dir_connection_t *dir_conn = TO_DIR_CONN(conn); + tor_free(dir_conn->requested_resource); + + tor_zlib_free(dir_conn->zlib_state); + if (dir_conn->fingerprint_stack) { + SMARTLIST_FOREACH(dir_conn->fingerprint_stack, char *, cp, tor_free(cp)); + smartlist_free(dir_conn->fingerprint_stack); + } + + cached_dir_decref(dir_conn->cached_dir); + rend_data_free(dir_conn->rend_data); + } + + if (SOCKET_OK(conn->s)) { + log_debug(LD_NET,"closing fd %d.",(int)conn->s); + tor_close_socket(conn->s); + conn->s = TOR_INVALID_SOCKET; + } + + if (conn->type == CONN_TYPE_OR && + !tor_digest_is_zero(TO_OR_CONN(conn)->identity_digest)) { + log_warn(LD_BUG, "called on OR conn with non-zeroed identity_digest"); + connection_or_remove_from_identity_map(TO_OR_CONN(conn)); + } + if (conn->type == CONN_TYPE_OR || conn->type == CONN_TYPE_EXT_OR) { + connection_or_remove_from_ext_or_id_map(TO_OR_CONN(conn)); + tor_free(TO_OR_CONN(conn)->ext_or_conn_id); + tor_free(TO_OR_CONN(conn)->ext_or_auth_correct_client_hash); + tor_free(TO_OR_CONN(conn)->ext_or_transport); + } + +#ifdef USE_BUFFEREVENTS + if (conn->type == CONN_TYPE_OR && TO_OR_CONN(conn)->bucket_cfg) { + ev_token_bucket_cfg_free(TO_OR_CONN(conn)->bucket_cfg); + TO_OR_CONN(conn)->bucket_cfg = NULL; + } +#endif + + memwipe(mem, 0xCC, memlen); /* poison memory */ + tor_free(mem); +} + +/** Make sure conn isn't in any of the global conn lists; then free it. + */ +void +connection_free(connection_t *conn) +{ + if (!conn) + return; + tor_assert(!connection_is_on_closeable_list(conn)); + tor_assert(!connection_in_array(conn)); + if (conn->linked_conn) { + log_err(LD_BUG, "Called with conn->linked_conn still set."); + tor_fragile_assert(); + conn->linked_conn->linked_conn = NULL; + if (! conn->linked_conn->marked_for_close && + conn->linked_conn->reading_from_linked_conn) + connection_start_reading(conn->linked_conn); + conn->linked_conn = NULL; + } + if (connection_speaks_cells(conn)) { + if (!tor_digest_is_zero(TO_OR_CONN(conn)->identity_digest)) { + connection_or_remove_from_identity_map(TO_OR_CONN(conn)); + } + } + if (conn->type == CONN_TYPE_CONTROL) { + connection_control_closed(TO_CONTROL_CONN(conn)); + } + connection_unregister_events(conn); + connection_free_(conn); +} + +/** + * Called when we're about to finally unlink and free a connection: + * perform necessary accounting and cleanup + * - Directory conns that failed to fetch a rendezvous descriptor + * need to inform pending rendezvous streams. + * - OR conns need to call rep_hist_note_*() to record status. + * - AP conns need to send a socks reject if necessary. + * - Exit conns need to call connection_dns_remove() if necessary. + * - AP and Exit conns need to send an end cell if they can. + * - DNS conns need to fail any resolves that are pending on them. + * - OR and edge connections need to be unlinked from circuits. + */ +void +connection_about_to_close_connection(connection_t *conn) +{ + tor_assert(conn->marked_for_close); + + switch (conn->type) { + case CONN_TYPE_DIR: + connection_dir_about_to_close(TO_DIR_CONN(conn)); + break; + case CONN_TYPE_OR: + case CONN_TYPE_EXT_OR: + connection_or_about_to_close(TO_OR_CONN(conn)); + break; + case CONN_TYPE_AP: + connection_ap_about_to_close(TO_ENTRY_CONN(conn)); + break; + case CONN_TYPE_EXIT: + connection_exit_about_to_close(TO_EDGE_CONN(conn)); + break; + } +} + +/** Return true iff connection_close_immediate() has been called on this + * connection. */ +#define CONN_IS_CLOSED(c) \ + ((c)->linked ? ((c)->linked_conn_is_closed) : (! SOCKET_OK(c->s))) + +/** Close the underlying socket for conn, so we don't try to + * flush it. Must be used in conjunction with (right before) + * connection_mark_for_close(). + */ +void +connection_close_immediate(connection_t *conn) +{ + assert_connection_ok(conn,0); + if (CONN_IS_CLOSED(conn)) { + log_err(LD_BUG,"Attempt to close already-closed connection."); + tor_fragile_assert(); + return; + } + if (conn->outbuf_flushlen) { + log_info(LD_NET,"fd %d, type %s, state %s, %d bytes on outbuf.", + (int)conn->s, conn_type_to_string(conn->type), + conn_state_to_string(conn->type, conn->state), + (int)conn->outbuf_flushlen); + } + + connection_unregister_events(conn); + + if (SOCKET_OK(conn->s)) + tor_close_socket(conn->s); + conn->s = TOR_INVALID_SOCKET; + if (conn->linked) + conn->linked_conn_is_closed = 1; + if (conn->outbuf) + buf_clear(conn->outbuf); + conn->outbuf_flushlen = 0; +} + +/** Mark conn to be closed next time we loop through + * conn_close_if_marked() in onion_main.c. */ +void +connection_mark_for_close_(connection_t *conn, int line, const char *file) +{ + assert_connection_ok(conn,0); + tor_assert(line); + tor_assert(line < 1<<16); /* marked_for_close can only fit a uint16_t. */ + tor_assert(file); + + if (conn->type == CONN_TYPE_OR) { + /* + * An or_connection should have been closed through one of the channel- + * aware functions in connection_or.c. We'll assume this is an error + * close and do that, and log a bug warning. + */ + log_warn(LD_CHANNEL | LD_BUG, + "Something tried to close an or_connection_t without going " + "through channels at %s:%d", + file, line); + connection_or_close_for_error(TO_OR_CONN(conn), 0); + } else { + /* Pass it down to the real function */ + connection_mark_for_close_internal_(conn, line, file); + } +} + +/** Mark conn to be closed next time we loop through + * conn_close_if_marked() in onion_main.c; the _internal version bypasses the + * CONN_TYPE_OR checks; this should be called when you either are sure that + * if this is an or_connection_t the controlling channel has been notified + * (e.g. with connection_or_notify_error()), or you actually are the + * connection_or_close_for_error() or connection_or_close_normally function. + * For all other cases, use connection_mark_and_flush() instead, which + * checks for or_connection_t properly, instead. See below. + */ +void +connection_mark_for_close_internal_(connection_t *conn, + int line, const char *file) +{ + assert_connection_ok(conn,0); + tor_assert(line); + tor_assert(line < 1<<16); /* marked_for_close can only fit a uint16_t. */ + tor_assert(file); + + if (conn->marked_for_close) { + log_warn(LD_BUG,"Duplicate call to connection_mark_for_close at %s:%d" + " (first at %s:%d)", file, line, conn->marked_for_close_file, + conn->marked_for_close); + tor_fragile_assert(); + return; + } + + if (conn->type == CONN_TYPE_OR) { + /* + * Bad news if this happens without telling the controlling channel; do + * this so we can find things that call this wrongly when the asserts hit. + */ + log_debug(LD_CHANNEL, + "Calling connection_mark_for_close_internal_() on an OR conn " + "at %s:%d", + file, line); + } + + conn->marked_for_close = line; + conn->marked_for_close_file = file; + add_connection_to_closeable_list(conn); + + /* in case we're going to be held-open-til-flushed, reset + * the number of seconds since last successful write, so + * we get our whole 15 seconds */ + conn->timestamp_lastwritten = time(NULL); +} + +/** Find each connection that has hold_open_until_flushed set to + * 1 but hasn't written in the past 15 seconds, and set + * hold_open_until_flushed to 0. This means it will get cleaned + * up in the next loop through close_if_marked() in onion_main.c. + */ +void +connection_expire_held_open(void) +{ + time_t now; + smartlist_t *conns = get_connection_array(); + + now = time(NULL); + + SMARTLIST_FOREACH_BEGIN(conns, connection_t *, conn) { + /* If we've been holding the connection open, but we haven't written + * for 15 seconds... + */ + if (conn->hold_open_until_flushed) { + tor_assert(conn->marked_for_close); + if (now - conn->timestamp_lastwritten >= 15) { + int severity; + if (conn->type == CONN_TYPE_EXIT || + (conn->type == CONN_TYPE_DIR && + conn->purpose == DIR_PURPOSE_SERVER)) + severity = LOG_INFO; + else + severity = LOG_NOTICE; + log_fn(severity, LD_NET, + "Giving up on marked_for_close conn that's been flushing " + "for 15s (fd %d, type %s, state %s).", + (int)conn->s, conn_type_to_string(conn->type), + conn_state_to_string(conn->type, conn->state)); + conn->hold_open_until_flushed = 0; + } + } + } SMARTLIST_FOREACH_END(conn); +} + +#if defined(HAVE_SYS_UN_H) || defined(RUNNING_DOXYGEN) +/** Create an AF_UNIX listenaddr struct. + * listenaddress provides the path to the Unix socket. + * + * Eventually listenaddress will also optionally contain user, group, + * and file permissions for the new socket. But not yet. XXX + * Also, since we do not create the socket here the information doesn't help + * here. + * + * If not NULL readable_address will contain a copy of the path part of + * listenaddress. + * + * The listenaddr struct has to be freed by the caller. + */ +static struct sockaddr_un * +create_unix_sockaddr(const char *listenaddress, char **readable_address, + socklen_t *len_out) +{ + struct sockaddr_un *sockaddr = NULL; + + sockaddr = tor_malloc_zero(sizeof(struct sockaddr_un)); + sockaddr->sun_family = AF_UNIX; + if (strlcpy(sockaddr->sun_path, listenaddress, sizeof(sockaddr->sun_path)) + >= sizeof(sockaddr->sun_path)) { + log_warn(LD_CONFIG, "Unix socket path '%s' is too long to fit.", + escaped(listenaddress)); + tor_free(sockaddr); + return NULL; + } + + if (readable_address) + *readable_address = tor_strdup(listenaddress); + + *len_out = sizeof(struct sockaddr_un); + return sockaddr; +} +#else +static struct sockaddr * +create_unix_sockaddr(const char *listenaddress, char **readable_address, + socklen_t *len_out) +{ + (void)listenaddress; + (void)readable_address; + log_fn(LOG_ERR, LD_BUG, + "Unix domain sockets not supported, yet we tried to create one."); + *len_out = 0; + tor_fragile_assert(); + return NULL; +} +#endif /* HAVE_SYS_UN_H */ + +/** Warn that an accept or a connect has failed because we're running up + * against our ulimit. Rate-limit these warnings so that we don't spam + * the log. */ +static void +warn_too_many_conns(void) +{ +#define WARN_TOO_MANY_CONNS_INTERVAL (6*60*60) + static ratelim_t last_warned = RATELIM_INIT(WARN_TOO_MANY_CONNS_INTERVAL); + char *m; + if ((m = rate_limit_log(&last_warned, approx_time()))) { + int n_conns = get_n_open_sockets(); + log_warn(LD_NET,"Failing because we have %d connections already. Please " + "raise your ulimit -n.%s", n_conns, m); + tor_free(m); + control_event_general_status(LOG_WARN, "TOO_MANY_CONNECTIONS CURRENT=%d", + n_conns); + } +} + +#ifdef HAVE_SYS_UN_H +/** Check whether we should be willing to open an AF_UNIX socket in + * path. Return 0 if we should go ahead and -1 if we shouldn't. */ +static int +check_location_for_unix_socket(const or_options_t *options, const char *path) +{ + int r = -1; + char *p = tor_strdup(path); + cpd_check_t flags = CPD_CHECK_MODE_ONLY; + if (get_parent_directory(p)<0 || p[0] != '/') { + log_warn(LD_GENERAL, "Bad unix socket address '%s'. Tor does not support " + "relative paths for unix sockets.", path); + goto done; + } + + if (options->ControlSocketsGroupWritable) + flags |= CPD_GROUP_OK; + + if (check_private_dir(p, flags, options->User) < 0) { + char *escpath, *escdir; + escpath = esc_for_log(path); + escdir = esc_for_log(p); + log_warn(LD_GENERAL, "Before Tor can create a control socket in %s, the " + "directory %s needs to exist, and to be accessible only by the " + "user%s account that is running Tor. (On some Unix systems, " + "anybody who can list a socket can connect to it, so Tor is " + "being careful.)", escpath, escdir, + options->ControlSocketsGroupWritable ? " and group" : ""); + tor_free(escpath); + tor_free(escdir); + goto done; + } + + r = 0; + done: + tor_free(p); + return r; +} +#endif + +/** Tell the TCP stack that it shouldn't wait for a long time after + * sock has closed before reusing its port. */ +static void +make_socket_reuseable(tor_socket_t sock) +{ +#ifdef _WIN32 + (void) sock; +#else + int one=1; + + /* REUSEADDR on normal places means you can rebind to the port + * right after somebody else has let it go. But REUSEADDR on win32 + * means you can bind to the port _even when somebody else + * already has it bound_. So, don't do that on Win32. */ + if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void*) &one, + (socklen_t)sizeof(one)) == -1) { + log_warn(LD_NET, "Error setting SO_REUSEADDR flag: %s", + tor_socket_strerror(errno)); + } +#endif +} + +/** Max backlog to pass to listen. We start at */ +static int listen_limit = INT_MAX; + +/* Listen on fd with appropriate backlog. Return as for listen. */ +static int +tor_listen(tor_socket_t fd) +{ + int r; + + if ((r = listen(fd, listen_limit)) < 0) { + if (listen_limit == SOMAXCONN) + return r; + if ((r = listen(fd, SOMAXCONN)) == 0) { + listen_limit = SOMAXCONN; + log_warn(LD_NET, "Setting listen backlog to INT_MAX connections " + "didn't work, but SOMAXCONN did. Lowering backlog limit."); + } + } + return r; +} + +/** Bind a new non-blocking socket listening to the socket described + * by listensockaddr. + * + * address is only used for logging purposes and to add the information + * to the conn. + */ +static connection_t * +connection_listener_new(const struct sockaddr *listensockaddr, + socklen_t socklen, + int type, const char *address, + const port_cfg_t *port_cfg) +{ + listener_connection_t *lis_conn; + connection_t *conn = NULL; + tor_socket_t s = TOR_INVALID_SOCKET; /* the socket we're going to make */ + or_options_t const *options = get_options(); +#if defined(HAVE_PWD_H) && defined(HAVE_SYS_UN_H) + struct passwd *pw = NULL; +#endif + uint16_t usePort = 0, gotPort = 0; + int start_reading = 0; + static int global_next_session_group = SESSION_GROUP_FIRST_AUTO; + tor_addr_t addr; + + if (get_n_open_sockets() >= get_options()->ConnLimit_-1) { + warn_too_many_conns(); + return NULL; + } + + if (listensockaddr->sa_family == AF_INET || + listensockaddr->sa_family == AF_INET6) { + int is_tcp = (type != CONN_TYPE_AP_DNS_LISTENER); + if (is_tcp) + start_reading = 1; + + tor_addr_from_sockaddr(&addr, listensockaddr, &usePort); + + log_notice(LD_NET, "Opening %s on %s", + conn_type_to_string(type), fmt_addrport(&addr, usePort)); + + s = tor_open_socket_nonblocking(tor_addr_family(&addr), + is_tcp ? SOCK_STREAM : SOCK_DGRAM, + is_tcp ? IPPROTO_TCP: IPPROTO_UDP); + if (!SOCKET_OK(s)) { + log_warn(LD_NET,"Socket creation failed: %s", + tor_socket_strerror(tor_socket_errno(-1))); + goto err; + } + + make_socket_reuseable(s); + +#if defined USE_TRANSPARENT && defined(IP_TRANSPARENT) + if (options->TransProxyType_parsed == TPT_TPROXY && + type == CONN_TYPE_AP_TRANS_LISTENER) { + int one = 1; + if (setsockopt(s, SOL_IP, IP_TRANSPARENT, &one, sizeof(one)) < 0) { + const char *extra = ""; + int e = tor_socket_errno(s); + if (e == EPERM) + extra = "TransTPROXY requires root privileges or similar" + " capabilities."; + log_warn(LD_NET, "Error setting IP_TRANSPARENT flag: %s.%s", + tor_socket_strerror(e), extra); + } + } +#endif + +#ifdef IPV6_V6ONLY + if (listensockaddr->sa_family == AF_INET6) { +#ifdef _WIN32 + /* In Redmond, this kind of thing passes for standards-conformance. */ + DWORD one = 1; +#else + int one = 1; +#endif + /* We need to set IPV6_V6ONLY so that this socket can't get used for + * IPv4 connections. */ + if (setsockopt(s,IPPROTO_IPV6, IPV6_V6ONLY, + (void*)&one, sizeof(one)) < 0) { + int e = tor_socket_errno(s); + log_warn(LD_NET, "Error setting IPV6_V6ONLY flag: %s", + tor_socket_strerror(e)); + /* Keep going; probably not harmful. */ + } + } +#endif + + if (bind(s,listensockaddr,socklen) < 0) { + const char *helpfulhint = ""; + int e = tor_socket_errno(s); + if (ERRNO_IS_EADDRINUSE(e)) + helpfulhint = ". Is Tor already running?"; + log_warn(LD_NET, "Could not bind to %s:%u: %s%s", address, usePort, + tor_socket_strerror(e), helpfulhint); + goto err; + } + + if (is_tcp) { + if (tor_listen(s) < 0) { + log_warn(LD_NET, "Could not listen on %s:%u: %s", address, usePort, + tor_socket_strerror(tor_socket_errno(s))); + goto err; + } + } + + if (usePort != 0) { + gotPort = usePort; + } else { + tor_addr_t addr2; + struct sockaddr_storage ss; + socklen_t ss_len=sizeof(ss); + if (getsockname(s, (struct sockaddr*)&ss, &ss_len)<0) { + log_warn(LD_NET, "getsockname() couldn't learn address for %s: %s", + conn_type_to_string(type), + tor_socket_strerror(tor_socket_errno(s))); + gotPort = 0; + } + tor_addr_from_sockaddr(&addr2, (struct sockaddr*)&ss, &gotPort); + } +#ifdef HAVE_SYS_UN_H + } else if (listensockaddr->sa_family == AF_UNIX) { + start_reading = 1; + + /* For now only control ports can be Unix domain sockets + * and listeners at the same time */ + tor_assert(type == CONN_TYPE_CONTROL_LISTENER); + + if (check_location_for_unix_socket(options, address) < 0) + goto err; + + log_notice(LD_NET, "Opening %s on %s", + conn_type_to_string(type), address); + + tor_addr_make_unspec(&addr); + + if (unlink(address) < 0 && errno != ENOENT) { + log_warn(LD_NET, "Could not unlink %s: %s", address, + strerror(errno)); + goto err; + } + s = tor_open_socket_nonblocking(AF_UNIX, SOCK_STREAM, 0); + if (! SOCKET_OK(s)) { + log_warn(LD_NET,"Socket creation failed: %s.", strerror(errno)); + goto err; + } + + if (bind(s, listensockaddr, (socklen_t)sizeof(struct sockaddr_un)) == -1) { + log_warn(LD_NET,"Bind to %s failed: %s.", address, + tor_socket_strerror(tor_socket_errno(s))); + goto err; + } +#ifdef HAVE_PWD_H + if (options->User) { + pw = getpwnam(options->User); + if (pw == NULL) { + log_warn(LD_NET,"Unable to chown() %s socket: user %s not found.", + address, options->User); + goto err; + } else if (chown(address, pw->pw_uid, pw->pw_gid) < 0) { + log_warn(LD_NET,"Unable to chown() %s socket: %s.", + address, strerror(errno)); + goto err; + } + } +#endif + if (options->ControlSocketsGroupWritable) { + /* We need to use chmod; fchmod doesn't work on sockets on all + * platforms. */ + if (chmod(address, 0660) < 0) { + log_warn(LD_FS,"Unable to make %s group-writable.", address); + goto err; + } + } + + if (listen(s, SOMAXCONN) < 0) { + log_warn(LD_NET, "Could not listen on %s: %s", address, + tor_socket_strerror(tor_socket_errno(s))); + goto err; + } +#else + (void)options; +#endif /* HAVE_SYS_UN_H */ + } else { + log_err(LD_BUG, "Got unexpected address family %d.", + listensockaddr->sa_family); + tor_assert(0); + } + + lis_conn = listener_connection_new(type, listensockaddr->sa_family); + conn = TO_CONN(lis_conn); + conn->socket_family = listensockaddr->sa_family; + conn->s = s; + s = TOR_INVALID_SOCKET; /* Prevent double-close */ + conn->address = tor_strdup(address); + conn->port = gotPort; + tor_addr_copy(&conn->addr, &addr); + + if (port_cfg->isolation_flags) { + lis_conn->isolation_flags = port_cfg->isolation_flags; + if (port_cfg->session_group >= 0) { + lis_conn->session_group = port_cfg->session_group; + } else { + /* This can wrap after around INT_MAX listeners are opened. But I don't + * believe that matters, since you would need to open a ridiculous + * number of listeners while keeping the early ones open before you ever + * hit this. An OR with a dozen ports open, for example, would have to + * close and re-open its listeners every second for 4 years nonstop. + */ + lis_conn->session_group = global_next_session_group--; + } + } + if (type == CONN_TYPE_AP_LISTENER) { + lis_conn->socks_ipv4_traffic = port_cfg->ipv4_traffic; + lis_conn->socks_ipv6_traffic = port_cfg->ipv6_traffic; + lis_conn->socks_prefer_ipv6 = port_cfg->prefer_ipv6; + } else { + lis_conn->socks_ipv4_traffic = 1; + lis_conn->socks_ipv6_traffic = 1; + } + lis_conn->cache_ipv4_answers = port_cfg->cache_ipv4_answers; + lis_conn->cache_ipv6_answers = port_cfg->cache_ipv6_answers; + lis_conn->use_cached_ipv4_answers = port_cfg->use_cached_ipv4_answers; + lis_conn->use_cached_ipv6_answers = port_cfg->use_cached_ipv6_answers; + lis_conn->prefer_ipv6_virtaddr = port_cfg->prefer_ipv6_virtaddr; + lis_conn->socks_prefer_no_auth = port_cfg->socks_prefer_no_auth; + + if (connection_add(conn) < 0) { /* no space, forget it */ + log_warn(LD_NET,"connection_add for listener failed. Giving up."); + goto err; + } + + log_fn(usePort==gotPort ? LOG_DEBUG : LOG_NOTICE, LD_NET, + "%s listening on port %u.", + conn_type_to_string(type), gotPort); + + conn->state = LISTENER_STATE_READY; + if (start_reading) { + connection_start_reading(conn); + } else { + tor_assert(type == CONN_TYPE_AP_DNS_LISTENER); + dnsserv_configure_listener(conn); + } + + return conn; + + err: + if (SOCKET_OK(s)) + tor_close_socket(s); + if (conn) + connection_free(conn); + + return NULL; +} + +/** Do basic sanity checking on a newly received socket. Return 0 + * if it looks ok, else return -1. + * + * Notably, some TCP stacks can erroneously have accept() return successfully + * with socklen 0, when the client sends an RST before the accept call (as + * nmap does). We want to detect that, and not go on with the connection. + */ +static int +check_sockaddr(const struct sockaddr *sa, int len, int level) +{ + int ok = 1; + + if (sa->sa_family == AF_INET) { + struct sockaddr_in *sin=(struct sockaddr_in*)sa; + if (len != sizeof(struct sockaddr_in)) { + log_fn(level, LD_NET, "Length of address not as expected: %d vs %d", + len,(int)sizeof(struct sockaddr_in)); + ok = 0; + } + if (sin->sin_addr.s_addr == 0 || sin->sin_port == 0) { + log_fn(level, LD_NET, + "Address for new connection has address/port equal to zero."); + ok = 0; + } + } else if (sa->sa_family == AF_INET6) { + struct sockaddr_in6 *sin6=(struct sockaddr_in6*)sa; + if (len != sizeof(struct sockaddr_in6)) { + log_fn(level, LD_NET, "Length of address not as expected: %d vs %d", + len,(int)sizeof(struct sockaddr_in6)); + ok = 0; + } + if (tor_mem_is_zero((void*)sin6->sin6_addr.s6_addr, 16) || + sin6->sin6_port == 0) { + log_fn(level, LD_NET, + "Address for new connection has address/port equal to zero."); + ok = 0; + } + } else { + ok = 0; + } + return ok ? 0 : -1; +} + +/** Check whether the socket family from an accepted socket got is the + * same as the one that listener is waiting for. If it isn't, log + * a useful message and return -1. Else return 0. + * + * This is annoying, but can apparently happen on some Darwins. */ +static int +check_sockaddr_family_match(sa_family_t got, connection_t *listener) +{ + if (got != listener->socket_family) { + log_info(LD_BUG, "A listener connection returned a socket with a " + "mismatched family. %s for addr_family %d gave us a socket " + "with address family %d. Dropping.", + conn_type_to_string(listener->type), + (int)listener->socket_family, + (int)got); + return -1; + } + return 0; +} + +/** The listener connection conn told poll() it wanted to read. + * Call accept() on conn-\>s, and add the new connection if necessary. + */ +static int +connection_handle_listener_read(connection_t *conn, int new_type) +{ + tor_socket_t news; /* the new socket */ + connection_t *newconn; + /* information about the remote peer when connecting to other routers */ + struct sockaddr_storage addrbuf; + struct sockaddr *remote = (struct sockaddr*)&addrbuf; + /* length of the remote address. Must be whatever accept() needs. */ + socklen_t remotelen = (socklen_t)sizeof(addrbuf); + const or_options_t *options = get_options(); + + tor_assert((size_t)remotelen >= sizeof(struct sockaddr_in)); + memset(&addrbuf, 0, sizeof(addrbuf)); + + news = tor_accept_socket_nonblocking(conn->s,remote,&remotelen); + if (!SOCKET_OK(news)) { /* accept() error */ + int e = tor_socket_errno(conn->s); + if (ERRNO_IS_ACCEPT_EAGAIN(e)) { + return 0; /* he hung up before we could accept(). that's fine. */ + } else if (ERRNO_IS_ACCEPT_RESOURCE_LIMIT(e)) { + warn_too_many_conns(); + return 0; + } + /* else there was a real error. */ + log_warn(LD_NET,"accept() failed: %s. Closing listener.", + tor_socket_strerror(e)); + connection_mark_for_close(conn); + return -1; + } + log_debug(LD_NET, + "Connection accepted on socket %d (child of fd %d).", + (int)news,(int)conn->s); + + make_socket_reuseable(news); + + if (options->ConstrainedSockets) + set_constrained_socket_buffers(news, (int)options->ConstrainedSockSize); + + if (check_sockaddr_family_match(remote->sa_family, conn) < 0) { + tor_close_socket(news); + return 0; + } + + if (conn->socket_family == AF_INET || conn->socket_family == AF_INET6) { + tor_addr_t addr; + uint16_t port; + if (check_sockaddr(remote, remotelen, LOG_INFO)<0) { + log_info(LD_NET, + "accept() returned a strange address; closing connection."); + tor_close_socket(news); + return 0; + } + + tor_addr_from_sockaddr(&addr, remote, &port); + + /* process entrance policies here, before we even create the connection */ + if (new_type == CONN_TYPE_AP) { + /* check sockspolicy to see if we should accept it */ + if (socks_policy_permits_address(&addr) == 0) { + log_notice(LD_APP, + "Denying socks connection from untrusted address %s.", + fmt_and_decorate_addr(&addr)); + tor_close_socket(news); + return 0; + } + } + if (new_type == CONN_TYPE_DIR) { + /* check dirpolicy to see if we should accept it */ + if (dir_policy_permits_address(&addr) == 0) { + log_notice(LD_DIRSERV,"Denying dir connection from address %s.", + fmt_and_decorate_addr(&addr)); + tor_close_socket(news); + return 0; + } + } + + newconn = connection_new(new_type, conn->socket_family); + newconn->s = news; + + /* remember the remote address */ + tor_addr_copy(&newconn->addr, &addr); + newconn->port = port; + newconn->address = tor_dup_addr(&addr); + + if (new_type == CONN_TYPE_AP) { + TO_ENTRY_CONN(newconn)->socks_request->socks_prefer_no_auth = + TO_LISTENER_CONN(conn)->socks_prefer_no_auth; + } + if (new_type == CONN_TYPE_CONTROL) { + log_notice(LD_CONTROL, "New control connection opened from %s.", + fmt_and_decorate_addr(&addr)); + } + + } else if (conn->socket_family == AF_UNIX) { + /* For now only control ports can be Unix domain sockets + * and listeners at the same time */ + tor_assert(conn->type == CONN_TYPE_CONTROL_LISTENER); + tor_assert(new_type == CONN_TYPE_CONTROL); + log_notice(LD_CONTROL, "New control connection opened."); + + newconn = connection_new(new_type, conn->socket_family); + newconn->s = news; + + /* remember the remote address -- do we have anything sane to put here? */ + tor_addr_make_unspec(&newconn->addr); + newconn->port = 1; + newconn->address = tor_strdup(conn->address); + } else { + tor_assert(0); + }; + + if (connection_add(newconn) < 0) { /* no space, forget it */ + connection_free(newconn); + return 0; /* no need to tear down the parent */ + } + + if (connection_init_accepted_conn(newconn, TO_LISTENER_CONN(conn)) < 0) { + if (! newconn->marked_for_close) + connection_mark_for_close(newconn); + return 0; + } + return 0; +} + +/** Initialize states for newly accepted connection conn. + * If conn is an OR, start the TLS handshake. + * If conn is a transparent AP, get its original destination + * and place it in circuit_wait. + */ +static int +connection_init_accepted_conn(connection_t *conn, + const listener_connection_t *listener) +{ + int rv; + + connection_start_reading(conn); + + switch (conn->type) { + case CONN_TYPE_EXT_OR: + /* Initiate Extended ORPort authentication. */ + return connection_ext_or_start_auth(TO_OR_CONN(conn)); + case CONN_TYPE_OR: + control_event_or_conn_status(TO_OR_CONN(conn), OR_CONN_EVENT_NEW, 0); + rv = connection_tls_start_handshake(TO_OR_CONN(conn), 1); + if (rv < 0) { + connection_or_close_for_error(TO_OR_CONN(conn), 0); + } + return rv; + break; + case CONN_TYPE_AP: + TO_ENTRY_CONN(conn)->isolation_flags = listener->isolation_flags; + TO_ENTRY_CONN(conn)->session_group = listener->session_group; + TO_ENTRY_CONN(conn)->nym_epoch = get_signewnym_epoch(); + TO_ENTRY_CONN(conn)->socks_request->listener_type = listener->base_.type; + TO_ENTRY_CONN(conn)->ipv4_traffic_ok = listener->socks_ipv4_traffic; + TO_ENTRY_CONN(conn)->ipv6_traffic_ok = listener->socks_ipv6_traffic; + TO_ENTRY_CONN(conn)->prefer_ipv6_traffic = listener->socks_prefer_ipv6; + TO_ENTRY_CONN(conn)->cache_ipv4_answers = listener->cache_ipv4_answers; + TO_ENTRY_CONN(conn)->cache_ipv6_answers = listener->cache_ipv6_answers; + TO_ENTRY_CONN(conn)->use_cached_ipv4_answers = + listener->use_cached_ipv4_answers; + TO_ENTRY_CONN(conn)->use_cached_ipv6_answers = + listener->use_cached_ipv6_answers; + TO_ENTRY_CONN(conn)->prefer_ipv6_virtaddr = + listener->prefer_ipv6_virtaddr; + + switch (TO_CONN(listener)->type) { + case CONN_TYPE_AP_LISTENER: + conn->state = AP_CONN_STATE_SOCKS_WAIT; + break; + case CONN_TYPE_AP_TRANS_LISTENER: + TO_ENTRY_CONN(conn)->is_transparent_ap = 1; + conn->state = AP_CONN_STATE_CIRCUIT_WAIT; + return connection_ap_process_transparent(TO_ENTRY_CONN(conn)); + case CONN_TYPE_AP_NATD_LISTENER: + TO_ENTRY_CONN(conn)->is_transparent_ap = 1; + conn->state = AP_CONN_STATE_NATD_WAIT; + break; + } + break; + case CONN_TYPE_DIR: + conn->purpose = DIR_PURPOSE_SERVER; + conn->state = DIR_CONN_STATE_SERVER_COMMAND_WAIT; + break; + case CONN_TYPE_CONTROL: + conn->state = CONTROL_CONN_STATE_NEEDAUTH; + break; + } + return 0; +} + +/** Take conn, make a nonblocking socket; try to connect to + * addr:port (they arrive in *host order*). If fail, return -1 and if + * applicable put your best guess about errno into *socket_error. + * Else assign s to conn-\>s: if connected return 1, if EAGAIN return 0. + * + * address is used to make the logs useful. + * + * On success, add conn to the list of polled connections. + */ +int +connection_connect(connection_t *conn, const char *address, + const tor_addr_t *addr, uint16_t port, int *socket_error) +{ + tor_socket_t s; + int inprogress = 0; + struct sockaddr_storage addrbuf; + struct sockaddr *dest_addr; + int dest_addr_len; + const or_options_t *options = get_options(); + int protocol_family; + + if (get_n_open_sockets() >= get_options()->ConnLimit_-1) { + warn_too_many_conns(); + *socket_error = SOCK_ERRNO(ENOBUFS); + return -1; + } + + if (tor_addr_family(addr) == AF_INET6) + protocol_family = PF_INET6; + else + protocol_family = PF_INET; + + if (get_options()->DisableNetwork) { + /* We should never even try to connect anyplace if DisableNetwork is set. + * Warn if we do, and refuse to make the connection. */ + static ratelim_t disablenet_violated = RATELIM_INIT(30*60); + *socket_error = SOCK_ERRNO(ENETUNREACH); + log_fn_ratelim(&disablenet_violated, LOG_WARN, LD_BUG, + "Tried to open a socket with DisableNetwork set."); + tor_fragile_assert(); + return -1; + } + + s = tor_open_socket_nonblocking(protocol_family,SOCK_STREAM,IPPROTO_TCP); + if (! SOCKET_OK(s)) { + *socket_error = tor_socket_errno(-1); + log_warn(LD_NET,"Error creating network socket: %s", + tor_socket_strerror(*socket_error)); + return -1; + } + + make_socket_reuseable(s); + + if (!tor_addr_is_loopback(addr)) { + const tor_addr_t *ext_addr = NULL; + if (protocol_family == AF_INET && + !tor_addr_is_null(&options->OutboundBindAddressIPv4_)) + ext_addr = &options->OutboundBindAddressIPv4_; + else if (protocol_family == AF_INET6 && + !tor_addr_is_null(&options->OutboundBindAddressIPv6_)) + ext_addr = &options->OutboundBindAddressIPv6_; + if (ext_addr) { + struct sockaddr_storage ext_addr_sa; + socklen_t ext_addr_len = 0; + memset(&ext_addr_sa, 0, sizeof(ext_addr_sa)); + ext_addr_len = tor_addr_to_sockaddr(ext_addr, 0, + (struct sockaddr *) &ext_addr_sa, + sizeof(ext_addr_sa)); + if (ext_addr_len == 0) { + log_warn(LD_NET, + "Error converting OutboundBindAddress %s into sockaddr. " + "Ignoring.", fmt_and_decorate_addr(ext_addr)); + } else { + if (bind(s, (struct sockaddr *) &ext_addr_sa, ext_addr_len) < 0) { + *socket_error = tor_socket_errno(s); + log_warn(LD_NET,"Error binding network socket to %s: %s", + fmt_and_decorate_addr(ext_addr), + tor_socket_strerror(*socket_error)); + tor_close_socket(s); + return -1; + } + } + } + } + + if (options->ConstrainedSockets) + set_constrained_socket_buffers(s, (int)options->ConstrainedSockSize); + + memset(&addrbuf,0,sizeof(addrbuf)); + dest_addr = (struct sockaddr*) &addrbuf; + dest_addr_len = tor_addr_to_sockaddr(addr, port, dest_addr, sizeof(addrbuf)); + tor_assert(dest_addr_len > 0); + + log_debug(LD_NET, "Connecting to %s:%u.", + escaped_safe_str_client(address), port); + + if (connect(s, dest_addr, (socklen_t)dest_addr_len) < 0) { + int e = tor_socket_errno(s); + if (!ERRNO_IS_CONN_EINPROGRESS(e)) { + /* yuck. kill it. */ + *socket_error = e; + log_info(LD_NET, + "connect() to %s:%u failed: %s", + escaped_safe_str_client(address), + port, tor_socket_strerror(e)); + tor_close_socket(s); + return -1; + } else { + inprogress = 1; + } + } + + /* it succeeded. we're connected. */ + log_fn(inprogress?LOG_DEBUG:LOG_INFO, LD_NET, + "Connection to %s:%u %s (sock "TOR_SOCKET_T_FORMAT").", + escaped_safe_str_client(address), + port, inprogress?"in progress":"established", s); + conn->s = s; + if (connection_add_connecting(conn) < 0) { + /* no space, forget it */ + *socket_error = SOCK_ERRNO(ENOBUFS); + return -1; + } + return inprogress ? 0 : 1; +} + +/** Convert state number to string representation for logging purposes. + */ +static const char * +connection_proxy_state_to_string(int state) +{ + static const char *unknown = "???"; + static const char *states[] = { + "PROXY_NONE", + "PROXY_INFANT", + "PROXY_HTTPS_WANT_CONNECT_OK", + "PROXY_SOCKS4_WANT_CONNECT_OK", + "PROXY_SOCKS5_WANT_AUTH_METHOD_NONE", + "PROXY_SOCKS5_WANT_AUTH_METHOD_RFC1929", + "PROXY_SOCKS5_WANT_AUTH_RFC1929_OK", + "PROXY_SOCKS5_WANT_CONNECT_OK", + "PROXY_CONNECTED", + }; + + if (state < PROXY_NONE || state > PROXY_CONNECTED) + return unknown; + + return states[state]; +} + +/** Returns the global proxy type used by tor. Use this function for + * logging or high-level purposes, don't use it to fill the + * proxy_type field of or_connection_t; use the actual proxy + * protocol instead.*/ +static int +get_proxy_type(void) +{ + const or_options_t *options = get_options(); + + if (options->HTTPSProxy) + return PROXY_CONNECT; + else if (options->Socks4Proxy) + return PROXY_SOCKS4; + else if (options->Socks5Proxy) + return PROXY_SOCKS5; + else if (options->ClientTransportPlugin) + return PROXY_PLUGGABLE; + else + return PROXY_NONE; +} + +/* One byte for the version, one for the command, two for the + port, and four for the addr... and, one more for the + username NUL: */ +#define SOCKS4_STANDARD_BUFFER_SIZE (1 + 1 + 2 + 4 + 1) + +/** Write a proxy request of type (socks4, socks5, https) to conn + * for conn->addr:conn->port, authenticating with the auth details given + * in the configuration (if available). SOCKS 5 and HTTP CONNECT proxies + * support authentication. + * + * Returns -1 if conn->addr is incompatible with the proxy protocol, and + * 0 otherwise. + * + * Use connection_read_proxy_handshake() to complete the handshake. + */ +int +connection_proxy_connect(connection_t *conn, int type) +{ + const or_options_t *options; + + tor_assert(conn); + + options = get_options(); + + switch (type) { + case PROXY_CONNECT: { + char buf[1024]; + char *base64_authenticator=NULL; + const char *authenticator = options->HTTPSProxyAuthenticator; + + /* Send HTTP CONNECT and authentication (if available) in + * one request */ + + if (authenticator) { + base64_authenticator = alloc_http_authenticator(authenticator); + if (!base64_authenticator) + log_warn(LD_OR, "Encoding https authenticator failed"); + } + + if (base64_authenticator) { + const char *addrport = fmt_addrport(&conn->addr, conn->port); + tor_snprintf(buf, sizeof(buf), "CONNECT %s HTTP/1.1\r\n" + "Host: %s\r\n" + "Proxy-Authorization: Basic %s\r\n\r\n", + addrport, + addrport, + base64_authenticator); + tor_free(base64_authenticator); + } else { + tor_snprintf(buf, sizeof(buf), "CONNECT %s HTTP/1.0\r\n\r\n", + fmt_addrport(&conn->addr, conn->port)); + } + + connection_write_to_buf(buf, strlen(buf), conn); + conn->proxy_state = PROXY_HTTPS_WANT_CONNECT_OK; + break; + } + + case PROXY_SOCKS4: { + unsigned char *buf; + uint16_t portn; + uint32_t ip4addr; + size_t buf_size = 0; + char *socks_args_string = NULL; + + /* Send a SOCKS4 connect request */ + + if (tor_addr_family(&conn->addr) != AF_INET) { + log_warn(LD_NET, "SOCKS4 client is incompatible with IPv6"); + return -1; + } + + { /* If we are here because we are trying to connect to a + pluggable transport proxy, check if we have any SOCKS + arguments to transmit. If we do, compress all arguments to + a single string in 'socks_args_string': */ + + if (get_proxy_type() == PROXY_PLUGGABLE) { + socks_args_string = + pt_get_socks_args_for_proxy_addrport(&conn->addr, conn->port); + if (socks_args_string) + log_debug(LD_NET, "Sending out '%s' as our SOCKS argument string.", + socks_args_string); + } + } + + { /* Figure out the buffer size we need for the SOCKS message: */ + + buf_size = SOCKS4_STANDARD_BUFFER_SIZE; + + /* If we have a SOCKS argument string, consider its size when + calculating the buffer size: */ + if (socks_args_string) + buf_size += strlen(socks_args_string); + } + + buf = tor_malloc_zero(buf_size); + + ip4addr = tor_addr_to_ipv4n(&conn->addr); + portn = htons(conn->port); + + buf[0] = 4; /* version */ + buf[1] = SOCKS_COMMAND_CONNECT; /* command */ + memcpy(buf + 2, &portn, 2); /* port */ + memcpy(buf + 4, &ip4addr, 4); /* addr */ + + /* Next packet field is the userid. If we have pluggable + transport SOCKS arguments, we have to embed them + there. Otherwise, we use an empty userid. */ + if (socks_args_string) { /* place the SOCKS args string: */ + tor_assert(strlen(socks_args_string) > 0); + tor_assert(buf_size >= + SOCKS4_STANDARD_BUFFER_SIZE + strlen(socks_args_string)); + strlcpy((char *)buf + 8, socks_args_string, buf_size - 8); + tor_free(socks_args_string); + } else { + buf[8] = 0; /* no userid */ + } + + connection_write_to_buf((char *)buf, buf_size, conn); + tor_free(buf); + + conn->proxy_state = PROXY_SOCKS4_WANT_CONNECT_OK; + break; + } + + case PROXY_SOCKS5: { + unsigned char buf[4]; /* fields: vers, num methods, method list */ + + /* Send a SOCKS5 greeting (connect request must wait) */ + + buf[0] = 5; /* version */ + + /* We have to use SOCKS5 authentication, if we have a + Socks5ProxyUsername or if we want to pass arguments to our + pluggable transport proxy: */ + if ((options->Socks5ProxyUsername) || + (get_proxy_type() == PROXY_PLUGGABLE && + (get_socks_args_by_bridge_addrport(&conn->addr, conn->port)))) { + /* number of auth methods */ + buf[1] = 2; + buf[2] = 0x00; /* no authentication */ + buf[3] = 0x02; /* rfc1929 Username/Passwd auth */ + conn->proxy_state = PROXY_SOCKS5_WANT_AUTH_METHOD_RFC1929; + } else { + buf[1] = 1; + buf[2] = 0x00; /* no authentication */ + conn->proxy_state = PROXY_SOCKS5_WANT_AUTH_METHOD_NONE; + } + + connection_write_to_buf((char *)buf, 2 + buf[1], conn); + break; + } + + default: + log_err(LD_BUG, "Invalid proxy protocol, %d", type); + tor_fragile_assert(); + return -1; + } + + log_debug(LD_NET, "set state %s", + connection_proxy_state_to_string(conn->proxy_state)); + + return 0; +} + +/** Read conn's inbuf. If the http response from the proxy is all + * here, make sure it's good news, then return 1. If it's bad news, + * return -1. Else return 0 and hope for better luck next time. + */ +static int +connection_read_https_proxy_response(connection_t *conn) +{ + char *headers; + char *reason=NULL; + int status_code; + time_t date_header; + + switch (fetch_from_buf_http(conn->inbuf, + &headers, MAX_HEADERS_SIZE, + NULL, NULL, 10000, 0)) { + case -1: /* overflow */ + log_warn(LD_PROTOCOL, + "Your https proxy sent back an oversized response. Closing."); + return -1; + case 0: + log_info(LD_NET,"https proxy response not all here yet. Waiting."); + return 0; + /* case 1, fall through */ + } + + if (parse_http_response(headers, &status_code, &date_header, + NULL, &reason) < 0) { + log_warn(LD_NET, + "Unparseable headers from proxy (connecting to '%s'). Closing.", + conn->address); + tor_free(headers); + return -1; + } + tor_free(headers); + if (!reason) reason = tor_strdup("[no reason given]"); + + if (status_code == 200) { + log_info(LD_NET, + "HTTPS connect to '%s' successful! (200 %s) Starting TLS.", + conn->address, escaped(reason)); + tor_free(reason); + return 1; + } + /* else, bad news on the status code */ + switch (status_code) { + case 403: + log_warn(LD_NET, + "The https proxy refused to allow connection to %s " + "(status code %d, %s). Closing.", + conn->address, status_code, escaped(reason)); + break; + default: + log_warn(LD_NET, + "The https proxy sent back an unexpected status code %d (%s). " + "Closing.", + status_code, escaped(reason)); + break; + } + tor_free(reason); + return -1; +} + +/** Send SOCKS5 CONNECT command to conn, copying conn->addr + * and conn->port into the request. + */ +static void +connection_send_socks5_connect(connection_t *conn) +{ + unsigned char buf[1024]; + size_t reqsize = 6; + uint16_t port = htons(conn->port); + + buf[0] = 5; /* version */ + buf[1] = SOCKS_COMMAND_CONNECT; /* command */ + buf[2] = 0; /* reserved */ + + if (tor_addr_family(&conn->addr) == AF_INET) { + uint32_t addr = tor_addr_to_ipv4n(&conn->addr); + + buf[3] = 1; + reqsize += 4; + memcpy(buf + 4, &addr, 4); + memcpy(buf + 8, &port, 2); + } else { /* AF_INET6 */ + buf[3] = 4; + reqsize += 16; + memcpy(buf + 4, tor_addr_to_in6(&conn->addr), 16); + memcpy(buf + 20, &port, 2); + } + + connection_write_to_buf((char *)buf, reqsize, conn); + + conn->proxy_state = PROXY_SOCKS5_WANT_CONNECT_OK; +} + +/** Wrapper around fetch_from_(buf/evbuffer)_socks_client: see those functions + * for documentation of its behavior. */ +static int +connection_fetch_from_buf_socks_client(connection_t *conn, + int state, char **reason) +{ + IF_HAS_BUFFEREVENT(conn, { + struct evbuffer *input = bufferevent_get_input(conn->bufev); + return fetch_from_evbuffer_socks_client(input, state, reason); + }) ELSE_IF_NO_BUFFEREVENT { + return fetch_from_buf_socks_client(conn->inbuf, state, reason); + } +} + +/** Call this from connection_*_process_inbuf() to advance the proxy + * handshake. + * + * No matter what proxy protocol is used, if this function returns 1, the + * handshake is complete, and the data remaining on inbuf may contain the + * start of the communication with the requested server. + * + * Returns 0 if the current buffer contains an incomplete response, and -1 + * on error. + */ +int +connection_read_proxy_handshake(connection_t *conn) +{ + int ret = 0; + char *reason = NULL; + + log_debug(LD_NET, "enter state %s", + connection_proxy_state_to_string(conn->proxy_state)); + + switch (conn->proxy_state) { + case PROXY_HTTPS_WANT_CONNECT_OK: + ret = connection_read_https_proxy_response(conn); + if (ret == 1) + conn->proxy_state = PROXY_CONNECTED; + break; + + case PROXY_SOCKS4_WANT_CONNECT_OK: + ret = connection_fetch_from_buf_socks_client(conn, + conn->proxy_state, + &reason); + if (ret == 1) + conn->proxy_state = PROXY_CONNECTED; + break; + + case PROXY_SOCKS5_WANT_AUTH_METHOD_NONE: + ret = connection_fetch_from_buf_socks_client(conn, + conn->proxy_state, + &reason); + /* no auth needed, do connect */ + if (ret == 1) { + connection_send_socks5_connect(conn); + ret = 0; + } + break; + + case PROXY_SOCKS5_WANT_AUTH_METHOD_RFC1929: + ret = connection_fetch_from_buf_socks_client(conn, + conn->proxy_state, + &reason); + + /* send auth if needed, otherwise do connect */ + if (ret == 1) { + connection_send_socks5_connect(conn); + ret = 0; + } else if (ret == 2) { + unsigned char buf[1024]; + size_t reqsize, usize, psize; + const char *user, *pass; + char *socks_args_string = NULL; + + if (get_proxy_type() == PROXY_PLUGGABLE) { + socks_args_string = + pt_get_socks_args_for_proxy_addrport(&conn->addr, conn->port); + if (!socks_args_string) { + log_warn(LD_NET, "Could not create SOCKS args string."); + ret = -1; + break; + } + + log_debug(LD_NET, "SOCKS5 arguments: %s", socks_args_string); + tor_assert(strlen(socks_args_string) > 0); + tor_assert(strlen(socks_args_string) <= MAX_SOCKS5_AUTH_SIZE_TOTAL); + + if (strlen(socks_args_string) > MAX_SOCKS5_AUTH_FIELD_SIZE) { + user = socks_args_string; + usize = MAX_SOCKS5_AUTH_FIELD_SIZE; + pass = socks_args_string + MAX_SOCKS5_AUTH_FIELD_SIZE; + psize = strlen(socks_args_string) - MAX_SOCKS5_AUTH_FIELD_SIZE; + } else { + user = socks_args_string; + usize = strlen(socks_args_string); + pass = "\0"; + psize = 1; + } + } else if (get_options()->Socks5ProxyUsername) { + user = get_options()->Socks5ProxyUsername; + pass = get_options()->Socks5ProxyPassword; + tor_assert(user && pass); + usize = strlen(user); + psize = strlen(pass); + } else { + log_err(LD_BUG, "We entered %s for no reason!", __func__); + tor_fragile_assert(); + ret = -1; + break; + } + + /* Username and password lengths should have been checked + above and during torrc parsing. */ + tor_assert(usize <= MAX_SOCKS5_AUTH_FIELD_SIZE && + psize <= MAX_SOCKS5_AUTH_FIELD_SIZE); + reqsize = 3 + usize + psize; + + buf[0] = 1; /* negotiation version */ + buf[1] = usize; + memcpy(buf + 2, user, usize); + buf[2 + usize] = psize; + memcpy(buf + 3 + usize, pass, psize); + + if (socks_args_string) + tor_free(socks_args_string); + + connection_write_to_buf((char *)buf, reqsize, conn); + + conn->proxy_state = PROXY_SOCKS5_WANT_AUTH_RFC1929_OK; + ret = 0; + } + break; + + case PROXY_SOCKS5_WANT_AUTH_RFC1929_OK: + ret = connection_fetch_from_buf_socks_client(conn, + conn->proxy_state, + &reason); + /* send the connect request */ + if (ret == 1) { + connection_send_socks5_connect(conn); + ret = 0; + } + break; + + case PROXY_SOCKS5_WANT_CONNECT_OK: + ret = connection_fetch_from_buf_socks_client(conn, + conn->proxy_state, + &reason); + if (ret == 1) + conn->proxy_state = PROXY_CONNECTED; + break; + + default: + log_err(LD_BUG, "Invalid proxy_state for reading, %d", + conn->proxy_state); + tor_fragile_assert(); + ret = -1; + break; + } + + log_debug(LD_NET, "leaving state %s", + connection_proxy_state_to_string(conn->proxy_state)); + + if (ret < 0) { + if (reason) { + log_warn(LD_NET, "Proxy Client: unable to connect to %s:%d (%s)", + conn->address, conn->port, escaped(reason)); + tor_free(reason); + } else { + log_warn(LD_NET, "Proxy Client: unable to connect to %s:%d", + conn->address, conn->port); + } + } else if (ret == 1) { + log_info(LD_NET, "Proxy Client: connection to %s:%d successful", + conn->address, conn->port); + } + + return ret; +} + +/** Given a list of listener connections in old_conns, and list of + * port_cfg_t entries in ports, open a new listener for every port in + * ports that does not already have a listener in old_conns. + * + * Remove from old_conns every connection that has a corresponding + * entry in ports. Add to new_conns new every connection we + * launch. + * + * If control_listeners_only is true, then we only open control + * listeners, and we do not remove any noncontrol listeners from old_conns. + * + * Return 0 on success, -1 on failure. + **/ +static int +retry_listener_ports(smartlist_t *old_conns, + const smartlist_t *ports, + smartlist_t *new_conns, + int control_listeners_only) +{ + smartlist_t *launch = smartlist_new(); + int r = 0; + + if (control_listeners_only) { + SMARTLIST_FOREACH(ports, port_cfg_t *, p, { + if (p->type == CONN_TYPE_CONTROL_LISTENER) + smartlist_add(launch, p); + }); + } else { + smartlist_add_all(launch, ports); + } + + /* Iterate through old_conns, comparing it to launch: remove from both lists + * each pair of elements that corresponds to the same port. */ + SMARTLIST_FOREACH_BEGIN(old_conns, connection_t *, conn) { + const port_cfg_t *found_port = NULL; + + /* Okay, so this is a listener. Is it configured? */ + SMARTLIST_FOREACH_BEGIN(launch, const port_cfg_t *, wanted) { + if (conn->type != wanted->type) + continue; + if ((conn->socket_family != AF_UNIX && wanted->is_unix_addr) || + (conn->socket_family == AF_UNIX && ! wanted->is_unix_addr)) + continue; + + if (wanted->no_listen) + continue; /* We don't want to open a listener for this one */ + + if (wanted->is_unix_addr) { + if (conn->socket_family == AF_UNIX && + !strcmp(wanted->unix_addr, conn->address)) { + found_port = wanted; + break; + } + } else { + int port_matches; + if (wanted->port == CFG_AUTO_PORT) { + port_matches = 1; + } else { + port_matches = (wanted->port == conn->port); + } + if (port_matches && tor_addr_eq(&wanted->addr, &conn->addr)) { + found_port = wanted; + break; + } + } + } SMARTLIST_FOREACH_END(wanted); + + if (found_port) { + /* This listener is already running; we don't need to launch it. */ + //log_debug(LD_NET, "Already have %s on %s:%d", + // conn_type_to_string(found_port->type), conn->address, conn->port); + smartlist_remove(launch, found_port); + /* And we can remove the connection from old_conns too. */ + SMARTLIST_DEL_CURRENT(old_conns, conn); + } + } SMARTLIST_FOREACH_END(conn); + + /* Now open all the listeners that are configured but not opened. */ + SMARTLIST_FOREACH_BEGIN(launch, const port_cfg_t *, port) { + struct sockaddr *listensockaddr; + socklen_t listensocklen = 0; + char *address=NULL; + connection_t *conn; + int real_port = port->port == CFG_AUTO_PORT ? 0 : port->port; + tor_assert(real_port <= UINT16_MAX); + if (port->no_listen) + continue; + + if (port->is_unix_addr) { + listensockaddr = (struct sockaddr *) + create_unix_sockaddr(port->unix_addr, + &address, &listensocklen); + } else { + listensockaddr = tor_malloc(sizeof(struct sockaddr_storage)); + listensocklen = tor_addr_to_sockaddr(&port->addr, + real_port, + listensockaddr, + sizeof(struct sockaddr_storage)); + address = tor_dup_addr(&port->addr); + } + + if (listensockaddr) { + conn = connection_listener_new(listensockaddr, listensocklen, + port->type, address, port); + tor_free(listensockaddr); + tor_free(address); + } else { + conn = NULL; + } + + if (!conn) { + r = -1; + } else { + if (new_conns) + smartlist_add(new_conns, conn); + } + } SMARTLIST_FOREACH_END(port); + + smartlist_free(launch); + + return r; +} + +/** Launch listeners for each port you should have open. Only launch + * listeners who are not already open, and only close listeners we no longer + * want. + * + * Add all old conns that should be closed to replaced_conns. + * Add all new connections to new_conns. + * + * If close_all_noncontrol is true, then we only open control + * listeners, and we close all other listeners. + */ +int +retry_all_listeners(smartlist_t *replaced_conns, + smartlist_t *new_conns, int close_all_noncontrol) +{ + smartlist_t *listeners = smartlist_new(); + const or_options_t *options = get_options(); + int retval = 0; + const uint16_t old_or_port = router_get_advertised_or_port(options); + const uint16_t old_or_port_ipv6 = + router_get_advertised_or_port_by_af(options,AF_INET6); + const uint16_t old_dir_port = router_get_advertised_dir_port(options, 0); + + SMARTLIST_FOREACH_BEGIN(get_connection_array(), connection_t *, conn) { + if (connection_is_listener(conn) && !conn->marked_for_close) + smartlist_add(listeners, conn); + } SMARTLIST_FOREACH_END(conn); + + if (retry_listener_ports(listeners, + get_configured_ports(), + new_conns, + close_all_noncontrol) < 0) + retval = -1; + + /* Any members that were still in 'listeners' don't correspond to + * any configured port. Kill 'em. */ + SMARTLIST_FOREACH_BEGIN(listeners, connection_t *, conn) { + log_notice(LD_NET, "Closing no-longer-configured %s on %s:%d", + conn_type_to_string(conn->type), conn->address, conn->port); + if (replaced_conns) { + smartlist_add(replaced_conns, conn); + } else { + connection_close_immediate(conn); + connection_mark_for_close(conn); + } + } SMARTLIST_FOREACH_END(conn); + + smartlist_free(listeners); + + if (old_or_port != router_get_advertised_or_port(options) || + old_or_port_ipv6 != router_get_advertised_or_port_by_af(options, + AF_INET6) || + old_dir_port != router_get_advertised_dir_port(options, 0)) { + /* Our chosen ORPort or DirPort is not what it used to be: the + * descriptor we had (if any) should be regenerated. (We won't + * automatically notice this because of changes in the option, + * since the value could be "auto".) */ + mark_my_descriptor_dirty("Chosen Or/DirPort changed"); + } + + return retval; +} + +/** Mark every listener of type other than CONTROL_LISTENER to be closed. */ +void +connection_mark_all_noncontrol_listeners(void) +{ + SMARTLIST_FOREACH_BEGIN(get_connection_array(), connection_t *, conn) { + if (conn->marked_for_close) + continue; + if (conn->type == CONN_TYPE_CONTROL_LISTENER) + continue; + if (connection_is_listener(conn)) + connection_mark_for_close(conn); + } SMARTLIST_FOREACH_END(conn); +} + +/** Mark every external connection not used for controllers for close. */ +void +connection_mark_all_noncontrol_connections(void) +{ + SMARTLIST_FOREACH_BEGIN(get_connection_array(), connection_t *, conn) { + if (conn->marked_for_close) + continue; + switch (conn->type) { + case CONN_TYPE_CPUWORKER: + case CONN_TYPE_CONTROL_LISTENER: + case CONN_TYPE_CONTROL: + break; + case CONN_TYPE_AP: + connection_mark_unattached_ap(TO_ENTRY_CONN(conn), + END_STREAM_REASON_HIBERNATING); + break; + default: + connection_mark_for_close(conn); + break; + } + } SMARTLIST_FOREACH_END(conn); +} + +/** Return 1 if we should apply rate limiting to conn, and 0 + * otherwise. + * Right now this just checks if it's an internal IP address or an + * internal connection. We also should, but don't, check if the connection + * uses pluggable transports, since we should then limit it even if it + * comes from an internal IP address. */ +static int +connection_is_rate_limited(connection_t *conn) +{ + const or_options_t *options = get_options(); + if (conn->linked) + return 0; /* Internal connection */ + else if (! options->CountPrivateBandwidth && + (tor_addr_family(&conn->addr) == AF_UNSPEC || /* no address */ + tor_addr_is_internal(&conn->addr, 0))) + return 0; /* Internal address */ + else + return 1; +} + +#ifdef USE_BUFFEREVENTS +static struct bufferevent_rate_limit_group *global_rate_limit = NULL; +#else +extern int global_read_bucket, global_write_bucket; +extern int global_relayed_read_bucket, global_relayed_write_bucket; + +/** Did either global write bucket run dry last second? If so, + * we are likely to run dry again this second, so be stingy with the + * tokens we just put in. */ +static int write_buckets_empty_last_second = 0; +#endif + +/** How many seconds of no active local circuits will make the + * connection revert to the "relayed" bandwidth class? */ +#define CLIENT_IDLE_TIME_FOR_PRIORITY 30 + +#ifndef USE_BUFFEREVENTS +/** Return 1 if conn should use tokens from the "relayed" + * bandwidth rates, else 0. Currently, only OR conns with bandwidth + * class 1, and directory conns that are serving data out, count. + */ +static int +connection_counts_as_relayed_traffic(connection_t *conn, time_t now) +{ + if (conn->type == CONN_TYPE_OR && + connection_or_client_used(TO_OR_CONN(conn)) + + CLIENT_IDLE_TIME_FOR_PRIORITY < now) + return 1; + if (conn->type == CONN_TYPE_DIR && DIR_CONN_IS_SERVER(conn)) + return 1; + return 0; +} + +/** Helper function to decide how many bytes out of global_bucket + * we're willing to use for this transaction. base is the size + * of a cell on the network; priority says whether we should + * write many of them or just a few; and conn_bucket (if + * non-negative) provides an upper limit for our answer. */ +static ssize_t +connection_bucket_round_robin(int base, int priority, + ssize_t global_bucket, ssize_t conn_bucket) +{ + ssize_t at_most; + ssize_t num_bytes_high = (priority ? 32 : 16) * base; + ssize_t num_bytes_low = (priority ? 4 : 2) * base; + + /* Do a rudimentary round-robin so one circuit can't hog a connection. + * Pick at most 32 cells, at least 4 cells if possible, and if we're in + * the middle pick 1/8 of the available bandwidth. */ + at_most = global_bucket / 8; + at_most -= (at_most % base); /* round down */ + if (at_most > num_bytes_high) /* 16 KB, or 8 KB for low-priority */ + at_most = num_bytes_high; + else if (at_most < num_bytes_low) /* 2 KB, or 1 KB for low-priority */ + at_most = num_bytes_low; + + if (at_most > global_bucket) + at_most = global_bucket; + + if (conn_bucket >= 0 && at_most > conn_bucket) + at_most = conn_bucket; + + if (at_most < 0) + return 0; + return at_most; +} + +/** How many bytes at most can we read onto this connection? */ +static ssize_t +connection_bucket_read_limit(connection_t *conn, time_t now) +{ + int base = RELAY_PAYLOAD_SIZE; + int priority = conn->type != CONN_TYPE_DIR; + int conn_bucket = -1; + int global_bucket = global_read_bucket; + + if (connection_speaks_cells(conn)) { + or_connection_t *or_conn = TO_OR_CONN(conn); + if (conn->state == OR_CONN_STATE_OPEN) + conn_bucket = or_conn->read_bucket; + base = get_cell_network_size(or_conn->wide_circ_ids); + } + + if (!connection_is_rate_limited(conn)) { + /* be willing to read on local conns even if our buckets are empty */ + return conn_bucket>=0 ? conn_bucket : 1<<14; + } + + if (connection_counts_as_relayed_traffic(conn, now) && + global_relayed_read_bucket <= global_read_bucket) + global_bucket = global_relayed_read_bucket; + + return connection_bucket_round_robin(base, priority, + global_bucket, conn_bucket); +} + +/** How many bytes at most can we write onto this connection? */ +ssize_t +connection_bucket_write_limit(connection_t *conn, time_t now) +{ + int base = RELAY_PAYLOAD_SIZE; + int priority = conn->type != CONN_TYPE_DIR; + int conn_bucket = (int)conn->outbuf_flushlen; + int global_bucket = global_write_bucket; + + if (!connection_is_rate_limited(conn)) { + /* be willing to write to local conns even if our buckets are empty */ + return conn->outbuf_flushlen; + } + + if (connection_speaks_cells(conn)) { + /* use the per-conn write limit if it's lower, but if it's less + * than zero just use zero */ + or_connection_t *or_conn = TO_OR_CONN(conn); + if (conn->state == OR_CONN_STATE_OPEN) + if (or_conn->write_bucket < conn_bucket) + conn_bucket = or_conn->write_bucket >= 0 ? + or_conn->write_bucket : 0; + base = get_cell_network_size(or_conn->wide_circ_ids); + } + + if (connection_counts_as_relayed_traffic(conn, now) && + global_relayed_write_bucket <= global_write_bucket) + global_bucket = global_relayed_write_bucket; + + return connection_bucket_round_robin(base, priority, + global_bucket, conn_bucket); +} +#else +static ssize_t +connection_bucket_read_limit(connection_t *conn, time_t now) +{ + (void) now; + return bufferevent_get_max_to_read(conn->bufev); +} +ssize_t +connection_bucket_write_limit(connection_t *conn, time_t now) +{ + (void) now; + return bufferevent_get_max_to_write(conn->bufev); +} +#endif + +/** Return 1 if the global write buckets are low enough that we + * shouldn't send attempt bytes of low-priority directory stuff + * out to conn. Else return 0. + + * Priority is 1 for v1 requests (directories and running-routers), + * and 2 for v2 requests (statuses and descriptors). But see FFFF in + * directory_handle_command_get() for why we don't use priority 2 yet. + * + * There are a lot of parameters we could use here: + * - global_relayed_write_bucket. Low is bad. + * - global_write_bucket. Low is bad. + * - bandwidthrate. Low is bad. + * - bandwidthburst. Not a big factor? + * - attempt. High is bad. + * - total bytes queued on outbufs. High is bad. But I'm wary of + * using this, since a few slow-flushing queues will pump up the + * number without meaning what we meant to mean. What we really + * mean is "total directory bytes added to outbufs recently", but + * that's harder to quantify and harder to keep track of. + */ +int +global_write_bucket_low(connection_t *conn, size_t attempt, int priority) +{ +#ifdef USE_BUFFEREVENTS + ssize_t smaller_bucket = bufferevent_get_max_to_write(conn->bufev); +#else + int smaller_bucket = global_write_bucket < global_relayed_write_bucket ? + global_write_bucket : global_relayed_write_bucket; +#endif + if (authdir_mode(get_options()) && priority>1) + return 0; /* there's always room to answer v2 if we're an auth dir */ + + if (!connection_is_rate_limited(conn)) + return 0; /* local conns don't get limited */ + + if (smaller_bucket < (int)attempt) + return 1; /* not enough space no matter the priority */ + +#ifndef USE_BUFFEREVENTS + if (write_buckets_empty_last_second) + return 1; /* we're already hitting our limits, no more please */ +#endif + + if (priority == 1) { /* old-style v1 query */ + /* Could we handle *two* of these requests within the next two seconds? */ + const or_options_t *options = get_options(); + int64_t can_write = (int64_t)smaller_bucket + + 2*(options->RelayBandwidthRate ? options->RelayBandwidthRate : + options->BandwidthRate); + if (can_write < 2*(int64_t)attempt) + return 1; + } else { /* v2 query */ + /* no further constraints yet */ + } + return 0; +} + +/** Helper: adjusts our bandwidth history and informs the controller as + * appropriate, given that we have just read num_read bytes and written + * num_written bytes on conn. */ +static void +record_num_bytes_transferred_impl(connection_t *conn, + time_t now, size_t num_read, size_t num_written) +{ + /* Count bytes of answering direct and tunneled directory requests */ + if (conn->type == CONN_TYPE_DIR && conn->purpose == DIR_PURPOSE_SERVER) { + if (num_read > 0) + rep_hist_note_dir_bytes_read(num_read, now); + if (num_written > 0) + rep_hist_note_dir_bytes_written(num_written, now); + } + + if (!connection_is_rate_limited(conn)) + return; /* local IPs are free */ + + if (conn->type == CONN_TYPE_OR) + rep_hist_note_or_conn_bytes(conn->global_identifier, num_read, + num_written, now); + + if (num_read > 0) { + rep_hist_note_bytes_read(num_read, now); + } + if (num_written > 0) { + rep_hist_note_bytes_written(num_written, now); + } + if (conn->type == CONN_TYPE_EXIT) + rep_hist_note_exit_bytes(conn->port, num_written, num_read); +} + +#ifdef USE_BUFFEREVENTS +/** Wrapper around fetch_from_(buf/evbuffer)_socks_client: see those functions + * for documentation of its behavior. */ +static void +record_num_bytes_transferred(connection_t *conn, + time_t now, size_t num_read, size_t num_written) +{ + /* XXX024 check if this is necessary */ + if (num_written >= INT_MAX || num_read >= INT_MAX) { + log_err(LD_BUG, "Value out of range. num_read=%lu, num_written=%lu, " + "connection type=%s, state=%s", + (unsigned long)num_read, (unsigned long)num_written, + conn_type_to_string(conn->type), + conn_state_to_string(conn->type, conn->state)); + if (num_written >= INT_MAX) num_written = 1; + if (num_read >= INT_MAX) num_read = 1; + tor_fragile_assert(); + } + + record_num_bytes_transferred_impl(conn,now,num_read,num_written); +} +#endif + +#ifndef USE_BUFFEREVENTS +/** Last time at which the global or relay buckets were emptied in msec + * since midnight. */ +static uint32_t global_relayed_read_emptied = 0, + global_relayed_write_emptied = 0, + global_read_emptied = 0, + global_write_emptied = 0; + +/** Helper: convert given tvnow time value to milliseconds since + * midnight. */ +static uint32_t +msec_since_midnight(const struct timeval *tvnow) +{ + return (uint32_t)(((tvnow->tv_sec % 86400L) * 1000L) + + ((uint32_t)tvnow->tv_usec / (uint32_t)1000L)); +} + +/** Check if a bucket which had tokens_before tokens and which got + * tokens_removed tokens removed at timestamp tvnow has run + * out of tokens, and if so, note the milliseconds since midnight in + * timestamp_var for the next TB_EMPTY event. */ +void +connection_buckets_note_empty_ts(uint32_t *timestamp_var, + int tokens_before, size_t tokens_removed, + const struct timeval *tvnow) +{ + if (tokens_before > 0 && (uint32_t)tokens_before <= tokens_removed) + *timestamp_var = msec_since_midnight(tvnow); +} + +/** We just read num_read and wrote num_written bytes + * onto conn. Decrement buckets appropriately. */ +static void +connection_buckets_decrement(connection_t *conn, time_t now, + size_t num_read, size_t num_written) +{ + if (num_written >= INT_MAX || num_read >= INT_MAX) { + log_err(LD_BUG, "Value out of range. num_read=%lu, num_written=%lu, " + "connection type=%s, state=%s", + (unsigned long)num_read, (unsigned long)num_written, + conn_type_to_string(conn->type), + conn_state_to_string(conn->type, conn->state)); + if (num_written >= INT_MAX) num_written = 1; + if (num_read >= INT_MAX) num_read = 1; + tor_fragile_assert(); + } + + record_num_bytes_transferred_impl(conn, now, num_read, num_written); + + if (!connection_is_rate_limited(conn)) + return; /* local IPs are free */ + + /* If one or more of our token buckets ran dry just now, note the + * timestamp for TB_EMPTY events. */ + if (get_options()->TestingEnableTbEmptyEvent) { + struct timeval tvnow; + tor_gettimeofday_cached(&tvnow); + if (connection_counts_as_relayed_traffic(conn, now)) { + connection_buckets_note_empty_ts(&global_relayed_read_emptied, + global_relayed_read_bucket, num_read, &tvnow); + connection_buckets_note_empty_ts(&global_relayed_write_emptied, + global_relayed_write_bucket, num_written, &tvnow); + } + connection_buckets_note_empty_ts(&global_read_emptied, + global_read_bucket, num_read, &tvnow); + connection_buckets_note_empty_ts(&global_write_emptied, + global_write_bucket, num_written, &tvnow); + if (connection_speaks_cells(conn) && conn->state == OR_CONN_STATE_OPEN) { + or_connection_t *or_conn = TO_OR_CONN(conn); + connection_buckets_note_empty_ts(&or_conn->read_emptied_time, + or_conn->read_bucket, num_read, &tvnow); + connection_buckets_note_empty_ts(&or_conn->write_emptied_time, + or_conn->write_bucket, num_written, &tvnow); + } + } + + if (connection_counts_as_relayed_traffic(conn, now)) { + global_relayed_read_bucket -= (int)num_read; + global_relayed_write_bucket -= (int)num_written; + } + global_read_bucket -= (int)num_read; + global_write_bucket -= (int)num_written; + if (connection_speaks_cells(conn) && conn->state == OR_CONN_STATE_OPEN) { + TO_OR_CONN(conn)->read_bucket -= (int)num_read; + TO_OR_CONN(conn)->write_bucket -= (int)num_written; + } +} + +/** If we have exhausted our global buckets, or the buckets for conn, + * stop reading. */ +static void +connection_consider_empty_read_buckets(connection_t *conn) +{ + const char *reason; + + if (!connection_is_rate_limited(conn)) + return; /* Always okay. */ + + if (global_read_bucket <= 0) { + reason = "global read bucket exhausted. Pausing."; + } else if (connection_counts_as_relayed_traffic(conn, approx_time()) && + global_relayed_read_bucket <= 0) { + reason = "global relayed read bucket exhausted. Pausing."; + } else if (connection_speaks_cells(conn) && + conn->state == OR_CONN_STATE_OPEN && + TO_OR_CONN(conn)->read_bucket <= 0) { + reason = "connection read bucket exhausted. Pausing."; + } else + return; /* all good, no need to stop it */ + + LOG_FN_CONN(conn, (LOG_DEBUG, LD_NET, "%s", reason)); + conn->read_blocked_on_bw = 1; + connection_stop_reading(conn); +} + +/** If we have exhausted our global buckets, or the buckets for conn, + * stop writing. */ +static void +connection_consider_empty_write_buckets(connection_t *conn) +{ + const char *reason; + + if (!connection_is_rate_limited(conn)) + return; /* Always okay. */ + + if (global_write_bucket <= 0) { + reason = "global write bucket exhausted. Pausing."; + } else if (connection_counts_as_relayed_traffic(conn, approx_time()) && + global_relayed_write_bucket <= 0) { + reason = "global relayed write bucket exhausted. Pausing."; + } else if (connection_speaks_cells(conn) && + conn->state == OR_CONN_STATE_OPEN && + TO_OR_CONN(conn)->write_bucket <= 0) { + reason = "connection write bucket exhausted. Pausing."; + } else + return; /* all good, no need to stop it */ + + LOG_FN_CONN(conn, (LOG_DEBUG, LD_NET, "%s", reason)); + conn->write_blocked_on_bw = 1; + connection_stop_writing(conn); +} + +/** Initialize the global read bucket to options-\>BandwidthBurst. */ +void +connection_bucket_init(void) +{ + const or_options_t *options = get_options(); + /* start it at max traffic */ + global_read_bucket = (int)options->BandwidthBurst; + global_write_bucket = (int)options->BandwidthBurst; + if (options->RelayBandwidthRate) { + global_relayed_read_bucket = (int)options->RelayBandwidthBurst; + global_relayed_write_bucket = (int)options->RelayBandwidthBurst; + } else { + global_relayed_read_bucket = (int)options->BandwidthBurst; + global_relayed_write_bucket = (int)options->BandwidthBurst; + } +} + +/** Refill a single bucket called name with bandwidth rate per + * second rate and bandwidth burst burst, assuming that + * milliseconds_elapsed milliseconds have passed since the last + * call. */ +static void +connection_bucket_refill_helper(int *bucket, int rate, int burst, + int milliseconds_elapsed, + const char *name) +{ + int starting_bucket = *bucket; + if (starting_bucket < burst && milliseconds_elapsed > 0) { + int64_t incr = (((int64_t)rate) * milliseconds_elapsed) / 1000; + if ((burst - starting_bucket) < incr) { + *bucket = burst; /* We would overflow the bucket; just set it to + * the maximum. */ + } else { + *bucket += (int)incr; + if (*bucket > burst || *bucket < starting_bucket) { + /* If we overflow the burst, or underflow our starting bucket, + * cap the bucket value to burst. */ + /* XXXX this might be redundant now, but it doesn't show up + * in profiles. Remove it after analysis. */ + *bucket = burst; + } + } + log_debug(LD_NET,"%s now %d.", name, *bucket); + } +} + +/** Helper: return the time in milliseconds since last_empty_time + * when a bucket ran empty that previously had tokens_before tokens + * now has tokens_after tokens after refilling at timestamp + * tvnow, capped at milliseconds_elapsed milliseconds since + * last refilling that bucket. Return 0 if the bucket has not been empty + * since the last refill or has not been refilled. */ +uint32_t +bucket_millis_empty(int tokens_before, uint32_t last_empty_time, + int tokens_after, int milliseconds_elapsed, + const struct timeval *tvnow) +{ + uint32_t result = 0, refilled; + if (tokens_before <= 0 && tokens_after > tokens_before) { + refilled = msec_since_midnight(tvnow); + result = (uint32_t)((refilled + 86400L * 1000L - last_empty_time) % + (86400L * 1000L)); + if (result > (uint32_t)milliseconds_elapsed) + result = (uint32_t)milliseconds_elapsed; + } + return result; +} + +/** Time has passed; increment buckets appropriately. */ +void +connection_bucket_refill(int milliseconds_elapsed, time_t now) +{ + const or_options_t *options = get_options(); + smartlist_t *conns = get_connection_array(); + int bandwidthrate, bandwidthburst, relayrate, relayburst; + + int prev_global_read = global_read_bucket; + int prev_global_write = global_write_bucket; + int prev_relay_read = global_relayed_read_bucket; + int prev_relay_write = global_relayed_write_bucket; + struct timeval tvnow; /*< Only used if TB_EMPTY events are enabled. */ + + bandwidthrate = (int)options->BandwidthRate; + bandwidthburst = (int)options->BandwidthBurst; + + if (options->RelayBandwidthRate) { + relayrate = (int)options->RelayBandwidthRate; + relayburst = (int)options->RelayBandwidthBurst; + } else { + relayrate = bandwidthrate; + relayburst = bandwidthburst; + } + + tor_assert(milliseconds_elapsed >= 0); + + write_buckets_empty_last_second = + global_relayed_write_bucket <= 0 || global_write_bucket <= 0; + + /* refill the global buckets */ + connection_bucket_refill_helper(&global_read_bucket, + bandwidthrate, bandwidthburst, + milliseconds_elapsed, + "global_read_bucket"); + connection_bucket_refill_helper(&global_write_bucket, + bandwidthrate, bandwidthburst, + milliseconds_elapsed, + "global_write_bucket"); + connection_bucket_refill_helper(&global_relayed_read_bucket, + relayrate, relayburst, + milliseconds_elapsed, + "global_relayed_read_bucket"); + connection_bucket_refill_helper(&global_relayed_write_bucket, + relayrate, relayburst, + milliseconds_elapsed, + "global_relayed_write_bucket"); + + /* If buckets were empty before and have now been refilled, tell any + * interested controllers. */ + if (get_options()->TestingEnableTbEmptyEvent) { + uint32_t global_read_empty_time, global_write_empty_time, + relay_read_empty_time, relay_write_empty_time; + tor_gettimeofday_cached(&tvnow); + global_read_empty_time = bucket_millis_empty(prev_global_read, + global_read_emptied, global_read_bucket, + milliseconds_elapsed, &tvnow); + global_write_empty_time = bucket_millis_empty(prev_global_write, + global_write_emptied, global_write_bucket, + milliseconds_elapsed, &tvnow); + control_event_tb_empty("GLOBAL", global_read_empty_time, + global_write_empty_time, milliseconds_elapsed); + relay_read_empty_time = bucket_millis_empty(prev_relay_read, + global_relayed_read_emptied, + global_relayed_read_bucket, + milliseconds_elapsed, &tvnow); + relay_write_empty_time = bucket_millis_empty(prev_relay_write, + global_relayed_write_emptied, + global_relayed_write_bucket, + milliseconds_elapsed, &tvnow); + control_event_tb_empty("RELAY", relay_read_empty_time, + relay_write_empty_time, milliseconds_elapsed); + } + + /* refill the per-connection buckets */ + SMARTLIST_FOREACH_BEGIN(conns, connection_t *, conn) { + if (connection_speaks_cells(conn)) { + or_connection_t *or_conn = TO_OR_CONN(conn); + int orbandwidthrate = or_conn->bandwidthrate; + int orbandwidthburst = or_conn->bandwidthburst; + + int prev_conn_read = or_conn->read_bucket; + int prev_conn_write = or_conn->write_bucket; + + if (connection_bucket_should_increase(or_conn->read_bucket, or_conn)) { + connection_bucket_refill_helper(&or_conn->read_bucket, + orbandwidthrate, + orbandwidthburst, + milliseconds_elapsed, + "or_conn->read_bucket"); + } + if (connection_bucket_should_increase(or_conn->write_bucket, or_conn)) { + connection_bucket_refill_helper(&or_conn->write_bucket, + orbandwidthrate, + orbandwidthburst, + milliseconds_elapsed, + "or_conn->write_bucket"); + } + + /* If buckets were empty before and have now been refilled, tell any + * interested controllers. */ + if (get_options()->TestingEnableTbEmptyEvent) { + char *bucket; + uint32_t conn_read_empty_time, conn_write_empty_time; + tor_asprintf(&bucket, "ORCONN ID="U64_FORMAT, + U64_PRINTF_ARG(or_conn->base_.global_identifier)); + conn_read_empty_time = bucket_millis_empty(prev_conn_read, + or_conn->read_emptied_time, + or_conn->read_bucket, + milliseconds_elapsed, &tvnow); + conn_write_empty_time = bucket_millis_empty(prev_conn_write, + or_conn->write_emptied_time, + or_conn->write_bucket, + milliseconds_elapsed, &tvnow); + control_event_tb_empty(bucket, conn_read_empty_time, + conn_write_empty_time, + milliseconds_elapsed); + tor_free(bucket); + } + } + + if (conn->read_blocked_on_bw == 1 /* marked to turn reading back on now */ + && global_read_bucket > 0 /* and we're allowed to read */ + && (!connection_counts_as_relayed_traffic(conn, now) || + global_relayed_read_bucket > 0) /* even if we're relayed traffic */ + && (!connection_speaks_cells(conn) || + conn->state != OR_CONN_STATE_OPEN || + TO_OR_CONN(conn)->read_bucket > 0)) { + /* and either a non-cell conn or a cell conn with non-empty bucket */ + LOG_FN_CONN(conn, (LOG_DEBUG,LD_NET, + "waking up conn (fd %d) for read", (int)conn->s)); + conn->read_blocked_on_bw = 0; + connection_start_reading(conn); + } + + if (conn->write_blocked_on_bw == 1 + && global_write_bucket > 0 /* and we're allowed to write */ + && (!connection_counts_as_relayed_traffic(conn, now) || + global_relayed_write_bucket > 0) /* even if it's relayed traffic */ + && (!connection_speaks_cells(conn) || + conn->state != OR_CONN_STATE_OPEN || + TO_OR_CONN(conn)->write_bucket > 0)) { + LOG_FN_CONN(conn, (LOG_DEBUG,LD_NET, + "waking up conn (fd %d) for write", (int)conn->s)); + conn->write_blocked_on_bw = 0; + connection_start_writing(conn); + } + } SMARTLIST_FOREACH_END(conn); +} + +/** Is the bucket for connection conn low enough that we + * should add another pile of tokens to it? + */ +static int +connection_bucket_should_increase(int bucket, or_connection_t *conn) +{ + tor_assert(conn); + + if (conn->base_.state != OR_CONN_STATE_OPEN) + return 0; /* only open connections play the rate limiting game */ + if (bucket >= conn->bandwidthburst) + return 0; + + return 1; +} +#else +static void +connection_buckets_decrement(connection_t *conn, time_t now, + size_t num_read, size_t num_written) +{ + (void) conn; + (void) now; + (void) num_read; + (void) num_written; + /* Libevent does this for us. */ +} + +void +connection_bucket_refill(int seconds_elapsed, time_t now) +{ + (void) seconds_elapsed; + (void) now; + /* Libevent does this for us. */ +} +void +connection_bucket_init(void) +{ + const or_options_t *options = get_options(); + const struct timeval *tick = tor_libevent_get_one_tick_timeout(); + struct ev_token_bucket_cfg *bucket_cfg; + + uint64_t rate, burst; + if (options->RelayBandwidthRate) { + rate = options->RelayBandwidthRate; + burst = options->RelayBandwidthBurst; + } else { + rate = options->BandwidthRate; + burst = options->BandwidthBurst; + } + + /* This can't overflow, since TokenBucketRefillInterval <= 1000, + * and rate started out less than INT32_MAX. */ + rate = (rate * options->TokenBucketRefillInterval) / 1000; + + bucket_cfg = ev_token_bucket_cfg_new((uint32_t)rate, (uint32_t)burst, + (uint32_t)rate, (uint32_t)burst, + tick); + + if (!global_rate_limit) { + global_rate_limit = + bufferevent_rate_limit_group_new(tor_libevent_get_base(), bucket_cfg); + } else { + bufferevent_rate_limit_group_set_cfg(global_rate_limit, bucket_cfg); + } + ev_token_bucket_cfg_free(bucket_cfg); +} + +void +connection_get_rate_limit_totals(uint64_t *read_out, uint64_t *written_out) +{ + if (global_rate_limit == NULL) { + *read_out = *written_out = 0; + } else { + bufferevent_rate_limit_group_get_totals( + global_rate_limit, read_out, written_out); + } +} + +/** Perform whatever operations are needed on conn to enable + * rate-limiting. */ +void +connection_enable_rate_limiting(connection_t *conn) +{ + if (conn->bufev) { + if (!global_rate_limit) + connection_bucket_init(); + tor_add_bufferevent_to_rate_limit_group(conn->bufev, global_rate_limit); + } +} + +static void +connection_consider_empty_write_buckets(connection_t *conn) +{ + (void) conn; +} +static void +connection_consider_empty_read_buckets(connection_t *conn) +{ + (void) conn; +} +#endif + +/** Read bytes from conn-\>s and process them. + * + * It calls connection_read_to_buf() to bring in any new bytes, + * and then calls connection_process_inbuf() to process them. + * + * Mark the connection and return -1 if you want to close it, else + * return 0. + */ +static int +connection_handle_read_impl(connection_t *conn) +{ + ssize_t max_to_read=-1, try_to_read; + size_t before, n_read = 0; + int socket_error = 0; + + if (conn->marked_for_close) + return 0; /* do nothing */ + + conn->timestamp_lastread = approx_time(); + + switch (conn->type) { + case CONN_TYPE_OR_LISTENER: + return connection_handle_listener_read(conn, CONN_TYPE_OR); + case CONN_TYPE_EXT_OR_LISTENER: + return connection_handle_listener_read(conn, CONN_TYPE_EXT_OR); + case CONN_TYPE_AP_LISTENER: + case CONN_TYPE_AP_TRANS_LISTENER: + case CONN_TYPE_AP_NATD_LISTENER: + return connection_handle_listener_read(conn, CONN_TYPE_AP); + case CONN_TYPE_DIR_LISTENER: + return connection_handle_listener_read(conn, CONN_TYPE_DIR); + case CONN_TYPE_CONTROL_LISTENER: + return connection_handle_listener_read(conn, CONN_TYPE_CONTROL); + case CONN_TYPE_AP_DNS_LISTENER: + /* This should never happen; eventdns.c handles the reads here. */ + tor_fragile_assert(); + return 0; + } + + loop_again: + try_to_read = max_to_read; + tor_assert(!conn->marked_for_close); + + before = buf_datalen(conn->inbuf); + if (connection_read_to_buf(conn, &max_to_read, &socket_error) < 0) { + /* There's a read error; kill the connection.*/ + if (conn->type == CONN_TYPE_OR) { + connection_or_notify_error(TO_OR_CONN(conn), + socket_error != 0 ? + errno_to_orconn_end_reason(socket_error) : + END_OR_CONN_REASON_CONNRESET, + socket_error != 0 ? + tor_socket_strerror(socket_error) : + "(unknown, errno was 0)"); + } + if (CONN_IS_EDGE(conn)) { + edge_connection_t *edge_conn = TO_EDGE_CONN(conn); + connection_edge_end_errno(edge_conn); + if (conn->type == CONN_TYPE_AP && TO_ENTRY_CONN(conn)->socks_request) { + /* broken, don't send a socks reply back */ + TO_ENTRY_CONN(conn)->socks_request->has_finished = 1; + } + } + connection_close_immediate(conn); /* Don't flush; connection is dead. */ + /* + * This can bypass normal channel checking since we did + * connection_or_notify_error() above. + */ + connection_mark_for_close_internal(conn); + return -1; + } + n_read += buf_datalen(conn->inbuf) - before; + if (CONN_IS_EDGE(conn) && try_to_read != max_to_read) { + /* instruct it not to try to package partial cells. */ + if (connection_process_inbuf(conn, 0) < 0) { + return -1; + } + if (!conn->marked_for_close && + connection_is_reading(conn) && + !conn->inbuf_reached_eof && + max_to_read > 0) + goto loop_again; /* try reading again, in case more is here now */ + } + /* one last try, packaging partial cells and all. */ + if (!conn->marked_for_close && + connection_process_inbuf(conn, 1) < 0) { + return -1; + } + if (conn->linked_conn) { + /* The other side's handle_write() will never actually get called, so + * we need to invoke the appropriate callbacks ourself. */ + connection_t *linked = conn->linked_conn; + + if (n_read) { + /* Probably a no-op, since linked conns typically don't count for + * bandwidth rate limiting. But do it anyway so we can keep stats + * accurately. Note that since we read the bytes from conn, and + * we're writing the bytes onto the linked connection, we count + * these as written bytes. */ + connection_buckets_decrement(linked, approx_time(), 0, n_read); + + if (connection_flushed_some(linked) < 0) + connection_mark_for_close(linked); + if (!connection_wants_to_flush(linked)) + connection_finished_flushing(linked); + } + + if (!buf_datalen(linked->outbuf) && conn->active_on_link) + connection_stop_reading_from_linked_conn(conn); + } + /* If we hit the EOF, call connection_reached_eof(). */ + if (!conn->marked_for_close && + conn->inbuf_reached_eof && + connection_reached_eof(conn) < 0) { + return -1; + } + return 0; +} + +/* DOCDOC connection_handle_read */ +int +connection_handle_read(connection_t *conn) +{ + int res; + + tor_gettimeofday_cache_clear(); + res = connection_handle_read_impl(conn); + return res; +} + +/** Pull in new bytes from conn-\>s or conn-\>linked_conn onto conn-\>inbuf, + * either directly or via TLS. Reduce the token buckets by the number of bytes + * read. + * + * If *max_to_read is -1, then decide it ourselves, else go with the + * value passed to us. When returning, if it's changed, subtract the + * number of bytes we read from *max_to_read. + * + * Return -1 if we want to break conn, else return 0. + */ +static int +connection_read_to_buf(connection_t *conn, ssize_t *max_to_read, + int *socket_error) +{ + int result; + ssize_t at_most = *max_to_read; + size_t slack_in_buf, more_to_read; + size_t n_read = 0, n_written = 0; + + if (at_most == -1) { /* we need to initialize it */ + /* how many bytes are we allowed to read? */ + at_most = connection_bucket_read_limit(conn, approx_time()); + } + + slack_in_buf = buf_slack(conn->inbuf); + again: + if ((size_t)at_most > slack_in_buf && slack_in_buf >= 1024) { + more_to_read = at_most - slack_in_buf; + at_most = slack_in_buf; + } else { + more_to_read = 0; + } + + if (connection_speaks_cells(conn) && + conn->state > OR_CONN_STATE_PROXY_HANDSHAKING) { + int pending; + or_connection_t *or_conn = TO_OR_CONN(conn); + size_t initial_size; + if (conn->state == OR_CONN_STATE_TLS_HANDSHAKING || + conn->state == OR_CONN_STATE_TLS_CLIENT_RENEGOTIATING) { + /* continue handshaking even if global token bucket is empty */ + return connection_tls_continue_handshake(or_conn); + } + + log_debug(LD_NET, + "%d: starting, inbuf_datalen %ld (%d pending in tls object)." + " at_most %ld.", + (int)conn->s,(long)buf_datalen(conn->inbuf), + tor_tls_get_pending_bytes(or_conn->tls), (long)at_most); + + initial_size = buf_datalen(conn->inbuf); + /* else open, or closing */ + result = read_to_buf_tls(or_conn->tls, at_most, conn->inbuf); + if (TOR_TLS_IS_ERROR(result) || result == TOR_TLS_CLOSE) + or_conn->tls_error = result; + else + or_conn->tls_error = 0; + + switch (result) { + case TOR_TLS_CLOSE: + case TOR_TLS_ERROR_IO: + log_debug(LD_NET,"TLS connection closed %son read. Closing. " + "(Nickname %s, address %s)", + result == TOR_TLS_CLOSE ? "cleanly " : "", + or_conn->nickname ? or_conn->nickname : "not set", + conn->address); + return result; + CASE_TOR_TLS_ERROR_ANY_NONIO: + log_debug(LD_NET,"tls error [%s]. breaking (nickname %s, address %s).", + tor_tls_err_to_string(result), + or_conn->nickname ? or_conn->nickname : "not set", + conn->address); + return result; + case TOR_TLS_WANTWRITE: + connection_start_writing(conn); + return 0; + case TOR_TLS_WANTREAD: + if (conn->in_connection_handle_write) { + /* We've been invoked from connection_handle_write, because we're + * waiting for a TLS renegotiation, the renegotiation started, and + * SSL_read returned WANTWRITE. But now SSL_read is saying WANTREAD + * again. Stop waiting for write events now, or else we'll + * busy-loop until data arrives for us to read. */ + connection_stop_writing(conn); + if (!connection_is_reading(conn)) + connection_start_reading(conn); + } + /* we're already reading, one hopes */ + result = 0; + break; + case TOR_TLS_DONE: /* no data read, so nothing to process */ + result = 0; + break; /* so we call bucket_decrement below */ + default: + break; + } + pending = tor_tls_get_pending_bytes(or_conn->tls); + if (pending) { + /* If we have any pending bytes, we read them now. This *can* + * take us over our read allotment, but really we shouldn't be + * believing that SSL bytes are the same as TCP bytes anyway. */ + int r2 = read_to_buf_tls(or_conn->tls, pending, conn->inbuf); + if (r2<0) { + log_warn(LD_BUG, "apparently, reading pending bytes can fail."); + return -1; + } + } + result = (int)(buf_datalen(conn->inbuf)-initial_size); + tor_tls_get_n_raw_bytes(or_conn->tls, &n_read, &n_written); + log_debug(LD_GENERAL, "After TLS read of %d: %ld read, %ld written", + result, (long)n_read, (long)n_written); + } else if (conn->linked) { + if (conn->linked_conn) { + result = move_buf_to_buf(conn->inbuf, conn->linked_conn->outbuf, + &conn->linked_conn->outbuf_flushlen); + } else { + result = 0; + } + //log_notice(LD_GENERAL, "Moved %d bytes on an internal link!", result); + /* If the other side has disappeared, or if it's been marked for close and + * we flushed its outbuf, then we should set our inbuf_reached_eof. */ + if (!conn->linked_conn || + (conn->linked_conn->marked_for_close && + buf_datalen(conn->linked_conn->outbuf) == 0)) + conn->inbuf_reached_eof = 1; + + n_read = (size_t) result; + } else { + /* !connection_speaks_cells, !conn->linked_conn. */ + int reached_eof = 0; + CONN_LOG_PROTECT(conn, + result = read_to_buf(conn->s, at_most, conn->inbuf, &reached_eof, + socket_error)); + if (reached_eof) + conn->inbuf_reached_eof = 1; + +// log_fn(LOG_DEBUG,"read_to_buf returned %d.",read_result); + + if (result < 0) + return -1; + n_read = (size_t) result; + } + + if (n_read > 0) { + /* change *max_to_read */ + *max_to_read = at_most - n_read; + + /* Update edge_conn->n_read and ocirc->n_read_circ_bw */ + if (conn->type == CONN_TYPE_AP) { + edge_connection_t *edge_conn = TO_EDGE_CONN(conn); + circuit_t *circ = circuit_get_by_edge_conn(edge_conn); + origin_circuit_t *ocirc; + + /* Check for overflow: */ + if (PREDICT_LIKELY(UINT32_MAX - edge_conn->n_read > n_read)) + edge_conn->n_read += (int)n_read; + else + edge_conn->n_read = UINT32_MAX; + + if (circ && CIRCUIT_IS_ORIGIN(circ)) { + ocirc = TO_ORIGIN_CIRCUIT(circ); + if (PREDICT_LIKELY(UINT32_MAX - ocirc->n_read_circ_bw > n_read)) + ocirc->n_read_circ_bw += (int)n_read; + else + ocirc->n_read_circ_bw = UINT32_MAX; + } + } + + /* If CONN_BW events are enabled, update conn->n_read_conn_bw for + * OR/DIR/EXIT connections, checking for overflow. */ + if (get_options()->TestingEnableConnBwEvent && + (conn->type == CONN_TYPE_OR || + conn->type == CONN_TYPE_DIR || + conn->type == CONN_TYPE_EXIT)) { + if (PREDICT_LIKELY(UINT32_MAX - conn->n_read_conn_bw > n_read)) + conn->n_read_conn_bw += (int)n_read; + else + conn->n_read_conn_bw = UINT32_MAX; + } + } + + connection_buckets_decrement(conn, approx_time(), n_read, n_written); + + if (more_to_read && result == at_most) { + slack_in_buf = buf_slack(conn->inbuf); + at_most = more_to_read; + goto again; + } + + /* Call even if result is 0, since the global read bucket may + * have reached 0 on a different conn, and this guy needs to + * know to stop reading. */ + connection_consider_empty_read_buckets(conn); + if (n_written > 0 && connection_is_writing(conn)) + connection_consider_empty_write_buckets(conn); + + return 0; +} + +#ifdef USE_BUFFEREVENTS +/* XXXX These generic versions could be simplified by making them + type-specific */ + +/** Callback: Invoked whenever bytes are added to or drained from an input + * evbuffer. Used to track the number of bytes read. */ +static void +evbuffer_inbuf_callback(struct evbuffer *buf, + const struct evbuffer_cb_info *info, void *arg) +{ + connection_t *conn = arg; + (void) buf; + /* XXXX These need to get real counts on the non-nested TLS case. - NM */ + if (info->n_added) { + time_t now = approx_time(); + conn->timestamp_lastread = now; + record_num_bytes_transferred(conn, now, info->n_added, 0); + connection_consider_empty_read_buckets(conn); + if (conn->type == CONN_TYPE_AP) { + edge_connection_t *edge_conn = TO_EDGE_CONN(conn); + /*XXXX024 check for overflow*/ + edge_conn->n_read += (int)info->n_added; + } + } +} + +/** Callback: Invoked whenever bytes are added to or drained from an output + * evbuffer. Used to track the number of bytes written. */ +static void +evbuffer_outbuf_callback(struct evbuffer *buf, + const struct evbuffer_cb_info *info, void *arg) +{ + connection_t *conn = arg; + (void)buf; + if (info->n_deleted) { + time_t now = approx_time(); + conn->timestamp_lastwritten = now; + record_num_bytes_transferred(conn, now, 0, info->n_deleted); + connection_consider_empty_write_buckets(conn); + if (conn->type == CONN_TYPE_AP) { + edge_connection_t *edge_conn = TO_EDGE_CONN(conn); + /*XXXX024 check for overflow*/ + edge_conn->n_written += (int)info->n_deleted; + } + } +} + +/** Callback: invoked whenever a bufferevent has read data. */ +void +connection_handle_read_cb(struct bufferevent *bufev, void *arg) +{ + connection_t *conn = arg; + (void) bufev; + if (!conn->marked_for_close) { + if (connection_process_inbuf(conn, 1)<0) /* XXXX Always 1? */ + if (!conn->marked_for_close) + connection_mark_for_close(conn); + } +} + +/** Callback: invoked whenever a bufferevent has written data. */ +void +connection_handle_write_cb(struct bufferevent *bufev, void *arg) +{ + connection_t *conn = arg; + struct evbuffer *output; + if (connection_flushed_some(conn)<0) { + if (!conn->marked_for_close) + connection_mark_for_close(conn); + return; + } + + output = bufferevent_get_output(bufev); + if (!evbuffer_get_length(output)) { + connection_finished_flushing(conn); + if (conn->marked_for_close && conn->hold_open_until_flushed) { + conn->hold_open_until_flushed = 0; + if (conn->linked) { + /* send eof */ + bufferevent_flush(conn->bufev, EV_WRITE, BEV_FINISHED); + } + } + } +} + +/** Callback: invoked whenever a bufferevent has had an event (like a + * connection, or an eof, or an error) occur. */ +void +connection_handle_event_cb(struct bufferevent *bufev, short event, void *arg) +{ + connection_t *conn = arg; + (void) bufev; + if (conn->marked_for_close) + return; + + if (event & BEV_EVENT_CONNECTED) { + tor_assert(connection_state_is_connecting(conn)); + if (connection_finished_connecting(conn)<0) + return; + } + if (event & BEV_EVENT_EOF) { + if (!conn->marked_for_close) { + conn->inbuf_reached_eof = 1; + if (connection_reached_eof(conn)<0) + return; + } + } + if (event & BEV_EVENT_ERROR) { + int socket_error = evutil_socket_geterror(conn->s); + if (conn->type == CONN_TYPE_OR && + conn->state == OR_CONN_STATE_CONNECTING) { + connection_or_connect_failed(TO_OR_CONN(conn), + errno_to_orconn_end_reason(socket_error), + tor_socket_strerror(socket_error)); + } else if (CONN_IS_EDGE(conn)) { + edge_connection_t *edge_conn = TO_EDGE_CONN(conn); + if (!edge_conn->edge_has_sent_end) + connection_edge_end_errno(edge_conn); + if (conn->type == CONN_TYPE_AP && TO_ENTRY_CONN(conn)->socks_request) { + /* broken, don't send a socks reply back */ + TO_ENTRY_CONN(conn)->socks_request->has_finished = 1; + } + } + connection_close_immediate(conn); /* Connection is dead. */ + if (!conn->marked_for_close) + connection_mark_for_close(conn); + } +} + +/** Set up the generic callbacks for the bufferevent on conn. */ +void +connection_configure_bufferevent_callbacks(connection_t *conn) +{ + struct bufferevent *bufev; + struct evbuffer *input, *output; + tor_assert(conn->bufev); + bufev = conn->bufev; + bufferevent_setcb(bufev, + connection_handle_read_cb, + connection_handle_write_cb, + connection_handle_event_cb, + conn); + /* Set a fairly high write low-watermark so that we get the write callback + called whenever data is written to bring us under 128K. Leave the + high-watermark at 0. + */ + bufferevent_setwatermark(bufev, EV_WRITE, 128*1024, 0); + + input = bufferevent_get_input(bufev); + output = bufferevent_get_output(bufev); + evbuffer_add_cb(input, evbuffer_inbuf_callback, conn); + evbuffer_add_cb(output, evbuffer_outbuf_callback, conn); +} +#endif + +/** A pass-through to fetch_from_buf. */ +int +connection_fetch_from_buf(char *string, size_t len, connection_t *conn) +{ + IF_HAS_BUFFEREVENT(conn, { + /* XXX overflow -seb */ + return (int)bufferevent_read(conn->bufev, string, len); + }) ELSE_IF_NO_BUFFEREVENT { + return fetch_from_buf(string, len, conn->inbuf); + } +} + +/** As fetch_from_buf_line(), but read from a connection's input buffer. */ +int +connection_fetch_from_buf_line(connection_t *conn, char *data, + size_t *data_len) +{ + IF_HAS_BUFFEREVENT(conn, { + int r; + size_t eol_len=0; + struct evbuffer *input = bufferevent_get_input(conn->bufev); + struct evbuffer_ptr ptr = + evbuffer_search_eol(input, NULL, &eol_len, EVBUFFER_EOL_LF); + if (ptr.pos == -1) + return 0; /* No EOL found. */ + if ((size_t)ptr.pos+eol_len >= *data_len) { + return -1; /* Too long */ + } + *data_len = ptr.pos+eol_len; + r = evbuffer_remove(input, data, ptr.pos+eol_len); + tor_assert(r >= 0); + data[ptr.pos+eol_len] = '\0'; + return 1; + }) ELSE_IF_NO_BUFFEREVENT { + return fetch_from_buf_line(conn->inbuf, data, data_len); + } +} + +/** As fetch_from_buf_http, but fetches from a conncetion's input buffer_t or + * its bufferevent as appropriate. */ +int +connection_fetch_from_buf_http(connection_t *conn, + char **headers_out, size_t max_headerlen, + char **body_out, size_t *body_used, + size_t max_bodylen, int force_complete) +{ + IF_HAS_BUFFEREVENT(conn, { + struct evbuffer *input = bufferevent_get_input(conn->bufev); + return fetch_from_evbuffer_http(input, headers_out, max_headerlen, + body_out, body_used, max_bodylen, force_complete); + }) ELSE_IF_NO_BUFFEREVENT { + return fetch_from_buf_http(conn->inbuf, headers_out, max_headerlen, + body_out, body_used, max_bodylen, force_complete); + } +} + +/** Return conn-\>outbuf_flushlen: how many bytes conn wants to flush + * from its outbuf. */ +int +connection_wants_to_flush(connection_t *conn) +{ + return conn->outbuf_flushlen > 0; +} + +/** Are there too many bytes on edge connection conn's outbuf to + * send back a relay-level sendme yet? Return 1 if so, 0 if not. Used by + * connection_edge_consider_sending_sendme(). + */ +int +connection_outbuf_too_full(connection_t *conn) +{ + return (conn->outbuf_flushlen > 10*CELL_PAYLOAD_SIZE); +} + +/** Try to flush more bytes onto conn-\>s. + * + * This function gets called either from conn_write_callback() in onion_main.c + * when libevent tells us that conn wants to write, or below + * from connection_write_to_buf() when an entire TLS record is ready. + * + * Update conn-\>timestamp_lastwritten to now, and call flush_buf + * or flush_buf_tls appropriately. If it succeeds and there are no more + * more bytes on conn-\>outbuf, then call connection_finished_flushing + * on it too. + * + * If force, then write as many bytes as possible, ignoring bandwidth + * limits. (Used for flushing messages to controller connections on fatal + * errors.) + * + * Mark the connection and return -1 if you want to close it, else + * return 0. + */ +static int +connection_handle_write_impl(connection_t *conn, int force) +{ + int e; + socklen_t len=(socklen_t)sizeof(e); + int result; + ssize_t max_to_write; + time_t now = approx_time(); + size_t n_read = 0, n_written = 0; + int dont_stop_writing = 0; + + tor_assert(!connection_is_listener(conn)); + + if (conn->marked_for_close || !SOCKET_OK(conn->s)) + return 0; /* do nothing */ + + if (conn->in_flushed_some) { + log_warn(LD_BUG, "called recursively from inside conn->in_flushed_some"); + return 0; + } + + conn->timestamp_lastwritten = now; + + /* Sometimes, "writable" means "connected". */ + if (connection_state_is_connecting(conn)) { + if (getsockopt(conn->s, SOL_SOCKET, SO_ERROR, (void*)&e, &len) < 0) { + log_warn(LD_BUG, "getsockopt() syscall failed"); + if (CONN_IS_EDGE(conn)) + connection_edge_end_errno(TO_EDGE_CONN(conn)); + connection_mark_for_close(conn); + return -1; + } + if (e) { + /* some sort of error, but maybe just inprogress still */ + if (!ERRNO_IS_CONN_EINPROGRESS(e)) { + log_info(LD_NET,"in-progress connect failed. Removing. (%s)", + tor_socket_strerror(e)); + if (CONN_IS_EDGE(conn)) + connection_edge_end_errno(TO_EDGE_CONN(conn)); + if (conn->type == CONN_TYPE_OR) + connection_or_notify_error(TO_OR_CONN(conn), + errno_to_orconn_end_reason(e), + tor_socket_strerror(e)); + + connection_close_immediate(conn); + /* + * This can bypass normal channel checking since we did + * connection_or_notify_error() above. + */ + connection_mark_for_close_internal(conn); + return -1; + } else { + return 0; /* no change, see if next time is better */ + } + } + /* The connection is successful. */ + if (connection_finished_connecting(conn)<0) + return -1; + } + + max_to_write = force ? (ssize_t)conn->outbuf_flushlen + : connection_bucket_write_limit(conn, now); + + if (connection_speaks_cells(conn) && + conn->state > OR_CONN_STATE_PROXY_HANDSHAKING) { + or_connection_t *or_conn = TO_OR_CONN(conn); + size_t initial_size; + if (conn->state == OR_CONN_STATE_TLS_HANDSHAKING || + conn->state == OR_CONN_STATE_TLS_CLIENT_RENEGOTIATING) { + connection_stop_writing(conn); + if (connection_tls_continue_handshake(or_conn) < 0) { + /* Don't flush; connection is dead. */ + connection_or_notify_error(or_conn, + END_OR_CONN_REASON_MISC, + "TLS error in connection_tls_" + "continue_handshake()"); + connection_close_immediate(conn); + /* + * This can bypass normal channel checking since we did + * connection_or_notify_error() above. + */ + connection_mark_for_close_internal(conn); + return -1; + } + return 0; + } else if (conn->state == OR_CONN_STATE_TLS_SERVER_RENEGOTIATING) { + return connection_handle_read(conn); + } + + /* else open, or closing */ + initial_size = buf_datalen(conn->outbuf); + result = flush_buf_tls(or_conn->tls, conn->outbuf, + max_to_write, &conn->outbuf_flushlen); + + /* If we just flushed the last bytes, tell the channel on the + * or_conn to check if it needs to geoip_change_dirreq_state() */ + /* XXXX move this to flushed_some or finished_flushing -NM */ + if (buf_datalen(conn->outbuf) == 0 && or_conn->chan) + channel_notify_flushed(TLS_CHAN_TO_BASE(or_conn->chan)); + + switch (result) { + CASE_TOR_TLS_ERROR_ANY: + case TOR_TLS_CLOSE: + log_info(LD_NET, result != TOR_TLS_CLOSE ? + "tls error. breaking.":"TLS connection closed on flush"); + /* Don't flush; connection is dead. */ + connection_or_notify_error(or_conn, + END_OR_CONN_REASON_MISC, + result != TOR_TLS_CLOSE ? + "TLS error in during flush" : + "TLS closed during flush"); + connection_close_immediate(conn); + /* + * This can bypass normal channel checking since we did + * connection_or_notify_error() above. + */ + connection_mark_for_close_internal(conn); + return -1; + case TOR_TLS_WANTWRITE: + log_debug(LD_NET,"wanted write."); + /* we're already writing */ + dont_stop_writing = 1; + break; + case TOR_TLS_WANTREAD: + /* Make sure to avoid a loop if the receive buckets are empty. */ + log_debug(LD_NET,"wanted read."); + if (!connection_is_reading(conn)) { + connection_stop_writing(conn); + conn->write_blocked_on_bw = 1; + /* we'll start reading again when we get more tokens in our + * read bucket; then we'll start writing again too. + */ + } + /* else no problem, we're already reading */ + return 0; + /* case TOR_TLS_DONE: + * for TOR_TLS_DONE, fall through to check if the flushlen + * is empty, so we can stop writing. + */ + } + + tor_tls_get_n_raw_bytes(or_conn->tls, &n_read, &n_written); + log_debug(LD_GENERAL, "After TLS write of %d: %ld read, %ld written", + result, (long)n_read, (long)n_written); + /* So we notice bytes were written even on error */ + /* XXXX024 This cast is safe since we can never write INT_MAX bytes in a + * single set of TLS operations. But it looks kinda ugly. If we refactor + * the *_buf_tls functions, we should make them return ssize_t or size_t + * or something. */ + result = (int)(initial_size-buf_datalen(conn->outbuf)); + } else { + CONN_LOG_PROTECT(conn, + result = flush_buf(conn->s, conn->outbuf, + max_to_write, &conn->outbuf_flushlen)); + if (result < 0) { + if (CONN_IS_EDGE(conn)) + connection_edge_end_errno(TO_EDGE_CONN(conn)); + if (conn->type == CONN_TYPE_AP) { + /* writing failed; we couldn't send a SOCKS reply if we wanted to */ + TO_ENTRY_CONN(conn)->socks_request->has_finished = 1; + } + + connection_close_immediate(conn); /* Don't flush; connection is dead. */ + connection_mark_for_close(conn); + return -1; + } + n_written = (size_t) result; + } + + if (n_written && conn->type == CONN_TYPE_AP) { + edge_connection_t *edge_conn = TO_EDGE_CONN(conn); + circuit_t *circ = circuit_get_by_edge_conn(edge_conn); + origin_circuit_t *ocirc; + + /* Check for overflow: */ + if (PREDICT_LIKELY(UINT32_MAX - edge_conn->n_written > n_written)) + edge_conn->n_written += (int)n_written; + else + edge_conn->n_written = UINT32_MAX; + + if (circ && CIRCUIT_IS_ORIGIN(circ)) { + ocirc = TO_ORIGIN_CIRCUIT(circ); + if (PREDICT_LIKELY(UINT32_MAX - ocirc->n_written_circ_bw > n_written)) + ocirc->n_written_circ_bw += (int)n_written; + else + ocirc->n_written_circ_bw = UINT32_MAX; + } + } + + /* If CONN_BW events are enabled, update conn->n_written_conn_bw for + * OR/DIR/EXIT connections, checking for overflow. */ + if (n_written && get_options()->TestingEnableConnBwEvent && + (conn->type == CONN_TYPE_OR || + conn->type == CONN_TYPE_DIR || + conn->type == CONN_TYPE_EXIT)) { + if (PREDICT_LIKELY(UINT32_MAX - conn->n_written_conn_bw > n_written)) + conn->n_written_conn_bw += (int)n_written; + else + conn->n_written_conn_bw = UINT32_MAX; + } + + connection_buckets_decrement(conn, approx_time(), n_read, n_written); + + if (result > 0) { + /* If we wrote any bytes from our buffer, then call the appropriate + * functions. */ + if (connection_flushed_some(conn) < 0) { + if (connection_speaks_cells(conn)) { + connection_or_notify_error(TO_OR_CONN(conn), + END_OR_CONN_REASON_MISC, + "Got error back from " + "connection_flushed_some()"); + } + + /* + * This can bypass normal channel checking since we did + * connection_or_notify_error() above. + */ + connection_mark_for_close_internal(conn); + } + } + + if (!connection_wants_to_flush(conn) && + !dont_stop_writing) { /* it's done flushing */ + if (connection_finished_flushing(conn) < 0) { + /* already marked */ + return -1; + } + return 0; + } + + /* Call even if result is 0, since the global write bucket may + * have reached 0 on a different conn, and this guy needs to + * know to stop writing. */ + connection_consider_empty_write_buckets(conn); + if (n_read > 0 && connection_is_reading(conn)) + connection_consider_empty_read_buckets(conn); + + return 0; +} + +/* DOCDOC connection_handle_write */ +int +connection_handle_write(connection_t *conn, int force) +{ + int res; + tor_gettimeofday_cache_clear(); + conn->in_connection_handle_write = 1; + res = connection_handle_write_impl(conn, force); + conn->in_connection_handle_write = 0; + return res; +} + +/** + * Try to flush data that's waiting for a write on conn. Return + * -1 on failure, 0 on success. + * + * Don't use this function for regular writing; the buffers/bufferevents + * system should be good enough at scheduling writes there. Instead, this + * function is for cases when we're about to exit or something and we want + * to report it right away. + */ +int +connection_flush(connection_t *conn) +{ + IF_HAS_BUFFEREVENT(conn, { + int r = bufferevent_flush(conn->bufev, EV_WRITE, BEV_FLUSH); + return (r < 0) ? -1 : 0; + }); + return connection_handle_write(conn, 1); +} + +/** Append len bytes of string onto conn's + * outbuf, and ask it to start writing. + * + * If zlib is nonzero, this is a directory connection that should get + * its contents compressed or decompressed as they're written. If zlib is + * negative, this is the last data to be compressed, and the connection's zlib + * state should be flushed. + * + * If it's a local control connection and a 64k chunk is ready, try to flush + * it all, so we don't end up with many megabytes of controller info queued at + * once. + */ +MOCK_IMPL(void, +connection_write_to_buf_impl_,(const char *string, size_t len, + connection_t *conn, int zlib)) +{ + /* XXXX This function really needs to return -1 on failure. */ + int r; + size_t old_datalen; + if (!len && !(zlib<0)) + return; + /* if it's marked for close, only allow write if we mean to flush it */ + if (conn->marked_for_close && !conn->hold_open_until_flushed) + return; + + IF_HAS_BUFFEREVENT(conn, { + if (zlib) { + int done = zlib < 0; + r = write_to_evbuffer_zlib(bufferevent_get_output(conn->bufev), + TO_DIR_CONN(conn)->zlib_state, + string, len, done); + } else { + r = bufferevent_write(conn->bufev, string, len); + } + if (r < 0) { + /* XXXX mark for close? */ + log_warn(LD_NET, "bufferevent_write failed! That shouldn't happen."); + } + return; + }); + + old_datalen = buf_datalen(conn->outbuf); + if (zlib) { + dir_connection_t *dir_conn = TO_DIR_CONN(conn); + int done = zlib < 0; + CONN_LOG_PROTECT(conn, r = write_to_buf_zlib(conn->outbuf, + dir_conn->zlib_state, + string, len, done)); + } else { + CONN_LOG_PROTECT(conn, r = write_to_buf(string, len, conn->outbuf)); + } + if (r < 0) { + if (CONN_IS_EDGE(conn)) { + /* if it failed, it means we have our package/delivery windows set + wrong compared to our max outbuf size. close the whole circuit. */ + log_warn(LD_NET, + "write_to_buf failed. Closing circuit (fd %d).", (int)conn->s); + circuit_mark_for_close(circuit_get_by_edge_conn(TO_EDGE_CONN(conn)), + END_CIRC_REASON_INTERNAL); + } else { + log_warn(LD_NET, + "write_to_buf failed. Closing connection (fd %d).", + (int)conn->s); + connection_mark_for_close(conn); + } + return; + } + + /* If we receive optimistic data in the EXIT_CONN_STATE_RESOLVING + * state, we don't want to try to write it right away, since + * conn->write_event won't be set yet. Otherwise, write data from + * this conn as the socket is available. */ + if (conn->write_event) { + connection_start_writing(conn); + } + if (zlib) { + conn->outbuf_flushlen += buf_datalen(conn->outbuf) - old_datalen; + } else { + conn->outbuf_flushlen += len; + + /* Should we try flushing the outbuf now? */ + if (conn->in_flushed_some) { + /* Don't flush the outbuf when the reason we're writing more stuff is + * _because_ we flushed the outbuf. That's unfair. */ + return; + } + + if (conn->type == CONN_TYPE_CONTROL && + !connection_is_rate_limited(conn) && + conn->outbuf_flushlen-len < 1<<16 && + conn->outbuf_flushlen >= 1<<16) { + /* just try to flush all of it */ + } else + return; /* no need to try flushing */ + + if (connection_handle_write(conn, 0) < 0) { + if (!conn->marked_for_close) { + /* this connection is broken. remove it. */ + log_warn(LD_BUG, "unhandled error on write for " + "conn (type %d, fd %d); removing", + conn->type, (int)conn->s); + tor_fragile_assert(); + /* do a close-immediate here, so we don't try to flush */ + connection_close_immediate(conn); + } + return; + } + } +} + +/** Return a connection with given type, address, port, and purpose; + * or NULL if no such connection exists. */ +connection_t * +connection_get_by_type_addr_port_purpose(int type, + const tor_addr_t *addr, uint16_t port, + int purpose) +{ + smartlist_t *conns = get_connection_array(); + SMARTLIST_FOREACH(conns, connection_t *, conn, + { + if (conn->type == type && + tor_addr_eq(&conn->addr, addr) && + conn->port == port && + conn->purpose == purpose && + !conn->marked_for_close) + return conn; + }); + return NULL; +} + +/** Return the stream with id id if it is not already marked for + * close. + */ +connection_t * +connection_get_by_global_id(uint64_t id) +{ + smartlist_t *conns = get_connection_array(); + SMARTLIST_FOREACH(conns, connection_t *, conn, + { + if (conn->global_identifier == id) + return conn; + }); + return NULL; +} + +/** Return a connection of type type that is not marked for close. + */ +connection_t * +connection_get_by_type(int type) +{ + smartlist_t *conns = get_connection_array(); + SMARTLIST_FOREACH(conns, connection_t *, conn, + { + if (conn->type == type && !conn->marked_for_close) + return conn; + }); + return NULL; +} + +/** Return a connection of type type that is in state state, + * and that is not marked for close. + */ +connection_t * +connection_get_by_type_state(int type, int state) +{ + smartlist_t *conns = get_connection_array(); + SMARTLIST_FOREACH(conns, connection_t *, conn, + { + if (conn->type == type && conn->state == state && !conn->marked_for_close) + return conn; + }); + return NULL; +} + +/** Return a connection of type type that has rendquery equal + * to rendquery, and that is not marked for close. If state + * is non-zero, conn must be of that state too. + */ +connection_t * +connection_get_by_type_state_rendquery(int type, int state, + const char *rendquery) +{ + smartlist_t *conns = get_connection_array(); + + tor_assert(type == CONN_TYPE_DIR || + type == CONN_TYPE_AP || type == CONN_TYPE_EXIT); + tor_assert(rendquery); + + SMARTLIST_FOREACH_BEGIN(conns, connection_t *, conn) { + if (conn->type == type && + !conn->marked_for_close && + (!state || state == conn->state)) { + if (type == CONN_TYPE_DIR && + TO_DIR_CONN(conn)->rend_data && + !rend_cmp_service_ids(rendquery, + TO_DIR_CONN(conn)->rend_data->onion_address)) + return conn; + else if (CONN_IS_EDGE(conn) && + TO_EDGE_CONN(conn)->rend_data && + !rend_cmp_service_ids(rendquery, + TO_EDGE_CONN(conn)->rend_data->onion_address)) + return conn; + } + } SMARTLIST_FOREACH_END(conn); + return NULL; +} + +/** Return a directory connection (if any one exists) that is fetching + * the item described by state/resource */ +dir_connection_t * +connection_dir_get_by_purpose_and_resource(int purpose, + const char *resource) +{ + smartlist_t *conns = get_connection_array(); + + SMARTLIST_FOREACH_BEGIN(conns, connection_t *, conn) { + dir_connection_t *dirconn; + if (conn->type != CONN_TYPE_DIR || conn->marked_for_close || + conn->purpose != purpose) + continue; + dirconn = TO_DIR_CONN(conn); + if (dirconn->requested_resource == NULL) { + if (resource == NULL) + return dirconn; + } else if (resource) { + if (0 == strcmp(resource, dirconn->requested_resource)) + return dirconn; + } + } SMARTLIST_FOREACH_END(conn); + + return NULL; +} + +/** Return an open, non-marked connection of a given type and purpose, or NULL + * if no such connection exists. */ +connection_t * +connection_get_by_type_purpose(int type, int purpose) +{ + smartlist_t *conns = get_connection_array(); + SMARTLIST_FOREACH(conns, connection_t *, conn, + { + if (conn->type == type && + !conn->marked_for_close && + (purpose == conn->purpose)) + return conn; + }); + return NULL; +} + +/** Return 1 if conn is a listener conn, else return 0. */ +int +connection_is_listener(connection_t *conn) +{ + if (conn->type == CONN_TYPE_OR_LISTENER || + conn->type == CONN_TYPE_EXT_OR_LISTENER || + conn->type == CONN_TYPE_AP_LISTENER || + conn->type == CONN_TYPE_AP_TRANS_LISTENER || + conn->type == CONN_TYPE_AP_DNS_LISTENER || + conn->type == CONN_TYPE_AP_NATD_LISTENER || + conn->type == CONN_TYPE_DIR_LISTENER || + conn->type == CONN_TYPE_CONTROL_LISTENER) + return 1; + return 0; +} + +/** Return 1 if conn is in state "open" and is not marked + * for close, else return 0. + */ +int +connection_state_is_open(connection_t *conn) +{ + tor_assert(conn); + + if (conn->marked_for_close) + return 0; + + if ((conn->type == CONN_TYPE_OR && conn->state == OR_CONN_STATE_OPEN) || + (conn->type == CONN_TYPE_EXT_OR) || + (conn->type == CONN_TYPE_AP && conn->state == AP_CONN_STATE_OPEN) || + (conn->type == CONN_TYPE_EXIT && conn->state == EXIT_CONN_STATE_OPEN) || + (conn->type == CONN_TYPE_CONTROL && + conn->state == CONTROL_CONN_STATE_OPEN)) + return 1; + + return 0; +} + +/** Return 1 if conn is in 'connecting' state, else return 0. */ +int +connection_state_is_connecting(connection_t *conn) +{ + tor_assert(conn); + + if (conn->marked_for_close) + return 0; + switch (conn->type) + { + case CONN_TYPE_OR: + return conn->state == OR_CONN_STATE_CONNECTING; + case CONN_TYPE_EXIT: + return conn->state == EXIT_CONN_STATE_CONNECTING; + case CONN_TYPE_DIR: + return conn->state == DIR_CONN_STATE_CONNECTING; + } + + return 0; +} + +/** Allocates a base64'ed authenticator for use in http or https + * auth, based on the input string authenticator. Returns it + * if success, else returns NULL. */ +char * +alloc_http_authenticator(const char *authenticator) +{ + /* an authenticator in Basic authentication + * is just the string "username:password" */ + const size_t authenticator_length = strlen(authenticator); + /* The base64_encode function needs a minimum buffer length + * of 66 bytes. */ + const size_t base64_authenticator_length = (authenticator_length/48+1)*66; + char *base64_authenticator = tor_malloc(base64_authenticator_length); + if (base64_encode(base64_authenticator, base64_authenticator_length, + authenticator, authenticator_length) < 0) { + tor_free(base64_authenticator); /* free and set to null */ + } else { + int i = 0, j = 0; + ssize_t len = strlen(base64_authenticator); + + /* remove all newline occurrences within the string */ + for (i=0; i < len; ++i) { + if ('\n' != base64_authenticator[i]) { + base64_authenticator[j] = base64_authenticator[i]; + ++j; + } + } + base64_authenticator[j]='\0'; + } + return base64_authenticator; +} + +/** Given a socket handle, check whether the local address (sockname) of the + * socket is one that we've connected from before. If so, double-check + * whether our address has changed and we need to generate keys. If we do, + * call init_keys(). + */ +static void +client_check_address_changed(tor_socket_t sock) +{ + struct sockaddr_storage out_sockaddr; + socklen_t out_addr_len = (socklen_t) sizeof(out_sockaddr); + tor_addr_t out_addr, iface_addr; + tor_addr_t **last_interface_ip_ptr; + sa_family_t family; + + if (!outgoing_addrs) + outgoing_addrs = smartlist_new(); + + if (getsockname(sock, (struct sockaddr*)&out_sockaddr, &out_addr_len)<0) { + int e = tor_socket_errno(sock); + log_warn(LD_NET, "getsockname() to check for address change failed: %s", + tor_socket_strerror(e)); + return; + } + tor_addr_from_sockaddr(&out_addr, (struct sockaddr*)&out_sockaddr, NULL); + family = tor_addr_family(&out_addr); + + if (family == AF_INET) + last_interface_ip_ptr = &last_interface_ipv4; + else if (family == AF_INET6) + last_interface_ip_ptr = &last_interface_ipv6; + else + return; + + if (! *last_interface_ip_ptr) { + tor_addr_t *a = tor_malloc_zero(sizeof(tor_addr_t)); + if (get_interface_address6(LOG_INFO, family, a)==0) { + *last_interface_ip_ptr = a; + } else { + tor_free(a); + } + } + + /* If we've used this address previously, we're okay. */ + SMARTLIST_FOREACH(outgoing_addrs, const tor_addr_t *, a_ptr, + if (tor_addr_eq(a_ptr, &out_addr)) + return; + ); + + /* Uh-oh. We haven't connected from this address before. Has the interface + * address changed? */ + if (get_interface_address6(LOG_INFO, family, &iface_addr)<0) + return; + + if (tor_addr_eq(&iface_addr, *last_interface_ip_ptr)) { + /* Nope, it hasn't changed. Add this address to the list. */ + smartlist_add(outgoing_addrs, tor_memdup(&out_addr, sizeof(tor_addr_t))); + } else { + /* The interface changed. We're a client, so we need to regenerate our + * keys. First, reset the state. */ + log_notice(LD_NET, "Our IP address has changed. Rotating keys..."); + tor_addr_copy(*last_interface_ip_ptr, &iface_addr); + SMARTLIST_FOREACH(outgoing_addrs, tor_addr_t*, a_ptr, tor_free(a_ptr)); + smartlist_clear(outgoing_addrs); + smartlist_add(outgoing_addrs, tor_memdup(&out_addr, sizeof(tor_addr_t))); + /* Okay, now change our keys. */ + ip_address_changed(1); + } +} + +/** Some systems have limited system buffers for recv and xmit on + * sockets allocated in a virtual server or similar environment. For a Tor + * server this can produce the "Error creating network socket: No buffer + * space available" error once all available TCP buffer space is consumed. + * This method will attempt to constrain the buffers allocated for the socket + * to the desired size to stay below system TCP buffer limits. + */ +static void +set_constrained_socket_buffers(tor_socket_t sock, int size) +{ + void *sz = (void*)&size; + socklen_t sz_sz = (socklen_t) sizeof(size); + if (setsockopt(sock, SOL_SOCKET, SO_SNDBUF, sz, sz_sz) < 0) { + int e = tor_socket_errno(sock); + log_warn(LD_NET, "setsockopt() to constrain send " + "buffer to %d bytes failed: %s", size, tor_socket_strerror(e)); + } + if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, sz, sz_sz) < 0) { + int e = tor_socket_errno(sock); + log_warn(LD_NET, "setsockopt() to constrain recv " + "buffer to %d bytes failed: %s", size, tor_socket_strerror(e)); + } +} + +/** Process new bytes that have arrived on conn-\>inbuf. + * + * This function just passes conn to the connection-specific + * connection_*_process_inbuf() function. It also passes in + * package_partial if wanted. + */ +static int +connection_process_inbuf(connection_t *conn, int package_partial) +{ + tor_assert(conn); + + switch (conn->type) { + case CONN_TYPE_OR: + return connection_or_process_inbuf(TO_OR_CONN(conn)); + case CONN_TYPE_EXT_OR: + return connection_ext_or_process_inbuf(TO_OR_CONN(conn)); + case CONN_TYPE_EXIT: + case CONN_TYPE_AP: + return connection_edge_process_inbuf(TO_EDGE_CONN(conn), + package_partial); + case CONN_TYPE_DIR: + return connection_dir_process_inbuf(TO_DIR_CONN(conn)); + case CONN_TYPE_CPUWORKER: + return connection_cpu_process_inbuf(conn); + case CONN_TYPE_CONTROL: + return connection_control_process_inbuf(TO_CONTROL_CONN(conn)); + default: + log_err(LD_BUG,"got unexpected conn type %d.", conn->type); + tor_fragile_assert(); + return -1; + } +} + +/** Called whenever we've written data on a connection. */ +static int +connection_flushed_some(connection_t *conn) +{ + int r = 0; + tor_assert(!conn->in_flushed_some); + conn->in_flushed_some = 1; + if (conn->type == CONN_TYPE_DIR && + conn->state == DIR_CONN_STATE_SERVER_WRITING) { + r = connection_dirserv_flushed_some(TO_DIR_CONN(conn)); + } else if (conn->type == CONN_TYPE_OR) { + r = connection_or_flushed_some(TO_OR_CONN(conn)); + } else if (CONN_IS_EDGE(conn)) { + r = connection_edge_flushed_some(TO_EDGE_CONN(conn)); + } + conn->in_flushed_some = 0; + return r; +} + +/** We just finished flushing bytes to the appropriately low network layer, + * and there are no more bytes remaining in conn-\>outbuf, conn-\>bev, or + * conn-\>tls to be flushed. + * + * This function just passes conn to the connection-specific + * connection_*_finished_flushing() function. + */ +static int +connection_finished_flushing(connection_t *conn) +{ + tor_assert(conn); + + /* If the connection is closed, don't try to do anything more here. */ + if (CONN_IS_CLOSED(conn)) + return 0; + +// log_fn(LOG_DEBUG,"entered. Socket %u.", conn->s); + + IF_HAS_NO_BUFFEREVENT(conn) + connection_stop_writing(conn); + + switch (conn->type) { + case CONN_TYPE_OR: + return connection_or_finished_flushing(TO_OR_CONN(conn)); + case CONN_TYPE_EXT_OR: + return connection_ext_or_finished_flushing(TO_OR_CONN(conn)); + case CONN_TYPE_AP: + case CONN_TYPE_EXIT: + return connection_edge_finished_flushing(TO_EDGE_CONN(conn)); + case CONN_TYPE_DIR: + return connection_dir_finished_flushing(TO_DIR_CONN(conn)); + case CONN_TYPE_CPUWORKER: + return connection_cpu_finished_flushing(conn); + case CONN_TYPE_CONTROL: + return connection_control_finished_flushing(TO_CONTROL_CONN(conn)); + default: + log_err(LD_BUG,"got unexpected conn type %d.", conn->type); + tor_fragile_assert(); + return -1; + } +} + +/** Called when our attempt to connect() to another server has just + * succeeded. + * + * This function just passes conn to the connection-specific + * connection_*_finished_connecting() function. + */ +static int +connection_finished_connecting(connection_t *conn) +{ + tor_assert(conn); + + if (!server_mode(get_options())) { + /* See whether getsockname() says our address changed. We need to do this + * now that the connection has finished, because getsockname() on Windows + * won't work until then. */ + client_check_address_changed(conn->s); + } + + switch (conn->type) + { + case CONN_TYPE_OR: + return connection_or_finished_connecting(TO_OR_CONN(conn)); + case CONN_TYPE_EXIT: + return connection_edge_finished_connecting(TO_EDGE_CONN(conn)); + case CONN_TYPE_DIR: + return connection_dir_finished_connecting(TO_DIR_CONN(conn)); + default: + log_err(LD_BUG,"got unexpected conn type %d.", conn->type); + tor_fragile_assert(); + return -1; + } +} + +/** Callback: invoked when a connection reaches an EOF event. */ +static int +connection_reached_eof(connection_t *conn) +{ + switch (conn->type) { + case CONN_TYPE_OR: + case CONN_TYPE_EXT_OR: + return connection_or_reached_eof(TO_OR_CONN(conn)); + case CONN_TYPE_AP: + case CONN_TYPE_EXIT: + return connection_edge_reached_eof(TO_EDGE_CONN(conn)); + case CONN_TYPE_DIR: + return connection_dir_reached_eof(TO_DIR_CONN(conn)); + case CONN_TYPE_CPUWORKER: + return connection_cpu_reached_eof(conn); + case CONN_TYPE_CONTROL: + return connection_control_reached_eof(TO_CONTROL_CONN(conn)); + default: + log_err(LD_BUG,"got unexpected conn type %d.", conn->type); + tor_fragile_assert(); + return -1; + } +} + +/** Log how many bytes are used by buffers of different kinds and sizes. */ +void +connection_dump_buffer_mem_stats(int severity) +{ + uint64_t used_by_type[CONN_TYPE_MAX_+1]; + uint64_t alloc_by_type[CONN_TYPE_MAX_+1]; + int n_conns_by_type[CONN_TYPE_MAX_+1]; + uint64_t total_alloc = 0; + uint64_t total_used = 0; + int i; + smartlist_t *conns = get_connection_array(); + + memset(used_by_type, 0, sizeof(used_by_type)); + memset(alloc_by_type, 0, sizeof(alloc_by_type)); + memset(n_conns_by_type, 0, sizeof(n_conns_by_type)); + + SMARTLIST_FOREACH_BEGIN(conns, connection_t *, c) { + int tp = c->type; + ++n_conns_by_type[tp]; + if (c->inbuf) { + used_by_type[tp] += buf_datalen(c->inbuf); + alloc_by_type[tp] += buf_allocation(c->inbuf); + } + if (c->outbuf) { + used_by_type[tp] += buf_datalen(c->outbuf); + alloc_by_type[tp] += buf_allocation(c->outbuf); + } + } SMARTLIST_FOREACH_END(c); + for (i=0; i <= CONN_TYPE_MAX_; ++i) { + total_used += used_by_type[i]; + total_alloc += alloc_by_type[i]; + } + + tor_log(severity, LD_GENERAL, + "In buffers for %d connections: "U64_FORMAT" used/"U64_FORMAT" allocated", + smartlist_len(conns), + U64_PRINTF_ARG(total_used), U64_PRINTF_ARG(total_alloc)); + for (i=CONN_TYPE_MIN_; i <= CONN_TYPE_MAX_; ++i) { + if (!n_conns_by_type[i]) + continue; + tor_log(severity, LD_GENERAL, + " For %d %s connections: "U64_FORMAT" used/"U64_FORMAT" allocated", + n_conns_by_type[i], conn_type_to_string(i), + U64_PRINTF_ARG(used_by_type[i]), U64_PRINTF_ARG(alloc_by_type[i])); + } +} + +/** Verify that connection conn has all of its invariants + * correct. Trigger an assert if anything is invalid. + */ +void +assert_connection_ok(connection_t *conn, time_t now) +{ + (void) now; /* XXXX unused. */ + tor_assert(conn); + tor_assert(conn->type >= CONN_TYPE_MIN_); + tor_assert(conn->type <= CONN_TYPE_MAX_); + +#ifdef USE_BUFFEREVENTS + if (conn->bufev) { + tor_assert(conn->read_event == NULL); + tor_assert(conn->write_event == NULL); + tor_assert(conn->inbuf == NULL); + tor_assert(conn->outbuf == NULL); + } +#endif + + switch (conn->type) { + case CONN_TYPE_OR: + case CONN_TYPE_EXT_OR: + tor_assert(conn->magic == OR_CONNECTION_MAGIC); + break; + case CONN_TYPE_AP: + tor_assert(conn->magic == ENTRY_CONNECTION_MAGIC); + break; + case CONN_TYPE_EXIT: + tor_assert(conn->magic == EDGE_CONNECTION_MAGIC); + break; + case CONN_TYPE_DIR: + tor_assert(conn->magic == DIR_CONNECTION_MAGIC); + break; + case CONN_TYPE_CONTROL: + tor_assert(conn->magic == CONTROL_CONNECTION_MAGIC); + break; + CASE_ANY_LISTENER_TYPE: + tor_assert(conn->magic == LISTENER_CONNECTION_MAGIC); + break; + default: + tor_assert(conn->magic == BASE_CONNECTION_MAGIC); + break; + } + + if (conn->linked_conn) { + tor_assert(conn->linked_conn->linked_conn == conn); + tor_assert(conn->linked); + } + if (conn->linked) + tor_assert(!SOCKET_OK(conn->s)); + + if (conn->outbuf_flushlen > 0) { + /* With optimistic data, we may have queued data in + * EXIT_CONN_STATE_RESOLVING while the conn is not yet marked to writing. + * */ + tor_assert((conn->type == CONN_TYPE_EXIT && + conn->state == EXIT_CONN_STATE_RESOLVING) || + connection_is_writing(conn) || + conn->write_blocked_on_bw || + (CONN_IS_EDGE(conn) && + TO_EDGE_CONN(conn)->edge_blocked_on_circ)); + } + + if (conn->hold_open_until_flushed) + tor_assert(conn->marked_for_close); + + /* XXXX check: read_blocked_on_bw, write_blocked_on_bw, s, conn_array_index, + * marked_for_close. */ + + /* buffers */ + if (conn->inbuf) + assert_buf_ok(conn->inbuf); + if (conn->outbuf) + assert_buf_ok(conn->outbuf); + + if (conn->type == CONN_TYPE_OR) { + or_connection_t *or_conn = TO_OR_CONN(conn); + if (conn->state == OR_CONN_STATE_OPEN) { + /* tor_assert(conn->bandwidth > 0); */ + /* the above isn't necessarily true: if we just did a TLS + * handshake but we didn't recognize the other peer, or it + * gave a bad cert/etc, then we won't have assigned bandwidth, + * yet it will be open. -RD + */ +// tor_assert(conn->read_bucket >= 0); + } +// tor_assert(conn->addr && conn->port); + tor_assert(conn->address); + if (conn->state > OR_CONN_STATE_PROXY_HANDSHAKING) + tor_assert(or_conn->tls); + } + + if (CONN_IS_EDGE(conn)) { + /* XXX unchecked: package window, deliver window. */ + if (conn->type == CONN_TYPE_AP) { + entry_connection_t *entry_conn = TO_ENTRY_CONN(conn); + if (entry_conn->chosen_exit_optional || entry_conn->chosen_exit_retries) + tor_assert(entry_conn->chosen_exit_name); + + tor_assert(entry_conn->socks_request); + if (conn->state == AP_CONN_STATE_OPEN) { + tor_assert(entry_conn->socks_request->has_finished); + if (!conn->marked_for_close) { + tor_assert(ENTRY_TO_EDGE_CONN(entry_conn)->cpath_layer); + assert_cpath_layer_ok(ENTRY_TO_EDGE_CONN(entry_conn)->cpath_layer); + } + } + } + if (conn->type == CONN_TYPE_EXIT) { + tor_assert(conn->purpose == EXIT_PURPOSE_CONNECT || + conn->purpose == EXIT_PURPOSE_RESOLVE); + } + } else if (conn->type == CONN_TYPE_DIR) { + } else { + /* Purpose is only used for dir and exit types currently */ + tor_assert(!conn->purpose); + } + + switch (conn->type) + { + CASE_ANY_LISTENER_TYPE: + tor_assert(conn->state == LISTENER_STATE_READY); + break; + case CONN_TYPE_OR: + tor_assert(conn->state >= OR_CONN_STATE_MIN_); + tor_assert(conn->state <= OR_CONN_STATE_MAX_); + break; + case CONN_TYPE_EXT_OR: + tor_assert(conn->state >= EXT_OR_CONN_STATE_MIN_); + tor_assert(conn->state <= EXT_OR_CONN_STATE_MAX_); + break; + case CONN_TYPE_EXIT: + tor_assert(conn->state >= EXIT_CONN_STATE_MIN_); + tor_assert(conn->state <= EXIT_CONN_STATE_MAX_); + tor_assert(conn->purpose >= EXIT_PURPOSE_MIN_); + tor_assert(conn->purpose <= EXIT_PURPOSE_MAX_); + break; + case CONN_TYPE_AP: + tor_assert(conn->state >= AP_CONN_STATE_MIN_); + tor_assert(conn->state <= AP_CONN_STATE_MAX_); + tor_assert(TO_ENTRY_CONN(conn)->socks_request); + break; + case CONN_TYPE_DIR: + tor_assert(conn->state >= DIR_CONN_STATE_MIN_); + tor_assert(conn->state <= DIR_CONN_STATE_MAX_); + tor_assert(conn->purpose >= DIR_PURPOSE_MIN_); + tor_assert(conn->purpose <= DIR_PURPOSE_MAX_); + break; + case CONN_TYPE_CPUWORKER: + tor_assert(conn->state >= CPUWORKER_STATE_MIN_); + tor_assert(conn->state <= CPUWORKER_STATE_MAX_); + break; + case CONN_TYPE_CONTROL: + tor_assert(conn->state >= CONTROL_CONN_STATE_MIN_); + tor_assert(conn->state <= CONTROL_CONN_STATE_MAX_); + break; + default: + tor_assert(0); + } +} + +/** Fills addr and port with the details of the global + * proxy server we are using. + * conn contains the connection we are using the proxy for. + * + * Return 0 on success, -1 on failure. + */ +int +get_proxy_addrport(tor_addr_t *addr, uint16_t *port, int *proxy_type, + const connection_t *conn) +{ + const or_options_t *options = get_options(); + + if (options->HTTPSProxy) { + tor_addr_copy(addr, &options->HTTPSProxyAddr); + *port = options->HTTPSProxyPort; + *proxy_type = PROXY_CONNECT; + return 0; + } else if (options->Socks4Proxy) { + tor_addr_copy(addr, &options->Socks4ProxyAddr); + *port = options->Socks4ProxyPort; + *proxy_type = PROXY_SOCKS4; + return 0; + } else if (options->Socks5Proxy) { + tor_addr_copy(addr, &options->Socks5ProxyAddr); + *port = options->Socks5ProxyPort; + *proxy_type = PROXY_SOCKS5; + return 0; + } else if (options->ClientTransportPlugin || + options->Bridges) { + const transport_t *transport = NULL; + int r; + r = get_transport_by_bridge_addrport(&conn->addr, conn->port, &transport); + if (r<0) + return -1; + if (transport) { /* transport found */ + tor_addr_copy(addr, &transport->addr); + *port = transport->port; + *proxy_type = transport->socks_version; + return 0; + } + } + + *proxy_type = PROXY_NONE; + return 0; +} + +/** Log a failed connection to a proxy server. + * conn is the connection we use the proxy server for. */ +void +log_failed_proxy_connection(connection_t *conn) +{ + tor_addr_t proxy_addr; + uint16_t proxy_port; + int proxy_type; + + if (get_proxy_addrport(&proxy_addr, &proxy_port, &proxy_type, conn) != 0) + return; /* if we have no proxy set up, leave this function. */ + + log_warn(LD_NET, + "The connection to the %s proxy server at %s just failed. " + "Make sure that the proxy server is up and running.", + proxy_type_to_string(get_proxy_type()), + fmt_addrport(&proxy_addr, proxy_port)); +} + +/** Return string representation of proxy_type. */ +static const char * +proxy_type_to_string(int proxy_type) +{ + switch (proxy_type) { + case PROXY_CONNECT: return "HTTP"; + case PROXY_SOCKS4: return "SOCKS4"; + case PROXY_SOCKS5: return "SOCKS5"; + case PROXY_PLUGGABLE: return "pluggable transports SOCKS"; + case PROXY_NONE: return "NULL"; + default: tor_assert(0); + } + return NULL; /*Unreached*/ +} + +/** Call connection_free_() on every connection in our array, and release all + * storage held by connection.c. This is used by cpuworkers and dnsworkers + * when they fork, so they don't keep resources held open (especially + * sockets). + * + * Don't do the checks in connection_free(), because they will + * fail. + */ +void +connection_free_all(void) +{ + smartlist_t *conns = get_connection_array(); + + /* We don't want to log any messages to controllers. */ + SMARTLIST_FOREACH(conns, connection_t *, conn, + if (conn->type == CONN_TYPE_CONTROL) + TO_CONTROL_CONN(conn)->event_mask = 0); + + control_update_global_event_mask(); + + /* Unlink everything from the identity map. */ + connection_or_clear_identity_map(); + connection_or_clear_ext_or_id_map(); + + /* Clear out our list of broken connections */ + clear_broken_connection_map(0); + + SMARTLIST_FOREACH(conns, connection_t *, conn, connection_free_(conn)); + + if (outgoing_addrs) { + SMARTLIST_FOREACH(outgoing_addrs, tor_addr_t *, addr, tor_free(addr)); + smartlist_free(outgoing_addrs); + outgoing_addrs = NULL; + } + + tor_free(last_interface_ipv4); + tor_free(last_interface_ipv6); + +#ifdef USE_BUFFEREVENTS + if (global_rate_limit) + bufferevent_rate_limit_group_free(global_rate_limit); +#endif +} + diff --git a/src/tor/connection.h b/src/tor/connection.h new file mode 100644 index 0000000..4073d9f --- /dev/null +++ b/src/tor/connection.h @@ -0,0 +1,231 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file connection.h + * \brief Header file for connection.c. + **/ + +#ifndef TOR_CONNECTION_H +#define TOR_CONNECTION_H + +/* XXXX For buf_datalen in inline function */ +#include "buffers.h" + +const char *conn_type_to_string(int type); +const char *conn_state_to_string(int type, int state); + +dir_connection_t *dir_connection_new(int socket_family); +or_connection_t *or_connection_new(int type, int socket_family); +edge_connection_t *edge_connection_new(int type, int socket_family); +entry_connection_t *entry_connection_new(int type, int socket_family); +control_connection_t *control_connection_new(int socket_family); +listener_connection_t *listener_connection_new(int type, int socket_family); +connection_t *connection_new(int type, int socket_family); + +void connection_link_connections(connection_t *conn_a, connection_t *conn_b); +void connection_free(connection_t *conn); +void connection_free_all(void); +void connection_about_to_close_connection(connection_t *conn); +void connection_close_immediate(connection_t *conn); +void connection_mark_for_close_(connection_t *conn, + int line, const char *file); +void connection_mark_for_close_internal_(connection_t *conn, + int line, const char *file); + +#define connection_mark_for_close(c) \ + connection_mark_for_close_((c), __LINE__, SHORT_FILE__) +#define connection_mark_for_close_internal(c) \ + connection_mark_for_close_internal_((c), __LINE__, SHORT_FILE__) + +/** + * Mark 'c' for close, but try to hold it open until all the data is written. + * Use the _internal versions of connection_mark_for_close; this should be + * called when you either are sure that if this is an or_connection_t the + * controlling channel has been notified (e.g. with + * connection_or_notify_error()), or you actually are the + * connection_or_close_for_error() or connection_or_close_normally function. + * For all other cases, use connection_mark_and_flush() instead, which + * checks for or_connection_t properly, instead. See below. + */ +#define connection_mark_and_flush_internal_(c,line,file) \ + do { \ + connection_t *tmp_conn_ = (c); \ + connection_mark_for_close_internal_(tmp_conn_, (line), (file)); \ + tmp_conn_->hold_open_until_flushed = 1; \ + IF_HAS_BUFFEREVENT(tmp_conn_, \ + connection_start_writing(tmp_conn_)); \ + } while (0) + +#define connection_mark_and_flush_internal(c) \ + connection_mark_and_flush_internal_((c), __LINE__, SHORT_FILE__) + +/** + * Mark 'c' for close, but try to hold it open until all the data is written. + */ +#define connection_mark_and_flush_(c,line,file) \ + do { \ + connection_t *tmp_conn_ = (c); \ + if (tmp_conn_->type == CONN_TYPE_OR) { \ + log_warn(LD_CHANNEL | LD_BUG, \ + "Something tried to close (and flush) an or_connection_t" \ + " without going through channels at %s:%d", \ + file, line); \ + connection_or_close_for_error(TO_OR_CONN(tmp_conn_), 1); \ + } else { \ + connection_mark_and_flush_internal_(c, line, file); \ + } \ + } while (0) + +#define connection_mark_and_flush(c) \ + connection_mark_and_flush_((c), __LINE__, SHORT_FILE__) + +void connection_expire_held_open(void); + +int connection_connect(connection_t *conn, const char *address, + const tor_addr_t *addr, + uint16_t port, int *socket_error); + +/** Maximum size of information that we can fit into SOCKS5 username + or password fields. */ +#define MAX_SOCKS5_AUTH_FIELD_SIZE 255 + +/** Total maximum size of information that we can fit into SOCKS5 + username and password fields. */ +#define MAX_SOCKS5_AUTH_SIZE_TOTAL 2*MAX_SOCKS5_AUTH_FIELD_SIZE + +int connection_proxy_connect(connection_t *conn, int type); +int connection_read_proxy_handshake(connection_t *conn); +void log_failed_proxy_connection(connection_t *conn); +int get_proxy_addrport(tor_addr_t *addr, uint16_t *port, int *proxy_type, + const connection_t *conn); + +int retry_all_listeners(smartlist_t *replaced_conns, + smartlist_t *new_conns, + int close_all_noncontrol); + +void connection_mark_all_noncontrol_listeners(void); +void connection_mark_all_noncontrol_connections(void); + +ssize_t connection_bucket_write_limit(connection_t *conn, time_t now); +int global_write_bucket_low(connection_t *conn, size_t attempt, int priority); +void connection_bucket_init(void); +void connection_bucket_refill(int seconds_elapsed, time_t now); + +int connection_handle_read(connection_t *conn); + +int connection_fetch_from_buf(char *string, size_t len, connection_t *conn); +int connection_fetch_from_buf_line(connection_t *conn, char *data, + size_t *data_len); +int connection_fetch_from_buf_http(connection_t *conn, + char **headers_out, size_t max_headerlen, + char **body_out, size_t *body_used, + size_t max_bodylen, int force_complete); + +int connection_wants_to_flush(connection_t *conn); +int connection_outbuf_too_full(connection_t *conn); +int connection_handle_write(connection_t *conn, int force); +int connection_flush(connection_t *conn); + +MOCK_DECL(void, connection_write_to_buf_impl_, + (const char *string, size_t len, connection_t *conn, int zlib)); +/* DOCDOC connection_write_to_buf */ +static void connection_write_to_buf(const char *string, size_t len, + connection_t *conn); +/* DOCDOC connection_write_to_buf_zlib */ +static void connection_write_to_buf_zlib(const char *string, size_t len, + dir_connection_t *conn, int done); +static INLINE void +connection_write_to_buf(const char *string, size_t len, connection_t *conn) +{ + connection_write_to_buf_impl_(string, len, conn, 0); +} +static INLINE void +connection_write_to_buf_zlib(const char *string, size_t len, + dir_connection_t *conn, int done) +{ + connection_write_to_buf_impl_(string, len, TO_CONN(conn), done ? -1 : 1); +} + +/* DOCDOC connection_get_inbuf_len */ +static size_t connection_get_inbuf_len(connection_t *conn); +/* DOCDOC connection_get_outbuf_len */ +static size_t connection_get_outbuf_len(connection_t *conn); + +static INLINE size_t +connection_get_inbuf_len(connection_t *conn) +{ + IF_HAS_BUFFEREVENT(conn, { + return evbuffer_get_length(bufferevent_get_input(conn->bufev)); + }) ELSE_IF_NO_BUFFEREVENT { + return conn->inbuf ? buf_datalen(conn->inbuf) : 0; + } +} + +static INLINE size_t +connection_get_outbuf_len(connection_t *conn) +{ + IF_HAS_BUFFEREVENT(conn, { + return evbuffer_get_length(bufferevent_get_output(conn->bufev)); + }) ELSE_IF_NO_BUFFEREVENT { + return conn->outbuf ? buf_datalen(conn->outbuf) : 0; + } +} + +connection_t *connection_get_by_global_id(uint64_t id); + +connection_t *connection_get_by_type(int type); +connection_t *connection_get_by_type_purpose(int type, int purpose); +connection_t *connection_get_by_type_addr_port_purpose(int type, + const tor_addr_t *addr, + uint16_t port, int purpose); +connection_t *connection_get_by_type_state(int type, int state); +connection_t *connection_get_by_type_state_rendquery(int type, int state, + const char *rendquery); +dir_connection_t *connection_dir_get_by_purpose_and_resource( + int state, const char *resource); + +#define connection_speaks_cells(conn) ((conn)->type == CONN_TYPE_OR) +int connection_is_listener(connection_t *conn); +int connection_state_is_open(connection_t *conn); +int connection_state_is_connecting(connection_t *conn); + +char *alloc_http_authenticator(const char *authenticator); + +void assert_connection_ok(connection_t *conn, time_t now); +int connection_or_nonopen_was_started_here(or_connection_t *conn); +void connection_dump_buffer_mem_stats(int severity); +void remove_file_if_very_old(const char *fname, time_t now); + +#ifdef USE_BUFFEREVENTS +int connection_type_uses_bufferevent(connection_t *conn); +void connection_configure_bufferevent_callbacks(connection_t *conn); +void connection_handle_read_cb(struct bufferevent *bufev, void *arg); +void connection_handle_write_cb(struct bufferevent *bufev, void *arg); +void connection_handle_event_cb(struct bufferevent *bufev, short event, + void *arg); +void connection_get_rate_limit_totals(uint64_t *read_out, + uint64_t *written_out); +void connection_enable_rate_limiting(connection_t *conn); +#else +#define connection_type_uses_bufferevent(c) (0) +#endif + +#ifdef CONNECTION_PRIVATE +STATIC void connection_free_(connection_t *conn); + +/* Used only by connection.c and test*.c */ +uint32_t bucket_millis_empty(int tokens_before, uint32_t last_empty_time, + int tokens_after, int milliseconds_elapsed, + const struct timeval *tvnow); +void connection_buckets_note_empty_ts(uint32_t *timestamp_var, + int tokens_before, + size_t tokens_removed, + const struct timeval *tvnow); +#endif + +#endif + diff --git a/src/tor/connection_edge.c b/src/tor/connection_edge.c new file mode 100644 index 0000000..a794f37 --- /dev/null +++ b/src/tor/connection_edge.c @@ -0,0 +1,3119 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file connection_edge.c + * \brief Handle edge streams. + **/ +#define CONNECTION_EDGE_PRIVATE + +#include "or.h" +#include "addressmap.h" +#include "buffers.h" +#include "channel.h" +#include "circpathbias.h" +#include "circuitlist.h" +#include "circuituse.h" +#include "config.h" +#include "connection.h" +#include "connection_edge.h" +#include "connection_or.h" +#include "control.h" +#include "dns.h" +#include "dnsserv.h" +#include "dirserv.h" +#include "hibernate.h" +#include "onion_main.h" +#include "nodelist.h" +#include "policies.h" +#include "reasons.h" +#include "relay.h" +#include "rendclient.h" +#include "rendcommon.h" +#include "rendservice.h" +#include "rephist.h" +#include "router.h" +#include "routerlist.h" +#include "routerset.h" +#include "circuitbuild.h" + +#ifdef HAVE_LINUX_TYPES_H +#include +#endif +#ifdef HAVE_LINUX_NETFILTER_IPV4_H +#include +#define TRANS_NETFILTER +#endif + +#if defined(HAVE_NET_IF_H) && defined(HAVE_NET_PFVAR_H) +#include +#include +#define TRANS_PF +#endif + +#define SOCKS4_GRANTED 90 +#define SOCKS4_REJECT 91 + +static int connection_ap_handshake_process_socks(entry_connection_t *conn); +static int connection_ap_process_natd(entry_connection_t *conn); +static int connection_exit_connect_dir(edge_connection_t *exitconn); +static int consider_plaintext_ports(entry_connection_t *conn, uint16_t port); +static int connection_ap_supports_optimistic_data(const entry_connection_t *); +static void connection_ap_handshake_socks_resolved_addr( + entry_connection_t *conn, + const tor_addr_t *answer, + int ttl, + time_t expires); + +/** An AP stream has failed/finished. If it hasn't already sent back + * a socks reply, send one now (based on endreason). Also set + * has_sent_end to 1, and mark the conn. + */ +void +connection_mark_unattached_ap_(entry_connection_t *conn, int endreason, + int line, const char *file) +{ + connection_t *base_conn = ENTRY_TO_CONN(conn); + edge_connection_t *edge_conn = ENTRY_TO_EDGE_CONN(conn); + tor_assert(base_conn->type == CONN_TYPE_AP); + ENTRY_TO_EDGE_CONN(conn)->edge_has_sent_end = 1; /* no circ yet */ + + /* If this is a rendezvous stream and it is failing without ever + * being attached to a circuit, assume that an attempt to connect to + * the destination hidden service has just ended. + * + * XXXX This condition doesn't limit to only streams failing + * without ever being attached. That sloppiness should be harmless, + * but we should fix it someday anyway. */ + if ((edge_conn->on_circuit != NULL || edge_conn->edge_has_sent_end) && + connection_edge_is_rendezvous_stream(edge_conn)) { + rend_client_note_connection_attempt_ended( + edge_conn->rend_data->onion_address); + } + + if (base_conn->marked_for_close) { + /* This call will warn as appropriate. */ + connection_mark_for_close_(base_conn, line, file); + return; + } + + if (!conn->socks_request->has_finished) { + if (endreason & END_STREAM_REASON_FLAG_ALREADY_SOCKS_REPLIED) + log_warn(LD_BUG, + "stream (marked at %s:%d) sending two socks replies?", + file, line); + + if (SOCKS_COMMAND_IS_CONNECT(conn->socks_request->command)) + connection_ap_handshake_socks_reply(conn, NULL, 0, endreason); + else if (SOCKS_COMMAND_IS_RESOLVE(conn->socks_request->command)) + connection_ap_handshake_socks_resolved(conn, + RESOLVED_TYPE_ERROR_TRANSIENT, + 0, NULL, -1, -1); + else /* unknown or no handshake at all. send no response. */ + conn->socks_request->has_finished = 1; + } + + connection_mark_and_flush_(base_conn, line, file); + + ENTRY_TO_EDGE_CONN(conn)->end_reason = endreason; +} + +/** There was an EOF. Send an end and mark the connection for close. + */ +int +connection_edge_reached_eof(edge_connection_t *conn) +{ + if (connection_get_inbuf_len(TO_CONN(conn)) && + connection_state_is_open(TO_CONN(conn))) { + /* it still has stuff to process. don't let it die yet. */ + return 0; + } + log_info(LD_EDGE,"conn (fd "TOR_SOCKET_T_FORMAT") reached eof. Closing.", + conn->base_.s); + if (!conn->base_.marked_for_close) { + /* only mark it if not already marked. it's possible to + * get the 'end' right around when the client hangs up on us. */ + connection_edge_end(conn, END_STREAM_REASON_DONE); + if (conn->base_.type == CONN_TYPE_AP) { + /* eof, so don't send a socks reply back */ + if (EDGE_TO_ENTRY_CONN(conn)->socks_request) + EDGE_TO_ENTRY_CONN(conn)->socks_request->has_finished = 1; + } + connection_mark_for_close(TO_CONN(conn)); + } + return 0; +} + +/** Handle new bytes on conn->inbuf based on state: + * - If it's waiting for socks info, try to read another step of the + * socks handshake out of conn->inbuf. + * - If it's waiting for the original destination, fetch it. + * - If it's open, then package more relay cells from the stream. + * - Else, leave the bytes on inbuf alone for now. + * + * Mark and return -1 if there was an unexpected error with the conn, + * else return 0. + */ +int +connection_edge_process_inbuf(edge_connection_t *conn, int package_partial) +{ + tor_assert(conn); + + switch (conn->base_.state) { + case AP_CONN_STATE_SOCKS_WAIT: + if (connection_ap_handshake_process_socks(EDGE_TO_ENTRY_CONN(conn)) <0) { + /* already marked */ + return -1; + } + return 0; + case AP_CONN_STATE_NATD_WAIT: + if (connection_ap_process_natd(EDGE_TO_ENTRY_CONN(conn)) < 0) { + /* already marked */ + return -1; + } + return 0; + case AP_CONN_STATE_OPEN: + case EXIT_CONN_STATE_OPEN: + if (connection_edge_package_raw_inbuf(conn, package_partial, NULL) < 0) { + /* (We already sent an end cell if possible) */ + connection_mark_for_close(TO_CONN(conn)); + return -1; + } + return 0; + case AP_CONN_STATE_CONNECT_WAIT: + if (connection_ap_supports_optimistic_data(EDGE_TO_ENTRY_CONN(conn))) { + log_info(LD_EDGE, + "data from edge while in '%s' state. Sending it anyway. " + "package_partial=%d, buflen=%ld", + conn_state_to_string(conn->base_.type, conn->base_.state), + package_partial, + (long)connection_get_inbuf_len(TO_CONN(conn))); + if (connection_edge_package_raw_inbuf(conn, package_partial, NULL)<0) { + /* (We already sent an end cell if possible) */ + connection_mark_for_close(TO_CONN(conn)); + return -1; + } + return 0; + } + /* Fall through if the connection is on a circuit without optimistic + * data support. */ + case EXIT_CONN_STATE_CONNECTING: + case AP_CONN_STATE_RENDDESC_WAIT: + case AP_CONN_STATE_CIRCUIT_WAIT: + case AP_CONN_STATE_RESOLVE_WAIT: + case AP_CONN_STATE_CONTROLLER_WAIT: + log_info(LD_EDGE, + "data from edge while in '%s' state. Leaving it on buffer.", + conn_state_to_string(conn->base_.type, conn->base_.state)); + return 0; + } + log_warn(LD_BUG,"Got unexpected state %d. Closing.",conn->base_.state); + tor_fragile_assert(); + connection_edge_end(conn, END_STREAM_REASON_INTERNAL); + connection_mark_for_close(TO_CONN(conn)); + return -1; +} + +/** This edge needs to be closed, because its circuit has closed. + * Mark it for close and return 0. + */ +int +connection_edge_destroy(circid_t circ_id, edge_connection_t *conn) +{ + if (!conn->base_.marked_for_close) { + log_info(LD_EDGE, "CircID %u: At an edge. Marking connection for close.", + (unsigned) circ_id); + if (conn->base_.type == CONN_TYPE_AP) { + entry_connection_t *entry_conn = EDGE_TO_ENTRY_CONN(conn); + connection_mark_unattached_ap(entry_conn, END_STREAM_REASON_DESTROY); + control_event_stream_bandwidth(conn); + control_event_stream_status(entry_conn, STREAM_EVENT_CLOSED, + END_STREAM_REASON_DESTROY); + conn->end_reason |= END_STREAM_REASON_FLAG_ALREADY_SENT_CLOSED; + } else { + /* closing the circuit, nothing to send an END to */ + conn->edge_has_sent_end = 1; + conn->end_reason = END_STREAM_REASON_DESTROY; + conn->end_reason |= END_STREAM_REASON_FLAG_ALREADY_SENT_CLOSED; + connection_mark_and_flush(TO_CONN(conn)); + } + } + conn->cpath_layer = NULL; + conn->on_circuit = NULL; + return 0; +} + +/** Send a raw end cell to the stream with ID stream_id out over the + * circ towards the hop identified with cpath_layer. If this + * is not a client connection, set the relay end cell's reason for closing + * as reason */ +static int +relay_send_end_cell_from_edge(streamid_t stream_id, circuit_t *circ, + uint8_t reason, crypt_path_t *cpath_layer) +{ + char payload[1]; + + if (CIRCUIT_PURPOSE_IS_CLIENT(circ->purpose)) { + /* Never send the server an informative reason code; it doesn't need to + * know why the client stream is failing. */ + reason = END_STREAM_REASON_MISC; + } + + payload[0] = (char) reason; + + return relay_send_command_from_edge(stream_id, circ, RELAY_COMMAND_END, + payload, 1, cpath_layer); +} + +/** Send a relay end cell from stream conn down conn's circuit, and + * remember that we've done so. If this is not a client connection, set the + * relay end cell's reason for closing as reason. + * + * Return -1 if this function has already been called on this conn, + * else return 0. + */ +int +connection_edge_end(edge_connection_t *conn, uint8_t reason) +{ + char payload[RELAY_PAYLOAD_SIZE]; + size_t payload_len=1; + circuit_t *circ; + uint8_t control_reason = reason; + + if (conn->edge_has_sent_end) { + log_warn(LD_BUG,"(Harmless.) Calling connection_edge_end (reason %d) " + "on an already ended stream?", reason); + tor_fragile_assert(); + return -1; + } + + if (conn->base_.marked_for_close) { + log_warn(LD_BUG, + "called on conn that's already marked for close at %s:%d.", + conn->base_.marked_for_close_file, conn->base_.marked_for_close); + return 0; + } + + circ = circuit_get_by_edge_conn(conn); + if (circ && CIRCUIT_PURPOSE_IS_CLIENT(circ->purpose)) { + /* If this is a client circuit, don't send the server an informative + * reason code; it doesn't need to know why the client stream is + * failing. */ + reason = END_STREAM_REASON_MISC; + } + + payload[0] = (char)reason; + if (reason == END_STREAM_REASON_EXITPOLICY && + !connection_edge_is_rendezvous_stream(conn)) { + int addrlen; + if (tor_addr_family(&conn->base_.addr) == AF_INET) { + set_uint32(payload+1, tor_addr_to_ipv4n(&conn->base_.addr)); + addrlen = 4; + } else { + memcpy(payload+1, tor_addr_to_in6_addr8(&conn->base_.addr), 16); + addrlen = 16; + } + set_uint32(payload+1+addrlen, htonl(dns_clip_ttl(conn->address_ttl))); + payload_len += 4+addrlen; + } + + if (circ && !circ->marked_for_close) { + log_debug(LD_EDGE,"Sending end on conn (fd "TOR_SOCKET_T_FORMAT").", + conn->base_.s); + connection_edge_send_command(conn, RELAY_COMMAND_END, + payload, payload_len); + } else { + log_debug(LD_EDGE,"No circ to send end on conn " + "(fd "TOR_SOCKET_T_FORMAT").", + conn->base_.s); + } + + conn->edge_has_sent_end = 1; + conn->end_reason = control_reason; + return 0; +} + +/** An error has just occurred on an operation on an edge connection + * conn. Extract the errno; convert it to an end reason, and send an + * appropriate relay end cell to the other end of the connection's circuit. + **/ +int +connection_edge_end_errno(edge_connection_t *conn) +{ + uint8_t reason; + tor_assert(conn); + reason = errno_to_stream_end_reason(tor_socket_errno(conn->base_.s)); + return connection_edge_end(conn, reason); +} + +/** We just wrote some data to conn; act appropriately. + * + * (That is, if it's open, consider sending a stream-level sendme cell if we + * have just flushed enough.) + */ +int +connection_edge_flushed_some(edge_connection_t *conn) +{ + switch (conn->base_.state) { + case AP_CONN_STATE_OPEN: + case EXIT_CONN_STATE_OPEN: + connection_edge_consider_sending_sendme(conn); + break; + } + return 0; +} + +/** Connection conn has finished writing and has no bytes left on + * its outbuf. + * + * If it's in state 'open', stop writing, consider responding with a + * sendme, and return. + * Otherwise, stop writing and return. + * + * If conn is broken, mark it for close and return -1, else + * return 0. + */ +int +connection_edge_finished_flushing(edge_connection_t *conn) +{ + tor_assert(conn); + + switch (conn->base_.state) { + case AP_CONN_STATE_OPEN: + case EXIT_CONN_STATE_OPEN: + connection_edge_consider_sending_sendme(conn); + return 0; + case AP_CONN_STATE_SOCKS_WAIT: + case AP_CONN_STATE_NATD_WAIT: + case AP_CONN_STATE_RENDDESC_WAIT: + case AP_CONN_STATE_CIRCUIT_WAIT: + case AP_CONN_STATE_CONNECT_WAIT: + case AP_CONN_STATE_CONTROLLER_WAIT: + case AP_CONN_STATE_RESOLVE_WAIT: + return 0; + default: + log_warn(LD_BUG, "Called in unexpected state %d.",conn->base_.state); + tor_fragile_assert(); + return -1; + } + return 0; +} + +/** Longest size for the relay payload of a RELAY_CONNECTED cell that we're + * able to generate. */ +/* 4 zero bytes; 1 type byte; 16 byte IPv6 address; 4 byte TTL. */ +#define MAX_CONNECTED_CELL_PAYLOAD_LEN 25 + +/** Set the buffer at payload_out -- which must have at least + * MAX_CONNECTED_CELL_PAYLOAD_LEN bytes available -- to the body of a + * RELAY_CONNECTED cell indicating that we have connected to addr, and + * that the name resolution that led us to addr will be valid for + * ttl seconds. Return -1 on error, or the number of bytes used on + * success. */ +STATIC int +connected_cell_format_payload(uint8_t *payload_out, + const tor_addr_t *addr, + uint32_t ttl) +{ + const sa_family_t family = tor_addr_family(addr); + int connected_payload_len; + + /* should be needless */ + memset(payload_out, 0, MAX_CONNECTED_CELL_PAYLOAD_LEN); + + if (family == AF_INET) { + set_uint32(payload_out, tor_addr_to_ipv4n(addr)); + connected_payload_len = 4; + } else if (family == AF_INET6) { + set_uint32(payload_out, 0); + set_uint8(payload_out + 4, 6); + memcpy(payload_out + 5, tor_addr_to_in6_addr8(addr), 16); + connected_payload_len = 21; + } else { + return -1; + } + + set_uint32(payload_out + connected_payload_len, htonl(dns_clip_ttl(ttl))); + connected_payload_len += 4; + + tor_assert(connected_payload_len <= MAX_CONNECTED_CELL_PAYLOAD_LEN); + + return connected_payload_len; +} + +/** Connected handler for exit connections: start writing pending + * data, deliver 'CONNECTED' relay cells as appropriate, and check + * any pending data that may have been received. */ +int +connection_edge_finished_connecting(edge_connection_t *edge_conn) +{ + connection_t *conn; + + tor_assert(edge_conn); + tor_assert(edge_conn->base_.type == CONN_TYPE_EXIT); + conn = TO_CONN(edge_conn); + tor_assert(conn->state == EXIT_CONN_STATE_CONNECTING); + + log_info(LD_EXIT,"Exit connection to %s:%u (%s) established.", + escaped_safe_str(conn->address), conn->port, + safe_str(fmt_and_decorate_addr(&conn->addr))); + + rep_hist_note_exit_stream_opened(conn->port); + + conn->state = EXIT_CONN_STATE_OPEN; + IF_HAS_NO_BUFFEREVENT(conn) + connection_watch_events(conn, READ_EVENT); /* stop writing, keep reading */ + if (connection_get_outbuf_len(conn)) /* in case there are any queued relay + * cells */ + connection_start_writing(conn); + /* deliver a 'connected' relay cell back through the circuit. */ + if (connection_edge_is_rendezvous_stream(edge_conn)) { + if (connection_edge_send_command(edge_conn, + RELAY_COMMAND_CONNECTED, NULL, 0) < 0) + return 0; /* circuit is closed, don't continue */ + } else { + uint8_t connected_payload[MAX_CONNECTED_CELL_PAYLOAD_LEN]; + int connected_payload_len = + connected_cell_format_payload(connected_payload, &conn->addr, + edge_conn->address_ttl); + if (connected_payload_len < 0) + return -1; + + if (connection_edge_send_command(edge_conn, + RELAY_COMMAND_CONNECTED, + (char*)connected_payload, connected_payload_len) < 0) + return 0; /* circuit is closed, don't continue */ + } + tor_assert(edge_conn->package_window > 0); + /* in case the server has written anything */ + return connection_edge_process_inbuf(edge_conn, 1); +} + +/** Common code to connection_(ap|exit)_about_to_close. */ +static void +connection_edge_about_to_close(edge_connection_t *edge_conn) +{ + if (!edge_conn->edge_has_sent_end) { + connection_t *conn = TO_CONN(edge_conn); + log_warn(LD_BUG, "(Harmless.) Edge connection (marked at %s:%d) " + "hasn't sent end yet?", + conn->marked_for_close_file, conn->marked_for_close); + tor_fragile_assert(); + } +} + +/** Called when we're about to finally unlink and free an AP (client) + * connection: perform necessary accounting and cleanup */ +void +connection_ap_about_to_close(entry_connection_t *entry_conn) +{ + circuit_t *circ; + edge_connection_t *edge_conn = ENTRY_TO_EDGE_CONN(entry_conn); + connection_t *conn = ENTRY_TO_CONN(entry_conn); + + if (entry_conn->socks_request->has_finished == 0) { + /* since conn gets removed right after this function finishes, + * there's no point trying to send back a reply at this point. */ + log_warn(LD_BUG,"Closing stream (marked at %s:%d) without sending" + " back a socks reply.", + conn->marked_for_close_file, conn->marked_for_close); + } + if (!edge_conn->end_reason) { + log_warn(LD_BUG,"Closing stream (marked at %s:%d) without having" + " set end_reason.", + conn->marked_for_close_file, conn->marked_for_close); + } + if (entry_conn->dns_server_request) { + log_warn(LD_BUG,"Closing stream (marked at %s:%d) without having" + " replied to DNS request.", + conn->marked_for_close_file, conn->marked_for_close); + dnsserv_reject_request(entry_conn); + } + control_event_stream_bandwidth(edge_conn); + control_event_stream_status(entry_conn, STREAM_EVENT_CLOSED, + edge_conn->end_reason); + circ = circuit_get_by_edge_conn(edge_conn); + if (circ) + circuit_detach_stream(circ, edge_conn); +} + +/** Called when we're about to finally unlink and free an exit + * connection: perform necessary accounting and cleanup */ +void +connection_exit_about_to_close(edge_connection_t *edge_conn) +{ + circuit_t *circ; + connection_t *conn = TO_CONN(edge_conn); + + connection_edge_about_to_close(edge_conn); + + circ = circuit_get_by_edge_conn(edge_conn); + if (circ) + circuit_detach_stream(circ, edge_conn); + if (conn->state == EXIT_CONN_STATE_RESOLVING) { + connection_dns_remove(edge_conn); + } +} + +/** Define a schedule for how long to wait between retrying + * application connections. Rather than waiting a fixed amount of + * time between each retry, we wait 10 seconds each for the first + * two tries, and 15 seconds for each retry after + * that. Hopefully this will improve the expected user experience. */ +static int +compute_retry_timeout(entry_connection_t *conn) +{ + int timeout = get_options()->CircuitStreamTimeout; + if (timeout) /* if our config options override the default, use them */ + return timeout; + if (conn->num_socks_retries < 2) /* try 0 and try 1 */ + return 10; + return 15; +} + +/** Find all general-purpose AP streams waiting for a response that sent their + * begin/resolve cell too long ago. Detach from their current circuit, and + * mark their current circuit as unsuitable for new streams. Then call + * connection_ap_handshake_attach_circuit() to attach to a new circuit (if + * available) or launch a new one. + * + * For rendezvous streams, simply give up after SocksTimeout seconds (with no + * retry attempt). + */ +void +connection_ap_expire_beginning(void) +{ + edge_connection_t *conn; + entry_connection_t *entry_conn; + circuit_t *circ; + time_t now = time(NULL); + const or_options_t *options = get_options(); + int severity; + int cutoff; + int seconds_idle, seconds_since_born; + smartlist_t *conns = get_connection_array(); + + SMARTLIST_FOREACH_BEGIN(conns, connection_t *, base_conn) { + if (base_conn->type != CONN_TYPE_AP || base_conn->marked_for_close) + continue; + entry_conn = TO_ENTRY_CONN(base_conn); + conn = ENTRY_TO_EDGE_CONN(entry_conn); + /* if it's an internal linked connection, don't yell its status. */ + severity = (tor_addr_is_null(&base_conn->addr) && !base_conn->port) + ? LOG_INFO : LOG_NOTICE; + seconds_idle = (int)( now - base_conn->timestamp_lastread ); + seconds_since_born = (int)( now - base_conn->timestamp_created ); + + if (base_conn->state == AP_CONN_STATE_OPEN) + continue; + + /* We already consider SocksTimeout in + * connection_ap_handshake_attach_circuit(), but we need to consider + * it here too because controllers that put streams in controller_wait + * state never ask Tor to attach the circuit. */ + if (AP_CONN_STATE_IS_UNATTACHED(base_conn->state)) { + if (seconds_since_born >= options->SocksTimeout) { + log_fn(severity, LD_APP, + "Tried for %d seconds to get a connection to %s:%d. " + "Giving up. (%s)", + seconds_since_born, + safe_str_client(entry_conn->socks_request->address), + entry_conn->socks_request->port, + conn_state_to_string(CONN_TYPE_AP, base_conn->state)); + connection_mark_unattached_ap(entry_conn, END_STREAM_REASON_TIMEOUT); + } + continue; + } + + /* We're in state connect_wait or resolve_wait now -- waiting for a + * reply to our relay cell. See if we want to retry/give up. */ + + cutoff = compute_retry_timeout(entry_conn); + if (seconds_idle < cutoff) + continue; + circ = circuit_get_by_edge_conn(conn); + if (!circ) { /* it's vanished? */ + log_info(LD_APP,"Conn is waiting (address %s), but lost its circ.", + safe_str_client(entry_conn->socks_request->address)); + connection_mark_unattached_ap(entry_conn, END_STREAM_REASON_TIMEOUT); + continue; + } + if (circ->purpose == CIRCUIT_PURPOSE_C_REND_JOINED) { + if (seconds_idle >= options->SocksTimeout) { + log_fn(severity, LD_REND, + "Rend stream is %d seconds late. Giving up on address" + " '%s.onion'.", + seconds_idle, + safe_str_client(entry_conn->socks_request->address)); + /* Roll back path bias use state so that we probe the circuit + * if nothing else succeeds on it */ + pathbias_mark_use_rollback(TO_ORIGIN_CIRCUIT(circ)); + + connection_edge_end(conn, END_STREAM_REASON_TIMEOUT); + connection_mark_unattached_ap(entry_conn, END_STREAM_REASON_TIMEOUT); + } + continue; + } + if (circ->purpose != CIRCUIT_PURPOSE_C_GENERAL && + circ->purpose != CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT && + circ->purpose != CIRCUIT_PURPOSE_PATH_BIAS_TESTING) { + log_warn(LD_BUG, "circuit->purpose == CIRCUIT_PURPOSE_C_GENERAL failed. " + "The purpose on the circuit was %s; it was in state %s, " + "path_state %s.", + circuit_purpose_to_string(circ->purpose), + circuit_state_to_string(circ->state), + CIRCUIT_IS_ORIGIN(circ) ? + pathbias_state_to_string(TO_ORIGIN_CIRCUIT(circ)->path_state) : + "none"); + } + log_fn(cutoff < 15 ? LOG_INFO : severity, LD_APP, + "We tried for %d seconds to connect to '%s' using exit %s." + " Retrying on a new circuit.", + seconds_idle, + safe_str_client(entry_conn->socks_request->address), + conn->cpath_layer ? + extend_info_describe(conn->cpath_layer->extend_info): + "*unnamed*"); + /* send an end down the circuit */ + connection_edge_end(conn, END_STREAM_REASON_TIMEOUT); + /* un-mark it as ending, since we're going to reuse it */ + conn->edge_has_sent_end = 0; + conn->end_reason = 0; + /* make us not try this circuit again, but allow + * current streams on it to survive if they can */ + mark_circuit_unusable_for_new_conns(TO_ORIGIN_CIRCUIT(circ)); + + /* give our stream another 'cutoff' seconds to try */ + conn->base_.timestamp_lastread += cutoff; + if (entry_conn->num_socks_retries < 250) /* avoid overflow */ + entry_conn->num_socks_retries++; + /* move it back into 'pending' state, and try to attach. */ + if (connection_ap_detach_retriable(entry_conn, TO_ORIGIN_CIRCUIT(circ), + END_STREAM_REASON_TIMEOUT)<0) { + if (!base_conn->marked_for_close) + connection_mark_unattached_ap(entry_conn, + END_STREAM_REASON_CANT_ATTACH); + } + } SMARTLIST_FOREACH_END(base_conn); +} + +/** Tell any AP streams that are waiting for a new circuit to try again, + * either attaching to an available circ or launching a new one. + */ +void +connection_ap_attach_pending(void) +{ + entry_connection_t *entry_conn; + smartlist_t *conns = get_connection_array(); + SMARTLIST_FOREACH_BEGIN(conns, connection_t *, conn) { + if (conn->marked_for_close || + conn->type != CONN_TYPE_AP || + conn->state != AP_CONN_STATE_CIRCUIT_WAIT) + continue; + entry_conn = TO_ENTRY_CONN(conn); + if (connection_ap_handshake_attach_circuit(entry_conn) < 0) { + if (!conn->marked_for_close) + connection_mark_unattached_ap(entry_conn, + END_STREAM_REASON_CANT_ATTACH); + } + } SMARTLIST_FOREACH_END(conn); +} + +/** Tell any AP streams that are waiting for a one-hop tunnel to + * failed_digest that they are going to fail. */ +/* XXX024 We should get rid of this function, and instead attach + * one-hop streams to circ->p_streams so they get marked in + * circuit_mark_for_close like normal p_streams. */ +void +connection_ap_fail_onehop(const char *failed_digest, + cpath_build_state_t *build_state) +{ + entry_connection_t *entry_conn; + char digest[DIGEST_LEN]; + smartlist_t *conns = get_connection_array(); + SMARTLIST_FOREACH_BEGIN(conns, connection_t *, conn) { + if (conn->marked_for_close || + conn->type != CONN_TYPE_AP || + conn->state != AP_CONN_STATE_CIRCUIT_WAIT) + continue; + entry_conn = TO_ENTRY_CONN(conn); + if (!entry_conn->want_onehop) + continue; + if (hexdigest_to_digest(entry_conn->chosen_exit_name, digest) < 0 || + tor_memneq(digest, failed_digest, DIGEST_LEN)) + continue; + if (tor_digest_is_zero(digest)) { + /* we don't know the digest; have to compare addr:port */ + tor_addr_t addr; + if (!build_state || !build_state->chosen_exit || + !entry_conn->socks_request || !entry_conn->socks_request->address) + continue; + if (tor_addr_parse(&addr, entry_conn->socks_request->address)<0 || + !tor_addr_eq(&build_state->chosen_exit->addr, &addr) || + build_state->chosen_exit->port != entry_conn->socks_request->port) + continue; + } + log_info(LD_APP, "Closing one-hop stream to '%s/%s' because the OR conn " + "just failed.", entry_conn->chosen_exit_name, + entry_conn->socks_request->address); + connection_mark_unattached_ap(entry_conn, END_STREAM_REASON_TIMEOUT); + } SMARTLIST_FOREACH_END(conn); +} + +/** A circuit failed to finish on its last hop info. If there + * are any streams waiting with this exit node in mind, but they + * don't absolutely require it, make them give up on it. + */ +void +circuit_discard_optional_exit_enclaves(extend_info_t *info) +{ + entry_connection_t *entry_conn; + const node_t *r1, *r2; + + smartlist_t *conns = get_connection_array(); + SMARTLIST_FOREACH_BEGIN(conns, connection_t *, conn) { + if (conn->marked_for_close || + conn->type != CONN_TYPE_AP || + conn->state != AP_CONN_STATE_CIRCUIT_WAIT) + continue; + entry_conn = TO_ENTRY_CONN(conn); + if (!entry_conn->chosen_exit_optional && + !entry_conn->chosen_exit_retries) + continue; + r1 = node_get_by_nickname(entry_conn->chosen_exit_name, 0); + r2 = node_get_by_id(info->identity_digest); + if (!r1 || !r2 || r1 != r2) + continue; + tor_assert(entry_conn->socks_request); + if (entry_conn->chosen_exit_optional) { + log_info(LD_APP, "Giving up on enclave exit '%s' for destination %s.", + safe_str_client(entry_conn->chosen_exit_name), + escaped_safe_str_client(entry_conn->socks_request->address)); + entry_conn->chosen_exit_optional = 0; + tor_free(entry_conn->chosen_exit_name); /* clears it */ + /* if this port is dangerous, warn or reject it now that we don't + * think it'll be using an enclave. */ + consider_plaintext_ports(entry_conn, entry_conn->socks_request->port); + } + if (entry_conn->chosen_exit_retries) { + if (--entry_conn->chosen_exit_retries == 0) { /* give up! */ + clear_trackexithost_mappings(entry_conn->chosen_exit_name); + tor_free(entry_conn->chosen_exit_name); /* clears it */ + /* if this port is dangerous, warn or reject it now that we don't + * think it'll be using an enclave. */ + consider_plaintext_ports(entry_conn, entry_conn->socks_request->port); + } + } + } SMARTLIST_FOREACH_END(conn); +} + +/** The AP connection conn has just failed while attaching or + * sending a BEGIN or resolving on circ, but another circuit + * might work. Detach the circuit, and either reattach it, launch a + * new circuit, tell the controller, or give up as appropriate. + * + * Returns -1 on err, 1 on success, 0 on not-yet-sure. + */ +int +connection_ap_detach_retriable(entry_connection_t *conn, + origin_circuit_t *circ, + int reason) +{ + control_event_stream_status(conn, STREAM_EVENT_FAILED_RETRIABLE, reason); + ENTRY_TO_CONN(conn)->timestamp_lastread = time(NULL); + + /* Roll back path bias use state so that we probe the circuit + * if nothing else succeeds on it */ + pathbias_mark_use_rollback(circ); + + if (conn->pending_optimistic_data) { + generic_buffer_set_to_copy(&conn->sending_optimistic_data, + conn->pending_optimistic_data); + } + + if (!get_options()->LeaveStreamsUnattached || conn->use_begindir) { + /* If we're attaching streams ourself, or if this connection is + * a tunneled directory connection, then just attach it. */ + ENTRY_TO_CONN(conn)->state = AP_CONN_STATE_CIRCUIT_WAIT; + circuit_detach_stream(TO_CIRCUIT(circ),ENTRY_TO_EDGE_CONN(conn)); + return connection_ap_handshake_attach_circuit(conn); + } else { + ENTRY_TO_CONN(conn)->state = AP_CONN_STATE_CONTROLLER_WAIT; + circuit_detach_stream(TO_CIRCUIT(circ),ENTRY_TO_EDGE_CONN(conn)); + return 0; + } +} + +/** Check if conn is using a dangerous port. Then warn and/or + * reject depending on our config options. */ +static int +consider_plaintext_ports(entry_connection_t *conn, uint16_t port) +{ + const or_options_t *options = get_options(); + int reject = smartlist_contains_int_as_string( + options->RejectPlaintextPorts, port); + + if (smartlist_contains_int_as_string(options->WarnPlaintextPorts, port)) { + log_warn(LD_APP, "Application request to port %d: this port is " + "commonly used for unencrypted protocols. Please make sure " + "you don't send anything you would mind the rest of the " + "Internet reading!%s", port, reject ? " Closing." : ""); + control_event_client_status(LOG_WARN, "DANGEROUS_PORT PORT=%d RESULT=%s", + port, reject ? "REJECT" : "WARN"); + } + + if (reject) { + log_info(LD_APP, "Port %d listed in RejectPlaintextPorts. Closing.", port); + connection_mark_unattached_ap(conn, END_STREAM_REASON_ENTRYPOLICY); + return -1; + } + + return 0; +} + +/** How many times do we try connecting with an exit configured via + * TrackHostExits before concluding that it won't work any more and trying a + * different one? */ +#define TRACKHOSTEXITS_RETRIES 5 + +/** Call connection_ap_handshake_rewrite_and_attach() unless a controller + * asked us to leave streams unattached. Return 0 in that case. + * + * See connection_ap_handshake_rewrite_and_attach()'s + * documentation for arguments and return value. + */ +int +connection_ap_rewrite_and_attach_if_allowed(entry_connection_t *conn, + origin_circuit_t *circ, + crypt_path_t *cpath) +{ + const or_options_t *options = get_options(); + + if (options->LeaveStreamsUnattached) { + ENTRY_TO_CONN(conn)->state = AP_CONN_STATE_CONTROLLER_WAIT; + return 0; + } + return connection_ap_handshake_rewrite_and_attach(conn, circ, cpath); +} + +/** Connection conn just finished its socks handshake, or the + * controller asked us to take care of it. If circ is defined, + * then that's where we'll want to attach it. Otherwise we have to + * figure it out ourselves. + * + * First, parse whether it's a .exit address, remap it, and so on. Then + * if it's for a general circuit, try to attach it to a circuit (or launch + * one as needed), else if it's for a rendezvous circuit, fetch a + * rendezvous descriptor first (or attach/launch a circuit if the + * rendezvous descriptor is already here and fresh enough). + * + * The stream will exit from the hop + * indicated by cpath, or from the last hop in circ's cpath if + * cpath is NULL. + */ +int +connection_ap_handshake_rewrite_and_attach(entry_connection_t *conn, + origin_circuit_t *circ, + crypt_path_t *cpath) +{ + socks_request_t *socks = conn->socks_request; + hostname_type_t addresstype; + const or_options_t *options = get_options(); + tor_addr_t addr_tmp; + /* We set this to true if this is an address we should automatically + * remap to a local address in VirtualAddrNetwork */ + int automap = 0; + char orig_address[MAX_SOCKS_ADDR_LEN]; + time_t map_expires = TIME_MAX; + time_t now = time(NULL); + connection_t *base_conn = ENTRY_TO_CONN(conn); + addressmap_entry_source_t exit_source = ADDRMAPSRC_NONE; + + tor_strlower(socks->address); /* normalize it */ + strlcpy(orig_address, socks->address, sizeof(orig_address)); + log_debug(LD_APP,"Client asked for %s:%d", + safe_str_client(socks->address), + socks->port); + + if (!strcmpend(socks->address, ".exit") && !options->AllowDotExit) { + log_warn(LD_APP, "The \".exit\" notation is disabled in Tor due to " + "security risks. Set AllowDotExit in your torrc to enable " + "it (at your own risk)."); + control_event_client_status(LOG_WARN, "SOCKS_BAD_HOSTNAME HOSTNAME=%s", + escaped(socks->address)); + connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL); + return -1; + } + + if (! conn->original_dest_address) + conn->original_dest_address = tor_strdup(conn->socks_request->address); + + if (socks->command == SOCKS_COMMAND_RESOLVE && + tor_addr_parse(&addr_tmp, socks->address)<0 && + options->AutomapHostsOnResolve) { + automap = addressmap_address_should_automap(socks->address, options); + if (automap) { + const char *new_addr; + int addr_type = RESOLVED_TYPE_IPV4; + if (conn->socks_request->socks_version != 4) { + if (!conn->ipv4_traffic_ok || + (conn->ipv6_traffic_ok && conn->prefer_ipv6_traffic) || + conn->prefer_ipv6_virtaddr) + addr_type = RESOLVED_TYPE_IPV6; + } + new_addr = addressmap_register_virtual_address( + addr_type, tor_strdup(socks->address)); + if (! new_addr) { + log_warn(LD_APP, "Unable to automap address %s", + escaped_safe_str(socks->address)); + connection_mark_unattached_ap(conn, END_STREAM_REASON_INTERNAL); + return -1; + } + log_info(LD_APP, "Automapping %s to %s", + escaped_safe_str_client(socks->address), + safe_str_client(new_addr)); + strlcpy(socks->address, new_addr, sizeof(socks->address)); + } + } + + if (socks->command == SOCKS_COMMAND_RESOLVE_PTR) { + unsigned rewrite_flags = 0; + if (conn->use_cached_ipv4_answers) + rewrite_flags |= AMR_FLAG_USE_IPV4_DNS; + if (conn->use_cached_ipv6_answers) + rewrite_flags |= AMR_FLAG_USE_IPV6_DNS; + + if (addressmap_rewrite_reverse(socks->address, sizeof(socks->address), + rewrite_flags, &map_expires)) { + char *result = tor_strdup(socks->address); + /* remember _what_ is supposed to have been resolved. */ + tor_snprintf(socks->address, sizeof(socks->address), "REVERSE[%s]", + orig_address); + connection_ap_handshake_socks_resolved(conn, RESOLVED_TYPE_HOSTNAME, + strlen(result), (uint8_t*)result, + -1, + map_expires); + connection_mark_unattached_ap(conn, + END_STREAM_REASON_DONE | + END_STREAM_REASON_FLAG_ALREADY_SOCKS_REPLIED); + return 0; + } + if (options->ClientDNSRejectInternalAddresses) { + /* Don't let people try to do a reverse lookup on 10.0.0.1. */ + tor_addr_t addr; + int ok; + ok = tor_addr_parse_PTR_name( + &addr, socks->address, AF_UNSPEC, 1); + if (ok == 1 && tor_addr_is_internal(&addr, 0)) { + connection_ap_handshake_socks_resolved(conn, RESOLVED_TYPE_ERROR, + 0, NULL, -1, TIME_MAX); + connection_mark_unattached_ap(conn, + END_STREAM_REASON_SOCKSPROTOCOL | + END_STREAM_REASON_FLAG_ALREADY_SOCKS_REPLIED); + return -1; + } + } + } else if (!automap) { + /* For address map controls, remap the address. */ + unsigned rewrite_flags = 0; + if (conn->use_cached_ipv4_answers) + rewrite_flags |= AMR_FLAG_USE_IPV4_DNS; + if (conn->use_cached_ipv6_answers) + rewrite_flags |= AMR_FLAG_USE_IPV6_DNS; + if (addressmap_rewrite(socks->address, sizeof(socks->address), + rewrite_flags, &map_expires, &exit_source)) { + control_event_stream_status(conn, STREAM_EVENT_REMAP, + REMAP_STREAM_SOURCE_CACHE); + } + } + + if (!automap && address_is_in_virtual_range(socks->address)) { + /* This address was probably handed out by client_dns_get_unmapped_address, + * but the mapping was discarded for some reason. We *don't* want to send + * the address through Tor; that's likely to fail, and may leak + * information. + */ + log_warn(LD_APP,"Missing mapping for virtual address '%s'. Refusing.", + safe_str_client(socks->address)); + connection_mark_unattached_ap(conn, END_STREAM_REASON_INTERNAL); + return -1; + } + + /* Parse the address provided by SOCKS. Modify it in-place if it + * specifies a hidden-service (.onion) or particular exit node (.exit). + */ + addresstype = parse_extended_hostname(socks->address); + + if (addresstype == BAD_HOSTNAME) { + control_event_client_status(LOG_WARN, "SOCKS_BAD_HOSTNAME HOSTNAME=%s", + escaped(socks->address)); + connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL); + return -1; + } + + if (addresstype == EXIT_HOSTNAME) { + /* foo.exit -- modify conn->chosen_exit_node to specify the exit + * node, and conn->address to hold only the address portion. */ + char *s = strrchr(socks->address,'.'); + + /* If StrictNodes is not set, then .exit overrides ExcludeNodes. */ + routerset_t *excludeset = options->StrictNodes ? + options->ExcludeExitNodesUnion_ : options->ExcludeExitNodes; + const node_t *node; + + if (exit_source == ADDRMAPSRC_AUTOMAP && !options->AllowDotExit) { + /* Whoops; this one is stale. It must have gotten added earlier, + * when AllowDotExit was on. */ + log_warn(LD_APP,"Stale automapped address for '%s.exit', with " + "AllowDotExit disabled. Refusing.", + safe_str_client(socks->address)); + control_event_client_status(LOG_WARN, "SOCKS_BAD_HOSTNAME HOSTNAME=%s", + escaped(socks->address)); + connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL); + return -1; + } + + if (exit_source == ADDRMAPSRC_DNS || + (exit_source == ADDRMAPSRC_NONE && !options->AllowDotExit)) { + /* It shouldn't be possible to get a .exit address from any of these + * sources. */ + log_warn(LD_BUG,"Address '%s.exit', with impossible source for the " + ".exit part. Refusing.", + safe_str_client(socks->address)); + control_event_client_status(LOG_WARN, "SOCKS_BAD_HOSTNAME HOSTNAME=%s", + escaped(socks->address)); + connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL); + return -1; + } + + tor_assert(!automap); + if (s) { + /* The address was of the form "(stuff).(name).exit */ + if (s[1] != '\0') { + conn->chosen_exit_name = tor_strdup(s+1); + node = node_get_by_nickname(conn->chosen_exit_name, 1); + + if (exit_source == ADDRMAPSRC_TRACKEXIT) { + /* We 5 tries before it expires the addressmap */ + conn->chosen_exit_retries = TRACKHOSTEXITS_RETRIES; + } + *s = 0; + } else { + /* Oops, the address was (stuff)..exit. That's not okay. */ + log_warn(LD_APP,"Malformed exit address '%s.exit'. Refusing.", + safe_str_client(socks->address)); + control_event_client_status(LOG_WARN, "SOCKS_BAD_HOSTNAME HOSTNAME=%s", + escaped(socks->address)); + connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL); + return -1; + } + } else { + /* It looks like they just asked for "foo.exit". */ + + conn->chosen_exit_name = tor_strdup(socks->address); + node = node_get_by_nickname(conn->chosen_exit_name, 1); + if (node) { + *socks->address = 0; + node_get_address_string(node, socks->address, sizeof(socks->address)); + } + } + /* Now make sure that the chosen exit exists... */ + if (!node) { + log_warn(LD_APP, + "Unrecognized relay in exit address '%s.exit'. Refusing.", + safe_str_client(socks->address)); + connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL); + return -1; + } + /* ...and make sure that it isn't excluded. */ + if (routerset_contains_node(excludeset, node)) { + log_warn(LD_APP, + "Excluded relay in exit address '%s.exit'. Refusing.", + safe_str_client(socks->address)); + connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL); + return -1; + } + /* XXXX024-1090 Should we also allow foo.bar.exit if ExitNodes is set and + Bar is not listed in it? I say yes, but our revised manpage branch + implies no. */ + } + + if (addresstype != ONION_HOSTNAME) { + /* not a hidden-service request (i.e. normal or .exit) */ + if (address_is_invalid_destination(socks->address, 1)) { + control_event_client_status(LOG_WARN, "SOCKS_BAD_HOSTNAME HOSTNAME=%s", + escaped(socks->address)); + log_warn(LD_APP, + "Destination '%s' seems to be an invalid hostname. Failing.", + safe_str_client(socks->address)); + connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL); + return -1; + } + + if (options->Tor2webMode) { + log_warn(LD_APP, "Refusing to connect to non-hidden-service hostname %s " + "because tor2web mode is enabled.", + safe_str_client(socks->address)); + connection_mark_unattached_ap(conn, END_STREAM_REASON_ENTRYPOLICY); + return -1; + } + + if (socks->command == SOCKS_COMMAND_RESOLVE) { + tor_addr_t answer; + /* Reply to resolves immediately if we can. */ + if (tor_addr_parse(&answer, socks->address) >= 0) {/* is it an IP? */ + /* remember _what_ is supposed to have been resolved. */ + strlcpy(socks->address, orig_address, sizeof(socks->address)); + connection_ap_handshake_socks_resolved_addr(conn, &answer, -1, + map_expires); + connection_mark_unattached_ap(conn, + END_STREAM_REASON_DONE | + END_STREAM_REASON_FLAG_ALREADY_SOCKS_REPLIED); + return 0; + } + tor_assert(!automap); + rep_hist_note_used_resolve(now); /* help predict this next time */ + } else if (socks->command == SOCKS_COMMAND_CONNECT) { + tor_assert(!automap); + if (socks->port == 0) { + log_notice(LD_APP,"Application asked to connect to port 0. Refusing."); + connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL); + return -1; + } + if (options->ClientRejectInternalAddresses && + !conn->use_begindir && !conn->chosen_exit_name && !circ) { + tor_addr_t addr; + if (tor_addr_hostname_is_local(socks->address) || + (tor_addr_parse(&addr, socks->address) >= 0 && + tor_addr_is_internal(&addr, 0))) { + /* If this is an explicit private address with no chosen exit node, + * then we really don't want to try to connect to it. That's + * probably an error. */ + if (conn->is_transparent_ap) { +#define WARN_INTRVL_LOOP 300 + static ratelim_t loop_warn_limit = RATELIM_INIT(WARN_INTRVL_LOOP); + char *m; + if ((m = rate_limit_log(&loop_warn_limit, approx_time()))) { + log_warn(LD_NET, + "Rejecting request for anonymous connection to private " + "address %s on a TransPort or NATDPort. Possible loop " + "in your NAT rules?%s", safe_str_client(socks->address), + m); + tor_free(m); + } + } else { +#define WARN_INTRVL_PRIV 300 + static ratelim_t priv_warn_limit = RATELIM_INIT(WARN_INTRVL_PRIV); + char *m; + if ((m = rate_limit_log(&priv_warn_limit, approx_time()))) { + log_warn(LD_NET, + "Rejecting SOCKS request for anonymous connection to " + "private address %s.%s", + safe_str_client(socks->address),m); + tor_free(m); + } + } + connection_mark_unattached_ap(conn, END_STREAM_REASON_PRIVATE_ADDR); + return -1; + } + } + + { + tor_addr_t addr; + /* XXX Duplicate call to tor_addr_parse. */ + if (tor_addr_parse(&addr, socks->address) >= 0) { + sa_family_t family = tor_addr_family(&addr); + if ((family == AF_INET && ! conn->ipv4_traffic_ok) || + (family == AF_INET6 && ! conn->ipv4_traffic_ok)) { + log_warn(LD_NET, "Rejecting SOCKS request for an IP address " + "family that this listener does not support."); + connection_mark_unattached_ap(conn, END_STREAM_REASON_ENTRYPOLICY); + return -1; + } else if (family == AF_INET6 && socks->socks_version == 4) { + log_warn(LD_NET, "Rejecting SOCKS4 request for an IPv6 address."); + connection_mark_unattached_ap(conn, END_STREAM_REASON_ENTRYPOLICY); + return -1; + } else if (socks->socks_version == 4 && !conn->ipv4_traffic_ok) { + log_warn(LD_NET, "Rejecting SOCKS4 request on a listener with " + "no IPv4 traffic supported."); + connection_mark_unattached_ap(conn, END_STREAM_REASON_ENTRYPOLICY); + return -1; + } else if (family == AF_INET6) { + conn->ipv4_traffic_ok = 0; + } else if (family == AF_INET) { + conn->ipv6_traffic_ok = 0; + } + } + } + + if (socks->socks_version == 4) + conn->ipv6_traffic_ok = 0; + + if (!conn->use_begindir && !conn->chosen_exit_name && !circ) { + /* see if we can find a suitable enclave exit */ + const node_t *r = + router_find_exact_exit_enclave(socks->address, socks->port); + if (r) { + log_info(LD_APP, + "Redirecting address %s to exit at enclave router %s", + safe_str_client(socks->address), node_describe(r)); + /* use the hex digest, not nickname, in case there are two + routers with this nickname */ + conn->chosen_exit_name = + tor_strdup(hex_str(r->identity, DIGEST_LEN)); + conn->chosen_exit_optional = 1; + } + } + + /* warn or reject if it's using a dangerous port */ + if (!conn->use_begindir && !conn->chosen_exit_name && !circ) + if (consider_plaintext_ports(conn, socks->port) < 0) + return -1; + + if (!conn->use_begindir) { + /* help predict this next time */ + rep_hist_note_used_port(now, socks->port); + } + } else if (socks->command == SOCKS_COMMAND_RESOLVE_PTR) { + rep_hist_note_used_resolve(now); /* help predict this next time */ + /* no extra processing needed */ + } else { + tor_fragile_assert(); + } + base_conn->state = AP_CONN_STATE_CIRCUIT_WAIT; + if ((circ && connection_ap_handshake_attach_chosen_circuit( + conn, circ, cpath) < 0) || + (!circ && + connection_ap_handshake_attach_circuit(conn) < 0)) { + if (!base_conn->marked_for_close) + connection_mark_unattached_ap(conn, END_STREAM_REASON_CANT_ATTACH); + return -1; + } + return 0; + } else { + /* it's a hidden-service request */ + rend_cache_entry_t *entry; + int r; + rend_service_authorization_t *client_auth; + rend_data_t *rend_data; + tor_assert(!automap); + if (SOCKS_COMMAND_IS_RESOLVE(socks->command)) { + /* if it's a resolve request, fail it right now, rather than + * building all the circuits and then realizing it won't work. */ + log_warn(LD_APP, + "Resolve requests to hidden services not allowed. Failing."); + connection_ap_handshake_socks_resolved(conn,RESOLVED_TYPE_ERROR, + 0,NULL,-1,TIME_MAX); + connection_mark_unattached_ap(conn, + END_STREAM_REASON_SOCKSPROTOCOL | + END_STREAM_REASON_FLAG_ALREADY_SOCKS_REPLIED); + return -1; + } + + if (circ) { + log_warn(LD_CONTROL, "Attachstream to a circuit is not " + "supported for .onion addresses currently. Failing."); + connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL); + return -1; + } + + ENTRY_TO_EDGE_CONN(conn)->rend_data = rend_data = + tor_malloc_zero(sizeof(rend_data_t)); + strlcpy(rend_data->onion_address, socks->address, + sizeof(rend_data->onion_address)); + log_info(LD_REND,"Got a hidden service request for ID '%s'", + safe_str_client(rend_data->onion_address)); + /* see if we already have it cached */ + r = rend_cache_lookup_entry(rend_data->onion_address, -1, &entry); + if (r<0) { + log_warn(LD_BUG,"Invalid service name '%s'", + safe_str_client(rend_data->onion_address)); + connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL); + return -1; + } + + /* Help predict this next time. We're not sure if it will need + * a stable circuit yet, but we know we'll need *something*. */ + rep_hist_note_used_internal(now, 0, 1); + + /* Look up if we have client authorization for it. */ + client_auth = rend_client_lookup_service_authorization( + rend_data->onion_address); + if (client_auth) { + log_info(LD_REND, "Using previously configured client authorization " + "for hidden service request."); + memcpy(rend_data->descriptor_cookie, + client_auth->descriptor_cookie, REND_DESC_COOKIE_LEN); + rend_data->auth_type = client_auth->auth_type; + } + if (r==0) { + base_conn->state = AP_CONN_STATE_RENDDESC_WAIT; + log_info(LD_REND, "Unknown descriptor %s. Fetching.", + safe_str_client(rend_data->onion_address)); + rend_client_refetch_v2_renddesc(rend_data); + } else { /* r > 0 */ + base_conn->state = AP_CONN_STATE_CIRCUIT_WAIT; + log_info(LD_REND, "Descriptor is here. Great."); + if (connection_ap_handshake_attach_circuit(conn) < 0) { + if (!base_conn->marked_for_close) + connection_mark_unattached_ap(conn, END_STREAM_REASON_CANT_ATTACH); + return -1; + } + } + return 0; + } + return 0; /* unreached but keeps the compiler happy */ +} + +#ifdef TRANS_PF +static int pf_socket = -1; +int +get_pf_socket(void) +{ + int pf; + /* This should be opened before dropping privileges. */ + if (pf_socket >= 0) + return pf_socket; + +#ifdef OPENBSD + /* only works on OpenBSD */ + pf = tor_open_cloexec("/dev/pf", O_RDONLY, 0); +#else + /* works on NetBSD and FreeBSD */ + pf = tor_open_cloexec("/dev/pf", O_RDWR, 0); +#endif + + if (pf < 0) { + log_warn(LD_NET, "open(\"/dev/pf\") failed: %s", strerror(errno)); + return -1; + } + + pf_socket = pf; + return pf_socket; +} +#endif + +/** Fetch the original destination address and port from a + * system-specific interface and put them into a + * socks_request_t as if they came from a socks request. + * + * Return -1 if an error prevents fetching the destination, + * else return 0. + */ +static int +connection_ap_get_original_destination(entry_connection_t *conn, + socks_request_t *req) +{ +#ifdef TRANS_NETFILTER + /* Linux 2.4+ */ + struct sockaddr_storage orig_dst; + socklen_t orig_dst_len = sizeof(orig_dst); + tor_addr_t addr; + + if (getsockopt(ENTRY_TO_CONN(conn)->s, SOL_IP, SO_ORIGINAL_DST, + (struct sockaddr*)&orig_dst, &orig_dst_len) < 0) { + int e = tor_socket_errno(ENTRY_TO_CONN(conn)->s); + log_warn(LD_NET, "getsockopt() failed: %s", tor_socket_strerror(e)); + return -1; + } + + tor_addr_from_sockaddr(&addr, (struct sockaddr*)&orig_dst, &req->port); + tor_addr_to_str(req->address, &addr, sizeof(req->address), 1); + + return 0; +#elif defined(TRANS_PF) + struct sockaddr_storage proxy_addr; + socklen_t proxy_addr_len = sizeof(proxy_addr); + struct sockaddr *proxy_sa = (struct sockaddr*) &proxy_addr; + struct pfioc_natlook pnl; + tor_addr_t addr; + int pf = -1; + + if (getsockname(ENTRY_TO_CONN(conn)->s, (struct sockaddr*)&proxy_addr, + &proxy_addr_len) < 0) { + int e = tor_socket_errno(ENTRY_TO_CONN(conn)->s); + log_warn(LD_NET, "getsockname() to determine transocks destination " + "failed: %s", tor_socket_strerror(e)); + return -1; + } + + memset(&pnl, 0, sizeof(pnl)); + pnl.proto = IPPROTO_TCP; + pnl.direction = PF_OUT; + if (proxy_sa->sa_family == AF_INET) { + struct sockaddr_in *sin = (struct sockaddr_in *)proxy_sa; + pnl.af = AF_INET; + pnl.saddr.v4.s_addr = tor_addr_to_ipv4n(&ENTRY_TO_CONN(conn)->addr); + pnl.sport = htons(ENTRY_TO_CONN(conn)->port); + pnl.daddr.v4.s_addr = sin->sin_addr.s_addr; + pnl.dport = sin->sin_port; + } else if (proxy_sa->sa_family == AF_INET6) { + struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)proxy_sa; + pnl.af = AF_INET6; + memcpy(&pnl.saddr.v6, tor_addr_to_in6(&ENTRY_TO_CONN(conn)->addr), + sizeof(struct in6_addr)); + pnl.sport = htons(ENTRY_TO_CONN(conn)->port); + memcpy(&pnl.daddr.v6, &sin6->sin6_addr, sizeof(struct in6_addr)); + pnl.dport = sin6->sin6_port; + } else { + log_warn(LD_NET, "getsockname() gave an unexpected address family (%d)", + (int)proxy_sa->sa_family); + return -1; + } + + pf = get_pf_socket(); + if (pf<0) + return -1; + + if (ioctl(pf, DIOCNATLOOK, &pnl) < 0) { + log_warn(LD_NET, "ioctl(DIOCNATLOOK) failed: %s", strerror(errno)); + return -1; + } + + if (pnl.af == AF_INET) { + tor_addr_from_ipv4n(&addr, pnl.rdaddr.v4.s_addr); + } else if (pnl.af == AF_INET6) { + tor_addr_from_in6(&addr, &pnl.rdaddr.v6); + } else { + tor_fragile_assert(); + return -1; + } + + tor_addr_to_str(req->address, &addr, sizeof(req->address), 1); + req->port = ntohs(pnl.rdport); + + return 0; +#else + (void)conn; + (void)req; + log_warn(LD_BUG, "Called connection_ap_get_original_destination, but no " + "transparent proxy method was configured."); + return -1; +#endif +} + +/** connection_edge_process_inbuf() found a conn in state + * socks_wait. See if conn->inbuf has the right bytes to proceed with + * the socks handshake. + * + * If the handshake is complete, send it to + * connection_ap_handshake_rewrite_and_attach(). + * + * Return -1 if an unexpected error with conn occurs (and mark it for close), + * else return 0. + */ +static int +connection_ap_handshake_process_socks(entry_connection_t *conn) +{ + socks_request_t *socks; + int sockshere; + const or_options_t *options = get_options(); + int had_reply = 0; + connection_t *base_conn = ENTRY_TO_CONN(conn); + + tor_assert(conn); + tor_assert(base_conn->type == CONN_TYPE_AP); + tor_assert(base_conn->state == AP_CONN_STATE_SOCKS_WAIT); + tor_assert(conn->socks_request); + socks = conn->socks_request; + + log_debug(LD_APP,"entered."); + + IF_HAS_BUFFEREVENT(base_conn, { + struct evbuffer *input = bufferevent_get_input(base_conn->bufev); + sockshere = fetch_from_evbuffer_socks(input, socks, + options->TestSocks, options->SafeSocks); + }) ELSE_IF_NO_BUFFEREVENT { + sockshere = fetch_from_buf_socks(base_conn->inbuf, socks, + options->TestSocks, options->SafeSocks); + }; + + if (socks->replylen) { + had_reply = 1; + connection_write_to_buf((const char*)socks->reply, socks->replylen, + base_conn); + socks->replylen = 0; + if (sockshere == -1) { + /* An invalid request just got a reply, no additional + * one is necessary. */ + socks->has_finished = 1; + } + } + + if (sockshere == 0) { + log_debug(LD_APP,"socks handshake not all here yet."); + return 0; + } else if (sockshere == -1) { + if (!had_reply) { + log_warn(LD_APP,"Fetching socks handshake failed. Closing."); + connection_ap_handshake_socks_reply(conn, NULL, 0, + END_STREAM_REASON_SOCKSPROTOCOL); + } + connection_mark_unattached_ap(conn, + END_STREAM_REASON_SOCKSPROTOCOL | + END_STREAM_REASON_FLAG_ALREADY_SOCKS_REPLIED); + return -1; + } /* else socks handshake is done, continue processing */ + + if (SOCKS_COMMAND_IS_CONNECT(socks->command)) + control_event_stream_status(conn, STREAM_EVENT_NEW, 0); + else + control_event_stream_status(conn, STREAM_EVENT_NEW_RESOLVE, 0); + + return connection_ap_rewrite_and_attach_if_allowed(conn, NULL, NULL); +} + +/** connection_init_accepted_conn() found a new trans AP conn. + * Get the original destination and send it to + * connection_ap_handshake_rewrite_and_attach(). + * + * Return -1 if an unexpected error with conn (and it should be marked + * for close), else return 0. + */ +int +connection_ap_process_transparent(entry_connection_t *conn) +{ + socks_request_t *socks; + + tor_assert(conn); + tor_assert(conn->socks_request); + socks = conn->socks_request; + + /* pretend that a socks handshake completed so we don't try to + * send a socks reply down a transparent conn */ + socks->command = SOCKS_COMMAND_CONNECT; + socks->has_finished = 1; + + log_debug(LD_APP,"entered."); + + if (connection_ap_get_original_destination(conn, socks) < 0) { + log_warn(LD_APP,"Fetching original destination failed. Closing."); + connection_mark_unattached_ap(conn, + END_STREAM_REASON_CANT_FETCH_ORIG_DEST); + return -1; + } + /* we have the original destination */ + + control_event_stream_status(conn, STREAM_EVENT_NEW, 0); + + return connection_ap_rewrite_and_attach_if_allowed(conn, NULL, NULL); +} + +/** connection_edge_process_inbuf() found a conn in state natd_wait. See if + * conn-\>inbuf has the right bytes to proceed. See FreeBSD's libalias(3) and + * ProxyEncodeTcpStream() in src/lib/libalias/alias_proxy.c for the encoding + * form of the original destination. + * + * If the original destination is complete, send it to + * connection_ap_handshake_rewrite_and_attach(). + * + * Return -1 if an unexpected error with conn (and it should be marked + * for close), else return 0. + */ +static int +connection_ap_process_natd(entry_connection_t *conn) +{ + char tmp_buf[36], *tbuf, *daddr; + size_t tlen = 30; + int err, port_ok; + socks_request_t *socks; + + tor_assert(conn); + tor_assert(ENTRY_TO_CONN(conn)->state == AP_CONN_STATE_NATD_WAIT); + tor_assert(conn->socks_request); + socks = conn->socks_request; + + log_debug(LD_APP,"entered."); + + /* look for LF-terminated "[DEST ip_addr port]" + * where ip_addr is a dotted-quad and port is in string form */ + err = connection_fetch_from_buf_line(ENTRY_TO_CONN(conn), tmp_buf, &tlen); + if (err == 0) + return 0; + if (err < 0) { + log_warn(LD_APP,"NATD handshake failed (DEST too long). Closing"); + connection_mark_unattached_ap(conn, END_STREAM_REASON_INVALID_NATD_DEST); + return -1; + } + + if (strcmpstart(tmp_buf, "[DEST ")) { + log_warn(LD_APP,"NATD handshake was ill-formed; closing. The client " + "said: %s", + escaped(tmp_buf)); + connection_mark_unattached_ap(conn, END_STREAM_REASON_INVALID_NATD_DEST); + return -1; + } + + daddr = tbuf = &tmp_buf[0] + 6; /* after end of "[DEST " */ + if (!(tbuf = strchr(tbuf, ' '))) { + log_warn(LD_APP,"NATD handshake was ill-formed; closing. The client " + "said: %s", + escaped(tmp_buf)); + connection_mark_unattached_ap(conn, END_STREAM_REASON_INVALID_NATD_DEST); + return -1; + } + *tbuf++ = '\0'; + + /* pretend that a socks handshake completed so we don't try to + * send a socks reply down a natd conn */ + strlcpy(socks->address, daddr, sizeof(socks->address)); + socks->port = (uint16_t) + tor_parse_long(tbuf, 10, 1, 65535, &port_ok, &daddr); + if (!port_ok) { + log_warn(LD_APP,"NATD handshake failed; port %s is ill-formed or out " + "of range.", escaped(tbuf)); + connection_mark_unattached_ap(conn, END_STREAM_REASON_INVALID_NATD_DEST); + return -1; + } + + socks->command = SOCKS_COMMAND_CONNECT; + socks->has_finished = 1; + + control_event_stream_status(conn, STREAM_EVENT_NEW, 0); + + ENTRY_TO_CONN(conn)->state = AP_CONN_STATE_CIRCUIT_WAIT; + + return connection_ap_rewrite_and_attach_if_allowed(conn, NULL, NULL); +} + +/** Iterate over the two bytes of stream_id until we get one that is not + * already in use; return it. Return 0 if can't get a unique stream_id. + */ +streamid_t +get_unique_stream_id_by_circ(origin_circuit_t *circ) +{ + edge_connection_t *tmpconn; + streamid_t test_stream_id; + uint32_t attempts=0; + + again: + test_stream_id = circ->next_stream_id++; + if (++attempts > 1<<16) { + /* Make sure we don't loop forever if all stream_id's are used. */ + log_warn(LD_APP,"No unused stream IDs. Failing."); + return 0; + } + if (test_stream_id == 0) + goto again; + for (tmpconn = circ->p_streams; tmpconn; tmpconn=tmpconn->next_stream) + if (tmpconn->stream_id == test_stream_id) + goto again; + return test_stream_id; +} + +/** Return true iff conn is linked to a circuit and configured to use + * an exit that supports optimistic data. */ +static int +connection_ap_supports_optimistic_data(const entry_connection_t *conn) +{ + const edge_connection_t *edge_conn = ENTRY_TO_EDGE_CONN(conn); + /* We can only send optimistic data if we're connected to an open + general circuit. */ + if (edge_conn->on_circuit == NULL || + edge_conn->on_circuit->state != CIRCUIT_STATE_OPEN || + edge_conn->on_circuit->purpose != CIRCUIT_PURPOSE_C_GENERAL) + return 0; + + return conn->may_use_optimistic_data; +} + +/** Return a bitmask of BEGIN_FLAG_* flags that we should transmit in the + * RELAY_BEGIN cell for ap_conn. */ +static uint32_t +connection_ap_get_begincell_flags(entry_connection_t *ap_conn) +{ + edge_connection_t *edge_conn = ENTRY_TO_EDGE_CONN(ap_conn); + const node_t *exitnode = NULL; + const crypt_path_t *cpath_layer = edge_conn->cpath_layer; + uint32_t flags = 0; + + /* No flags for begindir */ + if (ap_conn->use_begindir) + return 0; + + /* No flags for hidden services. */ + if (edge_conn->on_circuit->purpose != CIRCUIT_PURPOSE_C_GENERAL) + return 0; + + /* If only IPv4 is supported, no flags */ + if (ap_conn->ipv4_traffic_ok && !ap_conn->ipv6_traffic_ok) + return 0; + + if (! cpath_layer || + ! cpath_layer->extend_info) + return 0; + + if (!ap_conn->ipv4_traffic_ok) + flags |= BEGIN_FLAG_IPV4_NOT_OK; + + exitnode = node_get_by_id(cpath_layer->extend_info->identity_digest); + + if (ap_conn->ipv6_traffic_ok && exitnode) { + tor_addr_t a; + tor_addr_make_null(&a, AF_INET6); + if (compare_tor_addr_to_node_policy(&a, ap_conn->socks_request->port, + exitnode) + != ADDR_POLICY_REJECTED) { + /* Only say "IPv6 OK" if the exit node supports IPv6. Otherwise there's + * no point. */ + flags |= BEGIN_FLAG_IPV6_OK; + } + } + + if (flags == BEGIN_FLAG_IPV6_OK) { + /* When IPv4 and IPv6 are both allowed, consider whether to say we + * prefer IPv6. Otherwise there's no point in declaring a preference */ + if (ap_conn->prefer_ipv6_traffic) + flags |= BEGIN_FLAG_IPV6_PREFERRED; + } + + if (flags == BEGIN_FLAG_IPV4_NOT_OK) { + log_warn(LD_EDGE, "I'm about to ask a node for a connection that I " + "am telling it to fulfil with neither IPv4 nor IPv6. That's " + "not going to work. Did you perhaps ask for an IPv6 address " + "on an IPv4Only port, or vice versa?"); + } + + return flags; +} + +/** Write a relay begin cell, using destaddr and destport from ap_conn's + * socks_request field, and send it down circ. + * + * If ap_conn is broken, mark it for close and return -1. Else return 0. + */ +int +connection_ap_handshake_send_begin(entry_connection_t *ap_conn) +{ + char payload[CELL_PAYLOAD_SIZE]; + int payload_len; + int begin_type; + origin_circuit_t *circ; + edge_connection_t *edge_conn = ENTRY_TO_EDGE_CONN(ap_conn); + connection_t *base_conn = TO_CONN(edge_conn); + tor_assert(edge_conn->on_circuit); + circ = TO_ORIGIN_CIRCUIT(edge_conn->on_circuit); + + tor_assert(base_conn->type == CONN_TYPE_AP); + tor_assert(base_conn->state == AP_CONN_STATE_CIRCUIT_WAIT); + tor_assert(ap_conn->socks_request); + tor_assert(SOCKS_COMMAND_IS_CONNECT(ap_conn->socks_request->command)); + + edge_conn->stream_id = get_unique_stream_id_by_circ(circ); + if (edge_conn->stream_id==0) { + /* XXXX024 Instead of closing this stream, we should make it get + * retried on another circuit. */ + connection_mark_unattached_ap(ap_conn, END_STREAM_REASON_INTERNAL); + + /* Mark this circuit "unusable for new streams". */ + mark_circuit_unusable_for_new_conns(circ); + return -1; + } + + /* Set up begin cell flags. */ + edge_conn->begincell_flags = connection_ap_get_begincell_flags(ap_conn); + + tor_snprintf(payload,RELAY_PAYLOAD_SIZE, "%s:%d", + (circ->base_.purpose == CIRCUIT_PURPOSE_C_GENERAL) ? + ap_conn->socks_request->address : "", + ap_conn->socks_request->port); + payload_len = (int)strlen(payload)+1; + if (payload_len <= RELAY_PAYLOAD_SIZE - 4 && edge_conn->begincell_flags) { + set_uint32(payload + payload_len, htonl(edge_conn->begincell_flags)); + payload_len += 4; + } + + log_info(LD_APP, + "Sending relay cell %d to begin stream %d.", + (int)ap_conn->use_begindir, + edge_conn->stream_id); + + begin_type = ap_conn->use_begindir ? + RELAY_COMMAND_BEGIN_DIR : RELAY_COMMAND_BEGIN; + if (begin_type == RELAY_COMMAND_BEGIN) { +#ifndef NON_ANONYMOUS_MODE_ENABLED + tor_assert(circ->build_state->onehop_tunnel == 0); +#endif + } + + if (connection_edge_send_command(edge_conn, begin_type, + begin_type == RELAY_COMMAND_BEGIN ? payload : NULL, + begin_type == RELAY_COMMAND_BEGIN ? payload_len : 0) < 0) + return -1; /* circuit is closed, don't continue */ + + edge_conn->package_window = STREAMWINDOW_START; + edge_conn->deliver_window = STREAMWINDOW_START; + base_conn->state = AP_CONN_STATE_CONNECT_WAIT; + log_info(LD_APP,"Address/port sent, ap socket "TOR_SOCKET_T_FORMAT + ", n_circ_id %u", + base_conn->s, (unsigned)circ->base_.n_circ_id); + control_event_stream_status(ap_conn, STREAM_EVENT_SENT_CONNECT, 0); + + /* If there's queued-up data, send it now */ + if ((connection_get_inbuf_len(base_conn) || + ap_conn->sending_optimistic_data) && + connection_ap_supports_optimistic_data(ap_conn)) { + log_info(LD_APP, "Sending up to %ld + %ld bytes of queued-up data", + (long)connection_get_inbuf_len(base_conn), + ap_conn->sending_optimistic_data ? + (long)generic_buffer_len(ap_conn->sending_optimistic_data) : 0); + if (connection_edge_package_raw_inbuf(edge_conn, 1, NULL) < 0) { + connection_mark_for_close(base_conn); + } + } + + return 0; +} + +/** Write a relay resolve cell, using destaddr and destport from ap_conn's + * socks_request field, and send it down circ. + * + * If ap_conn is broken, mark it for close and return -1. Else return 0. + */ +int +connection_ap_handshake_send_resolve(entry_connection_t *ap_conn) +{ + int payload_len, command; + const char *string_addr; + char inaddr_buf[REVERSE_LOOKUP_NAME_BUF_LEN]; + origin_circuit_t *circ; + edge_connection_t *edge_conn = ENTRY_TO_EDGE_CONN(ap_conn); + connection_t *base_conn = TO_CONN(edge_conn); + tor_assert(edge_conn->on_circuit); + circ = TO_ORIGIN_CIRCUIT(edge_conn->on_circuit); + + tor_assert(base_conn->type == CONN_TYPE_AP); + tor_assert(base_conn->state == AP_CONN_STATE_CIRCUIT_WAIT); + tor_assert(ap_conn->socks_request); + tor_assert(circ->base_.purpose == CIRCUIT_PURPOSE_C_GENERAL); + + command = ap_conn->socks_request->command; + tor_assert(SOCKS_COMMAND_IS_RESOLVE(command)); + + edge_conn->stream_id = get_unique_stream_id_by_circ(circ); + if (edge_conn->stream_id==0) { + /* XXXX024 Instead of closing this stream, we should make it get + * retried on another circuit. */ + connection_mark_unattached_ap(ap_conn, END_STREAM_REASON_INTERNAL); + + /* Mark this circuit "unusable for new streams". */ + mark_circuit_unusable_for_new_conns(circ); + return -1; + } + + if (command == SOCKS_COMMAND_RESOLVE) { + string_addr = ap_conn->socks_request->address; + payload_len = (int)strlen(string_addr)+1; + } else { + /* command == SOCKS_COMMAND_RESOLVE_PTR */ + const char *a = ap_conn->socks_request->address; + tor_addr_t addr; + int r; + + /* We're doing a reverse lookup. The input could be an IP address, or + * could be an .in-addr.arpa or .ip6.arpa address */ + r = tor_addr_parse_PTR_name(&addr, a, AF_UNSPEC, 1); + if (r <= 0) { + log_warn(LD_APP, "Rejecting ill-formed reverse lookup of %s", + safe_str_client(a)); + connection_mark_unattached_ap(ap_conn, END_STREAM_REASON_INTERNAL); + return -1; + } + + r = tor_addr_to_PTR_name(inaddr_buf, sizeof(inaddr_buf), &addr); + if (r < 0) { + log_warn(LD_BUG, "Couldn't generate reverse lookup hostname of %s", + safe_str_client(a)); + connection_mark_unattached_ap(ap_conn, END_STREAM_REASON_INTERNAL); + return -1; + } + + string_addr = inaddr_buf; + payload_len = (int)strlen(inaddr_buf)+1; + tor_assert(payload_len <= (int)sizeof(inaddr_buf)); + } + + log_debug(LD_APP, + "Sending relay cell to begin stream %d.", edge_conn->stream_id); + + if (connection_edge_send_command(edge_conn, + RELAY_COMMAND_RESOLVE, + string_addr, payload_len) < 0) + return -1; /* circuit is closed, don't continue */ + + if (!base_conn->address) { + /* This might be unnecessary. XXXX */ + base_conn->address = tor_dup_addr(&base_conn->addr); + } + base_conn->state = AP_CONN_STATE_RESOLVE_WAIT; + log_info(LD_APP,"Address sent for resolve, ap socket "TOR_SOCKET_T_FORMAT + ", n_circ_id %u", + base_conn->s, (unsigned)circ->base_.n_circ_id); + control_event_stream_status(ap_conn, STREAM_EVENT_SENT_RESOLVE, 0); + return 0; +} + +/** Make an AP connection_t linked to the connection_t partner. make a + * new linked connection pair, and attach one side to the conn, connection_add + * it, initialize it to circuit_wait, and call + * connection_ap_handshake_attach_circuit(conn) on it. + * + * Return the newly created end of the linked connection pair, or -1 if error. + */ +entry_connection_t * +connection_ap_make_link(connection_t *partner, + char *address, uint16_t port, + const char *digest, + int session_group, int isolation_flags, + int use_begindir, int want_onehop) +{ + entry_connection_t *conn; + connection_t *base_conn; + + log_info(LD_APP,"Making internal %s tunnel to %s:%d ...", + want_onehop ? "direct" : "anonymized", + safe_str_client(address), port); + + conn = entry_connection_new(CONN_TYPE_AP, tor_addr_family(&partner->addr)); + base_conn = ENTRY_TO_CONN(conn); + base_conn->linked = 1; /* so that we can add it safely below. */ + + /* populate conn->socks_request */ + + /* leave version at zero, so the socks_reply is empty */ + conn->socks_request->socks_version = 0; + conn->socks_request->has_finished = 0; /* waiting for 'connected' */ + strlcpy(conn->socks_request->address, address, + sizeof(conn->socks_request->address)); + conn->socks_request->port = port; + conn->socks_request->command = SOCKS_COMMAND_CONNECT; + conn->want_onehop = want_onehop; + conn->use_begindir = use_begindir; + if (use_begindir) { + conn->chosen_exit_name = tor_malloc(HEX_DIGEST_LEN+2); + conn->chosen_exit_name[0] = '$'; + tor_assert(digest); + base16_encode(conn->chosen_exit_name+1,HEX_DIGEST_LEN+1, + digest, DIGEST_LEN); + } + + /* Populate isolation fields. */ + conn->socks_request->listener_type = CONN_TYPE_DIR_LISTENER; + conn->original_dest_address = tor_strdup(address); + conn->session_group = session_group; + conn->isolation_flags = isolation_flags; + + base_conn->address = tor_strdup("(Tor_internal)"); + tor_addr_make_unspec(&base_conn->addr); + base_conn->port = 0; + + connection_link_connections(partner, base_conn); + + if (connection_add(base_conn) < 0) { /* no space, forget it */ + connection_free(base_conn); + return NULL; + } + + base_conn->state = AP_CONN_STATE_CIRCUIT_WAIT; + + control_event_stream_status(conn, STREAM_EVENT_NEW, 0); + + /* attaching to a dirty circuit is fine */ + if (connection_ap_handshake_attach_circuit(conn) < 0) { + if (!base_conn->marked_for_close) + connection_mark_unattached_ap(conn, END_STREAM_REASON_CANT_ATTACH); + return NULL; + } + + log_info(LD_APP,"... application connection created and linked."); + return conn; +} + +/** Notify any interested controller connections about a new hostname resolve + * or resolve error. Takes the same arguments as does + * connection_ap_handshake_socks_resolved(). */ +static void +tell_controller_about_resolved_result(entry_connection_t *conn, + int answer_type, + size_t answer_len, + const char *answer, + int ttl, + time_t expires) +{ + expires = time(NULL) + ttl; + if (answer_type == RESOLVED_TYPE_IPV4 && answer_len >= 4) { + char *cp = tor_dup_ip(ntohl(get_uint32(answer))); + control_event_address_mapped(conn->socks_request->address, + cp, expires, NULL, 0); + tor_free(cp); + } else if (answer_type == RESOLVED_TYPE_HOSTNAME && answer_len < 256) { + char *cp = tor_strndup(answer, answer_len); + control_event_address_mapped(conn->socks_request->address, + cp, expires, NULL, 0); + tor_free(cp); + } else { + control_event_address_mapped(conn->socks_request->address, + "", time(NULL)+ttl, + "error=yes", 0); + } +} + +/** + * As connection_ap_handshake_socks_resolved, but take a tor_addr_t to send + * as the answer. + */ +static void +connection_ap_handshake_socks_resolved_addr(entry_connection_t *conn, + const tor_addr_t *answer, + int ttl, + time_t expires) +{ + if (tor_addr_family(answer) == AF_INET) { + uint32_t a = tor_addr_to_ipv4n(answer); /* network order */ + connection_ap_handshake_socks_resolved(conn,RESOLVED_TYPE_IPV4,4, + (uint8_t*)&a, + ttl, expires); + } else if (tor_addr_family(answer) == AF_INET6) { + const uint8_t *a = tor_addr_to_in6_addr8(answer); + connection_ap_handshake_socks_resolved(conn,RESOLVED_TYPE_IPV6,16, + a, + ttl, expires); + } else { + log_warn(LD_BUG, "Got called with address of unexpected family %d", + tor_addr_family(answer)); + connection_ap_handshake_socks_resolved(conn, + RESOLVED_TYPE_ERROR,0,NULL,-1,-1); + } +} + +/** Send an answer to an AP connection that has requested a DNS lookup via + * SOCKS. The type should be one of RESOLVED_TYPE_(IPV4|IPV6|HOSTNAME) or -1 + * for unreachable; the answer should be in the format specified in the socks + * extensions document. ttl is the ttl for the answer, or -1 on + * certain errors or for values that didn't come via DNS. expires is + * a time when the answer expires, or -1 or TIME_MAX if there's a good TTL. + **/ +/* XXXX the use of the ttl and expires fields is nutty. Let's make this + * interface and those that use it less ugly. */ +void +connection_ap_handshake_socks_resolved(entry_connection_t *conn, + int answer_type, + size_t answer_len, + const uint8_t *answer, + int ttl, + time_t expires) +{ + char buf[384]; + size_t replylen; + + if (ttl >= 0) { + if (answer_type == RESOLVED_TYPE_IPV4 && answer_len == 4) { + tor_addr_t a; + tor_addr_from_ipv4n(&a, get_uint32(answer)); + if (! tor_addr_is_null(&a)) { + client_dns_set_addressmap(conn, + conn->socks_request->address, &a, + conn->chosen_exit_name, ttl); + } + } else if (answer_type == RESOLVED_TYPE_IPV6 && answer_len == 16) { + tor_addr_t a; + tor_addr_from_ipv6_bytes(&a, (char*)answer); + if (! tor_addr_is_null(&a)) { + client_dns_set_addressmap(conn, + conn->socks_request->address, &a, + conn->chosen_exit_name, ttl); + } + } else if (answer_type == RESOLVED_TYPE_HOSTNAME && answer_len < 256) { + char *cp = tor_strndup((char*)answer, answer_len); + client_dns_set_reverse_addressmap(conn, + conn->socks_request->address, + cp, + conn->chosen_exit_name, ttl); + tor_free(cp); + } + } + + if (ENTRY_TO_EDGE_CONN(conn)->is_dns_request) { + if (conn->dns_server_request) { + /* We had a request on our DNS port: answer it. */ + dnsserv_resolved(conn, answer_type, answer_len, (char*)answer, ttl); + conn->socks_request->has_finished = 1; + return; + } else { + /* This must be a request from the controller. Since answers to those + * requests are not cached, they do not generate an ADDRMAP event on + * their own. */ + tell_controller_about_resolved_result(conn, answer_type, answer_len, + (char*)answer, ttl, expires); + conn->socks_request->has_finished = 1; + return; + } + /* We shouldn't need to free conn here; it gets marked by the caller. */ + } + + if (conn->socks_request->socks_version == 4) { + buf[0] = 0x00; /* version */ + if (answer_type == RESOLVED_TYPE_IPV4 && answer_len == 4) { + buf[1] = SOCKS4_GRANTED; + set_uint16(buf+2, 0); + memcpy(buf+4, answer, 4); /* address */ + replylen = SOCKS4_NETWORK_LEN; + } else { /* "error" */ + buf[1] = SOCKS4_REJECT; + memset(buf+2, 0, 6); + replylen = SOCKS4_NETWORK_LEN; + } + } else if (conn->socks_request->socks_version == 5) { + /* SOCKS5 */ + buf[0] = 0x05; /* version */ + if (answer_type == RESOLVED_TYPE_IPV4 && answer_len == 4) { + buf[1] = SOCKS5_SUCCEEDED; + buf[2] = 0; /* reserved */ + buf[3] = 0x01; /* IPv4 address type */ + memcpy(buf+4, answer, 4); /* address */ + set_uint16(buf+8, 0); /* port == 0. */ + replylen = 10; + } else if (answer_type == RESOLVED_TYPE_IPV6 && answer_len == 16) { + buf[1] = SOCKS5_SUCCEEDED; + buf[2] = 0; /* reserved */ + buf[3] = 0x04; /* IPv6 address type */ + memcpy(buf+4, answer, 16); /* address */ + set_uint16(buf+20, 0); /* port == 0. */ + replylen = 22; + } else if (answer_type == RESOLVED_TYPE_HOSTNAME && answer_len < 256) { + buf[1] = SOCKS5_SUCCEEDED; + buf[2] = 0; /* reserved */ + buf[3] = 0x03; /* Domainname address type */ + buf[4] = (char)answer_len; + memcpy(buf+5, answer, answer_len); /* address */ + set_uint16(buf+5+answer_len, 0); /* port == 0. */ + replylen = 5+answer_len+2; + } else { + buf[1] = SOCKS5_HOST_UNREACHABLE; + memset(buf+2, 0, 8); + replylen = 10; + } + } else { + /* no socks version info; don't send anything back */ + return; + } + connection_ap_handshake_socks_reply(conn, buf, replylen, + (answer_type == RESOLVED_TYPE_IPV4 || + answer_type == RESOLVED_TYPE_IPV6 || + answer_type == RESOLVED_TYPE_HOSTNAME) ? + 0 : END_STREAM_REASON_RESOLVEFAILED); +} + +/** Send a socks reply to stream conn, using the appropriate + * socks version, etc, and mark conn as completed with SOCKS + * handshaking. + * + * If reply is defined, then write replylen bytes of it to conn + * and return, else reply based on endreason (one of + * END_STREAM_REASON_*). If reply is undefined, endreason can't + * be 0 or REASON_DONE. Send endreason to the controller, if appropriate. + */ +void +connection_ap_handshake_socks_reply(entry_connection_t *conn, char *reply, + size_t replylen, int endreason) +{ + char buf[256]; + socks5_reply_status_t status = + stream_end_reason_to_socks5_response(endreason); + + tor_assert(conn->socks_request); /* make sure it's an AP stream */ + + if (!SOCKS_COMMAND_IS_RESOLVE(conn->socks_request->command)) { + control_event_stream_status(conn, status==SOCKS5_SUCCEEDED ? + STREAM_EVENT_SUCCEEDED : STREAM_EVENT_FAILED, + endreason); + } + + /* Flag this stream's circuit as having completed a stream successfully + * (for path bias) */ + if (status == SOCKS5_SUCCEEDED || + endreason == END_STREAM_REASON_RESOLVEFAILED || + endreason == END_STREAM_REASON_CONNECTREFUSED || + endreason == END_STREAM_REASON_CONNRESET || + endreason == END_STREAM_REASON_NOROUTE || + endreason == END_STREAM_REASON_RESOURCELIMIT) { + if (!conn->edge_.on_circuit || + !CIRCUIT_IS_ORIGIN(conn->edge_.on_circuit)) { + // DNS remaps can trigger this. So can failed hidden service + // lookups. + log_info(LD_BUG, + "No origin circuit for successful SOCKS stream "U64_FORMAT + ". Reason: %d", + U64_PRINTF_ARG(ENTRY_TO_CONN(conn)->global_identifier), + endreason); + } else { + // XXX: Hrmm. It looks like optimistic data can't go through this + // codepath, but someone should probably test it and make sure. + // We don't want to mark optimistically opened streams as successful. + pathbias_mark_use_success(TO_ORIGIN_CIRCUIT(conn->edge_.on_circuit)); + } + } + + if (conn->socks_request->has_finished) { + log_warn(LD_BUG, "(Harmless.) duplicate calls to " + "connection_ap_handshake_socks_reply."); + return; + } + if (replylen) { /* we already have a reply in mind */ + connection_write_to_buf(reply, replylen, ENTRY_TO_CONN(conn)); + conn->socks_request->has_finished = 1; + return; + } + if (conn->socks_request->socks_version == 4) { + memset(buf,0,SOCKS4_NETWORK_LEN); + buf[1] = (status==SOCKS5_SUCCEEDED ? SOCKS4_GRANTED : SOCKS4_REJECT); + /* leave version, destport, destip zero */ + connection_write_to_buf(buf, SOCKS4_NETWORK_LEN, ENTRY_TO_CONN(conn)); + } else if (conn->socks_request->socks_version == 5) { + buf[0] = 5; /* version 5 */ + buf[1] = (char)status; + buf[2] = 0; + buf[3] = 1; /* ipv4 addr */ + memset(buf+4,0,6); /* Set external addr/port to 0. + The spec doesn't seem to say what to do here. -RD */ + connection_write_to_buf(buf,10,ENTRY_TO_CONN(conn)); + } + /* If socks_version isn't 4 or 5, don't send anything. + * This can happen in the case of AP bridges. */ + conn->socks_request->has_finished = 1; + return; +} + +/** Read a RELAY_BEGIN or RELAY_BEGINDIR cell from cell, decode it, and + * place the result in bcell. On success return 0; on failure return + * <0 and set *end_reason_out to the end reason we should send back to + * the client. + * + * Return -1 in the case where want to send a RELAY_END cell, and < -1 when + * we don't. + **/ +STATIC int +begin_cell_parse(const cell_t *cell, begin_cell_t *bcell, + uint8_t *end_reason_out) +{ + relay_header_t rh; + const uint8_t *body, *nul; + + memset(bcell, 0, sizeof(*bcell)); + *end_reason_out = END_STREAM_REASON_MISC; + + relay_header_unpack(&rh, cell->payload); + if (rh.length > RELAY_PAYLOAD_SIZE) { + return -2; /*XXXX why not TORPROTOCOL? */ + } + + bcell->stream_id = rh.stream_id; + + if (rh.command == RELAY_COMMAND_BEGIN_DIR) { + bcell->is_begindir = 1; + return 0; + } else if (rh.command != RELAY_COMMAND_BEGIN) { + log_warn(LD_BUG, "Got an unexpected command %d", (int)rh.command); + *end_reason_out = END_STREAM_REASON_INTERNAL; + return -1; + } + + body = cell->payload + RELAY_HEADER_SIZE; + nul = memchr(body, 0, rh.length); + if (! nul) { + log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, + "Relay begin cell has no \\0. Closing."); + *end_reason_out = END_STREAM_REASON_TORPROTOCOL; + return -1; + } + + if (tor_addr_port_split(LOG_PROTOCOL_WARN, + (char*)(body), + &bcell->address,&bcell->port)<0) { + log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, + "Unable to parse addr:port in relay begin cell. Closing."); + *end_reason_out = END_STREAM_REASON_TORPROTOCOL; + return -1; + } + if (bcell->port == 0) { + log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, + "Missing port in relay begin cell. Closing."); + tor_free(bcell->address); + *end_reason_out = END_STREAM_REASON_TORPROTOCOL; + return -1; + } + if (body + rh.length >= nul + 4) + bcell->flags = ntohl(get_uint32(nul+1)); + + return 0; +} + +/** A relay 'begin' or 'begin_dir' cell has arrived, and either we are + * an exit hop for the circuit, or we are the origin and it is a + * rendezvous begin. + * + * Launch a new exit connection and initialize things appropriately. + * + * If it's a rendezvous stream, call connection_exit_connect() on + * it. + * + * For general streams, call dns_resolve() on it first, and only call + * connection_exit_connect() if the dns answer is already known. + * + * Note that we don't call connection_add() on the new stream! We wait + * for connection_exit_connect() to do that. + * + * Return -(some circuit end reason) if we want to tear down circ. + * Else return 0. + */ +int +connection_exit_begin_conn(cell_t *cell, circuit_t *circ) +{ + edge_connection_t *n_stream; + relay_header_t rh; + char *address = NULL; + uint16_t port = 0; + or_circuit_t *or_circ = NULL; + const or_options_t *options = get_options(); + begin_cell_t bcell; + int r; + uint8_t end_reason=0; + + assert_circuit_ok(circ); + if (!CIRCUIT_IS_ORIGIN(circ)) + or_circ = TO_OR_CIRCUIT(circ); + + relay_header_unpack(&rh, cell->payload); + if (rh.length > RELAY_PAYLOAD_SIZE) + return -1; + + /* Note: we have to use relay_send_command_from_edge here, not + * connection_edge_end or connection_edge_send_command, since those require + * that we have a stream connected to a circuit, and we don't connect to a + * circuit until we have a pending/successful resolve. */ + + if (!server_mode(options) && + circ->purpose != CIRCUIT_PURPOSE_S_REND_JOINED) { + log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, + "Relay begin cell at non-server. Closing."); + relay_send_end_cell_from_edge(rh.stream_id, circ, + END_STREAM_REASON_EXITPOLICY, NULL); + return 0; + } + + r = begin_cell_parse(cell, &bcell, &end_reason); + if (r < -1) { + return -1; + } else if (r == -1) { + tor_free(bcell.address); + relay_send_end_cell_from_edge(rh.stream_id, circ, end_reason, NULL); + return 0; + } + + if (! bcell.is_begindir) { + /* Steal reference */ + address = bcell.address; + port = bcell.port; + + if (or_circ && or_circ->p_chan) { + if (!options->AllowSingleHopExits && + (or_circ->is_first_hop || + (!connection_or_digest_is_known_relay( + or_circ->p_chan->identity_digest) && + should_refuse_unknown_exits(options)))) { + /* Don't let clients use us as a single-hop proxy, unless the user + * has explicitly allowed that in the config. It attracts attackers + * and users who'd be better off with, well, single-hop proxies. + */ + log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, + "Attempt by %s to open a stream %s. Closing.", + safe_str(channel_get_canonical_remote_descr(or_circ->p_chan)), + or_circ->is_first_hop ? "on first hop of circuit" : + "from unknown relay"); + relay_send_end_cell_from_edge(rh.stream_id, circ, + or_circ->is_first_hop ? + END_STREAM_REASON_TORPROTOCOL : + END_STREAM_REASON_MISC, + NULL); + tor_free(address); + return 0; + } + } + } else if (rh.command == RELAY_COMMAND_BEGIN_DIR) { + if (!directory_permits_begindir_requests(options) || + circ->purpose != CIRCUIT_PURPOSE_OR) { + relay_send_end_cell_from_edge(rh.stream_id, circ, + END_STREAM_REASON_NOTDIRECTORY, NULL); + return 0; + } + /* Make sure to get the 'real' address of the previous hop: the + * caller might want to know whether his IP address has changed, and + * we might already have corrected base_.addr[ess] for the relay's + * canonical IP address. */ + if (or_circ && or_circ->p_chan) + address = tor_strdup(channel_get_actual_remote_address(or_circ->p_chan)); + else + address = tor_strdup("127.0.0.1"); + port = 1; /* XXXX This value is never actually used anywhere, and there + * isn't "really" a connection here. But we + * need to set it to something nonzero. */ + } else { + log_warn(LD_BUG, "Got an unexpected command %d", (int)rh.command); + relay_send_end_cell_from_edge(rh.stream_id, circ, + END_STREAM_REASON_INTERNAL, NULL); + return 0; + } + + if (! options->IPv6Exit) { + /* I don't care if you prefer IPv6; I can't give you any. */ + bcell.flags &= ~BEGIN_FLAG_IPV6_PREFERRED; + /* If you don't want IPv4, I can't help. */ + if (bcell.flags & BEGIN_FLAG_IPV4_NOT_OK) { + tor_free(address); + relay_send_end_cell_from_edge(rh.stream_id, circ, + END_STREAM_REASON_EXITPOLICY, NULL); + return 0; + } + } + + log_debug(LD_EXIT,"Creating new exit connection."); + /* The 'AF_INET' here is temporary; we might need to change it later in + * connection_exit_connect(). */ + n_stream = edge_connection_new(CONN_TYPE_EXIT, AF_INET); + + /* Remember the tunneled request ID in the new edge connection, so that + * we can measure download times. */ + n_stream->dirreq_id = circ->dirreq_id; + + n_stream->base_.purpose = EXIT_PURPOSE_CONNECT; + n_stream->begincell_flags = bcell.flags; + n_stream->stream_id = rh.stream_id; + n_stream->base_.port = port; + /* leave n_stream->s at -1, because it's not yet valid */ + n_stream->package_window = STREAMWINDOW_START; + n_stream->deliver_window = STREAMWINDOW_START; + + if (circ->purpose == CIRCUIT_PURPOSE_S_REND_JOINED) { + origin_circuit_t *origin_circ = TO_ORIGIN_CIRCUIT(circ); + log_info(LD_REND,"begin is for rendezvous. configuring stream."); + n_stream->base_.address = tor_strdup("(rendezvous)"); + n_stream->base_.state = EXIT_CONN_STATE_CONNECTING; + n_stream->rend_data = rend_data_dup(origin_circ->rend_data); + tor_assert(connection_edge_is_rendezvous_stream(n_stream)); + assert_circuit_ok(circ); + if (rend_service_set_connection_addr_port(n_stream, origin_circ) < 0) { + log_info(LD_REND,"Didn't find rendezvous service (port %d)", + n_stream->base_.port); + relay_send_end_cell_from_edge(rh.stream_id, circ, + END_STREAM_REASON_EXITPOLICY, + origin_circ->cpath->prev); + connection_free(TO_CONN(n_stream)); + tor_free(address); + return 0; + } + assert_circuit_ok(circ); + log_debug(LD_REND,"Finished assigning addr/port"); + n_stream->cpath_layer = origin_circ->cpath->prev; /* link it */ + + /* add it into the linked list of p_streams on this circuit */ + n_stream->next_stream = origin_circ->p_streams; + n_stream->on_circuit = circ; + origin_circ->p_streams = n_stream; + assert_circuit_ok(circ); + + connection_exit_connect(n_stream); + + /* For path bias: This circuit was used successfully */ + pathbias_mark_use_success(origin_circ); + + tor_free(address); + return 0; + } + tor_strlower(address); + n_stream->base_.address = address; + n_stream->base_.state = EXIT_CONN_STATE_RESOLVEFAILED; + /* default to failed, change in dns_resolve if it turns out not to fail */ + + if (we_are_hibernating()) { + relay_send_end_cell_from_edge(rh.stream_id, circ, + END_STREAM_REASON_HIBERNATING, NULL); + connection_free(TO_CONN(n_stream)); + return 0; + } + + n_stream->on_circuit = circ; + + if (rh.command == RELAY_COMMAND_BEGIN_DIR) { + tor_addr_t tmp_addr; + tor_assert(or_circ); + if (or_circ->p_chan && + channel_get_addr_if_possible(or_circ->p_chan, &tmp_addr)) { + tor_addr_copy(&n_stream->base_.addr, &tmp_addr); + } + return connection_exit_connect_dir(n_stream); + } + + log_debug(LD_EXIT,"about to start the dns_resolve()."); + + /* send it off to the gethostbyname farm */ + switch (dns_resolve(n_stream)) { + case 1: /* resolve worked; now n_stream is attached to circ. */ + assert_circuit_ok(circ); + log_debug(LD_EXIT,"about to call connection_exit_connect()."); + connection_exit_connect(n_stream); + return 0; + case -1: /* resolve failed */ + relay_send_end_cell_from_edge(rh.stream_id, circ, + END_STREAM_REASON_RESOLVEFAILED, NULL); + /* n_stream got freed. don't touch it. */ + break; + case 0: /* resolve added to pending list */ + assert_circuit_ok(circ); + break; + } + return 0; +} + +/** + * Called when we receive a RELAY_COMMAND_RESOLVE cell 'cell' along the + * circuit circ; + * begin resolving the hostname, and (eventually) reply with a RESOLVED cell. + */ +int +connection_exit_begin_resolve(cell_t *cell, or_circuit_t *circ) +{ + edge_connection_t *dummy_conn; + relay_header_t rh; + + assert_circuit_ok(TO_CIRCUIT(circ)); + relay_header_unpack(&rh, cell->payload); + if (rh.length > RELAY_PAYLOAD_SIZE) + return -1; + + /* This 'dummy_conn' only exists to remember the stream ID + * associated with the resolve request; and to make the + * implementation of dns.c more uniform. (We really only need to + * remember the circuit, the stream ID, and the hostname to be + * resolved; but if we didn't store them in a connection like this, + * the housekeeping in dns.c would get way more complicated.) + */ + dummy_conn = edge_connection_new(CONN_TYPE_EXIT, AF_INET); + dummy_conn->stream_id = rh.stream_id; + dummy_conn->base_.address = tor_strndup( + (char*)cell->payload+RELAY_HEADER_SIZE, + rh.length); + dummy_conn->base_.port = 0; + dummy_conn->base_.state = EXIT_CONN_STATE_RESOLVEFAILED; + dummy_conn->base_.purpose = EXIT_PURPOSE_RESOLVE; + + dummy_conn->on_circuit = TO_CIRCUIT(circ); + + /* send it off to the gethostbyname farm */ + switch (dns_resolve(dummy_conn)) { + case -1: /* Impossible to resolve; a resolved cell was sent. */ + /* Connection freed; don't touch it. */ + return 0; + case 1: /* The result was cached; a resolved cell was sent. */ + if (!dummy_conn->base_.marked_for_close) + connection_free(TO_CONN(dummy_conn)); + return 0; + case 0: /* resolve added to pending list */ + assert_circuit_ok(TO_CIRCUIT(circ)); + break; + } + return 0; +} + +/** Connect to conn's specified addr and port. If it worked, conn + * has now been added to the connection_array. + * + * Send back a connected cell. Include the resolved IP of the destination + * address, but only if it's a general exit stream. (Rendezvous + * streams must not reveal what IP they connected to.) + */ +void +connection_exit_connect(edge_connection_t *edge_conn) +{ + const tor_addr_t *addr; + uint16_t port; + connection_t *conn = TO_CONN(edge_conn); + int socket_error = 0; + + if ( (!connection_edge_is_rendezvous_stream(edge_conn) && + router_compare_to_my_exit_policy(&edge_conn->base_.addr, + edge_conn->base_.port)) || + (tor_addr_family(&conn->addr) == AF_INET6 && + ! get_options()->IPv6Exit)) { + log_info(LD_EXIT,"%s:%d failed exit policy. Closing.", + escaped_safe_str_client(conn->address), conn->port); + connection_edge_end(edge_conn, END_STREAM_REASON_EXITPOLICY); + circuit_detach_stream(circuit_get_by_edge_conn(edge_conn), edge_conn); + connection_free(conn); + return; + } + + addr = &conn->addr; + port = conn->port; + + if (tor_addr_family(addr) == AF_INET6) + conn->socket_family = AF_INET6; + + log_debug(LD_EXIT,"about to try connecting"); + switch (connection_connect(conn, conn->address, addr, port, &socket_error)) { + case -1: { + int reason = errno_to_stream_end_reason(socket_error); + connection_edge_end(edge_conn, reason); + circuit_detach_stream(circuit_get_by_edge_conn(edge_conn), edge_conn); + connection_free(conn); + return; + } + case 0: + conn->state = EXIT_CONN_STATE_CONNECTING; + + connection_watch_events(conn, READ_EVENT | WRITE_EVENT); + /* writable indicates finish; + * readable/error indicates broken link in windows-land. */ + return; + /* case 1: fall through */ + } + + conn->state = EXIT_CONN_STATE_OPEN; + if (connection_get_outbuf_len(conn)) { + /* in case there are any queued data cells, from e.g. optimistic data */ + IF_HAS_NO_BUFFEREVENT(conn) + connection_watch_events(conn, READ_EVENT|WRITE_EVENT); + } else { + IF_HAS_NO_BUFFEREVENT(conn) + connection_watch_events(conn, READ_EVENT); + } + + /* also, deliver a 'connected' cell back through the circuit. */ + if (connection_edge_is_rendezvous_stream(edge_conn)) { + /* rendezvous stream */ + /* don't send an address back! */ + connection_edge_send_command(edge_conn, + RELAY_COMMAND_CONNECTED, + NULL, 0); + } else { /* normal stream */ + uint8_t connected_payload[MAX_CONNECTED_CELL_PAYLOAD_LEN]; + int connected_payload_len = + connected_cell_format_payload(connected_payload, &conn->addr, + edge_conn->address_ttl); + if (connected_payload_len < 0) { + connection_edge_end(edge_conn, END_STREAM_REASON_INTERNAL); + circuit_detach_stream(circuit_get_by_edge_conn(edge_conn), edge_conn); + connection_free(conn); + return; + } + + connection_edge_send_command(edge_conn, + RELAY_COMMAND_CONNECTED, + (char*)connected_payload, + connected_payload_len); + } +} + +/** Given an exit conn that should attach to us as a directory server, open a + * bridge connection with a linked connection pair, create a new directory + * conn, and join them together. Return 0 on success (or if there was an + * error we could send back an end cell for). Return -(some circuit end + * reason) if the circuit needs to be torn down. Either connects + * exitconn, frees it, or marks it, as appropriate. + */ +static int +connection_exit_connect_dir(edge_connection_t *exitconn) +{ + dir_connection_t *dirconn = NULL; + or_circuit_t *circ = TO_OR_CIRCUIT(exitconn->on_circuit); + + log_info(LD_EXIT, "Opening local connection for anonymized directory exit"); + + exitconn->base_.state = EXIT_CONN_STATE_OPEN; + + dirconn = dir_connection_new(tor_addr_family(&exitconn->base_.addr)); + + tor_addr_copy(&dirconn->base_.addr, &exitconn->base_.addr); + dirconn->base_.port = 0; + dirconn->base_.address = tor_strdup(exitconn->base_.address); + dirconn->base_.type = CONN_TYPE_DIR; + dirconn->base_.purpose = DIR_PURPOSE_SERVER; + dirconn->base_.state = DIR_CONN_STATE_SERVER_COMMAND_WAIT; + + /* Note that the new dir conn belongs to the same tunneled request as + * the edge conn, so that we can measure download times. */ + dirconn->dirreq_id = exitconn->dirreq_id; + + connection_link_connections(TO_CONN(dirconn), TO_CONN(exitconn)); + + if (connection_add(TO_CONN(exitconn))<0) { + connection_edge_end(exitconn, END_STREAM_REASON_RESOURCELIMIT); + connection_free(TO_CONN(exitconn)); + connection_free(TO_CONN(dirconn)); + return 0; + } + + /* link exitconn to circ, now that we know we can use it. */ + exitconn->next_stream = circ->n_streams; + circ->n_streams = exitconn; + + if (connection_add(TO_CONN(dirconn))<0) { + connection_edge_end(exitconn, END_STREAM_REASON_RESOURCELIMIT); + connection_close_immediate(TO_CONN(exitconn)); + connection_mark_for_close(TO_CONN(exitconn)); + connection_free(TO_CONN(dirconn)); + return 0; + } + + connection_start_reading(TO_CONN(dirconn)); + connection_start_reading(TO_CONN(exitconn)); + + if (connection_edge_send_command(exitconn, + RELAY_COMMAND_CONNECTED, NULL, 0) < 0) { + connection_mark_for_close(TO_CONN(exitconn)); + connection_mark_for_close(TO_CONN(dirconn)); + return 0; + } + + return 0; +} + +/** Return 1 if conn is a rendezvous stream, or 0 if + * it is a general stream. + */ +int +connection_edge_is_rendezvous_stream(edge_connection_t *conn) +{ + tor_assert(conn); + if (conn->rend_data) + return 1; + return 0; +} + +/** Return 1 if router exit is likely to allow stream conn + * to exit from it, or 0 if it probably will not allow it. + * (We might be uncertain if conn's destination address has not yet been + * resolved.) + */ +int +connection_ap_can_use_exit(const entry_connection_t *conn, const node_t *exit) +{ + const or_options_t *options = get_options(); + + tor_assert(conn); + tor_assert(conn->socks_request); + tor_assert(exit); + + /* If a particular exit node has been requested for the new connection, + * make sure the exit node of the existing circuit matches exactly. + */ + if (conn->chosen_exit_name) { + const node_t *chosen_exit = + node_get_by_nickname(conn->chosen_exit_name, 1); + if (!chosen_exit || tor_memneq(chosen_exit->identity, + exit->identity, DIGEST_LEN)) { + /* doesn't match */ +// log_debug(LD_APP,"Requested node '%s', considering node '%s'. No.", +// conn->chosen_exit_name, exit->nickname); + return 0; + } + } + + if (conn->use_begindir) { + /* Internal directory fetches do not count as exiting. */ + return 1; + } + + if (conn->socks_request->command == SOCKS_COMMAND_CONNECT) { + tor_addr_t addr, *addrp = NULL; + addr_policy_result_t r; + if (0 == tor_addr_parse(&addr, conn->socks_request->address)) { + addrp = &addr; + } else if (!conn->ipv4_traffic_ok && conn->ipv6_traffic_ok) { + tor_addr_make_null(&addr, AF_INET6); + addrp = &addr; + } else if (conn->ipv4_traffic_ok && !conn->ipv6_traffic_ok) { + tor_addr_make_null(&addr, AF_INET); + addrp = &addr; + } + r = compare_tor_addr_to_node_policy(addrp, conn->socks_request->port,exit); + if (r == ADDR_POLICY_REJECTED) + return 0; /* We know the address, and the exit policy rejects it. */ + if (r == ADDR_POLICY_PROBABLY_REJECTED && !conn->chosen_exit_name) + return 0; /* We don't know the addr, but the exit policy rejects most + * addresses with this port. Since the user didn't ask for + * this node, err on the side of caution. */ + } else if (SOCKS_COMMAND_IS_RESOLVE(conn->socks_request->command)) { + /* Don't send DNS requests to non-exit servers by default. */ + if (!conn->chosen_exit_name && node_exit_policy_rejects_all(exit)) + return 0; + } + if (routerset_contains_node(options->ExcludeExitNodesUnion_, exit)) { + /* Not a suitable exit. Refuse it. */ + return 0; + } + + return 1; +} + +/** If address is of the form "y.onion" with a well-formed handle y: + * Put a NUL after y, lower-case it, and return ONION_HOSTNAME. + * + * If address is of the form "x.y.onion" with a well-formed handle x: + * Drop "x.", put a NUL after y, lower-case it, and return ONION_HOSTNAME. + * + * If address is of the form "y.onion" with a badly-formed handle y: + * Return BAD_HOSTNAME and log a message. + * + * If address is of the form "y.exit": + * Put a NUL after y and return EXIT_HOSTNAME. + * + * Otherwise: + * Return NORMAL_HOSTNAME and change nothing. + */ +hostname_type_t +parse_extended_hostname(char *address) +{ + char *s; + char *q; + char query[REND_SERVICE_ID_LEN_BASE32+1]; + + s = strrchr(address,'.'); + if (!s) + return NORMAL_HOSTNAME; /* no dot, thus normal */ + if (!strcmp(s+1,"exit")) { + *s = 0; /* NUL-terminate it */ + return EXIT_HOSTNAME; /* .exit */ + } + if (strcmp(s+1,"onion")) + return NORMAL_HOSTNAME; /* neither .exit nor .onion, thus normal */ + + /* so it is .onion */ + *s = 0; /* NUL-terminate it */ + /* locate a 'sub-domain' component, in order to remove it */ + q = strrchr(address, '.'); + if (q == address) { + goto failed; /* reject sub-domain, as DNS does */ + } + q = (NULL == q) ? address : q + 1; + if (strlcpy(query, q, REND_SERVICE_ID_LEN_BASE32+1) >= + REND_SERVICE_ID_LEN_BASE32+1) + goto failed; + if (q != address) { + memmove(address, q, strlen(q) + 1 /* also get \0 */); + } + if (rend_valid_service_id(query)) { + return ONION_HOSTNAME; /* success */ + } + failed: + /* otherwise, return to previous state and return 0 */ + *s = '.'; + log_warn(LD_APP, "Invalid onion hostname %s; rejecting", + safe_str_client(address)); + return BAD_HOSTNAME; +} + +/** Return true iff the (possibly NULL) alen-byte chunk of memory at + * a is equal to the (possibly NULL) blen-byte chunk of memory + * at b. */ +static int +memeq_opt(const char *a, size_t alen, const char *b, size_t blen) +{ + if (a == NULL) { + return (b == NULL); + } else if (b == NULL) { + return 0; + } else if (alen != blen) { + return 0; + } else { + return tor_memeq(a, b, alen); + } +} + +/** + * Return true iff none of the isolation flags and fields in conn + * should prevent it from being attached to circ. + */ +int +connection_edge_compatible_with_circuit(const entry_connection_t *conn, + const origin_circuit_t *circ) +{ + const uint8_t iso = conn->isolation_flags; + const socks_request_t *sr = conn->socks_request; + + /* If circ has never been used for an isolated connection, we can + * totally use it for this one. */ + if (!circ->isolation_values_set) + return 1; + + /* If circ has been used for connections having more than one value + * for some field f, it will have the corresponding bit set in + * isolation_flags_mixed. If isolation_flags_mixed has any bits + * in common with iso, then conn must be isolated from at least + * one stream that has been attached to circ. */ + if ((iso & circ->isolation_flags_mixed) != 0) { + /* For at least one field where conn is isolated, the circuit + * already has mixed streams. */ + return 0; + } + + if (! conn->original_dest_address) { + log_warn(LD_BUG, "Reached connection_edge_compatible_with_circuit without " + "having set conn->original_dest_address"); + ((entry_connection_t*)conn)->original_dest_address = + tor_strdup(conn->socks_request->address); + } + + if ((iso & ISO_STREAM) && + (circ->associated_isolated_stream_global_id != + ENTRY_TO_CONN(conn)->global_identifier)) + return 0; + + if ((iso & ISO_DESTPORT) && conn->socks_request->port != circ->dest_port) + return 0; + if ((iso & ISO_DESTADDR) && + strcasecmp(conn->original_dest_address, circ->dest_address)) + return 0; + if ((iso & ISO_SOCKSAUTH) && + (! memeq_opt(sr->username, sr->usernamelen, + circ->socks_username, circ->socks_username_len) || + ! memeq_opt(sr->password, sr->passwordlen, + circ->socks_password, circ->socks_password_len))) + return 0; + if ((iso & ISO_CLIENTPROTO) && + (conn->socks_request->listener_type != circ->client_proto_type || + conn->socks_request->socks_version != circ->client_proto_socksver)) + return 0; + if ((iso & ISO_CLIENTADDR) && + !tor_addr_eq(&ENTRY_TO_CONN(conn)->addr, &circ->client_addr)) + return 0; + if ((iso & ISO_SESSIONGRP) && conn->session_group != circ->session_group) + return 0; + if ((iso & ISO_NYM_EPOCH) && conn->nym_epoch != circ->nym_epoch) + return 0; + + return 1; +} + +/** + * If dry_run is false, update circ's isolation flags and fields + * to reflect having had conn attached to it, and return 0. Otherwise, + * if dry_run is true, then make no changes to circ, and return + * a bitfield of isolation flags that we would have to set in + * isolation_flags_mixed to add conn to circ, or -1 if + * circ has had no streams attached to it. + */ +int +connection_edge_update_circuit_isolation(const entry_connection_t *conn, + origin_circuit_t *circ, + int dry_run) +{ + const socks_request_t *sr = conn->socks_request; + if (! conn->original_dest_address) { + log_warn(LD_BUG, "Reached connection_update_circuit_isolation without " + "having set conn->original_dest_address"); + ((entry_connection_t*)conn)->original_dest_address = + tor_strdup(conn->socks_request->address); + } + + if (!circ->isolation_values_set) { + if (dry_run) + return -1; + circ->associated_isolated_stream_global_id = + ENTRY_TO_CONN(conn)->global_identifier; + circ->dest_port = conn->socks_request->port; + circ->dest_address = tor_strdup(conn->original_dest_address); + circ->client_proto_type = conn->socks_request->listener_type; + circ->client_proto_socksver = conn->socks_request->socks_version; + tor_addr_copy(&circ->client_addr, &ENTRY_TO_CONN(conn)->addr); + circ->session_group = conn->session_group; + circ->nym_epoch = conn->nym_epoch; + circ->socks_username = sr->username ? + tor_memdup(sr->username, sr->usernamelen) : NULL; + circ->socks_password = sr->password ? + tor_memdup(sr->password, sr->passwordlen) : NULL; + circ->socks_username_len = sr->usernamelen; + circ->socks_password_len = sr->passwordlen; + + circ->isolation_values_set = 1; + return 0; + } else { + uint8_t mixed = 0; + if (conn->socks_request->port != circ->dest_port) + mixed |= ISO_DESTPORT; + if (strcasecmp(conn->original_dest_address, circ->dest_address)) + mixed |= ISO_DESTADDR; + if (!memeq_opt(sr->username, sr->usernamelen, + circ->socks_username, circ->socks_username_len) || + !memeq_opt(sr->password, sr->passwordlen, + circ->socks_password, circ->socks_password_len)) + mixed |= ISO_SOCKSAUTH; + if ((conn->socks_request->listener_type != circ->client_proto_type || + conn->socks_request->socks_version != circ->client_proto_socksver)) + mixed |= ISO_CLIENTPROTO; + if (!tor_addr_eq(&ENTRY_TO_CONN(conn)->addr, &circ->client_addr)) + mixed |= ISO_CLIENTADDR; + if (conn->session_group != circ->session_group) + mixed |= ISO_SESSIONGRP; + if (conn->nym_epoch != circ->nym_epoch) + mixed |= ISO_NYM_EPOCH; + + if (dry_run) + return mixed; + + if ((mixed & conn->isolation_flags) != 0) { + log_warn(LD_BUG, "Updating a circuit with seemingly incompatible " + "isolation flags."); + } + circ->isolation_flags_mixed |= mixed; + return 0; + } +} + +/** + * Clear the isolation settings on circ. + * + * This only works on an open circuit that has never had a stream attached to + * it, and whose isolation settings are hypothetical. (We set hypothetical + * isolation settings on circuits as we're launching them, so that we + * know whether they can handle more streams or whether we need to launch + * even more circuits. Once the circuit is open, if it turns out that + * we no longer have any streams to attach to it, we clear the isolation flags + * and data so that other streams can have a chance.) + */ +void +circuit_clear_isolation(origin_circuit_t *circ) +{ + if (circ->isolation_any_streams_attached) { + log_warn(LD_BUG, "Tried to clear the isolation status of a dirty circuit"); + return; + } + if (TO_CIRCUIT(circ)->state != CIRCUIT_STATE_OPEN) { + log_warn(LD_BUG, "Tried to clear the isolation status of a non-open " + "circuit"); + return; + } + + circ->isolation_values_set = 0; + circ->isolation_flags_mixed = 0; + circ->associated_isolated_stream_global_id = 0; + circ->client_proto_type = 0; + circ->client_proto_socksver = 0; + circ->dest_port = 0; + tor_addr_make_unspec(&circ->client_addr); + tor_free(circ->dest_address); + circ->session_group = -1; + circ->nym_epoch = 0; + if (circ->socks_username) { + memwipe(circ->socks_username, 0x11, circ->socks_username_len); + tor_free(circ->socks_username); + } + if (circ->socks_password) { + memwipe(circ->socks_password, 0x05, circ->socks_password_len); + tor_free(circ->socks_password); + } + circ->socks_username_len = circ->socks_password_len = 0; +} + diff --git a/src/tor/connection_edge.h b/src/tor/connection_edge.h new file mode 100644 index 0000000..e3a95ad --- /dev/null +++ b/src/tor/connection_edge.h @@ -0,0 +1,143 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file connection_edge.h + * \brief Header file for connection_edge.c. + **/ + +#ifndef TOR_CONNECTION_EDGE_H +#define TOR_CONNECTION_EDGE_H + +#include "testsupport.h" + +#define connection_mark_unattached_ap(conn, endreason) \ + connection_mark_unattached_ap_((conn), (endreason), __LINE__, SHORT_FILE__) + +void connection_mark_unattached_ap_(entry_connection_t *conn, int endreason, + int line, const char *file); +int connection_edge_reached_eof(edge_connection_t *conn); +int connection_edge_process_inbuf(edge_connection_t *conn, + int package_partial); +int connection_edge_destroy(circid_t circ_id, edge_connection_t *conn); +int connection_edge_end(edge_connection_t *conn, uint8_t reason); +int connection_edge_end_errno(edge_connection_t *conn); +int connection_edge_flushed_some(edge_connection_t *conn); +int connection_edge_finished_flushing(edge_connection_t *conn); +int connection_edge_finished_connecting(edge_connection_t *conn); + +void connection_ap_about_to_close(entry_connection_t *edge_conn); +void connection_exit_about_to_close(edge_connection_t *edge_conn); + +int connection_ap_handshake_send_begin(entry_connection_t *ap_conn); +int connection_ap_handshake_send_resolve(entry_connection_t *ap_conn); + +entry_connection_t *connection_ap_make_link(connection_t *partner, + char *address, uint16_t port, + const char *digest, + int session_group, + int isolation_flags, + int use_begindir, int want_onehop); +void connection_ap_handshake_socks_reply(entry_connection_t *conn, char *reply, + size_t replylen, + int endreason); +void connection_ap_handshake_socks_resolved(entry_connection_t *conn, + int answer_type, + size_t answer_len, + const uint8_t *answer, + int ttl, + time_t expires); + +int connection_exit_begin_conn(cell_t *cell, circuit_t *circ); +int connection_exit_begin_resolve(cell_t *cell, or_circuit_t *circ); +void connection_exit_connect(edge_connection_t *conn); +int connection_edge_is_rendezvous_stream(edge_connection_t *conn); +int connection_ap_can_use_exit(const entry_connection_t *conn, + const node_t *exit); +void connection_ap_expire_beginning(void); +void connection_ap_attach_pending(void); +void connection_ap_fail_onehop(const char *failed_digest, + cpath_build_state_t *build_state); +void circuit_discard_optional_exit_enclaves(extend_info_t *info); +int connection_ap_detach_retriable(entry_connection_t *conn, + origin_circuit_t *circ, + int reason); +int connection_ap_process_transparent(entry_connection_t *conn); + +int address_is_invalid_destination(const char *address, int client); + +int connection_ap_rewrite_and_attach_if_allowed(entry_connection_t *conn, + origin_circuit_t *circ, + crypt_path_t *cpath); +int connection_ap_handshake_rewrite_and_attach(entry_connection_t *conn, + origin_circuit_t *circ, + crypt_path_t *cpath); + +/** Possible return values for parse_extended_hostname. */ +typedef enum hostname_type_t { + NORMAL_HOSTNAME, ONION_HOSTNAME, EXIT_HOSTNAME, BAD_HOSTNAME +} hostname_type_t; +hostname_type_t parse_extended_hostname(char *address); + +#if defined(HAVE_NET_IF_H) && defined(HAVE_NET_PFVAR_H) +int get_pf_socket(void); +#endif + +int connection_edge_compatible_with_circuit(const entry_connection_t *conn, + const origin_circuit_t *circ); +int connection_edge_update_circuit_isolation(const entry_connection_t *conn, + origin_circuit_t *circ, + int dry_run); +void circuit_clear_isolation(origin_circuit_t *circ); +streamid_t get_unique_stream_id_by_circ(origin_circuit_t *circ); + +/** @name Begin-cell flags + * + * These flags are used in RELAY_BEGIN cells to change the default behavior + * of the cell. + * + * @{ + **/ +/** When this flag is set, the client is willing to get connected to IPv6 + * addresses */ +#define BEGIN_FLAG_IPV6_OK (1u<<0) +/** When this flag is set, the client DOES NOT support connecting to IPv4 + * addresses. (The sense of this flag is inverted from IPV6_OK, so that the + * old default behavior of Tor is equivalent to having all flags set to 0.) + **/ +#define BEGIN_FLAG_IPV4_NOT_OK (1u<<1) +/** When this flag is set, if we find both an IPv4 and an IPv6 address, + * we use the IPv6 address. Otherwise we use the IPv4 address. */ +#define BEGIN_FLAG_IPV6_PREFERRED (1u<<2) +/**@}*/ + +#ifdef CONNECTION_EDGE_PRIVATE + +/** A parsed BEGIN or BEGIN_DIR cell */ +typedef struct begin_cell_t { + /** The address the client has asked us to connect to, or NULL if this is + * a BEGIN_DIR cell*/ + char *address; + /** The flags specified in the BEGIN cell's body. One or more of + * BEGIN_FLAG_*. */ + uint32_t flags; + /** The client's requested port. */ + uint16_t port; + /** The client's requested Stream ID */ + uint16_t stream_id; + /** True iff this is a BEGIN_DIR cell. */ + unsigned is_begindir : 1; +} begin_cell_t; + +STATIC int begin_cell_parse(const cell_t *cell, begin_cell_t *bcell, + uint8_t *end_reason_out); +STATIC int connected_cell_format_payload(uint8_t *payload_out, + const tor_addr_t *addr, + uint32_t ttl); +#endif + +#endif + diff --git a/src/tor/connection_or.c b/src/tor/connection_or.c new file mode 100644 index 0000000..b89f7bf --- /dev/null +++ b/src/tor/connection_or.c @@ -0,0 +1,2452 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file connection_or.c + * \brief Functions to handle OR connections, TLS handshaking, and + * cells on the network. + **/ +#include "or.h" +#include "buffers.h" +/* + * Define this so we get channel internal functions, since we're implementing + * part of a subclass (channel_tls_t). + */ +#define TOR_CHANNEL_INTERNAL_ +#include "channel.h" +#include "channeltls.h" +#include "circuitbuild.h" +#include "circuitlist.h" +#include "circuitstats.h" +#include "command.h" +#include "config.h" +#include "connection.h" +#include "connection_or.h" +#include "control.h" +#include "dirserv.h" +#include "entrynodes.h" +#include "geoip.h" +#include "onion_main.h" +#include "networkstatus.h" +#include "nodelist.h" +#include "reasons.h" +#include "relay.h" +#include "rephist.h" +#include "router.h" +#include "routerlist.h" +#include "ext_orport.h" +#ifdef USE_BUFFEREVENTS +#include +#endif + +static int connection_tls_finish_handshake(or_connection_t *conn); +static int connection_or_launch_v3_or_handshake(or_connection_t *conn); +static int connection_or_process_cells_from_inbuf(or_connection_t *conn); +static int connection_or_check_valid_tls_handshake(or_connection_t *conn, + int started_here, + char *digest_rcvd_out); + +static void connection_or_tls_renegotiated_cb(tor_tls_t *tls, void *_conn); + +static unsigned int +connection_or_is_bad_for_new_circs(or_connection_t *or_conn); +static void connection_or_mark_bad_for_new_circs(or_connection_t *or_conn); + +/* + * Call this when changing connection state, so notifications to the owning + * channel can be handled. + */ + +static void connection_or_change_state(or_connection_t *conn, uint8_t state); + +#ifdef USE_BUFFEREVENTS +static void connection_or_handle_event_cb(struct bufferevent *bufev, + short event, void *arg); +#include /*XXXX REMOVE */ +#endif + +/**************************************************************/ + +/** Map from identity digest of connected OR or desired OR to a connection_t + * with that identity digest. If there is more than one such connection_t, + * they form a linked list, with next_with_same_id as the next pointer. */ +static digestmap_t *orconn_identity_map = NULL; + +/** Global map between Extended ORPort identifiers and OR + * connections. */ +static digestmap_t *orconn_ext_or_id_map = NULL; + +/** If conn is listed in orconn_identity_map, remove it, and clear + * conn->identity_digest. Otherwise do nothing. */ +void +connection_or_remove_from_identity_map(or_connection_t *conn) +{ + or_connection_t *tmp; + tor_assert(conn); + if (!orconn_identity_map) + return; + tmp = digestmap_get(orconn_identity_map, conn->identity_digest); + if (!tmp) { + if (!tor_digest_is_zero(conn->identity_digest)) { + log_warn(LD_BUG, "Didn't find connection '%s' on identity map when " + "trying to remove it.", + conn->nickname ? conn->nickname : "NULL"); + } + return; + } + if (conn == tmp) { + if (conn->next_with_same_id) + digestmap_set(orconn_identity_map, conn->identity_digest, + conn->next_with_same_id); + else + digestmap_remove(orconn_identity_map, conn->identity_digest); + } else { + while (tmp->next_with_same_id) { + if (tmp->next_with_same_id == conn) { + tmp->next_with_same_id = conn->next_with_same_id; + break; + } + tmp = tmp->next_with_same_id; + } + } + memset(conn->identity_digest, 0, DIGEST_LEN); + conn->next_with_same_id = NULL; +} + +/** Remove all entries from the identity-to-orconn map, and clear + * all identities in OR conns.*/ +void +connection_or_clear_identity_map(void) +{ + smartlist_t *conns = get_connection_array(); + SMARTLIST_FOREACH(conns, connection_t *, conn, + { + if (conn->type == CONN_TYPE_OR) { + or_connection_t *or_conn = TO_OR_CONN(conn); + memset(or_conn->identity_digest, 0, DIGEST_LEN); + or_conn->next_with_same_id = NULL; + } + }); + + digestmap_free(orconn_identity_map, NULL); + orconn_identity_map = NULL; +} + +/** Change conn->identity_digest to digest, and add conn into + * orconn_digest_map. */ +static void +connection_or_set_identity_digest(or_connection_t *conn, const char *digest) +{ + or_connection_t *tmp; + tor_assert(conn); + tor_assert(digest); + + if (!orconn_identity_map) + orconn_identity_map = digestmap_new(); + if (tor_memeq(conn->identity_digest, digest, DIGEST_LEN)) + return; + + /* If the identity was set previously, remove the old mapping. */ + if (! tor_digest_is_zero(conn->identity_digest)) { + connection_or_remove_from_identity_map(conn); + if (conn->chan) + channel_clear_identity_digest(TLS_CHAN_TO_BASE(conn->chan)); + } + + memcpy(conn->identity_digest, digest, DIGEST_LEN); + + /* If we're setting the ID to zero, don't add a mapping. */ + if (tor_digest_is_zero(digest)) + return; + + tmp = digestmap_set(orconn_identity_map, digest, conn); + conn->next_with_same_id = tmp; + + /* Deal with channels */ + if (conn->chan) + channel_set_identity_digest(TLS_CHAN_TO_BASE(conn->chan), digest); + +#if 1 + /* Testing code to check for bugs in representation. */ + for (; tmp; tmp = tmp->next_with_same_id) { + tor_assert(tor_memeq(tmp->identity_digest, digest, DIGEST_LEN)); + tor_assert(tmp != conn); + } +#endif +} + +/** Remove the Extended ORPort identifier of conn from the + * global identifier list. Also, clear the identifier from the + * connection itself. */ +void +connection_or_remove_from_ext_or_id_map(or_connection_t *conn) +{ + or_connection_t *tmp; + if (!orconn_ext_or_id_map) + return; + if (!conn->ext_or_conn_id) + return; + + tmp = digestmap_remove(orconn_ext_or_id_map, conn->ext_or_conn_id); + if (!tor_digest_is_zero(conn->ext_or_conn_id)) + tor_assert(tmp == conn); + + memset(conn->ext_or_conn_id, 0, EXT_OR_CONN_ID_LEN); +} + +/** Return the connection whose ext_or_id is id. Return NULL if no such + * connection is found. */ +or_connection_t * +connection_or_get_by_ext_or_id(const char *id) +{ + if (!orconn_ext_or_id_map) + return NULL; + return digestmap_get(orconn_ext_or_id_map, id); +} + +/** Deallocate the global Extended ORPort identifier list */ +void +connection_or_clear_ext_or_id_map(void) +{ + digestmap_free(orconn_ext_or_id_map, NULL); + orconn_ext_or_id_map = NULL; +} + +/** Creates an Extended ORPort identifier for conn and deposits + * it into the global list of identifiers. */ +void +connection_or_set_ext_or_identifier(or_connection_t *conn) +{ + char random_id[EXT_OR_CONN_ID_LEN]; + or_connection_t *tmp; + + if (!orconn_ext_or_id_map) + orconn_ext_or_id_map = digestmap_new(); + + /* Remove any previous identifiers: */ + if (conn->ext_or_conn_id && !tor_digest_is_zero(conn->ext_or_conn_id)) + connection_or_remove_from_ext_or_id_map(conn); + + do { + crypto_rand(random_id, sizeof(random_id)); + } while (digestmap_get(orconn_ext_or_id_map, random_id)); + + if (!conn->ext_or_conn_id) + conn->ext_or_conn_id = tor_malloc_zero(EXT_OR_CONN_ID_LEN); + + memcpy(conn->ext_or_conn_id, random_id, EXT_OR_CONN_ID_LEN); + + tmp = digestmap_set(orconn_ext_or_id_map, random_id, conn); + tor_assert(!tmp); +} + +/**************************************************************/ + +/** Map from a string describing what a non-open OR connection was doing when + * failed, to an intptr_t describing the count of connections that failed that + * way. Note that the count is stored _as_ the pointer. + */ +static strmap_t *broken_connection_counts; + +/** If true, do not record information in broken_connection_counts. */ +static int disable_broken_connection_counts = 0; + +/** Record that an OR connection failed in state. */ +static void +note_broken_connection(const char *state) +{ + void *ptr; + intptr_t val; + if (disable_broken_connection_counts) + return; + + if (!broken_connection_counts) + broken_connection_counts = strmap_new(); + + ptr = strmap_get(broken_connection_counts, state); + val = (intptr_t)ptr; + val++; + ptr = (void*)val; + strmap_set(broken_connection_counts, state, ptr); +} + +/** Forget all recorded states for failed connections. If + * stop_recording is true, don't record any more. */ +void +clear_broken_connection_map(int stop_recording) +{ + if (broken_connection_counts) + strmap_free(broken_connection_counts, NULL); + broken_connection_counts = NULL; + if (stop_recording) + disable_broken_connection_counts = 1; +} + +/** Write a detailed description the state of orconn into the + * buflen-byte buffer at buf. This description includes not + * only the OR-conn level state but also the TLS state. It's useful for + * diagnosing broken handshakes. */ +static void +connection_or_get_state_description(or_connection_t *orconn, + char *buf, size_t buflen) +{ + connection_t *conn = TO_CONN(orconn); + const char *conn_state; + char tls_state[256]; + + tor_assert(conn->type == CONN_TYPE_OR || conn->type == CONN_TYPE_EXT_OR); + + conn_state = conn_state_to_string(conn->type, conn->state); + tor_tls_get_state_description(orconn->tls, tls_state, sizeof(tls_state)); + + tor_snprintf(buf, buflen, "%s with SSL state %s", conn_state, tls_state); +} + +/** Record the current state of orconn as the state of a broken + * connection. */ +static void +connection_or_note_state_when_broken(or_connection_t *orconn) +{ + char buf[256]; + if (disable_broken_connection_counts) + return; + connection_or_get_state_description(orconn, buf, sizeof(buf)); + log_info(LD_HANDSHAKE,"Connection died in state '%s'", buf); + note_broken_connection(buf); +} + +/** Helper type used to sort connection states and find the most frequent. */ +typedef struct broken_state_count_t { + intptr_t count; + const char *state; +} broken_state_count_t; + +/** Helper function used to sort broken_state_count_t by frequency. */ +static int +broken_state_count_compare(const void **a_ptr, const void **b_ptr) +{ + const broken_state_count_t *a = *a_ptr, *b = *b_ptr; + if (b->count < a->count) + return -1; + else if (b->count == a->count) + return 0; + else + return 1; +} + +/** Upper limit on the number of different states to report for connection + * failure. */ +#define MAX_REASONS_TO_REPORT 10 + +/** Report a list of the top states for failed OR connections at log level + * severity, in log domain domain. */ +void +connection_or_report_broken_states(int severity, int domain) +{ + int total = 0; + smartlist_t *items; + + if (!broken_connection_counts || disable_broken_connection_counts) + return; + + items = smartlist_new(); + STRMAP_FOREACH(broken_connection_counts, state, void *, countptr) { + broken_state_count_t *c = tor_malloc(sizeof(broken_state_count_t)); + c->count = (intptr_t)countptr; + total += (int)c->count; + c->state = state; + smartlist_add(items, c); + } STRMAP_FOREACH_END; + + smartlist_sort(items, broken_state_count_compare); + + tor_log(severity, domain, "%d connections have failed%s", total, + smartlist_len(items) > MAX_REASONS_TO_REPORT ? ". Top reasons:" : ":"); + + SMARTLIST_FOREACH_BEGIN(items, const broken_state_count_t *, c) { + if (c_sl_idx > MAX_REASONS_TO_REPORT) + break; + tor_log(severity, domain, + " %d connections died in state %s", (int)c->count, c->state); + } SMARTLIST_FOREACH_END(c); + + SMARTLIST_FOREACH(items, broken_state_count_t *, c, tor_free(c)); + smartlist_free(items); +} + +/** Call this to change or_connection_t states, so the owning channel_tls_t can + * be notified. + */ + +static void +connection_or_change_state(or_connection_t *conn, uint8_t state) +{ + uint8_t old_state; + + tor_assert(conn); + + old_state = conn->base_.state; + conn->base_.state = state; + + if (conn->chan) + channel_tls_handle_state_change_on_orconn(conn->chan, conn, + old_state, state); +} + +/** Return the number of circuits using an or_connection_t; this used to + * be an or_connection_t field, but it got moved to channel_t and we + * shouldn't maintain two copies. */ + +int +connection_or_get_num_circuits(or_connection_t *conn) +{ + tor_assert(conn); + + if (conn->chan) { + return channel_num_circuits(TLS_CHAN_TO_BASE(conn->chan)); + } else return 0; +} + +/**************************************************************/ + +/** Pack the cell_t host-order structure src into network-order + * in the buffer dest. See tor-spec.txt for details about the + * wire format. + * + * Note that this function doesn't touch dst-\>next: the caller + * should set it or clear it as appropriate. + */ +void +cell_pack(packed_cell_t *dst, const cell_t *src, int wide_circ_ids) +{ + char *dest = dst->body; + if (wide_circ_ids) { + set_uint32(dest, htonl(src->circ_id)); + dest += 4; + } else { + set_uint16(dest, htons(src->circ_id)); + dest += 2; + memset(dest+CELL_MAX_NETWORK_SIZE-2, 0, 2); /*make sure it's clear */ + } + set_uint8(dest, src->command); + memcpy(dest+1, src->payload, CELL_PAYLOAD_SIZE); +} + +/** Unpack the network-order buffer src into a host-order + * cell_t structure dest. + */ +static void +cell_unpack(cell_t *dest, const char *src, int wide_circ_ids) +{ + if (wide_circ_ids) { + dest->circ_id = ntohl(get_uint32(src)); + src += 4; + } else { + dest->circ_id = ntohs(get_uint16(src)); + src += 2; + } + dest->command = get_uint8(src); + memcpy(dest->payload, src+1, CELL_PAYLOAD_SIZE); +} + +/** Write the header of cell into the first VAR_CELL_MAX_HEADER_SIZE + * bytes of hdr_out. Returns number of bytes used. */ +int +var_cell_pack_header(const var_cell_t *cell, char *hdr_out, int wide_circ_ids) +{ + int r; + if (wide_circ_ids) { + set_uint32(hdr_out, htonl(cell->circ_id)); + hdr_out += 4; + r = VAR_CELL_MAX_HEADER_SIZE; + } else { + set_uint16(hdr_out, htons(cell->circ_id)); + hdr_out += 2; + r = VAR_CELL_MAX_HEADER_SIZE - 2; + } + set_uint8(hdr_out, cell->command); + set_uint16(hdr_out+1, htons(cell->payload_len)); + return r; +} + +/** Allocate and return a new var_cell_t with payload_len bytes of + * payload space. */ +var_cell_t * +var_cell_new(uint16_t payload_len) +{ + size_t size = STRUCT_OFFSET(var_cell_t, payload) + payload_len; + var_cell_t *cell = tor_malloc_zero(size); + cell->payload_len = payload_len; + cell->command = 0; + cell->circ_id = 0; + return cell; +} + +/** Release all space held by cell. */ +void +var_cell_free(var_cell_t *cell) +{ + tor_free(cell); +} + +/** We've received an EOF from conn. Mark it for close and return. */ +int +connection_or_reached_eof(or_connection_t *conn) +{ + tor_assert(conn); + + log_info(LD_OR,"OR connection reached EOF. Closing."); + connection_or_close_normally(conn, 1); + + return 0; +} + +/** Handle any new bytes that have come in on connection conn. + * If conn is in 'open' state, hand it to + * connection_or_process_cells_from_inbuf() + * (else do nothing). + */ +int +connection_or_process_inbuf(or_connection_t *conn) +{ + /** Don't let the inbuf of a nonopen OR connection grow beyond this many + * bytes: it's either a broken client, a non-Tor client, or a DOS + * attempt. */ +#define MAX_OR_INBUF_WHEN_NONOPEN 0 + + int ret = 0; + tor_assert(conn); + + switch (conn->base_.state) { + case OR_CONN_STATE_PROXY_HANDSHAKING: + ret = connection_read_proxy_handshake(TO_CONN(conn)); + + /* start TLS after handshake completion, or deal with error */ + if (ret == 1) { + tor_assert(TO_CONN(conn)->proxy_state == PROXY_CONNECTED); + if (connection_tls_start_handshake(conn, 0) < 0) + ret = -1; + /* Touch the channel's active timestamp if there is one */ + if (conn->chan) + channel_timestamp_active(TLS_CHAN_TO_BASE(conn->chan)); + } + if (ret < 0) { + connection_or_close_for_error(conn, 0); + } + + return ret; + case OR_CONN_STATE_TLS_SERVER_RENEGOTIATING: +#ifdef USE_BUFFEREVENTS + if (tor_tls_server_got_renegotiate(conn->tls)) + connection_or_tls_renegotiated_cb(conn->tls, conn); + if (conn->base_.marked_for_close) + return 0; + /* fall through. */ +#endif + case OR_CONN_STATE_OPEN: + case OR_CONN_STATE_OR_HANDSHAKING_V2: + case OR_CONN_STATE_OR_HANDSHAKING_V3: + return connection_or_process_cells_from_inbuf(conn); + default: + break; /* don't do anything */ + } + + /* This check was necessary with 0.2.2, when the TLS_SERVER_RENEGOTIATING + * check would otherwise just let data accumulate. It serves no purpose + * in 0.2.3. + * + * XXX024 Remove this check once we verify that the above paragraph is + * 100% true. */ + if (buf_datalen(conn->base_.inbuf) > MAX_OR_INBUF_WHEN_NONOPEN) { + log_fn(LOG_PROTOCOL_WARN, LD_NET, "Accumulated too much data (%d bytes) " + "on nonopen OR connection %s %s:%u in state %s; closing.", + (int)buf_datalen(conn->base_.inbuf), + connection_or_nonopen_was_started_here(conn) ? "to" : "from", + conn->base_.address, conn->base_.port, + conn_state_to_string(conn->base_.type, conn->base_.state)); + connection_or_close_for_error(conn, 0); + ret = -1; + } + + return ret; +} + +/** When adding cells to an OR connection's outbuf, keep adding until the + * outbuf is at least this long, or we run out of cells. */ +#define OR_CONN_HIGHWATER (32*1024) + +/** Add cells to an OR connection's outbuf whenever the outbuf's data length + * drops below this size. */ +#define OR_CONN_LOWWATER (16*1024) + +/** Called whenever we have flushed some data on an or_conn: add more data + * from active circuits. */ +int +connection_or_flushed_some(or_connection_t *conn) +{ + size_t datalen, temp; + ssize_t n, flushed; + size_t cell_network_size = get_cell_network_size(conn->wide_circ_ids); + + /* If we're under the low water mark, add cells until we're just over the + * high water mark. */ + datalen = connection_get_outbuf_len(TO_CONN(conn)); + if (datalen < OR_CONN_LOWWATER) { + while ((conn->chan) && channel_tls_more_to_flush(conn->chan)) { + /* Compute how many more cells we want at most */ + n = CEIL_DIV(OR_CONN_HIGHWATER - datalen, cell_network_size); + /* Bail out if we don't want any more */ + if (n <= 0) break; + /* We're still here; try to flush some more cells */ + flushed = channel_tls_flush_some_cells(conn->chan, n); + /* Bail out if it says it didn't flush anything */ + if (flushed <= 0) break; + /* How much in the outbuf now? */ + temp = connection_get_outbuf_len(TO_CONN(conn)); + /* Bail out if we didn't actually increase the outbuf size */ + if (temp <= datalen) break; + /* Update datalen for the next iteration */ + datalen = temp; + } + } + + return 0; +} + +/** Connection conn has finished writing and has no bytes left on + * its outbuf. + * + * Otherwise it's in state "open": stop writing and return. + * + * If conn is broken, mark it for close and return -1, else + * return 0. + */ +int +connection_or_finished_flushing(or_connection_t *conn) +{ + tor_assert(conn); + assert_connection_ok(TO_CONN(conn),0); + + switch (conn->base_.state) { + case OR_CONN_STATE_PROXY_HANDSHAKING: + case OR_CONN_STATE_OPEN: + case OR_CONN_STATE_OR_HANDSHAKING_V2: + case OR_CONN_STATE_OR_HANDSHAKING_V3: + break; + default: + log_err(LD_BUG,"Called in unexpected state %d.", conn->base_.state); + tor_fragile_assert(); + return -1; + } + return 0; +} + +/** Connected handler for OR connections: begin the TLS handshake. + */ +int +connection_or_finished_connecting(or_connection_t *or_conn) +{ + const int proxy_type = or_conn->proxy_type; + connection_t *conn; + + tor_assert(or_conn); + conn = TO_CONN(or_conn); + tor_assert(conn->state == OR_CONN_STATE_CONNECTING); + + log_debug(LD_HANDSHAKE,"OR connect() to router at %s:%u finished.", + conn->address,conn->port); + control_event_bootstrap(BOOTSTRAP_STATUS_HANDSHAKE, 0); + + if (proxy_type != PROXY_NONE) { + /* start proxy handshake */ + if (connection_proxy_connect(conn, proxy_type) < 0) { + connection_or_close_for_error(or_conn, 0); + return -1; + } + + connection_start_reading(conn); + connection_or_change_state(or_conn, OR_CONN_STATE_PROXY_HANDSHAKING); + return 0; + } + + if (connection_tls_start_handshake(or_conn, 0) < 0) { + /* TLS handshaking error of some kind. */ + connection_or_close_for_error(or_conn, 0); + return -1; + } + return 0; +} + +/** Called when we're about to finally unlink and free an OR connection: + * perform necessary accounting and cleanup */ +void +connection_or_about_to_close(or_connection_t *or_conn) +{ + time_t now = time(NULL); + connection_t *conn = TO_CONN(or_conn); + + /* Tell the controlling channel we're closed */ + if (or_conn->chan) { + channel_closed(TLS_CHAN_TO_BASE(or_conn->chan)); + /* + * NULL this out because the channel might hang around a little + * longer before channel_run_cleanup() gets it. + */ + or_conn->chan->conn = NULL; + or_conn->chan = NULL; + } + + /* Remember why we're closing this connection. */ + if (conn->state != OR_CONN_STATE_OPEN) { + /* now mark things down as needed */ + if (connection_or_nonopen_was_started_here(or_conn)) { + const or_options_t *options = get_options(); + connection_or_note_state_when_broken(or_conn); + rep_hist_note_connect_failed(or_conn->identity_digest, now); + entry_guard_register_connect_status(or_conn->identity_digest,0, + !options->HTTPSProxy, now); + if (conn->state >= OR_CONN_STATE_TLS_HANDSHAKING) { + int reason = tls_error_to_orconn_end_reason(or_conn->tls_error); + control_event_or_conn_status(or_conn, OR_CONN_EVENT_FAILED, + reason); + if (!authdir_mode_tests_reachability(options)) + control_event_bootstrap_problem( + orconn_end_reason_to_control_string(reason), reason); + } + } + } else if (conn->hold_open_until_flushed) { + /* We only set hold_open_until_flushed when we're intentionally + * closing a connection. */ + rep_hist_note_disconnect(or_conn->identity_digest, now); + control_event_or_conn_status(or_conn, OR_CONN_EVENT_CLOSED, + tls_error_to_orconn_end_reason(or_conn->tls_error)); + } else if (!tor_digest_is_zero(or_conn->identity_digest)) { + rep_hist_note_connection_died(or_conn->identity_digest, now); + control_event_or_conn_status(or_conn, OR_CONN_EVENT_CLOSED, + tls_error_to_orconn_end_reason(or_conn->tls_error)); + } +} + +/** Return 1 if identity digest id_digest is known to be a + * currently or recently running relay. Otherwise return 0. */ +int +connection_or_digest_is_known_relay(const char *id_digest) +{ + if (router_get_consensus_status_by_id(id_digest)) + return 1; /* It's in the consensus: "yes" */ + if (router_get_by_id_digest(id_digest)) + return 1; /* Not in the consensus, but we have a descriptor for + * it. Probably it was in a recent consensus. "Yes". */ + return 0; +} + +/** Set the per-conn read and write limits for conn. If it's a known + * relay, we will rely on the global read and write buckets, so give it + * per-conn limits that are big enough they'll never matter. But if it's + * not a known relay, first check if we set PerConnBwRate/Burst, then + * check if the consensus sets them, else default to 'big enough'. + * + * If reset is true, set the bucket to be full. Otherwise, just + * clip the bucket if it happens to be too full. + */ +static void +connection_or_update_token_buckets_helper(or_connection_t *conn, int reset, + const or_options_t *options) +{ + int rate, burst; /* per-connection rate limiting params */ + if (connection_or_digest_is_known_relay(conn->identity_digest)) { + /* It's in the consensus, or we have a descriptor for it meaning it + * was probably in a recent consensus. It's a recognized relay: + * give it full bandwidth. */ + rate = (int)options->BandwidthRate; + burst = (int)options->BandwidthBurst; + } else { + /* Not a recognized relay. Squeeze it down based on the suggested + * bandwidth parameters in the consensus, but allow local config + * options to override. */ + rate = options->PerConnBWRate ? (int)options->PerConnBWRate : + networkstatus_get_param(NULL, "perconnbwrate", + (int)options->BandwidthRate, 1, INT32_MAX); + burst = options->PerConnBWBurst ? (int)options->PerConnBWBurst : + networkstatus_get_param(NULL, "perconnbwburst", + (int)options->BandwidthBurst, 1, INT32_MAX); + } + + conn->bandwidthrate = rate; + conn->bandwidthburst = burst; +#ifdef USE_BUFFEREVENTS + { + const struct timeval *tick = tor_libevent_get_one_tick_timeout(); + struct ev_token_bucket_cfg *cfg, *old_cfg; + int64_t rate64 = (((int64_t)rate) * options->TokenBucketRefillInterval) + / 1000; + /* This can't overflow, since TokenBucketRefillInterval <= 1000, + * and rate started out less than INT_MAX. */ + int rate_per_tick = (int) rate64; + + cfg = ev_token_bucket_cfg_new(rate_per_tick, burst, rate_per_tick, + burst, tick); + old_cfg = conn->bucket_cfg; + if (conn->base_.bufev) + tor_set_bufferevent_rate_limit(conn->base_.bufev, cfg); + if (old_cfg) + ev_token_bucket_cfg_free(old_cfg); + conn->bucket_cfg = cfg; + (void) reset; /* No way to do this with libevent yet. */ + } +#else + if (reset) { /* set up the token buckets to be full */ + conn->read_bucket = conn->write_bucket = burst; + return; + } + /* If the new token bucket is smaller, take out the extra tokens. + * (If it's larger, don't -- the buckets can grow to reach the cap.) */ + if (conn->read_bucket > burst) + conn->read_bucket = burst; + if (conn->write_bucket > burst) + conn->write_bucket = burst; +#endif +} + +/** Either our set of relays or our per-conn rate limits have changed. + * Go through all the OR connections and update their token buckets to make + * sure they don't exceed their maximum values. */ +void +connection_or_update_token_buckets(smartlist_t *conns, + const or_options_t *options) +{ + SMARTLIST_FOREACH(conns, connection_t *, conn, + { + if (connection_speaks_cells(conn)) + connection_or_update_token_buckets_helper(TO_OR_CONN(conn), 0, options); + }); +} + +/** If we don't necessarily know the router we're connecting to, but we + * have an addr/port/id_digest, then fill in as much as we can. Start + * by checking to see if this describes a router we know. + * started_here is 1 if we are the initiator of conn and + * 0 if it's an incoming connection. */ +void +connection_or_init_conn_from_address(or_connection_t *conn, + const tor_addr_t *addr, uint16_t port, + const char *id_digest, + int started_here) +{ + const node_t *r = node_get_by_id(id_digest); + connection_or_set_identity_digest(conn, id_digest); + connection_or_update_token_buckets_helper(conn, 1, get_options()); + + conn->base_.port = port; + tor_addr_copy(&conn->base_.addr, addr); + tor_addr_copy(&conn->real_addr, addr); + if (r) { + tor_addr_port_t node_ap; + node_get_pref_orport(r, &node_ap); + /* XXXX proposal 186 is making this more complex. For now, a conn + is canonical when it uses the _preferred_ address. */ + if (tor_addr_eq(&conn->base_.addr, &node_ap.addr)) + conn->is_canonical = 1; + if (!started_here) { + /* Override the addr/port, so our log messages will make sense. + * This is dangerous, since if we ever try looking up a conn by + * its actual addr/port, we won't remember. Careful! */ + /* XXXX arma: this is stupid, and it's the reason we need real_addr + * to track is_canonical properly. What requires it? */ + /* XXXX i believe the reason we did this, originally, is because + * we wanted to log what OR a connection was to, and if we logged the + * right IP address and port 56244, that wouldn't be as helpful. now we + * log the "right" port too, so we know if it's moria1 or moria2. + */ + tor_addr_copy(&conn->base_.addr, &node_ap.addr); + conn->base_.port = node_ap.port; + } + conn->nickname = tor_strdup(node_get_nickname(r)); + tor_free(conn->base_.address); + conn->base_.address = tor_dup_addr(&node_ap.addr); + } else { + const char *n; + /* If we're an authoritative directory server, we may know a + * nickname for this router. */ + n = dirserv_get_nickname_by_digest(id_digest); + if (n) { + conn->nickname = tor_strdup(n); + } else { + conn->nickname = tor_malloc(HEX_DIGEST_LEN+2); + conn->nickname[0] = '$'; + base16_encode(conn->nickname+1, HEX_DIGEST_LEN+1, + conn->identity_digest, DIGEST_LEN); + } + tor_free(conn->base_.address); + conn->base_.address = tor_dup_addr(addr); + } +} + +/** These just pass all the is_bad_for_new_circs manipulation on to + * channel_t */ + +static unsigned int +connection_or_is_bad_for_new_circs(or_connection_t *or_conn) +{ + tor_assert(or_conn); + + if (or_conn->chan) + return channel_is_bad_for_new_circs(TLS_CHAN_TO_BASE(or_conn->chan)); + else return 0; +} + +static void +connection_or_mark_bad_for_new_circs(or_connection_t *or_conn) +{ + tor_assert(or_conn); + + if (or_conn->chan) + channel_mark_bad_for_new_circs(TLS_CHAN_TO_BASE(or_conn->chan)); +} + +/** How old do we let a connection to an OR get before deciding it's + * too old for new circuits? */ +#define TIME_BEFORE_OR_CONN_IS_TOO_OLD (60*60*24*7) + +/** Given the head of the linked list for all the or_connections with a given + * identity, set elements of that list as is_bad_for_new_circs as + * appropriate. Helper for connection_or_set_bad_connections(). + * + * Specifically, we set the is_bad_for_new_circs flag on: + * - all connections if force is true. + * - all connections that are too old. + * - all open non-canonical connections for which a canonical connection + * exists to the same router. + * - all open canonical connections for which a 'better' canonical + * connection exists to the same router. + * - all open non-canonical connections for which a 'better' non-canonical + * connection exists to the same router at the same address. + * + * See channel_is_better() in channel.c for our idea of what makes one OR + * connection better than another. + */ +static void +connection_or_group_set_badness(or_connection_t *head, int force) +{ + or_connection_t *or_conn = NULL, *best = NULL; + int n_old = 0, n_inprogress = 0, n_canonical = 0, n_other = 0; + time_t now = time(NULL); + + /* Pass 1: expire everything that's old, and see what the status of + * everything else is. */ + for (or_conn = head; or_conn; or_conn = or_conn->next_with_same_id) { + if (or_conn->base_.marked_for_close || + connection_or_is_bad_for_new_circs(or_conn)) + continue; + if (force || + or_conn->base_.timestamp_created + TIME_BEFORE_OR_CONN_IS_TOO_OLD + < now) { + log_info(LD_OR, + "Marking OR conn to %s:%d as too old for new circuits " + "(fd "TOR_SOCKET_T_FORMAT", %d secs old).", + or_conn->base_.address, or_conn->base_.port, or_conn->base_.s, + (int)(now - or_conn->base_.timestamp_created)); + connection_or_mark_bad_for_new_circs(or_conn); + } + + if (connection_or_is_bad_for_new_circs(or_conn)) { + ++n_old; + } else if (or_conn->base_.state != OR_CONN_STATE_OPEN) { + ++n_inprogress; + } else if (or_conn->is_canonical) { + ++n_canonical; + } else { + ++n_other; + } + } + + /* Pass 2: We know how about how good the best connection is. + * expire everything that's worse, and find the very best if we can. */ + for (or_conn = head; or_conn; or_conn = or_conn->next_with_same_id) { + if (or_conn->base_.marked_for_close || + connection_or_is_bad_for_new_circs(or_conn)) + continue; /* This one doesn't need to be marked bad. */ + if (or_conn->base_.state != OR_CONN_STATE_OPEN) + continue; /* Don't mark anything bad until we have seen what happens + * when the connection finishes. */ + if (n_canonical && !or_conn->is_canonical) { + /* We have at least one open canonical connection to this router, + * and this one is open but not canonical. Mark it bad. */ + log_info(LD_OR, + "Marking OR conn to %s:%d as unsuitable for new circuits: " + "(fd "TOR_SOCKET_T_FORMAT", %d secs old). It is not " + "canonical, and we have another connection to that OR that is.", + or_conn->base_.address, or_conn->base_.port, or_conn->base_.s, + (int)(now - or_conn->base_.timestamp_created)); + connection_or_mark_bad_for_new_circs(or_conn); + continue; + } + + if (!best || + channel_is_better(now, + TLS_CHAN_TO_BASE(or_conn->chan), + TLS_CHAN_TO_BASE(best->chan), + 0)) { + best = or_conn; + } + } + + if (!best) + return; + + /* Pass 3: One connection to OR is best. If it's canonical, mark as bad + * every other open connection. If it's non-canonical, mark as bad + * every other open connection to the same address. + * + * XXXX This isn't optimal; if we have connections to an OR at multiple + * addresses, we'd like to pick the best _for each address_, and mark as + * bad every open connection that isn't best for its address. But this + * can only occur in cases where the other OR is old (so we have no + * canonical connection to it), or where all the connections to the OR are + * at noncanonical addresses and we have no good direct connection (which + * means we aren't at risk of attaching circuits to it anyway). As + * 0.1.2.x dies out, the first case will go away, and the second one is + * "mostly harmless", so a fix can wait until somebody is bored. + */ + for (or_conn = head; or_conn; or_conn = or_conn->next_with_same_id) { + if (or_conn->base_.marked_for_close || + connection_or_is_bad_for_new_circs(or_conn) || + or_conn->base_.state != OR_CONN_STATE_OPEN) + continue; + if (or_conn != best && + channel_is_better(now, + TLS_CHAN_TO_BASE(best->chan), + TLS_CHAN_TO_BASE(or_conn->chan), 1)) { + /* This isn't the best conn, _and_ the best conn is better than it, + even when we're being forgiving. */ + if (best->is_canonical) { + log_info(LD_OR, + "Marking OR conn to %s:%d as unsuitable for new circuits: " + "(fd "TOR_SOCKET_T_FORMAT", %d secs old). " + "We have a better canonical one " + "(fd "TOR_SOCKET_T_FORMAT"; %d secs old).", + or_conn->base_.address, or_conn->base_.port, or_conn->base_.s, + (int)(now - or_conn->base_.timestamp_created), + best->base_.s, (int)(now - best->base_.timestamp_created)); + connection_or_mark_bad_for_new_circs(or_conn); + } else if (!tor_addr_compare(&or_conn->real_addr, + &best->real_addr, CMP_EXACT)) { + log_info(LD_OR, + "Marking OR conn to %s:%d as unsuitable for new circuits: " + "(fd "TOR_SOCKET_T_FORMAT", %d secs old). We have a better " + "one with the " + "same address (fd "TOR_SOCKET_T_FORMAT"; %d secs old).", + or_conn->base_.address, or_conn->base_.port, or_conn->base_.s, + (int)(now - or_conn->base_.timestamp_created), + best->base_.s, (int)(now - best->base_.timestamp_created)); + connection_or_mark_bad_for_new_circs(or_conn); + } + } + } +} + +/** Go through all the OR connections (or if digest is non-NULL, just + * the OR connections with that digest), and set the is_bad_for_new_circs + * flag based on the rules in connection_or_group_set_badness() (or just + * always set it if force is true). + */ +void +connection_or_set_bad_connections(const char *digest, int force) +{ + if (!orconn_identity_map) + return; + + DIGESTMAP_FOREACH(orconn_identity_map, identity, or_connection_t *, conn) { + if (!digest || tor_memeq(digest, conn->identity_digest, DIGEST_LEN)) + connection_or_group_set_badness(conn, force); + } DIGESTMAP_FOREACH_END; +} + +/** conn is in the 'connecting' state, and it failed to complete + * a TCP connection. Send notifications appropriately. + * + * reason specifies the or_conn_end_reason for the failure; + * msg specifies the strerror-style error message. + */ +void +connection_or_connect_failed(or_connection_t *conn, + int reason, const char *msg) +{ + control_event_or_conn_status(conn, OR_CONN_EVENT_FAILED, reason); + if (!authdir_mode_tests_reachability(get_options())) + control_event_bootstrap_problem(msg, reason); +} + +/** conn got an error in connection_handle_read_impl() or + * connection_handle_write_impl() and is going to die soon. + * + * reason specifies the or_conn_end_reason for the failure; + * msg specifies the strerror-style error message. + */ +void +connection_or_notify_error(or_connection_t *conn, + int reason, const char *msg) +{ + channel_t *chan; + + tor_assert(conn); + + /* If we're connecting, call connect_failed() too */ + if (TO_CONN(conn)->state == OR_CONN_STATE_CONNECTING) + connection_or_connect_failed(conn, reason, msg); + + /* Tell the controlling channel if we have one */ + if (conn->chan) { + chan = TLS_CHAN_TO_BASE(conn->chan); + /* Don't transition if we're already in closing, closed or error */ + if (!(chan->state == CHANNEL_STATE_CLOSING || + chan->state == CHANNEL_STATE_CLOSED || + chan->state == CHANNEL_STATE_ERROR)) { + channel_close_for_error(chan); + } + } + + /* No need to mark for error because connection.c is about to do that */ +} + +/** Launch a new OR connection to addr:port and expect to + * handshake with an OR with identity digest id_digest. Optionally, + * pass in a pointer to a channel using this connection. + * + * If id_digest is me, do nothing. If we're already connected to it, + * return that connection. If the connect() is in progress, set the + * new conn's state to 'connecting' and return it. If connect() succeeds, + * call connection_tls_start_handshake() on it. + * + * This function is called from router_retry_connections(), for + * ORs connecting to ORs, and circuit_establish_circuit(), for + * OPs connecting to ORs. + * + * Return the launched conn, or NULL if it failed. + */ +or_connection_t * +connection_or_connect(const tor_addr_t *_addr, uint16_t port, + const char *id_digest, + channel_tls_t *chan) +{ + or_connection_t *conn; + const or_options_t *options = get_options(); + int socket_error = 0; + tor_addr_t addr; + + int r; + tor_addr_t proxy_addr; + uint16_t proxy_port; + int proxy_type; + + tor_assert(_addr); + tor_assert(id_digest); + tor_addr_copy(&addr, _addr); + + if (server_mode(options) && router_digest_is_me(id_digest)) { + log_info(LD_PROTOCOL,"Client asked me to connect to myself. Refusing."); + return NULL; + } + + conn = or_connection_new(CONN_TYPE_OR, tor_addr_family(&addr)); + + /* + * Set up conn so it's got all the data we need to remember for channels + * + * This stuff needs to happen before connection_or_init_conn_from_address() + * so connection_or_set_identity_digest() and such know where to look to + * keep the channel up to date. + */ + conn->chan = chan; + chan->conn = conn; + connection_or_init_conn_from_address(conn, &addr, port, id_digest, 1); + connection_or_change_state(conn, OR_CONN_STATE_CONNECTING); + control_event_or_conn_status(conn, OR_CONN_EVENT_LAUNCHED, 0); + + conn->is_outgoing = 1; + + /* If we are using a proxy server, find it and use it. */ + r = get_proxy_addrport(&proxy_addr, &proxy_port, &proxy_type, TO_CONN(conn)); + if (r == 0) { + conn->proxy_type = proxy_type; + if (proxy_type != PROXY_NONE) { + tor_addr_copy(&addr, &proxy_addr); + port = proxy_port; + conn->base_.proxy_state = PROXY_INFANT; + } + } else { + /* get_proxy_addrport() might fail if we have a Bridge line that + references a transport, but no ClientTransportPlugin lines + defining its transport proxy. If this is the case, let's try to + output a useful log message to the user. */ + const char *transport_name = + find_transport_name_by_bridge_addrport(&TO_CONN(conn)->addr, + TO_CONN(conn)->port); + + if (transport_name) { + log_warn(LD_GENERAL, "We were supposed to connect to bridge '%s' " + "using pluggable transport '%s', but we can't find a pluggable " + "transport proxy supporting '%s'. This can happen if you " + "haven't provided a ClientTransportPlugin line, or if " + "your pluggable transport proxy stopped running.", + fmt_addrport(&TO_CONN(conn)->addr, TO_CONN(conn)->port), + transport_name, transport_name); + } else { + log_warn(LD_GENERAL, "Tried to connect to '%s' through a proxy, but " + "the proxy address could not be found.", + fmt_addrport(&TO_CONN(conn)->addr, TO_CONN(conn)->port)); + } + + connection_free(TO_CONN(conn)); + return NULL; + } + + switch (connection_connect(TO_CONN(conn), conn->base_.address, + &addr, port, &socket_error)) { + case -1: + /* If the connection failed immediately, and we're using + * a proxy, our proxy is down. Don't blame the Tor server. */ + if (conn->base_.proxy_state == PROXY_INFANT) + entry_guard_register_connect_status(conn->identity_digest, + 0, 1, time(NULL)); + connection_or_connect_failed(conn, + errno_to_orconn_end_reason(socket_error), + tor_socket_strerror(socket_error)); + connection_free(TO_CONN(conn)); + return NULL; + case 0: + connection_watch_events(TO_CONN(conn), READ_EVENT | WRITE_EVENT); + /* writable indicates finish, readable indicates broken link, + error indicates broken link on windows */ + return conn; + /* case 1: fall through */ + } + + if (connection_or_finished_connecting(conn) < 0) { + /* already marked for close */ + return NULL; + } + return conn; +} + +/** Mark orconn for close and transition the associated channel, if any, to + * the closing state. + * + * It's safe to call this and connection_or_close_for_error() any time, and + * channel layer will treat it as a connection closing for reasons outside + * its control, like the remote end closing it. It can also be a local + * reason that's specific to connection_t/or_connection_t rather than + * the channel mechanism, such as expiration of old connections in + * run_connection_housekeeping(). If you want to close a channel_t + * from somewhere that logically works in terms of generic channels + * rather than connections, use channel_mark_for_close(); see also + * the comment on that function in channel.c. + */ + +void +connection_or_close_normally(or_connection_t *orconn, int flush) +{ + channel_t *chan = NULL; + + tor_assert(orconn); + if (flush) connection_mark_and_flush_internal(TO_CONN(orconn)); + else connection_mark_for_close_internal(TO_CONN(orconn)); + if (orconn->chan) { + chan = TLS_CHAN_TO_BASE(orconn->chan); + /* Don't transition if we're already in closing, closed or error */ + if (!(chan->state == CHANNEL_STATE_CLOSING || + chan->state == CHANNEL_STATE_CLOSED || + chan->state == CHANNEL_STATE_ERROR)) { + channel_close_from_lower_layer(chan); + } + } +} + +/** Mark orconn for close and transition the associated channel, if any, to + * the error state. + */ + +void +connection_or_close_for_error(or_connection_t *orconn, int flush) +{ + channel_t *chan = NULL; + + tor_assert(orconn); + if (flush) connection_mark_and_flush_internal(TO_CONN(orconn)); + else connection_mark_for_close_internal(TO_CONN(orconn)); + if (orconn->chan) { + chan = TLS_CHAN_TO_BASE(orconn->chan); + /* Don't transition if we're already in closing, closed or error */ + if (!(chan->state == CHANNEL_STATE_CLOSING || + chan->state == CHANNEL_STATE_CLOSED || + chan->state == CHANNEL_STATE_ERROR)) { + channel_close_for_error(chan); + } + } +} + +/** Begin the tls handshake with conn. receiving is 0 if + * we initiated the connection, else it's 1. + * + * Assign a new tls object to conn->tls, begin reading on conn, and + * pass conn to connection_tls_continue_handshake(). + * + * Return -1 if conn is broken, else return 0. + */ +MOCK_IMPL(int, +connection_tls_start_handshake,(or_connection_t *conn, int receiving)) +{ + channel_listener_t *chan_listener; + channel_t *chan; + + /* Incoming connections will need a new channel passed to the + * channel_tls_listener */ + if (receiving) { + /* It shouldn't already be set */ + tor_assert(!(conn->chan)); + chan_listener = channel_tls_get_listener(); + if (!chan_listener) { + chan_listener = channel_tls_start_listener(); + command_setup_listener(chan_listener); + } + chan = channel_tls_handle_incoming(conn); + channel_listener_queue_incoming(chan_listener, chan); + } + + connection_or_change_state(conn, OR_CONN_STATE_TLS_HANDSHAKING); + tor_assert(!conn->tls); + conn->tls = tor_tls_new(conn->base_.s, receiving); + if (!conn->tls) { + log_warn(LD_BUG,"tor_tls_new failed. Closing."); + return -1; + } + tor_tls_set_logged_address(conn->tls, // XXX client and relay? + escaped_safe_str(conn->base_.address)); + +#ifdef USE_BUFFEREVENTS + if (connection_type_uses_bufferevent(TO_CONN(conn))) { + const int filtering = get_options()->UseFilteringSSLBufferevents; + struct bufferevent *b = + tor_tls_init_bufferevent(conn->tls, conn->base_.bufev, conn->base_.s, + receiving, filtering); + if (!b) { + log_warn(LD_BUG,"tor_tls_init_bufferevent failed. Closing."); + return -1; + } + conn->base_.bufev = b; + if (conn->bucket_cfg) + tor_set_bufferevent_rate_limit(conn->base_.bufev, conn->bucket_cfg); + connection_enable_rate_limiting(TO_CONN(conn)); + + connection_configure_bufferevent_callbacks(TO_CONN(conn)); + bufferevent_setcb(b, + connection_handle_read_cb, + connection_handle_write_cb, + connection_or_handle_event_cb,/* overriding this one*/ + TO_CONN(conn)); + } +#endif + connection_start_reading(TO_CONN(conn)); + log_debug(LD_HANDSHAKE,"starting TLS handshake on fd "TOR_SOCKET_T_FORMAT, + conn->base_.s); + note_crypto_pk_op(receiving ? TLS_HANDSHAKE_S : TLS_HANDSHAKE_C); + + IF_HAS_BUFFEREVENT(TO_CONN(conn), { + /* ???? */; + }) ELSE_IF_NO_BUFFEREVENT { + if (connection_tls_continue_handshake(conn) < 0) + return -1; + } + return 0; +} + +/** Block all future attempts to renegotiate on 'conn' */ +void +connection_or_block_renegotiation(or_connection_t *conn) +{ + tor_tls_t *tls = conn->tls; + if (!tls) + return; + tor_tls_set_renegotiate_callback(tls, NULL, NULL); + tor_tls_block_renegotiation(tls); +} + +/** Invoked on the server side from inside tor_tls_read() when the server + * gets a successful TLS renegotiation from the client. */ +static void +connection_or_tls_renegotiated_cb(tor_tls_t *tls, void *_conn) +{ + or_connection_t *conn = _conn; + (void)tls; + + /* Don't invoke this again. */ + connection_or_block_renegotiation(conn); + + if (connection_tls_finish_handshake(conn) < 0) { + /* XXXX_TLS double-check that it's ok to do this from inside read. */ + /* XXXX_TLS double-check that this verifies certificates. */ + connection_or_close_for_error(conn, 0); + } +} + +/** Move forward with the tls handshake. If it finishes, hand + * conn to connection_tls_finish_handshake(). + * + * Return -1 if conn is broken, else return 0. + */ +int +connection_tls_continue_handshake(or_connection_t *conn) +{ + int result; + check_no_tls_errors(); + again: + if (conn->base_.state == OR_CONN_STATE_TLS_CLIENT_RENEGOTIATING) { + // log_notice(LD_OR, "Renegotiate with %p", conn->tls); + result = tor_tls_renegotiate(conn->tls); + // log_notice(LD_OR, "Result: %d", result); + } else { + tor_assert(conn->base_.state == OR_CONN_STATE_TLS_HANDSHAKING); + // log_notice(LD_OR, "Continue handshake with %p", conn->tls); + result = tor_tls_handshake(conn->tls); + // log_notice(LD_OR, "Result: %d", result); + } + switch (result) { + CASE_TOR_TLS_ERROR_ANY: + log_info(LD_OR,"tls error [%s]. breaking connection.", + tor_tls_err_to_string(result)); + return -1; + case TOR_TLS_DONE: + if (! tor_tls_used_v1_handshake(conn->tls)) { + if (!tor_tls_is_server(conn->tls)) { + if (conn->base_.state == OR_CONN_STATE_TLS_HANDSHAKING) { + if (tor_tls_received_v3_certificate(conn->tls)) { + log_info(LD_OR, "Client got a v3 cert! Moving on to v3 " + "handshake with ciphersuite %s", + tor_tls_get_ciphersuite_name(conn->tls)); + return connection_or_launch_v3_or_handshake(conn); + } else { + log_debug(LD_OR, "Done with initial SSL handshake (client-side)." + " Requesting renegotiation."); + connection_or_change_state(conn, + OR_CONN_STATE_TLS_CLIENT_RENEGOTIATING); + goto again; + } + } + // log_notice(LD_OR,"Done. state was %d.", conn->base_.state); + } else { + /* v2/v3 handshake, but not a client. */ + log_debug(LD_OR, "Done with initial SSL handshake (server-side). " + "Expecting renegotiation or VERSIONS cell"); + tor_tls_set_renegotiate_callback(conn->tls, + connection_or_tls_renegotiated_cb, + conn); + connection_or_change_state(conn, + OR_CONN_STATE_TLS_SERVER_RENEGOTIATING); + connection_stop_writing(TO_CONN(conn)); + connection_start_reading(TO_CONN(conn)); + return 0; + } + } + return connection_tls_finish_handshake(conn); + case TOR_TLS_WANTWRITE: + connection_start_writing(TO_CONN(conn)); + log_debug(LD_OR,"wanted write"); + return 0; + case TOR_TLS_WANTREAD: /* handshaking conns are *always* reading */ + log_debug(LD_OR,"wanted read"); + return 0; + case TOR_TLS_CLOSE: + log_info(LD_OR,"tls closed. breaking connection."); + return -1; + } + return 0; +} + +#ifdef USE_BUFFEREVENTS +static void +connection_or_handle_event_cb(struct bufferevent *bufev, short event, + void *arg) +{ + struct or_connection_t *conn = TO_OR_CONN(arg); + + /* XXXX cut-and-paste code; should become a function. */ + if (event & BEV_EVENT_CONNECTED) { + if (conn->base_.state == OR_CONN_STATE_TLS_HANDSHAKING) { + if (tor_tls_finish_handshake(conn->tls) < 0) { + log_warn(LD_OR, "Problem finishing handshake"); + connection_or_close_for_error(conn, 0); + return; + } + } + + if (! tor_tls_used_v1_handshake(conn->tls)) { + if (!tor_tls_is_server(conn->tls)) { + if (conn->base_.state == OR_CONN_STATE_TLS_HANDSHAKING) { + if (tor_tls_received_v3_certificate(conn->tls)) { + log_info(LD_OR, "Client got a v3 cert!"); + if (connection_or_launch_v3_or_handshake(conn) < 0) + connection_or_close_for_error(conn, 0); + return; + } else { + connection_or_change_state(conn, + OR_CONN_STATE_TLS_CLIENT_RENEGOTIATING); + tor_tls_unblock_renegotiation(conn->tls); + if (bufferevent_ssl_renegotiate(conn->base_.bufev)<0) { + log_warn(LD_OR, "Start_renegotiating went badly."); + connection_or_close_for_error(conn, 0); + } + tor_tls_unblock_renegotiation(conn->tls); + return; /* ???? */ + } + } + } else { + const int handshakes = tor_tls_get_num_server_handshakes(conn->tls); + + if (handshakes == 1) { + /* v2 or v3 handshake, as a server. Only got one handshake, so + * wait for the next one. */ + tor_tls_set_renegotiate_callback(conn->tls, + connection_or_tls_renegotiated_cb, + conn); + connection_or_change_state(conn, + OR_CONN_STATE_TLS_SERVER_RENEGOTIATING); + } else if (handshakes == 2) { + /* v2 handshake, as a server. Two handshakes happened already, + * so we treat renegotiation as done. + */ + connection_or_tls_renegotiated_cb(conn->tls, conn); + } else if (handshakes > 2) { + log_warn(LD_OR, "More than two handshakes done on connection. " + "Closing."); + connection_or_close_for_error(conn, 0); + } else { + log_warn(LD_BUG, "We were unexpectedly told that a connection " + "got %d handshakes. Closing.", handshakes); + connection_or_close_for_error(conn, 0); + } + return; + } + } + connection_watch_events(TO_CONN(conn), READ_EVENT|WRITE_EVENT); + if (connection_tls_finish_handshake(conn) < 0) + connection_or_close_for_error(conn, 0); /* ???? */ + return; + } + + if (event & BEV_EVENT_ERROR) { + unsigned long err; + while ((err = bufferevent_get_openssl_error(bufev))) { + tor_tls_log_one_error(conn->tls, err, LOG_WARN, LD_OR, + "handshaking (with bufferevent)"); + } + } + + connection_handle_event_cb(bufev, event, arg); +} +#endif + +/** Return 1 if we initiated this connection, or 0 if it started + * out as an incoming connection. + */ +int +connection_or_nonopen_was_started_here(or_connection_t *conn) +{ + tor_assert(conn->base_.type == CONN_TYPE_OR || + conn->base_.type == CONN_TYPE_EXT_OR); + if (!conn->tls) + return 1; /* it's still in proxy states or something */ + if (conn->handshake_state) + return conn->handshake_state->started_here; + return !tor_tls_is_server(conn->tls); +} + +/** Conn just completed its handshake. Return 0 if all is well, and + * return -1 if he is lying, broken, or otherwise something is wrong. + * + * If we initiated this connection (started_here is true), make sure + * the other side sent a correctly formed certificate. If I initiated the + * connection, make sure it's the right guy. + * + * Otherwise (if we _didn't_ initiate this connection), it's okay for + * the certificate to be weird or absent. + * + * If we return 0, and the certificate is as expected, write a hash of the + * identity key into digest_rcvd_out, which must have DIGEST_LEN + * space in it. + * If the certificate is invalid or missing on an incoming connection, + * we return 0 and set digest_rcvd_out to DIGEST_LEN NUL bytes. + * (If we return -1, the contents of this buffer are undefined.) + * + * As side effects, + * 1) Set conn->circ_id_type according to tor-spec.txt. + * 2) If we're an authdirserver and we initiated the connection: drop all + * descriptors that claim to be on that IP/port but that aren't + * this guy; and note that this guy is reachable. + * 3) If this is a bridge and we didn't configure its identity + * fingerprint, remember the keyid we just learned. + */ +static int +connection_or_check_valid_tls_handshake(or_connection_t *conn, + int started_here, + char *digest_rcvd_out) +{ + crypto_pk_t *identity_rcvd=NULL; + const or_options_t *options = get_options(); + int severity = server_mode(options) ? LOG_PROTOCOL_WARN : LOG_WARN; + const char *safe_address = + started_here ? conn->base_.address : + safe_str_client(conn->base_.address); + const char *conn_type = started_here ? "outgoing" : "incoming"; + int has_cert = 0; + + check_no_tls_errors(); + has_cert = tor_tls_peer_has_cert(conn->tls); + if (started_here && !has_cert) { + log_info(LD_HANDSHAKE,"Tried connecting to router at %s:%d, but it didn't " + "send a cert! Closing.", + safe_address, conn->base_.port); + return -1; + } else if (!has_cert) { + log_debug(LD_HANDSHAKE,"Got incoming connection with no certificate. " + "That's ok."); + } + check_no_tls_errors(); + + if (has_cert) { + int v = tor_tls_verify(started_here?severity:LOG_INFO, + conn->tls, &identity_rcvd); + if (started_here && v<0) { + log_fn(severity,LD_HANDSHAKE,"Tried connecting to router at %s:%d: It" + " has a cert but it's invalid. Closing.", + safe_address, conn->base_.port); + return -1; + } else if (v<0) { + log_info(LD_HANDSHAKE,"Incoming connection gave us an invalid cert " + "chain; ignoring."); + } else { + log_debug(LD_HANDSHAKE, + "The certificate seems to be valid on %s connection " + "with %s:%d", conn_type, safe_address, conn->base_.port); + } + check_no_tls_errors(); + } + + if (identity_rcvd) { + crypto_pk_get_digest(identity_rcvd, digest_rcvd_out); + } else { + memset(digest_rcvd_out, 0, DIGEST_LEN); + } + + tor_assert(conn->chan); + channel_set_circid_type(TLS_CHAN_TO_BASE(conn->chan), identity_rcvd, 1); + + crypto_pk_free(identity_rcvd); + + if (started_here) + return connection_or_client_learned_peer_id(conn, + (const uint8_t*)digest_rcvd_out); + + return 0; +} + +/** Called when we (as a connection initiator) have definitively, + * authenticatedly, learned that ID of the Tor instance on the other + * side of conn is peer_id. For v1 and v2 handshakes, + * this is right after we get a certificate chain in a TLS handshake + * or renegotiation. For v3 handshakes, this is right after we get a + * certificate chain in a CERTS cell. + * + * If we want any particular ID before, record the one we got. + * + * If we wanted an ID, but we didn't get it, log a warning and return -1. + * + * If we're testing reachability, remember what we learned. + * + * Return 0 on success, -1 on failure. + */ +int +connection_or_client_learned_peer_id(or_connection_t *conn, + const uint8_t *peer_id) +{ + const or_options_t *options = get_options(); + int severity = server_mode(options) ? LOG_PROTOCOL_WARN : LOG_WARN; + + if (tor_digest_is_zero(conn->identity_digest)) { + connection_or_set_identity_digest(conn, (const char*)peer_id); + tor_free(conn->nickname); + conn->nickname = tor_malloc(HEX_DIGEST_LEN+2); + conn->nickname[0] = '$'; + base16_encode(conn->nickname+1, HEX_DIGEST_LEN+1, + conn->identity_digest, DIGEST_LEN); + log_info(LD_HANDSHAKE, "Connected to router %s at %s:%d without knowing " + "its key. Hoping for the best.", + conn->nickname, conn->base_.address, conn->base_.port); + /* if it's a bridge and we didn't know its identity fingerprint, now + * we do -- remember it for future attempts. */ + learned_router_identity(&conn->base_.addr, conn->base_.port, + (const char*)peer_id); + } + + if (tor_memneq(peer_id, conn->identity_digest, DIGEST_LEN)) { + /* I was aiming for a particular digest. I didn't get it! */ + char seen[HEX_DIGEST_LEN+1]; + char expected[HEX_DIGEST_LEN+1]; + base16_encode(seen, sizeof(seen), (const char*)peer_id, DIGEST_LEN); + base16_encode(expected, sizeof(expected), conn->identity_digest, + DIGEST_LEN); + log_fn(severity, LD_HANDSHAKE, + "Tried connecting to router at %s:%d, but identity key was not " + "as expected: wanted %s but got %s.", + conn->base_.address, conn->base_.port, expected, seen); + entry_guard_register_connect_status(conn->identity_digest, 0, 1, + time(NULL)); + control_event_or_conn_status(conn, OR_CONN_EVENT_FAILED, + END_OR_CONN_REASON_OR_IDENTITY); + if (!authdir_mode_tests_reachability(options)) + control_event_bootstrap_problem( + "Unexpected identity in router certificate", + END_OR_CONN_REASON_OR_IDENTITY); + return -1; + } + if (authdir_mode_tests_reachability(options)) { + dirserv_orconn_tls_done(&conn->base_.addr, conn->base_.port, + (const char*)peer_id); + } + + return 0; +} + +/** Return when a client used this, for connection.c, since client_used + * is now one of the timestamps of channel_t */ + +time_t +connection_or_client_used(or_connection_t *conn) +{ + tor_assert(conn); + + if (conn->chan) { + return channel_when_last_client(TLS_CHAN_TO_BASE(conn->chan)); + } else return 0; +} + +/** The v1/v2 TLS handshake is finished. + * + * Make sure we are happy with the person we just handshaked with. + * + * If he initiated the connection, make sure he's not already connected, + * then initialize conn from the information in router. + * + * If all is successful, call circuit_n_conn_done() to handle events + * that have been pending on the base_.address), + tor_tls_get_ciphersuite_name(conn->tls)); + + directory_set_dirty(); + + if (connection_or_check_valid_tls_handshake(conn, started_here, + digest_rcvd) < 0) + return -1; + + circuit_build_times_network_is_live(get_circuit_build_times_mutable()); + + if (tor_tls_used_v1_handshake(conn->tls)) { + conn->link_proto = 1; + if (!started_here) { + connection_or_init_conn_from_address(conn, &conn->base_.addr, + conn->base_.port, digest_rcvd, 0); + } + tor_tls_block_renegotiation(conn->tls); + return connection_or_set_state_open(conn); + } else { + connection_or_change_state(conn, OR_CONN_STATE_OR_HANDSHAKING_V2); + if (connection_init_or_handshake_state(conn, started_here) < 0) + return -1; + if (!started_here) { + connection_or_init_conn_from_address(conn, &conn->base_.addr, + conn->base_.port, digest_rcvd, 0); + } + return connection_or_send_versions(conn, 0); + } +} + +/** + * Called as client when initial TLS handshake is done, and we notice + * that we got a v3-handshake signalling certificate from the server. + * Set up structures, do bookkeeping, and send the versions cell. + * Return 0 on success and -1 on failure. + */ +static int +connection_or_launch_v3_or_handshake(or_connection_t *conn) +{ + tor_assert(connection_or_nonopen_was_started_here(conn)); + tor_assert(tor_tls_received_v3_certificate(conn->tls)); + + circuit_build_times_network_is_live(get_circuit_build_times_mutable()); + + connection_or_change_state(conn, OR_CONN_STATE_OR_HANDSHAKING_V3); + if (connection_init_or_handshake_state(conn, 1) < 0) + return -1; + + return connection_or_send_versions(conn, 1); +} + +/** Allocate a new connection handshake state for the connection + * conn. Return 0 on success, -1 on failure. */ +int +connection_init_or_handshake_state(or_connection_t *conn, int started_here) +{ + or_handshake_state_t *s; + if (conn->handshake_state) { + log_warn(LD_BUG, "Duplicate call to connection_init_or_handshake_state!"); + return 0; + } + s = conn->handshake_state = tor_malloc_zero(sizeof(or_handshake_state_t)); + s->started_here = started_here ? 1 : 0; + s->digest_sent_data = 1; + s->digest_received_data = 1; + return 0; +} + +/** Free all storage held by state. */ +void +or_handshake_state_free(or_handshake_state_t *state) +{ + if (!state) + return; + crypto_digest_free(state->digest_sent); + crypto_digest_free(state->digest_received); + tor_cert_free(state->auth_cert); + tor_cert_free(state->id_cert); + memwipe(state, 0xBE, sizeof(or_handshake_state_t)); + tor_free(state); +} + +/** + * Remember that cell has been transmitted (if incoming is + * false) or received (if incoming is true) during a V3 handshake using + * state. + * + * (We don't record the cell, but we keep a digest of everything sent or + * received during the v3 handshake, and the client signs it in an + * authenticate cell.) + */ +void +or_handshake_state_record_cell(or_connection_t *conn, + or_handshake_state_t *state, + const cell_t *cell, + int incoming) +{ + size_t cell_network_size = get_cell_network_size(conn->wide_circ_ids); + crypto_digest_t *d, **dptr; + packed_cell_t packed; + if (incoming) { + if (!state->digest_received_data) + return; + } else { + if (!state->digest_sent_data) + return; + } + if (!incoming) { + log_warn(LD_BUG, "We shouldn't be sending any non-variable-length cells " + "while making a handshake digest. But we think we are sending " + "one with type %d.", (int)cell->command); + } + dptr = incoming ? &state->digest_received : &state->digest_sent; + if (! *dptr) + *dptr = crypto_digest256_new(DIGEST_SHA256); + + d = *dptr; + /* Re-packing like this is a little inefficient, but we don't have to do + this very often at all. */ + cell_pack(&packed, cell, conn->wide_circ_ids); + crypto_digest_add_bytes(d, packed.body, cell_network_size); + memwipe(&packed, 0, sizeof(packed)); +} + +/** Remember that a variable-length cell has been transmitted (if + * incoming is false) or received (if incoming is true) during a + * V3 handshake using state. + * + * (We don't record the cell, but we keep a digest of everything sent or + * received during the v3 handshake, and the client signs it in an + * authenticate cell.) + */ +void +or_handshake_state_record_var_cell(or_connection_t *conn, + or_handshake_state_t *state, + const var_cell_t *cell, + int incoming) +{ + crypto_digest_t *d, **dptr; + int n; + char buf[VAR_CELL_MAX_HEADER_SIZE]; + if (incoming) { + if (!state->digest_received_data) + return; + } else { + if (!state->digest_sent_data) + return; + } + dptr = incoming ? &state->digest_received : &state->digest_sent; + if (! *dptr) + *dptr = crypto_digest256_new(DIGEST_SHA256); + + d = *dptr; + + n = var_cell_pack_header(cell, buf, conn->wide_circ_ids); + crypto_digest_add_bytes(d, buf, n); + crypto_digest_add_bytes(d, (const char *)cell->payload, cell->payload_len); + + memwipe(buf, 0, sizeof(buf)); +} + +/** Set conn's state to OR_CONN_STATE_OPEN, and tell other subsystems + * as appropriate. Called when we are done with all TLS and OR handshaking. + */ +int +connection_or_set_state_open(or_connection_t *conn) +{ + connection_or_change_state(conn, OR_CONN_STATE_OPEN); + control_event_or_conn_status(conn, OR_CONN_EVENT_CONNECTED, 0); + + or_handshake_state_free(conn->handshake_state); + conn->handshake_state = NULL; + IF_HAS_BUFFEREVENT(TO_CONN(conn), { + connection_watch_events(TO_CONN(conn), READ_EVENT|WRITE_EVENT); + }) ELSE_IF_NO_BUFFEREVENT { + connection_start_reading(TO_CONN(conn)); + } + + return 0; +} + +/** Pack cell into wire-format, and write it onto conn's outbuf. + * For cells that use or affect a circuit, this should only be called by + * connection_or_flush_from_first_active_circuit(). + */ +void +connection_or_write_cell_to_buf(const cell_t *cell, or_connection_t *conn) +{ + packed_cell_t networkcell; + size_t cell_network_size = get_cell_network_size(conn->wide_circ_ids); + + tor_assert(cell); + tor_assert(conn); + + cell_pack(&networkcell, cell, conn->wide_circ_ids); + + connection_write_to_buf(networkcell.body, cell_network_size, TO_CONN(conn)); + + /* Touch the channel's active timestamp if there is one */ + if (conn->chan) + channel_timestamp_active(TLS_CHAN_TO_BASE(conn->chan)); + + if (conn->base_.state == OR_CONN_STATE_OR_HANDSHAKING_V3) + or_handshake_state_record_cell(conn, conn->handshake_state, cell, 0); + + if (cell->command != CELL_PADDING) + conn->timestamp_last_added_nonpadding = approx_time(); +} + +/** Pack a variable-length cell into wire-format, and write it onto + * conn's outbuf. Right now, this DOES NOT support cells that + * affect a circuit. + */ +void +connection_or_write_var_cell_to_buf(const var_cell_t *cell, + or_connection_t *conn) +{ + int n; + char hdr[VAR_CELL_MAX_HEADER_SIZE]; + tor_assert(cell); + tor_assert(conn); + n = var_cell_pack_header(cell, hdr, conn->wide_circ_ids); + connection_write_to_buf(hdr, n, TO_CONN(conn)); + connection_write_to_buf((char*)cell->payload, + cell->payload_len, TO_CONN(conn)); + if (conn->base_.state == OR_CONN_STATE_OR_HANDSHAKING_V3) + or_handshake_state_record_var_cell(conn, conn->handshake_state, cell, 0); + if (cell->command != CELL_PADDING) + conn->timestamp_last_added_nonpadding = approx_time(); + + /* Touch the channel's active timestamp if there is one */ + if (conn->chan) + channel_timestamp_active(TLS_CHAN_TO_BASE(conn->chan)); +} + +/** See whether there's a variable-length cell waiting on or_conn's + * inbuf. Return values as for fetch_var_cell_from_buf(). */ +static int +connection_fetch_var_cell_from_buf(or_connection_t *or_conn, var_cell_t **out) +{ + connection_t *conn = TO_CONN(or_conn); + IF_HAS_BUFFEREVENT(conn, { + struct evbuffer *input = bufferevent_get_input(conn->bufev); + return fetch_var_cell_from_evbuffer(input, out, or_conn->link_proto); + }) ELSE_IF_NO_BUFFEREVENT { + return fetch_var_cell_from_buf(conn->inbuf, out, or_conn->link_proto); + } +} + +/** Process cells from conn's inbuf. + * + * Loop: while inbuf contains a cell, pull it off the inbuf, unpack it, + * and hand it to command_process_cell(). + * + * Always return 0. + */ +static int +connection_or_process_cells_from_inbuf(or_connection_t *conn) +{ + var_cell_t *var_cell; + + while (1) { + log_debug(LD_OR, + TOR_SOCKET_T_FORMAT": starting, inbuf_datalen %d " + "(%d pending in tls object).", + conn->base_.s,(int)connection_get_inbuf_len(TO_CONN(conn)), + tor_tls_get_pending_bytes(conn->tls)); + if (connection_fetch_var_cell_from_buf(conn, &var_cell)) { + if (!var_cell) + return 0; /* not yet. */ + + /* Touch the channel's active timestamp if there is one */ + if (conn->chan) + channel_timestamp_active(TLS_CHAN_TO_BASE(conn->chan)); + + circuit_build_times_network_is_live(get_circuit_build_times_mutable()); + channel_tls_handle_var_cell(var_cell, conn); + var_cell_free(var_cell); + } else { + const int wide_circ_ids = conn->wide_circ_ids; + size_t cell_network_size = get_cell_network_size(conn->wide_circ_ids); + char buf[CELL_MAX_NETWORK_SIZE]; + cell_t cell; + if (connection_get_inbuf_len(TO_CONN(conn)) + < cell_network_size) /* whole response available? */ + return 0; /* not yet */ + + /* Touch the channel's active timestamp if there is one */ + if (conn->chan) + channel_timestamp_active(TLS_CHAN_TO_BASE(conn->chan)); + + circuit_build_times_network_is_live(get_circuit_build_times_mutable()); + connection_fetch_from_buf(buf, cell_network_size, TO_CONN(conn)); + + /* retrieve cell info from buf (create the host-order struct from the + * network-order string) */ + cell_unpack(&cell, buf, wide_circ_ids); + + channel_tls_handle_cell(&cell, conn); + } + } +} + +/** Array of recognized link protocol versions. */ +static const uint16_t or_protocol_versions[] = { 1, 2, 3, 4 }; +/** Number of versions in or_protocol_versions. */ +static const int n_or_protocol_versions = + (int)( sizeof(or_protocol_versions)/sizeof(uint16_t) ); + +/** Return true iff v is a link protocol version that this Tor + * implementation believes it can support. */ +int +is_or_protocol_version_known(uint16_t v) +{ + int i; + for (i = 0; i < n_or_protocol_versions; ++i) { + if (or_protocol_versions[i] == v) + return 1; + } + return 0; +} + +/** Send a VERSIONS cell on conn, telling the other host about the + * link protocol versions that this Tor can support. + * + * If v3_plus, this is part of a V3 protocol handshake, so only + * allow protocol version v3 or later. If not v3_plus, this is + * not part of a v3 protocol handshake, so don't allow protocol v3 or + * later. + **/ +int +connection_or_send_versions(or_connection_t *conn, int v3_plus) +{ + var_cell_t *cell; + int i; + int n_versions = 0; + const int min_version = v3_plus ? 3 : 0; + const int max_version = v3_plus ? UINT16_MAX : 2; + tor_assert(conn->handshake_state && + !conn->handshake_state->sent_versions_at); + cell = var_cell_new(n_or_protocol_versions * 2); + cell->command = CELL_VERSIONS; + for (i = 0; i < n_or_protocol_versions; ++i) { + uint16_t v = or_protocol_versions[i]; + if (v < min_version || v > max_version) + continue; + set_uint16(cell->payload+(2*n_versions), htons(v)); + ++n_versions; + } + cell->payload_len = n_versions * 2; + + connection_or_write_var_cell_to_buf(cell, conn); + conn->handshake_state->sent_versions_at = time(NULL); + + var_cell_free(cell); + return 0; +} + +/** Send a NETINFO cell on conn, telling the other server what we know + * about their address, our address, and the current time. */ +int +connection_or_send_netinfo(or_connection_t *conn) +{ + cell_t cell; + time_t now = time(NULL); + const routerinfo_t *me; + int len; + uint8_t *out; + + tor_assert(conn->handshake_state); + + if (conn->handshake_state->sent_netinfo) { + log_warn(LD_BUG, "Attempted to send an extra netinfo cell on a connection " + "where we already sent one."); + return 0; + } + + memset(&cell, 0, sizeof(cell_t)); + cell.command = CELL_NETINFO; + + /* Timestamp, if we're a relay. */ + if (public_server_mode(get_options()) || ! conn->is_outgoing) + set_uint32(cell.payload, htonl((uint32_t)now)); + + /* Their address. */ + out = cell.payload + 4; + /* We use &conn->real_addr below, unless it hasn't yet been set. If it + * hasn't yet been set, we know that base_.addr hasn't been tampered with + * yet either. */ + len = append_address_to_payload(out, !tor_addr_is_null(&conn->real_addr) + ? &conn->real_addr : &conn->base_.addr); + if (len<0) + return -1; + out += len; + + /* My address -- only include it if I'm a public relay, or if I'm a + * bridge and this is an incoming connection. If I'm a bridge and this + * is an outgoing connection, act like a normal client and omit it. */ + if ((public_server_mode(get_options()) || !conn->is_outgoing) && + (me = router_get_my_routerinfo())) { + tor_addr_t my_addr; + *out++ = 1 + !tor_addr_is_null(&me->ipv6_addr); + + tor_addr_from_ipv4h(&my_addr, me->addr); + len = append_address_to_payload(out, &my_addr); + if (len < 0) + return -1; + out += len; + + if (!tor_addr_is_null(&me->ipv6_addr)) { + len = append_address_to_payload(out, &me->ipv6_addr); + if (len < 0) + return -1; + } + } else { + *out = 0; + } + + conn->handshake_state->digest_sent_data = 0; + conn->handshake_state->sent_netinfo = 1; + connection_or_write_cell_to_buf(&cell, conn); + + return 0; +} + +/** Send a CERTS cell on the connection conn. Return 0 on success, -1 + * on failure. */ +int +connection_or_send_certs_cell(or_connection_t *conn) +{ + const tor_cert_t *link_cert = NULL, *id_cert = NULL; + const uint8_t *link_encoded = NULL, *id_encoded = NULL; + size_t link_len, id_len; + var_cell_t *cell; + size_t cell_len; + ssize_t pos; + int server_mode; + + tor_assert(conn->base_.state == OR_CONN_STATE_OR_HANDSHAKING_V3); + + if (! conn->handshake_state) + return -1; + server_mode = ! conn->handshake_state->started_here; + if (tor_tls_get_my_certs(server_mode, &link_cert, &id_cert) < 0) + return -1; + tor_cert_get_der(link_cert, &link_encoded, &link_len); + tor_cert_get_der(id_cert, &id_encoded, &id_len); + + cell_len = 1 /* 1 byte: num certs in cell */ + + 2 * ( 1 + 2 ) /* For each cert: 1 byte for type, 2 for length */ + + link_len + id_len; + cell = var_cell_new(cell_len); + cell->command = CELL_CERTS; + cell->payload[0] = 2; + pos = 1; + + if (server_mode) + cell->payload[pos] = OR_CERT_TYPE_TLS_LINK; /* Link cert */ + else + cell->payload[pos] = OR_CERT_TYPE_AUTH_1024; /* client authentication */ + set_uint16(&cell->payload[pos+1], htons(link_len)); + memcpy(&cell->payload[pos+3], link_encoded, link_len); + pos += 3 + link_len; + + cell->payload[pos] = OR_CERT_TYPE_ID_1024; /* ID cert */ + set_uint16(&cell->payload[pos+1], htons(id_len)); + memcpy(&cell->payload[pos+3], id_encoded, id_len); + pos += 3 + id_len; + + tor_assert(pos == (int)cell_len); /* Otherwise we just smashed the heap */ + + connection_or_write_var_cell_to_buf(cell, conn); + var_cell_free(cell); + + return 0; +} + +/** Send an AUTH_CHALLENGE cell on the connection conn. Return 0 + * on success, -1 on failure. */ +int +connection_or_send_auth_challenge_cell(or_connection_t *conn) +{ + var_cell_t *cell; + uint8_t *cp; + uint8_t challenge[OR_AUTH_CHALLENGE_LEN]; + tor_assert(conn->base_.state == OR_CONN_STATE_OR_HANDSHAKING_V3); + + if (! conn->handshake_state) + return -1; + + if (crypto_rand((char*)challenge, OR_AUTH_CHALLENGE_LEN) < 0) + return -1; + cell = var_cell_new(OR_AUTH_CHALLENGE_LEN + 4); + cell->command = CELL_AUTH_CHALLENGE; + memcpy(cell->payload, challenge, OR_AUTH_CHALLENGE_LEN); + cp = cell->payload + OR_AUTH_CHALLENGE_LEN; + set_uint16(cp, htons(1)); /* We recognize one authentication type. */ + set_uint16(cp+2, htons(AUTHTYPE_RSA_SHA256_TLSSECRET)); + + connection_or_write_var_cell_to_buf(cell, conn); + var_cell_free(cell); + memwipe(challenge, 0, sizeof(challenge)); + + return 0; +} + +/** Compute the main body of an AUTHENTICATE cell that a client can use + * to authenticate itself on a v3 handshake for conn. Write it to the + * outlen-byte buffer at out. + * + * If server is true, only calculate the first + * V3_AUTH_FIXED_PART_LEN bytes -- the part of the authenticator that's + * determined by the rest of the handshake, and which match the provided value + * exactly. + * + * If server is false and signing_key is NULL, calculate the + * first V3_AUTH_BODY_LEN bytes of the authenticator (that is, everything + * that should be signed), but don't actually sign it. + * + * If server is false and signing_key is provided, calculate the + * entire authenticator, signed with signing_key. + * + * Return the length of the cell body on success, and -1 on failure. + */ +int +connection_or_compute_authenticate_cell_body(or_connection_t *conn, + uint8_t *out, size_t outlen, + crypto_pk_t *signing_key, + int server) +{ + uint8_t *ptr; + + /* assert state is reasonable XXXX */ + + if (outlen < V3_AUTH_FIXED_PART_LEN || + (!server && outlen < V3_AUTH_BODY_LEN)) + return -1; + + ptr = out; + + /* Type: 8 bytes. */ + memcpy(ptr, "AUTH0001", 8); + ptr += 8; + + { + const tor_cert_t *id_cert=NULL, *link_cert=NULL; + const digests_t *my_digests, *their_digests; + const uint8_t *my_id, *their_id, *client_id, *server_id; + if (tor_tls_get_my_certs(server, &link_cert, &id_cert)) + return -1; + my_digests = tor_cert_get_id_digests(id_cert); + their_digests = tor_cert_get_id_digests(conn->handshake_state->id_cert); + tor_assert(my_digests); + tor_assert(their_digests); + my_id = (uint8_t*)my_digests->d[DIGEST_SHA256]; + their_id = (uint8_t*)their_digests->d[DIGEST_SHA256]; + + client_id = server ? their_id : my_id; + server_id = server ? my_id : their_id; + + /* Client ID digest: 32 octets. */ + memcpy(ptr, client_id, 32); + ptr += 32; + + /* Server ID digest: 32 octets. */ + memcpy(ptr, server_id, 32); + ptr += 32; + } + + { + crypto_digest_t *server_d, *client_d; + if (server) { + server_d = conn->handshake_state->digest_sent; + client_d = conn->handshake_state->digest_received; + } else { + client_d = conn->handshake_state->digest_sent; + server_d = conn->handshake_state->digest_received; + } + + /* Server log digest : 32 octets */ + crypto_digest_get_digest(server_d, (char*)ptr, 32); + ptr += 32; + + /* Client log digest : 32 octets */ + crypto_digest_get_digest(client_d, (char*)ptr, 32); + ptr += 32; + } + + { + /* Digest of cert used on TLS link : 32 octets. */ + const tor_cert_t *cert = NULL; + tor_cert_t *freecert = NULL; + if (server) { + tor_tls_get_my_certs(1, &cert, NULL); + } else { + freecert = tor_tls_get_peer_cert(conn->tls); + cert = freecert; + } + if (!cert) + return -1; + memcpy(ptr, tor_cert_get_cert_digests(cert)->d[DIGEST_SHA256], 32); + + if (freecert) + tor_cert_free(freecert); + ptr += 32; + } + + /* HMAC of clientrandom and serverrandom using master key : 32 octets */ + tor_tls_get_tlssecrets(conn->tls, ptr); + ptr += 32; + + tor_assert(ptr - out == V3_AUTH_FIXED_PART_LEN); + + if (server) + return V3_AUTH_FIXED_PART_LEN; // ptr-out + + /* 8 octets were reserved for the current time, but we're trying to get out + * of the habit of sending time around willynilly. Fortunately, nothing + * checks it. That's followed by 16 bytes of nonce. */ + crypto_rand((char*)ptr, 24); + ptr += 24; + + tor_assert(ptr - out == V3_AUTH_BODY_LEN); + + if (!signing_key) + return V3_AUTH_BODY_LEN; // ptr - out + + { + int siglen; + char d[32]; + crypto_digest256(d, (char*)out, ptr-out, DIGEST_SHA256); + siglen = crypto_pk_private_sign(signing_key, + (char*)ptr, outlen - (ptr-out), + d, 32); + if (siglen < 0) + return -1; + + ptr += siglen; + tor_assert(ptr <= out+outlen); + return (int)(ptr - out); + } +} + +/** Send an AUTHENTICATE cell on the connection conn. Return 0 on + * success, -1 on failure */ +int +connection_or_send_authenticate_cell(or_connection_t *conn, int authtype) +{ + var_cell_t *cell; + crypto_pk_t *pk = tor_tls_get_my_client_auth_key(); + int authlen; + size_t cell_maxlen; + /* XXXX make sure we're actually supposed to send this! */ + + if (!pk) { + log_warn(LD_BUG, "Can't compute authenticate cell: no client auth key"); + return -1; + } + if (authtype != AUTHTYPE_RSA_SHA256_TLSSECRET) { + log_warn(LD_BUG, "Tried to send authenticate cell with unknown " + "authentication type %d", authtype); + return -1; + } + + cell_maxlen = 4 + /* overhead */ + V3_AUTH_BODY_LEN + /* Authentication body */ + crypto_pk_keysize(pk) + /* Max signature length */ + 16 /* add a few extra bytes just in case. */; + + cell = var_cell_new(cell_maxlen); + cell->command = CELL_AUTHENTICATE; + set_uint16(cell->payload, htons(AUTHTYPE_RSA_SHA256_TLSSECRET)); + /* skip over length ; we don't know that yet. */ + + authlen = connection_or_compute_authenticate_cell_body(conn, + cell->payload+4, + cell_maxlen-4, + pk, + 0 /* not server */); + if (authlen < 0) { + log_warn(LD_BUG, "Unable to compute authenticate cell!"); + var_cell_free(cell); + return -1; + } + tor_assert(authlen + 4 <= cell->payload_len); + set_uint16(cell->payload+2, htons(authlen)); + cell->payload_len = authlen + 4; + + connection_or_write_var_cell_to_buf(cell, conn); + var_cell_free(cell); + + return 0; +} + diff --git a/src/tor/connection_or.h b/src/tor/connection_or.h new file mode 100644 index 0000000..8d93028 --- /dev/null +++ b/src/tor/connection_or.h @@ -0,0 +1,100 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file connection_or.h + * \brief Header file for connection_or.c. + **/ + +#ifndef TOR_CONNECTION_OR_H +#define TOR_CONNECTION_OR_H + +void connection_or_remove_from_identity_map(or_connection_t *conn); +void connection_or_clear_identity_map(void); +void clear_broken_connection_map(int disable); +or_connection_t *connection_or_get_for_extend(const char *digest, + const tor_addr_t *target_addr, + const char **msg_out, + int *launch_out); +void connection_or_set_bad_connections(const char *digest, int force); + +void connection_or_block_renegotiation(or_connection_t *conn); +int connection_or_reached_eof(or_connection_t *conn); +int connection_or_process_inbuf(or_connection_t *conn); +int connection_or_flushed_some(or_connection_t *conn); +int connection_or_finished_flushing(or_connection_t *conn); +int connection_or_finished_connecting(or_connection_t *conn); +void connection_or_about_to_close(or_connection_t *conn); +int connection_or_digest_is_known_relay(const char *id_digest); +void connection_or_update_token_buckets(smartlist_t *conns, + const or_options_t *options); + +void connection_or_connect_failed(or_connection_t *conn, + int reason, const char *msg); +void connection_or_notify_error(or_connection_t *conn, + int reason, const char *msg); +or_connection_t *connection_or_connect(const tor_addr_t *addr, uint16_t port, + const char *id_digest, + channel_tls_t *chan); + +void connection_or_close_normally(or_connection_t *orconn, int flush); +void connection_or_close_for_error(or_connection_t *orconn, int flush); + +void connection_or_report_broken_states(int severity, int domain); + +MOCK_DECL(int,connection_tls_start_handshake,(or_connection_t *conn, + int receiving)); +int connection_tls_continue_handshake(or_connection_t *conn); + +int connection_init_or_handshake_state(or_connection_t *conn, + int started_here); +void connection_or_init_conn_from_address(or_connection_t *conn, + const tor_addr_t *addr, + uint16_t port, + const char *id_digest, + int started_here); +int connection_or_client_learned_peer_id(or_connection_t *conn, + const uint8_t *peer_id); +time_t connection_or_client_used(or_connection_t *conn); +int connection_or_get_num_circuits(or_connection_t *conn); +void or_handshake_state_free(or_handshake_state_t *state); +void or_handshake_state_record_cell(or_connection_t *conn, + or_handshake_state_t *state, + const cell_t *cell, + int incoming); +void or_handshake_state_record_var_cell(or_connection_t *conn, + or_handshake_state_t *state, + const var_cell_t *cell, + int incoming); + +int connection_or_set_state_open(or_connection_t *conn); +void connection_or_write_cell_to_buf(const cell_t *cell, + or_connection_t *conn); +void connection_or_write_var_cell_to_buf(const var_cell_t *cell, + or_connection_t *conn); +int connection_or_send_versions(or_connection_t *conn, int v3_plus); +int connection_or_send_netinfo(or_connection_t *conn); +int connection_or_send_certs_cell(or_connection_t *conn); +int connection_or_send_auth_challenge_cell(or_connection_t *conn); +int connection_or_compute_authenticate_cell_body(or_connection_t *conn, + uint8_t *out, size_t outlen, + crypto_pk_t *signing_key, + int server); +int connection_or_send_authenticate_cell(or_connection_t *conn, int type); + +int is_or_protocol_version_known(uint16_t version); + +void cell_pack(packed_cell_t *dest, const cell_t *src, int wide_circ_ids); +int var_cell_pack_header(const var_cell_t *cell, char *hdr_out, + int wide_circ_ids); +var_cell_t *var_cell_new(uint16_t payload_len); +void var_cell_free(var_cell_t *cell); + +/** DOCDOC */ +#define MIN_LINK_PROTO_FOR_WIDE_CIRC_IDS 4 + +#endif + diff --git a/src/tor/container.c b/src/tor/container.c new file mode 100644 index 0000000..eee8591 --- /dev/null +++ b/src/tor/container.c @@ -0,0 +1,1557 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file container.c + * \brief Implements a smartlist (a resizable array) along + * with helper functions to use smartlists. Also includes + * hash table implementations of a string-to-void* map, and of + * a digest-to-void* map. + **/ + +#include "tor_compat.h" +#include "tor_util.h" +#include "torlog.h" +#include "container.h" +#include "crypto.h" + +#include +#include +#include + +#include "ht.h" + +/** All newly allocated smartlists have this capacity. */ +#define SMARTLIST_DEFAULT_CAPACITY 16 + +/** Allocate and return an empty smartlist. + */ +smartlist_t * +smartlist_new(void) +{ + smartlist_t *sl = tor_malloc(sizeof(smartlist_t)); + sl->num_used = 0; + sl->capacity = SMARTLIST_DEFAULT_CAPACITY; + sl->list = tor_malloc(sizeof(void *) * sl->capacity); + return sl; +} + +/** Deallocate a smartlist. Does not release storage associated with the + * list's elements. + */ +void +smartlist_free(smartlist_t *sl) +{ + if (!sl) + return; + tor_free(sl->list); + tor_free(sl); +} + +/** Remove all elements from the list. + */ +void +smartlist_clear(smartlist_t *sl) +{ + sl->num_used = 0; +} + +/** Make sure that sl can hold at least size entries. */ +static INLINE void +smartlist_ensure_capacity(smartlist_t *sl, int size) +{ +#if SIZEOF_SIZE_T > SIZEOF_INT +#define MAX_CAPACITY (INT_MAX) +#else +#define MAX_CAPACITY (int)((SIZE_MAX / (sizeof(void*)))) +#endif + if (size > sl->capacity) { + int higher = sl->capacity; + if (PREDICT_UNLIKELY(size > MAX_CAPACITY/2)) { + tor_assert(size <= MAX_CAPACITY); + higher = MAX_CAPACITY; + } else { + while (size > higher) + higher *= 2; + } + sl->capacity = higher; + sl->list = tor_realloc(sl->list, sizeof(void*)*((size_t)sl->capacity)); + } +} + +/** Append element to the end of the list. */ +void +smartlist_add(smartlist_t *sl, void *element) +{ + smartlist_ensure_capacity(sl, sl->num_used+1); + sl->list[sl->num_used++] = element; +} + +/** Append each element from S2 to the end of S1. */ +void +smartlist_add_all(smartlist_t *s1, const smartlist_t *s2) +{ + int new_size = s1->num_used + s2->num_used; + tor_assert(new_size >= s1->num_used); /* check for overflow. */ + smartlist_ensure_capacity(s1, new_size); + memcpy(s1->list + s1->num_used, s2->list, s2->num_used*sizeof(void*)); + s1->num_used = new_size; +} + +/** Remove all elements E from sl such that E==element. Preserve + * the order of any elements before E, but elements after E can be + * rearranged. + */ +void +smartlist_remove(smartlist_t *sl, const void *element) +{ + int i; + if (element == NULL) + return; + for (i=0; i < sl->num_used; i++) + if (sl->list[i] == element) { + sl->list[i] = sl->list[--sl->num_used]; /* swap with the end */ + i--; /* so we process the new i'th element */ + } +} + +/** If sl is nonempty, remove and return the final element. Otherwise, + * return NULL. */ +void * +smartlist_pop_last(smartlist_t *sl) +{ + tor_assert(sl); + if (sl->num_used) + return sl->list[--sl->num_used]; + else + return NULL; +} + +/** Reverse the order of the items in sl. */ +void +smartlist_reverse(smartlist_t *sl) +{ + int i, j; + void *tmp; + tor_assert(sl); + for (i = 0, j = sl->num_used-1; i < j; ++i, --j) { + tmp = sl->list[i]; + sl->list[i] = sl->list[j]; + sl->list[j] = tmp; + } +} + +/** If there are any strings in sl equal to element, remove and free them. + * Does not preserve order. */ +void +smartlist_string_remove(smartlist_t *sl, const char *element) +{ + int i; + tor_assert(sl); + tor_assert(element); + for (i = 0; i < sl->num_used; ++i) { + if (!strcmp(element, sl->list[i])) { + tor_free(sl->list[i]); + sl->list[i] = sl->list[--sl->num_used]; /* swap with the end */ + i--; /* so we process the new i'th element */ + } + } +} + +/** Return true iff some element E of sl has E==element. + */ +int +smartlist_contains(const smartlist_t *sl, const void *element) +{ + int i; + for (i=0; i < sl->num_used; i++) + if (sl->list[i] == element) + return 1; + return 0; +} + +/** Return true iff sl has some element E such that + * !strcmp(E,element) + */ +int +smartlist_contains_string(const smartlist_t *sl, const char *element) +{ + int i; + if (!sl) return 0; + for (i=0; i < sl->num_used; i++) + if (strcmp((const char*)sl->list[i],element)==0) + return 1; + return 0; +} + +/** If element is equal to an element of sl, return that + * element's index. Otherwise, return -1. */ +int +smartlist_string_pos(const smartlist_t *sl, const char *element) +{ + int i; + if (!sl) return -1; + for (i=0; i < sl->num_used; i++) + if (strcmp((const char*)sl->list[i],element)==0) + return i; + return -1; +} + +/** Return true iff sl has some element E such that + * !strcasecmp(E,element) + */ +int +smartlist_contains_string_case(const smartlist_t *sl, const char *element) +{ + int i; + if (!sl) return 0; + for (i=0; i < sl->num_used; i++) + if (strcasecmp((const char*)sl->list[i],element)==0) + return 1; + return 0; +} + +/** Return true iff sl has some element E such that E is equal + * to the decimal encoding of num. + */ +int +smartlist_contains_int_as_string(const smartlist_t *sl, int num) +{ + char buf[32]; /* long enough for 64-bit int, and then some. */ + tor_snprintf(buf,sizeof(buf),"%d", num); + return smartlist_contains_string(sl, buf); +} + +/** Return true iff the two lists contain the same strings in the same + * order, or if they are both NULL. */ +int +smartlist_strings_eq(const smartlist_t *sl1, const smartlist_t *sl2) +{ + if (sl1 == NULL) + return sl2 == NULL; + if (sl2 == NULL) + return 0; + if (smartlist_len(sl1) != smartlist_len(sl2)) + return 0; + SMARTLIST_FOREACH(sl1, const char *, cp1, { + const char *cp2 = smartlist_get(sl2, cp1_sl_idx); + if (strcmp(cp1, cp2)) + return 0; + }); + return 1; +} + +/** Return true iff the two lists contain the same int pointer values in + * the same order, or if they are both NULL. */ +int +smartlist_ints_eq(const smartlist_t *sl1, const smartlist_t *sl2) +{ + if (sl1 == NULL) + return sl2 == NULL; + if (sl2 == NULL) + return 0; + if (smartlist_len(sl1) != smartlist_len(sl2)) + return 0; + SMARTLIST_FOREACH(sl1, int *, cp1, { + int *cp2 = smartlist_get(sl2, cp1_sl_idx); + if (*cp1 != *cp2) + return 0; + }); + return 1; +} + +/** Return true iff sl has some element E such that + * tor_memeq(E,element,DIGEST_LEN) + */ +int +smartlist_contains_digest(const smartlist_t *sl, const char *element) +{ + int i; + if (!sl) return 0; + for (i=0; i < sl->num_used; i++) + if (tor_memeq((const char*)sl->list[i],element,DIGEST_LEN)) + return 1; + return 0; +} + +/** Return true iff some element E of sl2 has smartlist_contains(sl1,E). + */ +int +smartlist_overlap(const smartlist_t *sl1, const smartlist_t *sl2) +{ + int i; + for (i=0; i < sl2->num_used; i++) + if (smartlist_contains(sl1, sl2->list[i])) + return 1; + return 0; +} + +/** Remove every element E of sl1 such that !smartlist_contains(sl2,E). + * Does not preserve the order of sl1. + */ +void +smartlist_intersect(smartlist_t *sl1, const smartlist_t *sl2) +{ + int i; + for (i=0; i < sl1->num_used; i++) + if (!smartlist_contains(sl2, sl1->list[i])) { + sl1->list[i] = sl1->list[--sl1->num_used]; /* swap with the end */ + i--; /* so we process the new i'th element */ + } +} + +/** Remove every element E of sl1 such that smartlist_contains(sl2,E). + * Does not preserve the order of sl1. + */ +void +smartlist_subtract(smartlist_t *sl1, const smartlist_t *sl2) +{ + int i; + for (i=0; i < sl2->num_used; i++) + smartlist_remove(sl1, sl2->list[i]); +} + +/** Remove the idxth element of sl; if idx is not the last + * element, swap the last element of sl into the idxth space. + */ +void +smartlist_del(smartlist_t *sl, int idx) +{ + tor_assert(sl); + tor_assert(idx>=0); + tor_assert(idx < sl->num_used); + sl->list[idx] = sl->list[--sl->num_used]; +} + +/** Remove the idxth element of sl; if idx is not the last element, + * moving all subsequent elements back one space. Return the old value + * of the idxth element. + */ +void +smartlist_del_keeporder(smartlist_t *sl, int idx) +{ + tor_assert(sl); + tor_assert(idx>=0); + tor_assert(idx < sl->num_used); + --sl->num_used; + if (idx < sl->num_used) + memmove(sl->list+idx, sl->list+idx+1, sizeof(void*)*(sl->num_used-idx)); +} + +/** Insert the value val as the new idxth element of + * sl, moving all items previously at idx or later + * forward one space. + */ +void +smartlist_insert(smartlist_t *sl, int idx, void *val) +{ + tor_assert(sl); + tor_assert(idx>=0); + tor_assert(idx <= sl->num_used); + if (idx == sl->num_used) { + smartlist_add(sl, val); + } else { + smartlist_ensure_capacity(sl, sl->num_used+1); + /* Move other elements away */ + if (idx < sl->num_used) + memmove(sl->list + idx + 1, sl->list + idx, + sizeof(void*)*(sl->num_used-idx)); + sl->num_used++; + sl->list[idx] = val; + } +} + +/** + * Split a string str along all occurrences of sep, + * appending the (newly allocated) split strings, in order, to + * sl. Return the number of strings added to sl. + * + * If flags&SPLIT_SKIP_SPACE is true, remove initial and + * trailing space from each entry. + * If flags&SPLIT_IGNORE_BLANK is true, remove any entries + * of length 0. + * If flags&SPLIT_STRIP_SPACE is true, strip spaces from each + * split string. + * + * If max\>0, divide the string into no more than max pieces. If + * sep is NULL, split on any sequence of horizontal space. + */ +int +smartlist_split_string(smartlist_t *sl, const char *str, const char *sep, + int flags, int max) +{ + const char *cp, *end, *next; + int n = 0; + + tor_assert(sl); + tor_assert(str); + + cp = str; + while (1) { + if (flags&SPLIT_SKIP_SPACE) { + while (TOR_ISSPACE(*cp)) ++cp; + } + + if (max>0 && n == max-1) { + end = strchr(cp,'\0'); + } else if (sep) { + end = strstr(cp,sep); + if (!end) + end = strchr(cp,'\0'); + } else { + for (end = cp; *end && *end != '\t' && *end != ' '; ++end) + ; + } + + tor_assert(end); + + if (!*end) { + next = NULL; + } else if (sep) { + next = end+strlen(sep); + } else { + next = end+1; + while (*next == '\t' || *next == ' ') + ++next; + } + + if (flags&SPLIT_SKIP_SPACE) { + while (end > cp && TOR_ISSPACE(*(end-1))) + --end; + } + if (end != cp || !(flags&SPLIT_IGNORE_BLANK)) { + char *string = tor_strndup(cp, end-cp); + if (flags&SPLIT_STRIP_SPACE) + tor_strstrip(string, " "); + smartlist_add(sl, string); + ++n; + } + if (!next) + break; + cp = next; + } + + return n; +} + +/** Allocate and return a new string containing the concatenation of + * the elements of sl, in order, separated by join. If + * terminate is true, also terminate the string with join. + * If len_out is not NULL, set len_out to the length of + * the returned string. Requires that every element of sl is + * NUL-terminated string. + */ +char * +smartlist_join_strings(smartlist_t *sl, const char *join, + int terminate, size_t *len_out) +{ + return smartlist_join_strings2(sl,join,strlen(join),terminate,len_out); +} + +/** As smartlist_join_strings, but instead of separating/terminated with a + * NUL-terminated string join, uses the join_len-byte sequence + * at join. (Useful for generating a sequence of NUL-terminated + * strings.) + */ +char * +smartlist_join_strings2(smartlist_t *sl, const char *join, + size_t join_len, int terminate, size_t *len_out) +{ + int i; + size_t n = 0; + char *r = NULL, *dst, *src; + + tor_assert(sl); + tor_assert(join); + + if (terminate) + n = join_len; + + for (i = 0; i < sl->num_used; ++i) { + n += strlen(sl->list[i]); + if (i+1 < sl->num_used) /* avoid double-counting the last one */ + n += join_len; + } + dst = r = tor_malloc(n+1); + for (i = 0; i < sl->num_used; ) { + for (src = sl->list[i]; *src; ) + *dst++ = *src++; + if (++i < sl->num_used) { + memcpy(dst, join, join_len); + dst += join_len; + } + } + if (terminate) { + memcpy(dst, join, join_len); + dst += join_len; + } + *dst = '\0'; + + if (len_out) + *len_out = dst-r; + return r; +} + +/** Sort the members of sl into an order defined by + * the ordering function compare, which returns less then 0 if a + * precedes b, greater than 0 if b precedes a, and 0 if a 'equals' b. + */ +void +smartlist_sort(smartlist_t *sl, int (*compare)(const void **a, const void **b)) +{ + if (!sl->num_used) + return; + qsort(sl->list, sl->num_used, sizeof(void*), + (int (*)(const void *,const void*))compare); +} + +/** Given a smartlist sl sorted with the function compare, + * return the most frequent member in the list. Break ties in favor of + * later elements. If the list is empty, return NULL. + */ +void * +smartlist_get_most_frequent(const smartlist_t *sl, + int (*compare)(const void **a, const void **b)) +{ + const void *most_frequent = NULL; + int most_frequent_count = 0; + + const void *cur = NULL; + int i, count=0; + + if (!sl->num_used) + return NULL; + for (i = 0; i < sl->num_used; ++i) { + const void *item = sl->list[i]; + if (cur && 0 == compare(&cur, &item)) { + ++count; + } else { + if (cur && count >= most_frequent_count) { + most_frequent = cur; + most_frequent_count = count; + } + cur = item; + count = 1; + } + } + if (cur && count >= most_frequent_count) { + most_frequent = cur; + most_frequent_count = count; + } + return (void*)most_frequent; +} + +/** Given a sorted smartlist sl and the comparison function used to + * sort it, remove all duplicate members. If free_fn is provided, calls + * free_fn on each duplicate. Otherwise, just removes them. Preserves order. + */ +void +smartlist_uniq(smartlist_t *sl, + int (*compare)(const void **a, const void **b), + void (*free_fn)(void *a)) +{ + int i; + for (i=1; i < sl->num_used; ++i) { + if (compare((const void **)&(sl->list[i-1]), + (const void **)&(sl->list[i])) == 0) { + if (free_fn) + free_fn(sl->list[i]); + smartlist_del_keeporder(sl, i--); + } + } +} + +/** Assuming the members of sl are in order, return a pointer to the + * member that matches key. Ordering and matching are defined by a + * compare function that returns 0 on a match; less than 0 if key is + * less than member, and greater than 0 if key is greater then member. + */ +void * +smartlist_bsearch(smartlist_t *sl, const void *key, + int (*compare)(const void *key, const void **member)) +{ + int found, idx; + idx = smartlist_bsearch_idx(sl, key, compare, &found); + return found ? smartlist_get(sl, idx) : NULL; +} + +/** Assuming the members of sl are in order, return the index of the + * member that matches key. If no member matches, return the index of + * the first member greater than key, or smartlist_len(sl) if no member + * is greater than key. Set found_out to true on a match, to + * false otherwise. Ordering and matching are defined by a compare + * function that returns 0 on a match; less than 0 if key is less than member, + * and greater than 0 if key is greater then member. + */ +int +smartlist_bsearch_idx(const smartlist_t *sl, const void *key, + int (*compare)(const void *key, const void **member), + int *found_out) +{ + int hi, lo, cmp, mid, len, diff; + + tor_assert(sl); + tor_assert(compare); + tor_assert(found_out); + + len = smartlist_len(sl); + + /* Check for the trivial case of a zero-length list */ + if (len == 0) { + *found_out = 0; + /* We already know smartlist_len(sl) is 0 in this case */ + return 0; + } + + /* Okay, we have a real search to do */ + tor_assert(len > 0); + lo = 0; + hi = len - 1; + + /* + * These invariants are always true: + * + * For all i such that 0 <= i < lo, sl[i] < key + * For all i such that hi < i <= len, sl[i] > key + */ + + while (lo <= hi) { + diff = hi - lo; + /* + * We want mid = (lo + hi) / 2, but that could lead to overflow, so + * instead diff = hi - lo (non-negative because of loop condition), and + * then hi = lo + diff, mid = (lo + lo + diff) / 2 = lo + (diff / 2). + */ + mid = lo + (diff / 2); + cmp = compare(key, (const void**) &(sl->list[mid])); + if (cmp == 0) { + /* sl[mid] == key; we found it */ + *found_out = 1; + return mid; + } else if (cmp > 0) { + /* + * key > sl[mid] and an index i such that sl[i] == key must + * have i > mid if it exists. + */ + + /* + * Since lo <= mid <= hi, hi can only decrease on each iteration (by + * being set to mid - 1) and hi is initially len - 1, mid < len should + * always hold, and this is not symmetric with the left end of list + * mid > 0 test below. A key greater than the right end of the list + * should eventually lead to lo == hi == mid == len - 1, and then + * we set lo to len below and fall out to the same exit we hit for + * a key in the middle of the list but not matching. Thus, we just + * assert for consistency here rather than handle a mid == len case. + */ + tor_assert(mid < len); + /* Move lo to the element immediately after sl[mid] */ + lo = mid + 1; + } else { + /* This should always be true in this case */ + tor_assert(cmp < 0); + + /* + * key < sl[mid] and an index i such that sl[i] == key must + * have i < mid if it exists. + */ + + if (mid > 0) { + /* Normal case, move hi to the element immediately before sl[mid] */ + hi = mid - 1; + } else { + /* These should always be true in this case */ + tor_assert(mid == lo); + tor_assert(mid == 0); + /* + * We were at the beginning of the list and concluded that every + * element e compares e > key. + */ + *found_out = 0; + return 0; + } + } + } + + /* + * lo > hi; we have no element matching key but we have elements falling + * on both sides of it. The lo index points to the first element > key. + */ + tor_assert(lo == hi + 1); /* All other cases should have been handled */ + tor_assert(lo >= 0); + tor_assert(lo <= len); + tor_assert(hi >= 0); + tor_assert(hi <= len); + + if (lo < len) { + cmp = compare(key, (const void **) &(sl->list[lo])); + tor_assert(cmp < 0); + } else { + cmp = compare(key, (const void **) &(sl->list[len-1])); + tor_assert(cmp > 0); + } + + *found_out = 0; + return lo; +} + +/** Helper: compare two const char **s. */ +static int +compare_string_ptrs_(const void **_a, const void **_b) +{ + return strcmp((const char*)*_a, (const char*)*_b); +} + +/** Sort a smartlist sl containing strings into lexically ascending + * order. */ +void +smartlist_sort_strings(smartlist_t *sl) +{ + smartlist_sort(sl, compare_string_ptrs_); +} + +/** Return the most frequent string in the sorted list sl */ +char * +smartlist_get_most_frequent_string(smartlist_t *sl) +{ + return smartlist_get_most_frequent(sl, compare_string_ptrs_); +} + +/** Remove duplicate strings from a sorted list, and free them with tor_free(). + */ +void +smartlist_uniq_strings(smartlist_t *sl) +{ + smartlist_uniq(sl, compare_string_ptrs_, tor_free_); +} + +/* Heap-based priority queue implementation for O(lg N) insert and remove. + * Recall that the heap property is that, for every index I, h[I] < + * H[LEFT_CHILD[I]] and h[I] < H[RIGHT_CHILD[I]]. + * + * For us to remove items other than the topmost item, each item must store + * its own index within the heap. When calling the pqueue functions, tell + * them about the offset of the field that stores the index within the item. + * + * Example: + * + * typedef struct timer_t { + * struct timeval tv; + * int heap_index; + * } timer_t; + * + * static int compare(const void *p1, const void *p2) { + * const timer_t *t1 = p1, *t2 = p2; + * if (t1->tv.tv_sec < t2->tv.tv_sec) { + * return -1; + * } else if (t1->tv.tv_sec > t2->tv.tv_sec) { + * return 1; + * } else { + * return t1->tv.tv_usec - t2->tv_usec; + * } + * } + * + * void timer_heap_insert(smartlist_t *heap, timer_t *timer) { + * smartlist_pqueue_add(heap, compare, STRUCT_OFFSET(timer_t, heap_index), + * timer); + * } + * + * void timer_heap_pop(smartlist_t *heap) { + * return smartlist_pqueue_pop(heap, compare, + * STRUCT_OFFSET(timer_t, heap_index)); + * } + */ + +/** @{ */ +/** Functions to manipulate heap indices to find a node's parent and children. + * + * For a 1-indexed array, we would use LEFT_CHILD[x] = 2*x and RIGHT_CHILD[x] + * = 2*x + 1. But this is C, so we have to adjust a little. */ +//#define LEFT_CHILD(i) ( ((i)+1)*2 - 1) +//#define RIGHT_CHILD(i) ( ((i)+1)*2 ) +//#define PARENT(i) ( ((i)+1)/2 - 1) +#define LEFT_CHILD(i) ( 2*(i) + 1 ) +#define RIGHT_CHILD(i) ( 2*(i) + 2 ) +#define PARENT(i) ( ((i)-1) / 2 ) +/** }@ */ + +/** @{ */ +/** Helper macros for heaps: Given a local variable idx_field_offset + * set to the offset of an integer index within the heap element structure, + * IDX_OF_ITEM(p) gives you the index of p, and IDXP(p) gives you a pointer to + * where p's index is stored. Given additionally a local smartlist sl, + * UPDATE_IDX(i) sets the index of the element at i to the correct + * value (that is, to i). + */ +#define IDXP(p) ((int*)STRUCT_VAR_P(p, idx_field_offset)) + +#define UPDATE_IDX(i) do { \ + void *updated = sl->list[i]; \ + *IDXP(updated) = i; \ + } while (0) + +#define IDX_OF_ITEM(p) (*IDXP(p)) +/** @} */ + +/** Helper. sl may have at most one violation of the heap property: + * the item at idx may be greater than one or both of its children. + * Restore the heap property. */ +static INLINE void +smartlist_heapify(smartlist_t *sl, + int (*compare)(const void *a, const void *b), + int idx_field_offset, + int idx) +{ + while (1) { + int left_idx = LEFT_CHILD(idx); + int best_idx; + + if (left_idx >= sl->num_used) + return; + if (compare(sl->list[idx],sl->list[left_idx]) < 0) + best_idx = idx; + else + best_idx = left_idx; + if (left_idx+1 < sl->num_used && + compare(sl->list[left_idx+1],sl->list[best_idx]) < 0) + best_idx = left_idx + 1; + + if (best_idx == idx) { + return; + } else { + void *tmp = sl->list[idx]; + sl->list[idx] = sl->list[best_idx]; + sl->list[best_idx] = tmp; + UPDATE_IDX(idx); + UPDATE_IDX(best_idx); + + idx = best_idx; + } + } +} + +/** Insert item into the heap stored in sl, where order is + * determined by compare and the offset of the item in the heap is + * stored in an int-typed field at position idx_field_offset within + * item. + */ +void +smartlist_pqueue_add(smartlist_t *sl, + int (*compare)(const void *a, const void *b), + int idx_field_offset, + void *item) +{ + int idx; + smartlist_add(sl,item); + UPDATE_IDX(sl->num_used-1); + + for (idx = sl->num_used - 1; idx; ) { + int parent = PARENT(idx); + if (compare(sl->list[idx], sl->list[parent]) < 0) { + void *tmp = sl->list[parent]; + sl->list[parent] = sl->list[idx]; + sl->list[idx] = tmp; + UPDATE_IDX(parent); + UPDATE_IDX(idx); + idx = parent; + } else { + return; + } + } +} + +/** Remove and return the top-priority item from the heap stored in sl, + * where order is determined by compare and the item's position is + * stored at position idx_field_offset within the item. sl must + * not be empty. */ +void * +smartlist_pqueue_pop(smartlist_t *sl, + int (*compare)(const void *a, const void *b), + int idx_field_offset) +{ + void *top; + tor_assert(sl->num_used); + + top = sl->list[0]; + *IDXP(top)=-1; + if (--sl->num_used) { + sl->list[0] = sl->list[sl->num_used]; + UPDATE_IDX(0); + smartlist_heapify(sl, compare, idx_field_offset, 0); + } + return top; +} + +/** Remove the item item from the heap stored in sl, + * where order is determined by compare and the item's position is + * stored at position idx_field_offset within the item. sl must + * not be empty. */ +void +smartlist_pqueue_remove(smartlist_t *sl, + int (*compare)(const void *a, const void *b), + int idx_field_offset, + void *item) +{ + int idx = IDX_OF_ITEM(item); + tor_assert(idx >= 0); + tor_assert(sl->list[idx] == item); + --sl->num_used; + *IDXP(item) = -1; + if (idx == sl->num_used) { + return; + } else { + sl->list[idx] = sl->list[sl->num_used]; + UPDATE_IDX(idx); + smartlist_heapify(sl, compare, idx_field_offset, idx); + } +} + +/** Assert that the heap property is correctly maintained by the heap stored + * in sl, where order is determined by compare. */ +void +smartlist_pqueue_assert_ok(smartlist_t *sl, + int (*compare)(const void *a, const void *b), + int idx_field_offset) +{ + int i; + for (i = sl->num_used - 1; i >= 0; --i) { + if (i>0) + tor_assert(compare(sl->list[PARENT(i)], sl->list[i]) <= 0); + tor_assert(IDX_OF_ITEM(sl->list[i]) == i); + } +} + +/** Helper: compare two DIGEST_LEN digests. */ +static int +compare_digests_(const void **_a, const void **_b) +{ + return tor_memcmp((const char*)*_a, (const char*)*_b, DIGEST_LEN); +} + +/** Sort the list of DIGEST_LEN-byte digests into ascending order. */ +void +smartlist_sort_digests(smartlist_t *sl) +{ + smartlist_sort(sl, compare_digests_); +} + +/** Remove duplicate digests from a sorted list, and free them with tor_free(). + */ +void +smartlist_uniq_digests(smartlist_t *sl) +{ + smartlist_uniq(sl, compare_digests_, tor_free_); +} + +/** Helper: compare two DIGEST256_LEN digests. */ +static int +compare_digests256_(const void **_a, const void **_b) +{ + return tor_memcmp((const char*)*_a, (const char*)*_b, DIGEST256_LEN); +} + +/** Sort the list of DIGEST256_LEN-byte digests into ascending order. */ +void +smartlist_sort_digests256(smartlist_t *sl) +{ + smartlist_sort(sl, compare_digests256_); +} + +/** Return the most frequent member of the sorted list of DIGEST256_LEN + * digests in sl */ +char * +smartlist_get_most_frequent_digest256(smartlist_t *sl) +{ + return smartlist_get_most_frequent(sl, compare_digests256_); +} + +/** Remove duplicate 256-bit digests from a sorted list, and free them with + * tor_free(). + */ +void +smartlist_uniq_digests256(smartlist_t *sl) +{ + smartlist_uniq(sl, compare_digests256_, tor_free_); +} + +/** Helper: Declare an entry type and a map type to implement a mapping using + * ht.h. The map type will be called maptype. The key part of each + * entry is declared using the C declaration keydecl. All functions + * and types associated with the map get prefixed with prefix */ +#define DEFINE_MAP_STRUCTS(maptype, keydecl, prefix) \ + typedef struct prefix ## entry_t { \ + HT_ENTRY(prefix ## entry_t) node; \ + void *val; \ + keydecl; \ + } prefix ## entry_t; \ + struct maptype { \ + HT_HEAD(prefix ## impl, prefix ## entry_t) head; \ + } + +DEFINE_MAP_STRUCTS(strmap_t, char *key, strmap_); +DEFINE_MAP_STRUCTS(digestmap_t, char key[DIGEST_LEN], digestmap_); + +/** Helper: compare strmap_entry_t objects by key value. */ +static INLINE int +strmap_entries_eq(const strmap_entry_t *a, const strmap_entry_t *b) +{ + return !strcmp(a->key, b->key); +} + +/** Helper: return a hash value for a strmap_entry_t. */ +static INLINE unsigned int +strmap_entry_hash(const strmap_entry_t *a) +{ + return ht_string_hash(a->key); +} + +/** Helper: compare digestmap_entry_t objects by key value. */ +static INLINE int +digestmap_entries_eq(const digestmap_entry_t *a, const digestmap_entry_t *b) +{ + return tor_memeq(a->key, b->key, DIGEST_LEN); +} + +/** Helper: return a hash value for a digest_map_t. */ +static INLINE unsigned int +digestmap_entry_hash(const digestmap_entry_t *a) +{ +#if SIZEOF_INT != 8 + const uint32_t *p = (const uint32_t*)a->key; + return p[0] ^ p[1] ^ p[2] ^ p[3] ^ p[4]; +#else + const uint64_t *p = (const uint64_t*)a->key; + return p[0] ^ p[1]; +#endif +} + +HT_PROTOTYPE(strmap_impl, strmap_entry_t, node, strmap_entry_hash, + strmap_entries_eq) +HT_GENERATE(strmap_impl, strmap_entry_t, node, strmap_entry_hash, + strmap_entries_eq, 0.6, malloc, realloc, free) + +HT_PROTOTYPE(digestmap_impl, digestmap_entry_t, node, digestmap_entry_hash, + digestmap_entries_eq) +HT_GENERATE(digestmap_impl, digestmap_entry_t, node, digestmap_entry_hash, + digestmap_entries_eq, 0.6, malloc, realloc, free) + +/** Constructor to create a new empty map from strings to void*'s. + */ +strmap_t * +strmap_new(void) +{ + strmap_t *result; + result = tor_malloc(sizeof(strmap_t)); + HT_INIT(strmap_impl, &result->head); + return result; +} + +/** Constructor to create a new empty map from digests to void*'s. + */ +digestmap_t * +digestmap_new(void) +{ + digestmap_t *result; + result = tor_malloc(sizeof(digestmap_t)); + HT_INIT(digestmap_impl, &result->head); + return result; +} + +/** Set the current value for key to val. Returns the previous + * value for key if one was set, or NULL if one was not. + * + * This function makes a copy of key if necessary, but not of + * val. + */ +void * +strmap_set(strmap_t *map, const char *key, void *val) +{ + strmap_entry_t *resolve; + strmap_entry_t search; + void *oldval; + tor_assert(map); + tor_assert(key); + tor_assert(val); + search.key = (char*)key; + resolve = HT_FIND(strmap_impl, &map->head, &search); + if (resolve) { + oldval = resolve->val; + resolve->val = val; + return oldval; + } else { + resolve = tor_malloc_zero(sizeof(strmap_entry_t)); + resolve->key = tor_strdup(key); + resolve->val = val; + tor_assert(!HT_FIND(strmap_impl, &map->head, resolve)); + HT_INSERT(strmap_impl, &map->head, resolve); + return NULL; + } +} + +#define OPTIMIZED_DIGESTMAP_SET + +/** Like strmap_set() above but for digestmaps. */ +void * +digestmap_set(digestmap_t *map, const char *key, void *val) +{ +#ifndef OPTIMIZED_DIGESTMAP_SET + digestmap_entry_t *resolve; +#endif + digestmap_entry_t search; + void *oldval; + tor_assert(map); + tor_assert(key); + tor_assert(val); + memcpy(&search.key, key, DIGEST_LEN); +#ifndef OPTIMIZED_DIGESTMAP_SET + resolve = HT_FIND(digestmap_impl, &map->head, &search); + if (resolve) { + oldval = resolve->val; + resolve->val = val; + return oldval; + } else { + resolve = tor_malloc_zero(sizeof(digestmap_entry_t)); + memcpy(resolve->key, key, DIGEST_LEN); + resolve->val = val; + HT_INSERT(digestmap_impl, &map->head, resolve); + return NULL; + } +#else + /* We spend up to 5% of our time in this function, so the code below is + * meant to optimize the check/alloc/set cycle by avoiding the two trips to + * the hash table that we do in the unoptimized code above. (Each of + * HT_INSERT and HT_FIND calls HT_SET_HASH and HT_FIND_P.) + */ + HT_FIND_OR_INSERT_(digestmap_impl, node, digestmap_entry_hash, &(map->head), + digestmap_entry_t, &search, ptr, + { + /* we found an entry. */ + oldval = (*ptr)->val; + (*ptr)->val = val; + return oldval; + }, + { + /* We didn't find the entry. */ + digestmap_entry_t *newent = + tor_malloc_zero(sizeof(digestmap_entry_t)); + memcpy(newent->key, key, DIGEST_LEN); + newent->val = val; + HT_FOI_INSERT_(node, &(map->head), &search, newent, ptr); + return NULL; + }); +#endif +} + +/** Return the current value associated with key, or NULL if no + * value is set. + */ +void * +strmap_get(const strmap_t *map, const char *key) +{ + strmap_entry_t *resolve; + strmap_entry_t search; + tor_assert(map); + tor_assert(key); + search.key = (char*)key; + resolve = HT_FIND(strmap_impl, &map->head, &search); + if (resolve) { + return resolve->val; + } else { + return NULL; + } +} + +/** Like strmap_get() above but for digestmaps. */ +void * +digestmap_get(const digestmap_t *map, const char *key) +{ + digestmap_entry_t *resolve; + digestmap_entry_t search; + tor_assert(map); + tor_assert(key); + memcpy(&search.key, key, DIGEST_LEN); + resolve = HT_FIND(digestmap_impl, &map->head, &search); + if (resolve) { + return resolve->val; + } else { + return NULL; + } +} + +/** Remove the value currently associated with key from the map. + * Return the value if one was set, or NULL if there was no entry for + * key. + * + * Note: you must free any storage associated with the returned value. + */ +void * +strmap_remove(strmap_t *map, const char *key) +{ + strmap_entry_t *resolve; + strmap_entry_t search; + void *oldval; + tor_assert(map); + tor_assert(key); + search.key = (char*)key; + resolve = HT_REMOVE(strmap_impl, &map->head, &search); + if (resolve) { + oldval = resolve->val; + tor_free(resolve->key); + tor_free(resolve); + return oldval; + } else { + return NULL; + } +} + +/** Like strmap_remove() above but for digestmaps. */ +void * +digestmap_remove(digestmap_t *map, const char *key) +{ + digestmap_entry_t *resolve; + digestmap_entry_t search; + void *oldval; + tor_assert(map); + tor_assert(key); + memcpy(&search.key, key, DIGEST_LEN); + resolve = HT_REMOVE(digestmap_impl, &map->head, &search); + if (resolve) { + oldval = resolve->val; + tor_free(resolve); + return oldval; + } else { + return NULL; + } +} + +/** Same as strmap_set, but first converts key to lowercase. */ +void * +strmap_set_lc(strmap_t *map, const char *key, void *val) +{ + /* We could be a little faster by using strcasecmp instead, and a separate + * type, but I don't think it matters. */ + void *v; + char *lc_key = tor_strdup(key); + tor_strlower(lc_key); + v = strmap_set(map,lc_key,val); + tor_free(lc_key); + return v; +} + +/** Same as strmap_get, but first converts key to lowercase. */ +void * +strmap_get_lc(const strmap_t *map, const char *key) +{ + void *v; + char *lc_key = tor_strdup(key); + tor_strlower(lc_key); + v = strmap_get(map,lc_key); + tor_free(lc_key); + return v; +} + +/** Same as strmap_remove, but first converts key to lowercase */ +void * +strmap_remove_lc(strmap_t *map, const char *key) +{ + void *v; + char *lc_key = tor_strdup(key); + tor_strlower(lc_key); + v = strmap_remove(map,lc_key); + tor_free(lc_key); + return v; +} + +/** return an iterator pointer to the front of a map. + * + * Iterator example: + * + * \code + * // uppercase values in "map", removing empty values. + * + * strmap_iter_t *iter; + * const char *key; + * void *val; + * char *cp; + * + * for (iter = strmap_iter_init(map); !strmap_iter_done(iter); ) { + * strmap_iter_get(iter, &key, &val); + * cp = (char*)val; + * if (!*cp) { + * iter = strmap_iter_next_rmv(map,iter); + * free(val); + * } else { + * for (;*cp;cp++) *cp = TOR_TOUPPER(*cp); + * iter = strmap_iter_next(map,iter); + * } + * } + * \endcode + * + */ +strmap_iter_t * +strmap_iter_init(strmap_t *map) +{ + tor_assert(map); + return HT_START(strmap_impl, &map->head); +} + +/** Start iterating through map. See strmap_iter_init() for example. */ +digestmap_iter_t * +digestmap_iter_init(digestmap_t *map) +{ + tor_assert(map); + return HT_START(digestmap_impl, &map->head); +} + +/** Advance the iterator iter for map a single step to the next + * entry, and return its new value. */ +strmap_iter_t * +strmap_iter_next(strmap_t *map, strmap_iter_t *iter) +{ + tor_assert(map); + tor_assert(iter); + return HT_NEXT(strmap_impl, &map->head, iter); +} + +/** Advance the iterator iter for map a single step to the next entry, + * and return its new value. */ +digestmap_iter_t * +digestmap_iter_next(digestmap_t *map, digestmap_iter_t *iter) +{ + tor_assert(map); + tor_assert(iter); + return HT_NEXT(digestmap_impl, &map->head, iter); +} + +/** Advance the iterator iter a single step to the next entry, removing + * the current entry, and return its new value. + */ +strmap_iter_t * +strmap_iter_next_rmv(strmap_t *map, strmap_iter_t *iter) +{ + strmap_entry_t *rmv; + tor_assert(map); + tor_assert(iter); + tor_assert(*iter); + rmv = *iter; + iter = HT_NEXT_RMV(strmap_impl, &map->head, iter); + tor_free(rmv->key); + tor_free(rmv); + return iter; +} + +/** Advance the iterator iter a single step to the next entry, removing + * the current entry, and return its new value. + */ +digestmap_iter_t * +digestmap_iter_next_rmv(digestmap_t *map, digestmap_iter_t *iter) +{ + digestmap_entry_t *rmv; + tor_assert(map); + tor_assert(iter); + tor_assert(*iter); + rmv = *iter; + iter = HT_NEXT_RMV(digestmap_impl, &map->head, iter); + tor_free(rmv); + return iter; +} + +/** Set *keyp and *valp to the current entry pointed to by + * iter. */ +void +strmap_iter_get(strmap_iter_t *iter, const char **keyp, void **valp) +{ + tor_assert(iter); + tor_assert(*iter); + tor_assert(keyp); + tor_assert(valp); + *keyp = (*iter)->key; + *valp = (*iter)->val; +} + +/** Set *keyp and *valp to the current entry pointed to by + * iter. */ +void +digestmap_iter_get(digestmap_iter_t *iter, const char **keyp, void **valp) +{ + tor_assert(iter); + tor_assert(*iter); + tor_assert(keyp); + tor_assert(valp); + *keyp = (*iter)->key; + *valp = (*iter)->val; +} + +/** Return true iff iter has advanced past the last entry of + * map. */ +int +strmap_iter_done(strmap_iter_t *iter) +{ + return iter == NULL; +} + +/** Return true iff iter has advanced past the last entry of + * map. */ +int +digestmap_iter_done(digestmap_iter_t *iter) +{ + return iter == NULL; +} + +/** Remove all entries from map, and deallocate storage for those + * entries. If free_val is provided, it is invoked on every value in + * map. + */ +void +strmap_free(strmap_t *map, void (*free_val)(void*)) +{ + strmap_entry_t **ent, **next, *this; + if (!map) + return; + + for (ent = HT_START(strmap_impl, &map->head); ent != NULL; ent = next) { + this = *ent; + next = HT_NEXT_RMV(strmap_impl, &map->head, ent); + tor_free(this->key); + if (free_val) + free_val(this->val); + tor_free(this); + } + tor_assert(HT_EMPTY(&map->head)); + HT_CLEAR(strmap_impl, &map->head); + tor_free(map); +} + +/** Remove all entries from map, and deallocate storage for those + * entries. If free_val is provided, it is invoked on every value in + * map. + */ +void +digestmap_free(digestmap_t *map, void (*free_val)(void*)) +{ + digestmap_entry_t **ent, **next, *this; + if (!map) + return; + for (ent = HT_START(digestmap_impl, &map->head); ent != NULL; ent = next) { + this = *ent; + next = HT_NEXT_RMV(digestmap_impl, &map->head, ent); + if (free_val) + free_val(this->val); + tor_free(this); + } + tor_assert(HT_EMPTY(&map->head)); + HT_CLEAR(digestmap_impl, &map->head); + tor_free(map); +} + +/** Fail with an assertion error if anything has gone wrong with the internal + * representation of map. */ +void +strmap_assert_ok(const strmap_t *map) +{ + tor_assert(!strmap_impl_HT_REP_IS_BAD_(&map->head)); +} +/** Fail with an assertion error if anything has gone wrong with the internal + * representation of map. */ +void +digestmap_assert_ok(const digestmap_t *map) +{ + tor_assert(!digestmap_impl_HT_REP_IS_BAD_(&map->head)); +} + +/** Return true iff map has no entries. */ +int +strmap_isempty(const strmap_t *map) +{ + return HT_EMPTY(&map->head); +} + +/** Return true iff map has no entries. */ +int +digestmap_isempty(const digestmap_t *map) +{ + return HT_EMPTY(&map->head); +} + +/** Return the number of items in map. */ +int +strmap_size(const strmap_t *map) +{ + return HT_SIZE(&map->head); +} + +/** Return the number of items in map. */ +int +digestmap_size(const digestmap_t *map) +{ + return HT_SIZE(&map->head); +} + +/** Declare a function called funcname that acts as a find_nth_FOO + * function for an array of type elt_t*. + * + * NOTE: The implementation kind of sucks: It's O(n log n), whereas finding + * the kth element of an n-element list can be done in O(n). Then again, this + * implementation is not in critical path, and it is obviously correct. */ +#define IMPLEMENT_ORDER_FUNC(funcname, elt_t) \ + static int \ + _cmp_ ## elt_t(const void *_a, const void *_b) \ + { \ + const elt_t *a = _a, *b = _b; \ + if (*a<*b) \ + return -1; \ + else if (*a>*b) \ + return 1; \ + else \ + return 0; \ + } \ + elt_t \ + funcname(elt_t *array, int n_elements, int nth) \ + { \ + tor_assert(nth >= 0); \ + tor_assert(nth < n_elements); \ + qsort(array, n_elements, sizeof(elt_t), _cmp_ ##elt_t); \ + return array[nth]; \ + } + +IMPLEMENT_ORDER_FUNC(find_nth_int, int) +IMPLEMENT_ORDER_FUNC(find_nth_time, time_t) +IMPLEMENT_ORDER_FUNC(find_nth_double, double) +IMPLEMENT_ORDER_FUNC(find_nth_uint32, uint32_t) +IMPLEMENT_ORDER_FUNC(find_nth_int32, int32_t) +IMPLEMENT_ORDER_FUNC(find_nth_long, long) + +/** Return a newly allocated digestset_t, optimized to hold a total of + * max_elements digests with a reasonably low false positive weight. */ +digestset_t * +digestset_new(int max_elements) +{ + /* The probability of false positives is about P=(1 - exp(-kn/m))^k, where k + * is the number of hash functions per entry, m is the bits in the array, + * and n is the number of elements inserted. For us, k==4, n<=max_elements, + * and m==n_bits= approximately max_elements*32. This gives + * P<(1-exp(-4*n/(32*n)))^4 == (1-exp(1/-8))^4 == .00019 + * + * It would be more optimal in space vs false positives to get this false + * positive rate by going for k==13, and m==18.5n, but we also want to + * conserve CPU, and k==13 is pretty big. + */ + int n_bits = 1u << (tor_log2(max_elements)+5); + digestset_t *r = tor_malloc(sizeof(digestset_t)); + r->mask = n_bits - 1; + r->ba = bitarray_init_zero(n_bits); + return r; +} + +/** Free all storage held in set. */ +void +digestset_free(digestset_t *set) +{ + if (!set) + return; + bitarray_free(set->ba); + tor_free(set); +} + diff --git a/src/tor/container.h b/src/tor/container.h new file mode 100644 index 0000000..9b92aaa --- /dev/null +++ b/src/tor/container.h @@ -0,0 +1,681 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_CONTAINER_H +#define TOR_CONTAINER_H + +#include "tor_util.h" + +/** A resizeable list of pointers, with associated helpful functionality. + * + * The members of this struct are exposed only so that macros and inlines can + * use them; all access to smartlist internals should go through the functions + * and macros defined here. + **/ +typedef struct smartlist_t { + /** @{ */ + /** list has enough capacity to store exactly capacity elements + * before it needs to be resized. Only the first num_used (\<= + * capacity) elements point to valid data. + */ + void **list; + int num_used; + int capacity; + /** @} */ +} smartlist_t; + +smartlist_t *smartlist_new(void); +void smartlist_free(smartlist_t *sl); +void smartlist_clear(smartlist_t *sl); +void smartlist_add(smartlist_t *sl, void *element); +void smartlist_add_all(smartlist_t *sl, const smartlist_t *s2); +void smartlist_remove(smartlist_t *sl, const void *element); +void *smartlist_pop_last(smartlist_t *sl); +void smartlist_reverse(smartlist_t *sl); +void smartlist_string_remove(smartlist_t *sl, const char *element); +int smartlist_contains(const smartlist_t *sl, const void *element); +int smartlist_contains_string(const smartlist_t *sl, const char *element); +int smartlist_string_pos(const smartlist_t *, const char *elt); +int smartlist_contains_string_case(const smartlist_t *sl, const char *element); +int smartlist_contains_int_as_string(const smartlist_t *sl, int num); +int smartlist_strings_eq(const smartlist_t *sl1, const smartlist_t *sl2); +int smartlist_contains_digest(const smartlist_t *sl, const char *element); +int smartlist_ints_eq(const smartlist_t *sl1, const smartlist_t *sl2); +int smartlist_overlap(const smartlist_t *sl1, const smartlist_t *sl2); +void smartlist_intersect(smartlist_t *sl1, const smartlist_t *sl2); +void smartlist_subtract(smartlist_t *sl1, const smartlist_t *sl2); + +/* smartlist_choose() is defined in crypto.[ch] */ +#ifdef DEBUG_SMARTLIST +/** Return the number of items in sl. + */ +static INLINE int smartlist_len(const smartlist_t *sl); +static INLINE int smartlist_len(const smartlist_t *sl) { + tor_assert(sl); + return (sl)->num_used; +} +/** Return the idxth element of sl. + */ +static INLINE void *smartlist_get(const smartlist_t *sl, int idx); +static INLINE void *smartlist_get(const smartlist_t *sl, int idx) { + tor_assert(sl); + tor_assert(idx>=0); + tor_assert(sl->num_used > idx); + return sl->list[idx]; +} +static INLINE void smartlist_set(smartlist_t *sl, int idx, void *val) { + tor_assert(sl); + tor_assert(idx>=0); + tor_assert(sl->num_used > idx); + sl->list[idx] = val; +} +#else +#define smartlist_len(sl) ((sl)->num_used) +#define smartlist_get(sl, idx) ((sl)->list[idx]) +#define smartlist_set(sl, idx, val) ((sl)->list[idx] = (val)) +#endif + +/** Exchange the elements at indices idx1 and idx2 of the + * smartlist sl. */ +static INLINE void smartlist_swap(smartlist_t *sl, int idx1, int idx2) +{ + if (idx1 != idx2) { + void *elt = smartlist_get(sl, idx1); + smartlist_set(sl, idx1, smartlist_get(sl, idx2)); + smartlist_set(sl, idx2, elt); + } +} + +void smartlist_del(smartlist_t *sl, int idx); +void smartlist_del_keeporder(smartlist_t *sl, int idx); +void smartlist_insert(smartlist_t *sl, int idx, void *val); +void smartlist_sort(smartlist_t *sl, + int (*compare)(const void **a, const void **b)); +void *smartlist_get_most_frequent(const smartlist_t *sl, + int (*compare)(const void **a, const void **b)); +void smartlist_uniq(smartlist_t *sl, + int (*compare)(const void **a, const void **b), + void (*free_fn)(void *elt)); + +void smartlist_sort_strings(smartlist_t *sl); +void smartlist_sort_digests(smartlist_t *sl); +void smartlist_sort_digests256(smartlist_t *sl); + +char *smartlist_get_most_frequent_string(smartlist_t *sl); +char *smartlist_get_most_frequent_digest256(smartlist_t *sl); + +void smartlist_uniq_strings(smartlist_t *sl); +void smartlist_uniq_digests(smartlist_t *sl); +void smartlist_uniq_digests256(smartlist_t *sl); +void *smartlist_bsearch(smartlist_t *sl, const void *key, + int (*compare)(const void *key, const void **member)); +int smartlist_bsearch_idx(const smartlist_t *sl, const void *key, + int (*compare)(const void *key, const void **member), + int *found_out); + +void smartlist_pqueue_add(smartlist_t *sl, + int (*compare)(const void *a, const void *b), + int idx_field_offset, + void *item); +void *smartlist_pqueue_pop(smartlist_t *sl, + int (*compare)(const void *a, const void *b), + int idx_field_offset); +void smartlist_pqueue_remove(smartlist_t *sl, + int (*compare)(const void *a, const void *b), + int idx_field_offset, + void *item); +void smartlist_pqueue_assert_ok(smartlist_t *sl, + int (*compare)(const void *a, const void *b), + int idx_field_offset); + +#define SPLIT_SKIP_SPACE 0x01 +#define SPLIT_IGNORE_BLANK 0x02 +#define SPLIT_STRIP_SPACE 0x04 +int smartlist_split_string(smartlist_t *sl, const char *str, const char *sep, + int flags, int max); +char *smartlist_join_strings(smartlist_t *sl, const char *join, int terminate, + size_t *len_out) ATTR_MALLOC; +char *smartlist_join_strings2(smartlist_t *sl, const char *join, + size_t join_len, int terminate, size_t *len_out) + ATTR_MALLOC; + +/** Iterate over the items in a smartlist sl, in order. For each item, + * assign it to a new local variable of type type named var, and + * execute the statements inside the loop body. Inside the loop, the loop + * index can be accessed as var_sl_idx and the length of the list can + * be accessed as var_sl_len. + * + * NOTE: Do not change the length of the list while the loop is in progress, + * unless you adjust the _sl_len variable correspondingly. See second example + * below. + * + * Example use: + *
+ *   smartlist_t *list = smartlist_split("A:B:C", ":", 0, 0);
+ *   SMARTLIST_FOREACH_BEGIN(list, char *, cp) {
+ *     printf("%d: %s\n", cp_sl_idx, cp);
+ *     tor_free(cp);
+ *   } SMARTLIST_FOREACH_END(cp);
+ *   smartlist_free(list);
+ * 
+ * + * Example use (advanced): + *
+ *   SMARTLIST_FOREACH_BEGIN(list, char *, cp) {
+ *     if (!strcmp(cp, "junk")) {
+ *       tor_free(cp);
+ *       SMARTLIST_DEL_CURRENT(list, cp);
+ *     }
+ *   } SMARTLIST_FOREACH_END(cp);
+ * 
+ */ +/* Note: these macros use token pasting, and reach into smartlist internals. + * This can make them a little daunting. Here's the approximate unpacking of + * the above examples, for entertainment value: + * + *
+ * smartlist_t *list = smartlist_split("A:B:C", ":", 0, 0);
+ * {
+ *   int cp_sl_idx, cp_sl_len = smartlist_len(list);
+ *   char *cp;
+ *   for (cp_sl_idx = 0; cp_sl_idx < cp_sl_len; ++cp_sl_idx) {
+ *     cp = smartlist_get(list, cp_sl_idx);
+ *     printf("%d: %s\n", cp_sl_idx, cp);
+ *     tor_free(cp);
+ *   }
+ * }
+ * smartlist_free(list);
+ * 
+ * + *
+ * {
+ *   int cp_sl_idx, cp_sl_len = smartlist_len(list);
+ *   char *cp;
+ *   for (cp_sl_idx = 0; cp_sl_idx < cp_sl_len; ++cp_sl_idx) {
+ *     cp = smartlist_get(list, cp_sl_idx);
+ *     if (!strcmp(cp, "junk")) {
+ *       tor_free(cp);
+ *       smartlist_del(list, cp_sl_idx);
+ *       --cp_sl_idx;
+ *       --cp_sl_len;
+ *     }
+ *   }
+ * }
+ * 
+ */ +#define SMARTLIST_FOREACH_BEGIN(sl, type, var) \ + STMT_BEGIN \ + int var ## _sl_idx, var ## _sl_len=(sl)->num_used; \ + type var; \ + for (var ## _sl_idx = 0; var ## _sl_idx < var ## _sl_len; \ + ++var ## _sl_idx) { \ + var = (sl)->list[var ## _sl_idx]; + +#define SMARTLIST_FOREACH_END(var) \ + var = NULL; \ + } STMT_END + +/** + * An alias for SMARTLIST_FOREACH_BEGIN and SMARTLIST_FOREACH_END, using + * cmd as the loop body. This wrapper is here for convenience with + * very short loops. + * + * By convention, we do not use this for loops which nest, or for loops over + * 10 lines or so. Use SMARTLIST_FOREACH_{BEGIN,END} for those. + */ +#define SMARTLIST_FOREACH(sl, type, var, cmd) \ + SMARTLIST_FOREACH_BEGIN(sl,type,var) { \ + cmd; \ + } SMARTLIST_FOREACH_END(var) + +/** Helper: While in a SMARTLIST_FOREACH loop over the list sl indexed + * with the variable var, remove the current element in a way that + * won't confuse the loop. */ +#define SMARTLIST_DEL_CURRENT(sl, var) \ + STMT_BEGIN \ + smartlist_del(sl, var ## _sl_idx); \ + --var ## _sl_idx; \ + --var ## _sl_len; \ + STMT_END + +/** Helper: While in a SMARTLIST_FOREACH loop over the list sl indexed + * with the variable var, replace the current element with val. + * Does not deallocate the current value of var. + */ +#define SMARTLIST_REPLACE_CURRENT(sl, var, val) \ + STMT_BEGIN \ + smartlist_set(sl, var ## _sl_idx, val); \ + STMT_END + +/* Helper: Given two lists of items, possibly of different types, such that + * both lists are sorted on some common field (as determined by a comparison + * expression cmpexpr), and such that one list (sl1) has no + * duplicates on the common field, loop through the lists in lockstep, and + * execute unmatched_var2 on items in var2 that do not appear in + * var1. + * + * WARNING: It isn't safe to add remove elements from either list while the + * loop is in progress. + * + * Example use: + * SMARTLIST_FOREACH_JOIN(routerstatus_list, routerstatus_t *, rs, + * routerinfo_list, routerinfo_t *, ri, + * tor_memcmp(rs->identity_digest, ri->identity_digest, 20), + * log_info(LD_GENERAL,"No match for %s", ri->nickname)) { + * log_info(LD_GENERAL, "%s matches routerstatus %p", ri->nickname, rs); + * } SMARTLIST_FOREACH_JOIN_END(rs, ri); + **/ +/* The example above unpacks (approximately) to: + * int rs_sl_idx = 0, rs_sl_len = smartlist_len(routerstatus_list); + * int ri_sl_idx, ri_sl_len = smartlist_len(routerinfo_list); + * int rs_ri_cmp; + * routerstatus_t *rs; + * routerinfo_t *ri; + * for (; ri_sl_idx < ri_sl_len; ++ri_sl_idx) { + * ri = smartlist_get(routerinfo_list, ri_sl_idx); + * while (rs_sl_idx < rs_sl_len) { + * rs = smartlist_get(routerstatus_list, rs_sl_idx); + * rs_ri_cmp = tor_memcmp(rs->identity_digest, ri->identity_digest, 20); + * if (rs_ri_cmp > 0) { + * break; + * } else if (rs_ri_cmp == 0) { + * goto matched_ri; + * } else { + * ++rs_sl_idx; + * } + * } + * log_info(LD_GENERAL,"No match for %s", ri->nickname); + * continue; + * matched_ri: { + * log_info(LD_GENERAL,"%s matches with routerstatus %p",ri->nickname,rs); + * } + * } + */ +#define SMARTLIST_FOREACH_JOIN(sl1, type1, var1, sl2, type2, var2, \ + cmpexpr, unmatched_var2) \ + STMT_BEGIN \ + int var1 ## _sl_idx = 0, var1 ## _sl_len=(sl1)->num_used; \ + int var2 ## _sl_idx = 0, var2 ## _sl_len=(sl2)->num_used; \ + int var1 ## _ ## var2 ## _cmp; \ + type1 var1; \ + type2 var2; \ + for (; var2##_sl_idx < var2##_sl_len; ++var2##_sl_idx) { \ + var2 = (sl2)->list[var2##_sl_idx]; \ + while (var1##_sl_idx < var1##_sl_len) { \ + var1 = (sl1)->list[var1##_sl_idx]; \ + var1##_##var2##_cmp = (cmpexpr); \ + if (var1##_##var2##_cmp > 0) { \ + break; \ + } else if (var1##_##var2##_cmp == 0) { \ + goto matched_##var2; \ + } else { \ + ++var1##_sl_idx; \ + } \ + } \ + /* Ran out of v1, or no match for var2. */ \ + unmatched_var2; \ + continue; \ + matched_##var2: ; \ + +#define SMARTLIST_FOREACH_JOIN_END(var1, var2) \ + } \ + STMT_END + +#define DECLARE_MAP_FNS(maptype, keytype, prefix) \ + typedef struct maptype maptype; \ + typedef struct prefix##entry_t *prefix##iter_t; \ + maptype* prefix##new(void); \ + void* prefix##set(maptype *map, keytype key, void *val); \ + void* prefix##get(const maptype *map, keytype key); \ + void* prefix##remove(maptype *map, keytype key); \ + void prefix##free(maptype *map, void (*free_val)(void*)); \ + int prefix##isempty(const maptype *map); \ + int prefix##size(const maptype *map); \ + prefix##iter_t *prefix##iter_init(maptype *map); \ + prefix##iter_t *prefix##iter_next(maptype *map, prefix##iter_t *iter); \ + prefix##iter_t *prefix##iter_next_rmv(maptype *map, prefix##iter_t *iter); \ + void prefix##iter_get(prefix##iter_t *iter, keytype *keyp, void **valp); \ + int prefix##iter_done(prefix##iter_t *iter); \ + void prefix##assert_ok(const maptype *map) + +/* Map from const char * to void *. Implemented with a hash table. */ +DECLARE_MAP_FNS(strmap_t, const char *, strmap_); +/* Map from const char[DIGEST_LEN] to void *. Implemented with a hash table. */ +DECLARE_MAP_FNS(digestmap_t, const char *, digestmap_); + +#undef DECLARE_MAP_FNS + +/** Iterates over the key-value pairs in a map map in order. + * prefix is as for DECLARE_MAP_FNS (i.e., strmap_ or digestmap_). + * The map's keys and values are of type keytype and valtype respectively; + * each iteration assigns them to keyvar and valvar. + * + * Example use: + * MAP_FOREACH(digestmap_, m, const char *, k, routerinfo_t *, r) { + * // use k and r + * } MAP_FOREACH_END. + */ +/* Unpacks to, approximately: + * { + * digestmap_iter_t *k_iter; + * for (k_iter = digestmap_iter_init(m); !digestmap_iter_done(k_iter); + * k_iter = digestmap_iter_next(m, k_iter)) { + * const char *k; + * void *r_voidp; + * routerinfo_t *r; + * digestmap_iter_get(k_iter, &k, &r_voidp); + * r = r_voidp; + * // use k and r + * } + * } + */ +#define MAP_FOREACH(prefix, map, keytype, keyvar, valtype, valvar) \ + STMT_BEGIN \ + prefix##iter_t *keyvar##_iter; \ + for (keyvar##_iter = prefix##iter_init(map); \ + !prefix##iter_done(keyvar##_iter); \ + keyvar##_iter = prefix##iter_next(map, keyvar##_iter)) { \ + keytype keyvar; \ + void *valvar##_voidp; \ + valtype valvar; \ + prefix##iter_get(keyvar##_iter, &keyvar, &valvar##_voidp); \ + valvar = valvar##_voidp; + +/** As MAP_FOREACH, except allows members to be removed from the map + * during the iteration via MAP_DEL_CURRENT. Example use: + * + * Example use: + * MAP_FOREACH(digestmap_, m, const char *, k, routerinfo_t *, r) { + * if (is_very_old(r)) + * MAP_DEL_CURRENT(k); + * } MAP_FOREACH_END. + **/ +/* Unpacks to, approximately: + * { + * digestmap_iter_t *k_iter; + * int k_del=0; + * for (k_iter = digestmap_iter_init(m); !digestmap_iter_done(k_iter); + * k_iter = k_del ? digestmap_iter_next(m, k_iter) + * : digestmap_iter_next_rmv(m, k_iter)) { + * const char *k; + * void *r_voidp; + * routerinfo_t *r; + * k_del=0; + * digestmap_iter_get(k_iter, &k, &r_voidp); + * r = r_voidp; + * if (is_very_old(r)) { + * k_del = 1; + * } + * } + * } + */ +#define MAP_FOREACH_MODIFY(prefix, map, keytype, keyvar, valtype, valvar) \ + STMT_BEGIN \ + prefix##iter_t *keyvar##_iter; \ + int keyvar##_del=0; \ + for (keyvar##_iter = prefix##iter_init(map); \ + !prefix##iter_done(keyvar##_iter); \ + keyvar##_iter = keyvar##_del ? \ + prefix##iter_next_rmv(map, keyvar##_iter) : \ + prefix##iter_next(map, keyvar##_iter)) { \ + keytype keyvar; \ + void *valvar##_voidp; \ + valtype valvar; \ + keyvar##_del=0; \ + prefix##iter_get(keyvar##_iter, &keyvar, &valvar##_voidp); \ + valvar = valvar##_voidp; + +/** Used with MAP_FOREACH_MODIFY to remove the currently-iterated-upon + * member of the map. */ +#define MAP_DEL_CURRENT(keyvar) \ + STMT_BEGIN \ + keyvar##_del = 1; \ + STMT_END + +/** Used to end a MAP_FOREACH() block. */ +#define MAP_FOREACH_END } STMT_END ; + +/** As MAP_FOREACH, but does not require declaration of prefix or keytype. + * Example use: + * DIGESTMAP_FOREACH(m, k, routerinfo_t *, r) { + * // use k and r + * } DIGESTMAP_FOREACH_END. + */ +#define DIGESTMAP_FOREACH(map, keyvar, valtype, valvar) \ + MAP_FOREACH(digestmap_, map, const char *, keyvar, valtype, valvar) + +/** As MAP_FOREACH_MODIFY, but does not require declaration of prefix or + * keytype. + * Example use: + * DIGESTMAP_FOREACH_MODIFY(m, k, routerinfo_t *, r) { + * if (is_very_old(r)) + * MAP_DEL_CURRENT(k); + * } DIGESTMAP_FOREACH_END. + */ +#define DIGESTMAP_FOREACH_MODIFY(map, keyvar, valtype, valvar) \ + MAP_FOREACH_MODIFY(digestmap_, map, const char *, keyvar, valtype, valvar) +/** Used to end a DIGESTMAP_FOREACH() block. */ +#define DIGESTMAP_FOREACH_END MAP_FOREACH_END + +#define STRMAP_FOREACH(map, keyvar, valtype, valvar) \ + MAP_FOREACH(strmap_, map, const char *, keyvar, valtype, valvar) +#define STRMAP_FOREACH_MODIFY(map, keyvar, valtype, valvar) \ + MAP_FOREACH_MODIFY(strmap_, map, const char *, keyvar, valtype, valvar) +#define STRMAP_FOREACH_END MAP_FOREACH_END + +void* strmap_set_lc(strmap_t *map, const char *key, void *val); +void* strmap_get_lc(const strmap_t *map, const char *key); +void* strmap_remove_lc(strmap_t *map, const char *key); + +#define DECLARE_TYPED_DIGESTMAP_FNS(prefix, maptype, valtype) \ + typedef struct maptype maptype; \ + typedef struct prefix##iter_t prefix##iter_t; \ + static INLINE maptype* prefix##new(void) \ + { \ + return (maptype*)digestmap_new(); \ + } \ + static INLINE digestmap_t* prefix##to_digestmap(maptype *map) \ + { \ + return (digestmap_t*)map; \ + } \ + static INLINE valtype* prefix##get(maptype *map, const char *key) \ + { \ + return (valtype*)digestmap_get((digestmap_t*)map, key); \ + } \ + static INLINE valtype* prefix##set(maptype *map, const char *key, \ + valtype *val) \ + { \ + return (valtype*)digestmap_set((digestmap_t*)map, key, val); \ + } \ + static INLINE valtype* prefix##remove(maptype *map, const char *key) \ + { \ + return (valtype*)digestmap_remove((digestmap_t*)map, key); \ + } \ + static INLINE void prefix##free(maptype *map, void (*free_val)(void*)) \ + { \ + digestmap_free((digestmap_t*)map, free_val); \ + } \ + static INLINE int prefix##isempty(maptype *map) \ + { \ + return digestmap_isempty((digestmap_t*)map); \ + } \ + static INLINE int prefix##size(maptype *map) \ + { \ + return digestmap_size((digestmap_t*)map); \ + } \ + static INLINE prefix##iter_t *prefix##iter_init(maptype *map) \ + { \ + return (prefix##iter_t*) digestmap_iter_init((digestmap_t*)map); \ + } \ + static INLINE prefix##iter_t *prefix##iter_next(maptype *map, \ + prefix##iter_t *iter) \ + { \ + return (prefix##iter_t*) digestmap_iter_next( \ + (digestmap_t*)map, (digestmap_iter_t*)iter); \ + } \ + static INLINE prefix##iter_t *prefix##iter_next_rmv(maptype *map, \ + prefix##iter_t *iter) \ + { \ + return (prefix##iter_t*) digestmap_iter_next_rmv( \ + (digestmap_t*)map, (digestmap_iter_t*)iter); \ + } \ + static INLINE void prefix##iter_get(prefix##iter_t *iter, \ + const char **keyp, \ + valtype **valp) \ + { \ + void *v; \ + digestmap_iter_get((digestmap_iter_t*) iter, keyp, &v); \ + *valp = v; \ + } \ + static INLINE int prefix##iter_done(prefix##iter_t *iter) \ + { \ + return digestmap_iter_done((digestmap_iter_t*)iter); \ + } + +#if SIZEOF_INT == 4 +#define BITARRAY_SHIFT 5 +#elif SIZEOF_INT == 8 +#define BITARRAY_SHIFT 6 +#else +#error "int is neither 4 nor 8 bytes. I can't deal with that." +#endif +#define BITARRAY_MASK ((1u<n_bits
bits. */ +static INLINE bitarray_t * +bitarray_init_zero(unsigned int n_bits) +{ + /* round up to the next int. */ + size_t sz = (n_bits+BITARRAY_MASK) >> BITARRAY_SHIFT; + return tor_malloc_zero(sz*sizeof(unsigned int)); +} +/** Expand ba from holding n_bits_old to n_bits_new, + * clearing all new bits. Returns a possibly changed pointer to the + * bitarray. */ +static INLINE bitarray_t * +bitarray_expand(bitarray_t *ba, + unsigned int n_bits_old, unsigned int n_bits_new) +{ + size_t sz_old = (n_bits_old+BITARRAY_MASK) >> BITARRAY_SHIFT; + size_t sz_new = (n_bits_new+BITARRAY_MASK) >> BITARRAY_SHIFT; + char *ptr; + if (sz_new <= sz_old) + return ba; + ptr = tor_realloc(ba, sz_new*sizeof(unsigned int)); + /* This memset does nothing to the older excess bytes. But they were + * already set to 0 by bitarry_init_zero. */ + memset(ptr+sz_old*sizeof(unsigned int), 0, + (sz_new-sz_old)*sizeof(unsigned int)); + return (bitarray_t*) ptr; +} +/** Free the bit array ba. */ +static INLINE void +bitarray_free(bitarray_t *ba) +{ + tor_free(ba); +} +/** Set the bitth bit in b to 1. */ +static INLINE void +bitarray_set(bitarray_t *b, int bit) +{ + b[bit >> BITARRAY_SHIFT] |= (1u << (bit & BITARRAY_MASK)); +} +/** Set the bitth bit in b to 0. */ +static INLINE void +bitarray_clear(bitarray_t *b, int bit) +{ + b[bit >> BITARRAY_SHIFT] &= ~ (1u << (bit & BITARRAY_MASK)); +} +/** Return true iff bitth bit in b is nonzero. NOTE: does + * not necessarily return 1 on true. */ +static INLINE unsigned int +bitarray_is_set(bitarray_t *b, int bit) +{ + return b[bit >> BITARRAY_SHIFT] & (1u << (bit & BITARRAY_MASK)); +} + +/** A set of digests, implemented as a Bloom filter. */ +typedef struct { + int mask; /**< One less than the number of bits in ba; always one less + * than a power of two. */ + bitarray_t *ba; /**< A bit array to implement the Bloom filter. */ +} digestset_t; + +#define BIT(n) ((n) & set->mask) +/** Add the digest digest to set. */ +static INLINE void +digestset_add(digestset_t *set, const char *digest) +{ + const uint32_t *p = (const uint32_t *)digest; + const uint32_t d1 = p[0] + (p[1]>>16); + const uint32_t d2 = p[1] + (p[2]>>16); + const uint32_t d3 = p[2] + (p[3]>>16); + const uint32_t d4 = p[3] + (p[0]>>16); + bitarray_set(set->ba, BIT(d1)); + bitarray_set(set->ba, BIT(d2)); + bitarray_set(set->ba, BIT(d3)); + bitarray_set(set->ba, BIT(d4)); +} + +/** If digest is in set, return nonzero. Otherwise, + * probably return zero. */ +static INLINE int +digestset_contains(const digestset_t *set, const char *digest) +{ + const uint32_t *p = (const uint32_t *)digest; + const uint32_t d1 = p[0] + (p[1]>>16); + const uint32_t d2 = p[1] + (p[2]>>16); + const uint32_t d3 = p[2] + (p[3]>>16); + const uint32_t d4 = p[3] + (p[0]>>16); + return bitarray_is_set(set->ba, BIT(d1)) && + bitarray_is_set(set->ba, BIT(d2)) && + bitarray_is_set(set->ba, BIT(d3)) && + bitarray_is_set(set->ba, BIT(d4)); +} +#undef BIT + +digestset_t *digestset_new(int max_elements); +void digestset_free(digestset_t* set); + +/* These functions, given an array of n_elements, return the + * nth lowest element. nth=0 gives the lowest element; + * n_elements-1 gives the highest; and (n_elements-1) / 2 gives + * the median. As a side effect, the elements of array are sorted. */ +int find_nth_int(int *array, int n_elements, int nth); +time_t find_nth_time(time_t *array, int n_elements, int nth); +double find_nth_double(double *array, int n_elements, int nth); +int32_t find_nth_int32(int32_t *array, int n_elements, int nth); +uint32_t find_nth_uint32(uint32_t *array, int n_elements, int nth); +long find_nth_long(long *array, int n_elements, int nth); +static INLINE int +median_int(int *array, int n_elements) +{ + return find_nth_int(array, n_elements, (n_elements-1)/2); +} +static INLINE time_t +median_time(time_t *array, int n_elements) +{ + return find_nth_time(array, n_elements, (n_elements-1)/2); +} +static INLINE double +median_double(double *array, int n_elements) +{ + return find_nth_double(array, n_elements, (n_elements-1)/2); +} +static INLINE uint32_t +median_uint32(uint32_t *array, int n_elements) +{ + return find_nth_uint32(array, n_elements, (n_elements-1)/2); +} +static INLINE int32_t +median_int32(int32_t *array, int n_elements) +{ + return find_nth_int32(array, n_elements, (n_elements-1)/2); +} + +#endif + diff --git a/src/tor/control.c b/src/tor/control.c new file mode 100644 index 0000000..cba8a69 --- /dev/null +++ b/src/tor/control.c @@ -0,0 +1,5110 @@ +/* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file control.c + * \brief Implementation for Tor's control-socket interface. + * See doc/spec/control-spec.txt for full details on protocol. + **/ + +#define CONTROL_PRIVATE + +#include "or.h" +#include "addressmap.h" +#include "buffers.h" +#include "channel.h" +#include "channeltls.h" +#include "circuitbuild.h" +#include "circuitlist.h" +#include "circuitstats.h" +#include "circuituse.h" +#include "command.h" +#include "config.h" +#include "confparse.h" +#include "connection.h" +#include "connection_edge.h" +#include "connection_or.h" +#include "control.h" +#include "directory.h" +#include "dirserv.h" +#include "dnsserv.h" +#include "entrynodes.h" +#include "geoip.h" +#include "hibernate.h" +#include "onion_main.h" +#include "networkstatus.h" +#include "nodelist.h" +#include "policies.h" +#include "reasons.h" +#include "rephist.h" +#include "router.h" +#include "routerlist.h" +#include "routerparse.h" + +#ifndef _WIN32 +#include +#include +#endif + +#include "procmon.h" + +/** Yield true iff s is the state of a control_connection_t that has + * finished authentication and is accepting commands. */ +#define STATE_IS_OPEN(s) ((s) == CONTROL_CONN_STATE_OPEN) + +/** Bitfield: The bit 1<<e is set if any open control + * connection is interested in events of type e. We use this + * so that we can decide to skip generating event messages that nobody + * has interest in without having to walk over the global connection + * list to find out. + **/ +typedef uint64_t event_mask_t; + +/** An event mask of all the events that any controller is interested in + * receiving. */ +static event_mask_t global_event_mask = 0; + +/** True iff we have disabled log messages from being sent to the controller */ +static int disable_log_messages = 0; + +/** Macro: true if any control connection is interested in events of type + * e. */ +#define EVENT_IS_INTERESTING(e) \ + (!! (global_event_mask & (((uint64_t)1)<<(e)))) + +/** If we're using cookie-type authentication, how long should our cookies be? + */ +#define AUTHENTICATION_COOKIE_LEN 32 + +/** If true, we've set authentication_cookie to a secret code and + * stored it to disk. */ +static int authentication_cookie_is_set = 0; +/** If authentication_cookie_is_set, a secret cookie that we've stored to disk + * and which we're using to authenticate controllers. (If the controller can + * read it off disk, it has permission to connect.) */ +static uint8_t *authentication_cookie = NULL; + +#define SAFECOOKIE_SERVER_TO_CONTROLLER_CONSTANT \ + "Tor safe cookie authentication server-to-controller hash" +#define SAFECOOKIE_CONTROLLER_TO_SERVER_CONSTANT \ + "Tor safe cookie authentication controller-to-server hash" +#define SAFECOOKIE_SERVER_NONCE_LEN DIGEST256_LEN + +/** A sufficiently large size to record the last bootstrap phase string. */ +#define BOOTSTRAP_MSG_LEN 1024 + +/** What was the last bootstrap phase message we sent? We keep track + * of this so we can respond to getinfo status/bootstrap-phase queries. */ +static char last_sent_bootstrap_message[BOOTSTRAP_MSG_LEN]; + +static void connection_printf_to_buf(control_connection_t *conn, + const char *format, ...) + CHECK_PRINTF(2,3); +static void send_control_event_impl(uint16_t event, event_format_t which, + const char *format, va_list ap) + CHECK_PRINTF(3,0); +static int control_event_status(int type, int severity, const char *format, + va_list args) + CHECK_PRINTF(3,0); + +static void send_control_done(control_connection_t *conn); +static void send_control_event(uint16_t event, event_format_t which, + const char *format, ...) + CHECK_PRINTF(3,4); +static int handle_control_setconf(control_connection_t *conn, uint32_t len, + char *body); +static int handle_control_resetconf(control_connection_t *conn, uint32_t len, + char *body); +static int handle_control_getconf(control_connection_t *conn, uint32_t len, + const char *body); +static int handle_control_loadconf(control_connection_t *conn, uint32_t len, + const char *body); +static int handle_control_setevents(control_connection_t *conn, uint32_t len, + const char *body); +static int handle_control_authenticate(control_connection_t *conn, + uint32_t len, + const char *body); +static int handle_control_signal(control_connection_t *conn, uint32_t len, + const char *body); +static int handle_control_mapaddress(control_connection_t *conn, uint32_t len, + const char *body); +static char *list_getinfo_options(void); +static int handle_control_getinfo(control_connection_t *conn, uint32_t len, + const char *body); +static int handle_control_extendcircuit(control_connection_t *conn, + uint32_t len, + const char *body); +static int handle_control_setcircuitpurpose(control_connection_t *conn, + uint32_t len, const char *body); +static int handle_control_attachstream(control_connection_t *conn, + uint32_t len, + const char *body); +static int handle_control_postdescriptor(control_connection_t *conn, + uint32_t len, + const char *body); +static int handle_control_redirectstream(control_connection_t *conn, + uint32_t len, + const char *body); +static int handle_control_closestream(control_connection_t *conn, uint32_t len, + const char *body); +static int handle_control_closecircuit(control_connection_t *conn, + uint32_t len, + const char *body); +static int handle_control_resolve(control_connection_t *conn, uint32_t len, + const char *body); +static int handle_control_usefeature(control_connection_t *conn, + uint32_t len, + const char *body); +static int write_stream_target_to_buf(entry_connection_t *conn, char *buf, + size_t len); +static void orconn_target_get_name(char *buf, size_t len, + or_connection_t *conn); +static char *get_cookie_file(void); + +/** Given a control event code for a message event, return the corresponding + * log severity. */ +static INLINE int +event_to_log_severity(int event) +{ + switch (event) { + case EVENT_DEBUG_MSG: return LOG_DEBUG; + case EVENT_INFO_MSG: return LOG_INFO; + case EVENT_NOTICE_MSG: return LOG_NOTICE; + case EVENT_WARN_MSG: return LOG_WARN; + case EVENT_ERR_MSG: return LOG_ERR; + default: return -1; + } +} + +/** Given a log severity, return the corresponding control event code. */ +static INLINE int +log_severity_to_event(int severity) +{ + switch (severity) { + case LOG_DEBUG: return EVENT_DEBUG_MSG; + case LOG_INFO: return EVENT_INFO_MSG; + case LOG_NOTICE: return EVENT_NOTICE_MSG; + case LOG_WARN: return EVENT_WARN_MSG; + case LOG_ERR: return EVENT_ERR_MSG; + default: return -1; + } +} + +/** Helper: clear bandwidth counters of all origin circuits. */ +static void +clear_circ_bw_fields(void) +{ + circuit_t *circ; + origin_circuit_t *ocirc; + TOR_LIST_FOREACH(circ, circuit_get_global_list(), head) { + if (!CIRCUIT_IS_ORIGIN(circ)) + continue; + ocirc = TO_ORIGIN_CIRCUIT(circ); + ocirc->n_written_circ_bw = ocirc->n_read_circ_bw = 0; + } +} + +/** Set global_event_mask* to the bitwise OR of each live control + * connection's event_mask field. */ +void +control_update_global_event_mask(void) +{ + smartlist_t *conns = get_connection_array(); + event_mask_t old_mask, new_mask; + old_mask = global_event_mask; + + global_event_mask = 0; + SMARTLIST_FOREACH(conns, connection_t *, _conn, + { + if (_conn->type == CONN_TYPE_CONTROL && + STATE_IS_OPEN(_conn->state)) { + control_connection_t *conn = TO_CONTROL_CONN(_conn); + global_event_mask |= conn->event_mask; + } + }); + + new_mask = global_event_mask; + + /* Handle the aftermath. Set up the log callback to tell us only what + * we want to hear...*/ + control_adjust_event_log_severity(); + + /* ...then, if we've started logging stream or circ bw, clear the + * appropriate fields. */ + if (! (old_mask & EVENT_STREAM_BANDWIDTH_USED) && + (new_mask & EVENT_STREAM_BANDWIDTH_USED)) { + SMARTLIST_FOREACH(conns, connection_t *, conn, + { + if (conn->type == CONN_TYPE_AP) { + edge_connection_t *edge_conn = TO_EDGE_CONN(conn); + edge_conn->n_written = edge_conn->n_read = 0; + } + }); + } + if (! (old_mask & EVENT_CIRC_BANDWIDTH_USED) && + (new_mask & EVENT_CIRC_BANDWIDTH_USED)) { + clear_circ_bw_fields(); + } +} + +/** Adjust the log severities that result in control_event_logmsg being called + * to match the severity of log messages that any controllers are interested + * in. */ +void +control_adjust_event_log_severity(void) +{ + int i; + int min_log_event=EVENT_ERR_MSG, max_log_event=EVENT_DEBUG_MSG; + + for (i = EVENT_DEBUG_MSG; i <= EVENT_ERR_MSG; ++i) { + if (EVENT_IS_INTERESTING(i)) { + min_log_event = i; + break; + } + } + for (i = EVENT_ERR_MSG; i >= EVENT_DEBUG_MSG; --i) { + if (EVENT_IS_INTERESTING(i)) { + max_log_event = i; + break; + } + } + if (EVENT_IS_INTERESTING(EVENT_STATUS_GENERAL)) { + if (min_log_event > EVENT_NOTICE_MSG) + min_log_event = EVENT_NOTICE_MSG; + if (max_log_event < EVENT_ERR_MSG) + max_log_event = EVENT_ERR_MSG; + } + if (min_log_event <= max_log_event) + change_callback_log_severity(event_to_log_severity(min_log_event), + event_to_log_severity(max_log_event), + control_event_logmsg); + else + change_callback_log_severity(LOG_ERR, LOG_ERR, + control_event_logmsg); +} + +/** Return true iff the event with code c is being sent to any current + * control connection. This is useful if the amount of work needed to prepare + * to call the appropriate control_event_...() function is high. + */ +int +control_event_is_interesting(int event) +{ + return EVENT_IS_INTERESTING(event); +} + +/** Append a NUL-terminated string s to the end of + * conn-\>outbuf. + */ +static INLINE void +connection_write_str_to_buf(const char *s, control_connection_t *conn) +{ + size_t len = strlen(s); + connection_write_to_buf(s, len, TO_CONN(conn)); +} + +/** Given a len-character string in data, made of lines + * terminated by CRLF, allocate a new string in *out, and copy the + * contents of data into *out, adding a period before any period + * that appears at the start of a line, and adding a period-CRLF line at + * the end. Replace all LF characters sequences with CRLF. Return the number + * of bytes in *out. + */ +STATIC size_t +write_escaped_data(const char *data, size_t len, char **out) +{ + size_t sz_out = len+8; + char *outp; + const char *start = data, *end; + int i; + int start_of_line; + for (i=0; i<(int)len; ++i) { + if (data[i]== '\n') + sz_out += 2; /* Maybe add a CR; maybe add a dot. */ + } + *out = outp = tor_malloc(sz_out+1); + end = data+len; + start_of_line = 1; + while (data < end) { + if (*data == '\n') { + if (data > start && data[-1] != '\r') + *outp++ = '\r'; + start_of_line = 1; + } else if (*data == '.') { + if (start_of_line) { + start_of_line = 0; + *outp++ = '.'; + } + } else { + start_of_line = 0; + } + *outp++ = *data++; + } + if (outp < *out+2 || fast_memcmp(outp-2, "\r\n", 2)) { + *outp++ = '\r'; + *outp++ = '\n'; + } + *outp++ = '.'; + *outp++ = '\r'; + *outp++ = '\n'; + *outp = '\0'; /* NUL-terminate just in case. */ + tor_assert((outp - *out) <= (int)sz_out); + return outp - *out; +} + +/** Given a len-character string in data, made of lines + * terminated by CRLF, allocate a new string in *out, and copy + * the contents of data into *out, removing any period + * that appears at the start of a line, and replacing all CRLF sequences + * with LF. Return the number of + * bytes in *out. */ +STATIC size_t +read_escaped_data(const char *data, size_t len, char **out) +{ + char *outp; + const char *next; + const char *end; + + *out = outp = tor_malloc(len+1); + + end = data+len; + + while (data < end) { + /* we're at the start of a line. */ + if (*data == '.') + ++data; + next = memchr(data, '\n', end-data); + if (next) { + size_t n_to_copy = next-data; + /* Don't copy a CR that precedes this LF. */ + if (n_to_copy && *(next-1) == '\r') + --n_to_copy; + memcpy(outp, data, n_to_copy); + outp += n_to_copy; + data = next+1; /* This will point at the start of the next line, + * or the end of the string, or a period. */ + } else { + memcpy(outp, data, end-data); + outp += (end-data); + *outp = '\0'; + return outp - *out; + } + *outp++ = '\n'; + } + + *outp = '\0'; + return outp - *out; +} + +/** If the first in_len_max characters in start contain a + * double-quoted string with escaped characters, return the length of that + * string (as encoded, including quotes). Otherwise return -1. */ +static INLINE int +get_escaped_string_length(const char *start, size_t in_len_max, + int *chars_out) +{ + const char *cp, *end; + int chars = 0; + + if (*start != '\"') + return -1; + + cp = start+1; + end = start+in_len_max; + + /* Calculate length. */ + while (1) { + if (cp >= end) { + return -1; /* Too long. */ + } else if (*cp == '\\') { + if (++cp == end) + return -1; /* Can't escape EOS. */ + ++cp; + ++chars; + } else if (*cp == '\"') { + break; + } else { + ++cp; + ++chars; + } + } + if (chars_out) + *chars_out = chars; + return (int)(cp - start+1); +} + +/** As decode_escaped_string, but does not decode the string: copies the + * entire thing, including quotation marks. */ +static const char * +extract_escaped_string(const char *start, size_t in_len_max, + char **out, size_t *out_len) +{ + int length = get_escaped_string_length(start, in_len_max, NULL); + if (length<0) + return NULL; + *out_len = length; + *out = tor_strndup(start, *out_len); + return start+length; +} + +/** Given a pointer to a string starting at start containing + * in_len_max characters, decode a string beginning with one double + * quote, containing any number of non-quote characters or characters escaped + * with a backslash, and ending with a final double quote. Place the resulting + * string (unquoted, unescaped) into a newly allocated string in *out; + * store its length in out_len. On success, return a pointer to the + * character immediately following the escaped string. On failure, return + * NULL. */ +static const char * +decode_escaped_string(const char *start, size_t in_len_max, + char **out, size_t *out_len) +{ + const char *cp, *end; + char *outp; + int len, n_chars = 0; + + len = get_escaped_string_length(start, in_len_max, &n_chars); + if (len<0) + return NULL; + + end = start+len-1; /* Index of last quote. */ + tor_assert(*end == '\"'); + outp = *out = tor_malloc(len+1); + *out_len = n_chars; + + cp = start+1; + while (cp < end) { + if (*cp == '\\') + ++cp; + *outp++ = *cp++; + } + *outp = '\0'; + tor_assert((outp - *out) == (int)*out_len); + + return end+1; +} + +/** Acts like sprintf, but writes its formatted string to the end of + * conn-\>outbuf. */ +static void +connection_printf_to_buf(control_connection_t *conn, const char *format, ...) +{ + va_list ap; + char *buf = NULL; + int len; + + va_start(ap,format); + len = tor_vasprintf(&buf, format, ap); + va_end(ap); + + if (len < 0) { + log_err(LD_BUG, "Unable to format string for controller."); + tor_assert(0); + } + + connection_write_to_buf(buf, (size_t)len, TO_CONN(conn)); + + tor_free(buf); +} + +/** Write all of the open control ports to ControlPortWriteToFile */ +void +control_ports_write_to_file(void) +{ + smartlist_t *lines; + char *joined = NULL; + const or_options_t *options = get_options(); + + if (!options->ControlPortWriteToFile) + return; + + lines = smartlist_new(); + + SMARTLIST_FOREACH_BEGIN(get_connection_array(), const connection_t *, conn) { + if (conn->type != CONN_TYPE_CONTROL_LISTENER || conn->marked_for_close) + continue; +#ifdef AF_UNIX + if (conn->socket_family == AF_UNIX) { + smartlist_add_asprintf(lines, "UNIX_PORT=%s\n", conn->address); + continue; + } +#endif + smartlist_add_asprintf(lines, "PORT=%s:%d\n", conn->address, conn->port); + } SMARTLIST_FOREACH_END(conn); + + joined = smartlist_join_strings(lines, "", 0, NULL); + + if (write_str_to_file(options->ControlPortWriteToFile, joined, 0) < 0) { + log_warn(LD_CONTROL, "Writing %s failed: %s", + options->ControlPortWriteToFile, strerror(errno)); + } +#ifndef _WIN32 + if (options->ControlPortFileGroupReadable) { + if (chmod(options->ControlPortWriteToFile, 0640)) { + log_warn(LD_FS,"Unable to make %s group-readable.", + options->ControlPortWriteToFile); + } + } +#endif + tor_free(joined); + SMARTLIST_FOREACH(lines, char *, cp, tor_free(cp)); + smartlist_free(lines); +} + +/** Send a "DONE" message down the control connection conn. */ +static void +send_control_done(control_connection_t *conn) +{ + connection_write_str_to_buf("250 OK\r\n", conn); +} + +/** Send an event to all v1 controllers that are listening for code + * event. The event's body is given by msg. + * + * If which & SHORT_NAMES, the event contains short-format names: send + * it to controllers that haven't enabled the VERBOSE_NAMES feature. If + * which & LONG_NAMES, the event contains long-format names: send it + * to controllers that have enabled VERBOSE_NAMES. + * + * The EXTENDED_FORMAT and NONEXTENDED_FORMAT flags behave similarly with + * respect to the EXTENDED_EVENTS feature. */ +MOCK_IMPL(STATIC void, +send_control_event_string,(uint16_t event, event_format_t which, + const char *msg)) +{ + smartlist_t *conns = get_connection_array(); + (void)which; + tor_assert(event >= EVENT_MIN_ && event <= EVENT_MAX_); + + SMARTLIST_FOREACH_BEGIN(conns, connection_t *, conn) { + if (conn->type == CONN_TYPE_CONTROL && + !conn->marked_for_close && + conn->state == CONTROL_CONN_STATE_OPEN) { + control_connection_t *control_conn = TO_CONTROL_CONN(conn); + + if (control_conn->event_mask & (1<event
. The event's body is created by the printf-style format in + * format, and other arguments as provided. */ +static void +send_control_event_impl(uint16_t event, event_format_t which, + const char *format, va_list ap) +{ + char *buf = NULL; + int len; + + len = tor_vasprintf(&buf, format, ap); + if (len < 0) { + log_warn(LD_BUG, "Unable to format event for controller."); + return; + } + + send_control_event_string(event, which|ALL_FORMATS, buf); + + tor_free(buf); +} + +/** Send an event to all v1 controllers that are listening for code + * event. The event's body is created by the printf-style format in + * format, and other arguments as provided. */ +static void +send_control_event(uint16_t event, event_format_t which, + const char *format, ...) +{ + va_list ap; + va_start(ap, format); + send_control_event_impl(event, which, format, ap); + va_end(ap); +} + +/** Given a text circuit id, return the corresponding circuit. */ +static origin_circuit_t * +get_circ(const char *id) +{ + uint32_t n_id; + int ok; + n_id = (uint32_t) tor_parse_ulong(id, 10, 0, UINT32_MAX, &ok, NULL); + if (!ok) + return NULL; + return circuit_get_by_global_id(n_id); +} + +/** Given a text stream id, return the corresponding AP connection. */ +static entry_connection_t * +get_stream(const char *id) +{ + uint64_t n_id; + int ok; + connection_t *conn; + n_id = tor_parse_uint64(id, 10, 0, UINT64_MAX, &ok, NULL); + if (!ok) + return NULL; + conn = connection_get_by_global_id(n_id); + if (!conn || conn->type != CONN_TYPE_AP || conn->marked_for_close) + return NULL; + return TO_ENTRY_CONN(conn); +} + +/** Helper for setconf and resetconf. Acts like setconf, except + * it passes use_defaults on to options_trial_assign(). Modifies the + * contents of body. + */ +static int +control_setconf_helper(control_connection_t *conn, uint32_t len, char *body, + int use_defaults) +{ + setopt_err_t opt_err; + config_line_t *lines=NULL; + char *start = body; + char *errstring = NULL; + const int clear_first = 1; + + char *config; + smartlist_t *entries = smartlist_new(); + + /* We have a string, "body", of the format '(key(=val|="val")?)' entries + * separated by space. break it into a list of configuration entries. */ + while (*body) { + char *eq = body; + char *key; + char *entry; + while (!TOR_ISSPACE(*eq) && *eq != '=') + ++eq; + key = tor_strndup(body, eq-body); + body = eq+1; + if (*eq == '=') { + char *val=NULL; + size_t val_len=0; + if (*body != '\"') { + char *val_start = body; + while (!TOR_ISSPACE(*body)) + body++; + val = tor_strndup(val_start, body-val_start); + val_len = strlen(val); + } else { + body = (char*)extract_escaped_string(body, (len - (body-start)), + &val, &val_len); + if (!body) { + connection_write_str_to_buf("551 Couldn't parse string\r\n", conn); + SMARTLIST_FOREACH(entries, char *, cp, tor_free(cp)); + smartlist_free(entries); + tor_free(key); + return 0; + } + } + tor_asprintf(&entry, "%s %s", key, val); + tor_free(key); + tor_free(val); + } else { + entry = key; + } + smartlist_add(entries, entry); + while (TOR_ISSPACE(*body)) + ++body; + } + + smartlist_add(entries, tor_strdup("")); + config = smartlist_join_strings(entries, "\n", 0, NULL); + SMARTLIST_FOREACH(entries, char *, cp, tor_free(cp)); + smartlist_free(entries); + + if (config_get_lines(config, &lines, 0) < 0) { + log_warn(LD_CONTROL,"Controller gave us config lines we can't parse."); + connection_write_str_to_buf("551 Couldn't parse configuration\r\n", + conn); + tor_free(config); + return 0; + } + tor_free(config); + + opt_err = options_trial_assign(lines, use_defaults, clear_first, &errstring); + { + const char *msg; + switch (opt_err) { + case SETOPT_ERR_MISC: + msg = "552 Unrecognized option"; + break; + case SETOPT_ERR_PARSE: + msg = "513 Unacceptable option value"; + break; + case SETOPT_ERR_TRANSITION: + msg = "553 Transition not allowed"; + break; + case SETOPT_ERR_SETTING: + default: + msg = "553 Unable to set option"; + break; + case SETOPT_OK: + config_free_lines(lines); + send_control_done(conn); + return 0; + } + log_warn(LD_CONTROL, + "Controller gave us config lines that didn't validate: %s", + errstring); + connection_printf_to_buf(conn, "%s: %s\r\n", msg, errstring); + config_free_lines(lines); + tor_free(errstring); + return 0; + } +} + +/** Called when we receive a SETCONF message: parse the body and try + * to update our configuration. Reply with a DONE or ERROR message. + * Modifies the contents of body.*/ +static int +handle_control_setconf(control_connection_t *conn, uint32_t len, char *body) +{ + return control_setconf_helper(conn, len, body, 0); +} + +/** Called when we receive a RESETCONF message: parse the body and try + * to update our configuration. Reply with a DONE or ERROR message. + * Modifies the contents of body. */ +static int +handle_control_resetconf(control_connection_t *conn, uint32_t len, char *body) +{ + return control_setconf_helper(conn, len, body, 1); +} + +/** Called when we receive a GETCONF message. Parse the request, and + * reply with a CONFVALUE or an ERROR message */ +static int +handle_control_getconf(control_connection_t *conn, uint32_t body_len, + const char *body) +{ + smartlist_t *questions = smartlist_new(); + smartlist_t *answers = smartlist_new(); + smartlist_t *unrecognized = smartlist_new(); + char *msg = NULL; + size_t msg_len; + const or_options_t *options = get_options(); + int i, len; + + (void) body_len; /* body is NUL-terminated; so we can ignore len. */ + smartlist_split_string(questions, body, " ", + SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); + SMARTLIST_FOREACH_BEGIN(questions, const char *, q) { + if (!option_is_recognized(q)) { + smartlist_add(unrecognized, (char*) q); + } else { + config_line_t *answer = option_get_assignment(options,q); + if (!answer) { + const char *name = option_get_canonical_name(q); + smartlist_add_asprintf(answers, "250-%s\r\n", name); + } + + while (answer) { + config_line_t *next; + smartlist_add_asprintf(answers, "250-%s=%s\r\n", + answer->key, answer->value); + + next = answer->next; + tor_free(answer->key); + tor_free(answer->value); + tor_free(answer); + answer = next; + } + } + } SMARTLIST_FOREACH_END(q); + + if ((len = smartlist_len(unrecognized))) { + for (i=0; i < len-1; ++i) + connection_printf_to_buf(conn, + "552-Unrecognized configuration key \"%s\"\r\n", + (char*)smartlist_get(unrecognized, i)); + connection_printf_to_buf(conn, + "552 Unrecognized configuration key \"%s\"\r\n", + (char*)smartlist_get(unrecognized, len-1)); + } else if ((len = smartlist_len(answers))) { + char *tmp = smartlist_get(answers, len-1); + tor_assert(strlen(tmp)>4); + tmp[3] = ' '; + msg = smartlist_join_strings(answers, "", 0, &msg_len); + connection_write_to_buf(msg, msg_len, TO_CONN(conn)); + } else { + connection_write_str_to_buf("250 OK\r\n", conn); + } + + SMARTLIST_FOREACH(answers, char *, cp, tor_free(cp)); + smartlist_free(answers); + SMARTLIST_FOREACH(questions, char *, cp, tor_free(cp)); + smartlist_free(questions); + smartlist_free(unrecognized); + + tor_free(msg); + + return 0; +} + +/** Called when we get a +LOADCONF message. */ +static int +handle_control_loadconf(control_connection_t *conn, uint32_t len, + const char *body) +{ + setopt_err_t retval; + char *errstring = NULL; + const char *msg = NULL; + (void) len; + + retval = options_init_from_string(NULL, body, CMD_RUN_TOR, NULL, &errstring); + + if (retval != SETOPT_OK) + log_warn(LD_CONTROL, + "Controller gave us config file that didn't validate: %s", + errstring); + + switch (retval) { + case SETOPT_ERR_PARSE: + msg = "552 Invalid config file"; + break; + case SETOPT_ERR_TRANSITION: + msg = "553 Transition not allowed"; + break; + case SETOPT_ERR_SETTING: + msg = "553 Unable to set option"; + break; + case SETOPT_ERR_MISC: + default: + msg = "550 Unable to load config"; + break; + case SETOPT_OK: + break; + } + if (msg) { + if (errstring) + connection_printf_to_buf(conn, "%s: %s\r\n", msg, errstring); + else + connection_printf_to_buf(conn, "%s\r\n", msg); + } else { + send_control_done(conn); + } + tor_free(errstring); + return 0; +} + +/** Helper structure: maps event values to their names. */ +struct control_event_t { + uint16_t event_code; + const char *event_name; +}; +/** Table mapping event values to their names. Used to implement SETEVENTS + * and GETINFO events/names, and to keep they in sync. */ +static const struct control_event_t control_event_table[] = { + { EVENT_CIRCUIT_STATUS, "CIRC" }, + { EVENT_CIRCUIT_STATUS_MINOR, "CIRC_MINOR" }, + { EVENT_STREAM_STATUS, "STREAM" }, + { EVENT_OR_CONN_STATUS, "ORCONN" }, + { EVENT_BANDWIDTH_USED, "BW" }, + { EVENT_DEBUG_MSG, "DEBUG" }, + { EVENT_INFO_MSG, "INFO" }, + { EVENT_NOTICE_MSG, "NOTICE" }, + { EVENT_WARN_MSG, "WARN" }, + { EVENT_ERR_MSG, "ERR" }, + { EVENT_NEW_DESC, "NEWDESC" }, + { EVENT_ADDRMAP, "ADDRMAP" }, + { EVENT_AUTHDIR_NEWDESCS, "AUTHDIR_NEWDESCS" }, + { EVENT_DESCCHANGED, "DESCCHANGED" }, + { EVENT_NS, "NS" }, + { EVENT_STATUS_GENERAL, "STATUS_GENERAL" }, + { EVENT_STATUS_CLIENT, "STATUS_CLIENT" }, + { EVENT_STATUS_SERVER, "STATUS_SERVER" }, + { EVENT_GUARD, "GUARD" }, + { EVENT_STREAM_BANDWIDTH_USED, "STREAM_BW" }, + { EVENT_CLIENTS_SEEN, "CLIENTS_SEEN" }, + { EVENT_NEWCONSENSUS, "NEWCONSENSUS" }, + { EVENT_BUILDTIMEOUT_SET, "BUILDTIMEOUT_SET" }, + { EVENT_SIGNAL, "SIGNAL" }, + { EVENT_CONF_CHANGED, "CONF_CHANGED"}, + { EVENT_CONN_BW, "CONN_BW" }, + { EVENT_CELL_STATS, "CELL_STATS" }, + { EVENT_TB_EMPTY, "TB_EMPTY" }, + { EVENT_CIRC_BANDWIDTH_USED, "CIRC_BW" }, + { EVENT_TRANSPORT_LAUNCHED, "TRANSPORT_LAUNCHED" }, + { EVENT_HS_DESC, "HS_DESC" }, + { 0, NULL }, +}; + +/** Called when we get a SETEVENTS message: update conn->event_mask, + * and reply with DONE or ERROR. */ +static int +handle_control_setevents(control_connection_t *conn, uint32_t len, + const char *body) +{ + int event_code = -1; + uint32_t event_mask = 0; + smartlist_t *events = smartlist_new(); + + (void) len; + + smartlist_split_string(events, body, " ", + SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); + SMARTLIST_FOREACH_BEGIN(events, const char *, ev) + { + if (!strcasecmp(ev, "EXTENDED")) { + continue; + } else { + int i; + for (i = 0; control_event_table[i].event_name != NULL; ++i) { + if (!strcasecmp(ev, control_event_table[i].event_name)) { + event_code = control_event_table[i].event_code; + break; + } + } + + if (event_code == -1) { + connection_printf_to_buf(conn, "552 Unrecognized event \"%s\"\r\n", + ev); + SMARTLIST_FOREACH(events, char *, e, tor_free(e)); + smartlist_free(events); + return 0; + } + } + event_mask |= (1 << event_code); + } + SMARTLIST_FOREACH_END(ev); + SMARTLIST_FOREACH(events, char *, e, tor_free(e)); + smartlist_free(events); + + conn->event_mask = event_mask; + + control_update_global_event_mask(); + send_control_done(conn); + return 0; +} + +/** Decode the hashed, base64'd passwords stored in passwords. + * Return a smartlist of acceptable passwords (unterminated strings of + * length S2K_SPECIFIER_LEN+DIGEST_LEN) on success, or NULL on failure. + */ +smartlist_t * +decode_hashed_passwords(config_line_t *passwords) +{ + char decoded[64]; + config_line_t *cl; + smartlist_t *sl = smartlist_new(); + + tor_assert(passwords); + + for (cl = passwords; cl; cl = cl->next) { + const char *hashed = cl->value; + + if (!strcmpstart(hashed, "16:")) { + if (base16_decode(decoded, sizeof(decoded), hashed+3, strlen(hashed+3))<0 + || strlen(hashed+3) != (S2K_SPECIFIER_LEN+DIGEST_LEN)*2) { + goto err; + } + } else { + if (base64_decode(decoded, sizeof(decoded), hashed, strlen(hashed)) + != S2K_SPECIFIER_LEN+DIGEST_LEN) { + goto err; + } + } + smartlist_add(sl, tor_memdup(decoded, S2K_SPECIFIER_LEN+DIGEST_LEN)); + } + + return sl; + + err: + SMARTLIST_FOREACH(sl, char*, cp, tor_free(cp)); + smartlist_free(sl); + return NULL; +} + +/** Called when we get an AUTHENTICATE message. Check whether the + * authentication is valid, and if so, update the connection's state to + * OPEN. Reply with DONE or ERROR. + */ +static int +handle_control_authenticate(control_connection_t *conn, uint32_t len, + const char *body) +{ + int used_quoted_string = 0; + const or_options_t *options = get_options(); + const char *errstr = NULL; + char *password; + size_t password_len; + const char *cp; + int i; + int bad_cookie=0, bad_password=0; + smartlist_t *sl = NULL; + + if (!len) { + password = tor_strdup(""); + password_len = 0; + } else if (TOR_ISXDIGIT(body[0])) { + cp = body; + while (TOR_ISXDIGIT(*cp)) + ++cp; + i = (int)(cp - body); + tor_assert(i>0); + password_len = i/2; + password = tor_malloc(password_len + 1); + if (base16_decode(password, password_len+1, body, i)<0) { + connection_write_str_to_buf( + "551 Invalid hexadecimal encoding. Maybe you tried a plain text " + "password? If so, the standard requires that you put it in " + "double quotes.\r\n", conn); + connection_mark_for_close(TO_CONN(conn)); + tor_free(password); + return 0; + } + } else { + if (!decode_escaped_string(body, len, &password, &password_len)) { + connection_write_str_to_buf("551 Invalid quoted string. You need " + "to put the password in double quotes.\r\n", conn); + connection_mark_for_close(TO_CONN(conn)); + return 0; + } + used_quoted_string = 1; + } + + if (conn->safecookie_client_hash != NULL) { + /* The controller has chosen safe cookie authentication; the only + * acceptable authentication value is the controller-to-server + * response. */ + + tor_assert(authentication_cookie_is_set); + + if (password_len != DIGEST256_LEN) { + log_warn(LD_CONTROL, + "Got safe cookie authentication response with wrong length " + "(%d)", (int)password_len); + errstr = "Wrong length for safe cookie response."; + goto err; + } + + if (tor_memneq(conn->safecookie_client_hash, password, DIGEST256_LEN)) { + log_warn(LD_CONTROL, + "Got incorrect safe cookie authentication response"); + errstr = "Safe cookie response did not match expected value."; + goto err; + } + + tor_free(conn->safecookie_client_hash); + goto ok; + } + + if (!options->CookieAuthentication && !options->HashedControlPassword && + !options->HashedControlSessionPassword) { + /* if Tor doesn't demand any stronger authentication, then + * the controller can get in with anything. */ + goto ok; + } + + if (options->CookieAuthentication) { + int also_password = options->HashedControlPassword != NULL || + options->HashedControlSessionPassword != NULL; + if (password_len != AUTHENTICATION_COOKIE_LEN) { + if (!also_password) { + log_warn(LD_CONTROL, "Got authentication cookie with wrong length " + "(%d)", (int)password_len); + errstr = "Wrong length on authentication cookie."; + goto err; + } + bad_cookie = 1; + } else if (tor_memneq(authentication_cookie, password, password_len)) { + if (!also_password) { + log_warn(LD_CONTROL, "Got mismatched authentication cookie"); + errstr = "Authentication cookie did not match expected value."; + goto err; + } + bad_cookie = 1; + } else { + goto ok; + } + } + + if (options->HashedControlPassword || + options->HashedControlSessionPassword) { + int bad = 0; + smartlist_t *sl_tmp; + char received[DIGEST_LEN]; + int also_cookie = options->CookieAuthentication; + sl = smartlist_new(); + if (options->HashedControlPassword) { + sl_tmp = decode_hashed_passwords(options->HashedControlPassword); + if (!sl_tmp) + bad = 1; + else { + smartlist_add_all(sl, sl_tmp); + smartlist_free(sl_tmp); + } + } + if (options->HashedControlSessionPassword) { + sl_tmp = decode_hashed_passwords(options->HashedControlSessionPassword); + if (!sl_tmp) + bad = 1; + else { + smartlist_add_all(sl, sl_tmp); + smartlist_free(sl_tmp); + } + } + if (bad) { + if (!also_cookie) { + log_warn(LD_CONTROL, + "Couldn't decode HashedControlPassword: invalid base16"); + errstr="Couldn't decode HashedControlPassword value in configuration."; + } + bad_password = 1; + SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp)); + smartlist_free(sl); + } else { + SMARTLIST_FOREACH(sl, char *, expected, + { + secret_to_key(received,DIGEST_LEN,password,password_len,expected); + if (tor_memeq(expected+S2K_SPECIFIER_LEN, received, DIGEST_LEN)) + goto ok; + }); + SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp)); + smartlist_free(sl); + + if (used_quoted_string) + errstr = "Password did not match HashedControlPassword value from " + "configuration"; + else + errstr = "Password did not match HashedControlPassword value from " + "configuration. Maybe you tried a plain text password? " + "If so, the standard requires that you put it in double quotes."; + bad_password = 1; + if (!also_cookie) + goto err; + } + } + + /** We only get here if both kinds of authentication failed. */ + tor_assert(bad_password && bad_cookie); + log_warn(LD_CONTROL, "Bad password or authentication cookie on controller."); + errstr = "Password did not match HashedControlPassword *or* authentication " + "cookie."; + + err: + tor_free(password); + connection_printf_to_buf(conn, "515 Authentication failed: %s\r\n", + errstr ? errstr : "Unknown reason."); + connection_mark_for_close(TO_CONN(conn)); + return 0; + ok: + log_info(LD_CONTROL, "Authenticated control connection ("TOR_SOCKET_T_FORMAT + ")", conn->base_.s); + send_control_done(conn); + conn->base_.state = CONTROL_CONN_STATE_OPEN; + tor_free(password); + if (sl) { /* clean up */ + SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp)); + smartlist_free(sl); + } + return 0; +} + +/** Called when we get a SAVECONF command. Try to flush the current options to + * disk, and report success or failure. */ +static int +handle_control_saveconf(control_connection_t *conn, uint32_t len, + const char *body) +{ + (void) len; + (void) body; + if (options_save_current()<0) { + connection_write_str_to_buf( + "551 Unable to write configuration to disk.\r\n", conn); + } else { + send_control_done(conn); + } + return 0; +} + +struct signal_t { + int sig; + const char *signal_name; +}; + +static const struct signal_t signal_table[] = { + { SIGHUP, "RELOAD" }, + { SIGHUP, "HUP" }, + { SIGINT, "SHUTDOWN" }, + { SIGUSR1, "DUMP" }, + { SIGUSR1, "USR1" }, + { SIGUSR2, "DEBUG" }, + { SIGUSR2, "USR2" }, + { SIGTERM, "HALT" }, + { SIGTERM, "TERM" }, + { SIGTERM, "INT" }, + { SIGNEWNYM, "NEWNYM" }, + { SIGCLEARDNSCACHE, "CLEARDNSCACHE"}, + { 0, NULL }, +}; + +/** Called when we get a SIGNAL command. React to the provided signal, and + * report success or failure. (If the signal results in a shutdown, success + * may not be reported.) */ +static int +handle_control_signal(control_connection_t *conn, uint32_t len, + const char *body) +{ + int sig = -1; + int i; + int n = 0; + char *s; + + (void) len; + + while (body[n] && ! TOR_ISSPACE(body[n])) + ++n; + s = tor_strndup(body, n); + + for (i = 0; signal_table[i].signal_name != NULL; ++i) { + if (!strcasecmp(s, signal_table[i].signal_name)) { + sig = signal_table[i].sig; + break; + } + } + + if (sig < 0) + connection_printf_to_buf(conn, "552 Unrecognized signal code \"%s\"\r\n", + s); + tor_free(s); + if (sig < 0) + return 0; + + send_control_done(conn); + /* Flush the "done" first if the signal might make us shut down. */ + if (sig == SIGTERM || sig == SIGINT) + connection_flush(TO_CONN(conn)); + + process_signal(sig); + + return 0; +} + +/** Called when we get a TAKEOWNERSHIP command. Mark this connection + * as an owning connection, so that we will exit if the connection + * closes. */ +static int +handle_control_takeownership(control_connection_t *conn, uint32_t len, + const char *body) +{ + (void)len; + (void)body; + + conn->is_owning_control_connection = 1; + + log_info(LD_CONTROL, "Control connection %d has taken ownership of this " + "Tor instance.", + (int)(conn->base_.s)); + + send_control_done(conn); + return 0; +} + +/** Return true iff addr is unusable as a mapaddress target because of + * containing funny characters. */ +static int +address_is_invalid_mapaddress_target(const char *addr) +{ + if (!strcmpstart(addr, "*.")) + return address_is_invalid_destination(addr+2, 1); + else + return address_is_invalid_destination(addr, 1); +} + +/** Called when we get a MAPADDRESS command; try to bind all listed addresses, + * and report success or failure. */ +static int +handle_control_mapaddress(control_connection_t *conn, uint32_t len, + const char *body) +{ + smartlist_t *elts; + smartlist_t *lines; + smartlist_t *reply; + char *r; + size_t sz; + (void) len; /* body is NUL-terminated, so it's safe to ignore the length. */ + + lines = smartlist_new(); + elts = smartlist_new(); + reply = smartlist_new(); + smartlist_split_string(lines, body, " ", + SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); + SMARTLIST_FOREACH_BEGIN(lines, char *, line) { + tor_strlower(line); + smartlist_split_string(elts, line, "=", 0, 2); + if (smartlist_len(elts) == 2) { + const char *from = smartlist_get(elts,0); + const char *to = smartlist_get(elts,1); + if (address_is_invalid_mapaddress_target(to)) { + smartlist_add_asprintf(reply, + "512-syntax error: invalid address '%s'", to); + log_warn(LD_CONTROL, + "Skipping invalid argument '%s' in MapAddress msg", to); + } else if (!strcmp(from, ".") || !strcmp(from, "0.0.0.0") || + !strcmp(from, "::")) { + const char type = + !strcmp(from,".") ? RESOLVED_TYPE_HOSTNAME : + (!strcmp(from, "0.0.0.0") ? RESOLVED_TYPE_IPV4 : RESOLVED_TYPE_IPV6); + const char *address = addressmap_register_virtual_address( + type, tor_strdup(to)); + if (!address) { + smartlist_add_asprintf(reply, + "451-resource exhausted: skipping '%s'", line); + log_warn(LD_CONTROL, + "Unable to allocate address for '%s' in MapAddress msg", + safe_str_client(line)); + } else { + smartlist_add_asprintf(reply, "250-%s=%s", address, to); + } + } else { + const char *msg; + if (addressmap_register_auto(from, to, 1, + ADDRMAPSRC_CONTROLLER, &msg) < 0) { + smartlist_add_asprintf(reply, + "512-syntax error: invalid address mapping " + " '%s': %s", line, msg); + log_warn(LD_CONTROL, + "Skipping invalid argument '%s' in MapAddress msg: %s", + line, msg); + } else { + smartlist_add_asprintf(reply, "250-%s", line); + } + } + } else { + smartlist_add_asprintf(reply, "512-syntax error: mapping '%s' is " + "not of expected form 'foo=bar'.", line); + log_info(LD_CONTROL, "Skipping MapAddress '%s': wrong " + "number of items.", + safe_str_client(line)); + } + SMARTLIST_FOREACH(elts, char *, cp, tor_free(cp)); + smartlist_clear(elts); + } SMARTLIST_FOREACH_END(line); + SMARTLIST_FOREACH(lines, char *, cp, tor_free(cp)); + smartlist_free(lines); + smartlist_free(elts); + + if (smartlist_len(reply)) { + ((char*)smartlist_get(reply,smartlist_len(reply)-1))[3] = ' '; + r = smartlist_join_strings(reply, "\r\n", 1, &sz); + connection_write_to_buf(r, sz, TO_CONN(conn)); + tor_free(r); + } else { + const char *response = + "512 syntax error: not enough arguments to mapaddress.\r\n"; + connection_write_to_buf(response, strlen(response), TO_CONN(conn)); + } + + SMARTLIST_FOREACH(reply, char *, cp, tor_free(cp)); + smartlist_free(reply); + return 0; +} + +/** Implementation helper for GETINFO: knows the answers for various + * trivial-to-implement questions. */ +static int +getinfo_helper_misc(control_connection_t *conn, const char *question, + char **answer, const char **errmsg) +{ + (void) conn; + if (!strcmp(question, "version")) { + *answer = tor_strdup(get_version()); + } else if (!strcmp(question, "config-file")) { + *answer = tor_strdup(get_torrc_fname(0)); + } else if (!strcmp(question, "config-defaults-file")) { + *answer = tor_strdup(get_torrc_fname(1)); + } else if (!strcmp(question, "config-text")) { + *answer = options_dump(get_options(), OPTIONS_DUMP_MINIMAL); + } else if (!strcmp(question, "info/names")) { + *answer = list_getinfo_options(); + } else if (!strcmp(question, "dormant")) { + int dormant = rep_hist_circbuilding_dormant(time(NULL)); + *answer = tor_strdup(dormant ? "1" : "0"); + } else if (!strcmp(question, "events/names")) { + int i; + smartlist_t *event_names = smartlist_new(); + + for (i = 0; control_event_table[i].event_name != NULL; ++i) { + smartlist_add(event_names, (char *)control_event_table[i].event_name); + } + + *answer = smartlist_join_strings(event_names, " ", 0, NULL); + + smartlist_free(event_names); + } else if (!strcmp(question, "signal/names")) { + smartlist_t *signal_names = smartlist_new(); + int j; + for (j = 0; signal_table[j].signal_name != NULL; ++j) { + smartlist_add(signal_names, (char*)signal_table[j].signal_name); + } + + *answer = smartlist_join_strings(signal_names, " ", 0, NULL); + + smartlist_free(signal_names); + } else if (!strcmp(question, "features/names")) { + *answer = tor_strdup("VERBOSE_NAMES EXTENDED_EVENTS"); + } else if (!strcmp(question, "address")) { + uint32_t addr; + if (router_pick_published_address(get_options(), &addr) < 0) { + *errmsg = "Address unknown"; + return -1; + } + *answer = tor_dup_ip(addr); + } else if (!strcmp(question, "traffic/read")) { + tor_asprintf(answer, U64_FORMAT, U64_PRINTF_ARG(get_bytes_read())); + } else if (!strcmp(question, "traffic/written")) { + tor_asprintf(answer, U64_FORMAT, U64_PRINTF_ARG(get_bytes_written())); + } else if (!strcmp(question, "process/pid")) { + int myPid = -1; + + #ifdef _WIN32 + myPid = _getpid(); + #else + myPid = getpid(); + #endif + + tor_asprintf(answer, "%d", myPid); + } else if (!strcmp(question, "process/uid")) { + #ifdef _WIN32 + *answer = tor_strdup("-1"); + #else + int myUid = geteuid(); + tor_asprintf(answer, "%d", myUid); + #endif + } else if (!strcmp(question, "process/user")) { + #ifdef _WIN32 + *answer = tor_strdup(""); + #else + int myUid = geteuid(); + struct passwd *myPwEntry = getpwuid(myUid); + + if (myPwEntry) { + *answer = tor_strdup(myPwEntry->pw_name); + } else { + *answer = tor_strdup(""); + } + #endif + } else if (!strcmp(question, "process/descriptor-limit")) { + int max_fds=-1; + set_max_file_descriptors(0, &max_fds); + tor_asprintf(answer, "%d", max_fds); + } else if (!strcmp(question, "dir-usage")) { + *answer = directory_dump_request_log(); + } else if (!strcmp(question, "fingerprint")) { + crypto_pk_t *server_key; + if (!server_mode(get_options())) { + *errmsg = "Not running in server mode"; + return -1; + } + server_key = get_server_identity_key(); + *answer = tor_malloc(HEX_DIGEST_LEN+1); + crypto_pk_get_fingerprint(server_key, *answer, 0); + } + return 0; +} + +/** Awful hack: return a newly allocated string based on a routerinfo and + * (possibly) an extrainfo, sticking the read-history and write-history from + * ei into the resulting string. The thing you get back won't + * necessarily have a valid signature. + * + * New code should never use this; it's for backward compatibility. + * + * NOTE: ri_body is as returned by signed_descriptor_get_body: it might + * not be NUL-terminated. */ +static char * +munge_extrainfo_into_routerinfo(const char *ri_body, + const signed_descriptor_t *ri, + const signed_descriptor_t *ei) +{ + char *out = NULL, *outp; + int i; + const char *router_sig; + const char *ei_body = signed_descriptor_get_body(ei); + size_t ri_len = ri->signed_descriptor_len; + size_t ei_len = ei->signed_descriptor_len; + if (!ei_body) + goto bail; + + outp = out = tor_malloc(ri_len+ei_len+1); + if (!(router_sig = tor_memstr(ri_body, ri_len, "\nrouter-signature"))) + goto bail; + ++router_sig; + memcpy(out, ri_body, router_sig-ri_body); + outp += router_sig-ri_body; + + for (i=0; i < 2; ++i) { + const char *kwd = i ? "\nwrite-history " : "\nread-history "; + const char *cp, *eol; + if (!(cp = tor_memstr(ei_body, ei_len, kwd))) + continue; + ++cp; + if (!(eol = memchr(cp, '\n', ei_len - (cp-ei_body)))) + continue; + memcpy(outp, cp, eol-cp+1); + outp += eol-cp+1; + } + memcpy(outp, router_sig, ri_len - (router_sig-ri_body)); + *outp++ = '\0'; + tor_assert(outp-out < (int)(ri_len+ei_len+1)); + + return out; + bail: + tor_free(out); + return tor_strndup(ri_body, ri->signed_descriptor_len); +} + +/** Implementation helper for GETINFO: answers requests for information about + * which ports are bound. */ +static int +getinfo_helper_listeners(control_connection_t *control_conn, + const char *question, + char **answer, const char **errmsg) +{ + int type; + smartlist_t *res; + + (void)control_conn; + (void)errmsg; + + if (!strcmp(question, "net/listeners/or")) + type = CONN_TYPE_OR_LISTENER; + else if (!strcmp(question, "net/listeners/dir")) + type = CONN_TYPE_DIR_LISTENER; + else if (!strcmp(question, "net/listeners/socks")) + type = CONN_TYPE_AP_LISTENER; + else if (!strcmp(question, "net/listeners/trans")) + type = CONN_TYPE_AP_TRANS_LISTENER; + else if (!strcmp(question, "net/listeners/natd")) + type = CONN_TYPE_AP_NATD_LISTENER; + else if (!strcmp(question, "net/listeners/dns")) + type = CONN_TYPE_AP_DNS_LISTENER; + else if (!strcmp(question, "net/listeners/control")) + type = CONN_TYPE_CONTROL_LISTENER; + else + return 0; /* unknown key */ + + res = smartlist_new(); + SMARTLIST_FOREACH_BEGIN(get_connection_array(), connection_t *, conn) { + struct sockaddr_storage ss; + socklen_t ss_len = sizeof(ss); + + if (conn->type != type || conn->marked_for_close || !SOCKET_OK(conn->s)) + continue; + + if (getsockname(conn->s, (struct sockaddr *)&ss, &ss_len) < 0) { + smartlist_add_asprintf(res, "%s:%d", conn->address, (int)conn->port); + } else { + char *tmp = tor_sockaddr_to_str((struct sockaddr *)&ss); + smartlist_add(res, esc_for_log(tmp)); + tor_free(tmp); + } + + } SMARTLIST_FOREACH_END(conn); + + *answer = smartlist_join_strings(res, " ", 0, NULL); + + SMARTLIST_FOREACH(res, char *, cp, tor_free(cp)); + smartlist_free(res); + return 0; +} + +/** Implementation helper for GETINFO: knows the answers for questions about + * directory information. */ +static int +getinfo_helper_dir(control_connection_t *control_conn, + const char *question, char **answer, + const char **errmsg) +{ + const node_t *node; + const routerinfo_t *ri = NULL; + (void) control_conn; + if (!strcmpstart(question, "desc/id/")) { + node = node_get_by_hex_id(question+strlen("desc/id/")); + if (node) + ri = node->ri; + if (ri) { + const char *body = signed_descriptor_get_body(&ri->cache_info); + if (body) + *answer = tor_strndup(body, ri->cache_info.signed_descriptor_len); + } + } else if (!strcmpstart(question, "desc/name/")) { + /* XXX023 Setting 'warn_if_unnamed' here is a bit silly -- the + * warning goes to the user, not to the controller. */ + node = node_get_by_nickname(question+strlen("desc/name/"), 1); + if (node) + ri = node->ri; + if (ri) { + const char *body = signed_descriptor_get_body(&ri->cache_info); + if (body) + *answer = tor_strndup(body, ri->cache_info.signed_descriptor_len); + } + } else if (!strcmp(question, "desc/all-recent")) { + routerlist_t *routerlist = router_get_routerlist(); + smartlist_t *sl = smartlist_new(); + if (routerlist && routerlist->routers) { + SMARTLIST_FOREACH(routerlist->routers, const routerinfo_t *, ri, + { + const char *body = signed_descriptor_get_body(&ri->cache_info); + if (body) + smartlist_add(sl, + tor_strndup(body, ri->cache_info.signed_descriptor_len)); + }); + } + *answer = smartlist_join_strings(sl, "", 0, NULL); + SMARTLIST_FOREACH(sl, char *, c, tor_free(c)); + smartlist_free(sl); + } else if (!strcmp(question, "desc/all-recent-extrainfo-hack")) { + /* XXXX Remove this once Torstat asks for extrainfos. */ + routerlist_t *routerlist = router_get_routerlist(); + smartlist_t *sl = smartlist_new(); + if (routerlist && routerlist->routers) { + SMARTLIST_FOREACH_BEGIN(routerlist->routers, const routerinfo_t *, ri) { + const char *body = signed_descriptor_get_body(&ri->cache_info); + signed_descriptor_t *ei = extrainfo_get_by_descriptor_digest( + ri->cache_info.extra_info_digest); + if (ei && body) { + smartlist_add(sl, munge_extrainfo_into_routerinfo(body, + &ri->cache_info, ei)); + } else if (body) { + smartlist_add(sl, + tor_strndup(body, ri->cache_info.signed_descriptor_len)); + } + } SMARTLIST_FOREACH_END(ri); + } + *answer = smartlist_join_strings(sl, "", 0, NULL); + SMARTLIST_FOREACH(sl, char *, c, tor_free(c)); + smartlist_free(sl); + } else if (!strcmpstart(question, "md/id/")) { + const node_t *node = node_get_by_hex_id(question+strlen("md/id/")); + const microdesc_t *md = NULL; + if (node) md = node->md; + if (md && md->body) { + *answer = tor_strndup(md->body, md->bodylen); + } + } else if (!strcmpstart(question, "md/name/")) { + /* XXX023 Setting 'warn_if_unnamed' here is a bit silly -- the + * warning goes to the user, not to the controller. */ + const node_t *node = node_get_by_nickname(question+strlen("md/name/"), 1); + /* XXXX duplicated code */ + const microdesc_t *md = NULL; + if (node) md = node->md; + if (md && md->body) { + *answer = tor_strndup(md->body, md->bodylen); + } + } else if (!strcmpstart(question, "desc-annotations/id/")) { + node = node_get_by_hex_id(question+strlen("desc-annotations/id/")); + if (node) + ri = node->ri; + if (ri) { + const char *annotations = + signed_descriptor_get_annotations(&ri->cache_info); + if (annotations) + *answer = tor_strndup(annotations, + ri->cache_info.annotations_len); + } + } else if (!strcmpstart(question, "dir/server/")) { + size_t answer_len = 0; + char *url = NULL; + smartlist_t *descs = smartlist_new(); + const char *msg; + int res; + char *cp; + tor_asprintf(&url, "/tor/%s", question+4); + res = dirserv_get_routerdescs(descs, url, &msg); + if (res) { + log_warn(LD_CONTROL, "getinfo '%s': %s", question, msg); + smartlist_free(descs); + tor_free(url); + *errmsg = msg; + return -1; + } + SMARTLIST_FOREACH(descs, signed_descriptor_t *, sd, + answer_len += sd->signed_descriptor_len); + cp = *answer = tor_malloc(answer_len+1); + SMARTLIST_FOREACH(descs, signed_descriptor_t *, sd, + { + memcpy(cp, signed_descriptor_get_body(sd), + sd->signed_descriptor_len); + cp += sd->signed_descriptor_len; + }); + *cp = '\0'; + tor_free(url); + smartlist_free(descs); + } else if (!strcmpstart(question, "dir/status/")) { + *answer = tor_strdup(""); + } else if (!strcmp(question, "dir/status-vote/current/consensus")) { /* v3 */ + if (directory_caches_dir_info(get_options())) { + const cached_dir_t *consensus = dirserv_get_consensus("ns"); + if (consensus) + *answer = tor_strdup(consensus->dir); + } + if (!*answer) { /* try loading it from disk */ + char *filename = get_datadir_fname("cached-consensus"); + *answer = read_file_to_str(filename, RFTS_IGNORE_MISSING, NULL); + tor_free(filename); + } + } else if (!strcmp(question, "network-status")) { /* v1 */ + routerlist_t *routerlist = router_get_routerlist(); + if (!routerlist || !routerlist->routers || + list_server_status_v1(routerlist->routers, answer, 1) < 0) { + return -1; + } + } else if (!strcmpstart(question, "extra-info/digest/")) { + question += strlen("extra-info/digest/"); + if (strlen(question) == HEX_DIGEST_LEN) { + char d[DIGEST_LEN]; + signed_descriptor_t *sd = NULL; + if (base16_decode(d, sizeof(d), question, strlen(question))==0) { + /* XXXX this test should move into extrainfo_get_by_descriptor_digest, + * but I don't want to risk affecting other parts of the code, + * especially since the rules for using our own extrainfo (including + * when it might be freed) are different from those for using one + * we have downloaded. */ + if (router_extrainfo_digest_is_me(d)) + sd = &(router_get_my_extrainfo()->cache_info); + else + sd = extrainfo_get_by_descriptor_digest(d); + } + if (sd) { + const char *body = signed_descriptor_get_body(sd); + if (body) + *answer = tor_strndup(body, sd->signed_descriptor_len); + } + } + } + + return 0; +} + +/** Allocate and return a description of circ's current status, + * including its path (if any). */ +static char * +circuit_describe_status_for_controller(origin_circuit_t *circ) +{ + char *rv; + smartlist_t *descparts = smartlist_new(); + + { + char *vpath = circuit_list_path_for_controller(circ); + if (*vpath) { + smartlist_add(descparts, vpath); + } else { + tor_free(vpath); /* empty path; don't put an extra space in the result */ + } + } + + { + cpath_build_state_t *build_state = circ->build_state; + smartlist_t *flaglist = smartlist_new(); + char *flaglist_joined; + + if (build_state->onehop_tunnel) + smartlist_add(flaglist, (void *)"ONEHOP_TUNNEL"); + if (build_state->is_internal) + smartlist_add(flaglist, (void *)"IS_INTERNAL"); + if (build_state->need_capacity) + smartlist_add(flaglist, (void *)"NEED_CAPACITY"); + if (build_state->need_uptime) + smartlist_add(flaglist, (void *)"NEED_UPTIME"); + + /* Only emit a BUILD_FLAGS argument if it will have a non-empty value. */ + if (smartlist_len(flaglist)) { + flaglist_joined = smartlist_join_strings(flaglist, ",", 0, NULL); + + smartlist_add_asprintf(descparts, "BUILD_FLAGS=%s", flaglist_joined); + + tor_free(flaglist_joined); + } + + smartlist_free(flaglist); + } + + smartlist_add_asprintf(descparts, "PURPOSE=%s", + circuit_purpose_to_controller_string(circ->base_.purpose)); + + { + const char *hs_state = + circuit_purpose_to_controller_hs_state_string(circ->base_.purpose); + + if (hs_state != NULL) { + smartlist_add_asprintf(descparts, "HS_STATE=%s", hs_state); + } + } + + if (circ->rend_data != NULL) { + smartlist_add_asprintf(descparts, "REND_QUERY=%s", + circ->rend_data->onion_address); + } + + { + char tbuf[ISO_TIME_USEC_LEN+1]; + format_iso_time_nospace_usec(tbuf, &circ->base_.timestamp_created); + + smartlist_add_asprintf(descparts, "TIME_CREATED=%s", tbuf); + } + + rv = smartlist_join_strings(descparts, " ", 0, NULL); + + SMARTLIST_FOREACH(descparts, char *, cp, tor_free(cp)); + smartlist_free(descparts); + + return rv; +} + +/** Implementation helper for GETINFO: knows how to generate summaries of the + * current states of things we send events about. */ +static int +getinfo_helper_events(control_connection_t *control_conn, + const char *question, char **answer, + const char **errmsg) +{ + (void) control_conn; + if (!strcmp(question, "circuit-status")) { + circuit_t *circ_; + smartlist_t *status = smartlist_new(); + TOR_LIST_FOREACH(circ_, circuit_get_global_list(), head) { + origin_circuit_t *circ; + char *circdesc; + const char *state; + if (! CIRCUIT_IS_ORIGIN(circ_) || circ_->marked_for_close) + continue; + circ = TO_ORIGIN_CIRCUIT(circ_); + + if (circ->base_.state == CIRCUIT_STATE_OPEN) + state = "BUILT"; + else if (circ->cpath) + state = "EXTENDED"; + else + state = "LAUNCHED"; + + circdesc = circuit_describe_status_for_controller(circ); + + smartlist_add_asprintf(status, "%lu %s%s%s", + (unsigned long)circ->global_identifier, + state, *circdesc ? " " : "", circdesc); + tor_free(circdesc); + } + *answer = smartlist_join_strings(status, "\r\n", 0, NULL); + SMARTLIST_FOREACH(status, char *, cp, tor_free(cp)); + smartlist_free(status); + } else if (!strcmp(question, "stream-status")) { + smartlist_t *conns = get_connection_array(); + smartlist_t *status = smartlist_new(); + char buf[256]; + SMARTLIST_FOREACH_BEGIN(conns, connection_t *, base_conn) { + const char *state; + entry_connection_t *conn; + circuit_t *circ; + origin_circuit_t *origin_circ = NULL; + if (base_conn->type != CONN_TYPE_AP || + base_conn->marked_for_close || + base_conn->state == AP_CONN_STATE_SOCKS_WAIT || + base_conn->state == AP_CONN_STATE_NATD_WAIT) + continue; + conn = TO_ENTRY_CONN(base_conn); + switch (base_conn->state) + { + case AP_CONN_STATE_CONTROLLER_WAIT: + case AP_CONN_STATE_CIRCUIT_WAIT: + if (conn->socks_request && + SOCKS_COMMAND_IS_RESOLVE(conn->socks_request->command)) + state = "NEWRESOLVE"; + else + state = "NEW"; + break; + case AP_CONN_STATE_RENDDESC_WAIT: + case AP_CONN_STATE_CONNECT_WAIT: + state = "SENTCONNECT"; break; + case AP_CONN_STATE_RESOLVE_WAIT: + state = "SENTRESOLVE"; break; + case AP_CONN_STATE_OPEN: + state = "SUCCEEDED"; break; + default: + log_warn(LD_BUG, "Asked for stream in unknown state %d", + base_conn->state); + continue; + } + circ = circuit_get_by_edge_conn(ENTRY_TO_EDGE_CONN(conn)); + if (circ && CIRCUIT_IS_ORIGIN(circ)) + origin_circ = TO_ORIGIN_CIRCUIT(circ); + write_stream_target_to_buf(conn, buf, sizeof(buf)); + smartlist_add_asprintf(status, "%lu %s %lu %s", + (unsigned long) base_conn->global_identifier,state, + origin_circ? + (unsigned long)origin_circ->global_identifier : 0ul, + buf); + } SMARTLIST_FOREACH_END(base_conn); + *answer = smartlist_join_strings(status, "\r\n", 0, NULL); + SMARTLIST_FOREACH(status, char *, cp, tor_free(cp)); + smartlist_free(status); + } else if (!strcmp(question, "orconn-status")) { + smartlist_t *conns = get_connection_array(); + smartlist_t *status = smartlist_new(); + SMARTLIST_FOREACH_BEGIN(conns, connection_t *, base_conn) { + const char *state; + char name[128]; + or_connection_t *conn; + if (base_conn->type != CONN_TYPE_OR || base_conn->marked_for_close) + continue; + conn = TO_OR_CONN(base_conn); + if (conn->base_.state == OR_CONN_STATE_OPEN) + state = "CONNECTED"; + else if (conn->nickname) + state = "LAUNCHED"; + else + state = "NEW"; + orconn_target_get_name(name, sizeof(name), conn); + smartlist_add_asprintf(status, "%s %s", name, state); + } SMARTLIST_FOREACH_END(base_conn); + *answer = smartlist_join_strings(status, "\r\n", 0, NULL); + SMARTLIST_FOREACH(status, char *, cp, tor_free(cp)); + smartlist_free(status); + } else if (!strcmpstart(question, "address-mappings/")) { + time_t min_e, max_e; + smartlist_t *mappings; + question += strlen("address-mappings/"); + if (!strcmp(question, "all")) { + min_e = 0; max_e = TIME_MAX; + } else if (!strcmp(question, "cache")) { + min_e = 2; max_e = TIME_MAX; + } else if (!strcmp(question, "config")) { + min_e = 0; max_e = 0; + } else if (!strcmp(question, "control")) { + min_e = 1; max_e = 1; + } else { + return 0; + } + mappings = smartlist_new(); + addressmap_get_mappings(mappings, min_e, max_e, 1); + *answer = smartlist_join_strings(mappings, "\r\n", 0, NULL); + SMARTLIST_FOREACH(mappings, char *, cp, tor_free(cp)); + smartlist_free(mappings); + } else if (!strcmpstart(question, "status/")) { + /* Note that status/ is not a catch-all for events; there's only supposed + * to be a status GETINFO if there's a corresponding STATUS event. */ + if (!strcmp(question, "status/circuit-established")) { + *answer = tor_strdup(can_complete_circuit ? "1" : "0"); + } else if (!strcmp(question, "status/enough-dir-info")) { + *answer = tor_strdup(router_have_minimum_dir_info() ? "1" : "0"); + } else if (!strcmp(question, "status/good-server-descriptor") || + !strcmp(question, "status/accepted-server-descriptor")) { + /* They're equivalent for now, until we can figure out how to make + * good-server-descriptor be what we want. See comment in + * control-spec.txt. */ + *answer = tor_strdup(directories_have_accepted_server_descriptor() + ? "1" : "0"); + } else if (!strcmp(question, "status/reachability-succeeded/or")) { + *answer = tor_strdup(check_whether_orport_reachable() ? "1" : "0"); + } else if (!strcmp(question, "status/reachability-succeeded/dir")) { + *answer = tor_strdup(check_whether_dirport_reachable() ? "1" : "0"); + } else if (!strcmp(question, "status/reachability-succeeded")) { + tor_asprintf(answer, "OR=%d DIR=%d", + check_whether_orport_reachable() ? 1 : 0, + check_whether_dirport_reachable() ? 1 : 0); + } else if (!strcmp(question, "status/bootstrap-phase")) { + *answer = tor_strdup(last_sent_bootstrap_message); + } else if (!strcmpstart(question, "status/version/")) { + int is_server = server_mode(get_options()); + networkstatus_t *c = networkstatus_get_latest_consensus(); + version_status_t status; + const char *recommended; + if (c) { + recommended = is_server ? c->server_versions : c->client_versions; + status = tor_version_is_obsolete(VERSION, recommended); + } else { + recommended = "?"; + status = VS_UNKNOWN; + } + + if (!strcmp(question, "status/version/recommended")) { + *answer = tor_strdup(recommended); + return 0; + } + if (!strcmp(question, "status/version/current")) { + switch (status) + { + case VS_RECOMMENDED: *answer = tor_strdup("recommended"); break; + case VS_OLD: *answer = tor_strdup("obsolete"); break; + case VS_NEW: *answer = tor_strdup("new"); break; + case VS_NEW_IN_SERIES: *answer = tor_strdup("new in series"); break; + case VS_UNRECOMMENDED: *answer = tor_strdup("unrecommended"); break; + case VS_EMPTY: *answer = tor_strdup("none recommended"); break; + case VS_UNKNOWN: *answer = tor_strdup("unknown"); break; + default: tor_fragile_assert(); + } + } else if (!strcmp(question, "status/version/num-versioning") || + !strcmp(question, "status/version/num-concurring")) { + tor_asprintf(answer, "%d", get_n_authorities(V3_DIRINFO)); + log_warn(LD_GENERAL, "%s is deprecated; it no longer gives useful " + "information", question); + } + } else if (!strcmp(question, "status/clients-seen")) { + char *bridge_stats = geoip_get_bridge_stats_controller(time(NULL)); + if (!bridge_stats) { + *errmsg = "No bridge-client stats available"; + return -1; + } + *answer = bridge_stats; + } else { + return 0; + } + } + return 0; +} + +/** Callback function for GETINFO: on a given control connection, try to + * answer the question q and store the newly-allocated answer in + * *a. If an internal error occurs, return -1 and optionally set + * *error_out to point to an error message to be delivered to the + * controller. On success, _or if the key is not recognized_, return 0. Do not + * set a if the key is not recognized. + */ +typedef int (*getinfo_helper_t)(control_connection_t *, + const char *q, char **a, + const char **error_out); + +/** A single item for the GETINFO question-to-answer-function table. */ +typedef struct getinfo_item_t { + const char *varname; /**< The value (or prefix) of the question. */ + getinfo_helper_t fn; /**< The function that knows the answer: NULL if + * this entry is documentation-only. */ + const char *desc; /**< Description of the variable. */ + int is_prefix; /** Must varname match exactly, or must it be a prefix? */ +} getinfo_item_t; + +#define ITEM(name, fn, desc) { name, getinfo_helper_##fn, desc, 0 } +#define PREFIX(name, fn, desc) { name, getinfo_helper_##fn, desc, 1 } +#define DOC(name, desc) { name, NULL, desc, 0 } + +/** Table mapping questions accepted by GETINFO to the functions that know how + * to answer them. */ +static const getinfo_item_t getinfo_items[] = { + ITEM("version", misc, "The current version of Tor."), + ITEM("config-file", misc, "Current location of the \"torrc\" file."), + ITEM("config-defaults-file", misc, "Current location of the defaults file."), + ITEM("config-text", misc, + "Return the string that would be written by a saveconf command."), + ITEM("accounting/bytes", accounting, + "Number of bytes read/written so far in the accounting interval."), + ITEM("accounting/bytes-left", accounting, + "Number of bytes left to write/read so far in the accounting interval."), + ITEM("accounting/enabled", accounting, "Is accounting currently enabled?"), + ITEM("accounting/hibernating", accounting, "Are we hibernating or awake?"), + ITEM("accounting/interval-start", accounting, + "Time when the accounting period starts."), + ITEM("accounting/interval-end", accounting, + "Time when the accounting period ends."), + ITEM("accounting/interval-wake", accounting, + "Time to wake up in this accounting period."), + ITEM("helper-nodes", entry_guards, NULL), /* deprecated */ + ITEM("entry-guards", entry_guards, + "Which nodes are we using as entry guards?"), + ITEM("fingerprint", misc, NULL), + PREFIX("config/", config, "Current configuration values."), + DOC("config/names", + "List of configuration options, types, and documentation."), + DOC("config/defaults", + "List of default values for configuration options. " + "See also config/names"), + ITEM("info/names", misc, + "List of GETINFO options, types, and documentation."), + ITEM("events/names", misc, + "Events that the controller can ask for with SETEVENTS."), + ITEM("signal/names", misc, "Signal names recognized by the SIGNAL command"), + ITEM("features/names", misc, "What arguments can USEFEATURE take?"), + PREFIX("desc/id/", dir, "Router descriptors by ID."), + PREFIX("desc/name/", dir, "Router descriptors by nickname."), + ITEM("desc/all-recent", dir, + "All non-expired, non-superseded router descriptors."), + ITEM("desc/all-recent-extrainfo-hack", dir, NULL), /* Hack. */ + PREFIX("md/id/", dir, "Microdescriptors by ID"), + PREFIX("md/name/", dir, "Microdescriptors by name"), + PREFIX("extra-info/digest/", dir, "Extra-info documents by digest."), + PREFIX("net/listeners/", listeners, "Bound addresses by type"), + ITEM("ns/all", networkstatus, + "Brief summary of router status (v2 directory format)"), + PREFIX("ns/id/", networkstatus, + "Brief summary of router status by ID (v2 directory format)."), + PREFIX("ns/name/", networkstatus, + "Brief summary of router status by nickname (v2 directory format)."), + PREFIX("ns/purpose/", networkstatus, + "Brief summary of router status by purpose (v2 directory format)."), + ITEM("network-status", dir, + "Brief summary of router status (v1 directory format)"), + ITEM("circuit-status", events, "List of current circuits originating here."), + ITEM("stream-status", events,"List of current streams."), + ITEM("orconn-status", events, "A list of current OR connections."), + ITEM("dormant", misc, + "Is Tor dormant (not building circuits because it's idle)?"), + PREFIX("address-mappings/", events, NULL), + DOC("address-mappings/all", "Current address mappings."), + DOC("address-mappings/cache", "Current cached DNS replies."), + DOC("address-mappings/config", + "Current address mappings from configuration."), + DOC("address-mappings/control", "Current address mappings from controller."), + PREFIX("status/", events, NULL), + DOC("status/circuit-established", + "Whether we think client functionality is working."), + DOC("status/enough-dir-info", + "Whether we have enough up-to-date directory information to build " + "circuits."), + DOC("status/bootstrap-phase", + "The last bootstrap phase status event that Tor sent."), + DOC("status/clients-seen", + "Breakdown of client countries seen by a bridge."), + DOC("status/version/recommended", "List of currently recommended versions."), + DOC("status/version/current", "Status of the current version."), + DOC("status/version/num-versioning", "Number of versioning authorities."), + DOC("status/version/num-concurring", + "Number of versioning authorities agreeing on the status of the " + "current version"), + ITEM("address", misc, "IP address of this Tor host, if we can guess it."), + ITEM("traffic/read", misc,"Bytes read since the process was started."), + ITEM("traffic/written", misc, + "Bytes written since the process was started."), + ITEM("process/pid", misc, "Process id belonging to the main tor process."), + ITEM("process/uid", misc, "User id running the tor process."), + ITEM("process/user", misc, + "Username under which the tor process is running."), + ITEM("process/descriptor-limit", misc, "File descriptor limit."), + ITEM("dir-usage", misc, "Breakdown of bytes transferred over DirPort."), + PREFIX("desc-annotations/id/", dir, "Router annotations by hexdigest."), + PREFIX("dir/server/", dir,"Router descriptors as retrieved from a DirPort."), + PREFIX("dir/status/", dir, + "v2 networkstatus docs as retrieved from a DirPort."), + ITEM("dir/status-vote/current/consensus", dir, + "v3 Networkstatus consensus as retrieved from a DirPort."), + ITEM("exit-policy/default", policies, + "The default value appended to the configured exit policy."), + PREFIX("ip-to-country/", geoip, "Perform a GEOIP lookup"), + { NULL, NULL, NULL, 0 } +}; + +/** Allocate and return a list of recognized GETINFO options. */ +static char * +list_getinfo_options(void) +{ + int i; + smartlist_t *lines = smartlist_new(); + char *ans; + for (i = 0; getinfo_items[i].varname; ++i) { + if (!getinfo_items[i].desc) + continue; + + smartlist_add_asprintf(lines, "%s%s -- %s\n", + getinfo_items[i].varname, + getinfo_items[i].is_prefix ? "*" : "", + getinfo_items[i].desc); + } + smartlist_sort_strings(lines); + + ans = smartlist_join_strings(lines, "", 0, NULL); + SMARTLIST_FOREACH(lines, char *, cp, tor_free(cp)); + smartlist_free(lines); + + return ans; +} + +/** Lookup the 'getinfo' entry question, and return + * the answer in *answer (or NULL if key not recognized). + * Return 0 if success or unrecognized, or -1 if recognized but + * internal error. */ +static int +handle_getinfo_helper(control_connection_t *control_conn, + const char *question, char **answer, + const char **err_out) +{ + int i; + *answer = NULL; /* unrecognized key by default */ + + for (i = 0; getinfo_items[i].varname; ++i) { + int match; + if (getinfo_items[i].is_prefix) + match = !strcmpstart(question, getinfo_items[i].varname); + else + match = !strcmp(question, getinfo_items[i].varname); + if (match) { + tor_assert(getinfo_items[i].fn); + return getinfo_items[i].fn(control_conn, question, answer, err_out); + } + } + + return 0; /* unrecognized */ +} + +/** Called when we receive a GETINFO command. Try to fetch all requested + * information, and reply with information or error message. */ +static int +handle_control_getinfo(control_connection_t *conn, uint32_t len, + const char *body) +{ + smartlist_t *questions = smartlist_new(); + smartlist_t *answers = smartlist_new(); + smartlist_t *unrecognized = smartlist_new(); + char *msg = NULL, *ans = NULL; + int i; + (void) len; /* body is NUL-terminated, so it's safe to ignore the length. */ + + smartlist_split_string(questions, body, " ", + SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); + SMARTLIST_FOREACH_BEGIN(questions, const char *, q) { + const char *errmsg = NULL; + if (handle_getinfo_helper(conn, q, &ans, &errmsg) < 0) { + if (!errmsg) + errmsg = "Internal error"; + connection_printf_to_buf(conn, "551 %s\r\n", errmsg); + goto done; + } + if (!ans) { + smartlist_add(unrecognized, (char*)q); + } else { + smartlist_add(answers, tor_strdup(q)); + smartlist_add(answers, ans); + } + } SMARTLIST_FOREACH_END(q); + if (smartlist_len(unrecognized)) { + for (i=0; i < smartlist_len(unrecognized)-1; ++i) + connection_printf_to_buf(conn, + "552-Unrecognized key \"%s\"\r\n", + (char*)smartlist_get(unrecognized, i)); + connection_printf_to_buf(conn, + "552 Unrecognized key \"%s\"\r\n", + (char*)smartlist_get(unrecognized, i)); + goto done; + } + + for (i = 0; i < smartlist_len(answers); i += 2) { + char *k = smartlist_get(answers, i); + char *v = smartlist_get(answers, i+1); + if (!strchr(v, '\n') && !strchr(v, '\r')) { + connection_printf_to_buf(conn, "250-%s=", k); + connection_write_str_to_buf(v, conn); + connection_write_str_to_buf("\r\n", conn); + } else { + char *esc = NULL; + size_t esc_len; + esc_len = write_escaped_data(v, strlen(v), &esc); + connection_printf_to_buf(conn, "250+%s=\r\n", k); + connection_write_to_buf(esc, esc_len, TO_CONN(conn)); + tor_free(esc); + } + } + connection_write_str_to_buf("250 OK\r\n", conn); + + done: + SMARTLIST_FOREACH(answers, char *, cp, tor_free(cp)); + smartlist_free(answers); + SMARTLIST_FOREACH(questions, char *, cp, tor_free(cp)); + smartlist_free(questions); + smartlist_free(unrecognized); + tor_free(msg); + + return 0; +} + +/** Given a string, convert it to a circuit purpose. */ +static uint8_t +circuit_purpose_from_string(const char *string) +{ + if (!strcasecmpstart(string, "purpose=")) + string += strlen("purpose="); + + if (!strcasecmp(string, "general")) + return CIRCUIT_PURPOSE_C_GENERAL; + else if (!strcasecmp(string, "controller")) + return CIRCUIT_PURPOSE_CONTROLLER; + else + return CIRCUIT_PURPOSE_UNKNOWN; +} + +/** Return a newly allocated smartlist containing the arguments to the command + * waiting in body. If there are fewer than min_args arguments, + * or if max_args is nonnegative and there are more than + * max_args arguments, send a 512 error to the controller, using + * command as the command name in the error message. */ +static smartlist_t * +getargs_helper(const char *command, control_connection_t *conn, + const char *body, int min_args, int max_args) +{ + smartlist_t *args = smartlist_new(); + smartlist_split_string(args, body, " ", + SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); + if (smartlist_len(args) < min_args) { + connection_printf_to_buf(conn, "512 Missing argument to %s\r\n",command); + goto err; + } else if (max_args >= 0 && smartlist_len(args) > max_args) { + connection_printf_to_buf(conn, "512 Too many arguments to %s\r\n",command); + goto err; + } + return args; + err: + SMARTLIST_FOREACH(args, char *, s, tor_free(s)); + smartlist_free(args); + return NULL; +} + +/** Helper. Return the first element of sl at index start_at or + * higher that starts with prefix, case-insensitive. Return NULL if no + * such element exists. */ +static const char * +find_element_starting_with(smartlist_t *sl, int start_at, const char *prefix) +{ + int i; + for (i = start_at; i < smartlist_len(sl); ++i) { + const char *elt = smartlist_get(sl, i); + if (!strcasecmpstart(elt, prefix)) + return elt; + } + return NULL; +} + +/** Helper. Return true iff s is an argument that we should treat as a + * key-value pair. */ +static int +is_keyval_pair(const char *s) +{ + /* An argument is a key-value pair if it has an =, and it isn't of the form + * $fingeprint=name */ + return strchr(s, '=') && s[0] != '$'; +} + +/** Called when we get an EXTENDCIRCUIT message. Try to extend the listed + * circuit, and report success or failure. */ +static int +handle_control_extendcircuit(control_connection_t *conn, uint32_t len, + const char *body) +{ + smartlist_t *router_nicknames=NULL, *nodes=NULL; + origin_circuit_t *circ = NULL; + int zero_circ; + uint8_t intended_purpose = CIRCUIT_PURPOSE_C_GENERAL; + smartlist_t *args; + (void) len; + + router_nicknames = smartlist_new(); + + args = getargs_helper("EXTENDCIRCUIT", conn, body, 1, -1); + if (!args) + goto done; + + zero_circ = !strcmp("0", (char*)smartlist_get(args,0)); + + if (zero_circ) { + const char *purp = find_element_starting_with(args, 1, "PURPOSE="); + + if (purp) { + intended_purpose = circuit_purpose_from_string(purp); + if (intended_purpose == CIRCUIT_PURPOSE_UNKNOWN) { + connection_printf_to_buf(conn, "552 Unknown purpose \"%s\"\r\n", purp); + SMARTLIST_FOREACH(args, char *, cp, tor_free(cp)); + smartlist_free(args); + goto done; + } + } + + if ((smartlist_len(args) == 1) || + (smartlist_len(args) >= 2 && is_keyval_pair(smartlist_get(args, 1)))) { + // "EXTENDCIRCUIT 0" || EXTENDCIRCUIT 0 foo=bar" + circ = circuit_launch(intended_purpose, CIRCLAUNCH_NEED_CAPACITY); + if (!circ) { + connection_write_str_to_buf("551 Couldn't start circuit\r\n", conn); + } else { + connection_printf_to_buf(conn, "250 EXTENDED %lu\r\n", + (unsigned long)circ->global_identifier); + } + SMARTLIST_FOREACH(args, char *, cp, tor_free(cp)); + smartlist_free(args); + goto done; + } + // "EXTENDCIRCUIT 0 router1,router2" || + // "EXTENDCIRCUIT 0 router1,router2 PURPOSE=foo" + } + + if (!zero_circ && !(circ = get_circ(smartlist_get(args,0)))) { + connection_printf_to_buf(conn, "552 Unknown circuit \"%s\"\r\n", + (char*)smartlist_get(args, 0)); + SMARTLIST_FOREACH(args, char *, cp, tor_free(cp)); + smartlist_free(args); + goto done; + } + + smartlist_split_string(router_nicknames, smartlist_get(args,1), ",", 0, 0); + + SMARTLIST_FOREACH(args, char *, cp, tor_free(cp)); + smartlist_free(args); + + nodes = smartlist_new(); + SMARTLIST_FOREACH_BEGIN(router_nicknames, const char *, n) { + const node_t *node = node_get_by_nickname(n, 1); + if (!node) { + connection_printf_to_buf(conn, "552 No such router \"%s\"\r\n", n); + goto done; + } + if (!node_has_descriptor(node)) { + connection_printf_to_buf(conn, "552 descriptor for \"%s\"\r\n", n); + goto done; + } + smartlist_add(nodes, (void*)node); + } SMARTLIST_FOREACH_END(n); + if (!smartlist_len(nodes)) { + connection_write_str_to_buf("512 No router names provided\r\n", conn); + goto done; + } + + if (zero_circ) { + /* start a new circuit */ + circ = origin_circuit_init(intended_purpose, 0); + } + + /* now circ refers to something that is ready to be extended */ + SMARTLIST_FOREACH(nodes, const node_t *, node, + { + extend_info_t *info = extend_info_from_node(node, 0); + tor_assert(info); /* True, since node_has_descriptor(node) == true */ + circuit_append_new_exit(circ, info); + extend_info_free(info); + }); + + /* now that we've populated the cpath, start extending */ + if (zero_circ) { + int err_reason = 0; + if ((err_reason = circuit_handle_first_hop(circ)) < 0) { + circuit_mark_for_close(TO_CIRCUIT(circ), -err_reason); + connection_write_str_to_buf("551 Couldn't start circuit\r\n", conn); + goto done; + } + } else { + if (circ->base_.state == CIRCUIT_STATE_OPEN) { + int err_reason = 0; + circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_BUILDING); + if ((err_reason = circuit_send_next_onion_skin(circ)) < 0) { + log_info(LD_CONTROL, + "send_next_onion_skin failed; circuit marked for closing."); + circuit_mark_for_close(TO_CIRCUIT(circ), -err_reason); + connection_write_str_to_buf("551 Couldn't send onion skin\r\n", conn); + goto done; + } + } + } + + connection_printf_to_buf(conn, "250 EXTENDED %lu\r\n", + (unsigned long)circ->global_identifier); + if (zero_circ) /* send a 'launched' event, for completeness */ + control_event_circuit_status(circ, CIRC_EVENT_LAUNCHED, 0); + done: + SMARTLIST_FOREACH(router_nicknames, char *, n, tor_free(n)); + smartlist_free(router_nicknames); + smartlist_free(nodes); + return 0; +} + +/** Called when we get a SETCIRCUITPURPOSE message. If we can find the + * circuit and it's a valid purpose, change it. */ +static int +handle_control_setcircuitpurpose(control_connection_t *conn, + uint32_t len, const char *body) +{ + origin_circuit_t *circ = NULL; + uint8_t new_purpose; + smartlist_t *args; + (void) len; /* body is NUL-terminated, so it's safe to ignore the length. */ + + args = getargs_helper("SETCIRCUITPURPOSE", conn, body, 2, -1); + if (!args) + goto done; + + if (!(circ = get_circ(smartlist_get(args,0)))) { + connection_printf_to_buf(conn, "552 Unknown circuit \"%s\"\r\n", + (char*)smartlist_get(args, 0)); + goto done; + } + + { + const char *purp = find_element_starting_with(args,1,"PURPOSE="); + if (!purp) { + connection_write_str_to_buf("552 No purpose given\r\n", conn); + goto done; + } + new_purpose = circuit_purpose_from_string(purp); + if (new_purpose == CIRCUIT_PURPOSE_UNKNOWN) { + connection_printf_to_buf(conn, "552 Unknown purpose \"%s\"\r\n", purp); + goto done; + } + } + + circuit_change_purpose(TO_CIRCUIT(circ), new_purpose); + connection_write_str_to_buf("250 OK\r\n", conn); + + done: + if (args) { + SMARTLIST_FOREACH(args, char *, cp, tor_free(cp)); + smartlist_free(args); + } + return 0; +} + +/** Called when we get an ATTACHSTREAM message. Try to attach the requested + * stream, and report success or failure. */ +static int +handle_control_attachstream(control_connection_t *conn, uint32_t len, + const char *body) +{ + entry_connection_t *ap_conn = NULL; + origin_circuit_t *circ = NULL; + int zero_circ; + smartlist_t *args; + crypt_path_t *cpath=NULL; + int hop=0, hop_line_ok=1; + (void) len; + + args = getargs_helper("ATTACHSTREAM", conn, body, 2, -1); + if (!args) + return 0; + + zero_circ = !strcmp("0", (char*)smartlist_get(args,1)); + + if (!(ap_conn = get_stream(smartlist_get(args, 0)))) { + connection_printf_to_buf(conn, "552 Unknown stream \"%s\"\r\n", + (char*)smartlist_get(args, 0)); + } else if (!zero_circ && !(circ = get_circ(smartlist_get(args, 1)))) { + connection_printf_to_buf(conn, "552 Unknown circuit \"%s\"\r\n", + (char*)smartlist_get(args, 1)); + } else if (circ) { + const char *hopstring = find_element_starting_with(args,2,"HOP="); + if (hopstring) { + hopstring += strlen("HOP="); + hop = (int) tor_parse_ulong(hopstring, 10, 0, INT_MAX, + &hop_line_ok, NULL); + if (!hop_line_ok) { /* broken hop line */ + connection_printf_to_buf(conn, "552 Bad value hop=%s\r\n", hopstring); + } + } + } + SMARTLIST_FOREACH(args, char *, cp, tor_free(cp)); + smartlist_free(args); + if (!ap_conn || (!zero_circ && !circ) || !hop_line_ok) + return 0; + + if (ENTRY_TO_CONN(ap_conn)->state != AP_CONN_STATE_CONTROLLER_WAIT && + ENTRY_TO_CONN(ap_conn)->state != AP_CONN_STATE_CONNECT_WAIT && + ENTRY_TO_CONN(ap_conn)->state != AP_CONN_STATE_RESOLVE_WAIT) { + connection_write_str_to_buf( + "555 Connection is not managed by controller.\r\n", + conn); + return 0; + } + + /* Do we need to detach it first? */ + if (ENTRY_TO_CONN(ap_conn)->state != AP_CONN_STATE_CONTROLLER_WAIT) { + edge_connection_t *edge_conn = ENTRY_TO_EDGE_CONN(ap_conn); + circuit_t *tmpcirc = circuit_get_by_edge_conn(edge_conn); + connection_edge_end(edge_conn, END_STREAM_REASON_TIMEOUT); + /* Un-mark it as ending, since we're going to reuse it. */ + edge_conn->edge_has_sent_end = 0; + edge_conn->end_reason = 0; + if (tmpcirc) + circuit_detach_stream(tmpcirc, edge_conn); + TO_CONN(edge_conn)->state = AP_CONN_STATE_CONTROLLER_WAIT; + } + + if (circ && (circ->base_.state != CIRCUIT_STATE_OPEN)) { + connection_write_str_to_buf( + "551 Can't attach stream to non-open origin circuit\r\n", + conn); + return 0; + } + /* Is this a single hop circuit? */ + if (circ && (circuit_get_cpath_len(circ)<2 || hop==1)) { + const node_t *node = NULL; + char *exit_digest; + if (circ->build_state && + circ->build_state->chosen_exit && + !tor_digest_is_zero(circ->build_state->chosen_exit->identity_digest)) { + exit_digest = circ->build_state->chosen_exit->identity_digest; + node = node_get_by_id(exit_digest); + } + /* Do both the client and relay allow one-hop exit circuits? */ + if (!node || + !node_allows_single_hop_exits(node) || + !get_options()->AllowSingleHopCircuits) { + connection_write_str_to_buf( + "551 Can't attach stream to this one-hop circuit.\r\n", conn); + return 0; + } + ap_conn->chosen_exit_name = tor_strdup(hex_str(exit_digest, DIGEST_LEN)); + } + + if (circ && hop>0) { + /* find this hop in the circuit, and set cpath */ + cpath = circuit_get_cpath_hop(circ, hop); + if (!cpath) { + connection_printf_to_buf(conn, + "551 Circuit doesn't have %d hops.\r\n", hop); + return 0; + } + } + if (connection_ap_handshake_rewrite_and_attach(ap_conn, circ, cpath) < 0) { + connection_write_str_to_buf("551 Unable to attach stream\r\n", conn); + return 0; + } + send_control_done(conn); + return 0; +} + +/** Called when we get a POSTDESCRIPTOR message. Try to learn the provided + * descriptor, and report success or failure. */ +static int +handle_control_postdescriptor(control_connection_t *conn, uint32_t len, + const char *body) +{ + char *desc; + const char *msg=NULL; + uint8_t purpose = ROUTER_PURPOSE_GENERAL; + int cache = 0; /* eventually, we may switch this to 1 */ + + char *cp = memchr(body, '\n', len); + smartlist_t *args = smartlist_new(); + tor_assert(cp); + *cp++ = '\0'; + + smartlist_split_string(args, body, " ", + SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); + SMARTLIST_FOREACH_BEGIN(args, char *, option) { + if (!strcasecmpstart(option, "purpose=")) { + option += strlen("purpose="); + purpose = router_purpose_from_string(option); + if (purpose == ROUTER_PURPOSE_UNKNOWN) { + connection_printf_to_buf(conn, "552 Unknown purpose \"%s\"\r\n", + option); + goto done; + } + } else if (!strcasecmpstart(option, "cache=")) { + option += strlen("cache="); + if (!strcasecmp(option, "no")) + cache = 0; + else if (!strcasecmp(option, "yes")) + cache = 1; + else { + connection_printf_to_buf(conn, "552 Unknown cache request \"%s\"\r\n", + option); + goto done; + } + } else { /* unrecognized argument? */ + connection_printf_to_buf(conn, + "512 Unexpected argument \"%s\" to postdescriptor\r\n", option); + goto done; + } + } SMARTLIST_FOREACH_END(option); + + read_escaped_data(cp, len-(cp-body), &desc); + + switch (router_load_single_router(desc, purpose, cache, &msg)) { + case -1: + if (!msg) msg = "Could not parse descriptor"; + connection_printf_to_buf(conn, "554 %s\r\n", msg); + break; + case 0: + if (!msg) msg = "Descriptor not added"; + connection_printf_to_buf(conn, "251 %s\r\n",msg); + break; + case 1: + send_control_done(conn); + break; + } + + tor_free(desc); + done: + SMARTLIST_FOREACH(args, char *, arg, tor_free(arg)); + smartlist_free(args); + return 0; +} + +/** Called when we receive a REDIRECTSTERAM command. Try to change the target + * address of the named AP stream, and report success or failure. */ +static int +handle_control_redirectstream(control_connection_t *conn, uint32_t len, + const char *body) +{ + entry_connection_t *ap_conn = NULL; + char *new_addr = NULL; + uint16_t new_port = 0; + smartlist_t *args; + (void) len; + + args = getargs_helper("REDIRECTSTREAM", conn, body, 2, -1); + if (!args) + return 0; + + if (!(ap_conn = get_stream(smartlist_get(args, 0))) + || !ap_conn->socks_request) { + connection_printf_to_buf(conn, "552 Unknown stream \"%s\"\r\n", + (char*)smartlist_get(args, 0)); + } else { + int ok = 1; + if (smartlist_len(args) > 2) { /* they included a port too */ + new_port = (uint16_t) tor_parse_ulong(smartlist_get(args, 2), + 10, 1, 65535, &ok, NULL); + } + if (!ok) { + connection_printf_to_buf(conn, "512 Cannot parse port \"%s\"\r\n", + (char*)smartlist_get(args, 2)); + } else { + new_addr = tor_strdup(smartlist_get(args, 1)); + } + } + + SMARTLIST_FOREACH(args, char *, cp, tor_free(cp)); + smartlist_free(args); + if (!new_addr) + return 0; + + strlcpy(ap_conn->socks_request->address, new_addr, + sizeof(ap_conn->socks_request->address)); + if (new_port) + ap_conn->socks_request->port = new_port; + tor_free(new_addr); + send_control_done(conn); + return 0; +} + +/** Called when we get a CLOSESTREAM command; try to close the named stream + * and report success or failure. */ +static int +handle_control_closestream(control_connection_t *conn, uint32_t len, + const char *body) +{ + entry_connection_t *ap_conn=NULL; + uint8_t reason=0; + smartlist_t *args; + int ok; + (void) len; + + args = getargs_helper("CLOSESTREAM", conn, body, 2, -1); + if (!args) + return 0; + + else if (!(ap_conn = get_stream(smartlist_get(args, 0)))) + connection_printf_to_buf(conn, "552 Unknown stream \"%s\"\r\n", + (char*)smartlist_get(args, 0)); + else { + reason = (uint8_t) tor_parse_ulong(smartlist_get(args,1), 10, 0, 255, + &ok, NULL); + if (!ok) { + connection_printf_to_buf(conn, "552 Unrecognized reason \"%s\"\r\n", + (char*)smartlist_get(args, 1)); + ap_conn = NULL; + } + } + SMARTLIST_FOREACH(args, char *, cp, tor_free(cp)); + smartlist_free(args); + if (!ap_conn) + return 0; + + connection_mark_unattached_ap(ap_conn, reason); + send_control_done(conn); + return 0; +} + +/** Called when we get a CLOSECIRCUIT command; try to close the named circuit + * and report success or failure. */ +static int +handle_control_closecircuit(control_connection_t *conn, uint32_t len, + const char *body) +{ + origin_circuit_t *circ = NULL; + int safe = 0; + smartlist_t *args; + (void) len; + + args = getargs_helper("CLOSECIRCUIT", conn, body, 1, -1); + if (!args) + return 0; + + if (!(circ=get_circ(smartlist_get(args, 0)))) + connection_printf_to_buf(conn, "552 Unknown circuit \"%s\"\r\n", + (char*)smartlist_get(args, 0)); + else { + int i; + for (i=1; i < smartlist_len(args); ++i) { + if (!strcasecmp(smartlist_get(args, i), "IfUnused")) + safe = 1; + else + log_info(LD_CONTROL, "Skipping unknown option %s", + (char*)smartlist_get(args,i)); + } + } + SMARTLIST_FOREACH(args, char *, cp, tor_free(cp)); + smartlist_free(args); + if (!circ) + return 0; + + if (!safe || !circ->p_streams) { + circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_REQUESTED); + } + + send_control_done(conn); + return 0; +} + +/** Called when we get a RESOLVE command: start trying to resolve + * the listed addresses. */ +static int +handle_control_resolve(control_connection_t *conn, uint32_t len, + const char *body) +{ + smartlist_t *args, *failed; + int is_reverse = 0; + (void) len; /* body is nul-terminated; it's safe to ignore the length */ + + if (!(conn->event_mask & ((uint32_t)1L<have_sent_protocolinfo = 1; + args = smartlist_new(); + smartlist_split_string(args, body, " ", + SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); + SMARTLIST_FOREACH(args, const char *, arg, { + int ok; + tor_parse_long(arg, 10, 0, LONG_MAX, &ok, NULL); + if (!ok) { + bad_arg = arg; + break; + } + }); + if (bad_arg) { + connection_printf_to_buf(conn, "513 No such version %s\r\n", + escaped(bad_arg)); + /* Don't tolerate bad arguments when not authenticated. */ + if (!STATE_IS_OPEN(TO_CONN(conn)->state)) + connection_mark_for_close(TO_CONN(conn)); + goto done; + } else { + const or_options_t *options = get_options(); + int cookies = options->CookieAuthentication; + char *cfile = get_cookie_file(); + char *abs_cfile; + char *esc_cfile; + char *methods; + abs_cfile = make_path_absolute(cfile); + esc_cfile = esc_for_log(abs_cfile); + { + int passwd = (options->HashedControlPassword != NULL || + options->HashedControlSessionPassword != NULL); + smartlist_t *mlist = smartlist_new(); + if (cookies) { + smartlist_add(mlist, (char*)"COOKIE"); + smartlist_add(mlist, (char*)"SAFECOOKIE"); + } + if (passwd) + smartlist_add(mlist, (char*)"HASHEDPASSWORD"); + if (!cookies && !passwd) + smartlist_add(mlist, (char*)"NULL"); + methods = smartlist_join_strings(mlist, ",", 0, NULL); + smartlist_free(mlist); + } + + connection_printf_to_buf(conn, + "250-PROTOCOLINFO 1\r\n" + "250-AUTH METHODS=%s%s%s\r\n" + "250-VERSION Tor=%s\r\n" + "250 OK\r\n", + methods, + cookies?" COOKIEFILE=":"", + cookies?esc_cfile:"", + escaped(VERSION)); + tor_free(methods); + tor_free(cfile); + tor_free(abs_cfile); + tor_free(esc_cfile); + } + done: + SMARTLIST_FOREACH(args, char *, cp, tor_free(cp)); + smartlist_free(args); + return 0; +} + +/** Called when we get an AUTHCHALLENGE command. */ +static int +handle_control_authchallenge(control_connection_t *conn, uint32_t len, + const char *body) +{ + const char *cp = body; + char *client_nonce; + size_t client_nonce_len; + char server_hash[DIGEST256_LEN]; + char server_hash_encoded[HEX_DIGEST256_LEN+1]; + char server_nonce[SAFECOOKIE_SERVER_NONCE_LEN]; + char server_nonce_encoded[(2*SAFECOOKIE_SERVER_NONCE_LEN) + 1]; + + cp += strspn(cp, " \t\n\r"); + if (!strcasecmpstart(cp, "SAFECOOKIE")) { + cp += strlen("SAFECOOKIE"); + } else { + connection_write_str_to_buf("513 AUTHCHALLENGE only supports SAFECOOKIE " + "authentication\r\n", conn); + connection_mark_for_close(TO_CONN(conn)); + return -1; + } + + if (!authentication_cookie_is_set) { + connection_write_str_to_buf("515 Cookie authentication is disabled\r\n", + conn); + connection_mark_for_close(TO_CONN(conn)); + return -1; + } + + cp += strspn(cp, " \t\n\r"); + if (*cp == '"') { + const char *newcp = + decode_escaped_string(cp, len - (cp - body), + &client_nonce, &client_nonce_len); + if (newcp == NULL) { + connection_write_str_to_buf("513 Invalid quoted client nonce\r\n", + conn); + connection_mark_for_close(TO_CONN(conn)); + return -1; + } + cp = newcp; + } else { + size_t client_nonce_encoded_len = strspn(cp, "0123456789ABCDEFabcdef"); + + client_nonce_len = client_nonce_encoded_len / 2; + client_nonce = tor_malloc_zero(client_nonce_len); + + if (base16_decode(client_nonce, client_nonce_len, + cp, client_nonce_encoded_len) < 0) { + connection_write_str_to_buf("513 Invalid base16 client nonce\r\n", + conn); + connection_mark_for_close(TO_CONN(conn)); + tor_free(client_nonce); + return -1; + } + + cp += client_nonce_encoded_len; + } + + cp += strspn(cp, " \t\n\r"); + if (*cp != '\0' || + cp != body + len) { + connection_write_str_to_buf("513 Junk at end of AUTHCHALLENGE command\r\n", + conn); + connection_mark_for_close(TO_CONN(conn)); + tor_free(client_nonce); + return -1; + } + + tor_assert(!crypto_rand(server_nonce, SAFECOOKIE_SERVER_NONCE_LEN)); + + /* Now compute and send the server-to-controller response, and the + * server's nonce. */ + tor_assert(authentication_cookie != NULL); + + { + size_t tmp_len = (AUTHENTICATION_COOKIE_LEN + + client_nonce_len + + SAFECOOKIE_SERVER_NONCE_LEN); + char *tmp = tor_malloc_zero(tmp_len); + char *client_hash = tor_malloc_zero(DIGEST256_LEN); + memcpy(tmp, authentication_cookie, AUTHENTICATION_COOKIE_LEN); + memcpy(tmp + AUTHENTICATION_COOKIE_LEN, client_nonce, client_nonce_len); + memcpy(tmp + AUTHENTICATION_COOKIE_LEN + client_nonce_len, + server_nonce, SAFECOOKIE_SERVER_NONCE_LEN); + + crypto_hmac_sha256(server_hash, + SAFECOOKIE_SERVER_TO_CONTROLLER_CONSTANT, + strlen(SAFECOOKIE_SERVER_TO_CONTROLLER_CONSTANT), + tmp, + tmp_len); + + crypto_hmac_sha256(client_hash, + SAFECOOKIE_CONTROLLER_TO_SERVER_CONSTANT, + strlen(SAFECOOKIE_CONTROLLER_TO_SERVER_CONSTANT), + tmp, + tmp_len); + + conn->safecookie_client_hash = client_hash; + + tor_free(tmp); + } + + base16_encode(server_hash_encoded, sizeof(server_hash_encoded), + server_hash, sizeof(server_hash)); + base16_encode(server_nonce_encoded, sizeof(server_nonce_encoded), + server_nonce, sizeof(server_nonce)); + + connection_printf_to_buf(conn, + "250 AUTHCHALLENGE SERVERHASH=%s " + "SERVERNONCE=%s\r\n", + server_hash_encoded, + server_nonce_encoded); + + tor_free(client_nonce); + return 0; +} + +/** Called when we get a USEFEATURE command: parse the feature list, and + * set up the control_connection's options properly. */ +static int +handle_control_usefeature(control_connection_t *conn, + uint32_t len, + const char *body) +{ + smartlist_t *args; + int bad = 0; + (void) len; /* body is nul-terminated; it's safe to ignore the length */ + args = smartlist_new(); + smartlist_split_string(args, body, " ", + SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); + SMARTLIST_FOREACH_BEGIN(args, const char *, arg) { + if (!strcasecmp(arg, "VERBOSE_NAMES")) + ; + else if (!strcasecmp(arg, "EXTENDED_EVENTS")) + ; + else { + connection_printf_to_buf(conn, "552 Unrecognized feature \"%s\"\r\n", + arg); + bad = 1; + break; + } + } SMARTLIST_FOREACH_END(arg); + + if (!bad) { + send_control_done(conn); + } + + SMARTLIST_FOREACH(args, char *, cp, tor_free(cp)); + smartlist_free(args); + return 0; +} + +/** Implementation for the DROPGUARDS command. */ +static int +handle_control_dropguards(control_connection_t *conn, + uint32_t len, + const char *body) +{ + smartlist_t *args; + (void) len; /* body is nul-terminated; it's safe to ignore the length */ + args = smartlist_new(); + smartlist_split_string(args, body, " ", + SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); + + if (smartlist_len(args)) { + connection_printf_to_buf(conn, "512 Too many arguments to DROPGUARDS\r\n"); + } else { + remove_all_entry_guards(); + send_control_done(conn); + } + + SMARTLIST_FOREACH(args, char *, cp, tor_free(cp)); + smartlist_free(args); + return 0; +} + +/** Called when conn has no more bytes left on its outbuf. */ +int +connection_control_finished_flushing(control_connection_t *conn) +{ + tor_assert(conn); + return 0; +} + +/** Called when conn has gotten its socket closed. */ +int +connection_control_reached_eof(control_connection_t *conn) +{ + tor_assert(conn); + + log_info(LD_CONTROL,"Control connection reached EOF. Closing."); + connection_mark_for_close(TO_CONN(conn)); + return 0; +} + +/** Shut down this Tor instance in the same way that SIGINT would, but + * with a log message appropriate for the loss of an owning controller. */ +static void +lost_owning_controller(const char *owner_type, const char *loss_manner) +{ + int shutdown_slowly = server_mode(get_options()); + + log_notice(LD_CONTROL, "Owning controller %s has %s -- %s.", + owner_type, loss_manner, + shutdown_slowly ? "shutting down" : "exiting now"); + + /* XXXX Perhaps this chunk of code should be a separate function, + * called here and by process_signal(SIGINT). */ + + if (!shutdown_slowly) { + tor_cleanup(); + exit(0); + } + /* XXXX This will close all listening sockets except control-port + * listeners. Perhaps we should close those too. */ + hibernate_begin_shutdown(); +} + +/** Called when conn is being freed. */ +void +connection_control_closed(control_connection_t *conn) +{ + tor_assert(conn); + + conn->event_mask = 0; + control_update_global_event_mask(); + + if (conn->is_owning_control_connection) { + lost_owning_controller("connection", "closed"); + } +} + +/** Return true iff cmd is allowable (or at least forgivable) at this + * stage of the protocol. */ +static int +is_valid_initial_command(control_connection_t *conn, const char *cmd) +{ + if (conn->base_.state == CONTROL_CONN_STATE_OPEN) + return 1; + if (!strcasecmp(cmd, "PROTOCOLINFO")) + return (!conn->have_sent_protocolinfo && + conn->safecookie_client_hash == NULL); + if (!strcasecmp(cmd, "AUTHCHALLENGE")) + return (conn->safecookie_client_hash == NULL); + if (!strcasecmp(cmd, "AUTHENTICATE") || + !strcasecmp(cmd, "QUIT")) + return 1; + return 0; +} + +/** Do not accept any control command of more than 1MB in length. Anything + * that needs to be anywhere near this long probably means that one of our + * interfaces is broken. */ +#define MAX_COMMAND_LINE_LENGTH (1024*1024) + +/** Wrapper around peek_(evbuffer|buf)_has_control0 command: presents the same + * interface as those underlying functions, but takes a connection_t intead of + * an evbuffer or a buf_t. + */ +static int +peek_connection_has_control0_command(connection_t *conn) +{ + IF_HAS_BUFFEREVENT(conn, { + struct evbuffer *input = bufferevent_get_input(conn->bufev); + return peek_evbuffer_has_control0_command(input); + }) ELSE_IF_NO_BUFFEREVENT { + return peek_buf_has_control0_command(conn->inbuf); + } +} + +/** Called when data has arrived on a v1 control connection: Try to fetch + * commands from conn->inbuf, and execute them. + */ +int +connection_control_process_inbuf(control_connection_t *conn) +{ + size_t data_len; + uint32_t cmd_data_len; + int cmd_len; + char *args; + + tor_assert(conn); + tor_assert(conn->base_.state == CONTROL_CONN_STATE_OPEN || + conn->base_.state == CONTROL_CONN_STATE_NEEDAUTH); + + if (!conn->incoming_cmd) { + conn->incoming_cmd = tor_malloc(1024); + conn->incoming_cmd_len = 1024; + conn->incoming_cmd_cur_len = 0; + } + + if (conn->base_.state == CONTROL_CONN_STATE_NEEDAUTH && + peek_connection_has_control0_command(TO_CONN(conn))) { + /* Detect v0 commands and send a "no more v0" message. */ + size_t body_len; + char buf[128]; + set_uint16(buf+2, htons(0x0000)); /* type == error */ + set_uint16(buf+4, htons(0x0001)); /* code == internal error */ + strlcpy(buf+6, "The v0 control protocol is not supported by Tor 0.1.2.17 " + "and later; upgrade your controller.", + sizeof(buf)-6); + body_len = 2+strlen(buf+6)+2; /* code, msg, nul. */ + set_uint16(buf+0, htons(body_len)); + connection_write_to_buf(buf, 4+body_len, TO_CONN(conn)); + + connection_mark_and_flush(TO_CONN(conn)); + return 0; + } + + again: + while (1) { + size_t last_idx; + int r; + /* First, fetch a line. */ + do { + data_len = conn->incoming_cmd_len - conn->incoming_cmd_cur_len; + r = connection_fetch_from_buf_line(TO_CONN(conn), + conn->incoming_cmd+conn->incoming_cmd_cur_len, + &data_len); + if (r == 0) + /* Line not all here yet. Wait. */ + return 0; + else if (r == -1) { + if (data_len + conn->incoming_cmd_cur_len > MAX_COMMAND_LINE_LENGTH) { + connection_write_str_to_buf("500 Line too long.\r\n", conn); + connection_stop_reading(TO_CONN(conn)); + connection_mark_and_flush(TO_CONN(conn)); + } + while (conn->incoming_cmd_len < data_len+conn->incoming_cmd_cur_len) + conn->incoming_cmd_len *= 2; + conn->incoming_cmd = tor_realloc(conn->incoming_cmd, + conn->incoming_cmd_len); + } + } while (r != 1); + + tor_assert(data_len); + + last_idx = conn->incoming_cmd_cur_len; + conn->incoming_cmd_cur_len += (int)data_len; + + /* We have appended a line to incoming_cmd. Is the command done? */ + if (last_idx == 0 && *conn->incoming_cmd != '+') + /* One line command, didn't start with '+'. */ + break; + /* XXXX this code duplication is kind of dumb. */ + if (last_idx+3 == conn->incoming_cmd_cur_len && + tor_memeq(conn->incoming_cmd + last_idx, ".\r\n", 3)) { + /* Just appended ".\r\n"; we're done. Remove it. */ + conn->incoming_cmd[last_idx] = '\0'; + conn->incoming_cmd_cur_len -= 3; + break; + } else if (last_idx+2 == conn->incoming_cmd_cur_len && + tor_memeq(conn->incoming_cmd + last_idx, ".\n", 2)) { + /* Just appended ".\n"; we're done. Remove it. */ + conn->incoming_cmd[last_idx] = '\0'; + conn->incoming_cmd_cur_len -= 2; + break; + } + /* Otherwise, read another line. */ + } + data_len = conn->incoming_cmd_cur_len; + /* Okay, we now have a command sitting on conn->incoming_cmd. See if we + * recognize it. + */ + cmd_len = 0; + while ((size_t)cmd_len < data_len + && !TOR_ISSPACE(conn->incoming_cmd[cmd_len])) + ++cmd_len; + + conn->incoming_cmd[cmd_len]='\0'; + args = conn->incoming_cmd+cmd_len+1; + tor_assert(data_len>(size_t)cmd_len); + data_len -= (cmd_len+1); /* skip the command and NUL we added after it */ + while (TOR_ISSPACE(*args)) { + ++args; + --data_len; + } + + /* If the connection is already closing, ignore further commands */ + if (TO_CONN(conn)->marked_for_close) { + return 0; + } + + /* Otherwise, Quit is always valid. */ + if (!strcasecmp(conn->incoming_cmd, "QUIT")) { + connection_write_str_to_buf("250 closing connection\r\n", conn); + connection_mark_and_flush(TO_CONN(conn)); + return 0; + } + + if (conn->base_.state == CONTROL_CONN_STATE_NEEDAUTH && + !is_valid_initial_command(conn, conn->incoming_cmd)) { + connection_write_str_to_buf("514 Authentication required.\r\n", conn); + connection_mark_for_close(TO_CONN(conn)); + return 0; + } + + if (data_len >= UINT32_MAX) { + connection_write_str_to_buf("500 A 4GB command? Nice try.\r\n", conn); + connection_mark_for_close(TO_CONN(conn)); + return 0; + } + + /* XXXX Why is this not implemented as a table like the GETINFO + * items are? Even handling the plus signs at the beginnings of + * commands wouldn't be very hard with proper macros. */ + cmd_data_len = (uint32_t)data_len; + if (!strcasecmp(conn->incoming_cmd, "SETCONF")) { + if (handle_control_setconf(conn, cmd_data_len, args)) + return -1; + } else if (!strcasecmp(conn->incoming_cmd, "RESETCONF")) { + if (handle_control_resetconf(conn, cmd_data_len, args)) + return -1; + } else if (!strcasecmp(conn->incoming_cmd, "GETCONF")) { + if (handle_control_getconf(conn, cmd_data_len, args)) + return -1; + } else if (!strcasecmp(conn->incoming_cmd, "+LOADCONF")) { + if (handle_control_loadconf(conn, cmd_data_len, args)) + return -1; + } else if (!strcasecmp(conn->incoming_cmd, "SETEVENTS")) { + if (handle_control_setevents(conn, cmd_data_len, args)) + return -1; + } else if (!strcasecmp(conn->incoming_cmd, "AUTHENTICATE")) { + if (handle_control_authenticate(conn, cmd_data_len, args)) + return -1; + } else if (!strcasecmp(conn->incoming_cmd, "SAVECONF")) { + if (handle_control_saveconf(conn, cmd_data_len, args)) + return -1; + } else if (!strcasecmp(conn->incoming_cmd, "SIGNAL")) { + if (handle_control_signal(conn, cmd_data_len, args)) + return -1; + } else if (!strcasecmp(conn->incoming_cmd, "TAKEOWNERSHIP")) { + if (handle_control_takeownership(conn, cmd_data_len, args)) + return -1; + } else if (!strcasecmp(conn->incoming_cmd, "MAPADDRESS")) { + if (handle_control_mapaddress(conn, cmd_data_len, args)) + return -1; + } else if (!strcasecmp(conn->incoming_cmd, "GETINFO")) { + if (handle_control_getinfo(conn, cmd_data_len, args)) + return -1; + } else if (!strcasecmp(conn->incoming_cmd, "EXTENDCIRCUIT")) { + if (handle_control_extendcircuit(conn, cmd_data_len, args)) + return -1; + } else if (!strcasecmp(conn->incoming_cmd, "SETCIRCUITPURPOSE")) { + if (handle_control_setcircuitpurpose(conn, cmd_data_len, args)) + return -1; + } else if (!strcasecmp(conn->incoming_cmd, "SETROUTERPURPOSE")) { + connection_write_str_to_buf("511 SETROUTERPURPOSE is obsolete.\r\n", conn); + } else if (!strcasecmp(conn->incoming_cmd, "ATTACHSTREAM")) { + if (handle_control_attachstream(conn, cmd_data_len, args)) + return -1; + } else if (!strcasecmp(conn->incoming_cmd, "+POSTDESCRIPTOR")) { + if (handle_control_postdescriptor(conn, cmd_data_len, args)) + return -1; + } else if (!strcasecmp(conn->incoming_cmd, "REDIRECTSTREAM")) { + if (handle_control_redirectstream(conn, cmd_data_len, args)) + return -1; + } else if (!strcasecmp(conn->incoming_cmd, "CLOSESTREAM")) { + if (handle_control_closestream(conn, cmd_data_len, args)) + return -1; + } else if (!strcasecmp(conn->incoming_cmd, "CLOSECIRCUIT")) { + if (handle_control_closecircuit(conn, cmd_data_len, args)) + return -1; + } else if (!strcasecmp(conn->incoming_cmd, "USEFEATURE")) { + if (handle_control_usefeature(conn, cmd_data_len, args)) + return -1; + } else if (!strcasecmp(conn->incoming_cmd, "RESOLVE")) { + if (handle_control_resolve(conn, cmd_data_len, args)) + return -1; + } else if (!strcasecmp(conn->incoming_cmd, "PROTOCOLINFO")) { + if (handle_control_protocolinfo(conn, cmd_data_len, args)) + return -1; + } else if (!strcasecmp(conn->incoming_cmd, "AUTHCHALLENGE")) { + if (handle_control_authchallenge(conn, cmd_data_len, args)) + return -1; + } else if (!strcasecmp(conn->incoming_cmd, "DROPGUARDS")) { + if (handle_control_dropguards(conn, cmd_data_len, args)) + return -1; + } else { + connection_printf_to_buf(conn, "510 Unrecognized command \"%s\"\r\n", + conn->incoming_cmd); + } + + conn->incoming_cmd_cur_len = 0; + goto again; +} + +/** Something major has happened to circuit circ: tell any + * interested control connections. */ +int +control_event_circuit_status(origin_circuit_t *circ, circuit_status_event_t tp, + int reason_code) +{ + const char *status; + char reasons[64] = ""; + if (!EVENT_IS_INTERESTING(EVENT_CIRCUIT_STATUS)) + return 0; + tor_assert(circ); + + switch (tp) + { + case CIRC_EVENT_LAUNCHED: status = "LAUNCHED"; break; + case CIRC_EVENT_BUILT: status = "BUILT"; break; + case CIRC_EVENT_EXTENDED: status = "EXTENDED"; break; + case CIRC_EVENT_FAILED: status = "FAILED"; break; + case CIRC_EVENT_CLOSED: status = "CLOSED"; break; + default: + log_warn(LD_BUG, "Unrecognized status code %d", (int)tp); + tor_fragile_assert(); + return 0; + } + + if (tp == CIRC_EVENT_FAILED || tp == CIRC_EVENT_CLOSED) { + const char *reason_str = circuit_end_reason_to_control_string(reason_code); + char unk_reason_buf[16]; + if (!reason_str) { + tor_snprintf(unk_reason_buf, 16, "UNKNOWN_%d", reason_code); + reason_str = unk_reason_buf; + } + if (reason_code > 0 && reason_code & END_CIRC_REASON_FLAG_REMOTE) { + tor_snprintf(reasons, sizeof(reasons), + " REASON=DESTROYED REMOTE_REASON=%s", reason_str); + } else { + tor_snprintf(reasons, sizeof(reasons), + " REASON=%s", reason_str); + } + } + + { + char *circdesc = circuit_describe_status_for_controller(circ); + const char *sp = strlen(circdesc) ? " " : ""; + send_control_event(EVENT_CIRCUIT_STATUS, ALL_FORMATS, + "650 CIRC %lu %s%s%s%s\r\n", + (unsigned long)circ->global_identifier, + status, sp, + circdesc, + reasons); + tor_free(circdesc); + } + + return 0; +} + +/** Something minor has happened to circuit circ: tell any + * interested control connections. */ +static int +control_event_circuit_status_minor(origin_circuit_t *circ, + circuit_status_minor_event_t e, + int purpose, const struct timeval *tv) +{ + const char *event_desc; + char event_tail[160] = ""; + if (!EVENT_IS_INTERESTING(EVENT_CIRCUIT_STATUS_MINOR)) + return 0; + tor_assert(circ); + + switch (e) + { + case CIRC_MINOR_EVENT_PURPOSE_CHANGED: + event_desc = "PURPOSE_CHANGED"; + + { + /* event_tail can currently be up to 68 chars long */ + const char *hs_state_str = + circuit_purpose_to_controller_hs_state_string(purpose); + tor_snprintf(event_tail, sizeof(event_tail), + " OLD_PURPOSE=%s%s%s", + circuit_purpose_to_controller_string(purpose), + (hs_state_str != NULL) ? " OLD_HS_STATE=" : "", + (hs_state_str != NULL) ? hs_state_str : ""); + } + + break; + case CIRC_MINOR_EVENT_CANNIBALIZED: + event_desc = "CANNIBALIZED"; + + { + /* event_tail can currently be up to 130 chars long */ + const char *hs_state_str = + circuit_purpose_to_controller_hs_state_string(purpose); + const struct timeval *old_timestamp_began = tv; + char tbuf[ISO_TIME_USEC_LEN+1]; + format_iso_time_nospace_usec(tbuf, old_timestamp_began); + + tor_snprintf(event_tail, sizeof(event_tail), + " OLD_PURPOSE=%s%s%s OLD_TIME_CREATED=%s", + circuit_purpose_to_controller_string(purpose), + (hs_state_str != NULL) ? " OLD_HS_STATE=" : "", + (hs_state_str != NULL) ? hs_state_str : "", + tbuf); + } + + break; + default: + log_warn(LD_BUG, "Unrecognized status code %d", (int)e); + tor_fragile_assert(); + return 0; + } + + { + char *circdesc = circuit_describe_status_for_controller(circ); + const char *sp = strlen(circdesc) ? " " : ""; + send_control_event(EVENT_CIRCUIT_STATUS_MINOR, ALL_FORMATS, + "650 CIRC_MINOR %lu %s%s%s%s\r\n", + (unsigned long)circ->global_identifier, + event_desc, sp, + circdesc, + event_tail); + tor_free(circdesc); + } + + return 0; +} + +/** + * circ has changed its purpose from old_purpose: tell any + * interested controllers. + */ +int +control_event_circuit_purpose_changed(origin_circuit_t *circ, + int old_purpose) +{ + return control_event_circuit_status_minor(circ, + CIRC_MINOR_EVENT_PURPOSE_CHANGED, + old_purpose, + NULL); +} + +/** + * circ has changed its purpose from old_purpose, and its + * created-time from old_tv_created: tell any interested controllers. + */ +int +control_event_circuit_cannibalized(origin_circuit_t *circ, + int old_purpose, + const struct timeval *old_tv_created) +{ + return control_event_circuit_status_minor(circ, + CIRC_MINOR_EVENT_CANNIBALIZED, + old_purpose, + old_tv_created); +} + +/** Given an AP connection conn and a len-character buffer + * buf, determine the address:port combination requested on + * conn, and write it to buf. Return 0 on success, -1 on + * failure. */ +static int +write_stream_target_to_buf(entry_connection_t *conn, char *buf, size_t len) +{ + char buf2[256]; + if (conn->chosen_exit_name) + if (tor_snprintf(buf2, sizeof(buf2), ".%s.exit", conn->chosen_exit_name)<0) + return -1; + if (!conn->socks_request) + return -1; + if (tor_snprintf(buf, len, "%s%s%s:%d", + conn->socks_request->address, + conn->chosen_exit_name ? buf2 : "", + !conn->chosen_exit_name && connection_edge_is_rendezvous_stream( + ENTRY_TO_EDGE_CONN(conn)) ? ".onion" : "", + conn->socks_request->port)<0) + return -1; + return 0; +} + +/** Something has happened to the stream associated with AP connection + * conn: tell any interested control connections. */ +int +control_event_stream_status(entry_connection_t *conn, stream_status_event_t tp, + int reason_code) +{ + char reason_buf[64]; + char addrport_buf[64]; + const char *status; + circuit_t *circ; + origin_circuit_t *origin_circ = NULL; + char buf[256]; + const char *purpose = ""; + tor_assert(conn->socks_request); + + if (!EVENT_IS_INTERESTING(EVENT_STREAM_STATUS)) + return 0; + + if (tp == STREAM_EVENT_CLOSED && + (reason_code & END_STREAM_REASON_FLAG_ALREADY_SENT_CLOSED)) + return 0; + + write_stream_target_to_buf(conn, buf, sizeof(buf)); + + reason_buf[0] = '\0'; + switch (tp) + { + case STREAM_EVENT_SENT_CONNECT: status = "SENTCONNECT"; break; + case STREAM_EVENT_SENT_RESOLVE: status = "SENTRESOLVE"; break; + case STREAM_EVENT_SUCCEEDED: status = "SUCCEEDED"; break; + case STREAM_EVENT_FAILED: status = "FAILED"; break; + case STREAM_EVENT_CLOSED: status = "CLOSED"; break; + case STREAM_EVENT_NEW: status = "NEW"; break; + case STREAM_EVENT_NEW_RESOLVE: status = "NEWRESOLVE"; break; + case STREAM_EVENT_FAILED_RETRIABLE: status = "DETACHED"; break; + case STREAM_EVENT_REMAP: status = "REMAP"; break; + default: + log_warn(LD_BUG, "Unrecognized status code %d", (int)tp); + return 0; + } + if (reason_code && (tp == STREAM_EVENT_FAILED || + tp == STREAM_EVENT_CLOSED || + tp == STREAM_EVENT_FAILED_RETRIABLE)) { + const char *reason_str = stream_end_reason_to_control_string(reason_code); + char *r = NULL; + if (!reason_str) { + tor_asprintf(&r, " UNKNOWN_%d", reason_code); + reason_str = r; + } + if (reason_code & END_STREAM_REASON_FLAG_REMOTE) + tor_snprintf(reason_buf, sizeof(reason_buf), + " REASON=END REMOTE_REASON=%s", reason_str); + else + tor_snprintf(reason_buf, sizeof(reason_buf), + " REASON=%s", reason_str); + tor_free(r); + } else if (reason_code && tp == STREAM_EVENT_REMAP) { + switch (reason_code) { + case REMAP_STREAM_SOURCE_CACHE: + strlcpy(reason_buf, " SOURCE=CACHE", sizeof(reason_buf)); + break; + case REMAP_STREAM_SOURCE_EXIT: + strlcpy(reason_buf, " SOURCE=EXIT", sizeof(reason_buf)); + break; + default: + tor_snprintf(reason_buf, sizeof(reason_buf), " REASON=UNKNOWN_%d", + reason_code); + /* XXX do we want SOURCE=UNKNOWN_%d above instead? -RD */ + break; + } + } + + if (tp == STREAM_EVENT_NEW || tp == STREAM_EVENT_NEW_RESOLVE) { + /* + * When the control conn is an AF_UNIX socket and we have no address, + * it gets set to "(Tor_internal)"; see dnsserv_launch_request() in + * dnsserv.c. + */ + if (strcmp(ENTRY_TO_CONN(conn)->address, "(Tor_internal)") != 0) { + tor_snprintf(addrport_buf,sizeof(addrport_buf), " SOURCE_ADDR=%s:%d", + ENTRY_TO_CONN(conn)->address, ENTRY_TO_CONN(conn)->port); + } else { + /* + * else leave it blank so control on AF_UNIX doesn't need to make + * something up. + */ + addrport_buf[0] = '\0'; + } + } else { + addrport_buf[0] = '\0'; + } + + if (tp == STREAM_EVENT_NEW_RESOLVE) { + purpose = " PURPOSE=DNS_REQUEST"; + } else if (tp == STREAM_EVENT_NEW) { + if (conn->use_begindir) { + connection_t *linked = ENTRY_TO_CONN(conn)->linked_conn; + int linked_dir_purpose = -1; + if (linked && linked->type == CONN_TYPE_DIR) + linked_dir_purpose = linked->purpose; + if (DIR_PURPOSE_IS_UPLOAD(linked_dir_purpose)) + purpose = " PURPOSE=DIR_UPLOAD"; + else + purpose = " PURPOSE=DIR_FETCH"; + } else + purpose = " PURPOSE=USER"; + } + + circ = circuit_get_by_edge_conn(ENTRY_TO_EDGE_CONN(conn)); + if (circ && CIRCUIT_IS_ORIGIN(circ)) + origin_circ = TO_ORIGIN_CIRCUIT(circ); + send_control_event(EVENT_STREAM_STATUS, ALL_FORMATS, + "650 STREAM "U64_FORMAT" %s %lu %s%s%s%s\r\n", + U64_PRINTF_ARG(ENTRY_TO_CONN(conn)->global_identifier), + status, + origin_circ? + (unsigned long)origin_circ->global_identifier : 0ul, + buf, reason_buf, addrport_buf, purpose); + + /* XXX need to specify its intended exit, etc? */ + + return 0; +} + +/** Figure out the best name for the target router of an OR connection + * conn, and write it into the len-character buffer + * name. */ +static void +orconn_target_get_name(char *name, size_t len, or_connection_t *conn) +{ + const node_t *node = node_get_by_id(conn->identity_digest); + if (node) { + tor_assert(len > MAX_VERBOSE_NICKNAME_LEN); + node_get_verbose_nickname(node, name); + } else if (! tor_digest_is_zero(conn->identity_digest)) { + name[0] = '$'; + base16_encode(name+1, len-1, conn->identity_digest, + DIGEST_LEN); + } else { + tor_snprintf(name, len, "%s:%d", + conn->base_.address, conn->base_.port); + } +} + +/** Called when the status of an OR connection conn changes: tell any + * interested control connections. tp is the new status for the + * connection. If conn has just closed or failed, then reason + * may be the reason why. + */ +int +control_event_or_conn_status(or_connection_t *conn, or_conn_status_event_t tp, + int reason) +{ + int ncircs = 0; + const char *status; + char name[128]; + char ncircs_buf[32] = {0}; /* > 8 + log10(2^32)=10 + 2 */ + + if (!EVENT_IS_INTERESTING(EVENT_OR_CONN_STATUS)) + return 0; + + switch (tp) + { + case OR_CONN_EVENT_LAUNCHED: status = "LAUNCHED"; break; + case OR_CONN_EVENT_CONNECTED: status = "CONNECTED"; break; + case OR_CONN_EVENT_FAILED: status = "FAILED"; break; + case OR_CONN_EVENT_CLOSED: status = "CLOSED"; break; + case OR_CONN_EVENT_NEW: status = "NEW"; break; + default: + log_warn(LD_BUG, "Unrecognized status code %d", (int)tp); + return 0; + } + if (conn->chan) { + ncircs = circuit_count_pending_on_channel(TLS_CHAN_TO_BASE(conn->chan)); + } else { + ncircs = 0; + } + ncircs += connection_or_get_num_circuits(conn); + if (ncircs && (tp == OR_CONN_EVENT_FAILED || tp == OR_CONN_EVENT_CLOSED)) { + tor_snprintf(ncircs_buf, sizeof(ncircs_buf), " NCIRCS=%d", ncircs); + } + + orconn_target_get_name(name, sizeof(name), conn); + send_control_event(EVENT_OR_CONN_STATUS, ALL_FORMATS, + "650 ORCONN %s %s%s%s%s ID="U64_FORMAT"\r\n", + name, status, + reason ? " REASON=" : "", + orconn_end_reason_to_control_string(reason), + ncircs_buf, + U64_PRINTF_ARG(conn->base_.global_identifier)); + + return 0; +} + +/** + * Print out STREAM_BW event for a single conn + */ +int +control_event_stream_bandwidth(edge_connection_t *edge_conn) +{ + circuit_t *circ; + origin_circuit_t *ocirc; + if (EVENT_IS_INTERESTING(EVENT_STREAM_BANDWIDTH_USED)) { + if (!edge_conn->n_read && !edge_conn->n_written) + return 0; + + send_control_event(EVENT_STREAM_BANDWIDTH_USED, ALL_FORMATS, + "650 STREAM_BW "U64_FORMAT" %lu %lu\r\n", + U64_PRINTF_ARG(edge_conn->base_.global_identifier), + (unsigned long)edge_conn->n_read, + (unsigned long)edge_conn->n_written); + + circ = circuit_get_by_edge_conn(edge_conn); + if (circ && CIRCUIT_IS_ORIGIN(circ)) { + ocirc = TO_ORIGIN_CIRCUIT(circ); + ocirc->n_read_circ_bw += edge_conn->n_read; + ocirc->n_written_circ_bw += edge_conn->n_written; + } + edge_conn->n_written = edge_conn->n_read = 0; + } + + return 0; +} + +/** A second or more has elapsed: tell any interested control + * connections how much bandwidth streams have used. */ +int +control_event_stream_bandwidth_used(void) +{ + if (EVENT_IS_INTERESTING(EVENT_STREAM_BANDWIDTH_USED)) { + smartlist_t *conns = get_connection_array(); + edge_connection_t *edge_conn; + + SMARTLIST_FOREACH_BEGIN(conns, connection_t *, conn) + { + if (conn->type != CONN_TYPE_AP) + continue; + edge_conn = TO_EDGE_CONN(conn); + if (!edge_conn->n_read && !edge_conn->n_written) + continue; + + send_control_event(EVENT_STREAM_BANDWIDTH_USED, ALL_FORMATS, + "650 STREAM_BW "U64_FORMAT" %lu %lu\r\n", + U64_PRINTF_ARG(edge_conn->base_.global_identifier), + (unsigned long)edge_conn->n_read, + (unsigned long)edge_conn->n_written); + + edge_conn->n_written = edge_conn->n_read = 0; + } + SMARTLIST_FOREACH_END(conn); + } + + return 0; +} + +/** A second or more has elapsed: tell any interested control connections + * how much bandwidth origin circuits have used. */ +int +control_event_circ_bandwidth_used(void) +{ + circuit_t *circ; + origin_circuit_t *ocirc; + if (!EVENT_IS_INTERESTING(EVENT_CIRC_BANDWIDTH_USED)) + return 0; + + TOR_LIST_FOREACH(circ, circuit_get_global_list(), head) { + if (!CIRCUIT_IS_ORIGIN(circ)) + continue; + ocirc = TO_ORIGIN_CIRCUIT(circ); + if (!ocirc->n_read_circ_bw && !ocirc->n_written_circ_bw) + continue; + send_control_event(EVENT_CIRC_BANDWIDTH_USED, ALL_FORMATS, + "650 CIRC_BW ID=%d READ=%lu WRITTEN=%lu\r\n", + ocirc->global_identifier, + (unsigned long)ocirc->n_read_circ_bw, + (unsigned long)ocirc->n_written_circ_bw); + ocirc->n_written_circ_bw = ocirc->n_read_circ_bw = 0; + } + + return 0; +} + +/** Print out CONN_BW event for a single OR/DIR/EXIT conn and reset + * bandwidth counters. */ +int +control_event_conn_bandwidth(connection_t *conn) +{ + const char *conn_type_str; + if (!get_options()->TestingEnableConnBwEvent || + !EVENT_IS_INTERESTING(EVENT_CONN_BW)) + return 0; + if (!conn->n_read_conn_bw && !conn->n_written_conn_bw) + return 0; + switch (conn->type) { + case CONN_TYPE_OR: + conn_type_str = "OR"; + break; + case CONN_TYPE_DIR: + conn_type_str = "DIR"; + break; + case CONN_TYPE_EXIT: + conn_type_str = "EXIT"; + break; + default: + return 0; + } + send_control_event(EVENT_CONN_BW, ALL_FORMATS, + "650 CONN_BW ID="U64_FORMAT" TYPE=%s " + "READ=%lu WRITTEN=%lu\r\n", + U64_PRINTF_ARG(conn->global_identifier), + conn_type_str, + (unsigned long)conn->n_read_conn_bw, + (unsigned long)conn->n_written_conn_bw); + conn->n_written_conn_bw = conn->n_read_conn_bw = 0; + return 0; +} + +/** A second or more has elapsed: tell any interested control + * connections how much bandwidth connections have used. */ +int +control_event_conn_bandwidth_used(void) +{ + if (get_options()->TestingEnableConnBwEvent && + EVENT_IS_INTERESTING(EVENT_CONN_BW)) { + SMARTLIST_FOREACH(get_connection_array(), connection_t *, conn, + control_event_conn_bandwidth(conn)); + } + return 0; +} + +/** Helper: iterate over cell statistics of circ and sum up added + * cells, removed cells, and waiting times by cell command and direction. + * Store results in cell_stats. Free cell statistics of the + * circuit afterwards. */ +void +sum_up_cell_stats_by_command(circuit_t *circ, cell_stats_t *cell_stats) +{ + memset(cell_stats, 0, sizeof(cell_stats_t)); + SMARTLIST_FOREACH_BEGIN(circ->testing_cell_stats, + testing_cell_stats_entry_t *, ent) { + tor_assert(ent->command <= CELL_COMMAND_MAX_); + if (!ent->removed && !ent->exitward) { + cell_stats->added_cells_appward[ent->command] += 1; + } else if (!ent->removed && ent->exitward) { + cell_stats->added_cells_exitward[ent->command] += 1; + } else if (!ent->exitward) { + cell_stats->removed_cells_appward[ent->command] += 1; + cell_stats->total_time_appward[ent->command] += ent->waiting_time * 10; + } else { + cell_stats->removed_cells_exitward[ent->command] += 1; + cell_stats->total_time_exitward[ent->command] += ent->waiting_time * 10; + } + tor_free(ent); + } SMARTLIST_FOREACH_END(ent); + smartlist_free(circ->testing_cell_stats); + circ->testing_cell_stats = NULL; +} + +/** Helper: append a cell statistics string to event_parts, + * prefixed with key=. Statistics consist of comma-separated + * key:value pairs with lower-case command strings as keys and cell + * numbers or total waiting times as values. A key:value pair is included + * if the entry in include_if_non_zero is not zero, but with + * the (possibly zero) entry from number_to_include. Both + * arrays are expected to have a length of CELL_COMMAND_MAX_ + 1. If no + * entry in include_if_non_zero is positive, no string will + * be added to event_parts. */ +void +append_cell_stats_by_command(smartlist_t *event_parts, const char *key, + const uint64_t *include_if_non_zero, + const uint64_t *number_to_include) +{ + smartlist_t *key_value_strings = smartlist_new(); + int i; + for (i = 0; i <= CELL_COMMAND_MAX_; i++) { + if (include_if_non_zero[i] > 0) { + smartlist_add_asprintf(key_value_strings, "%s:"U64_FORMAT, + cell_command_to_string(i), + U64_PRINTF_ARG(number_to_include[i])); + } + } + if (smartlist_len(key_value_strings) > 0) { + char *joined = smartlist_join_strings(key_value_strings, ",", 0, NULL); + smartlist_add_asprintf(event_parts, "%s=%s", key, joined); + SMARTLIST_FOREACH(key_value_strings, char *, cp, tor_free(cp)); + tor_free(joined); + } + smartlist_free(key_value_strings); +} + +/** Helper: format cell_stats for circ for inclusion in a + * CELL_STATS event and write result string to event_string. */ +void +format_cell_stats(char **event_string, circuit_t *circ, + cell_stats_t *cell_stats) +{ + smartlist_t *event_parts = smartlist_new(); + if (CIRCUIT_IS_ORIGIN(circ)) { + origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ); + smartlist_add_asprintf(event_parts, "ID=%lu", + (unsigned long)ocirc->global_identifier); + } else if (TO_OR_CIRCUIT(circ)->p_chan) { + or_circuit_t *or_circ = TO_OR_CIRCUIT(circ); + smartlist_add_asprintf(event_parts, "InboundQueue=%lu", + (unsigned long)or_circ->p_circ_id); + smartlist_add_asprintf(event_parts, "InboundConn="U64_FORMAT, + U64_PRINTF_ARG(or_circ->p_chan->global_identifier)); + append_cell_stats_by_command(event_parts, "InboundAdded", + cell_stats->added_cells_appward, + cell_stats->added_cells_appward); + append_cell_stats_by_command(event_parts, "InboundRemoved", + cell_stats->removed_cells_appward, + cell_stats->removed_cells_appward); + append_cell_stats_by_command(event_parts, "InboundTime", + cell_stats->removed_cells_appward, + cell_stats->total_time_appward); + } + if (circ->n_chan) { + smartlist_add_asprintf(event_parts, "OutboundQueue=%lu", + (unsigned long)circ->n_circ_id); + smartlist_add_asprintf(event_parts, "OutboundConn="U64_FORMAT, + U64_PRINTF_ARG(circ->n_chan->global_identifier)); + append_cell_stats_by_command(event_parts, "OutboundAdded", + cell_stats->added_cells_exitward, + cell_stats->added_cells_exitward); + append_cell_stats_by_command(event_parts, "OutboundRemoved", + cell_stats->removed_cells_exitward, + cell_stats->removed_cells_exitward); + append_cell_stats_by_command(event_parts, "OutboundTime", + cell_stats->removed_cells_exitward, + cell_stats->total_time_exitward); + } + *event_string = smartlist_join_strings(event_parts, " ", 0, NULL); + SMARTLIST_FOREACH(event_parts, char *, cp, tor_free(cp)); + smartlist_free(event_parts); +} + +/** A second or more has elapsed: tell any interested control connection + * how many cells have been processed for a given circuit. */ +int +control_event_circuit_cell_stats(void) +{ + circuit_t *circ; + cell_stats_t *cell_stats; + char *event_string; + if (!get_options()->TestingEnableCellStatsEvent || + !EVENT_IS_INTERESTING(EVENT_CELL_STATS)) + return 0; + cell_stats = tor_malloc(sizeof(cell_stats_t));; + TOR_LIST_FOREACH(circ, circuit_get_global_list(), head) { + if (!circ->testing_cell_stats) + continue; + sum_up_cell_stats_by_command(circ, cell_stats); + format_cell_stats(&event_string, circ, cell_stats); + send_control_event(EVENT_CELL_STATS, ALL_FORMATS, + "650 CELL_STATS %s\r\n", event_string); + tor_free(event_string); + } + tor_free(cell_stats); + return 0; +} + +/** Tokens in bucket have been refilled: the read bucket was empty + * for read_empty_time millis, the write bucket was empty for + * write_empty_time millis, and buckets were last refilled + * milliseconds_elapsed millis ago. Only emit TB_EMPTY event if + * either read or write bucket have been empty before. */ +int +control_event_tb_empty(const char *bucket, uint32_t read_empty_time, + uint32_t write_empty_time, + int milliseconds_elapsed) +{ + if (get_options()->TestingEnableTbEmptyEvent && + EVENT_IS_INTERESTING(EVENT_TB_EMPTY) && + (read_empty_time > 0 || write_empty_time > 0)) { + send_control_event(EVENT_TB_EMPTY, ALL_FORMATS, + "650 TB_EMPTY %s READ=%d WRITTEN=%d " + "LAST=%d\r\n", + bucket, read_empty_time, write_empty_time, + milliseconds_elapsed); + } + return 0; +} + +/** A second or more has elapsed: tell any interested control + * connections how much bandwidth we used. */ +int +control_event_bandwidth_used(uint32_t n_read, uint32_t n_written) +{ + if (EVENT_IS_INTERESTING(EVENT_BANDWIDTH_USED)) { + send_control_event(EVENT_BANDWIDTH_USED, ALL_FORMATS, + "650 BW %lu %lu\r\n", + (unsigned long)n_read, + (unsigned long)n_written); + } + + return 0; +} + +/** Called when we are sending a log message to the controllers: suspend + * sending further log messages to the controllers until we're done. Used by + * CONN_LOG_PROTECT. */ +void +disable_control_logging(void) +{ + ++disable_log_messages; +} + +/** We're done sending a log message to the controllers: re-enable controller + * logging. Used by CONN_LOG_PROTECT. */ +void +enable_control_logging(void) +{ + if (--disable_log_messages < 0) + tor_assert(0); +} + +/** We got a log message: tell any interested control connections. */ +void +control_event_logmsg(int severity, uint32_t domain, const char *msg) +{ + int event; + + /* Don't even think of trying to add stuff to a buffer from a cpuworker + * thread. */ + if (! in_main_thread()) + return; + + if (disable_log_messages) + return; + + if (domain == LD_BUG && EVENT_IS_INTERESTING(EVENT_STATUS_GENERAL) && + severity <= LOG_NOTICE) { + char *esc = esc_for_log(msg); + ++disable_log_messages; + control_event_general_status(severity, "BUG REASON=%s", esc); + --disable_log_messages; + tor_free(esc); + } + + event = log_severity_to_event(severity); + if (event >= 0 && EVENT_IS_INTERESTING(event)) { + char *b = NULL; + const char *s; + if (strchr(msg, '\n')) { + char *cp; + b = tor_strdup(msg); + for (cp = b; *cp; ++cp) + if (*cp == '\r' || *cp == '\n') + *cp = ' '; + } + switch (severity) { + case LOG_DEBUG: s = "DEBUG"; break; + case LOG_INFO: s = "INFO"; break; + case LOG_NOTICE: s = "NOTICE"; break; + case LOG_WARN: s = "WARN"; break; + case LOG_ERR: s = "ERR"; break; + default: s = "UnknownLogSeverity"; break; + } + ++disable_log_messages; + send_control_event(event, ALL_FORMATS, "650 %s %s\r\n", s, b?b:msg); + --disable_log_messages; + tor_free(b); + } +} + +/** Called whenever we receive new router descriptors: tell any + * interested control connections. routers is a list of + * routerinfo_t's. + */ +int +control_event_descriptors_changed(smartlist_t *routers) +{ + char *msg; + + if (!EVENT_IS_INTERESTING(EVENT_NEW_DESC)) + return 0; + + { + smartlist_t *names = smartlist_new(); + char *ids; + SMARTLIST_FOREACH(routers, routerinfo_t *, ri, { + char *b = tor_malloc(MAX_VERBOSE_NICKNAME_LEN+1); + router_get_verbose_nickname(b, ri); + smartlist_add(names, b); + }); + ids = smartlist_join_strings(names, " ", 0, NULL); + tor_asprintf(&msg, "650 NEWDESC %s\r\n", ids); + send_control_event_string(EVENT_NEW_DESC, ALL_FORMATS, msg); + tor_free(ids); + tor_free(msg); + SMARTLIST_FOREACH(names, char *, cp, tor_free(cp)); + smartlist_free(names); + } + return 0; +} + +/** Called when an address mapping on from from changes to to. + * expires values less than 3 are special; see connection_edge.c. If + * error is non-NULL, it is an error code describing the failure + * mode of the mapping. + */ +int +control_event_address_mapped(const char *from, const char *to, time_t expires, + const char *error, const int cached) +{ + if (!EVENT_IS_INTERESTING(EVENT_ADDRMAP)) + return 0; + + if (expires < 3 || expires == TIME_MAX) + send_control_event(EVENT_ADDRMAP, ALL_FORMATS, + "650 ADDRMAP %s %s NEVER %s%s" + "CACHED=\"%s\"\r\n", + from, to, error?error:"", error?" ":"", + cached?"YES":"NO"); + else { + char buf[ISO_TIME_LEN+1]; + char buf2[ISO_TIME_LEN+1]; + format_local_iso_time(buf,expires); + format_iso_time(buf2,expires); + send_control_event(EVENT_ADDRMAP, ALL_FORMATS, + "650 ADDRMAP %s %s \"%s\"" + " %s%sEXPIRES=\"%s\" CACHED=\"%s\"\r\n", + from, to, buf, + error?error:"", error?" ":"", + buf2, cached?"YES":"NO"); + } + + return 0; +} + +/** The authoritative dirserver has received a new descriptor that + * has passed basic syntax checks and is properly self-signed. + * + * Notify any interested party of the new descriptor and what has + * been done with it, and also optionally give an explanation/reason. */ +int +control_event_or_authdir_new_descriptor(const char *action, + const char *desc, size_t desclen, + const char *msg) +{ + char firstline[1024]; + char *buf; + size_t totallen; + char *esc = NULL; + size_t esclen; + + if (!EVENT_IS_INTERESTING(EVENT_AUTHDIR_NEWDESCS)) + return 0; + + tor_snprintf(firstline, sizeof(firstline), + "650+AUTHDIR_NEWDESC=\r\n%s\r\n%s\r\n", + action, + msg ? msg : ""); + + /* Escape the server descriptor properly */ + esclen = write_escaped_data(desc, desclen, &esc); + + totallen = strlen(firstline) + esclen + 1; + buf = tor_malloc(totallen); + strlcpy(buf, firstline, totallen); + strlcpy(buf+strlen(firstline), esc, totallen); + send_control_event_string(EVENT_AUTHDIR_NEWDESCS, ALL_FORMATS, + buf); + send_control_event_string(EVENT_AUTHDIR_NEWDESCS, ALL_FORMATS, + "650 OK\r\n"); + tor_free(esc); + tor_free(buf); + + return 0; +} + +/** Helper function for NS-style events. Constructs and sends an event + * of type event with string event_string out of the set of + * networkstatuses statuses. Currently it is used for NS events + * and NEWCONSENSUS events. */ +static int +control_event_networkstatus_changed_helper(smartlist_t *statuses, + uint16_t event, + const char *event_string) +{ + smartlist_t *strs; + char *s, *esc = NULL; + if (!EVENT_IS_INTERESTING(event) || !smartlist_len(statuses)) + return 0; + + strs = smartlist_new(); + smartlist_add(strs, tor_strdup("650+")); + smartlist_add(strs, tor_strdup(event_string)); + smartlist_add(strs, tor_strdup("\r\n")); + SMARTLIST_FOREACH(statuses, const routerstatus_t *, rs, + { + s = networkstatus_getinfo_helper_single(rs); + if (!s) continue; + smartlist_add(strs, s); + }); + + s = smartlist_join_strings(strs, "", 0, NULL); + write_escaped_data(s, strlen(s), &esc); + SMARTLIST_FOREACH(strs, char *, cp, tor_free(cp)); + smartlist_free(strs); + tor_free(s); + send_control_event_string(event, ALL_FORMATS, esc); + send_control_event_string(event, ALL_FORMATS, + "650 OK\r\n"); + + tor_free(esc); + return 0; +} + +/** Called when the routerstatus_ts statuses have changed: sends + * an NS event to any controller that cares. */ +int +control_event_networkstatus_changed(smartlist_t *statuses) +{ + return control_event_networkstatus_changed_helper(statuses, EVENT_NS, "NS"); +} + +/** Called when we get a new consensus networkstatus. Sends a NEWCONSENSUS + * event consisting of an NS-style line for each relay in the consensus. */ +int +control_event_newconsensus(const networkstatus_t *consensus) +{ + if (!control_event_is_interesting(EVENT_NEWCONSENSUS)) + return 0; + return control_event_networkstatus_changed_helper( + consensus->routerstatus_list, EVENT_NEWCONSENSUS, "NEWCONSENSUS"); +} + +/** Called when we compute a new circuitbuildtimeout */ +int +control_event_buildtimeout_set(buildtimeout_set_event_t type, + const char *args) +{ + const char *type_string = NULL; + + if (!control_event_is_interesting(EVENT_BUILDTIMEOUT_SET)) + return 0; + + switch (type) { + case BUILDTIMEOUT_SET_EVENT_COMPUTED: + type_string = "COMPUTED"; + break; + case BUILDTIMEOUT_SET_EVENT_RESET: + type_string = "RESET"; + break; + case BUILDTIMEOUT_SET_EVENT_SUSPENDED: + type_string = "SUSPENDED"; + break; + case BUILDTIMEOUT_SET_EVENT_DISCARD: + type_string = "DISCARD"; + break; + case BUILDTIMEOUT_SET_EVENT_RESUME: + type_string = "RESUME"; + break; + default: + type_string = "UNKNOWN"; + break; + } + + send_control_event(EVENT_BUILDTIMEOUT_SET, ALL_FORMATS, + "650 BUILDTIMEOUT_SET %s %s\r\n", + type_string, args); + + return 0; +} + +/** Called when a signal has been processed from signal_callback */ +int +control_event_signal(uintptr_t signal) +{ + const char *signal_string = NULL; + + if (!control_event_is_interesting(EVENT_SIGNAL)) + return 0; + + switch (signal) { + case SIGHUP: + signal_string = "RELOAD"; + break; + case SIGUSR1: + signal_string = "DUMP"; + break; + case SIGUSR2: + signal_string = "DEBUG"; + break; + case SIGNEWNYM: + signal_string = "NEWNYM"; + break; + case SIGCLEARDNSCACHE: + signal_string = "CLEARDNSCACHE"; + break; + default: + log_warn(LD_BUG, "Unrecognized signal %lu in control_event_signal", + (unsigned long)signal); + return -1; + } + + send_control_event(EVENT_SIGNAL, ALL_FORMATS, "650 SIGNAL %s\r\n", + signal_string); + return 0; +} + +/** Called when a single local_routerstatus_t has changed: Sends an NS event + * to any controller that cares. */ +int +control_event_networkstatus_changed_single(const routerstatus_t *rs) +{ + smartlist_t *statuses; + int r; + + if (!EVENT_IS_INTERESTING(EVENT_NS)) + return 0; + + statuses = smartlist_new(); + smartlist_add(statuses, (void*)rs); + r = control_event_networkstatus_changed(statuses); + smartlist_free(statuses); + return r; +} + +/** Our own router descriptor has changed; tell any controllers that care. + */ +int +control_event_my_descriptor_changed(void) +{ + send_control_event(EVENT_DESCCHANGED, ALL_FORMATS, "650 DESCCHANGED\r\n"); + return 0; +} + +/** Helper: sends a status event where type is one of + * EVENT_STATUS_{GENERAL,CLIENT,SERVER}, where severity is one of + * LOG_{NOTICE,WARN,ERR}, and where format is a printf-style format + * string corresponding to args. */ +static int +control_event_status(int type, int severity, const char *format, va_list args) +{ + char *user_buf = NULL; + char format_buf[160]; + const char *status, *sev; + + switch (type) { + case EVENT_STATUS_GENERAL: + status = "STATUS_GENERAL"; + break; + case EVENT_STATUS_CLIENT: + status = "STATUS_CLIENT"; + break; + case EVENT_STATUS_SERVER: + status = "STATUS_SERVER"; + break; + default: + log_warn(LD_BUG, "Unrecognized status type %d", type); + return -1; + } + switch (severity) { + case LOG_NOTICE: + sev = "NOTICE"; + break; + case LOG_WARN: + sev = "WARN"; + break; + case LOG_ERR: + sev = "ERR"; + break; + default: + log_warn(LD_BUG, "Unrecognized status severity %d", severity); + return -1; + } + if (tor_snprintf(format_buf, sizeof(format_buf), "650 %s %s", + status, sev)<0) { + log_warn(LD_BUG, "Format string too long."); + return -1; + } + tor_vasprintf(&user_buf, format, args); + + send_control_event(type, ALL_FORMATS, "%s %s\r\n", format_buf, user_buf); + tor_free(user_buf); + return 0; +} + +/** Format and send an EVENT_STATUS_GENERAL event whose main text is obtained + * by formatting the arguments using the printf-style format. */ +int +control_event_general_status(int severity, const char *format, ...) +{ + va_list ap; + int r; + if (!EVENT_IS_INTERESTING(EVENT_STATUS_GENERAL)) + return 0; + + va_start(ap, format); + r = control_event_status(EVENT_STATUS_GENERAL, severity, format, ap); + va_end(ap); + return r; +} + +/** Format and send an EVENT_STATUS_CLIENT event whose main text is obtained + * by formatting the arguments using the printf-style format. */ +int +control_event_client_status(int severity, const char *format, ...) +{ + va_list ap; + int r; + if (!EVENT_IS_INTERESTING(EVENT_STATUS_CLIENT)) + return 0; + + va_start(ap, format); + r = control_event_status(EVENT_STATUS_CLIENT, severity, format, ap); + va_end(ap); + return r; +} + +/** Format and send an EVENT_STATUS_SERVER event whose main text is obtained + * by formatting the arguments using the printf-style format. */ +int +control_event_server_status(int severity, const char *format, ...) +{ + va_list ap; + int r; + if (!EVENT_IS_INTERESTING(EVENT_STATUS_SERVER)) + return 0; + + va_start(ap, format); + r = control_event_status(EVENT_STATUS_SERVER, severity, format, ap); + va_end(ap); + return r; +} + +/** Called when the status of an entry guard with the given nickname + * and identity digest has changed to status: tells any + * controllers that care. */ +int +control_event_guard(const char *nickname, const char *digest, + const char *status) +{ + char hbuf[HEX_DIGEST_LEN+1]; + base16_encode(hbuf, sizeof(hbuf), digest, DIGEST_LEN); + if (!EVENT_IS_INTERESTING(EVENT_GUARD)) + return 0; + + { + char buf[MAX_VERBOSE_NICKNAME_LEN+1]; + const node_t *node = node_get_by_id(digest); + if (node) { + node_get_verbose_nickname(node, buf); + } else { + tor_snprintf(buf, sizeof(buf), "$%s~%s", hbuf, nickname); + } + send_control_event(EVENT_GUARD, ALL_FORMATS, + "650 GUARD ENTRY %s %s\r\n", buf, status); + } + return 0; +} + +/** Called when a configuration option changes. This is generally triggered + * by SETCONF requests and RELOAD/SIGHUP signals. The elements is + * a smartlist_t containing (key, value, ...) pairs in sequence. + * value can be NULL. */ +int +control_event_conf_changed(const smartlist_t *elements) +{ + int i; + char *result; + smartlist_t *lines; + if (!EVENT_IS_INTERESTING(EVENT_CONF_CHANGED) || + smartlist_len(elements) == 0) { + return 0; + } + lines = smartlist_new(); + for (i = 0; i < smartlist_len(elements); i += 2) { + char *k = smartlist_get(elements, i); + char *v = smartlist_get(elements, i+1); + if (v == NULL) { + smartlist_add_asprintf(lines, "650-%s", k); + } else { + smartlist_add_asprintf(lines, "650-%s=%s", k, v); + } + } + result = smartlist_join_strings(lines, "\r\n", 0, NULL); + send_control_event(EVENT_CONF_CHANGED, 0, + "650-CONF_CHANGED\r\n%s\r\n650 OK\r\n", result); + tor_free(result); + SMARTLIST_FOREACH(lines, char *, cp, tor_free(cp)); + smartlist_free(lines); + return 0; +} + +/** Helper: Return a newly allocated string containing a path to the + * file where we store our authentication cookie. */ +static char * +get_cookie_file(void) +{ + const or_options_t *options = get_options(); + if (options->CookieAuthFile && strlen(options->CookieAuthFile)) { + return tor_strdup(options->CookieAuthFile); + } else { + return get_datadir_fname("control_auth_cookie"); + } +} + +/* Initialize the cookie-based authentication system of the + * ControlPort. If enabled is 0, then disable the cookie + * authentication system. */ +int +init_control_cookie_authentication(int enabled) +{ + char *fname = NULL; + int retval; + + if (!enabled) { + authentication_cookie_is_set = 0; + return 0; + } + + fname = get_cookie_file(); + retval = init_cookie_authentication(fname, "", /* no header */ + AUTHENTICATION_COOKIE_LEN, + &authentication_cookie, + &authentication_cookie_is_set); + tor_free(fname); + return retval; +} + +/** A copy of the process specifier of Tor's owning controller, or + * NULL if this Tor instance is not currently owned by a process. */ +static char *owning_controller_process_spec = NULL; + +/** A process-termination monitor for Tor's owning controller, or NULL + * if this Tor instance is not currently owned by a process. */ +static tor_process_monitor_t *owning_controller_process_monitor = NULL; + +/** Process-termination monitor callback for Tor's owning controller + * process. */ +static void +owning_controller_procmon_cb(void *unused) +{ + (void)unused; + + lost_owning_controller("process", "vanished"); +} + +/** Set process_spec as Tor's owning controller process. + * Exit on failure. */ +void +monitor_owning_controller_process(const char *process_spec) +{ + const char *msg; + + tor_assert((owning_controller_process_spec == NULL) == + (owning_controller_process_monitor == NULL)); + + if (owning_controller_process_spec != NULL) { + if ((process_spec != NULL) && !strcmp(process_spec, + owning_controller_process_spec)) { + /* Same process -- return now, instead of disposing of and + * recreating the process-termination monitor. */ + return; + } + + /* We are currently owned by a process, and we should no longer be + * owned by it. Free the process-termination monitor. */ + tor_process_monitor_free(owning_controller_process_monitor); + owning_controller_process_monitor = NULL; + + tor_free(owning_controller_process_spec); + owning_controller_process_spec = NULL; + } + + tor_assert((owning_controller_process_spec == NULL) && + (owning_controller_process_monitor == NULL)); + + if (process_spec == NULL) + return; + + owning_controller_process_spec = tor_strdup(process_spec); + owning_controller_process_monitor = + tor_process_monitor_new(tor_libevent_get_base(), + owning_controller_process_spec, + LD_CONTROL, + owning_controller_procmon_cb, NULL, + &msg); + + if (owning_controller_process_monitor == NULL) { + log_err(LD_BUG, "Couldn't create process-termination monitor for " + "owning controller: %s. Exiting.", + msg); + owning_controller_process_spec = NULL; + tor_cleanup(); + exit(0); + } +} + +/** Convert the name of a bootstrapping phase s into strings + * tag and summary suitable for display by the controller. */ +static int +bootstrap_status_to_string(bootstrap_status_t s, const char **tag, + const char **summary) +{ + switch (s) { + case BOOTSTRAP_STATUS_UNDEF: + *tag = "undef"; + *summary = "Undefined"; + break; + case BOOTSTRAP_STATUS_STARTING: + *tag = "starting"; + *summary = "Starting"; + break; + case BOOTSTRAP_STATUS_CONN_DIR: + *tag = "conn_dir"; + *summary = "Connecting to directory server"; + break; + case BOOTSTRAP_STATUS_HANDSHAKE: + *tag = "status_handshake"; + *summary = "Finishing handshake"; + break; + case BOOTSTRAP_STATUS_HANDSHAKE_DIR: + *tag = "handshake_dir"; + *summary = "Finishing handshake with directory server"; + break; + case BOOTSTRAP_STATUS_ONEHOP_CREATE: + *tag = "onehop_create"; + *summary = "Establishing an encrypted directory connection"; + break; + case BOOTSTRAP_STATUS_REQUESTING_STATUS: + *tag = "requesting_status"; + *summary = "Asking for networkstatus consensus"; + break; + case BOOTSTRAP_STATUS_LOADING_STATUS: + *tag = "loading_status"; + *summary = "Loading networkstatus consensus"; + break; + case BOOTSTRAP_STATUS_LOADING_KEYS: + *tag = "loading_keys"; + *summary = "Loading authority key certs"; + break; + case BOOTSTRAP_STATUS_REQUESTING_DESCRIPTORS: + *tag = "requesting_descriptors"; + *summary = "Asking for relay descriptors"; + break; + case BOOTSTRAP_STATUS_LOADING_DESCRIPTORS: + *tag = "loading_descriptors"; + *summary = "Loading relay descriptors"; + break; + case BOOTSTRAP_STATUS_CONN_OR: + *tag = "conn_or"; + *summary = "Connecting to the Tor network"; + break; + case BOOTSTRAP_STATUS_HANDSHAKE_OR: + *tag = "handshake_or"; + *summary = "Finishing handshake with first hop"; + break; + case BOOTSTRAP_STATUS_CIRCUIT_CREATE: + *tag = "circuit_create"; + *summary = "Establishing a Tor circuit"; + break; + case BOOTSTRAP_STATUS_DONE: + *tag = "done"; + *summary = "Done"; + break; + default: +// log_warn(LD_BUG, "Unrecognized bootstrap status code %d", s); + *tag = *summary = "unknown"; + return -1; + } + return 0; +} + +/** What percentage through the bootstrap process are we? We remember + * this so we can avoid sending redundant bootstrap status events, and + * so we can guess context for the bootstrap messages which are + * ambiguous. It starts at 'undef', but gets set to 'starting' while + * Tor initializes. */ +static int bootstrap_percent = BOOTSTRAP_STATUS_UNDEF; + +/** How many problems have we had getting to the next bootstrapping phase? + * These include failure to establish a connection to a Tor relay, + * failures to finish the TLS handshake, failures to validate the + * consensus document, etc. */ +static int bootstrap_problems = 0; + +/* We only tell the controller once we've hit a threshold of problems + * for the current phase. */ +#define BOOTSTRAP_PROBLEM_THRESHOLD 10 + +/** Called when Tor has made progress at bootstrapping its directory + * information and initial circuits. + * + * status is the new status, that is, what task we will be doing + * next. progress is zero if we just started this task, else it + * represents progress on the task. */ +void +control_event_bootstrap(bootstrap_status_t status, int progress) +{ + const char *tag, *summary; + char buf[BOOTSTRAP_MSG_LEN]; + + if (bootstrap_percent == BOOTSTRAP_STATUS_DONE) + return; /* already bootstrapped; nothing to be done here. */ + + /* special case for handshaking status, since our TLS handshaking code + * can't distinguish what the connection is going to be for. */ + if (status == BOOTSTRAP_STATUS_HANDSHAKE) { + if (bootstrap_percent < BOOTSTRAP_STATUS_CONN_OR) { + status = BOOTSTRAP_STATUS_HANDSHAKE_DIR; + } else { + status = BOOTSTRAP_STATUS_HANDSHAKE_OR; + } + } + + if (status > bootstrap_percent || + (progress && progress > bootstrap_percent)) { + bootstrap_status_to_string(status, &tag, &summary); + tor_log(status ? LOG_NOTICE : LOG_INFO, LD_CONTROL, + "Bootstrapped %d%%: %s.", progress ? progress : status, summary); + tor_snprintf(buf, sizeof(buf), + "BOOTSTRAP PROGRESS=%d TAG=%s SUMMARY=\"%s\"", + progress ? progress : status, tag, summary); + tor_snprintf(last_sent_bootstrap_message, + sizeof(last_sent_bootstrap_message), + "NOTICE %s", buf); + control_event_client_status(LOG_NOTICE, "%s", buf); + if (status > bootstrap_percent) { + bootstrap_percent = status; /* new milestone reached */ + } + if (progress > bootstrap_percent) { + /* incremental progress within a milestone */ + bootstrap_percent = progress; + bootstrap_problems = 0; /* Progress! Reset our problem counter. */ + } + } +} + +/** Called when Tor has failed to make bootstrapping progress in a way + * that indicates a problem. warn gives a hint as to why, and + * reason provides an "or_conn_end_reason" tag. + */ +MOCK_IMPL(void, +control_event_bootstrap_problem, (const char *warn, int reason)) +{ + int status = bootstrap_percent; + const char *tag, *summary; + char buf[BOOTSTRAP_MSG_LEN]; + const char *recommendation = "ignore"; + int severity; + + /* bootstrap_percent must not be in "undefined" state here. */ + tor_assert(status >= 0); + + if (bootstrap_percent == 100) + return; /* already bootstrapped; nothing to be done here. */ + + bootstrap_problems++; + + if (bootstrap_problems >= BOOTSTRAP_PROBLEM_THRESHOLD) + recommendation = "warn"; + + if (reason == END_OR_CONN_REASON_NO_ROUTE) + recommendation = "warn"; + + if (get_options()->UseBridges && + !any_bridge_descriptors_known() && + !any_pending_bridge_descriptor_fetches()) + recommendation = "warn"; + + if (we_are_hibernating()) + recommendation = "ignore"; + + while (status>=0 && bootstrap_status_to_string(status, &tag, &summary) < 0) + status--; /* find a recognized status string based on current progress */ + status = bootstrap_percent; /* set status back to the actual number */ + + severity = !strcmp(recommendation, "warn") ? LOG_WARN : LOG_INFO; + + log_fn(severity, + LD_CONTROL, "Problem bootstrapping. Stuck at %d%%: %s. (%s; %s; " + "count %d; recommendation %s)", + status, summary, warn, + orconn_end_reason_to_control_string(reason), + bootstrap_problems, recommendation); + + connection_or_report_broken_states(severity, LD_HANDSHAKE); + + tor_snprintf(buf, sizeof(buf), + "BOOTSTRAP PROGRESS=%d TAG=%s SUMMARY=\"%s\" WARNING=\"%s\" REASON=%s " + "COUNT=%d RECOMMENDATION=%s", + bootstrap_percent, tag, summary, warn, + orconn_end_reason_to_control_string(reason), bootstrap_problems, + recommendation); + tor_snprintf(last_sent_bootstrap_message, + sizeof(last_sent_bootstrap_message), + "WARN %s", buf); + control_event_client_status(LOG_WARN, "%s", buf); +} + +/** We just generated a new summary of which countries we've seen clients + * from recently. Send a copy to the controller in case it wants to + * display it for the user. */ +void +control_event_clients_seen(const char *controller_str) +{ + send_control_event(EVENT_CLIENTS_SEEN, 0, + "650 CLIENTS_SEEN %s\r\n", controller_str); +} + +/** A new pluggable transport called transport_name was + * launched on addr:port. mode is either + * "server" or "client" depending on the mode of the pluggable + * transport. + * "650" SP "TRANSPORT_LAUNCHED" SP Mode SP Name SP Address SP Port + */ +void +control_event_transport_launched(const char *mode, const char *transport_name, + tor_addr_t *addr, uint16_t port) +{ + send_control_event(EVENT_TRANSPORT_LAUNCHED, ALL_FORMATS, + "650 TRANSPORT_LAUNCHED %s %s %s %u\r\n", + mode, transport_name, fmt_addr(addr), port); +} + +/** Convert rendezvous auth type to string for HS_DESC control events + */ +const char * +rend_auth_type_to_string(rend_auth_type_t auth_type) +{ + const char *str; + + switch (auth_type) { + case REND_NO_AUTH: + str = "NO_AUTH"; + break; + case REND_BASIC_AUTH: + str = "BASIC_AUTH"; + break; + case REND_STEALTH_AUTH: + str = "STEALTH_AUTH"; + break; + default: + str = "UNKNOWN"; + } + + return str; +} + +/** Return a longname the node whose identity is id_digest. If + * node_get_by_id() returns NULL, base 16 encoding of id_digest is + * returned instead. + * + * This function is not thread-safe. Each call to this function invalidates + * previous values returned by this function. + */ +MOCK_IMPL(const char *, +node_describe_longname_by_id,(const char *id_digest)) +{ + static char longname[MAX_VERBOSE_NICKNAME_LEN+1]; + node_get_verbose_nickname_by_id(id_digest, longname); + return longname; +} + +/** send HS_DESC requested event. + * + * rend_query is used to fetch requested onion address and auth type. + * hs_dir is the description of contacting hs directory. + * desc_id_base32 is the ID of requested hs descriptor. + */ +void +control_event_hs_descriptor_requested(const rend_data_t *rend_query, + const char *id_digest, + const char *desc_id_base32) +{ + if (!id_digest || !rend_query || !desc_id_base32) { + log_warn(LD_BUG, "Called with rend_query==%p, " + "id_digest==%p, desc_id_base32==%p", + rend_query, id_digest, desc_id_base32); + return; + } + + send_control_event(EVENT_HS_DESC, ALL_FORMATS, + "650 HS_DESC REQUESTED %s %s %s %s\r\n", + rend_query->onion_address, + rend_auth_type_to_string(rend_query->auth_type), + node_describe_longname_by_id(id_digest), + desc_id_base32); +} + +/** send HS_DESC event after got response from hs directory. + * + * NOTE: this is an internal function used by following functions: + * control_event_hs_descriptor_received + * control_event_hs_descriptor_failed + * + * So do not call this function directly. + */ +void +control_event_hs_descriptor_receive_end(const char *action, + const rend_data_t *rend_query, + const char *id_digest) +{ + if (!action || !rend_query || !id_digest) { + log_warn(LD_BUG, "Called with action==%p, rend_query==%p, " + "id_digest==%p", action, rend_query, id_digest); + return; + } + + send_control_event(EVENT_HS_DESC, ALL_FORMATS, + "650 HS_DESC %s %s %s %s\r\n", + action, + rend_query->onion_address, + rend_auth_type_to_string(rend_query->auth_type), + node_describe_longname_by_id(id_digest)); +} + +/** send HS_DESC RECEIVED event + * + * called when a we successfully received a hidden service descriptor. + */ +void +control_event_hs_descriptor_received(const rend_data_t *rend_query, + const char *id_digest) +{ + if (!rend_query || !id_digest) { + log_warn(LD_BUG, "Called with rend_query==%p, id_digest==%p", + rend_query, id_digest); + return; + } + control_event_hs_descriptor_receive_end("RECEIVED", rend_query, id_digest); +} + +/** send HS_DESC FAILED event + * + * called when request for hidden service descriptor returned failure. + */ +void +control_event_hs_descriptor_failed(const rend_data_t *rend_query, + const char *id_digest) +{ + if (!rend_query || !id_digest) { + log_warn(LD_BUG, "Called with rend_query==%p, id_digest==%p", + rend_query, id_digest); + return; + } + control_event_hs_descriptor_receive_end("FAILED", rend_query, id_digest); +} + +/** Free any leftover allocated memory of the control.c subsystem. */ +void +control_free_all(void) +{ + if (authentication_cookie) /* Free the auth cookie */ + tor_free(authentication_cookie); +} + +#ifdef TOR_UNIT_TESTS +/* For testing: change the value of global_event_mask */ +void +control_testing_set_global_event_mask(uint64_t mask) +{ + global_event_mask = mask; +} +#endif + diff --git a/src/tor/control.h b/src/tor/control.h new file mode 100644 index 0000000..0466de1 --- /dev/null +++ b/src/tor/control.h @@ -0,0 +1,205 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file control.h + * \brief Header file for control.c. + **/ + +#ifndef TOR_CONTROL_H +#define TOR_CONTROL_H + +void control_update_global_event_mask(void); +void control_adjust_event_log_severity(void); + +void control_ports_write_to_file(void); + +/** Log information about the connection conn, protecting it as with + * CONN_LOG_PROTECT. Example: + * + * LOG_FN_CONN(conn, (LOG_DEBUG, "Socket %d wants to write", conn->s)); + **/ +#define LOG_FN_CONN(conn, args) \ + CONN_LOG_PROTECT(conn, log_fn args) + +int connection_control_finished_flushing(control_connection_t *conn); +int connection_control_reached_eof(control_connection_t *conn); +void connection_control_closed(control_connection_t *conn); + +int connection_control_process_inbuf(control_connection_t *conn); + +#define EVENT_AUTHDIR_NEWDESCS 0x000D +#define EVENT_NS 0x000F +int control_event_is_interesting(int event); + +int control_event_circuit_status(origin_circuit_t *circ, + circuit_status_event_t e, int reason); +int control_event_circuit_purpose_changed(origin_circuit_t *circ, + int old_purpose); +int control_event_circuit_cannibalized(origin_circuit_t *circ, + int old_purpose, + const struct timeval *old_tv_created); +int control_event_stream_status(entry_connection_t *conn, + stream_status_event_t e, + int reason); +int control_event_or_conn_status(or_connection_t *conn, + or_conn_status_event_t e, int reason); +int control_event_bandwidth_used(uint32_t n_read, uint32_t n_written); +int control_event_stream_bandwidth(edge_connection_t *edge_conn); +int control_event_stream_bandwidth_used(void); +int control_event_circ_bandwidth_used(void); +int control_event_conn_bandwidth(connection_t *conn); +int control_event_conn_bandwidth_used(void); +int control_event_circuit_cell_stats(void); +int control_event_tb_empty(const char *bucket, uint32_t read_empty_time, + uint32_t write_empty_time, + int milliseconds_elapsed); +void control_event_logmsg(int severity, uint32_t domain, const char *msg); +int control_event_descriptors_changed(smartlist_t *routers); +int control_event_address_mapped(const char *from, const char *to, + time_t expires, const char *error, + const int cached); +int control_event_or_authdir_new_descriptor(const char *action, + const char *desc, + size_t desclen, + const char *msg); +int control_event_my_descriptor_changed(void); +int control_event_networkstatus_changed(smartlist_t *statuses); + +int control_event_newconsensus(const networkstatus_t *consensus); +int control_event_networkstatus_changed_single(const routerstatus_t *rs); +int control_event_general_status(int severity, const char *format, ...) + CHECK_PRINTF(2,3); +int control_event_client_status(int severity, const char *format, ...) + CHECK_PRINTF(2,3); +int control_event_server_status(int severity, const char *format, ...) + CHECK_PRINTF(2,3); +int control_event_guard(const char *nickname, const char *digest, + const char *status); +int control_event_conf_changed(const smartlist_t *elements); +int control_event_buildtimeout_set(buildtimeout_set_event_t type, + const char *args); +int control_event_signal(uintptr_t signal); + +int init_control_cookie_authentication(int enabled); +smartlist_t *decode_hashed_passwords(config_line_t *passwords); +void disable_control_logging(void); +void enable_control_logging(void); + +void monitor_owning_controller_process(const char *process_spec); + +void control_event_bootstrap(bootstrap_status_t status, int progress); +MOCK_DECL(void, control_event_bootstrap_problem,(const char *warn, + int reason)); + +void control_event_clients_seen(const char *controller_str); +void control_event_transport_launched(const char *mode, + const char *transport_name, + tor_addr_t *addr, uint16_t port); +const char *rend_auth_type_to_string(rend_auth_type_t auth_type); +MOCK_DECL(const char *, node_describe_longname_by_id,(const char *id_digest)); +void control_event_hs_descriptor_requested(const rend_data_t *rend_query, + const char *desc_id_base32, + const char *hs_dir); +void control_event_hs_descriptor_receive_end(const char *action, + const rend_data_t *rend_query, + const char *hs_dir); +void control_event_hs_descriptor_received(const rend_data_t *rend_query, + const char *hs_dir); +void control_event_hs_descriptor_failed(const rend_data_t *rend_query, + const char *hs_dir); + +void control_free_all(void); + +#ifdef CONTROL_PRIVATE +/* Recognized asynchronous event types. It's okay to expand this list + * because it is used both as a list of v0 event types, and as indices + * into the bitfield to determine which controllers want which events. + */ +#define EVENT_MIN_ 0x0001 +#define EVENT_CIRCUIT_STATUS 0x0001 +#define EVENT_STREAM_STATUS 0x0002 +#define EVENT_OR_CONN_STATUS 0x0003 +#define EVENT_BANDWIDTH_USED 0x0004 +#define EVENT_CIRCUIT_STATUS_MINOR 0x0005 +#define EVENT_NEW_DESC 0x0006 +#define EVENT_DEBUG_MSG 0x0007 +#define EVENT_INFO_MSG 0x0008 +#define EVENT_NOTICE_MSG 0x0009 +#define EVENT_WARN_MSG 0x000A +#define EVENT_ERR_MSG 0x000B +#define EVENT_ADDRMAP 0x000C +/* Exposed above */ +// #define EVENT_AUTHDIR_NEWDESCS 0x000D +#define EVENT_DESCCHANGED 0x000E +/* Exposed above */ +// #define EVENT_NS 0x000F +#define EVENT_STATUS_CLIENT 0x0010 +#define EVENT_STATUS_SERVER 0x0011 +#define EVENT_STATUS_GENERAL 0x0012 +#define EVENT_GUARD 0x0013 +#define EVENT_STREAM_BANDWIDTH_USED 0x0014 +#define EVENT_CLIENTS_SEEN 0x0015 +#define EVENT_NEWCONSENSUS 0x0016 +#define EVENT_BUILDTIMEOUT_SET 0x0017 +#define EVENT_SIGNAL 0x0018 +#define EVENT_CONF_CHANGED 0x0019 +#define EVENT_CONN_BW 0x001A +#define EVENT_CELL_STATS 0x001B +#define EVENT_TB_EMPTY 0x001C +#define EVENT_CIRC_BANDWIDTH_USED 0x001D +#define EVENT_TRANSPORT_LAUNCHED 0x0020 +#define EVENT_HS_DESC 0x0021 +#define EVENT_MAX_ 0x0021 +/* If EVENT_MAX_ ever hits 0x0040, we need to make the mask into a + * different structure. */ + +/* Used only by control.c and test.c */ +STATIC size_t write_escaped_data(const char *data, size_t len, char **out); +STATIC size_t read_escaped_data(const char *data, size_t len, char **out); +/** Flag for event_format_t. Indicates that we should use the one standard + format. (Other formats previous existed, and are now deprecated) + */ +#define ALL_FORMATS 1 +/** Bit field of flags to select how to format a controller event. Recognized + * flag is ALL_FORMATS. */ +typedef int event_format_t; + +#ifdef TOR_UNIT_TESTS +MOCK_DECL(STATIC void, +send_control_event_string,(uint16_t event, event_format_t which, + const char *msg)); + +void control_testing_set_global_event_mask(uint64_t mask); +#endif + +/** Helper structure: temporarily stores cell statistics for a circuit. */ +typedef struct cell_stats_t { + /** Number of cells added in app-ward direction by command. */ + uint64_t added_cells_appward[CELL_COMMAND_MAX_ + 1]; + /** Number of cells added in exit-ward direction by command. */ + uint64_t added_cells_exitward[CELL_COMMAND_MAX_ + 1]; + /** Number of cells removed in app-ward direction by command. */ + uint64_t removed_cells_appward[CELL_COMMAND_MAX_ + 1]; + /** Number of cells removed in exit-ward direction by command. */ + uint64_t removed_cells_exitward[CELL_COMMAND_MAX_ + 1]; + /** Total waiting time of cells in app-ward direction by command. */ + uint64_t total_time_appward[CELL_COMMAND_MAX_ + 1]; + /** Total waiting time of cells in exit-ward direction by command. */ + uint64_t total_time_exitward[CELL_COMMAND_MAX_ + 1]; +} cell_stats_t; +void sum_up_cell_stats_by_command(circuit_t *circ, + cell_stats_t *cell_stats); +void append_cell_stats_by_command(smartlist_t *event_parts, + const char *key, + const uint64_t *include_if_non_zero, + const uint64_t *number_to_include); +void format_cell_stats(char **event_string, circuit_t *circ, + cell_stats_t *cell_stats); +#endif + +#endif + diff --git a/src/tor/cpuworker.c b/src/tor/cpuworker.c new file mode 100644 index 0000000..9611c3b --- /dev/null +++ b/src/tor/cpuworker.c @@ -0,0 +1,718 @@ +/* Copyright (c) 2003-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file cpuworker.c + * \brief Implements a farm of 'CPU worker' processes to perform + * CPU-intensive tasks in another thread or process, to not + * interrupt the main thread. + * + * Right now, we only use this for processing onionskins. + **/ +#include "or.h" +#include "buffers.h" +#include "channel.h" +#include "channeltls.h" +#include "circuitbuild.h" +#include "circuitlist.h" +#include "config.h" +#include "connection.h" +#include "connection_or.h" +#include "cpuworker.h" +#include "onion_main.h" +#include "onion.h" +#include "rephist.h" +#include "router.h" + +/** The maximum number of cpuworker processes we will keep around. */ +#define MAX_CPUWORKERS 16 +/** The minimum number of cpuworker processes we will keep around. */ +#define MIN_CPUWORKERS 1 + +/** The tag specifies which circuit this onionskin was from. */ +#define TAG_LEN 12 + +/** How many cpuworkers we have running right now. */ +static int num_cpuworkers=0; +/** How many of the running cpuworkers have an assigned task right now. */ +static int num_cpuworkers_busy=0; +/** We need to spawn new cpuworkers whenever we rotate the onion keys + * on platforms where execution contexts==processes. This variable stores + * the last time we got a key rotation event. */ +static time_t last_rotation_time=0; + +static void cpuworker_main(void *data) ATTR_NORETURN; +static int spawn_cpuworker(void); +static void spawn_enough_cpuworkers(void); +static void process_pending_task(connection_t *cpuworker); + +/** Initialize the cpuworker subsystem. + */ +void +cpu_init(void) +{ + cpuworkers_rotate(); +} + +/** Called when we're done sending a request to a cpuworker. */ +int +connection_cpu_finished_flushing(connection_t *conn) +{ + tor_assert(conn); + tor_assert(conn->type == CONN_TYPE_CPUWORKER); + return 0; +} + +/** Pack global_id and circ_id; set *tag to the result. (See note on + * cpuworker_main for wire format.) */ +static void +tag_pack(uint8_t *tag, uint64_t chan_id, circid_t circ_id) +{ + /*XXXX RETHINK THIS WHOLE MESS !!!! !NM NM NM NM*/ + /*XXXX DOUBLEPLUSTHIS!!!! AS AS AS AS*/ + set_uint64(tag, chan_id); + set_uint32(tag+8, circ_id); +} + +/** Unpack tag into addr, port, and circ_id. + */ +static void +tag_unpack(const uint8_t *tag, uint64_t *chan_id, circid_t *circ_id) +{ + *chan_id = get_uint64(tag); + *circ_id = get_uint32(tag+8); +} + +/** Magic numbers to make sure our cpuworker_requests don't grow any + * mis-framing bugs. */ +#define CPUWORKER_REQUEST_MAGIC 0xda4afeed +#define CPUWORKER_REPLY_MAGIC 0x5eedf00d + +/** A request sent to a cpuworker. */ +typedef struct cpuworker_request_t { + /** Magic number; must be CPUWORKER_REQUEST_MAGIC. */ + uint32_t magic; + /** Opaque tag to identify the job */ + uint8_t tag[TAG_LEN]; + /** Task code. Must be one of CPUWORKER_TASK_* */ + uint8_t task; + + /** Flag: Are we timing this request? */ + unsigned timed : 1; + /** If we're timing this request, when was it sent to the cpuworker? */ + struct timeval started_at; + + /** A create cell for the cpuworker to process. */ + create_cell_t create_cell; + + /* Turn the above into a tagged union if needed. */ +} cpuworker_request_t; + +/** A reply sent by a cpuworker. */ +typedef struct cpuworker_reply_t { + /** Magic number; must be CPUWORKER_REPLY_MAGIC. */ + uint32_t magic; + /** Opaque tag to identify the job; matches the request's tag.*/ + uint8_t tag[TAG_LEN]; + /** True iff we got a successful request. */ + uint8_t success; + + /** Are we timing this request? */ + unsigned int timed : 1; + /** What handshake type was the request? (Used for timing) */ + uint16_t handshake_type; + /** When did we send the request to the cpuworker? */ + struct timeval started_at; + /** Once the cpuworker received the request, how many microseconds did it + * take? (This shouldn't overflow; 4 billion micoseconds is over an hour, + * and we'll never have an onion handshake that takes so long.) */ + uint32_t n_usec; + + /** Output of processing a create cell + * + * @{ + */ + /** The created cell to send back. */ + created_cell_t created_cell; + /** The keys to use on this circuit. */ + uint8_t keys[CPATH_KEY_MATERIAL_LEN]; + /** Input to use for authenticating introduce1 cells. */ + uint8_t rend_auth_material[DIGEST_LEN]; +} cpuworker_reply_t; + +/** Called when the onion key has changed and we need to spawn new + * cpuworkers. Close all currently idle cpuworkers, and mark the last + * rotation time as now. + */ +void +cpuworkers_rotate(void) +{ + connection_t *cpuworker; + while ((cpuworker = connection_get_by_type_state(CONN_TYPE_CPUWORKER, + CPUWORKER_STATE_IDLE))) { + connection_mark_for_close(cpuworker); + --num_cpuworkers; + } + last_rotation_time = time(NULL); + if (server_mode(get_options())) + spawn_enough_cpuworkers(); +} + +/** If the cpuworker closes the connection, + * mark it as closed and spawn a new one as needed. */ +int +connection_cpu_reached_eof(connection_t *conn) +{ + log_warn(LD_GENERAL,"Read eof. CPU worker died unexpectedly."); + if (conn->state != CPUWORKER_STATE_IDLE) { + /* the circ associated with this cpuworker will have to wait until + * it gets culled in run_connection_housekeeping(), since we have + * no way to find out which circ it was. */ + log_warn(LD_GENERAL,"...and it left a circuit queued; abandoning circ."); + num_cpuworkers_busy--; + } + num_cpuworkers--; + spawn_enough_cpuworkers(); /* try to regrow. hope we don't end up + spinning. */ + connection_mark_for_close(conn); + return 0; +} + +/** Indexed by handshake type: how many onionskins have we processed and + * counted of that type? */ +static uint64_t onionskins_n_processed[MAX_ONION_HANDSHAKE_TYPE+1]; +/** Indexed by handshake type, corresponding to the onionskins counted in + * onionskins_n_processed: how many microseconds have we spent in cpuworkers + * processing that kind of onionskin? */ +static uint64_t onionskins_usec_internal[MAX_ONION_HANDSHAKE_TYPE+1]; +/** Indexed by handshake type, corresponding to onionskins counted in + * onionskins_n_processed: how many microseconds have we spent waiting for + * cpuworkers to give us answers for that kind of onionskin? + */ +static uint64_t onionskins_usec_roundtrip[MAX_ONION_HANDSHAKE_TYPE+1]; + +/** If any onionskin takes longer than this, we clip them to this + * time. (microseconds) */ +#define MAX_BELIEVABLE_ONIONSKIN_DELAY (2*1000*1000) + +static tor_weak_rng_t request_sample_rng = TOR_WEAK_RNG_INIT; + +/** Return true iff we'd like to measure a handshake of type + * onionskin_type. Call only from the main thread. */ +static int +should_time_request(uint16_t onionskin_type) +{ + /* If we've never heard of this type, we shouldn't even be here. */ + if (onionskin_type > MAX_ONION_HANDSHAKE_TYPE) + return 0; + /* Measure the first N handshakes of each type, to ensure we have a + * sample */ + if (onionskins_n_processed[onionskin_type] < 4096) + return 1; + /** Otherwise, measure with P=1/128. We avoid doing this for every + * handshake, since the measurement itself can take a little time. */ + return tor_weak_random_one_in_n(&request_sample_rng, 128); +} + +/** Return an estimate of how many microseconds we will need for a single + * cpuworker to to process n_requests onionskins of type + * onionskin_type. */ +uint64_t +estimated_usec_for_onionskins(uint32_t n_requests, uint16_t onionskin_type) +{ + if (onionskin_type > MAX_ONION_HANDSHAKE_TYPE) /* should be impossible */ + return 1000 * (uint64_t)n_requests; + if (PREDICT_UNLIKELY(onionskins_n_processed[onionskin_type] < 100)) { + /* Until we have 100 data points, just asssume everything takes 1 msec. */ + return 1000 * (uint64_t)n_requests; + } else { + /* This can't overflow: we'll never have more than 500000 onionskins + * measured in onionskin_usec_internal, and they won't take anything near + * 1 sec each, and we won't have anything like 1 million queued + * onionskins. But that's 5e5 * 1e6 * 1e6, which is still less than + * UINT64_MAX. */ + return (onionskins_usec_internal[onionskin_type] * n_requests) / + onionskins_n_processed[onionskin_type]; + } +} + +/** Compute the absolute and relative overhead of using the cpuworker + * framework for onionskins of type onionskin_type.*/ +static int +get_overhead_for_onionskins(uint32_t *usec_out, double *frac_out, + uint16_t onionskin_type) +{ + uint64_t overhead; + + *usec_out = 0; + *frac_out = 0.0; + + if (onionskin_type > MAX_ONION_HANDSHAKE_TYPE) /* should be impossible */ + return -1; + if (onionskins_n_processed[onionskin_type] == 0 || + onionskins_usec_internal[onionskin_type] == 0 || + onionskins_usec_roundtrip[onionskin_type] == 0) + return -1; + + overhead = onionskins_usec_roundtrip[onionskin_type] - + onionskins_usec_internal[onionskin_type]; + + *usec_out = (uint32_t)(overhead / onionskins_n_processed[onionskin_type]); + *frac_out = U64_TO_DBL(overhead) / onionskins_usec_internal[onionskin_type]; + + return 0; +} + +/** If we've measured overhead for onionskins of type onionskin_type, + * log it. */ +void +cpuworker_log_onionskin_overhead(int severity, int onionskin_type, + const char *onionskin_type_name) +{ + uint32_t overhead; + double relative_overhead; + int r; + + r = get_overhead_for_onionskins(&overhead, &relative_overhead, + onionskin_type); + if (!overhead || r<0) + return; + + log_fn(severity, LD_OR, + "%s onionskins have averaged %u usec overhead (%.2f%%) in " + "cpuworker code ", + onionskin_type_name, (unsigned)overhead, relative_overhead*100); +} + +/** Called when we get data from a cpuworker. If the answer is not complete, + * wait for a complete answer. If the answer is complete, + * process it as appropriate. + */ +int +connection_cpu_process_inbuf(connection_t *conn) +{ + uint64_t chan_id; + circid_t circ_id; + channel_t *p_chan = NULL; + circuit_t *circ; + + tor_assert(conn); + tor_assert(conn->type == CONN_TYPE_CPUWORKER); + + if (!connection_get_inbuf_len(conn)) + return 0; + + if (conn->state == CPUWORKER_STATE_BUSY_ONION) { + cpuworker_reply_t rpl; + if (connection_get_inbuf_len(conn) < sizeof(cpuworker_reply_t)) + return 0; /* not yet */ + tor_assert(connection_get_inbuf_len(conn) == sizeof(cpuworker_reply_t)); + + connection_fetch_from_buf((void*)&rpl,sizeof(cpuworker_reply_t),conn); + + tor_assert(rpl.magic == CPUWORKER_REPLY_MAGIC); + + if (rpl.timed && rpl.success && + rpl.handshake_type <= MAX_ONION_HANDSHAKE_TYPE) { + /* Time how long this request took. The handshake_type check should be + needless, but let's leave it in to be safe. */ + struct timeval tv_end, tv_diff; + int64_t usec_roundtrip; + tor_gettimeofday(&tv_end); + timersub(&tv_end, &rpl.started_at, &tv_diff); + usec_roundtrip = ((int64_t)tv_diff.tv_sec)*1000000 + tv_diff.tv_usec; + if (usec_roundtrip >= 0 && + usec_roundtrip < MAX_BELIEVABLE_ONIONSKIN_DELAY) { + ++onionskins_n_processed[rpl.handshake_type]; + onionskins_usec_internal[rpl.handshake_type] += rpl.n_usec; + onionskins_usec_roundtrip[rpl.handshake_type] += usec_roundtrip; + if (onionskins_n_processed[rpl.handshake_type] >= 500000) { + /* Scale down every 500000 handshakes. On a busy server, that's + * less impressive than it sounds. */ + onionskins_n_processed[rpl.handshake_type] /= 2; + onionskins_usec_internal[rpl.handshake_type] /= 2; + onionskins_usec_roundtrip[rpl.handshake_type] /= 2; + } + } + } + /* parse out the circ it was talking about */ + tag_unpack(rpl.tag, &chan_id, &circ_id); + circ = NULL; + log_debug(LD_OR, + "Unpacking cpuworker reply, chan_id is " U64_FORMAT + ", circ_id is %u", + U64_PRINTF_ARG(chan_id), (unsigned)circ_id); + p_chan = channel_find_by_global_id(chan_id); + + if (p_chan) + circ = circuit_get_by_circid_channel(circ_id, p_chan); + + if (rpl.success == 0) { + log_debug(LD_OR, + "decoding onionskin failed. " + "(Old key or bad software.) Closing."); + if (circ) + circuit_mark_for_close(circ, END_CIRC_REASON_TORPROTOCOL); + goto done_processing; + } + if (!circ) { + /* This happens because somebody sends us a destroy cell and the + * circuit goes away, while the cpuworker is working. This is also + * why our tag doesn't include a pointer to the circ, because we'd + * never know if it's still valid. + */ + log_debug(LD_OR,"processed onion for a circ that's gone. Dropping."); + goto done_processing; + } + tor_assert(! CIRCUIT_IS_ORIGIN(circ)); + if (onionskin_answer(TO_OR_CIRCUIT(circ), + &rpl.created_cell, + (const char*)rpl.keys, + rpl.rend_auth_material) < 0) { + log_warn(LD_OR,"onionskin_answer failed. Closing."); + circuit_mark_for_close(circ, END_CIRC_REASON_INTERNAL); + goto done_processing; + } + log_debug(LD_OR,"onionskin_answer succeeded. Yay."); + } else { + tor_assert(0); /* don't ask me to do handshakes yet */ + } + + done_processing: + conn->state = CPUWORKER_STATE_IDLE; + num_cpuworkers_busy--; + if (conn->timestamp_created < last_rotation_time) { + connection_mark_for_close(conn); + num_cpuworkers--; + spawn_enough_cpuworkers(); + } else { + process_pending_task(conn); + } + return 0; +} + +/** Implement a cpuworker. 'data' is an fdarray as returned by socketpair. + * Read and writes from fdarray[1]. Reads requests, writes answers. + * + * Request format: + * cpuworker_request_t. + * Response format: + * cpuworker_reply_t + */ +static void +cpuworker_main(void *data) +{ + /* For talking to the parent thread/process */ + tor_socket_t *fdarray = data; + tor_socket_t fd; + + /* variables for onion processing */ + server_onion_keys_t onion_keys; + cpuworker_request_t req; + cpuworker_reply_t rpl; + + fd = fdarray[1]; /* this side is ours */ +#ifndef TOR_IS_MULTITHREADED + tor_close_socket(fdarray[0]); /* this is the side of the socketpair the + * parent uses */ + tor_free_all(1); /* so the child doesn't hold the parent's fd's open */ + handle_signals(0); /* ignore interrupts from the keyboard, etc */ +#endif + tor_free(data); + + setup_server_onion_keys(&onion_keys); + + for (;;) { + if (read_all(fd, (void *)&req, sizeof(req), 1) != sizeof(req)) { + log_info(LD_OR, "read request failed. Exiting."); + goto end; + } + tor_assert(req.magic == CPUWORKER_REQUEST_MAGIC); + + memset(&rpl, 0, sizeof(rpl)); + + if (req.task == CPUWORKER_TASK_ONION) { + const create_cell_t *cc = &req.create_cell; + created_cell_t *cell_out = &rpl.created_cell; + struct timeval tv_start, tv_end; + int n; + rpl.timed = req.timed; + rpl.started_at = req.started_at; + rpl.handshake_type = cc->handshake_type; + if (req.timed) + tor_gettimeofday(&tv_start); + n = onion_skin_server_handshake(cc->handshake_type, + cc->onionskin, cc->handshake_len, + &onion_keys, + cell_out->reply, + rpl.keys, CPATH_KEY_MATERIAL_LEN, + rpl.rend_auth_material); + if (n < 0) { + /* failure */ + log_debug(LD_OR,"onion_skin_server_handshake failed."); + memset(&rpl, 0, sizeof(rpl)); + memcpy(rpl.tag, req.tag, TAG_LEN); + rpl.success = 0; + } else { + /* success */ + log_debug(LD_OR,"onion_skin_server_handshake succeeded."); + memcpy(rpl.tag, req.tag, TAG_LEN); + cell_out->handshake_len = n; + switch (cc->cell_type) { + case CELL_CREATE: + cell_out->cell_type = CELL_CREATED; break; + case CELL_CREATE2: + cell_out->cell_type = CELL_CREATED2; break; + case CELL_CREATE_FAST: + cell_out->cell_type = CELL_CREATED_FAST; break; + default: + tor_assert(0); + goto end; + } + rpl.success = 1; + } + rpl.magic = CPUWORKER_REPLY_MAGIC; + if (req.timed) { + struct timeval tv_diff; + int64_t usec; + tor_gettimeofday(&tv_end); + timersub(&tv_end, &tv_start, &tv_diff); + usec = ((int64_t)tv_diff.tv_sec)*1000000 + tv_diff.tv_usec; + if (usec < 0 || usec > MAX_BELIEVABLE_ONIONSKIN_DELAY) + rpl.n_usec = MAX_BELIEVABLE_ONIONSKIN_DELAY; + else + rpl.n_usec = (uint32_t) usec; + } + if (write_all(fd, (void*)&rpl, sizeof(rpl), 1) != sizeof(rpl)) { + log_err(LD_BUG,"writing response buf failed. Exiting."); + goto end; + } + log_debug(LD_OR,"finished writing response."); + } else if (req.task == CPUWORKER_TASK_SHUTDOWN) { + log_info(LD_OR,"Clean shutdown: exiting"); + goto end; + } + memwipe(&req, 0, sizeof(req)); + memwipe(&rpl, 0, sizeof(req)); + } + end: + memwipe(&req, 0, sizeof(req)); + memwipe(&rpl, 0, sizeof(req)); + release_server_onion_keys(&onion_keys); + tor_close_socket(fd); + crypto_thread_cleanup(); + spawn_exit(); +} + +/** Launch a new cpuworker. Return 0 if we're happy, -1 if we failed. + */ +static int +spawn_cpuworker(void) +{ + tor_socket_t *fdarray; + tor_socket_t fd; + connection_t *conn; + int err; + + fdarray = tor_malloc(sizeof(tor_socket_t)*2); + if ((err = tor_socketpair(AF_UNIX, SOCK_STREAM, 0, fdarray)) < 0) { + log_warn(LD_NET, "Couldn't construct socketpair for cpuworker: %s", + tor_socket_strerror(-err)); + tor_free(fdarray); + return -1; + } + + tor_assert(SOCKET_OK(fdarray[0])); + tor_assert(SOCKET_OK(fdarray[1])); + + fd = fdarray[0]; + spawn_func(cpuworker_main, (void*)fdarray); + log_debug(LD_OR,"just spawned a cpu worker."); +#ifndef TOR_IS_MULTITHREADED + tor_close_socket(fdarray[1]); /* don't need the worker's side of the pipe */ + tor_free(fdarray); +#endif + + conn = connection_new(CONN_TYPE_CPUWORKER, AF_UNIX); + + /* set up conn so it's got all the data we need to remember */ + conn->s = fd; + conn->address = tor_strdup("localhost"); + tor_addr_make_unspec(&conn->addr); + + if (set_socket_nonblocking(fd) == -1) { + connection_free(conn); /* this closes fd */ + return -1; + } + + if (connection_add(conn) < 0) { /* no space, forget it */ + log_warn(LD_NET,"connection_add for cpuworker failed. Giving up."); + connection_free(conn); /* this closes fd */ + return -1; + } + + conn->state = CPUWORKER_STATE_IDLE; + connection_start_reading(conn); + + return 0; /* success */ +} + +/** If we have too few or too many active cpuworkers, try to spawn new ones + * or kill idle ones. + */ +static void +spawn_enough_cpuworkers(void) +{ + int num_cpuworkers_needed = get_num_cpus(get_options()); + int reseed = 0; + + if (num_cpuworkers_needed < MIN_CPUWORKERS) + num_cpuworkers_needed = MIN_CPUWORKERS; + if (num_cpuworkers_needed > MAX_CPUWORKERS) + num_cpuworkers_needed = MAX_CPUWORKERS; + + while (num_cpuworkers < num_cpuworkers_needed) { + if (spawn_cpuworker() < 0) { + log_warn(LD_GENERAL,"Cpuworker spawn failed. Will try again later."); + return; + } + num_cpuworkers++; + reseed++; + } + + if (reseed) + crypto_seed_weak_rng(&request_sample_rng); +} + +/** Take a pending task from the queue and assign it to 'cpuworker'. */ +static void +process_pending_task(connection_t *cpuworker) +{ + or_circuit_t *circ; + create_cell_t *onionskin = NULL; + + tor_assert(cpuworker); + + /* for now only process onion tasks */ + + circ = onion_next_task(&onionskin); + if (!circ) + return; + if (assign_onionskin_to_cpuworker(cpuworker, circ, onionskin)) + log_warn(LD_OR,"assign_to_cpuworker failed. Ignoring."); +} + +/** How long should we let a cpuworker stay busy before we give + * up on it and decide that we have a bug or infinite loop? + * This value is high because some servers with low memory/cpu + * sometimes spend an hour or more swapping, and Tor starves. */ +#define CPUWORKER_BUSY_TIMEOUT (60*60*12) + +/** We have a bug that I can't find. Sometimes, very rarely, cpuworkers get + * stuck in the 'busy' state, even though the cpuworker process thinks of + * itself as idle. I don't know why. But here's a workaround to kill any + * cpuworker that's been busy for more than CPUWORKER_BUSY_TIMEOUT. + */ +static void +cull_wedged_cpuworkers(void) +{ + time_t now = time(NULL); + smartlist_t *conns = get_connection_array(); + SMARTLIST_FOREACH_BEGIN(conns, connection_t *, conn) { + if (!conn->marked_for_close && + conn->type == CONN_TYPE_CPUWORKER && + conn->state == CPUWORKER_STATE_BUSY_ONION && + conn->timestamp_lastwritten + CPUWORKER_BUSY_TIMEOUT < now) { + log_notice(LD_BUG, + "closing wedged cpuworker. Can somebody find the bug?"); + num_cpuworkers_busy--; + num_cpuworkers--; + connection_mark_for_close(conn); + } + } SMARTLIST_FOREACH_END(conn); +} + +/** Try to tell a cpuworker to perform the public key operations necessary to + * respond to onionskin for the circuit circ. + * + * If cpuworker is defined, assert that he's idle, and use him. Else, + * look for an idle cpuworker and use him. If none idle, queue task onto the + * pending onion list and return. Return 0 if we successfully assign the + * task, or -1 on failure. + */ +int +assign_onionskin_to_cpuworker(connection_t *cpuworker, + or_circuit_t *circ, + create_cell_t *onionskin) +{ + cpuworker_request_t req; + time_t now = approx_time(); + static time_t last_culled_cpuworkers = 0; + int should_time; + + /* Checking for wedged cpuworkers requires a linear search over all + * connections, so let's do it only once a minute. + */ +#define CULL_CPUWORKERS_INTERVAL 60 + + if (last_culled_cpuworkers + CULL_CPUWORKERS_INTERVAL <= now) { + cull_wedged_cpuworkers(); + spawn_enough_cpuworkers(); + last_culled_cpuworkers = now; + } + + if (1) { + if (num_cpuworkers_busy == num_cpuworkers) { + log_debug(LD_OR,"No idle cpuworkers. Queuing."); + if (onion_pending_add(circ, onionskin) < 0) { + tor_free(onionskin); + return -1; + } + return 0; + } + + if (!cpuworker) + cpuworker = connection_get_by_type_state(CONN_TYPE_CPUWORKER, + CPUWORKER_STATE_IDLE); + + tor_assert(cpuworker); + + if (!circ->p_chan) { + log_info(LD_OR,"circ->p_chan gone. Failing circ."); + tor_free(onionskin); + return -1; + } + + if (connection_or_digest_is_known_relay(circ->p_chan->identity_digest)) + rep_hist_note_circuit_handshake_completed(onionskin->handshake_type); + + should_time = should_time_request(onionskin->handshake_type); + memset(&req, 0, sizeof(req)); + req.magic = CPUWORKER_REQUEST_MAGIC; + tag_pack(req.tag, circ->p_chan->global_identifier, + circ->p_circ_id); + req.timed = should_time; + + cpuworker->state = CPUWORKER_STATE_BUSY_ONION; + /* touch the lastwritten timestamp, since that's how we check to + * see how long it's been since we asked the question, and sometimes + * we check before the first call to connection_handle_write(). */ + cpuworker->timestamp_lastwritten = now; + num_cpuworkers_busy++; + + req.task = CPUWORKER_TASK_ONION; + memcpy(&req.create_cell, onionskin, sizeof(create_cell_t)); + + tor_free(onionskin); + + if (should_time) + tor_gettimeofday(&req.started_at); + + connection_write_to_buf((void*)&req, sizeof(req), cpuworker); + memwipe(&req, 0, sizeof(req)); + } + return 0; +} + diff --git a/src/tor/cpuworker.h b/src/tor/cpuworker.h new file mode 100644 index 0000000..317cef4 --- /dev/null +++ b/src/tor/cpuworker.h @@ -0,0 +1,31 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file cpuworker.h + * \brief Header file for cpuworker.c. + **/ + +#ifndef TOR_CPUWORKER_H +#define TOR_CPUWORKER_H + +void cpu_init(void); +void cpuworkers_rotate(void); +int connection_cpu_finished_flushing(connection_t *conn); +int connection_cpu_reached_eof(connection_t *conn); +int connection_cpu_process_inbuf(connection_t *conn); +struct create_cell_t; +int assign_onionskin_to_cpuworker(connection_t *cpuworker, + or_circuit_t *circ, + struct create_cell_t *onionskin); + +uint64_t estimated_usec_for_onionskins(uint32_t n_requests, + uint16_t onionskin_type); +void cpuworker_log_onionskin_overhead(int severity, int onionskin_type, + const char *onionskin_type_name); + +#endif + diff --git a/src/tor/crypto.c b/src/tor/crypto.c new file mode 100644 index 0000000..044e151 --- /dev/null +++ b/src/tor/crypto.c @@ -0,0 +1,3154 @@ +/* Copyright (c) 2001, Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file crypto.c + * \brief Wrapper functions to present a consistent interface to + * public-key and symmetric cryptography operations from OpenSSL. + **/ + +#include "orconfig.h" + +#ifdef _WIN32 +#ifndef _WIN32_WINNT +#define _WIN32_WINNT 0x0501 +#endif +#define WIN32_LEAN_AND_MEAN +#include +#include +/* Windows defines this; so does OpenSSL 0.9.8h and later. We don't actually + * use either definition. */ +#undef OCSP_RESPONSE +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_CTYPE_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif +#ifdef HAVE_FCNTL_H +#include +#endif +#ifdef HAVE_SYS_FCNTL_H +#include +#endif + +#define CRYPTO_PRIVATE +#include "crypto.h" +#include "torlog.h" +#include "aes.h" +#include "tor_util.h" +#include "container.h" +#include "tor_compat.h" +#include "sandbox.h" + +#if OPENSSL_VERSION_NUMBER < OPENSSL_V_SERIES(0,9,8) +#error "We require OpenSSL >= 0.9.8" +#endif + +#ifdef ANDROID +/* Android's OpenSSL seems to have removed all of its Engine support. */ +#define DISABLE_ENGINES +#endif + +/** Longest recognized */ +#define MAX_DNS_LABEL_SIZE 63 + +/** Macro: is k a valid RSA public or private key? */ +#define PUBLIC_KEY_OK(k) ((k) && (k)->key && (k)->key->n) +/** Macro: is k a valid RSA private key? */ +#define PRIVATE_KEY_OK(k) ((k) && (k)->key && (k)->key->p) + +#ifdef TOR_IS_MULTITHREADED +/** A number of preallocated mutexes for use by OpenSSL. */ +static tor_mutex_t **openssl_mutexes_ = NULL; +/** How many mutexes have we allocated for use by OpenSSL? */ +static int n_openssl_mutexes_ = 0; +#endif + +/** A public key, or a public/private key-pair. */ +struct crypto_pk_t +{ + int refs; /**< reference count, so we don't have to copy keys */ + RSA *key; /**< The key itself */ +}; + +/** Key and stream information for a stream cipher. */ +struct crypto_cipher_t +{ + char key[CIPHER_KEY_LEN]; /**< The raw key. */ + char iv[CIPHER_IV_LEN]; /**< The initial IV. */ + aes_cnt_cipher_t *cipher; /**< The key in format usable for counter-mode AES + * encryption */ +}; + +/** A structure to hold the first half (x, g^x) of a Diffie-Hellman handshake + * while we're waiting for the second.*/ +struct crypto_dh_t { + DH *dh; /**< The openssl DH object */ +}; + +static int setup_openssl_threading(void); +static int tor_check_dh_key(int severity, BIGNUM *bn); + +/** Return the number of bytes added by padding method padding. + */ +static INLINE int +crypto_get_rsa_padding_overhead(int padding) +{ + switch (padding) + { + case RSA_PKCS1_OAEP_PADDING: return PKCS1_OAEP_PADDING_OVERHEAD; + default: tor_assert(0); return -1; + } +} + +/** Given a padding method padding, return the correct OpenSSL constant. + */ +static INLINE int +crypto_get_rsa_padding(int padding) +{ + switch (padding) + { + case PK_PKCS1_OAEP_PADDING: return RSA_PKCS1_OAEP_PADDING; + default: tor_assert(0); return -1; + } +} + +/** Boolean: has OpenSSL's crypto been initialized? */ +static int crypto_global_initialized_ = 0; + +/** Log all pending crypto errors at level severity. Use + * doing to describe our current activities. + */ +static void +crypto_log_errors(int severity, const char *doing) +{ + unsigned long err; + const char *msg, *lib, *func; + while ((err = ERR_get_error()) != 0) { + msg = (const char*)ERR_reason_error_string(err); + lib = (const char*)ERR_lib_error_string(err); + func = (const char*)ERR_func_error_string(err); + if (!msg) msg = "(null)"; + if (!lib) lib = "(null)"; + if (!func) func = "(null)"; + if (doing) { + tor_log(severity, LD_CRYPTO, "crypto error while %s: %s (in %s:%s)", + doing, msg, lib, func); + } else { + tor_log(severity, LD_CRYPTO, "crypto error: %s (in %s:%s)", + msg, lib, func); + } + } +} + +#ifndef DISABLE_ENGINES +/** Log any OpenSSL engines we're using at NOTICE. */ +static void +log_engine(const char *fn, ENGINE *e) +{ + if (e) { + const char *name, *id; + name = ENGINE_get_name(e); + id = ENGINE_get_id(e); + log_notice(LD_CRYPTO, "Default OpenSSL engine for %s is %s [%s]", + fn, name?name:"?", id?id:"?"); + } else { + log_info(LD_CRYPTO, "Using default implementation for %s", fn); + } +} +#endif + +#ifndef DISABLE_ENGINES +/** Try to load an engine in a shared library via fully qualified path. + */ +static ENGINE * +try_load_engine(const char *path, const char *engine) +{ + ENGINE *e = ENGINE_by_id("dynamic"); + if (e) { + if (!ENGINE_ctrl_cmd_string(e, "ID", engine, 0) || + !ENGINE_ctrl_cmd_string(e, "DIR_LOAD", "2", 0) || + !ENGINE_ctrl_cmd_string(e, "DIR_ADD", path, 0) || + !ENGINE_ctrl_cmd_string(e, "LOAD", NULL, 0)) { + ENGINE_free(e); + e = NULL; + } + } + return e; +} +#endif + +/* Returns a trimmed and human-readable version of an openssl version string +* raw_version. They are usually in the form of 'OpenSSL 1.0.0b 10 +* May 2012' and this will parse them into a form similar to '1.0.0b' */ +static char * +parse_openssl_version_str(const char *raw_version) +{ + const char *end_of_version = NULL; + /* The output should be something like "OpenSSL 1.0.0b 10 May 2012. Let's + trim that down. */ + if (!strcmpstart(raw_version, "OpenSSL ")) { + raw_version += strlen("OpenSSL "); + end_of_version = strchr(raw_version, ' '); + } + + if (end_of_version) + return tor_strndup(raw_version, + end_of_version-raw_version); + else + return tor_strdup(raw_version); +} + +static char *crypto_openssl_version_str = NULL; +/* Return a human-readable version of the run-time openssl version number. */ +const char * +crypto_openssl_get_version_str(void) +{ + if (crypto_openssl_version_str == NULL) { + const char *raw_version = SSLeay_version(SSLEAY_VERSION); + crypto_openssl_version_str = parse_openssl_version_str(raw_version); + } + return crypto_openssl_version_str; +} + +static char *crypto_openssl_header_version_str = NULL; +/* Return a human-readable version of the compile-time openssl version +* number. */ +const char * +crypto_openssl_get_header_version_str(void) +{ + if (crypto_openssl_header_version_str == NULL) { + crypto_openssl_header_version_str = + parse_openssl_version_str(OPENSSL_VERSION_TEXT); + } + return crypto_openssl_header_version_str; +} + +/** Initialize the crypto library. Return 0 on success, -1 on failure. + */ +int +crypto_global_init(int useAccel, const char *accelName, const char *accelDir) +{ + if (!crypto_global_initialized_) { + ERR_load_crypto_strings(); + OpenSSL_add_all_algorithms(); + crypto_global_initialized_ = 1; + setup_openssl_threading(); + + if (SSLeay() == OPENSSL_VERSION_NUMBER && + !strcmp(SSLeay_version(SSLEAY_VERSION), OPENSSL_VERSION_TEXT)) { + log_info(LD_CRYPTO, "OpenSSL version matches version from headers " + "(%lx: %s).", SSLeay(), SSLeay_version(SSLEAY_VERSION)); + } else { + log_warn(LD_CRYPTO, "OpenSSL version from headers does not match the " + "version we're running with. If you get weird crashes, that " + "might be why. (Compiled with %lx: %s; running with %lx: %s).", + (unsigned long)OPENSSL_VERSION_NUMBER, OPENSSL_VERSION_TEXT, + SSLeay(), SSLeay_version(SSLEAY_VERSION)); + } + + if (SSLeay() < OPENSSL_V_SERIES(1,0,0)) { + log_notice(LD_CRYPTO, + "Your OpenSSL version seems to be %s. We recommend 1.0.0 " + "or later.", + crypto_openssl_get_version_str()); + } + + if (useAccel > 0) { +#ifdef DISABLE_ENGINES + (void)accelName; + (void)accelDir; + log_warn(LD_CRYPTO, "No OpenSSL hardware acceleration support enabled."); +#else + ENGINE *e = NULL; + + log_info(LD_CRYPTO, "Initializing OpenSSL engine support."); + ENGINE_load_builtin_engines(); + ENGINE_register_all_complete(); + + if (accelName) { + if (accelDir) { + log_info(LD_CRYPTO, "Trying to load dynamic OpenSSL engine \"%s\"" + " via path \"%s\".", accelName, accelDir); + e = try_load_engine(accelName, accelDir); + } else { + log_info(LD_CRYPTO, "Initializing dynamic OpenSSL engine \"%s\"" + " acceleration support.", accelName); + e = ENGINE_by_id(accelName); + } + if (!e) { + log_warn(LD_CRYPTO, "Unable to load dynamic OpenSSL engine \"%s\".", + accelName); + } else { + log_info(LD_CRYPTO, "Loaded dynamic OpenSSL engine \"%s\".", + accelName); + } + } + if (e) { + log_info(LD_CRYPTO, "Loaded OpenSSL hardware acceleration engine," + " setting default ciphers."); + ENGINE_set_default(e, ENGINE_METHOD_ALL); + } + /* Log, if available, the intersection of the set of algorithms + used by Tor and the set of algorithms available in the engine */ + log_engine("RSA", ENGINE_get_default_RSA()); + log_engine("DH", ENGINE_get_default_DH()); + log_engine("ECDH", ENGINE_get_default_ECDH()); + log_engine("ECDSA", ENGINE_get_default_ECDSA()); + log_engine("RAND", ENGINE_get_default_RAND()); + log_engine("RAND (which we will not use)", ENGINE_get_default_RAND()); + log_engine("SHA1", ENGINE_get_digest_engine(NID_sha1)); + log_engine("3DES-CBC", ENGINE_get_cipher_engine(NID_des_ede3_cbc)); + log_engine("AES-128-ECB", ENGINE_get_cipher_engine(NID_aes_128_ecb)); + log_engine("AES-128-CBC", ENGINE_get_cipher_engine(NID_aes_128_cbc)); +#ifdef NID_aes_128_ctr + log_engine("AES-128-CTR", ENGINE_get_cipher_engine(NID_aes_128_ctr)); +#endif +#ifdef NID_aes_128_gcm + log_engine("AES-128-GCM", ENGINE_get_cipher_engine(NID_aes_128_gcm)); +#endif + log_engine("AES-256-CBC", ENGINE_get_cipher_engine(NID_aes_256_cbc)); +#ifdef NID_aes_256_gcm + log_engine("AES-256-GCM", ENGINE_get_cipher_engine(NID_aes_256_gcm)); +#endif + +#endif + } else { + log_info(LD_CRYPTO, "NOT using OpenSSL engine support."); + } + + if (RAND_get_rand_method() != RAND_SSLeay()) { + log_notice(LD_CRYPTO, "It appears that one of our engines has provided " + "a replacement the OpenSSL RNG. Resetting it to the default " + "implementation."); + RAND_set_rand_method(RAND_SSLeay()); + } + + evaluate_evp_for_aes(-1); + evaluate_ctr_for_aes(); + + return crypto_seed_rng(1); + } + return 0; +} + +/** Free crypto resources held by this thread. */ +void +crypto_thread_cleanup(void) +{ + ERR_remove_state(0); +} + +/** used by tortls.c: wrap an RSA* in a crypto_pk_t. */ +crypto_pk_t * +crypto_new_pk_from_rsa_(RSA *rsa) +{ + crypto_pk_t *env; + tor_assert(rsa); + env = tor_malloc(sizeof(crypto_pk_t)); + env->refs = 1; + env->key = rsa; + return env; +} + +/** Helper, used by tor-checkkey.c and tor-gencert.c. Return the RSA from a + * crypto_pk_t. */ +RSA * +crypto_pk_get_rsa_(crypto_pk_t *env) +{ + return env->key; +} + +/** used by tortls.c: get an equivalent EVP_PKEY* for a crypto_pk_t. Iff + * private is set, include the private-key portion of the key. */ +EVP_PKEY * +crypto_pk_get_evp_pkey_(crypto_pk_t *env, int private) +{ + RSA *key = NULL; + EVP_PKEY *pkey = NULL; + tor_assert(env->key); + if (private) { + if (!(key = RSAPrivateKey_dup(env->key))) + goto error; + } else { + if (!(key = RSAPublicKey_dup(env->key))) + goto error; + } + if (!(pkey = EVP_PKEY_new())) + goto error; + if (!(EVP_PKEY_assign_RSA(pkey, key))) + goto error; + return pkey; + error: + if (pkey) + EVP_PKEY_free(pkey); + if (key) + RSA_free(key); + return NULL; +} + +/** Used by tortls.c: Get the DH* from a crypto_dh_t. + */ +DH * +crypto_dh_get_dh_(crypto_dh_t *dh) +{ + return dh->dh; +} + +/** Allocate and return storage for a public key. The key itself will not yet + * be set. + */ +crypto_pk_t * +crypto_pk_new(void) +{ + RSA *rsa; + + rsa = RSA_new(); + tor_assert(rsa); + return crypto_new_pk_from_rsa_(rsa); +} + +/** Release a reference to an asymmetric key; when all the references + * are released, free the key. + */ +void +crypto_pk_free(crypto_pk_t *env) +{ + if (!env) + return; + + if (--env->refs > 0) + return; + tor_assert(env->refs == 0); + + if (env->key) + RSA_free(env->key); + + tor_free(env); +} + +/** Allocate and return a new symmetric cipher using the provided key and iv. + * The key is CIPHER_KEY_LEN bytes; the IV is CIPHER_IV_LEN bytes. If you + * provide NULL in place of either one, it is generated at random. + */ +crypto_cipher_t * +crypto_cipher_new_with_iv(const char *key, const char *iv) +{ + crypto_cipher_t *env; + + env = tor_malloc_zero(sizeof(crypto_cipher_t)); + + if (key == NULL) + crypto_rand(env->key, CIPHER_KEY_LEN); + else + memcpy(env->key, key, CIPHER_KEY_LEN); + if (iv == NULL) + crypto_rand(env->iv, CIPHER_IV_LEN); + else + memcpy(env->iv, iv, CIPHER_IV_LEN); + + env->cipher = aes_new_cipher(env->key, env->iv); + + return env; +} + +/** Return a new crypto_cipher_t with the provided key and an IV of all + * zero bytes. */ +crypto_cipher_t * +crypto_cipher_new(const char *key) +{ + char zeroiv[CIPHER_IV_LEN]; + memset(zeroiv, 0, sizeof(zeroiv)); + return crypto_cipher_new_with_iv(key, zeroiv); +} + +/** Free a symmetric cipher. + */ +void +crypto_cipher_free(crypto_cipher_t *env) +{ + if (!env) + return; + + tor_assert(env->cipher); + aes_cipher_free(env->cipher); + memwipe(env, 0, sizeof(crypto_cipher_t)); + tor_free(env); +} + +/* public key crypto */ + +/** Generate a bits-bit new public/private keypair in env. + * Return 0 on success, -1 on failure. + */ +int +crypto_pk_generate_key_with_bits(crypto_pk_t *env, int bits) +{ + tor_assert(env); + + if (env->key) + RSA_free(env->key); + + { + BIGNUM *e = BN_new(); + RSA *r = NULL; + if (!e) + goto done; + if (! BN_set_word(e, 65537)) + goto done; + r = RSA_new(); + if (!r) + goto done; + if (RSA_generate_key_ex(r, bits, e, NULL) == -1) + goto done; + + env->key = r; + r = NULL; + done: + if (e) + BN_clear_free(e); + if (r) + RSA_free(r); + } + + if (!env->key) { + crypto_log_errors(LOG_WARN, "generating RSA key"); + return -1; + } + + return 0; +} + +/** Read a PEM-encoded private key from the len-byte string s + * into env. Return 0 on success, -1 on failure. If len is -1, + * the string is nul-terminated. + */ +/* Used here, and used for testing. */ +int +crypto_pk_read_private_key_from_string(crypto_pk_t *env, + const char *s, ssize_t len) +{ + BIO *b; + + tor_assert(env); + tor_assert(s); + tor_assert(len < INT_MAX && len < SSIZE_T_CEILING); + + /* Create a read-only memory BIO, backed by the string 's' */ + b = BIO_new_mem_buf((char*)s, (int)len); + if (!b) + return -1; + + if (env->key) + RSA_free(env->key); + + env->key = PEM_read_bio_RSAPrivateKey(b,NULL,NULL,NULL); + + BIO_free(b); + + if (!env->key) { + crypto_log_errors(LOG_WARN, "Error parsing private key"); + return -1; + } + return 0; +} + +/** Read a PEM-encoded private key from the file named by + * keyfile into env. Return 0 on success, -1 on failure. + */ +int +crypto_pk_read_private_key_from_filename(crypto_pk_t *env, + const char *keyfile) +{ + char *contents; + int r; + + /* Read the file into a string. */ + contents = read_file_to_str(keyfile, 0, NULL); + if (!contents) { + log_warn(LD_CRYPTO, "Error reading private key from \"%s\"", keyfile); + return -1; + } + + /* Try to parse it. */ + r = crypto_pk_read_private_key_from_string(env, contents, -1); + memwipe(contents, 0, strlen(contents)); + tor_free(contents); + if (r) + return -1; /* read_private_key_from_string already warned, so we don't.*/ + + /* Make sure it's valid. */ + if (crypto_pk_check_key(env) <= 0) + return -1; + + return 0; +} + +/** Helper function to implement crypto_pk_write_*_key_to_string. */ +static int +crypto_pk_write_key_to_string_impl(crypto_pk_t *env, char **dest, + size_t *len, int is_public) +{ + BUF_MEM *buf; + BIO *b; + int r; + + tor_assert(env); + tor_assert(env->key); + tor_assert(dest); + + b = BIO_new(BIO_s_mem()); /* Create a memory BIO */ + if (!b) + return -1; + + /* Now you can treat b as if it were a file. Just use the + * PEM_*_bio_* functions instead of the non-bio variants. + */ + if (is_public) + r = PEM_write_bio_RSAPublicKey(b, env->key); + else + r = PEM_write_bio_RSAPrivateKey(b, env->key, NULL,NULL,0,NULL,NULL); + + if (!r) { + crypto_log_errors(LOG_WARN, "writing RSA key to string"); + BIO_free(b); + return -1; + } + + BIO_get_mem_ptr(b, &buf); + (void)BIO_set_close(b, BIO_NOCLOSE); /* so BIO_free doesn't free buf */ + BIO_free(b); + + *dest = tor_malloc(buf->length+1); + memcpy(*dest, buf->data, buf->length); + (*dest)[buf->length] = 0; /* nul terminate it */ + *len = buf->length; + BUF_MEM_free(buf); + + return 0; +} + +/** PEM-encode the public key portion of env and write it to a + * newly allocated string. On success, set *dest to the new + * string, *len to the string's length, and return 0. On + * failure, return -1. + */ +int +crypto_pk_write_public_key_to_string(crypto_pk_t *env, char **dest, + size_t *len) +{ + return crypto_pk_write_key_to_string_impl(env, dest, len, 1); +} + +/** PEM-encode the private key portion of env and write it to a + * newly allocated string. On success, set *dest to the new + * string, *len to the string's length, and return 0. On + * failure, return -1. + */ +int +crypto_pk_write_private_key_to_string(crypto_pk_t *env, char **dest, + size_t *len) +{ + return crypto_pk_write_key_to_string_impl(env, dest, len, 0); +} + +/** Read a PEM-encoded public key from the first len characters of + * src, and store the result in env. Return 0 on success, -1 on + * failure. + */ +int +crypto_pk_read_public_key_from_string(crypto_pk_t *env, const char *src, + size_t len) +{ + BIO *b; + + tor_assert(env); + tor_assert(src); + tor_assert(lenkey) + RSA_free(env->key); + env->key = PEM_read_bio_RSAPublicKey(b, NULL, NULL, NULL); + BIO_free(b); + if (!env->key) { + crypto_log_errors(LOG_WARN, "reading public key from string"); + return -1; + } + + return 0; +} + +/** Write the private key from env into the file named by fname, + * PEM-encoded. Return 0 on success, -1 on failure. + */ +int +crypto_pk_write_private_key_to_filename(crypto_pk_t *env, + const char *fname) +{ + BIO *bio; + char *cp; + long len; + char *s; + int r; + + tor_assert(PRIVATE_KEY_OK(env)); + + if (!(bio = BIO_new(BIO_s_mem()))) + return -1; + if (PEM_write_bio_RSAPrivateKey(bio, env->key, NULL,NULL,0,NULL,NULL) + == 0) { + crypto_log_errors(LOG_WARN, "writing private key"); + BIO_free(bio); + return -1; + } + len = BIO_get_mem_data(bio, &cp); + tor_assert(len >= 0); + s = tor_malloc(len+1); + memcpy(s, cp, len); + s[len]='\0'; + r = write_str_to_file(fname, s, 0); + BIO_free(bio); + memwipe(s, 0, strlen(s)); + tor_free(s); + return r; +} + +/** Return true iff env has a valid key. + */ +int +crypto_pk_check_key(crypto_pk_t *env) +{ + int r; + tor_assert(env); + + r = RSA_check_key(env->key); + if (r <= 0) + crypto_log_errors(LOG_WARN,"checking RSA key"); + return r; +} + +/** Return true iff key contains the private-key portion of the RSA + * key. */ +int +crypto_pk_key_is_private(const crypto_pk_t *key) +{ + tor_assert(key); + return PRIVATE_KEY_OK(key); +} + +/** Return true iff env contains a public key whose public exponent + * equals 65537. + */ +int +crypto_pk_public_exponent_ok(crypto_pk_t *env) +{ + tor_assert(env); + tor_assert(env->key); + + return BN_is_word(env->key->e, 65537); +} + +/** Compare the public-key components of a and b. Return less than 0 + * if a\b. A NULL key is + * considered to be less than all non-NULL keys, and equal to itself. + * + * Note that this may leak information about the keys through timing. + */ +int +crypto_pk_cmp_keys(crypto_pk_t *a, crypto_pk_t *b) +{ + int result; + char a_is_non_null = (a != NULL) && (a->key != NULL); + char b_is_non_null = (b != NULL) && (b->key != NULL); + char an_argument_is_null = !a_is_non_null | !b_is_non_null; + + result = tor_memcmp(&a_is_non_null, &b_is_non_null, sizeof(a_is_non_null)); + if (an_argument_is_null) + return result; + + tor_assert(PUBLIC_KEY_OK(a)); + tor_assert(PUBLIC_KEY_OK(b)); + result = BN_cmp((a->key)->n, (b->key)->n); + if (result) + return result; + return BN_cmp((a->key)->e, (b->key)->e); +} + +/** Compare the public-key components of a and b. Return non-zero iff + * a==b. A NULL key is considered to be distinct from all non-NULL + * keys, and equal to itself. + * + * Note that this may leak information about the keys through timing. + */ +int +crypto_pk_eq_keys(crypto_pk_t *a, crypto_pk_t *b) +{ + return (crypto_pk_cmp_keys(a, b) == 0); +} + +/** Return the size of the public key modulus in env, in bytes. */ +size_t +crypto_pk_keysize(crypto_pk_t *env) +{ + tor_assert(env); + tor_assert(env->key); + + return (size_t) RSA_size(env->key); +} + +/** Return the size of the public key modulus of env, in bits. */ +int +crypto_pk_num_bits(crypto_pk_t *env) +{ + tor_assert(env); + tor_assert(env->key); + tor_assert(env->key->n); + + return BN_num_bits(env->key->n); +} + +/** Increase the reference count of env, and return it. + */ +crypto_pk_t * +crypto_pk_dup_key(crypto_pk_t *env) +{ + tor_assert(env); + tor_assert(env->key); + + env->refs++; + return env; +} + +/** Make a real honest-to-goodness copy of env, and return it. */ +crypto_pk_t * +crypto_pk_copy_full(crypto_pk_t *env) +{ + RSA *new_key; + int privatekey = 0; + tor_assert(env); + tor_assert(env->key); + + if (PRIVATE_KEY_OK(env)) { + new_key = RSAPrivateKey_dup(env->key); + privatekey = 1; + } else { + new_key = RSAPublicKey_dup(env->key); + } + if (!new_key) { + log_err(LD_CRYPTO, "Unable to duplicate a %s key: openssl failed.", + privatekey?"private":"public"); + crypto_log_errors(LOG_ERR, + privatekey ? "Duplicating a private key" : + "Duplicating a public key"); + tor_fragile_assert(); + return NULL; + } + + return crypto_new_pk_from_rsa_(new_key); +} + +/** Encrypt fromlen bytes from from with the public key + * in env, using the padding method padding. On success, + * write the result to to, and return the number of bytes + * written. On failure, return -1. + * + * tolen is the number of writable bytes in to, and must be + * at least the length of the modulus of env. + */ +int +crypto_pk_public_encrypt(crypto_pk_t *env, char *to, size_t tolen, + const char *from, size_t fromlen, int padding) +{ + int r; + tor_assert(env); + tor_assert(from); + tor_assert(to); + tor_assert(fromlen= crypto_pk_keysize(env)); + + r = RSA_public_encrypt((int)fromlen, + (unsigned char*)from, (unsigned char*)to, + env->key, crypto_get_rsa_padding(padding)); + if (r<0) { + crypto_log_errors(LOG_WARN, "performing RSA encryption"); + return -1; + } + return r; +} + +/** Decrypt fromlen bytes from from with the private key + * in env, using the padding method padding. On success, + * write the result to to, and return the number of bytes + * written. On failure, return -1. + * + * tolen is the number of writable bytes in to, and must be + * at least the length of the modulus of env. + */ +int +crypto_pk_private_decrypt(crypto_pk_t *env, char *to, + size_t tolen, + const char *from, size_t fromlen, + int padding, int warnOnFailure) +{ + int r; + tor_assert(env); + tor_assert(from); + tor_assert(to); + tor_assert(env->key); + tor_assert(fromlen= crypto_pk_keysize(env)); + if (!env->key->p) + /* Not a private key */ + return -1; + + r = RSA_private_decrypt((int)fromlen, + (unsigned char*)from, (unsigned char*)to, + env->key, crypto_get_rsa_padding(padding)); + + if (r<0) { + crypto_log_errors(warnOnFailure?LOG_WARN:LOG_DEBUG, + "performing RSA decryption"); + return -1; + } + return r; +} + +/** Check the signature in from (fromlen bytes long) with the + * public key in env, using PKCS1 padding. On success, write the + * signed data to to, and return the number of bytes written. + * On failure, return -1. + * + * tolen is the number of writable bytes in to, and must be + * at least the length of the modulus of env. + */ +int +crypto_pk_public_checksig(crypto_pk_t *env, char *to, + size_t tolen, + const char *from, size_t fromlen) +{ + int r; + tor_assert(env); + tor_assert(from); + tor_assert(to); + tor_assert(fromlen < INT_MAX); + tor_assert(tolen >= crypto_pk_keysize(env)); + r = RSA_public_decrypt((int)fromlen, + (unsigned char*)from, (unsigned char*)to, + env->key, RSA_PKCS1_PADDING); + + if (r<0) { + crypto_log_errors(LOG_WARN, "checking RSA signature"); + return -1; + } + return r; +} + +/** Check a siglen-byte long signature at sig against + * datalen bytes of data at data, using the public key + * in env. Return 0 if sig is a correct signature for + * SHA1(data). Else return -1. + */ +int +crypto_pk_public_checksig_digest(crypto_pk_t *env, const char *data, + size_t datalen, const char *sig, size_t siglen) +{ + char digest[DIGEST_LEN]; + char *buf; + size_t buflen; + int r; + + tor_assert(env); + tor_assert(data); + tor_assert(sig); + tor_assert(datalen < SIZE_T_CEILING); + tor_assert(siglen < SIZE_T_CEILING); + + if (crypto_digest(digest,data,datalen)<0) { + log_warn(LD_BUG, "couldn't compute digest"); + return -1; + } + buflen = crypto_pk_keysize(env); + buf = tor_malloc(buflen); + r = crypto_pk_public_checksig(env,buf,buflen,sig,siglen); + if (r != DIGEST_LEN) { + log_warn(LD_CRYPTO, "Invalid signature"); + tor_free(buf); + return -1; + } + if (tor_memneq(buf, digest, DIGEST_LEN)) { + log_warn(LD_CRYPTO, "Signature mismatched with digest."); + tor_free(buf); + return -1; + } + tor_free(buf); + + return 0; +} + +/** Sign fromlen bytes of data from from with the private key in + * env, using PKCS1 padding. On success, write the signature to + * to, and return the number of bytes written. On failure, return + * -1. + * + * tolen is the number of writable bytes in to, and must be + * at least the length of the modulus of env. + */ +int +crypto_pk_private_sign(crypto_pk_t *env, char *to, size_t tolen, + const char *from, size_t fromlen) +{ + int r; + tor_assert(env); + tor_assert(from); + tor_assert(to); + tor_assert(fromlen < INT_MAX); + tor_assert(tolen >= crypto_pk_keysize(env)); + if (!env->key->p) + /* Not a private key */ + return -1; + + r = RSA_private_encrypt((int)fromlen, + (unsigned char*)from, (unsigned char*)to, + env->key, RSA_PKCS1_PADDING); + if (r<0) { + crypto_log_errors(LOG_WARN, "generating RSA signature"); + return -1; + } + return r; +} + +/** Compute a SHA1 digest of fromlen bytes of data stored at + * from; sign the data with the private key in env, and + * store it in to. Return the number of bytes written on + * success, and -1 on failure. + * + * tolen is the number of writable bytes in to, and must be + * at least the length of the modulus of env. + */ +int +crypto_pk_private_sign_digest(crypto_pk_t *env, char *to, size_t tolen, + const char *from, size_t fromlen) +{ + int r; + char digest[DIGEST_LEN]; + if (crypto_digest(digest,from,fromlen)<0) + return -1; + r = crypto_pk_private_sign(env,to,tolen,digest,DIGEST_LEN); + memwipe(digest, 0, sizeof(digest)); + return r; +} + +/** Perform a hybrid (public/secret) encryption on fromlen + * bytes of data from from, with padding type 'padding', + * storing the results on to. + * + * Returns the number of bytes written on success, -1 on failure. + * + * The encrypted data consists of: + * - The source data, padded and encrypted with the public key, if the + * padded source data is no longer than the public key, and force + * is false, OR + * - The beginning of the source data prefixed with a 16-byte symmetric key, + * padded and encrypted with the public key; followed by the rest of + * the source data encrypted in AES-CTR mode with the symmetric key. + */ +int +crypto_pk_public_hybrid_encrypt(crypto_pk_t *env, + char *to, size_t tolen, + const char *from, + size_t fromlen, + int padding, int force) +{ + int overhead, outlen, r; + size_t pkeylen, symlen; + crypto_cipher_t *cipher = NULL; + char *buf = NULL; + + tor_assert(env); + tor_assert(from); + tor_assert(to); + tor_assert(fromlen < SIZE_T_CEILING); + + overhead = crypto_get_rsa_padding_overhead(crypto_get_rsa_padding(padding)); + pkeylen = crypto_pk_keysize(env); + + if (!force && fromlen+overhead <= pkeylen) { + /* It all fits in a single encrypt. */ + return crypto_pk_public_encrypt(env,to, + tolen, + from,fromlen,padding); + } + tor_assert(tolen >= fromlen + overhead + CIPHER_KEY_LEN); + tor_assert(tolen >= pkeylen); + + cipher = crypto_cipher_new(NULL); /* generate a new key. */ + + buf = tor_malloc(pkeylen+1); + memcpy(buf, cipher->key, CIPHER_KEY_LEN); + memcpy(buf+CIPHER_KEY_LEN, from, pkeylen-overhead-CIPHER_KEY_LEN); + + /* Length of symmetrically encrypted data. */ + symlen = fromlen-(pkeylen-overhead-CIPHER_KEY_LEN); + + outlen = crypto_pk_public_encrypt(env,to,tolen,buf,pkeylen-overhead,padding); + if (outlen!=(int)pkeylen) { + goto err; + } + r = crypto_cipher_encrypt(cipher, to+outlen, + from+pkeylen-overhead-CIPHER_KEY_LEN, symlen); + + if (r<0) goto err; + memwipe(buf, 0, pkeylen); + tor_free(buf); + crypto_cipher_free(cipher); + tor_assert(outlen+symlen < INT_MAX); + return (int)(outlen + symlen); + err: + + memwipe(buf, 0, pkeylen); + tor_free(buf); + crypto_cipher_free(cipher); + return -1; +} + +/** Invert crypto_pk_public_hybrid_encrypt. */ +int +crypto_pk_private_hybrid_decrypt(crypto_pk_t *env, + char *to, + size_t tolen, + const char *from, + size_t fromlen, + int padding, int warnOnFailure) +{ + int outlen, r; + size_t pkeylen; + crypto_cipher_t *cipher = NULL; + char *buf = NULL; + + tor_assert(fromlen < SIZE_T_CEILING); + pkeylen = crypto_pk_keysize(env); + + if (fromlen <= pkeylen) { + return crypto_pk_private_decrypt(env,to,tolen,from,fromlen,padding, + warnOnFailure); + } + + buf = tor_malloc(pkeylen); + outlen = crypto_pk_private_decrypt(env,buf,pkeylen,from,pkeylen,padding, + warnOnFailure); + if (outlen<0) { + log_fn(warnOnFailure?LOG_WARN:LOG_DEBUG, LD_CRYPTO, + "Error decrypting public-key data"); + goto err; + } + if (outlen < CIPHER_KEY_LEN) { + log_fn(warnOnFailure?LOG_WARN:LOG_INFO, LD_CRYPTO, + "No room for a symmetric key"); + goto err; + } + cipher = crypto_cipher_new(buf); + if (!cipher) { + goto err; + } + memcpy(to,buf+CIPHER_KEY_LEN,outlen-CIPHER_KEY_LEN); + outlen -= CIPHER_KEY_LEN; + tor_assert(tolen - outlen >= fromlen - pkeylen); + r = crypto_cipher_decrypt(cipher, to+outlen, from+pkeylen, fromlen-pkeylen); + if (r<0) + goto err; + memwipe(buf,0,pkeylen); + tor_free(buf); + crypto_cipher_free(cipher); + tor_assert(outlen + fromlen < INT_MAX); + return (int)(outlen + (fromlen-pkeylen)); + err: + memwipe(buf,0,pkeylen); + tor_free(buf); + crypto_cipher_free(cipher); + return -1; +} + +/** ASN.1-encode the public portion of pk into dest. + * Return -1 on error, or the number of characters used on success. + */ +int +crypto_pk_asn1_encode(crypto_pk_t *pk, char *dest, size_t dest_len) +{ + int len; + unsigned char *buf = NULL; + + len = i2d_RSAPublicKey(pk->key, &buf); + if (len < 0 || buf == NULL) + return -1; + + if ((size_t)len > dest_len || dest_len > SIZE_T_CEILING) { + OPENSSL_free(buf); + return -1; + } + /* We don't encode directly into 'dest', because that would be illegal + * type-punning. (C99 is smarter than me, C99 is smarter than me...) + */ + memcpy(dest,buf,len); + OPENSSL_free(buf); + return len; +} + +/** Decode an ASN.1-encoded public key from str; return the result on + * success and NULL on failure. + */ +crypto_pk_t * +crypto_pk_asn1_decode(const char *str, size_t len) +{ + RSA *rsa; + unsigned char *buf; + const unsigned char *cp; + cp = buf = tor_malloc(len); + memcpy(buf,str,len); + rsa = d2i_RSAPublicKey(NULL, &cp, len); + tor_free(buf); + if (!rsa) { + crypto_log_errors(LOG_WARN,"decoding public key"); + return NULL; + } + return crypto_new_pk_from_rsa_(rsa); +} + +/** Given a private or public key pk, put a SHA1 hash of the + * public key into digest_out (must have DIGEST_LEN bytes of space). + * Return 0 on success, -1 on failure. + */ +int +crypto_pk_get_digest(crypto_pk_t *pk, char *digest_out) +{ + unsigned char *buf = NULL; + int len; + + len = i2d_RSAPublicKey(pk->key, &buf); + if (len < 0 || buf == NULL) + return -1; + if (crypto_digest(digest_out, (char*)buf, len) < 0) { + OPENSSL_free(buf); + return -1; + } + OPENSSL_free(buf); + return 0; +} + +/** Compute all digests of the DER encoding of pk, and store them + * in digests_out. Return 0 on success, -1 on failure. */ +int +crypto_pk_get_all_digests(crypto_pk_t *pk, digests_t *digests_out) +{ + unsigned char *buf = NULL; + int len; + + len = i2d_RSAPublicKey(pk->key, &buf); + if (len < 0 || buf == NULL) + return -1; + if (crypto_digest_all(digests_out, (char*)buf, len) < 0) { + OPENSSL_free(buf); + return -1; + } + OPENSSL_free(buf); + return 0; +} + +/** Copy in to the outlen-byte buffer out, adding spaces + * every four spaces. */ +void +crypto_add_spaces_to_fp(char *out, size_t outlen, const char *in) +{ + int n = 0; + char *end = out+outlen; + tor_assert(outlen < SIZE_T_CEILING); + + while (*in && outpk, put a fingerprint of the + * public key into fp_out (must have at least FINGERPRINT_LEN+1 bytes of + * space). Return 0 on success, -1 on failure. + * + * Fingerprints are computed as the SHA1 digest of the ASN.1 encoding + * of the public key, converted to hexadecimal, in upper case, with a + * space after every four digits. + * + * If add_space is false, omit the spaces. + */ +int +crypto_pk_get_fingerprint(crypto_pk_t *pk, char *fp_out, int add_space) +{ + char digest[DIGEST_LEN]; + char hexdigest[HEX_DIGEST_LEN+1]; + if (crypto_pk_get_digest(pk, digest)) { + return -1; + } + base16_encode(hexdigest,sizeof(hexdigest),digest,DIGEST_LEN); + if (add_space) { + crypto_add_spaces_to_fp(fp_out, FINGERPRINT_LEN+1, hexdigest); + } else { + strncpy(fp_out, hexdigest, HEX_DIGEST_LEN+1); + } + return 0; +} + +/* symmetric crypto */ + +/** Return a pointer to the key set for the cipher in env. + */ +const char * +crypto_cipher_get_key(crypto_cipher_t *env) +{ + return env->key; +} + +/** Encrypt fromlen bytes from from using the cipher + * env; on success, store the result to to and return 0. + * On failure, return -1. + */ +int +crypto_cipher_encrypt(crypto_cipher_t *env, char *to, + const char *from, size_t fromlen) +{ + tor_assert(env); + tor_assert(env->cipher); + tor_assert(from); + tor_assert(fromlen); + tor_assert(to); + tor_assert(fromlen < SIZE_T_CEILING); + + aes_crypt(env->cipher, from, fromlen, to); + return 0; +} + +/** Decrypt fromlen bytes from from using the cipher + * env; on success, store the result to to and return 0. + * On failure, return -1. + */ +int +crypto_cipher_decrypt(crypto_cipher_t *env, char *to, + const char *from, size_t fromlen) +{ + tor_assert(env); + tor_assert(from); + tor_assert(to); + tor_assert(fromlen < SIZE_T_CEILING); + + aes_crypt(env->cipher, from, fromlen, to); + return 0; +} + +/** Encrypt len bytes on from using the cipher in env; + * on success, return 0. On failure, return -1. + */ +int +crypto_cipher_crypt_inplace(crypto_cipher_t *env, char *buf, size_t len) +{ + tor_assert(len < SIZE_T_CEILING); + aes_crypt_inplace(env->cipher, buf, len); + return 0; +} + +/** Encrypt fromlen bytes (at least 1) from from with the key in + * key to the buffer in to of length + * tolen. tolen must be at least fromlen plus + * CIPHER_IV_LEN bytes for the initialization vector. On success, return the + * number of bytes written, on failure, return -1. + */ +int +crypto_cipher_encrypt_with_iv(const char *key, + char *to, size_t tolen, + const char *from, size_t fromlen) +{ + crypto_cipher_t *cipher; + tor_assert(from); + tor_assert(to); + tor_assert(fromlen < INT_MAX); + + if (fromlen < 1) + return -1; + if (tolen < fromlen + CIPHER_IV_LEN) + return -1; + + cipher = crypto_cipher_new_with_iv(key, NULL); + + memcpy(to, cipher->iv, CIPHER_IV_LEN); + crypto_cipher_encrypt(cipher, to+CIPHER_IV_LEN, from, fromlen); + crypto_cipher_free(cipher); + return (int)(fromlen + CIPHER_IV_LEN); +} + +/** Decrypt fromlen bytes (at least 1+CIPHER_IV_LEN) from from + * with the key in key to the buffer in to of length + * tolen. tolen must be at least fromlen minus + * CIPHER_IV_LEN bytes for the initialization vector. On success, return the + * number of bytes written, on failure, return -1. + */ +int +crypto_cipher_decrypt_with_iv(const char *key, + char *to, size_t tolen, + const char *from, size_t fromlen) +{ + crypto_cipher_t *cipher; + tor_assert(key); + tor_assert(from); + tor_assert(to); + tor_assert(fromlen < INT_MAX); + + if (fromlen <= CIPHER_IV_LEN) + return -1; + if (tolen < fromlen - CIPHER_IV_LEN) + return -1; + + cipher = crypto_cipher_new_with_iv(key, from); + + crypto_cipher_encrypt(cipher, to, from+CIPHER_IV_LEN, fromlen-CIPHER_IV_LEN); + crypto_cipher_free(cipher); + return (int)(fromlen - CIPHER_IV_LEN); +} + +/* SHA-1 */ + +/** Compute the SHA1 digest of the len bytes on data stored in + * m. Write the DIGEST_LEN byte result into digest. + * Return 0 on success, -1 on failure. + */ +int +crypto_digest(char *digest, const char *m, size_t len) +{ + tor_assert(m); + tor_assert(digest); + return (SHA1((const unsigned char*)m,len,(unsigned char*)digest) == NULL); +} + +/** Compute a 256-bit digest of len bytes in data stored in m, + * using the algorithm algorithm. Write the DIGEST_LEN256-byte result + * into digest. Return 0 on success, -1 on failure. */ +int +crypto_digest256(char *digest, const char *m, size_t len, + digest_algorithm_t algorithm) +{ + tor_assert(m); + tor_assert(digest); + tor_assert(algorithm == DIGEST_SHA256); + return (SHA256((const unsigned char*)m,len,(unsigned char*)digest) == NULL); +} + +/** Set the digests_t in ds_out to contain every digest on the + * len bytes in m that we know how to compute. Return 0 on + * success, -1 on failure. */ +int +crypto_digest_all(digests_t *ds_out, const char *m, size_t len) +{ + int i; + tor_assert(ds_out); + memset(ds_out, 0, sizeof(*ds_out)); + if (crypto_digest(ds_out->d[DIGEST_SHA1], m, len) < 0) + return -1; + for (i = DIGEST_SHA256; i < N_DIGEST_ALGORITHMS; ++i) { + if (crypto_digest256(ds_out->d[i], m, len, i) < 0) + return -1; + } + return 0; +} + +/** Return the name of an algorithm, as used in directory documents. */ +const char * +crypto_digest_algorithm_get_name(digest_algorithm_t alg) +{ + switch (alg) { + case DIGEST_SHA1: + return "sha1"; + case DIGEST_SHA256: + return "sha256"; + default: + tor_fragile_assert(); + return "??unknown_digest??"; + } +} + +/** Given the name of a digest algorithm, return its integer value, or -1 if + * the name is not recognized. */ +int +crypto_digest_algorithm_parse_name(const char *name) +{ + if (!strcmp(name, "sha1")) + return DIGEST_SHA1; + else if (!strcmp(name, "sha256")) + return DIGEST_SHA256; + else + return -1; +} + +/** Intermediate information about the digest of a stream of data. */ +struct crypto_digest_t { + union { + SHA_CTX sha1; /**< state for SHA1 */ + SHA256_CTX sha2; /**< state for SHA256 */ + } d; /**< State for the digest we're using. Only one member of the + * union is usable, depending on the value of algorithm. */ + ENUM_BF(digest_algorithm_t) algorithm : 8; /**< Which algorithm is in use? */ +}; + +/** Allocate and return a new digest object to compute SHA1 digests. + */ +crypto_digest_t * +crypto_digest_new(void) +{ + crypto_digest_t *r; + r = tor_malloc(sizeof(crypto_digest_t)); + SHA1_Init(&r->d.sha1); + r->algorithm = DIGEST_SHA1; + return r; +} + +/** Allocate and return a new digest object to compute 256-bit digests + * using algorithm. */ +crypto_digest_t * +crypto_digest256_new(digest_algorithm_t algorithm) +{ + crypto_digest_t *r; + tor_assert(algorithm == DIGEST_SHA256); + r = tor_malloc(sizeof(crypto_digest_t)); + SHA256_Init(&r->d.sha2); + r->algorithm = algorithm; + return r; +} + +/** Deallocate a digest object. + */ +void +crypto_digest_free(crypto_digest_t *digest) +{ + if (!digest) + return; + memwipe(digest, 0, sizeof(crypto_digest_t)); + tor_free(digest); +} + +/** Add len bytes from data to the digest object. + */ +void +crypto_digest_add_bytes(crypto_digest_t *digest, const char *data, + size_t len) +{ + tor_assert(digest); + tor_assert(data); + /* Using the SHA*_*() calls directly means we don't support doing + * SHA in hardware. But so far the delay of getting the question + * to the hardware, and hearing the answer, is likely higher than + * just doing it ourselves. Hashes are fast. + */ + switch (digest->algorithm) { + case DIGEST_SHA1: + SHA1_Update(&digest->d.sha1, (void*)data, len); + break; + case DIGEST_SHA256: + SHA256_Update(&digest->d.sha2, (void*)data, len); + break; + default: + tor_fragile_assert(); + break; + } +} + +/** Compute the hash of the data that has been passed to the digest + * object; write the first out_len bytes of the result to out. + * out_len must be \<= DIGEST256_LEN. + */ +void +crypto_digest_get_digest(crypto_digest_t *digest, + char *out, size_t out_len) +{ + unsigned char r[DIGEST256_LEN]; + crypto_digest_t tmpenv; + tor_assert(digest); + tor_assert(out); + /* memcpy into a temporary ctx, since SHA*_Final clears the context */ + memcpy(&tmpenv, digest, sizeof(crypto_digest_t)); + switch (digest->algorithm) { + case DIGEST_SHA1: + tor_assert(out_len <= DIGEST_LEN); + SHA1_Final(r, &tmpenv.d.sha1); + break; + case DIGEST_SHA256: + tor_assert(out_len <= DIGEST256_LEN); + SHA256_Final(r, &tmpenv.d.sha2); + break; + default: + log_warn(LD_BUG, "Called with unknown algorithm %d", digest->algorithm); + /* If fragile_assert is not enabled, then we should at least not + * leak anything. */ + memset(r, 0xff, sizeof(r)); + tor_fragile_assert(); + break; + } + memcpy(out, r, out_len); + memwipe(r, 0, sizeof(r)); +} + +/** Allocate and return a new digest object with the same state as + * digest + */ +crypto_digest_t * +crypto_digest_dup(const crypto_digest_t *digest) +{ + crypto_digest_t *r; + tor_assert(digest); + r = tor_malloc(sizeof(crypto_digest_t)); + memcpy(r,digest,sizeof(crypto_digest_t)); + return r; +} + +/** Replace the state of the digest object into with the state + * of the digest object from. + */ +void +crypto_digest_assign(crypto_digest_t *into, + const crypto_digest_t *from) +{ + tor_assert(into); + tor_assert(from); + memcpy(into,from,sizeof(crypto_digest_t)); +} + +/** Given a list of strings in lst, set the len_out-byte digest + * at digest_out to the hash of the concatenation of those strings, + * plus the optional string append, computed with the algorithm + * alg. + * out_len must be \<= DIGEST256_LEN. */ +void +crypto_digest_smartlist(char *digest_out, size_t len_out, + const smartlist_t *lst, const char *append, + digest_algorithm_t alg) +{ + crypto_digest_t *d; + if (alg == DIGEST_SHA1) + d = crypto_digest_new(); + else + d = crypto_digest256_new(alg); + SMARTLIST_FOREACH(lst, const char *, cp, + crypto_digest_add_bytes(d, cp, strlen(cp))); + if (append) + crypto_digest_add_bytes(d, append, strlen(append)); + crypto_digest_get_digest(d, digest_out, len_out); + crypto_digest_free(d); +} + +/** Compute the HMAC-SHA-256 of the msg_len bytes in msg, using + * the key of length key_len. Store the DIGEST256_LEN-byte + * result in hmac_out. + */ +void +crypto_hmac_sha256(char *hmac_out, + const char *key, size_t key_len, + const char *msg, size_t msg_len) +{ + /* If we've got OpenSSL >=0.9.8 we can use its hmac implementation. */ + tor_assert(key_len < INT_MAX); + tor_assert(msg_len < INT_MAX); + HMAC(EVP_sha256(), key, (int)key_len, (unsigned char*)msg, (int)msg_len, + (unsigned char*)hmac_out, NULL); +} + +/* DH */ + +/** Our DH 'g' parameter */ +#define DH_GENERATOR 2 + +/** Shared P parameter for our circuit-crypto DH key exchanges. */ +static BIGNUM *dh_param_p = NULL; +/** Shared P parameter for our TLS DH key exchanges. */ +static BIGNUM *dh_param_p_tls = NULL; +/** Shared G parameter for our DH key exchanges. */ +static BIGNUM *dh_param_g = NULL; + +/** Generate and return a reasonable and safe DH parameter p. */ +static BIGNUM * +crypto_generate_dynamic_dh_modulus(void) +{ + BIGNUM *dynamic_dh_modulus; + DH *dh_parameters; + int r, dh_codes; + char *s; + + dynamic_dh_modulus = BN_new(); + tor_assert(dynamic_dh_modulus); + + dh_parameters = DH_generate_parameters(DH_BYTES*8, DH_GENERATOR, NULL, NULL); + tor_assert(dh_parameters); + + r = DH_check(dh_parameters, &dh_codes); + tor_assert(r && !dh_codes); + + BN_copy(dynamic_dh_modulus, dh_parameters->p); + tor_assert(dynamic_dh_modulus); + + DH_free(dh_parameters); + + { /* log the dynamic DH modulus: */ + s = BN_bn2hex(dynamic_dh_modulus); + tor_assert(s); + log_info(LD_OR, "Dynamic DH modulus generated: [%s]", s); + OPENSSL_free(s); + } + + return dynamic_dh_modulus; +} + +/** Store our dynamic DH modulus (and its group parameters) to + fname for future use. */ +static int +crypto_store_dynamic_dh_modulus(const char *fname) +{ + int len, new_len; + DH *dh = NULL; + unsigned char *dh_string_repr = NULL; + char *base64_encoded_dh = NULL; + char *file_string = NULL; + int retval = -1; + static const char file_header[] = "# This file contains stored Diffie-" + "Hellman parameters for future use.\n# You *do not* need to edit this " + "file.\n\n"; + + tor_assert(fname); + + if (!dh_param_p_tls) { + log_info(LD_CRYPTO, "Tried to store a DH modulus that does not exist."); + goto done; + } + + if (!(dh = DH_new())) + goto done; + if (!(dh->p = BN_dup(dh_param_p_tls))) + goto done; + if (!(dh->g = BN_new())) + goto done; + if (!BN_set_word(dh->g, DH_GENERATOR)) + goto done; + + len = i2d_DHparams(dh, &dh_string_repr); + if ((len < 0) || (dh_string_repr == NULL)) { + log_warn(LD_CRYPTO, "Error occured while DER encoding DH modulus (2)."); + goto done; + } + + base64_encoded_dh = tor_malloc_zero(len * 2); /* should be enough */ + new_len = base64_encode(base64_encoded_dh, len * 2, + (char *)dh_string_repr, len); + if (new_len < 0) { + log_warn(LD_CRYPTO, "Error occured while base64-encoding DH modulus."); + goto done; + } + + /* concatenate file header and the dh parameters blob */ + new_len = tor_asprintf(&file_string, "%s%s", file_header, base64_encoded_dh); + + /* write to file */ + if (write_bytes_to_new_file(fname, file_string, new_len, 0) < 0) { + log_info(LD_CRYPTO, "'%s' was already occupied.", fname); + goto done; + } + + retval = 0; + + done: + if (dh) + DH_free(dh); + if (dh_string_repr) + OPENSSL_free(dh_string_repr); + tor_free(base64_encoded_dh); + tor_free(file_string); + + return retval; +} + +/** Return the dynamic DH modulus stored in fname. If there is no + dynamic DH modulus stored in fname, return NULL. */ +static BIGNUM * +crypto_get_stored_dynamic_dh_modulus(const char *fname) +{ + int retval; + char *contents = NULL; + const char *contents_tmp = NULL; + int dh_codes; + DH *stored_dh = NULL; + BIGNUM *dynamic_dh_modulus = NULL; + int length = 0; + unsigned char *base64_decoded_dh = NULL; + const unsigned char *cp = NULL; + + tor_assert(fname); + + contents = read_file_to_str(fname, RFTS_IGNORE_MISSING, NULL); + if (!contents) { + log_info(LD_CRYPTO, "Could not open file '%s'", fname); + goto done; /*usually means that ENOENT. don't try to move file to broken.*/ + } + + /* skip the file header */ + contents_tmp = eat_whitespace(contents); + if (!*contents_tmp) { + log_warn(LD_CRYPTO, "Stored dynamic DH modulus file " + "seems corrupted (eat_whitespace)."); + goto err; + } + + /* 'fname' contains the DH parameters stored in base64-ed DER + * format. We are only interested in the DH modulus. + * NOTE: We allocate more storage here than we need. Since we're already + * doing that, we can also add 1 byte extra to appease Coverity's + * scanner. */ + + cp = base64_decoded_dh = tor_malloc_zero(strlen(contents_tmp) + 1); + length = base64_decode((char *)base64_decoded_dh, strlen(contents_tmp), + contents_tmp, strlen(contents_tmp)); + if (length < 0) { + log_warn(LD_CRYPTO, "Stored dynamic DH modulus seems corrupted (base64)."); + goto err; + } + + stored_dh = d2i_DHparams(NULL, &cp, length); + if ((!stored_dh) || (cp - base64_decoded_dh != length)) { + log_warn(LD_CRYPTO, "Stored dynamic DH modulus seems corrupted (d2i)."); + goto err; + } + + { /* check the cryptographic qualities of the stored dynamic DH modulus: */ + retval = DH_check(stored_dh, &dh_codes); + if (!retval || dh_codes) { + log_warn(LD_CRYPTO, "Stored dynamic DH modulus is not a safe prime."); + goto err; + } + + retval = DH_size(stored_dh); + if (retval < DH_BYTES) { + log_warn(LD_CRYPTO, "Stored dynamic DH modulus is smaller " + "than '%d' bits.", DH_BYTES*8); + goto err; + } + + if (!BN_is_word(stored_dh->g, 2)) { + log_warn(LD_CRYPTO, "Stored dynamic DH parameters do not use '2' " + "as the group generator."); + goto err; + } + } + + { /* log the dynamic DH modulus: */ + char *s = BN_bn2hex(stored_dh->p); + tor_assert(s); + log_info(LD_OR, "Found stored dynamic DH modulus: [%s]", s); + OPENSSL_free(s); + } + + goto done; + + err: + + { + /* move broken prime to $filename.broken */ + char *fname_new=NULL; + tor_asprintf(&fname_new, "%s.broken", fname); + + log_warn(LD_CRYPTO, "Moving broken dynamic DH prime to '%s'.", fname_new); + + if (replace_file(fname, fname_new)) + log_notice(LD_CRYPTO, "Error while moving '%s' to '%s'.", + fname, fname_new); + + tor_free(fname_new); + } + + if (stored_dh) { + DH_free(stored_dh); + stored_dh = NULL; + } + + done: + tor_free(contents); + tor_free(base64_decoded_dh); + + if (stored_dh) { + dynamic_dh_modulus = BN_dup(stored_dh->p); + DH_free(stored_dh); + } + + return dynamic_dh_modulus; +} + +/** Set the global TLS Diffie-Hellman modulus. + * If dynamic_dh_modulus_fname is set, try to read a dynamic DH modulus + * off it and use it as the DH modulus. If that's not possible, + * generate a new dynamic DH modulus. + * If dynamic_dh_modulus_fname is NULL, use the Apache mod_ssl DH + * modulus. */ +void +crypto_set_tls_dh_prime(const char *dynamic_dh_modulus_fname) +{ + BIGNUM *tls_prime = NULL; + int store_dh_prime_afterwards = 0; + int r; + + /* If the space is occupied, free the previous TLS DH prime */ + if (dh_param_p_tls) { + BN_clear_free(dh_param_p_tls); + dh_param_p_tls = NULL; + } + + if (dynamic_dh_modulus_fname) { /* use dynamic DH modulus: */ + log_info(LD_OR, "Using stored dynamic DH modulus."); + tls_prime = crypto_get_stored_dynamic_dh_modulus(dynamic_dh_modulus_fname); + + if (!tls_prime) { + log_notice(LD_OR, "Generating fresh dynamic DH modulus. " + "This might take a while..."); + tls_prime = crypto_generate_dynamic_dh_modulus(); + + store_dh_prime_afterwards++; + } + } else { /* use the static DH prime modulus used by Apache in mod_ssl: */ + tls_prime = BN_new(); + tor_assert(tls_prime); + + /* This is the 1024-bit safe prime that Apache uses for its DH stuff; see + * modules/ssl/ssl_engine_dh.c; Apache also uses a generator of 2 with this + * prime. + */ + r =BN_hex2bn(&tls_prime, + "D67DE440CBBBDC1936D693D34AFD0AD50C84D239A45F520BB88174CB98" + "BCE951849F912E639C72FB13B4B4D7177E16D55AC179BA420B2A29FE324A" + "467A635E81FF5901377BEDDCFD33168A461AAD3B72DAE8860078045B07A7" + "DBCA7874087D1510EA9FCC9DDD330507DD62DB88AEAA747DE0F4D6E2BD68" + "B0E7393E0F24218EB3"); + tor_assert(r); + } + + tor_assert(tls_prime); + + dh_param_p_tls = tls_prime; + + if (store_dh_prime_afterwards) + /* save the new dynamic DH modulus to disk. */ + if (crypto_store_dynamic_dh_modulus(dynamic_dh_modulus_fname)) { + log_notice(LD_CRYPTO, "Failed while storing dynamic DH modulus. " + "Make sure your data directory is sane."); + } +} + +/** Initialize dh_param_p and dh_param_g if they are not already + * set. */ +static void +init_dh_param(void) +{ + BIGNUM *circuit_dh_prime, *generator; + int r; + if (dh_param_p && dh_param_g) + return; + + circuit_dh_prime = BN_new(); + generator = BN_new(); + tor_assert(circuit_dh_prime && generator); + + /* Set our generator for all DH parameters */ + r = BN_set_word(generator, DH_GENERATOR); + tor_assert(r); + + /* This is from rfc2409, section 6.2. It's a safe prime, and + supposedly it equals: + 2^1024 - 2^960 - 1 + 2^64 * { [2^894 pi] + 129093 }. + */ + r = BN_hex2bn(&circuit_dh_prime, + "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E08" + "8A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B" + "302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9" + "A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE6" + "49286651ECE65381FFFFFFFFFFFFFFFF"); + tor_assert(r); + + /* Set the new values as the global DH parameters. */ + dh_param_p = circuit_dh_prime; + dh_param_g = generator; + + /* Ensure that we have TLS DH parameters set up, too, even if we're + going to change them soon. */ + if (!dh_param_p_tls) { + crypto_set_tls_dh_prime(NULL); + } +} + +/** Number of bits to use when choosing the x or y value in a Diffie-Hellman + * handshake. Since we exponentiate by this value, choosing a smaller one + * lets our handhake go faster. + */ +#define DH_PRIVATE_KEY_BITS 320 + +/** Allocate and return a new DH object for a key exchange. + */ +crypto_dh_t * +crypto_dh_new(int dh_type) +{ + crypto_dh_t *res = tor_malloc_zero(sizeof(crypto_dh_t)); + + tor_assert(dh_type == DH_TYPE_CIRCUIT || dh_type == DH_TYPE_TLS || + dh_type == DH_TYPE_REND); + + if (!dh_param_p) + init_dh_param(); + + if (!(res->dh = DH_new())) + goto err; + + if (dh_type == DH_TYPE_TLS) { + if (!(res->dh->p = BN_dup(dh_param_p_tls))) + goto err; + } else { + if (!(res->dh->p = BN_dup(dh_param_p))) + goto err; + } + + if (!(res->dh->g = BN_dup(dh_param_g))) + goto err; + + res->dh->length = DH_PRIVATE_KEY_BITS; + + return res; + err: + crypto_log_errors(LOG_WARN, "creating DH object"); + if (res->dh) DH_free(res->dh); /* frees p and g too */ + tor_free(res); + return NULL; +} + +/** Return a copy of dh, sharing its internal state. */ +crypto_dh_t * +crypto_dh_dup(const crypto_dh_t *dh) +{ + crypto_dh_t *dh_new = tor_malloc_zero(sizeof(crypto_dh_t)); + dh_new->dh = dh->dh; + DH_up_ref(dh->dh); + return dh_new; +} + +/** Return the length of the DH key in dh, in bytes. + */ +int +crypto_dh_get_bytes(crypto_dh_t *dh) +{ + tor_assert(dh); + return DH_size(dh->dh); +} + +/** Generate \ for our part of the key exchange. Return 0 on + * success, -1 on failure. + */ +int +crypto_dh_generate_public(crypto_dh_t *dh) +{ + again: + if (!DH_generate_key(dh->dh)) { + crypto_log_errors(LOG_WARN, "generating DH key"); + return -1; + } + if (tor_check_dh_key(LOG_WARN, dh->dh->pub_key)<0) { + log_warn(LD_CRYPTO, "Weird! Our own DH key was invalid. I guess once-in-" + "the-universe chances really do happen. Trying again."); + /* Free and clear the keys, so OpenSSL will actually try again. */ + BN_clear_free(dh->dh->pub_key); + BN_clear_free(dh->dh->priv_key); + dh->dh->pub_key = dh->dh->priv_key = NULL; + goto again; + } + return 0; +} + +/** Generate g^x as necessary, and write the g^x for the key exchange + * as a pubkey_len-byte value into pubkey. Return 0 on + * success, -1 on failure. pubkey_len must be \>= DH_BYTES. + */ +int +crypto_dh_get_public(crypto_dh_t *dh, char *pubkey, size_t pubkey_len) +{ + int bytes; + tor_assert(dh); + if (!dh->dh->pub_key) { + if (crypto_dh_generate_public(dh)<0) + return -1; + } + + tor_assert(dh->dh->pub_key); + bytes = BN_num_bytes(dh->dh->pub_key); + tor_assert(bytes >= 0); + if (pubkey_len < (size_t)bytes) { + log_warn(LD_CRYPTO, + "Weird! pubkey_len (%d) was smaller than DH_BYTES (%d)", + (int) pubkey_len, bytes); + return -1; + } + + memset(pubkey, 0, pubkey_len); + BN_bn2bin(dh->dh->pub_key, (unsigned char*)(pubkey+(pubkey_len-bytes))); + + return 0; +} + +/** Check for bad Diffie-Hellman public keys (g^x). Return 0 if the key is + * okay (in the subgroup [2,p-2]), or -1 if it's bad. + * See http://www.cl.cam.ac.uk/ftp/users/rja14/psandqs.ps.gz for some tips. + */ +static int +tor_check_dh_key(int severity, BIGNUM *bn) +{ + BIGNUM *x; + char *s; + tor_assert(bn); + x = BN_new(); + tor_assert(x); + if (!dh_param_p) + init_dh_param(); + BN_set_word(x, 1); + if (BN_cmp(bn,x)<=0) { + log_fn(severity, LD_CRYPTO, "DH key must be at least 2."); + goto err; + } + BN_copy(x,dh_param_p); + BN_sub_word(x, 1); + if (BN_cmp(bn,x)>=0) { + log_fn(severity, LD_CRYPTO, "DH key must be at most p-2."); + goto err; + } + BN_clear_free(x); + return 0; + err: + BN_clear_free(x); + s = BN_bn2hex(bn); + log_fn(severity, LD_CRYPTO, "Rejecting insecure DH key [%s]", s); + OPENSSL_free(s); + return -1; +} + +#undef MIN +#define MIN(a,b) ((a)<(b)?(a):(b)) +/** Given a DH key exchange object, and our peer's value of g^y (as a + * pubkey_len-byte value in pubkey) generate + * secret_bytes_out bytes of shared key material and write them + * to secret_out. Return the number of bytes generated on success, + * or -1 on failure. + * + * (We generate key material by computing + * SHA1( g^xy || "\x00" ) || SHA1( g^xy || "\x01" ) || ... + * where || is concatenation.) + */ +ssize_t +crypto_dh_compute_secret(int severity, crypto_dh_t *dh, + const char *pubkey, size_t pubkey_len, + char *secret_out, size_t secret_bytes_out) +{ + char *secret_tmp = NULL; + BIGNUM *pubkey_bn = NULL; + size_t secret_len=0, secret_tmp_len=0; + int result=0; + tor_assert(dh); + tor_assert(secret_bytes_out/DIGEST_LEN <= 255); + tor_assert(pubkey_len < INT_MAX); + + if (!(pubkey_bn = BN_bin2bn((const unsigned char*)pubkey, + (int)pubkey_len, NULL))) + goto error; + if (tor_check_dh_key(severity, pubkey_bn)<0) { + /* Check for invalid public keys. */ + log_fn(severity, LD_CRYPTO,"Rejected invalid g^x"); + goto error; + } + secret_tmp_len = crypto_dh_get_bytes(dh); + secret_tmp = tor_malloc(secret_tmp_len); + result = DH_compute_key((unsigned char*)secret_tmp, pubkey_bn, dh->dh); + if (result < 0) { + log_warn(LD_CRYPTO,"DH_compute_key() failed."); + goto error; + } + secret_len = result; + if (crypto_expand_key_material_TAP((uint8_t*)secret_tmp, secret_len, + (uint8_t*)secret_out, secret_bytes_out)<0) + goto error; + secret_len = secret_bytes_out; + + goto done; + error: + result = -1; + done: + crypto_log_errors(LOG_WARN, "completing DH handshake"); + if (pubkey_bn) + BN_clear_free(pubkey_bn); + if (secret_tmp) { + memwipe(secret_tmp, 0, secret_tmp_len); + tor_free(secret_tmp); + } + if (result < 0) + return result; + else + return secret_len; +} + +/** Given key_in_len bytes of negotiated randomness in key_in + * ("K"), expand it into key_out_len bytes of negotiated key material in + * key_out by taking the first key_out_len bytes of + * H(K | [00]) | H(K | [01]) | .... + * + * This is the key expansion algorithm used in the "TAP" circuit extension + * mechanism; it shouldn't be used for new protocols. + * + * Return 0 on success, -1 on failure. + */ +int +crypto_expand_key_material_TAP(const uint8_t *key_in, size_t key_in_len, + uint8_t *key_out, size_t key_out_len) +{ + int i; + uint8_t *cp, *tmp = tor_malloc(key_in_len+1); + uint8_t digest[DIGEST_LEN]; + + /* If we try to get more than this amount of key data, we'll repeat blocks.*/ + tor_assert(key_out_len <= DIGEST_LEN*256); + + memcpy(tmp, key_in, key_in_len); + for (cp = key_out, i=0; cp < key_out+key_out_len; + ++i, cp += DIGEST_LEN) { + tmp[key_in_len] = i; + if (crypto_digest((char*)digest, (const char *)tmp, key_in_len+1)) + goto err; + memcpy(cp, digest, MIN(DIGEST_LEN, key_out_len-(cp-key_out))); + } + memwipe(tmp, 0, key_in_len+1); + tor_free(tmp); + memwipe(digest, 0, sizeof(digest)); + return 0; + + err: + memwipe(tmp, 0, key_in_len+1); + tor_free(tmp); + memwipe(digest, 0, sizeof(digest)); + return -1; +} + +/** Expand some secret key material according to RFC5869, using SHA256 as the + * underlying hash. The key_in_len bytes at key_in are the + * secret key material; the salt_in_len bytes at salt_in and the + * info_in_len bytes in info_in_len are the algorithm's "salt" + * and "info" parameters respectively. On success, write key_out_len + * bytes to key_out and return 0. On failure, return -1. + */ +int +crypto_expand_key_material_rfc5869_sha256( + const uint8_t *key_in, size_t key_in_len, + const uint8_t *salt_in, size_t salt_in_len, + const uint8_t *info_in, size_t info_in_len, + uint8_t *key_out, size_t key_out_len) +{ + uint8_t prk[DIGEST256_LEN]; + uint8_t tmp[DIGEST256_LEN + 128 + 1]; + uint8_t mac[DIGEST256_LEN]; + int i; + uint8_t *outp; + size_t tmp_len; + + crypto_hmac_sha256((char*)prk, + (const char*)salt_in, salt_in_len, + (const char*)key_in, key_in_len); + + /* If we try to get more than this amount of key data, we'll repeat blocks.*/ + tor_assert(key_out_len <= DIGEST256_LEN * 256); + tor_assert(info_in_len <= 128); + memset(tmp, 0, sizeof(tmp)); + outp = key_out; + i = 1; + + while (key_out_len) { + size_t n; + if (i > 1) { + memcpy(tmp, mac, DIGEST256_LEN); + memcpy(tmp+DIGEST256_LEN, info_in, info_in_len); + tmp[DIGEST256_LEN+info_in_len] = i; + tmp_len = DIGEST256_LEN + info_in_len + 1; + } else { + memcpy(tmp, info_in, info_in_len); + tmp[info_in_len] = i; + tmp_len = info_in_len + 1; + } + crypto_hmac_sha256((char*)mac, + (const char*)prk, DIGEST256_LEN, + (const char*)tmp, tmp_len); + n = key_out_len < DIGEST256_LEN ? key_out_len : DIGEST256_LEN; + memcpy(outp, mac, n); + key_out_len -= n; + outp += n; + ++i; + } + + memwipe(tmp, 0, sizeof(tmp)); + memwipe(mac, 0, sizeof(mac)); + return 0; +} + +/** Free a DH key exchange object. + */ +void +crypto_dh_free(crypto_dh_t *dh) +{ + if (!dh) + return; + tor_assert(dh->dh); + DH_free(dh->dh); + tor_free(dh); +} + +/* random numbers */ + +/** How many bytes of entropy we add at once. + * + * This is how much entropy OpenSSL likes to add right now, so maybe it will + * work for us too. */ +#define ADD_ENTROPY 32 + +/** True iff it's safe to use RAND_poll after setup. + * + * Versions of OpenSSL prior to 0.9.7k and 0.9.8c had a bug where RAND_poll + * would allocate an fd_set on the stack, open a new file, and try to FD_SET + * that fd without checking whether it fit in the fd_set. Thus, if the + * system has not just been started up, it is unsafe to call */ +#define RAND_POLL_IS_SAFE \ + (OPENSSL_VERSION_NUMBER >= OPENSSL_V(0,9,8,'c')) + +/** Set the seed of the weak RNG to a random value. */ +void +crypto_seed_weak_rng(tor_weak_rng_t *rng) +{ + unsigned seed; + crypto_rand((void*)&seed, sizeof(seed)); + tor_init_weak_random(rng, seed); +} + +/** Try to get out_len bytes of the strongest entropy we can generate, + * storing it into out. + */ +int +crypto_strongest_rand(uint8_t *out, size_t out_len) +{ +#ifdef _WIN32 + static int provider_set = 0; + static HCRYPTPROV provider; +#else + static const char *filenames[] = { + "/dev/srandom", "/dev/urandom", "/dev/random", NULL + }; + int fd, i; + size_t n; +#endif + +#ifdef _WIN32 + if (!provider_set) { + if (!CryptAcquireContext(&provider, NULL, NULL, PROV_RSA_FULL, + CRYPT_VERIFYCONTEXT)) { + if ((unsigned long)GetLastError() != (unsigned long)NTE_BAD_KEYSET) { + log_warn(LD_CRYPTO, "Can't get CryptoAPI provider [1]"); + return -1; + } + } + provider_set = 1; + } + if (!CryptGenRandom(provider, out_len, out)) { + log_warn(LD_CRYPTO, "Can't get entropy from CryptoAPI."); + return -1; + } + + return 0; +#else + for (i = 0; filenames[i]; ++i) { + fd = open(sandbox_intern_string(filenames[i]), O_RDONLY, 0); + if (fd<0) continue; + log_info(LD_CRYPTO, "Reading entropy from \"%s\"", filenames[i]); + n = read_all(fd, (char*)out, out_len, 0); + close(fd); + if (n != out_len) { + log_warn(LD_CRYPTO, + "Error reading from entropy source (read only %lu bytes).", + (unsigned long)n); + return -1; + } + + return 0; + } + + log_warn(LD_CRYPTO, "Cannot get strong entropy: no entropy source found."); + return -1; +#endif +} + +/** Seed OpenSSL's random number generator with bytes from the operating + * system. startup should be true iff we have just started Tor and + * have not yet allocated a bunch of fds. Return 0 on success, -1 on failure. + */ +int +crypto_seed_rng(int startup) +{ + int rand_poll_ok = 0, load_entropy_ok = 0; + uint8_t buf[ADD_ENTROPY]; + + /* OpenSSL has a RAND_poll function that knows about more kinds of + * entropy than we do. We'll try calling that, *and* calling our own entropy + * functions. If one succeeds, we'll accept the RNG as seeded. */ + if (startup || RAND_POLL_IS_SAFE) { + rand_poll_ok = RAND_poll(); + if (rand_poll_ok == 0) + log_warn(LD_CRYPTO, "RAND_poll() failed."); + } + + load_entropy_ok = !crypto_strongest_rand(buf, sizeof(buf)); + if (load_entropy_ok) { + RAND_seed(buf, sizeof(buf)); + } + + memwipe(buf, 0, sizeof(buf)); + + if (rand_poll_ok || load_entropy_ok) + return 0; + else + return -1; +} + +/** Write n bytes of strong random data to to. Return 0 on + * success, -1 on failure. + */ +MOCK_IMPL(int, +crypto_rand, (char *to, size_t n)) +{ + int r; + tor_assert(n < INT_MAX); + tor_assert(to); + r = RAND_bytes((unsigned char*)to, (int)n); + if (r == 0) + crypto_log_errors(LOG_WARN, "generating random data"); + return (r == 1) ? 0 : -1; +} + +/** Return a pseudorandom integer, chosen uniformly from the values + * between 0 and max-1 inclusive. max must be between 1 and + * INT_MAX+1, inclusive. */ +int +crypto_rand_int(unsigned int max) +{ + unsigned int val; + unsigned int cutoff; + tor_assert(max <= ((unsigned int)INT_MAX)+1); + tor_assert(max > 0); /* don't div by 0 */ + + /* We ignore any values that are >= 'cutoff,' to avoid biasing the + * distribution with clipping at the upper end of unsigned int's + * range. + */ + cutoff = UINT_MAX - (UINT_MAX%max); + while (1) { + crypto_rand((char*)&val, sizeof(val)); + if (val < cutoff) + return val % max; + } +} + +/** Return a pseudorandom 64-bit integer, chosen uniformly from the values + * between 0 and max-1. */ +uint64_t +crypto_rand_uint64(uint64_t max) +{ + uint64_t val; + uint64_t cutoff; + tor_assert(max < UINT64_MAX); + tor_assert(max > 0); /* don't div by 0 */ + + /* We ignore any values that are >= 'cutoff,' to avoid biasing the + * distribution with clipping at the upper end of unsigned int's + * range. + */ + cutoff = UINT64_MAX - (UINT64_MAX%max); + while (1) { + crypto_rand((char*)&val, sizeof(val)); + if (val < cutoff) + return val % max; + } +} + +/** Return a pseudorandom double d, chosen uniformly from the range + * 0.0 <= d < 1.0. + */ +double +crypto_rand_double(void) +{ + /* We just use an unsigned int here; we don't really care about getting + * more than 32 bits of resolution */ + unsigned int uint; + crypto_rand((char*)&uint, sizeof(uint)); +#if SIZEOF_INT == 4 +#define UINT_MAX_AS_DOUBLE 4294967296.0 +#elif SIZEOF_INT == 8 +#define UINT_MAX_AS_DOUBLE 1.8446744073709552e+19 +#else +#error SIZEOF_INT is neither 4 nor 8 +#endif + return ((double)uint) / UINT_MAX_AS_DOUBLE; +} + +/** Generate and return a new random hostname starting with prefix, + * ending with suffix, and containing no fewer than + * min_rand_len and no more than max_rand_len random base32 + * characters between. + * + * Clip max_rand_len to MAX_DNS_LABEL_SIZE. + **/ +char * +crypto_random_hostname(int min_rand_len, int max_rand_len, const char *prefix, + const char *suffix) +{ + char *result, *rand_bytes; + int randlen, rand_bytes_len; + size_t resultlen, prefixlen; + + if (max_rand_len > MAX_DNS_LABEL_SIZE) + max_rand_len = MAX_DNS_LABEL_SIZE; + if (min_rand_len > max_rand_len) + min_rand_len = max_rand_len; + + randlen = min_rand_len + crypto_rand_int(max_rand_len - min_rand_len + 1); + + prefixlen = strlen(prefix); + resultlen = prefixlen + strlen(suffix) + randlen + 16; + + rand_bytes_len = ((randlen*5)+7)/8; + if (rand_bytes_len % 5) + rand_bytes_len += 5 - (rand_bytes_len%5); + rand_bytes = tor_malloc(rand_bytes_len); + crypto_rand(rand_bytes, rand_bytes_len); + + result = tor_malloc(resultlen); + memcpy(result, prefix, prefixlen); + base32_encode(result+prefixlen, resultlen-prefixlen, + rand_bytes, rand_bytes_len); + tor_free(rand_bytes); + strlcpy(result+prefixlen+randlen, suffix, resultlen-(prefixlen+randlen)); + + return result; +} + +/** Return a randomly chosen element of sl; or NULL if sl + * is empty. */ +void * +smartlist_choose(const smartlist_t *sl) +{ + int len = smartlist_len(sl); + if (len) + return smartlist_get(sl,crypto_rand_int(len)); + return NULL; /* no elements to choose from */ +} + +/** Scramble the elements of sl into a random order. */ +void +smartlist_shuffle(smartlist_t *sl) +{ + int i; + /* From the end of the list to the front, choose at random from the + positions we haven't looked at yet, and swap that position into the + current position. Remember to give "no swap" the same probability as + any other swap. */ + for (i = smartlist_len(sl)-1; i > 0; --i) { + int j = crypto_rand_int(i+1); + smartlist_swap(sl, i, j); + } +} + +/** Base64 encode srclen bytes of data from src. Write + * the result into dest, if it will fit within destlen + * bytes. Return the number of bytes written on success; -1 if + * destlen is too short, or other failure. + */ +int +base64_encode(char *dest, size_t destlen, const char *src, size_t srclen) +{ + /* FFFF we might want to rewrite this along the lines of base64_decode, if + * it ever shows up in the profile. */ + EVP_ENCODE_CTX ctx; + int len, ret; + tor_assert(srclen < INT_MAX); + + /* 48 bytes of input -> 64 bytes of output plus newline. + Plus one more byte, in case I'm wrong. + */ + if (destlen < ((srclen/48)+1)*66) + return -1; + if (destlen > SIZE_T_CEILING) + return -1; + + EVP_EncodeInit(&ctx); + EVP_EncodeUpdate(&ctx, (unsigned char*)dest, &len, + (unsigned char*)src, (int)srclen); + EVP_EncodeFinal(&ctx, (unsigned char*)(dest+len), &ret); + ret += len; + return ret; +} + +/** @{ */ +/** Special values used for the base64_decode_table */ +#define X 255 +#define SP 64 +#define PAD 65 +/** @} */ +/** Internal table mapping byte values to what they represent in base64. + * Numbers 0..63 are 6-bit integers. SPs are spaces, and should be + * skipped. Xs are invalid and must not appear in base64. PAD indicates + * end-of-string. */ +static const uint8_t base64_decode_table[256] = { + X, X, X, X, X, X, X, X, X, SP, SP, SP, X, SP, X, X, /* */ + X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, + SP, X, X, X, X, X, X, X, X, X, X, 62, X, X, X, 63, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, X, X, X, PAD, X, X, + X, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, X, X, X, X, X, + X, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, X, X, X, X, X, + X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, + X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, + X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, + X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, + X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, + X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, + X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, + X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, +}; + +/** Base64 decode srclen bytes of data from src. Write + * the result into dest, if it will fit within destlen + * bytes. Return the number of bytes written on success; -1 if + * destlen is too short, or other failure. + * + * NOTE 1: destlen is checked conservatively, as though srclen contained no + * spaces or padding. + * + * NOTE 2: This implementation does not check for the correct number of + * padding "=" characters at the end of the string, and does not check + * for internal padding characters. + */ +int +base64_decode(char *dest, size_t destlen, const char *src, size_t srclen) +{ +#ifdef USE_OPENSSL_BASE64 + EVP_ENCODE_CTX ctx; + int len, ret; + /* 64 bytes of input -> *up to* 48 bytes of output. + Plus one more byte, in case I'm wrong. + */ + if (destlen < ((srclen/64)+1)*49) + return -1; + if (destlen > SIZE_T_CEILING) + return -1; + + EVP_DecodeInit(&ctx); + EVP_DecodeUpdate(&ctx, (unsigned char*)dest, &len, + (unsigned char*)src, srclen); + EVP_DecodeFinal(&ctx, (unsigned char*)dest, &ret); + ret += len; + return ret; +#else + const char *eos = src+srclen; + uint32_t n=0; + int n_idx=0; + char *dest_orig = dest; + + /* Max number of bits == srclen*6. + * Number of bytes required to hold all bits == (srclen*6)/8. + * Yes, we want to round down: anything that hangs over the end of a + * byte is padding. */ + if (destlen < (srclen*3)/4) + return -1; + if (destlen > SIZE_T_CEILING) + return -1; + + /* Iterate over all the bytes in src. Each one will add 0 or 6 bits to the + * value we're decoding. Accumulate bits in n, and whenever we have + * 24 bits, batch them into 3 bytes and flush those bytes to dest. + */ + for ( ; src < eos; ++src) { + unsigned char c = (unsigned char) *src; + uint8_t v = base64_decode_table[c]; + switch (v) { + case X: + /* This character isn't allowed in base64. */ + return -1; + case SP: + /* This character is whitespace, and has no effect. */ + continue; + case PAD: + /* We've hit an = character: the data is over. */ + goto end_of_loop; + default: + /* We have an actual 6-bit value. Append it to the bits in n. */ + n = (n<<6) | v; + if ((++n_idx) == 4) { + /* We've accumulated 24 bits in n. Flush them. */ + *dest++ = (n>>16); + *dest++ = (n>>8) & 0xff; + *dest++ = (n) & 0xff; + n_idx = 0; + n = 0; + } + } + } + end_of_loop: + /* If we have leftover bits, we need to cope. */ + switch (n_idx) { + case 0: + default: + /* No leftover bits. We win. */ + break; + case 1: + /* 6 leftover bits. That's invalid; we can't form a byte out of that. */ + return -1; + case 2: + /* 12 leftover bits: The last 4 are padding and the first 8 are data. */ + *dest++ = n >> 4; + break; + case 3: + /* 18 leftover bits: The last 2 are padding and the first 16 are data. */ + *dest++ = n >> 10; + *dest++ = n >> 2; + } + + tor_assert((dest-dest_orig) <= (ssize_t)destlen); + tor_assert((dest-dest_orig) <= INT_MAX); + + return (int)(dest-dest_orig); +#endif +} +#undef X +#undef SP +#undef PAD + +/** Base64 encode DIGEST_LINE bytes from digest, remove the trailing = + * and newline characters, and store the nul-terminated result in the first + * BASE64_DIGEST_LEN+1 bytes of d64. */ +int +digest_to_base64(char *d64, const char *digest) +{ + char buf[256]; + base64_encode(buf, sizeof(buf), digest, DIGEST_LEN); + buf[BASE64_DIGEST_LEN] = '\0'; + memcpy(d64, buf, BASE64_DIGEST_LEN+1); + return 0; +} + +/** Given a base64 encoded, nul-terminated digest in d64 (without + * trailing newline or = characters), decode it and store the result in the + * first DIGEST_LEN bytes at digest. */ +int +digest_from_base64(char *digest, const char *d64) +{ +#ifdef USE_OPENSSL_BASE64 + char buf_in[BASE64_DIGEST_LEN+3]; + char buf[256]; + if (strlen(d64) != BASE64_DIGEST_LEN) + return -1; + memcpy(buf_in, d64, BASE64_DIGEST_LEN); + memcpy(buf_in+BASE64_DIGEST_LEN, "=\n\0", 3); + if (base64_decode(buf, sizeof(buf), buf_in, strlen(buf_in)) != DIGEST_LEN) + return -1; + memcpy(digest, buf, DIGEST_LEN); + return 0; +#else + if (base64_decode(digest, DIGEST_LEN, d64, strlen(d64)) == DIGEST_LEN) + return 0; + else + return -1; +#endif +} + +/** Base64 encode DIGEST256_LINE bytes from digest, remove the + * trailing = and newline characters, and store the nul-terminated result in + * the first BASE64_DIGEST256_LEN+1 bytes of d64. */ +int +digest256_to_base64(char *d64, const char *digest) +{ + char buf[256]; + base64_encode(buf, sizeof(buf), digest, DIGEST256_LEN); + buf[BASE64_DIGEST256_LEN] = '\0'; + memcpy(d64, buf, BASE64_DIGEST256_LEN+1); + return 0; +} + +/** Given a base64 encoded, nul-terminated digest in d64 (without + * trailing newline or = characters), decode it and store the result in the + * first DIGEST256_LEN bytes at digest. */ +int +digest256_from_base64(char *digest, const char *d64) +{ +#ifdef USE_OPENSSL_BASE64 + char buf_in[BASE64_DIGEST256_LEN+3]; + char buf[256]; + if (strlen(d64) != BASE64_DIGEST256_LEN) + return -1; + memcpy(buf_in, d64, BASE64_DIGEST256_LEN); + memcpy(buf_in+BASE64_DIGEST256_LEN, "=\n\0", 3); + if (base64_decode(buf, sizeof(buf), buf_in, strlen(buf_in)) != DIGEST256_LEN) + return -1; + memcpy(digest, buf, DIGEST256_LEN); + return 0; +#else + if (base64_decode(digest, DIGEST256_LEN, d64, strlen(d64)) == DIGEST256_LEN) + return 0; + else + return -1; +#endif +} + +/** Implements base32 encoding as in RFC 4648. Limitation: Requires + * that srclen*8 is a multiple of 5. + */ +void +base32_encode(char *dest, size_t destlen, const char *src, size_t srclen) +{ + unsigned int i, v, u; + size_t nbits = srclen * 8, bit; + + tor_assert(srclen < SIZE_T_CEILING/8); + tor_assert((nbits%5) == 0); /* We need an even multiple of 5 bits. */ + tor_assert((nbits/5)+1 <= destlen); /* We need enough space. */ + tor_assert(destlen < SIZE_T_CEILING); + + for (i=0,bit=0; bit < nbits; ++i, bit+=5) { + /* set v to the 16-bit value starting at src[bits/8], 0-padded. */ + v = ((uint8_t)src[bit/8]) << 8; + if (bit+5> (11-(bit%8))) & 0x1F; + dest[i] = BASE32_CHARS[u]; + } + dest[i] = '\0'; +} + +/** Implements base32 decoding as in RFC 4648. Limitation: Requires + * that srclen*5 is a multiple of 8. Returns 0 if successful, -1 otherwise. + */ +int +base32_decode(char *dest, size_t destlen, const char *src, size_t srclen) +{ + /* XXXX we might want to rewrite this along the lines of base64_decode, if + * it ever shows up in the profile. */ + unsigned int i; + size_t nbits, j, bit; + char *tmp; + nbits = srclen * 5; + + tor_assert(srclen < SIZE_T_CEILING / 5); + tor_assert((nbits%8) == 0); /* We need an even multiple of 8 bits. */ + tor_assert((nbits/8) <= destlen); /* We need enough space. */ + tor_assert(destlen < SIZE_T_CEILING); + + /* Convert base32 encoded chars to the 5-bit values that they represent. */ + tmp = tor_malloc_zero(srclen); + for (j = 0; j < srclen; ++j) { + if (src[j] > 0x60 && src[j] < 0x7B) tmp[j] = src[j] - 0x61; + else if (src[j] > 0x31 && src[j] < 0x38) tmp[j] = src[j] - 0x18; + else if (src[j] > 0x40 && src[j] < 0x5B) tmp[j] = src[j] - 0x41; + else { + log_warn(LD_BUG, "illegal character in base32 encoded string"); + tor_free(tmp); + return -1; + } + } + + /* Assemble result byte-wise by applying five possible cases. */ + for (i = 0, bit = 0; bit < nbits; ++i, bit += 8) { + switch (bit % 40) { + case 0: + dest[i] = (((uint8_t)tmp[(bit/5)]) << 3) + + (((uint8_t)tmp[(bit/5)+1]) >> 2); + break; + case 8: + dest[i] = (((uint8_t)tmp[(bit/5)]) << 6) + + (((uint8_t)tmp[(bit/5)+1]) << 1) + + (((uint8_t)tmp[(bit/5)+2]) >> 4); + break; + case 16: + dest[i] = (((uint8_t)tmp[(bit/5)]) << 4) + + (((uint8_t)tmp[(bit/5)+1]) >> 1); + break; + case 24: + dest[i] = (((uint8_t)tmp[(bit/5)]) << 7) + + (((uint8_t)tmp[(bit/5)+1]) << 2) + + (((uint8_t)tmp[(bit/5)+2]) >> 3); + break; + case 32: + dest[i] = (((uint8_t)tmp[(bit/5)]) << 5) + + ((uint8_t)tmp[(bit/5)+1]); + break; + } + } + + memwipe(tmp, 0, srclen); + tor_free(tmp); + tmp = NULL; + return 0; +} + +/** Implement RFC2440-style iterated-salted S2K conversion: convert the + * secret_len-byte secret into a key_out_len byte + * key_out. As in RFC2440, the first 8 bytes of s2k_specifier + * are a salt; the 9th byte describes how much iteration to do. + * Does not support key_out_len > DIGEST_LEN. + */ +void +secret_to_key(char *key_out, size_t key_out_len, const char *secret, + size_t secret_len, const char *s2k_specifier) +{ + crypto_digest_t *d; + uint8_t c; + size_t count, tmplen; + char *tmp; + tor_assert(key_out_len < SIZE_T_CEILING); + +#define EXPBIAS 6 + c = s2k_specifier[8]; + count = ((uint32_t)16 + (c & 15)) << ((c >> 4) + EXPBIAS); +#undef EXPBIAS + + tor_assert(key_out_len <= DIGEST_LEN); + + d = crypto_digest_new(); + tmplen = 8+secret_len; + tmp = tor_malloc(tmplen); + memcpy(tmp,s2k_specifier,8); + memcpy(tmp+8,secret,secret_len); + secret_len += 8; + while (count) { + if (count >= secret_len) { + crypto_digest_add_bytes(d, tmp, secret_len); + count -= secret_len; + } else { + crypto_digest_add_bytes(d, tmp, count); + count = 0; + } + } + crypto_digest_get_digest(d, key_out, key_out_len); + memwipe(tmp, 0, tmplen); + tor_free(tmp); + crypto_digest_free(d); +} + +/** + * Destroy the sz bytes of data stored at mem, setting them to + * the value byte. + * + * This function is preferable to memset, since many compilers will happily + * optimize out memset() when they can convince themselves that the data being + * cleared will never be read. + * + * Right now, our convention is to use this function when we are wiping data + * that's about to become inaccessible, such as stack buffers that are about + * to go out of scope or structures that are about to get freed. (In + * practice, it appears that the compilers we're currently using will optimize + * out the memset()s for stack-allocated buffers, but not those for + * about-to-be-freed structures. That could change, though, so we're being + * wary.) If there are live reads for the data, then you can just use + * memset(). + */ +void +memwipe(void *mem, uint8_t byte, size_t sz) +{ + /* Because whole-program-optimization exists, we may not be able to just + * have this function call "memset". A smart compiler could inline it, then + * eliminate dead memsets, and declare itself to be clever. */ + + /* This is a slow and ugly function from OpenSSL that fills 'mem' with junk + * based on the pointer value, then uses that junk to update a global + * variable. It's an elaborate ruse to trick the compiler into not + * optimizing out the "wipe this memory" code. Read it if you like zany + * programming tricks! In later versions of Tor, we should look for better + * not-optimized-out memory wiping stuff. */ + OPENSSL_cleanse(mem, sz); + /* Just in case some caller of memwipe() is relying on getting a buffer + * filled with a particular value, fill the buffer. + * + * If this function gets inlined, this memset might get eliminated, but + * that's okay: We only care about this particular memset in the case where + * the caller should have been using memset(), and the memset() wouldn't get + * eliminated. In other words, this is here so that we won't break anything + * if somebody accidentally calls memwipe() instead of memset(). + **/ + memset(mem, byte, sz); +} + +#ifdef TOR_IS_MULTITHREADED + +#ifndef OPENSSL_THREADS +#error OpenSSL has been built without thread support. Tor requires an \ + OpenSSL library with thread support enabled. +#endif + +/** Helper: OpenSSL uses this callback to manipulate mutexes. */ +static void +openssl_locking_cb_(int mode, int n, const char *file, int line) +{ + (void)file; + (void)line; + if (!openssl_mutexes_) + /* This is not a really good fix for the + * "release-freed-lock-from-separate-thread-on-shutdown" problem, but + * it can't hurt. */ + return; + if (mode & CRYPTO_LOCK) + tor_mutex_acquire(openssl_mutexes_[n]); + else + tor_mutex_release(openssl_mutexes_[n]); +} + +/** OpenSSL helper type: wraps a Tor mutex so that OpenSSL can use it + * as a lock. */ +struct CRYPTO_dynlock_value { + tor_mutex_t *lock; +}; + +/** OpenSSL callback function to allocate a lock: see CRYPTO_set_dynlock_* + * documentation in OpenSSL's docs for more info. */ +static struct CRYPTO_dynlock_value * +openssl_dynlock_create_cb_(const char *file, int line) +{ + struct CRYPTO_dynlock_value *v; + (void)file; + (void)line; + v = tor_malloc(sizeof(struct CRYPTO_dynlock_value)); + v->lock = tor_mutex_new(); + return v; +} + +/** OpenSSL callback function to acquire or release a lock: see + * CRYPTO_set_dynlock_* documentation in OpenSSL's docs for more info. */ +static void +openssl_dynlock_lock_cb_(int mode, struct CRYPTO_dynlock_value *v, + const char *file, int line) +{ + (void)file; + (void)line; + if (mode & CRYPTO_LOCK) + tor_mutex_acquire(v->lock); + else + tor_mutex_release(v->lock); +} + +/** OpenSSL callback function to free a lock: see CRYPTO_set_dynlock_* + * documentation in OpenSSL's docs for more info. */ +static void +openssl_dynlock_destroy_cb_(struct CRYPTO_dynlock_value *v, + const char *file, int line) +{ + (void)file; + (void)line; + tor_mutex_free(v->lock); + tor_free(v); +} + +/** @{ */ +/** Helper: Construct mutexes, and set callbacks to help OpenSSL handle being + * multithreaded. */ +static int +setup_openssl_threading(void) +{ + int i; + int n = CRYPTO_num_locks(); + n_openssl_mutexes_ = n; + openssl_mutexes_ = tor_malloc(n*sizeof(tor_mutex_t *)); + for (i=0; i < n; ++i) + openssl_mutexes_[i] = tor_mutex_new(); + CRYPTO_set_locking_callback(openssl_locking_cb_); + CRYPTO_set_id_callback(tor_get_thread_id); + CRYPTO_set_dynlock_create_callback(openssl_dynlock_create_cb_); + CRYPTO_set_dynlock_lock_callback(openssl_dynlock_lock_cb_); + CRYPTO_set_dynlock_destroy_callback(openssl_dynlock_destroy_cb_); + return 0; +} +#else +static int +setup_openssl_threading(void) +{ + return 0; +} +#endif + +/** Uninitialize the crypto library. Return 0 on success, -1 on failure. + */ +int +crypto_global_cleanup(void) +{ + EVP_cleanup(); + ERR_remove_state(0); + ERR_free_strings(); + + if (dh_param_p) + BN_clear_free(dh_param_p); + if (dh_param_p_tls) + BN_clear_free(dh_param_p_tls); + if (dh_param_g) + BN_clear_free(dh_param_g); + +#ifndef DISABLE_ENGINES + ENGINE_cleanup(); +#endif + + CONF_modules_unload(1); + CRYPTO_cleanup_all_ex_data(); +#ifdef TOR_IS_MULTITHREADED + if (n_openssl_mutexes_) { + int n = n_openssl_mutexes_; + tor_mutex_t **ms = openssl_mutexes_; + int i; + openssl_mutexes_ = NULL; + n_openssl_mutexes_ = 0; + for (i=0;i +#include "torint.h" +#include "testsupport.h" + +/* + Macro to create an arbitrary OpenSSL version number as used by + OPENSSL_VERSION_NUMBER or SSLeay(), since the actual numbers are a bit hard + to read. + + Don't use this directly, instead use one of the other OPENSSL_V macros + below. + + The format is: 4 bits major, 8 bits minor, 8 bits fix, 8 bits patch, 4 bit + status. + */ +#define OPENSSL_VER(a,b,c,d,e) \ + (((a)<<28) | \ + ((b)<<20) | \ + ((c)<<12) | \ + ((d)<< 4) | \ + (e)) +/** An openssl release number. For example, OPENSSL_V(0,9,8,'j') is the + * version for the released version of 0.9.8j */ +#define OPENSSL_V(a,b,c,d) \ + OPENSSL_VER((a),(b),(c),(d)-'a'+1,0xf) +/** An openssl release number for the first release in the series. For + * example, OPENSSL_V_NOPATCH(1,0,0) is the first released version of OpenSSL + * 1.0.0. */ +#define OPENSSL_V_NOPATCH(a,b,c) \ + OPENSSL_VER((a),(b),(c),0,0xf) +/** The first version that would occur for any alpha or beta in an openssl + * series. For example, OPENSSL_V_SERIES(0,9,8) is greater than any released + * 0.9.7, and less than any released 0.9.8. */ +#define OPENSSL_V_SERIES(a,b,c) \ + OPENSSL_VER((a),(b),(c),0,0) + +/** Length of the output of our message digest. */ +#define DIGEST_LEN 20 +/** Length of the output of our second (improved) message digests. (For now + * this is just sha256, but it could be any other 256-bit digest.) */ +#define DIGEST256_LEN 32 +/** Length of our symmetric cipher's keys. */ +#define CIPHER_KEY_LEN 16 +/** Length of our symmetric cipher's IV. */ +#define CIPHER_IV_LEN 16 +/** Length of our public keys. */ +#define PK_BYTES (1024/8) +/** Length of our DH keys. */ +#define DH_BYTES (1024/8) + +/** Length of a sha1 message digest when encoded in base64 with trailing = + * signs removed. */ +#define BASE64_DIGEST_LEN 27 +/** Length of a sha256 message digest when encoded in base64 with trailing = + * signs removed. */ +#define BASE64_DIGEST256_LEN 43 + +/** Constant used to indicate OAEP padding for public-key encryption */ +#define PK_PKCS1_OAEP_PADDING 60002 + +/** Number of bytes added for PKCS1-OAEP padding. */ +#define PKCS1_OAEP_PADDING_OVERHEAD 42 + +/** Length of encoded public key fingerprints, including space; but not + * including terminating NUL. */ +#define FINGERPRINT_LEN 49 +/** Length of hex encoding of SHA1 digest, not including final NUL. */ +#define HEX_DIGEST_LEN 40 +/** Length of hex encoding of SHA256 digest, not including final NUL. */ +#define HEX_DIGEST256_LEN 64 + +typedef enum { + DIGEST_SHA1 = 0, + DIGEST_SHA256 = 1, +} digest_algorithm_t; +#define N_DIGEST_ALGORITHMS (DIGEST_SHA256+1) + +/** A set of all the digests we know how to compute, taken on a single + * string. Any digests that are shorter than 256 bits are right-padded + * with 0 bits. + * + * Note that this representation wastes 12 bytes for the SHA1 case, so + * don't use it for anything where we need to allocate a whole bunch at + * once. + **/ +typedef struct { + char d[N_DIGEST_ALGORITHMS][DIGEST256_LEN]; +} digests_t; + +typedef struct crypto_pk_t crypto_pk_t; +typedef struct crypto_cipher_t crypto_cipher_t; +typedef struct crypto_digest_t crypto_digest_t; +typedef struct crypto_dh_t crypto_dh_t; + +/* global state */ +const char * crypto_openssl_get_version_str(void); +const char * crypto_openssl_get_header_version_str(void); +int crypto_global_init(int hardwareAccel, + const char *accelName, + const char *accelPath); +void crypto_thread_cleanup(void); +int crypto_global_cleanup(void); + +/* environment setup */ +crypto_pk_t *crypto_pk_new(void); +void crypto_pk_free(crypto_pk_t *env); + +void crypto_set_tls_dh_prime(const char *dynamic_dh_modulus_fname); + +crypto_cipher_t *crypto_cipher_new(const char *key); +crypto_cipher_t *crypto_cipher_new_with_iv(const char *key, const char *iv); +void crypto_cipher_free(crypto_cipher_t *env); + +/* public key crypto */ +int crypto_pk_generate_key_with_bits(crypto_pk_t *env, int bits); +#define crypto_pk_generate_key(env) \ + crypto_pk_generate_key_with_bits((env), (PK_BYTES*8)) + +int crypto_pk_read_private_key_from_filename(crypto_pk_t *env, + const char *keyfile); +int crypto_pk_write_public_key_to_string(crypto_pk_t *env, + char **dest, size_t *len); +int crypto_pk_write_private_key_to_string(crypto_pk_t *env, + char **dest, size_t *len); +int crypto_pk_read_public_key_from_string(crypto_pk_t *env, + const char *src, size_t len); +int crypto_pk_read_private_key_from_string(crypto_pk_t *env, + const char *s, ssize_t len); +int crypto_pk_write_private_key_to_filename(crypto_pk_t *env, + const char *fname); + +int crypto_pk_check_key(crypto_pk_t *env); +int crypto_pk_cmp_keys(crypto_pk_t *a, crypto_pk_t *b); +int crypto_pk_eq_keys(crypto_pk_t *a, crypto_pk_t *b); +size_t crypto_pk_keysize(crypto_pk_t *env); +int crypto_pk_num_bits(crypto_pk_t *env); +crypto_pk_t *crypto_pk_dup_key(crypto_pk_t *orig); +crypto_pk_t *crypto_pk_copy_full(crypto_pk_t *orig); +int crypto_pk_key_is_private(const crypto_pk_t *key); +int crypto_pk_public_exponent_ok(crypto_pk_t *env); + +int crypto_pk_public_encrypt(crypto_pk_t *env, char *to, size_t tolen, + const char *from, size_t fromlen, int padding); +int crypto_pk_private_decrypt(crypto_pk_t *env, char *to, size_t tolen, + const char *from, size_t fromlen, + int padding, int warnOnFailure); +int crypto_pk_public_checksig(crypto_pk_t *env, char *to, size_t tolen, + const char *from, size_t fromlen); +int crypto_pk_public_checksig_digest(crypto_pk_t *env, const char *data, + size_t datalen, const char *sig, size_t siglen); +int crypto_pk_private_sign(crypto_pk_t *env, char *to, size_t tolen, + const char *from, size_t fromlen); +int crypto_pk_private_sign_digest(crypto_pk_t *env, char *to, size_t tolen, + const char *from, size_t fromlen); +int crypto_pk_public_hybrid_encrypt(crypto_pk_t *env, char *to, + size_t tolen, + const char *from, size_t fromlen, + int padding, int force); +int crypto_pk_private_hybrid_decrypt(crypto_pk_t *env, char *to, + size_t tolen, + const char *from, size_t fromlen, + int padding, int warnOnFailure); + +int crypto_pk_asn1_encode(crypto_pk_t *pk, char *dest, size_t dest_len); +crypto_pk_t *crypto_pk_asn1_decode(const char *str, size_t len); +int crypto_pk_get_digest(crypto_pk_t *pk, char *digest_out); +int crypto_pk_get_all_digests(crypto_pk_t *pk, digests_t *digests_out); +int crypto_pk_get_fingerprint(crypto_pk_t *pk, char *fp_out,int add_space); + +/* symmetric crypto */ +const char *crypto_cipher_get_key(crypto_cipher_t *env); + +int crypto_cipher_encrypt(crypto_cipher_t *env, char *to, + const char *from, size_t fromlen); +int crypto_cipher_decrypt(crypto_cipher_t *env, char *to, + const char *from, size_t fromlen); +int crypto_cipher_crypt_inplace(crypto_cipher_t *env, char *d, size_t len); + +int crypto_cipher_encrypt_with_iv(const char *key, + char *to, size_t tolen, + const char *from, size_t fromlen); +int crypto_cipher_decrypt_with_iv(const char *key, + char *to, size_t tolen, + const char *from, size_t fromlen); + +/* SHA-1 and other digests. */ +int crypto_digest(char *digest, const char *m, size_t len); +int crypto_digest256(char *digest, const char *m, size_t len, + digest_algorithm_t algorithm); +int crypto_digest_all(digests_t *ds_out, const char *m, size_t len); +struct smartlist_t; +void crypto_digest_smartlist(char *digest_out, size_t len_out, + const struct smartlist_t *lst, const char *append, + digest_algorithm_t alg); +const char *crypto_digest_algorithm_get_name(digest_algorithm_t alg); +int crypto_digest_algorithm_parse_name(const char *name); +crypto_digest_t *crypto_digest_new(void); +crypto_digest_t *crypto_digest256_new(digest_algorithm_t algorithm); +void crypto_digest_free(crypto_digest_t *digest); +void crypto_digest_add_bytes(crypto_digest_t *digest, const char *data, + size_t len); +void crypto_digest_get_digest(crypto_digest_t *digest, + char *out, size_t out_len); +crypto_digest_t *crypto_digest_dup(const crypto_digest_t *digest); +void crypto_digest_assign(crypto_digest_t *into, + const crypto_digest_t *from); +void crypto_hmac_sha256(char *hmac_out, + const char *key, size_t key_len, + const char *msg, size_t msg_len); + +/* Key negotiation */ +#define DH_TYPE_CIRCUIT 1 +#define DH_TYPE_REND 2 +#define DH_TYPE_TLS 3 +crypto_dh_t *crypto_dh_new(int dh_type); +crypto_dh_t *crypto_dh_dup(const crypto_dh_t *dh); +int crypto_dh_get_bytes(crypto_dh_t *dh); +int crypto_dh_generate_public(crypto_dh_t *dh); +int crypto_dh_get_public(crypto_dh_t *dh, char *pubkey_out, + size_t pubkey_out_len); +ssize_t crypto_dh_compute_secret(int severity, crypto_dh_t *dh, + const char *pubkey, size_t pubkey_len, + char *secret_out, size_t secret_out_len); +void crypto_dh_free(crypto_dh_t *dh); + +int crypto_expand_key_material_TAP(const uint8_t *key_in, + size_t key_in_len, + uint8_t *key_out, size_t key_out_len); +int crypto_expand_key_material_rfc5869_sha256( + const uint8_t *key_in, size_t key_in_len, + const uint8_t *salt_in, size_t salt_in_len, + const uint8_t *info_in, size_t info_in_len, + uint8_t *key_out, size_t key_out_len); + +/* random numbers */ +int crypto_seed_rng(int startup); +MOCK_DECL(int,crypto_rand,(char *to, size_t n)); +int crypto_strongest_rand(uint8_t *out, size_t out_len); +int crypto_rand_int(unsigned int max); +uint64_t crypto_rand_uint64(uint64_t max); +double crypto_rand_double(void); +struct tor_weak_rng_t; +void crypto_seed_weak_rng(struct tor_weak_rng_t *rng); + +char *crypto_random_hostname(int min_rand_len, int max_rand_len, + const char *prefix, const char *suffix); + +struct smartlist_t; +void *smartlist_choose(const struct smartlist_t *sl); +void smartlist_shuffle(struct smartlist_t *sl); + +int base64_encode(char *dest, size_t destlen, const char *src, size_t srclen); +int base64_decode(char *dest, size_t destlen, const char *src, size_t srclen); +/** Characters that can appear (case-insensitively) in a base32 encoding. */ +#define BASE32_CHARS "abcdefghijklmnopqrstuvwxyz234567" +void base32_encode(char *dest, size_t destlen, const char *src, size_t srclen); +int base32_decode(char *dest, size_t destlen, const char *src, size_t srclen); + +int digest_to_base64(char *d64, const char *digest); +int digest_from_base64(char *digest, const char *d64); +int digest256_to_base64(char *d64, const char *digest); +int digest256_from_base64(char *digest, const char *d64); + +/** Length of RFC2440-style S2K specifier: the first 8 bytes are a salt, the + * 9th describes how much iteration to do. */ +#define S2K_SPECIFIER_LEN 9 +void secret_to_key(char *key_out, size_t key_out_len, const char *secret, + size_t secret_len, const char *s2k_specifier); + +/** OpenSSL-based utility functions. */ +void memwipe(void *mem, uint8_t byte, size_t sz); + +/* Prototypes for private functions only used by tortls.c, crypto.c, and the + * unit tests. */ +struct rsa_st; +struct evp_pkey_st; +struct dh_st; +struct rsa_st *crypto_pk_get_rsa_(crypto_pk_t *env); +crypto_pk_t *crypto_new_pk_from_rsa_(struct rsa_st *rsa); +struct evp_pkey_st *crypto_pk_get_evp_pkey_(crypto_pk_t *env, + int private); +struct dh_st *crypto_dh_get_dh_(crypto_dh_t *dh); + +void crypto_add_spaces_to_fp(char *out, size_t outlen, const char *in); + +#endif + diff --git a/src/tor/crypto_curve25519.c b/src/tor/crypto_curve25519.c new file mode 100644 index 0000000..8fe1e1b --- /dev/null +++ b/src/tor/crypto_curve25519.c @@ -0,0 +1,191 @@ +/* Copyright (c) 2012-2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/* Wrapper code for a curve25519 implementation. */ + +#define CRYPTO_CURVE25519_PRIVATE +#include "orconfig.h" +#ifdef HAVE_SYS_STAT_H +#include +#endif +#include "crypto.h" +#include "crypto_curve25519.h" +#include "tor_util.h" +#include "torlog.h" + +/* ============================== + Part 1: wrap a suitable curve25519 implementation as curve25519_impl + ============================== */ + +#ifdef USE_CURVE25519_DONNA +int curve25519_donna(uint8_t *mypublic, + const uint8_t *secret, const uint8_t *basepoint); +#endif +#ifdef USE_CURVE25519_NACL +#ifdef HAVE_CRYPTO_SCALARMULT_CURVE25519_H +#include +#elif defined(HAVE_NACL_CRYPTO_SCALARMULT_CURVE25519_H) +#include +#endif +#endif + +STATIC int +curve25519_impl(uint8_t *output, const uint8_t *secret, + const uint8_t *basepoint) +{ + uint8_t bp[CURVE25519_PUBKEY_LEN]; + int r; + memcpy(bp, basepoint, CURVE25519_PUBKEY_LEN); + /* Clear the high bit, in case our backend foolishly looks at it. */ + bp[31] &= 0x7f; +#ifdef USE_CURVE25519_DONNA + r = curve25519_donna(output, secret, bp); +#elif defined(USE_CURVE25519_NACL) + r = crypto_scalarmult_curve25519(output, secret, bp); +#else +#error "No implementation of curve25519 is available." +#endif + memwipe(bp, 0, sizeof(bp)); + return r; +} + +/* ============================== + Part 2: Wrap curve25519_impl with some convenience types and functions. + ============================== */ + +/** + * Return true iff a curve25519_public_key_t seems valid. (It's not necessary + * to see if the point is on the curve, since the twist is also secure, but we + * do need to make sure that it isn't the point at infinity.) */ +int +curve25519_public_key_is_ok(const curve25519_public_key_t *key) +{ + return !safe_mem_is_zero(key->public_key, CURVE25519_PUBKEY_LEN); +} + +/** Generate a new keypair and return the secret key. If extra_strong + * is true, this key is possibly going to get used more than once, so + * use a better-than-usual RNG. Return 0 on success, -1 on failure. */ +int +curve25519_secret_key_generate(curve25519_secret_key_t *key_out, + int extra_strong) +{ + uint8_t k_tmp[CURVE25519_SECKEY_LEN]; + + if (crypto_rand((char*)key_out->secret_key, CURVE25519_SECKEY_LEN) < 0) + return -1; + if (extra_strong && !crypto_strongest_rand(k_tmp, CURVE25519_SECKEY_LEN)) { + /* If they asked for extra-strong entropy and we have some, use it as an + * HMAC key to improve not-so-good entropy rather than using it directly, + * just in case the extra-strong entropy is less amazing than we hoped. */ + crypto_hmac_sha256((char *)key_out->secret_key, + (const char *)k_tmp, sizeof(k_tmp), + (const char *)key_out->secret_key, CURVE25519_SECKEY_LEN); + } + memwipe(k_tmp, 0, sizeof(k_tmp)); + key_out->secret_key[0] &= 248; + key_out->secret_key[31] &= 127; + key_out->secret_key[31] |= 64; + + return 0; +} + +void +curve25519_public_key_generate(curve25519_public_key_t *key_out, + const curve25519_secret_key_t *seckey) +{ + static const uint8_t basepoint[32] = {9}; + + curve25519_impl(key_out->public_key, seckey->secret_key, basepoint); +} + +int +curve25519_keypair_generate(curve25519_keypair_t *keypair_out, + int extra_strong) +{ + if (curve25519_secret_key_generate(&keypair_out->seckey, extra_strong) < 0) + return -1; + curve25519_public_key_generate(&keypair_out->pubkey, &keypair_out->seckey); + return 0; +} + +int +curve25519_keypair_write_to_file(const curve25519_keypair_t *keypair, + const char *fname, + const char *tag) +{ + char contents[32 + CURVE25519_SECKEY_LEN + CURVE25519_PUBKEY_LEN]; + int r; + + memset(contents, 0, sizeof(contents)); + tor_snprintf(contents, sizeof(contents), "== c25519v1: %s ==", tag); + tor_assert(strlen(contents) <= 32); + memcpy(contents+32, keypair->seckey.secret_key, CURVE25519_SECKEY_LEN); + memcpy(contents+32+CURVE25519_SECKEY_LEN, + keypair->pubkey.public_key, CURVE25519_PUBKEY_LEN); + + r = write_bytes_to_file(fname, contents, sizeof(contents), 1); + + memwipe(contents, 0, sizeof(contents)); + return r; +} + +int +curve25519_keypair_read_from_file(curve25519_keypair_t *keypair_out, + char **tag_out, + const char *fname) +{ + char prefix[33]; + char *content; + struct stat st; + int r = -1; + + *tag_out = NULL; + + st.st_size = 0; + content = read_file_to_str(fname, RFTS_BIN|RFTS_IGNORE_MISSING, &st); + if (! content) + goto end; + if (st.st_size != 32 + CURVE25519_SECKEY_LEN + CURVE25519_PUBKEY_LEN) + goto end; + + memcpy(prefix, content, 32); + prefix[32] = '\0'; + if (strcmpstart(prefix, "== c25519v1: ") || + strcmpend(prefix, " ==")) + goto end; + + *tag_out = tor_strndup(prefix+strlen("== c25519v1: "), + strlen(prefix) - strlen("== c25519v1: ==")); + + memcpy(keypair_out->seckey.secret_key, content+32, CURVE25519_SECKEY_LEN); + curve25519_public_key_generate(&keypair_out->pubkey, &keypair_out->seckey); + if (tor_memneq(keypair_out->pubkey.public_key, + content + 32 + CURVE25519_SECKEY_LEN, + CURVE25519_PUBKEY_LEN)) + goto end; + + r = 0; + + end: + if (content) { + memwipe(content, 0, (size_t) st.st_size); + tor_free(content); + } + if (r != 0) { + memset(keypair_out, 0, sizeof(*keypair_out)); + tor_free(*tag_out); + } + return r; +} + +/** Perform the curve25519 ECDH handshake with skey and pkey, + * writing CURVE25519_OUTPUT_LEN bytes of output into output. */ +void +curve25519_handshake(uint8_t *output, + const curve25519_secret_key_t *skey, + const curve25519_public_key_t *pkey) +{ + curve25519_impl(output, skey->secret_key, pkey->public_key); +} + diff --git a/src/tor/crypto_curve25519.h b/src/tor/crypto_curve25519.h new file mode 100644 index 0000000..57018ac --- /dev/null +++ b/src/tor/crypto_curve25519.h @@ -0,0 +1,74 @@ +/* Copyright (c) 2012-2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_CRYPTO_CURVE25519_H +#define TOR_CRYPTO_CURVE25519_H + +#include "testsupport.h" +#include "torint.h" + +/** Length of a curve25519 public key when encoded. */ +#define CURVE25519_PUBKEY_LEN 32 +/** Length of a curve25519 secret key when encoded. */ +#define CURVE25519_SECKEY_LEN 32 +/** Length of the result of a curve25519 handshake. */ +#define CURVE25519_OUTPUT_LEN 32 + +/** Wrapper type for a curve25519 public key */ +typedef struct curve25519_public_key_t { + uint8_t public_key[CURVE25519_PUBKEY_LEN]; +} curve25519_public_key_t; + +/** Wrapper type for a curve25519 secret key */ +typedef struct curve25519_secret_key_t { + uint8_t secret_key[CURVE25519_SECKEY_LEN]; +} curve25519_secret_key_t; + +/** A paired public and private key for curve25519. **/ +typedef struct curve25519_keypair_t { + curve25519_public_key_t pubkey; + curve25519_secret_key_t seckey; +} curve25519_keypair_t; + +#ifdef CURVE25519_ENABLED +/* These functions require that we actually know how to use curve25519 keys. + * The other data structures and functions in this header let us parse them, + * store them, and move them around. + */ + +int curve25519_public_key_is_ok(const curve25519_public_key_t *); + +int curve25519_secret_key_generate(curve25519_secret_key_t *key_out, + int extra_strong); +void curve25519_public_key_generate(curve25519_public_key_t *key_out, + const curve25519_secret_key_t *seckey); +int curve25519_keypair_generate(curve25519_keypair_t *keypair_out, + int extra_strong); + +void curve25519_handshake(uint8_t *output, + const curve25519_secret_key_t *, + const curve25519_public_key_t *); + +int curve25519_keypair_write_to_file(const curve25519_keypair_t *keypair, + const char *fname, + const char *tag); + +int curve25519_keypair_read_from_file(curve25519_keypair_t *keypair_out, + char **tag_out, + const char *fname); + +#ifdef CRYPTO_CURVE25519_PRIVATE +STATIC int curve25519_impl(uint8_t *output, const uint8_t *secret, + const uint8_t *basepoint); +#endif +#endif + +#define CURVE25519_BASE64_PADDED_LEN 44 + +int curve25519_public_from_base64(curve25519_public_key_t *pkey, + const char *input); +int curve25519_public_to_base64(char *output, + const curve25519_public_key_t *pkey); + +#endif + diff --git a/src/tor/crypto_format.c b/src/tor/crypto_format.c new file mode 100644 index 0000000..acb3463 --- /dev/null +++ b/src/tor/crypto_format.c @@ -0,0 +1,45 @@ +/* Copyright (c) 2012-2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/* Formatting and parsing code for crypto-related data structures. */ + +#include "orconfig.h" +#ifdef HAVE_SYS_STAT_H +#include +#endif +#include "crypto.h" +#include "crypto_curve25519.h" +#include "tor_util.h" +#include "torlog.h" + +int +curve25519_public_to_base64(char *output, + const curve25519_public_key_t *pkey) +{ + char buf[128]; + base64_encode(buf, sizeof(buf), + (const char*)pkey->public_key, CURVE25519_PUBKEY_LEN); + buf[CURVE25519_BASE64_PADDED_LEN] = '\0'; + memcpy(output, buf, CURVE25519_BASE64_PADDED_LEN+1); + return 0; +} + +int +curve25519_public_from_base64(curve25519_public_key_t *pkey, + const char *input) +{ + size_t len = strlen(input); + if (len == CURVE25519_BASE64_PADDED_LEN - 1) { + /* not padded */ + return digest256_from_base64((char*)pkey->public_key, input); + } else if (len == CURVE25519_BASE64_PADDED_LEN) { + char buf[128]; + if (base64_decode(buf, sizeof(buf), input, len) != CURVE25519_PUBKEY_LEN) + return -1; + memcpy(pkey->public_key, buf, CURVE25519_PUBKEY_LEN); + return 0; + } else { + return -1; + } +} + diff --git a/src/tor/curve25519-donna.c b/src/tor/curve25519-donna.c new file mode 100644 index 0000000..5c6821c --- /dev/null +++ b/src/tor/curve25519-donna.c @@ -0,0 +1,732 @@ +/* Copyright 2008, Google Inc. + * 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. + * * Neither the name of Google Inc. 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 + * OWNER 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. + * + * curve25519-donna: Curve25519 elliptic curve, public key function + * + * http://code.google.com/p/curve25519-donna/ + * + * Adam Langley + * + * Derived from public domain C code by Daniel J. Bernstein + * + * More information about curve25519 can be found here + * http://cr.yp.to/ecdh.html + * + * djb's sample implementation of curve25519 is written in a special assembly + * language called qhasm and uses the floating point registers. + * + * This is, almost, a clean room reimplementation from the curve25519 paper. It + * uses many of the tricks described therein. Only the crecip function is taken + * from the sample implementation. + */ + +#include "orconfig.h" + +#include +#include "torint.h" + +typedef uint8_t u8; +typedef int32_t s32; +typedef int64_t limb; + +/* Field element representation: + * + * Field elements are written as an array of signed, 64-bit limbs, least + * significant first. The value of the field element is: + * x[0] + 2^26·x[1] + x^51·x[2] + 2^102·x[3] + ... + * + * i.e. the limbs are 26, 25, 26, 25, ... bits wide. + */ + +/* Sum two numbers: output += in */ +static void fsum(limb *output, const limb *in) { + unsigned i; + for (i = 0; i < 10; i += 2) { + output[0+i] = (output[0+i] + in[0+i]); + output[1+i] = (output[1+i] + in[1+i]); + } +} + +/* Find the difference of two numbers: output = in - output + * (note the order of the arguments!) + */ +static void fdifference(limb *output, const limb *in) { + unsigned i; + for (i = 0; i < 10; ++i) { + output[i] = (in[i] - output[i]); + } +} + +/* Multiply a number by a scalar: output = in * scalar */ +static void fscalar_product(limb *output, const limb *in, const limb scalar) { + unsigned i; + for (i = 0; i < 10; ++i) { + output[i] = in[i] * scalar; + } +} + +/* Multiply two numbers: output = in2 * in + * + * output must be distinct to both inputs. The inputs are reduced coefficient + * form, the output is not. + */ +static void fproduct(limb *output, const limb *in2, const limb *in) { + output[0] = ((limb) ((s32) in2[0])) * ((s32) in[0]); + output[1] = ((limb) ((s32) in2[0])) * ((s32) in[1]) + + ((limb) ((s32) in2[1])) * ((s32) in[0]); + output[2] = 2 * ((limb) ((s32) in2[1])) * ((s32) in[1]) + + ((limb) ((s32) in2[0])) * ((s32) in[2]) + + ((limb) ((s32) in2[2])) * ((s32) in[0]); + output[3] = ((limb) ((s32) in2[1])) * ((s32) in[2]) + + ((limb) ((s32) in2[2])) * ((s32) in[1]) + + ((limb) ((s32) in2[0])) * ((s32) in[3]) + + ((limb) ((s32) in2[3])) * ((s32) in[0]); + output[4] = ((limb) ((s32) in2[2])) * ((s32) in[2]) + + 2 * (((limb) ((s32) in2[1])) * ((s32) in[3]) + + ((limb) ((s32) in2[3])) * ((s32) in[1])) + + ((limb) ((s32) in2[0])) * ((s32) in[4]) + + ((limb) ((s32) in2[4])) * ((s32) in[0]); + output[5] = ((limb) ((s32) in2[2])) * ((s32) in[3]) + + ((limb) ((s32) in2[3])) * ((s32) in[2]) + + ((limb) ((s32) in2[1])) * ((s32) in[4]) + + ((limb) ((s32) in2[4])) * ((s32) in[1]) + + ((limb) ((s32) in2[0])) * ((s32) in[5]) + + ((limb) ((s32) in2[5])) * ((s32) in[0]); + output[6] = 2 * (((limb) ((s32) in2[3])) * ((s32) in[3]) + + ((limb) ((s32) in2[1])) * ((s32) in[5]) + + ((limb) ((s32) in2[5])) * ((s32) in[1])) + + ((limb) ((s32) in2[2])) * ((s32) in[4]) + + ((limb) ((s32) in2[4])) * ((s32) in[2]) + + ((limb) ((s32) in2[0])) * ((s32) in[6]) + + ((limb) ((s32) in2[6])) * ((s32) in[0]); + output[7] = ((limb) ((s32) in2[3])) * ((s32) in[4]) + + ((limb) ((s32) in2[4])) * ((s32) in[3]) + + ((limb) ((s32) in2[2])) * ((s32) in[5]) + + ((limb) ((s32) in2[5])) * ((s32) in[2]) + + ((limb) ((s32) in2[1])) * ((s32) in[6]) + + ((limb) ((s32) in2[6])) * ((s32) in[1]) + + ((limb) ((s32) in2[0])) * ((s32) in[7]) + + ((limb) ((s32) in2[7])) * ((s32) in[0]); + output[8] = ((limb) ((s32) in2[4])) * ((s32) in[4]) + + 2 * (((limb) ((s32) in2[3])) * ((s32) in[5]) + + ((limb) ((s32) in2[5])) * ((s32) in[3]) + + ((limb) ((s32) in2[1])) * ((s32) in[7]) + + ((limb) ((s32) in2[7])) * ((s32) in[1])) + + ((limb) ((s32) in2[2])) * ((s32) in[6]) + + ((limb) ((s32) in2[6])) * ((s32) in[2]) + + ((limb) ((s32) in2[0])) * ((s32) in[8]) + + ((limb) ((s32) in2[8])) * ((s32) in[0]); + output[9] = ((limb) ((s32) in2[4])) * ((s32) in[5]) + + ((limb) ((s32) in2[5])) * ((s32) in[4]) + + ((limb) ((s32) in2[3])) * ((s32) in[6]) + + ((limb) ((s32) in2[6])) * ((s32) in[3]) + + ((limb) ((s32) in2[2])) * ((s32) in[7]) + + ((limb) ((s32) in2[7])) * ((s32) in[2]) + + ((limb) ((s32) in2[1])) * ((s32) in[8]) + + ((limb) ((s32) in2[8])) * ((s32) in[1]) + + ((limb) ((s32) in2[0])) * ((s32) in[9]) + + ((limb) ((s32) in2[9])) * ((s32) in[0]); + output[10] = 2 * (((limb) ((s32) in2[5])) * ((s32) in[5]) + + ((limb) ((s32) in2[3])) * ((s32) in[7]) + + ((limb) ((s32) in2[7])) * ((s32) in[3]) + + ((limb) ((s32) in2[1])) * ((s32) in[9]) + + ((limb) ((s32) in2[9])) * ((s32) in[1])) + + ((limb) ((s32) in2[4])) * ((s32) in[6]) + + ((limb) ((s32) in2[6])) * ((s32) in[4]) + + ((limb) ((s32) in2[2])) * ((s32) in[8]) + + ((limb) ((s32) in2[8])) * ((s32) in[2]); + output[11] = ((limb) ((s32) in2[5])) * ((s32) in[6]) + + ((limb) ((s32) in2[6])) * ((s32) in[5]) + + ((limb) ((s32) in2[4])) * ((s32) in[7]) + + ((limb) ((s32) in2[7])) * ((s32) in[4]) + + ((limb) ((s32) in2[3])) * ((s32) in[8]) + + ((limb) ((s32) in2[8])) * ((s32) in[3]) + + ((limb) ((s32) in2[2])) * ((s32) in[9]) + + ((limb) ((s32) in2[9])) * ((s32) in[2]); + output[12] = ((limb) ((s32) in2[6])) * ((s32) in[6]) + + 2 * (((limb) ((s32) in2[5])) * ((s32) in[7]) + + ((limb) ((s32) in2[7])) * ((s32) in[5]) + + ((limb) ((s32) in2[3])) * ((s32) in[9]) + + ((limb) ((s32) in2[9])) * ((s32) in[3])) + + ((limb) ((s32) in2[4])) * ((s32) in[8]) + + ((limb) ((s32) in2[8])) * ((s32) in[4]); + output[13] = ((limb) ((s32) in2[6])) * ((s32) in[7]) + + ((limb) ((s32) in2[7])) * ((s32) in[6]) + + ((limb) ((s32) in2[5])) * ((s32) in[8]) + + ((limb) ((s32) in2[8])) * ((s32) in[5]) + + ((limb) ((s32) in2[4])) * ((s32) in[9]) + + ((limb) ((s32) in2[9])) * ((s32) in[4]); + output[14] = 2 * (((limb) ((s32) in2[7])) * ((s32) in[7]) + + ((limb) ((s32) in2[5])) * ((s32) in[9]) + + ((limb) ((s32) in2[9])) * ((s32) in[5])) + + ((limb) ((s32) in2[6])) * ((s32) in[8]) + + ((limb) ((s32) in2[8])) * ((s32) in[6]); + output[15] = ((limb) ((s32) in2[7])) * ((s32) in[8]) + + ((limb) ((s32) in2[8])) * ((s32) in[7]) + + ((limb) ((s32) in2[6])) * ((s32) in[9]) + + ((limb) ((s32) in2[9])) * ((s32) in[6]); + output[16] = ((limb) ((s32) in2[8])) * ((s32) in[8]) + + 2 * (((limb) ((s32) in2[7])) * ((s32) in[9]) + + ((limb) ((s32) in2[9])) * ((s32) in[7])); + output[17] = ((limb) ((s32) in2[8])) * ((s32) in[9]) + + ((limb) ((s32) in2[9])) * ((s32) in[8]); + output[18] = 2 * ((limb) ((s32) in2[9])) * ((s32) in[9]); +} + +/* Reduce a long form to a short form by taking the input mod 2^255 - 19. */ +static void freduce_degree(limb *output) { + /* Each of these shifts and adds ends up multiplying the value by 19. */ + output[8] += output[18] << 4; + output[8] += output[18] << 1; + output[8] += output[18]; + output[7] += output[17] << 4; + output[7] += output[17] << 1; + output[7] += output[17]; + output[6] += output[16] << 4; + output[6] += output[16] << 1; + output[6] += output[16]; + output[5] += output[15] << 4; + output[5] += output[15] << 1; + output[5] += output[15]; + output[4] += output[14] << 4; + output[4] += output[14] << 1; + output[4] += output[14]; + output[3] += output[13] << 4; + output[3] += output[13] << 1; + output[3] += output[13]; + output[2] += output[12] << 4; + output[2] += output[12] << 1; + output[2] += output[12]; + output[1] += output[11] << 4; + output[1] += output[11] << 1; + output[1] += output[11]; + output[0] += output[10] << 4; + output[0] += output[10] << 1; + output[0] += output[10]; +} + +#if (-1 & 3) != 3 +#error "This code only works on a two's complement system" +#endif + +/* return v / 2^26, using only shifts and adds. */ +static inline limb +div_by_2_26(const limb v) +{ + /* High word of v; no shift needed*/ + const uint32_t highword = (uint32_t) (((uint64_t) v) >> 32); + /* Set to all 1s if v was negative; else set to 0s. */ + const int32_t sign = ((int32_t) highword) >> 31; + /* Set to 0x3ffffff if v was negative; else set to 0. */ + const int32_t roundoff = ((uint32_t) sign) >> 6; + /* Should return v / (1<<26) */ + return (v + roundoff) >> 26; +} + +/* return v / (2^25), using only shifts and adds. */ +static inline limb +div_by_2_25(const limb v) +{ + /* High word of v; no shift needed*/ + const uint32_t highword = (uint32_t) (((uint64_t) v) >> 32); + /* Set to all 1s if v was negative; else set to 0s. */ + const int32_t sign = ((int32_t) highword) >> 31; + /* Set to 0x1ffffff if v was negative; else set to 0. */ + const int32_t roundoff = ((uint32_t) sign) >> 7; + /* Should return v / (1<<25) */ + return (v + roundoff) >> 25; +} + +static inline s32 +div_s32_by_2_25(const s32 v) +{ + const s32 roundoff = ((uint32_t)(v >> 31)) >> 7; + return (v + roundoff) >> 25; +} + +/* Reduce all coefficients of the short form input so that |x| < 2^26. + * + * On entry: |output[i]| < 2^62 + */ +static void freduce_coefficients(limb *output) { + unsigned i; + + output[10] = 0; + + for (i = 0; i < 10; i += 2) { + limb over = div_by_2_26(output[i]); + output[i] -= over << 26; + output[i+1] += over; + + over = div_by_2_25(output[i+1]); + output[i+1] -= over << 25; + output[i+2] += over; + } + /* Now |output[10]| < 2 ^ 38 and all other coefficients are reduced. */ + output[0] += output[10] << 4; + output[0] += output[10] << 1; + output[0] += output[10]; + + output[10] = 0; + + /* Now output[1..9] are reduced, and |output[0]| < 2^26 + 19 * 2^38 + * So |over| will be no more than 77825 */ + { + limb over = div_by_2_26(output[0]); + output[0] -= over << 26; + output[1] += over; + } + + /* Now output[0,2..9] are reduced, and |output[1]| < 2^25 + 77825 + * So |over| will be no more than 1. */ + { + /* output[1] fits in 32 bits, so we can use div_s32_by_2_25 here. */ + s32 over32 = div_s32_by_2_25((s32) output[1]); + output[1] -= over32 << 25; + output[2] += over32; + } + + /* Finally, output[0,1,3..9] are reduced, and output[2] is "nearly reduced": + * we have |output[2]| <= 2^26. This is good enough for all of our math, + * but it will require an extra freduce_coefficients before fcontract. */ +} + +/* A helpful wrapper around fproduct: output = in * in2. + * + * output must be distinct to both inputs. The output is reduced degree and + * reduced coefficient. + */ +static void +fmul(limb *output, const limb *in, const limb *in2) { + limb t[19]; + fproduct(t, in, in2); + freduce_degree(t); + freduce_coefficients(t); + memcpy(output, t, sizeof(limb) * 10); +} + +static void fsquare_inner(limb *output, const limb *in) { + output[0] = ((limb) ((s32) in[0])) * ((s32) in[0]); + output[1] = 2 * ((limb) ((s32) in[0])) * ((s32) in[1]); + output[2] = 2 * (((limb) ((s32) in[1])) * ((s32) in[1]) + + ((limb) ((s32) in[0])) * ((s32) in[2])); + output[3] = 2 * (((limb) ((s32) in[1])) * ((s32) in[2]) + + ((limb) ((s32) in[0])) * ((s32) in[3])); + output[4] = ((limb) ((s32) in[2])) * ((s32) in[2]) + + 4 * ((limb) ((s32) in[1])) * ((s32) in[3]) + + 2 * ((limb) ((s32) in[0])) * ((s32) in[4]); + output[5] = 2 * (((limb) ((s32) in[2])) * ((s32) in[3]) + + ((limb) ((s32) in[1])) * ((s32) in[4]) + + ((limb) ((s32) in[0])) * ((s32) in[5])); + output[6] = 2 * (((limb) ((s32) in[3])) * ((s32) in[3]) + + ((limb) ((s32) in[2])) * ((s32) in[4]) + + ((limb) ((s32) in[0])) * ((s32) in[6]) + + 2 * ((limb) ((s32) in[1])) * ((s32) in[5])); + output[7] = 2 * (((limb) ((s32) in[3])) * ((s32) in[4]) + + ((limb) ((s32) in[2])) * ((s32) in[5]) + + ((limb) ((s32) in[1])) * ((s32) in[6]) + + ((limb) ((s32) in[0])) * ((s32) in[7])); + output[8] = ((limb) ((s32) in[4])) * ((s32) in[4]) + + 2 * (((limb) ((s32) in[2])) * ((s32) in[6]) + + ((limb) ((s32) in[0])) * ((s32) in[8]) + + 2 * (((limb) ((s32) in[1])) * ((s32) in[7]) + + ((limb) ((s32) in[3])) * ((s32) in[5]))); + output[9] = 2 * (((limb) ((s32) in[4])) * ((s32) in[5]) + + ((limb) ((s32) in[3])) * ((s32) in[6]) + + ((limb) ((s32) in[2])) * ((s32) in[7]) + + ((limb) ((s32) in[1])) * ((s32) in[8]) + + ((limb) ((s32) in[0])) * ((s32) in[9])); + output[10] = 2 * (((limb) ((s32) in[5])) * ((s32) in[5]) + + ((limb) ((s32) in[4])) * ((s32) in[6]) + + ((limb) ((s32) in[2])) * ((s32) in[8]) + + 2 * (((limb) ((s32) in[3])) * ((s32) in[7]) + + ((limb) ((s32) in[1])) * ((s32) in[9]))); + output[11] = 2 * (((limb) ((s32) in[5])) * ((s32) in[6]) + + ((limb) ((s32) in[4])) * ((s32) in[7]) + + ((limb) ((s32) in[3])) * ((s32) in[8]) + + ((limb) ((s32) in[2])) * ((s32) in[9])); + output[12] = ((limb) ((s32) in[6])) * ((s32) in[6]) + + 2 * (((limb) ((s32) in[4])) * ((s32) in[8]) + + 2 * (((limb) ((s32) in[5])) * ((s32) in[7]) + + ((limb) ((s32) in[3])) * ((s32) in[9]))); + output[13] = 2 * (((limb) ((s32) in[6])) * ((s32) in[7]) + + ((limb) ((s32) in[5])) * ((s32) in[8]) + + ((limb) ((s32) in[4])) * ((s32) in[9])); + output[14] = 2 * (((limb) ((s32) in[7])) * ((s32) in[7]) + + ((limb) ((s32) in[6])) * ((s32) in[8]) + + 2 * ((limb) ((s32) in[5])) * ((s32) in[9])); + output[15] = 2 * (((limb) ((s32) in[7])) * ((s32) in[8]) + + ((limb) ((s32) in[6])) * ((s32) in[9])); + output[16] = ((limb) ((s32) in[8])) * ((s32) in[8]) + + 4 * ((limb) ((s32) in[7])) * ((s32) in[9]); + output[17] = 2 * ((limb) ((s32) in[8])) * ((s32) in[9]); + output[18] = 2 * ((limb) ((s32) in[9])) * ((s32) in[9]); +} + +static void +fsquare(limb *output, const limb *in) { + limb t[19]; + fsquare_inner(t, in); + freduce_degree(t); + freduce_coefficients(t); + memcpy(output, t, sizeof(limb) * 10); +} + +/* Take a little-endian, 32-byte number and expand it into polynomial form */ +static void +fexpand(limb *output, const u8 *input) { +#define F(n,start,shift,mask) \ + output[n] = ((((limb) input[start + 0]) | \ + ((limb) input[start + 1]) << 8 | \ + ((limb) input[start + 2]) << 16 | \ + ((limb) input[start + 3]) << 24) >> shift) & mask; + F(0, 0, 0, 0x3ffffff); + F(1, 3, 2, 0x1ffffff); + F(2, 6, 3, 0x3ffffff); + F(3, 9, 5, 0x1ffffff); + F(4, 12, 6, 0x3ffffff); + F(5, 16, 0, 0x1ffffff); + F(6, 19, 1, 0x3ffffff); + F(7, 22, 3, 0x1ffffff); + F(8, 25, 4, 0x3ffffff); + F(9, 28, 6, 0x1ffffff); +#undef F +} + +#if (-32 >> 1) != -16 +#error "This code only works when >> does sign-extension on negative numbers" +#endif + +/* Take a fully reduced polynomial form number and contract it into a + * little-endian, 32-byte array + */ +static void +fcontract(u8 *output, limb *input) { + int i; + int j; + + for (j = 0; j < 2; ++j) { + for (i = 0; i < 9; ++i) { + if ((i & 1) == 1) { + /* This calculation is a time-invariant way to make input[i] positive + by borrowing from the next-larger limb. + */ + const s32 mask = (s32)(input[i]) >> 31; + const s32 carry = -(((s32)(input[i]) & mask) >> 25); + input[i] = (s32)(input[i]) + (carry << 25); + input[i+1] = (s32)(input[i+1]) - carry; + } else { + const s32 mask = (s32)(input[i]) >> 31; + const s32 carry = -(((s32)(input[i]) & mask) >> 26); + input[i] = (s32)(input[i]) + (carry << 26); + input[i+1] = (s32)(input[i+1]) - carry; + } + } + { + const s32 mask = (s32)(input[9]) >> 31; + const s32 carry = -(((s32)(input[9]) & mask) >> 25); + input[9] = (s32)(input[9]) + (carry << 25); + input[0] = (s32)(input[0]) - (carry * 19); + } + } + + /* The first borrow-propagation pass above ended with every limb + except (possibly) input[0] non-negative. + + Since each input limb except input[0] is decreased by at most 1 + by a borrow-propagation pass, the second borrow-propagation pass + could only have wrapped around to decrease input[0] again if the + first pass left input[0] negative *and* input[1] through input[9] + were all zero. In that case, input[1] is now 2^25 - 1, and this + last borrow-propagation step will leave input[1] non-negative. + */ + { + const s32 mask = (s32)(input[0]) >> 31; + const s32 carry = -(((s32)(input[0]) & mask) >> 26); + input[0] = (s32)(input[0]) + (carry << 26); + input[1] = (s32)(input[1]) - carry; + } + + /* Both passes through the above loop, plus the last 0-to-1 step, are + necessary: if input[9] is -1 and input[0] through input[8] are 0, + negative values will remain in the array until the end. + */ + + input[1] <<= 2; + input[2] <<= 3; + input[3] <<= 5; + input[4] <<= 6; + input[6] <<= 1; + input[7] <<= 3; + input[8] <<= 4; + input[9] <<= 6; +#define F(i, s) \ + output[s+0] |= input[i] & 0xff; \ + output[s+1] = (input[i] >> 8) & 0xff; \ + output[s+2] = (input[i] >> 16) & 0xff; \ + output[s+3] = (input[i] >> 24) & 0xff; + output[0] = 0; + output[16] = 0; + F(0,0); + F(1,3); + F(2,6); + F(3,9); + F(4,12); + F(5,16); + F(6,19); + F(7,22); + F(8,25); + F(9,28); +#undef F +} + +/* Input: Q, Q', Q-Q' + * Output: 2Q, Q+Q' + * + * x2 z3: long form + * x3 z3: long form + * x z: short form, destroyed + * xprime zprime: short form, destroyed + * qmqp: short form, preserved + */ +static void fmonty(limb *x2, limb *z2, /* output 2Q */ + limb *x3, limb *z3, /* output Q + Q' */ + limb *x, limb *z, /* input Q */ + limb *xprime, limb *zprime, /* input Q' */ + const limb *qmqp /* input Q - Q' */) { + limb origx[10], origxprime[10], zzz[19], xx[19], zz[19], xxprime[19], + zzprime[19], zzzprime[19], xxxprime[19]; + + memcpy(origx, x, 10 * sizeof(limb)); + fsum(x, z); + fdifference(z, origx); // does x - z + + memcpy(origxprime, xprime, sizeof(limb) * 10); + fsum(xprime, zprime); + fdifference(zprime, origxprime); + fproduct(xxprime, xprime, z); + fproduct(zzprime, x, zprime); + freduce_degree(xxprime); + freduce_coefficients(xxprime); + freduce_degree(zzprime); + freduce_coefficients(zzprime); + memcpy(origxprime, xxprime, sizeof(limb) * 10); + fsum(xxprime, zzprime); + fdifference(zzprime, origxprime); + fsquare(xxxprime, xxprime); + fsquare(zzzprime, zzprime); + fproduct(zzprime, zzzprime, qmqp); + freduce_degree(zzprime); + freduce_coefficients(zzprime); + memcpy(x3, xxxprime, sizeof(limb) * 10); + memcpy(z3, zzprime, sizeof(limb) * 10); + + fsquare(xx, x); + fsquare(zz, z); + fproduct(x2, xx, zz); + freduce_degree(x2); + freduce_coefficients(x2); + fdifference(zz, xx); // does zz = xx - zz + memset(zzz + 10, 0, sizeof(limb) * 9); + fscalar_product(zzz, zz, 121665); + /* No need to call freduce_degree here: + fscalar_product doesn't increase the degree of its input. */ + freduce_coefficients(zzz); + fsum(zzz, xx); + fproduct(z2, zz, zzz); + freduce_degree(z2); + freduce_coefficients(z2); +} + +/* Conditionally swap two reduced-form limb arrays if 'iswap' is 1, but leave + * them unchanged if 'iswap' is 0. Runs in data-invariant time to avoid + * side-channel attacks. + * + * NOTE that this function requires that 'iswap' be 1 or 0; other values give + * wrong results. Also, the two limb arrays must be in reduced-coefficient, + * reduced-degree form: the values in a[10..19] or b[10..19] aren't swapped, + * and all all values in a[0..9],b[0..9] must have magnitude less than + * INT32_MAX. + */ +static void +swap_conditional(limb a[19], limb b[19], limb iswap) { + unsigned i; + const s32 swap = (s32) -iswap; + + for (i = 0; i < 10; ++i) { + const s32 x = swap & ( ((s32)a[i]) ^ ((s32)b[i]) ); + a[i] = ((s32)a[i]) ^ x; + b[i] = ((s32)b[i]) ^ x; + } +} + +/* Calculates nQ where Q is the x-coordinate of a point on the curve + * + * resultx/resultz: the x coordinate of the resulting curve point (short form) + * n: a little endian, 32-byte number + * q: a point of the curve (short form) + */ +static void +cmult(limb *resultx, limb *resultz, const u8 *n, const limb *q) { + limb a[19] = {0}, b[19] = {1}, c[19] = {1}, d[19] = {0}; + limb *nqpqx = a, *nqpqz = b, *nqx = c, *nqz = d, *t; + limb e[19] = {0}, f[19] = {1}, g[19] = {0}, h[19] = {1}; + limb *nqpqx2 = e, *nqpqz2 = f, *nqx2 = g, *nqz2 = h; + + unsigned i, j; + + memcpy(nqpqx, q, sizeof(limb) * 10); + + for (i = 0; i < 32; ++i) { + u8 byte = n[31 - i]; + for (j = 0; j < 8; ++j) { + const limb bit = byte >> 7; + + swap_conditional(nqx, nqpqx, bit); + swap_conditional(nqz, nqpqz, bit); + fmonty(nqx2, nqz2, + nqpqx2, nqpqz2, + nqx, nqz, + nqpqx, nqpqz, + q); + swap_conditional(nqx2, nqpqx2, bit); + swap_conditional(nqz2, nqpqz2, bit); + + t = nqx; + nqx = nqx2; + nqx2 = t; + t = nqz; + nqz = nqz2; + nqz2 = t; + t = nqpqx; + nqpqx = nqpqx2; + nqpqx2 = t; + t = nqpqz; + nqpqz = nqpqz2; + nqpqz2 = t; + + byte <<= 1; + } + } + + memcpy(resultx, nqx, sizeof(limb) * 10); + memcpy(resultz, nqz, sizeof(limb) * 10); +} + +// ----------------------------------------------------------------------------- +// Shamelessly copied from djb's code +// ----------------------------------------------------------------------------- +static void +crecip(limb *out, const limb *z) { + limb z2[10]; + limb z9[10]; + limb z11[10]; + limb z2_5_0[10]; + limb z2_10_0[10]; + limb z2_20_0[10]; + limb z2_50_0[10]; + limb z2_100_0[10]; + limb t0[10]; + limb t1[10]; + int i; + + /* 2 */ fsquare(z2,z); + /* 4 */ fsquare(t1,z2); + /* 8 */ fsquare(t0,t1); + /* 9 */ fmul(z9,t0,z); + /* 11 */ fmul(z11,z9,z2); + /* 22 */ fsquare(t0,z11); + /* 2^5 - 2^0 = 31 */ fmul(z2_5_0,t0,z9); + + /* 2^6 - 2^1 */ fsquare(t0,z2_5_0); + /* 2^7 - 2^2 */ fsquare(t1,t0); + /* 2^8 - 2^3 */ fsquare(t0,t1); + /* 2^9 - 2^4 */ fsquare(t1,t0); + /* 2^10 - 2^5 */ fsquare(t0,t1); + /* 2^10 - 2^0 */ fmul(z2_10_0,t0,z2_5_0); + + /* 2^11 - 2^1 */ fsquare(t0,z2_10_0); + /* 2^12 - 2^2 */ fsquare(t1,t0); + /* 2^20 - 2^10 */ for (i = 2;i < 10;i += 2) { fsquare(t0,t1); fsquare(t1,t0); } + /* 2^20 - 2^0 */ fmul(z2_20_0,t1,z2_10_0); + + /* 2^21 - 2^1 */ fsquare(t0,z2_20_0); + /* 2^22 - 2^2 */ fsquare(t1,t0); + /* 2^40 - 2^20 */ for (i = 2;i < 20;i += 2) { fsquare(t0,t1); fsquare(t1,t0); } + /* 2^40 - 2^0 */ fmul(t0,t1,z2_20_0); + + /* 2^41 - 2^1 */ fsquare(t1,t0); + /* 2^42 - 2^2 */ fsquare(t0,t1); + /* 2^50 - 2^10 */ for (i = 2;i < 10;i += 2) { fsquare(t1,t0); fsquare(t0,t1); } + /* 2^50 - 2^0 */ fmul(z2_50_0,t0,z2_10_0); + + /* 2^51 - 2^1 */ fsquare(t0,z2_50_0); + /* 2^52 - 2^2 */ fsquare(t1,t0); + /* 2^100 - 2^50 */ for (i = 2;i < 50;i += 2) { fsquare(t0,t1); fsquare(t1,t0); } + /* 2^100 - 2^0 */ fmul(z2_100_0,t1,z2_50_0); + + /* 2^101 - 2^1 */ fsquare(t1,z2_100_0); + /* 2^102 - 2^2 */ fsquare(t0,t1); + /* 2^200 - 2^100 */ for (i = 2;i < 100;i += 2) { fsquare(t1,t0); fsquare(t0,t1); } + /* 2^200 - 2^0 */ fmul(t1,t0,z2_100_0); + + /* 2^201 - 2^1 */ fsquare(t0,t1); + /* 2^202 - 2^2 */ fsquare(t1,t0); + /* 2^250 - 2^50 */ for (i = 2;i < 50;i += 2) { fsquare(t0,t1); fsquare(t1,t0); } + /* 2^250 - 2^0 */ fmul(t0,t1,z2_50_0); + + /* 2^251 - 2^1 */ fsquare(t1,t0); + /* 2^252 - 2^2 */ fsquare(t0,t1); + /* 2^253 - 2^3 */ fsquare(t1,t0); + /* 2^254 - 2^4 */ fsquare(t0,t1); + /* 2^255 - 2^5 */ fsquare(t1,t0); + /* 2^255 - 21 */ fmul(out,t1,z11); +} + +int curve25519_donna(u8 *, const u8 *, const u8 *); + +int +curve25519_donna(u8 *mypublic, const u8 *secret, const u8 *basepoint) { + limb bp[10], x[10], z[11], zmone[10]; + uint8_t e[32]; + int i; + + for (i = 0; i < 32; ++i) e[i] = secret[i]; + e[0] &= 248; + e[31] &= 127; + e[31] |= 64; + + fexpand(bp, basepoint); + cmult(x, z, e, bp); + crecip(zmone, z); + fmul(z, x, zmone); + freduce_coefficients(z); + fcontract(mypublic, z); + return 0; +} diff --git a/src/tor/di_ops.c b/src/tor/di_ops.c new file mode 100644 index 0000000..eeb7a16 --- /dev/null +++ b/src/tor/di_ops.c @@ -0,0 +1,222 @@ +/* Copyright (c) 2011-2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file di_ops.c + * \brief Functions for data-independent operations. + **/ + +#include "orconfig.h" +#include "di_ops.h" +#include "torlog.h" +#include "tor_util.h" + +/** + * Timing-safe version of memcmp. As memcmp, compare the sz bytes at + * a with the sz bytes at b, and return less than 0 if + * the bytes at a lexically precede those at b, 0 if the byte + * ranges are equal, and greater than zero if the bytes at a lexically + * follow those at b. + * + * This implementation differs from memcmp in that its timing behavior is not + * data-dependent: it should return in the same amount of time regardless of + * the contents of a and b. + */ +int +tor_memcmp(const void *a, const void *b, size_t len) +{ + const uint8_t *x = a; + const uint8_t *y = b; + size_t i = len; + int retval = 0; + + /* This loop goes from the end of the arrays to the start. At the + * start of every iteration, before we decrement i, we have set + * "retval" equal to the result of memcmp(a+i,b+i,len-i). During the + * loop, we update retval by leaving it unchanged if x[i]==y[i] and + * setting it to x[i]-y[i] if x[i]!= y[i]. + * + * The following assumes we are on a system with two's-complement + * arithmetic. We check for this at configure-time with the check + * that sets USING_TWOS_COMPLEMENT. If we aren't two's complement, then + * torint.h will stop compilation with an error. + */ + while (i--) { + int v1 = x[i]; + int v2 = y[i]; + int equal_p = v1 ^ v2; + + /* The following sets bits 8 and above of equal_p to 'equal_p == + * 0', and thus to v1 == v2. (To see this, note that if v1 == + * v2, then v1^v2 == equal_p == 0, so equal_p-1 == -1, which is the + * same as ~0 on a two's-complement machine. Then note that if + * v1 != v2, then 0 < v1 ^ v2 < 256, so 0 <= equal_p - 1 < 255.) + */ + --equal_p; + + equal_p >>= 8; + /* Thanks to (sign-preserving) arithmetic shift, equal_p is now + * equal to -(v1 == v2), which is exactly what we need below. + * (Since we're assuming two's-complement arithmetic, -1 is the + * same as ~0 (all bits set).) + * + * (The result of an arithmetic shift on a negative value is + * actually implementation-defined in standard C. So how do we + * get away with assuming it? Easy. We check.) */ +#if ((-60 >> 8) != -1) +#error "According to cpp, right-shift doesn't perform sign-extension." +#endif +#ifndef RSHIFT_DOES_SIGN_EXTEND +#error "According to configure, right-shift doesn't perform sign-extension." +#endif + + /* If v1 == v2, equal_p is ~0, so this will leave retval + * unchanged; otherwise, equal_p is 0, so this will zero it. */ + retval &= equal_p; + + /* If v1 == v2, then this adds 0, and leaves retval unchanged. + * Otherwise, we just zeroed retval, so this sets it to v1 - v2. */ + retval += (v1 - v2); + + /* There. Now retval is equal to its previous value if v1 == v2, and + * equal to v1 - v2 if v1 != v2. */ + } + + return retval; +} + +/** + * Timing-safe memory comparison. Return true if the sz bytes at + * a are the same as the sz bytes at b, and 0 otherwise. + * + * This implementation differs from !memcmp(a,b,sz) in that its timing + * behavior is not data-dependent: it should return in the same amount of time + * regardless of the contents of a and b. It differs from + * !tor_memcmp(a,b,sz) by being faster. + */ +int +tor_memeq(const void *a, const void *b, size_t sz) +{ + /* Treat a and b as byte ranges. */ + const uint8_t *ba = a, *bb = b; + uint32_t any_difference = 0; + while (sz--) { + /* Set byte_diff to all of those bits that are different in *ba and *bb, + * and advance both ba and bb. */ + const uint8_t byte_diff = *ba++ ^ *bb++; + + /* Set bits in any_difference if they are set in byte_diff. */ + any_difference |= byte_diff; + } + + /* Now any_difference is 0 if there are no bits different between + * a and b, and is nonzero if there are bits different between a + * and b. Now for paranoia's sake, let's convert it to 0 or 1. + * + * (If we say "!any_difference", the compiler might get smart enough + * to optimize-out our data-independence stuff above.) + * + * To unpack: + * + * If any_difference == 0: + * any_difference - 1 == ~0 + * (any_difference - 1) >> 8 == 0x00ffffff + * 1 & ((any_difference - 1) >> 8) == 1 + * + * If any_difference != 0: + * 0 < any_difference < 256, so + * 0 <= any_difference - 1 < 255 + * (any_difference - 1) >> 8 == 0 + * 1 & ((any_difference - 1) >> 8) == 0 + */ + + return 1 & ((any_difference - 1) >> 8); +} + +/* Implement di_digest256_map_t as a linked list of entries. */ +struct di_digest256_map_t { + struct di_digest256_map_t *next; + uint8_t key[32]; + void *val; +}; + +/** Release all storage held in map, calling free_fn on each value + * as we go. */ +void +dimap_free(di_digest256_map_t *map, dimap_free_fn free_fn) +{ + while (map) { + di_digest256_map_t *victim = map; + map = map->next; + if (free_fn) + free_fn(victim->val); + tor_free(victim); + } +} + +/** Adjust the map at *map, adding an entry for key -> + * val, where key is a DIGEST256_LEN-byte key. + * + * The caller MUST NOT add a key that already appears in the map. + */ +void +dimap_add_entry(di_digest256_map_t **map, + const uint8_t *key, void *val) +{ + di_digest256_map_t *new_ent; + { + void *old_val = dimap_search(*map, key, NULL); + tor_assert(! old_val); + tor_assert(val); + } + new_ent = tor_malloc_zero(sizeof(di_digest256_map_t)); + new_ent->next = *map; + memcpy(new_ent->key, key, 32); + new_ent->val = val; + *map = new_ent; +} + +/** Search the map at map for an entry whose key is key (a + * DIGEST256_LEN-byte key) returning the corresponding value if we found one, + * and returning dflt_val if the key wasn't found. + * + * This operation takes an amount of time dependent only on the length of + * map, not on the position or presence of key within map. + */ +void * +dimap_search(const di_digest256_map_t *map, const uint8_t *key, + void *dflt_val) +{ + uintptr_t result = (uintptr_t)dflt_val; + + while (map) { + uintptr_t r = (uintptr_t) tor_memeq(map->key, key, 32); + r -= 1; /* Now r is (uintptr_t)-1 if memeq returned false, and + * 0 if memeq returned true. */ + + result &= r; + result |= ((uintptr_t)(map->val)) & ~r; + + map = map->next; + } + + return (void *)result; +} + +/** + * Return true iff the sz bytes at mem are all zero. Runs in + * time independent of the contents of mem. + */ +int +safe_mem_is_zero(const void *mem, size_t sz) +{ + uint32_t total = 0; + const uint8_t *ptr = mem; + + while (sz--) { + total |= *ptr++; + } + + return 1 & ((total - 1) >> 8); +} + diff --git a/src/tor/di_ops.h b/src/tor/di_ops.h new file mode 100644 index 0000000..d93534b --- /dev/null +++ b/src/tor/di_ops.h @@ -0,0 +1,47 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file di_ops.h + * \brief Headers for di_ops.c + **/ + +#ifndef TOR_DI_OPS_H +#define TOR_DI_OPS_H + +#include "orconfig.h" +#include "torint.h" + +int tor_memcmp(const void *a, const void *b, size_t sz); +int tor_memeq(const void *a, const void *b, size_t sz); +#define tor_memneq(a,b,sz) (!tor_memeq((a),(b),(sz))) + +/** Alias for the platform's memcmp() function. This function is + * not data-independent: we define this alias so that we can + * mark cases where we are deliberately using a data-dependent memcmp() + * implementation. + */ +#define fast_memcmp(a,b,c) (memcmp((a),(b),(c))) +#define fast_memeq(a,b,c) (0==memcmp((a),(b),(c))) +#define fast_memneq(a,b,c) (0!=memcmp((a),(b),(c))) + +int safe_mem_is_zero(const void *mem, size_t sz); + +/** A type for a map from DIGEST256_LEN-byte blobs to void*, such that + * data lookups take an amount of time proportional only to the size + * of the map, and not to the position or presence of the item in the map. + * + * Not efficient for large maps! */ +typedef struct di_digest256_map_t di_digest256_map_t; +typedef void (*dimap_free_fn)(void *); + +void dimap_free(di_digest256_map_t *map, dimap_free_fn free_fn); +void dimap_add_entry(di_digest256_map_t **map, + const uint8_t *key, void *val); +void *dimap_search(const di_digest256_map_t *map, const uint8_t *key, + void *dflt_val); + +#endif + diff --git a/src/tor/directory.c b/src/tor/directory.c new file mode 100644 index 0000000..4c4fd7b --- /dev/null +++ b/src/tor/directory.c @@ -0,0 +1,3894 @@ +/* Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#include "or.h" +#include "buffers.h" +#include "circuitbuild.h" +#include "config.h" +#include "connection.h" +#include "connection_edge.h" +#include "control.h" +#include "directory.h" +#include "dirserv.h" +#include "dirvote.h" +#include "entrynodes.h" +#include "geoip.h" +#include "onion_main.h" +#include "microdesc.h" +#include "networkstatus.h" +#include "nodelist.h" +#include "policies.h" +#include "rendclient.h" +#include "rendcommon.h" +#include "rephist.h" +#include "router.h" +#include "routerlist.h" +#include "routerparse.h" +#include "routerset.h" + +#if defined(EXPORTMALLINFO) && defined(HAVE_MALLOC_H) && defined(HAVE_MALLINFO) +#ifndef OPENBSD +#include +#endif +#endif + +/** + * \file directory.c + * \brief Code to send and fetch directories and router + * descriptors via HTTP. Directories use dirserv.c to generate the + * results; clients use routers.c to parse them. + **/ + +/* In-points to directory.c: + * + * - directory_post_to_dirservers(), called from + * router_upload_dir_desc_to_dirservers() in router.c + * upload_service_descriptor() in rendservice.c + * - directory_get_from_dirserver(), called from + * rend_client_refetch_renddesc() in rendclient.c + * run_scheduled_events() in onion_main.c + * do_hup() in onion_main.c + * - connection_dir_process_inbuf(), called from + * connection_process_inbuf() in connection.c + * - connection_dir_finished_flushing(), called from + * connection_finished_flushing() in connection.c + * - connection_dir_finished_connecting(), called from + * connection_finished_connecting() in connection.c + */ +static void directory_send_command(dir_connection_t *conn, + int purpose, int direct, const char *resource, + const char *payload, size_t payload_len, + time_t if_modified_since); +static int directory_handle_command(dir_connection_t *conn); +static int body_is_plausible(const char *body, size_t body_len, int purpose); +static int purpose_needs_anonymity(uint8_t dir_purpose, + uint8_t router_purpose); +static char *http_get_header(const char *headers, const char *which); +static void http_set_address_origin(const char *headers, connection_t *conn); +static void connection_dir_download_routerdesc_failed(dir_connection_t *conn); +static void connection_dir_bridge_routerdesc_failed(dir_connection_t *conn); +static void connection_dir_download_cert_failed( + dir_connection_t *conn, int status_code); +static void connection_dir_retry_bridges(smartlist_t *descs); +static void dir_routerdesc_download_failed(smartlist_t *failed, + int status_code, + int router_purpose, + int was_extrainfo, + int was_descriptor_digests); +static void dir_microdesc_download_failed(smartlist_t *failed, + int status_code); +static void note_client_request(int purpose, int compressed, size_t bytes); +static int client_likes_consensus(networkstatus_t *v, const char *want_url); + +static void directory_initiate_command_rend(const char *address, + const tor_addr_t *addr, + uint16_t or_port, + uint16_t dir_port, + const char *digest, + uint8_t dir_purpose, + uint8_t router_purpose, + dir_indirection_t indirection, + const char *resource, + const char *payload, + size_t payload_len, + time_t if_modified_since, + const rend_data_t *rend_query); + +/********* START VARIABLES **********/ + +/** How far in the future do we allow a directory server to tell us it is + * before deciding that one of us has the wrong time? */ +#define ALLOW_DIRECTORY_TIME_SKEW (30*60) + +#define X_ADDRESS_HEADER "X-Your-Address-Is: " + +/** HTTP cache control: how long do we tell proxies they can cache each + * kind of document we serve? */ +#define FULL_DIR_CACHE_LIFETIME (60*60) +#define RUNNINGROUTERS_CACHE_LIFETIME (20*60) +#define DIRPORTFRONTPAGE_CACHE_LIFETIME (20*60) +#define NETWORKSTATUS_CACHE_LIFETIME (5*60) +#define ROUTERDESC_CACHE_LIFETIME (30*60) +#define ROUTERDESC_BY_DIGEST_CACHE_LIFETIME (48*60*60) +#define ROBOTS_CACHE_LIFETIME (24*60*60) +#define MICRODESC_CACHE_LIFETIME (48*60*60) + +/********* END VARIABLES ************/ + +/** Return true iff the directory purpose dir_purpose (and if it's + * fetching descriptors, it's fetching them for router_purpose) + * must use an anonymous connection to a directory. */ +static int +purpose_needs_anonymity(uint8_t dir_purpose, uint8_t router_purpose) +{ + if (get_options()->AllDirActionsPrivate) + return 1; + if (router_purpose == ROUTER_PURPOSE_BRIDGE) + return 1; /* if no circuits yet, this might break bootstrapping, but it's + * needed to be safe. */ + if (dir_purpose == DIR_PURPOSE_UPLOAD_DIR || + dir_purpose == DIR_PURPOSE_UPLOAD_VOTE || + dir_purpose == DIR_PURPOSE_UPLOAD_SIGNATURES || + dir_purpose == DIR_PURPOSE_FETCH_STATUS_VOTE || + dir_purpose == DIR_PURPOSE_FETCH_DETACHED_SIGNATURES || + dir_purpose == DIR_PURPOSE_FETCH_CONSENSUS || + dir_purpose == DIR_PURPOSE_FETCH_CERTIFICATE || + dir_purpose == DIR_PURPOSE_FETCH_SERVERDESC || + dir_purpose == DIR_PURPOSE_FETCH_EXTRAINFO || + dir_purpose == DIR_PURPOSE_FETCH_MICRODESC) + return 0; + return 1; +} + +/** Return a newly allocated string describing auth. Only describes + * authority features. */ +static char * +authdir_type_to_string(dirinfo_type_t auth) +{ + char *result; + smartlist_t *lst = smartlist_new(); + if (auth & V1_DIRINFO) + smartlist_add(lst, (void*)"V1"); + if (auth & V3_DIRINFO) + smartlist_add(lst, (void*)"V3"); + if (auth & BRIDGE_DIRINFO) + smartlist_add(lst, (void*)"Bridge"); + if (auth & HIDSERV_DIRINFO) + smartlist_add(lst, (void*)"Hidden service"); + if (smartlist_len(lst)) { + result = smartlist_join_strings(lst, ", ", 0, NULL); + } else { + result = tor_strdup("[Not an authority]"); + } + smartlist_free(lst); + return result; +} + +/** Return a string describing a given directory connection purpose. */ +static const char * +dir_conn_purpose_to_string(int purpose) +{ + switch (purpose) + { + case DIR_PURPOSE_FETCH_RENDDESC: + return "hidden-service descriptor fetch"; + case DIR_PURPOSE_UPLOAD_DIR: + return "server descriptor upload"; + case DIR_PURPOSE_UPLOAD_RENDDESC: + return "hidden-service descriptor upload"; + case DIR_PURPOSE_UPLOAD_VOTE: + return "server vote upload"; + case DIR_PURPOSE_UPLOAD_SIGNATURES: + return "consensus signature upload"; + case DIR_PURPOSE_FETCH_SERVERDESC: + return "server descriptor fetch"; + case DIR_PURPOSE_FETCH_EXTRAINFO: + return "extra-info fetch"; + case DIR_PURPOSE_FETCH_CONSENSUS: + return "consensus network-status fetch"; + case DIR_PURPOSE_FETCH_CERTIFICATE: + return "authority cert fetch"; + case DIR_PURPOSE_FETCH_STATUS_VOTE: + return "status vote fetch"; + case DIR_PURPOSE_FETCH_DETACHED_SIGNATURES: + return "consensus signature fetch"; + case DIR_PURPOSE_FETCH_RENDDESC_V2: + return "hidden-service v2 descriptor fetch"; + case DIR_PURPOSE_UPLOAD_RENDDESC_V2: + return "hidden-service v2 descriptor upload"; + case DIR_PURPOSE_FETCH_MICRODESC: + return "microdescriptor fetch"; + } + + log_warn(LD_BUG, "Called with unknown purpose %d", purpose); + return "(unknown)"; +} + +/** Return true iff identity_digest is the digest of a router we + * believe to support extrainfo downloads. (If is_authority we do + * additional checking that's only valid for authorities.) */ +int +router_supports_extrainfo(const char *identity_digest, int is_authority) +{ + const node_t *node = node_get_by_id(identity_digest); + + if (node && node->ri) { + if (node->ri->caches_extra_info) + return 1; + } + if (is_authority) { + return 1; + } + return 0; +} + +/** Return true iff any trusted directory authority has accepted our + * server descriptor. + * + * We consider any authority sufficient because waiting for all of + * them means it never happens while any authority is down; we don't + * go for something more complex in the middle (like \>1/3 or \>1/2 or + * \>=1/2) because that doesn't seem necessary yet. + */ +int +directories_have_accepted_server_descriptor(void) +{ + const smartlist_t *servers = router_get_trusted_dir_servers(); + const or_options_t *options = get_options(); + SMARTLIST_FOREACH(servers, dir_server_t *, d, { + if ((d->type & options->PublishServerDescriptor_) && + d->has_accepted_serverdesc) { + return 1; + } + }); + return 0; +} + +/** Start a connection to every suitable directory authority, using + * connection purpose dir_purpose and uploading payload + * (of length payload_len). The dir_purpose should be one of + * 'DIR_PURPOSE_UPLOAD_DIR' or 'DIR_PURPOSE_UPLOAD_RENDDESC'. + * + * router_purpose describes the type of descriptor we're + * publishing, if we're publishing a descriptor -- e.g. general or bridge. + * + * type specifies what sort of dir authorities (V1, V3, + * HIDSERV, BRIDGE, etc) we should upload to. + * + * If extrainfo_len is nonzero, the first payload_len bytes of + * payload hold a router descriptor, and the next extrainfo_len + * bytes of payload hold an extra-info document. Upload the descriptor + * to all authorities, and the extra-info document to all authorities that + * support it. + */ +void +directory_post_to_dirservers(uint8_t dir_purpose, uint8_t router_purpose, + dirinfo_type_t type, + const char *payload, + size_t payload_len, size_t extrainfo_len) +{ + const or_options_t *options = get_options(); + int post_via_tor; + const smartlist_t *dirservers = router_get_trusted_dir_servers(); + int found = 0; + const int exclude_self = (dir_purpose == DIR_PURPOSE_UPLOAD_VOTE || + dir_purpose == DIR_PURPOSE_UPLOAD_SIGNATURES); + tor_assert(dirservers); + /* This tries dirservers which we believe to be down, but ultimately, that's + * harmless, and we may as well err on the side of getting things uploaded. + */ + SMARTLIST_FOREACH_BEGIN(dirservers, dir_server_t *, ds) { + routerstatus_t *rs = &(ds->fake_status); + size_t upload_len = payload_len; + tor_addr_t ds_addr; + + if ((type & ds->type) == 0) + continue; + + if (exclude_self && router_digest_is_me(ds->digest)) + continue; + + if (options->StrictNodes && + routerset_contains_routerstatus(options->ExcludeNodes, rs, -1)) { + log_warn(LD_DIR, "Wanted to contact authority '%s' for %s, but " + "it's in our ExcludedNodes list and StrictNodes is set. " + "Skipping.", + ds->nickname, + dir_conn_purpose_to_string(dir_purpose)); + continue; + } + + found = 1; /* at least one authority of this type was listed */ + if (dir_purpose == DIR_PURPOSE_UPLOAD_DIR) + ds->has_accepted_serverdesc = 0; + + if (extrainfo_len && router_supports_extrainfo(ds->digest, 1)) { + upload_len += extrainfo_len; + log_info(LD_DIR, "Uploading an extrainfo too (length %d)", + (int) extrainfo_len); + } + tor_addr_from_ipv4h(&ds_addr, ds->addr); + post_via_tor = purpose_needs_anonymity(dir_purpose, router_purpose) || + !fascist_firewall_allows_address_dir(&ds_addr, ds->dir_port); + directory_initiate_command_routerstatus(rs, dir_purpose, + router_purpose, + post_via_tor, + NULL, payload, upload_len, 0); + } SMARTLIST_FOREACH_END(ds); + if (!found) { + char *s = authdir_type_to_string(type); + log_warn(LD_DIR, "Publishing server descriptor to directory authorities " + "of type '%s', but no authorities of that type listed!", s); + tor_free(s); + } +} + +/** Return true iff, according to the values in options, we should be + * using directory guards for direct downloads of directory information. */ +static int +should_use_directory_guards(const or_options_t *options) +{ + /* Public (non-bridge) servers never use directory guards. */ + if (public_server_mode(options)) + return 0; + /* If guards are disabled, or directory guards are disabled, we can't + * use directory guards. + */ + if (!options->UseEntryGuards || !options->UseEntryGuardsAsDirGuards) + return 0; + /* If we're configured to fetch directory info aggressively or of a + * nonstandard type, don't use directory guards. */ + if (options->DownloadExtraInfo || options->FetchDirInfoEarly || + options->FetchDirInfoExtraEarly || options->FetchUselessDescriptors) + return 0; + if (! options->PreferTunneledDirConns) + return 0; + return 1; +} + +/** Pick an unconsetrained directory server from among our guards, the latest + * networkstatus, or the fallback dirservers, for use in downloading + * information of type type, and return its routerstatus. */ +static const routerstatus_t * +directory_pick_generic_dirserver(dirinfo_type_t type, int pds_flags, + uint8_t dir_purpose) +{ + const routerstatus_t *rs = NULL; + const or_options_t *options = get_options(); + + if (options->UseBridges) + log_warn(LD_BUG, "Called when we have UseBridges set."); + + if (should_use_directory_guards(options)) { + const node_t *node = choose_random_dirguard(type); + if (node) + rs = node->rs; + } else { + /* anybody with a non-zero dirport will do */ + rs = router_pick_directory_server(type, pds_flags); + } + if (!rs) { + log_info(LD_DIR, "No router found for %s; falling back to " + "dirserver list.", dir_conn_purpose_to_string(dir_purpose)); + rs = router_pick_fallback_dirserver(type, pds_flags); + } + + return rs; +} + +/** Start a connection to a random running directory server, using + * connection purpose dir_purpose, intending to fetch descriptors + * of purpose router_purpose, and requesting resource. + * Use pds_flags as arguments to router_pick_directory_server() + * or router_pick_trusteddirserver(). + */ +void +directory_get_from_dirserver(uint8_t dir_purpose, uint8_t router_purpose, + const char *resource, int pds_flags) +{ + const routerstatus_t *rs = NULL; + const or_options_t *options = get_options(); + int prefer_authority = directory_fetches_from_authorities(options); + int require_authority = 0; + int get_via_tor = purpose_needs_anonymity(dir_purpose, router_purpose); + dirinfo_type_t type; + time_t if_modified_since = 0; + + /* FFFF we could break this switch into its own function, and call + * it elsewhere in directory.c. -RD */ + switch (dir_purpose) { + case DIR_PURPOSE_FETCH_EXTRAINFO: + type = EXTRAINFO_DIRINFO | + (router_purpose == ROUTER_PURPOSE_BRIDGE ? BRIDGE_DIRINFO : + V3_DIRINFO); + break; + case DIR_PURPOSE_FETCH_SERVERDESC: + type = (router_purpose == ROUTER_PURPOSE_BRIDGE ? BRIDGE_DIRINFO : + V3_DIRINFO); + break; + case DIR_PURPOSE_FETCH_RENDDESC: + type = HIDSERV_DIRINFO; + break; + case DIR_PURPOSE_FETCH_STATUS_VOTE: + case DIR_PURPOSE_FETCH_DETACHED_SIGNATURES: + case DIR_PURPOSE_FETCH_CERTIFICATE: + type = V3_DIRINFO; + break; + case DIR_PURPOSE_FETCH_CONSENSUS: + type = V3_DIRINFO; + if (resource && !strcmp(resource,"microdesc")) + type |= MICRODESC_DIRINFO; + break; + case DIR_PURPOSE_FETCH_MICRODESC: + type = MICRODESC_DIRINFO; + break; + default: + log_warn(LD_BUG, "Unexpected purpose %d", (int)dir_purpose); + return; + } + + if (dir_purpose == DIR_PURPOSE_FETCH_CONSENSUS) { + int flav = FLAV_NS; + networkstatus_t *v; + if (resource) + flav = networkstatus_parse_flavor_name(resource); + + if (flav != -1) { + /* IF we have a parsed consensus of this type, we can do an + * if-modified-time based on it. */ + v = networkstatus_get_latest_consensus_by_flavor(flav); + if (v) + if_modified_since = v->valid_after + 180; + } else { + /* Otherwise it might be a consensus we don't parse, but which we + * do cache. Look at the cached copy, perhaps. */ + cached_dir_t *cd = dirserv_get_consensus(resource); + if (cd) + if_modified_since = cd->published + 180; + } + } + + if (!options->FetchServerDescriptors && type != HIDSERV_DIRINFO) + return; + + if (!get_via_tor) { + if (options->UseBridges && type != BRIDGE_DIRINFO) { + /* We want to ask a running bridge for which we have a descriptor. + * + * When we ask choose_random_entry() for a bridge, we specify what + * sort of dir fetch we'll be doing, so it won't return a bridge + * that can't answer our question. + */ + /* XXX024 Not all bridges handle conditional consensus downloading, + * so, for now, never assume the server supports that. -PP */ + const node_t *node = choose_random_dirguard(type); + if (node && node->ri) { + /* every bridge has a routerinfo. */ + tor_addr_t addr; + routerinfo_t *ri = node->ri; + node_get_addr(node, &addr); + directory_initiate_command(ri->address, &addr, + ri->or_port, 0/*no dirport*/, + ri->cache_info.identity_digest, + dir_purpose, + router_purpose, + DIRIND_ONEHOP, + resource, NULL, 0, if_modified_since); + } else + log_notice(LD_DIR, "Ignoring directory request, since no bridge " + "nodes are available yet."); + return; + } else { + if (prefer_authority || type == BRIDGE_DIRINFO) { + /* only ask authdirservers, and don't ask myself */ + rs = router_pick_trusteddirserver(type, pds_flags); + if (rs == NULL && (pds_flags & (PDS_NO_EXISTING_SERVERDESC_FETCH| + PDS_NO_EXISTING_MICRODESC_FETCH))) { + /* We don't want to fetch from any authorities that we're currently + * fetching server descriptors from, and we got no match. Did we + * get no match because all the authorities have connections + * fetching server descriptors (in which case we should just + * return,) or because all the authorities are down or on fire or + * unreachable or something (in which case we should go on with + * our fallback code)? */ + pds_flags &= ~(PDS_NO_EXISTING_SERVERDESC_FETCH| + PDS_NO_EXISTING_MICRODESC_FETCH); + rs = router_pick_trusteddirserver(type, pds_flags); + if (rs) { + log_debug(LD_DIR, "Deferring serverdesc fetch: all authorities " + "are in use."); + return; + } + } + if (rs == NULL && require_authority) { + log_info(LD_DIR, "No authorities were available for %s: will try " + "later.", dir_conn_purpose_to_string(dir_purpose)); + return; + } + } + if (!rs && type != BRIDGE_DIRINFO) { + /* */ + rs = directory_pick_generic_dirserver(type, pds_flags, + dir_purpose); + if (!rs) { + /*XXXX024 I'm pretty sure this can never do any good, since + * rs isn't set. */ + get_via_tor = 1; /* last resort: try routing it via Tor */ + } + } + } + } else { /* get_via_tor */ + /* Never use fascistfirewall; we're going via Tor. */ + if (dir_purpose == DIR_PURPOSE_FETCH_RENDDESC) { + /* only ask hidserv authorities, any of them will do */ + pds_flags |= PDS_IGNORE_FASCISTFIREWALL|PDS_ALLOW_SELF; + rs = router_pick_trusteddirserver(HIDSERV_DIRINFO, pds_flags); + } else { + /* anybody with a non-zero dirport will do. Disregard firewalls. */ + pds_flags |= PDS_IGNORE_FASCISTFIREWALL; + rs = router_pick_directory_server(type, pds_flags); + /* If we have any hope of building an indirect conn, we know some router + * descriptors. If (rs==NULL), we can't build circuits anyway, so + * there's no point in falling back to the authorities in this case. */ + } + } + + if (rs) { + const dir_indirection_t indirection = + get_via_tor ? DIRIND_ANONYMOUS : DIRIND_ONEHOP; + directory_initiate_command_routerstatus(rs, dir_purpose, + router_purpose, + indirection, + resource, NULL, 0, + if_modified_since); + } else { + log_notice(LD_DIR, + "While fetching directory info, " + "no running dirservers known. Will try again later. " + "(purpose %d)", dir_purpose); + if (!purpose_needs_anonymity(dir_purpose, router_purpose)) { + /* remember we tried them all and failed. */ + directory_all_unreachable(time(NULL)); + } + } +} + +/** As directory_get_from_dirserver, but initiates a request to every + * directory authority other than ourself. Only for use by authorities when + * searching for missing information while voting. */ +void +directory_get_from_all_authorities(uint8_t dir_purpose, + uint8_t router_purpose, + const char *resource) +{ + tor_assert(dir_purpose == DIR_PURPOSE_FETCH_STATUS_VOTE || + dir_purpose == DIR_PURPOSE_FETCH_DETACHED_SIGNATURES); + + SMARTLIST_FOREACH_BEGIN(router_get_trusted_dir_servers(), + dir_server_t *, ds) { + routerstatus_t *rs; + if (router_digest_is_me(ds->digest)) + continue; + if (!(ds->type & V3_DIRINFO)) + continue; + rs = &ds->fake_status; + directory_initiate_command_routerstatus(rs, dir_purpose, router_purpose, + DIRIND_ONEHOP, resource, NULL, + 0, 0); + } SMARTLIST_FOREACH_END(ds); +} + +/** Return true iff ind requires a multihop circuit. */ +static int +dirind_is_anon(dir_indirection_t ind) +{ + return ind == DIRIND_ANON_DIRPORT || ind == DIRIND_ANONYMOUS; +} + +/** Same as directory_initiate_command_routerstatus(), but accepts + * rendezvous data to fetch a hidden service descriptor. */ +void +directory_initiate_command_routerstatus_rend(const routerstatus_t *status, + uint8_t dir_purpose, + uint8_t router_purpose, + dir_indirection_t indirection, + const char *resource, + const char *payload, + size_t payload_len, + time_t if_modified_since, + const rend_data_t *rend_query) +{ + const or_options_t *options = get_options(); + const node_t *node; + char address_buf[INET_NTOA_BUF_LEN+1]; + struct in_addr in; + const char *address; + tor_addr_t addr; + const int anonymized_connection = dirind_is_anon(indirection); + node = node_get_by_id(status->identity_digest); + + if (!node && anonymized_connection) { + log_info(LD_DIR, "Not sending anonymized request to directory '%s'; we " + "don't have its router descriptor.", + routerstatus_describe(status)); + return; + } else if (node) { + node_get_address_string(node, address_buf, sizeof(address_buf)); + address = address_buf; + } else { + in.s_addr = htonl(status->addr); + tor_inet_ntoa(&in, address_buf, sizeof(address_buf)); + address = address_buf; + } + tor_addr_from_ipv4h(&addr, status->addr); + + if (options->ExcludeNodes && options->StrictNodes && + routerset_contains_routerstatus(options->ExcludeNodes, status, -1)) { + log_warn(LD_DIR, "Wanted to contact directory mirror %s for %s, but " + "it's in our ExcludedNodes list and StrictNodes is set. " + "Skipping. This choice might make your Tor not work.", + routerstatus_describe(status), + dir_conn_purpose_to_string(dir_purpose)); + return; + } + + directory_initiate_command_rend(address, &addr, + status->or_port, status->dir_port, + status->identity_digest, + dir_purpose, router_purpose, + indirection, resource, + payload, payload_len, if_modified_since, + rend_query); +} + +/** Launch a new connection to the directory server status to + * upload or download a server or rendezvous + * descriptor. dir_purpose determines what + * kind of directory connection we're launching, and must be one of + * DIR_PURPOSE_{FETCH|UPLOAD}_{DIR|RENDDESC|RENDDESC_V2}. router_purpose + * specifies the descriptor purposes we have in mind (currently only + * used for FETCH_DIR). + * + * When uploading, payload and payload_len determine the content + * of the HTTP post. Otherwise, payload should be NULL. + * + * When fetching a rendezvous descriptor, resource is the service ID we + * want to fetch. + */ +void +directory_initiate_command_routerstatus(const routerstatus_t *status, + uint8_t dir_purpose, + uint8_t router_purpose, + dir_indirection_t indirection, + const char *resource, + const char *payload, + size_t payload_len, + time_t if_modified_since) +{ + directory_initiate_command_routerstatus_rend(status, dir_purpose, + router_purpose, + indirection, resource, + payload, payload_len, + if_modified_since, NULL); +} + +/** Return true iff conn is the client side of a directory connection + * we launched to ourself in order to determine the reachability of our + * dir_port. */ +static int +directory_conn_is_self_reachability_test(dir_connection_t *conn) +{ + if (conn->requested_resource && + !strcmpstart(conn->requested_resource,"authority")) { + const routerinfo_t *me = router_get_my_routerinfo(); + if (me && + router_digest_is_me(conn->identity_digest) && + tor_addr_eq_ipv4h(&conn->base_.addr, me->addr) && /*XXXX prop 118*/ + me->dir_port == conn->base_.port) + return 1; + } + return 0; +} + +/** Called when we are unable to complete the client's request to a directory + * server due to a network error: Mark the router as down and try again if + * possible. + */ +static void +connection_dir_request_failed(dir_connection_t *conn) +{ + if (directory_conn_is_self_reachability_test(conn)) { + return; /* this was a test fetch. don't retry. */ + } + if (!entry_list_is_constrained(get_options())) + router_set_status(conn->identity_digest, 0); /* don't try him again */ + if (conn->base_.purpose == DIR_PURPOSE_FETCH_SERVERDESC || + conn->base_.purpose == DIR_PURPOSE_FETCH_EXTRAINFO) { + log_info(LD_DIR, "Giving up on serverdesc/extrainfo fetch from " + "directory server at '%s'; retrying", + conn->base_.address); + if (conn->router_purpose == ROUTER_PURPOSE_BRIDGE) + connection_dir_bridge_routerdesc_failed(conn); + connection_dir_download_routerdesc_failed(conn); + } else if (conn->base_.purpose == DIR_PURPOSE_FETCH_CONSENSUS) { + if (conn->requested_resource) + networkstatus_consensus_download_failed(0, conn->requested_resource); + } else if (conn->base_.purpose == DIR_PURPOSE_FETCH_CERTIFICATE) { + log_info(LD_DIR, "Giving up on certificate fetch from directory server " + "at '%s'; retrying", + conn->base_.address); + connection_dir_download_cert_failed(conn, 0); + } else if (conn->base_.purpose == DIR_PURPOSE_FETCH_DETACHED_SIGNATURES) { + log_info(LD_DIR, "Giving up downloading detached signatures from '%s'", + conn->base_.address); + } else if (conn->base_.purpose == DIR_PURPOSE_FETCH_STATUS_VOTE) { + log_info(LD_DIR, "Giving up downloading votes from '%s'", + conn->base_.address); + } else if (conn->base_.purpose == DIR_PURPOSE_FETCH_MICRODESC) { + log_info(LD_DIR, "Giving up on downloading microdescriptors from " + "directory server at '%s'; will retry", conn->base_.address); + connection_dir_download_routerdesc_failed(conn); + } +} + +/** Helper: Attempt to fetch directly the descriptors of each bridge + * listed in failed. + */ +static void +connection_dir_retry_bridges(smartlist_t *descs) +{ + char digest[DIGEST_LEN]; + SMARTLIST_FOREACH(descs, const char *, cp, + { + if (base16_decode(digest, DIGEST_LEN, cp, strlen(cp))<0) { + log_warn(LD_BUG, "Malformed fingerprint in list: %s", + escaped(cp)); + continue; + } + retry_bridge_descriptor_fetch_directly(digest); + }); +} + +/** Called when an attempt to download one or more router descriptors + * or extra-info documents on connection conn failed. + */ +static void +connection_dir_download_routerdesc_failed(dir_connection_t *conn) +{ + /* No need to increment the failure count for routerdescs, since + * it's not their fault. */ + + /* No need to relaunch descriptor downloads here: we already do it + * every 10 or 60 seconds (FOO_DESCRIPTOR_RETRY_INTERVAL) in onion_main.c. */ + tor_assert(conn->base_.purpose == DIR_PURPOSE_FETCH_SERVERDESC || + conn->base_.purpose == DIR_PURPOSE_FETCH_EXTRAINFO || + conn->base_.purpose == DIR_PURPOSE_FETCH_MICRODESC); + + (void) conn; +} + +/** Called when an attempt to download a bridge's routerdesc from + * one of the authorities failed due to a network error. If + * possible attempt to download descriptors from the bridge directly. + */ +static void +connection_dir_bridge_routerdesc_failed(dir_connection_t *conn) +{ + smartlist_t *which = NULL; + + /* Requests for bridge descriptors are in the form 'fp/', so ignore + anything else. */ + if (!conn->requested_resource || strcmpstart(conn->requested_resource,"fp/")) + return; + + which = smartlist_new(); + dir_split_resource_into_fingerprints(conn->requested_resource + + strlen("fp/"), + which, NULL, 0); + + tor_assert(conn->base_.purpose != DIR_PURPOSE_FETCH_EXTRAINFO); + if (smartlist_len(which)) { + connection_dir_retry_bridges(which); + SMARTLIST_FOREACH(which, char *, cp, tor_free(cp)); + } + smartlist_free(which); +} + +/** Called when an attempt to fetch a certificate fails. */ +static void +connection_dir_download_cert_failed(dir_connection_t *conn, int status) +{ + const char *fp_pfx = "fp/"; + const char *fpsk_pfx = "fp-sk/"; + smartlist_t *failed; + tor_assert(conn->base_.purpose == DIR_PURPOSE_FETCH_CERTIFICATE); + + if (!conn->requested_resource) + return; + failed = smartlist_new(); + /* + * We have two cases download by fingerprint (resource starts + * with "fp/") or download by fingerprint/signing key pair + * (resource starts with "fp-sk/"). + */ + if (!strcmpstart(conn->requested_resource, fp_pfx)) { + /* Download by fingerprint case */ + dir_split_resource_into_fingerprints(conn->requested_resource + + strlen(fp_pfx), + failed, NULL, DSR_HEX); + SMARTLIST_FOREACH_BEGIN(failed, char *, cp) { + /* Null signing key digest indicates download by fp only */ + authority_cert_dl_failed(cp, NULL, status); + tor_free(cp); + } SMARTLIST_FOREACH_END(cp); + } else if (!strcmpstart(conn->requested_resource, fpsk_pfx)) { + /* Download by (fp,sk) pairs */ + dir_split_resource_into_fingerprint_pairs(conn->requested_resource + + strlen(fpsk_pfx), failed); + SMARTLIST_FOREACH_BEGIN(failed, fp_pair_t *, cp) { + authority_cert_dl_failed(cp->first, cp->second, status); + tor_free(cp); + } SMARTLIST_FOREACH_END(cp); + } else { + log_warn(LD_DIR, + "Don't know what to do with failure for cert fetch %s", + conn->requested_resource); + } + + smartlist_free(failed); + + update_certificate_downloads(time(NULL)); +} + +/** Evaluate the situation and decide if we should use an encrypted + * "begindir-style" connection for this directory request. + * 1) If or_port is 0, or it's a direct conn and or_port is firewalled + * or we're a dir mirror, no. + * 2) If we prefer to avoid begindir conns, and we're not fetching or + * publishing a bridge relay descriptor, no. + * 3) Else yes. + */ +static int +directory_command_should_use_begindir(const or_options_t *options, + const tor_addr_t *addr, + int or_port, uint8_t router_purpose, + dir_indirection_t indirection) +{ + if (!or_port) + return 0; /* We don't know an ORPort -- no chance. */ + if (indirection == DIRIND_DIRECT_CONN || indirection == DIRIND_ANON_DIRPORT) + return 0; + if (indirection == DIRIND_ONEHOP) + if (!fascist_firewall_allows_address_or(addr, or_port) || + directory_fetches_from_authorities(options)) + return 0; /* We're firewalled or are acting like a relay -- also no. */ + if (!options->TunnelDirConns && + router_purpose != ROUTER_PURPOSE_BRIDGE) + return 0; /* We prefer to avoid using begindir conns. Fine. */ + return 1; +} + +/** Helper for directory_initiate_command_routerstatus: send the + * command to a server whose address is address, whose IP is + * addr, whose directory port is dir_port, whose tor version + * supports_begindir, and whose identity key digest is + * digest. */ +void +directory_initiate_command(const char *address, const tor_addr_t *_addr, + uint16_t or_port, uint16_t dir_port, + const char *digest, + uint8_t dir_purpose, uint8_t router_purpose, + dir_indirection_t indirection, const char *resource, + const char *payload, size_t payload_len, + time_t if_modified_since) +{ + directory_initiate_command_rend(address, _addr, or_port, dir_port, + digest, dir_purpose, + router_purpose, indirection, + resource, payload, payload_len, + if_modified_since, NULL); +} + +/** Return non-zero iff a directory connection with purpose + * dir_purpose reveals sensitive information about a Tor + * instance's client activities. (Such connections must be performed + * through normal three-hop Tor circuits.) */ +static int +is_sensitive_dir_purpose(uint8_t dir_purpose) +{ + return ((dir_purpose == DIR_PURPOSE_FETCH_RENDDESC) || + (dir_purpose == DIR_PURPOSE_HAS_FETCHED_RENDDESC) || + (dir_purpose == DIR_PURPOSE_UPLOAD_RENDDESC) || + (dir_purpose == DIR_PURPOSE_UPLOAD_RENDDESC_V2) || + (dir_purpose == DIR_PURPOSE_FETCH_RENDDESC_V2)); +} + +/** Same as directory_initiate_command(), but accepts rendezvous data to + * fetch a hidden service descriptor. */ +static void +directory_initiate_command_rend(const char *address, const tor_addr_t *_addr, + uint16_t or_port, uint16_t dir_port, + const char *digest, + uint8_t dir_purpose, uint8_t router_purpose, + dir_indirection_t indirection, + const char *resource, + const char *payload, size_t payload_len, + time_t if_modified_since, + const rend_data_t *rend_query) +{ + dir_connection_t *conn; + const or_options_t *options = get_options(); + int socket_error = 0; + int use_begindir = directory_command_should_use_begindir(options, _addr, + or_port, router_purpose, indirection); + const int anonymized_connection = dirind_is_anon(indirection); + tor_addr_t addr; + + tor_assert(address); + tor_assert(_addr); + tor_assert(or_port || dir_port); + tor_assert(digest); + + tor_addr_copy(&addr, _addr); + + log_debug(LD_DIR, "anonymized %d, use_begindir %d.", + anonymized_connection, use_begindir); + + log_debug(LD_DIR, "Initiating %s", dir_conn_purpose_to_string(dir_purpose)); + +#ifndef NON_ANONYMOUS_MODE_ENABLED + tor_assert(!(is_sensitive_dir_purpose(dir_purpose) && + !anonymized_connection)); +#else + (void)is_sensitive_dir_purpose; +#endif + + /* ensure that we don't make direct connections when a SOCKS server is + * configured. */ + if (!anonymized_connection && !use_begindir && !options->HTTPProxy && + (options->Socks4Proxy || options->Socks5Proxy)) { + log_warn(LD_DIR, "Cannot connect to a directory server through a " + "SOCKS proxy!"); + return; + } + + conn = dir_connection_new(tor_addr_family(&addr)); + + /* set up conn so it's got all the data we need to remember */ + tor_addr_copy(&conn->base_.addr, &addr); + conn->base_.port = use_begindir ? or_port : dir_port; + conn->base_.address = tor_strdup(address); + memcpy(conn->identity_digest, digest, DIGEST_LEN); + + conn->base_.purpose = dir_purpose; + conn->router_purpose = router_purpose; + + /* give it an initial state */ + conn->base_.state = DIR_CONN_STATE_CONNECTING; + + /* decide whether we can learn our IP address from this conn */ + /* XXXX This is a bad name for this field now. */ + conn->dirconn_direct = !anonymized_connection; + + /* copy rendezvous data, if any */ + if (rend_query) + conn->rend_data = rend_data_dup(rend_query); + + if (!anonymized_connection && !use_begindir) { + /* then we want to connect to dirport directly */ + + if (options->HTTPProxy) { + tor_addr_copy(&addr, &options->HTTPProxyAddr); + dir_port = options->HTTPProxyPort; + } + + switch (connection_connect(TO_CONN(conn), conn->base_.address, &addr, + dir_port, &socket_error)) { + case -1: + connection_dir_request_failed(conn); /* retry if we want */ + /* XXX we only pass 'conn' above, not 'resource', 'payload', + * etc. So in many situations it can't retry! -RD */ + connection_free(TO_CONN(conn)); + return; + case 1: + /* start flushing conn */ + conn->base_.state = DIR_CONN_STATE_CLIENT_SENDING; + /* fall through */ + case 0: + /* queue the command on the outbuf */ + directory_send_command(conn, dir_purpose, 1, resource, + payload, payload_len, + if_modified_since); + connection_watch_events(TO_CONN(conn), READ_EVENT | WRITE_EVENT); + /* writable indicates finish, readable indicates broken link, + error indicates broken link in windowsland. */ + } + } else { /* we want to connect via a tor connection */ + entry_connection_t *linked_conn; + /* Anonymized tunneled connections can never share a circuit. + * One-hop directory connections can share circuits with each other + * but nothing else. */ + int iso_flags = anonymized_connection ? ISO_STREAM : ISO_SESSIONGRP; + + /* If it's an anonymized connection, remember the fact that we + * wanted it for later: maybe we'll want it again soon. */ + if (anonymized_connection && use_begindir) + rep_hist_note_used_internal(time(NULL), 0, 1); + else if (anonymized_connection && !use_begindir) + rep_hist_note_used_port(time(NULL), conn->base_.port); + + /* make an AP connection + * populate it and add it at the right state + * hook up both sides + */ + linked_conn = + connection_ap_make_link(TO_CONN(conn), + conn->base_.address, conn->base_.port, + digest, + SESSION_GROUP_DIRCONN, iso_flags, + use_begindir, conn->dirconn_direct); + if (!linked_conn) { + log_warn(LD_NET,"Making tunnel to dirserver failed."); + connection_mark_for_close(TO_CONN(conn)); + return; + } + + if (connection_add(TO_CONN(conn)) < 0) { + log_warn(LD_NET,"Unable to add connection for link to dirserver."); + connection_mark_for_close(TO_CONN(conn)); + return; + } + conn->base_.state = DIR_CONN_STATE_CLIENT_SENDING; + /* queue the command on the outbuf */ + directory_send_command(conn, dir_purpose, 0, resource, + payload, payload_len, + if_modified_since); + + connection_watch_events(TO_CONN(conn), READ_EVENT|WRITE_EVENT); + IF_HAS_BUFFEREVENT(ENTRY_TO_CONN(linked_conn), { + connection_watch_events(ENTRY_TO_CONN(linked_conn), + READ_EVENT|WRITE_EVENT); + }) ELSE_IF_NO_BUFFEREVENT + connection_start_reading(ENTRY_TO_CONN(linked_conn)); + } +} + +/** Return true iff anything we say on conn is being encrypted before + * we send it to the client/server. */ +int +connection_dir_is_encrypted(dir_connection_t *conn) +{ + /* Right now it's sufficient to see if conn is or has been linked, since + * the only thing it could be linked to is an edge connection on a + * circuit, and the only way it could have been unlinked is at the edge + * connection getting closed. + */ + return TO_CONN(conn)->linked; +} + +/** Helper for sorting + * + * sort strings alphabetically + */ +static int +compare_strs_(const void **a, const void **b) +{ + const char *s1 = *a, *s2 = *b; + return strcmp(s1, s2); +} + +#define CONDITIONAL_CONSENSUS_FPR_LEN 3 +#if (CONDITIONAL_CONSENSUS_FPR_LEN > DIGEST_LEN) +#error "conditional consensus fingerprint length is larger than digest length" +#endif + +/** Return the URL we should use for a consensus download. + * + * This url depends on whether or not the server we go to + * is sufficiently new to support conditional consensus downloading, + * i.e. GET .../consensus/fpr+fpr+fpr + * + * If 'resource' is provided, it is the name of a consensus flavor to request. + */ +static char * +directory_get_consensus_url(const char *resource) +{ + char *url = NULL; + const char *hyphen, *flavor; + if (resource==NULL || strcmp(resource, "ns")==0) { + flavor = ""; /* Request ns consensuses as "", so older servers will work*/ + hyphen = ""; + } else { + flavor = resource; + hyphen = "-"; + } + + { + char *authority_id_list; + smartlist_t *authority_digests = smartlist_new(); + + SMARTLIST_FOREACH_BEGIN(router_get_trusted_dir_servers(), + dir_server_t *, ds) { + char *hex; + if (!(ds->type & V3_DIRINFO)) + continue; + + hex = tor_malloc(2*CONDITIONAL_CONSENSUS_FPR_LEN+1); + base16_encode(hex, 2*CONDITIONAL_CONSENSUS_FPR_LEN+1, + ds->v3_identity_digest, CONDITIONAL_CONSENSUS_FPR_LEN); + smartlist_add(authority_digests, hex); + } SMARTLIST_FOREACH_END(ds); + smartlist_sort(authority_digests, compare_strs_); + authority_id_list = smartlist_join_strings(authority_digests, + "+", 0, NULL); + + tor_asprintf(&url, "/tor/status-vote/current/consensus%s%s/%s.z", + hyphen, flavor, authority_id_list); + + SMARTLIST_FOREACH(authority_digests, char *, cp, tor_free(cp)); + smartlist_free(authority_digests); + tor_free(authority_id_list); + } + return url; +} + +/** Queue an appropriate HTTP command on conn-\>outbuf. The other args + * are as in directory_initiate_command(). + */ +static void +directory_send_command(dir_connection_t *conn, + int purpose, int direct, const char *resource, + const char *payload, size_t payload_len, + time_t if_modified_since) +{ + char proxystring[256]; + char hoststring[128]; + smartlist_t *headers = smartlist_new(); + char *url; + char request[8192]; + const char *httpcommand = NULL; + + tor_assert(conn); + tor_assert(conn->base_.type == CONN_TYPE_DIR); + + tor_free(conn->requested_resource); + if (resource) + conn->requested_resource = tor_strdup(resource); + + /* come up with a string for which Host: we want */ + if (conn->base_.port == 80) { + strlcpy(hoststring, conn->base_.address, sizeof(hoststring)); + } else { + tor_snprintf(hoststring, sizeof(hoststring),"%s:%d", + conn->base_.address, conn->base_.port); + } + + /* Format if-modified-since */ + if (if_modified_since) { + char b[RFC1123_TIME_LEN+1]; + format_rfc1123_time(b, if_modified_since); + smartlist_add_asprintf(headers, "If-Modified-Since: %s\r\n", b); + } + + /* come up with some proxy lines, if we're using one. */ + if (direct && get_options()->HTTPProxy) { + char *base64_authenticator=NULL; + const char *authenticator = get_options()->HTTPProxyAuthenticator; + + tor_snprintf(proxystring, sizeof(proxystring),"http://%s", hoststring); + if (authenticator) { + base64_authenticator = alloc_http_authenticator(authenticator); + if (!base64_authenticator) + log_warn(LD_BUG, "Encoding http authenticator failed"); + } + if (base64_authenticator) { + smartlist_add_asprintf(headers, + "Proxy-Authorization: Basic %s\r\n", + base64_authenticator); + tor_free(base64_authenticator); + } + } else { + proxystring[0] = 0; + } + + switch (purpose) { + case DIR_PURPOSE_FETCH_CONSENSUS: + /* resource is optional. If present, it's a flavor name */ + tor_assert(!payload); + httpcommand = "GET"; + url = directory_get_consensus_url(resource); + log_info(LD_DIR, "Downloading consensus from %s using %s", + hoststring, url); + break; + case DIR_PURPOSE_FETCH_CERTIFICATE: + tor_assert(resource); + tor_assert(!payload); + httpcommand = "GET"; + tor_asprintf(&url, "/tor/keys/%s", resource); + break; + case DIR_PURPOSE_FETCH_STATUS_VOTE: + tor_assert(resource); + tor_assert(!payload); + httpcommand = "GET"; + tor_asprintf(&url, "/tor/status-vote/next/%s.z", resource); + break; + case DIR_PURPOSE_FETCH_DETACHED_SIGNATURES: + tor_assert(!resource); + tor_assert(!payload); + httpcommand = "GET"; + url = tor_strdup("/tor/status-vote/next/consensus-signatures.z"); + break; + case DIR_PURPOSE_FETCH_SERVERDESC: + tor_assert(resource); + httpcommand = "GET"; + tor_asprintf(&url, "/tor/server/%s", resource); + break; + case DIR_PURPOSE_FETCH_EXTRAINFO: + tor_assert(resource); + httpcommand = "GET"; + tor_asprintf(&url, "/tor/extra/%s", resource); + break; + case DIR_PURPOSE_FETCH_MICRODESC: + tor_assert(resource); + httpcommand = "GET"; + tor_asprintf(&url, "/tor/micro/%s", resource); + break; + case DIR_PURPOSE_UPLOAD_DIR: { + const char *why = router_get_descriptor_gen_reason(); + tor_assert(!resource); + tor_assert(payload); + httpcommand = "POST"; + url = tor_strdup("/tor/"); + if (why) { + smartlist_add_asprintf(headers, "X-Desc-Gen-Reason: %s\r\n", why); + } + break; + } + case DIR_PURPOSE_UPLOAD_VOTE: + tor_assert(!resource); + tor_assert(payload); + httpcommand = "POST"; + url = tor_strdup("/tor/post/vote"); + break; + case DIR_PURPOSE_UPLOAD_SIGNATURES: + tor_assert(!resource); + tor_assert(payload); + httpcommand = "POST"; + url = tor_strdup("/tor/post/consensus-signature"); + break; + case DIR_PURPOSE_FETCH_RENDDESC_V2: + tor_assert(resource); + tor_assert(strlen(resource) <= REND_DESC_ID_V2_LEN_BASE32); + tor_assert(!payload); + httpcommand = "GET"; + tor_asprintf(&url, "/tor/rendezvous2/%s", resource); + break; + case DIR_PURPOSE_UPLOAD_RENDDESC: + tor_assert(!resource); + tor_assert(payload); + httpcommand = "POST"; + url = tor_strdup("/tor/rendezvous/publish"); + break; + case DIR_PURPOSE_UPLOAD_RENDDESC_V2: + tor_assert(!resource); + tor_assert(payload); + httpcommand = "POST"; + url = tor_strdup("/tor/rendezvous2/publish"); + break; + default: + tor_assert(0); + return; + } + + if (strlen(proxystring) + strlen(url) >= 4096) { + log_warn(LD_BUG, + "Squid does not like URLs longer than 4095 bytes, and this " + "one is %d bytes long: %s%s", + (int)(strlen(proxystring) + strlen(url)), proxystring, url); + } + + tor_snprintf(request, sizeof(request), "%s %s", httpcommand, proxystring); + connection_write_to_buf(request, strlen(request), TO_CONN(conn)); + connection_write_to_buf(url, strlen(url), TO_CONN(conn)); + tor_free(url); + + if (!strcmp(httpcommand, "POST") || payload) { + smartlist_add_asprintf(headers, "Content-Length: %lu\r\n", + payload ? (unsigned long)payload_len : 0); + } + + { + char *header = smartlist_join_strings(headers, "", 0, NULL); + tor_snprintf(request, sizeof(request), " HTTP/1.0\r\nHost: %s\r\n%s\r\n", + hoststring, header); + tor_free(header); + } + + connection_write_to_buf(request, strlen(request), TO_CONN(conn)); + + if (payload) { + /* then send the payload afterwards too */ + connection_write_to_buf(payload, payload_len, TO_CONN(conn)); + } + + SMARTLIST_FOREACH(headers, char *, h, tor_free(h)); + smartlist_free(headers); +} + +/** Parse an HTTP request string headers of the form + * \verbatim + * "\%s [http[s]://]\%s HTTP/1..." + * \endverbatim + * If it's well-formed, strdup the second \%s into *url, and + * nul-terminate it. If the url doesn't start with "/tor/", rewrite it + * so it does. Return 0. + * Otherwise, return -1. + */ +STATIC int +parse_http_url(const char *headers, char **url) +{ + char *s, *start, *tmp; + + s = (char *)eat_whitespace_no_nl(headers); + if (!*s) return -1; + s = (char *)find_whitespace(s); /* get past GET/POST */ + if (!*s) return -1; + s = (char *)eat_whitespace_no_nl(s); + if (!*s) return -1; + start = s; /* this is it, assuming it's valid */ + s = (char *)find_whitespace(start); + if (!*s) return -1; + + /* tolerate the http[s] proxy style of putting the hostname in the url */ + if (s-start >= 4 && !strcmpstart(start,"http")) { + tmp = start + 4; + if (*tmp == 's') + tmp++; + if (s-tmp >= 3 && !strcmpstart(tmp,"://")) { + tmp = strchr(tmp+3, '/'); + if (tmp && tmp < s) { + log_debug(LD_DIR,"Skipping over 'http[s]://hostname/' string"); + start = tmp; + } + } + } + + /* Check if the header is well formed (next sequence + * should be HTTP/1.X\r\n). Assumes we're supporting 1.0? */ + { + unsigned minor_ver; + char ch; + char *e = (char *)eat_whitespace_no_nl(s); + if (2 != tor_sscanf(e, "HTTP/1.%u%c", &minor_ver, &ch)) { + return -1; + } + if (ch != '\r') + return -1; + } + + if (s-start < 5 || strcmpstart(start,"/tor/")) { /* need to rewrite it */ + *url = tor_malloc(s - start + 5); + strlcpy(*url,"/tor", s-start+5); + strlcat((*url)+4, start, s-start+1); + } else { + *url = tor_strndup(start, s-start); + } + return 0; +} + +/** Return a copy of the first HTTP header in headers whose key is + * which. The key should be given with a terminating colon and space; + * this function copies everything after, up to but not including the + * following \\r\\n. */ +static char * +http_get_header(const char *headers, const char *which) +{ + const char *cp = headers; + while (cp) { + if (!strcasecmpstart(cp, which)) { + char *eos; + cp += strlen(which); + if ((eos = strchr(cp,'\r'))) + return tor_strndup(cp, eos-cp); + else + return tor_strdup(cp); + } + cp = strchr(cp, '\n'); + if (cp) + ++cp; + } + return NULL; +} + +/** If headers indicates that a proxy was involved, then rewrite + * conn-\>address to describe our best guess of the address that + * originated this HTTP request. */ +static void +http_set_address_origin(const char *headers, connection_t *conn) +{ + char *fwd; + + fwd = http_get_header(headers, "Forwarded-For: "); + if (!fwd) + fwd = http_get_header(headers, "X-Forwarded-For: "); + if (fwd) { + struct in_addr in; + if (!tor_inet_aton(fwd, &in) || is_internal_IP(ntohl(in.s_addr), 0)) { + log_debug(LD_DIR, "Ignoring unrecognized or internal IP %s", + escaped(fwd)); + tor_free(fwd); + return; + } + tor_free(conn->address); + conn->address = tor_strdup(fwd); + tor_free(fwd); + } +} + +/** Parse an HTTP response string headers of the form + * \verbatim + * "HTTP/1.\%d \%d\%s\r\n...". + * \endverbatim + * + * If it's well-formed, assign the status code to *code and + * return 0. Otherwise, return -1. + * + * On success: If date is provided, set *date to the Date + * header in the http headers, or 0 if no such header is found. If + * compression is provided, set *compression to the + * compression method given in the Content-Encoding header, or 0 if no + * such header is found, or -1 if the value of the header is not + * recognized. If reason is provided, strdup the reason string + * into it. + */ +int +parse_http_response(const char *headers, int *code, time_t *date, + compress_method_t *compression, char **reason) +{ + unsigned n1, n2; + char datestr[RFC1123_TIME_LEN+1]; + smartlist_t *parsed_headers; + tor_assert(headers); + tor_assert(code); + + while (TOR_ISSPACE(*headers)) headers++; /* tolerate leading whitespace */ + + if (tor_sscanf(headers, "HTTP/1.%u %u", &n1, &n2) < 2 || + (n1 != 0 && n1 != 1) || + (n2 < 100 || n2 >= 600)) { + log_warn(LD_HTTP,"Failed to parse header %s",escaped(headers)); + return -1; + } + *code = n2; + + parsed_headers = smartlist_new(); + smartlist_split_string(parsed_headers, headers, "\n", + SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, -1); + if (reason) { + smartlist_t *status_line_elements = smartlist_new(); + tor_assert(smartlist_len(parsed_headers)); + smartlist_split_string(status_line_elements, + smartlist_get(parsed_headers, 0), + " ", SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 3); + tor_assert(smartlist_len(status_line_elements) <= 3); + if (smartlist_len(status_line_elements) == 3) { + *reason = smartlist_get(status_line_elements, 2); + smartlist_set(status_line_elements, 2, NULL); /* Prevent free */ + } + SMARTLIST_FOREACH(status_line_elements, char *, cp, tor_free(cp)); + smartlist_free(status_line_elements); + } + if (date) { + *date = 0; + SMARTLIST_FOREACH(parsed_headers, const char *, s, + if (!strcmpstart(s, "Date: ")) { + strlcpy(datestr, s+6, sizeof(datestr)); + /* This will do nothing on failure, so we don't need to check + the result. We shouldn't warn, since there are many other valid + date formats besides the one we use. */ + parse_rfc1123_time(datestr, date); + break; + }); + } + if (compression) { + const char *enc = NULL; + SMARTLIST_FOREACH(parsed_headers, const char *, s, + if (!strcmpstart(s, "Content-Encoding: ")) { + enc = s+18; break; + }); + if (!enc || !strcmp(enc, "identity")) { + *compression = NO_METHOD; + } else if (!strcmp(enc, "deflate") || !strcmp(enc, "x-deflate")) { + *compression = ZLIB_METHOD; + } else if (!strcmp(enc, "gzip") || !strcmp(enc, "x-gzip")) { + *compression = GZIP_METHOD; + } else { + log_info(LD_HTTP, "Unrecognized content encoding: %s. Trying to deal.", + escaped(enc)); + *compression = UNKNOWN_METHOD; + } + } + SMARTLIST_FOREACH(parsed_headers, char *, s, tor_free(s)); + smartlist_free(parsed_headers); + + return 0; +} + +/** Return true iff body doesn't start with a plausible router or + * running-list or directory opening. This is a sign of possible compression. + **/ +static int +body_is_plausible(const char *body, size_t len, int purpose) +{ + int i; + if (len == 0) + return 1; /* empty bodies don't need decompression */ + if (len < 32) + return 0; + if (purpose == DIR_PURPOSE_FETCH_MICRODESC) { + return (!strcmpstart(body,"onion-key")); + } + if (purpose != DIR_PURPOSE_FETCH_RENDDESC) { + if (!strcmpstart(body,"router") || + !strcmpstart(body,"signed-directory") || + !strcmpstart(body,"network-status") || + !strcmpstart(body,"running-routers")) + return 1; + for (i=0;i<32;++i) { + if (!TOR_ISPRINT(body[i]) && !TOR_ISSPACE(body[i])) + return 0; + } + return 1; + } else { + return 1; + } +} + +/** Called when we've just fetched a bunch of router descriptors in + * body. The list which, if present, holds digests for + * descriptors we requested: descriptor digests if descriptor_digests + * is true, or identity digests otherwise. Parse the descriptors, validate + * them, and annotate them as having purpose purpose and as having been + * downloaded from source. + * + * Return the number of routers actually added. */ +static int +load_downloaded_routers(const char *body, smartlist_t *which, + int descriptor_digests, + int router_purpose, + const char *source) +{ + char buf[256]; + char time_buf[ISO_TIME_LEN+1]; + int added = 0; + int general = router_purpose == ROUTER_PURPOSE_GENERAL; + format_iso_time(time_buf, time(NULL)); + tor_assert(source); + + if (tor_snprintf(buf, sizeof(buf), + "@downloaded-at %s\n" + "@source %s\n" + "%s%s%s", time_buf, escaped(source), + !general ? "@purpose " : "", + !general ? router_purpose_to_string(router_purpose) : "", + !general ? "\n" : "")<0) + return added; + + added = router_load_routers_from_string(body, NULL, SAVED_NOWHERE, which, + descriptor_digests, buf); + if (general) + control_event_bootstrap(BOOTSTRAP_STATUS_LOADING_DESCRIPTORS, + count_loading_descriptors_progress()); + return added; +} + +/** We are a client, and we've finished reading the server's + * response. Parse it and act appropriately. + * + * If we're still happy with using this directory server in the future, return + * 0. Otherwise return -1; and the caller should consider trying the request + * again. + * + * The caller will take care of marking the connection for close. + */ +static int +connection_dir_client_reached_eof(dir_connection_t *conn) +{ + char *body; + char *headers; + char *reason = NULL; + size_t body_len = 0, orig_len = 0; + int status_code; + time_t date_header = 0; + long delta; + compress_method_t compression; + int plausible; + int skewed = 0; + int allow_partial = (conn->base_.purpose == DIR_PURPOSE_FETCH_SERVERDESC || + conn->base_.purpose == DIR_PURPOSE_FETCH_EXTRAINFO || + conn->base_.purpose == DIR_PURPOSE_FETCH_MICRODESC); + int was_compressed = 0; + time_t now = time(NULL); + int src_code; + + switch (connection_fetch_from_buf_http(TO_CONN(conn), + &headers, MAX_HEADERS_SIZE, + &body, &body_len, MAX_DIR_DL_SIZE, + allow_partial)) { + case -1: /* overflow */ + log_warn(LD_PROTOCOL, + "'fetch' response too large (server '%s:%d'). Closing.", + conn->base_.address, conn->base_.port); + return -1; + case 0: + log_info(LD_HTTP, + "'fetch' response not all here, but we're at eof. Closing."); + return -1; + /* case 1, fall through */ + } + orig_len = body_len; + + if (parse_http_response(headers, &status_code, &date_header, + &compression, &reason) < 0) { + log_warn(LD_HTTP,"Unparseable headers (server '%s:%d'). Closing.", + conn->base_.address, conn->base_.port); + tor_free(body); tor_free(headers); + return -1; + } + if (!reason) reason = tor_strdup("[no reason given]"); + + log_debug(LD_DIR, + "Received response from directory server '%s:%d': %d %s " + "(purpose: %d)", + conn->base_.address, conn->base_.port, status_code, + escaped(reason), + conn->base_.purpose); + + /* now check if it's got any hints for us about our IP address. */ + if (conn->dirconn_direct) { + char *guess = http_get_header(headers, X_ADDRESS_HEADER); + if (guess) { + router_new_address_suggestion(guess, conn); + tor_free(guess); + } + } + + if (date_header > 0) { + /* The date header was written very soon after we sent our request, + * so compute the skew as the difference between sending the request + * and the date header. (We used to check now-date_header, but that's + * inaccurate if we spend a lot of time downloading.) + */ + delta = conn->base_.timestamp_lastwritten - date_header; + if (labs(delta)>ALLOW_DIRECTORY_TIME_SKEW) { + char dbuf[64]; + int trusted = router_digest_is_trusted_dir(conn->identity_digest); + format_time_interval(dbuf, sizeof(dbuf), delta); + log_fn(trusted ? LOG_WARN : LOG_INFO, + LD_HTTP, + "Received directory with skewed time (server '%s:%d'): " + "It seems that our clock is %s by %s, or that theirs is %s. " + "Tor requires an accurate clock to work: please check your time, " + "timezone, and date settings.", + conn->base_.address, conn->base_.port, + delta>0 ? "ahead" : "behind", dbuf, + delta>0 ? "behind" : "ahead"); + skewed = 1; /* don't check the recommended-versions line */ + if (trusted) + control_event_general_status(LOG_WARN, + "CLOCK_SKEW SKEW=%ld SOURCE=DIRSERV:%s:%d", + delta, conn->base_.address, conn->base_.port); + } else { + log_debug(LD_HTTP, "Time on received directory is within tolerance; " + "we are %ld seconds skewed. (That's okay.)", delta); + } + } + (void) skewed; /* skewed isn't used yet. */ + + if (status_code == 503) { + routerstatus_t *rs; + dir_server_t *ds; + const char *id_digest = conn->identity_digest; + log_info(LD_DIR,"Received http status code %d (%s) from server " + "'%s:%d'. I'll try again soon.", + status_code, escaped(reason), conn->base_.address, + conn->base_.port); + if ((rs = router_get_mutable_consensus_status_by_id(id_digest))) + rs->last_dir_503_at = now; + if ((ds = router_get_fallback_dirserver_by_digest(id_digest))) + ds->fake_status.last_dir_503_at = now; + + tor_free(body); tor_free(headers); tor_free(reason); + return -1; + } + + plausible = body_is_plausible(body, body_len, conn->base_.purpose); + if (compression != NO_METHOD || !plausible) { + char *new_body = NULL; + size_t new_len = 0; + compress_method_t guessed = detect_compression_method(body, body_len); + if (compression == UNKNOWN_METHOD || guessed != compression) { + /* Tell the user if we don't believe what we're told about compression.*/ + const char *description1, *description2; + if (compression == ZLIB_METHOD) + description1 = "as deflated"; + else if (compression == GZIP_METHOD) + description1 = "as gzipped"; + else if (compression == NO_METHOD) + description1 = "as uncompressed"; + else + description1 = "with an unknown Content-Encoding"; + if (guessed == ZLIB_METHOD) + description2 = "deflated"; + else if (guessed == GZIP_METHOD) + description2 = "gzipped"; + else if (!plausible) + description2 = "confusing binary junk"; + else + description2 = "uncompressed"; + + log_info(LD_HTTP, "HTTP body from server '%s:%d' was labeled %s, " + "but it seems to be %s.%s", + conn->base_.address, conn->base_.port, description1, + description2, + (compression>0 && guessed>0)?" Trying both.":""); + } + /* Try declared compression first if we can. */ + if (compression == GZIP_METHOD || compression == ZLIB_METHOD) + tor_gzip_uncompress(&new_body, &new_len, body, body_len, compression, + !allow_partial, LOG_PROTOCOL_WARN); + /* Okay, if that didn't work, and we think that it was compressed + * differently, try that. */ + if (!new_body && + (guessed == GZIP_METHOD || guessed == ZLIB_METHOD) && + compression != guessed) + tor_gzip_uncompress(&new_body, &new_len, body, body_len, guessed, + !allow_partial, LOG_PROTOCOL_WARN); + /* If we're pretty sure that we have a compressed directory, and + * we didn't manage to uncompress it, then warn and bail. */ + if (!plausible && !new_body) { + log_fn(LOG_PROTOCOL_WARN, LD_HTTP, + "Unable to decompress HTTP body (server '%s:%d').", + conn->base_.address, conn->base_.port); + tor_free(body); tor_free(headers); tor_free(reason); + return -1; + } + if (new_body) { + tor_free(body); + body = new_body; + body_len = new_len; + was_compressed = 1; + } + } + + if (conn->base_.purpose == DIR_PURPOSE_FETCH_CONSENSUS) { + int r; + const char *flavname = conn->requested_resource; + if (status_code != 200) { + int severity = (status_code == 304) ? LOG_INFO : LOG_WARN; + tor_log(severity, LD_DIR, + "Received http status code %d (%s) from server " + "'%s:%d' while fetching consensus directory.", + status_code, escaped(reason), conn->base_.address, + conn->base_.port); + tor_free(body); tor_free(headers); tor_free(reason); + networkstatus_consensus_download_failed(status_code, flavname); + return -1; + } + log_info(LD_DIR,"Received consensus directory (size %d) from server " + "'%s:%d'", (int)body_len, conn->base_.address, conn->base_.port); + if ((r=networkstatus_set_current_consensus(body, flavname, 0))<0) { + log_fn(r<-1?LOG_WARN:LOG_INFO, LD_DIR, + "Unable to load %s consensus directory downloaded from " + "server '%s:%d'. I'll try again soon.", + flavname, conn->base_.address, conn->base_.port); + tor_free(body); tor_free(headers); tor_free(reason); + networkstatus_consensus_download_failed(0, flavname); + return -1; + } + /* launches router downloads as needed */ + routers_update_all_from_networkstatus(now, 3); + update_microdescs_from_networkstatus(now); + update_microdesc_downloads(now); + directory_info_has_arrived(now, 0); + log_info(LD_DIR, "Successfully loaded consensus."); + } + + if (conn->base_.purpose == DIR_PURPOSE_FETCH_CERTIFICATE) { + if (status_code != 200) { + log_warn(LD_DIR, + "Received http status code %d (%s) from server " + "'%s:%d' while fetching \"/tor/keys/%s\".", + status_code, escaped(reason), conn->base_.address, + conn->base_.port, conn->requested_resource); + connection_dir_download_cert_failed(conn, status_code); + tor_free(body); tor_free(headers); tor_free(reason); + return -1; + } + log_info(LD_DIR,"Received authority certificates (size %d) from server " + "'%s:%d'", (int)body_len, conn->base_.address, conn->base_.port); + + /* + * Tell trusted_dirs_load_certs_from_string() whether it was by fp + * or fp-sk pair. + */ + src_code = -1; + if (!strcmpstart(conn->requested_resource, "fp/")) { + src_code = TRUSTED_DIRS_CERTS_SRC_DL_BY_ID_DIGEST; + } else if (!strcmpstart(conn->requested_resource, "fp-sk/")) { + src_code = TRUSTED_DIRS_CERTS_SRC_DL_BY_ID_SK_DIGEST; + } + + if (src_code != -1) { + if (trusted_dirs_load_certs_from_string(body, src_code, 1)<0) { + log_warn(LD_DIR, "Unable to parse fetched certificates"); + /* if we fetched more than one and only some failed, the successful + * ones got flushed to disk so it's safe to call this on them */ + connection_dir_download_cert_failed(conn, status_code); + } else { + directory_info_has_arrived(now, 0); + log_info(LD_DIR, "Successfully loaded certificates from fetch."); + } + } else { + log_warn(LD_DIR, + "Couldn't figure out what to do with fetched certificates for " + "unknown resource %s", + conn->requested_resource); + connection_dir_download_cert_failed(conn, status_code); + } + } + if (conn->base_.purpose == DIR_PURPOSE_FETCH_STATUS_VOTE) { + const char *msg; + int st; + log_info(LD_DIR,"Got votes (size %d) from server %s:%d", + (int)body_len, conn->base_.address, conn->base_.port); + if (status_code != 200) { + log_warn(LD_DIR, + "Received http status code %d (%s) from server " + "'%s:%d' while fetching \"/tor/status-vote/next/%s.z\".", + status_code, escaped(reason), conn->base_.address, + conn->base_.port, conn->requested_resource); + tor_free(body); tor_free(headers); tor_free(reason); + return -1; + } + dirvote_add_vote(body, &msg, &st); + if (st > 299) { + log_warn(LD_DIR, "Error adding retrieved vote: %s", msg); + } else { + log_info(LD_DIR, "Added vote(s) successfully [msg: %s]", msg); + } + } + if (conn->base_.purpose == DIR_PURPOSE_FETCH_DETACHED_SIGNATURES) { + const char *msg = NULL; + log_info(LD_DIR,"Got detached signatures (size %d) from server %s:%d", + (int)body_len, conn->base_.address, conn->base_.port); + if (status_code != 200) { + log_warn(LD_DIR, + "Received http status code %d (%s) from server '%s:%d' while fetching " + "\"/tor/status-vote/next/consensus-signatures.z\".", + status_code, escaped(reason), conn->base_.address, + conn->base_.port); + tor_free(body); tor_free(headers); tor_free(reason); + return -1; + } + if (dirvote_add_signatures(body, conn->base_.address, &msg)<0) { + log_warn(LD_DIR, "Problem adding detached signatures from %s:%d: %s", + conn->base_.address, conn->base_.port, msg?msg:"???"); + } + } + + if (conn->base_.purpose == DIR_PURPOSE_FETCH_SERVERDESC || + conn->base_.purpose == DIR_PURPOSE_FETCH_EXTRAINFO) { + int was_ei = conn->base_.purpose == DIR_PURPOSE_FETCH_EXTRAINFO; + smartlist_t *which = NULL; + int n_asked_for = 0; + int descriptor_digests = conn->requested_resource && + !strcmpstart(conn->requested_resource,"d/"); + log_info(LD_DIR,"Received %s (size %d) from server '%s:%d'", + was_ei ? "extra server info" : "server info", + (int)body_len, conn->base_.address, conn->base_.port); + if (conn->requested_resource && + (!strcmpstart(conn->requested_resource,"d/") || + !strcmpstart(conn->requested_resource,"fp/"))) { + which = smartlist_new(); + dir_split_resource_into_fingerprints(conn->requested_resource + + (descriptor_digests ? 2 : 3), + which, NULL, 0); + n_asked_for = smartlist_len(which); + } + if (status_code != 200) { + int dir_okay = status_code == 404 || + (status_code == 400 && !strcmp(reason, "Servers unavailable.")); + /* 404 means that it didn't have them; no big deal. + * Older (pre-0.1.1.8) servers said 400 Servers unavailable instead. */ + log_fn(dir_okay ? LOG_INFO : LOG_WARN, LD_DIR, + "Received http status code %d (%s) from server '%s:%d' " + "while fetching \"/tor/server/%s\". I'll try again soon.", + status_code, escaped(reason), conn->base_.address, + conn->base_.port, conn->requested_resource); + if (!which) { + connection_dir_download_routerdesc_failed(conn); + } else { + dir_routerdesc_download_failed(which, status_code, + conn->router_purpose, + was_ei, descriptor_digests); + SMARTLIST_FOREACH(which, char *, cp, tor_free(cp)); + smartlist_free(which); + } + tor_free(body); tor_free(headers); tor_free(reason); + return dir_okay ? 0 : -1; + } + /* Learn the routers, assuming we requested by fingerprint or "all" + * or "authority". + * + * We use "authority" to fetch our own descriptor for + * testing, and to fetch bridge descriptors for bootstrapping. Ignore + * the output of "authority" requests unless we are using bridges, + * since otherwise they'll be the response from reachability tests, + * and we don't really want to add that to our routerlist. */ + if (which || (conn->requested_resource && + (!strcmpstart(conn->requested_resource, "all") || + (!strcmpstart(conn->requested_resource, "authority") && + get_options()->UseBridges)))) { + /* as we learn from them, we remove them from 'which' */ + if (was_ei) { + router_load_extrainfo_from_string(body, NULL, SAVED_NOWHERE, which, + descriptor_digests); + } else { + //router_load_routers_from_string(body, NULL, SAVED_NOWHERE, which, + // descriptor_digests, conn->router_purpose); + if (load_downloaded_routers(body, which, descriptor_digests, + conn->router_purpose, + conn->base_.address)) + directory_info_has_arrived(now, 0); + } + } + if (which) { /* mark remaining ones as failed */ + log_info(LD_DIR, "Received %d/%d %s requested from %s:%d", + n_asked_for-smartlist_len(which), n_asked_for, + was_ei ? "extra-info documents" : "router descriptors", + conn->base_.address, (int)conn->base_.port); + if (smartlist_len(which)) { + dir_routerdesc_download_failed(which, status_code, + conn->router_purpose, + was_ei, descriptor_digests); + } + SMARTLIST_FOREACH(which, char *, cp, tor_free(cp)); + smartlist_free(which); + } + if (directory_conn_is_self_reachability_test(conn)) + router_dirport_found_reachable(); + } + if (conn->base_.purpose == DIR_PURPOSE_FETCH_MICRODESC) { + smartlist_t *which = NULL; + log_info(LD_DIR,"Received answer to microdescriptor request (status %d, " + "size %d) from server '%s:%d'", + status_code, (int)body_len, conn->base_.address, + conn->base_.port); + tor_assert(conn->requested_resource && + !strcmpstart(conn->requested_resource, "d/")); + which = smartlist_new(); + dir_split_resource_into_fingerprints(conn->requested_resource+2, + which, NULL, + DSR_DIGEST256|DSR_BASE64); + if (status_code != 200) { + log_info(LD_DIR, "Received status code %d (%s) from server " + "'%s:%d' while fetching \"/tor/micro/%s\". I'll try again " + "soon.", + status_code, escaped(reason), conn->base_.address, + (int)conn->base_.port, conn->requested_resource); + dir_microdesc_download_failed(which, status_code); + SMARTLIST_FOREACH(which, char *, cp, tor_free(cp)); + smartlist_free(which); + tor_free(body); tor_free(headers); tor_free(reason); + return 0; + } else { + smartlist_t *mds; + mds = microdescs_add_to_cache(get_microdesc_cache(), + body, body+body_len, SAVED_NOWHERE, 0, + now, which); + if (smartlist_len(which)) { + /* Mark remaining ones as failed. */ + dir_microdesc_download_failed(which, status_code); + } + control_event_bootstrap(BOOTSTRAP_STATUS_LOADING_DESCRIPTORS, + count_loading_descriptors_progress()); + SMARTLIST_FOREACH(which, char *, cp, tor_free(cp)); + smartlist_free(which); + smartlist_free(mds); + } + } + + if (conn->base_.purpose == DIR_PURPOSE_UPLOAD_DIR) { + switch (status_code) { + case 200: { + dir_server_t *ds = + router_get_trusteddirserver_by_digest(conn->identity_digest); + char *rejected_hdr = http_get_header(headers, + "X-Descriptor-Not-New: "); + if (rejected_hdr) { + if (!strcmp(rejected_hdr, "Yes")) { + log_info(LD_GENERAL, + "Authority '%s' declined our descriptor (not new)", + ds->nickname); + /* XXXX use this information; be sure to upload next one + * sooner. -NM */ + /* XXXX023 On further thought, the task above implies that we're + * basing our regenerate-descriptor time on when we uploaded the + * last descriptor, not on the published time of the last + * descriptor. If those are different, that's a bad thing to + * do. -NM */ + } + tor_free(rejected_hdr); + } + log_info(LD_GENERAL,"eof (status 200) after uploading server " + "descriptor: finished."); + control_event_server_status( + LOG_NOTICE, "ACCEPTED_SERVER_DESCRIPTOR DIRAUTH=%s:%d", + conn->base_.address, conn->base_.port); + + ds->has_accepted_serverdesc = 1; + if (directories_have_accepted_server_descriptor()) + control_event_server_status(LOG_NOTICE, "GOOD_SERVER_DESCRIPTOR"); + } + break; + case 400: + log_warn(LD_GENERAL,"http status 400 (%s) response from " + "dirserver '%s:%d'. Please correct.", + escaped(reason), conn->base_.address, conn->base_.port); + control_event_server_status(LOG_WARN, + "BAD_SERVER_DESCRIPTOR DIRAUTH=%s:%d REASON=\"%s\"", + conn->base_.address, conn->base_.port, escaped(reason)); + break; + default: + log_warn(LD_GENERAL, + "http status %d (%s) reason unexpected while uploading " + "descriptor to server '%s:%d').", + status_code, escaped(reason), conn->base_.address, + conn->base_.port); + break; + } + /* return 0 in all cases, since we don't want to mark any + * dirservers down just because they don't like us. */ + } + + if (conn->base_.purpose == DIR_PURPOSE_UPLOAD_VOTE) { + switch (status_code) { + case 200: { + log_notice(LD_DIR,"Uploaded a vote to dirserver %s:%d", + conn->base_.address, conn->base_.port); + } + break; + case 400: + log_warn(LD_DIR,"http status 400 (%s) response after uploading " + "vote to dirserver '%s:%d'. Please correct.", + escaped(reason), conn->base_.address, conn->base_.port); + break; + default: + log_warn(LD_GENERAL, + "http status %d (%s) reason unexpected while uploading " + "vote to server '%s:%d').", + status_code, escaped(reason), conn->base_.address, + conn->base_.port); + break; + } + /* return 0 in all cases, since we don't want to mark any + * dirservers down just because they don't like us. */ + } + + if (conn->base_.purpose == DIR_PURPOSE_UPLOAD_SIGNATURES) { + switch (status_code) { + case 200: { + log_notice(LD_DIR,"Uploaded signature(s) to dirserver %s:%d", + conn->base_.address, conn->base_.port); + } + break; + case 400: + log_warn(LD_DIR,"http status 400 (%s) response after uploading " + "signatures to dirserver '%s:%d'. Please correct.", + escaped(reason), conn->base_.address, conn->base_.port); + break; + default: + log_warn(LD_GENERAL, + "http status %d (%s) reason unexpected while uploading " + "signatures to server '%s:%d').", + status_code, escaped(reason), conn->base_.address, + conn->base_.port); + break; + } + /* return 0 in all cases, since we don't want to mark any + * dirservers down just because they don't like us. */ + } + + if (conn->base_.purpose == DIR_PURPOSE_FETCH_RENDDESC) { + tor_assert(conn->rend_data); + log_info(LD_REND,"Received rendezvous descriptor (size %d, status %d " + "(%s))", + (int)body_len, status_code, escaped(reason)); + switch (status_code) { + case 200: + if (rend_cache_store(body, body_len, 0, + conn->rend_data->onion_address) < -1) { + log_warn(LD_REND,"Failed to parse rendezvous descriptor."); + /* Any pending rendezvous attempts will notice when + * connection_about_to_close_connection() + * cleans this dir conn up. */ + /* We could retry. But since v0 descriptors are going out of + * style, it isn't worth the hassle. We'll do better in v2. */ + } else { + /* Success, or at least there's a v2 descriptor already + * present. Notify pending connections about this. */ + conn->base_.purpose = DIR_PURPOSE_HAS_FETCHED_RENDDESC; + rend_client_desc_trynow(conn->rend_data->onion_address); + } + break; + case 404: + /* Not there. Pending connections will be notified when + * connection_about_to_close_connection() cleans this conn up. */ + break; + case 400: + log_warn(LD_REND, + "http status 400 (%s). Dirserver didn't like our " + "rendezvous query?", escaped(reason)); + break; + default: + log_warn(LD_REND,"http status %d (%s) response unexpected while " + "fetching hidden service descriptor (server '%s:%d').", + status_code, escaped(reason), conn->base_.address, + conn->base_.port); + break; + } + } + + if (conn->base_.purpose == DIR_PURPOSE_FETCH_RENDDESC_V2) { + #define SEND_HS_DESC_FAILED_EVENT() ( \ + control_event_hs_descriptor_failed(conn->rend_data, \ + conn->identity_digest) ) + tor_assert(conn->rend_data); + log_info(LD_REND,"Received rendezvous descriptor (size %d, status %d " + "(%s))", + (int)body_len, status_code, escaped(reason)); + switch (status_code) { + case 200: + switch (rend_cache_store_v2_desc_as_client(body, conn->rend_data)) { + case -2: + log_warn(LD_REND,"Fetching v2 rendezvous descriptor failed. " + "Retrying at another directory."); + /* We'll retry when connection_about_to_close_connection() + * cleans this dir conn up. */ + SEND_HS_DESC_FAILED_EVENT(); + break; + case -1: + /* We already have a v0 descriptor here. Ignoring this one + * and _not_ performing another request. */ + log_info(LD_REND, "Successfully fetched v2 rendezvous " + "descriptor, but we already have a v0 descriptor."); + conn->base_.purpose = DIR_PURPOSE_HAS_FETCHED_RENDDESC; + break; + default: + /* success. notify pending connections about this. */ + log_info(LD_REND, "Successfully fetched v2 rendezvous " + "descriptor."); + control_event_hs_descriptor_received(conn->rend_data, + conn->identity_digest); + conn->base_.purpose = DIR_PURPOSE_HAS_FETCHED_RENDDESC; + rend_client_desc_trynow(conn->rend_data->onion_address); + break; + } + break; + case 404: + /* Not there. We'll retry when + * connection_about_to_close_connection() cleans this conn up. */ + log_info(LD_REND,"Fetching v2 rendezvous descriptor failed: " + "Retrying at another directory."); + SEND_HS_DESC_FAILED_EVENT(); + break; + case 400: + log_warn(LD_REND, "Fetching v2 rendezvous descriptor failed: " + "http status 400 (%s). Dirserver didn't like our " + "v2 rendezvous query? Retrying at another directory.", + escaped(reason)); + SEND_HS_DESC_FAILED_EVENT(); + break; + default: + log_warn(LD_REND, "Fetching v2 rendezvous descriptor failed: " + "http status %d (%s) response unexpected while " + "fetching v2 hidden service descriptor (server '%s:%d'). " + "Retrying at another directory.", + status_code, escaped(reason), conn->base_.address, + conn->base_.port); + SEND_HS_DESC_FAILED_EVENT(); + break; + } + } + + if (conn->base_.purpose == DIR_PURPOSE_UPLOAD_RENDDESC || + conn->base_.purpose == DIR_PURPOSE_UPLOAD_RENDDESC_V2) { + log_info(LD_REND,"Uploaded rendezvous descriptor (status %d " + "(%s))", + status_code, escaped(reason)); + switch (status_code) { + case 200: + log_info(LD_REND, + "Uploading rendezvous descriptor: finished with status " + "200 (%s)", escaped(reason)); + break; + case 400: + log_warn(LD_REND,"http status 400 (%s) response from dirserver " + "'%s:%d'. Malformed rendezvous descriptor?", + escaped(reason), conn->base_.address, conn->base_.port); + break; + default: + log_warn(LD_REND,"http status %d (%s) response unexpected (server " + "'%s:%d').", + status_code, escaped(reason), conn->base_.address, + conn->base_.port); + break; + } + } + note_client_request(conn->base_.purpose, was_compressed, orig_len); + tor_free(body); tor_free(headers); tor_free(reason); + return 0; +} + +/** Called when a directory connection reaches EOF. */ +int +connection_dir_reached_eof(dir_connection_t *conn) +{ + int retval; + if (conn->base_.state != DIR_CONN_STATE_CLIENT_READING) { + log_info(LD_HTTP,"conn reached eof, not reading. [state=%d] Closing.", + conn->base_.state); + connection_close_immediate(TO_CONN(conn)); /* error: give up on flushing */ + connection_mark_for_close(TO_CONN(conn)); + return -1; + } + + retval = connection_dir_client_reached_eof(conn); + if (retval == 0) /* success */ + conn->base_.state = DIR_CONN_STATE_CLIENT_FINISHED; + connection_mark_for_close(TO_CONN(conn)); + return retval; +} + +/** If any directory object is arriving, and it's over 10MB large, we're + * getting DoS'd. (As of 0.1.2.x, raw directories are about 1MB, and we never + * ask for more than 96 router descriptors at a time.) + */ +#define MAX_DIRECTORY_OBJECT_SIZE (10*(1<<20)) + +/** Read handler for directory connections. (That's connections to + * directory servers and connections at directory servers.) + */ +int +connection_dir_process_inbuf(dir_connection_t *conn) +{ + tor_assert(conn); + tor_assert(conn->base_.type == CONN_TYPE_DIR); + + /* Directory clients write, then read data until they receive EOF; + * directory servers read data until they get an HTTP command, then + * write their response (when it's finished flushing, they mark for + * close). + */ + + /* If we're on the dirserver side, look for a command. */ + if (conn->base_.state == DIR_CONN_STATE_SERVER_COMMAND_WAIT) { + if (directory_handle_command(conn) < 0) { + connection_mark_for_close(TO_CONN(conn)); + return -1; + } + return 0; + } + + if (connection_get_inbuf_len(TO_CONN(conn)) > MAX_DIRECTORY_OBJECT_SIZE) { + log_warn(LD_HTTP, "Too much data received from directory connection: " + "denial of service attempt, or you need to upgrade?"); + connection_mark_for_close(TO_CONN(conn)); + return -1; + } + + if (!conn->base_.inbuf_reached_eof) + log_debug(LD_HTTP,"Got data, not eof. Leaving on inbuf."); + return 0; +} + +/** Called when we're about to finally unlink and free a directory connection: + * perform necessary accounting and cleanup */ +void +connection_dir_about_to_close(dir_connection_t *dir_conn) +{ + connection_t *conn = TO_CONN(dir_conn); + + if (conn->state < DIR_CONN_STATE_CLIENT_FINISHED) { + /* It's a directory connection and connecting or fetching + * failed: forget about this router, and maybe try again. */ + connection_dir_request_failed(dir_conn); + } + /* If we were trying to fetch a v2 rend desc and did not succeed, + * retry as needed. (If a fetch is successful, the connection state + * is changed to DIR_PURPOSE_HAS_FETCHED_RENDDESC to mark that + * refetching is unnecessary.) */ + if (conn->purpose == DIR_PURPOSE_FETCH_RENDDESC_V2 && + dir_conn->rend_data && + strlen(dir_conn->rend_data->onion_address) == REND_SERVICE_ID_LEN_BASE32) + rend_client_refetch_v2_renddesc(dir_conn->rend_data); +} + +/** Create an http response for the client conn out of + * status and reason_phrase. Write it to conn. + */ +static void +write_http_status_line(dir_connection_t *conn, int status, + const char *reason_phrase) +{ + char buf[256]; + if (tor_snprintf(buf, sizeof(buf), "HTTP/1.0 %d %s\r\n\r\n", + status, reason_phrase ? reason_phrase : "OK") < 0) { + log_warn(LD_BUG,"status line too long."); + return; + } + connection_write_to_buf(buf, strlen(buf), TO_CONN(conn)); +} + +/** Write the header for an HTTP/1.0 response onto conn-\>outbuf, + * with type as the Content-Type. + * + * If length is nonnegative, it is the Content-Length. + * If encoding is provided, it is the Content-Encoding. + * If cache_lifetime is greater than 0, the content may be cached for + * up to cache_lifetime seconds. Otherwise, the content may not be cached. */ +static void +write_http_response_header_impl(dir_connection_t *conn, ssize_t length, + const char *type, const char *encoding, + const char *extra_headers, + long cache_lifetime) +{ + char date[RFC1123_TIME_LEN+1]; + char tmp[1024]; + char *cp; + time_t now = time(NULL); + + tor_assert(conn); + + format_rfc1123_time(date, now); + cp = tmp; + tor_snprintf(cp, sizeof(tmp), + "HTTP/1.0 200 OK\r\nDate: %s\r\n", + date); + cp += strlen(tmp); + if (type) { + tor_snprintf(cp, sizeof(tmp)-(cp-tmp), "Content-Type: %s\r\n", type); + cp += strlen(cp); + } + if (!is_local_addr(&conn->base_.addr)) { + /* Don't report the source address for a nearby/private connection. + * Otherwise we tend to mis-report in cases where incoming ports are + * being forwarded to a Tor server running behind the firewall. */ + tor_snprintf(cp, sizeof(tmp)-(cp-tmp), + X_ADDRESS_HEADER "%s\r\n", conn->base_.address); + cp += strlen(cp); + } + if (encoding) { + tor_snprintf(cp, sizeof(tmp)-(cp-tmp), + "Content-Encoding: %s\r\n", encoding); + cp += strlen(cp); + } + if (length >= 0) { + tor_snprintf(cp, sizeof(tmp)-(cp-tmp), + "Content-Length: %ld\r\n", (long)length); + cp += strlen(cp); + } + if (cache_lifetime > 0) { + char expbuf[RFC1123_TIME_LEN+1]; + format_rfc1123_time(expbuf, now + cache_lifetime); + /* We could say 'Cache-control: max-age=%d' here if we start doing + * http/1.1 */ + tor_snprintf(cp, sizeof(tmp)-(cp-tmp), + "Expires: %s\r\n", expbuf); + cp += strlen(cp); + } else if (cache_lifetime == 0) { + /* We could say 'Cache-control: no-cache' here if we start doing + * http/1.1 */ + strlcpy(cp, "Pragma: no-cache\r\n", sizeof(tmp)-(cp-tmp)); + cp += strlen(cp); + } + if (extra_headers) { + strlcpy(cp, extra_headers, sizeof(tmp)-(cp-tmp)); + cp += strlen(cp); + } + if (sizeof(tmp)-(cp-tmp) > 3) + memcpy(cp, "\r\n", 3); + else + tor_assert(0); + connection_write_to_buf(tmp, strlen(tmp), TO_CONN(conn)); +} + +/** As write_http_response_header_impl, but sets encoding and content-typed + * based on whether the response will be compressed or not. */ +static void +write_http_response_header(dir_connection_t *conn, ssize_t length, + int compressed, long cache_lifetime) +{ + write_http_response_header_impl(conn, length, + compressed?"application/octet-stream":"text/plain", + compressed?"deflate":"identity", + NULL, + cache_lifetime); +} + +#if defined(INSTRUMENT_DOWNLOADS) || defined(RUNNING_DOXYGEN) +/* DOCDOC */ +typedef struct request_t { + uint64_t bytes; /**< How many bytes have we transferred? */ + uint64_t count; /**< How many requests have we made? */ +} request_t; + +/** Map used to keep track of how much data we've up/downloaded in what kind + * of request. Maps from request type to pointer to request_t. */ +static strmap_t *request_map = NULL; + +/** Record that a client request of purpose was made, and that + * bytes bytes of possibly compressed data were sent/received. + * Used to keep track of how much we've up/downloaded in what kind of + * request. */ +static void +note_client_request(int purpose, int compressed, size_t bytes) +{ + char *key; + const char *kind = NULL; + switch (purpose) { + case DIR_PURPOSE_FETCH_CONSENSUS: kind = "dl/consensus"; break; + case DIR_PURPOSE_FETCH_CERTIFICATE: kind = "dl/cert"; break; + case DIR_PURPOSE_FETCH_STATUS_VOTE: kind = "dl/vote"; break; + case DIR_PURPOSE_FETCH_DETACHED_SIGNATURES: kind = "dl/detached_sig"; + break; + case DIR_PURPOSE_FETCH_SERVERDESC: kind = "dl/server"; break; + case DIR_PURPOSE_FETCH_EXTRAINFO: kind = "dl/extra"; break; + case DIR_PURPOSE_UPLOAD_DIR: kind = "dl/ul-dir"; break; + case DIR_PURPOSE_UPLOAD_VOTE: kind = "dl/ul-vote"; break; + case DIR_PURPOSE_UPLOAD_SIGNATURES: kind = "dl/ul-sig"; break; + case DIR_PURPOSE_FETCH_RENDDESC: kind = "dl/rend"; break; + case DIR_PURPOSE_FETCH_RENDDESC_V2: kind = "dl/rend2"; break; + case DIR_PURPOSE_UPLOAD_RENDDESC: kind = "dl/ul-rend"; break; + case DIR_PURPOSE_UPLOAD_RENDDESC_V2: kind = "dl/ul-rend2"; break; + } + if (kind) { + tor_asprintf(&key, "%s%s", kind, compressed?".z":""); + } else { + tor_asprintf(&key, "unknown purpose (%d)%s", + purpose, compressed?".z":""); + } + note_request(key, bytes); + tor_free(key); +} + +/** Helper: initialize the request map to instrument downloads. */ +static void +ensure_request_map_initialized(void) +{ + if (!request_map) + request_map = strmap_new(); +} + +/** Called when we just transmitted or received bytes worth of data + * because of a request of type key (an arbitrary identifier): adds + * bytes to the total associated with key. */ +void +note_request(const char *key, size_t bytes) +{ + request_t *r; + ensure_request_map_initialized(); + + r = strmap_get(request_map, key); + if (!r) { + r = tor_malloc_zero(sizeof(request_t)); + strmap_set(request_map, key, r); + } + r->bytes += bytes; + r->count++; +} + +/** Return a newly allocated string holding a summary of bytes used per + * request type. */ +char * +directory_dump_request_log(void) +{ + smartlist_t *lines; + char *result; + strmap_iter_t *iter; + + ensure_request_map_initialized(); + + lines = smartlist_new(); + + for (iter = strmap_iter_init(request_map); + !strmap_iter_done(iter); + iter = strmap_iter_next(request_map, iter)) { + const char *key; + void *val; + request_t *r; + strmap_iter_get(iter, &key, &val); + r = val; + smartlist_add_asprintf(lines, "%s "U64_FORMAT" "U64_FORMAT"\n", + key, U64_PRINTF_ARG(r->bytes), U64_PRINTF_ARG(r->count)); + } + smartlist_sort_strings(lines); + result = smartlist_join_strings(lines, "", 0, NULL); + SMARTLIST_FOREACH(lines, char *, cp, tor_free(cp)); + smartlist_free(lines); + return result; +} +#else +static void +note_client_request(int purpose, int compressed, size_t bytes) +{ + (void)purpose; + (void)compressed; + (void)bytes; +} + +void +note_request(const char *key, size_t bytes) +{ + (void)key; + (void)bytes; +} + +char * +directory_dump_request_log(void) +{ + return tor_strdup("Not supported."); +} +#endif + +/** Decide whether a client would accept the consensus we have. + * + * Clients can say they only want a consensus if it's signed by more + * than half the authorities in a list. They pass this list in + * the url as "...consensus/fpr+fpr+fpr". + * + * fpr may be an abbreviated fingerprint, i.e. only a left substring + * of the full authority identity digest. (Only strings of even length, + * i.e. encodings of full bytes, are handled correctly. In the case + * of an odd number of hex digits the last one is silently ignored.) + * + * Returns 1 if more than half of the requested authorities signed the + * consensus, 0 otherwise. + */ +int +client_likes_consensus(networkstatus_t *v, const char *want_url) +{ + smartlist_t *want_authorities = smartlist_new(); + int need_at_least; + int have = 0; + + dir_split_resource_into_fingerprints(want_url, want_authorities, NULL, 0); + need_at_least = smartlist_len(want_authorities)/2+1; + SMARTLIST_FOREACH_BEGIN(want_authorities, const char *, d) { + char want_digest[DIGEST_LEN]; + size_t want_len = strlen(d)/2; + if (want_len > DIGEST_LEN) + want_len = DIGEST_LEN; + + if (base16_decode(want_digest, DIGEST_LEN, d, want_len*2) < 0) { + log_fn(LOG_PROTOCOL_WARN, LD_DIR, + "Failed to decode requested authority digest %s.", d); + continue; + }; + + SMARTLIST_FOREACH_BEGIN(v->voters, networkstatus_voter_info_t *, vi) { + if (smartlist_len(vi->sigs) && + tor_memeq(vi->identity_digest, want_digest, want_len)) { + have++; + break; + }; + } SMARTLIST_FOREACH_END(vi); + + /* early exit, if we already have enough */ + if (have >= need_at_least) + break; + } SMARTLIST_FOREACH_END(d); + + SMARTLIST_FOREACH(want_authorities, char *, d, tor_free(d)); + smartlist_free(want_authorities); + return (have >= need_at_least); +} + +/** Helper function: called when a dirserver gets a complete HTTP GET + * request. Look for a request for a directory or for a rendezvous + * service descriptor. On finding one, write a response into + * conn-\>outbuf. If the request is unrecognized, send a 400. + * Always return 0. */ +static int +directory_handle_command_get(dir_connection_t *conn, const char *headers, + const char *req_body, size_t req_body_len) +{ + size_t dlen; + char *url, *url_mem, *header; + const or_options_t *options = get_options(); + time_t if_modified_since = 0; + int compressed; + size_t url_len; + + /* We ignore the body of a GET request. */ + (void)req_body; + (void)req_body_len; + + log_debug(LD_DIRSERV,"Received GET command."); + + conn->base_.state = DIR_CONN_STATE_SERVER_WRITING; + + if (parse_http_url(headers, &url) < 0) { + write_http_status_line(conn, 400, "Bad request"); + return 0; + } + if ((header = http_get_header(headers, "If-Modified-Since: "))) { + struct tm tm; + if (parse_http_time(header, &tm) == 0) { + if (tor_timegm(&tm, &if_modified_since)<0) + if_modified_since = 0; + } + /* The correct behavior on a malformed If-Modified-Since header is to + * act as if no If-Modified-Since header had been given. */ + tor_free(header); + } + log_debug(LD_DIRSERV,"rewritten url as '%s'.", url); + + url_mem = url; + url_len = strlen(url); + compressed = url_len > 2 && !strcmp(url+url_len-2, ".z"); + if (compressed) { + url[url_len-2] = '\0'; + url_len -= 2; + } + + if (!strcmp(url,"/tor/")) { + const char *frontpage = get_dirportfrontpage(); + + if (frontpage) { + dlen = strlen(frontpage); + /* Let's return a disclaimer page (users shouldn't use V1 anymore, + and caches don't fetch '/', so this is safe). */ + + /* [We don't check for write_bucket_low here, since we want to serve + * this page no matter what.] */ + note_request(url, dlen); + write_http_response_header_impl(conn, dlen, "text/html", "identity", + NULL, DIRPORTFRONTPAGE_CACHE_LIFETIME); + connection_write_to_buf(frontpage, dlen, TO_CONN(conn)); + goto done; + } + /* if no disclaimer file, fall through and continue */ + } + + if (!strcmp(url,"/tor/") || !strcmp(url,"/tor/dir")) { /* v1 dir fetch */ + cached_dir_t *d = dirserv_get_directory(); + + if (!d) { + log_info(LD_DIRSERV,"Client asked for the mirrored directory, but we " + "don't have a good one yet. Sending 503 Dir not available."); + write_http_status_line(conn, 503, "Directory unavailable"); + goto done; + } + if (d->published < if_modified_since) { + write_http_status_line(conn, 304, "Not modified"); + goto done; + } + + dlen = compressed ? d->dir_z_len : d->dir_len; + + if (global_write_bucket_low(TO_CONN(conn), dlen, 1)) { + log_debug(LD_DIRSERV, + "Client asked for the mirrored directory, but we've been " + "writing too many bytes lately. Sending 503 Dir busy."); + write_http_status_line(conn, 503, "Directory busy, try again later"); + goto done; + } + + note_request(url, dlen); + + log_debug(LD_DIRSERV,"Dumping %sdirectory to client.", + compressed?"compressed ":""); + write_http_response_header(conn, dlen, compressed, + FULL_DIR_CACHE_LIFETIME); + conn->cached_dir = d; + conn->cached_dir_offset = 0; + if (!compressed) + conn->zlib_state = tor_zlib_new(0, ZLIB_METHOD); + ++d->refcnt; + + /* Prime the connection with some data. */ + conn->dir_spool_src = DIR_SPOOL_CACHED_DIR; + connection_dirserv_flushed_some(conn); + goto done; + } + + if (!strcmp(url,"/tor/running-routers")) { /* running-routers fetch */ + cached_dir_t *d = dirserv_get_runningrouters(); + if (!d) { + write_http_status_line(conn, 503, "Directory unavailable"); + goto done; + } + if (d->published < if_modified_since) { + write_http_status_line(conn, 304, "Not modified"); + goto done; + } + dlen = compressed ? d->dir_z_len : d->dir_len; + + if (global_write_bucket_low(TO_CONN(conn), dlen, 1)) { + log_info(LD_DIRSERV, + "Client asked for running-routers, but we've been " + "writing too many bytes lately. Sending 503 Dir busy."); + write_http_status_line(conn, 503, "Directory busy, try again later"); + goto done; + } + note_request(url, dlen); + write_http_response_header(conn, dlen, compressed, + RUNNINGROUTERS_CACHE_LIFETIME); + connection_write_to_buf(compressed ? d->dir_z : d->dir, dlen, + TO_CONN(conn)); + goto done; + } + + if (!strcmpstart(url, "/tor/status-vote/current/consensus")) { + /* v3 network status fetch. */ + smartlist_t *dir_fps = smartlist_new(); + const char *request_type = NULL; + long lifetime = NETWORKSTATUS_CACHE_LIFETIME; + + if (1) { + networkstatus_t *v; + time_t now = time(NULL); + const char *want_fps = NULL; + char *flavor = NULL; + int flav = FLAV_NS; + #define CONSENSUS_URL_PREFIX "/tor/status-vote/current/consensus/" + #define CONSENSUS_FLAVORED_PREFIX "/tor/status-vote/current/consensus-" + /* figure out the flavor if any, and who we wanted to sign the thing */ + if (!strcmpstart(url, CONSENSUS_FLAVORED_PREFIX)) { + const char *f, *cp; + f = url + strlen(CONSENSUS_FLAVORED_PREFIX); + cp = strchr(f, '/'); + if (cp) { + want_fps = cp+1; + flavor = tor_strndup(f, cp-f); + } else { + flavor = tor_strdup(f); + } + flav = networkstatus_parse_flavor_name(flavor); + if (flav < 0) + flav = FLAV_NS; + } else { + if (!strcmpstart(url, CONSENSUS_URL_PREFIX)) + want_fps = url+strlen(CONSENSUS_URL_PREFIX); + } + + v = networkstatus_get_latest_consensus_by_flavor(flav); + + if (v && want_fps && + !client_likes_consensus(v, want_fps)) { + write_http_status_line(conn, 404, "Consensus not signed by sufficient " + "number of requested authorities"); + smartlist_free(dir_fps); + geoip_note_ns_response(GEOIP_REJECT_NOT_ENOUGH_SIGS); + tor_free(flavor); + goto done; + } + + { + char *fp = tor_malloc_zero(DIGEST_LEN); + if (flavor) + strlcpy(fp, flavor, DIGEST_LEN); + tor_free(flavor); + smartlist_add(dir_fps, fp); + } + request_type = compressed?"v3.z":"v3"; + lifetime = (v && v->fresh_until > now) ? v->fresh_until - now : 0; + } + + if (!smartlist_len(dir_fps)) { /* we failed to create/cache cp */ + write_http_status_line(conn, 503, "Network status object unavailable"); + smartlist_free(dir_fps); + geoip_note_ns_response(GEOIP_REJECT_UNAVAILABLE); + goto done; + } + + if (!dirserv_remove_old_statuses(dir_fps, if_modified_since)) { + write_http_status_line(conn, 404, "Not found"); + SMARTLIST_FOREACH(dir_fps, char *, cp, tor_free(cp)); + smartlist_free(dir_fps); + geoip_note_ns_response(GEOIP_REJECT_NOT_FOUND); + goto done; + } else if (!smartlist_len(dir_fps)) { + write_http_status_line(conn, 304, "Not modified"); + SMARTLIST_FOREACH(dir_fps, char *, cp, tor_free(cp)); + smartlist_free(dir_fps); + geoip_note_ns_response(GEOIP_REJECT_NOT_MODIFIED); + goto done; + } + + dlen = dirserv_estimate_data_size(dir_fps, 0, compressed); + if (global_write_bucket_low(TO_CONN(conn), dlen, 2)) { + log_debug(LD_DIRSERV, + "Client asked for network status lists, but we've been " + "writing too many bytes lately. Sending 503 Dir busy."); + write_http_status_line(conn, 503, "Directory busy, try again later"); + SMARTLIST_FOREACH(dir_fps, char *, fp, tor_free(fp)); + smartlist_free(dir_fps); + + geoip_note_ns_response(GEOIP_REJECT_BUSY); + goto done; + } + + if (1) { + struct in_addr in; + tor_addr_t addr; + if (tor_inet_aton((TO_CONN(conn))->address, &in)) { + tor_addr_from_ipv4h(&addr, ntohl(in.s_addr)); + geoip_note_client_seen(GEOIP_CLIENT_NETWORKSTATUS, + &addr, NULL, + time(NULL)); + geoip_note_ns_response(GEOIP_SUCCESS); + /* Note that a request for a network status has started, so that we + * can measure the download time later on. */ + if (conn->dirreq_id) + geoip_start_dirreq(conn->dirreq_id, dlen, DIRREQ_TUNNELED); + else + geoip_start_dirreq(TO_CONN(conn)->global_identifier, dlen, + DIRREQ_DIRECT); + } + } + + // note_request(request_type,dlen); + (void) request_type; + write_http_response_header(conn, -1, compressed, + smartlist_len(dir_fps) == 1 ? lifetime : 0); + conn->fingerprint_stack = dir_fps; + if (! compressed) + conn->zlib_state = tor_zlib_new(0, ZLIB_METHOD); + + /* Prime the connection with some data. */ + conn->dir_spool_src = DIR_SPOOL_NETWORKSTATUS; + connection_dirserv_flushed_some(conn); + goto done; + } + + if (!strcmpstart(url,"/tor/status-vote/current/") || + !strcmpstart(url,"/tor/status-vote/next/")) { + /* XXXX If-modified-since is only implemented for the current + * consensus: that's probably fine, since it's the only vote document + * people fetch much. */ + int current; + ssize_t body_len = 0; + ssize_t estimated_len = 0; + smartlist_t *items = smartlist_new(); + smartlist_t *dir_items = smartlist_new(); + int lifetime = 60; /* XXXX023 should actually use vote intervals. */ + url += strlen("/tor/status-vote/"); + current = !strcmpstart(url, "current/"); + url = strchr(url, '/'); + tor_assert(url); + ++url; + if (!strcmp(url, "consensus")) { + const char *item; + tor_assert(!current); /* we handle current consensus specially above, + * since it wants to be spooled. */ + if ((item = dirvote_get_pending_consensus(FLAV_NS))) + smartlist_add(items, (char*)item); + } else if (!current && !strcmp(url, "consensus-signatures")) { + /* XXXX the spec says that we should implement + * current/consensus-signatures too. It doesn't seem to be needed, + * though. */ + const char *item; + if ((item=dirvote_get_pending_detached_signatures())) + smartlist_add(items, (char*)item); + } else if (!strcmp(url, "authority")) { + const cached_dir_t *d; + int flags = DGV_BY_ID | + (current ? DGV_INCLUDE_PREVIOUS : DGV_INCLUDE_PENDING); + if ((d=dirvote_get_vote(NULL, flags))) + smartlist_add(dir_items, (cached_dir_t*)d); + } else { + const cached_dir_t *d; + smartlist_t *fps = smartlist_new(); + int flags; + if (!strcmpstart(url, "d/")) { + url += 2; + flags = DGV_INCLUDE_PENDING | DGV_INCLUDE_PREVIOUS; + } else { + flags = DGV_BY_ID | + (current ? DGV_INCLUDE_PREVIOUS : DGV_INCLUDE_PENDING); + } + dir_split_resource_into_fingerprints(url, fps, NULL, + DSR_HEX|DSR_SORT_UNIQ); + SMARTLIST_FOREACH(fps, char *, fp, { + if ((d = dirvote_get_vote(fp, flags))) + smartlist_add(dir_items, (cached_dir_t*)d); + tor_free(fp); + }); + smartlist_free(fps); + } + if (!smartlist_len(dir_items) && !smartlist_len(items)) { + write_http_status_line(conn, 404, "Not found"); + goto vote_done; + } + SMARTLIST_FOREACH(dir_items, cached_dir_t *, d, + body_len += compressed ? d->dir_z_len : d->dir_len); + estimated_len += body_len; + SMARTLIST_FOREACH(items, const char *, item, { + size_t ln = strlen(item); + if (compressed) { + estimated_len += ln/2; + } else { + body_len += ln; estimated_len += ln; + } + }); + + if (global_write_bucket_low(TO_CONN(conn), estimated_len, 2)) { + write_http_status_line(conn, 503, "Directory busy, try again later."); + goto vote_done; + } + write_http_response_header(conn, body_len ? body_len : -1, compressed, + lifetime); + + if (smartlist_len(items)) { + if (compressed) { + conn->zlib_state = tor_zlib_new(1, ZLIB_METHOD); + SMARTLIST_FOREACH(items, const char *, c, + connection_write_to_buf_zlib(c, strlen(c), conn, 0)); + connection_write_to_buf_zlib("", 0, conn, 1); + } else { + SMARTLIST_FOREACH(items, const char *, c, + connection_write_to_buf(c, strlen(c), TO_CONN(conn))); + } + } else { + SMARTLIST_FOREACH(dir_items, cached_dir_t *, d, + connection_write_to_buf(compressed ? d->dir_z : d->dir, + compressed ? d->dir_z_len : d->dir_len, + TO_CONN(conn))); + } + vote_done: + smartlist_free(items); + smartlist_free(dir_items); + goto done; + } + + if (!strcmpstart(url, "/tor/micro/d/")) { + smartlist_t *fps = smartlist_new(); + + dir_split_resource_into_fingerprints(url+strlen("/tor/micro/d/"), + fps, NULL, + DSR_DIGEST256|DSR_BASE64|DSR_SORT_UNIQ); + + if (!dirserv_have_any_microdesc(fps)) { + write_http_status_line(conn, 404, "Not found"); + SMARTLIST_FOREACH(fps, char *, fp, tor_free(fp)); + smartlist_free(fps); + goto done; + } + dlen = dirserv_estimate_microdesc_size(fps, compressed); + if (global_write_bucket_low(TO_CONN(conn), dlen, 2)) { + log_info(LD_DIRSERV, + "Client asked for server descriptors, but we've been " + "writing too many bytes lately. Sending 503 Dir busy."); + write_http_status_line(conn, 503, "Directory busy, try again later"); + SMARTLIST_FOREACH(fps, char *, fp, tor_free(fp)); + smartlist_free(fps); + goto done; + } + + write_http_response_header(conn, -1, compressed, MICRODESC_CACHE_LIFETIME); + conn->dir_spool_src = DIR_SPOOL_MICRODESC; + conn->fingerprint_stack = fps; + + if (compressed) + conn->zlib_state = tor_zlib_new(1, ZLIB_METHOD); + + connection_dirserv_flushed_some(conn); + goto done; + } + + if (!strcmpstart(url,"/tor/server/") || + (!options->BridgeAuthoritativeDir && + !options->BridgeRelay && !strcmpstart(url,"/tor/extra/"))) { + int res; + const char *msg; + const char *request_type = NULL; + int cache_lifetime = 0; + int is_extra = !strcmpstart(url,"/tor/extra/"); + url += is_extra ? strlen("/tor/extra/") : strlen("/tor/server/"); + conn->fingerprint_stack = smartlist_new(); + res = dirserv_get_routerdesc_fingerprints(conn->fingerprint_stack, url, + &msg, + !connection_dir_is_encrypted(conn), + is_extra); + + if (!strcmpstart(url, "fp/")) { + request_type = compressed?"/tor/server/fp.z":"/tor/server/fp"; + if (smartlist_len(conn->fingerprint_stack) == 1) + cache_lifetime = ROUTERDESC_CACHE_LIFETIME; + } else if (!strcmpstart(url, "authority")) { + request_type = compressed?"/tor/server/authority.z": + "/tor/server/authority"; + cache_lifetime = ROUTERDESC_CACHE_LIFETIME; + } else if (!strcmpstart(url, "all")) { + request_type = compressed?"/tor/server/all.z":"/tor/server/all"; + cache_lifetime = FULL_DIR_CACHE_LIFETIME; + } else if (!strcmpstart(url, "d/")) { + request_type = compressed?"/tor/server/d.z":"/tor/server/d"; + if (smartlist_len(conn->fingerprint_stack) == 1) + cache_lifetime = ROUTERDESC_BY_DIGEST_CACHE_LIFETIME; + } else { + request_type = "/tor/server/?"; + } + (void) request_type; /* usable for note_request. */ + if (!strcmpstart(url, "d/")) + conn->dir_spool_src = + is_extra ? DIR_SPOOL_EXTRA_BY_DIGEST : DIR_SPOOL_SERVER_BY_DIGEST; + else + conn->dir_spool_src = + is_extra ? DIR_SPOOL_EXTRA_BY_FP : DIR_SPOOL_SERVER_BY_FP; + + if (!dirserv_have_any_serverdesc(conn->fingerprint_stack, + conn->dir_spool_src)) { + res = -1; + msg = "Not found"; + } + + if (res < 0) + write_http_status_line(conn, 404, msg); + else { + dlen = dirserv_estimate_data_size(conn->fingerprint_stack, + 1, compressed); + if (global_write_bucket_low(TO_CONN(conn), dlen, 2)) { + log_info(LD_DIRSERV, + "Client asked for server descriptors, but we've been " + "writing too many bytes lately. Sending 503 Dir busy."); + write_http_status_line(conn, 503, "Directory busy, try again later"); + conn->dir_spool_src = DIR_SPOOL_NONE; + goto done; + } + write_http_response_header(conn, -1, compressed, cache_lifetime); + if (compressed) + conn->zlib_state = tor_zlib_new(1, ZLIB_METHOD); + /* Prime the connection with some data. */ + connection_dirserv_flushed_some(conn); + } + goto done; + } + + if (!strcmpstart(url,"/tor/keys/")) { + smartlist_t *certs = smartlist_new(); + ssize_t len = -1; + if (!strcmp(url, "/tor/keys/all")) { + authority_cert_get_all(certs); + } else if (!strcmp(url, "/tor/keys/authority")) { + authority_cert_t *cert = get_my_v3_authority_cert(); + if (cert) + smartlist_add(certs, cert); + } else if (!strcmpstart(url, "/tor/keys/fp/")) { + smartlist_t *fps = smartlist_new(); + dir_split_resource_into_fingerprints(url+strlen("/tor/keys/fp/"), + fps, NULL, + DSR_HEX|DSR_SORT_UNIQ); + SMARTLIST_FOREACH(fps, char *, d, { + authority_cert_t *c = authority_cert_get_newest_by_id(d); + if (c) smartlist_add(certs, c); + tor_free(d); + }); + smartlist_free(fps); + } else if (!strcmpstart(url, "/tor/keys/sk/")) { + smartlist_t *fps = smartlist_new(); + dir_split_resource_into_fingerprints(url+strlen("/tor/keys/sk/"), + fps, NULL, + DSR_HEX|DSR_SORT_UNIQ); + SMARTLIST_FOREACH(fps, char *, d, { + authority_cert_t *c = authority_cert_get_by_sk_digest(d); + if (c) smartlist_add(certs, c); + tor_free(d); + }); + smartlist_free(fps); + } else if (!strcmpstart(url, "/tor/keys/fp-sk/")) { + smartlist_t *fp_sks = smartlist_new(); + dir_split_resource_into_fingerprint_pairs(url+strlen("/tor/keys/fp-sk/"), + fp_sks); + SMARTLIST_FOREACH(fp_sks, fp_pair_t *, pair, { + authority_cert_t *c = authority_cert_get_by_digests(pair->first, + pair->second); + if (c) smartlist_add(certs, c); + tor_free(pair); + }); + smartlist_free(fp_sks); + } else { + write_http_status_line(conn, 400, "Bad request"); + goto keys_done; + } + if (!smartlist_len(certs)) { + write_http_status_line(conn, 404, "Not found"); + goto keys_done; + } + SMARTLIST_FOREACH(certs, authority_cert_t *, c, + if (c->cache_info.published_on < if_modified_since) + SMARTLIST_DEL_CURRENT(certs, c)); + if (!smartlist_len(certs)) { + write_http_status_line(conn, 304, "Not modified"); + goto keys_done; + } + len = 0; + SMARTLIST_FOREACH(certs, authority_cert_t *, c, + len += c->cache_info.signed_descriptor_len); + + if (global_write_bucket_low(TO_CONN(conn), compressed?len/2:len, 2)) { + write_http_status_line(conn, 503, "Directory busy, try again later."); + goto keys_done; + } + + write_http_response_header(conn, compressed?-1:len, compressed, 60*60); + if (compressed) { + conn->zlib_state = tor_zlib_new(1, ZLIB_METHOD); + SMARTLIST_FOREACH(certs, authority_cert_t *, c, + connection_write_to_buf_zlib(c->cache_info.signed_descriptor_body, + c->cache_info.signed_descriptor_len, + conn, 0)); + connection_write_to_buf_zlib("", 0, conn, 1); + } else { + SMARTLIST_FOREACH(certs, authority_cert_t *, c, + connection_write_to_buf(c->cache_info.signed_descriptor_body, + c->cache_info.signed_descriptor_len, + TO_CONN(conn))); + } + keys_done: + smartlist_free(certs); + goto done; + } + + if (options->HidServDirectoryV2 && + connection_dir_is_encrypted(conn) && + !strcmpstart(url,"/tor/rendezvous2/")) { + /* Handle v2 rendezvous descriptor fetch request. */ + const char *descp; + const char *query = url + strlen("/tor/rendezvous2/"); + if (strlen(query) == REND_DESC_ID_V2_LEN_BASE32) { + log_info(LD_REND, "Got a v2 rendezvous descriptor request for ID '%s'", + safe_str(query)); + switch (rend_cache_lookup_v2_desc_as_dir(query, &descp)) { + case 1: /* valid */ + write_http_response_header(conn, strlen(descp), 0, 0); + connection_write_to_buf(descp, strlen(descp), TO_CONN(conn)); + break; + case 0: /* well-formed but not present */ + write_http_status_line(conn, 404, "Not found"); + break; + case -1: /* not well-formed */ + write_http_status_line(conn, 400, "Bad request"); + break; + } + } else { /* not well-formed */ + write_http_status_line(conn, 400, "Bad request"); + } + goto done; + } + + if (options->HSAuthoritativeDir && !strcmpstart(url,"/tor/rendezvous/")) { + /* rendezvous descriptor fetch */ + const char *descp; + size_t desc_len; + const char *query = url+strlen("/tor/rendezvous/"); + + log_info(LD_REND, "Handling rendezvous descriptor get"); + switch (rend_cache_lookup_desc(query, 0, &descp, &desc_len)) { + case 1: /* valid */ + write_http_response_header_impl(conn, desc_len, + "application/octet-stream", + NULL, NULL, 0); + note_request("/tor/rendezvous?/", desc_len); + /* need to send descp separately, because it may include NULs */ + connection_write_to_buf(descp, desc_len, TO_CONN(conn)); + break; + case 0: /* well-formed but not present */ + write_http_status_line(conn, 404, "Not found"); + break; + case -1: /* not well-formed */ + write_http_status_line(conn, 400, "Bad request"); + break; + } + goto done; + } + + if (options->BridgeAuthoritativeDir && + options->BridgePassword_AuthDigest_ && + connection_dir_is_encrypted(conn) && + !strcmp(url,"/tor/networkstatus-bridges")) { + char *status; + char digest[DIGEST256_LEN]; + + header = http_get_header(headers, "Authorization: Basic "); + if (header) + crypto_digest256(digest, header, strlen(header), DIGEST_SHA256); + + /* now make sure the password is there and right */ + if (!header || + tor_memneq(digest, + options->BridgePassword_AuthDigest_, DIGEST256_LEN)) { + write_http_status_line(conn, 404, "Not found"); + tor_free(header); + goto done; + } + tor_free(header); + + /* all happy now. send an answer. */ + status = networkstatus_getinfo_by_purpose("bridge", time(NULL)); + dlen = strlen(status); + write_http_response_header(conn, dlen, 0, 0); + connection_write_to_buf(status, dlen, TO_CONN(conn)); + tor_free(status); + goto done; + } + + if (!strcmpstart(url,"/tor/bytes.txt")) { + char *bytes = directory_dump_request_log(); + size_t len = strlen(bytes); + write_http_response_header(conn, len, 0, 0); + connection_write_to_buf(bytes, len, TO_CONN(conn)); + tor_free(bytes); + goto done; + } + + if (!strcmp(url,"/tor/robots.txt")) { /* /robots.txt will have been + rewritten to /tor/robots.txt */ + char robots[] = "User-agent: *\r\nDisallow: /\r\n"; + size_t len = strlen(robots); + write_http_response_header(conn, len, 0, ROBOTS_CACHE_LIFETIME); + connection_write_to_buf(robots, len, TO_CONN(conn)); + goto done; + } + + if (!strcmp(url,"/tor/dbg-stability.txt")) { + const char *stability; + size_t len; + if (options->BridgeAuthoritativeDir || + ! authdir_mode_tests_reachability(options) || + ! (stability = rep_hist_get_router_stability_doc(time(NULL)))) { + write_http_status_line(conn, 404, "Not found."); + goto done; + } + + len = strlen(stability); + write_http_response_header(conn, len, 0, 0); + connection_write_to_buf(stability, len, TO_CONN(conn)); + goto done; + } + +#if defined(EXPORTMALLINFO) && defined(HAVE_MALLOC_H) && defined(HAVE_MALLINFO) +#define ADD_MALLINFO_LINE(x) do { \ + smartlist_add_asprintf(lines, "%s %d\n", #x, mi.x); \ + }while(0); + + if (!strcmp(url,"/tor/mallinfo.txt") && + (tor_addr_eq_ipv4h(&conn->base_.addr, 0x7f000001ul))) { + char *result; + size_t len; + struct mallinfo mi; + smartlist_t *lines; + + memset(&mi, 0, sizeof(mi)); + mi = mallinfo(); + lines = smartlist_new(); + + ADD_MALLINFO_LINE(arena) + ADD_MALLINFO_LINE(ordblks) + ADD_MALLINFO_LINE(smblks) + ADD_MALLINFO_LINE(hblks) + ADD_MALLINFO_LINE(hblkhd) + ADD_MALLINFO_LINE(usmblks) + ADD_MALLINFO_LINE(fsmblks) + ADD_MALLINFO_LINE(uordblks) + ADD_MALLINFO_LINE(fordblks) + ADD_MALLINFO_LINE(keepcost) + + result = smartlist_join_strings(lines, "", 0, NULL); + SMARTLIST_FOREACH(lines, char *, cp, tor_free(cp)); + smartlist_free(lines); + + len = strlen(result); + write_http_response_header(conn, len, 0, 0); + connection_write_to_buf(result, len, TO_CONN(conn)); + tor_free(result); + goto done; + } +#endif + + /* we didn't recognize the url */ + write_http_status_line(conn, 404, "Not found"); + + done: + tor_free(url_mem); + return 0; +} + +/** Helper function: called when a dirserver gets a complete HTTP POST + * request. Look for an uploaded server descriptor or rendezvous + * service descriptor. On finding one, process it and write a + * response into conn-\>outbuf. If the request is unrecognized, send a + * 400. Always return 0. */ +static int +directory_handle_command_post(dir_connection_t *conn, const char *headers, + const char *body, size_t body_len) +{ + char *url = NULL; + const or_options_t *options = get_options(); + + log_debug(LD_DIRSERV,"Received POST command."); + + conn->base_.state = DIR_CONN_STATE_SERVER_WRITING; + + if (parse_http_url(headers, &url) < 0) { + write_http_status_line(conn, 400, "Bad request"); + return 0; + } + log_debug(LD_DIRSERV,"rewritten url as '%s'.", url); + + /* Handle v2 rendezvous service publish request. */ + if (options->HidServDirectoryV2 && + connection_dir_is_encrypted(conn) && + !strcmpstart(url,"/tor/rendezvous2/publish")) { + switch (rend_cache_store_v2_desc_as_dir(body)) { + case -2: + log_info(LD_REND, "Rejected v2 rend descriptor (length %d) from %s " + "since we're not currently a hidden service directory.", + (int)body_len, conn->base_.address); + write_http_status_line(conn, 503, "Currently not acting as v2 " + "hidden service directory"); + break; + case -1: + log_warn(LD_REND, "Rejected v2 rend descriptor (length %d) from %s.", + (int)body_len, conn->base_.address); + write_http_status_line(conn, 400, + "Invalid v2 service descriptor rejected"); + break; + default: + write_http_status_line(conn, 200, "Service descriptor (v2) stored"); + log_info(LD_REND, "Handled v2 rendezvous descriptor post: accepted"); + } + goto done; + } + + if (!authdir_mode(options)) { + /* we just provide cached directories; we don't want to + * receive anything. */ + write_http_status_line(conn, 400, "Nonauthoritative directory does not " + "accept posted server descriptors"); + goto done; + } + + if (authdir_mode_handles_descs(options, -1) && + !strcmp(url,"/tor/")) { /* server descriptor post */ + const char *msg = "[None]"; + uint8_t purpose = authdir_mode_bridge(options) ? + ROUTER_PURPOSE_BRIDGE : ROUTER_PURPOSE_GENERAL; + was_router_added_t r = dirserv_add_multiple_descriptors(body, purpose, + conn->base_.address, &msg); + tor_assert(msg); + if (WRA_WAS_ADDED(r)) + dirserv_get_directory(); /* rebuild and write to disk */ + + if (r == ROUTER_ADDED_NOTIFY_GENERATOR) { + /* Accepted with a message. */ + log_info(LD_DIRSERV, + "Problematic router descriptor or extra-info from %s " + "(\"%s\").", + conn->base_.address, msg); + write_http_status_line(conn, 400, msg); + } else if (r == ROUTER_ADDED_SUCCESSFULLY) { + write_http_status_line(conn, 200, msg); + } else if (WRA_WAS_OUTDATED(r)) { + write_http_response_header_impl(conn, -1, NULL, NULL, + "X-Descriptor-Not-New: Yes\r\n", -1); + } else { + log_info(LD_DIRSERV, + "Rejected router descriptor or extra-info from %s " + "(\"%s\").", + conn->base_.address, msg); + write_http_status_line(conn, 400, msg); + } + goto done; + } + + if (options->HSAuthoritativeDir && + !strcmpstart(url,"/tor/rendezvous/publish")) { + /* rendezvous descriptor post */ + log_info(LD_REND, "Handling rendezvous descriptor post."); + if (rend_cache_store(body, body_len, 1, NULL) < 0) { + log_fn(LOG_PROTOCOL_WARN, LD_DIRSERV, + "Rejected rend descriptor (length %d) from %s.", + (int)body_len, conn->base_.address); + write_http_status_line(conn, 400, + "Invalid v0 service descriptor rejected"); + } else { + write_http_status_line(conn, 200, "Service descriptor (v0) stored"); + } + goto done; + } + + if (authdir_mode_v3(options) && + !strcmp(url,"/tor/post/vote")) { /* v3 networkstatus vote */ + const char *msg = "OK"; + int status; + if (dirvote_add_vote(body, &msg, &status)) { + write_http_status_line(conn, status, "Vote stored"); + } else { + tor_assert(msg); + log_warn(LD_DIRSERV, "Rejected vote from %s (\"%s\").", + conn->base_.address, msg); + write_http_status_line(conn, status, msg); + } + goto done; + } + + if (authdir_mode_v3(options) && + !strcmp(url,"/tor/post/consensus-signature")) { /* sigs on consensus. */ + const char *msg = NULL; + if (dirvote_add_signatures(body, conn->base_.address, &msg)>=0) { + write_http_status_line(conn, 200, msg?msg:"Signatures stored"); + } else { + log_warn(LD_DIR, "Unable to store signatures posted by %s: %s", + conn->base_.address, msg?msg:"???"); + write_http_status_line(conn, 400, msg?msg:"Unable to store signatures"); + } + goto done; + } + + /* we didn't recognize the url */ + write_http_status_line(conn, 404, "Not found"); + + done: + tor_free(url); + return 0; +} + +/** Called when a dirserver receives data on a directory connection; + * looks for an HTTP request. If the request is complete, remove it + * from the inbuf, try to process it; otherwise, leave it on the + * buffer. Return a 0 on success, or -1 on error. + */ +static int +directory_handle_command(dir_connection_t *conn) +{ + char *headers=NULL, *body=NULL; + size_t body_len=0; + int r; + + tor_assert(conn); + tor_assert(conn->base_.type == CONN_TYPE_DIR); + + switch (connection_fetch_from_buf_http(TO_CONN(conn), + &headers, MAX_HEADERS_SIZE, + &body, &body_len, MAX_DIR_UL_SIZE, 0)) { + case -1: /* overflow */ + log_warn(LD_DIRSERV, + "Request too large from address '%s' to DirPort. Closing.", + safe_str(conn->base_.address)); + return -1; + case 0: + log_debug(LD_DIRSERV,"command not all here yet."); + return 0; + /* case 1, fall through */ + } + + http_set_address_origin(headers, TO_CONN(conn)); + //log_debug(LD_DIRSERV,"headers %s, body %s.", headers, body); + + if (!strncasecmp(headers,"GET",3)) + r = directory_handle_command_get(conn, headers, body, body_len); + else if (!strncasecmp(headers,"POST",4)) + r = directory_handle_command_post(conn, headers, body, body_len); + else { + log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, + "Got headers %s with unknown command. Closing.", + escaped(headers)); + r = -1; + } + + tor_free(headers); tor_free(body); + return r; +} + +/** Write handler for directory connections; called when all data has + * been flushed. Close the connection or wait for a response as + * appropriate. + */ +int +connection_dir_finished_flushing(dir_connection_t *conn) +{ + tor_assert(conn); + tor_assert(conn->base_.type == CONN_TYPE_DIR); + + /* Note that we have finished writing the directory response. For direct + * connections this means we're done, for tunneled connections its only + * an intermediate step. */ + if (conn->dirreq_id) + geoip_change_dirreq_state(conn->dirreq_id, DIRREQ_TUNNELED, + DIRREQ_FLUSHING_DIR_CONN_FINISHED); + else + geoip_change_dirreq_state(TO_CONN(conn)->global_identifier, + DIRREQ_DIRECT, + DIRREQ_FLUSHING_DIR_CONN_FINISHED); + switch (conn->base_.state) { + case DIR_CONN_STATE_CONNECTING: + case DIR_CONN_STATE_CLIENT_SENDING: + log_debug(LD_DIR,"client finished sending command."); + conn->base_.state = DIR_CONN_STATE_CLIENT_READING; + return 0; + case DIR_CONN_STATE_SERVER_WRITING: + if (conn->dir_spool_src != DIR_SPOOL_NONE) { +#ifdef USE_BUFFEREVENTS + /* This can happen with paired bufferevents, since a paired connection + * can flush immediately when you write to it, making the subsequent + * check in connection_handle_write_cb() decide that the connection + * is flushed. */ + log_debug(LD_DIRSERV, "Emptied a dirserv buffer, but still spooling."); +#else + log_warn(LD_BUG, "Emptied a dirserv buffer, but it's still spooling!"); + connection_mark_for_close(TO_CONN(conn)); +#endif + } else { + log_debug(LD_DIRSERV, "Finished writing server response. Closing."); + connection_mark_for_close(TO_CONN(conn)); + } + return 0; + default: + log_warn(LD_BUG,"called in unexpected state %d.", + conn->base_.state); + tor_fragile_assert(); + return -1; + } + return 0; +} + +/** Connected handler for directory connections: begin sending data to the + * server */ +int +connection_dir_finished_connecting(dir_connection_t *conn) +{ + tor_assert(conn); + tor_assert(conn->base_.type == CONN_TYPE_DIR); + tor_assert(conn->base_.state == DIR_CONN_STATE_CONNECTING); + + log_debug(LD_HTTP,"Dir connection to router %s:%u established.", + conn->base_.address,conn->base_.port); + + conn->base_.state = DIR_CONN_STATE_CLIENT_SENDING; /* start flushing conn */ + return 0; +} + +/** Decide which download schedule we want to use based on descriptor type + * in dls and whether we are acting as directory server, and + * then return a list of int pointers defining download delays in seconds. + * Helper function for download_status_increment_failure() and + * download_status_reset(). */ +static const smartlist_t * +find_dl_schedule_and_len(download_status_t *dls, int server) +{ + switch (dls->schedule) { + case DL_SCHED_GENERIC: + if (server) + return get_options()->TestingServerDownloadSchedule; + else + return get_options()->TestingClientDownloadSchedule; + case DL_SCHED_CONSENSUS: + if (server) + return get_options()->TestingServerConsensusDownloadSchedule; + else + return get_options()->TestingClientConsensusDownloadSchedule; + case DL_SCHED_BRIDGE: + return get_options()->TestingBridgeDownloadSchedule; + default: + tor_assert(0); + } +} + +/** Called when an attempt to download dls has failed with HTTP status + * status_code. Increment the failure count (if the code indicates a + * real failure) and set dls-\>next_attempt_at to an appropriate time + * in the future. */ +time_t +download_status_increment_failure(download_status_t *dls, int status_code, + const char *item, int server, time_t now) +{ + const smartlist_t *schedule; + int increment; + tor_assert(dls); + if (status_code != 503 || server) { + if (dls->n_download_failures < IMPOSSIBLE_TO_DOWNLOAD-1) + ++dls->n_download_failures; + } + + schedule = find_dl_schedule_and_len(dls, server); + + if (dls->n_download_failures < smartlist_len(schedule)) + increment = *(int *)smartlist_get(schedule, dls->n_download_failures); + else if (dls->n_download_failures == IMPOSSIBLE_TO_DOWNLOAD) + increment = INT_MAX; + else + increment = *(int *)smartlist_get(schedule, smartlist_len(schedule) - 1); + + if (increment < INT_MAX) + dls->next_attempt_at = now+increment; + else + dls->next_attempt_at = TIME_MAX; + + if (item) { + if (increment == 0) + log_debug(LD_DIR, "%s failed %d time(s); I'll try again immediately.", + item, (int)dls->n_download_failures); + else if (dls->next_attempt_at < TIME_MAX) + log_debug(LD_DIR, "%s failed %d time(s); I'll try again in %d seconds.", + item, (int)dls->n_download_failures, + (int)(dls->next_attempt_at-now)); + else + log_debug(LD_DIR, "%s failed %d time(s); Giving up for a while.", + item, (int)dls->n_download_failures); + } + return dls->next_attempt_at; +} + +/** Reset dls so that it will be considered downloadable + * immediately, and/or to show that we don't need it anymore. + * + * (We find the zeroth element of the download schedule, and set + * next_attempt_at to be the appropriate offset from 'now'. In most + * cases this means setting it to 'now', so the item will be immediately + * downloadable; in the case of bridge descriptors, the zeroth element + * is an hour from now.) */ +void +download_status_reset(download_status_t *dls) +{ + const smartlist_t *schedule = find_dl_schedule_and_len( + dls, get_options()->DirPort_set); + + dls->n_download_failures = 0; + dls->next_attempt_at = time(NULL) + *(int *)smartlist_get(schedule, 0); +} + +/** Return the number of failures on dls since the last success (if + * any). */ +int +download_status_get_n_failures(const download_status_t *dls) +{ + return dls->n_download_failures; +} + +/** Called when one or more routerdesc (or extrainfo, if was_extrainfo) + * fetches have failed (with uppercase fingerprints listed in failed, + * either as descriptor digests or as identity digests based on + * was_descriptor_digests). + */ +static void +dir_routerdesc_download_failed(smartlist_t *failed, int status_code, + int router_purpose, + int was_extrainfo, int was_descriptor_digests) +{ + char digest[DIGEST_LEN]; + time_t now = time(NULL); + int server = directory_fetches_from_authorities(get_options()); + if (!was_descriptor_digests) { + if (router_purpose == ROUTER_PURPOSE_BRIDGE) { + tor_assert(!was_extrainfo); + connection_dir_retry_bridges(failed); + } + return; /* FFFF should implement for other-than-router-purpose someday */ + } + SMARTLIST_FOREACH_BEGIN(failed, const char *, cp) { + download_status_t *dls = NULL; + if (base16_decode(digest, DIGEST_LEN, cp, strlen(cp)) < 0) { + log_warn(LD_BUG, "Malformed fingerprint in list: %s", escaped(cp)); + continue; + } + if (was_extrainfo) { + signed_descriptor_t *sd = + router_get_by_extrainfo_digest(digest); + if (sd) + dls = &sd->ei_dl_status; + } else { + dls = router_get_dl_status_by_descriptor_digest(digest); + } + if (!dls || dls->n_download_failures >= + get_options()->TestingDescriptorMaxDownloadTries) + continue; + download_status_increment_failure(dls, status_code, cp, server, now); + } SMARTLIST_FOREACH_END(cp); + + /* No need to relaunch descriptor downloads here: we already do it + * every 10 or 60 seconds (FOO_DESCRIPTOR_RETRY_INTERVAL) in onion_main.c. */ +} + +/** Called when a connection to download microdescriptors has failed in whole + * or in part. failed is a list of every microdesc digest we didn't + * get. status_code is the http status code we received. Reschedule the + * microdesc downloads as appropriate. */ +static void +dir_microdesc_download_failed(smartlist_t *failed, + int status_code) +{ + networkstatus_t *consensus + = networkstatus_get_latest_consensus_by_flavor(FLAV_MICRODESC); + routerstatus_t *rs; + download_status_t *dls; + time_t now = time(NULL); + int server = directory_fetches_from_authorities(get_options()); + + if (! consensus) + return; + SMARTLIST_FOREACH_BEGIN(failed, const char *, d) { + rs = router_get_mutable_consensus_status_by_descriptor_digest(consensus,d); + if (!rs) + continue; + dls = &rs->dl_status; + if (dls->n_download_failures >= + get_options()->TestingMicrodescMaxDownloadTries) + continue; + { + char buf[BASE64_DIGEST256_LEN+1]; + digest256_to_base64(buf, d); + download_status_increment_failure(dls, status_code, buf, + server, now); + } + } SMARTLIST_FOREACH_END(d); +} + +/** Helper. Compare two fp_pair_t objects, and return negative, 0, or + * positive as appropriate. */ +static int +compare_pairs_(const void **a, const void **b) +{ + const fp_pair_t *fp1 = *a, *fp2 = *b; + int r; + if ((r = fast_memcmp(fp1->first, fp2->first, DIGEST_LEN))) + return r; + else + return fast_memcmp(fp1->second, fp2->second, DIGEST_LEN); +} + +/** Divide a string res of the form FP1-FP2+FP3-FP4...[.z], where each + * FP is a hex-encoded fingerprint, into a sequence of distinct sorted + * fp_pair_t. Skip malformed pairs. On success, return 0 and add those + * fp_pair_t into pairs_out. On failure, return -1. */ +int +dir_split_resource_into_fingerprint_pairs(const char *res, + smartlist_t *pairs_out) +{ + smartlist_t *pairs_tmp = smartlist_new(); + smartlist_t *pairs_result = smartlist_new(); + + smartlist_split_string(pairs_tmp, res, "+", 0, 0); + if (smartlist_len(pairs_tmp)) { + char *last = smartlist_get(pairs_tmp,smartlist_len(pairs_tmp)-1); + size_t last_len = strlen(last); + if (last_len > 2 && !strcmp(last+last_len-2, ".z")) { + last[last_len-2] = '\0'; + } + } + SMARTLIST_FOREACH_BEGIN(pairs_tmp, char *, cp) { + if (strlen(cp) != HEX_DIGEST_LEN*2+1) { + log_info(LD_DIR, + "Skipping digest pair %s with non-standard length.", escaped(cp)); + } else if (cp[HEX_DIGEST_LEN] != '-') { + log_info(LD_DIR, + "Skipping digest pair %s with missing dash.", escaped(cp)); + } else { + fp_pair_t pair; + if (base16_decode(pair.first, DIGEST_LEN, cp, HEX_DIGEST_LEN)<0 || + base16_decode(pair.second, + DIGEST_LEN, cp+HEX_DIGEST_LEN+1, HEX_DIGEST_LEN)<0) { + log_info(LD_DIR, "Skipping non-decodable digest pair %s", escaped(cp)); + } else { + smartlist_add(pairs_result, tor_memdup(&pair, sizeof(pair))); + } + } + tor_free(cp); + } SMARTLIST_FOREACH_END(cp); + smartlist_free(pairs_tmp); + + /* Uniq-and-sort */ + smartlist_sort(pairs_result, compare_pairs_); + smartlist_uniq(pairs_result, compare_pairs_, tor_free_); + + smartlist_add_all(pairs_out, pairs_result); + smartlist_free(pairs_result); + return 0; +} + +/** Given a directory resource request, containing zero + * or more strings separated by plus signs, followed optionally by ".z", store + * the strings, in order, into fp_out. If compressed_out is + * non-NULL, set it to 1 if the resource ends in ".z", else set it to 0. + * + * If (flags & DSR_HEX), then delete all elements that aren't hex digests, and + * decode the rest. If (flags & DSR_BASE64), then use "-" rather than "+" as + * a separator, delete all the elements that aren't base64-encoded digests, + * and decode the rest. If (flags & DSR_DIGEST256), these digests should be + * 256 bits long; else they should be 160. + * + * If (flags & DSR_SORT_UNIQ), then sort the list and remove all duplicates. + */ +int +dir_split_resource_into_fingerprints(const char *resource, + smartlist_t *fp_out, int *compressed_out, + int flags) +{ + const int decode_hex = flags & DSR_HEX; + const int decode_base64 = flags & DSR_BASE64; + const int digests_are_256 = flags & DSR_DIGEST256; + const int sort_uniq = flags & DSR_SORT_UNIQ; + + const int digest_len = digests_are_256 ? DIGEST256_LEN : DIGEST_LEN; + const int hex_digest_len = digests_are_256 ? + HEX_DIGEST256_LEN : HEX_DIGEST_LEN; + const int base64_digest_len = digests_are_256 ? + BASE64_DIGEST256_LEN : BASE64_DIGEST_LEN; + smartlist_t *fp_tmp = smartlist_new(); + + tor_assert(!(decode_hex && decode_base64)); + tor_assert(fp_out); + + smartlist_split_string(fp_tmp, resource, decode_base64?"-":"+", 0, 0); + if (compressed_out) + *compressed_out = 0; + if (smartlist_len(fp_tmp)) { + char *last = smartlist_get(fp_tmp,smartlist_len(fp_tmp)-1); + size_t last_len = strlen(last); + if (last_len > 2 && !strcmp(last+last_len-2, ".z")) { + last[last_len-2] = '\0'; + if (compressed_out) + *compressed_out = 1; + } + } + if (decode_hex || decode_base64) { + const size_t encoded_len = decode_hex ? hex_digest_len : base64_digest_len; + int i; + char *cp, *d = NULL; + for (i = 0; i < smartlist_len(fp_tmp); ++i) { + cp = smartlist_get(fp_tmp, i); + if (strlen(cp) != encoded_len) { + log_info(LD_DIR, + "Skipping digest %s with non-standard length.", escaped(cp)); + smartlist_del_keeporder(fp_tmp, i--); + goto again; + } + d = tor_malloc_zero(digest_len); + if (decode_hex ? + (base16_decode(d, digest_len, cp, hex_digest_len)<0) : + (base64_decode(d, digest_len, cp, base64_digest_len)<0)) { + log_info(LD_DIR, "Skipping non-decodable digest %s", escaped(cp)); + smartlist_del_keeporder(fp_tmp, i--); + goto again; + } + smartlist_set(fp_tmp, i, d); + d = NULL; + again: + tor_free(cp); + tor_free(d); + } + } + if (sort_uniq) { + if (decode_hex || decode_base64) { + if (digests_are_256) { + smartlist_sort_digests256(fp_tmp); + smartlist_uniq_digests256(fp_tmp); + } else { + smartlist_sort_digests(fp_tmp); + smartlist_uniq_digests(fp_tmp); + } + } else { + smartlist_sort_strings(fp_tmp); + smartlist_uniq_strings(fp_tmp); + } + } + smartlist_add_all(fp_out, fp_tmp); + smartlist_free(fp_tmp); + return 0; +} + diff --git a/src/tor/directory.h b/src/tor/directory.h new file mode 100644 index 0000000..0453160 --- /dev/null +++ b/src/tor/directory.h @@ -0,0 +1,127 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file directory.h + * \brief Header file for directory.c. + **/ + +#ifndef TOR_DIRECTORY_H +#define TOR_DIRECTORY_H + +int directories_have_accepted_server_descriptor(void); +void directory_post_to_dirservers(uint8_t dir_purpose, uint8_t router_purpose, + dirinfo_type_t type, const char *payload, + size_t payload_len, size_t extrainfo_len); +void directory_get_from_dirserver(uint8_t dir_purpose, uint8_t router_purpose, + const char *resource, + int pds_flags); +void directory_get_from_all_authorities(uint8_t dir_purpose, + uint8_t router_purpose, + const char *resource); + +/** Enumeration of ways to connect to a directory server */ +typedef enum { + /** Default: connect over a one-hop Tor circuit but fall back to direct + * connection */ + DIRIND_ONEHOP=0, + /** Connect over a multi-hop anonymizing Tor circuit */ + DIRIND_ANONYMOUS=1, + /** Conncet to the DirPort directly */ + DIRIND_DIRECT_CONN, + /** Connect over a multi-hop anonymizing Tor circuit to our dirport */ + DIRIND_ANON_DIRPORT, +} dir_indirection_t; + +void directory_initiate_command_routerstatus(const routerstatus_t *status, + uint8_t dir_purpose, + uint8_t router_purpose, + dir_indirection_t indirection, + const char *resource, + const char *payload, + size_t payload_len, + time_t if_modified_since); +void directory_initiate_command_routerstatus_rend(const routerstatus_t *status, + uint8_t dir_purpose, + uint8_t router_purpose, + dir_indirection_t indirection, + const char *resource, + const char *payload, + size_t payload_len, + time_t if_modified_since, + const rend_data_t *rend_query); + +int parse_http_response(const char *headers, int *code, time_t *date, + compress_method_t *compression, char **response); + +int connection_dir_is_encrypted(dir_connection_t *conn); +int connection_dir_reached_eof(dir_connection_t *conn); +int connection_dir_process_inbuf(dir_connection_t *conn); +int connection_dir_finished_flushing(dir_connection_t *conn); +int connection_dir_finished_connecting(dir_connection_t *conn); +void connection_dir_about_to_close(dir_connection_t *dir_conn); +void directory_initiate_command(const char *address, const tor_addr_t *addr, + uint16_t or_port, uint16_t dir_port, + const char *digest, + uint8_t dir_purpose, uint8_t router_purpose, + dir_indirection_t indirection, + const char *resource, + const char *payload, size_t payload_len, + time_t if_modified_since); + +#define DSR_HEX (1<<0) +#define DSR_BASE64 (1<<1) +#define DSR_DIGEST256 (1<<2) +#define DSR_SORT_UNIQ (1<<3) +int dir_split_resource_into_fingerprints(const char *resource, + smartlist_t *fp_out, int *compressed_out, + int flags); + +int dir_split_resource_into_fingerprint_pairs(const char *res, + smartlist_t *pairs_out); +char *directory_dump_request_log(void); +void note_request(const char *key, size_t bytes); +int router_supports_extrainfo(const char *identity_digest, int is_authority); + +time_t download_status_increment_failure(download_status_t *dls, + int status_code, const char *item, + int server, time_t now); +/** Increment the failure count of the download_status_t dls, with + * the optional status code sc. */ +#define download_status_failed(dls, sc) \ + download_status_increment_failure((dls), (sc), NULL, \ + get_options()->DirPort_set, time(NULL)) + +void download_status_reset(download_status_t *dls); +static int download_status_is_ready(download_status_t *dls, time_t now, + int max_failures); +/** Return true iff, as of now, the resource tracked by dls is + * ready to get its download reattempted. */ +static INLINE int +download_status_is_ready(download_status_t *dls, time_t now, + int max_failures) +{ + return (dls->n_download_failures <= max_failures + && dls->next_attempt_at <= now); +} + +static void download_status_mark_impossible(download_status_t *dl); +/** Mark dl as never downloadable. */ +static INLINE void +download_status_mark_impossible(download_status_t *dl) +{ + dl->n_download_failures = IMPOSSIBLE_TO_DOWNLOAD; +} + +int download_status_get_n_failures(const download_status_t *dls); + +#ifdef TOR_UNIT_TESTS +/* Used only by directory.c and test_dir.c */ +STATIC int parse_http_url(const char *headers, char **url); +#endif + +#endif + diff --git a/src/tor/dirserv.c b/src/tor/dirserv.c new file mode 100644 index 0000000..b156282 --- /dev/null +++ b/src/tor/dirserv.c @@ -0,0 +1,3780 @@ +/* Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#define DIRSERV_PRIVATE +#include "or.h" +#include "buffers.h" +#include "config.h" +#include "confparse.h" +#include "channel.h" +#include "channeltls.h" +#include "command.h" +#include "connection.h" +#include "connection_or.h" +#include "control.h" +#include "directory.h" +#include "dirserv.h" +#include "dirvote.h" +#include "hibernate.h" +#include "microdesc.h" +#include "networkstatus.h" +#include "nodelist.h" +#include "policies.h" +#include "rephist.h" +#include "router.h" +#include "routerlist.h" +#include "routerparse.h" +#include "routerset.h" + +/** + * \file dirserv.c + * \brief Directory server core implementation. Manages directory + * contents and generates directories. + */ + +/** How far in the future do we allow a router to get? (seconds) */ +#define ROUTER_ALLOW_SKEW (60*60*12) +/** How many seconds do we wait before regenerating the directory? */ +#define DIR_REGEN_SLACK_TIME 30 +/** If we're a cache, keep this many networkstatuses around from non-trusted + * directory authorities. */ +#define MAX_UNTRUSTED_NETWORKSTATUSES 16 + +/** If a v1 directory is older than this, discard it. */ +#define MAX_V1_DIRECTORY_AGE (30*24*60*60) +/** If a v1 running-routers is older than this, discard it. */ +#define MAX_V1_RR_AGE (7*24*60*60) + +extern time_t time_of_process_start; /* from onion_main.c */ + +extern long stats_n_seconds_working; /* from onion_main.c */ + +/** Do we need to regenerate the v1 directory when someone asks for it? */ +static time_t the_directory_is_dirty = 1; +/** Do we need to regenerate the v1 runningrouters document when somebody + * asks for it? */ +static time_t runningrouters_is_dirty = 1; + +/** Most recently generated encoded signed v1 directory. (v1 auth dirservers + * only.) */ +static cached_dir_t *the_directory = NULL; + +/** For authoritative directories: the current (v1) network status. */ +static cached_dir_t the_runningrouters; + +/** Total number of routers with measured bandwidth; this is set by + * dirserv_count_measured_bws() before the loop in + * dirserv_generate_networkstatus_vote_obj() and checked by + * dirserv_get_credible_bandwidth() and + * dirserv_compute_performance_thresholds() */ +static int routers_with_measured_bw = 0; + +static void directory_remove_invalid(void); +static cached_dir_t *dirserv_regenerate_directory(void); +static char *format_versions_list(config_line_t *ln); +struct authdir_config_t; +static int add_fingerprint_to_dir(const char *nickname, const char *fp, + struct authdir_config_t *list); +static uint32_t +dirserv_get_status_impl(const char *fp, const char *nickname, + const char *address, + uint32_t addr, uint16_t or_port, + const char *platform, const char *contact, + const char **msg, int should_log); +static void clear_cached_dir(cached_dir_t *d); +static const signed_descriptor_t *get_signed_descriptor_by_fp( + const char *fp, + int extrainfo, + time_t publish_cutoff); +static was_router_added_t dirserv_add_extrainfo(extrainfo_t *ei, + const char **msg); +static uint32_t dirserv_get_bandwidth_for_router_kb(const routerinfo_t *ri); +static uint32_t dirserv_get_credible_bandwidth_kb(const routerinfo_t *ri); + +/************** Fingerprint handling code ************/ + +#define FP_NAMED 1 /**< Listed in fingerprint file. */ +#define FP_INVALID 2 /**< Believed invalid. */ +#define FP_REJECT 4 /**< We will not publish this router. */ +#define FP_BADDIR 8 /**< We'll tell clients to avoid using this as a dir. */ +#define FP_BADEXIT 16 /**< We'll tell clients not to use this as an exit. */ +#define FP_UNNAMED 32 /**< Another router has this name in fingerprint file. */ + +/** Encapsulate a nickname and an FP_* status; target of status_by_digest + * map. */ +typedef struct router_status_t { + char nickname[MAX_NICKNAME_LEN+1]; + uint32_t status; +} router_status_t; + +/** List of nickname-\>identity fingerprint mappings for all the routers + * that we name. Used to prevent router impersonation. */ +typedef struct authdir_config_t { + strmap_t *fp_by_name; /**< Map from lc nickname to fingerprint. */ + digestmap_t *status_by_digest; /**< Map from digest to router_status_t. */ +} authdir_config_t; + +/** Should be static; exposed for testing. */ +static authdir_config_t *fingerprint_list = NULL; + +/** Allocate and return a new, empty, authdir_config_t. */ +static authdir_config_t * +authdir_config_new(void) +{ + authdir_config_t *list = tor_malloc_zero(sizeof(authdir_config_t)); + list->fp_by_name = strmap_new(); + list->status_by_digest = digestmap_new(); + return list; +} + +/** Add the fingerprint fp for nickname to + * the smartlist of fingerprint_entry_t's list. Return 0 if it's + * new, or 1 if we replaced the old value. + */ +/* static */ int +add_fingerprint_to_dir(const char *nickname, const char *fp, + authdir_config_t *list) +{ + char *fingerprint; + char d[DIGEST_LEN]; + router_status_t *status; + tor_assert(nickname); + tor_assert(fp); + tor_assert(list); + + fingerprint = tor_strdup(fp); + tor_strstrip(fingerprint, " "); + if (base16_decode(d, DIGEST_LEN, fingerprint, strlen(fingerprint))) { + log_warn(LD_DIRSERV, "Couldn't decode fingerprint \"%s\"", + escaped(fp)); + tor_free(fingerprint); + return 0; + } + + if (!strcasecmp(nickname, UNNAMED_ROUTER_NICKNAME)) { + log_warn(LD_DIRSERV, "Tried to add a mapping for reserved nickname %s", + UNNAMED_ROUTER_NICKNAME); + tor_free(fingerprint); + return 0; + } + + status = digestmap_get(list->status_by_digest, d); + if (!status) { + status = tor_malloc_zero(sizeof(router_status_t)); + digestmap_set(list->status_by_digest, d, status); + } + + if (nickname[0] != '!') { + char *old_fp = strmap_get_lc(list->fp_by_name, nickname); + if (old_fp && !strcasecmp(fingerprint, old_fp)) { + tor_free(fingerprint); + } else { + tor_free(old_fp); + strmap_set_lc(list->fp_by_name, nickname, fingerprint); + } + status->status |= FP_NAMED; + strlcpy(status->nickname, nickname, sizeof(status->nickname)); + } else { + tor_free(fingerprint); + if (!strcasecmp(nickname, "!reject")) { + status->status |= FP_REJECT; + } else if (!strcasecmp(nickname, "!invalid")) { + status->status |= FP_INVALID; + } else if (!strcasecmp(nickname, "!baddir")) { + status->status |= FP_BADDIR; + } else if (!strcasecmp(nickname, "!badexit")) { + status->status |= FP_BADEXIT; + } + } + return 0; +} + +/** Add the nickname and fingerprint for this OR to the + * global list of recognized identity key fingerprints. */ +int +dirserv_add_own_fingerprint(const char *nickname, crypto_pk_t *pk) +{ + char fp[FINGERPRINT_LEN+1]; + if (crypto_pk_get_fingerprint(pk, fp, 0)<0) { + log_err(LD_BUG, "Error computing fingerprint"); + return -1; + } + if (!fingerprint_list) + fingerprint_list = authdir_config_new(); + add_fingerprint_to_dir(nickname, fp, fingerprint_list); + return 0; +} + +/** Load the nickname-\>fingerprint mappings stored in the approved-routers + * file. The file format is line-based, with each non-blank holding one + * nickname, some space, and a fingerprint for that nickname. On success, + * replace the current fingerprint list with the new list and return 0. On + * failure, leave the current fingerprint list untouched, and return -1. */ +int +dirserv_load_fingerprint_file(void) +{ + char *fname; + char *cf; + char *nickname, *fingerprint; + authdir_config_t *fingerprint_list_new; + int result; + config_line_t *front=NULL, *list; + const or_options_t *options = get_options(); + + fname = get_datadir_fname("approved-routers"); + log_info(LD_GENERAL, + "Reloading approved fingerprints from \"%s\"...", fname); + + cf = read_file_to_str(fname, RFTS_IGNORE_MISSING, NULL); + if (!cf) { + if (options->NamingAuthoritativeDir) { + log_warn(LD_FS, "Cannot open fingerprint file '%s'. Failing.", fname); + tor_free(fname); + return -1; + } else { + log_info(LD_FS, "Cannot open fingerprint file '%s'. That's ok.", fname); + tor_free(fname); + return 0; + } + } + tor_free(fname); + + result = config_get_lines(cf, &front, 0); + tor_free(cf); + if (result < 0) { + log_warn(LD_CONFIG, "Error reading from fingerprint file"); + return -1; + } + + fingerprint_list_new = authdir_config_new(); + + for (list=front; list; list=list->next) { + char digest_tmp[DIGEST_LEN]; + nickname = list->key; fingerprint = list->value; + if (strlen(nickname) > MAX_NICKNAME_LEN) { + log_notice(LD_CONFIG, + "Nickname '%s' too long in fingerprint file. Skipping.", + nickname); + continue; + } + if (!is_legal_nickname(nickname) && + strcasecmp(nickname, "!reject") && + strcasecmp(nickname, "!invalid") && + strcasecmp(nickname, "!badexit")) { + log_notice(LD_CONFIG, + "Invalid nickname '%s' in fingerprint file. Skipping.", + nickname); + continue; + } + tor_strstrip(fingerprint, " "); /* remove spaces */ + if (strlen(fingerprint) != HEX_DIGEST_LEN || + base16_decode(digest_tmp, sizeof(digest_tmp), + fingerprint, HEX_DIGEST_LEN) < 0) { + log_notice(LD_CONFIG, + "Invalid fingerprint (nickname '%s', " + "fingerprint %s). Skipping.", + nickname, fingerprint); + continue; + } + if (0==strcasecmp(nickname, DEFAULT_CLIENT_NICKNAME)) { + /* If you approved an OR called "client", then clients who use + * the default nickname could all be rejected. That's no good. */ + log_notice(LD_CONFIG, + "Authorizing nickname '%s' would break " + "many clients; skipping.", + DEFAULT_CLIENT_NICKNAME); + continue; + } + if (0==strcasecmp(nickname, UNNAMED_ROUTER_NICKNAME)) { + /* If you approved an OR called "unnamed", then clients will be + * confused. */ + log_notice(LD_CONFIG, + "Authorizing nickname '%s' is not allowed; skipping.", + UNNAMED_ROUTER_NICKNAME); + continue; + } + if (add_fingerprint_to_dir(nickname, fingerprint, fingerprint_list_new) + != 0) + log_notice(LD_CONFIG, "Duplicate nickname '%s'.", nickname); + } + + config_free_lines(front); + dirserv_free_fingerprint_list(); + fingerprint_list = fingerprint_list_new; + /* Delete any routers whose fingerprints we no longer recognize */ + directory_remove_invalid(); + return 0; +} + +/** Check whether router has a nickname/identity key combination that + * we recognize from the fingerprint list, or an IP we automatically act on + * according to our configuration. Return the appropriate router status. + * + * If the status is 'FP_REJECT' and msg is provided, set + * *msg to an explanation of why. */ +uint32_t +dirserv_router_get_status(const routerinfo_t *router, const char **msg) +{ + char d[DIGEST_LEN]; + + if (crypto_pk_get_digest(router->identity_pkey, d)) { + log_warn(LD_BUG,"Error computing fingerprint"); + if (msg) + *msg = "Bug: Error computing fingerprint"; + return FP_REJECT; + } + + return dirserv_get_status_impl(d, router->nickname, + router->address, + router->addr, router->or_port, + router->platform, router->contact_info, + msg, 1); +} + +/** Return true if there is no point in downloading the router described by + * rs because this directory would reject it. */ +int +dirserv_would_reject_router(const routerstatus_t *rs) +{ + uint32_t res; + + res = dirserv_get_status_impl(rs->identity_digest, rs->nickname, + "", /* address is only used in logs */ + rs->addr, rs->or_port, + NULL, NULL, + NULL, 0); + + return (res & FP_REJECT) != 0; +} + +/** Helper: Based only on the ID/Nickname combination, + * return FP_UNNAMED (unnamed), FP_NAMED (named), or 0 (neither). + */ +static uint32_t +dirserv_get_name_status(const char *id_digest, const char *nickname) +{ + char fp[HEX_DIGEST_LEN+1]; + char *fp_by_name; + + base16_encode(fp, sizeof(fp), id_digest, DIGEST_LEN); + + if ((fp_by_name = + strmap_get_lc(fingerprint_list->fp_by_name, nickname))) { + if (!strcasecmp(fp, fp_by_name)) { + return FP_NAMED; + } else { + return FP_UNNAMED; /* Wrong fingerprint. */ + } + } + return 0; +} + +/** Helper: As dirserv_router_get_status, but takes the router fingerprint + * (hex, no spaces), nickname, address (used for logging only), IP address, OR + * port, platform (logging only) and contact info (logging only) as arguments. + * + * If should_log is false, do not log messages. (There's not much point in + * logging that we're rejecting servers we'll not download.) + */ +static uint32_t +dirserv_get_status_impl(const char *id_digest, const char *nickname, + const char *address, + uint32_t addr, uint16_t or_port, + const char *platform, const char *contact, + const char **msg, int should_log) +{ + int reject_unlisted = get_options()->AuthDirRejectUnlisted; + uint32_t result; + router_status_t *status_by_digest; + + if (!fingerprint_list) + fingerprint_list = authdir_config_new(); + + if (should_log) + log_debug(LD_DIRSERV, "%d fingerprints, %d digests known.", + strmap_size(fingerprint_list->fp_by_name), + digestmap_size(fingerprint_list->status_by_digest)); + + /* Versions before Tor 0.2.2.35 have known security issues that + * make them unsuitable for the current network. */ + if (platform && !tor_version_as_new_as(platform,"0.2.2.35")) { + if (msg) + *msg = "Tor version is insecure or unsupported. Please upgrade!"; + return FP_REJECT; + } else if (platform && tor_version_as_new_as(platform,"0.2.3.0-alpha")) { + /* Versions from 0.2.3-alpha...0.2.3.9-alpha have known security + * issues that make them unusable for the current network */ + if (!tor_version_as_new_as(platform, "0.2.3.10-alpha")) { + if (msg) + *msg = "Tor version is insecure or unsupported. Please upgrade!"; + return FP_REJECT; + } + } + + result = dirserv_get_name_status(id_digest, nickname); + if (result & FP_NAMED) { + if (should_log) + log_debug(LD_DIRSERV,"Good fingerprint for '%s'",nickname); + } + if (result & FP_UNNAMED) { + if (should_log) { + char *esc_contact = esc_for_log(contact); + log_info(LD_DIRSERV, + "Mismatched fingerprint for '%s'. " + "ContactInfo '%s', platform '%s'.)", + nickname, + esc_contact, + platform ? escaped(platform) : ""); + tor_free(esc_contact); + } + if (msg) + *msg = "Rejected: There is already a named server with this nickname " + "and a different fingerprint."; + } + + status_by_digest = digestmap_get(fingerprint_list->status_by_digest, + id_digest); + if (status_by_digest) + result |= (status_by_digest->status & ~FP_NAMED); + + if (result & FP_REJECT) { + if (msg) + *msg = "Fingerprint is marked rejected"; + return FP_REJECT; + } else if (result & FP_INVALID) { + if (msg) + *msg = "Fingerprint is marked invalid"; + } + + if (authdir_policy_baddir_address(addr, or_port)) { + if (should_log) + log_info(LD_DIRSERV, + "Marking '%s' as bad directory because of address '%s'", + nickname, address); + result |= FP_BADDIR; + } + + if (authdir_policy_badexit_address(addr, or_port)) { + if (should_log) + log_info(LD_DIRSERV, "Marking '%s' as bad exit because of address '%s'", + nickname, address); + result |= FP_BADEXIT; + } + + if (!(result & FP_NAMED)) { + if (!authdir_policy_permits_address(addr, or_port)) { + if (should_log) + log_info(LD_DIRSERV, "Rejecting '%s' because of address '%s'", + nickname, address); + if (msg) + *msg = "Authdir is rejecting routers in this range."; + return FP_REJECT; + } + if (!authdir_policy_valid_address(addr, or_port)) { + if (should_log) + log_info(LD_DIRSERV, "Not marking '%s' valid because of address '%s'", + nickname, address); + result |= FP_INVALID; + } + if (reject_unlisted) { + if (msg) + *msg = "Authdir rejects unknown routers."; + return FP_REJECT; + } + } + + return result; +} + +/** If we are an authoritative dirserver, and the list of approved + * servers contains one whose identity key digest is digest, + * return that router's nickname. Otherwise return NULL. */ +const char * +dirserv_get_nickname_by_digest(const char *digest) +{ + router_status_t *status; + if (!fingerprint_list) + return NULL; + tor_assert(digest); + + status = digestmap_get(fingerprint_list->status_by_digest, digest); + return status ? status->nickname : NULL; +} + +/** Clear the current fingerprint list. */ +void +dirserv_free_fingerprint_list(void) +{ + if (!fingerprint_list) + return; + + strmap_free(fingerprint_list->fp_by_name, tor_free_); + digestmap_free(fingerprint_list->status_by_digest, tor_free_); + tor_free(fingerprint_list); +} + +/* + * Descriptor list + */ + +/** Return -1 if ri has a private or otherwise bad address, + * unless we're configured to not care. Return 0 if all ok. */ +static int +dirserv_router_has_valid_address(routerinfo_t *ri) +{ + struct in_addr iaddr; + if (get_options()->DirAllowPrivateAddresses) + return 0; /* whatever it is, we're fine with it */ + if (!tor_inet_aton(ri->address, &iaddr)) { + log_info(LD_DIRSERV,"Router %s published non-IP address '%s'. Refusing.", + router_describe(ri), + ri->address); + return -1; + } + if (is_internal_IP(ntohl(iaddr.s_addr), 0)) { + log_info(LD_DIRSERV, + "Router %s published internal IP address '%s'. Refusing.", + router_describe(ri), ri->address); + return -1; /* it's a private IP, we should reject it */ + } + return 0; +} + +/** Check whether we, as a directory server, want to accept ri. If so, + * set its is_valid,named,running fields and return 0. Otherwise, return -1. + * + * If the router is rejected, set *msg to an explanation of why. + * + * If complain then explain at log-level 'notice' why we refused + * a descriptor; else explain at log-level 'info'. + */ +int +authdir_wants_to_reject_router(routerinfo_t *ri, const char **msg, + int complain, int *valid_out) +{ + /* Okay. Now check whether the fingerprint is recognized. */ + uint32_t status = dirserv_router_get_status(ri, msg); + time_t now; + int severity = (complain && ri->contact_info) ? LOG_NOTICE : LOG_INFO; + tor_assert(msg); + if (status & FP_REJECT) + return -1; /* msg is already set. */ + + /* Is there too much clock skew? */ + now = time(NULL); + if (ri->cache_info.published_on > now+ROUTER_ALLOW_SKEW) { + log_fn(severity, LD_DIRSERV, "Publication time for %s is too " + "far (%d minutes) in the future; possible clock skew. Not adding " + "(%s)", + router_describe(ri), + (int)((ri->cache_info.published_on-now)/60), + esc_router_info(ri)); + *msg = "Rejected: Your clock is set too far in the future, or your " + "timezone is not correct."; + return -1; + } + if (ri->cache_info.published_on < now-ROUTER_MAX_AGE_TO_PUBLISH) { + log_fn(severity, LD_DIRSERV, + "Publication time for %s is too far " + "(%d minutes) in the past. Not adding (%s)", + router_describe(ri), + (int)((now-ri->cache_info.published_on)/60), + esc_router_info(ri)); + *msg = "Rejected: Server is expired, or your clock is too far in the past," + " or your timezone is not correct."; + return -1; + } + if (dirserv_router_has_valid_address(ri) < 0) { + log_fn(severity, LD_DIRSERV, + "Router %s has invalid address '%s'. " + "Not adding (%s).", + router_describe(ri), + ri->address, + esc_router_info(ri)); + *msg = "Rejected: Address is not an IP, or IP is a private address."; + return -1; + } + + *valid_out = ! (status & FP_INVALID); + + return 0; +} + +/** Update the relevant flags of node based on our opinion as a + * directory authority in authstatus, as returned by + * dirserv_router_get_status or equivalent. */ +void +dirserv_set_node_flags_from_authoritative_status(node_t *node, + uint32_t authstatus) +{ + node->is_valid = (authstatus & FP_INVALID) ? 0 : 1; + node->is_bad_directory = (authstatus & FP_BADDIR) ? 1 : 0; + node->is_bad_exit = (authstatus & FP_BADEXIT) ? 1 : 0; +} + +/** True iff a is more severe than b. */ +static int +WRA_MORE_SEVERE(was_router_added_t a, was_router_added_t b) +{ + return a < b; +} + +/** As for dirserv_add_descriptor(), but accepts multiple documents, and + * returns the most severe error that occurred for any one of them. */ +was_router_added_t +dirserv_add_multiple_descriptors(const char *desc, uint8_t purpose, + const char *source, + const char **msg) +{ + was_router_added_t r, r_tmp; + const char *msg_out; + smartlist_t *list; + const char *s; + int n_parsed = 0; + time_t now = time(NULL); + char annotation_buf[ROUTER_ANNOTATION_BUF_LEN]; + char time_buf[ISO_TIME_LEN+1]; + int general = purpose == ROUTER_PURPOSE_GENERAL; + tor_assert(msg); + + r=ROUTER_ADDED_SUCCESSFULLY; /*Least severe return value. */ + + format_iso_time(time_buf, now); + if (tor_snprintf(annotation_buf, sizeof(annotation_buf), + "@uploaded-at %s\n" + "@source %s\n" + "%s%s%s", time_buf, escaped(source), + !general ? "@purpose " : "", + !general ? router_purpose_to_string(purpose) : "", + !general ? "\n" : "")<0) { + *msg = "Couldn't format annotations"; + return -1; + } + + s = desc; + list = smartlist_new(); + if (!router_parse_list_from_string(&s, NULL, list, SAVED_NOWHERE, 0, 0, + annotation_buf)) { + SMARTLIST_FOREACH(list, routerinfo_t *, ri, { + msg_out = NULL; + tor_assert(ri->purpose == purpose); + r_tmp = dirserv_add_descriptor(ri, &msg_out, source); + if (WRA_MORE_SEVERE(r_tmp, r)) { + r = r_tmp; + *msg = msg_out; + } + }); + } + n_parsed += smartlist_len(list); + smartlist_clear(list); + + s = desc; + if (!router_parse_list_from_string(&s, NULL, list, SAVED_NOWHERE, 1, 0, + NULL)) { + SMARTLIST_FOREACH(list, extrainfo_t *, ei, { + msg_out = NULL; + + r_tmp = dirserv_add_extrainfo(ei, &msg_out); + if (WRA_MORE_SEVERE(r_tmp, r)) { + r = r_tmp; + *msg = msg_out; + } + }); + } + n_parsed += smartlist_len(list); + smartlist_free(list); + + if (! *msg) { + if (!n_parsed) { + *msg = "No descriptors found in your POST."; + if (WRA_WAS_ADDED(r)) + r = ROUTER_WAS_NOT_NEW; + } else { + *msg = "(no message)"; + } + } + + return r; +} + +/** Examine the parsed server descriptor in ri and maybe insert it into + * the list of server descriptors. Set *msg to a message that should be + * passed back to the origin of this descriptor, or NULL if there is no such + * message. Use source to produce better log messages. + * + * Return the status of the operation + * + * This function is only called when fresh descriptors are posted, not when + * we re-load the cache. + */ +was_router_added_t +dirserv_add_descriptor(routerinfo_t *ri, const char **msg, const char *source) +{ + was_router_added_t r; + routerinfo_t *ri_old; + char *desc, *nickname; + size_t desclen = 0; + *msg = NULL; + + /* If it's too big, refuse it now. Otherwise we'll cache it all over the + * network and it'll clog everything up. */ + if (ri->cache_info.signed_descriptor_len > MAX_DESCRIPTOR_UPLOAD_SIZE) { + log_notice(LD_DIR, "Somebody attempted to publish a router descriptor '%s'" + " (source: %s) with size %d. Either this is an attack, or the " + "MAX_DESCRIPTOR_UPLOAD_SIZE (%d) constant is too low.", + ri->nickname, source, (int)ri->cache_info.signed_descriptor_len, + MAX_DESCRIPTOR_UPLOAD_SIZE); + *msg = "Router descriptor was too large."; + control_event_or_authdir_new_descriptor("REJECTED", + ri->cache_info.signed_descriptor_body, + ri->cache_info.signed_descriptor_len, *msg); + routerinfo_free(ri); + return ROUTER_AUTHDIR_REJECTS; + } + + /* Check whether this descriptor is semantically identical to the last one + * from this server. (We do this here and not in router_add_to_routerlist + * because we want to be able to accept the newest router descriptor that + * another authority has, so we all converge on the same one.) */ + ri_old = router_get_mutable_by_digest(ri->cache_info.identity_digest); + if (ri_old && ri_old->cache_info.published_on < ri->cache_info.published_on + && router_differences_are_cosmetic(ri_old, ri) + && !router_is_me(ri)) { + log_info(LD_DIRSERV, + "Not replacing descriptor from %s (source: %s); " + "differences are cosmetic.", + router_describe(ri), source); + *msg = "Not replacing router descriptor; no information has changed since " + "the last one with this identity."; + control_event_or_authdir_new_descriptor("DROPPED", + ri->cache_info.signed_descriptor_body, + ri->cache_info.signed_descriptor_len, *msg); + routerinfo_free(ri); + return ROUTER_WAS_NOT_NEW; + } + + /* Make a copy of desc, since router_add_to_routerlist might free + * ri and its associated signed_descriptor_t. */ + desclen = ri->cache_info.signed_descriptor_len; + desc = tor_strndup(ri->cache_info.signed_descriptor_body, desclen); + nickname = tor_strdup(ri->nickname); + + /* Tell if we're about to need to launch a test if we add this. */ + ri->needs_retest_if_added = + dirserv_should_launch_reachability_test(ri, ri_old); + + r = router_add_to_routerlist(ri, msg, 0, 0); + if (!WRA_WAS_ADDED(r)) { + /* unless the routerinfo was fine, just out-of-date */ + if (WRA_WAS_REJECTED(r)) + control_event_or_authdir_new_descriptor("REJECTED", desc, desclen, *msg); + log_info(LD_DIRSERV, + "Did not add descriptor from '%s' (source: %s): %s.", + nickname, source, *msg ? *msg : "(no message)"); + } else { + smartlist_t *changed; + control_event_or_authdir_new_descriptor("ACCEPTED", desc, desclen, *msg); + + changed = smartlist_new(); + smartlist_add(changed, ri); + routerlist_descriptors_added(changed, 0); + smartlist_free(changed); + if (!*msg) { + *msg = "Descriptor accepted"; + } + log_info(LD_DIRSERV, + "Added descriptor from '%s' (source: %s): %s.", + nickname, source, *msg); + } + tor_free(desc); + tor_free(nickname); + return r; +} + +/** As dirserv_add_descriptor, but for an extrainfo_t ei. */ +static was_router_added_t +dirserv_add_extrainfo(extrainfo_t *ei, const char **msg) +{ + const routerinfo_t *ri; + int r; + tor_assert(msg); + *msg = NULL; + + ri = router_get_by_id_digest(ei->cache_info.identity_digest); + if (!ri) { + *msg = "No corresponding router descriptor for extra-info descriptor"; + extrainfo_free(ei); + return ROUTER_BAD_EI; + } + + /* If it's too big, refuse it now. Otherwise we'll cache it all over the + * network and it'll clog everything up. */ + if (ei->cache_info.signed_descriptor_len > MAX_EXTRAINFO_UPLOAD_SIZE) { + log_notice(LD_DIR, "Somebody attempted to publish an extrainfo " + "with size %d. Either this is an attack, or the " + "MAX_EXTRAINFO_UPLOAD_SIZE (%d) constant is too low.", + (int)ei->cache_info.signed_descriptor_len, + MAX_EXTRAINFO_UPLOAD_SIZE); + *msg = "Extrainfo document was too large"; + extrainfo_free(ei); + return ROUTER_BAD_EI; + } + + if ((r = routerinfo_incompatible_with_extrainfo(ri, ei, NULL, msg))) { + extrainfo_free(ei); + return r < 0 ? ROUTER_WAS_NOT_NEW : ROUTER_BAD_EI; + } + router_add_extrainfo_to_routerlist(ei, msg, 0, 0); + return ROUTER_ADDED_SUCCESSFULLY; +} + +/** Remove all descriptors whose nicknames or fingerprints no longer + * are allowed by our fingerprint list. (Descriptors that used to be + * good can become bad when we reload the fingerprint list.) + */ +static void +directory_remove_invalid(void) +{ + int changed = 0; + routerlist_t *rl = router_get_routerlist(); + smartlist_t *nodes = smartlist_new(); + smartlist_add_all(nodes, nodelist_get_list()); + + SMARTLIST_FOREACH_BEGIN(nodes, node_t *, node) { + const char *msg; + routerinfo_t *ent = node->ri; + char description[NODE_DESC_BUF_LEN]; + uint32_t r; + if (!ent) + continue; + r = dirserv_router_get_status(ent, &msg); + router_get_description(description, ent); + if (r & FP_REJECT) { + log_info(LD_DIRSERV, "Router %s is now rejected: %s", + description, msg?msg:""); + routerlist_remove(rl, ent, 0, time(NULL)); + changed = 1; + continue; + } +#if 0 + if (bool_neq((r & FP_NAMED), ent->auth_says_is_named)) { + log_info(LD_DIRSERV, + "Router %s is now %snamed.", description, + (r&FP_NAMED)?"":"un"); + ent->is_named = (r&FP_NAMED)?1:0; + changed = 1; + } + if (bool_neq((r & FP_UNNAMED), ent->auth_says_is_unnamed)) { + log_info(LD_DIRSERV, + "Router '%s' is now %snamed. (FP_UNNAMED)", description, + (r&FP_NAMED)?"":"un"); + ent->is_named = (r&FP_NUNAMED)?0:1; + changed = 1; + } +#endif + if (bool_neq((r & FP_INVALID), !node->is_valid)) { + log_info(LD_DIRSERV, "Router '%s' is now %svalid.", description, + (r&FP_INVALID) ? "in" : ""); + node->is_valid = (r&FP_INVALID)?0:1; + changed = 1; + } + if (bool_neq((r & FP_BADDIR), node->is_bad_directory)) { + log_info(LD_DIRSERV, "Router '%s' is now a %s directory", description, + (r & FP_BADDIR) ? "bad" : "good"); + node->is_bad_directory = (r&FP_BADDIR) ? 1: 0; + changed = 1; + } + if (bool_neq((r & FP_BADEXIT), node->is_bad_exit)) { + log_info(LD_DIRSERV, "Router '%s' is now a %s exit", description, + (r & FP_BADEXIT) ? "bad" : "good"); + node->is_bad_exit = (r&FP_BADEXIT) ? 1: 0; + changed = 1; + } + } SMARTLIST_FOREACH_END(node); + if (changed) + directory_set_dirty(); + + routerlist_assert_ok(rl); + smartlist_free(nodes); +} + +/** Mark the directory as dirty -- when we're next asked for a + * directory, we will rebuild it instead of reusing the most recently + * generated one. + */ +void +directory_set_dirty(void) +{ + time_t now = time(NULL); + int set_v1_dirty=0; + + /* Regenerate stubs only every 8 hours. + * XXXX It would be nice to generate less often, but these are just + * stubs: it doesn't matter. */ +#define STUB_REGENERATE_INTERVAL (8*60*60) + if (!the_directory || !the_runningrouters.dir) + set_v1_dirty = 1; + else if (the_directory->published < now - STUB_REGENERATE_INTERVAL || + the_runningrouters.published < now - STUB_REGENERATE_INTERVAL) + set_v1_dirty = 1; + + if (set_v1_dirty) { + if (!the_directory_is_dirty) + the_directory_is_dirty = now; + if (!runningrouters_is_dirty) + runningrouters_is_dirty = now; + } +} + +/** + * Allocate and return a description of the status of the server desc, + * for use in a v1-style router-status line. The server is listed + * as running iff is_live is true. + */ +static char * +list_single_server_status(const routerinfo_t *desc, int is_live) +{ + char buf[MAX_NICKNAME_LEN+HEX_DIGEST_LEN+4]; /* !nickname=$hexdigest\0 */ + char *cp; + const node_t *node; + + tor_assert(desc); + + cp = buf; + if (!is_live) { + *cp++ = '!'; + } + node = node_get_by_id(desc->cache_info.identity_digest); + if (node && node->is_valid) { + strlcpy(cp, desc->nickname, sizeof(buf)-(cp-buf)); + cp += strlen(cp); + *cp++ = '='; + } + *cp++ = '$'; + base16_encode(cp, HEX_DIGEST_LEN+1, desc->cache_info.identity_digest, + DIGEST_LEN); + return tor_strdup(buf); +} + +/* DOCDOC running_long_enough_to_decide_unreachable */ +static INLINE int +running_long_enough_to_decide_unreachable(void) +{ + return time_of_process_start + + get_options()->TestingAuthDirTimeToLearnReachability < approx_time(); +} + +/** Each server needs to have passed a reachability test no more + * than this number of seconds ago, or he is listed as down in + * the directory. */ +#define REACHABLE_TIMEOUT (45*60) + +/** If we tested a router and found it reachable _at least this long_ after it + * declared itself hibernating, it is probably done hibernating and we just + * missed a descriptor from it. */ +#define HIBERNATION_PUBLICATION_SKEW (60*60) + +/** Treat a router as alive if + * - It's me, and I'm not hibernating. + * or - We've found it reachable recently. */ +void +dirserv_set_router_is_running(routerinfo_t *router, time_t now) +{ + /*XXXX024 This function is a mess. Separate out the part that calculates + whether it's reachable and the part that tells rephist that the router was + unreachable. + */ + int answer; + const or_options_t *options = get_options(); + node_t *node = node_get_mutable_by_id(router->cache_info.identity_digest); + tor_assert(node); + + if (router_is_me(router)) { + /* We always know if we are down ourselves. */ + answer = ! we_are_hibernating(); + } else if (router->is_hibernating && + (router->cache_info.published_on + + HIBERNATION_PUBLICATION_SKEW) > node->last_reachable) { + /* A hibernating router is down unless we (somehow) had contact with it + * since it declared itself to be hibernating. */ + answer = 0; + } else if (options->AssumeReachable) { + /* If AssumeReachable, everybody is up unless they say they are down! */ + answer = 1; + } else { + /* Otherwise, a router counts as up if we found all announced OR + ports reachable in the last REACHABLE_TIMEOUT seconds. + + XXX prop186 For now there's always one IPv4 and at most one + IPv6 OR port. + + If we're not on IPv6, don't consider reachability of potential + IPv6 OR port since that'd kill all dual stack relays until a + majority of the dir auths have IPv6 connectivity. */ + answer = (now < node->last_reachable + REACHABLE_TIMEOUT && + (options->AuthDirHasIPv6Connectivity != 1 || + tor_addr_is_null(&router->ipv6_addr) || + now < node->last_reachable6 + REACHABLE_TIMEOUT)); + } + + if (!answer && running_long_enough_to_decide_unreachable()) { + /* Not considered reachable. tell rephist about that. + + Because we launch a reachability test for each router every + REACHABILITY_TEST_CYCLE_PERIOD seconds, then the router has probably + been down since at least that time after we last successfully reached + it. + + XXX ipv6 + */ + time_t when = now; + if (node->last_reachable && + node->last_reachable + REACHABILITY_TEST_CYCLE_PERIOD < now) + when = node->last_reachable + REACHABILITY_TEST_CYCLE_PERIOD; + rep_hist_note_router_unreachable(router->cache_info.identity_digest, when); + } + + node->is_running = answer; +} + +/** Based on the routerinfo_ts in routers, allocate the + * contents of a v1-style router-status line, and store it in + * *router_status_out. Return 0 on success, -1 on failure. + * + * If for_controller is true, include the routers with very old descriptors. + */ +int +list_server_status_v1(smartlist_t *routers, char **router_status_out, + int for_controller) +{ + /* List of entries in a router-status style: An optional !, then an optional + * equals-suffixed nickname, then a dollar-prefixed hexdigest. */ + smartlist_t *rs_entries; + time_t now = time(NULL); + time_t cutoff = now - ROUTER_MAX_AGE_TO_PUBLISH; + const or_options_t *options = get_options(); + /* We include v2 dir auths here too, because they need to answer + * controllers. Eventually we'll deprecate this whole function; + * see also networkstatus_getinfo_by_purpose(). */ + int authdir = authdir_mode_publishes_statuses(options); + tor_assert(router_status_out); + + rs_entries = smartlist_new(); + + SMARTLIST_FOREACH_BEGIN(routers, routerinfo_t *, ri) { + const node_t *node = node_get_by_id(ri->cache_info.identity_digest); + tor_assert(node); + if (authdir) { + /* Update router status in routerinfo_t. */ + dirserv_set_router_is_running(ri, now); + } + if (for_controller) { + char name_buf[MAX_VERBOSE_NICKNAME_LEN+2]; + char *cp = name_buf; + if (!node->is_running) + *cp++ = '!'; + router_get_verbose_nickname(cp, ri); + smartlist_add(rs_entries, tor_strdup(name_buf)); + } else if (ri->cache_info.published_on >= cutoff) { + smartlist_add(rs_entries, list_single_server_status(ri, + node->is_running)); + } + } SMARTLIST_FOREACH_END(ri); + + *router_status_out = smartlist_join_strings(rs_entries, " ", 0, NULL); + + SMARTLIST_FOREACH(rs_entries, char *, cp, tor_free(cp)); + smartlist_free(rs_entries); + + return 0; +} + +/** Given a (possibly empty) list of config_line_t, each line of which contains + * a list of comma-separated version numbers surrounded by optional space, + * allocate and return a new string containing the version numbers, in order, + * separated by commas. Used to generate Recommended(Client|Server)?Versions + */ +static char * +format_versions_list(config_line_t *ln) +{ + smartlist_t *versions; + char *result; + versions = smartlist_new(); + for ( ; ln; ln = ln->next) { + smartlist_split_string(versions, ln->value, ",", + SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); + } + sort_version_list(versions, 1); + result = smartlist_join_strings(versions,",",0,NULL); + SMARTLIST_FOREACH(versions,char *,s,tor_free(s)); + smartlist_free(versions); + return result; +} + +/** Return 1 if ri's descriptor is "active" -- running, valid, + * not hibernating, and not too old. Else return 0. + */ +static int +router_is_active(const routerinfo_t *ri, const node_t *node, time_t now) +{ + time_t cutoff = now - ROUTER_MAX_AGE_TO_PUBLISH; + if (ri->cache_info.published_on < cutoff) + return 0; + if (!node->is_running || !node->is_valid || ri->is_hibernating) + return 0; + return 1; +} + +/** Generate a new v1 directory and write it into a newly allocated string. + * Point *dir_out to the allocated string. Sign the + * directory with private_key. Return 0 on success, -1 on + * failure. If complete is set, give us all the descriptors; + * otherwise leave out non-running and non-valid ones. + */ +int +dirserv_dump_directory_to_string(char **dir_out, + crypto_pk_t *private_key) +{ + /* XXXX 024 Get rid of this function if we can confirm that nobody's + * fetching these any longer */ + char *cp; + char *identity_pkey; /* Identity key, DER64-encoded. */ + char *recommended_versions; + char digest[DIGEST_LEN]; + char published[ISO_TIME_LEN+1]; + char *buf = NULL; + size_t buf_len; + size_t identity_pkey_len; + time_t now = time(NULL); + + tor_assert(dir_out); + *dir_out = NULL; + + if (crypto_pk_write_public_key_to_string(private_key,&identity_pkey, + &identity_pkey_len)<0) { + log_warn(LD_BUG,"write identity_pkey to string failed!"); + return -1; + } + + recommended_versions = + format_versions_list(get_options()->RecommendedVersions); + + format_iso_time(published, now); + + buf_len = 2048+strlen(recommended_versions); + + buf = tor_malloc(buf_len); + /* We'll be comparing against buf_len throughout the rest of the + function, though strictly speaking we shouldn't be able to exceed + it. This is C, after all, so we may as well check for buffer + overruns.*/ + + tor_snprintf(buf, buf_len, + "signed-directory\n" + "published %s\n" + "recommended-software %s\n" + "router-status %s\n" + "dir-signing-key\n%s\n", + published, recommended_versions, "", + identity_pkey); + + tor_free(recommended_versions); + tor_free(identity_pkey); + + cp = buf + strlen(buf); + *cp = '\0'; + + /* These multiple strlcat calls are inefficient, but dwarfed by the RSA + signature. */ + if (strlcat(buf, "directory-signature ", buf_len) >= buf_len) + goto truncated; + if (strlcat(buf, get_options()->Nickname, buf_len) >= buf_len) + goto truncated; + if (strlcat(buf, "\n", buf_len) >= buf_len) + goto truncated; + + if (router_get_dir_hash(buf,digest)) { + log_warn(LD_BUG,"couldn't compute digest"); + tor_free(buf); + return -1; + } + note_crypto_pk_op(SIGN_DIR); + if (router_append_dirobj_signature(buf,buf_len,digest,DIGEST_LEN, + private_key)<0) { + tor_free(buf); + return -1; + } + + *dir_out = buf; + return 0; + truncated: + log_warn(LD_BUG,"tried to exceed string length."); + tor_free(buf); + return -1; +} + +/********************************************************************/ + +/* A set of functions to answer questions about how we'd like to behave + * as a directory mirror/client. */ + +/** Return 1 if we fetch our directory material directly from the + * authorities, rather than from a mirror. */ +int +directory_fetches_from_authorities(const or_options_t *options) +{ + const routerinfo_t *me; + uint32_t addr; + int refuseunknown; + if (options->FetchDirInfoEarly) + return 1; + if (options->BridgeRelay == 1) + return 0; + if (server_mode(options) && router_pick_published_address(options, &addr)<0) + return 1; /* we don't know our IP address; ask an authority. */ + refuseunknown = ! router_my_exit_policy_is_reject_star() && + should_refuse_unknown_exits(options); + if (!options->DirPort_set && !refuseunknown) + return 0; + if (!server_mode(options) || !advertised_server_mode()) + return 0; + me = router_get_my_routerinfo(); + if (!me || (!me->dir_port && !refuseunknown)) + return 0; /* if dirport not advertised, return 0 too */ + return 1; +} + +/** Return 1 if we should fetch new networkstatuses, descriptors, etc + * on the "mirror" schedule rather than the "client" schedule. + */ +int +directory_fetches_dir_info_early(const or_options_t *options) +{ + return directory_fetches_from_authorities(options); +} + +/** Return 1 if we should fetch new networkstatuses, descriptors, etc + * on a very passive schedule -- waiting long enough for ordinary clients + * to probably have the info we want. These would include bridge users, + * and maybe others in the future e.g. if a Tor client uses another Tor + * client as a directory guard. + */ +int +directory_fetches_dir_info_later(const or_options_t *options) +{ + return options->UseBridges != 0; +} + +/** Return true iff we want to fetch and keep certificates for authorities + * that we don't acknowledge as aurthorities ourself. + */ +int +directory_caches_unknown_auth_certs(const or_options_t *options) +{ + return options->DirPort_set || options->BridgeRelay; +} + +/** Return 1 if we want to keep descriptors, networkstatuses, etc around + * and we're willing to serve them to others. Else return 0. + */ +int +directory_caches_dir_info(const or_options_t *options) +{ + if (options->BridgeRelay || options->DirPort_set) + return 1; + if (!server_mode(options) || !advertised_server_mode()) + return 0; + /* We need an up-to-date view of network info if we're going to try to + * block exit attempts from unknown relays. */ + return ! router_my_exit_policy_is_reject_star() && + should_refuse_unknown_exits(options); +} + +/** Return 1 if we want to allow remote people to ask us directory + * requests via the "begin_dir" interface, which doesn't require + * having any separate port open. */ +int +directory_permits_begindir_requests(const or_options_t *options) +{ + return options->BridgeRelay != 0 || options->DirPort_set; +} + +/** Return 1 if we want to allow controllers to ask us directory + * requests via the controller interface, which doesn't require + * having any separate port open. */ +int +directory_permits_controller_requests(const or_options_t *options) +{ + return options->DirPort_set; +} + +/** Return 1 if we have no need to fetch new descriptors. This generally + * happens when we're not a dir cache and we haven't built any circuits + * lately. + */ +int +directory_too_idle_to_fetch_descriptors(const or_options_t *options, + time_t now) +{ + return !directory_caches_dir_info(options) && + !options->FetchUselessDescriptors && + rep_hist_circbuilding_dormant(now); +} + +/********************************************************************/ + +/* Used only by non-v1-auth dirservers: The v1 directory and + * runningrouters we'll serve when requested. */ + +/** The v1 directory we'll serve (as a cache or as an authority) if + * requested. */ +static cached_dir_t *cached_directory = NULL; +/** The v1 runningrouters document we'll serve (as a cache or as an authority) + * if requested. */ +static cached_dir_t cached_runningrouters; + +/** Map from flavor name to the cached_dir_t for the v3 consensuses that we're + * currently serving. */ +static strmap_t *cached_consensuses = NULL; + +/** Possibly replace the contents of d with the value of + * directory published on when, unless when is older than + * the last value, or too far in the future. + * + * Does not copy directory; frees it if it isn't used. + */ +static void +set_cached_dir(cached_dir_t *d, char *directory, time_t when) +{ + time_t now = time(NULL); + if (when<=d->published) { + log_info(LD_DIRSERV, "Ignoring old directory; not caching."); + tor_free(directory); + } else if (when>=now+ROUTER_MAX_AGE_TO_PUBLISH) { + log_info(LD_DIRSERV, "Ignoring future directory; not caching."); + tor_free(directory); + } else { + /* if (when>d->published && whendir); + d->dir = directory; + d->dir_len = strlen(directory); + tor_free(d->dir_z); + if (tor_gzip_compress(&(d->dir_z), &(d->dir_z_len), d->dir, d->dir_len, + ZLIB_METHOD)) { + log_warn(LD_BUG,"Error compressing cached directory"); + } + d->published = when; + } +} + +/** Decrement the reference count on d, and free it if it no longer has + * any references. */ +void +cached_dir_decref(cached_dir_t *d) +{ + if (!d || --d->refcnt > 0) + return; + clear_cached_dir(d); + tor_free(d); +} + +/** Allocate and return a new cached_dir_t containing the string s, + * published at published. */ +cached_dir_t * +new_cached_dir(char *s, time_t published) +{ + cached_dir_t *d = tor_malloc_zero(sizeof(cached_dir_t)); + d->refcnt = 1; + d->dir = s; + d->dir_len = strlen(s); + d->published = published; + if (tor_gzip_compress(&(d->dir_z), &(d->dir_z_len), d->dir, d->dir_len, + ZLIB_METHOD)) { + log_warn(LD_BUG, "Error compressing directory"); + } + return d; +} + +/** Remove all storage held in d, but do not free d itself. */ +static void +clear_cached_dir(cached_dir_t *d) +{ + tor_free(d->dir); + tor_free(d->dir_z); + memset(d, 0, sizeof(cached_dir_t)); +} + +/** Free all storage held by the cached_dir_t in d. */ +static void +free_cached_dir_(void *_d) +{ + cached_dir_t *d; + if (!_d) + return; + + d = (cached_dir_t *)_d; + cached_dir_decref(d); +} + +/** If we have no cached v1 directory, or it is older than published, + * then replace it with directory, published at published. + * + * If published is too old, do nothing. + * + * If is_running_routers, this is really a v1 running_routers + * document rather than a v1 directory. + */ +static void +dirserv_set_cached_directory(const char *directory, time_t published) +{ + + cached_dir_decref(cached_directory); + cached_directory = new_cached_dir(tor_strdup(directory), published); +} + +/** Replace the v3 consensus networkstatus of type flavor_name that + * we're serving with networkstatus, published at published. No + * validation is performed. */ +void +dirserv_set_cached_consensus_networkstatus(const char *networkstatus, + const char *flavor_name, + const digests_t *digests, + time_t published) +{ + cached_dir_t *new_networkstatus; + cached_dir_t *old_networkstatus; + if (!cached_consensuses) + cached_consensuses = strmap_new(); + + new_networkstatus = new_cached_dir(tor_strdup(networkstatus), published); + memcpy(&new_networkstatus->digests, digests, sizeof(digests_t)); + old_networkstatus = strmap_set(cached_consensuses, flavor_name, + new_networkstatus); + if (old_networkstatus) + cached_dir_decref(old_networkstatus); +} + +/** Remove any v1 info from the directory cache that was published + * too long ago. */ +void +dirserv_clear_old_v1_info(time_t now) +{ + if (cached_directory && + cached_directory->published < (now - MAX_V1_DIRECTORY_AGE)) { + cached_dir_decref(cached_directory); + cached_directory = NULL; + } + if (cached_runningrouters.published < (now - MAX_V1_RR_AGE)) { + clear_cached_dir(&cached_runningrouters); + } +} + +/** Helper: If we're an authority for the right directory version (v1) + * (based on auth_type), try to regenerate + * auth_src as appropriate and return it, falling back to cache_src on + * failure. If we're a cache, simply return cache_src. + */ +static cached_dir_t * +dirserv_pick_cached_dir_obj(cached_dir_t *cache_src, + cached_dir_t *auth_src, + time_t dirty, cached_dir_t *(*regenerate)(void), + const char *name, + dirinfo_type_t auth_type) +{ + const or_options_t *options = get_options(); + int authority = (auth_type == V1_DIRINFO && authdir_mode_v1(options)); + + if (!authority || authdir_mode_bridge(options)) { + return cache_src; + } else { + /* We're authoritative. */ + if (regenerate != NULL) { + if (dirty && dirty + DIR_REGEN_SLACK_TIME < time(NULL)) { + if (!(auth_src = regenerate())) { + log_err(LD_BUG, "Couldn't generate %s?", name); + exit(1); + } + } else { + log_info(LD_DIRSERV, "The %s is still clean; reusing.", name); + } + } + return auth_src ? auth_src : cache_src; + } +} + +/** Return the most recently generated encoded signed v1 directory, + * generating a new one as necessary. If not a v1 authoritative directory + * may return NULL if no directory is yet cached. */ +cached_dir_t * +dirserv_get_directory(void) +{ + return dirserv_pick_cached_dir_obj(cached_directory, the_directory, + the_directory_is_dirty, + dirserv_regenerate_directory, + "v1 server directory", V1_DIRINFO); +} + +/** Only called by v1 auth dirservers. + * Generate a fresh v1 directory; set the_directory and return a pointer + * to the new value. + */ +static cached_dir_t * +dirserv_regenerate_directory(void) +{ + /* XXXX 024 Get rid of this function if we can confirm that nobody's + * fetching these any longer */ + char *new_directory=NULL; + + if (dirserv_dump_directory_to_string(&new_directory, + get_server_identity_key())) { + log_warn(LD_BUG, "Error creating directory."); + tor_free(new_directory); + return NULL; + } + cached_dir_decref(the_directory); + the_directory = new_cached_dir(new_directory, time(NULL)); + log_info(LD_DIRSERV,"New directory (size %d) has been built.", + (int)the_directory->dir_len); + log_debug(LD_DIRSERV,"New directory (size %d):\n%s", + (int)the_directory->dir_len, the_directory->dir); + + the_directory_is_dirty = 0; + + /* Save the directory to disk so we re-load it quickly on startup. + */ + dirserv_set_cached_directory(the_directory->dir, time(NULL)); + + return the_directory; +} + +/** Only called by v1 auth dirservers. + * Replace the current running-routers list with a newly generated one. */ +static cached_dir_t * +generate_runningrouters(void) +{ + char *s=NULL; + char digest[DIGEST_LEN]; + char published[ISO_TIME_LEN+1]; + size_t len; + crypto_pk_t *private_key = get_server_identity_key(); + char *identity_pkey; /* Identity key, DER64-encoded. */ + size_t identity_pkey_len; + + if (crypto_pk_write_public_key_to_string(private_key,&identity_pkey, + &identity_pkey_len)<0) { + log_warn(LD_BUG,"write identity_pkey to string failed!"); + goto err; + } + format_iso_time(published, time(NULL)); + + len = 2048; + s = tor_malloc_zero(len); + tor_snprintf(s, len, + "network-status\n" + "published %s\n" + "router-status %s\n" + "dir-signing-key\n%s" + "directory-signature %s\n", + published, "", identity_pkey, + get_options()->Nickname); + tor_free(identity_pkey); + if (router_get_runningrouters_hash(s,digest)) { + log_warn(LD_BUG,"couldn't compute digest"); + goto err; + } + note_crypto_pk_op(SIGN_DIR); + if (router_append_dirobj_signature(s, len, digest, DIGEST_LEN, + private_key)<0) + goto err; + + set_cached_dir(&the_runningrouters, s, time(NULL)); + runningrouters_is_dirty = 0; + + return &the_runningrouters; + err: + tor_free(s); + return NULL; +} + +/** Set *rr to the most recently generated encoded signed + * running-routers list, generating a new one as necessary. Return the + * size of the directory on success, and 0 on failure. */ +cached_dir_t * +dirserv_get_runningrouters(void) +{ + return dirserv_pick_cached_dir_obj( + &cached_runningrouters, &the_runningrouters, + runningrouters_is_dirty, + generate_runningrouters, + "v1 network status list", V1_DIRINFO); +} + +/** Return the latest downloaded consensus networkstatus in encoded, signed, + * optionally compressed format, suitable for sending to clients. */ +cached_dir_t * +dirserv_get_consensus(const char *flavor_name) +{ + if (!cached_consensuses) + return NULL; + return strmap_get(cached_consensuses, flavor_name); +} + +/** If a router's uptime is at least this value, then it is always + * considered stable, regardless of the rest of the network. This + * way we resist attacks where an attacker doubles the size of the + * network using allegedly high-uptime nodes, displacing all the + * current guards. */ +#define UPTIME_TO_GUARANTEE_STABLE (3600*24*30) +/** If a router's MTBF is at least this value, then it is always stable. + * See above. (Corresponds to about 7 days for current decay rates.) */ +#define MTBF_TO_GUARANTEE_STABLE (60*60*24*5) +/** Similarly, every node with at least this much weighted time known can be + * considered familiar enough to be a guard. Corresponds to about 20 days for + * current decay rates. + */ +#define TIME_KNOWN_TO_GUARANTEE_FAMILIAR (8*24*60*60) +/** Similarly, every node with sufficient WFU is around enough to be a guard. + */ +#define WFU_TO_GUARANTEE_GUARD (0.98) + +/* Thresholds for server performance: set by + * dirserv_compute_performance_thresholds, and used by + * generate_v2_networkstatus */ + +/** Any router with an uptime of at least this value is stable. */ +static uint32_t stable_uptime = 0; /* start at a safe value */ +/** Any router with an mtbf of at least this value is stable. */ +static double stable_mtbf = 0.0; +/** If true, we have measured enough mtbf info to look at stable_mtbf rather + * than stable_uptime. */ +static int enough_mtbf_info = 0; +/** Any router with a weighted fractional uptime of at least this much might + * be good as a guard. */ +static double guard_wfu = 0.0; +/** Don't call a router a guard unless we've known about it for at least this + * many seconds. */ +static long guard_tk = 0; +/** Any router with a bandwidth at least this high is "Fast" */ +static uint32_t fast_bandwidth_kb = 0; +/** If exits can be guards, then all guards must have a bandwidth this + * high. */ +static uint32_t guard_bandwidth_including_exits_kb = 0; +/** If exits can't be guards, then all guards must have a bandwidth this + * high. */ +static uint32_t guard_bandwidth_excluding_exits_kb = 0; + +/** Helper: estimate the uptime of a router given its stated uptime and the + * amount of time since it last stated its stated uptime. */ +static INLINE long +real_uptime(const routerinfo_t *router, time_t now) +{ + if (now < router->cache_info.published_on) + return router->uptime; + else + return router->uptime + (now - router->cache_info.published_on); +} + +/** Return 1 if router is not suitable for these parameters, else 0. + * If need_uptime is non-zero, we require a minimum uptime. + * If need_capacity is non-zero, we require a minimum advertised + * bandwidth. + */ +static int +dirserv_thinks_router_is_unreliable(time_t now, + routerinfo_t *router, + int need_uptime, int need_capacity) +{ + if (need_uptime) { + if (!enough_mtbf_info) { + /* XXX024 Once most authorities are on v3, we should change the rule from + * "use uptime if we don't have mtbf data" to "don't advertise Stable on + * v3 if we don't have enough mtbf data." Or maybe not, since if we ever + * hit a point where we need to reset a lot of authorities at once, + * none of them would be in a position to declare Stable. + */ + long uptime = real_uptime(router, now); + if ((unsigned)uptime < stable_uptime && + (unsigned)uptime < UPTIME_TO_GUARANTEE_STABLE) + return 1; + } else { + double mtbf = + rep_hist_get_stability(router->cache_info.identity_digest, now); + if (mtbf < stable_mtbf && + mtbf < MTBF_TO_GUARANTEE_STABLE) + return 1; + } + } + if (need_capacity) { + uint32_t bw_kb = dirserv_get_credible_bandwidth_kb(router); + if (bw_kb < fast_bandwidth_kb) + return 1; + } + return 0; +} + +/** Return true iff router should be assigned the "HSDir" flag. + * Right now this means it advertises support for it, it has a high + * uptime, it has a DirPort open, and it's currently considered Running. + * + * This function needs to be called after router-\>is_running has + * been set. + */ +static int +dirserv_thinks_router_is_hs_dir(const routerinfo_t *router, + const node_t *node, time_t now) +{ + + long uptime; + + /* If we haven't been running for at least + * get_options()->MinUptimeHidServDirectoryV2 seconds, we can't + * have accurate data telling us a relay has been up for at least + * that long. We also want to allow a bit of slack: Reachability + * tests aren't instant. If we haven't been running long enough, + * trust the relay. */ + + if (stats_n_seconds_working > + get_options()->MinUptimeHidServDirectoryV2 * 1.1) + uptime = MIN(rep_hist_get_uptime(router->cache_info.identity_digest, now), + real_uptime(router, now)); + else + uptime = real_uptime(router, now); + + /* XXX We shouldn't need to check dir_port, but we do because of + * bug 1693. In the future, once relays set wants_to_be_hs_dir + * correctly, we can revert to only checking dir_port if router's + * version is too old. */ + /* XXX Unfortunately, we need to keep checking dir_port until all + * *clients* suffering from bug 2722 are obsolete. The first version + * to fix the bug was 0.2.2.25-alpha. */ + return (router->wants_to_be_hs_dir && router->dir_port && + uptime >= get_options()->MinUptimeHidServDirectoryV2 && + node->is_running); +} + +/** Don't consider routers with less bandwidth than this when computing + * thresholds. */ +#define ABSOLUTE_MIN_BW_VALUE_TO_CONSIDER_KB 4 + +/** Helper for dirserv_compute_performance_thresholds(): Decide whether to + * include a router in our calculations, and return true iff we should; the + * require_mbw parameter is passed in by + * dirserv_compute_performance_thresholds() and controls whether we ever + * count routers with only advertised bandwidths */ +static int +router_counts_toward_thresholds(const node_t *node, time_t now, + const digestmap_t *omit_as_sybil, + int require_mbw) +{ + /* Have measured bw? */ + int have_mbw = + dirserv_has_measured_bw(node->identity); + uint64_t min_bw_kb = ABSOLUTE_MIN_BW_VALUE_TO_CONSIDER_KB; + const or_options_t *options = get_options(); + + if (options->TestingTorNetwork) { + min_bw_kb = (int64_t)options->TestingMinExitFlagThreshold / 1000; + } + + return node->ri && router_is_active(node->ri, node, now) && + !digestmap_get(omit_as_sybil, node->identity) && + (dirserv_get_credible_bandwidth_kb(node->ri) >= min_bw_kb) && + (have_mbw || !require_mbw); +} + +/** Look through the routerlist, the Mean Time Between Failure history, and + * the Weighted Fractional Uptime history, and use them to set thresholds for + * the Stable, Fast, and Guard flags. Update the fields stable_uptime, + * stable_mtbf, enough_mtbf_info, guard_wfu, guard_tk, fast_bandwidth, + * guard_bandwidth_including_exits, and guard_bandwidth_excluding_exits. + * + * Also, set the is_exit flag of each router appropriately. */ +static void +dirserv_compute_performance_thresholds(routerlist_t *rl, + digestmap_t *omit_as_sybil) +{ + int n_active, n_active_nonexit, n_familiar; + uint32_t *uptimes, *bandwidths_kb, *bandwidths_excluding_exits_kb; + long *tks; + double *mtbfs, *wfus; + time_t now = time(NULL); + const or_options_t *options = get_options(); + + /* Require mbw? */ + int require_mbw = + (routers_with_measured_bw > + options->MinMeasuredBWsForAuthToIgnoreAdvertised) ? 1 : 0; + + /* initialize these all here, in case there are no routers */ + stable_uptime = 0; + stable_mtbf = 0; + fast_bandwidth_kb = 0; + guard_bandwidth_including_exits_kb = 0; + guard_bandwidth_excluding_exits_kb = 0; + guard_tk = 0; + guard_wfu = 0; + + /* Initialize arrays that will hold values for each router. We'll + * sort them and use that to compute thresholds. */ + n_active = n_active_nonexit = 0; + /* Uptime for every active router. */ + uptimes = tor_malloc(sizeof(uint32_t)*smartlist_len(rl->routers)); + /* Bandwidth for every active router. */ + bandwidths_kb = tor_malloc(sizeof(uint32_t)*smartlist_len(rl->routers)); + /* Bandwidth for every active non-exit router. */ + bandwidths_excluding_exits_kb = + tor_malloc(sizeof(uint32_t)*smartlist_len(rl->routers)); + /* Weighted mean time between failure for each active router. */ + mtbfs = tor_malloc(sizeof(double)*smartlist_len(rl->routers)); + /* Time-known for each active router. */ + tks = tor_malloc(sizeof(long)*smartlist_len(rl->routers)); + /* Weighted fractional uptime for each active router. */ + wfus = tor_malloc(sizeof(double)*smartlist_len(rl->routers)); + + nodelist_assert_ok(); + + /* Now, fill in the arrays. */ + SMARTLIST_FOREACH_BEGIN(nodelist_get_list(), node_t *, node) { + if (options->BridgeAuthoritativeDir && + node->ri && + node->ri->purpose != ROUTER_PURPOSE_BRIDGE) + continue; + if (router_counts_toward_thresholds(node, now, omit_as_sybil, + require_mbw)) { + routerinfo_t *ri = node->ri; + const char *id = node->identity; + uint32_t bw_kb; + node->is_exit = (!router_exit_policy_rejects_all(ri) && + exit_policy_is_general_exit(ri->exit_policy)); + uptimes[n_active] = (uint32_t)real_uptime(ri, now); + mtbfs[n_active] = rep_hist_get_stability(id, now); + tks [n_active] = rep_hist_get_weighted_time_known(id, now); + bandwidths_kb[n_active] = bw_kb = dirserv_get_credible_bandwidth_kb(ri); + if (!node->is_exit || node->is_bad_exit) { + bandwidths_excluding_exits_kb[n_active_nonexit] = bw_kb; + ++n_active_nonexit; + } + ++n_active; + } + } SMARTLIST_FOREACH_END(node); + + /* Now, compute thresholds. */ + if (n_active) { + /* The median uptime is stable. */ + stable_uptime = median_uint32(uptimes, n_active); + /* The median mtbf is stable, if we have enough mtbf info */ + stable_mtbf = median_double(mtbfs, n_active); + /* The 12.5th percentile bandwidth is fast. */ + fast_bandwidth_kb = find_nth_uint32(bandwidths_kb, n_active, n_active/8); + /* (Now bandwidths is sorted.) */ + if (fast_bandwidth_kb < ROUTER_REQUIRED_MIN_BANDWIDTH/(2 * 1000)) + fast_bandwidth_kb = bandwidths_kb[n_active/4]; + guard_bandwidth_including_exits_kb = bandwidths_kb[(n_active-1)/2]; + guard_tk = find_nth_long(tks, n_active, n_active/8); + } + + if (guard_tk > TIME_KNOWN_TO_GUARANTEE_FAMILIAR) + guard_tk = TIME_KNOWN_TO_GUARANTEE_FAMILIAR; + + { + /* We can vote on a parameter for the minimum and maximum. */ +#define ABSOLUTE_MIN_VALUE_FOR_FAST_FLAG 4 + int32_t min_fast_kb, max_fast_kb, min_fast, max_fast; + min_fast = networkstatus_get_param(NULL, "FastFlagMinThreshold", + ABSOLUTE_MIN_VALUE_FOR_FAST_FLAG, + ABSOLUTE_MIN_VALUE_FOR_FAST_FLAG, + INT32_MAX); + if (options->TestingTorNetwork) { + min_fast = (int32_t)options->TestingMinFastFlagThreshold; + } + max_fast = networkstatus_get_param(NULL, "FastFlagMaxThreshold", + INT32_MAX, min_fast, INT32_MAX); + min_fast_kb = min_fast / 1000; + max_fast_kb = max_fast / 1000; + + if (fast_bandwidth_kb < (uint32_t)min_fast_kb) + fast_bandwidth_kb = min_fast_kb; + if (fast_bandwidth_kb > (uint32_t)max_fast_kb) + fast_bandwidth_kb = max_fast_kb; + } + /* Protect sufficiently fast nodes from being pushed out of the set + * of Fast nodes. */ + if (options->AuthDirFastGuarantee && + fast_bandwidth_kb > options->AuthDirFastGuarantee/1000) + fast_bandwidth_kb = (uint32_t)options->AuthDirFastGuarantee/1000; + + /* Now that we have a time-known that 7/8 routers are known longer than, + * fill wfus with the wfu of every such "familiar" router. */ + n_familiar = 0; + + SMARTLIST_FOREACH_BEGIN(nodelist_get_list(), node_t *, node) { + if (router_counts_toward_thresholds(node, now, + omit_as_sybil, require_mbw)) { + routerinfo_t *ri = node->ri; + const char *id = ri->cache_info.identity_digest; + long tk = rep_hist_get_weighted_time_known(id, now); + if (tk < guard_tk) + continue; + wfus[n_familiar++] = rep_hist_get_weighted_fractional_uptime(id, now); + } + } SMARTLIST_FOREACH_END(node); + if (n_familiar) + guard_wfu = median_double(wfus, n_familiar); + if (guard_wfu > WFU_TO_GUARANTEE_GUARD) + guard_wfu = WFU_TO_GUARANTEE_GUARD; + + enough_mtbf_info = rep_hist_have_measured_enough_stability(); + + if (n_active_nonexit) { + guard_bandwidth_excluding_exits_kb = + median_uint32(bandwidths_excluding_exits_kb, n_active_nonexit); + } + + log_info(LD_DIRSERV, + "Cutoffs: For Stable, %lu sec uptime, %lu sec MTBF. " + "For Fast: %lu kilobytes/sec. " + "For Guard: WFU %.03f%%, time-known %lu sec, " + "and bandwidth %lu or %lu kilobytes/sec. " + "We%s have enough stability data.", + (unsigned long)stable_uptime, + (unsigned long)stable_mtbf, + (unsigned long)fast_bandwidth_kb, + guard_wfu*100, + (unsigned long)guard_tk, + (unsigned long)guard_bandwidth_including_exits_kb, + (unsigned long)guard_bandwidth_excluding_exits_kb, + enough_mtbf_info ? "" : " don't "); + + tor_free(uptimes); + tor_free(mtbfs); + tor_free(bandwidths_kb); + tor_free(bandwidths_excluding_exits_kb); + tor_free(tks); + tor_free(wfus); +} + +/* Use dirserv_compute_performance_thresholds() to compute the thresholds + * for the status flags, specifically for bridges. + * + * This is only called by a Bridge Authority from + * networkstatus_getinfo_by_purpose(). + */ +void +dirserv_compute_bridge_flag_thresholds(routerlist_t *rl) +{ + + digestmap_t *omit_as_sybil = digestmap_new(); + dirserv_compute_performance_thresholds(rl, omit_as_sybil); + digestmap_free(omit_as_sybil, NULL); +} + +/** Measured bandwidth cache entry */ +typedef struct mbw_cache_entry_s { + long mbw_kb; + time_t as_of; +} mbw_cache_entry_t; + +/** Measured bandwidth cache - keys are identity_digests, values are + * mbw_cache_entry_t *. */ +static digestmap_t *mbw_cache = NULL; + +/** Store a measured bandwidth cache entry when reading the measured + * bandwidths file. */ +STATIC void +dirserv_cache_measured_bw(const measured_bw_line_t *parsed_line, + time_t as_of) +{ + mbw_cache_entry_t *e = NULL; + + tor_assert(parsed_line); + + /* Allocate a cache if we need */ + if (!mbw_cache) mbw_cache = digestmap_new(); + + /* Check if we have an existing entry */ + e = digestmap_get(mbw_cache, parsed_line->node_id); + /* If we do, we can re-use it */ + if (e) { + /* Check that we really are newer, and update */ + if (as_of > e->as_of) { + e->mbw_kb = parsed_line->bw_kb; + e->as_of = as_of; + } + } else { + /* We'll have to insert a new entry */ + e = tor_malloc(sizeof(*e)); + e->mbw_kb = parsed_line->bw_kb; + e->as_of = as_of; + digestmap_set(mbw_cache, parsed_line->node_id, e); + } +} + +/** Clear and free the measured bandwidth cache */ +STATIC void +dirserv_clear_measured_bw_cache(void) +{ + if (mbw_cache) { + /* Free the map and all entries */ + digestmap_free(mbw_cache, tor_free_); + mbw_cache = NULL; + } +} + +/** Scan the measured bandwidth cache and remove expired entries */ +STATIC void +dirserv_expire_measured_bw_cache(time_t now) +{ + + if (mbw_cache) { + /* Iterate through the cache and check each entry */ + DIGESTMAP_FOREACH_MODIFY(mbw_cache, k, mbw_cache_entry_t *, e) { + if (now > e->as_of + MAX_MEASUREMENT_AGE) { + tor_free(e); + MAP_DEL_CURRENT(k); + } + } DIGESTMAP_FOREACH_END; + + /* Check if we cleared the whole thing and free if so */ + if (digestmap_size(mbw_cache) == 0) { + digestmap_free(mbw_cache, tor_free_); + mbw_cache = 0; + } + } +} + +/** Get the current size of the measured bandwidth cache */ +STATIC int +dirserv_get_measured_bw_cache_size(void) +{ + if (mbw_cache) return digestmap_size(mbw_cache); + else return 0; +} + +/** Query the cache by identity digest, return value indicates whether + * we found it. The bw_out and as_of_out pointers receive the cached + * bandwidth value and the time it was cached if not NULL. */ +STATIC int +dirserv_query_measured_bw_cache_kb(const char *node_id, long *bw_kb_out, + time_t *as_of_out) +{ + mbw_cache_entry_t *v = NULL; + int rv = 0; + + if (mbw_cache && node_id) { + v = digestmap_get(mbw_cache, node_id); + if (v) { + /* Found something */ + rv = 1; + if (bw_kb_out) *bw_kb_out = v->mbw_kb; + if (as_of_out) *as_of_out = v->as_of; + } + } + + return rv; +} + +/** Predicate wrapper for dirserv_query_measured_bw_cache() */ +STATIC int +dirserv_has_measured_bw(const char *node_id) +{ + return dirserv_query_measured_bw_cache_kb(node_id, NULL, NULL); +} + +/** Get the best estimate of a router's bandwidth for dirauth purposes, + * preferring measured to advertised values if available. */ + +static uint32_t +dirserv_get_bandwidth_for_router_kb(const routerinfo_t *ri) +{ + uint32_t bw_kb = 0; + /* + * Yeah, measured bandwidths in measured_bw_line_t are (implicitly + * signed) longs and the ones router_get_advertised_bandwidth() returns + * are uint32_t. + */ + long mbw_kb = 0; + + if (ri) { + /* + * * First try to see if we have a measured bandwidth; don't bother with + * as_of_out here, on the theory that a stale measured bandwidth is still + * better to trust than an advertised one. + */ + if (dirserv_query_measured_bw_cache_kb(ri->cache_info.identity_digest, + &mbw_kb, NULL)) { + /* Got one! */ + bw_kb = (uint32_t)mbw_kb; + } else { + /* If not, fall back to advertised */ + bw_kb = router_get_advertised_bandwidth(ri) / 1000; + } + } + + return bw_kb; +} + +/** Look through the routerlist, and using the measured bandwidth cache count + * how many measured bandwidths we know. This is used to decide whether we + * ever trust advertised bandwidths for purposes of assigning flags. */ +static void +dirserv_count_measured_bws(routerlist_t *rl) +{ + /* Initialize this first */ + routers_with_measured_bw = 0; + + tor_assert(rl); + tor_assert(rl->routers); + + /* Iterate over the routerlist and count measured bandwidths */ + SMARTLIST_FOREACH_BEGIN(rl->routers, routerinfo_t *, ri) { + /* Check if we know a measured bandwidth for this one */ + if (dirserv_has_measured_bw(ri->cache_info.identity_digest)) { + ++routers_with_measured_bw; + } + } SMARTLIST_FOREACH_END(ri); +} + +/** Return the bandwidth we believe for assigning flags; prefer measured + * over advertised, and if we have above a threshold quantity of measured + * bandwidths, we don't want to ever give flags to unmeasured routers, so + * return 0. */ +static uint32_t +dirserv_get_credible_bandwidth_kb(const routerinfo_t *ri) +{ + int threshold; + uint32_t bw_kb = 0; + long mbw_kb; + + tor_assert(ri); + /* Check if we have a measured bandwidth, and check the threshold if not */ + if (!(dirserv_query_measured_bw_cache_kb(ri->cache_info.identity_digest, + &mbw_kb, NULL))) { + threshold = get_options()->MinMeasuredBWsForAuthToIgnoreAdvertised; + if (routers_with_measured_bw > threshold) { + /* Return zero for unmeasured bandwidth if we are above threshold */ + bw_kb = 0; + } else { + /* Return an advertised bandwidth otherwise */ + bw_kb = router_get_advertised_bandwidth_capped(ri) / 1000; + } + } else { + /* We have the measured bandwidth in mbw */ + bw_kb = (uint32_t)mbw_kb; + } + + return bw_kb; +} + +/** Give a statement of our current performance thresholds for inclusion + * in a vote document. */ +char * +dirserv_get_flag_thresholds_line(void) +{ + char *result=NULL; + const int measured_threshold = + get_options()->MinMeasuredBWsForAuthToIgnoreAdvertised; + const int enough_measured_bw = routers_with_measured_bw > measured_threshold; + + tor_asprintf(&result, + "stable-uptime=%lu stable-mtbf=%lu " + "fast-speed=%lu " + "guard-wfu=%.03f%% guard-tk=%lu " + "guard-bw-inc-exits=%lu guard-bw-exc-exits=%lu " + "enough-mtbf=%d ignoring-advertised-bws=%d", + (unsigned long)stable_uptime, + (unsigned long)stable_mtbf, + (unsigned long)fast_bandwidth_kb*1000, + guard_wfu*100, + (unsigned long)guard_tk, + (unsigned long)guard_bandwidth_including_exits_kb*1000, + (unsigned long)guard_bandwidth_excluding_exits_kb*1000, + enough_mtbf_info ? 1 : 0, + enough_measured_bw ? 1 : 0); + + return result; +} + +/** Given a platform string as in a routerinfo_t (possibly null), return a + * newly allocated version string for a networkstatus document, or NULL if the + * platform doesn't give a Tor version. */ +static char * +version_from_platform(const char *platform) +{ + if (platform && !strcmpstart(platform, "Tor ")) { + const char *eos = find_whitespace(platform+4); + if (eos && !strcmpstart(eos, " (r")) { + /* XXXX Unify this logic with the other version extraction + * logic in routerparse.c. */ + eos = find_whitespace(eos+1); + } + if (eos) { + return tor_strndup(platform, eos-platform); + } + } + return NULL; +} + +/** Helper: write the router-status information in rs into a newly + * allocated character buffer. Use the same format as in network-status + * documents. If version is non-NULL, add a "v" line for the platform. + * Return 0 on success, -1 on failure. + * + * The format argument has one of the following values: + * NS_V2 - Output an entry suitable for a V2 NS opinion document + * NS_V3_CONSENSUS - Output the first portion of a V3 NS consensus entry + * NS_V3_CONSENSUS_MICRODESC - Output the first portion of a V3 microdesc + * consensus entry. + * NS_V3_VOTE - Output a complete V3 NS vote. If vrs is present, + * it contains additional information for the vote. + * NS_CONTROL_PORT - Output a NS document for the control port + */ +char * +routerstatus_format_entry(const routerstatus_t *rs, const char *version, + routerstatus_format_type_t format, + const vote_routerstatus_t *vrs) +{ + char *summary; + char *result = NULL; + + char published[ISO_TIME_LEN+1]; + char identity64[BASE64_DIGEST_LEN+1]; + char digest64[BASE64_DIGEST_LEN+1]; + smartlist_t *chunks = NULL; + + format_iso_time(published, rs->published_on); + digest_to_base64(identity64, rs->identity_digest); + digest_to_base64(digest64, rs->descriptor_digest); + + chunks = smartlist_new(); + smartlist_add_asprintf(chunks, + "r %s %s %s%s%s %s %d %d\n", + rs->nickname, + identity64, + (format==NS_V3_CONSENSUS_MICRODESC)?"":digest64, + (format==NS_V3_CONSENSUS_MICRODESC)?"":" ", + published, + fmt_addr32(rs->addr), + (int)rs->or_port, + (int)rs->dir_port); + + /* TODO: Maybe we want to pass in what we need to build the rest of + * this here, instead of in the caller. Then we could use the + * networkstatus_type_t values, with an additional control port value + * added -MP */ + + /* V3 microdesc consensuses don't have "a" lines. */ + if (format == NS_V3_CONSENSUS_MICRODESC) + goto done; + + /* Possible "a" line. At most one for now. */ + if (!tor_addr_is_null(&rs->ipv6_addr)) { + smartlist_add_asprintf(chunks, "a %s\n", + fmt_addrport(&rs->ipv6_addr, rs->ipv6_orport)); + } + + if (format == NS_V3_CONSENSUS) + goto done; + + smartlist_add_asprintf(chunks, + "s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", + /* These must stay in alphabetical order. */ + rs->is_authority?" Authority":"", + rs->is_bad_directory?" BadDirectory":"", + rs->is_bad_exit?" BadExit":"", + rs->is_exit?" Exit":"", + rs->is_fast?" Fast":"", + rs->is_possible_guard?" Guard":"", + rs->is_hs_dir?" HSDir":"", + rs->is_named?" Named":"", + rs->is_flagged_running?" Running":"", + rs->is_stable?" Stable":"", + rs->is_unnamed?" Unnamed":"", + (rs->dir_port!=0)?" V2Dir":"", + rs->is_valid?" Valid":""); + + /* length of "opt v \n" */ +#define V_LINE_OVERHEAD 7 + if (version && strlen(version) < MAX_V_LINE_LEN - V_LINE_OVERHEAD) { + smartlist_add_asprintf(chunks, "v %s\n", version); + } + + if (format != NS_V2) { + const routerinfo_t* desc = router_get_by_id_digest(rs->identity_digest); + uint32_t bw_kb; + + if (format != NS_CONTROL_PORT) { + /* Blow up more or less nicely if we didn't get anything or not the + * thing we expected. + */ + if (!desc) { + char id[HEX_DIGEST_LEN+1]; + char dd[HEX_DIGEST_LEN+1]; + + base16_encode(id, sizeof(id), rs->identity_digest, DIGEST_LEN); + base16_encode(dd, sizeof(dd), rs->descriptor_digest, DIGEST_LEN); + log_warn(LD_BUG, "Cannot get any descriptor for %s " + "(wanted descriptor %s).", + id, dd); + goto err; + } + + /* This assert could fire for the control port, because + * it can request NS documents before all descriptors + * have been fetched. Therefore, we only do this test when + * format != NS_CONTROL_PORT. */ + if (tor_memneq(desc->cache_info.signed_descriptor_digest, + rs->descriptor_digest, + DIGEST_LEN)) { + char rl_d[HEX_DIGEST_LEN+1]; + char rs_d[HEX_DIGEST_LEN+1]; + char id[HEX_DIGEST_LEN+1]; + + base16_encode(rl_d, sizeof(rl_d), + desc->cache_info.signed_descriptor_digest, DIGEST_LEN); + base16_encode(rs_d, sizeof(rs_d), rs->descriptor_digest, DIGEST_LEN); + base16_encode(id, sizeof(id), rs->identity_digest, DIGEST_LEN); + log_err(LD_BUG, "descriptor digest in routerlist does not match " + "the one in routerstatus: %s vs %s " + "(router %s)\n", + rl_d, rs_d, id); + + tor_assert(tor_memeq(desc->cache_info.signed_descriptor_digest, + rs->descriptor_digest, + DIGEST_LEN)); + } + } + + if (format == NS_CONTROL_PORT && rs->has_bandwidth) { + bw_kb = rs->bandwidth_kb; + } else { + tor_assert(desc); + bw_kb = router_get_advertised_bandwidth_capped(desc) / 1000; + } + smartlist_add_asprintf(chunks, + "w Bandwidth=%d", bw_kb); + + if (format == NS_V3_VOTE && vrs && vrs->has_measured_bw) { + smartlist_add_asprintf(chunks, + " Measured=%d", vrs->measured_bw_kb); + } + smartlist_add(chunks, tor_strdup("\n")); + + if (desc) { + summary = policy_summarize(desc->exit_policy, AF_INET); + smartlist_add_asprintf(chunks, "p %s\n", summary); + tor_free(summary); + } + } + + done: + result = smartlist_join_strings(chunks, "", 0, NULL); + + err: + if (chunks) { + SMARTLIST_FOREACH(chunks, char *, cp, tor_free(cp)); + smartlist_free(chunks); + } + + return result; +} + +/** Helper for sorting: compares two routerinfos first by address, and then by + * descending order of "usefulness". (An authority is more useful than a + * non-authority; a running router is more useful than a non-running router; + * and a router with more bandwidth is more useful than one with less.) + **/ +static int +compare_routerinfo_by_ip_and_bw_(const void **a, const void **b) +{ + routerinfo_t *first = *(routerinfo_t **)a, *second = *(routerinfo_t **)b; + int first_is_auth, second_is_auth; + uint32_t bw_kb_first, bw_kb_second; + const node_t *node_first, *node_second; + int first_is_running, second_is_running; + + /* we return -1 if first should appear before second... that is, + * if first is a better router. */ + if (first->addr < second->addr) + return -1; + else if (first->addr > second->addr) + return 1; + + /* Potentially, this next bit could cause k n lg n memeq calls. But in + * reality, we will almost never get here, since addresses will usually be + * different. */ + + first_is_auth = + router_digest_is_trusted_dir(first->cache_info.identity_digest); + second_is_auth = + router_digest_is_trusted_dir(second->cache_info.identity_digest); + + if (first_is_auth && !second_is_auth) + return -1; + else if (!first_is_auth && second_is_auth) + return 1; + + node_first = node_get_by_id(first->cache_info.identity_digest); + node_second = node_get_by_id(second->cache_info.identity_digest); + first_is_running = node_first && node_first->is_running; + second_is_running = node_second && node_second->is_running; + + if (first_is_running && !second_is_running) + return -1; + else if (!first_is_running && second_is_running) + return 1; + + bw_kb_first = dirserv_get_bandwidth_for_router_kb(first); + bw_kb_second = dirserv_get_bandwidth_for_router_kb(second); + + if (bw_kb_first > bw_kb_second) + return -1; + else if (bw_kb_first < bw_kb_second) + return 1; + + /* They're equal! Compare by identity digest, so there's a + * deterministic order and we avoid flapping. */ + return fast_memcmp(first->cache_info.identity_digest, + second->cache_info.identity_digest, + DIGEST_LEN); +} + +/** Given a list of routerinfo_t in routers, return a new digestmap_t + * whose keys are the identity digests of those routers that we're going to + * exclude for Sybil-like appearance. */ +static digestmap_t * +get_possible_sybil_list(const smartlist_t *routers) +{ + const or_options_t *options = get_options(); + digestmap_t *omit_as_sybil; + smartlist_t *routers_by_ip = smartlist_new(); + uint32_t last_addr; + int addr_count; + /* Allow at most this number of Tor servers on a single IP address, ... */ + int max_with_same_addr = options->AuthDirMaxServersPerAddr; + /* ... unless it's a directory authority, in which case allow more. */ + int max_with_same_addr_on_authority = options->AuthDirMaxServersPerAuthAddr; + if (max_with_same_addr <= 0) + max_with_same_addr = INT_MAX; + if (max_with_same_addr_on_authority <= 0) + max_with_same_addr_on_authority = INT_MAX; + + smartlist_add_all(routers_by_ip, routers); + smartlist_sort(routers_by_ip, compare_routerinfo_by_ip_and_bw_); + omit_as_sybil = digestmap_new(); + + last_addr = 0; + addr_count = 0; + SMARTLIST_FOREACH_BEGIN(routers_by_ip, routerinfo_t *, ri) { + if (last_addr != ri->addr) { + last_addr = ri->addr; + addr_count = 1; + } else if (++addr_count > max_with_same_addr) { + if (!router_addr_is_trusted_dir(ri->addr) || + addr_count > max_with_same_addr_on_authority) + digestmap_set(omit_as_sybil, ri->cache_info.identity_digest, ri); + } + } SMARTLIST_FOREACH_END(ri); + + smartlist_free(routers_by_ip); + return omit_as_sybil; +} + +/** Return non-zero iff a relay running the Tor version specified in + * platform is suitable for use as a potential entry guard. */ +static int +is_router_version_good_for_possible_guard(const char *platform) +{ + static int parsed_versions_initialized = 0; + static tor_version_t first_good_0_2_1_guard_version; + static tor_version_t first_good_0_2_2_guard_version; + static tor_version_t first_good_later_guard_version; + + tor_version_t router_version; + + /* XXX024 This block should be extracted into its own function. */ + /* XXXX Begin code copied from tor_version_as_new_as (in routerparse.c) */ + { + char *s, *s2, *start; + char tmp[128]; + + tor_assert(platform); + + /* nonstandard Tor; be safe and say yes */ + if (strcmpstart(platform,"Tor ")) + return 1; + + start = (char *)eat_whitespace(platform+3); + if (!*start) return 0; + s = (char *)find_whitespace(start); /* also finds '\0', which is fine */ + s2 = (char*)eat_whitespace(s); + if (!strcmpstart(s2, "(r") || !strcmpstart(s2, "(git-")) + s = (char*)find_whitespace(s2); + + if ((size_t)(s-start+1) >= sizeof(tmp)) /* too big, no */ + return 0; + strlcpy(tmp, start, s-start+1); + + if (tor_version_parse(tmp, &router_version)<0) { + log_info(LD_DIR,"Router version '%s' unparseable.",tmp); + return 1; /* be safe and say yes */ + } + } + /* XXXX End code copied from tor_version_as_new_as (in routerparse.c) */ + + if (!parsed_versions_initialized) { + /* CVE-2011-2769 was fixed on the relay side in Tor versions + * 0.2.1.31, 0.2.2.34, and 0.2.3.6-alpha. */ + tor_assert(tor_version_parse("0.2.1.31", + &first_good_0_2_1_guard_version)>=0); + tor_assert(tor_version_parse("0.2.2.34", + &first_good_0_2_2_guard_version)>=0); + tor_assert(tor_version_parse("0.2.3.6-alpha", + &first_good_later_guard_version)>=0); + + /* Don't parse these constant version strings once for every relay + * for every vote. */ + parsed_versions_initialized = 1; + } + + return ((tor_version_same_series(&first_good_0_2_1_guard_version, + &router_version) && + tor_version_compare(&first_good_0_2_1_guard_version, + &router_version) <= 0) || + (tor_version_same_series(&first_good_0_2_2_guard_version, + &router_version) && + tor_version_compare(&first_good_0_2_2_guard_version, + &router_version) <= 0) || + (tor_version_compare(&first_good_later_guard_version, + &router_version) <= 0)); +} + +/** Extract status information from ri and from other authority + * functions and store it in rs>. If naming, consider setting + * the named flag in rs. + * + * We assume that ri-\>is_running has already been set, e.g. by + * dirserv_set_router_is_running(ri, now); + */ +void +set_routerstatus_from_routerinfo(routerstatus_t *rs, + node_t *node, + routerinfo_t *ri, + time_t now, + int naming, int listbadexits, + int listbaddirs, int vote_on_hsdirs) +{ + const or_options_t *options = get_options(); + uint32_t routerbw_kb = dirserv_get_credible_bandwidth_kb(ri); + + memset(rs, 0, sizeof(routerstatus_t)); + + rs->is_authority = + router_digest_is_trusted_dir(ri->cache_info.identity_digest); + + /* Already set by compute_performance_thresholds. */ + rs->is_exit = node->is_exit; + rs->is_stable = node->is_stable = + router_is_active(ri, node, now) && + !dirserv_thinks_router_is_unreliable(now, ri, 1, 0); + rs->is_fast = node->is_fast = + router_is_active(ri, node, now) && + !dirserv_thinks_router_is_unreliable(now, ri, 0, 1); + rs->is_flagged_running = node->is_running; /* computed above */ + + if (naming) { + uint32_t name_status = dirserv_get_name_status( + node->identity, ri->nickname); + rs->is_named = (naming && (name_status & FP_NAMED)) ? 1 : 0; + rs->is_unnamed = (naming && (name_status & FP_UNNAMED)) ? 1 : 0; + } + rs->is_valid = node->is_valid; + + if (node->is_fast && + ((options->AuthDirGuardBWGuarantee && + routerbw_kb >= options->AuthDirGuardBWGuarantee/1000) || + routerbw_kb >= MIN(guard_bandwidth_including_exits_kb, + guard_bandwidth_excluding_exits_kb)) && + is_router_version_good_for_possible_guard(ri->platform)) { + long tk = rep_hist_get_weighted_time_known( + node->identity, now); + double wfu = rep_hist_get_weighted_fractional_uptime( + node->identity, now); + rs->is_possible_guard = (wfu >= guard_wfu && tk >= guard_tk) ? 1 : 0; + } else { + rs->is_possible_guard = 0; + } + if (options->TestingTorNetwork && + routerset_contains_routerstatus(options->TestingDirAuthVoteGuard, + rs, 0)) { + rs->is_possible_guard = 1; + } + + rs->is_bad_directory = listbaddirs && node->is_bad_directory; + rs->is_bad_exit = listbadexits && node->is_bad_exit; + node->is_hs_dir = dirserv_thinks_router_is_hs_dir(ri, node, now); + rs->is_hs_dir = vote_on_hsdirs && node->is_hs_dir; + + if (!strcasecmp(ri->nickname, UNNAMED_ROUTER_NICKNAME)) + rs->is_named = rs->is_unnamed = 0; + + rs->published_on = ri->cache_info.published_on; + memcpy(rs->identity_digest, node->identity, DIGEST_LEN); + memcpy(rs->descriptor_digest, ri->cache_info.signed_descriptor_digest, + DIGEST_LEN); + rs->addr = ri->addr; + strlcpy(rs->nickname, ri->nickname, sizeof(rs->nickname)); + rs->or_port = ri->or_port; + rs->dir_port = ri->dir_port; + if (options->AuthDirHasIPv6Connectivity == 1 && + !tor_addr_is_null(&ri->ipv6_addr) && + node->last_reachable6 >= now - REACHABLE_TIMEOUT) { + /* We're configured as having IPv6 connectivity. There's an IPv6 + OR port and it's reachable so copy it to the routerstatus. */ + tor_addr_copy(&rs->ipv6_addr, &ri->ipv6_addr); + rs->ipv6_orport = ri->ipv6_orport; + } +} + +/** Routerstatus rs is part of a group of routers that are on + * too narrow an IP-space. Clear out its flags: we don't want people + * using it. + */ +static void +clear_status_flags_on_sybil(routerstatus_t *rs) +{ + rs->is_authority = rs->is_exit = rs->is_stable = rs->is_fast = + rs->is_flagged_running = rs->is_named = rs->is_valid = + rs->is_hs_dir = rs->is_possible_guard = rs->is_bad_exit = + rs->is_bad_directory = 0; + /* FFFF we might want some mechanism to check later on if we + * missed zeroing any flags: it's easy to add a new flag but + * forget to add it to this clause. */ +} + +/** + * Helper function to parse out a line in the measured bandwidth file + * into a measured_bw_line_t output structure. Returns -1 on failure + * or 0 on success. + */ +STATIC int +measured_bw_line_parse(measured_bw_line_t *out, const char *orig_line) +{ + char *line = tor_strdup(orig_line); + char *cp = line; + int got_bw = 0; + int got_node_id = 0; + char *strtok_state; /* lame sauce d'jour */ + cp = tor_strtok_r(cp, " \t", &strtok_state); + + if (!cp) { + log_warn(LD_DIRSERV, "Invalid line in bandwidth file: %s", + escaped(orig_line)); + tor_free(line); + return -1; + } + + if (orig_line[strlen(orig_line)-1] != '\n') { + log_warn(LD_DIRSERV, "Incomplete line in bandwidth file: %s", + escaped(orig_line)); + tor_free(line); + return -1; + } + + do { + if (strcmpstart(cp, "bw=") == 0) { + int parse_ok = 0; + char *endptr; + if (got_bw) { + log_warn(LD_DIRSERV, "Double bw= in bandwidth file line: %s", + escaped(orig_line)); + tor_free(line); + return -1; + } + cp+=strlen("bw="); + + out->bw_kb = tor_parse_long(cp, 0, 0, LONG_MAX, &parse_ok, &endptr); + if (!parse_ok || (*endptr && !TOR_ISSPACE(*endptr))) { + log_warn(LD_DIRSERV, "Invalid bandwidth in bandwidth file line: %s", + escaped(orig_line)); + tor_free(line); + return -1; + } + got_bw=1; + } else if (strcmpstart(cp, "node_id=$") == 0) { + if (got_node_id) { + log_warn(LD_DIRSERV, "Double node_id= in bandwidth file line: %s", + escaped(orig_line)); + tor_free(line); + return -1; + } + cp+=strlen("node_id=$"); + + if (strlen(cp) != HEX_DIGEST_LEN || + base16_decode(out->node_id, DIGEST_LEN, cp, HEX_DIGEST_LEN)) { + log_warn(LD_DIRSERV, "Invalid node_id in bandwidth file line: %s", + escaped(orig_line)); + tor_free(line); + return -1; + } + strlcpy(out->node_hex, cp, sizeof(out->node_hex)); + got_node_id=1; + } + } while ((cp = tor_strtok_r(NULL, " \t", &strtok_state))); + + if (got_bw && got_node_id) { + tor_free(line); + return 0; + } else { + log_warn(LD_DIRSERV, "Incomplete line in bandwidth file: %s", + escaped(orig_line)); + tor_free(line); + return -1; + } +} + +/** + * Helper function to apply a parsed measurement line to a list + * of bandwidth statuses. Returns true if a line is found, + * false otherwise. + */ +STATIC int +measured_bw_line_apply(measured_bw_line_t *parsed_line, + smartlist_t *routerstatuses) +{ + vote_routerstatus_t *rs = NULL; + if (!routerstatuses) + return 0; + + rs = smartlist_bsearch(routerstatuses, parsed_line->node_id, + compare_digest_to_vote_routerstatus_entry); + + if (rs) { + rs->has_measured_bw = 1; + rs->measured_bw_kb = (uint32_t)parsed_line->bw_kb; + } else { + log_info(LD_DIRSERV, "Node ID %s not found in routerstatus list", + parsed_line->node_hex); + } + + return rs != NULL; +} + +/** + * Read the measured bandwidth file and apply it to the list of + * vote_routerstatus_t. Returns -1 on error, 0 otherwise. + */ +int +dirserv_read_measured_bandwidths(const char *from_file, + smartlist_t *routerstatuses) +{ + char line[256]; + FILE *fp = tor_fopen_cloexec(from_file, "r"); + int applied_lines = 0; + time_t file_time, now; + int ok; + + if (fp == NULL) { + log_warn(LD_CONFIG, "Can't open bandwidth file at configured location: %s", + from_file); + return -1; + } + + if (!fgets(line, sizeof(line), fp) + || !strlen(line) || line[strlen(line)-1] != '\n') { + log_warn(LD_DIRSERV, "Long or truncated time in bandwidth file: %s", + escaped(line)); + fclose(fp); + return -1; + } + + line[strlen(line)-1] = '\0'; + file_time = tor_parse_ulong(line, 10, 0, ULONG_MAX, &ok, NULL); + if (!ok) { + log_warn(LD_DIRSERV, "Non-integer time in bandwidth file: %s", + escaped(line)); + fclose(fp); + return -1; + } + + now = time(NULL); + if ((now - file_time) > MAX_MEASUREMENT_AGE) { + log_warn(LD_DIRSERV, "Bandwidth measurement file stale. Age: %u", + (unsigned)(time(NULL) - file_time)); + fclose(fp); + return -1; + } + + if (routerstatuses) + smartlist_sort(routerstatuses, compare_vote_routerstatus_entries); + + while (!feof(fp)) { + measured_bw_line_t parsed_line; + if (fgets(line, sizeof(line), fp) && strlen(line)) { + if (measured_bw_line_parse(&parsed_line, line) != -1) { + /* Also cache the line for dirserv_get_bandwidth_for_router() */ + dirserv_cache_measured_bw(&parsed_line, file_time); + if (measured_bw_line_apply(&parsed_line, routerstatuses) > 0) + applied_lines++; + } + } + } + + /* Now would be a nice time to clean the cache, too */ + dirserv_expire_measured_bw_cache(now); + + fclose(fp); + log_info(LD_DIRSERV, + "Bandwidth measurement file successfully read. " + "Applied %d measurements.", applied_lines); + return 0; +} + +/** Return a new networkstatus_t* containing our current opinion. (For v3 + * authorities) */ +networkstatus_t * +dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key, + authority_cert_t *cert) +{ + const or_options_t *options = get_options(); + networkstatus_t *v3_out = NULL; + uint32_t addr; + char *hostname = NULL, *client_versions = NULL, *server_versions = NULL; + const char *contact; + smartlist_t *routers, *routerstatuses; + char identity_digest[DIGEST_LEN]; + char signing_key_digest[DIGEST_LEN]; + int naming = options->NamingAuthoritativeDir; + int listbadexits = options->AuthDirListBadExits; + int listbaddirs = options->AuthDirListBadDirs; + int vote_on_hsdirs = options->VoteOnHidServDirectoriesV2; + routerlist_t *rl = router_get_routerlist(); + time_t now = time(NULL); + time_t cutoff = now - ROUTER_MAX_AGE_TO_PUBLISH; + networkstatus_voter_info_t *voter = NULL; + vote_timing_t timing; + digestmap_t *omit_as_sybil = NULL; + const int vote_on_reachability = running_long_enough_to_decide_unreachable(); + smartlist_t *microdescriptors = NULL; + + tor_assert(private_key); + tor_assert(cert); + + if (resolve_my_address(LOG_WARN, options, &addr, NULL, &hostname)<0) { + log_warn(LD_NET, "Couldn't resolve my hostname"); + return NULL; + } + if (!hostname || !strchr(hostname, '.')) { + tor_free(hostname); + hostname = tor_dup_ip(addr); + } + if (crypto_pk_get_digest(private_key, signing_key_digest)<0) { + log_err(LD_BUG, "Error computing signing key digest"); + return NULL; + } + if (crypto_pk_get_digest(cert->identity_key, identity_digest)<0) { + log_err(LD_BUG, "Error computing identity key digest"); + return NULL; + } + + if (options->VersioningAuthoritativeDir) { + client_versions = format_versions_list(options->RecommendedClientVersions); + server_versions = format_versions_list(options->RecommendedServerVersions); + } + + contact = get_options()->ContactInfo; + if (!contact) + contact = "(none)"; + + /* + * Do this so dirserv_compute_performance_thresholds() and + * set_routerstatus_from_routerinfo() see up-to-date bandwidth info. + */ + if (options->V3BandwidthsFile) { + dirserv_read_measured_bandwidths(options->V3BandwidthsFile, NULL); + } else { + /* + * No bandwidths file; clear the measured bandwidth cache in case we had + * one last time around. + */ + if (dirserv_get_measured_bw_cache_size() > 0) { + dirserv_clear_measured_bw_cache(); + } + } + + /* precompute this part, since we need it to decide what "stable" + * means. */ + SMARTLIST_FOREACH(rl->routers, routerinfo_t *, ri, { + dirserv_set_router_is_running(ri, now); + }); + + routers = smartlist_new(); + smartlist_add_all(routers, rl->routers); + routers_sort_by_identity(routers); + omit_as_sybil = get_possible_sybil_list(routers); + + DIGESTMAP_FOREACH(omit_as_sybil, sybil_id, void *, ignore) { + (void) ignore; + rep_hist_make_router_pessimal(sybil_id, now); + } DIGESTMAP_FOREACH_END; + + /* Count how many have measured bandwidths so we know how to assign flags; + * this must come before dirserv_compute_performance_thresholds() */ + dirserv_count_measured_bws(rl); + + dirserv_compute_performance_thresholds(rl, omit_as_sybil); + + routerstatuses = smartlist_new(); + microdescriptors = smartlist_new(); + + SMARTLIST_FOREACH_BEGIN(routers, routerinfo_t *, ri) { + if (ri->cache_info.published_on >= cutoff) { + routerstatus_t *rs; + vote_routerstatus_t *vrs; + node_t *node = node_get_mutable_by_id(ri->cache_info.identity_digest); + if (!node) + continue; + + vrs = tor_malloc_zero(sizeof(vote_routerstatus_t)); + rs = &vrs->status; + set_routerstatus_from_routerinfo(rs, node, ri, now, + naming, listbadexits, listbaddirs, + vote_on_hsdirs); + + if (digestmap_get(omit_as_sybil, ri->cache_info.identity_digest)) + clear_status_flags_on_sybil(rs); + + if (!vote_on_reachability) + rs->is_flagged_running = 0; + + vrs->version = version_from_platform(ri->platform); + vrs->microdesc = dirvote_format_all_microdesc_vote_lines(ri, now, + microdescriptors); + + smartlist_add(routerstatuses, vrs); + } + } SMARTLIST_FOREACH_END(ri); + + { + smartlist_t *added = + microdescs_add_list_to_cache(get_microdesc_cache(), + microdescriptors, SAVED_NOWHERE, 0); + smartlist_free(added); + smartlist_free(microdescriptors); + } + + smartlist_free(routers); + digestmap_free(omit_as_sybil, NULL); + + /* This pass through applies the measured bw lines to the routerstatuses */ + if (options->V3BandwidthsFile) { + dirserv_read_measured_bandwidths(options->V3BandwidthsFile, + routerstatuses); + } else { + /* + * No bandwidths file; clear the measured bandwidth cache in case we had + * one last time around. + */ + if (dirserv_get_measured_bw_cache_size() > 0) { + dirserv_clear_measured_bw_cache(); + } + } + + v3_out = tor_malloc_zero(sizeof(networkstatus_t)); + + v3_out->type = NS_TYPE_VOTE; + dirvote_get_preferred_voting_intervals(&timing); + v3_out->published = now; + { + char tbuf[ISO_TIME_LEN+1]; + networkstatus_t *current_consensus = + networkstatus_get_live_consensus(now); + long last_consensus_interval; /* only used to pick a valid_after */ + if (current_consensus) + last_consensus_interval = current_consensus->fresh_until - + current_consensus->valid_after; + else + last_consensus_interval = options->TestingV3AuthInitialVotingInterval; + v3_out->valid_after = + dirvote_get_start_of_next_interval(now, (int)last_consensus_interval, + options->TestingV3AuthVotingStartOffset); + format_iso_time(tbuf, v3_out->valid_after); + log_notice(LD_DIR,"Choosing valid-after time in vote as %s: " + "consensus_set=%d, last_interval=%d", + tbuf, current_consensus?1:0, (int)last_consensus_interval); + } + v3_out->fresh_until = v3_out->valid_after + timing.vote_interval; + v3_out->valid_until = v3_out->valid_after + + (timing.vote_interval * timing.n_intervals_valid); + v3_out->vote_seconds = timing.vote_delay; + v3_out->dist_seconds = timing.dist_delay; + tor_assert(v3_out->vote_seconds > 0); + tor_assert(v3_out->dist_seconds > 0); + tor_assert(timing.n_intervals_valid > 0); + + v3_out->client_versions = client_versions; + v3_out->server_versions = server_versions; + v3_out->known_flags = smartlist_new(); + smartlist_split_string(v3_out->known_flags, + "Authority Exit Fast Guard Stable V2Dir Valid", + 0, SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); + if (vote_on_reachability) + smartlist_add(v3_out->known_flags, tor_strdup("Running")); + if (listbaddirs) + smartlist_add(v3_out->known_flags, tor_strdup("BadDirectory")); + if (listbadexits) + smartlist_add(v3_out->known_flags, tor_strdup("BadExit")); + if (naming) { + smartlist_add(v3_out->known_flags, tor_strdup("Named")); + smartlist_add(v3_out->known_flags, tor_strdup("Unnamed")); + } + if (vote_on_hsdirs) + smartlist_add(v3_out->known_flags, tor_strdup("HSDir")); + smartlist_sort_strings(v3_out->known_flags); + + if (options->ConsensusParams) { + v3_out->net_params = smartlist_new(); + smartlist_split_string(v3_out->net_params, + options->ConsensusParams, NULL, 0, 0); + smartlist_sort_strings(v3_out->net_params); + } + + voter = tor_malloc_zero(sizeof(networkstatus_voter_info_t)); + voter->nickname = tor_strdup(options->Nickname); + memcpy(voter->identity_digest, identity_digest, DIGEST_LEN); + voter->sigs = smartlist_new(); + voter->address = hostname; + voter->addr = addr; + voter->dir_port = router_get_advertised_dir_port(options, 0); + voter->or_port = router_get_advertised_or_port(options); + voter->contact = tor_strdup(contact); + if (options->V3AuthUseLegacyKey) { + authority_cert_t *c = get_my_v3_legacy_cert(); + if (c) { + if (crypto_pk_get_digest(c->identity_key, voter->legacy_id_digest)) { + log_warn(LD_BUG, "Unable to compute digest of legacy v3 identity key"); + memset(voter->legacy_id_digest, 0, DIGEST_LEN); + } + } + } + + v3_out->voters = smartlist_new(); + smartlist_add(v3_out->voters, voter); + v3_out->cert = authority_cert_dup(cert); + v3_out->routerstatus_list = routerstatuses; + /* Note: networkstatus_digest is unset; it won't get set until we actually + * format the vote. */ + + return v3_out; +} + +/** As dirserv_get_routerdescs(), but instead of getting signed_descriptor_t + * pointers, adds copies of digests to fps_out, and doesn't use the + * /tor/server/ prefix. For a /d/ request, adds descriptor digests; for other + * requests, adds identity digests. + */ +int +dirserv_get_routerdesc_fingerprints(smartlist_t *fps_out, const char *key, + const char **msg, int for_unencrypted_conn, + int is_extrainfo) +{ + int by_id = 1; + *msg = NULL; + + if (!strcmp(key, "all")) { + routerlist_t *rl = router_get_routerlist(); + SMARTLIST_FOREACH(rl->routers, routerinfo_t *, r, + smartlist_add(fps_out, + tor_memdup(r->cache_info.identity_digest, DIGEST_LEN))); + /* Treat "all" requests as if they were unencrypted */ + for_unencrypted_conn = 1; + } else if (!strcmp(key, "authority")) { + const routerinfo_t *ri = router_get_my_routerinfo(); + if (ri) + smartlist_add(fps_out, + tor_memdup(ri->cache_info.identity_digest, DIGEST_LEN)); + } else if (!strcmpstart(key, "d/")) { + by_id = 0; + key += strlen("d/"); + dir_split_resource_into_fingerprints(key, fps_out, NULL, + DSR_HEX|DSR_SORT_UNIQ); + } else if (!strcmpstart(key, "fp/")) { + key += strlen("fp/"); + dir_split_resource_into_fingerprints(key, fps_out, NULL, + DSR_HEX|DSR_SORT_UNIQ); + } else { + *msg = "Key not recognized"; + return -1; + } + + if (for_unencrypted_conn) { + /* Remove anything that insists it not be sent unencrypted. */ + SMARTLIST_FOREACH_BEGIN(fps_out, char *, cp) { + const signed_descriptor_t *sd; + if (by_id) + sd = get_signed_descriptor_by_fp(cp,is_extrainfo,0); + else if (is_extrainfo) + sd = extrainfo_get_by_descriptor_digest(cp); + else + sd = router_get_by_descriptor_digest(cp); + if (sd && !sd->send_unencrypted) { + tor_free(cp); + SMARTLIST_DEL_CURRENT(fps_out, cp); + } + } SMARTLIST_FOREACH_END(cp); + } + + if (!smartlist_len(fps_out)) { + *msg = "Servers unavailable"; + return -1; + } + return 0; +} + +/** Add a signed_descriptor_t to descs_out for each router matching + * key. The key should be either + * - "/tor/server/authority" for our own routerinfo; + * - "/tor/server/all" for all the routerinfos we have, concatenated; + * - "/tor/server/fp/FP" where FP is a plus-separated sequence of + * hex identity digests; or + * - "/tor/server/d/D" where D is a plus-separated sequence + * of server descriptor digests, in hex. + * + * Return 0 if we found some matching descriptors, or -1 if we do not + * have any descriptors, no matching descriptors, or if we did not + * recognize the key (URL). + * If -1 is returned *msg will be set to an appropriate error + * message. + * + * XXXX rename this function. It's only called from the controller. + * XXXX in fact, refactor this function, merging as much as possible. + */ +int +dirserv_get_routerdescs(smartlist_t *descs_out, const char *key, + const char **msg) +{ + *msg = NULL; + + if (!strcmp(key, "/tor/server/all")) { + routerlist_t *rl = router_get_routerlist(); + SMARTLIST_FOREACH(rl->routers, routerinfo_t *, r, + smartlist_add(descs_out, &(r->cache_info))); + } else if (!strcmp(key, "/tor/server/authority")) { + const routerinfo_t *ri = router_get_my_routerinfo(); + if (ri) + smartlist_add(descs_out, (void*) &(ri->cache_info)); + } else if (!strcmpstart(key, "/tor/server/d/")) { + smartlist_t *digests = smartlist_new(); + key += strlen("/tor/server/d/"); + dir_split_resource_into_fingerprints(key, digests, NULL, + DSR_HEX|DSR_SORT_UNIQ); + SMARTLIST_FOREACH(digests, const char *, d, + { + signed_descriptor_t *sd = router_get_by_descriptor_digest(d); + if (sd) + smartlist_add(descs_out,sd); + }); + SMARTLIST_FOREACH(digests, char *, d, tor_free(d)); + smartlist_free(digests); + } else if (!strcmpstart(key, "/tor/server/fp/")) { + smartlist_t *digests = smartlist_new(); + time_t cutoff = time(NULL) - ROUTER_MAX_AGE_TO_PUBLISH; + key += strlen("/tor/server/fp/"); + dir_split_resource_into_fingerprints(key, digests, NULL, + DSR_HEX|DSR_SORT_UNIQ); + SMARTLIST_FOREACH_BEGIN(digests, const char *, d) { + if (router_digest_is_me(d)) { + /* make sure desc_routerinfo exists */ + const routerinfo_t *ri = router_get_my_routerinfo(); + if (ri) + smartlist_add(descs_out, (void*) &(ri->cache_info)); + } else { + const routerinfo_t *ri = router_get_by_id_digest(d); + /* Don't actually serve a descriptor that everyone will think is + * expired. This is an (ugly) workaround to keep buggy 0.1.1.10 + * Tors from downloading descriptors that they will throw away. + */ + if (ri && ri->cache_info.published_on > cutoff) + smartlist_add(descs_out, (void*) &(ri->cache_info)); + } + } SMARTLIST_FOREACH_END(d); + SMARTLIST_FOREACH(digests, char *, d, tor_free(d)); + smartlist_free(digests); + } else { + *msg = "Key not recognized"; + return -1; + } + + if (!smartlist_len(descs_out)) { + *msg = "Servers unavailable"; + return -1; + } + return 0; +} + +/** Called when a TLS handshake has completed successfully with a + * router listening at address:or_port, and has yielded + * a certificate with digest digest_rcvd. + * + * Inform the reachability checker that we could get to this guy. + */ +void +dirserv_orconn_tls_done(const tor_addr_t *addr, + uint16_t or_port, + const char *digest_rcvd) +{ + node_t *node = NULL; + tor_addr_port_t orport; + routerinfo_t *ri = NULL; + time_t now = time(NULL); + tor_assert(addr); + tor_assert(digest_rcvd); + + node = node_get_mutable_by_id(digest_rcvd); + if (node == NULL || node->ri == NULL) + return; + ri = node->ri; + + tor_addr_copy(&orport.addr, addr); + orport.port = or_port; + if (router_has_orport(ri, &orport)) { + /* Found the right router. */ + if (!authdir_mode_bridge(get_options()) || + ri->purpose == ROUTER_PURPOSE_BRIDGE) { + char addrstr[TOR_ADDR_BUF_LEN]; + /* This is a bridge or we're not a bridge authorititative -- + mark it as reachable. */ + log_info(LD_DIRSERV, "Found router %s to be reachable at %s:%d. Yay.", + router_describe(ri), + tor_addr_to_str(addrstr, addr, sizeof(addrstr), 1), + ri->or_port); + if (tor_addr_family(addr) == AF_INET) { + rep_hist_note_router_reachable(digest_rcvd, addr, or_port, now); + node->last_reachable = now; + } else if (tor_addr_family(addr) == AF_INET6) { + /* No rephist for IPv6. */ + node->last_reachable6 = now; + } + } + } +} + +/** Called when we, as an authority, receive a new router descriptor either as + * an upload or a download. Used to decide whether to relaunch reachability + * testing for the server. */ +int +dirserv_should_launch_reachability_test(const routerinfo_t *ri, + const routerinfo_t *ri_old) +{ + if (!authdir_mode_handles_descs(get_options(), ri->purpose)) + return 0; + if (!ri_old) { + /* New router: Launch an immediate reachability test, so we will have an + * opinion soon in case we're generating a consensus soon */ + return 1; + } + if (ri_old->is_hibernating && !ri->is_hibernating) { + /* It just came out of hibernation; launch a reachability test */ + return 1; + } + if (! routers_have_same_or_addrs(ri, ri_old)) { + /* Address or port changed; launch a reachability test */ + return 1; + } + return 0; +} + +/** Helper function for dirserv_test_reachability(). Start a TLS + * connection to router, and annotate it with when we started + * the test. */ +void +dirserv_single_reachability_test(time_t now, routerinfo_t *router) +{ + channel_t *chan = NULL; + node_t *node = NULL; + tor_addr_t router_addr; + (void) now; + + tor_assert(router); + node = node_get_mutable_by_id(router->cache_info.identity_digest); + tor_assert(node); + + /* IPv4. */ + log_debug(LD_OR,"Testing reachability of %s at %s:%u.", + router->nickname, router->address, router->or_port); + tor_addr_from_ipv4h(&router_addr, router->addr); + chan = channel_tls_connect(&router_addr, router->or_port, + router->cache_info.identity_digest); + if (chan) command_setup_channel(chan); + + /* Possible IPv6. */ + if (get_options()->AuthDirHasIPv6Connectivity == 1 && + !tor_addr_is_null(&router->ipv6_addr)) { + char addrstr[TOR_ADDR_BUF_LEN]; + log_debug(LD_OR, "Testing reachability of %s at %s:%u.", + router->nickname, + tor_addr_to_str(addrstr, &router->ipv6_addr, sizeof(addrstr), 1), + router->ipv6_orport); + chan = channel_tls_connect(&router->ipv6_addr, router->ipv6_orport, + router->cache_info.identity_digest); + if (chan) command_setup_channel(chan); + } +} + +/** Auth dir server only: load balance such that we only + * try a few connections per call. + * + * The load balancing is such that if we get called once every ten + * seconds, we will cycle through all the tests in + * REACHABILITY_TEST_CYCLE_PERIOD seconds (a bit over 20 minutes). + */ +void +dirserv_test_reachability(time_t now) +{ + /* XXX decide what to do here; see or-talk thread "purging old router + * information, revocation." -NM + * We can't afford to mess with this in 0.1.2.x. The reason is that + * if we stop doing reachability tests on some of routerlist, then + * we'll for-sure think they're down, which may have unexpected + * effects in other parts of the code. It doesn't hurt much to do + * the testing, and directory authorities are easy to upgrade. Let's + * wait til 0.2.0. -RD */ +// time_t cutoff = now - ROUTER_MAX_AGE_TO_PUBLISH; + routerlist_t *rl = router_get_routerlist(); + static char ctr = 0; + int bridge_auth = authdir_mode_bridge(get_options()); + + SMARTLIST_FOREACH_BEGIN(rl->routers, routerinfo_t *, router) { + const char *id_digest = router->cache_info.identity_digest; + if (router_is_me(router)) + continue; + if (bridge_auth && router->purpose != ROUTER_PURPOSE_BRIDGE) + continue; /* bridge authorities only test reachability on bridges */ +// if (router->cache_info.published_on > cutoff) +// continue; + if ((((uint8_t)id_digest[0]) % REACHABILITY_MODULO_PER_TEST) == ctr) { + dirserv_single_reachability_test(now, router); + } + } SMARTLIST_FOREACH_END(router); + ctr = (ctr + 1) % REACHABILITY_MODULO_PER_TEST; /* increment ctr */ +} + +/** Given a fingerprint fp which is either set if we're looking for a + * v2 status, or zeroes if we're looking for a v3 status, or a NUL-padded + * flavor name if we want a flavored v3 status, return a pointer to the + * appropriate cached dir object, or NULL if there isn't one available. */ +static cached_dir_t * +lookup_cached_dir_by_fp(const char *fp) +{ + cached_dir_t *d = NULL; + if (tor_digest_is_zero(fp) && cached_consensuses) { + d = strmap_get(cached_consensuses, "ns"); + } else if (memchr(fp, '\0', DIGEST_LEN) && cached_consensuses && + (d = strmap_get(cached_consensuses, fp))) { + /* this here interface is a nasty hack XXXX024 */; + } + return d; +} + +/** Remove from fps every networkstatus key where both + * a) we have a networkstatus document and + * b) it is not newer than cutoff. + * + * Return 1 if any items were present at all; else return 0. + */ +int +dirserv_remove_old_statuses(smartlist_t *fps, time_t cutoff) +{ + int found_any = 0; + SMARTLIST_FOREACH_BEGIN(fps, char *, digest) { + cached_dir_t *d = lookup_cached_dir_by_fp(digest); + if (!d) + continue; + found_any = 1; + if (d->published <= cutoff) { + tor_free(digest); + SMARTLIST_DEL_CURRENT(fps, digest); + } + } SMARTLIST_FOREACH_END(digest); + + return found_any; +} + +/** Return the cache-info for identity fingerprint fp, or + * its extra-info document if extrainfo is true. Return + * NULL if not found or if the descriptor is older than + * publish_cutoff. */ +static const signed_descriptor_t * +get_signed_descriptor_by_fp(const char *fp, int extrainfo, + time_t publish_cutoff) +{ + if (router_digest_is_me(fp)) { + if (extrainfo) + return &(router_get_my_extrainfo()->cache_info); + else + return &(router_get_my_routerinfo()->cache_info); + } else { + const routerinfo_t *ri = router_get_by_id_digest(fp); + if (ri && + ri->cache_info.published_on > publish_cutoff) { + if (extrainfo) + return extrainfo_get_by_descriptor_digest( + ri->cache_info.extra_info_digest); + else + return &ri->cache_info; + } + } + return NULL; +} + +/** Return true iff we have any of the documents (extrainfo or routerdesc) + * specified by the fingerprints in fps and spool_src. Used to + * decide whether to send a 404. */ +int +dirserv_have_any_serverdesc(smartlist_t *fps, int spool_src) +{ + time_t publish_cutoff = time(NULL)-ROUTER_MAX_AGE_TO_PUBLISH; + SMARTLIST_FOREACH_BEGIN(fps, const char *, fp) { + switch (spool_src) + { + case DIR_SPOOL_EXTRA_BY_DIGEST: + if (extrainfo_get_by_descriptor_digest(fp)) return 1; + break; + case DIR_SPOOL_SERVER_BY_DIGEST: + if (router_get_by_descriptor_digest(fp)) return 1; + break; + case DIR_SPOOL_EXTRA_BY_FP: + case DIR_SPOOL_SERVER_BY_FP: + if (get_signed_descriptor_by_fp(fp, + spool_src == DIR_SPOOL_EXTRA_BY_FP, publish_cutoff)) + return 1; + break; + } + } SMARTLIST_FOREACH_END(fp); + return 0; +} + +/** Return true iff any of the 256-bit elements in fps is the digest of + * a microdescriptor we have. */ +int +dirserv_have_any_microdesc(const smartlist_t *fps) +{ + microdesc_cache_t *cache = get_microdesc_cache(); + SMARTLIST_FOREACH(fps, const char *, fp, + if (microdesc_cache_lookup_by_digest256(cache, fp)) + return 1); + return 0; +} + +/** Return an approximate estimate of the number of bytes that will + * be needed to transmit the server descriptors (if is_serverdescs -- + * they can be either d/ or fp/ queries) or networkstatus objects (if + * !is_serverdescs) listed in fps. If compressed is set, + * we guess how large the data will be after compression. + * + * The return value is an estimate; it might be larger or smaller. + **/ +size_t +dirserv_estimate_data_size(smartlist_t *fps, int is_serverdescs, + int compressed) +{ + size_t result; + tor_assert(fps); + if (is_serverdescs) { + int n = smartlist_len(fps); + const routerinfo_t *me = router_get_my_routerinfo(); + result = (me?me->cache_info.signed_descriptor_len:2048) * n; + if (compressed) + result /= 2; /* observed compressibility is between 35 and 55%. */ + } else { + result = 0; + SMARTLIST_FOREACH(fps, const char *, digest, { + cached_dir_t *dir = lookup_cached_dir_by_fp(digest); + if (dir) + result += compressed ? dir->dir_z_len : dir->dir_len; + }); + } + return result; +} + +/** Given a list of microdescriptor hashes, guess how many bytes will be + * needed to transmit them, and return the guess. */ +size_t +dirserv_estimate_microdesc_size(const smartlist_t *fps, int compressed) +{ + size_t result = smartlist_len(fps) * microdesc_average_size(NULL); + if (compressed) + result /= 2; + return result; +} + +/** When we're spooling data onto our outbuf, add more whenever we dip + * below this threshold. */ +#define DIRSERV_BUFFER_MIN 16384 + +/** Spooling helper: called when we have no more data to spool to conn. + * Flushes any remaining data to be (un)compressed, and changes the spool + * source to NONE. Returns 0 on success, negative on failure. */ +static int +connection_dirserv_finish_spooling(dir_connection_t *conn) +{ + if (conn->zlib_state) { + connection_write_to_buf_zlib("", 0, conn, 1); + tor_zlib_free(conn->zlib_state); + conn->zlib_state = NULL; + } + conn->dir_spool_src = DIR_SPOOL_NONE; + return 0; +} + +/** Spooling helper: called when we're sending a bunch of server descriptors, + * and the outbuf has become too empty. Pulls some entries from + * fingerprint_stack, and writes the corresponding servers onto outbuf. If we + * run out of entries, flushes the zlib state and sets the spool source to + * NONE. Returns 0 on success, negative on failure. + */ +static int +connection_dirserv_add_servers_to_outbuf(dir_connection_t *conn) +{ + int by_fp = (conn->dir_spool_src == DIR_SPOOL_SERVER_BY_FP || + conn->dir_spool_src == DIR_SPOOL_EXTRA_BY_FP); + int extra = (conn->dir_spool_src == DIR_SPOOL_EXTRA_BY_FP || + conn->dir_spool_src == DIR_SPOOL_EXTRA_BY_DIGEST); + time_t publish_cutoff = time(NULL)-ROUTER_MAX_AGE_TO_PUBLISH; + + const or_options_t *options = get_options(); + + while (smartlist_len(conn->fingerprint_stack) && + connection_get_outbuf_len(TO_CONN(conn)) < DIRSERV_BUFFER_MIN) { + const char *body; + char *fp = smartlist_pop_last(conn->fingerprint_stack); + const signed_descriptor_t *sd = NULL; + if (by_fp) { + sd = get_signed_descriptor_by_fp(fp, extra, publish_cutoff); + } else { + sd = extra ? extrainfo_get_by_descriptor_digest(fp) + : router_get_by_descriptor_digest(fp); + } + tor_free(fp); + if (!sd) + continue; + if (!connection_dir_is_encrypted(conn) && !sd->send_unencrypted) { + /* we did this check once before (so we could have an accurate size + * estimate and maybe send a 404 if somebody asked for only bridges on a + * connection), but we need to do it again in case a previously + * unknown bridge descriptor has shown up between then and now. */ + continue; + } + + /** If we are the bridge authority and the descriptor is a bridge + * descriptor, remember that we served this descriptor for desc stats. */ + if (options->BridgeAuthoritativeDir && by_fp) { + const routerinfo_t *router = + router_get_by_id_digest(sd->identity_digest); + /* router can be NULL here when the bridge auth is asked for its own + * descriptor. */ + if (router && router->purpose == ROUTER_PURPOSE_BRIDGE) + rep_hist_note_desc_served(sd->identity_digest); + } + body = signed_descriptor_get_body(sd); + if (conn->zlib_state) { + /* XXXX024 This 'last' business should actually happen on the last + * routerinfo, not on the last fingerprint. */ + int last = ! smartlist_len(conn->fingerprint_stack); + connection_write_to_buf_zlib(body, sd->signed_descriptor_len, conn, + last); + if (last) { + tor_zlib_free(conn->zlib_state); + conn->zlib_state = NULL; + } + } else { + connection_write_to_buf(body, + sd->signed_descriptor_len, + TO_CONN(conn)); + } + } + + if (!smartlist_len(conn->fingerprint_stack)) { + /* We just wrote the last one; finish up. */ + conn->dir_spool_src = DIR_SPOOL_NONE; + smartlist_free(conn->fingerprint_stack); + conn->fingerprint_stack = NULL; + } + return 0; +} + +/** Spooling helper: called when we're sending a bunch of microdescriptors, + * and the outbuf has become too empty. Pulls some entries from + * fingerprint_stack, and writes the corresponding microdescs onto outbuf. If + * we run out of entries, flushes the zlib state and sets the spool source to + * NONE. Returns 0 on success, negative on failure. + */ +static int +connection_dirserv_add_microdescs_to_outbuf(dir_connection_t *conn) +{ + microdesc_cache_t *cache = get_microdesc_cache(); + while (smartlist_len(conn->fingerprint_stack) && + connection_get_outbuf_len(TO_CONN(conn)) < DIRSERV_BUFFER_MIN) { + char *fp256 = smartlist_pop_last(conn->fingerprint_stack); + microdesc_t *md = microdesc_cache_lookup_by_digest256(cache, fp256); + tor_free(fp256); + if (!md || !md->body) + continue; + if (conn->zlib_state) { + /* XXXX024 This 'last' business should actually happen on the last + * routerinfo, not on the last fingerprint. */ + int last = !smartlist_len(conn->fingerprint_stack); + connection_write_to_buf_zlib(md->body, md->bodylen, conn, last); + if (last) { + tor_zlib_free(conn->zlib_state); + conn->zlib_state = NULL; + } + } else { + connection_write_to_buf(md->body, md->bodylen, TO_CONN(conn)); + } + } + if (!smartlist_len(conn->fingerprint_stack)) { + conn->dir_spool_src = DIR_SPOOL_NONE; + smartlist_free(conn->fingerprint_stack); + conn->fingerprint_stack = NULL; + } + return 0; +} + +/** Spooling helper: Called when we're sending a directory or networkstatus, + * and the outbuf has become too empty. Pulls some bytes from + * conn-\>cached_dir-\>dir_z, uncompresses them if appropriate, and + * puts them on the outbuf. If we run out of entries, flushes the zlib state + * and sets the spool source to NONE. Returns 0 on success, negative on + * failure. */ +static int +connection_dirserv_add_dir_bytes_to_outbuf(dir_connection_t *conn) +{ + ssize_t bytes; + int64_t remaining; + + bytes = DIRSERV_BUFFER_MIN - connection_get_outbuf_len(TO_CONN(conn)); + tor_assert(bytes > 0); + tor_assert(conn->cached_dir); + if (bytes < 8192) + bytes = 8192; + remaining = conn->cached_dir->dir_z_len - conn->cached_dir_offset; + if (bytes > remaining) + bytes = (ssize_t) remaining; + + if (conn->zlib_state) { + connection_write_to_buf_zlib( + conn->cached_dir->dir_z + conn->cached_dir_offset, + bytes, conn, bytes == remaining); + } else { + connection_write_to_buf(conn->cached_dir->dir_z + conn->cached_dir_offset, + bytes, TO_CONN(conn)); + } + conn->cached_dir_offset += bytes; + if (conn->cached_dir_offset == (int)conn->cached_dir->dir_z_len) { + /* We just wrote the last one; finish up. */ + connection_dirserv_finish_spooling(conn); + cached_dir_decref(conn->cached_dir); + conn->cached_dir = NULL; + } + return 0; +} + +/** Spooling helper: Called when we're spooling networkstatus objects on + * conn, and the outbuf has become too empty. If the current + * networkstatus object (in conn-\>cached_dir) has more data, pull data + * from there. Otherwise, pop the next fingerprint from fingerprint_stack, + * and start spooling the next networkstatus. (A digest of all 0 bytes is + * treated as a request for the current consensus.) If we run out of entries, + * flushes the zlib state and sets the spool source to NONE. Returns 0 on + * success, negative on failure. */ +static int +connection_dirserv_add_networkstatus_bytes_to_outbuf(dir_connection_t *conn) +{ + + while (connection_get_outbuf_len(TO_CONN(conn)) < DIRSERV_BUFFER_MIN) { + if (conn->cached_dir) { + int uncompressing = (conn->zlib_state != NULL); + int r = connection_dirserv_add_dir_bytes_to_outbuf(conn); + if (conn->dir_spool_src == DIR_SPOOL_NONE) { + /* add_dir_bytes thinks we're done with the cached_dir. But we + * may have more cached_dirs! */ + conn->dir_spool_src = DIR_SPOOL_NETWORKSTATUS; + /* This bit is tricky. If we were uncompressing the last + * networkstatus, we may need to make a new zlib object to + * uncompress the next one. */ + if (uncompressing && ! conn->zlib_state && + conn->fingerprint_stack && + smartlist_len(conn->fingerprint_stack)) { + conn->zlib_state = tor_zlib_new(0, ZLIB_METHOD); + } + } + if (r) return r; + } else if (conn->fingerprint_stack && + smartlist_len(conn->fingerprint_stack)) { + /* Add another networkstatus; start serving it. */ + char *fp = smartlist_pop_last(conn->fingerprint_stack); + cached_dir_t *d = lookup_cached_dir_by_fp(fp); + tor_free(fp); + if (d) { + ++d->refcnt; + conn->cached_dir = d; + conn->cached_dir_offset = 0; + } + } else { + connection_dirserv_finish_spooling(conn); + smartlist_free(conn->fingerprint_stack); + conn->fingerprint_stack = NULL; + return 0; + } + } + return 0; +} + +/** Called whenever we have flushed some directory data in state + * SERVER_WRITING. */ +int +connection_dirserv_flushed_some(dir_connection_t *conn) +{ + tor_assert(conn->base_.state == DIR_CONN_STATE_SERVER_WRITING); + + if (connection_get_outbuf_len(TO_CONN(conn)) >= DIRSERV_BUFFER_MIN) + return 0; + + switch (conn->dir_spool_src) { + case DIR_SPOOL_EXTRA_BY_DIGEST: + case DIR_SPOOL_EXTRA_BY_FP: + case DIR_SPOOL_SERVER_BY_DIGEST: + case DIR_SPOOL_SERVER_BY_FP: + return connection_dirserv_add_servers_to_outbuf(conn); + case DIR_SPOOL_MICRODESC: + return connection_dirserv_add_microdescs_to_outbuf(conn); + case DIR_SPOOL_CACHED_DIR: + return connection_dirserv_add_dir_bytes_to_outbuf(conn); + case DIR_SPOOL_NETWORKSTATUS: + return connection_dirserv_add_networkstatus_bytes_to_outbuf(conn); + case DIR_SPOOL_NONE: + default: + return 0; + } +} + +/** Release all storage used by the directory server. */ +void +dirserv_free_all(void) +{ + dirserv_free_fingerprint_list(); + + cached_dir_decref(the_directory); + clear_cached_dir(&the_runningrouters); + cached_dir_decref(cached_directory); + clear_cached_dir(&cached_runningrouters); + + strmap_free(cached_consensuses, free_cached_dir_); + cached_consensuses = NULL; + + dirserv_clear_measured_bw_cache(); +} + diff --git a/src/tor/dirserv.h b/src/tor/dirserv.h new file mode 100644 index 0000000..8591c4c --- /dev/null +++ b/src/tor/dirserv.h @@ -0,0 +1,138 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file dirserv.h + * \brief Header file for dirserv.c. + **/ + +#ifndef TOR_DIRSERV_H +#define TOR_DIRSERV_H + +#include "testsupport.h" + +/** What fraction (1 over this number) of the relay ID space do we + * (as a directory authority) launch connections to at each reachability + * test? */ +#define REACHABILITY_MODULO_PER_TEST 128 + +/** How often (in seconds) do we launch reachability tests? */ +#define REACHABILITY_TEST_INTERVAL 10 + +/** How many seconds apart are the reachability tests for a given relay? */ +#define REACHABILITY_TEST_CYCLE_PERIOD \ + (REACHABILITY_TEST_INTERVAL*REACHABILITY_MODULO_PER_TEST) + +/** Maximum length of an exit policy summary. */ +#define MAX_EXITPOLICY_SUMMARY_LEN 1000 + +/** Maximum allowable length of a version line in a networkstatus. */ +#define MAX_V_LINE_LEN 128 + +int connection_dirserv_flushed_some(dir_connection_t *conn); + +int dirserv_add_own_fingerprint(const char *nickname, crypto_pk_t *pk); +int dirserv_load_fingerprint_file(void); +void dirserv_free_fingerprint_list(void); +const char *dirserv_get_nickname_by_digest(const char *digest); +enum was_router_added_t dirserv_add_multiple_descriptors( + const char *desc, uint8_t purpose, + const char *source, + const char **msg); +enum was_router_added_t dirserv_add_descriptor(routerinfo_t *ri, + const char **msg, + const char *source); +void dirserv_set_router_is_running(routerinfo_t *router, time_t now); +int list_server_status_v1(smartlist_t *routers, char **router_status_out, + int for_controller); +int dirserv_dump_directory_to_string(char **dir_out, + crypto_pk_t *private_key); +char *dirserv_get_flag_thresholds_line(void); +void dirserv_compute_bridge_flag_thresholds(routerlist_t *rl); + +int directory_fetches_from_authorities(const or_options_t *options); +int directory_fetches_dir_info_early(const or_options_t *options); +int directory_fetches_dir_info_later(const or_options_t *options); +int directory_caches_unknown_auth_certs(const or_options_t *options); +int directory_caches_dir_info(const or_options_t *options); +int directory_permits_begindir_requests(const or_options_t *options); +int directory_permits_controller_requests(const or_options_t *options); +int directory_too_idle_to_fetch_descriptors(const or_options_t *options, + time_t now); + +void directory_set_dirty(void); +cached_dir_t *dirserv_get_directory(void); +cached_dir_t *dirserv_get_runningrouters(void); +cached_dir_t *dirserv_get_consensus(const char *flavor_name); +void dirserv_set_cached_consensus_networkstatus(const char *consensus, + const char *flavor_name, + const digests_t *digests, + time_t published); +void dirserv_clear_old_networkstatuses(time_t cutoff); +void dirserv_clear_old_v1_info(time_t now); +int dirserv_get_routerdesc_fingerprints(smartlist_t *fps_out, const char *key, + const char **msg, + int for_unencrypted_conn, + int is_extrainfo); +int dirserv_get_routerdescs(smartlist_t *descs_out, const char *key, + const char **msg); +void dirserv_orconn_tls_done(const tor_addr_t *addr, + uint16_t or_port, + const char *digest_rcvd); +int dirserv_should_launch_reachability_test(const routerinfo_t *ri, + const routerinfo_t *ri_old); +void dirserv_single_reachability_test(time_t now, routerinfo_t *router); +void dirserv_test_reachability(time_t now); +int authdir_wants_to_reject_router(routerinfo_t *ri, const char **msg, + int complain, + int *valid_out); +uint32_t dirserv_router_get_status(const routerinfo_t *router, + const char **msg); +void dirserv_set_node_flags_from_authoritative_status(node_t *node, + uint32_t authstatus); + +int dirserv_would_reject_router(const routerstatus_t *rs); +int dirserv_remove_old_statuses(smartlist_t *fps, time_t cutoff); +int dirserv_have_any_serverdesc(smartlist_t *fps, int spool_src); +int dirserv_have_any_microdesc(const smartlist_t *fps); +size_t dirserv_estimate_data_size(smartlist_t *fps, int is_serverdescs, + int compressed); +size_t dirserv_estimate_microdesc_size(const smartlist_t *fps, int compressed); + +char *routerstatus_format_entry( + const routerstatus_t *rs, const char *platform, + routerstatus_format_type_t format, + const vote_routerstatus_t *vrs); +void dirserv_free_all(void); +void cached_dir_decref(cached_dir_t *d); +cached_dir_t *new_cached_dir(char *s, time_t published); + +#ifdef DIRSERV_PRIVATE + +/* Put the MAX_MEASUREMENT_AGE #define here so unit tests can see it */ +#define MAX_MEASUREMENT_AGE (3*24*60*60) /* 3 days */ + +STATIC int measured_bw_line_parse(measured_bw_line_t *out, const char *line); + +STATIC int measured_bw_line_apply(measured_bw_line_t *parsed_line, + smartlist_t *routerstatuses); + +STATIC void dirserv_cache_measured_bw(const measured_bw_line_t *parsed_line, + time_t as_of); +STATIC void dirserv_clear_measured_bw_cache(void); +STATIC void dirserv_expire_measured_bw_cache(time_t now); +STATIC int dirserv_get_measured_bw_cache_size(void); +STATIC int dirserv_query_measured_bw_cache_kb(const char *node_id, + long *bw_out, + time_t *as_of_out); +STATIC int dirserv_has_measured_bw(const char *node_id); +#endif + +int dirserv_read_measured_bandwidths(const char *from_file, + smartlist_t *routerstatuses); + +#endif + diff --git a/src/tor/dirvote.c b/src/tor/dirvote.c new file mode 100644 index 0000000..4d3ee9c --- /dev/null +++ b/src/tor/dirvote.c @@ -0,0 +1,3778 @@ +/* Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#define DIRVOTE_PRIVATE +#include "or.h" +#include "config.h" +#include "directory.h" +#include "dirserv.h" +#include "dirvote.h" +#include "microdesc.h" +#include "networkstatus.h" +#include "policies.h" +#include "rephist.h" +#include "router.h" +#include "routerlist.h" +#include "routerparse.h" + +/** + * \file dirvote.c + * \brief Functions to compute directory consensus, and schedule voting. + **/ + +/** A consensus that we have built and are appending signatures to. Once it's + * time to publish it, it will become an active consensus if it accumulates + * enough signatures. */ +typedef struct pending_consensus_t { + /** The body of the consensus that we're currently building. Once we + * have it built, it goes into dirserv.c */ + char *body; + /** The parsed in-progress consensus document. */ + networkstatus_t *consensus; +} pending_consensus_t; + +/* DOCDOC dirvote_add_signatures_to_all_pending_consensuses */ +static int dirvote_add_signatures_to_all_pending_consensuses( + const char *detached_signatures_body, + const char *source, + const char **msg_out); +static int dirvote_add_signatures_to_pending_consensus( + pending_consensus_t *pc, + ns_detached_signatures_t *sigs, + const char *source, + int severity, + const char **msg_out); +static char *list_v3_auth_ids(void); +static void dirvote_fetch_missing_votes(void); +static void dirvote_fetch_missing_signatures(void); +static int dirvote_perform_vote(void); +static void dirvote_clear_votes(int all_votes); +static int dirvote_compute_consensuses(void); +static int dirvote_publish_consensus(void); +static char *make_consensus_method_list(int low, int high, const char *sep); + +/* ===== + * Voting + * =====*/ + +/** Return a new string containing the string representation of the vote in + * v3_ns, signed with our v3 signing key private_signing_key. + * For v3 authorities. */ +STATIC char * +format_networkstatus_vote(crypto_pk_t *private_signing_key, + networkstatus_t *v3_ns) +{ + smartlist_t *chunks; + const char *client_versions = NULL, *server_versions = NULL; + char fingerprint[FINGERPRINT_LEN+1]; + char digest[DIGEST_LEN]; + uint32_t addr; + char *client_versions_line = NULL, *server_versions_line = NULL; + networkstatus_voter_info_t *voter; + char *status = NULL; + + tor_assert(private_signing_key); + tor_assert(v3_ns->type == NS_TYPE_VOTE || v3_ns->type == NS_TYPE_OPINION); + + voter = smartlist_get(v3_ns->voters, 0); + + addr = voter->addr; + + base16_encode(fingerprint, sizeof(fingerprint), + v3_ns->cert->cache_info.identity_digest, DIGEST_LEN); + client_versions = v3_ns->client_versions; + server_versions = v3_ns->server_versions; + + if (client_versions) { + tor_asprintf(&client_versions_line, "client-versions %s\n", + client_versions); + } else { + client_versions_line = tor_strdup(""); + } + if (server_versions) { + tor_asprintf(&server_versions_line, "server-versions %s\n", + server_versions); + } else { + server_versions_line = tor_strdup(""); + } + + chunks = smartlist_new(); + { + char published[ISO_TIME_LEN+1]; + char va[ISO_TIME_LEN+1]; + char fu[ISO_TIME_LEN+1]; + char vu[ISO_TIME_LEN+1]; + char *flags = smartlist_join_strings(v3_ns->known_flags, " ", 0, NULL); + /* XXXX Abstraction violation: should be pulling a field out of v3_ns.*/ + char *flag_thresholds = dirserv_get_flag_thresholds_line(); + char *params; + authority_cert_t *cert = v3_ns->cert; + char *methods = + make_consensus_method_list(1, MAX_SUPPORTED_CONSENSUS_METHOD, " "); + format_iso_time(published, v3_ns->published); + format_iso_time(va, v3_ns->valid_after); + format_iso_time(fu, v3_ns->fresh_until); + format_iso_time(vu, v3_ns->valid_until); + + if (v3_ns->net_params) + params = smartlist_join_strings(v3_ns->net_params, " ", 0, NULL); + else + params = tor_strdup(""); + + tor_assert(cert); + smartlist_add_asprintf(chunks, + "network-status-version 3\n" + "vote-status %s\n" + "consensus-methods %s\n" + "published %s\n" + "valid-after %s\n" + "fresh-until %s\n" + "valid-until %s\n" + "voting-delay %d %d\n" + "%s%s" /* versions */ + "known-flags %s\n" + "flag-thresholds %s\n" + "params %s\n" + "dir-source %s %s %s %s %d %d\n" + "contact %s\n", + v3_ns->type == NS_TYPE_VOTE ? "vote" : "opinion", + methods, + published, va, fu, vu, + v3_ns->vote_seconds, v3_ns->dist_seconds, + client_versions_line, + server_versions_line, + flags, + flag_thresholds, + params, + voter->nickname, fingerprint, voter->address, + fmt_addr32(addr), voter->dir_port, voter->or_port, + voter->contact); + + tor_free(params); + tor_free(flags); + tor_free(flag_thresholds); + tor_free(methods); + + if (!tor_digest_is_zero(voter->legacy_id_digest)) { + char fpbuf[HEX_DIGEST_LEN+1]; + base16_encode(fpbuf, sizeof(fpbuf), voter->legacy_id_digest, DIGEST_LEN); + smartlist_add_asprintf(chunks, "legacy-dir-key %s\n", fpbuf); + } + + smartlist_add(chunks, tor_strndup(cert->cache_info.signed_descriptor_body, + cert->cache_info.signed_descriptor_len)); + } + + SMARTLIST_FOREACH_BEGIN(v3_ns->routerstatus_list, vote_routerstatus_t *, + vrs) { + char *rsf; + vote_microdesc_hash_t *h; + rsf = routerstatus_format_entry(&vrs->status, + vrs->version, NS_V3_VOTE, vrs); + if (rsf) + smartlist_add(chunks, rsf); + + for (h = vrs->microdesc; h; h = h->next) { + smartlist_add(chunks, tor_strdup(h->microdesc_hash_line)); + } + } SMARTLIST_FOREACH_END(vrs); + + smartlist_add(chunks, tor_strdup("directory-footer\n")); + + /* The digest includes everything up through the space after + * directory-signature. (Yuck.) */ + crypto_digest_smartlist(digest, DIGEST_LEN, chunks, + "directory-signature ", DIGEST_SHA1); + + { + char signing_key_fingerprint[FINGERPRINT_LEN+1]; + if (crypto_pk_get_fingerprint(private_signing_key, + signing_key_fingerprint, 0)<0) { + log_warn(LD_BUG, "Unable to get fingerprint for signing key"); + goto err; + } + + smartlist_add_asprintf(chunks, "directory-signature %s %s\n", fingerprint, + signing_key_fingerprint); + } + + note_crypto_pk_op(SIGN_DIR); + { + char *sig = router_get_dirobj_signature(digest, DIGEST_LEN, + private_signing_key); + if (!sig) { + log_warn(LD_BUG, "Unable to sign networkstatus vote."); + goto err; + } + smartlist_add(chunks, sig); + } + + status = smartlist_join_strings(chunks, "", 0, NULL); + + { + networkstatus_t *v; + if (!(v = networkstatus_parse_vote_from_string(status, NULL, + v3_ns->type))) { + log_err(LD_BUG,"Generated a networkstatus %s we couldn't parse: " + "<<%s>>", + v3_ns->type == NS_TYPE_VOTE ? "vote" : "opinion", status); + goto err; + } + networkstatus_vote_free(v); + } + + goto done; + + err: + tor_free(status); + done: + tor_free(client_versions_line); + tor_free(server_versions_line); + if (chunks) { + SMARTLIST_FOREACH(chunks, char *, cp, tor_free(cp)); + smartlist_free(chunks); + } + return status; +} + +/* ===== + * Consensus generation + * ===== */ + +/** Given a vote vote (not a consensus!), return its associated + * networkstatus_voter_info_t. */ +static networkstatus_voter_info_t * +get_voter(const networkstatus_t *vote) +{ + tor_assert(vote); + tor_assert(vote->type == NS_TYPE_VOTE); + tor_assert(vote->voters); + tor_assert(smartlist_len(vote->voters) == 1); + return smartlist_get(vote->voters, 0); +} + +/** Return the signature made by voter using the algorithm + * alg, or NULL if none is found. */ +document_signature_t * +voter_get_sig_by_algorithm(const networkstatus_voter_info_t *voter, + digest_algorithm_t alg) +{ + if (!voter->sigs) + return NULL; + SMARTLIST_FOREACH(voter->sigs, document_signature_t *, sig, + if (sig->alg == alg) + return sig); + return NULL; +} + +/** Temporary structure used in constructing a list of dir-source entries + * for a consensus. One of these is generated for every vote, and one more + * for every legacy key in each vote. */ +typedef struct dir_src_ent_t { + networkstatus_t *v; + const char *digest; + int is_legacy; +} dir_src_ent_t; + +/** Helper for sorting networkstatus_t votes (not consensuses) by the + * hash of their voters' identity digests. */ +static int +compare_votes_by_authority_id_(const void **_a, const void **_b) +{ + const networkstatus_t *a = *_a, *b = *_b; + return fast_memcmp(get_voter(a)->identity_digest, + get_voter(b)->identity_digest, DIGEST_LEN); +} + +/** Helper: Compare the dir_src_ent_ts in *_a and *_b by + * their identity digests, and return -1, 0, or 1 depending on their + * ordering */ +static int +compare_dir_src_ents_by_authority_id_(const void **_a, const void **_b) +{ + const dir_src_ent_t *a = *_a, *b = *_b; + const networkstatus_voter_info_t *a_v = get_voter(a->v), + *b_v = get_voter(b->v); + const char *a_id, *b_id; + a_id = a->is_legacy ? a_v->legacy_id_digest : a_v->identity_digest; + b_id = b->is_legacy ? b_v->legacy_id_digest : b_v->identity_digest; + + return fast_memcmp(a_id, b_id, DIGEST_LEN); +} + +/** Given a sorted list of strings in, add every member to out + * that occurs more than min times. */ +static void +get_frequent_members(smartlist_t *out, smartlist_t *in, int min) +{ + char *cur = NULL; + int count = 0; + SMARTLIST_FOREACH_BEGIN(in, char *, cp) { + if (cur && !strcmp(cp, cur)) { + ++count; + } else { + if (count > min) + smartlist_add(out, cur); + cur = cp; + count = 1; + } + } SMARTLIST_FOREACH_END(cp); + if (count > min) + smartlist_add(out, cur); +} + +/** Given a sorted list of strings lst, return the member that appears + * most. Break ties in favor of later-occurring members. */ +#define get_most_frequent_member(lst) \ + smartlist_get_most_frequent_string(lst) + +/** Return 0 if and only if a and b are routerstatuses + * that come from the same routerinfo, with the same derived elements. + */ +static int +compare_vote_rs(const vote_routerstatus_t *a, const vote_routerstatus_t *b) +{ + int r; + if ((r = fast_memcmp(a->status.identity_digest, b->status.identity_digest, + DIGEST_LEN))) + return r; + if ((r = fast_memcmp(a->status.descriptor_digest, + b->status.descriptor_digest, + DIGEST_LEN))) + return r; + if ((r = (int)(b->status.published_on - a->status.published_on))) + return r; + if ((r = strcmp(b->status.nickname, a->status.nickname))) + return r; + if ((r = (((int)b->status.addr) - ((int)a->status.addr)))) + return r; + if ((r = (((int)b->status.or_port) - ((int)a->status.or_port)))) + return r; + if ((r = (((int)b->status.dir_port) - ((int)a->status.dir_port)))) + return r; + return 0; +} + +/** Helper for sorting routerlists based on compare_vote_rs. */ +static int +compare_vote_rs_(const void **_a, const void **_b) +{ + const vote_routerstatus_t *a = *_a, *b = *_b; + return compare_vote_rs(a,b); +} + +/** Helper for sorting OR ports. */ +static int +compare_orports_(const void **_a, const void **_b) +{ + const tor_addr_port_t *a = *_a, *b = *_b; + int r; + + if ((r = tor_addr_compare(&a->addr, &b->addr, CMP_EXACT))) + return r; + if ((r = (((int) b->port) - ((int) a->port)))) + return r; + + return 0; +} + +/** Given a list of vote_routerstatus_t, all for the same router identity, + * return whichever is most frequent, breaking ties in favor of more + * recently published vote_routerstatus_t and in case of ties there, + * in favor of smaller descriptor digest. + */ +static vote_routerstatus_t * +compute_routerstatus_consensus(smartlist_t *votes, int consensus_method, + char *microdesc_digest256_out, + tor_addr_port_t *best_alt_orport_out) +{ + vote_routerstatus_t *most = NULL, *cur = NULL; + int most_n = 0, cur_n = 0; + time_t most_published = 0; + + /* compare_vote_rs_() sorts the items by identity digest (all the same), + * then by SD digest. That way, if we have a tie that the published_on + * date cannot tie, we use the descriptor with the smaller digest. + */ + smartlist_sort(votes, compare_vote_rs_); + SMARTLIST_FOREACH_BEGIN(votes, vote_routerstatus_t *, rs) { + if (cur && !compare_vote_rs(cur, rs)) { + ++cur_n; + } else { + if (cur && (cur_n > most_n || + (cur_n == most_n && + cur->status.published_on > most_published))) { + most = cur; + most_n = cur_n; + most_published = cur->status.published_on; + } + cur_n = 1; + cur = rs; + } + } SMARTLIST_FOREACH_END(rs); + + if (cur_n > most_n || + (cur && cur_n == most_n && cur->status.published_on > most_published)) { + most = cur; + most_n = cur_n; + most_published = cur->status.published_on; + } + + tor_assert(most); + + /* If we're producing "a" lines, vote on potential alternative (sets + * of) OR port(s) in the winning routerstatuses. + * + * XXX prop186 There's at most one alternative OR port (_the_ IPv6 + * port) for now. */ + if (consensus_method >= MIN_METHOD_FOR_A_LINES && best_alt_orport_out) { + smartlist_t *alt_orports = smartlist_new(); + const tor_addr_port_t *most_alt_orport = NULL; + + SMARTLIST_FOREACH_BEGIN(votes, vote_routerstatus_t *, rs) { + if (compare_vote_rs(most, rs) == 0 && + !tor_addr_is_null(&rs->status.ipv6_addr) + && rs->status.ipv6_orport) { + smartlist_add(alt_orports, tor_addr_port_new(&rs->status.ipv6_addr, + rs->status.ipv6_orport)); + } + } SMARTLIST_FOREACH_END(rs); + + smartlist_sort(alt_orports, compare_orports_); + most_alt_orport = smartlist_get_most_frequent(alt_orports, + compare_orports_); + if (most_alt_orport) { + memcpy(best_alt_orport_out, most_alt_orport, sizeof(tor_addr_port_t)); + log_debug(LD_DIR, "\"a\" line winner for %s is %s", + most->status.nickname, + fmt_addrport(&most_alt_orport->addr, most_alt_orport->port)); + } + + SMARTLIST_FOREACH(alt_orports, tor_addr_port_t *, ap, tor_free(ap)); + smartlist_free(alt_orports); + } + + if (consensus_method >= MIN_METHOD_FOR_MICRODESC && + microdesc_digest256_out) { + smartlist_t *digests = smartlist_new(); + const char *best_microdesc_digest; + SMARTLIST_FOREACH_BEGIN(votes, vote_routerstatus_t *, rs) { + char d[DIGEST256_LEN]; + if (compare_vote_rs(rs, most)) + continue; + if (!vote_routerstatus_find_microdesc_hash(d, rs, consensus_method, + DIGEST_SHA256)) + smartlist_add(digests, tor_memdup(d, sizeof(d))); + } SMARTLIST_FOREACH_END(rs); + smartlist_sort_digests256(digests); + best_microdesc_digest = smartlist_get_most_frequent_digest256(digests); + if (best_microdesc_digest) + memcpy(microdesc_digest256_out, best_microdesc_digest, DIGEST256_LEN); + SMARTLIST_FOREACH(digests, char *, cp, tor_free(cp)); + smartlist_free(digests); + } + + return most; +} + +/** Sorting helper: compare two strings based on their values as base-ten + * positive integers. (Non-integers are treated as prior to all integers, and + * compared lexically.) */ +static int +cmp_int_strings_(const void **_a, const void **_b) +{ + const char *a = *_a, *b = *_b; + int ai = (int)tor_parse_long(a, 10, 1, INT_MAX, NULL, NULL); + int bi = (int)tor_parse_long(b, 10, 1, INT_MAX, NULL, NULL); + if (aisupported_methods); + smartlist_add_all(tmp, vote->supported_methods); + smartlist_sort(tmp, cmp_int_strings_); + smartlist_uniq(tmp, cmp_int_strings_, NULL); + smartlist_add_all(all_methods, tmp); + smartlist_clear(tmp); + }); + + smartlist_sort(all_methods, cmp_int_strings_); + get_frequent_members(acceptable_methods, all_methods, min); + n_ok = smartlist_len(acceptable_methods); + if (n_ok) { + const char *best = smartlist_get(acceptable_methods, n_ok-1); + result = (int)tor_parse_long(best, 10, 1, INT_MAX, NULL, NULL); + } else { + result = 1; + } + smartlist_free(tmp); + smartlist_free(all_methods); + smartlist_free(acceptable_methods); + return result; +} + +/** Return true iff method is a consensus method that we support. */ +static int +consensus_method_is_supported(int method) +{ + return (method >= 1) && (method <= MAX_SUPPORTED_CONSENSUS_METHOD); +} + +/** Return a newly allocated string holding the numbers between low and high + * (inclusive) that are supported consensus methods. */ +static char * +make_consensus_method_list(int low, int high, const char *separator) +{ + char *list; + + int i; + smartlist_t *lst; + lst = smartlist_new(); + for (i = low; i <= high; ++i) { + if (!consensus_method_is_supported(i)) + continue; + smartlist_add_asprintf(lst, "%d", i); + } + list = smartlist_join_strings(lst, separator, 0, NULL); + tor_assert(list); + SMARTLIST_FOREACH(lst, char *, cp, tor_free(cp)); + smartlist_free(lst); + return list; +} + +/** Helper: given lst, a list of version strings such that every + * version appears once for every versioning voter who recommends it, return a + * newly allocated string holding the resulting client-versions or + * server-versions list. May change contents of lst */ +static char * +compute_consensus_versions_list(smartlist_t *lst, int n_versioning) +{ + int min = n_versioning / 2; + smartlist_t *good = smartlist_new(); + char *result; + sort_version_list(lst, 0); + get_frequent_members(good, lst, min); + result = smartlist_join_strings(good, ",", 0, NULL); + smartlist_free(good); + return result; +} + +/** Minimum number of directory authorities voting for a parameter to + * include it in the consensus, if consensus method 12 or later is to be + * used. See proposal 178 for details. */ +#define MIN_VOTES_FOR_PARAM 3 + +/** Helper: given a list of valid networkstatus_t, return a new string + * containing the contents of the consensus network parameter set. + */ +STATIC char * +dirvote_compute_params(smartlist_t *votes, int method, int total_authorities) +{ + int i; + int32_t *vals; + + int cur_param_len; + const char *cur_param; + const char *eq; + char *result; + + const int n_votes = smartlist_len(votes); + smartlist_t *output; + smartlist_t *param_list = smartlist_new(); + + /* We require that the parameter lists in the votes are well-formed: that + is, that their keywords are unique and sorted, and that their values are + between INT32_MIN and INT32_MAX inclusive. This should be guaranteed by + the parsing code. */ + + vals = tor_malloc(sizeof(int)*n_votes); + + SMARTLIST_FOREACH_BEGIN(votes, networkstatus_t *, v) { + if (!v->net_params) + continue; + smartlist_add_all(param_list, v->net_params); + } SMARTLIST_FOREACH_END(v); + + if (smartlist_len(param_list) == 0) { + tor_free(vals); + smartlist_free(param_list); + return NULL; + } + + smartlist_sort_strings(param_list); + i = 0; + cur_param = smartlist_get(param_list, 0); + eq = strchr(cur_param, '='); + tor_assert(eq); + cur_param_len = (int)(eq+1 - cur_param); + + output = smartlist_new(); + + SMARTLIST_FOREACH_BEGIN(param_list, const char *, param) { + const char *next_param; + int ok=0; + eq = strchr(param, '='); + tor_assert(i total_authorities/2 || + i >= MIN_VOTES_FOR_PARAM) { + int32_t median = median_int32(vals, i); + char *out_string = tor_malloc(64+cur_param_len); + memcpy(out_string, param, cur_param_len); + tor_snprintf(out_string+cur_param_len,64, "%ld", (long)median); + smartlist_add(output, out_string); + } + + i = 0; + if (next_param) { + eq = strchr(next_param, '='); + cur_param_len = (int)(eq+1 - next_param); + } + } + } SMARTLIST_FOREACH_END(param); + + result = smartlist_join_strings(output, " ", 0, NULL); + SMARTLIST_FOREACH(output, char *, cp, tor_free(cp)); + smartlist_free(output); + smartlist_free(param_list); + tor_free(vals); + return result; +} + +#define RANGE_CHECK(a,b,c,d,e,f,g,mx) \ + ((a) >= 0 && (a) <= (mx) && (b) >= 0 && (b) <= (mx) && \ + (c) >= 0 && (c) <= (mx) && (d) >= 0 && (d) <= (mx) && \ + (e) >= 0 && (e) <= (mx) && (f) >= 0 && (f) <= (mx) && \ + (g) >= 0 && (g) <= (mx)) + +#define CHECK_EQ(a, b, margin) \ + ((a)-(b) >= 0 ? (a)-(b) <= (margin) : (b)-(a) <= (margin)) + +typedef enum { + BW_WEIGHTS_NO_ERROR = 0, + BW_WEIGHTS_RANGE_ERROR = 1, + BW_WEIGHTS_SUMG_ERROR = 2, + BW_WEIGHTS_SUME_ERROR = 3, + BW_WEIGHTS_SUMD_ERROR = 4, + BW_WEIGHTS_BALANCE_MID_ERROR = 5, + BW_WEIGHTS_BALANCE_EG_ERROR = 6 +} bw_weights_error_t; + +/** + * Verify that any weightings satisfy the balanced formulas. + */ +static bw_weights_error_t +networkstatus_check_weights(int64_t Wgg, int64_t Wgd, int64_t Wmg, + int64_t Wme, int64_t Wmd, int64_t Wee, + int64_t Wed, int64_t scale, int64_t G, + int64_t M, int64_t E, int64_t D, int64_t T, + int64_t margin, int do_balance) { + bw_weights_error_t berr = BW_WEIGHTS_NO_ERROR; + + // Wed + Wmd + Wgd == 1 + if (!CHECK_EQ(Wed + Wmd + Wgd, scale, margin)) { + berr = BW_WEIGHTS_SUMD_ERROR; + goto out; + } + + // Wmg + Wgg == 1 + if (!CHECK_EQ(Wmg + Wgg, scale, margin)) { + berr = BW_WEIGHTS_SUMG_ERROR; + goto out; + } + + // Wme + Wee == 1 + if (!CHECK_EQ(Wme + Wee, scale, margin)) { + berr = BW_WEIGHTS_SUME_ERROR; + goto out; + } + + // Verify weights within range 0->1 + if (!RANGE_CHECK(Wgg, Wgd, Wmg, Wme, Wmd, Wed, Wee, scale)) { + berr = BW_WEIGHTS_RANGE_ERROR; + goto out; + } + + if (do_balance) { + // Wgg*G + Wgd*D == Wee*E + Wed*D, already scaled + if (!CHECK_EQ(Wgg*G + Wgd*D, Wee*E + Wed*D, (margin*T)/3)) { + berr = BW_WEIGHTS_BALANCE_EG_ERROR; + goto out; + } + + // Wgg*G + Wgd*D == M*scale + Wmd*D + Wme*E + Wmg*G, already scaled + if (!CHECK_EQ(Wgg*G + Wgd*D, M*scale + Wmd*D + Wme*E + Wmg*G, + (margin*T)/3)) { + berr = BW_WEIGHTS_BALANCE_MID_ERROR; + goto out; + } + } + + out: + if (berr) { + log_info(LD_DIR, + "Bw weight mismatch %d. G="I64_FORMAT" M="I64_FORMAT + " E="I64_FORMAT" D="I64_FORMAT" T="I64_FORMAT + " Wmd=%d Wme=%d Wmg=%d Wed=%d Wee=%d" + " Wgd=%d Wgg=%d Wme=%d Wmg=%d", + berr, + I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E), + I64_PRINTF_ARG(D), I64_PRINTF_ARG(T), + (int)Wmd, (int)Wme, (int)Wmg, (int)Wed, (int)Wee, + (int)Wgd, (int)Wgg, (int)Wme, (int)Wmg); + } + + return berr; +} + +/** + * This function computes the bandwidth weights for consensus method 10. + * + * It returns true if weights could be computed, false otherwise. + */ +static int +networkstatus_compute_bw_weights_v10(smartlist_t *chunks, int64_t G, + int64_t M, int64_t E, int64_t D, + int64_t T, int64_t weight_scale) +{ + bw_weights_error_t berr = 0; + int64_t Wgg = -1, Wgd = -1; + int64_t Wmg = -1, Wme = -1, Wmd = -1; + int64_t Wed = -1, Wee = -1; + const char *casename; + + if (G <= 0 || M <= 0 || E <= 0 || D <= 0) { + log_warn(LD_DIR, "Consensus with empty bandwidth: " + "G="I64_FORMAT" M="I64_FORMAT" E="I64_FORMAT + " D="I64_FORMAT" T="I64_FORMAT, + I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E), + I64_PRINTF_ARG(D), I64_PRINTF_ARG(T)); + return 0; + } + + /* + * Computed from cases in 3.4.3 of dir-spec.txt + * + * 1. Neither are scarce + * 2. Both Guard and Exit are scarce + * a. R+D <= S + * b. R+D > S + * 3. One of Guard or Exit is scarce + * a. S+D < T/3 + * b. S+D >= T/3 + */ + if (3*E >= T && 3*G >= T) { // E >= T/3 && G >= T/3 + /* Case 1: Neither are scarce. */ + casename = "Case 1 (Wgd=Wmd=Wed)"; + Wgd = weight_scale/3; + Wed = weight_scale/3; + Wmd = weight_scale/3; + Wee = (weight_scale*(E+G+M))/(3*E); + Wme = weight_scale - Wee; + Wmg = (weight_scale*(2*G-E-M))/(3*G); + Wgg = weight_scale - Wmg; + + berr = networkstatus_check_weights(Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed, + weight_scale, G, M, E, D, T, 10, 1); + + if (berr) { + log_warn(LD_DIR, + "Bw Weights error %d for %s v10. G="I64_FORMAT" M="I64_FORMAT + " E="I64_FORMAT" D="I64_FORMAT" T="I64_FORMAT + " Wmd=%d Wme=%d Wmg=%d Wed=%d Wee=%d" + " Wgd=%d Wgg=%d Wme=%d Wmg=%d weight_scale=%d", + berr, casename, + I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E), + I64_PRINTF_ARG(D), I64_PRINTF_ARG(T), + (int)Wmd, (int)Wme, (int)Wmg, (int)Wed, (int)Wee, + (int)Wgd, (int)Wgg, (int)Wme, (int)Wmg, (int)weight_scale); + return 0; + } + } else if (3*E < T && 3*G < T) { // E < T/3 && G < T/3 + int64_t R = MIN(E, G); + int64_t S = MAX(E, G); + /* + * Case 2: Both Guards and Exits are scarce + * Balance D between E and G, depending upon + * D capacity and scarcity. + */ + if (R+D < S) { // Subcase a + Wgg = weight_scale; + Wee = weight_scale; + Wmg = 0; + Wme = 0; + Wmd = 0; + if (E < G) { + casename = "Case 2a (E scarce)"; + Wed = weight_scale; + Wgd = 0; + } else { /* E >= G */ + casename = "Case 2a (G scarce)"; + Wed = 0; + Wgd = weight_scale; + } + } else { // Subcase b: R+D >= S + casename = "Case 2b1 (Wgg=1, Wmd=Wgd)"; + Wee = (weight_scale*(E - G + M))/E; + Wed = (weight_scale*(D - 2*E + 4*G - 2*M))/(3*D); + Wme = (weight_scale*(G-M))/E; + Wmg = 0; + Wgg = weight_scale; + Wmd = (weight_scale - Wed)/2; + Wgd = (weight_scale - Wed)/2; + + berr = networkstatus_check_weights(Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed, + weight_scale, G, M, E, D, T, 10, 1); + + if (berr) { + casename = "Case 2b2 (Wgg=1, Wee=1)"; + Wgg = weight_scale; + Wee = weight_scale; + Wed = (weight_scale*(D - 2*E + G + M))/(3*D); + Wmd = (weight_scale*(D - 2*M + G + E))/(3*D); + Wme = 0; + Wmg = 0; + + if (Wmd < 0) { // Can happen if M > T/3 + casename = "Case 2b3 (Wmd=0)"; + Wmd = 0; + log_warn(LD_DIR, + "Too much Middle bandwidth on the network to calculate " + "balanced bandwidth-weights. Consider increasing the " + "number of Guard nodes by lowering the requirements."); + } + Wgd = weight_scale - Wed - Wmd; + berr = networkstatus_check_weights(Wgg, Wgd, Wmg, Wme, Wmd, Wee, + Wed, weight_scale, G, M, E, D, T, 10, 1); + } + if (berr != BW_WEIGHTS_NO_ERROR && + berr != BW_WEIGHTS_BALANCE_MID_ERROR) { + log_warn(LD_DIR, + "Bw Weights error %d for %s v10. G="I64_FORMAT" M="I64_FORMAT + " E="I64_FORMAT" D="I64_FORMAT" T="I64_FORMAT + " Wmd=%d Wme=%d Wmg=%d Wed=%d Wee=%d" + " Wgd=%d Wgg=%d Wme=%d Wmg=%d weight_scale=%d", + berr, casename, + I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E), + I64_PRINTF_ARG(D), I64_PRINTF_ARG(T), + (int)Wmd, (int)Wme, (int)Wmg, (int)Wed, (int)Wee, + (int)Wgd, (int)Wgg, (int)Wme, (int)Wmg, (int)weight_scale); + return 0; + } + } + } else { // if (E < T/3 || G < T/3) { + int64_t S = MIN(E, G); + // Case 3: Exactly one of Guard or Exit is scarce + if (!(3*E < T || 3*G < T) || !(3*G >= T || 3*E >= T)) { + log_warn(LD_BUG, + "Bw-Weights Case 3 v10 but with G="I64_FORMAT" M=" + I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT" T="I64_FORMAT, + I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E), + I64_PRINTF_ARG(D), I64_PRINTF_ARG(T)); + } + + if (3*(S+D) < T) { // Subcase a: S+D < T/3 + if (G < E) { + casename = "Case 3a (G scarce)"; + Wgg = Wgd = weight_scale; + Wmd = Wed = Wmg = 0; + // Minor subcase, if E is more scarce than M, + // keep its bandwidth in place. + if (E < M) Wme = 0; + else Wme = (weight_scale*(E-M))/(2*E); + Wee = weight_scale-Wme; + } else { // G >= E + casename = "Case 3a (E scarce)"; + Wee = Wed = weight_scale; + Wmd = Wgd = Wme = 0; + // Minor subcase, if G is more scarce than M, + // keep its bandwidth in place. + if (G < M) Wmg = 0; + else Wmg = (weight_scale*(G-M))/(2*G); + Wgg = weight_scale-Wmg; + } + } else { // Subcase b: S+D >= T/3 + // D != 0 because S+D >= T/3 + if (G < E) { + casename = "Case 3bg (G scarce, Wgg=1, Wmd == Wed)"; + Wgg = weight_scale; + Wgd = (weight_scale*(D - 2*G + E + M))/(3*D); + Wmg = 0; + Wee = (weight_scale*(E+M))/(2*E); + Wme = weight_scale - Wee; + Wmd = (weight_scale - Wgd)/2; + Wed = (weight_scale - Wgd)/2; + + berr = networkstatus_check_weights(Wgg, Wgd, Wmg, Wme, Wmd, Wee, + Wed, weight_scale, G, M, E, D, T, 10, 1); + } else { // G >= E + casename = "Case 3be (E scarce, Wee=1, Wmd == Wgd)"; + Wee = weight_scale; + Wed = (weight_scale*(D - 2*E + G + M))/(3*D); + Wme = 0; + Wgg = (weight_scale*(G+M))/(2*G); + Wmg = weight_scale - Wgg; + Wmd = (weight_scale - Wed)/2; + Wgd = (weight_scale - Wed)/2; + + berr = networkstatus_check_weights(Wgg, Wgd, Wmg, Wme, Wmd, Wee, + Wed, weight_scale, G, M, E, D, T, 10, 1); + } + if (berr) { + log_warn(LD_DIR, + "Bw Weights error %d for %s v10. G="I64_FORMAT" M="I64_FORMAT + " E="I64_FORMAT" D="I64_FORMAT" T="I64_FORMAT + " Wmd=%d Wme=%d Wmg=%d Wed=%d Wee=%d" + " Wgd=%d Wgg=%d Wme=%d Wmg=%d weight_scale=%d", + berr, casename, + I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E), + I64_PRINTF_ARG(D), I64_PRINTF_ARG(T), + (int)Wmd, (int)Wme, (int)Wmg, (int)Wed, (int)Wee, + (int)Wgd, (int)Wgg, (int)Wme, (int)Wmg, (int)weight_scale); + return 0; + } + } + } + + /* We cast down the weights to 32 bit ints on the assumption that + * weight_scale is ~= 10000. We need to ensure a rogue authority + * doesn't break this assumption to rig our weights */ + tor_assert(0 < weight_scale && weight_scale <= INT32_MAX); + + /* + * Provide Wgm=Wgg, Wmm=1, Wem=Wee, Weg=Wed. May later determine + * that middle nodes need different bandwidth weights for dirport traffic, + * or that weird exit policies need special weight, or that bridges + * need special weight. + * + * NOTE: This list is sorted. + */ + smartlist_add_asprintf(chunks, + "bandwidth-weights Wbd=%d Wbe=%d Wbg=%d Wbm=%d " + "Wdb=%d " + "Web=%d Wed=%d Wee=%d Weg=%d Wem=%d " + "Wgb=%d Wgd=%d Wgg=%d Wgm=%d " + "Wmb=%d Wmd=%d Wme=%d Wmg=%d Wmm=%d\n", + (int)Wmd, (int)Wme, (int)Wmg, (int)weight_scale, + (int)weight_scale, + (int)weight_scale, (int)Wed, (int)Wee, (int)Wed, (int)Wee, + (int)weight_scale, (int)Wgd, (int)Wgg, (int)Wgg, + (int)weight_scale, (int)Wmd, (int)Wme, (int)Wmg, (int)weight_scale); + + log_notice(LD_CIRC, "Computed bandwidth weights for %s with v10: " + "G="I64_FORMAT" M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT + " T="I64_FORMAT, + casename, + I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E), + I64_PRINTF_ARG(D), I64_PRINTF_ARG(T)); + return 1; +} +/** + * This function computes the bandwidth weights for consensus method 9. + * + * It has been obsoleted in favor of consensus method 10. + */ +static void +networkstatus_compute_bw_weights_v9(smartlist_t *chunks, int64_t G, int64_t M, + int64_t E, int64_t D, int64_t T, + int64_t weight_scale) +{ + int64_t Wgg = -1, Wgd = -1; + int64_t Wmg = -1, Wme = -1, Wmd = -1; + int64_t Wed = -1, Wee = -1; + const char *casename; + + if (G <= 0 || M <= 0 || E <= 0 || D <= 0) { + log_warn(LD_DIR, "Consensus with empty bandwidth: " + "G="I64_FORMAT" M="I64_FORMAT" E="I64_FORMAT + " D="I64_FORMAT" T="I64_FORMAT, + I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E), + I64_PRINTF_ARG(D), I64_PRINTF_ARG(T)); + return; + } + + /* + * Computed from cases in 3.4.3 of dir-spec.txt + * + * 1. Neither are scarce + * 2. Both Guard and Exit are scarce + * a. R+D <= S + * b. R+D > S + * 3. One of Guard or Exit is scarce + * a. S+D < T/3 + * b. S+D >= T/3 + */ + if (3*E >= T && 3*G >= T) { // E >= T/3 && G >= T/3 + bw_weights_error_t berr = 0; + /* Case 1: Neither are scarce. + * + * Attempt to ensure that we have a large amount of exit bandwidth + * in the middle position. + */ + casename = "Case 1 (Wme*E = Wmd*D)"; + Wgg = (weight_scale*(D+E+G+M))/(3*G); + if (D==0) Wmd = 0; + else Wmd = (weight_scale*(2*D + 2*E - G - M))/(6*D); + Wme = (weight_scale*(2*D + 2*E - G - M))/(6*E); + Wee = (weight_scale*(-2*D + 4*E + G + M))/(6*E); + Wgd = 0; + Wmg = weight_scale - Wgg; + Wed = weight_scale - Wmd; + + berr = networkstatus_check_weights(Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed, + weight_scale, G, M, E, D, T, 10, 1); + + if (berr) { + log_warn(LD_DIR, "Bw Weights error %d for case %s. " + "G="I64_FORMAT" M="I64_FORMAT" E="I64_FORMAT + " D="I64_FORMAT" T="I64_FORMAT, + berr, casename, + I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E), + I64_PRINTF_ARG(D), I64_PRINTF_ARG(T)); + } + } else if (3*E < T && 3*G < T) { // E < T/3 && G < T/3 + int64_t R = MIN(E, G); + int64_t S = MAX(E, G); + /* + * Case 2: Both Guards and Exits are scarce + * Balance D between E and G, depending upon + * D capacity and scarcity. + */ + if (R+D < S) { // Subcase a + Wgg = weight_scale; + Wee = weight_scale; + Wmg = 0; + Wme = 0; + Wmd = 0; + if (E < G) { + casename = "Case 2a (E scarce)"; + Wed = weight_scale; + Wgd = 0; + } else { /* E >= G */ + casename = "Case 2a (G scarce)"; + Wed = 0; + Wgd = weight_scale; + } + } else { // Subcase b: R+D > S + bw_weights_error_t berr = 0; + casename = "Case 2b (Wme*E == Wmd*D)"; + if (D != 0) { + Wgg = weight_scale; + Wgd = (weight_scale*(D + E - 2*G + M))/(3*D); // T/3 >= G (Ok) + Wmd = (weight_scale*(D + E + G - 2*M))/(6*D); // T/3 >= M + Wme = (weight_scale*(D + E + G - 2*M))/(6*E); + Wee = (weight_scale*(-D + 5*E - G + 2*M))/(6*E); // 2E+M >= T/3 + Wmg = 0; + Wed = weight_scale - Wgd - Wmd; + + berr = networkstatus_check_weights(Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed, + weight_scale, G, M, E, D, T, 10, 1); + } + + if (D == 0 || berr) { // Can happen if M > T/3 + casename = "Case 2b (E=G)"; + Wgg = weight_scale; + Wee = weight_scale; + Wmg = 0; + Wme = 0; + Wmd = 0; + if (D == 0) Wgd = 0; + else Wgd = (weight_scale*(D+E-G))/(2*D); + Wed = weight_scale - Wgd; + berr = networkstatus_check_weights(Wgg, Wgd, Wmg, Wme, Wmd, Wee, + Wed, weight_scale, G, M, E, D, T, 10, 1); + } + if (berr != BW_WEIGHTS_NO_ERROR && + berr != BW_WEIGHTS_BALANCE_MID_ERROR) { + log_warn(LD_DIR, "Bw Weights error %d for case %s. " + "G="I64_FORMAT" M="I64_FORMAT" E="I64_FORMAT + " D="I64_FORMAT" T="I64_FORMAT, + berr, casename, + I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E), + I64_PRINTF_ARG(D), I64_PRINTF_ARG(T)); + } + } + } else { // if (E < T/3 || G < T/3) { + int64_t S = MIN(E, G); + // Case 3: Exactly one of Guard or Exit is scarce + if (!(3*E < T || 3*G < T) || !(3*G >= T || 3*E >= T)) { + log_warn(LD_BUG, + "Bw-Weights Case 3 but with G="I64_FORMAT" M=" + I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT" T="I64_FORMAT, + I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E), + I64_PRINTF_ARG(D), I64_PRINTF_ARG(T)); + } + + if (3*(S+D) < T) { // Subcase a: S+D < T/3 + if (G < E) { + casename = "Case 3a (G scarce)"; + Wgg = Wgd = weight_scale; + Wmd = Wed = Wmg = 0; + // Minor subcase, if E is more scarce than M, + // keep its bandwidth in place. + if (E < M) Wme = 0; + else Wme = (weight_scale*(E-M))/(2*E); + Wee = weight_scale-Wme; + } else { // G >= E + casename = "Case 3a (E scarce)"; + Wee = Wed = weight_scale; + Wmd = Wgd = Wme = 0; + // Minor subcase, if G is more scarce than M, + // keep its bandwidth in place. + if (G < M) Wmg = 0; + else Wmg = (weight_scale*(G-M))/(2*G); + Wgg = weight_scale-Wmg; + } + } else { // Subcase b: S+D >= T/3 + bw_weights_error_t berr = 0; + // D != 0 because S+D >= T/3 + if (G < E) { + casename = "Case 3b (G scarce, Wme*E == Wmd*D)"; + Wgd = (weight_scale*(D + E - 2*G + M))/(3*D); + Wmd = (weight_scale*(D + E + G - 2*M))/(6*D); + Wme = (weight_scale*(D + E + G - 2*M))/(6*E); + Wee = (weight_scale*(-D + 5*E - G + 2*M))/(6*E); + Wgg = weight_scale; + Wmg = 0; + Wed = weight_scale - Wgd - Wmd; + + berr = networkstatus_check_weights(Wgg, Wgd, Wmg, Wme, Wmd, Wee, + Wed, weight_scale, G, M, E, D, T, 10, 1); + } else { // G >= E + casename = "Case 3b (E scarce, Wme*E == Wmd*D)"; + Wgg = (weight_scale*(D + E + G + M))/(3*G); + Wmd = (weight_scale*(2*D + 2*E - G - M))/(6*D); + Wme = (weight_scale*(2*D + 2*E - G - M))/(6*E); + Wee = (weight_scale*(-2*D + 4*E + G + M))/(6*E); + Wgd = 0; + Wmg = weight_scale - Wgg; + Wed = weight_scale - Wmd; + + berr = networkstatus_check_weights(Wgg, Wgd, Wmg, Wme, Wmd, Wee, + Wed, weight_scale, G, M, E, D, T, 10, 1); + } + if (berr) { + log_warn(LD_DIR, "Bw Weights error %d for case %s. " + "G="I64_FORMAT" M="I64_FORMAT + " E="I64_FORMAT" D="I64_FORMAT" T="I64_FORMAT, + berr, casename, + I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E), + I64_PRINTF_ARG(D), I64_PRINTF_ARG(T)); + } + } + } + + /* We cast down the weights to 32 bit ints on the assumption that + * weight_scale is ~= 10000. We need to ensure a rogue authority + * doesn't break this assumption to rig our weights */ + tor_assert(0 < weight_scale && weight_scale <= INT32_MAX); + + if (Wgg < 0 || Wgg > weight_scale) { + log_warn(LD_DIR, "Bw %s: Wgg="I64_FORMAT"! G="I64_FORMAT + " M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT + " T="I64_FORMAT, + casename, I64_PRINTF_ARG(Wgg), + I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E), + I64_PRINTF_ARG(D), I64_PRINTF_ARG(T)); + + Wgg = MAX(MIN(Wgg, weight_scale), 0); + } + if (Wgd < 0 || Wgd > weight_scale) { + log_warn(LD_DIR, "Bw %s: Wgd="I64_FORMAT"! G="I64_FORMAT + " M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT + " T="I64_FORMAT, + casename, I64_PRINTF_ARG(Wgd), + I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E), + I64_PRINTF_ARG(D), I64_PRINTF_ARG(T)); + Wgd = MAX(MIN(Wgd, weight_scale), 0); + } + if (Wmg < 0 || Wmg > weight_scale) { + log_warn(LD_DIR, "Bw %s: Wmg="I64_FORMAT"! G="I64_FORMAT + " M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT + " T="I64_FORMAT, + casename, I64_PRINTF_ARG(Wmg), + I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E), + I64_PRINTF_ARG(D), I64_PRINTF_ARG(T)); + Wmg = MAX(MIN(Wmg, weight_scale), 0); + } + if (Wme < 0 || Wme > weight_scale) { + log_warn(LD_DIR, "Bw %s: Wme="I64_FORMAT"! G="I64_FORMAT + " M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT + " T="I64_FORMAT, + casename, I64_PRINTF_ARG(Wme), + I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E), + I64_PRINTF_ARG(D), I64_PRINTF_ARG(T)); + Wme = MAX(MIN(Wme, weight_scale), 0); + } + if (Wmd < 0 || Wmd > weight_scale) { + log_warn(LD_DIR, "Bw %s: Wmd="I64_FORMAT"! G="I64_FORMAT + " M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT + " T="I64_FORMAT, + casename, I64_PRINTF_ARG(Wmd), + I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E), + I64_PRINTF_ARG(D), I64_PRINTF_ARG(T)); + Wmd = MAX(MIN(Wmd, weight_scale), 0); + } + if (Wee < 0 || Wee > weight_scale) { + log_warn(LD_DIR, "Bw %s: Wee="I64_FORMAT"! G="I64_FORMAT + " M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT + " T="I64_FORMAT, + casename, I64_PRINTF_ARG(Wee), + I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E), + I64_PRINTF_ARG(D), I64_PRINTF_ARG(T)); + Wee = MAX(MIN(Wee, weight_scale), 0); + } + if (Wed < 0 || Wed > weight_scale) { + log_warn(LD_DIR, "Bw %s: Wed="I64_FORMAT"! G="I64_FORMAT + " M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT + " T="I64_FORMAT, + casename, I64_PRINTF_ARG(Wed), + I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E), + I64_PRINTF_ARG(D), I64_PRINTF_ARG(T)); + Wed = MAX(MIN(Wed, weight_scale), 0); + } + + // Add consensus weight keywords + smartlist_add(chunks, tor_strdup("bandwidth-weights ")); + /* + * Provide Wgm=Wgg, Wmm=1, Wem=Wee, Weg=Wed. May later determine + * that middle nodes need different bandwidth weights for dirport traffic, + * or that weird exit policies need special weight, or that bridges + * need special weight. + * + * NOTE: This list is sorted. + */ + smartlist_add_asprintf(chunks, + "Wbd=%d Wbe=%d Wbg=%d Wbm=%d " + "Wdb=%d " + "Web=%d Wed=%d Wee=%d Weg=%d Wem=%d " + "Wgb=%d Wgd=%d Wgg=%d Wgm=%d " + "Wmb=%d Wmd=%d Wme=%d Wmg=%d Wmm=%d\n", + (int)Wmd, (int)Wme, (int)Wmg, (int)weight_scale, + (int)weight_scale, + (int)weight_scale, (int)Wed, (int)Wee, (int)Wed, (int)Wee, + (int)weight_scale, (int)Wgd, (int)Wgg, (int)Wgg, + (int)weight_scale, (int)Wmd, (int)Wme, (int)Wmg, (int)weight_scale); + + log_notice(LD_CIRC, "Computed bandwidth weights for %s with v9: " + "G="I64_FORMAT" M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT + " T="I64_FORMAT, + casename, + I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E), + I64_PRINTF_ARG(D), I64_PRINTF_ARG(T)); +} + +/** Given a list of vote networkstatus_t in votes, our public + * authority identity_key, our private authority signing_key, + * and the number of total_authorities that we believe exist in our + * voting quorum, generate the text of a new v3 consensus vote, and return the + * value in a newly allocated string. + * + * Note: this function DOES NOT check whether the votes are from + * recognized authorities. (dirvote_add_vote does that.) */ +char * +networkstatus_compute_consensus(smartlist_t *votes, + int total_authorities, + crypto_pk_t *identity_key, + crypto_pk_t *signing_key, + const char *legacy_id_key_digest, + crypto_pk_t *legacy_signing_key, + consensus_flavor_t flavor) +{ + smartlist_t *chunks; + char *result = NULL; + int consensus_method; + time_t valid_after, fresh_until, valid_until; + int vote_seconds, dist_seconds; + char *client_versions = NULL, *server_versions = NULL; + smartlist_t *flags; + const char *flavor_name; + uint32_t max_unmeasured_bw_kb = DEFAULT_MAX_UNMEASURED_BW_KB; + int64_t G=0, M=0, E=0, D=0, T=0; /* For bandwidth weights */ + const routerstatus_format_type_t rs_format = + flavor == FLAV_NS ? NS_V3_CONSENSUS : NS_V3_CONSENSUS_MICRODESC; + char *params = NULL; + int added_weights = 0; + tor_assert(flavor == FLAV_NS || flavor == FLAV_MICRODESC); + tor_assert(total_authorities >= smartlist_len(votes)); + + flavor_name = networkstatus_get_flavor_name(flavor); + + if (!smartlist_len(votes)) { + log_warn(LD_DIR, "Can't compute a consensus from no votes."); + return NULL; + } + flags = smartlist_new(); + + consensus_method = compute_consensus_method(votes); + if (consensus_method_is_supported(consensus_method)) { + log_info(LD_DIR, "Generating consensus using method %d.", + consensus_method); + } else { + log_warn(LD_DIR, "The other authorities will use consensus method %d, " + "which I don't support. Maybe I should upgrade!", + consensus_method); + consensus_method = 1; + } + + /* Compute medians of time-related things, and figure out how many + * routers we might need to talk about. */ + { + int n_votes = smartlist_len(votes); + time_t *va_times = tor_malloc(n_votes * sizeof(time_t)); + time_t *fu_times = tor_malloc(n_votes * sizeof(time_t)); + time_t *vu_times = tor_malloc(n_votes * sizeof(time_t)); + int *votesec_list = tor_malloc(n_votes * sizeof(int)); + int *distsec_list = tor_malloc(n_votes * sizeof(int)); + int n_versioning_clients = 0, n_versioning_servers = 0; + smartlist_t *combined_client_versions = smartlist_new(); + smartlist_t *combined_server_versions = smartlist_new(); + + SMARTLIST_FOREACH_BEGIN(votes, networkstatus_t *, v) { + tor_assert(v->type == NS_TYPE_VOTE); + va_times[v_sl_idx] = v->valid_after; + fu_times[v_sl_idx] = v->fresh_until; + vu_times[v_sl_idx] = v->valid_until; + votesec_list[v_sl_idx] = v->vote_seconds; + distsec_list[v_sl_idx] = v->dist_seconds; + if (v->client_versions) { + smartlist_t *cv = smartlist_new(); + ++n_versioning_clients; + smartlist_split_string(cv, v->client_versions, ",", + SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); + sort_version_list(cv, 1); + smartlist_add_all(combined_client_versions, cv); + smartlist_free(cv); /* elements get freed later. */ + } + if (v->server_versions) { + smartlist_t *sv = smartlist_new(); + ++n_versioning_servers; + smartlist_split_string(sv, v->server_versions, ",", + SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); + sort_version_list(sv, 1); + smartlist_add_all(combined_server_versions, sv); + smartlist_free(sv); /* elements get freed later. */ + } + SMARTLIST_FOREACH(v->known_flags, const char *, cp, + smartlist_add(flags, tor_strdup(cp))); + } SMARTLIST_FOREACH_END(v); + valid_after = median_time(va_times, n_votes); + fresh_until = median_time(fu_times, n_votes); + valid_until = median_time(vu_times, n_votes); + vote_seconds = median_int(votesec_list, n_votes); + dist_seconds = median_int(distsec_list, n_votes); + + tor_assert(valid_after+MIN_VOTE_INTERVAL <= fresh_until); + tor_assert(fresh_until+MIN_VOTE_INTERVAL <= valid_until); + tor_assert(vote_seconds >= MIN_VOTE_SECONDS); + tor_assert(dist_seconds >= MIN_DIST_SECONDS); + + server_versions = compute_consensus_versions_list(combined_server_versions, + n_versioning_servers); + client_versions = compute_consensus_versions_list(combined_client_versions, + n_versioning_clients); + + SMARTLIST_FOREACH(combined_server_versions, char *, cp, tor_free(cp)); + SMARTLIST_FOREACH(combined_client_versions, char *, cp, tor_free(cp)); + smartlist_free(combined_server_versions); + smartlist_free(combined_client_versions); + + smartlist_sort_strings(flags); + smartlist_uniq_strings(flags); + + tor_free(va_times); + tor_free(fu_times); + tor_free(vu_times); + tor_free(votesec_list); + tor_free(distsec_list); + } + + chunks = smartlist_new(); + + { + char va_buf[ISO_TIME_LEN+1], fu_buf[ISO_TIME_LEN+1], + vu_buf[ISO_TIME_LEN+1]; + char *flaglist; + format_iso_time(va_buf, valid_after); + format_iso_time(fu_buf, fresh_until); + format_iso_time(vu_buf, valid_until); + flaglist = smartlist_join_strings(flags, " ", 0, NULL); + + smartlist_add_asprintf(chunks, "network-status-version 3%s%s\n" + "vote-status consensus\n", + flavor == FLAV_NS ? "" : " ", + flavor == FLAV_NS ? "" : flavor_name); + + if (consensus_method >= 2) { + smartlist_add_asprintf(chunks, "consensus-method %d\n", + consensus_method); + } + + smartlist_add_asprintf(chunks, + "valid-after %s\n" + "fresh-until %s\n" + "valid-until %s\n" + "voting-delay %d %d\n" + "client-versions %s\n" + "server-versions %s\n" + "known-flags %s\n", + va_buf, fu_buf, vu_buf, + vote_seconds, dist_seconds, + client_versions, server_versions, flaglist); + + tor_free(flaglist); + } + + if (consensus_method >= MIN_METHOD_FOR_PARAMS) { + params = dirvote_compute_params(votes, consensus_method, + total_authorities); + if (params) { + smartlist_add(chunks, tor_strdup("params ")); + smartlist_add(chunks, params); + smartlist_add(chunks, tor_strdup("\n")); + } + } + + /* Sort the votes. */ + smartlist_sort(votes, compare_votes_by_authority_id_); + /* Add the authority sections. */ + { + smartlist_t *dir_sources = smartlist_new(); + SMARTLIST_FOREACH_BEGIN(votes, networkstatus_t *, v) { + dir_src_ent_t *e = tor_malloc_zero(sizeof(dir_src_ent_t)); + e->v = v; + e->digest = get_voter(v)->identity_digest; + e->is_legacy = 0; + smartlist_add(dir_sources, e); + if (consensus_method >= 3 && + !tor_digest_is_zero(get_voter(v)->legacy_id_digest)) { + dir_src_ent_t *e_legacy = tor_malloc_zero(sizeof(dir_src_ent_t)); + e_legacy->v = v; + e_legacy->digest = get_voter(v)->legacy_id_digest; + e_legacy->is_legacy = 1; + smartlist_add(dir_sources, e_legacy); + } + } SMARTLIST_FOREACH_END(v); + smartlist_sort(dir_sources, compare_dir_src_ents_by_authority_id_); + + SMARTLIST_FOREACH_BEGIN(dir_sources, const dir_src_ent_t *, e) { + char fingerprint[HEX_DIGEST_LEN+1]; + char votedigest[HEX_DIGEST_LEN+1]; + networkstatus_t *v = e->v; + networkstatus_voter_info_t *voter = get_voter(v); + + if (e->is_legacy) + tor_assert(consensus_method >= 2); + + base16_encode(fingerprint, sizeof(fingerprint), e->digest, DIGEST_LEN); + base16_encode(votedigest, sizeof(votedigest), voter->vote_digest, + DIGEST_LEN); + + smartlist_add_asprintf(chunks, + "dir-source %s%s %s %s %s %d %d\n", + voter->nickname, e->is_legacy ? "-legacy" : "", + fingerprint, voter->address, fmt_addr32(voter->addr), + voter->dir_port, + voter->or_port); + if (! e->is_legacy) { + smartlist_add_asprintf(chunks, + "contact %s\n" + "vote-digest %s\n", + voter->contact, + votedigest); + } + } SMARTLIST_FOREACH_END(e); + SMARTLIST_FOREACH(dir_sources, dir_src_ent_t *, e, tor_free(e)); + smartlist_free(dir_sources); + } + + if (consensus_method >= MIN_METHOD_TO_CLIP_UNMEASURED_BW) { + char *max_unmeasured_param = NULL; + /* XXXX Extract this code into a common function */ + if (params) { + if (strcmpstart(params, "maxunmeasuredbw=") == 0) + max_unmeasured_param = params; + else + max_unmeasured_param = strstr(params, " maxunmeasuredbw="); + } + if (max_unmeasured_param) { + int ok = 0; + char *eq = strchr(max_unmeasured_param, '='); + if (eq) { + max_unmeasured_bw_kb = (uint32_t) + tor_parse_ulong(eq+1, 10, 1, UINT32_MAX, &ok, NULL); + if (!ok) { + log_warn(LD_DIR, "Bad element '%s' in max unmeasured bw param", + escaped(max_unmeasured_param)); + max_unmeasured_bw_kb = DEFAULT_MAX_UNMEASURED_BW_KB; + } + } + } + } + + /* Add the actual router entries. */ + { + int *index; /* index[j] is the current index into votes[j]. */ + int *size; /* size[j] is the number of routerstatuses in votes[j]. */ + int *flag_counts; /* The number of voters that list flag[j] for the + * currently considered router. */ + int i; + smartlist_t *matching_descs = smartlist_new(); + smartlist_t *chosen_flags = smartlist_new(); + smartlist_t *versions = smartlist_new(); + smartlist_t *exitsummaries = smartlist_new(); + uint32_t *bandwidths_kb = tor_malloc(sizeof(uint32_t) * + smartlist_len(votes)); + uint32_t *measured_bws_kb = tor_malloc(sizeof(uint32_t) * + smartlist_len(votes)); + int num_bandwidths; + int num_mbws; + + int *n_voter_flags; /* n_voter_flags[j] is the number of flags that + * votes[j] knows about. */ + int *n_flag_voters; /* n_flag_voters[f] is the number of votes that care + * about flags[f]. */ + int **flag_map; /* flag_map[j][b] is an index f such that flag_map[f] + * is the same flag as votes[j]->known_flags[b]. */ + int *named_flag; /* Index of the flag "Named" for votes[j] */ + int *unnamed_flag; /* Index of the flag "Unnamed" for votes[j] */ + int chosen_named_idx; + int n_authorities_measuring_bandwidth; + + strmap_t *name_to_id_map = strmap_new(); + char conflict[DIGEST_LEN]; + char unknown[DIGEST_LEN]; + memset(conflict, 0, sizeof(conflict)); + memset(unknown, 0xff, sizeof(conflict)); + + index = tor_malloc_zero(sizeof(int)*smartlist_len(votes)); + size = tor_malloc_zero(sizeof(int)*smartlist_len(votes)); + n_voter_flags = tor_malloc_zero(sizeof(int) * smartlist_len(votes)); + n_flag_voters = tor_malloc_zero(sizeof(int) * smartlist_len(flags)); + flag_map = tor_malloc_zero(sizeof(int*) * smartlist_len(votes)); + named_flag = tor_malloc_zero(sizeof(int) * smartlist_len(votes)); + unnamed_flag = tor_malloc_zero(sizeof(int) * smartlist_len(votes)); + for (i = 0; i < smartlist_len(votes); ++i) + unnamed_flag[i] = named_flag[i] = -1; + chosen_named_idx = smartlist_string_pos(flags, "Named"); + + /* Build the flag indexes. Note that no vote can have more than 64 members + * for known_flags, so no value will be greater than 63, so it's safe to + * do U64_LITERAL(1) << index on these values. But note also that + * named_flag and unnamed_flag are initialized to -1, so we need to check + * that they're actually set before doing U64_LITERAL(1) << index with + * them.*/ + SMARTLIST_FOREACH_BEGIN(votes, networkstatus_t *, v) { + flag_map[v_sl_idx] = tor_malloc_zero( + sizeof(int)*smartlist_len(v->known_flags)); + if (smartlist_len(v->known_flags) > MAX_KNOWN_FLAGS_IN_VOTE) { + log_warn(LD_BUG, "Somehow, a vote has %d entries in known_flags", + smartlist_len(v->known_flags)); + } + SMARTLIST_FOREACH_BEGIN(v->known_flags, const char *, fl) { + int p = smartlist_string_pos(flags, fl); + tor_assert(p >= 0); + flag_map[v_sl_idx][fl_sl_idx] = p; + ++n_flag_voters[p]; + if (!strcmp(fl, "Named")) + named_flag[v_sl_idx] = fl_sl_idx; + if (!strcmp(fl, "Unnamed")) + unnamed_flag[v_sl_idx] = fl_sl_idx; + } SMARTLIST_FOREACH_END(fl); + n_voter_flags[v_sl_idx] = smartlist_len(v->known_flags); + size[v_sl_idx] = smartlist_len(v->routerstatus_list); + } SMARTLIST_FOREACH_END(v); + + /* Named and Unnamed get treated specially */ + if (consensus_method >= 2) { + SMARTLIST_FOREACH_BEGIN(votes, networkstatus_t *, v) { + uint64_t nf; + if (named_flag[v_sl_idx]<0) + continue; + nf = U64_LITERAL(1) << named_flag[v_sl_idx]; + SMARTLIST_FOREACH_BEGIN(v->routerstatus_list, + vote_routerstatus_t *, rs) { + + if ((rs->flags & nf) != 0) { + const char *d = strmap_get_lc(name_to_id_map, rs->status.nickname); + if (!d) { + /* We have no name officially mapped to this digest. */ + strmap_set_lc(name_to_id_map, rs->status.nickname, + rs->status.identity_digest); + } else if (d != conflict && + fast_memcmp(d, rs->status.identity_digest, DIGEST_LEN)) { + /* Authorities disagree about this nickname. */ + strmap_set_lc(name_to_id_map, rs->status.nickname, conflict); + } else { + /* It's already a conflict, or it's already this ID. */ + } + } + } SMARTLIST_FOREACH_END(rs); + } SMARTLIST_FOREACH_END(v); + + SMARTLIST_FOREACH_BEGIN(votes, networkstatus_t *, v) { + uint64_t uf; + if (unnamed_flag[v_sl_idx]<0) + continue; + uf = U64_LITERAL(1) << unnamed_flag[v_sl_idx]; + SMARTLIST_FOREACH_BEGIN(v->routerstatus_list, + vote_routerstatus_t *, rs) { + if ((rs->flags & uf) != 0) { + const char *d = strmap_get_lc(name_to_id_map, rs->status.nickname); + if (d == conflict || d == unknown) { + /* Leave it alone; we know what it is. */ + } else if (!d) { + /* We have no name officially mapped to this digest. */ + strmap_set_lc(name_to_id_map, rs->status.nickname, unknown); + } else if (fast_memeq(d, rs->status.identity_digest, DIGEST_LEN)) { + /* Authorities disagree about this nickname. */ + strmap_set_lc(name_to_id_map, rs->status.nickname, conflict); + } else { + /* It's mapped to a different name. */ + } + } + } SMARTLIST_FOREACH_END(rs); + } SMARTLIST_FOREACH_END(v); + } + + /* We need to know how many votes measure bandwidth. */ + n_authorities_measuring_bandwidth = 0; + SMARTLIST_FOREACH(votes, networkstatus_t *, v, + if (v->has_measured_bws) { + ++n_authorities_measuring_bandwidth; + } + ); + + /* Now go through all the votes */ + flag_counts = tor_malloc(sizeof(int) * smartlist_len(flags)); + while (1) { + vote_routerstatus_t *rs; + routerstatus_t rs_out; + const char *lowest_id = NULL; + const char *chosen_version; + const char *chosen_name = NULL; + int exitsummary_disagreement = 0; + int is_named = 0, is_unnamed = 0, is_running = 0; + int is_guard = 0, is_exit = 0, is_bad_exit = 0; + int naming_conflict = 0; + int n_listing = 0; + int i; + char microdesc_digest[DIGEST256_LEN]; + tor_addr_port_t alt_orport = {TOR_ADDR_NULL, 0}; + + /* Of the next-to-be-considered digest in each voter, which is first? */ + SMARTLIST_FOREACH(votes, networkstatus_t *, v, { + if (index[v_sl_idx] < size[v_sl_idx]) { + rs = smartlist_get(v->routerstatus_list, index[v_sl_idx]); + if (!lowest_id || + fast_memcmp(rs->status.identity_digest, + lowest_id, DIGEST_LEN) < 0) + lowest_id = rs->status.identity_digest; + } + }); + if (!lowest_id) /* we're out of routers. */ + break; + + memset(flag_counts, 0, sizeof(int)*smartlist_len(flags)); + smartlist_clear(matching_descs); + smartlist_clear(chosen_flags); + smartlist_clear(versions); + num_bandwidths = 0; + num_mbws = 0; + + /* Okay, go through all the entries for this digest. */ + SMARTLIST_FOREACH_BEGIN(votes, networkstatus_t *, v) { + if (index[v_sl_idx] >= size[v_sl_idx]) + continue; /* out of entries. */ + rs = smartlist_get(v->routerstatus_list, index[v_sl_idx]); + if (fast_memcmp(rs->status.identity_digest, lowest_id, DIGEST_LEN)) + continue; /* doesn't include this router. */ + /* At this point, we know that we're looking at a routerstatus with + * identity "lowest". + */ + ++index[v_sl_idx]; + ++n_listing; + + smartlist_add(matching_descs, rs); + if (rs->version && rs->version[0]) + smartlist_add(versions, rs->version); + + /* Tally up all the flags. */ + for (i = 0; i < n_voter_flags[v_sl_idx]; ++i) { + if (rs->flags & (U64_LITERAL(1) << i)) + ++flag_counts[flag_map[v_sl_idx][i]]; + } + if (named_flag[v_sl_idx] >= 0 && + (rs->flags & (U64_LITERAL(1) << named_flag[v_sl_idx]))) { + if (chosen_name && strcmp(chosen_name, rs->status.nickname)) { + log_notice(LD_DIR, "Conflict on naming for router: %s vs %s", + chosen_name, rs->status.nickname); + naming_conflict = 1; + } + chosen_name = rs->status.nickname; + } + + /* count bandwidths */ + if (rs->has_measured_bw) + measured_bws_kb[num_mbws++] = rs->measured_bw_kb; + + if (rs->status.has_bandwidth) + bandwidths_kb[num_bandwidths++] = rs->status.bandwidth_kb; + } SMARTLIST_FOREACH_END(v); + + /* We don't include this router at all unless more than half of + * the authorities we believe in list it. */ + if (n_listing <= total_authorities/2) + continue; + + /* Figure out the most popular opinion of what the most recent + * routerinfo and its contents are. */ + memset(microdesc_digest, 0, sizeof(microdesc_digest)); + rs = compute_routerstatus_consensus(matching_descs, consensus_method, + microdesc_digest, &alt_orport); + /* Copy bits of that into rs_out. */ + memset(&rs_out, 0, sizeof(rs_out)); + tor_assert(fast_memeq(lowest_id, rs->status.identity_digest,DIGEST_LEN)); + memcpy(rs_out.identity_digest, lowest_id, DIGEST_LEN); + memcpy(rs_out.descriptor_digest, rs->status.descriptor_digest, + DIGEST_LEN); + rs_out.addr = rs->status.addr; + rs_out.published_on = rs->status.published_on; + rs_out.dir_port = rs->status.dir_port; + rs_out.or_port = rs->status.or_port; + if (consensus_method >= MIN_METHOD_FOR_A_LINES) { + tor_addr_copy(&rs_out.ipv6_addr, &alt_orport.addr); + rs_out.ipv6_orport = alt_orport.port; + } + rs_out.has_bandwidth = 0; + rs_out.has_exitsummary = 0; + + if (chosen_name && !naming_conflict) { + strlcpy(rs_out.nickname, chosen_name, sizeof(rs_out.nickname)); + } else { + strlcpy(rs_out.nickname, rs->status.nickname, sizeof(rs_out.nickname)); + } + + if (consensus_method == 1) { + is_named = chosen_named_idx >= 0 && + (!naming_conflict && flag_counts[chosen_named_idx]); + } else { + const char *d = strmap_get_lc(name_to_id_map, rs_out.nickname); + if (!d) { + is_named = is_unnamed = 0; + } else if (fast_memeq(d, lowest_id, DIGEST_LEN)) { + is_named = 1; is_unnamed = 0; + } else { + is_named = 0; is_unnamed = 1; + } + } + + /* Set the flags. */ + smartlist_add(chosen_flags, (char*)"s"); /* for the start of the line. */ + SMARTLIST_FOREACH_BEGIN(flags, const char *, fl) { + if (!strcmp(fl, "Named")) { + if (is_named) + smartlist_add(chosen_flags, (char*)fl); + } else if (!strcmp(fl, "Unnamed") && consensus_method >= 2) { + if (is_unnamed) + smartlist_add(chosen_flags, (char*)fl); + } else { + if (flag_counts[fl_sl_idx] > n_flag_voters[fl_sl_idx]/2) { + smartlist_add(chosen_flags, (char*)fl); + if (!strcmp(fl, "Exit")) + is_exit = 1; + else if (!strcmp(fl, "Guard")) + is_guard = 1; + else if (!strcmp(fl, "Running")) + is_running = 1; + else if (!strcmp(fl, "BadExit")) + is_bad_exit = 1; + } + } + } SMARTLIST_FOREACH_END(fl); + + /* Starting with consensus method 4 we do not list servers + * that are not running in a consensus. See Proposal 138 */ + if (consensus_method >= 4 && !is_running) + continue; + + /* Pick the version. */ + if (smartlist_len(versions)) { + sort_version_list(versions, 0); + chosen_version = get_most_frequent_member(versions); + } else { + chosen_version = NULL; + } + + /* Pick a bandwidth */ + if (consensus_method >= 6 && num_mbws > 2) { + rs_out.has_bandwidth = 1; + rs_out.bw_is_unmeasured = 0; + rs_out.bandwidth_kb = median_uint32(measured_bws_kb, num_mbws); + } else if (consensus_method >= 5 && num_bandwidths > 0) { + rs_out.has_bandwidth = 1; + rs_out.bw_is_unmeasured = 1; + rs_out.bandwidth_kb = median_uint32(bandwidths_kb, num_bandwidths); + if (consensus_method >= MIN_METHOD_TO_CLIP_UNMEASURED_BW && + n_authorities_measuring_bandwidth > 2) { + /* Cap non-measured bandwidths. */ + if (rs_out.bandwidth_kb > max_unmeasured_bw_kb) { + rs_out.bandwidth_kb = max_unmeasured_bw_kb; + } + } + } + + /* Fix bug 2203: Do not count BadExit nodes as Exits for bw weights */ + if (consensus_method >= MIN_METHOD_TO_CUT_BADEXIT_WEIGHT) { + is_exit = is_exit && !is_bad_exit; + } + + if (consensus_method >= MIN_METHOD_FOR_BW_WEIGHTS) { + if (rs_out.has_bandwidth) { + T += rs_out.bandwidth_kb; + if (is_exit && is_guard) + D += rs_out.bandwidth_kb; + else if (is_exit) + E += rs_out.bandwidth_kb; + else if (is_guard) + G += rs_out.bandwidth_kb; + else + M += rs_out.bandwidth_kb; + } else { + log_warn(LD_BUG, "Missing consensus bandwidth for router %s", + rs_out.nickname); + } + } + + /* Ok, we already picked a descriptor digest we want to list + * previously. Now we want to use the exit policy summary from + * that descriptor. If everybody plays nice all the voters who + * listed that descriptor will have the same summary. If not then + * something is fishy and we'll use the most common one (breaking + * ties in favor of lexicographically larger one (only because it + * lets me reuse more existing code)). + * + * The other case that can happen is that no authority that voted + * for that descriptor has an exit policy summary. That's + * probably quite unlikely but can happen. In that case we use + * the policy that was most often listed in votes, again breaking + * ties like in the previous case. + */ + if (consensus_method >= 5) { + /* Okay, go through all the votes for this router. We prepared + * that list previously */ + const char *chosen_exitsummary = NULL; + smartlist_clear(exitsummaries); + SMARTLIST_FOREACH_BEGIN(matching_descs, vote_routerstatus_t *, vsr) { + /* Check if the vote where this status comes from had the + * proper descriptor */ + tor_assert(fast_memeq(rs_out.identity_digest, + vsr->status.identity_digest, + DIGEST_LEN)); + if (vsr->status.has_exitsummary && + fast_memeq(rs_out.descriptor_digest, + vsr->status.descriptor_digest, + DIGEST_LEN)) { + tor_assert(vsr->status.exitsummary); + smartlist_add(exitsummaries, vsr->status.exitsummary); + if (!chosen_exitsummary) { + chosen_exitsummary = vsr->status.exitsummary; + } else if (strcmp(chosen_exitsummary, vsr->status.exitsummary)) { + /* Great. There's disagreement among the voters. That + * really shouldn't be */ + exitsummary_disagreement = 1; + } + } + } SMARTLIST_FOREACH_END(vsr); + + if (exitsummary_disagreement) { + char id[HEX_DIGEST_LEN+1]; + char dd[HEX_DIGEST_LEN+1]; + base16_encode(id, sizeof(dd), rs_out.identity_digest, DIGEST_LEN); + base16_encode(dd, sizeof(dd), rs_out.descriptor_digest, DIGEST_LEN); + log_warn(LD_DIR, "The voters disagreed on the exit policy summary " + " for router %s with descriptor %s. This really shouldn't" + " have happened.", id, dd); + + smartlist_sort_strings(exitsummaries); + chosen_exitsummary = get_most_frequent_member(exitsummaries); + } else if (!chosen_exitsummary) { + char id[HEX_DIGEST_LEN+1]; + char dd[HEX_DIGEST_LEN+1]; + base16_encode(id, sizeof(dd), rs_out.identity_digest, DIGEST_LEN); + base16_encode(dd, sizeof(dd), rs_out.descriptor_digest, DIGEST_LEN); + log_warn(LD_DIR, "Not one of the voters that made us select" + "descriptor %s for router %s had an exit policy" + "summary", dd, id); + + /* Ok, none of those voting for the digest we chose had an + * exit policy for us. Well, that kinda sucks. + */ + smartlist_clear(exitsummaries); + SMARTLIST_FOREACH(matching_descs, vote_routerstatus_t *, vsr, { + if (vsr->status.has_exitsummary) + smartlist_add(exitsummaries, vsr->status.exitsummary); + }); + smartlist_sort_strings(exitsummaries); + chosen_exitsummary = get_most_frequent_member(exitsummaries); + + if (!chosen_exitsummary) + log_warn(LD_DIR, "Wow, not one of the voters had an exit " + "policy summary for %s. Wow.", id); + } + + if (chosen_exitsummary) { + rs_out.has_exitsummary = 1; + /* yea, discards the const */ + rs_out.exitsummary = (char *)chosen_exitsummary; + } + } + + if (flavor == FLAV_MICRODESC && + consensus_method >= MIN_METHOD_FOR_MANDATORY_MICRODESC && + tor_digest256_is_zero(microdesc_digest)) { + /* With no microdescriptor digest, we omit the entry entirely. */ + continue; + } + + { + char *buf; + /* Okay!! Now we can write the descriptor... */ + /* First line goes into "buf". */ + buf = routerstatus_format_entry(&rs_out, NULL, rs_format, NULL); + if (buf) + smartlist_add(chunks, buf); + } + /* Now an m line, if applicable. */ + if (flavor == FLAV_MICRODESC && + !tor_digest256_is_zero(microdesc_digest)) { + char m[BASE64_DIGEST256_LEN+1]; + digest256_to_base64(m, microdesc_digest); + smartlist_add_asprintf(chunks, "m %s\n", m); + } + /* Next line is all flags. The "\n" is missing. */ + smartlist_add(chunks, + smartlist_join_strings(chosen_flags, " ", 0, NULL)); + /* Now the version line. */ + if (chosen_version) { + smartlist_add(chunks, tor_strdup("\nv ")); + smartlist_add(chunks, tor_strdup(chosen_version)); + } + smartlist_add(chunks, tor_strdup("\n")); + /* Now the weight line. */ + if (rs_out.has_bandwidth) { + int unmeasured = rs_out.bw_is_unmeasured && + consensus_method >= MIN_METHOD_TO_CLIP_UNMEASURED_BW; + smartlist_add_asprintf(chunks, "w Bandwidth=%d%s\n", + rs_out.bandwidth_kb, + unmeasured?" Unmeasured=1":""); + } + + /* Now the exitpolicy summary line. */ + if (rs_out.has_exitsummary && flavor == FLAV_NS) { + smartlist_add_asprintf(chunks, "p %s\n", rs_out.exitsummary); + } + + /* And the loop is over and we move on to the next router */ + } + + tor_free(index); + tor_free(size); + tor_free(n_voter_flags); + tor_free(n_flag_voters); + for (i = 0; i < smartlist_len(votes); ++i) + tor_free(flag_map[i]); + tor_free(flag_map); + tor_free(flag_counts); + tor_free(named_flag); + tor_free(unnamed_flag); + strmap_free(name_to_id_map, NULL); + smartlist_free(matching_descs); + smartlist_free(chosen_flags); + smartlist_free(versions); + smartlist_free(exitsummaries); + tor_free(bandwidths_kb); + tor_free(measured_bws_kb); + } + + if (consensus_method >= MIN_METHOD_FOR_FOOTER) { + /* Starting with consensus method 9, we clearly mark the directory + * footer region */ + smartlist_add(chunks, tor_strdup("directory-footer\n")); + } + + if (consensus_method >= MIN_METHOD_FOR_BW_WEIGHTS) { + int64_t weight_scale = BW_WEIGHT_SCALE; + char *bw_weight_param = NULL; + + // Parse params, extract BW_WEIGHT_SCALE if present + // DO NOT use consensus_param_bw_weight_scale() in this code! + // The consensus is not formed yet! + /* XXXX Extract this code into a common function */ + if (params) { + if (strcmpstart(params, "bwweightscale=") == 0) + bw_weight_param = params; + else + bw_weight_param = strstr(params, " bwweightscale="); + } + + if (bw_weight_param) { + int ok=0; + char *eq = strchr(bw_weight_param, '='); + if (eq) { + weight_scale = tor_parse_long(eq+1, 10, 1, INT32_MAX, &ok, + NULL); + if (!ok) { + log_warn(LD_DIR, "Bad element '%s' in bw weight param", + escaped(bw_weight_param)); + weight_scale = BW_WEIGHT_SCALE; + } + } else { + log_warn(LD_DIR, "Bad element '%s' in bw weight param", + escaped(bw_weight_param)); + weight_scale = BW_WEIGHT_SCALE; + } + } + + if (consensus_method < 10) { + networkstatus_compute_bw_weights_v9(chunks, G, M, E, D, T, weight_scale); + added_weights = 1; + } else { + added_weights = networkstatus_compute_bw_weights_v10(chunks, G, M, E, D, + T, weight_scale); + } + } + + /* Add a signature. */ + { + char digest[DIGEST256_LEN]; + char fingerprint[HEX_DIGEST_LEN+1]; + char signing_key_fingerprint[HEX_DIGEST_LEN+1]; + digest_algorithm_t digest_alg = + flavor == FLAV_NS ? DIGEST_SHA1 : DIGEST_SHA256; + size_t digest_len = + flavor == FLAV_NS ? DIGEST_LEN : DIGEST256_LEN; + const char *algname = crypto_digest_algorithm_get_name(digest_alg); + char *signature; + + smartlist_add(chunks, tor_strdup("directory-signature ")); + + /* Compute the hash of the chunks. */ + crypto_digest_smartlist(digest, digest_len, chunks, "", digest_alg); + + /* Get the fingerprints */ + crypto_pk_get_fingerprint(identity_key, fingerprint, 0); + crypto_pk_get_fingerprint(signing_key, signing_key_fingerprint, 0); + + /* add the junk that will go at the end of the line. */ + if (flavor == FLAV_NS) { + smartlist_add_asprintf(chunks, "%s %s\n", fingerprint, + signing_key_fingerprint); + } else { + smartlist_add_asprintf(chunks, "%s %s %s\n", + algname, fingerprint, + signing_key_fingerprint); + } + /* And the signature. */ + if (!(signature = router_get_dirobj_signature(digest, digest_len, + signing_key))) { + log_warn(LD_BUG, "Couldn't sign consensus networkstatus."); + goto done; + } + smartlist_add(chunks, signature); + + if (legacy_id_key_digest && legacy_signing_key && consensus_method >= 3) { + smartlist_add(chunks, tor_strdup("directory-signature ")); + base16_encode(fingerprint, sizeof(fingerprint), + legacy_id_key_digest, DIGEST_LEN); + crypto_pk_get_fingerprint(legacy_signing_key, + signing_key_fingerprint, 0); + if (flavor == FLAV_NS) { + smartlist_add_asprintf(chunks, "%s %s\n", fingerprint, + signing_key_fingerprint); + } else { + smartlist_add_asprintf(chunks, "%s %s %s\n", + algname, fingerprint, + signing_key_fingerprint); + } + + if (!(signature = router_get_dirobj_signature(digest, digest_len, + legacy_signing_key))) { + log_warn(LD_BUG, "Couldn't sign consensus networkstatus."); + goto done; + } + smartlist_add(chunks, signature); + } + } + + result = smartlist_join_strings(chunks, "", 0, NULL); + + { + networkstatus_t *c; + if (!(c = networkstatus_parse_vote_from_string(result, NULL, + NS_TYPE_CONSENSUS))) { + log_err(LD_BUG, "Generated a networkstatus consensus we couldn't " + "parse."); + tor_free(result); + goto done; + } + // Verify balancing parameters + if (consensus_method >= MIN_METHOD_FOR_BW_WEIGHTS && added_weights) { + networkstatus_verify_bw_weights(c, consensus_method); + } + networkstatus_vote_free(c); + } + + done: + + tor_free(client_versions); + tor_free(server_versions); + SMARTLIST_FOREACH(flags, char *, cp, tor_free(cp)); + smartlist_free(flags); + SMARTLIST_FOREACH(chunks, char *, cp, tor_free(cp)); + smartlist_free(chunks); + + return result; +} + +/** Given a consensus vote target and a set of detached signatures in + * sigs that correspond to the same consensus, check whether there are + * any new signatures in src_voter_list that should be added to + * target. (A signature should be added if we have no signature for that + * voter in target yet, or if we have no verifiable signature and the + * new signature is verifiable.) Return the number of signatures added or + * changed, or -1 if the document signed by sigs isn't the same + * document as target. */ +int +networkstatus_add_detached_signatures(networkstatus_t *target, + ns_detached_signatures_t *sigs, + const char *source, + int severity, + const char **msg_out) +{ + int r = 0; + const char *flavor; + smartlist_t *siglist; + tor_assert(sigs); + tor_assert(target); + tor_assert(target->type == NS_TYPE_CONSENSUS); + + flavor = networkstatus_get_flavor_name(target->flavor); + + /* Do the times seem right? */ + if (target->valid_after != sigs->valid_after) { + *msg_out = "Valid-After times do not match " + "when adding detached signatures to consensus"; + return -1; + } + if (target->fresh_until != sigs->fresh_until) { + *msg_out = "Fresh-until times do not match " + "when adding detached signatures to consensus"; + return -1; + } + if (target->valid_until != sigs->valid_until) { + *msg_out = "Valid-until times do not match " + "when adding detached signatures to consensus"; + return -1; + } + siglist = strmap_get(sigs->signatures, flavor); + if (!siglist) { + *msg_out = "No signatures for given consensus flavor"; + return -1; + } + + /** Make sure all the digests we know match, and at least one matches. */ + { + digests_t *digests = strmap_get(sigs->digests, flavor); + int n_matches = 0; + int alg; + if (!digests) { + *msg_out = "No digests for given consensus flavor"; + return -1; + } + for (alg = DIGEST_SHA1; alg < N_DIGEST_ALGORITHMS; ++alg) { + if (!tor_mem_is_zero(digests->d[alg], DIGEST256_LEN)) { + if (fast_memeq(target->digests.d[alg], digests->d[alg], + DIGEST256_LEN)) { + ++n_matches; + } else { + *msg_out = "Mismatched digest."; + return -1; + } + } + } + if (!n_matches) { + *msg_out = "No regognized digests for given consensus flavor"; + } + } + + /* For each voter in src... */ + SMARTLIST_FOREACH_BEGIN(siglist, document_signature_t *, sig) { + char voter_identity[HEX_DIGEST_LEN+1]; + networkstatus_voter_info_t *target_voter = + networkstatus_get_voter_by_id(target, sig->identity_digest); + authority_cert_t *cert = NULL; + const char *algorithm; + document_signature_t *old_sig = NULL; + + algorithm = crypto_digest_algorithm_get_name(sig->alg); + + base16_encode(voter_identity, sizeof(voter_identity), + sig->identity_digest, DIGEST_LEN); + log_info(LD_DIR, "Looking at signature from %s using %s", voter_identity, + algorithm); + /* If the target doesn't know about this voter, then forget it. */ + if (!target_voter) { + log_info(LD_DIR, "We do not know any voter with ID %s", voter_identity); + continue; + } + + old_sig = voter_get_sig_by_algorithm(target_voter, sig->alg); + + /* If the target already has a good signature from this voter, then skip + * this one. */ + if (old_sig && old_sig->good_signature) { + log_info(LD_DIR, "We already have a good signature from %s using %s", + voter_identity, algorithm); + continue; + } + + /* Try checking the signature if we haven't already. */ + if (!sig->good_signature && !sig->bad_signature) { + cert = authority_cert_get_by_digests(sig->identity_digest, + sig->signing_key_digest); + if (cert) + networkstatus_check_document_signature(target, sig, cert); + } + + /* If this signature is good, or we don't have any signature yet, + * then maybe add it. */ + if (sig->good_signature || !old_sig || old_sig->bad_signature) { + log_info(LD_DIR, "Adding signature from %s with %s", voter_identity, + algorithm); + tor_log(severity, LD_DIR, "Added a signature for %s from %s.", + target_voter->nickname, source); + ++r; + if (old_sig) { + smartlist_remove(target_voter->sigs, old_sig); + document_signature_free(old_sig); + } + smartlist_add(target_voter->sigs, document_signature_dup(sig)); + } else { + log_info(LD_DIR, "Not adding signature from %s", voter_identity); + } + } SMARTLIST_FOREACH_END(sig); + + return r; +} + +/** Return a newly allocated string containing all the signatures on + * consensus by all voters. If for_detached_signatures is true, + * then the signatures will be put in a detached signatures document, so + * prefix any non-NS-flavored signatures with "additional-signature" rather + * than "directory-signature". */ +static char * +networkstatus_format_signatures(networkstatus_t *consensus, + int for_detached_signatures) +{ + smartlist_t *elements; + char buf[4096]; + char *result = NULL; + int n_sigs = 0; + const consensus_flavor_t flavor = consensus->flavor; + const char *flavor_name = networkstatus_get_flavor_name(flavor); + const char *keyword; + + if (for_detached_signatures && flavor != FLAV_NS) + keyword = "additional-signature"; + else + keyword = "directory-signature"; + + elements = smartlist_new(); + + SMARTLIST_FOREACH_BEGIN(consensus->voters, networkstatus_voter_info_t *, v) { + SMARTLIST_FOREACH_BEGIN(v->sigs, document_signature_t *, sig) { + char sk[HEX_DIGEST_LEN+1]; + char id[HEX_DIGEST_LEN+1]; + if (!sig->signature || sig->bad_signature) + continue; + ++n_sigs; + base16_encode(sk, sizeof(sk), sig->signing_key_digest, DIGEST_LEN); + base16_encode(id, sizeof(id), sig->identity_digest, DIGEST_LEN); + if (flavor == FLAV_NS) { + smartlist_add_asprintf(elements, + "%s %s %s\n-----BEGIN SIGNATURE-----\n", + keyword, id, sk); + } else { + const char *digest_name = + crypto_digest_algorithm_get_name(sig->alg); + smartlist_add_asprintf(elements, + "%s%s%s %s %s %s\n-----BEGIN SIGNATURE-----\n", + keyword, + for_detached_signatures ? " " : "", + for_detached_signatures ? flavor_name : "", + digest_name, id, sk); + } + base64_encode(buf, sizeof(buf), sig->signature, sig->signature_len); + strlcat(buf, "-----END SIGNATURE-----\n", sizeof(buf)); + smartlist_add(elements, tor_strdup(buf)); + } SMARTLIST_FOREACH_END(sig); + } SMARTLIST_FOREACH_END(v); + + result = smartlist_join_strings(elements, "", 0, NULL); + SMARTLIST_FOREACH(elements, char *, cp, tor_free(cp)); + smartlist_free(elements); + if (!n_sigs) + tor_free(result); + return result; +} + +/** Return a newly allocated string holding the detached-signatures document + * corresponding to the signatures on consensuses, which must contain + * exactly one FLAV_NS consensus, and no more than one consensus for each + * other flavor. */ +char * +networkstatus_get_detached_signatures(smartlist_t *consensuses) +{ + smartlist_t *elements; + char *result = NULL, *sigs = NULL; + networkstatus_t *consensus_ns = NULL; + tor_assert(consensuses); + + SMARTLIST_FOREACH(consensuses, networkstatus_t *, ns, { + tor_assert(ns); + tor_assert(ns->type == NS_TYPE_CONSENSUS); + if (ns && ns->flavor == FLAV_NS) + consensus_ns = ns; + }); + if (!consensus_ns) { + log_warn(LD_BUG, "No NS consensus given."); + return NULL; + } + + elements = smartlist_new(); + + { + char va_buf[ISO_TIME_LEN+1], fu_buf[ISO_TIME_LEN+1], + vu_buf[ISO_TIME_LEN+1]; + char d[HEX_DIGEST_LEN+1]; + + base16_encode(d, sizeof(d), + consensus_ns->digests.d[DIGEST_SHA1], DIGEST_LEN); + format_iso_time(va_buf, consensus_ns->valid_after); + format_iso_time(fu_buf, consensus_ns->fresh_until); + format_iso_time(vu_buf, consensus_ns->valid_until); + + smartlist_add_asprintf(elements, + "consensus-digest %s\n" + "valid-after %s\n" + "fresh-until %s\n" + "valid-until %s\n", d, va_buf, fu_buf, vu_buf); + } + + /* Get all the digests for the non-FLAV_NS consensuses */ + SMARTLIST_FOREACH_BEGIN(consensuses, networkstatus_t *, ns) { + const char *flavor_name = networkstatus_get_flavor_name(ns->flavor); + int alg; + if (ns->flavor == FLAV_NS) + continue; + + /* start with SHA256; we don't include SHA1 for anything but the basic + * consensus. */ + for (alg = DIGEST_SHA256; alg < N_DIGEST_ALGORITHMS; ++alg) { + char d[HEX_DIGEST256_LEN+1]; + const char *alg_name = + crypto_digest_algorithm_get_name(alg); + if (tor_mem_is_zero(ns->digests.d[alg], DIGEST256_LEN)) + continue; + base16_encode(d, sizeof(d), ns->digests.d[alg], DIGEST256_LEN); + smartlist_add_asprintf(elements, "additional-digest %s %s %s\n", + flavor_name, alg_name, d); + } + } SMARTLIST_FOREACH_END(ns); + + /* Now get all the sigs for non-FLAV_NS consensuses */ + SMARTLIST_FOREACH_BEGIN(consensuses, networkstatus_t *, ns) { + char *sigs; + if (ns->flavor == FLAV_NS) + continue; + sigs = networkstatus_format_signatures(ns, 1); + if (!sigs) { + log_warn(LD_DIR, "Couldn't format signatures"); + goto err; + } + smartlist_add(elements, sigs); + } SMARTLIST_FOREACH_END(ns); + + /* Now add the FLAV_NS consensus signatrures. */ + sigs = networkstatus_format_signatures(consensus_ns, 1); + if (!sigs) + goto err; + smartlist_add(elements, sigs); + + result = smartlist_join_strings(elements, "", 0, NULL); + err: + SMARTLIST_FOREACH(elements, char *, cp, tor_free(cp)); + smartlist_free(elements); + return result; +} + +/** Return a newly allocated string holding a detached-signatures document for + * all of the in-progress consensuses in the n_flavors-element array at + * pending. */ +static char * +get_detached_signatures_from_pending_consensuses(pending_consensus_t *pending, + int n_flavors) +{ + int flav; + char *signatures; + smartlist_t *c = smartlist_new(); + for (flav = 0; flav < n_flavors; ++flav) { + if (pending[flav].consensus) + smartlist_add(c, pending[flav].consensus); + } + signatures = networkstatus_get_detached_signatures(c); + smartlist_free(c); + return signatures; +} + +/** Release all storage held in s. */ +void +ns_detached_signatures_free(ns_detached_signatures_t *s) +{ + if (!s) + return; + if (s->signatures) { + STRMAP_FOREACH(s->signatures, flavor, smartlist_t *, sigs) { + SMARTLIST_FOREACH(sigs, document_signature_t *, sig, + document_signature_free(sig)); + smartlist_free(sigs); + } STRMAP_FOREACH_END; + strmap_free(s->signatures, NULL); + strmap_free(s->digests, tor_free_); + } + + tor_free(s); +} + +/* ===== + * Certificate functions + * ===== */ + +/** Allocate and return a new authority_cert_t with the same contents as + * cert. */ +authority_cert_t * +authority_cert_dup(authority_cert_t *cert) +{ + authority_cert_t *out = tor_malloc(sizeof(authority_cert_t)); + tor_assert(cert); + + memcpy(out, cert, sizeof(authority_cert_t)); + /* Now copy pointed-to things. */ + out->cache_info.signed_descriptor_body = + tor_strndup(cert->cache_info.signed_descriptor_body, + cert->cache_info.signed_descriptor_len); + out->cache_info.saved_location = SAVED_NOWHERE; + out->identity_key = crypto_pk_dup_key(cert->identity_key); + out->signing_key = crypto_pk_dup_key(cert->signing_key); + + return out; +} + +/* ===== + * Vote scheduling + * ===== */ + +/** Set *timing_out to the intervals at which we would like to vote. + * Note that these aren't the intervals we'll use to vote; they're the ones + * that we'll vote to use. */ +void +dirvote_get_preferred_voting_intervals(vote_timing_t *timing_out) +{ + const or_options_t *options = get_options(); + + tor_assert(timing_out); + + timing_out->vote_interval = options->V3AuthVotingInterval; + timing_out->n_intervals_valid = options->V3AuthNIntervalsValid; + timing_out->vote_delay = options->V3AuthVoteDelay; + timing_out->dist_delay = options->V3AuthDistDelay; +} + +/** Return the start of the next interval of size interval (in + * seconds) after now, plus offset. Midnight always + * starts a fresh interval, and if the last interval of a day would be + * truncated to less than half its size, it is rolled into the + * previous interval. */ +time_t +dirvote_get_start_of_next_interval(time_t now, int interval, int offset) +{ + struct tm tm; + time_t midnight_today=0; + time_t midnight_tomorrow; + time_t next; + + tor_gmtime_r(&now, &tm); + tm.tm_hour = 0; + tm.tm_min = 0; + tm.tm_sec = 0; + + if (tor_timegm(&tm, &midnight_today) < 0) { + log_warn(LD_BUG, "Ran into an invalid time when trying to find midnight."); + } + midnight_tomorrow = midnight_today + (24*60*60); + + next = midnight_today + ((now-midnight_today)/interval + 1)*interval; + + /* Intervals never cross midnight. */ + if (next > midnight_tomorrow) + next = midnight_tomorrow; + + /* If the interval would only last half as long as it's supposed to, then + * skip over to the next day. */ + if (next + interval/2 > midnight_tomorrow) + next = midnight_tomorrow; + + next += offset; + if (next - interval > now) + next -= interval; + + return next; +} + +/** Scheduling information for a voting interval. */ +static struct { + /** When do we generate and distribute our vote for this interval? */ + time_t voting_starts; + /** When do we send an HTTP request for any votes that we haven't + * been posted yet?*/ + time_t fetch_missing_votes; + /** When do we give up on getting more votes and generate a consensus? */ + time_t voting_ends; + /** When do we send an HTTP request for any signatures we're expecting to + * see on the consensus? */ + time_t fetch_missing_signatures; + /** When do we publish the consensus? */ + time_t interval_starts; + + /* True iff we have generated and distributed our vote. */ + int have_voted; + /* True iff we've requested missing votes. */ + int have_fetched_missing_votes; + /* True iff we have built a consensus and sent the signatures around. */ + int have_built_consensus; + /* True iff we've fetched missing signatures. */ + int have_fetched_missing_signatures; + /* True iff we have published our consensus. */ + int have_published_consensus; +} voting_schedule = {0,0,0,0,0,0,0,0,0,0}; + +/** Set voting_schedule to hold the timing for the next vote we should be + * doing. */ +void +dirvote_recalculate_timing(const or_options_t *options, time_t now) +{ + int interval, vote_delay, dist_delay; + time_t start; + time_t end; + networkstatus_t *consensus; + + if (!authdir_mode_v3(options)) + return; + + consensus = networkstatus_get_live_consensus(now); + + memset(&voting_schedule, 0, sizeof(voting_schedule)); + + if (consensus) { + interval = (int)( consensus->fresh_until - consensus->valid_after ); + vote_delay = consensus->vote_seconds; + dist_delay = consensus->dist_seconds; + } else { + interval = options->TestingV3AuthInitialVotingInterval; + vote_delay = options->TestingV3AuthInitialVoteDelay; + dist_delay = options->TestingV3AuthInitialDistDelay; + } + + tor_assert(interval > 0); + + if (vote_delay + dist_delay > interval/2) + vote_delay = dist_delay = interval / 4; + + start = voting_schedule.interval_starts = + dirvote_get_start_of_next_interval(now,interval, + options->TestingV3AuthVotingStartOffset); + end = dirvote_get_start_of_next_interval(start+1, interval, + options->TestingV3AuthVotingStartOffset); + + tor_assert(end > start); + + voting_schedule.fetch_missing_signatures = start - (dist_delay/2); + voting_schedule.voting_ends = start - dist_delay; + voting_schedule.fetch_missing_votes = start - dist_delay - (vote_delay/2); + voting_schedule.voting_starts = start - dist_delay - vote_delay; + + { + char tbuf[ISO_TIME_LEN+1]; + format_iso_time(tbuf, voting_schedule.interval_starts); + log_notice(LD_DIR,"Choosing expected valid-after time as %s: " + "consensus_set=%d, interval=%d", + tbuf, consensus?1:0, interval); + } +} + +/** Entry point: Take whatever voting actions are pending as of now. */ +void +dirvote_act(const or_options_t *options, time_t now) +{ + if (!authdir_mode_v3(options)) + return; + if (!voting_schedule.voting_starts) { + char *keys = list_v3_auth_ids(); + authority_cert_t *c = get_my_v3_authority_cert(); + log_notice(LD_DIR, "Scheduling voting. Known authority IDs are %s. " + "Mine is %s.", + keys, hex_str(c->cache_info.identity_digest, DIGEST_LEN)); + tor_free(keys); + dirvote_recalculate_timing(options, now); + } + if (voting_schedule.voting_starts < now && !voting_schedule.have_voted) { + log_notice(LD_DIR, "Time to vote."); + dirvote_perform_vote(); + voting_schedule.have_voted = 1; + } + if (voting_schedule.fetch_missing_votes < now && + !voting_schedule.have_fetched_missing_votes) { + log_notice(LD_DIR, "Time to fetch any votes that we're missing."); + dirvote_fetch_missing_votes(); + voting_schedule.have_fetched_missing_votes = 1; + } + if (voting_schedule.voting_ends < now && + !voting_schedule.have_built_consensus) { + log_notice(LD_DIR, "Time to compute a consensus."); + dirvote_compute_consensuses(); + /* XXXX We will want to try again later if we haven't got enough + * votes yet. Implement this if it turns out to ever happen. */ + voting_schedule.have_built_consensus = 1; + } + if (voting_schedule.fetch_missing_signatures < now && + !voting_schedule.have_fetched_missing_signatures) { + log_notice(LD_DIR, "Time to fetch any signatures that we're missing."); + dirvote_fetch_missing_signatures(); + voting_schedule.have_fetched_missing_signatures = 1; + } + if (voting_schedule.interval_starts < now && + !voting_schedule.have_published_consensus) { + log_notice(LD_DIR, "Time to publish the consensus and discard old votes"); + dirvote_publish_consensus(); + dirvote_clear_votes(0); + voting_schedule.have_published_consensus = 1; + /* XXXX We will want to try again later if we haven't got enough + * signatures yet. Implement this if it turns out to ever happen. */ + dirvote_recalculate_timing(options, now); + } +} + +/** A vote networkstatus_t and its unparsed body: held around so we can + * use it to generate a consensus (at voting_ends) and so we can serve it to + * other authorities that might want it. */ +typedef struct pending_vote_t { + cached_dir_t *vote_body; + networkstatus_t *vote; +} pending_vote_t; + +/** List of pending_vote_t for the current vote. Before we've used them to + * build a consensus, the votes go here. */ +static smartlist_t *pending_vote_list = NULL; +/** List of pending_vote_t for the previous vote. After we've used them to + * build a consensus, the votes go here for the next period. */ +static smartlist_t *previous_vote_list = NULL; + +/* DOCDOC pending_consensuses */ +static pending_consensus_t pending_consensuses[N_CONSENSUS_FLAVORS]; + +/** The detached signatures for the consensus that we're currently + * building. */ +static char *pending_consensus_signatures = NULL; + +/** List of ns_detached_signatures_t: hold signatures that get posted to us + * before we have generated the consensus on our own. */ +static smartlist_t *pending_consensus_signature_list = NULL; + +/** Generate a networkstatus vote and post it to all the v3 authorities. + * (V3 Authority only) */ +static int +dirvote_perform_vote(void) +{ + crypto_pk_t *key = get_my_v3_authority_signing_key(); + authority_cert_t *cert = get_my_v3_authority_cert(); + networkstatus_t *ns; + char *contents; + pending_vote_t *pending_vote; + time_t now = time(NULL); + + int status; + const char *msg = ""; + + if (!cert || !key) { + log_warn(LD_NET, "Didn't find key/certificate to generate v3 vote"); + return -1; + } else if (cert->expires < now) { + log_warn(LD_NET, "Can't generate v3 vote with expired certificate"); + return -1; + } + if (!(ns = dirserv_generate_networkstatus_vote_obj(key, cert))) + return -1; + + contents = format_networkstatus_vote(key, ns); + networkstatus_vote_free(ns); + if (!contents) + return -1; + + pending_vote = dirvote_add_vote(contents, &msg, &status); + tor_free(contents); + if (!pending_vote) { + log_warn(LD_DIR, "Couldn't store my own vote! (I told myself, '%s'.)", + msg); + return -1; + } + + directory_post_to_dirservers(DIR_PURPOSE_UPLOAD_VOTE, + ROUTER_PURPOSE_GENERAL, + V3_DIRINFO, + pending_vote->vote_body->dir, + pending_vote->vote_body->dir_len, 0); + log_notice(LD_DIR, "Vote posted."); + return 0; +} + +/** Send an HTTP request to every other v3 authority, for the votes of every + * authority for which we haven't received a vote yet in this period. (V3 + * authority only) */ +static void +dirvote_fetch_missing_votes(void) +{ + smartlist_t *missing_fps = smartlist_new(); + char *resource; + + SMARTLIST_FOREACH_BEGIN(router_get_trusted_dir_servers(), + dir_server_t *, ds) { + if (!(ds->type & V3_DIRINFO)) + continue; + if (!dirvote_get_vote(ds->v3_identity_digest, + DGV_BY_ID|DGV_INCLUDE_PENDING)) { + char *cp = tor_malloc(HEX_DIGEST_LEN+1); + base16_encode(cp, HEX_DIGEST_LEN+1, ds->v3_identity_digest, + DIGEST_LEN); + smartlist_add(missing_fps, cp); + } + } SMARTLIST_FOREACH_END(ds); + + if (!smartlist_len(missing_fps)) { + smartlist_free(missing_fps); + return; + } + { + char *tmp = smartlist_join_strings(missing_fps, " ", 0, NULL); + log_notice(LOG_NOTICE, "We're missing votes from %d authorities (%s). " + "Asking every other authority for a copy.", + smartlist_len(missing_fps), tmp); + tor_free(tmp); + } + resource = smartlist_join_strings(missing_fps, "+", 0, NULL); + directory_get_from_all_authorities(DIR_PURPOSE_FETCH_STATUS_VOTE, + 0, resource); + tor_free(resource); + SMARTLIST_FOREACH(missing_fps, char *, cp, tor_free(cp)); + smartlist_free(missing_fps); +} + +/** Send a request to every other authority for its detached signatures, + * unless we have signatures from all other v3 authorities already. */ +static void +dirvote_fetch_missing_signatures(void) +{ + int need_any = 0; + int i; + for (i=0; i < N_CONSENSUS_FLAVORS; ++i) { + networkstatus_t *consensus = pending_consensuses[i].consensus; + if (!consensus || + networkstatus_check_consensus_signature(consensus, -1) == 1) { + /* We have no consensus, or we have one that's signed by everybody. */ + continue; + } + need_any = 1; + } + if (!need_any) + return; + + directory_get_from_all_authorities(DIR_PURPOSE_FETCH_DETACHED_SIGNATURES, + 0, NULL); +} + +/** Release all storage held by pending consensuses (those waiting for + * signatures). */ +static void +dirvote_clear_pending_consensuses(void) +{ + int i; + for (i = 0; i < N_CONSENSUS_FLAVORS; ++i) { + pending_consensus_t *pc = &pending_consensuses[i]; + tor_free(pc->body); + + networkstatus_vote_free(pc->consensus); + pc->consensus = NULL; + } +} + +/** Drop all currently pending votes, consensus, and detached signatures. */ +static void +dirvote_clear_votes(int all_votes) +{ + if (!previous_vote_list) + previous_vote_list = smartlist_new(); + if (!pending_vote_list) + pending_vote_list = smartlist_new(); + + /* All "previous" votes are now junk. */ + SMARTLIST_FOREACH(previous_vote_list, pending_vote_t *, v, { + cached_dir_decref(v->vote_body); + v->vote_body = NULL; + networkstatus_vote_free(v->vote); + tor_free(v); + }); + smartlist_clear(previous_vote_list); + + if (all_votes) { + /* If we're dumping all the votes, we delete the pending ones. */ + SMARTLIST_FOREACH(pending_vote_list, pending_vote_t *, v, { + cached_dir_decref(v->vote_body); + v->vote_body = NULL; + networkstatus_vote_free(v->vote); + tor_free(v); + }); + } else { + /* Otherwise, we move them into "previous". */ + smartlist_add_all(previous_vote_list, pending_vote_list); + } + smartlist_clear(pending_vote_list); + + if (pending_consensus_signature_list) { + SMARTLIST_FOREACH(pending_consensus_signature_list, char *, cp, + tor_free(cp)); + smartlist_clear(pending_consensus_signature_list); + } + tor_free(pending_consensus_signatures); + dirvote_clear_pending_consensuses(); +} + +/** Return a newly allocated string containing the hex-encoded v3 authority + identity digest of every recognized v3 authority. */ +static char * +list_v3_auth_ids(void) +{ + smartlist_t *known_v3_keys = smartlist_new(); + char *keys; + SMARTLIST_FOREACH(router_get_trusted_dir_servers(), + dir_server_t *, ds, + if ((ds->type & V3_DIRINFO) && + !tor_digest_is_zero(ds->v3_identity_digest)) + smartlist_add(known_v3_keys, + tor_strdup(hex_str(ds->v3_identity_digest, DIGEST_LEN)))); + keys = smartlist_join_strings(known_v3_keys, ", ", 0, NULL); + SMARTLIST_FOREACH(known_v3_keys, char *, cp, tor_free(cp)); + smartlist_free(known_v3_keys); + return keys; +} + +/** Called when we have received a networkstatus vote in vote_body. + * Parse and validate it, and on success store it as a pending vote (which we + * then return). Return NULL on failure. Sets *msg_out and + * *status_out to an HTTP response and status code. (V3 authority + * only) */ +pending_vote_t * +dirvote_add_vote(const char *vote_body, const char **msg_out, int *status_out) +{ + networkstatus_t *vote; + networkstatus_voter_info_t *vi; + dir_server_t *ds; + pending_vote_t *pending_vote = NULL; + const char *end_of_vote = NULL; + int any_failed = 0; + tor_assert(vote_body); + tor_assert(msg_out); + tor_assert(status_out); + + if (!pending_vote_list) + pending_vote_list = smartlist_new(); + *status_out = 0; + *msg_out = NULL; + + again: + vote = networkstatus_parse_vote_from_string(vote_body, &end_of_vote, + NS_TYPE_VOTE); + if (!end_of_vote) + end_of_vote = vote_body + strlen(vote_body); + if (!vote) { + log_warn(LD_DIR, "Couldn't parse vote: length was %d", + (int)strlen(vote_body)); + *msg_out = "Unable to parse vote"; + goto err; + } + tor_assert(smartlist_len(vote->voters) == 1); + vi = get_voter(vote); + { + int any_sig_good = 0; + SMARTLIST_FOREACH(vi->sigs, document_signature_t *, sig, + if (sig->good_signature) + any_sig_good = 1); + tor_assert(any_sig_good); + } + ds = trusteddirserver_get_by_v3_auth_digest(vi->identity_digest); + if (!ds) { + char *keys = list_v3_auth_ids(); + log_warn(LD_DIR, "Got a vote from an authority (nickname %s, address %s) " + "with authority key ID %s. " + "This key ID is not recognized. Known v3 key IDs are: %s", + vi->nickname, vi->address, + hex_str(vi->identity_digest, DIGEST_LEN), keys); + tor_free(keys); + *msg_out = "Vote not from a recognized v3 authority"; + goto err; + } + tor_assert(vote->cert); + if (!authority_cert_get_by_digests(vote->cert->cache_info.identity_digest, + vote->cert->signing_key_digest)) { + /* Hey, it's a new cert! */ + trusted_dirs_load_certs_from_string( + vote->cert->cache_info.signed_descriptor_body, + TRUSTED_DIRS_CERTS_SRC_FROM_VOTE, 1 /*flush*/); + if (!authority_cert_get_by_digests(vote->cert->cache_info.identity_digest, + vote->cert->signing_key_digest)) { + log_warn(LD_BUG, "We added a cert, but still couldn't find it."); + } + } + + /* Is it for the right period? */ + if (vote->valid_after != voting_schedule.interval_starts) { + char tbuf1[ISO_TIME_LEN+1], tbuf2[ISO_TIME_LEN+1]; + format_iso_time(tbuf1, vote->valid_after); + format_iso_time(tbuf2, voting_schedule.interval_starts); + log_warn(LD_DIR, "Rejecting vote from %s with valid-after time of %s; " + "we were expecting %s", vi->address, tbuf1, tbuf2); + *msg_out = "Bad valid-after time"; + goto err; + } + + /* Fetch any new router descriptors we just learned about */ + update_consensus_router_descriptor_downloads(time(NULL), 1, vote); + + /* Now see whether we already have a vote from this authority. */ + SMARTLIST_FOREACH_BEGIN(pending_vote_list, pending_vote_t *, v) { + if (fast_memeq(v->vote->cert->cache_info.identity_digest, + vote->cert->cache_info.identity_digest, + DIGEST_LEN)) { + networkstatus_voter_info_t *vi_old = get_voter(v->vote); + if (fast_memeq(vi_old->vote_digest, vi->vote_digest, DIGEST_LEN)) { + /* Ah, it's the same vote. Not a problem. */ + log_info(LD_DIR, "Discarding a vote we already have (from %s).", + vi->address); + if (*status_out < 200) + *status_out = 200; + goto discard; + } else if (v->vote->published < vote->published) { + log_notice(LD_DIR, "Replacing an older pending vote from this " + "directory."); + cached_dir_decref(v->vote_body); + networkstatus_vote_free(v->vote); + v->vote_body = new_cached_dir(tor_strndup(vote_body, + end_of_vote-vote_body), + vote->published); + v->vote = vote; + if (end_of_vote && + !strcmpstart(end_of_vote, "network-status-version")) + goto again; + + if (*status_out < 200) + *status_out = 200; + if (!*msg_out) + *msg_out = "OK"; + return v; + } else { + *msg_out = "Already have a newer pending vote"; + goto err; + } + } + } SMARTLIST_FOREACH_END(v); + + pending_vote = tor_malloc_zero(sizeof(pending_vote_t)); + pending_vote->vote_body = new_cached_dir(tor_strndup(vote_body, + end_of_vote-vote_body), + vote->published); + pending_vote->vote = vote; + smartlist_add(pending_vote_list, pending_vote); + + if (!strcmpstart(end_of_vote, "network-status-version ")) { + vote_body = end_of_vote; + goto again; + } + + goto done; + + err: + any_failed = 1; + if (!*msg_out) + *msg_out = "Error adding vote"; + if (*status_out < 400) + *status_out = 400; + + discard: + networkstatus_vote_free(vote); + + if (end_of_vote && !strcmpstart(end_of_vote, "network-status-version ")) { + vote_body = end_of_vote; + goto again; + } + + done: + + if (*status_out < 200) + *status_out = 200; + if (!*msg_out) { + if (!any_failed && !pending_vote) { + *msg_out = "Duplicate discarded"; + } else { + *msg_out = "ok"; + } + } + + return any_failed ? NULL : pending_vote; +} + +/** Try to compute a v3 networkstatus consensus from the currently pending + * votes. Return 0 on success, -1 on failure. Store the consensus in + * pending_consensus: it won't be ready to be published until we have + * everybody else's signatures collected too. (V3 Authority only) */ +static int +dirvote_compute_consensuses(void) +{ + /* Have we got enough votes to try? */ + int n_votes, n_voters, n_vote_running = 0; + smartlist_t *votes = NULL, *votestrings = NULL; + char *consensus_body = NULL, *signatures = NULL, *votefile; + networkstatus_t *consensus = NULL; + authority_cert_t *my_cert; + pending_consensus_t pending[N_CONSENSUS_FLAVORS]; + int flav; + + memset(pending, 0, sizeof(pending)); + + if (!pending_vote_list) + pending_vote_list = smartlist_new(); + + n_voters = get_n_authorities(V3_DIRINFO); + n_votes = smartlist_len(pending_vote_list); + if (n_votes <= n_voters/2) { + log_warn(LD_DIR, "We don't have enough votes to generate a consensus: " + "%d of %d", n_votes, n_voters/2+1); + goto err; + } + tor_assert(pending_vote_list); + SMARTLIST_FOREACH(pending_vote_list, pending_vote_t *, v, { + if (smartlist_contains_string(v->vote->known_flags, "Running")) + n_vote_running++; + }); + if (!n_vote_running) { + /* See task 1066. */ + log_warn(LD_DIR, "Nobody has voted on the Running flag. Generating " + "and publishing a consensus without Running nodes " + "would make many clients stop working. Not " + "generating a consensus!"); + goto err; + } + + if (!(my_cert = get_my_v3_authority_cert())) { + log_warn(LD_DIR, "Can't generate consensus without a certificate."); + goto err; + } + + votes = smartlist_new(); + votestrings = smartlist_new(); + SMARTLIST_FOREACH(pending_vote_list, pending_vote_t *, v, + { + sized_chunk_t *c = tor_malloc(sizeof(sized_chunk_t)); + c->bytes = v->vote_body->dir; + c->len = v->vote_body->dir_len; + smartlist_add(votestrings, c); /* collect strings to write to disk */ + + smartlist_add(votes, v->vote); /* collect votes to compute consensus */ + }); + + votefile = get_datadir_fname("v3-status-votes"); + write_chunks_to_file(votefile, votestrings, 0, 0); + tor_free(votefile); + SMARTLIST_FOREACH(votestrings, sized_chunk_t *, c, tor_free(c)); + smartlist_free(votestrings); + + { + char legacy_dbuf[DIGEST_LEN]; + crypto_pk_t *legacy_sign=NULL; + char *legacy_id_digest = NULL; + int n_generated = 0; + if (get_options()->V3AuthUseLegacyKey) { + authority_cert_t *cert = get_my_v3_legacy_cert(); + legacy_sign = get_my_v3_legacy_signing_key(); + if (cert) { + if (crypto_pk_get_digest(cert->identity_key, legacy_dbuf)) { + log_warn(LD_BUG, + "Unable to compute digest of legacy v3 identity key"); + } else { + legacy_id_digest = legacy_dbuf; + } + } + } + + for (flav = 0; flav < N_CONSENSUS_FLAVORS; ++flav) { + const char *flavor_name = networkstatus_get_flavor_name(flav); + consensus_body = networkstatus_compute_consensus( + votes, n_voters, + my_cert->identity_key, + get_my_v3_authority_signing_key(), legacy_id_digest, legacy_sign, + flav); + + if (!consensus_body) { + log_warn(LD_DIR, "Couldn't generate a %s consensus at all!", + flavor_name); + continue; + } + consensus = networkstatus_parse_vote_from_string(consensus_body, NULL, + NS_TYPE_CONSENSUS); + if (!consensus) { + log_warn(LD_DIR, "Couldn't parse %s consensus we generated!", + flavor_name); + tor_free(consensus_body); + continue; + } + + /* 'Check' our own signature, to mark it valid. */ + networkstatus_check_consensus_signature(consensus, -1); + + pending[flav].body = consensus_body; + pending[flav].consensus = consensus; + n_generated++; + consensus_body = NULL; + consensus = NULL; + } + if (!n_generated) { + log_warn(LD_DIR, "Couldn't generate any consensus flavors at all."); + goto err; + } + } + + signatures = get_detached_signatures_from_pending_consensuses( + pending, N_CONSENSUS_FLAVORS); + + if (!signatures) { + log_warn(LD_DIR, "Couldn't extract signatures."); + goto err; + } + + dirvote_clear_pending_consensuses(); + memcpy(pending_consensuses, pending, sizeof(pending)); + + tor_free(pending_consensus_signatures); + pending_consensus_signatures = signatures; + + if (pending_consensus_signature_list) { + int n_sigs = 0; + /* we may have gotten signatures for this consensus before we built + * it ourself. Add them now. */ + SMARTLIST_FOREACH_BEGIN(pending_consensus_signature_list, char *, sig) { + const char *msg = NULL; + int r = dirvote_add_signatures_to_all_pending_consensuses(sig, + "pending", &msg); + if (r >= 0) + n_sigs += r; + else + log_warn(LD_DIR, + "Could not add queued signature to new consensus: %s", + msg); + tor_free(sig); + } SMARTLIST_FOREACH_END(sig); + if (n_sigs) + log_notice(LD_DIR, "Added %d pending signatures while building " + "consensus.", n_sigs); + smartlist_clear(pending_consensus_signature_list); + } + + log_notice(LD_DIR, "Consensus computed; uploading signature(s)"); + + directory_post_to_dirservers(DIR_PURPOSE_UPLOAD_SIGNATURES, + ROUTER_PURPOSE_GENERAL, + V3_DIRINFO, + pending_consensus_signatures, + strlen(pending_consensus_signatures), 0); + log_notice(LD_DIR, "Signature(s) posted."); + + smartlist_free(votes); + return 0; + err: + smartlist_free(votes); + tor_free(consensus_body); + tor_free(signatures); + networkstatus_vote_free(consensus); + + return -1; +} + +/** Helper: we just got the detached_signatures_body sent to us as + * signatures on the currently pending consensus. Add them to pc + * as appropriate. Return the number of signatures added. (?) */ +static int +dirvote_add_signatures_to_pending_consensus( + pending_consensus_t *pc, + ns_detached_signatures_t *sigs, + const char *source, + int severity, + const char **msg_out) +{ + const char *flavor_name; + int r = -1; + + /* Only call if we have a pending consensus right now. */ + tor_assert(pc->consensus); + tor_assert(pc->body); + tor_assert(pending_consensus_signatures); + + flavor_name = networkstatus_get_flavor_name(pc->consensus->flavor); + *msg_out = NULL; + + { + smartlist_t *sig_list = strmap_get(sigs->signatures, flavor_name); + log_info(LD_DIR, "Have %d signatures for adding to %s consensus.", + sig_list ? smartlist_len(sig_list) : 0, flavor_name); + } + r = networkstatus_add_detached_signatures(pc->consensus, sigs, + source, severity, msg_out); + log_info(LD_DIR,"Added %d signatures to consensus.", r); + + if (r >= 1) { + char *new_signatures = + networkstatus_format_signatures(pc->consensus, 0); + char *dst, *dst_end; + size_t new_consensus_len; + if (!new_signatures) { + *msg_out = "No signatures to add"; + goto err; + } + new_consensus_len = + strlen(pc->body) + strlen(new_signatures) + 1; + pc->body = tor_realloc(pc->body, new_consensus_len); + dst_end = pc->body + new_consensus_len; + dst = strstr(pc->body, "directory-signature "); + tor_assert(dst); + strlcpy(dst, new_signatures, dst_end-dst); + + /* We remove this block once it has failed to crash for a while. But + * unless it shows up in profiles, we're probably better leaving it in, + * just in case we break detached signature processing at some point. */ + { + networkstatus_t *v = networkstatus_parse_vote_from_string( + pc->body, NULL, + NS_TYPE_CONSENSUS); + tor_assert(v); + networkstatus_vote_free(v); + } + *msg_out = "Signatures added"; + tor_free(new_signatures); + } else if (r == 0) { + *msg_out = "Signatures ignored"; + } else { + goto err; + } + + goto done; + err: + if (!*msg_out) + *msg_out = "Unrecognized error while adding detached signatures."; + done: + return r; +} + +static int +dirvote_add_signatures_to_all_pending_consensuses( + const char *detached_signatures_body, + const char *source, + const char **msg_out) +{ + int r=0, i, n_added = 0, errors = 0; + ns_detached_signatures_t *sigs; + tor_assert(detached_signatures_body); + tor_assert(msg_out); + tor_assert(pending_consensus_signatures); + + if (!(sigs = networkstatus_parse_detached_signatures( + detached_signatures_body, NULL))) { + *msg_out = "Couldn't parse detached signatures."; + goto err; + } + + for (i = 0; i < N_CONSENSUS_FLAVORS; ++i) { + int res; + int severity = i == FLAV_NS ? LOG_NOTICE : LOG_INFO; + pending_consensus_t *pc = &pending_consensuses[i]; + if (!pc->consensus) + continue; + res = dirvote_add_signatures_to_pending_consensus(pc, sigs, source, + severity, msg_out); + if (res < 0) + errors++; + else + n_added += res; + } + + if (errors && !n_added) { + r = -1; + goto err; + } + + if (n_added && pending_consensuses[FLAV_NS].consensus) { + char *new_detached = + get_detached_signatures_from_pending_consensuses( + pending_consensuses, N_CONSENSUS_FLAVORS); + if (new_detached) { + tor_free(pending_consensus_signatures); + pending_consensus_signatures = new_detached; + } + } + + r = n_added; + goto done; + err: + if (!*msg_out) + *msg_out = "Unrecognized error while adding detached signatures."; + done: + ns_detached_signatures_free(sigs); + /* XXXX NM Check how return is used. We can now have an error *and* + signatures added. */ + return r; +} + +/** Helper: we just got the detached_signatures_body sent to us as + * signatures on the currently pending consensus. Add them to the pending + * consensus (if we have one); otherwise queue them until we have a + * consensus. Return negative on failure, nonnegative on success. */ +int +dirvote_add_signatures(const char *detached_signatures_body, + const char *source, + const char **msg) +{ + if (pending_consensuses[FLAV_NS].consensus) { + log_notice(LD_DIR, "Got a signature from %s. " + "Adding it to the pending consensus.", source); + return dirvote_add_signatures_to_all_pending_consensuses( + detached_signatures_body, source, msg); + } else { + log_notice(LD_DIR, "Got a signature from %s. " + "Queuing it for the next consensus.", source); + if (!pending_consensus_signature_list) + pending_consensus_signature_list = smartlist_new(); + smartlist_add(pending_consensus_signature_list, + tor_strdup(detached_signatures_body)); + *msg = "Signature queued"; + return 0; + } +} + +/** Replace the consensus that we're currently serving with the one that we've + * been building. (V3 Authority only) */ +static int +dirvote_publish_consensus(void) +{ + int i; + + /* Now remember all the other consensuses as if we were a directory cache. */ + for (i = 0; i < N_CONSENSUS_FLAVORS; ++i) { + pending_consensus_t *pending = &pending_consensuses[i]; + const char *name; + name = networkstatus_get_flavor_name(i); + tor_assert(name); + if (!pending->consensus || + networkstatus_check_consensus_signature(pending->consensus, 1)<0) { + log_warn(LD_DIR, "Not enough info to publish pending %s consensus",name); + continue; + } + + if (networkstatus_set_current_consensus(pending->body, name, 0)) + log_warn(LD_DIR, "Error publishing %s consensus", name); + else + log_notice(LD_DIR, "Published %s consensus", name); + } + + return 0; +} + +/** Release all static storage held in dirvote.c */ +void +dirvote_free_all(void) +{ + dirvote_clear_votes(1); + /* now empty as a result of dirvote_clear_votes(). */ + smartlist_free(pending_vote_list); + pending_vote_list = NULL; + smartlist_free(previous_vote_list); + previous_vote_list = NULL; + + dirvote_clear_pending_consensuses(); + tor_free(pending_consensus_signatures); + if (pending_consensus_signature_list) { + /* now empty as a result of dirvote_clear_votes(). */ + smartlist_free(pending_consensus_signature_list); + pending_consensus_signature_list = NULL; + } +} + +/* ==== + * Access to pending items. + * ==== */ + +/** Return the body of the consensus that we're currently trying to build. */ +const char * +dirvote_get_pending_consensus(consensus_flavor_t flav) +{ + tor_assert(((int)flav) >= 0 && (int)flav < N_CONSENSUS_FLAVORS); + return pending_consensuses[flav].body; +} + +/** Return the signatures that we know for the consensus that we're currently + * trying to build. */ +const char * +dirvote_get_pending_detached_signatures(void) +{ + return pending_consensus_signatures; +} + +/** Return a given vote specified by fp. If by_id, return the + * vote for the authority with the v3 authority identity key digest fp; + * if by_id is false, return the vote whose digest is fp. If + * fp is NULL, return our own vote. If include_previous is + * false, do not consider any votes for a consensus that's already been built. + * If include_pending is false, do not consider any votes for the + * consensus that's in progress. May return NULL if we have no vote for the + * authority in question. */ +const cached_dir_t * +dirvote_get_vote(const char *fp, int flags) +{ + int by_id = flags & DGV_BY_ID; + const int include_pending = flags & DGV_INCLUDE_PENDING; + const int include_previous = flags & DGV_INCLUDE_PREVIOUS; + + if (!pending_vote_list && !previous_vote_list) + return NULL; + if (fp == NULL) { + authority_cert_t *c = get_my_v3_authority_cert(); + if (c) { + fp = c->cache_info.identity_digest; + by_id = 1; + } else + return NULL; + } + if (by_id) { + if (pending_vote_list && include_pending) { + SMARTLIST_FOREACH(pending_vote_list, pending_vote_t *, pv, + if (fast_memeq(get_voter(pv->vote)->identity_digest, fp, DIGEST_LEN)) + return pv->vote_body); + } + if (previous_vote_list && include_previous) { + SMARTLIST_FOREACH(previous_vote_list, pending_vote_t *, pv, + if (fast_memeq(get_voter(pv->vote)->identity_digest, fp, DIGEST_LEN)) + return pv->vote_body); + } + } else { + if (pending_vote_list && include_pending) { + SMARTLIST_FOREACH(pending_vote_list, pending_vote_t *, pv, + if (fast_memeq(pv->vote->digests.d[DIGEST_SHA1], fp, DIGEST_LEN)) + return pv->vote_body); + } + if (previous_vote_list && include_previous) { + SMARTLIST_FOREACH(previous_vote_list, pending_vote_t *, pv, + if (fast_memeq(pv->vote->digests.d[DIGEST_SHA1], fp, DIGEST_LEN)) + return pv->vote_body); + } + } + return NULL; +} + +/** Construct and return a new microdescriptor from a routerinfo ri + * according to consensus_method. + **/ +microdesc_t * +dirvote_create_microdescriptor(const routerinfo_t *ri, int consensus_method) +{ + microdesc_t *result = NULL; + char *key = NULL, *summary = NULL, *family = NULL; + size_t keylen; + smartlist_t *chunks = smartlist_new(); + char *output = NULL; + + if (crypto_pk_write_public_key_to_string(ri->onion_pkey, &key, &keylen)<0) + goto done; + summary = policy_summarize(ri->exit_policy, AF_INET); + if (ri->declared_family) + family = smartlist_join_strings(ri->declared_family, " ", 0, NULL); + + smartlist_add_asprintf(chunks, "onion-key\n%s", key); + + if (consensus_method >= MIN_METHOD_FOR_NTOR_KEY && + ri->onion_curve25519_pkey) { + char kbuf[128]; + base64_encode(kbuf, sizeof(kbuf), + (const char*)ri->onion_curve25519_pkey->public_key, + CURVE25519_PUBKEY_LEN); + smartlist_add_asprintf(chunks, "ntor-onion-key %s", kbuf); + } + + if (consensus_method >= MIN_METHOD_FOR_A_LINES && + !tor_addr_is_null(&ri->ipv6_addr) && ri->ipv6_orport) + smartlist_add_asprintf(chunks, "a %s\n", + fmt_addrport(&ri->ipv6_addr, ri->ipv6_orport)); + + if (family) + smartlist_add_asprintf(chunks, "family %s\n", family); + + if (summary && strcmp(summary, "reject 1-65535")) + smartlist_add_asprintf(chunks, "p %s\n", summary); + + if (consensus_method >= MIN_METHOD_FOR_P6_LINES && + ri->ipv6_exit_policy) { + /* XXXX024 This doesn't match proposal 208, which says these should + * be taken unchanged from the routerinfo. That's bogosity, IMO: + * the proposal should have said to do this instead.*/ + char *p6 = write_short_policy(ri->ipv6_exit_policy); + if (p6 && strcmp(p6, "reject 1-65535")) + smartlist_add_asprintf(chunks, "p6 %s\n", p6); + tor_free(p6); + } + + output = smartlist_join_strings(chunks, "", 0, NULL); + + { + smartlist_t *lst = microdescs_parse_from_string(output, + output+strlen(output), 0, + SAVED_NOWHERE); + if (smartlist_len(lst) != 1) { + log_warn(LD_DIR, "We generated a microdescriptor we couldn't parse."); + SMARTLIST_FOREACH(lst, microdesc_t *, md, microdesc_free(md)); + smartlist_free(lst); + goto done; + } + result = smartlist_get(lst, 0); + smartlist_free(lst); + } + + done: + tor_free(output); + tor_free(key); + tor_free(summary); + tor_free(family); + if (chunks) { + SMARTLIST_FOREACH(chunks, char *, cp, tor_free(cp)); + smartlist_free(chunks); + } + return result; +} + +/** Format the appropriate vote line to describe the microdescriptor md + * in a consensus vote document. Write it into the out_len-byte buffer + * in out. Return -1 on failure and the number of characters written + * on success. */ +ssize_t +dirvote_format_microdesc_vote_line(char *out_buf, size_t out_buf_len, + const microdesc_t *md, + int consensus_method_low, + int consensus_method_high) +{ + ssize_t ret = -1; + char d64[BASE64_DIGEST256_LEN+1]; + char *microdesc_consensus_methods = + make_consensus_method_list(consensus_method_low, + consensus_method_high, + ","); + tor_assert(microdesc_consensus_methods); + + if (digest256_to_base64(d64, md->digest)<0) + goto out; + + if (tor_snprintf(out_buf, out_buf_len, "m %s sha256=%s\n", + microdesc_consensus_methods, d64)<0) + goto out; + + ret = strlen(out_buf); + + out: + tor_free(microdesc_consensus_methods); + return ret; +} + +/** Array of start and end of consensus methods used for supported + microdescriptor formats. */ +static const struct consensus_method_range_t { + int low; + int high; +} microdesc_consensus_methods[] = { + {MIN_METHOD_FOR_MICRODESC, MIN_METHOD_FOR_A_LINES - 1}, + {MIN_METHOD_FOR_A_LINES, MIN_METHOD_FOR_P6_LINES - 1}, + {MIN_METHOD_FOR_P6_LINES, MIN_METHOD_FOR_NTOR_KEY - 1}, + {MIN_METHOD_FOR_NTOR_KEY, MAX_SUPPORTED_CONSENSUS_METHOD}, + {-1, -1} +}; + +/** Helper type used when generating the microdescriptor lines in a directory + * vote. */ +typedef struct microdesc_vote_line_t { + int low; + int high; + microdesc_t *md; + struct microdesc_vote_line_t *next; +} microdesc_vote_line_t; + +/** Generate and return a linked list of all the lines that should appear to + * describe a router's microdescriptor versions in a directory vote. + * Add the generated microdescriptors to microdescriptors_out. */ +vote_microdesc_hash_t * +dirvote_format_all_microdesc_vote_lines(const routerinfo_t *ri, time_t now, + smartlist_t *microdescriptors_out) +{ + const struct consensus_method_range_t *cmr; + microdesc_vote_line_t *entries = NULL, *ep; + vote_microdesc_hash_t *result = NULL; + + /* Generate the microdescriptors. */ + for (cmr = microdesc_consensus_methods; + cmr->low != -1 && cmr->high != -1; + cmr++) { + microdesc_t *md = dirvote_create_microdescriptor(ri, cmr->low); + if (md) { + microdesc_vote_line_t *e = + tor_malloc_zero(sizeof(microdesc_vote_line_t)); + e->md = md; + e->low = cmr->low; + e->high = cmr->high; + e->next = entries; + entries = e; + } + } + + /* Compress adjacent identical ones */ + for (ep = entries; ep; ep = ep->next) { + while (ep->next && + fast_memeq(ep->md->digest, ep->next->md->digest, DIGEST256_LEN) && + ep->low == ep->next->high + 1) { + microdesc_vote_line_t *next = ep->next; + ep->low = next->low; + microdesc_free(next->md); + ep->next = next->next; + tor_free(next); + } + } + + /* Format them into vote_microdesc_hash_t, and add to microdescriptors_out.*/ + while ((ep = entries)) { + char buf[128]; + vote_microdesc_hash_t *h; + dirvote_format_microdesc_vote_line(buf, sizeof(buf), ep->md, + ep->low, ep->high); + h = tor_malloc_zero(sizeof(vote_microdesc_hash_t)); + h->microdesc_hash_line = tor_strdup(buf); + h->next = result; + result = h; + ep->md->last_listed = now; + smartlist_add(microdescriptors_out, ep->md); + entries = ep->next; + tor_free(ep); + } + + return result; +} + +/** If vrs has a hash made for the consensus method method with + * the digest algorithm alg, decode it and copy it into + * digest256_out and return 0. Otherwise return -1. */ +int +vote_routerstatus_find_microdesc_hash(char *digest256_out, + const vote_routerstatus_t *vrs, + int method, + digest_algorithm_t alg) +{ + /* XXXX only returns the sha256 method. */ + const vote_microdesc_hash_t *h; + char mstr[64]; + size_t mlen; + char dstr[64]; + + tor_snprintf(mstr, sizeof(mstr), "%d", method); + mlen = strlen(mstr); + tor_snprintf(dstr, sizeof(dstr), " %s=", + crypto_digest_algorithm_get_name(alg)); + + for (h = vrs->microdesc; h; h = h->next) { + const char *cp = h->microdesc_hash_line; + size_t num_len; + /* cp looks like \d+(,\d+)* (digesttype=val )+ . Let's hunt for mstr in + * the first part. */ + while (1) { + num_len = strspn(cp, "1234567890"); + if (num_len == mlen && fast_memeq(mstr, cp, mlen)) { + /* This is the line. */ + char buf[BASE64_DIGEST256_LEN+1]; + /* XXXX ignores extraneous stuff if the digest is too long. This + * seems harmless enough, right? */ + cp = strstr(cp, dstr); + if (!cp) + return -1; + cp += strlen(dstr); + strlcpy(buf, cp, sizeof(buf)); + return digest256_from_base64(digest256_out, buf); + } + if (num_len == 0 || cp[num_len] != ',') + break; + cp += num_len + 1; + } + } + return -1; +} + diff --git a/src/tor/dirvote.h b/src/tor/dirvote.h new file mode 100644 index 0000000..3a4951a --- /dev/null +++ b/src/tor/dirvote.h @@ -0,0 +1,148 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file dirvote.h + * \brief Header file for dirvote.c. + **/ + +#ifndef TOR_DIRVOTE_H +#define TOR_DIRVOTE_H + +#include "testsupport.h" + +/** Lowest allowable value for VoteSeconds. */ +#define MIN_VOTE_SECONDS 2 +/** Lowest allowable value for DistSeconds. */ +#define MIN_DIST_SECONDS 2 +/** Smallest allowable voting interval. */ +#define MIN_VOTE_INTERVAL 300 + +/** The highest consensus method that we currently support. */ +#define MAX_SUPPORTED_CONSENSUS_METHOD 17 + +/** Lowest consensus method that contains a 'directory-footer' marker */ +#define MIN_METHOD_FOR_FOOTER 9 + +/** Lowest consensus method that contains bandwidth weights */ +#define MIN_METHOD_FOR_BW_WEIGHTS 9 + +/** Lowest consensus method that contains consensus params */ +#define MIN_METHOD_FOR_PARAMS 7 + +/** Lowest consensus method that generates microdescriptors */ +#define MIN_METHOD_FOR_MICRODESC 8 + +/** Lowest consensus method that doesn't count bad exits as exits for weight */ +#define MIN_METHOD_TO_CUT_BADEXIT_WEIGHT 11 + +/** Lowest consensus method that ensures a majority of authorities voted + * for a param. */ +#define MIN_METHOD_FOR_MAJORITY_PARAMS 12 + +/** Lowest consensus method where microdesc consensuses omit any entry + * with no microdesc. */ +#define MIN_METHOD_FOR_MANDATORY_MICRODESC 13 + +/** Lowest consensus method that contains "a" lines. */ +#define MIN_METHOD_FOR_A_LINES 14 + +/** Lowest consensus method where microdescs may include a "p6" line. */ +#define MIN_METHOD_FOR_P6_LINES 15 + +/** Lowest consensus method where microdescs may include an onion-key-ntor + * line */ +#define MIN_METHOD_FOR_NTOR_KEY 16 + +/** Lowest consensus method that ensures that authorities output an + * Unmeasured=1 flag for unmeasured bandwidths */ +#define MIN_METHOD_TO_CLIP_UNMEASURED_BW 17 + +/** Default bandwidth to clip unmeasured bandwidths to using method >= + * MIN_METHOD_TO_CLIP_UNMEASURED_BW */ +#define DEFAULT_MAX_UNMEASURED_BW_KB 20 + +void dirvote_free_all(void); + +/* vote manipulation */ +char *networkstatus_compute_consensus(smartlist_t *votes, + int total_authorities, + crypto_pk_t *identity_key, + crypto_pk_t *signing_key, + const char *legacy_identity_key_digest, + crypto_pk_t *legacy_signing_key, + consensus_flavor_t flavor); +int networkstatus_add_detached_signatures(networkstatus_t *target, + ns_detached_signatures_t *sigs, + const char *source, + int severity, + const char **msg_out); +char *networkstatus_get_detached_signatures(smartlist_t *consensuses); +void ns_detached_signatures_free(ns_detached_signatures_t *s); + +/* cert manipulation */ +authority_cert_t *authority_cert_dup(authority_cert_t *cert); + +/* vote scheduling */ +void dirvote_get_preferred_voting_intervals(vote_timing_t *timing_out); +time_t dirvote_get_start_of_next_interval(time_t now, + int interval, + int offset); +void dirvote_recalculate_timing(const or_options_t *options, time_t now); +void dirvote_act(const or_options_t *options, time_t now); + +/* invoked on timers and by outside triggers. */ +struct pending_vote_t * dirvote_add_vote(const char *vote_body, + const char **msg_out, + int *status_out); +int dirvote_add_signatures(const char *detached_signatures_body, + const char *source, + const char **msg_out); + +/* Item access */ +const char *dirvote_get_pending_consensus(consensus_flavor_t flav); +const char *dirvote_get_pending_detached_signatures(void); +#define DGV_BY_ID 1 +#define DGV_INCLUDE_PENDING 2 +#define DGV_INCLUDE_PREVIOUS 4 +const cached_dir_t *dirvote_get_vote(const char *fp, int flags); +void set_routerstatus_from_routerinfo(routerstatus_t *rs, + node_t *node, + routerinfo_t *ri, time_t now, + int naming, int listbadexits, + int listbaddirs, int vote_on_hsdirs); +networkstatus_t * +dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key, + authority_cert_t *cert); + +microdesc_t *dirvote_create_microdescriptor(const routerinfo_t *ri, + int consensus_method); +ssize_t dirvote_format_microdesc_vote_line(char *out, size_t out_len, + const microdesc_t *md, + int consensus_method_low, + int consensus_method_high); +vote_microdesc_hash_t *dirvote_format_all_microdesc_vote_lines( + const routerinfo_t *ri, + time_t now, + smartlist_t *microdescriptors_out); + +int vote_routerstatus_find_microdesc_hash(char *digest256_out, + const vote_routerstatus_t *vrs, + int method, + digest_algorithm_t alg); +document_signature_t *voter_get_sig_by_algorithm( + const networkstatus_voter_info_t *voter, + digest_algorithm_t alg); + +#ifdef DIRVOTE_PRIVATE +STATIC char *format_networkstatus_vote(crypto_pk_t *private_key, + networkstatus_t *v3_ns); +STATIC char *dirvote_compute_params(smartlist_t *votes, int method, + int total_authorities); +#endif + +#endif + diff --git a/src/tor/dns.c b/src/tor/dns.c new file mode 100644 index 0000000..9abf550 --- /dev/null +++ b/src/tor/dns.c @@ -0,0 +1,2203 @@ +/* Copyright (c) 2003-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file dns.c + * \brief Implements a local cache for DNS results for Tor servers. + * This is implemented as a wrapper around Adam Langley's eventdns.c code. + * (We can't just use gethostbyname() and friends because we really need to + * be nonblocking.) + **/ + +#include "or.h" +#include "circuitlist.h" +#include "circuituse.h" +#include "config.h" +#include "connection.h" +#include "connection_edge.h" +#include "control.h" +#include "dns.h" +#include "onion_main.h" +#include "policies.h" +#include "relay.h" +#include "router.h" +#include "ht.h" +#include "sandbox.h" +#ifdef HAVE_EVENT2_DNS_H +#include +#include +#else +#include +#include "eventdns.h" +#ifndef HAVE_EVDNS_SET_DEFAULT_OUTGOING_BIND_ADDRESS +#define HAVE_EVDNS_SET_DEFAULT_OUTGOING_BIND_ADDRESS +#endif +#endif + +#ifndef HAVE_EVENT2_DNS_H +struct evdns_base; +struct evdns_request; +#define evdns_base_new(x,y) tor_malloc(1) +#define evdns_base_clear_nameservers_and_suspend(base) \ + evdns_clear_nameservers_and_suspend() +#define evdns_base_search_clear(base) evdns_search_clear() +#define evdns_base_set_default_outgoing_bind_address(base, a, len) \ + evdns_set_default_outgoing_bind_address((a),(len)) +#define evdns_base_resolv_conf_parse(base, options, fname) \ + evdns_resolv_conf_parse((options), (fname)) +#define evdns_base_count_nameservers(base) \ + evdns_count_nameservers() +#define evdns_base_resume(base) \ + evdns_resume() +#define evdns_base_config_windows_nameservers(base) \ + evdns_config_windows_nameservers() +#define evdns_base_set_option_(base, opt, val) \ + evdns_set_option((opt),(val),DNS_OPTIONS_ALL) +/* Note: our internal eventdns.c, plus Libevent 1.4, used a 1 return to + * signify failure to launch a resolve. Libevent 2.0 uses a -1 return to + * signify a failure on a resolve, though if we're on Libevent 2.0, we should + * have event2/dns.h and never hit these macros. Regardless, 0 is success. */ +#define evdns_base_resolve_ipv4(base, addr, options, cb, ptr) \ + ((evdns_resolve_ipv4((addr), (options), (cb), (ptr))!=0) \ + ? NULL : ((void*)1)) +#define evdns_base_resolve_ipv6(base, addr, options, cb, ptr) \ + ((evdns_resolve_ipv6((addr), (options), (cb), (ptr))!=0) \ + ? NULL : ((void*)1)) +#define evdns_base_resolve_reverse(base, addr, options, cb, ptr) \ + ((evdns_resolve_reverse((addr), (options), (cb), (ptr))!=0) \ + ? NULL : ((void*)1)) +#define evdns_base_resolve_reverse_ipv6(base, addr, options, cb, ptr) \ + ((evdns_resolve_reverse_ipv6((addr), (options), (cb), (ptr))!=0) \ + ? NULL : ((void*)1)) + +#elif defined(LIBEVENT_VERSION_NUMBER) && LIBEVENT_VERSION_NUMBER < 0x02000303 +#define evdns_base_set_option_(base, opt, val) \ + evdns_base_set_option((base), (opt),(val),DNS_OPTIONS_ALL) + +#else +#define evdns_base_set_option_ evdns_base_set_option + +#endif + +/** Longest hostname we're willing to resolve. */ +#define MAX_ADDRESSLEN 256 + +/** How long will we wait for an answer from the resolver before we decide + * that the resolver is wedged? */ +#define RESOLVE_MAX_TIMEOUT 300 + +/** Our evdns_base; this structure handles all our name lookups. */ +static struct evdns_base *the_evdns_base = NULL; + +/** Have we currently configured nameservers with eventdns? */ +static int nameservers_configured = 0; +/** Did our most recent attempt to configure nameservers with eventdns fail? */ +static int nameserver_config_failed = 0; +/** What was the resolv_conf fname we last used when configuring the + * nameservers? Used to check whether we need to reconfigure. */ +static char *resolv_conf_fname = NULL; +/** What was the mtime on the resolv.conf file we last used when configuring + * the nameservers? Used to check whether we need to reconfigure. */ +static time_t resolv_conf_mtime = 0; + +/** Linked list of connections waiting for a DNS answer. */ +typedef struct pending_connection_t { + edge_connection_t *conn; + struct pending_connection_t *next; +} pending_connection_t; + +/** Value of 'magic' field for cached_resolve_t. Used to try to catch bad + * pointers and memory stomping. */ +#define CACHED_RESOLVE_MAGIC 0x1234F00D + +/* Possible states for a cached resolve_t */ +/** We are waiting for the resolver system to tell us an answer here. + * When we get one, or when we time out, the state of this cached_resolve_t + * will become "DONE" and we'll possibly add a CACHED + * entry. This cached_resolve_t will be in the hash table so that we will + * know not to launch more requests for this addr, but rather to add more + * connections to the pending list for the addr. */ +#define CACHE_STATE_PENDING 0 +/** This used to be a pending cached_resolve_t, and we got an answer for it. + * Now we're waiting for this cached_resolve_t to expire. This should + * have no pending connections, and should not appear in the hash table. */ +#define CACHE_STATE_DONE 1 +/** We are caching an answer for this address. This should have no pending + * connections, and should appear in the hash table. */ +#define CACHE_STATE_CACHED 2 + +/** @name status values for a single DNS request. + * + * @{ */ +/** The DNS request is in progress. */ +#define RES_STATUS_INFLIGHT 1 +/** The DNS request finished and gave an answer */ +#define RES_STATUS_DONE_OK 2 +/** The DNS request finished and gave an error */ +#define RES_STATUS_DONE_ERR 3 +/**@}*/ + +/** A DNS request: possibly completed, possibly pending; cached_resolve + * structs are stored at the OR side in a hash table, and as a linked + * list from oldest to newest. + */ +typedef struct cached_resolve_t { + HT_ENTRY(cached_resolve_t) node; + uint32_t magic; /**< Must be CACHED_RESOLVE_MAGIC */ + char address[MAX_ADDRESSLEN]; /**< The hostname to be resolved. */ + + union { + uint32_t addr_ipv4; /**< IPv4 addr for address, if successful. + * (In host order.) */ + int err_ipv4; /**< One of DNS_ERR_*, if IPv4 lookup failed. */ + } result_ipv4; /**< Outcome of IPv4 lookup */ + union { + struct in6_addr addr_ipv6; /**< IPv6 addr for address, if + * successful */ + int err_ipv6; /**< One of DNS_ERR_*, if IPv6 lookup failed. */ + } result_ipv6; /**< Outcome of IPv6 lookup, if any */ + union { + char *hostname; /** A hostname, if PTR lookup happened successfully*/ + int err_hostname; /** One of DNS_ERR_*, if PTR lookup failed. */ + } result_ptr; + /** @name Status fields + * + * These take one of the RES_STATUS_* values, depending on the state + * of the corresponding lookup. + * + * @{ */ + unsigned int res_status_ipv4 : 2; + unsigned int res_status_ipv6 : 2; + unsigned int res_status_hostname : 2; + /**@}*/ + uint8_t state; /**< Is this cached entry pending/done/informative? */ + + time_t expire; /**< Remove items from cache after this time. */ + uint32_t ttl_ipv4; /**< What TTL did the nameserver tell us? */ + uint32_t ttl_ipv6; /**< What TTL did the nameserver tell us? */ + uint32_t ttl_hostname; /**< What TTL did the nameserver tell us? */ + /** Connections that want to know when we get an answer for this resolve. */ + pending_connection_t *pending_connections; + /** Position of this element in the heap*/ + int minheap_idx; +} cached_resolve_t; + +static void purge_expired_resolves(time_t now); +static void dns_found_answer(const char *address, uint8_t query_type, + int dns_answer, + const tor_addr_t *addr, + const char *hostname, + uint32_t ttl); +static void send_resolved_cell(edge_connection_t *conn, uint8_t answer_type, + const cached_resolve_t *resolve); +static int launch_resolve(cached_resolve_t *resolve); +static void add_wildcarded_test_address(const char *address); +static int configure_nameservers(int force); +static int answer_is_wildcarded(const char *ip); +static int dns_resolve_impl(edge_connection_t *exitconn, int is_resolve, + or_circuit_t *oncirc, char **resolved_to_hostname, + int *made_connection_pending_out, + cached_resolve_t **resolve_out); +static int set_exitconn_info_from_resolve(edge_connection_t *exitconn, + const cached_resolve_t *resolve, + char **hostname_out); +static int evdns_err_is_transient(int err); +static void inform_pending_connections(cached_resolve_t *resolve); +static void make_pending_resolve_cached(cached_resolve_t *cached); + +#ifdef DEBUG_DNS_CACHE +static void assert_cache_ok_(void); +#define assert_cache_ok() assert_cache_ok_() +#else +#define assert_cache_ok() STMT_NIL +#endif +static void assert_resolve_ok(cached_resolve_t *resolve); + +/** Hash table of cached_resolve objects. */ +static HT_HEAD(cache_map, cached_resolve_t) cache_root; + +/** Global: how many IPv6 requests have we made in all? */ +static uint64_t n_ipv6_requests_made = 0; +/** Global: how many IPv6 requests have timed out? */ +static uint64_t n_ipv6_timeouts = 0; +/** Global: Do we think that IPv6 DNS is broken? */ +static int dns_is_broken_for_ipv6 = 0; + +/** Function to compare hashed resolves on their addresses; used to + * implement hash tables. */ +static INLINE int +cached_resolves_eq(cached_resolve_t *a, cached_resolve_t *b) +{ + /* make this smarter one day? */ + assert_resolve_ok(a); // Not b; b may be just a search. + return !strncmp(a->address, b->address, MAX_ADDRESSLEN); +} + +/** Hash function for cached_resolve objects */ +static INLINE unsigned int +cached_resolve_hash(cached_resolve_t *a) +{ + return ht_string_hash(a->address); +} + +HT_PROTOTYPE(cache_map, cached_resolve_t, node, cached_resolve_hash, + cached_resolves_eq) +HT_GENERATE(cache_map, cached_resolve_t, node, cached_resolve_hash, + cached_resolves_eq, 0.6, malloc, realloc, free) + +/** Initialize the DNS cache. */ +static void +init_cache_map(void) +{ + HT_INIT(cache_map, &cache_root); +} + +/** Helper: called by eventdns when eventdns wants to log something. */ +static void +evdns_log_cb(int warn, const char *msg) +{ + const char *cp; + static int all_down = 0; + int severity = warn ? LOG_WARN : LOG_INFO; + if (!strcmpstart(msg, "Resolve requested for") && + get_options()->SafeLogging) { + log_info(LD_EXIT, "eventdns: Resolve requested."); + return; + } else if (!strcmpstart(msg, "Search: ")) { + return; + } + if (!strcmpstart(msg, "Nameserver ") && (cp=strstr(msg, " has failed: "))) { + char *ns = tor_strndup(msg+11, cp-(msg+11)); + const char *err = strchr(cp, ':')+2; + tor_assert(err); + /* Don't warn about a single failed nameserver; we'll warn with 'all + * nameservers have failed' if we're completely out of nameservers; + * otherwise, the situation is tolerable. */ + severity = LOG_INFO; + control_event_server_status(LOG_NOTICE, + "NAMESERVER_STATUS NS=%s STATUS=DOWN ERR=%s", + ns, escaped(err)); + tor_free(ns); + } else if (!strcmpstart(msg, "Nameserver ") && + (cp=strstr(msg, " is back up"))) { + char *ns = tor_strndup(msg+11, cp-(msg+11)); + severity = (all_down && warn) ? LOG_NOTICE : LOG_INFO; + all_down = 0; + control_event_server_status(LOG_NOTICE, + "NAMESERVER_STATUS NS=%s STATUS=UP", ns); + tor_free(ns); + } else if (!strcmp(msg, "All nameservers have failed")) { + control_event_server_status(LOG_WARN, "NAMESERVER_ALL_DOWN"); + all_down = 1; + } + tor_log(severity, LD_EXIT, "eventdns: %s", msg); +} + +/** Helper: passed to eventdns.c as a callback so it can generate random + * numbers for transaction IDs and 0x20-hack coding. */ +static void +dns_randfn_(char *b, size_t n) +{ + crypto_rand(b,n); +} + +/** Initialize the DNS subsystem; called by the OR process. */ +int +dns_init(void) +{ + init_cache_map(); + evdns_set_random_bytes_fn(dns_randfn_); + if (server_mode(get_options())) { + int r = configure_nameservers(1); + return r; + } + return 0; +} + +/** Called when DNS-related options change (or may have changed). Returns -1 + * on failure, 0 on success. */ +int +dns_reset(void) +{ + const or_options_t *options = get_options(); + if (! server_mode(options)) { + + if (!the_evdns_base) { + if (!(the_evdns_base = evdns_base_new(tor_libevent_get_base(), 0))) { + log_err(LD_BUG, "Couldn't create an evdns_base"); + return -1; + } + } + + evdns_base_clear_nameservers_and_suspend(the_evdns_base); + evdns_base_search_clear(the_evdns_base); + nameservers_configured = 0; + tor_free(resolv_conf_fname); + resolv_conf_mtime = 0; + } else { + if (configure_nameservers(0) < 0) { + return -1; + } + } + return 0; +} + +/** Return true iff the most recent attempt to initialize the DNS subsystem + * failed. */ +int +has_dns_init_failed(void) +{ + return nameserver_config_failed; +} + +/** Helper: Given a TTL from a DNS response, determine what TTL to give the + * OP that asked us to resolve it. */ +uint32_t +dns_clip_ttl(uint32_t ttl) +{ + if (ttl < MIN_DNS_TTL) + return MIN_DNS_TTL; + else if (ttl > MAX_DNS_TTL) + return MAX_DNS_TTL; + else + return ttl; +} + +/** Helper: Given a TTL from a DNS response, determine how long to hold it in + * our cache. */ +static uint32_t +dns_get_expiry_ttl(uint32_t ttl) +{ + if (ttl < MIN_DNS_TTL) + return MIN_DNS_TTL; + else if (ttl > MAX_DNS_ENTRY_AGE) + return MAX_DNS_ENTRY_AGE; + else + return ttl; +} + +/** Helper: free storage held by an entry in the DNS cache. */ +static void +free_cached_resolve_(cached_resolve_t *r) +{ + if (!r) + return; + while (r->pending_connections) { + pending_connection_t *victim = r->pending_connections; + r->pending_connections = victim->next; + tor_free(victim); + } + if (r->res_status_hostname == RES_STATUS_DONE_OK) + tor_free(r->result_ptr.hostname); + r->magic = 0xFF00FF00; + tor_free(r); +} + +/** Compare two cached_resolve_t pointers by expiry time, and return + * less-than-zero, zero, or greater-than-zero as appropriate. Used for + * the priority queue implementation. */ +static int +compare_cached_resolves_by_expiry_(const void *_a, const void *_b) +{ + const cached_resolve_t *a = _a, *b = _b; + if (a->expire < b->expire) + return -1; + else if (a->expire == b->expire) + return 0; + else + return 1; +} + +/** Priority queue of cached_resolve_t objects to let us know when they + * will expire. */ +static smartlist_t *cached_resolve_pqueue = NULL; + +static void +cached_resolve_add_answer(cached_resolve_t *resolve, + int query_type, + int dns_result, + const tor_addr_t *answer_addr, + const char *answer_hostname, + uint32_t ttl) +{ + if (query_type == DNS_PTR) { + if (resolve->res_status_hostname != RES_STATUS_INFLIGHT) + return; + + if (dns_result == DNS_ERR_NONE && answer_hostname) { + resolve->result_ptr.hostname = tor_strdup(answer_hostname); + resolve->res_status_hostname = RES_STATUS_DONE_OK; + } else { + resolve->result_ptr.err_hostname = dns_result; + resolve->res_status_hostname = RES_STATUS_DONE_ERR; + } + resolve->ttl_hostname = ttl; + } else if (query_type == DNS_IPv4_A) { + if (resolve->res_status_ipv4 != RES_STATUS_INFLIGHT) + return; + + if (dns_result == DNS_ERR_NONE && answer_addr && + tor_addr_family(answer_addr) == AF_INET) { + resolve->result_ipv4.addr_ipv4 = tor_addr_to_ipv4h(answer_addr); + resolve->res_status_ipv4 = RES_STATUS_DONE_OK; + } else { + resolve->result_ipv4.err_ipv4 = dns_result; + resolve->res_status_ipv4 = RES_STATUS_DONE_ERR; + } + + } else if (query_type == DNS_IPv6_AAAA) { + if (resolve->res_status_ipv6 != RES_STATUS_INFLIGHT) + return; + + if (dns_result == DNS_ERR_NONE && answer_addr && + tor_addr_family(answer_addr) == AF_INET6) { + memcpy(&resolve->result_ipv6.addr_ipv6, + tor_addr_to_in6(answer_addr), + sizeof(struct in6_addr)); + resolve->res_status_ipv6 = RES_STATUS_DONE_OK; + } else { + resolve->result_ipv6.err_ipv6 = dns_result; + resolve->res_status_ipv6 = RES_STATUS_DONE_ERR; + } + } +} + +/** Return true iff there are no in-flight requests for resolve. */ +static int +cached_resolve_have_all_answers(const cached_resolve_t *resolve) +{ + return (resolve->res_status_ipv4 != RES_STATUS_INFLIGHT && + resolve->res_status_ipv6 != RES_STATUS_INFLIGHT && + resolve->res_status_hostname != RES_STATUS_INFLIGHT); +} + +/** Set an expiry time for a cached_resolve_t, and add it to the expiry + * priority queue */ +static void +set_expiry(cached_resolve_t *resolve, time_t expires) +{ + tor_assert(resolve && resolve->expire == 0); + if (!cached_resolve_pqueue) + cached_resolve_pqueue = smartlist_new(); + resolve->expire = expires; + smartlist_pqueue_add(cached_resolve_pqueue, + compare_cached_resolves_by_expiry_, + STRUCT_OFFSET(cached_resolve_t, minheap_idx), + resolve); +} + +/** Free all storage held in the DNS cache and related structures. */ +void +dns_free_all(void) +{ + cached_resolve_t **ptr, **next, *item; + assert_cache_ok(); + if (cached_resolve_pqueue) { + SMARTLIST_FOREACH(cached_resolve_pqueue, cached_resolve_t *, res, + { + if (res->state == CACHE_STATE_DONE) + free_cached_resolve_(res); + }); + } + for (ptr = HT_START(cache_map, &cache_root); ptr != NULL; ptr = next) { + item = *ptr; + next = HT_NEXT_RMV(cache_map, &cache_root, ptr); + free_cached_resolve_(item); + } + HT_CLEAR(cache_map, &cache_root); + smartlist_free(cached_resolve_pqueue); + cached_resolve_pqueue = NULL; + tor_free(resolv_conf_fname); +} + +/** Remove every cached_resolve whose expire time is before or + * equal to now from the cache. */ +static void +purge_expired_resolves(time_t now) +{ + cached_resolve_t *resolve, *removed; + pending_connection_t *pend; + edge_connection_t *pendconn; + + assert_cache_ok(); + if (!cached_resolve_pqueue) + return; + + while (smartlist_len(cached_resolve_pqueue)) { + resolve = smartlist_get(cached_resolve_pqueue, 0); + if (resolve->expire > now) + break; + smartlist_pqueue_pop(cached_resolve_pqueue, + compare_cached_resolves_by_expiry_, + STRUCT_OFFSET(cached_resolve_t, minheap_idx)); + + if (resolve->state == CACHE_STATE_PENDING) { + log_debug(LD_EXIT, + "Expiring a dns resolve %s that's still pending. Forgot to " + "cull it? DNS resolve didn't tell us about the timeout?", + escaped_safe_str(resolve->address)); + } else if (resolve->state == CACHE_STATE_CACHED) { + log_debug(LD_EXIT, + "Forgetting old cached resolve (address %s, expires %lu)", + escaped_safe_str(resolve->address), + (unsigned long)resolve->expire); + tor_assert(!resolve->pending_connections); + } else { + tor_assert(resolve->state == CACHE_STATE_DONE); + tor_assert(!resolve->pending_connections); + } + + if (resolve->pending_connections) { + log_debug(LD_EXIT, + "Closing pending connections on timed-out DNS resolve!"); + while (resolve->pending_connections) { + pend = resolve->pending_connections; + resolve->pending_connections = pend->next; + /* Connections should only be pending if they have no socket. */ + tor_assert(!SOCKET_OK(pend->conn->base_.s)); + pendconn = pend->conn; + if (!pendconn->base_.marked_for_close) { + connection_edge_end(pendconn, END_STREAM_REASON_TIMEOUT); + circuit_detach_stream(circuit_get_by_edge_conn(pendconn), pendconn); + connection_free(TO_CONN(pendconn)); + } + tor_free(pend); + } + } + + if (resolve->state == CACHE_STATE_CACHED || + resolve->state == CACHE_STATE_PENDING) { + removed = HT_REMOVE(cache_map, &cache_root, resolve); + if (removed != resolve) { + log_err(LD_BUG, "The expired resolve we purged didn't match any in" + " the cache. Tried to purge %s (%p); instead got %s (%p).", + resolve->address, (void*)resolve, + removed ? removed->address : "NULL", (void*)removed); + } + tor_assert(removed == resolve); + } else { + /* This should be in state DONE. Make sure it's not in the cache. */ + cached_resolve_t *tmp = HT_FIND(cache_map, &cache_root, resolve); + tor_assert(tmp != resolve); + } + if (resolve->res_status_hostname == RES_STATUS_DONE_OK) + tor_free(resolve->result_ptr.hostname); + resolve->magic = 0xF0BBF0BB; + tor_free(resolve); + } + + assert_cache_ok(); +} + +/* argument for send_resolved_cell only, meaning "let the answer type be ipv4 + * or ipv6 depending on the connection's address". */ +#define RESOLVED_TYPE_AUTO 0xff + +/** Send a response to the RESOLVE request of a connection. + * answer_type must be one of + * RESOLVED_TYPE_(AUTO|ERROR|ERROR_TRANSIENT|). + * + * If circ is provided, and we have a cached answer, send the + * answer back along circ; otherwise, send the answer back along + * conn's attached circuit. + */ +static void +send_resolved_cell(edge_connection_t *conn, uint8_t answer_type, + const cached_resolve_t *resolved) +{ + char buf[RELAY_PAYLOAD_SIZE], *cp = buf; + size_t buflen = 0; + uint32_t ttl; + + buf[0] = answer_type; + ttl = dns_clip_ttl(conn->address_ttl); + + switch (answer_type) + { + case RESOLVED_TYPE_AUTO: + if (resolved && resolved->res_status_ipv4 == RES_STATUS_DONE_OK) { + cp[0] = RESOLVED_TYPE_IPV4; + cp[1] = 4; + set_uint32(cp+2, htonl(resolved->result_ipv4.addr_ipv4)); + set_uint32(cp+6, htonl(ttl)); + cp += 10; + } + if (resolved && resolved->res_status_ipv6 == RES_STATUS_DONE_OK) { + const uint8_t *bytes = resolved->result_ipv6.addr_ipv6.s6_addr; + cp[0] = RESOLVED_TYPE_IPV6; + cp[1] = 16; + memcpy(cp+2, bytes, 16); + set_uint32(cp+18, htonl(ttl)); + cp += 22; + } + if (cp != buf) { + buflen = cp - buf; + break; + } else { + answer_type = RESOLVED_TYPE_ERROR; + /* fall through. */ + } + case RESOLVED_TYPE_ERROR_TRANSIENT: + case RESOLVED_TYPE_ERROR: + { + const char *errmsg = "Error resolving hostname"; + size_t msglen = strlen(errmsg); + + buf[0] = answer_type; + buf[1] = msglen; + strlcpy(buf+2, errmsg, sizeof(buf)-2); + set_uint32(buf+2+msglen, htonl(ttl)); + buflen = 6+msglen; + break; + } + default: + tor_assert(0); + return; + } + // log_notice(LD_EXIT, "Sending a regular RESOLVED reply: "); + + connection_edge_send_command(conn, RELAY_COMMAND_RESOLVED, buf, buflen); +} + +/** Send a response to the RESOLVE request of a connection for an in-addr.arpa + * address on connection conn which yielded the result hostname. + * The answer type will be RESOLVED_HOSTNAME. + * + * If circ is provided, and we have a cached answer, send the + * answer back along circ; otherwise, send the answer back along + * conn's attached circuit. + */ +static void +send_resolved_hostname_cell(edge_connection_t *conn, const char *hostname) +{ + char buf[RELAY_PAYLOAD_SIZE]; + size_t buflen; + uint32_t ttl; + size_t namelen = strlen(hostname); + tor_assert(hostname); + + tor_assert(namelen < 256); + ttl = dns_clip_ttl(conn->address_ttl); + + buf[0] = RESOLVED_TYPE_HOSTNAME; + buf[1] = (uint8_t)namelen; + memcpy(buf+2, hostname, namelen); + set_uint32(buf+2+namelen, htonl(ttl)); + buflen = 2+namelen+4; + + // log_notice(LD_EXIT, "Sending a reply RESOLVED reply: %s", hostname); + connection_edge_send_command(conn, RELAY_COMMAND_RESOLVED, buf, buflen); + // log_notice(LD_EXIT, "Sent"); +} + +/** See if we have a cache entry for exitconn-\>address. If so, + * if resolve valid, put it into exitconn-\>addr and return 1. + * If resolve failed, free exitconn and return -1. + * + * (For EXIT_PURPOSE_RESOLVE connections, send back a RESOLVED error cell + * on returning -1. For EXIT_PURPOSE_CONNECT connections, there's no + * need to send back an END cell, since connection_exit_begin_conn will + * do that for us.) + * + * If we have a cached answer, send the answer back along exitconn's + * circuit. + * + * Else, if seen before and pending, add conn to the pending list, + * and return 0. + * + * Else, if not seen before, add conn to pending list, hand to + * dns farm, and return 0. + * + * Exitconn's on_circuit field must be set, but exitconn should not + * yet be linked onto the n_streams/resolving_streams list of that circuit. + * On success, link the connection to n_streams if it's an exit connection. + * On "pending", link the connection to resolving streams. Otherwise, + * clear its on_circuit field. + */ +int +dns_resolve(edge_connection_t *exitconn) +{ + or_circuit_t *oncirc = TO_OR_CIRCUIT(exitconn->on_circuit); + int is_resolve, r; + int made_connection_pending = 0; + char *hostname = NULL; + cached_resolve_t *resolve = NULL; + is_resolve = exitconn->base_.purpose == EXIT_PURPOSE_RESOLVE; + + r = dns_resolve_impl(exitconn, is_resolve, oncirc, &hostname, + &made_connection_pending, &resolve); + + switch (r) { + case 1: + /* We got an answer without a lookup -- either the answer was + * cached, or it was obvious (like an IP address). */ + if (is_resolve) { + /* Send the answer back right now, and detach. */ + if (hostname) + send_resolved_hostname_cell(exitconn, hostname); + else + send_resolved_cell(exitconn, RESOLVED_TYPE_AUTO, resolve); + exitconn->on_circuit = NULL; + } else { + /* Add to the n_streams list; the calling function will send back a + * connected cell. */ + exitconn->next_stream = oncirc->n_streams; + oncirc->n_streams = exitconn; + } + break; + case 0: + /* The request is pending: add the connection into the linked list of + * resolving_streams on this circuit. */ + exitconn->base_.state = EXIT_CONN_STATE_RESOLVING; + exitconn->next_stream = oncirc->resolving_streams; + oncirc->resolving_streams = exitconn; + break; + case -2: + case -1: + /* The request failed before it could start: cancel this connection, + * and stop everybody waiting for the same connection. */ + if (is_resolve) { + send_resolved_cell(exitconn, + (r == -1) ? RESOLVED_TYPE_ERROR : RESOLVED_TYPE_ERROR_TRANSIENT, + NULL); + } + + exitconn->on_circuit = NULL; + + dns_cancel_pending_resolve(exitconn->base_.address); + + if (!made_connection_pending && !exitconn->base_.marked_for_close) { + /* If we made the connection pending, then we freed it already in + * dns_cancel_pending_resolve(). If we marked it for close, it'll + * get freed from the main loop. Otherwise, can free it now. */ + connection_free(TO_CONN(exitconn)); + } + break; + default: + tor_assert(0); + } + + tor_free(hostname); + return r; +} + +/** Helper function for dns_resolve: same functionality, but does not handle: + * - marking connections on error and clearing their on_circuit + * - linking connections to n_streams/resolving_streams, + * - sending resolved cells if we have an answer/error right away, + * + * Return -2 on a transient error. If it's a reverse resolve and it's + * successful, sets *hostname_out to a newly allocated string + * holding the cached reverse DNS value. + * + * Set *made_connection_pending_out to true if we have placed + * exitconn on the list of pending connections for some resolve; set it + * to false otherwise. + * + * Set *resolve_out to a cached resolve, if we found one. + */ +static int +dns_resolve_impl(edge_connection_t *exitconn, int is_resolve, + or_circuit_t *oncirc, char **hostname_out, + int *made_connection_pending_out, + cached_resolve_t **resolve_out) +{ + cached_resolve_t *resolve; + cached_resolve_t search; + pending_connection_t *pending_connection; + int is_reverse = 0; + tor_addr_t addr; + time_t now = time(NULL); + int r; + assert_connection_ok(TO_CONN(exitconn), 0); + tor_assert(!SOCKET_OK(exitconn->base_.s)); + assert_cache_ok(); + tor_assert(oncirc); + *made_connection_pending_out = 0; + + /* first check if exitconn->base_.address is an IP. If so, we already + * know the answer. */ + if (tor_addr_parse(&addr, exitconn->base_.address) >= 0) { + if (tor_addr_family(&addr) == AF_INET || + tor_addr_family(&addr) == AF_INET6) { + tor_addr_copy(&exitconn->base_.addr, &addr); + exitconn->address_ttl = DEFAULT_DNS_TTL; + return 1; + } else { + /* XXXX unspec? Bogus? */ + return -1; + } + } + + /* If we're a non-exit, don't even do DNS lookups. */ + if (router_my_exit_policy_is_reject_star()) + return -1; + + if (address_is_invalid_destination(exitconn->base_.address, 0)) { + tor_log(LOG_PROTOCOL_WARN, LD_EXIT, + "Rejecting invalid destination address %s", + escaped_safe_str(exitconn->base_.address)); + return -1; + } + + /* then take this opportunity to see if there are any expired + * resolves in the hash table. */ + purge_expired_resolves(now); + + /* lower-case exitconn->base_.address, so it's in canonical form */ + tor_strlower(exitconn->base_.address); + + /* Check whether this is a reverse lookup. If it's malformed, or it's a + * .in-addr.arpa address but this isn't a resolve request, kill the + * connection. + */ + if ((r = tor_addr_parse_PTR_name(&addr, exitconn->base_.address, + AF_UNSPEC, 0)) != 0) { + if (r == 1) { + is_reverse = 1; + if (tor_addr_is_internal(&addr, 0)) /* internal address? */ + return -1; + } + + if (!is_reverse || !is_resolve) { + if (!is_reverse) + log_info(LD_EXIT, "Bad .in-addr.arpa address \"%s\"; sending error.", + escaped_safe_str(exitconn->base_.address)); + else if (!is_resolve) + log_info(LD_EXIT, + "Attempt to connect to a .in-addr.arpa address \"%s\"; " + "sending error.", + escaped_safe_str(exitconn->base_.address)); + + return -1; + } + //log_notice(LD_EXIT, "Looks like an address %s", + //exitconn->base_.address); + } + exitconn->is_reverse_dns_lookup = is_reverse; + + /* now check the hash table to see if 'address' is already there. */ + strlcpy(search.address, exitconn->base_.address, sizeof(search.address)); + resolve = HT_FIND(cache_map, &cache_root, &search); + if (resolve && resolve->expire > now) { /* already there */ + switch (resolve->state) { + case CACHE_STATE_PENDING: + /* add us to the pending list */ + pending_connection = tor_malloc_zero( + sizeof(pending_connection_t)); + pending_connection->conn = exitconn; + pending_connection->next = resolve->pending_connections; + resolve->pending_connections = pending_connection; + *made_connection_pending_out = 1; + log_debug(LD_EXIT,"Connection (fd "TOR_SOCKET_T_FORMAT") waiting " + "for pending DNS resolve of %s", exitconn->base_.s, + escaped_safe_str(exitconn->base_.address)); + return 0; + case CACHE_STATE_CACHED: + log_debug(LD_EXIT,"Connection (fd "TOR_SOCKET_T_FORMAT") found " + "cached answer for %s", + exitconn->base_.s, + escaped_safe_str(resolve->address)); + + *resolve_out = resolve; + + return set_exitconn_info_from_resolve(exitconn, resolve, hostname_out); + case CACHE_STATE_DONE: + log_err(LD_BUG, "Found a 'DONE' dns resolve still in the cache."); + tor_fragile_assert(); + } + tor_assert(0); + } + tor_assert(!resolve); + /* not there, need to add it */ + resolve = tor_malloc_zero(sizeof(cached_resolve_t)); + resolve->magic = CACHED_RESOLVE_MAGIC; + resolve->state = CACHE_STATE_PENDING; + resolve->minheap_idx = -1; + strlcpy(resolve->address, exitconn->base_.address, sizeof(resolve->address)); + + /* add this connection to the pending list */ + pending_connection = tor_malloc_zero(sizeof(pending_connection_t)); + pending_connection->conn = exitconn; + resolve->pending_connections = pending_connection; + *made_connection_pending_out = 1; + + /* Add this resolve to the cache and priority queue. */ + HT_INSERT(cache_map, &cache_root, resolve); + set_expiry(resolve, now + RESOLVE_MAX_TIMEOUT); + + log_debug(LD_EXIT,"Launching %s.", + escaped_safe_str(exitconn->base_.address)); + assert_cache_ok(); + + return launch_resolve(resolve); +} + +/** Given an exit connection exitconn, and a cached_resolve_t + * resolve whose DNS lookups have all succeeded or failed, update the + * appropriate fields (address_ttl and addr) of exitconn. + * + * If this is a reverse lookup, set *hostname_out to a newly allocated + * copy of the name resulting hostname. + * + * Return -2 on a transient error, -1 on a permenent error, and 1 on + * a successful lookup. + */ +static int +set_exitconn_info_from_resolve(edge_connection_t *exitconn, + const cached_resolve_t *resolve, + char **hostname_out) +{ + int ipv4_ok, ipv6_ok, answer_with_ipv4, r; + uint32_t begincell_flags; + const int is_resolve = exitconn->base_.purpose == EXIT_PURPOSE_RESOLVE; + tor_assert(exitconn); + tor_assert(resolve); + + if (exitconn->is_reverse_dns_lookup) { + exitconn->address_ttl = resolve->ttl_hostname; + if (resolve->res_status_hostname == RES_STATUS_DONE_OK) { + *hostname_out = tor_strdup(resolve->result_ptr.hostname); + return 1; + } else { + return -1; + } + } + + /* If we're here then the connection wants one or either of ipv4, ipv6, and + * we can give it one or both. */ + if (is_resolve) { + begincell_flags = BEGIN_FLAG_IPV6_OK; + } else { + begincell_flags = exitconn->begincell_flags; + } + + ipv4_ok = (resolve->res_status_ipv4 == RES_STATUS_DONE_OK) && + ! (begincell_flags & BEGIN_FLAG_IPV4_NOT_OK); + ipv6_ok = (resolve->res_status_ipv6 == RES_STATUS_DONE_OK) && + (begincell_flags & BEGIN_FLAG_IPV6_OK) && + get_options()->IPv6Exit; + + /* Now decide which one to actually give. */ + if (ipv4_ok && ipv6_ok && is_resolve) { + answer_with_ipv4 = 1; + } else if (ipv4_ok && ipv6_ok) { + /* If we have both, see if our exit policy has an opinion. */ + const uint16_t port = exitconn->base_.port; + int ipv4_allowed, ipv6_allowed; + tor_addr_t a4, a6; + tor_addr_from_ipv4h(&a4, resolve->result_ipv4.addr_ipv4); + tor_addr_from_in6(&a6, &resolve->result_ipv6.addr_ipv6); + ipv4_allowed = !router_compare_to_my_exit_policy(&a4, port); + ipv6_allowed = !router_compare_to_my_exit_policy(&a6, port); + if (ipv4_allowed && !ipv6_allowed) { + answer_with_ipv4 = 1; + } else if (ipv6_allowed && !ipv4_allowed) { + answer_with_ipv4 = 0; + } else { + /* Our exit policy would permit both. Answer with whichever the user + * prefers */ + answer_with_ipv4 = !(begincell_flags & + BEGIN_FLAG_IPV6_PREFERRED); + } + } else { + /* Otherwise if one is okay, send it back. */ + if (ipv4_ok) { + answer_with_ipv4 = 1; + } else if (ipv6_ok) { + answer_with_ipv4 = 0; + } else { + /* Neither one was okay. Choose based on user preference. */ + answer_with_ipv4 = !(begincell_flags & + BEGIN_FLAG_IPV6_PREFERRED); + } + } + + /* Finally, we write the answer back. */ + r = 1; + if (answer_with_ipv4) { + if (resolve->res_status_ipv4 == RES_STATUS_DONE_OK) { + tor_addr_from_ipv4h(&exitconn->base_.addr, + resolve->result_ipv4.addr_ipv4); + } else { + r = evdns_err_is_transient(resolve->result_ipv4.err_ipv4) ? -2 : -1; + } + + exitconn->address_ttl = resolve->ttl_ipv4; + } else { + if (resolve->res_status_ipv6 == RES_STATUS_DONE_OK) { + tor_addr_from_in6(&exitconn->base_.addr, + &resolve->result_ipv6.addr_ipv6); + } else { + r = evdns_err_is_transient(resolve->result_ipv6.err_ipv6) ? -2 : -1; + } + + exitconn->address_ttl = resolve->ttl_ipv6; + } + + return r; +} + +/** Log an error and abort if conn is waiting for a DNS resolve. + */ +void +assert_connection_edge_not_dns_pending(edge_connection_t *conn) +{ + pending_connection_t *pend; + cached_resolve_t search; + +#if 1 + cached_resolve_t *resolve; + strlcpy(search.address, conn->base_.address, sizeof(search.address)); + resolve = HT_FIND(cache_map, &cache_root, &search); + if (!resolve) + return; + for (pend = resolve->pending_connections; pend; pend = pend->next) { + tor_assert(pend->conn != conn); + } +#else + cached_resolve_t **resolve; + HT_FOREACH(resolve, cache_map, &cache_root) { + for (pend = (*resolve)->pending_connections; pend; pend = pend->next) { + tor_assert(pend->conn != conn); + } + } +#endif +} + +/** Log an error and abort if any connection waiting for a DNS resolve is + * corrupted. */ +void +assert_all_pending_dns_resolves_ok(void) +{ + pending_connection_t *pend; + cached_resolve_t **resolve; + + HT_FOREACH(resolve, cache_map, &cache_root) { + for (pend = (*resolve)->pending_connections; + pend; + pend = pend->next) { + assert_connection_ok(TO_CONN(pend->conn), 0); + tor_assert(!SOCKET_OK(pend->conn->base_.s)); + tor_assert(!connection_in_array(TO_CONN(pend->conn))); + } + } +} + +/** Remove conn from the list of connections waiting for conn-\>address. + */ +void +connection_dns_remove(edge_connection_t *conn) +{ + pending_connection_t *pend, *victim; + cached_resolve_t search; + cached_resolve_t *resolve; + + tor_assert(conn->base_.type == CONN_TYPE_EXIT); + tor_assert(conn->base_.state == EXIT_CONN_STATE_RESOLVING); + + strlcpy(search.address, conn->base_.address, sizeof(search.address)); + + resolve = HT_FIND(cache_map, &cache_root, &search); + if (!resolve) { + log_notice(LD_BUG, "Address %s is not pending. Dropping.", + escaped_safe_str(conn->base_.address)); + return; + } + + tor_assert(resolve->pending_connections); + assert_connection_ok(TO_CONN(conn),0); + + pend = resolve->pending_connections; + + if (pend->conn == conn) { + resolve->pending_connections = pend->next; + tor_free(pend); + log_debug(LD_EXIT, "First connection (fd "TOR_SOCKET_T_FORMAT") no " + "longer waiting for resolve of %s", + conn->base_.s, + escaped_safe_str(conn->base_.address)); + return; + } else { + for ( ; pend->next; pend = pend->next) { + if (pend->next->conn == conn) { + victim = pend->next; + pend->next = victim->next; + tor_free(victim); + log_debug(LD_EXIT, + "Connection (fd "TOR_SOCKET_T_FORMAT") no longer waiting " + "for resolve of %s", + conn->base_.s, escaped_safe_str(conn->base_.address)); + return; /* more are pending */ + } + } + tor_assert(0); /* not reachable unless onlyconn not in pending list */ + } +} + +/** Mark all connections waiting for address for close. Then cancel + * the resolve for address itself, and remove any cached results for + * address from the cache. + */ +void +dns_cancel_pending_resolve(const char *address) +{ + pending_connection_t *pend; + cached_resolve_t search; + cached_resolve_t *resolve, *tmp; + edge_connection_t *pendconn; + circuit_t *circ; + + strlcpy(search.address, address, sizeof(search.address)); + + resolve = HT_FIND(cache_map, &cache_root, &search); + if (!resolve) + return; + + if (resolve->state != CACHE_STATE_PENDING) { + /* We can get into this state if we never actually created the pending + * resolve, due to finding an earlier cached error or something. Just + * ignore it. */ + if (resolve->pending_connections) { + log_warn(LD_BUG, + "Address %s is not pending but has pending connections!", + escaped_safe_str(address)); + tor_fragile_assert(); + } + return; + } + + if (!resolve->pending_connections) { + log_warn(LD_BUG, + "Address %s is pending but has no pending connections!", + escaped_safe_str(address)); + tor_fragile_assert(); + return; + } + tor_assert(resolve->pending_connections); + + /* mark all pending connections to fail */ + log_debug(LD_EXIT, + "Failing all connections waiting on DNS resolve of %s", + escaped_safe_str(address)); + while (resolve->pending_connections) { + pend = resolve->pending_connections; + pend->conn->base_.state = EXIT_CONN_STATE_RESOLVEFAILED; + pendconn = pend->conn; + assert_connection_ok(TO_CONN(pendconn), 0); + tor_assert(!SOCKET_OK(pendconn->base_.s)); + if (!pendconn->base_.marked_for_close) { + connection_edge_end(pendconn, END_STREAM_REASON_RESOLVEFAILED); + } + circ = circuit_get_by_edge_conn(pendconn); + if (circ) + circuit_detach_stream(circ, pendconn); + if (!pendconn->base_.marked_for_close) + connection_free(TO_CONN(pendconn)); + resolve->pending_connections = pend->next; + tor_free(pend); + } + + tmp = HT_REMOVE(cache_map, &cache_root, resolve); + if (tmp != resolve) { + log_err(LD_BUG, "The cancelled resolve we purged didn't match any in" + " the cache. Tried to purge %s (%p); instead got %s (%p).", + resolve->address, (void*)resolve, + tmp ? tmp->address : "NULL", (void*)tmp); + } + tor_assert(tmp == resolve); + + resolve->state = CACHE_STATE_DONE; +} + +/** Return true iff address is one of the addresses we use to verify + * that well-known sites aren't being hijacked by our DNS servers. */ +static INLINE int +is_test_address(const char *address) +{ + const or_options_t *options = get_options(); + return options->ServerDNSTestAddresses && + smartlist_contains_string_case(options->ServerDNSTestAddresses, address); +} + +/** Called on the OR side when the eventdns library tells us the outcome of a + * single DNS resolve: remember the answer, and tell all pending connections + * about the result of the lookup if the lookup is now done. (address + * is a NUL-terminated string containing the address to look up; + * query_type is one of DNS_{IPv4_A,IPv6_AAAA,PTR}; dns_answer + * is DNS_OK or one of DNS_ERR_*, addr is an IPv4 or IPv6 address if we + * got one; hostname is a hostname fora PTR request if we got one, and + * ttl is the time-to-live of this answer, in seconds.) + */ +static void +dns_found_answer(const char *address, uint8_t query_type, + int dns_answer, + const tor_addr_t *addr, + const char *hostname, uint32_t ttl) +{ + cached_resolve_t search; + cached_resolve_t *resolve; + + assert_cache_ok(); + + strlcpy(search.address, address, sizeof(search.address)); + + resolve = HT_FIND(cache_map, &cache_root, &search); + if (!resolve) { + int is_test_addr = is_test_address(address); + if (!is_test_addr) + log_info(LD_EXIT,"Resolved unasked address %s; ignoring.", + escaped_safe_str(address)); + return; + } + assert_resolve_ok(resolve); + + if (resolve->state != CACHE_STATE_PENDING) { + /* XXXX Maybe update addr? or check addr for consistency? Or let + * VALID replace FAILED? */ + int is_test_addr = is_test_address(address); + if (!is_test_addr) + log_notice(LD_EXIT, + "Resolved %s which was already resolved; ignoring", + escaped_safe_str(address)); + tor_assert(resolve->pending_connections == NULL); + return; + } + + cached_resolve_add_answer(resolve, query_type, dns_answer, + addr, hostname, ttl); + + if (cached_resolve_have_all_answers(resolve)) { + inform_pending_connections(resolve); + + make_pending_resolve_cached(resolve); + } +} + +/** Given a pending cached_resolve_t that we just finished resolving, + * inform every connection that was waiting for the outcome of that + * resolution. */ +static void +inform_pending_connections(cached_resolve_t *resolve) +{ + pending_connection_t *pend; + edge_connection_t *pendconn; + int r; + + while (resolve->pending_connections) { + char *hostname = NULL; + pend = resolve->pending_connections; + pendconn = pend->conn; /* don't pass complex things to the + connection_mark_for_close macro */ + assert_connection_ok(TO_CONN(pendconn),time(NULL)); + + if (pendconn->base_.marked_for_close) { + /* prevent double-remove. */ + pendconn->base_.state = EXIT_CONN_STATE_RESOLVEFAILED; + resolve->pending_connections = pend->next; + tor_free(pend); + continue; + } + + r = set_exitconn_info_from_resolve(pendconn, + resolve, + &hostname); + + if (r < 0) { + /* prevent double-remove. */ + pendconn->base_.state = EXIT_CONN_STATE_RESOLVEFAILED; + if (pendconn->base_.purpose == EXIT_PURPOSE_CONNECT) { + connection_edge_end(pendconn, END_STREAM_REASON_RESOLVEFAILED); + /* This detach must happen after we send the end cell. */ + circuit_detach_stream(circuit_get_by_edge_conn(pendconn), pendconn); + } else { + send_resolved_cell(pendconn, r == -1 ? + RESOLVED_TYPE_ERROR : RESOLVED_TYPE_ERROR_TRANSIENT, + NULL); + /* This detach must happen after we send the resolved cell. */ + circuit_detach_stream(circuit_get_by_edge_conn(pendconn), pendconn); + } + connection_free(TO_CONN(pendconn)); + } else { + circuit_t *circ; + if (pendconn->base_.purpose == EXIT_PURPOSE_CONNECT) { + /* prevent double-remove. */ + pend->conn->base_.state = EXIT_CONN_STATE_CONNECTING; + + circ = circuit_get_by_edge_conn(pend->conn); + tor_assert(circ); + tor_assert(!CIRCUIT_IS_ORIGIN(circ)); + /* unlink pend->conn from resolving_streams, */ + circuit_detach_stream(circ, pend->conn); + /* and link it to n_streams */ + pend->conn->next_stream = TO_OR_CIRCUIT(circ)->n_streams; + pend->conn->on_circuit = circ; + TO_OR_CIRCUIT(circ)->n_streams = pend->conn; + + connection_exit_connect(pend->conn); + } else { + /* prevent double-remove. This isn't really an accurate state, + * but it does the right thing. */ + pendconn->base_.state = EXIT_CONN_STATE_RESOLVEFAILED; + if (pendconn->is_reverse_dns_lookup) + send_resolved_hostname_cell(pendconn, hostname); + else + send_resolved_cell(pendconn, RESOLVED_TYPE_AUTO, resolve); + circ = circuit_get_by_edge_conn(pendconn); + tor_assert(circ); + circuit_detach_stream(circ, pendconn); + connection_free(TO_CONN(pendconn)); + } + } + resolve->pending_connections = pend->next; + tor_free(pend); + } +} + +/** Remove a pending cached_resolve_t from the hashtable, and add a + * corresponding cached cached_resolve_t. + * + * This function is only necessary because of the perversity of our + * cache timeout code; see inline comment for ideas on eliminating it. + **/ +static void +make_pending_resolve_cached(cached_resolve_t *resolve) +{ + cached_resolve_t *removed; + + resolve->state = CACHE_STATE_DONE; + removed = HT_REMOVE(cache_map, &cache_root, resolve); + if (removed != resolve) { + log_err(LD_BUG, "The pending resolve we found wasn't removable from" + " the cache. Tried to purge %s (%p); instead got %s (%p).", + resolve->address, (void*)resolve, + removed ? removed->address : "NULL", (void*)removed); + } + assert_resolve_ok(resolve); + assert_cache_ok(); + /* The resolve will eventually just hit the time-out in the expiry queue and + * expire. See fd0bafb0dedc7e2 for a brief explanation of how this got that + * way. XXXXX we could do better!*/ + + { + cached_resolve_t *new_resolve = tor_memdup(resolve, + sizeof(cached_resolve_t)); + uint32_t ttl = UINT32_MAX; + new_resolve->expire = 0; /* So that set_expiry won't croak. */ + if (resolve->res_status_hostname == RES_STATUS_DONE_OK) + new_resolve->result_ptr.hostname = + tor_strdup(resolve->result_ptr.hostname); + + new_resolve->state = CACHE_STATE_CACHED; + + assert_resolve_ok(new_resolve); + HT_INSERT(cache_map, &cache_root, new_resolve); + + if ((resolve->res_status_ipv4 == RES_STATUS_DONE_OK || + resolve->res_status_ipv4 == RES_STATUS_DONE_ERR) && + resolve->ttl_ipv4 < ttl) + ttl = resolve->ttl_ipv4; + + if ((resolve->res_status_ipv6 == RES_STATUS_DONE_OK || + resolve->res_status_ipv6 == RES_STATUS_DONE_ERR) && + resolve->ttl_ipv6 < ttl) + ttl = resolve->ttl_ipv6; + + if ((resolve->res_status_hostname == RES_STATUS_DONE_OK || + resolve->res_status_hostname == RES_STATUS_DONE_ERR) && + resolve->ttl_hostname < ttl) + ttl = resolve->ttl_hostname; + + set_expiry(new_resolve, time(NULL) + dns_get_expiry_ttl(ttl)); + } + + assert_cache_ok(); +} + +/** Eventdns helper: return true iff the eventdns result err is + * a transient failure. */ +static int +evdns_err_is_transient(int err) +{ + switch (err) + { + case DNS_ERR_SERVERFAILED: + case DNS_ERR_TRUNCATED: + case DNS_ERR_TIMEOUT: + return 1; + default: + return 0; + } +} + +/** Configure eventdns nameservers if force is true, or if the configuration + * has changed since the last time we called this function, or if we failed on + * our last attempt. On Unix, this reads from /etc/resolv.conf or + * options->ServerDNSResolvConfFile; on Windows, this reads from + * options->ServerDNSResolvConfFile or the registry. Return 0 on success or + * -1 on failure. */ +static int +configure_nameservers(int force) +{ + const or_options_t *options; + const char *conf_fname; + struct stat st; + int r, flags; + options = get_options(); + conf_fname = options->ServerDNSResolvConfFile; +#ifndef _WIN32 + if (!conf_fname) + conf_fname = "/etc/resolv.conf"; +#endif + flags = DNS_OPTIONS_ALL; + + if (!the_evdns_base) { + if (!(the_evdns_base = evdns_base_new(tor_libevent_get_base(), 0))) { + log_err(LD_BUG, "Couldn't create an evdns_base"); + return -1; + } + } + +#ifdef HAVE_EVDNS_SET_DEFAULT_OUTGOING_BIND_ADDRESS + if (! tor_addr_is_null(&options->OutboundBindAddressIPv4_)) { + int socklen; + struct sockaddr_storage ss; + socklen = tor_addr_to_sockaddr(&options->OutboundBindAddressIPv4_, 0, + (struct sockaddr *)&ss, sizeof(ss)); + if (socklen <= 0) { + log_warn(LD_BUG, "Couldn't convert outbound bind address to sockaddr." + " Ignoring."); + } else { + evdns_base_set_default_outgoing_bind_address(the_evdns_base, + (struct sockaddr *)&ss, + socklen); + } + } +#endif + + evdns_set_log_fn(evdns_log_cb); + if (conf_fname) { + if (stat(sandbox_intern_string(conf_fname), &st)) { + log_warn(LD_EXIT, "Unable to stat resolver configuration in '%s': %s", + conf_fname, strerror(errno)); + goto err; + } + if (!force && resolv_conf_fname && !strcmp(conf_fname,resolv_conf_fname) + && st.st_mtime == resolv_conf_mtime) { + log_info(LD_EXIT, "No change to '%s'", conf_fname); + return 0; + } + if (nameservers_configured) { + evdns_base_search_clear(the_evdns_base); + evdns_base_clear_nameservers_and_suspend(the_evdns_base); + } +#if defined(DNS_OPTION_HOSTSFILE) && defined(USE_LIBSECCOMP) + if (flags & DNS_OPTION_HOSTSFILE) { + flags ^= DNS_OPTION_HOSTSFILE; + evdns_base_load_hosts(the_evdns_base, + sandbox_intern_string("/etc/hosts")); + } +#endif + log_info(LD_EXIT, "Parsing resolver configuration in '%s'", conf_fname); + if ((r = evdns_base_resolv_conf_parse(the_evdns_base, flags, + sandbox_intern_string(conf_fname)))) { + log_warn(LD_EXIT, "Unable to parse '%s', or no nameservers in '%s' (%d)", + conf_fname, conf_fname, r); + goto err; + } + if (evdns_base_count_nameservers(the_evdns_base) == 0) { + log_warn(LD_EXIT, "Unable to find any nameservers in '%s'.", conf_fname); + goto err; + } + tor_free(resolv_conf_fname); + resolv_conf_fname = tor_strdup(conf_fname); + resolv_conf_mtime = st.st_mtime; + if (nameservers_configured) + evdns_base_resume(the_evdns_base); + } +#ifdef _WIN32 + else { + if (nameservers_configured) { + evdns_base_search_clear(the_evdns_base); + evdns_base_clear_nameservers_and_suspend(the_evdns_base); + } + if (evdns_base_config_windows_nameservers(the_evdns_base)) { + log_warn(LD_EXIT,"Could not config nameservers."); + goto err; + } + if (evdns_base_count_nameservers(the_evdns_base) == 0) { + log_warn(LD_EXIT, "Unable to find any platform nameservers in " + "your Windows configuration."); + goto err; + } + if (nameservers_configured) + evdns_base_resume(the_evdns_base); + tor_free(resolv_conf_fname); + resolv_conf_mtime = 0; + } +#endif + +#define SET(k,v) evdns_base_set_option_(the_evdns_base, (k), (v)) + + if (evdns_base_count_nameservers(the_evdns_base) == 1) { + SET("max-timeouts:", "16"); + SET("timeout:", "10"); + } else { + SET("max-timeouts:", "3"); + SET("timeout:", "5"); + } + + if (options->ServerDNSRandomizeCase) + SET("randomize-case:", "1"); + else + SET("randomize-case:", "0"); + +#undef SET + + dns_servers_relaunch_checks(); + + nameservers_configured = 1; + if (nameserver_config_failed) { + nameserver_config_failed = 0; + /* XXX the three calls to republish the descriptor might be producing + * descriptors that are only cosmetically different, especially on + * non-exit relays! -RD */ + mark_my_descriptor_dirty("dns resolvers back"); + } + return 0; + err: + nameservers_configured = 0; + if (! nameserver_config_failed) { + nameserver_config_failed = 1; + mark_my_descriptor_dirty("dns resolvers failed"); + } + return -1; +} + +/** For eventdns: Called when we get an answer for a request we launched. + * See eventdns.h for arguments; 'arg' holds the address we tried to resolve. + */ +static void +evdns_callback(int result, char type, int count, int ttl, void *addresses, + void *arg) +{ + char *arg_ = arg; + uint8_t orig_query_type = arg_[0]; + char *string_address = arg_ + 1; + tor_addr_t addr; + const char *hostname = NULL; + int was_wildcarded = 0; + + tor_addr_make_unspec(&addr); + + /* Keep track of whether IPv6 is working */ + if (type == DNS_IPv6_AAAA) { + if (result == DNS_ERR_TIMEOUT) { + ++n_ipv6_timeouts; + } + + if (n_ipv6_timeouts > 10 && + n_ipv6_timeouts > n_ipv6_requests_made / 2) { + if (! dns_is_broken_for_ipv6) { + log_notice(LD_EXIT, "More than half of our IPv6 requests seem to " + "have timed out. I'm going to assume I can't get AAAA " + "responses."); + dns_is_broken_for_ipv6 = 1; + } + } + } + + if (result == DNS_ERR_NONE) { + if (type == DNS_IPv4_A && count) { + char answer_buf[INET_NTOA_BUF_LEN+1]; + char *escaped_address; + uint32_t *addrs = addresses; + tor_addr_from_ipv4n(&addr, addrs[0]); + + tor_addr_to_str(answer_buf, &addr, sizeof(answer_buf), 0); + escaped_address = esc_for_log(string_address); + + if (answer_is_wildcarded(answer_buf)) { + log_debug(LD_EXIT, "eventdns said that %s resolves to ISP-hijacked " + "address %s; treating as a failure.", + safe_str(escaped_address), + escaped_safe_str(answer_buf)); + was_wildcarded = 1; + tor_addr_make_unspec(&addr); + result = DNS_ERR_NOTEXIST; + } else { + log_debug(LD_EXIT, "eventdns said that %s resolves to %s", + safe_str(escaped_address), + escaped_safe_str(answer_buf)); + } + tor_free(escaped_address); + } else if (type == DNS_IPv6_AAAA && count) { + char answer_buf[TOR_ADDR_BUF_LEN]; + char *escaped_address; + struct in6_addr *addrs = addresses; + tor_addr_from_in6(&addr, &addrs[0]); + tor_inet_ntop(AF_INET6, &addrs[0], answer_buf, sizeof(answer_buf)); + escaped_address = esc_for_log(string_address); + + if (answer_is_wildcarded(answer_buf)) { + log_debug(LD_EXIT, "eventdns said that %s resolves to ISP-hijacked " + "address %s; treating as a failure.", + safe_str(escaped_address), + escaped_safe_str(answer_buf)); + was_wildcarded = 1; + tor_addr_make_unspec(&addr); + result = DNS_ERR_NOTEXIST; + } else { + log_debug(LD_EXIT, "eventdns said that %s resolves to %s", + safe_str(escaped_address), + escaped_safe_str(answer_buf)); + } + tor_free(escaped_address); + } else if (type == DNS_PTR && count) { + char *escaped_address; + hostname = ((char**)addresses)[0]; + escaped_address = esc_for_log(string_address); + log_debug(LD_EXIT, "eventdns said that %s resolves to %s", + safe_str(escaped_address), + escaped_safe_str(hostname)); + tor_free(escaped_address); + } else if (count) { + log_warn(LD_EXIT, "eventdns returned only non-IPv4 answers for %s.", + escaped_safe_str(string_address)); + } else { + log_warn(LD_BUG, "eventdns returned no addresses or error for %s!", + escaped_safe_str(string_address)); + } + } + if (was_wildcarded) { + if (is_test_address(string_address)) { + /* Ick. We're getting redirected on known-good addresses. Our DNS + * server must really hate us. */ + add_wildcarded_test_address(string_address); + } + } + + if (orig_query_type && type && orig_query_type != type) { + log_warn(LD_BUG, "Weird; orig_query_type == %d but type == %d", + (int)orig_query_type, (int)type); + } + if (result != DNS_ERR_SHUTDOWN) + dns_found_answer(string_address, orig_query_type, + result, &addr, hostname, ttl); + + tor_free(arg_); +} + +/** Start a single DNS resolve for address (if query_type is + * DNS_IPv4_A or DNS_IPv6_AAAA) ptr_address (if query_type is + * DNS_PTR). Return 0 if we launched the request, -1 otherwise. */ +static int +launch_one_resolve(const char *address, uint8_t query_type, + const tor_addr_t *ptr_address) +{ + const int options = get_options()->ServerDNSSearchDomains ? 0 + : DNS_QUERY_NO_SEARCH; + const size_t addr_len = strlen(address); + struct evdns_request *req = 0; + char *addr = tor_malloc(addr_len + 2); + addr[0] = (char) query_type; + memcpy(addr+1, address, addr_len + 1); + + switch (query_type) { + case DNS_IPv4_A: + req = evdns_base_resolve_ipv4(the_evdns_base, + address, options, evdns_callback, addr); + break; + case DNS_IPv6_AAAA: + req = evdns_base_resolve_ipv6(the_evdns_base, + address, options, evdns_callback, addr); + ++n_ipv6_requests_made; + break; + case DNS_PTR: + if (tor_addr_family(ptr_address) == AF_INET) + req = evdns_base_resolve_reverse(the_evdns_base, + tor_addr_to_in(ptr_address), + DNS_QUERY_NO_SEARCH, + evdns_callback, addr); + else if (tor_addr_family(ptr_address) == AF_INET6) + req = evdns_base_resolve_reverse_ipv6(the_evdns_base, + tor_addr_to_in6(ptr_address), + DNS_QUERY_NO_SEARCH, + evdns_callback, addr); + else + log_warn(LD_BUG, "Called with PTR query and unexpected address family"); + break; + default: + log_warn(LD_BUG, "Called with unexpectd query type %d", (int)query_type); + break; + } + + if (req) { + return 0; + } else { + tor_free(addr); + return -1; + } +} + +/** For eventdns: start resolving as necessary to find the target for + * exitconn. Returns -1 on error, -2 on transient error, + * 0 on "resolve launched." */ +static int +launch_resolve(cached_resolve_t *resolve) +{ + tor_addr_t a; + int r; + + if (get_options()->DisableNetwork) + return -1; + + /* What? Nameservers not configured? Sounds like a bug. */ + if (!nameservers_configured) { + log_warn(LD_EXIT, "(Harmless.) Nameservers not configured, but resolve " + "launched. Configuring."); + if (configure_nameservers(1) < 0) { + return -1; + } + } + + r = tor_addr_parse_PTR_name( + &a, resolve->address, AF_UNSPEC, 0); + + tor_assert(the_evdns_base); + if (r == 0) { + log_info(LD_EXIT, "Launching eventdns request for %s", + escaped_safe_str(resolve->address)); + resolve->res_status_ipv4 = RES_STATUS_INFLIGHT; + if (get_options()->IPv6Exit) + resolve->res_status_ipv6 = RES_STATUS_INFLIGHT; + + if (launch_one_resolve(resolve->address, DNS_IPv4_A, NULL) < 0) { + resolve->res_status_ipv4 = 0; + r = -1; + } + + if (r==0 && get_options()->IPv6Exit) { + /* We ask for an IPv6 address for *everything*. */ + if (launch_one_resolve(resolve->address, DNS_IPv6_AAAA, NULL) < 0) { + resolve->res_status_ipv6 = 0; + r = -1; + } + } + } else if (r == 1) { + r = 0; + log_info(LD_EXIT, "Launching eventdns reverse request for %s", + escaped_safe_str(resolve->address)); + resolve->res_status_hostname = RES_STATUS_INFLIGHT; + if (launch_one_resolve(resolve->address, DNS_PTR, &a) < 0) { + resolve->res_status_hostname = 0; + r = -1; + } + } else if (r == -1) { + log_warn(LD_BUG, "Somehow a malformed in-addr.arpa address reached here."); + } + + if (r < 0) { + log_fn(LOG_PROTOCOL_WARN, LD_EXIT, "eventdns rejected address %s.", + escaped_safe_str(resolve->address)); + } + return r; +} + +/** How many requests for bogus addresses have we launched so far? */ +static int n_wildcard_requests = 0; + +/** Map from dotted-quad IP address in response to an int holding how many + * times we've seen it for a randomly generated (hopefully bogus) address. It + * would be easier to use definitely-invalid addresses (as specified by + * RFC2606), but see comment in dns_launch_wildcard_checks(). */ +static strmap_t *dns_wildcard_response_count = NULL; + +/** If present, a list of dotted-quad IP addresses that we are pretty sure our + * nameserver wants to return in response to requests for nonexistent domains. + */ +static smartlist_t *dns_wildcard_list = NULL; +/** True iff we've logged about a single address getting wildcarded. + * Subsequent warnings will be less severe. */ +static int dns_wildcard_one_notice_given = 0; +/** True iff we've warned that our DNS server is wildcarding too many failures. + */ +static int dns_wildcard_notice_given = 0; + +/** List of supposedly good addresses that are getting wildcarded to the + * same addresses as nonexistent addresses. */ +static smartlist_t *dns_wildcarded_test_address_list = NULL; +/** True iff we've warned about a test address getting wildcarded */ +static int dns_wildcarded_test_address_notice_given = 0; +/** True iff all addresses seem to be getting wildcarded. */ +static int dns_is_completely_invalid = 0; + +/** Called when we see id (a dotted quad or IPv6 address) in response + * to a request for a hopefully bogus address. */ +static void +wildcard_increment_answer(const char *id) +{ + int *ip; + if (!dns_wildcard_response_count) + dns_wildcard_response_count = strmap_new(); + + ip = strmap_get(dns_wildcard_response_count, id); // may be null (0) + if (!ip) { + ip = tor_malloc_zero(sizeof(int)); + strmap_set(dns_wildcard_response_count, id, ip); + } + ++*ip; + + if (*ip > 5 && n_wildcard_requests > 10) { + if (!dns_wildcard_list) dns_wildcard_list = smartlist_new(); + if (!smartlist_contains_string(dns_wildcard_list, id)) { + tor_log(dns_wildcard_notice_given ? LOG_INFO : LOG_NOTICE, LD_EXIT, + "Your DNS provider has given \"%s\" as an answer for %d different " + "invalid addresses. Apparently they are hijacking DNS failures. " + "I'll try to correct for this by treating future occurrences of " + "\"%s\" as 'not found'.", id, *ip, id); + smartlist_add(dns_wildcard_list, tor_strdup(id)); + } + if (!dns_wildcard_notice_given) + control_event_server_status(LOG_NOTICE, "DNS_HIJACKED"); + dns_wildcard_notice_given = 1; + } +} + +/** Note that a single test address (one believed to be good) seems to be + * getting redirected to the same IP as failures are. */ +static void +add_wildcarded_test_address(const char *address) +{ + int n, n_test_addrs; + if (!dns_wildcarded_test_address_list) + dns_wildcarded_test_address_list = smartlist_new(); + + if (smartlist_contains_string_case(dns_wildcarded_test_address_list, + address)) + return; + + n_test_addrs = get_options()->ServerDNSTestAddresses ? + smartlist_len(get_options()->ServerDNSTestAddresses) : 0; + + smartlist_add(dns_wildcarded_test_address_list, tor_strdup(address)); + n = smartlist_len(dns_wildcarded_test_address_list); + if (n > n_test_addrs/2) { + tor_log(dns_wildcarded_test_address_notice_given ? LOG_INFO : LOG_NOTICE, + LD_EXIT, "Your DNS provider tried to redirect \"%s\" to a junk " + "address. It has done this with %d test addresses so far. I'm " + "going to stop being an exit node for now, since our DNS seems so " + "broken.", address, n); + if (!dns_is_completely_invalid) { + dns_is_completely_invalid = 1; + mark_my_descriptor_dirty("dns hijacking confirmed"); + } + if (!dns_wildcarded_test_address_notice_given) + control_event_server_status(LOG_WARN, "DNS_USELESS"); + dns_wildcarded_test_address_notice_given = 1; + } +} + +/** Callback function when we get an answer (possibly failing) for a request + * for a (hopefully) nonexistent domain. */ +static void +evdns_wildcard_check_callback(int result, char type, int count, int ttl, + void *addresses, void *arg) +{ + (void)ttl; + ++n_wildcard_requests; + if (result == DNS_ERR_NONE && count) { + char *string_address = arg; + int i; + if (type == DNS_IPv4_A) { + const uint32_t *addrs = addresses; + for (i = 0; i < count; ++i) { + char answer_buf[INET_NTOA_BUF_LEN+1]; + struct in_addr in; + in.s_addr = addrs[i]; + tor_inet_ntoa(&in, answer_buf, sizeof(answer_buf)); + wildcard_increment_answer(answer_buf); + } + } else if (type == DNS_IPv6_AAAA) { + const struct in6_addr *addrs = addresses; + for (i = 0; i < count; ++i) { + char answer_buf[TOR_ADDR_BUF_LEN+1]; + tor_inet_ntop(AF_INET6, &addrs[i], answer_buf, sizeof(answer_buf)); + wildcard_increment_answer(answer_buf); + } + } + + tor_log(dns_wildcard_one_notice_given ? LOG_INFO : LOG_NOTICE, LD_EXIT, + "Your DNS provider gave an answer for \"%s\", which " + "is not supposed to exist. Apparently they are hijacking " + "DNS failures. Trying to correct for this. We've noticed %d " + "possibly bad address%s so far.", + string_address, strmap_size(dns_wildcard_response_count), + (strmap_size(dns_wildcard_response_count) == 1) ? "" : "es"); + dns_wildcard_one_notice_given = 1; + } + tor_free(arg); +} + +/** Launch a single request for a nonexistent hostname consisting of between + * min_len and max_len random (plausible) characters followed by + * suffix */ +static void +launch_wildcard_check(int min_len, int max_len, int is_ipv6, + const char *suffix) +{ + char *addr; + struct evdns_request *req; + + addr = crypto_random_hostname(min_len, max_len, "", suffix); + log_info(LD_EXIT, "Testing whether our DNS server is hijacking nonexistent " + "domains with request for bogus hostname \"%s\"", addr); + + tor_assert(the_evdns_base); + if (is_ipv6) + req = evdns_base_resolve_ipv6( + the_evdns_base, + /* This "addr" tells us which address to resolve */ + addr, + DNS_QUERY_NO_SEARCH, evdns_wildcard_check_callback, + /* This "addr" is an argument to the callback*/ addr); + else + req = evdns_base_resolve_ipv4( + the_evdns_base, + /* This "addr" tells us which address to resolve */ + addr, + DNS_QUERY_NO_SEARCH, evdns_wildcard_check_callback, + /* This "addr" is an argument to the callback*/ addr); + if (!req) { + /* There is no evdns request in progress; stop addr from getting leaked */ + tor_free(addr); + } +} + +/** Launch attempts to resolve a bunch of known-good addresses (configured in + * ServerDNSTestAddresses). [Callback for a libevent timer] */ +static void +launch_test_addresses(evutil_socket_t fd, short event, void *args) +{ + const or_options_t *options = get_options(); + (void)fd; + (void)event; + (void)args; + + if (options->DisableNetwork) + return; + + log_info(LD_EXIT, "Launching checks to see whether our nameservers like to " + "hijack *everything*."); + /* This situation is worse than the failure-hijacking situation. When this + * happens, we're no good for DNS requests at all, and we shouldn't really + * be an exit server.*/ + if (options->ServerDNSTestAddresses) { + + tor_assert(the_evdns_base); + SMARTLIST_FOREACH_BEGIN(options->ServerDNSTestAddresses, + const char *, address) { + if (launch_one_resolve(address, DNS_IPv4_A, NULL) < 0) { + log_info(LD_EXIT, "eventdns rejected test address %s", + escaped_safe_str(address)); + } + + if (launch_one_resolve(address, DNS_IPv6_AAAA, NULL) < 0) { + log_info(LD_EXIT, "eventdns rejected test address %s", + escaped_safe_str(address)); + } + } SMARTLIST_FOREACH_END(address); + } +} + +#define N_WILDCARD_CHECKS 2 + +/** Launch DNS requests for a few nonexistent hostnames and a few well-known + * hostnames, and see if we can catch our nameserver trying to hijack them and + * map them to a stupid "I couldn't find ggoogle.com but maybe you'd like to + * buy these lovely encyclopedias" page. */ +static void +dns_launch_wildcard_checks(void) +{ + int i, ipv6; + log_info(LD_EXIT, "Launching checks to see whether our nameservers like " + "to hijack DNS failures."); + for (ipv6 = 0; ipv6 <= 1; ++ipv6) { + for (i = 0; i < N_WILDCARD_CHECKS; ++i) { + /* RFC2606 reserves these. Sadly, some DNS hijackers, in a silly + * attempt to 'comply' with rfc2606, refrain from giving A records for + * these. This is the standards-compliance equivalent of making sure + * that your crackhouse's elevator inspection certificate is up to date. + */ + launch_wildcard_check(2, 16, ipv6, ".invalid"); + launch_wildcard_check(2, 16, ipv6, ".test"); + + /* These will break specs if there are ever any number of + * 8+-character top-level domains. */ + launch_wildcard_check(8, 16, ipv6, ""); + + /* Try some random .com/org/net domains. This will work fine so long as + * not too many resolve to the same place. */ + launch_wildcard_check(8, 16, ipv6, ".com"); + launch_wildcard_check(8, 16, ipv6, ".org"); + launch_wildcard_check(8, 16, ipv6, ".net"); + } + } +} + +/** If appropriate, start testing whether our DNS servers tend to lie to + * us. */ +void +dns_launch_correctness_checks(void) +{ + static struct event *launch_event = NULL; + struct timeval timeout; + if (!get_options()->ServerDNSDetectHijacking) + return; + dns_launch_wildcard_checks(); + + /* Wait a while before launching requests for test addresses, so we can + * get the results from checking for wildcarding. */ + if (! launch_event) + launch_event = tor_evtimer_new(tor_libevent_get_base(), + launch_test_addresses, NULL); + timeout.tv_sec = 30; + timeout.tv_usec = 0; + if (evtimer_add(launch_event, &timeout)<0) { + log_warn(LD_BUG, "Couldn't add timer for checking for dns hijacking"); + } +} + +/** Return true iff our DNS servers lie to us too much to be trusted. */ +int +dns_seems_to_be_broken(void) +{ + return dns_is_completely_invalid; +} + +/** Return true iff we think that IPv6 hostname lookup is broken */ +int +dns_seems_to_be_broken_for_ipv6(void) +{ + return dns_is_broken_for_ipv6; +} + +/** Forget what we've previously learned about our DNS servers' correctness. */ +void +dns_reset_correctness_checks(void) +{ + strmap_free(dns_wildcard_response_count, tor_free_); + dns_wildcard_response_count = NULL; + + n_wildcard_requests = 0; + + n_ipv6_requests_made = n_ipv6_timeouts = 0; + + if (dns_wildcard_list) { + SMARTLIST_FOREACH(dns_wildcard_list, char *, cp, tor_free(cp)); + smartlist_clear(dns_wildcard_list); + } + if (dns_wildcarded_test_address_list) { + SMARTLIST_FOREACH(dns_wildcarded_test_address_list, char *, cp, + tor_free(cp)); + smartlist_clear(dns_wildcarded_test_address_list); + } + dns_wildcard_one_notice_given = dns_wildcard_notice_given = + dns_wildcarded_test_address_notice_given = dns_is_completely_invalid = + dns_is_broken_for_ipv6 = 0; +} + +/** Return true iff we have noticed that the dotted-quad ip has been + * returned in response to requests for nonexistent hostnames. */ +static int +answer_is_wildcarded(const char *ip) +{ + return dns_wildcard_list && smartlist_contains_string(dns_wildcard_list, ip); +} + +/** Exit with an assertion if resolve is corrupt. */ +static void +assert_resolve_ok(cached_resolve_t *resolve) +{ + tor_assert(resolve); + tor_assert(resolve->magic == CACHED_RESOLVE_MAGIC); + tor_assert(strlen(resolve->address) < MAX_ADDRESSLEN); + tor_assert(tor_strisnonupper(resolve->address)); + if (resolve->state != CACHE_STATE_PENDING) { + tor_assert(!resolve->pending_connections); + } + if (resolve->state == CACHE_STATE_PENDING || + resolve->state == CACHE_STATE_DONE) { +#if 0 + tor_assert(!resolve->ttl); + if (resolve->is_reverse) + tor_assert(!resolve->hostname); + else + tor_assert(!resolve->result_ipv4.addr_ipv4); +#endif + /*XXXXX ADD MORE */ + } +} + +/** Return the number of DNS cache entries as an int */ +static int +dns_cache_entry_count(void) +{ + return HT_SIZE(&cache_root); +} + +/** Log memory information about our internal DNS cache at level 'severity'. */ +void +dump_dns_mem_usage(int severity) +{ + /* This should never be larger than INT_MAX. */ + int hash_count = dns_cache_entry_count(); + size_t hash_mem = sizeof(struct cached_resolve_t) * hash_count; + hash_mem += HT_MEM_USAGE(&cache_root); + + /* Print out the count and estimated size of our &cache_root. It undercounts + hostnames in cached reverse resolves. + */ + tor_log(severity, LD_MM, "Our DNS cache has %d entries.", hash_count); + tor_log(severity, LD_MM, "Our DNS cache size is approximately %u bytes.", + (unsigned)hash_mem); +} + +#ifdef DEBUG_DNS_CACHE +/** Exit with an assertion if the DNS cache is corrupt. */ +static void +assert_cache_ok_(void) +{ + cached_resolve_t **resolve; + int bad_rep = _cache_map_HT_REP_IS_BAD(&cache_root); + if (bad_rep) { + log_err(LD_BUG, "Bad rep type %d on dns cache hash table", bad_rep); + tor_assert(!bad_rep); + } + + HT_FOREACH(resolve, cache_map, &cache_root) { + assert_resolve_ok(*resolve); + tor_assert((*resolve)->state != CACHE_STATE_DONE); + } + if (!cached_resolve_pqueue) + return; + + smartlist_pqueue_assert_ok(cached_resolve_pqueue, + compare_cached_resolves_by_expiry_, + STRUCT_OFFSET(cached_resolve_t, minheap_idx)); + + SMARTLIST_FOREACH(cached_resolve_pqueue, cached_resolve_t *, res, + { + if (res->state == CACHE_STATE_DONE) { + cached_resolve_t *found = HT_FIND(cache_map, &cache_root, res); + tor_assert(!found || found != res); + } else { + cached_resolve_t *found = HT_FIND(cache_map, &cache_root, res); + tor_assert(found); + } + }); +} +#endif + diff --git a/src/tor/dns.h b/src/tor/dns.h new file mode 100644 index 0000000..022cd4a --- /dev/null +++ b/src/tor/dns.h @@ -0,0 +1,32 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file dns.h + * \brief Header file for dns.c. + **/ + +#ifndef TOR_DNS_H +#define TOR_DNS_H + +int dns_init(void); +int has_dns_init_failed(void); +void dns_free_all(void); +uint32_t dns_clip_ttl(uint32_t ttl); +int dns_reset(void); +void connection_dns_remove(edge_connection_t *conn); +void assert_connection_edge_not_dns_pending(edge_connection_t *conn); +void assert_all_pending_dns_resolves_ok(void); +void dns_cancel_pending_resolve(const char *question); +int dns_resolve(edge_connection_t *exitconn); +void dns_launch_correctness_checks(void); +int dns_seems_to_be_broken(void); +int dns_seems_to_be_broken_for_ipv6(void); +void dns_reset_correctness_checks(void); +void dump_dns_mem_usage(int severity); + +#endif + diff --git a/src/tor/dnsserv.c b/src/tor/dnsserv.c new file mode 100644 index 0000000..9ac42e4 --- /dev/null +++ b/src/tor/dnsserv.c @@ -0,0 +1,374 @@ +/* Copyright (c) 2007-2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file dnsserv.c \brief Implements client-side DNS proxy server code. Note: + * this is the DNS Server code, not the Server DNS code. Confused? This code + * runs on client-side, and acts as a DNS server. The code in dns.c, on the + * other hand, runs on Tor servers, and acts as a DNS client. + **/ + +#include "or.h" +#include "dnsserv.h" +#include "config.h" +#include "connection.h" +#include "connection_edge.h" +#include "control.h" +#include "onion_main.h" +#include "policies.h" +#ifdef HAVE_EVENT2_DNS_H +#include +#include +/* XXXX this implies we want an improved evdns */ +#include +#else +#include "eventdns.h" +#endif + +/** Helper function: called by evdns whenever the client sends a request to our + * DNSPort. We need to eventually answer the request req. + */ +static void +evdns_server_callback(struct evdns_server_request *req, void *data_) +{ + const listener_connection_t *listener = data_; + entry_connection_t *entry_conn; + edge_connection_t *conn; + int i = 0; + struct evdns_server_question *q = NULL; + struct sockaddr_storage addr; + struct sockaddr *sa; + int addrlen; + tor_addr_t tor_addr; + uint16_t port; + int err = DNS_ERR_NONE; + char *q_name; + + tor_assert(req); + + log_info(LD_APP, "Got a new DNS request!"); + + req->flags |= 0x80; /* set RA */ + + /* First, check whether the requesting address matches our SOCKSPolicy. */ + if ((addrlen = evdns_server_request_get_requesting_addr(req, + (struct sockaddr*)&addr, (socklen_t)sizeof(addr))) < 0) { + log_warn(LD_APP, "Couldn't get requesting address."); + evdns_server_request_respond(req, DNS_ERR_SERVERFAILED); + return; + } + (void) addrlen; + sa = (struct sockaddr*) &addr; + if (tor_addr_from_sockaddr(&tor_addr, sa, &port)<0) { + log_warn(LD_APP, "Requesting address wasn't recognized."); + evdns_server_request_respond(req, DNS_ERR_SERVERFAILED); + return; + } + + if (!socks_policy_permits_address(&tor_addr)) { + log_warn(LD_APP, "Rejecting DNS request from disallowed IP."); + evdns_server_request_respond(req, DNS_ERR_REFUSED); + return; + } + + /* Now, let's find the first actual question of a type we can answer in this + * DNS request. It makes us a little noncompliant to act like this; we + * should fix that eventually if it turns out to make a difference for + * anybody. */ + if (req->nquestions == 0) { + log_info(LD_APP, "No questions in DNS request; sending back nil reply."); + evdns_server_request_respond(req, 0); + return; + } + if (req->nquestions > 1) { + log_info(LD_APP, "Got a DNS request with more than one question; I only " + "handle one question at a time for now. Skipping the extras."); + } + for (i = 0; i < req->nquestions; ++i) { + if (req->questions[i]->dns_question_class != EVDNS_CLASS_INET) + continue; + switch (req->questions[i]->type) { + case EVDNS_TYPE_A: + case EVDNS_TYPE_AAAA: + case EVDNS_TYPE_PTR: + q = req->questions[i]; + default: + break; + } + } + if (!q) { + log_info(LD_APP, "None of the questions we got were ones we're willing " + "to support. Sending NOTIMPL."); + evdns_server_request_respond(req, DNS_ERR_NOTIMPL); + return; + } + if (q->type != EVDNS_TYPE_A && q->type != EVDNS_TYPE_AAAA) { + tor_assert(q->type == EVDNS_TYPE_PTR); + } + + /* Make sure the name isn't too long: This should be impossible, I think. */ + if (err == DNS_ERR_NONE && strlen(q->name) > MAX_SOCKS_ADDR_LEN-1) + err = DNS_ERR_FORMAT; + + if (err != DNS_ERR_NONE) { + /* We got an error? Then send back an answer immediately; we're done. */ + evdns_server_request_respond(req, err); + return; + } + + /* Make a new dummy AP connection, and attach the request to it. */ + entry_conn = entry_connection_new(CONN_TYPE_AP, AF_INET); + conn = ENTRY_TO_EDGE_CONN(entry_conn); + TO_CONN(conn)->state = AP_CONN_STATE_RESOLVE_WAIT; + conn->is_dns_request = 1; + + tor_addr_copy(&TO_CONN(conn)->addr, &tor_addr); + TO_CONN(conn)->port = port; + TO_CONN(conn)->address = tor_dup_addr(&tor_addr); + + if (q->type == EVDNS_TYPE_A || q->type == EVDNS_TYPE_AAAA) + entry_conn->socks_request->command = SOCKS_COMMAND_RESOLVE; + else + entry_conn->socks_request->command = SOCKS_COMMAND_RESOLVE_PTR; + + strlcpy(entry_conn->socks_request->address, q->name, + sizeof(entry_conn->socks_request->address)); + + entry_conn->socks_request->listener_type = listener->base_.type; + entry_conn->dns_server_request = req; + entry_conn->isolation_flags = listener->isolation_flags; + entry_conn->session_group = listener->session_group; + entry_conn->nym_epoch = get_signewnym_epoch(); + + if (connection_add(ENTRY_TO_CONN(entry_conn)) < 0) { + log_warn(LD_APP, "Couldn't register dummy connection for DNS request"); + evdns_server_request_respond(req, DNS_ERR_SERVERFAILED); + connection_free(ENTRY_TO_CONN(entry_conn)); + return; + } + + control_event_stream_status(entry_conn, STREAM_EVENT_NEW_RESOLVE, 0); + + /* Now, unless a controller asked us to leave streams unattached, + * throw the connection over to get rewritten (which will + * answer it immediately if it's in the cache, or completely bogus, or + * automapped), and then attached to a circuit. */ + log_info(LD_APP, "Passing request for %s to rewrite_and_attach.", + escaped_safe_str_client(q->name)); + q_name = tor_strdup(q->name); /* q could be freed in rewrite_and_attach */ + connection_ap_rewrite_and_attach_if_allowed(entry_conn, NULL, NULL); + /* Now, the connection is marked if it was bad. */ + + log_info(LD_APP, "Passed request for %s to rewrite_and_attach_if_allowed.", + escaped_safe_str_client(q_name)); + tor_free(q_name); +} + +/** Helper function: called whenever the client sends a resolve request to our + * controller. We need to eventually answer the request req. + * Returns 0 if the controller will be getting (or has gotten) an event in + * response; -1 if we couldn't launch the request. + */ +int +dnsserv_launch_request(const char *name, int reverse, + control_connection_t *control_conn) +{ + entry_connection_t *entry_conn; + edge_connection_t *conn; + char *q_name; + + /* Make a new dummy AP connection, and attach the request to it. */ + entry_conn = entry_connection_new(CONN_TYPE_AP, AF_INET); + conn = ENTRY_TO_EDGE_CONN(entry_conn); + conn->base_.state = AP_CONN_STATE_RESOLVE_WAIT; + + tor_addr_copy(&TO_CONN(conn)->addr, &control_conn->base_.addr); +#ifdef AF_UNIX + /* + * The control connection can be AF_UNIX and if so tor_dup_addr will + * unhelpfully say ""; say "(Tor_internal)" + * instead. + */ + if (control_conn->base_.socket_family == AF_UNIX) { + TO_CONN(conn)->port = 0; + TO_CONN(conn)->address = tor_strdup("(Tor_internal)"); + } else { + TO_CONN(conn)->port = control_conn->base_.port; + TO_CONN(conn)->address = tor_dup_addr(&control_conn->base_.addr); + } +#else + TO_CONN(conn)->port = control_conn->base_.port; + TO_CONN(conn)->address = tor_dup_addr(&control_conn->base_.addr); +#endif + + if (reverse) + entry_conn->socks_request->command = SOCKS_COMMAND_RESOLVE_PTR; + else + entry_conn->socks_request->command = SOCKS_COMMAND_RESOLVE; + + conn->is_dns_request = 1; + + strlcpy(entry_conn->socks_request->address, name, + sizeof(entry_conn->socks_request->address)); + + entry_conn->socks_request->listener_type = CONN_TYPE_CONTROL_LISTENER; + entry_conn->original_dest_address = tor_strdup(name); + entry_conn->session_group = SESSION_GROUP_CONTROL_RESOLVE; + entry_conn->nym_epoch = get_signewnym_epoch(); + entry_conn->isolation_flags = ISO_DEFAULT; + + if (connection_add(TO_CONN(conn))<0) { + log_warn(LD_APP, "Couldn't register dummy connection for RESOLVE request"); + connection_free(TO_CONN(conn)); + return -1; + } + + control_event_stream_status(entry_conn, STREAM_EVENT_NEW_RESOLVE, 0); + + /* Now, unless a controller asked us to leave streams unattached, + * throw the connection over to get rewritten (which will + * answer it immediately if it's in the cache, or completely bogus, or + * automapped), and then attached to a circuit. */ + log_info(LD_APP, "Passing request for %s to rewrite_and_attach.", + escaped_safe_str_client(name)); + q_name = tor_strdup(name); /* q could be freed in rewrite_and_attach */ + connection_ap_rewrite_and_attach_if_allowed(entry_conn, NULL, NULL); + /* Now, the connection is marked if it was bad. */ + + log_info(LD_APP, "Passed request for %s to rewrite_and_attach_if_allowed.", + escaped_safe_str_client(q_name)); + tor_free(q_name); + return 0; +} + +/** If there is a pending request on conn that's waiting for an answer, + * send back an error and free the request. */ +void +dnsserv_reject_request(entry_connection_t *conn) +{ + if (conn->dns_server_request) { + evdns_server_request_respond(conn->dns_server_request, + DNS_ERR_SERVERFAILED); + conn->dns_server_request = NULL; + } +} + +/** Look up the original name that corresponds to 'addr' in req. We use this + * to preserve case in order to facilitate people using 0x20-hacks to avoid + * DNS poisoning. */ +static const char * +evdns_get_orig_address(const struct evdns_server_request *req, + int rtype, const char *addr) +{ + int i, type; + + switch (rtype) { + case RESOLVED_TYPE_IPV4: + type = EVDNS_TYPE_A; + break; + case RESOLVED_TYPE_HOSTNAME: + type = EVDNS_TYPE_PTR; + break; + case RESOLVED_TYPE_IPV6: + type = EVDNS_TYPE_AAAA; + break; + default: + tor_fragile_assert(); + return addr; + } + + for (i = 0; i < req->nquestions; ++i) { + const struct evdns_server_question *q = req->questions[i]; + if (q->type == type && !strcasecmp(q->name, addr)) + return q->name; + } + return addr; +} + +/** Tell the dns request waiting for an answer on conn that we have an + * answer of type answer_type (RESOLVE_TYPE_IPV4/IPV6/ERR), of length + * answer_len, in answer, with TTL ttl. Doesn't do + * any caching; that's handled elsewhere. */ +void +dnsserv_resolved(entry_connection_t *conn, + int answer_type, + size_t answer_len, + const char *answer, + int ttl) +{ + struct evdns_server_request *req = conn->dns_server_request; + const char *name; + int err = DNS_ERR_NONE; + if (!req) + return; + name = evdns_get_orig_address(req, answer_type, + conn->socks_request->address); + + /* XXXX Re-do; this is dumb. */ + if (ttl < 60) + ttl = 60; + + /* The evdns interface is: add a bunch of reply items (corresponding to one + * or more of the questions in the request); then, call + * evdns_server_request_respond. */ + if (answer_type == RESOLVED_TYPE_IPV6) { + evdns_server_request_add_aaaa_reply(req, + name, + 1, answer, ttl); + } else if (answer_type == RESOLVED_TYPE_IPV4 && answer_len == 4 && + conn->socks_request->command == SOCKS_COMMAND_RESOLVE) { + evdns_server_request_add_a_reply(req, + name, + 1, answer, ttl); + } else if (answer_type == RESOLVED_TYPE_HOSTNAME && + answer_len < 256 && + conn->socks_request->command == SOCKS_COMMAND_RESOLVE_PTR) { + char *ans = tor_strndup(answer, answer_len); + evdns_server_request_add_ptr_reply(req, NULL, + name, + ans, ttl); + tor_free(ans); + } else if (answer_type == RESOLVED_TYPE_ERROR) { + err = DNS_ERR_NOTEXIST; + } else { /* answer_type == RESOLVED_TYPE_ERROR_TRANSIENT */ + err = DNS_ERR_SERVERFAILED; + } + + evdns_server_request_respond(req, err); + + conn->dns_server_request = NULL; +} + +/** Set up the evdns server port for the UDP socket on conn, which + * must be an AP_DNS_LISTENER */ +void +dnsserv_configure_listener(connection_t *conn) +{ + listener_connection_t *listener_conn; + tor_assert(conn); + tor_assert(SOCKET_OK(conn->s)); + tor_assert(conn->type == CONN_TYPE_AP_DNS_LISTENER); + + listener_conn = TO_LISTENER_CONN(conn); + listener_conn->dns_server_port = + tor_evdns_add_server_port(conn->s, 0, evdns_server_callback, + listener_conn); +} + +/** Free the evdns server port for conn, which must be an + * AP_DNS_LISTENER. */ +void +dnsserv_close_listener(connection_t *conn) +{ + listener_connection_t *listener_conn; + tor_assert(conn); + tor_assert(conn->type == CONN_TYPE_AP_DNS_LISTENER); + + listener_conn = TO_LISTENER_CONN(conn); + + if (listener_conn->dns_server_port) { + evdns_close_server_port(listener_conn->dns_server_port); + listener_conn->dns_server_port = NULL; + } +} + diff --git a/src/tor/dnsserv.h b/src/tor/dnsserv.h new file mode 100644 index 0000000..687a77e --- /dev/null +++ b/src/tor/dnsserv.h @@ -0,0 +1,27 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file dnsserv.h + * \brief Header file for dnsserv.c. + **/ + +#ifndef TOR_DNSSERV_H +#define TOR_DNSSERV_H + +void dnsserv_configure_listener(connection_t *conn); +void dnsserv_close_listener(connection_t *conn); +void dnsserv_resolved(entry_connection_t *conn, + int answer_type, + size_t answer_len, + const char *answer, + int ttl); +void dnsserv_reject_request(entry_connection_t *conn); +int dnsserv_launch_request(const char *name, int is_reverse, + control_connection_t *control_conn); + +#endif + diff --git a/src/tor/entrynodes.c b/src/tor/entrynodes.c new file mode 100644 index 0000000..566896e --- /dev/null +++ b/src/tor/entrynodes.c @@ -0,0 +1,2334 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file entrynodes.c + * \brief Code to manage our fixed first nodes for various functions. + * + * Entry nodes can be guards (for general use) or bridges (for censorship + * circumvention). + **/ + +#include "or.h" +#include "circpathbias.h" +#include "circuitbuild.h" +#include "circuitstats.h" +#include "config.h" +#include "confparse.h" +#include "connection.h" +#include "connection_or.h" +#include "control.h" +#include "directory.h" +#include "entrynodes.h" +#include "onion_main.h" +#include "microdesc.h" +#include "networkstatus.h" +#include "nodelist.h" +#include "policies.h" +#include "router.h" +#include "routerlist.h" +#include "routerparse.h" +#include "routerset.h" +#include "transports.h" +#include "statefile.h" + +/** Information about a configured bridge. Currently this just matches the + * ones in the torrc file, but one day we may be able to learn about new + * bridges on our own, and remember them in the state file. */ +typedef struct { + /** Address of the bridge. */ + tor_addr_t addr; + /** TLS port for the bridge. */ + uint16_t port; + /** Boolean: We are re-parsing our bridge list, and we are going to remove + * this one if we don't find it in the list of configured bridges. */ + unsigned marked_for_removal : 1; + /** Expected identity digest, or all zero bytes if we don't know what the + * digest should be. */ + char identity[DIGEST_LEN]; + + /** Name of pluggable transport protocol taken from its config line. */ + char *transport_name; + + /** When should we next try to fetch a descriptor for this bridge? */ + download_status_t fetch_status; + + /** A smartlist of k=v values to be passed to the SOCKS proxy, if + transports are used for this bridge. */ + smartlist_t *socks_args; +} bridge_info_t; + +/** A list of our chosen entry guards. */ +static smartlist_t *entry_guards = NULL; +/** A value of 1 means that the entry_guards list has changed + * and those changes need to be flushed to disk. */ +static int entry_guards_dirty = 0; + +static void bridge_free(bridge_info_t *bridge); +static const node_t *choose_random_entry_impl(cpath_build_state_t *state, + int for_directory, + dirinfo_type_t dirtype); + +/** Return the list of entry guards, creating it if necessary. */ +const smartlist_t * +get_entry_guards(void) +{ + if (! entry_guards) + entry_guards = smartlist_new(); + return entry_guards; +} + +/** Check whether the entry guard e is usable, given the directory + * authorities' opinion about the router (stored in ri) and the user's + * configuration (in options). Set e->bad_since + * accordingly. Return true iff the entry guard's status changes. + * + * If it's not usable, set *reason to a static string explaining why. + */ +static int +entry_guard_set_status(entry_guard_t *e, const node_t *node, + time_t now, const or_options_t *options, + const char **reason) +{ + char buf[HEX_DIGEST_LEN+1]; + int changed = 0; + + *reason = NULL; + + /* Do we want to mark this guard as bad? */ + if (!node) + *reason = "unlisted"; + else if (!node->is_running) + *reason = "down"; + else if (options->UseBridges && (!node->ri || + node->ri->purpose != ROUTER_PURPOSE_BRIDGE)) + *reason = "not a bridge"; + else if (options->UseBridges && !node_is_a_configured_bridge(node)) + *reason = "not a configured bridge"; + else if (!options->UseBridges && !node->is_possible_guard && + !routerset_contains_node(options->EntryNodes,node)) + *reason = "not recommended as a guard"; + else if (routerset_contains_node(options->ExcludeNodes, node)) + *reason = "excluded"; + else if (e->path_bias_disabled) + *reason = "path-biased"; + + if (*reason && ! e->bad_since) { + /* Router is newly bad. */ + base16_encode(buf, sizeof(buf), e->identity, DIGEST_LEN); + log_info(LD_CIRC, "Entry guard %s (%s) is %s: marking as unusable.", + e->nickname, buf, *reason); + + e->bad_since = now; + control_event_guard(e->nickname, e->identity, "BAD"); + changed = 1; + } else if (!*reason && e->bad_since) { + /* There's nothing wrong with the router any more. */ + base16_encode(buf, sizeof(buf), e->identity, DIGEST_LEN); + log_info(LD_CIRC, "Entry guard %s (%s) is no longer unusable: " + "marking as ok.", e->nickname, buf); + + e->bad_since = 0; + control_event_guard(e->nickname, e->identity, "GOOD"); + changed = 1; + } + + if (node) { + int is_dir = node_is_dir(node) && node->rs && + node->rs->version_supports_microdesc_cache; + if (options->UseBridges && node_is_a_configured_bridge(node)) + is_dir = 1; + if (e->is_dir_cache != is_dir) { + e->is_dir_cache = is_dir; + changed = 1; + } + } + + return changed; +} + +/** Return true iff enough time has passed since we last tried to connect + * to the unreachable guard e that we're willing to try again. */ +static int +entry_is_time_to_retry(entry_guard_t *e, time_t now) +{ + long diff; + if (e->last_attempted < e->unreachable_since) + return 1; + diff = now - e->unreachable_since; + if (diff < 6*60*60) + return now > (e->last_attempted + 60*60); + else if (diff < 3*24*60*60) + return now > (e->last_attempted + 4*60*60); + else if (diff < 7*24*60*60) + return now > (e->last_attempted + 18*60*60); + else + return now > (e->last_attempted + 36*60*60); +} + +/** Return the node corresponding to e, if e is + * working well enough that we are willing to use it as an entry + * right now. (Else return NULL.) In particular, it must be + * - Listed as either up or never yet contacted; + * - Present in the routerlist; + * - Listed as 'stable' or 'fast' by the current dirserver consensus, + * if demanded by need_uptime or need_capacity + * (unless it's a configured EntryNode); + * - Allowed by our current ReachableORAddresses config option; and + * - Currently thought to be reachable by us (unless assume_reachable + * is true). + * + * If the answer is no, set *msg to an explanation of why. + * + * If need_descriptor is true, only return the node if we currently have + * a descriptor (routerinfo or microdesc) for it. + */ +static INLINE const node_t * +entry_is_live(entry_guard_t *e, int need_uptime, int need_capacity, + int assume_reachable, int need_descriptor, const char **msg) +{ + const node_t *node; + const or_options_t *options = get_options(); + tor_assert(msg); + + if (e->path_bias_disabled) { + *msg = "path-biased"; + return NULL; + } + if (e->bad_since) { + *msg = "bad"; + return NULL; + } + /* no good if it's unreachable, unless assume_unreachable or can_retry. */ + if (!assume_reachable && !e->can_retry && + e->unreachable_since && !entry_is_time_to_retry(e, time(NULL))) { + *msg = "unreachable"; + return NULL; + } + node = node_get_by_id(e->identity); + if (!node) { + *msg = "no node info"; + return NULL; + } + if (need_descriptor && !node_has_descriptor(node)) { + *msg = "no descriptor"; + return NULL; + } + if (get_options()->UseBridges) { + if (node_get_purpose(node) != ROUTER_PURPOSE_BRIDGE) { + *msg = "not a bridge"; + return NULL; + } + if (!node_is_a_configured_bridge(node)) { + *msg = "not a configured bridge"; + return NULL; + } + } else { /* !get_options()->UseBridges */ + if (node_get_purpose(node) != ROUTER_PURPOSE_GENERAL) { + *msg = "not general-purpose"; + return NULL; + } + } + if (routerset_contains_node(options->EntryNodes, node)) { + /* they asked for it, they get it */ + need_uptime = need_capacity = 0; + } + if (node_is_unreliable(node, need_uptime, need_capacity, 0)) { + *msg = "not fast/stable"; + return NULL; + } + if (!fascist_firewall_allows_node(node)) { + *msg = "unreachable by config"; + return NULL; + } + return node; +} + +/** Return the number of entry guards that we think are usable. */ +int +num_live_entry_guards(int for_directory) +{ + int n = 0; + const char *msg; + if (! entry_guards) + return 0; + SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, entry) { + if (for_directory && !entry->is_dir_cache) + continue; + if (entry_is_live(entry, 0, 1, 0, !for_directory, &msg)) + ++n; + } SMARTLIST_FOREACH_END(entry); + return n; +} + +/** If digest matches the identity of any node in the + * entry_guards list, return that node. Else return NULL. */ +entry_guard_t * +entry_guard_get_by_id_digest(const char *digest) +{ + SMARTLIST_FOREACH(entry_guards, entry_guard_t *, entry, + if (tor_memeq(digest, entry->identity, DIGEST_LEN)) + return entry; + ); + return NULL; +} + +/** Dump a description of our list of entry guards to the log at level + * severity. */ +static void +log_entry_guards(int severity) +{ + smartlist_t *elements = smartlist_new(); + char *s; + + SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, e) + { + const char *msg = NULL; + if (entry_is_live(e, 0, 1, 0, 0, &msg)) + smartlist_add_asprintf(elements, "%s [%s] (up %s)", + e->nickname, + hex_str(e->identity, DIGEST_LEN), + e->made_contact ? "made-contact" : "never-contacted"); + else + smartlist_add_asprintf(elements, "%s [%s] (%s, %s)", + e->nickname, + hex_str(e->identity, DIGEST_LEN), + msg, + e->made_contact ? "made-contact" : "never-contacted"); + } + SMARTLIST_FOREACH_END(e); + + s = smartlist_join_strings(elements, ",", 0, NULL); + SMARTLIST_FOREACH(elements, char*, cp, tor_free(cp)); + smartlist_free(elements); + log_fn(severity,LD_CIRC,"%s",s); + tor_free(s); +} + +/** Called when one or more guards that we would previously have used for some + * purpose are no longer in use because a higher-priority guard has become + * usable again. */ +static void +control_event_guard_deferred(void) +{ + /* XXXX We don't actually have a good way to figure out _how many_ entries + * are live for some purpose. We need an entry_is_even_slightly_live() + * function for this to work right. NumEntryGuards isn't reliable: if we + * need guards with weird properties, we can have more than that number + * live. + **/ +#if 0 + int n = 0; + const char *msg; + const or_options_t *options = get_options(); + if (!entry_guards) + return; + SMARTLIST_FOREACH(entry_guards, entry_guard_t *, entry, + { + if (entry_is_live(entry, 0, 1, 0, &msg)) { + if (n++ == options->NumEntryGuards) { + control_event_guard(entry->nickname, entry->identity, "DEFERRED"); + return; + } + } + }); +#endif +} + +/** Largest amount that we'll backdate chosen_on_date */ +#define CHOSEN_ON_DATE_SLOP (30*86400) + +/** Add a new (preferably stable and fast) router to our + * entry_guards list. Return a pointer to the router if we succeed, + * or NULL if we can't find any more suitable entries. + * + * If chosen is defined, use that one, and if it's not + * already in our entry_guards list, put it at the *beginning*. + * Else, put the one we pick at the end of the list. */ +static const node_t * +add_an_entry_guard(const node_t *chosen, int reset_status, int prepend, + int for_discovery, int for_directory) +{ + const node_t *node; + entry_guard_t *entry; + + if (chosen) { + node = chosen; + entry = entry_guard_get_by_id_digest(node->identity); + if (entry) { + if (reset_status) { + entry->bad_since = 0; + entry->can_retry = 1; + } + entry->is_dir_cache = node->rs && + node->rs->version_supports_microdesc_cache; + if (get_options()->UseBridges && node_is_a_configured_bridge(node)) + entry->is_dir_cache = 1; + return NULL; + } + } else if (!for_directory) { + node = choose_good_entry_server(CIRCUIT_PURPOSE_C_GENERAL, NULL); + if (!node) + return NULL; + } else { + const routerstatus_t *rs; + rs = router_pick_directory_server(MICRODESC_DIRINFO|V3_DIRINFO, + PDS_PREFER_TUNNELED_DIR_CONNS_|PDS_FOR_GUARD); + if (!rs) + return NULL; + node = node_get_by_id(rs->identity_digest); + if (!node) + return NULL; + } + if (node->using_as_guard) + return NULL; + if (entry_guard_get_by_id_digest(node->identity) != NULL) { + log_info(LD_CIRC, "I was about to add a duplicate entry guard."); + /* This can happen if we choose a guard, then the node goes away, then + * comes back. */ + ((node_t*) node)->using_as_guard = 1; + return NULL; + } + entry = tor_malloc_zero(sizeof(entry_guard_t)); + log_info(LD_CIRC, "Chose %s as new entry guard.", + node_describe(node)); + strlcpy(entry->nickname, node_get_nickname(node), sizeof(entry->nickname)); + memcpy(entry->identity, node->identity, DIGEST_LEN); + entry->is_dir_cache = node_is_dir(node) && node->rs && + node->rs->version_supports_microdesc_cache; + if (get_options()->UseBridges && node_is_a_configured_bridge(node)) + entry->is_dir_cache = 1; + + /* Choose expiry time smudged over the past month. The goal here + * is to a) spread out when Tor clients rotate their guards, so they + * don't all select them on the same day, and b) avoid leaving a + * precise timestamp in the state file about when we first picked + * this guard. For details, see the Jan 2010 or-dev thread. */ + entry->chosen_on_date = time(NULL) - crypto_rand_int(3600*24*30); + entry->chosen_by_version = tor_strdup(VERSION); + + /* Are we picking this guard because all of our current guards are + * down so we need another one (for_discovery is 1), or because we + * decided we need more variety in our guard list (for_discovery is 0)? + * + * Currently we hack this behavior into place by setting "made_contact" + * for guards of the latter variety, so we'll be willing to use any of + * them right off the bat. + */ + if (!for_discovery) + entry->made_contact = 1; + + ((node_t*)node)->using_as_guard = 1; + if (prepend) + smartlist_insert(entry_guards, 0, entry); + else + smartlist_add(entry_guards, entry); + control_event_guard(entry->nickname, entry->identity, "NEW"); + control_event_guard_deferred(); + log_entry_guards(LOG_INFO); + return node; +} + +/** Choose how many entry guards or directory guards we'll use. If + * for_directory is true, we return how many directory guards to + * use; else we return how many entry guards to use. */ +static int +decide_num_guards(const or_options_t *options, int for_directory) +{ + if (for_directory && options->NumDirectoryGuards != 0) + return options->NumDirectoryGuards; + return options->NumEntryGuards; +} + +/** If the use of entry guards is configured, choose more entry guards + * until we have enough in the list. */ +static void +pick_entry_guards(const or_options_t *options, int for_directory) +{ + int changed = 0; + const int num_needed = decide_num_guards(options, for_directory); + + tor_assert(entry_guards); + + while (num_live_entry_guards(for_directory) < num_needed) { + if (!add_an_entry_guard(NULL, 0, 0, 0, for_directory)) + break; + changed = 1; + } + if (changed) + entry_guards_changed(); +} + +/** How long (in seconds) do we allow an entry guard to be nonfunctional, + * unlisted, excluded, or otherwise nonusable before we give up on it? */ +#define ENTRY_GUARD_REMOVE_AFTER (30*24*60*60) + +/** Release all storage held by e. */ +static void +entry_guard_free(entry_guard_t *e) +{ + if (!e) + return; + tor_free(e->chosen_by_version); + tor_free(e); +} + +/** + * Return the minimum lifetime of working entry guard, in seconds, + * as given in the consensus networkstatus. (Plus CHOSEN_ON_DATE_SLOP, + * so that we can do the chosen_on_date randomization while achieving the + * desired minimum lifetime.) + */ +static int32_t +guards_get_lifetime(void) +{ + const or_options_t *options = get_options(); +#define DFLT_GUARD_LIFETIME (86400 * 60) /* Two months. */ +#define MIN_GUARD_LIFETIME (86400 * 30) /* One months. */ +#define MAX_GUARD_LIFETIME (86400 * 1826) /* Five years. */ + + if (options->GuardLifetime >= 1) { + return CLAMP(MIN_GUARD_LIFETIME, + options->GuardLifetime, + MAX_GUARD_LIFETIME) + CHOSEN_ON_DATE_SLOP; + } + + return networkstatus_get_param(NULL, "GuardLifetime", + DFLT_GUARD_LIFETIME, + MIN_GUARD_LIFETIME, + MAX_GUARD_LIFETIME) + CHOSEN_ON_DATE_SLOP; +} + +/** Remove any entry guard which was selected by an unknown version of Tor, + * or which was selected by a version of Tor that's known to select + * entry guards badly, or which was selected more 2 months ago. */ +/* XXXX The "obsolete guards" and "chosen long ago guards" things should + * probably be different functions. */ +static int +remove_obsolete_entry_guards(time_t now) +{ + int changed = 0, i; + int32_t guard_lifetime = guards_get_lifetime(); + + for (i = 0; i < smartlist_len(entry_guards); ++i) { + entry_guard_t *entry = smartlist_get(entry_guards, i); + const char *ver = entry->chosen_by_version; + const char *msg = NULL; + tor_version_t v; + int version_is_bad = 0, date_is_bad = 0; + if (!ver) { + msg = "does not say what version of Tor it was selected by"; + version_is_bad = 1; + } else if (tor_version_parse(ver, &v)) { + msg = "does not seem to be from any recognized version of Tor"; + version_is_bad = 1; + } else { + char *tor_ver = NULL; + tor_asprintf(&tor_ver, "Tor %s", ver); + if ((tor_version_as_new_as(tor_ver, "0.1.0.10-alpha") && + !tor_version_as_new_as(tor_ver, "0.1.2.16-dev")) || + (tor_version_as_new_as(tor_ver, "0.2.0.0-alpha") && + !tor_version_as_new_as(tor_ver, "0.2.0.6-alpha")) || + /* above are bug 440; below are bug 1217 */ + (tor_version_as_new_as(tor_ver, "0.2.1.3-alpha") && + !tor_version_as_new_as(tor_ver, "0.2.1.23")) || + (tor_version_as_new_as(tor_ver, "0.2.2.0-alpha") && + !tor_version_as_new_as(tor_ver, "0.2.2.7-alpha"))) { + msg = "was selected without regard for guard bandwidth"; + version_is_bad = 1; + } + tor_free(tor_ver); + } + if (!version_is_bad && entry->chosen_on_date + guard_lifetime < now) { + /* It's been too long since the date listed in our state file. */ + msg = "was selected several months ago"; + date_is_bad = 1; + } + + if (version_is_bad || date_is_bad) { /* we need to drop it */ + char dbuf[HEX_DIGEST_LEN+1]; + tor_assert(msg); + base16_encode(dbuf, sizeof(dbuf), entry->identity, DIGEST_LEN); + log_fn(version_is_bad ? LOG_NOTICE : LOG_INFO, LD_CIRC, + "Entry guard '%s' (%s) %s. (Version=%s.) Replacing it.", + entry->nickname, dbuf, msg, ver?escaped(ver):"none"); + control_event_guard(entry->nickname, entry->identity, "DROPPED"); + entry_guard_free(entry); + smartlist_del_keeporder(entry_guards, i--); + log_entry_guards(LOG_INFO); + changed = 1; + } + } + + return changed ? 1 : 0; +} + +/** Remove all entry guards that have been down or unlisted for so + * long that we don't think they'll come up again. Return 1 if we + * removed any, or 0 if we did nothing. */ +static int +remove_dead_entry_guards(time_t now) +{ + char dbuf[HEX_DIGEST_LEN+1]; + char tbuf[ISO_TIME_LEN+1]; + int i; + int changed = 0; + + for (i = 0; i < smartlist_len(entry_guards); ) { + entry_guard_t *entry = smartlist_get(entry_guards, i); + if (entry->bad_since && + ! entry->path_bias_disabled && + entry->bad_since + ENTRY_GUARD_REMOVE_AFTER < now) { + + base16_encode(dbuf, sizeof(dbuf), entry->identity, DIGEST_LEN); + format_local_iso_time(tbuf, entry->bad_since); + log_info(LD_CIRC, "Entry guard '%s' (%s) has been down or unlisted " + "since %s local time; removing.", + entry->nickname, dbuf, tbuf); + control_event_guard(entry->nickname, entry->identity, "DROPPED"); + entry_guard_free(entry); + smartlist_del_keeporder(entry_guards, i); + log_entry_guards(LOG_INFO); + changed = 1; + } else + ++i; + } + return changed ? 1 : 0; +} + +/** Remove all currently listed entry guards. So new ones will be chosen. */ +void +remove_all_entry_guards(void) +{ + char dbuf[HEX_DIGEST_LEN+1]; + + while (smartlist_len(entry_guards)) { + entry_guard_t *entry = smartlist_get(entry_guards, 0); + base16_encode(dbuf, sizeof(dbuf), entry->identity, DIGEST_LEN); + log_info(LD_CIRC, "Entry guard '%s' (%s) has been dropped.", + entry->nickname, dbuf); + control_event_guard(entry->nickname, entry->identity, "DROPPED"); + entry_guard_free(entry); + smartlist_del(entry_guards, 0); + } + log_entry_guards(LOG_INFO); + entry_guards_changed(); +} + +/** A new directory or router-status has arrived; update the down/listed + * status of the entry guards. + * + * An entry is 'down' if the directory lists it as nonrunning. + * An entry is 'unlisted' if the directory doesn't include it. + * + * Don't call this on startup; only on a fresh download. Otherwise we'll + * think that things are unlisted. + */ +void +entry_guards_compute_status(const or_options_t *options, time_t now) +{ + int changed = 0; + digestmap_t *reasons; + + if (! entry_guards) + return; + + if (options->EntryNodes) /* reshuffle the entry guard list if needed */ + entry_nodes_should_be_added(); + + reasons = digestmap_new(); + SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, entry) + { + const node_t *r = node_get_by_id(entry->identity); + const char *reason = NULL; + if (entry_guard_set_status(entry, r, now, options, &reason)) + changed = 1; + + if (entry->bad_since) + tor_assert(reason); + if (reason) + digestmap_set(reasons, entry->identity, (char*)reason); + } + SMARTLIST_FOREACH_END(entry); + + if (remove_dead_entry_guards(now)) + changed = 1; + if (remove_obsolete_entry_guards(now)) + changed = 1; + + if (changed) { + SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, entry) { + const char *reason = digestmap_get(reasons, entry->identity); + const char *live_msg = ""; + const node_t *r = entry_is_live(entry, 0, 1, 0, 0, &live_msg); + log_info(LD_CIRC, "Summary: Entry %s [%s] is %s, %s%s%s, and %s%s.", + entry->nickname, + hex_str(entry->identity, DIGEST_LEN), + entry->unreachable_since ? "unreachable" : "reachable", + entry->bad_since ? "unusable" : "usable", + reason ? ", ": "", + reason ? reason : "", + r ? "live" : "not live / ", + r ? "" : live_msg); + } SMARTLIST_FOREACH_END(entry); + log_info(LD_CIRC, " (%d/%d entry guards are usable/new)", + num_live_entry_guards(0), smartlist_len(entry_guards)); + log_entry_guards(LOG_INFO); + entry_guards_changed(); + } + + digestmap_free(reasons, NULL); +} + +/** Called when a connection to an OR with the identity digest digest + * is established (succeeded==1) or has failed (succeeded==0). + * If the OR is an entry, change that entry's up/down status. + * Return 0 normally, or -1 if we want to tear down the new connection. + * + * If mark_relay_status, also call router_set_status() on this + * relay. + * + * XXX024 change succeeded and mark_relay_status into 'int flags'. + */ +int +entry_guard_register_connect_status(const char *digest, int succeeded, + int mark_relay_status, time_t now) +{ + int changed = 0; + int refuse_conn = 0; + int first_contact = 0; + entry_guard_t *entry = NULL; + int idx = -1; + char buf[HEX_DIGEST_LEN+1]; + + if (! entry_guards) + return 0; + + SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, e) { + tor_assert(e); + if (tor_memeq(e->identity, digest, DIGEST_LEN)) { + entry = e; + idx = e_sl_idx; + break; + } + } SMARTLIST_FOREACH_END(e); + + if (!entry) + return 0; + + base16_encode(buf, sizeof(buf), entry->identity, DIGEST_LEN); + + if (succeeded) { + if (entry->unreachable_since) { + log_info(LD_CIRC, "Entry guard '%s' (%s) is now reachable again. Good.", + entry->nickname, buf); + entry->can_retry = 0; + entry->unreachable_since = 0; + entry->last_attempted = now; + control_event_guard(entry->nickname, entry->identity, "UP"); + changed = 1; + } + if (!entry->made_contact) { + entry->made_contact = 1; + first_contact = changed = 1; + } + } else { /* ! succeeded */ + if (!entry->made_contact) { + /* We've never connected to this one. */ + log_info(LD_CIRC, + "Connection to never-contacted entry guard '%s' (%s) failed. " + "Removing from the list. %d/%d entry guards usable/new.", + entry->nickname, buf, + num_live_entry_guards(0)-1, smartlist_len(entry_guards)-1); + control_event_guard(entry->nickname, entry->identity, "DROPPED"); + entry_guard_free(entry); + smartlist_del_keeporder(entry_guards, idx); + log_entry_guards(LOG_INFO); + changed = 1; + } else if (!entry->unreachable_since) { + log_info(LD_CIRC, "Unable to connect to entry guard '%s' (%s). " + "Marking as unreachable.", entry->nickname, buf); + entry->unreachable_since = entry->last_attempted = now; + control_event_guard(entry->nickname, entry->identity, "DOWN"); + changed = 1; + entry->can_retry = 0; /* We gave it an early chance; no good. */ + } else { + char tbuf[ISO_TIME_LEN+1]; + format_iso_time(tbuf, entry->unreachable_since); + log_debug(LD_CIRC, "Failed to connect to unreachable entry guard " + "'%s' (%s). It has been unreachable since %s.", + entry->nickname, buf, tbuf); + entry->last_attempted = now; + entry->can_retry = 0; /* We gave it an early chance; no good. */ + } + } + + /* if the caller asked us to, also update the is_running flags for this + * relay */ + if (mark_relay_status) + router_set_status(digest, succeeded); + + if (first_contact) { + /* We've just added a new long-term entry guard. Perhaps the network just + * came back? We should give our earlier entries another try too, + * and close this connection so we don't use it before we've given + * the others a shot. */ + SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, e) { + if (e == entry) + break; + if (e->made_contact) { + const char *msg; + const node_t *r = entry_is_live(e, 0, 1, 1, 0, &msg); + if (r && e->unreachable_since) { + refuse_conn = 1; + e->can_retry = 1; + } + } + } SMARTLIST_FOREACH_END(e); + if (refuse_conn) { + log_info(LD_CIRC, + "Connected to new entry guard '%s' (%s). Marking earlier " + "entry guards up. %d/%d entry guards usable/new.", + entry->nickname, buf, + num_live_entry_guards(0), smartlist_len(entry_guards)); + log_entry_guards(LOG_INFO); + changed = 1; + } + } + + if (changed) + entry_guards_changed(); + return refuse_conn ? -1 : 0; +} + +/** When we try to choose an entry guard, should we parse and add + * config's EntryNodes first? */ +static int should_add_entry_nodes = 0; + +/** Called when the value of EntryNodes changes in our configuration. */ +void +entry_nodes_should_be_added(void) +{ + log_info(LD_CIRC, "EntryNodes config option set. Putting configured " + "relays at the front of the entry guard list."); + should_add_entry_nodes = 1; +} + +/** Update the using_as_guard fields of all the nodes. We do this after we + * remove entry guards from the list: This is the only function that clears + * the using_as_guard field. */ +static void +update_node_guard_status(void) +{ + smartlist_t *nodes = nodelist_get_list(); + SMARTLIST_FOREACH(nodes, node_t *, node, node->using_as_guard = 0); + SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, entry) { + node_t *node = node_get_mutable_by_id(entry->identity); + if (node) + node->using_as_guard = 1; + } SMARTLIST_FOREACH_END(entry); +} + +/** Adjust the entry guards list so that it only contains entries from + * EntryNodes, adding new entries from EntryNodes to the list as needed. */ +static void +entry_guards_set_from_config(const or_options_t *options) +{ + smartlist_t *entry_nodes, *worse_entry_nodes, *entry_fps; + smartlist_t *old_entry_guards_on_list, *old_entry_guards_not_on_list; + tor_assert(entry_guards); + + should_add_entry_nodes = 0; + + if (!options->EntryNodes) { + /* It's possible that a controller set EntryNodes, thus making + * should_add_entry_nodes set, then cleared it again, all before the + * call to choose_random_entry() that triggered us. If so, just return. + */ + return; + } + + { + char *string = routerset_to_string(options->EntryNodes); + log_info(LD_CIRC,"Adding configured EntryNodes '%s'.", string); + tor_free(string); + } + + entry_nodes = smartlist_new(); + worse_entry_nodes = smartlist_new(); + entry_fps = smartlist_new(); + old_entry_guards_on_list = smartlist_new(); + old_entry_guards_not_on_list = smartlist_new(); + + /* Split entry guards into those on the list and those not. */ + + routerset_get_all_nodes(entry_nodes, options->EntryNodes, + options->ExcludeNodes, 0); + SMARTLIST_FOREACH(entry_nodes, const node_t *,node, + smartlist_add(entry_fps, (void*)node->identity)); + + SMARTLIST_FOREACH(entry_guards, entry_guard_t *, e, { + if (smartlist_contains_digest(entry_fps, e->identity)) + smartlist_add(old_entry_guards_on_list, e); + else + smartlist_add(old_entry_guards_not_on_list, e); + }); + + /* Remove all currently configured guard nodes, excluded nodes, unreachable + * nodes, or non-Guard nodes from entry_nodes. */ + SMARTLIST_FOREACH_BEGIN(entry_nodes, const node_t *, node) { + if (entry_guard_get_by_id_digest(node->identity)) { + SMARTLIST_DEL_CURRENT(entry_nodes, node); + continue; + } else if (routerset_contains_node(options->ExcludeNodes, node)) { + SMARTLIST_DEL_CURRENT(entry_nodes, node); + continue; + } else if (!fascist_firewall_allows_node(node)) { + SMARTLIST_DEL_CURRENT(entry_nodes, node); + continue; + } else if (! node->is_possible_guard) { + smartlist_add(worse_entry_nodes, (node_t*)node); + SMARTLIST_DEL_CURRENT(entry_nodes, node); + } + } SMARTLIST_FOREACH_END(node); + + /* Now build the new entry_guards list. */ + smartlist_clear(entry_guards); + /* First, the previously configured guards that are in EntryNodes. */ + smartlist_add_all(entry_guards, old_entry_guards_on_list); + /* Next, scramble the rest of EntryNodes, putting the guards first. */ + smartlist_shuffle(entry_nodes); + smartlist_shuffle(worse_entry_nodes); + smartlist_add_all(entry_nodes, worse_entry_nodes); + + /* Next, the rest of EntryNodes */ + SMARTLIST_FOREACH_BEGIN(entry_nodes, const node_t *, node) { + add_an_entry_guard(node, 0, 0, 1, 0); + if (smartlist_len(entry_guards) > options->NumEntryGuards * 10) + break; + } SMARTLIST_FOREACH_END(node); + log_notice(LD_GENERAL, "%d entries in guards", smartlist_len(entry_guards)); + /* Finally, free the remaining previously configured guards that are not in + * EntryNodes. */ + SMARTLIST_FOREACH(old_entry_guards_not_on_list, entry_guard_t *, e, + entry_guard_free(e)); + + update_node_guard_status(); + + smartlist_free(entry_nodes); + smartlist_free(worse_entry_nodes); + smartlist_free(entry_fps); + smartlist_free(old_entry_guards_on_list); + smartlist_free(old_entry_guards_not_on_list); + entry_guards_changed(); +} + +/** Return 0 if we're fine adding arbitrary routers out of the + * directory to our entry guard list, or return 1 if we have a + * list already and we must stick to it. + */ +int +entry_list_is_constrained(const or_options_t *options) +{ + if (options->EntryNodes) + return 1; + if (options->UseBridges) + return 1; + return 0; +} + +/** Return true iff this node can answer directory questions about + * microdescriptors. */ +static int +node_understands_microdescriptors(const node_t *node) +{ + tor_assert(node); + if (node->rs && node->rs->version_supports_microdesc_cache) + return 1; + if (node->ri && tor_version_supports_microdescriptors(node->ri->platform)) + return 1; + return 0; +} + +/** Return true iff node is able to answer directory questions + * of type dirinfo. */ +static int +node_can_handle_dirinfo(const node_t *node, dirinfo_type_t dirinfo) +{ + /* Checking dirinfo for any type other than microdescriptors isn't required + yet, since we only choose directory guards that can support microdescs, + routerinfos, and networkstatuses, AND we don't use directory guards if + we're configured to do direct downloads of anything else. The only case + where we might have a guard that doesn't know about a type of directory + information is when we're retrieving directory information from a + bridge. */ + + if ((dirinfo & MICRODESC_DIRINFO) && + !node_understands_microdescriptors(node)) + return 0; + return 1; +} + +/** Pick a live (up and listed) entry guard from entry_guards. If + * state is non-NULL, this is for a specific circuit -- + * make sure not to pick this circuit's exit or any node in the + * exit's family. If state is NULL, we're looking for a random + * guard (likely a bridge). If dirinfo is not NO_DIRINFO, then + * only select from nodes that know how to answer directory questions + * of that type. */ +const node_t * +choose_random_entry(cpath_build_state_t *state) +{ + return choose_random_entry_impl(state, 0, 0); +} + +/** Pick a live (up and listed) directory guard from entry_guards for + * downloading information of type type. */ +const node_t * +choose_random_dirguard(dirinfo_type_t type) +{ + return choose_random_entry_impl(NULL, 1, type); +} + +/** Helper for choose_random{entry,dirguard}. */ +static const node_t * +choose_random_entry_impl(cpath_build_state_t *state, int for_directory, + dirinfo_type_t dirinfo_type) +{ + const or_options_t *options = get_options(); + smartlist_t *live_entry_guards = smartlist_new(); + smartlist_t *exit_family = smartlist_new(); + const node_t *chosen_exit = + state?build_state_get_exit_node(state) : NULL; + const node_t *node = NULL; + int need_uptime = state ? state->need_uptime : 0; + int need_capacity = state ? state->need_capacity : 0; + int preferred_min, consider_exit_family = 0; + int need_descriptor = !for_directory; + const int num_needed = decide_num_guards(options, for_directory); + + if (chosen_exit) { + nodelist_add_node_and_family(exit_family, chosen_exit); + consider_exit_family = 1; + } + + if (!entry_guards) + entry_guards = smartlist_new(); + + if (should_add_entry_nodes) + entry_guards_set_from_config(options); + + if (!entry_list_is_constrained(options) && + smartlist_len(entry_guards) < num_needed) + pick_entry_guards(options, for_directory); + + retry: + smartlist_clear(live_entry_guards); + SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, entry) { + const char *msg; + node = entry_is_live(entry, need_uptime, need_capacity, 0, + need_descriptor, &msg); + if (!node) + continue; /* down, no point */ + if (for_directory) { + if (!entry->is_dir_cache) + continue; /* We need a directory and didn't get one. */ + } + if (node == chosen_exit) + continue; /* don't pick the same node for entry and exit */ + if (consider_exit_family && smartlist_contains(exit_family, node)) + continue; /* avoid relays that are family members of our exit */ + if (dirinfo_type != NO_DIRINFO && + !node_can_handle_dirinfo(node, dirinfo_type)) + continue; /* this node won't be able to answer our dir questions */ +#if 0 /* since EntryNodes is always strict now, this clause is moot */ + if (options->EntryNodes && + !routerset_contains_node(options->EntryNodes, node)) { + /* We've come to the end of our preferred entry nodes. */ + if (smartlist_len(live_entry_guards)) + goto choose_and_finish; /* only choose from the ones we like */ + if (options->StrictNodes) { + /* in theory this case should never happen, since + * entry_guards_set_from_config() drops unwanted relays */ + tor_fragile_assert(); + } else { + log_info(LD_CIRC, + "No relays from EntryNodes available. Using others."); + } + } +#endif + smartlist_add(live_entry_guards, (void*)node); + if (!entry->made_contact) { + /* Always start with the first not-yet-contacted entry + * guard. Otherwise we might add several new ones, pick + * the second new one, and now we've expanded our entry + * guard list without needing to. */ + goto choose_and_finish; + } + if (smartlist_len(live_entry_guards) >= num_needed) + goto choose_and_finish; /* we have enough */ + } SMARTLIST_FOREACH_END(entry); + + if (entry_list_is_constrained(options)) { + /* If we prefer the entry nodes we've got, and we have at least + * one choice, that's great. Use it. */ + preferred_min = 1; + } else { + /* Try to have at least 2 choices available. This way we don't + * get stuck with a single live-but-crummy entry and just keep + * using him. + * (We might get 2 live-but-crummy entry guards, but so be it.) */ + preferred_min = 2; + } + + if (smartlist_len(live_entry_guards) < preferred_min) { + if (!entry_list_is_constrained(options)) { + /* still no? try adding a new entry then */ + /* XXX if guard doesn't imply fast and stable, then we need + * to tell add_an_entry_guard below what we want, or it might + * be a long time til we get it. -RD */ + node = add_an_entry_guard(NULL, 0, 0, 1, for_directory); + if (node) { + entry_guards_changed(); + /* XXX we start over here in case the new node we added shares + * a family with our exit node. There's a chance that we'll just + * load up on entry guards here, if the network we're using is + * one big family. Perhaps we should teach add_an_entry_guard() + * to understand nodes-to-avoid-if-possible? -RD */ + goto retry; + } + } + if (!node && need_uptime) { + need_uptime = 0; /* try without that requirement */ + goto retry; + } + if (!node && need_capacity) { + /* still no? last attempt, try without requiring capacity */ + need_capacity = 0; + goto retry; + } +#if 0 + /* Removing this retry logic: if we only allow one exit, and it is in the + same family as all our entries, then we are just plain not going to win + here. */ + if (!node && entry_list_is_constrained(options) && consider_exit_family) { + /* still no? if we're using bridges or have strictentrynodes + * set, and our chosen exit is in the same family as all our + * bridges/entry guards, then be flexible about families. */ + consider_exit_family = 0; + goto retry; + } +#endif + /* live_entry_guards may be empty below. Oh well, we tried. */ + } + + choose_and_finish: + if (entry_list_is_constrained(options)) { + /* We need to weight by bandwidth, because our bridges or entryguards + * were not already selected proportional to their bandwidth. */ + node = node_sl_choose_by_bandwidth(live_entry_guards, WEIGHT_FOR_GUARD); + } else { + /* We choose uniformly at random here, because choose_good_entry_server() + * already weights its choices by bandwidth, so we don't want to + * *double*-weight our guard selection. */ + node = smartlist_choose(live_entry_guards); + } + smartlist_free(live_entry_guards); + smartlist_free(exit_family); + return node; +} + +/** Parse state and learn about the entry guards it describes. + * If set is true, and there are no errors, replace the global + * entry_list with what we find. + * On success, return 0. On failure, alloc into *msg a string + * describing the error, and return -1. + */ +int +entry_guards_parse_state(or_state_t *state, int set, char **msg) +{ + entry_guard_t *node = NULL; + smartlist_t *new_entry_guards = smartlist_new(); + config_line_t *line; + time_t now = time(NULL); + const char *state_version = state->TorVersion; + digestmap_t *added_by = digestmap_new(); + + *msg = NULL; + for (line = state->EntryGuards; line; line = line->next) { + if (!strcasecmp(line->key, "EntryGuard")) { + smartlist_t *args = smartlist_new(); + node = tor_malloc_zero(sizeof(entry_guard_t)); + /* all entry guards on disk have been contacted */ + node->made_contact = 1; + smartlist_add(new_entry_guards, node); + smartlist_split_string(args, line->value, " ", + SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); + if (smartlist_len(args)<2) { + *msg = tor_strdup("Unable to parse entry nodes: " + "Too few arguments to EntryGuard"); + } else if (!is_legal_nickname(smartlist_get(args,0))) { + *msg = tor_strdup("Unable to parse entry nodes: " + "Bad nickname for EntryGuard"); + } else { + strlcpy(node->nickname, smartlist_get(args,0), MAX_NICKNAME_LEN+1); + if (base16_decode(node->identity, DIGEST_LEN, smartlist_get(args,1), + strlen(smartlist_get(args,1)))<0) { + *msg = tor_strdup("Unable to parse entry nodes: " + "Bad hex digest for EntryGuard"); + } + } + if (smartlist_len(args) >= 3) { + const char *is_cache = smartlist_get(args, 2); + if (!strcasecmp(is_cache, "DirCache")) { + node->is_dir_cache = 1; + } else if (!strcasecmp(is_cache, "NoDirCache")) { + node->is_dir_cache = 0; + } else { + log_warn(LD_CONFIG, "Bogus third argument to EntryGuard line: %s", + escaped(is_cache)); + } + } + SMARTLIST_FOREACH(args, char*, cp, tor_free(cp)); + smartlist_free(args); + if (*msg) + break; + } else if (!strcasecmp(line->key, "EntryGuardDownSince") || + !strcasecmp(line->key, "EntryGuardUnlistedSince")) { + time_t when; + time_t last_try = 0; + if (!node) { + *msg = tor_strdup("Unable to parse entry nodes: " + "EntryGuardDownSince/UnlistedSince without EntryGuard"); + break; + } + if (parse_iso_time(line->value, &when)<0) { + *msg = tor_strdup("Unable to parse entry nodes: " + "Bad time in EntryGuardDownSince/UnlistedSince"); + break; + } + if (when > now) { + /* It's a bad idea to believe info in the future: you can wind + * up with timeouts that aren't allowed to happen for years. */ + continue; + } + if (strlen(line->value) >= ISO_TIME_LEN+ISO_TIME_LEN+1) { + /* ignore failure */ + (void) parse_iso_time(line->value+ISO_TIME_LEN+1, &last_try); + } + if (!strcasecmp(line->key, "EntryGuardDownSince")) { + node->unreachable_since = when; + node->last_attempted = last_try; + } else { + node->bad_since = when; + } + } else if (!strcasecmp(line->key, "EntryGuardAddedBy")) { + char d[DIGEST_LEN]; + /* format is digest version date */ + if (strlen(line->value) < HEX_DIGEST_LEN+1+1+1+ISO_TIME_LEN) { + log_warn(LD_BUG, "EntryGuardAddedBy line is not long enough."); + continue; + } + if (base16_decode(d, sizeof(d), line->value, HEX_DIGEST_LEN)<0 || + line->value[HEX_DIGEST_LEN] != ' ') { + log_warn(LD_BUG, "EntryGuardAddedBy line %s does not begin with " + "hex digest", escaped(line->value)); + continue; + } + digestmap_set(added_by, d, tor_strdup(line->value+HEX_DIGEST_LEN+1)); + } else if (!strcasecmp(line->key, "EntryGuardPathUseBias")) { + const or_options_t *options = get_options(); + double use_cnt, success_cnt; + + if (!node) { + *msg = tor_strdup("Unable to parse entry nodes: " + "EntryGuardPathUseBias without EntryGuard"); + break; + } + + if (tor_sscanf(line->value, "%lf %lf", + &use_cnt, &success_cnt) != 2) { + log_info(LD_GENERAL, "Malformed path use bias line for node %s", + node->nickname); + continue; + } + + if (use_cnt < success_cnt) { + int severity = LOG_INFO; + /* If this state file was written by a Tor that would have + * already fixed it, then the overcounting bug is still there.. */ + if (tor_version_as_new_as(state_version, "0.2.4.13-alpha")) { + severity = LOG_NOTICE; + } + log_fn(severity, LD_BUG, + "State file contains unexpectedly high usage success " + "counts %lf/%lf for Guard %s ($%s)", + success_cnt, use_cnt, + node->nickname, hex_str(node->identity, DIGEST_LEN)); + success_cnt = use_cnt; + } + + node->use_attempts = use_cnt; + node->use_successes = success_cnt; + + log_info(LD_GENERAL, "Read %f/%f path use bias for node %s", + node->use_successes, node->use_attempts, node->nickname); + + /* Note: We rely on the < comparison here to allow us to set a 0 + * rate and disable the feature entirely. If refactoring, don't + * change to <= */ + if (pathbias_get_use_success_count(node)/node->use_attempts + < pathbias_get_extreme_use_rate(options) && + pathbias_get_dropguards(options)) { + node->path_bias_disabled = 1; + log_info(LD_GENERAL, + "Path use bias is too high (%f/%f); disabling node %s", + node->circ_successes, node->circ_attempts, node->nickname); + } + } else if (!strcasecmp(line->key, "EntryGuardPathBias")) { + const or_options_t *options = get_options(); + double hop_cnt, success_cnt, timeouts, collapsed, successful_closed, + unusable; + + if (!node) { + *msg = tor_strdup("Unable to parse entry nodes: " + "EntryGuardPathBias without EntryGuard"); + break; + } + + /* First try 3 params, then 2. */ + /* In the long run: circuit_success ~= successful_circuit_close + + * collapsed_circuits + + * unusable_circuits */ + if (tor_sscanf(line->value, "%lf %lf %lf %lf %lf %lf", + &hop_cnt, &success_cnt, &successful_closed, + &collapsed, &unusable, &timeouts) != 6) { + int old_success, old_hops; + if (tor_sscanf(line->value, "%u %u", &old_success, &old_hops) != 2) { + continue; + } + log_info(LD_GENERAL, "Reading old-style EntryGuardPathBias %s", + escaped(line->value)); + + success_cnt = old_success; + successful_closed = old_success; + hop_cnt = old_hops; + timeouts = 0; + collapsed = 0; + unusable = 0; + } + + if (hop_cnt < success_cnt) { + int severity = LOG_INFO; + /* If this state file was written by a Tor that would have + * already fixed it, then the overcounting bug is still there.. */ + if (tor_version_as_new_as(state_version, "0.2.4.13-alpha")) { + severity = LOG_NOTICE; + } + log_fn(severity, LD_BUG, + "State file contains unexpectedly high success counts " + "%lf/%lf for Guard %s ($%s)", + success_cnt, hop_cnt, + node->nickname, hex_str(node->identity, DIGEST_LEN)); + success_cnt = hop_cnt; + } + + node->circ_attempts = hop_cnt; + node->circ_successes = success_cnt; + + node->successful_circuits_closed = successful_closed; + node->timeouts = timeouts; + node->collapsed_circuits = collapsed; + node->unusable_circuits = unusable; + + log_info(LD_GENERAL, "Read %f/%f path bias for node %s", + node->circ_successes, node->circ_attempts, node->nickname); + /* Note: We rely on the < comparison here to allow us to set a 0 + * rate and disable the feature entirely. If refactoring, don't + * change to <= */ + if (pathbias_get_close_success_count(node)/node->circ_attempts + < pathbias_get_extreme_rate(options) && + pathbias_get_dropguards(options)) { + node->path_bias_disabled = 1; + log_info(LD_GENERAL, + "Path bias is too high (%f/%f); disabling node %s", + node->circ_successes, node->circ_attempts, node->nickname); + } + + } else { + log_warn(LD_BUG, "Unexpected key %s", line->key); + } + } + + SMARTLIST_FOREACH_BEGIN(new_entry_guards, entry_guard_t *, e) { + char *sp; + char *val = digestmap_get(added_by, e->identity); + if (val && (sp = strchr(val, ' '))) { + time_t when; + *sp++ = '\0'; + if (parse_iso_time(sp, &when)<0) { + log_warn(LD_BUG, "Can't read time %s in EntryGuardAddedBy", sp); + } else { + e->chosen_by_version = tor_strdup(val); + e->chosen_on_date = when; + } + } else { + if (state_version) { + e->chosen_by_version = tor_strdup(state_version); + e->chosen_on_date = time(NULL) - crypto_rand_int(3600*24*30); + } + } + if (e->path_bias_disabled && !e->bad_since) + e->bad_since = time(NULL); + } + SMARTLIST_FOREACH_END(e); + + if (*msg || !set) { + SMARTLIST_FOREACH(new_entry_guards, entry_guard_t *, e, + entry_guard_free(e)); + smartlist_free(new_entry_guards); + } else { /* !err && set */ + if (entry_guards) { + SMARTLIST_FOREACH(entry_guards, entry_guard_t *, e, + entry_guard_free(e)); + smartlist_free(entry_guards); + } + entry_guards = new_entry_guards; + entry_guards_dirty = 0; + /* XXX024 hand new_entry_guards to this func, and move it up a + * few lines, so we don't have to re-dirty it */ + if (remove_obsolete_entry_guards(now)) + entry_guards_dirty = 1; + + update_node_guard_status(); + } + digestmap_free(added_by, tor_free_); + return *msg ? -1 : 0; +} + +/** Our list of entry guards has changed, or some element of one + * of our entry guards has changed. Write the changes to disk within + * the next few minutes. + */ +void +entry_guards_changed(void) +{ + time_t when; + entry_guards_dirty = 1; + + /* or_state_save() will call entry_guards_update_state(). */ + when = get_options()->AvoidDiskWrites ? time(NULL) + 3600 : time(NULL)+600; + or_state_mark_dirty(get_or_state(), when); +} + +/** If the entry guard info has not changed, do nothing and return. + * Otherwise, free the EntryGuards piece of state and create + * a new one out of the global entry_guards list, and then mark + * state dirty so it will get saved to disk. + */ +void +entry_guards_update_state(or_state_t *state) +{ + config_line_t **next, *line; + if (! entry_guards_dirty) + return; + + config_free_lines(state->EntryGuards); + next = &state->EntryGuards; + *next = NULL; + if (!entry_guards) + entry_guards = smartlist_new(); + SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, e) { + char dbuf[HEX_DIGEST_LEN+1]; + if (!e->made_contact) + continue; /* don't write this one to disk */ + *next = line = tor_malloc_zero(sizeof(config_line_t)); + line->key = tor_strdup("EntryGuard"); + base16_encode(dbuf, sizeof(dbuf), e->identity, DIGEST_LEN); + tor_asprintf(&line->value, "%s %s %sDirCache", e->nickname, dbuf, + e->is_dir_cache ? "" : "No"); + next = &(line->next); + if (e->unreachable_since) { + *next = line = tor_malloc_zero(sizeof(config_line_t)); + line->key = tor_strdup("EntryGuardDownSince"); + line->value = tor_malloc(ISO_TIME_LEN+1+ISO_TIME_LEN+1); + format_iso_time(line->value, e->unreachable_since); + if (e->last_attempted) { + line->value[ISO_TIME_LEN] = ' '; + format_iso_time(line->value+ISO_TIME_LEN+1, e->last_attempted); + } + next = &(line->next); + } + if (e->bad_since) { + *next = line = tor_malloc_zero(sizeof(config_line_t)); + line->key = tor_strdup("EntryGuardUnlistedSince"); + line->value = tor_malloc(ISO_TIME_LEN+1); + format_iso_time(line->value, e->bad_since); + next = &(line->next); + } + if (e->chosen_on_date && e->chosen_by_version && + !strchr(e->chosen_by_version, ' ')) { + char d[HEX_DIGEST_LEN+1]; + char t[ISO_TIME_LEN+1]; + *next = line = tor_malloc_zero(sizeof(config_line_t)); + line->key = tor_strdup("EntryGuardAddedBy"); + base16_encode(d, sizeof(d), e->identity, DIGEST_LEN); + format_iso_time(t, e->chosen_on_date); + tor_asprintf(&line->value, "%s %s %s", + d, e->chosen_by_version, t); + next = &(line->next); + } + if (e->circ_attempts > 0) { + *next = line = tor_malloc_zero(sizeof(config_line_t)); + line->key = tor_strdup("EntryGuardPathBias"); + /* In the long run: circuit_success ~= successful_circuit_close + + * collapsed_circuits + + * unusable_circuits */ + tor_asprintf(&line->value, "%f %f %f %f %f %f", + e->circ_attempts, e->circ_successes, + pathbias_get_close_success_count(e), + e->collapsed_circuits, + e->unusable_circuits, e->timeouts); + next = &(line->next); + } + if (e->use_attempts > 0) { + *next = line = tor_malloc_zero(sizeof(config_line_t)); + line->key = tor_strdup("EntryGuardPathUseBias"); + + tor_asprintf(&line->value, "%f %f", + e->use_attempts, + pathbias_get_use_success_count(e)); + next = &(line->next); + } + + } SMARTLIST_FOREACH_END(e); + if (!get_options()->AvoidDiskWrites) + or_state_mark_dirty(get_or_state(), 0); + entry_guards_dirty = 0; +} + +/** If question is the string "entry-guards", then dump + * to *answer a newly allocated string describing all of + * the nodes in the global entry_guards list. See control-spec.txt + * for details. + * For backward compatibility, we also handle the string "helper-nodes". + * */ +int +getinfo_helper_entry_guards(control_connection_t *conn, + const char *question, char **answer, + const char **errmsg) +{ + (void) conn; + (void) errmsg; + + if (!strcmp(question,"entry-guards") || + !strcmp(question,"helper-nodes")) { + smartlist_t *sl = smartlist_new(); + char tbuf[ISO_TIME_LEN+1]; + char nbuf[MAX_VERBOSE_NICKNAME_LEN+1]; + if (!entry_guards) + entry_guards = smartlist_new(); + SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, e) { + const char *status = NULL; + time_t when = 0; + const node_t *node; + + if (!e->made_contact) { + status = "never-connected"; + } else if (e->bad_since) { + when = e->bad_since; + status = "unusable"; + } else { + status = "up"; + } + + node = node_get_by_id(e->identity); + if (node) { + node_get_verbose_nickname(node, nbuf); + } else { + nbuf[0] = '$'; + base16_encode(nbuf+1, sizeof(nbuf)-1, e->identity, DIGEST_LEN); + /* e->nickname field is not very reliable if we don't know about + * this router any longer; don't include it. */ + } + + if (when) { + format_iso_time(tbuf, when); + smartlist_add_asprintf(sl, "%s %s %s\n", nbuf, status, tbuf); + } else { + smartlist_add_asprintf(sl, "%s %s\n", nbuf, status); + } + } SMARTLIST_FOREACH_END(e); + *answer = smartlist_join_strings(sl, "", 0, NULL); + SMARTLIST_FOREACH(sl, char *, c, tor_free(c)); + smartlist_free(sl); + } + return 0; +} + +/** A list of configured bridges. Whenever we actually get a descriptor + * for one, we add it as an entry guard. Note that the order of bridges + * in this list does not necessarily correspond to the order of bridges + * in the torrc. */ +static smartlist_t *bridge_list = NULL; + +/** Mark every entry of the bridge list to be removed on our next call to + * sweep_bridge_list unless it has first been un-marked. */ +void +mark_bridge_list(void) +{ + if (!bridge_list) + bridge_list = smartlist_new(); + SMARTLIST_FOREACH(bridge_list, bridge_info_t *, b, + b->marked_for_removal = 1); +} + +/** Remove every entry of the bridge list that was marked with + * mark_bridge_list if it has not subsequently been un-marked. */ +void +sweep_bridge_list(void) +{ + if (!bridge_list) + bridge_list = smartlist_new(); + SMARTLIST_FOREACH_BEGIN(bridge_list, bridge_info_t *, b) { + if (b->marked_for_removal) { + SMARTLIST_DEL_CURRENT(bridge_list, b); + bridge_free(b); + } + } SMARTLIST_FOREACH_END(b); +} + +/** Initialize the bridge list to empty, creating it if needed. */ +static void +clear_bridge_list(void) +{ + if (!bridge_list) + bridge_list = smartlist_new(); + SMARTLIST_FOREACH(bridge_list, bridge_info_t *, b, bridge_free(b)); + smartlist_clear(bridge_list); +} + +/** Free the bridge bridge. */ +static void +bridge_free(bridge_info_t *bridge) +{ + if (!bridge) + return; + + tor_free(bridge->transport_name); + if (bridge->socks_args) { + SMARTLIST_FOREACH(bridge->socks_args, char*, s, tor_free(s)); + smartlist_free(bridge->socks_args); + } + + tor_free(bridge); +} + +/** If we have a bridge configured whose digest matches digest, or a + * bridge with no known digest whose address matches any of the + * tor_addr_port_t's in orports, return that bridge. Else return + * NULL. */ +static bridge_info_t * +get_configured_bridge_by_orports_digest(const char *digest, + const smartlist_t *orports) +{ + if (!bridge_list) + return NULL; + SMARTLIST_FOREACH_BEGIN(bridge_list, bridge_info_t *, bridge) + { + if (tor_digest_is_zero(bridge->identity)) { + SMARTLIST_FOREACH_BEGIN(orports, tor_addr_port_t *, ap) + { + if (tor_addr_compare(&bridge->addr, &ap->addr, CMP_EXACT) == 0 && + bridge->port == ap->port) + return bridge; + } + SMARTLIST_FOREACH_END(ap); + } + if (digest && tor_memeq(bridge->identity, digest, DIGEST_LEN)) + return bridge; + } + SMARTLIST_FOREACH_END(bridge); + return NULL; +} + +/** If we have a bridge configured whose digest matches digest, or a + * bridge with no known digest whose address matches addr:/port, + * return that bridge. Else return NULL. If digest is NULL, check for + * address/port matches only. */ +static bridge_info_t * +get_configured_bridge_by_addr_port_digest(const tor_addr_t *addr, + uint16_t port, + const char *digest) +{ + if (!bridge_list) + return NULL; + SMARTLIST_FOREACH_BEGIN(bridge_list, bridge_info_t *, bridge) + { + if ((tor_digest_is_zero(bridge->identity) || digest == NULL) && + !tor_addr_compare(&bridge->addr, addr, CMP_EXACT) && + bridge->port == port) + return bridge; + if (digest && tor_memeq(bridge->identity, digest, DIGEST_LEN)) + return bridge; + } + SMARTLIST_FOREACH_END(bridge); + return NULL; +} + +/** Wrapper around get_configured_bridge_by_addr_port_digest() to look + * it up via router descriptor ri. */ +static bridge_info_t * +get_configured_bridge_by_routerinfo(const routerinfo_t *ri) +{ + bridge_info_t *bi = NULL; + smartlist_t *orports = router_get_all_orports(ri); + bi = get_configured_bridge_by_orports_digest(ri->cache_info.identity_digest, + orports); + SMARTLIST_FOREACH(orports, tor_addr_port_t *, p, tor_free(p)); + smartlist_free(orports); + return bi; +} + +/** Return 1 if ri is one of our known bridges, else 0. */ +int +routerinfo_is_a_configured_bridge(const routerinfo_t *ri) +{ + return get_configured_bridge_by_routerinfo(ri) ? 1 : 0; +} + +/** Return 1 if node is one of our configured bridges, else 0. */ +int +node_is_a_configured_bridge(const node_t *node) +{ + int retval = 0; + smartlist_t *orports = node_get_all_orports(node); + retval = get_configured_bridge_by_orports_digest(node->identity, + orports) != NULL; + SMARTLIST_FOREACH(orports, tor_addr_port_t *, p, tor_free(p)); + smartlist_free(orports); + return retval; +} + +/** We made a connection to a router at addr:port + * without knowing its digest. Its digest turned out to be digest. + * If it was a bridge, and we still don't know its digest, record it. + */ +void +learned_router_identity(const tor_addr_t *addr, uint16_t port, + const char *digest) +{ + bridge_info_t *bridge = + get_configured_bridge_by_addr_port_digest(addr, port, digest); + if (bridge && tor_digest_is_zero(bridge->identity)) { + char *transport_info = NULL; + const char *transport_name = + find_transport_name_by_bridge_addrport(addr, port); + if (transport_name) + tor_asprintf(&transport_info, " (with transport '%s')", transport_name); + + memcpy(bridge->identity, digest, DIGEST_LEN); + log_notice(LD_DIR, "Learned fingerprint %s for bridge %s%s.", + hex_str(digest, DIGEST_LEN), fmt_addrport(addr, port), + transport_info ? transport_info : ""); + tor_free(transport_info); + } +} + +/** Return true if bridge has the same identity digest as + * digest. If digest is NULL, it matches + * bridges with unspecified identity digests. */ +static int +bridge_has_digest(const bridge_info_t *bridge, const char *digest) +{ + if (digest) + return tor_memeq(digest, bridge->identity, DIGEST_LEN); + else + return tor_digest_is_zero(bridge->identity); +} + +/** We are about to add a new bridge at addr:port, with optional + * digest and transport_name. Mark for removal any previously + * existing bridge with the same address and port, and warn the user as + * appropriate. + */ +static void +bridge_resolve_conflicts(const tor_addr_t *addr, uint16_t port, + const char *digest, const char *transport_name) +{ + /* Iterate the already-registered bridge list: + + If you find a bridge with the same adress and port, mark it for + removal. It doesn't make sense to have two active bridges with + the same IP:PORT. If the bridge in question has a different + digest or transport than digest/transport_name, + it's probably a misconfiguration and we should warn the user. + */ + SMARTLIST_FOREACH_BEGIN(bridge_list, bridge_info_t *, bridge) { + if (bridge->marked_for_removal) + continue; + + if (tor_addr_eq(&bridge->addr, addr) && (bridge->port == port)) { + + bridge->marked_for_removal = 1; + + if (!bridge_has_digest(bridge, digest) || + strcmp_opt(bridge->transport_name, transport_name)) { + /* warn the user */ + char *bridge_description_new, *bridge_description_old; + tor_asprintf(&bridge_description_new, "%s:%s:%s", + fmt_addrport(addr, port), + digest ? hex_str(digest, DIGEST_LEN) : "", + transport_name ? transport_name : ""); + tor_asprintf(&bridge_description_old, "%s:%s:%s", + fmt_addrport(&bridge->addr, bridge->port), + tor_digest_is_zero(bridge->identity) ? + "" : hex_str(bridge->identity,DIGEST_LEN), + bridge->transport_name ? bridge->transport_name : ""); + + log_warn(LD_GENERAL,"Tried to add bridge '%s', but we found a conflict" + " with the already registered bridge '%s'. We will discard" + " the old bridge and keep '%s'. If this is not what you" + " wanted, please change your configuration file accordingly.", + bridge_description_new, bridge_description_old, + bridge_description_new); + + tor_free(bridge_description_new); + tor_free(bridge_description_old); + } + } + } SMARTLIST_FOREACH_END(bridge); +} + +/** Return True if we have a bridge that uses a transport with name + * transport_name. */ +int +transport_is_needed(const char *transport_name) +{ + if (!bridge_list) + return 0; + + SMARTLIST_FOREACH_BEGIN(bridge_list, const bridge_info_t *, bridge) { + if (bridge->transport_name && + !strcmp(bridge->transport_name, transport_name)) + return 1; + } SMARTLIST_FOREACH_END(bridge); + + return 0; +} + +/** Register the bridge information in bridge_line to the + * bridge subsystem. Steals reference of bridge_line. */ +void +bridge_add_from_config(bridge_line_t *bridge_line) +{ + bridge_info_t *b; + + { /* Log the bridge we are about to register: */ + log_debug(LD_GENERAL, "Registering bridge at %s (transport: %s) (%s)", + fmt_addrport(&bridge_line->addr, bridge_line->port), + bridge_line->transport_name ? + bridge_line->transport_name : "no transport", + tor_digest_is_zero(bridge_line->digest) ? + "no key listed" : hex_str(bridge_line->digest, DIGEST_LEN)); + + if (bridge_line->socks_args) { /* print socks arguments */ + int i = 0; + + tor_assert(smartlist_len(bridge_line->socks_args) > 0); + + log_debug(LD_GENERAL, "Bridge uses %d SOCKS arguments:", + smartlist_len(bridge_line->socks_args)); + SMARTLIST_FOREACH(bridge_line->socks_args, const char *, arg, + log_debug(LD_CONFIG, "%d: %s", ++i, arg)); + } + } + + bridge_resolve_conflicts(&bridge_line->addr, + bridge_line->port, + bridge_line->digest, + bridge_line->transport_name); + + b = tor_malloc_zero(sizeof(bridge_info_t)); + tor_addr_copy(&b->addr, &bridge_line->addr); + b->port = bridge_line->port; + memcpy(b->identity, bridge_line->digest, DIGEST_LEN); + if (bridge_line->transport_name) + b->transport_name = bridge_line->transport_name; + b->fetch_status.schedule = DL_SCHED_BRIDGE; + b->socks_args = bridge_line->socks_args; + if (!bridge_list) + bridge_list = smartlist_new(); + + tor_free(bridge_line); /* Deallocate bridge_line now. */ + + smartlist_add(bridge_list, b); +} + +/** Return true iff routerset contains the bridge bridge. */ +static int +routerset_contains_bridge(const routerset_t *routerset, + const bridge_info_t *bridge) +{ + int result; + extend_info_t *extinfo; + tor_assert(bridge); + if (!routerset) + return 0; + + extinfo = extend_info_new( + NULL, bridge->identity, NULL, NULL, &bridge->addr, bridge->port); + result = routerset_contains_extendinfo(routerset, extinfo); + extend_info_free(extinfo); + return result; +} + +/** If digest is one of our known bridges, return it. */ +static bridge_info_t * +find_bridge_by_digest(const char *digest) +{ + SMARTLIST_FOREACH(bridge_list, bridge_info_t *, bridge, + { + if (tor_memeq(bridge->identity, digest, DIGEST_LEN)) + return bridge; + }); + return NULL; +} + +/** Given the addr and port of a bridge, if that bridge + * supports a pluggable transport, return its name. Otherwise, return + * NULL. */ +const char * +find_transport_name_by_bridge_addrport(const tor_addr_t *addr, uint16_t port) +{ + if (!bridge_list) + return NULL; + + SMARTLIST_FOREACH_BEGIN(bridge_list, const bridge_info_t *, bridge) { + if (tor_addr_eq(&bridge->addr, addr) && + (bridge->port == port)) + return bridge->transport_name; + } SMARTLIST_FOREACH_END(bridge); + + return NULL; +} + +/** If addr and port match the address and port of a + * bridge of ours that uses pluggable transports, place its transport + * in transport. + * + * Return 0 on success (found a transport, or found a bridge with no + * transport, or found no bridge); return -1 if we should be using a + * transport, but the transport could not be found. + */ +int +get_transport_by_bridge_addrport(const tor_addr_t *addr, uint16_t port, + const transport_t **transport) +{ + *transport = NULL; + if (!bridge_list) + return 0; + + SMARTLIST_FOREACH_BEGIN(bridge_list, const bridge_info_t *, bridge) { + if (tor_addr_eq(&bridge->addr, addr) && + (bridge->port == port)) { /* bridge matched */ + if (bridge->transport_name) { /* it also uses pluggable transports */ + *transport = transport_get_by_name(bridge->transport_name); + if (*transport == NULL) { /* it uses pluggable transports, but + the transport could not be found! */ + return -1; + } + return 0; + } else { /* bridge matched, but it doesn't use transports. */ + break; + } + } + } SMARTLIST_FOREACH_END(bridge); + + *transport = NULL; + return 0; +} + +/** Return a smartlist containing all the SOCKS arguments that we + * should pass to the SOCKS proxy. */ +const smartlist_t * +get_socks_args_by_bridge_addrport(const tor_addr_t *addr, uint16_t port) +{ + bridge_info_t *bridge = get_configured_bridge_by_addr_port_digest(addr, + port, + NULL); + return bridge ? bridge->socks_args : NULL; +} + +/** We need to ask bridge for its server descriptor. */ +static void +launch_direct_bridge_descriptor_fetch(bridge_info_t *bridge) +{ + char *address; + const or_options_t *options = get_options(); + + if (connection_get_by_type_addr_port_purpose( + CONN_TYPE_DIR, &bridge->addr, bridge->port, + DIR_PURPOSE_FETCH_SERVERDESC)) + return; /* it's already on the way */ + + if (routerset_contains_bridge(options->ExcludeNodes, bridge)) { + download_status_mark_impossible(&bridge->fetch_status); + log_warn(LD_APP, "Not using bridge at %s: it is in ExcludeNodes.", + safe_str_client(fmt_and_decorate_addr(&bridge->addr))); + return; + } + + address = tor_dup_addr(&bridge->addr); + + directory_initiate_command(address, &bridge->addr, + bridge->port, 0/*no dirport*/, + bridge->identity, + DIR_PURPOSE_FETCH_SERVERDESC, + ROUTER_PURPOSE_BRIDGE, + DIRIND_ONEHOP, "authority.z", NULL, 0, 0); + tor_free(address); +} + +/** Fetching the bridge descriptor from the bridge authority returned a + * "not found". Fall back to trying a direct fetch. */ +void +retry_bridge_descriptor_fetch_directly(const char *digest) +{ + bridge_info_t *bridge = find_bridge_by_digest(digest); + if (!bridge) + return; /* not found? oh well. */ + + launch_direct_bridge_descriptor_fetch(bridge); +} + +/** For each bridge in our list for which we don't currently have a + * descriptor, fetch a new copy of its descriptor -- either directly + * from the bridge or via a bridge authority. */ +void +fetch_bridge_descriptors(const or_options_t *options, time_t now) +{ + int num_bridge_auths = get_n_authorities(BRIDGE_DIRINFO); + int ask_bridge_directly; + int can_use_bridge_authority; + + if (!bridge_list) + return; + + /* If we still have unconfigured managed proxies, don't go and + connect to a bridge. */ + if (pt_proxies_configuration_pending()) + return; + + SMARTLIST_FOREACH_BEGIN(bridge_list, bridge_info_t *, bridge) + { + if (!download_status_is_ready(&bridge->fetch_status, now, + IMPOSSIBLE_TO_DOWNLOAD)) + continue; /* don't bother, no need to retry yet */ + if (routerset_contains_bridge(options->ExcludeNodes, bridge)) { + download_status_mark_impossible(&bridge->fetch_status); + log_warn(LD_APP, "Not using bridge at %s: it is in ExcludeNodes.", + safe_str_client(fmt_and_decorate_addr(&bridge->addr))); + continue; + } + + /* schedule another fetch as if this one will fail, in case it does */ + download_status_failed(&bridge->fetch_status, 0); + + can_use_bridge_authority = !tor_digest_is_zero(bridge->identity) && + num_bridge_auths; + ask_bridge_directly = !can_use_bridge_authority || + !options->UpdateBridgesFromAuthority; + log_debug(LD_DIR, "ask_bridge_directly=%d (%d, %d, %d)", + ask_bridge_directly, tor_digest_is_zero(bridge->identity), + !options->UpdateBridgesFromAuthority, !num_bridge_auths); + + if (ask_bridge_directly && + !fascist_firewall_allows_address_or(&bridge->addr, bridge->port)) { + log_notice(LD_DIR, "Bridge at '%s' isn't reachable by our " + "firewall policy. %s.", + fmt_addrport(&bridge->addr, bridge->port), + can_use_bridge_authority ? + "Asking bridge authority instead" : "Skipping"); + if (can_use_bridge_authority) + ask_bridge_directly = 0; + else + continue; + } + + if (ask_bridge_directly) { + /* we need to ask the bridge itself for its descriptor. */ + launch_direct_bridge_descriptor_fetch(bridge); + } else { + /* We have a digest and we want to ask an authority. We could + * combine all the requests into one, but that may give more + * hints to the bridge authority than we want to give. */ + char resource[10 + HEX_DIGEST_LEN]; + memcpy(resource, "fp/", 3); + base16_encode(resource+3, HEX_DIGEST_LEN+1, + bridge->identity, DIGEST_LEN); + memcpy(resource+3+HEX_DIGEST_LEN, ".z", 3); + log_info(LD_DIR, "Fetching bridge info '%s' from bridge authority.", + resource); + directory_get_from_dirserver(DIR_PURPOSE_FETCH_SERVERDESC, + ROUTER_PURPOSE_BRIDGE, resource, 0); + } + } + SMARTLIST_FOREACH_END(bridge); +} + +/** If our bridge is configured to be a different address than + * the bridge gives in node, rewrite the routerinfo + * we received to use the address we meant to use. Now we handle + * multihomed bridges better. + */ +static void +rewrite_node_address_for_bridge(const bridge_info_t *bridge, node_t *node) +{ + /* XXXX move this function. */ + /* XXXX overridden addresses should really live in the node_t, so that the + * routerinfo_t and the microdesc_t can be immutable. But we can only + * do that safely if we know that no function that connects to an OR + * does so through an address from any source other than node_get_addr(). + */ + tor_addr_t addr; + + if (node->ri) { + routerinfo_t *ri = node->ri; + tor_addr_from_ipv4h(&addr, ri->addr); + + if ((!tor_addr_compare(&bridge->addr, &addr, CMP_EXACT) && + bridge->port == ri->or_port) || + (!tor_addr_compare(&bridge->addr, &ri->ipv6_addr, CMP_EXACT) && + bridge->port == ri->ipv6_orport)) { + /* they match, so no need to do anything */ + } else { + if (tor_addr_family(&bridge->addr) == AF_INET) { + ri->addr = tor_addr_to_ipv4h(&bridge->addr); + tor_free(ri->address); + ri->address = tor_dup_ip(ri->addr); + ri->or_port = bridge->port; + log_info(LD_DIR, + "Adjusted bridge routerinfo for '%s' to match configured " + "address %s:%d.", + ri->nickname, ri->address, ri->or_port); + } else if (tor_addr_family(&bridge->addr) == AF_INET6) { + tor_addr_copy(&ri->ipv6_addr, &bridge->addr); + ri->ipv6_orport = bridge->port; + log_info(LD_DIR, + "Adjusted bridge routerinfo for '%s' to match configured " + "address %s.", + ri->nickname, fmt_addrport(&ri->ipv6_addr, ri->ipv6_orport)); + } else { + log_err(LD_BUG, "Address family not supported: %d.", + tor_addr_family(&bridge->addr)); + return; + } + } + + /* Mark which address to use based on which bridge_t we got. */ + node->ipv6_preferred = (tor_addr_family(&bridge->addr) == AF_INET6 && + !tor_addr_is_null(&node->ri->ipv6_addr)); + + /* XXXipv6 we lack support for falling back to another address for + the same relay, warn the user */ + if (!tor_addr_is_null(&ri->ipv6_addr)) { + tor_addr_port_t ap; + node_get_pref_orport(node, &ap); + log_notice(LD_CONFIG, + "Bridge '%s' has both an IPv4 and an IPv6 address. " + "Will prefer using its %s address (%s).", + ri->nickname, + tor_addr_family(&ap.addr) == AF_INET6 ? "IPv6" : "IPv4", + fmt_addrport(&ap.addr, ap.port)); + } + } + if (node->rs) { + routerstatus_t *rs = node->rs; + tor_addr_from_ipv4h(&addr, rs->addr); + + if (!tor_addr_compare(&bridge->addr, &addr, CMP_EXACT) && + bridge->port == rs->or_port) { + /* they match, so no need to do anything */ + } else { + rs->addr = tor_addr_to_ipv4h(&bridge->addr); + rs->or_port = bridge->port; + log_info(LD_DIR, + "Adjusted bridge routerstatus for '%s' to match " + "configured address %s.", + rs->nickname, fmt_addrport(&bridge->addr, rs->or_port)); + } + } +} + +/** We just learned a descriptor for a bridge. See if that + * digest is in our entry guard list, and add it if not. */ +void +learned_bridge_descriptor(routerinfo_t *ri, int from_cache) +{ + tor_assert(ri); + tor_assert(ri->purpose == ROUTER_PURPOSE_BRIDGE); + if (get_options()->UseBridges) { + int first = !any_bridge_descriptors_known(); + bridge_info_t *bridge = get_configured_bridge_by_routerinfo(ri); + time_t now = time(NULL); + router_set_status(ri->cache_info.identity_digest, 1); + + if (bridge) { /* if we actually want to use this one */ + node_t *node; + /* it's here; schedule its re-fetch for a long time from now. */ + if (!from_cache) + download_status_reset(&bridge->fetch_status); + + node = node_get_mutable_by_id(ri->cache_info.identity_digest); + tor_assert(node); + rewrite_node_address_for_bridge(bridge, node); + add_an_entry_guard(node, 1, 1, 0, 0); + + log_notice(LD_DIR, "new bridge descriptor '%s' (%s): %s", ri->nickname, + from_cache ? "cached" : "fresh", router_describe(ri)); + /* set entry->made_contact so if it goes down we don't drop it from + * our entry node list */ + entry_guard_register_connect_status(ri->cache_info.identity_digest, + 1, 0, now); + if (first) + routerlist_retry_directory_downloads(now); + } + } +} + +/** Return 1 if any of our entry guards have descriptors that + * are marked with purpose 'bridge' and are running. Else return 0. + * + * We use this function to decide if we're ready to start building + * circuits through our bridges, or if we need to wait until the + * directory "server/authority" requests finish. */ +int +any_bridge_descriptors_known(void) +{ + tor_assert(get_options()->UseBridges); + return choose_random_entry(NULL) != NULL; +} + +/** Return 1 if there are any directory conns fetching bridge descriptors + * that aren't marked for close. We use this to guess if we should tell + * the controller that we have a problem. */ +int +any_pending_bridge_descriptor_fetches(void) +{ + smartlist_t *conns = get_connection_array(); + SMARTLIST_FOREACH_BEGIN(conns, connection_t *, conn) { + if (conn->type == CONN_TYPE_DIR && + conn->purpose == DIR_PURPOSE_FETCH_SERVERDESC && + TO_DIR_CONN(conn)->router_purpose == ROUTER_PURPOSE_BRIDGE && + !conn->marked_for_close && + conn->linked && + conn->linked_conn && !conn->linked_conn->marked_for_close) { + log_debug(LD_DIR, "found one: %s", conn->address); + return 1; + } + } SMARTLIST_FOREACH_END(conn); + return 0; +} + +/** Return 1 if we have at least one descriptor for an entry guard + * (bridge or member of EntryNodes) and all descriptors we know are + * down. Else return 0. If act is 1, then mark the down guards + * up; else just observe and report. */ +static int +entries_retry_helper(const or_options_t *options, int act) +{ + const node_t *node; + int any_known = 0; + int any_running = 0; + int need_bridges = options->UseBridges != 0; + if (!entry_guards) + entry_guards = smartlist_new(); + SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, e) { + node = node_get_by_id(e->identity); + if (node && node_has_descriptor(node) && + node_is_bridge(node) == need_bridges) { + any_known = 1; + if (node->is_running) + any_running = 1; /* some entry is both known and running */ + else if (act) { + /* Mark all current connections to this OR as unhealthy, since + * otherwise there could be one that started 30 seconds + * ago, and in 30 seconds it will time out, causing us to mark + * the node down and undermine the retry attempt. We mark even + * the established conns, since if the network just came back + * we'll want to attach circuits to fresh conns. */ + connection_or_set_bad_connections(node->identity, 1); + + /* mark this entry node for retry */ + router_set_status(node->identity, 1); + e->can_retry = 1; + e->bad_since = 0; + } + } + } SMARTLIST_FOREACH_END(e); + log_debug(LD_DIR, "%d: any_known %d, any_running %d", + act, any_known, any_running); + return any_known && !any_running; +} + +/** Do we know any descriptors for our bridges / entrynodes, and are + * all the ones we have descriptors for down? */ +int +entries_known_but_down(const or_options_t *options) +{ + tor_assert(entry_list_is_constrained(options)); + return entries_retry_helper(options, 0); +} + +/** Mark all down known bridges / entrynodes up. */ +void +entries_retry_all(const or_options_t *options) +{ + tor_assert(entry_list_is_constrained(options)); + entries_retry_helper(options, 1); +} + +/** Return true if at least one of our bridges runs a Tor version that can + * provide microdescriptors to us. If not, we'll fall back to asking for + * full descriptors. */ +int +any_bridge_supports_microdescriptors(void) +{ + const node_t *node; + if (!get_options()->UseBridges || !entry_guards) + return 0; + SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, e) { + node = node_get_by_id(e->identity); + if (node && node->is_running && + node_is_bridge(node) && node_is_a_configured_bridge(node) && + node_understands_microdescriptors(node)) { + /* This is one of our current bridges, and we know enough about + * it to know that it will be able to answer our microdescriptor + * questions. */ + return 1; + } + } SMARTLIST_FOREACH_END(e); + return 0; +} + +/** Release all storage held by the list of entry guards and related + * memory structs. */ +void +entry_guards_free_all(void) +{ + if (entry_guards) { + SMARTLIST_FOREACH(entry_guards, entry_guard_t *, e, + entry_guard_free(e)); + smartlist_free(entry_guards); + entry_guards = NULL; + } + clear_bridge_list(); + smartlist_free(bridge_list); + bridge_list = NULL; + circuit_build_times_free_timeouts(get_circuit_build_times_mutable()); +} + diff --git a/src/tor/entrynodes.h b/src/tor/entrynodes.h new file mode 100644 index 0000000..772c666 --- /dev/null +++ b/src/tor/entrynodes.h @@ -0,0 +1,133 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file guardnodes.h + * \brief Header file for circuitbuild.c. + **/ + +#ifndef TOR_ENTRYNODES_H +#define TOR_ENTRYNODES_H + +#if 1 +/* XXXX NM I would prefer that all of this stuff be private to + * entrynodes.c. */ + +/** An entry_guard_t represents our information about a chosen long-term + * first hop, known as a "helper" node in the literature. We can't just + * use a node_t, since we want to remember these even when we + * don't have any directory info. */ +typedef struct entry_guard_t { + char nickname[MAX_NICKNAME_LEN+1]; + char identity[DIGEST_LEN]; + time_t chosen_on_date; /**< Approximately when was this guard added? + * "0" if we don't know. */ + char *chosen_by_version; /**< What tor version added this guard? NULL + * if we don't know. */ + unsigned int made_contact : 1; /**< 0 if we have never connected to this + * router, 1 if we have. */ + unsigned int can_retry : 1; /**< Should we retry connecting to this entry, + * in spite of having it marked as unreachable?*/ + unsigned int path_bias_noticed : 1; /**< Did we alert the user about path + * bias for this node already? */ + unsigned int path_bias_warned : 1; /**< Did we alert the user about path bias + * for this node already? */ + unsigned int path_bias_extreme : 1; /**< Did we alert the user about path + * bias for this node already? */ + unsigned int path_bias_disabled : 1; /**< Have we disabled this node because + * of path bias issues? */ + unsigned int path_bias_use_noticed : 1; /**< Did we alert the user about path + * use bias for this node already? */ + unsigned int path_bias_use_extreme : 1; /**< Did we alert the user about path + * use bias for this node already? */ + unsigned int is_dir_cache : 1; /**< Is this node a directory cache? */ + time_t bad_since; /**< 0 if this guard is currently usable, or the time at + * which it was observed to become (according to the + * directory or the user configuration) unusable. */ + time_t unreachable_since; /**< 0 if we can connect to this guard, or the + * time at which we first noticed we couldn't + * connect to it. */ + time_t last_attempted; /**< 0 if we can connect to this guard, or the time + * at which we last failed to connect to it. */ + + double circ_attempts; /**< Number of circuits this guard has "attempted" */ + double circ_successes; /**< Number of successfully built circuits using + * this guard as first hop. */ + double successful_circuits_closed; /**< Number of circuits that carried + * streams successfully. */ + double collapsed_circuits; /**< Number of fully built circuits that were + * remotely closed before any streams were + * attempted. */ + double unusable_circuits; /**< Number of circuits for which streams were + * attempted, but none succeeded. */ + double timeouts; /**< Number of 'right-censored' circuit timeouts for this + * guard. */ + double use_attempts; /**< Number of circuits we tried to use with streams */ + double use_successes; /**< Number of successfully used circuits using + * this guard as first hop. */ +} entry_guard_t; + +entry_guard_t *entry_guard_get_by_id_digest(const char *digest); +void entry_guards_changed(void); +const smartlist_t *get_entry_guards(void); +int num_live_entry_guards(int for_directory); + +#endif + +void remove_all_entry_guards(void); + +void entry_guards_compute_status(const or_options_t *options, time_t now); +int entry_guard_register_connect_status(const char *digest, int succeeded, + int mark_relay_status, time_t now); +void entry_nodes_should_be_added(void); +int entry_list_is_constrained(const or_options_t *options); +const node_t *choose_random_entry(cpath_build_state_t *state); +const node_t *choose_random_dirguard(dirinfo_type_t t); +int entry_guards_parse_state(or_state_t *state, int set, char **msg); +void entry_guards_update_state(or_state_t *state); +int getinfo_helper_entry_guards(control_connection_t *conn, + const char *question, char **answer, + const char **errmsg); + +void mark_bridge_list(void); +void sweep_bridge_list(void); + +int routerinfo_is_a_configured_bridge(const routerinfo_t *ri); +int node_is_a_configured_bridge(const node_t *node); +void learned_router_identity(const tor_addr_t *addr, uint16_t port, + const char *digest); +struct bridge_line_t; +void bridge_add_from_config(struct bridge_line_t *bridge_line); +void retry_bridge_descriptor_fetch_directly(const char *digest); +void fetch_bridge_descriptors(const or_options_t *options, time_t now); +void learned_bridge_descriptor(routerinfo_t *ri, int from_cache); +int any_bridge_descriptors_known(void); +int any_pending_bridge_descriptor_fetches(void); +int entries_known_but_down(const or_options_t *options); +void entries_retry_all(const or_options_t *options); + +int any_bridge_supports_microdescriptors(void); +const smartlist_t *get_socks_args_by_bridge_addrport(const tor_addr_t *addr, + uint16_t port); + +int any_bridges_dont_support_microdescriptors(void); + +void entry_guards_free_all(void); + +const char *find_transport_name_by_bridge_addrport(const tor_addr_t *addr, + uint16_t port); +struct transport_t; +int get_transport_by_bridge_addrport(const tor_addr_t *addr, uint16_t port, + const struct transport_t **transport); + +int transport_is_needed(const char *transport_name); +int validate_pluggable_transports_config(void); + +double pathbias_get_close_success_count(entry_guard_t *guard); +double pathbias_get_use_success_count(entry_guard_t *guard); + +#endif + diff --git a/src/tor/eventdns.h b/src/tor/eventdns.h new file mode 100644 index 0000000..ad8c100 --- /dev/null +++ b/src/tor/eventdns.h @@ -0,0 +1,337 @@ + +/* + * The original DNS code is due to Adam Langley with heavy + * modifications by Nick Mathewson. Adam put his DNS software in the + * public domain. You can find his original copyright below. Please, + * aware that the code as part of libevent is governed by the 3-clause + * BSD license above. + * + * This software is Public Domain. To view a copy of the public domain dedication, + * visit http://creativecommons.org/licenses/publicdomain/ or send a letter to + * Creative Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA. + * + * I ask and expect, but do not require, that all derivative works contain an + * attribution similar to: + * Parts developed by Adam Langley + * + * You may wish to replace the word "Parts" with something else depending on + * the amount of original code. + * + * (Derivative works does not include programs which link against, run or include + * the source verbatim in their source distributions) + */ + +/* + * Welcome, gentle reader + * + * Async DNS lookups are really a whole lot harder than they should be, + * mostly stemming from the fact that the libc resolver has never been + * very good at them. Before you use this library you should see if libc + * can do the job for you with the modern async call getaddrinfo_a + * (see http://www.imperialviolet.org/page25.html#e498). Otherwise, + * please continue. + * + * This code is based on libevent and you must call event_init before + * any of the APIs in this file. You must also seed the OpenSSL random + * source if you are using OpenSSL for ids (see below). + * + * This library is designed to be included and shipped with your source + * code. You statically link with it. You should also test for the + * existence of strtok_r and define HAVE_STRTOK_R if you have it. + * + * The DNS protocol requires a good source of id numbers and these + * numbers should be unpredictable for spoofing reasons. There are + * three methods for generating them here and you must define exactly + * one of them. In increasing order of preference: + * + * DNS_USE_GETTIMEOFDAY_FOR_ID: + * Using the bottom 16 bits of the usec result from gettimeofday. This + * is a pretty poor solution but should work anywhere. + * DNS_USE_CPU_CLOCK_FOR_ID: + * Using the bottom 16 bits of the nsec result from the CPU's time + * counter. This is better, but may not work everywhere. Requires + * POSIX realtime support and you'll need to link against -lrt on + * glibc systems at least. + * DNS_USE_OPENSSL_FOR_ID: + * Uses the OpenSSL RAND_bytes call to generate the data. You must + * have seeded the pool before making any calls to this library. + * + * The library keeps track of the state of nameservers and will avoid + * them when they go down. Otherwise it will round robin between them. + * + * Quick start guide: + * #include "evdns.h" + * void callback(int result, char type, int count, int ttl, + * void *addresses, void *arg); + * evdns_resolv_conf_parse(DNS_OPTIONS_ALL, "/etc/resolv.conf"); + * evdns_resolve("www.hostname.com", 0, callback, NULL); + * + * When the lookup is complete the callback function is called. The + * first argument will be one of the DNS_ERR_* defines in evdns.h. + * Hopefully it will be DNS_ERR_NONE, in which case type will be + * DNS_IPv4_A, count will be the number of IP addresses, ttl is the time + * which the data can be cached for (in seconds), addresses will point + * to an array of uint32_t's and arg will be whatever you passed to + * evdns_resolve. + * + * Searching: + * + * In order for this library to be a good replacement for glibc's resolver it + * supports searching. This involves setting a list of default domains, in + * which names will be queried for. The number of dots in the query name + * determines the order in which this list is used. + * + * Searching appears to be a single lookup from the point of view of the API, + * although many DNS queries may be generated from a single call to + * evdns_resolve. Searching can also drastically slow down the resolution + * of names. + * + * To disable searching: + * 1. Never set it up. If you never call evdns_resolv_conf_parse or + * evdns_search_add then no searching will occur. + * + * 2. If you do call evdns_resolv_conf_parse then don't pass + * DNS_OPTION_SEARCH (or DNS_OPTIONS_ALL, which implies it). + * + * 3. When calling evdns_resolve, pass the DNS_QUERY_NO_SEARCH flag. + * + * The order of searches depends on the number of dots in the name. If the + * number is greater than the ndots setting then the names is first tried + * globally. Otherwise each search domain is appended in turn. + * + * The ndots setting can either be set from a resolv.conf, or by calling + * evdns_search_ndots_set. + * + * For example, with ndots set to 1 (the default) and a search domain list of + * ["myhome.net"]: + * Query: www + * Order: www.myhome.net, www. + * + * Query: www.abc + * Order: www.abc., www.abc.myhome.net + * + * API reference: + * + * int evdns_nameserver_add(uint32_t address) + * Add a nameserver. The address should be an IP address in + * network byte order. The type of address is chosen so that + * it matches in_addr.s_addr. + * Returns non-zero on error. + * + * int evdns_nameserver_ip_add(const char *ip_as_string) + * This wraps the above function by parsing a string as an IP + * address and adds it as a nameserver. + * Returns non-zero on error + * + * int evdns_resolve(const char *name, int flags, + * evdns_callback_type callback, + * void *ptr) + * Resolve a name. The name parameter should be a DNS name. + * The flags parameter should be 0, or DNS_QUERY_NO_SEARCH + * which disables searching for this query. (see defn of + * searching above). + * + * The callback argument is a function which is called when + * this query completes and ptr is an argument which is passed + * to that callback function. + * + * Returns non-zero on error + * + * void evdns_search_clear() + * Clears the list of search domains + * + * void evdns_search_add(const char *domain) + * Add a domain to the list of search domains + * + * void evdns_search_ndots_set(int ndots) + * Set the number of dots which, when found in a name, causes + * the first query to be without any search domain. + * + * int evdns_count_nameservers(void) + * Return the number of configured nameservers (not necessarily the + * number of running nameservers). This is useful for double-checking + * whether our calls to the various nameserver configuration functions + * have been successful. + * + * int evdns_clear_nameservers_and_suspend(void) + * Remove all currently configured nameservers, and suspend all pending + * resolves. Resolves will not necessarily be re-attempted until + * evdns_resume() is called. + * + * int evdns_resume(void) + * Re-attempt resolves left in limbo after an earlier call to + * evdns_clear_nameservers_and_suspend(). + * + * int evdns_config_windows_nameservers(void) + * Attempt to configure a set of nameservers based on platform settings on + * a win32 host. Preferentially tries to use GetNetworkParams; if that fails, + * looks in the registry. Returns 0 on success, nonzero on failure. + * + * int evdns_resolv_conf_parse(int flags, const char *filename) + * Parse a resolv.conf like file from the given filename. + * + * See the man page for resolv.conf for the format of this file. + * The flags argument determines what information is parsed from + * this file: + * DNS_OPTION_SEARCH - domain, search and ndots options + * DNS_OPTION_NAMESERVERS - nameserver lines + * DNS_OPTION_MISC - timeout and attempts options + * DNS_OPTIONS_ALL - all of the above + * The following directives are not parsed from the file: + * sortlist, rotate, no-check-names, inet6, debug + * + * Returns non-zero on error: + * 0 no errors + * 1 failed to open file + * 2 failed to stat file + * 3 file too large + * 4 out of memory + * 5 short read from file + * 6 no nameservers in file + * + * Internals: + * + * Requests are kept in two queues. The first is the inflight queue. In + * this queue requests have an allocated transaction id and nameserver. + * They will soon be transmitted if they haven't already been. + * + * The second is the waiting queue. The size of the inflight ring is + * limited and all other requests wait in waiting queue for space. This + * bounds the number of concurrent requests so that we don't flood the + * nameserver. Several algorithms require a full walk of the inflight + * queue and so bounding its size keeps thing going nicely under huge + * (many thousands of requests) loads. + * + * If a nameserver loses too many requests it is considered down and we + * try not to use it. After a while we send a probe to that nameserver + * (a lookup for google.com) and, if it replies, we consider it working + * again. If the nameserver fails a probe we wait longer to try again + * with the next probe. + */ + +#ifndef TOR_EVENTDNS_H +#define TOR_EVENTDNS_H + +/* Error codes 0-5 are as described in RFC 1035. */ +#define DNS_ERR_NONE 0 +/* The name server was unable to interpret the query */ +#define DNS_ERR_FORMAT 1 +/* The name server was unable to process this query due to a problem with the + * name server */ +#define DNS_ERR_SERVERFAILED 2 +/* The domain name does not exist */ +#define DNS_ERR_NOTEXIST 3 +/* The name server does not support the requested kind of query */ +#define DNS_ERR_NOTIMPL 4 +/* The name server refuses to reform the specified operation for policy + * reasons */ +#define DNS_ERR_REFUSED 5 +/* The reply was truncated or ill-formated */ +#define DNS_ERR_TRUNCATED 65 +/* An unknown error occurred */ +#define DNS_ERR_UNKNOWN 66 +/* Communication with the server timed out */ +#define DNS_ERR_TIMEOUT 67 +/* The request was canceled because the DNS subsystem was shut down. */ +#define DNS_ERR_SHUTDOWN 68 + +#define DNS_IPv4_A 1 +#define DNS_PTR 2 +#define DNS_IPv6_AAAA 3 + +#define DNS_QUERY_NO_SEARCH 1 + +#define DNS_OPTION_SEARCH 1 +#define DNS_OPTION_NAMESERVERS 2 +#define DNS_OPTION_MISC 4 +#define DNS_OPTIONS_ALL 7 + +/* + * The callback that contains the results from a lookup. + * - type is either DNS_IPv4_A or DNS_IPv6_AAAA or DNS_PTR + * - count contains the number of addresses of form type + * - ttl is the number of seconds the resolution may be cached for. + * - addresses needs to be cast according to type + */ +typedef void (*evdns_callback_type) (int result, char type, int count, int ttl, void *addresses, void *arg); + +int evdns_init(void); +void evdns_shutdown(int fail_requests); +const char *evdns_err_to_string(int err); +int evdns_nameserver_add(uint32_t address); +int evdns_count_nameservers(void); +int evdns_clear_nameservers_and_suspend(void); +int evdns_resume(void); +int evdns_nameserver_ip_add(const char *ip_as_string); +int evdns_nameserver_sockaddr_add(const struct sockaddr *sa, socklen_t len); +void evdns_set_default_outgoing_bind_address(const struct sockaddr *addr, socklen_t addrlen); +int evdns_resolve_ipv4(const char *name, int flags, evdns_callback_type callback, void *ptr); +int evdns_resolve_ipv6(const char *name, int flags, evdns_callback_type callback, void *ptr); +struct in_addr; +struct in6_addr; +int evdns_resolve_reverse(const struct in_addr *in, int flags, evdns_callback_type callback, void *ptr); +int evdns_resolve_reverse_ipv6(const struct in6_addr *in, int flags, evdns_callback_type callback, void *ptr); +int evdns_set_option(const char *option, const char *val, int flags); +int evdns_resolv_conf_parse(int flags, const char *); +#ifdef _WIN32 +int evdns_config_windows_nameservers(void); +#endif +void evdns_search_clear(void); +void evdns_search_add(const char *domain); +void evdns_search_ndots_set(const int ndots); + +typedef void (*evdns_debug_log_fn_type)(int is_warning, const char *msg); +void evdns_set_log_fn(evdns_debug_log_fn_type fn); + +void evdns_set_transaction_id_fn(uint16_t (*fn)(void)); +void evdns_set_random_bytes_fn(void (*fn)(char *, size_t)); + +#define DNS_NO_SEARCH 1 + +/* Structures and functions used to implement a DNS server. */ + +struct evdns_server_request { + int flags; + int nquestions; + struct evdns_server_question **questions; +}; +struct evdns_server_question { + int type; + int dns_question_class; + char name[1]; +}; +typedef void (*evdns_request_callback_fn_type)(struct evdns_server_request *, void *); +#define EVDNS_ANSWER_SECTION 0 +#define EVDNS_AUTHORITY_SECTION 1 +#define EVDNS_ADDITIONAL_SECTION 2 + +#define EVDNS_TYPE_A 1 +#define EVDNS_TYPE_NS 2 +#define EVDNS_TYPE_CNAME 5 +#define EVDNS_TYPE_SOA 6 +#define EVDNS_TYPE_PTR 12 +#define EVDNS_TYPE_MX 15 +#define EVDNS_TYPE_TXT 16 +#define EVDNS_TYPE_AAAA 28 + +#define EVDNS_QTYPE_AXFR 252 +#define EVDNS_QTYPE_ALL 255 + +#define EVDNS_CLASS_INET 1 + +struct evdns_server_port *evdns_add_server_port(tor_socket_t socket, int is_tcp, evdns_request_callback_fn_type callback, void *user_data); +void evdns_close_server_port(struct evdns_server_port *port); + +int evdns_server_request_add_reply(struct evdns_server_request *req, int section, const char *name, int type, int class, int ttl, int datalen, int is_name, const char *data); +int evdns_server_request_add_a_reply(struct evdns_server_request *req, const char *name, int n, const void *addrs, int ttl); +int evdns_server_request_add_aaaa_reply(struct evdns_server_request *req, const char *name, int n, const void *addrs, int ttl); +int evdns_server_request_add_ptr_reply(struct evdns_server_request *req, struct in_addr *in, const char *inaddr_name, const char *hostname, int ttl); +int evdns_server_request_add_cname_reply(struct evdns_server_request *req, const char *name, const char *cname, int ttl); + +struct sockaddr; +int evdns_server_request_get_requesting_addr(struct evdns_server_request *req, struct sockaddr *sa, int addr_len); + +int evdns_server_request_respond(struct evdns_server_request *req, int err); +int evdns_server_request_drop(struct evdns_server_request *req); + +#endif // !EVENTDNS_H diff --git a/src/tor/eventdns_tor.h b/src/tor/eventdns_tor.h new file mode 100644 index 0000000..4dc3c2f --- /dev/null +++ b/src/tor/eventdns_tor.h @@ -0,0 +1,25 @@ +/* Copyright (c) 2007-2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_EVENTDNS_TOR_H +#define TOR_EVENTDNS_TOR_H + +#include "orconfig.h" +#define DNS_USE_OPENSSL_FOR_ID +#ifndef HAVE_UINT +typedef unsigned int uint; +#endif +#ifndef HAVE_U_CHAR +typedef unsigned char u_char; +#endif +#ifdef _WIN32 +#define inline __inline +#endif +#include "torint.h" + +/* These are for debugging possible memory leaks. */ +#include "tor_util.h" +#include "tor_compat.h" + +#endif + diff --git a/src/tor/ext_orport.c b/src/tor/ext_orport.c new file mode 100644 index 0000000..fcfe15c --- /dev/null +++ b/src/tor/ext_orport.c @@ -0,0 +1,648 @@ +/* Copyright (c) 2012, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file ext_orport.c + * \brief Code implementing the Extended ORPort. +*/ + +#define EXT_ORPORT_PRIVATE +#include "or.h" +#include "connection.h" +#include "connection_or.h" +#include "ext_orport.h" +#include "control.h" +#include "config.h" +#include "tor_util.h" +#include "onion_main.h" + +/** Allocate and return a structure capable of holding an Extended + * ORPort message of body length len. */ +ext_or_cmd_t * +ext_or_cmd_new(uint16_t len) +{ + size_t size = STRUCT_OFFSET(ext_or_cmd_t, body) + len; + ext_or_cmd_t *cmd = tor_malloc(size); + cmd->len = len; + return cmd; +} + +/** Deallocate the Extended ORPort message in cmd. */ +void +ext_or_cmd_free(ext_or_cmd_t *cmd) +{ + tor_free(cmd); +} + +/** Get an Extended ORPort message from conn, and place it in + * out. Return -1 on fail, 0 if we need more data, and 1 if we + * successfully extracted an Extended ORPort command from the + * buffer. */ +static int +connection_fetch_ext_or_cmd_from_buf(connection_t *conn, ext_or_cmd_t **out) +{ + IF_HAS_BUFFEREVENT(conn, { + struct evbuffer *input = bufferevent_get_input(conn->bufev); + return fetch_ext_or_command_from_evbuffer(input, out); + }) ELSE_IF_NO_BUFFEREVENT { + return fetch_ext_or_command_from_buf(conn->inbuf, out); + } +} + +/** Write an Extended ORPort message to conn. Use + * command as the command type, bodylen as the body + * length, and body, if it's present, as the body of the + * message. */ +STATIC int +connection_write_ext_or_command(connection_t *conn, + uint16_t command, + const char *body, + size_t bodylen) +{ + char header[4]; + if (bodylen > UINT16_MAX) + return -1; + set_uint16(header, htons(command)); + set_uint16(header+2, htons(bodylen)); + connection_write_to_buf(header, 4, conn); + if (bodylen) { + tor_assert(body); + connection_write_to_buf(body, bodylen, conn); + } + return 0; +} + +/** Transition from an Extended ORPort which accepts Extended ORPort + * messages, to an Extended ORport which accepts OR traffic. */ +static void +connection_ext_or_transition(or_connection_t *conn) +{ + tor_assert(conn->base_.type == CONN_TYPE_EXT_OR); + + conn->base_.type = CONN_TYPE_OR; + TO_CONN(conn)->state = 0; // set the state to a neutral value + control_event_or_conn_status(conn, OR_CONN_EVENT_NEW, 0); + connection_tls_start_handshake(conn, 1); +} + +/** Length of authentication cookie. */ +#define EXT_OR_PORT_AUTH_COOKIE_LEN 32 +/** Length of the header of the cookie file. */ +#define EXT_OR_PORT_AUTH_COOKIE_HEADER_LEN 32 +/** Static cookie file header. */ +#define EXT_OR_PORT_AUTH_COOKIE_HEADER "! Extended ORPort Auth Cookie !\x0a" +/** Length of safe-cookie protocol hashes. */ +#define EXT_OR_PORT_AUTH_HASH_LEN DIGEST256_LEN +/** Length of safe-cookie protocol nonces. */ +#define EXT_OR_PORT_AUTH_NONCE_LEN 32 +/** Safe-cookie protocol constants. */ +#define EXT_OR_PORT_AUTH_SERVER_TO_CLIENT_CONST \ + "ExtORPort authentication server-to-client hash" +#define EXT_OR_PORT_AUTH_CLIENT_TO_SERVER_CONST \ + "ExtORPort authentication client-to-server hash" + +/* Code to indicate cookie authentication */ +#define EXT_OR_AUTHTYPE_SAFECOOKIE 0x01 + +/** If true, we've set ext_or_auth_cookie to a secret code and stored + * it to disk. */ +STATIC int ext_or_auth_cookie_is_set = 0; +/** If ext_or_auth_cookie_is_set, a secret cookie that we've stored to disk + * and which we're using to authenticate controllers. (If the controller can + * read it off disk, it has permission to connect.) */ +STATIC uint8_t *ext_or_auth_cookie = NULL; + +/** Helper: Return a newly allocated string containing a path to the + * file where we store our authentication cookie. */ +char * +get_ext_or_auth_cookie_file_name(void) +{ + const or_options_t *options = get_options(); + if (options->ExtORPortCookieAuthFile && + strlen(options->ExtORPortCookieAuthFile)) { + return tor_strdup(options->ExtORPortCookieAuthFile); + } else { + return get_datadir_fname("extended_orport_auth_cookie"); + } +} + +/* Initialize the cookie-based authentication system of the + * Extended ORPort. If is_enabled is 0, then disable the cookie + * authentication system. */ +int +init_ext_or_cookie_authentication(int is_enabled) +{ + char *fname = NULL; + int retval; + + if (!is_enabled) { + ext_or_auth_cookie_is_set = 0; + return 0; + } + + fname = get_ext_or_auth_cookie_file_name(); + retval = init_cookie_authentication(fname, EXT_OR_PORT_AUTH_COOKIE_HEADER, + EXT_OR_PORT_AUTH_COOKIE_HEADER_LEN, + &ext_or_auth_cookie, + &ext_or_auth_cookie_is_set); + tor_free(fname); + return retval; +} + +/** Read data from conn and see if the client sent us the + * authentication type that she prefers to use in this session. + * + * Return -1 if we received corrupted data or if we don't support the + * authentication type. Return 0 if we need more data in + * conn. Return 1 if the authentication type negotiation was + * successful. */ +static int +connection_ext_or_auth_neg_auth_type(connection_t *conn) +{ + char authtype[1] = {0}; + + if (connection_get_inbuf_len(conn) < 1) + return 0; + + if (connection_fetch_from_buf(authtype, 1, conn) < 0) + return -1; + + log_debug(LD_GENERAL, "Client wants us to use %d auth type", authtype[0]); + if (authtype[0] != EXT_OR_AUTHTYPE_SAFECOOKIE) { + /* '1' is the only auth type supported atm */ + return -1; + } + + conn->state = EXT_OR_CONN_STATE_AUTH_WAIT_CLIENT_NONCE; + return 1; +} + +/** DOCDOC */ +STATIC int +handle_client_auth_nonce(const char *client_nonce, size_t client_nonce_len, + char **client_hash_out, + char **reply_out, size_t *reply_len_out) +{ + char server_hash[EXT_OR_PORT_AUTH_HASH_LEN] = {0}; + char server_nonce[EXT_OR_PORT_AUTH_NONCE_LEN] = {0}; + char *reply; + size_t reply_len; + + if (client_nonce_len != EXT_OR_PORT_AUTH_NONCE_LEN) + return -1; + + /* Get our nonce */ + if (crypto_rand(server_nonce, EXT_OR_PORT_AUTH_NONCE_LEN) < 0) + return -1; + + { /* set up macs */ + size_t hmac_s_msg_len = strlen(EXT_OR_PORT_AUTH_SERVER_TO_CLIENT_CONST) + + 2*EXT_OR_PORT_AUTH_NONCE_LEN; + size_t hmac_c_msg_len = strlen(EXT_OR_PORT_AUTH_CLIENT_TO_SERVER_CONST) + + 2*EXT_OR_PORT_AUTH_NONCE_LEN; + + char *hmac_s_msg = tor_malloc_zero(hmac_s_msg_len); + char *hmac_c_msg = tor_malloc_zero(hmac_c_msg_len); + char *correct_client_hash = tor_malloc_zero(EXT_OR_PORT_AUTH_HASH_LEN); + + memcpy(hmac_s_msg, + EXT_OR_PORT_AUTH_SERVER_TO_CLIENT_CONST, + strlen(EXT_OR_PORT_AUTH_SERVER_TO_CLIENT_CONST)); + memcpy(hmac_s_msg + strlen(EXT_OR_PORT_AUTH_SERVER_TO_CLIENT_CONST), + client_nonce, EXT_OR_PORT_AUTH_NONCE_LEN); + memcpy(hmac_s_msg + strlen(EXT_OR_PORT_AUTH_SERVER_TO_CLIENT_CONST) + + EXT_OR_PORT_AUTH_NONCE_LEN, + server_nonce, EXT_OR_PORT_AUTH_NONCE_LEN); + + memcpy(hmac_c_msg, + EXT_OR_PORT_AUTH_CLIENT_TO_SERVER_CONST, + strlen(EXT_OR_PORT_AUTH_CLIENT_TO_SERVER_CONST)); + memcpy(hmac_c_msg + strlen(EXT_OR_PORT_AUTH_CLIENT_TO_SERVER_CONST), + client_nonce, EXT_OR_PORT_AUTH_NONCE_LEN); + memcpy(hmac_c_msg + strlen(EXT_OR_PORT_AUTH_CLIENT_TO_SERVER_CONST) + + EXT_OR_PORT_AUTH_NONCE_LEN, + server_nonce, EXT_OR_PORT_AUTH_NONCE_LEN); + + crypto_hmac_sha256(server_hash, + (char*)ext_or_auth_cookie, + EXT_OR_PORT_AUTH_COOKIE_LEN, + hmac_s_msg, + hmac_s_msg_len); + + crypto_hmac_sha256(correct_client_hash, + (char*)ext_or_auth_cookie, + EXT_OR_PORT_AUTH_COOKIE_LEN, + hmac_c_msg, + hmac_c_msg_len); + + /* Store the client hash we generated. We will need to compare it + with the hash sent by the client. */ + *client_hash_out = correct_client_hash; + + memwipe(hmac_s_msg, 0, hmac_s_msg_len); + memwipe(hmac_c_msg, 0, hmac_c_msg_len); + + tor_free(hmac_s_msg); + tor_free(hmac_c_msg); + } + + { /* debug logging */ /* XXX disable this codepath if not logging on debug?*/ + char server_hash_encoded[(2*EXT_OR_PORT_AUTH_HASH_LEN) + 1]; + char server_nonce_encoded[(2*EXT_OR_PORT_AUTH_NONCE_LEN) + 1]; + char client_nonce_encoded[(2*EXT_OR_PORT_AUTH_NONCE_LEN) + 1]; + + base16_encode(server_hash_encoded, sizeof(server_hash_encoded), + server_hash, sizeof(server_hash)); + base16_encode(server_nonce_encoded, sizeof(server_nonce_encoded), + server_nonce, sizeof(server_nonce)); + base16_encode(client_nonce_encoded, sizeof(client_nonce_encoded), + client_nonce, sizeof(client_nonce)); + + log_debug(LD_GENERAL, + "server_hash: '%s'\nserver_nonce: '%s'\nclient_nonce: '%s'", + server_hash_encoded, server_nonce_encoded, client_nonce_encoded); + + memwipe(server_hash_encoded, 0, sizeof(server_hash_encoded)); + memwipe(server_nonce_encoded, 0, sizeof(server_nonce_encoded)); + memwipe(client_nonce_encoded, 0, sizeof(client_nonce_encoded)); + } + + { /* write reply: (server_hash, server_nonce) */ + + reply_len = EXT_OR_PORT_AUTH_COOKIE_LEN+EXT_OR_PORT_AUTH_NONCE_LEN; + reply = tor_malloc_zero(reply_len); + memcpy(reply, server_hash, EXT_OR_PORT_AUTH_HASH_LEN); + memcpy(reply + EXT_OR_PORT_AUTH_HASH_LEN, server_nonce, + EXT_OR_PORT_AUTH_NONCE_LEN); + } + + *reply_out = reply; + *reply_len_out = reply_len; + + return 0; +} + +/** Read the client's nonce out of conn, setup the safe-cookie + * crypto, and then send our own hash and nonce to the client + * + * Return -1 if there was an error; return 0 if we need more data in + * conn, and return 1 if we successfully retrieved the + * client's nonce and sent our own. */ +static int +connection_ext_or_auth_handle_client_nonce(connection_t *conn) +{ + char client_nonce[EXT_OR_PORT_AUTH_NONCE_LEN]; + char *reply=NULL; + size_t reply_len=0; + + if (!ext_or_auth_cookie_is_set) { /* this should not happen */ + log_warn(LD_BUG, "Extended ORPort authentication cookie was not set. " + "That's weird since we should have done that on startup. " + "This might be a Tor bug, please file a bug report. "); + return -1; + } + + if (connection_get_inbuf_len(conn) < EXT_OR_PORT_AUTH_NONCE_LEN) + return 0; + + if (connection_fetch_from_buf(client_nonce, + EXT_OR_PORT_AUTH_NONCE_LEN, conn) < 0) + return -1; + + /* We extract the ClientNonce from the received data, and use it to + calculate ServerHash and ServerNonce according to proposal 217. + + We also calculate our own ClientHash value and save it in the + connection state. We validate it later against the ClientHash + sent by the client. */ + if (handle_client_auth_nonce(client_nonce, sizeof(client_nonce), + &TO_OR_CONN(conn)->ext_or_auth_correct_client_hash, + &reply, &reply_len) < 0) + return -1; + + connection_write_to_buf(reply, reply_len, conn); + + memwipe(reply, 0, reply_len); + tor_free(reply); + + log_debug(LD_GENERAL, "Got client nonce, and sent our own nonce and hash."); + + conn->state = EXT_OR_CONN_STATE_AUTH_WAIT_CLIENT_HASH; + return 1; +} + +#define connection_ext_or_auth_send_result_success(c) \ + connection_ext_or_auth_send_result(c, 1) +#define connection_ext_or_auth_send_result_fail(c) \ + connection_ext_or_auth_send_result(c, 0) + +/** Send authentication results to conn. Successful results if + * success is set; failure results otherwise. */ +static void +connection_ext_or_auth_send_result(connection_t *conn, int success) +{ + if (success) + connection_write_to_buf("\x01", 1, conn); + else + connection_write_to_buf("\x00", 1, conn); +} + +/** Receive the client's hash from conn, validate that it's + * correct, and then send the authentication results to the client. + * + * Return -1 if there was an error during validation; return 0 if we + * need more data in conn, and return 1 if we successfully + * validated the client's hash and sent a happy authentication + * result. */ +static int +connection_ext_or_auth_handle_client_hash(connection_t *conn) +{ + char provided_client_hash[EXT_OR_PORT_AUTH_HASH_LEN] = {0}; + + if (connection_get_inbuf_len(conn) < EXT_OR_PORT_AUTH_HASH_LEN) + return 0; + + if (connection_fetch_from_buf(provided_client_hash, + EXT_OR_PORT_AUTH_HASH_LEN, conn) < 0) + return -1; + + if (tor_memneq(TO_OR_CONN(conn)->ext_or_auth_correct_client_hash, + provided_client_hash, EXT_OR_PORT_AUTH_HASH_LEN)) { + log_warn(LD_GENERAL, "Incorrect client hash. Authentication failed."); + connection_ext_or_auth_send_result_fail(conn); + return -1; + } + + log_debug(LD_GENERAL, "Got client's hash and it was legit."); + + /* send positive auth result */ + connection_ext_or_auth_send_result_success(conn); + conn->state = EXT_OR_CONN_STATE_OPEN; + return 1; +} + +/** Handle data from or_conn received on Extended ORPort. + * Return -1 on error. 0 on unsufficient data. 1 on correct. */ +static int +connection_ext_or_auth_process_inbuf(or_connection_t *or_conn) +{ + connection_t *conn = TO_CONN(or_conn); + + /* State transitions of the Extended ORPort authentication protocol: + + EXT_OR_CONN_STATE_AUTH_WAIT_AUTH_TYPE (start state) -> + EXT_OR_CONN_STATE_AUTH_WAIT_CLIENT_NONCE -> + EXT_OR_CONN_STATE_AUTH_WAIT_CLIENT_HASH -> + EXT_OR_CONN_STATE_OPEN + + During EXT_OR_CONN_STATE_OPEN, data is handled by + connection_ext_or_process_inbuf(). + */ + + switch (conn->state) { /* Functionify */ + case EXT_OR_CONN_STATE_AUTH_WAIT_AUTH_TYPE: + return connection_ext_or_auth_neg_auth_type(conn); + + case EXT_OR_CONN_STATE_AUTH_WAIT_CLIENT_NONCE: + return connection_ext_or_auth_handle_client_nonce(conn); + + case EXT_OR_CONN_STATE_AUTH_WAIT_CLIENT_HASH: + return connection_ext_or_auth_handle_client_hash(conn); + + default: + log_warn(LD_BUG, "Encountered unexpected connection state %d while trying " + "to process Extended ORPort authentication data.", conn->state); + return -1; + } +} + +/** Extended ORPort commands (Transport-to-Bridge) */ +#define EXT_OR_CMD_TB_DONE 0x0000 +#define EXT_OR_CMD_TB_USERADDR 0x0001 +#define EXT_OR_CMD_TB_TRANSPORT 0x0002 + +/** Extended ORPort commands (Bridge-to-Transport) */ +#define EXT_OR_CMD_BT_OKAY 0x1000 +#define EXT_OR_CMD_BT_DENY 0x1001 +#define EXT_OR_CMD_BT_CONTROL 0x1002 + +/** Process a USERADDR command from the Extended + * ORPort. payload is a payload of size len. + * + * If the USERADDR command was well formed, change the address of + * conn to the address on the USERADDR command. + * + * Return 0 on success and -1 on error. */ +static int +connection_ext_or_handle_cmd_useraddr(connection_t *conn, + const char *payload, uint16_t len) +{ + /* Copy address string. */ + tor_addr_t addr; + uint16_t port; + char *addr_str; + char *address_part=NULL; + int res; + if (memchr(payload, '\0', len)) { + log_fn(LOG_PROTOCOL_WARN, LD_NET, "Unexpected NUL in ExtORPort UserAddr"); + return -1; + } + + addr_str = tor_memdup_nulterm(payload, len); + + res = tor_addr_port_split(LOG_INFO, addr_str, &address_part, &port); + tor_free(addr_str); + if (res<0) + return -1; + + res = tor_addr_parse(&addr, address_part); + tor_free(address_part); + if (res<0) + return -1; + + { /* do some logging */ + char *old_address = tor_dup_addr(&conn->addr); + char *new_address = tor_dup_addr(&addr); + + log_debug(LD_NET, "Received USERADDR." + "We rewrite our address from '%s:%u' to '%s:%u'.", + safe_str(old_address), conn->port, safe_str(new_address), port); + + tor_free(old_address); + tor_free(new_address); + } + + /* record the address */ + tor_addr_copy(&conn->addr, &addr); + conn->port = port; + if (conn->address) { + tor_free(conn->address); + } + conn->address = tor_dup_addr(&addr); + + return 0; +} + +/** Process a TRANSPORT command from the Extended + * ORPort. payload is a payload of size len. + * + * If the TRANSPORT command was well formed, register the name of the + * transport on conn. + * + * Return 0 on success and -1 on error. */ +static int +connection_ext_or_handle_cmd_transport(or_connection_t *conn, + const char *payload, uint16_t len) +{ + char *transport_str; + if (memchr(payload, '\0', len)) { + log_fn(LOG_PROTOCOL_WARN, LD_NET, "Unexpected NUL in ExtORPort Transport"); + return -1; + } + + transport_str = tor_memdup_nulterm(payload, len); + + /* Transport names MUST be C-identifiers. */ + if (!string_is_C_identifier(transport_str)) { + tor_free(transport_str); + return -1; + } + + /* If ext_or_transport is already occupied (because the PT sent two + * TRANSPORT commands), deallocate the old name and keep the new + * one */ + if (conn->ext_or_transport) + tor_free(conn->ext_or_transport); + + conn->ext_or_transport = transport_str; + return 0; +} + +#define EXT_OR_CONN_STATE_IS_AUTHENTICATING(st) \ + ((st) <= EXT_OR_CONN_STATE_AUTH_MAX) + +/** Process Extended ORPort messages from or_conn. */ +int +connection_ext_or_process_inbuf(or_connection_t *or_conn) +{ + connection_t *conn = TO_CONN(or_conn); + ext_or_cmd_t *command; + int r; + + /* DOCDOC Document the state machine and transitions in this function */ + + /* If we are still in the authentication stage, process traffic as + authentication data: */ + while (EXT_OR_CONN_STATE_IS_AUTHENTICATING(conn->state)) { + log_debug(LD_GENERAL, "Got Extended ORPort authentication data (%u).", + (unsigned int) connection_get_inbuf_len(conn)); + r = connection_ext_or_auth_process_inbuf(or_conn); + if (r < 0) { + connection_mark_for_close(conn); + return -1; + } else if (r == 0) { + return 0; + } + /* if r > 0, loop and process more data (if any). */ + } + + while (1) { + log_debug(LD_GENERAL, "Got Extended ORPort data."); + command = NULL; + r = connection_fetch_ext_or_cmd_from_buf(conn, &command); + if (r < 0) + goto err; + else if (r == 0) + return 0; /* need to wait for more data */ + + /* Got a command! */ + tor_assert(command); + + if (command->cmd == EXT_OR_CMD_TB_DONE) { + if (connection_get_inbuf_len(conn)) { + /* The inbuf isn't empty; the client is misbehaving. */ + goto err; + } + + log_debug(LD_NET, "Received DONE."); + + /* If the transport proxy did not use the TRANSPORT command to + * specify the transport name, mark this as unknown transport. */ + if (!or_conn->ext_or_transport) { + /* We write this string this way to avoid ??>, which is a C + * trigraph. */ + or_conn->ext_or_transport = tor_strdup(""); + } + + connection_write_ext_or_command(conn, EXT_OR_CMD_BT_OKAY, NULL, 0); + + /* can't transition immediately; need to flush first. */ + conn->state = EXT_OR_CONN_STATE_FLUSHING; + connection_stop_reading(conn); + } else if (command->cmd == EXT_OR_CMD_TB_USERADDR) { + if (connection_ext_or_handle_cmd_useraddr(conn, + command->body, command->len) < 0) + goto err; + } else if (command->cmd == EXT_OR_CMD_TB_TRANSPORT) { + if (connection_ext_or_handle_cmd_transport(or_conn, + command->body, command->len) < 0) + goto err; + } else { + log_notice(LD_NET,"Got Extended ORPort command we don't regognize (%u).", + command->cmd); + } + + ext_or_cmd_free(command); + } + + return 0; + + err: + ext_or_cmd_free(command); + connection_mark_for_close(conn); + return -1; +} + +/** conn finished flushing Extended ORPort messages to the + * network, and is now ready to accept OR traffic. This function + * does the transition. */ +int +connection_ext_or_finished_flushing(or_connection_t *conn) +{ + if (conn->base_.state == EXT_OR_CONN_STATE_FLUSHING) { + connection_start_reading(TO_CONN(conn)); + connection_ext_or_transition(conn); + } + return 0; +} + +/** Initiate Extended ORPort authentication, by sending the list of + * supported authentication types to the client. */ +int +connection_ext_or_start_auth(or_connection_t *or_conn) +{ + connection_t *conn = TO_CONN(or_conn); + const uint8_t authtypes[] = { + /* We only support authtype '1' for now. */ + EXT_OR_AUTHTYPE_SAFECOOKIE, + /* Marks the end of the list. */ + 0 + }; + + log_debug(LD_GENERAL, + "ExtORPort authentication: Sending supported authentication types"); + + connection_write_to_buf((const char *)authtypes, sizeof(authtypes), conn); + conn->state = EXT_OR_CONN_STATE_AUTH_WAIT_AUTH_TYPE; + + return 0; +} + +/** Free any leftover allocated memory of the ext_orport.c subsystem. */ +void +ext_orport_free_all(void) +{ + if (ext_or_auth_cookie) /* Free the auth cookie */ + tor_free(ext_or_auth_cookie); +} + diff --git a/src/tor/ext_orport.h b/src/tor/ext_orport.h new file mode 100644 index 0000000..ce45e5f --- /dev/null +++ b/src/tor/ext_orport.h @@ -0,0 +1,42 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef EXT_ORPORT_H +#define EXT_ORPORT_H + +int connection_ext_or_start_auth(or_connection_t *or_conn); + +ext_or_cmd_t *ext_or_cmd_new(uint16_t len); +void ext_or_cmd_free(ext_or_cmd_t *cmd); +void connection_or_set_ext_or_identifier(or_connection_t *conn); +void connection_or_remove_from_ext_or_id_map(or_connection_t *conn); +void connection_or_clear_ext_or_id_map(void); +or_connection_t *connection_or_get_by_ext_or_id(const char *id); + +int connection_ext_or_finished_flushing(or_connection_t *conn); +int connection_ext_or_process_inbuf(or_connection_t *or_conn); + +int init_ext_or_cookie_authentication(int is_enabled); +char *get_ext_or_auth_cookie_file_name(void); +void ext_orport_free_all(void); + +#ifdef EXT_ORPORT_PRIVATE +STATIC int connection_write_ext_or_command(connection_t *conn, + uint16_t command, + const char *body, + size_t bodylen); +STATIC int handle_client_auth_nonce(const char *client_nonce, + size_t client_nonce_len, + char **client_hash_out, + char **reply_out, size_t *reply_len_out); +#ifdef TOR_UNIT_TESTS +extern uint8_t *ext_or_auth_cookie; +extern int ext_or_auth_cookie_is_set; +#endif +#endif + +#endif + diff --git a/src/tor/fp_pair.c b/src/tor/fp_pair.c new file mode 100644 index 0000000..4d8a835 --- /dev/null +++ b/src/tor/fp_pair.c @@ -0,0 +1,308 @@ +/* Copyright (c) 2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#include "or.h" +#include "fp_pair.h" + +/* Define fp_pair_map_t structures */ + +struct fp_pair_map_entry_s { + HT_ENTRY(fp_pair_map_entry_s) node; + void *val; + fp_pair_t key; +}; + +struct fp_pair_map_s { + HT_HEAD(fp_pair_map_impl, fp_pair_map_entry_s) head; +}; + +/* + * Hash function and equality checker for fp_pair_map_t + */ + +/** Compare fp_pair_entry_t objects by key value. */ +static INLINE int +fp_pair_map_entries_eq(const fp_pair_map_entry_t *a, + const fp_pair_map_entry_t *b) +{ + return tor_memeq(&(a->key), &(b->key), sizeof(fp_pair_t)); +} + +/** Return a hash value for an fp_pair_entry_t. */ +static INLINE unsigned int +fp_pair_map_entry_hash(const fp_pair_map_entry_t *a) +{ + const uint32_t *p; + unsigned int hash; + + p = (const uint32_t *)(a->key.first); + /* Hashes are 20 bytes long, so 5 times uint32_t */ + hash = p[0] ^ p[1] ^ p[2] ^ p[3] ^ p[4]; + /* Now XOR in the second fingerprint */ + p = (const uint32_t *)(a->key.second); + hash ^= p[0] ^ p[1] ^ p[2] ^ p[3] ^ p[4]; + + return hash; +} + +/* + * Hash table functions for fp_pair_map_t + */ + +HT_PROTOTYPE(fp_pair_map_impl, fp_pair_map_entry_s, node, + fp_pair_map_entry_hash, fp_pair_map_entries_eq) +HT_GENERATE(fp_pair_map_impl, fp_pair_map_entry_s, node, + fp_pair_map_entry_hash, fp_pair_map_entries_eq, + 0.6, tor_malloc, tor_realloc, tor_free) + +/** Constructor to create a new empty map from fp_pair_t to void * + */ + +fp_pair_map_t * +fp_pair_map_new(void) +{ + fp_pair_map_t *result; + + result = tor_malloc(sizeof(fp_pair_map_t)); + HT_INIT(fp_pair_map_impl, &result->head); + return result; +} + +/** Set the current value for key to val; returns the previous + * value for key if one was set, or NULL if one was not. + */ + +void * +fp_pair_map_set(fp_pair_map_t *map, const fp_pair_t *key, void *val) +{ + fp_pair_map_entry_t *resolve; + fp_pair_map_entry_t search; + void *oldval; + + tor_assert(map); + tor_assert(key); + tor_assert(val); + + memcpy(&(search.key), key, sizeof(*key)); + resolve = HT_FIND(fp_pair_map_impl, &(map->head), &search); + if (resolve) { + oldval = resolve->val; + resolve->val = val; + } else { + resolve = tor_malloc_zero(sizeof(fp_pair_map_entry_t)); + memcpy(&(resolve->key), key, sizeof(*key)); + resolve->val = val; + HT_INSERT(fp_pair_map_impl, &(map->head), resolve); + oldval = NULL; + } + + return oldval; +} + +/** Set the current value for the key (first, second) to val; returns + * the previous value for key if one was set, or NULL if one was not. + */ + +void * +fp_pair_map_set_by_digests(fp_pair_map_t *map, + const char *first, const char *second, + void *val) +{ + fp_pair_t k; + + tor_assert(first); + tor_assert(second); + + memcpy(k.first, first, DIGEST_LEN); + memcpy(k.second, second, DIGEST_LEN); + + return fp_pair_map_set(map, &k, val); +} + +/** Return the current value associated with key, or NULL if no value is set. + */ + +void * +fp_pair_map_get(const fp_pair_map_t *map, const fp_pair_t *key) +{ + fp_pair_map_entry_t *resolve; + fp_pair_map_entry_t search; + void *val = NULL; + + tor_assert(map); + tor_assert(key); + + memcpy(&(search.key), key, sizeof(*key)); + resolve = HT_FIND(fp_pair_map_impl, &(map->head), &search); + if (resolve) val = resolve->val; + + return val; +} + +/** Return the current value associated the key (first, second), or + * NULL if no value is set. + */ + +void * +fp_pair_map_get_by_digests(const fp_pair_map_t *map, + const char *first, const char *second) +{ + fp_pair_t k; + + tor_assert(first); + tor_assert(second); + + memcpy(k.first, first, DIGEST_LEN); + memcpy(k.second, second, DIGEST_LEN); + + return fp_pair_map_get(map, &k); +} + +/** Remove the value currently associated with key from the map. + * Return the value if one was set, or NULL if there was no entry for + * key. The caller must free any storage associated with the + * returned value. + */ + +void * +fp_pair_map_remove(fp_pair_map_t *map, const fp_pair_t *key) +{ + fp_pair_map_entry_t *resolve; + fp_pair_map_entry_t search; + void *val = NULL; + + tor_assert(map); + tor_assert(key); + + memcpy(&(search.key), key, sizeof(*key)); + resolve = HT_REMOVE(fp_pair_map_impl, &(map->head), &search); + if (resolve) { + val = resolve->val; + tor_free(resolve); + } + + return val; +} + +/** Remove all entries from map, and deallocate storage for those entries. + * If free_val is provided, it is invoked on every value in map. + */ + +void +fp_pair_map_free(fp_pair_map_t *map, void (*free_val)(void*)) +{ + fp_pair_map_entry_t **ent, **next, *this; + + if (map) { + for (ent = HT_START(fp_pair_map_impl, &(map->head)); + ent != NULL; ent = next) { + this = *ent; + next = HT_NEXT_RMV(fp_pair_map_impl, &(map->head), ent); + if (free_val) free_val(this->val); + tor_free(this); + } + tor_assert(HT_EMPTY(&(map->head))); + HT_CLEAR(fp_pair_map_impl, &(map->head)); + tor_free(map); + } +} + +/** Return true iff map has no entries. + */ + +int +fp_pair_map_isempty(const fp_pair_map_t *map) +{ + tor_assert(map); + + return HT_EMPTY(&(map->head)); +} + +/** Return the number of items in map. + */ + +int +fp_pair_map_size(const fp_pair_map_t *map) +{ + tor_assert(map); + + return HT_SIZE(&(map->head)); +} + +/** return an iterator pointing to the start of map. + */ + +fp_pair_map_iter_t * +fp_pair_map_iter_init(fp_pair_map_t *map) +{ + tor_assert(map); + + return HT_START(fp_pair_map_impl, &(map->head)); +} + +/** Advance iter a single step to the next entry of map, and return + * its new value. + */ + +fp_pair_map_iter_t * +fp_pair_map_iter_next(fp_pair_map_t *map, fp_pair_map_iter_t *iter) +{ + tor_assert(map); + tor_assert(iter); + + return HT_NEXT(fp_pair_map_impl, &(map->head), iter); +} + +/** Advance iter a single step to the next entry of map, removing the current + * entry, and return its new value. + */ + +fp_pair_map_iter_t * +fp_pair_map_iter_next_rmv(fp_pair_map_t *map, fp_pair_map_iter_t *iter) +{ + fp_pair_map_entry_t *rmv; + + tor_assert(map); + tor_assert(iter); + tor_assert(*iter); + + rmv = *iter; + iter = HT_NEXT_RMV(fp_pair_map_impl, &(map->head), iter); + tor_free(rmv); + + return iter; +} + +/** Set *key_out and *val_out to the current entry pointed to by iter. + */ + +void +fp_pair_map_iter_get(fp_pair_map_iter_t *iter, + fp_pair_t *key_out, void **val_out) +{ + tor_assert(iter); + tor_assert(*iter); + + if (key_out) memcpy(key_out, &((*iter)->key), sizeof(fp_pair_t)); + if (val_out) *val_out = (*iter)->val; +} + +/** Return true iff iter has advanced past the last entry of its map. + */ + +int +fp_pair_map_iter_done(fp_pair_map_iter_t *iter) +{ + return (iter == NULL); +} + +/** Assert if anything has gone wrong with the internal + * representation of map. + */ + +void +fp_pair_map_assert_ok(const fp_pair_map_t *map) +{ + tor_assert(!fp_pair_map_impl_HT_REP_IS_BAD_(&(map->head))); +} + diff --git a/src/tor/fp_pair.h b/src/tor/fp_pair.h new file mode 100644 index 0000000..89f664a --- /dev/null +++ b/src/tor/fp_pair.h @@ -0,0 +1,45 @@ +/* Copyright (c) 2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file fp_pair.h + * \brief Header file for fp_pair.c. + **/ + +#ifndef _TOR_FP_PAIR_H +#define _TOR_FP_PAIR_H + +/* + * Declare fp_pair_map_t functions and structs + */ + +typedef struct fp_pair_map_entry_s fp_pair_map_entry_t; +typedef struct fp_pair_map_s fp_pair_map_t; +typedef fp_pair_map_entry_t *fp_pair_map_iter_t; + +fp_pair_map_t * fp_pair_map_new(void); +void * fp_pair_map_set(fp_pair_map_t *map, const fp_pair_t *key, void *val); +void * fp_pair_map_set_by_digests(fp_pair_map_t *map, + const char *first, const char *second, + void *val); +void * fp_pair_map_get(const fp_pair_map_t *map, const fp_pair_t *key); +void * fp_pair_map_get_by_digests(const fp_pair_map_t *map, + const char *first, const char *second); +void * fp_pair_map_remove(fp_pair_map_t *map, const fp_pair_t *key); +void fp_pair_map_free(fp_pair_map_t *map, void (*free_val)(void*)); +int fp_pair_map_isempty(const fp_pair_map_t *map); +int fp_pair_map_size(const fp_pair_map_t *map); +fp_pair_map_iter_t * fp_pair_map_iter_init(fp_pair_map_t *map); +fp_pair_map_iter_t * fp_pair_map_iter_next(fp_pair_map_t *map, + fp_pair_map_iter_t *iter); +fp_pair_map_iter_t * fp_pair_map_iter_next_rmv(fp_pair_map_t *map, + fp_pair_map_iter_t *iter); +void fp_pair_map_iter_get(fp_pair_map_iter_t *iter, + fp_pair_t *key_out, void **val_out); +int fp_pair_map_iter_done(fp_pair_map_iter_t *iter); +void fp_pair_map_assert_ok(const fp_pair_map_t *map); + +#undef DECLARE_MAP_FNS + +#endif + diff --git a/src/tor/geoip.c b/src/tor/geoip.c new file mode 100644 index 0000000..dc4730c --- /dev/null +++ b/src/tor/geoip.c @@ -0,0 +1,1684 @@ +/* Copyright (c) 2007-2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file geoip.c + * \brief Functions related to maintaining an IP-to-country database; + * to summarizing client connections by country to entry guards, bridges, + * and directory servers; and for statistics on answering network status + * requests. + */ + +#define GEOIP_PRIVATE +#include "or.h" +#include "ht.h" +#include "config.h" +#include "control.h" +#include "dnsserv.h" +#include "geoip.h" +#include "routerlist.h" + +static void clear_geoip_db(void); +static void init_geoip_countries(void); + +/** An entry from the GeoIP IPv4 file: maps an IPv4 range to a country. */ +typedef struct geoip_ipv4_entry_t { + uint32_t ip_low; /**< The lowest IP in the range, in host order */ + uint32_t ip_high; /**< The highest IP in the range, in host order */ + intptr_t country; /**< An index into geoip_countries */ +} geoip_ipv4_entry_t; + +/** An entry from the GeoIP IPv6 file: maps an IPv6 range to a country. */ +typedef struct geoip_ipv6_entry_t { + struct in6_addr ip_low; /**< The lowest IP in the range, in host order */ + struct in6_addr ip_high; /**< The highest IP in the range, in host order */ + intptr_t country; /**< An index into geoip_countries */ +} geoip_ipv6_entry_t; + +/** A per-country record for GeoIP request history. */ +typedef struct geoip_country_t { + char countrycode[3]; + uint32_t n_v3_ns_requests; +} geoip_country_t; + +/** A list of geoip_country_t */ +static smartlist_t *geoip_countries = NULL; +/** A map from lowercased country codes to their position in geoip_countries. + * The index is encoded in the pointer, and 1 is added so that NULL can mean + * not found. */ +static strmap_t *country_idxplus1_by_lc_code = NULL; +/** Lists of all known geoip_ipv4_entry_t and geoip_ipv6_entry_t, sorted + * by their respective ip_low. */ +static smartlist_t *geoip_ipv4_entries = NULL, *geoip_ipv6_entries = NULL; + +/** SHA1 digest of the GeoIP files to include in extra-info descriptors. */ +static char geoip_digest[DIGEST_LEN]; +static char geoip6_digest[DIGEST_LEN]; + +/** Return the index of the country's entry in the GeoIP + * country list if it is a valid 2-letter country code, otherwise + * return -1. */ +country_t +geoip_get_country(const char *country) +{ + void *idxplus1_; + intptr_t idx; + + idxplus1_ = strmap_get_lc(country_idxplus1_by_lc_code, country); + if (!idxplus1_) + return -1; + + idx = ((uintptr_t)idxplus1_)-1; + return (country_t)idx; +} + +/** Add an entry to a GeoIP table, mapping all IP addresses between low + * and high, inclusive, to the 2-letter country code country. */ +static void +geoip_add_entry(const tor_addr_t *low, const tor_addr_t *high, + const char *country) +{ + intptr_t idx; + void *idxplus1_; + + if (tor_addr_family(low) != tor_addr_family(high)) + return; + if (tor_addr_compare(high, low, CMP_EXACT) < 0) + return; + + idxplus1_ = strmap_get_lc(country_idxplus1_by_lc_code, country); + + if (!idxplus1_) { + geoip_country_t *c = tor_malloc_zero(sizeof(geoip_country_t)); + strlcpy(c->countrycode, country, sizeof(c->countrycode)); + tor_strlower(c->countrycode); + smartlist_add(geoip_countries, c); + idx = smartlist_len(geoip_countries) - 1; + strmap_set_lc(country_idxplus1_by_lc_code, country, (void*)(idx+1)); + } else { + idx = ((uintptr_t)idxplus1_)-1; + } + { + geoip_country_t *c = smartlist_get(geoip_countries, idx); + tor_assert(!strcasecmp(c->countrycode, country)); + } + + if (tor_addr_family(low) == AF_INET) { + geoip_ipv4_entry_t *ent = tor_malloc_zero(sizeof(geoip_ipv4_entry_t)); + ent->ip_low = tor_addr_to_ipv4h(low); + ent->ip_high = tor_addr_to_ipv4h(high); + ent->country = idx; + smartlist_add(geoip_ipv4_entries, ent); + } else if (tor_addr_family(low) == AF_INET6) { + geoip_ipv6_entry_t *ent = tor_malloc_zero(sizeof(geoip_ipv6_entry_t)); + ent->ip_low = *tor_addr_to_in6(low); + ent->ip_high = *tor_addr_to_in6(high); + ent->country = idx; + smartlist_add(geoip_ipv6_entries, ent); + } +} + +/** Add an entry to the GeoIP table indicated by family, + * parsing it from line. The format is as for geoip_load_file(). */ +STATIC int +geoip_parse_entry(const char *line, sa_family_t family) +{ + tor_addr_t low_addr, high_addr; + char c[3]; + char *country = NULL; + + if (!geoip_countries) + init_geoip_countries(); + if (family == AF_INET) { + if (!geoip_ipv4_entries) + geoip_ipv4_entries = smartlist_new(); + } else if (family == AF_INET6) { + if (!geoip_ipv6_entries) + geoip_ipv6_entries = smartlist_new(); + } else { + log_warn(LD_GENERAL, "Unsupported family: %d", family); + return -1; + } + + while (TOR_ISSPACE(*line)) + ++line; + if (*line == '#') + return 0; + + if (family == AF_INET) { + unsigned int low, high; + if (tor_sscanf(line,"%u,%u,%2s", &low, &high, c) == 3 || + tor_sscanf(line,"\"%u\",\"%u\",\"%2s\",", &low, &high, c) == 3) { + tor_addr_from_ipv4h(&low_addr, low); + tor_addr_from_ipv4h(&high_addr, high); + } else + goto fail; + country = c; + } else { /* AF_INET6 */ + char buf[512]; + char *low_str, *high_str; + struct in6_addr low, high; + char *strtok_state; + strlcpy(buf, line, sizeof(buf)); + low_str = tor_strtok_r(buf, ",", &strtok_state); + if (!low_str) + goto fail; + high_str = tor_strtok_r(NULL, ",", &strtok_state); + if (!high_str) + goto fail; + country = tor_strtok_r(NULL, "\n", &strtok_state); + if (!country) + goto fail; + if (strlen(country) != 2) + goto fail; + if (tor_inet_pton(AF_INET6, low_str, &low) <= 0) + goto fail; + tor_addr_from_in6(&low_addr, &low); + if (tor_inet_pton(AF_INET6, high_str, &high) <= 0) + goto fail; + tor_addr_from_in6(&high_addr, &high); + } + geoip_add_entry(&low_addr, &high_addr, country); + return 0; + + fail: + log_warn(LD_GENERAL, "Unable to parse line from GEOIP %s file: %s", + family == AF_INET ? "IPv4" : "IPv6", escaped(line)); + return -1; +} + +/** Sorting helper: return -1, 1, or 0 based on comparison of two + * geoip_ipv4_entry_t */ +static int +geoip_ipv4_compare_entries_(const void **_a, const void **_b) +{ + const geoip_ipv4_entry_t *a = *_a, *b = *_b; + if (a->ip_low < b->ip_low) + return -1; + else if (a->ip_low > b->ip_low) + return 1; + else + return 0; +} + +/** bsearch helper: return -1, 1, or 0 based on comparison of an IP (a pointer + * to a uint32_t in host order) to a geoip_ipv4_entry_t */ +static int +geoip_ipv4_compare_key_to_entry_(const void *_key, const void **_member) +{ + /* No alignment issue here, since _key really is a pointer to uint32_t */ + const uint32_t addr = *(uint32_t *)_key; + const geoip_ipv4_entry_t *entry = *_member; + if (addr < entry->ip_low) + return -1; + else if (addr > entry->ip_high) + return 1; + else + return 0; +} + +/** Sorting helper: return -1, 1, or 0 based on comparison of two + * geoip_ipv6_entry_t */ +static int +geoip_ipv6_compare_entries_(const void **_a, const void **_b) +{ + const geoip_ipv6_entry_t *a = *_a, *b = *_b; + return fast_memcmp(a->ip_low.s6_addr, b->ip_low.s6_addr, + sizeof(struct in6_addr)); +} + +/** bsearch helper: return -1, 1, or 0 based on comparison of an IPv6 + * (a pointer to a in6_addr) to a geoip_ipv6_entry_t */ +static int +geoip_ipv6_compare_key_to_entry_(const void *_key, const void **_member) +{ + const struct in6_addr *addr = (struct in6_addr *)_key; + const geoip_ipv6_entry_t *entry = *_member; + + if (fast_memcmp(addr->s6_addr, entry->ip_low.s6_addr, + sizeof(struct in6_addr)) < 0) + return -1; + else if (fast_memcmp(addr->s6_addr, entry->ip_high.s6_addr, + sizeof(struct in6_addr)) > 0) + return 1; + else + return 0; +} + +/** Return 1 if we should collect geoip stats on bridge users, and + * include them in our extrainfo descriptor. Else return 0. */ +int +should_record_bridge_info(const or_options_t *options) +{ + return options->BridgeRelay && options->BridgeRecordUsageByCountry; +} + +/** Set up a new list of geoip countries with no countries (yet) set in it, + * except for the unknown country. + */ +static void +init_geoip_countries(void) +{ + geoip_country_t *geoip_unresolved; + geoip_countries = smartlist_new(); + /* Add a geoip_country_t for requests that could not be resolved to a + * country as first element (index 0) to geoip_countries. */ + geoip_unresolved = tor_malloc_zero(sizeof(geoip_country_t)); + strlcpy(geoip_unresolved->countrycode, "??", + sizeof(geoip_unresolved->countrycode)); + smartlist_add(geoip_countries, geoip_unresolved); + country_idxplus1_by_lc_code = strmap_new(); + strmap_set_lc(country_idxplus1_by_lc_code, "??", (void*)(1)); +} + +/** Clear appropriate GeoIP database, based on family, and + * reload it from the file filename. Return 0 on success, -1 on + * failure. + * + * Recognized line formats for IPv4 are: + * INTIPLOW,INTIPHIGH,CC + * and + * "INTIPLOW","INTIPHIGH","CC","CC3","COUNTRY NAME" + * where INTIPLOW and INTIPHIGH are IPv4 addresses encoded as 4-byte unsigned + * integers, and CC is a country code. + * + * Recognized line format for IPv6 is: + * IPV6LOW,IPV6HIGH,CC + * where IPV6LOW and IPV6HIGH are IPv6 addresses and CC is a country code. + * + * It also recognizes, and skips over, blank lines and lines that start + * with '#' (comments). + */ +int +geoip_load_file(sa_family_t family, const char *filename) +{ + FILE *f; + const char *msg = ""; + const or_options_t *options = get_options(); + int severity = options_need_geoip_info(options, &msg) ? LOG_WARN : LOG_INFO; + crypto_digest_t *geoip_digest_env = NULL; + + tor_assert(family == AF_INET || family == AF_INET6); + + if (!(f = tor_fopen_cloexec(filename, "r"))) { + log_fn(severity, LD_GENERAL, "Failed to open GEOIP file %s. %s", + filename, msg); + return -1; + } + if (!geoip_countries) + init_geoip_countries(); + + if (family == AF_INET) { + if (geoip_ipv4_entries) { + SMARTLIST_FOREACH(geoip_ipv4_entries, geoip_ipv4_entry_t *, e, + tor_free(e)); + smartlist_free(geoip_ipv4_entries); + } + geoip_ipv4_entries = smartlist_new(); + } else { /* AF_INET6 */ + if (geoip_ipv6_entries) { + SMARTLIST_FOREACH(geoip_ipv6_entries, geoip_ipv6_entry_t *, e, + tor_free(e)); + smartlist_free(geoip_ipv6_entries); + } + geoip_ipv6_entries = smartlist_new(); + } + geoip_digest_env = crypto_digest_new(); + + log_notice(LD_GENERAL, "Parsing GEOIP %s file %s.", + (family == AF_INET) ? "IPv4" : "IPv6", filename); + while (!feof(f)) { + char buf[512]; + if (fgets(buf, (int)sizeof(buf), f) == NULL) + break; + crypto_digest_add_bytes(geoip_digest_env, buf, strlen(buf)); + /* FFFF track full country name. */ + geoip_parse_entry(buf, family); + } + /*XXXX abort and return -1 if no entries/illformed?*/ + fclose(f); + + /* Sort list and remember file digests so that we can include it in + * our extra-info descriptors. */ + if (family == AF_INET) { + smartlist_sort(geoip_ipv4_entries, geoip_ipv4_compare_entries_); + /* Okay, now we need to maybe change our mind about what is in + * which country. We do this for IPv4 only since that's what we + * store in node->country. */ + refresh_all_country_info(); + crypto_digest_get_digest(geoip_digest_env, geoip_digest, DIGEST_LEN); + } else { + /* AF_INET6 */ + smartlist_sort(geoip_ipv6_entries, geoip_ipv6_compare_entries_); + crypto_digest_get_digest(geoip_digest_env, geoip6_digest, DIGEST_LEN); + } + crypto_digest_free(geoip_digest_env); + + return 0; +} + +/** Given an IP address in host order, return a number representing the + * country to which that address belongs, -1 for "No geoip information + * available", or 0 for the 'unknown country'. The return value will always + * be less than geoip_get_n_countries(). To decode it, call + * geoip_get_country_name(). + */ +STATIC int +geoip_get_country_by_ipv4(uint32_t ipaddr) +{ + geoip_ipv4_entry_t *ent; + if (!geoip_ipv4_entries) + return -1; + ent = smartlist_bsearch(geoip_ipv4_entries, &ipaddr, + geoip_ipv4_compare_key_to_entry_); + return ent ? (int)ent->country : 0; +} + +/** Given an IPv6 address, return a number representing the country to + * which that address belongs, -1 for "No geoip information available", or + * 0 for the 'unknown country'. The return value will always be less than + * geoip_get_n_countries(). To decode it, call geoip_get_country_name(). + */ +STATIC int +geoip_get_country_by_ipv6(const struct in6_addr *addr) +{ + geoip_ipv6_entry_t *ent; + + if (!geoip_ipv6_entries) + return -1; + ent = smartlist_bsearch(geoip_ipv6_entries, addr, + geoip_ipv6_compare_key_to_entry_); + return ent ? (int)ent->country : 0; +} + +/** Given an IP address, return a number representing the country to which + * that address belongs, -1 for "No geoip information available", or 0 for + * the 'unknown country'. The return value will always be less than + * geoip_get_n_countries(). To decode it, call geoip_get_country_name(). + */ +int +geoip_get_country_by_addr(const tor_addr_t *addr) +{ + if (tor_addr_family(addr) == AF_INET) { + return geoip_get_country_by_ipv4(tor_addr_to_ipv4h(addr)); + } else if (tor_addr_family(addr) == AF_INET6) { + return geoip_get_country_by_ipv6(tor_addr_to_in6(addr)); + } else { + return -1; + } +} + +/** Return the number of countries recognized by the GeoIP country list. */ +int +geoip_get_n_countries(void) +{ + if (!geoip_countries) + init_geoip_countries(); + return (int) smartlist_len(geoip_countries); +} + +/** Return the two-letter country code associated with the number num, + * or "??" for an unknown value. */ +const char * +geoip_get_country_name(country_t num) +{ + if (geoip_countries && num >= 0 && num < smartlist_len(geoip_countries)) { + geoip_country_t *c = smartlist_get(geoip_countries, num); + return c->countrycode; + } else + return "??"; +} + +/** Return true iff we have loaded a GeoIP database.*/ +int +geoip_is_loaded(sa_family_t family) +{ + tor_assert(family == AF_INET || family == AF_INET6); + if (geoip_countries == NULL) + return 0; + if (family == AF_INET) + return geoip_ipv4_entries != NULL; + else /* AF_INET6 */ + return geoip_ipv6_entries != NULL; +} + +/** Return the hex-encoded SHA1 digest of the loaded GeoIP file. The + * result does not need to be deallocated, but will be overwritten by the + * next call of hex_str(). */ +const char * +geoip_db_digest(sa_family_t family) +{ + tor_assert(family == AF_INET || family == AF_INET6); + if (family == AF_INET) + return hex_str(geoip_digest, DIGEST_LEN); + else /* AF_INET6 */ + return hex_str(geoip6_digest, DIGEST_LEN); +} + +/** Entry in a map from IP address to the last time we've seen an incoming + * connection from that IP address. Used by bridges only, to track which + * countries have them blocked. */ +typedef struct clientmap_entry_t { + HT_ENTRY(clientmap_entry_t) node; + tor_addr_t addr; + /* Name of pluggable transport used by this client. NULL if no + pluggable transport was used. */ + char *transport_name; + + /** Time when we last saw this IP address, in MINUTES since the epoch. + * + * (This will run out of space around 4011 CE. If Tor is still in use around + * 4000 CE, please remember to add more bits to last_seen_in_minutes.) */ + unsigned int last_seen_in_minutes:30; + unsigned int action:2; +} clientmap_entry_t; + +/** Largest allowable value for last_seen_in_minutes. (It's a 30-bit field, + * so it can hold up to (1u<<30)-1, or 0x3fffffffu. + */ +#define MAX_LAST_SEEN_IN_MINUTES 0X3FFFFFFFu + +/** Map from client IP address to last time seen. */ +static HT_HEAD(clientmap, clientmap_entry_t) client_history = + HT_INITIALIZER(); + +/** Hashtable helper: compute a hash of a clientmap_entry_t. */ +static INLINE unsigned +clientmap_entry_hash(const clientmap_entry_t *a) +{ + unsigned h = tor_addr_hash(&a->addr); + if (a->transport_name) + h += ht_string_hash(a->transport_name); + return ht_improve_hash(h); +} +/** Hashtable helper: compare two clientmap_entry_t values for equality. */ +static INLINE int +clientmap_entries_eq(const clientmap_entry_t *a, const clientmap_entry_t *b) +{ + if (strcmp_opt(a->transport_name, b->transport_name)) + return 0; + + return !tor_addr_compare(&a->addr, &b->addr, CMP_EXACT) && + a->action == b->action; +} + +HT_PROTOTYPE(clientmap, clientmap_entry_t, node, clientmap_entry_hash, + clientmap_entries_eq); +HT_GENERATE(clientmap, clientmap_entry_t, node, clientmap_entry_hash, + clientmap_entries_eq, 0.6, malloc, realloc, free); + +/** Free all storage held by ent. */ +static void +clientmap_entry_free(clientmap_entry_t *ent) +{ + if (!ent) + return; + + tor_free(ent->transport_name); + tor_free(ent); +} + +/** Clear history of connecting clients used by entry and bridge stats. */ +static void +client_history_clear(void) +{ + clientmap_entry_t **ent, **next, *this; + for (ent = HT_START(clientmap, &client_history); ent != NULL; + ent = next) { + if ((*ent)->action == GEOIP_CLIENT_CONNECT) { + this = *ent; + next = HT_NEXT_RMV(clientmap, &client_history, ent); + clientmap_entry_free(this); + } else { + next = HT_NEXT(clientmap, &client_history, ent); + } + } +} + +/** Note that we've seen a client connect from the IP addr + * at time now. Ignored by all but bridges and directories if + * configured accordingly. */ +void +geoip_note_client_seen(geoip_client_action_t action, + const tor_addr_t *addr, + const char *transport_name, + time_t now) +{ + const or_options_t *options = get_options(); + clientmap_entry_t lookup, *ent; + memset(&lookup, 0, sizeof(clientmap_entry_t)); + + if (action == GEOIP_CLIENT_CONNECT) { + /* Only remember statistics as entry guard or as bridge. */ + if (!options->EntryStatistics && + (!(options->BridgeRelay && options->BridgeRecordUsageByCountry))) + return; + } else { + if (options->BridgeRelay || options->BridgeAuthoritativeDir || + !options->DirReqStatistics) + return; + } + + log_debug(LD_GENERAL, "Seen client from '%s' with transport '%s'.", + safe_str_client(fmt_addr((addr))), + transport_name ? transport_name : ""); + + tor_addr_copy(&lookup.addr, addr); + lookup.action = (int)action; + lookup.transport_name = (char*) transport_name; + ent = HT_FIND(clientmap, &client_history, &lookup); + + if (! ent) { + ent = tor_malloc_zero(sizeof(clientmap_entry_t)); + tor_addr_copy(&ent->addr, addr); + if (transport_name) + ent->transport_name = tor_strdup(transport_name); + ent->action = (int)action; + HT_INSERT(clientmap, &client_history, ent); + } + if (now / 60 <= (int)MAX_LAST_SEEN_IN_MINUTES && now >= 0) + ent->last_seen_in_minutes = (unsigned)(now/60); + else + ent->last_seen_in_minutes = 0; + + if (action == GEOIP_CLIENT_NETWORKSTATUS) { + int country_idx = geoip_get_country_by_addr(addr); + if (country_idx < 0) + country_idx = 0; /** unresolved requests are stored at index 0. */ + if (country_idx >= 0 && country_idx < smartlist_len(geoip_countries)) { + geoip_country_t *country = smartlist_get(geoip_countries, country_idx); + ++country->n_v3_ns_requests; + } + } +} + +/** HT_FOREACH helper: remove a clientmap_entry_t from the hashtable if it's + * older than a certain time. */ +static int +remove_old_client_helper_(struct clientmap_entry_t *ent, void *_cutoff) +{ + time_t cutoff = *(time_t*)_cutoff / 60; + if (ent->last_seen_in_minutes < cutoff) { + clientmap_entry_free(ent); + return 1; + } else { + return 0; + } +} + +/** Forget about all clients that haven't connected since cutoff. */ +void +geoip_remove_old_clients(time_t cutoff) +{ + clientmap_HT_FOREACH_FN(&client_history, + remove_old_client_helper_, + &cutoff); +} + +/** How many responses are we giving to clients requesting v3 network + * statuses? */ +static uint32_t ns_v3_responses[GEOIP_NS_RESPONSE_NUM]; + +/** Note that we've rejected a client's request for a v3 network status + * for reason reason at time now. */ +void +geoip_note_ns_response(geoip_ns_response_t response) +{ + static int arrays_initialized = 0; + if (!get_options()->DirReqStatistics) + return; + if (!arrays_initialized) { + memset(ns_v3_responses, 0, sizeof(ns_v3_responses)); + arrays_initialized = 1; + } + tor_assert(response < GEOIP_NS_RESPONSE_NUM); + ns_v3_responses[response]++; +} + +/** Do not mention any country from which fewer than this number of IPs have + * connected. This conceivably avoids reporting information that could + * deanonymize users, though analysis is lacking. */ +#define MIN_IPS_TO_NOTE_COUNTRY 1 +/** Do not report any geoip data at all if we have fewer than this number of + * IPs to report about. */ +#define MIN_IPS_TO_NOTE_ANYTHING 1 +/** When reporting geoip data about countries, round up to the nearest + * multiple of this value. */ +#define IP_GRANULARITY 8 + +/** Helper type: used to sort per-country totals by value. */ +typedef struct c_hist_t { + char country[3]; /**< Two-letter country code. */ + unsigned total; /**< Total IP addresses seen in this country. */ +} c_hist_t; + +/** Sorting helper: return -1, 1, or 0 based on comparison of two + * geoip_ipv4_entry_t. Sort in descending order of total, and then by country + * code. */ +static int +c_hist_compare_(const void **_a, const void **_b) +{ + const c_hist_t *a = *_a, *b = *_b; + if (a->total > b->total) + return -1; + else if (a->total < b->total) + return 1; + else + return strcmp(a->country, b->country); +} + +/** When there are incomplete directory requests at the end of a 24-hour + * period, consider those requests running for longer than this timeout as + * failed, the others as still running. */ +#define DIRREQ_TIMEOUT (10*60) + +/** Entry in a map from either chan->global_identifier for direct requests + * or a unique circuit identifier for tunneled requests to request time, + * response size, and completion time of a network status request. Used to + * measure download times of requests to derive average client + * bandwidths. */ +typedef struct dirreq_map_entry_t { + HT_ENTRY(dirreq_map_entry_t) node; + /** Unique identifier for this network status request; this is either the + * chan->global_identifier of the dir channel (direct request) or a new + * locally unique identifier of a circuit (tunneled request). This ID is + * only unique among other direct or tunneled requests, respectively. */ + uint64_t dirreq_id; + unsigned int state:3; /**< State of this directory request. */ + unsigned int type:1; /**< Is this a direct or a tunneled request? */ + unsigned int completed:1; /**< Is this request complete? */ + /** When did we receive the request and started sending the response? */ + struct timeval request_time; + size_t response_size; /**< What is the size of the response in bytes? */ + struct timeval completion_time; /**< When did the request succeed? */ +} dirreq_map_entry_t; + +/** Map of all directory requests asking for v2 or v3 network statuses in + * the current geoip-stats interval. Values are + * of type *dirreq_map_entry_t. */ +static HT_HEAD(dirreqmap, dirreq_map_entry_t) dirreq_map = + HT_INITIALIZER(); + +static int +dirreq_map_ent_eq(const dirreq_map_entry_t *a, + const dirreq_map_entry_t *b) +{ + return a->dirreq_id == b->dirreq_id && a->type == b->type; +} + +/* DOCDOC dirreq_map_ent_hash */ +static unsigned +dirreq_map_ent_hash(const dirreq_map_entry_t *entry) +{ + unsigned u = (unsigned) entry->dirreq_id; + u += entry->type << 20; + return u; +} + +HT_PROTOTYPE(dirreqmap, dirreq_map_entry_t, node, dirreq_map_ent_hash, + dirreq_map_ent_eq); +HT_GENERATE(dirreqmap, dirreq_map_entry_t, node, dirreq_map_ent_hash, + dirreq_map_ent_eq, 0.6, malloc, realloc, free); + +/** Helper: Put entry into map of directory requests using + * type and dirreq_id as key parts. If there is + * already an entry for that key, print out a BUG warning and return. */ +static void +dirreq_map_put_(dirreq_map_entry_t *entry, dirreq_type_t type, + uint64_t dirreq_id) +{ + dirreq_map_entry_t *old_ent; + tor_assert(entry->type == type); + tor_assert(entry->dirreq_id == dirreq_id); + + /* XXXX we could switch this to HT_INSERT some time, since it seems that + * this bug doesn't happen. But since this function doesn't seem to be + * critical-path, it's sane to leave it alone. */ + old_ent = HT_REPLACE(dirreqmap, &dirreq_map, entry); + if (old_ent && old_ent != entry) { + log_warn(LD_BUG, "Error when putting directory request into local " + "map. There was already an entry for the same identifier."); + return; + } +} + +/** Helper: Look up and return an entry in the map of directory requests + * using type and dirreq_id as key parts. If there + * is no such entry, return NULL. */ +static dirreq_map_entry_t * +dirreq_map_get_(dirreq_type_t type, uint64_t dirreq_id) +{ + dirreq_map_entry_t lookup; + lookup.type = type; + lookup.dirreq_id = dirreq_id; + return HT_FIND(dirreqmap, &dirreq_map, &lookup); +} + +/** Note that an either direct or tunneled (see type) directory + * request for a v3 network status with unique ID dirreq_id of size + * response_size has started. */ +void +geoip_start_dirreq(uint64_t dirreq_id, size_t response_size, + dirreq_type_t type) +{ + dirreq_map_entry_t *ent; + if (!get_options()->DirReqStatistics) + return; + ent = tor_malloc_zero(sizeof(dirreq_map_entry_t)); + ent->dirreq_id = dirreq_id; + tor_gettimeofday(&ent->request_time); + ent->response_size = response_size; + ent->type = type; + dirreq_map_put_(ent, type, dirreq_id); +} + +/** Change the state of the either direct or tunneled (see type) + * directory request with dirreq_id to new_state and + * possibly mark it as completed. If no entry can be found for the given + * key parts (e.g., if this is a directory request that we are not + * measuring, or one that was started in the previous measurement period), + * or if the state cannot be advanced to new_state, do nothing. */ +void +geoip_change_dirreq_state(uint64_t dirreq_id, dirreq_type_t type, + dirreq_state_t new_state) +{ + dirreq_map_entry_t *ent; + if (!get_options()->DirReqStatistics) + return; + ent = dirreq_map_get_(type, dirreq_id); + if (!ent) + return; + if (new_state == DIRREQ_IS_FOR_NETWORK_STATUS) + return; + if (new_state - 1 != ent->state) + return; + ent->state = new_state; + if ((type == DIRREQ_DIRECT && + new_state == DIRREQ_FLUSHING_DIR_CONN_FINISHED) || + (type == DIRREQ_TUNNELED && + new_state == DIRREQ_CHANNEL_BUFFER_FLUSHED)) { + tor_gettimeofday(&ent->completion_time); + ent->completed = 1; + } +} + +/** Return the bridge-ip-transports string that should be inserted in + * our extra-info descriptor. Return NULL if the bridge-ip-transports + * line should be empty. */ +char * +geoip_get_transport_history(void) +{ + unsigned granularity = IP_GRANULARITY; + /** String hash table -> . */ + strmap_t *transport_counts = strmap_new(); + + /** Smartlist that contains copies of the names of the transports + that have been used. */ + smartlist_t *transports_used = smartlist_new(); + + /* Special string to signify that no transport was used for this + connection. Pluggable transport names can't have symbols in their + names, so this string will never collide with a real transport. */ + static const char* no_transport_str = ""; + + clientmap_entry_t **ent; + const char *transport_name = NULL; + smartlist_t *string_chunks = smartlist_new(); + char *the_string = NULL; + + /* If we haven't seen any clients yet, return NULL. */ + if (HT_EMPTY(&client_history)) + goto done; + + /** We do the following steps to form the transport history string: + * a) Foreach client that uses a pluggable transport, we increase the + * times that transport was used by one. If the client did not use + * a transport, we increase the number of times someone connected + * without obfuscation. + * b) Foreach transport we observed, we write its transport history + * string and push it to string_chunks. So, for example, if we've + * seen 665 obfs2 clients, we write "obfs2=665". + * c) We concatenate string_chunks to form the final string. + */ + + log_debug(LD_GENERAL,"Starting iteration for transport history. %d clients.", + HT_SIZE(&client_history)); + + /* Loop through all clients. */ + HT_FOREACH(ent, clientmap, &client_history) { + uintptr_t val; + void *ptr; + transport_name = (*ent)->transport_name; + if (!transport_name) + transport_name = no_transport_str; + + /* Increase the count for this transport name. */ + ptr = strmap_get(transport_counts, transport_name); + val = (uintptr_t)ptr; + val++; + ptr = (void*)val; + strmap_set(transport_counts, transport_name, ptr); + + /* If it's the first time we see this transport, note it. */ + if (val == 1) + smartlist_add(transports_used, tor_strdup(transport_name)); + + log_debug(LD_GENERAL, "Client from '%s' with transport '%s'. " + "I've now seen %d clients.", + safe_str_client(fmt_addr(&(*ent)->addr)), + transport_name ? transport_name : "", + (int)val); + } + + /* Sort the transport names (helps with unit testing). */ + smartlist_sort_strings(transports_used); + + /* Loop through all seen transports. */ + SMARTLIST_FOREACH_BEGIN(transports_used, const char *, transport_name) { + void *transport_count_ptr = strmap_get(transport_counts, transport_name); + uintptr_t transport_count = (uintptr_t) transport_count_ptr; + + log_debug(LD_GENERAL, "We got "U64_FORMAT" clients with transport '%s'.", + U64_PRINTF_ARG((uint64_t)transport_count), transport_name); + + smartlist_add_asprintf(string_chunks, "%s="U64_FORMAT, + transport_name, + U64_PRINTF_ARG(round_uint64_to_next_multiple_of( + (uint64_t)transport_count, + granularity))); + } SMARTLIST_FOREACH_END(transport_name); + + the_string = smartlist_join_strings(string_chunks, ",", 0, NULL); + + log_debug(LD_GENERAL, "Final bridge-ip-transports string: '%s'", the_string); + + done: + strmap_free(transport_counts, NULL); + SMARTLIST_FOREACH(transports_used, char *, s, tor_free(s)); + smartlist_free(transports_used); + SMARTLIST_FOREACH(string_chunks, char *, s, tor_free(s)); + smartlist_free(string_chunks); + + return the_string; +} + +/** Return a newly allocated comma-separated string containing statistics + * on network status downloads. The string contains the number of completed + * requests, timeouts, and still running requests as well as the download + * times by deciles and quartiles. Return NULL if we have not observed + * requests for long enough. */ +static char * +geoip_get_dirreq_history(dirreq_type_t type) +{ + char *result = NULL; + smartlist_t *dirreq_completed = NULL; + uint32_t complete = 0, timeouts = 0, running = 0; + int bufsize = 1024, written; + dirreq_map_entry_t **ptr, **next, *ent; + struct timeval now; + + tor_gettimeofday(&now); + dirreq_completed = smartlist_new(); + for (ptr = HT_START(dirreqmap, &dirreq_map); ptr; ptr = next) { + ent = *ptr; + if (ent->type != type) { + next = HT_NEXT(dirreqmap, &dirreq_map, ptr); + continue; + } else { + if (ent->completed) { + smartlist_add(dirreq_completed, ent); + complete++; + next = HT_NEXT_RMV(dirreqmap, &dirreq_map, ptr); + } else { + if (tv_mdiff(&ent->request_time, &now) / 1000 > DIRREQ_TIMEOUT) + timeouts++; + else + running++; + next = HT_NEXT_RMV(dirreqmap, &dirreq_map, ptr); + tor_free(ent); + } + } + } +#define DIR_REQ_GRANULARITY 4 + complete = round_uint32_to_next_multiple_of(complete, + DIR_REQ_GRANULARITY); + timeouts = round_uint32_to_next_multiple_of(timeouts, + DIR_REQ_GRANULARITY); + running = round_uint32_to_next_multiple_of(running, + DIR_REQ_GRANULARITY); + result = tor_malloc_zero(bufsize); + written = tor_snprintf(result, bufsize, "complete=%u,timeout=%u," + "running=%u", complete, timeouts, running); + if (written < 0) { + tor_free(result); + goto done; + } + +#define MIN_DIR_REQ_RESPONSES 16 + if (complete >= MIN_DIR_REQ_RESPONSES) { + uint32_t *dltimes; + /* We may have rounded 'completed' up. Here we want to use the + * real value. */ + complete = smartlist_len(dirreq_completed); + dltimes = tor_malloc_zero(sizeof(uint32_t) * complete); + SMARTLIST_FOREACH_BEGIN(dirreq_completed, dirreq_map_entry_t *, ent) { + uint32_t bytes_per_second; + uint32_t time_diff = (uint32_t) tv_mdiff(&ent->request_time, + &ent->completion_time); + if (time_diff == 0) + time_diff = 1; /* Avoid DIV/0; "instant" answers are impossible + * by law of nature or something, but a milisecond + * is a bit greater than "instantly" */ + bytes_per_second = (uint32_t)(1000 * ent->response_size / time_diff); + dltimes[ent_sl_idx] = bytes_per_second; + } SMARTLIST_FOREACH_END(ent); + median_uint32(dltimes, complete); /* sorts as a side effect. */ + written = tor_snprintf(result + written, bufsize - written, + ",min=%u,d1=%u,d2=%u,q1=%u,d3=%u,d4=%u,md=%u," + "d6=%u,d7=%u,q3=%u,d8=%u,d9=%u,max=%u", + dltimes[0], + dltimes[1*complete/10-1], + dltimes[2*complete/10-1], + dltimes[1*complete/4-1], + dltimes[3*complete/10-1], + dltimes[4*complete/10-1], + dltimes[5*complete/10-1], + dltimes[6*complete/10-1], + dltimes[7*complete/10-1], + dltimes[3*complete/4-1], + dltimes[8*complete/10-1], + dltimes[9*complete/10-1], + dltimes[complete-1]); + if (written<0) + tor_free(result); + tor_free(dltimes); + } + done: + SMARTLIST_FOREACH(dirreq_completed, dirreq_map_entry_t *, ent, + tor_free(ent)); + smartlist_free(dirreq_completed); + return result; +} + +/** Store a newly allocated comma-separated string in + * *country_str containing entries for all the countries from + * which we've seen enough clients connect as a bridge, directory + * server, or entry guard. The entry format is cc=num where num is the + * number of IPs we've seen connecting from that country, and cc is a + * lowercased country code. *country_str is set to NULL if + * we're not ready to export per country data yet. + * + * Store a newly allocated comma-separated string in ipver_str + * containing entries for clients connecting over IPv4 and IPv6. The + * format is family=num where num is the nubmer of IPs we've seen + * connecting over that protocol family, and family is 'v4' or 'v6'. + * + * Return 0 on success and -1 if we're missing geoip data. */ +int +geoip_get_client_history(geoip_client_action_t action, + char **country_str, char **ipver_str) +{ + unsigned granularity = IP_GRANULARITY; + smartlist_t *entries = NULL; + int n_countries = geoip_get_n_countries(); + int i; + clientmap_entry_t **ent; + unsigned *counts = NULL; + unsigned total = 0; + unsigned ipv4_count = 0, ipv6_count = 0; + + if (!geoip_is_loaded(AF_INET) && !geoip_is_loaded(AF_INET6)) + return -1; + + counts = tor_malloc_zero(sizeof(unsigned)*n_countries); + HT_FOREACH(ent, clientmap, &client_history) { + int country; + if ((*ent)->action != (int)action) + continue; + country = geoip_get_country_by_addr(&(*ent)->addr); + if (country < 0) + country = 0; /** unresolved requests are stored at index 0. */ + tor_assert(0 <= country && country < n_countries); + ++counts[country]; + ++total; + switch (tor_addr_family(&(*ent)->addr)) { + case AF_INET: + ipv4_count++; + break; + case AF_INET6: + ipv6_count++; + break; + } + } + if (ipver_str) { + smartlist_t *chunks = smartlist_new(); + smartlist_add_asprintf(chunks, "v4=%u", + round_to_next_multiple_of(ipv4_count, granularity)); + smartlist_add_asprintf(chunks, "v6=%u", + round_to_next_multiple_of(ipv6_count, granularity)); + *ipver_str = smartlist_join_strings(chunks, ",", 0, NULL); + SMARTLIST_FOREACH(chunks, char *, c, tor_free(c)); + smartlist_free(chunks); + } + + /* Don't record per country data if we haven't seen enough IPs. */ + if (total < MIN_IPS_TO_NOTE_ANYTHING) { + tor_free(counts); + if (country_str) + *country_str = NULL; + return 0; + } + + /* Make a list of c_hist_t */ + entries = smartlist_new(); + for (i = 0; i < n_countries; ++i) { + unsigned c = counts[i]; + const char *countrycode; + c_hist_t *ent; + /* Only report a country if it has a minimum number of IPs. */ + if (c >= MIN_IPS_TO_NOTE_COUNTRY) { + c = round_to_next_multiple_of(c, granularity); + countrycode = geoip_get_country_name(i); + ent = tor_malloc(sizeof(c_hist_t)); + strlcpy(ent->country, countrycode, sizeof(ent->country)); + ent->total = c; + smartlist_add(entries, ent); + } + } + /* Sort entries. Note that we must do this _AFTER_ rounding, or else + * the sort order could leak info. */ + smartlist_sort(entries, c_hist_compare_); + + if (country_str) { + smartlist_t *chunks = smartlist_new(); + SMARTLIST_FOREACH(entries, c_hist_t *, ch, { + smartlist_add_asprintf(chunks, "%s=%u", ch->country, ch->total); + }); + *country_str = smartlist_join_strings(chunks, ",", 0, NULL); + SMARTLIST_FOREACH(chunks, char *, c, tor_free(c)); + smartlist_free(chunks); + } + + SMARTLIST_FOREACH(entries, c_hist_t *, c, tor_free(c)); + smartlist_free(entries); + tor_free(counts); + + return 0; +} + +/** Return a newly allocated string holding the per-country request history + * for v3 network statuses in a format suitable for an extra-info document, + * or NULL on failure. */ +char * +geoip_get_request_history(void) +{ + smartlist_t *entries, *strings; + char *result; + unsigned granularity = IP_GRANULARITY; + + if (!geoip_countries) + return NULL; + + entries = smartlist_new(); + SMARTLIST_FOREACH_BEGIN(geoip_countries, geoip_country_t *, c) { + uint32_t tot = 0; + c_hist_t *ent; + tot = c->n_v3_ns_requests; + if (!tot) + continue; + ent = tor_malloc_zero(sizeof(c_hist_t)); + strlcpy(ent->country, c->countrycode, sizeof(ent->country)); + ent->total = round_to_next_multiple_of(tot, granularity); + smartlist_add(entries, ent); + } SMARTLIST_FOREACH_END(c); + smartlist_sort(entries, c_hist_compare_); + + strings = smartlist_new(); + SMARTLIST_FOREACH(entries, c_hist_t *, ent, { + smartlist_add_asprintf(strings, "%s=%u", ent->country, ent->total); + }); + result = smartlist_join_strings(strings, ",", 0, NULL); + SMARTLIST_FOREACH(strings, char *, cp, tor_free(cp)); + SMARTLIST_FOREACH(entries, c_hist_t *, ent, tor_free(ent)); + smartlist_free(strings); + smartlist_free(entries); + return result; +} + +/** Start time of directory request stats or 0 if we're not collecting + * directory request statistics. */ +static time_t start_of_dirreq_stats_interval; + +/** Initialize directory request stats. */ +void +geoip_dirreq_stats_init(time_t now) +{ + start_of_dirreq_stats_interval = now; +} + +/** Reset counters for dirreq stats. */ +void +geoip_reset_dirreq_stats(time_t now) +{ + SMARTLIST_FOREACH(geoip_countries, geoip_country_t *, c, { + c->n_v3_ns_requests = 0; + }); + { + clientmap_entry_t **ent, **next, *this; + for (ent = HT_START(clientmap, &client_history); ent != NULL; + ent = next) { + if ((*ent)->action == GEOIP_CLIENT_NETWORKSTATUS) { + this = *ent; + next = HT_NEXT_RMV(clientmap, &client_history, ent); + clientmap_entry_free(this); + } else { + next = HT_NEXT(clientmap, &client_history, ent); + } + } + } + memset(ns_v3_responses, 0, sizeof(ns_v3_responses)); + { + dirreq_map_entry_t **ent, **next, *this; + for (ent = HT_START(dirreqmap, &dirreq_map); ent != NULL; ent = next) { + this = *ent; + next = HT_NEXT_RMV(dirreqmap, &dirreq_map, ent); + tor_free(this); + } + } + start_of_dirreq_stats_interval = now; +} + +/** Stop collecting directory request stats in a way that we can re-start + * doing so in geoip_dirreq_stats_init(). */ +void +geoip_dirreq_stats_term(void) +{ + geoip_reset_dirreq_stats(0); +} + +/** Return a newly allocated string containing the dirreq statistics + * until now, or NULL if we're not collecting dirreq stats. Caller + * must ensure start_of_dirreq_stats_interval is in the past. */ +char * +geoip_format_dirreq_stats(time_t now) +{ + char t[ISO_TIME_LEN+1]; + int i; + char *v3_ips_string, *v3_reqs_string, *v3_direct_dl_string, + *v3_tunneled_dl_string; + char *result; + + if (!start_of_dirreq_stats_interval) + return NULL; /* Not initialized. */ + + tor_assert(now >= start_of_dirreq_stats_interval); + + format_iso_time(t, now); + geoip_get_client_history(GEOIP_CLIENT_NETWORKSTATUS, &v3_ips_string, NULL); + v3_reqs_string = geoip_get_request_history(); + +#define RESPONSE_GRANULARITY 8 + for (i = 0; i < GEOIP_NS_RESPONSE_NUM; i++) { + ns_v3_responses[i] = round_uint32_to_next_multiple_of( + ns_v3_responses[i], RESPONSE_GRANULARITY); + } +#undef RESPONSE_GRANULARITY + + v3_direct_dl_string = geoip_get_dirreq_history(DIRREQ_DIRECT); + v3_tunneled_dl_string = geoip_get_dirreq_history(DIRREQ_TUNNELED); + + /* Put everything together into a single string. */ + tor_asprintf(&result, "dirreq-stats-end %s (%d s)\n" + "dirreq-v3-ips %s\n" + "dirreq-v3-reqs %s\n" + "dirreq-v3-resp ok=%u,not-enough-sigs=%u,unavailable=%u," + "not-found=%u,not-modified=%u,busy=%u\n" + "dirreq-v3-direct-dl %s\n" + "dirreq-v3-tunneled-dl %s\n", + t, + (unsigned) (now - start_of_dirreq_stats_interval), + v3_ips_string ? v3_ips_string : "", + v3_reqs_string ? v3_reqs_string : "", + ns_v3_responses[GEOIP_SUCCESS], + ns_v3_responses[GEOIP_REJECT_NOT_ENOUGH_SIGS], + ns_v3_responses[GEOIP_REJECT_UNAVAILABLE], + ns_v3_responses[GEOIP_REJECT_NOT_FOUND], + ns_v3_responses[GEOIP_REJECT_NOT_MODIFIED], + ns_v3_responses[GEOIP_REJECT_BUSY], + v3_direct_dl_string ? v3_direct_dl_string : "", + v3_tunneled_dl_string ? v3_tunneled_dl_string : ""); + + /* Free partial strings. */ + tor_free(v3_ips_string); + tor_free(v3_reqs_string); + tor_free(v3_direct_dl_string); + tor_free(v3_tunneled_dl_string); + + return result; +} + +/** If 24 hours have passed since the beginning of the current dirreq + * stats period, write dirreq stats to $DATADIR/stats/dirreq-stats + * (possibly overwriting an existing file) and reset counters. Return + * when we would next want to write dirreq stats or 0 if we never want to + * write. */ +time_t +geoip_dirreq_stats_write(time_t now) +{ + char *str = NULL; + + if (!start_of_dirreq_stats_interval) + return 0; /* Not initialized. */ + if (start_of_dirreq_stats_interval + WRITE_STATS_INTERVAL > now) + goto done; /* Not ready to write. */ + + /* Discard all items in the client history that are too old. */ + geoip_remove_old_clients(start_of_dirreq_stats_interval); + + /* Generate history string .*/ + str = geoip_format_dirreq_stats(now); + + /* Write dirreq-stats string to disk. */ + if (!check_or_create_data_subdir("stats")) { + write_to_data_subdir("stats", "dirreq-stats", str, "dirreq statistics"); + /* Reset measurement interval start. */ + geoip_reset_dirreq_stats(now); + } + + done: + tor_free(str); + return start_of_dirreq_stats_interval + WRITE_STATS_INTERVAL; +} + +/** Start time of bridge stats or 0 if we're not collecting bridge + * statistics. */ +static time_t start_of_bridge_stats_interval; + +/** Initialize bridge stats. */ +void +geoip_bridge_stats_init(time_t now) +{ + start_of_bridge_stats_interval = now; +} + +/** Stop collecting bridge stats in a way that we can re-start doing so in + * geoip_bridge_stats_init(). */ +void +geoip_bridge_stats_term(void) +{ + client_history_clear(); + start_of_bridge_stats_interval = 0; +} + +/** Validate a bridge statistics string as it would be written to a + * current extra-info descriptor. Return 1 if the string is valid and + * recent enough, or 0 otherwise. */ +static int +validate_bridge_stats(const char *stats_str, time_t now) +{ + char stats_end_str[ISO_TIME_LEN+1], stats_start_str[ISO_TIME_LEN+1], + *eos; + + const char *BRIDGE_STATS_END = "bridge-stats-end "; + const char *BRIDGE_IPS = "bridge-ips "; + const char *BRIDGE_IPS_EMPTY_LINE = "bridge-ips\n"; + const char *BRIDGE_TRANSPORTS = "bridge-ip-transports "; + const char *BRIDGE_TRANSPORTS_EMPTY_LINE = "bridge-ip-transports\n"; + const char *tmp; + time_t stats_end_time; + int seconds; + tor_assert(stats_str); + + /* Parse timestamp and number of seconds from + "bridge-stats-end YYYY-MM-DD HH:MM:SS (N s)" */ + tmp = find_str_at_start_of_line(stats_str, BRIDGE_STATS_END); + if (!tmp) + return 0; + tmp += strlen(BRIDGE_STATS_END); + + if (strlen(tmp) < ISO_TIME_LEN + 6) + return 0; + strlcpy(stats_end_str, tmp, sizeof(stats_end_str)); + if (parse_iso_time(stats_end_str, &stats_end_time) < 0) + return 0; + if (stats_end_time < now - (25*60*60) || + stats_end_time > now + (1*60*60)) + return 0; + seconds = (int)strtol(tmp + ISO_TIME_LEN + 2, &eos, 10); + if (!eos || seconds < 23*60*60) + return 0; + format_iso_time(stats_start_str, stats_end_time - seconds); + + /* Parse: "bridge-ips CC=N,CC=N,..." */ + tmp = find_str_at_start_of_line(stats_str, BRIDGE_IPS); + if (!tmp) { + /* Look if there is an empty "bridge-ips" line */ + tmp = find_str_at_start_of_line(stats_str, BRIDGE_IPS_EMPTY_LINE); + if (!tmp) + return 0; + } + + /* Parse: "bridge-ip-transports PT=N,PT=N,..." */ + tmp = find_str_at_start_of_line(stats_str, BRIDGE_TRANSPORTS); + if (!tmp) { + /* Look if there is an empty "bridge-ip-transports" line */ + tmp = find_str_at_start_of_line(stats_str, BRIDGE_TRANSPORTS_EMPTY_LINE); + if (!tmp) + return 0; + } + + return 1; +} + +/** Most recent bridge statistics formatted to be written to extra-info + * descriptors. */ +static char *bridge_stats_extrainfo = NULL; + +/** Return a newly allocated string holding our bridge usage stats by country + * in a format suitable for inclusion in an extrainfo document. Return NULL on + * failure. */ +char * +geoip_format_bridge_stats(time_t now) +{ + char *out = NULL; + char *country_data = NULL, *ipver_data = NULL, *transport_data = NULL; + long duration = now - start_of_bridge_stats_interval; + char written[ISO_TIME_LEN+1]; + + if (duration < 0) + return NULL; + if (!start_of_bridge_stats_interval) + return NULL; /* Not initialized. */ + + format_iso_time(written, now); + geoip_get_client_history(GEOIP_CLIENT_CONNECT, &country_data, &ipver_data); + transport_data = geoip_get_transport_history(); + + tor_asprintf(&out, + "bridge-stats-end %s (%ld s)\n" + "bridge-ips %s\n" + "bridge-ip-versions %s\n" + "bridge-ip-transports %s\n", + written, duration, + country_data ? country_data : "", + ipver_data ? ipver_data : "", + transport_data ? transport_data : ""); + tor_free(country_data); + tor_free(ipver_data); + tor_free(transport_data); + + return out; +} + +/** Return a newly allocated string holding our bridge usage stats by country + * in a format suitable for the answer to a controller request. Return NULL on + * failure. */ +static char * +format_bridge_stats_controller(time_t now) +{ + char *out = NULL, *country_data = NULL, *ipver_data = NULL; + char started[ISO_TIME_LEN+1]; + (void) now; + + format_iso_time(started, start_of_bridge_stats_interval); + geoip_get_client_history(GEOIP_CLIENT_CONNECT, &country_data, &ipver_data); + + tor_asprintf(&out, + "TimeStarted=\"%s\" CountrySummary=%s IPVersions=%s", + started, + country_data ? country_data : "", + ipver_data ? ipver_data : ""); + tor_free(country_data); + tor_free(ipver_data); + return out; +} + +/** Write bridge statistics to $DATADIR/stats/bridge-stats and return + * when we should next try to write statistics. */ +time_t +geoip_bridge_stats_write(time_t now) +{ + char *val = NULL; + + /* Check if 24 hours have passed since starting measurements. */ + if (now < start_of_bridge_stats_interval + WRITE_STATS_INTERVAL) + return start_of_bridge_stats_interval + WRITE_STATS_INTERVAL; + + /* Discard all items in the client history that are too old. */ + geoip_remove_old_clients(start_of_bridge_stats_interval); + + /* Generate formatted string */ + val = geoip_format_bridge_stats(now); + if (val == NULL) + goto done; + + /* Update the stored value. */ + tor_free(bridge_stats_extrainfo); + bridge_stats_extrainfo = val; + start_of_bridge_stats_interval = now; + + /* Write it to disk. */ + if (!check_or_create_data_subdir("stats")) { + write_to_data_subdir("stats", "bridge-stats", + bridge_stats_extrainfo, "bridge statistics"); + + /* Tell the controller, "hey, there are clients!" */ + { + char *controller_str = format_bridge_stats_controller(now); + if (controller_str) + control_event_clients_seen(controller_str); + tor_free(controller_str); + } + } + + done: + return start_of_bridge_stats_interval + WRITE_STATS_INTERVAL; +} + +/** Try to load the most recent bridge statistics from disk, unless we + * have finished a measurement interval lately, and check whether they + * are still recent enough. */ +static void +load_bridge_stats(time_t now) +{ + char *fname, *contents; + if (bridge_stats_extrainfo) + return; + + fname = get_datadir_fname2("stats", "bridge-stats"); + contents = read_file_to_str(fname, RFTS_IGNORE_MISSING, NULL); + if (contents && validate_bridge_stats(contents, now)) { + bridge_stats_extrainfo = contents; + } else { + tor_free(contents); + } + + tor_free(fname); +} + +/** Return most recent bridge statistics for inclusion in extra-info + * descriptors, or NULL if we don't have recent bridge statistics. */ +const char * +geoip_get_bridge_stats_extrainfo(time_t now) +{ + load_bridge_stats(now); + return bridge_stats_extrainfo; +} + +/** Return a new string containing the recent bridge statistics to be returned + * to controller clients, or NULL if we don't have any bridge statistics. */ +char * +geoip_get_bridge_stats_controller(time_t now) +{ + return format_bridge_stats_controller(now); +} + +/** Start time of entry stats or 0 if we're not collecting entry + * statistics. */ +static time_t start_of_entry_stats_interval; + +/** Initialize entry stats. */ +void +geoip_entry_stats_init(time_t now) +{ + start_of_entry_stats_interval = now; +} + +/** Reset counters for entry stats. */ +void +geoip_reset_entry_stats(time_t now) +{ + client_history_clear(); + start_of_entry_stats_interval = now; +} + +/** Stop collecting entry stats in a way that we can re-start doing so in + * geoip_entry_stats_init(). */ +void +geoip_entry_stats_term(void) +{ + geoip_reset_entry_stats(0); +} + +/** Return a newly allocated string containing the entry statistics + * until now, or NULL if we're not collecting entry stats. Caller + * must ensure start_of_entry_stats_interval lies in the past. */ +char * +geoip_format_entry_stats(time_t now) +{ + char t[ISO_TIME_LEN+1]; + char *data = NULL; + char *result; + + if (!start_of_entry_stats_interval) + return NULL; /* Not initialized. */ + + tor_assert(now >= start_of_entry_stats_interval); + + geoip_get_client_history(GEOIP_CLIENT_CONNECT, &data, NULL); + format_iso_time(t, now); + tor_asprintf(&result, + "entry-stats-end %s (%u s)\n" + "entry-ips %s\n", + t, (unsigned) (now - start_of_entry_stats_interval), + data ? data : ""); + tor_free(data); + return result; +} + +/** If 24 hours have passed since the beginning of the current entry stats + * period, write entry stats to $DATADIR/stats/entry-stats (possibly + * overwriting an existing file) and reset counters. Return when we would + * next want to write entry stats or 0 if we never want to write. */ +time_t +geoip_entry_stats_write(time_t now) +{ + char *str = NULL; + + if (!start_of_entry_stats_interval) + return 0; /* Not initialized. */ + if (start_of_entry_stats_interval + WRITE_STATS_INTERVAL > now) + goto done; /* Not ready to write. */ + + /* Discard all items in the client history that are too old. */ + geoip_remove_old_clients(start_of_entry_stats_interval); + + /* Generate history string .*/ + str = geoip_format_entry_stats(now); + + /* Write entry-stats string to disk. */ + if (!check_or_create_data_subdir("stats")) { + write_to_data_subdir("stats", "entry-stats", str, "entry statistics"); + + /* Reset measurement interval start. */ + geoip_reset_entry_stats(now); + } + + done: + tor_free(str); + return start_of_entry_stats_interval + WRITE_STATS_INTERVAL; +} + +/** Helper used to implement GETINFO ip-to-country/... controller command. */ +int +getinfo_helper_geoip(control_connection_t *control_conn, + const char *question, char **answer, + const char **errmsg) +{ + (void)control_conn; + if (!strcmpstart(question, "ip-to-country/")) { + int c; + sa_family_t family; + tor_addr_t addr; + question += strlen("ip-to-country/"); + family = tor_addr_parse(&addr, question); + if (family != AF_INET && family != AF_INET6) { + *errmsg = "Invalid address family"; + return -1; + } + if (!geoip_is_loaded(family)) { + *errmsg = "GeoIP data not loaded"; + return -1; + } + if (family == AF_INET) + c = geoip_get_country_by_ipv4(tor_addr_to_ipv4h(&addr)); + else /* AF_INET6 */ + c = geoip_get_country_by_ipv6(tor_addr_to_in6(&addr)); + *answer = tor_strdup(geoip_get_country_name(c)); + } + return 0; +} + +/** Release all storage held by the GeoIP databases and country list. */ +static void +clear_geoip_db(void) +{ + if (geoip_countries) { + SMARTLIST_FOREACH(geoip_countries, geoip_country_t *, c, tor_free(c)); + smartlist_free(geoip_countries); + } + + strmap_free(country_idxplus1_by_lc_code, NULL); + if (geoip_ipv4_entries) { + SMARTLIST_FOREACH(geoip_ipv4_entries, geoip_ipv4_entry_t *, ent, + tor_free(ent)); + smartlist_free(geoip_ipv4_entries); + } + if (geoip_ipv6_entries) { + SMARTLIST_FOREACH(geoip_ipv6_entries, geoip_ipv6_entry_t *, ent, + tor_free(ent)); + smartlist_free(geoip_ipv6_entries); + } + geoip_countries = NULL; + country_idxplus1_by_lc_code = NULL; + geoip_ipv4_entries = NULL; + geoip_ipv6_entries = NULL; +} + +/** Release all storage held in this file. */ +void +geoip_free_all(void) +{ + { + clientmap_entry_t **ent, **next, *this; + for (ent = HT_START(clientmap, &client_history); ent != NULL; ent = next) { + this = *ent; + next = HT_NEXT_RMV(clientmap, &client_history, ent); + clientmap_entry_free(this); + } + HT_CLEAR(clientmap, &client_history); + } + { + dirreq_map_entry_t **ent, **next, *this; + for (ent = HT_START(dirreqmap, &dirreq_map); ent != NULL; ent = next) { + this = *ent; + next = HT_NEXT_RMV(dirreqmap, &dirreq_map, ent); + tor_free(this); + } + HT_CLEAR(dirreqmap, &dirreq_map); + } + + clear_geoip_db(); + tor_free(bridge_stats_extrainfo); +} + diff --git a/src/tor/geoip.h b/src/tor/geoip.h new file mode 100644 index 0000000..b9b53c3 --- /dev/null +++ b/src/tor/geoip.h @@ -0,0 +1,69 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file geoip.h + * \brief Header file for geoip.c. + **/ + +#ifndef TOR_GEOIP_H +#define TOR_GEOIP_H + +#include "testsupport.h" + +#ifdef GEOIP_PRIVATE +STATIC int geoip_parse_entry(const char *line, sa_family_t family); +STATIC int geoip_get_country_by_ipv4(uint32_t ipaddr); +STATIC int geoip_get_country_by_ipv6(const struct in6_addr *addr); +#endif +int should_record_bridge_info(const or_options_t *options); +int geoip_load_file(sa_family_t family, const char *filename); +int geoip_get_country_by_addr(const tor_addr_t *addr); +int geoip_get_n_countries(void); +const char *geoip_get_country_name(country_t num); +int geoip_is_loaded(sa_family_t family); +const char *geoip_db_digest(sa_family_t family); +country_t geoip_get_country(const char *countrycode); + +void geoip_note_client_seen(geoip_client_action_t action, + const tor_addr_t *addr, const char *transport_name, + time_t now); +void geoip_remove_old_clients(time_t cutoff); + +void geoip_note_ns_response(geoip_ns_response_t response); +char *geoip_get_transport_history(void); +int geoip_get_client_history(geoip_client_action_t action, + char **country_str, char **ipver_str); +char *geoip_get_request_history(void); +int getinfo_helper_geoip(control_connection_t *control_conn, + const char *question, char **answer, + const char **errmsg); +void geoip_free_all(void); + +void geoip_start_dirreq(uint64_t dirreq_id, size_t response_size, + dirreq_type_t type); +void geoip_change_dirreq_state(uint64_t dirreq_id, dirreq_type_t type, + dirreq_state_t new_state); + +void geoip_dirreq_stats_init(time_t now); +void geoip_reset_dirreq_stats(time_t now); +char *geoip_format_dirreq_stats(time_t now); +time_t geoip_dirreq_stats_write(time_t now); +void geoip_dirreq_stats_term(void); +void geoip_entry_stats_init(time_t now); +time_t geoip_entry_stats_write(time_t now); +void geoip_entry_stats_term(void); +void geoip_reset_entry_stats(time_t now); +char *geoip_format_entry_stats(time_t now); +void geoip_bridge_stats_init(time_t now); +char *geoip_format_bridge_stats(time_t now); +time_t geoip_bridge_stats_write(time_t now); +void geoip_bridge_stats_term(void); +const char *geoip_get_bridge_stats_extrainfo(time_t); +char *geoip_get_bridge_stats_controller(time_t); + +#endif + diff --git a/src/tor/hibernate.c b/src/tor/hibernate.c new file mode 100644 index 0000000..c234e4e --- /dev/null +++ b/src/tor/hibernate.c @@ -0,0 +1,1031 @@ +/* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file hibernate.c + * \brief Functions to close listeners, stop allowing new circuits, + * etc in preparation for closing down or going dormant; and to track + * bandwidth and time intervals to know when to hibernate and when to + * stop hibernating. + **/ + +/* +hibernating, phase 1: + - send destroy in response to create cells + - send end (policy failed) in response to begin cells + - close an OR conn when it has no circuits + +hibernating, phase 2: + (entered when bandwidth hard limit reached) + - close all OR/AP/exit conns) +*/ + +#define HIBERNATE_PRIVATE +#include "or.h" +#include "channel.h" +#include "channeltls.h" +#include "config.h" +#include "connection.h" +#include "connection_edge.h" +#include "hibernate.h" +#include "onion_main.h" +#include "router.h" +#include "statefile.h" + +extern long stats_n_seconds_working; /* published uptime */ + +/** Are we currently awake, asleep, running out of bandwidth, or shutting + * down? */ +static hibernate_state_t hibernate_state = HIBERNATE_STATE_INITIAL; +/** If are hibernating, when do we plan to wake up? Set to 0 if we + * aren't hibernating. */ +static time_t hibernate_end_time = 0; +/** If we are shutting down, when do we plan finally exit? Set to 0 if + * we aren't shutting down. */ +static time_t shutdown_time = 0; + +/** Possible accounting periods. */ +typedef enum { + UNIT_MONTH=1, UNIT_WEEK=2, UNIT_DAY=3, +} time_unit_t; + +/* Fields for accounting logic. Accounting overview: + * + * Accounting is designed to ensure that no more than N bytes are sent in + * either direction over a given interval (currently, one month, one week, or + * one day) We could + * try to do this by choking our bandwidth to a trickle, but that + * would make our streams useless. Instead, we estimate what our + * bandwidth usage will be, and guess how long we'll be able to + * provide that much bandwidth before hitting our limit. We then + * choose a random time within the accounting interval to come up (so + * that we don't get 50 Tors running on the 1st of the month and none + * on the 30th). + * + * Each interval runs as follows: + * + * 1. We guess our bandwidth usage, based on how much we used + * last time. We choose a "wakeup time" within the interval to come up. + * 2. Until the chosen wakeup time, we hibernate. + * 3. We come up at the wakeup time, and provide bandwidth until we are + * "very close" to running out. + * 4. Then we go into low-bandwidth mode, and stop accepting new + * connections, but provide bandwidth until we run out. + * 5. Then we hibernate until the end of the interval. + * + * If the interval ends before we run out of bandwidth, we go back to + * step one. + */ + +/** How many bytes have we read in this accounting interval? */ +static uint64_t n_bytes_read_in_interval = 0; +/** How many bytes have we written in this accounting interval? */ +static uint64_t n_bytes_written_in_interval = 0; +/** How many seconds have we been running this interval? */ +static uint32_t n_seconds_active_in_interval = 0; +/** How many seconds were we active in this interval before we hit our soft + * limit? */ +static int n_seconds_to_hit_soft_limit = 0; +/** When in this interval was the soft limit hit. */ +static time_t soft_limit_hit_at = 0; +/** How many bytes had we read/written when we hit the soft limit? */ +static uint64_t n_bytes_at_soft_limit = 0; +/** When did this accounting interval start? */ +static time_t interval_start_time = 0; +/** When will this accounting interval end? */ +static time_t interval_end_time = 0; +/** How far into the accounting interval should we hibernate? */ +static time_t interval_wakeup_time = 0; +/** How much bandwidth do we 'expect' to use per minute? (0 if we have no + * info from the last period.) */ +static uint64_t expected_bandwidth_usage = 0; +/** What unit are we using for our accounting? */ +static time_unit_t cfg_unit = UNIT_MONTH; + +/** How many days,hours,minutes into each unit does our accounting interval + * start? */ +/** @{ */ +static int cfg_start_day = 0, + cfg_start_hour = 0, + cfg_start_min = 0; +/** @} */ + +static void reset_accounting(time_t now); +static int read_bandwidth_usage(void); +static time_t start_of_accounting_period_after(time_t now); +static time_t start_of_accounting_period_containing(time_t now); +static void accounting_set_wakeup_time(void); + +/* ************ + * Functions for bandwidth accounting. + * ************/ + +/** Configure accounting start/end time settings based on + * options->AccountingStart. Return 0 on success, -1 on failure. If + * validate_only is true, do not change the current settings. */ +int +accounting_parse_options(const or_options_t *options, int validate_only) +{ + time_unit_t unit; + int ok, idx; + long d,h,m; + smartlist_t *items; + const char *v = options->AccountingStart; + const char *s; + char *cp; + + if (!v) { + if (!validate_only) { + cfg_unit = UNIT_MONTH; + cfg_start_day = 1; + cfg_start_hour = 0; + cfg_start_min = 0; + } + return 0; + } + + items = smartlist_new(); + smartlist_split_string(items, v, NULL, + SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK,0); + if (smartlist_len(items)<2) { + log_warn(LD_CONFIG, "Too few arguments to AccountingStart"); + goto err; + } + s = smartlist_get(items,0); + if (0==strcasecmp(s, "month")) { + unit = UNIT_MONTH; + } else if (0==strcasecmp(s, "week")) { + unit = UNIT_WEEK; + } else if (0==strcasecmp(s, "day")) { + unit = UNIT_DAY; + } else { + log_warn(LD_CONFIG, + "Unrecognized accounting unit '%s': only 'month', 'week'," + " and 'day' are supported.", s); + goto err; + } + + switch (unit) { + case UNIT_WEEK: + d = tor_parse_long(smartlist_get(items,1), 10, 1, 7, &ok, NULL); + if (!ok) { + log_warn(LD_CONFIG, "Weekly accounting must begin on a day between " + "1 (Monday) and 7 (Sunday)"); + goto err; + } + break; + case UNIT_MONTH: + d = tor_parse_long(smartlist_get(items,1), 10, 1, 28, &ok, NULL); + if (!ok) { + log_warn(LD_CONFIG, "Monthly accounting must begin on a day between " + "1 and 28"); + goto err; + } + break; + case UNIT_DAY: + d = 0; + break; + /* Coverity dislikes unreachable default cases; some compilers warn on + * switch statements missing a case. Tell Coverity not to worry. */ + /* coverity[dead_error_begin] */ + default: + tor_assert(0); + } + + idx = unit==UNIT_DAY?1:2; + if (smartlist_len(items) != (idx+1)) { + log_warn(LD_CONFIG,"Accounting unit '%s' requires %d argument%s.", + s, idx, (idx>1)?"s":""); + goto err; + } + s = smartlist_get(items, idx); + h = tor_parse_long(s, 10, 0, 23, &ok, &cp); + if (!ok) { + log_warn(LD_CONFIG,"Accounting start time not parseable: bad hour."); + goto err; + } + if (!cp || *cp!=':') { + log_warn(LD_CONFIG, + "Accounting start time not parseable: not in HH:MM format"); + goto err; + } + m = tor_parse_long(cp+1, 10, 0, 59, &ok, &cp); + if (!ok) { + log_warn(LD_CONFIG, "Accounting start time not parseable: bad minute"); + goto err; + } + if (!cp || *cp!='\0') { + log_warn(LD_CONFIG, + "Accounting start time not parseable: not in HH:MM format"); + goto err; + } + + if (!validate_only) { + cfg_unit = unit; + cfg_start_day = (int)d; + cfg_start_hour = (int)h; + cfg_start_min = (int)m; + } + SMARTLIST_FOREACH(items, char *, item, tor_free(item)); + smartlist_free(items); + return 0; + err: + SMARTLIST_FOREACH(items, char *, item, tor_free(item)); + smartlist_free(items); + return -1; +} + +/** If we want to manage the accounting system and potentially + * hibernate, return 1, else return 0. + */ +int +accounting_is_enabled(const or_options_t *options) +{ + if (options->AccountingMax) + return 1; + return 0; +} + +/** If accounting is enabled, return how long (in seconds) this + * interval lasts. */ +int +accounting_get_interval_length(void) +{ + return (int)(interval_end_time - interval_start_time); +} + +/** Return the time at which the current accounting interval will end. */ +time_t +accounting_get_end_time(void) +{ + return interval_end_time; +} + +/** Called from onion_main.c to tell us that seconds seconds have + * passed, n_read bytes have been read, and n_written + * bytes have been written. */ +void +accounting_add_bytes(size_t n_read, size_t n_written, int seconds) +{ + n_bytes_read_in_interval += n_read; + n_bytes_written_in_interval += n_written; + /* If we haven't been called in 10 seconds, we're probably jumping + * around in time. */ + n_seconds_active_in_interval += (seconds < 10) ? seconds : 0; +} + +/** If get_end, return the end of the accounting period that contains + * the time now. Else, return the start of the accounting + * period that contains the time now */ +static time_t +edge_of_accounting_period_containing(time_t now, int get_end) +{ + int before; + struct tm tm; + tor_localtime_r(&now, &tm); + + /* Set 'before' to true iff the current time is before the hh:mm + * changeover time for today. */ + before = tm.tm_hour < cfg_start_hour || + (tm.tm_hour == cfg_start_hour && tm.tm_min < cfg_start_min); + + /* Dispatch by unit. First, find the start day of the given period; + * then, if get_end is true, increment to the end day. */ + switch (cfg_unit) + { + case UNIT_MONTH: { + /* If this is before the Nth, we want the Nth of last month. */ + if (tm.tm_mday < cfg_start_day || + (tm.tm_mday < cfg_start_day && before)) { + --tm.tm_mon; + } + /* Otherwise, the month is correct. */ + tm.tm_mday = cfg_start_day; + if (get_end) + ++tm.tm_mon; + break; + } + case UNIT_WEEK: { + /* What is the 'target' day of the week in struct tm format? (We + say Sunday==7; struct tm says Sunday==0.) */ + int wday = cfg_start_day % 7; + /* How many days do we subtract from today to get to the right day? */ + int delta = (7+tm.tm_wday-wday)%7; + /* If we are on the right day, but the changeover hasn't happened yet, + * then subtract a whole week. */ + if (delta == 0 && before) + delta = 7; + tm.tm_mday -= delta; + if (get_end) + tm.tm_mday += 7; + break; + } + case UNIT_DAY: + if (before) + --tm.tm_mday; + if (get_end) + ++tm.tm_mday; + break; + default: + tor_assert(0); + } + + tm.tm_hour = cfg_start_hour; + tm.tm_min = cfg_start_min; + tm.tm_sec = 0; + tm.tm_isdst = -1; /* Autodetect DST */ + return mktime(&tm); +} + +/** Return the start of the accounting period containing the time + * now. */ +static time_t +start_of_accounting_period_containing(time_t now) +{ + return edge_of_accounting_period_containing(now, 0); +} + +/** Return the start of the accounting period that comes after the one + * containing the time now. */ +static time_t +start_of_accounting_period_after(time_t now) +{ + return edge_of_accounting_period_containing(now, 1); +} + +/** Return the length of the accounting period containing the time + * now. */ +static long +length_of_accounting_period_containing(time_t now) +{ + return edge_of_accounting_period_containing(now, 1) - + edge_of_accounting_period_containing(now, 0); +} + +/** Initialize the accounting subsystem. */ +void +configure_accounting(time_t now) +{ + time_t s_now; + /* Try to remember our recorded usage. */ + if (!interval_start_time) + read_bandwidth_usage(); /* If we fail, we'll leave values at zero, and + * reset below.*/ + + s_now = start_of_accounting_period_containing(now); + + if (!interval_start_time) { + /* We didn't have recorded usage; Start a new interval. */ + log_info(LD_ACCT, "Starting new accounting interval."); + reset_accounting(now); + } else if (s_now == interval_start_time) { + log_info(LD_ACCT, "Continuing accounting interval."); + /* We are in the interval we thought we were in. Do nothing.*/ + interval_end_time = start_of_accounting_period_after(interval_start_time); + } else { + long duration = + length_of_accounting_period_containing(interval_start_time); + double delta = ((double)(s_now - interval_start_time)) / duration; + if (-0.50 <= delta && delta <= 0.50) { + /* The start of the period is now a little later or earlier than we + * remembered. That's fine; we might lose some bytes we could otherwise + * have written, but better to err on the side of obeying people's + * accounting settings. */ + log_info(LD_ACCT, "Accounting interval moved by %.02f%%; " + "that's fine.", delta*100); + interval_end_time = start_of_accounting_period_after(now); + } else if (delta >= 0.99) { + /* This is the regular time-moved-forward case; don't be too noisy + * about it or people will complain */ + log_info(LD_ACCT, "Accounting interval elapsed; starting a new one"); + reset_accounting(now); + } else { + log_warn(LD_ACCT, + "Mismatched accounting interval: moved by %.02f%%. " + "Starting a fresh one.", delta*100); + reset_accounting(now); + } + } + accounting_set_wakeup_time(); +} + +/** Set expected_bandwidth_usage based on how much we sent/received + * per minute last interval (if we were up for at least 30 minutes), + * or based on our declared bandwidth otherwise. */ +static void +update_expected_bandwidth(void) +{ + uint64_t expected; + const or_options_t *options= get_options(); + uint64_t max_configured = (options->RelayBandwidthRate > 0 ? + options->RelayBandwidthRate : + options->BandwidthRate) * 60; + +#define MIN_TIME_FOR_MEASUREMENT (1800) + + if (soft_limit_hit_at > interval_start_time && n_bytes_at_soft_limit && + (soft_limit_hit_at - interval_start_time) > MIN_TIME_FOR_MEASUREMENT) { + /* If we hit our soft limit last time, only count the bytes up to that + * time. This is a better predictor of our actual bandwidth than + * considering the entirety of the last interval, since we likely started + * using bytes very slowly once we hit our soft limit. */ + expected = n_bytes_at_soft_limit / + (soft_limit_hit_at - interval_start_time); + expected /= 60; + } else if (n_seconds_active_in_interval >= MIN_TIME_FOR_MEASUREMENT) { + /* Otherwise, we either measured enough time in the last interval but + * never hit our soft limit, or we're using a state file from a Tor that + * doesn't know to store soft-limit info. Just take rate at which + * we were reading/writing in the last interval as our expected rate. + */ + uint64_t used = MAX(n_bytes_written_in_interval, + n_bytes_read_in_interval); + expected = used / (n_seconds_active_in_interval / 60); + } else { + /* If we haven't gotten enough data last interval, set 'expected' + * to 0. This will set our wakeup to the start of the interval. + * Next interval, we'll choose our starting time based on how much + * we sent this interval. + */ + expected = 0; + } + if (expected > max_configured) + expected = max_configured; + expected_bandwidth_usage = expected; +} + +/** Called at the start of a new accounting interval: reset our + * expected bandwidth usage based on what happened last time, set up + * the start and end of the interval, and clear byte/time totals. + */ +static void +reset_accounting(time_t now) +{ + log_info(LD_ACCT, "Starting new accounting interval."); + update_expected_bandwidth(); + interval_start_time = start_of_accounting_period_containing(now); + interval_end_time = start_of_accounting_period_after(interval_start_time); + n_bytes_read_in_interval = 0; + n_bytes_written_in_interval = 0; + n_seconds_active_in_interval = 0; + n_bytes_at_soft_limit = 0; + soft_limit_hit_at = 0; + n_seconds_to_hit_soft_limit = 0; +} + +/** Return true iff we should save our bandwidth usage to disk. */ +static INLINE int +time_to_record_bandwidth_usage(time_t now) +{ + /* Note every 600 sec */ +#define NOTE_INTERVAL (600) + /* Or every 20 megabytes */ +#define NOTE_BYTES 20*(1024*1024) + static uint64_t last_read_bytes_noted = 0; + static uint64_t last_written_bytes_noted = 0; + static time_t last_time_noted = 0; + + if (last_time_noted + NOTE_INTERVAL <= now || + last_read_bytes_noted + NOTE_BYTES <= n_bytes_read_in_interval || + last_written_bytes_noted + NOTE_BYTES <= n_bytes_written_in_interval || + (interval_end_time && interval_end_time <= now)) { + last_time_noted = now; + last_read_bytes_noted = n_bytes_read_in_interval; + last_written_bytes_noted = n_bytes_written_in_interval; + return 1; + } + return 0; +} + +/** Invoked once per second. Checks whether it is time to hibernate, + * record bandwidth used, etc. */ +void +accounting_run_housekeeping(time_t now) +{ + if (now >= interval_end_time) { + configure_accounting(now); + } + if (time_to_record_bandwidth_usage(now)) { + if (accounting_record_bandwidth_usage(now, get_or_state())) { + log_warn(LD_FS, "Couldn't record bandwidth usage to disk."); + } + } +} + +/** Based on our interval and our estimated bandwidth, choose a + * deterministic (but random-ish) time to wake up. */ +static void +accounting_set_wakeup_time(void) +{ + char digest[DIGEST_LEN]; + crypto_digest_t *d_env; + uint64_t time_to_exhaust_bw; + int time_to_consider; + + if (! server_identity_key_is_set()) { + if (init_keys() < 0) { + log_err(LD_BUG, "Error initializing keys"); + tor_assert(0); + } + } + + if (server_identity_key_is_set()) { + char buf[ISO_TIME_LEN+1]; + format_iso_time(buf, interval_start_time); + + crypto_pk_get_digest(get_server_identity_key(), digest); + + d_env = crypto_digest_new(); + crypto_digest_add_bytes(d_env, buf, ISO_TIME_LEN); + crypto_digest_add_bytes(d_env, digest, DIGEST_LEN); + crypto_digest_get_digest(d_env, digest, DIGEST_LEN); + crypto_digest_free(d_env); + } else { + crypto_rand(digest, DIGEST_LEN); + } + + if (!expected_bandwidth_usage) { + char buf1[ISO_TIME_LEN+1]; + char buf2[ISO_TIME_LEN+1]; + format_local_iso_time(buf1, interval_start_time); + format_local_iso_time(buf2, interval_end_time); + interval_wakeup_time = interval_start_time; + + log_notice(LD_ACCT, + "Configured hibernation. This interval begins at %s " + "and ends at %s. We have no prior estimate for bandwidth, so " + "we will start out awake and hibernate when we exhaust our quota.", + buf1, buf2); + return; + } + + time_to_exhaust_bw = + (get_options()->AccountingMax/expected_bandwidth_usage)*60; + if (time_to_exhaust_bw > INT_MAX) { + time_to_exhaust_bw = INT_MAX; + time_to_consider = 0; + } else { + time_to_consider = accounting_get_interval_length() - + (int)time_to_exhaust_bw; + } + + if (time_to_consider<=0) { + interval_wakeup_time = interval_start_time; + } else { + /* XXX can we simplify this just by picking a random (non-deterministic) + * time to be up? If we go down and come up, then we pick a new one. Is + * that good enough? -RD */ + + /* This is not a perfectly unbiased conversion, but it is good enough: + * in the worst case, the first half of the day is 0.06 percent likelier + * to be chosen than the last half. */ + interval_wakeup_time = interval_start_time + + (get_uint32(digest) % time_to_consider); + } + + { + char buf1[ISO_TIME_LEN+1]; + char buf2[ISO_TIME_LEN+1]; + char buf3[ISO_TIME_LEN+1]; + char buf4[ISO_TIME_LEN+1]; + time_t down_time; + if (interval_wakeup_time+time_to_exhaust_bw > TIME_MAX) + down_time = TIME_MAX; + else + down_time = (time_t)(interval_wakeup_time+time_to_exhaust_bw); + if (down_time>interval_end_time) + down_time = interval_end_time; + format_local_iso_time(buf1, interval_start_time); + format_local_iso_time(buf2, interval_wakeup_time); + format_local_iso_time(buf3, down_time); + format_local_iso_time(buf4, interval_end_time); + + log_notice(LD_ACCT, + "Configured hibernation. This interval began at %s; " + "the scheduled wake-up time %s %s; " + "we expect%s to exhaust our quota for this interval around %s; " + "the next interval begins at %s (all times local)", + buf1, + time(NULL)AccountingIntervalStart = interval_start_time; + state->AccountingBytesReadInInterval = ROUND_UP(n_bytes_read_in_interval); + state->AccountingBytesWrittenInInterval = + ROUND_UP(n_bytes_written_in_interval); + state->AccountingSecondsActive = n_seconds_active_in_interval; + state->AccountingExpectedUsage = expected_bandwidth_usage; + + state->AccountingSecondsToReachSoftLimit = n_seconds_to_hit_soft_limit; + state->AccountingSoftLimitHitAt = soft_limit_hit_at; + state->AccountingBytesAtSoftLimit = n_bytes_at_soft_limit; + + or_state_mark_dirty(state, + now+(get_options()->AvoidDiskWrites ? 7200 : 60)); + + return 0; +} +#undef ROUND_UP + +/** Read stored accounting information from disk. Return 0 on success; + * return -1 and change nothing on failure. */ +static int +read_bandwidth_usage(void) +{ + or_state_t *state = get_or_state(); + + { + char *fname = get_datadir_fname("bw_accounting"); + unlink(fname); + tor_free(fname); + } + + if (!state) + return -1; + + log_info(LD_ACCT, "Reading bandwidth accounting data from state file"); + n_bytes_read_in_interval = state->AccountingBytesReadInInterval; + n_bytes_written_in_interval = state->AccountingBytesWrittenInInterval; + n_seconds_active_in_interval = state->AccountingSecondsActive; + interval_start_time = state->AccountingIntervalStart; + expected_bandwidth_usage = state->AccountingExpectedUsage; + + /* Older versions of Tor (before 0.2.2.17-alpha or so) didn't generate these + * fields. If you switch back and forth, you might get an + * AccountingSoftLimitHitAt value from long before the most recent + * interval_start_time. If that's so, then ignore the softlimit-related + * values. */ + if (state->AccountingSoftLimitHitAt > interval_start_time) { + soft_limit_hit_at = state->AccountingSoftLimitHitAt; + n_bytes_at_soft_limit = state->AccountingBytesAtSoftLimit; + n_seconds_to_hit_soft_limit = state->AccountingSecondsToReachSoftLimit; + } else { + soft_limit_hit_at = 0; + n_bytes_at_soft_limit = 0; + n_seconds_to_hit_soft_limit = 0; + } + + { + char tbuf1[ISO_TIME_LEN+1]; + char tbuf2[ISO_TIME_LEN+1]; + format_iso_time(tbuf1, state->LastWritten); + format_iso_time(tbuf2, state->AccountingIntervalStart); + + log_info(LD_ACCT, + "Successfully read bandwidth accounting info from state written at %s " + "for interval starting at %s. We have been active for %lu seconds in " + "this interval. At the start of the interval, we expected to use " + "about %lu KB per second. ("U64_FORMAT" bytes read so far, " + U64_FORMAT" bytes written so far)", + tbuf1, tbuf2, + (unsigned long)n_seconds_active_in_interval, + (unsigned long)(expected_bandwidth_usage*1024/60), + U64_PRINTF_ARG(n_bytes_read_in_interval), + U64_PRINTF_ARG(n_bytes_written_in_interval)); + } + + return 0; +} + +/** Return true iff we have sent/received all the bytes we are willing + * to send/receive this interval. */ +static int +hibernate_hard_limit_reached(void) +{ + uint64_t hard_limit = get_options()->AccountingMax; + if (!hard_limit) + return 0; + return n_bytes_read_in_interval >= hard_limit + || n_bytes_written_in_interval >= hard_limit; +} + +/** Return true iff we have sent/received almost all the bytes we are willing + * to send/receive this interval. */ +static int +hibernate_soft_limit_reached(void) +{ + const uint64_t acct_max = get_options()->AccountingMax; +#define SOFT_LIM_PCT (.95) +#define SOFT_LIM_BYTES (500*1024*1024) +#define SOFT_LIM_MINUTES (3*60) + /* The 'soft limit' is a fair bit more complicated now than once it was. + * We want to stop accepting connections when ALL of the following are true: + * - We expect to use up the remaining bytes in under 3 hours + * - We have used up 95% of our bytes. + * - We have less than 500MB of bytes left. + */ + uint64_t soft_limit = DBL_TO_U64(U64_TO_DBL(acct_max) * SOFT_LIM_PCT); + if (acct_max > SOFT_LIM_BYTES && acct_max - SOFT_LIM_BYTES > soft_limit) { + soft_limit = acct_max - SOFT_LIM_BYTES; + } + if (expected_bandwidth_usage) { + const uint64_t expected_usage = + expected_bandwidth_usage * SOFT_LIM_MINUTES; + if (acct_max > expected_usage && acct_max - expected_usage > soft_limit) + soft_limit = acct_max - expected_usage; + } + + if (!soft_limit) + return 0; + return n_bytes_read_in_interval >= soft_limit + || n_bytes_written_in_interval >= soft_limit; +} + +/** Called when we get a SIGINT, or when bandwidth soft limit is + * reached. Puts us into "loose hibernation": we don't accept new + * connections, but we continue handling old ones. */ +static void +hibernate_begin(hibernate_state_t new_state, time_t now) +{ + const or_options_t *options = get_options(); + + if (new_state == HIBERNATE_STATE_EXITING && + hibernate_state != HIBERNATE_STATE_LIVE) { + log_notice(LD_GENERAL,"SIGINT received %s; exiting now.", + hibernate_state == HIBERNATE_STATE_EXITING ? + "a second time" : "while hibernating"); + tor_cleanup(); + exit(0); + } + + if (new_state == HIBERNATE_STATE_LOWBANDWIDTH && + hibernate_state == HIBERNATE_STATE_LIVE) { + soft_limit_hit_at = now; + n_seconds_to_hit_soft_limit = n_seconds_active_in_interval; + n_bytes_at_soft_limit = MAX(n_bytes_read_in_interval, + n_bytes_written_in_interval); + } + + /* close listeners. leave control listener(s). */ + connection_mark_all_noncontrol_listeners(); + + /* XXX kill intro point circs */ + /* XXX upload rendezvous service descriptors with no intro points */ + + if (new_state == HIBERNATE_STATE_EXITING) { + log_notice(LD_GENERAL,"Interrupt: we have stopped accepting new " + "connections, and will shut down in %d seconds. Interrupt " + "again to exit now.", options->ShutdownWaitLength); + shutdown_time = time(NULL) + options->ShutdownWaitLength; + } else { /* soft limit reached */ + hibernate_end_time = interval_end_time; + } + + hibernate_state = new_state; + accounting_record_bandwidth_usage(now, get_or_state()); + + or_state_mark_dirty(get_or_state(), + get_options()->AvoidDiskWrites ? now+600 : 0); +} + +/** Called when we've been hibernating and our timeout is reached. */ +static void +hibernate_end(hibernate_state_t new_state) +{ + tor_assert(hibernate_state == HIBERNATE_STATE_LOWBANDWIDTH || + hibernate_state == HIBERNATE_STATE_DORMANT || + hibernate_state == HIBERNATE_STATE_INITIAL); + + /* listeners will be relaunched in run_scheduled_events() in onion_main.c */ + if (hibernate_state != HIBERNATE_STATE_INITIAL) + log_notice(LD_ACCT,"Hibernation period ended. Resuming normal activity."); + + hibernate_state = new_state; + hibernate_end_time = 0; /* no longer hibernating */ + stats_n_seconds_working = 0; /* reset published uptime */ +} + +/** A wrapper around hibernate_begin, for when we get SIGINT. */ +void +hibernate_begin_shutdown(void) +{ + hibernate_begin(HIBERNATE_STATE_EXITING, time(NULL)); +} + +/** Return true iff we are currently hibernating. */ +int +we_are_hibernating(void) +{ + return hibernate_state != HIBERNATE_STATE_LIVE; +} + +/** If we aren't currently dormant, close all connections and become + * dormant. */ +static void +hibernate_go_dormant(time_t now) +{ + connection_t *conn; + + if (hibernate_state == HIBERNATE_STATE_DORMANT) + return; + else if (hibernate_state == HIBERNATE_STATE_LOWBANDWIDTH) + hibernate_state = HIBERNATE_STATE_DORMANT; + else + hibernate_begin(HIBERNATE_STATE_DORMANT, now); + + log_notice(LD_ACCT,"Going dormant. Blowing away remaining connections."); + + /* Close all OR/AP/exit conns. Leave dir conns because we still want + * to be able to upload server descriptors so people know we're still + * running, and download directories so we can detect if we're obsolete. + * Leave control conns because we still want to be controllable. + */ + while ((conn = connection_get_by_type(CONN_TYPE_OR)) || + (conn = connection_get_by_type(CONN_TYPE_AP)) || + (conn = connection_get_by_type(CONN_TYPE_EXIT))) { + if (CONN_IS_EDGE(conn)) + connection_edge_end(TO_EDGE_CONN(conn), END_STREAM_REASON_HIBERNATING); + log_info(LD_NET,"Closing conn type %d", conn->type); + if (conn->type == CONN_TYPE_AP) /* send socks failure if needed */ + connection_mark_unattached_ap(TO_ENTRY_CONN(conn), + END_STREAM_REASON_HIBERNATING); + else if (conn->type == CONN_TYPE_OR) { + if (TO_OR_CONN(conn)->chan) { + channel_mark_for_close(TLS_CHAN_TO_BASE(TO_OR_CONN(conn)->chan)); + } else { + connection_mark_for_close(conn); + } + } else + connection_mark_for_close(conn); + } + + if (now < interval_wakeup_time) + hibernate_end_time = interval_wakeup_time; + else + hibernate_end_time = interval_end_time; + + accounting_record_bandwidth_usage(now, get_or_state()); + + or_state_mark_dirty(get_or_state(), + get_options()->AvoidDiskWrites ? now+600 : 0); +} + +/** Called when hibernate_end_time has arrived. */ +static void +hibernate_end_time_elapsed(time_t now) +{ + char buf[ISO_TIME_LEN+1]; + + /* The interval has ended, or it is wakeup time. Find out which. */ + accounting_run_housekeeping(now); + if (interval_wakeup_time <= now) { + /* The interval hasn't changed, but interval_wakeup_time has passed. + * It's time to wake up and start being a server. */ + hibernate_end(HIBERNATE_STATE_LIVE); + return; + } else { + /* The interval has changed, and it isn't time to wake up yet. */ + hibernate_end_time = interval_wakeup_time; + format_iso_time(buf,interval_wakeup_time); + if (hibernate_state != HIBERNATE_STATE_DORMANT) { + /* We weren't sleeping before; we should sleep now. */ + log_notice(LD_ACCT, + "Accounting period ended. Commencing hibernation until " + "%s UTC", buf); + hibernate_go_dormant(now); + } else { + log_notice(LD_ACCT, + "Accounting period ended. This period, we will hibernate" + " until %s UTC",buf); + } + } +} + +/** Consider our environment and decide if it's time + * to start/stop hibernating. + */ +void +consider_hibernation(time_t now) +{ + int accounting_enabled = get_options()->AccountingMax != 0; + char buf[ISO_TIME_LEN+1]; + + /* If we're in 'exiting' mode, then we just shut down after the interval + * elapses. */ + if (hibernate_state == HIBERNATE_STATE_EXITING) { + tor_assert(shutdown_time); + if (shutdown_time <= now) { + log_notice(LD_GENERAL, "Clean shutdown finished. Exiting."); + tor_cleanup(); + exit(0); + } + return; /* if exiting soon, don't worry about bandwidth limits */ + } + + if (hibernate_state == HIBERNATE_STATE_DORMANT) { + /* We've been hibernating because of bandwidth accounting. */ + tor_assert(hibernate_end_time); + if (hibernate_end_time > now && accounting_enabled) { + /* If we're hibernating, don't wake up until it's time, regardless of + * whether we're in a new interval. */ + return ; + } else { + hibernate_end_time_elapsed(now); + } + } + + /* Else, we aren't hibernating. See if it's time to start hibernating, or to + * go dormant. */ + if (hibernate_state == HIBERNATE_STATE_LIVE || + hibernate_state == HIBERNATE_STATE_INITIAL) { + if (hibernate_soft_limit_reached()) { + log_notice(LD_ACCT, + "Bandwidth soft limit reached; commencing hibernation. " + "No new connections will be accepted"); + hibernate_begin(HIBERNATE_STATE_LOWBANDWIDTH, now); + } else if (accounting_enabled && now < interval_wakeup_time) { + format_local_iso_time(buf,interval_wakeup_time); + log_notice(LD_ACCT, + "Commencing hibernation. We will wake up at %s local time.", + buf); + hibernate_go_dormant(now); + } else if (hibernate_state == HIBERNATE_STATE_INITIAL) { + hibernate_end(HIBERNATE_STATE_LIVE); + } + } + + if (hibernate_state == HIBERNATE_STATE_LOWBANDWIDTH) { + if (!accounting_enabled) { + hibernate_end_time_elapsed(now); + } else if (hibernate_hard_limit_reached()) { + hibernate_go_dormant(now); + } else if (hibernate_end_time <= now) { + /* The hibernation period ended while we were still in lowbandwidth.*/ + hibernate_end_time_elapsed(now); + } + } +} + +/** Helper function: called when we get a GETINFO request for an + * accounting-related key on the control connection conn. If we can + * answer the request for question, then set *answer to a newly + * allocated string holding the result. Otherwise, set *answer to + * NULL. */ +int +getinfo_helper_accounting(control_connection_t *conn, + const char *question, char **answer, + const char **errmsg) +{ + (void) conn; + (void) errmsg; + if (!strcmp(question, "accounting/enabled")) { + *answer = tor_strdup(accounting_is_enabled(get_options()) ? "1" : "0"); + } else if (!strcmp(question, "accounting/hibernating")) { + if (hibernate_state == HIBERNATE_STATE_DORMANT) + *answer = tor_strdup("hard"); + else if (hibernate_state == HIBERNATE_STATE_LOWBANDWIDTH) + *answer = tor_strdup("soft"); + else + *answer = tor_strdup("awake"); + } else if (!strcmp(question, "accounting/bytes")) { + tor_asprintf(answer, U64_FORMAT" "U64_FORMAT, + U64_PRINTF_ARG(n_bytes_read_in_interval), + U64_PRINTF_ARG(n_bytes_written_in_interval)); + } else if (!strcmp(question, "accounting/bytes-left")) { + uint64_t limit = get_options()->AccountingMax; + uint64_t read_left = 0, write_left = 0; + if (n_bytes_read_in_interval < limit) + read_left = limit - n_bytes_read_in_interval; + if (n_bytes_written_in_interval < limit) + write_left = limit - n_bytes_written_in_interval; + tor_asprintf(answer, U64_FORMAT" "U64_FORMAT, + U64_PRINTF_ARG(read_left), U64_PRINTF_ARG(write_left)); + } else if (!strcmp(question, "accounting/interval-start")) { + *answer = tor_malloc(ISO_TIME_LEN+1); + format_iso_time(*answer, interval_start_time); + } else if (!strcmp(question, "accounting/interval-wake")) { + *answer = tor_malloc(ISO_TIME_LEN+1); + format_iso_time(*answer, interval_wakeup_time); + } else if (!strcmp(question, "accounting/interval-end")) { + *answer = tor_malloc(ISO_TIME_LEN+1); + format_iso_time(*answer, interval_end_time); + } else { + *answer = NULL; + } + return 0; +} + +#ifdef TOR_UNIT_TESTS +/** + * Manually change the hibernation state. Private; used only by the unit + * tests. + */ +void +hibernate_set_state_for_testing_(hibernate_state_t newstate) +{ + hibernate_state = newstate; +} +#endif + diff --git a/src/tor/hibernate.h b/src/tor/hibernate.h new file mode 100644 index 0000000..4f7331c --- /dev/null +++ b/src/tor/hibernate.h @@ -0,0 +1,55 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file hibernate.h + * \brief Header file for hibernate.c. + **/ + +#ifndef TOR_HIBERNATE_H +#define TOR_HIBERNATE_H + +int accounting_parse_options(const or_options_t *options, int validate_only); +int accounting_is_enabled(const or_options_t *options); +int accounting_get_interval_length(void); +time_t accounting_get_end_time(void); +void configure_accounting(time_t now); +void accounting_run_housekeeping(time_t now); +void accounting_add_bytes(size_t n_read, size_t n_written, int seconds); +int accounting_record_bandwidth_usage(time_t now, or_state_t *state); +void hibernate_begin_shutdown(void); +int we_are_hibernating(void); +void consider_hibernation(time_t now); +int getinfo_helper_accounting(control_connection_t *conn, + const char *question, char **answer, + const char **errmsg); + +#ifdef HIBERNATE_PRIVATE +/** Possible values of hibernate_state */ +typedef enum { + /** We are running normally. */ + HIBERNATE_STATE_LIVE=1, + /** We're trying to shut down cleanly, and we'll kill all active connections + * at shutdown_time. */ + HIBERNATE_STATE_EXITING=2, + /** We're running low on allocated bandwidth for this period, so we won't + * accept any new connections. */ + HIBERNATE_STATE_LOWBANDWIDTH=3, + /** We are hibernating, and we won't wake up till there's more bandwidth to + * use. */ + HIBERNATE_STATE_DORMANT=4, + /** We start out in state default, which means we havent decided which state + * we're in. */ + HIBERNATE_STATE_INITIAL=5 +} hibernate_state_t; + +#ifdef TOR_UNIT_TESTS +void hibernate_set_state_for_testing_(hibernate_state_t newstate); +#endif +#endif + +#endif + diff --git a/src/tor/ht.h b/src/tor/ht.h new file mode 100644 index 0000000..669a2ed --- /dev/null +++ b/src/tor/ht.h @@ -0,0 +1,490 @@ +/* Copyright (c) 2002, Christopher Clark. + * Copyright (c) 2005-2006, Nick Mathewson. + * Copyright (c) 2007-2013, The Tor Project, Inc. */ +/* See license at end. */ + +/* Based on ideas by Christopher Clark and interfaces from Niels Provos. */ + +#ifndef HT_H_INCLUDED_ +#define HT_H_INCLUDED_ + +#define HT_HEAD(name, type) \ + struct name { \ + /* The hash table itself. */ \ + struct type **hth_table; \ + /* How long is the hash table? */ \ + unsigned hth_table_length; \ + /* How many elements does the table contain? */ \ + unsigned hth_n_entries; \ + /* How many elements will we allow in the table before resizing it? */ \ + unsigned hth_load_limit; \ + /* Position of hth_table_length in the primes table. */ \ + int hth_prime_idx; \ + } + +#define HT_INITIALIZER() \ + { NULL, 0, 0, 0, -1 } + +#ifdef HT_NO_CACHE_HASH_VALUES +#define HT_ENTRY(type) \ + struct { \ + struct type *hte_next; \ + } +#else +#define HT_ENTRY(type) \ + struct { \ + struct type *hte_next; \ + unsigned hte_hash; \ + } +#endif + +#define HT_EMPTY(head) \ + ((head)->hth_n_entries == 0) + +/* How many elements in 'head'? */ +#define HT_SIZE(head) \ + ((head)->hth_n_entries) + +/* Return memory usage for a hashtable (not counting the entries themselves) */ +#define HT_MEM_USAGE(head) \ + (sizeof(*head) + (head)->hth_table_length * sizeof(void*)) + +#define HT_FIND(name, head, elm) name##_HT_FIND((head), (elm)) +#define HT_INSERT(name, head, elm) name##_HT_INSERT((head), (elm)) +#define HT_REPLACE(name, head, elm) name##_HT_REPLACE((head), (elm)) +#define HT_REMOVE(name, head, elm) name##_HT_REMOVE((head), (elm)) +#define HT_START(name, head) name##_HT_START(head) +#define HT_NEXT(name, head, elm) name##_HT_NEXT((head), (elm)) +#define HT_NEXT_RMV(name, head, elm) name##_HT_NEXT_RMV((head), (elm)) +#define HT_CLEAR(name, head) name##_HT_CLEAR(head) +#define HT_INIT(name, head) name##_HT_INIT(head) +/* Helper: */ +static INLINE unsigned +ht_improve_hash(unsigned h) +{ + /* Aim to protect against poor hash functions by adding logic here + * - logic taken from java 1.4 hashtable source */ + h += ~(h << 9); + h ^= ((h >> 14) | (h << 18)); /* >>> */ + h += (h << 4); + h ^= ((h >> 10) | (h << 22)); /* >>> */ + return h; +} + +#if 0 +/** Basic string hash function, from Java standard String.hashCode(). */ +static INLINE unsigned +ht_string_hash(const char *s) +{ + unsigned h = 0; + int m = 1; + while (*s) { + h += ((signed char)*s++)*m; + m = (m<<5)-1; /* m *= 31 */ + } + return h; +} +#endif + +/** Basic string hash function, from Python's str.__hash__() */ +static INLINE unsigned +ht_string_hash(const char *s) +{ + unsigned h; + const unsigned char *cp = (const unsigned char *)s; + h = *cp << 7; + while (*cp) { + h = (1000003*h) ^ *cp++; + } + /* This conversion truncates the length of the string, but that's ok. */ + h ^= (unsigned)(cp-(const unsigned char*)s); + return h; +} + +#ifndef HT_NO_CACHE_HASH_VALUES +#define HT_SET_HASH_(elm, field, hashfn) \ + do { (elm)->field.hte_hash = hashfn(elm); } while (0) +#define HT_SET_HASHVAL_(elm, field, val) \ + do { (elm)->field.hte_hash = (val); } while (0) +#define HT_ELT_HASH_(elm, field, hashfn) \ + ((elm)->field.hte_hash) +#else +#define HT_SET_HASH_(elm, field, hashfn) \ + ((void)0) +#define HT_ELT_HASH_(elm, field, hashfn) \ + (hashfn(elm)) +#define HT_SET_HASHVAL_(elm, field, val) \ + ((void)0) +#endif + +/* Helper: alias for the bucket containing 'elm'. */ +#define HT_BUCKET_(head, field, elm, hashfn) \ + ((head)->hth_table[HT_ELT_HASH_(elm,field,hashfn) \ + % head->hth_table_length]) + +#define HT_FOREACH(x, name, head) \ + for ((x) = HT_START(name, head); \ + (x) != NULL; \ + (x) = HT_NEXT(name, head, x)) + +#define HT_PROTOTYPE(name, type, field, hashfn, eqfn) \ + int name##_HT_GROW(struct name *ht, unsigned min_capacity); \ + void name##_HT_CLEAR(struct name *ht); \ + int name##_HT_REP_IS_BAD_(const struct name *ht); \ + static INLINE void \ + name##_HT_INIT(struct name *head) { \ + head->hth_table_length = 0; \ + head->hth_table = NULL; \ + head->hth_n_entries = 0; \ + head->hth_load_limit = 0; \ + head->hth_prime_idx = -1; \ + } \ + /* Helper: returns a pointer to the right location in the table \ + * 'head' to find or insert the element 'elm'. */ \ + static INLINE struct type ** \ + name##_HT_FIND_P_(struct name *head, struct type *elm) \ + { \ + struct type **p; \ + if (!head->hth_table) \ + return NULL; \ + p = &HT_BUCKET_(head, field, elm, hashfn); \ + while (*p) { \ + if (eqfn(*p, elm)) \ + return p; \ + p = &(*p)->field.hte_next; \ + } \ + return p; \ + } \ + /* Return a pointer to the element in the table 'head' matching 'elm', \ + * or NULL if no such element exists */ \ + static INLINE struct type * \ + name##_HT_FIND(const struct name *head, struct type *elm) \ + { \ + struct type **p; \ + struct name *h = (struct name *) head; \ + HT_SET_HASH_(elm, field, hashfn); \ + p = name##_HT_FIND_P_(h, elm); \ + return p ? *p : NULL; \ + } \ + /* Insert the element 'elm' into the table 'head'. Do not call this \ + * function if the table might already contain a matching element. */ \ + static INLINE void \ + name##_HT_INSERT(struct name *head, struct type *elm) \ + { \ + struct type **p; \ + if (!head->hth_table || head->hth_n_entries >= head->hth_load_limit) \ + name##_HT_GROW(head, head->hth_n_entries+1); \ + ++head->hth_n_entries; \ + HT_SET_HASH_(elm, field, hashfn); \ + p = &HT_BUCKET_(head, field, elm, hashfn); \ + elm->field.hte_next = *p; \ + *p = elm; \ + } \ + /* Insert the element 'elm' into the table 'head'. If there already \ + * a matching element in the table, replace that element and return \ + * it. */ \ + static INLINE struct type * \ + name##_HT_REPLACE(struct name *head, struct type *elm) \ + { \ + struct type **p, *r; \ + if (!head->hth_table || head->hth_n_entries >= head->hth_load_limit) \ + name##_HT_GROW(head, head->hth_n_entries+1); \ + HT_SET_HASH_(elm, field, hashfn); \ + p = name##_HT_FIND_P_(head, elm); \ + r = *p; \ + *p = elm; \ + if (r && (r!=elm)) { \ + elm->field.hte_next = r->field.hte_next; \ + r->field.hte_next = NULL; \ + return r; \ + } else { \ + ++head->hth_n_entries; \ + return NULL; \ + } \ + } \ + /* Remove any element matching 'elm' from the table 'head'. If such \ + * an element is found, return it; otherwise return NULL. */ \ + static INLINE struct type * \ + name##_HT_REMOVE(struct name *head, struct type *elm) \ + { \ + struct type **p, *r; \ + HT_SET_HASH_(elm, field, hashfn); \ + p = name##_HT_FIND_P_(head,elm); \ + if (!p || !*p) \ + return NULL; \ + r = *p; \ + *p = r->field.hte_next; \ + r->field.hte_next = NULL; \ + --head->hth_n_entries; \ + return r; \ + } \ + /* Invoke the function 'fn' on every element of the table 'head', \ + * using 'data' as its second argument. If the function returns \ + * nonzero, remove the most recently examined element before invoking \ + * the function again. */ \ + static INLINE void \ + name##_HT_FOREACH_FN(struct name *head, \ + int (*fn)(struct type *, void *), \ + void *data) \ + { \ + unsigned idx; \ + struct type **p, **nextp, *next; \ + if (!head->hth_table) \ + return; \ + for (idx=0; idx < head->hth_table_length; ++idx) { \ + p = &head->hth_table[idx]; \ + while (*p) { \ + nextp = &(*p)->field.hte_next; \ + next = *nextp; \ + if (fn(*p, data)) { \ + --head->hth_n_entries; \ + *p = next; \ + } else { \ + p = nextp; \ + } \ + } \ + } \ + } \ + /* Return a pointer to the first element in the table 'head', under \ + * an arbitrary order. This order is stable under remove operations, \ + * but not under others. If the table is empty, return NULL. */ \ + static INLINE struct type ** \ + name##_HT_START(struct name *head) \ + { \ + unsigned b = 0; \ + while (b < head->hth_table_length) { \ + if (head->hth_table[b]) \ + return &head->hth_table[b]; \ + ++b; \ + } \ + return NULL; \ + } \ + /* Return the next element in 'head' after 'elm', under the arbitrary \ + * order used by HT_START. If there are no more elements, return \ + * NULL. If 'elm' is to be removed from the table, you must call \ + * this function for the next value before you remove it. \ + */ \ + static INLINE struct type ** \ + name##_HT_NEXT(struct name *head, struct type **elm) \ + { \ + if ((*elm)->field.hte_next) { \ + return &(*elm)->field.hte_next; \ + } else { \ + unsigned b = (HT_ELT_HASH_(*elm, field, hashfn) \ + % head->hth_table_length)+1; \ + while (b < head->hth_table_length) { \ + if (head->hth_table[b]) \ + return &head->hth_table[b]; \ + ++b; \ + } \ + return NULL; \ + } \ + } \ + static INLINE struct type ** \ + name##_HT_NEXT_RMV(struct name *head, struct type **elm) \ + { \ + unsigned h = HT_ELT_HASH_(*elm, field, hashfn); \ + *elm = (*elm)->field.hte_next; \ + --head->hth_n_entries; \ + if (*elm) { \ + return elm; \ + } else { \ + unsigned b = (h % head->hth_table_length)+1; \ + while (b < head->hth_table_length) { \ + if (head->hth_table[b]) \ + return &head->hth_table[b]; \ + ++b; \ + } \ + return NULL; \ + } \ + } + +#define HT_GENERATE(name, type, field, hashfn, eqfn, load, mallocfn, \ + reallocfn, freefn) \ + static unsigned name##_PRIMES[] = { \ + 53, 97, 193, 389, \ + 769, 1543, 3079, 6151, \ + 12289, 24593, 49157, 98317, \ + 196613, 393241, 786433, 1572869, \ + 3145739, 6291469, 12582917, 25165843, \ + 50331653, 100663319, 201326611, 402653189, \ + 805306457, 1610612741 \ + }; \ + static unsigned name##_N_PRIMES = \ + (unsigned)(sizeof(name##_PRIMES)/sizeof(name##_PRIMES[0])); \ + /* Expand the internal table of 'head' until it is large enough to \ + * hold 'size' elements. Return 0 on success, -1 on allocation \ + * failure. */ \ + int \ + name##_HT_GROW(struct name *head, unsigned size) \ + { \ + unsigned new_len, new_load_limit; \ + int prime_idx; \ + struct type **new_table; \ + if (head->hth_prime_idx == (int)name##_N_PRIMES - 1) \ + return 0; \ + if (head->hth_load_limit > size) \ + return 0; \ + prime_idx = head->hth_prime_idx; \ + do { \ + new_len = name##_PRIMES[++prime_idx]; \ + new_load_limit = (unsigned)(load*new_len); \ + } while (new_load_limit <= size && \ + prime_idx < (int)name##_N_PRIMES); \ + if ((new_table = mallocfn(new_len*sizeof(struct type*)))) { \ + unsigned b; \ + memset(new_table, 0, new_len*sizeof(struct type*)); \ + for (b = 0; b < head->hth_table_length; ++b) { \ + struct type *elm, *next; \ + unsigned b2; \ + elm = head->hth_table[b]; \ + while (elm) { \ + next = elm->field.hte_next; \ + b2 = HT_ELT_HASH_(elm, field, hashfn) % new_len; \ + elm->field.hte_next = new_table[b2]; \ + new_table[b2] = elm; \ + elm = next; \ + } \ + } \ + if (head->hth_table) \ + freefn(head->hth_table); \ + head->hth_table = new_table; \ + } else { \ + unsigned b, b2; \ + new_table = reallocfn(head->hth_table, new_len*sizeof(struct type*)); \ + if (!new_table) return -1; \ + memset(new_table + head->hth_table_length, 0, \ + (new_len - head->hth_table_length)*sizeof(struct type*)); \ + for (b=0; b < head->hth_table_length; ++b) { \ + struct type *e, **pE; \ + for (pE = &new_table[b], e = *pE; e != NULL; e = *pE) { \ + b2 = HT_ELT_HASH_(e, field, hashfn) % new_len; \ + if (b2 == b) { \ + pE = &e->field.hte_next; \ + } else { \ + *pE = e->field.hte_next; \ + e->field.hte_next = new_table[b2]; \ + new_table[b2] = e; \ + } \ + } \ + } \ + head->hth_table = new_table; \ + } \ + head->hth_table_length = new_len; \ + head->hth_prime_idx = prime_idx; \ + head->hth_load_limit = new_load_limit; \ + return 0; \ + } \ + /* Free all storage held by 'head'. Does not free 'head' itself, or \ + * individual elements. */ \ + void \ + name##_HT_CLEAR(struct name *head) \ + { \ + if (head->hth_table) \ + freefn(head->hth_table); \ + head->hth_table_length = 0; \ + name##_HT_INIT(head); \ + } \ + /* Debugging helper: return false iff the representation of 'head' is \ + * internally consistent. */ \ + int \ + name##_HT_REP_IS_BAD_(const struct name *head) \ + { \ + unsigned n, i; \ + struct type *elm; \ + if (!head->hth_table_length) { \ + if (!head->hth_table && !head->hth_n_entries && \ + !head->hth_load_limit && head->hth_prime_idx == -1) \ + return 0; \ + else \ + return 1; \ + } \ + if (!head->hth_table || head->hth_prime_idx < 0 || \ + !head->hth_load_limit) \ + return 2; \ + if (head->hth_n_entries > head->hth_load_limit) \ + return 3; \ + if (head->hth_table_length != name##_PRIMES[head->hth_prime_idx]) \ + return 4; \ + if (head->hth_load_limit != (unsigned)(load*head->hth_table_length)) \ + return 5; \ + for (n = i = 0; i < head->hth_table_length; ++i) { \ + for (elm = head->hth_table[i]; elm; elm = elm->field.hte_next) { \ + if (HT_ELT_HASH_(elm, field, hashfn) != hashfn(elm)) \ + return 1000 + i; \ + if ((HT_ELT_HASH_(elm, field, hashfn) % head->hth_table_length) != i) \ + return 10000 + i; \ + ++n; \ + } \ + } \ + if (n != head->hth_n_entries) \ + return 6; \ + return 0; \ + } + +/** Implements an over-optimized "find and insert if absent" block; + * not meant for direct usage by typical code, or usage outside the critical + * path.*/ +#define HT_FIND_OR_INSERT_(name, field, hashfn, head, eltype, elm, var, y, n) \ + { \ + struct name *var##_head_ = head; \ + struct eltype **var; \ + if (!var##_head_->hth_table || \ + var##_head_->hth_n_entries >= var##_head_->hth_load_limit) \ + name##_HT_GROW(var##_head_, var##_head_->hth_n_entries+1); \ + HT_SET_HASH_((elm), field, hashfn); \ + var = name##_HT_FIND_P_(var##_head_, (elm)); \ + if (*var) { \ + y; \ + } else { \ + n; \ + } \ + } +#define HT_FOI_INSERT_(field, head, elm, newent, var) \ + { \ + HT_SET_HASHVAL_(newent, field, (elm)->field.hte_hash); \ + newent->field.hte_next = NULL; \ + *var = newent; \ + ++((head)->hth_n_entries); \ + } + +/* + * Copyright 2005, Nick Mathewson. Implementation logic is adapted from code + * by Christopher Clark, retrofit to allow drop-in memory management, and to + * use the same interface as Niels Provos's tree.h. This is probably still + * a derived work, so the original license below still applies. + * + * Copyright (c) 2002, Christopher Clark + * 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. + * + * * Neither the name of the original author; nor the names of any 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 OWNER + * 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. +*/ + +#endif + diff --git a/src/tor/log.c b/src/tor/log.c new file mode 100644 index 0000000..6e3e95f --- /dev/null +++ b/src/tor/log.c @@ -0,0 +1,1316 @@ +/* Copyright (c) 2001, Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file log.c + * \brief Functions to send messages to log files or the console. + **/ + +#include "orconfig.h" +#include +#include +// #include +#include +#include +#ifdef HAVE_SYS_TIME_H +#include +#endif +#ifdef HAVE_TIME_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_FCNTL_H +#include +#endif +#include "tor_compat.h" +#include "tor_util.h" +#define LOG_PRIVATE +#include "torlog.h" +#include "container.h" + +/** Given a severity, yields an index into log_severity_list_t.masks to use + * for that severity. */ +#define SEVERITY_MASK_IDX(sev) ((sev) - LOG_ERR) + +/** @{ */ +/** The string we stick at the end of a log message when it is too long, + * and its length. */ +#define TRUNCATED_STR "[...truncated]" +#define TRUNCATED_STR_LEN 14 +/** @} */ + +/** Information for a single logfile; only used in log.c */ +typedef struct logfile_t { + struct logfile_t *next; /**< Next logfile_t in the linked list. */ + char *filename; /**< Filename to open. */ + int fd; /**< fd to receive log messages, or -1 for none. */ + int seems_dead; /**< Boolean: true if the stream seems to be kaput. */ + int needs_close; /**< Boolean: true if the stream gets closed on shutdown. */ + int is_temporary; /**< Boolean: close after initializing logging subsystem.*/ + int is_syslog; /**< Boolean: send messages to syslog. */ + log_callback callback; /**< If not NULL, send messages to this function. */ + log_severity_list_t *severities; /**< Which severity of messages should we + * log for each log domain? */ +} logfile_t; + +static void log_free(logfile_t *victim); + +/** Helper: map a log severity to descriptive string. */ +static INLINE const char * +sev_to_string(int severity) +{ + switch (severity) { + case LOG_DEBUG: return "debug"; + case LOG_INFO: return "info"; + case LOG_NOTICE: return "notice"; + case LOG_WARN: return "warn"; + case LOG_ERR: return "err"; + default: /* Call assert, not tor_assert, since tor_assert + * calls log on failure. */ + assert(0); return "UNKNOWN"; + } +} + +/** Helper: decide whether to include the function name in the log message. */ +static INLINE int +should_log_function_name(log_domain_mask_t domain, int severity) +{ + switch (severity) { + case LOG_DEBUG: + case LOG_INFO: + /* All debugging messages occur in interesting places. */ + return (domain & LD_NOFUNCNAME) == 0; + case LOG_NOTICE: + case LOG_WARN: + case LOG_ERR: + /* We care about places where bugs occur. */ + return (domain & (LD_BUG|LD_NOFUNCNAME)) == LD_BUG; + default: + /* Call assert, not tor_assert, since tor_assert calls log on failure. */ + assert(0); return 0; + } +} + +/** A mutex to guard changes to logfiles and logging. */ +static tor_mutex_t log_mutex; +/** True iff we have initialized log_mutex */ +static int log_mutex_initialized = 0; + +/** Linked list of logfile_t. */ +static logfile_t *logfiles = NULL; +/** Boolean: do we report logging domains? */ +static int log_domains_are_logged = 0; + +#ifdef HAVE_SYSLOG_H +/** The number of open syslog log handlers that we have. When this reaches 0, + * we can close our connection to the syslog facility. */ +static int syslog_count = 0; +#endif + +/** Represents a log message that we are going to send to callback-driven + * loggers once we can do so in a non-reentrant way. */ +typedef struct pending_cb_message_t { + int severity; /**< The severity of the message */ + log_domain_mask_t domain; /**< The domain of the message */ + char *msg; /**< The content of the message */ +} pending_cb_message_t; + +/** Log messages waiting to be replayed onto callback-based logs */ +static smartlist_t *pending_cb_messages = NULL; + +/** Lock the log_mutex to prevent others from changing the logfile_t list */ +#define LOCK_LOGS() STMT_BEGIN \ + tor_mutex_acquire(&log_mutex); \ + STMT_END +/** Unlock the log_mutex */ +#define UNLOCK_LOGS() STMT_BEGIN tor_mutex_release(&log_mutex); STMT_END + +/** What's the lowest log level anybody cares about? Checking this lets us + * bail out early from log_debug if we aren't debugging. */ +int log_global_min_severity_ = LOG_NOTICE; + +static void delete_log(logfile_t *victim); +static void close_log(logfile_t *victim); + +static char *domain_to_string(log_domain_mask_t domain, + char *buf, size_t buflen); +static INLINE char *format_msg(char *buf, size_t buf_len, + log_domain_mask_t domain, int severity, const char *funcname, + const char *suffix, + const char *format, va_list ap, size_t *msg_len_out) + CHECK_PRINTF(7,0); +static void logv(int severity, log_domain_mask_t domain, const char *funcname, + const char *suffix, const char *format, va_list ap) + CHECK_PRINTF(5,0); + +/** Name of the application: used to generate the message we write at the + * start of each new log. */ +static char *appname = NULL; + +/** Set the "application name" for the logs to name: we'll use this + * name in the message we write when starting up, and at the start of each new + * log. + * + * Tor uses this string to write the version number to the log file. */ +void +log_set_application_name(const char *name) +{ + tor_free(appname); + appname = name ? tor_strdup(name) : NULL; +} + +/** Log time granularity in milliseconds. */ +static int log_time_granularity = 1; + +/** Define log time granularity for all logs to be granularity_msec + * milliseconds. */ +void +set_log_time_granularity(int granularity_msec) +{ + log_time_granularity = granularity_msec; +} + +/** Helper: Write the standard prefix for log lines to a + * buf_len character buffer in buf. + */ +static INLINE size_t +log_prefix_(char *buf, size_t buf_len, int severity) +{ + time_t t; + struct timeval now; + struct tm tm; + size_t n; + int r, ms; + + tor_gettimeofday(&now); + t = (time_t)now.tv_sec; + ms = (int)now.tv_usec / 1000; + if (log_time_granularity >= 1000) { + t -= t % (log_time_granularity / 1000); + ms = 0; + } else { + ms -= ((int)now.tv_usec / 1000) % log_time_granularity; + } + + n = strftime(buf, buf_len, "%b %d %H:%M:%S", tor_localtime_r(&t, &tm)); + r = tor_snprintf(buf+n, buf_len-n, ".%.3i [%s] ", ms, + sev_to_string(severity)); + + if (r<0) + return buf_len-1; + else + return n+r; +} + +/** If lf refers to an actual file that we have just opened, and the file + * contains no data, log an "opening new logfile" message at the top. + * + * Return -1 if the log is broken and needs to be deleted, else return 0. + */ +static int +log_tor_version(logfile_t *lf, int reset) +{ + char buf[256]; + size_t n; + int is_new; + + if (!lf->needs_close) + /* If it doesn't get closed, it isn't really a file. */ + return 0; + if (lf->is_temporary) + /* If it's temporary, it isn't really a file. */ + return 0; + + is_new = lf->fd >= 0 && tor_fd_getpos(lf->fd) == 0; + + if (reset && !is_new) + /* We are resetting, but we aren't at the start of the file; no + * need to log again. */ + return 0; + n = log_prefix_(buf, sizeof(buf), LOG_NOTICE); + if (appname) { + tor_snprintf(buf+n, sizeof(buf)-n, + "%s opening %slog file.\n", appname, is_new?"new ":""); + } else { + tor_snprintf(buf+n, sizeof(buf)-n, + "Tor %s opening %slog file.\n", VERSION, is_new?"new ":""); + } + if (write_all(lf->fd, buf, strlen(buf), 0) < 0) /* error */ + return -1; /* failed */ + return 0; +} + +/** Helper: Format a log message into a fixed-sized buffer. (This is + * factored out of logv so that we never format a message more + * than once.) Return a pointer to the first character of the message + * portion of the formatted string. + */ +static INLINE char * +format_msg(char *buf, size_t buf_len, + log_domain_mask_t domain, int severity, const char *funcname, + const char *suffix, + const char *format, va_list ap, size_t *msg_len_out) +{ + size_t n; + int r; + char *end_of_prefix; + char *buf_end; + + assert(buf_len >= 16); /* prevent integer underflow and general stupidity */ + buf_len -= 2; /* subtract 2 characters so we have room for \n\0 */ + buf_end = buf+buf_len; /* point *after* the last char we can write to */ + + n = log_prefix_(buf, buf_len, severity); + end_of_prefix = buf+n; + + if (log_domains_are_logged) { + char *cp = buf+n; + if (cp == buf_end) goto format_msg_no_room_for_domains; + *cp++ = '{'; + if (cp == buf_end) goto format_msg_no_room_for_domains; + cp = domain_to_string(domain, cp, (buf+buf_len-cp)); + if (cp == buf_end) goto format_msg_no_room_for_domains; + *cp++ = '}'; + if (cp == buf_end) goto format_msg_no_room_for_domains; + *cp++ = ' '; + if (cp == buf_end) goto format_msg_no_room_for_domains; + end_of_prefix = cp; + n = cp-buf; + format_msg_no_room_for_domains: + /* This will leave end_of_prefix and n unchanged, and thus cause + * whatever log domain string we had written to be clobbered. */ + ; + } + + if (funcname && should_log_function_name(domain, severity)) { + r = tor_snprintf(buf+n, buf_len-n, "%s(): ", funcname); + if (r<0) + n = strlen(buf); + else + n += r; + } + + if (domain == LD_BUG && buf_len-n > 6) { + memcpy(buf+n, "Bug: ", 6); + n += 5; + } + + r = tor_vsnprintf(buf+n,buf_len-n,format,ap); + if (r < 0) { + /* The message was too long; overwrite the end of the buffer with + * "[...truncated]" */ + if (buf_len >= TRUNCATED_STR_LEN) { + size_t offset = buf_len-TRUNCATED_STR_LEN; + /* We have an extra 2 characters after buf_len to hold the \n\0, + * so it's safe to add 1 to the size here. */ + strlcpy(buf+offset, TRUNCATED_STR, buf_len-offset+1); + } + /* Set 'n' to the end of the buffer, where we'll be writing \n\0. + * Since we already subtracted 2 from buf_len, this is safe.*/ + n = buf_len; + } else { + n += r; + if (suffix) { + size_t suffix_len = strlen(suffix); + if (buf_len-n >= suffix_len) { + memcpy(buf+n, suffix, suffix_len); + n += suffix_len; + } + } + } + buf[n]='\n'; + buf[n+1]='\0'; + *msg_len_out = n+1; + return end_of_prefix; +} + +/** Helper: sends a message to the appropriate logfiles, at loglevel + * severity. If provided, funcname is prepended to the + * message. The actual message is derived as from tor_snprintf(format,ap). + */ +static void +logv(int severity, log_domain_mask_t domain, const char *funcname, + const char *suffix, const char *format, va_list ap) +{ + char buf[10024]; + size_t msg_len = 0; + int formatted = 0; + logfile_t *lf; + char *end_of_prefix=NULL; + int callbacks_deferred = 0; + + /* Call assert, not tor_assert, since tor_assert calls log on failure. */ + assert(format); + /* check that severity is sane. Overrunning the masks array leads to + * interesting and hard to diagnose effects */ + assert(severity >= LOG_ERR && severity <= LOG_DEBUG); + LOCK_LOGS(); + + if ((! (domain & LD_NOCB)) && smartlist_len(pending_cb_messages)) + flush_pending_log_callbacks(); + + lf = logfiles; + while (lf) { + if (! (lf->severities->masks[SEVERITY_MASK_IDX(severity)] & domain)) { + lf = lf->next; + continue; + } + if (! (lf->fd >= 0 || lf->is_syslog || lf->callback)) { + lf = lf->next; + continue; + } + if (lf->seems_dead) { + lf = lf->next; + continue; + } + + if (!formatted) { + end_of_prefix = + format_msg(buf, sizeof(buf), domain, severity, funcname, suffix, + format, ap, &msg_len); + formatted = 1; + } + + if (lf->is_syslog) { +#ifdef HAVE_SYSLOG_H + char *m = end_of_prefix; +#ifdef MAXLINE + /* Some syslog implementations have limits on the length of what you can + * pass them, and some very old ones do not detect overflow so well. + * Regrettably, they call their maximum line length MAXLINE. */ +#if MAXLINE < 64 +#warn "MAXLINE is a very low number; it might not be from syslog.h after all" +#endif + if (msg_len >= MAXLINE) + m = tor_strndup(end_of_prefix, MAXLINE-1); +#endif + syslog(severity, "%s", m); +#ifdef MAXLINE + if (m != end_of_prefix) { + tor_free(m); + } +#endif +#endif + lf = lf->next; + continue; + } else if (lf->callback) { + if (domain & LD_NOCB) { + if (!callbacks_deferred && pending_cb_messages) { + pending_cb_message_t *msg = tor_malloc(sizeof(pending_cb_message_t)); + msg->severity = severity; + msg->domain = domain; + msg->msg = tor_strdup(end_of_prefix); + smartlist_add(pending_cb_messages, msg); + + callbacks_deferred = 1; + } + } else { + lf->callback(severity, domain, end_of_prefix); + } + lf = lf->next; + continue; + } + if (write_all(lf->fd, buf, msg_len, 0) < 0) { /* error */ + /* don't log the error! mark this log entry to be blown away, and + * continue. */ + lf->seems_dead = 1; + } + lf = lf->next; + } + UNLOCK_LOGS(); +} + +/** Output a message to the log. It gets logged to all logfiles that + * care about messages with severity in domain. The content + * is formatted printf-style based on format and extra arguments. + * */ +void +tor_log(int severity, log_domain_mask_t domain, const char *format, ...) +{ + va_list ap; + if (severity > log_global_min_severity_) + return; + va_start(ap,format); + logv(severity, domain, NULL, NULL, format, ap); + va_end(ap); +} + +/** Maximum number of fds that will get notifications if we crash */ +#define MAX_SIGSAFE_FDS 8 +/** Array of fds to log crash-style warnings to. */ +static int sigsafe_log_fds[MAX_SIGSAFE_FDS] = { STDERR_FILENO }; +/** The number of elements used in sigsafe_log_fds */ +static int n_sigsafe_log_fds = 1; + +/** Write s to each element of sigsafe_log_fds. Return 0 on success, -1 + * on failure. */ +static int +tor_log_err_sigsafe_write(const char *s) +{ + int i; + ssize_t r; + size_t len = strlen(s); + int err = 0; + for (i=0; i < n_sigsafe_log_fds; ++i) { + r = write(sigsafe_log_fds[i], s, len); + err += (r != (ssize_t)len); + } + return err ? -1 : 0; +} + +/** Given a list of string arguments ending with a NULL, writes them + * to our logs and to stderr (if possible). This function is safe to call + * from within a signal handler. */ +void +tor_log_err_sigsafe(const char *m, ...) +{ + va_list ap; + const char *x; + char timebuf[33]; + time_t now = time(NULL); + + if (!m) + return; + if (log_time_granularity >= 2000) { + int g = log_time_granularity / 1000; + now -= now % g; + } + timebuf[0] = now < 0 ? '-' : ' '; + if (now < 0) now = -now; + timebuf[1] = '\0'; + format_dec_number_sigsafe(now, timebuf+1, sizeof(timebuf)-1); + tor_log_err_sigsafe_write("\n==========================================" + "================== T="); + tor_log_err_sigsafe_write(timebuf); + tor_log_err_sigsafe_write("\n"); + tor_log_err_sigsafe_write(m); + va_start(ap, m); + while ((x = va_arg(ap, const char*))) { + tor_log_err_sigsafe_write(x); + } + va_end(ap); +} + +/** Set *out to a pointer to an array of the fds to log errors to from + * inside a signal handler. Return the number of elements in the array. */ +int +tor_log_get_sigsafe_err_fds(const int **out) +{ + *out = sigsafe_log_fds; + return n_sigsafe_log_fds; +} + +/** Helper function; return true iff the n-element array array + * contains item. */ +static int +int_array_contains(const int *array, int n, int item) +{ + int j; + for (j = 0; j < n; ++j) { + if (array[j] == item) + return 1; + } + return 0; +} + +/** Function to call whenever the list of logs changes to get ready to log + * from signal handlers. */ +void +tor_log_update_sigsafe_err_fds(void) +{ + const logfile_t *lf; + int found_real_stderr = 0; + + LOCK_LOGS(); + /* Reserve the first one for stderr. This is safe because when we daemonize, + * we dup2 /dev/null to stderr, */ + sigsafe_log_fds[0] = STDERR_FILENO; + n_sigsafe_log_fds = 1; + + for (lf = logfiles; lf; lf = lf->next) { + /* Don't try callback to the control port, or syslogs: We can't + * do them from a signal handler. Don't try stdout: we always do stderr. + */ + if (lf->is_temporary || lf->is_syslog || + lf->callback || lf->seems_dead || lf->fd < 0) + continue; + if (lf->severities->masks[SEVERITY_MASK_IDX(LOG_ERR)] & + (LD_BUG|LD_GENERAL)) { + if (lf->fd == STDERR_FILENO) + found_real_stderr = 1; + /* Avoid duplicates */ + if (int_array_contains(sigsafe_log_fds, n_sigsafe_log_fds, lf->fd)) + continue; + sigsafe_log_fds[n_sigsafe_log_fds++] = lf->fd; + if (n_sigsafe_log_fds == MAX_SIGSAFE_FDS) + break; + } + } + + if (!found_real_stderr && + int_array_contains(sigsafe_log_fds, n_sigsafe_log_fds, STDOUT_FILENO)) { + /* Don't use a virtual stderr when we're also logging to stdout. */ + assert(n_sigsafe_log_fds >= 2); /* Don't use assert inside log functions*/ + sigsafe_log_fds[0] = sigsafe_log_fds[--n_sigsafe_log_fds]; + } + + UNLOCK_LOGS(); +} + +/** Output a message to the log, prefixed with a function name fn. */ +#ifdef __GNUC__ +/** GCC-based implementation of the log_fn backend, used when we have + * variadic macros. All arguments are as for log_fn, except for + * fn, which is the name of the calling functions. */ +void +log_fn_(int severity, log_domain_mask_t domain, const char *fn, + const char *format, ...) +{ + va_list ap; + if (severity > log_global_min_severity_) + return; + va_start(ap,format); + logv(severity, domain, fn, NULL, format, ap); + va_end(ap); +} +void +log_fn_ratelim_(ratelim_t *ratelim, int severity, log_domain_mask_t domain, + const char *fn, const char *format, ...) +{ + va_list ap; + char *m; + if (severity > log_global_min_severity_) + return; + m = rate_limit_log(ratelim, approx_time()); + if (m == NULL) + return; + va_start(ap, format); + logv(severity, domain, fn, m, format, ap); + va_end(ap); + tor_free(m); +} +#else +/** @{ */ +/** Variant implementation of log_fn, log_debug, log_info,... for C compilers + * without variadic macros. In this case, the calling function sets + * log_fn_function_name_ to the name of the function, then invokes the + * appropriate log_fn_, log_debug_, etc. */ +const char *log_fn_function_name_=NULL; +void +log_fn_(int severity, log_domain_mask_t domain, const char *format, ...) +{ + va_list ap; + if (severity > log_global_min_severity_) + return; + va_start(ap,format); + logv(severity, domain, log_fn_function_name_, NULL, format, ap); + va_end(ap); + log_fn_function_name_ = NULL; +} +void +log_fn_ratelim_(ratelim_t *ratelim, int severity, log_domain_mask_t domain, + const char *format, ...) +{ + va_list ap; + char *m; + if (severity > log_global_min_severity_) + return; + m = rate_limit_log(ratelim, approx_time()); + if (m == NULL) + return; + va_start(ap, format); + logv(severity, domain, log_fn_function_name_, m, format, ap); + va_end(ap); + tor_free(m); +} +void +log_debug_(log_domain_mask_t domain, const char *format, ...) +{ + va_list ap; + /* For GCC we do this check in the macro. */ + if (PREDICT_LIKELY(LOG_DEBUG > log_global_min_severity_)) + return; + va_start(ap,format); + logv(LOG_DEBUG, domain, log_fn_function_name_, NULL, format, ap); + va_end(ap); + log_fn_function_name_ = NULL; +} +void +log_info_(log_domain_mask_t domain, const char *format, ...) +{ + va_list ap; + if (LOG_INFO > log_global_min_severity_) + return; + va_start(ap,format); + logv(LOG_INFO, domain, log_fn_function_name_, NULL, format, ap); + va_end(ap); + log_fn_function_name_ = NULL; +} +void +log_notice_(log_domain_mask_t domain, const char *format, ...) +{ + va_list ap; + if (LOG_NOTICE > log_global_min_severity_) + return; + va_start(ap,format); + logv(LOG_NOTICE, domain, log_fn_function_name_, NULL, format, ap); + va_end(ap); + log_fn_function_name_ = NULL; +} +void +log_warn_(log_domain_mask_t domain, const char *format, ...) +{ + va_list ap; + if (LOG_WARN > log_global_min_severity_) + return; + va_start(ap,format); + logv(LOG_WARN, domain, log_fn_function_name_, NULL, format, ap); + va_end(ap); + log_fn_function_name_ = NULL; +} +void +log_err_(log_domain_mask_t domain, const char *format, ...) +{ + va_list ap; + if (LOG_ERR > log_global_min_severity_) + return; + va_start(ap,format); + logv(LOG_ERR, domain, log_fn_function_name_, NULL, format, ap); + va_end(ap); + log_fn_function_name_ = NULL; +} +/** @} */ +#endif + +/** Free all storage held by victim. */ +static void +log_free(logfile_t *victim) +{ + if (!victim) + return; + tor_free(victim->severities); + tor_free(victim->filename); + tor_free(victim); +} + +/** Close all open log files, and free other static memory. */ +void +logs_free_all(void) +{ + logfile_t *victim, *next; + smartlist_t *messages; + LOCK_LOGS(); + next = logfiles; + logfiles = NULL; + messages = pending_cb_messages; + pending_cb_messages = NULL; + UNLOCK_LOGS(); + while (next) { + victim = next; + next = next->next; + close_log(victim); + log_free(victim); + } + tor_free(appname); + + SMARTLIST_FOREACH(messages, pending_cb_message_t *, msg, { + tor_free(msg->msg); + tor_free(msg); + }); + smartlist_free(messages); + + /* We _could_ destroy the log mutex here, but that would screw up any logs + * that happened between here and the end of execution. */ +} + +/** Remove and free the log entry victim from the linked-list + * logfiles (it is probably present, but it might not be due to thread + * racing issues). After this function is called, the caller shouldn't + * refer to victim anymore. + * + * Long-term, we need to do something about races in the log subsystem + * in general. See bug 222 for more details. + */ +static void +delete_log(logfile_t *victim) +{ + logfile_t *tmpl; + if (victim == logfiles) + logfiles = victim->next; + else { + for (tmpl = logfiles; tmpl && tmpl->next != victim; tmpl=tmpl->next) ; +// tor_assert(tmpl); +// tor_assert(tmpl->next == victim); + if (!tmpl) + return; + tmpl->next = victim->next; + } + log_free(victim); +} + +/** Helper: release system resources (but not memory) held by a single + * logfile_t. */ +static void +close_log(logfile_t *victim) +{ + if (victim->needs_close && victim->fd >= 0) { + close(victim->fd); + victim->fd = -1; + } else if (victim->is_syslog) { +#ifdef HAVE_SYSLOG_H + if (--syslog_count == 0) { + /* There are no other syslogs; close the logging facility. */ + closelog(); + } +#endif + } +} + +/** Adjust a log severity configuration in severity_out to contain + * every domain between loglevelMin and loglevelMax, inclusive. + */ +void +set_log_severity_config(int loglevelMin, int loglevelMax, + log_severity_list_t *severity_out) +{ + int i; + tor_assert(loglevelMin >= loglevelMax); + tor_assert(loglevelMin >= LOG_ERR && loglevelMin <= LOG_DEBUG); + tor_assert(loglevelMax >= LOG_ERR && loglevelMax <= LOG_DEBUG); + memset(severity_out, 0, sizeof(log_severity_list_t)); + for (i = loglevelMin; i >= loglevelMax; --i) { + severity_out->masks[SEVERITY_MASK_IDX(i)] = ~0u; + } +} + +/** Add a log handler named name to send all messages in severity + * to fd. Copies severity. Helper: does no locking. */ +static void +add_stream_log_impl(const log_severity_list_t *severity, + const char *name, int fd) +{ + logfile_t *lf; + lf = tor_malloc_zero(sizeof(logfile_t)); + lf->fd = fd; + lf->filename = tor_strdup(name); + lf->severities = tor_memdup(severity, sizeof(log_severity_list_t)); + lf->next = logfiles; + + logfiles = lf; + log_global_min_severity_ = get_min_log_level(); +} + +/** Add a log handler named name to send all messages in severity + * to fd. Steals a reference to severity; the caller must + * not use it after calling this function. */ +void +add_stream_log(const log_severity_list_t *severity, const char *name, int fd) +{ + LOCK_LOGS(); + add_stream_log_impl(severity, name, fd); + UNLOCK_LOGS(); +} + +/** Initialize the global logging facility */ +void +init_logging(void) +{ + if (!log_mutex_initialized) { + tor_mutex_init(&log_mutex); + log_mutex_initialized = 1; + } + if (pending_cb_messages == NULL) + pending_cb_messages = smartlist_new(); +} + +/** Set whether we report logging domains as a part of our log messages. + */ +void +logs_set_domain_logging(int enabled) +{ + LOCK_LOGS(); + log_domains_are_logged = enabled; + UNLOCK_LOGS(); +} + +/** Add a log handler to receive messages during startup (before the real + * logs are initialized). + */ +void +add_temp_log(int min_severity) +{ + log_severity_list_t *s = tor_malloc_zero(sizeof(log_severity_list_t)); + set_log_severity_config(min_severity, LOG_ERR, s); + LOCK_LOGS(); + add_stream_log_impl(s, "", fileno(stdout)); + tor_free(s); + logfiles->is_temporary = 1; + UNLOCK_LOGS(); +} + +/** + * Add a log handler to send messages in severity + * to the function cb. + */ +int +add_callback_log(const log_severity_list_t *severity, log_callback cb) +{ + logfile_t *lf; + lf = tor_malloc_zero(sizeof(logfile_t)); + lf->fd = -1; + lf->severities = tor_memdup(severity, sizeof(log_severity_list_t)); + lf->filename = tor_strdup(""); + lf->callback = cb; + lf->next = logfiles; + + LOCK_LOGS(); + logfiles = lf; + log_global_min_severity_ = get_min_log_level(); + UNLOCK_LOGS(); + return 0; +} + +/** Adjust the configured severity of any logs whose callback function is + * cb. */ +void +change_callback_log_severity(int loglevelMin, int loglevelMax, + log_callback cb) +{ + logfile_t *lf; + log_severity_list_t severities; + set_log_severity_config(loglevelMin, loglevelMax, &severities); + LOCK_LOGS(); + for (lf = logfiles; lf; lf = lf->next) { + if (lf->callback == cb) { + memcpy(lf->severities, &severities, sizeof(severities)); + } + } + log_global_min_severity_ = get_min_log_level(); + UNLOCK_LOGS(); +} + +/** If there are any log messages that were generated with LD_NOCB waiting to + * be sent to callback-based loggers, send them now. */ +void +flush_pending_log_callbacks(void) +{ + logfile_t *lf; + smartlist_t *messages, *messages_tmp; + + LOCK_LOGS(); + if (0 == smartlist_len(pending_cb_messages)) { + UNLOCK_LOGS(); + return; + } + + messages = pending_cb_messages; + pending_cb_messages = smartlist_new(); + do { + SMARTLIST_FOREACH_BEGIN(messages, pending_cb_message_t *, msg) { + const int severity = msg->severity; + const int domain = msg->domain; + for (lf = logfiles; lf; lf = lf->next) { + if (! lf->callback || lf->seems_dead || + ! (lf->severities->masks[SEVERITY_MASK_IDX(severity)] & domain)) { + continue; + } + lf->callback(severity, domain, msg->msg); + } + tor_free(msg->msg); + tor_free(msg); + } SMARTLIST_FOREACH_END(msg); + smartlist_clear(messages); + + messages_tmp = pending_cb_messages; + pending_cb_messages = messages; + messages = messages_tmp; + } while (smartlist_len(messages)); + + smartlist_free(messages); + + UNLOCK_LOGS(); +} + +/** Close any log handlers added by add_temp_log() or marked by + * mark_logs_temp(). */ +void +close_temp_logs(void) +{ + logfile_t *lf, **p; + + LOCK_LOGS(); + for (p = &logfiles; *p; ) { + if ((*p)->is_temporary) { + lf = *p; + /* we use *p here to handle the edge case of the head of the list */ + *p = (*p)->next; + close_log(lf); + log_free(lf); + } else { + p = &((*p)->next); + } + } + + log_global_min_severity_ = get_min_log_level(); + UNLOCK_LOGS(); +} + +/** Make all currently temporary logs (set to be closed by close_temp_logs) + * live again, and close all non-temporary logs. */ +void +rollback_log_changes(void) +{ + logfile_t *lf; + LOCK_LOGS(); + for (lf = logfiles; lf; lf = lf->next) + lf->is_temporary = ! lf->is_temporary; + UNLOCK_LOGS(); + close_temp_logs(); +} + +/** Configure all log handles to be closed by close_temp_logs(). */ +void +mark_logs_temp(void) +{ + logfile_t *lf; + LOCK_LOGS(); + for (lf = logfiles; lf; lf = lf->next) + lf->is_temporary = 1; + UNLOCK_LOGS(); +} + +/** + * Add a log handler to send messages to filename. If opening the + * logfile fails, -1 is returned and errno is set appropriately (by open(2)). + */ +int +add_file_log(const log_severity_list_t *severity, const char *filename) +{ + int fd; + logfile_t *lf; + + fd = tor_open_cloexec(filename, O_WRONLY|O_CREAT|O_APPEND, 0644); + if (fd<0) + return -1; + if (tor_fd_seekend(fd)<0) { + close(fd); + return -1; + } + + LOCK_LOGS(); + add_stream_log_impl(severity, filename, fd); + logfiles->needs_close = 1; + lf = logfiles; + log_global_min_severity_ = get_min_log_level(); + + if (log_tor_version(lf, 0) < 0) { + delete_log(lf); + } + UNLOCK_LOGS(); + + return 0; +} + +#ifdef HAVE_SYSLOG_H +/** + * Add a log handler to send messages to they system log facility. + */ +int +add_syslog_log(const log_severity_list_t *severity) +{ + logfile_t *lf; + if (syslog_count++ == 0) + /* This is the first syslog. */ + openlog("Tor", LOG_PID | LOG_NDELAY, LOGFACILITY); + + lf = tor_malloc_zero(sizeof(logfile_t)); + lf->fd = -1; + lf->severities = tor_memdup(severity, sizeof(log_severity_list_t)); + lf->filename = tor_strdup(""); + lf->is_syslog = 1; + + LOCK_LOGS(); + lf->next = logfiles; + logfiles = lf; + log_global_min_severity_ = get_min_log_level(); + UNLOCK_LOGS(); + return 0; +} +#endif + +/** If level is a valid log severity, return the corresponding + * numeric value. Otherwise, return -1. */ +int +parse_log_level(const char *level) +{ + if (!strcasecmp(level, "err")) + return LOG_ERR; + if (!strcasecmp(level, "warn")) + return LOG_WARN; + if (!strcasecmp(level, "notice")) + return LOG_NOTICE; + if (!strcasecmp(level, "info")) + return LOG_INFO; + if (!strcasecmp(level, "debug")) + return LOG_DEBUG; + return -1; +} + +/** Return the string equivalent of a given log level. */ +const char * +log_level_to_string(int level) +{ + return sev_to_string(level); +} + +/** NULL-terminated array of names for log domains such that domain_list[dom] + * is a description of dom. */ +static const char *domain_list[] = { + "GENERAL", "CRYPTO", "NET", "CONFIG", "FS", "PROTOCOL", "MM", + "HTTP", "APP", "CONTROL", "CIRC", "REND", "BUG", "DIR", "DIRSERV", + "OR", "EDGE", "ACCT", "HIST", "HANDSHAKE", "HEARTBEAT", "CHANNEL", NULL +}; + +/** Return a bitmask for the log domain for which domain is the name, + * or 0 if there is no such name. */ +static log_domain_mask_t +parse_log_domain(const char *domain) +{ + int i; + for (i=0; domain_list[i]; ++i) { + if (!strcasecmp(domain, domain_list[i])) + return (1u<= N_LOGGING_DOMAINS) { + tor_snprintf(buf, buflen, "", (long)domain); + return buf+strlen(buf); + } + d = domain_list[bit]; + n = strlcpy(cp, d, eos-cp); + if (n >= buflen) { + tor_snprintf(buf, buflen, "", (long)domain); + return buf+strlen(buf); + } + cp += n; + domain &= ~(1<cfg_ptr. Advance cfg_ptr after + * the end of the severityPattern. Set the value of severity_out to + * the parsed pattern. Return 0 on success, -1 on failure. + * + * The syntax for a SeverityPattern is: + *
+ *   SeverityPattern = *(DomainSeverity SP)* DomainSeverity
+ *   DomainSeverity = (DomainList SP)? SeverityRange
+ *   SeverityRange = MinSeverity ("-" MaxSeverity )?
+ *   DomainList = "[" (SP? DomainSpec SP? ",") SP? DomainSpec "]"
+ *   DomainSpec = "*" | Domain | "~" Domain
+ * 
+ * A missing MaxSeverity defaults to ERR. Severities and domains are + * case-insensitive. "~" indicates negation for a domain; negation happens + * last inside a DomainList. Only one SeverityRange without a DomainList is + * allowed per line. + */ +int +parse_log_severity_config(const char **cfg_ptr, + log_severity_list_t *severity_out) +{ + const char *cfg = *cfg_ptr; + int got_anything = 0; + int got_an_unqualified_range = 0; + memset(severity_out, 0, sizeof(*severity_out)); + + cfg = eat_whitespace(cfg); + while (*cfg) { + const char *dash, *space; + char *sev_lo, *sev_hi; + int low, high, i; + log_domain_mask_t domains = ~0u; + + if (*cfg == '[') { + int err = 0; + char *domains_str; + smartlist_t *domains_list; + log_domain_mask_t neg_domains = 0; + const char *closebracket = strchr(cfg, ']'); + if (!closebracket) + return -1; + domains = 0; + domains_str = tor_strndup(cfg+1, closebracket-cfg-1); + domains_list = smartlist_new(); + smartlist_split_string(domains_list, domains_str, ",", SPLIT_SKIP_SPACE, + -1); + tor_free(domains_str); + SMARTLIST_FOREACH_BEGIN(domains_list, const char *, domain) { + if (!strcmp(domain, "*")) { + domains = ~0u; + } else { + int d; + int negate=0; + if (*domain == '~') { + negate = 1; + ++domain; + } + d = parse_log_domain(domain); + if (!d) { + log_warn(LD_CONFIG, "No such logging domain as %s", domain); + err = 1; + } else { + if (negate) + neg_domains |= d; + else + domains |= d; + } + } + } SMARTLIST_FOREACH_END(domain); + SMARTLIST_FOREACH(domains_list, char *, d, tor_free(d)); + smartlist_free(domains_list); + if (err) + return -1; + if (domains == 0 && neg_domains) + domains = ~neg_domains; + else + domains &= ~neg_domains; + cfg = eat_whitespace(closebracket+1); + } else { + ++got_an_unqualified_range; + } + if (!strcasecmpstart(cfg, "file") || + !strcasecmpstart(cfg, "stderr") || + !strcasecmpstart(cfg, "stdout") || + !strcasecmpstart(cfg, "syslog")) { + goto done; + } + if (got_an_unqualified_range > 1) + return -1; + + space = strchr(cfg, ' '); + dash = strchr(cfg, '-'); + if (!space) + space = strchr(cfg, '\0'); + if (dash && dash < space) { + sev_lo = tor_strndup(cfg, dash-cfg); + sev_hi = tor_strndup(dash+1, space-(dash+1)); + } else { + sev_lo = tor_strndup(cfg, space-cfg); + sev_hi = tor_strdup("ERR"); + } + low = parse_log_level(sev_lo); + high = parse_log_level(sev_hi); + tor_free(sev_lo); + tor_free(sev_hi); + if (low == -1) + return -1; + if (high == -1) + return -1; + + got_anything = 1; + for (i=low; i >= high; --i) + severity_out->masks[SEVERITY_MASK_IDX(i)] |= domains; + + cfg = eat_whitespace(space); + } + + done: + *cfg_ptr = cfg; + return got_anything ? 0 : -1; +} + +/** Return the least severe log level that any current log is interested in. */ +int +get_min_log_level(void) +{ + logfile_t *lf; + int i; + int min = LOG_ERR; + for (lf = logfiles; lf; lf = lf->next) { + for (i = LOG_DEBUG; i > min; --i) + if (lf->severities->masks[SEVERITY_MASK_IDX(i)]) + min = i; + } + return min; +} + +/** Switch all logs to output at most verbose level. */ +void +switch_logs_debug(void) +{ + logfile_t *lf; + int i; + LOCK_LOGS(); + for (lf = logfiles; lf; lf=lf->next) { + for (i = LOG_DEBUG; i >= LOG_ERR; --i) + lf->severities->masks[SEVERITY_MASK_IDX(i)] = ~0u; + } + log_global_min_severity_ = get_min_log_level(); + UNLOCK_LOGS(); +} + +#if 0 +static void +dump_log_info(logfile_t *lf) +{ + const char *tp; + + if (lf->filename) { + printf("=== log into \"%s\" (%s-%s) (%stemporary)\n", lf->filename, + sev_to_string(lf->min_loglevel), + sev_to_string(lf->max_loglevel), + lf->is_temporary?"":"not "); + } else if (lf->is_syslog) { + printf("=== syslog (%s-%s) (%stemporary)\n", + sev_to_string(lf->min_loglevel), + sev_to_string(lf->max_loglevel), + lf->is_temporary?"":"not "); + } else { + printf("=== log (%s-%s) (%stemporary)\n", + sev_to_string(lf->min_loglevel), + sev_to_string(lf->max_loglevel), + lf->is_temporary?"":"not "); + } +} + +void +describe_logs(void) +{ + logfile_t *lf; + printf("==== BEGIN LOGS ====\n"); + for (lf = logfiles; lf; lf = lf->next) + dump_log_info(lf); + printf("==== END LOGS ====\n"); +} +#endif + diff --git a/src/tor/memarea.c b/src/tor/memarea.c new file mode 100644 index 0000000..96f95bf --- /dev/null +++ b/src/tor/memarea.c @@ -0,0 +1,328 @@ +/* Copyright (c) 2008-2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** \file memarea.c + * \brief Implementation for memarea_t, an allocator for allocating lots of + * small objects that will be freed all at once. + */ + +#include "orconfig.h" +#include +#include "memarea.h" +#include "tor_util.h" +#include "tor_compat.h" +#include "torlog.h" + +/** If true, we try to detect any attempts to write beyond the length of a + * memarea. */ +#define USE_SENTINELS + +/** All returned pointers should be aligned to the nearest multiple of this + * value. */ +#define MEMAREA_ALIGN SIZEOF_VOID_P + +#if MEMAREA_ALIGN == 4 +#define MEMAREA_ALIGN_MASK 3lu +#elif MEMAREA_ALIGN == 8 +#define MEMAREA_ALIGN_MASK 7lu +#else +#error "void* is neither 4 nor 8 bytes long. I don't know how to align stuff." +#endif + +#ifdef USE_SENTINELS +/** Magic value that we stick at the end of a memarea so we can make sure + * there are no run-off-the-end bugs. */ +#define SENTINEL_VAL 0x90806622u +/** How many bytes per area do we devote to the sentinel? */ +#define SENTINEL_LEN sizeof(uint32_t) +/** Given a mem_area_chunk_t with SENTINEL_LEN extra bytes allocated at the + * end, set those bytes. */ +#define SET_SENTINEL(chunk) \ + STMT_BEGIN \ + set_uint32( &(chunk)->u.mem[chunk->mem_size], SENTINEL_VAL ); \ + STMT_END +/** Assert that the sentinel on a memarea is set correctly. */ +#define CHECK_SENTINEL(chunk) \ + STMT_BEGIN \ + uint32_t sent_val = get_uint32(&(chunk)->u.mem[chunk->mem_size]); \ + tor_assert(sent_val == SENTINEL_VAL); \ + STMT_END +#else +#define SENTINEL_LEN 0 +#define SET_SENTINEL(chunk) STMT_NIL +#define CHECK_SENTINEL(chunk) STMT_NIL +#endif + +/** Increment ptr until it is aligned to MEMAREA_ALIGN. */ +static INLINE void * +realign_pointer(void *ptr) +{ + uintptr_t x = (uintptr_t)ptr; + x = (x+MEMAREA_ALIGN_MASK) & ~MEMAREA_ALIGN_MASK; + /* Reinstate this if bug 930 ever reappears + tor_assert(((void*)x) >= ptr); + */ + return (void*)x; +} + +/** Implements part of a memarea. New memory is carved off from chunk->mem in + * increasing order until a request is too big, at which point a new chunk is + * allocated. */ +typedef struct memarea_chunk_t { + /** Next chunk in this area. Only kept around so we can free it. */ + struct memarea_chunk_t *next_chunk; + size_t mem_size; /**< How much RAM is available in u.mem, total? */ + char *next_mem; /**< Next position in u.mem to allocate data at. If it's + * greater than or equal to mem+mem_size, this chunk is + * full. */ + union { + char mem[1]; /**< Memory space in this chunk. */ + void *void_for_alignment_; /**< Dummy; used to make sure mem is aligned. */ + } u; +} memarea_chunk_t; + +/** How many bytes are needed for overhead before we get to the memory part + * of a chunk? */ +#define CHUNK_HEADER_SIZE STRUCT_OFFSET(memarea_chunk_t, u) + +/** What's the smallest that we'll allocate a chunk? */ +#define CHUNK_SIZE 4096 + +/** A memarea_t is an allocation region for a set of small memory requests + * that will all be freed at once. */ +struct memarea_t { + memarea_chunk_t *first; /**< Top of the chunk stack: never NULL. */ +}; + +/** How many chunks will we put into the freelist before freeing them? */ +#define MAX_FREELIST_LEN 4 +/** The number of memarea chunks currently in our freelist. */ +static int freelist_len=0; +/** A linked list of unused memory area chunks. Used to prevent us from + * spinning in malloc/free loops. */ +static memarea_chunk_t *freelist = NULL; + +/** Helper: allocate a new memarea chunk of around chunk_size bytes. */ +static memarea_chunk_t * +alloc_chunk(size_t sz, int freelist_ok) +{ + tor_assert(sz < SIZE_T_CEILING); + if (freelist && freelist_ok) { + memarea_chunk_t *res = freelist; + freelist = res->next_chunk; + res->next_chunk = NULL; + --freelist_len; + CHECK_SENTINEL(res); + return res; + } else { + size_t chunk_size = freelist_ok ? CHUNK_SIZE : sz; + memarea_chunk_t *res; + chunk_size += SENTINEL_LEN; + res = tor_malloc(chunk_size); + res->next_chunk = NULL; + res->mem_size = chunk_size - CHUNK_HEADER_SIZE - SENTINEL_LEN; + res->next_mem = res->u.mem; + tor_assert(res->next_mem+res->mem_size+SENTINEL_LEN == + ((char*)res)+chunk_size); + tor_assert(realign_pointer(res->next_mem) == res->next_mem); + SET_SENTINEL(res); + return res; + } +} + +/** Release chunk from a memarea, either by adding it to the freelist + * or by freeing it if the freelist is already too big. */ +static void +chunk_free_unchecked(memarea_chunk_t *chunk) +{ + CHECK_SENTINEL(chunk); + if (freelist_len < MAX_FREELIST_LEN) { + ++freelist_len; + chunk->next_chunk = freelist; + freelist = chunk; + chunk->next_mem = chunk->u.mem; + } else { + tor_free(chunk); + } +} + +/** Allocate and return new memarea. */ +memarea_t * +memarea_new(void) +{ + memarea_t *head = tor_malloc(sizeof(memarea_t)); + head->first = alloc_chunk(CHUNK_SIZE, 1); + return head; +} + +/** Free area, invalidating all pointers returned from memarea_alloc() + * and friends for this area */ +void +memarea_drop_all(memarea_t *area) +{ + memarea_chunk_t *chunk, *next; + for (chunk = area->first; chunk; chunk = next) { + next = chunk->next_chunk; + chunk_free_unchecked(chunk); + } + area->first = NULL; /*fail fast on */ + tor_free(area); +} + +/** Forget about having allocated anything in area, and free some of + * the backing storage associated with it, as appropriate. Invalidates all + * pointers returned from memarea_alloc() for this area. */ +void +memarea_clear(memarea_t *area) +{ + memarea_chunk_t *chunk, *next; + if (area->first->next_chunk) { + for (chunk = area->first->next_chunk; chunk; chunk = next) { + next = chunk->next_chunk; + chunk_free_unchecked(chunk); + } + area->first->next_chunk = NULL; + } + area->first->next_mem = area->first->u.mem; +} + +/** Remove all unused memarea chunks from the internal freelist. */ +void +memarea_clear_freelist(void) +{ + memarea_chunk_t *chunk, *next; + freelist_len = 0; + for (chunk = freelist; chunk; chunk = next) { + next = chunk->next_chunk; + tor_free(chunk); + } + freelist = NULL; +} + +/** Return true iff p is in a range that has been returned by an + * allocation from area. */ +int +memarea_owns_ptr(const memarea_t *area, const void *p) +{ + memarea_chunk_t *chunk; + const char *ptr = p; + for (chunk = area->first; chunk; chunk = chunk->next_chunk) { + if (ptr >= chunk->u.mem && ptr < chunk->next_mem) + return 1; + } + return 0; +} + +/** Return a pointer to a chunk of memory in area of at least sz + * bytes. sz should be significantly smaller than the area's chunk + * size, though we can deal if it isn't. */ +void * +memarea_alloc(memarea_t *area, size_t sz) +{ + memarea_chunk_t *chunk = area->first; + char *result; + tor_assert(chunk); + CHECK_SENTINEL(chunk); + tor_assert(sz < SIZE_T_CEILING); + if (sz == 0) + sz = 1; + if (chunk->next_mem+sz > chunk->u.mem+chunk->mem_size) { + if (sz+CHUNK_HEADER_SIZE >= CHUNK_SIZE) { + /* This allocation is too big. Stick it in a special chunk, and put + * that chunk second in the list. */ + memarea_chunk_t *new_chunk = alloc_chunk(sz+CHUNK_HEADER_SIZE, 0); + new_chunk->next_chunk = chunk->next_chunk; + chunk->next_chunk = new_chunk; + chunk = new_chunk; + } else { + memarea_chunk_t *new_chunk = alloc_chunk(CHUNK_SIZE, 1); + new_chunk->next_chunk = chunk; + area->first = chunk = new_chunk; + } + tor_assert(chunk->mem_size >= sz); + } + result = chunk->next_mem; + chunk->next_mem = chunk->next_mem + sz; + /* Reinstate these if bug 930 ever comes back + tor_assert(chunk->next_mem >= chunk->u.mem); + tor_assert(chunk->next_mem <= chunk->u.mem+chunk->mem_size); + */ + chunk->next_mem = realign_pointer(chunk->next_mem); + return result; +} + +/** As memarea_alloc(), but clears the memory it returns. */ +void * +memarea_alloc_zero(memarea_t *area, size_t sz) +{ + void *result = memarea_alloc(area, sz); + memset(result, 0, sz); + return result; +} + +/** As memdup, but returns the memory from area. */ +void * +memarea_memdup(memarea_t *area, const void *s, size_t n) +{ + char *result = memarea_alloc(area, n); + memcpy(result, s, n); + return result; +} + +/** As strdup, but returns the memory from area. */ +char * +memarea_strdup(memarea_t *area, const char *s) +{ + return memarea_memdup(area, s, strlen(s)+1); +} + +/** As strndup, but returns the memory from area. */ +char * +memarea_strndup(memarea_t *area, const char *s, size_t n) +{ + size_t ln; + char *result; + const char *cp, *end = s+n; + tor_assert(n < SIZE_T_CEILING); + for (cp = s; cp < end && *cp; ++cp) + ; + /* cp now points to s+n, or to the 0 in the string. */ + ln = cp-s; + result = memarea_alloc(area, ln+1); + memcpy(result, s, ln); + result[ln]='\0'; + return result; +} + +/** Set allocated_out to the number of bytes allocated in area, + * and used_out to the number of bytes currently used. */ +void +memarea_get_stats(memarea_t *area, size_t *allocated_out, size_t *used_out) +{ + size_t a = 0, u = 0; + memarea_chunk_t *chunk; + for (chunk = area->first; chunk; chunk = chunk->next_chunk) { + CHECK_SENTINEL(chunk); + a += CHUNK_HEADER_SIZE + chunk->mem_size; + tor_assert(chunk->next_mem >= chunk->u.mem); + u += CHUNK_HEADER_SIZE + (chunk->next_mem - chunk->u.mem); + } + *allocated_out = a; + *used_out = u; +} + +/** Assert that area is okay. */ +void +memarea_assert_ok(memarea_t *area) +{ + memarea_chunk_t *chunk; + tor_assert(area->first); + + for (chunk = area->first; chunk; chunk = chunk->next_chunk) { + CHECK_SENTINEL(chunk); + tor_assert(chunk->next_mem >= chunk->u.mem); + tor_assert(chunk->next_mem <= + (char*) realign_pointer(chunk->u.mem+chunk->mem_size)); + } +} + diff --git a/src/tor/memarea.h b/src/tor/memarea.h new file mode 100644 index 0000000..8b88585 --- /dev/null +++ b/src/tor/memarea.h @@ -0,0 +1,25 @@ +/* Copyright (c) 2008-2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ +/* Tor dependencies */ + +#ifndef TOR_MEMAREA_H +#define TOR_MEMAREA_H + +typedef struct memarea_t memarea_t; + +memarea_t *memarea_new(void); +void memarea_drop_all(memarea_t *area); +void memarea_clear(memarea_t *area); +int memarea_owns_ptr(const memarea_t *area, const void *ptr); +void *memarea_alloc(memarea_t *area, size_t sz); +void *memarea_alloc_zero(memarea_t *area, size_t sz); +void *memarea_memdup(memarea_t *area, const void *s, size_t n); +char *memarea_strdup(memarea_t *area, const char *s); +char *memarea_strndup(memarea_t *area, const char *s, size_t n); +void memarea_get_stats(memarea_t *area, + size_t *allocated_out, size_t *used_out); +void memarea_clear_freelist(void); +void memarea_assert_ok(memarea_t *area); + +#endif + diff --git a/src/tor/mempool.c b/src/tor/mempool.c new file mode 100644 index 0000000..4102aa4 --- /dev/null +++ b/src/tor/mempool.c @@ -0,0 +1,628 @@ +/* Copyright (c) 2007-2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ +#if 1 +/* Tor dependencies */ +#include "orconfig.h" +#endif + +#include +#include +#include "torint.h" +#include "crypto.h" +#define MEMPOOL_PRIVATE +#include "mempool.h" + +/* OVERVIEW: + * + * This is an implementation of memory pools for Tor cells. It may be + * useful for you too. + * + * Generally, a memory pool is an allocation strategy optimized for large + * numbers of identically-sized objects. Rather than the elaborate arena + * and coalescing strategies you need to get good performance for a + * general-purpose malloc(), pools use a series of large memory "chunks", + * each of which is carved into a bunch of smaller "items" or + * "allocations". + * + * To get decent performance, you need to: + * - Minimize the number of times you hit the underlying allocator. + * - Try to keep accesses as local in memory as possible. + * - Try to keep the common case fast. + * + * Our implementation uses three lists of chunks per pool. Each chunk can + * be either "full" (no more room for items); "empty" (no items); or + * "used" (not full, not empty). There are independent doubly-linked + * lists for each state. + * + * CREDIT: + * + * I wrote this after looking at 3 or 4 other pooling allocators, but + * without copying. The strategy this most resembles (which is funny, + * since that's the one I looked at longest ago) is the pool allocator + * underlying Python's obmalloc code. Major differences from obmalloc's + * pools are: + * - We don't even try to be threadsafe. + * - We only handle objects of one size. + * - Our list of empty chunks is doubly-linked, not singly-linked. + * (This could change pretty easily; it's only doubly-linked for + * consistency.) + * - We keep a list of full chunks (so we can have a "nuke everything" + * function). Obmalloc's pools leave full chunks to float unanchored. + * + * LIMITATIONS: + * - Not even slightly threadsafe. + * - Likes to have lots of items per chunks. + * - One pointer overhead per allocated thing. (The alternative is + * something like glib's use of an RB-tree to keep track of what + * chunk any given piece of memory is in.) + * - Only aligns allocated things to void* level: redefine ALIGNMENT_TYPE + * if you need doubles. + * - Could probably be optimized a bit; the representation contains + * a bit more info than it really needs to have. + */ + +#if 1 +/* Tor dependencies */ +#include "tor_util.h" +#include "tor_compat.h" +#include "torlog.h" +#define ALLOC(x) tor_malloc(x) +#define FREE(x) tor_free(x) +#define ASSERT(x) tor_assert(x) +#undef ALLOC_CAN_RETURN_NULL +#define TOR +/* End Tor dependencies */ +#else +/* If you're not building this as part of Tor, you'll want to define the + * following macros. For now, these should do as defaults. + */ +#include +#define PREDICT_UNLIKELY(x) (x) +#define PREDICT_LIKELY(x) (x) +#define ALLOC(x) malloc(x) +#define FREE(x) free(x) +#define STRUCT_OFFSET(tp, member) \ + ((off_t) (((char*)&((tp*)0)->member)-(char*)0)) +#define ASSERT(x) assert(x) +#define ALLOC_CAN_RETURN_NULL +#endif + +/* Tuning parameters */ +/** Largest type that we need to ensure returned memory items are aligned to. + * Change this to "double" if we need to be safe for structs with doubles. */ +#define ALIGNMENT_TYPE void * +/** Increment that we need to align allocated. */ +#define ALIGNMENT sizeof(ALIGNMENT_TYPE) +/** Largest memory chunk that we should allocate. */ +#define MAX_CHUNK (8*(1L<<20)) +/** Smallest memory chunk size that we should allocate. */ +#define MIN_CHUNK 4096 + +typedef struct mp_allocated_t mp_allocated_t; +typedef struct mp_chunk_t mp_chunk_t; + +/** Holds a single allocated item, allocated as part of a chunk. */ +struct mp_allocated_t { + /** The chunk that this item is allocated in. This adds overhead to each + * allocated item, thus making this implementation inappropriate for + * very small items. */ + mp_chunk_t *in_chunk; + union { + /** If this item is free, the next item on the free list. */ + mp_allocated_t *next_free; + /** If this item is not free, the actual memory contents of this item. + * (Not actual size.) */ + char mem[1]; + /** An extra element to the union to insure correct alignment. */ + ALIGNMENT_TYPE dummy_; + } u; +}; + +/** 'Magic' value used to detect memory corruption. */ +#define MP_CHUNK_MAGIC 0x09870123 + +/** A chunk of memory. Chunks come from malloc; we use them */ +struct mp_chunk_t { + unsigned long magic; /**< Must be MP_CHUNK_MAGIC if this chunk is valid. */ + mp_chunk_t *next; /**< The next free, used, or full chunk in sequence. */ + mp_chunk_t *prev; /**< The previous free, used, or full chunk in sequence. */ + mp_pool_t *pool; /**< The pool that this chunk is part of. */ + /** First free item in the freelist for this chunk. Note that this may be + * NULL even if this chunk is not at capacity: if so, the free memory at + * next_mem has not yet been carved into items. + */ + mp_allocated_t *first_free; + int n_allocated; /**< Number of currently allocated items in this chunk. */ + int capacity; /**< Number of items that can be fit into this chunk. */ + size_t mem_size; /**< Number of usable bytes in mem. */ + char *next_mem; /**< Pointer into part of mem not yet carved up. */ + char mem[FLEXIBLE_ARRAY_MEMBER]; /**< Storage for this chunk. */ +}; + +/** Number of extra bytes needed beyond mem_size to allocate a chunk. */ +#define CHUNK_OVERHEAD STRUCT_OFFSET(mp_chunk_t, mem[0]) + +/** Given a pointer to a mp_allocated_t, return a pointer to the memory + * item it holds. */ +#define A2M(a) (&(a)->u.mem) +/** Given a pointer to a memory_item_t, return a pointer to its enclosing + * mp_allocated_t. */ +#define M2A(p) ( ((char*)p) - STRUCT_OFFSET(mp_allocated_t, u.mem) ) + +#ifdef ALLOC_CAN_RETURN_NULL +/** If our ALLOC() macro can return NULL, check whether x is NULL, + * and if so, return NULL. */ +#define CHECK_ALLOC(x) \ + if (PREDICT_UNLIKELY(!x)) { return NULL; } +#else +/** If our ALLOC() macro can't return NULL, do nothing. */ +#define CHECK_ALLOC(x) +#endif + +/** Helper: Allocate and return a new memory chunk for pool. Does not + * link the chunk into any list. */ +static mp_chunk_t * +mp_chunk_new(mp_pool_t *pool) +{ + size_t sz = pool->new_chunk_capacity * pool->item_alloc_size; + mp_chunk_t *chunk = ALLOC(CHUNK_OVERHEAD + sz); + +#ifdef MEMPOOL_STATS + ++pool->total_chunks_allocated; +#endif + CHECK_ALLOC(chunk); + memset(chunk, 0, sizeof(mp_chunk_t)); /* Doesn't clear the whole thing. */ + chunk->magic = MP_CHUNK_MAGIC; + chunk->capacity = pool->new_chunk_capacity; + chunk->mem_size = sz; + chunk->next_mem = chunk->mem; + chunk->pool = pool; + return chunk; +} + +/** Take a chunk that has just been allocated or removed from + * pool's empty chunk list, and add it to the head of the used chunk + * list. */ +static INLINE void +add_newly_used_chunk_to_used_list(mp_pool_t *pool, mp_chunk_t *chunk) +{ + chunk->next = pool->used_chunks; + if (chunk->next) + chunk->next->prev = chunk; + pool->used_chunks = chunk; + ASSERT(!chunk->prev); +} + +/** Return a newly allocated item from pool. */ +void * +mp_pool_get(mp_pool_t *pool) +{ + mp_chunk_t *chunk; + mp_allocated_t *allocated; + + if (PREDICT_LIKELY(pool->used_chunks != NULL)) { + /* Common case: there is some chunk that is neither full nor empty. Use + * that one. (We can't use the full ones, obviously, and we should fill + * up the used ones before we start on any empty ones. */ + chunk = pool->used_chunks; + + } else if (pool->empty_chunks) { + /* We have no used chunks, but we have an empty chunk that we haven't + * freed yet: use that. (We pull from the front of the list, which should + * get us the most recently emptied chunk.) */ + chunk = pool->empty_chunks; + + /* Remove the chunk from the empty list. */ + pool->empty_chunks = chunk->next; + if (chunk->next) + chunk->next->prev = NULL; + + /* Put the chunk on the 'used' list*/ + add_newly_used_chunk_to_used_list(pool, chunk); + + ASSERT(!chunk->prev); + --pool->n_empty_chunks; + if (pool->n_empty_chunks < pool->min_empty_chunks) + pool->min_empty_chunks = pool->n_empty_chunks; + } else { + /* We have no used or empty chunks: allocate a new chunk. */ + chunk = mp_chunk_new(pool); + CHECK_ALLOC(chunk); + + /* Add the new chunk to the used list. */ + add_newly_used_chunk_to_used_list(pool, chunk); + } + + ASSERT(chunk->n_allocated < chunk->capacity); + + if (chunk->first_free) { + /* If there's anything on the chunk's freelist, unlink it and use it. */ + allocated = chunk->first_free; + chunk->first_free = allocated->u.next_free; + allocated->u.next_free = NULL; /* For debugging; not really needed. */ + ASSERT(allocated->in_chunk == chunk); + } else { + /* Otherwise, the chunk had better have some free space left on it. */ + ASSERT(chunk->next_mem + pool->item_alloc_size <= + chunk->mem + chunk->mem_size); + + /* Good, it did. Let's carve off a bit of that free space, and use + * that. */ + allocated = (void*)chunk->next_mem; + chunk->next_mem += pool->item_alloc_size; + allocated->in_chunk = chunk; + allocated->u.next_free = NULL; /* For debugging; not really needed. */ + } + + ++chunk->n_allocated; +#ifdef MEMPOOL_STATS + ++pool->total_items_allocated; +#endif + + if (PREDICT_UNLIKELY(chunk->n_allocated == chunk->capacity)) { + /* This chunk just became full. */ + ASSERT(chunk == pool->used_chunks); + ASSERT(chunk->prev == NULL); + + /* Take it off the used list. */ + pool->used_chunks = chunk->next; + if (chunk->next) + chunk->next->prev = NULL; + + /* Put it on the full list. */ + chunk->next = pool->full_chunks; + if (chunk->next) + chunk->next->prev = chunk; + pool->full_chunks = chunk; + } + /* And return the memory portion of the mp_allocated_t. */ + return A2M(allocated); +} + +/** Return an allocated memory item to its memory pool. */ +void +mp_pool_release(void *item) +{ + mp_allocated_t *allocated = (void*) M2A(item); + mp_chunk_t *chunk = allocated->in_chunk; + + ASSERT(chunk); + ASSERT(chunk->magic == MP_CHUNK_MAGIC); + ASSERT(chunk->n_allocated > 0); + + allocated->u.next_free = chunk->first_free; + chunk->first_free = allocated; + + if (PREDICT_UNLIKELY(chunk->n_allocated == chunk->capacity)) { + /* This chunk was full and is about to be used. */ + mp_pool_t *pool = chunk->pool; + /* unlink from the full list */ + if (chunk->prev) + chunk->prev->next = chunk->next; + if (chunk->next) + chunk->next->prev = chunk->prev; + if (chunk == pool->full_chunks) + pool->full_chunks = chunk->next; + + /* link to the used list. */ + chunk->next = pool->used_chunks; + chunk->prev = NULL; + if (chunk->next) + chunk->next->prev = chunk; + pool->used_chunks = chunk; + } else if (PREDICT_UNLIKELY(chunk->n_allocated == 1)) { + /* This was used and is about to be empty. */ + mp_pool_t *pool = chunk->pool; + + /* Unlink from the used list */ + if (chunk->prev) + chunk->prev->next = chunk->next; + if (chunk->next) + chunk->next->prev = chunk->prev; + if (chunk == pool->used_chunks) + pool->used_chunks = chunk->next; + + /* Link to the empty list */ + chunk->next = pool->empty_chunks; + chunk->prev = NULL; + if (chunk->next) + chunk->next->prev = chunk; + pool->empty_chunks = chunk; + + /* Reset the guts of this chunk to defragment it, in case it gets + * used again. */ + chunk->first_free = NULL; + chunk->next_mem = chunk->mem; + + ++pool->n_empty_chunks; + } + --chunk->n_allocated; +} + +/** Allocate a new memory pool to hold items of size item_size. We'll + * try to fit about chunk_capacity bytes in each chunk. */ +mp_pool_t * +mp_pool_new(size_t item_size, size_t chunk_capacity) +{ + mp_pool_t *pool; + size_t alloc_size, new_chunk_cap; + + tor_assert(item_size < SIZE_T_CEILING); + tor_assert(chunk_capacity < SIZE_T_CEILING); + tor_assert(SIZE_T_CEILING / item_size > chunk_capacity); + + pool = ALLOC(sizeof(mp_pool_t)); + CHECK_ALLOC(pool); + memset(pool, 0, sizeof(mp_pool_t)); + + /* First, we figure out how much space to allow per item. We'll want to + * use make sure we have enough for the overhead plus the item size. */ + alloc_size = (size_t)(STRUCT_OFFSET(mp_allocated_t, u.mem) + item_size); + /* If the item_size is less than sizeof(next_free), we need to make + * the allocation bigger. */ + if (alloc_size < sizeof(mp_allocated_t)) + alloc_size = sizeof(mp_allocated_t); + + /* If we're not an even multiple of ALIGNMENT, round up. */ + if (alloc_size % ALIGNMENT) { + alloc_size = alloc_size + ALIGNMENT - (alloc_size % ALIGNMENT); + } + if (alloc_size < ALIGNMENT) + alloc_size = ALIGNMENT; + ASSERT((alloc_size % ALIGNMENT) == 0); + + /* Now we figure out how many items fit in each chunk. We need to fit at + * least 2 items per chunk. No chunk can be more than MAX_CHUNK bytes long, + * or less than MIN_CHUNK. */ + if (chunk_capacity > MAX_CHUNK) + chunk_capacity = MAX_CHUNK; + /* Try to be around a power of 2 in size, since that's what allocators like + * handing out. 512K-1 byte is a lot better than 512K+1 byte. */ + chunk_capacity = (size_t) round_to_power_of_2(chunk_capacity); + while (chunk_capacity < alloc_size * 2 + CHUNK_OVERHEAD) + chunk_capacity *= 2; + if (chunk_capacity < MIN_CHUNK) + chunk_capacity = MIN_CHUNK; + + new_chunk_cap = (chunk_capacity-CHUNK_OVERHEAD) / alloc_size; + tor_assert(new_chunk_cap < INT_MAX); + pool->new_chunk_capacity = (int)new_chunk_cap; + + pool->item_alloc_size = alloc_size; + + log_debug(LD_MM, "Capacity is %lu, item size is %lu, alloc size is %lu", + (unsigned long)pool->new_chunk_capacity, + (unsigned long)pool->item_alloc_size, + (unsigned long)(pool->new_chunk_capacity*pool->item_alloc_size)); + + return pool; +} + +/** Helper function for qsort: used to sort pointers to mp_chunk_t into + * descending order of fullness. */ +static int +mp_pool_sort_used_chunks_helper(const void *_a, const void *_b) +{ + mp_chunk_t *a = *(mp_chunk_t**)_a; + mp_chunk_t *b = *(mp_chunk_t**)_b; + return b->n_allocated - a->n_allocated; +} + +/** Sort the used chunks in pool into descending order of fullness, + * so that we preferentially fill up mostly full chunks before we make + * nearly empty chunks less nearly empty. */ +static void +mp_pool_sort_used_chunks(mp_pool_t *pool) +{ + int i, n=0, inverted=0; + mp_chunk_t **chunks, *chunk; + for (chunk = pool->used_chunks; chunk; chunk = chunk->next) { + ++n; + if (chunk->next && chunk->next->n_allocated > chunk->n_allocated) + ++inverted; + } + if (!inverted) + return; + //printf("Sort %d/%d\n",inverted,n); + chunks = ALLOC(sizeof(mp_chunk_t *)*n); +#ifdef ALLOC_CAN_RETURN_NULL + if (PREDICT_UNLIKELY(!chunks)) return; +#endif + for (i=0,chunk = pool->used_chunks; chunk; chunk = chunk->next) + chunks[i++] = chunk; + qsort(chunks, n, sizeof(mp_chunk_t *), mp_pool_sort_used_chunks_helper); + pool->used_chunks = chunks[0]; + chunks[0]->prev = NULL; + for (i=1;inext = chunks[i]; + chunks[i]->prev = chunks[i-1]; + } + chunks[n-1]->next = NULL; + FREE(chunks); + mp_pool_assert_ok(pool); +} + +/** If there are more than n empty chunks in pool, free the + * excess ones that have been empty for the longest. If + * keep_recently_used is true, do not free chunks unless they have been + * empty since the last call to this function. + **/ +void +mp_pool_clean(mp_pool_t *pool, int n_to_keep, int keep_recently_used) +{ + mp_chunk_t *chunk, **first_to_free; + + mp_pool_sort_used_chunks(pool); + ASSERT(n_to_keep >= 0); + + if (keep_recently_used) { + int n_recently_used = pool->n_empty_chunks - pool->min_empty_chunks; + if (n_to_keep < n_recently_used) + n_to_keep = n_recently_used; + } + + ASSERT(n_to_keep >= 0); + + first_to_free = &pool->empty_chunks; + while (*first_to_free && n_to_keep > 0) { + first_to_free = &(*first_to_free)->next; + --n_to_keep; + } + if (!*first_to_free) { + pool->min_empty_chunks = pool->n_empty_chunks; + return; + } + + chunk = *first_to_free; + while (chunk) { + mp_chunk_t *next = chunk->next; + chunk->magic = 0xdeadbeef; + FREE(chunk); +#ifdef MEMPOOL_STATS + ++pool->total_chunks_freed; +#endif + --pool->n_empty_chunks; + chunk = next; + } + + pool->min_empty_chunks = pool->n_empty_chunks; + *first_to_free = NULL; +} + +/** Helper: Given a list of chunks, free all the chunks in the list. */ +static void +destroy_chunks(mp_chunk_t *chunk) +{ + mp_chunk_t *next; + while (chunk) { + chunk->magic = 0xd3adb33f; + next = chunk->next; + FREE(chunk); + chunk = next; + } +} + +/** Free all space held in pool This makes all pointers returned from + * mp_pool_get(pool) invalid. */ +void +mp_pool_destroy(mp_pool_t *pool) +{ + destroy_chunks(pool->empty_chunks); + destroy_chunks(pool->used_chunks); + destroy_chunks(pool->full_chunks); + memwipe(pool, 0xe0, sizeof(mp_pool_t)); + FREE(pool); +} + +/** Helper: make sure that a given chunk list is not corrupt. */ +static int +assert_chunks_ok(mp_pool_t *pool, mp_chunk_t *chunk, int empty, int full) +{ + mp_allocated_t *allocated; + int n = 0; + if (chunk) + ASSERT(chunk->prev == NULL); + + while (chunk) { + n++; + ASSERT(chunk->magic == MP_CHUNK_MAGIC); + ASSERT(chunk->pool == pool); + for (allocated = chunk->first_free; allocated; + allocated = allocated->u.next_free) { + ASSERT(allocated->in_chunk == chunk); + } + if (empty) + ASSERT(chunk->n_allocated == 0); + else if (full) + ASSERT(chunk->n_allocated == chunk->capacity); + else + ASSERT(chunk->n_allocated > 0 && chunk->n_allocated < chunk->capacity); + + ASSERT(chunk->capacity == pool->new_chunk_capacity); + + ASSERT(chunk->mem_size == + pool->new_chunk_capacity * pool->item_alloc_size); + + ASSERT(chunk->next_mem >= chunk->mem && + chunk->next_mem <= chunk->mem + chunk->mem_size); + + if (chunk->next) + ASSERT(chunk->next->prev == chunk); + + chunk = chunk->next; + } + return n; +} + +/** Fail with an assertion if pool is not internally consistent. */ +void +mp_pool_assert_ok(mp_pool_t *pool) +{ + int n_empty; + + n_empty = assert_chunks_ok(pool, pool->empty_chunks, 1, 0); + assert_chunks_ok(pool, pool->full_chunks, 0, 1); + assert_chunks_ok(pool, pool->used_chunks, 0, 0); + + ASSERT(pool->n_empty_chunks == n_empty); +} + +#ifdef TOR +/** Dump information about pool's memory usage to the Tor log at level + * severity. */ +/*FFFF uses Tor logging functions. */ +void +mp_pool_log_status(mp_pool_t *pool, int severity) +{ + uint64_t bytes_used = 0; + uint64_t bytes_allocated = 0; + uint64_t bu = 0, ba = 0; + mp_chunk_t *chunk; + int n_full = 0, n_used = 0; + + ASSERT(pool); + + for (chunk = pool->empty_chunks; chunk; chunk = chunk->next) { + bytes_allocated += chunk->mem_size; + } + log_fn(severity, LD_MM, U64_FORMAT" bytes in %d empty chunks", + U64_PRINTF_ARG(bytes_allocated), pool->n_empty_chunks); + for (chunk = pool->used_chunks; chunk; chunk = chunk->next) { + ++n_used; + bu += chunk->n_allocated * pool->item_alloc_size; + ba += chunk->mem_size; + log_fn(severity, LD_MM, " used chunk: %d items allocated", + chunk->n_allocated); + } + log_fn(severity, LD_MM, U64_FORMAT"/"U64_FORMAT + " bytes in %d partially full chunks", + U64_PRINTF_ARG(bu), U64_PRINTF_ARG(ba), n_used); + bytes_used += bu; + bytes_allocated += ba; + bu = ba = 0; + for (chunk = pool->full_chunks; chunk; chunk = chunk->next) { + ++n_full; + bu += chunk->n_allocated * pool->item_alloc_size; + ba += chunk->mem_size; + } + log_fn(severity, LD_MM, U64_FORMAT"/"U64_FORMAT + " bytes in %d full chunks", + U64_PRINTF_ARG(bu), U64_PRINTF_ARG(ba), n_full); + bytes_used += bu; + bytes_allocated += ba; + + log_fn(severity, LD_MM, "Total: "U64_FORMAT"/"U64_FORMAT" bytes allocated " + "for cell pools are full.", + U64_PRINTF_ARG(bytes_used), U64_PRINTF_ARG(bytes_allocated)); + +#ifdef MEMPOOL_STATS + log_fn(severity, LD_MM, U64_FORMAT" cell allocations ever; " + U64_FORMAT" chunk allocations ever; " + U64_FORMAT" chunk frees ever.", + U64_PRINTF_ARG(pool->total_items_allocated), + U64_PRINTF_ARG(pool->total_chunks_allocated), + U64_PRINTF_ARG(pool->total_chunks_freed)); +#endif +} +#endif + diff --git a/src/tor/mempool.h b/src/tor/mempool.h new file mode 100644 index 0000000..0fc1e4c --- /dev/null +++ b/src/tor/mempool.h @@ -0,0 +1,65 @@ +/* Copyright (c) 2007-2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file mempool.h + * \brief Headers for mempool.c + **/ + +#ifndef TOR_MEMPOOL_H +#define TOR_MEMPOOL_H + +/** A memory pool is a context in which a large number of fixed-sized +* objects can be allocated efficiently. See mempool.c for implementation +* details. */ +typedef struct mp_pool_t mp_pool_t; + +void *mp_pool_get(mp_pool_t *pool); +void mp_pool_release(void *item); +mp_pool_t *mp_pool_new(size_t item_size, size_t chunk_capacity); +void mp_pool_clean(mp_pool_t *pool, int n_to_keep, int keep_recently_used); +void mp_pool_destroy(mp_pool_t *pool); +void mp_pool_assert_ok(mp_pool_t *pool); +void mp_pool_log_status(mp_pool_t *pool, int severity); + +#define MP_POOL_ITEM_OVERHEAD (sizeof(void*)) + +#define MEMPOOL_STATS + +#ifdef MEMPOOL_PRIVATE +/* These declarations are only used by mempool.c and test.c */ + +struct mp_pool_t { + /** Doubly-linked list of chunks in which no items have been allocated. + * The front of the list is the most recently emptied chunk. */ + struct mp_chunk_t *empty_chunks; + /** Doubly-linked list of chunks in which some items have been allocated, + * but which are not yet full. The front of the list is the chunk that has + * most recently been modified. */ + struct mp_chunk_t *used_chunks; + /** Doubly-linked list of chunks in which no more items can be allocated. + * The front of the list is the chunk that has most recently become full. */ + struct mp_chunk_t *full_chunks; + /** Length of empty_chunks. */ + int n_empty_chunks; + /** Lowest value of empty_chunks since last call to + * mp_pool_clean(-1). */ + int min_empty_chunks; + /** Size of each chunk (in items). */ + int new_chunk_capacity; + /** Size to allocate for each item, including overhead and alignment + * padding. */ + size_t item_alloc_size; +#ifdef MEMPOOL_STATS + /** Total number of items allocated ever. */ + uint64_t total_items_allocated; + /** Total number of chunks allocated ever. */ + uint64_t total_chunks_allocated; + /** Total number of chunks freed ever. */ + uint64_t total_chunks_freed; +#endif +}; +#endif + +#endif + diff --git a/src/tor/microdesc.c b/src/tor/microdesc.c new file mode 100644 index 0000000..1124991 --- /dev/null +++ b/src/tor/microdesc.c @@ -0,0 +1,833 @@ +/* Copyright (c) 2009-2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#include "or.h" +#include "circuitbuild.h" +#include "config.h" +#include "directory.h" +#include "dirserv.h" +#include "entrynodes.h" +#include "microdesc.h" +#include "networkstatus.h" +#include "nodelist.h" +#include "policies.h" +#include "router.h" +#include "routerlist.h" +#include "routerparse.h" + +/** A data structure to hold a bunch of cached microdescriptors. There are + * two active files in the cache: a "cache file" that we mmap, and a "journal + * file" that we append to. Periodically, we rebuild the cache file to hold + * only the microdescriptors that we want to keep */ +struct microdesc_cache_t { + /** Map from sha256-digest to microdesc_t for every microdesc_t in the + * cache. */ + HT_HEAD(microdesc_map, microdesc_t) map; + + /** Name of the cache file. */ + char *cache_fname; + /** Name of the journal file. */ + char *journal_fname; + /** Mmap'd contents of the cache file, or NULL if there is none. */ + tor_mmap_t *cache_content; + /** Number of bytes used in the journal file. */ + size_t journal_len; + /** Number of bytes in descriptors removed as too old. */ + size_t bytes_dropped; + + /** Total bytes of microdescriptor bodies we have added to this cache */ + uint64_t total_len_seen; + /** Total number of microdescriptors we have added to this cache */ + unsigned n_seen; +}; + +/** Helper: computes a hash of md to place it in a hash table. */ +static INLINE unsigned int +microdesc_hash_(microdesc_t *md) +{ + unsigned *d = (unsigned*)md->digest; +#if SIZEOF_INT == 4 + return d[0] ^ d[1] ^ d[2] ^ d[3] ^ d[4] ^ d[5] ^ d[6] ^ d[7]; +#else + return d[0] ^ d[1] ^ d[2] ^ d[3]; +#endif +} + +/** Helper: compares a and for equality for hash-table purposes. */ +static INLINE int +microdesc_eq_(microdesc_t *a, microdesc_t *b) +{ + return tor_memeq(a->digest, b->digest, DIGEST256_LEN); +} + +HT_PROTOTYPE(microdesc_map, microdesc_t, node, + microdesc_hash_, microdesc_eq_); +HT_GENERATE(microdesc_map, microdesc_t, node, + microdesc_hash_, microdesc_eq_, 0.6, + malloc, realloc, free); + +/** Write the body of md into f, with appropriate annotations. + * On success, return the total number of bytes written, and set + * *annotation_len_out to the number of bytes written as + * annotations. */ +static ssize_t +dump_microdescriptor(int fd, microdesc_t *md, size_t *annotation_len_out) +{ + ssize_t r = 0; + ssize_t written; + if (md->body == NULL) { + *annotation_len_out = 0; + return 0; + } + /* XXXX drops unknown annotations. */ + if (md->last_listed) { + char buf[ISO_TIME_LEN+1]; + char annotation[ISO_TIME_LEN+32]; + format_iso_time(buf, md->last_listed); + tor_snprintf(annotation, sizeof(annotation), "@last-listed %s\n", buf); + if (write_all(fd, annotation, strlen(annotation), 0) < 0) { + log_warn(LD_DIR, + "Couldn't write microdescriptor annotation: %s", + strerror(errno)); + return -1; + } + r += strlen(annotation); + *annotation_len_out = r; + } else { + *annotation_len_out = 0; + } + + md->off = tor_fd_getpos(fd); + written = write_all(fd, md->body, md->bodylen, 0); + if (written != (ssize_t)md->bodylen) { + log_warn(LD_DIR, + "Couldn't dump microdescriptor (wrote %ld out of %lu): %s", + (long)written, (unsigned long)md->bodylen, + strerror(errno)); + return -1; + } + r += md->bodylen; + return r; +} + +/** Holds a pointer to the current microdesc_cache_t object, or NULL if no + * such object has been allocated. */ +static microdesc_cache_t *the_microdesc_cache = NULL; + +/** Return a pointer to the microdescriptor cache, loading it if necessary. */ +microdesc_cache_t * +get_microdesc_cache(void) +{ + if (PREDICT_UNLIKELY(the_microdesc_cache==NULL)) { + microdesc_cache_t *cache = tor_malloc_zero(sizeof(microdesc_cache_t)); + HT_INIT(microdesc_map, &cache->map); + cache->cache_fname = get_datadir_fname("cached-microdescs"); + cache->journal_fname = get_datadir_fname("cached-microdescs.new"); + microdesc_cache_reload(cache); + the_microdesc_cache = cache; + } + return the_microdesc_cache; +} + +/* There are three sources of microdescriptors: + 1) Generated by us while acting as a directory authority. + 2) Loaded from the cache on disk. + 3) Downloaded. +*/ + +/** Decode the microdescriptors from the string starting at s and + * ending at eos, and store them in cache. If no_save, + * mark them as non-writable to disk. If where is SAVED_IN_CACHE, + * leave their bodies as pointers to the mmap'd cache. If where is + * SAVED_NOWHERE, do not allow annotations. If listed_at is not -1, + * set the last_listed field of every microdesc to listed_at. If + * requested_digests is non-null, then it contains a list of digests we mean + * to allow, so we should reject any non-requested microdesc with a different + * digest, and alter the list to contain only the digests of those microdescs + * we didn't find. + * Return a newly allocated list of the added microdescriptors, or NULL */ +smartlist_t * +microdescs_add_to_cache(microdesc_cache_t *cache, + const char *s, const char *eos, saved_location_t where, + int no_save, time_t listed_at, + smartlist_t *requested_digests256) +{ + smartlist_t *descriptors, *added; + const int allow_annotations = (where != SAVED_NOWHERE); + + descriptors = microdescs_parse_from_string(s, eos, + allow_annotations, + where); + if (listed_at != (time_t)-1) { + SMARTLIST_FOREACH(descriptors, microdesc_t *, md, + md->last_listed = listed_at); + } + if (requested_digests256) { + digestmap_t *requested; /* XXXX actually we should just use a + digest256map */ + requested = digestmap_new(); + SMARTLIST_FOREACH(requested_digests256, const char *, cp, + digestmap_set(requested, cp, (void*)1)); + SMARTLIST_FOREACH_BEGIN(descriptors, microdesc_t *, md) { + if (digestmap_get(requested, md->digest)) { + digestmap_set(requested, md->digest, (void*)2); + } else { + log_fn(LOG_PROTOCOL_WARN, LD_DIR, "Received non-requested microdesc"); + microdesc_free(md); + SMARTLIST_DEL_CURRENT(descriptors, md); + } + } SMARTLIST_FOREACH_END(md); + SMARTLIST_FOREACH_BEGIN(requested_digests256, char *, cp) { + if (digestmap_get(requested, cp) == (void*)2) { + tor_free(cp); + SMARTLIST_DEL_CURRENT(requested_digests256, cp); + } + } SMARTLIST_FOREACH_END(cp); + digestmap_free(requested, NULL); + } + + added = microdescs_add_list_to_cache(cache, descriptors, where, no_save); + smartlist_free(descriptors); + return added; +} + +/** As microdescs_add_to_cache, but takes a list of microdescriptors instead of + * a string to decode. Frees any members of descriptors that it does + * not add. */ +smartlist_t * +microdescs_add_list_to_cache(microdesc_cache_t *cache, + smartlist_t *descriptors, saved_location_t where, + int no_save) +{ + smartlist_t *added; + open_file_t *open_file = NULL; + int fd = -1; + // int n_added = 0; + ssize_t size = 0; + + if (where == SAVED_NOWHERE && !no_save) { + fd = start_writing_to_file(cache->journal_fname, + OPEN_FLAGS_APPEND|O_BINARY, + 0600, &open_file); + if (fd < 0) { + log_warn(LD_DIR, "Couldn't append to journal in %s: %s", + cache->journal_fname, strerror(errno)); + } + } + + added = smartlist_new(); + SMARTLIST_FOREACH_BEGIN(descriptors, microdesc_t *, md) { + microdesc_t *md2; + md2 = HT_FIND(microdesc_map, &cache->map, md); + if (md2) { + /* We already had this one. */ + if (md2->last_listed < md->last_listed) + md2->last_listed = md->last_listed; + microdesc_free(md); + if (where != SAVED_NOWHERE) + cache->bytes_dropped += size; + continue; + } + + /* Okay, it's a new one. */ + if (fd >= 0) { + size_t annotation_len; + size = dump_microdescriptor(fd, md, &annotation_len); + if (size < 0) { + /* we already warned in dump_microdescriptor */ + abort_writing_to_file(open_file); + fd = -1; + } else { + md->saved_location = SAVED_IN_JOURNAL; + cache->journal_len += size; + } + } else { + md->saved_location = where; + } + + md->no_save = no_save; + + HT_INSERT(microdesc_map, &cache->map, md); + md->held_in_map = 1; + smartlist_add(added, md); + ++cache->n_seen; + cache->total_len_seen += md->bodylen; + } SMARTLIST_FOREACH_END(md); + + if (fd >= 0) { + if (finish_writing_to_file(open_file) < 0) { + log_warn(LD_DIR, "Error appending to microdescriptor file: %s", + strerror(errno)); + smartlist_clear(added); + return added; + } + } + + { + networkstatus_t *ns = networkstatus_get_latest_consensus(); + if (ns && ns->flavor == FLAV_MICRODESC) + SMARTLIST_FOREACH(added, microdesc_t *, md, nodelist_add_microdesc(md)); + } + + if (smartlist_len(added)) + router_dir_info_changed(); + + return added; +} + +/** Remove every microdescriptor in cache. */ +void +microdesc_cache_clear(microdesc_cache_t *cache) +{ + microdesc_t **entry, **next; + for (entry = HT_START(microdesc_map, &cache->map); entry; entry = next) { + microdesc_t *md = *entry; + next = HT_NEXT_RMV(microdesc_map, &cache->map, entry); + md->held_in_map = 0; + microdesc_free(md); + } + HT_CLEAR(microdesc_map, &cache->map); + if (cache->cache_content) { + tor_munmap_file(cache->cache_content); + cache->cache_content = NULL; + } + cache->total_len_seen = 0; + cache->n_seen = 0; + cache->bytes_dropped = 0; +} + +/** Reload the contents of cache from disk. If it is empty, load it + * for the first time. Return 0 on success, -1 on failure. */ +int +microdesc_cache_reload(microdesc_cache_t *cache) +{ + struct stat st; + char *journal_content; + smartlist_t *added; + tor_mmap_t *mm; + int total = 0; + + microdesc_cache_clear(cache); + + mm = cache->cache_content = tor_mmap_file(cache->cache_fname); + if (mm) { + added = microdescs_add_to_cache(cache, mm->data, mm->data+mm->size, + SAVED_IN_CACHE, 0, -1, NULL); + if (added) { + total += smartlist_len(added); + smartlist_free(added); + } + } + + journal_content = read_file_to_str(cache->journal_fname, + RFTS_IGNORE_MISSING, &st); + if (journal_content) { + cache->journal_len = (size_t) st.st_size; + added = microdescs_add_to_cache(cache, journal_content, + journal_content+st.st_size, + SAVED_IN_JOURNAL, 0, -1, NULL); + if (added) { + total += smartlist_len(added); + smartlist_free(added); + } + tor_free(journal_content); + } + log_info(LD_DIR, "Reloaded microdescriptor cache. Found %d descriptors.", + total); + + microdesc_cache_rebuild(cache, 0 /* don't force */); + + return 0; +} + +/** By default, we remove any microdescriptors that have gone at least this + * long without appearing in a current consensus. */ +#define TOLERATE_MICRODESC_AGE (7*24*60*60) + +/** Remove all microdescriptors from cache that haven't been listed for + * a long time. Does not rebuild the cache on disk. If cutoff is + * positive, specifically remove microdescriptors that have been unlisted + * since cutoff. If force is true, remove microdescriptors even + * if we have no current live microdescriptor consensus. + */ +void +microdesc_cache_clean(microdesc_cache_t *cache, time_t cutoff, int force) +{ + microdesc_t **mdp, *victim; + int dropped=0, kept=0; + size_t bytes_dropped = 0; + time_t now = time(NULL); + + /* If we don't know a live consensus, don't believe last_listed values: we + * might be starting up after being down for a while. */ + if (! force && + ! networkstatus_get_reasonably_live_consensus(now, FLAV_MICRODESC)) + return; + + if (cutoff <= 0) + cutoff = now - TOLERATE_MICRODESC_AGE; + + for (mdp = HT_START(microdesc_map, &cache->map); mdp != NULL; ) { + if ((*mdp)->last_listed < cutoff) { + ++dropped; + victim = *mdp; + mdp = HT_NEXT_RMV(microdesc_map, &cache->map, mdp); + victim->held_in_map = 0; + bytes_dropped += victim->bodylen; + microdesc_free(victim); + } else { + ++kept; + mdp = HT_NEXT(microdesc_map, &cache->map, mdp); + } + } + + if (dropped) { + log_info(LD_DIR, "Removed %d/%d microdescriptors as old.", + dropped,dropped+kept); + cache->bytes_dropped += bytes_dropped; + } +} + +static int +should_rebuild_md_cache(microdesc_cache_t *cache) +{ + const size_t old_len = + cache->cache_content ? cache->cache_content->size : 0; + const size_t journal_len = cache->journal_len; + const size_t dropped = cache->bytes_dropped; + + if (journal_len < 16384) + return 0; /* Don't bother, not enough has happened yet. */ + if (dropped > (journal_len + old_len) / 3) + return 1; /* We could save 1/3 or more of the currently used space. */ + if (journal_len > old_len / 2) + return 1; /* We should append to the regular file */ + + return 0; +} + +/** + * Mark md as having no body, and release any storage previously held + * by its body. + */ +static void +microdesc_wipe_body(microdesc_t *md) +{ + if (!md) + return; + + if (md->saved_location != SAVED_IN_CACHE) + tor_free(md->body); + + md->off = 0; + md->saved_location = SAVED_NOWHERE; + md->body = NULL; + md->bodylen = 0; + md->no_save = 1; +} + +/** Regenerate the main cache file for cache, clear the journal file, + * and update every microdesc_t in the cache with pointers to its new + * location. If force is true, do this unconditionally. If + * force is false, do it only if we expect to save space on disk. */ +int +microdesc_cache_rebuild(microdesc_cache_t *cache, int force) +{ + open_file_t *open_file; + int fd = -1; + microdesc_t **mdp; + smartlist_t *wrote; + ssize_t size; + off_t off = 0, off_real; + int orig_size, new_size; + + if (cache == NULL) { + cache = the_microdesc_cache; + if (cache == NULL) + return 0; + } + + /* Remove dead descriptors */ + microdesc_cache_clean(cache, 0/*cutoff*/, 0/*force*/); + + if (!force && !should_rebuild_md_cache(cache)) + return 0; + + log_info(LD_DIR, "Rebuilding the microdescriptor cache..."); + + orig_size = (int)(cache->cache_content ? cache->cache_content->size : 0); + orig_size += (int)cache->journal_len; + + fd = start_writing_to_file(cache->cache_fname, + OPEN_FLAGS_REPLACE|O_BINARY, + 0600, &open_file); + if (fd < 0) + return -1; + + wrote = smartlist_new(); + + HT_FOREACH(mdp, microdesc_map, &cache->map) { + microdesc_t *md = *mdp; + size_t annotation_len; + if (md->no_save || !md->body) + continue; + + size = dump_microdescriptor(fd, md, &annotation_len); + if (size < 0) { + microdesc_wipe_body(md); + + /* rewind, in case it was a partial write. */ + tor_fd_setpos(fd, off); + continue; + } + tor_assert(((size_t)size) == annotation_len + md->bodylen); + md->off = off + annotation_len; + off += size; + off_real = tor_fd_getpos(fd); + if (off_real != off) { + log_warn(LD_BUG, "Discontinuity in position in microdescriptor cache." + "By my count, I'm at "I64_FORMAT + ", but I should be at "I64_FORMAT, + I64_PRINTF_ARG(off), I64_PRINTF_ARG(off_real)); + if (off_real >= 0) + off = off_real; + } + if (md->saved_location != SAVED_IN_CACHE) { + tor_free(md->body); + md->saved_location = SAVED_IN_CACHE; + } + smartlist_add(wrote, md); + } + + /* We must do this unmap _before_ we call finish_writing_to_file(), or + * windows will not actually replace the file. */ + if (cache->cache_content) + tor_munmap_file(cache->cache_content); + + if (finish_writing_to_file(open_file) < 0) { + log_warn(LD_DIR, "Error rebuilding microdescriptor cache: %s", + strerror(errno)); + /* Okay. Let's prevent from making things worse elsewhere. */ + cache->cache_content = NULL; + HT_FOREACH(mdp, microdesc_map, &cache->map) { + microdesc_t *md = *mdp; + if (md->saved_location == SAVED_IN_CACHE) { + microdesc_wipe_body(md); + } + } + return -1; + } + + cache->cache_content = tor_mmap_file(cache->cache_fname); + + if (!cache->cache_content && smartlist_len(wrote)) { + log_err(LD_DIR, "Couldn't map file that we just wrote to %s!", + cache->cache_fname); + smartlist_free(wrote); + return -1; + } + SMARTLIST_FOREACH_BEGIN(wrote, microdesc_t *, md) { + tor_assert(md->saved_location == SAVED_IN_CACHE); + md->body = (char*)cache->cache_content->data + md->off; + if (PREDICT_UNLIKELY( + md->bodylen < 9 || fast_memneq(md->body, "onion-key", 9) != 0)) { + /* XXXX once bug 2022 is solved, we can kill this block and turn it + * into just the tor_assert(fast_memeq) */ + off_t avail = cache->cache_content->size - md->off; + char *bad_str; + tor_assert(avail >= 0); + bad_str = tor_strndup(md->body, MIN(128, (size_t)avail)); + log_err(LD_BUG, "After rebuilding microdesc cache, offsets seem wrong. " + " At offset %d, I expected to find a microdescriptor starting " + " with \"onion-key\". Instead I got %s.", + (int)md->off, escaped(bad_str)); + tor_free(bad_str); + tor_assert(fast_memeq(md->body, "onion-key", 9)); + } + } SMARTLIST_FOREACH_END(md); + + smartlist_free(wrote); + + write_str_to_file(cache->journal_fname, "", 1); + cache->journal_len = 0; + cache->bytes_dropped = 0; + + new_size = cache->cache_content ? (int)cache->cache_content->size : 0; + log_info(LD_DIR, "Done rebuilding microdesc cache. " + "Saved %d bytes; %d still used.", + orig_size-new_size, new_size); + + return 0; +} + +/** Make sure that the reference count of every microdescriptor in cache is + * accurate. */ +void +microdesc_check_counts(void) +{ + microdesc_t **mdp; + if (!the_microdesc_cache) + return; + + HT_FOREACH(mdp, microdesc_map, &the_microdesc_cache->map) { + microdesc_t *md = *mdp; + unsigned int found=0; + const smartlist_t *nodes = nodelist_get_list(); + SMARTLIST_FOREACH(nodes, node_t *, node, { + if (node->md == md) { + ++found; + } + }); + tor_assert(found == md->held_by_nodes); + } +} + +/** Deallocate a single microdescriptor. Note: the microdescriptor MUST have + * previously been removed from the cache if it had ever been inserted. */ +void +microdesc_free_(microdesc_t *md, const char *fname, int lineno) +{ + if (!md) + return; + + /* Make sure that the microdesc was really removed from the appropriate data + structures. */ + if (md->held_in_map) { + microdesc_cache_t *cache = get_microdesc_cache(); + microdesc_t *md2 = HT_FIND(microdesc_map, &cache->map, md); + if (md2 == md) { + log_warn(LD_BUG, "microdesc_free() called from %s:%d, but md was still " + "in microdesc_map", fname, lineno); + HT_REMOVE(microdesc_map, &cache->map, md); + } else { + log_warn(LD_BUG, "microdesc_free() called from %s:%d with held_in_map " + "set, but microdesc was not in the map.", fname, lineno); + } + tor_fragile_assert(); + } + if (md->held_by_nodes) { + int found=0; + const smartlist_t *nodes = nodelist_get_list(); + SMARTLIST_FOREACH(nodes, node_t *, node, { + if (node->md == md) { + ++found; + node->md = NULL; + } + }); + if (found) { + log_warn(LD_BUG, "microdesc_free() called from %s:%d, but md was still " + "referenced %d node(s); held_by_nodes == %u", + fname, lineno, found, md->held_by_nodes); + } else { + log_warn(LD_BUG, "microdesc_free() called from %s:%d with held_by_nodes " + "set to %u, but md was not referenced by any nodes", + fname, lineno, md->held_by_nodes); + } + tor_fragile_assert(); + } + //tor_assert(md->held_in_map == 0); + //tor_assert(md->held_by_nodes == 0); + + if (md->onion_pkey) + crypto_pk_free(md->onion_pkey); + tor_free(md->onion_curve25519_pkey); + if (md->body && md->saved_location != SAVED_IN_CACHE) + tor_free(md->body); + + if (md->family) { + SMARTLIST_FOREACH(md->family, char *, cp, tor_free(cp)); + smartlist_free(md->family); + } + short_policy_free(md->exit_policy); + short_policy_free(md->ipv6_exit_policy); + + tor_free(md); +} + +/** Free all storage held in the microdesc.c module. */ +void +microdesc_free_all(void) +{ + if (the_microdesc_cache) { + microdesc_cache_clear(the_microdesc_cache); + tor_free(the_microdesc_cache->cache_fname); + tor_free(the_microdesc_cache->journal_fname); + tor_free(the_microdesc_cache); + } +} + +/** If there is a microdescriptor in cache whose sha256 digest is + * d, return it. Otherwise return NULL. */ +microdesc_t * +microdesc_cache_lookup_by_digest256(microdesc_cache_t *cache, const char *d) +{ + microdesc_t *md, search; + if (!cache) + cache = get_microdesc_cache(); + memcpy(search.digest, d, DIGEST256_LEN); + md = HT_FIND(microdesc_map, &cache->map, &search); + return md; +} + +/** Return the mean size of decriptors added to cache since it was last + * cleared. Used to estimate the size of large downloads. */ +size_t +microdesc_average_size(microdesc_cache_t *cache) +{ + if (!cache) + cache = get_microdesc_cache(); + if (!cache->n_seen) + return 512; + return (size_t)(cache->total_len_seen / cache->n_seen); +} + +/** Return a smartlist of all the sha256 digest of the microdescriptors that + * are listed in ns but not present in cache. Returns pointers + * to internals of ns; you should not free the members of the resulting + * smartlist. Omit all microdescriptors whose digest appear in skip. */ +smartlist_t * +microdesc_list_missing_digest256(networkstatus_t *ns, microdesc_cache_t *cache, + int downloadable_only, digestmap_t *skip) +{ + smartlist_t *result = smartlist_new(); + time_t now = time(NULL); + tor_assert(ns->flavor == FLAV_MICRODESC); + SMARTLIST_FOREACH_BEGIN(ns->routerstatus_list, routerstatus_t *, rs) { + if (microdesc_cache_lookup_by_digest256(cache, rs->descriptor_digest)) + continue; + if (downloadable_only && + !download_status_is_ready(&rs->dl_status, now, + get_options()->TestingMicrodescMaxDownloadTries)) + continue; + if (skip && digestmap_get(skip, rs->descriptor_digest)) + continue; + if (tor_mem_is_zero(rs->descriptor_digest, DIGEST256_LEN)) + continue; + /* XXXX Also skip if we're a noncache and wouldn't use this router. + * XXXX NM Microdesc + */ + smartlist_add(result, rs->descriptor_digest); + } SMARTLIST_FOREACH_END(rs); + return result; +} + +/** Launch download requests for microdescriptors as appropriate. + * + * Specifically, we should launch download requests if we are configured to + * download mirodescriptors, and there are some microdescriptors listed the + * current microdesc consensus that we don't have, and either we never asked + * for them, or we failed to download them but we're willing to retry. + */ +void +update_microdesc_downloads(time_t now) +{ + const or_options_t *options = get_options(); + networkstatus_t *consensus; + smartlist_t *missing; + digestmap_t *pending; + + if (should_delay_dir_fetches(options)) + return; + if (directory_too_idle_to_fetch_descriptors(options, now)) + return; + + consensus = networkstatus_get_reasonably_live_consensus(now, FLAV_MICRODESC); + if (!consensus) + return; + + if (!we_fetch_microdescriptors(options)) + return; + + pending = digestmap_new(); + list_pending_microdesc_downloads(pending); + + missing = microdesc_list_missing_digest256(consensus, + get_microdesc_cache(), + 1, + pending); + digestmap_free(pending, NULL); + + launch_descriptor_downloads(DIR_PURPOSE_FETCH_MICRODESC, + missing, NULL, now); + + smartlist_free(missing); +} + +/** For every microdescriptor listed in the current microdecriptor consensus, + * update its last_listed field to be at least as recent as the publication + * time of the current microdescriptor consensus. + */ +void +update_microdescs_from_networkstatus(time_t now) +{ + microdesc_cache_t *cache = get_microdesc_cache(); + microdesc_t *md; + networkstatus_t *ns = + networkstatus_get_reasonably_live_consensus(now, FLAV_MICRODESC); + + if (! ns) + return; + + tor_assert(ns->flavor == FLAV_MICRODESC); + + SMARTLIST_FOREACH_BEGIN(ns->routerstatus_list, routerstatus_t *, rs) { + md = microdesc_cache_lookup_by_digest256(cache, rs->descriptor_digest); + if (md && ns->valid_after > md->last_listed) + md->last_listed = ns->valid_after; + } SMARTLIST_FOREACH_END(rs); +} + +/** Return true iff we should prefer to use microdescriptors rather than + * routerdescs for building circuits. */ +int +we_use_microdescriptors_for_circuits(const or_options_t *options) +{ + int ret = options->UseMicrodescriptors; + if (ret == -1) { + /* UseMicrodescriptors is "auto"; we need to decide: */ + /* If we are configured to use bridges and none of our bridges + * know what a microdescriptor is, the answer is no. */ + if (options->UseBridges && !any_bridge_supports_microdescriptors()) + return 0; + /* Otherwise, we decide that we'll use microdescriptors iff we are + * not a server, and we're not autofetching everything. */ + /* XXX023 what does not being a server have to do with it? also there's + * a partitioning issue here where bridges differ from clients. */ + ret = !server_mode(options) && !options->FetchUselessDescriptors; + } + return ret; +} + +/** Return true iff we should try to download microdescriptors at all. */ +int +we_fetch_microdescriptors(const or_options_t *options) +{ + if (directory_caches_dir_info(options)) + return 1; + if (options->FetchUselessDescriptors) + return 1; + return we_use_microdescriptors_for_circuits(options); +} + +/** Return true iff we should try to download router descriptors at all. */ +int +we_fetch_router_descriptors(const or_options_t *options) +{ + if (directory_caches_dir_info(options)) + return 1; + if (options->FetchUselessDescriptors) + return 1; + return ! we_use_microdescriptors_for_circuits(options); +} + +/** Return the consensus flavor we actually want to use to build circuits. */ +int +usable_consensus_flavor(void) +{ + if (we_use_microdescriptors_for_circuits(get_options())) { + return FLAV_MICRODESC; + } else { + return FLAV_NS; + } +} + diff --git a/src/tor/microdesc.h b/src/tor/microdesc.h new file mode 100644 index 0000000..7adb8c6 --- /dev/null +++ b/src/tor/microdesc.h @@ -0,0 +1,56 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file microdesc.h + * \brief Header file for microdesc.c. + **/ + +#ifndef TOR_MICRODESC_H +#define TOR_MICRODESC_H + +microdesc_cache_t *get_microdesc_cache(void); + +void microdesc_check_counts(void); + +smartlist_t *microdescs_add_to_cache(microdesc_cache_t *cache, + const char *s, const char *eos, saved_location_t where, + int no_save, time_t listed_at, + smartlist_t *requested_digests256); +smartlist_t *microdescs_add_list_to_cache(microdesc_cache_t *cache, + smartlist_t *descriptors, saved_location_t where, + int no_save); + +void microdesc_cache_clean(microdesc_cache_t *cache, time_t cutoff, int force); +int microdesc_cache_rebuild(microdesc_cache_t *cache, int force); +int microdesc_cache_reload(microdesc_cache_t *cache); +void microdesc_cache_clear(microdesc_cache_t *cache); + +microdesc_t *microdesc_cache_lookup_by_digest256(microdesc_cache_t *cache, + const char *d); + +size_t microdesc_average_size(microdesc_cache_t *cache); + +smartlist_t *microdesc_list_missing_digest256(networkstatus_t *ns, + microdesc_cache_t *cache, + int downloadable_only, + digestmap_t *skip); + +void microdesc_free_(microdesc_t *md, const char *fname, int line); +#define microdesc_free(md) \ + microdesc_free_((md), __FILE__, __LINE__) +void microdesc_free_all(void); + +void update_microdesc_downloads(time_t now); +void update_microdescs_from_networkstatus(time_t now); + +int usable_consensus_flavor(void); +int we_fetch_microdescriptors(const or_options_t *options); +int we_fetch_router_descriptors(const or_options_t *options); +int we_use_microdescriptors_for_circuits(const or_options_t *options); + +#endif + diff --git a/src/tor/networkstatus.c b/src/tor/networkstatus.c new file mode 100644 index 0000000..9f3d881 --- /dev/null +++ b/src/tor/networkstatus.c @@ -0,0 +1,1871 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file networkstatus.c + * \brief Functions and structures for handling network status documents as a + * client or cache. + */ + +#include "or.h" +#include "channel.h" +#include "circuitmux.h" +#include "circuitmux_ewma.h" +#include "circuitstats.h" +#include "config.h" +#include "connection.h" +#include "connection_or.h" +#include "control.h" +#include "directory.h" +#include "dirserv.h" +#include "dirvote.h" +#include "entrynodes.h" +#include "onion_main.h" +#include "microdesc.h" +#include "networkstatus.h" +#include "nodelist.h" +#include "relay.h" +#include "router.h" +#include "routerlist.h" +#include "routerparse.h" + +/** Map from lowercase nickname to identity digest of named server, if any. */ +static strmap_t *named_server_map = NULL; +/** Map from lowercase nickname to (void*)1 for all names that are listed + * as unnamed for some server in the consensus. */ +static strmap_t *unnamed_server_map = NULL; + +/** Most recently received and validated v3 consensus network status, + * of whichever type we are using for our own circuits. This will be the same + * as one of current_ns_consensus or current_md_consensus. + */ +#define current_consensus \ + (we_use_microdescriptors_for_circuits(get_options()) ? \ + current_md_consensus : current_ns_consensus) + +/** Most recently received and validated v3 "ns"-flavored consensus network + * status. */ +static networkstatus_t *current_ns_consensus = NULL; + +/** Most recently received and validated v3 "microdec"-flavored consensus + * network status. */ +static networkstatus_t *current_md_consensus = NULL; + +/** A v3 consensus networkstatus that we've received, but which we don't + * have enough certificates to be happy about. */ +typedef struct consensus_waiting_for_certs_t { + /** The consensus itself. */ + networkstatus_t *consensus; + /** The encoded version of the consensus, nul-terminated. */ + char *body; + /** When did we set the current value of consensus_waiting_for_certs? If + * this is too recent, we shouldn't try to fetch a new consensus for a + * little while, to give ourselves time to get certificates for this one. */ + time_t set_at; + /** Set to 1 if we've been holding on to it for so long we should maybe + * treat it as being bad. */ + int dl_failed; +} consensus_waiting_for_certs_t; + +/** An array, for each flavor of consensus we might want, of consensuses that + * we have downloaded, but which we cannot verify due to having insufficient + * authority certificates. */ +static consensus_waiting_for_certs_t + consensus_waiting_for_certs[N_CONSENSUS_FLAVORS]; + +/** A time before which we shouldn't try to replace the current consensus: + * this will be at some point after the next consensus becomes valid, but + * before the current consensus becomes invalid. */ +static time_t time_to_download_next_consensus[N_CONSENSUS_FLAVORS]; +/** Download status for the current consensus networkstatus. */ +static download_status_t consensus_dl_status[N_CONSENSUS_FLAVORS]; + +/** True iff we have logged a warning about this OR's version being older than + * listed by the authorities. */ +static int have_warned_about_old_version = 0; +/** True iff we have logged a warning about this OR's version being newer than + * listed by the authorities. */ +static int have_warned_about_new_version = 0; + +static void routerstatus_list_update_named_server_map(void); + +/** Forget that we've warned about anything networkstatus-related, so we will + * give fresh warnings if the same behavior happens again. */ +void +networkstatus_reset_warnings(void) +{ + if (current_consensus) { + SMARTLIST_FOREACH(nodelist_get_list(), node_t *, node, + node->name_lookup_warned = 0); + } + + have_warned_about_old_version = 0; + have_warned_about_new_version = 0; +} + +/** Reset the descriptor download failure count on all networkstatus docs, so + * that we can retry any long-failed documents immediately. + */ +void +networkstatus_reset_download_failures(void) +{ + int i; + + for (i=0; i < N_CONSENSUS_FLAVORS; ++i) + download_status_reset(&consensus_dl_status[i]); +} + +/** Read every cached v3 consensus networkstatus from the disk. */ +int +router_reload_consensus_networkstatus(void) +{ + char *filename; + char *s; + const unsigned int flags = NSSET_FROM_CACHE | NSSET_DONT_DOWNLOAD_CERTS; + int flav; + + /* FFFF Suppress warnings if cached consensus is bad? */ + for (flav = 0; flav < N_CONSENSUS_FLAVORS; ++flav) { + char buf[128]; + const char *flavor = networkstatus_get_flavor_name(flav); + if (flav == FLAV_NS) { + filename = get_datadir_fname("cached-consensus"); + } else { + tor_snprintf(buf, sizeof(buf), "cached-%s-consensus", flavor); + filename = get_datadir_fname(buf); + } + s = read_file_to_str(filename, RFTS_IGNORE_MISSING, NULL); + if (s) { + if (networkstatus_set_current_consensus(s, flavor, flags) < -1) { + log_warn(LD_FS, "Couldn't load consensus %s networkstatus from \"%s\"", + flavor, filename); + } + tor_free(s); + } + tor_free(filename); + + if (flav == FLAV_NS) { + filename = get_datadir_fname("unverified-consensus"); + } else { + tor_snprintf(buf, sizeof(buf), "unverified-%s-consensus", flavor); + filename = get_datadir_fname(buf); + } + + s = read_file_to_str(filename, RFTS_IGNORE_MISSING, NULL); + if (s) { + if (networkstatus_set_current_consensus(s, flavor, + flags|NSSET_WAS_WAITING_FOR_CERTS)) { + log_info(LD_FS, "Couldn't load consensus %s networkstatus from \"%s\"", + flavor, filename); + } + tor_free(s); + } + tor_free(filename); + } + + if (!current_consensus) { + if (!named_server_map) + named_server_map = strmap_new(); + if (!unnamed_server_map) + unnamed_server_map = strmap_new(); + } + + update_certificate_downloads(time(NULL)); + + routers_update_all_from_networkstatus(time(NULL), 3); + update_microdescs_from_networkstatus(time(NULL)); + + return 0; +} + +/** Free all storage held by the vote_routerstatus object rs. */ +static void +vote_routerstatus_free(vote_routerstatus_t *rs) +{ + vote_microdesc_hash_t *h, *next; + if (!rs) + return; + tor_free(rs->version); + tor_free(rs->status.exitsummary); + for (h = rs->microdesc; h; h = next) { + tor_free(h->microdesc_hash_line); + next = h->next; + tor_free(h); + } + tor_free(rs); +} + +/** Free all storage held by the routerstatus object rs. */ +void +routerstatus_free(routerstatus_t *rs) +{ + if (!rs) + return; + tor_free(rs->exitsummary); + tor_free(rs); +} + +/** Free all storage held in sig */ +void +document_signature_free(document_signature_t *sig) +{ + tor_free(sig->signature); + tor_free(sig); +} + +/** Return a newly allocated copy of sig */ +document_signature_t * +document_signature_dup(const document_signature_t *sig) +{ + document_signature_t *r = tor_memdup(sig, sizeof(document_signature_t)); + if (r->signature) + r->signature = tor_memdup(sig->signature, sig->signature_len); + return r; +} + +/** Free all storage held in ns. */ +void +networkstatus_vote_free(networkstatus_t *ns) +{ + if (!ns) + return; + + tor_free(ns->client_versions); + tor_free(ns->server_versions); + if (ns->known_flags) { + SMARTLIST_FOREACH(ns->known_flags, char *, c, tor_free(c)); + smartlist_free(ns->known_flags); + } + if (ns->weight_params) { + SMARTLIST_FOREACH(ns->weight_params, char *, c, tor_free(c)); + smartlist_free(ns->weight_params); + } + if (ns->net_params) { + SMARTLIST_FOREACH(ns->net_params, char *, c, tor_free(c)); + smartlist_free(ns->net_params); + } + if (ns->supported_methods) { + SMARTLIST_FOREACH(ns->supported_methods, char *, c, tor_free(c)); + smartlist_free(ns->supported_methods); + } + if (ns->voters) { + SMARTLIST_FOREACH_BEGIN(ns->voters, networkstatus_voter_info_t *, voter) { + tor_free(voter->nickname); + tor_free(voter->address); + tor_free(voter->contact); + if (voter->sigs) { + SMARTLIST_FOREACH(voter->sigs, document_signature_t *, sig, + document_signature_free(sig)); + smartlist_free(voter->sigs); + } + tor_free(voter); + } SMARTLIST_FOREACH_END(voter); + smartlist_free(ns->voters); + } + authority_cert_free(ns->cert); + + if (ns->routerstatus_list) { + if (ns->type == NS_TYPE_VOTE || ns->type == NS_TYPE_OPINION) { + SMARTLIST_FOREACH(ns->routerstatus_list, vote_routerstatus_t *, rs, + vote_routerstatus_free(rs)); + } else { + SMARTLIST_FOREACH(ns->routerstatus_list, routerstatus_t *, rs, + routerstatus_free(rs)); + } + + smartlist_free(ns->routerstatus_list); + } + + digestmap_free(ns->desc_digest_map, NULL); + + memwipe(ns, 11, sizeof(*ns)); + tor_free(ns); +} + +/** Return the voter info from vote for the voter whose identity digest + * is identity, or NULL if no such voter is associated with + * vote. */ +networkstatus_voter_info_t * +networkstatus_get_voter_by_id(networkstatus_t *vote, + const char *identity) +{ + if (!vote || !vote->voters) + return NULL; + SMARTLIST_FOREACH(vote->voters, networkstatus_voter_info_t *, voter, + if (fast_memeq(voter->identity_digest, identity, DIGEST_LEN)) + return voter); + return NULL; +} + +/** Check whether the signature sig is correctly signed with the + * signing key in cert. Return -1 if cert doesn't match the + * signing key; otherwise set the good_signature or bad_signature flag on + * voter, and return 0. */ +int +networkstatus_check_document_signature(const networkstatus_t *consensus, + document_signature_t *sig, + const authority_cert_t *cert) +{ + char key_digest[DIGEST_LEN]; + const int dlen = sig->alg == DIGEST_SHA1 ? DIGEST_LEN : DIGEST256_LEN; + char *signed_digest; + size_t signed_digest_len; + + if (crypto_pk_get_digest(cert->signing_key, key_digest)<0) + return -1; + if (tor_memneq(sig->signing_key_digest, key_digest, DIGEST_LEN) || + tor_memneq(sig->identity_digest, cert->cache_info.identity_digest, + DIGEST_LEN)) + return -1; + + signed_digest_len = crypto_pk_keysize(cert->signing_key); + signed_digest = tor_malloc(signed_digest_len); + if (crypto_pk_public_checksig(cert->signing_key, + signed_digest, + signed_digest_len, + sig->signature, + sig->signature_len) < dlen || + tor_memneq(signed_digest, consensus->digests.d[sig->alg], dlen)) { + log_warn(LD_DIR, "Got a bad signature on a networkstatus vote"); + sig->bad_signature = 1; + } else { + sig->good_signature = 1; + } + tor_free(signed_digest); + return 0; +} + +/** Given a v3 networkstatus consensus in consensus, check every + * as-yet-unchecked signature on consensus. Return 1 if there is a + * signature from every recognized authority on it, 0 if there are + * enough good signatures from recognized authorities on it, -1 if we might + * get enough good signatures by fetching missing certificates, and -2 + * otherwise. Log messages at INFO or WARN: if warn is over 1, warn + * about every problem; if warn is at least 1, warn only if we can't get + * enough signatures; if warn is negative, log nothing at all. */ +int +networkstatus_check_consensus_signature(networkstatus_t *consensus, + int warn) +{ + int n_good = 0; + int n_missing_key = 0, n_dl_failed_key = 0; + int n_bad = 0; + int n_unknown = 0; + int n_no_signature = 0; + int n_v3_authorities = get_n_authorities(V3_DIRINFO); + int n_required = n_v3_authorities/2 + 1; + smartlist_t *list_good = smartlist_new(); + smartlist_t *list_no_signature = smartlist_new(); + smartlist_t *need_certs_from = smartlist_new(); + smartlist_t *unrecognized = smartlist_new(); + smartlist_t *missing_authorities = smartlist_new(); + int severity; + time_t now = time(NULL); + + tor_assert(consensus->type == NS_TYPE_CONSENSUS); + + SMARTLIST_FOREACH_BEGIN(consensus->voters, networkstatus_voter_info_t *, + voter) { + int good_here = 0; + int bad_here = 0; + int unknown_here = 0; + int missing_key_here = 0, dl_failed_key_here = 0; + SMARTLIST_FOREACH_BEGIN(voter->sigs, document_signature_t *, sig) { + if (!sig->good_signature && !sig->bad_signature && + sig->signature) { + /* we can try to check the signature. */ + int is_v3_auth = trusteddirserver_get_by_v3_auth_digest( + sig->identity_digest) != NULL; + authority_cert_t *cert = + authority_cert_get_by_digests(sig->identity_digest, + sig->signing_key_digest); + tor_assert(tor_memeq(sig->identity_digest, voter->identity_digest, + DIGEST_LEN)); + + if (!is_v3_auth) { + smartlist_add(unrecognized, voter); + ++unknown_here; + continue; + } else if (!cert || cert->expires < now) { + smartlist_add(need_certs_from, voter); + ++missing_key_here; + if (authority_cert_dl_looks_uncertain(sig->identity_digest)) + ++dl_failed_key_here; + continue; + } + if (networkstatus_check_document_signature(consensus, sig, cert) < 0) { + smartlist_add(need_certs_from, voter); + ++missing_key_here; + if (authority_cert_dl_looks_uncertain(sig->identity_digest)) + ++dl_failed_key_here; + continue; + } + } + if (sig->good_signature) + ++good_here; + else if (sig->bad_signature) + ++bad_here; + } SMARTLIST_FOREACH_END(sig); + + if (good_here) { + ++n_good; + smartlist_add(list_good, voter->nickname); + } else if (bad_here) { + ++n_bad; + } else if (missing_key_here) { + ++n_missing_key; + if (dl_failed_key_here) + ++n_dl_failed_key; + } else if (unknown_here) { + ++n_unknown; + } else { + ++n_no_signature; + smartlist_add(list_no_signature, voter->nickname); + } + } SMARTLIST_FOREACH_END(voter); + + /* Now see whether we're missing any voters entirely. */ + SMARTLIST_FOREACH(router_get_trusted_dir_servers(), + dir_server_t *, ds, + { + if ((ds->type & V3_DIRINFO) && + !networkstatus_get_voter_by_id(consensus, ds->v3_identity_digest)) + smartlist_add(missing_authorities, ds); + }); + + if (warn > 1 || (warn >= 0 && + (n_good + n_missing_key - n_dl_failed_key < n_required))) { + severity = LOG_WARN; + } else { + severity = LOG_INFO; + } + + if (warn >= 0) { + SMARTLIST_FOREACH(unrecognized, networkstatus_voter_info_t *, voter, + { + tor_log(severity, LD_DIR, "Consensus includes unrecognized authority " + "'%s' at %s:%d (contact %s; identity %s)", + voter->nickname, voter->address, (int)voter->dir_port, + voter->contact?voter->contact:"n/a", + hex_str(voter->identity_digest, DIGEST_LEN)); + }); + SMARTLIST_FOREACH(need_certs_from, networkstatus_voter_info_t *, voter, + { + tor_log(severity, LD_DIR, "Looks like we need to download a new " + "certificate from authority '%s' at %s:%d (contact %s; " + "identity %s)", + voter->nickname, voter->address, (int)voter->dir_port, + voter->contact?voter->contact:"n/a", + hex_str(voter->identity_digest, DIGEST_LEN)); + }); + SMARTLIST_FOREACH(missing_authorities, dir_server_t *, ds, + { + tor_log(severity, LD_DIR, "Consensus does not include configured " + "authority '%s' at %s:%d (identity %s)", + ds->nickname, ds->address, (int)ds->dir_port, + hex_str(ds->v3_identity_digest, DIGEST_LEN)); + }); + { + char *joined; + smartlist_t *sl = smartlist_new(); + char *tmp = smartlist_join_strings(list_good, " ", 0, NULL); + smartlist_add_asprintf(sl, + "A consensus needs %d good signatures from recognized " + "authorities for us to accept it. This one has %d (%s).", + n_required, n_good, tmp); + tor_free(tmp); + if (n_no_signature) { + tmp = smartlist_join_strings(list_no_signature, " ", 0, NULL); + smartlist_add_asprintf(sl, + "%d (%s) of the authorities we know didn't sign it.", + n_no_signature, tmp); + tor_free(tmp); + } + if (n_unknown) { + smartlist_add_asprintf(sl, + "It has %d signatures from authorities we don't " + "recognize.", n_unknown); + } + if (n_bad) { + smartlist_add_asprintf(sl, "%d of the signatures on it didn't verify " + "correctly.", n_bad); + } + if (n_missing_key) { + smartlist_add_asprintf(sl, + "We were unable to check %d of the signatures, " + "because we were missing the keys.", n_missing_key); + } + joined = smartlist_join_strings(sl, " ", 0, NULL); + tor_log(severity, LD_DIR, "%s", joined); + tor_free(joined); + SMARTLIST_FOREACH(sl, char *, c, tor_free(c)); + smartlist_free(sl); + } + } + + smartlist_free(list_good); + smartlist_free(list_no_signature); + smartlist_free(unrecognized); + smartlist_free(need_certs_from); + smartlist_free(missing_authorities); + + if (n_good == n_v3_authorities) + return 1; + else if (n_good >= n_required) + return 0; + else if (n_good + n_missing_key >= n_required) + return -1; + else + return -2; +} + +/** Helper: return a newly allocated string containing the name of the filename + * where we plan to cache the network status with the given identity digest. */ +char * +networkstatus_get_cache_filename(const char *identity_digest) +{ + char fp[HEX_DIGEST_LEN+1]; + base16_encode(fp, HEX_DIGEST_LEN+1, identity_digest, DIGEST_LEN); + return get_datadir_fname2("cached-status", fp); +} + +/** How far in the future do we allow a network-status to get before removing + * it? (seconds) */ +#define NETWORKSTATUS_ALLOW_SKEW (24*60*60) + +/** Helper for bsearching a list of routerstatus_t pointers: compare a + * digest in the key to the identity digest of a routerstatus_t. */ +int +compare_digest_to_routerstatus_entry(const void *_key, const void **_member) +{ + const char *key = _key; + const routerstatus_t *rs = *_member; + return tor_memcmp(key, rs->identity_digest, DIGEST_LEN); +} + +/** Helper for bsearching a list of routerstatus_t pointers: compare a + * digest in the key to the identity digest of a routerstatus_t. */ +int +compare_digest_to_vote_routerstatus_entry(const void *_key, + const void **_member) +{ + const char *key = _key; + const vote_routerstatus_t *vrs = *_member; + return tor_memcmp(key, vrs->status.identity_digest, DIGEST_LEN); +} + +/** As networkstatus_find_entry, but do not return a const pointer */ +routerstatus_t * +networkstatus_vote_find_mutable_entry(networkstatus_t *ns, const char *digest) +{ + return smartlist_bsearch(ns->routerstatus_list, digest, + compare_digest_to_routerstatus_entry); +} + +/** Return the entry in ns for the identity digest digest, or + * NULL if none was found. */ +const routerstatus_t * +networkstatus_vote_find_entry(networkstatus_t *ns, const char *digest) +{ + return networkstatus_vote_find_mutable_entry(ns, digest); +} + +/*XXXX MOVE make this static once functions are moved into this file. */ +/** Search the routerstatuses in ns for one whose identity digest is + * digest. Return value and set *found_out as for + * smartlist_bsearch_idx(). */ +int +networkstatus_vote_find_entry_idx(networkstatus_t *ns, + const char *digest, int *found_out) +{ + return smartlist_bsearch_idx(ns->routerstatus_list, digest, + compare_digest_to_routerstatus_entry, + found_out); +} + +/** As router_get_consensus_status_by_descriptor_digest, but does not return + * a const pointer. */ +routerstatus_t * +router_get_mutable_consensus_status_by_descriptor_digest( + networkstatus_t *consensus, + const char *digest) +{ + if (!consensus) + consensus = current_consensus; + if (!consensus) + return NULL; + if (!consensus->desc_digest_map) { + digestmap_t *m = consensus->desc_digest_map = digestmap_new(); + SMARTLIST_FOREACH(consensus->routerstatus_list, + routerstatus_t *, rs, + { + digestmap_set(m, rs->descriptor_digest, rs); + }); + } + return digestmap_get(consensus->desc_digest_map, digest); +} + +/** Return the consensus view of the status of the router whose current + * descriptor digest in consensus is digest, or NULL if + * no such router is known. */ +const routerstatus_t * +router_get_consensus_status_by_descriptor_digest(networkstatus_t *consensus, + const char *digest) +{ + return router_get_mutable_consensus_status_by_descriptor_digest( + consensus, digest); +} + +/** Given the digest of a router descriptor, return its current download + * status, or NULL if the digest is unrecognized. */ +download_status_t * +router_get_dl_status_by_descriptor_digest(const char *d) +{ + routerstatus_t *rs; + if (!current_ns_consensus) + return NULL; + if ((rs = router_get_mutable_consensus_status_by_descriptor_digest( + current_ns_consensus, d))) + return &rs->dl_status; + + return NULL; +} + +/** As router_get_consensus_status_by_id, but do not return a const pointer */ +routerstatus_t * +router_get_mutable_consensus_status_by_id(const char *digest) +{ + if (!current_consensus) + return NULL; + return smartlist_bsearch(current_consensus->routerstatus_list, digest, + compare_digest_to_routerstatus_entry); +} + +/** Return the consensus view of the status of the router whose identity + * digest is digest, or NULL if we don't know about any such router. */ +const routerstatus_t * +router_get_consensus_status_by_id(const char *digest) +{ + return router_get_mutable_consensus_status_by_id(digest); +} + +/** Given a nickname (possibly verbose, possibly a hexadecimal digest), return + * the corresponding routerstatus_t, or NULL if none exists. Warn the + * user if warn_if_unnamed is set, and they have specified a router by + * nickname, but the Named flag isn't set for that router. */ +const routerstatus_t * +router_get_consensus_status_by_nickname(const char *nickname, + int warn_if_unnamed) +{ + const node_t *node = node_get_by_nickname(nickname, warn_if_unnamed); + if (node) + return node->rs; + else + return NULL; +} + +/** Return the identity digest that's mapped to officially by + * nickname. */ +const char * +networkstatus_get_router_digest_by_nickname(const char *nickname) +{ + if (!named_server_map) + return NULL; + return strmap_get_lc(named_server_map, nickname); +} + +/** Return true iff nickname is disallowed from being the nickname + * of any server. */ +int +networkstatus_nickname_is_unnamed(const char *nickname) +{ + if (!unnamed_server_map) + return 0; + return strmap_get_lc(unnamed_server_map, nickname) != NULL; +} + +/** How frequently do directory authorities re-download fresh networkstatus + * documents? */ +#define AUTHORITY_NS_CACHE_INTERVAL (10*60) + +/** How frequently do non-authority directory caches re-download fresh + * networkstatus documents? */ +#define NONAUTHORITY_NS_CACHE_INTERVAL (60*60) + +/** Return true iff, given the options listed in options, flavor + * is the flavor of a consensus networkstatus that we would like to fetch. */ +static int +we_want_to_fetch_flavor(const or_options_t *options, int flavor) +{ + if (flavor < 0 || flavor > N_CONSENSUS_FLAVORS) { + /* This flavor is crazy; we don't want it */ + /*XXXX handle unrecognized flavors later */ + return 0; + } + if (authdir_mode_v3(options) || directory_caches_dir_info(options)) { + /* We want to serve all flavors to others, regardless if we would use + * it ourselves. */ + return 1; + } + if (options->FetchUselessDescriptors) { + /* In order to get all descriptors, we need to fetch all consensuses. */ + return 1; + } + /* Otherwise, we want the flavor only if we want to use it to build + * circuits. */ + return flavor == usable_consensus_flavor(); +} + +/** How long will we hang onto a possibly live consensus for which we're + * fetching certs before we check whether there is a better one? */ +#define DELAY_WHILE_FETCHING_CERTS (20*60) + +/** If we want to download a fresh consensus, launch a new download as + * appropriate. */ +static void +update_consensus_networkstatus_downloads(time_t now) +{ + int i; + const or_options_t *options = get_options(); + + for (i=0; i < N_CONSENSUS_FLAVORS; ++i) { + /* XXXX need some way to download unknown flavors if we are caching. */ + const char *resource; + consensus_waiting_for_certs_t *waiting; + networkstatus_t *c; + + if (! we_want_to_fetch_flavor(options, i)) + continue; + + c = networkstatus_get_latest_consensus_by_flavor(i); + if (! (c && c->valid_after <= now && now <= c->valid_until)) { + /* No live consensus? Get one now!*/ + time_to_download_next_consensus[i] = now; + } + + if (time_to_download_next_consensus[i] > now) + continue; /* Wait until the current consensus is older. */ + + resource = networkstatus_get_flavor_name(i); + + if (!download_status_is_ready(&consensus_dl_status[i], now, + options->TestingConsensusMaxDownloadTries)) + continue; /* We failed downloading a consensus too recently. */ + if (connection_dir_get_by_purpose_and_resource( + DIR_PURPOSE_FETCH_CONSENSUS, resource)) + continue; /* There's an in-progress download.*/ + + waiting = &consensus_waiting_for_certs[i]; + if (waiting->consensus) { + /* XXXX make sure this doesn't delay sane downloads. */ + if (waiting->set_at + DELAY_WHILE_FETCHING_CERTS > now) { + continue; /* We're still getting certs for this one. */ + } else { + if (!waiting->dl_failed) { + download_status_failed(&consensus_dl_status[i], 0); + waiting->dl_failed=1; + } + } + } + + log_info(LD_DIR, "Launching %s networkstatus consensus download.", + networkstatus_get_flavor_name(i)); + + directory_get_from_dirserver(DIR_PURPOSE_FETCH_CONSENSUS, + ROUTER_PURPOSE_GENERAL, resource, + PDS_RETRY_IF_NO_SERVERS); + } +} + +/** Called when an attempt to download a consensus fails: note that the + * failure occurred, and possibly retry. */ +void +networkstatus_consensus_download_failed(int status_code, const char *flavname) +{ + int flav = networkstatus_parse_flavor_name(flavname); + if (flav >= 0) { + tor_assert(flav < N_CONSENSUS_FLAVORS); + /* XXXX handle unrecognized flavors */ + download_status_failed(&consensus_dl_status[flav], status_code); + /* Retry immediately, if appropriate. */ + update_consensus_networkstatus_downloads(time(NULL)); + } +} + +/** How long do we (as a cache) wait after a consensus becomes non-fresh + * before trying to fetch another? */ +#define CONSENSUS_MIN_SECONDS_BEFORE_CACHING 120 + +/** Update the time at which we'll consider replacing the current + * consensus of flavor flav */ +static void +update_consensus_networkstatus_fetch_time_impl(time_t now, int flav) +{ + const or_options_t *options = get_options(); + networkstatus_t *c = networkstatus_get_latest_consensus_by_flavor(flav); + const char *flavor = networkstatus_get_flavor_name(flav); + if (! we_want_to_fetch_flavor(get_options(), flav)) + return; + + if (c && c->valid_after <= now && now <= c->valid_until) { + long dl_interval; + long interval = c->fresh_until - c->valid_after; + long min_sec_before_caching = CONSENSUS_MIN_SECONDS_BEFORE_CACHING; + time_t start; + + if (min_sec_before_caching > interval/16) { + /* Usually we allow 2-minutes slop factor in case clocks get + desynchronized a little. If we're on a private network with + a crazy-fast voting interval, though, 2 minutes may be too + much. */ + min_sec_before_caching = interval/16; + } + + if (directory_fetches_dir_info_early(options)) { + /* We want to cache the next one at some point after this one + * is no longer fresh... */ + start = c->fresh_until + min_sec_before_caching; + /* Some clients may need the consensus sooner than others. */ + if (options->FetchDirInfoExtraEarly || authdir_mode_v3(options)) { + dl_interval = 60; + if (min_sec_before_caching + dl_interval > interval) + dl_interval = interval/2; + } else { + /* But only in the first half-interval after that. */ + dl_interval = interval/2; + } + } else { + /* We're an ordinary client or a bridge. Give all the caches enough + * time to download the consensus. */ + start = c->fresh_until + (interval*3)/4; + /* But download the next one well before this one is expired. */ + dl_interval = ((c->valid_until - start) * 7 )/ 8; + + /* If we're a bridge user, make use of the numbers we just computed + * to choose the rest of the interval *after* them. */ + if (directory_fetches_dir_info_later(options)) { + /* Give all the *clients* enough time to download the consensus. */ + start = start + dl_interval + min_sec_before_caching; + /* But try to get it before ours actually expires. */ + dl_interval = (c->valid_until - start) - min_sec_before_caching; + } + } + if (dl_interval < 1) + dl_interval = 1; + /* We must not try to replace c while it's still fresh: */ + tor_assert(c->fresh_until < start); + /* We must download the next one before c is invalid: */ + tor_assert(start+dl_interval < c->valid_until); + time_to_download_next_consensus[flav] = + start + crypto_rand_int((int)dl_interval); + { + char tbuf1[ISO_TIME_LEN+1]; + char tbuf2[ISO_TIME_LEN+1]; + char tbuf3[ISO_TIME_LEN+1]; + format_local_iso_time(tbuf1, c->fresh_until); + format_local_iso_time(tbuf2, c->valid_until); + format_local_iso_time(tbuf3, time_to_download_next_consensus[flav]); + log_info(LD_DIR, "Live %s consensus %s the most recent until %s and " + "will expire at %s; fetching the next one at %s.", + flavor, (c->fresh_until > now) ? "will be" : "was", + tbuf1, tbuf2, tbuf3); + } + } else { + time_to_download_next_consensus[flav] = now; + log_info(LD_DIR, "No live %s consensus; we should fetch one immediately.", + flavor); + } +} + +/** Update the time at which we'll consider replacing the current + * consensus of flavor 'flavor' */ +void +update_consensus_networkstatus_fetch_time(time_t now) +{ + int i; + for (i = 0; i < N_CONSENSUS_FLAVORS; ++i) { + if (we_want_to_fetch_flavor(get_options(), i)) + update_consensus_networkstatus_fetch_time_impl(now, i); + } +} + +/** Return 1 if there's a reason we shouldn't try any directory + * fetches yet (e.g. we demand bridges and none are yet known). + * Else return 0. */ +int +should_delay_dir_fetches(const or_options_t *options) +{ + if (options->UseBridges && !any_bridge_descriptors_known()) { + log_info(LD_DIR, "delaying dir fetches (no running bridges known)"); + return 1; + } + return 0; +} + +/** Launch requests for networkstatus documents and authority certificates as + * appropriate. */ +void +update_networkstatus_downloads(time_t now) +{ + const or_options_t *options = get_options(); + if (should_delay_dir_fetches(options)) + return; + update_consensus_networkstatus_downloads(now); + update_certificate_downloads(now); +} + +/** Launch requests as appropriate for missing directory authority + * certificates. */ +void +update_certificate_downloads(time_t now) +{ + int i; + for (i = 0; i < N_CONSENSUS_FLAVORS; ++i) { + if (consensus_waiting_for_certs[i].consensus) + authority_certs_fetch_missing(consensus_waiting_for_certs[i].consensus, + now); + } + + if (current_ns_consensus) + authority_certs_fetch_missing(current_ns_consensus, now); + if (current_md_consensus) + authority_certs_fetch_missing(current_md_consensus, now); +} + +/** Return 1 if we have a consensus but we don't have enough certificates + * to start using it yet. */ +int +consensus_is_waiting_for_certs(void) +{ + return consensus_waiting_for_certs[usable_consensus_flavor()].consensus + ? 1 : 0; +} + +/** Return the most recent consensus that we have downloaded, or NULL if we + * don't have one. */ +networkstatus_t * +networkstatus_get_latest_consensus(void) +{ + return current_consensus; +} + +/** Return the latest consensus we have whose flavor matches f, or NULL + * if we don't have one. */ +networkstatus_t * +networkstatus_get_latest_consensus_by_flavor(consensus_flavor_t f) +{ + if (f == FLAV_NS) + return current_ns_consensus; + else if (f == FLAV_MICRODESC) + return current_md_consensus; + else { + tor_assert(0); + return NULL; + } +} + +/** Return the most recent consensus that we have downloaded, or NULL if it is + * no longer live. */ +networkstatus_t * +networkstatus_get_live_consensus(time_t now) +{ + if (current_consensus && + current_consensus->valid_after <= now && + now <= current_consensus->valid_until) + return current_consensus; + else + return NULL; +} + +/* XXXX remove this in favor of get_live_consensus. But actually, + * leave something like it for bridge users, who need to not totally + * lose if they spend a while fetching a new consensus. */ +/** As networkstatus_get_live_consensus(), but is way more tolerant of expired + * consensuses. */ +networkstatus_t * +networkstatus_get_reasonably_live_consensus(time_t now, int flavor) +{ +#define REASONABLY_LIVE_TIME (24*60*60) + networkstatus_t *consensus = + networkstatus_get_latest_consensus_by_flavor(flavor); + if (consensus && + consensus->valid_after <= now && + now <= consensus->valid_until+REASONABLY_LIVE_TIME) + return consensus; + else + return NULL; +} + +/** Given two router status entries for the same router identity, return 1 if + * if the contents have changed between them. Otherwise, return 0. */ +static int +routerstatus_has_changed(const routerstatus_t *a, const routerstatus_t *b) +{ + tor_assert(tor_memeq(a->identity_digest, b->identity_digest, DIGEST_LEN)); + + return strcmp(a->nickname, b->nickname) || + fast_memneq(a->descriptor_digest, b->descriptor_digest, DIGEST_LEN) || + a->addr != b->addr || + a->or_port != b->or_port || + a->dir_port != b->dir_port || + a->is_authority != b->is_authority || + a->is_exit != b->is_exit || + a->is_stable != b->is_stable || + a->is_fast != b->is_fast || + a->is_flagged_running != b->is_flagged_running || + a->is_named != b->is_named || + a->is_unnamed != b->is_unnamed || + a->is_valid != b->is_valid || + a->is_possible_guard != b->is_possible_guard || + a->is_bad_exit != b->is_bad_exit || + a->is_bad_directory != b->is_bad_directory || + a->is_hs_dir != b->is_hs_dir || + a->version_known != b->version_known; +} + +/** Notify controllers of any router status entries that changed between + * old_c and new_c. */ +static void +notify_control_networkstatus_changed(const networkstatus_t *old_c, + const networkstatus_t *new_c) +{ + smartlist_t *changed; + if (old_c == new_c) + return; + + /* tell the controller exactly which relays are still listed, as well + * as what they're listed as */ + control_event_newconsensus(new_c); + + if (!control_event_is_interesting(EVENT_NS)) + return; + + if (!old_c) { + control_event_networkstatus_changed(new_c->routerstatus_list); + return; + } + changed = smartlist_new(); + + SMARTLIST_FOREACH_JOIN( + old_c->routerstatus_list, const routerstatus_t *, rs_old, + new_c->routerstatus_list, const routerstatus_t *, rs_new, + tor_memcmp(rs_old->identity_digest, + rs_new->identity_digest, DIGEST_LEN), + smartlist_add(changed, (void*) rs_new)) { + if (routerstatus_has_changed(rs_old, rs_new)) + smartlist_add(changed, (void*)rs_new); + } SMARTLIST_FOREACH_JOIN_END(rs_old, rs_new); + + control_event_networkstatus_changed(changed); + smartlist_free(changed); +} + +/** Copy all the ancillary information (like router download status and so on) + * from old_c to new_c. */ +static void +networkstatus_copy_old_consensus_info(networkstatus_t *new_c, + const networkstatus_t *old_c) +{ + if (old_c == new_c) + return; + if (!old_c || !smartlist_len(old_c->routerstatus_list)) + return; + + SMARTLIST_FOREACH_JOIN(old_c->routerstatus_list, routerstatus_t *, rs_old, + new_c->routerstatus_list, routerstatus_t *, rs_new, + tor_memcmp(rs_old->identity_digest, + rs_new->identity_digest, DIGEST_LEN), + STMT_NIL) { + /* Okay, so we're looking at the same identity. */ + rs_new->last_dir_503_at = rs_old->last_dir_503_at; + + if (tor_memeq(rs_old->descriptor_digest, rs_new->descriptor_digest, + DIGEST_LEN)) { + /* And the same descriptor too! */ + memcpy(&rs_new->dl_status, &rs_old->dl_status,sizeof(download_status_t)); + } + } SMARTLIST_FOREACH_JOIN_END(rs_old, rs_new); +} + +/** Try to replace the current cached v3 networkstatus with the one in + * consensus. If we don't have enough certificates to validate it, + * store it in consensus_waiting_for_certs and launch a certificate fetch. + * + * If flags & NSSET_FROM_CACHE, this networkstatus has come from the disk + * cache. If flags & NSSET_WAS_WAITING_FOR_CERTS, this networkstatus was + * already received, but we were waiting for certificates on it. If flags & + * NSSET_DONT_DOWNLOAD_CERTS, do not launch certificate downloads as needed. + * If flags & NSSET_ACCEPT_OBSOLETE, then we should be willing to take this + * consensus, even if it comes from many days in the past. + * + * Return 0 on success, <0 on failure. On failure, caller should increment + * the failure count as appropriate. + * + * We return -1 for mild failures that don't need to be reported to the + * user, and -2 for more serious problems. + */ +int +networkstatus_set_current_consensus(const char *consensus, + const char *flavor, + unsigned flags) +{ + networkstatus_t *c=NULL; + int r, result = -1; + time_t now = time(NULL); + const or_options_t *options = get_options(); + char *unverified_fname = NULL, *consensus_fname = NULL; + int flav = networkstatus_parse_flavor_name(flavor); + const unsigned from_cache = flags & NSSET_FROM_CACHE; + const unsigned was_waiting_for_certs = flags & NSSET_WAS_WAITING_FOR_CERTS; + const unsigned dl_certs = !(flags & NSSET_DONT_DOWNLOAD_CERTS); + const unsigned accept_obsolete = flags & NSSET_ACCEPT_OBSOLETE; + const unsigned require_flavor = flags & NSSET_REQUIRE_FLAVOR; + const digests_t *current_digests = NULL; + consensus_waiting_for_certs_t *waiting = NULL; + time_t current_valid_after = 0; + int free_consensus = 1; /* Free 'c' at the end of the function */ + int old_ewma_enabled; + + if (flav < 0) { + /* XXXX we don't handle unrecognized flavors yet. */ + log_warn(LD_BUG, "Unrecognized consensus flavor %s", flavor); + return -2; + } + + /* Make sure it's parseable. */ + c = networkstatus_parse_vote_from_string(consensus, NULL, NS_TYPE_CONSENSUS); + if (!c) { + log_warn(LD_DIR, "Unable to parse networkstatus consensus"); + result = -2; + goto done; + } + + if ((int)c->flavor != flav) { + /* This wasn't the flavor we thought we were getting. */ + if (require_flavor) { + log_warn(LD_DIR, "Got consensus with unexpected flavor %s (wanted %s)", + networkstatus_get_flavor_name(c->flavor), flavor); + goto done; + } + flav = c->flavor; + flavor = networkstatus_get_flavor_name(flav); + } + + if (flav != usable_consensus_flavor() && + !directory_caches_dir_info(options)) { + /* This consensus is totally boring to us: we won't use it, and we won't + * serve it. Drop it. */ + goto done; + } + + if (from_cache && !accept_obsolete && + c->valid_until < now-OLD_ROUTER_DESC_MAX_AGE) { + log_info(LD_DIR, "Loaded an expired consensus. Discarding."); + goto done; + } + + if (!strcmp(flavor, "ns")) { + consensus_fname = get_datadir_fname("cached-consensus"); + unverified_fname = get_datadir_fname("unverified-consensus"); + if (current_ns_consensus) { + current_digests = ¤t_ns_consensus->digests; + current_valid_after = current_ns_consensus->valid_after; + } + } else if (!strcmp(flavor, "microdesc")) { + consensus_fname = get_datadir_fname("cached-microdesc-consensus"); + unverified_fname = get_datadir_fname("unverified-microdesc-consensus"); + if (current_md_consensus) { + current_digests = ¤t_md_consensus->digests; + current_valid_after = current_md_consensus->valid_after; + } + } else { + cached_dir_t *cur; + char buf[128]; + tor_snprintf(buf, sizeof(buf), "cached-%s-consensus", flavor); + consensus_fname = get_datadir_fname(buf); + tor_snprintf(buf, sizeof(buf), "unverified-%s-consensus", flavor); + unverified_fname = get_datadir_fname(buf); + cur = dirserv_get_consensus(flavor); + if (cur) { + current_digests = &cur->digests; + current_valid_after = cur->published; + } + } + + if (current_digests && + tor_memeq(&c->digests, current_digests, sizeof(c->digests))) { + /* We already have this one. That's a failure. */ + log_info(LD_DIR, "Got a %s consensus we already have", flavor); + goto done; + } + + if (current_valid_after && c->valid_after <= current_valid_after) { + /* We have a newer one. There's no point in accepting this one, + * even if it's great. */ + log_info(LD_DIR, "Got a %s consensus at least as old as the one we have", + flavor); + goto done; + } + + /* Make sure it's signed enough. */ + if ((r=networkstatus_check_consensus_signature(c, 1))<0) { + if (r == -1) { + /* Okay, so it _might_ be signed enough if we get more certificates. */ + if (!was_waiting_for_certs) { + log_info(LD_DIR, + "Not enough certificates to check networkstatus consensus"); + } + if (!current_valid_after || + c->valid_after > current_valid_after) { + waiting = &consensus_waiting_for_certs[flav]; + networkstatus_vote_free(waiting->consensus); + tor_free(waiting->body); + waiting->consensus = c; + free_consensus = 0; + waiting->body = tor_strdup(consensus); + waiting->set_at = now; + waiting->dl_failed = 0; + if (!from_cache) { + write_str_to_file(unverified_fname, consensus, 0); + } + if (dl_certs) + authority_certs_fetch_missing(c, now); + /* This case is not a success or a failure until we get the certs + * or fail to get the certs. */ + result = 0; + } else { + /* Even if we had enough signatures, we'd never use this as the + * latest consensus. */ + if (was_waiting_for_certs && from_cache) + unlink(unverified_fname); + } + goto done; + } else { + /* This can never be signed enough: Kill it. */ + if (!was_waiting_for_certs) { + log_warn(LD_DIR, "Not enough good signatures on networkstatus " + "consensus"); + result = -2; + } + if (was_waiting_for_certs && (r < -1) && from_cache) + unlink(unverified_fname); + goto done; + } + } + + if (!from_cache && flav == usable_consensus_flavor()) + control_event_client_status(LOG_NOTICE, "CONSENSUS_ARRIVED"); + + /* Are we missing any certificates at all? */ + if (r != 1 && dl_certs) + authority_certs_fetch_missing(c, now); + + if (flav == usable_consensus_flavor()) { + notify_control_networkstatus_changed(current_consensus, c); + } + if (flav == FLAV_NS) { + if (current_ns_consensus) { + networkstatus_copy_old_consensus_info(c, current_ns_consensus); + networkstatus_vote_free(current_ns_consensus); + /* Defensive programming : we should set current_consensus very soon, + * but we're about to call some stuff in the meantime, and leaving this + * dangling pointer around has proven to be trouble. */ + current_ns_consensus = NULL; + } + current_ns_consensus = c; + free_consensus = 0; /* avoid free */ + } else if (flav == FLAV_MICRODESC) { + if (current_md_consensus) { + networkstatus_copy_old_consensus_info(c, current_md_consensus); + networkstatus_vote_free(current_md_consensus); + /* more defensive programming */ + current_md_consensus = NULL; + } + current_md_consensus = c; + free_consensus = 0; /* avoid free */ + } + + waiting = &consensus_waiting_for_certs[flav]; + if (waiting->consensus && + waiting->consensus->valid_after <= c->valid_after) { + networkstatus_vote_free(waiting->consensus); + waiting->consensus = NULL; + if (consensus != waiting->body) + tor_free(waiting->body); + else + waiting->body = NULL; + waiting->set_at = 0; + waiting->dl_failed = 0; + unlink(unverified_fname); + } + + /* Reset the failure count only if this consensus is actually valid. */ + if (c->valid_after <= now && now <= c->valid_until) { + download_status_reset(&consensus_dl_status[flav]); + } else { + if (!from_cache) + download_status_failed(&consensus_dl_status[flav], 0); + } + + if (flav == usable_consensus_flavor()) { + /* XXXXNM Microdescs: needs a non-ns variant. ???? NM*/ + update_consensus_networkstatus_fetch_time(now); + + nodelist_set_consensus(current_consensus); + + dirvote_recalculate_timing(options, now); + routerstatus_list_update_named_server_map(); + + /* Update ewma and adjust policy if needed; first cache the old value */ + old_ewma_enabled = cell_ewma_enabled(); + /* Change the cell EWMA settings */ + cell_ewma_set_scale_factor(options, networkstatus_get_latest_consensus()); + /* If we just enabled ewma, set the cmux policy on all active channels */ + if (cell_ewma_enabled() && !old_ewma_enabled) { + channel_set_cmux_policy_everywhere(&ewma_policy); + } else if (!cell_ewma_enabled() && old_ewma_enabled) { + /* Turn it off everywhere */ + channel_set_cmux_policy_everywhere(NULL); + } + + /* XXXX024 this call might be unnecessary here: can changing the + * current consensus really alter our view of any OR's rate limits? */ + connection_or_update_token_buckets(get_connection_array(), options); + + circuit_build_times_new_consensus_params(get_circuit_build_times_mutable(), + current_consensus); + } + + if (directory_caches_dir_info(options)) { + dirserv_set_cached_consensus_networkstatus(consensus, + flavor, + &c->digests, + c->valid_after); + } + + if (!from_cache) { + write_str_to_file(consensus_fname, consensus, 0); + } + +/** If a consensus appears more than this many seconds before its declared + * valid-after time, declare that our clock is skewed. */ +#define EARLY_CONSENSUS_NOTICE_SKEW 60 + + if (now < c->valid_after - EARLY_CONSENSUS_NOTICE_SKEW) { + char tbuf[ISO_TIME_LEN+1]; + char dbuf[64]; + long delta = now - c->valid_after; + format_iso_time(tbuf, c->valid_after); + format_time_interval(dbuf, sizeof(dbuf), delta); + log_warn(LD_GENERAL, "Our clock is %s behind the time published in the " + "consensus network status document (%s UTC). Tor needs an " + "accurate clock to work correctly. Please check your time and " + "date settings!", dbuf, tbuf); + control_event_general_status(LOG_WARN, + "CLOCK_SKEW MIN_SKEW=%ld SOURCE=CONSENSUS", delta); + } + + router_dir_info_changed(); + + result = 0; + done: + if (free_consensus) + networkstatus_vote_free(c); + tor_free(consensus_fname); + tor_free(unverified_fname); + return result; +} + +/** Called when we have gotten more certificates: see whether we can + * now verify a pending consensus. */ +void +networkstatus_note_certs_arrived(void) +{ + int i; + for (i=0; iconsensus) + continue; + if (networkstatus_check_consensus_signature(waiting->consensus, 0)>=0) { + char *waiting_body = waiting->body; + if (!networkstatus_set_current_consensus( + waiting_body, + networkstatus_get_flavor_name(i), + NSSET_WAS_WAITING_FOR_CERTS)) { + tor_free(waiting_body); + } + } + } +} + +/** If the network-status list has changed since the last time we called this + * function, update the status of every routerinfo from the network-status + * list. If dir_version is 2, it's a v2 networkstatus that changed. + * If dir_version is 3, it's a v3 consensus that changed. + */ +void +routers_update_all_from_networkstatus(time_t now, int dir_version) +{ + routerlist_t *rl = router_get_routerlist(); + networkstatus_t *consensus = networkstatus_get_reasonably_live_consensus(now, + FLAV_NS); + + if (!consensus || dir_version < 3) /* nothing more we should do */ + return; + + /* calls router_dir_info_changed() when it's done -- more routers + * might be up or down now, which might affect whether there's enough + * directory info. */ + routers_update_status_from_consensus_networkstatus(rl->routers, 0); + + SMARTLIST_FOREACH(rl->routers, routerinfo_t *, ri, + ri->cache_info.routerlist_index = ri_sl_idx); + if (rl->old_routers) + signed_descs_update_status_from_consensus_networkstatus(rl->old_routers); + + if (!have_warned_about_old_version) { + int is_server = server_mode(get_options()); + version_status_t status; + const char *recommended = is_server ? + consensus->server_versions : consensus->client_versions; + status = tor_version_is_obsolete(VERSION, recommended); + + if (status == VS_RECOMMENDED) { + log_info(LD_GENERAL, "The directory authorities say my version is ok."); + } else if (status == VS_EMPTY) { + log_info(LD_GENERAL, + "The directory authorities don't recommend any versions."); + } else if (status == VS_NEW || status == VS_NEW_IN_SERIES) { + if (!have_warned_about_new_version) { + log_notice(LD_GENERAL, "This version of Tor (%s) is newer than any " + "recommended version%s, according to the directory " + "authorities. Recommended versions are: %s", + VERSION, + status == VS_NEW_IN_SERIES ? " in its series" : "", + recommended); + have_warned_about_new_version = 1; + control_event_general_status(LOG_WARN, "DANGEROUS_VERSION " + "CURRENT=%s REASON=%s RECOMMENDED=\"%s\"", + VERSION, "NEW", recommended); + } + } else { + log_warn(LD_GENERAL, "Please upgrade! " + "This version of Tor (%s) is %s, according to the directory " + "authorities. Recommended versions are: %s", + VERSION, + status == VS_OLD ? "obsolete" : "not recommended", + recommended); + have_warned_about_old_version = 1; + control_event_general_status(LOG_WARN, "DANGEROUS_VERSION " + "CURRENT=%s REASON=%s RECOMMENDED=\"%s\"", + VERSION, status == VS_OLD ? "OBSOLETE" : "UNRECOMMENDED", + recommended); + } + } +} + +/** Update our view of the list of named servers from the most recently + * retrieved networkstatus consensus. */ +static void +routerstatus_list_update_named_server_map(void) +{ + if (!current_consensus) + return; + + strmap_free(named_server_map, tor_free_); + named_server_map = strmap_new(); + strmap_free(unnamed_server_map, NULL); + unnamed_server_map = strmap_new(); + SMARTLIST_FOREACH_BEGIN(current_consensus->routerstatus_list, + const routerstatus_t *, rs) { + if (rs->is_named) { + strmap_set_lc(named_server_map, rs->nickname, + tor_memdup(rs->identity_digest, DIGEST_LEN)); + } + if (rs->is_unnamed) { + strmap_set_lc(unnamed_server_map, rs->nickname, (void*)1); + } + } SMARTLIST_FOREACH_END(rs); +} + +/** Given a list routers of routerinfo_t *, update each status field + * according to our current consensus networkstatus. May re-order + * routers. */ +void +routers_update_status_from_consensus_networkstatus(smartlist_t *routers, + int reset_failures) +{ + const or_options_t *options = get_options(); + int authdir = authdir_mode_v3(options); + networkstatus_t *ns = current_consensus; + if (!ns || !smartlist_len(ns->routerstatus_list)) + return; + + routers_sort_by_identity(routers); + + SMARTLIST_FOREACH_JOIN(ns->routerstatus_list, routerstatus_t *, rs, + routers, routerinfo_t *, router, + tor_memcmp(rs->identity_digest, + router->cache_info.identity_digest, DIGEST_LEN), + { + }) { + /* Is it the same descriptor, or only the same identity? */ + if (tor_memeq(router->cache_info.signed_descriptor_digest, + rs->descriptor_digest, DIGEST_LEN)) { + if (ns->valid_until > router->cache_info.last_listed_as_valid_until) + router->cache_info.last_listed_as_valid_until = ns->valid_until; + } + + if (authdir) { + /* If we _are_ an authority, we should check whether this router + * is one that will cause us to need a reachability test. */ + routerinfo_t *old_router = + router_get_mutable_by_digest(router->cache_info.identity_digest); + if (old_router != router) { + router->needs_retest_if_added = + dirserv_should_launch_reachability_test(router, old_router); + } + } + if (reset_failures) { + download_status_reset(&rs->dl_status); + } + } SMARTLIST_FOREACH_JOIN_END(rs, router); + + router_dir_info_changed(); +} + +/** Given a list of signed_descriptor_t, update their fields (mainly, when + * they were last listed) from the most recent consensus. */ +void +signed_descs_update_status_from_consensus_networkstatus(smartlist_t *descs) +{ + networkstatus_t *ns = current_ns_consensus; + if (!ns) + return; + + if (!ns->desc_digest_map) { + char dummy[DIGEST_LEN]; + /* instantiates the digest map. */ + memset(dummy, 0, sizeof(dummy)); + router_get_consensus_status_by_descriptor_digest(ns, dummy); + } + SMARTLIST_FOREACH(descs, signed_descriptor_t *, d, + { + const routerstatus_t *rs = digestmap_get(ns->desc_digest_map, + d->signed_descriptor_digest); + if (rs) { + if (ns->valid_until > d->last_listed_as_valid_until) + d->last_listed_as_valid_until = ns->valid_until; + } + }); +} + +/** Generate networkstatus lines for a single routerstatus_t object, and + * return the result in a newly allocated string. Used only by controller + * interface (for now.) */ +char * +networkstatus_getinfo_helper_single(const routerstatus_t *rs) +{ + return routerstatus_format_entry(rs, NULL, NS_CONTROL_PORT, NULL); +} + +/** Alloc and return a string describing routerstatuses for the most + * recent info of each router we know about that is of purpose + * purpose_string. Return NULL if unrecognized purpose. + * + * Right now this function is oriented toward listing bridges (you + * shouldn't use this for general-purpose routers, since those + * should be listed from the consensus, not from the routers list). */ +char * +networkstatus_getinfo_by_purpose(const char *purpose_string, time_t now) +{ + time_t cutoff = now - ROUTER_MAX_AGE_TO_PUBLISH; + char *answer; + routerlist_t *rl = router_get_routerlist(); + smartlist_t *statuses; + uint8_t purpose = router_purpose_from_string(purpose_string); + routerstatus_t rs; + int bridge_auth = authdir_mode_bridge(get_options()); + + if (purpose == ROUTER_PURPOSE_UNKNOWN) { + log_info(LD_DIR, "Unrecognized purpose '%s' when listing router statuses.", + purpose_string); + return NULL; + } + + statuses = smartlist_new(); + SMARTLIST_FOREACH_BEGIN(rl->routers, routerinfo_t *, ri) { + node_t *node = node_get_mutable_by_id(ri->cache_info.identity_digest); + if (!node) + continue; + if (ri->cache_info.published_on < cutoff) + continue; + if (ri->purpose != purpose) + continue; + if (bridge_auth && ri->purpose == ROUTER_PURPOSE_BRIDGE) + dirserv_set_router_is_running(ri, now); + /* then generate and write out status lines for each of them */ + set_routerstatus_from_routerinfo(&rs, node, ri, now, 0, 0, 0, 0); + smartlist_add(statuses, networkstatus_getinfo_helper_single(&rs)); + } SMARTLIST_FOREACH_END(ri); + + answer = smartlist_join_strings(statuses, "", 0, NULL); + SMARTLIST_FOREACH(statuses, char *, cp, tor_free(cp)); + smartlist_free(statuses); + return answer; +} + +/** Write out router status entries for all our bridge descriptors. */ +void +networkstatus_dump_bridge_status_to_file(time_t now) +{ + char *status = networkstatus_getinfo_by_purpose("bridge", now); + const or_options_t *options = get_options(); + char *fname = NULL; + char *thresholds = NULL, *thresholds_and_status = NULL; + routerlist_t *rl = router_get_routerlist(); + dirserv_compute_bridge_flag_thresholds(rl); + thresholds = dirserv_get_flag_thresholds_line(); + tor_asprintf(&thresholds_and_status, "flag-thresholds %s\n%s", + thresholds, status); + tor_asprintf(&fname, "%s"PATH_SEPARATOR"networkstatus-bridges", + options->DataDirectory); + write_str_to_file(fname,thresholds_and_status,0); + tor_free(thresholds); + tor_free(thresholds_and_status); + tor_free(fname); + tor_free(status); +} + +/* DOCDOC get_net_param_from_list */ +static int32_t +get_net_param_from_list(smartlist_t *net_params, const char *param_name, + int32_t default_val, int32_t min_val, int32_t max_val) +{ + int32_t res = default_val; + size_t name_len = strlen(param_name); + + tor_assert(max_val > min_val); + tor_assert(min_val <= default_val); + tor_assert(max_val >= default_val); + + SMARTLIST_FOREACH_BEGIN(net_params, const char *, p) { + if (!strcmpstart(p, param_name) && p[name_len] == '=') { + int ok=0; + long v = tor_parse_long(p+name_len+1, 10, INT32_MIN, + INT32_MAX, &ok, NULL); + if (ok) { + res = (int32_t) v; + break; + } + } + } SMARTLIST_FOREACH_END(p); + + if (res < min_val) { + log_warn(LD_DIR, "Consensus parameter %s is too small. Got %d, raising to " + "%d.", param_name, res, min_val); + res = min_val; + } else if (res > max_val) { + log_warn(LD_DIR, "Consensus parameter %s is too large. Got %d, capping to " + "%d.", param_name, res, max_val); + res = max_val; + } + + return res; +} + +/** Return the value of a integer parameter from the networkstatus ns + * whose name is param_name. If ns is NULL, try loading the + * latest consensus ourselves. Return default_val if no latest + * consensus, or if it has no parameter called param_name. + * Make sure the value parsed from the consensus is at least + * min_val and at most max_val and raise/cap the parsed value + * if necessary. */ +int32_t +networkstatus_get_param(const networkstatus_t *ns, const char *param_name, + int32_t default_val, int32_t min_val, int32_t max_val) +{ + if (!ns) /* if they pass in null, go find it ourselves */ + ns = networkstatus_get_latest_consensus(); + + if (!ns || !ns->net_params) + return default_val; + + return get_net_param_from_list(ns->net_params, param_name, + default_val, min_val, max_val); +} + +/** + * Retrieve the consensus parameter that governs the + * fixed-point precision of our network balancing 'bandwidth-weights' + * (which are themselves integer consensus values). We divide them + * by this value and ensure they never exceed this value. + */ +int +networkstatus_get_weight_scale_param(networkstatus_t *ns) +{ + return networkstatus_get_param(ns, "bwweightscale", + BW_WEIGHT_SCALE, + BW_MIN_WEIGHT_SCALE, + BW_MAX_WEIGHT_SCALE); +} + +/** Return the value of a integer bw weight parameter from the networkstatus + * ns whose name is weight_name. If ns is NULL, try + * loading the latest consensus ourselves. Return default_val if no + * latest consensus, or if it has no parameter called weight_name. */ +int32_t +networkstatus_get_bw_weight(networkstatus_t *ns, const char *weight_name, + int32_t default_val) +{ + int32_t param; + int max; + if (!ns) /* if they pass in null, go find it ourselves */ + ns = networkstatus_get_latest_consensus(); + + if (!ns || !ns->weight_params) + return default_val; + + max = networkstatus_get_weight_scale_param(ns); + param = get_net_param_from_list(ns->weight_params, weight_name, + default_val, -1, + BW_MAX_WEIGHT_SCALE); + if (param > max) { + log_warn(LD_DIR, "Value of consensus weight %s was too large, capping " + "to %d", weight_name, max); + param = max; + } + return param; +} + +/** Return the name of the consensus flavor flav as used to identify + * the flavor in directory documents. */ +const char * +networkstatus_get_flavor_name(consensus_flavor_t flav) +{ + switch (flav) { + case FLAV_NS: + return "ns"; + case FLAV_MICRODESC: + return "microdesc"; + default: + tor_fragile_assert(); + return "??"; + } +} + +/** Return the consensus_flavor_t value for the flavor called flavname, + * or -1 if the flavor is not recognized. */ +int +networkstatus_parse_flavor_name(const char *flavname) +{ + if (!strcmp(flavname, "ns")) + return FLAV_NS; + else if (!strcmp(flavname, "microdesc")) + return FLAV_MICRODESC; + else + return -1; +} + +/** Return 0 if this routerstatus is obsolete, too new, isn't + * running, or otherwise not a descriptor that we would make any + * use of even if we had it. Else return 1. */ +int +client_would_use_router(const routerstatus_t *rs, time_t now, + const or_options_t *options) +{ + if (!rs->is_flagged_running && !options->FetchUselessDescriptors) { + /* If we had this router descriptor, we wouldn't even bother using it. + * But, if we want to have a complete list, fetch it anyway. */ + return 0; + } + if (rs->published_on + options->TestingEstimatedDescriptorPropagationTime + > now) { + /* Most caches probably don't have this descriptor yet. */ + return 0; + } + if (rs->published_on + OLD_ROUTER_DESC_MAX_AGE < now) { + /* We'd drop it immediately for being too old. */ + return 0; + } + return 1; +} + +/** If question is a string beginning with "ns/" in a format the + * control interface expects for a GETINFO question, set *answer to a + * newly-allocated string containing networkstatus lines for the appropriate + * ORs. Return 0 on success, -1 on unrecognized question format. */ +int +getinfo_helper_networkstatus(control_connection_t *conn, + const char *question, char **answer, + const char **errmsg) +{ + const routerstatus_t *status; + (void) conn; + + if (!current_consensus) { + *answer = tor_strdup(""); + return 0; + } + + if (!strcmp(question, "ns/all")) { + smartlist_t *statuses = smartlist_new(); + SMARTLIST_FOREACH(current_consensus->routerstatus_list, + const routerstatus_t *, rs, + { + smartlist_add(statuses, networkstatus_getinfo_helper_single(rs)); + }); + *answer = smartlist_join_strings(statuses, "", 0, NULL); + SMARTLIST_FOREACH(statuses, char *, cp, tor_free(cp)); + smartlist_free(statuses); + return 0; + } else if (!strcmpstart(question, "ns/id/")) { + char d[DIGEST_LEN]; + const char *q = question + 6; + if (*q == '$') + ++q; + + if (base16_decode(d, DIGEST_LEN, q, strlen(q))) { + *errmsg = "Data not decodeable as hex"; + return -1; + } + status = router_get_consensus_status_by_id(d); + } else if (!strcmpstart(question, "ns/name/")) { + status = router_get_consensus_status_by_nickname(question+8, 0); + } else if (!strcmpstart(question, "ns/purpose/")) { + *answer = networkstatus_getinfo_by_purpose(question+11, time(NULL)); + return *answer ? 0 : -1; + } else { + return 0; + } + + if (status) + *answer = networkstatus_getinfo_helper_single(status); + return 0; +} + +/** Free all storage held locally in this module. */ +void +networkstatus_free_all(void) +{ + int i; + networkstatus_vote_free(current_ns_consensus); + networkstatus_vote_free(current_md_consensus); + current_md_consensus = current_ns_consensus = NULL; + + for (i=0; i < N_CONSENSUS_FLAVORS; ++i) { + consensus_waiting_for_certs_t *waiting = &consensus_waiting_for_certs[i]; + if (waiting->consensus) { + networkstatus_vote_free(waiting->consensus); + waiting->consensus = NULL; + } + tor_free(waiting->body); + } + + strmap_free(named_server_map, tor_free_); + strmap_free(unnamed_server_map, NULL); +} + diff --git a/src/tor/networkstatus.h b/src/tor/networkstatus.h new file mode 100644 index 0000000..fed32ea --- /dev/null +++ b/src/tor/networkstatus.h @@ -0,0 +1,104 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file networkstatus.h + * \brief Header file for networkstatus.c. + **/ + +#ifndef TOR_NETWORKSTATUS_H +#define TOR_NETWORKSTATUS_H + +void networkstatus_reset_warnings(void); +void networkstatus_reset_download_failures(void); +int router_reload_consensus_networkstatus(void); +void routerstatus_free(routerstatus_t *rs); +void networkstatus_vote_free(networkstatus_t *ns); +networkstatus_voter_info_t *networkstatus_get_voter_by_id( + networkstatus_t *vote, + const char *identity); +int networkstatus_check_consensus_signature(networkstatus_t *consensus, + int warn); +int networkstatus_check_document_signature(const networkstatus_t *consensus, + document_signature_t *sig, + const authority_cert_t *cert); +char *networkstatus_get_cache_filename(const char *identity_digest); +int compare_digest_to_routerstatus_entry(const void *_key, + const void **_member); +int compare_digest_to_vote_routerstatus_entry(const void *_key, + const void **_member); +const routerstatus_t *networkstatus_vote_find_entry(networkstatus_t *ns, + const char *digest); +routerstatus_t *networkstatus_vote_find_mutable_entry(networkstatus_t *ns, + const char *digest); +int networkstatus_vote_find_entry_idx(networkstatus_t *ns, + const char *digest, int *found_out); +download_status_t *router_get_dl_status_by_descriptor_digest(const char *d); +const routerstatus_t *router_get_consensus_status_by_id(const char *digest); +routerstatus_t *router_get_mutable_consensus_status_by_id( + const char *digest); +const routerstatus_t *router_get_consensus_status_by_descriptor_digest( + networkstatus_t *consensus, + const char *digest); +routerstatus_t *router_get_mutable_consensus_status_by_descriptor_digest( + networkstatus_t *consensus, + const char *digest); +const routerstatus_t *router_get_consensus_status_by_nickname( + const char *nickname, + int warn_if_unnamed); +const char *networkstatus_get_router_digest_by_nickname(const char *nickname); +int networkstatus_nickname_is_unnamed(const char *nickname); +void networkstatus_consensus_download_failed(int status_code, + const char *flavname); +void update_consensus_networkstatus_fetch_time(time_t now); +int should_delay_dir_fetches(const or_options_t *options); +void update_networkstatus_downloads(time_t now); +void update_certificate_downloads(time_t now); +int consensus_is_waiting_for_certs(void); +int client_would_use_router(const routerstatus_t *rs, time_t now, + const or_options_t *options); +networkstatus_t *networkstatus_get_latest_consensus(void); +networkstatus_t *networkstatus_get_latest_consensus_by_flavor( + consensus_flavor_t f); +networkstatus_t *networkstatus_get_live_consensus(time_t now); +networkstatus_t *networkstatus_get_reasonably_live_consensus(time_t now, + int flavor); +#define NSSET_FROM_CACHE 1 +#define NSSET_WAS_WAITING_FOR_CERTS 2 +#define NSSET_DONT_DOWNLOAD_CERTS 4 +#define NSSET_ACCEPT_OBSOLETE 8 +#define NSSET_REQUIRE_FLAVOR 16 +int networkstatus_set_current_consensus(const char *consensus, + const char *flavor, + unsigned flags); +void networkstatus_note_certs_arrived(void); +void routers_update_all_from_networkstatus(time_t now, int dir_version); +void routers_update_status_from_consensus_networkstatus(smartlist_t *routers, + int reset_failures); +void signed_descs_update_status_from_consensus_networkstatus( + smartlist_t *descs); + +char *networkstatus_getinfo_helper_single(const routerstatus_t *rs); +char *networkstatus_getinfo_by_purpose(const char *purpose_string, time_t now); +void networkstatus_dump_bridge_status_to_file(time_t now); +int32_t networkstatus_get_param(const networkstatus_t *ns, + const char *param_name, + int32_t default_val, int32_t min_val, + int32_t max_val); +int getinfo_helper_networkstatus(control_connection_t *conn, + const char *question, char **answer, + const char **errmsg); +int32_t networkstatus_get_bw_weight(networkstatus_t *ns, const char *weight, + int32_t default_val); +const char *networkstatus_get_flavor_name(consensus_flavor_t flav); +int networkstatus_parse_flavor_name(const char *flavname); +void document_signature_free(document_signature_t *sig); +document_signature_t *document_signature_dup(const document_signature_t *sig); +void networkstatus_free_all(void); +int networkstatus_get_weight_scale_param(networkstatus_t *ns); + +#endif + diff --git a/src/tor/nodelist.c b/src/tor/nodelist.c new file mode 100644 index 0000000..96d8881 --- /dev/null +++ b/src/tor/nodelist.c @@ -0,0 +1,1557 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#include "or.h" +#include "address.h" +#include "config.h" +#include "control.h" +#include "dirserv.h" +#include "geoip.h" +#include "onion_main.h" +#include "microdesc.h" +#include "networkstatus.h" +#include "nodelist.h" +#include "policies.h" +#include "rendservice.h" +#include "router.h" +#include "routerlist.h" +#include "routerset.h" + +#include + +static void nodelist_drop_node(node_t *node, int remove_from_ht); +static void node_free(node_t *node); +static void update_router_have_minimum_dir_info(void); +static double get_frac_paths_needed_for_circs(const or_options_t *options, + const networkstatus_t *ns); + +/** A nodelist_t holds a node_t object for every router we're "willing to use + * for something". Specifically, it should hold a node_t for every node that + * is currently in the routerlist, or currently in the consensus we're using. + */ +typedef struct nodelist_t { + /* A list of all the nodes. */ + smartlist_t *nodes; + /* Hash table to map from node ID digest to node. */ + HT_HEAD(nodelist_map, node_t) nodes_by_id; + +} nodelist_t; + +static INLINE unsigned int +node_id_hash(const node_t *node) +{ +#if SIZEOF_INT == 4 + const uint32_t *p = (const uint32_t*)node->identity; + return p[0] ^ p[1] ^ p[2] ^ p[3] ^ p[4]; +#elif SIZEOF_INT == 8 + const uint64_t *p = (const uint32_t*)node->identity; + const uint32_t *p32 = (const uint32_t*)node->identity; + return p[0] ^ p[1] ^ p32[4]; +#endif +} + +static INLINE unsigned int +node_id_eq(const node_t *node1, const node_t *node2) +{ + return tor_memeq(node1->identity, node2->identity, DIGEST_LEN); +} + +HT_PROTOTYPE(nodelist_map, node_t, ht_ent, node_id_hash, node_id_eq); +HT_GENERATE(nodelist_map, node_t, ht_ent, node_id_hash, node_id_eq, + 0.6, malloc, realloc, free); + +/** The global nodelist. */ +static nodelist_t *the_nodelist=NULL; + +/** Create an empty nodelist if we haven't done so already. */ +static void +init_nodelist(void) +{ + if (PREDICT_UNLIKELY(the_nodelist == NULL)) { + the_nodelist = tor_malloc_zero(sizeof(nodelist_t)); + HT_INIT(nodelist_map, &the_nodelist->nodes_by_id); + the_nodelist->nodes = smartlist_new(); + } +} + +/** As node_get_by_id, but returns a non-const pointer */ +node_t * +node_get_mutable_by_id(const char *identity_digest) +{ + node_t search, *node; + if (PREDICT_UNLIKELY(the_nodelist == NULL)) + return NULL; + + memcpy(&search.identity, identity_digest, DIGEST_LEN); + node = HT_FIND(nodelist_map, &the_nodelist->nodes_by_id, &search); + return node; +} + +/** Return the node_t whose identity is identity_digest, or NULL + * if no such node exists. */ +const node_t * +node_get_by_id(const char *identity_digest) +{ + return node_get_mutable_by_id(identity_digest); +} + +/** Internal: return the node_t whose identity_digest is + * identity_digest. If none exists, create a new one, add it to the + * nodelist, and return it. + * + * Requires that the nodelist be initialized. + */ +static node_t * +node_get_or_create(const char *identity_digest) +{ + node_t *node; + + if ((node = node_get_mutable_by_id(identity_digest))) + return node; + + node = tor_malloc_zero(sizeof(node_t)); + memcpy(node->identity, identity_digest, DIGEST_LEN); + HT_INSERT(nodelist_map, &the_nodelist->nodes_by_id, node); + + smartlist_add(the_nodelist->nodes, node); + node->nodelist_idx = smartlist_len(the_nodelist->nodes) - 1; + + node->country = -1; + + return node; +} + +/** Called when a node's address changes. */ +static void +node_addrs_changed(node_t *node) +{ + node->last_reachable = node->last_reachable6 = 0; + node->country = -1; +} + +/** Add ri to an appropriate node in the nodelist. If we replace an + * old routerinfo, and ri_old_out is not NULL, set *ri_old_out + * to the previous routerinfo. + */ +node_t * +nodelist_set_routerinfo(routerinfo_t *ri, routerinfo_t **ri_old_out) +{ + node_t *node; + const char *id_digest; + int had_router = 0; + tor_assert(ri); + + init_nodelist(); + id_digest = ri->cache_info.identity_digest; + node = node_get_or_create(id_digest); + + if (node->ri) { + if (!routers_have_same_or_addrs(node->ri, ri)) { + node_addrs_changed(node); + } + had_router = 1; + if (ri_old_out) + *ri_old_out = node->ri; + } else { + if (ri_old_out) + *ri_old_out = NULL; + } + node->ri = ri; + + if (node->country == -1) + node_set_country(node); + + if (authdir_mode(get_options()) && !had_router) { + const char *discard=NULL; + uint32_t status = dirserv_router_get_status(ri, &discard); + dirserv_set_node_flags_from_authoritative_status(node, status); + } + + return node; +} + +/** Set the appropriate node_t to use md as its microdescriptor. + * + * Called when a new microdesc has arrived and the usable consensus flavor + * is "microdesc". + **/ +node_t * +nodelist_add_microdesc(microdesc_t *md) +{ + networkstatus_t *ns = + networkstatus_get_latest_consensus_by_flavor(FLAV_MICRODESC); + const routerstatus_t *rs; + node_t *node; + if (ns == NULL) + return NULL; + init_nodelist(); + + /* Microdescriptors don't carry an identity digest, so we need to figure + * it out by looking up the routerstatus. */ + rs = router_get_consensus_status_by_descriptor_digest(ns, md->digest); + if (rs == NULL) + return NULL; + node = node_get_mutable_by_id(rs->identity_digest); + if (node) { + if (node->md) + node->md->held_by_nodes--; + node->md = md; + md->held_by_nodes++; + } + return node; +} + +/** Tell the nodelist that the current usable consensus is ns. + * This makes the nodelist change all of the routerstatus entries for + * the nodes, drop nodes that no longer have enough info to get used, + * and grab microdescriptors into nodes as appropriate. + */ +void +nodelist_set_consensus(networkstatus_t *ns) +{ + const or_options_t *options = get_options(); + int authdir = authdir_mode_v3(options); + int client = !server_mode(options); + + init_nodelist(); + if (ns->flavor == FLAV_MICRODESC) + (void) get_microdesc_cache(); /* Make sure it exists first. */ + + SMARTLIST_FOREACH(the_nodelist->nodes, node_t *, node, + node->rs = NULL); + + SMARTLIST_FOREACH_BEGIN(ns->routerstatus_list, routerstatus_t *, rs) { + node_t *node = node_get_or_create(rs->identity_digest); + node->rs = rs; + if (ns->flavor == FLAV_MICRODESC) { + if (node->md == NULL || + tor_memneq(node->md->digest,rs->descriptor_digest,DIGEST256_LEN)) { + if (node->md) + node->md->held_by_nodes--; + node->md = microdesc_cache_lookup_by_digest256(NULL, + rs->descriptor_digest); + if (node->md) + node->md->held_by_nodes++; + } + } + + node_set_country(node); + + /* If we're not an authdir, believe others. */ + if (!authdir) { + node->is_valid = rs->is_valid; + node->is_running = rs->is_flagged_running; + node->is_fast = rs->is_fast; + node->is_stable = rs->is_stable; + node->is_possible_guard = rs->is_possible_guard; + node->is_exit = rs->is_exit; + node->is_bad_directory = rs->is_bad_directory; + node->is_bad_exit = rs->is_bad_exit; + node->is_hs_dir = rs->is_hs_dir; + node->ipv6_preferred = 0; + if (client && options->ClientPreferIPv6ORPort == 1 && + (tor_addr_is_null(&rs->ipv6_addr) == 0 || + (node->md && tor_addr_is_null(&node->md->ipv6_addr) == 0))) + node->ipv6_preferred = 1; + } + + } SMARTLIST_FOREACH_END(rs); + + nodelist_purge(); + + if (! authdir) { + SMARTLIST_FOREACH_BEGIN(the_nodelist->nodes, node_t *, node) { + /* We have no routerstatus for this router. Clear flags so we can skip + * it, maybe.*/ + if (!node->rs) { + tor_assert(node->ri); /* if it had only an md, or nothing, purge + * would have removed it. */ + if (node->ri->purpose == ROUTER_PURPOSE_GENERAL) { + /* Clear all flags. */ + node->is_valid = node->is_running = node->is_hs_dir = + node->is_fast = node->is_stable = + node->is_possible_guard = node->is_exit = + node->is_bad_exit = node->is_bad_directory = + node->ipv6_preferred = 0; + } + } + } SMARTLIST_FOREACH_END(node); + } +} + +/** Helper: return true iff a node has a usable amount of information*/ +static INLINE int +node_is_usable(const node_t *node) +{ + return (node->rs) || (node->ri); +} + +/** Tell the nodelist that md is no longer a microdescriptor for the + * node with identity_digest. */ +void +nodelist_remove_microdesc(const char *identity_digest, microdesc_t *md) +{ + node_t *node = node_get_mutable_by_id(identity_digest); + if (node && node->md == md) { + node->md = NULL; + md->held_by_nodes--; + } +} + +/** Tell the nodelist that ri is no longer in the routerlist. */ +void +nodelist_remove_routerinfo(routerinfo_t *ri) +{ + node_t *node = node_get_mutable_by_id(ri->cache_info.identity_digest); + if (node && node->ri == ri) { + node->ri = NULL; + if (! node_is_usable(node)) { + nodelist_drop_node(node, 1); + node_free(node); + } + } +} + +/** Remove node from the nodelist. (Asserts that it was there to begin + * with.) */ +static void +nodelist_drop_node(node_t *node, int remove_from_ht) +{ + node_t *tmp; + int idx; + if (remove_from_ht) { + tmp = HT_REMOVE(nodelist_map, &the_nodelist->nodes_by_id, node); + tor_assert(tmp == node); + } + + idx = node->nodelist_idx; + tor_assert(idx >= 0); + + tor_assert(node == smartlist_get(the_nodelist->nodes, idx)); + smartlist_del(the_nodelist->nodes, idx); + if (idx < smartlist_len(the_nodelist->nodes)) { + tmp = smartlist_get(the_nodelist->nodes, idx); + tmp->nodelist_idx = idx; + } + node->nodelist_idx = -1; +} + +/** Release storage held by node */ +static void +node_free(node_t *node) +{ + if (!node) + return; + if (node->md) + node->md->held_by_nodes--; + tor_assert(node->nodelist_idx == -1); + tor_free(node); +} + +/** Remove all entries from the nodelist that don't have enough info to be + * usable for anything. */ +void +nodelist_purge(void) +{ + node_t **iter; + if (PREDICT_UNLIKELY(the_nodelist == NULL)) + return; + + /* Remove the non-usable nodes. */ + for (iter = HT_START(nodelist_map, &the_nodelist->nodes_by_id); iter; ) { + node_t *node = *iter; + + if (node->md && !node->rs) { + /* An md is only useful if there is an rs. */ + node->md->held_by_nodes--; + node->md = NULL; + } + + if (node_is_usable(node)) { + iter = HT_NEXT(nodelist_map, &the_nodelist->nodes_by_id, iter); + } else { + iter = HT_NEXT_RMV(nodelist_map, &the_nodelist->nodes_by_id, iter); + nodelist_drop_node(node, 0); + node_free(node); + } + } + nodelist_assert_ok(); +} + +/** Release all storage held by the nodelist. */ +void +nodelist_free_all(void) +{ + if (PREDICT_UNLIKELY(the_nodelist == NULL)) + return; + + HT_CLEAR(nodelist_map, &the_nodelist->nodes_by_id); + SMARTLIST_FOREACH_BEGIN(the_nodelist->nodes, node_t *, node) { + node->nodelist_idx = -1; + node_free(node); + } SMARTLIST_FOREACH_END(node); + + smartlist_free(the_nodelist->nodes); + + tor_free(the_nodelist); +} + +/** Check that the nodelist is internally consistent, and consistent with + * the directory info it's derived from. + */ +void +nodelist_assert_ok(void) +{ + routerlist_t *rl = router_get_routerlist(); + networkstatus_t *ns = networkstatus_get_latest_consensus(); + digestmap_t *dm; + + if (!the_nodelist) + return; + + dm = digestmap_new(); + + /* every routerinfo in rl->routers should be in the nodelist. */ + if (rl) { + SMARTLIST_FOREACH_BEGIN(rl->routers, routerinfo_t *, ri) { + const node_t *node = node_get_by_id(ri->cache_info.identity_digest); + tor_assert(node && node->ri == ri); + tor_assert(fast_memeq(ri->cache_info.identity_digest, + node->identity, DIGEST_LEN)); + tor_assert(! digestmap_get(dm, node->identity)); + digestmap_set(dm, node->identity, (void*)node); + } SMARTLIST_FOREACH_END(ri); + } + + /* every routerstatus in ns should be in the nodelist */ + if (ns) { + SMARTLIST_FOREACH_BEGIN(ns->routerstatus_list, routerstatus_t *, rs) { + const node_t *node = node_get_by_id(rs->identity_digest); + tor_assert(node && node->rs == rs); + tor_assert(fast_memeq(rs->identity_digest, node->identity, DIGEST_LEN)); + digestmap_set(dm, node->identity, (void*)node); + if (ns->flavor == FLAV_MICRODESC) { + /* If it's a microdesc consensus, every entry that has a + * microdescriptor should be in the nodelist. + */ + microdesc_t *md = + microdesc_cache_lookup_by_digest256(NULL, rs->descriptor_digest); + tor_assert(md == node->md); + if (md) + tor_assert(md->held_by_nodes >= 1); + } + } SMARTLIST_FOREACH_END(rs); + } + + /* The nodelist should have no other entries, and its entries should be + * well-formed. */ + SMARTLIST_FOREACH_BEGIN(the_nodelist->nodes, node_t *, node) { + tor_assert(digestmap_get(dm, node->identity) != NULL); + tor_assert(node_sl_idx == node->nodelist_idx); + } SMARTLIST_FOREACH_END(node); + + tor_assert((long)smartlist_len(the_nodelist->nodes) == + (long)HT_SIZE(&the_nodelist->nodes_by_id)); + + digestmap_free(dm, NULL); +} + +/** Return a list of a node_t * for every node we know about. The caller + * MUST NOT modify the list. (You can set and clear flags in the nodes if + * you must, but you must not add or remove nodes.) */ +smartlist_t * +nodelist_get_list(void) +{ + init_nodelist(); + return the_nodelist->nodes; +} + +/** Given a hex-encoded nickname of the format DIGEST, $DIGEST, $DIGEST=name, + * or $DIGEST~name, return the node with the matching identity digest and + * nickname (if any). Return NULL if no such node exists, or if hex_id + * is not well-formed. */ +const node_t * +node_get_by_hex_id(const char *hex_id) +{ + char digest_buf[DIGEST_LEN]; + char nn_buf[MAX_NICKNAME_LEN+1]; + char nn_char='\0'; + + if (hex_digest_nickname_decode(hex_id, digest_buf, &nn_char, nn_buf)==0) { + const node_t *node = node_get_by_id(digest_buf); + if (!node) + return NULL; + if (nn_char) { + const char *real_name = node_get_nickname(node); + if (!real_name || strcasecmp(real_name, nn_buf)) + return NULL; + if (nn_char == '=') { + const char *named_id = + networkstatus_get_router_digest_by_nickname(nn_buf); + if (!named_id || tor_memneq(named_id, digest_buf, DIGEST_LEN)) + return NULL; + } + } + return node; + } + + return NULL; +} + +/** Given a nickname (possibly verbose, possibly a hexadecimal digest), return + * the corresponding node_t, or NULL if none exists. Warn the user if + * warn_if_unnamed is set, and they have specified a router by + * nickname, but the Named flag isn't set for that router. */ +const node_t * +node_get_by_nickname(const char *nickname, int warn_if_unnamed) +{ + const node_t *node; + if (!the_nodelist) + return NULL; + + /* Handle these cases: DIGEST, $DIGEST, $DIGEST=name, $DIGEST~name. */ + if ((node = node_get_by_hex_id(nickname)) != NULL) + return node; + + if (!strcasecmp(nickname, UNNAMED_ROUTER_NICKNAME)) + return NULL; + + /* Okay, so if we get here, the nickname is just a nickname. Is there + * a binding for it in the consensus? */ + { + const char *named_id = + networkstatus_get_router_digest_by_nickname(nickname); + if (named_id) + return node_get_by_id(named_id); + } + + /* Is it marked as owned-by-someone-else? */ + if (networkstatus_nickname_is_unnamed(nickname)) { + log_info(LD_GENERAL, "The name %s is listed as Unnamed: there is some " + "router that holds it, but not one listed in the current " + "consensus.", escaped(nickname)); + return NULL; + } + + /* Okay, so the name is not canonical for anybody. */ + { + smartlist_t *matches = smartlist_new(); + const node_t *choice = NULL; + + SMARTLIST_FOREACH_BEGIN(the_nodelist->nodes, node_t *, node) { + if (!strcasecmp(node_get_nickname(node), nickname)) + smartlist_add(matches, node); + } SMARTLIST_FOREACH_END(node); + + if (smartlist_len(matches)>1 && warn_if_unnamed) { + int any_unwarned = 0; + SMARTLIST_FOREACH_BEGIN(matches, node_t *, node) { + if (!node->name_lookup_warned) { + node->name_lookup_warned = 1; + any_unwarned = 1; + } + } SMARTLIST_FOREACH_END(node); + + if (any_unwarned) { + log_warn(LD_CONFIG, "There are multiple matches for the name %s, " + "but none is listed as Named in the directory consensus. " + "Choosing one arbitrarily.", nickname); + } + } else if (smartlist_len(matches)>1 && warn_if_unnamed) { + char fp[HEX_DIGEST_LEN+1]; + node_t *node = smartlist_get(matches, 0); + if (node->name_lookup_warned) { + base16_encode(fp, sizeof(fp), node->identity, DIGEST_LEN); + log_warn(LD_CONFIG, + "You specified a server \"%s\" by name, but the directory " + "authorities do not have any key registered for this " + "nickname -- so it could be used by any server, not just " + "the one you meant. " + "To make sure you get the same server in the future, refer " + "to it by key, as \"$%s\".", nickname, fp); + node->name_lookup_warned = 1; + } + } + + if (smartlist_len(matches)) + choice = smartlist_get(matches, 0); + + smartlist_free(matches); + return choice; + } +} + +/** Return the nickname of node, or NULL if we can't find one. */ +const char * +node_get_nickname(const node_t *node) +{ + tor_assert(node); + if (node->rs) + return node->rs->nickname; + else if (node->ri) + return node->ri->nickname; + else + return NULL; +} + +/** Return true iff the nickname of node is canonical, based on the + * latest consensus. */ +int +node_is_named(const node_t *node) +{ + const char *named_id; + const char *nickname = node_get_nickname(node); + if (!nickname) + return 0; + named_id = networkstatus_get_router_digest_by_nickname(nickname); + if (!named_id) + return 0; + return tor_memeq(named_id, node->identity, DIGEST_LEN); +} + +/** Return true iff node appears to be a directory authority or + * directory cache */ +int +node_is_dir(const node_t *node) +{ + if (node->rs) + return node->rs->dir_port != 0; + else if (node->ri) + return node->ri->dir_port != 0; + else + return 0; +} + +/** Return true iff node has either kind of usable descriptor -- that + * is, a routerdescriptor or a microdescriptor. */ +int +node_has_descriptor(const node_t *node) +{ + return (node->ri || + (node->rs && node->md)); +} + +/** Return the router_purpose of node. */ +int +node_get_purpose(const node_t *node) +{ + if (node->ri) + return node->ri->purpose; + else + return ROUTER_PURPOSE_GENERAL; +} + +/** Compute the verbose ("extended") nickname of node and store it + * into the MAX_VERBOSE_NICKNAME_LEN+1 character buffer at + * verbose_name_out */ +void +node_get_verbose_nickname(const node_t *node, + char *verbose_name_out) +{ + const char *nickname = node_get_nickname(node); + int is_named = node_is_named(node); + verbose_name_out[0] = '$'; + base16_encode(verbose_name_out+1, HEX_DIGEST_LEN+1, node->identity, + DIGEST_LEN); + if (!nickname) + return; + verbose_name_out[1+HEX_DIGEST_LEN] = is_named ? '=' : '~'; + strlcpy(verbose_name_out+1+HEX_DIGEST_LEN+1, nickname, MAX_NICKNAME_LEN+1); +} + +/** Compute the verbose ("extended") nickname of node with + * given id_digest and store it into the MAX_VERBOSE_NICKNAME_LEN+1 + * character buffer at verbose_name_out + * + * If node_get_by_id() returns NULL, base 16 encoding of + * id_digest is returned instead. */ +void +node_get_verbose_nickname_by_id(const char *id_digest, + char *verbose_name_out) +{ + const node_t *node = node_get_by_id(id_digest); + if (!node) { + verbose_name_out[0] = '$'; + base16_encode(verbose_name_out+1, HEX_DIGEST_LEN+1, id_digest, DIGEST_LEN); + } else { + node_get_verbose_nickname(node, verbose_name_out); + } +} + +/** Return true iff it seems that node allows circuits to exit + * through it directlry from the client. */ +int +node_allows_single_hop_exits(const node_t *node) +{ + if (node && node->ri) + return node->ri->allow_single_hop_exits; + else + return 0; +} + +/** Return true iff it seems that node has an exit policy that doesn't + * actually permit anything to exit, or we don't know its exit policy */ +int +node_exit_policy_rejects_all(const node_t *node) +{ + if (node->rejects_all) + return 1; + + if (node->ri) + return node->ri->policy_is_reject_star; + else if (node->md) + return node->md->exit_policy == NULL || + short_policy_is_reject_star(node->md->exit_policy); + else + return 1; +} + +/** Return true iff the exit policy for node is such that we can treat + * rejecting an address of type family unexpectedly as a sign of that + * node's failure. */ +int +node_exit_policy_is_exact(const node_t *node, sa_family_t family) +{ + if (family == AF_UNSPEC) { + return 1; /* Rejecting an address but not telling us what address + * is a bad sign. */ + } else if (family == AF_INET) { + return node->ri != NULL; + } else if (family == AF_INET6) { + return 0; + } + tor_fragile_assert(); + return 1; +} + +/** Return list of tor_addr_port_t with all OR ports (in the sense IP + * addr + TCP port) for node. Caller must free all elements + * using tor_free() and free the list using smartlist_free(). + * + * XXX this is potentially a memory fragmentation hog -- if on + * critical path consider the option of having the caller allocate the + * memory + */ +smartlist_t * +node_get_all_orports(const node_t *node) +{ + smartlist_t *sl = smartlist_new(); + + if (node->ri != NULL) { + if (node->ri->addr != 0) { + tor_addr_port_t *ap = tor_malloc(sizeof(tor_addr_port_t)); + tor_addr_from_ipv4h(&ap->addr, node->ri->addr); + ap->port = node->ri->or_port; + smartlist_add(sl, ap); + } + if (!tor_addr_is_null(&node->ri->ipv6_addr)) { + tor_addr_port_t *ap = tor_malloc(sizeof(tor_addr_port_t)); + tor_addr_copy(&ap->addr, &node->ri->ipv6_addr); + ap->port = node->ri->or_port; + smartlist_add(sl, ap); + } + } else if (node->rs != NULL) { + tor_addr_port_t *ap = tor_malloc(sizeof(tor_addr_port_t)); + tor_addr_from_ipv4h(&ap->addr, node->rs->addr); + ap->port = node->rs->or_port; + smartlist_add(sl, ap); + } + + return sl; +} + +/** Wrapper around node_get_prim_orport for backward + compatibility. */ +void +node_get_addr(const node_t *node, tor_addr_t *addr_out) +{ + tor_addr_port_t ap; + node_get_prim_orport(node, &ap); + tor_addr_copy(addr_out, &ap.addr); +} + +/** Return the host-order IPv4 address for node, or 0 if it doesn't + * seem to have one. */ +uint32_t +node_get_prim_addr_ipv4h(const node_t *node) +{ + if (node->ri) { + return node->ri->addr; + } else if (node->rs) { + return node->rs->addr; + } + return 0; +} + +/** Copy a string representation of an IP address for node into + * the len-byte buffer at buf. */ +void +node_get_address_string(const node_t *node, char *buf, size_t len) +{ + if (node->ri) { + strlcpy(buf, node->ri->address, len); + } else if (node->rs) { + tor_addr_t addr; + tor_addr_from_ipv4h(&addr, node->rs->addr); + tor_addr_to_str(buf, &addr, len, 0); + } else { + buf[0] = '\0'; + } +} + +/** Return node's declared uptime, or -1 if it doesn't seem to have + * one. */ +long +node_get_declared_uptime(const node_t *node) +{ + if (node->ri) + return node->ri->uptime; + else + return -1; +} + +/** Return node's platform string, or NULL if we don't know it. */ +const char * +node_get_platform(const node_t *node) +{ + /* If we wanted, we could record the version in the routerstatus_t, since + * the consensus lists it. We don't, though, so this function just won't + * work with microdescriptors. */ + if (node->ri) + return node->ri->platform; + else + return NULL; +} + +/** Return node's time of publication, or 0 if we don't have one. */ +time_t +node_get_published_on(const node_t *node) +{ + if (node->ri) + return node->ri->cache_info.published_on; + else + return 0; +} + +/** Return true iff node is one representing this router. */ +int +node_is_me(const node_t *node) +{ + return router_digest_is_me(node->identity); +} + +/** Return node declared family (as a list of names), or NULL if + * the node didn't declare a family. */ +const smartlist_t * +node_get_declared_family(const node_t *node) +{ + if (node->ri && node->ri->declared_family) + return node->ri->declared_family; + else if (node->md && node->md->family) + return node->md->family; + else + return NULL; +} + +/** Return 1 if we prefer the IPv6 address and OR TCP port of + * node, else 0. + * + * We prefer the IPv6 address if the router has an IPv6 address and + * i) the node_t says that it prefers IPv6 + * or + * ii) the router has no IPv4 address. */ +int +node_ipv6_preferred(const node_t *node) +{ + tor_addr_port_t ipv4_addr; + node_assert_ok(node); + + if (node->ipv6_preferred || node_get_prim_orport(node, &ipv4_addr)) { + if (node->ri) + return !tor_addr_is_null(&node->ri->ipv6_addr); + if (node->md) + return !tor_addr_is_null(&node->md->ipv6_addr); + if (node->rs) + return !tor_addr_is_null(&node->rs->ipv6_addr); + } + return 0; +} + +/** Copy the primary (IPv4) OR port (IP address and TCP port) for + * node into *ap_out. Return 0 if a valid address and + * port was copied, else return non-zero.*/ +int +node_get_prim_orport(const node_t *node, tor_addr_port_t *ap_out) +{ + node_assert_ok(node); + tor_assert(ap_out); + + if (node->ri) { + if (node->ri->addr == 0 || node->ri->or_port == 0) + return -1; + tor_addr_from_ipv4h(&ap_out->addr, node->ri->addr); + ap_out->port = node->ri->or_port; + return 0; + } + if (node->rs) { + if (node->rs->addr == 0 || node->rs->or_port == 0) + return -1; + tor_addr_from_ipv4h(&ap_out->addr, node->rs->addr); + ap_out->port = node->rs->or_port; + return 0; + } + return -1; +} + +/** Copy the preferred OR port (IP address and TCP port) for + * node into *ap_out. */ +void +node_get_pref_orport(const node_t *node, tor_addr_port_t *ap_out) +{ + const or_options_t *options = get_options(); + tor_assert(ap_out); + + /* Cheap implementation of config option ClientUseIPv6 -- simply + don't prefer IPv6 when ClientUseIPv6 is not set and we're not a + client running with bridges. See #4455 for more on this subject. + + Note that this filter is too strict since we're hindering not + only clients! Erring on the safe side shouldn't be a problem + though. XXX move this check to where outgoing connections are + made? -LN */ + if ((options->ClientUseIPv6 || options->UseBridges) && + node_ipv6_preferred(node)) { + node_get_pref_ipv6_orport(node, ap_out); + } else { + node_get_prim_orport(node, ap_out); + } +} + +/** Copy the preferred IPv6 OR port (IP address and TCP port) for + * node into *ap_out. */ +void +node_get_pref_ipv6_orport(const node_t *node, tor_addr_port_t *ap_out) +{ + node_assert_ok(node); + tor_assert(ap_out); + + /* We prefer the microdesc over a potential routerstatus here. They + are not being synchronised atm so there might be a chance that + they differ at some point, f.ex. when flipping + UseMicrodescriptors? -LN */ + + if (node->ri) { + tor_addr_copy(&ap_out->addr, &node->ri->ipv6_addr); + ap_out->port = node->ri->ipv6_orport; + } else if (node->md) { + tor_addr_copy(&ap_out->addr, &node->md->ipv6_addr); + ap_out->port = node->md->ipv6_orport; + } else if (node->rs) { + tor_addr_copy(&ap_out->addr, &node->rs->ipv6_addr); + ap_out->port = node->rs->ipv6_orport; + } +} + +/** Return true iff node has a curve25519 onion key. */ +int +node_has_curve25519_onion_key(const node_t *node) +{ + if (node->ri) + return node->ri->onion_curve25519_pkey != NULL; + else if (node->md) + return node->md->onion_curve25519_pkey != NULL; + else + return 0; +} + +/** Refresh the country code of ri. This function MUST be called on + * each router when the GeoIP database is reloaded, and on all new routers. */ +void +node_set_country(node_t *node) +{ + tor_addr_t addr = TOR_ADDR_NULL; + + /* XXXXipv6 */ + if (node->rs) + tor_addr_from_ipv4h(&addr, node->rs->addr); + else if (node->ri) + tor_addr_from_ipv4h(&addr, node->ri->addr); + + node->country = geoip_get_country_by_addr(&addr); +} + +/** Set the country code of all routers in the routerlist. */ +void +nodelist_refresh_countries(void) +{ + smartlist_t *nodes = nodelist_get_list(); + SMARTLIST_FOREACH(nodes, node_t *, node, + node_set_country(node)); +} + +/** Return true iff router1 and router2 have similar enough network addresses + * that we should treat them as being in the same family */ +static INLINE int +addrs_in_same_network_family(const tor_addr_t *a1, + const tor_addr_t *a2) +{ + return 0 == tor_addr_compare_masked(a1, a2, 16, CMP_SEMANTIC); +} + +/** Return true if node's nickname matches nickname + * (case-insensitive), or if node's identity key digest + * matches a hexadecimal value stored in nickname. Return + * false otherwise. */ +static int +node_nickname_matches(const node_t *node, const char *nickname) +{ + const char *n = node_get_nickname(node); + if (n && nickname[0]!='$' && !strcasecmp(n, nickname)) + return 1; + return hex_digest_nickname_matches(nickname, + node->identity, + n, + node_is_named(node)); +} + +/** Return true iff node is named by some nickname in lst. */ +static INLINE int +node_in_nickname_smartlist(const smartlist_t *lst, const node_t *node) +{ + if (!lst) return 0; + SMARTLIST_FOREACH(lst, const char *, name, { + if (node_nickname_matches(node, name)) + return 1; + }); + return 0; +} + +/** Return true iff r1 and r2 are in the same family, but not the same + * router. */ +int +nodes_in_same_family(const node_t *node1, const node_t *node2) +{ + const or_options_t *options = get_options(); + + /* Are they in the same family because of their addresses? */ + if (options->EnforceDistinctSubnets) { + tor_addr_t a1, a2; + node_get_addr(node1, &a1); + node_get_addr(node2, &a2); + if (addrs_in_same_network_family(&a1, &a2)) + return 1; + } + + /* Are they in the same family because the agree they are? */ + { + const smartlist_t *f1, *f2; + f1 = node_get_declared_family(node1); + f2 = node_get_declared_family(node2); + if (f1 && f2 && + node_in_nickname_smartlist(f1, node2) && + node_in_nickname_smartlist(f2, node1)) + return 1; + } + + /* Are they in the same option because the user says they are? */ + if (options->NodeFamilySets) { + SMARTLIST_FOREACH(options->NodeFamilySets, const routerset_t *, rs, { + if (routerset_contains_node(rs, node1) && + routerset_contains_node(rs, node2)) + return 1; + }); + } + + return 0; +} + +/** + * Add all the family of node, including node itself, to + * the smartlist sl. + * + * This is used to make sure we don't pick siblings in a single path, or + * pick more than one relay from a family for our entry guard list. + * Note that a node may be added to sl more than once if it is + * part of node's family for more than one reason. + */ +void +nodelist_add_node_and_family(smartlist_t *sl, const node_t *node) +{ + const smartlist_t *all_nodes = nodelist_get_list(); + const smartlist_t *declared_family; + const or_options_t *options = get_options(); + + tor_assert(node); + + declared_family = node_get_declared_family(node); + + /* Let's make sure that we have the node itself, if it's a real node. */ + { + const node_t *real_node = node_get_by_id(node->identity); + if (real_node) + smartlist_add(sl, (node_t*)real_node); + } + + /* First, add any nodes with similar network addresses. */ + if (options->EnforceDistinctSubnets) { + tor_addr_t node_addr; + node_get_addr(node, &node_addr); + + SMARTLIST_FOREACH_BEGIN(all_nodes, const node_t *, node2) { + tor_addr_t a; + node_get_addr(node2, &a); + if (addrs_in_same_network_family(&a, &node_addr)) + smartlist_add(sl, (void*)node2); + } SMARTLIST_FOREACH_END(node2); + } + + /* Now, add all nodes in the declared_family of this node, if they + * also declare this node to be in their family. */ + if (declared_family) { + /* Add every r such that router declares familyness with node, and node + * declares familyhood with router. */ + SMARTLIST_FOREACH_BEGIN(declared_family, const char *, name) { + const node_t *node2; + const smartlist_t *family2; + if (!(node2 = node_get_by_nickname(name, 0))) + continue; + if (!(family2 = node_get_declared_family(node2))) + continue; + SMARTLIST_FOREACH_BEGIN(family2, const char *, name2) { + if (node_nickname_matches(node, name2)) { + smartlist_add(sl, (void*)node2); + break; + } + } SMARTLIST_FOREACH_END(name2); + } SMARTLIST_FOREACH_END(name); + } + + /* If the user declared any families locally, honor those too. */ + if (options->NodeFamilySets) { + SMARTLIST_FOREACH(options->NodeFamilySets, const routerset_t *, rs, { + if (routerset_contains_node(rs, node)) { + routerset_get_all_nodes(sl, rs, NULL, 0); + } + }); + } +} + +/** Find a router that's up, that has this IP address, and + * that allows exit to this address:port, or return NULL if there + * isn't a good one. + * Don't exit enclave to excluded relays -- it wouldn't actually + * hurt anything, but this way there are fewer confused users. + */ +const node_t * +router_find_exact_exit_enclave(const char *address, uint16_t port) +{/*XXXX MOVE*/ + uint32_t addr; + struct in_addr in; + tor_addr_t a; + const or_options_t *options = get_options(); + + if (!tor_inet_aton(address, &in)) + return NULL; /* it's not an IP already */ + addr = ntohl(in.s_addr); + + tor_addr_from_ipv4h(&a, addr); + + SMARTLIST_FOREACH(nodelist_get_list(), const node_t *, node, { + if (node_get_addr_ipv4h(node) == addr && + node->is_running && + compare_tor_addr_to_node_policy(&a, port, node) == + ADDR_POLICY_ACCEPTED && + !routerset_contains_node(options->ExcludeExitNodesUnion_, node)) + return node; + }); + return NULL; +} + +/** Return 1 if router is not suitable for these parameters, else 0. + * If need_uptime is non-zero, we require a minimum uptime. + * If need_capacity is non-zero, we require a minimum advertised + * bandwidth. + * If need_guard, we require that the router is a possible entry guard. + */ +int +node_is_unreliable(const node_t *node, int need_uptime, + int need_capacity, int need_guard) +{ + if (need_uptime && !node->is_stable) + return 1; + if (need_capacity && !node->is_fast) + return 1; + if (need_guard && !node->is_possible_guard) + return 1; + return 0; +} + +/** Return 1 if all running sufficiently-stable routers we can use will reject + * addr:port. Return 0 if any might accept it. */ +int +router_exit_policy_all_nodes_reject(const tor_addr_t *addr, uint16_t port, + int need_uptime) +{ + addr_policy_result_t r; + + SMARTLIST_FOREACH_BEGIN(nodelist_get_list(), const node_t *, node) { + if (node->is_running && + !node_is_unreliable(node, need_uptime, 0, 0)) { + + r = compare_tor_addr_to_node_policy(addr, port, node); + + if (r != ADDR_POLICY_REJECTED && r != ADDR_POLICY_PROBABLY_REJECTED) + return 0; /* this one could be ok. good enough. */ + } + } SMARTLIST_FOREACH_END(node); + return 1; /* all will reject. */ +} + +/** Mark the router with ID digest as running or non-running + * in our routerlist. */ +void +router_set_status(const char *digest, int up) +{ + node_t *node; + tor_assert(digest); + + SMARTLIST_FOREACH(router_get_fallback_dir_servers(), + dir_server_t *, d, + if (tor_memeq(d->digest, digest, DIGEST_LEN)) + d->is_running = up); + + SMARTLIST_FOREACH(router_get_trusted_dir_servers(), + dir_server_t *, d, + if (tor_memeq(d->digest, digest, DIGEST_LEN)) + d->is_running = up); + + node = node_get_mutable_by_id(digest); + if (node) { +#if 0 + log_debug(LD_DIR,"Marking router %s as %s.", + node_describe(node), up ? "up" : "down"); +#endif + if (!up && node_is_me(node) && !net_is_disabled()) + log_warn(LD_NET, "We just marked ourself as down. Are your external " + "addresses reachable?"); + node->is_running = up; + } + + router_dir_info_changed(); +} + +/** True iff, the last time we checked whether we had enough directory info + * to build circuits, the answer was "yes". */ +static int have_min_dir_info = 0; +/** True iff enough has changed since the last time we checked whether we had + * enough directory info to build circuits that our old answer can no longer + * be trusted. */ +static int need_to_update_have_min_dir_info = 1; +/** String describing what we're missing before we have enough directory + * info. */ +static char dir_info_status[256] = ""; + +/** Return true iff we have enough networkstatus and router information to + * start building circuits. Right now, this means "more than half the + * networkstatus documents, and at least 1/4 of expected routers." */ +//XXX should consider whether we have enough exiting nodes here. +int +router_have_minimum_dir_info(void) +{ + if (PREDICT_UNLIKELY(need_to_update_have_min_dir_info)) { + update_router_have_minimum_dir_info(); + need_to_update_have_min_dir_info = 0; + } + return have_min_dir_info; +} + +/** Called when our internal view of the directory has changed. This can be + * when the authorities change, networkstatuses change, the list of routerdescs + * changes, or number of running routers changes. + */ +void +router_dir_info_changed(void) +{ + need_to_update_have_min_dir_info = 1; + rend_hsdir_routers_changed(); +} + +/** Return a string describing what we're missing before we have enough + * directory info. */ +const char * +get_dir_info_status_string(void) +{ + return dir_info_status; +} + +/** Iterate over the servers listed in consensus, and count how many of + * them seem like ones we'd use, and how many of those we have + * descriptors for. Store the former in *num_usable and the latter in + * *num_present. If in_set is non-NULL, only consider those + * routers in in_set. If exit_only is true, only consider nodes + * with the Exit flag. If *descs_out is present, add a node_t for each + * usable descriptor to it. + */ +static void +count_usable_descriptors(int *num_present, int *num_usable, + smartlist_t *descs_out, + const networkstatus_t *consensus, + const or_options_t *options, time_t now, + routerset_t *in_set, int exit_only) +{ + const int md = (consensus->flavor == FLAV_MICRODESC); + *num_present = 0, *num_usable=0; + + SMARTLIST_FOREACH_BEGIN(consensus->routerstatus_list, routerstatus_t *, rs) + { + const node_t *node = node_get_by_id(rs->identity_digest); + if (!node) + continue; /* This would be a bug: every entry in the consensus is + * supposed to have a node. */ + if (exit_only && ! rs->is_exit) + continue; + if (in_set && ! routerset_contains_routerstatus(in_set, rs, -1)) + continue; + if (client_would_use_router(rs, now, options)) { + const char * const digest = rs->descriptor_digest; + int present; + ++*num_usable; /* the consensus says we want it. */ + if (md) + present = NULL != microdesc_cache_lookup_by_digest256(NULL, digest); + else + present = NULL != router_get_by_descriptor_digest(digest); + if (present) { + /* we have the descriptor listed in the consensus. */ + ++*num_present; + } + if (descs_out) + smartlist_add(descs_out, (node_t*)node); + } + } + SMARTLIST_FOREACH_END(rs); + + log_debug(LD_DIR, "%d usable, %d present (%s%s).", + *num_usable, *num_present, + md ? "microdesc" : "desc", exit_only ? " exits" : "s"); +} + +/** Return an estimate of which fraction of usable paths through the Tor + * network we have available for use. */ +static double +compute_frac_paths_available(const networkstatus_t *consensus, + const or_options_t *options, time_t now, + int *num_present_out, int *num_usable_out, + char **status_out) +{ + smartlist_t *guards = smartlist_new(); + smartlist_t *mid = smartlist_new(); + smartlist_t *exits = smartlist_new(); + smartlist_t *myexits= smartlist_new(); + smartlist_t *myexits_unflagged = smartlist_new(); + double f_guard, f_mid, f_exit, f_myexit, f_myexit_unflagged; + int np, nu; /* Ignored */ + const int authdir = authdir_mode_v3(options); + + count_usable_descriptors(num_present_out, num_usable_out, + mid, consensus, options, now, NULL, 0); + if (options->EntryNodes) { + count_usable_descriptors(&np, &nu, guards, consensus, options, now, + options->EntryNodes, 0); + } else { + SMARTLIST_FOREACH(mid, const node_t *, node, { + if (authdir) { + if (node->rs && node->rs->is_possible_guard) + smartlist_add(guards, (node_t*)node); + } else { + if (node->is_possible_guard) + smartlist_add(guards, (node_t*)node); + } + }); + } + + /* All nodes with exit flag */ + count_usable_descriptors(&np, &nu, exits, consensus, options, now, + NULL, 1); + /* All nodes with exit flag in ExitNodes option */ + count_usable_descriptors(&np, &nu, myexits, consensus, options, now, + options->ExitNodes, 1); + /* Now compute the nodes in the ExitNodes option where which we don't know + * what their exit policy is, or we know it permits something. */ + count_usable_descriptors(&np, &nu, myexits_unflagged, + consensus, options, now, + options->ExitNodes, 0); + SMARTLIST_FOREACH_BEGIN(myexits_unflagged, const node_t *, node) { + if (node_has_descriptor(node) && node_exit_policy_rejects_all(node)) + SMARTLIST_DEL_CURRENT(myexits_unflagged, node); + } SMARTLIST_FOREACH_END(node); + + f_guard = frac_nodes_with_descriptors(guards, WEIGHT_FOR_GUARD); + f_mid = frac_nodes_with_descriptors(mid, WEIGHT_FOR_MID); + f_exit = frac_nodes_with_descriptors(exits, WEIGHT_FOR_EXIT); + f_myexit= frac_nodes_with_descriptors(myexits,WEIGHT_FOR_EXIT); + f_myexit_unflagged= + frac_nodes_with_descriptors(myexits_unflagged,WEIGHT_FOR_EXIT); + + /* If our ExitNodes list has eliminated every possible Exit node, and there + * were some possible Exit nodes, then instead consider nodes that permit + * exiting to some ports. */ + if (smartlist_len(myexits) == 0 && + smartlist_len(myexits_unflagged)) { + f_myexit = f_myexit_unflagged; + } + + smartlist_free(guards); + smartlist_free(mid); + smartlist_free(exits); + smartlist_free(myexits); + smartlist_free(myexits_unflagged); + + /* This is a tricky point here: we don't want to make it easy for a + * directory to trickle exits to us until it learns which exits we have + * configured, so require that we have a threshold both of total exits + * and usable exits. */ + if (f_myexit < f_exit) + f_exit = f_myexit; + + if (status_out) + tor_asprintf(status_out, + "%d%% of guards bw, " + "%d%% of midpoint bw, and " + "%d%% of exit bw", + (int)(f_guard*100), + (int)(f_mid*100), + (int)(f_exit*100)); + + return f_guard * f_mid * f_exit; +} + +/** We just fetched a new set of descriptors. Compute how far through + * the "loading descriptors" bootstrapping phase we are, so we can inform + * the controller of our progress. */ +int +count_loading_descriptors_progress(void) +{ + int num_present = 0, num_usable=0; + time_t now = time(NULL); + const or_options_t *options = get_options(); + const networkstatus_t *consensus = + networkstatus_get_reasonably_live_consensus(now,usable_consensus_flavor()); + double paths, fraction; + + if (!consensus) + return 0; /* can't count descriptors if we have no list of them */ + + paths = compute_frac_paths_available(consensus, options, now, + &num_present, &num_usable, + NULL); + + fraction = paths / get_frac_paths_needed_for_circs(options,consensus); + if (fraction > 1.0) + return 0; /* it's not the number of descriptors holding us back */ + return BOOTSTRAP_STATUS_LOADING_DESCRIPTORS + (int) + (fraction*(BOOTSTRAP_STATUS_CONN_OR-1 - + BOOTSTRAP_STATUS_LOADING_DESCRIPTORS)); +} + +/** Return the fraction of paths needed before we're willing to build + * circuits, as configured in options, or in the consensus ns. */ +static double +get_frac_paths_needed_for_circs(const or_options_t *options, + const networkstatus_t *ns) +{ +#define DFLT_PCT_USABLE_NEEDED 60 + if (options->PathsNeededToBuildCircuits >= 0.0) { + return options->PathsNeededToBuildCircuits; + } else { + return networkstatus_get_param(ns, "min_paths_for_circs_pct", + DFLT_PCT_USABLE_NEEDED, + 25, 95)/100.0; + } +} + +/** Change the value of have_min_dir_info, setting it true iff we have enough + * network and router information to build circuits. Clear the value of + * need_to_update_have_min_dir_info. */ +static void +update_router_have_minimum_dir_info(void) +{ + time_t now = time(NULL); + int res; + const or_options_t *options = get_options(); + const networkstatus_t *consensus = + networkstatus_get_reasonably_live_consensus(now,usable_consensus_flavor()); + int using_md; + + if (!consensus) { + if (!networkstatus_get_latest_consensus()) + strlcpy(dir_info_status, "We have no usable consensus.", + sizeof(dir_info_status)); + else + strlcpy(dir_info_status, "We have no recent usable consensus.", + sizeof(dir_info_status)); + res = 0; + goto done; + } + + if (should_delay_dir_fetches(get_options())) { + log_notice(LD_DIR, "no known bridge descriptors running yet; stalling"); + strlcpy(dir_info_status, "No live bridge descriptors.", + sizeof(dir_info_status)); + res = 0; + goto done; + } + + using_md = consensus->flavor == FLAV_MICRODESC; + + { + char *status = NULL; + int num_present=0, num_usable=0; + double paths = compute_frac_paths_available(consensus, options, now, + &num_present, &num_usable, + &status); + + if (paths < get_frac_paths_needed_for_circs(options,consensus)) { + tor_snprintf(dir_info_status, sizeof(dir_info_status), + "We need more %sdescriptors: we have %d/%d, and " + "can only build %d%% of likely paths. (We have %s.)", + using_md?"micro":"", num_present, num_usable, + (int)(paths*100), status); + /* log_notice(LD_NET, "%s", dir_info_status); */ + tor_free(status); + res = 0; + control_event_bootstrap(BOOTSTRAP_STATUS_REQUESTING_DESCRIPTORS, 0); + goto done; + } + + tor_free(status); + res = 1; + } + + done: + if (res && !have_min_dir_info) { + log_notice(LD_DIR, + "We now have enough directory information to build circuits."); + control_event_client_status(LOG_NOTICE, "ENOUGH_DIR_INFO"); + control_event_bootstrap(BOOTSTRAP_STATUS_CONN_OR, 0); + } + if (!res && have_min_dir_info) { + int quiet = directory_too_idle_to_fetch_descriptors(options, now); + tor_log(quiet ? LOG_INFO : LOG_NOTICE, LD_DIR, + "Our directory information is no longer up-to-date " + "enough to build circuits: %s", dir_info_status); + + /* a) make us log when we next complete a circuit, so we know when Tor + * is back up and usable, and b) disable some activities that Tor + * should only do while circuits are working, like reachability tests + * and fetching bridge descriptors only over circuits. */ + can_complete_circuit = 0; + + control_event_client_status(LOG_NOTICE, "NOT_ENOUGH_DIR_INFO"); + } + have_min_dir_info = res; + need_to_update_have_min_dir_info = 0; +} + diff --git a/src/tor/nodelist.h b/src/tor/nodelist.h new file mode 100644 index 0000000..565caa7 --- /dev/null +++ b/src/tor/nodelist.h @@ -0,0 +1,86 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file nodelist.h + * \brief Header file for nodelist.c. + **/ + +#ifndef TOR_NODELIST_H +#define TOR_NODELIST_H + +#define node_assert_ok(n) STMT_BEGIN { \ + tor_assert((n)->ri || (n)->rs); \ + } STMT_END + +node_t *node_get_mutable_by_id(const char *identity_digest); +const node_t *node_get_by_id(const char *identity_digest); +const node_t *node_get_by_hex_id(const char *identity_digest); +node_t *nodelist_set_routerinfo(routerinfo_t *ri, routerinfo_t **ri_old_out); +node_t *nodelist_add_microdesc(microdesc_t *md); +void nodelist_set_consensus(networkstatus_t *ns); + +void nodelist_remove_microdesc(const char *identity_digest, microdesc_t *md); +void nodelist_remove_routerinfo(routerinfo_t *ri); +void nodelist_purge(void); + +void nodelist_free_all(void); +void nodelist_assert_ok(void); + +const node_t *node_get_by_nickname(const char *nickname, int warn_if_unnamed); +void node_get_verbose_nickname(const node_t *node, + char *verbose_name_out); +void node_get_verbose_nickname_by_id(const char *id_digest, + char *verbose_name_out); +int node_is_named(const node_t *node); +int node_is_dir(const node_t *node); +int node_has_descriptor(const node_t *node); +int node_get_purpose(const node_t *node); +#define node_is_bridge(node) \ + (node_get_purpose((node)) == ROUTER_PURPOSE_BRIDGE) +int node_is_me(const node_t *node); +int node_exit_policy_rejects_all(const node_t *node); +int node_exit_policy_is_exact(const node_t *node, sa_family_t family); +smartlist_t *node_get_all_orports(const node_t *node); +int node_allows_single_hop_exits(const node_t *node); +const char *node_get_nickname(const node_t *node); +const char *node_get_platform(const node_t *node); +uint32_t node_get_prim_addr_ipv4h(const node_t *node); +void node_get_address_string(const node_t *node, char *cp, size_t len); +long node_get_declared_uptime(const node_t *node); +time_t node_get_published_on(const node_t *node); +const smartlist_t *node_get_declared_family(const node_t *node); +int node_ipv6_preferred(const node_t *node); +int node_get_prim_orport(const node_t *node, tor_addr_port_t *ap_out); +void node_get_pref_orport(const node_t *node, tor_addr_port_t *ap_out); +void node_get_pref_ipv6_orport(const node_t *node, tor_addr_port_t *ap_out); +int node_has_curve25519_onion_key(const node_t *node); + +smartlist_t *nodelist_get_list(void); + +/* Temporary during transition to multiple addresses. */ +void node_get_addr(const node_t *node, tor_addr_t *addr_out); +#define node_get_addr_ipv4h(n) node_get_prim_addr_ipv4h((n)) + +void nodelist_refresh_countries(void); +void node_set_country(node_t *node); +void nodelist_add_node_and_family(smartlist_t *nodes, const node_t *node); +int nodes_in_same_family(const node_t *node1, const node_t *node2); + +const node_t *router_find_exact_exit_enclave(const char *address, + uint16_t port); +int node_is_unreliable(const node_t *router, int need_uptime, + int need_capacity, int need_guard); +int router_exit_policy_all_nodes_reject(const tor_addr_t *addr, uint16_t port, + int need_uptime); +void router_set_status(const char *digest, int up); +int router_have_minimum_dir_info(void); +void router_dir_info_changed(void); +const char *get_dir_info_status_string(void); +int count_loading_descriptors_progress(void); + +#endif + diff --git a/src/tor/ntmain.h b/src/tor/ntmain.h new file mode 100644 index 0000000..c6927f1 --- /dev/null +++ b/src/tor/ntmain.h @@ -0,0 +1,30 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file ntmain.h + * \brief Header file for ntmain.c. + **/ + +#ifndef TOR_NTMAIN_H +#define TOR_NTMAIN_H + +//#ifdef _WIN32 +//#if !defined (WINCE) +//#define NT_SERVICE +//#endif +//#endif + +#ifdef NT_SERVICE +int nt_service_parse_options(int argc, char **argv, int *should_exit); +int nt_service_is_stopping(void); +void nt_service_set_state(DWORD state); +#else +#define nt_service_is_stopping() 0 +#endif + +#endif + diff --git a/src/tor/onion.c b/src/tor/onion.c new file mode 100644 index 0000000..30b983d --- /dev/null +++ b/src/tor/onion.c @@ -0,0 +1,1183 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file onion.c + * \brief Functions to queue create cells, wrap the various onionskin types, + * and parse and create the CREATE cell and its allies. + **/ + +#include "or.h" +#include "circuitlist.h" +#include "config.h" +#include "cpuworker.h" +#include "networkstatus.h" +#include "onion.h" +#include "onion_fast.h" +#include "onion_ntor.h" +#include "onion_tap.h" +#include "relay.h" +#include "rephist.h" +#include "router.h" + +/** Type for a linked list of circuits that are waiting for a free CPU worker + * to process a waiting onion handshake. */ +typedef struct onion_queue_t { + TOR_TAILQ_ENTRY(onion_queue_t) next; + or_circuit_t *circ; + uint16_t handshake_type; + create_cell_t *onionskin; + time_t when_added; +} onion_queue_t; + +/** 5 seconds on the onion queue til we just send back a destroy */ +#define ONIONQUEUE_WAIT_CUTOFF 5 + +/** Array of queues of circuits waiting for CPU workers. An element is NULL + * if that queue is empty.*/ +TOR_TAILQ_HEAD(onion_queue_head_t, onion_queue_t) + ol_list[MAX_ONION_HANDSHAKE_TYPE+1] = { + TOR_TAILQ_HEAD_INITIALIZER(ol_list[0]), /* tap */ + TOR_TAILQ_HEAD_INITIALIZER(ol_list[1]), /* fast */ + TOR_TAILQ_HEAD_INITIALIZER(ol_list[2]), /* ntor */ +}; + +/** Number of entries of each type currently in each element of ol_list[]. */ +static int ol_entries[MAX_ONION_HANDSHAKE_TYPE+1]; + +static int num_ntors_per_tap(void); +static void onion_queue_entry_remove(onion_queue_t *victim); + +/* XXXX024 Check lengths vs MAX_ONIONSKIN_{CHALLENGE,REPLY}_LEN. + * + * (By which I think I meant, "make sure that no + * X_ONIONSKIN_CHALLENGE/REPLY_LEN is greater than + * MAX_ONIONSKIN_CHALLENGE/REPLY_LEN." Also, make sure that we can pass + * over-large values via EXTEND2/EXTENDED2, for future-compatibility.*/ + +/** Return true iff we have room to queue another onionskin of type + * type. */ +static int +have_room_for_onionskin(uint16_t type) +{ + const or_options_t *options = get_options(); + int num_cpus; + uint64_t tap_usec, ntor_usec; + uint64_t ntor_during_tap_usec, tap_during_ntor_usec; + + /* If we've got fewer than 50 entries, we always have room for one more. */ + if (ol_entries[type] < 50) + return 1; + num_cpus = get_num_cpus(options); + /* Compute how many microseconds we'd expect to need to clear all + * onionskins in various combinations of the queues. */ + + /* How long would it take to process all the TAP cells in the queue? */ + tap_usec = estimated_usec_for_onionskins( + ol_entries[ONION_HANDSHAKE_TYPE_TAP], + ONION_HANDSHAKE_TYPE_TAP) / num_cpus; + + /* How long would it take to process all the NTor cells in the queue? */ + ntor_usec = estimated_usec_for_onionskins( + ol_entries[ONION_HANDSHAKE_TYPE_NTOR], + ONION_HANDSHAKE_TYPE_NTOR) / num_cpus; + + /* How long would it take to process the tap cells that we expect to + * process while draining the ntor queue? */ + tap_during_ntor_usec = estimated_usec_for_onionskins( + MIN(ol_entries[ONION_HANDSHAKE_TYPE_TAP], + ol_entries[ONION_HANDSHAKE_TYPE_NTOR] / num_ntors_per_tap()), + ONION_HANDSHAKE_TYPE_TAP) / num_cpus; + + /* How long would it take to process the ntor cells that we expect to + * process while draining the tap queue? */ + ntor_during_tap_usec = estimated_usec_for_onionskins( + MIN(ol_entries[ONION_HANDSHAKE_TYPE_NTOR], + ol_entries[ONION_HANDSHAKE_TYPE_TAP] * num_ntors_per_tap()), + ONION_HANDSHAKE_TYPE_NTOR) / num_cpus; + + /* See whether that exceeds MaxOnionQueueDelay. If so, we can't queue + * this. */ + if (type == ONION_HANDSHAKE_TYPE_NTOR && + (ntor_usec + tap_during_ntor_usec) / 1000 > + (uint64_t)options->MaxOnionQueueDelay) + return 0; + + if (type == ONION_HANDSHAKE_TYPE_TAP && + (tap_usec + ntor_during_tap_usec) / 1000 > + (uint64_t)options->MaxOnionQueueDelay) + return 0; + +#ifdef CURVE25519_ENABLED + /* If we support the ntor handshake, then don't let TAP handshakes use + * more than 2/3 of the space on the queue. */ + if (type == ONION_HANDSHAKE_TYPE_TAP && + tap_usec / 1000 > (uint64_t)options->MaxOnionQueueDelay * 2 / 3) + return 0; +#else + (void) type; +#endif + + return 1; +} + +/** Add circ to the end of ol_list and return 0, except + * if ol_list is too long, in which case do nothing and return -1. + */ +int +onion_pending_add(or_circuit_t *circ, create_cell_t *onionskin) +{ + onion_queue_t *tmp; + time_t now = time(NULL); + + if (onionskin->handshake_type > MAX_ONION_HANDSHAKE_TYPE) { + log_warn(LD_BUG, "Handshake %d out of range! Dropping.", + onionskin->handshake_type); + return -1; + } + + tmp = tor_malloc_zero(sizeof(onion_queue_t)); + tmp->circ = circ; + tmp->handshake_type = onionskin->handshake_type; + tmp->onionskin = onionskin; + tmp->when_added = now; + + if (!have_room_for_onionskin(onionskin->handshake_type)) { +#define WARN_TOO_MANY_CIRC_CREATIONS_INTERVAL (60) + static ratelim_t last_warned = + RATELIM_INIT(WARN_TOO_MANY_CIRC_CREATIONS_INTERVAL); + char *m; + if (onionskin->handshake_type == ONION_HANDSHAKE_TYPE_NTOR && + (m = rate_limit_log(&last_warned, approx_time()))) { + log_warn(LD_GENERAL, + "Your computer is too slow to handle this many circuit " + "creation requests! Please consider using the " + "MaxAdvertisedBandwidth config option or choosing a more " + "restricted exit policy.%s",m); + tor_free(m); + } + tor_free(tmp); + return -1; + } + + ++ol_entries[onionskin->handshake_type]; + log_info(LD_OR, "New create (%s). Queues now ntor=%d and tap=%d.", + onionskin->handshake_type == ONION_HANDSHAKE_TYPE_NTOR ? "ntor" : "tap", + ol_entries[ONION_HANDSHAKE_TYPE_NTOR], + ol_entries[ONION_HANDSHAKE_TYPE_TAP]); + + circ->onionqueue_entry = tmp; + TOR_TAILQ_INSERT_TAIL(&ol_list[onionskin->handshake_type], tmp, next); + + /* cull elderly requests. */ + while (1) { + onion_queue_t *head = TOR_TAILQ_FIRST(&ol_list[onionskin->handshake_type]); + if (now - head->when_added < (time_t)ONIONQUEUE_WAIT_CUTOFF) + break; + + circ = head->circ; + circ->onionqueue_entry = NULL; + onion_queue_entry_remove(head); + log_info(LD_CIRC, + "Circuit create request is too old; canceling due to overload."); + circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_RESOURCELIMIT); + } + return 0; +} + +/** Return a fairness parameter, to prefer processing NTOR style + * handshakes but still slowly drain the TAP queue so we don't starve + * it entirely. */ +static int +num_ntors_per_tap(void) +{ +#define DEFAULT_NUM_NTORS_PER_TAP 10 +#define MIN_NUM_NTORS_PER_TAP 1 +#define MAX_NUM_NTORS_PER_TAP 100000 + + return networkstatus_get_param(NULL, "NumNTorsPerTAP", + DEFAULT_NUM_NTORS_PER_TAP, + MIN_NUM_NTORS_PER_TAP, + MAX_NUM_NTORS_PER_TAP); +} + +/** Choose which onion queue we'll pull from next. If one is empty choose + * the other; if they both have elements, load balance across them but + * favoring NTOR. */ +static uint16_t +decide_next_handshake_type(void) +{ + /* The number of times we've chosen ntor lately when both were available. */ + static int recently_chosen_ntors = 0; + + if (!ol_entries[ONION_HANDSHAKE_TYPE_NTOR]) + return ONION_HANDSHAKE_TYPE_TAP; /* no ntors? try tap */ + + if (!ol_entries[ONION_HANDSHAKE_TYPE_TAP]) { + + /* Nick wants us to prioritize new tap requests when there aren't + * any in the queue and we've processed k ntor cells since the last + * tap cell. This strategy is maybe a good idea, since it starves tap + * less in the case where tap is rare, or maybe a poor idea, since it + * makes the new tap cell unfairly jump in front of ntor cells that + * got here first. In any case this edge case will only become relevant + * once tap is rare. We should reevaluate whether we like this decision + * once tap gets more rare. */ + if (ol_entries[ONION_HANDSHAKE_TYPE_NTOR] && + recently_chosen_ntors <= num_ntors_per_tap()) + ++recently_chosen_ntors; + + return ONION_HANDSHAKE_TYPE_NTOR; /* no taps? try ntor */ + } + + /* They both have something queued. Pick ntor if we haven't done that + * too much lately. */ + if (++recently_chosen_ntors <= num_ntors_per_tap()) { + return ONION_HANDSHAKE_TYPE_NTOR; + } + + /* Else, it's time to let tap have its turn. */ + recently_chosen_ntors = 0; + return ONION_HANDSHAKE_TYPE_TAP; +} + +/** Remove the highest priority item from ol_list[] and return it, or + * return NULL if the lists are empty. + */ +or_circuit_t * +onion_next_task(create_cell_t **onionskin_out) +{ + or_circuit_t *circ; + uint16_t handshake_to_choose = decide_next_handshake_type(); + onion_queue_t *head = TOR_TAILQ_FIRST(&ol_list[handshake_to_choose]); + + if (!head) + return NULL; /* no onions pending, we're done */ + + tor_assert(head->circ); + tor_assert(head->handshake_type <= MAX_ONION_HANDSHAKE_TYPE); +// tor_assert(head->circ->p_chan); /* make sure it's still valid */ +/* XXX I only commented out the above line to make the unit tests + * more manageable. That's probably not good long-term. -RD */ + circ = head->circ; + if (head->onionskin) + --ol_entries[head->handshake_type]; + log_info(LD_OR, "Processing create (%s). Queues now ntor=%d and tap=%d.", + head->handshake_type == ONION_HANDSHAKE_TYPE_NTOR ? "ntor" : "tap", + ol_entries[ONION_HANDSHAKE_TYPE_NTOR], + ol_entries[ONION_HANDSHAKE_TYPE_TAP]); + + *onionskin_out = head->onionskin; + head->onionskin = NULL; /* prevent free. */ + circ->onionqueue_entry = NULL; + onion_queue_entry_remove(head); + return circ; +} + +/** Return the number of handshake_type-style create requests pending. + */ +int +onion_num_pending(uint16_t handshake_type) +{ + return ol_entries[handshake_type]; +} + +/** Go through ol_list, find the onion_queue_t element which points to + * circ, remove and free that element. Leave circ itself alone. + */ +void +onion_pending_remove(or_circuit_t *circ) +{ + onion_queue_t *victim; + + if (!circ) + return; + + victim = circ->onionqueue_entry; + if (victim) + onion_queue_entry_remove(victim); +} + +/** Remove a queue entry victim from the queue, unlinking it from + * its circuit and freeing it and any structures it owns.*/ +static void +onion_queue_entry_remove(onion_queue_t *victim) +{ + if (victim->handshake_type > MAX_ONION_HANDSHAKE_TYPE) { + log_warn(LD_BUG, "Handshake %d out of range! Dropping.", + victim->handshake_type); + /* XXX leaks */ + return; + } + + TOR_TAILQ_REMOVE(&ol_list[victim->handshake_type], victim, next); + + if (victim->circ) + victim->circ->onionqueue_entry = NULL; + + if (victim->onionskin) + --ol_entries[victim->handshake_type]; + + tor_free(victim->onionskin); + tor_free(victim); +} + +/** Remove all circuits from the pending list. Called from tor_free_all. */ +void +clear_pending_onions(void) +{ + onion_queue_t *victim; + int i; + for (i=0; i<=MAX_ONION_HANDSHAKE_TYPE; i++) { + while ((victim = TOR_TAILQ_FIRST(&ol_list[i]))) { + onion_queue_entry_remove(victim); + } + } + memset(ol_entries, 0, sizeof(ol_entries)); +} + +/* ============================================================ */ + +/** Fill in a server_onion_keys_t object at keys with all of the keys + * and other info we might need to do onion handshakes. (We make a copy of + * our keys for each cpuworker to avoid race conditions with the main thread, + * and to avoid locking) */ +void +setup_server_onion_keys(server_onion_keys_t *keys) +{ + memset(keys, 0, sizeof(server_onion_keys_t)); + memcpy(keys->my_identity, router_get_my_id_digest(), DIGEST_LEN); + dup_onion_keys(&keys->onion_key, &keys->last_onion_key); +#ifdef CURVE25519_ENABLED + keys->curve25519_key_map = construct_ntor_key_map(); + keys->junk_keypair = tor_malloc_zero(sizeof(curve25519_keypair_t)); + curve25519_keypair_generate(keys->junk_keypair, 0); +#endif +} + +/** Release all storage held in keys, but do not free keys + * itself (as it's likely to be stack-allocated.) */ +void +release_server_onion_keys(server_onion_keys_t *keys) +{ + if (! keys) + return; + + crypto_pk_free(keys->onion_key); + crypto_pk_free(keys->last_onion_key); +#ifdef CURVE25519_ENABLED + ntor_key_map_free(keys->curve25519_key_map); + tor_free(keys->junk_keypair); +#endif + memset(keys, 0, sizeof(server_onion_keys_t)); +} + +/** Release whatever storage is held in state, depending on its + * type, and clear its pointer. */ +void +onion_handshake_state_release(onion_handshake_state_t *state) +{ + switch (state->tag) { + case ONION_HANDSHAKE_TYPE_TAP: + crypto_dh_free(state->u.tap); + state->u.tap = NULL; + break; + case ONION_HANDSHAKE_TYPE_FAST: + fast_handshake_state_free(state->u.fast); + state->u.fast = NULL; + break; +#ifdef CURVE25519_ENABLED + case ONION_HANDSHAKE_TYPE_NTOR: + ntor_handshake_state_free(state->u.ntor); + state->u.ntor = NULL; + break; +#endif + default: + log_warn(LD_BUG, "called with unknown handshake state type %d", + (int)state->tag); + tor_fragile_assert(); + } +} + +/** Perform the first step of a circuit-creation handshake of type type + * (one of ONION_HANDSHAKE_TYPE_*): generate the initial "onion skin" in + * onion_skin_out, and store any state information in state_out. + * Return -1 on failure, and the length of the onionskin on acceptance. + */ +int +onion_skin_create(int type, + const extend_info_t *node, + onion_handshake_state_t *state_out, + uint8_t *onion_skin_out) +{ + int r = -1; + + switch (type) { + case ONION_HANDSHAKE_TYPE_TAP: + if (!node->onion_key) + return -1; + + if (onion_skin_TAP_create(node->onion_key, + &state_out->u.tap, + (char*)onion_skin_out) < 0) + return -1; + + r = TAP_ONIONSKIN_CHALLENGE_LEN; + break; + case ONION_HANDSHAKE_TYPE_FAST: + if (fast_onionskin_create(&state_out->u.fast, onion_skin_out) < 0) + return -1; + + r = CREATE_FAST_LEN; + break; + case ONION_HANDSHAKE_TYPE_NTOR: +#ifdef CURVE25519_ENABLED + if (tor_mem_is_zero((const char*)node->curve25519_onion_key.public_key, + CURVE25519_PUBKEY_LEN)) + return -1; + if (onion_skin_ntor_create((const uint8_t*)node->identity_digest, + &node->curve25519_onion_key, + &state_out->u.ntor, + onion_skin_out) < 0) + return -1; + + r = NTOR_ONIONSKIN_LEN; +#else + return -1; +#endif + break; + default: + log_warn(LD_BUG, "called with unknown handshake state type %d", type); + tor_fragile_assert(); + r = -1; + } + + if (r > 0) + state_out->tag = (uint16_t) type; + + return r; +} + +/** Perform the second (server-side) step of a circuit-creation handshake of + * type type, responding to the client request in onion_skin + * using the keys in keys. On success, write our response into + * reply_out, generate keys_out_len bytes worth of key material + * in keys_out_len, a hidden service nonce to rend_nonce_out, + * and return the length of the reply. On failure, return -1. + */ +int +onion_skin_server_handshake(int type, + const uint8_t *onion_skin, size_t onionskin_len, + const server_onion_keys_t *keys, + uint8_t *reply_out, + uint8_t *keys_out, size_t keys_out_len, + uint8_t *rend_nonce_out) +{ + int r = -1; + + switch (type) { + case ONION_HANDSHAKE_TYPE_TAP: + if (onionskin_len != TAP_ONIONSKIN_CHALLENGE_LEN) + return -1; + if (onion_skin_TAP_server_handshake((const char*)onion_skin, + keys->onion_key, keys->last_onion_key, + (char*)reply_out, + (char*)keys_out, keys_out_len)<0) + return -1; + r = TAP_ONIONSKIN_REPLY_LEN; + memcpy(rend_nonce_out, reply_out+DH_KEY_LEN, DIGEST_LEN); + break; + case ONION_HANDSHAKE_TYPE_FAST: + if (onionskin_len != CREATE_FAST_LEN) + return -1; + if (fast_server_handshake(onion_skin, reply_out, keys_out, keys_out_len)<0) + return -1; + r = CREATED_FAST_LEN; + memcpy(rend_nonce_out, reply_out+DIGEST_LEN, DIGEST_LEN); + break; + case ONION_HANDSHAKE_TYPE_NTOR: +#ifdef CURVE25519_ENABLED + if (onionskin_len < NTOR_ONIONSKIN_LEN) + return -1; + { + size_t keys_tmp_len = keys_out_len + DIGEST_LEN; + uint8_t *keys_tmp = tor_malloc(keys_out_len + DIGEST_LEN); + + if (onion_skin_ntor_server_handshake( + onion_skin, keys->curve25519_key_map, + keys->junk_keypair, + keys->my_identity, + reply_out, keys_tmp, keys_tmp_len)<0) { + tor_free(keys_tmp); + return -1; + } + memcpy(keys_out, keys_tmp, keys_out_len); + memcpy(rend_nonce_out, keys_tmp+keys_out_len, DIGEST_LEN); + memwipe(keys_tmp, 0, keys_tmp_len); + tor_free(keys_tmp); + r = NTOR_REPLY_LEN; + } +#else + return -1; +#endif + break; + default: + log_warn(LD_BUG, "called with unknown handshake state type %d", type); + tor_fragile_assert(); + return -1; + } + + return r; +} + +/** Perform the final (client-side) step of a circuit-creation handshake of + * type type, using our state in handshake_state and the + * server's response in reply. On success, generate keys_out_len + * bytes worth of key material in keys_out_len, set + * rend_authenticator_out to the "KH" field that can be used to + * establish introduction points at this hop, and return 0. On failure, + * return -1. */ +int +onion_skin_client_handshake(int type, + const onion_handshake_state_t *handshake_state, + const uint8_t *reply, size_t reply_len, + uint8_t *keys_out, size_t keys_out_len, + uint8_t *rend_authenticator_out) +{ + if (handshake_state->tag != type) + return -1; + + switch (type) { + case ONION_HANDSHAKE_TYPE_TAP: + if (reply_len != TAP_ONIONSKIN_REPLY_LEN) + return -1; + if (onion_skin_TAP_client_handshake(handshake_state->u.tap, + (const char*)reply, + (char *)keys_out, keys_out_len) < 0) + return -1; + + memcpy(rend_authenticator_out, reply+DH_KEY_LEN, DIGEST_LEN); + + return 0; + case ONION_HANDSHAKE_TYPE_FAST: + if (reply_len != CREATED_FAST_LEN) + return -1; + if (fast_client_handshake(handshake_state->u.fast, reply, + keys_out, keys_out_len) < 0) + return -1; + + memcpy(rend_authenticator_out, reply+DIGEST_LEN, DIGEST_LEN); + return 0; +#ifdef CURVE25519_ENABLED + case ONION_HANDSHAKE_TYPE_NTOR: + if (reply_len < NTOR_REPLY_LEN) + return -1; + { + size_t keys_tmp_len = keys_out_len + DIGEST_LEN; + uint8_t *keys_tmp = tor_malloc(keys_tmp_len); + if (onion_skin_ntor_client_handshake(handshake_state->u.ntor, + reply, + keys_tmp, keys_tmp_len) < 0) { + tor_free(keys_tmp); + return -1; + } + memcpy(keys_out, keys_tmp, keys_out_len); + memcpy(rend_authenticator_out, keys_tmp + keys_out_len, DIGEST_LEN); + memwipe(keys_tmp, 0, keys_tmp_len); + tor_free(keys_tmp); + } + return 0; +#endif + default: + log_warn(LD_BUG, "called with unknown handshake state type %d", type); + tor_fragile_assert(); + return -1; + } +} + +/** Helper: return 0 if cell appears valid, -1 otherwise. If + * unknown_ok is true, allow cells with handshake types we don't + * recognize. */ +static int +check_create_cell(const create_cell_t *cell, int unknown_ok) +{ + switch (cell->cell_type) { + case CELL_CREATE: + if (cell->handshake_type != ONION_HANDSHAKE_TYPE_TAP && + cell->handshake_type != ONION_HANDSHAKE_TYPE_NTOR) + return -1; + break; + case CELL_CREATE_FAST: + if (cell->handshake_type != ONION_HANDSHAKE_TYPE_FAST) + return -1; + break; + case CELL_CREATE2: + break; + default: + return -1; + } + + switch (cell->handshake_type) { + case ONION_HANDSHAKE_TYPE_TAP: + if (cell->handshake_len != TAP_ONIONSKIN_CHALLENGE_LEN) + return -1; + break; + case ONION_HANDSHAKE_TYPE_FAST: + if (cell->handshake_len != CREATE_FAST_LEN) + return -1; + break; +#ifdef CURVE25519_ENABLED + case ONION_HANDSHAKE_TYPE_NTOR: + if (cell->handshake_len != NTOR_ONIONSKIN_LEN) + return -1; + break; +#endif + default: + if (! unknown_ok) + return -1; + } + + return 0; +} + +/** Write the various parameters into the create cell. Separate from + * create_cell_parse() to make unit testing easier. + */ +void +create_cell_init(create_cell_t *cell_out, uint8_t cell_type, + uint16_t handshake_type, uint16_t handshake_len, + const uint8_t *onionskin) +{ + memset(cell_out, 0, sizeof(*cell_out)); + + cell_out->cell_type = cell_type; + cell_out->handshake_type = handshake_type; + cell_out->handshake_len = handshake_len; + memcpy(cell_out->onionskin, onionskin, handshake_len); +} + +/** Helper: parse the CREATE2 payload at p, which could be up to + * p_len bytes long, and use it to fill the fields of + * cell_out. Return 0 on success and -1 on failure. + * + * Note that part of the body of an EXTEND2 cell is a CREATE2 payload, so + * this function is also used for parsing those. + */ +static int +parse_create2_payload(create_cell_t *cell_out, const uint8_t *p, size_t p_len) +{ + uint16_t handshake_type, handshake_len; + + if (p_len < 4) + return -1; + + handshake_type = ntohs(get_uint16(p)); + handshake_len = ntohs(get_uint16(p+2)); + + if (handshake_len > CELL_PAYLOAD_SIZE - 4 || handshake_len > p_len - 4) + return -1; + if (handshake_type == ONION_HANDSHAKE_TYPE_FAST) + return -1; + + create_cell_init(cell_out, CELL_CREATE2, handshake_type, handshake_len, + p+4); + return 0; +} + +/** Magic string which, in a CREATE or EXTEND cell, indicates that a seeming + * TAP payload is really an ntor payload. We'd do away with this if every + * relay supported EXTEND2, but we want to be able to extend from A to B with + * ntor even when A doesn't understand EXTEND2 and so can't generate a + * CREATE2 cell. + **/ +#define NTOR_CREATE_MAGIC "ntorNTORntorNTOR" + +/** Parse a CREATE, CREATE_FAST, or CREATE2 cell from cell_in into + * cell_out. Return 0 on success, -1 on failure. (We reject some + * syntactically valid CREATE2 cells that we can't generate or react to.) */ +int +create_cell_parse(create_cell_t *cell_out, const cell_t *cell_in) +{ + switch (cell_in->command) { + case CELL_CREATE: + if (tor_memeq(cell_in->payload, NTOR_CREATE_MAGIC, 16)) { + create_cell_init(cell_out, CELL_CREATE, ONION_HANDSHAKE_TYPE_NTOR, + NTOR_ONIONSKIN_LEN, cell_in->payload+16); + } else { + create_cell_init(cell_out, CELL_CREATE, ONION_HANDSHAKE_TYPE_TAP, + TAP_ONIONSKIN_CHALLENGE_LEN, cell_in->payload); + } + break; + case CELL_CREATE_FAST: + create_cell_init(cell_out, CELL_CREATE_FAST, ONION_HANDSHAKE_TYPE_FAST, + CREATE_FAST_LEN, cell_in->payload); + break; + case CELL_CREATE2: + if (parse_create2_payload(cell_out, cell_in->payload, + CELL_PAYLOAD_SIZE) < 0) + return -1; + break; + default: + return -1; + } + + return check_create_cell(cell_out, 0); +} + +/** Helper: return 0 if cell appears valid, -1 otherwise. */ +static int +check_created_cell(const created_cell_t *cell) +{ + switch (cell->cell_type) { + case CELL_CREATED: + if (cell->handshake_len != TAP_ONIONSKIN_REPLY_LEN && + cell->handshake_len != NTOR_REPLY_LEN) + return -1; + break; + case CELL_CREATED_FAST: + if (cell->handshake_len != CREATED_FAST_LEN) + return -1; + break; + case CELL_CREATED2: + if (cell->handshake_len > RELAY_PAYLOAD_SIZE-2) + return -1; + break; + } + + return 0; +} + +/** Parse a CREATED, CREATED_FAST, or CREATED2 cell from cell_in into + * cell_out. Return 0 on success, -1 on failure. */ +int +created_cell_parse(created_cell_t *cell_out, const cell_t *cell_in) +{ + memset(cell_out, 0, sizeof(*cell_out)); + + switch (cell_in->command) { + case CELL_CREATED: + cell_out->cell_type = CELL_CREATED; + cell_out->handshake_len = TAP_ONIONSKIN_REPLY_LEN; + memcpy(cell_out->reply, cell_in->payload, TAP_ONIONSKIN_REPLY_LEN); + break; + case CELL_CREATED_FAST: + cell_out->cell_type = CELL_CREATED_FAST; + cell_out->handshake_len = CREATED_FAST_LEN; + memcpy(cell_out->reply, cell_in->payload, CREATED_FAST_LEN); + break; + case CELL_CREATED2: + { + const uint8_t *p = cell_in->payload; + cell_out->cell_type = CELL_CREATED2; + cell_out->handshake_len = ntohs(get_uint16(p)); + if (cell_out->handshake_len > CELL_PAYLOAD_SIZE - 2) + return -1; + memcpy(cell_out->reply, p+2, cell_out->handshake_len); + break; + } + } + + return check_created_cell(cell_out); +} + +/** Helper: return 0 if cell appears valid, -1 otherwise. */ +static int +check_extend_cell(const extend_cell_t *cell) +{ + if (tor_digest_is_zero((const char*)cell->node_id)) + return -1; + /* We don't currently allow EXTEND2 cells without an IPv4 address */ + if (tor_addr_family(&cell->orport_ipv4.addr) == AF_UNSPEC) + return -1; + if (cell->create_cell.cell_type == CELL_CREATE) { + if (cell->cell_type != RELAY_COMMAND_EXTEND) + return -1; + } else if (cell->create_cell.cell_type == CELL_CREATE2) { + if (cell->cell_type != RELAY_COMMAND_EXTEND2 && + cell->cell_type != RELAY_COMMAND_EXTEND) + return -1; + } else { + /* In particular, no CREATE_FAST cells are allowed */ + return -1; + } + if (cell->create_cell.handshake_type == ONION_HANDSHAKE_TYPE_FAST) + return -1; + + return check_create_cell(&cell->create_cell, 1); +} + +/** Protocol constants for specifier types in EXTEND2 + * @{ + */ +#define SPECTYPE_IPV4 0 +#define SPECTYPE_IPV6 1 +#define SPECTYPE_LEGACY_ID 2 +/** @} */ + +/** Parse an EXTEND or EXTEND2 cell (according to command) from the + * payload_length bytes of payload into cell_out. Return + * 0 on success, -1 on failure. */ +int +extend_cell_parse(extend_cell_t *cell_out, const uint8_t command, + const uint8_t *payload, size_t payload_length) +{ + const uint8_t *eop; + + memset(cell_out, 0, sizeof(*cell_out)); + if (payload_length > RELAY_PAYLOAD_SIZE) + return -1; + eop = payload + payload_length; + + switch (command) { + case RELAY_COMMAND_EXTEND: + { + if (payload_length != 6 + TAP_ONIONSKIN_CHALLENGE_LEN + DIGEST_LEN) + return -1; + + cell_out->cell_type = RELAY_COMMAND_EXTEND; + tor_addr_from_ipv4n(&cell_out->orport_ipv4.addr, get_uint32(payload)); + cell_out->orport_ipv4.port = ntohs(get_uint16(payload+4)); + tor_addr_make_unspec(&cell_out->orport_ipv6.addr); + if (tor_memeq(payload + 6, NTOR_CREATE_MAGIC, 16)) { + cell_out->create_cell.cell_type = CELL_CREATE2; + cell_out->create_cell.handshake_type = ONION_HANDSHAKE_TYPE_NTOR; + cell_out->create_cell.handshake_len = NTOR_ONIONSKIN_LEN; + memcpy(cell_out->create_cell.onionskin, payload + 22, + NTOR_ONIONSKIN_LEN); + } else { + cell_out->create_cell.cell_type = CELL_CREATE; + cell_out->create_cell.handshake_type = ONION_HANDSHAKE_TYPE_TAP; + cell_out->create_cell.handshake_len = TAP_ONIONSKIN_CHALLENGE_LEN; + memcpy(cell_out->create_cell.onionskin, payload + 6, + TAP_ONIONSKIN_CHALLENGE_LEN); + } + memcpy(cell_out->node_id, payload + 6 + TAP_ONIONSKIN_CHALLENGE_LEN, + DIGEST_LEN); + break; + } + case RELAY_COMMAND_EXTEND2: + { + uint8_t n_specs, spectype, speclen; + int i; + int found_ipv4 = 0, found_ipv6 = 0, found_id = 0; + tor_addr_make_unspec(&cell_out->orport_ipv4.addr); + tor_addr_make_unspec(&cell_out->orport_ipv6.addr); + + if (payload_length == 0) + return -1; + + cell_out->cell_type = RELAY_COMMAND_EXTEND2; + n_specs = *payload++; + /* Parse the specifiers. We'll only take the first IPv4 and first IPv6 + * address, and the node ID, and ignore everything else */ + for (i = 0; i < n_specs; ++i) { + if (eop - payload < 2) + return -1; + spectype = payload[0]; + speclen = payload[1]; + payload += 2; + if (eop - payload < speclen) + return -1; + switch (spectype) { + case SPECTYPE_IPV4: + if (speclen != 6) + return -1; + if (!found_ipv4) { + tor_addr_from_ipv4n(&cell_out->orport_ipv4.addr, + get_uint32(payload)); + cell_out->orport_ipv4.port = ntohs(get_uint16(payload+4)); + found_ipv4 = 1; + } + break; + case SPECTYPE_IPV6: + if (speclen != 18) + return -1; + if (!found_ipv6) { + tor_addr_from_ipv6_bytes(&cell_out->orport_ipv6.addr, + (const char*)payload); + cell_out->orport_ipv6.port = ntohs(get_uint16(payload+16)); + found_ipv6 = 1; + } + break; + case SPECTYPE_LEGACY_ID: + if (speclen != 20) + return -1; + if (found_id) + return -1; + memcpy(cell_out->node_id, payload, 20); + found_id = 1; + break; + } + payload += speclen; + } + if (!found_id || !found_ipv4) + return -1; + if (parse_create2_payload(&cell_out->create_cell,payload,eop-payload)<0) + return -1; + break; + } + default: + return -1; + } + + return check_extend_cell(cell_out); +} + +/** Helper: return 0 if cell appears valid, -1 otherwise. */ +static int +check_extended_cell(const extended_cell_t *cell) +{ + if (cell->created_cell.cell_type == CELL_CREATED) { + if (cell->cell_type != RELAY_COMMAND_EXTENDED) + return -1; + } else if (cell->created_cell.cell_type == CELL_CREATED2) { + if (cell->cell_type != RELAY_COMMAND_EXTENDED2) + return -1; + } else { + return -1; + } + + return check_created_cell(&cell->created_cell); +} + +/** Parse an EXTENDED or EXTENDED2 cell (according to command) from the + * payload_length bytes of payload into cell_out. Return + * 0 on success, -1 on failure. */ +int +extended_cell_parse(extended_cell_t *cell_out, + const uint8_t command, const uint8_t *payload, + size_t payload_len) +{ + memset(cell_out, 0, sizeof(*cell_out)); + if (payload_len > RELAY_PAYLOAD_SIZE) + return -1; + + switch (command) { + case RELAY_COMMAND_EXTENDED: + if (payload_len != TAP_ONIONSKIN_REPLY_LEN) + return -1; + cell_out->cell_type = RELAY_COMMAND_EXTENDED; + cell_out->created_cell.cell_type = CELL_CREATED; + cell_out->created_cell.handshake_len = TAP_ONIONSKIN_REPLY_LEN; + memcpy(cell_out->created_cell.reply, payload, TAP_ONIONSKIN_REPLY_LEN); + break; + case RELAY_COMMAND_EXTENDED2: + { + cell_out->cell_type = RELAY_COMMAND_EXTENDED2; + cell_out->created_cell.cell_type = CELL_CREATED2; + cell_out->created_cell.handshake_len = ntohs(get_uint16(payload)); + if (cell_out->created_cell.handshake_len > RELAY_PAYLOAD_SIZE - 2 || + cell_out->created_cell.handshake_len > payload_len - 2) + return -1; + memcpy(cell_out->created_cell.reply, payload+2, + cell_out->created_cell.handshake_len); + } + break; + default: + return -1; + } + + return check_extended_cell(cell_out); +} + +/** Fill cell_out with a correctly formatted version of the + * CREATE{,_FAST,2} cell in cell_in. Return 0 on success, -1 on + * failure. This is a cell we didn't originate if relayed is true. */ +static int +create_cell_format_impl(cell_t *cell_out, const create_cell_t *cell_in, + int relayed) +{ + uint8_t *p; + size_t space; + if (check_create_cell(cell_in, relayed) < 0) + return -1; + + memset(cell_out->payload, 0, sizeof(cell_out->payload)); + cell_out->command = cell_in->cell_type; + + p = cell_out->payload; + space = sizeof(cell_out->payload); + + switch (cell_in->cell_type) { + case CELL_CREATE: + if (cell_in->handshake_type == ONION_HANDSHAKE_TYPE_NTOR) { + memcpy(p, NTOR_CREATE_MAGIC, 16); + p += 16; + space -= 16; + } + /* Fall through */ + case CELL_CREATE_FAST: + tor_assert(cell_in->handshake_len <= space); + memcpy(p, cell_in->onionskin, cell_in->handshake_len); + break; + case CELL_CREATE2: + tor_assert(cell_in->handshake_len <= sizeof(cell_out->payload)-4); + set_uint16(cell_out->payload, htons(cell_in->handshake_type)); + set_uint16(cell_out->payload+2, htons(cell_in->handshake_len)); + memcpy(cell_out->payload + 4, cell_in->onionskin, cell_in->handshake_len); + break; + default: + return -1; + } + + return 0; +} + +int +create_cell_format(cell_t *cell_out, const create_cell_t *cell_in) +{ + return create_cell_format_impl(cell_out, cell_in, 0); +} + +int +create_cell_format_relayed(cell_t *cell_out, const create_cell_t *cell_in) +{ + return create_cell_format_impl(cell_out, cell_in, 1); +} + +/** Fill cell_out with a correctly formatted version of the + * CREATED{,_FAST,2} cell in cell_in. Return 0 on success, -1 on + * failure. */ +int +created_cell_format(cell_t *cell_out, const created_cell_t *cell_in) +{ + if (check_created_cell(cell_in) < 0) + return -1; + + memset(cell_out->payload, 0, sizeof(cell_out->payload)); + cell_out->command = cell_in->cell_type; + + switch (cell_in->cell_type) { + case CELL_CREATED: + case CELL_CREATED_FAST: + tor_assert(cell_in->handshake_len <= sizeof(cell_out->payload)); + memcpy(cell_out->payload, cell_in->reply, cell_in->handshake_len); + break; + case CELL_CREATED2: + tor_assert(cell_in->handshake_len <= sizeof(cell_out->payload)-2); + set_uint16(cell_out->payload, htons(cell_in->handshake_len)); + memcpy(cell_out->payload + 2, cell_in->reply, cell_in->handshake_len); + break; + default: + return -1; + } + return 0; +} + +/** Format the EXTEND{,2} cell in cell_in, storing its relay payload in + * payload_out, the number of bytes used in *len_out, and the + * relay command in *command_out. The payload_out must have + * RELAY_PAYLOAD_SIZE bytes available. Return 0 on success, -1 on failure. */ +int +extend_cell_format(uint8_t *command_out, uint16_t *len_out, + uint8_t *payload_out, const extend_cell_t *cell_in) +{ + uint8_t *p, *eop; + if (check_extend_cell(cell_in) < 0) + return -1; + + p = payload_out; + eop = payload_out + RELAY_PAYLOAD_SIZE; + + memset(p, 0, RELAY_PAYLOAD_SIZE); + + switch (cell_in->cell_type) { + case RELAY_COMMAND_EXTEND: + { + *command_out = RELAY_COMMAND_EXTEND; + *len_out = 6 + TAP_ONIONSKIN_CHALLENGE_LEN + DIGEST_LEN; + set_uint32(p, tor_addr_to_ipv4n(&cell_in->orport_ipv4.addr)); + set_uint16(p+4, ntohs(cell_in->orport_ipv4.port)); + if (cell_in->create_cell.handshake_type == ONION_HANDSHAKE_TYPE_NTOR) { + memcpy(p+6, NTOR_CREATE_MAGIC, 16); + memcpy(p+22, cell_in->create_cell.onionskin, NTOR_ONIONSKIN_LEN); + } else { + memcpy(p+6, cell_in->create_cell.onionskin, + TAP_ONIONSKIN_CHALLENGE_LEN); + } + memcpy(p+6+TAP_ONIONSKIN_CHALLENGE_LEN, cell_in->node_id, DIGEST_LEN); + } + break; + case RELAY_COMMAND_EXTEND2: + { + uint8_t n = 2; + *command_out = RELAY_COMMAND_EXTEND2; + + *p++ = n; /* 2 identifiers */ + *p++ = SPECTYPE_IPV4; /* First is IPV4. */ + *p++ = 6; /* It's 6 bytes long. */ + set_uint32(p, tor_addr_to_ipv4n(&cell_in->orport_ipv4.addr)); + set_uint16(p+4, htons(cell_in->orport_ipv4.port)); + p += 6; + *p++ = SPECTYPE_LEGACY_ID; /* Next is an identity digest. */ + *p++ = 20; /* It's 20 bytes long */ + memcpy(p, cell_in->node_id, DIGEST_LEN); + p += 20; + + /* Now we can send the handshake */ + set_uint16(p, htons(cell_in->create_cell.handshake_type)); + set_uint16(p+2, htons(cell_in->create_cell.handshake_len)); + p += 4; + + if (cell_in->create_cell.handshake_len > eop - p) + return -1; + + memcpy(p, cell_in->create_cell.onionskin, + cell_in->create_cell.handshake_len); + + p += cell_in->create_cell.handshake_len; + *len_out = p - payload_out; + } + break; + default: + return -1; + } + + return 0; +} + +/** Format the EXTENDED{,2} cell in cell_in, storing its relay payload + * in payload_out, the number of bytes used in *len_out, and the + * relay command in *command_out. The payload_out must have + * RELAY_PAYLOAD_SIZE bytes available. Return 0 on success, -1 on failure. */ +int +extended_cell_format(uint8_t *command_out, uint16_t *len_out, + uint8_t *payload_out, const extended_cell_t *cell_in) +{ + uint8_t *p; + if (check_extended_cell(cell_in) < 0) + return -1; + + p = payload_out; + memset(p, 0, RELAY_PAYLOAD_SIZE); + + switch (cell_in->cell_type) { + case RELAY_COMMAND_EXTENDED: + { + *command_out = RELAY_COMMAND_EXTENDED; + *len_out = TAP_ONIONSKIN_REPLY_LEN; + memcpy(payload_out, cell_in->created_cell.reply, + TAP_ONIONSKIN_REPLY_LEN); + } + break; + case RELAY_COMMAND_EXTENDED2: + { + *command_out = RELAY_COMMAND_EXTENDED2; + *len_out = 2 + cell_in->created_cell.handshake_len; + set_uint16(payload_out, htons(cell_in->created_cell.handshake_len)); + if (2+cell_in->created_cell.handshake_len > RELAY_PAYLOAD_SIZE) + return -1; + memcpy(payload_out+2, cell_in->created_cell.reply, + cell_in->created_cell.handshake_len); + } + break; + default: + return -1; + } + + return 0; +} + diff --git a/src/tor/onion.h b/src/tor/onion.h new file mode 100644 index 0000000..d62f032 --- /dev/null +++ b/src/tor/onion.h @@ -0,0 +1,122 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file onion.h + * \brief Header file for onion.c. + **/ + +#ifndef TOR_ONION_H +#define TOR_ONION_H + +struct create_cell_t; +int onion_pending_add(or_circuit_t *circ, struct create_cell_t *onionskin); +or_circuit_t *onion_next_task(struct create_cell_t **onionskin_out); +int onion_num_pending(uint16_t handshake_type); +void onion_pending_remove(or_circuit_t *circ); +void clear_pending_onions(void); + +typedef struct server_onion_keys_t { + uint8_t my_identity[DIGEST_LEN]; + crypto_pk_t *onion_key; + crypto_pk_t *last_onion_key; +#ifdef CURVE25519_ENABLED + di_digest256_map_t *curve25519_key_map; + curve25519_keypair_t *junk_keypair; +#endif +} server_onion_keys_t; + +#define MAX_ONIONSKIN_CHALLENGE_LEN 255 +#define MAX_ONIONSKIN_REPLY_LEN 255 + +void setup_server_onion_keys(server_onion_keys_t *keys); +void release_server_onion_keys(server_onion_keys_t *keys); + +void onion_handshake_state_release(onion_handshake_state_t *state); + +int onion_skin_create(int type, + const extend_info_t *node, + onion_handshake_state_t *state_out, + uint8_t *onion_skin_out); +int onion_skin_server_handshake(int type, + const uint8_t *onion_skin, size_t onionskin_len, + const server_onion_keys_t *keys, + uint8_t *reply_out, + uint8_t *keys_out, size_t key_out_len, + uint8_t *rend_nonce_out); +int onion_skin_client_handshake(int type, + const onion_handshake_state_t *handshake_state, + const uint8_t *reply, size_t reply_len, + uint8_t *keys_out, size_t key_out_len, + uint8_t *rend_authenticator_out); + +/** A parsed CREATE, CREATE_FAST, or CREATE2 cell. */ +typedef struct create_cell_t { + /** The cell command. One of CREATE{,_FAST,2} */ + uint8_t cell_type; + /** One of the ONION_HANDSHAKE_TYPE_* values */ + uint16_t handshake_type; + /** The number of bytes used in onionskin. */ + uint16_t handshake_len; + /** The client-side message for the circuit creation handshake. */ + uint8_t onionskin[CELL_PAYLOAD_SIZE - 4]; +} create_cell_t; + +/** A parsed CREATED, CREATED_FAST, or CREATED2 cell. */ +typedef struct created_cell_t { + /** The cell command. One of CREATED{,_FAST,2} */ + uint8_t cell_type; + /** The number of bytes used in reply. */ + uint16_t handshake_len; + /** The server-side message for the circuit creation handshake. */ + uint8_t reply[CELL_PAYLOAD_SIZE - 2]; +} created_cell_t; + +/** A parsed RELAY_EXTEND or RELAY_EXTEND2 cell */ +typedef struct extend_cell_t { + /** One of RELAY_EXTEND or RELAY_EXTEND2 */ + uint8_t cell_type; + /** An IPv4 address and port for the node we're connecting to. */ + tor_addr_port_t orport_ipv4; + /** An IPv6 address and port for the node we're connecting to. Not currently + * used. */ + tor_addr_port_t orport_ipv6; + /** Identity fingerprint of the node we're conecting to.*/ + uint8_t node_id[DIGEST_LEN]; + /** The "create cell" embedded in this extend cell. Note that unlike the + * create cells we generate ourself, this once can have a handshake type we + * don't recognize. */ + create_cell_t create_cell; +} extend_cell_t; + +/** A parsed RELAY_EXTEND or RELAY_EXTEND2 cell */ +typedef struct extended_cell_t { + /** One of RELAY_EXTENDED or RELAY_EXTENDED2. */ + uint8_t cell_type; + /** The "created cell" embedded in this extended cell. */ + created_cell_t created_cell; +} extended_cell_t; + +void create_cell_init(create_cell_t *cell_out, uint8_t cell_type, + uint16_t handshake_type, uint16_t handshake_len, + const uint8_t *onionskin); +int create_cell_parse(create_cell_t *cell_out, const cell_t *cell_in); +int created_cell_parse(created_cell_t *cell_out, const cell_t *cell_in); +int extend_cell_parse(extend_cell_t *cell_out, const uint8_t command, + const uint8_t *payload_in, size_t payload_len); +int extended_cell_parse(extended_cell_t *cell_out, const uint8_t command, + const uint8_t *payload_in, size_t payload_len); + +int create_cell_format(cell_t *cell_out, const create_cell_t *cell_in); +int create_cell_format_relayed(cell_t *cell_out, const create_cell_t *cell_in); +int created_cell_format(cell_t *cell_out, const created_cell_t *cell_in); +int extend_cell_format(uint8_t *command_out, uint16_t *len_out, + uint8_t *payload_out, const extend_cell_t *cell_in); +int extended_cell_format(uint8_t *command_out, uint16_t *len_out, + uint8_t *payload_out, const extended_cell_t *cell_in); + +#endif + diff --git a/src/tor/onion_fast.c b/src/tor/onion_fast.c new file mode 100644 index 0000000..8e778db --- /dev/null +++ b/src/tor/onion_fast.c @@ -0,0 +1,123 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file onion_fast.c + * \brief Functions implement the CREATE_FAST circuit handshake. + **/ + +#include "or.h" +#include "onion_fast.h" + +/** Release all state held in victim. */ +void +fast_handshake_state_free(fast_handshake_state_t *victim) +{ + if (! victim) + return; + memwipe(victim, 0, sizeof(fast_handshake_state_t)); + tor_free(victim); +} + +/** Create the state needed to perform a CREATE_FAST handshake. Return 0 + * on success, -1 on failure. */ +int +fast_onionskin_create(fast_handshake_state_t **handshake_state_out, + uint8_t *handshake_out) +{ + fast_handshake_state_t *s; + *handshake_state_out = s = tor_malloc(sizeof(fast_handshake_state_t)); + if (crypto_rand((char*)s->state, sizeof(s->state)) < 0) { + tor_free(s); + return -1; + } + memcpy(handshake_out, s->state, DIGEST_LEN); + return 0; +} + +/** Implement the server side of the CREATE_FAST abbreviated handshake. The + * client has provided DIGEST_LEN key bytes in key_in ("x"). We + * generate a reply of DIGEST_LEN*2 bytes in key_out, consisting of a + * new random "y", followed by H(x|y) to check for correctness. We set + * key_out_len bytes of key material in key_out. + * Return 0 on success, <0 on failure. + **/ +int +fast_server_handshake(const uint8_t *key_in, /* DIGEST_LEN bytes */ + uint8_t *handshake_reply_out, /* DIGEST_LEN*2 bytes */ + uint8_t *key_out, + size_t key_out_len) +{ + uint8_t tmp[DIGEST_LEN+DIGEST_LEN]; + uint8_t *out = NULL; + size_t out_len; + int r = -1; + + if (crypto_rand((char*)handshake_reply_out, DIGEST_LEN)<0) + return -1; + + memcpy(tmp, key_in, DIGEST_LEN); + memcpy(tmp+DIGEST_LEN, handshake_reply_out, DIGEST_LEN); + out_len = key_out_len+DIGEST_LEN; + out = tor_malloc(out_len); + if (crypto_expand_key_material_TAP(tmp, sizeof(tmp), out, out_len)) { + goto done; + } + memcpy(handshake_reply_out+DIGEST_LEN, out, DIGEST_LEN); + memcpy(key_out, out+DIGEST_LEN, key_out_len); + r = 0; + done: + memwipe(tmp, 0, sizeof(tmp)); + memwipe(out, 0, out_len); + tor_free(out); + return r; +} + +/** Implement the second half of the client side of the CREATE_FAST handshake. + * We sent the server handshake_state ("x") already, and the server + * told us handshake_reply_out (y|H(x|y)). Make sure that the hash is + * correct, and generate key material in key_out. Return 0 on success, + * true on failure. + * + * NOTE: The "CREATE_FAST" handshake path is distinguishable from regular + * "onionskin" handshakes, and is not secure if an adversary can see or modify + * the messages. Therefore, it should only be used by clients, and only as + * the first hop of a circuit (since the first hop is already authenticated + * and protected by TLS). + */ +int +fast_client_handshake(const fast_handshake_state_t *handshake_state, + const uint8_t *handshake_reply_out,/*DIGEST_LEN*2 bytes*/ + uint8_t *key_out, + size_t key_out_len) +{ + uint8_t tmp[DIGEST_LEN+DIGEST_LEN]; + uint8_t *out; + size_t out_len; + int r = -1; + + memcpy(tmp, handshake_state->state, DIGEST_LEN); + memcpy(tmp+DIGEST_LEN, handshake_reply_out, DIGEST_LEN); + out_len = key_out_len+DIGEST_LEN; + out = tor_malloc(out_len); + if (crypto_expand_key_material_TAP(tmp, sizeof(tmp), out, out_len)) { + goto done; + } + if (tor_memneq(out, handshake_reply_out+DIGEST_LEN, DIGEST_LEN)) { + /* H(K) does *not* match. Something fishy. */ + log_warn(LD_PROTOCOL,"Digest DOES NOT MATCH on fast handshake. " + "Bug or attack."); + goto done; + } + memcpy(key_out, out+DIGEST_LEN, key_out_len); + r = 0; + done: + memwipe(tmp, 0, sizeof(tmp)); + memwipe(out, 0, out_len); + tor_free(out); + return r; +} + diff --git a/src/tor/onion_fast.h b/src/tor/onion_fast.h new file mode 100644 index 0000000..8c07837 --- /dev/null +++ b/src/tor/onion_fast.h @@ -0,0 +1,38 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file onion_fast.h + * \brief Header file for onion_fast.c. + **/ + +#ifndef TOR_ONION_FAST_H +#define TOR_ONION_FAST_H + +#define CREATE_FAST_LEN DIGEST_LEN +#define CREATED_FAST_LEN (DIGEST_LEN*2) + +typedef struct fast_handshake_state_t { + uint8_t state[DIGEST_LEN]; +} fast_handshake_state_t; + +void fast_handshake_state_free(fast_handshake_state_t *victim); + +int fast_onionskin_create(fast_handshake_state_t **handshake_state_out, + uint8_t *handshake_out); + +int fast_server_handshake(const uint8_t *message_in, + uint8_t *handshake_reply_out, + uint8_t *key_out, + size_t key_out_len); + +int fast_client_handshake(const fast_handshake_state_t *handshake_state, + const uint8_t *handshake_reply_out, + uint8_t *key_out, + size_t key_out_len); + +#endif + diff --git a/src/tor/onion_main.c b/src/tor/onion_main.c new file mode 100644 index 0000000..9fe915b --- /dev/null +++ b/src/tor/onion_main.c @@ -0,0 +1,2908 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file onion_main.c + * \brief Toplevel module. Handles signals, multiplexes between + * connections, implements main loop, and drives scheduled events. + **/ + +#define MAIN_PRIVATE +#include "or.h" +#include "addressmap.h" +#include "backtrace.h" +#include "buffers.h" +#include "channel.h" +#include "channeltls.h" +#include "circuitbuild.h" +#include "circuitlist.h" +#include "circuituse.h" +#include "command.h" +#include "config.h" +#include "confparse.h" +#include "connection.h" +#include "connection_edge.h" +#include "connection_or.h" +#include "control.h" +#include "cpuworker.h" +#include "directory.h" +#include "dirserv.h" +#include "dirvote.h" +#include "dns.h" +#include "dnsserv.h" +#include "entrynodes.h" +#include "geoip.h" +#include "hibernate.h" +#include "onion_main.h" +#include "microdesc.h" +#include "networkstatus.h" +#include "nodelist.h" +#include "ntmain.h" +#include "onion.h" +#include "policies.h" +#include "transports.h" +#include "relay.h" +#include "rendclient.h" +#include "rendcommon.h" +#include "rendservice.h" +#include "rephist.h" +#include "router.h" +#include "routerlist.h" +#include "routerparse.h" +#include "statefile.h" +#include "status.h" +#include "ext_orport.h" +#include "anonymize.h" +#ifdef USE_DMALLOC +#include +#include +#endif +#include "memarea.h" +#include "sandbox.h" + +#ifdef HAVE_EVENT2_EVENT_H +#include +#else +#include +#endif + +#ifdef USE_BUFFEREVENTS +#include +#endif + +void evdns_shutdown(int); + +/********* PROTOTYPES **********/ + +static void dumpmemusage(int severity); +static void dumpstats(int severity); /* log stats */ +static void conn_read_callback(evutil_socket_t fd, short event, void *_conn); +static void conn_write_callback(evutil_socket_t fd, short event, void *_conn); +static void second_elapsed_callback(periodic_timer_t *timer, void *args); +static int conn_close_if_marked(int i); +static void connection_start_reading_from_linked_conn(connection_t *conn); +static int connection_should_read_from_linked_conn(connection_t *conn); + +/********* START VARIABLES **********/ + +#ifndef USE_BUFFEREVENTS +int global_read_bucket; /**< Max number of bytes I can read this second. */ +int global_write_bucket; /**< Max number of bytes I can write this second. */ + +/** Max number of relayed (bandwidth class 1) bytes I can read this second. */ +int global_relayed_read_bucket; +/** Max number of relayed (bandwidth class 1) bytes I can write this second. */ +int global_relayed_write_bucket; +/** What was the read bucket before the last second_elapsed_callback() call? + * (used to determine how many bytes we've read). */ +static int stats_prev_global_read_bucket; +/** What was the write bucket before the last second_elapsed_callback() call? + * (used to determine how many bytes we've written). */ +static int stats_prev_global_write_bucket; +#endif + +/* DOCDOC stats_prev_n_read */ +static uint64_t stats_prev_n_read = 0; +/* DOCDOC stats_prev_n_written */ +static uint64_t stats_prev_n_written = 0; + +/* XXX we might want to keep stats about global_relayed_*_bucket too. Or not.*/ +/** How many bytes have we read since we started the process? */ +static uint64_t stats_n_bytes_read = 0; +/** How many bytes have we written since we started the process? */ +static uint64_t stats_n_bytes_written = 0; +/** What time did this process start up? */ +time_t time_of_process_start = 0; +/** How many seconds have we been running? */ +long stats_n_seconds_working = 0; +/** When do we next launch DNS wildcarding checks? */ +static time_t time_to_check_for_correct_dns = 0; + +/** How often will we honor SIGNEWNYM requests? */ +#define MAX_SIGNEWNYM_RATE 10 +/** When did we last process a SIGNEWNYM request? */ +static time_t time_of_last_signewnym = 0; +/** Is there a signewnym request we're currently waiting to handle? */ +static int signewnym_is_pending = 0; +/** How many times have we called newnym? */ +static unsigned newnym_epoch = 0; + +/** Smartlist of all open connections. */ +static smartlist_t *connection_array = NULL; +/** List of connections that have been marked for close and need to be freed + * and removed from connection_array. */ +static smartlist_t *closeable_connection_lst = NULL; +/** List of linked connections that are currently reading data into their + * inbuf from their partner's outbuf. */ +static smartlist_t *active_linked_connection_lst = NULL; +/** Flag: Set to true iff we entered the current libevent main loop via + * loop_once. If so, there's no need to trigger a loopexit in order + * to handle linked connections. */ +static int called_loop_once = 0; + +/** We set this to 1 when we've opened a circuit, so we can print a log + * entry to inform the user that Tor is working. We set it to 0 when + * we think the fact that we once opened a circuit doesn't mean we can do so + * any longer (a big time jump happened, when we notice our directory is + * heinously out-of-date, etc. + */ +int can_complete_circuit=0; + +const char tor_git_revision[] = ""; + +/** How often do we check for router descriptors that we should download + * when we have too little directory info? */ +#define GREEDY_DESCRIPTOR_RETRY_INTERVAL (10) +/** How often do we check for router descriptors that we should download + * when we have enough directory info? */ +#define LAZY_DESCRIPTOR_RETRY_INTERVAL (60) +/** How often do we 'forgive' undownloadable router descriptors and attempt + * to download them again? */ +#define DESCRIPTOR_FAILURE_RESET_INTERVAL (60*60) + +/** Decides our behavior when no logs are configured/before any + * logs have been configured. For 0, we log notice to stdout as normal. + * For 1, we log warnings only. For 2, we log nothing. + */ +int quiet_level = 0; + +/********* END VARIABLES ************/ + +/**************************************************************************** +* +* This section contains accessors and other methods on the connection_array +* variables (which are global within this file and unavailable outside it). +* +****************************************************************************/ + +#if 0 && defined(USE_BUFFEREVENTS) +static void +free_old_inbuf(connection_t *conn) +{ + if (! conn->inbuf) + return; + + tor_assert(conn->outbuf); + tor_assert(buf_datalen(conn->inbuf) == 0); + tor_assert(buf_datalen(conn->outbuf) == 0); + buf_free(conn->inbuf); + buf_free(conn->outbuf); + conn->inbuf = conn->outbuf = NULL; + + if (conn->read_event) { + event_del(conn->read_event); + tor_event_free(conn->read_event); + } + if (conn->write_event) { + event_del(conn->read_event); + tor_event_free(conn->write_event); + } + conn->read_event = conn->write_event = NULL; +} +#endif + +#if defined(_WIN32) && defined(USE_BUFFEREVENTS) +/** Remove the kernel-space send and receive buffers for s. For use + * with IOCP only. */ +static int +set_buffer_lengths_to_zero(tor_socket_t s) +{ + int zero = 0; + int r = 0; + if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, (void*)&zero, sizeof(zero))) { + log_warn(LD_NET, "Unable to clear SO_SNDBUF"); + r = -1; + } + if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, (void*)&zero, sizeof(zero))) { + log_warn(LD_NET, "Unable to clear SO_RCVBUF"); + r = -1; + } + return r; +} +#endif + +/** Add conn to the array of connections that we can poll on. The + * connection's socket must be set; the connection starts out + * non-reading and non-writing. + */ +int +connection_add_impl(connection_t *conn, int is_connecting) +{ + tor_assert(conn); + tor_assert(SOCKET_OK(conn->s) || + conn->linked || + (conn->type == CONN_TYPE_AP && + TO_EDGE_CONN(conn)->is_dns_request)); + + tor_assert(conn->conn_array_index == -1); /* can only connection_add once */ + conn->conn_array_index = smartlist_len(connection_array); + smartlist_add(connection_array, conn); + +#ifdef USE_BUFFEREVENTS + if (connection_type_uses_bufferevent(conn)) { + if (SOCKET_OK(conn->s) && !conn->linked) { + +#ifdef _WIN32 + if (tor_libevent_using_iocp_bufferevents() && + get_options()->UserspaceIOCPBuffers) { + set_buffer_lengths_to_zero(conn->s); + } +#endif + + conn->bufev = bufferevent_socket_new( + tor_libevent_get_base(), + conn->s, + BEV_OPT_DEFER_CALLBACKS); + if (!conn->bufev) { + log_warn(LD_BUG, "Unable to create socket bufferevent"); + smartlist_del(connection_array, conn->conn_array_index); + conn->conn_array_index = -1; + return -1; + } + if (is_connecting) { + /* Put the bufferevent into a "connecting" state so that we'll get + * a "connected" event callback on successful write. */ + bufferevent_socket_connect(conn->bufev, NULL, 0); + } + connection_configure_bufferevent_callbacks(conn); + } else if (conn->linked && conn->linked_conn && + connection_type_uses_bufferevent(conn->linked_conn)) { + tor_assert(!(SOCKET_OK(conn->s))); + if (!conn->bufev) { + struct bufferevent *pair[2] = { NULL, NULL }; + if (bufferevent_pair_new(tor_libevent_get_base(), + BEV_OPT_DEFER_CALLBACKS, + pair) < 0) { + log_warn(LD_BUG, "Unable to create bufferevent pair"); + smartlist_del(connection_array, conn->conn_array_index); + conn->conn_array_index = -1; + return -1; + } + tor_assert(pair[0]); + conn->bufev = pair[0]; + conn->linked_conn->bufev = pair[1]; + } /* else the other side already was added, and got a bufferevent_pair */ + connection_configure_bufferevent_callbacks(conn); + } else { + tor_assert(!conn->linked); + } + + if (conn->bufev) + tor_assert(conn->inbuf == NULL); + + if (conn->linked_conn && conn->linked_conn->bufev) + tor_assert(conn->linked_conn->inbuf == NULL); + } +#else + (void) is_connecting; +#endif + + if (!HAS_BUFFEREVENT(conn) && (SOCKET_OK(conn->s) || conn->linked)) { + conn->read_event = tor_event_new(tor_libevent_get_base(), + conn->s, EV_READ|EV_PERSIST, conn_read_callback, conn); + conn->write_event = tor_event_new(tor_libevent_get_base(), + conn->s, EV_WRITE|EV_PERSIST, conn_write_callback, conn); + /* XXXX CHECK FOR NULL RETURN! */ + } + + log_debug(LD_NET,"new conn type %s, socket %d, address %s, n_conns %d.", + conn_type_to_string(conn->type), (int)conn->s, conn->address, + smartlist_len(connection_array)); + + return 0; +} + +/** Tell libevent that we don't care about conn any more. */ +void +connection_unregister_events(connection_t *conn) +{ + if (conn->read_event) { + if (event_del(conn->read_event)) + log_warn(LD_BUG, "Error removing read event for %d", (int)conn->s); + tor_free(conn->read_event); + } + if (conn->write_event) { + if (event_del(conn->write_event)) + log_warn(LD_BUG, "Error removing write event for %d", (int)conn->s); + tor_free(conn->write_event); + } +#ifdef USE_BUFFEREVENTS + if (conn->bufev) { + bufferevent_free(conn->bufev); + conn->bufev = NULL; + } +#endif + if (conn->type == CONN_TYPE_AP_DNS_LISTENER) { + dnsserv_close_listener(conn); + } +} + +/** Remove the connection from the global list, and remove the + * corresponding poll entry. Calling this function will shift the last + * connection (if any) into the position occupied by conn. + */ +int +connection_remove(connection_t *conn) +{ + int current_index; + connection_t *tmp; + + tor_assert(conn); + + log_debug(LD_NET,"removing socket %d (type %s), n_conns now %d", + (int)conn->s, conn_type_to_string(conn->type), + smartlist_len(connection_array)); + + control_event_conn_bandwidth(conn); + + tor_assert(conn->conn_array_index >= 0); + current_index = conn->conn_array_index; + connection_unregister_events(conn); /* This is redundant, but cheap. */ + if (current_index == smartlist_len(connection_array)-1) { /* at the end */ + smartlist_del(connection_array, current_index); + return 0; + } + + /* replace this one with the one at the end */ + smartlist_del(connection_array, current_index); + tmp = smartlist_get(connection_array, current_index); + tmp->conn_array_index = current_index; + + return 0; +} + +/** If conn is an edge conn, remove it from the list + * of conn's on this circuit. If it's not on an edge, + * flush and send destroys for all circuits on this conn. + * + * Remove it from connection_array (if applicable) and + * from closeable_connection_list. + * + * Then free it. + */ +static void +connection_unlink(connection_t *conn) +{ + connection_about_to_close_connection(conn); + if (conn->conn_array_index >= 0) { + connection_remove(conn); + } + if (conn->linked_conn) { + conn->linked_conn->linked_conn = NULL; + if (! conn->linked_conn->marked_for_close && + conn->linked_conn->reading_from_linked_conn) + connection_start_reading(conn->linked_conn); + conn->linked_conn = NULL; + } + smartlist_remove(closeable_connection_lst, conn); + smartlist_remove(active_linked_connection_lst, conn); + if (conn->type == CONN_TYPE_EXIT) { + assert_connection_edge_not_dns_pending(TO_EDGE_CONN(conn)); + } + if (conn->type == CONN_TYPE_OR) { + if (!tor_digest_is_zero(TO_OR_CONN(conn)->identity_digest)) + connection_or_remove_from_identity_map(TO_OR_CONN(conn)); + /* connection_unlink() can only get called if the connection + * was already on the closeable list, and it got there by + * connection_mark_for_close(), which was called from + * connection_or_close_normally() or + * connection_or_close_for_error(), so the channel should + * already be in CHANNEL_STATE_CLOSING, and then the + * connection_about_to_close_connection() goes to + * connection_or_about_to_close(), which calls channel_closed() + * to notify the channel_t layer, and closed the channel, so + * nothing more to do here to deal with the channel associated + * with an orconn. + */ + } + connection_free(conn); +} + +/** Initialize the global connection list, closeable connection list, + * and active connection list. */ +STATIC void +init_connection_lists(void) +{ + if (!connection_array) + connection_array = smartlist_new(); + if (!closeable_connection_lst) + closeable_connection_lst = smartlist_new(); + if (!active_linked_connection_lst) + active_linked_connection_lst = smartlist_new(); +} + +/** Schedule conn to be closed. **/ +void +add_connection_to_closeable_list(connection_t *conn) +{ + tor_assert(!smartlist_contains(closeable_connection_lst, conn)); + tor_assert(conn->marked_for_close); + assert_connection_ok(conn, time(NULL)); + smartlist_add(closeable_connection_lst, conn); +} + +/** Return 1 if conn is on the closeable list, else return 0. */ +int +connection_is_on_closeable_list(connection_t *conn) +{ + return smartlist_contains(closeable_connection_lst, conn); +} + +/** Return true iff conn is in the current poll array. */ +int +connection_in_array(connection_t *conn) +{ + return smartlist_contains(connection_array, conn); +} + +/** Set *array to an array of all connections, and *n + * to the length of the array. *array and *n must not + * be modified. + */ +smartlist_t * +get_connection_array(void) +{ + if (!connection_array) + connection_array = smartlist_new(); + return connection_array; +} + +/** Provides the traffic read and written over the life of the process. */ + +uint64_t +get_bytes_read(void) +{ + return stats_n_bytes_read; +} + +/* DOCDOC get_bytes_written */ +uint64_t +get_bytes_written(void) +{ + return stats_n_bytes_written; +} + +/** Set the event mask on conn to events. (The event + * mask is a bitmask whose bits are READ_EVENT and WRITE_EVENT) + */ +void +connection_watch_events(connection_t *conn, watchable_events_t events) +{ + IF_HAS_BUFFEREVENT(conn, { + short ev = ((short)events) & (EV_READ|EV_WRITE); + short old_ev = bufferevent_get_enabled(conn->bufev); + if ((ev & ~old_ev) != 0) { + bufferevent_enable(conn->bufev, ev); + } + if ((old_ev & ~ev) != 0) { + bufferevent_disable(conn->bufev, old_ev & ~ev); + } + return; + }); + if (events & READ_EVENT) + connection_start_reading(conn); + else + connection_stop_reading(conn); + + if (events & WRITE_EVENT) + connection_start_writing(conn); + else + connection_stop_writing(conn); +} + +/** Return true iff conn is listening for read events. */ +int +connection_is_reading(connection_t *conn) +{ + tor_assert(conn); + + IF_HAS_BUFFEREVENT(conn, + return (bufferevent_get_enabled(conn->bufev) & EV_READ) != 0; + ); + return conn->reading_from_linked_conn || + (conn->read_event && event_pending(conn->read_event, EV_READ, NULL)); +} + +/** Tell the main loop to stop notifying conn of any read events. */ +MOCK_IMPL(void, +connection_stop_reading,(connection_t *conn)) +{ + tor_assert(conn); + + IF_HAS_BUFFEREVENT(conn, { + bufferevent_disable(conn->bufev, EV_READ); + return; + }); + + tor_assert(conn->read_event); + + if (conn->linked) { + conn->reading_from_linked_conn = 0; + connection_stop_reading_from_linked_conn(conn); + } else { + if (event_del(conn->read_event)) + log_warn(LD_NET, "Error from libevent setting read event state for %d " + "to unwatched: %s", + (int)conn->s, + tor_socket_strerror(tor_socket_errno(conn->s))); + } +} + +/** Tell the main loop to start notifying conn of any read events. */ +MOCK_IMPL(void, +connection_start_reading,(connection_t *conn)) +{ + tor_assert(conn); + + IF_HAS_BUFFEREVENT(conn, { + bufferevent_enable(conn->bufev, EV_READ); + return; + }); + + tor_assert(conn->read_event); + + if (conn->linked) { + conn->reading_from_linked_conn = 1; + if (connection_should_read_from_linked_conn(conn)) + connection_start_reading_from_linked_conn(conn); + } else { + if (event_add(conn->read_event, NULL)) + log_warn(LD_NET, "Error from libevent setting read event state for %d " + "to watched: %s", + (int)conn->s, + tor_socket_strerror(tor_socket_errno(conn->s))); + } +} + +/** Return true iff conn is listening for write events. */ +int +connection_is_writing(connection_t *conn) +{ + tor_assert(conn); + + IF_HAS_BUFFEREVENT(conn, + return (bufferevent_get_enabled(conn->bufev) & EV_WRITE) != 0; + ); + + return conn->writing_to_linked_conn || + (conn->write_event && event_pending(conn->write_event, EV_WRITE, NULL)); +} + +/** Tell the main loop to stop notifying conn of any write events. */ +MOCK_IMPL(void, +connection_stop_writing,(connection_t *conn)) +{ + tor_assert(conn); + + IF_HAS_BUFFEREVENT(conn, { + bufferevent_disable(conn->bufev, EV_WRITE); + return; + }); + + tor_assert(conn->write_event); + + if (conn->linked) { + conn->writing_to_linked_conn = 0; + if (conn->linked_conn) + connection_stop_reading_from_linked_conn(conn->linked_conn); + } else { + if (event_del(conn->write_event)) + log_warn(LD_NET, "Error from libevent setting write event state for %d " + "to unwatched: %s", + (int)conn->s, + tor_socket_strerror(tor_socket_errno(conn->s))); + } +} + +/** Tell the main loop to start notifying conn of any write events. */ +MOCK_IMPL(void, +connection_start_writing,(connection_t *conn)) +{ + tor_assert(conn); + + IF_HAS_BUFFEREVENT(conn, { + bufferevent_enable(conn->bufev, EV_WRITE); + return; + }); + + tor_assert(conn->write_event); + + if (conn->linked) { + conn->writing_to_linked_conn = 1; + if (conn->linked_conn && + connection_should_read_from_linked_conn(conn->linked_conn)) + connection_start_reading_from_linked_conn(conn->linked_conn); + } else { + if (event_add(conn->write_event, NULL)) + log_warn(LD_NET, "Error from libevent setting write event state for %d " + "to watched: %s", + (int)conn->s, + tor_socket_strerror(tor_socket_errno(conn->s))); + } +} + +/** Return true iff conn is linked conn, and reading from the conn + * linked to it would be good and feasible. (Reading is "feasible" if the + * other conn exists and has data in its outbuf, and is "good" if we have our + * reading_from_linked_conn flag set and the other conn has its + * writing_to_linked_conn flag set.)*/ +static int +connection_should_read_from_linked_conn(connection_t *conn) +{ + if (conn->linked && conn->reading_from_linked_conn) { + if (! conn->linked_conn || + (conn->linked_conn->writing_to_linked_conn && + buf_datalen(conn->linked_conn->outbuf))) + return 1; + } + return 0; +} + +/** Helper: Tell the main loop to begin reading bytes into conn from + * its linked connection, if it is not doing so already. Called by + * connection_start_reading and connection_start_writing as appropriate. */ +static void +connection_start_reading_from_linked_conn(connection_t *conn) +{ + tor_assert(conn); + tor_assert(conn->linked == 1); + + if (!conn->active_on_link) { + conn->active_on_link = 1; + smartlist_add(active_linked_connection_lst, conn); + if (!called_loop_once) { + /* This is the first event on the list; we won't be in LOOP_ONCE mode, + * so we need to make sure that the event_base_loop() actually exits at + * the end of its run through the current connections and lets us + * activate read events for linked connections. */ + struct timeval tv = { 0, 0 }; + tor_event_base_loopexit(tor_libevent_get_base(), &tv); + } + } else { + tor_assert(smartlist_contains(active_linked_connection_lst, conn)); + } +} + +/** Tell the main loop to stop reading bytes into conn from its linked + * connection, if is currently doing so. Called by connection_stop_reading, + * connection_stop_writing, and connection_read. */ +void +connection_stop_reading_from_linked_conn(connection_t *conn) +{ + tor_assert(conn); + tor_assert(conn->linked == 1); + + if (conn->active_on_link) { + conn->active_on_link = 0; + /* FFFF We could keep an index here so we can smartlist_del + * cleanly. On the other hand, this doesn't show up on profiles, + * so let's leave it alone for now. */ + smartlist_remove(active_linked_connection_lst, conn); + } else { + tor_assert(!smartlist_contains(active_linked_connection_lst, conn)); + } +} + +/** Close all connections that have been scheduled to get closed. */ +STATIC void +close_closeable_connections(void) +{ + int i; + for (i = 0; i < smartlist_len(closeable_connection_lst); ) { + connection_t *conn = smartlist_get(closeable_connection_lst, i); + if (conn->conn_array_index < 0) { + connection_unlink(conn); /* blow it away right now */ + } else { + if (!conn_close_if_marked(conn->conn_array_index)) + ++i; + } + } +} + +/** Libevent callback: this gets invoked when (connection_t*)conn has + * some data to read. */ +static void +conn_read_callback(evutil_socket_t fd, short event, void *_conn) +{ + connection_t *conn = _conn; + (void)fd; + (void)event; + + log_debug(LD_NET,"socket %d wants to read.",(int)conn->s); + + /* assert_connection_ok(conn, time(NULL)); */ + + if (connection_handle_read(conn) < 0) { + if (!conn->marked_for_close) { +#ifndef _WIN32 + log_warn(LD_BUG,"Unhandled error on read for %s connection " + "(fd %d); removing", + conn_type_to_string(conn->type), (int)conn->s); + tor_fragile_assert(); +#endif + if (CONN_IS_EDGE(conn)) + connection_edge_end_errno(TO_EDGE_CONN(conn)); + connection_mark_for_close(conn); + } + } + assert_connection_ok(conn, time(NULL)); + + if (smartlist_len(closeable_connection_lst)) + close_closeable_connections(); +} + +/** Libevent callback: this gets invoked when (connection_t*)conn has + * some data to write. */ +static void +conn_write_callback(evutil_socket_t fd, short events, void *_conn) +{ + connection_t *conn = _conn; + (void)fd; + (void)events; + + LOG_FN_CONN(conn, (LOG_DEBUG, LD_NET, "socket %d wants to write.", + (int)conn->s)); + + /* assert_connection_ok(conn, time(NULL)); */ + + if (connection_handle_write(conn, 0) < 0) { + if (!conn->marked_for_close) { + /* this connection is broken. remove it. */ + log_fn(LOG_WARN,LD_BUG, + "unhandled error on write for %s connection (fd %d); removing", + conn_type_to_string(conn->type), (int)conn->s); + tor_fragile_assert(); + if (CONN_IS_EDGE(conn)) { + /* otherwise we cry wolf about duplicate close */ + edge_connection_t *edge_conn = TO_EDGE_CONN(conn); + if (!edge_conn->end_reason) + edge_conn->end_reason = END_STREAM_REASON_INTERNAL; + edge_conn->edge_has_sent_end = 1; + } + connection_close_immediate(conn); /* So we don't try to flush. */ + connection_mark_for_close(conn); + } + } + assert_connection_ok(conn, time(NULL)); + + if (smartlist_len(closeable_connection_lst)) + close_closeable_connections(); +} + +/** If the connection at connection_array[i] is marked for close, then: + * - If it has data that it wants to flush, try to flush it. + * - If it _still_ has data to flush, and conn->hold_open_until_flushed is + * true, then leave the connection open and return. + * - Otherwise, remove the connection from connection_array and from + * all other lists, close it, and free it. + * Returns 1 if the connection was closed, 0 otherwise. + */ +static int +conn_close_if_marked(int i) +{ + connection_t *conn; + int retval; + time_t now; + + conn = smartlist_get(connection_array, i); + if (!conn->marked_for_close) + return 0; /* nothing to see here, move along */ + now = time(NULL); + assert_connection_ok(conn, now); + /* assert_all_pending_dns_resolves_ok(); */ + +#ifdef USE_BUFFEREVENTS + if (conn->bufev) { + if (conn->hold_open_until_flushed && + evbuffer_get_length(bufferevent_get_output(conn->bufev))) { + /* don't close yet. */ + return 0; + } + if (conn->linked_conn && ! conn->linked_conn->marked_for_close) { + /* We need to do this explicitly so that the linked connection + * notices that there was an EOF. */ + bufferevent_flush(conn->bufev, EV_WRITE, BEV_FINISHED); + } + } +#endif + + log_debug(LD_NET,"Cleaning up connection (fd "TOR_SOCKET_T_FORMAT").", + conn->s); + + /* If the connection we are about to close was trying to connect to + a proxy server and failed, the client won't be able to use that + proxy. We should warn the user about this. */ + if (conn->proxy_state == PROXY_INFANT) + log_failed_proxy_connection(conn); + + IF_HAS_BUFFEREVENT(conn, goto unlink); + if ((SOCKET_OK(conn->s) || conn->linked_conn) && + connection_wants_to_flush(conn)) { + /* s == -1 means it's an incomplete edge connection, or that the socket + * has already been closed as unflushable. */ + ssize_t sz = connection_bucket_write_limit(conn, now); + if (!conn->hold_open_until_flushed) + log_info(LD_NET, + "Conn (addr %s, fd %d, type %s, state %d) marked, but wants " + "to flush %d bytes. (Marked at %s:%d)", + escaped_safe_str_client(conn->address), + (int)conn->s, conn_type_to_string(conn->type), conn->state, + (int)conn->outbuf_flushlen, + conn->marked_for_close_file, conn->marked_for_close); + if (conn->linked_conn) { + retval = move_buf_to_buf(conn->linked_conn->inbuf, conn->outbuf, + &conn->outbuf_flushlen); + if (retval >= 0) { + /* The linked conn will notice that it has data when it notices that + * we're gone. */ + connection_start_reading_from_linked_conn(conn->linked_conn); + } + log_debug(LD_GENERAL, "Flushed last %d bytes from a linked conn; " + "%d left; flushlen %d; wants-to-flush==%d", retval, + (int)connection_get_outbuf_len(conn), + (int)conn->outbuf_flushlen, + connection_wants_to_flush(conn)); + } else if (connection_speaks_cells(conn)) { + if (conn->state == OR_CONN_STATE_OPEN) { + retval = flush_buf_tls(TO_OR_CONN(conn)->tls, conn->outbuf, sz, + &conn->outbuf_flushlen); + } else + retval = -1; /* never flush non-open broken tls connections */ + } else { + retval = flush_buf(conn->s, conn->outbuf, sz, &conn->outbuf_flushlen); + } + if (retval >= 0 && /* Technically, we could survive things like + TLS_WANT_WRITE here. But don't bother for now. */ + conn->hold_open_until_flushed && connection_wants_to_flush(conn)) { + if (retval > 0) { + LOG_FN_CONN(conn, (LOG_INFO,LD_NET, + "Holding conn (fd %d) open for more flushing.", + (int)conn->s)); + conn->timestamp_lastwritten = now; /* reset so we can flush more */ + } else if (sz == 0) { + /* Also, retval==0. If we get here, we didn't want to write anything + * (because of rate-limiting) and we didn't. */ + + /* Connection must flush before closing, but it's being rate-limited. + * Let's remove from Libevent, and mark it as blocked on bandwidth + * so it will be re-added on next token bucket refill. Prevents + * busy Libevent loops where we keep ending up here and returning + * 0 until we are no longer blocked on bandwidth. + */ + if (connection_is_writing(conn)) { + conn->write_blocked_on_bw = 1; + connection_stop_writing(conn); + } + if (connection_is_reading(conn)) { + /* XXXX024 We should make this code unreachable; if a connection is + * marked for close and flushing, there is no point in reading to it + * at all. Further, checking at this point is a bit of a hack: it + * would make much more sense to react in + * connection_handle_read_impl, or to just stop reading in + * mark_and_flush */ +#if 0 +#define MARKED_READING_RATE 180 + static ratelim_t marked_read_lim = RATELIM_INIT(MARKED_READING_RATE); + char *m; + if ((m = rate_limit_log(&marked_read_lim, now))) { + log_warn(LD_BUG, "Marked connection (fd %d, type %s, state %s) " + "is still reading; that shouldn't happen.%s", + (int)conn->s, conn_type_to_string(conn->type), + conn_state_to_string(conn->type, conn->state), m); + tor_free(m); + } +#endif + conn->read_blocked_on_bw = 1; + connection_stop_reading(conn); + } + } + return 0; + } + if (connection_wants_to_flush(conn)) { + int severity; + if (conn->type == CONN_TYPE_EXIT || + (conn->type == CONN_TYPE_OR && server_mode(get_options())) || + (conn->type == CONN_TYPE_DIR && conn->purpose == DIR_PURPOSE_SERVER)) + severity = LOG_INFO; + else + severity = LOG_NOTICE; + /* XXXX Maybe allow this to happen a certain amount per hour; it usually + * is meaningless. */ + log_fn(severity, LD_NET, "We stalled too much while trying to write %d " + "bytes to address %s. If this happens a lot, either " + "something is wrong with your network connection, or " + "something is wrong with theirs. " + "(fd %d, type %s, state %d, marked at %s:%d).", + (int)connection_get_outbuf_len(conn), + escaped_safe_str_client(conn->address), + (int)conn->s, conn_type_to_string(conn->type), conn->state, + conn->marked_for_close_file, + conn->marked_for_close); + } + } + +#ifdef USE_BUFFEREVENTS + unlink: +#endif + connection_unlink(conn); /* unlink, remove, free */ + return 1; +} + +/** We've just tried every dirserver we know about, and none of + * them were reachable. Assume the network is down. Change state + * so next time an application connection arrives we'll delay it + * and try another directory fetch. Kill off all the circuit_wait + * streams that are waiting now, since they will all timeout anyway. + */ +void +directory_all_unreachable(time_t now) +{ + connection_t *conn; + (void)now; + + stats_n_seconds_working=0; /* reset it */ + + while ((conn = connection_get_by_type_state(CONN_TYPE_AP, + AP_CONN_STATE_CIRCUIT_WAIT))) { + entry_connection_t *entry_conn = TO_ENTRY_CONN(conn); + log_notice(LD_NET, + "Is your network connection down? " + "Failing connection to '%s:%d'.", + safe_str_client(entry_conn->socks_request->address), + entry_conn->socks_request->port); + connection_mark_unattached_ap(entry_conn, + END_STREAM_REASON_NET_UNREACHABLE); + } + control_event_general_status(LOG_ERR, "DIR_ALL_UNREACHABLE"); +} + +/** This function is called whenever we successfully pull down some new + * network statuses or server descriptors. */ +void +directory_info_has_arrived(time_t now, int from_cache) +{ + const or_options_t *options = get_options(); + + if (!router_have_minimum_dir_info()) { + int quiet = from_cache || + directory_too_idle_to_fetch_descriptors(options, now); + tor_log(quiet ? LOG_INFO : LOG_NOTICE, LD_DIR, + "I learned some more directory information, but not enough to " + "build a circuit: %s", get_dir_info_status_string()); + update_all_descriptor_downloads(now); + return; + } else { + if (directory_fetches_from_authorities(options)) { + update_all_descriptor_downloads(now); + } + + /* if we have enough dir info, then update our guard status with + * whatever we just learned. */ + entry_guards_compute_status(options, now); + /* Don't even bother trying to get extrainfo until the rest of our + * directory info is up-to-date */ + if (options->DownloadExtraInfo) + update_extrainfo_downloads(now); + } + + if (server_mode(options) && !net_is_disabled() && !from_cache && + (can_complete_circuit || !any_predicted_circuits(now))) + consider_testing_reachability(1, 1); +} + +/** How long do we wait before killing OR connections with no circuits? + * In Tor versions up to 0.2.1.25 and 0.2.2.12-alpha, we waited 15 minutes + * before cancelling these connections, which caused fast relays to accrue + * many many idle connections. Hopefully 3 minutes is low enough that + * it kills most idle connections, without being so low that we cause + * clients to bounce on and off. + */ +#define IDLE_OR_CONN_TIMEOUT 180 + +/** Perform regular maintenance tasks for a single connection. This + * function gets run once per second per connection by run_scheduled_events. + */ +static void +run_connection_housekeeping(int i, time_t now) +{ + cell_t cell; + connection_t *conn = smartlist_get(connection_array, i); + const or_options_t *options = get_options(); + or_connection_t *or_conn; + int past_keepalive = + now >= conn->timestamp_lastwritten + options->KeepalivePeriod; + + if (conn->outbuf && !connection_get_outbuf_len(conn) && + conn->type == CONN_TYPE_OR) + TO_OR_CONN(conn)->timestamp_lastempty = now; + + if (conn->marked_for_close) { + /* nothing to do here */ + return; + } + + /* Expire any directory connections that haven't been active (sent + * if a server or received if a client) for 5 min */ + if (conn->type == CONN_TYPE_DIR && + ((DIR_CONN_IS_SERVER(conn) && + conn->timestamp_lastwritten + + options->TestingDirConnectionMaxStall < now) || + (!DIR_CONN_IS_SERVER(conn) && + conn->timestamp_lastread + + options->TestingDirConnectionMaxStall < now))) { + log_info(LD_DIR,"Expiring wedged directory conn (fd %d, purpose %d)", + (int)conn->s, conn->purpose); + /* This check is temporary; it's to let us know whether we should consider + * parsing partial serverdesc responses. */ + if (conn->purpose == DIR_PURPOSE_FETCH_SERVERDESC && + connection_get_inbuf_len(conn) >= 1024) { + log_info(LD_DIR,"Trying to extract information from wedged server desc " + "download."); + connection_dir_reached_eof(TO_DIR_CONN(conn)); + } else { + connection_mark_for_close(conn); + } + return; + } + + if (!connection_speaks_cells(conn)) + return; /* we're all done here, the rest is just for OR conns */ + + /* If we haven't written to an OR connection for a while, then either nuke + the connection or send a keepalive, depending. */ + + or_conn = TO_OR_CONN(conn); +#ifdef USE_BUFFEREVENTS + tor_assert(conn->bufev); +#else + tor_assert(conn->outbuf); +#endif + + if (channel_is_bad_for_new_circs(TLS_CHAN_TO_BASE(or_conn->chan)) && + !connection_or_get_num_circuits(or_conn)) { + /* It's bad for new circuits, and has no unmarked circuits on it: + * mark it now. */ + log_info(LD_OR, + "Expiring non-used OR connection to fd %d (%s:%d) [Too old].", + (int)conn->s, conn->address, conn->port); + if (conn->state == OR_CONN_STATE_CONNECTING) + connection_or_connect_failed(TO_OR_CONN(conn), + END_OR_CONN_REASON_TIMEOUT, + "Tor gave up on the connection"); + connection_or_close_normally(TO_OR_CONN(conn), 1); + } else if (!connection_state_is_open(conn)) { + if (past_keepalive) { + /* We never managed to actually get this connection open and happy. */ + log_info(LD_OR,"Expiring non-open OR connection to fd %d (%s:%d).", + (int)conn->s,conn->address, conn->port); + connection_or_close_normally(TO_OR_CONN(conn), 0); + } + } else if (we_are_hibernating() && + !connection_or_get_num_circuits(or_conn) && + !connection_get_outbuf_len(conn)) { + /* We're hibernating, there's no circuits, and nothing to flush.*/ + log_info(LD_OR,"Expiring non-used OR connection to fd %d (%s:%d) " + "[Hibernating or exiting].", + (int)conn->s,conn->address, conn->port); + connection_or_close_normally(TO_OR_CONN(conn), 1); + } else if (!connection_or_get_num_circuits(or_conn) && + now >= or_conn->timestamp_last_added_nonpadding + + IDLE_OR_CONN_TIMEOUT) { + log_info(LD_OR,"Expiring non-used OR connection to fd %d (%s:%d) " + "[idle %d].", (int)conn->s,conn->address, conn->port, + (int)(now - or_conn->timestamp_last_added_nonpadding)); + connection_or_close_normally(TO_OR_CONN(conn), 0); + } else if ( + now >= or_conn->timestamp_lastempty + options->KeepalivePeriod*10 && + now >= conn->timestamp_lastwritten + options->KeepalivePeriod*10) { + log_fn(LOG_PROTOCOL_WARN,LD_PROTOCOL, + "Expiring stuck OR connection to fd %d (%s:%d). (%d bytes to " + "flush; %d seconds since last write)", + (int)conn->s, conn->address, conn->port, + (int)connection_get_outbuf_len(conn), + (int)(now-conn->timestamp_lastwritten)); + connection_or_close_normally(TO_OR_CONN(conn), 0); + } else if (past_keepalive && !connection_get_outbuf_len(conn)) { + /* send a padding cell */ + log_fn(LOG_DEBUG,LD_OR,"Sending keepalive to (%s:%d)", + conn->address, conn->port); + memset(&cell,0,sizeof(cell_t)); + cell.command = CELL_PADDING; + connection_or_write_cell_to_buf(&cell, or_conn); + } +} + +/** Honor a NEWNYM request: make future requests unlinkable to past + * requests. */ +static void +signewnym_impl(time_t now) +{ + const or_options_t *options = get_options(); + if (!proxy_mode(options)) { + log_info(LD_CONTROL, "Ignoring SIGNAL NEWNYM because client functionality " + "is disabled."); + return; + } + + circuit_mark_all_dirty_circs_as_unusable(); + addressmap_clear_transient(); + rend_client_purge_state(); + time_of_last_signewnym = now; + signewnym_is_pending = 0; + + ++newnym_epoch; + + control_event_signal(SIGNEWNYM); +} + +/** Return the number of times that signewnym has been called. */ +unsigned +get_signewnym_epoch(void) +{ + return newnym_epoch; +} + +/** Perform regular maintenance tasks. This function gets run once per + * second by second_elapsed_callback(). + */ +static void +run_scheduled_events(time_t now) +{ + static time_t last_rotated_x509_certificate = 0; + static time_t time_to_check_v3_certificate = 0; + static time_t time_to_check_listeners = 0; + static time_t time_to_check_descriptor = 0; + static time_t time_to_download_networkstatus = 0; + static time_t time_to_shrink_memory = 0; + static time_t time_to_try_getting_descriptors = 0; + static time_t time_to_reset_descriptor_failures = 0; + static time_t time_to_add_entropy = 0; + static time_t time_to_write_bridge_status_file = 0; + static time_t time_to_downrate_stability = 0; + static time_t time_to_save_stability = 0; + static time_t time_to_clean_caches = 0; + static time_t time_to_recheck_bandwidth = 0; + static time_t time_to_check_for_expired_networkstatus = 0; + static time_t time_to_write_stats_files = 0; + static time_t time_to_write_bridge_stats = 0; + static time_t time_to_check_port_forwarding = 0; + static time_t time_to_launch_reachability_tests = 0; + static int should_init_bridge_stats = 1; + static time_t time_to_retry_dns_init = 0; + static time_t time_to_next_heartbeat = 0; + const or_options_t *options = get_options(); + + int is_server = server_mode(options); + int i; + int have_dir_info; + + /** 0. See if we've been asked to shut down and our timeout has + * expired; or if our bandwidth limits are exhausted and we + * should hibernate; or if it's time to wake up from hibernation. + */ + consider_hibernation(now); + +#if 0 + { + static time_t nl_check_time = 0; + if (nl_check_time <= now) { + nodelist_assert_ok(); + nl_check_time = now + 30; + } + } +#endif + + /* 0b. If we've deferred a signewnym, make sure it gets handled + * eventually. */ + if (signewnym_is_pending && + time_of_last_signewnym + MAX_SIGNEWNYM_RATE <= now) { + log_info(LD_CONTROL, "Honoring delayed NEWNYM request"); + signewnym_impl(now); + } + + /* 0c. If we've deferred log messages for the controller, handle them now */ + flush_pending_log_callbacks(); + + /** 1a. Every MIN_ONION_KEY_LIFETIME seconds, rotate the onion keys, + * shut down and restart all cpuworkers, and update the directory if + * necessary. + */ + if (is_server && + get_onion_key_set_at()+MIN_ONION_KEY_LIFETIME < now) { + log_info(LD_GENERAL,"Rotating onion key."); + rotate_onion_key(); + cpuworkers_rotate(); + if (router_rebuild_descriptor(1)<0) { + log_info(LD_CONFIG, "Couldn't rebuild router descriptor"); + } + if (advertised_server_mode() && !options->DisableNetwork) + router_upload_dir_desc_to_dirservers(0); + } + + if (!options->DisableNetwork && time_to_try_getting_descriptors < now) { + update_all_descriptor_downloads(now); + update_extrainfo_downloads(now); + if (router_have_minimum_dir_info()) + time_to_try_getting_descriptors = now + LAZY_DESCRIPTOR_RETRY_INTERVAL; + else + time_to_try_getting_descriptors = now + GREEDY_DESCRIPTOR_RETRY_INTERVAL; + } + + if (time_to_reset_descriptor_failures < now) { + router_reset_descriptor_download_failures(); + time_to_reset_descriptor_failures = + now + DESCRIPTOR_FAILURE_RESET_INTERVAL; + } + + if (options->UseBridges) + fetch_bridge_descriptors(options, now); + + /** 1b. Every MAX_SSL_KEY_LIFETIME_INTERNAL seconds, we change our + * TLS context. */ + if (!last_rotated_x509_certificate) + last_rotated_x509_certificate = now; + if (last_rotated_x509_certificate+MAX_SSL_KEY_LIFETIME_INTERNAL < now) { + log_info(LD_GENERAL,"Rotating tls context."); + if (router_initialize_tls_context() < 0) { + log_warn(LD_BUG, "Error reinitializing TLS context"); + /* XXX is it a bug here, that we just keep going? -RD */ + } + last_rotated_x509_certificate = now; + /* We also make sure to rotate the TLS connections themselves if they've + * been up for too long -- but that's done via is_bad_for_new_circs in + * connection_run_housekeeping() above. */ + } + + if (time_to_add_entropy < now) { + if (time_to_add_entropy) { + /* We already seeded once, so don't die on failure. */ + crypto_seed_rng(0); + } +/** How often do we add more entropy to OpenSSL's RNG pool? */ +#define ENTROPY_INTERVAL (60*60) + time_to_add_entropy = now + ENTROPY_INTERVAL; + } + + /** 1c. If we have to change the accounting interval or record + * bandwidth used in this accounting interval, do so. */ + if (accounting_is_enabled(options)) + accounting_run_housekeeping(now); + + if (time_to_launch_reachability_tests < now && + (authdir_mode_tests_reachability(options)) && + !net_is_disabled()) { + time_to_launch_reachability_tests = now + REACHABILITY_TEST_INTERVAL; + /* try to determine reachability of the other Tor relays */ + dirserv_test_reachability(now); + } + + /** 1d. Periodically, we discount older stability information so that new + * stability info counts more, and save the stability information to disk as + * appropriate. */ + if (time_to_downrate_stability < now) + time_to_downrate_stability = rep_hist_downrate_old_runs(now); + if (authdir_mode_tests_reachability(options)) { + if (time_to_save_stability < now) { + if (time_to_save_stability && rep_hist_record_mtbf_data(now, 1)<0) { + log_warn(LD_GENERAL, "Couldn't store mtbf data."); + } +#define SAVE_STABILITY_INTERVAL (30*60) + time_to_save_stability = now + SAVE_STABILITY_INTERVAL; + } + } + + /* 1e. Periodically, if we're a v3 authority, we check whether our cert is + * close to expiring and warn the admin if it is. */ + if (time_to_check_v3_certificate < now) { + v3_authority_check_key_expiry(); +#define CHECK_V3_CERTIFICATE_INTERVAL (5*60) + time_to_check_v3_certificate = now + CHECK_V3_CERTIFICATE_INTERVAL; + } + + /* 1f. Check whether our networkstatus has expired. + */ + if (time_to_check_for_expired_networkstatus < now) { + networkstatus_t *ns = networkstatus_get_latest_consensus(); + /*XXXX RD: This value needs to be the same as REASONABLY_LIVE_TIME in + * networkstatus_get_reasonably_live_consensus(), but that value is way + * way too high. Arma: is the bridge issue there resolved yet? -NM */ +#define NS_EXPIRY_SLOP (24*60*60) + if (ns && ns->valid_until < now+NS_EXPIRY_SLOP && + router_have_minimum_dir_info()) { + router_dir_info_changed(); + } +#define CHECK_EXPIRED_NS_INTERVAL (2*60) + time_to_check_for_expired_networkstatus = now + CHECK_EXPIRED_NS_INTERVAL; + } + + /* 1g. Check whether we should write statistics to disk. + */ + if (time_to_write_stats_files < now) { +#define CHECK_WRITE_STATS_INTERVAL (60*60) + time_t next_time_to_write_stats_files = (time_to_write_stats_files > 0 ? + time_to_write_stats_files : now) + CHECK_WRITE_STATS_INTERVAL; + if (options->CellStatistics) { + time_t next_write = + rep_hist_buffer_stats_write(time_to_write_stats_files); + if (next_write && next_write < next_time_to_write_stats_files) + next_time_to_write_stats_files = next_write; + } + if (options->DirReqStatistics) { + time_t next_write = geoip_dirreq_stats_write(time_to_write_stats_files); + if (next_write && next_write < next_time_to_write_stats_files) + next_time_to_write_stats_files = next_write; + } + if (options->EntryStatistics) { + time_t next_write = geoip_entry_stats_write(time_to_write_stats_files); + if (next_write && next_write < next_time_to_write_stats_files) + next_time_to_write_stats_files = next_write; + } + if (options->ExitPortStatistics) { + time_t next_write = rep_hist_exit_stats_write(time_to_write_stats_files); + if (next_write && next_write < next_time_to_write_stats_files) + next_time_to_write_stats_files = next_write; + } + if (options->ConnDirectionStatistics) { + time_t next_write = rep_hist_conn_stats_write(time_to_write_stats_files); + if (next_write && next_write < next_time_to_write_stats_files) + next_time_to_write_stats_files = next_write; + } + if (options->BridgeAuthoritativeDir) { + time_t next_write = rep_hist_desc_stats_write(time_to_write_stats_files); + if (next_write && next_write < next_time_to_write_stats_files) + next_time_to_write_stats_files = next_write; + } + time_to_write_stats_files = next_time_to_write_stats_files; + } + + /* 1h. Check whether we should write bridge statistics to disk. + */ + if (should_record_bridge_info(options)) { + if (time_to_write_bridge_stats < now) { + if (should_init_bridge_stats) { + /* (Re-)initialize bridge statistics. */ + geoip_bridge_stats_init(now); + time_to_write_bridge_stats = now + WRITE_STATS_INTERVAL; + should_init_bridge_stats = 0; + } else { + /* Possibly write bridge statistics to disk and ask when to write + * them next time. */ + time_to_write_bridge_stats = geoip_bridge_stats_write( + time_to_write_bridge_stats); + } + } + } else if (!should_init_bridge_stats) { + /* Bridge mode was turned off. Ensure that stats are re-initialized + * next time bridge mode is turned on. */ + should_init_bridge_stats = 1; + } + + /* Remove old information from rephist and the rend cache. */ + if (time_to_clean_caches < now) { + rep_history_clean(now - options->RephistTrackTime); + rend_cache_clean(now); + rend_cache_clean_v2_descs_as_dir(now); + microdesc_cache_rebuild(NULL, 0); +#define CLEAN_CACHES_INTERVAL (30*60) + time_to_clean_caches = now + CLEAN_CACHES_INTERVAL; + } + +#define RETRY_DNS_INTERVAL (10*60) + /* If we're a server and initializing dns failed, retry periodically. */ + if (time_to_retry_dns_init < now) { + time_to_retry_dns_init = now + RETRY_DNS_INTERVAL; + if (is_server && has_dns_init_failed()) + dns_init(); + } + + /** 2. Periodically, we consider force-uploading our descriptor + * (if we've passed our internal checks). */ + +/** How often do we check whether part of our router info has changed in a + * way that would require an upload? That includes checking whether our IP + * address has changed. */ +#define CHECK_DESCRIPTOR_INTERVAL (60) + + /* 2b. Once per minute, regenerate and upload the descriptor if the old + * one is inaccurate. */ + if (time_to_check_descriptor < now && !options->DisableNetwork) { + static int dirport_reachability_count = 0; + time_to_check_descriptor = now + CHECK_DESCRIPTOR_INTERVAL; + check_descriptor_bandwidth_changed(now); + check_descriptor_ipaddress_changed(now); + mark_my_descriptor_dirty_if_too_old(now); + consider_publishable_server(0); + /* also, check religiously for reachability, if it's within the first + * 20 minutes of our uptime. */ + if (is_server && + (can_complete_circuit || !any_predicted_circuits(now)) && + !we_are_hibernating()) { + if (stats_n_seconds_working < TIMEOUT_UNTIL_UNREACHABILITY_COMPLAINT) { + consider_testing_reachability(1, dirport_reachability_count==0); + if (++dirport_reachability_count > 5) + dirport_reachability_count = 0; + } else if (time_to_recheck_bandwidth < now) { + /* If we haven't checked for 12 hours and our bandwidth estimate is + * low, do another bandwidth test. This is especially important for + * bridges, since they might go long periods without much use. */ + const routerinfo_t *me = router_get_my_routerinfo(); + if (time_to_recheck_bandwidth && me && + me->bandwidthcapacity < me->bandwidthrate && + me->bandwidthcapacity < 51200) { + reset_bandwidth_test(); + } +#define BANDWIDTH_RECHECK_INTERVAL (12*60*60) + time_to_recheck_bandwidth = now + BANDWIDTH_RECHECK_INTERVAL; + } + } + + /* If any networkstatus documents are no longer recent, we need to + * update all the descriptors' running status. */ + /* Remove dead routers. */ + routerlist_remove_old_routers(); + } + + /* 2c. Every minute (or every second if TestingTorNetwork), check + * whether we want to download any networkstatus documents. */ + +/* How often do we check whether we should download network status + * documents? */ +#define networkstatus_dl_check_interval(o) ((o)->TestingTorNetwork ? 1 : 60) + + if (time_to_download_networkstatus < now && !options->DisableNetwork) { + time_to_download_networkstatus = + now + networkstatus_dl_check_interval(options); + update_networkstatus_downloads(now); + } + + /** 2c. Let directory voting happen. */ + if (authdir_mode_v3(options)) + dirvote_act(options, now); + + /** 3a. Every second, we examine pending circuits and prune the + * ones which have been pending for more than a few seconds. + * We do this before step 4, so it can try building more if + * it's not comfortable with the number of available circuits. + */ + /* (If our circuit build timeout can ever become lower than a second (which + * it can't, currently), we should do this more often.) */ + circuit_expire_building(); + + /** 3b. Also look at pending streams and prune the ones that 'began' + * a long time ago but haven't gotten a 'connected' yet. + * Do this before step 4, so we can put them back into pending + * state to be picked up by the new circuit. + */ + connection_ap_expire_beginning(); + + /** 3c. And expire connections that we've held open for too long. + */ + connection_expire_held_open(); + + /** 3d. And every 60 seconds, we relaunch listeners if any died. */ + if (!net_is_disabled() && time_to_check_listeners < now) { + retry_all_listeners(NULL, NULL, 0); + time_to_check_listeners = now+60; + } + + /** 4. Every second, we try a new circuit if there are no valid + * circuits. Every NewCircuitPeriod seconds, we expire circuits + * that became dirty more than MaxCircuitDirtiness seconds ago, + * and we make a new circ if there are no clean circuits. + */ + have_dir_info = router_have_minimum_dir_info(); + if (have_dir_info && !net_is_disabled()) + circuit_build_needed_circs(now); + + /* every 10 seconds, but not at the same second as other such events */ + if (now % 10 == 5) + circuit_expire_old_circuits_serverside(now); + + /** 5. We do housekeeping for each connection... */ + connection_or_set_bad_connections(NULL, 0); + for (i=0;ioutbuf) + buf_shrink(conn->outbuf); + if (conn->inbuf) + buf_shrink(conn->inbuf); + }); + clean_cell_pool(); + buf_shrink_freelists(0); +/** How often do we check buffers and pools for empty space that can be + * deallocated? */ +#define MEM_SHRINK_INTERVAL (60) + time_to_shrink_memory = now + MEM_SHRINK_INTERVAL; + } + + /** 6. And remove any marked circuits... */ + circuit_close_all_marked(); + + /** 7. And upload service descriptors if necessary. */ + if (can_complete_circuit && !net_is_disabled()) { + rend_consider_services_upload(now); + rend_consider_descriptor_republication(); + } + + /** 8. and blow away any connections that need to die. have to do this now, + * because if we marked a conn for close and left its socket -1, then + * we'll pass it to poll/select and bad things will happen. + */ + close_closeable_connections(); + + /** 8b. And if anything in our state is ready to get flushed to disk, we + * flush it. */ + or_state_save(now); + + /** 8c. Do channel cleanup just like for connections */ + channel_run_cleanup(); + channel_listener_run_cleanup(); + + /** 9. and if we're a server, check whether our DNS is telling stories to + * us. */ + if (!net_is_disabled() && + public_server_mode(options) && time_to_check_for_correct_dns < now) { + if (!time_to_check_for_correct_dns) { + time_to_check_for_correct_dns = now + 60 + crypto_rand_int(120); + } else { + dns_launch_correctness_checks(); + time_to_check_for_correct_dns = now + 12*3600 + + crypto_rand_int(12*3600); + } + } + + /** 10. write bridge networkstatus file to disk */ + if (options->BridgeAuthoritativeDir && + time_to_write_bridge_status_file < now) { + networkstatus_dump_bridge_status_to_file(now); +#define BRIDGE_STATUSFILE_INTERVAL (30*60) + time_to_write_bridge_status_file = now+BRIDGE_STATUSFILE_INTERVAL; + } + + /** 11. check the port forwarding app */ + if (!net_is_disabled() && + time_to_check_port_forwarding < now && + options->PortForwarding && + is_server) { +#define PORT_FORWARDING_CHECK_INTERVAL 5 + smartlist_t *ports_to_forward = get_list_of_ports_to_forward(); + if (ports_to_forward) { + tor_check_port_forwarding(options->PortForwardingHelper, + ports_to_forward, + now); + + SMARTLIST_FOREACH(ports_to_forward, char *, cp, tor_free(cp)); + smartlist_free(ports_to_forward); + } + time_to_check_port_forwarding = now+PORT_FORWARDING_CHECK_INTERVAL; + } + + /** 11b. check pending unconfigured managed proxies */ + if (!net_is_disabled() && pt_proxies_configuration_pending()) + pt_configure_remaining_proxies(); + + /** 12. write the heartbeat message */ + if (options->HeartbeatPeriod && + time_to_next_heartbeat <= now) { + if (time_to_next_heartbeat) /* don't log the first heartbeat */ + log_heartbeat(now); + time_to_next_heartbeat = now+options->HeartbeatPeriod; + } +} + +/** Timer: used to invoke second_elapsed_callback() once per second. */ +static periodic_timer_t *second_timer = NULL; +/** Number of libevent errors in the last second: we die if we get too many. */ +static int n_libevent_errors = 0; + +/** Libevent callback: invoked once every second. */ +static void +second_elapsed_callback(periodic_timer_t *timer, void *arg) +{ + /* XXXX This could be sensibly refactored into multiple callbacks, and we + * could use Libevent's timers for this rather than checking the current + * time against a bunch of timeouts every second. */ + static time_t current_second = 0; + time_t now; + size_t bytes_written; + size_t bytes_read; + int seconds_elapsed; + const or_options_t *options = get_options(); + (void)timer; + (void)arg; + + n_libevent_errors = 0; + + /* log_notice(LD_GENERAL, "Tick."); */ + now = time(NULL); + update_approx_time(now); + + /* the second has rolled over. check more stuff. */ + seconds_elapsed = current_second ? (int)(now - current_second) : 0; +#ifdef USE_BUFFEREVENTS + { + uint64_t cur_read,cur_written; + connection_get_rate_limit_totals(&cur_read, &cur_written); + bytes_written = (size_t)(cur_written - stats_prev_n_written); + bytes_read = (size_t)(cur_read - stats_prev_n_read); + stats_n_bytes_read += bytes_read; + stats_n_bytes_written += bytes_written; + if (accounting_is_enabled(options) && seconds_elapsed >= 0) + accounting_add_bytes(bytes_read, bytes_written, seconds_elapsed); + stats_prev_n_written = cur_written; + stats_prev_n_read = cur_read; + } +#else + bytes_read = (size_t)(stats_n_bytes_read - stats_prev_n_read); + bytes_written = (size_t)(stats_n_bytes_written - stats_prev_n_written); + stats_prev_n_read = stats_n_bytes_read; + stats_prev_n_written = stats_n_bytes_written; +#endif + + control_event_bandwidth_used((uint32_t)bytes_read,(uint32_t)bytes_written); + control_event_stream_bandwidth_used(); + control_event_conn_bandwidth_used(); + control_event_circ_bandwidth_used(); + control_event_circuit_cell_stats(); + + if (server_mode(options) && + !net_is_disabled() && + seconds_elapsed > 0 && + can_complete_circuit && + stats_n_seconds_working / TIMEOUT_UNTIL_UNREACHABILITY_COMPLAINT != + (stats_n_seconds_working+seconds_elapsed) / + TIMEOUT_UNTIL_UNREACHABILITY_COMPLAINT) { + /* every 20 minutes, check and complain if necessary */ + const routerinfo_t *me = router_get_my_routerinfo(); + if (me && !check_whether_orport_reachable()) { + log_warn(LD_CONFIG,"Your server (%s:%d) has not managed to confirm that " + "its ORPort is reachable. Please check your firewalls, ports, " + "address, /etc/hosts file, etc.", + me->address, me->or_port); + control_event_server_status(LOG_WARN, + "REACHABILITY_FAILED ORADDRESS=%s:%d", + me->address, me->or_port); + } + + if (me && !check_whether_dirport_reachable()) { + log_warn(LD_CONFIG, + "Your server (%s:%d) has not managed to confirm that its " + "DirPort is reachable. Please check your firewalls, ports, " + "address, /etc/hosts file, etc.", + me->address, me->dir_port); + control_event_server_status(LOG_WARN, + "REACHABILITY_FAILED DIRADDRESS=%s:%d", + me->address, me->dir_port); + } + } + +/** If more than this many seconds have elapsed, probably the clock + * jumped: doesn't count. */ +#define NUM_JUMPED_SECONDS_BEFORE_WARN 100 + if (seconds_elapsed < -NUM_JUMPED_SECONDS_BEFORE_WARN || + seconds_elapsed >= NUM_JUMPED_SECONDS_BEFORE_WARN) { + circuit_note_clock_jumped(seconds_elapsed); + /* XXX if the time jumps *back* many months, do our events in + * run_scheduled_events() recover? I don't think they do. -RD */ + } else if (seconds_elapsed > 0) + stats_n_seconds_working += seconds_elapsed; + + run_scheduled_events(now); + + current_second = now; /* remember which second it is, for next time */ +} + +#ifndef USE_BUFFEREVENTS +/** Timer: used to invoke refill_callback(). */ +static periodic_timer_t *refill_timer = NULL; + +/** Libevent callback: invoked periodically to refill token buckets + * and count r/w bytes. It is only used when bufferevents are disabled. */ +static void +refill_callback(periodic_timer_t *timer, void *arg) +{ + static struct timeval current_millisecond; + struct timeval now; + + size_t bytes_written; + size_t bytes_read; + int milliseconds_elapsed = 0; + int seconds_rolled_over = 0; + + const or_options_t *options = get_options(); + + (void)timer; + (void)arg; + + tor_gettimeofday(&now); + + /* If this is our first time, no time has passed. */ + if (current_millisecond.tv_sec) { + long mdiff = tv_mdiff(¤t_millisecond, &now); + if (mdiff > INT_MAX) + mdiff = INT_MAX; + milliseconds_elapsed = (int)mdiff; + seconds_rolled_over = (int)(now.tv_sec - current_millisecond.tv_sec); + } + + bytes_written = stats_prev_global_write_bucket - global_write_bucket; + bytes_read = stats_prev_global_read_bucket - global_read_bucket; + + stats_n_bytes_read += bytes_read; + stats_n_bytes_written += bytes_written; + if (accounting_is_enabled(options) && milliseconds_elapsed >= 0) + accounting_add_bytes(bytes_read, bytes_written, seconds_rolled_over); + + if (milliseconds_elapsed > 0) + connection_bucket_refill(milliseconds_elapsed, now.tv_sec); + + stats_prev_global_read_bucket = global_read_bucket; + stats_prev_global_write_bucket = global_write_bucket; + + current_millisecond = now; /* remember what time it is, for next time */ +} +#endif + +#ifndef _WIN32 +/** Called when a possibly ignorable libevent error occurs; ensures that we + * don't get into an infinite loop by ignoring too many errors from + * libevent. */ +static int +got_libevent_error(void) +{ + if (++n_libevent_errors > 8) { + log_err(LD_NET, "Too many libevent errors in one second; dying"); + return -1; + } + return 0; +} +#endif + +#define UPTIME_CUTOFF_FOR_NEW_BANDWIDTH_TEST (6*60*60) + +/** Called when our IP address seems to have changed. at_interface + * should be true if we detected a change in our interface, and false if we + * detected a change in our published address. */ +void +ip_address_changed(int at_interface) +{ + int server = server_mode(get_options()); + + if (at_interface) { + if (! server) { + /* Okay, change our keys. */ + if (init_keys()<0) + log_warn(LD_GENERAL, "Unable to rotate keys after IP change!"); + } + } else { + if (server) { + if (stats_n_seconds_working > UPTIME_CUTOFF_FOR_NEW_BANDWIDTH_TEST) + reset_bandwidth_test(); + stats_n_seconds_working = 0; + router_reset_reachability(); + mark_my_descriptor_dirty("IP address changed"); + } + } + + dns_servers_relaunch_checks(); +} + +/** Forget what we've learned about the correctness of our DNS servers, and + * start learning again. */ +void +dns_servers_relaunch_checks(void) +{ + if (server_mode(get_options())) { + dns_reset_correctness_checks(); + time_to_check_for_correct_dns = 0; + } +} + +/** Called when we get a SIGHUP: reload configuration files and keys, + * retry all connections, and so on. */ +static int +do_hup(void) +{ + const or_options_t *options = get_options(); + +#ifdef USE_DMALLOC + dmalloc_log_stats(); + dmalloc_log_changed(0, 1, 0, 0); +#endif + + log_notice(LD_GENERAL,"Received reload signal (hup). Reloading config and " + "resetting internal state."); + if (accounting_is_enabled(options)) + accounting_record_bandwidth_usage(time(NULL), get_or_state()); + + router_reset_warnings(); + routerlist_reset_warnings(); + /* first, reload config variables, in case they've changed */ + if (options->ReloadTorrcOnSIGHUP) { + /* no need to provide argc/v, they've been cached in init_from_config */ + if (options_init_from_torrc(0, NULL) < 0) { + log_err(LD_CONFIG,"Reading config failed--see warnings above. " + "For usage, try -h."); + return -1; + } + options = get_options(); /* they have changed now */ + } else { + char *msg = NULL; + log_notice(LD_GENERAL, "Not reloading config file: the controller told " + "us not to."); + /* Make stuff get rescanned, reloaded, etc. */ + if (set_options((or_options_t*)options, &msg) < 0) { + if (!msg) + msg = tor_strdup("Unknown error"); + log_warn(LD_GENERAL, "Unable to re-set previous options: %s", msg); + tor_free(msg); + } + } + if (authdir_mode_handles_descs(options, -1)) { + /* reload the approved-routers file */ + if (dirserv_load_fingerprint_file() < 0) { + /* warnings are logged from dirserv_load_fingerprint_file() directly */ + log_info(LD_GENERAL, "Error reloading fingerprints. " + "Continuing with old list."); + } + } + + /* Rotate away from the old dirty circuits. This has to be done + * after we've read the new options, but before we start using + * circuits for directory fetches. */ + circuit_mark_all_dirty_circs_as_unusable(); + + /* retry appropriate downloads */ + router_reset_status_download_failures(); + router_reset_descriptor_download_failures(); + if (!options->DisableNetwork) + update_networkstatus_downloads(time(NULL)); + + /* We'll retry routerstatus downloads in about 10 seconds; no need to + * force a retry there. */ + + if (server_mode(options)) { + /* Restart cpuworker and dnsworker processes, so they get up-to-date + * configuration options. */ + cpuworkers_rotate(); + dns_reset(); + } + return 0; +} + +/** Tor main loop. */ +int +do_main_loop(void) +{ + int loop_result; + time_t now; + + /* initialize dns resolve map, spawn workers if needed */ + if (dns_init() < 0) { + if (get_options()->ServerDNSAllowBrokenConfig) + log_warn(LD_GENERAL, "Couldn't set up any working nameservers. " + "Network not up yet? Will try again soon."); + else { + log_err(LD_GENERAL,"Error initializing dns subsystem; exiting. To " + "retry instead, set the ServerDNSAllowBrokenResolvConf option."); + } + } + +#ifdef USE_BUFFEREVENTS + log_warn(LD_GENERAL, "Tor was compiled with the --enable-bufferevents " + "option. This is still experimental, and might cause strange " + "bugs. If you want a more stable Tor, be sure to build without " + "--enable-bufferevents."); +#endif + + handle_signals(1); + + /* load the private keys, if we're supposed to have them, and set up the + * TLS context. */ + if (! client_identity_key_is_set()) { + if (init_keys() < 0) { + log_err(LD_BUG,"Error initializing keys; exiting"); + return -1; + } + } + + /* Set up the packed_cell_t memory pool. */ + init_cell_pool(); + + /* Set up our buckets */ + connection_bucket_init(); +#ifndef USE_BUFFEREVENTS + stats_prev_global_read_bucket = global_read_bucket; + stats_prev_global_write_bucket = global_write_bucket; +#endif + + /* initialize the bootstrap status events to know we're starting up */ + control_event_bootstrap(BOOTSTRAP_STATUS_STARTING, 0); + + if (trusted_dirs_reload_certs()) { + log_warn(LD_DIR, + "Couldn't load all cached v3 certificates. Starting anyway."); + } + if (router_reload_consensus_networkstatus()) { + return -1; + } + /* load the routers file, or assign the defaults. */ + if (router_reload_router_list()) { + return -1; + } + /* load the networkstatuses. (This launches a download for new routers as + * appropriate.) + */ + now = time(NULL); + directory_info_has_arrived(now, 1); + + if (server_mode(get_options())) { + /* launch cpuworkers. Need to do this *after* we've read the onion key. */ + cpu_init(); + } + + /* set up once-a-second callback. */ + if (! second_timer) { + struct timeval one_second; + one_second.tv_sec = 1; + one_second.tv_usec = 0; + + second_timer = periodic_timer_new(tor_libevent_get_base(), + &one_second, + second_elapsed_callback, + NULL); + tor_assert(second_timer); + } + +#ifndef USE_BUFFEREVENTS + if (!refill_timer) { + struct timeval refill_interval; + int msecs = get_options()->TokenBucketRefillInterval; + + refill_interval.tv_sec = msecs/1000; + refill_interval.tv_usec = (msecs%1000)*1000; + + refill_timer = periodic_timer_new(tor_libevent_get_base(), + &refill_interval, + refill_callback, + NULL); + tor_assert(refill_timer); + } +#endif + + for (;;) { + if (nt_service_is_stopping()) + return 0; + + if (check_interrupted()) + return 0; + +#ifndef _WIN32 + /* Make it easier to tell whether libevent failure is our fault or not. */ + errno = 0; +#endif + /* All active linked conns should get their read events activated. */ + SMARTLIST_FOREACH(active_linked_connection_lst, connection_t *, conn, + event_active(conn->read_event, EV_READ, 1)); + called_loop_once = smartlist_len(active_linked_connection_lst) ? 1 : 0; + + update_approx_time(time(NULL)); + + /* poll until we have an event, or the second ends, or until we have + * some active linked connections to trigger events for. */ + loop_result = event_base_loop(tor_libevent_get_base(), + called_loop_once ? EVLOOP_ONCE : 0); + + /* let catch() handle things like ^c, and otherwise don't worry about it */ + if (loop_result < 0) { + int e = tor_socket_errno(-1); + /* let the program survive things like ^z */ + if (e != EINTR && !ERRNO_IS_EINPROGRESS(e)) { + log_err(LD_NET,"libevent call with %s failed: %s [%d]", + tor_libevent_get_method(), tor_socket_strerror(e), e); + return -1; +#ifndef _WIN32 + } else if (e == EINVAL) { + log_warn(LD_NET, "EINVAL from libevent: should you upgrade libevent?"); + if (got_libevent_error()) + return -1; +#endif + } else { + if (ERRNO_IS_EINPROGRESS(e)) + log_warn(LD_BUG, + "libevent call returned EINPROGRESS? Please report."); + log_debug(LD_NET,"libevent call interrupted."); + /* You can't trust the results of this poll(). Go back to the + * top of the big for loop. */ + continue; + } + } + } +} + +#ifndef _WIN32 /* Only called when we're willing to use signals */ +/** Libevent callback: invoked when we get a signal. + */ +static void +signal_callback(int fd, short events, void *arg) +{ + uintptr_t sig = (uintptr_t)arg; + (void)fd; + (void)events; + + process_signal(sig); +} +#endif + +/** Do the work of acting on a signal received in sig */ +void +process_signal(uintptr_t sig) +{ + switch (sig) + { + case SIGTERM: + log_notice(LD_GENERAL,"Catching signal TERM, exiting cleanly."); + tor_cleanup(); + exit(0); + break; + case SIGINT: + if (!server_mode(get_options())) { /* do it now */ + log_notice(LD_GENERAL,"Interrupt: exiting cleanly."); + tor_cleanup(); + exit(0); + } + hibernate_begin_shutdown(); + break; +#ifdef SIGPIPE + case SIGPIPE: + log_debug(LD_GENERAL,"Caught SIGPIPE. Ignoring."); + break; +#endif + case SIGUSR1: + /* prefer to log it at INFO, but make sure we always see it */ + dumpstats(get_min_log_level() 0) ; /* keep reaping until no more + zombies */ + break; +#endif + case SIGNEWNYM: { + time_t now = time(NULL); + if (time_of_last_signewnym + MAX_SIGNEWNYM_RATE > now) { + signewnym_is_pending = 1; + log_notice(LD_CONTROL, + "Rate limiting NEWNYM request: delaying by %d second(s)", + (int)(MAX_SIGNEWNYM_RATE+time_of_last_signewnym-now)); + } else { + signewnym_impl(now); + } + break; + } + case SIGCLEARDNSCACHE: + addressmap_clear_transient(); + control_event_signal(sig); + break; + } +} + +/** Returns Tor's uptime. */ +long +get_uptime(void) +{ + return stats_n_seconds_working; +} + +extern uint64_t rephist_total_alloc; +extern uint32_t rephist_total_num; + +/** + * Write current memory usage information to the log. + */ +static void +dumpmemusage(int severity) +{ + connection_dump_buffer_mem_stats(severity); + tor_log(severity, LD_GENERAL, "In rephist: "U64_FORMAT" used by %d Tors.", + U64_PRINTF_ARG(rephist_total_alloc), rephist_total_num); + dump_routerlist_mem_usage(severity); + dump_cell_pool_usage(severity); + dump_dns_mem_usage(severity); + buf_dump_freelist_sizes(severity); + tor_log_mallinfo(severity); +} + +/** Write all statistics to the log, with log level severity. Called + * in response to a SIGUSR1. */ +static void +dumpstats(int severity) +{ + time_t now = time(NULL); + time_t elapsed; + size_t rbuf_cap, wbuf_cap, rbuf_len, wbuf_len; + + tor_log(severity, LD_GENERAL, "Dumping stats:"); + + SMARTLIST_FOREACH_BEGIN(connection_array, connection_t *, conn) { + int i = conn_sl_idx; + tor_log(severity, LD_GENERAL, + "Conn %d (socket %d) type %d (%s), state %d (%s), created %d secs ago", + i, (int)conn->s, conn->type, conn_type_to_string(conn->type), + conn->state, conn_state_to_string(conn->type, conn->state), + (int)(now - conn->timestamp_created)); + if (!connection_is_listener(conn)) { + tor_log(severity,LD_GENERAL, + "Conn %d is to %s:%d.", i, + safe_str_client(conn->address), + conn->port); + tor_log(severity,LD_GENERAL, + "Conn %d: %d bytes waiting on inbuf (len %d, last read %d secs ago)", + i, + (int)connection_get_inbuf_len(conn), + (int)buf_allocation(conn->inbuf), + (int)(now - conn->timestamp_lastread)); + tor_log(severity,LD_GENERAL, + "Conn %d: %d bytes waiting on outbuf " + "(len %d, last written %d secs ago)",i, + (int)connection_get_outbuf_len(conn), + (int)buf_allocation(conn->outbuf), + (int)(now - conn->timestamp_lastwritten)); + if (conn->type == CONN_TYPE_OR) { + or_connection_t *or_conn = TO_OR_CONN(conn); + if (or_conn->tls) { + tor_tls_get_buffer_sizes(or_conn->tls, &rbuf_cap, &rbuf_len, + &wbuf_cap, &wbuf_len); + tor_log(severity, LD_GENERAL, + "Conn %d: %d/%d bytes used on OpenSSL read buffer; " + "%d/%d bytes used on write buffer.", + i, (int)rbuf_len, (int)rbuf_cap, (int)wbuf_len, (int)wbuf_cap); + } + } + } + circuit_dump_by_conn(conn, severity); /* dump info about all the circuits + * using this conn */ + } SMARTLIST_FOREACH_END(conn); + + channel_dumpstats(severity); + channel_listener_dumpstats(severity); + + tor_log(severity, LD_NET, + "Cells processed: "U64_FORMAT" padding\n" + " "U64_FORMAT" create\n" + " "U64_FORMAT" created\n" + " "U64_FORMAT" relay\n" + " ("U64_FORMAT" relayed)\n" + " ("U64_FORMAT" delivered)\n" + " "U64_FORMAT" destroy", + U64_PRINTF_ARG(stats_n_padding_cells_processed), + U64_PRINTF_ARG(stats_n_create_cells_processed), + U64_PRINTF_ARG(stats_n_created_cells_processed), + U64_PRINTF_ARG(stats_n_relay_cells_processed), + U64_PRINTF_ARG(stats_n_relay_cells_relayed), + U64_PRINTF_ARG(stats_n_relay_cells_delivered), + U64_PRINTF_ARG(stats_n_destroy_cells_processed)); + if (stats_n_data_cells_packaged) + tor_log(severity,LD_NET,"Average packaged cell fullness: %2.3f%%", + 100*(U64_TO_DBL(stats_n_data_bytes_packaged) / + U64_TO_DBL(stats_n_data_cells_packaged*RELAY_PAYLOAD_SIZE)) ); + if (stats_n_data_cells_received) + tor_log(severity,LD_NET,"Average delivered cell fullness: %2.3f%%", + 100*(U64_TO_DBL(stats_n_data_bytes_received) / + U64_TO_DBL(stats_n_data_cells_received*RELAY_PAYLOAD_SIZE)) ); + + cpuworker_log_onionskin_overhead(severity, ONION_HANDSHAKE_TYPE_TAP, "TAP"); + cpuworker_log_onionskin_overhead(severity, ONION_HANDSHAKE_TYPE_NTOR,"ntor"); + + if (now - time_of_process_start >= 0) + elapsed = now - time_of_process_start; + else + elapsed = 0; + + if (elapsed) { + tor_log(severity, LD_NET, + "Average bandwidth: "U64_FORMAT"/%d = %d bytes/sec reading", + U64_PRINTF_ARG(stats_n_bytes_read), + (int)elapsed, + (int) (stats_n_bytes_read/elapsed)); + tor_log(severity, LD_NET, + "Average bandwidth: "U64_FORMAT"/%d = %d bytes/sec writing", + U64_PRINTF_ARG(stats_n_bytes_written), + (int)elapsed, + (int) (stats_n_bytes_written/elapsed)); + } + + tor_log(severity, LD_NET, "--------------- Dumping memory information:"); + dumpmemusage(severity); + + rep_hist_dump_stats(now,severity); + rend_service_dump_stats(severity); + dump_pk_ops(severity); + dump_distinct_digest_count(severity); +} + +/** Called by exit() as we shut down the process. + */ +static void +exit_function(void) +{ + /* NOTE: If we ever daemonize, this gets called immediately. That's + * okay for now, because we only use this on Windows. */ +#ifdef _WIN32 + WSACleanup(); +#endif +} + +/** Set up the signal handlers for either parent or child. */ +void +handle_signals(int is_parent) +{ +#ifndef _WIN32 /* do signal stuff only on Unix */ + int i; + static const int signals[] = { + SIGINT, /* do a controlled slow shutdown */ + SIGTERM, /* to terminate now */ + SIGPIPE, /* otherwise SIGPIPE kills us */ + SIGUSR1, /* dump stats */ + SIGUSR2, /* go to loglevel debug */ + SIGHUP, /* to reload config, retry conns, etc */ +#ifdef SIGXFSZ + SIGXFSZ, /* handle file-too-big resource exhaustion */ +#endif + SIGCHLD, /* handle dns/cpu workers that exit */ + -1 }; + static struct event *signal_events[16]; /* bigger than it has to be. */ + if (is_parent) { + for (i = 0; signals[i] >= 0; ++i) { + signal_events[i] = tor_evsignal_new( + tor_libevent_get_base(), signals[i], signal_callback, + (void*)(uintptr_t)signals[i]); + if (event_add(signal_events[i], NULL)) + log_warn(LD_BUG, "Error from libevent when adding event for signal %d", + signals[i]); + } + } else { + struct sigaction action; + action.sa_flags = 0; + sigemptyset(&action.sa_mask); + action.sa_handler = SIG_IGN; + sigaction(SIGINT, &action, NULL); + sigaction(SIGTERM, &action, NULL); + sigaction(SIGPIPE, &action, NULL); + sigaction(SIGUSR1, &action, NULL); + sigaction(SIGUSR2, &action, NULL); + sigaction(SIGHUP, &action, NULL); +#ifdef SIGXFSZ + sigaction(SIGXFSZ, &action, NULL); +#endif + } +#else /* MS windows */ + (void)is_parent; +#endif /* signal stuff */ +} + +/** Main entry point for the Tor command-line client. + */ +int +tor_init(int argc, char *argv[]) +{ + char progname[256]; + int quiet = 0; + + time_of_process_start = time(NULL); + init_connection_lists(); + /* Have the log set up with our application name. */ + tor_snprintf(progname, sizeof(progname), "Tor %s", get_version()); + log_set_application_name(progname); + /* Initialize the history structures. */ + rep_hist_init(); + /* Initialize the service cache. */ + rend_cache_init(); + addressmap_init(); /* Init the client dns cache. Do it always, since it's + * cheap. */ + + { + /* We search for the "quiet" option first, since it decides whether we + * will log anything at all to the command line. */ + config_line_t *opts = NULL, *cmdline_opts = NULL; + const config_line_t *cl; + (void) config_parse_commandline(argc, argv, 1, &opts, &cmdline_opts); + for (cl = cmdline_opts; cl; cl = cl->next) { + if (!strcmp(cl->key, "--hush")) + quiet = 1; + if (!strcmp(cl->key, "--quiet") || + !strcmp(cl->key, "--dump-config")) + quiet = 2; + /* --version, --digests, and --help imply --hush */ + if (!strcmp(cl->key, "--version") || !strcmp(cl->key, "--digests") || + !strcmp(cl->key, "--list-torrc-options") || + !strcmp(cl->key, "--library-versions") || + !strcmp(cl->key, "-h") || !strcmp(cl->key, "--help")) { + if (quiet < 1) + quiet = 1; + } + } + config_free_lines(opts); + config_free_lines(cmdline_opts); + } + + /* give it somewhere to log to initially */ + switch (quiet) { + case 2: + /* no initial logging */ + break; + case 1: + add_temp_log(LOG_WARN); + break; + default: + add_temp_log(LOG_NOTICE); + } + quiet_level = quiet; + + { + const char *version = get_version(); + const char *bev_str = +#ifdef USE_BUFFEREVENTS + "(with bufferevents) "; +#else + ""; +#endif + log_notice(LD_GENERAL, "Tor v%s %srunning on %s with Libevent %s, " + "OpenSSL %s and Zlib %s.", version, bev_str, + get_uname(), + tor_libevent_get_version_str(), + crypto_openssl_get_version_str(), + tor_zlib_get_version_str()); + + log_notice(LD_GENERAL, "Tor can't help you if you use it wrong! " + "Learn how to be safe at " + "https://www.torproject.org/download/download#warning"); + + if (strstr(version, "alpha") || strstr(version, "beta")) + log_notice(LD_GENERAL, "This version is not a stable Tor release. " + "Expect more bugs than usual."); + } + +#ifdef NON_ANONYMOUS_MODE_ENABLED + log_warn(LD_GENERAL, "This copy of Tor was compiled to run in a " + "non-anonymous mode. It will provide NO ANONYMITY."); +#endif + + if (network_init()<0) { + log_err(LD_BUG,"Error initializing network; exiting."); + return -1; + } + atexit(exit_function); + + if (options_init_from_torrc(argc,argv) < 0) { + log_err(LD_CONFIG,"Reading config failed--see warnings above."); + return -1; + } + +#ifndef _WIN32 + if (geteuid()==0) + log_warn(LD_GENERAL,"You are running Tor as root. You don't need to, " + "and you probably shouldn't."); +#endif + + if (crypto_global_init(get_options()->HardwareAccel, + get_options()->AccelName, + get_options()->AccelDir)) { + log_err(LD_BUG, "Unable to initialize OpenSSL. Exiting."); + return -1; + } + stream_choice_seed_weak_rng(); + + return 0; +} + +/** A lockfile structure, used to prevent two Tors from messing with the + * data directory at once. If this variable is non-NULL, we're holding + * the lockfile. */ +static tor_lockfile_t *lockfile = NULL; + +/** Try to grab the lock file described in options, if we do not + * already have it. If err_if_locked is true, warn if somebody else is + * holding the lock, and exit if we can't get it after waiting. Otherwise, + * return -1 if we can't get the lockfile. Return 0 on success. + */ +int +try_locking(const or_options_t *options, int err_if_locked) +{ + if (lockfile) + return 0; + else { + char *fname = options_get_datadir_fname2_suffix(options, "lock",NULL,NULL); + int already_locked = 0; + tor_lockfile_t *lf = tor_lockfile_lock(fname, 0, &already_locked); + tor_free(fname); + if (!lf) { + if (err_if_locked && already_locked) { + int r; + log_warn(LD_GENERAL, "It looks like another Tor process is running " + "with the same data directory. Waiting 5 seconds to see " + "if it goes away."); +#ifndef _WIN32 + sleep(5); +#else + Sleep(5000); +#endif + r = try_locking(options, 0); + if (r<0) { + log_err(LD_GENERAL, "No, it's still there. Exiting."); + exit(0); + } + return r; + } + return -1; + } + lockfile = lf; + return 0; + } +} + +/** Return true iff we've successfully acquired the lock file. */ +int +have_lockfile(void) +{ + return lockfile != NULL; +} + +/** If we have successfully acquired the lock file, release it. */ +void +release_lockfile(void) +{ + if (lockfile) { + tor_lockfile_unlock(lockfile); + lockfile = NULL; + } +} + +/** Free all memory that we might have allocated somewhere. + * If postfork, we are a worker process and we want to free + * only the parts of memory that we won't touch. If !postfork, + * Tor is shutting down and we should free everything. + * + * Helps us find the real leaks with dmalloc and the like. Also valgrind + * should then report 0 reachable in its leak report (in an ideal world -- + * in practice libevent, SSL, libc etc never quite free everything). */ +void +tor_free_all(int postfork) +{ + if (!postfork) { + evdns_shutdown(1); + } + geoip_free_all(); + dirvote_free_all(); + routerlist_free_all(); + networkstatus_free_all(); + addressmap_free_all(); + dirserv_free_all(); + rend_service_free_all(); + rend_cache_free_all(); + rend_service_authorization_free_all(); + rep_hist_free_all(); + dns_free_all(); + clear_pending_onions(); + circuit_free_all(); + entry_guards_free_all(); + pt_free_all(); + channel_tls_free_all(); + channel_free_all(); + connection_free_all(); + buf_shrink_freelists(1); + memarea_clear_freelist(); + nodelist_free_all(); + microdesc_free_all(); + ext_orport_free_all(); + control_free_all(); + if (!postfork) { + config_free_all(); + or_state_free_all(); + router_free_all(); + policies_free_all(); + } + free_cell_pool(); + if (!postfork) { + tor_tls_free_all(); + } + /* stuff in onion_main.c */ + + smartlist_free(connection_array); + smartlist_free(closeable_connection_lst); + smartlist_free(active_linked_connection_lst); + periodic_timer_free(second_timer); +#ifndef USE_BUFFEREVENTS + periodic_timer_free(refill_timer); +#endif + + if (!postfork) { + release_lockfile(); + } + /* Stuff in util.c and address.c*/ + if (!postfork) { + escaped(NULL); + esc_router_info(NULL); + logs_free_all(); /* free log strings. do this last so logs keep working. */ + } +} + +/** Do whatever cleanup is necessary before shutting Tor down. */ +void +tor_cleanup(void) +{ + const or_options_t *options = get_options(); + if (options->command == CMD_RUN_TOR) { + time_t now = time(NULL); + /* Remove our pid file. We don't care if there was an error when we + * unlink, nothing we could do about it anyways. */ + if (options->PidFile) + unlink(options->PidFile); + if (options->ControlPortWriteToFile) + unlink(options->ControlPortWriteToFile); + if (accounting_is_enabled(options)) + accounting_record_bandwidth_usage(now, get_or_state()); + or_state_mark_dirty(get_or_state(), 0); /* force an immediate save. */ + or_state_save(now); + if (authdir_mode_tests_reachability(options)) + rep_hist_record_mtbf_data(now, 0); + } +#ifdef USE_DMALLOC + dmalloc_log_stats(); +#endif + tor_free_all(0); /* We could move tor_free_all back into the ifdef below + later, if it makes shutdown unacceptably slow. But for + now, leave it here: it's helped us catch bugs in the + past. */ + crypto_global_cleanup(); +#ifdef USE_DMALLOC + dmalloc_log_unfreed(); + dmalloc_shutdown(); +#endif +} + +/** Read/create keys as needed, and echo our fingerprint to stdout. */ +static int +do_list_fingerprint(void) +{ + char buf[FINGERPRINT_LEN+1]; + crypto_pk_t *k; + const char *nickname = get_options()->Nickname; + if (!server_mode(get_options())) { + log_err(LD_GENERAL, + "Clients don't have long-term identity keys. Exiting."); + return -1; + } + tor_assert(nickname); + if (init_keys() < 0) { + log_err(LD_BUG,"Error initializing keys; can't display fingerprint"); + return -1; + } + if (!(k = get_server_identity_key())) { + log_err(LD_GENERAL,"Error: missing identity key."); + return -1; + } + if (crypto_pk_get_fingerprint(k, buf, 1)<0) { + log_err(LD_BUG, "Error computing fingerprint"); + return -1; + } + printf("%s %s\n", nickname, buf); + return 0; +} + +/** Entry point for password hashing: take the desired password from + * the command line, and print its salted hash to stdout. **/ +static void +do_hash_password(void) +{ + + char output[256]; + char key[S2K_SPECIFIER_LEN+DIGEST_LEN]; + + crypto_rand(key, S2K_SPECIFIER_LEN-1); + key[S2K_SPECIFIER_LEN-1] = (uint8_t)96; /* Hash 64 K of data. */ + secret_to_key(key+S2K_SPECIFIER_LEN, DIGEST_LEN, + get_options()->command_arg, strlen(get_options()->command_arg), + key); + base16_encode(output, sizeof(output), key, sizeof(key)); + printf("16:%s\n",output); +} + +/** Entry point for configuration dumping: write the configuration to + * stdout. */ +static int +do_dump_config(void) +{ + const or_options_t *options = get_options(); + const char *arg = options->command_arg; + int how; + char *opts; + if (!strcmp(arg, "short")) { + how = OPTIONS_DUMP_MINIMAL; + } else if (!strcmp(arg, "non-builtin")) { + how = OPTIONS_DUMP_DEFAULTS; + } else if (!strcmp(arg, "full")) { + how = OPTIONS_DUMP_ALL; + } else { + printf("%s is not a recognized argument to --dump-config. " + "Please select 'short', 'non-builtin', or 'full'", arg); + return -1; + } + + opts = options_dump(options, how); + printf("%s", opts); + tor_free(opts); + + return 0; +} + +#if defined (WINCE) +int +find_flashcard_path(PWCHAR path, size_t size) +{ + WIN32_FIND_DATA d = {0}; + HANDLE h = NULL; + + if (!path) + return -1; + + h = FindFirstFlashCard(&d); + if (h == INVALID_HANDLE_VALUE) + return -1; + + if (wcslen(d.cFileName) == 0) { + FindClose(h); + return -1; + } + + wcsncpy(path,d.cFileName,size); + FindClose(h); + return 0; +} +#endif + +static void +init_addrinfo(void) +{ + char hname[256]; + + // host name to sandbox + gethostname(hname, sizeof(hname)); + sandbox_add_addrinfo(hname); +} + +static sandbox_cfg_t* +sandbox_init_filter(void) +{ + sandbox_cfg_t *cfg = sandbox_cfg_new(); + + sandbox_cfg_allow_openat_filename(&cfg, + get_datadir_fname("cached-status"), 1); + + sandbox_cfg_allow_open_filename_array(&cfg, + get_datadir_fname("cached-certs"), 1, + get_datadir_fname("cached-certs.tmp"), 1, + get_datadir_fname("cached-consensus"), 1, + get_datadir_fname("unverified-consensus"), 1, + get_datadir_fname("unverified-consensus.tmp"), 1, + get_datadir_fname("cached-microdesc-consensus"), 1, + get_datadir_fname("cached-microdesc-consensus.tmp"), 1, + get_datadir_fname("cached-microdescs"), 1, + get_datadir_fname("cached-microdescs.tmp"), 1, + get_datadir_fname("cached-microdescs.new"), 1, + get_datadir_fname("cached-microdescs.new.tmp"), 1, + get_datadir_fname("unverified-microdesc-consensus"), 1, + get_datadir_fname("cached-descriptors"), 1, + get_datadir_fname("cached-descriptors.new"), 1, + get_datadir_fname("cached-descriptors.tmp"), 1, + get_datadir_fname("cached-descriptors.new.tmp"), 1, + get_datadir_fname("cached-descriptors.tmp.tmp"), 1, + get_datadir_fname("cached-extrainfo"), 1, + get_datadir_fname("state.tmp"), 1, + get_datadir_fname("unparseable-desc.tmp"), 1, + get_datadir_fname("unparseable-desc"), 1, + "/dev/srandom", 0, + "/dev/urandom", 0, + "/dev/random", 0, + NULL, 0 + ); + + sandbox_cfg_allow_stat_filename_array(&cfg, + get_datadir_fname(NULL), 1, + get_datadir_fname("lock"), 1, + get_datadir_fname("state"), 1, + get_datadir_fname("router-stability"), 1, + get_datadir_fname("cached-extrainfo.new"), 1, + NULL, 0 + ); + + // orport + if (server_mode(get_options())) { + sandbox_cfg_allow_open_filename_array(&cfg, + get_datadir_fname2("keys", "secret_id_key"), 1, + get_datadir_fname2("keys", "secret_onion_key"), 1, + get_datadir_fname2("keys", "secret_onion_key_ntor"), 1, + get_datadir_fname2("keys", "secret_onion_key_ntor.tmp"), 1, + get_datadir_fname2("keys", "secret_id_key.old"), 1, + get_datadir_fname2("keys", "secret_onion_key.old"), 1, + get_datadir_fname2("keys", "secret_onion_key_ntor.old"), 1, + get_datadir_fname2("keys", "secret_onion_key.tmp"), 1, + get_datadir_fname2("keys", "secret_id_key.tmp"), 1, + get_datadir_fname("fingerprint"), 1, + get_datadir_fname("fingerprint.tmp"), 1, + get_datadir_fname("cached-consensus"), 1, + get_datadir_fname("cached-consensus.tmp"), 1, + "/etc/resolv.conf", 0, + NULL, 0 + ); + + sandbox_cfg_allow_stat_filename_array(&cfg, + get_datadir_fname("keys"), 1, + get_datadir_fname("stats/dirreq-stats"), 1, + NULL, 0 + ); + } + + sandbox_cfg_allow_execve(&cfg, "/usr/local/bin/tor"); + + init_addrinfo(); + + return cfg; +} + +/** Main entry point for the Tor process. Called from main(). */ +/* This function is distinct from main() only so we can link onion_main.c into + * the unittest binary without conflicting with the unittests' main. */ +int +tor_main(int argc, char *argv[]) +{ + int result = 0; +#if defined (WINCE) + WCHAR path [MAX_PATH] = {0}; + WCHAR fullpath [MAX_PATH] = {0}; + PWCHAR p = NULL; + FILE* redir = NULL; + FILE* redirdbg = NULL; + + // this is to facilitate debugging by opening + // a file on a folder shared by the wm emulator. + // if no flashcard (real or emulated) is present, + // log files will be written in the root folder + if (find_flashcard_path(path,MAX_PATH) == -1) { + redir = _wfreopen( L"\\stdout.log", L"w", stdout ); + redirdbg = _wfreopen( L"\\stderr.log", L"w", stderr ); + } else { + swprintf(fullpath,L"\\%s\\tor",path); + CreateDirectory(fullpath,NULL); + + swprintf(fullpath,L"\\%s\\tor\\stdout.log",path); + redir = _wfreopen( fullpath, L"w", stdout ); + + swprintf(fullpath,L"\\%s\\tor\\stderr.log",path); + redirdbg = _wfreopen( fullpath, L"w", stderr ); + } +#endif + +#ifdef _WIN32 + /* Call SetProcessDEPPolicy to permanently enable DEP. + The function will not resolve on earlier versions of Windows, + and failure is not dangerous. */ + HMODULE hMod = GetModuleHandleA("Kernel32.dll"); + if (hMod) { + typedef BOOL (WINAPI *PSETDEP)(DWORD); + PSETDEP setdeppolicy = (PSETDEP)GetProcAddress(hMod, + "SetProcessDEPPolicy"); + if (setdeppolicy) setdeppolicy(1); /* PROCESS_DEP_ENABLE */ + } +#endif + + configure_backtrace_handler(get_version()); + + update_approx_time(time(NULL)); + tor_threads_init(); + init_logging(); +#ifdef USE_DMALLOC + { + /* Instruct OpenSSL to use our internal wrappers for malloc, + realloc and free. */ + int r = CRYPTO_set_mem_ex_functions(tor_malloc_, tor_realloc_, tor_free_); + tor_assert(r); + } +#endif +#ifdef NT_SERVICE + { + int done = 0; + result = nt_service_parse_options(argc, argv, &done); + if (done) return result; + } +#endif + if (tor_init(argc, argv)<0) + return -1; + + if (get_options()->Sandbox) { + sandbox_cfg_t* cfg = sandbox_init_filter(); + + if (sandbox_init(cfg)) { + log_err(LD_BUG,"Failed to create syscall sandbox filter"); + return -1; + } + + // registering libevent rng +#ifdef HAVE_EVUTIL_SECURE_RNG_SET_URANDOM_DEVICE_FILE + evutil_secure_rng_set_urandom_device_file( + (char*) sandbox_intern_string("/dev/urandom")); +#endif + } + + switch (get_options()->command) { + case CMD_RUN_TOR: +#ifdef NT_SERVICE + nt_service_set_state(SERVICE_RUNNING); +#endif + result = do_main_loop(); + break; + case CMD_LIST_FINGERPRINT: + result = do_list_fingerprint(); + break; + case CMD_HASH_PASSWORD: + do_hash_password(); + result = 0; + break; + case CMD_VERIFY_CONFIG: + printf("Configuration was valid\n"); + result = 0; + break; + case CMD_DUMP_CONFIG: + result = do_dump_config(); + break; + case CMD_RUN_UNITTESTS: /* only set by test.c */ + default: + log_warn(LD_BUG,"Illegal command number %d: internal error.", + get_options()->command); + result = -1; + } + tor_cleanup(); + return result; +} + diff --git a/src/tor/onion_main.h b/src/tor/onion_main.h new file mode 100644 index 0000000..1746ce8 --- /dev/null +++ b/src/tor/onion_main.h @@ -0,0 +1,86 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file onion_main.h + * \brief Header file for onion_main.c. + **/ + +#ifndef TOR_MAIN_H +#define TOR_MAIN_H + +#ifdef __cplusplus +extern "C" { +#endif + +extern int can_complete_circuit; + +int connection_add_impl(connection_t *conn, int is_connecting); +#define connection_add(conn) connection_add_impl((conn), 0) +#define connection_add_connecting(conn) connection_add_impl((conn), 1) +int connection_remove(connection_t *conn); +void connection_unregister_events(connection_t *conn); +int connection_in_array(connection_t *conn); +void add_connection_to_closeable_list(connection_t *conn); +int connection_is_on_closeable_list(connection_t *conn); + +smartlist_t *get_connection_array(void); +uint64_t get_bytes_read(void); +uint64_t get_bytes_written(void); + +/** Bitmask for events that we can turn on and off with + * connection_watch_events. */ +typedef enum watchable_events { + /* Yes, it is intentional that these match Libevent's EV_READ and EV_WRITE */ + READ_EVENT=0x02, /**< We want to know when a connection is readable */ + WRITE_EVENT=0x04 /**< We want to know when a connection is writable */ +} watchable_events_t; +void connection_watch_events(connection_t *conn, watchable_events_t events); +int connection_is_reading(connection_t *conn); +MOCK_DECL(void,connection_stop_reading,(connection_t *conn)); +MOCK_DECL(void,connection_start_reading,(connection_t *conn)); + +int connection_is_writing(connection_t *conn); +MOCK_DECL(void,connection_stop_writing,(connection_t *conn)); +MOCK_DECL(void,connection_start_writing,(connection_t *conn)); + +void connection_stop_reading_from_linked_conn(connection_t *conn); + +void directory_all_unreachable(time_t now); +void directory_info_has_arrived(time_t now, int from_cache); + +void ip_address_changed(int at_interface); +void dns_servers_relaunch_checks(void); + +long get_uptime(void); +unsigned get_signewnym_epoch(void); + +void handle_signals(int is_parent); +void process_signal(uintptr_t sig); + +int try_locking(const or_options_t *options, int err_if_locked); +int have_lockfile(void); +void release_lockfile(void); + +void tor_cleanup(void); +void tor_free_all(int postfork); + +int tor_main(int argc, char *argv[]); + +int do_main_loop(void); +int tor_init(int argc, char **argv); + +#ifdef MAIN_PRIVATE +STATIC void init_connection_lists(void); +STATIC void close_closeable_connections(void); +#endif + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/src/tor/onion_ntor.c b/src/tor/onion_ntor.c new file mode 100644 index 0000000..e37ce9e --- /dev/null +++ b/src/tor/onion_ntor.c @@ -0,0 +1,295 @@ +/* Copyright (c) 2012-2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#include "orconfig.h" + +#include "crypto.h" +#define ONION_NTOR_PRIVATE +#include "onion_ntor.h" +#include "torlog.h" +#include "tor_util.h" + +/** Free storage held in an ntor handshake state. */ +void +ntor_handshake_state_free(ntor_handshake_state_t *state) +{ + if (!state) + return; + memwipe(state, 0, sizeof(*state)); + tor_free(state); +} + +/** Convenience function to represent HMAC_SHA256 as our instantiation of + * ntor's "tweaked hash'. Hash the inp_len bytes at inp into + * a DIGEST256_LEN-byte digest at out, with the hash changing + * depending on the value of tweak. */ +static void +h_tweak(uint8_t *out, + const uint8_t *inp, size_t inp_len, + const char *tweak) +{ + size_t tweak_len = strlen(tweak); + crypto_hmac_sha256((char*)out, tweak, tweak_len, (const char*)inp, inp_len); +} + +/** Wrapper around a set of tweak-values for use with the ntor handshake. */ +typedef struct tweakset_t { + const char *t_mac; + const char *t_key; + const char *t_verify; + const char *m_expand; +} tweakset_t; + +/** The tweaks to be used with our handshake. */ +const tweakset_t proto1_tweaks = { +#define PROTOID "ntor-curve25519-sha256-1" +#define PROTOID_LEN 24 + PROTOID ":mac", + PROTOID ":key_extract", + PROTOID ":verify", + PROTOID ":key_expand" +}; + +/** Convenience macro: copy len bytes from inp to ptr, + * and advance ptr by the number of bytes copied. */ +#define APPEND(ptr, inp, len) \ + STMT_BEGIN { \ + memcpy(ptr, (inp), (len)); \ + ptr += len; \ + } STMT_END + +/** + * Compute the first client-side step of the ntor handshake for communicating + * with a server whose DIGEST_LEN-byte server identity is router_id, + * and whose onion key is router_key. Store the NTOR_ONIONSKIN_LEN-byte + * message in onion_skin_out, and store the handshake state in + * *handshake_state_out. Return 0 on success, -1 on failure. + */ +int +onion_skin_ntor_create(const uint8_t *router_id, + const curve25519_public_key_t *router_key, + ntor_handshake_state_t **handshake_state_out, + uint8_t *onion_skin_out) +{ + ntor_handshake_state_t *state; + uint8_t *op; + + state = tor_malloc_zero(sizeof(ntor_handshake_state_t)); + + memcpy(state->router_id, router_id, DIGEST_LEN); + memcpy(&state->pubkey_B, router_key, sizeof(curve25519_public_key_t)); + if (curve25519_secret_key_generate(&state->seckey_x, 0) < 0) { + tor_free(state); + return -1; + } + curve25519_public_key_generate(&state->pubkey_X, &state->seckey_x); + + op = onion_skin_out; + APPEND(op, router_id, DIGEST_LEN); + APPEND(op, router_key->public_key, CURVE25519_PUBKEY_LEN); + APPEND(op, state->pubkey_X.public_key, CURVE25519_PUBKEY_LEN); + tor_assert(op == onion_skin_out + NTOR_ONIONSKIN_LEN); + + *handshake_state_out = state; + + return 0; +} + +#define SERVER_STR "Server" +#define SERVER_STR_LEN 6 + +#define SECRET_INPUT_LEN (CURVE25519_PUBKEY_LEN * 3 + \ + CURVE25519_OUTPUT_LEN * 2 + \ + DIGEST_LEN + PROTOID_LEN) +#define AUTH_INPUT_LEN (DIGEST256_LEN + DIGEST_LEN + \ + CURVE25519_PUBKEY_LEN*3 + \ + PROTOID_LEN + SERVER_STR_LEN) + +/** + * Perform the server side of an ntor handshake. Given an + * NTOR_ONIONSKIN_LEN-byte message in onion_skin, our own identity + * fingerprint as my_node_id, and an associative array mapping public + * onion keys to curve25519_keypair_t in private_keys, attempt to + * perform the handshake. Use junk_keys if present if the handshake + * indicates an unrecognized public key. Write an NTOR_REPLY_LEN-byte + * message to send back to the client into handshake_reply_out, and + * generate key_out_len bytes of key material in key_out. Return + * 0 on success, -1 on failure. + */ +int +onion_skin_ntor_server_handshake(const uint8_t *onion_skin, + const di_digest256_map_t *private_keys, + const curve25519_keypair_t *junk_keys, + const uint8_t *my_node_id, + uint8_t *handshake_reply_out, + uint8_t *key_out, + size_t key_out_len) +{ + const tweakset_t *T = &proto1_tweaks; + /* Sensitive stack-allocated material. Kept in an anonymous struct to make + * it easy to wipe. */ + struct { + uint8_t secret_input[SECRET_INPUT_LEN]; + uint8_t auth_input[AUTH_INPUT_LEN]; + curve25519_public_key_t pubkey_X; + curve25519_secret_key_t seckey_y; + curve25519_public_key_t pubkey_Y; + uint8_t verify[DIGEST256_LEN]; + } s; + uint8_t *si = s.secret_input, *ai = s.auth_input; + const curve25519_keypair_t *keypair_bB; + int bad; + + /* Decode the onion skin */ + /* XXXX Does this possible early-return business threaten our security? */ + if (tor_memneq(onion_skin, my_node_id, DIGEST_LEN)) + return -1; + /* Note that on key-not-found, we go through with this operation anyway, + * using "junk_keys". This will result in failed authentication, but won't + * leak whether we recognized the key. */ + keypair_bB = dimap_search(private_keys, onion_skin + DIGEST_LEN, + (void*)junk_keys); + if (!keypair_bB) + return -1; + + memcpy(s.pubkey_X.public_key, onion_skin+DIGEST_LEN+DIGEST256_LEN, + CURVE25519_PUBKEY_LEN); + + /* Make y, Y */ + curve25519_secret_key_generate(&s.seckey_y, 0); + curve25519_public_key_generate(&s.pubkey_Y, &s.seckey_y); + + /* NOTE: If we ever use a group other than curve25519, or a different + * representation for its points, we may need to perform different or + * additional checks on X here and on Y in the client handshake, or lose our + * security properties. What checks we need would depend on the properties + * of the group and its representation. + * + * In short: if you use anything other than curve25519, this aspect of the + * code will need to be reconsidered carefully. */ + + /* build secret_input */ + curve25519_handshake(si, &s.seckey_y, &s.pubkey_X); + bad = safe_mem_is_zero(si, CURVE25519_OUTPUT_LEN); + si += CURVE25519_OUTPUT_LEN; + curve25519_handshake(si, &keypair_bB->seckey, &s.pubkey_X); + bad |= safe_mem_is_zero(si, CURVE25519_OUTPUT_LEN); + si += CURVE25519_OUTPUT_LEN; + + APPEND(si, my_node_id, DIGEST_LEN); + APPEND(si, keypair_bB->pubkey.public_key, CURVE25519_PUBKEY_LEN); + APPEND(si, s.pubkey_X.public_key, CURVE25519_PUBKEY_LEN); + APPEND(si, s.pubkey_Y.public_key, CURVE25519_PUBKEY_LEN); + APPEND(si, PROTOID, PROTOID_LEN); + tor_assert(si == s.secret_input + sizeof(s.secret_input)); + + /* Compute hashes of secret_input */ + h_tweak(s.verify, s.secret_input, sizeof(s.secret_input), T->t_verify); + + /* Compute auth_input */ + APPEND(ai, s.verify, DIGEST256_LEN); + APPEND(ai, my_node_id, DIGEST_LEN); + APPEND(ai, keypair_bB->pubkey.public_key, CURVE25519_PUBKEY_LEN); + APPEND(ai, s.pubkey_Y.public_key, CURVE25519_PUBKEY_LEN); + APPEND(ai, s.pubkey_X.public_key, CURVE25519_PUBKEY_LEN); + APPEND(ai, PROTOID, PROTOID_LEN); + APPEND(ai, SERVER_STR, SERVER_STR_LEN); + tor_assert(ai == s.auth_input + sizeof(s.auth_input)); + + /* Build the reply */ + memcpy(handshake_reply_out, s.pubkey_Y.public_key, CURVE25519_PUBKEY_LEN); + h_tweak(handshake_reply_out+CURVE25519_PUBKEY_LEN, + s.auth_input, sizeof(s.auth_input), + T->t_mac); + + /* Generate the key material */ + crypto_expand_key_material_rfc5869_sha256( + s.secret_input, sizeof(s.secret_input), + (const uint8_t*)T->t_key, strlen(T->t_key), + (const uint8_t*)T->m_expand, strlen(T->m_expand), + key_out, key_out_len); + + /* Wipe all of our local state */ + memwipe(&s, 0, sizeof(s)); + + return bad ? -1 : 0; +} + +/** + * Perform the final client side of the ntor handshake, using the state in + * handshake_state and the server's NTOR_REPLY_LEN-byte reply in + * handshake_reply. Generate key_out_len bytes of key material + * in key_out. Return 0 on success, -1 on failure. + */ +int +onion_skin_ntor_client_handshake( + const ntor_handshake_state_t *handshake_state, + const uint8_t *handshake_reply, + uint8_t *key_out, + size_t key_out_len) +{ + const tweakset_t *T = &proto1_tweaks; + /* Sensitive stack-allocated material. Kept in an anonymous struct to make + * it easy to wipe. */ + struct { + curve25519_public_key_t pubkey_Y; + uint8_t secret_input[SECRET_INPUT_LEN]; + uint8_t verify[DIGEST256_LEN]; + uint8_t auth_input[AUTH_INPUT_LEN]; + uint8_t auth[DIGEST256_LEN]; + } s; + uint8_t *ai = s.auth_input, *si = s.secret_input; + const uint8_t *auth_candidate; + int bad; + + /* Decode input */ + memcpy(s.pubkey_Y.public_key, handshake_reply, CURVE25519_PUBKEY_LEN); + auth_candidate = handshake_reply + CURVE25519_PUBKEY_LEN; + + /* See note in server_handshake above about checking points. The + * circumstances under which we'd need to check Y for membership are + * different than those under which we'd be checking X. */ + + /* Compute secret_input */ + curve25519_handshake(si, &handshake_state->seckey_x, &s.pubkey_Y); + bad = safe_mem_is_zero(si, CURVE25519_OUTPUT_LEN); + si += CURVE25519_OUTPUT_LEN; + curve25519_handshake(si, &handshake_state->seckey_x, + &handshake_state->pubkey_B); + bad |= safe_mem_is_zero(si, CURVE25519_OUTPUT_LEN); + si += CURVE25519_OUTPUT_LEN; + APPEND(si, handshake_state->router_id, DIGEST_LEN); + APPEND(si, handshake_state->pubkey_B.public_key, CURVE25519_PUBKEY_LEN); + APPEND(si, handshake_state->pubkey_X.public_key, CURVE25519_PUBKEY_LEN); + APPEND(si, s.pubkey_Y.public_key, CURVE25519_PUBKEY_LEN); + APPEND(si, PROTOID, PROTOID_LEN); + tor_assert(si == s.secret_input + sizeof(s.secret_input)); + + /* Compute verify from secret_input */ + h_tweak(s.verify, s.secret_input, sizeof(s.secret_input), T->t_verify); + + /* Compute auth_input */ + APPEND(ai, s.verify, DIGEST256_LEN); + APPEND(ai, handshake_state->router_id, DIGEST_LEN); + APPEND(ai, handshake_state->pubkey_B.public_key, CURVE25519_PUBKEY_LEN); + APPEND(ai, s.pubkey_Y.public_key, CURVE25519_PUBKEY_LEN); + APPEND(ai, handshake_state->pubkey_X.public_key, CURVE25519_PUBKEY_LEN); + APPEND(ai, PROTOID, PROTOID_LEN); + APPEND(ai, SERVER_STR, SERVER_STR_LEN); + tor_assert(ai == s.auth_input + sizeof(s.auth_input)); + + /* Compute auth */ + h_tweak(s.auth, s.auth_input, sizeof(s.auth_input), T->t_mac); + + bad |= tor_memneq(s.auth, auth_candidate, DIGEST256_LEN); + + crypto_expand_key_material_rfc5869_sha256( + s.secret_input, sizeof(s.secret_input), + (const uint8_t*)T->t_key, strlen(T->t_key), + (const uint8_t*)T->m_expand, strlen(T->m_expand), + key_out, key_out_len); + + memwipe(&s, 0, sizeof(s)); + return bad ? -1 : 0; +} + diff --git a/src/tor/onion_ntor.h b/src/tor/onion_ntor.h new file mode 100644 index 0000000..c942e6e --- /dev/null +++ b/src/tor/onion_ntor.h @@ -0,0 +1,63 @@ +/* Copyright (c) 2012-2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_ONION_NTOR_H +#define TOR_ONION_NTOR_H + +#include "torint.h" +#include "crypto_curve25519.h" +#include "di_ops.h" + +/** State to be maintained by a client between sending an ntor onionskin + * and receiving a reply. */ +typedef struct ntor_handshake_state_t ntor_handshake_state_t; + +/** Length of an ntor onionskin, as sent from the client to server. */ +#define NTOR_ONIONSKIN_LEN 84 +/** Length of an ntor reply, as sent from server to client. */ +#define NTOR_REPLY_LEN 64 + +#ifdef CURVE25519_ENABLED +void ntor_handshake_state_free(ntor_handshake_state_t *state); + +int onion_skin_ntor_create(const uint8_t *router_id, + const curve25519_public_key_t *router_key, + ntor_handshake_state_t **handshake_state_out, + uint8_t *onion_skin_out); + +int onion_skin_ntor_server_handshake(const uint8_t *onion_skin, + const di_digest256_map_t *private_keys, + const curve25519_keypair_t *junk_keypair, + const uint8_t *my_node_id, + uint8_t *handshake_reply_out, + uint8_t *key_out, + size_t key_out_len); + +int onion_skin_ntor_client_handshake( + const ntor_handshake_state_t *handshake_state, + const uint8_t *handshake_reply, + uint8_t *key_out, + size_t key_out_len); + +#ifdef ONION_NTOR_PRIVATE + +/** Storage held by a client while waiting for an ntor reply from a server. */ +struct ntor_handshake_state_t { + /** Identity digest of the router we're talking to. */ + uint8_t router_id[DIGEST_LEN]; + /** Onion key of the router we're talking to. */ + curve25519_public_key_t pubkey_B; + + /** + * Short-lived keypair for use with this handshake. + * @{ */ + curve25519_secret_key_t seckey_x; + curve25519_public_key_t pubkey_X; + /** @} */ +}; +#endif + +#endif + +#endif + diff --git a/src/tor/onion_tap.c b/src/tor/onion_tap.c new file mode 100644 index 0000000..3782e75 --- /dev/null +++ b/src/tor/onion_tap.c @@ -0,0 +1,218 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file onion_tap.c + * \brief Functions to implement the original Tor circuit extension handshake + * (a.k.a TAP). + * + * We didn't call it "TAP" ourselves -- Ian Goldberg named it in "On the + * Security of the Tor Authentication Protocol". (Spoiler: it's secure, but + * its security is kind of fragile and implementation dependent. Never modify + * this implementation without reading and understanding that paper at least.) + **/ + +#include "or.h" +#include "config.h" +#include "onion_tap.h" +#include "rephist.h" + +/*----------------------------------------------------------------------*/ + +/** Given a router's 128 byte public key, + * stores the following in onion_skin_out: + * - [42 bytes] OAEP padding + * - [16 bytes] Symmetric key for encrypting blob past RSA + * - [70 bytes] g^x part 1 (inside the RSA) + * - [58 bytes] g^x part 2 (symmetrically encrypted) + * + * Stores the DH private key into handshake_state_out for later completion + * of the handshake. + * + * The meeting point/cookies and auth are zeroed out for now. + */ +int +onion_skin_TAP_create(crypto_pk_t *dest_router_key, + crypto_dh_t **handshake_state_out, + char *onion_skin_out) /* TAP_ONIONSKIN_CHALLENGE_LEN bytes */ +{ + char challenge[DH_KEY_LEN]; + crypto_dh_t *dh = NULL; + int dhbytes, pkbytes; + + tor_assert(dest_router_key); + tor_assert(handshake_state_out); + tor_assert(onion_skin_out); + *handshake_state_out = NULL; + memset(onion_skin_out, 0, TAP_ONIONSKIN_CHALLENGE_LEN); + + if (!(dh = crypto_dh_new(DH_TYPE_CIRCUIT))) + goto err; + + dhbytes = crypto_dh_get_bytes(dh); + pkbytes = (int) crypto_pk_keysize(dest_router_key); + tor_assert(dhbytes == 128); + tor_assert(pkbytes == 128); + + if (crypto_dh_get_public(dh, challenge, dhbytes)) + goto err; + + note_crypto_pk_op(ENC_ONIONSKIN); + + /* set meeting point, meeting cookie, etc here. Leave zero for now. */ + if (crypto_pk_public_hybrid_encrypt(dest_router_key, onion_skin_out, + TAP_ONIONSKIN_CHALLENGE_LEN, + challenge, DH_KEY_LEN, + PK_PKCS1_OAEP_PADDING, 1)<0) + goto err; + + memwipe(challenge, 0, sizeof(challenge)); + *handshake_state_out = dh; + + return 0; + err: + memwipe(challenge, 0, sizeof(challenge)); + if (dh) crypto_dh_free(dh); + return -1; +} + +/** Given an encrypted DH public key as generated by onion_skin_create, + * and the private key for this onion router, generate the reply (128-byte + * DH plus the first 20 bytes of shared key material), and store the + * next key_out_len bytes of key material in key_out. + */ +int +onion_skin_TAP_server_handshake( + /*TAP_ONIONSKIN_CHALLENGE_LEN*/ + const char *onion_skin, + crypto_pk_t *private_key, + crypto_pk_t *prev_private_key, + /*TAP_ONIONSKIN_REPLY_LEN*/ + char *handshake_reply_out, + char *key_out, + size_t key_out_len) +{ + char challenge[TAP_ONIONSKIN_CHALLENGE_LEN]; + crypto_dh_t *dh = NULL; + ssize_t len; + char *key_material=NULL; + size_t key_material_len=0; + int i; + crypto_pk_t *k; + + len = -1; + for (i=0;i<2;++i) { + k = i==0?private_key:prev_private_key; + if (!k) + break; + note_crypto_pk_op(DEC_ONIONSKIN); + len = crypto_pk_private_hybrid_decrypt(k, challenge, + TAP_ONIONSKIN_CHALLENGE_LEN, + onion_skin, + TAP_ONIONSKIN_CHALLENGE_LEN, + PK_PKCS1_OAEP_PADDING,0); + if (len>0) + break; + } + if (len<0) { + log_info(LD_PROTOCOL, + "Couldn't decrypt onionskin: client may be using old onion key"); + goto err; + } else if (len != DH_KEY_LEN) { + log_warn(LD_PROTOCOL, "Unexpected onionskin length after decryption: %ld", + (long)len); + goto err; + } + + dh = crypto_dh_new(DH_TYPE_CIRCUIT); + if (!dh) { + log_warn(LD_BUG, "Couldn't allocate DH key"); + goto err; + } + if (crypto_dh_get_public(dh, handshake_reply_out, DH_KEY_LEN)) { + log_info(LD_GENERAL, "crypto_dh_get_public failed."); + goto err; + } + + key_material_len = DIGEST_LEN+key_out_len; + key_material = tor_malloc(key_material_len); + len = crypto_dh_compute_secret(LOG_PROTOCOL_WARN, dh, challenge, + DH_KEY_LEN, key_material, + key_material_len); + if (len < 0) { + log_info(LD_GENERAL, "crypto_dh_compute_secret failed."); + goto err; + } + + /* send back H(K|0) as proof that we learned K. */ + memcpy(handshake_reply_out+DH_KEY_LEN, key_material, DIGEST_LEN); + + /* use the rest of the key material for our shared keys, digests, etc */ + memcpy(key_out, key_material+DIGEST_LEN, key_out_len); + + memwipe(challenge, 0, sizeof(challenge)); + memwipe(key_material, 0, key_material_len); + tor_free(key_material); + crypto_dh_free(dh); + return 0; + err: + memwipe(challenge, 0, sizeof(challenge)); + if (key_material) { + memwipe(key_material, 0, key_material_len); + tor_free(key_material); + } + if (dh) crypto_dh_free(dh); + + return -1; +} + +/** Finish the client side of the DH handshake. + * Given the 128 byte DH reply + 20 byte hash as generated by + * onion_skin_server_handshake and the handshake state generated by + * onion_skin_create, verify H(K) with the first 20 bytes of shared + * key material, then generate key_out_len more bytes of shared key + * material and store them in key_out. + * + * After the invocation, call crypto_dh_free on handshake_state. + */ +int +onion_skin_TAP_client_handshake(crypto_dh_t *handshake_state, + const char *handshake_reply, /* TAP_ONIONSKIN_REPLY_LEN bytes */ + char *key_out, + size_t key_out_len) +{ + ssize_t len; + char *key_material=NULL; + size_t key_material_len; + tor_assert(crypto_dh_get_bytes(handshake_state) == DH_KEY_LEN); + + key_material_len = DIGEST_LEN + key_out_len; + key_material = tor_malloc(key_material_len); + len = crypto_dh_compute_secret(LOG_PROTOCOL_WARN, handshake_state, + handshake_reply, DH_KEY_LEN, key_material, + key_material_len); + if (len < 0) + goto err; + + if (tor_memneq(key_material, handshake_reply+DH_KEY_LEN, DIGEST_LEN)) { + /* H(K) does *not* match. Something fishy. */ + log_warn(LD_PROTOCOL,"Digest DOES NOT MATCH on onion handshake. " + "Bug or attack."); + goto err; + } + + /* use the rest of the key material for our shared keys, digests, etc */ + memcpy(key_out, key_material+DIGEST_LEN, key_out_len); + + memwipe(key_material, 0, key_material_len); + tor_free(key_material); + return 0; + err: + memwipe(key_material, 0, key_material_len); + tor_free(key_material); + return -1; +} + diff --git a/src/tor/onion_tap.h b/src/tor/onion_tap.h new file mode 100644 index 0000000..b978b66 --- /dev/null +++ b/src/tor/onion_tap.h @@ -0,0 +1,37 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file onion_tap.h + * \brief Header file for onion_tap.c. + **/ + +#ifndef TOR_ONION_TAP_H +#define TOR_ONION_TAP_H + +#define TAP_ONIONSKIN_CHALLENGE_LEN (PKCS1_OAEP_PADDING_OVERHEAD+\ + CIPHER_KEY_LEN+\ + DH_KEY_LEN) +#define TAP_ONIONSKIN_REPLY_LEN (DH_KEY_LEN+DIGEST_LEN) + +int onion_skin_TAP_create(crypto_pk_t *router_key, + crypto_dh_t **handshake_state_out, + char *onion_skin_out); + +int onion_skin_TAP_server_handshake(const char *onion_skin, + crypto_pk_t *private_key, + crypto_pk_t *prev_private_key, + char *handshake_reply_out, + char *key_out, + size_t key_out_len); + +int onion_skin_TAP_client_handshake(crypto_dh_t *handshake_state, + const char *handshake_reply, + char *key_out, + size_t key_out_len); + +#endif + diff --git a/src/tor/or.h b/src/tor/or.h new file mode 100644 index 0000000..e28f82c --- /dev/null +++ b/src/tor/or.h @@ -0,0 +1,5044 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file or.h + * \brief Master header file for Tor-specific functionality. + **/ + +#ifndef TOR_OR_H +#define TOR_OR_H + +#include "orconfig.h" + +#ifdef __COVERITY__ +/* If we're building for a static analysis, turn on all the off-by-default + * features. */ +#ifndef INSTRUMENT_DOWNLOADS +#define INSTRUMENT_DOWNLOADS 1 +#endif +#endif + +#ifdef _WIN32 +#ifndef _WIN32_WINNT +#define _WIN32_WINNT 0x0501 +#endif +#define WIN32_LEAN_AND_MEAN +#endif + +#ifdef HAVE_UNISTD_H +#include +#endif +#ifdef HAVE_SIGNAL_H +#include +#endif +#ifdef HAVE_NETDB_H +#include +#endif +#ifdef HAVE_SYS_PARAM_H +#include /* FreeBSD needs this to know what version it is */ +#endif +#include "torint.h" +#ifdef HAVE_SYS_WAIT_H +#include +#endif +#ifdef HAVE_SYS_FCNTL_H +#include +#endif +#ifdef HAVE_FCNTL_H +#include +#endif +#ifdef HAVE_SYS_IOCTL_H +#include +#endif +#ifdef HAVE_SYS_UN_H +#include +#endif +#ifdef HAVE_SYS_STAT_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_ARPA_INET_H +#include +#endif +#ifdef HAVE_ERRNO_H +#include +#endif +#ifdef HAVE_ASSERT_H +#include +#endif +#ifdef HAVE_TIME_H +#include +#endif + +#ifdef _WIN32 +#include +#include +#include +#include +#endif + +#ifdef USE_BUFFEREVENTS +#include +#include +#include +#endif + +#include "crypto.h" +#include "tortls.h" +#include "torlog.h" +#include "container.h" +#include "torgzip.h" +#include "address.h" +#include "compat_libevent.h" +#include "ht.h" +#include "replaycache.h" +#include "crypto_curve25519.h" +#include "tor_queue.h" + +/* These signals are defined to help handle_control_signal work. + */ +#ifndef SIGHUP +#define SIGHUP 1 +#endif +#ifndef SIGINT +#define SIGINT 2 +#endif +#ifndef SIGUSR1 +#define SIGUSR1 10 +#endif +#ifndef SIGUSR2 +#define SIGUSR2 12 +#endif +#ifndef SIGTERM +#define SIGTERM 15 +#endif +/* Controller signals start at a high number so we don't + * conflict with system-defined signals. */ +#define SIGNEWNYM 129 +#define SIGCLEARDNSCACHE 130 + +#if (SIZEOF_CELL_T != 0) +/* On Irix, stdlib.h defines a cell_t type, so we need to make sure + * that our stuff always calls cell_t something different. */ +#define cell_t tor_cell_t +#endif + +#ifdef ENABLE_TOR2WEB_MODE +#define NON_ANONYMOUS_MODE_ENABLED 1 +#endif + +/** Length of longest allowable configured nickname. */ +#define MAX_NICKNAME_LEN 19 +/** Length of a router identity encoded as a hexadecimal digest, plus + * possible dollar sign. */ +#define MAX_HEX_NICKNAME_LEN (HEX_DIGEST_LEN+1) +/** Maximum length of verbose router identifier: dollar sign, hex ID digest, + * equal sign or tilde, nickname. */ +#define MAX_VERBOSE_NICKNAME_LEN (1+HEX_DIGEST_LEN+1+MAX_NICKNAME_LEN) + +/** Maximum size, in bytes, for resized buffers. */ +#define MAX_BUF_SIZE ((1<<24)-1) /* 16MB-1 */ +/** Maximum size, in bytes, for any directory object that we've downloaded. */ +#define MAX_DIR_DL_SIZE MAX_BUF_SIZE + +/** For HTTP parsing: Maximum number of bytes we'll accept in the headers + * of an HTTP request or response. */ +#define MAX_HEADERS_SIZE 50000 +/** Maximum size, in bytes, for any directory object that we're accepting + * as an upload. */ +#define MAX_DIR_UL_SIZE MAX_BUF_SIZE + +/** Maximum size, in bytes, of a single router descriptor uploaded to us + * as a directory authority. Caches and clients fetch whatever descriptors + * the authorities tell them to fetch, and don't care about size. */ +#define MAX_DESCRIPTOR_UPLOAD_SIZE 20000 + +/** Maximum size of a single extrainfo document, as above. */ +#define MAX_EXTRAINFO_UPLOAD_SIZE 50000 + +/** How long do we keep DNS cache entries before purging them (regardless of + * their TTL)? */ +#define MAX_DNS_ENTRY_AGE (30*60) +/** How long do we cache/tell clients to cache DNS records when no TTL is + * known? */ +#define DEFAULT_DNS_TTL (30*60) +/** How long can a TTL be before we stop believing it? */ +#define MAX_DNS_TTL (3*60*60) +/** How small can a TTL be before we stop believing it? Provides rudimentary + * pinning. */ +#define MIN_DNS_TTL 60 + +/** How often do we rotate onion keys? */ +#define MIN_ONION_KEY_LIFETIME (7*24*60*60) +/** How often do we rotate TLS contexts? */ +#define MAX_SSL_KEY_LIFETIME_INTERNAL (2*60*60) + +/** How old do we allow a router to get before removing it + * from the router list? In seconds. */ +#define ROUTER_MAX_AGE (60*60*48) +/** How old can a router get before we (as a server) will no longer + * consider it live? In seconds. */ +#define ROUTER_MAX_AGE_TO_PUBLISH (60*60*24) +/** How old do we let a saved descriptor get before force-removing it? */ +#define OLD_ROUTER_DESC_MAX_AGE (60*60*24*5) + +/** Possible rules for generating circuit IDs on an OR connection. */ +typedef enum { + CIRC_ID_TYPE_LOWER=0, /**< Pick from 0..1<<15-1. */ + CIRC_ID_TYPE_HIGHER=1, /**< Pick from 1<<15..1<<16-1. */ + /** The other side of a connection is an OP: never create circuits to it, + * and let it use any circuit ID it wants. */ + CIRC_ID_TYPE_NEITHER=2 +} circ_id_type_t; + +#define CONN_TYPE_MIN_ 3 +/** Type for sockets listening for OR connections. */ +#define CONN_TYPE_OR_LISTENER 3 +/** A bidirectional TLS connection transmitting a sequence of cells. + * May be from an OR to an OR, or from an OP to an OR. */ +#define CONN_TYPE_OR 4 +/** A TCP connection from an onion router to a stream's destination. */ +#define CONN_TYPE_EXIT 5 +/** Type for sockets listening for SOCKS connections. */ +#define CONN_TYPE_AP_LISTENER 6 +/** A SOCKS proxy connection from the user application to the onion + * proxy. */ +#define CONN_TYPE_AP 7 +/** Type for sockets listening for HTTP connections to the directory server. */ +#define CONN_TYPE_DIR_LISTENER 8 +/** Type for HTTP connections to the directory server. */ +#define CONN_TYPE_DIR 9 +/** Connection from the main process to a CPU worker process. */ +#define CONN_TYPE_CPUWORKER 10 +/** Type for listening for connections from user interface process. */ +#define CONN_TYPE_CONTROL_LISTENER 11 +/** Type for connections from user interface process. */ +#define CONN_TYPE_CONTROL 12 +/** Type for sockets listening for transparent connections redirected by pf or + * netfilter. */ +#define CONN_TYPE_AP_TRANS_LISTENER 13 +/** Type for sockets listening for transparent connections redirected by + * natd. */ +#define CONN_TYPE_AP_NATD_LISTENER 14 +/** Type for sockets listening for DNS requests. */ +#define CONN_TYPE_AP_DNS_LISTENER 15 + +/** Type for connections from the Extended ORPort. */ +#define CONN_TYPE_EXT_OR 16 +/** Type for sockets listening for Extended ORPort connections. */ +#define CONN_TYPE_EXT_OR_LISTENER 17 + +#define CONN_TYPE_MAX_ 17 +/* !!!! If _CONN_TYPE_MAX is ever over 31, we must grow the type field in + * connection_t. */ + +/* Proxy client types */ +#define PROXY_NONE 0 +#define PROXY_CONNECT 1 +#define PROXY_SOCKS4 2 +#define PROXY_SOCKS5 3 +/* !!!! If there is ever a PROXY_* type over 2, we must grow the proxy_type + * field in or_connection_t */ + +/* Pluggable transport proxy type. Don't use this in or_connection_t, + * instead use the actual underlying proxy type (see above). */ +#define PROXY_PLUGGABLE 4 + +/* Proxy client handshake states */ +/* We use a proxy but we haven't even connected to it yet. */ +#define PROXY_INFANT 1 +/* We use an HTTP proxy and we've sent the CONNECT command. */ +#define PROXY_HTTPS_WANT_CONNECT_OK 2 +/* We use a SOCKS4 proxy and we've sent the CONNECT command. */ +#define PROXY_SOCKS4_WANT_CONNECT_OK 3 +/* We use a SOCKS5 proxy and we try to negotiate without + any authentication . */ +#define PROXY_SOCKS5_WANT_AUTH_METHOD_NONE 4 +/* We use a SOCKS5 proxy and we try to negotiate with + Username/Password authentication . */ +#define PROXY_SOCKS5_WANT_AUTH_METHOD_RFC1929 5 +/* We use a SOCKS5 proxy and we just sent our credentials. */ +#define PROXY_SOCKS5_WANT_AUTH_RFC1929_OK 6 +/* We use a SOCKS5 proxy and we just sent our CONNECT command. */ +#define PROXY_SOCKS5_WANT_CONNECT_OK 7 +/* We use a proxy and we CONNECTed successfully!. */ +#define PROXY_CONNECTED 8 + +/** True iff x is an edge connection. */ +#define CONN_IS_EDGE(x) \ + ((x)->type == CONN_TYPE_EXIT || (x)->type == CONN_TYPE_AP) + +/** State for any listener connection. */ +#define LISTENER_STATE_READY 0 + +#define CPUWORKER_STATE_MIN_ 1 +/** State for a connection to a cpuworker process that's idle. */ +#define CPUWORKER_STATE_IDLE 1 +/** State for a connection to a cpuworker process that's processing a + * handshake. */ +#define CPUWORKER_STATE_BUSY_ONION 2 +#define CPUWORKER_STATE_MAX_ 2 + +#define CPUWORKER_TASK_ONION CPUWORKER_STATE_BUSY_ONION +#define CPUWORKER_TASK_SHUTDOWN 255 + +#define OR_CONN_STATE_MIN_ 1 +/** State for a connection to an OR: waiting for connect() to finish. */ +#define OR_CONN_STATE_CONNECTING 1 +/** State for a connection to an OR: waiting for proxy handshake to complete */ +#define OR_CONN_STATE_PROXY_HANDSHAKING 2 +/** State for an OR connection client: SSL is handshaking, not done + * yet. */ +#define OR_CONN_STATE_TLS_HANDSHAKING 3 +/** State for a connection to an OR: We're doing a second SSL handshake for + * renegotiation purposes. (V2 handshake only.) */ +#define OR_CONN_STATE_TLS_CLIENT_RENEGOTIATING 4 +/** State for a connection at an OR: We're waiting for the client to + * renegotiate (to indicate a v2 handshake) or send a versions cell (to + * indicate a v3 handshake) */ +#define OR_CONN_STATE_TLS_SERVER_RENEGOTIATING 5 +/** State for an OR connection: We're done with our SSL handshake, we've done + * renegotiation, but we haven't yet negotiated link protocol versions and + * sent a netinfo cell. */ +#define OR_CONN_STATE_OR_HANDSHAKING_V2 6 +/** State for an OR connection: We're done with our SSL handshake, but we + * haven't yet negotiated link protocol versions, done a V3 handshake, and + * sent a netinfo cell. */ +#define OR_CONN_STATE_OR_HANDSHAKING_V3 7 +/** State for an OR connection: Ready to send/receive cells. */ +#define OR_CONN_STATE_OPEN 8 +#define OR_CONN_STATE_MAX_ 8 + +/** States of the Extended ORPort protocol. Be careful before changing + * the numbers: they matter. */ +#define EXT_OR_CONN_STATE_MIN_ 1 +/** Extended ORPort authentication is waiting for the authentication + * type selected by the client. */ +#define EXT_OR_CONN_STATE_AUTH_WAIT_AUTH_TYPE 1 +/** Extended ORPort authentication is waiting for the client nonce. */ +#define EXT_OR_CONN_STATE_AUTH_WAIT_CLIENT_NONCE 2 +/** Extended ORPort authentication is waiting for the client hash. */ +#define EXT_OR_CONN_STATE_AUTH_WAIT_CLIENT_HASH 3 +#define EXT_OR_CONN_STATE_AUTH_MAX 3 +/** Authentication finished and the Extended ORPort is now accepting + * traffic. */ +#define EXT_OR_CONN_STATE_OPEN 4 +/** Extended ORPort is flushing its last messages and preparing to + * start accepting OR connections. */ +#define EXT_OR_CONN_STATE_FLUSHING 5 +#define EXT_OR_CONN_STATE_MAX_ 5 + +#define EXIT_CONN_STATE_MIN_ 1 +/** State for an exit connection: waiting for response from DNS farm. */ +#define EXIT_CONN_STATE_RESOLVING 1 +/** State for an exit connection: waiting for connect() to finish. */ +#define EXIT_CONN_STATE_CONNECTING 2 +/** State for an exit connection: open and ready to transmit data. */ +#define EXIT_CONN_STATE_OPEN 3 +/** State for an exit connection: waiting to be removed. */ +#define EXIT_CONN_STATE_RESOLVEFAILED 4 +#define EXIT_CONN_STATE_MAX_ 4 + +/* The AP state values must be disjoint from the EXIT state values. */ +#define AP_CONN_STATE_MIN_ 5 +/** State for a SOCKS connection: waiting for SOCKS request. */ +#define AP_CONN_STATE_SOCKS_WAIT 5 +/** State for a SOCKS connection: got a y.onion URL; waiting to receive + * rendezvous descriptor. */ +#define AP_CONN_STATE_RENDDESC_WAIT 6 +/** The controller will attach this connection to a circuit; it isn't our + * job to do so. */ +#define AP_CONN_STATE_CONTROLLER_WAIT 7 +/** State for a SOCKS connection: waiting for a completed circuit. */ +#define AP_CONN_STATE_CIRCUIT_WAIT 8 +/** State for a SOCKS connection: sent BEGIN, waiting for CONNECTED. */ +#define AP_CONN_STATE_CONNECT_WAIT 9 +/** State for a SOCKS connection: sent RESOLVE, waiting for RESOLVED. */ +#define AP_CONN_STATE_RESOLVE_WAIT 10 +/** State for a SOCKS connection: ready to send and receive. */ +#define AP_CONN_STATE_OPEN 11 +/** State for a transparent natd connection: waiting for original + * destination. */ +#define AP_CONN_STATE_NATD_WAIT 12 +#define AP_CONN_STATE_MAX_ 12 + +/** True iff the AP_CONN_STATE_* value s means that the corresponding + * edge connection is not attached to any circuit. */ +#define AP_CONN_STATE_IS_UNATTACHED(s) \ + ((s) <= AP_CONN_STATE_CIRCUIT_WAIT || (s) == AP_CONN_STATE_NATD_WAIT) + +#define DIR_CONN_STATE_MIN_ 1 +/** State for connection to directory server: waiting for connect(). */ +#define DIR_CONN_STATE_CONNECTING 1 +/** State for connection to directory server: sending HTTP request. */ +#define DIR_CONN_STATE_CLIENT_SENDING 2 +/** State for connection to directory server: reading HTTP response. */ +#define DIR_CONN_STATE_CLIENT_READING 3 +/** State for connection to directory server: happy and finished. */ +#define DIR_CONN_STATE_CLIENT_FINISHED 4 +/** State for connection at directory server: waiting for HTTP request. */ +#define DIR_CONN_STATE_SERVER_COMMAND_WAIT 5 +/** State for connection at directory server: sending HTTP response. */ +#define DIR_CONN_STATE_SERVER_WRITING 6 +#define DIR_CONN_STATE_MAX_ 6 + +/** True iff the purpose of conn means that it's a server-side + * directory connection. */ +#define DIR_CONN_IS_SERVER(conn) ((conn)->purpose == DIR_PURPOSE_SERVER) + +#define CONTROL_CONN_STATE_MIN_ 1 +/** State for a control connection: Authenticated and accepting v1 commands. */ +#define CONTROL_CONN_STATE_OPEN 1 +/** State for a control connection: Waiting for authentication; speaking + * protocol v1. */ +#define CONTROL_CONN_STATE_NEEDAUTH 2 +#define CONTROL_CONN_STATE_MAX_ 2 + +#define DIR_PURPOSE_MIN_ 3 +/** A connection to a directory server: download a rendezvous + * descriptor. */ +#define DIR_PURPOSE_FETCH_RENDDESC 3 +/** A connection to a directory server: set after a rendezvous + * descriptor is downloaded. */ +#define DIR_PURPOSE_HAS_FETCHED_RENDDESC 4 +/** A connection to a directory server: download one or more server + * descriptors. */ +#define DIR_PURPOSE_FETCH_SERVERDESC 6 +/** A connection to a directory server: download one or more extra-info + * documents. */ +#define DIR_PURPOSE_FETCH_EXTRAINFO 7 +/** A connection to a directory server: upload a server descriptor. */ +#define DIR_PURPOSE_UPLOAD_DIR 8 +/** A connection to a directory server: upload a rendezvous + * descriptor. */ +#define DIR_PURPOSE_UPLOAD_RENDDESC 9 +/** A connection to a directory server: upload a v3 networkstatus vote. */ +#define DIR_PURPOSE_UPLOAD_VOTE 10 +/** A connection to a directory server: upload a v3 consensus signature */ +#define DIR_PURPOSE_UPLOAD_SIGNATURES 11 +/** A connection to a directory server: download one or more v3 networkstatus + * votes. */ +#define DIR_PURPOSE_FETCH_STATUS_VOTE 12 +/** A connection to a directory server: download a v3 detached signatures + * object for a consensus. */ +#define DIR_PURPOSE_FETCH_DETACHED_SIGNATURES 13 +/** A connection to a directory server: download a v3 networkstatus + * consensus. */ +#define DIR_PURPOSE_FETCH_CONSENSUS 14 +/** A connection to a directory server: download one or more directory + * authority certificates. */ +#define DIR_PURPOSE_FETCH_CERTIFICATE 15 + +/** Purpose for connection at a directory server. */ +#define DIR_PURPOSE_SERVER 16 +/** A connection to a hidden service directory server: upload a v2 rendezvous + * descriptor. */ +#define DIR_PURPOSE_UPLOAD_RENDDESC_V2 17 +/** A connection to a hidden service directory server: download a v2 rendezvous + * descriptor. */ +#define DIR_PURPOSE_FETCH_RENDDESC_V2 18 +/** A connection to a directory server: download a microdescriptor. */ +#define DIR_PURPOSE_FETCH_MICRODESC 19 +#define DIR_PURPOSE_MAX_ 19 + +/** True iff p is a purpose corresponding to uploading data to a + * directory server. */ +#define DIR_PURPOSE_IS_UPLOAD(p) \ + ((p)==DIR_PURPOSE_UPLOAD_DIR || \ + (p)==DIR_PURPOSE_UPLOAD_RENDDESC || \ + (p)==DIR_PURPOSE_UPLOAD_VOTE || \ + (p)==DIR_PURPOSE_UPLOAD_SIGNATURES) + +#define EXIT_PURPOSE_MIN_ 1 +/** This exit stream wants to do an ordinary connect. */ +#define EXIT_PURPOSE_CONNECT 1 +/** This exit stream wants to do a resolve (either normal or reverse). */ +#define EXIT_PURPOSE_RESOLVE 2 +#define EXIT_PURPOSE_MAX_ 2 + +/* !!!! If any connection purpose is ever over 31, we must grow the type + * field in connection_t. */ + +/** Circuit state: I'm the origin, still haven't done all my handshakes. */ +#define CIRCUIT_STATE_BUILDING 0 +/** Circuit state: Waiting to process the onionskin. */ +#define CIRCUIT_STATE_ONIONSKIN_PENDING 1 +/** Circuit state: I'd like to deliver a create, but my n_chan is still + * connecting. */ +#define CIRCUIT_STATE_CHAN_WAIT 2 +/** Circuit state: onionskin(s) processed, ready to send/receive cells. */ +#define CIRCUIT_STATE_OPEN 3 + +#define CIRCUIT_PURPOSE_MIN_ 1 + +/* these circuits were initiated elsewhere */ +#define CIRCUIT_PURPOSE_OR_MIN_ 1 +/** OR-side circuit purpose: normal circuit, at OR. */ +#define CIRCUIT_PURPOSE_OR 1 +/** OR-side circuit purpose: At OR, from Bob, waiting for intro from Alices. */ +#define CIRCUIT_PURPOSE_INTRO_POINT 2 +/** OR-side circuit purpose: At OR, from Alice, waiting for Bob. */ +#define CIRCUIT_PURPOSE_REND_POINT_WAITING 3 +/** OR-side circuit purpose: At OR, both circuits have this purpose. */ +#define CIRCUIT_PURPOSE_REND_ESTABLISHED 4 +#define CIRCUIT_PURPOSE_OR_MAX_ 4 + +/* these circuits originate at this node */ + +/* here's how circ client-side purposes work: + * normal circuits are C_GENERAL. + * circuits that are c_introducing are either on their way to + * becoming open, or they are open and waiting for a + * suitable rendcirc before they send the intro. + * circuits that are c_introduce_ack_wait have sent the intro, + * but haven't gotten a response yet. + * circuits that are c_establish_rend are either on their way + * to becoming open, or they are open and have sent the + * establish_rendezvous cell but haven't received an ack. + * circuits that are c_rend_ready are open and have received a + * rend ack, but haven't heard from bob yet. if they have a + * buildstate->pending_final_cpath then they're expecting a + * cell from bob, else they're not. + * circuits that are c_rend_ready_intro_acked are open, and + * some intro circ has sent its intro and received an ack. + * circuits that are c_rend_joined are open, have heard from + * bob, and are talking to him. + */ +/** Client-side circuit purpose: Normal circuit, with cpath. */ +#define CIRCUIT_PURPOSE_C_GENERAL 5 +/** Client-side circuit purpose: at Alice, connecting to intro point. */ +#define CIRCUIT_PURPOSE_C_INTRODUCING 6 +/** Client-side circuit purpose: at Alice, sent INTRODUCE1 to intro point, + * waiting for ACK/NAK. */ +#define CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT 7 +/** Client-side circuit purpose: at Alice, introduced and acked, closing. */ +#define CIRCUIT_PURPOSE_C_INTRODUCE_ACKED 8 +/** Client-side circuit purpose: at Alice, waiting for ack. */ +#define CIRCUIT_PURPOSE_C_ESTABLISH_REND 9 +/** Client-side circuit purpose: at Alice, waiting for Bob. */ +#define CIRCUIT_PURPOSE_C_REND_READY 10 +/** Client-side circuit purpose: at Alice, waiting for Bob, INTRODUCE + * has been acknowledged. */ +#define CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED 11 +/** Client-side circuit purpose: at Alice, rendezvous established. */ +#define CIRCUIT_PURPOSE_C_REND_JOINED 12 +/** This circuit is used for build time measurement only */ +#define CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT 13 +#define CIRCUIT_PURPOSE_C_MAX_ 13 +/** Hidden-service-side circuit purpose: at Bob, waiting for introductions. */ +#define CIRCUIT_PURPOSE_S_ESTABLISH_INTRO 14 +/** Hidden-service-side circuit purpose: at Bob, successfully established + * intro. */ +#define CIRCUIT_PURPOSE_S_INTRO 15 +/** Hidden-service-side circuit purpose: at Bob, connecting to rend point. */ +#define CIRCUIT_PURPOSE_S_CONNECT_REND 16 +/** Hidden-service-side circuit purpose: at Bob, rendezvous established. */ +#define CIRCUIT_PURPOSE_S_REND_JOINED 17 +/** A testing circuit; not meant to be used for actual traffic. */ +#define CIRCUIT_PURPOSE_TESTING 18 +/** A controller made this circuit and Tor should not use it. */ +#define CIRCUIT_PURPOSE_CONTROLLER 19 +/** This circuit is used for path bias probing only */ +#define CIRCUIT_PURPOSE_PATH_BIAS_TESTING 20 +#define CIRCUIT_PURPOSE_MAX_ 20 +/** A catch-all for unrecognized purposes. Currently we don't expect + * to make or see any circuits with this purpose. */ +#define CIRCUIT_PURPOSE_UNKNOWN 255 + +/** True iff the circuit purpose p is for a circuit that + * originated at this node. */ +#define CIRCUIT_PURPOSE_IS_ORIGIN(p) ((p)>CIRCUIT_PURPOSE_OR_MAX_) +/** True iff the circuit purpose p is for a circuit that originated + * here to serve as a client. (Hidden services don't count here.) */ +#define CIRCUIT_PURPOSE_IS_CLIENT(p) \ + ((p)> CIRCUIT_PURPOSE_OR_MAX_ && \ + (p)<=CIRCUIT_PURPOSE_C_MAX_) +/** True iff the circuit_t c is actually an origin_circuit_t. */ +#define CIRCUIT_IS_ORIGIN(c) (CIRCUIT_PURPOSE_IS_ORIGIN((c)->purpose)) +/** True iff the circuit purpose p is for an established rendezvous + * circuit. */ +#define CIRCUIT_PURPOSE_IS_ESTABLISHED_REND(p) \ + ((p) == CIRCUIT_PURPOSE_C_REND_JOINED || \ + (p) == CIRCUIT_PURPOSE_S_REND_JOINED) +/** True iff the circuit_t c is actually an or_circuit_t */ +#define CIRCUIT_IS_ORCIRC(c) (((circuit_t *)(c))->magic == OR_CIRCUIT_MAGIC) + +/** How many circuits do we want simultaneously in-progress to handle + * a given stream? */ +#define MIN_CIRCUITS_HANDLING_STREAM 2 + +/* These RELAY_COMMAND constants define values for relay cell commands, and +* must match those defined in tor-spec.txt. */ +#define RELAY_COMMAND_BEGIN 1 +#define RELAY_COMMAND_DATA 2 +#define RELAY_COMMAND_END 3 +#define RELAY_COMMAND_CONNECTED 4 +#define RELAY_COMMAND_SENDME 5 +#define RELAY_COMMAND_EXTEND 6 +#define RELAY_COMMAND_EXTENDED 7 +#define RELAY_COMMAND_TRUNCATE 8 +#define RELAY_COMMAND_TRUNCATED 9 +#define RELAY_COMMAND_DROP 10 +#define RELAY_COMMAND_RESOLVE 11 +#define RELAY_COMMAND_RESOLVED 12 +#define RELAY_COMMAND_BEGIN_DIR 13 +#define RELAY_COMMAND_EXTEND2 14 +#define RELAY_COMMAND_EXTENDED2 15 + +#define RELAY_COMMAND_ESTABLISH_INTRO 32 +#define RELAY_COMMAND_ESTABLISH_RENDEZVOUS 33 +#define RELAY_COMMAND_INTRODUCE1 34 +#define RELAY_COMMAND_INTRODUCE2 35 +#define RELAY_COMMAND_RENDEZVOUS1 36 +#define RELAY_COMMAND_RENDEZVOUS2 37 +#define RELAY_COMMAND_INTRO_ESTABLISHED 38 +#define RELAY_COMMAND_RENDEZVOUS_ESTABLISHED 39 +#define RELAY_COMMAND_INTRODUCE_ACK 40 + +/* Reasons why an OR connection is closed. */ +#define END_OR_CONN_REASON_DONE 1 +#define END_OR_CONN_REASON_REFUSED 2 /* connection refused */ +#define END_OR_CONN_REASON_OR_IDENTITY 3 +#define END_OR_CONN_REASON_CONNRESET 4 /* connection reset by peer */ +#define END_OR_CONN_REASON_TIMEOUT 5 +#define END_OR_CONN_REASON_NO_ROUTE 6 /* no route to host/net */ +#define END_OR_CONN_REASON_IO_ERROR 7 /* read/write error */ +#define END_OR_CONN_REASON_RESOURCE_LIMIT 8 /* sockets, buffers, etc */ +#define END_OR_CONN_REASON_MISC 9 + +/* Reasons why we (or a remote OR) might close a stream. See tor-spec.txt for + * documentation of these. The values must match. */ +#define END_STREAM_REASON_MISC 1 +#define END_STREAM_REASON_RESOLVEFAILED 2 +#define END_STREAM_REASON_CONNECTREFUSED 3 +#define END_STREAM_REASON_EXITPOLICY 4 +#define END_STREAM_REASON_DESTROY 5 +#define END_STREAM_REASON_DONE 6 +#define END_STREAM_REASON_TIMEOUT 7 +#define END_STREAM_REASON_NOROUTE 8 +#define END_STREAM_REASON_HIBERNATING 9 +#define END_STREAM_REASON_INTERNAL 10 +#define END_STREAM_REASON_RESOURCELIMIT 11 +#define END_STREAM_REASON_CONNRESET 12 +#define END_STREAM_REASON_TORPROTOCOL 13 +#define END_STREAM_REASON_NOTDIRECTORY 14 +#define END_STREAM_REASON_ENTRYPOLICY 15 + +/* These high-numbered end reasons are not part of the official spec, + * and are not intended to be put in relay end cells. They are here + * to be more informative when sending back socks replies to the + * application. */ +/* XXXX 256 is no longer used; feel free to reuse it. */ +/** We were unable to attach the connection to any circuit at all. */ +/* XXXX the ways we use this one don't make a lot of sense. */ +#define END_STREAM_REASON_CANT_ATTACH 257 +/** We can't connect to any directories at all, so we killed our streams + * before they can time out. */ +#define END_STREAM_REASON_NET_UNREACHABLE 258 +/** This is a SOCKS connection, and the client used (or misused) the SOCKS + * protocol in a way we couldn't handle. */ +#define END_STREAM_REASON_SOCKSPROTOCOL 259 +/** This is a transparent proxy connection, but we can't extract the original + * target address:port. */ +#define END_STREAM_REASON_CANT_FETCH_ORIG_DEST 260 +/** This is a connection on the NATD port, and the destination IP:Port was + * either ill-formed or out-of-range. */ +#define END_STREAM_REASON_INVALID_NATD_DEST 261 +/** The target address is in a private network (like 127.0.0.1 or 10.0.0.1); + * you don't want to do that over a randomly chosen exit */ +#define END_STREAM_REASON_PRIVATE_ADDR 262 + +/** Bitwise-and this value with endreason to mask out all flags. */ +#define END_STREAM_REASON_MASK 511 + +/** Bitwise-or this with the argument to control_event_stream_status + * to indicate that the reason came from an END cell. */ +#define END_STREAM_REASON_FLAG_REMOTE 512 +/** Bitwise-or this with the argument to control_event_stream_status + * to indicate that we already sent a CLOSED stream event. */ +#define END_STREAM_REASON_FLAG_ALREADY_SENT_CLOSED 1024 +/** Bitwise-or this with endreason to indicate that we already sent + * a socks reply, and no further reply needs to be sent from + * connection_mark_unattached_ap(). */ +#define END_STREAM_REASON_FLAG_ALREADY_SOCKS_REPLIED 2048 + +/** Reason for remapping an AP connection's address: we have a cached + * answer. */ +#define REMAP_STREAM_SOURCE_CACHE 1 +/** Reason for remapping an AP connection's address: the exit node told us an + * answer. */ +#define REMAP_STREAM_SOURCE_EXIT 2 + +/* 'type' values to use in RESOLVED cells. Specified in tor-spec.txt. */ +#define RESOLVED_TYPE_HOSTNAME 0 +#define RESOLVED_TYPE_IPV4 4 +#define RESOLVED_TYPE_IPV6 6 +#define RESOLVED_TYPE_ERROR_TRANSIENT 0xF0 +#define RESOLVED_TYPE_ERROR 0xF1 + +/* Negative reasons are internal: we never send them in a DESTROY or TRUNCATE + * call; they only go to the controller for tracking */ +/** Our post-timeout circuit time measurement period expired. + * We must give up now */ +#define END_CIRC_REASON_MEASUREMENT_EXPIRED -3 + +/** We couldn't build a path for this circuit. */ +#define END_CIRC_REASON_NOPATH -2 +/** Catch-all "other" reason for closing origin circuits. */ +#define END_CIRC_AT_ORIGIN -1 + +/* Reasons why we (or a remote OR) might close a circuit. See tor-spec.txt for + * documentation of these. */ +#define END_CIRC_REASON_MIN_ 0 +#define END_CIRC_REASON_NONE 0 +#define END_CIRC_REASON_TORPROTOCOL 1 +#define END_CIRC_REASON_INTERNAL 2 +#define END_CIRC_REASON_REQUESTED 3 +#define END_CIRC_REASON_HIBERNATING 4 +#define END_CIRC_REASON_RESOURCELIMIT 5 +#define END_CIRC_REASON_CONNECTFAILED 6 +#define END_CIRC_REASON_OR_IDENTITY 7 +#define END_CIRC_REASON_CHANNEL_CLOSED 8 +#define END_CIRC_REASON_FINISHED 9 +#define END_CIRC_REASON_TIMEOUT 10 +#define END_CIRC_REASON_DESTROYED 11 +#define END_CIRC_REASON_NOSUCHSERVICE 12 +#define END_CIRC_REASON_MAX_ 12 + +/** Bitwise-OR this with the argument to circuit_mark_for_close() or + * control_event_circuit_status() to indicate that the reason was + * passed through from a destroy or truncate cell. */ +#define END_CIRC_REASON_FLAG_REMOTE 512 + +/** Length of 'y' portion of 'y.onion' URL. */ +#define REND_SERVICE_ID_LEN_BASE32 16 + +/** Length of 'y.onion' including '.onion' URL. */ +#define REND_SERVICE_ADDRESS_LEN (16+1+5) + +/** Length of a binary-encoded rendezvous service ID. */ +#define REND_SERVICE_ID_LEN 10 + +/** Time period for which a v2 descriptor will be valid. */ +#define REND_TIME_PERIOD_V2_DESC_VALIDITY (24*60*60) + +/** Time period within which two sets of v2 descriptors will be uploaded in + * parallel. */ +#define REND_TIME_PERIOD_OVERLAPPING_V2_DESCS (60*60) + +/** Number of non-consecutive replicas (i.e. distributed somewhere + * in the ring) for a descriptor. */ +#define REND_NUMBER_OF_NON_CONSECUTIVE_REPLICAS 2 + +/** Number of consecutive replicas for a descriptor. */ +#define REND_NUMBER_OF_CONSECUTIVE_REPLICAS 3 + +/** Length of v2 descriptor ID (32 base32 chars = 160 bits). */ +#define REND_DESC_ID_V2_LEN_BASE32 32 + +/** Length of the base32-encoded secret ID part of versioned hidden service + * descriptors. */ +#define REND_SECRET_ID_PART_LEN_BASE32 32 + +/** Length of the base32-encoded hash of an introduction point's + * identity key. */ +#define REND_INTRO_POINT_ID_LEN_BASE32 32 + +/** Length of the descriptor cookie that is used for client authorization + * to hidden services. */ +#define REND_DESC_COOKIE_LEN 16 + +/** Length of the base64-encoded descriptor cookie that is used for + * exchanging client authorization between hidden service and client. */ +#define REND_DESC_COOKIE_LEN_BASE64 22 + +/** Length of client identifier in encrypted introduction points for hidden + * service authorization type 'basic'. */ +#define REND_BASIC_AUTH_CLIENT_ID_LEN 4 + +/** Multiple of the number of clients to which the real number of clients + * is padded with fake clients for hidden service authorization type + * 'basic'. */ +#define REND_BASIC_AUTH_CLIENT_MULTIPLE 16 + +/** Length of client entry consisting of client identifier and encrypted + * session key for hidden service authorization type 'basic'. */ +#define REND_BASIC_AUTH_CLIENT_ENTRY_LEN (REND_BASIC_AUTH_CLIENT_ID_LEN \ + + CIPHER_KEY_LEN) + +/** Maximum size of v2 hidden service descriptors. */ +#define REND_DESC_MAX_SIZE (20 * 1024) + +/** Legal characters for use in authorized client names for a hidden + * service. */ +#define REND_LEGAL_CLIENTNAME_CHARACTERS \ + "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+-_" + +/** Maximum length of authorized client names for a hidden service. */ +#define REND_CLIENTNAME_MAX_LEN 16 + +/** Length of the rendezvous cookie that is used to connect circuits at the + * rendezvous point. */ +#define REND_COOKIE_LEN DIGEST_LEN + +/** Client authorization type that a hidden service performs. */ +typedef enum rend_auth_type_t { + REND_NO_AUTH = 0, + REND_BASIC_AUTH = 1, + REND_STEALTH_AUTH = 2, +} rend_auth_type_t; + +/** Client-side configuration of authorization for a hidden service. */ +typedef struct rend_service_authorization_t { + char descriptor_cookie[REND_DESC_COOKIE_LEN]; + char onion_address[REND_SERVICE_ADDRESS_LEN+1]; + rend_auth_type_t auth_type; +} rend_service_authorization_t; + +/** Client- and server-side data that is used for hidden service connection + * establishment. Not all fields contain data depending on where this struct + * is used. */ +typedef struct rend_data_t { + /** Onion address (without the .onion part) that a client requests. */ + char onion_address[REND_SERVICE_ID_LEN_BASE32+1]; + + /** (Optional) descriptor cookie that is used by a client. */ + char descriptor_cookie[REND_DESC_COOKIE_LEN]; + + /** Authorization type for accessing a service used by a client. */ + rend_auth_type_t auth_type; + + /** Hash of the hidden service's PK used by a service. */ + char rend_pk_digest[DIGEST_LEN]; + + /** Rendezvous cookie used by both, client and service. */ + char rend_cookie[REND_COOKIE_LEN]; +} rend_data_t; + +/** Time interval for tracking replays of DH public keys received in + * INTRODUCE2 cells. Used only to avoid launching multiple + * simultaneous attempts to connect to the same rendezvous point. */ +#define REND_REPLAY_TIME_INTERVAL (5 * 60) + +/** Used to indicate which way a cell is going on a circuit. */ +typedef enum { + CELL_DIRECTION_IN=1, /**< The cell is moving towards the origin. */ + CELL_DIRECTION_OUT=2, /**< The cell is moving away from the origin. */ +} cell_direction_t; + +/** Initial value for both sides of a circuit transmission window when the + * circuit is initialized. Measured in cells. */ +#define CIRCWINDOW_START 1000 +#define CIRCWINDOW_START_MIN 100 +#define CIRCWINDOW_START_MAX 1000 +/** Amount to increment a circuit window when we get a circuit SENDME. */ +#define CIRCWINDOW_INCREMENT 100 +/** Initial value on both sides of a stream transmission window when the + * stream is initialized. Measured in cells. */ +#define STREAMWINDOW_START 500 +/** Amount to increment a stream window when we get a stream SENDME. */ +#define STREAMWINDOW_INCREMENT 50 + +/** Maximum number of queued cells on a circuit for which we are the + * midpoint before we give up and kill it. This must be >= circwindow + * to avoid killing innocent circuits, and >= circwindow*2 to give + * leaky-pipe a chance of working someday. The ORCIRC_MAX_MIDDLE_KILL_THRESH + * ratio controls the margin of error between emitting a warning and + * killing the circuit. + */ +#define ORCIRC_MAX_MIDDLE_CELLS (CIRCWINDOW_START_MAX*2) +/** Ratio of hard (circuit kill) to soft (warning) thresholds for the + * ORCIRC_MAX_MIDDLE_CELLS tests. + */ +#define ORCIRC_MAX_MIDDLE_KILL_THRESH (1.1f) + +/* Cell commands. These values are defined in tor-spec.txt. */ +#define CELL_PADDING 0 +#define CELL_CREATE 1 +#define CELL_CREATED 2 +#define CELL_RELAY 3 +#define CELL_DESTROY 4 +#define CELL_CREATE_FAST 5 +#define CELL_CREATED_FAST 6 +#define CELL_VERSIONS 7 +#define CELL_NETINFO 8 +#define CELL_RELAY_EARLY 9 +#define CELL_CREATE2 10 +#define CELL_CREATED2 11 + +#define CELL_VPADDING 128 +#define CELL_CERTS 129 +#define CELL_AUTH_CHALLENGE 130 +#define CELL_AUTHENTICATE 131 +#define CELL_AUTHORIZE 132 +#define CELL_COMMAND_MAX_ 132 + +/** How long to test reachability before complaining to the user. */ +#define TIMEOUT_UNTIL_UNREACHABILITY_COMPLAINT (20*60) + +/** Legal characters in a nickname. */ +#define LEGAL_NICKNAME_CHARACTERS \ + "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" + +/** Name to use in client TLS certificates if no nickname is given. Once + * Tor 0.1.2.x is obsolete, we can remove this. */ +#define DEFAULT_CLIENT_NICKNAME "client" + +/** Name chosen by routers that don't configure nicknames */ +#define UNNAMED_ROUTER_NICKNAME "Unnamed" + +/** Number of bytes in a SOCKS4 header. */ +#define SOCKS4_NETWORK_LEN 8 + +/* + * Relay payload: + * Relay command [1 byte] + * Recognized [2 bytes] + * Stream ID [2 bytes] + * Partial SHA-1 [4 bytes] + * Length [2 bytes] + * Relay payload [498 bytes] + */ + +/** Number of bytes in a cell, minus cell header. */ +#define CELL_PAYLOAD_SIZE 509 +/** Number of bytes in a cell transmitted over the network, in the longest + * form */ +#define CELL_MAX_NETWORK_SIZE 514 + +/** Maximum length of a header on a variable-length cell. */ +#define VAR_CELL_MAX_HEADER_SIZE 7 + +static int get_cell_network_size(int wide_circ_ids); +static INLINE int get_cell_network_size(int wide_circ_ids) +{ + return wide_circ_ids ? CELL_MAX_NETWORK_SIZE : CELL_MAX_NETWORK_SIZE - 2; +} +static int get_var_cell_header_size(int wide_circ_ids); +static INLINE int get_var_cell_header_size(int wide_circ_ids) +{ + return wide_circ_ids ? VAR_CELL_MAX_HEADER_SIZE : + VAR_CELL_MAX_HEADER_SIZE - 2; +} +static int get_circ_id_size(int wide_circ_ids); +static INLINE int get_circ_id_size(int wide_circ_ids) +{ + return wide_circ_ids ? 4 : 2; +} + +/** Number of bytes in a relay cell's header (not including general cell + * header). */ +#define RELAY_HEADER_SIZE (1+2+2+4+2) +/** Largest number of bytes that can fit in a relay cell payload. */ +#define RELAY_PAYLOAD_SIZE (CELL_PAYLOAD_SIZE-RELAY_HEADER_SIZE) + +/** Identifies a circuit on an or_connection */ +typedef uint32_t circid_t; +/** Identifies a stream on a circuit */ +typedef uint16_t streamid_t; + +/* channel_t typedef; struct channel_s is in channel.h */ + +typedef struct channel_s channel_t; + +/* channel_listener_t typedef; struct channel_listener_s is in channel.h */ + +typedef struct channel_listener_s channel_listener_t; + +/* channel states for channel_t */ + +typedef enum { + /* + * Closed state - channel is inactive + * + * Permitted transitions from: + * - CHANNEL_STATE_CLOSING + * Permitted transitions to: + * - CHANNEL_STATE_OPENING + */ + CHANNEL_STATE_CLOSED = 0, + /* + * Opening state - channel is trying to connect + * + * Permitted transitions from: + * - CHANNEL_STATE_CLOSED + * Permitted transitions to: + * - CHANNEL_STATE_CLOSING + * - CHANNEL_STATE_ERROR + * - CHANNEL_STATE_OPEN + */ + CHANNEL_STATE_OPENING, + /* + * Open state - channel is active and ready for use + * + * Permitted transitions from: + * - CHANNEL_STATE_MAINT + * - CHANNEL_STATE_OPENING + * Permitted transitions to: + * - CHANNEL_STATE_CLOSING + * - CHANNEL_STATE_ERROR + * - CHANNEL_STATE_MAINT + */ + CHANNEL_STATE_OPEN, + /* + * Maintenance state - channel is temporarily offline for subclass specific + * maintenance activities such as TLS renegotiation. + * + * Permitted transitions from: + * - CHANNEL_STATE_OPEN + * Permitted transitions to: + * - CHANNEL_STATE_CLOSING + * - CHANNEL_STATE_ERROR + * - CHANNEL_STATE_OPEN + */ + CHANNEL_STATE_MAINT, + /* + * Closing state - channel is shutting down + * + * Permitted transitions from: + * - CHANNEL_STATE_MAINT + * - CHANNEL_STATE_OPEN + * Permitted transitions to: + * - CHANNEL_STATE_CLOSED, + * - CHANNEL_STATE_ERROR + */ + CHANNEL_STATE_CLOSING, + /* + * Error state - channel has experienced a permanent error + * + * Permitted transitions from: + * - CHANNEL_STATE_CLOSING + * - CHANNEL_STATE_MAINT + * - CHANNEL_STATE_OPENING + * - CHANNEL_STATE_OPEN + * Permitted transitions to: + * - None + */ + CHANNEL_STATE_ERROR, + /* + * Placeholder for maximum state value + */ + CHANNEL_STATE_LAST +} channel_state_t; + +/* channel listener states for channel_listener_t */ + +typedef enum { + /* + * Closed state - channel listener is inactive + * + * Permitted transitions from: + * - CHANNEL_LISTENER_STATE_CLOSING + * Permitted transitions to: + * - CHANNEL_LISTENER_STATE_LISTENING + */ + CHANNEL_LISTENER_STATE_CLOSED = 0, + /* + * Listening state - channel listener is listening for incoming + * connections + * + * Permitted transitions from: + * - CHANNEL_LISTENER_STATE_CLOSED + * Permitted transitions to: + * - CHANNEL_LISTENER_STATE_CLOSING + * - CHANNEL_LISTENER_STATE_ERROR + */ + CHANNEL_LISTENER_STATE_LISTENING, + /* + * Closing state - channel listener is shutting down + * + * Permitted transitions from: + * - CHANNEL_LISTENER_STATE_LISTENING + * Permitted transitions to: + * - CHANNEL_LISTENER_STATE_CLOSED, + * - CHANNEL_LISTENER_STATE_ERROR + */ + CHANNEL_LISTENER_STATE_CLOSING, + /* + * Error state - channel listener has experienced a permanent error + * + * Permitted transitions from: + * - CHANNEL_STATE_CLOSING + * - CHANNEL_STATE_LISTENING + * Permitted transitions to: + * - None + */ + CHANNEL_LISTENER_STATE_ERROR, + /* + * Placeholder for maximum state value + */ + CHANNEL_LISTENER_STATE_LAST +} channel_listener_state_t; + +/* TLS channel stuff */ + +typedef struct channel_tls_s channel_tls_t; + +/* circuitmux_t typedef; struct circuitmux_s is in circuitmux.h */ + +typedef struct circuitmux_s circuitmux_t; + +/** Parsed onion routing cell. All communication between nodes + * is via cells. */ +typedef struct cell_t { + circid_t circ_id; /**< Circuit which received the cell. */ + uint8_t command; /**< Type of the cell: one of CELL_PADDING, CELL_CREATE, + * CELL_DESTROY, etc */ + uint8_t payload[CELL_PAYLOAD_SIZE]; /**< Cell body. */ +} cell_t; + +/** Parsed variable-length onion routing cell. */ +typedef struct var_cell_t { + /** Type of the cell: CELL_VERSIONS, etc. */ + uint8_t command; + /** Circuit thich received the cell */ + circid_t circ_id; + /** Number of bytes actually stored in payload */ + uint16_t payload_len; + /** Payload of this cell */ + uint8_t payload[FLEXIBLE_ARRAY_MEMBER]; +} var_cell_t; + +/** A parsed Extended ORPort message. */ +typedef struct ext_or_cmd_t { + uint16_t cmd; /** Command type */ + uint16_t len; /** Body length */ + char body[FLEXIBLE_ARRAY_MEMBER]; /** Message body */ +} ext_or_cmd_t; + +/** A cell as packed for writing to the network. */ +typedef struct packed_cell_t { + /** Next cell queued on this circuit. */ + TOR_SIMPLEQ_ENTRY(packed_cell_t) next; + char body[CELL_MAX_NETWORK_SIZE]; /**< Cell as packed for network. */ + uint32_t inserted_time; /**< Time (in milliseconds since epoch, with high + * bits truncated) when this cell was inserted. */ +} packed_cell_t; + +/* XXXX This next structure may be obsoleted by inserted_time in + * packed_cell_t */ + +/** Number of cells added to a circuit queue including their insertion + * time on 10 millisecond detail; used for buffer statistics. */ +typedef struct insertion_time_elem_t { + struct insertion_time_elem_t *next; /**< Next element in queue. */ + uint32_t insertion_time; /**< When were cells inserted (in 10 ms steps + * starting at 0:00 of the current day)? */ + unsigned counter; /**< How many cells were inserted? */ +} insertion_time_elem_t; + +/** Queue of insertion times. */ +typedef struct insertion_time_queue_t { + struct insertion_time_elem_t *first; /**< First element in queue. */ + struct insertion_time_elem_t *last; /**< Last element in queue. */ +} insertion_time_queue_t; + +/** Number of cells with the same command consecutively added to a circuit + * queue; used for cell statistics only if CELL_STATS events are enabled. */ +typedef struct insertion_command_elem_t { + struct insertion_command_elem_t *next; /**< Next element in queue. */ + /** Which command did these consecutively added cells have? */ + uint8_t command; + unsigned counter; /**< How many cells were inserted? */ +} insertion_command_elem_t; + +/** Queue of insertion commands. */ +typedef struct insertion_command_queue_t { + struct insertion_command_elem_t *first; /**< First element in queue. */ + struct insertion_command_elem_t *last; /**< Last element in queue. */ +} insertion_command_queue_t; + +/** A queue of cells on a circuit, waiting to be added to the + * or_connection_t's outbuf. */ +typedef struct cell_queue_t { + /** Linked list of packed_cell_t*/ + TOR_SIMPLEQ_HEAD(cell_simpleq, packed_cell_t) head; + int n; /**< The number of cells in the queue. */ + insertion_time_queue_t *insertion_times; /**< Insertion times of cells. */ + /** Commands of inserted cells. */ + insertion_command_queue_t *insertion_commands; +} cell_queue_t; + +/** Beginning of a RELAY cell payload. */ +typedef struct { + uint8_t command; /**< The end-to-end relay command. */ + uint16_t recognized; /**< Used to tell whether cell is for us. */ + streamid_t stream_id; /**< Which stream is this cell associated with? */ + char integrity[4]; /**< Used to tell whether cell is corrupted. */ + uint16_t length; /**< How long is the payload body? */ +} relay_header_t; + +typedef struct buf_t buf_t; +typedef struct socks_request_t socks_request_t; +#ifdef USE_BUFFEREVENTS +#define generic_buffer_t struct evbuffer +#else +#define generic_buffer_t buf_t +#endif + +/* Values for connection_t.magic: used to make sure that downcasts (casts from +* connection_t to foo_connection_t) are safe. */ +#define BASE_CONNECTION_MAGIC 0x7C3C304Eu +#define OR_CONNECTION_MAGIC 0x7D31FF03u +#define EDGE_CONNECTION_MAGIC 0xF0374013u +#define ENTRY_CONNECTION_MAGIC 0xbb4a5703 +#define DIR_CONNECTION_MAGIC 0x9988ffeeu +#define CONTROL_CONNECTION_MAGIC 0x8abc765du +#define LISTENER_CONNECTION_MAGIC 0x1a1ac741u + +/** Description of a connection to another host or process, and associated + * data. + * + * A connection is named based on what it's connected to -- an "OR + * connection" has a Tor node on the other end, an "exit + * connection" has a website or other server on the other end, and an + * "AP connection" has an application proxy (and thus a user) on the + * other end. + * + * Every connection has a type and a state. Connections never change + * their type, but can go through many state changes in their lifetime. + * + * Every connection has two associated input and output buffers. + * Listeners don't use them. For non-listener connections, incoming + * data is appended to conn->inbuf, and outgoing data is taken from + * conn->outbuf. Connections differ primarily in the functions called + * to fill and drain these buffers. + */ +typedef struct connection_t { + uint32_t magic; /**< For memory debugging: must equal one of + * *_CONNECTION_MAGIC. */ + + uint8_t state; /**< Current state of this connection. */ + unsigned int type:5; /**< What kind of connection is this? */ + unsigned int purpose:5; /**< Only used for DIR and EXIT types currently. */ + + /* The next fields are all one-bit booleans. Some are only applicable to + * connection subtypes, but we hold them here anyway, to save space. + */ + unsigned int read_blocked_on_bw:1; /**< Boolean: should we start reading + * again once the bandwidth throttler allows it? */ + unsigned int write_blocked_on_bw:1; /**< Boolean: should we start writing + * again once the bandwidth throttler allows + * writes? */ + unsigned int hold_open_until_flushed:1; /**< Despite this connection's being + * marked for close, do we flush it + * before closing it? */ + unsigned int inbuf_reached_eof:1; /**< Boolean: did read() return 0 on this + * conn? */ + /** Set to 1 when we're inside connection_flushed_some to keep us from + * calling connection_handle_write() recursively. */ + unsigned int in_flushed_some:1; + /** True if connection_handle_write is currently running on this connection. + */ + unsigned int in_connection_handle_write:1; + + /* For linked connections: + */ + unsigned int linked:1; /**< True if there is, or has been, a linked_conn. */ + /** True iff we'd like to be notified about read events from the + * linked conn. */ + unsigned int reading_from_linked_conn:1; + /** True iff we're willing to write to the linked conn. */ + unsigned int writing_to_linked_conn:1; + /** True iff we're currently able to read on the linked conn, and our + * read_event should be made active with libevent. */ + unsigned int active_on_link:1; + /** True iff we've called connection_close_immediate() on this linked + * connection. */ + unsigned int linked_conn_is_closed:1; + + /** CONNECT/SOCKS proxy client handshake state (for outgoing connections). */ + unsigned int proxy_state:4; + + /** Our socket; set to TOR_INVALID_SOCKET if this connection is closed, + * or has no socket. */ + tor_socket_t s; + int conn_array_index; /**< Index into the global connection array. */ + + struct event *read_event; /**< Libevent event structure. */ + struct event *write_event; /**< Libevent event structure. */ + buf_t *inbuf; /**< Buffer holding data read over this connection. */ + buf_t *outbuf; /**< Buffer holding data to write over this connection. */ + size_t outbuf_flushlen; /**< How much data should we try to flush from the + * outbuf? */ + time_t timestamp_lastread; /**< When was the last time libevent said we could + * read? */ + time_t timestamp_lastwritten; /**< When was the last time libevent said we + * could write? */ + +#ifdef USE_BUFFEREVENTS + struct bufferevent *bufev; /**< A Libevent buffered IO structure. */ +#endif + + time_t timestamp_created; /**< When was this connection_t created? */ + + /* XXXX_IP6 make this IPv6-capable */ + int socket_family; /**< Address family of this connection's socket. Usually + * AF_INET, but it can also be AF_UNIX, or in the future + * AF_INET6 */ + tor_addr_t addr; /**< IP of the other side of the connection; used to + * identify routers, along with port. */ + uint16_t port; /**< If non-zero, port on the other end + * of the connection. */ + uint16_t marked_for_close; /**< Should we close this conn on the next + * iteration of the main loop? (If true, holds + * the line number where this connection was + * marked.) */ + const char *marked_for_close_file; /**< For debugging: in which file were + * we marked for close? */ + char *address; /**< FQDN (or IP) of the guy on the other end. + * strdup into this, because free_connection() frees it. */ + /** Another connection that's connected to this one in lieu of a socket. */ + struct connection_t *linked_conn; + + /** Unique identifier for this connection on this Tor instance. */ + uint64_t global_identifier; + + /** Bytes read since last call to control_event_conn_bandwidth_used(). + * Only used if we're configured to emit CONN_BW events. */ + uint32_t n_read_conn_bw; + + /** Bytes written since last call to control_event_conn_bandwidth_used(). + * Only used if we're configured to emit CONN_BW events. */ + uint32_t n_written_conn_bw; +} connection_t; + +/** Subtype of connection_t; used for a listener socket. */ +typedef struct listener_connection_t { + connection_t base_; + + /** If the connection is a CONN_TYPE_AP_DNS_LISTENER, this field points + * to the evdns_server_port it uses to listen to and answer connections. */ + struct evdns_server_port *dns_server_port; + + /** @name Isolation parameters + * + * For an AP listener, these fields describe how to isolate streams that + * arrive on the listener. + * + * @{ + */ + /** The session group for this listener. */ + int session_group; + /** One or more ISO_ flags to describe how to isolate streams. */ + uint8_t isolation_flags; + /**@}*/ + /** For SOCKS connections only: If this is set, we will choose "no + * authentication" instead of "username/password" authentication if both + * are offered. Used as input to parse_socks. */ + unsigned int socks_prefer_no_auth : 1; + + /** For a SOCKS listeners, these fields describe whether we should + * allow IPv4 and IPv6 addresses from our exit nodes, respectively. + * + * @{ + */ + unsigned int socks_ipv4_traffic : 1; + unsigned int socks_ipv6_traffic : 1; + /** @} */ + /** For a socks listener: should we tell the exit that we prefer IPv6 + * addresses? */ + unsigned int socks_prefer_ipv6 : 1; + + /** For a socks listener: should we cache IPv4/IPv6 DNS information that + * exit nodes tell us? + * + * @{ */ + unsigned int cache_ipv4_answers : 1; + unsigned int cache_ipv6_answers : 1; + /** @} */ + /** For a socks listeners: if we find an answer in our client-side DNS cache, + * should we use it? + * + * @{ */ + unsigned int use_cached_ipv4_answers : 1; + unsigned int use_cached_ipv6_answers : 1; + /** @} */ + /** For socks listeners: When we can automap an address to IPv4 or IPv6, + * do we prefer IPv6? */ + unsigned int prefer_ipv6_virtaddr : 1; + +} listener_connection_t; + +/** Minimum length of the random part of an AUTH_CHALLENGE cell. */ +#define OR_AUTH_CHALLENGE_LEN 32 + +/** + * @name Certificate types for CERTS cells. + * + * These values are defined by the protocol, and affect how an X509 + * certificate in a CERTS cell is interpreted and used. + * + * @{ */ +/** A certificate that authenticates a TLS link key. The subject key + * must match the key used in the TLS handshake; it must be signed by + * the identity key. */ +#define OR_CERT_TYPE_TLS_LINK 1 +/** A self-signed identity certificate. The subject key must be a + * 1024-bit RSA key. */ +#define OR_CERT_TYPE_ID_1024 2 +/** A certificate that authenticates a key used in an AUTHENTICATE cell + * in the v3 handshake. The subject key must be a 1024-bit RSA key; it + * must be signed by the identity key */ +#define OR_CERT_TYPE_AUTH_1024 3 +/**@}*/ + +/** The one currently supported type of AUTHENTICATE cell. It contains + * a bunch of structures signed with an RSA1024 key. The signed + * structures include a HMAC using negotiated TLS secrets, and a digest + * of all cells sent or received before the AUTHENTICATE cell (including + * the random server-generated AUTH_CHALLENGE cell). + */ +#define AUTHTYPE_RSA_SHA256_TLSSECRET 1 + +/** The length of the part of the AUTHENTICATE cell body that the client and + * server can generate independently (when using RSA_SHA256_TLSSECRET). It + * contains everything except the client's timestamp, the client's randomly + * generated nonce, and the signature. */ +#define V3_AUTH_FIXED_PART_LEN (8+(32*6)) +/** The length of the part of the AUTHENTICATE cell body that the client + * signs. */ +#define V3_AUTH_BODY_LEN (V3_AUTH_FIXED_PART_LEN + 8 + 16) + +/** Stores flags and information related to the portion of a v2/v3 Tor OR + * connection handshake that happens after the TLS handshake is finished. + */ +typedef struct or_handshake_state_t { + /** When was the VERSIONS cell sent on this connection? Used to get + * an estimate of the skew in the returning NETINFO reply. */ + time_t sent_versions_at; + /** True iff we originated this connection */ + unsigned int started_here : 1; + /** True iff we have received and processed a VERSIONS cell. */ + unsigned int received_versions : 1; + /** True iff we have received and processed an AUTH_CHALLENGE cell */ + unsigned int received_auth_challenge : 1; + /** True iff we have received and processed a CERTS cell. */ + unsigned int received_certs_cell : 1; + /** True iff we have received and processed an AUTHENTICATE cell */ + unsigned int received_authenticate : 1; + + /* True iff we've received valid authentication to some identity. */ + unsigned int authenticated : 1; + + /* True iff we have sent a netinfo cell */ + unsigned int sent_netinfo : 1; + + /** True iff we should feed outgoing cells into digest_sent and + * digest_received respectively. + * + * From the server's side of the v3 handshake, we want to capture everything + * from the VERSIONS cell through and including the AUTH_CHALLENGE cell. + * From the client's, we want to capture everything from the VERSIONS cell + * through but *not* including the AUTHENTICATE cell. + * + * @{ */ + unsigned int digest_sent_data : 1; + unsigned int digest_received_data : 1; + /**@}*/ + + /** Identity digest that we have received and authenticated for our peer + * on this connection. */ + uint8_t authenticated_peer_id[DIGEST_LEN]; + + /** Digests of the cells that we have sent or received as part of a V3 + * handshake. Used for making and checking AUTHENTICATE cells. + * + * @{ + */ + crypto_digest_t *digest_sent; + crypto_digest_t *digest_received; + /** @} */ + + /** Certificates that a connection initiator sent us in a CERTS cell; we're + * holding on to them until we get an AUTHENTICATE cell. + * + * @{ + */ + /** The cert for the key that's supposed to sign the AUTHENTICATE cell */ + tor_cert_t *auth_cert; + /** A self-signed identity certificate */ + tor_cert_t *id_cert; + /**@}*/ +} or_handshake_state_t; + +/** Length of Extended ORPort connection identifier. */ +#define EXT_OR_CONN_ID_LEN DIGEST_LEN /* 20 */ + +/** Subtype of connection_t for an "OR connection" -- that is, one that speaks + * cells over TLS. */ +typedef struct or_connection_t { + connection_t base_; + + /** Hash of the public RSA key for the other side's identity key, or zeroes + * if the other side hasn't shown us a valid identity key. */ + char identity_digest[DIGEST_LEN]; + + /** Extended ORPort connection identifier. */ + char *ext_or_conn_id; + /** This is the ClientHash value we expect to receive from the + * client during the Extended ORPort authentication protocol. We + * compute it upon receiving the ClientNoce from the client, and we + * compare it with the acual ClientHash value sent by the + * client. */ + char *ext_or_auth_correct_client_hash; + /** String carrying the name of the pluggable transport + * (e.g. "obfs2") that is obfuscating this connection. If no + * pluggable transports are used, it's NULL. */ + char *ext_or_transport; + + char *nickname; /**< Nickname of OR on other side (if any). */ + + tor_tls_t *tls; /**< TLS connection state. */ + int tls_error; /**< Last tor_tls error code. */ + /** When we last used this conn for any client traffic. If not + * recent, we can rate limit it further. */ + + /* Channel using this connection */ + channel_tls_t *chan; + + tor_addr_t real_addr; /**< The actual address that this connection came from + * or went to. The addr field is prone to + * getting overridden by the address from the router + * descriptor matching identity_digest. */ + + /** Should this connection be used for extending circuits to the server + * matching the identity_digest field? Set to true if we're pretty + * sure we aren't getting MITMed, either because we're connected to an + * address listed in a server descriptor, or because an authenticated + * NETINFO cell listed the address we're connected to as recognized. */ + unsigned int is_canonical:1; + + /** True iff we have decided that the other end of this connection + * is a client. Connections with this flag set should never be used + * to satisfy an EXTEND request. */ + unsigned int is_connection_with_client:1; + /** True iff this is an outgoing connection. */ + unsigned int is_outgoing:1; + unsigned int proxy_type:2; /**< One of PROXY_NONE...PROXY_SOCKS5 */ + unsigned int wide_circ_ids:1; + uint16_t link_proto; /**< What protocol version are we using? 0 for + * "none negotiated yet." */ + + or_handshake_state_t *handshake_state; /**< If we are setting this connection + * up, state information to do so. */ + + time_t timestamp_lastempty; /**< When was the outbuf last completely empty?*/ + time_t timestamp_last_added_nonpadding; /** When did we last add a + * non-padding cell to the outbuf? */ + + /* bandwidth* and *_bucket only used by ORs in OPEN state: */ + int bandwidthrate; /**< Bytes/s added to the bucket. (OPEN ORs only.) */ + int bandwidthburst; /**< Max bucket size for this conn. (OPEN ORs only.) */ +#ifndef USE_BUFFEREVENTS + int read_bucket; /**< When this hits 0, stop receiving. Every second we + * add 'bandwidthrate' to this, capping it at + * bandwidthburst. (OPEN ORs only) */ + int write_bucket; /**< When this hits 0, stop writing. Like read_bucket. */ +#else + /** A rate-limiting configuration object to determine how this connection + * set its read- and write- limits. */ + /* XXXX we could share this among all connections. */ + struct ev_token_bucket_cfg *bucket_cfg; +#endif + + struct or_connection_t *next_with_same_id; /**< Next connection with same + * identity digest as this one. */ + /** Last emptied read token bucket in msec since midnight; only used if + * TB_EMPTY events are enabled. */ + uint32_t read_emptied_time; + /** Last emptied write token bucket in msec since midnight; only used if + * TB_EMPTY events are enabled. */ + uint32_t write_emptied_time; +} or_connection_t; + +/** Subtype of connection_t for an "edge connection" -- that is, an entry (ap) + * connection, or an exit. */ +typedef struct edge_connection_t { + connection_t base_; + + struct edge_connection_t *next_stream; /**< Points to the next stream at this + * edge, if any */ + int package_window; /**< How many more relay cells can I send into the + * circuit? */ + int deliver_window; /**< How many more relay cells can end at me? */ + + struct circuit_t *on_circuit; /**< The circuit (if any) that this edge + * connection is using. */ + + /** A pointer to which node in the circ this conn exits at. Set for AP + * connections and for hidden service exit connections. */ + struct crypt_path_t *cpath_layer; + /** What rendezvous service are we querying for (if an AP) or providing (if + * an exit)? */ + rend_data_t *rend_data; + + uint32_t address_ttl; /**< TTL for address-to-addr mapping on exit + * connection. Exit connections only. */ + uint32_t begincell_flags; /** Flags sent or received in the BEGIN cell + * for this connection */ + + streamid_t stream_id; /**< The stream ID used for this edge connection on its + * circuit */ + + /** The reason why this connection is closing; passed to the controller. */ + uint16_t end_reason; + + /** Bytes read since last call to control_event_stream_bandwidth_used() */ + uint32_t n_read; + + /** Bytes written since last call to control_event_stream_bandwidth_used() */ + uint32_t n_written; + + /** True iff this connection is for a DNS request only. */ + unsigned int is_dns_request:1; + /** True iff this connection is for a PTR DNS request. (exit only) */ + unsigned int is_reverse_dns_lookup:1; + + unsigned int edge_has_sent_end:1; /**< For debugging; only used on edge + * connections. Set once we've set the stream end, + * and check in connection_about_to_close_connection(). + */ + /** True iff we've blocked reading until the circuit has fewer queued + * cells. */ + unsigned int edge_blocked_on_circ:1; + + /** Unique ID for directory requests; this used to be in connection_t, but + * that's going away and being used on channels instead. We still tag + * edge connections with dirreq_id from circuits, so it's copied here. */ + uint64_t dirreq_id; +} edge_connection_t; + +/** Subtype of edge_connection_t for an "entry connection" -- that is, a SOCKS + * connection, a DNS request, a TransPort connection or a NATD connection */ +typedef struct entry_connection_t { + edge_connection_t edge_; + + /** Nickname of planned exit node -- used with .exit support. */ + char *chosen_exit_name; + + socks_request_t *socks_request; /**< SOCKS structure describing request (AP + * only.) */ + + /* === Isolation related, AP only. === */ + /** AP only: based on which factors do we isolate this stream? */ + uint8_t isolation_flags; + /** AP only: what session group is this stream in? */ + int session_group; + /** AP only: The newnym epoch in which we created this connection. */ + unsigned nym_epoch; + /** AP only: The original requested address before we rewrote it. */ + char *original_dest_address; + /* Other fields to isolate on already exist. The ClientAddr is addr. The + ClientProtocol is a combination of type and socks_request-> + socks_version. SocksAuth is socks_request->username/password. + DestAddr is in socks_request->address. */ + + /** Number of times we've reassigned this application connection to + * a new circuit. We keep track because the timeout is longer if we've + * already retried several times. */ + uint8_t num_socks_retries; + + /** For AP connections only: buffer for data that we have sent + * optimistically, which we might need to re-send if we have to + * retry this connection. */ + generic_buffer_t *pending_optimistic_data; + /* For AP connections only: buffer for data that we previously sent + * optimistically which we are currently re-sending as we retry this + * connection. */ + generic_buffer_t *sending_optimistic_data; + + /** If this is a DNSPort connection, this field holds the pending DNS + * request that we're going to try to answer. */ + struct evdns_server_request *dns_server_request; + +#define NUM_CIRCUITS_LAUNCHED_THRESHOLD 10 + /** Number of times we've launched a circuit to handle this stream. If + * it gets too high, that could indicate an inconsistency between our + * "launch a circuit to handle this stream" logic and our "attach our + * stream to one of the available circuits" logic. */ + unsigned int num_circuits_launched:4; + + /** True iff this stream must attach to a one-hop circuit (e.g. for + * begin_dir). */ + unsigned int want_onehop:1; + /** True iff this stream should use a BEGIN_DIR relay command to establish + * itself rather than BEGIN (either via onehop or via a whole circuit). */ + unsigned int use_begindir:1; + + /** For AP connections only. If 1, and we fail to reach the chosen exit, + * stop requiring it. */ + unsigned int chosen_exit_optional:1; + /** For AP connections only. If non-zero, this exit node was picked as + * a result of the TrackHostExit, and the value decrements every time + * we fail to complete a circuit to our chosen exit -- if it reaches + * zero, abandon the associated mapaddress. */ + unsigned int chosen_exit_retries:3; + + /** True iff this is an AP connection that came from a transparent or + * NATd connection */ + unsigned int is_transparent_ap:1; + + /** For AP connections only: Set if this connection's target exit node + * allows optimistic data (that is, data sent on this stream before + * the exit has sent a CONNECTED cell) and we have chosen to use it. + */ + unsigned int may_use_optimistic_data : 1; + + /** Should we permit IPv4 and IPv6 traffic to use this connection? + * + * @{ */ + unsigned int ipv4_traffic_ok : 1; + unsigned int ipv6_traffic_ok : 1; + /** @} */ + /** Should we say we prefer IPv6 traffic? */ + unsigned int prefer_ipv6_traffic : 1; + + /** For a socks listener: should we cache IPv4/IPv6 DNS information that + * exit nodes tell us? + * + * @{ */ + unsigned int cache_ipv4_answers : 1; + unsigned int cache_ipv6_answers : 1; + /** @} */ + /** For a socks listeners: if we find an answer in our client-side DNS cache, + * should we use it? + * + * @{ */ + unsigned int use_cached_ipv4_answers : 1; + unsigned int use_cached_ipv6_answers : 1; + /** @} */ + /** For socks listeners: When we can automap an address to IPv4 or IPv6, + * do we prefer IPv6? */ + unsigned int prefer_ipv6_virtaddr : 1; + +} entry_connection_t; + +typedef enum { + DIR_SPOOL_NONE=0, DIR_SPOOL_SERVER_BY_DIGEST, DIR_SPOOL_SERVER_BY_FP, + DIR_SPOOL_EXTRA_BY_DIGEST, DIR_SPOOL_EXTRA_BY_FP, + DIR_SPOOL_CACHED_DIR, DIR_SPOOL_NETWORKSTATUS, + DIR_SPOOL_MICRODESC, /* NOTE: if we add another entry, add another bit. */ +} dir_spool_source_t; + +/** Subtype of connection_t for an "directory connection" -- that is, an HTTP + * connection to retrieve or serve directory material. */ +typedef struct dir_connection_t { + connection_t base_; + + /** Which 'resource' did we ask the directory for? This is typically the part + * of the URL string that defines, relative to the directory conn purpose, + * what thing we want. For example, in router descriptor downloads by + * descriptor digest, it contains "d/", then one ore more +-separated + * fingerprints. + **/ + char *requested_resource; + unsigned int dirconn_direct:1; /**< Is this dirconn direct, or via Tor? */ + + /* Used only for server sides of some dir connections, to implement + * "spooling" of directory material to the outbuf. Otherwise, we'd have + * to append everything to the outbuf in one enormous chunk. */ + /** What exactly are we spooling right now? */ + ENUM_BF(dir_spool_source_t) dir_spool_src : 3; + + /** If we're fetching descriptors, what router purpose shall we assign + * to them? */ + uint8_t router_purpose; + /** List of fingerprints for networkstatuses or descriptors to be spooled. */ + smartlist_t *fingerprint_stack; + /** A cached_dir_t object that we're currently spooling out */ + struct cached_dir_t *cached_dir; + /** The current offset into cached_dir. */ + off_t cached_dir_offset; + /** The zlib object doing on-the-fly compression for spooled data. */ + tor_zlib_state_t *zlib_state; + + /** What rendezvous service are we querying for? */ + rend_data_t *rend_data; + + char identity_digest[DIGEST_LEN]; /**< Hash of the public RSA key for + * the directory server's signing key. */ + + /** Unique ID for directory requests; this used to be in connection_t, but + * that's going away and being used on channels instead. The dirserver still + * needs this for the incoming side, so it's moved here. */ + uint64_t dirreq_id; +} dir_connection_t; + +/** Subtype of connection_t for an connection to a controller. */ +typedef struct control_connection_t { + connection_t base_; + + uint32_t event_mask; /**< Bitfield: which events does this controller + * care about? */ + + /** True if we have sent a protocolinfo reply on this connection. */ + unsigned int have_sent_protocolinfo:1; + /** True if we have received a takeownership command on this + * connection. */ + unsigned int is_owning_control_connection:1; + + /** If we have sent an AUTHCHALLENGE reply on this connection and + * have not received a successful AUTHENTICATE command, points to + * the value which the client must send to authenticate itself; + * otherwise, NULL. */ + char *safecookie_client_hash; + + /** Amount of space allocated in incoming_cmd. */ + uint32_t incoming_cmd_len; + /** Number of bytes currently stored in incoming_cmd. */ + uint32_t incoming_cmd_cur_len; + /** A control command that we're reading from the inbuf, but which has not + * yet arrived completely. */ + char *incoming_cmd; +} control_connection_t; + +/** Cast a connection_t subtype pointer to a connection_t **/ +#define TO_CONN(c) (&(((c)->base_))) +/** Helper macro: Given a pointer to to.base_, of type from*, return &to. */ +#define DOWNCAST(to, ptr) ((to*)SUBTYPE_P(ptr, to, base_)) + +/** Cast a entry_connection_t subtype pointer to a edge_connection_t **/ +#define ENTRY_TO_EDGE_CONN(c) (&(((c))->edge_)) +/** Cast a entry_connection_t subtype pointer to a connection_t **/ +#define ENTRY_TO_CONN(c) (TO_CONN(ENTRY_TO_EDGE_CONN(c))) + +/** Convert a connection_t* to an or_connection_t*; assert if the cast is + * invalid. */ +static or_connection_t *TO_OR_CONN(connection_t *); +/** Convert a connection_t* to a dir_connection_t*; assert if the cast is + * invalid. */ +static dir_connection_t *TO_DIR_CONN(connection_t *); +/** Convert a connection_t* to an edge_connection_t*; assert if the cast is + * invalid. */ +static edge_connection_t *TO_EDGE_CONN(connection_t *); +/** Convert a connection_t* to an entry_connection_t*; assert if the cast is + * invalid. */ +static entry_connection_t *TO_ENTRY_CONN(connection_t *); +/** Convert a edge_connection_t* to an entry_connection_t*; assert if the cast + * is invalid. */ +static entry_connection_t *EDGE_TO_ENTRY_CONN(edge_connection_t *); +/** Convert a connection_t* to an control_connection_t*; assert if the cast is + * invalid. */ +static control_connection_t *TO_CONTROL_CONN(connection_t *); +/** Convert a connection_t* to an listener_connection_t*; assert if the cast is + * invalid. */ +static listener_connection_t *TO_LISTENER_CONN(connection_t *); + +static INLINE or_connection_t *TO_OR_CONN(connection_t *c) +{ + tor_assert(c->magic == OR_CONNECTION_MAGIC); + return DOWNCAST(or_connection_t, c); +} +static INLINE dir_connection_t *TO_DIR_CONN(connection_t *c) +{ + tor_assert(c->magic == DIR_CONNECTION_MAGIC); + return DOWNCAST(dir_connection_t, c); +} +static INLINE edge_connection_t *TO_EDGE_CONN(connection_t *c) +{ + tor_assert(c->magic == EDGE_CONNECTION_MAGIC || + c->magic == ENTRY_CONNECTION_MAGIC); + return DOWNCAST(edge_connection_t, c); +} +static INLINE entry_connection_t *TO_ENTRY_CONN(connection_t *c) +{ + tor_assert(c->magic == ENTRY_CONNECTION_MAGIC); + return (entry_connection_t*) SUBTYPE_P(c, entry_connection_t, edge_.base_); +} +static INLINE entry_connection_t *EDGE_TO_ENTRY_CONN(edge_connection_t *c) +{ + tor_assert(c->base_.magic == ENTRY_CONNECTION_MAGIC); + return (entry_connection_t*) SUBTYPE_P(c, entry_connection_t, edge_); +} +static INLINE control_connection_t *TO_CONTROL_CONN(connection_t *c) +{ + tor_assert(c->magic == CONTROL_CONNECTION_MAGIC); + return DOWNCAST(control_connection_t, c); +} +static INLINE listener_connection_t *TO_LISTENER_CONN(connection_t *c) +{ + tor_assert(c->magic == LISTENER_CONNECTION_MAGIC); + return DOWNCAST(listener_connection_t, c); +} + +/* Conditional macros to help write code that works whether bufferevents are + disabled or not. + + We can't just write: + if (conn->bufev) { + do bufferevent stuff; + } else { + do other stuff; + } + because the bufferevent stuff won't even compile unless we have a fairly + new version of Libevent. Instead, we say: + IF_HAS_BUFFEREVENT(conn, { do_bufferevent_stuff } ); + or: + IF_HAS_BUFFEREVENT(conn, { + do bufferevent stuff; + }) ELSE_IF_NO_BUFFEREVENT { + do non-bufferevent stuff; + } + If we're compiling with bufferevent support, then the macros expand more or + less to: + if (conn->bufev) { + do_bufferevent_stuff; + } else { + do non-bufferevent stuff; + } + and if we aren't using bufferevents, they expand more or less to: + { do non-bufferevent stuff; } +*/ +#ifdef USE_BUFFEREVENTS +#define HAS_BUFFEREVENT(c) (((c)->bufev) != NULL) +#define IF_HAS_BUFFEREVENT(c, stmt) \ + if ((c)->bufev) do { \ + stmt ; \ + } while (0) +#define ELSE_IF_NO_BUFFEREVENT ; else +#define IF_HAS_NO_BUFFEREVENT(c) \ + if (NULL == (c)->bufev) +#else +#define HAS_BUFFEREVENT(c) (0) +#define IF_HAS_BUFFEREVENT(c, stmt) (void)0 +#define ELSE_IF_NO_BUFFEREVENT ; +#define IF_HAS_NO_BUFFEREVENT(c) \ + if (1) +#endif + +/** What action type does an address policy indicate: accept or reject? */ +typedef enum { + ADDR_POLICY_ACCEPT=1, + ADDR_POLICY_REJECT=2, +} addr_policy_action_t; + +/** A reference-counted address policy rule. */ +typedef struct addr_policy_t { + int refcnt; /**< Reference count */ + /** What to do when the policy matches.*/ + ENUM_BF(addr_policy_action_t) policy_type:2; + unsigned int is_private:1; /**< True iff this is the pseudo-address, + * "private". */ + unsigned int is_canonical:1; /**< True iff this policy is the canonical + * copy (stored in a hash table to avoid + * duplication of common policies) */ + maskbits_t maskbits; /**< Accept/reject all addresses a such that the + * first maskbits bits of a match + * addr. */ + /** Base address to accept or reject. + * + * Note that wildcards are treated + * differntly depending on address family. An AF_UNSPEC address means + * "All addresses, IPv4 or IPv6." An AF_INET address with maskbits==0 means + * "All IPv4 addresses" and an AF_INET6 address with maskbits == 0 means + * "All IPv6 addresses". + **/ + tor_addr_t addr; + uint16_t prt_min; /**< Lowest port number to accept/reject. */ + uint16_t prt_max; /**< Highest port number to accept/reject. */ +} addr_policy_t; + +/** A cached_dir_t represents a cacheable directory object, along with its + * compressed form. */ +typedef struct cached_dir_t { + char *dir; /**< Contents of this object, NUL-terminated. */ + char *dir_z; /**< Compressed contents of this object. */ + size_t dir_len; /**< Length of dir (not counting its NUL). */ + size_t dir_z_len; /**< Length of dir_z. */ + time_t published; /**< When was this object published. */ + digests_t digests; /**< Digests of this object (networkstatus only) */ + int refcnt; /**< Reference count for this cached_dir_t. */ +} cached_dir_t; + +/** Enum used to remember where a signed_descriptor_t is stored and how to + * manage the memory for signed_descriptor_body. */ +typedef enum { + /** The descriptor isn't stored on disk at all: the copy in memory is + * canonical; the saved_offset field is meaningless. */ + SAVED_NOWHERE=0, + /** The descriptor is stored in the cached_routers file: the + * signed_descriptor_body is meaningless; the signed_descriptor_len and + * saved_offset are used to index into the mmaped cache file. */ + SAVED_IN_CACHE, + /** The descriptor is stored in the cached_routers.new file: the + * signed_descriptor_body and saved_offset fields are both set. */ + /* FFFF (We could also mmap the file and grow the mmap as needed, or + * lazy-load the descriptor text by using seek and read. We don't, for + * now.) + */ + SAVED_IN_JOURNAL +} saved_location_t; + +/** Enumeration: what kind of download schedule are we using for a given + * object? */ +typedef enum { + DL_SCHED_GENERIC = 0, + DL_SCHED_CONSENSUS = 1, + DL_SCHED_BRIDGE = 2, +} download_schedule_t; + +/** Information about our plans for retrying downloads for a downloadable + * object. */ +typedef struct download_status_t { + time_t next_attempt_at; /**< When should we try downloading this descriptor + * again? */ + uint8_t n_download_failures; /**< Number of failures trying to download the + * most recent descriptor. */ + ENUM_BF(download_schedule_t) schedule : 8; +} download_status_t; + +/** If n_download_failures is this high, the download can never happen. */ +#define IMPOSSIBLE_TO_DOWNLOAD 255 + +/** The max size we expect router descriptor annotations we create to + * be. We'll accept larger ones if we see them on disk, but we won't + * create any that are larger than this. */ +#define ROUTER_ANNOTATION_BUF_LEN 256 + +/** Information need to cache an onion router's descriptor. */ +typedef struct signed_descriptor_t { + /** Pointer to the raw server descriptor, preceded by annotations. Not + * necessarily NUL-terminated. If saved_location is SAVED_IN_CACHE, this + * pointer is null. */ + char *signed_descriptor_body; + /** Length of the annotations preceding the server descriptor. */ + size_t annotations_len; + /** Length of the server descriptor. */ + size_t signed_descriptor_len; + /** Digest of the server descriptor, computed as specified in + * dir-spec.txt. */ + char signed_descriptor_digest[DIGEST_LEN]; + /** Identity digest of the router. */ + char identity_digest[DIGEST_LEN]; + /** Declared publication time of the descriptor. */ + time_t published_on; + /** For routerdescs only: digest of the corresponding extrainfo. */ + char extra_info_digest[DIGEST_LEN]; + /** For routerdescs only: Status of downloading the corresponding + * extrainfo. */ + download_status_t ei_dl_status; + /** Where is the descriptor saved? */ + saved_location_t saved_location; + /** If saved_location is SAVED_IN_CACHE or SAVED_IN_JOURNAL, the offset of + * this descriptor in the corresponding file. */ + off_t saved_offset; + /** What position is this descriptor within routerlist->routers or + * routerlist->old_routers? -1 for none. */ + int routerlist_index; + /** The valid-until time of the most recent consensus that listed this + * descriptor. 0 for "never listed in a consensus, so far as we know." */ + time_t last_listed_as_valid_until; + /* If true, we do not ever try to save this object in the cache. */ + unsigned int do_not_cache : 1; + /* If true, this item is meant to represent an extrainfo. */ + unsigned int is_extrainfo : 1; + /* If true, we got an extrainfo for this item, and the digest was right, + * but it was incompatible. */ + unsigned int extrainfo_is_bogus : 1; + /* If true, we are willing to transmit this item unencrypted. */ + unsigned int send_unencrypted : 1; +} signed_descriptor_t; + +/** A signed integer representing a country code. */ +typedef int16_t country_t; + +/** Information about another onion router in the network. */ +typedef struct { + signed_descriptor_t cache_info; + char *address; /**< Location of OR: either a hostname or an IP address. */ + char *nickname; /**< Human-readable OR name. */ + + uint32_t addr; /**< IPv4 address of OR, in host order. */ + uint16_t or_port; /**< Port for TLS connections. */ + uint16_t dir_port; /**< Port for HTTP directory connections. */ + + /** A router's IPv6 address, if it has one. */ + /* XXXXX187 Actually these should probably be part of a list of addresses, + * not just a special case. Use abstractions to access these; don't do it + * directly. */ + tor_addr_t ipv6_addr; + uint16_t ipv6_orport; + + crypto_pk_t *onion_pkey; /**< Public RSA key for onions. */ + crypto_pk_t *identity_pkey; /**< Public RSA key for signing. */ + /** Public curve25519 key for onions */ + curve25519_public_key_t *onion_curve25519_pkey; + + char *platform; /**< What software/operating system is this OR using? */ + + /* link info */ + uint32_t bandwidthrate; /**< How many bytes does this OR add to its token + * bucket per second? */ + uint32_t bandwidthburst; /**< How large is this OR's token bucket? */ + /** How many bytes/s is this router known to handle? */ + uint32_t bandwidthcapacity; + smartlist_t *exit_policy; /**< What streams will this OR permit + * to exit on IPv4? NULL for 'reject *:*'. */ + /** What streams will this OR permit to exit on IPv6? + * NULL for 'reject *:*' */ + struct short_policy_t *ipv6_exit_policy; + long uptime; /**< How many seconds the router claims to have been up */ + smartlist_t *declared_family; /**< Nicknames of router which this router + * claims are its family. */ + char *contact_info; /**< Declared contact info for this router. */ + unsigned int is_hibernating:1; /**< Whether the router claims to be + * hibernating */ + unsigned int caches_extra_info:1; /**< Whether the router says it caches and + * serves extrainfo documents. */ + unsigned int allow_single_hop_exits:1; /**< Whether the router says + * it allows single hop exits. */ + + unsigned int wants_to_be_hs_dir:1; /**< True iff this router claims to be + * a hidden service directory. */ + unsigned int policy_is_reject_star:1; /**< True iff the exit policy for this + * router rejects everything. */ + /** True if, after we have added this router, we should re-launch + * tests for it. */ + unsigned int needs_retest_if_added:1; + +/** Tor can use this router for general positions in circuits; we got it + * from a directory server as usual, or we're an authority and a server + * uploaded it. */ +#define ROUTER_PURPOSE_GENERAL 0 +/** Tor should avoid using this router for circuit-building: we got it + * from a crontroller. If the controller wants to use it, it'll have to + * ask for it by identity. */ +#define ROUTER_PURPOSE_CONTROLLER 1 +/** Tor should use this router only for bridge positions in circuits: we got + * it via a directory request from the bridge itself, or a bridge + * authority. x*/ +#define ROUTER_PURPOSE_BRIDGE 2 +/** Tor should not use this router; it was marked in cached-descriptors with + * a purpose we didn't recognize. */ +#define ROUTER_PURPOSE_UNKNOWN 255 + + /* In what way did we find out about this router? One of ROUTER_PURPOSE_*. + * Routers of different purposes are kept segregated and used for different + * things; see notes on ROUTER_PURPOSE_* macros above. + */ + uint8_t purpose; +} routerinfo_t; + +/** Information needed to keep and cache a signed extra-info document. */ +typedef struct extrainfo_t { + signed_descriptor_t cache_info; + /** The router's nickname. */ + char nickname[MAX_NICKNAME_LEN+1]; + /** True iff we found the right key for this extra-info, verified the + * signature, and found it to be bad. */ + unsigned int bad_sig : 1; + /** If present, we didn't have the right key to verify this extra-info, + * so this is a copy of the signature in the document. */ + char *pending_sig; + /** Length of pending_sig. */ + size_t pending_sig_len; +} extrainfo_t; + +/** Contents of a single router entry in a network status object. + */ +typedef struct routerstatus_t { + time_t published_on; /**< When was this router published? */ + char nickname[MAX_NICKNAME_LEN+1]; /**< The nickname this router says it + * has. */ + char identity_digest[DIGEST_LEN]; /**< Digest of the router's identity + * key. */ + /** Digest of the router's most recent descriptor or microdescriptor. + * If it's a descriptor, we only use the first DIGEST_LEN bytes. */ + char descriptor_digest[DIGEST256_LEN]; + uint32_t addr; /**< IPv4 address for this router. */ + uint16_t or_port; /**< OR port for this router. */ + uint16_t dir_port; /**< Directory port for this router. */ + tor_addr_t ipv6_addr; /**< IPv6 address for this router. */ + uint16_t ipv6_orport; /**